github.com/chwjbn/xclash@v0.2.0/component/dialer/bind_darwin.go (about) 1 package dialer 2 3 import ( 4 "net" 5 "syscall" 6 7 "golang.org/x/sys/unix" 8 9 "github.com/chwjbn/xclash/component/iface" 10 ) 11 12 type controlFn = func(network, address string, c syscall.RawConn) error 13 14 func bindControl(ifaceIdx int, chain controlFn) controlFn { 15 return func(network, address string, c syscall.RawConn) (err error) { 16 defer func() { 17 if err == nil && chain != nil { 18 err = chain(network, address, c) 19 } 20 }() 21 22 ipStr, _, err := net.SplitHostPort(address) 23 if err == nil { 24 ip := net.ParseIP(ipStr) 25 if ip != nil && !ip.IsGlobalUnicast() { 26 return 27 } 28 } 29 30 var innerErr error 31 err = c.Control(func(fd uintptr) { 32 switch network { 33 case "tcp4", "udp4": 34 innerErr = unix.SetsockoptInt(int(fd), unix.IPPROTO_IP, unix.IP_BOUND_IF, ifaceIdx) 35 case "tcp6", "udp6": 36 innerErr = unix.SetsockoptInt(int(fd), unix.IPPROTO_IPV6, unix.IPV6_BOUND_IF, ifaceIdx) 37 } 38 }) 39 40 if innerErr != nil { 41 err = innerErr 42 } 43 44 return 45 } 46 } 47 48 func bindIfaceToDialer(ifaceName string, dialer *net.Dialer, _ string, _ net.IP) error { 49 ifaceObj, err := iface.ResolveInterface(ifaceName) 50 if err != nil { 51 return err 52 } 53 54 dialer.Control = bindControl(ifaceObj.Index, dialer.Control) 55 return nil 56 } 57 58 func bindIfaceToListenConfig(ifaceName string, lc *net.ListenConfig, _, address string) (string, error) { 59 ifaceObj, err := iface.ResolveInterface(ifaceName) 60 if err != nil { 61 return "", err 62 } 63 64 lc.Control = bindControl(ifaceObj.Index, lc.Control) 65 return address, nil 66 }