mirror of
https://github.com/amnezia-vpn/amneziawg-go.git
synced 2026-10-13 21:34:25 +00:00
[PR #137] [CLOSED] device: apply S4 transport padding to keepalive packets #161
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#161
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/137
Author: @remotetohome
Created: 5/13/2026
Status: ❌ Closed
Base:
master← Head:fix/transport-s4-keepalive-padding📝 Commits (1)
5e025badevice: apply S4 transport padding to keepalive packets📊 Changes
2 files changed (+146 additions, -8 deletions)
View changed files
📝
device/device_test.go(+138 -0)📝
device/send.go(+8 -8)📄 Description
@ygurov - was finally able to hunt this down, but got it working.
I reproduced my initial test. I set the s3/4 back to non-zero values (38/22) on the server side (linux kernel).
I then tested the exact same client profile side by side on my Kubuntu laptop.. just as before:
After monitoring both the server and desktop client via the daemon socket (then putting Claude to work on the logs), I was able to isolate and draft fix - then retested (exact reproduction with same profie) = desktop client works!
This issue is awg-go isn't adding the s4 padding on the keepalive packets so when the server strips the expected s4 padding from the keepalive, it actually mangles the real data instead and then drops it. The tunnel then dies soon after initial setup.
Had Claude attend to the PR writeup:
Summary
RoutineSequentialSenderskipped S4 padding for keepalive packets (len(elem.packet) != MessageKeepaliveSizeguard), while the kernel module'sencrypt_packet()(send.c:210) unconditionally prepends S4 random bytes to all transport packets including keepalives. This size mismatch caused the kernel module to reject awg-go client keepalives when S4 > 0:Without keepalives, the server-side keypair for the client never gets promoted from
nexttocurrent(requiresReceivedWithKeypair), and the connection dies shortly after handshake.The fix
Move the S4 padding block outside the keepalive-size check (2 lines changed in
send.go). ThedataSentflag — which controlstimersDataSent()— remains gated on the size check, preserving WireGuard timer semantics (keepalives don't trigger data-sent timers).Reproduction
Same laptop, same server (amneziawg.ko v1.0.20260329-2), same AWG profile (S3=38, S4=22, full STUN preset), three client implementations:
awg-quickCGO_ENABLED=0Server-side
awg showconfirmed: upstream awg-go client transmitted 0 bytes of transport data across 4 connection attempts. Patched binary: immediate symmetric traffic flow with keepalives every 25 seconds.Patched awg-go verbose log (keepalive cycle)
No "Retrying handshake" messages — connection stays alive indefinitely.
Test coverage
Added
TestKeepaliveIncludesS4Padding: uses a spy bind to capture raw wire packets, verifies keepalive size is exactlyS4 + MessageKeepaliveSize(not bareMessageKeepaliveSize). Passes with bothCGO_ENABLED=0andCGO_ENABLED=1.Cross-references
Acknowledgments
🔄 This issue represents a GitHub Pull Request. It cannot be merged through Gitea due to API limitations.