parent
c092000b20
commit
3afc519414
@ -0,0 +1,4 @@ |
|||||||
|
#[cfg(not(target_os="windows"))] |
||||||
|
mod unix; |
||||||
|
#[cfg(not(target_os="windows"))] |
||||||
|
pub use self::unix::*; |
@ -0,0 +1,17 @@ |
|||||||
|
#![allow(non_camel_case_types)] |
||||||
|
#![allow(non_snake_case)] |
||||||
|
#![allow(dead_code)] |
||||||
|
|
||||||
|
pub const AF_LINK: libc::c_int = 18; |
||||||
|
|
||||||
|
#[cfg(any(target_os = "openbsd", target_os = "freebsd", target_os = "netbsd", target_os = "macos", target_os = "ios"))] |
||||||
|
pub struct sockaddr_dl { |
||||||
|
pub sdl_len: libc::c_uchar, |
||||||
|
pub sdl_family: libc::c_uchar, |
||||||
|
pub sdl_index: libc::c_ushort, |
||||||
|
pub sdl_type: libc::c_uchar, |
||||||
|
pub sdl_nlen: libc::c_uchar, |
||||||
|
pub sdl_alen: libc::c_uchar, |
||||||
|
pub sdl_slen: libc::c_uchar, |
||||||
|
pub sdl_data: [libc::c_char; 46], |
||||||
|
} |
@ -0,0 +1,110 @@ |
|||||||
|
#[cfg(not(target_os="windows"))] |
||||||
|
mod unix; |
||||||
|
|
||||||
|
use std::net::{IpAddr, Ipv4Addr, Ipv6Addr}; |
||||||
|
use crate::gateway::{Gateway}; |
||||||
|
use crate::os; |
||||||
|
|
||||||
|
/// Structure of MAC address
|
||||||
|
#[derive(Clone, Debug)] |
||||||
|
pub struct MacAddr(u8, u8, u8, u8, u8, u8); |
||||||
|
|
||||||
|
impl MacAddr { |
||||||
|
/// Construct a new MacAddr struct from the given octets
|
||||||
|
pub fn new(octets: [u8; 6]) -> MacAddr { |
||||||
|
MacAddr(octets[0], octets[1], octets[2], octets[3], octets[4], octets[5]) |
||||||
|
} |
||||||
|
/// Returns an array of MAC address octets
|
||||||
|
pub fn octets(&self) -> [u8; 6] { |
||||||
|
[self.0,self.1,self.2,self.3,self.4,self.5] |
||||||
|
} |
||||||
|
/// Return a formatted string of MAC address
|
||||||
|
pub fn address(&self) -> String { |
||||||
|
format!("{:02x}:{:02x}:{:02x}:{:02x}:{:02x}:{:02x}", self.0,self.1,self.2,self.3,self.4,self.5) |
||||||
|
} |
||||||
|
pub fn zero() -> MacAddr { |
||||||
|
MacAddr(0,0,0,0,0,0) |
||||||
|
} |
||||||
|
} |
||||||
|
|
||||||
|
impl std::fmt::Display for MacAddr { |
||||||
|
fn fmt(&self, f: &mut std::fmt::Formatter) -> std::fmt::Result { |
||||||
|
let _ = write!(f,"{:<02x}:{:<02x}:{:<02x}:{:<02x}:{:<02x}:{:<02x}",self.0,self.1,self.2,self.3,self.4,self.5); |
||||||
|
Ok(())
|
||||||
|
} |
||||||
|
} |
||||||
|
|
||||||
|
/// Structure of Network Interface information
|
||||||
|
#[derive(Clone, Debug)] |
||||||
|
pub struct Interface { |
||||||
|
pub index: u32, |
||||||
|
pub name: String, |
||||||
|
pub description: Option<String>, |
||||||
|
pub mac_addr: Option<MacAddr>, |
||||||
|
pub ipv4: Vec<Ipv4Addr>, |
||||||
|
pub ipv6: Vec<Ipv6Addr>, |
||||||
|
pub gateway: Option<Gateway>, |
||||||
|
} |
||||||
|
|
||||||
|
/// Get default Network Interface
|
||||||
|
pub fn get_default_interface() -> Result<Interface, String> { |
||||||
|
let local_ip: IpAddr = match os::get_local_ipaddr(){ |
||||||
|
Some(local_ip) => local_ip, |
||||||
|
None => return Err(String::from("Local IP address not found")), |
||||||
|
}; |
||||||
|
let interfaces: Vec<Interface> = os::interfaces(); |
||||||
|
for iface in interfaces { |
||||||
|
match local_ip { |
||||||
|
IpAddr::V4(local_ipv4) => { |
||||||
|
if iface.ipv4.contains(&local_ipv4) { |
||||||
|
return Ok(iface); |
||||||
|
} |
||||||
|
}, |
||||||
|
IpAddr::V6(local_ipv6) => { |
||||||
|
if iface.ipv6.contains(&local_ipv6) { |
||||||
|
return Ok(iface); |
||||||
|
} |
||||||
|
}, |
||||||
|
} |
||||||
|
} |
||||||
|
Err(String::from("Default Interface not found")) |
||||||
|
} |
||||||
|
|
||||||
|
/// Get default Network Interface index
|
||||||
|
pub fn get_default_interface_index() -> Option<u32> { |
||||||
|
os::default_interface_index() |
||||||
|
} |
||||||
|
|
||||||
|
/// Get default Network Interface name
|
||||||
|
pub fn get_default_interface_name() -> Option<String> { |
||||||
|
os::default_interface_name() |
||||||
|
} |
||||||
|
|
||||||
|
/// Get a list of available Network Interfaces
|
||||||
|
pub fn get_interfaces() -> Vec<Interface> { |
||||||
|
os::interfaces() |
||||||
|
} |
||||||
|
|
||||||
|
#[cfg(test)] |
||||||
|
mod tests { |
||||||
|
use super::*; |
||||||
|
#[test] |
||||||
|
fn test_interfaces() { |
||||||
|
let interfaces = get_interfaces(); |
||||||
|
for interface in interfaces { |
||||||
|
println!("{:#?}", interface); |
||||||
|
} |
||||||
|
} |
||||||
|
#[test] |
||||||
|
fn test_default_interface() { |
||||||
|
println!("{:#?}", get_default_interface()); |
||||||
|
} |
||||||
|
#[test] |
||||||
|
fn test_default_interface_index() { |
||||||
|
println!("{:?}", get_default_interface_index()); |
||||||
|
} |
||||||
|
#[test] |
||||||
|
fn test_default_interface_name() { |
||||||
|
println!("{:?}", get_default_interface_name()); |
||||||
|
} |
||||||
|
} |
@ -0,0 +1,163 @@ |
|||||||
|
use super::Interface; |
||||||
|
use super::MacAddr; |
||||||
|
use crate::sys; |
||||||
|
|
||||||
|
use libc; |
||||||
|
use std::ffi::{CStr, CString}; |
||||||
|
use std::mem::{self, MaybeUninit}; |
||||||
|
use std::os::raw::c_char; |
||||||
|
use std::str::from_utf8_unchecked; |
||||||
|
use std::net::{IpAddr, Ipv4Addr, Ipv6Addr}; |
||||||
|
|
||||||
|
pub fn interfaces() -> Vec<Interface> { |
||||||
|
unix_interfaces() |
||||||
|
} |
||||||
|
|
||||||
|
pub fn unix_interfaces() -> Vec<Interface> { |
||||||
|
let mut ifaces: Vec<Interface> = vec![]; |
||||||
|
let mut addrs: MaybeUninit<*mut libc::ifaddrs> = MaybeUninit::uninit(); |
||||||
|
if unsafe { libc::getifaddrs(addrs.as_mut_ptr()) } != 0 { |
||||||
|
return ifaces; |
||||||
|
} |
||||||
|
let addrs = unsafe { addrs.assume_init() }; |
||||||
|
let mut addr = addrs; |
||||||
|
while !addr.is_null() { |
||||||
|
let addr_ref: &libc::ifaddrs = unsafe {&*addr}; |
||||||
|
let c_str = addr_ref.ifa_name as *const c_char; |
||||||
|
let bytes = unsafe { CStr::from_ptr(c_str).to_bytes() }; |
||||||
|
let name = unsafe {from_utf8_unchecked(bytes).to_owned() }; |
||||||
|
let (mac, ip) = sockaddr_to_network_addr(addr_ref.ifa_addr as *const libc::sockaddr); |
||||||
|
let mut ini_ipv4: Vec<Ipv4Addr> = vec![]; |
||||||
|
let mut ini_ipv6: Vec<Ipv6Addr> = vec![]; |
||||||
|
if let Some(ip) = ip { |
||||||
|
match ip { |
||||||
|
IpAddr::V4(ipv4) => { |
||||||
|
ini_ipv4.push(ipv4); |
||||||
|
}, |
||||||
|
IpAddr::V6(ipv6) => { |
||||||
|
ini_ipv6.push(ipv6); |
||||||
|
}, |
||||||
|
} |
||||||
|
} |
||||||
|
let interface: Interface = Interface{ |
||||||
|
index: 0, |
||||||
|
name: name.clone(), |
||||||
|
description: None, |
||||||
|
mac_addr: mac.clone(), |
||||||
|
ipv4: ini_ipv4, |
||||||
|
ipv6: ini_ipv6, |
||||||
|
gateway: None, |
||||||
|
}; |
||||||
|
let mut found: bool = false; |
||||||
|
for iface in &mut ifaces { |
||||||
|
if name == iface.name { |
||||||
|
if let Some(mac) = mac.clone() { |
||||||
|
iface.mac_addr = Some(mac); |
||||||
|
} |
||||||
|
if let Some(ip) = ip { |
||||||
|
match ip { |
||||||
|
IpAddr::V4(ipv4) => { |
||||||
|
iface.ipv4.push(ipv4); |
||||||
|
}, |
||||||
|
IpAddr::V6(ipv6) => { |
||||||
|
iface.ipv6.push(ipv6); |
||||||
|
}, |
||||||
|
} |
||||||
|
} |
||||||
|
found = true; |
||||||
|
} |
||||||
|
} |
||||||
|
if !found { |
||||||
|
ifaces.push(interface); |
||||||
|
} |
||||||
|
addr = addr_ref.ifa_next; |
||||||
|
} |
||||||
|
unsafe{ libc::freeifaddrs(addrs); }
|
||||||
|
for iface in &mut ifaces { |
||||||
|
let name = CString::new(iface.name.as_bytes()).unwrap(); |
||||||
|
unsafe { iface.index = libc::if_nametoindex(name.as_ptr()); } |
||||||
|
} |
||||||
|
ifaces |
||||||
|
} |
||||||
|
|
||||||
|
#[cfg(any(target_os = "linux", target_os = "android"))] |
||||||
|
fn sockaddr_to_network_addr(sa: *const libc::sockaddr) -> (Option<MacAddr>, Option<IpAddr>) { |
||||||
|
use std::net::SocketAddr; |
||||||
|
|
||||||
|
unsafe { |
||||||
|
if sa.is_null() { |
||||||
|
(None, None) |
||||||
|
} else if (*sa).sa_family as libc::c_int == libc::AF_PACKET { |
||||||
|
let sll: *const libc::sockaddr_ll = mem::transmute(sa); |
||||||
|
let mac = MacAddr( |
||||||
|
(*sll).sll_addr[0], |
||||||
|
(*sll).sll_addr[1], |
||||||
|
(*sll).sll_addr[2], |
||||||
|
(*sll).sll_addr[3], |
||||||
|
(*sll).sll_addr[4], |
||||||
|
(*sll).sll_addr[5], |
||||||
|
); |
||||||
|
|
||||||
|
(Some(mac), None) |
||||||
|
} else { |
||||||
|
let addr = sys::sockaddr_to_addr( |
||||||
|
mem::transmute(sa), |
||||||
|
mem::size_of::<libc::sockaddr_storage>(), |
||||||
|
); |
||||||
|
|
||||||
|
match addr { |
||||||
|
Ok(SocketAddr::V4(sa)) => (None, Some(IpAddr::V4(*sa.ip()))), |
||||||
|
Ok(SocketAddr::V6(sa)) => (None, Some(IpAddr::V6(*sa.ip()))), |
||||||
|
Err(_) => (None, None), |
||||||
|
} |
||||||
|
} |
||||||
|
} |
||||||
|
} |
||||||
|
|
||||||
|
#[cfg(any(target_os = "openbsd", target_os = "freebsd", target_os = "netbsd", target_os = "macos", target_os = "ios"))] |
||||||
|
fn sockaddr_to_network_addr(sa: *const libc::sockaddr) -> (Option<MacAddr>, Option<IpAddr>) { |
||||||
|
use crate::bpf; |
||||||
|
use std::net::SocketAddr; |
||||||
|
|
||||||
|
unsafe { |
||||||
|
if sa.is_null() { |
||||||
|
(None, None) |
||||||
|
} else if (*sa).sa_family as libc::c_int == bpf::AF_LINK { |
||||||
|
let sdl: *const bpf::sockaddr_dl = mem::transmute(sa); |
||||||
|
let nlen = (*sdl).sdl_nlen as usize; |
||||||
|
let mac = MacAddr( |
||||||
|
(*sdl).sdl_data[nlen] as u8, |
||||||
|
(*sdl).sdl_data[nlen + 1] as u8, |
||||||
|
(*sdl).sdl_data[nlen + 2] as u8, |
||||||
|
(*sdl).sdl_data[nlen + 3] as u8, |
||||||
|
(*sdl).sdl_data[nlen + 4] as u8, |
||||||
|
(*sdl).sdl_data[nlen + 5] as u8, |
||||||
|
); |
||||||
|
|
||||||
|
(Some(mac), None) |
||||||
|
} else { |
||||||
|
let addr = sys::sockaddr_to_addr( |
||||||
|
mem::transmute(sa), |
||||||
|
mem::size_of::<libc::sockaddr_storage>(), |
||||||
|
); |
||||||
|
|
||||||
|
match addr { |
||||||
|
Ok(SocketAddr::V4(sa)) => (None, Some(IpAddr::V4(*sa.ip()))), |
||||||
|
Ok(SocketAddr::V6(sa)) => (None, Some(IpAddr::V6(*sa.ip()))), |
||||||
|
Err(_) => (None, None), |
||||||
|
} |
||||||
|
} |
||||||
|
} |
||||||
|
} |
||||||
|
|
||||||
|
#[cfg(test)] |
||||||
|
mod tests { |
||||||
|
use super::*; |
||||||
|
#[test] |
||||||
|
fn test_unix_interfaces() { |
||||||
|
let interfaces = interfaces(); |
||||||
|
for interface in interfaces { |
||||||
|
println!("{:#?}", interface); |
||||||
|
} |
||||||
|
} |
||||||
|
} |
@ -0,0 +1,4 @@ |
|||||||
|
#[cfg(not(target_os="windows"))] |
||||||
|
mod unix; |
||||||
|
#[cfg(not(target_os="windows"))] |
||||||
|
pub use self::unix::*; |
@ -0,0 +1,61 @@ |
|||||||
|
use std::io; |
||||||
|
use std::mem; |
||||||
|
use std::net::{Ipv4Addr, Ipv6Addr, SocketAddr, SocketAddrV4, SocketAddrV6}; |
||||||
|
|
||||||
|
pub type SockAddrIn = libc::sockaddr_in; |
||||||
|
pub type SockAddrIn6 = libc::sockaddr_in6; |
||||||
|
pub type SockAddrStorage = libc::sockaddr_storage; |
||||||
|
pub type InAddr = libc::in_addr; |
||||||
|
|
||||||
|
pub const AF_INET: libc::c_int = libc::AF_INET; |
||||||
|
pub const AF_INET6: libc::c_int = libc::AF_INET6; |
||||||
|
|
||||||
|
pub use libc::{IFF_BROADCAST, IFF_LOOPBACK, IFF_MULTICAST, IFF_POINTOPOINT, IFF_UP}; |
||||||
|
|
||||||
|
fn ntohs(u: u16) -> u16 { |
||||||
|
u16::from_be(u) |
||||||
|
} |
||||||
|
|
||||||
|
pub fn sockaddr_to_addr(storage: &SockAddrStorage, len: usize) -> io::Result<SocketAddr> { |
||||||
|
match storage.ss_family as libc::c_int { |
||||||
|
AF_INET => { |
||||||
|
assert!(len as usize >= mem::size_of::<SockAddrIn>()); |
||||||
|
let storage: &SockAddrIn = unsafe { mem::transmute(storage) }; |
||||||
|
let ip = ipv4_addr_int(storage.sin_addr); |
||||||
|
// octets
|
||||||
|
let o1 = (ip >> 24) as u8; |
||||||
|
let o2 = (ip >> 16) as u8; |
||||||
|
let o3 = (ip >> 8) as u8; |
||||||
|
let o4 = ip as u8; |
||||||
|
let sockaddrv4 = SocketAddrV4::new(Ipv4Addr::new(o1, o2, o3, o4), ntohs(storage.sin_port)); |
||||||
|
Ok(SocketAddr::V4(sockaddrv4)) |
||||||
|
} |
||||||
|
AF_INET6 => { |
||||||
|
assert!(len as usize >= mem::size_of::<SockAddrIn6>()); |
||||||
|
let storage: &SockAddrIn6 = unsafe { mem::transmute(storage) }; |
||||||
|
let arr: [u16; 8] = unsafe { mem::transmute(storage.sin6_addr.s6_addr) }; |
||||||
|
// hextets
|
||||||
|
let h1 = ntohs(arr[0]); |
||||||
|
let h2 = ntohs(arr[1]); |
||||||
|
let h3 = ntohs(arr[2]); |
||||||
|
let h4 = ntohs(arr[3]); |
||||||
|
let h5 = ntohs(arr[4]); |
||||||
|
let h6 = ntohs(arr[5]); |
||||||
|
let h7 = ntohs(arr[6]); |
||||||
|
let h8 = ntohs(arr[7]); |
||||||
|
let ip = Ipv6Addr::new(h1, h2, h3, h4, h5, h6, h7, h8); |
||||||
|
Ok(SocketAddr::V6(SocketAddrV6::new( |
||||||
|
ip, |
||||||
|
ntohs(storage.sin6_port), |
||||||
|
u32::from_be(storage.sin6_flowinfo), |
||||||
|
storage.sin6_scope_id, |
||||||
|
))) |
||||||
|
} |
||||||
|
_ => Err(io::Error::new(io::ErrorKind::InvalidData, "expected IPv4 or IPv6 socket",)), |
||||||
|
} |
||||||
|
} |
||||||
|
|
||||||
|
#[inline(always)] |
||||||
|
pub fn ipv4_addr_int(addr: InAddr) -> u32 { |
||||||
|
(addr.s_addr as u32).to_be() |
||||||
|
} |
Loading…
Reference in new issue