aboutsummaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
authortv <tv@krebsco.de>2026-11-01 13:30:12 +0100
committertv <tv@krebsco.de>2026-11-01 13:30:12 +0100
commit53d132ff902ff07198b0e01f8c1a030f06aa562b (patch)
tree3c964e657a3044438295fe85f4e3c50f1a3acab5
parent400c4e845998101b94780b101a400c04d38897da (diff)
libp2p: one Book::usable for all dials
-rw-r--r--src/transport/libp2p/book.rs40
-rw-r--r--src/transport/libp2p/ignore.rs23
-rw-r--r--src/transport/libp2p/mod.rs12
-rw-r--r--src/transport/libp2p/relays.rs17
4 files changed, 63 insertions, 29 deletions
diff --git a/src/transport/libp2p/book.rs b/src/transport/libp2p/book.rs
index 087cd17..c5a73c4 100644
--- a/src/transport/libp2p/book.rs
+++ b/src/transport/libp2p/book.rs
@@ -493,18 +493,20 @@ impl Book {
/// (`left_out`), or without a route from here (`routes`), directly or through a
/// relay there.
pub(super) fn left_out(&mut self, address: &Multiaddr) -> bool {
- if left_out(&self.ignored, address) {
- return true;
- }
- let at = if is_relayed(address) {
- address
- .iter()
- .take_while(|protocol| !matches!(protocol, Protocol::P2pCircuit))
- .collect::<Multiaddr>()
- } else {
- address.clone()
+ excluded(&self.ignored, &mut self.routes, address)
+ }
+
+ /// Where `peer` can be dialled: its known addresses, but those through this node,
+ /// and those left out (`left_out`). What every dial of ours goes to (connecting,
+ /// upgrading a relayed connection, retrying a hole punch), so none dials into a
+ /// range left out.
+ pub(super) fn usable(&mut self, peer: &PeerId, local: PeerId) -> Vec<Multiaddr> {
+ let Some(known) = self.addresses.get(peer) else {
+ return Vec::new();
};
- ip_of(&at).is_some_and(|ip| !self.routes.routable(ip))
+ let mut usable = dialable(known, local);
+ usable.retain(|address| !excluded(&self.ignored, &mut self.routes, address));
+ usable
}
/// Asks again which ranges have a route (`Routes::recheck`); the addresses in those
@@ -698,6 +700,22 @@ pub(super) fn book_connection(
/// The addresses of `known` this node can dial: not those through itself as the relay
/// (a relay reaches the nodes it relays for only while they are connected to it).
+/// `Book::left_out`, by the fields it needs, for where the book is borrowed in parts.
+pub(super) fn excluded(ignored: &[IpRange], routes: &mut Routes, address: &Multiaddr) -> bool {
+ if left_out(ignored, address) {
+ return true;
+ }
+ let at = if is_relayed(address) {
+ address
+ .iter()
+ .take_while(|protocol| !matches!(protocol, Protocol::P2pCircuit))
+ .collect::<Multiaddr>()
+ } else {
+ address.clone()
+ };
+ ip_of(&at).is_some_and(|ip| !routes.routable(ip))
+}
+
pub(super) fn dialable(known: &[Multiaddr], local: PeerId) -> Vec<Multiaddr> {
known
.iter()
diff --git a/src/transport/libp2p/ignore.rs b/src/transport/libp2p/ignore.rs
index 2fcbd6f..6062839 100644
--- a/src/transport/libp2p/ignore.rs
+++ b/src/transport/libp2p/ignore.rs
@@ -155,6 +155,29 @@ impl ::libp2p::swarm::NetworkBehaviour for Ignoring {
Ok(::libp2p::swarm::dummy::ConnectionHandler)
}
+ /// Dials libp2p makes itself (hole punching, AutoNAT, the DHT) to addresses all in
+ /// ranges left out are refused before they go out; ours never go there
+ /// (`Book::usable`). A dial with an address elsewhere too goes, and a connection it
+ /// makes in a range left out is refused once established (below).
+ fn handle_pending_outbound_connection(
+ &mut self,
+ _connection_id: ConnectionId,
+ _maybe_peer: Option<PeerId>,
+ addresses: &[Multiaddr],
+ _effective_role: ::libp2p::core::Endpoint,
+ ) -> Result<Vec<Multiaddr>, ::libp2p::swarm::ConnectionDenied> {
+ if let Some(first) = addresses.first()
+ && addresses
+ .iter()
+ .all(|address| ignored(&self.ranges, address))
+ {
+ return Err(::libp2p::swarm::ConnectionDenied::new(IgnoredAddress(
+ first.clone(),
+ )));
+ }
+ Ok(Vec::new())
+ }
+
fn handle_established_outbound_connection(
&mut self,
_connection_id: ConnectionId,
diff --git a/src/transport/libp2p/mod.rs b/src/transport/libp2p/mod.rs
index 6c57867..6fea05a 100644
--- a/src/transport/libp2p/mod.rs
+++ b/src/transport/libp2p/mod.rs
@@ -49,8 +49,9 @@
//! it can be dialled, it lets the relays it picked go.
//!
//! With `--libp2p-ignore`, address ranges are left out (VPNs): not published, not told
-//! peers by identify (`Identifying`), not offered for hole punching, not dialled, and
-//! connections there refused (`Ignoring`). Ranges this node has no route to are left
+//! peers by identify (`Identifying`), not offered for hole punching, not dialled by us
+//! (`Book::usable`) nor by libp2p unless with an address elsewhere too, and connections
+//! there refused (`Ignoring`). Ranges this node has no route to are left
//! out alike, as long as it has none (`routes`): without IPv6 to the internet, peers'
//! public IPv6 addresses; and with `--libp2p-internet-hosts`, its own aren't published
//! then. With `--libp2p-prefer`,
@@ -302,12 +303,7 @@ impl Libp2pTransport {
async fn connect(&self, peer: PeerId) -> Result<()> {
let addresses = {
let mut book = lock(&self.book);
- let mut known = book
- .addresses
- .get(&peer)
- .map(|known| dialable(known, self.peer_id))
- .unwrap_or_default();
- known.retain(|address| !book.left_out(address));
+ let known = book.usable(&peer, self.peer_id);
if known.is_empty() {
book.through_relays(peer, self.peer_id)
} else {
diff --git a/src/transport/libp2p/relays.rs b/src/transport/libp2p/relays.rs
index 81a97fe..1a57635 100644
--- a/src/transport/libp2p/relays.rs
+++ b/src/transport/libp2p/relays.rs
@@ -137,18 +137,12 @@ pub(super) fn upgrade(
local: PeerId,
) {
let (direct, now, wait) = {
- let book = lock(book);
+ let mut book = lock(book);
if book.connection(&peer) != Some(Connection::Relayed) {
return;
}
- let direct: Vec<Multiaddr> = book
- .addresses
- .get(&peer)
- .map(|known| dialable(known, local))
- .unwrap_or_default()
- .into_iter()
- .filter(|address| !is_relayed(address) && !ignored(&book.ignored, address))
- .collect();
+ let mut direct = book.usable(&peer, local);
+ direct.retain(|address| !is_relayed(address));
if direct.is_empty() {
return;
}
@@ -227,13 +221,16 @@ pub(super) fn retry_punches(swarm: &mut Swarm<Behaviour>, book: &Mutex<Book>, lo
Some(Connection::Relayed) if now < *next => return true,
Some(Connection::Relayed) => {}
}
+ // As `Book::usable`, by parts: `punching` is borrowed.
let through: Vec<Multiaddr> = book
.addresses
.get(peer)
.map(|known| dialable(known, local))
.unwrap_or_default()
.into_iter()
- .filter(is_relayed)
+ .filter(|address| {
+ is_relayed(address) && !excluded(&book.ignored, &mut book.routes, address)
+ })
.collect();
// Until its punch fails again (or the peer tries from its side).
*next = now + PUNCH_RETRIES[(*failed).min(PUNCH_RETRIES.len() - 1)];