github.com/code-reading/golang@v0.0.0-20220303082512-ba5bc0e589a3/go/src/net/lookup.go (about) 1 // Copyright 2012 The Go Authors. All rights reserved. 2 // Use of this source code is governed by a BSD-style 3 // license that can be found in the LICENSE file. 4 5 package net 6 7 import ( 8 "context" 9 "internal/nettrace" 10 "internal/singleflight" 11 "sync" 12 ) 13 14 // protocols contains minimal mappings between internet protocol 15 // names and numbers for platforms that don't have a complete list of 16 // protocol numbers. 17 // 18 // See https://www.iana.org/assignments/protocol-numbers 19 // 20 // On Unix, this map is augmented by readProtocols via lookupProtocol. 21 var protocols = map[string]int{ 22 "icmp": 1, 23 "igmp": 2, 24 "tcp": 6, 25 "udp": 17, 26 "ipv6-icmp": 58, 27 } 28 29 // services contains minimal mappings between services names and port 30 // numbers for platforms that don't have a complete list of port numbers. 31 // 32 // See https://www.iana.org/assignments/service-names-port-numbers 33 // 34 // On Unix, this map is augmented by readServices via goLookupPort. 35 var services = map[string]map[string]int{ 36 "udp": { 37 "domain": 53, 38 }, 39 "tcp": { 40 "ftp": 21, 41 "ftps": 990, 42 "gopher": 70, // ʕ◔ϖ◔ʔ 43 "http": 80, 44 "https": 443, 45 "imap2": 143, 46 "imap3": 220, 47 "imaps": 993, 48 "pop3": 110, 49 "pop3s": 995, 50 "smtp": 25, 51 "ssh": 22, 52 "telnet": 23, 53 }, 54 } 55 56 // dnsWaitGroup can be used by tests to wait for all DNS goroutines to 57 // complete. This avoids races on the test hooks. 58 var dnsWaitGroup sync.WaitGroup 59 60 const maxProtoLength = len("RSVP-E2E-IGNORE") + 10 // with room to grow 61 62 func lookupProtocolMap(name string) (int, error) { 63 var lowerProtocol [maxProtoLength]byte 64 n := copy(lowerProtocol[:], name) 65 lowerASCIIBytes(lowerProtocol[:n]) 66 proto, found := protocols[string(lowerProtocol[:n])] 67 if !found || n != len(name) { 68 return 0, &AddrError{Err: "unknown IP protocol specified", Addr: name} 69 } 70 return proto, nil 71 } 72 73 // maxPortBufSize is the longest reasonable name of a service 74 // (non-numeric port). 75 // Currently the longest known IANA-unregistered name is 76 // "mobility-header", so we use that length, plus some slop in case 77 // something longer is added in the future. 78 const maxPortBufSize = len("mobility-header") + 10 79 80 func lookupPortMap(network, service string) (port int, error error) { 81 switch network { 82 case "tcp4", "tcp6": 83 network = "tcp" 84 case "udp4", "udp6": 85 network = "udp" 86 } 87 88 if m, ok := services[network]; ok { 89 var lowerService [maxPortBufSize]byte 90 n := copy(lowerService[:], service) 91 lowerASCIIBytes(lowerService[:n]) 92 if port, ok := m[string(lowerService[:n])]; ok && n == len(service) { 93 return port, nil 94 } 95 } 96 return 0, &AddrError{Err: "unknown port", Addr: network + "/" + service} 97 } 98 99 // ipVersion returns the provided network's IP version: '4', '6' or 0 100 // if network does not end in a '4' or '6' byte. 101 func ipVersion(network string) byte { 102 if network == "" { 103 return 0 104 } 105 n := network[len(network)-1] 106 if n != '4' && n != '6' { 107 n = 0 108 } 109 return n 110 } 111 112 // DefaultResolver is the resolver used by the package-level Lookup 113 // functions and by Dialers without a specified Resolver. 114 var DefaultResolver = &Resolver{} 115 116 // A Resolver looks up names and numbers. 117 // 118 // A nil *Resolver is equivalent to a zero Resolver. 119 type Resolver struct { 120 // PreferGo controls whether Go's built-in DNS resolver is preferred 121 // on platforms where it's available. It is equivalent to setting 122 // GODEBUG=netdns=go, but scoped to just this resolver. 123 PreferGo bool 124 125 // StrictErrors controls the behavior of temporary errors 126 // (including timeout, socket errors, and SERVFAIL) when using 127 // Go's built-in resolver. For a query composed of multiple 128 // sub-queries (such as an A+AAAA address lookup, or walking the 129 // DNS search list), this option causes such errors to abort the 130 // whole query instead of returning a partial result. This is 131 // not enabled by default because it may affect compatibility 132 // with resolvers that process AAAA queries incorrectly. 133 StrictErrors bool 134 135 // Dial optionally specifies an alternate dialer for use by 136 // Go's built-in DNS resolver to make TCP and UDP connections 137 // to DNS services. The host in the address parameter will 138 // always be a literal IP address and not a host name, and the 139 // port in the address parameter will be a literal port number 140 // and not a service name. 141 // If the Conn returned is also a PacketConn, sent and received DNS 142 // messages must adhere to RFC 1035 section 4.2.1, "UDP usage". 143 // Otherwise, DNS messages transmitted over Conn must adhere 144 // to RFC 7766 section 5, "Transport Protocol Selection". 145 // If nil, the default dialer is used. 146 Dial func(ctx context.Context, network, address string) (Conn, error) 147 148 // lookupGroup merges LookupIPAddr calls together for lookups for the same 149 // host. The lookupGroup key is the LookupIPAddr.host argument. 150 // The return values are ([]IPAddr, error). 151 lookupGroup singleflight.Group 152 153 // TODO(bradfitz): optional interface impl override hook 154 // TODO(bradfitz): Timeout time.Duration? 155 } 156 157 func (r *Resolver) preferGo() bool { return r != nil && r.PreferGo } 158 func (r *Resolver) strictErrors() bool { return r != nil && r.StrictErrors } 159 160 func (r *Resolver) getLookupGroup() *singleflight.Group { 161 if r == nil { 162 return &DefaultResolver.lookupGroup 163 } 164 return &r.lookupGroup 165 } 166 167 // LookupHost looks up the given host using the local resolver. 168 // It returns a slice of that host's addresses. 169 // 170 // LookupHost uses context.Background internally; to specify the context, use 171 // Resolver.LookupHost. 172 func LookupHost(host string) (addrs []string, err error) { 173 return DefaultResolver.LookupHost(context.Background(), host) 174 } 175 176 // LookupHost looks up the given host using the local resolver. 177 // It returns a slice of that host's addresses. 178 func (r *Resolver) LookupHost(ctx context.Context, host string) (addrs []string, err error) { 179 // Make sure that no matter what we do later, host=="" is rejected. 180 // parseIP, for example, does accept empty strings. 181 if host == "" { 182 return nil, &DNSError{Err: errNoSuchHost.Error(), Name: host, IsNotFound: true} 183 } 184 if ip, _ := parseIPZone(host); ip != nil { 185 return []string{host}, nil 186 } 187 return r.lookupHost(ctx, host) 188 } 189 190 // LookupIP looks up host using the local resolver. 191 // It returns a slice of that host's IPv4 and IPv6 addresses. 192 func LookupIP(host string) ([]IP, error) { 193 addrs, err := DefaultResolver.LookupIPAddr(context.Background(), host) 194 if err != nil { 195 return nil, err 196 } 197 ips := make([]IP, len(addrs)) 198 for i, ia := range addrs { 199 ips[i] = ia.IP 200 } 201 return ips, nil 202 } 203 204 // LookupIPAddr looks up host using the local resolver. 205 // It returns a slice of that host's IPv4 and IPv6 addresses. 206 func (r *Resolver) LookupIPAddr(ctx context.Context, host string) ([]IPAddr, error) { 207 return r.lookupIPAddr(ctx, "ip", host) 208 } 209 210 // LookupIP looks up host for the given network using the local resolver. 211 // It returns a slice of that host's IP addresses of the type specified by 212 // network. 213 // network must be one of "ip", "ip4" or "ip6". 214 func (r *Resolver) LookupIP(ctx context.Context, network, host string) ([]IP, error) { 215 afnet, _, err := parseNetwork(ctx, network, false) 216 if err != nil { 217 return nil, err 218 } 219 switch afnet { 220 case "ip", "ip4", "ip6": 221 default: 222 return nil, UnknownNetworkError(network) 223 } 224 addrs, err := r.internetAddrList(ctx, afnet, host) 225 if err != nil { 226 return nil, err 227 } 228 ips := make([]IP, 0, len(addrs)) 229 for _, addr := range addrs { 230 ips = append(ips, addr.(*IPAddr).IP) 231 } 232 return ips, nil 233 } 234 235 // onlyValuesCtx is a context that uses an underlying context 236 // for value lookup if the underlying context hasn't yet expired. 237 type onlyValuesCtx struct { 238 context.Context 239 lookupValues context.Context 240 } 241 242 var _ context.Context = (*onlyValuesCtx)(nil) 243 244 // Value performs a lookup if the original context hasn't expired. 245 func (ovc *onlyValuesCtx) Value(key interface{}) interface{} { 246 select { 247 case <-ovc.lookupValues.Done(): 248 return nil 249 default: 250 return ovc.lookupValues.Value(key) 251 } 252 } 253 254 // withUnexpiredValuesPreserved returns a context.Context that only uses lookupCtx 255 // for its values, otherwise it is never canceled and has no deadline. 256 // If the lookup context expires, any looked up values will return nil. 257 // See Issue 28600. 258 func withUnexpiredValuesPreserved(lookupCtx context.Context) context.Context { 259 return &onlyValuesCtx{Context: context.Background(), lookupValues: lookupCtx} 260 } 261 262 // lookupIPAddr looks up host using the local resolver and particular network. 263 // It returns a slice of that host's IPv4 and IPv6 addresses. 264 func (r *Resolver) lookupIPAddr(ctx context.Context, network, host string) ([]IPAddr, error) { 265 // Make sure that no matter what we do later, host=="" is rejected. 266 // parseIP, for example, does accept empty strings. 267 if host == "" { 268 return nil, &DNSError{Err: errNoSuchHost.Error(), Name: host, IsNotFound: true} 269 } 270 if ip, zone := parseIPZone(host); ip != nil { 271 return []IPAddr{{IP: ip, Zone: zone}}, nil 272 } 273 trace, _ := ctx.Value(nettrace.TraceKey{}).(*nettrace.Trace) 274 if trace != nil && trace.DNSStart != nil { 275 trace.DNSStart(host) 276 } 277 // The underlying resolver func is lookupIP by default but it 278 // can be overridden by tests. This is needed by net/http, so it 279 // uses a context key instead of unexported variables. 280 resolverFunc := r.lookupIP 281 if alt, _ := ctx.Value(nettrace.LookupIPAltResolverKey{}).(func(context.Context, string, string) ([]IPAddr, error)); alt != nil { 282 resolverFunc = alt 283 } 284 285 // We don't want a cancellation of ctx to affect the 286 // lookupGroup operation. Otherwise if our context gets 287 // canceled it might cause an error to be returned to a lookup 288 // using a completely different context. However we need to preserve 289 // only the values in context. See Issue 28600. 290 lookupGroupCtx, lookupGroupCancel := context.WithCancel(withUnexpiredValuesPreserved(ctx)) 291 292 lookupKey := network + "\000" + host 293 dnsWaitGroup.Add(1) 294 ch, called := r.getLookupGroup().DoChan(lookupKey, func() (interface{}, error) { 295 defer dnsWaitGroup.Done() 296 return testHookLookupIP(lookupGroupCtx, resolverFunc, network, host) 297 }) 298 if !called { 299 dnsWaitGroup.Done() 300 } 301 302 select { 303 case <-ctx.Done(): 304 // Our context was canceled. If we are the only 305 // goroutine looking up this key, then drop the key 306 // from the lookupGroup and cancel the lookup. 307 // If there are other goroutines looking up this key, 308 // let the lookup continue uncanceled, and let later 309 // lookups with the same key share the result. 310 // See issues 8602, 20703, 22724. 311 if r.getLookupGroup().ForgetUnshared(lookupKey) { 312 lookupGroupCancel() 313 } else { 314 go func() { 315 <-ch 316 lookupGroupCancel() 317 }() 318 } 319 err := mapErr(ctx.Err()) 320 if trace != nil && trace.DNSDone != nil { 321 trace.DNSDone(nil, false, err) 322 } 323 return nil, err 324 case r := <-ch: 325 lookupGroupCancel() 326 if trace != nil && trace.DNSDone != nil { 327 addrs, _ := r.Val.([]IPAddr) 328 trace.DNSDone(ipAddrsEface(addrs), r.Shared, r.Err) 329 } 330 return lookupIPReturn(r.Val, r.Err, r.Shared) 331 } 332 } 333 334 // lookupIPReturn turns the return values from singleflight.Do into 335 // the return values from LookupIP. 336 func lookupIPReturn(addrsi interface{}, err error, shared bool) ([]IPAddr, error) { 337 if err != nil { 338 return nil, err 339 } 340 addrs := addrsi.([]IPAddr) 341 if shared { 342 clone := make([]IPAddr, len(addrs)) 343 copy(clone, addrs) 344 addrs = clone 345 } 346 return addrs, nil 347 } 348 349 // ipAddrsEface returns an empty interface slice of addrs. 350 func ipAddrsEface(addrs []IPAddr) []interface{} { 351 s := make([]interface{}, len(addrs)) 352 for i, v := range addrs { 353 s[i] = v 354 } 355 return s 356 } 357 358 // LookupPort looks up the port for the given network and service. 359 // 360 // LookupPort uses context.Background internally; to specify the context, use 361 // Resolver.LookupPort. 362 func LookupPort(network, service string) (port int, err error) { 363 return DefaultResolver.LookupPort(context.Background(), network, service) 364 } 365 366 // LookupPort looks up the port for the given network and service. 367 func (r *Resolver) LookupPort(ctx context.Context, network, service string) (port int, err error) { 368 port, needsLookup := parsePort(service) 369 if needsLookup { 370 switch network { 371 case "tcp", "tcp4", "tcp6", "udp", "udp4", "udp6": 372 case "": // a hint wildcard for Go 1.0 undocumented behavior 373 network = "ip" 374 default: 375 return 0, &AddrError{Err: "unknown network", Addr: network} 376 } 377 port, err = r.lookupPort(ctx, network, service) 378 if err != nil { 379 return 0, err 380 } 381 } 382 if 0 > port || port > 65535 { 383 return 0, &AddrError{Err: "invalid port", Addr: service} 384 } 385 return port, nil 386 } 387 388 // LookupCNAME returns the canonical name for the given host. 389 // Callers that do not care about the canonical name can call 390 // LookupHost or LookupIP directly; both take care of resolving 391 // the canonical name as part of the lookup. 392 // 393 // A canonical name is the final name after following zero 394 // or more CNAME records. 395 // LookupCNAME does not return an error if host does not 396 // contain DNS "CNAME" records, as long as host resolves to 397 // address records. 398 // 399 // The returned canonical name is validated to be a properly 400 // formatted presentation-format domain name. 401 // 402 // LookupCNAME uses context.Background internally; to specify the context, use 403 // Resolver.LookupCNAME. 404 func LookupCNAME(host string) (cname string, err error) { 405 return DefaultResolver.LookupCNAME(context.Background(), host) 406 } 407 408 // LookupCNAME returns the canonical name for the given host. 409 // Callers that do not care about the canonical name can call 410 // LookupHost or LookupIP directly; both take care of resolving 411 // the canonical name as part of the lookup. 412 // 413 // A canonical name is the final name after following zero 414 // or more CNAME records. 415 // LookupCNAME does not return an error if host does not 416 // contain DNS "CNAME" records, as long as host resolves to 417 // address records. 418 // 419 // The returned canonical name is validated to be a properly 420 // formatted presentation-format domain name. 421 func (r *Resolver) LookupCNAME(ctx context.Context, host string) (string, error) { 422 cname, err := r.lookupCNAME(ctx, host) 423 if err != nil { 424 return "", err 425 } 426 if !isDomainName(cname) { 427 return "", &DNSError{Err: errMalformedDNSRecordsDetail, Name: host} 428 } 429 return cname, nil 430 } 431 432 // LookupSRV tries to resolve an SRV query of the given service, 433 // protocol, and domain name. The proto is "tcp" or "udp". 434 // The returned records are sorted by priority and randomized 435 // by weight within a priority. 436 // 437 // LookupSRV constructs the DNS name to look up following RFC 2782. 438 // That is, it looks up _service._proto.name. To accommodate services 439 // publishing SRV records under non-standard names, if both service 440 // and proto are empty strings, LookupSRV looks up name directly. 441 // 442 // The returned service names are validated to be properly 443 // formatted presentation-format domain names. If the response contains 444 // invalid names, those records are filtered out and an error 445 // will be returned alongside the the remaining results, if any. 446 func LookupSRV(service, proto, name string) (cname string, addrs []*SRV, err error) { 447 return DefaultResolver.LookupSRV(context.Background(), service, proto, name) 448 } 449 450 // LookupSRV tries to resolve an SRV query of the given service, 451 // protocol, and domain name. The proto is "tcp" or "udp". 452 // The returned records are sorted by priority and randomized 453 // by weight within a priority. 454 // 455 // LookupSRV constructs the DNS name to look up following RFC 2782. 456 // That is, it looks up _service._proto.name. To accommodate services 457 // publishing SRV records under non-standard names, if both service 458 // and proto are empty strings, LookupSRV looks up name directly. 459 // 460 // The returned service names are validated to be properly 461 // formatted presentation-format domain names. If the response contains 462 // invalid names, those records are filtered out and an error 463 // will be returned alongside the the remaining results, if any. 464 func (r *Resolver) LookupSRV(ctx context.Context, service, proto, name string) (string, []*SRV, error) { 465 cname, addrs, err := r.lookupSRV(ctx, service, proto, name) 466 if err != nil { 467 return "", nil, err 468 } 469 if cname != "" && !isDomainName(cname) { 470 return "", nil, &DNSError{Err: "SRV header name is invalid", Name: name} 471 } 472 filteredAddrs := make([]*SRV, 0, len(addrs)) 473 for _, addr := range addrs { 474 if addr == nil { 475 continue 476 } 477 if !isDomainName(addr.Target) { 478 continue 479 } 480 filteredAddrs = append(filteredAddrs, addr) 481 } 482 if len(addrs) != len(filteredAddrs) { 483 return cname, filteredAddrs, &DNSError{Err: errMalformedDNSRecordsDetail, Name: name} 484 } 485 return cname, filteredAddrs, nil 486 } 487 488 // LookupMX returns the DNS MX records for the given domain name sorted by preference. 489 // 490 // The returned mail server names are validated to be properly 491 // formatted presentation-format domain names. If the response contains 492 // invalid names, those records are filtered out and an error 493 // will be returned alongside the the remaining results, if any. 494 // 495 // LookupMX uses context.Background internally; to specify the context, use 496 // Resolver.LookupMX. 497 func LookupMX(name string) ([]*MX, error) { 498 return DefaultResolver.LookupMX(context.Background(), name) 499 } 500 501 // LookupMX returns the DNS MX records for the given domain name sorted by preference. 502 // 503 // The returned mail server names are validated to be properly 504 // formatted presentation-format domain names. If the response contains 505 // invalid names, those records are filtered out and an error 506 // will be returned alongside the the remaining results, if any. 507 func (r *Resolver) LookupMX(ctx context.Context, name string) ([]*MX, error) { 508 records, err := r.lookupMX(ctx, name) 509 if err != nil { 510 return nil, err 511 } 512 filteredMX := make([]*MX, 0, len(records)) 513 for _, mx := range records { 514 if mx == nil { 515 continue 516 } 517 // Bypass the hostname validity check for targets which contain only a dot, 518 // as this is used to represent a 'Null' MX record. 519 if mx.Host != "." && !isDomainName(mx.Host) { 520 continue 521 } 522 filteredMX = append(filteredMX, mx) 523 } 524 if len(records) != len(filteredMX) { 525 return filteredMX, &DNSError{Err: errMalformedDNSRecordsDetail, Name: name} 526 } 527 return filteredMX, nil 528 } 529 530 // LookupNS returns the DNS NS records for the given domain name. 531 // 532 // The returned name server names are validated to be properly 533 // formatted presentation-format domain names. If the response contains 534 // invalid names, those records are filtered out and an error 535 // will be returned alongside the the remaining results, if any. 536 // 537 // LookupNS uses context.Background internally; to specify the context, use 538 // Resolver.LookupNS. 539 func LookupNS(name string) ([]*NS, error) { 540 return DefaultResolver.LookupNS(context.Background(), name) 541 } 542 543 // LookupNS returns the DNS NS records for the given domain name. 544 // 545 // The returned name server names are validated to be properly 546 // formatted presentation-format domain names. If the response contains 547 // invalid names, those records are filtered out and an error 548 // will be returned alongside the the remaining results, if any. 549 func (r *Resolver) LookupNS(ctx context.Context, name string) ([]*NS, error) { 550 records, err := r.lookupNS(ctx, name) 551 if err != nil { 552 return nil, err 553 } 554 filteredNS := make([]*NS, 0, len(records)) 555 for _, ns := range records { 556 if ns == nil { 557 continue 558 } 559 if !isDomainName(ns.Host) { 560 continue 561 } 562 filteredNS = append(filteredNS, ns) 563 } 564 if len(records) != len(filteredNS) { 565 return filteredNS, &DNSError{Err: errMalformedDNSRecordsDetail, Name: name} 566 } 567 return filteredNS, nil 568 } 569 570 // LookupTXT returns the DNS TXT records for the given domain name. 571 // 572 // LookupTXT uses context.Background internally; to specify the context, use 573 // Resolver.LookupTXT. 574 func LookupTXT(name string) ([]string, error) { 575 return DefaultResolver.lookupTXT(context.Background(), name) 576 } 577 578 // LookupTXT returns the DNS TXT records for the given domain name. 579 func (r *Resolver) LookupTXT(ctx context.Context, name string) ([]string, error) { 580 return r.lookupTXT(ctx, name) 581 } 582 583 // LookupAddr performs a reverse lookup for the given address, returning a list 584 // of names mapping to that address. 585 // 586 // The returned names are validated to be properly formatted presentation-format 587 // domain names. If the response contains invalid names, those records are filtered 588 // out and an error will be returned alongside the the remaining results, if any. 589 // 590 // When using the host C library resolver, at most one result will be 591 // returned. To bypass the host resolver, use a custom Resolver. 592 // 593 // LookupAddr uses context.Background internally; to specify the context, use 594 // Resolver.LookupAddr. 595 func LookupAddr(addr string) (names []string, err error) { 596 return DefaultResolver.LookupAddr(context.Background(), addr) 597 } 598 599 // LookupAddr performs a reverse lookup for the given address, returning a list 600 // of names mapping to that address. 601 // 602 // The returned names are validated to be properly formatted presentation-format 603 // domain names. If the response contains invalid names, those records are filtered 604 // out and an error will be returned alongside the the remaining results, if any. 605 func (r *Resolver) LookupAddr(ctx context.Context, addr string) ([]string, error) { 606 names, err := r.lookupAddr(ctx, addr) 607 if err != nil { 608 return nil, err 609 } 610 filteredNames := make([]string, 0, len(names)) 611 for _, name := range names { 612 if isDomainName(name) { 613 filteredNames = append(filteredNames, name) 614 } 615 } 616 if len(names) != len(filteredNames) { 617 return filteredNames, &DNSError{Err: errMalformedDNSRecordsDetail, Name: addr} 618 } 619 return filteredNames, nil 620 } 621 622 // errMalformedDNSRecordsDetail is the DNSError detail which is returned when a Resolver.Lookup... 623 // method recieves DNS records which contain invalid DNS names. This may be returned alongside 624 // results which have had the malformed records filtered out. 625 var errMalformedDNSRecordsDetail = "DNS response contained records which contain invalid names"