Add if_type for macOS and iOS

main
shellrow 3 years ago
parent c131e15441
commit 65aa839803
  1. 3
      Cargo.toml
  2. 22
      src/interface/linux.rs
  3. 23
      src/interface/macos.rs
  4. 6
      src/interface/mod.rs
  5. 200
      src/interface/unix.rs

@ -16,3 +16,6 @@ libc = "0.2"
[target.'cfg(windows)'.dependencies.windows] [target.'cfg(windows)'.dependencies.windows]
version = "0.29.0" version = "0.29.0"
features = ["Win32_Foundation","Win32_NetworkManagement_IpHelper"] features = ["Win32_Foundation","Win32_NetworkManagement_IpHelper"]
[target.'cfg(any(target_os = "macos", target_os = "ios"))'.dependencies]
system-configuration = "0.5.0"

@ -0,0 +1,22 @@
use std::convert::TryFrom;
use std::fs::read_to_string;
pub fn get_interface_type(if_name: String) -> InterfaceType {
use std::convert::TryFrom;
use std::fs::read_to_string;
let if_type_path: String = format!("/sys/class/net/{}/type", if_name);
let r = read_to_string(if_type_path);
let if_type_string = match r {
Ok(content) => content.trim().to_string(),
Err(_) => String::from("999"),
};
match if_type_string.parse::<u32>() {
Ok(if_type) => {
InterfaceType::try_from(if_type).unwrap_or(InterfaceType::Unknown)
},
Err(_) => {
InterfaceType::Unknown
}
}
}

@ -0,0 +1,23 @@
use std::collections::HashMap;
use system_configuration::network_configuration;
use crate::interface::InterfaceType;
fn get_if_type_from_id(type_id: String) -> InterfaceType {
match type_id.as_str() {
"Ethernet" => InterfaceType::Ethernet,
"IEEE80211" => InterfaceType::Wireless80211,
"PPP" => InterfaceType::Ppp,
_ => InterfaceType::Unknown,
}
}
pub fn get_if_type_map() -> HashMap<String, InterfaceType> {
let mut map: HashMap<String, InterfaceType> = HashMap::new();
let interfaces = network_configuration::get_interfaces();
for interface in &interfaces {
let if_name: String = interface.bsd_name().unwrap().to_string();
let type_id: String = interface.interface_type_string().unwrap().to_string();
map.insert(if_name, get_if_type_from_id(type_id));
}
return map;
}

@ -14,6 +14,12 @@ mod windows;
#[cfg(target_os = "windows")] #[cfg(target_os = "windows")]
use self::windows::*; use self::windows::*;
#[cfg(any(target_os = "linux", target_os = "android"))]
mod linux;
#[cfg(any(target_os = "macos", target_os = "ios"))]
mod macos;
use std::net::IpAddr; use std::net::IpAddr;
use crate::ip::{Ipv4Net, Ipv6Net}; use crate::ip::{Ipv4Net, Ipv6Net};
use crate::gateway::{Gateway}; use crate::gateway::{Gateway};

@ -12,19 +12,52 @@ use std::str::from_utf8_unchecked;
use std::net::{IpAddr, Ipv4Addr, Ipv6Addr}; use std::net::{IpAddr, Ipv4Addr, Ipv6Addr};
use crate::interface::InterfaceType; use crate::interface::InterfaceType;
#[cfg(any(target_os = "linux", target_os = "android"))] #[cfg(any(target_os = "openbsd", target_os = "freebsd", target_os = "netbsd"))]
use std::convert::TryFrom; pub fn interfaces() -> Vec<Interface> {
#[cfg(any(target_os = "linux", target_os = "android"))] let mut interfaces: Vec<Interface> = unix_interfaces();
use std::fs::read_to_string; let local_ip: IpAddr = match super::get_local_ipaddr(){
Some(local_ip) => local_ip,
None => return interfaces,
};
for iface in &mut interfaces {
match local_ip {
IpAddr::V4(local_ipv4) => {
if iface.ipv4.iter().any(|x| x.addr == local_ipv4) {
match gateway::unix::get_default_gateway(iface.name.clone()) {
Ok(gateway) => {
iface.gateway = Some(gateway);
},
Err(_) => {},
}
}
},
IpAddr::V6(local_ipv6) => {
if iface.ipv6.iter().any(|x| x.addr == local_ipv6) {
match gateway::unix::get_default_gateway(iface.name.clone()) {
Ok(gateway) => {
iface.gateway = Some(gateway);
},
Err(_) => {},
}
}
},
}
}
interfaces
}
#[cfg(any(target_os = "macos", target_os = "openbsd", target_os = "freebsd", target_os = "netbsd", target_os = "ios"))] #[cfg(any(target_os = "macos", target_os = "ios"))]
pub fn interfaces() -> Vec<Interface> { pub fn interfaces() -> Vec<Interface> {
use super::macos;
let type_map = macos::get_if_type_map();
let mut interfaces: Vec<Interface> = unix_interfaces(); let mut interfaces: Vec<Interface> = unix_interfaces();
let local_ip: IpAddr = match super::get_local_ipaddr(){ let local_ip: IpAddr = match super::get_local_ipaddr(){
Some(local_ip) => local_ip, Some(local_ip) => local_ip,
None => return interfaces, None => return interfaces,
}; };
for iface in &mut interfaces { for iface in &mut interfaces {
iface.if_type = *type_map.get(&iface.name).unwrap_or(&InterfaceType::Unknown);
match local_ip { match local_ip {
IpAddr::V4(local_ipv4) => { IpAddr::V4(local_ipv4) => {
if iface.ipv4.iter().any(|x| x.addr == local_ipv4) { if iface.ipv4.iter().any(|x| x.addr == local_ipv4) {
@ -53,12 +86,15 @@ pub fn interfaces() -> Vec<Interface> {
#[cfg(any(target_os = "linux", target_os = "android"))] #[cfg(any(target_os = "linux", target_os = "android"))]
pub fn interfaces() -> Vec<Interface> { pub fn interfaces() -> Vec<Interface> {
use super::linux;
let mut interfaces: Vec<Interface> = unix_interfaces(); let mut interfaces: Vec<Interface> = unix_interfaces();
let local_ip: IpAddr = match super::get_local_ipaddr(){ let local_ip: IpAddr = match super::get_local_ipaddr(){
Some(local_ip) => local_ip, Some(local_ip) => local_ip,
None => return interfaces, None => return interfaces,
}; };
for iface in &mut interfaces { for iface in &mut interfaces {
iface.if_type = linux::get_interface_type(iface.name.clone());
match local_ip { match local_ip {
IpAddr::V4(local_ipv4) => { IpAddr::V4(local_ipv4) => {
if iface.ipv4.iter().any(|x| x.addr == local_ipv4) { if iface.ipv4.iter().any(|x| x.addr == local_ipv4) {
@ -85,26 +121,72 @@ pub fn interfaces() -> Vec<Interface> {
interfaces interfaces
} }
#[cfg(any(target_os = "macos", target_os = "openbsd", target_os = "freebsd", target_os = "netbsd", target_os = "ios"))] #[cfg(any(target_os = "linux", target_os = "android"))]
pub fn get_interface_type(_if_name: String) -> InterfaceType { fn sockaddr_to_network_addr(sa: *const libc::sockaddr) -> (Option<MacAddr>, Option<IpAddr>) {
// TODO use std::net::SocketAddr;
InterfaceType::Unknown
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 = "linux", target_os = "android"))] #[cfg(any(target_os = "openbsd", target_os = "freebsd", target_os = "netbsd", target_os = "macos", target_os = "ios"))]
pub fn get_interface_type(if_name: String) -> InterfaceType { fn sockaddr_to_network_addr(sa: *const libc::sockaddr) -> (Option<MacAddr>, Option<IpAddr>) {
let if_type_path: String = format!("/sys/class/net/{}/type", if_name); use crate::bpf;
let r = read_to_string(if_type_path); use std::net::SocketAddr;
let if_type_string = match r {
Ok(content) => content.trim().to_string(), unsafe {
Err(_) => String::from("999"), if sa.is_null() {
}; (None, None)
match if_type_string.parse::<u32>() { } else if (*sa).sa_family as libc::c_int == bpf::AF_LINK {
Ok(if_type) => { let sdl: *const bpf::sockaddr_dl = mem::transmute(sa);
InterfaceType::try_from(if_type).unwrap_or(InterfaceType::Unknown) let nlen = (*sdl).sdl_nlen as usize;
}, let mac = MacAddr(
Err(_) => { (*sdl).sdl_data[nlen] as u8,
InterfaceType::Unknown (*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),
}
} }
} }
} }
@ -160,7 +242,7 @@ pub fn unix_interfaces() -> Vec<Interface> {
index: 0, index: 0,
name: name.clone(), name: name.clone(),
description: None, description: None,
if_type: get_interface_type(name.clone()), if_type: InterfaceType::Unknown,
mac_addr: mac.clone(), mac_addr: mac.clone(),
ipv4: ini_ipv4, ipv4: ini_ipv4,
ipv6: ini_ipv6, ipv6: ini_ipv6,
@ -219,76 +301,6 @@ pub fn unix_interfaces() -> Vec<Interface> {
ifaces 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)] #[cfg(test)]
mod tests { mod tests {
use super::*; use super::*;

Loading…
Cancel
Save