Skip to content

[v0.20.x-branch] Backport #11132: peer: answer every valid ping - #11217

Merged
ziggie1984 merged 4 commits into
v0.20.x-branchfrom
backport-11132-to-v0.20.x-branch
Sep 23, 2026
Merged

ziggie1984 merged 4 commits into
v0.20.x-branchfrom
backport-11132-to-v0.20.x-branch

Conversation

@github-actions

Copy link
Copy Markdown

Backport of #11132


Summary

Restore BOLT 1 compliance by answering every valid Ping admitted by the peer flood policy while retaining the former worst-case Pong bandwidth bound.

Closes #11129.

Change Description

Remove the separate Pong reply limiter and retain one per-peer token bucket at 10 tokens per second with a burst of 200. Valid requests cost max(1, ceil(num_pong_bytes / 6554)) tokens, so normal lnd requests up to 4,096 bytes cost one token while a maximum 65,531-byte Pong costs ten.

Every admitted valid Ping receives its required Pong through the existing high-priority outgoing queue. Exhausting the weighted budget disconnects the peer instead of silently suppressing a required response. Requests for 65,532 or more Pong bytes remain ignored under BOLT 1 and cost one token so they cannot bypass inbound flood protection.

@github-actions github-actions Bot added this to the v0.21.4 milestone Sep 22, 2026
@github-actions

Copy link
Copy Markdown
Author

Please cherry-pick the changes locally and resolve any conflicts.

git fetch origin backport-11132-to-v0.20.x-branch
git worktree add --checkout .worktree/backport-11132-to-v0.20.x-branch backport-11132-to-v0.20.x-branch
cd .worktree/backport-11132-to-v0.20.x-branch
git reset --hard HEAD^
git cherry-pick -x 458fc48ef9a8b5b011e68f9f2fd03da2b7ee0a1d 0e9b7f241826b4cd3af7bb35e509a776ddb9a4af 4d7805c8282bb2ec03d7b477a5dc80d4f728bb95 bef201833cb6fa1c88270cd7ee218bd6c43b1177
git push --force-with-lease

@ziggie1984
ziggie1984 force-pushed the backport-11132-to-v0.20.x-branch branch from b152346 to ce9ae06 Compare September 22, 2026 11:05
@ziggie1984
ziggie1984 marked this pull request as ready for review September 22, 2026 11:06
@github-actions github-actions Bot added the severity-critical Requires expert review - security/consensus critical label Sep 22, 2026
@github-actions

Copy link
Copy Markdown
Author

🔴 PR Severity: CRITICAL

package classification | 4 files | 269 additions, 169 deletions

🔴 Critical (2 files)
  • peer/brontide.go - encrypted peer connection / Noise protocol handling
  • peer/ping_limits.go - peer connection ping/liveness limits
🟢 Low (2 files)
  • peer/brontide_test.go - test-only changes
  • docs/release-notes/release-notes-0.20.5.md - release notes

Analysis

This PR modifies peer/brontide.go and peer/ping_limits.go, both under peer/*, which governs encrypted peer connection handling and liveness/ping logic — classified CRITICAL per policy. Excluding the test file and release notes, the non-test diff is small (~104 lines across 2 files), so no severity bump applies beyond the CRITICAL floor already set by the package. Recommend review from someone familiar with the peer connection and ping/pong liveness handling.


To override, add a severity-override-{critical,high,medium,low} label.

@ziggie1984
ziggie1984 force-pushed the backport-11132-to-v0.20.x-branch branch 2 times, most recently from 3fc6e63 to 6cb71cd Compare September 22, 2026 12:03
Remove the separate Pong reply check so every accepted Ping below
the BOLT 1 size ceiling receives its mandated response. Keep the
request flood limiter as the abuse boundary and verify full-burst
replies continue through the high-priority queue.

(cherry picked from commit 458fc48)
Delete the unused reply limiter after valid Pongs stop consulting
it. Store the remaining request flood limiter directly on the peer
and retain its existing rate, burst, and teardown behavior.

(cherry picked from commit 0e9b7f2)
Document the Ping reply correction in the 0.20.5 and 0.21.4
release notes and credit the contributor in both versions.

(cherry picked from commit 4d7805c)
Charge the existing inbound Ping budget based on requested Pong
bytes. Keep normal and oversized no-reply Pings at one token while
maximum replies cost ten.

Disconnect when the weighted budget is exhausted so admitted valid
Pings still receive BOLT-required responses without restoring a
separate limiter.

(cherry picked from commit bef2018)
@ziggie1984

Copy link
Copy Markdown
Collaborator

Divergence from the parent PR

Derived by diffing this branch's net patch against #11132's net patch, so
pre-existing base differences are separated from what the backport itself does.

Parent commits, cherry-picked with -x in order: 458fc48ef, 0e9b7f241,
4d7805c82, bef201833.

Root cause

v0.20.x-branch does not have #10674 ("lnwire+peer: ignore BOLT 1 no-reply
pings"), which master and v0.21.x-branch both carry. On this branch
Ping.Decode still rejects NumPongBytes > MaxPongBytes with
ErrMaxPongBytesExceeded, whereas master accepts the message and the Ping
handler ignores it.

Every difference below follows from that. Backporting #10674 was considered
and deliberately declined: real-world impact is negligible (lnd requests at
most 4,096 pong bytes and the sender only drops its own connection), and
dd61acd9d would delete the exported lnwire.ErrMaxPongBytesExceeded, an API
break on a patch release.

Differences

# File Difference vs parent Class
1 peer/ping_limits.go none — byte-identical —
2 peer/brontide.go Flood-counter comment keeps this branch's "Oversized requests never reach this point because this release rejects them during wire decoding" instead of the parent's "oversized no-reply requests still consume one flood token". Code (AllowN + calcPingCost) identical forced — conflict, both sides edited it
3 peer/brontide_test.go Test doc comment: "one-token Ping accounting" vs "one-token oversized Ping accounting" forced — conflict
4 peer/brontide_test.go "Arrange: Encode one valid Pong request…" vs "…one BOLT 1 no-reply request…" forced — conflict
5 peer/brontide_test.go "Act: Send two valid Pings…" vs "…two oversized Pings…" forced — conflict
6 peer/brontide_test.go Same tc := tc whitespace hunk as #11218 forced — conflict
7 docs/release-notes-0.21.4.md hunk dropped forced — file does not exist here

All five conflict regions from the bef201833 pick are accounted for. Nothing
diverges that a conflict did not force.

Looks like a difference, but is pre-existing base state

Both verified as context lines on both sides of the patch comparison — the
backport does not touch either:

  • The if msg.NumPongBytes > lnwire.MaxPongBytes { continue } block is absent
    from the Ping handler here. The parent carries it as unchanged context; this
    branch never had it, because decode rejects first.
  • TestPeerPingFloodDisconnects encodes lnwire.NewPing(1) rather than
    MaxPongBytes + 1. That was already this branch's adaptation before this
    backport. Cost is 1 token either way, so the test proves the same property.

Consequently calcPingCost's NumPongBytes > MaxPongBytes guard is
unreachable on this branch. It is kept verbatim from the parent anyway — dead,
but not wrong.

Verification

  • go build ./..., go vet ./peer/, gofmt clean
  • per-commit build + vet: 4/4 pass
  • go test ./peer/ ./lnwire/: pass
  • full Static Checks job run locally (all 9 steps): pass
  • make lint (new-from-rev active): 0 issues

Rebased onto 86dd72eec so it picks up the go.sum fix from #11221; the
ping/pong commits themselves are unchanged by the rebase.

The companion v0.21.x backport is #11218, which is a clean parent adoption.

@ziggie1984
ziggie1984 merged commit 0a6470c into v0.20.x-branch Sep 23, 2026
34 of 36 checks passed
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

no-changelog severity-critical Requires expert review - security/consensus critical

Projects

None yet

Development

Successfully merging this pull request may close these issues.

2 participants