github.com/igoogolx/clash@v1.19.8/component/dialer/fallbackbind.go (about) 1 package dialer 2 3 import ( 4 "net" 5 "strconv" 6 "strings" 7 8 "github.com/igoogolx/clash/component/iface" 9 ) 10 11 func lookupLocalAddr(ifaceName string, network string, destination net.IP, port int) (net.Addr, error) { 12 ifaceObj, err := iface.ResolveInterface(ifaceName) 13 if err != nil { 14 return nil, err 15 } 16 17 var addr *net.IPNet 18 switch network { 19 case "udp4", "tcp4": 20 addr, err = ifaceObj.PickIPv4Addr(destination) 21 case "tcp6", "udp6": 22 addr, err = ifaceObj.PickIPv6Addr(destination) 23 default: 24 if destination != nil { 25 if destination.To4() != nil { 26 addr, err = ifaceObj.PickIPv4Addr(destination) 27 } else { 28 addr, err = ifaceObj.PickIPv6Addr(destination) 29 } 30 } else { 31 addr, err = ifaceObj.PickIPv4Addr(destination) 32 } 33 } 34 if err != nil { 35 return nil, err 36 } 37 38 if strings.HasPrefix(network, "tcp") { 39 return &net.TCPAddr{ 40 IP: addr.IP, 41 Port: port, 42 }, nil 43 } else if strings.HasPrefix(network, "udp") { 44 return &net.UDPAddr{ 45 IP: addr.IP, 46 Port: port, 47 }, nil 48 } 49 50 return nil, iface.ErrAddrNotFound 51 } 52 53 func fallbackBindIfaceToDialer(ifaceName string, dialer *net.Dialer, network string, destination net.IP) error { 54 if !destination.IsGlobalUnicast() { 55 return nil 56 } 57 58 local := uint64(0) 59 if dialer.LocalAddr != nil { 60 _, port, err := net.SplitHostPort(dialer.LocalAddr.String()) 61 if err == nil { 62 local, _ = strconv.ParseUint(port, 10, 16) 63 } 64 } 65 66 addr, err := lookupLocalAddr(ifaceName, network, destination, int(local)) 67 if err != nil { 68 return err 69 } 70 71 dialer.LocalAddr = addr 72 73 return nil 74 } 75 76 func fallbackBindIfaceToListenConfig(ifaceName string, _ *net.ListenConfig, network, address string) (string, error) { 77 _, port, err := net.SplitHostPort(address) 78 if err != nil { 79 port = "0" 80 } 81 82 local, _ := strconv.ParseUint(port, 10, 16) 83 84 addr, err := lookupLocalAddr(ifaceName, network, nil, int(local)) 85 if err != nil { 86 return "", err 87 } 88 89 return addr.String(), nil 90 }