network_interface/target/
windows.rs1use std::ffi::c_void;
2use std::fmt::Pointer;
3use std::mem::size_of;
4use std::net::{Ipv4Addr, Ipv6Addr};
5use std::ptr::null_mut;
6use std::slice::from_raw_parts;
7use std::iter::Iterator;
8use std::marker::PhantomData;
9
10use libc::{free, malloc, wchar_t, wcslen};
11use winapi::{
12 ctypes::c_ulong,
13 shared::{
14 ws2def::{AF_UNSPEC, SOCKADDR_IN},
15 ws2ipdef::SOCKADDR_IN6,
16 netioapi::{ConvertLengthToIpv4Mask, ConvertInterfaceLuidToIndex},
17 ntdef::ULONG,
18 ifdef::IF_LUID,
19 winerror,
20 },
21 um::{
22 iptypes::{IP_ADAPTER_ADDRESSES, IP_ADAPTER_UNICAST_ADDRESS, IP_ADAPTER_PREFIX},
23 iphlpapi::GetAdaptersAddresses,
24 },
25};
26
27use crate::utils::hex::HexSlice;
28use crate::utils::ffialloc::FFIAlloc;
29use crate::{Addr, Error, NetworkInterface, NetworkInterfaceConfig, Result, V4IfAddr, V6IfAddr};
30use crate::interface::Netmask;
31
32type AdapterAddress = IP_ADAPTER_ADDRESSES;
34
35const AF_INET: u16 = winapi::shared::ws2def::AF_INET as u16;
37
38const AF_INET6: u16 = winapi::shared::ws2def::AF_INET6 as u16;
40
41const GET_ADAPTERS_ADDRESSES_FAMILY: u32 = AF_UNSPEC as u32;
46
47const GET_ADAPTERS_ADDRESSES_FLAGS: ULONG = winapi::um::iptypes::GAA_FLAG_INCLUDE_PREFIX;
49
50type MacAddress = Option<String>;
51
52macro_rules! iterable_raw_pointer {
53 ($t: ty, $n: ident) => {
54 impl IterableRawPointer for $t {
55 type Pointer = *const $t;
56 type Value = $t;
57
58 fn next(&self) -> Self::Pointer {
59 self.$n
60 }
61 }
62 };
63}
64
65iterable_raw_pointer!(IP_ADAPTER_ADDRESSES, Next);
66iterable_raw_pointer!(IP_ADAPTER_UNICAST_ADDRESS, Next);
67iterable_raw_pointer!(IP_ADAPTER_PREFIX, Next);
68
69impl NetworkInterfaceConfig for NetworkInterface {
70 fn show() -> Result<Vec<NetworkInterface>> {
71 let mut buffer_size: u32 = 15000;
73 const MAX_TRIES: i32 = 10;
75 let mut try_no = 1;
76
77 let adapter_address = loop {
78 let adapter_address = FFIAlloc::alloc(buffer_size as usize).ok_or_else(|| {
79 Error::GetIfAddrsError(String::from("GetAdaptersAddresses"), 1)
81 })?;
82
83 let res = unsafe {
84 GetAdaptersAddresses(
85 GET_ADAPTERS_ADDRESSES_FAMILY,
86 GET_ADAPTERS_ADDRESSES_FLAGS,
87 null_mut(),
88 adapter_address.as_mut_ptr(),
89 &mut buffer_size,
90 )
91 };
92 match res {
93 winerror::ERROR_SUCCESS => {
94 break Ok(adapter_address);
95 }
96 winerror::ERROR_BUFFER_OVERFLOW => {
97 if try_no == MAX_TRIES {
104 break Err(Error::GetIfAddrsError(
105 "GetAdapterAddresses: alloc error".to_string(),
106 res as i32,
107 ));
108 }
109 try_no += 1;
110 }
111 _ => {
112 break Err(Error::GetIfAddrsError(
113 "GetAdapterAddresses".to_string(),
114 res as i32,
115 ));
116 }
117 }
118 }?;
119
120 let mut network_interfaces = Vec::<NetworkInterface>::new();
122
123 for adapter_address in RawPointerWrapper::new(adapter_address.as_ptr()) {
124 let name = make_adapter_address_name(adapter_address)?;
125 let index = get_adapter_address_index(adapter_address)?;
126 let mac_addr = make_mac_address(adapter_address);
127 let mut network_interface = NetworkInterface {
128 name,
129 addr: Vec::new(),
130 mac_addr,
131 index,
132 };
133
134 for current_unicast_address in
135 RawPointerWrapper::new(adapter_address.FirstUnicastAddress)
136 {
137 let address = current_unicast_address.Address;
138
139 network_interface
140 .addr
141 .push(match unsafe { (*address.lpSockaddr).sa_family } {
142 AF_INET => {
143 let sockaddr = &unsafe { *(address.lpSockaddr as *const SOCKADDR_IN) };
144 Addr::V4(V4IfAddr {
145 ip: make_ipv4_addr(sockaddr),
146 broadcast: lookup_ipv4_broadcast_addr(adapter_address, sockaddr),
147 netmask: make_ipv4_netmask(current_unicast_address),
148 })
149 }
150 AF_INET6 => {
151 let sockaddr = &unsafe { *(address.lpSockaddr as *const SOCKADDR_IN6) };
152 Addr::V6(V6IfAddr {
153 ip: make_ipv6_addr(sockaddr)?,
154 broadcast: None,
155 netmask: make_ipv6_netmask(sockaddr),
156 })
157 }
158 _ => continue,
159 });
160 }
161
162 network_interfaces.push(network_interface);
163 }
164
165 Ok(network_interfaces)
166 }
167}
168
169fn lookup_ipv4_broadcast_addr(
187 adapter_address: &IP_ADAPTER_ADDRESSES,
188 unicast_ip: &SOCKADDR_IN,
189) -> Option<Ipv4Addr> {
190 let mut prefix_index_v4 = 0;
191 let mut broadcast_index: Option<i32> = None;
192
193 for prefix_address in RawPointerWrapper::new(adapter_address.FirstPrefix) {
195 let address = prefix_address.Address;
196
197 if unsafe { (*address.lpSockaddr).sa_family } == AF_INET {
198 let sockaddr = &unsafe { *(address.lpSockaddr as *const SOCKADDR_IN) };
199
200 if let Some(broadcast_index) = broadcast_index {
201 if prefix_index_v4 == broadcast_index {
202 return Some(make_ipv4_addr(sockaddr));
203 }
204 } else if prefix_index_v4 % 3 == 1 && ipv4_addr_equal(sockaddr, unicast_ip) {
205 broadcast_index = Some(prefix_index_v4 + 1);
206 }
207 prefix_index_v4 += 1;
208 }
209 }
210 None
211}
212
213fn make_adapter_address_name(adapter_address: &AdapterAddress) -> Result<String> {
215 let address_name = adapter_address.FriendlyName;
216 let address_name_length = unsafe { wcslen(address_name as *const wchar_t) };
217 let byte_slice = unsafe { from_raw_parts(address_name, address_name_length) };
218 let string = String::from_utf16(byte_slice).map_err(Error::from)?;
219
220 Ok(string)
221}
222
223fn make_ipv6_addr(sockaddr: &SOCKADDR_IN6) -> Result<Ipv6Addr> {
225 let address_bytes = unsafe { sockaddr.sin6_addr.u.Byte() };
226 let ip = Ipv6Addr::from(*address_bytes);
227
228 Ok(ip)
229}
230
231fn make_ipv4_addr(sockaddr: &SOCKADDR_IN) -> Ipv4Addr {
233 let address = unsafe { sockaddr.sin_addr.S_un.S_addr() };
234
235 if cfg!(target_endian = "little") {
236 return Ipv4Addr::from(address.swap_bytes());
242 }
243
244 Ipv4Addr::from(*address)
245}
246
247fn ipv4_addr_equal(sockaddr1: &SOCKADDR_IN, sockaddr2: &SOCKADDR_IN) -> bool {
249 let address1 = unsafe { sockaddr1.sin_addr.S_un.S_addr() };
250 let address2 = unsafe { sockaddr2.sin_addr.S_un.S_addr() };
251 address1 == address2
252}
253
254fn make_ipv4_netmask(unicast_address: &IP_ADAPTER_UNICAST_ADDRESS) -> Netmask<Ipv4Addr> {
260 let mut mask: c_ulong = 0;
261 let on_link_prefix_length = unicast_address.OnLinkPrefixLength;
262 unsafe {
263 ConvertLengthToIpv4Mask(on_link_prefix_length as u32, &mut mask as *mut c_ulong);
264 }
265
266 if cfg!(target_endian = "little") {
267 return Some(Ipv4Addr::from(mask.swap_bytes()));
273 }
274
275 Some(Ipv4Addr::from(mask))
276}
277
278fn make_ipv6_netmask(_sockaddr: &SOCKADDR_IN6) -> Netmask<Ipv6Addr> {
279 None
280}
281
282fn make_mac_address(adapter_address: &AdapterAddress) -> MacAddress {
284 let mac_addr_len = adapter_address.PhysicalAddressLength as usize;
286 match mac_addr_len {
287 0 => None,
288 len => Some(format!(
289 "{}",
290 HexSlice::new(&adapter_address.PhysicalAddress[..len])
291 )),
292 }
293}
294
295fn get_adapter_address_index(adapter_address: &AdapterAddress) -> Result<u32> {
296 let adapter_luid = &adapter_address.Luid as *const IF_LUID;
297
298 let index = &mut 0u32 as *mut u32;
299
300 match unsafe { ConvertInterfaceLuidToIndex(adapter_luid, index) } {
301 0 => Ok(unsafe { *index }),
302 e => Err(crate::error::Error::GetIfNameError(
303 "ConvertInterfaceLuidToIndex".to_string(),
304 e,
305 )),
306 }
307}
308
309trait IterableRawPointer {
311 type Pointer;
312 type Value;
313
314 fn next(&self) -> Self::Pointer;
317}
318
319struct RawPointerWrapper<'a, T>(*const T, PhantomData<&'a T>)
321where
322 T: IterableRawPointer<Value = T, Pointer = *const T>;
323
324impl<'a, T> RawPointerWrapper<'a, T>
325where
326 T: IterableRawPointer<Value = T, Pointer = *const T>,
327{
328 fn new(ptr: *const T) -> RawPointerWrapper<'a, T> {
329 Self(ptr, PhantomData)
330 }
331}
332
333impl<'a, T> Iterator for RawPointerWrapper<'a, T>
335where
336 T: IterableRawPointer<Value = T, Pointer = *const T>,
337{
338 type Item = &'a T::Value;
339
340 fn next(&mut self) -> Option<Self::Item> {
341 let ret = unsafe { self.0.as_ref() };
342 if let Some(v) = ret {
343 self.0 = v.next();
344 }
345 ret
346 }
347}
348
349#[cfg(test)]
350mod tests {
351 use std::{process::Command, cmp::min};
352
353 use crate::{NetworkInterface, NetworkInterfaceConfig, Addr};
354
355 #[test]
356 fn test_mac_addr() {
357 const MAC_ADDR_LEN: usize = "00:22:48:03:ED:76".len();
358
359 let output = Command::new("getmac").arg("/nh").output().unwrap().stdout;
360 let output_string = String::from_utf8(output).unwrap();
361 let mac_addr_list: Vec<_> = output_string
362 .lines()
363 .filter_map(|line| {
364 let line = line.trim();
365 let line = &line[..min(MAC_ADDR_LEN, line.len())];
366 match line.split('-').count() {
367 6 => Some(line.replace('-', ":")),
368 _ => None,
369 }
370 })
371 .collect();
372 assert!(!mac_addr_list.is_empty());
373
374 let interfaces = NetworkInterface::show().unwrap();
375 for mac_addr in mac_addr_list {
376 assert!(interfaces
377 .iter()
378 .any(|int| int.mac_addr.as_ref() == Some(&mac_addr)));
379 }
380 }
381
382 #[test]
383 fn test_ipv4_broadcast() {
385 let interfaces = NetworkInterface::show().unwrap();
386 for ipv4 in interfaces.iter().flat_map(|i| &i.addr).filter_map(|addr| {
387 if let Addr::V4(ipv4) = addr {
388 Some(ipv4)
389 } else {
390 None
391 }
392 }) {
393 let Some(bc_addr) = ipv4.broadcast else {
394 continue;
395 };
396 let ip_bytes = ipv4.ip.octets();
397 let mask_bytes = ipv4.netmask.unwrap().octets();
398 let bc_bytes = bc_addr.octets();
399 for i in 0..4 {
400 assert_eq!(ip_bytes[i] & mask_bytes[i], bc_bytes[i] & mask_bytes[i]);
401 assert_eq!(bc_bytes[i] | mask_bytes[i], 255);
402 }
403 }
404 }
405}