From 189cd36d9e015968b751117688fa4f0fd64bde36 Mon Sep 17 00:00:00 2001 From: tv Date: Sat, 31 Oct 2026 21:58:21 +0100 Subject: libp2p: warn/refuse bad prefer/ignore combos --- src/transport/libp2p/config.rs | 37 +++++++++++++++++++++++++++++++++++-- src/transport/libp2p/ignore.rs | 7 +++++++ src/transport/libp2p/tests.rs | 34 ++++++++++++++++++++++++++++++++++ 3 files changed, 76 insertions(+), 2 deletions(-) (limited to 'src') diff --git a/src/transport/libp2p/config.rs b/src/transport/libp2p/config.rs index 8b172ba..4db8444 100644 --- a/src/transport/libp2p/config.rs +++ b/src/transport/libp2p/config.rs @@ -59,8 +59,14 @@ pub(crate) fn check(settings: &crate::config::Settings) -> Result<()> { parse_addresses("libp2p-listen", &settings.libp2p_listen)?; parse_addresses("libp2p-announce", &settings.libp2p_announce)?; parse_addresses("libp2p-relays", &settings.libp2p_relays)?; - parse_ranges("libp2p-ignore", &settings.libp2p_ignore)?; - parse_ranges("libp2p-prefer", &settings.libp2p_prefer)?; + let ignore = parse_ranges("libp2p-ignore", &settings.libp2p_ignore)?; + let prefer = parse_ranges("libp2p-prefer", &settings.libp2p_prefer)?; + check_preferred( + &ignore, + &prefer, + &settings.libp2p_ignore, + &settings.libp2p_prefer, + )?; if settings.relay_only { if settings.libp2p_listen.is_empty() { bail!("relay-only needs libp2p-listen: where nodes reach the relay"); @@ -74,6 +80,33 @@ pub(crate) fn check(settings: &crate::config::Settings) -> Result<()> { Ok(()) } +/// A range both ignored and preferred: refused where all of the preferred one is +/// ignored (it would name nothing usable), a warning where only part of it is (the +/// ignored part stays left out). `ignore_given` and `prefer_given`: as written, for +/// the messages. Ranges nest or are apart, so there's nothing in between. +pub(super) fn check_preferred( + ignore: &[IpRange], + prefer: &[IpRange], + ignore_given: &[String], + prefer_given: &[String], +) -> Result<()> { + for (preferred, preferred_given) in prefer.iter().zip(prefer_given) { + for (ignored, ignored_given) in ignore.iter().zip(ignore_given) { + if ignored.covers(preferred) { + bail!( + "libp2p-prefer {preferred_given:?} is all in libp2p-ignore {ignored_given:?}: nothing there is used" + ); + } + if preferred.covers(ignored) { + warn!( + "libp2p-prefer {preferred_given:?} has libp2p-ignore {ignored_given:?} in it: addresses there stay left out" + ); + } + } + } + Ok(()) +} + impl Libp2pConfig { /// The configuration `settings` give; `relay_only`: a relay that is no node /// (`--relay-only`). diff --git a/src/transport/libp2p/ignore.rs b/src/transport/libp2p/ignore.rs index 659ec91..51e1f45 100644 --- a/src/transport/libp2p/ignore.rs +++ b/src/transport/libp2p/ignore.rs @@ -37,6 +37,13 @@ impl FromStr for IpRange { } impl IpRange { + /// Whether every address of `other` is in this range too. + pub(super) fn covers(&self, other: &IpRange) -> bool { + self.network.is_ipv4() == other.network.is_ipv4() + && self.prefix <= other.prefix + && self.contains(other.network) + } + pub(super) fn contains(&self, ip: std::net::IpAddr) -> bool { use std::net::IpAddr; match (self.network, ip) { diff --git a/src/transport/libp2p/tests.rs b/src/transport/libp2p/tests.rs index 9eb2808..f3c9374 100644 --- a/src/transport/libp2p/tests.rs +++ b/src/transport/libp2p/tests.rs @@ -220,6 +220,40 @@ fn address_ranges() { for wrong in ["10.244.0.0/33", "42::/129", "nowhere", "10.0.0.0/x"] { assert!(wrong.parse::().is_err(), "{wrong}"); } + // Mycelium's range: a prefix that isn't a multiple of 8. + let mycelium = [range("400::/7")]; + assert!(ignored( + &mycelium, + &address("/ip6/45f:fa21:4bdd:1::1/tcp/9661") + )); + assert!(ignored(&mycelium, &address("/ip6/5ff::1/tcp/9661"))); + assert!(!ignored(&mycelium, &address("/ip6/600::1/tcp/9661"))); +} + +/// A preferred range all ignored is refused; one with an ignored range in it is fine +/// (with a warning). +#[test] +fn preferred_and_ignored_ranges() { + let check = |ignore: &[&str], prefer: &[&str]| { + let given = |ranges: &[&str]| { + ranges + .iter() + .map(|range| range.to_string()) + .collect::>() + }; + let (ignore, prefer) = (given(ignore), given(prefer)); + super::config::check_preferred( + &super::config::parse_ranges("libp2p-ignore", &ignore).unwrap(), + &super::config::parse_ranges("libp2p-prefer", &prefer).unwrap(), + &ignore, + &prefer, + ) + }; + assert!(check(&["10.244.0.0/16"], &["10.23.0.0/16"]).is_ok()); + assert!(check(&["10.0.0.0/8"], &["10.23.0.0/16"]).is_err()); + assert!(check(&["10.23.0.0/16"], &["10.23.0.0/16"]).is_err()); + assert!(check(&["10.23.5.0/24"], &["10.23.0.0/16"]).is_ok()); + assert!(check(&["42::/16"], &["10.0.0.0/8"]).is_ok()); } /// Ranges left out aren't published; announced addresses are, whatever they are. -- cgit v1.3.1