From f6159a5ef836f8ce33ce54fd0e11d3c0b8919089 Mon Sep 17 00:00:00 2001 From: shellrow <81893184+shellrow@users.noreply.github.com> Date: Sun, 16 Jan 2022 15:27:11 +0900 Subject: [PATCH] Windows support --- src/interface/windows.rs | 48 -------- src/lib.rs | 3 + src/os/mod.rs | 12 -- src/os/shared.rs | 18 --- src/os/unix.rs | 242 --------------------------------------- src/os/windows.rs | 215 ---------------------------------- 6 files changed, 3 insertions(+), 535 deletions(-) delete mode 100644 src/os/mod.rs delete mode 100644 src/os/shared.rs delete mode 100644 src/os/unix.rs delete mode 100644 src/os/windows.rs diff --git a/src/interface/windows.rs b/src/interface/windows.rs index df93119..0d32923 100644 --- a/src/interface/windows.rs +++ b/src/interface/windows.rs @@ -165,51 +165,3 @@ pub fn interfaces() -> Vec { } return interfaces; } - -// Get default Interface index -pub fn default_interface_index() -> Option { - let local_ip: IpAddr = match super::get_local_ipaddr(){ - Some(local_ip) => local_ip, - None => return None, - }; - let interfaces = interfaces(); - for iface in interfaces { - match local_ip { - IpAddr::V4(local_ipv4) => { - if iface.ipv4.contains(&local_ipv4) { - return Some(iface.index); - } - }, - IpAddr::V6(local_ipv6) => { - if iface.ipv6.contains(&local_ipv6) { - return Some(iface.index); - } - }, - } - } - None -} - -// Get default Interface name -pub fn default_interface_name() -> Option { - let local_ip: IpAddr = match super::get_local_ipaddr(){ - Some(local_ip) => local_ip, - None => return None, - }; - let interfaces = interfaces(); - for iface in interfaces { - match local_ip { - IpAddr::V4(local_ipv4) => { - if iface.ipv4.contains(&local_ipv4) { - return Some(iface.name); - } - }, - IpAddr::V6(local_ipv6) => { - if iface.ipv6.contains(&local_ipv6) { - return Some(iface.name); - } - }, - } - } - None -} diff --git a/src/lib.rs b/src/lib.rs index 0bf422c..db28a1c 100644 --- a/src/lib.rs +++ b/src/lib.rs @@ -1,5 +1,8 @@ +#[cfg(not(target_os="windows"))] mod sys; +#[cfg(not(target_os="windows"))] mod bpf; +#[cfg(not(target_os="windows"))] mod socket; pub mod interface; diff --git a/src/os/mod.rs b/src/os/mod.rs deleted file mode 100644 index bc54554..0000000 --- a/src/os/mod.rs +++ /dev/null @@ -1,12 +0,0 @@ -mod shared; -pub use self::shared::*; - -#[cfg(target_os = "windows")] -mod windows; -#[cfg(target_os = "windows")] -pub use self::windows::*; - -#[cfg(not(target_os="windows"))] -mod unix; -#[cfg(not(target_os="windows"))] -pub use self::unix::*; diff --git a/src/os/shared.rs b/src/os/shared.rs deleted file mode 100644 index eb39895..0000000 --- a/src/os/shared.rs +++ /dev/null @@ -1,18 +0,0 @@ -use std::net::{IpAddr, UdpSocket}; - -pub fn get_local_ipaddr() -> Option { - let socket = match UdpSocket::bind("0.0.0.0:0") { - Ok(s) => s, - Err(_) => return None, - }; - - match socket.connect("1.1.1.1:80") { - Ok(()) => (), - Err(_) => return None, - }; - - match socket.local_addr() { - Ok(addr) => return Some(addr.ip()), - Err(_) => return None, - }; -} diff --git a/src/os/unix.rs b/src/os/unix.rs deleted file mode 100644 index 12417ef..0000000 --- a/src/os/unix.rs +++ /dev/null @@ -1,242 +0,0 @@ -use std::net::{IpAddr, Ipv4Addr, Ipv6Addr}; -use std::net::UdpSocket; -use std::time::{Duration, Instant}; -use pnet_packet::Packet; -use crate::interface::{MacAddr, Interface}; -use crate::gateway::Gateway; - -const TIMEOUT: u64 = 3000; - -fn get_default_gateway(interface_index: u32) -> Result { - let interfaces = pnet_datalink::interfaces(); - let interface = interfaces.into_iter().filter(|interface: &pnet_datalink::NetworkInterface| interface.index == interface_index).next().expect("Failed to get Interface"); - let config = pnet_datalink::Config { - write_buffer_size: 4096, - read_buffer_size: 4096, - read_timeout: None, - write_timeout: None, - channel_type: pnet_datalink::ChannelType::Layer2, - bpf_fd_attempts: 1000, - linux_fanout: None, - promiscuous: false, - }; - let (mut _tx, mut rx) = match pnet_datalink::channel(&interface, config) { - Ok(pnet_datalink::Channel::Ethernet(tx, rx)) => (tx, rx), - Ok(_) => panic!("Unknown channel type"), - Err(e) => panic!("Error happened {}", e), - }; - match send_udp_packet() { - Ok(_) => (), - Err(e) => return Err(format!("Failed to send UDP packet {}", e)), - } - receive_packets(&mut rx) -} - -fn send_udp_packet() -> Result<(), String> { - let buf = [0u8; 0]; - let socket = match UdpSocket::bind("0.0.0.0:0") { - Ok(s) => s, - Err(e) => return Err(format!("Failed to create UDP socket {}", e)), - }; - let dst: &str = "1.1.1.1:80"; - match socket.set_ttl(1) { - Ok(_) => (), - Err(e) => return Err(format!("Failed to set TTL {}", e)), - } - match socket.send_to(&buf, dst) { - Ok(_) => (), - Err(e) => return Err(format!("Failed to send data {}", e)), - } - Ok(()) -} - -fn receive_packets(rx: &mut Box) -> Result{ - let timeout = Duration::from_millis(TIMEOUT); - let start_time = Instant::now(); - loop { - match rx.next() { - Ok(frame) => { - let frame = match pnet_packet::ethernet::EthernetPacket::new(frame) { - Some(f) => f, - None => return Err(String::from("Failed to read packet")), - }; - match frame.get_ethertype() { - pnet_packet::ethernet::EtherTypes::Ipv4 => { - if let Some(ip_addr) = ipv4_handler(&frame) { - let gateway = Gateway { - mac_addr: MacAddr::new(frame.get_source().octets()), - ip_addr: ip_addr, - }; - return Ok(gateway); - } - }, - pnet_packet::ethernet::EtherTypes::Ipv6 => { - if let Some(ip_addr) = ipv6_handler(&frame) { - let gateway = Gateway { - mac_addr: MacAddr::new(frame.get_source().octets()), - ip_addr: ip_addr, - }; - return Ok(gateway); - } - }, - _ => {} - } - }, - Err(e) => { - return Err(format!("An error occurred while reading: {}", e)); - } - } - if Instant::now().duration_since(start_time) > timeout { - return Err(String::from("Recieve timeout")); - }else{ - match send_udp_packet() { - Ok(_) => (), - Err(e) => return Err(format!("Failed to send UDP packet {}", e)), - } - } - } -} - -fn ipv4_handler(ethernet: &pnet_packet::ethernet::EthernetPacket) -> Option { - if let Some(packet) = pnet_packet::ipv4::Ipv4Packet::new(ethernet.payload()) { - match packet.get_next_level_protocol() { - pnet_packet::ip::IpNextHeaderProtocols::Icmp => { - return icmp_handler(&packet); - }, - _ => { - None - } - } - }else{ - None - } -} - -fn ipv6_handler(ethernet: &pnet_packet::ethernet::EthernetPacket) -> Option { - if let Some(packet) = pnet_packet::ipv6::Ipv6Packet::new(ethernet.payload()) { - match packet.get_next_header() { - pnet_packet::ip::IpNextHeaderProtocols::Icmpv6 => { - return icmpv6_handler(&packet); - }, - _ => { - None - } - } - }else{ - None - } -} - -fn icmp_handler(ip_packet: &pnet_packet::ipv4::Ipv4Packet) -> Option { - if let Some(packet) = pnet_packet::icmp::IcmpPacket::new(ip_packet.payload()) { - if packet.get_icmp_type() == pnet_packet::icmp::IcmpTypes::TimeExceeded { - let ipv4_addr = ip_packet.get_source(); - return Some(IpAddr::V4(ipv4_addr)) - }else{ - None - } - }else{ - None - } -} - -fn icmpv6_handler(ip_packet: &pnet_packet::ipv6::Ipv6Packet) -> Option { - if let Some(packet) = pnet_packet::icmpv6::Icmpv6Packet::new(ip_packet.payload()) { - if packet.get_icmpv6_type() == pnet_packet::icmpv6::Icmpv6Types::TimeExceeded { - let ipv6_addr = ip_packet.get_source(); - return Some(IpAddr::V6(ipv6_addr)) - }else{ - None - } - }else{ - None - } -} - -// Get network interfaces -pub fn interfaces() -> Vec { - let mut result: Vec = vec![]; - let local_ip: IpAddr = match super::get_local_ipaddr(){ - Some(local_ip) => local_ip, - None => return result, - }; - let interfaces = pnet_datalink::interfaces(); - for iface in interfaces{ - let mac_addr: Option = match iface.mac { - Some(mac_addr) => Some(MacAddr::new(mac_addr.octets())), - None => None, - }; - let mut ipv4_vec: Vec = vec![]; - let mut ipv6_vec: Vec = vec![]; - let mut ips: Vec = vec![]; - for ip in &iface.ips { - match ip.ip() { - IpAddr::V4(ipv4_addr) => { - ipv4_vec.push(ipv4_addr); - }, - IpAddr::V6(ipv6_addr) => { - ipv6_vec.push(ipv6_addr); - }, - } - ips.push(ip.ip()); - } - let default_gateway: Option = if ips.contains(&local_ip) { - match get_default_gateway(iface.index) { - Ok(default_gateway) => Some(default_gateway), - Err(_) => None, - } - } else{ - None - }; - let desc: Option = if iface.description.is_empty() { - None - } else{ - Some(iface.description) - }; - let interface: Interface = Interface{ - index: iface.index, - name: iface.name, - description: desc, - mac_addr: mac_addr, - ipv4: ipv4_vec, - ipv6: ipv6_vec, - gateway: default_gateway, - }; - result.push(interface); - } - return result; -} - -// Get default Interface index -pub fn default_interface_index() -> Option { - let local_ip: IpAddr = match super::get_local_ipaddr(){ - Some(local_ip) => local_ip, - None => return None, - }; - let interfaces = pnet_datalink::interfaces(); - for iface in interfaces { - for ip in iface.ips { - if local_ip == ip.ip() { - return Some(iface.index) - } - } - } - return None; -} - -// Get default Interface name -pub fn default_interface_name() -> Option { - let local_ip: IpAddr = match super::get_local_ipaddr(){ - Some(local_ip) => local_ip, - None => return None, - }; - let interfaces = pnet_datalink::interfaces(); - for iface in interfaces { - for ip in iface.ips { - if local_ip == ip.ip() { - return Some(iface.name) - } - } - } - return None; -} diff --git a/src/os/windows.rs b/src/os/windows.rs deleted file mode 100644 index df93119..0000000 --- a/src/os/windows.rs +++ /dev/null @@ -1,215 +0,0 @@ -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; - -use crate::interface::{Interface, MacAddr}; -use crate::gateway::Gateway; - -const EXCEPTION_INTERFACE_INDEX: u32 = 0; -const EXCEPTION_INTERFACE_COMBOINDEX: u32 = 4928; - -// 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 interfaces() -> Vec { - let mut interfaces: Vec = vec![]; - let mut out_buf_len : u32 = mem::size_of::().try_into().unwrap(); - let mut raw_adaptor_mem: Vec = Vec::with_capacity(out_buf_len as usize); - let mut p_adaptor: *mut IP_ADAPTER_INFO; - let mut res = unsafe { GetAdaptersInfo(raw_adaptor_mem.as_mut_ptr() as *mut IP_ADAPTER_INFO, &mut out_buf_len ) }; - // Make an initial call to GetAdaptersInfo to get the necessary size into the out_buf_len variable - if res == ERROR_BUFFER_OVERFLOW { - raw_adaptor_mem = Vec::with_capacity(out_buf_len as usize); - unsafe { - res = GetAdaptersInfo(raw_adaptor_mem.as_mut_ptr() as *mut IP_ADAPTER_INFO, &mut out_buf_len); - } - } - if res != NO_ERROR { - return interfaces; - } - //Enumerate all adapters - p_adaptor = unsafe { mem::transmute(&raw_adaptor_mem) }; - while p_adaptor as u64 != 0 { - let adapter: IP_ADAPTER_INFO = unsafe { *p_adaptor }; - if adapter.Index == EXCEPTION_INTERFACE_INDEX || adapter.ComboIndex == EXCEPTION_INTERFACE_COMBOINDEX{ - unsafe { 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 = vec![]; - let mut ipv6_vec: Vec = vec![]; - let mut p_ip_addr: *mut IP_ADDR_STRING; - p_ip_addr = unsafe { mem::transmute(&(*p_adaptor).IpAddressList) }; - while p_ip_addr as u64 != 0 { - let ip_addr_string: IP_ADDR_STRING = unsafe{ *p_ip_addr }; - let ip_addr: String = bytes_to_string(&ip_addr_string.IpAddress.String); - match ip_addr.parse::() { - 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(_) => {}, - } - unsafe { p_ip_addr = (*p_ip_addr).Next; } - } - //Enumerate all gateways - let mut gateway_ips: Vec = vec![]; - let mut p_gateway_addr: *mut IP_ADDR_STRING; - p_gateway_addr = unsafe { mem::transmute(&(*p_adaptor).GatewayList) }; - while p_gateway_addr as u64 != 0 { - let gateway_addr_string: IP_ADDR_STRING = unsafe { *p_gateway_addr }; - let gateway_addr: String = bytes_to_string(&gateway_addr_string.IpAddress.String); - match gateway_addr.parse::() { - Ok(ip_addr) => { - gateway_ips.push(ip_addr); - }, - Err(_) => {}, - } - unsafe { p_gateway_addr = (*p_gateway_addr).Next; } - } - let default_gateway: Option = match gateway_ips.get(0) { - Some(gateway_ip) => { - let gateway_ip: IpAddr = *gateway_ip; - let default_gateway: Option = 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; -} - -// Get default Interface index -pub fn default_interface_index() -> Option { - let local_ip: IpAddr = match super::get_local_ipaddr(){ - Some(local_ip) => local_ip, - None => return None, - }; - let interfaces = interfaces(); - for iface in interfaces { - match local_ip { - IpAddr::V4(local_ipv4) => { - if iface.ipv4.contains(&local_ipv4) { - return Some(iface.index); - } - }, - IpAddr::V6(local_ipv6) => { - if iface.ipv6.contains(&local_ipv6) { - return Some(iface.index); - } - }, - } - } - None -} - -// Get default Interface name -pub fn default_interface_name() -> Option { - let local_ip: IpAddr = match super::get_local_ipaddr(){ - Some(local_ip) => local_ip, - None => return None, - }; - let interfaces = interfaces(); - for iface in interfaces { - match local_ip { - IpAddr::V4(local_ipv4) => { - if iface.ipv4.contains(&local_ipv4) { - return Some(iface.name); - } - }, - IpAddr::V6(local_ipv6) => { - if iface.ipv6.contains(&local_ipv6) { - return Some(iface.name); - } - }, - } - } - None -}