Skip to content
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
2 changes: 1 addition & 1 deletion Cargo.toml
Original file line number Diff line number Diff line change
@@ -1,6 +1,6 @@
[package]
name = "netdev"
version = "0.38.2"
version = "0.39.0"
authors = ["shellrow <[email protected]>"]
edition = "2024"
description = "Cross-platform library for network interface"
Expand Down
2 changes: 1 addition & 1 deletion README.md
Original file line number Diff line number Diff line change
Expand Up @@ -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].
Expand Down
27 changes: 27 additions & 0 deletions src/interface/interface.rs
Original file line number Diff line number Diff line change
Expand Up @@ -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)));
}
}
66 changes: 66 additions & 0 deletions src/interface/mod.rs
Original file line number Diff line number Diff line change
Expand Up @@ -93,3 +93,69 @@ pub(crate) fn interfaces() -> Vec<Interface> {
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::<Ipv6Addr>().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::<Ipv6Addr>().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);
}
}
18 changes: 18 additions & 0 deletions src/net/db/oui.rs
Original file line number Diff line number Diff line change
Expand Up @@ -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));
}
}