network interfaces work

This commit is contained in:
John Smith
2021-12-30 23:24:17 -05:00
parent cf2acc4bd5
commit 7ba6748cd2
19 changed files with 975 additions and 164 deletions

View File

@@ -1061,7 +1061,9 @@ impl Network {
info!("starting network");
// initialize interfaces
self.inner.lock().interfaces.refresh()?;
let mut interfaces = NetworkInterfaces::new();
interfaces.refresh().await?;
self.inner.lock().interfaces = interfaces;
// get protocol config
let protocol_config = {

View File

@@ -95,8 +95,11 @@ impl TableStore {
let dbpath = Self::get_dbpath(&inner, &table_name)?;
let cfg = DatabaseConfig::with_columns(column_count);
let db =
Database::open(dbpath, cfg).map_err(|e| format!("failed to open tabledb: {}", e))?;
Database::open(&dbpath, cfg).map_err(|e| format!("failed to open tabledb: {}", e))?;
info!(
"opened table store '{}' at path '{:?}' with {} columns",
name, dbpath, column_count
);
let table_db = TableDB::new(table_name.clone(), self.clone(), db);
inner.opened.insert(table_name, table_db.weak_inner());

View File

@@ -1,6 +1,8 @@
mod android_get_if_addrs;
// xxx : support for android older than API 24, if we need it someday
//mod android_get_if_addrs;
//pub use android_get_if_addrs::*;
mod get_directories;
pub use android_get_if_addrs::*;
pub use get_directories::*;
use crate::xx::*;

View File

@@ -1,108 +0,0 @@
#[cfg(target_os = "android")]
pub use super::android::*;
use crate::xx::*;
#[cfg(not(target_os = "android"))]
pub use if_addrs::*;
#[derive(PartialEq, Eq, Clone)]
pub struct NetworkInterface {
name: String,
is_loopback: bool,
addrs: Vec<IfAddr>,
}
#[allow(dead_code)]
impl NetworkInterface {
pub fn new(name: String, is_loopback: bool) -> Self {
Self {
name,
is_loopback,
addrs: Vec::new(),
}
}
pub fn name(&self) -> String {
self.name.clone()
}
pub fn is_loopback(&self) -> bool {
self.is_loopback
}
pub fn primary_ipv4(&self) -> Option<Ipv4Addr> {
for x in self.addrs.iter() {
if let IfAddr::V4(a) = x {
return Some(a.ip);
}
}
None
}
pub fn primary_ipv6(&self) -> Option<Ipv6Addr> {
for x in self.addrs.iter() {
if let IfAddr::V6(a) = x {
return Some(a.ip);
}
}
None
}
}
pub struct NetworkInterfaces {
valid: bool,
interfaces: BTreeMap<String, NetworkInterface>,
}
#[allow(dead_code)]
impl NetworkInterfaces {
pub fn new() -> Self {
Self {
valid: false,
interfaces: BTreeMap::new(),
}
}
pub fn is_valid(&self) -> bool {
self.valid
}
pub fn clear(&mut self) {
self.interfaces.clear();
self.valid = false;
}
// returns Ok(false) if refresh had no changes, Ok(true) if changes were present
pub fn refresh(&mut self) -> Result<bool, String> {
self.valid = false;
let last_interfaces = core::mem::take(&mut self.interfaces);
let mut intfs = match get_if_addrs() {
Err(e) => {
return Err(format!("failed to refresh network interfaces: {}", e));
}
Ok(v) => v,
};
intfs.sort();
// debug!("{} interfaces found", intfs.len());
for intf in intfs {
// trace!("interface {} at {}", &intf.name, &intf.addr.ip());
let ni = match self.interfaces.get_mut(&intf.name) {
None => {
self.interfaces.insert(
intf.name.clone(),
NetworkInterface::new(intf.name.clone(), intf.is_loopback()),
);
self.interfaces.get_mut(&intf.name).unwrap()
}
Some(v) => v,
};
ni.addrs.push(intf.addr.clone());
}
self.valid = true;
Ok(last_interfaces != self.interfaces)
}
pub fn len(&self) -> usize {
self.interfaces.len()
}
pub fn iter(&self) -> std::collections::btree_map::Iter<String, NetworkInterface> {
self.interfaces.iter()
}
}

View File

@@ -0,0 +1,19 @@
use super::*;
pub struct PlatformSupportApple {
//
}
impl PlatformSupportApple {
pub fn new() -> Result<Self, String> {
Ok(PlatformSupportApple {})
}
pub async fn get_interfaces(
&mut self,
interfaces: &mut BTreeMap<String, NetworkInterface>,
) -> Result<(), String> {
//
Ok(())
}
}

View File

@@ -1,54 +1,8 @@
use super::*;
use crate::xx::*;
pub use if_addrs::{IfAddr, Ifv4Addr, Ifv6Addr, Interface};
use jni::objects::JValue;
use std::io;
fn get_netmask_from_prefix_length_v4(out: &mut [u8; 4], mut plen: i16) {
for n in 0..4 {
out[n] = if plen >= 8 {
plen -= 8;
255u8
} else if plen <= 0 {
0u8
} else {
let v = 255u8 << (8 - plen);
plen = 0;
v
}
}
}
fn get_netmask_from_prefix_length_v6(out: &mut [u8; 16], mut plen: i16) {
for n in 0..16 {
out[n] = if plen >= 8 {
plen -= 8;
255u8
} else if plen == 0 {
0u8
} else {
let v = 255u8 << (8 - plen);
plen = 0;
v
}
}
}
fn convert_to_unsigned_4(x: [i8; 4]) -> [u8; 4] {
let mut out: [u8; 4] = [0u8; 4];
for i in 0..4 {
out[i] = x[i] as u8;
}
out
}
fn convert_to_unsigned_16(x: [i8; 16]) -> [u8; 16] {
let mut out: [u8; 16] = [0u8; 16];
for i in 0..16 {
out[i] = x[i] as u8;
}
out
}
macro_rules! call_method_checked {
($env:expr, $obj:expr, $name:expr, $sig:expr, $args:expr, $kind:ident) => {
$env.call_method($obj, $name, $sig, $args)

View File

@@ -0,0 +1,232 @@
#![allow(dead_code)]
use super::*;
use crate::xx::*;
use hex::FromHex;
use if_addrs::{IfAddr, Ifv4Addr, Ifv6Addr};
use std::fs::File;
use std::io::{BufRead, BufReader, Error, ErrorKind};
use std::net::{Ipv4Addr, Ipv6Addr};
#[derive(Debug)]
struct ProcNetIpv6RouteEntry {
dest_network: Ipv6Addr,
dest_prefix: u8,
src_network: Ipv6Addr,
src_prefix: u8,
next_hop: Ipv6Addr,
metric: u32,
ref_count: u32,
use_count: u32,
flags: u32,
intf_name: String,
}
#[derive(Debug)]
struct ProcNetRouteEntry {
iface: String,
destination: Ipv4Addr,
gateway: Ipv4Addr,
flags: u16,
ref_count: u32,
use_count: u32,
metric: u32,
mask: Ipv4Addr,
mtu: u32,
window: u32,
irtt: u32,
}
#[derive(Debug)]
pub struct PlatformSupport {
proc_net_ipv6_route: Vec<ProcNetIpv6RouteEntry>,
proc_net_route: Vec<ProcNetRouteEntry>,
}
impl PlatformSupport {
fn parse_proc_net_ipv6_route() -> Result<Vec<ProcNetIpv6RouteEntry>, Error> {
let file = File::open("/proc/net/ipv6_route")?;
let reader = BufReader::new(file);
let mut ipv6_route: Vec<ProcNetIpv6RouteEntry> = Vec::new();
for line in reader.lines() {
let line = line?;
let line: Vec<&str> = line.split_ascii_whitespace().collect();
if line.len() != 10 {
return Err(Error::new(
ErrorKind::InvalidData,
"Unexpected number of columns in /proc/net/ipv6_route",
));
}
let entry =
ProcNetIpv6RouteEntry {
dest_network: Ipv6Addr::from(<[u8; 16]>::from_hex(line[0]).map_err(|_| {
Error::new(ErrorKind::InvalidData, "Unable to parse dest_network")
})?),
dest_prefix: <[u8; 1]>::from_hex(line[1]).map_err(|_| {
Error::new(ErrorKind::InvalidData, "Unable to parse dest_prefix")
})?[0],
src_network: Ipv6Addr::from(<[u8; 16]>::from_hex(line[2]).map_err(|_| {
Error::new(ErrorKind::InvalidData, "Unable to parse src_network")
})?),
src_prefix: <[u8; 1]>::from_hex(line[3]).map_err(|_| {
Error::new(ErrorKind::InvalidData, "Unable to parse src_prefix")
})?[0],
next_hop: Ipv6Addr::from(<[u8; 16]>::from_hex(line[4]).map_err(|_| {
Error::new(ErrorKind::InvalidData, "Unable to parse next_hop")
})?),
metric: u32::from_be_bytes(<[u8; 4]>::from_hex(line[5]).map_err(|_| {
Error::new(ErrorKind::InvalidData, "Unable to parse metric")
})?),
ref_count: u32::from_be_bytes(<[u8; 4]>::from_hex(line[6]).map_err(|_| {
Error::new(ErrorKind::InvalidData, "Unable to parse ref_count")
})?),
use_count: u32::from_be_bytes(<[u8; 4]>::from_hex(line[7]).map_err(|_| {
Error::new(ErrorKind::InvalidData, "Unable to parse use_count")
})?),
flags: u32::from_be_bytes(<[u8; 4]>::from_hex(line[8]).map_err(|_| {
Error::new(ErrorKind::InvalidData, "Unable to parse flags")
})?),
intf_name: String::from(line[9]),
};
ipv6_route.push(entry)
}
Ok(ipv6_route)
}
fn parse_proc_net_route() -> Result<Vec<ProcNetRouteEntry>, Error> {
let file = File::open("/proc/net/route")?;
let reader = BufReader::new(file);
let mut route: Vec<ProcNetRouteEntry> = Vec::new();
let mut first = false;
for line in reader.lines() {
let line = line?;
let line: Vec<&str> = line.split_ascii_whitespace().collect();
if line.len() != 11 {
return Err(Error::new(
ErrorKind::InvalidData,
"Unexpected number of columns in /proc/net/route",
));
}
if first {
if line
!= [
"Iface",
"Destination",
"Gateway",
"Flags",
"RefCnt",
"Use",
"Metric",
"Mask",
"MTU",
"Window",
"IRTT",
]
{
return Err(Error::new(
ErrorKind::InvalidData,
format!("Unexpected columns in /proc/net/route: {:?}", line),
));
}
first = false;
continue;
}
let entry =
ProcNetRouteEntry {
iface: String::from(line[0]),
destination: Ipv4Addr::from(u32::from_le_bytes(
<[u8; 4]>::from_hex(line[0]).map_err(|_| {
Error::new(ErrorKind::InvalidData, "Unable to parse destination")
})?,
)),
gateway: Ipv4Addr::from(u32::from_le_bytes(
<[u8; 4]>::from_hex(line[0]).map_err(|_| {
Error::new(ErrorKind::InvalidData, "Unable to parse gateway")
})?,
)),
flags: u16::from_be_bytes(<[u8; 2]>::from_hex(line[8]).map_err(|_| {
Error::new(ErrorKind::InvalidData, "Unable to parse flags")
})?),
ref_count: u32::from_be_bytes(<[u8; 4]>::from_hex(line[6]).map_err(|_| {
Error::new(ErrorKind::InvalidData, "Unable to parse ref_count")
})?),
use_count: u32::from_be_bytes(<[u8; 4]>::from_hex(line[7]).map_err(|_| {
Error::new(ErrorKind::InvalidData, "Unable to parse use_count")
})?),
metric: u32::from_be_bytes(<[u8; 4]>::from_hex(line[5]).map_err(|_| {
Error::new(ErrorKind::InvalidData, "Unable to parse metric")
})?),
mask: Ipv4Addr::from(u32::from_le_bytes(
<[u8; 4]>::from_hex(line[0]).map_err(|_| {
Error::new(ErrorKind::InvalidData, "Unable to parse mask")
})?,
)),
mtu: u32::from_be_bytes(
<[u8; 4]>::from_hex(line[5]).map_err(|_| {
Error::new(ErrorKind::InvalidData, "Unable to parse mtu")
})?,
),
window: u32::from_be_bytes(<[u8; 4]>::from_hex(line[5]).map_err(|_| {
Error::new(ErrorKind::InvalidData, "Unable to parse window")
})?),
irtt: u32::from_be_bytes(
<[u8; 4]>::from_hex(line[5]).map_err(|_| {
Error::new(ErrorKind::InvalidData, "Unable to parse irtt")
})?,
),
};
route.push(entry)
}
Ok(route)
}
pub fn new() -> Result<Self, Error> {
// Read /proc/net/ipv6_route
let proc_net_ipv6_route = Self::parse_proc_net_ipv6_route().unwrap_or_default();
// Read /proc/net/route
let proc_net_route = Self::parse_proc_net_route().unwrap_or_default();
trace!("proc_net_ipv6_route: {:#?}", proc_net_ipv6_route);
trace!("proc_net_route: {:#?}", proc_net_route);
// At least one routing table must be available
if proc_net_ipv6_route.is_empty() && proc_net_route.is_empty() {
return Err(Error::new(
ErrorKind::InvalidData,
"No routing tables available",
));
}
Ok(Self {
proc_net_ipv6_route,
proc_net_route,
})
}
pub fn has_default_route(&self, name: &str) -> bool {
for e in &self.proc_net_ipv6_route {
if e.intf_name == name && e.dest_prefix == 0u8 {
return true;
}
}
for e in &self.proc_net_route {
if e.iface == name && e.mask == Ipv4Addr::new(0, 0, 0, 0) {
return true;
}
}
false
}
pub fn get_address_flags(&self, _addr: &IfAddr) -> AddressFlags {
AddressFlags {
is_temporary: false,
is_dynamic: false,
is_deprecated: false,
}
}
}

View File

@@ -0,0 +1,216 @@
use crate::xx::*;
use crate::*;
mod tools;
cfg_if::cfg_if! {
if #[cfg(any(target_os = "linux", target_os = "android"))] {
mod netlink;
use netlink::PlatformSupportNetlink as PlatformSupport;
} else if #[cfg(target_os = "windows")] {
mod windows;
use windows::PlatformSupportWindows as PlatformSupport;
} else if #[cfg(any(target_os = "macos", target_os = "ios"))] {
mod apple;
use apple::PlatformSupportApple as PlatformSupport;
} else {
compile_error!("No network interfaces support for this platform!");
}
}
#[derive(Debug, PartialEq, Eq, Ord, PartialOrd, Hash, Clone)]
pub enum IfAddr {
V4(Ifv4Addr),
V6(Ifv6Addr),
}
impl IfAddr {
pub fn ip(&self) -> IpAddr {
match *self {
IfAddr::V4(ref ifv4_addr) => IpAddr::V4(ifv4_addr.ip),
IfAddr::V6(ref ifv6_addr) => IpAddr::V6(ifv6_addr.ip),
}
}
pub fn netmask(&self) -> IpAddr {
match *self {
IfAddr::V4(ref ifv4_addr) => IpAddr::V4(ifv4_addr.netmask),
IfAddr::V6(ref ifv6_addr) => IpAddr::V6(ifv6_addr.netmask),
}
}
pub fn broadcast(&self) -> Option<IpAddr> {
match *self {
IfAddr::V4(ref ifv4_addr) => ifv4_addr.broadcast.map(IpAddr::V4),
IfAddr::V6(ref ifv6_addr) => ifv6_addr.broadcast.map(IpAddr::V6),
}
}
}
/// Details about the ipv4 address of an interface on this host.
#[derive(Debug, PartialEq, Eq, Ord, PartialOrd, Hash, Clone)]
pub struct Ifv4Addr {
/// The IP address of the interface.
pub ip: Ipv4Addr,
/// The netmask of the interface.
pub netmask: Ipv4Addr,
/// The broadcast address of the interface.
pub broadcast: Option<Ipv4Addr>,
}
/// Details about the ipv6 address of an interface on this host.
#[derive(Debug, PartialEq, Eq, Ord, PartialOrd, Hash, Clone)]
pub struct Ifv6Addr {
/// The IP address of the interface.
pub ip: Ipv6Addr,
/// The netmask of the interface.
pub netmask: Ipv6Addr,
/// The broadcast address of the interface.
pub broadcast: Option<Ipv6Addr>,
}
/// Some of the flags associated with an interface.
#[derive(Debug, Default, PartialEq, Eq, Ord, PartialOrd, Hash, Clone, Copy)]
pub struct InterfaceFlags {
pub is_loopback: bool,
pub is_running: bool,
pub has_default_route: bool,
}
/// Some of the flags associated with an address.
#[derive(Debug, Default, PartialEq, Eq, Ord, PartialOrd, Hash, Clone, Copy)]
pub struct AddressFlags {
pub is_temporary: bool,
pub is_dynamic: bool,
pub is_deprecated: bool,
}
#[derive(PartialEq, Eq, Clone, Debug)]
pub struct InterfaceAddress {
if_addr: IfAddr,
flags: AddressFlags,
}
#[allow(dead_code)]
impl InterfaceAddress {
pub fn new(if_addr: IfAddr, flags: AddressFlags) -> Self {
Self { if_addr, flags }
}
pub fn if_addr(&self) -> &IfAddr {
&self.if_addr
}
pub fn is_temporary(&self) -> bool {
self.flags.is_temporary
}
pub fn is_dynamic(&self) -> bool {
self.flags.is_dynamic
}
pub fn is_deprecated(&self) -> bool {
self.flags.is_deprecated
}
}
#[derive(PartialEq, Eq, Clone, Debug)]
pub struct NetworkInterface {
pub name: String,
pub flags: InterfaceFlags,
pub addrs: Vec<InterfaceAddress>,
}
#[allow(dead_code)]
impl NetworkInterface {
pub fn new(name: String, flags: InterfaceFlags) -> Self {
Self {
name,
flags,
addrs: Vec::new(),
}
}
pub fn name(&self) -> String {
self.name.clone()
}
pub fn is_loopback(&self) -> bool {
self.flags.is_loopback
}
pub fn is_running(&self) -> bool {
self.flags.is_running
}
pub fn has_default_route(&self) -> bool {
self.flags.has_default_route
}
pub fn primary_ipv4(&self) -> Option<Ipv4Addr> {
// see if we have a non-dynamic address to use first
let mut best_dynamic: Option<Ipv4Addr> = None;
for x in self.addrs.iter() {
if let IfAddr::V4(a) = x.if_addr() {
if !x.is_dynamic() {
return Some(a.ip);
} else if best_dynamic.is_none() {
best_dynamic = Some(a.ip);
}
}
}
best_dynamic
}
pub fn primary_ipv6(&self) -> Option<Ipv6Addr> {
let mut best_dynamic: Option<Ipv6Addr> = None;
for x in self.addrs.iter() {
if let IfAddr::V6(a) = x.if_addr() {
if x.is_temporary() || x.is_deprecated() {
if !x.is_dynamic() {
return Some(a.ip);
} else if best_dynamic.is_none() {
best_dynamic = Some(a.ip);
}
}
}
}
best_dynamic
}
}
#[derive(PartialEq, Eq, Clone, Debug)]
pub struct NetworkInterfaces {
valid: bool,
interfaces: BTreeMap<String, NetworkInterface>,
}
#[allow(dead_code)]
impl NetworkInterfaces {
pub fn new() -> Self {
Self {
valid: false,
interfaces: BTreeMap::new(),
}
}
pub fn is_valid(&self) -> bool {
self.valid
}
pub fn clear(&mut self) {
self.interfaces.clear();
self.valid = false;
}
// returns Ok(false) if refresh had no changes, Ok(true) if changes were present
pub async fn refresh(&mut self) -> Result<bool, String> {
self.valid = false;
let last_interfaces = core::mem::take(&mut self.interfaces);
let mut platform_support = PlatformSupport::new().map_err(logthru_net!())?;
platform_support
.get_interfaces(&mut self.interfaces)
.await?;
self.valid = true;
Ok(last_interfaces != self.interfaces)
}
pub fn len(&self) -> usize {
self.interfaces.len()
}
pub fn iter(&self) -> std::collections::btree_map::Iter<String, NetworkInterface> {
self.interfaces.iter()
}
}

View File

@@ -0,0 +1,288 @@
use super::*;
use alloc::collections::btree_map::Entry;
use futures_util::stream::TryStreamExt;
use ifstructs::ifreq;
use libc::{
close, if_indextoname, ioctl, socket, IFA_F_DADFAILED, IFA_F_DEPRECATED, IFA_F_PERMANENT,
IFA_F_TEMPORARY, IFA_F_TENTATIVE, IFF_LOOPBACK, IFF_RUNNING, IF_NAMESIZE, SIOCGIFFLAGS,
SOCK_DGRAM,
};
use rtnetlink::packet::{nlas::address::Nla, AddressMessage, AF_INET, AF_INET6};
use rtnetlink::{new_connection_with_socket, sys::SmolSocket, Handle, IpVersion};
use std::convert::TryInto;
use std::ffi::CStr;
use std::io;
use std::os::raw::c_int;
use tools::*;
fn get_interface_name(index: u32) -> Result<String, String> {
let mut ifnamebuf = [0u8; (IF_NAMESIZE + 1)];
if unsafe { if_indextoname(index, ifnamebuf.as_mut_ptr() as *mut i8) }.is_null() {
return Err("if_indextoname returned null".to_owned());
}
let ifnamebuflen = ifnamebuf
.iter()
.position(|c| *c == 0u8)
.ok_or_else(|| "null not found in interface name".to_owned())?;
let ifname_str = CStr::from_bytes_with_nul(&ifnamebuf[0..=ifnamebuflen])
.map_err(map_to_string)?
.to_str()
.map_err(map_to_string)?;
Ok(ifname_str.to_owned())
}
fn flags_to_address_flags(flags: u32) -> AddressFlags {
AddressFlags {
is_temporary: (flags & IFA_F_TEMPORARY) != 0,
is_dynamic: (flags & IFA_F_PERMANENT) == 0,
is_deprecated: (flags & IFA_F_DEPRECATED) != 0,
}
}
pub struct PlatformSupportNetlink {
_connection_jh: intf::JoinHandle<()>,
handle: Handle,
default_route_interfaces: BTreeSet<u32>,
}
impl PlatformSupportNetlink {
pub fn new() -> Result<Self, String> {
// Get the netlink connection
let (connection, handle, _) = new_connection_with_socket::<SmolSocket>()
.map_err(map_to_string)
.map_err(logthru_net!(error))?;
// Spawn a connection handler
let _connection_jh = intf::spawn(connection);
Ok(PlatformSupportNetlink {
_connection_jh,
handle,
default_route_interfaces: BTreeSet::new(),
})
}
// Figure out which interfaces have default routes
async fn refresh_default_route_interfaces(&mut self) -> Result<(), String> {
self.default_route_interfaces.clear();
let mut routesv4 = self.handle.route().get(IpVersion::V4).execute();
while let Some(routev4) = routesv4.try_next().await.unwrap_or_default() {
if let Some(index) = routev4.input_interface() {
if let Some((dest, prefix)) = routev4.destination_prefix() {
if prefix == 0 && dest.is_unspecified() {
self.default_route_interfaces.insert(index);
}
}
}
}
let mut routesv6 = self.handle.route().get(IpVersion::V6).execute();
while let Some(routev6) = routesv6.try_next().await.unwrap_or_default() {
if let Some(index) = routev6.input_interface() {
if let Some((dest, prefix)) = routev6.destination_prefix() {
if prefix == 0 && dest.is_unspecified() {
self.default_route_interfaces.insert(index);
}
}
}
}
Ok(())
}
fn get_interface_flags(&self, index: u32, ifname: &str) -> Result<InterfaceFlags, String> {
let mut req = ifreq::from_name(ifname).map_err(map_to_string)?;
let sock = unsafe { socket(AF_INET as i32, SOCK_DGRAM, 0) };
if sock < 0 {
return Err(io::Error::last_os_error()).map_err(map_to_string);
}
let res = unsafe { ioctl(sock, SIOCGIFFLAGS, &mut req) };
unsafe { close(sock) };
if res < 0 {
return Err(io::Error::last_os_error()).map_err(map_to_string);
}
let flags = req.get_flags() as c_int;
Ok(InterfaceFlags {
is_loopback: (flags & IFF_LOOPBACK) != 0,
is_running: (flags & IFF_RUNNING) != 0,
has_default_route: self.default_route_interfaces.contains(&index),
})
}
fn process_address_message_v4(msg: AddressMessage) -> Option<InterfaceAddress> {
// Get ip address
let ip = msg.nlas.iter().find_map(|nla| {
if let Nla::Address(a) = nla {
let a: Option<[u8; 4]> = a.clone().try_into().ok();
a.map(Ipv4Addr::from)
} else {
None
}
})?;
// get netmask
let plen = msg.header.prefix_len as i16;
let mut netmask = [0u8; 4];
get_netmask_from_prefix_length_v4(&mut netmask, plen);
let netmask = Ipv4Addr::from(netmask);
// get broadcast address
let broadcast = msg.nlas.iter().find_map(|nla| {
if let Nla::Broadcast(b) = nla {
let b: Option<[u8; 4]> = b.clone().try_into().ok();
b.map(Ipv4Addr::from)
} else {
None
}
});
// get address flags
let flags = msg
.nlas
.iter()
.find_map(|nla| {
if let Nla::Flags(f) = nla {
Some(*f)
} else {
None
}
})
.unwrap_or(msg.header.flags as u32);
Some(InterfaceAddress::new(
IfAddr::V4(Ifv4Addr {
ip,
/// The netmask of the interface.
netmask,
/// The broadcast address of the interface.
broadcast,
}),
flags_to_address_flags(flags),
))
}
fn process_address_message_v6(msg: AddressMessage) -> Option<InterfaceAddress> {
// Get ip address
let ip = msg.nlas.iter().find_map(|nla| {
if let Nla::Address(a) = nla {
let a: Option<[u8; 16]> = a.clone().try_into().ok();
a.map(Ipv6Addr::from)
} else {
None
}
})?;
// get netmask
let plen = msg.header.prefix_len as i16;
let mut netmask = [0u8; 16];
get_netmask_from_prefix_length_v6(&mut netmask, plen);
let netmask = Ipv6Addr::from(netmask);
// get address flags
let flags = msg
.nlas
.iter()
.find_map(|nla| {
if let Nla::Flags(f) = nla {
Some(*f)
} else {
None
}
})
.unwrap_or(msg.header.flags as u32);
// Skip addresses going through duplicate address detection, or ones that have failed it
if ((flags & IFA_F_TENTATIVE) != 0) || ((flags & IFA_F_DADFAILED) != 0) {
return None;
}
Some(InterfaceAddress::new(
IfAddr::V6(Ifv6Addr {
ip,
/// The netmask of the interface.
netmask,
/// The broadcast address of the interface.
broadcast: None,
}),
flags_to_address_flags(flags),
))
}
pub async fn get_interfaces(
&mut self,
interfaces: &mut BTreeMap<String, NetworkInterface>,
) -> Result<(), String> {
// Refresh the routes
self.refresh_default_route_interfaces().await?;
// If we have no routes, this isn't going to work
if self.default_route_interfaces.is_empty() {
return Err("no routes available for NetworkInterfaces".to_owned());
}
// Ask for all the addresses we have
let mut names = BTreeMap::<u32, String>::new();
let mut addresses = self.handle.address().get().execute();
while let Some(msg) = addresses
.try_next()
.await
.map_err(map_to_string)
.map_err(logthru_net!(error))?
{
// Have we seen this interface index yet?
// Get the name from the index, cached, if we can
let ifname = match names.entry(msg.header.index) {
Entry::Vacant(v) => {
// If not, get the name for the index if we can
let ifname = match get_interface_name(msg.header.index) {
Ok(v) => v,
Err(e) => {
log_net!(
"couldn't get interface name for index {}: {}",
msg.header.index,
e
);
continue;
}
};
v.insert(ifname).clone()
}
Entry::Occupied(o) => o.get().clone(),
};
// Map the name to a NetworkInterface
if !interfaces.contains_key(&ifname) {
// If we have no NetworkInterface yet, make one
let flags = self.get_interface_flags(msg.header.index, &ifname)?;
interfaces.insert(ifname.clone(), NetworkInterface::new(ifname.clone(), flags));
}
let intf = interfaces.get_mut(&ifname).unwrap();
// Process the address
let intf_addr = match msg.header.family as u16 {
AF_INET => match Self::process_address_message_v4(msg) {
Some(ia) => ia,
None => {
continue;
}
},
AF_INET6 => match Self::process_address_message_v6(msg) {
Some(ia) => ia,
None => {
continue;
}
},
_ => {
continue;
}
};
intf.addrs.push(intf_addr);
}
Ok(())
}
}

View File

@@ -0,0 +1,45 @@
pub fn convert_to_unsigned_4(x: [i8; 4]) -> [u8; 4] {
let mut out: [u8; 4] = [0u8; 4];
for i in 0..4 {
out[i] = x[i] as u8;
}
out
}
pub fn convert_to_unsigned_16(x: [i8; 16]) -> [u8; 16] {
let mut out: [u8; 16] = [0u8; 16];
for i in 0..16 {
out[i] = x[i] as u8;
}
out
}
pub fn get_netmask_from_prefix_length_v4(out: &mut [u8; 4], mut plen: i16) {
for outb in out.iter_mut() {
*outb = if plen >= 8 {
plen -= 8;
255u8
} else if plen <= 0 {
0u8
} else {
let v = 255u8 << (8 - plen);
plen = 0;
v
}
}
}
pub fn get_netmask_from_prefix_length_v6(out: &mut [u8; 16], mut plen: i16) {
for outb in out.iter_mut() {
*outb = if plen >= 8 {
plen -= 8;
255u8
} else if plen == 0 {
0u8
} else {
let v = 255u8 << (8 - plen);
plen = 0;
v
}
}
}

View File

@@ -0,0 +1,19 @@
use super::*;
pub struct PlatformSupportWindows {
//
}
impl PlatformSupportWindows {
pub fn new() -> Result<Self, String> {
Ok(PlatformSupportWindows {})
}
pub async fn get_interfaces(
&mut self,
interfaces: &mut BTreeMap<String, NetworkInterface>,
) -> Result<(), String> {
//
Ok(())
}
}

View File

@@ -80,6 +80,7 @@ impl TableStore {
let db = Database::open(table_name.clone(), column_count)
.await
.map_err(|e| format!("failed to open tabledb at: {} ({})", table_name, e))?;
info!("opened table store '{}' with table name '{:?}' with {} columns", name, table_name, column_count);
let table_db = TableDB::new(table_name.clone(), self.clone(), db);