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
42 changes: 36 additions & 6 deletions Cargo.toml
Original file line number Diff line number Diff line change
Expand Up @@ -12,7 +12,7 @@ edition = "2021"
license = "MIT OR Apache-2.0"
# Don't increase beyond what Firefox is currently using:
# https://searchfox.org/mozilla-central/search?q=MINIMUM_RUST_VERSION&path=python/mozboot/mozboot/util.py
rust-version = "1.76.0"
rust-version = "1.82.0"

[badges]
codecov = { repository = "mozilla/mtu", branch = "main" }
Expand Down Expand Up @@ -46,7 +46,6 @@ gecko = ["dep:mozbuild"]
[lints.rust]
absolute_paths_not_starting_with_crate = "warn"
ambiguous_negative_literals = "warn"
closure_returning_async_block = "warn"
explicit_outlives_requirements = "warn"
macro_use_extern_crate = "warn"
missing_abi = "warn"
Expand All @@ -58,27 +57,58 @@ unit_bindings = "warn"
unused_import_braces = "warn"
unused_lifetimes = "warn"
unused_macro_rules = "warn"
# unused_qualifications = "warn" # Try to re-enable when MSRV is > 1.76
unused_qualifications = "warn"

[lints.clippy]
cargo = { level = "warn", priority = -1 }
nursery = { level = "warn", priority = -1 }
pedantic = { level = "warn", priority = -1 }
multiple_crate_versions = "allow"
allow_attributes = "warn"
allow_attributes_without_reason = "warn"
Comment thread
larseggert marked this conversation as resolved.
cfg_not_test = "warn"
clone_on_ref_ptr = "warn"
create_dir = "warn"
if_then_some_else_none = "warn"
dbg_macro = "warn"
empty_drop = "warn"
empty_enum_variants_with_brackets = "warn"
filetype_is_file = "warn"
float_cmp_const = "warn"
fn_to_numeric_cast_any = "warn"
get_unwrap = "warn"
if_then_some_else_none = "warn"
infinite_loop = "warn"
large_include_file = "warn"
let_underscore_must_use = "warn"
let_underscore_untyped = "warn"
literal_string_with_formatting_args = "allow" # FIXME: Re-enable "warn" when MRSV is > 1.87. See https://github.com/rust-lang/rust-clippy/pull/13953#issuecomment-2676336899
lossy_float_literal = "warn"
mem_forget = "warn"
mixed_read_write_in_expression = "warn"
multiple_crate_versions = "allow"
multiple_inherent_impl = "warn"
mutex_atomic = "warn"
mutex_integer = "warn"
needless_raw_strings = "warn"
pathbuf_init_then_push = "warn"
pub_without_shorthand = "warn"
rc_buffer = "warn"
rc_mutex = "warn"
redundant_type_annotations = "warn"
ref_patterns = "warn"
renamed_function_params = "warn"
rest_pat_in_fully_bound_structs = "warn"
self_named_module_files = "warn"
semicolon_inside_block = "warn"
string_lit_chars_any = "warn"
string_to_string = "warn"
suspicious_xor_used_as_pow = "warn"
try_err = "warn"
unnecessary_safety_comment = "warn"
unnecessary_safety_doc = "warn"
unnecessary_self_imports = "warn"
unneeded_field_pattern = "warn"
unused_result_ok = "warn"
unused_trait_names = "warn"
unwrap_used = "warn"
unwrap_in_result = "warn"
unwrap_used = "warn"
verbose_file_reads = "warn"
2 changes: 1 addition & 1 deletion build.rs
Original file line number Diff line number Diff line change
Expand Up @@ -4,7 +4,7 @@
// option. This file may not be copied, modified, or distributed
// except according to those terms.

#![allow(clippy::unwrap_used)] // OK in build scripts.
#![expect(clippy::unwrap_used, reason = "OK in build scripts.")]

use std::env;

Expand Down
91 changes: 50 additions & 41 deletions src/bsd.rs
Original file line number Diff line number Diff line change
Expand Up @@ -21,11 +21,14 @@ use libc::{
use static_assertions::{const_assert, const_assert_eq};

#[allow(
clippy::allow_attributes,
non_camel_case_types,
non_snake_case,
clippy::struct_field_names,
clippy::too_many_lines,
clippy::cognitive_complexity,
dead_code // RTA_IFP is only used on NetBSD and Solaris
dead_code, // RTA_IFP is only used on NetBSD and Solaris
reason = "Bindgen-generated code"
)]
mod bindings {
include!(env!("BINDINGS"));
Expand All @@ -42,13 +45,13 @@ use crate::{
};

#[cfg(target_os = "macos")]
const ALIGN: usize = std::mem::size_of::<libc::c_int>();
const ALIGN: usize = size_of::<libc::c_int>();

#[cfg(bsd)]
// See https://github.com/freebsd/freebsd-src/blob/524a425d30fce3d5e47614db796046830b1f6a83/sys/net/route.h#L362-L371
// See https://github.com/NetBSD/src/blob/4b50954e98313db58d189dd87b4541929efccb09/sys/net/route.h#L329-L331
// See https://github.com/Arquivotheca/Solaris-8/blob/2ad1d32f9eeed787c5adb07eb32544276e2e2444/osnet_volume/usr/src/cmd/cmd-inet/usr.sbin/route.c#L238-L239
const ALIGN: usize = std::mem::size_of::<libc::c_long>();
const ALIGN: usize = size_of::<libc::c_long>();

#[cfg(any(target_os = "macos", target_os = "freebsd", target_os = "openbsd"))]
asserted_const_with_type!(RTM_ADDRS, i32, RTA_DST, u32);
Expand All @@ -68,9 +71,9 @@ asserted_const_with_type!(AF_LINK, AddressFamily, libc::AF_LINK, i32);
asserted_const_with_type!(RTM_VERSION, u8, bindings::RTM_VERSION, u32);
asserted_const_with_type!(RTM_GET, u8, bindings::RTM_GET, u32);

const_assert!(std::mem::size_of::<sockaddr_in>() + ALIGN <= u8::MAX as usize);
const_assert!(std::mem::size_of::<sockaddr_in6>() + ALIGN <= u8::MAX as usize);
const_assert!(std::mem::size_of::<rt_msghdr>() <= u8::MAX as usize);
const_assert!(size_of::<sockaddr_in>() + ALIGN <= u8::MAX as usize);
const_assert!(size_of::<sockaddr_in6>() + ALIGN <= u8::MAX as usize);
const_assert!(size_of::<rt_msghdr>() <= u8::MAX as usize);

struct IfAddrs(*mut ifaddrs);

Expand Down Expand Up @@ -165,7 +168,7 @@ fn if_name_mtu(idx: u32) -> Result<(String, Option<usize>)> {
let name = unsafe {
CStr::from_ptr(name.as_ptr())
.to_str()
.map_err(|err| Error::new(ErrorKind::Other, err))?
.map_err(Error::other)?
};
let mtu = IfAddrs::new()?
.iter()
Expand All @@ -183,8 +186,8 @@ union SockaddrStorage {

fn sockaddr_len(af: AddressFamily) -> Result<usize> {
let sa_len = match af {
AF_INET => std::mem::size_of::<sockaddr_in>(),
AF_INET6 => std::mem::size_of::<sockaddr_in6>(),
AF_INET => size_of::<sockaddr_in>(),
AF_INET6 => size_of::<sockaddr_in6>(),
_ => {
return Err(Error::new(
ErrorKind::InvalidInput,
Expand All @@ -200,33 +203,37 @@ impl From<IpAddr> for SockaddrStorage {
match ip {
IpAddr::V4(ip) => SockaddrStorage {
sin: sockaddr_in {
#[cfg(not(target_os = "solaris"))]
#[allow(clippy::cast_possible_truncation)]
// `sockaddr_in` len is <= u8::MAX per `const_assert!` above.
sin_len: std::mem::size_of::<sockaddr_in>() as u8,
sin_family: AF_INET,
sin_addr: in_addr {
s_addr: u32::from_ne_bytes(ip.octets()),
#[cfg(not(target_os = "solaris"))]
#[expect(
clippy::cast_possible_truncation,
reason = "`sockaddr_in` len is <= u8::MAX per `const_assert!` above."
)]
sin_len: size_of::<sockaddr_in>() as u8,
sin_family: AF_INET,
sin_addr: in_addr {
s_addr: u32::from_ne_bytes(ip.octets()),
},
sin_port: 0,
sin_zero: [0; 8],
},
sin_port: 0,
sin_zero: [0; 8],
},
},
IpAddr::V6(ip) => SockaddrStorage {
sin6: sockaddr_in6 {
#[cfg(not(target_os = "solaris"))]
#[allow(clippy::cast_possible_truncation)]
// `sockaddr_in6` len is <= u8::MAX per `const_assert!` above.
sin6_len: std::mem::size_of::<sockaddr_in6>() as u8,
sin6_family: AF_INET6,
sin6_addr: in6_addr {
s6_addr: ip.octets(),
},
sin6_port: 0,
sin6_flowinfo: 0,
sin6_scope_id: 0,
#[cfg(target_os = "solaris")]
__sin6_src_id: 0,
#[cfg(not(target_os = "solaris"))]
#[expect(
clippy::cast_possible_truncation,
reason = "`sockaddr_in6` len is <= u8::MAX per `const_assert!` above."
)]
sin6_len: size_of::<sockaddr_in6>() as u8,
sin6_family: AF_INET6,
sin6_addr: in6_addr {
s6_addr: ip.octets(),
},
sin6_port: 0,
sin6_flowinfo: 0,
sin6_scope_id: 0,
#[cfg(target_os = "solaris")]
__sin6_src_id: 0,
},
},
}
Expand All @@ -248,9 +255,11 @@ impl RouteMessage {
})?;
Ok(Self {
rtm: rt_msghdr {
#[allow(clippy::cast_possible_truncation)]
// `rt_msghdr` len + `ALIGN` is <= u8::MAX per `const_assert!` above.
rtm_msglen: (std::mem::size_of::<rt_msghdr>() + sa_len) as u16,
#[expect(
clippy::cast_possible_truncation,
reason = "`rt_msghdr` len + `ALIGN` is <= u8::MAX per `const_assert!` above."
)]
rtm_msglen: (size_of::<rt_msghdr>() + sa_len) as u16,
rtm_version: RTM_VERSION,
rtm_type: RTM_GET,
rtm_seq: seq,
Expand All @@ -276,14 +285,14 @@ impl RouteMessage {

impl From<&RouteMessage> for &[u8] {
fn from(value: &RouteMessage) -> Self {
debug_assert!(value.len() >= std::mem::size_of::<Self>());
debug_assert!(value.len() >= size_of::<Self>());
unsafe { slice::from_raw_parts(ptr::from_ref(value).cast(), value.len()) }
}
}

impl From<&[u8]> for rt_msghdr {
fn from(value: &[u8]) -> Self {
debug_assert!(value.len() >= std::mem::size_of::<Self>());
debug_assert!(value.len() >= size_of::<Self>());
unsafe { ptr::read_unaligned(value.as_ptr().cast()) }
}
}
Expand All @@ -304,15 +313,15 @@ fn if_index_mtu(remote: IpAddr) -> Result<(u16, Option<usize>)> {
loop {
let mut buf = vec![
0u8;
std::mem::size_of::<rt_msghdr>() +
size_of::<rt_msghdr>() +
// There will never be `RTAX_MAX` sockaddrs attached, but it's a safe upper bound.
(RTAX_MAX as usize * std::mem::size_of::<sockaddr_storage>())
(RTAX_MAX as usize * size_of::<sockaddr_storage>())
];
let len = fd.read(&mut buf[..])?;
if len < std::mem::size_of::<rt_msghdr>() {
if len < size_of::<rt_msghdr>() {
return Err(default_err());
}
let (reply, mut sa) = buf.split_at(std::mem::size_of::<rt_msghdr>());
let (reply, mut sa) = buf.split_at(size_of::<rt_msghdr>());
let reply: rt_msghdr = reply.into();
if !(reply.rtm_version == query_version
&& reply.rtm_pid == pid
Expand Down
11 changes: 8 additions & 3 deletions src/lib.rs
Original file line number Diff line number Diff line change
Expand Up @@ -51,7 +51,12 @@ use std::{
#[cfg(not(target_os = "windows"))]
macro_rules! asserted_const_with_type {
($name:ident, $t1:ty, $e:expr, $t2:ty) => {
#[allow(clippy::cast_possible_truncation, clippy::cast_possible_wrap)] // Guarded by the following `const_assert_eq!`.
#[allow(
clippy::allow_attributes,
clippy::cast_possible_truncation,
clippy::cast_possible_wrap,
reason = "Guarded by the following `const_assert_eq!`."
)]
const $name: $t1 = $e as $t1;
const_assert_eq!($name as $t2, $e);
};
Expand Down Expand Up @@ -85,7 +90,7 @@ fn default_err() -> Error {
#[cfg(not(target_os = "windows"))]
fn unlikely_err(msg: String) -> Error {
debug_assert!(false, "{msg}");
Error::new(ErrorKind::Other, msg)
Error::other(msg)
}

/// Align `size` to the next multiple of `align` (which needs to be a power of two).
Expand Down Expand Up @@ -135,7 +140,7 @@ mod test {

impl PartialEq<NameMtu<'_>> for (String, usize) {
fn eq(&self, other: &NameMtu<'_>) -> bool {
other.0.map_or(true, |name| name == self.0) && other.1 == self.1
other.0.is_none_or(|name| name == self.0) && other.1 == self.1
}
}

Expand Down
Loading