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