use libc::{c_void, c_char, c_int, c_uint};
use std::{mem, ptr};
use nix::sys::socket;
use std::net::{SocketAddr, SocketAddrV4, SocketAddrV6, Ipv4Addr, Ipv6Addr};
pub const AF_PACKET: i32 = 17;
#[allow(dead_code)]
#[repr(C)]
pub enum SIOCGIFFLAGS {
IFF_UP = 0x1,
IFF_BROADCAST = 0x2,
IFF_DEBUG = 0x4,
IFF_LOOPBACK = 0x8,
IFF_POINTOPOINT = 0x10,
IFF_NOTRAILERS = 0x20,
IFF_RUNNING = 0x40,
IFF_NOARP = 0x80,
IFF_PROMISC = 0x100,
IFF_ALLMULTI = 0x200,
IFF_MASTER = 0x400,
IFF_SLAVE = 0x800,
IFF_MULTICAST = 0x1000,
IFF_PORTSEL = 0x2000,
IFF_AUTOMEDIA = 0x4000,
IFF_DYNAMIC = 0x8000
}
#[repr(C)]
pub struct union_ifa_ifu {
pub data: *mut c_void,
}
impl union_ifa_ifu {
pub fn ifu_broadaddr (&mut self) -> *mut socket::sockaddr {
self.data as *mut socket::sockaddr
}
pub fn ifu_dstaddr (&mut self) -> *mut socket::sockaddr {
self.data as *mut socket::sockaddr
}
}
#[repr(C)]
pub struct ifaddrs {
pub ifa_next: *mut ifaddrs,
pub ifa_name: *mut c_char,
pub ifa_flags: c_uint,
pub ifa_addr: *mut socket::sockaddr,
pub ifa_netmask: *mut socket::sockaddr,
pub ifa_ifu: union_ifa_ifu,
pub ifa_data: *mut c_void,
}
extern "C" {
pub fn getifaddrs (ifap: *mut *mut ifaddrs) -> c_int;
pub fn freeifaddrs (ifa: *mut ifaddrs) -> c_void;
}
pub fn convert_sockaddr (sa: *mut socket::sockaddr) -> Option<SocketAddr> {
if sa == ptr::null_mut() { return None; }
match unsafe { *sa }.sa_family as i32 {
socket::AF_INET => {
let sa: *const socket::sockaddr_in = unsafe { mem::transmute(sa) };
let sa = & unsafe { *sa };
let addr: [u8; 4] = unsafe { mem::transmute(sa.sin_addr.s_addr) };
Some(SocketAddr::V4(SocketAddrV4::new(
Ipv4Addr::new(
addr[0],
addr[1],
addr[2],
addr[3],
), sa.sin_port
)))
},
socket::AF_INET6 => {
let sa: *const socket::sockaddr_in6 = unsafe { mem::transmute(sa) };
let sa = & unsafe { *sa };
let addr: [u16; 8] = unsafe { mem::transmute(sa.sin6_addr.s6_addr) };
Some(SocketAddr::V6(SocketAddrV6::new(
Ipv6Addr::new(
u16::from_be(addr[0]),
u16::from_be(addr[1]),
u16::from_be(addr[2]),
u16::from_be(addr[3]),
u16::from_be(addr[4]),
u16::from_be(addr[5]),
u16::from_be(addr[6]),
u16::from_be(addr[7]),
), sa.sin6_port, sa.sin6_flowinfo, sa.sin6_scope_id
)))
},
_ => None,
}
}