github.com/yaling888/clash@v1.53.0/component/dialer/bind_fallback.go (about) 1 package dialer 2 3 import ( 4 "net" 5 "net/netip" 6 "strconv" 7 "strings" 8 9 "github.com/yaling888/clash/component/iface" 10 ) 11 12 func lookupLocalAddr(ifaceName string, network string, destination netip.Addr, port int) (net.Addr, error) { 13 ifaceObj, err := iface.ResolveInterface(ifaceName) 14 if err != nil { 15 return nil, err 16 } 17 18 var addr *netip.Prefix 19 switch network { 20 case "udp4", "tcp4": 21 addr, err = ifaceObj.PickIPv4Addr(destination) 22 case "tcp6", "udp6": 23 addr, err = ifaceObj.PickIPv6Addr(destination) 24 default: 25 if destination.IsValid() { 26 if destination.Is4() { 27 addr, err = ifaceObj.PickIPv4Addr(destination) 28 } else { 29 addr, err = ifaceObj.PickIPv6Addr(destination) 30 } 31 } else { 32 addr, err = ifaceObj.PickIPv4Addr(destination) 33 } 34 } 35 if err != nil { 36 return nil, err 37 } 38 39 if strings.HasPrefix(network, "tcp") { 40 return &net.TCPAddr{ 41 IP: addr.Addr().AsSlice(), 42 Port: port, 43 }, nil 44 } else if strings.HasPrefix(network, "udp") { 45 return &net.UDPAddr{ 46 IP: addr.Addr().AsSlice(), 47 Port: port, 48 }, nil 49 } 50 51 return nil, iface.ErrAddrNotFound 52 } 53 54 func fallbackBindIfaceToListenConfig(ifaceName string, _ *net.ListenConfig, network, address string) (string, error) { 55 _, port, err := net.SplitHostPort(address) 56 if err != nil { 57 port = "0" 58 } 59 60 local, _ := strconv.ParseUint(port, 10, 16) 61 62 addr, err := lookupLocalAddr(ifaceName, network, netip.Addr{}, int(local)) 63 if err != nil { 64 return "", err 65 } 66 67 return addr.String(), nil 68 }