use netdev::Interface;
use netdev::interface::types::InterfaceType;
pub use netdev::MacAddr;
pub fn current_mac_gateway() -> Option<MacAddr> {
physical_gateway_mac(&netdev::get_interfaces())
}
fn physical_gateway_mac(interfaces: &[Interface]) -> Option<MacAddr> {
interfaces
.iter()
.filter(|iface| is_physical(&iface.if_type))
.filter_map(|iface| iface.gateway.as_ref())
.map(|gateway| gateway.mac_addr)
.find(is_resolved)
}
fn is_resolved(mac: &MacAddr) -> bool {
*mac != MacAddr::zero() && mac.is_unicast()
}
fn is_physical(if_type: &InterfaceType) -> bool {
!matches!(
if_type,
InterfaceType::Tunnel | InterfaceType::Loopback | InterfaceType::PeerToPeerWireless
)
}
#[cfg(test)]
mod tests {
use super::*;
use netdev::NetworkDevice;
fn iface(if_type: InterfaceType, gateway_mac: Option<MacAddr>) -> Interface {
let mut iface = Interface::dummy();
iface.if_type = if_type;
iface.gateway = gateway_mac.map(|mac| NetworkDevice {
mac_addr: mac,
ipv4: Vec::new(),
ipv6: Vec::new(),
});
iface
}
fn mac(s: &str) -> MacAddr {
s.parse().expect("valid test MAC")
}
#[test]
fn picks_resolved_gateway_on_physical_interface() {
let ifaces = [iface(
InterfaceType::Wireless80211,
Some(mac("d8:ec:e5:af:d0:29")),
)];
assert_eq!(
physical_gateway_mac(&ifaces),
Some(mac("d8:ec:e5:af:d0:29"))
);
}
#[test]
fn ignores_tunnel_and_picks_physical() {
let ifaces = [
iface(InterfaceType::Tunnel, Some(MacAddr::zero())),
iface(InterfaceType::Wireless80211, Some(mac("d8:ec:e5:af:d0:29"))),
];
assert_eq!(
physical_gateway_mac(&ifaces),
Some(mac("d8:ec:e5:af:d0:29"))
);
}
#[test]
fn rejects_tunnel_even_with_nonzero_mac() {
let ifaces = [iface(InterfaceType::Tunnel, Some(mac("d8:ec:e5:af:d0:29")))];
assert_eq!(physical_gateway_mac(&ifaces), None);
}
#[test]
fn rejects_unresolved_zero_mac() {
let ifaces = [iface(InterfaceType::Ethernet, Some(MacAddr::zero()))];
assert_eq!(physical_gateway_mac(&ifaces), None);
}
#[test]
fn ignores_interface_without_gateway() {
let ifaces = [iface(InterfaceType::Ethernet, None)];
assert_eq!(physical_gateway_mac(&ifaces), None);
}
#[test]
fn none_when_no_interfaces() {
assert_eq!(physical_gateway_mac(&[]), None);
}
}