github.com/igoogolx/clash@v1.19.8/component/dialer/bind_linux.go (about) 1 package dialer 2 3 import ( 4 "net" 5 "syscall" 6 7 "golang.org/x/sys/unix" 8 ) 9 10 type controlFn = func(network, address string, c syscall.RawConn) error 11 12 func bindControl(ifaceName string, chain controlFn) controlFn { 13 return func(network, address string, c syscall.RawConn) (err error) { 14 defer func() { 15 if err == nil && chain != nil { 16 err = chain(network, address, c) 17 } 18 }() 19 20 ipStr, _, err := net.SplitHostPort(address) 21 if err == nil { 22 ip := net.ParseIP(ipStr) 23 if ip != nil && !ip.IsGlobalUnicast() { 24 return 25 } 26 } 27 28 var innerErr error 29 err = c.Control(func(fd uintptr) { 30 innerErr = unix.BindToDevice(int(fd), ifaceName) 31 }) 32 33 if innerErr != nil { 34 err = innerErr 35 } 36 37 return 38 } 39 } 40 41 func bindIfaceToDialer(ifaceName string, dialer *net.Dialer, _ string, _ net.IP) error { 42 dialer.Control = bindControl(ifaceName, dialer.Control) 43 44 return nil 45 } 46 47 func bindIfaceToListenConfig(ifaceName string, lc *net.ListenConfig, _, address string) (string, error) { 48 lc.Control = bindControl(ifaceName, lc.Control) 49 50 return address, nil 51 }