X-Git-Url: https://code.octet-stream.net/netwatcher/blobdiff_plain/0fdfcccec1a2e6cbd70ec47a57a255fbe1e285e0..1c34fe3947aaf8af2d773d59bdebf19e17d78527:/src/list_win.rs diff --git a/src/list_win.rs b/src/list_win.rs new file mode 100644 index 0000000..e842244 --- /dev/null +++ b/src/list_win.rs @@ -0,0 +1,113 @@ +use std::collections::HashMap; +use std::fmt::Write; +use std::net::IpAddr; + +use windows::Win32::Foundation::{ + ERROR_ADDRESS_NOT_ASSOCIATED, ERROR_BUFFER_OVERFLOW, ERROR_INVALID_PARAMETER, + ERROR_NOT_ENOUGH_MEMORY, ERROR_NO_DATA, ERROR_SUCCESS, WIN32_ERROR, +}; +use windows::Win32::NetworkManagement::IpHelper::{ + GetAdaptersAddresses, IP_ADAPTER_UNICAST_ADDRESS_LH, +}; +use windows::Win32::NetworkManagement::IpHelper::{ + GAA_FLAG_SKIP_ANYCAST, GAA_FLAG_SKIP_MULTICAST, IP_ADAPTER_ADDRESSES_LH, +}; +use windows::Win32::Networking::WinSock::{ + AF_INET, AF_INET6, AF_UNSPEC, SOCKADDR, SOCKADDR_IN, SOCKADDR_IN6, +}; + +use crate::{Error, IfIndex, Interface}; + +pub fn list_interfaces() -> Result, Error> { + let mut ifs = HashMap::new(); + // Microsoft recommends a 15 KB initial buffer + let start_size = 15 * 1024; + let mut buf: Vec = vec![0; start_size]; + let mut sizepointer: u32 = start_size as u32; + + unsafe { + loop { + let bufptr = &mut buf[0] as *mut _ as *mut IP_ADAPTER_ADDRESSES_LH; + let res = GetAdaptersAddresses( + AF_UNSPEC.0.into(), + GAA_FLAG_SKIP_ANYCAST | GAA_FLAG_SKIP_MULTICAST, + None, + Some(bufptr), + &mut sizepointer, + ); + match WIN32_ERROR(res) { + ERROR_SUCCESS => break, + ERROR_ADDRESS_NOT_ASSOCIATED => return Err(Error::Internal), + ERROR_BUFFER_OVERFLOW => { + buf.resize(sizepointer as usize, 0); + continue; + } + ERROR_INVALID_PARAMETER => return Err(Error::Internal), + ERROR_NOT_ENOUGH_MEMORY => return Err(Error::Internal), + ERROR_NO_DATA => return Ok(HashMap::new()), // there aren't any + _ => return Err(Error::Internal), // TODO: Use FormatMessage to get a string + } + } + + // We have at least one + let mut adapter_ptr = &buf[0] as *const _ as *const IP_ADAPTER_ADDRESSES_LH; + while !adapter_ptr.is_null() { + let adapter = &*adapter_ptr as &IP_ADAPTER_ADDRESSES_LH; + let mut hw_addr = String::with_capacity(adapter.PhysicalAddressLength as usize * 3); + for i in 0..adapter.PhysicalAddressLength as usize { + if i != 0 { + write!(hw_addr, ":").map_err(|_| Error::Internal)?; + } + write!(hw_addr, "{:02X}", adapter.PhysicalAddress[i]) + .map_err(|_| Error::Internal)?; + } + let mut ips = vec![]; + let mut unicast_ptr = adapter.FirstUnicastAddress; + while !unicast_ptr.is_null() { + let unicast = &*unicast_ptr as &IP_ADAPTER_UNICAST_ADDRESS_LH; + let sockaddr = &*unicast.Address.lpSockaddr as &SOCKADDR; + let ip = match sockaddr.sa_family { + AF_INET => { + let sockaddr_in = + &*(unicast.Address.lpSockaddr as *const SOCKADDR_IN) as &SOCKADDR_IN; + IpAddr::V4(sockaddr_in.sin_addr.into()) + } + AF_INET6 => { + let sockaddr_in6 = + &*(unicast.Address.lpSockaddr as *const SOCKADDR_IN6) as &SOCKADDR_IN6; + IpAddr::V6(sockaddr_in6.sin6_addr.into()) + } + _ => continue, + }; + ips.push(ip); + unicast_ptr = unicast.Next; + } + let ifindex = adapter.Ipv6IfIndex; + let name = adapter + .FriendlyName + .to_string() + .unwrap_or_else(|_| "".to_owned()); + let iface = Interface { + index: ifindex, + name, + hw_addr, + ips, + }; + ifs.insert(ifindex, iface); + adapter_ptr = adapter.Next; + } + } + + Ok(ifs) +} + +#[cfg(test)] +mod test { + use super::list_interfaces; + + #[test] + fn list() { + let ifaces = list_interfaces().unwrap(); + println!("{:?}", ifaces); + } +}