From ba060bd0eee01c5a537311591aca7dea5c7f1fca Mon Sep 17 00:00:00 2001 From: Dreamacro <8615343+Dreamacro@users.noreply.github.com> Date: Sun, 25 Oct 2020 20:31:01 +0800 Subject: [PATCH] Fix: should not bind interface on local address --- component/dialer/bind_darwin.go | 45 ++++++++++++++++++--------------- component/dialer/bind_linux.go | 24 +++++++++++++----- 2 files changed, 42 insertions(+), 27 deletions(-) diff --git a/component/dialer/bind_darwin.go b/component/dialer/bind_darwin.go index d46c6735..469054ca 100644 --- a/component/dialer/bind_darwin.go +++ b/component/dialer/bind_darwin.go @@ -5,22 +5,36 @@ import ( "syscall" ) +type controlFn = func(network, address string, c syscall.RawConn) error + +func bindControl(ifaceIdx int) controlFn { + return func(network, address string, c syscall.RawConn) error { + ipStr, _, err := net.SplitHostPort(address) + if err == nil { + ip := net.ParseIP(ipStr) + if ip != nil && !ip.IsGlobalUnicast() { + return nil + } + } + + return c.Control(func(fd uintptr) { + switch network { + case "tcp4", "udp4": + syscall.SetsockoptInt(int(fd), syscall.IPPROTO_IP, syscall.IP_BOUND_IF, ifaceIdx) + case "tcp6", "udp6": + syscall.SetsockoptInt(int(fd), syscall.IPPROTO_IPV6, syscall.IPV6_BOUND_IF, ifaceIdx) + } + }) + } +} + func bindIfaceToDialer(dialer *net.Dialer, ifaceName string) error { iface, err := net.InterfaceByName(ifaceName) if err != nil { return err } - dialer.Control = func(network, address string, c syscall.RawConn) error { - return c.Control(func(fd uintptr) { - switch network { - case "tcp4", "udp4": - syscall.SetsockoptInt(int(fd), syscall.IPPROTO_IP, syscall.IP_BOUND_IF, iface.Index) - case "tcp6", "udp6": - syscall.SetsockoptInt(int(fd), syscall.IPPROTO_IPV6, syscall.IPV6_BOUND_IF, iface.Index) - } - }) - } + dialer.Control = bindControl(iface.Index) return nil } @@ -31,16 +45,7 @@ func bindIfaceToListenConfig(lc *net.ListenConfig, ifaceName string) error { return err } - lc.Control = func(network, address string, c syscall.RawConn) error { - return c.Control(func(fd uintptr) { - switch network { - case "tcp4", "udp4": - syscall.SetsockoptInt(int(fd), syscall.IPPROTO_IP, syscall.IP_BOUND_IF, iface.Index) - case "tcp6", "udp6": - syscall.SetsockoptInt(int(fd), syscall.IPPROTO_IPV6, syscall.IPV6_BOUND_IF, iface.Index) - } - }) - } + lc.Control = bindControl(iface.Index) return nil } diff --git a/component/dialer/bind_linux.go b/component/dialer/bind_linux.go index 8afa3d38..7e9d308d 100644 --- a/component/dialer/bind_linux.go +++ b/component/dialer/bind_linux.go @@ -5,22 +5,32 @@ import ( "syscall" ) -func bindIfaceToDialer(dialer *net.Dialer, ifaceName string) error { - dialer.Control = func(network, address string, c syscall.RawConn) error { +type controlFn = func(network, address string, c syscall.RawConn) error + +func bindControl(ifaceName string) controlFn { + return func(network, address string, c syscall.RawConn) error { + ipStr, _, err := net.SplitHostPort(address) + if err == nil { + ip := net.ParseIP(ipStr) + if ip != nil && !ip.IsGlobalUnicast() { + return nil + } + } + return c.Control(func(fd uintptr) { syscall.BindToDevice(int(fd), ifaceName) }) } +} + +func bindIfaceToDialer(dialer *net.Dialer, ifaceName string) error { + dialer.Control = bindControl(ifaceName) return nil } func bindIfaceToListenConfig(lc *net.ListenConfig, ifaceName string) error { - lc.Control = func(network, address string, c syscall.RawConn) error { - return c.Control(func(fd uintptr) { - syscall.BindToDevice(int(fd), ifaceName) - }) - } + lc.Control = bindControl(ifaceName) return nil }