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