mirror of
https://github.com/amnezia-vpn/amneziawg-go.git
synced 2026-10-13 21:34:25 +00:00
[PR #144] conn: fix sticky source address on multi-IP hosts #164
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#164
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/144
Author: @akaWolf
Created: 6/8/2026
Status: 🔄 Open
Base:
master← Head:fix-sticky-pktinfo📝 Commits (3)
9d2f826conn: enable IP_PKTINFO ancillary data on PacketConn73b3791conn: reset udpAddrPool slice length before copy3588e16conn: propagate ancillary data to coalesced split frames📊 Changes
1 file changed (+9 additions, -2 deletions)
View changed files
📝
conn/bind_std.go(+9 -2)📄 Description
Summary
Three independent bugs in
conn/bind_std.gobreak the sticky source address feature on multi-IP hosts. On a server with multiple global IPv6 addresses (e.g. a static::100and a DHCPv6-assigned::943), the server responds to handshake initiations with the kernel's route-preferred source rather than the destination the peer connected to, so the peer rejects the response and the session never establishes.Patches
conn: enable IP_PKTINFO ancillary data on PacketConn— callSetControlMessage(FlagDst|FlagInterface, true)afterNewPacketConn. Without it,ipv6.PacketConn.ReadBatch/RecvMsgsdiscards the PKTINFO cmsg even thoughIPV6_RECVPKTINFO=1is set at the socket level —Message.NNalways returns 0,ep.srcnever populates, sticky source becomes a silent no-op.conn: reset udpAddrPool slice length before copy—Send()truncatesua.IPaftercopy(...), so after a v4 send the pooled*net.UDPAddrhaslen(IP)==4, and the next v6 reuse only writes the upper 4 bytes of the IPv6 destination, leaving 12 stale bytes from the previous send. Resize the slice before the copy.conn: propagate ancillary data to coalesced split frames—splitCoalescedMessagescopiesBuffers[0],N, andAddrto each child frame but never propagatesOOB/NN. With UDP_GRO active (Linux 5.12+), every frame past the first loses its PKTINFO and sticky source breaks even after fix #1 is applied.Each commit fixes one independent issue and is self-contained; they can be applied or reverted individually.
Reproduction
Network namespaces with a server holding
::100and::943on the same/64, whereip route get <client>returnssrc ::943:Then run an amneziawg-go server in
srvnslistening on port 53400, and a client incltnswithEndpoint = [fd00:1::100]:53400. Without the patches,tcpdump -i br-testshows the handshake response coming fromfd00:1::943. With the patches, the response comes fromfd00:1::100and the client does not roam endpoints.Testing
End-to-end tested in netns on Linux 6.x (both arm64 and x86_64). Verified against a real-world production setup where this bug was causing handshake failures for an IPv6 client behind a sticky-source-sensitive peer; with the patches applied, the workaround route (
ip -6 route ... src ::100) was removed and the tunnel handshakes cleanly.This same patch series is being submitted to wireguard-go upstream (the bugs are identical there since amneziawg-go inherits
conn/bind_std.go).Test plan
go 1.23+::943to::100after the patches🔄 This issue represents a GitHub Pull Request. It cannot be merged through Gitea due to API limitations.