Skip to content

Commit

Permalink
feat(iroh-net): implement HomeRouter detection
Browse files Browse the repository at this point in the history
  • Loading branch information
dignifiedquire committed Jul 4, 2023
1 parent 96da24c commit b14049e
Show file tree
Hide file tree
Showing 3 changed files with 72 additions and 3 deletions.
47 changes: 47 additions & 0 deletions iroh-net/src/net/interfaces.rs
Original file line number Diff line number Diff line change
Expand Up @@ -335,6 +335,47 @@ pub async fn default_route_interface() -> Option<String> {
DefaultRouteDetails::new().await.map(|v| v.interface_name)
}

/// Likely IPs of the residentla router, and the ip address of the current
/// machine using it.
#[derive(Debug, Clone)]
pub struct HomeRouter {
pub gateway: IpAddr,
pub my_ip: Option<IpAddr>,
}

impl HomeRouter {
/// Returns the likely IP of the residential router, which will always
/// be a private address, if found.
/// In addition, it returns the IP address of the current machine on
/// the LAN using that gateway.
/// This is used as the destination for UPnP, NAT-PMP, PCP, etc queries.
pub fn new() -> Option<Self> {
let gateway = Self::get_default_gateway()?;
let my_ip = default_net::interface::get_local_ipaddr();

Some(HomeRouter { gateway, my_ip })
}

#[cfg(any(
target_os = "freebsd",
target_os = "openbsd",
target_os = "netbsd",
target_os = "macos",
target_os = "ios"
))]
fn get_default_gateway() -> Option<IpAddr> {
// default_net doesn't work yet
// See: https://github.com/shellrow/default-net/issues/34
bsd::likely_home_router()
}

#[cfg(any(target_os = "linux", target_os = "android", target_os = "windows"))]
fn get_default_gateway() -> Option<IpAddr> {
let gateway = default_net::get_default_gateway().ok()?;
Some(gateway.ip_addr)
}
}

#[cfg(test)]
mod tests {
use super::*;
Expand All @@ -346,4 +387,10 @@ mod tests {
.expect("missing default route");
println!("default_route: {:#?}", default_route);
}

#[tokio::test]
async fn test_likely_home_router() {
let home_router = HomeRouter::new().expect("missing home router");
println!("home router: {:#?}", home_router);
}
}
23 changes: 22 additions & 1 deletion iroh-net/src/net/interfaces/bsd.rs
Original file line number Diff line number Diff line change
Expand Up @@ -4,7 +4,7 @@

use std::{
collections::HashMap,
net::{Ipv4Addr, Ipv6Addr},
net::{IpAddr, Ipv4Addr, Ipv6Addr},
};

use once_cell::sync::Lazy;
Expand All @@ -26,6 +26,27 @@ pub async fn default_route() -> Option<DefaultRouteDetails> {
})
}

pub fn likely_home_router() -> Option<IpAddr> {
let rib = fetch_routing_table()?;
let msgs = parse_routing_table(&rib)?;
for rm in msgs {
if !is_default_gateway(&rm) {
continue;
}

if let Some(gw) = rm.addrs.get(libc::RTAX_GATEWAY as usize) {
if let Addr::Inet4 { ip } = gw {
return Some(IpAddr::V4(*ip));
}

if let Addr::Inet6 { ip, .. } = gw {
return Some(IpAddr::V6(*ip));
}
}
}
None
}

/// Returns the index of the network interface that
/// owns the default route. It returns the first IPv4 or IPv6 default route it
/// finds (it does not prefer one or the other).
Expand Down
5 changes: 3 additions & 2 deletions iroh-net/src/net/interfaces/linux.rs
Original file line number Diff line number Diff line change
Expand Up @@ -23,10 +23,11 @@ pub async fn default_route() -> Option<DefaultRouteDetails> {
res.ok().flatten()
}

const PROC_NET_ROUTE_PATH: &str = "/proc/net/route";

async fn default_route_proc() -> Result<Option<DefaultRouteDetails>> {
const PATH: &str = "/proc/net/route";
const ZERO_ADDR: &str = "00000000";
let file = File::open(PATH).await?;
let file = File::open(PROC_NET_ROUTE_PATH).await?;

// Explicitly set capacity, this is min(4096, DEFAULT_BUF_SIZE):
// https://github.com/google/gvisor/issues/5732
Expand Down

0 comments on commit b14049e

Please sign in to comment.