diff options
| author | tv <tv@krebsco.de> | 2026-11-01 13:30:12 +0100 |
|---|---|---|
| committer | tv <tv@krebsco.de> | 2026-11-01 13:30:12 +0100 |
| commit | 53d132ff902ff07198b0e01f8c1a030f06aa562b (patch) | |
| tree | 3c964e657a3044438295fe85f4e3c50f1a3acab5 /src/transport/libp2p | |
| parent | 400c4e845998101b94780b101a400c04d38897da (diff) | |
libp2p: one Book::usable for all dials
Diffstat (limited to 'src/transport/libp2p')
| -rw-r--r-- | src/transport/libp2p/book.rs | 40 | ||||
| -rw-r--r-- | src/transport/libp2p/ignore.rs | 23 | ||||
| -rw-r--r-- | src/transport/libp2p/mod.rs | 12 | ||||
| -rw-r--r-- | src/transport/libp2p/relays.rs | 17 |
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)]; |
