[WIP] Improve Windows support

Get gateway information using IP Helper API
main
shellrow 3 years ago
parent 2218cc197a
commit 60feaff4be
  1. 5
      src/interface.rs
  2. 169
      src/os/windows.rs

@ -19,6 +19,9 @@ impl MacAddr {
pub fn address(&self) -> String {
format!("{:02x}:{:02x}:{:02x}:{:02x}:{:02x}:{:02x}", self.0,self.1,self.2,self.3,self.4,self.5)
}
pub fn zero() -> MacAddr {
MacAddr(0,0,0,0,0,0)
}
}
impl std::fmt::Display for MacAddr {
@ -33,6 +36,7 @@ impl std::fmt::Display for MacAddr {
pub struct Interface {
pub index: u32,
pub name: String,
pub description: Option<String>,
pub mac_addr: Option<MacAddr>,
pub ipv4: Vec<Ipv4Addr>,
pub ipv6: Vec<Ipv6Addr>,
@ -70,6 +74,7 @@ pub fn get_default_interface() -> Result<Interface, String> {
let interface: Interface = Interface{
index: iface.index,
name: iface.name,
description: None,
mac_addr: mac_addr,
ipv4: ipv4_vec,
ipv6: ipv6_vec,

@ -1,14 +1,64 @@
use windows::Win32::NetworkManagement::IpHelper::{GetAdaptersInfo, IP_ADAPTER_INFO, IP_ADDR_STRING};
use windows::Win32::Foundation::{ERROR_BUFFER_OVERFLOW, NO_ERROR};
use windows::Win32::NetworkManagement::IpHelper::{GetAdaptersInfo, IP_ADAPTER_INFO, IP_ADDR_STRING, SendARP};
use std::convert::TryInto;
use std::mem;
use std::net::{IpAddr, Ipv4Addr, Ipv6Addr};
use std::ffi::CStr;
use core::ffi::c_void;
pub const ERROR_BUFFER_OVERFLOW: u32 = 111;
pub const NO_ERROR: u32 = 0;
use crate::interface::{Interface, MacAddr};
use crate::gateway::Gateway;
// Get network interface information using the IP Helper API
// TODO: Make more rusty way...
pub const EXCEPTION_INTERFACE_INDEX: u32 = 0;
// Convert C string to Rust string without trailing null bytes
fn bytes_to_string(bytes: &[u8]) -> String {
let result: String = match CStr::from_bytes_with_nul(bytes) {
Ok(cstr) => {
match cstr.to_str() {
Ok(rstr) => rstr.to_string(),
Err(_) => cstr.to_string_lossy().replace("\u{0}", "").to_string(),
}
},
Err(_) => {
String::from_utf8_lossy(bytes).replace("\u{0}", "").to_string()
}
};
result
}
#[cfg(target_endian = "little")]
fn htonl(val : u32) -> u32 {
let o3 = (val >> 24) as u8;
let o2 = (val >> 16) as u8;
let o1 = (val >> 8) as u8;
let o0 = val as u8;
(o0 as u32) << 24 | (o1 as u32) << 16 | (o2 as u32) << 8 | (o3 as u32)
}
#[cfg(target_endian = "big")]
fn htonl(val : u32) -> u32 {
val
}
fn get_mac_through_arp(src_ip: Ipv4Addr, dst_ip: Ipv4Addr) -> MacAddr {
let src_ip_int: u32 = htonl(u32::from(src_ip));
let dst_ip_int: u32 = htonl(u32::from(dst_ip));
let mut out_buf_len : u32 = 6;
let mut target_mac_addr: [u8; 6] = [0; 6];
let res = unsafe { SendARP(dst_ip_int, src_ip_int, target_mac_addr.as_mut_ptr() as *mut c_void, &mut out_buf_len) };
if res == NO_ERROR {
MacAddr::new(target_mac_addr)
}else{
MacAddr::zero()
}
}
// Get network interfaces using the IP Helper API
// TODO: Make more rusty ...
// Reference: https://docs.microsoft.com/en-us/windows/win32/api/iphlpapi/nf-iphlpapi-getadaptersinfo
pub fn get_interfaces() {
pub fn get_interfaces() -> Vec<Interface> {
let mut interfaces: Vec<Interface> = vec![];
let mut out_buf_len : u32 = mem::size_of::<IP_ADAPTER_INFO>().try_into().unwrap();
let mut raw_adaptor_mem: Vec<u8> = Vec::with_capacity(out_buf_len as usize);
let mut p_adaptor: *mut IP_ADAPTER_INFO;
@ -21,49 +71,118 @@ pub fn get_interfaces() {
}
}
if res != NO_ERROR {
//TODO
println!("failed to get adapters info");
// for test
std::process::exit(1);
return interfaces;
}
//Enumerate all adapters
p_adaptor = unsafe { mem::transmute(&raw_adaptor_mem) };
while p_adaptor as u64 != 0 {
unsafe {
let adapter = *p_adaptor;
let adapter_name = String::from_utf8_lossy(&adapter.AdapterName);
let adapter_desc = String::from_utf8_lossy(&adapter.Description);
let mac_addr = adapter.Address.to_vec();
println!("{} {} {} {} {:?}", adapter.Index, adapter.ComboIndex, adapter_name, adapter_desc, mac_addr);
let adapter: IP_ADAPTER_INFO = *p_adaptor;
if adapter.Index == EXCEPTION_INTERFACE_INDEX{
p_adaptor = (*p_adaptor).Next;
continue;
}
let adapter_name: String = bytes_to_string(&adapter.AdapterName);
let adapter_desc: String = bytes_to_string(&adapter.Description);
let mac_addr:[u8; 6] = adapter.Address[..6].try_into().unwrap_or([0, 0, 0, 0, 0, 0]);
//Enumerate all IPs
let mut ipv4_vec: Vec<Ipv4Addr> = vec![];
let mut ipv6_vec: Vec<Ipv6Addr> = vec![];
let mut p_ip_addr: *mut IP_ADDR_STRING;
p_ip_addr = mem::transmute(&(*p_adaptor).IpAddressList);
while p_ip_addr as u64 != 0 {
let ip_addr_string = *p_ip_addr;
let ip_addr = String::from_utf8_lossy(&ip_addr_string.IpAddress.String);
println!("{}", ip_addr);
let ip_addr_string: IP_ADDR_STRING = *p_ip_addr;
let ip_addr: String = bytes_to_string(&ip_addr_string.IpAddress.String);
match ip_addr.parse::<IpAddr>() {
Ok(ip_addr) => {
match ip_addr {
IpAddr::V4(ipv4_addr) => {
ipv4_vec.push(ipv4_addr);
},
IpAddr::V6(ipv6_addr) => {
ipv6_vec.push(ipv6_addr);
}
}
},
Err(_) => {},
}
p_ip_addr = (*p_ip_addr).Next;
}
//Enumerate all gateways
let mut gateway_ips: Vec<IpAddr> = vec![];
let mut p_gateway_addr: *mut IP_ADDR_STRING;
p_gateway_addr = mem::transmute(&(*p_adaptor).GatewayList);
while p_gateway_addr as u64 != 0 {
let gateway_addr_string = *p_gateway_addr;
let gateway_addr = String::from_utf8_lossy(&gateway_addr_string.IpAddress.String);
println!("{}", gateway_addr);
let gateway_addr_string: IP_ADDR_STRING = *p_gateway_addr;
let gateway_addr: String = bytes_to_string(&gateway_addr_string.IpAddress.String);
match gateway_addr.parse::<IpAddr>() {
Ok(ip_addr) => {
gateway_ips.push(ip_addr);
},
Err(_) => {},
}
p_gateway_addr = (*p_gateway_addr).Next;
}
//TODO
let default_gateway: Option<Gateway> = match gateway_ips.get(0) {
Some(gateway_ip) => {
let gateway_ip: IpAddr = *gateway_ip;
let default_gateway: Option<Gateway> = if gateway_ip != IpAddr::V4(Ipv4Addr::UNSPECIFIED) {
match gateway_ip {
IpAddr::V4(dst_ip) => {
if let Some(src_ip) = ipv4_vec.get(0) {
let mac_addr = get_mac_through_arp(*src_ip, dst_ip);
let gateway = Gateway {
mac_addr: mac_addr,
ip_addr: IpAddr::V4(dst_ip),
};
Some(gateway)
}else{
None
}
},
IpAddr::V6(_dst_ip) => {
None
},
}
}else{
None
};
default_gateway
},
None => None,
};
let interface: Interface = Interface{
index: adapter.Index,
name: adapter_name,
description: Some(adapter_desc),
mac_addr: Some(MacAddr::new(mac_addr)),
ipv4: ipv4_vec,
ipv6: ipv6_vec,
gateway: default_gateway,
};
interfaces.push(interface);
}
unsafe { p_adaptor = (*p_adaptor).Next; }
}
return interfaces;
}
#[cfg(test)]
mod tests {
use crate::os::windows;
use std::net::Ipv4Addr;
use super::*;
#[test]
fn test_nw_interfaces() {
let interfaces = get_interfaces();
for interface in interfaces {
println!("{:?}", interface);
}
}
#[test]
fn list_nw_interfaces() {
windows::get_interfaces();
fn test_arp() {
let src_ip: Ipv4Addr = Ipv4Addr::new(192, 168, 1, 2);
let dst_ip: Ipv4Addr = Ipv4Addr::new(192, 168, 1, 1);
let mac_addr = get_mac_through_arp(src_ip, dst_ip);
println!("{}", mac_addr);
}
}

Loading…
Cancel
Save