diff options
| author | tv <tv@krebsco.de> | 2026-10-29 05:32:23 +0100 |
|---|---|---|
| committer | tv <tv@krebsco.de> | 2026-10-29 05:32:23 +0100 |
| commit | a94037c1124c424638e862a8a6c35518f0f7ca73 (patch) | |
| tree | 5567d60b008e1dec67aa48499f4919ca1e97b201 /src/transport | |
| parent | 355c85940b387c292cc65e2a291b6990d4ac6234 (diff) | |
libp2p: publish confirmed addresses
Diffstat (limited to 'src/transport')
| -rw-r--r-- | src/transport/libp2p.rs | 50 |
1 files changed, 40 insertions, 10 deletions
diff --git a/src/transport/libp2p.rs b/src/transport/libp2p.rs index 6602c2e..2808fae 100644 --- a/src/transport/libp2p.rs +++ b/src/transport/libp2p.rs @@ -579,8 +579,9 @@ impl Book { } /// Where others could dial us directly: the announced addresses, or else those we - /// listen on (`published`) and where the router forwards to them (`mapped`), without - /// the peer ID. + /// listen on (`published`), where the router forwards to them (`mapped`), and where + /// AutoNAT found others can dial us (`public_address`: a port forwarded by hand, say), + /// without the peer ID. fn direct(&self) -> Vec<Multiaddr> { if !self.announced.is_empty() { return self.announced.clone(); @@ -592,14 +593,24 @@ impl Book { .cloned() .collect(); let mut direct = published(&direct); - direct.extend( - self.mapped - .iter() - .filter(|address| !direct.contains(address)) - .cloned() - .collect::<Vec<_>>(), - ); - direct + let confirmed = self.public_address.iter().filter_map(|address| { + let mut address = address.clone(); + if let Some(Protocol::P2p(_)) = address.iter().last() { + address.pop(); + } + (!address.is_empty() && !is_relayed(&address)).then_some(address) + }); + // First: the member list keeps only so many (`members::MAX_ADDRESSES`), and a + // node listening everywhere has many. + let mut first: Vec<Multiaddr> = Vec::new(); + for address in self.mapped.iter().cloned().chain(confirmed) { + if !first.contains(&address) { + first.push(address); + } + } + direct.retain(|address| !first.contains(address)); + first.extend(direct); + first } } @@ -2449,6 +2460,25 @@ mod tests { ); } + /// A port forwarded by hand: once AutoNAT found the node dialable at the router's + /// address, that is published with the listen addresses; announced ones still win. + #[test] + fn the_address_autonat_confirmed_is_published() { + let parse = |text: &str| text.parse::<Multiaddr>().unwrap(); + let lan = parse("/ip4/10.23.1.5/udp/9663/quic-v1"); + let public = parse("/ip4/91.65.180.254/udp/9663/quic-v1"); + let mut book = Book { + listening: vec![lan.clone()], + ..Book::default() + }; + assert_eq!(book.direct(), [lan.clone()]); + book.public_address = Some(public.clone().with_p2p(peer()).unwrap()); + assert_eq!(book.direct(), [public.clone(), lan.clone()]); + let announced = parse("/dns4/example.org/udp/9663/quic-v1"); + book.announced = vec![announced.clone()]; + assert_eq!(book.direct(), [announced]); + } + #[test] fn local_addresses_are_left_out_unless_there_are_only_local_ones() { let parse = |text: &str| text.parse::<Multiaddr>().unwrap(); |
