#![allow(unused, non_upper_case_globals)]
use winapi::shared::basetsd::{UINT32, UINT8, ULONG64};
use winapi::shared::guiddef::GUID;
use winapi::shared::minwindef::{BYTE, DWORD, PULONG, ULONG};
use winapi::shared::ws2def::SOCKET_ADDRESS;
use winapi::um::winnt::{PCHAR, PVOID, PWCHAR, WCHAR};
const MAX_ADAPTER_ADDRESS_LENGTH: usize = 8;
const ZONE_INDICES_LENGTH: usize = 16;
const MAX_DHCPV6_DUID_LENGTH: usize = 130;
const MAX_DNS_SUFFIX_STRING_LENGTH: usize = 256;
pub const IP_ADAPTER_IPV4_ENABLED: DWORD = 0x0080;
pub const IP_ADAPTER_IPV6_ENABLED: DWORD = 0x0100;
use std::net::{Ipv4Addr, SocketAddr, SocketAddrV4, SocketAddrV6};
use std::{io, mem, ptr};
use winapi::shared::winerror::{
ERROR_ADDRESS_NOT_ASSOCIATED, ERROR_BUFFER_OVERFLOW, ERROR_INVALID_PARAMETER,
ERROR_NOT_ENOUGH_MEMORY, ERROR_NO_DATA, ERROR_SUCCESS,
};
use winapi::shared::ws2def::{AF_INET, AF_INET6, AF_UNSPEC, SOCKADDR_IN};
use winapi::shared::ws2ipdef::SOCKADDR_IN6;
const PREALLOC_ADAPTERS_LEN: usize = 15 * 1024;
use crate::ifaces::{Interface, Kind, NextHop};
#[link(name = "iphlpapi")]
extern "system" {
pub fn GetAdaptersAddresses(
family: ULONG,
flags: ULONG,
reserved: PVOID,
addresses: *mut u8,
size: PULONG,
) -> ULONG;
}
#[repr(C)]
pub struct IpAdapterAddresses {
pub head: IpAdapterAddressesHead,
pub all: IpAdaptersAddressesAll,
pub xp: IpAdaptersAddressesXp,
pub vista: IpAdaptersAddressesVista,
}
#[repr(C)]
pub struct IpAdapterAddressesHead {
pub length: ULONG,
if_index: DWORD,
}
#[repr(C)]
pub struct IpAdaptersAddressesAll {
pub next: *const IpAdapterAddresses,
pub adapter_name: PCHAR,
pub first_unicast_address: *const IpAdapterUnicastAddress,
first_anycast_address: *const IpAdapterAnycastAddress,
first_multicast_address: *const IpAdapterMulticastAddress,
first_dns_server_address: *const IpAdapterDnsServerAddress,
dns_suffix: PWCHAR,
pub description: PWCHAR,
friendly_name: PWCHAR,
pub physical_address: [BYTE; MAX_ADAPTER_ADDRESS_LENGTH],
pub physical_address_length: DWORD,
pub flags: DWORD,
mtu: DWORD,
pub if_type: DWORD,
oper_status: IfOperStatus,
}
#[repr(C)]
pub struct IpAdaptersAddressesXp {
pub ipv6_if_index: DWORD,
pub zone_indices: [DWORD; ZONE_INDICES_LENGTH],
first_prefix: *const IpAdapterPrefix,
}
#[repr(C)]
pub struct IpAdaptersAddressesVista {
transmit_link_speed: ULONG64,
receive_link_speed: ULONG64,
first_wins_server_address: *const IpAdapterWinsServerAddress,
first_gateway_address: *const IpAdapterGatewayAddress,
ipv4_metric: ULONG,
ipv6_metric: ULONG,
luid: IfLuid,
dhcpv4_server: SOCKET_ADDRESS,
compartment_id: UINT32,
network_guid: GUID,
connection_type: NetIfConnectionType,
tunnel_type: TunnelType,
dhcpv6_server: SOCKET_ADDRESS,
dhcpv6_client_duid: [BYTE; MAX_DHCPV6_DUID_LENGTH],
dhcpv6_client_duid_length: ULONG,
dhcpv6_iaid: ULONG,
first_dns_suffix: *const IpAdapterDnsSuffix,
}
#[repr(C)]
pub struct IpAdapterUnicastAddress {
pub length: ULONG,
flags: DWORD,
pub next: *const IpAdapterUnicastAddress,
pub address: SOCKET_ADDRESS,
prefix_origin: IpPrefixOrigin,
suffix_origin: IpSuffixOrigin,
pub dad_state: IpDadState,
valid_lifetime: ULONG,
preferred_lifetime: ULONG,
lease_lifetime: ULONG,
on_link_prefix_length: UINT8,
}
#[repr(C)]
pub struct IpAdapterAnycastAddress {
length: ULONG,
flags: DWORD,
next: *const IpAdapterAnycastAddress,
address: SOCKET_ADDRESS,
}
#[repr(C)]
pub struct IpAdapterMulticastAddress {
length: ULONG,
flags: DWORD,
next: *const IpAdapterMulticastAddress,
address: SOCKET_ADDRESS,
}
#[repr(C)]
pub struct IpAdapterDnsServerAddress {
length: ULONG,
reserved: DWORD,
next: *const IpAdapterDnsServerAddress,
address: SOCKET_ADDRESS,
}
#[repr(C)]
pub struct IpAdapterPrefix {
length: ULONG,
flags: DWORD,
next: *const IpAdapterPrefix,
address: SOCKET_ADDRESS,
prefix_length: ULONG,
}
#[repr(C)]
pub struct IpAdapterWinsServerAddress {
length: ULONG,
reserved: DWORD,
next: *const IpAdapterWinsServerAddress,
address: SOCKET_ADDRESS,
}
#[repr(C)]
pub struct IpAdapterGatewayAddress {
length: ULONG,
reserved: DWORD,
next: *const IpAdapterGatewayAddress,
address: SOCKET_ADDRESS,
}
#[repr(C)]
pub struct IpAdapterDnsSuffix {
next: *const IpAdapterDnsSuffix,
string: [WCHAR; MAX_DNS_SUFFIX_STRING_LENGTH],
}
bitflags! {
struct IfLuid: ULONG64 {
const Reserved = 0x0000000000FFFFFF;
const NetLuidIndex = 0x0000FFFFFF000000;
const IfType = 0xFFFF00000000000;
}
}
#[repr(C)]
pub enum IpPrefixOrigin {
IpPrefixOriginOther = 0,
IpPrefixOriginManual,
IpPrefixOriginWellKnown,
IpPrefixOriginDhcp,
IpPrefixOriginRouterAdvertisement,
IpPrefixOriginUnchanged = 16,
}
#[repr(C)]
pub enum IpSuffixOrigin {
IpSuffixOriginOther = 0,
IpSuffixOriginManual,
IpSuffixOriginWellKnown,
IpSuffixOriginDhcp,
IpSuffixOriginLinkLayerAddress,
IpSuffixOriginRandom,
IpSuffixOriginUnchanged = 16,
}
#[derive(PartialEq, Eq)]
#[repr(C)]
pub enum IpDadState {
IpDadStateInvalid = 0,
IpDadStateTentative,
IpDadStateDuplicate,
IpDadStateDeprecated,
IpDadStatePreferred,
}
#[repr(C)]
pub enum IfOperStatus {
IfOperStatusUp = 1,
IfOperStatusDown = 2,
IfOperStatusTesting = 3,
IfOperStatusUnknown = 4,
IfOperStatusDormant = 5,
IfOperStatusNotPresent = 6,
IfOperStatusLowerLayerDown = 7,
}
#[repr(C)]
pub enum NetIfConnectionType {
NetIfConnectionDedicated = 1,
NetIfConnectionPassive = 2,
NetIfConnectionDemand = 3,
NetIfConnectionMaximum = 4,
}
#[repr(C)]
pub enum TunnelType {
TunnelTypeNone = 0,
TunnelTypeOther = 1,
TunnelTypeDirect = 2,
TunnelType6To4 = 11,
TunnelTypeIsatap = 13,
TunnelTypeTeredo = 14,
TunnelTypeIpHttps = 15,
}
unsafe fn v4_socket_from_adapter(unicast_addr: &IpAdapterUnicastAddress) -> SocketAddrV4 {
let socket_addr = &unicast_addr.address;
let in_addr: SOCKADDR_IN = mem::transmute(*socket_addr.lpSockaddr);
let sin_addr = in_addr.sin_addr.S_un;
let v4_addr = Ipv4Addr::new(
*sin_addr.S_addr() as u8,
(*sin_addr.S_addr() >> 8) as u8,
(*sin_addr.S_addr() >> 16) as u8,
(*sin_addr.S_addr() >> 24) as u8,
);
SocketAddrV4::new(v4_addr, 0)
}
unsafe fn v6_socket_from_adapter(unicast_addr: &IpAdapterUnicastAddress) -> SocketAddrV6 {
let socket_addr = &unicast_addr.address;
let sock_addr6: *const SOCKADDR_IN6 = socket_addr.lpSockaddr as *const SOCKADDR_IN6;
let in6_addr: SOCKADDR_IN6 = *sock_addr6;
let v6_addr = (*in6_addr.sin6_addr.u.Word()).into();
SocketAddrV6::new(
v6_addr,
0,
in6_addr.sin6_flowinfo,
*in6_addr.u.sin6_scope_id(),
)
}
unsafe fn local_ifaces_with_buffer(buffer: &mut Vec<u8>) -> io::Result<()> {
let mut length = buffer.capacity() as u32;
let ret_code = GetAdaptersAddresses(
AF_UNSPEC as u32,
0,
ptr::null_mut(),
buffer.as_mut_ptr(),
&mut length,
);
match ret_code {
ERROR_SUCCESS => Ok(()),
ERROR_ADDRESS_NOT_ASSOCIATED => Err(io::Error::new(
io::ErrorKind::AddrNotAvailable,
"An address has not yet been associated with the network endpoint.",
)),
ERROR_BUFFER_OVERFLOW => {
buffer.reserve_exact(length as usize);
local_ifaces_with_buffer(buffer)
}
ERROR_INVALID_PARAMETER => Err(io::Error::new(
io::ErrorKind::InvalidInput,
"One of the parameters is invalid.",
)),
ERROR_NOT_ENOUGH_MEMORY => Err(io::Error::new(
io::ErrorKind::Other,
"Insufficient memory resources are available to complete the operation.",
)),
ERROR_NO_DATA => Err(io::Error::new(
io::ErrorKind::AddrNotAvailable,
"No addresses were found for the requested parameters.",
)),
_ => Err(io::Error::new(
io::ErrorKind::Other,
"Some Other Error Occurred.",
)),
}
}
unsafe fn map_adapter_addresses(mut adapter_addr: *const IpAdapterAddresses) -> Vec<Interface> {
let mut adapter_addresses = Vec::new();
while !adapter_addr.is_null() {
let curr_adapter_addr = &*adapter_addr;
let mut unicast_addr = curr_adapter_addr.all.first_unicast_address;
while !unicast_addr.is_null() {
let curr_unicast_addr = &*unicast_addr;
if curr_unicast_addr.dad_state != IpDadState::IpDadStateDeprecated {
if is_ipv4_enabled(curr_unicast_addr) {
adapter_addresses.push(Interface {
name: "".to_string(),
kind: Kind::Ipv4,
addr: Some(SocketAddr::V4(v4_socket_from_adapter(curr_unicast_addr))),
mask: None,
hop: None,
});
} else if is_ipv6_enabled(curr_unicast_addr) {
let mut v6_sock = v6_socket_from_adapter(curr_unicast_addr);
v6_sock.set_scope_id(curr_adapter_addr.xp.ipv6_if_index);
adapter_addresses.push(Interface {
name: "".to_string(),
kind: Kind::Ipv6,
addr: Some(SocketAddr::V6(v6_sock)),
mask: None,
hop: None,
});
}
}
unicast_addr = curr_unicast_addr.next;
}
adapter_addr = curr_adapter_addr.all.next;
}
adapter_addresses
}
pub fn ifaces() -> Result<Vec<Interface>, ::std::io::Error> {
let mut adapters_list = Vec::with_capacity(PREALLOC_ADAPTERS_LEN);
unsafe {
local_ifaces_with_buffer(&mut adapters_list)?;
Ok(map_adapter_addresses(
adapters_list.as_ptr() as *const IpAdapterAddresses
))
}
}
unsafe fn is_ipv4_enabled(unicast_addr: &IpAdapterUnicastAddress) -> bool {
if unicast_addr.length != 0 {
let socket_addr = &unicast_addr.address;
let sa_family = (*socket_addr.lpSockaddr).sa_family;
sa_family == AF_INET as u16
} else {
false
}
}
unsafe fn is_ipv6_enabled(unicast_addr: &IpAdapterUnicastAddress) -> bool {
if unicast_addr.length != 0 {
let socket_addr = &unicast_addr.address;
let sa_family = (*socket_addr.lpSockaddr).sa_family;
sa_family == AF_INET6 as u16
} else {
false
}
}