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  }