github.com/yaling888/clash@v1.53.0/component/dialer/bind_darwin.go (about) 1 package dialer 2 3 import ( 4 "net" 5 "net/netip" 6 "syscall" 7 8 "golang.org/x/sys/unix" 9 10 "github.com/yaling888/clash/component/iface" 11 ) 12 13 type controlFn = func(network, address string, c syscall.RawConn) error 14 15 func bindControl(ifaceIdx int, chain controlFn) controlFn { 16 return func(network, address string, c syscall.RawConn) (err error) { 17 defer func() { 18 if err == nil && chain != nil { 19 err = chain(network, address, c) 20 } 21 }() 22 23 addrPort, err := netip.ParseAddrPort(address) 24 if err == nil && !addrPort.Addr().IsGlobalUnicast() { 25 return 26 } 27 28 var innerErr error 29 err = c.Control(func(fd uintptr) { 30 switch network { 31 case "tcp4", "udp4": 32 innerErr = unix.SetsockoptInt(int(fd), unix.IPPROTO_IP, unix.IP_BOUND_IF, ifaceIdx) 33 case "tcp6", "udp6": 34 innerErr = unix.SetsockoptInt(int(fd), unix.IPPROTO_IPV6, unix.IPV6_BOUND_IF, ifaceIdx) 35 } 36 }) 37 38 if innerErr != nil { 39 err = innerErr 40 } 41 42 return 43 } 44 } 45 46 func bindIfaceToDialer(ifaceName string, dialer *net.Dialer, _ string, _ netip.Addr) error { 47 ifaceObj, err := iface.ResolveInterface(ifaceName) 48 if err != nil { 49 return err 50 } 51 52 dialer.Control = bindControl(ifaceObj.Index, dialer.Control) 53 return nil 54 } 55 56 func bindIfaceToListenConfig(ifaceName string, lc *net.ListenConfig, _, address string) (string, error) { 57 ifaceObj, err := iface.ResolveInterface(ifaceName) 58 if err != nil { 59 return "", err 60 } 61 62 lc.Control = bindControl(ifaceObj.Index, lc.Control) 63 return address, nil 64 } 65 66 func WithBindToInterfaceControlFn(interfaceName string) func(network, address string, c syscall.RawConn) (err error) { 67 return func(network, address string, c syscall.RawConn) (err error) { 68 if interfaceName == "" { 69 return nil 70 } 71 72 var ( 73 innerErr error 74 ifaceObj *iface.Interface 75 ) 76 77 ifaceObj, err = iface.ResolveInterface(interfaceName) 78 if err != nil { 79 return 80 } 81 82 err = c.Control(func(fd uintptr) { 83 switch network { 84 case "udp4": 85 innerErr = unix.SetsockoptInt(int(fd), unix.IPPROTO_IP, unix.IP_BOUND_IF, ifaceObj.Index) 86 case "udp6": 87 innerErr = unix.SetsockoptInt(int(fd), unix.IPPROTO_IPV6, unix.IPV6_BOUND_IF, ifaceObj.Index) 88 } 89 }) 90 91 if innerErr != nil { 92 err = innerErr 93 } 94 95 return 96 } 97 }