aboutsummaryrefslogtreecommitdiffstats
path: root/src/transport/libp2p/book.rs
diff options
context:
space:
mode:
authortv <tv@krebsco.de>2026-10-31 20:51:53 +0100
committertv <tv@krebsco.de>2026-10-31 20:51:53 +0100
commit491b24d27c2e70d2197c5cd16397967232f087fe (patch)
tree0dd860c27c83bfd2e8de6a07d4b7abdd2382a385 /src/transport/libp2p/book.rs
parent468112d27b272214e0dbec08c662c39826eb684a (diff)
libp2p: identify replaces addresses
Diffstat (limited to 'src/transport/libp2p/book.rs')
-rw-r--r--src/transport/libp2p/book.rs40
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.