Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
56 changes: 56 additions & 0 deletions src/os/bsd/route/freebsd.rs
Original file line number Diff line number Diff line change
@@ -0,0 +1,56 @@
use libc::{c_int, c_ulong, c_ushort, pid_t};

#[repr(C)]
#[derive(Debug, Copy, Clone)]
pub(in crate::os::bsd) struct rt_metrics {
pub(in crate::os::bsd) rmx_locks: c_ulong,
pub(in crate::os::bsd) rmx_mtu: c_ulong,
pub(in crate::os::bsd) rmx_hopcount: c_ulong,
pub(in crate::os::bsd) rmx_expire: c_ulong,
pub(in crate::os::bsd) rmx_recvpipe: c_ulong,
pub(in crate::os::bsd) rmx_sendpipe: c_ulong,
pub(in crate::os::bsd) rmx_ssthresh: c_ulong,
pub(in crate::os::bsd) rmx_rtt: c_ulong,
pub(in crate::os::bsd) rmx_rttvar: c_ulong,
pub(in crate::os::bsd) rmx_pksent: c_ulong,
pub(in crate::os::bsd) rmx_weight: c_ulong,
pub(in crate::os::bsd) rmx_nhidx: c_ulong,
pub(in crate::os::bsd) rmx_filler: [c_ulong; 2],
}

#[repr(C)]
#[derive(Debug, Copy, Clone)]
pub(in crate::os::bsd) struct rt_msghdr {
pub(in crate::os::bsd) rtm_msglen: c_ushort,
pub(in crate::os::bsd) rtm_version: u8,
pub(in crate::os::bsd) rtm_type: u8,
pub(in crate::os::bsd) rtm_index: c_ushort,
pub(in crate::os::bsd) _rtm_spare1: c_ushort,
pub(in crate::os::bsd) rtm_flags: c_int,
pub(in crate::os::bsd) rtm_addrs: c_int,
pub(in crate::os::bsd) rtm_pid: pid_t,
pub(in crate::os::bsd) rtm_seq: c_int,
pub(in crate::os::bsd) rtm_errno: c_int,
pub(in crate::os::bsd) rtm_fmask: c_int,
pub(in crate::os::bsd) rtm_inits: c_ulong,
pub(in crate::os::bsd) rtm_rmx: rt_metrics,
}

pub(in crate::os::bsd) const SOCKADDR_ALIGN: usize = core::mem::size_of::<libc::c_long>();

#[inline]
pub(in crate::os::bsd) fn message_header_len(_: &rt_msghdr) -> usize {
core::mem::size_of::<rt_msghdr>()
}

#[cfg(all(
target_pointer_width = "64",
any(target_arch = "x86_64", target_arch = "aarch64")
))]
const _: [(); 112] = [(); core::mem::size_of::<rt_metrics>()];

#[cfg(all(
target_pointer_width = "64",
any(target_arch = "x86_64", target_arch = "aarch64")
))]
const _: [(); 152] = [(); core::mem::size_of::<rt_msghdr>()];
78 changes: 28 additions & 50 deletions src/os/bsd/route.rs → src/os/bsd/route/mod.rs
Original file line number Diff line number Diff line change
@@ -1,6 +1,13 @@
#![allow(non_camel_case_types)]

use libc::{c_int, pid_t, size_t};
#[cfg(target_os = "freebsd")]
mod freebsd;
#[cfg(target_os = "netbsd")]
mod netbsd;
#[cfg(target_os = "openbsd")]
mod openbsd;

use libc::{c_int, size_t};
use std::{
collections::HashMap,
ffi::c_void,
Expand All @@ -9,6 +16,13 @@ use std::{
ptr,
};

#[cfg(target_os = "freebsd")]
use self::freebsd::{SOCKADDR_ALIGN, message_header_len, rt_msghdr};
#[cfg(target_os = "netbsd")]
use self::netbsd::{SOCKADDR_ALIGN, message_header_len, rt_msghdr};
#[cfg(target_os = "openbsd")]
use self::openbsd::{SOCKADDR_ALIGN, message_header_len, rt_msghdr};

use crate::net::{device::NetworkDevice, mac::MacAddr};

const CTL_NET: c_int = libc::CTL_NET;
Expand All @@ -21,8 +35,6 @@ const RTM_VERSION: u8 = 5;
#[cfg(target_os = "netbsd")]
const RTM_VERSION: u8 = 4;

const RTF_WASCLONED: i32 = 0x20000;

const RTAX_DST: usize = 0;
const RTAX_GATEWAY: usize = 1;
const RTAX_NETMASK: usize = 2;
Expand All @@ -34,43 +46,6 @@ const RTAX_MAX: usize = 9;
#[cfg(target_os = "openbsd")]
const RTAX_MAX: usize = 15;

const SA_ALIGN: usize = 4;

#[repr(C)]
#[derive(Debug, Copy, Clone)]
struct rt_metrics {
rmx_locks: u32,
rmx_mtu: u32,
rmx_hopcount: u32,
rmx_expire: i32,
rmx_recvpipe: u32,
rmx_sendpipe: u32,
rmx_ssthresh: u32,
rmx_rtt: u32,
rmx_rttvar: u32,
rmx_pksent: u32,
rmx_weight: u32,
rmx_nhidx: u32,
rmx_filler: [u32; 2],
}

#[repr(C)]
#[derive(Debug, Copy, Clone)]
struct rt_msghdr {
rtm_msglen: u16,
rtm_version: u8,
rtm_type: u8,
rtm_index: u16,
rtm_flags: c_int,
rtm_addrs: c_int,
rtm_pid: pid_t,
rtm_seq: c_int,
rtm_errno: c_int,
rtm_use: c_int,
rtm_inits: u32,
rtm_rmx: rt_metrics,
}

unsafe extern "C" {
fn sysctl(
name: *mut c_int,
Expand Down Expand Up @@ -154,9 +129,9 @@ fn sysctl_vec(mib: &mut [c_int]) -> io::Result<Vec<u8>> {
#[inline]
fn roundup(len: usize) -> usize {
if len == 0 {
SA_ALIGN
SOCKADDR_ALIGN
} else {
(len + (SA_ALIGN - 1)) & !(SA_ALIGN - 1)
(len + (SOCKADDR_ALIGN - 1)) & !(SOCKADDR_ALIGN - 1)
}
}

Expand Down Expand Up @@ -344,9 +319,8 @@ struct RawRoute {
}

fn parse_one_route(hdr: &rt_msghdr, addr_block: &[u8]) -> Option<RawRoute> {
const MSG_START_INDEX: usize = 60;
let mut addrs: [Option<*const libc::sockaddr>; RTAX_MAX] = [None; RTAX_MAX];
let mut off = MSG_START_INDEX;
let mut off = 0usize;

for idx in 0..RTAX_MAX {
if (hdr.rtm_addrs & (1 << idx)) != 0 {
Expand Down Expand Up @@ -432,7 +406,11 @@ fn get_arp_table() -> io::Result<HashMap<IpAddr, MacAddr>> {
return Err(code_to_error(hdr.rtm_errno));
}

let addr_block = &buf[off + mem::size_of::<rt_msghdr>()..off + msglen];
let hdrlen = message_header_len(hdr);
if hdrlen < mem::size_of::<rt_msghdr>() || off + hdrlen > off + msglen {
break;
}
let addr_block = &buf[off + hdrlen..off + msglen];
if let Some((ip, mac)) = message_to_arppair(addr_block) {
arp_map.insert(ip, mac);
}
Expand Down Expand Up @@ -469,15 +447,15 @@ fn list_routes() -> io::Result<Vec<RawRoute>> {
off += msglen;
continue;
}
if (hdr.rtm_flags & RTF_WASCLONED) != 0 {
off += msglen;
continue;
}
if hdr.rtm_errno != 0 {
return Err(code_to_error(hdr.rtm_errno));
}

let addr_block = &buf[off + mem::size_of::<rt_msghdr>()..off + msglen];
let hdrlen = message_header_len(hdr);
if hdrlen < mem::size_of::<rt_msghdr>() || off + hdrlen > off + msglen {
break;
}
let addr_block = &buf[off + hdrlen..off + msglen];
if let Some(rr) = parse_one_route(hdr, addr_block) {
out.push(rr);
}
Expand Down
43 changes: 43 additions & 0 deletions src/os/bsd/route/netbsd.rs
Original file line number Diff line number Diff line change
@@ -0,0 +1,43 @@
use libc::{c_int, pid_t};

#[repr(C, align(8))]
#[derive(Debug, Copy, Clone)]
pub(in crate::os::bsd) struct rt_metrics {
pub(in crate::os::bsd) rmx_locks: u64,
pub(in crate::os::bsd) rmx_mtu: u64,
pub(in crate::os::bsd) rmx_hopcount: u64,
pub(in crate::os::bsd) rmx_recvpipe: u64,
pub(in crate::os::bsd) rmx_sendpipe: u64,
pub(in crate::os::bsd) rmx_ssthresh: u64,
pub(in crate::os::bsd) rmx_rtt: u64,
pub(in crate::os::bsd) rmx_rttvar: u64,
pub(in crate::os::bsd) rmx_expire: i64,
pub(in crate::os::bsd) rmx_pksent: i64,
}

#[repr(C, align(8))]
#[derive(Debug, Copy, Clone)]
pub(in crate::os::bsd) struct rt_msghdr {
pub(in crate::os::bsd) rtm_msglen: u16,
pub(in crate::os::bsd) rtm_version: u8,
pub(in crate::os::bsd) rtm_type: u8,
pub(in crate::os::bsd) rtm_index: u16,
pub(in crate::os::bsd) rtm_flags: c_int,
pub(in crate::os::bsd) rtm_addrs: c_int,
pub(in crate::os::bsd) rtm_pid: pid_t,
pub(in crate::os::bsd) rtm_seq: c_int,
pub(in crate::os::bsd) rtm_errno: c_int,
pub(in crate::os::bsd) rtm_use: c_int,
pub(in crate::os::bsd) rtm_inits: c_int,
pub(in crate::os::bsd) rtm_rmx: rt_metrics,
}

pub(in crate::os::bsd) const SOCKADDR_ALIGN: usize = core::mem::size_of::<u64>();

#[inline]
pub(in crate::os::bsd) fn message_header_len(_: &rt_msghdr) -> usize {
core::mem::size_of::<rt_msghdr>()
}

const _: [(); 80] = [(); core::mem::size_of::<rt_metrics>()];
const _: [(); 120] = [(); core::mem::size_of::<rt_msghdr>()];
52 changes: 52 additions & 0 deletions src/os/bsd/route/openbsd.rs
Original file line number Diff line number Diff line change
@@ -0,0 +1,52 @@
use libc::{c_int, pid_t};

#[repr(C)]
#[derive(Debug, Copy, Clone)]
pub(in crate::os::bsd) struct rt_metrics {
pub(in crate::os::bsd) rmx_pksent: u64,
pub(in crate::os::bsd) rmx_expire: i64,
pub(in crate::os::bsd) rmx_locks: u32,
pub(in crate::os::bsd) rmx_mtu: u32,
pub(in crate::os::bsd) rmx_refcnt: u32,
pub(in crate::os::bsd) rmx_hopcount: u32,
pub(in crate::os::bsd) rmx_recvpipe: u32,
pub(in crate::os::bsd) rmx_sendpipe: u32,
pub(in crate::os::bsd) rmx_ssthresh: u32,
pub(in crate::os::bsd) rmx_rtt: u32,
pub(in crate::os::bsd) rmx_rttvar: u32,
pub(in crate::os::bsd) rmx_pad: u32,
}

#[repr(C)]
#[derive(Debug, Copy, Clone)]
pub(in crate::os::bsd) struct rt_msghdr {
pub(in crate::os::bsd) rtm_msglen: u16,
pub(in crate::os::bsd) rtm_version: u8,
pub(in crate::os::bsd) rtm_type: u8,
pub(in crate::os::bsd) rtm_hdrlen: u16,
pub(in crate::os::bsd) rtm_index: u16,
pub(in crate::os::bsd) rtm_tableid: u16,
pub(in crate::os::bsd) rtm_priority: u8,
pub(in crate::os::bsd) rtm_mpls: u8,
pub(in crate::os::bsd) rtm_addrs: c_int,
pub(in crate::os::bsd) rtm_flags: c_int,
pub(in crate::os::bsd) rtm_fmask: c_int,
pub(in crate::os::bsd) rtm_pid: pid_t,
pub(in crate::os::bsd) rtm_seq: c_int,
pub(in crate::os::bsd) rtm_errno: c_int,
pub(in crate::os::bsd) rtm_inits: u32,
pub(in crate::os::bsd) rtm_rmx: rt_metrics,
}

pub(in crate::os::bsd) const SOCKADDR_ALIGN: usize = core::mem::size_of::<libc::c_long>();

#[inline]
pub(in crate::os::bsd) fn message_header_len(hdr: &rt_msghdr) -> usize {
hdr.rtm_hdrlen as usize
}

#[cfg(target_pointer_width = "64")]
const _: [(); 56] = [(); core::mem::size_of::<rt_metrics>()];

#[cfg(target_pointer_width = "64")]
const _: [(); 96] = [(); core::mem::size_of::<rt_msghdr>()];
59 changes: 46 additions & 13 deletions src/os/unix/interface.rs
Original file line number Diff line number Diff line change
@@ -1,16 +1,15 @@
use std::ffi::{CStr, CString};
use std::ffi::CString;
use std::mem::MaybeUninit;
use std::net::{IpAddr, Ipv4Addr, Ipv6Addr};
use std::os::raw::c_char;
use std::str::from_utf8_unchecked;

use super::sockaddr::{SockaddrRef, compute_sockaddr_len, netmask_ip_autolen, try_mac_from_raw};
use crate::interface::interface::Interface;
use crate::interface::ipv6_addr_flags::get_ipv6_addr_flags;
use crate::interface::mtu::get_mtu;
use crate::interface::state::OperState;
use crate::ipnet::{Ipv4Net, Ipv6Net};
use crate::os::unix::types::get_interface_type;
use crate::os::unix::types::{get_interface_type, interface_name_from_ptr};
use crate::stats::counters::{InterfaceStats, get_stats};

#[cfg(target_os = "android")]
Expand Down Expand Up @@ -43,8 +42,7 @@ fn unix_interfaces_inner(
let addr_ref: &libc::ifaddrs = unsafe { &*addr };
let if_type = get_interface_type(addr_ref);
let c_str = addr_ref.ifa_name as *const c_char;
let bytes = unsafe { CStr::from_ptr(c_str).to_bytes() };
let name: String = unsafe { from_utf8_unchecked(bytes).to_owned() };
let name = interface_name_from_ptr(c_str);
let if_index = if_nametoindex_or_zero(&name);
let cap: libc::socklen_t = super::sockaddr::sockaddr_storage_cap();
let addr_len_opt = unsafe { compute_sockaddr_len(addr_ref.ifa_addr, None, Some(cap)) };
Expand Down Expand Up @@ -122,20 +120,25 @@ fn unix_interfaces_inner(
iface.stats = stats;
}
if let Some(ipv4_addr) = ini_ipv4 {
iface.ipv4.push(ipv4_addr);
push_ipv4(&mut iface.ipv4, ipv4_addr);
}
if let (Some(ipv6_addr), Some(scope_id)) = (ini_ipv6, ipv6_scope_id) {
let af = get_ipv6_addr_flags(&iface.name, &ipv6_addr.addr());
iface.ipv6.push(ipv6_addr);
iface.ipv6_scope_ids.push(scope_id);
iface.ipv6_addr_flags.push(af);
push_ipv6(
&mut iface.ipv6,
&mut iface.ipv6_scope_ids,
&mut iface.ipv6_addr_flags,
ipv6_addr,
scope_id,
af,
);
}
} else {
let mtu = get_mtu(addr_ref, &name);
let ini_ipv6_flags = ini_ipv6
.as_ref()
.map(|net| vec![get_ipv6_addr_flags(&name, &net.addr())])
.unwrap_or_default();
let ini_ipv6_flags = match ini_ipv6.as_ref() {
Some(ipv6_addr) => vec![get_ipv6_addr_flags(&name, &ipv6_addr.addr())],
None => Vec::new(),
};
let interface: Interface = Interface {
index: if_index,
name,
Expand Down Expand Up @@ -184,6 +187,36 @@ fn unix_interfaces_inner(
ifaces
}

fn push_ipv4(v: &mut Vec<Ipv4Net>, net: Ipv4Net) -> bool {
if v.iter()
.any(|existing| existing.addr() == net.addr() && existing.prefix_len() == net.prefix_len())
{
return false;
}
v.push(net);
true
}

fn push_ipv6(
addrs: &mut Vec<Ipv6Net>,
scope_ids: &mut Vec<u32>,
addr_flags: &mut Vec<crate::interface::ipv6_addr_flags::Ipv6AddrFlags>,
net: Ipv6Net,
scope_id: u32,
flags: crate::interface::ipv6_addr_flags::Ipv6AddrFlags,
) -> bool {
if addrs
.iter()
.any(|existing| existing.addr() == net.addr() && existing.prefix_len() == net.prefix_len())
{
return false;
}
addrs.push(net);
scope_ids.push(scope_id);
addr_flags.push(flags);
true
}

fn if_nametoindex_or_zero(name: &str) -> u32 {
match CString::new(name.as_bytes()) {
Ok(name) => unsafe { libc::if_nametoindex(name.as_ptr()) },
Expand Down
Loading
Loading