Add modules

main
shellrow 2 years ago
parent c092000b20
commit 3afc519414
  1. 1
      Cargo.toml
  2. 4
      src/bpf/mod.rs
  3. 17
      src/bpf/unix.rs
  4. 110
      src/interface/mod.rs
  5. 163
      src/interface/unix.rs
  6. 0
      src/interface/windows.rs
  7. 0
      src/interface1.rs
  8. 2
      src/lib.rs
  9. 4
      src/sys/mod.rs
  10. 61
      src/sys/unix.rs
  11. 0
      src/sys/windows.rs

@ -13,6 +13,7 @@ license = "MIT"
[target.'cfg(not(windows))'.dependencies]
pnet_packet = "0.28"
pnet_datalink = "0.28"
libc = "0.2"
[target.'cfg(windows)'.dependencies.windows]
version = "0.29.0"

@ -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);
}
}
}

@ -1,4 +1,6 @@
mod os;
mod sys;
mod bpf;
pub mod interface;
pub mod gateway;

@ -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…
Cancel
Save