mirror of
https://github.com/amnezia-vpn/amneziawg-go.git
synced 2026-10-13 21:34:25 +00:00
[PR #161] [CLOSED] device: AWG 3.0 - don't count S4-padded keepalives as data (idle re-handshake storm) #174
Labels
No labels
pull-request
No milestone
No project
No assignees
1 participant
Notifications
Due date
No due date set.
Dependencies
No dependencies set.
Reference
amnezia-vpn/amneziawg-go#174
Loading…
Add table
Add a link
Reference in a new issue
No description provided.
Delete branch "%!s()"
Deleting a branch is permanent. Although the deleted branch may continue to exist for a short time before it actually gets removed, it CANNOT be undone in most cases. Continue?
📋 Pull Request Information
Original PR: https://github.com/amnezia-vpn/amneziawg-go/pull/161
Author: @william-aqn
Created: 7/26/2026
Status: ❌ Closed
Base:
master← Head:fix-s4-keepalive-rehandshake📝 Commits (1)
77060e0device: don't count S4-padded keepalives as data (idle re-handshake storm)📊 Changes
1 file changed (+9 additions, -1 deletions)
View changed files
📝
device/send.go(+9 -1)📄 Description
AWG 3.0 moved the S4 transport padding into RoutineEncryption, which now seals from elem.buffer[:elem.padding+MessageTransportHeaderSize]. The sealed keepalive therefore measures elem.padding+MessageKeepaliveSize, but RoutineSequentialSender still compared it against the bare MessageKeepaliveSize constant.
With S4 > 0 every keepalive was consequently classified as data, so timersDataSent() armed newHandshake (~15 s + jitter) on a completely idle tunnel. Nothing inbound ever answers a keepalive, so the timer expired into markEndpointSrcForClearing() + SendHandshakeInitiation() and the peer re-handshaked forever.
Measured on an idle tunnel with PersistentKeepalive=5s over 75 s (handshake count read from last_handshake_time_*):
v0.2.19 1 1
v3.0.1 1 5 <- storm, ~1 handshake / 15 s
v3.0.1+fix 1 1
Also reproduced with a v3 client against an unmodified v0.2.19 peer, so it breaks existing deployments on upgrade, not just v3-to-v3 ones.
Compare against elem.padding+MessageKeepaliveSize instead. Real data is unaffected: a data packet is padding+16+content+16 with content > 0, so it still exceeds the keepalive size and still arms the data timers.
🔄 This issue represents a GitHub Pull Request. It cannot be merged through Gitea due to API limitations.