From ccea376a9af7148b53fa5e6a54ede09f3a54fdfc Mon Sep 17 00:00:00 2001 From: shellrow Date: Sat, 8 Nov 2025 20:30:17 +0900 Subject: [PATCH 1/3] Add tests --- src/interface/interface.rs | 27 +++++++++++++++++ src/interface/mod.rs | 60 ++++++++++++++++++++++++++++++++++++++ src/net/db/oui.rs | 18 ++++++++++++ 3 files changed, 105 insertions(+) diff --git a/src/interface/interface.rs b/src/interface/interface.rs index ac95573..c59421b 100644 --- a/src/interface/interface.rs +++ b/src/interface/interface.rs @@ -246,3 +246,30 @@ impl Interface { crate::stats::counters::update_interface_stats(self) } } + +#[cfg(test)] +mod tests { + use std::net::{IpAddr, Ipv4Addr, Ipv6Addr}; + use crate::interface::interface::Interface; + use ipnet::{Ipv4Net, Ipv6Net}; + + #[test] + fn global_helpers_filter() { + let mut itf = Interface::dummy(); + itf.ipv4 = vec![ + Ipv4Net::new(Ipv4Addr::new(10,0,0,1), 8).unwrap(), // private + Ipv4Net::new(Ipv4Addr::new(1,1,1,1), 32).unwrap(), // global + ]; + itf.ipv6 = vec![ + Ipv6Net::new(Ipv6Addr::LOCALHOST, 128).unwrap(), // loopback + Ipv6Net::new("2606:4700:4700::1111".parse().unwrap(), 128).unwrap(), // global + ]; + + // Check global_ip_addrs() fillters correctly + let globals = itf.global_ip_addrs(); + assert!(globals.contains(&IpAddr::V4(Ipv4Addr::new(1,1,1,1)))); + assert!(globals.contains(&IpAddr::V6("2606:4700:4700::1111".parse().unwrap()))); + assert!(!globals.contains(&IpAddr::V4(Ipv4Addr::new(10,0,0,1)))); + assert!(!globals.contains(&IpAddr::V6(Ipv6Addr::LOCALHOST))); + } +} diff --git a/src/interface/mod.rs b/src/interface/mod.rs index eeeeb87..5834be9 100644 --- a/src/interface/mod.rs +++ b/src/interface/mod.rs @@ -93,3 +93,63 @@ pub(crate) fn interfaces() -> Vec { crate::os::bsd::interface::interfaces() } } + +#[cfg(test)] +mod tests { + #![cfg(feature = "gateway")] + use std::net::{IpAddr, Ipv4Addr, Ipv6Addr}; + use crate::interface::{interface::Interface, pick_default_iface_index}; + use crate::interface::types::InterfaceType; + use ipnet::{Ipv4Net, Ipv6Net}; + + #[test] + fn exact_match_and_fallback_v4() { + let mut a = Interface::dummy(); + a.index = 1; + a.if_type = InterfaceType::Ethernet; + a.ipv4 = vec![Ipv4Net::new(Ipv4Addr::new(192,168,1,10), 24).unwrap()]; + + let mut b = Interface::dummy(); + b.index = 2; + b.if_type = InterfaceType::Ethernet; + b.ipv4 = vec![Ipv4Net::new(Ipv4Addr::new(10,0,0,2), 8).unwrap()]; + + // Prefers exact match + let local = IpAddr::V4(Ipv4Addr::new(192,168,1,10)); + assert_eq!(pick_default_iface_index(&[a.clone(), b.clone()], local), Some(1)); + + // Fallback to subnet match + let in_subnet = IpAddr::V4(Ipv4Addr::new(10,0,5,23)); + assert_eq!(pick_default_iface_index(&[a, b], in_subnet), Some(2)); + } + + #[test] + fn exact_match_and_fallback_v6() { + let mut a = Interface::dummy(); + a.index = 11; + a.if_type = InterfaceType::Ethernet; + a.ipv6 = vec![Ipv6Net::new("2001:db8::10".parse::().unwrap(), 64).unwrap()]; + + let mut b = Interface::dummy(); + b.index = 22; + b.if_type = InterfaceType::Ethernet; + b.ipv6 = vec![Ipv6Net::new("2606:4700::2".parse::().unwrap(), 32).unwrap()]; + + // Prefers exact match + let local = IpAddr::V6("2001:db8::10".parse().unwrap()); + assert_eq!(pick_default_iface_index(&[a.clone(), b.clone()], local), Some(11)); + + // Fallback to subnet match + let in_subnet = IpAddr::V6("2606:4700::abcd".parse().unwrap()); + assert_eq!(pick_default_iface_index(&[a, b], in_subnet), Some(22)); + } + + #[test] + fn no_exact_nor_subnet() { + let mut a = Interface::dummy(); + a.index = 3; + a.ipv4 = vec![Ipv4Net::new(Ipv4Addr::new(192,168,0,5), 24).unwrap()]; + let local = IpAddr::V4(Ipv4Addr::new(172,16,0,1)); + assert_eq!(pick_default_iface_index(&[a], local), None); + } +} diff --git a/src/net/db/oui.rs b/src/net/db/oui.rs index 6169d0f..4f99952 100644 --- a/src/net/db/oui.rs +++ b/src/net/db/oui.rs @@ -32,3 +32,21 @@ pub fn is_known_loopback_mac(mac: &MacAddr) -> bool { let mac = mac.address(); KNOWN_LOOPBACK_MAC_ADDRESSES.contains(&mac.to_uppercase().as_str()) } + +#[cfg(test)] +mod tests { + use crate::net::mac::MacAddr; + use crate::net::db::oui; + + #[test] + fn detects_loopback() { + let mac: MacAddr = "00:00:00:00:00:00".parse().unwrap(); + assert!(oui::is_known_loopback_mac(&mac)); + } + + #[test] + fn detects_virtual() { + let mac: MacAddr = "00:50:56:AA:BB:CC".parse().unwrap(); + assert!(oui::is_virtual_mac(&mac)); + } +} From 9f51c3910b120aedcdde01be4822f211d11ad5f9 Mon Sep 17 00:00:00 2001 From: shellrow Date: Sat, 8 Nov 2025 20:43:23 +0900 Subject: [PATCH 2/3] Format code with cargo fmt --- src/interface/interface.rs | 10 +++++----- src/interface/mod.rs | 26 ++++++++++++++++---------- src/net/db/oui.rs | 2 +- 3 files changed, 22 insertions(+), 16 deletions(-) diff --git a/src/interface/interface.rs b/src/interface/interface.rs index c59421b..3978093 100644 --- a/src/interface/interface.rs +++ b/src/interface/interface.rs @@ -249,16 +249,16 @@ impl Interface { #[cfg(test)] mod tests { - use std::net::{IpAddr, Ipv4Addr, Ipv6Addr}; use crate::interface::interface::Interface; use ipnet::{Ipv4Net, Ipv6Net}; + use std::net::{IpAddr, Ipv4Addr, Ipv6Addr}; #[test] fn global_helpers_filter() { let mut itf = Interface::dummy(); itf.ipv4 = vec![ - Ipv4Net::new(Ipv4Addr::new(10,0,0,1), 8).unwrap(), // private - Ipv4Net::new(Ipv4Addr::new(1,1,1,1), 32).unwrap(), // global + Ipv4Net::new(Ipv4Addr::new(10, 0, 0, 1), 8).unwrap(), // private + Ipv4Net::new(Ipv4Addr::new(1, 1, 1, 1), 32).unwrap(), // global ]; itf.ipv6 = vec![ Ipv6Net::new(Ipv6Addr::LOCALHOST, 128).unwrap(), // loopback @@ -267,9 +267,9 @@ mod tests { // Check global_ip_addrs() fillters correctly let globals = itf.global_ip_addrs(); - assert!(globals.contains(&IpAddr::V4(Ipv4Addr::new(1,1,1,1)))); + assert!(globals.contains(&IpAddr::V4(Ipv4Addr::new(1, 1, 1, 1)))); assert!(globals.contains(&IpAddr::V6("2606:4700:4700::1111".parse().unwrap()))); - assert!(!globals.contains(&IpAddr::V4(Ipv4Addr::new(10,0,0,1)))); + assert!(!globals.contains(&IpAddr::V4(Ipv4Addr::new(10, 0, 0, 1)))); assert!(!globals.contains(&IpAddr::V6(Ipv6Addr::LOCALHOST))); } } diff --git a/src/interface/mod.rs b/src/interface/mod.rs index 5834be9..647e95f 100644 --- a/src/interface/mod.rs +++ b/src/interface/mod.rs @@ -97,29 +97,32 @@ pub(crate) fn interfaces() -> Vec { #[cfg(test)] mod tests { #![cfg(feature = "gateway")] - use std::net::{IpAddr, Ipv4Addr, Ipv6Addr}; - use crate::interface::{interface::Interface, pick_default_iface_index}; use crate::interface::types::InterfaceType; + use crate::interface::{interface::Interface, pick_default_iface_index}; use ipnet::{Ipv4Net, Ipv6Net}; + use std::net::{IpAddr, Ipv4Addr, Ipv6Addr}; #[test] fn exact_match_and_fallback_v4() { let mut a = Interface::dummy(); a.index = 1; a.if_type = InterfaceType::Ethernet; - a.ipv4 = vec![Ipv4Net::new(Ipv4Addr::new(192,168,1,10), 24).unwrap()]; + a.ipv4 = vec![Ipv4Net::new(Ipv4Addr::new(192, 168, 1, 10), 24).unwrap()]; let mut b = Interface::dummy(); b.index = 2; b.if_type = InterfaceType::Ethernet; - b.ipv4 = vec![Ipv4Net::new(Ipv4Addr::new(10,0,0,2), 8).unwrap()]; + b.ipv4 = vec![Ipv4Net::new(Ipv4Addr::new(10, 0, 0, 2), 8).unwrap()]; // Prefers exact match - let local = IpAddr::V4(Ipv4Addr::new(192,168,1,10)); - assert_eq!(pick_default_iface_index(&[a.clone(), b.clone()], local), Some(1)); + let local = IpAddr::V4(Ipv4Addr::new(192, 168, 1, 10)); + assert_eq!( + pick_default_iface_index(&[a.clone(), b.clone()], local), + Some(1) + ); // Fallback to subnet match - let in_subnet = IpAddr::V4(Ipv4Addr::new(10,0,5,23)); + let in_subnet = IpAddr::V4(Ipv4Addr::new(10, 0, 5, 23)); assert_eq!(pick_default_iface_index(&[a, b], in_subnet), Some(2)); } @@ -137,7 +140,10 @@ mod tests { // Prefers exact match let local = IpAddr::V6("2001:db8::10".parse().unwrap()); - assert_eq!(pick_default_iface_index(&[a.clone(), b.clone()], local), Some(11)); + assert_eq!( + pick_default_iface_index(&[a.clone(), b.clone()], local), + Some(11) + ); // Fallback to subnet match let in_subnet = IpAddr::V6("2606:4700::abcd".parse().unwrap()); @@ -148,8 +154,8 @@ mod tests { fn no_exact_nor_subnet() { let mut a = Interface::dummy(); a.index = 3; - a.ipv4 = vec![Ipv4Net::new(Ipv4Addr::new(192,168,0,5), 24).unwrap()]; - let local = IpAddr::V4(Ipv4Addr::new(172,16,0,1)); + a.ipv4 = vec![Ipv4Net::new(Ipv4Addr::new(192, 168, 0, 5), 24).unwrap()]; + let local = IpAddr::V4(Ipv4Addr::new(172, 16, 0, 1)); assert_eq!(pick_default_iface_index(&[a], local), None); } } diff --git a/src/net/db/oui.rs b/src/net/db/oui.rs index 4f99952..ddf9b6d 100644 --- a/src/net/db/oui.rs +++ b/src/net/db/oui.rs @@ -35,8 +35,8 @@ pub fn is_known_loopback_mac(mac: &MacAddr) -> bool { #[cfg(test)] mod tests { - use crate::net::mac::MacAddr; use crate::net::db::oui; + use crate::net::mac::MacAddr; #[test] fn detects_loopback() { From 0a943a033a9c0cd8d5a48a0068b1d0cdb6614e1a Mon Sep 17 00:00:00 2001 From: shellrow Date: Sat, 8 Nov 2025 20:44:21 +0900 Subject: [PATCH 3/3] Bump version to 0.39.0 --- Cargo.toml | 2 +- README.md | 2 +- 2 files changed, 2 insertions(+), 2 deletions(-) diff --git a/Cargo.toml b/Cargo.toml index faf5334..507816d 100644 --- a/Cargo.toml +++ b/Cargo.toml @@ -1,6 +1,6 @@ [package] name = "netdev" -version = "0.38.2" +version = "0.39.0" authors = ["shellrow "] edition = "2024" description = "Cross-platform library for network interface" diff --git a/README.md b/README.md index 3f2b6da..6bc1489 100644 --- a/README.md +++ b/README.md @@ -32,7 +32,7 @@ This project was rebranded from [default-net][default-net-crates-io-url] by the Add `netdev` to your dependencies ```toml:Cargo.toml [dependencies] -netdev = "0.38" +netdev = "0.39" ``` For more details, see [examples][examples-url] or [doc][doc-url].