github.com/yaling888/clash@v1.53.0/component/dialer/bind_linux.go (about) 1 package dialer 2 3 import ( 4 "net" 5 "net/netip" 6 "syscall" 7 8 "golang.org/x/sys/unix" 9 ) 10 11 type controlFn = func(network, address string, c syscall.RawConn) error 12 13 func bindControl(ifaceName string, chain controlFn) controlFn { 14 return func(network, address string, c syscall.RawConn) (err error) { 15 defer func() { 16 if err == nil && chain != nil { 17 err = chain(network, address, c) 18 } 19 }() 20 21 addrPort, err := netip.ParseAddrPort(address) 22 if err == nil && !addrPort.Addr().IsGlobalUnicast() { 23 return 24 } 25 26 var innerErr error 27 err = c.Control(func(fd uintptr) { 28 innerErr = unix.BindToDevice(int(fd), ifaceName) 29 }) 30 31 if innerErr != nil { 32 err = innerErr 33 } 34 35 return 36 } 37 } 38 39 func bindIfaceToDialer(ifaceName string, dialer *net.Dialer, _ string, _ netip.Addr) error { 40 dialer.Control = bindControl(ifaceName, dialer.Control) 41 42 return nil 43 } 44 45 func bindIfaceToListenConfig(ifaceName string, lc *net.ListenConfig, _, address string) (string, error) { 46 lc.Control = bindControl(ifaceName, lc.Control) 47 48 return address, nil 49 } 50 51 func WithBindToInterfaceControlFn(interfaceName string) func(network, address string, c syscall.RawConn) (err error) { 52 return func(network, address string, c syscall.RawConn) (err error) { 53 if interfaceName == "" { 54 return nil 55 } 56 57 var innerErr error 58 err = c.Control(func(fd uintptr) { 59 innerErr = unix.BindToDevice(int(fd), interfaceName) 60 }) 61 62 if innerErr != nil { 63 err = innerErr 64 } 65 66 return 67 } 68 }