use std::net::{IpAddr, Ipv4Addr, SocketAddr, UdpSocket};
#[must_use]
pub fn local_ipv4s() -> Vec<Ipv4Addr> {
let mut ips = interface_ipv4s();
for ip in route_probe_ipv4s() {
if !ips.contains(&ip) {
ips.push(ip);
}
}
ips
}
#[must_use]
pub fn local_subnets() -> Vec<Ipv4Addr> {
let mut bases = Vec::new();
for ip in local_ipv4s() {
let o = ip.octets();
let base = Ipv4Addr::new(o[0], o[1], o[2], 0);
if !bases.contains(&base) {
bases.push(base);
}
}
bases
}
#[must_use]
pub fn primary_local_ipv4() -> Option<Ipv4Addr> {
local_ipv4s().into_iter().next()
}
#[must_use]
pub fn is_local_ip(ip: IpAddr) -> bool {
if let Ok(ifaces) = if_addrs::get_if_addrs() {
return ifaces
.into_iter()
.any(|iface| !iface.is_loopback() && iface.ip() == ip);
}
false
}
fn interface_ipv4s() -> Vec<Ipv4Addr> {
let mut ips = Vec::new();
if let Ok(ifaces) = if_addrs::get_if_addrs() {
for iface in ifaces {
if iface.is_loopback() {
continue;
}
if let if_addrs::IfAddr::V4(ifv4) = iface.addr
&& is_usable_local_ipv4(ifv4.ip)
&& !ips.contains(&ifv4.ip)
{
ips.push(ifv4.ip);
}
}
}
ips
}
fn route_probe_ipv4s() -> Vec<Ipv4Addr> {
let mut ips = Vec::new();
let probes = [
SocketAddr::from(([8, 8, 8, 8], 80)),
SocketAddr::from(([1, 1, 1, 1], 80)),
SocketAddr::from(([192, 168, 1, 1], 80)),
SocketAddr::from(([10, 0, 0, 1], 80)),
];
for target in probes {
let Ok(socket) = UdpSocket::bind("0.0.0.0:0") else {
continue;
};
if socket.connect(target).is_err() {
continue;
}
let Ok(local_addr) = socket.local_addr() else {
continue;
};
let IpAddr::V4(ip) = local_addr.ip() else {
continue;
};
if is_usable_local_ipv4(ip) && !ips.contains(&ip) {
ips.push(ip);
}
}
ips
}
fn is_usable_local_ipv4(ip: Ipv4Addr) -> bool {
!ip.is_loopback()
&& !ip.is_unspecified()
&& !ip.is_multicast()
&& !ip.is_broadcast()
&& !ip.is_documentation()
}