AutoNAT v2 dial-back work can grow with every inbound connection
Nobody has claimed this yet.
- Dominant language
- Rust
- Stars
- 5.6k
- Forks
- 1.3k
- Avg merge
- 8h 47m
- Merged PRs (30d)
- 19
Description
Summary
AutoNAT v2 limits in-flight requests per connection, but has no behaviour-wide global or per-peer limit. An untrusted peer can therefore increase pending dial-back work by opening additional connections.
Expected behavior
Accepted dial-back work should remain within explicit global and per-peer limits across all streams and connections.
Actual behavior
Each connection permits ten concurrent request handlers with a ten-second timeout. After the cross-IP data cost is paid, every accepted DialBackCommand is added to the behaviour-wide dialing_dial_back map and produces a ToSwarm::Dial, without aggregate admission control.
This establishes a missing bound, not a demonstrated denial of service. Actual resource impact depends on transport timeouts and application-level connection limits.
Relevant log output
Add this test to `protocols/autonat/src/v2/server/behaviour.rs`:
#[cfg(test)]
mod tests {
use futures::channel::oneshot;
use super::*;
#[test]
fn one_peer_can_enqueue_more_than_ten_dial_backs_across_connections() {
let mut behaviour = Behaviour::default();
let peer = PeerId::random();
let addr: Multiaddr = "/ip4/198.51.100.1/tcp/9".parse().unwrap();
for connection in 1..=11 {
let (back_channel, _receiver) = oneshot::channel();
let command = DialBackCommand {
addr: addr.clone(),
nonce: connection as u64,
back_channel,
};
behaviour.on_connection_handler_event(
peer,
ConnectionId::new_unchecked(connection),
Either::Right(Either::Left(command)),
);
}
assert_eq!(behaviour.dialing_dial_back.len(), 11);
assert_eq!(behaviour.pending_events.len(), 11);
}
}
Run:
cargo test -p libp2p-autonat one_peer_can_enqueue_more_than_ten_dial_backs_across_connections --lib
The test passes because all eleven commands become pending dials despite belonging to one peer.
Possible Solution
Add configurable global and per-peer in-flight limits. Reserve capacity before emitting ToSwarm::Dial, reject excess work with E_REQUEST_REJECTED, and release capacity after success, failure, timeout, or connection closure.
Version
Confirmed with libp2p-autonat 0.16.0 at commit 850319b. Earlier versions were not assessed.
Would you like to work on fixing this bug?
No
Contributor guide
First steps
- Read the whole issue, then the project's contributing guide.
- Comment on the issue to say you are picking it up — it saves two people doing the same work.
- Fork the repository and make your change on a branch.
- Open a pull request that references the issue number.
Research direction
Start in protocols/autonat/src/v2/server/behaviour.rs and run the named cargo test to reproduce eleven pending dial-backs from one peer. Trace DialBackCommand handling, dialing_dial_back, pending_events, and the relevant completion, failure, timeout, and connection-closure paths. Done means configurable global and per-peer limits reject excess work and release capacity in each terminal path.
Written by the indexing model from the issue text.
Assessment
- Tech stack
- rust
- Domain
- networking
- Issue type
- Bug
- Difficulty
- 4/5
- Estimated time
- 3-5 days
- Activity status
- Active
- Clarity
- Mostly clear
- Newbie friendliness
- 55/100