aboutsummaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
authortv <tv@krebsco.de>2026-11-01 13:23:21 +0100
committertv <tv@krebsco.de>2026-11-01 13:23:21 +0100
commitd5de69630cf544fd048c8376e1b51cd0e4e7c7fc (patch)
tree0a27c4b92b6faab64a872958e9e010affd27660a
parent7348524430ab2af7ccdcf38bfe76461b476337a5 (diff)
libp2p: public means global routable
-rw-r--r--src/transport/libp2p/book.rs28
-rw-r--r--src/transport/libp2p/tests.rs24
2 files changed, 45 insertions, 7 deletions
diff --git a/src/transport/libp2p/book.rs b/src/transport/libp2p/book.rs
index 02a6b49..c2296d3 100644
--- a/src/transport/libp2p/book.rs
+++ b/src/transport/libp2p/book.rs
@@ -611,24 +611,38 @@ pub(super) fn ip_of(address: &Multiaddr) -> Option<std::net::IpAddr> {
}
}
-/// Whether `ip` can be reached from the internet, as far as its range tells.
+/// Whether `ip` can be reached from the internet, as far as its range tells. For IPv6,
+/// only global unicast (`2000::/3`) is: other ranges in use are an overlay's
+/// (Mycelium's `400::/7`), a translator's (`64:ff9b::/96`) or local, and, ranked as
+/// public, would be preferred over the LAN (`preference`).
pub(super) fn is_public(ip: std::net::IpAddr) -> bool {
use std::net::IpAddr;
match ip {
IpAddr::V4(ip) => {
+ let [a, b, c, _] = ip.octets();
// 100.64.0.0/10: carrier-grade NAT.
- let shared = ip.octets()[0] == 100 && (ip.octets()[1] & 0xc0) == 64;
+ let shared = a == 100 && (b & 0xc0) == 64;
+ // 198.18.0.0/15: benchmarking; 240.0.0.0/4: reserved (and broadcast).
+ let benchmarking = a == 198 && (b & 0xfe) == 18;
+ let reserved = a >= 240;
+ // 192.0.0.0/24: protocol assignments.
+ let protocol = a == 192 && b == 0 && c == 0;
!(ip.is_private()
|| ip.is_loopback()
|| ip.is_link_local()
|| ip.is_unspecified()
- || shared)
+ || ip.is_documentation()
+ || ip.is_multicast()
+ || shared
+ || benchmarking
+ || reserved
+ || protocol)
}
IpAddr::V6(ip) => {
- !(ip.is_loopback()
- || ip.is_unspecified()
- || ip.is_unique_local()
- || ip.is_unicast_link_local())
+ let [first, second, ..] = ip.segments();
+ // 2001:db8::/32: documentation.
+ let documentation = first == 0x2001 && second == 0x0db8;
+ (first & 0xe000) == 0x2000 && !documentation
}
}
}
diff --git a/src/transport/libp2p/tests.rs b/src/transport/libp2p/tests.rs
index 801dfd3..fd607fe 100644
--- a/src/transport/libp2p/tests.rs
+++ b/src/transport/libp2p/tests.rs
@@ -539,6 +539,30 @@ async fn a_member_that_relays_is_picked() {
/// A peer on the LAN that speaks continuum becomes a seed once, at its address.
#[test]
+fn public_ranges() {
+ let public = |ip: &str| book::is_public(ip.parse().unwrap());
+ assert!(public("203.0.114.5"));
+ assert!(public("2a01:4f8::1"));
+ for not in [
+ "10.1.2.3",
+ "100.64.0.1",
+ "192.0.2.1",
+ "198.18.0.1",
+ "224.0.0.1",
+ "255.255.255.255",
+ "::1",
+ "fd00::1",
+ "fe80::1",
+ "2001:db8::1",
+ "64:ff9b::1",
+ // Mycelium's overlay.
+ "45f:fa21:4bdd::1",
+ ] {
+ assert!(!public(not), "{not}");
+ }
+}
+
+#[test]
fn lan_peers_become_seeds_once() {
let mut book = Book::default();
let lan = peer();