webrtc_util/ifaces/ffi/windows/
mod.rs

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/// All Windows & Later
57#[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/// Windows XP & Later
77#[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/// Windows Vista & Later
85#[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            // For some reason, some IpDadState::IpDadStateDeprecated addresses are return
328            // These contain BOGUS interface indices and will cause problesm if used
329            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                    // Make sure the scope id is set for ALL interfaces, not just link-local
341                    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
361/// Query the local system for all interface addresses.
362pub 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}