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