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  }