#![allow(clippy::cast_ptr_alignment)]
use std;
use std::convert::TryFrom;
use std::ffi::CStr;
use std::net::IpAddr;
use crate::error::*;
use socket2;
use widestring::WideCString;
use windows_sys::Win32::Foundation::ERROR_BUFFER_OVERFLOW;
use windows_sys::Win32::Foundation::ERROR_SUCCESS;
use windows_sys::Win32::Networking::WinSock::AF_UNSPEC;
use crate::bindings::*;
#[derive(Debug, Clone, Copy, PartialEq)]
pub enum OperStatus {
IfOperStatusUp = 1,
IfOperStatusDown = 2,
IfOperStatusTesting = 3,
IfOperStatusUnknown = 4,
IfOperStatusDormant = 5,
IfOperStatusNotPresent = 6,
IfOperStatusLowerLayerDown = 7,
}
#[derive(Debug, Clone, Copy, PartialEq)]
pub enum IfType {
Other = 1,
EthernetCsmacd = 6,
Iso88025Tokenring = 9,
Ppp = 23,
SoftwareLoopback = 24,
Atm = 37,
Ieee80211 = 71,
Tunnel = 131,
Ieee1394 = 144,
Unsupported,
#[doc(hidden)]
__Nonexhaustive,
}
#[derive(Debug)]
pub struct Adapter {
adapter_name: String,
ip_addresses: Vec<IpAddr>,
prefixes: Vec<(IpAddr, u32)>,
gateways: Vec<IpAddr>,
dns_servers: Vec<IpAddr>,
description: String,
friendly_name: String,
physical_address: Option<Vec<u8>>,
receive_link_speed: u64,
transmit_link_speed: u64,
oper_status: OperStatus,
if_type: IfType,
ipv6_if_index: u32,
ipv4_metric: u32,
ipv6_metric: u32,
}
impl Adapter {
pub fn adapter_name(&self) -> &str {
&self.adapter_name
}
pub fn ip_addresses(&self) -> &[IpAddr] {
&self.ip_addresses
}
pub fn prefixes(&self) -> &[(IpAddr, u32)] {
&self.prefixes
}
pub fn gateways(&self) -> &[IpAddr] {
&self.gateways
}
pub fn dns_servers(&self) -> &[IpAddr] {
&self.dns_servers
}
pub fn description(&self) -> &str {
&self.description
}
pub fn friendly_name(&self) -> &str {
&self.friendly_name
}
pub fn physical_address(&self) -> Option<&[u8]> {
self.physical_address.as_ref().map(std::vec::Vec::as_slice)
}
pub fn receive_link_speed(&self) -> u64 {
self.receive_link_speed
}
pub fn transmit_link_speed(&self) -> u64 {
self.transmit_link_speed
}
pub fn oper_status(&self) -> OperStatus {
self.oper_status
}
pub fn if_type(&self) -> IfType {
self.if_type
}
pub fn ipv6_if_index(&self) -> u32 {
self.ipv6_if_index
}
pub fn ipv4_metric(&self) -> u32 {
self.ipv4_metric
}
pub fn ipv6_metric(&self) -> u32 {
self.ipv6_metric
}
}
pub fn get_adapters() -> Result<Vec<Adapter>> {
unsafe {
let mut buf_len: ULONG = 16384;
let mut adapters_addresses_buffer = Vec::new();
let mut result = ERROR_BUFFER_OVERFLOW;
while result == ERROR_BUFFER_OVERFLOW {
adapters_addresses_buffer.resize(buf_len as usize, 0);
result = GetAdaptersAddresses(
AF_UNSPEC as u32,
0x0080 | 0x0010, std::ptr::null_mut(),
adapters_addresses_buffer.as_mut_ptr() as PIP_ADAPTER_ADDRESSES,
&mut buf_len as *mut ULONG,
);
}
if result != ERROR_SUCCESS {
return Err(Error {
kind: ErrorKind::Os(result),
});
}
let mut adapters = vec![];
let mut adapter_addresses_ptr =
adapters_addresses_buffer.as_mut_ptr() as PIP_ADAPTER_ADDRESSES;
while !adapter_addresses_ptr.is_null() {
adapters.push(get_adapter(adapter_addresses_ptr)?);
adapter_addresses_ptr = adapter_addresses_ptr.read_unaligned().Next;
}
Ok(adapters)
}
}
unsafe fn get_adapter(adapter_addresses_ptr: PIP_ADAPTER_ADDRESSES) -> Result<Adapter> {
let adapter_addresses = adapter_addresses_ptr.read_unaligned();
let adapter_name = CStr::from_ptr(adapter_addresses.AdapterName)
.to_str()?
.to_owned();
let dns_servers = get_dns_servers(adapter_addresses.FirstDnsServerAddress)?;
let gateways = get_gateways(adapter_addresses.FirstGatewayAddress)?;
let prefixes = get_prefixes(adapter_addresses.FirstPrefix)?;
let unicast_addresses = get_unicast_addresses(adapter_addresses.FirstUnicastAddress)?;
let receive_link_speed: u64 = adapter_addresses.ReceiveLinkSpeed;
let transmit_link_speed: u64 = adapter_addresses.TransmitLinkSpeed;
let ipv4_metric = adapter_addresses.Ipv4Metric;
let ipv6_metric = adapter_addresses.Ipv6Metric;
let oper_status = match adapter_addresses.OperStatus {
1 => OperStatus::IfOperStatusUp,
2 => OperStatus::IfOperStatusDown,
3 => OperStatus::IfOperStatusTesting,
4 => OperStatus::IfOperStatusUnknown,
5 => OperStatus::IfOperStatusDormant,
6 => OperStatus::IfOperStatusNotPresent,
7 => OperStatus::IfOperStatusLowerLayerDown,
v => {
panic!("unexpected OperStatus value: {}", v);
}
};
let if_type = match adapter_addresses.IfType {
1 => IfType::Other,
6 => IfType::EthernetCsmacd,
9 => IfType::Iso88025Tokenring,
23 => IfType::Ppp,
24 => IfType::SoftwareLoopback,
37 => IfType::Atm,
71 => IfType::Ieee80211,
131 => IfType::Tunnel,
144 => IfType::Ieee1394,
_ => IfType::Unsupported,
};
let ipv6_if_index = adapter_addresses.Ipv6IfIndex;
let description = WideCString::from_ptr_str(adapter_addresses.Description).to_string()?;
let friendly_name = WideCString::from_ptr_str(adapter_addresses.FriendlyName).to_string()?;
let physical_address = if adapter_addresses.PhysicalAddressLength == 0 {
None
} else {
Some(
adapter_addresses.PhysicalAddress[..adapter_addresses.PhysicalAddressLength as usize]
.to_vec(),
)
};
Ok(Adapter {
adapter_name,
ip_addresses: unicast_addresses,
prefixes,
gateways,
dns_servers,
description,
friendly_name,
physical_address,
receive_link_speed,
transmit_link_speed,
oper_status,
if_type,
ipv6_if_index,
ipv4_metric,
ipv6_metric,
})
}
unsafe fn socket_address_to_ipaddr(socket_address: &SOCKET_ADDRESS) -> IpAddr {
let (_, sockaddr) = socket2::SockAddr::try_init(|storage, length| {
let sockaddr_length = usize::try_from(socket_address.iSockaddrLength).unwrap();
assert!(sockaddr_length <= std::mem::size_of_val(&storage.read_unaligned()));
let dst: *mut u8 = storage.cast();
let src: *const u8 = socket_address.lpSockaddr.cast();
dst.copy_from_nonoverlapping(src, sockaddr_length);
std::ptr::write_unaligned(length, socket_address.iSockaddrLength);
Ok(())
})
.unwrap();
sockaddr.as_socket().map(|s| s.ip()).unwrap()
}
unsafe fn get_dns_servers(
mut dns_server_ptr: PIP_ADAPTER_DNS_SERVER_ADDRESS_XP,
) -> Result<Vec<IpAddr>> {
let mut dns_servers = vec![];
while !dns_server_ptr.is_null() {
let dns_server = dns_server_ptr.read_unaligned();
let ipaddr = socket_address_to_ipaddr(&dns_server.Address);
dns_servers.push(ipaddr);
dns_server_ptr = dns_server.Next;
}
Ok(dns_servers)
}
unsafe fn get_gateways(mut gateway_ptr: PIP_ADAPTER_GATEWAY_ADDRESS_LH) -> Result<Vec<IpAddr>> {
let mut gateways = vec![];
while !gateway_ptr.is_null() {
let gateway = gateway_ptr.read_unaligned();
let ipaddr = socket_address_to_ipaddr(&gateway.Address);
gateways.push(ipaddr);
gateway_ptr = gateway.Next;
}
Ok(gateways)
}
unsafe fn get_unicast_addresses(
mut unicast_addresses_ptr: PIP_ADAPTER_UNICAST_ADDRESS_LH,
) -> Result<Vec<IpAddr>> {
let mut unicast_addresses = vec![];
while !unicast_addresses_ptr.is_null() {
let unicast_address = unicast_addresses_ptr.read_unaligned();
let ipaddr = socket_address_to_ipaddr(&unicast_address.Address);
unicast_addresses.push(ipaddr);
unicast_addresses_ptr = unicast_address.Next;
}
Ok(unicast_addresses)
}
unsafe fn get_prefixes(mut prefixes_ptr: PIP_ADAPTER_PREFIX_XP) -> Result<Vec<(IpAddr, u32)>> {
let mut prefixes = vec![];
while !prefixes_ptr.is_null() {
let prefix = prefixes_ptr.read_unaligned();
let ipaddr = socket_address_to_ipaddr(&prefix.Address);
prefixes.push((ipaddr, prefix.PrefixLength));
prefixes_ptr = prefix.Next;
}
Ok(prefixes)
}