mod bindings {
windows::include_bindings!();
}
use std::ffi::c_void;
use std::mem::size_of;
use std::net::{Ipv4Addr, Ipv6Addr};
use std::ptr::null_mut;
use std::slice::from_raw_parts;
use libc::{free, malloc, wchar_t, wcslen};
use crate::interface::Netmask;
use crate::{Error, NetworkInterface, NetworkInterfaceConfig, Result};
use self::bindings::Windows::Win32;
use self::Win32::Networking::WinSock::{SOCKADDR_IN, SOCKADDR_IN6};
use self::Win32::NetworkManagement::IpHelper::{
ADDRESS_FAMILY, AF_UNSPEC, IP_ADAPTER_ADDRESSES_LH, IP_ADAPTER_UNICAST_ADDRESS_LH,
ConvertLengthToIpv4Mask, GetAdaptersAddresses,
};
type AdapterAddress = IP_ADAPTER_ADDRESSES_LH;
type GetAdaptersAddressesFlags =
self::Win32::NetworkManagement::IpHelper::GET_ADAPTERS_ADDRESSES_FLAGS;
const ERROR_BUFFER_OVERFLOW: u32 = 111;
const MAX_TRIES: usize = 3;
const GET_ADAPTERS_ADDRESSES_SUCCESS_RESULT: u32 = 0;
const AF_INET: u16 = self::Win32::NetworkManagement::IpHelper::AF_INET.0 as u16;
const AF_INET6: u16 = self::Win32::NetworkManagement::IpHelper::AF_INET6.0 as u16;
const GET_ADAPTERS_ADDRESSES_FAMILY: ADDRESS_FAMILY = ADDRESS_FAMILY(AF_UNSPEC.0);
const GET_ADAPTERS_ADDRESSES_FLAGS: GetAdaptersAddressesFlags =
self::Win32::NetworkManagement::IpHelper::GET_ADAPTERS_ADDRESSES_FLAGS(0x0);
impl NetworkInterfaceConfig for NetworkInterface {
fn show() -> Result<Vec<NetworkInterface>> {
let mut size_pointer: u32 = 15000;
let mut adapter_address = unsafe { malloc(size_pointer as usize) as *mut AdapterAddress };
let mut iterations = 0;
let mut get_adapter_addresses_result = 0;
let mut network_interfaces: Vec<NetworkInterface> = Vec::new();
while get_adapter_addresses_result != ERROR_BUFFER_OVERFLOW || iterations <= MAX_TRIES {
adapter_address = unsafe { malloc(size_pointer as usize) as *mut AdapterAddress };
if adapter_address.is_null() {
return Err(Error::GetIfAddrsError(
String::from("GetAdaptersAddresses"),
1,
));
}
get_adapter_addresses_result = unsafe {
GetAdaptersAddresses(
GET_ADAPTERS_ADDRESSES_FAMILY,
GET_ADAPTERS_ADDRESSES_FLAGS,
null_mut::<c_void>(),
adapter_address,
&mut size_pointer,
)
};
if get_adapter_addresses_result == ERROR_BUFFER_OVERFLOW {
unsafe {
free(adapter_address as *mut c_void);
};
adapter_address = null_mut();
} else {
break;
}
iterations += 1;
}
if get_adapter_addresses_result == GET_ADAPTERS_ADDRESSES_SUCCESS_RESULT {
while !adapter_address.is_null() {
let address_name = make_adapter_address_name(&adapter_address)?;
let mut current_unicast_address = unsafe { (*adapter_address).FirstUnicastAddress };
while !current_unicast_address.is_null() {
let address = unsafe { (*current_unicast_address).Address };
match unsafe { (*address.lpSockaddr).sa_family } {
AF_INET => {
let sockaddr: *mut SOCKADDR_IN = address.lpSockaddr as *mut SOCKADDR_IN;
let addr = make_ipv4_addr(&sockaddr)?;
let netmask = make_ipv4_netmask(¤t_unicast_address);
let network_interface =
NetworkInterface::new_afinet(&address_name, addr, netmask, None);
network_interfaces.push(network_interface);
}
AF_INET6 => {
let sockaddr: *mut SOCKADDR_IN6 =
address.lpSockaddr as *mut SOCKADDR_IN6;
let addr = make_ipv6_addr(&sockaddr)?;
let netmask = make_ipv6_netmask(&sockaddr);
let network_interface =
NetworkInterface::new_afinet6(&address_name, addr, netmask, None);
network_interfaces.push(network_interface);
}
_ => {}
}
if !current_unicast_address.is_null() {
println!("BEFORE: {:#?}", current_unicast_address);
current_unicast_address = unsafe { (*current_unicast_address).Next };
println!("AFTER: {:#?}", current_unicast_address);
}
}
if !adapter_address.is_null() {
adapter_address = unsafe { (*adapter_address).Next };
}
}
}
Ok(network_interfaces)
}
}
fn make_adapter_address_name(adapter_address: &*mut AdapterAddress) -> Result<String> {
let address_name = unsafe { (*(*adapter_address)).FriendlyName.0 };
let address_name_length = unsafe { wcslen(address_name as *const wchar_t) };
let byte_slice = unsafe { from_raw_parts(address_name, address_name_length) };
let string = String::from_utf16(byte_slice).map_err(Error::from)?;
Ok(string)
}
fn make_ipv6_addr(sockaddr: &*mut SOCKADDR_IN6) -> Result<Ipv6Addr> {
let address_bytes = unsafe { (*(*sockaddr)).sin6_addr.u.Byte };
let ip = Ipv6Addr::from(address_bytes);
Ok(ip)
}
fn make_ipv4_addr(sockaddr: &*mut SOCKADDR_IN) -> Result<Ipv4Addr> {
let address = unsafe { (*(*sockaddr)).sin_addr.S_un.S_addr };
if cfg!(target_endian = "little") {
return Ok(Ipv4Addr::from(address.swap_bytes()));
}
Ok(Ipv4Addr::from(address))
}
fn make_ipv4_netmask(unicast_address: &*mut IP_ADAPTER_UNICAST_ADDRESS_LH) -> Netmask<Ipv4Addr> {
let mask = unsafe { malloc(size_of::<u32>()) as *mut u32 };
let on_link_prefix_length = unsafe { (*(*unicast_address)).OnLinkPrefixLength };
match unsafe { ConvertLengthToIpv4Mask(on_link_prefix_length as u32, mask) } {
Ok(_) => {
let mask = unsafe { *mask };
if cfg!(target_endian = "little") {
return Some(Ipv4Addr::from(mask.swap_bytes()));
}
Some(Ipv4Addr::from(mask))
}
Err(_) => None,
}
}
fn make_ipv6_netmask(_sockaddr: &*mut SOCKADDR_IN6) -> Netmask<Ipv6Addr> {
None
}
#[cfg(target_os = "windows")]
mod tests {
#[test]
fn show_network_interfaces() {
use super::{NetworkInterface, NetworkInterfaceConfig};
let network_interfaces = NetworkInterface::show().unwrap();
assert!(network_interfaces.len() > 1);
}
}