Add Ipv4Net and Ipv6Net struct (#2)

Fields: addr, prefix_len, and netmask
main
shellrow 3 years ago
parent 75f24cfe6c
commit ad4bf96587
  1. 4
      src/gateway/mod.rs
  2. 23
      src/interface/mod.rs
  3. 58
      src/interface/unix.rs
  4. 95
      src/ip.rs
  5. 1
      src/lib.rs

@ -33,14 +33,14 @@ pub fn get_default_gateway() -> Result<Gateway, String> {
for iface in interfaces { for iface in interfaces {
match local_ip { match local_ip {
IpAddr::V4(local_ipv4) => { IpAddr::V4(local_ipv4) => {
if iface.ipv4.contains(&local_ipv4) { if iface.ipv4.iter().any(|x| x.addr == local_ipv4) {
if let Some(gateway) = iface.gateway { if let Some(gateway) = iface.gateway {
return Ok(gateway); return Ok(gateway);
} }
} }
}, },
IpAddr::V6(local_ipv6) => { IpAddr::V6(local_ipv6) => {
if iface.ipv6.contains(&local_ipv6) { if iface.ipv6.iter().any(|x| x.addr == local_ipv6) {
if let Some(gateway) = iface.gateway { if let Some(gateway) = iface.gateway {
return Ok(gateway); return Ok(gateway);
} }

@ -11,7 +11,8 @@ mod windows;
#[cfg(target_os = "windows")] #[cfg(target_os = "windows")]
use self::windows::*; use self::windows::*;
use std::net::{IpAddr, Ipv4Addr, Ipv6Addr}; use std::net::IpAddr;
use crate::ip::{Ipv4Net, Ipv6Net};
use crate::gateway::{Gateway}; use crate::gateway::{Gateway};
/// Structure of MAC address /// Structure of MAC address
@ -71,10 +72,10 @@ pub struct Interface {
pub description: Option<String>, pub description: Option<String>,
/// MAC address of network interface /// MAC address of network interface
pub mac_addr: Option<MacAddr>, pub mac_addr: Option<MacAddr>,
/// List of IPv4 addresses for the network interface /// List of Ipv4Net for the network interface
pub ipv4: Vec<Ipv4Addr>, pub ipv4: Vec<Ipv4Net>,
/// List of IPv6 addresses for the network interface /// List of Ipv6Net for the network interface
pub ipv6: Vec<Ipv6Addr>, pub ipv6: Vec<Ipv6Net>,
/// Default gateway for the network interface /// Default gateway for the network interface
pub gateway: Option<Gateway>, pub gateway: Option<Gateway>,
} }
@ -89,12 +90,12 @@ pub fn get_default_interface() -> Result<Interface, String> {
for iface in interfaces { for iface in interfaces {
match local_ip { match local_ip {
IpAddr::V4(local_ipv4) => { IpAddr::V4(local_ipv4) => {
if iface.ipv4.contains(&local_ipv4) { if iface.ipv4.iter().any(|x| x.addr == local_ipv4) {
return Ok(iface); return Ok(iface);
} }
}, },
IpAddr::V6(local_ipv6) => { IpAddr::V6(local_ipv6) => {
if iface.ipv6.contains(&local_ipv6) { if iface.ipv6.iter().any(|x| x.addr == local_ipv6) {
return Ok(iface); return Ok(iface);
} }
}, },
@ -113,12 +114,12 @@ pub fn get_default_interface_index() -> Option<u32> {
for iface in interfaces { for iface in interfaces {
match local_ip { match local_ip {
IpAddr::V4(local_ipv4) => { IpAddr::V4(local_ipv4) => {
if iface.ipv4.contains(&local_ipv4) { if iface.ipv4.iter().any(|x| x.addr == local_ipv4) {
return Some(iface.index); return Some(iface.index);
} }
}, },
IpAddr::V6(local_ipv6) => { IpAddr::V6(local_ipv6) => {
if iface.ipv6.contains(&local_ipv6) { if iface.ipv6.iter().any(|x| x.addr == local_ipv6) {
return Some(iface.index); return Some(iface.index);
} }
}, },
@ -137,12 +138,12 @@ pub fn get_default_interface_name() -> Option<String> {
for iface in interfaces { for iface in interfaces {
match local_ip { match local_ip {
IpAddr::V4(local_ipv4) => { IpAddr::V4(local_ipv4) => {
if iface.ipv4.contains(&local_ipv4) { if iface.ipv4.iter().any(|x| x.addr == local_ipv4) {
return Some(iface.name); return Some(iface.name);
} }
}, },
IpAddr::V6(local_ipv6) => { IpAddr::V6(local_ipv6) => {
if iface.ipv6.contains(&local_ipv6) { if iface.ipv6.iter().any(|x| x.addr == local_ipv6) {
return Some(iface.name); return Some(iface.name);
} }
}, },

@ -2,6 +2,7 @@ use super::Interface;
use super::MacAddr; use super::MacAddr;
use crate::sys; use crate::sys;
use crate::gateway; use crate::gateway;
use crate::ip::{Ipv4Net, Ipv6Net};
use libc; use libc;
use std::ffi::{CStr, CString}; use std::ffi::{CStr, CString};
@ -20,7 +21,7 @@ pub fn interfaces() -> Vec<Interface> {
for iface in &mut interfaces { for iface in &mut interfaces {
match local_ip { match local_ip {
IpAddr::V4(local_ipv4) => { IpAddr::V4(local_ipv4) => {
if iface.ipv4.contains(&local_ipv4) { if iface.ipv4.iter().any(|x| x.addr == local_ipv4) {
match gateway::unix::get_default_gateway(iface.name.clone()) { match gateway::unix::get_default_gateway(iface.name.clone()) {
Ok(gateway) => { Ok(gateway) => {
iface.gateway = Some(gateway); iface.gateway = Some(gateway);
@ -30,7 +31,7 @@ pub fn interfaces() -> Vec<Interface> {
} }
}, },
IpAddr::V6(local_ipv6) => { IpAddr::V6(local_ipv6) => {
if iface.ipv6.contains(&local_ipv6) { if iface.ipv6.iter().any(|x| x.addr == local_ipv6) {
match gateway::unix::get_default_gateway(iface.name.clone()) { match gateway::unix::get_default_gateway(iface.name.clone()) {
Ok(gateway) => { Ok(gateway) => {
iface.gateway = Some(gateway); iface.gateway = Some(gateway);
@ -92,15 +93,36 @@ pub fn unix_interfaces() -> Vec<Interface> {
let bytes = unsafe { CStr::from_ptr(c_str).to_bytes() }; let bytes = unsafe { CStr::from_ptr(c_str).to_bytes() };
let name = unsafe {from_utf8_unchecked(bytes).to_owned() }; 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 (mac, ip) = sockaddr_to_network_addr(addr_ref.ifa_addr as *const libc::sockaddr);
let mut ini_ipv4: Vec<Ipv4Addr> = vec![]; let (_, netmask) = sockaddr_to_network_addr(addr_ref.ifa_netmask as *const libc::sockaddr);
let mut ini_ipv6: Vec<Ipv6Addr> = vec![]; let mut ini_ipv4: Vec<Ipv4Net> = vec![];
let mut ini_ipv6: Vec<Ipv6Net> = vec![];
if let Some(ip) = ip { if let Some(ip) = ip {
match ip { match ip {
IpAddr::V4(ipv4) => { IpAddr::V4(ipv4) => {
ini_ipv4.push(ipv4); let netmask: Ipv4Addr = match netmask {
Some(netmask) => {
match netmask {
IpAddr::V4(netmask) => netmask,
IpAddr::V6(_) => Ipv4Addr::UNSPECIFIED,
}
},
None => Ipv4Addr::UNSPECIFIED,
};
let ipv4_net: Ipv4Net = Ipv4Net::new_with_netmask(ipv4, netmask);
ini_ipv4.push(ipv4_net);
}, },
IpAddr::V6(ipv6) => { IpAddr::V6(ipv6) => {
ini_ipv6.push(ipv6); let netmask: Ipv6Addr = match netmask {
Some(netmask) => {
match netmask {
IpAddr::V4(_) => Ipv6Addr::UNSPECIFIED,
IpAddr::V6(netmask) => netmask,
}
},
None => Ipv6Addr::UNSPECIFIED,
};
let ipv6_net: Ipv6Net = Ipv6Net::new_with_netmask(ipv6, netmask);
ini_ipv6.push(ipv6_net);
}, },
} }
} }
@ -122,10 +144,30 @@ pub fn unix_interfaces() -> Vec<Interface> {
if let Some(ip) = ip { if let Some(ip) = ip {
match ip { match ip {
IpAddr::V4(ipv4) => { IpAddr::V4(ipv4) => {
iface.ipv4.push(ipv4); let netmask: Ipv4Addr = match netmask {
Some(netmask) => {
match netmask {
IpAddr::V4(netmask) => netmask,
IpAddr::V6(_) => Ipv4Addr::UNSPECIFIED,
}
},
None => Ipv4Addr::UNSPECIFIED,
};
let ipv4_net: Ipv4Net = Ipv4Net::new_with_netmask(ipv4, netmask);
iface.ipv4.push(ipv4_net);
}, },
IpAddr::V6(ipv6) => { IpAddr::V6(ipv6) => {
iface.ipv6.push(ipv6); let netmask: Ipv6Addr = match netmask {
Some(netmask) => {
match netmask {
IpAddr::V4(_) => Ipv6Addr::UNSPECIFIED,
IpAddr::V6(netmask) => netmask,
}
},
None => Ipv6Addr::UNSPECIFIED,
};
let ipv6_net: Ipv6Net = Ipv6Net::new_with_netmask(ipv6, netmask);
iface.ipv6.push(ipv6_net);
}, },
} }
} }

@ -0,0 +1,95 @@
use std::net::{Ipv4Addr, Ipv6Addr};
#[derive(Clone, Debug)]
pub struct Ipv4Net {
pub addr: Ipv4Addr,
pub prefix_len: u8,
pub netmask: Ipv4Addr,
}
impl Ipv4Net {
pub fn new(ipv4_addr: Ipv4Addr, prefix_len: u8) -> Ipv4Net {
Ipv4Net {
addr: ipv4_addr,
prefix_len: prefix_len,
netmask: prefix_to_ipv4_netmask(prefix_len),
}
}
pub fn new_with_netmask(ipv4_addr: Ipv4Addr, netmask: Ipv4Addr) -> Ipv4Net {
Ipv4Net {
addr: ipv4_addr,
prefix_len: ipv4_netmask_to_prefix(netmask),
netmask: netmask,
}
}
}
#[derive(Clone, Debug)]
pub struct Ipv6Net {
pub addr: Ipv6Addr,
pub prefix_len: u8,
pub netmask: Ipv6Addr,
}
impl Ipv6Net {
pub fn new(ipv6_addr: Ipv6Addr, prefix_len: u8) -> Ipv6Net {
Ipv6Net {
addr: ipv6_addr,
prefix_len: prefix_len,
netmask: prefix_to_ipv6_netmask(prefix_len),
}
}
pub fn new_with_netmask(ipv6_addr: Ipv6Addr, netmask: Ipv6Addr) -> Ipv6Net {
Ipv6Net {
addr: ipv6_addr,
prefix_len: ipv6_netmask_to_prefix(netmask),
netmask: netmask,
}
}
}
fn ipv4_netmask_to_prefix(netmask: Ipv4Addr) -> u8 {
let netmask = u32::from(netmask);
let prefix = (!netmask).leading_zeros() as u8;
if (u64::from(netmask) << prefix) & 0xffff_ffff != 0 {
0
} else {
prefix
}
}
fn ipv6_netmask_to_prefix(netmask: Ipv6Addr) -> u8 {
let netmask = netmask.segments();
let mut mask_iter = netmask.iter();
let mut prefix = 0;
for &segment in &mut mask_iter {
if segment == 0xffff {
prefix += 16;
} else if segment == 0 {
break;
} else {
let prefix_bits = (!segment).leading_zeros() as u8;
if segment << prefix_bits != 0 {
return 0;
}
prefix += prefix_bits;
break;
}
}
for &segment in mask_iter {
if segment != 0 {
return 0;
}
}
prefix
}
fn prefix_to_ipv4_netmask(prefix_len: u8) -> Ipv4Addr {
let netmask_u32: u32 = u32::max_value().checked_shl(32 - prefix_len as u32).unwrap_or(0);
Ipv4Addr::from(netmask_u32)
}
fn prefix_to_ipv6_netmask(prefix_len: u8) -> Ipv6Addr {
let netmask_u128: u128 = u128::max_value().checked_shl((128 - prefix_len) as u32).unwrap_or(u128::min_value());
Ipv6Addr::from(netmask_u128)
}

@ -5,6 +5,7 @@ mod bpf;
#[cfg(any(target_os = "macos", target_os = "openbsd", target_os = "freebsd", target_os = "netbsd", target_os = "ios"))] #[cfg(any(target_os = "macos", target_os = "openbsd", target_os = "freebsd", target_os = "netbsd", target_os = "ios"))]
mod socket; mod socket;
pub mod ip;
pub mod interface; pub mod interface;
pub mod gateway; pub mod gateway;

Loading…
Cancel
Save