mirror of
https://github.com/domcyrus/rustnet.git
synced 2026-05-13 15:29:27 -05:00
Update default interface selection to use active routing table (#194)
* Update default interface selection to use active routing table Use a connectionless UDP socket to determine the active routed local IP from the OS routing table. Matches this IP to an available capture device to securely detect the preferred default network interface without sending traffic. * Add contributor Ken Tobias and fix formatting * fix: collapse nested if-let and fix unused import for clippy --------- Co-authored-by: Marco Cadetg <cadetg@gmail.com>
This commit is contained in:
@@ -12,6 +12,7 @@ We would like to thank these people for their valuable contributions:
|
||||
|
||||
- **DeepChirp** ([@DeepChirp](https://github.com/DeepChirp)) - Code contributions
|
||||
- **Conor O'Callaghan** ([@Conor0Callaghan](https://github.com/Conor0Callaghan)) - JSON/SIEM logging research and design input
|
||||
- **Ken Tobias** ([@l1a](https://github.com/l1a)) - Code contributions
|
||||
|
||||
## Contributing
|
||||
|
||||
|
||||
@@ -367,6 +367,27 @@ fn find_capture_device(interface_name: &Option<String>) -> Result<Device> {
|
||||
None => {
|
||||
log::info!("No interface specified, using default");
|
||||
|
||||
// Resolve active interface via OS routing table by creating a connectionless UDP socket
|
||||
if let Some(active_ip) = std::net::UdpSocket::bind("0.0.0.0:0")
|
||||
.and_then(|s| {
|
||||
let _ = s.connect("8.8.8.8:53");
|
||||
s.local_addr()
|
||||
})
|
||||
.ok()
|
||||
.map(|addr| addr.ip())
|
||||
{
|
||||
log::info!("Found active routed IP: {}", active_ip);
|
||||
if let Ok(devices) = Device::list()
|
||||
&& let Some(device) = devices
|
||||
.into_iter()
|
||||
.find(|d| d.addresses.iter().any(|a| a.addr == active_ip))
|
||||
{
|
||||
log::info!("Selected interface {} based on active route", device.name);
|
||||
return Ok(device);
|
||||
}
|
||||
}
|
||||
log::info!("Fallback: using libpcap default device logic");
|
||||
|
||||
// Try to get default device
|
||||
match Device::lookup() {
|
||||
Ok(Some(device)) => {
|
||||
@@ -497,4 +518,24 @@ mod tests {
|
||||
assert_eq!(config.snaplen, 1514);
|
||||
assert!(config.filter.is_none()); // Default starts without filter
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn test_udp_routing_resolution_can_execute() {
|
||||
// Sanity-check test to ensure the OS handles UDP metric routing cleanly.
|
||||
// It's perfectly fine if this fails in hermetic CI environments without outbound routes.
|
||||
if let Ok(socket) = std::net::UdpSocket::bind("0.0.0.0:0") {
|
||||
if socket.connect("8.8.8.8:53").is_ok() {
|
||||
if let Ok(addr) = socket.local_addr() {
|
||||
assert!(
|
||||
!addr.ip().is_loopback(),
|
||||
"Active routed IP should not be loopback"
|
||||
);
|
||||
assert!(
|
||||
!addr.ip().is_unspecified(),
|
||||
"Active routed IP should not be unspecified"
|
||||
);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@@ -4,7 +4,7 @@
|
||||
//! network packets on different platforms (Linux, macOS, Windows).
|
||||
|
||||
use anyhow::Result;
|
||||
#[cfg(any(target_os = "linux", target_os = "macos", target_os = "freebsd"))]
|
||||
#[cfg(target_os = "linux")]
|
||||
use anyhow::anyhow;
|
||||
#[cfg(any(
|
||||
not(any(
|
||||
|
||||
Reference in New Issue
Block a user