use std::net::Ipv4Addr;
use std::{ffi, io, ptr};
use libc::{AF_INET, freeifaddrs, getifaddrs, ifaddrs, sockaddr};
use crate::upnp::Network;
pub fn get_local_net_state() -> io::Result<Vec<Network>> {
let mut p_ifa: *mut ifaddrs = ptr::null_mut();
if unsafe { getifaddrs(&mut p_ifa) } != 0 {
return Err(io::Error::new(io::ErrorKind::Other, "getifaddrs() failed"));
}
let top_ptr = p_ifa;
let mut result = Vec::new();
while !p_ifa.is_null() {
let ifa = unsafe { *p_ifa };
let name = unsafe { ffi::CStr::from_ptr(ifa.ifa_name).to_string_lossy() };
if name.starts_with("docker") || name.starts_with("lo") {
p_ifa = unsafe { (*p_ifa).ifa_next };
continue;
}
if let Some(address) = parse_addr(ifa.ifa_addr) {
result.push(Network {
address,
net_mask: parse_addr(ifa.ifa_netmask).expect("Invalid subnet mask"),
});
}
p_ifa = unsafe { (*p_ifa).ifa_next };
}
unsafe { freeifaddrs(top_ptr) };
Ok(result)
}
fn parse_addr(p_sock: *const sockaddr) -> Option<Ipv4Addr> {
if p_sock.is_null() {
return None;
}
let addr = unsafe { *p_sock };
match i32::from(addr.sa_family) {
AF_INET => Some(Ipv4Addr::new(
addr.sa_data[2] as u8,
addr.sa_data[3] as u8,
addr.sa_data[4] as u8,
addr.sa_data[5] as u8,
)),
_ => None,
}
}