[PATCH wireguard-go 1/3] conn: enable IP_PKTINFO ancillary data on PacketConn

Artjom Vejsel akawolf0 at gmail.com
Tue Jun 9 22:01:52 UTC 2026


The IPV6_RECVPKTINFO/IP_PKTINFO setsockopts are set during socket
creation via the ListenConfig control function. However, x/net/ipv4 and
x/net/ipv6 PacketConn instances maintain their own internal control
message option tracking (rawOpt), which is consulted during recvmmsg
unpacking. Without calling SetControlMessage(FlagDst|FlagInterface,
true), the PacketConn does not advertise these flags to the unpack
path, and the resulting Message.NN remains zero on every read.

Because Message.NN is zero, getSrcFromControl never finds a PKTINFO
cmsg, StdNetEndpoint.src is never populated, and setSrcControl writes
empty control bytes on send. The kernel then selects the outgoing
source address by route lookup (RFC 6724) rather than honoring the
destination address of the incoming packet. The sticky source address
behavior is silently broken on hosts with multiple addresses on the
listening interface.

Reproduced with a userspace bind on a Linux interface holding two
global IPv6 addresses, where the route preferred source differs from
the address the peer initiated the handshake on: the server responded
from the route-preferred address, the peer rejected the response, and
the session never established.

Signed-off-by: Artjom Vejsel <akawolf0 at gmail.com>
---
 conn/bind_std.go | 2 ++
 1 file changed, 2 insertions(+)

diff --git a/conn/bind_std.go b/conn/bind_std.go
index f5c8816..c88ed4e 100644
--- a/conn/bind_std.go
+++ b/conn/bind_std.go
@@ -177,6 +177,7 @@ again:
 		s.ipv4TxOffload, s.ipv4RxOffload = supportsUDPOffload(v4conn)
 		if runtime.GOOS == "linux" || runtime.GOOS == "android" {
 			v4pc = ipv4.NewPacketConn(v4conn)
+			_ = v4pc.SetControlMessage(ipv4.FlagDst|ipv4.FlagInterface, true)
 			s.ipv4PC = v4pc
 		}
 		fns = append(fns, s.makeReceiveIPv4(v4pc, v4conn, s.ipv4RxOffload))
@@ -186,6 +187,7 @@ again:
 		s.ipv6TxOffload, s.ipv6RxOffload = supportsUDPOffload(v6conn)
 		if runtime.GOOS == "linux" || runtime.GOOS == "android" {
 			v6pc = ipv6.NewPacketConn(v6conn)
+			_ = v6pc.SetControlMessage(ipv6.FlagDst|ipv6.FlagInterface, true)
 			s.ipv6PC = v6pc
 		}
 		fns = append(fns, s.makeReceiveIPv6(v6pc, v6conn, s.ipv6RxOffload))
-- 
2.54.0



More information about the WireGuard mailing list