github.com/mtsmfm/go/src@v0.0.0-20221020090648-44bdcb9f8fde/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 "net/netip" 12 "sync" 13 14 "golang.org/x/net/dns/dnsmessage" 15 ) 16 17 // protocols contains minimal mappings between internet protocol 18 // names and numbers for platforms that don't have a complete list of 19 // protocol numbers. 20 // 21 // See https://www.iana.org/assignments/protocol-numbers 22 // 23 // On Unix, this map is augmented by readProtocols via lookupProtocol. 24 var protocols = map[string]int{ 25 "icmp": 1, 26 "igmp": 2, 27 "tcp": 6, 28 "udp": 17, 29 "ipv6-icmp": 58, 30 } 31 32 // services contains minimal mappings between services names and port 33 // numbers for platforms that don't have a complete list of port numbers. 34 // 35 // See https://www.iana.org/assignments/service-names-port-numbers 36 // 37 // On Unix, this map is augmented by readServices via goLookupPort. 38 var services = map[string]map[string]int{ 39 "udp": { 40 "domain": 53, 41 }, 42 "tcp": { 43 "ftp": 21, 44 "ftps": 990, 45 "gopher": 70, // ʕ◔ϖ◔ʔ 46 "http": 80, 47 "https": 443, 48 "imap2": 143, 49 "imap3": 220, 50 "imaps": 993, 51 "pop3": 110, 52 "pop3s": 995, 53 "smtp": 25, 54 "ssh": 22, 55 "telnet": 23, 56 }, 57 } 58 59 // dnsWaitGroup can be used by tests to wait for all DNS goroutines to 60 // complete. This avoids races on the test hooks. 61 var dnsWaitGroup sync.WaitGroup 62 63 const maxProtoLength = len("RSVP-E2E-IGNORE") + 10 // with room to grow 64 65 func lookupProtocolMap(name string) (int, error) { 66 var lowerProtocol [maxProtoLength]byte 67 n := copy(lowerProtocol[:], name) 68 lowerASCIIBytes(lowerProtocol[:n]) 69 proto, found := protocols[string(lowerProtocol[:n])] 70 if !found || n != len(name) { 71 return 0, &AddrError{Err: "unknown IP protocol specified", Addr: name} 72 } 73 return proto, nil 74 } 75 76 // maxPortBufSize is the longest reasonable name of a service 77 // (non-numeric port). 78 // Currently the longest known IANA-unregistered name is 79 // "mobility-header", so we use that length, plus some slop in case 80 // something longer is added in the future. 81 const maxPortBufSize = len("mobility-header") + 10 82 83 func lookupPortMap(network, service string) (port int, error error) { 84 switch network { 85 case "tcp4", "tcp6": 86 network = "tcp" 87 case "udp4", "udp6": 88 network = "udp" 89 } 90 91 if m, ok := services[network]; ok { 92 var lowerService [maxPortBufSize]byte 93 n := copy(lowerService[:], service) 94 lowerASCIIBytes(lowerService[:n]) 95 if port, ok := m[string(lowerService[:n])]; ok && n == len(service) { 96 return port, nil 97 } 98 } 99 return 0, &AddrError{Err: "unknown port", Addr: network + "/" + service} 100 } 101 102 // ipVersion returns the provided network's IP version: '4', '6' or 0 103 // if network does not end in a '4' or '6' byte. 104 func ipVersion(network string) byte { 105 if network == "" { 106 return 0 107 } 108 n := network[len(network)-1] 109 if n != '4' && n != '6' { 110 n = 0 111 } 112 return n 113 } 114 115 // DefaultResolver is the resolver used by the package-level Lookup 116 // functions and by Dialers without a specified Resolver. 117 var DefaultResolver = &Resolver{} 118 119 // A Resolver looks up names and numbers. 120 // 121 // A nil *Resolver is equivalent to a zero Resolver. 122 type Resolver struct { 123 // PreferGo controls whether Go's built-in DNS resolver is preferred 124 // on platforms where it's available. It is equivalent to setting 125 // GODEBUG=netdns=go, but scoped to just this resolver. 126 PreferGo bool 127 128 // StrictErrors controls the behavior of temporary errors 129 // (including timeout, socket errors, and SERVFAIL) when using 130 // Go's built-in resolver. For a query composed of multiple 131 // sub-queries (such as an A+AAAA address lookup, or walking the 132 // DNS search list), this option causes such errors to abort the 133 // whole query instead of returning a partial result. This is 134 // not enabled by default because it may affect compatibility 135 // with resolvers that process AAAA queries incorrectly. 136 StrictErrors bool 137 138 // Dial optionally specifies an alternate dialer for use by 139 // Go's built-in DNS resolver to make TCP and UDP connections 140 // to DNS services. The host in the address parameter will 141 // always be a literal IP address and not a host name, and the 142 // port in the address parameter will be a literal port number 143 // and not a service name. 144 // If the Conn returned is also a PacketConn, sent and received DNS 145 // messages must adhere to RFC 1035 section 4.2.1, "UDP usage". 146 // Otherwise, DNS messages transmitted over Conn must adhere 147 // to RFC 7766 section 5, "Transport Protocol Selection". 148 // If nil, the default dialer is used. 149 Dial func(ctx context.Context, network, address string) (Conn, error) 150 151 // lookupGroup merges LookupIPAddr calls together for lookups for the same 152 // host. The lookupGroup key is the LookupIPAddr.host argument. 153 // The return values are ([]IPAddr, error). 154 lookupGroup singleflight.Group 155 156 // TODO(bradfitz): optional interface impl override hook 157 // TODO(bradfitz): Timeout time.Duration? 158 } 159 160 func (r *Resolver) preferGo() bool { return r != nil && r.PreferGo } 161 func (r *Resolver) strictErrors() bool { return r != nil && r.StrictErrors } 162 163 func (r *Resolver) getLookupGroup() *singleflight.Group { 164 if r == nil { 165 return &DefaultResolver.lookupGroup 166 } 167 return &r.lookupGroup 168 } 169 170 // LookupHost looks up the given host using the local resolver. 171 // It returns a slice of that host's addresses. 172 // 173 // LookupHost uses context.Background internally; to specify the context, use 174 // Resolver.LookupHost. 175 func LookupHost(host string) (addrs []string, err error) { 176 return DefaultResolver.LookupHost(context.Background(), host) 177 } 178 179 // LookupHost looks up the given host using the local resolver. 180 // It returns a slice of that host's addresses. 181 func (r *Resolver) LookupHost(ctx context.Context, host string) (addrs []string, err error) { 182 // Make sure that no matter what we do later, host=="" is rejected. 183 // parseIP, for example, does accept empty strings. 184 if host == "" { 185 return nil, &DNSError{Err: errNoSuchHost.Error(), Name: host, IsNotFound: true} 186 } 187 if ip, _ := parseIPZone(host); ip != nil { 188 return []string{host}, nil 189 } 190 return r.lookupHost(ctx, host) 191 } 192 193 // LookupIP looks up host using the local resolver. 194 // It returns a slice of that host's IPv4 and IPv6 addresses. 195 func LookupIP(host string) ([]IP, error) { 196 addrs, err := DefaultResolver.LookupIPAddr(context.Background(), host) 197 if err != nil { 198 return nil, err 199 } 200 ips := make([]IP, len(addrs)) 201 for i, ia := range addrs { 202 ips[i] = ia.IP 203 } 204 return ips, nil 205 } 206 207 // LookupIPAddr looks up host using the local resolver. 208 // It returns a slice of that host's IPv4 and IPv6 addresses. 209 func (r *Resolver) LookupIPAddr(ctx context.Context, host string) ([]IPAddr, error) { 210 return r.lookupIPAddr(ctx, "ip", host) 211 } 212 213 // LookupIP looks up host for the given network using the local resolver. 214 // It returns a slice of that host's IP addresses of the type specified by 215 // network. 216 // network must be one of "ip", "ip4" or "ip6". 217 func (r *Resolver) LookupIP(ctx context.Context, network, host string) ([]IP, error) { 218 afnet, _, err := parseNetwork(ctx, network, false) 219 if err != nil { 220 return nil, err 221 } 222 switch afnet { 223 case "ip", "ip4", "ip6": 224 default: 225 return nil, UnknownNetworkError(network) 226 } 227 228 if host == "" { 229 return nil, &DNSError{Err: errNoSuchHost.Error(), Name: host, IsNotFound: true} 230 } 231 addrs, err := r.internetAddrList(ctx, afnet, host) 232 if err != nil { 233 return nil, err 234 } 235 236 ips := make([]IP, 0, len(addrs)) 237 for _, addr := range addrs { 238 ips = append(ips, addr.(*IPAddr).IP) 239 } 240 return ips, nil 241 } 242 243 // LookupNetIP looks up host using the local resolver. 244 // It returns a slice of that host's IP addresses of the type specified by 245 // network. 246 // The network must be one of "ip", "ip4" or "ip6". 247 func (r *Resolver) LookupNetIP(ctx context.Context, network, host string) ([]netip.Addr, error) { 248 // TODO(bradfitz): make this efficient, making the internal net package 249 // type throughout be netip.Addr and only converting to the net.IP slice 250 // version at the edge. But for now (2021-10-20), this is a wrapper around 251 // the old way. 252 ips, err := r.LookupIP(ctx, network, host) 253 if err != nil { 254 return nil, err 255 } 256 ret := make([]netip.Addr, 0, len(ips)) 257 for _, ip := range ips { 258 if a, ok := netip.AddrFromSlice(ip); ok { 259 ret = append(ret, a) 260 } 261 } 262 return ret, nil 263 } 264 265 // onlyValuesCtx is a context that uses an underlying context 266 // for value lookup if the underlying context hasn't yet expired. 267 type onlyValuesCtx struct { 268 context.Context 269 lookupValues context.Context 270 } 271 272 var _ context.Context = (*onlyValuesCtx)(nil) 273 274 // Value performs a lookup if the original context hasn't expired. 275 func (ovc *onlyValuesCtx) Value(key any) any { 276 select { 277 case <-ovc.lookupValues.Done(): 278 return nil 279 default: 280 return ovc.lookupValues.Value(key) 281 } 282 } 283 284 // withUnexpiredValuesPreserved returns a context.Context that only uses lookupCtx 285 // for its values, otherwise it is never canceled and has no deadline. 286 // If the lookup context expires, any looked up values will return nil. 287 // See Issue 28600. 288 func withUnexpiredValuesPreserved(lookupCtx context.Context) context.Context { 289 return &onlyValuesCtx{Context: context.Background(), lookupValues: lookupCtx} 290 } 291 292 // lookupIPAddr looks up host using the local resolver and particular network. 293 // It returns a slice of that host's IPv4 and IPv6 addresses. 294 func (r *Resolver) lookupIPAddr(ctx context.Context, network, host string) ([]IPAddr, error) { 295 // Make sure that no matter what we do later, host=="" is rejected. 296 // parseIPZone, for example, does accept empty strings. 297 if host == "" { 298 return nil, &DNSError{Err: errNoSuchHost.Error(), Name: host, IsNotFound: true} 299 } 300 if ip, zone := parseIPZone(host); ip != nil { 301 return []IPAddr{{IP: ip, Zone: zone}}, nil 302 } 303 trace, _ := ctx.Value(nettrace.TraceKey{}).(*nettrace.Trace) 304 if trace != nil && trace.DNSStart != nil { 305 trace.DNSStart(host) 306 } 307 // The underlying resolver func is lookupIP by default but it 308 // can be overridden by tests. This is needed by net/http, so it 309 // uses a context key instead of unexported variables. 310 resolverFunc := r.lookupIP 311 if alt, _ := ctx.Value(nettrace.LookupIPAltResolverKey{}).(func(context.Context, string, string) ([]IPAddr, error)); alt != nil { 312 resolverFunc = alt 313 } 314 315 // We don't want a cancellation of ctx to affect the 316 // lookupGroup operation. Otherwise if our context gets 317 // canceled it might cause an error to be returned to a lookup 318 // using a completely different context. However we need to preserve 319 // only the values in context. See Issue 28600. 320 lookupGroupCtx, lookupGroupCancel := context.WithCancel(withUnexpiredValuesPreserved(ctx)) 321 322 lookupKey := network + "\000" + host 323 dnsWaitGroup.Add(1) 324 ch := r.getLookupGroup().DoChan(lookupKey, func() (any, error) { 325 return testHookLookupIP(lookupGroupCtx, resolverFunc, network, host) 326 }) 327 328 dnsWaitGroupDone := func(ch <-chan singleflight.Result, cancelFn context.CancelFunc) { 329 <-ch 330 dnsWaitGroup.Done() 331 cancelFn() 332 } 333 select { 334 case <-ctx.Done(): 335 // Our context was canceled. If we are the only 336 // goroutine looking up this key, then drop the key 337 // from the lookupGroup and cancel the lookup. 338 // If there are other goroutines looking up this key, 339 // let the lookup continue uncanceled, and let later 340 // lookups with the same key share the result. 341 // See issues 8602, 20703, 22724. 342 if r.getLookupGroup().ForgetUnshared(lookupKey) { 343 lookupGroupCancel() 344 go dnsWaitGroupDone(ch, func() {}) 345 } else { 346 go dnsWaitGroupDone(ch, lookupGroupCancel) 347 } 348 ctxErr := ctx.Err() 349 err := &DNSError{ 350 Err: mapErr(ctxErr).Error(), 351 Name: host, 352 IsTimeout: ctxErr == context.DeadlineExceeded, 353 } 354 if trace != nil && trace.DNSDone != nil { 355 trace.DNSDone(nil, false, err) 356 } 357 return nil, err 358 case r := <-ch: 359 dnsWaitGroup.Done() 360 lookupGroupCancel() 361 err := r.Err 362 if err != nil { 363 if _, ok := err.(*DNSError); !ok { 364 isTimeout := false 365 if err == context.DeadlineExceeded { 366 isTimeout = true 367 } else if terr, ok := err.(timeout); ok { 368 isTimeout = terr.Timeout() 369 } 370 err = &DNSError{ 371 Err: err.Error(), 372 Name: host, 373 IsTimeout: isTimeout, 374 } 375 } 376 } 377 if trace != nil && trace.DNSDone != nil { 378 addrs, _ := r.Val.([]IPAddr) 379 trace.DNSDone(ipAddrsEface(addrs), r.Shared, err) 380 } 381 return lookupIPReturn(r.Val, err, r.Shared) 382 } 383 } 384 385 // lookupIPReturn turns the return values from singleflight.Do into 386 // the return values from LookupIP. 387 func lookupIPReturn(addrsi any, err error, shared bool) ([]IPAddr, error) { 388 if err != nil { 389 return nil, err 390 } 391 addrs := addrsi.([]IPAddr) 392 if shared { 393 clone := make([]IPAddr, len(addrs)) 394 copy(clone, addrs) 395 addrs = clone 396 } 397 return addrs, nil 398 } 399 400 // ipAddrsEface returns an empty interface slice of addrs. 401 func ipAddrsEface(addrs []IPAddr) []any { 402 s := make([]any, len(addrs)) 403 for i, v := range addrs { 404 s[i] = v 405 } 406 return s 407 } 408 409 // LookupPort looks up the port for the given network and service. 410 // 411 // LookupPort uses context.Background internally; to specify the context, use 412 // Resolver.LookupPort. 413 func LookupPort(network, service string) (port int, err error) { 414 return DefaultResolver.LookupPort(context.Background(), network, service) 415 } 416 417 // LookupPort looks up the port for the given network and service. 418 func (r *Resolver) LookupPort(ctx context.Context, network, service string) (port int, err error) { 419 port, needsLookup := parsePort(service) 420 if needsLookup { 421 switch network { 422 case "tcp", "tcp4", "tcp6", "udp", "udp4", "udp6": 423 case "": // a hint wildcard for Go 1.0 undocumented behavior 424 network = "ip" 425 default: 426 return 0, &AddrError{Err: "unknown network", Addr: network} 427 } 428 port, err = r.lookupPort(ctx, network, service) 429 if err != nil { 430 return 0, err 431 } 432 } 433 if 0 > port || port > 65535 { 434 return 0, &AddrError{Err: "invalid port", Addr: service} 435 } 436 return port, nil 437 } 438 439 // LookupCNAME returns the canonical name for the given host. 440 // Callers that do not care about the canonical name can call 441 // LookupHost or LookupIP directly; both take care of resolving 442 // the canonical name as part of the lookup. 443 // 444 // A canonical name is the final name after following zero 445 // or more CNAME records. 446 // LookupCNAME does not return an error if host does not 447 // contain DNS "CNAME" records, as long as host resolves to 448 // address records. 449 // 450 // The returned canonical name is validated to be a properly 451 // formatted presentation-format domain name. 452 // 453 // LookupCNAME uses context.Background internally; to specify the context, use 454 // Resolver.LookupCNAME. 455 func LookupCNAME(host string) (cname string, err error) { 456 return DefaultResolver.LookupCNAME(context.Background(), host) 457 } 458 459 // LookupCNAME returns the canonical name for the given host. 460 // Callers that do not care about the canonical name can call 461 // LookupHost or LookupIP directly; both take care of resolving 462 // the canonical name as part of the lookup. 463 // 464 // A canonical name is the final name after following zero 465 // or more CNAME records. 466 // LookupCNAME does not return an error if host does not 467 // contain DNS "CNAME" records, as long as host resolves to 468 // address records. 469 // 470 // The returned canonical name is validated to be a properly 471 // formatted presentation-format domain name. 472 func (r *Resolver) LookupCNAME(ctx context.Context, host string) (string, error) { 473 cname, err := r.lookupCNAME(ctx, host) 474 if err != nil { 475 return "", err 476 } 477 if !isDomainName(cname) { 478 return "", &DNSError{Err: errMalformedDNSRecordsDetail, Name: host} 479 } 480 return cname, nil 481 } 482 483 // LookupSRV tries to resolve an SRV query of the given service, 484 // protocol, and domain name. The proto is "tcp" or "udp". 485 // The returned records are sorted by priority and randomized 486 // by weight within a priority. 487 // 488 // LookupSRV constructs the DNS name to look up following RFC 2782. 489 // That is, it looks up _service._proto.name. To accommodate services 490 // publishing SRV records under non-standard names, if both service 491 // and proto are empty strings, LookupSRV looks up name directly. 492 // 493 // The returned service names are validated to be properly 494 // formatted presentation-format domain names. If the response contains 495 // invalid names, those records are filtered out and an error 496 // will be returned alongside the remaining results, if any. 497 func LookupSRV(service, proto, name string) (cname string, addrs []*SRV, err error) { 498 return DefaultResolver.LookupSRV(context.Background(), service, proto, name) 499 } 500 501 // LookupSRV tries to resolve an SRV query of the given service, 502 // protocol, and domain name. The proto is "tcp" or "udp". 503 // The returned records are sorted by priority and randomized 504 // by weight within a priority. 505 // 506 // LookupSRV constructs the DNS name to look up following RFC 2782. 507 // That is, it looks up _service._proto.name. To accommodate services 508 // publishing SRV records under non-standard names, if both service 509 // and proto are empty strings, LookupSRV looks up name directly. 510 // 511 // The returned service names are validated to be properly 512 // formatted presentation-format domain names. If the response contains 513 // invalid names, those records are filtered out and an error 514 // will be returned alongside the remaining results, if any. 515 func (r *Resolver) LookupSRV(ctx context.Context, service, proto, name string) (string, []*SRV, error) { 516 cname, addrs, err := r.lookupSRV(ctx, service, proto, name) 517 if err != nil { 518 return "", nil, err 519 } 520 if cname != "" && !isDomainName(cname) { 521 return "", nil, &DNSError{Err: "SRV header name is invalid", Name: name} 522 } 523 filteredAddrs := make([]*SRV, 0, len(addrs)) 524 for _, addr := range addrs { 525 if addr == nil { 526 continue 527 } 528 if !isDomainName(addr.Target) { 529 continue 530 } 531 filteredAddrs = append(filteredAddrs, addr) 532 } 533 if len(addrs) != len(filteredAddrs) { 534 return cname, filteredAddrs, &DNSError{Err: errMalformedDNSRecordsDetail, Name: name} 535 } 536 return cname, filteredAddrs, nil 537 } 538 539 // LookupMX returns the DNS MX records for the given domain name sorted by preference. 540 // 541 // The returned mail server names are validated to be properly 542 // formatted presentation-format domain names. If the response contains 543 // invalid names, those records are filtered out and an error 544 // will be returned alongside the remaining results, if any. 545 // 546 // LookupMX uses context.Background internally; to specify the context, use 547 // Resolver.LookupMX. 548 func LookupMX(name string) ([]*MX, error) { 549 return DefaultResolver.LookupMX(context.Background(), name) 550 } 551 552 // LookupMX returns the DNS MX records for the given domain name sorted by preference. 553 // 554 // The returned mail server names are validated to be properly 555 // formatted presentation-format domain names. If the response contains 556 // invalid names, those records are filtered out and an error 557 // will be returned alongside the remaining results, if any. 558 func (r *Resolver) LookupMX(ctx context.Context, name string) ([]*MX, error) { 559 records, err := r.lookupMX(ctx, name) 560 if err != nil { 561 return nil, err 562 } 563 filteredMX := make([]*MX, 0, len(records)) 564 for _, mx := range records { 565 if mx == nil { 566 continue 567 } 568 if !isDomainName(mx.Host) { 569 continue 570 } 571 filteredMX = append(filteredMX, mx) 572 } 573 if len(records) != len(filteredMX) { 574 return filteredMX, &DNSError{Err: errMalformedDNSRecordsDetail, Name: name} 575 } 576 return filteredMX, nil 577 } 578 579 // LookupNS returns the DNS NS records for the given domain name. 580 // 581 // The returned name server names are validated to be properly 582 // formatted presentation-format domain names. If the response contains 583 // invalid names, those records are filtered out and an error 584 // will be returned alongside the remaining results, if any. 585 // 586 // LookupNS uses context.Background internally; to specify the context, use 587 // Resolver.LookupNS. 588 func LookupNS(name string) ([]*NS, error) { 589 return DefaultResolver.LookupNS(context.Background(), name) 590 } 591 592 // LookupNS returns the DNS NS records for the given domain name. 593 // 594 // The returned name server names are validated to be properly 595 // formatted presentation-format domain names. If the response contains 596 // invalid names, those records are filtered out and an error 597 // will be returned alongside the remaining results, if any. 598 func (r *Resolver) LookupNS(ctx context.Context, name string) ([]*NS, error) { 599 records, err := r.lookupNS(ctx, name) 600 if err != nil { 601 return nil, err 602 } 603 filteredNS := make([]*NS, 0, len(records)) 604 for _, ns := range records { 605 if ns == nil { 606 continue 607 } 608 if !isDomainName(ns.Host) { 609 continue 610 } 611 filteredNS = append(filteredNS, ns) 612 } 613 if len(records) != len(filteredNS) { 614 return filteredNS, &DNSError{Err: errMalformedDNSRecordsDetail, Name: name} 615 } 616 return filteredNS, nil 617 } 618 619 // LookupTXT returns the DNS TXT records for the given domain name. 620 // 621 // LookupTXT uses context.Background internally; to specify the context, use 622 // Resolver.LookupTXT. 623 func LookupTXT(name string) ([]string, error) { 624 return DefaultResolver.lookupTXT(context.Background(), name) 625 } 626 627 // LookupTXT returns the DNS TXT records for the given domain name. 628 func (r *Resolver) LookupTXT(ctx context.Context, name string) ([]string, error) { 629 return r.lookupTXT(ctx, name) 630 } 631 632 // LookupAddr performs a reverse lookup for the given address, returning a list 633 // of names mapping to that address. 634 // 635 // The returned names are validated to be properly formatted presentation-format 636 // domain names. If the response contains invalid names, those records are filtered 637 // out and an error will be returned alongside the remaining results, if any. 638 // 639 // When using the host C library resolver, at most one result will be 640 // returned. To bypass the host resolver, use a custom Resolver. 641 // 642 // LookupAddr uses context.Background internally; to specify the context, use 643 // Resolver.LookupAddr. 644 func LookupAddr(addr string) (names []string, err error) { 645 return DefaultResolver.LookupAddr(context.Background(), addr) 646 } 647 648 // LookupAddr performs a reverse lookup for the given address, returning a list 649 // of names mapping to that address. 650 // 651 // The returned names are validated to be properly formatted presentation-format 652 // domain names. If the response contains invalid names, those records are filtered 653 // out and an error will be returned alongside the remaining results, if any. 654 func (r *Resolver) LookupAddr(ctx context.Context, addr string) ([]string, error) { 655 names, err := r.lookupAddr(ctx, addr) 656 if err != nil { 657 return nil, err 658 } 659 filteredNames := make([]string, 0, len(names)) 660 for _, name := range names { 661 if isDomainName(name) { 662 filteredNames = append(filteredNames, name) 663 } 664 } 665 if len(names) != len(filteredNames) { 666 return filteredNames, &DNSError{Err: errMalformedDNSRecordsDetail, Name: addr} 667 } 668 return filteredNames, nil 669 } 670 671 // errMalformedDNSRecordsDetail is the DNSError detail which is returned when a Resolver.Lookup... 672 // method receives DNS records which contain invalid DNS names. This may be returned alongside 673 // results which have had the malformed records filtered out. 674 var errMalformedDNSRecordsDetail = "DNS response contained records which contain invalid names" 675 676 // dial makes a new connection to the provided server (which must be 677 // an IP address) with the provided network type, using either r.Dial 678 // (if both r and r.Dial are non-nil) or else Dialer.DialContext. 679 func (r *Resolver) dial(ctx context.Context, network, server string) (Conn, error) { 680 // Calling Dial here is scary -- we have to be sure not to 681 // dial a name that will require a DNS lookup, or Dial will 682 // call back here to translate it. The DNS config parser has 683 // already checked that all the cfg.servers are IP 684 // addresses, which Dial will use without a DNS lookup. 685 var c Conn 686 var err error 687 if r != nil && r.Dial != nil { 688 c, err = r.Dial(ctx, network, server) 689 } else { 690 var d Dialer 691 c, err = d.DialContext(ctx, network, server) 692 } 693 if err != nil { 694 return nil, mapErr(err) 695 } 696 return c, nil 697 } 698 699 // goLookupSRV returns the SRV records for a target name, built either 700 // from its component service ("sip"), protocol ("tcp"), and name 701 // ("example.com."), or from name directly (if service and proto are 702 // both empty). 703 // 704 // In either case, the returned target name ("_sip._tcp.example.com.") 705 // is also returned on success. 706 // 707 // The records are sorted by weight. 708 func (r *Resolver) goLookupSRV(ctx context.Context, service, proto, name string) (target string, srvs []*SRV, err error) { 709 if service == "" && proto == "" { 710 target = name 711 } else { 712 target = "_" + service + "._" + proto + "." + name 713 } 714 p, server, err := r.lookup(ctx, target, dnsmessage.TypeSRV) 715 if err != nil { 716 return "", nil, err 717 } 718 var cname dnsmessage.Name 719 for { 720 h, err := p.AnswerHeader() 721 if err == dnsmessage.ErrSectionDone { 722 break 723 } 724 if err != nil { 725 return "", nil, &DNSError{ 726 Err: "cannot unmarshal DNS message", 727 Name: name, 728 Server: server, 729 } 730 } 731 if h.Type != dnsmessage.TypeSRV { 732 if err := p.SkipAnswer(); err != nil { 733 return "", nil, &DNSError{ 734 Err: "cannot unmarshal DNS message", 735 Name: name, 736 Server: server, 737 } 738 } 739 continue 740 } 741 if cname.Length == 0 && h.Name.Length != 0 { 742 cname = h.Name 743 } 744 srv, err := p.SRVResource() 745 if err != nil { 746 return "", nil, &DNSError{ 747 Err: "cannot unmarshal DNS message", 748 Name: name, 749 Server: server, 750 } 751 } 752 srvs = append(srvs, &SRV{Target: srv.Target.String(), Port: srv.Port, Priority: srv.Priority, Weight: srv.Weight}) 753 } 754 byPriorityWeight(srvs).sort() 755 return cname.String(), srvs, nil 756 } 757 758 // goLookupMX returns the MX records for name. 759 func (r *Resolver) goLookupMX(ctx context.Context, name string) ([]*MX, error) { 760 p, server, err := r.lookup(ctx, name, dnsmessage.TypeMX) 761 if err != nil { 762 return nil, err 763 } 764 var mxs []*MX 765 for { 766 h, err := p.AnswerHeader() 767 if err == dnsmessage.ErrSectionDone { 768 break 769 } 770 if err != nil { 771 return nil, &DNSError{ 772 Err: "cannot unmarshal DNS message", 773 Name: name, 774 Server: server, 775 } 776 } 777 if h.Type != dnsmessage.TypeMX { 778 if err := p.SkipAnswer(); err != nil { 779 return nil, &DNSError{ 780 Err: "cannot unmarshal DNS message", 781 Name: name, 782 Server: server, 783 } 784 } 785 continue 786 } 787 mx, err := p.MXResource() 788 if err != nil { 789 return nil, &DNSError{ 790 Err: "cannot unmarshal DNS message", 791 Name: name, 792 Server: server, 793 } 794 } 795 mxs = append(mxs, &MX{Host: mx.MX.String(), Pref: mx.Pref}) 796 797 } 798 byPref(mxs).sort() 799 return mxs, nil 800 } 801 802 // goLookupNS returns the NS records for name. 803 func (r *Resolver) goLookupNS(ctx context.Context, name string) ([]*NS, error) { 804 p, server, err := r.lookup(ctx, name, dnsmessage.TypeNS) 805 if err != nil { 806 return nil, err 807 } 808 var nss []*NS 809 for { 810 h, err := p.AnswerHeader() 811 if err == dnsmessage.ErrSectionDone { 812 break 813 } 814 if err != nil { 815 return nil, &DNSError{ 816 Err: "cannot unmarshal DNS message", 817 Name: name, 818 Server: server, 819 } 820 } 821 if h.Type != dnsmessage.TypeNS { 822 if err := p.SkipAnswer(); err != nil { 823 return nil, &DNSError{ 824 Err: "cannot unmarshal DNS message", 825 Name: name, 826 Server: server, 827 } 828 } 829 continue 830 } 831 ns, err := p.NSResource() 832 if err != nil { 833 return nil, &DNSError{ 834 Err: "cannot unmarshal DNS message", 835 Name: name, 836 Server: server, 837 } 838 } 839 nss = append(nss, &NS{Host: ns.NS.String()}) 840 } 841 return nss, nil 842 } 843 844 // goLookupTXT returns the TXT records from name. 845 func (r *Resolver) goLookupTXT(ctx context.Context, name string) ([]string, error) { 846 p, server, err := r.lookup(ctx, name, dnsmessage.TypeTXT) 847 if err != nil { 848 return nil, err 849 } 850 var txts []string 851 for { 852 h, err := p.AnswerHeader() 853 if err == dnsmessage.ErrSectionDone { 854 break 855 } 856 if err != nil { 857 return nil, &DNSError{ 858 Err: "cannot unmarshal DNS message", 859 Name: name, 860 Server: server, 861 } 862 } 863 if h.Type != dnsmessage.TypeTXT { 864 if err := p.SkipAnswer(); err != nil { 865 return nil, &DNSError{ 866 Err: "cannot unmarshal DNS message", 867 Name: name, 868 Server: server, 869 } 870 } 871 continue 872 } 873 txt, err := p.TXTResource() 874 if err != nil { 875 return nil, &DNSError{ 876 Err: "cannot unmarshal DNS message", 877 Name: name, 878 Server: server, 879 } 880 } 881 // Multiple strings in one TXT record need to be 882 // concatenated without separator to be consistent 883 // with previous Go resolver. 884 n := 0 885 for _, s := range txt.TXT { 886 n += len(s) 887 } 888 txtJoin := make([]byte, 0, n) 889 for _, s := range txt.TXT { 890 txtJoin = append(txtJoin, s...) 891 } 892 if len(txts) == 0 { 893 txts = make([]string, 0, 1) 894 } 895 txts = append(txts, string(txtJoin)) 896 } 897 return txts, nil 898 }