diff --git a/examples/default_interface.rs b/examples/default_interface.rs index a3409a7..cc3dfb7 100644 --- a/examples/default_interface.rs +++ b/examples/default_interface.rs @@ -36,6 +36,7 @@ fn main() { println!("Default Gateway: (Not found)"); } println!("DNS Servers: {:?}", interface.dns_servers); + println!("MTU: {:?}", interface.mtu); println!("Default: {}", interface.default); } Err(e) => { diff --git a/examples/list_interfaces.rs b/examples/list_interfaces.rs index fad1bd1..526e279 100644 --- a/examples/list_interfaces.rs +++ b/examples/list_interfaces.rs @@ -45,6 +45,7 @@ fn main() { println!("Gateway: (Not found)"); } println!("DNS Servers: {:?}", interface.dns_servers); + println!("MTU: {:?}", interface.mtu); println!("Default: {}", interface.default); println!(); } diff --git a/src/interface/android.rs b/src/interface/android.rs index b439471..dc148ad 100644 --- a/src/interface/android.rs +++ b/src/interface/android.rs @@ -107,6 +107,7 @@ pub mod netlink { receive_speed: None, gateway: None, dns_servers: Vec::new(), + mtu: None, default: false, }; diff --git a/src/interface/mod.rs b/src/interface/mod.rs index 39982ca..bf7dce8 100644 --- a/src/interface/mod.rs +++ b/src/interface/mod.rs @@ -95,6 +95,8 @@ pub struct Interface { pub gateway: Option, /// DNS server addresses for the network interface pub dns_servers: Vec, + /// Maximum Transmission Unit (MTU) for the network interface + pub mtu: Option, /// Whether this is the default interface for accessing the Internet. pub default: bool, } @@ -145,6 +147,7 @@ impl Interface { receive_speed: None, gateway: None, dns_servers: Vec::new(), + mtu: None, default: false, } } diff --git a/src/interface/unix.rs b/src/interface/unix.rs index dce5269..bf3b2fc 100644 --- a/src/interface/unix.rs +++ b/src/interface/unix.rs @@ -267,6 +267,78 @@ pub fn is_physical_interface(interface: &Interface) -> bool { || (!interface.is_loopback() && !linux::is_virtual_interface(&interface.name)) } +#[cfg(any( + target_os = "macos", + target_os = "ios", + target_os = "openbsd", + target_os = "freebsd", + target_os = "netbsd" +))] +fn get_mtu(ifa: &libc::ifaddrs, _name: &str) -> Option { + if !ifa.ifa_data.is_null() { + let data = unsafe { &*(ifa.ifa_data as *mut libc::if_data) }; + Some(data.ifi_mtu as u32) + } else { + None + } +} + +#[cfg(any(target_os = "linux", target_os = "android"))] +fn get_mtu(_ifa: &libc::ifaddrs, name: &str) -> Option { + use libc::{c_char, c_int, close, ifreq, ioctl, socket, AF_INET, SIOCGIFMTU, SOCK_DGRAM}; + use std::os::unix::io::RawFd; + use std::ptr; + + // Create a socket for ioctl operations + let sock: RawFd = unsafe { socket(AF_INET, SOCK_DGRAM, 0) }; + if sock < 0 { + eprintln!( + "Failed to create socket: {:?}", + std::io::Error::last_os_error() + ); + return None; + } + + let mut ifr: ifreq = unsafe { mem::zeroed() }; + + // Set the interface name (must not exceed `IFNAMSIZ`) + let c_interface = CString::new(name).ok()?; + // Ensure null termination + let bytes = c_interface.to_bytes_with_nul(); + if bytes.len() > ifr.ifr_name.len() { + eprintln!("Interface name too long: {}", name); + unsafe { close(sock) }; + return None; + } + + unsafe { + ptr::copy_nonoverlapping( + bytes.as_ptr() as *const c_char, + ifr.ifr_name.as_mut_ptr(), + bytes.len(), + ); + } + + // Retrieve the MTU using ioctl + let ret: c_int = unsafe { ioctl(sock, SIOCGIFMTU as _, &mut ifr) }; + if ret < 0 { + eprintln!( + "ioctl(SIOCGIFMTU) failed for {}: {:?}", + name, + std::io::Error::last_os_error() + ); + unsafe { close(sock) }; + return None; + } + + let mtu = unsafe { ifr.ifr_ifru.ifru_mtu } as u32; + + // Close the socket + unsafe { close(sock) }; + + Some(mtu) +} + #[cfg(target_os = "android")] pub fn unix_interfaces() -> Vec { use super::android; @@ -387,6 +459,7 @@ fn unix_interfaces_inner( receive_speed: None, gateway: None, dns_servers: Vec::new(), + mtu: get_mtu(addr_ref, &name), default: false, }; ifaces.push(interface); diff --git a/src/interface/windows.rs b/src/interface/windows.rs index ccd7815..b8e2acf 100644 --- a/src/interface/windows.rs +++ b/src/interface/windows.rs @@ -279,6 +279,7 @@ pub fn interfaces() -> Vec { Some(default_gateway) }, dns_servers, + mtu: Some(cur.Mtu), default, }; Some(interface)