diff --git a/src/linux.rs b/src/linux.rs index 5417bbc..5b59bd2 100644 --- a/src/linux.rs +++ b/src/linux.rs @@ -1,5 +1,10 @@ #![allow(dead_code)] +use std::{ + collections::HashMap, + net::{IpAddr, Ipv4Addr, Ipv6Addr}, +}; + use crate::MacAddressError; use nix::ifaddrs::*; @@ -30,6 +35,54 @@ pub fn get_mac(name: Option<&str>) -> Result, MacAddressError> { Ok(None) } +/// Uses the `getifaddrs` call to retrieve a list of network interfaces on the +/// host device and returns the MAC address that matching the adapter with +/// the given IP +/// +/// Because nix returns all of the IP's and MAC's in a combined list, we need +/// to map the IP to an inteface name and track the MAC addresses by interface name +/// and see if there's a match +pub fn get_mac_address_by_ip(ip: &IpAddr) -> Result, MacAddressError> { + let ifiter = getifaddrs()?; + + let mut ip_on_inferface: Option = None; + let mut mac_to_interface: HashMap> = HashMap::new(); + for interface in ifiter { + if let Some(iface_address) = interface.address { + // is this a mac address? + if let Some(link) = iface_address.as_link_addr() { + mac_to_interface.insert(interface.interface_name.clone(), link.addr()); + // did we just find what we're looking for? + if let Some(intf_name) = &ip_on_inferface { + if *intf_name == interface.interface_name { + return Ok(link.addr()); + } + } + } + if let Some(adapter_ip) = if let Some(sin4) = iface_address.as_sockaddr_in() { + // v4 addr? + Some(IpAddr::from(Ipv4Addr::from(sin4.ip()))) + } else if let Some(sin6) = iface_address.as_sockaddr_in6() { + // v6 addr? + Some(IpAddr::from(Ipv6Addr::from(sin6.ip()))) + } else { + // something else, ignore + None + } { + // found an IP for this adapter - if it's the one we're looking for, save it + if adapter_ip == *ip { + ip_on_inferface = Some(interface.interface_name.clone()); + if let Some(mac) = mac_to_interface.get(&interface.interface_name) { + return Ok(mac.clone()); + } + } + } + } + } + + Ok(None) +} + pub fn get_ifname(mac: &[u8; 6]) -> Result, MacAddressError> { let ifiter = getifaddrs()?;