github.com/metacubex/mihomo@v1.18.5/component/dialer/bind.go (about) 1 package dialer 2 3 import ( 4 "net" 5 "net/netip" 6 "strconv" 7 "strings" 8 9 "github.com/metacubex/mihomo/component/iface" 10 ) 11 12 func LookupLocalAddrFromIfaceName(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 destination = destination.Unmap() 18 19 var addr netip.Prefix 20 switch network { 21 case "udp4", "tcp4": 22 addr, err = ifaceObj.PickIPv4Addr(destination) 23 case "tcp6", "udp6": 24 addr, err = ifaceObj.PickIPv6Addr(destination) 25 default: 26 if destination.IsValid() { 27 if destination.Is4() { 28 addr, err = ifaceObj.PickIPv4Addr(destination) 29 } else { 30 addr, err = ifaceObj.PickIPv6Addr(destination) 31 } 32 } else { 33 addr, err = ifaceObj.PickIPv4Addr(destination) 34 } 35 } 36 if err != nil { 37 return nil, err 38 } 39 40 if strings.HasPrefix(network, "tcp") { 41 return &net.TCPAddr{ 42 IP: addr.Addr().AsSlice(), 43 Port: port, 44 }, nil 45 } else if strings.HasPrefix(network, "udp") { 46 return &net.UDPAddr{ 47 IP: addr.Addr().AsSlice(), 48 Port: port, 49 }, nil 50 } 51 52 return nil, iface.ErrAddrNotFound 53 } 54 55 func fallbackBindIfaceToDialer(ifaceName string, dialer *net.Dialer, network string, destination netip.Addr) error { 56 if !destination.IsGlobalUnicast() { 57 return nil 58 } 59 60 local := uint64(0) 61 if dialer.LocalAddr != nil { 62 _, port, err := net.SplitHostPort(dialer.LocalAddr.String()) 63 if err == nil { 64 local, _ = strconv.ParseUint(port, 10, 16) 65 } 66 } 67 68 addr, err := LookupLocalAddrFromIfaceName(ifaceName, network, destination, int(local)) 69 if err != nil { 70 return err 71 } 72 73 dialer.LocalAddr = addr 74 75 return nil 76 } 77 78 func fallbackBindIfaceToListenConfig(ifaceName string, _ *net.ListenConfig, network, address string, rAddrPort netip.AddrPort) (string, error) { 79 _, port, err := net.SplitHostPort(address) 80 if err != nil { 81 port = "0" 82 } 83 84 local, _ := strconv.ParseUint(port, 10, 16) 85 86 addr, err := LookupLocalAddrFromIfaceName(ifaceName, network, netip.Addr{}, int(local)) 87 if err != nil { 88 return "", err 89 } 90 91 return addr.String(), nil 92 } 93 94 func fallbackParseNetwork(network string, addr netip.Addr) string { 95 // fix fallbackBindIfaceToListenConfig() force bind to an ipv4 address 96 if !strings.HasSuffix(network, "4") && 97 !strings.HasSuffix(network, "6") && 98 addr.Unmap().Is6() { 99 network += "6" 100 } 101 return network 102 }