use std::io;
use std::net::Ipv4Addr;
struct Interface {
name: String,
index: Option<u32>,
address: Ipv4Addr,
netmask: Ipv4Addr,
}
fn interfaces() -> Vec<Interface> {
if_addrs::get_if_addrs()
.unwrap_or_default()
.into_iter()
.filter(|i| !i.is_loopback())
.filter_map(|i| match i.addr {
if_addrs::IfAddr::V4(ref v4) => Some(Interface {
name: i.name.clone(),
index: i.index,
address: v4.ip,
netmask: v4.netmask,
}),
if_addrs::IfAddr::V6(_) => None,
})
.collect()
}
pub fn valid_addresses() -> Vec<Ipv4Addr> {
interfaces().into_iter().map(|i| i.address).collect()
}
pub(crate) fn default_local_ip() -> io::Result<Ipv4Addr> {
interfaces().first().map(|i| i.address).ok_or_else(|| {
io::Error::new(
io::ErrorKind::AddrNotAvailable,
"the host has no non-loopback IPv4 address",
)
})
}
pub(crate) fn broadcast_address(local: Option<Ipv4Addr>) -> io::Result<Ipv4Addr> {
interfaces()
.into_iter()
.find(|i| local.map_or(true, |want| i.address == want))
.map(|i| {
let (a, m) = (i.address.octets(), i.netmask.octets());
Ipv4Addr::new(a[0] | !m[0], a[1] | !m[1], a[2] | !m[2], a[3] | !m[3])
})
.ok_or_else(|| {
io::Error::new(
io::ErrorKind::AddrNotAvailable,
"no interface to derive a broadcast address from",
)
})
}
pub(crate) fn index_of(name: &str) -> io::Result<u32> {
interfaces()
.into_iter()
.find(|i| i.name == name)
.and_then(|i| i.index)
.ok_or_else(|| {
io::Error::new(
io::ErrorKind::NotFound,
format!("no interface named {name:?}"),
)
})
}
pub(crate) fn address_of(name: &str) -> Option<Ipv4Addr> {
interfaces()
.into_iter()
.find(|i| i.name == name)
.map(|i| i.address)
}