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]. diff --git a/src/interface/interface.rs b/src/interface/interface.rs index ac95573..3978093 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 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 + ]; + 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..647e95f 100644 --- a/src/interface/mod.rs +++ b/src/interface/mod.rs @@ -93,3 +93,69 @@ pub(crate) fn interfaces() -> Vec { crate::os::bsd::interface::interfaces() } } + +#[cfg(test)] +mod tests { + #![cfg(feature = "gateway")] + 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()]; + + 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..ddf9b6d 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::db::oui; + use crate::net::mac::MacAddr; + + #[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)); + } +}