diff --git a/iroh-net/src/net/interfaces.rs b/iroh-net/src/net/interfaces.rs index 76f3b22de3c..0d251a460b7 100644 --- a/iroh-net/src/net/interfaces.rs +++ b/iroh-net/src/net/interfaces.rs @@ -282,10 +282,10 @@ impl State { } } -/// Reports whether ip is a usable IPv4 address which could -/// conceivably be used to get Internet connectivity. Globally routable and -/// private IPv4 addresses are always Usable, and link local 169.254.x.x -/// addresses are in some environments. +/// Reports whether ip is a usable IPv4 address which should have Internet connectivity. +/// +/// Globally routable and private IPv4 addresses are always Usable, and link local +/// 169.254.x.x addresses are in some environments. fn is_usable_v4(ip: &IpAddr) -> bool { if !ip.is_ipv4() || ip.is_loopback() { return false; @@ -294,15 +294,25 @@ fn is_usable_v4(ip: &IpAddr) -> bool { true } -/// Reports whether ip is a usable IPv6 address which could -/// conceivably be used to get Internet connectivity. Globally routable -/// IPv6 addresses are always Usable, and Unique Local Addresses +/// Reports whether ip is a usable IPv6 address which should have Internet connectivity. +/// +/// Globally routable IPv6 addresses are always Usable, and Unique Local Addresses /// (fc00::/7) are in some environments used with address translation. +/// +/// We consider all 2000::/3 addresses to be routable, which is the interpretation of +/// +/// as well. However this probably includes some addresses which should not be routed, +/// e.g. documentation addresses. See also +/// for an +/// alternative implementation which is both stricter and laxer in some regards. fn is_usable_v6(ip: &IpAddr) -> bool { match ip { IpAddr::V6(ip) => { // V6 Global1 2000::/3 - if matches!(ip.segments(), [0x2000, _, _, _, _, _, _, _]) { + let mask: u16 = 0b1110_0000_0000_0000; + let base: u16 = 0x2000; + let segment1 = ip.segments()[0]; + if (base & mask) == (segment1 & mask) { return true; } @@ -383,6 +393,8 @@ impl HomeRouter { #[cfg(test)] mod tests { + use std::net::Ipv6Addr; + use super::*; #[tokio::test] @@ -398,4 +410,19 @@ mod tests { let home_router = HomeRouter::new().expect("missing home router"); println!("home router: {:#?}", home_router); } + + #[test] + fn test_is_usable_v6() { + let loopback = Ipv6Addr::new(0, 0, 0, 0, 0, 0, 0, 0x1); + assert!(!is_usable_v6(&loopback.into())); + + let link_local = Ipv6Addr::new(0xfe80, 0, 0, 0, 0xcbc9, 0x6aff, 0x5b07, 0x4a9e); + assert!(!is_usable_v6(&link_local.into())); + + let derp_use1 = Ipv6Addr::new(0x2a01, 0x4ff, 0xf0, 0xc4a1, 0, 0, 0, 0x1); + assert!(is_usable_v6(&derp_use1.into())); + + let random_2603 = Ipv6Addr::new(0x2603, 0x3ff, 0xf1, 0xc3aa, 0x1, 0x2, 0x3, 0x1); + assert!(is_usable_v6(&random_2603.into())); + } } diff --git a/iroh-net/src/netcheck.rs b/iroh-net/src/netcheck.rs index 47b3b6cd746..1af6919ce2d 100644 --- a/iroh-net/src/netcheck.rs +++ b/iroh-net/src/netcheck.rs @@ -847,7 +847,10 @@ mod tests { "expected key 1 in DERPLatency; got {:?}", r.derp_latency ); - assert!(r.global_v4.is_some(), "expected globalV4 set"); + assert!( + r.global_v4.is_some() || r.global_v6.is_some(), + "expected at least one of global_v4 or global_v6" + ); assert!(r.preferred_derp.is_some()); } else { eprintln!("missing UDP, probe not returned by network"); diff --git a/iroh-net/src/netcheck/reportgen.rs b/iroh-net/src/netcheck/reportgen.rs index 03128d3a9f6..6c2ae7aeaf9 100644 --- a/iroh-net/src/netcheck/reportgen.rs +++ b/iroh-net/src/netcheck/reportgen.rs @@ -581,6 +581,7 @@ impl Actor { /// aborted. That is, the main actor loop stops polling them. async fn spawn_probes_task(&mut self) -> Result>> { let if_state = interfaces::State::new().await; + debug!(?if_state, "Local interfaces"); let plan = match self.last_report { Some(ref report) => ProbePlan::with_last_report(&self.derp_map, &if_state, report), None => ProbePlan::initial(&self.derp_map, &if_state),