github.com/yaling888/clash@v1.53.0/component/resolver/resolver.go (about) 1 package resolver 2 3 import ( 4 "context" 5 "errors" 6 "math/rand/v2" 7 "net" 8 "net/netip" 9 "time" 10 11 "github.com/miekg/dns" 12 "github.com/samber/lo" 13 14 "github.com/yaling888/clash/component/trie" 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 // RemoteDnsResolve reports whether TCP/UDP handler should be remote resolve DNS 26 // default value is true 27 RemoteDnsResolve = true 28 29 // DefaultHosts aim to resolve hosts 30 DefaultHosts = trie.New[netip.Addr]() 31 32 // DefaultDNSTimeout defined the default dns request timeout 33 DefaultDNSTimeout = time.Second * 5 34 35 needProxyHostIPv6 = false 36 ) 37 38 var ( 39 ErrIPNotFound = errors.New("couldn't find ip") 40 ErrIPVersion = errors.New("ip version error") 41 ErrIPv6Disabled = errors.New("ipv6 disabled") 42 ) 43 44 const ( 45 proxyServerHostKey = ipContextKey("key-lookup-proxy-server-ip") 46 proxyKey = ipContextKey("key-lookup-by-proxy") 47 ) 48 49 const ( 50 typeNone uint16 = 0 51 typeA uint16 = 1 52 typeAAAA uint16 = 28 53 ) 54 55 type ipContextKey string 56 57 type Resolver interface { 58 LookupIP(ctx context.Context, host string) ([]netip.Addr, error) 59 LookupIPv4(ctx context.Context, host string) ([]netip.Addr, error) 60 LookupIPv6(ctx context.Context, host string) ([]netip.Addr, error) 61 ResolveIP(host string) (ip netip.Addr, err error) 62 ResolveIPv4(host string) (ip netip.Addr, err error) 63 ResolveIPv6(host string) (ip netip.Addr, err error) 64 ExchangeContext(ctx context.Context, m *dns.Msg) (msg *dns.Msg, source string, err error) 65 ExchangeContextWithoutCache(ctx context.Context, m *dns.Msg) (msg *dns.Msg, source string, err error) 66 RemoveCache(host string) 67 } 68 69 // LookupIP with a host, return ip list 70 func LookupIP(ctx context.Context, host string) ([]netip.Addr, error) { 71 return LookupIPByResolver(ctx, host, DefaultResolver) 72 } 73 74 // LookupIPv4 with a host, return ipv4 list 75 func LookupIPv4(ctx context.Context, host string) ([]netip.Addr, error) { 76 return lookupIPByResolverAndType(ctx, host, DefaultResolver, typeA, false) 77 } 78 79 // LookupIPv6 with a host, return ipv6 list 80 func LookupIPv6(ctx context.Context, host string) ([]netip.Addr, error) { 81 return lookupIPByResolverAndType(ctx, host, DefaultResolver, typeAAAA, false) 82 } 83 84 // LookupIPByResolver same as ResolveIP, but with a resolver 85 func LookupIPByResolver(ctx context.Context, host string, r Resolver) ([]netip.Addr, error) { 86 return lookupIPByResolverAndType(ctx, host, r, typeNone, false) 87 } 88 89 // LookupIPByProxy with a host and proxy, reports force combined ipv6 list whether the DisableIPv6 value is true 90 func LookupIPByProxy(ctx context.Context, host, proxy string) ([]netip.Addr, error) { 91 return lookupIPByProxyAndType(ctx, host, proxy, typeNone, true) 92 } 93 94 // LookupIPv4ByProxy with a host and proxy, reports ipv4 list 95 func LookupIPv4ByProxy(ctx context.Context, host, proxy string) ([]netip.Addr, error) { 96 return lookupIPByProxyAndType(ctx, host, proxy, typeA, false) 97 } 98 99 // LookupIPv6ByProxy with a host and proxy, reports ipv6 list whether the DisableIPv6 value is true 100 func LookupIPv6ByProxy(ctx context.Context, host, proxy string) ([]netip.Addr, error) { 101 return lookupIPByProxyAndType(ctx, host, proxy, typeAAAA, true) 102 } 103 104 // ResolveIP with a host, return ip 105 func ResolveIP(host string) (netip.Addr, error) { 106 return resolveIPByType(host, typeNone) 107 } 108 109 // ResolveIPv4 with a host, return ipv4 110 func ResolveIPv4(host string) (netip.Addr, error) { 111 return resolveIPByType(host, typeA) 112 } 113 114 // ResolveIPv6 with a host, return ipv6 115 func ResolveIPv6(host string) (netip.Addr, error) { 116 return resolveIPByType(host, typeAAAA) 117 } 118 119 // ResolveProxyServerHost proxies server host only 120 func ResolveProxyServerHost(host string) (netip.Addr, error) { 121 return resolveProxyServerHostByType(host, typeNone) 122 } 123 124 // ResolveIPv4ProxyServerHost proxies server host only 125 func ResolveIPv4ProxyServerHost(host string) (netip.Addr, error) { 126 return resolveProxyServerHostByType(host, typeA) 127 } 128 129 // ResolveIPv6ProxyServerHost proxies server host only 130 func ResolveIPv6ProxyServerHost(host string) (netip.Addr, error) { 131 return resolveProxyServerHostByType(host, typeAAAA) 132 } 133 134 // SetDisableIPv6 set DisableIPv6 & needProxyHostIPv6 value 135 func SetDisableIPv6(v bool) { 136 DisableIPv6 = v 137 needProxyHostIPv6 = !v 138 } 139 140 // RemoveCache remove cache by host 141 func RemoveCache(host string) { 142 if DefaultResolver != nil { 143 DefaultResolver.RemoveCache(host) 144 } 145 } 146 147 // IsProxyServer reports whether the DefaultResolver should be exchanged by proxyServer DNS client 148 func IsProxyServer(ctx context.Context) bool { 149 return ctx.Value(proxyServerHostKey) != nil 150 } 151 152 // IsRemote reports whether the DefaultResolver should be exchanged by remote DNS client 153 func IsRemote(ctx context.Context) bool { 154 return ctx.Value(proxyKey) != nil 155 } 156 157 // GetProxy reports the proxy name used by the DNS client and whether there is a proxy 158 func GetProxy(ctx context.Context) (string, bool) { 159 v, ok := ctx.Value(proxyKey).(string) 160 return v, ok 161 } 162 163 // WithProxy returns a new context with proxy name 164 func WithProxy(ctx context.Context, proxy string) context.Context { 165 return context.WithValue(ctx, proxyKey, proxy) 166 } 167 168 // CopyCtxValues returns a new context with parent's values 169 func CopyCtxValues(parent context.Context) context.Context { 170 newCtx := context.Background() 171 if v, ok := parent.Value(proxyKey).(string); ok { 172 newCtx = context.WithValue(newCtx, proxyKey, v) 173 } 174 if parent.Value(proxyServerHostKey) != nil { 175 newCtx = context.WithValue(newCtx, proxyServerHostKey, struct{}{}) 176 } 177 return newCtx 178 } 179 180 func resolveIPByType(host string, _type uint16) (netip.Addr, error) { 181 var ( 182 ips []netip.Addr 183 err error 184 ) 185 186 switch _type { 187 case typeNone: 188 ips, err = LookupIP(context.Background(), host) 189 case typeA: 190 ips, err = LookupIPv4(context.Background(), host) 191 default: 192 ips, err = LookupIPv6(context.Background(), host) 193 } 194 195 if err != nil { 196 return netip.Addr{}, err 197 } 198 199 return ips[rand.IntN(len(ips))], nil 200 } 201 202 func resolveProxyServerHostByType(host string, _type uint16) (netip.Addr, error) { 203 var ( 204 ips []netip.Addr 205 err error 206 ctx = context.WithValue(context.Background(), proxyServerHostKey, struct{}{}) 207 ) 208 209 ips, err = lookupIPByResolverAndType(ctx, host, DefaultResolver, _type, needProxyHostIPv6) 210 if err != nil { 211 return netip.Addr{}, err 212 } 213 214 return ips[rand.IntN(len(ips))], nil 215 } 216 217 func lookupIPByProxyAndType(ctx context.Context, host, proxy string, t uint16, both bool) ([]netip.Addr, error) { 218 ctx = context.WithValue(ctx, proxyKey, proxy) 219 return lookupIPByResolverAndType(ctx, host, DefaultResolver, t, both) 220 } 221 222 func lookupIPByResolverAndType(ctx context.Context, host string, r Resolver, t uint16, both bool) ([]netip.Addr, error) { 223 if t == typeAAAA && DisableIPv6 && !both { 224 return nil, ErrIPv6Disabled 225 } 226 227 if node := DefaultHosts.Search(host); node != nil { 228 ip := node.Data 229 if t != typeAAAA { 230 ip = ip.Unmap() 231 } 232 if t == typeNone || (t == typeA && ip.Is4()) || (t == typeAAAA && ip.Is6()) { 233 return []netip.Addr{ip}, nil 234 } 235 } 236 237 if r != nil { 238 if t == typeA { 239 return r.LookupIPv4(ctx, host) 240 } else if t == typeAAAA { 241 return r.LookupIPv6(ctx, host) 242 } 243 if DisableIPv6 && !both { 244 return r.LookupIPv4(ctx, host) 245 } 246 return r.LookupIP(ctx, host) 247 } else if t == typeNone && DisableIPv6 { 248 return LookupIPv4(ctx, host) 249 } 250 251 if ip, err := netip.ParseAddr(host); err == nil { 252 if t != typeAAAA { 253 ip = ip.Unmap() 254 } 255 is4 := ip.Is4() 256 if (t == typeA && !is4) || (t == typeAAAA && is4) { 257 return nil, ErrIPVersion 258 } 259 return []netip.Addr{ip}, nil 260 } 261 262 network := "ip" 263 if t == typeA { 264 network = "ip4" 265 } else if t == typeAAAA { 266 network = "ip6" 267 } 268 269 ips, err := net.DefaultResolver.LookupIP(ctx, network, host) 270 if err != nil { 271 return nil, err 272 } else if len(ips) == 0 { 273 return nil, ErrIPNotFound 274 } 275 276 return lo.Map(ips, func(item net.IP, _ int) netip.Addr { 277 ip, _ := netip.AddrFromSlice(item) 278 if t != typeAAAA { 279 ip = ip.Unmap() 280 } 281 return ip 282 }), nil 283 }