fix(dialer): skip SO_BINDTODEVICE for empty-addr UDP relay sockets

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
This commit is contained in:
ginuerzh
2026-06-20 21:13:49 +08:00
parent 48f31513c7
commit ae92f5aee6
+6 -5
View File
@@ -123,11 +123,12 @@ func (d *Dialer) dialOnce(ctx context.Context, network, addr, ifceName string, i
return nil, err return nil, err
} }
err = sc.Control(func(fd uintptr) { err = sc.Control(func(fd uintptr) {
if ifceName != "" { // NOTE: bindDevice is intentionally skipped for empty-addr UDP
if err := bindDevice(network, addr, fd, ifceName); err != nil { // (relay/listener sockets). The ListenUDP laddr binding above
log.Warnf("bind device: %v", err) // 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 d.Mark != 0 {
if err := setMark(fd, d.Mark); err != nil { if err := setMark(fd, d.Mark); err != nil {
log.Warnf("set mark: %v", err) log.Warnf("set mark: %v", err)