Fix: should not bind interface on local address

This commit is contained in:
Dreamacro 2020-10-25 20:31:01 +08:00
parent b1795b1e3d
commit ba060bd0ee
2 changed files with 42 additions and 27 deletions

View file

@ -5,22 +5,36 @@ import (
"syscall" "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 { func bindIfaceToDialer(dialer *net.Dialer, ifaceName string) error {
iface, err := net.InterfaceByName(ifaceName) iface, err := net.InterfaceByName(ifaceName)
if err != nil { if err != nil {
return err return err
} }
dialer.Control = func(network, address string, c syscall.RawConn) error { dialer.Control = bindControl(iface.Index)
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)
}
})
}
return nil return nil
} }
@ -31,16 +45,7 @@ func bindIfaceToListenConfig(lc *net.ListenConfig, ifaceName string) error {
return err return err
} }
lc.Control = func(network, address string, c syscall.RawConn) error { lc.Control = bindControl(iface.Index)
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)
}
})
}
return nil return nil
} }

View file

@ -5,22 +5,32 @@ import (
"syscall" "syscall"
) )
func bindIfaceToDialer(dialer *net.Dialer, ifaceName string) error { type controlFn = func(network, address string, c syscall.RawConn) error
dialer.Control = 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) { return c.Control(func(fd uintptr) {
syscall.BindToDevice(int(fd), ifaceName) syscall.BindToDevice(int(fd), ifaceName)
}) })
} }
}
func bindIfaceToDialer(dialer *net.Dialer, ifaceName string) error {
dialer.Control = bindControl(ifaceName)
return nil return nil
} }
func bindIfaceToListenConfig(lc *net.ListenConfig, ifaceName string) error { func bindIfaceToListenConfig(lc *net.ListenConfig, ifaceName string) error {
lc.Control = func(network, address string, c syscall.RawConn) error { lc.Control = bindControl(ifaceName)
return c.Control(func(fd uintptr) {
syscall.BindToDevice(int(fd), ifaceName)
})
}
return nil return nil
} }