1 #![allow(clippy::cast_ptr_alignment)]
2 
3 use std;
4 use std::ffi::CStr;
5 use std::net::IpAddr;
6 
7 use crate::error::*;
8 use socket2;
9 use widestring::WideCString;
10 use winapi::shared::winerror::{ERROR_SUCCESS, ERROR_BUFFER_OVERFLOW};
11 use winapi::shared::ws2def::AF_UNSPEC;
12 use winapi::shared::ws2def::SOCKADDR;
13 
14 use crate::bindings::*;
15 
16 /// Represent an operational status of the adapter
17 /// See IP_ADAPTER_ADDRESSES docs for more details
18 #[derive(Debug, Clone, Copy, PartialEq)]
19 pub enum OperStatus {
20     IfOperStatusUp = 1,
21     IfOperStatusDown = 2,
22     IfOperStatusTesting = 3,
23     IfOperStatusUnknown = 4,
24     IfOperStatusDormant = 5,
25     IfOperStatusNotPresent = 6,
26     IfOperStatusLowerLayerDown = 7,
27 }
28 
29 /// Represent an interface type
30 /// See IANA docs on iftype for more details
31 /// https://www.iana.org/assignments/ianaiftype-mib/ianaiftype-mib
32 /// Note that we only support a subset of the IANA interface
33 /// types and in case the adapter has an unsupported type,
34 /// `IfType::Unsupported` is used. `IfType::Other`
35 /// is different from `IfType::Unsupported`, as the former
36 /// one is defined by the IANA itself.
37 #[derive(Debug, Clone, Copy, PartialEq)]
38 pub enum IfType {
39     Other = 1,
40     EthernetCsmacd = 6,
41     Iso88025Tokenring = 9,
42     Ppp = 23,
43     SoftwareLoopback = 24,
44     Atm = 37,
45     Ieee80211 = 71,
46     Tunnel = 131,
47     Ieee1394 = 144,
48     Unsupported,
49     /// This enum may grow additional variants, so this makes sure clients
50     /// don't count on exhaustive matching. (Otherwise, adding a new variant
51     /// could break existing code.)
52     #[doc(hidden)]
53     __Nonexhaustive,
54 }
55 
56 /// Represent an adapter.
57 #[derive(Debug)]
58 pub struct Adapter {
59     adapter_name: String,
60     ip_addresses: Vec<IpAddr>,
61     prefixes: Vec<(IpAddr, u32)>,
62     gateways: Vec<IpAddr>,
63     dns_servers: Vec<IpAddr>,
64     description: String,
65     friendly_name: String,
66     physical_address: Option<Vec<u8>>,
67     receive_link_speed: u64,
68     transmit_link_speed: u64,
69     oper_status: OperStatus,
70     if_type: IfType,
71     ipv6_if_index: u32,
72 }
73 
74 impl Adapter {
75     /// Get the adapter's name
adapter_name(&self) -> &str76     pub fn adapter_name(&self) -> &str {
77         &self.adapter_name
78     }
79     /// Get the adapter's ip addresses (unicast ip addresses)
ip_addresses(&self) -> &[IpAddr]80     pub fn ip_addresses(&self) -> &[IpAddr] {
81         &self.ip_addresses
82     }
83     /// Get the adapter's prefixes. Returns a list of tuples (IpAddr, u32),
84     /// where first element is a subnet address, e.g. 192.168.1.0
85     /// and second element is prefix length, e.g. 24
prefixes(&self) -> &[(IpAddr, u32)]86     pub fn prefixes(&self) -> &[(IpAddr, u32)] {
87         &self.prefixes
88     }
89     /// Get the adapter's gateways
gateways(&self) -> &[IpAddr]90     pub fn gateways(&self) -> &[IpAddr] {
91         &self.gateways
92     }
93     /// Get the adapter's dns servers (the preferred dns server is first)
dns_servers(&self) -> &[IpAddr]94     pub fn dns_servers(&self) -> &[IpAddr] {
95         &self.dns_servers
96     }
97     /// Get the adapter's description
description(&self) -> &str98     pub fn description(&self) -> &str {
99         &self.description
100     }
101     /// Get the adapter's friendly name
friendly_name(&self) -> &str102     pub fn friendly_name(&self) -> &str {
103         &self.friendly_name
104     }
105     /// Get the adapter's physical (MAC) address
physical_address(&self) -> Option<&[u8]>106     pub fn physical_address(&self) -> Option<&[u8]> {
107         self.physical_address.as_ref().map(std::vec::Vec::as_slice)
108     }
109 
110     /// Get the adapter Recieve Link Speed (bits per second)
receive_link_speed(&self) -> u64111     pub fn receive_link_speed(&self) -> u64 {
112         self.receive_link_speed
113     }
114 
115     /// Get the Trasnmit Link Speed (bits per second)
transmit_link_speed(&self) -> u64116     pub fn transmit_link_speed(&self) -> u64 {
117         self.transmit_link_speed
118     }
119 
120     /// Check if the adapter is up (OperStatus is IfOperStatusUp)
oper_status(&self) -> OperStatus121     pub fn oper_status(&self) -> OperStatus {
122         self.oper_status
123     }
124 
125     /// Get the interface type
if_type(&self) -> IfType126     pub fn if_type(&self) -> IfType {
127         self.if_type
128     }
129 
130     /// Get the IPv6 interface index.
131     ///
132     /// The return value can be used as an IPv6 scope id for link-local
133     /// addresses.
ipv6_if_index(&self) -> u32134     pub fn ipv6_if_index(&self) -> u32 {
135         self.ipv6_if_index
136     }
137 }
138 
139 /// Get all the network adapters on this machine.
get_adapters() -> Result<Vec<Adapter>>140 pub fn get_adapters() -> Result<Vec<Adapter>> {
141     unsafe {
142         // Preallocate 16K per Microsoft recommendation, see Remarks section
143         // https://docs.microsoft.com/en-us/windows/desktop/api/iphlpapi/nf-iphlpapi-getadaptersaddresses
144         let mut buf_len: ULONG = 16384;
145         let mut adapters_addresses_buffer = Vec::new();
146 
147         let mut result = ERROR_BUFFER_OVERFLOW;
148         while result == ERROR_BUFFER_OVERFLOW {
149             adapters_addresses_buffer.resize(buf_len as usize, 0);
150 
151             result = GetAdaptersAddresses(
152                 AF_UNSPEC as u32,
153                 0x0080 | 0x0010, //GAA_FLAG_INCLUDE_GATEWAYS | GAA_FLAG_INCLUDE_PREFIX,
154                 std::ptr::null_mut(),
155                 adapters_addresses_buffer.as_mut_ptr() as PIP_ADAPTER_ADDRESSES,
156                 &mut buf_len as *mut ULONG,
157             );
158         }
159 
160         if result != ERROR_SUCCESS {
161             return Err(Error {
162                 kind: ErrorKind::Os(result),
163             });
164         }
165 
166         let mut adapters = vec![];
167         let mut adapter_addresses_ptr = adapters_addresses_buffer.as_mut_ptr() as PIP_ADAPTER_ADDRESSES;
168 
169         while !adapter_addresses_ptr.is_null() {
170             adapters.push(get_adapter(adapter_addresses_ptr)?);
171             adapter_addresses_ptr = (*adapter_addresses_ptr).Next;
172         }
173 
174         Ok(adapters)
175     }
176 }
177 
get_adapter(adapter_addresses_ptr: PIP_ADAPTER_ADDRESSES) -> Result<Adapter>178 unsafe fn get_adapter(adapter_addresses_ptr: PIP_ADAPTER_ADDRESSES) -> Result<Adapter> {
179     let adapter_addresses = &*adapter_addresses_ptr;
180     let adapter_name = CStr::from_ptr(adapter_addresses.AdapterName)
181         .to_str()?
182         .to_owned();
183     let dns_servers = get_dns_servers(adapter_addresses.FirstDnsServerAddress)?;
184     let gateways = get_gateways(adapter_addresses.FirstGatewayAddress)?;
185     let prefixes = get_prefixes(adapter_addresses.FirstPrefix)?;
186     let unicast_addresses = get_unicast_addresses(adapter_addresses.FirstUnicastAddress)?;
187     let receive_link_speed: u64 = adapter_addresses.ReceiveLinkSpeed;
188     let transmit_link_speed: u64 = adapter_addresses.TransmitLinkSpeed;
189     let oper_status = match adapter_addresses.OperStatus {
190         1 => OperStatus::IfOperStatusUp,
191         2 => OperStatus::IfOperStatusDown,
192         3 => OperStatus::IfOperStatusTesting,
193         4 => OperStatus::IfOperStatusUnknown,
194         5 => OperStatus::IfOperStatusDormant,
195         6 => OperStatus::IfOperStatusNotPresent,
196         7 => OperStatus::IfOperStatusLowerLayerDown,
197         v => {
198             panic!("unexpected OperStatus value: {}", v);
199         }
200     };
201     let if_type = match adapter_addresses.IfType {
202         1 => IfType::Other,
203         6 => IfType::EthernetCsmacd,
204         9 => IfType::Iso88025Tokenring,
205         23 => IfType::Ppp,
206         24 => IfType::SoftwareLoopback,
207         37 => IfType::Atm,
208         71 => IfType::Ieee80211,
209         131 => IfType::Tunnel,
210         144 => IfType::Ieee1394,
211         _ => IfType::Unsupported,
212     };
213     let ipv6_if_index = adapter_addresses.Ipv6IfIndex;
214 
215     let description = WideCString::from_ptr_str(adapter_addresses.Description).to_string()?;
216     let friendly_name = WideCString::from_ptr_str(adapter_addresses.FriendlyName).to_string()?;
217     let physical_address = if adapter_addresses.PhysicalAddressLength == 0 {
218         None
219     } else {
220         Some(
221             adapter_addresses.PhysicalAddress[..adapter_addresses.PhysicalAddressLength as usize]
222                 .to_vec(),
223         )
224     };
225     Ok(Adapter {
226         adapter_name,
227         ip_addresses: unicast_addresses,
228         prefixes,
229         gateways,
230         dns_servers,
231         description,
232         friendly_name,
233         physical_address,
234         receive_link_speed,
235         transmit_link_speed,
236         oper_status,
237         if_type,
238         ipv6_if_index,
239     })
240 }
241 
socket_address_to_ipaddr(socket_address: &SOCKET_ADDRESS) -> IpAddr242 unsafe fn socket_address_to_ipaddr(socket_address: &SOCKET_ADDRESS) -> IpAddr {
243     let sockaddr = socket2::SockAddr::from_raw_parts(
244         socket_address.lpSockaddr as *const SOCKADDR,
245         socket_address.iSockaddrLength,
246     );
247 
248     // Could be either ipv4 or ipv6
249     sockaddr
250         .as_inet()
251         .map(|s| IpAddr::V4(*s.ip()))
252         .unwrap_or_else(|| IpAddr::V6(*sockaddr.as_inet6().unwrap().ip()))
253 }
254 
get_dns_servers( mut dns_server_ptr: PIP_ADAPTER_DNS_SERVER_ADDRESS_XP, ) -> Result<Vec<IpAddr>>255 unsafe fn get_dns_servers(
256     mut dns_server_ptr: PIP_ADAPTER_DNS_SERVER_ADDRESS_XP,
257 ) -> Result<Vec<IpAddr>> {
258     let mut dns_servers = vec![];
259 
260     while !dns_server_ptr.is_null() {
261         let dns_server = &*dns_server_ptr;
262         let ipaddr = socket_address_to_ipaddr(&dns_server.Address);
263         dns_servers.push(ipaddr);
264 
265         dns_server_ptr = dns_server.Next;
266     }
267 
268     Ok(dns_servers)
269 }
270 
get_gateways(mut gateway_ptr: PIP_ADAPTER_GATEWAY_ADDRESS_LH) -> Result<Vec<IpAddr>>271 unsafe fn get_gateways(mut gateway_ptr: PIP_ADAPTER_GATEWAY_ADDRESS_LH) -> Result<Vec<IpAddr>> {
272     let mut gateways = vec![];
273 
274     while !gateway_ptr.is_null() {
275         let gateway = &*gateway_ptr;
276         let ipaddr = socket_address_to_ipaddr(&gateway.Address);
277         gateways.push(ipaddr);
278 
279         gateway_ptr = gateway.Next;
280     }
281 
282     Ok(gateways)
283 }
284 
get_unicast_addresses( mut unicast_addresses_ptr: PIP_ADAPTER_UNICAST_ADDRESS_LH, ) -> Result<Vec<IpAddr>>285 unsafe fn get_unicast_addresses(
286     mut unicast_addresses_ptr: PIP_ADAPTER_UNICAST_ADDRESS_LH,
287 ) -> Result<Vec<IpAddr>> {
288     let mut unicast_addresses = vec![];
289 
290     while !unicast_addresses_ptr.is_null() {
291         let unicast_address = &*unicast_addresses_ptr;
292         let ipaddr = socket_address_to_ipaddr(&unicast_address.Address);
293         unicast_addresses.push(ipaddr);
294 
295         unicast_addresses_ptr = unicast_address.Next;
296     }
297 
298     Ok(unicast_addresses)
299 }
300 
get_prefixes(mut prefixes_ptr: PIP_ADAPTER_PREFIX_XP) -> Result<Vec<(IpAddr, u32)>>301 unsafe fn get_prefixes(mut prefixes_ptr: PIP_ADAPTER_PREFIX_XP) -> Result<Vec<(IpAddr, u32)>> {
302     let mut prefixes = vec![];
303 
304     while !prefixes_ptr.is_null() {
305         let prefix = &*prefixes_ptr;
306         let ipaddr = socket_address_to_ipaddr(&prefix.Address);
307         prefixes.push((ipaddr, prefix.PrefixLength));
308 
309         prefixes_ptr = prefix.Next;
310     }
311 
312     Ok(prefixes)
313 }
314