Skip to content
This repository was archived by the owner on Sep 2, 2025. It is now read-only.
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
1 change: 1 addition & 0 deletions .clippy.toml
Original file line number Diff line number Diff line change
@@ -0,0 +1 @@
doc-valid-idents = ["NetBSD", "OpenBSD", ".."]
19 changes: 19 additions & 0 deletions .github/workflows/check.yml
Original file line number Diff line number Diff line change
Expand Up @@ -198,6 +198,25 @@ jobs:

- run: cargo semver-checks

readme:
runs-on: ubuntu-latest
steps:
- uses: actions/checkout@d632683dd7b4114ad314bca15554477dd762a938 # v4.2.0
- uses: actions/checkout@d632683dd7b4114ad314bca15554477dd762a938 # v4.2.0
with:
repository: mozilla/neqo
sparse-checkout: |
.github/actions/rust
path: neqo
- uses: ./neqo/.github/actions/rust
with:
tools: cargo-readme
token: ${{ secrets.GITHUB_TOKEN }}

- run: |
cargo readme -o /tmp/README.md
diff -u README.md /tmp/README.md

check-vm:
strategy:
fail-fast: false
Expand Down
6 changes: 6 additions & 0 deletions Cargo.toml
Original file line number Diff line number Diff line change
Expand Up @@ -15,6 +15,12 @@ license = "MIT OR Apache-2.0"
# Also keep in sync with .github/workflows/check.yml
rust-version = "1.76.0"

[badges]
codecov = { repository = "mozilla/mtu", branch = "main" }
is-it-maintained-issue-resolution = { repository = "mozilla/mtu", branch = "main" }
is-it-maintained-open-issues = { repository = "mozilla/mtu", branch = "main" }
maintenance = { status = "actively-developed", branch = "main" }

[dependencies]
# Don't increase beyond what Firefox is currently using: https://searchfox.org/mozilla-central/source/Cargo.lock
libc = { version = "0.2", default-features = false }
Expand Down
22 changes: 17 additions & 5 deletions README.md
Original file line number Diff line number Diff line change
@@ -1,12 +1,20 @@
# MTU
[![Coverage Status](https://codecov.io/gh/mozilla/mtu/branch/main/graph/badge.svg)](https://codecov.io/gh/mozilla/mtu)
[![Average time to resolve an issue](https://isitmaintained.com/badge/resolution/mozilla/mtu.svg)](https://isitmaintained.com/project/mozilla/mtu "Average time to resolve an issue")
[![Percentage of issues still open](https://isitmaintained.com/badge/open/mozilla/mtu.svg)](https://isitmaintained.com/project/mozilla/mtu "Percentage of issues still open")
![Maintenance](https://img.shields.io/badge/maintenance-activly--developed-brightgreen.svg)

A crate to return the name and maximum transmission unit (MTU) of the local network interface towards a given destination `SocketAddr`, optionally from a given local `SocketAddr`.
# mtu

A crate to return the name and maximum transmission unit (MTU) of the local network interface
towards a given destination `SocketAddr`, optionally from a given local `SocketAddr`.

## Usage

This crate exports a single function `interface_and_mtu` that, given a pair of local and remote `SocketAddr`s, returns the name and [maximum transmission unit (MTU)](https://en.wikipedia.org/wiki/Maximum_transmission_unit) of the local network interface used by a socket bound to the local address and connected towards the remote destination.

If the local address is `None`, the function will let the operating system choose the local address based on the given remote address. If the remote address is `None`, the function will return the name and MTU of the local network interface with the given local address.
If the local address is `None`, the function will let the operating system choose the local
address based on the given remote address. If the remote address is `None`, the function will
return the name and MTU of the local network interface with the given local address.

## Example

Expand All @@ -27,10 +35,14 @@ println!("MTU for {saddr:?} is {mtu} on {name}");

## Notes

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 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 name is obtained from the operating system.

## Contributing

We're happy to receive PRs that improve this crate. Please take a look at our [community guidelines](CODE_OF_CONDUCT.md) beforehand.
We're happy to receive PRs that improve this crate. Please take a look at our [community
guidelines](CODE_OF_CONDUCT.md) beforehand.

License: MIT OR Apache-2.0
49 changes: 44 additions & 5 deletions src/lib.rs
Original file line number Diff line number Diff line change
Expand Up @@ -4,6 +4,46 @@
// option. This file may not be copied, modified, or distributed
// except according to those terms.

//! A crate to return the name and maximum transmission unit (MTU) of the local network interface
//! towards a given destination `SocketAddr`, optionally from a given local `SocketAddr`.
//!
//! # Usage
//!
//! This crate exports a single function `interface_and_mtu` that, given a pair of local and remote `SocketAddr`s, returns the name and [maximum transmission unit (MTU)](https://en.wikipedia.org/wiki/Maximum_transmission_unit) of the local network interface used by a socket bound to the local address and connected towards the remote destination.
//!
//! If the local address is `None`, the function will let the operating system choose the local
//! address based on the given remote address. If the remote address is `None`, the function will
//! return the name and MTU of the local network interface with the given local address.
//!
//! # Example
//!
//! ```rust
//! let saddr = "127.0.0.1:443".parse().unwrap();
//! let (name, mtu) = mtu::interface_and_mtu(&(None, saddr)).unwrap();
//! println!("MTU for {saddr:?} is {mtu} on {name}");
//! ```
//!
//! # Supported Platforms
//!
//! * Linux
//! * macOS
//! * Windows
//! * FreeBSD
//! * NetBSD
//! * OpenBSD
//!
//! # Notes
//!
//! 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 name is obtained from the operating system.
//!
//! # Contributing
//!
//! We're happy to receive PRs that improve this crate. Please take a look at our [community
//! guidelines](CODE_OF_CONDUCT.md) beforehand.

use std::{
io::{Error, ErrorKind},
net::{IpAddr, Ipv4Addr, Ipv6Addr, SocketAddr, UdpSocket},
Expand Down Expand Up @@ -120,12 +160,12 @@ fn interface_and_mtu_impl(_socket: &UdpSocket) -> Result<(String, usize), Error>
target_os = "linux"
))]
fn interface_and_mtu_impl(socket: &UdpSocket) -> Result<(String, usize), Error> {
#[cfg(target_os = "linux")]
use std::{ffi::c_char, mem, os::fd::AsRawFd};
use std::{
ffi::{c_int, CStr},
ptr,
};
#[cfg(target_os = "linux")]
use std::{mem, os::fd::AsRawFd};

use libc::{
freeifaddrs, getifaddrs, ifaddrs, in_addr_t, sockaddr_in, sockaddr_in6, AF_INET, AF_INET6,
Expand Down Expand Up @@ -220,9 +260,8 @@ fn interface_and_mtu_impl(socket: &UdpSocket) -> Result<(String, usize), Error>
{
// On Linux, we can get the MTU via an ioctl on the socket.
let mut ifr: ifreq = unsafe { mem::zeroed() };
ifr.ifr_name[..iface.len()].copy_from_slice(unsafe {
&*(ptr::from_ref::<[u8]>(iface.as_bytes()) as *const [c_char])
});
ifr.ifr_name[..iface.len()]
.copy_from_slice(unsafe { &*ptr::from_ref::<[u8]>(iface.as_bytes()) });
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 }) {
Expand Down