use libc::{c_void, free, malloc, size_t};
use winapi::ctypes::*;
use winapi::shared::minwindef::*;
use winapi::shared::winerror::{ERROR_BUFFER_OVERFLOW, ERROR_SUCCESS};
use winapi::shared::ws2def::{AF_INET6, AF_INET, AF_UNSPEC, SOCKADDR};
use winapi::shared::ws2ipdef::SOCKADDR_IN6_LH;
use super::{c_char_array_to_string, last_os_error, u16_array_to_string};
use crate::data::*;
use std::collections::BTreeMap;
use std::io::Write;
use std::{io, mem, ptr};
#[repr(C)]
struct LengthIfIndex {
length: ULONG,
ifindex: DWORD,
}
#[repr(C)]
struct LengthFlags {
length: ULONG,
flags: DWORD,
}
#[repr(C)]
struct SoketAddress {
lp_sockaddr: *mut SOCKADDR,
i_sockaddr_length: c_int,
}
#[repr(C)]
struct IpAdapterPrefix {
aol: LengthIfIndex,
next: *mut IpAdapterPrefix,
address: SoketAddress,
prefix_length: ULONG,
}
#[repr(C)]
struct IpAdapterUnicastAddress {
aol: LengthFlags,
next: *mut IpAdapterUnicastAddress,
address: SoketAddress,
prefix_origin: c_int,
suffix_origin: c_int,
dad_state: c_int,
valid_lifetime: ULONG,
preferred_lifetime: ULONG,
lease_lifetime: ULONG,
on_link_prefix_length: u8,
}
const MAX_ADAPTER_ADDRESS_LENGTH: usize = 8;
#[repr(C)]
struct IpAdapterAddresses {
aol: LengthIfIndex,
next: *mut IpAdapterAddresses,
adapter_name: *mut c_char,
first_unicass_address: *mut IpAdapterUnicastAddress,
first_anycass_address: *const c_void,
first_multicass_address: *const c_void,
first_dns_server_address: *const c_void,
dns_suffix: *mut wchar_t,
description: *mut wchar_t,
friendly_name: *mut wchar_t,
physical_address: [u8; MAX_ADAPTER_ADDRESS_LENGTH],
physical_address_length: DWORD,
flags: DWORD,
mtu: DWORD,
if_type: DWORD,
oper_status: c_int,
ipv6_if_index: DWORD,
zone_indices: [DWORD; 16],
first_prefix: *mut IpAdapterPrefix,
}
#[link(name = "iphlpapi")]
extern "system" {
fn GetAdaptersAddresses(
family: ULONG,
flags: ULONG,
reserved: *const c_void,
addresses: *mut IpAdapterAddresses,
size: *mut ULONG,
) -> ULONG;
}
const WORKING_BUFFER_SIZEL: size_t = 15000;
pub fn get() -> io::Result<BTreeMap<String, Network>> {
let mut new_size: ULONG = WORKING_BUFFER_SIZEL as ULONG;
let mut p_adapter: *mut IpAdapterAddresses;
loop {
unsafe {
p_adapter = malloc(new_size as size_t) as *mut IpAdapterAddresses;
if p_adapter.is_null() {
panic!("Failed: malloc!");
}
let res_code = GetAdaptersAddresses(
0,
AF_UNSPEC as ULONG, ptr::null(),
p_adapter,
&mut new_size as *mut ULONG,
);
match res_code {
ERROR_SUCCESS => break,
ERROR_BUFFER_OVERFLOW => {
new_size *= 2;
free(p_adapter as *mut c_void);
continue;
}
_ => {
free(p_adapter as *mut c_void);
last_os_error()?;
}
}
}
}
let mut map = BTreeMap::new();
unsafe {
let mut cur_p_adapter = p_adapter;
while !cur_p_adapter.is_null() {
let adapter_name = c_char_array_to_string((*cur_p_adapter).adapter_name);
let friendly_name = u16_array_to_string((*cur_p_adapter).friendly_name);
let mut addrs = Vec::new();
let mut cur_p_addr = (*cur_p_adapter).first_unicass_address;
while !cur_p_addr.is_null() {
let addr = parse_addr_and_netmask(
(*cur_p_addr).address.lp_sockaddr,
(*cur_p_addr).on_link_prefix_length,
);
addrs.push(addr);
cur_p_addr = (*cur_p_addr).next;
}
let network = Network {
name: friendly_name,
addrs,
};
map.insert(adapter_name, network);
cur_p_adapter = (*cur_p_adapter).next;
}
}
unsafe {
free(p_adapter as *mut c_void);
}
Ok(map)
}
fn _physical_address_to_string(array: [u8; 8], length: DWORD) -> String {
let mut bytes = Vec::with_capacity(length as usize);
for (idx, b) in array.iter().enumerate().take(length as usize) {
if idx == 0 {
write!(&mut bytes, "{:02X}", b).unwrap();
} else {
write!(&mut bytes, "-{:02X}", b).unwrap();
}
}
String::from_utf8_lossy(&bytes[..]).into_owned()
}
fn parse_addr_and_netmask(aptr: *const SOCKADDR, net_bits: u8) -> NetworkAddrs {
if aptr.is_null() {
return NetworkAddrs {
addr: IpAddr::Empty,
netmask: IpAddr::Empty,
};
}
let addr = unsafe { *aptr };
match addr.sa_family as i32 {
AF_INET => {
let addr = IpAddr::V4(Ipv4Addr::new(
addr.sa_data[2] as u8,
addr.sa_data[3] as u8,
addr.sa_data[4] as u8,
addr.sa_data[5] as u8,
));
let netmask = if net_bits <= 32 {
IpAddr::V4(netmask_v4(net_bits))
} else {
IpAddr::Empty
};
NetworkAddrs { addr, netmask }
}
AF_INET6 => {
#[allow(clippy::cast_ptr_alignment)]
let addr6: *const SOCKADDR_IN6_LH = aptr as *const SOCKADDR_IN6_LH;
let mut a: [u8; 16] = unsafe { *std::ptr::read_unaligned(addr6).sin6_addr.u.Byte() };
a[..].reverse();
let a: [u16; 8] = unsafe { mem::transmute(a) };
let addr = IpAddr::V6(Ipv6Addr::new(
a[7],
a[6],
a[5],
a[4],
a[3],
a[2],
a[1],
a[0],
));
let netmask = if net_bits <= 128 {
IpAddr::V6(netmask_v6(net_bits))
} else {
IpAddr::Empty
};
NetworkAddrs { addr, netmask }
}
_ => NetworkAddrs {
addr: IpAddr::Empty,
netmask: IpAddr::Empty,
},
}
}
fn netmask_v4(bits: u8) -> Ipv4Addr {
let mut i = (0..4).map(|idx| {
let idx8 = idx << 3;
match (bits as usize > idx8, bits as usize > idx8 + 8) {
(true, true) => 255,
(true, false) => 255u8.wrapping_shl((8 - bits % 8) as u32),
_ => 0,
}
});
Ipv4Addr::new(
i.next().unwrap(),
i.next().unwrap(),
i.next().unwrap(),
i.next().unwrap(),
)
}
fn netmask_v6(bits: u8) -> Ipv6Addr {
let mut tmp = [0u16; 8];
(0..8).for_each(|idx| {
let idx16 = idx << 4;
match (bits as usize > idx16, bits as usize > idx16 + 16) {
(true, true) => {
tmp[idx] = 0xffff;
}
(true, false) => {
tmp[idx] = 0xffffu16.wrapping_shl((16 - bits % 16) as u32);
}
_ => {}
}
});
Ipv6Addr::new(
tmp[0],
tmp[1],
tmp[2],
tmp[3],
tmp[4],
tmp[5],
tmp[6],
tmp[7],
)
}
#[test]
fn netmask_v4_test() {
vec![
(0, "0.0.0.0"),
(1, "128.0.0.0"),
(2, "192.0.0.0"),
(3, "224.0.0.0"),
(4, "240.0.0.0"),
(5, "248.0.0.0"),
(6, "252.0.0.0"),
(7, "254.0.0.0"),
(8, "255.0.0.0"),
(9, "255.128.0.0"),
(10, "255.192.0.0"),
(11, "255.224.0.0"),
(12, "255.240.0.0"),
(13, "255.248.0.0"),
(14, "255.252.0.0"),
(15, "255.254.0.0"),
(16, "255.255.0.0"),
(17, "255.255.128.0"),
(18, "255.255.192.0"),
(19, "255.255.224.0"),
(20, "255.255.240.0"),
(21, "255.255.248.0"),
(22, "255.255.252.0"),
(23, "255.255.254.0"),
(24, "255.255.255.0"),
(25, "255.255.255.128"),
(26, "255.255.255.192"),
(27, "255.255.255.224"),
(28, "255.255.255.240"),
(29, "255.255.255.248"),
(30, "255.255.255.252"),
(31, "255.255.255.254"),
(32, "255.255.255.255"),
].into_iter()
.for_each(|(i, addr)| assert_eq!(netmask_v4(i), addr.parse::<Ipv4Addr>().unwrap()))
}
#[test]
fn netmask_v6_test() {
vec![
(0, "::"),
(1, "8000::"),
(2, "c000::"),
(3, "e000::"),
(4, "f000::"),
(5, "f800::"),
(6, "fc00::"),
(7, "fe00::"),
(8, "ff00::"),
(9, "ff80::"),
(10, "ffc0::"),
(11, "ffe0::"),
(12, "fff0::"),
(13, "fff8::"),
(14, "fffc::"),
(15, "fffe::"),
(16, "ffff::"),
(17, "ffff:8000::"),
(18, "ffff:c000::"),
(19, "ffff:e000::"),
(20, "ffff:f000::"),
(21, "ffff:f800::"),
(22, "ffff:fc00::"),
(23, "ffff:fe00::"),
(24, "ffff:ff00::"),
(25, "ffff:ff80::"),
(26, "ffff:ffc0::"),
(27, "ffff:ffe0::"),
(28, "ffff:fff0::"),
(29, "ffff:fff8::"),
(30, "ffff:fffc::"),
(31, "ffff:fffe::"),
(32, "ffff:ffff::"),
(33, "ffff:ffff:8000::"),
(34, "ffff:ffff:c000::"),
(35, "ffff:ffff:e000::"),
(36, "ffff:ffff:f000::"),
(37, "ffff:ffff:f800::"),
(38, "ffff:ffff:fc00::"),
(39, "ffff:ffff:fe00::"),
(40, "ffff:ffff:ff00::"),
(41, "ffff:ffff:ff80::"),
(42, "ffff:ffff:ffc0::"),
(43, "ffff:ffff:ffe0::"),
(44, "ffff:ffff:fff0::"),
(45, "ffff:ffff:fff8::"),
(46, "ffff:ffff:fffc::"),
(47, "ffff:ffff:fffe::"),
(48, "ffff:ffff:ffff::"),
(49, "ffff:ffff:ffff:8000::"),
(50, "ffff:ffff:ffff:c000::"),
(51, "ffff:ffff:ffff:e000::"),
(52, "ffff:ffff:ffff:f000::"),
(53, "ffff:ffff:ffff:f800::"),
(54, "ffff:ffff:ffff:fc00::"),
(55, "ffff:ffff:ffff:fe00::"),
(56, "ffff:ffff:ffff:ff00::"),
(57, "ffff:ffff:ffff:ff80::"),
(58, "ffff:ffff:ffff:ffc0::"),
(59, "ffff:ffff:ffff:ffe0::"),
(60, "ffff:ffff:ffff:fff0::"),
(61, "ffff:ffff:ffff:fff8::"),
(62, "ffff:ffff:ffff:fffc::"),
(63, "ffff:ffff:ffff:fffe::"),
(64, "ffff:ffff:ffff:ffff::"),
(65, "ffff:ffff:ffff:ffff:8000::"),
(66, "ffff:ffff:ffff:ffff:c000::"),
(67, "ffff:ffff:ffff:ffff:e000::"),
(68, "ffff:ffff:ffff:ffff:f000::"),
(69, "ffff:ffff:ffff:ffff:f800::"),
(70, "ffff:ffff:ffff:ffff:fc00::"),
(71, "ffff:ffff:ffff:ffff:fe00::"),
(72, "ffff:ffff:ffff:ffff:ff00::"),
(73, "ffff:ffff:ffff:ffff:ff80::"),
(74, "ffff:ffff:ffff:ffff:ffc0::"),
(75, "ffff:ffff:ffff:ffff:ffe0::"),
(76, "ffff:ffff:ffff:ffff:fff0::"),
(77, "ffff:ffff:ffff:ffff:fff8::"),
(78, "ffff:ffff:ffff:ffff:fffc::"),
(79, "ffff:ffff:ffff:ffff:fffe::"),
(80, "ffff:ffff:ffff:ffff:ffff::"),
(81, "ffff:ffff:ffff:ffff:ffff:8000::"),
(82, "ffff:ffff:ffff:ffff:ffff:c000::"),
(83, "ffff:ffff:ffff:ffff:ffff:e000::"),
(84, "ffff:ffff:ffff:ffff:ffff:f000::"),
(85, "ffff:ffff:ffff:ffff:ffff:f800::"),
(86, "ffff:ffff:ffff:ffff:ffff:fc00::"),
(87, "ffff:ffff:ffff:ffff:ffff:fe00::"),
(88, "ffff:ffff:ffff:ffff:ffff:ff00::"),
(89, "ffff:ffff:ffff:ffff:ffff:ff80::"),
(90, "ffff:ffff:ffff:ffff:ffff:ffc0::"),
(91, "ffff:ffff:ffff:ffff:ffff:ffe0::"),
(92, "ffff:ffff:ffff:ffff:ffff:fff0::"),
(93, "ffff:ffff:ffff:ffff:ffff:fff8::"),
(94, "ffff:ffff:ffff:ffff:ffff:fffc::"),
(95, "ffff:ffff:ffff:ffff:ffff:fffe::"),
(96, "ffff:ffff:ffff:ffff:ffff:ffff::"),
(97, "ffff:ffff:ffff:ffff:ffff:ffff:8000:0"),
(98, "ffff:ffff:ffff:ffff:ffff:ffff:c000:0"),
(99, "ffff:ffff:ffff:ffff:ffff:ffff:e000:0"),
(100, "ffff:ffff:ffff:ffff:ffff:ffff:f000:0"),
(101, "ffff:ffff:ffff:ffff:ffff:ffff:f800:0"),
(102, "ffff:ffff:ffff:ffff:ffff:ffff:fc00:0"),
(103, "ffff:ffff:ffff:ffff:ffff:ffff:fe00:0"),
(104, "ffff:ffff:ffff:ffff:ffff:ffff:ff00:0"),
(105, "ffff:ffff:ffff:ffff:ffff:ffff:ff80:0"),
(106, "ffff:ffff:ffff:ffff:ffff:ffff:ffc0:0"),
(107, "ffff:ffff:ffff:ffff:ffff:ffff:ffe0:0"),
(108, "ffff:ffff:ffff:ffff:ffff:ffff:fff0:0"),
(109, "ffff:ffff:ffff:ffff:ffff:ffff:fff8:0"),
(110, "ffff:ffff:ffff:ffff:ffff:ffff:fffc:0"),
(111, "ffff:ffff:ffff:ffff:ffff:ffff:fffe:0"),
(112, "ffff:ffff:ffff:ffff:ffff:ffff:ffff:0"),
(113, "ffff:ffff:ffff:ffff:ffff:ffff:ffff:8000"),
(114, "ffff:ffff:ffff:ffff:ffff:ffff:ffff:c000"),
(115, "ffff:ffff:ffff:ffff:ffff:ffff:ffff:e000"),
(116, "ffff:ffff:ffff:ffff:ffff:ffff:ffff:f000"),
(117, "ffff:ffff:ffff:ffff:ffff:ffff:ffff:f800"),
(118, "ffff:ffff:ffff:ffff:ffff:ffff:ffff:fc00"),
(119, "ffff:ffff:ffff:ffff:ffff:ffff:ffff:fe00"),
(120, "ffff:ffff:ffff:ffff:ffff:ffff:ffff:ff00"),
(121, "ffff:ffff:ffff:ffff:ffff:ffff:ffff:ff80"),
(122, "ffff:ffff:ffff:ffff:ffff:ffff:ffff:ffc0"),
(123, "ffff:ffff:ffff:ffff:ffff:ffff:ffff:ffe0"),
(124, "ffff:ffff:ffff:ffff:ffff:ffff:ffff:fff0"),
(125, "ffff:ffff:ffff:ffff:ffff:ffff:ffff:fff8"),
(126, "ffff:ffff:ffff:ffff:ffff:ffff:ffff:fffc"),
(127, "ffff:ffff:ffff:ffff:ffff:ffff:ffff:fffe"),
(128, "ffff:ffff:ffff:ffff:ffff:ffff:ffff:ffff"),
].into_iter()
.for_each(|(i, addr)| assert_eq!(netmask_v6(i), addr.parse::<Ipv6Addr>().unwrap()))
}