From caa82f2861fa84ed4170877596558ffc777a1abf Mon Sep 17 00:00:00 2001 From: ginuerzh Date: Mon, 8 Jun 2026 21:36:33 +0800 Subject: [PATCH] fix(dialer): skip SO_BINDTODEVICE for loopback interface (issue #785) MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit When using IP aliases on loopback (e.g. ip addr add 10.1.1.1/32 dev lo) with policy routing, findInterfaceByIP() resolves the alias IP to the loopback interface. Binding the socket to lo via SO_BINDTODEVICE prevents outbound traffic from reaching non-local destinations. Skip SO_BINDTODEVICE when the resolved interface is loopback — source IP binding via LocalAddr is sufficient for policy routing to steer traffic through the correct physical interface. --- internal/net/dialer/dialer_linux.go | 8 ++++++++ 1 file changed, 8 insertions(+) diff --git a/internal/net/dialer/dialer_linux.go b/internal/net/dialer/dialer_linux.go index bf5f863e..29ce583b 100644 --- a/internal/net/dialer/dialer_linux.go +++ b/internal/net/dialer/dialer_linux.go @@ -11,6 +11,14 @@ func bindDevice(network, address string, fd uintptr, ifceName string) error { return nil } + // Skip SO_BINDTODEVICE for loopback interface — it prevents + // outbound traffic from reaching non-local destinations. + // Source IP binding via LocalAddr is sufficient for policy routing + // when using IP aliases on loopback (e.g. ip addr add 10.1.1.1/32 dev lo). + if ifce, err := net.InterfaceByName(ifceName); err == nil && ifce.Flags&net.FlagLoopback != 0 { + return nil + } + host, _, _ := net.SplitHostPort(address) if ip := net.ParseIP(host); ip != nil && !ip.IsGlobalUnicast() { return nil