From 7ad6493c8871a4df52d5f7f3a6e9345707a316d9 Mon Sep 17 00:00:00 2001 From: shellrow <81893184+shellrow@users.noreply.github.com> Date: Sun, 16 Jan 2022 15:15:23 +0900 Subject: [PATCH] Refactoring for unix-like OS --- Cargo.toml | 2 - src/bpf/binding.rs | 34 ++----- src/bpf/unix.rs | 1 + src/gateway/linux.rs | 24 +++++ src/gateway/mod.rs | 13 ++- src/gateway/unix.rs | 67 ++++++++++++ src/gateway/windows.rs | 0 src/interface/mod.rs | 61 +++++++++-- src/interface/shared.rs | 18 ++++ src/interface/unix.rs | 67 +++++++++++- src/interface/windows.rs | 215 +++++++++++++++++++++++++++++++++++++++ src/lib.rs | 1 - src/socket/mod.rs | 40 ++++---- src/socket/packet.rs | 1 + src/socket/unix.rs | 16 +-- 15 files changed, 488 insertions(+), 72 deletions(-) create mode 100644 src/gateway/linux.rs create mode 100644 src/gateway/windows.rs create mode 100644 src/interface/shared.rs diff --git a/Cargo.toml b/Cargo.toml index 03b7b95..be0c21e 100644 --- a/Cargo.toml +++ b/Cargo.toml @@ -11,8 +11,6 @@ categories = ["network-programming"] license = "MIT" [target.'cfg(not(windows))'.dependencies] -pnet_packet = "0.28" -pnet_datalink = "0.28" libc = "0.2" [target.'cfg(windows)'.dependencies.windows] diff --git a/src/bpf/binding.rs b/src/bpf/binding.rs index afe65ac..ab186b4 100644 --- a/src/bpf/binding.rs +++ b/src/bpf/binding.rs @@ -1,11 +1,9 @@ #![allow(non_camel_case_types)] #![allow(non_snake_case)] -#![allow(dead_code)] -extern crate libc; +use libc; pub type SockAddr = libc::sockaddr; - pub const AF_LINK: libc::c_int = 18; const IF_NAMESIZE: usize = 16; @@ -16,39 +14,29 @@ const IOC_INOUT: libc::c_ulong = IOC_IN | IOC_OUT; const IOCPARM_SHIFT: libc::c_ulong = 13; const IOCPARM_MASK: libc::c_ulong = (1 << (IOCPARM_SHIFT as usize)) - 1; -const SIZEOF_TIMEVAL: libc::c_ulong = 16; const SIZEOF_IFREQ: libc::c_ulong = 32; const SIZEOF_C_UINT: libc::c_ulong = 4; + #[cfg(any(target_os = "freebsd", target_os = "netbsd"))] const SIZEOF_C_LONG: libc::c_int = 8; -pub const BIOCSETIF: libc::c_ulong = - IOC_IN | ((SIZEOF_IFREQ & IOCPARM_MASK) << 16usize) | (('B' as libc::c_ulong) << 8usize) | 108; -pub const BIOCIMMEDIATE: libc::c_ulong = - IOC_IN | ((SIZEOF_C_UINT & IOCPARM_MASK) << 16) | (('B' as libc::c_ulong) << 8) | 112; -pub const BIOCGBLEN: libc::c_ulong = - IOC_OUT | ((SIZEOF_C_UINT & IOCPARM_MASK) << 16) | (('B' as libc::c_ulong) << 8) | 102; -pub const BIOCGDLT: libc::c_ulong = - IOC_OUT | ((SIZEOF_C_UINT & IOCPARM_MASK) << 16) | (('B' as libc::c_ulong) << 8) | 106; - -pub const BIOCSBLEN: libc::c_ulong = - IOC_INOUT | ((SIZEOF_C_UINT & IOCPARM_MASK) << 16) | (('B' as libc::c_ulong) << 8) | 102; -pub const BIOCSHDRCMPLT: libc::c_ulong = - IOC_IN | ((SIZEOF_C_UINT & IOCPARM_MASK) << 16) | (('B' as libc::c_ulong) << 8) | 117; -pub const BIOCSRTIMEOUT: libc::c_ulong = - IOC_IN | ((SIZEOF_TIMEVAL & IOCPARM_MASK) << 16) | (('B' as libc::c_ulong) << 8) | 109; +pub const BIOCSETIF: libc::c_ulong = IOC_IN | ((SIZEOF_IFREQ & IOCPARM_MASK) << 16usize) | (('B' as libc::c_ulong) << 8usize) | 108; +pub const BIOCIMMEDIATE: libc::c_ulong = IOC_IN | ((SIZEOF_C_UINT & IOCPARM_MASK) << 16) | (('B' as libc::c_ulong) << 8) | 112; +pub const BIOCGDLT: libc::c_ulong = IOC_OUT | ((SIZEOF_C_UINT & IOCPARM_MASK) << 16) | (('B' as libc::c_ulong) << 8) | 106; +pub const BIOCSBLEN: libc::c_ulong = IOC_INOUT | ((SIZEOF_C_UINT & IOCPARM_MASK) << 16) | (('B' as libc::c_ulong) << 8) | 102; +pub const BIOCSHDRCMPLT: libc::c_ulong = IOC_IN | ((SIZEOF_C_UINT & IOCPARM_MASK) << 16) | (('B' as libc::c_ulong) << 8) | 117; #[cfg(target_os = "freebsd")] -pub const BIOCFEEDBACK: libc::c_ulong = - IOC_IN | ((SIZEOF_C_UINT & IOCPARM_MASK) << 16) | (('B' as libc::c_ulong) << 8) | 124; +pub const BIOCFEEDBACK: libc::c_ulong = IOC_IN | ((SIZEOF_C_UINT & IOCPARM_MASK) << 16) | (('B' as libc::c_ulong) << 8) | 124; + #[cfg(target_os = "netbsd")] -pub const BIOCFEEDBACK: libc::c_ulong = - IOC_IN | ((SIZEOF_C_UINT & IOCPARM_MASK) << 16) | (('B' as libc::c_ulong) << 8) | 125; +pub const BIOCFEEDBACK: libc::c_ulong = IOC_IN | ((SIZEOF_C_UINT & IOCPARM_MASK) << 16) | (('B' as libc::c_ulong) << 8) | 125; pub const DLT_NULL: libc::c_uint = 0; #[cfg(any(target_os = "freebsd", target_os = "netbsd"))] const BPF_ALIGNMENT: libc::c_int = SIZEOF_C_LONG; + #[cfg(any(target_os = "openbsd", target_os = "macos", target_os = "ios", windows))] const BPF_ALIGNMENT: libc::c_int = 4; diff --git a/src/bpf/unix.rs b/src/bpf/unix.rs index 80a093e..c2d41c9 100644 --- a/src/bpf/unix.rs +++ b/src/bpf/unix.rs @@ -84,6 +84,7 @@ pub fn channel(interface_name: String, config: Config) -> io::Result libc::c_int { for i in 0..attempts { diff --git a/src/gateway/linux.rs b/src/gateway/linux.rs new file mode 100644 index 0000000..27c78ff --- /dev/null +++ b/src/gateway/linux.rs @@ -0,0 +1,24 @@ +use std::net::UdpSocket; +use super::Gateway; + +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(()) +} + +pub fn get_default_gateway(interface_name: String) -> Result { + Err(String::new()) +} diff --git a/src/gateway/mod.rs b/src/gateway/mod.rs index 77a6f5d..432b31a 100644 --- a/src/gateway/mod.rs +++ b/src/gateway/mod.rs @@ -1,6 +1,11 @@ +#[cfg(any(target_os = "macos", target_os = "openbsd", target_os = "freebsd", target_os = "netbsd", target_os = "ios"))] +pub mod unix; + +#[cfg(any(target_os = "linux", target_os = "android"))] +pub mod linux; + use std::net::{IpAddr, Ipv4Addr}; -use crate::interface::{MacAddr, Interface}; -use crate::os; +use crate::interface::{self, MacAddr, Interface}; /// Structure of default Gateway information #[derive(Clone, Debug)] @@ -20,11 +25,11 @@ impl Gateway { /// Get default Gateway pub fn get_default_gateway() -> Result { - let local_ip: IpAddr = match os::get_local_ipaddr(){ + let local_ip: IpAddr = match interface::get_local_ipaddr(){ Some(local_ip) => local_ip, None => return Err(String::from("Local IP address not found")), }; - let interfaces: Vec = os::interfaces(); + let interfaces: Vec = interface::get_interfaces(); for iface in interfaces { match local_ip { IpAddr::V4(local_ipv4) => { diff --git a/src/gateway/unix.rs b/src/gateway/unix.rs index e69de29..04357a7 100644 --- a/src/gateway/unix.rs +++ b/src/gateway/unix.rs @@ -0,0 +1,67 @@ +use std::net::UdpSocket; +use std::time::{Duration, Instant}; +use crate::socket; +use super::Gateway; + +const TIMEOUT: u64 = 3000; + +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(()) +} + +pub fn get_default_gateway(interface_name: String) -> Result { + let timeout = Duration::from_millis(TIMEOUT); + let start_time = Instant::now(); + let config = socket::Config { + write_buffer_size: 4096, + read_buffer_size: 4096, + read_timeout: None, + write_timeout: None, + channel_type: socket::ChannelType::Layer2, + bpf_fd_attempts: 1000, + promiscuous: false, + }; + let (mut _tx, mut rx) = match socket::channel(interface_name, config) { + Ok(socket::Channel::Ethernet(tx, rx)) => (tx, rx), + Err(e) => panic!("Failed to create channel {}", e), + }; + match send_udp_packet() { + Ok(_) => (), + Err(e) => return Err(format!("Failed to send UDP packet {}", e)), + } + loop { + match rx.next() { + Ok(frame) => { + match socket::packet::parse_frame(frame){ + Ok(gateway) => { + return Ok(gateway); + }, + Err(_) => {}, + } + }, + Err(_) => {} + } + 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)), + } + } + } +} diff --git a/src/gateway/windows.rs b/src/gateway/windows.rs new file mode 100644 index 0000000..e69de29 diff --git a/src/interface/mod.rs b/src/interface/mod.rs index f53a144..aca9521 100644 --- a/src/interface/mod.rs +++ b/src/interface/mod.rs @@ -1,9 +1,18 @@ -#[cfg(not(target_os="windows"))] +mod shared; +pub use self::shared::*; + +#[cfg(any(target_os = "linux", target_os = "macos", target_os = "openbsd", target_os = "freebsd", target_os = "netbsd", target_os = "ios", target_os = "android"))] mod unix; +#[cfg(any(target_os = "linux", target_os = "macos", target_os = "openbsd", target_os = "freebsd", target_os = "netbsd", target_os = "ios", target_os = "android"))] +use self::unix::*; + +#[cfg(target_os = "windows")] +mod windows; +#[cfg(target_os = "windows")] +use self::windows::*; use std::net::{IpAddr, Ipv4Addr, Ipv6Addr}; use crate::gateway::{Gateway}; -use crate::os; /// Structure of MAC address #[derive(Clone, Debug)] @@ -48,11 +57,11 @@ pub struct Interface { /// Get default Network Interface pub fn get_default_interface() -> Result { - let local_ip: IpAddr = match os::get_local_ipaddr(){ + let local_ip: IpAddr = match get_local_ipaddr(){ Some(local_ip) => local_ip, None => return Err(String::from("Local IP address not found")), }; - let interfaces: Vec = os::interfaces(); + let interfaces: Vec = interfaces(); for iface in interfaces { match local_ip { IpAddr::V4(local_ipv4) => { @@ -72,17 +81,55 @@ pub fn get_default_interface() -> Result { /// Get default Network Interface index pub fn get_default_interface_index() -> Option { - os::default_interface_index() + let local_ip: IpAddr = match 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 Network Interface name pub fn get_default_interface_name() -> Option { - os::default_interface_name() + let local_ip: IpAddr = match 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 } /// Get a list of available Network Interfaces pub fn get_interfaces() -> Vec { - os::interfaces() + interfaces() } #[cfg(test)] diff --git a/src/interface/shared.rs b/src/interface/shared.rs new file mode 100644 index 0000000..eb39895 --- /dev/null +++ b/src/interface/shared.rs @@ -0,0 +1,18 @@ +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/interface/unix.rs b/src/interface/unix.rs index 5cfc817..3fd5bfe 100644 --- a/src/interface/unix.rs +++ b/src/interface/unix.rs @@ -1,6 +1,7 @@ use super::Interface; use super::MacAddr; use crate::sys; +use crate::gateway; use libc; use std::ffi::{CStr, CString}; @@ -9,8 +10,72 @@ use std::os::raw::c_char; use std::str::from_utf8_unchecked; use std::net::{IpAddr, Ipv4Addr, Ipv6Addr}; +#[cfg(any(target_os = "macos", target_os = "openbsd", target_os = "freebsd", target_os = "netbsd", target_os = "ios"))] pub fn interfaces() -> Vec { - unix_interfaces() + let mut interfaces: Vec = unix_interfaces(); + let local_ip: IpAddr = match super::get_local_ipaddr(){ + Some(local_ip) => local_ip, + None => return interfaces, + }; + for iface in &mut interfaces { + match local_ip { + IpAddr::V4(local_ipv4) => { + if iface.ipv4.contains(&local_ipv4) { + match gateway::unix::get_default_gateway(iface.name.clone()) { + Ok(gateway) => { + iface.gateway = Some(gateway); + }, + Err(_) => {}, + } + } + }, + IpAddr::V6(local_ipv6) => { + if iface.ipv6.contains(&local_ipv6) { + match gateway::unix::get_default_gateway(iface.name.clone()) { + Ok(gateway) => { + iface.gateway = Some(gateway); + }, + Err(_) => {}, + } + } + }, + } + } + interfaces +} + +#[cfg(any(target_os = "linux", target_os = "android"))] +pub fn interfaces() -> Vec { + let mut interfaces: Vec = unix_interfaces(); + let local_ip: IpAddr = match super::get_local_ipaddr(){ + Some(local_ip) => local_ip, + None => return interfaces, + }; + for iface in &mut interfaces { + match local_ip { + IpAddr::V4(local_ipv4) => { + if iface.ipv4.contains(&local_ipv4) { + match gateway::unix::get_default_gateway(iface.name.clone()) { + Ok(gateway) => { + iface.gateway = Some(gateway); + }, + Err(_) => {}, + } + } + }, + IpAddr::V6(local_ipv6) => { + if iface.ipv6.contains(&local_ipv6) { + match gateway::unix::get_default_gateway(iface.name.clone()) { + Ok(gateway) => { + iface.gateway = Some(gateway); + }, + Err(_) => {}, + } + } + }, + } + } + interfaces } pub fn unix_interfaces() -> Vec { diff --git a/src/interface/windows.rs b/src/interface/windows.rs index e69de29..df93119 100644 --- a/src/interface/windows.rs +++ b/src/interface/windows.rs @@ -0,0 +1,215 @@ +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 +} diff --git a/src/lib.rs b/src/lib.rs index 4cba196..0bf422c 100644 --- a/src/lib.rs +++ b/src/lib.rs @@ -1,4 +1,3 @@ -mod os; mod sys; mod bpf; mod socket; diff --git a/src/socket/mod.rs b/src/socket/mod.rs index 180b8ef..6743f14 100644 --- a/src/socket/mod.rs +++ b/src/socket/mod.rs @@ -9,25 +9,7 @@ pub use self::unix::*; mod tests { use super::*; use std::net::UdpSocket; - #[test] - fn test_packet_capture() { - let interface_name: String = String::from("en0"); - let config = Config { - write_buffer_size: 4096, - read_buffer_size: 4096, - read_timeout: None, - write_timeout: None, - channel_type: ChannelType::Layer2, - bpf_fd_attempts: 1000, - linux_fanout: None, - promiscuous: false, - }; - let (mut _tx, mut rx) = match channel(interface_name, config) { - Ok(Channel::Ethernet(tx, rx)) => (tx, rx), - //Ok(_) => panic!("Unknown channel type"), - Err(e) => panic!("Error happened {}", e), - }; - + fn send_udp_packet() { let buf = [0u8; 0]; let socket = match UdpSocket::bind("0.0.0.0:0") { Ok(s) => s, @@ -51,6 +33,25 @@ mod tests { return; }, } + } + #[test] + fn test_packet_capture() { + let interface_name: String = String::from("en7"); + let config = Config { + write_buffer_size: 4096, + read_buffer_size: 4096, + read_timeout: None, + write_timeout: None, + channel_type: ChannelType::Layer2, + bpf_fd_attempts: 1000, + promiscuous: false, + }; + let (mut _tx, mut rx) = match channel(interface_name, config) { + Ok(Channel::Ethernet(tx, rx)) => (tx, rx), + Err(e) => panic!("Error happened {}", e), + }; + + send_udp_packet(); loop { match rx.next() { @@ -71,6 +72,7 @@ mod tests { println!("{}", e); } } + send_udp_packet(); } } } diff --git a/src/socket/packet.rs b/src/socket/packet.rs index ee82fda..2a4415f 100644 --- a/src/socket/packet.rs +++ b/src/socket/packet.rs @@ -11,6 +11,7 @@ pub const NEXT_HEADER_ICMPV6: u8 = 58; pub const ICMP_TYPE_TIME_EXCEEDED: u8 = 11; pub const ICMPV6_TYPE_TIME_EXCEEDED: u8 = 3; +#[allow(dead_code)] pub enum Frame { SrcMacAddr, DstMacAddr, diff --git a/src/socket/unix.rs b/src/socket/unix.rs index 2b3e69c..9673fdb 100644 --- a/src/socket/unix.rs +++ b/src/socket/unix.rs @@ -6,6 +6,7 @@ use crate::interface::Interface; pub type EtherType = u16; +#[allow(dead_code)] #[derive(Clone, Copy, Debug, Eq, Hash, PartialEq)] pub enum ChannelType { Layer2, @@ -17,22 +18,9 @@ pub enum Channel { Ethernet(Box, Box), } -#[derive(Clone, Copy, Debug, Eq, Hash, PartialEq)] -pub enum FanoutType { - HASH, - LB, - CPU, - ROLLOVER, - RND, - QM, - CBPF, - EBPF, -} - #[derive(Clone, Copy, Debug, Eq, Hash, PartialEq)] pub struct FanoutOption { pub group_id: u16, - pub fanout_type: FanoutType, pub defrag: bool, pub rollover: bool, } @@ -45,7 +33,6 @@ pub struct Config { pub write_timeout: Option, pub channel_type: ChannelType, pub bpf_fd_attempts: usize, - pub linux_fanout: Option, pub promiscuous: bool, } @@ -58,7 +45,6 @@ impl Default for Config { write_timeout: None, channel_type: ChannelType::Layer2, bpf_fd_attempts: 1000, - linux_fanout: None, promiscuous: true, } }