Skip to content

15.3 regression: UDP responses to WireGuard/VPN clients egress the wrong interface (SO_BINDTODEVICE on dynamically bound per-IP sockets) #2035

Description

@rxcid

Adding another affected topology plus a workaround for VPN setups, in case it helps others until the fix ships.

Setup: bare-metal 15.3 (Debian 12, Raspberry Pi aarch64), keepalived VIP (e.g. 192.168.1.2) on eth0, WireGuard server on the same host (wg0, clients in e.g. 10.8.0.0/24) with clients using the VIP as their DNS. dnsServerLocalEndPoints is only 0.0.0.0:53.

Symptom: since 15.3, all WireGuard clients lost DNS over UDP (TCP still works). Queries arrive via wg0, but responses are transmitted out eth0 in plaintext toward the default gateway instead of following the routing table back into the tunnel. Confirmed with tcpdump on both interfaces, and with strace: the reply sendmsg() happens on the dynamically-created per-IP socket bound to the VIP. A plain test socket bound to the same source IP routes via wg0 correctly, so it is the device binding (SO_BINDTODEVICE), not the address binding, that breaks it.

This is the same transmit-side behavior described above: any client whose return path is a different interface than the one that owns the queried IP is affected (VPN clients, keepalived VIPs, anycast, routed subnets).

Workaround for VPN users until the fix is released — DNAT tunnel-borne DNS to the tunnel interface's own IP, so replies leave via the correct interface (adjust IPs to your setup):

iptables -t nat -A PREROUTING -i wg0 -d 192.168.1.2 -p udp --dport 53 -j DNAT --to-destination 10.8.0.1
iptables -t nat -A PREROUTING -i wg0 -d 192.168.1.2 -p tcp --dport 53 -j DNAT --to-destination 10.8.0.1
conntrack rewrites the replies, so clients keep using the VIP unchanged. Remember to flush existing conntrack entries for port 53 after adding the rules, or in-flight flows keep bypassing the DNAT.

Looking forward to the update — thanks for the quick turnaround!

Metadata

Metadata

Assignees

No one assigned

    Labels

    No labels
    No labels

    Type

    No type

    Fields

    No fields configured for issues without a type.

    Projects

    No projects

    Milestone

    No milestone

    Relationships

    None yet

    Development

    No branches or pull requests

    Issue actions