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