github.com/chwjbn/xclash@v0.2.0/component/resolver/resolver.go (about)

     1  package resolver
     2  
     3  import (
     4  	"context"
     5  	"errors"
     6  	"math/rand"
     7  	"net"
     8  	"strings"
     9  	"time"
    10  
    11  	"github.com/chwjbn/xclash/component/trie"
    12  )
    13  
    14  var (
    15  	// DefaultResolver aim to resolve ip
    16  	DefaultResolver Resolver
    17  
    18  	// DisableIPv6 means don't resolve ipv6 host
    19  	// default value is true
    20  	DisableIPv6 = true
    21  
    22  	// DefaultHosts aim to resolve hosts
    23  	DefaultHosts = trie.New()
    24  
    25  	// DefaultDNSTimeout defined the default dns request timeout
    26  	DefaultDNSTimeout = time.Second * 5
    27  )
    28  
    29  var (
    30  	ErrIPNotFound   = errors.New("couldn't find ip")
    31  	ErrIPVersion    = errors.New("ip version error")
    32  	ErrIPv6Disabled = errors.New("ipv6 disabled")
    33  )
    34  
    35  type Resolver interface {
    36  	ResolveIP(host string) (ip net.IP, err error)
    37  	ResolveIPv4(host string) (ip net.IP, err error)
    38  	ResolveIPv6(host string) (ip net.IP, err error)
    39  }
    40  
    41  // ResolveIPv4 with a host, return ipv4
    42  func ResolveIPv4(host string) (net.IP, error) {
    43  	if node := DefaultHosts.Search(host); node != nil {
    44  		if ip := node.Data.(net.IP).To4(); ip != nil {
    45  			return ip, nil
    46  		}
    47  	}
    48  
    49  	ip := net.ParseIP(host)
    50  	if ip != nil {
    51  		if !strings.Contains(host, ":") {
    52  			return ip, nil
    53  		}
    54  		return nil, ErrIPVersion
    55  	}
    56  
    57  	if DefaultResolver != nil {
    58  		return DefaultResolver.ResolveIPv4(host)
    59  	}
    60  
    61  	ctx, cancel := context.WithTimeout(context.Background(), DefaultDNSTimeout)
    62  	defer cancel()
    63  	ipAddrs, err := net.DefaultResolver.LookupIP(ctx, "ip4", host)
    64  	if err != nil {
    65  		return nil, err
    66  	} else if len(ipAddrs) == 0 {
    67  		return nil, ErrIPNotFound
    68  	}
    69  
    70  	return ipAddrs[rand.Intn(len(ipAddrs))], nil
    71  }
    72  
    73  // ResolveIPv6 with a host, return ipv6
    74  func ResolveIPv6(host string) (net.IP, error) {
    75  	if DisableIPv6 {
    76  		return nil, ErrIPv6Disabled
    77  	}
    78  
    79  	if node := DefaultHosts.Search(host); node != nil {
    80  		if ip := node.Data.(net.IP).To16(); ip != nil {
    81  			return ip, nil
    82  		}
    83  	}
    84  
    85  	ip := net.ParseIP(host)
    86  	if ip != nil {
    87  		if strings.Contains(host, ":") {
    88  			return ip, nil
    89  		}
    90  		return nil, ErrIPVersion
    91  	}
    92  
    93  	if DefaultResolver != nil {
    94  		return DefaultResolver.ResolveIPv6(host)
    95  	}
    96  
    97  	ctx, cancel := context.WithTimeout(context.Background(), DefaultDNSTimeout)
    98  	defer cancel()
    99  	ipAddrs, err := net.DefaultResolver.LookupIP(ctx, "ip6", host)
   100  	if err != nil {
   101  		return nil, err
   102  	} else if len(ipAddrs) == 0 {
   103  		return nil, ErrIPNotFound
   104  	}
   105  
   106  	return ipAddrs[rand.Intn(len(ipAddrs))], nil
   107  }
   108  
   109  // ResolveIPWithResolver same as ResolveIP, but with a resolver
   110  func ResolveIPWithResolver(host string, r Resolver) (net.IP, error) {
   111  	if node := DefaultHosts.Search(host); node != nil {
   112  		return node.Data.(net.IP), nil
   113  	}
   114  
   115  	if r != nil {
   116  		if DisableIPv6 {
   117  			return r.ResolveIPv4(host)
   118  		}
   119  		return r.ResolveIP(host)
   120  	} else if DisableIPv6 {
   121  		return ResolveIPv4(host)
   122  	}
   123  
   124  	ip := net.ParseIP(host)
   125  	if ip != nil {
   126  		return ip, nil
   127  	}
   128  
   129  	ipAddr, err := net.ResolveIPAddr("ip", host)
   130  	if err != nil {
   131  		return nil, err
   132  	}
   133  
   134  	return ipAddr.IP, nil
   135  }
   136  
   137  // ResolveIP with a host, return ip
   138  func ResolveIP(host string) (net.IP, error) {
   139  	return ResolveIPWithResolver(host, DefaultResolver)
   140  }