1#![allow(unused, non_upper_case_globals)]
2
3use winapi::shared::basetsd::{UINT32, UINT8, ULONG64};
4use winapi::shared::guiddef::GUID;
5use winapi::shared::minwindef::{BYTE, DWORD, PULONG, ULONG};
6use winapi::shared::ws2def::SOCKET_ADDRESS;
7use winapi::um::winnt::{PCHAR, PVOID, PWCHAR, WCHAR};
8
9const MAX_ADAPTER_ADDRESS_LENGTH: usize = 8;
10const ZONE_INDICES_LENGTH: usize = 16;
11const MAX_DHCPV6_DUID_LENGTH: usize = 130;
12const MAX_DNS_SUFFIX_STRING_LENGTH: usize = 256;
13
14pub const IP_ADAPTER_IPV4_ENABLED: DWORD = 0x0080;
15pub const IP_ADAPTER_IPV6_ENABLED: DWORD = 0x0100;
16
17use std::net::{Ipv4Addr, SocketAddr, SocketAddrV4, SocketAddrV6};
18use std::{io, mem, ptr};
19
20use winapi::shared::winerror::{
21 ERROR_ADDRESS_NOT_ASSOCIATED, ERROR_BUFFER_OVERFLOW, ERROR_INVALID_PARAMETER,
22 ERROR_NOT_ENOUGH_MEMORY, ERROR_NO_DATA, ERROR_SUCCESS,
23};
24use winapi::shared::ws2def::{AF_INET, AF_INET6, AF_UNSPEC, SOCKADDR_IN};
25use winapi::shared::ws2ipdef::SOCKADDR_IN6;
26
27const PREALLOC_ADAPTERS_LEN: usize = 15 * 1024;
28
29use crate::ifaces::{Interface, Kind, NextHop};
30
31#[link(name = "iphlpapi")]
32extern "system" {
33 pub fn GetAdaptersAddresses(
34 family: ULONG,
35 flags: ULONG,
36 reserved: PVOID,
37 addresses: *mut u8,
38 size: PULONG,
39 ) -> ULONG;
40}
41
42#[repr(C)]
43pub struct IpAdapterAddresses {
44 pub head: IpAdapterAddressesHead,
45 pub all: IpAdaptersAddressesAll,
46 pub xp: IpAdaptersAddressesXp,
47 pub vista: IpAdaptersAddressesVista,
48}
49
50#[repr(C)]
51pub struct IpAdapterAddressesHead {
52 pub length: ULONG,
53 if_index: DWORD,
54}
55
56#[repr(C)]
58pub struct IpAdaptersAddressesAll {
59 pub next: *const IpAdapterAddresses,
60 pub adapter_name: PCHAR,
61 pub first_unicast_address: *const IpAdapterUnicastAddress,
62 first_anycast_address: *const IpAdapterAnycastAddress,
63 first_multicast_address: *const IpAdapterMulticastAddress,
64 first_dns_server_address: *const IpAdapterDnsServerAddress,
65 dns_suffix: PWCHAR,
66 pub description: PWCHAR,
67 friendly_name: PWCHAR,
68 pub physical_address: [BYTE; MAX_ADAPTER_ADDRESS_LENGTH],
69 pub physical_address_length: DWORD,
70 pub flags: DWORD,
71 mtu: DWORD,
72 pub if_type: DWORD,
73 oper_status: IfOperStatus,
74}
75
76#[repr(C)]
78pub struct IpAdaptersAddressesXp {
79 pub ipv6_if_index: DWORD,
80 pub zone_indices: [DWORD; ZONE_INDICES_LENGTH],
81 first_prefix: *const IpAdapterPrefix,
82}
83
84#[repr(C)]
86pub struct IpAdaptersAddressesVista {
87 transmit_link_speed: ULONG64,
88 receive_link_speed: ULONG64,
89 first_wins_server_address: *const IpAdapterWinsServerAddress,
90 first_gateway_address: *const IpAdapterGatewayAddress,
91 ipv4_metric: ULONG,
92 ipv6_metric: ULONG,
93 luid: IfLuid,
94 dhcpv4_server: SOCKET_ADDRESS,
95 compartment_id: UINT32,
96 network_guid: GUID,
97 connection_type: NetIfConnectionType,
98 tunnel_type: TunnelType,
99 dhcpv6_server: SOCKET_ADDRESS,
100 dhcpv6_client_duid: [BYTE; MAX_DHCPV6_DUID_LENGTH],
101 dhcpv6_client_duid_length: ULONG,
102 dhcpv6_iaid: ULONG,
103 first_dns_suffix: *const IpAdapterDnsSuffix,
104}
105
106#[repr(C)]
107pub struct IpAdapterUnicastAddress {
108 pub length: ULONG,
109 flags: DWORD,
110 pub next: *const IpAdapterUnicastAddress,
111 pub address: SOCKET_ADDRESS,
112 prefix_origin: IpPrefixOrigin,
113 suffix_origin: IpSuffixOrigin,
114 pub dad_state: IpDadState,
115 valid_lifetime: ULONG,
116 preferred_lifetime: ULONG,
117 lease_lifetime: ULONG,
118 on_link_prefix_length: UINT8,
119}
120
121#[repr(C)]
122pub struct IpAdapterAnycastAddress {
123 length: ULONG,
124 flags: DWORD,
125 next: *const IpAdapterAnycastAddress,
126 address: SOCKET_ADDRESS,
127}
128
129#[repr(C)]
130pub struct IpAdapterMulticastAddress {
131 length: ULONG,
132 flags: DWORD,
133 next: *const IpAdapterMulticastAddress,
134 address: SOCKET_ADDRESS,
135}
136
137#[repr(C)]
138pub struct IpAdapterDnsServerAddress {
139 length: ULONG,
140 reserved: DWORD,
141 next: *const IpAdapterDnsServerAddress,
142 address: SOCKET_ADDRESS,
143}
144
145#[repr(C)]
146pub struct IpAdapterPrefix {
147 length: ULONG,
148 flags: DWORD,
149 next: *const IpAdapterPrefix,
150 address: SOCKET_ADDRESS,
151 prefix_length: ULONG,
152}
153
154#[repr(C)]
155pub struct IpAdapterWinsServerAddress {
156 length: ULONG,
157 reserved: DWORD,
158 next: *const IpAdapterWinsServerAddress,
159 address: SOCKET_ADDRESS,
160}
161
162#[repr(C)]
163pub struct IpAdapterGatewayAddress {
164 length: ULONG,
165 reserved: DWORD,
166 next: *const IpAdapterGatewayAddress,
167 address: SOCKET_ADDRESS,
168}
169
170#[repr(C)]
171pub struct IpAdapterDnsSuffix {
172 next: *const IpAdapterDnsSuffix,
173 string: [WCHAR; MAX_DNS_SUFFIX_STRING_LENGTH],
174}
175
176bitflags! {
177 struct IfLuid: ULONG64 {
178 const Reserved = 0x0000000000FFFFFF;
179 const NetLuidIndex = 0x0000FFFFFF000000;
180 const IfType = 0xFFFF00000000000;
181 }
182}
183
184#[repr(C)]
185pub enum IpPrefixOrigin {
186 IpPrefixOriginOther = 0,
187 IpPrefixOriginManual,
188 IpPrefixOriginWellKnown,
189 IpPrefixOriginDhcp,
190 IpPrefixOriginRouterAdvertisement,
191 IpPrefixOriginUnchanged = 16,
192}
193
194#[repr(C)]
195pub enum IpSuffixOrigin {
196 IpSuffixOriginOther = 0,
197 IpSuffixOriginManual,
198 IpSuffixOriginWellKnown,
199 IpSuffixOriginDhcp,
200 IpSuffixOriginLinkLayerAddress,
201 IpSuffixOriginRandom,
202 IpSuffixOriginUnchanged = 16,
203}
204
205#[derive(PartialEq, Eq)]
206#[repr(C)]
207pub enum IpDadState {
208 IpDadStateInvalid = 0,
209 IpDadStateTentative,
210 IpDadStateDuplicate,
211 IpDadStateDeprecated,
212 IpDadStatePreferred,
213}
214
215#[repr(C)]
216pub enum IfOperStatus {
217 IfOperStatusUp = 1,
218 IfOperStatusDown = 2,
219 IfOperStatusTesting = 3,
220 IfOperStatusUnknown = 4,
221 IfOperStatusDormant = 5,
222 IfOperStatusNotPresent = 6,
223 IfOperStatusLowerLayerDown = 7,
224}
225
226#[repr(C)]
227pub enum NetIfConnectionType {
228 NetIfConnectionDedicated = 1,
229 NetIfConnectionPassive = 2,
230 NetIfConnectionDemand = 3,
231 NetIfConnectionMaximum = 4,
232}
233
234#[repr(C)]
235pub enum TunnelType {
236 TunnelTypeNone = 0,
237 TunnelTypeOther = 1,
238 TunnelTypeDirect = 2,
239 TunnelType6To4 = 11,
240 TunnelTypeIsatap = 13,
241 TunnelTypeTeredo = 14,
242 TunnelTypeIpHttps = 15,
243}
244
245unsafe fn v4_socket_from_adapter(unicast_addr: &IpAdapterUnicastAddress) -> SocketAddrV4 {
246 let socket_addr = &unicast_addr.address;
247
248 let in_addr: SOCKADDR_IN = mem::transmute(*socket_addr.lpSockaddr);
249 let sin_addr = in_addr.sin_addr.S_un;
250
251 let v4_addr = Ipv4Addr::new(
252 *sin_addr.S_addr() as u8,
253 (*sin_addr.S_addr() >> 8) as u8,
254 (*sin_addr.S_addr() >> 16) as u8,
255 (*sin_addr.S_addr() >> 24) as u8,
256 );
257
258 SocketAddrV4::new(v4_addr, 0)
259}
260
261unsafe fn v6_socket_from_adapter(unicast_addr: &IpAdapterUnicastAddress) -> SocketAddrV6 {
262 let socket_addr = &unicast_addr.address;
263
264 let sock_addr6: *const SOCKADDR_IN6 = socket_addr.lpSockaddr as *const SOCKADDR_IN6;
265 let in6_addr: SOCKADDR_IN6 = *sock_addr6;
266
267 let v6_addr = (*in6_addr.sin6_addr.u.Word()).into();
268
269 SocketAddrV6::new(
270 v6_addr,
271 0,
272 in6_addr.sin6_flowinfo,
273 *in6_addr.u.sin6_scope_id(),
274 )
275}
276
277unsafe fn local_ifaces_with_buffer(buffer: &mut Vec<u8>) -> io::Result<()> {
278 let mut length = buffer.capacity() as u32;
279
280 let ret_code = GetAdaptersAddresses(
281 AF_UNSPEC as u32,
282 0,
283 ptr::null_mut(),
284 buffer.as_mut_ptr(),
285 &mut length,
286 );
287 match ret_code {
288 ERROR_SUCCESS => Ok(()),
289 ERROR_ADDRESS_NOT_ASSOCIATED => Err(io::Error::new(
290 io::ErrorKind::AddrNotAvailable,
291 "An address has not yet been associated with the network endpoint.",
292 )),
293 ERROR_BUFFER_OVERFLOW => {
294 buffer.reserve_exact(length as usize);
295
296 local_ifaces_with_buffer(buffer)
297 }
298 ERROR_INVALID_PARAMETER => Err(io::Error::new(
299 io::ErrorKind::InvalidInput,
300 "One of the parameters is invalid.",
301 )),
302 ERROR_NOT_ENOUGH_MEMORY => Err(io::Error::new(
303 io::ErrorKind::Other,
304 "Insufficient memory resources are available to complete the operation.",
305 )),
306 ERROR_NO_DATA => Err(io::Error::new(
307 io::ErrorKind::AddrNotAvailable,
308 "No addresses were found for the requested parameters.",
309 )),
310 _ => Err(io::Error::new(
311 io::ErrorKind::Other,
312 "Some Other Error Occurred.",
313 )),
314 }
315}
316
317unsafe fn map_adapter_addresses(mut adapter_addr: *const IpAdapterAddresses) -> Vec<Interface> {
318 let mut adapter_addresses = Vec::new();
319
320 while !adapter_addr.is_null() {
321 let curr_adapter_addr = &*adapter_addr;
322
323 let mut unicast_addr = curr_adapter_addr.all.first_unicast_address;
324 while !unicast_addr.is_null() {
325 let curr_unicast_addr = &*unicast_addr;
326
327 if curr_unicast_addr.dad_state != IpDadState::IpDadStateDeprecated {
330 if is_ipv4_enabled(curr_unicast_addr) {
331 adapter_addresses.push(Interface {
332 name: "".to_string(),
333 kind: Kind::Ipv4,
334 addr: Some(SocketAddr::V4(v4_socket_from_adapter(curr_unicast_addr))),
335 mask: None,
336 hop: None,
337 });
338 } else if is_ipv6_enabled(curr_unicast_addr) {
339 let mut v6_sock = v6_socket_from_adapter(curr_unicast_addr);
340 v6_sock.set_scope_id(curr_adapter_addr.xp.ipv6_if_index);
342 adapter_addresses.push(Interface {
343 name: "".to_string(),
344 kind: Kind::Ipv6,
345 addr: Some(SocketAddr::V6(v6_sock)),
346 mask: None,
347 hop: None,
348 });
349 }
350 }
351
352 unicast_addr = curr_unicast_addr.next;
353 }
354
355 adapter_addr = curr_adapter_addr.all.next;
356 }
357
358 adapter_addresses
359}
360
361pub fn ifaces() -> Result<Vec<Interface>, ::std::io::Error> {
363 let mut adapters_list = Vec::with_capacity(PREALLOC_ADAPTERS_LEN);
364 unsafe {
365 local_ifaces_with_buffer(&mut adapters_list)?;
366
367 Ok(map_adapter_addresses(
368 adapters_list.as_ptr() as *const IpAdapterAddresses
369 ))
370 }
371}
372
373unsafe fn is_ipv4_enabled(unicast_addr: &IpAdapterUnicastAddress) -> bool {
374 if unicast_addr.length != 0 {
375 let socket_addr = &unicast_addr.address;
376 let sa_family = (*socket_addr.lpSockaddr).sa_family;
377
378 sa_family == AF_INET as u16
379 } else {
380 false
381 }
382}
383
384unsafe fn is_ipv6_enabled(unicast_addr: &IpAdapterUnicastAddress) -> bool {
385 if unicast_addr.length != 0 {
386 let socket_addr = &unicast_addr.address;
387 let sa_family = (*socket_addr.lpSockaddr).sa_family;
388
389 sa_family == AF_INET6 as u16
390 } else {
391 false
392 }
393}