diff options
| author | tv <tv@krebsco.de> | 2026-10-31 20:51:53 +0100 |
|---|---|---|
| committer | tv <tv@krebsco.de> | 2026-10-31 20:51:53 +0100 |
| commit | 8124270037d2949fb455f704f6bc45716179767e (patch) | |
| tree | 1c710c13b7fe998053e36f0f5b2c6a787cf63c88 /src/transport/libp2p/book.rs | |
| parent | fbaadc3a072916dddcb659e3b3d5e47f34f511b1 (diff) | |
libp2p: identify replaces addresses
Diffstat (limited to 'src/transport/libp2p/book.rs')
| -rw-r--r-- | src/transport/libp2p/book.rs | 40 |
1 files changed, 39 insertions, 1 deletions
diff --git a/src/transport/libp2p/book.rs b/src/transport/libp2p/book.rs index 6706512..ceb9d27 100644 --- a/src/transport/libp2p/book.rs +++ b/src/transport/libp2p/book.rs @@ -36,6 +36,11 @@ pub(super) struct NamedRelay { #[derive(Default)] pub(super) struct Book { pub(super) addresses: HashMap<PeerId, Vec<Multiaddr>>, + /// Where connected peers say they are, by their last identify (`identified`): while + /// connected, the only direct addresses of theirs kept. Forgotten when the last + /// connection to the peer closes, as a peer restarted elsewhere is found by what + /// the others say. + pub(super) identified: HashMap<PeerId, Vec<Multiaddr>>, pub(super) listening: Vec<Multiaddr>, /// Where the router forwards to our listen addresses (UPnP, `Libp2pConfig::upnp`). pub(super) mapped: Vec<Multiaddr>, @@ -205,6 +210,7 @@ impl Book { .collect(); for peer in &stale { self.addresses.remove(peer); + self.identified.remove(peer); self.relays.remove(peer); self.public_relays.remove(peer); self.continuum.remove(peer); @@ -439,18 +445,50 @@ impl Book { .all(|address| known.contains(&without_peer(address.clone()))) } - /// `peer` is at `address` (without its `/p2p` part): kept first. + /// `peer` is at `address` (without its `/p2p` part): kept first. Not a direct + /// address the peer's identify left out (`identified`): one it no longer has, or + /// one it doesn't publish (`Libp2pConfig::ignore`). pub(super) fn remember(&mut self, peer: PeerId, address: Multiaddr) { let address = without_peer(address); if !self.addresses.contains_key(&peer) && self.addresses.len() >= MAX_PEERS { return; } + if self + .identified + .get(&peer) + .is_some_and(|said| is_ip(&address) && !said.contains(&address)) + { + return; + } self.touch(peer); let addresses = self.addresses.entry(peer).or_default(); addresses.retain(|known| *known != address); addresses.insert(0, address); addresses.truncate(ADDRESSES_PER_PEER); } + + /// `peer`, connected, identified itself at `listen` (`published`): its direct + /// addresses are those from now on, while connected (`remember`); those through + /// relays and by name stay. + pub(super) fn identified(&mut self, peer: PeerId, listen: Vec<Multiaddr>) { + let listen: Vec<Multiaddr> = listen.into_iter().map(without_peer).collect(); + if let Some(known) = self.addresses.get_mut(&peer) { + known.retain(|address| !is_ip(address) || listen.contains(address)); + } + self.identified.insert(peer, listen.clone()); + // Last first: `remember` puts each in front. + for address in listen.into_iter().rev() { + self.remember(peer, address); + } + } +} + +/// Whether `address` is a direct one at an IP address (not through a relay, nor a name). +pub(super) fn is_ip(address: &Multiaddr) -> bool { + matches!( + address.iter().next(), + Some(Protocol::Ip4(_) | Protocol::Ip6(_)) + ) && !is_relayed(address) } /// Whether `address` goes through a relay. |
