Skip to content

feat(quic): rate-limit Retry for unvalidated inbound addresses - #6756

Open
jxs wants to merge 1 commit into
libp2p:masterfrom
jxs:feat-quic-retry
Open

jxs wants to merge 1 commit into
libp2p:masterfrom
jxs:feat-quic-retry

Conversation

@jxs

@jxs jxs commented Nov 9, 2026 •

Copy link
Copy Markdown
Member

Inbound connections from an unvalidated source address now have to pass a stateless QUIC Retry round trip (RFC 9000 §8.1.2) before the TLS handshake starts, once that source's budget of free attempts is spent.
Without this, a peer can trivially burn CPU by repeatedly sending fresh connection ClientHellos, each of which immediately starts a handshake.

Budgets are tracked per source address (IPv4 exactly, IPv6 per /58 prefix, matching libp2p-connection-limits; loopback exempt) in an LRU cache of 4096 token buckets, defaulting to burst 4 and 6 attempts/minute, following go-libp2p's resource manager. Configurable via
Config::inbound_address_validation (Disabled/Always/RateLimited), enabled by default.

This matches libp2p/go-libp2p#3283

@jxs
jxs force-pushed the feat-quic-retry branch from 0c4e223 to f1c8f31 Compare November 9, 2026 19:37
@jxs
jxs marked this pull request as draft November 9, 2026 19:45
@jxs
jxs force-pushed the feat-quic-retry branch 5 times, most recently from 614db41 to c3066f4 Compare November 10, 2026 17:58
@jxs
jxs marked this pull request as ready for review November 10, 2026 18:00
@mergify

mergify Bot commented Nov 10, 2026

Copy link
Copy Markdown
Contributor

This pull request has merge conflicts. Could you please resolve them @jxs? 🙏

@mergify

mergify Bot commented Nov 10, 2026

Copy link
Copy Markdown
Contributor

Tick the box to add this pull request to the merge queue (same as @mergifyio queue). If it does not match the queue conditions yet, it enters the queue once it does.

  • Queue this pull request

@jxs
jxs force-pushed the feat-quic-retry branch 2 times, most recently from 5c75e8f to a45c48c Compare November 10, 2026 18:04
Inbound connections from an unvalidated source address now have to pass a
stateless QUIC Retry round trip (RFC 9000 §8.1.2) before the TLS handshake
starts, once that source's budget of free attempts is spent. Without it,
a peer can trivially burn CPU by repeatedly sending fresh connection
ClientHellos, each of which immediately starts a handshake.

Budgets are tracked per source address (IPv4 exactly, IPv6 per /58 prefix,
matching libp2p-connection-limits; loopback exempt) in an LRU cache of 4096
token buckets, defaulting to burst 4 and 6 attempts/minute, following
go-libp2p's resource manager. Configurable via
`Config::inbound_address_validation` (`Disabled`/`Always`/`RateLimited`),
enabled by default.

test(quic): assert the inbound Retry is sent before the handshake
@elenaf9

elenaf9 commented Nov 10, 2026

Copy link
Copy Markdown
Member

I think go-libp2p applies the limit to all peers, not per source address:

https://github.com/libp2p/go-libp2p/blob/da148e114b94cf312bcd9be17a6d79515651276b/p2p/host/resource-manager/conn_limiter.go#L300-L303

We should do the same, otherwise an attacker can just spoof src IP addresses and circumvent the rate limiter I think?

This branch has not been deployed

No deployments
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

2 participants