Merge pull request #10 from shellrow/4-feature-request-interface-type

4 feature request interface type
main
shellrow 3 years ago committed by GitHub
commit 568b43d959
No known key found for this signature in database
GPG Key ID: 4AEE18F83AFDEB23
  1. 5
      Cargo.toml
  2. 16
      README.md
  3. 2
      examples/default_interface.rs
  4. 2
      examples/list_interfaces.rs
  5. 24
      src/interface/linux.rs
  6. 31
      src/interface/macos.rs
  7. 10
      src/interface/mod.rs
  8. 14
      src/interface/types.rs
  9. 186
      src/interface/unix.rs
  10. 2
      src/interface/windows.rs

@ -1,6 +1,6 @@
[package] [package]
name = "default-net" name = "default-net"
version = "0.8.2" version = "0.9.0"
authors = ["shellrow <shellrow@protonmail.com>"] authors = ["shellrow <shellrow@protonmail.com>"]
edition = "2018" edition = "2018"
description = "Cross-platform library for network interface and gateway" description = "Cross-platform library for network interface and gateway"
@ -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"

@ -18,7 +18,7 @@
Add `default-net` to your dependencies Add `default-net` to your dependencies
```toml:Cargo.toml ```toml:Cargo.toml
[dependencies] [dependencies]
default-net = "0.8.2" default-net = "0.9.0"
``` ```
## Example ## Example
@ -33,6 +33,7 @@ fn main(){
println!("\tIndex: {}", default_interface.index); println!("\tIndex: {}", default_interface.index);
println!("\tName: {}", default_interface.name); println!("\tName: {}", default_interface.name);
println!("\tDescription: {:?}", default_interface.description); println!("\tDescription: {:?}", default_interface.description);
println!("\tType: {}", default_interface.if_type.name());
if let Some(mac_addr) = default_interface.mac_addr { if let Some(mac_addr) = default_interface.mac_addr {
println!("\tMAC: {}", mac_addr); println!("\tMAC: {}", mac_addr);
}else{ }else{
@ -40,6 +41,7 @@ fn main(){
} }
println!("\tIPv4: {:?}", default_interface.ipv4); println!("\tIPv4: {:?}", default_interface.ipv4);
println!("\tIPv6: {:?}", default_interface.ipv6); println!("\tIPv6: {:?}", default_interface.ipv6);
println!("\tFlags: {:?}", default_interface.flags);
if let Some(gateway) = default_interface.gateway { if let Some(gateway) = default_interface.gateway {
println!("Default Gateway"); println!("Default Gateway");
println!("\tMAC: {}", gateway.mac_addr); println!("\tMAC: {}", gateway.mac_addr);
@ -58,13 +60,15 @@ fn main(){
## Tested on ## Tested on
- Linux - Linux
- Ubuntu - Ubuntu
- 21.10 - 21.10
- 20.04 - 20.04
- 18.04 - 18.04
- Kali 2021.1 (VM) - Kali
- 2022.1 (VM)
- 2021.1 (VM)
- macOS 11.6 - macOS 11.6
- Windows - Windows
- Windows 10 21H2 19044.1526 - Windows 10 21H2 19044.1586
- Windows 11 21H2 22000.493 (VM) - Windows 11 21H2 22000.493 (VM)
For more details, see [examples][examples-url] or doc. For more details, see [examples][examples-url] or doc.

@ -7,6 +7,7 @@ fn main(){
println!("\tIndex: {}", default_interface.index); println!("\tIndex: {}", default_interface.index);
println!("\tName: {}", default_interface.name); println!("\tName: {}", default_interface.name);
println!("\tDescription: {:?}", default_interface.description); println!("\tDescription: {:?}", default_interface.description);
println!("\tType: {}", default_interface.if_type.name());
if let Some(mac_addr) = default_interface.mac_addr { if let Some(mac_addr) = default_interface.mac_addr {
println!("\tMAC: {}", mac_addr); println!("\tMAC: {}", mac_addr);
}else{ }else{
@ -14,6 +15,7 @@ fn main(){
} }
println!("\tIPv4: {:?}", default_interface.ipv4); println!("\tIPv4: {:?}", default_interface.ipv4);
println!("\tIPv6: {:?}", default_interface.ipv6); println!("\tIPv6: {:?}", default_interface.ipv6);
println!("\tFlags: {:?}", default_interface.flags);
if let Some(gateway) = default_interface.gateway { if let Some(gateway) = default_interface.gateway {
println!("Default Gateway"); println!("Default Gateway");
println!("\tMAC: {}", gateway.mac_addr); println!("\tMAC: {}", gateway.mac_addr);

@ -7,6 +7,7 @@ fn main(){
println!("\tIndex: {}", interface.index); println!("\tIndex: {}", interface.index);
println!("\tName: {}", interface.name); println!("\tName: {}", interface.name);
println!("\tDescription: {:?}", interface.description); println!("\tDescription: {:?}", interface.description);
println!("\tType: {}", interface.if_type.name());
if let Some(mac_addr) = interface.mac_addr { if let Some(mac_addr) = interface.mac_addr {
println!("\tMAC: {}", mac_addr); println!("\tMAC: {}", mac_addr);
}else{ }else{
@ -14,6 +15,7 @@ fn main(){
} }
println!("\tIPv4: {:?}", interface.ipv4); println!("\tIPv4: {:?}", interface.ipv4);
println!("\tIPv6: {:?}", interface.ipv6); println!("\tIPv6: {:?}", interface.ipv6);
println!("\tFlags: {:?}", interface.flags);
if let Some(gateway) = interface.gateway { if let Some(gateway) = interface.gateway {
println!("Gateway"); println!("Gateway");
println!("\tMAC: {}", gateway.mac_addr); println!("\tMAC: {}", gateway.mac_addr);

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

@ -0,0 +1,31 @@
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 = if let Some(bsd_name) = interface.bsd_name() {
bsd_name.to_string()
}else{
continue;
};
let type_id: String = if let Some(type_string) = interface.interface_type_string() {
type_string.to_string()
}else{
continue;
};
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};
@ -73,12 +79,16 @@ pub struct Interface {
/// ///
/// On Windows, this field is the adapter name /// On Windows, this field is the adapter name
pub description: Option<String>, pub description: Option<String>,
/// Interface Type
pub if_type: InterfaceType,
/// MAC address of network interface /// MAC address of network interface
pub mac_addr: Option<MacAddr>, pub mac_addr: Option<MacAddr>,
/// List of Ipv4Net for the network interface /// List of Ipv4Net for the network interface
pub ipv4: Vec<Ipv4Net>, pub ipv4: Vec<Ipv4Net>,
/// List of Ipv6Net for the network interface /// List of Ipv6Net for the network interface
pub ipv6: Vec<Ipv6Net>, pub ipv6: Vec<Ipv6Net>,
/// Flags for the network interface (OS Specific)
pub flags: u32,
/// Default gateway for the network interface /// Default gateway for the network interface
pub gateway: Option<Gateway>, pub gateway: Option<Gateway>,
} }

@ -1,5 +1,6 @@
use std::convert::TryFrom; use std::convert::TryFrom;
/// Type of Network Interface
#[derive(Clone, Copy, Debug, PartialEq)] #[derive(Clone, Copy, Debug, PartialEq)]
pub enum InterfaceType { pub enum InterfaceType {
Unknown, Unknown,
@ -69,9 +70,18 @@ impl InterfaceType {
#[cfg(any(target_os = "linux", target_os = "android"))] #[cfg(any(target_os = "linux", target_os = "android"))]
pub fn value(&self) -> u32 { pub fn value(&self) -> u32 {
// TODO
match *self { match *self {
_ => 0, InterfaceType::Ethernet => 1,
InterfaceType::TokenRing => 4,
InterfaceType::Fddi => 774,
InterfaceType::Ppp => 512,
InterfaceType::Loopback => 772,
InterfaceType::Ethernet3Megabit => 2,
InterfaceType::Slip => 256,
InterfaceType::Atm => 19,
InterfaceType::Wireless80211 => 801,
InterfaceType::Tunnel => 768,
_ => u32::MAX,
} }
} }

@ -10,8 +10,9 @@ use std::mem::{self, MaybeUninit};
use std::os::raw::c_char; use std::os::raw::c_char;
use std::str::from_utf8_unchecked; use std::str::from_utf8_unchecked;
use std::net::{IpAddr, Ipv4Addr, Ipv6Addr}; use std::net::{IpAddr, Ipv4Addr, Ipv6Addr};
use crate::interface::InterfaceType;
#[cfg(any(target_os = "macos", target_os = "openbsd", target_os = "freebsd", target_os = "netbsd", target_os = "ios"))] #[cfg(any(target_os = "openbsd", target_os = "freebsd", target_os = "netbsd"))]
pub fn interfaces() -> Vec<Interface> { pub fn interfaces() -> Vec<Interface> {
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(){
@ -45,14 +46,55 @@ pub fn interfaces() -> Vec<Interface> {
interfaces interfaces
} }
#[cfg(any(target_os = "macos", target_os = "ios"))]
pub fn interfaces() -> Vec<Interface> {
use super::macos;
let type_map = macos::get_if_type_map();
let mut interfaces: Vec<Interface> = unix_interfaces();
let local_ip: IpAddr = match super::get_local_ipaddr(){
Some(local_ip) => local_ip,
None => return interfaces,
};
for iface in &mut interfaces {
iface.if_type = *type_map.get(&iface.name).unwrap_or(&InterfaceType::Unknown);
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 = "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) {
@ -79,6 +121,76 @@ pub fn interfaces() -> Vec<Interface> {
interfaces interfaces
} }
#[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),
}
}
}
}
pub fn unix_interfaces() -> Vec<Interface> { pub fn unix_interfaces() -> Vec<Interface> {
let mut ifaces: Vec<Interface> = vec![]; let mut ifaces: Vec<Interface> = vec![];
let mut addrs: MaybeUninit<*mut libc::ifaddrs> = MaybeUninit::uninit(); let mut addrs: MaybeUninit<*mut libc::ifaddrs> = MaybeUninit::uninit();
@ -130,9 +242,11 @@ pub fn unix_interfaces() -> Vec<Interface> {
index: 0, index: 0,
name: name.clone(), name: name.clone(),
description: None, description: None,
if_type: InterfaceType::Unknown,
mac_addr: mac.clone(), mac_addr: mac.clone(),
ipv4: ini_ipv4, ipv4: ini_ipv4,
ipv6: ini_ipv6, ipv6: ini_ipv6,
flags: addr_ref.ifa_flags,
gateway: None, gateway: None,
}; };
let mut found: bool = false; let mut found: bool = false;
@ -187,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::*;

@ -178,9 +178,11 @@ pub fn interfaces() -> Vec<Interface> {
index: adapter.Index, index: adapter.Index,
name: adapter_name, name: adapter_name,
description: Some(adapter_desc), description: Some(adapter_desc),
if_type: InterfaceType::try_from(adapter.Type).unwrap_or(InterfaceType::Unknown),
mac_addr: Some(MacAddr::new(mac_addr)), mac_addr: Some(MacAddr::new(mac_addr)),
ipv4: ipv4_vec, ipv4: ipv4_vec,
ipv6: ipv6_vec, ipv6: ipv6_vec,
flags: adapter.Type,
gateway: default_gateway, gateway: default_gateway,
}; };
interfaces.push(interface); interfaces.push(interface);

Loading…
Cancel
Save