github.com/Uhtred009/v2ray-core-1@v4.31.2+incompatible/app/dns/server.go (about) 1 // +build !confonly 2 3 package dns 4 5 //go:generate go run v2ray.com/core/common/errors/errorgen 6 7 import ( 8 "context" 9 "fmt" 10 "log" 11 "net/url" 12 "strings" 13 "sync" 14 "time" 15 16 "v2ray.com/core" 17 "v2ray.com/core/app/router" 18 "v2ray.com/core/common" 19 "v2ray.com/core/common/errors" 20 "v2ray.com/core/common/net" 21 "v2ray.com/core/common/session" 22 "v2ray.com/core/common/strmatcher" 23 "v2ray.com/core/common/uuid" 24 "v2ray.com/core/features" 25 "v2ray.com/core/features/dns" 26 "v2ray.com/core/features/routing" 27 ) 28 29 // Server is a DNS rely server. 30 type Server struct { 31 sync.Mutex 32 hosts *StaticHosts 33 clientIP net.IP 34 clients []Client // clientIdx -> Client 35 ipIndexMap []*MultiGeoIPMatcher // clientIdx -> *MultiGeoIPMatcher 36 domainRules [][]string // clientIdx -> domainRuleIdx -> DomainRule 37 domainMatcher strmatcher.IndexMatcher 38 matcherInfos []DomainMatcherInfo // matcherIdx -> DomainMatcherInfo 39 tag string 40 } 41 42 // DomainMatcherInfo contains information attached to index returned by Server.domainMatcher 43 type DomainMatcherInfo struct { 44 clientIdx uint16 45 domainRuleIdx uint16 46 } 47 48 // MultiGeoIPMatcher for match 49 type MultiGeoIPMatcher struct { 50 matchers []*router.GeoIPMatcher 51 } 52 53 var errExpectedIPNonMatch = errors.New("expectIPs not match") 54 55 // Match check ip match 56 func (c *MultiGeoIPMatcher) Match(ip net.IP) bool { 57 for _, matcher := range c.matchers { 58 if matcher.Match(ip) { 59 return true 60 } 61 } 62 return false 63 } 64 65 // HasMatcher check has matcher 66 func (c *MultiGeoIPMatcher) HasMatcher() bool { 67 return len(c.matchers) > 0 68 } 69 70 func generateRandomTag() string { 71 id := uuid.New() 72 return "v2ray.system." + id.String() 73 } 74 75 // New creates a new DNS server with given configuration. 76 func New(ctx context.Context, config *Config) (*Server, error) { 77 server := &Server{ 78 clients: make([]Client, 0, len(config.NameServers)+len(config.NameServer)), 79 tag: config.Tag, 80 } 81 if server.tag == "" { 82 server.tag = generateRandomTag() 83 } 84 if len(config.ClientIp) > 0 { 85 if len(config.ClientIp) != net.IPv4len && len(config.ClientIp) != net.IPv6len { 86 return nil, newError("unexpected IP length", len(config.ClientIp)) 87 } 88 server.clientIP = net.IP(config.ClientIp) 89 } 90 91 hosts, err := NewStaticHosts(config.StaticHosts, config.Hosts) 92 if err != nil { 93 return nil, newError("failed to create hosts").Base(err) 94 } 95 server.hosts = hosts 96 97 addNameServer := func(ns *NameServer) int { 98 endpoint := ns.Address 99 address := endpoint.Address.AsAddress() 100 if address.Family().IsDomain() && address.Domain() == "localhost" { 101 server.clients = append(server.clients, NewLocalNameServer()) 102 // Priotize local domains with specific TLDs or without any dot to local DNS 103 // References: 104 // https://www.iana.org/assignments/special-use-domain-names/special-use-domain-names.xhtml 105 // https://unix.stackexchange.com/questions/92441/whats-the-difference-between-local-home-and-lan 106 localTLDsAndDotlessDomains := []*NameServer_PriorityDomain{ 107 {Type: DomainMatchingType_Regex, Domain: "^[^.]+$"}, // This will only match domains without any dot 108 {Type: DomainMatchingType_Subdomain, Domain: "local"}, 109 {Type: DomainMatchingType_Subdomain, Domain: "localdomain"}, 110 {Type: DomainMatchingType_Subdomain, Domain: "localhost"}, 111 {Type: DomainMatchingType_Subdomain, Domain: "lan"}, 112 {Type: DomainMatchingType_Subdomain, Domain: "home.arpa"}, 113 {Type: DomainMatchingType_Subdomain, Domain: "example"}, 114 {Type: DomainMatchingType_Subdomain, Domain: "invalid"}, 115 {Type: DomainMatchingType_Subdomain, Domain: "test"}, 116 } 117 ns.PrioritizedDomain = append(ns.PrioritizedDomain, localTLDsAndDotlessDomains...) 118 } else if address.Family().IsDomain() && strings.HasPrefix(address.Domain(), "https+local://") { 119 // URI schemed string treated as domain 120 // DOH Local mode 121 u, err := url.Parse(address.Domain()) 122 if err != nil { 123 log.Fatalln(newError("DNS config error").Base(err)) 124 } 125 server.clients = append(server.clients, NewDoHLocalNameServer(u, server.clientIP)) 126 } else if address.Family().IsDomain() && strings.HasPrefix(address.Domain(), "https://") { 127 // DOH Remote mode 128 u, err := url.Parse(address.Domain()) 129 if err != nil { 130 log.Fatalln(newError("DNS config error").Base(err)) 131 } 132 idx := len(server.clients) 133 server.clients = append(server.clients, nil) 134 135 // need the core dispatcher, register DOHClient at callback 136 common.Must(core.RequireFeatures(ctx, func(d routing.Dispatcher) { 137 c, err := NewDoHNameServer(u, d, server.clientIP) 138 if err != nil { 139 log.Fatalln(newError("DNS config error").Base(err)) 140 } 141 server.clients[idx] = c 142 })) 143 } else { 144 // UDP classic DNS mode 145 dest := endpoint.AsDestination() 146 if dest.Network == net.Network_Unknown { 147 dest.Network = net.Network_UDP 148 } 149 if dest.Network == net.Network_UDP { 150 idx := len(server.clients) 151 server.clients = append(server.clients, nil) 152 153 common.Must(core.RequireFeatures(ctx, func(d routing.Dispatcher) { 154 server.clients[idx] = NewClassicNameServer(dest, d, server.clientIP) 155 })) 156 } 157 } 158 server.ipIndexMap = append(server.ipIndexMap, nil) 159 return len(server.clients) - 1 160 } 161 162 if len(config.NameServers) > 0 { 163 features.PrintDeprecatedFeatureWarning("simple DNS server") 164 for _, destPB := range config.NameServers { 165 addNameServer(&NameServer{Address: destPB}) 166 } 167 } 168 169 if len(config.NameServer) > 0 { 170 clientIndices := []int{} 171 domainRuleCount := 0 172 for _, ns := range config.NameServer { 173 idx := addNameServer(ns) 174 clientIndices = append(clientIndices, idx) 175 domainRuleCount += len(ns.PrioritizedDomain) 176 } 177 178 domainRules := make([][]string, len(server.clients)) 179 domainMatcher := &strmatcher.MatcherGroup{} 180 matcherInfos := make([]DomainMatcherInfo, domainRuleCount+1) // matcher index starts from 1 181 var geoIPMatcherContainer router.GeoIPMatcherContainer 182 for nidx, ns := range config.NameServer { 183 idx := clientIndices[nidx] 184 185 // Establish domain rule matcher 186 rules := []string{} 187 ruleCurr := 0 188 ruleIter := 0 189 for _, domain := range ns.PrioritizedDomain { 190 matcher, err := toStrMatcher(domain.Type, domain.Domain) 191 if err != nil { 192 return nil, newError("failed to create prioritized domain").Base(err).AtWarning() 193 } 194 midx := domainMatcher.Add(matcher) 195 if midx >= uint32(len(matcherInfos)) { // This rarely happens according to current matcher's implementation 196 newError("expanding domain matcher info array to size ", midx, " when adding ", matcher).AtDebug().WriteToLog() 197 matcherInfos = append(matcherInfos, make([]DomainMatcherInfo, midx-uint32(len(matcherInfos))+1)...) 198 } 199 info := &matcherInfos[midx] 200 info.clientIdx = uint16(idx) 201 if ruleCurr < len(ns.OriginalRules) { 202 info.domainRuleIdx = uint16(ruleCurr) 203 rule := ns.OriginalRules[ruleCurr] 204 if ruleCurr >= len(rules) { 205 rules = append(rules, rule.Rule) 206 } 207 ruleIter++ 208 if ruleIter >= int(rule.Size) { 209 ruleIter = 0 210 ruleCurr++ 211 } 212 } else { // No original rule, generate one according to current domain matcher (majorly for compatibility with tests) 213 info.domainRuleIdx = uint16(len(rules)) 214 rules = append(rules, matcher.String()) 215 } 216 } 217 domainRules[idx] = rules 218 219 // only add to ipIndexMap if GeoIP is configured 220 if len(ns.Geoip) > 0 { 221 var matchers []*router.GeoIPMatcher 222 for _, geoip := range ns.Geoip { 223 matcher, err := geoIPMatcherContainer.Add(geoip) 224 if err != nil { 225 return nil, newError("failed to create ip matcher").Base(err).AtWarning() 226 } 227 matchers = append(matchers, matcher) 228 } 229 matcher := &MultiGeoIPMatcher{matchers: matchers} 230 server.ipIndexMap[idx] = matcher 231 } 232 } 233 server.domainRules = domainRules 234 server.domainMatcher = domainMatcher 235 server.matcherInfos = matcherInfos 236 } 237 238 if len(server.clients) == 0 { 239 server.clients = append(server.clients, NewLocalNameServer()) 240 server.ipIndexMap = append(server.ipIndexMap, nil) 241 } 242 243 return server, nil 244 } 245 246 // Type implements common.HasType. 247 func (*Server) Type() interface{} { 248 return dns.ClientType() 249 } 250 251 // Start implements common.Runnable. 252 func (s *Server) Start() error { 253 return nil 254 } 255 256 // Close implements common.Closable. 257 func (s *Server) Close() error { 258 return nil 259 } 260 261 func (s *Server) IsOwnLink(ctx context.Context) bool { 262 inbound := session.InboundFromContext(ctx) 263 return inbound != nil && inbound.Tag == s.tag 264 } 265 266 // Match check dns ip match geoip 267 func (s *Server) Match(idx int, client Client, domain string, ips []net.IP) ([]net.IP, error) { 268 var matcher *MultiGeoIPMatcher 269 if idx < len(s.ipIndexMap) { 270 matcher = s.ipIndexMap[idx] 271 } 272 if matcher == nil { 273 return ips, nil 274 } 275 276 if !matcher.HasMatcher() { 277 newError("domain ", domain, " server has no valid matcher: ", client.Name(), " idx:", idx).AtDebug().WriteToLog() 278 return ips, nil 279 } 280 281 newIps := []net.IP{} 282 for _, ip := range ips { 283 if matcher.Match(ip) { 284 newIps = append(newIps, ip) 285 } 286 } 287 if len(newIps) == 0 { 288 return nil, errExpectedIPNonMatch 289 } 290 newError("domain ", domain, " expectIPs ", newIps, " matched at server ", client.Name(), " idx:", idx).AtDebug().WriteToLog() 291 return newIps, nil 292 } 293 294 func (s *Server) queryIPTimeout(idx int, client Client, domain string, option IPOption) ([]net.IP, error) { 295 ctx, cancel := context.WithTimeout(context.Background(), time.Second*4) 296 if len(s.tag) > 0 { 297 ctx = session.ContextWithInbound(ctx, &session.Inbound{ 298 Tag: s.tag, 299 }) 300 } 301 ips, err := client.QueryIP(ctx, domain, option) 302 cancel() 303 304 if err != nil { 305 return ips, err 306 } 307 308 ips, err = s.Match(idx, client, domain, ips) 309 return ips, err 310 } 311 312 // LookupIP implements dns.Client. 313 func (s *Server) LookupIP(domain string) ([]net.IP, error) { 314 return s.lookupIPInternal(domain, IPOption{ 315 IPv4Enable: true, 316 IPv6Enable: true, 317 }) 318 } 319 320 // LookupIPv4 implements dns.IPv4Lookup. 321 func (s *Server) LookupIPv4(domain string) ([]net.IP, error) { 322 return s.lookupIPInternal(domain, IPOption{ 323 IPv4Enable: true, 324 IPv6Enable: false, 325 }) 326 } 327 328 // LookupIPv6 implements dns.IPv6Lookup. 329 func (s *Server) LookupIPv6(domain string) ([]net.IP, error) { 330 return s.lookupIPInternal(domain, IPOption{ 331 IPv4Enable: false, 332 IPv6Enable: true, 333 }) 334 } 335 336 func (s *Server) lookupStatic(domain string, option IPOption, depth int32) []net.Address { 337 ips := s.hosts.LookupIP(domain, option) 338 if ips == nil { 339 return nil 340 } 341 if ips[0].Family().IsDomain() && depth < 5 { 342 if newIPs := s.lookupStatic(ips[0].Domain(), option, depth+1); newIPs != nil { 343 return newIPs 344 } 345 } 346 return ips 347 } 348 349 func toNetIP(ips []net.Address) []net.IP { 350 if len(ips) == 0 { 351 return nil 352 } 353 netips := make([]net.IP, 0, len(ips)) 354 for _, ip := range ips { 355 netips = append(netips, ip.IP()) 356 } 357 return netips 358 } 359 360 func (s *Server) lookupIPInternal(domain string, option IPOption) ([]net.IP, error) { 361 if domain == "" { 362 return nil, newError("empty domain name") 363 } 364 365 // normalize the FQDN form query 366 if domain[len(domain)-1] == '.' { 367 domain = domain[:len(domain)-1] 368 } 369 370 ips := s.lookupStatic(domain, option, 0) 371 if ips != nil && ips[0].Family().IsIP() { 372 newError("returning ", len(ips), " IPs for domain ", domain).WriteToLog() 373 return toNetIP(ips), nil 374 } 375 376 if ips != nil && ips[0].Family().IsDomain() { 377 newdomain := ips[0].Domain() 378 newError("domain replaced: ", domain, " -> ", newdomain).WriteToLog() 379 domain = newdomain 380 } 381 382 var lastErr error 383 var matchedClient Client 384 if s.domainMatcher != nil { 385 indices := s.domainMatcher.Match(domain) 386 domainRules := []string{} 387 matchingDNS := []string{} 388 for _, idx := range indices { 389 info := s.matcherInfos[idx] 390 rule := s.domainRules[info.clientIdx][info.domainRuleIdx] 391 domainRules = append(domainRules, fmt.Sprintf("%s(DNS idx:%d)", rule, info.clientIdx)) 392 matchingDNS = append(matchingDNS, s.clients[info.clientIdx].Name()) 393 } 394 if len(domainRules) > 0 { 395 newError("domain ", domain, " matches following rules: ", domainRules).AtDebug().WriteToLog() 396 } 397 if len(matchingDNS) > 0 { 398 newError("domain ", domain, " uses following DNS first: ", matchingDNS).AtDebug().WriteToLog() 399 } 400 for _, idx := range indices { 401 clientIdx := int(s.matcherInfos[idx].clientIdx) 402 matchedClient = s.clients[clientIdx] 403 ips, err := s.queryIPTimeout(clientIdx, matchedClient, domain, option) 404 if len(ips) > 0 { 405 return ips, nil 406 } 407 if err == dns.ErrEmptyResponse { 408 return nil, err 409 } 410 if err != nil { 411 newError("failed to lookup ip for domain ", domain, " at server ", matchedClient.Name()).Base(err).WriteToLog() 412 lastErr = err 413 } 414 } 415 } 416 417 for idx, client := range s.clients { 418 if client == matchedClient { 419 newError("domain ", domain, " at server ", client.Name(), " idx:", idx, " already lookup failed, just ignore").AtDebug().WriteToLog() 420 continue 421 } 422 423 ips, err := s.queryIPTimeout(idx, client, domain, option) 424 if len(ips) > 0 { 425 return ips, nil 426 } 427 428 if err != nil { 429 newError("failed to lookup ip for domain ", domain, " at server ", client.Name()).Base(err).WriteToLog() 430 lastErr = err 431 } 432 if err != context.Canceled && err != context.DeadlineExceeded && err != errExpectedIPNonMatch { 433 return nil, err 434 } 435 } 436 437 return nil, newError("returning nil for domain ", domain).Base(lastErr) 438 } 439 440 func init() { 441 common.Must(common.RegisterConfig((*Config)(nil), func(ctx context.Context, config interface{}) (interface{}, error) { 442 return New(ctx, config.(*Config)) 443 })) 444 }