Skip to content

Add addr-entries spammer detection to the alerts tool - #459

Open
GuiSchet wants to merge 2 commits into
peer-observer:masterfrom
GuiSchet:alerts-addr-entries-spammer
Open

Add addr-entries spammer detection to the alerts tool#459
GuiSchet wants to merge 2 commits into
peer-observer:masterfrom
GuiSchet:alerts-addr-entries-spammer

Conversation

@GuiSchet

@GuiSchet GuiSchet commented Jun 8, 2026

Copy link
Copy Markdown
Contributor

Adds an AddrEntriesSpammer heuristic that flags peers whose addr/addrv2 messages carry too many entries - catching peers that stay under the message-count threshold by sending a few oversized messages.

Detection uses a per-peer token bucket modeled on Core's addr rate limiting.

Part of #185 (the addr-spammer / addr-entries item).

Note: overlaps with anyhow refactor, happy to rebase on top of whichever lands first.

@0xB10C

0xB10C commented Jun 8, 2026

Copy link
Copy Markdown
Collaborator

Defaults to 2000 entries over 60s.

Any reason for picking this number?

Bitcoin Core treats everything with a rate higher than 1 entry per 10 seconds as "spammer" and rate-limits it.

@GuiSchet

GuiSchet commented Jun 9, 2026

Copy link
Copy Markdown
Contributor Author

I anchored it to the per-message cap, not the rate limiter. Since an addr message can hold up to MAX_ADDR_TO_SEND (1000) entries and the message-count rule only trips at 6 messages, I set the threshold at ~2× the per-message cap so it catches a peer sending a couple of maxed-out messages that slip under that rule.

@0xB10C

0xB10C commented Jun 9, 2026

Copy link
Copy Markdown
Collaborator

I see - however, I don't think that someone spamming addresses would send multiple 1000 addresses at a time. Normally, addr message with up to 1000 addresses are only send in response to an GETADDR message. Sending them without us having send a GETADDR before will get most of them rate-limited, so it won't have any effect on the node. Additionally, if a goal is to get us to propagate these addr messages, you'll want to send batches smaller than 11 addresses (and not older than 10min): https://github.com/bitcoin/bitcoin/blob/bcbf5bae1645605939f0700c438f0cafb47056dc/src/net_processing.cpp#L5711-L5714

So my recommendation would be to:

  • track if we send an GETADDR to the peer, and if yes, allow an extra 1000 in the response
  • otherwise, trigger it at >60 per 300 seconds maybe? This should give us enough head-room to process a larger one once in a while and allows for double the rate of Bitcoin Core at 2 per 10s.

Another approach could be to implement a token-bucket similar to Bitcoin Core (bitcoin/bitcoin#22387) and seed it with a higher starting token number. This is probably a bit more work, but could mean that we rule out false-positive alerts better.

Comment thread tools/alerts/src/alerter.rs Outdated
Comment on lines +10 to +12
impl SpammerKind {
/// The single source of truth for the set of kinds and their order. The
/// per-peer state array is sized and indexed off this, and `index()` is

Copy link
Copy Markdown
Collaborator

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I think this could happen in it's own commit - it's not directly related to the AddrSpammer?

Comment thread tools/alerts/README.md Outdated

```
PeerDisconnected | peer_id=<id> addr=<addr> | active=<duration>s
PeerDisconnected | peer_id=<id> addr=<addr> | active=<duration>s | flags=[PingSpammer, AddrSpammer]

Copy link
Copy Markdown
Collaborator

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

This also seems to be an unrelated addition?

@GuiSchet

GuiSchet commented Jun 9, 2026

Copy link
Copy Markdown
Contributor Author

I like the token-bucket approach with higher starting token number. Sorry about that, I was just trying to replicate the solution from the first addrSpammer.

@GuiSchet
GuiSchet marked this pull request as draft June 9, 2026 18:35
@GuiSchet
GuiSchet force-pushed the alerts-addr-entries-spammer branch from 88dba15 to a1c5e5d Compare June 18, 2026 13:41
@GuiSchet

Copy link
Copy Markdown
Contributor Author

I found some trade-offs working on the token-bucket:

The heuristic counts rate-limited entries via a token bucket modeled on Core's limiter, so an alert means "this peer sent addr entries faster than Core would accept" rather than some arbitrary number. That keeps false positives low and can't be dodged by splitting a flood across many small messages.

The main limitation: the count is cumulative over the connection (not windowed), and it intentionally doesn't catch relay abuse, which stays under the rate limit on purpose. A follow-up could be a separate relay-focused signal (fresh, small addr batches over a sliding window).

Next (I wanted to share the addr-entries heuristic first): improving the PeerDisconnected log to include flags=[...] so it says why the peer was tracked.

I'd also still like to tighten up the tests a bit more on this one before it's final.

@GuiSchet
GuiSchet force-pushed the alerts-addr-entries-spammer branch from a1c5e5d to 77a2b3a Compare July 14, 2026 23:06
@GuiSchet

Copy link
Copy Markdown
Contributor Author

I modified the implementation and compared it more closely with Core's behavior.

The scope for this PR is therefore an EBPF-only, close-effort estimate of Core's standard addr rate limiting:

  • Start new connections with Core's 1-token seed,
  • refill at 0.1 entries/s up to the configured bucket capacity,
  • observe outbound GETADDR and add a fixed 1000-entry allowance,
  • initialize peers first seen without a connection-open event conservatively, since the alerts tool may have started mid-connection,

This intentionally won't account for peers with the addr permission, since that requires RPC correlation.

The alert threshold (default 20) is separate from Core's rate limit. It is configurable headroom so a few excess entries do no t immediately label a a peer, while an unsolicited oversized message still triggers quickly.

It keeps the heuristic useful without pulling RPC state management into it.

@0xB10C

0xB10C commented Jul 28, 2026

Copy link
Copy Markdown
Collaborator

nice! let me know when this is ready for review!

@GuiSchet
GuiSchet force-pushed the alerts-addr-entries-spammer branch from 18673d8 to be46383 Compare July 28, 2026 19:58
@GuiSchet
GuiSchet marked this pull request as ready for review July 28, 2026 20:29
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