github.com/kelleygo/clashcore@v1.0.2/component/resolver/resolver.go (about)

     1  package resolver
     2  
     3  import (
     4  	"context"
     5  	"errors"
     6  	"fmt"
     7  	"net"
     8  	"net/netip"
     9  	"strings"
    10  	"time"
    11  
    12  	"github.com/kelleygo/clashcore/common/utils"
    13  	"github.com/kelleygo/clashcore/component/trie"
    14  
    15  	"github.com/miekg/dns"
    16  	"github.com/zhangyunhao116/fastrand"
    17  )
    18  
    19  var (
    20  	// DefaultResolver aim to resolve ip
    21  	DefaultResolver Resolver
    22  
    23  	// ProxyServerHostResolver resolve ip to proxies server host
    24  	ProxyServerHostResolver Resolver
    25  
    26  	// DisableIPv6 means don't resolve ipv6 host
    27  	// default value is true
    28  	DisableIPv6 = true
    29  
    30  	// DefaultHosts aim to resolve hosts
    31  	DefaultHosts = NewHosts(trie.New[HostValue]())
    32  
    33  	// DefaultDNSTimeout defined the default dns request timeout
    34  	DefaultDNSTimeout = time.Second * 5
    35  )
    36  
    37  var (
    38  	ErrIPNotFound   = errors.New("couldn't find ip")
    39  	ErrIPVersion    = errors.New("ip version error")
    40  	ErrIPv6Disabled = errors.New("ipv6 disabled")
    41  )
    42  
    43  type Resolver interface {
    44  	LookupIP(ctx context.Context, host string) (ips []netip.Addr, err error)
    45  	LookupIPv4(ctx context.Context, host string) (ips []netip.Addr, err error)
    46  	LookupIPv6(ctx context.Context, host string) (ips []netip.Addr, err error)
    47  	ExchangeContext(ctx context.Context, m *dns.Msg) (msg *dns.Msg, err error)
    48  	Invalid() bool
    49  }
    50  
    51  // LookupIPv4WithResolver same as LookupIPv4, but with a resolver
    52  func LookupIPv4WithResolver(ctx context.Context, host string, r Resolver) ([]netip.Addr, error) {
    53  	if node, ok := DefaultHosts.Search(host, false); ok {
    54  		if addrs := utils.Filter(node.IPs, func(ip netip.Addr) bool {
    55  			return ip.Is4()
    56  		}); len(addrs) > 0 {
    57  			return addrs, nil
    58  		}
    59  	}
    60  
    61  	ip, err := netip.ParseAddr(host)
    62  	if err == nil {
    63  		if ip.Is4() || ip.Is4In6() {
    64  			return []netip.Addr{ip}, nil
    65  		}
    66  		return []netip.Addr{}, ErrIPVersion
    67  	}
    68  
    69  	if r != nil && r.Invalid() {
    70  		return r.LookupIPv4(ctx, host)
    71  	}
    72  
    73  	ipAddrs, err := net.DefaultResolver.LookupNetIP(ctx, "ip4", host)
    74  	if err != nil {
    75  		return nil, err
    76  	} else if len(ipAddrs) == 0 {
    77  		return nil, ErrIPNotFound
    78  	}
    79  
    80  	return ipAddrs, nil
    81  }
    82  
    83  // LookupIPv4 with a host, return ipv4 list
    84  func LookupIPv4(ctx context.Context, host string) ([]netip.Addr, error) {
    85  	return LookupIPv4WithResolver(ctx, host, DefaultResolver)
    86  }
    87  
    88  // ResolveIPv4WithResolver same as ResolveIPv4, but with a resolver
    89  func ResolveIPv4WithResolver(ctx context.Context, host string, r Resolver) (netip.Addr, error) {
    90  	ips, err := LookupIPv4WithResolver(ctx, host, r)
    91  	if err != nil {
    92  		return netip.Addr{}, err
    93  	} else if len(ips) == 0 {
    94  		return netip.Addr{}, fmt.Errorf("%w: %s", ErrIPNotFound, host)
    95  	}
    96  	return ips[fastrand.Intn(len(ips))], nil
    97  }
    98  
    99  // ResolveIPv4 with a host, return ipv4
   100  func ResolveIPv4(ctx context.Context, host string) (netip.Addr, error) {
   101  	return ResolveIPv4WithResolver(ctx, host, DefaultResolver)
   102  }
   103  
   104  // LookupIPv6WithResolver same as LookupIPv6, but with a resolver
   105  func LookupIPv6WithResolver(ctx context.Context, host string, r Resolver) ([]netip.Addr, error) {
   106  	if DisableIPv6 {
   107  		return nil, ErrIPv6Disabled
   108  	}
   109  
   110  	if node, ok := DefaultHosts.Search(host, false); ok {
   111  		if addrs := utils.Filter(node.IPs, func(ip netip.Addr) bool {
   112  			return ip.Is6()
   113  		}); len(addrs) > 0 {
   114  			return addrs, nil
   115  		}
   116  	}
   117  
   118  	if ip, err := netip.ParseAddr(host); err == nil {
   119  		if strings.Contains(host, ":") {
   120  			return []netip.Addr{ip}, nil
   121  		}
   122  		return nil, ErrIPVersion
   123  	}
   124  
   125  	if r != nil && r.Invalid() {
   126  		return r.LookupIPv6(ctx, host)
   127  	}
   128  
   129  	ipAddrs, err := net.DefaultResolver.LookupNetIP(ctx, "ip6", host)
   130  	if err != nil {
   131  		return nil, err
   132  	} else if len(ipAddrs) == 0 {
   133  		return nil, ErrIPNotFound
   134  	}
   135  
   136  	return ipAddrs, nil
   137  }
   138  
   139  // LookupIPv6 with a host, return ipv6 list
   140  func LookupIPv6(ctx context.Context, host string) ([]netip.Addr, error) {
   141  	return LookupIPv6WithResolver(ctx, host, DefaultResolver)
   142  }
   143  
   144  // ResolveIPv6WithResolver same as ResolveIPv6, but with a resolver
   145  func ResolveIPv6WithResolver(ctx context.Context, host string, r Resolver) (netip.Addr, error) {
   146  	ips, err := LookupIPv6WithResolver(ctx, host, r)
   147  	if err != nil {
   148  		return netip.Addr{}, err
   149  	} else if len(ips) == 0 {
   150  		return netip.Addr{}, fmt.Errorf("%w: %s", ErrIPNotFound, host)
   151  	}
   152  	return ips[fastrand.Intn(len(ips))], nil
   153  }
   154  
   155  func ResolveIPv6(ctx context.Context, host string) (netip.Addr, error) {
   156  	return ResolveIPv6WithResolver(ctx, host, DefaultResolver)
   157  }
   158  
   159  // LookupIPWithResolver same as LookupIP, but with a resolver
   160  func LookupIPWithResolver(ctx context.Context, host string, r Resolver) ([]netip.Addr, error) {
   161  	if node, ok := DefaultHosts.Search(host, false); ok {
   162  		return node.IPs, nil
   163  	}
   164  
   165  	if r != nil && r.Invalid() {
   166  		if DisableIPv6 {
   167  			return r.LookupIPv4(ctx, host)
   168  		}
   169  		return r.LookupIP(ctx, host)
   170  	} else if DisableIPv6 {
   171  		return LookupIPv4WithResolver(ctx, host, r)
   172  	}
   173  
   174  	if ip, err := netip.ParseAddr(host); err == nil {
   175  		return []netip.Addr{ip}, nil
   176  	}
   177  
   178  	ips, err := net.DefaultResolver.LookupNetIP(ctx, "ip", host)
   179  	if err != nil {
   180  		return nil, err
   181  	} else if len(ips) == 0 {
   182  		return nil, ErrIPNotFound
   183  	}
   184  
   185  	return ips, nil
   186  }
   187  
   188  // LookupIP with a host, return ip
   189  func LookupIP(ctx context.Context, host string) ([]netip.Addr, error) {
   190  	return LookupIPWithResolver(ctx, host, DefaultResolver)
   191  }
   192  
   193  // ResolveIPWithResolver same as ResolveIP, but with a resolver
   194  func ResolveIPWithResolver(ctx context.Context, host string, r Resolver) (netip.Addr, error) {
   195  	ips, err := LookupIPWithResolver(ctx, host, r)
   196  	if err != nil {
   197  		return netip.Addr{}, err
   198  	} else if len(ips) == 0 {
   199  		return netip.Addr{}, fmt.Errorf("%w: %s", ErrIPNotFound, host)
   200  	}
   201  	ipv4s, ipv6s := SortationAddr(ips)
   202  	if len(ipv4s) > 0 {
   203  		return ipv4s[fastrand.Intn(len(ipv4s))], nil
   204  	}
   205  	return ipv6s[fastrand.Intn(len(ipv6s))], nil
   206  }
   207  
   208  // ResolveIP with a host, return ip and priority return TypeA
   209  func ResolveIP(ctx context.Context, host string) (netip.Addr, error) {
   210  	return ResolveIPWithResolver(ctx, host, DefaultResolver)
   211  }
   212  
   213  // ResolveIPv4ProxyServerHost proxies server host only
   214  func ResolveIPv4ProxyServerHost(ctx context.Context, host string) (netip.Addr, error) {
   215  	if ProxyServerHostResolver != nil {
   216  		return ResolveIPv4WithResolver(ctx, host, ProxyServerHostResolver)
   217  	}
   218  	return ResolveIPv4(ctx, host)
   219  }
   220  
   221  // ResolveIPv6ProxyServerHost proxies server host only
   222  func ResolveIPv6ProxyServerHost(ctx context.Context, host string) (netip.Addr, error) {
   223  	if ProxyServerHostResolver != nil {
   224  		return ResolveIPv6WithResolver(ctx, host, ProxyServerHostResolver)
   225  	}
   226  	return ResolveIPv6(ctx, host)
   227  }
   228  
   229  // ResolveProxyServerHost proxies server host only
   230  func ResolveProxyServerHost(ctx context.Context, host string) (netip.Addr, error) {
   231  	if ProxyServerHostResolver != nil {
   232  		return ResolveIPWithResolver(ctx, host, ProxyServerHostResolver)
   233  	}
   234  	return ResolveIP(ctx, host)
   235  }
   236  
   237  func LookupIPv6ProxyServerHost(ctx context.Context, host string) ([]netip.Addr, error) {
   238  	if ProxyServerHostResolver != nil {
   239  		return LookupIPv6WithResolver(ctx, host, ProxyServerHostResolver)
   240  	}
   241  	return LookupIPv6(ctx, host)
   242  }
   243  
   244  func LookupIPv4ProxyServerHost(ctx context.Context, host string) ([]netip.Addr, error) {
   245  	if ProxyServerHostResolver != nil {
   246  		return LookupIPv4WithResolver(ctx, host, ProxyServerHostResolver)
   247  	}
   248  	return LookupIPv4(ctx, host)
   249  }
   250  
   251  func LookupIPProxyServerHost(ctx context.Context, host string) ([]netip.Addr, error) {
   252  	if ProxyServerHostResolver != nil {
   253  		return LookupIPWithResolver(ctx, host, ProxyServerHostResolver)
   254  	}
   255  	return LookupIP(ctx, host)
   256  }
   257  
   258  func SortationAddr(ips []netip.Addr) (ipv4s, ipv6s []netip.Addr) {
   259  	for _, v := range ips {
   260  		if v.Unmap().Is4() {
   261  			ipv4s = append(ipv4s, v)
   262  		} else {
   263  			ipv6s = append(ipv6s, v)
   264  		}
   265  	}
   266  	return
   267  }