From bad910084fe35cba4c40c4b04733c9e4ee56a05d Mon Sep 17 00:00:00 2001 From: Lars Eggert Date: Tue, 3 Sep 2024 09:54:28 +0300 Subject: [PATCH 01/21] feat: Also return an interface ID --- Cargo.toml | 2 +- README.md | 8 +++--- src/lib.rs | 73 ++++++++++++++++++++++++++++++++++++++++++++---------- 3 files changed, 66 insertions(+), 17 deletions(-) diff --git a/Cargo.toml b/Cargo.toml index 41bac4e..582ebbb 100644 --- a/Cargo.toml +++ b/Cargo.toml @@ -7,7 +7,7 @@ homepage = "https://github.com/mozilla/mtu/" repository = "https://github.com/mozilla/mtu/" authors = ["The Mozilla Necko Team "] readme = "README.md" -version = "0.1.1" +version = "0.2.0" edition = "2021" license = "MIT OR Apache-2.0" # Don't increase beyond what Firefox is currently using: diff --git a/README.md b/README.md index a6b1f41..1efff94 100644 --- a/README.md +++ b/README.md @@ -4,13 +4,13 @@ A crate to return the maximum transmission unit (MTU) of the local network inter ## Usage -This crate exports a single function +The main function exported by this crate is ```rust -pub fn get_interface_mtu(remote: &SocketAddr) -> Result +pub fn get_interface_and_mtu(remote: &SocketAddr) -> Result<(InterfaceId, usize), Error> ``` -that returns the MTU of the local network interface towards the `remote` destination, or an `Error` when the MTU could not be determined. It supports both IPv4 and IPv6. +that returns an opaque identifier of the local network interface towards the `remote` destination together with its MTU, or an `Error` when the MTU could not be determined. It supports both IPv4 and IPv6. ## Supported Platforms @@ -22,6 +22,8 @@ that returns the MTU of the local network interface towards the `remote` destina The returned MTU may exceed the maximum IP packet size of 65,535 bytes on some platforms for some remote destinations. (For example, loopback destinations on Windows.) +The returned interface ID is an opaque identifier that can be used to identify the local interface. It is a hash of the interface name (on Linux and macOS) or interface index (on Windows), and has the same stability guarantees as those identifiers. + ## Contributing We're happy to receive PRs that improve this crate. Please take a look at our [community guidelines](CODE_OF_CONDUCT.md) beforehand. diff --git a/src/lib.rs b/src/lib.rs index c2a939b..30869eb 100644 --- a/src/lib.rs +++ b/src/lib.rs @@ -13,32 +13,38 @@ use std::{ use log::trace; /// Prepare a default error result. -fn default_result() -> Result { +fn default_result() -> Result<(InterfaceId, T), Error> { Err(Error::new( ErrorKind::NotFound, "Local interface MTU not found", )) } -/// Return the maximum transmission unit (MTU) of the local network interface towards the -/// destination [`SocketAddr`] given in `remote`. +type InterfaceId = u64; + +/// Return a unique interface ID and the maximum transmission unit (MTU) of the local network +/// interface towards the destination [`SocketAddr`] given in `remote`. /// /// The returned MTU may exceed the maximum IP packet size of 65,535 bytes on some /// platforms for some remote destinations. (For example, loopback destinations on /// Windows.) /// +/// The returned interface ID is an opaque identifier that can be used to identify the local +/// interface. It is a hash of the interface name (on Linux and macOS) or interface index (on +/// Windows), and has the same stability guarantees as those identifiers. +/// /// # Examples /// /// ``` /// let saddr = "127.0.0.1:443".parse().unwrap(); -/// let mtu = mtu::get_interface_mtu(&saddr).unwrap(); +/// let (id, mtu) = mtu::get_interface_and_mtu(&saddr).unwrap(); /// println!("MTU towards {:?} is {}", saddr, mtu); /// ``` /// /// # Errors /// /// This function returns an error if the local interface MTU cannot be determined. -pub fn get_interface_mtu(remote: &SocketAddr) -> Result { +pub fn get_interface_and_mtu(remote: &SocketAddr) -> Result<(InterfaceId, usize), Error> { #[cfg(any(target_os = "macos", target_os = "linux", target_os = "windows"))] #[allow(unused_assignments)] // Yes, res is reassigned in the platform-specific code. let mut res = default_result(); @@ -59,12 +65,12 @@ pub fn get_interface_mtu(remote: &SocketAddr) -> Result { #[cfg(any(target_os = "macos", target_os = "linux"))] { - res = get_interface_mtu_linux_macos(&socket); + res = get_interface_and_mtu_linux_macos(&socket); } #[cfg(target_os = "windows")] { - res = get_interface_mtu_windows(&socket); + res = get_interface_and_mtu_windows(&socket); } } @@ -73,10 +79,13 @@ pub fn get_interface_mtu(remote: &SocketAddr) -> Result { } #[cfg(any(target_os = "macos", target_os = "linux"))] -fn get_interface_mtu_linux_macos(socket: &UdpSocket) -> Result { - use std::ffi::{c_int, CStr}; +fn get_interface_and_mtu_linux_macos(socket: &UdpSocket) -> Result<(InterfaceId, usize), Error> { #[cfg(target_os = "linux")] use std::{ffi::c_char, mem, os::fd::AsRawFd}; + use std::{ + ffi::{c_int, CStr}, + hash::{DefaultHasher, Hash, Hasher}, + }; use libc::{ freeifaddrs, getifaddrs, ifaddrs, in_addr_t, sockaddr_in, sockaddr_in6, AF_INET, AF_INET6, @@ -126,6 +135,10 @@ fn get_interface_mtu_linux_macos(socket: &UdpSocket) -> Result { // If we have found the interface name we are looking for, find the MTU. let mut res = default_result(); if let Some(iface) = iface { + let mut hasher = DefaultHasher::new(); + iface.hash(&mut hasher); + let id = hasher.finish(); + #[cfg(target_os = "macos")] { // On macOS, we need to loop again to find the MTU of that interface. We need to @@ -147,7 +160,9 @@ fn get_interface_mtu_linux_macos(socket: &UdpSocket) -> Result { && name == iface { let data = unsafe { &*(ifa.ifa_data as *const if_data) }; - res = usize::try_from(data.ifi_mtu).or(res); + if let Ok(mtu) = usize::try_from(data.ifi_mtu) { + res = Ok((id, mtu)); + } break; } } @@ -165,7 +180,9 @@ fn get_interface_mtu_linux_macos(socket: &UdpSocket) -> Result { if unsafe { ioctl(socket.as_raw_fd(), libc::SIOCGIFMTU, &ifr) } != 0 { res = Err(Error::last_os_error()); } else { - res = unsafe { usize::try_from(ifr.ifr_ifru.ifru_mtu).or(res) }; + if let Ok(mtu) = usize::try_from(ifr.ifr_ifru.ifru_mtu) { + res = Ok((id, mtu)); + } } } } @@ -175,7 +192,7 @@ fn get_interface_mtu_linux_macos(socket: &UdpSocket) -> Result { } #[cfg(target_os = "windows")] -fn get_interface_mtu_windows(socket: &UdpSocket) -> Result { +fn get_interface_mtu_windows(socket: &UdpSocket) -> Result<(InterfaceId, usize), Error> { use std::{ffi::c_void, slice}; use windows::Win32::{ @@ -235,7 +252,12 @@ fn get_interface_mtu_windows(socket: &UdpSocket) -> Result { // For the matching address, find local interface and its MTU. for iface in ifaces { if iface.InterfaceIndex == addr.InterfaceIndex { - res = iface.NlMtu.try_into().or(res); + if Ok(mtu) = iface.NlMtu.try_into() { + let mut hasher = DefaultHasher::new(); + iface.InterfaceIndex.hash(&mut hasher); + let id = hasher.finish(); + res = Ok((id, mtu)); + } break 'addr_loop; } } @@ -248,6 +270,31 @@ fn get_interface_mtu_windows(socket: &UdpSocket) -> Result { res } +/// Return the maximum transmission unit (MTU) of the local network interface towards the +/// destination [`SocketAddr`] given in `remote`. +/// +/// The returned MTU may exceed the maximum IP packet size of 65,535 bytes on some +/// platforms for some remote destinations. (For example, loopback destinations on +/// Windows.) +/// +/// This function is a convenience wrapper around [`get_interface_and_mtu`] that only returns the +/// MTU. It is provided for compatibility with version 0.1 of the `mtu` crate. +/// +/// # Examples +/// +/// ``` +/// let saddr = "127.0.0.1:443".parse().unwrap(); +/// let mtu = mtu::get_interface_mtu(&saddr).unwrap(); +/// println!("MTU towards {:?} is {}", saddr, mtu); +/// ``` +/// +/// # Errors +/// +/// This function returns an error if the local interface MTU cannot be determined. +pub fn get_interface_mtu(remote: &SocketAddr) -> Result { + get_interface_and_mtu(remote).map(|(_, mtu)| mtu) +} + #[cfg(test)] mod test { use std::net::ToSocketAddrs; From a473b55e7e8bcf573b6d36d00df9197dd41b619a Mon Sep 17 00:00:00 2001 From: Lars Eggert Date: Tue, 3 Sep 2024 09:59:52 +0300 Subject: [PATCH 02/21] Fixes --- src/lib.rs | 8 +++----- 1 file changed, 3 insertions(+), 5 deletions(-) diff --git a/src/lib.rs b/src/lib.rs index 30869eb..3d0e84c 100644 --- a/src/lib.rs +++ b/src/lib.rs @@ -179,10 +179,8 @@ fn get_interface_and_mtu_linux_macos(socket: &UdpSocket) -> Result<(InterfaceId, }); if unsafe { ioctl(socket.as_raw_fd(), libc::SIOCGIFMTU, &ifr) } != 0 { res = Err(Error::last_os_error()); - } else { - if let Ok(mtu) = usize::try_from(ifr.ifr_ifru.ifru_mtu) { - res = Ok((id, mtu)); - } + } else if let Ok(mtu) = usize::try_from(unsafe { ifr.ifr_ifru.ifru_mtu }) { + res = Ok((id, mtu)); } } } @@ -193,7 +191,7 @@ fn get_interface_and_mtu_linux_macos(socket: &UdpSocket) -> Result<(InterfaceId, #[cfg(target_os = "windows")] fn get_interface_mtu_windows(socket: &UdpSocket) -> Result<(InterfaceId, usize), Error> { - use std::{ffi::c_void, slice}; + use std::{ffi::c_void, hash::DefaultHasher, slice}; use windows::Win32::{ Foundation::NO_ERROR, From 09f2ebe82013d2f681b64713a014176e659a09f5 Mon Sep 17 00:00:00 2001 From: Lars Eggert Date: Tue, 3 Sep 2024 10:05:09 +0300 Subject: [PATCH 03/21] Fixes --- src/lib.rs | 8 ++++++-- 1 file changed, 6 insertions(+), 2 deletions(-) diff --git a/src/lib.rs b/src/lib.rs index 3d0e84c..c481a80 100644 --- a/src/lib.rs +++ b/src/lib.rs @@ -191,7 +191,11 @@ fn get_interface_and_mtu_linux_macos(socket: &UdpSocket) -> Result<(InterfaceId, #[cfg(target_os = "windows")] fn get_interface_mtu_windows(socket: &UdpSocket) -> Result<(InterfaceId, usize), Error> { - use std::{ffi::c_void, hash::DefaultHasher, slice}; + use std::{ + ffi::c_void, + hash::{DefaultHasher, Hasher}, + slice, + }; use windows::Win32::{ Foundation::NO_ERROR, @@ -250,7 +254,7 @@ fn get_interface_mtu_windows(socket: &UdpSocket) -> Result<(InterfaceId, usize), // For the matching address, find local interface and its MTU. for iface in ifaces { if iface.InterfaceIndex == addr.InterfaceIndex { - if Ok(mtu) = iface.NlMtu.try_into() { + if let Ok(mtu) = iface.NlMtu.try_into() { let mut hasher = DefaultHasher::new(); iface.InterfaceIndex.hash(&mut hasher); let id = hasher.finish(); From 4f4e98037bbc7362493191a892bee6405e5198d4 Mon Sep 17 00:00:00 2001 From: Lars Eggert Date: Tue, 3 Sep 2024 10:05:49 +0300 Subject: [PATCH 04/21] Fixes --- src/lib.rs | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/lib.rs b/src/lib.rs index c481a80..dd33181 100644 --- a/src/lib.rs +++ b/src/lib.rs @@ -190,7 +190,7 @@ fn get_interface_and_mtu_linux_macos(socket: &UdpSocket) -> Result<(InterfaceId, } #[cfg(target_os = "windows")] -fn get_interface_mtu_windows(socket: &UdpSocket) -> Result<(InterfaceId, usize), Error> { +fn get_interface_and_mtu_windows(socket: &UdpSocket) -> Result<(InterfaceId, usize), Error> { use std::{ ffi::c_void, hash::{DefaultHasher, Hasher}, From b1f75255a182040dbb7476bbae1bddddda51e70b Mon Sep 17 00:00:00 2001 From: Lars Eggert Date: Tue, 3 Sep 2024 10:11:47 +0300 Subject: [PATCH 05/21] Fixes --- src/lib.rs | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/lib.rs b/src/lib.rs index dd33181..dd95d6d 100644 --- a/src/lib.rs +++ b/src/lib.rs @@ -193,7 +193,7 @@ fn get_interface_and_mtu_linux_macos(socket: &UdpSocket) -> Result<(InterfaceId, fn get_interface_and_mtu_windows(socket: &UdpSocket) -> Result<(InterfaceId, usize), Error> { use std::{ ffi::c_void, - hash::{DefaultHasher, Hasher}, + hash::{DefaultHasher, Hash, Hasher}, slice, }; From ddcd63dcd5e519a18e0f6ddf69a671707a00ce98 Mon Sep 17 00:00:00 2001 From: Lars Eggert Date: Tue, 3 Sep 2024 10:24:15 +0300 Subject: [PATCH 06/21] Simplify --- src/lib.rs | 14 ++++++++------ 1 file changed, 8 insertions(+), 6 deletions(-) diff --git a/src/lib.rs b/src/lib.rs index dd95d6d..d1c9b7e 100644 --- a/src/lib.rs +++ b/src/lib.rs @@ -95,6 +95,12 @@ fn get_interface_and_mtu_linux_macos(socket: &UdpSocket) -> Result<(InterfaceId, #[cfg(target_os = "linux")] use libc::{ifreq, ioctl}; + fn hash_interface_name(name: &str) -> InterfaceId { + let mut hasher = DefaultHasher::new(); + name.hash(&mut hasher); + hasher.finish() + } + // Get the interface list. let mut ifap: *mut ifaddrs = ptr::null_mut(); if unsafe { getifaddrs(&mut ifap) } != 0 { @@ -135,10 +141,6 @@ fn get_interface_and_mtu_linux_macos(socket: &UdpSocket) -> Result<(InterfaceId, // If we have found the interface name we are looking for, find the MTU. let mut res = default_result(); if let Some(iface) = iface { - let mut hasher = DefaultHasher::new(); - iface.hash(&mut hasher); - let id = hasher.finish(); - #[cfg(target_os = "macos")] { // On macOS, we need to loop again to find the MTU of that interface. We need to @@ -161,7 +163,7 @@ fn get_interface_and_mtu_linux_macos(socket: &UdpSocket) -> Result<(InterfaceId, { let data = unsafe { &*(ifa.ifa_data as *const if_data) }; if let Ok(mtu) = usize::try_from(data.ifi_mtu) { - res = Ok((id, mtu)); + res = Ok((hash_interface_name(iface), mtu)); } break; } @@ -180,7 +182,7 @@ fn get_interface_and_mtu_linux_macos(socket: &UdpSocket) -> Result<(InterfaceId, if unsafe { ioctl(socket.as_raw_fd(), libc::SIOCGIFMTU, &ifr) } != 0 { res = Err(Error::last_os_error()); } else if let Ok(mtu) = usize::try_from(unsafe { ifr.ifr_ifru.ifru_mtu }) { - res = Ok((id, mtu)); + res = Ok((hash_interface_name(iface), mtu)); } } } From c1156ca4d9ed9703f810009e6653b921294bd75f Mon Sep 17 00:00:00 2001 From: Lars Eggert Date: Tue, 3 Sep 2024 11:31:44 +0300 Subject: [PATCH 07/21] Update Cargo.toml Co-authored-by: Max Inden --- Cargo.toml | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/Cargo.toml b/Cargo.toml index 582ebbb..fcce6fb 100644 --- a/Cargo.toml +++ b/Cargo.toml @@ -7,7 +7,7 @@ homepage = "https://github.com/mozilla/mtu/" repository = "https://github.com/mozilla/mtu/" authors = ["The Mozilla Necko Team "] readme = "README.md" -version = "0.2.0" +version = "0.1.2" edition = "2021" license = "MIT OR Apache-2.0" # Don't increase beyond what Firefox is currently using: From dce0de85896c9a5a629bcd013f77caf4602365e5 Mon Sep 17 00:00:00 2001 From: Lars Eggert Date: Tue, 3 Sep 2024 11:48:25 +0300 Subject: [PATCH 08/21] Return interface name --- src/lib.rs | 49 +++++++++++++++++-------------------------------- 1 file changed, 17 insertions(+), 32 deletions(-) diff --git a/src/lib.rs b/src/lib.rs index d1c9b7e..fc5a49b 100644 --- a/src/lib.rs +++ b/src/lib.rs @@ -13,15 +13,13 @@ use std::{ use log::trace; /// Prepare a default error result. -fn default_result() -> Result<(InterfaceId, T), Error> { +fn default_result() -> Result<(String, T), Error> { Err(Error::new( ErrorKind::NotFound, "Local interface MTU not found", )) } -type InterfaceId = u64; - /// Return a unique interface ID and the maximum transmission unit (MTU) of the local network /// interface towards the destination [`SocketAddr`] given in `remote`. /// @@ -37,14 +35,14 @@ type InterfaceId = u64; /// /// ``` /// let saddr = "127.0.0.1:443".parse().unwrap(); -/// let (id, mtu) = mtu::get_interface_and_mtu(&saddr).unwrap(); -/// println!("MTU towards {:?} is {}", saddr, mtu); +/// let (name, mtu) = mtu::get_interface_and_mtu(&saddr).unwrap(); +/// println!("MTU towards {saddr:?} is {mtu} on {name}"); /// ``` /// /// # Errors /// /// This function returns an error if the local interface MTU cannot be determined. -pub fn get_interface_and_mtu(remote: &SocketAddr) -> Result<(InterfaceId, usize), Error> { +pub fn get_interface_and_mtu(remote: &SocketAddr) -> Result<(String, usize), Error> { #[cfg(any(target_os = "macos", target_os = "linux", target_os = "windows"))] #[allow(unused_assignments)] // Yes, res is reassigned in the platform-specific code. let mut res = default_result(); @@ -79,13 +77,10 @@ pub fn get_interface_and_mtu(remote: &SocketAddr) -> Result<(InterfaceId, usize) } #[cfg(any(target_os = "macos", target_os = "linux"))] -fn get_interface_and_mtu_linux_macos(socket: &UdpSocket) -> Result<(InterfaceId, usize), Error> { +fn get_interface_and_mtu_linux_macos(socket: &UdpSocket) -> Result<(String, usize), Error> { + use std::ffi::{c_int, CStr}; #[cfg(target_os = "linux")] use std::{ffi::c_char, mem, os::fd::AsRawFd}; - use std::{ - ffi::{c_int, CStr}, - hash::{DefaultHasher, Hash, Hasher}, - }; use libc::{ freeifaddrs, getifaddrs, ifaddrs, in_addr_t, sockaddr_in, sockaddr_in6, AF_INET, AF_INET6, @@ -95,12 +90,6 @@ fn get_interface_and_mtu_linux_macos(socket: &UdpSocket) -> Result<(InterfaceId, #[cfg(target_os = "linux")] use libc::{ifreq, ioctl}; - fn hash_interface_name(name: &str) -> InterfaceId { - let mut hasher = DefaultHasher::new(); - name.hash(&mut hasher); - hasher.finish() - } - // Get the interface list. let mut ifap: *mut ifaddrs = ptr::null_mut(); if unsafe { getifaddrs(&mut ifap) } != 0 { @@ -163,7 +152,7 @@ fn get_interface_and_mtu_linux_macos(socket: &UdpSocket) -> Result<(InterfaceId, { let data = unsafe { &*(ifa.ifa_data as *const if_data) }; if let Ok(mtu) = usize::try_from(data.ifi_mtu) { - res = Ok((hash_interface_name(iface), mtu)); + res = Ok((iface.to_string(), mtu)); } break; } @@ -182,7 +171,7 @@ fn get_interface_and_mtu_linux_macos(socket: &UdpSocket) -> Result<(InterfaceId, if unsafe { ioctl(socket.as_raw_fd(), libc::SIOCGIFMTU, &ifr) } != 0 { res = Err(Error::last_os_error()); } else if let Ok(mtu) = usize::try_from(unsafe { ifr.ifr_ifru.ifru_mtu }) { - res = Ok((hash_interface_name(iface), mtu)); + res = Ok((iface.to_string(), mtu)); } } } @@ -192,18 +181,15 @@ fn get_interface_and_mtu_linux_macos(socket: &UdpSocket) -> Result<(InterfaceId, } #[cfg(target_os = "windows")] -fn get_interface_and_mtu_windows(socket: &UdpSocket) -> Result<(InterfaceId, usize), Error> { - use std::{ - ffi::c_void, - hash::{DefaultHasher, Hash, Hasher}, - slice, - }; +fn get_interface_and_mtu_windows(socket: &UdpSocket) -> Result<(String, usize), Error> { + use std::{ffi::c_void, slice}; use windows::Win32::{ Foundation::NO_ERROR, NetworkManagement::IpHelper::{ - FreeMibTable, GetIpInterfaceTable, GetUnicastIpAddressTable, MIB_IPINTERFACE_ROW, - MIB_IPINTERFACE_TABLE, MIB_UNICASTIPADDRESS_ROW, MIB_UNICASTIPADDRESS_TABLE, + if_indextoname, FreeMibTable, GetIpInterfaceTable, GetUnicastIpAddressTable, + MIB_IPINTERFACE_ROW, MIB_IPINTERFACE_TABLE, MIB_UNICASTIPADDRESS_ROW, + MIB_UNICASTIPADDRESS_TABLE, }, Networking::WinSock::{AF_INET, AF_INET6, AF_UNSPEC}, }; @@ -257,10 +243,9 @@ fn get_interface_and_mtu_windows(socket: &UdpSocket) -> Result<(InterfaceId, usi for iface in ifaces { if iface.InterfaceIndex == addr.InterfaceIndex { if let Ok(mtu) = iface.NlMtu.try_into() { - let mut hasher = DefaultHasher::new(); - iface.InterfaceIndex.hash(&mut hasher); - let id = hasher.finish(); - res = Ok((id, mtu)); + if_indextoname(iface.InterfaceIndex, |name| { + res = Ok((name, mtu)); + }); } break 'addr_loop; } @@ -289,7 +274,7 @@ fn get_interface_and_mtu_windows(socket: &UdpSocket) -> Result<(InterfaceId, usi /// ``` /// let saddr = "127.0.0.1:443".parse().unwrap(); /// let mtu = mtu::get_interface_mtu(&saddr).unwrap(); -/// println!("MTU towards {:?} is {}", saddr, mtu); +/// println!("MTU towards {saddr:?} is {mtu}"); /// ``` /// /// # Errors From f53cd88f367cf672167458682a56ea764624992c Mon Sep 17 00:00:00 2001 From: Lars Eggert Date: Tue, 3 Sep 2024 12:03:40 +0300 Subject: [PATCH 09/21] Fixes --- src/lib.rs | 5 +++-- 1 file changed, 3 insertions(+), 2 deletions(-) diff --git a/src/lib.rs b/src/lib.rs index fc5a49b..68d8d0a 100644 --- a/src/lib.rs +++ b/src/lib.rs @@ -243,9 +243,10 @@ fn get_interface_and_mtu_windows(socket: &UdpSocket) -> Result<(String, usize), for iface in ifaces { if iface.InterfaceIndex == addr.InterfaceIndex { if let Ok(mtu) = iface.NlMtu.try_into() { - if_indextoname(iface.InterfaceIndex, |name| { + let name = String::with_capacity(256); // IF_NAMESIZE not available? + if !if_indextoname(iface.InterfaceIndex, &name).is_null() { res = Ok((name, mtu)); - }); + } } break 'addr_loop; } From 734d33ef6aca874d5c2fdcdcc7a60ef6f1cc7dc1 Mon Sep 17 00:00:00 2001 From: Lars Eggert Date: Tue, 3 Sep 2024 12:07:14 +0300 Subject: [PATCH 10/21] Fixes --- src/lib.rs | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/lib.rs b/src/lib.rs index 68d8d0a..5da21fa 100644 --- a/src/lib.rs +++ b/src/lib.rs @@ -244,7 +244,7 @@ fn get_interface_and_mtu_windows(socket: &UdpSocket) -> Result<(String, usize), if iface.InterfaceIndex == addr.InterfaceIndex { if let Ok(mtu) = iface.NlMtu.try_into() { let name = String::with_capacity(256); // IF_NAMESIZE not available? - if !if_indextoname(iface.InterfaceIndex, &name).is_null() { + if !if_indextoname(iface.InterfaceIndex, &mut name).is_null() { res = Ok((name, mtu)); } } From 6b421810fb950d9118a0cecf9c350f86e20c5031 Mon Sep 17 00:00:00 2001 From: Lars Eggert Date: Tue, 3 Sep 2024 12:13:24 +0300 Subject: [PATCH 11/21] Fixes --- src/lib.rs | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/src/lib.rs b/src/lib.rs index 66a945f..42f498b 100644 --- a/src/lib.rs +++ b/src/lib.rs @@ -273,14 +273,14 @@ fn interface_and_mtu_windows(socket: &UdpSocket) -> Result<(String, usize), Erro /// platforms for some remote destinations. (For example, loopback destinations on /// Windows.) /// -/// This function is a convenience wrapper around [`get_interface_and_mtu`] that only returns the +/// This function is a convenience wrapper around [`interface_and_mtu`] that only returns the /// MTU. It is provided for compatibility with version 0.1 of the `mtu` crate. /// /// # Examples /// /// ``` /// let saddr = "127.0.0.1:443".parse().unwrap(); -/// let mtu = mtu::get_interface_mtu(&saddr).unwrap(); +/// let mtu = mtu::interface_mtu(&saddr).unwrap(); /// println!("MTU towards {saddr:?} is {mtu}"); /// ``` /// From 45991d401095fb5af874428fed5035048ff09c55 Mon Sep 17 00:00:00 2001 From: Lars Eggert Date: Tue, 3 Sep 2024 12:24:03 +0300 Subject: [PATCH 12/21] Fixes --- src/lib.rs | 7 +++++-- 1 file changed, 5 insertions(+), 2 deletions(-) diff --git a/src/lib.rs b/src/lib.rs index 42f498b..cb0b260 100644 --- a/src/lib.rs +++ b/src/lib.rs @@ -188,6 +188,7 @@ fn interface_and_mtu_linux_macos(socket: &UdpSocket) -> Result<(String, usize), #[cfg(target_os = "windows")] fn interface_and_mtu_windows(socket: &UdpSocket) -> Result<(String, usize), Error> { + use core::str; use std::{ffi::c_void, slice}; use windows::Win32::{ @@ -249,9 +250,11 @@ fn interface_and_mtu_windows(socket: &UdpSocket) -> Result<(String, usize), Erro for iface in ifaces { if iface.InterfaceIndex == addr.InterfaceIndex { if let Ok(mtu) = iface.NlMtu.try_into() { - let name = String::with_capacity(256); // IF_NAMESIZE not available? + let name: [u8; 256]; // IF_NAMESIZE not available? if !if_indextoname(iface.InterfaceIndex, &mut name).is_null() { - res = Ok((name, mtu)); + if let Ok(name) = str::from_utf8(&name) { + res = Ok((name.to_string(), mtu)); + } } } break 'addr_loop; From 78e8a785d7b5f6cdbcc7a51e920d63474e02129c Mon Sep 17 00:00:00 2001 From: Lars Eggert Date: Tue, 3 Sep 2024 12:29:26 +0300 Subject: [PATCH 13/21] Fixes --- src/lib.rs | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/src/lib.rs b/src/lib.rs index cb0b260..f9204b0 100644 --- a/src/lib.rs +++ b/src/lib.rs @@ -250,8 +250,8 @@ fn interface_and_mtu_windows(socket: &UdpSocket) -> Result<(String, usize), Erro for iface in ifaces { if iface.InterfaceIndex == addr.InterfaceIndex { if let Ok(mtu) = iface.NlMtu.try_into() { - let name: [u8; 256]; // IF_NAMESIZE not available? - if !if_indextoname(iface.InterfaceIndex, &mut name).is_null() { + let name = [0u8; 256]; // IF_NAMESIZE not available? + if unsafe { !if_indextoname(iface.InterfaceIndex, &mut name).is_null() } { if let Ok(name) = str::from_utf8(&name) { res = Ok((name.to_string(), mtu)); } From 28cba5ff9f717e021060728d78c9b128a8608eff Mon Sep 17 00:00:00 2001 From: Lars Eggert Date: Tue, 3 Sep 2024 12:33:52 +0300 Subject: [PATCH 14/21] Docs --- README.md | 4 ++-- src/lib.rs | 6 ++---- 2 files changed, 4 insertions(+), 6 deletions(-) diff --git a/README.md b/README.md index ff4b53c..984b07b 100644 --- a/README.md +++ b/README.md @@ -10,7 +10,7 @@ The main function exported by this crate is pub fn interface_and_mtu(remote: &SocketAddr) -> Result<(String, usize), Error> ``` -that returns an opaque identifier of the local network interface towards the `remote` destination together with its MTU, or an `Error` when the MTU could not be determined. It supports both IPv4 and IPv6. +that returns the interface name and MTU of the local network interface used for transmission towards the `remote` destination, or an `Error` when the MTU could not be determined. It supports both IPv4 and IPv6. ## Supported Platforms @@ -22,7 +22,7 @@ that returns an opaque identifier of the local network interface towards the `re The returned MTU may exceed the maximum IP packet size of 65,535 bytes on some platforms for some remote destinations. (For example, loopback destinations on Windows.) -The returned interface ID is an opaque identifier that can be used to identify the local interface. It is a hash of the interface name (on Linux and macOS) or interface index (on Windows), and has the same stability guarantees as those identifiers. +The returned interface name is obtained from the operating system. ## Contributing diff --git a/src/lib.rs b/src/lib.rs index f9204b0..a464bdb 100644 --- a/src/lib.rs +++ b/src/lib.rs @@ -20,16 +20,14 @@ fn default_result() -> Result<(String, T), Error> { )) } -/// Return a unique interface ID and the maximum transmission unit (MTU) of the local network +/// Return the interface name and the maximum transmission unit (MTU) of the local network /// interface towards the destination [`SocketAddr`] given in `remote`. /// /// The returned MTU may exceed the maximum IP packet size of 65,535 bytes on some /// platforms for some remote destinations. (For example, loopback destinations on /// Windows.) /// -/// The returned interface ID is an opaque identifier that can be used to identify the local -/// interface. It is a hash of the interface name (on Linux and macOS) or interface index (on -/// Windows), and has the same stability guarantees as those identifiers. +/// The returned interface name is obtained from the operating system. /// /// # Examples /// From d12d925c3d8052a253ad7ba42942841dd2ce8853 Mon Sep 17 00:00:00 2001 From: Lars Eggert Date: Tue, 3 Sep 2024 12:34:26 +0300 Subject: [PATCH 15/21] Fixes --- src/lib.rs | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/lib.rs b/src/lib.rs index a464bdb..cdac0cf 100644 --- a/src/lib.rs +++ b/src/lib.rs @@ -248,7 +248,7 @@ fn interface_and_mtu_windows(socket: &UdpSocket) -> Result<(String, usize), Erro for iface in ifaces { if iface.InterfaceIndex == addr.InterfaceIndex { if let Ok(mtu) = iface.NlMtu.try_into() { - let name = [0u8; 256]; // IF_NAMESIZE not available? + let mut name = [0u8; 256]; // IF_NAMESIZE not available? if unsafe { !if_indextoname(iface.InterfaceIndex, &mut name).is_null() } { if let Ok(name) = str::from_utf8(&name) { res = Ok((name.to_string(), mtu)); From 7c8584587f47cc3d303dbc622a4e1fa6b98322e9 Mon Sep 17 00:00:00 2001 From: Lars Eggert Date: Tue, 3 Sep 2024 12:38:32 +0300 Subject: [PATCH 16/21] Pass up error --- src/lib.rs | 2 ++ 1 file changed, 2 insertions(+) diff --git a/src/lib.rs b/src/lib.rs index cdac0cf..25c0d2a 100644 --- a/src/lib.rs +++ b/src/lib.rs @@ -253,6 +253,8 @@ fn interface_and_mtu_windows(socket: &UdpSocket) -> Result<(String, usize), Erro if let Ok(name) = str::from_utf8(&name) { res = Ok((name.to_string(), mtu)); } + } else { + res = Err(Error::last_os_error()); } } break 'addr_loop; From 343db2a460ed277c5bcee01c80bdcc1a20c85b0b Mon Sep 17 00:00:00 2001 From: Lars Eggert Date: Tue, 3 Sep 2024 12:49:10 +0300 Subject: [PATCH 17/21] Deprecate more --- README.md | 2 +- src/lib.rs | 39 ++++++++++----------------------------- 2 files changed, 11 insertions(+), 30 deletions(-) diff --git a/README.md b/README.md index 984b07b..b6b4428 100644 --- a/README.md +++ b/README.md @@ -4,7 +4,7 @@ A crate to return the maximum transmission unit (MTU) of the local network inter ## Usage -The main function exported by this crate is +This crate exports a single function ```rust pub fn interface_and_mtu(remote: &SocketAddr) -> Result<(String, usize), Error> diff --git a/src/lib.rs b/src/lib.rs index 25c0d2a..d968133 100644 --- a/src/lib.rs +++ b/src/lib.rs @@ -74,12 +74,6 @@ pub fn interface_and_mtu(remote: &SocketAddr) -> Result<(String, usize), Error> res } -#[doc(hidden)] -#[deprecated(since = "0.1.2", note = "Use `interface_mtu()` instead")] -pub fn get_interface_mtu(remote: &SocketAddr) -> Result { - interface_mtu(remote) -} - #[cfg(any(target_os = "macos", target_os = "linux"))] fn interface_and_mtu_linux_macos(socket: &UdpSocket) -> Result<(String, usize), Error> { use std::ffi::{c_int, CStr}; @@ -269,31 +263,18 @@ fn interface_and_mtu_windows(socket: &UdpSocket) -> Result<(String, usize), Erro res } -/// Return the maximum transmission unit (MTU) of the local network interface towards the -/// destination [`SocketAddr`] given in `remote`. -/// -/// The returned MTU may exceed the maximum IP packet size of 65,535 bytes on some -/// platforms for some remote destinations. (For example, loopback destinations on -/// Windows.) -/// -/// This function is a convenience wrapper around [`interface_and_mtu`] that only returns the -/// MTU. It is provided for compatibility with version 0.1 of the `mtu` crate. -/// -/// # Examples -/// -/// ``` -/// let saddr = "127.0.0.1:443".parse().unwrap(); -/// let mtu = mtu::interface_mtu(&saddr).unwrap(); -/// println!("MTU towards {saddr:?} is {mtu}"); -/// ``` -/// -/// # Errors -/// -/// This function returns an error if the local interface MTU cannot be determined. +#[doc(hidden)] +#[deprecated(since = "0.1.2", note = "Use `interface_and_mtu()` instead")] pub fn interface_mtu(remote: &SocketAddr) -> Result { interface_and_mtu(remote).map(|(_, mtu)| mtu) } +#[doc(hidden)] +#[deprecated(since = "0.1.2", note = "Use `interface_and_mtu()` instead")] +pub fn get_interface_mtu(remote: &SocketAddr) -> Result { + interface_and_mtu(remote).map(|(_, mtu)| mtu) +} + #[cfg(test)] mod test { use std::net::ToSocketAddrs; @@ -306,8 +287,8 @@ mod test { .unwrap() .find(|a| a.is_ipv4() == ipv4); if let Some(addr) = addr { - match super::interface_mtu(&addr) { - Ok(mtu) => assert_eq!(mtu, expected), + match super::interface_and_mtu(&addr) { + Ok((_, mtu)) => assert_eq!(mtu, expected), Err(e) => { // Some GitHub runners don't have IPv6. Just warn if we can't get the MTU. assert!(addr.is_ipv6()); From 78a11529f7926ce556e2044a559b4862f470d540 Mon Sep 17 00:00:00 2001 From: Lars Eggert Date: Tue, 3 Sep 2024 12:56:45 +0300 Subject: [PATCH 18/21] Add test --- src/lib.rs | 8 ++++++++ 1 file changed, 8 insertions(+) diff --git a/src/lib.rs b/src/lib.rs index d968133..8a38990 100644 --- a/src/lib.rs +++ b/src/lib.rs @@ -331,4 +331,12 @@ mod test { fn default_interface_mtu_v6() { check_mtu("ietf.org:443", false, 1500); } + + #[test] + #[allow(deprecated)] // Purpose of the test is to cover deprecated functions. + fn deprecated_functions() { + let addr = "localhost:443".to_socket_addrs().unwrap().next().unwrap(); + assert!(super::interface_mtu(&addr).is_ok()); + assert!(super::get_interface_mtu(&addr).is_ok()); + } } From 1170b3bb00d7919abddb3a4f7cab51bd500f44aa Mon Sep 17 00:00:00 2001 From: Lars Eggert Date: Wed, 4 Sep 2024 09:58:07 +0300 Subject: [PATCH 19/21] Add `if_indextoname` --- src/lib.rs | 4 ++-- tests/win_bindings.rs | 1 + 2 files changed, 3 insertions(+), 2 deletions(-) diff --git a/src/lib.rs b/src/lib.rs index c7ffe77..7ed5c3a 100644 --- a/src/lib.rs +++ b/src/lib.rs @@ -189,8 +189,8 @@ fn interface_and_mtu_windows(socket: &UdpSocket) -> Result<(String, usize), Erro use std::{ffi::c_void, slice}; use win_bindings::{ - FreeMibTable, GetIpInterfaceTable, GetUnicastIpAddressTable, AF_INET, AF_INET6, AF_UNSPEC, - MIB_IPINTERFACE_ROW, MIB_IPINTERFACE_TABLE, MIB_UNICASTIPADDRESS_ROW, + if_indextoname, FreeMibTable, GetIpInterfaceTable, GetUnicastIpAddressTable, AF_INET, + AF_INET6, AF_UNSPEC, MIB_IPINTERFACE_ROW, MIB_IPINTERFACE_TABLE, MIB_UNICASTIPADDRESS_ROW, MIB_UNICASTIPADDRESS_TABLE, NO_ERROR, }; diff --git a/tests/win_bindings.rs b/tests/win_bindings.rs index 09afdc2..1367397 100644 --- a/tests/win_bindings.rs +++ b/tests/win_bindings.rs @@ -19,6 +19,7 @@ fn codegen_windows_bindings() { "Windows.Win32.NetworkManagement.IpHelper.MIB_IPINTERFACE_TABLE", "Windows.Win32.NetworkManagement.IpHelper.MIB_UNICASTIPADDRESS_ROW", "Windows.Win32.NetworkManagement.IpHelper.MIB_UNICASTIPADDRESS_TABLE", + "Windows.Win32.NetworkManagement.IpHelper.if_indextoname", "Windows.Win32.Networking.WinSock.AF_INET", "Windows.Win32.Networking.WinSock.AF_INET6", "Windows.Win32.Networking.WinSock.AF_UNSPEC", From e1b2076df485fd85a31c6dfae0a94a792237acd0 Mon Sep 17 00:00:00 2001 From: Lars Eggert Date: Wed, 4 Sep 2024 10:33:23 +0300 Subject: [PATCH 20/21] Bindings from #18 --- src/win_bindings.rs | 9 +++++++++ 1 file changed, 9 insertions(+) diff --git a/src/win_bindings.rs b/src/win_bindings.rs index 4c4273a..dd0b822 100644 --- a/src/win_bindings.rs +++ b/src/win_bindings.rs @@ -28,6 +28,14 @@ pub unsafe fn GetUnicastIpAddressTable( windows_targets::link!("iphlpapi.dll" "system" fn GetUnicastIpAddressTable(family : ADDRESS_FAMILY, table : *mut *mut MIB_UNICASTIPADDRESS_TABLE) -> WIN32_ERROR); GetUnicastIpAddressTable(family, table) } +#[inline] +pub unsafe fn if_indextoname( + interfaceindex: u32, + interfacename: &mut [u8; 256], +) -> windows_core::PSTR { + windows_targets::link!("iphlpapi.dll" "system" fn if_indextoname(interfaceindex : u32, interfacename : windows_core::PSTR) -> windows_core::PSTR); + if_indextoname(interfaceindex, core::mem::transmute(interfacename.as_ptr())) +} #[repr(transparent)] #[derive(PartialEq, Eq, Copy, Clone, Default)] pub struct ADDRESS_FAMILY(pub u16); @@ -450,3 +458,4 @@ impl core::fmt::Debug for WIN32_ERROR { f.debug_tuple("WIN32_ERROR").field(&self.0).finish() } } + From 608403389cfe662070b8846a288321709e73cd3d Mon Sep 17 00:00:00 2001 From: Lars Eggert Date: Wed, 4 Sep 2024 10:34:35 +0300 Subject: [PATCH 21/21] Nit --- src/win_bindings.rs | 1 - 1 file changed, 1 deletion(-) diff --git a/src/win_bindings.rs b/src/win_bindings.rs index dd0b822..107b5c6 100644 --- a/src/win_bindings.rs +++ b/src/win_bindings.rs @@ -458,4 +458,3 @@ impl core::fmt::Debug for WIN32_ERROR { f.debug_tuple("WIN32_ERROR").field(&self.0).finish() } } -