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 }