//! Query network interface addresses //! //! Uses the Linux and/or BSD specific function `getifaddrs` to query the list //! of interfaces and their associated addresses. use std::ffi; use std::iter::Iterator; use std::mem; use std::option::Option; use libc; use {Result, Errno}; use sys::socket::SockAddr; use net::if_::*; /// Describes a single address for an interface as returned by `getifaddrs`. #[derive(Clone, Eq, Hash, PartialEq, Debug)] pub struct InterfaceAddress { /// Name of the network interface pub interface_name: String, /// Flags as from `SIOCGIFFLAGS` ioctl pub flags: InterfaceFlags, /// Network address of this interface pub address: Option, /// Netmask of this interface pub netmask: Option, /// Broadcast address of this interface, if applicable pub broadcast: Option, /// Point-to-point destination address pub destination: Option, } cfg_if! { if #[cfg(any(target_os = "emscripten", target_os = "fuchsia", target_os = "linux"))] { fn get_ifu_from_sockaddr(info: &libc::ifaddrs) -> *const libc::sockaddr { info.ifa_ifu } } else { fn get_ifu_from_sockaddr(info: &libc::ifaddrs) -> *const libc::sockaddr { info.ifa_dstaddr } } } impl InterfaceAddress { /// Create an `InterfaceAddress` from the libc struct. fn from_libc_ifaddrs(info: &libc::ifaddrs) -> InterfaceAddress { let ifname = unsafe { ffi::CStr::from_ptr(info.ifa_name) }; let address = unsafe { SockAddr::from_libc_sockaddr(info.ifa_addr) }; let netmask = unsafe { SockAddr::from_libc_sockaddr(info.ifa_netmask) }; let mut addr = InterfaceAddress { interface_name: ifname.to_string_lossy().to_string(), flags: InterfaceFlags::from_bits_truncate(info.ifa_flags as i32), address: address, netmask: netmask, broadcast: None, destination: None, }; let ifu = get_ifu_from_sockaddr(info); if addr.flags.contains(InterfaceFlags::IFF_POINTOPOINT) { addr.destination = unsafe { SockAddr::from_libc_sockaddr(ifu) }; } else if addr.flags.contains(InterfaceFlags::IFF_BROADCAST) { addr.broadcast = unsafe { SockAddr::from_libc_sockaddr(ifu) }; } addr } } /// Holds the results of `getifaddrs`. /// /// Use the function `getifaddrs` to create this Iterator. Note that the /// actual list of interfaces can be iterated once and will be freed as /// soon as the Iterator goes out of scope. #[derive(Debug, Eq, Hash, PartialEq)] pub struct InterfaceAddressIterator { base: *mut libc::ifaddrs, next: *mut libc::ifaddrs, } impl Drop for InterfaceAddressIterator { fn drop(&mut self) { unsafe { libc::freeifaddrs(self.base) }; } } impl Iterator for InterfaceAddressIterator { type Item = InterfaceAddress; fn next(&mut self) -> Option<::Item> { match unsafe { self.next.as_ref() } { Some(ifaddr) => { self.next = ifaddr.ifa_next; Some(InterfaceAddress::from_libc_ifaddrs(ifaddr)) } None => None, } } } /// Get interface addresses using libc's `getifaddrs` /// /// Note that the underlying implementation differs between OSes. Only the /// most common address families are supported by the nix crate (due to /// lack of time and complexity of testing). The address family is encoded /// in the specific variant of `SockAddr` returned for the fields `address`, /// `netmask`, `broadcast`, and `destination`. For any entry not supported, /// the returned list will contain a `None` entry. /// /// # Example /// ``` /// let addrs = nix::ifaddrs::getifaddrs().unwrap(); /// for ifaddr in addrs { /// match ifaddr.address { /// Some(address) => { /// println!("interface {} address {}", /// ifaddr.interface_name, address); /// }, /// None => { /// println!("interface {} with unsupported address family", /// ifaddr.interface_name); /// } /// } /// } /// ``` pub fn getifaddrs() -> Result { let mut addrs: *mut libc::ifaddrs = unsafe { mem::uninitialized() }; Errno::result(unsafe { libc::getifaddrs(&mut addrs) }).map(|_| { InterfaceAddressIterator { base: addrs, next: addrs, } }) } #[cfg(test)] mod tests { use super::*; // Only checks if `getifaddrs` can be invoked without panicking. #[test] fn test_getifaddrs() { let _ = getifaddrs(); } }