libp2p / libp2p/rust-libp2p

AutoNAT v2 dial-back work can grow with every inbound connection

Open
#6,611 0 comments 0 reactions 0 assignees View on GitHub

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

Open the contributing guide

First steps

  1. Read the whole issue, then the project's contributing guide.
  2. Comment on the issue to say you are picking it up — it saves two people doing the same work.
  3. Fork the repository and make your change on a branch.
  4. 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

Get new issues in your inbox

A short digest of beginner-friendly GitHub issues.