github.com/igoogolx/clash@v1.19.8/component/resolver/resolver.go (about)

     1  package resolver
     2  
     3  import (
     4  	"context"
     5  	"errors"
     6  	"fmt"
     7  	"math/rand"
     8  	"net"
     9  	"strings"
    10  	"time"
    11  
    12  	"github.com/igoogolx/clash/component/trie"
    13  
    14  	"github.com/miekg/dns"
    15  )
    16  
    17  var (
    18  	// DefaultResolver aim to resolve ip
    19  	DefaultResolver Resolver
    20  
    21  	// DisableIPv6 means don't resolve ipv6 host
    22  	// default value is true
    23  	DisableIPv6 = true
    24  
    25  	// DefaultHosts aim to resolve hosts
    26  	DefaultHosts = trie.New()
    27  
    28  	// DefaultDNSTimeout defined the default dns request timeout
    29  	DefaultDNSTimeout = time.Second * 5
    30  )
    31  
    32  var (
    33  	ErrIPNotFound   = errors.New("couldn't find ip")
    34  	ErrIPVersion    = errors.New("ip version error")
    35  	ErrIPv6Disabled = errors.New("ipv6 disabled")
    36  )
    37  
    38  type Resolver interface {
    39  	LookupIP(ctx context.Context, host string) ([]net.IP, error)
    40  	LookupIPv4(ctx context.Context, host string) ([]net.IP, error)
    41  	LookupIPv6(ctx context.Context, host string) ([]net.IP, error)
    42  	ResolveIP(host string) (ip net.IP, err error)
    43  	ResolveIPv4(host string) (ip net.IP, err error)
    44  	ResolveIPv6(host string) (ip net.IP, err error)
    45  	ExchangeContext(ctx context.Context, m *dns.Msg) (msg *dns.Msg, err error)
    46  }
    47  
    48  // LookupIPv4 with a host, return ipv4 list
    49  func LookupIPv4(ctx context.Context, host string) ([]net.IP, error) {
    50  	if node := DefaultHosts.Search(host); node != nil {
    51  		if ip := node.Data.(net.IP).To4(); ip != nil {
    52  			return []net.IP{ip}, nil
    53  		}
    54  	}
    55  
    56  	ip := net.ParseIP(host)
    57  	if ip != nil {
    58  		if !strings.Contains(host, ":") {
    59  			return []net.IP{ip}, nil
    60  		}
    61  		return nil, ErrIPVersion
    62  	}
    63  
    64  	if DefaultResolver != nil {
    65  		return DefaultResolver.LookupIPv4(ctx, host)
    66  	}
    67  
    68  	ctx, cancel := context.WithTimeout(context.Background(), DefaultDNSTimeout)
    69  	defer cancel()
    70  	ipAddrs, err := net.DefaultResolver.LookupIP(ctx, "ip4", host)
    71  	if err != nil {
    72  		return nil, err
    73  	} else if len(ipAddrs) == 0 {
    74  		return nil, ErrIPNotFound
    75  	}
    76  
    77  	return ipAddrs, nil
    78  }
    79  
    80  // ResolveIPv4 with a host, return ipv4
    81  func ResolveIPv4(host string) (net.IP, error) {
    82  	ips, err := LookupIPv4(context.Background(), host)
    83  	if err != nil {
    84  		return nil, err
    85  	} else if len(ips) == 0 {
    86  		return nil, fmt.Errorf("%w: %s", ErrIPNotFound, host)
    87  	}
    88  	return ips[rand.Intn(len(ips))], nil
    89  }
    90  
    91  // LookupIPv6 with a host, return ipv6 list
    92  func LookupIPv6(ctx context.Context, host string) ([]net.IP, error) {
    93  	if DisableIPv6 {
    94  		return nil, ErrIPv6Disabled
    95  	}
    96  
    97  	if node := DefaultHosts.Search(host); node != nil {
    98  		if ip := node.Data.(net.IP).To16(); ip != nil {
    99  			return []net.IP{ip}, nil
   100  		}
   101  	}
   102  
   103  	ip := net.ParseIP(host)
   104  	if ip != nil {
   105  		if strings.Contains(host, ":") {
   106  			return []net.IP{ip}, nil
   107  		}
   108  		return nil, ErrIPVersion
   109  	}
   110  
   111  	if DefaultResolver != nil {
   112  		return DefaultResolver.LookupIPv6(ctx, host)
   113  	}
   114  
   115  	ctx, cancel := context.WithTimeout(context.Background(), DefaultDNSTimeout)
   116  	defer cancel()
   117  	ipAddrs, err := net.DefaultResolver.LookupIP(ctx, "ip6", host)
   118  	if err != nil {
   119  		return nil, err
   120  	} else if len(ipAddrs) == 0 {
   121  		return nil, ErrIPNotFound
   122  	}
   123  
   124  	return ipAddrs, nil
   125  }
   126  
   127  // ResolveIPv6 with a host, return ipv6
   128  func ResolveIPv6(host string) (net.IP, error) {
   129  	ips, err := LookupIPv6(context.Background(), host)
   130  	if err != nil {
   131  		return nil, err
   132  	} else if len(ips) == 0 {
   133  		return nil, fmt.Errorf("%w: %s", ErrIPNotFound, host)
   134  	}
   135  	return ips[rand.Intn(len(ips))], nil
   136  }
   137  
   138  // LookupIPWithResolver same as ResolveIP, but with a resolver
   139  func LookupIPWithResolver(ctx context.Context, host string, r Resolver) ([]net.IP, error) {
   140  	if node := DefaultHosts.Search(host); node != nil {
   141  		return []net.IP{node.Data.(net.IP)}, nil
   142  	}
   143  
   144  	if r != nil {
   145  		if DisableIPv6 {
   146  			return r.LookupIPv4(ctx, host)
   147  		}
   148  		return r.LookupIP(ctx, host)
   149  	} else if DisableIPv6 {
   150  		return LookupIPv4(ctx, host)
   151  	}
   152  
   153  	ip := net.ParseIP(host)
   154  	if ip != nil {
   155  		return []net.IP{ip}, nil
   156  	}
   157  
   158  	ips, err := net.DefaultResolver.LookupIP(ctx, "ip", host)
   159  	if err != nil {
   160  		return nil, err
   161  	} else if len(ips) == 0 {
   162  		return nil, ErrIPNotFound
   163  	}
   164  
   165  	return ips, nil
   166  }
   167  
   168  // ResolveIP with a host, return ip
   169  func LookupIP(ctx context.Context, host string) ([]net.IP, error) {
   170  	return LookupIPWithResolver(ctx, host, DefaultResolver)
   171  }
   172  
   173  // ResolveIP with a host, return ip
   174  func ResolveIP(host string) (net.IP, error) {
   175  	ips, err := LookupIP(context.Background(), host)
   176  	if err != nil {
   177  		return nil, err
   178  	} else if len(ips) == 0 {
   179  		return nil, fmt.Errorf("%w: %s", ErrIPNotFound, host)
   180  	}
   181  	return ips[rand.Intn(len(ips))], nil
   182  }