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