]> code.octet-stream.net Git - netwatcher/blob - src/imp_win.rs
Basic listing of interfaces on Windows
[netwatcher] / src / imp_win.rs
1 use std::collections::HashMap;
2 use std::fmt::Write;
3 use std::net::IpAddr;
4
5 use windows::Win32::Foundation::{
6 ERROR_ADDRESS_NOT_ASSOCIATED, ERROR_BUFFER_OVERFLOW, ERROR_INVALID_PARAMETER,
7 ERROR_NOT_ENOUGH_MEMORY, ERROR_NO_DATA, ERROR_SUCCESS, WIN32_ERROR,
8 };
9 use windows::Win32::NetworkManagement::IpHelper::{
10 GetAdaptersAddresses, IP_ADAPTER_UNICAST_ADDRESS_LH,
11 };
12 use windows::Win32::NetworkManagement::IpHelper::{
13 GAA_FLAG_SKIP_ANYCAST, GAA_FLAG_SKIP_MULTICAST, IP_ADAPTER_ADDRESSES_LH,
14 };
15 use windows::Win32::Networking::WinSock::{AF_INET, AF_INET6, SOCKADDR, SOCKADDR_IN, SOCKADDR_IN6};
16
17 use crate::{Error, IfIndex, Interface};
18
19 pub(crate) fn list_interfaces() -> Result<HashMap<IfIndex, Interface>, Error> {
20 let mut ifs = HashMap::new();
21 // Microsoft recommends a 15 KB initial buffer
22 let start_size = 15 * 1024;
23 let mut buf: Vec<u8> = vec![0; start_size];
24 let mut sizepointer: u32 = start_size as u32;
25
26 unsafe {
27 loop {
28 let bufptr = &mut buf[0] as *mut _ as *mut IP_ADAPTER_ADDRESSES_LH;
29 let res = GetAdaptersAddresses(
30 0, /* AF_UNSPEC */
31 GAA_FLAG_SKIP_ANYCAST | GAA_FLAG_SKIP_MULTICAST,
32 None,
33 Some(bufptr),
34 &mut sizepointer,
35 );
36 match WIN32_ERROR(res) {
37 ERROR_SUCCESS => break,
38 ERROR_ADDRESS_NOT_ASSOCIATED => return Err(Error::Internal),
39 ERROR_BUFFER_OVERFLOW => {
40 buf.resize(sizepointer as usize, 0);
41 continue;
42 }
43 ERROR_INVALID_PARAMETER => return Err(Error::Internal),
44 ERROR_NOT_ENOUGH_MEMORY => return Err(Error::Internal),
45 ERROR_NO_DATA => return Ok(HashMap::new()), // there aren't any
46 _ => return Err(Error::Internal), // TODO: Use FormatMessage to get a string
47 }
48 }
49
50 // We have at least one
51 let mut adapter_ptr = &buf[0] as *const _ as *const IP_ADAPTER_ADDRESSES_LH;
52 while !adapter_ptr.is_null() {
53 let adapter = &*adapter_ptr as &IP_ADAPTER_ADDRESSES_LH;
54 let mut hw_addr = String::with_capacity(adapter.PhysicalAddressLength as usize * 3);
55 for i in 0..adapter.PhysicalAddressLength as usize {
56 if i != 0 {
57 write!(hw_addr, ":").map_err(|_| Error::Internal)?;
58 }
59 write!(hw_addr, "{:02X}", adapter.PhysicalAddress[i])
60 .map_err(|_| Error::Internal)?;
61 }
62 let mut ips = vec![];
63 let mut unicast_ptr = adapter.FirstUnicastAddress;
64 while !unicast_ptr.is_null() {
65 let unicast = &*unicast_ptr as &IP_ADAPTER_UNICAST_ADDRESS_LH;
66 let sockaddr = &*unicast.Address.lpSockaddr as &SOCKADDR;
67 let ip = match sockaddr.sa_family {
68 AF_INET => {
69 let sockaddr_in =
70 &*(unicast.Address.lpSockaddr as *const SOCKADDR_IN) as &SOCKADDR_IN;
71 IpAddr::V4(sockaddr_in.sin_addr.into())
72 }
73 AF_INET6 => {
74 let sockaddr_in6 =
75 &*(unicast.Address.lpSockaddr as *const SOCKADDR_IN6) as &SOCKADDR_IN6;
76 IpAddr::V6(sockaddr_in6.sin6_addr.into())
77 }
78 _ => continue,
79 };
80 ips.push(ip);
81 unicast_ptr = unicast.Next;
82 }
83 let ifindex = adapter.Ipv6IfIndex;
84 let name = adapter
85 .FriendlyName
86 .to_string()
87 .unwrap_or_else(|_| "".to_owned());
88 let iface = Interface {
89 index: ifindex,
90 name,
91 hw_addr,
92 ips,
93 };
94 ifs.insert(ifindex, iface);
95 adapter_ptr = adapter.Next;
96 }
97 }
98
99 Ok(ifs)
100 }
101
102 #[cfg(test)]
103 mod test {
104 use super::list_interfaces;
105
106 #[test]
107 fn list() {
108 let ifaces = list_interfaces().unwrap();
109 println!("{:?}", ifaces);
110 }
111 }