use std::net::{IpAddr, Ipv4Addr, UdpSocket};
pub struct SysInfo {
pub interface: Option<String>,
pub gateway: Option<Ipv4Addr>,
pub local_ip: Option<Ipv4Addr>,
pub dns_servers: Vec<IpAddr>,
}
fn egress_ipv4() -> Option<Ipv4Addr> {
let sock = UdpSocket::bind("0.0.0.0:0").ok()?;
sock.connect("1.1.1.1:80").ok()?;
match sock.local_addr().ok()?.ip() {
IpAddr::V4(v4) if !v4.is_unspecified() => Some(v4),
_ => None,
}
}
pub fn gather() -> SysInfo {
let egress = egress_ipv4();
let interfaces = netdev::get_interfaces();
let active = egress.and_then(|ip| {
interfaces
.iter()
.find(|i| i.ipv4.iter().any(|net| net.addr() == ip))
});
let fallback;
let iface = match active {
Some(i) => Some(i),
None => {
fallback = netdev::get_default_interface().ok();
fallback.as_ref()
}
};
let interface = iface.map(|i| {
match i.friendly_name.as_deref() {
Some(fname) if !fname.is_empty() => fname.to_string(),
_ => i.name.clone(),
}
});
let gateway = iface
.and_then(|i| i.gateway.as_ref())
.and_then(|g| g.ipv4.first().copied());
let local_ip = egress.or_else(|| iface.and_then(|i| i.ipv4.first().map(|net| net.addr())));
SysInfo {
interface,
gateway,
local_ip,
dns_servers: crate::dns::configured_servers(),
}
}