From ae92f5aee66f2f158b7f0281e45a59447107908e Mon Sep 17 00:00:00 2001 From: ginuerzh Date: Sat, 20 Jun 2026 21:13:49 +0800 Subject: [PATCH] fix(dialer): skip SO_BINDTODEVICE for empty-addr UDP relay sockets MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Removes bindDevice from dialOnce's UDP empty-addr path. For relay/listener UDP sockets, the ListenUDP laddr binding already pins the source IP correctly. The additional SO_BINDTODEVICE forced all outbound datagrams through the named interface, which conflicts with the kernel routing table for unconnected UDP sockets and causes silent packet drops — breaking SOCKS5 UDP associate when interface is configured. Fixes go-gost/gost#287 --- internal/net/dialer/dialer.go | 11 ++++++----- 1 file changed, 6 insertions(+), 5 deletions(-) diff --git a/internal/net/dialer/dialer.go b/internal/net/dialer/dialer.go index ddc341f8..14eab31c 100644 --- a/internal/net/dialer/dialer.go +++ b/internal/net/dialer/dialer.go @@ -123,11 +123,12 @@ func (d *Dialer) dialOnce(ctx context.Context, network, addr, ifceName string, i return nil, err } err = sc.Control(func(fd uintptr) { - if ifceName != "" { - if err := bindDevice(network, addr, fd, ifceName); err != nil { - log.Warnf("bind device: %v", err) - } - } + // NOTE: bindDevice is intentionally skipped for empty-addr UDP + // (relay/listener sockets). The ListenUDP laddr binding above + // is sufficient to pin the source IP. SO_BINDTODEVICE would + // force all outbound datagrams through the named interface, + // which may conflict with the kernel routing table and cause + // silent packet drops — breaking UDP associate (issue #287). if d.Mark != 0 { if err := setMark(fd, d.Mark); err != nil { log.Warnf("set mark: %v", err)