From 830aeaddbf044a9dcc105853b7dcd2d84744db46 Mon Sep 17 00:00:00 2001 From: Friedel Ziegelmayer Date: Fri, 24 May 2024 18:54:04 +0200 Subject: [PATCH] feat: support {Free|Net|Open}BSD (#2311) MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Adds support for `iroh` on `NetBSD`, `FreeBSD` and `OpenBSD`. ## Status - NetBsd - [x] Compiles - [ ] Tests passing - [ ] Iroh: mostly passing, failures are only due to https://github.com/shellrow/netdev/issues/69 - [x] Quinn - [x] Implementation adapted - FreeBsd - [x] Compiles - [ ] Tests passing - [ ] Iroh: mostly passing, failures are only due to https://github.com/shellrow/netdev/issues/69 - [x] Quinn - [x] Implementation adapted - OpenBsd - [x] Compiles - [ ] Tests passing - [ ] Iroh: mostly passing, failures are only due to https://github.com/shellrow/netdev/issues/69 - [x] Quinn - [x] Implementation adapted ## Caveats - Build only in CI for now ## Related Issues - https://github.com/shellrow/netdev/issues/69 - https://github.com/n0-computer/quinn/pull/9 ## References - https://github.com/freebsd/freebsd-ports/blob/78ad38f04f51/games/jumpy/files/patch-iroh - https://github.com/rust-lang/libc/issues/3711 Closes #2306 --------- Co-authored-by: Floris Bruynooghe --- .github/workflows/ci.yml | 43 ++- Cargo.lock | 2 +- iroh-net/Cargo.toml | 8 +- iroh-net/bench/Cargo.toml | 4 +- iroh-net/bench/src/bin/bulk.rs | 6 +- iroh-net/bench/src/lib.rs | 12 + iroh-net/src/net/interfaces/bsd.rs | 288 +++++++++--------- iroh-net/src/net/interfaces/bsd/freebsd.rs | 326 +++++++++++++++++++++ iroh-net/src/net/interfaces/bsd/macos.rs | 86 ++++++ iroh-net/src/net/interfaces/bsd/netbsd.rs | 115 ++++++++ iroh-net/src/net/interfaces/bsd/openbsd.rs | 105 +++++++ iroh-net/src/net/netmon/bsd.rs | 10 +- iroh-net/src/tls/certificate.rs | 8 +- 13 files changed, 861 insertions(+), 152 deletions(-) create mode 100644 iroh-net/src/net/interfaces/bsd/freebsd.rs create mode 100644 iroh-net/src/net/interfaces/bsd/macos.rs create mode 100644 iroh-net/src/net/interfaces/bsd/netbsd.rs create mode 100644 iroh-net/src/net/interfaces/bsd/openbsd.rs diff --git a/.github/workflows/ci.yml b/.github/workflows/ci.yml index 2a207c1b0a6..074a3bea4ac 100644 --- a/.github/workflows/ci.yml +++ b/.github/workflows/ci.yml @@ -25,18 +25,23 @@ jobs: if: "github.event_name != 'pull_request' || ! contains(github.event.pull_request.labels.*.name, 'flaky-test')" uses: './.github/workflows/tests.yaml' - cross: + cross_build: + name: Cross Build Only if: "github.event_name != 'pull_request' || ! contains(github.event.pull_request.labels.*.name, 'flaky-test')" timeout-minutes: 30 - name: Cross compile runs-on: [self-hosted, linux, X64] strategy: fail-fast: false matrix: target: - - i686-unknown-linux-gnu + # cross tests are currently broken vor armv7 and aarch64 + # see https://github.com/cross-rs/cross/issues/1311 - armv7-linux-androideabi - aarch64-linux-android + # Freebsd execution fails in cross + # - i686-unknown-freebsd # Linking fails :/ + - x86_64-unknown-freebsd + - x86_64-unknown-netbsd steps: - name: Checkout uses: actions/checkout@v4 @@ -59,15 +64,39 @@ jobs: # cross tests are currently broken vor armv7 and aarch64 # see https://github.com/cross-rs/cross/issues/1311. So on # those platforms we only build but do not run tests. - if: matrix.target != 'i686-unknown-linux-gnu' run: cross build --all --target ${{ matrix.target }} env: RUST_LOG: ${{ runner.debug && 'TRACE' || 'DEBUG'}} + cross_test: + name: Cross Test + if: "github.event_name != 'pull_request' || ! contains(github.event.pull_request.labels.*.name, 'flaky-test')" + timeout-minutes: 30 + runs-on: [self-hosted, linux, X64] + strategy: + fail-fast: false + matrix: + target: + - i686-unknown-linux-gnu + steps: + - name: Checkout + uses: actions/checkout@v4 + with: + submodules: recursive + + - name: Install rust stable + uses: dtolnay/rust-toolchain@stable + + - name: Cleanup Docker + continue-on-error: true + run: | + docker kill $(docker ps -q) + + - name: Install cross + # See https://github.com/cross-rs/cross/issues/1222 + run: cargo install cross --git https://github.com/cross-rs/cross + - name: test - # cross tests are currently broken vor armv7 and aarch64 - # see https://github.com/cross-rs/cross/issues/1311 - if: matrix.target == 'i686-unknown-linux-gnu' run: cross test --all --target ${{ matrix.target }} -- --test-threads=12 env: RUST_LOG: ${{ runner.debug && 'TRACE' || 'DEBUG' }} diff --git a/Cargo.lock b/Cargo.lock index 2e7c2c17b78..49b5936d00f 100644 --- a/Cargo.lock +++ b/Cargo.lock @@ -2806,7 +2806,7 @@ dependencies = [ "rand", "rand_chacha", "rand_core", - "rcgen 0.11.3", + "rcgen 0.12.1", "regex", "reqwest 0.12.4", "ring 0.17.8", diff --git a/iroh-net/Cargo.toml b/iroh-net/Cargo.toml index f73a8f1ab06..35e9758a2e0 100644 --- a/iroh-net/Cargo.toml +++ b/iroh-net/Cargo.toml @@ -49,12 +49,12 @@ parking_lot = "0.12.1" pin-project = "1" pkarr = { version = "1.1.4", default-features = false, features = ["async", "relay"] } postcard = { version = "1", default-features = false, features = ["alloc", "use-std", "experimental-derive"] } -quinn = { package = "iroh-quinn", version = "0.10.4" } -quinn-proto = { package = "iroh-quinn-proto", version = "0.10.7" } -quinn-udp = { package = "iroh-quinn-udp", version = "0.4" } +quinn = { package = "iroh-quinn", version = "0.10.5" } +quinn-proto = { package = "iroh-quinn-proto", version = "0.10.8" } +quinn-udp = { package = "iroh-quinn-udp", version = "0.4.2" } rand = "0.8" rand_core = "0.6.4" -rcgen = "0.11" +rcgen = "0.12" reqwest = { version = "0.12.4", default-features = false, features = ["rustls-tls"] } ring = "0.17" rustls = { version = "0.21.11", default-features = false, features = ["dangerous_configuration"] } diff --git a/iroh-net/bench/Cargo.toml b/iroh-net/bench/Cargo.toml index b5c7048e0a6..c947025f9b5 100644 --- a/iroh-net/bench/Cargo.toml +++ b/iroh-net/bench/Cargo.toml @@ -10,7 +10,6 @@ anyhow = "1.0.22" bytes = "1" hdrhistogram = { version = "7.2", default-features = false } iroh-net = { path = ".." } -quinn = "0.10" rcgen = "0.11.1" rustls = { version = "0.21.0", default-features = false, features = ["quic"] } clap = { version = "4", features = ["derive"] } @@ -18,3 +17,6 @@ tokio = { version = "1.0.1", features = ["rt", "sync"] } tracing = "0.1" tracing-subscriber = { version = "0.3.0", default-features = false, features = ["env-filter", "fmt", "ansi", "time", "local-time"] } socket2 = "0.5" + +[target.'cfg(not(any(target_os = "freebsd", target_os = "openbsd", target_os = "netbsd")))'.dependencies] +quinn = "0.10" \ No newline at end of file diff --git a/iroh-net/bench/src/bin/bulk.rs b/iroh-net/bench/src/bin/bulk.rs index 5c7e956249b..a0c69338769 100644 --- a/iroh-net/bench/src/bin/bulk.rs +++ b/iroh-net/bench/src/bin/bulk.rs @@ -1,7 +1,9 @@ use anyhow::Result; use clap::Parser; -use iroh_net_bench::{configure_tracing_subscriber, iroh, quinn, rt, s2n, Commands, Opt}; +#[cfg(not(any(target_os = "freebsd", target_os = "openbsd", target_os = "netbsd")))] +use iroh_net_bench::quinn; +use iroh_net_bench::{configure_tracing_subscriber, iroh, rt, s2n, Commands, Opt}; fn main() { let cmd = Commands::parse(); @@ -13,6 +15,7 @@ fn main() { eprintln!("failed: {e:#}"); } } + #[cfg(not(any(target_os = "freebsd", target_os = "openbsd", target_os = "netbsd")))] Commands::Quinn(opt) => { if let Err(e) = run_quinn(opt) { eprintln!("failed: {e:#}"); @@ -70,6 +73,7 @@ pub fn run_iroh(opt: Opt) -> Result<()> { Ok(()) } +#[cfg(not(any(target_os = "freebsd", target_os = "openbsd", target_os = "netbsd")))] pub fn run_quinn(opt: Opt) -> Result<()> { let server_span = tracing::error_span!("server"); let runtime = rt(); diff --git a/iroh-net/bench/src/lib.rs b/iroh-net/bench/src/lib.rs index b92665e77ec..cf1ecab6c09 100644 --- a/iroh-net/bench/src/lib.rs +++ b/iroh-net/bench/src/lib.rs @@ -13,6 +13,7 @@ use tokio::sync::Semaphore; use tracing::info; pub mod iroh; +#[cfg(not(any(target_os = "freebsd", target_os = "openbsd", target_os = "netbsd")))] pub mod quinn; pub mod s2n; pub mod stats; @@ -21,6 +22,7 @@ pub mod stats; #[clap(name = "bulk")] pub enum Commands { Iroh(Opt), + #[cfg(not(any(target_os = "freebsd", target_os = "openbsd", target_os = "netbsd")))] Quinn(Opt), S2n(s2n::Opt), } @@ -62,6 +64,7 @@ pub struct Opt { pub enum EndpointSelector { Iroh(iroh_net::Endpoint), + #[cfg(not(any(target_os = "freebsd", target_os = "openbsd", target_os = "netbsd")))] Quinn(::quinn::Endpoint), } @@ -71,6 +74,7 @@ impl EndpointSelector { EndpointSelector::Iroh(endpoint) => { endpoint.close(0u32.into(), b"").await?; } + #[cfg(not(any(target_os = "freebsd", target_os = "openbsd", target_os = "netbsd")))] EndpointSelector::Quinn(endpoint) => { endpoint.close(0u32.into(), b""); } @@ -81,6 +85,7 @@ impl EndpointSelector { pub enum ConnectionSelector { Iroh(iroh_net::endpoint::Connection), + #[cfg(not(any(target_os = "freebsd", target_os = "openbsd", target_os = "netbsd")))] Quinn(::quinn::Connection), } @@ -90,6 +95,7 @@ impl ConnectionSelector { ConnectionSelector::Iroh(connection) => { println!("{:#?}", connection.stats()); } + #[cfg(not(any(target_os = "freebsd", target_os = "openbsd", target_os = "netbsd")))] ConnectionSelector::Quinn(connection) => { println!("{:#?}", connection.stats()); } @@ -101,6 +107,7 @@ impl ConnectionSelector { ConnectionSelector::Iroh(connection) => { connection.close(error_code.into(), reason); } + #[cfg(not(any(target_os = "freebsd", target_os = "openbsd", target_os = "netbsd")))] ConnectionSelector::Quinn(connection) => { connection.close(error_code.into(), reason); } @@ -193,6 +200,11 @@ pub async fn client_handler( iroh::handle_client_stream(connection, opt.upload_size, opt.read_unordered) .await } + #[cfg(not(any( + target_os = "freebsd", + target_os = "openbsd", + target_os = "netbsd" + )))] ConnectionSelector::Quinn(connection) => { quinn::handle_client_stream(connection, opt.upload_size, opt.read_unordered) .await diff --git a/iroh-net/src/net/interfaces/bsd.rs b/iroh-net/src/net/interfaces/bsd.rs index 51c3f677287..dd6ca7e3ca2 100644 --- a/iroh-net/src/net/interfaces/bsd.rs +++ b/iroh-net/src/net/interfaces/bsd.rs @@ -7,13 +7,33 @@ use std::{ net::{IpAddr, Ipv4Addr, Ipv6Addr}, }; +use libc::{c_int, uintptr_t, AF_INET, AF_INET6, AF_LINK, AF_ROUTE, AF_UNSPEC, CTL_NET}; +#[cfg(any(target_os = "macos", target_os = "ios"))] +use libc::{ + NET_RT_DUMP, RTAX_BRD, RTAX_DST, RTAX_GATEWAY, RTAX_MAX, RTAX_NETMASK, RTA_IFP, RTF_GATEWAY, +}; use once_cell::sync::Lazy; use tracing::warn; use super::DefaultRouteDetails; +#[cfg(target_os = "freebsd")] +mod freebsd; +#[cfg(target_os = "freebsd")] +pub(crate) use self::freebsd::*; +#[cfg(target_os = "netbsd")] +mod netbsd; +#[cfg(target_os = "netbsd")] +pub(crate) use self::netbsd::*; +#[cfg(target_os = "openbsd")] +mod openbsd; +#[cfg(target_os = "openbsd")] +pub(crate) use self::openbsd::*; + +#[cfg(any(target_os = "macos", target_os = "ios"))] +mod macos; #[cfg(any(target_os = "macos", target_os = "ios"))] -use macos::*; +use self::macos::*; pub async fn default_route() -> Option { let idx = default_route_interface_index()?; @@ -33,7 +53,7 @@ pub fn likely_home_router() -> Option { continue; } - if let Some(gw) = rm.addrs.get(libc::RTAX_GATEWAY as usize) { + if let Some(gw) = rm.addrs.get(RTAX_GATEWAY as usize) { if let Addr::Inet4 { ip } = gw { return Some(IpAddr::V4(*ip)); } @@ -78,23 +98,24 @@ const V4_DEFAULT: [u8; 4] = [0u8; 4]; const V6_DEFAULT: [u8; 16] = [0u8; 16]; fn is_default_gateway(rm: &RouteMessage) -> bool { - if rm.flags & libc::RTF_GATEWAY as u32 == 0 { + if rm.flags & RTF_GATEWAY as u32 == 0 { return false; } + #[cfg(any(target_os = "macos", target_os = "ios"))] if rm.flags & libc::RTF_IFSCOPE as u32 != 0 { return false; } // Addrs is [RTAX_DST, RTAX_GATEWAY, RTAX_NETMASK, ...] - if rm.addrs.len() <= libc::RTAX_NETMASK as usize { + if rm.addrs.len() <= RTAX_NETMASK as usize { return false; } - let Some(dst) = rm.addrs.get(libc::RTAX_DST as usize) else { + let Some(dst) = rm.addrs.get(RTAX_DST as usize) else { return false; }; - let Some(netmask) = rm.addrs.get(libc::RTAX_NETMASK as usize) else { + let Some(netmask) = rm.addrs.get(RTAX_NETMASK as usize) else { return false; }; @@ -114,9 +135,9 @@ fn is_default_gateway(rm: &RouteMessage) -> bool { false } -#[cfg(any(target_os = "freebsd", target_os = "openbsd", target_os = "netbsd",))] +#[cfg(any(target_os = "freebsd", target_os = "openbsd", target_os = "netbsd"))] fn fetch_routing_table() -> Option> { - match fetch_rib(libc::AF_UNSPEC, libc::NET_RT_DUMP, 0) { + match fetch_rib(AF_UNSPEC, libc::NET_RT_DUMP, 0) { Ok(res) => Some(res), Err(err) => { warn!("fetch_rib failed: {:?}", err); @@ -125,10 +146,19 @@ fn fetch_routing_table() -> Option> { } } -#[cfg(any(target_os = "freebsd", target_os = "openbsd", target_os = "netbsd",))] +#[cfg(any(target_os = "freebsd", target_os = "openbsd", target_os = "netbsd"))] fn parse_routing_table(rib: &[u8]) -> Option> { match parse_rib(libc::NET_RT_IFLIST, rib) { - Ok(res) => Some(res), + Ok(res) => { + let res = res + .into_iter() + .filter_map(|m| match m { + WireMessage::Route(r) => Some(r), + _ => None, + }) + .collect(); + Some(res) + } Err(err) => { warn!("parse_rib failed: {:?}", err); None @@ -178,14 +208,14 @@ const fn is_valid_rib_type(typ: RIBType) -> bool { true } -#[cfg(any(target_os = "free", target_os = "netbsd"))] +#[cfg(any(target_os = "freebsd", target_os = "netbsd"))] const fn is_valid_rib_type(typ: RIBType) -> bool { true } #[cfg(target_os = "openbsd")] -const fn is_valid_rib_type(_typ: RIBType) -> bool { - if typ == libc::NET_RT_STATS || typ == libc::NET_RT_TABLE { +const fn is_valid_rib_type(typ: RIBType) -> bool { + if typ == NET_RT_STATS || typ == NET_RT_TABLE { return false; } true @@ -206,6 +236,7 @@ pub enum WireMessage { Interface(InterfaceMessage), InterfaceAddr(InterfaceAddrMessage), InterfaceMulticastAddr(InterfaceMulticastAddrMessage), + InterfaceAnnounce(InterfaceAnnounceMessage), } /// Safely convert a some bytes from a slice into a u16. @@ -231,14 +262,14 @@ fn u32_from_ne_range( } impl WireFormat { - #[cfg(any( - target_os = "freebsd", - target_os = "netbsd", - target_os = "macos", - target_os = "ios" - ))] fn parse(&self, _typ: RIBType, data: &[u8]) -> Result, RouteError> { match self.typ { + #[cfg(any( + target_os = "freebsd", + target_os = "netbsd", + target_os = "macos", + target_os = "ios" + ))] MessageType::Route => { if data.len() < self.body_off { return Err(RouteError::MessageTooShort); @@ -269,6 +300,44 @@ impl WireFormat { Ok(Some(WireMessage::Route(m))) } + #[cfg(any(target_os = "openbsd",))] + MessageType::Route => { + if data.len() < self.body_off { + return Err(RouteError::MessageTooShort); + } + let l = u16_from_ne_range(data, ..2)?; + if data.len() < l as usize { + return Err(RouteError::InvalidMessage); + } + let ll = u16_from_ne_range(data, 4..6)? as usize; + if data.len() < ll { + return Err(RouteError::InvalidMessage); + } + + let addrs = parse_addrs( + u32_from_ne_range(data, 12..16)? as _, + parse_kernel_inet_addr, + &data[ll..], + )?; + + let mut m = RouteMessage { + version: data[2] as _, + r#type: data[3] as _, + flags: u32_from_ne_range(data, 16..20)?, + index: u16_from_ne_range(data, 6..8)?, + id: u32_from_ne_range(data, 24..28)? as _, + seq: u32_from_ne_range(data, 28..32)?, + ext_off: self.ext_off, + error: None, + addrs, + }; + let errno = u32_from_ne_range(data, 32..36)?; + if errno != 0 { + m.error = Some(std::io::Error::from_raw_os_error(errno as _)); + } + + Ok(Some(WireMessage::Route(m))) + } MessageType::Interface => { if data.len() < self.body_off { return Err(RouteError::MessageTooShort); @@ -279,7 +348,7 @@ impl WireFormat { } let attrs = u32_from_ne_range(data, 4..8)?; - if attrs as libc::c_int & libc::RTA_IFP == 0 { + if attrs as c_int & RTA_IFP == 0 { return Ok(None); } let addr = parse_link_addr(&data[self.body_off..])?; @@ -347,13 +416,37 @@ impl WireFormat { }; Ok(Some(WireMessage::InterfaceMulticastAddr(m))) } - } - } + MessageType::InterfaceAnnounce => { + if data.len() < self.body_off { + return Err(RouteError::MessageTooShort); + } + let l = u16_from_ne_range(data, ..2)?; + if data.len() < l as usize { + return Err(RouteError::InvalidMessage); + } + + let mut name = String::new(); + for i in 0..16 { + if data[6 + i] != 0 { + continue; + } + name = std::str::from_utf8(&data[6..6 + i]) + .map_err(|_| RouteError::InvalidAddress)? + .to_string(); + break; + } - #[cfg(target_os = "openbsd")] - fn parse(&self, typ: RIBType, data: &[u8]) -> Result, RouteError> { - // https://cs.opensource.google/go/x/net/+/master:route/route_openbsd.go - todo!() + let m = InterfaceAnnounceMessage { + version: data[2] as _, + r#type: data[3] as _, + index: u16_from_ne_range(data, 4..6)? as _, + what: u16_from_ne_range(data, 22..24)? as _, + name, + }; + + Ok(Some(WireMessage::InterfaceAnnounce(m))) + } + } } } @@ -363,6 +456,7 @@ enum MessageType { Interface, InterfaceAddr, InterfaceMulticastAddr, + InterfaceAnnounce, } static ROUTING_STACK: Lazy = Lazy::new(probe_routing_stack); @@ -454,7 +548,7 @@ pub struct RouteMessage { /// interface index when attached pub index: u16, /// sender's identifier; usually process ID - pub id: libc::uintptr_t, + pub id: uintptr_t, /// sequence number pub seq: u32, // error on requested operation @@ -515,95 +609,19 @@ pub struct InterfaceMulticastAddrMessage { pub addrs: Vec, } -#[cfg(any(target_os = "macos", target_os = "ios"))] -mod macos { - use super::*; - - // Hardcoded based on the generated values here: https://cs.opensource.google/go/x/net/+/master:route/zsys_darwin.go - - pub(super) const SIZEOF_IF_MSGHDR_DARWIN15: usize = 0x70; - pub(super) const SIZEOF_IFA_MSGHDR_DARWIN15: usize = 0x14; - pub(super) const SIZEOF_IFMA_MSGHDR_DARWIN15: usize = 0x10; - pub(super) const SIZEOF_IF_MSGHDR2_DARWIN15: usize = 0xa0; - pub(super) const SIZEOF_IFMA_MSGHDR2_DARWIN15: usize = 0x14; - pub(super) const SIZEOF_IF_DATA_DARWIN15: usize = 0x60; - pub(super) const SIZEOF_IF_DATA64_DARWIN15: usize = 0x80; - - pub(super) const SIZEOF_RT_MSGHDR_DARWIN15: usize = 0x5c; - pub(super) const SIZEOF_RT_MSGHDR2_DARWIN15: usize = 0x5c; - pub(super) const SIZEOF_RT_METRICS_DARWIN15: usize = 0x38; - - pub(super) const SIZEOF_SOCKADDR_STORAGE: usize = 0x80; - pub(super) const SIZEOF_SOCKADDR_INET: usize = 0x10; - pub(super) const SIZEOF_SOCKADDR_INET6: usize = 0x1c; - - pub(super) fn probe_routing_stack() -> RoutingStack { - let rtm_version = libc::RTM_VERSION; - - let rtm = WireFormat { - ext_off: 36, - body_off: SIZEOF_RT_MSGHDR_DARWIN15, - typ: MessageType::Route, - }; - let rtm2 = WireFormat { - ext_off: 36, - body_off: SIZEOF_RT_MSGHDR2_DARWIN15, - typ: MessageType::Route, - }; - let ifm = WireFormat { - ext_off: 16, - body_off: SIZEOF_IF_MSGHDR_DARWIN15, - typ: MessageType::Interface, - }; - let ifm2 = WireFormat { - ext_off: 32, - body_off: SIZEOF_IF_MSGHDR2_DARWIN15, - typ: MessageType::Interface, - }; - let ifam = WireFormat { - ext_off: SIZEOF_IFA_MSGHDR_DARWIN15, - body_off: SIZEOF_IFA_MSGHDR_DARWIN15, - typ: MessageType::InterfaceAddr, - }; - let ifmam = WireFormat { - ext_off: SIZEOF_IFMA_MSGHDR_DARWIN15, - body_off: SIZEOF_IFMA_MSGHDR_DARWIN15, - typ: MessageType::InterfaceMulticastAddr, - }; - let ifmam2 = WireFormat { - ext_off: SIZEOF_IFMA_MSGHDR2_DARWIN15, - body_off: SIZEOF_IFMA_MSGHDR2_DARWIN15, - typ: MessageType::InterfaceMulticastAddr, - }; - - let wire_formats = [ - (libc::RTM_ADD, rtm), - (libc::RTM_DELETE, rtm), - (libc::RTM_CHANGE, rtm), - (libc::RTM_GET, rtm), - (libc::RTM_LOSING, rtm), - (libc::RTM_REDIRECT, rtm), - (libc::RTM_MISS, rtm), - (libc::RTM_LOCK, rtm), - (libc::RTM_RESOLVE, rtm), - (libc::RTM_NEWADDR, ifam), - (libc::RTM_DELADDR, ifam), - (libc::RTM_IFINFO, ifm), - (libc::RTM_NEWMADDR, ifmam), - (libc::RTM_DELMADDR, ifmam), - (libc::RTM_IFINFO2, ifm2), - (libc::RTM_NEWMADDR2, ifmam2), - (libc::RTM_GET2, rtm2), - ] - .into_iter() - .collect(); - - RoutingStack { - rtm_version, - wire_formats, - kernel_align: 4, - } - } +/// Interface announce message. +#[derive(Debug)] +pub struct InterfaceAnnounceMessage { + /// message version + pub version: isize, + /// message type + pub r#type: isize, + /// interface index + pub index: isize, + /// interface name + pub name: String, + /// what type of announcement + pub what: isize, } /// Represents a type of routing information base. @@ -639,7 +657,7 @@ fn fetch_rib(af: i32, typ: RIBType, arg: i32) -> Result, RouteError> { loop { round += 1; - let mut mib: [i32; 6] = [libc::CTL_NET, libc::AF_ROUTE, 0, af, typ, arg]; + let mut mib: [i32; 6] = [CTL_NET, AF_ROUTE, 0, af, typ, arg]; let mut n: libc::size_t = 0; let err = unsafe { libc::sysctl( @@ -680,6 +698,9 @@ fn fetch_rib(af: i32, typ: RIBType, arg: i32) -> Result, RouteError> { } return Err(RouteError::Io("sysctl", io_err)); } + // Truncate b, to the new length + b.truncate(n); + return Ok(b); } } @@ -711,9 +732,9 @@ pub enum Addr { impl Addr { pub fn family(&self) -> i32 { match self { - Addr::Link { .. } => libc::AF_LINK, - Addr::Inet4 { .. } => libc::AF_INET, - Addr::Inet6 { .. } => libc::AF_INET6, + Addr::Link { .. } => AF_LINK, + Addr::Inet4 { .. } => AF_INET, + Addr::Inet6 { .. } => AF_INET6, Addr::Default { af, .. } => *af, } } @@ -750,11 +771,11 @@ fn parse_addrs(attrs: i32, default_fn: F, data: &[u8]) -> Result, R where F: Fn(i32, &[u8]) -> Result<(i32, Addr), RouteError>, { - let mut addrs = Vec::with_capacity(libc::RTAX_MAX as usize); - let af = libc::AF_UNSPEC; + let mut addrs = Vec::with_capacity(RTAX_MAX as usize); + let af = AF_UNSPEC; let mut b = data; - for i in 0..libc::RTAX_MAX as usize { + for i in 0..RTAX_MAX as usize { if b.len() < roundup(0) { break; } @@ -762,9 +783,9 @@ where if attrs & (1 << i) == 0 { continue; } - if i <= libc::RTAX_BRD as usize { + if i <= RTAX_BRD as usize { match b[1] as i32 { - libc::AF_LINK => { + AF_LINK => { let a = parse_link_addr(b)?; addrs.push(a); let l = roundup(b[0] as usize); @@ -773,7 +794,7 @@ where } b = &b[l..]; } - libc::AF_INET | libc::AF_INET6 => { + AF_INET | AF_INET6 => { let af = b[1] as i32; let a = parse_inet_addr(af, b)?; addrs.push(a); @@ -814,7 +835,7 @@ where /// Parses `b` as an internet address for IPv4 or IPv6. fn parse_inet_addr(af: i32, b: &[u8]) -> Result { match af { - libc::AF_INET => { + AF_INET => { if b.len() < SIZEOF_SOCKADDR_INET { return Err(RouteError::InvalidAddress); } @@ -822,7 +843,7 @@ fn parse_inet_addr(af: i32, b: &[u8]) -> Result { let ip = Ipv4Addr::new(b[4], b[5], b[6], b[7]); Ok(Addr::Inet4 { ip }) } - libc::AF_INET6 => { + AF_INET6 => { if b.len() < SIZEOF_SOCKADDR_INET6 { return Err(RouteError::InvalidAddress); } @@ -910,7 +931,7 @@ fn parse_kernel_inet_addr(af: i32, b: &[u8]) -> Result<(i32, Addr), RouteError> .ok_or(RouteError::InvalidMessage)?; let ip = Ipv6Addr::from(octets); Addr::Inet6 { ip, zone: 0 } - } else if af == libc::AF_INET6 { + } else if af == AF_INET6 { let mut octets = [0u8; 16]; if l - 1 < OFF6 { octets[..l - 1].copy_from_slice(&b[1..l]); @@ -945,7 +966,7 @@ fn parse_link_addr(b: &[u8]) -> Result { if b.len() < 8 { return Err(RouteError::InvalidAddress); } - let (_, mut a) = parse_kernel_link_addr(libc::AF_LINK, &b[4..])?; + let (_, mut a) = parse_kernel_link_addr(AF_LINK, &b[4..])?; if let Addr::Link { index, .. } = &mut a { *index = u16_from_ne_range(b, 2..4)? as _; @@ -1051,9 +1072,12 @@ mod tests { #[test] #[cfg(target_endian = "little")] fn test_parse_addrs() { + #[cfg(any(target_os = "macos", target_os = "ios"))] + use libc::{RTA_BRD, RTA_DST, RTA_GATEWAY, RTA_IFA, RTA_IFP, RTA_NETMASK}; + let parse_addrs_little_endian_tests = [ ParseAddrsTest { - attrs: libc::RTA_DST | libc::RTA_GATEWAY | libc::RTA_NETMASK | libc::RTA_BRD, + attrs: RTA_DST | RTA_GATEWAY | RTA_NETMASK | RTA_BRD, parse_fn: Box::new(parse_kernel_inet_addr), b: vec![ 0x38, 0x12, 0x0, 0x0, 0xff, 0xff, 0xff, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, @@ -1091,7 +1115,7 @@ mod tests { ], }, ParseAddrsTest { - attrs: libc::RTA_NETMASK | libc::RTA_IFP | libc::RTA_IFA, + attrs: RTA_NETMASK | RTA_IFP | RTA_IFA, parse_fn: Box::new(parse_kernel_inet_addr), b: vec![ 0x7, 0x0, 0x0, 0x0, 0xff, 0xff, 0xff, 0x0, 0x18, 0x12, 0xa, 0x0, 0x87, 0x8, diff --git a/iroh-net/src/net/interfaces/bsd/freebsd.rs b/iroh-net/src/net/interfaces/bsd/freebsd.rs new file mode 100644 index 00000000000..b5efc288dce --- /dev/null +++ b/iroh-net/src/net/interfaces/bsd/freebsd.rs @@ -0,0 +1,326 @@ +use super::{MessageType, RoutingStack, WireFormat}; + +use libc::c_int; + +// Missing constants from libc. +// https://github.com/rust-lang/libc/issues/3711 + +// net/route.h +pub const RTF_GATEWAY: c_int = 0x2; +pub const RTAX_DST: c_int = 0; +pub const RTAX_GATEWAY: c_int = 1; +pub const RTAX_NETMASK: c_int = 2; +pub const RTAX_IFP: c_int = 4; +pub const RTAX_BRD: c_int = 7; +pub const RTAX_MAX: c_int = 8; +pub const RTM_VERSION: c_int = 5; +pub const RTA_DST: c_int = 0x1; +pub const RTA_GATEWAY: c_int = 0x2; +pub const RTA_NETMASK: c_int = 0x4; +pub const RTA_GENMASK: c_int = 0x8; +pub const RTA_IFP: c_int = 0x10; +pub const RTA_IFA: c_int = 0x20; +pub const RTA_AUTHOR: c_int = 0x40; +pub const RTA_BRD: c_int = 0x80; + +// Message types +pub const RTM_ADD: c_int = 0x1; +pub const RTM_DELETE: c_int = 0x2; +pub const RTM_CHANGE: c_int = 0x3; +pub const RTM_GET: c_int = 0x4; +pub const RTM_LOSING: c_int = 0x5; +pub const RTM_REDIRECT: c_int = 0x6; +pub const RTM_MISS: c_int = 0x7; +pub const RTM_LOCK: c_int = 0x8; +pub const RTM_OLDADD: c_int = 0x9; +pub const RTM_OLDDEL: c_int = 0xa; +pub const RTM_RESOLVE: c_int = 0xb; +pub const RTM_NEWADDR: c_int = 0xc; +pub const RTM_DELADDR: c_int = 0xd; +pub const RTM_IFINFO: c_int = 0xe; +pub const RTM_NEWMADDR: c_int = 0xf; +pub const RTM_DELMADDR: c_int = 0x10; +pub const RTM_IFANNOUNCE: c_int = 0x11; +pub const RTM_IEEE80211: c_int = 0x12; + +// Hardcoded based on the generated values here: https://cs.opensource.google/go/x/net/+/master:route/zsys_freebsd_amd64.go +#[cfg(target_arch = "x86_64")] +pub use self::amd64::*; +#[cfg(target_arch = "x86_64")] +mod amd64 { + pub const SIZEOF_IF_MSGHDRL_FREE_BSD10: usize = 0xb0; + pub const SIZEOF_IFA_MSGHDR_FREE_BSD10: usize = 0x14; + pub const SIZEOF_IFA_MSGHDRL_FREE_BSD10: usize = 0xb0; + pub const SIZEOF_IFMA_MSGHDR_FREE_BSD10: usize = 0x10; + pub const SIZEOF_IF_ANNOUNCEMSGHDR_FREE_BSD10: usize = 0x18; + + pub const SIZEOF_RT_MSGHDR_FREE_BSD10: usize = 0x98; + pub const SIZEOF_RT_METRICS_FREE_BSD10: usize = 0x70; + + pub const SIZEOF_IF_MSGHDR_FREE_BSD7: usize = 0xa8; + pub const SIZEOF_IF_MSGHDR_FREE_BSD8: usize = 0xa8; + pub const SIZEOF_IF_MSGHDR_FREE_BSD9: usize = 0xa8; + pub const SIZEOF_IF_MSGHDR_FREE_BSD10: usize = 0xa8; + pub const SIZEOF_IF_MSGHDR_FREE_BSD11: usize = 0xa8; + + pub const SIZEOF_IF_DATA_FREE_BSD7: usize = 0x98; + pub const SIZEOF_IF_DATA_FREE_BSD8: usize = 0x98; + pub const SIZEOF_IF_DATA_FREE_BSD9: usize = 0x98; + pub const SIZEOF_IF_DATA_FREE_BSD10: usize = 0x98; + pub const SIZEOF_IF_DATA_FREE_BSD11: usize = 0x98; + + pub const SIZEOF_IF_MSGHDRL_FREE_BSD10_EMU: usize = 0xb0; + pub const SIZEOF_IFA_MSGHDR_FREE_BSD10_EMU: usize = 0x14; + pub const SIZEOF_IFA_MSGHDRL_FREE_BSD10_EMU: usize = 0xb0; + pub const SIZEOF_IFMA_MSGHDR_FREE_BSD10_EMU: usize = 0x10; + pub const SIZEOF_IF_ANNOUNCEMSGHDR_FREE_BSD10_EMU: usize = 0x18; + + pub const SIZEOF_RT_MSGHDR_FREE_BSD10_EMU: usize = 0x98; + pub const SIZEOF_RT_METRICS_FREE_BSD10_EMU: usize = 0x70; + + pub const SIZEOF_IF_MSGHDR_FREE_BSD7_EMU: usize = 0xa8; + pub const SIZEOF_IF_MSGHDR_FREE_BSD8_EMU: usize = 0xa8; + pub const SIZEOF_IF_MSGHDR_FREE_BSD9_EMU: usize = 0xa8; + pub const SIZEOF_IF_MSGHDR_FREE_BSD10_EMU: usize = 0xa8; + pub const SIZEOF_IF_MSGHDR_FREE_BSD11_EMU: usize = 0xa8; + + pub const SIZEOF_IF_DATA_FREE_BSD7_EMU: usize = 0x98; + pub const SIZEOF_IF_DATA_FREE_BSD8_EMU: usize = 0x98; + pub const SIZEOF_IF_DATA_FREE_BSD9_EMU: usize = 0x98; + pub const SIZEOF_IF_DATA_FREE_BSD10_EMU: usize = 0x98; + pub const SIZEOF_IF_DATA_FREE_BSD11_EMU: usize = 0x98; + + pub const SIZEOF_SOCKADDR_STORAGE: usize = 0x80; + pub const SIZEOF_SOCKADDR_INET: usize = 0x10; + pub const SIZEOF_SOCKADDR_INET6: usize = 0x1c; +} + +// Hardcoded based on the generated values here: https://cs.opensource.google/go/x/net/+/master:route/zsys_freebsd_386.go +#[cfg(target_arch = "x86")] +pub use self::i686::*; +#[cfg(target_arch = "x86")] +mod i686 { + pub const SIZEOF_IF_MSGHDRL_FREE_BSD10: usize = 0x68; + pub const SIZEOF_IFA_MSGHDR_FREE_BSD10: usize = 0x14; + pub const SIZEOF_IFA_MSGHDRL_FREE_BSD10: usize = 0x6c; + pub const SIZEOF_IFMA_MSGHDR_FREE_BSD10: usize = 0x10; + pub const SIZEOF_IF_ANNOUNCEMSGHDR_FREE_BSD10: usize = 0x18; + + pub const SIZEOF_RT_MSGHDR_FREE_BSD10: usize = 0x5c; + pub const SIZEOF_RT_METRICS_FREE_BSD10: usize = 0x38; + + pub const SIZEOF_IF_MSGHDR_FREE_BSD7: usize = 0x60; + pub const SIZEOF_IF_MSGHDR_FREE_BSD8: usize = 0x60; + pub const SIZEOF_IF_MSGHDR_FREE_BSD9: usize = 0x60; + pub const SIZEOF_IF_MSGHDR_FREE_BSD10: usize = 0x64; + pub const SIZEOF_IF_MSGHDR_FREE_BSD11: usize = 0xa8; + + pub const SIZEOF_IF_DATA_FREE_BSD7: usize = 0x50; + pub const SIZEOF_IF_DATA_FREE_BSD8: usize = 0x50; + pub const SIZEOF_IF_DATA_FREE_BSD9: usize = 0x50; + pub const SIZEOF_IF_DATA_FREE_BSD10: usize = 0x54; + pub const SIZEOF_IF_DATA_FREE_BSD11: usize = 0x98; + + // MODIFIED BY HAND FOR 386 EMULATION ON AMD64 + // 386 EMULATION USES THE UNDERLYING RAW DATA LAYOUT + + pub const SIZEOF_IF_MSGHDRL_FREE_BSD10_EMU: usize = 0xb0; + pub const SIZEOF_IFA_MSGHDR_FREE_BSD10_EMU: usize = 0x14; + pub const SIZEOF_IFA_MSGHDRL_FREE_BSD10_EMU: usize = 0xb0; + pub const SIZEOF_IFMA_MSGHDR_FREE_BSD10_EMU: usize = 0x10; + pub const SIZEOF_IF_ANNOUNCEMSGHDR_FREE_BSD10_EMU: usize = 0x18; + + pub const SIZEOF_RT_MSGHDR_FREE_BSD10_EMU: usize = 0x98; + pub const SIZEOF_RT_METRICS_FREE_BSD10_EMU: usize = 0x70; + + pub const SIZEOF_IF_MSGHDR_FREE_BSD7_EMU: usize = 0xa8; + pub const SIZEOF_IF_MSGHDR_FREE_BSD8_EMU: usize = 0xa8; + pub const SIZEOF_IF_MSGHDR_FREE_BSD9_EMU: usize = 0xa8; + pub const SIZEOF_IF_MSGHDR_FREE_BSD10_EMU: usize = 0xa8; + pub const SIZEOF_IF_MSGHDR_FREE_BSD11_EMU: usize = 0xa8; + + pub const SIZEOF_IF_DATA_FREE_BSD7_EMU: usize = 0x98; + pub const SIZEOF_IF_DATA_FREE_BSD8_EMU: usize = 0x98; + pub const SIZEOF_IF_DATA_FREE_BSD9_EMU: usize = 0x98; + pub const SIZEOF_IF_DATA_FREE_BSD10_EMU: usize = 0x98; + pub const SIZEOF_IF_DATA_FREE_BSD11_EMU: usize = 0x98; + + pub const SIZEOF_SOCKADDR_STORAGE: usize = 0x80; + pub const SIZEOF_SOCKADDR_INET: usize = 0x10; + pub const SIZEOF_SOCKADDR_INET6: usize = 0x1c; +} + +// Hardcoded based on the generated values here: https://cs.opensource.google/go/x/net/+/master:route/zsys_freebsd_arm.go +#[cfg(target_arch = "arm")] +pub use self::arm::*; +#[cfg(target_arch = "arm")] +mod arm { + pub const SIZEOF_IF_MSGHDRL_FREE_BSD10: usize = 0x68; + pub const SIZEOF_IFA_MSGHDR_FREE_BSD10: usize = 0x14; + pub const SIZEOF_IFA_MSGHDRL_FREE_BSD10: usize = 0x6c; + pub const SIZEOF_IFMA_MSGHDR_FREE_BSD10: usize = 0x10; + pub const SIZEOF_IF_ANNOUNCEMSGHDR_FREE_BSD10: usize = 0x18; + + pub const SIZEOF_RT_MSGHDR_FREE_BSD10: usize = 0x5c; + pub const SIZEOF_RT_METRICS_FREE_BSD10: usize = 0x38; + + pub const SIZEOF_IF_MSGHDR_FREE_BSD7: usize = 0x70; + pub const SIZEOF_IF_MSGHDR_FREE_BSD8: usize = 0x70; + pub const SIZEOF_IF_MSGHDR_FREE_BSD9: usize = 0x70; + pub const SIZEOF_IF_MSGHDR_FREE_BSD10: usize = 0x70; + pub const SIZEOF_IF_MSGHDR_FREE_BSD11: usize = 0xa8; + + pub const SIZEOF_IF_DATA_FREE_BSD7: usize = 0x60; + pub const SIZEOF_IF_DATA_FREE_BSD8: usize = 0x60; + pub const SIZEOF_IF_DATA_FREE_BSD9: usize = 0x60; + pub const SIZEOF_IF_DATA_FREE_BSD10: usize = 0x60; + pub const SIZEOF_IF_DATA_FREE_BSD11: usize = 0x98; + + pub const SIZEOF_IF_MSGHDRL_FREE_BSD10_EMU: usize = 0x68; + pub const SIZEOF_IFA_MSGHDR_FREE_BSD10_EMU: usize = 0x14; + pub const SIZEOF_IFA_MSGHDRL_FREE_BSD10_EMU: usize = 0x6c; + pub const SIZEOF_IFMA_MSGHDR_FREE_BSD10_EMU: usize = 0x10; + pub const SIZEOF_IF_ANNOUNCEMSGHDR_FREE_BSD10_EMU: usize = 0x18; + + pub const SIZEOF_RT_MSGHDR_FREE_BSD10_EMU: usize = 0x5c; + pub const SIZEOF_RT_METRICS_FREE_BSD10_EMU: usize = 0x38; + + pub const SIZEOF_IF_MSGHDR_FREE_BSD7_EMU: usize = 0x70; + pub const SIZEOF_IF_MSGHDR_FREE_BSD8_EMU: usize = 0x70; + pub const SIZEOF_IF_MSGHDR_FREE_BSD9_EMU: usize = 0x70; + pub const SIZEOF_IF_MSGHDR_FREE_BSD10_EMU: usize = 0x70; + pub const SIZEOF_IF_MSGHDR_FREE_BSD11_EMU: usize = 0xa8; + + pub const SIZEOF_IF_DATA_FREE_BSD7_EMU: usize = 0x60; + pub const SIZEOF_IF_DATA_FREE_BSD8_EMU: usize = 0x60; + pub const SIZEOF_IF_DATA_FREE_BSD9_EMU: usize = 0x60; + pub const SIZEOF_IF_DATA_FREE_BSD10_EMU: usize = 0x60; + pub const SIZEOF_IF_DATA_FREE_BSD11_EMU: usize = 0x98; + + pub const SIZEOF_SOCKADDR_STORAGE: usize = 0x80; + pub const SIZEOF_SOCKADDR_INET: usize = 0x10; + pub const SIZEOF_SOCKADDR_INET6: usize = 0x1c; +} + +// Hardcoded based on the generated values here: https://cs.opensource.google/go/x/net/+/master:route/zsys_freebsd_arm.go +#[cfg(target_arch = "aarch64")] +pub use self::arm64::*; +#[cfg(target_arch = "aarch64")] +mod arm64 { + pub const SIZEOF_IF_MSGHDRL_FREE_BSD10: usize = 0xb0; + pub const SIZEOF_IFA_MSGHDR_FREE_BSD10: usize = 0x14; + pub const SIZEOF_IFA_MSGHDRL_FREE_BSD10: usize = 0xb0; + pub const SIZEOF_IFMA_MSGHDR_FREE_BSD10: usize = 0x10; + pub const SIZEOF_IF_ANNOUNCEMSGHDR_FREE_BSD10: usize = 0x18; + + pub const SIZEOF_RT_MSGHDR_FREE_BSD10: usize = 0x98; + pub const SIZEOF_RT_METRICS_FREE_BSD10: usize = 0x70; + + pub const SIZEOF_IF_MSGHDR_FREE_BSD7: usize = 0xa8; + pub const SIZEOF_IF_MSGHDR_FREE_BSD8: usize = 0xa8; + pub const SIZEOF_IF_MSGHDR_FREE_BSD9: usize = 0xa8; + pub const SIZEOF_IF_MSGHDR_FREE_BSD10: usize = 0xa8; + pub const SIZEOF_IF_MSGHDR_FREE_BSD11: usize = 0xa8; + + pub const SIZEOF_IF_DATA_FREE_BSD7: usize = 0x98; + pub const SIZEOF_IF_DATA_FREE_BSD8: usize = 0x98; + pub const SIZEOF_IF_DATA_FREE_BSD9: usize = 0x98; + pub const SIZEOF_IF_DATA_FREE_BSD10: usize = 0x98; + pub const SIZEOF_IF_DATA_FREE_BSD11: usize = 0x98; + + pub const SIZEOF_IF_MSGHDRL_FREE_BSD10_EMU: usize = 0xb0; + pub const SIZEOF_IFA_MSGHDR_FREE_BSD10_EMU: usize = 0x14; + pub const SIZEOF_IFA_MSGHDRL_FREE_BSD10_EMU: usize = 0xb0; + pub const SIZEOF_IFMA_MSGHDR_FREE_BSD10_EMU: usize = 0x10; + pub const SIZEOF_IF_ANNOUNCEMSGHDR_FREE_BSD10_EMU: usize = 0x18; + + pub const SIZEOF_RT_MSGHDR_FREE_BSD10_EMU: usize = 0x98; + pub const SIZEOF_RT_METRICS_FREE_BSD10_EMU: usize = 0x70; + + pub const SIZEOF_IF_MSGHDR_FREE_BSD7_EMU: usize = 0xa8; + pub const SIZEOF_IF_MSGHDR_FREE_BSD8_EMU: usize = 0xa8; + pub const SIZEOF_IF_MSGHDR_FREE_BSD9_EMU: usize = 0xa8; + pub const SIZEOF_IF_MSGHDR_FREE_BSD10_EMU: usize = 0xa8; + pub const SIZEOF_IF_MSGHDR_FREE_BSD11_EMU: usize = 0xa8; + + pub const SIZEOF_IF_DATA_FREE_BSD7_EMU: usize = 0x98; + pub const SIZEOF_IF_DATA_FREE_BSD8_EMU: usize = 0x98; + pub const SIZEOF_IF_DATA_FREE_BSD9_EMU: usize = 0x98; + pub const SIZEOF_IF_DATA_FREE_BSD10_EMU: usize = 0x98; + pub const SIZEOF_IF_DATA_FREE_BSD11_EMU: usize = 0x98; + + pub const SIZEOF_SOCKADDR_STORAGE: usize = 0x80; + pub const SIZEOF_SOCKADDR_INET: usize = 0x10; + pub const SIZEOF_SOCKADDR_INET6: usize = 0x1c; +} + +/// 386 emulation on amd64 +fn detect_compat_freebsd32() -> bool { + // TODO: implement detection when someone actually needs it + false +} + +pub(super) fn probe_routing_stack() -> RoutingStack { + let rtm_version = RTM_VERSION; + + // Currently only BSD11 support is implemented. + // At the time of this writing rust supports 10 and 11, if this is a problem + // please file an issue. + + let (rtm, ifm, ifam, ifmam, ifanm) = if detect_compat_freebsd32() { + unimplemented!() + } else { + let rtm = WireFormat { + ext_off: SIZEOF_RT_MSGHDR_FREE_BSD10 - SIZEOF_RT_METRICS_FREE_BSD10, + body_off: SIZEOF_RT_MSGHDR_FREE_BSD10, + typ: MessageType::Route, + }; + let ifm = WireFormat { + ext_off: 16, + body_off: SIZEOF_IF_MSGHDR_FREE_BSD11, + typ: MessageType::Interface, + }; + let ifam = WireFormat { + ext_off: SIZEOF_IFA_MSGHDR_FREE_BSD10, + body_off: SIZEOF_IFA_MSGHDR_FREE_BSD10, + typ: MessageType::InterfaceAddr, + }; + let ifmam = WireFormat { + ext_off: SIZEOF_IFMA_MSGHDR_FREE_BSD10, + body_off: SIZEOF_IFMA_MSGHDR_FREE_BSD10, + typ: MessageType::InterfaceMulticastAddr, + }; + let ifanm = WireFormat { + ext_off: SIZEOF_IF_ANNOUNCEMSGHDR_FREE_BSD10, + body_off: SIZEOF_IF_ANNOUNCEMSGHDR_FREE_BSD10, + typ: MessageType::InterfaceAnnounce, + }; + (rtm, ifm, ifam, ifmam, ifanm) + }; + + let wire_formats = [ + (RTM_ADD, rtm), + (RTM_DELETE, rtm), + (RTM_CHANGE, rtm), + (RTM_GET, rtm), + (RTM_LOSING, rtm), + (RTM_REDIRECT, rtm), + (RTM_MISS, rtm), + (RTM_LOCK, rtm), + (RTM_RESOLVE, rtm), + (RTM_NEWADDR, ifam), + (RTM_DELADDR, ifam), + (RTM_IFINFO, ifm), + (RTM_NEWMADDR, ifmam), + (RTM_DELMADDR, ifmam), + (RTM_IFANNOUNCE, ifanm), + (RTM_IEEE80211, ifanm), + ] + .into_iter() + .collect(); + RoutingStack { + rtm_version, + wire_formats, + kernel_align: 4, + } +} diff --git a/iroh-net/src/net/interfaces/bsd/macos.rs b/iroh-net/src/net/interfaces/bsd/macos.rs new file mode 100644 index 00000000000..5c29ff943a1 --- /dev/null +++ b/iroh-net/src/net/interfaces/bsd/macos.rs @@ -0,0 +1,86 @@ +use super::{MessageType, RoutingStack, WireFormat}; + +// Hardcoded based on the generated values here: https://cs.opensource.google/go/x/net/+/master:route/zsys_darwin.go +const SIZEOF_IF_MSGHDR_DARWIN15: usize = 0x70; +const SIZEOF_IFA_MSGHDR_DARWIN15: usize = 0x14; +const SIZEOF_IFMA_MSGHDR_DARWIN15: usize = 0x10; +const SIZEOF_IF_MSGHDR2_DARWIN15: usize = 0xa0; +const SIZEOF_IFMA_MSGHDR2_DARWIN15: usize = 0x14; +const SIZEOF_IF_DATA_DARWIN15: usize = 0x60; +const SIZEOF_IF_DATA64_DARWIN15: usize = 0x80; + +const SIZEOF_RT_MSGHDR_DARWIN15: usize = 0x5c; +const SIZEOF_RT_MSGHDR2_DARWIN15: usize = 0x5c; +const SIZEOF_RT_METRICS_DARWIN15: usize = 0x38; + +const SIZEOF_SOCKADDR_STORAGE: usize = 0x80; +pub(super) const SIZEOF_SOCKADDR_INET: usize = 0x10; +pub(super) const SIZEOF_SOCKADDR_INET6: usize = 0x1c; + +pub(super) fn probe_routing_stack() -> RoutingStack { + let rtm_version = libc::RTM_VERSION; + + let rtm = WireFormat { + ext_off: 36, + body_off: SIZEOF_RT_MSGHDR_DARWIN15, + typ: MessageType::Route, + }; + let rtm2 = WireFormat { + ext_off: 36, + body_off: SIZEOF_RT_MSGHDR2_DARWIN15, + typ: MessageType::Route, + }; + let ifm = WireFormat { + ext_off: 16, + body_off: SIZEOF_IF_MSGHDR_DARWIN15, + typ: MessageType::Interface, + }; + let ifm2 = WireFormat { + ext_off: 32, + body_off: SIZEOF_IF_MSGHDR2_DARWIN15, + typ: MessageType::Interface, + }; + let ifam = WireFormat { + ext_off: SIZEOF_IFA_MSGHDR_DARWIN15, + body_off: SIZEOF_IFA_MSGHDR_DARWIN15, + typ: MessageType::InterfaceAddr, + }; + let ifmam = WireFormat { + ext_off: SIZEOF_IFMA_MSGHDR_DARWIN15, + body_off: SIZEOF_IFMA_MSGHDR_DARWIN15, + typ: MessageType::InterfaceMulticastAddr, + }; + let ifmam2 = WireFormat { + ext_off: SIZEOF_IFMA_MSGHDR2_DARWIN15, + body_off: SIZEOF_IFMA_MSGHDR2_DARWIN15, + typ: MessageType::InterfaceMulticastAddr, + }; + + let wire_formats = [ + (libc::RTM_ADD, rtm), + (libc::RTM_DELETE, rtm), + (libc::RTM_CHANGE, rtm), + (libc::RTM_GET, rtm), + (libc::RTM_LOSING, rtm), + (libc::RTM_REDIRECT, rtm), + (libc::RTM_MISS, rtm), + (libc::RTM_LOCK, rtm), + (libc::RTM_RESOLVE, rtm), + (libc::RTM_NEWADDR, ifam), + (libc::RTM_DELADDR, ifam), + (libc::RTM_IFINFO, ifm), + (libc::RTM_NEWMADDR, ifmam), + (libc::RTM_DELMADDR, ifmam), + (libc::RTM_IFINFO2, ifm2), + (libc::RTM_NEWMADDR2, ifmam2), + (libc::RTM_GET2, rtm2), + ] + .into_iter() + .collect(); + + RoutingStack { + rtm_version, + wire_formats, + kernel_align: 4, + } +} diff --git a/iroh-net/src/net/interfaces/bsd/netbsd.rs b/iroh-net/src/net/interfaces/bsd/netbsd.rs new file mode 100644 index 00000000000..f3a286cb84c --- /dev/null +++ b/iroh-net/src/net/interfaces/bsd/netbsd.rs @@ -0,0 +1,115 @@ +use super::{MessageType, RoutingStack, WireFormat}; + +use libc::c_int; + +// Missing constants from libc. +// https://github.com/rust-lang/libc/issues/3711 + +// net/route.h +pub const RTF_GATEWAY: c_int = 0x2; +pub const RTAX_DST: c_int = 0; +pub const RTAX_GATEWAY: c_int = 1; +pub const RTAX_NETMASK: c_int = 2; +pub const RTAX_IFP: c_int = 4; +pub const RTAX_BRD: c_int = 7; +pub const RTAX_MAX: c_int = 9; +pub const RTM_VERSION: c_int = 4; +pub const RTA_DST: c_int = 0x1; +pub const RTA_GATEWAY: c_int = 0x2; +pub const RTA_NETMASK: c_int = 0x4; +pub const RTA_GENMASK: c_int = 0x8; +pub const RTA_IFP: c_int = 0x10; +pub const RTA_IFA: c_int = 0x20; +pub const RTA_AUTHOR: c_int = 0x40; +pub const RTA_BRD: c_int = 0x80; + +// Message types +pub const RTM_ADD: c_int = 0x1; +pub const RTM_DELETE: c_int = 0x2; +pub const RTM_CHANGE: c_int = 0x3; +pub const RTM_GET: c_int = 0x4; +pub const RTM_LOSING: c_int = 0x5; +pub const RTM_REDIRECT: c_int = 0x6; +pub const RTM_MISS: c_int = 0x7; +pub const RTM_LOCK: c_int = 0x8; +pub const RTM_OLDADD: c_int = 0x9; +pub const RTM_OLDDEL: c_int = 0xa; +// pub const RTM_RESOLVE: c_int = 0xb; +pub const RTM_ONEWADDR: c_int = 0xc; +pub const RTM_ODELADDR: c_int = 0xd; +pub const RTM_OOIFINFO: c_int = 0xe; +pub const RTM_OIFINFO: c_int = 0xf; +pub const RTM_NEWMADDR: c_int = 0xf; +pub const RTM_IFANNOUNCE: c_int = 0x10; +pub const RTM_IEEE80211: c_int = 0x11; +pub const RTM_SETGATE: c_int = 0x12; + +pub const RTM_LLINFO_UPD: c_int = 0x13; + +pub const RTM_IFINFO: c_int = 0x14; +pub const RTM_OCHGADDR: c_int = 0x15; +pub const RTM_NEWADDR: c_int = 0x16; +pub const RTM_DELADDR: c_int = 0x17; +pub const RTM_CHGADDR: c_int = 0x18; + +// Hardcoded based on the generated values here: https://cs.opensource.google/go/x/net/+/master:route/zsys_netbsd.go + +pub(super) const SIZEOF_IF_MSGHDR_NET_BSD7: usize = 0x98; +pub(super) const SIZEOF_IFA_MSGHDR_NET_BSD7: usize = 0x18; +pub(super) const SIZEOF_IF_ANNOUNCEMSGHDR_NET_BSD7: usize = 0x18; + +pub(super) const SIZEOF_RT_MSGHDR_NET_BSD7: usize = 0x78; +pub(super) const SIZEOF_RT_METRICS_NET_BSD7: usize = 0x50; + +pub(super) const SIZEOF_SOCKADDR_STORAGE: usize = 0x80; +pub(super) const SIZEOF_SOCKADDR_INET: usize = 0x10; +pub(super) const SIZEOF_SOCKADDR_INET6: usize = 0x1c; + +pub(super) fn probe_routing_stack() -> RoutingStack { + let rtm_version = RTM_VERSION; + + let rtm = WireFormat { + ext_off: 40, + body_off: SIZEOF_RT_MSGHDR_NET_BSD7, + typ: MessageType::Route, + }; + let ifm = WireFormat { + ext_off: 16, + body_off: SIZEOF_IF_MSGHDR_NET_BSD7, + typ: MessageType::Interface, + }; + let ifam = WireFormat { + ext_off: SIZEOF_IFA_MSGHDR_NET_BSD7, + body_off: SIZEOF_IFA_MSGHDR_NET_BSD7, + typ: MessageType::InterfaceAddr, + }; + let ifannm = WireFormat { + ext_off: SIZEOF_IF_ANNOUNCEMSGHDR_NET_BSD7, + body_off: SIZEOF_IF_ANNOUNCEMSGHDR_NET_BSD7, + typ: MessageType::InterfaceAnnounce, + }; + + let wire_formats = [ + (RTM_ADD, rtm), + (RTM_DELETE, rtm), + (RTM_CHANGE, rtm), + (RTM_GET, rtm), + (RTM_LOSING, rtm), + (RTM_REDIRECT, rtm), + (RTM_MISS, rtm), + (RTM_LOCK, rtm), + (RTM_NEWADDR, ifam), + (RTM_DELADDR, ifam), + (RTM_IFANNOUNCE, ifannm), + (RTM_IFINFO, ifm), + ] + .into_iter() + .collect(); + + // NetBSD 6 and above kernels require 64-bit aligned access to routing facilities. + RoutingStack { + rtm_version, + wire_formats, + kernel_align: 8, + } +} diff --git a/iroh-net/src/net/interfaces/bsd/openbsd.rs b/iroh-net/src/net/interfaces/bsd/openbsd.rs new file mode 100644 index 00000000000..2e9faf8df5a --- /dev/null +++ b/iroh-net/src/net/interfaces/bsd/openbsd.rs @@ -0,0 +1,105 @@ +use super::{MessageType, RoutingStack, WireFormat}; + +use libc::c_int; + +// Missing constants from libc. +// https://github.com/rust-lang/libc/issues/3711 + +// net/route.h +pub const RTF_GATEWAY: c_int = 0x2; +pub const RTAX_DST: c_int = 0; +pub const RTAX_GATEWAY: c_int = 1; +pub const RTAX_NETMASK: c_int = 2; +pub const RTAX_IFP: c_int = 4; +pub const RTAX_BRD: c_int = 7; +pub const RTAX_MAX: c_int = 15; +pub const RTM_VERSION: c_int = 5; +pub const RTA_DST: c_int = 0x1; +pub const RTA_GATEWAY: c_int = 0x2; +pub const RTA_NETMASK: c_int = 0x4; +pub const RTA_GENMASK: c_int = 0x8; +pub const RTA_IFP: c_int = 0x10; +pub const RTA_IFA: c_int = 0x20; +pub const RTA_AUTHOR: c_int = 0x40; +pub const RTA_BRD: c_int = 0x80; + +// Message types +pub const RTM_ADD: c_int = 0x1; +pub const RTM_DELETE: c_int = 0x2; +pub const RTM_CHANGE: c_int = 0x3; +pub const RTM_GET: c_int = 0x4; +pub const RTM_LOSING: c_int = 0x5; +pub const RTM_REDIRECT: c_int = 0x6; +pub const RTM_MISS: c_int = 0x7; +pub const RTM_RESOLVE: c_int = 0xb; +pub const RTM_NEWADDR: c_int = 0xc; +pub const RTM_DELADDR: c_int = 0xd; +pub const RTM_IFINFO: c_int = 0xe; +pub const RTM_IFANNOUNCE: c_int = 0xf; +pub const RTM_DESYNC: c_int = 0x10; +pub const RTM_INVALIDATE: c_int = 0x11; +pub const RTM_BFD: c_int = 0x12; +pub const RTM_PROPOSAL: c_int = 0x13; +pub const RTM_CHGADDRATTR: c_int = 0x14; +pub const RTM_80211INFO: c_int = 0x15; +pub const RTM_SOURCE: c_int = 0x16; + +// socket.h +pub const NET_RT_STATS: c_int = 5; +pub const NET_RT_TABLE: c_int = 5; + +pub const SIZEOF_SOCKADDR_STORAGE: usize = 0x80; +pub const SIZEOF_SOCKADDR_INET: usize = 0x10; +pub const SIZEOF_SOCKADDR_INET6: usize = 0x1c; + +// Hardcoded based on the generated values here: https://cs.opensource.google/go/x/net/+/master:route/sys_openbsd.go + +pub(super) fn probe_routing_stack() -> RoutingStack { + let rtm_version = RTM_VERSION; + + let rtm = WireFormat { + ext_off: 0, + body_off: 0, + typ: MessageType::Route, + }; + let ifm = WireFormat { + ext_off: 0, + body_off: 0, + typ: MessageType::Interface, + }; + let ifam = WireFormat { + ext_off: 0, + body_off: 0, + typ: MessageType::InterfaceAddr, + }; + let ifannm = WireFormat { + ext_off: 0, + body_off: 0, + typ: MessageType::InterfaceAnnounce, + }; + + let wire_formats = [ + (RTM_ADD, rtm), + (RTM_DELETE, rtm), + (RTM_CHANGE, rtm), + (RTM_GET, rtm), + (RTM_LOSING, rtm), + (RTM_REDIRECT, rtm), + (RTM_MISS, rtm), + (RTM_RESOLVE, rtm), + (RTM_NEWADDR, ifam), + (RTM_DELADDR, ifam), + (RTM_IFINFO, ifm), + (RTM_IFANNOUNCE, ifannm), + (RTM_DESYNC, ifannm), + ] + .into_iter() + .collect(); + + // NetBSD 6 and above kernels require 64-bit aligned access to routing facilities. + RoutingStack { + rtm_version, + wire_formats, + kernel_align: 8, + } +} diff --git a/iroh-net/src/net/netmon/bsd.rs b/iroh-net/src/net/netmon/bsd.rs index 8d498f20c41..aa3bc7c47a3 100644 --- a/iroh-net/src/net/netmon/bsd.rs +++ b/iroh-net/src/net/netmon/bsd.rs @@ -2,6 +2,11 @@ use anyhow::Result; use tokio::{io::AsyncReadExt, task::JoinHandle}; use tracing::{trace, warn}; +#[cfg(any(target_os = "freebsd", target_os = "netbsd", target_os = "openbsd"))] +use crate::net::interfaces::bsd::{RTAX_DST, RTAX_IFP}; +#[cfg(any(target_os = "macos", target_os = "ios"))] +use libc::{RTAX_DST, RTAX_IFP}; + use crate::net::{interfaces::bsd::WireMessage, ip::is_link_local}; use super::actor::NetworkMessage; @@ -67,7 +72,7 @@ pub(super) fn is_interesting_message(msg: &WireMessage) -> bool { WireMessage::InterfaceMulticastAddr(_) => true, WireMessage::Interface(_) => false, WireMessage::InterfaceAddr(msg) => { - if let Some(addr) = msg.addrs.get(libc::RTAX_IFP as usize) { + if let Some(addr) = msg.addrs.get(RTAX_IFP as usize) { if let Some(name) = addr.name() { if !is_interesting_interface(name) { return false; @@ -78,7 +83,7 @@ pub(super) fn is_interesting_message(msg: &WireMessage) -> bool { } WireMessage::Route(msg) => { // Ignore local unicast - if let Some(addr) = msg.addrs.get(libc::RTAX_DST as usize) { + if let Some(addr) = msg.addrs.get(RTAX_DST as usize) { if let Some(ip) = addr.ip() { if is_link_local(ip) { return false; @@ -88,6 +93,7 @@ pub(super) fn is_interesting_message(msg: &WireMessage) -> bool { true } + WireMessage::InterfaceAnnounce(_) => false, } } diff --git a/iroh-net/src/tls/certificate.rs b/iroh-net/src/tls/certificate.rs index b26e6d87a99..a31209f51bf 100644 --- a/iroh-net/src/tls/certificate.rs +++ b/iroh-net/src/tls/certificate.rs @@ -100,7 +100,7 @@ pub struct P2pExtension { /// An error that occurs during certificate generation. #[derive(Debug, thiserror::Error)] #[error(transparent)] -pub struct GenError(#[from] rcgen::RcgenError); +pub struct GenError(#[from] rcgen::Error); /// An error that occurs during certificate parsing. #[derive(Debug, thiserror::Error)] @@ -173,7 +173,7 @@ fn parse_unverified(der_input: &[u8]) -> Result { fn make_libp2p_extension( identity_secret_key: &SecretKey, certificate_keypair: &rcgen::KeyPair, -) -> Result { +) -> Result { // The peer signs the concatenation of the string `libp2p-tls-handshake:` // and the public key that it used to generate the certificate carrying // the libp2p Public Key Extension, using its private host key. @@ -187,10 +187,10 @@ fn make_libp2p_extension( let public_key = identity_secret_key.public(); let public_key_ref = OctetStringRef::new(&public_key.as_bytes()[..]) - .map_err(|_| rcgen::RcgenError::CouldNotParseKeyPair)?; + .map_err(|_| rcgen::Error::CouldNotParseKeyPair)?; let signature = signature.to_bytes(); let signature_ref = - OctetStringRef::new(&signature).map_err(|_| rcgen::RcgenError::CouldNotParseCertificate)?; + OctetStringRef::new(&signature).map_err(|_| rcgen::Error::CouldNotParseCertificate)?; let key = SignedKey { public_key: public_key_ref, signature: signature_ref,