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 }