]> code.octet-stream.net Git - netwatcher/blob - src/list_win.rs
Update licence in Cargo.toml
[netwatcher] / src / list_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::NetworkManagement::Ndis::IfOperStatusDown;
16 use windows::Win32::Networking::WinSock::{
17 AF_INET, AF_INET6, AF_UNSPEC, SOCKADDR, SOCKADDR_IN, SOCKADDR_IN6,
18 };
19
20 use crate::{Error, Interface, List};
21
22 pub(crate) fn list_interfaces() -> Result<List, Error> {
23 let mut ifs = HashMap::new();
24 // Microsoft recommends a 15 KB initial buffer
25 let start_size = 15 * 1024;
26 let mut buf: Vec<u8> = vec![0; start_size];
27 let mut sizepointer: u32 = start_size as u32;
28
29 unsafe {
30 loop {
31 let bufptr = &mut buf[0] as *mut _ as *mut IP_ADAPTER_ADDRESSES_LH;
32 let res = GetAdaptersAddresses(
33 AF_UNSPEC.0.into(),
34 GAA_FLAG_SKIP_ANYCAST | GAA_FLAG_SKIP_MULTICAST,
35 None,
36 Some(bufptr),
37 &mut sizepointer,
38 );
39 match WIN32_ERROR(res) {
40 ERROR_SUCCESS => break,
41 ERROR_ADDRESS_NOT_ASSOCIATED => return Err(Error::AddressNotAssociated),
42 ERROR_BUFFER_OVERFLOW => {
43 buf.resize(sizepointer as usize, 0);
44 continue;
45 }
46 ERROR_INVALID_PARAMETER => return Err(Error::InvalidParameter),
47 ERROR_NOT_ENOUGH_MEMORY => return Err(Error::NotEnoughMemory),
48 ERROR_NO_DATA => return Ok(List(HashMap::new())), // there aren't any
49 _ => return Err(Error::UnexpectedWindowsResult(res)),
50 }
51 }
52
53 // We have at least one
54 let mut adapter_ptr = &buf[0] as *const _ as *const IP_ADAPTER_ADDRESSES_LH;
55 while !adapter_ptr.is_null() {
56 let adapter = &*adapter_ptr as &IP_ADAPTER_ADDRESSES_LH;
57 if adapter.OperStatus == IfOperStatusDown {
58 adapter_ptr = adapter.Next;
59 continue;
60 }
61 let mut hw_addr = String::with_capacity(adapter.PhysicalAddressLength as usize * 3);
62 for i in 0..adapter.PhysicalAddressLength as usize {
63 if i != 0 {
64 write!(hw_addr, ":").map_err(|_| Error::FormatMacAddress)?;
65 }
66 write!(hw_addr, "{:02X}", adapter.PhysicalAddress[i])
67 .map_err(|_| Error::FormatMacAddress)?;
68 }
69 let mut ips = vec![];
70 let mut unicast_ptr = adapter.FirstUnicastAddress;
71 while !unicast_ptr.is_null() {
72 let unicast = &*unicast_ptr as &IP_ADAPTER_UNICAST_ADDRESS_LH;
73 let sockaddr = &*unicast.Address.lpSockaddr as &SOCKADDR;
74 let ip = match sockaddr.sa_family {
75 AF_INET => {
76 let sockaddr_in =
77 &*(unicast.Address.lpSockaddr as *const SOCKADDR_IN) as &SOCKADDR_IN;
78 IpAddr::V4(sockaddr_in.sin_addr.into())
79 }
80 AF_INET6 => {
81 let sockaddr_in6 =
82 &*(unicast.Address.lpSockaddr as *const SOCKADDR_IN6) as &SOCKADDR_IN6;
83 IpAddr::V6(sockaddr_in6.sin6_addr.into())
84 }
85 _ => continue,
86 };
87 ips.push(ip);
88 unicast_ptr = unicast.Next;
89 }
90 let ifindex = adapter.Ipv6IfIndex;
91 let name = adapter
92 .FriendlyName
93 .to_string()
94 .unwrap_or_else(|_| "".to_owned());
95 let iface = Interface {
96 index: ifindex,
97 name,
98 hw_addr,
99 ips,
100 };
101 ifs.insert(ifindex, iface);
102 adapter_ptr = adapter.Next;
103 }
104 }
105
106 Ok(List(ifs))
107 }