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 }