-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(crate) fn list_interfaces() -> Result<HashMap<IfIndex, Interface>, Error> {
- let mut ifs = HashMap::new();
- // Microsoft recommends a 15 KB initial buffer
- let start_size = 15 * 1024;
- let mut buf: Vec<u8> = 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);
- }
-}