From 500c5a4328f03be8c43a38956205318c8bf7a963 Mon Sep 17 00:00:00 2001 From: imabdulbasit Date: Fri, 17 Jul 2026 21:10:22 +0500 Subject: [PATCH 1/3] fix(autonat): close dial-back connections once probes complete --- protocols/autonat/CHANGELOG.md | 11 +++++++---- protocols/autonat/src/v1/behaviour.rs | 10 ++++++++-- protocols/autonat/src/v2/server/behaviour.rs | 19 +++++++++++++------ 3 files changed, 28 insertions(+), 12 deletions(-) diff --git a/protocols/autonat/CHANGELOG.md b/protocols/autonat/CHANGELOG.md index 97517fa4a61..f0238ac561c 100644 --- a/protocols/autonat/CHANGELOG.md +++ b/protocols/autonat/CHANGELOG.md @@ -1,5 +1,8 @@ ## 0.16.0 +- Close server dial-back connections once the probe completes instead of leaving them open. + See [PR 6528](https://github.com/libp2p/rust-libp2p/pull/6528). + - Use `futures-timer` instead of tokio's timer for stream timeouts so the bounded `Delay` works on `wasm32`; tokio's timer has no driver in the browser and panics at runtime. See [PR 6488](https://github.com/libp2p/rust-libp2p/pull/6488). @@ -32,7 +35,7 @@ ## 0.13.0 - Due to the refactor of `Transport` it's no longer required to create a separate transport for -AutoNAT where port reuse is disabled. This information is now passed by the behaviour. + AutoNAT where port reuse is disabled. This information is now passed by the behaviour. See [PR 4568](https://github.com/libp2p/rust-libp2p/pull/4568). - Introduce the new AutoNATv2 protocol. It's split into a client and a server part, represented in their respective modules @@ -40,11 +43,12 @@ AutoNAT where port reuse is disabled. This information is now passed by the beha - The server now always dials back over a newly allocated port. This more accurately reflects the reachability state for other peers and avoids accidental hole punching. - The server can now test addresses different from the observed address (i.e., the connection to the server was made through a `p2p-circuit`). To mitigate against DDoS attacks, the client has to send more data to the server than the dial-back costs. - See [PR 5526](https://github.com/libp2p/rust-libp2p/pull/5526). + See [PR 5526](https://github.com/libp2p/rust-libp2p/pull/5526). ## 0.12.1 + - Use `web-time` instead of `instant`. See [PR 5347](https://github.com/libp2p/rust-libp2p/pull/5347). @@ -92,7 +96,6 @@ AutoNAT where port reuse is disabled. This information is now passed by the beha [PR 3351]: https://github.com/libp2p/rust-libp2p/pull/3351 - ## 0.9.0 - Update to `libp2p-core` `v0.38.0`. @@ -177,7 +180,7 @@ AutoNAT where port reuse is disabled. This information is now passed by the beha - Update to `libp2p-request-response` `v0.16.0`. -- Merge NetworkBehaviour's inject_\* paired methods (see PR 2445). +- Merge NetworkBehaviour's inject\_\* paired methods (see PR 2445). [PR 2445]: https://github.com/libp2p/rust-libp2p/pull/2445 diff --git a/protocols/autonat/src/v1/behaviour.rs b/protocols/autonat/src/v1/behaviour.rs index aefd3a337b0..17bf1e813dd 100644 --- a/protocols/autonat/src/v1/behaviour.rs +++ b/protocols/autonat/src/v1/behaviour.rs @@ -39,8 +39,8 @@ use libp2p_request_response::{ self as request_response, InboundRequestId, OutboundRequestId, ProtocolSupport, ResponseChannel, }; use libp2p_swarm::{ - ConnectionDenied, ConnectionId, ListenAddresses, NetworkBehaviour, THandler, THandlerInEvent, - THandlerOutEvent, ToSwarm, + CloseConnection, ConnectionDenied, ConnectionId, ListenAddresses, NetworkBehaviour, THandler, + THandlerInEvent, THandlerOutEvent, ToSwarm, behaviour::{AddressChange, ConnectionClosed, ConnectionEstablished, DialFailure, FromSwarm}, }; use web_time::Instant; @@ -349,6 +349,12 @@ impl Behaviour { if let Some(event) = self.as_server().on_outbound_connection(&peer, address) { self.pending_actions .push_back(ToSwarm::GenerateEvent(Event::InboundProbe(event))); + // The probe is resolved and the response is sent over the peer's own + // connection. Close the dial-back connection. + self.pending_actions.push_back(ToSwarm::CloseConnection { + peer_id: peer, + connection: CloseConnection::One(conn), + }); } } ConnectedPoint::Dialer { diff --git a/protocols/autonat/src/v2/server/behaviour.rs b/protocols/autonat/src/v2/server/behaviour.rs index b7a9b98d141..9adaf833d45 100644 --- a/protocols/autonat/src/v2/server/behaviour.rs +++ b/protocols/autonat/src/v2/server/behaviour.rs @@ -8,8 +8,8 @@ use either::Either; use libp2p_core::{Endpoint, Multiaddr, transport::PortUse}; use libp2p_identity::PeerId; use libp2p_swarm::{ - ConnectionDenied, ConnectionHandler, ConnectionId, DialFailure, FromSwarm, NetworkBehaviour, - ToSwarm, + CloseConnection, ConnectionDenied, ConnectionHandler, ConnectionId, DialFailure, FromSwarm, + NetworkBehaviour, ToSwarm, dial_opts::{DialOpts, PeerCondition}, dummy, }; @@ -102,13 +102,20 @@ where fn on_connection_handler_event( &mut self, peer_id: PeerId, - _connection_id: ConnectionId, + connection_id: ConnectionId, event: as ConnectionHandler>::ToBehaviour, ) { match event { - Either::Left(Either::Left(Ok(_))) => {} - Either::Left(Either::Left(Err(e))) => { - tracing::debug!("dial back error: {e:?}"); + Either::Left(Either::Left(result)) => { + if let Err(e) = result { + tracing::debug!("dial back error: {e:?}"); + } + // The dial-back has completed and its outcome reaches the client over + // the client's own connection. Close the dial-back connection. + self.pending_events.push_back(ToSwarm::CloseConnection { + peer_id, + connection: CloseConnection::One(connection_id), + }); } Either::Left(Either::Right(v)) => libp2p_core::util::unreachable(v), Either::Right(Either::Left(cmd)) => { From 8908ac9bf31a836f52385200da94785a92d287f3 Mon Sep 17 00:00:00 2001 From: imabdulbasit Date: Mon, 27 Jul 2026 16:31:23 +0500 Subject: [PATCH 2/3] revert unrelated changelog formatting cleanups --- protocols/autonat/CHANGELOG.md | 8 ++++---- 1 file changed, 4 insertions(+), 4 deletions(-) diff --git a/protocols/autonat/CHANGELOG.md b/protocols/autonat/CHANGELOG.md index f0238ac561c..07f377f6184 100644 --- a/protocols/autonat/CHANGELOG.md +++ b/protocols/autonat/CHANGELOG.md @@ -35,7 +35,7 @@ ## 0.13.0 - Due to the refactor of `Transport` it's no longer required to create a separate transport for - AutoNAT where port reuse is disabled. This information is now passed by the behaviour. +AutoNAT where port reuse is disabled. This information is now passed by the behaviour. See [PR 4568](https://github.com/libp2p/rust-libp2p/pull/4568). - Introduce the new AutoNATv2 protocol. It's split into a client and a server part, represented in their respective modules @@ -43,12 +43,11 @@ - The server now always dials back over a newly allocated port. This more accurately reflects the reachability state for other peers and avoids accidental hole punching. - The server can now test addresses different from the observed address (i.e., the connection to the server was made through a `p2p-circuit`). To mitigate against DDoS attacks, the client has to send more data to the server than the dial-back costs. - See [PR 5526](https://github.com/libp2p/rust-libp2p/pull/5526). + See [PR 5526](https://github.com/libp2p/rust-libp2p/pull/5526). ## 0.12.1 - - Use `web-time` instead of `instant`. See [PR 5347](https://github.com/libp2p/rust-libp2p/pull/5347). @@ -96,6 +95,7 @@ [PR 3351]: https://github.com/libp2p/rust-libp2p/pull/3351 + ## 0.9.0 - Update to `libp2p-core` `v0.38.0`. @@ -180,7 +180,7 @@ - Update to `libp2p-request-response` `v0.16.0`. -- Merge NetworkBehaviour's inject\_\* paired methods (see PR 2445). +- Merge NetworkBehaviour's inject_\* paired methods (see PR 2445). [PR 2445]: https://github.com/libp2p/rust-libp2p/pull/2445 From fbdd3e5bdb5094364cee7c486d147ab7294dfd7e Mon Sep 17 00:00:00 2001 From: imabdulbasit Date: Wed, 29 Jul 2026 20:58:55 +0500 Subject: [PATCH 3/3] address comments drop v1 changes, changelog changes --- protocols/autonat/CHANGELOG.md | 2 +- protocols/autonat/src/v1/behaviour.rs | 10 ++-------- protocols/autonat/src/v2/server/behaviour.rs | 6 ++++-- 3 files changed, 7 insertions(+), 11 deletions(-) diff --git a/protocols/autonat/CHANGELOG.md b/protocols/autonat/CHANGELOG.md index e56bbb30c14..303cd9e7954 100644 --- a/protocols/autonat/CHANGELOG.md +++ b/protocols/autonat/CHANGELOG.md @@ -1,6 +1,6 @@ ## 0.16.0 -- Close server dial-back connections once the probe completes instead of leaving them open. +- Close v2 server dial-back connections once the client acknowledges the dial-back instead of leaving them open. See [PR 6528](https://github.com/libp2p/rust-libp2p/pull/6528). - Fix AutoNAT v2 server preserving the selected address index for multi-address `DialRequest`s. diff --git a/protocols/autonat/src/v1/behaviour.rs b/protocols/autonat/src/v1/behaviour.rs index 17bf1e813dd..aefd3a337b0 100644 --- a/protocols/autonat/src/v1/behaviour.rs +++ b/protocols/autonat/src/v1/behaviour.rs @@ -39,8 +39,8 @@ use libp2p_request_response::{ self as request_response, InboundRequestId, OutboundRequestId, ProtocolSupport, ResponseChannel, }; use libp2p_swarm::{ - CloseConnection, ConnectionDenied, ConnectionId, ListenAddresses, NetworkBehaviour, THandler, - THandlerInEvent, THandlerOutEvent, ToSwarm, + ConnectionDenied, ConnectionId, ListenAddresses, NetworkBehaviour, THandler, THandlerInEvent, + THandlerOutEvent, ToSwarm, behaviour::{AddressChange, ConnectionClosed, ConnectionEstablished, DialFailure, FromSwarm}, }; use web_time::Instant; @@ -349,12 +349,6 @@ impl Behaviour { if let Some(event) = self.as_server().on_outbound_connection(&peer, address) { self.pending_actions .push_back(ToSwarm::GenerateEvent(Event::InboundProbe(event))); - // The probe is resolved and the response is sent over the peer's own - // connection. Close the dial-back connection. - self.pending_actions.push_back(ToSwarm::CloseConnection { - peer_id: peer, - connection: CloseConnection::One(conn), - }); } } ConnectedPoint::Dialer { diff --git a/protocols/autonat/src/v2/server/behaviour.rs b/protocols/autonat/src/v2/server/behaviour.rs index 9adaf833d45..fbb0f484667 100644 --- a/protocols/autonat/src/v2/server/behaviour.rs +++ b/protocols/autonat/src/v2/server/behaviour.rs @@ -110,8 +110,10 @@ where if let Err(e) = result { tracing::debug!("dial back error: {e:?}"); } - // The dial-back has completed and its outcome reaches the client over - // the client's own connection. Close the dial-back connection. + // By now the dial-back exchange has concluded: the handler + // waited for the `DialBackResponse` confirming the nonce was + // delivered, or failed. Either way the connection is safe to + // close. self.pending_events.push_back(ToSwarm::CloseConnection { peer_id, connection: CloseConnection::One(connection_id),