From 423234d07b8b2ed686636956419c9c4dcfc61c2f Mon Sep 17 00:00:00 2001 From: shellrow Date: Sat, 8 Mar 2025 21:34:42 +0900 Subject: [PATCH 1/5] Add MTU for Interface --- examples/default_interface.rs | 1 + examples/list_interfaces.rs | 1 + src/interface/mod.rs | 3 +++ src/interface/unix.rs | 45 +++++++++++++++++++++++++++++++++++ src/interface/windows.rs | 1 + 5 files changed, 51 insertions(+) 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/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..335d56b 100644 --- a/src/interface/unix.rs +++ b/src/interface/unix.rs @@ -267,6 +267,50 @@ 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 std::ffi::CString; + use std::mem; + use std::os::unix::io::AsRawFd; + use std::os::unix::net::UnixDatagram; + use libc::{c_char, ifreq, ioctl, SIOCGIFMTU}; + + let sock = UnixDatagram::bind("/dev/null").ok()?; + let mut ifr: ifreq = unsafe { mem::zeroed() }; + + let c_interface = CString::new(name).ok()?; + unsafe { + std::ptr::copy_nonoverlapping( + c_interface.as_ptr() as *const c_char, + ifr.ifr_name.as_mut_ptr(), + c_interface.as_bytes().len(), + ); + } + + let ret = unsafe { ioctl(sock.as_raw_fd(), SIOCGIFMTU, &mut ifr) }; + if ret < 0 { + return None; + } + + Some(unsafe { ifr.ifr_ifru.ifru_mtu } as u32) +} + #[cfg(target_os = "android")] pub fn unix_interfaces() -> Vec { use super::android; @@ -387,6 +431,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) From ca81c050ac9fc1568aa409dc3c4714fb824b4964 Mon Sep 17 00:00:00 2001 From: shellrow <81893184+shellrow@users.noreply.github.com> Date: Sat, 8 Mar 2025 13:09:14 +0000 Subject: [PATCH 2/5] Fix Linux MTU retrieval using ioctl --- src/interface/unix.rs | 43 ++++++++++++++++++++++++++++++++----------- 1 file changed, 32 insertions(+), 11 deletions(-) diff --git a/src/interface/unix.rs b/src/interface/unix.rs index 335d56b..8282849 100644 --- a/src/interface/unix.rs +++ b/src/interface/unix.rs @@ -285,30 +285,51 @@ fn get_mtu(ifa: &libc::ifaddrs, _name: &str) -> Option { #[cfg(any(target_os = "linux", target_os = "android"))] fn get_mtu(_ifa: &libc::ifaddrs, name: &str) -> Option { - use std::ffi::CString; - use std::mem; - use std::os::unix::io::AsRawFd; - use std::os::unix::net::UnixDatagram; - use libc::{c_char, ifreq, ioctl, SIOCGIFMTU}; + use std::os::unix::io::RawFd; + use std::ptr; + use libc::{c_char, c_int, ifreq, ioctl, socket, AF_INET, SOCK_DGRAM, SIOCGIFMTU, close}; + + // 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 sock = UnixDatagram::bind("/dev/null").ok()?; 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 { - std::ptr::copy_nonoverlapping( - c_interface.as_ptr() as *const c_char, + ptr::copy_nonoverlapping( + bytes.as_ptr() as *const c_char, ifr.ifr_name.as_mut_ptr(), - c_interface.as_bytes().len(), + bytes.len(), ); } - let ret = unsafe { ioctl(sock.as_raw_fd(), SIOCGIFMTU, &mut ifr) }; + // Retrieve the MTU using ioctl + let ret: c_int = unsafe { ioctl(sock, SIOCGIFMTU, &mut ifr) }; if ret < 0 { + eprintln!("ioctl(SIOCGIFMTU) failed for {}: {:?}", name, std::io::Error::last_os_error()); + unsafe { close(sock) }; return None; } - Some(unsafe { ifr.ifr_ifru.ifru_mtu } as u32) + let mtu = unsafe { ifr.ifr_ifru.ifru_mtu } as u32; + + // Close the socket + unsafe { close(sock) }; + + Some(mtu) } #[cfg(target_os = "android")] From d17de4acd7137b66512532c214536d274bc75670 Mon Sep 17 00:00:00 2001 From: shellrow <81893184+shellrow@users.noreply.github.com> Date: Sat, 8 Mar 2025 13:53:53 +0000 Subject: [PATCH 3/5] Fix ioctl type mismatch for cross-compilation --- src/interface/unix.rs | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/interface/unix.rs b/src/interface/unix.rs index 8282849..c75d9e9 100644 --- a/src/interface/unix.rs +++ b/src/interface/unix.rs @@ -317,7 +317,7 @@ fn get_mtu(_ifa: &libc::ifaddrs, name: &str) -> Option { } // Retrieve the MTU using ioctl - let ret: c_int = unsafe { ioctl(sock, SIOCGIFMTU, &mut ifr) }; + 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) }; From 7c5b5d3c46679ca9580b1c1156acb0db49112ef6 Mon Sep 17 00:00:00 2001 From: shellrow Date: Sat, 8 Mar 2025 22:57:02 +0900 Subject: [PATCH 4/5] Run cargo fmt --- src/interface/unix.rs | 13 ++++++++++--- 1 file changed, 10 insertions(+), 3 deletions(-) diff --git a/src/interface/unix.rs b/src/interface/unix.rs index c75d9e9..bf3b2fc 100644 --- a/src/interface/unix.rs +++ b/src/interface/unix.rs @@ -285,14 +285,17 @@ fn get_mtu(ifa: &libc::ifaddrs, _name: &str) -> Option { #[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; - use libc::{c_char, c_int, ifreq, ioctl, socket, AF_INET, SOCK_DGRAM, SIOCGIFMTU, close}; // 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()); + eprintln!( + "Failed to create socket: {:?}", + std::io::Error::last_os_error() + ); return None; } @@ -319,7 +322,11 @@ fn get_mtu(_ifa: &libc::ifaddrs, name: &str) -> Option { // 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()); + eprintln!( + "ioctl(SIOCGIFMTU) failed for {}: {:?}", + name, + std::io::Error::last_os_error() + ); unsafe { close(sock) }; return None; } From 87a41424cfb5083e102d7b48e688c37e9f3bf2ec Mon Sep 17 00:00:00 2001 From: shellrow Date: Sat, 8 Mar 2025 23:09:25 +0900 Subject: [PATCH 5/5] Add missing mtu field in netlink module --- src/interface/android.rs | 1 + 1 file changed, 1 insertion(+) 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, };