github.com/ice-blockchain/go/src@v0.0.0-20240403114104-1564d284e521/net/dnsclient_unix.go (about) 1 // Copyright 2009 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 // DNS client: see RFC 1035. 6 // Has to be linked into package net for Dial. 7 8 // TODO(rsc): 9 // Could potentially handle many outstanding lookups faster. 10 // Random UDP source port (net.Dial should do that for us). 11 // Random request IDs. 12 13 package net 14 15 import ( 16 "context" 17 "errors" 18 "internal/bytealg" 19 "internal/itoa" 20 "io" 21 "os" 22 "runtime" 23 "sync" 24 "sync/atomic" 25 "time" 26 27 "golang.org/x/net/dns/dnsmessage" 28 ) 29 30 const ( 31 // to be used as a useTCP parameter to exchange 32 useTCPOnly = true 33 useUDPOrTCP = false 34 35 // Maximum DNS packet size. 36 // Value taken from https://dnsflagday.net/2020/. 37 maxDNSPacketSize = 1232 38 ) 39 40 var ( 41 errLameReferral = errors.New("lame referral") 42 errCannotUnmarshalDNSMessage = errors.New("cannot unmarshal DNS message") 43 errCannotMarshalDNSMessage = errors.New("cannot marshal DNS message") 44 errServerMisbehaving = errors.New("server misbehaving") 45 errInvalidDNSResponse = errors.New("invalid DNS response") 46 errNoAnswerFromDNSServer = errors.New("no answer from DNS server") 47 48 // errServerTemporarilyMisbehaving is like errServerMisbehaving, except 49 // that when it gets translated to a DNSError, the IsTemporary field 50 // gets set to true. 51 errServerTemporarilyMisbehaving = errors.New("server misbehaving") 52 ) 53 54 func newRequest(q dnsmessage.Question, ad bool) (id uint16, udpReq, tcpReq []byte, err error) { 55 id = uint16(randInt()) 56 b := dnsmessage.NewBuilder(make([]byte, 2, 514), dnsmessage.Header{ID: id, RecursionDesired: true, AuthenticData: ad}) 57 if err := b.StartQuestions(); err != nil { 58 return 0, nil, nil, err 59 } 60 if err := b.Question(q); err != nil { 61 return 0, nil, nil, err 62 } 63 64 // Accept packets up to maxDNSPacketSize. RFC 6891. 65 if err := b.StartAdditionals(); err != nil { 66 return 0, nil, nil, err 67 } 68 var rh dnsmessage.ResourceHeader 69 if err := rh.SetEDNS0(maxDNSPacketSize, dnsmessage.RCodeSuccess, false); err != nil { 70 return 0, nil, nil, err 71 } 72 if err := b.OPTResource(rh, dnsmessage.OPTResource{}); err != nil { 73 return 0, nil, nil, err 74 } 75 76 tcpReq, err = b.Finish() 77 if err != nil { 78 return 0, nil, nil, err 79 } 80 udpReq = tcpReq[2:] 81 l := len(tcpReq) - 2 82 tcpReq[0] = byte(l >> 8) 83 tcpReq[1] = byte(l) 84 return id, udpReq, tcpReq, nil 85 } 86 87 func checkResponse(reqID uint16, reqQues dnsmessage.Question, respHdr dnsmessage.Header, respQues dnsmessage.Question) bool { 88 if !respHdr.Response { 89 return false 90 } 91 if reqID != respHdr.ID { 92 return false 93 } 94 if reqQues.Type != respQues.Type || reqQues.Class != respQues.Class || !equalASCIIName(reqQues.Name, respQues.Name) { 95 return false 96 } 97 return true 98 } 99 100 func dnsPacketRoundTrip(c Conn, id uint16, query dnsmessage.Question, b []byte) (dnsmessage.Parser, dnsmessage.Header, error) { 101 if _, err := c.Write(b); err != nil { 102 return dnsmessage.Parser{}, dnsmessage.Header{}, err 103 } 104 105 b = make([]byte, maxDNSPacketSize) 106 for { 107 n, err := c.Read(b) 108 if err != nil { 109 return dnsmessage.Parser{}, dnsmessage.Header{}, err 110 } 111 var p dnsmessage.Parser 112 // Ignore invalid responses as they may be malicious 113 // forgery attempts. Instead continue waiting until 114 // timeout. See golang.org/issue/13281. 115 h, err := p.Start(b[:n]) 116 if err != nil { 117 continue 118 } 119 q, err := p.Question() 120 if err != nil || !checkResponse(id, query, h, q) { 121 continue 122 } 123 return p, h, nil 124 } 125 } 126 127 func dnsStreamRoundTrip(c Conn, id uint16, query dnsmessage.Question, b []byte) (dnsmessage.Parser, dnsmessage.Header, error) { 128 if _, err := c.Write(b); err != nil { 129 return dnsmessage.Parser{}, dnsmessage.Header{}, err 130 } 131 132 b = make([]byte, 1280) // 1280 is a reasonable initial size for IP over Ethernet, see RFC 4035 133 if _, err := io.ReadFull(c, b[:2]); err != nil { 134 return dnsmessage.Parser{}, dnsmessage.Header{}, err 135 } 136 l := int(b[0])<<8 | int(b[1]) 137 if l > len(b) { 138 b = make([]byte, l) 139 } 140 n, err := io.ReadFull(c, b[:l]) 141 if err != nil { 142 return dnsmessage.Parser{}, dnsmessage.Header{}, err 143 } 144 var p dnsmessage.Parser 145 h, err := p.Start(b[:n]) 146 if err != nil { 147 return dnsmessage.Parser{}, dnsmessage.Header{}, errCannotUnmarshalDNSMessage 148 } 149 q, err := p.Question() 150 if err != nil { 151 return dnsmessage.Parser{}, dnsmessage.Header{}, errCannotUnmarshalDNSMessage 152 } 153 if !checkResponse(id, query, h, q) { 154 return dnsmessage.Parser{}, dnsmessage.Header{}, errInvalidDNSResponse 155 } 156 return p, h, nil 157 } 158 159 // exchange sends a query on the connection and hopes for a response. 160 func (r *Resolver) exchange(ctx context.Context, server string, q dnsmessage.Question, timeout time.Duration, useTCP, ad bool) (dnsmessage.Parser, dnsmessage.Header, error) { 161 q.Class = dnsmessage.ClassINET 162 id, udpReq, tcpReq, err := newRequest(q, ad) 163 if err != nil { 164 return dnsmessage.Parser{}, dnsmessage.Header{}, errCannotMarshalDNSMessage 165 } 166 var networks []string 167 if useTCP { 168 networks = []string{"tcp"} 169 } else { 170 networks = []string{"udp", "tcp"} 171 } 172 for _, network := range networks { 173 ctx, cancel := context.WithDeadline(ctx, time.Now().Add(timeout)) 174 defer cancel() 175 176 c, err := r.dial(ctx, network, server) 177 if err != nil { 178 return dnsmessage.Parser{}, dnsmessage.Header{}, err 179 } 180 if d, ok := ctx.Deadline(); ok && !d.IsZero() { 181 c.SetDeadline(d) 182 } 183 var p dnsmessage.Parser 184 var h dnsmessage.Header 185 if _, ok := c.(PacketConn); ok { 186 p, h, err = dnsPacketRoundTrip(c, id, q, udpReq) 187 } else { 188 p, h, err = dnsStreamRoundTrip(c, id, q, tcpReq) 189 } 190 c.Close() 191 if err != nil { 192 return dnsmessage.Parser{}, dnsmessage.Header{}, mapErr(err) 193 } 194 if err := p.SkipQuestion(); err != dnsmessage.ErrSectionDone { 195 return dnsmessage.Parser{}, dnsmessage.Header{}, errInvalidDNSResponse 196 } 197 // RFC 5966 indicates that when a client receives a UDP response with 198 // the TC flag set, it should take the TC flag as an indication that it 199 // should retry over TCP instead. 200 // The case when the TC flag is set in a TCP response is not well specified, 201 // so this implements the glibc resolver behavior, returning the existing 202 // dns response instead of returning a "errNoAnswerFromDNSServer" error. 203 // See go.dev/issue/64896 204 if h.Truncated && network == "udp" { 205 continue 206 } 207 return p, h, nil 208 } 209 return dnsmessage.Parser{}, dnsmessage.Header{}, errNoAnswerFromDNSServer 210 } 211 212 // checkHeader performs basic sanity checks on the header. 213 func checkHeader(p *dnsmessage.Parser, h dnsmessage.Header) error { 214 rcode, hasAdd := extractExtendedRCode(*p, h) 215 216 if rcode == dnsmessage.RCodeNameError { 217 return errNoSuchHost 218 } 219 220 _, err := p.AnswerHeader() 221 if err != nil && err != dnsmessage.ErrSectionDone { 222 return errCannotUnmarshalDNSMessage 223 } 224 225 // libresolv continues to the next server when it receives 226 // an invalid referral response. See golang.org/issue/15434. 227 if rcode == dnsmessage.RCodeSuccess && !h.Authoritative && !h.RecursionAvailable && err == dnsmessage.ErrSectionDone && !hasAdd { 228 return errLameReferral 229 } 230 231 if rcode != dnsmessage.RCodeSuccess && rcode != dnsmessage.RCodeNameError { 232 // None of the error codes make sense 233 // for the query we sent. If we didn't get 234 // a name error and we didn't get success, 235 // the server is behaving incorrectly or 236 // having temporary trouble. 237 if rcode == dnsmessage.RCodeServerFailure { 238 return errServerTemporarilyMisbehaving 239 } 240 return errServerMisbehaving 241 } 242 243 return nil 244 } 245 246 func skipToAnswer(p *dnsmessage.Parser, qtype dnsmessage.Type) error { 247 for { 248 h, err := p.AnswerHeader() 249 if err == dnsmessage.ErrSectionDone { 250 return errNoSuchHost 251 } 252 if err != nil { 253 return errCannotUnmarshalDNSMessage 254 } 255 if h.Type == qtype { 256 return nil 257 } 258 if err := p.SkipAnswer(); err != nil { 259 return errCannotUnmarshalDNSMessage 260 } 261 } 262 } 263 264 // extractExtendedRCode extracts the extended RCode from the OPT resource (EDNS(0)) 265 // If an OPT record is not found, the RCode from the hdr is returned. 266 // Another return value indicates whether an additional resource was found. 267 func extractExtendedRCode(p dnsmessage.Parser, hdr dnsmessage.Header) (dnsmessage.RCode, bool) { 268 p.SkipAllAnswers() 269 p.SkipAllAuthorities() 270 hasAdd := false 271 for { 272 ahdr, err := p.AdditionalHeader() 273 if err != nil { 274 return hdr.RCode, hasAdd 275 } 276 hasAdd = true 277 if ahdr.Type == dnsmessage.TypeOPT { 278 return ahdr.ExtendedRCode(hdr.RCode), hasAdd 279 } 280 p.SkipAdditional() 281 } 282 } 283 284 // Do a lookup for a single name, which must be rooted 285 // (otherwise answer will not find the answers). 286 func (r *Resolver) tryOneName(ctx context.Context, cfg *dnsConfig, name string, qtype dnsmessage.Type) (dnsmessage.Parser, string, error) { 287 var lastErr error 288 serverOffset := cfg.serverOffset() 289 sLen := uint32(len(cfg.servers)) 290 291 n, err := dnsmessage.NewName(name) 292 if err != nil { 293 return dnsmessage.Parser{}, "", errCannotMarshalDNSMessage 294 } 295 q := dnsmessage.Question{ 296 Name: n, 297 Type: qtype, 298 Class: dnsmessage.ClassINET, 299 } 300 301 for i := 0; i < cfg.attempts; i++ { 302 for j := uint32(0); j < sLen; j++ { 303 server := cfg.servers[(serverOffset+j)%sLen] 304 305 p, h, err := r.exchange(ctx, server, q, cfg.timeout, cfg.useTCP, cfg.trustAD) 306 if err != nil { 307 dnsErr := &DNSError{ 308 Err: err.Error(), 309 Name: name, 310 Server: server, 311 } 312 if nerr, ok := err.(Error); ok && nerr.Timeout() { 313 dnsErr.IsTimeout = true 314 } 315 // Set IsTemporary for socket-level errors. Note that this flag 316 // may also be used to indicate a SERVFAIL response. 317 if _, ok := err.(*OpError); ok { 318 dnsErr.IsTemporary = true 319 } 320 lastErr = dnsErr 321 continue 322 } 323 324 if err := checkHeader(&p, h); err != nil { 325 dnsErr := &DNSError{ 326 Err: err.Error(), 327 Name: name, 328 Server: server, 329 } 330 if err == errServerTemporarilyMisbehaving { 331 dnsErr.IsTemporary = true 332 } 333 if err == errNoSuchHost { 334 // The name does not exist, so trying 335 // another server won't help. 336 337 dnsErr.IsNotFound = true 338 return p, server, dnsErr 339 } 340 lastErr = dnsErr 341 continue 342 } 343 344 err = skipToAnswer(&p, qtype) 345 if err == nil { 346 return p, server, nil 347 } 348 lastErr = &DNSError{ 349 Err: err.Error(), 350 Name: name, 351 Server: server, 352 } 353 if err == errNoSuchHost { 354 // The name does not exist, so trying another 355 // server won't help. 356 357 lastErr.(*DNSError).IsNotFound = true 358 return p, server, lastErr 359 } 360 } 361 } 362 return dnsmessage.Parser{}, "", lastErr 363 } 364 365 // A resolverConfig represents a DNS stub resolver configuration. 366 type resolverConfig struct { 367 initOnce sync.Once // guards init of resolverConfig 368 369 // ch is used as a semaphore that only allows one lookup at a 370 // time to recheck resolv.conf. 371 ch chan struct{} // guards lastChecked and modTime 372 lastChecked time.Time // last time resolv.conf was checked 373 374 dnsConfig atomic.Pointer[dnsConfig] // parsed resolv.conf structure used in lookups 375 } 376 377 var resolvConf resolverConfig 378 379 func getSystemDNSConfig() *dnsConfig { 380 resolvConf.tryUpdate("/etc/resolv.conf") 381 return resolvConf.dnsConfig.Load() 382 } 383 384 // init initializes conf and is only called via conf.initOnce. 385 func (conf *resolverConfig) init() { 386 // Set dnsConfig and lastChecked so we don't parse 387 // resolv.conf twice the first time. 388 conf.dnsConfig.Store(dnsReadConfig("/etc/resolv.conf")) 389 conf.lastChecked = time.Now() 390 391 // Prepare ch so that only one update of resolverConfig may 392 // run at once. 393 conf.ch = make(chan struct{}, 1) 394 } 395 396 // tryUpdate tries to update conf with the named resolv.conf file. 397 // The name variable only exists for testing. It is otherwise always 398 // "/etc/resolv.conf". 399 func (conf *resolverConfig) tryUpdate(name string) { 400 conf.initOnce.Do(conf.init) 401 402 if conf.dnsConfig.Load().noReload { 403 return 404 } 405 406 // Ensure only one update at a time checks resolv.conf. 407 if !conf.tryAcquireSema() { 408 return 409 } 410 defer conf.releaseSema() 411 412 now := time.Now() 413 if conf.lastChecked.After(now.Add(-5 * time.Second)) { 414 return 415 } 416 conf.lastChecked = now 417 418 switch runtime.GOOS { 419 case "windows": 420 // There's no file on disk, so don't bother checking 421 // and failing. 422 // 423 // The Windows implementation of dnsReadConfig (called 424 // below) ignores the name. 425 default: 426 var mtime time.Time 427 if fi, err := os.Stat(name); err == nil { 428 mtime = fi.ModTime() 429 } 430 if mtime.Equal(conf.dnsConfig.Load().mtime) { 431 return 432 } 433 } 434 435 dnsConf := dnsReadConfig(name) 436 conf.dnsConfig.Store(dnsConf) 437 } 438 439 func (conf *resolverConfig) tryAcquireSema() bool { 440 select { 441 case conf.ch <- struct{}{}: 442 return true 443 default: 444 return false 445 } 446 } 447 448 func (conf *resolverConfig) releaseSema() { 449 <-conf.ch 450 } 451 452 func (r *Resolver) lookup(ctx context.Context, name string, qtype dnsmessage.Type, conf *dnsConfig) (dnsmessage.Parser, string, error) { 453 if !isDomainName(name) { 454 // We used to use "invalid domain name" as the error, 455 // but that is a detail of the specific lookup mechanism. 456 // Other lookups might allow broader name syntax 457 // (for example Multicast DNS allows UTF-8; see RFC 6762). 458 // For consistency with libc resolvers, report no such host. 459 return dnsmessage.Parser{}, "", &DNSError{Err: errNoSuchHost.Error(), Name: name, IsNotFound: true} 460 } 461 462 if conf == nil { 463 conf = getSystemDNSConfig() 464 } 465 466 var ( 467 p dnsmessage.Parser 468 server string 469 err error 470 ) 471 for _, fqdn := range conf.nameList(name) { 472 p, server, err = r.tryOneName(ctx, conf, fqdn, qtype) 473 if err == nil { 474 break 475 } 476 if nerr, ok := err.(Error); ok && nerr.Temporary() && r.strictErrors() { 477 // If we hit a temporary error with StrictErrors enabled, 478 // stop immediately instead of trying more names. 479 break 480 } 481 } 482 if err == nil { 483 return p, server, nil 484 } 485 if err, ok := err.(*DNSError); ok { 486 // Show original name passed to lookup, not suffixed one. 487 // In general we might have tried many suffixes; showing 488 // just one is misleading. See also golang.org/issue/6324. 489 err.Name = name 490 } 491 return dnsmessage.Parser{}, "", err 492 } 493 494 // avoidDNS reports whether this is a hostname for which we should not 495 // use DNS. Currently this includes only .onion, per RFC 7686. See 496 // golang.org/issue/13705. Does not cover .local names (RFC 6762), 497 // see golang.org/issue/16739. 498 func avoidDNS(name string) bool { 499 if name == "" { 500 return true 501 } 502 if name[len(name)-1] == '.' { 503 name = name[:len(name)-1] 504 } 505 return stringsHasSuffixFold(name, ".onion") 506 } 507 508 // nameList returns a list of names for sequential DNS queries. 509 func (conf *dnsConfig) nameList(name string) []string { 510 // Check name length (see isDomainName). 511 l := len(name) 512 rooted := l > 0 && name[l-1] == '.' 513 if l > 254 || l == 254 && !rooted { 514 return nil 515 } 516 517 // If name is rooted (trailing dot), try only that name. 518 if rooted { 519 if avoidDNS(name) { 520 return nil 521 } 522 return []string{name} 523 } 524 525 hasNdots := bytealg.CountString(name, '.') >= conf.ndots 526 name += "." 527 l++ 528 529 // Build list of search choices. 530 names := make([]string, 0, 1+len(conf.search)) 531 // If name has enough dots, try unsuffixed first. 532 if hasNdots && !avoidDNS(name) { 533 names = append(names, name) 534 } 535 // Try suffixes that are not too long (see isDomainName). 536 for _, suffix := range conf.search { 537 fqdn := name + suffix 538 if !avoidDNS(fqdn) && len(fqdn) <= 254 { 539 names = append(names, fqdn) 540 } 541 } 542 // Try unsuffixed, if not tried first above. 543 if !hasNdots && !avoidDNS(name) { 544 names = append(names, name) 545 } 546 return names 547 } 548 549 // hostLookupOrder specifies the order of LookupHost lookup strategies. 550 // It is basically a simplified representation of nsswitch.conf. 551 // "files" means /etc/hosts. 552 type hostLookupOrder int 553 554 const ( 555 // hostLookupCgo means defer to cgo. 556 hostLookupCgo hostLookupOrder = iota 557 hostLookupFilesDNS // files first 558 hostLookupDNSFiles // dns first 559 hostLookupFiles // only files 560 hostLookupDNS // only DNS 561 ) 562 563 var lookupOrderName = map[hostLookupOrder]string{ 564 hostLookupCgo: "cgo", 565 hostLookupFilesDNS: "files,dns", 566 hostLookupDNSFiles: "dns,files", 567 hostLookupFiles: "files", 568 hostLookupDNS: "dns", 569 } 570 571 func (o hostLookupOrder) String() string { 572 if s, ok := lookupOrderName[o]; ok { 573 return s 574 } 575 return "hostLookupOrder=" + itoa.Itoa(int(o)) + "??" 576 } 577 578 func (r *Resolver) goLookupHostOrder(ctx context.Context, name string, order hostLookupOrder, conf *dnsConfig) (addrs []string, err error) { 579 if order == hostLookupFilesDNS || order == hostLookupFiles { 580 // Use entries from /etc/hosts if they match. 581 addrs, _ = lookupStaticHost(name) 582 if len(addrs) > 0 { 583 return 584 } 585 586 if order == hostLookupFiles { 587 return nil, &DNSError{Err: errNoSuchHost.Error(), Name: name, IsNotFound: true} 588 } 589 } 590 ips, _, err := r.goLookupIPCNAMEOrder(ctx, "ip", name, order, conf) 591 if err != nil { 592 return 593 } 594 addrs = make([]string, 0, len(ips)) 595 for _, ip := range ips { 596 addrs = append(addrs, ip.String()) 597 } 598 return 599 } 600 601 // lookup entries from /etc/hosts 602 func goLookupIPFiles(name string) (addrs []IPAddr, canonical string) { 603 addr, canonical := lookupStaticHost(name) 604 for _, haddr := range addr { 605 haddr, zone := splitHostZone(haddr) 606 if ip := ParseIP(haddr); ip != nil { 607 addr := IPAddr{IP: ip, Zone: zone} 608 addrs = append(addrs, addr) 609 } 610 } 611 sortByRFC6724(addrs) 612 return addrs, canonical 613 } 614 615 // goLookupIP is the native Go implementation of LookupIP. 616 // The libc versions are in cgo_*.go. 617 func (r *Resolver) goLookupIP(ctx context.Context, network, host string, order hostLookupOrder, conf *dnsConfig) (addrs []IPAddr, err error) { 618 addrs, _, err = r.goLookupIPCNAMEOrder(ctx, network, host, order, conf) 619 return 620 } 621 622 func (r *Resolver) goLookupIPCNAMEOrder(ctx context.Context, network, name string, order hostLookupOrder, conf *dnsConfig) (addrs []IPAddr, cname dnsmessage.Name, err error) { 623 if order == hostLookupFilesDNS || order == hostLookupFiles { 624 var canonical string 625 addrs, canonical = goLookupIPFiles(name) 626 627 if len(addrs) > 0 { 628 var err error 629 cname, err = dnsmessage.NewName(canonical) 630 if err != nil { 631 return nil, dnsmessage.Name{}, err 632 } 633 return addrs, cname, nil 634 } 635 636 if order == hostLookupFiles { 637 return nil, dnsmessage.Name{}, &DNSError{Err: errNoSuchHost.Error(), Name: name, IsNotFound: true} 638 } 639 } 640 641 if !isDomainName(name) { 642 // See comment in func lookup above about use of errNoSuchHost. 643 return nil, dnsmessage.Name{}, &DNSError{Err: errNoSuchHost.Error(), Name: name, IsNotFound: true} 644 } 645 type result struct { 646 p dnsmessage.Parser 647 server string 648 error 649 } 650 651 if conf == nil { 652 conf = getSystemDNSConfig() 653 } 654 655 lane := make(chan result, 1) 656 qtypes := []dnsmessage.Type{dnsmessage.TypeA, dnsmessage.TypeAAAA} 657 if network == "CNAME" { 658 qtypes = append(qtypes, dnsmessage.TypeCNAME) 659 } 660 switch ipVersion(network) { 661 case '4': 662 qtypes = []dnsmessage.Type{dnsmessage.TypeA} 663 case '6': 664 qtypes = []dnsmessage.Type{dnsmessage.TypeAAAA} 665 } 666 var queryFn func(fqdn string, qtype dnsmessage.Type) 667 var responseFn func(fqdn string, qtype dnsmessage.Type) result 668 if conf.singleRequest { 669 queryFn = func(fqdn string, qtype dnsmessage.Type) {} 670 responseFn = func(fqdn string, qtype dnsmessage.Type) result { 671 dnsWaitGroup.Add(1) 672 defer dnsWaitGroup.Done() 673 p, server, err := r.tryOneName(ctx, conf, fqdn, qtype) 674 return result{p, server, err} 675 } 676 } else { 677 queryFn = func(fqdn string, qtype dnsmessage.Type) { 678 dnsWaitGroup.Add(1) 679 go func(qtype dnsmessage.Type) { 680 p, server, err := r.tryOneName(ctx, conf, fqdn, qtype) 681 lane <- result{p, server, err} 682 dnsWaitGroup.Done() 683 }(qtype) 684 } 685 responseFn = func(fqdn string, qtype dnsmessage.Type) result { 686 return <-lane 687 } 688 } 689 var lastErr error 690 for _, fqdn := range conf.nameList(name) { 691 for _, qtype := range qtypes { 692 queryFn(fqdn, qtype) 693 } 694 hitStrictError := false 695 for _, qtype := range qtypes { 696 result := responseFn(fqdn, qtype) 697 if result.error != nil { 698 if nerr, ok := result.error.(Error); ok && nerr.Temporary() && r.strictErrors() { 699 // This error will abort the nameList loop. 700 hitStrictError = true 701 lastErr = result.error 702 } else if lastErr == nil || fqdn == name+"." { 703 // Prefer error for original name. 704 lastErr = result.error 705 } 706 continue 707 } 708 709 // Presotto says it's okay to assume that servers listed in 710 // /etc/resolv.conf are recursive resolvers. 711 // 712 // We asked for recursion, so it should have included all the 713 // answers we need in this one packet. 714 // 715 // Further, RFC 1034 section 4.3.1 says that "the recursive 716 // response to a query will be... The answer to the query, 717 // possibly preface by one or more CNAME RRs that specify 718 // aliases encountered on the way to an answer." 719 // 720 // Therefore, we should be able to assume that we can ignore 721 // CNAMEs and that the A and AAAA records we requested are 722 // for the canonical name. 723 724 loop: 725 for { 726 h, err := result.p.AnswerHeader() 727 if err != nil && err != dnsmessage.ErrSectionDone { 728 lastErr = &DNSError{ 729 Err: errCannotUnmarshalDNSMessage.Error(), 730 Name: name, 731 Server: result.server, 732 } 733 } 734 if err != nil { 735 break 736 } 737 switch h.Type { 738 case dnsmessage.TypeA: 739 a, err := result.p.AResource() 740 if err != nil { 741 lastErr = &DNSError{ 742 Err: errCannotUnmarshalDNSMessage.Error(), 743 Name: name, 744 Server: result.server, 745 } 746 break loop 747 } 748 addrs = append(addrs, IPAddr{IP: IP(a.A[:])}) 749 if cname.Length == 0 && h.Name.Length != 0 { 750 cname = h.Name 751 } 752 753 case dnsmessage.TypeAAAA: 754 aaaa, err := result.p.AAAAResource() 755 if err != nil { 756 lastErr = &DNSError{ 757 Err: errCannotUnmarshalDNSMessage.Error(), 758 Name: name, 759 Server: result.server, 760 } 761 break loop 762 } 763 addrs = append(addrs, IPAddr{IP: IP(aaaa.AAAA[:])}) 764 if cname.Length == 0 && h.Name.Length != 0 { 765 cname = h.Name 766 } 767 768 case dnsmessage.TypeCNAME: 769 c, err := result.p.CNAMEResource() 770 if err != nil { 771 lastErr = &DNSError{ 772 Err: errCannotUnmarshalDNSMessage.Error(), 773 Name: name, 774 Server: result.server, 775 } 776 break loop 777 } 778 if cname.Length == 0 && c.CNAME.Length > 0 { 779 cname = c.CNAME 780 } 781 782 default: 783 if err := result.p.SkipAnswer(); err != nil { 784 lastErr = &DNSError{ 785 Err: errCannotUnmarshalDNSMessage.Error(), 786 Name: name, 787 Server: result.server, 788 } 789 break loop 790 } 791 continue 792 } 793 } 794 } 795 if hitStrictError { 796 // If either family hit an error with StrictErrors enabled, 797 // discard all addresses. This ensures that network flakiness 798 // cannot turn a dualstack hostname IPv4/IPv6-only. 799 addrs = nil 800 break 801 } 802 if len(addrs) > 0 || network == "CNAME" && cname.Length > 0 { 803 break 804 } 805 } 806 if lastErr, ok := lastErr.(*DNSError); ok { 807 // Show original name passed to lookup, not suffixed one. 808 // In general we might have tried many suffixes; showing 809 // just one is misleading. See also golang.org/issue/6324. 810 lastErr.Name = name 811 } 812 sortByRFC6724(addrs) 813 if len(addrs) == 0 && !(network == "CNAME" && cname.Length > 0) { 814 if order == hostLookupDNSFiles { 815 var canonical string 816 addrs, canonical = goLookupIPFiles(name) 817 if len(addrs) > 0 { 818 var err error 819 cname, err = dnsmessage.NewName(canonical) 820 if err != nil { 821 return nil, dnsmessage.Name{}, err 822 } 823 return addrs, cname, nil 824 } 825 } 826 if lastErr != nil { 827 return nil, dnsmessage.Name{}, lastErr 828 } 829 } 830 return addrs, cname, nil 831 } 832 833 // goLookupCNAME is the native Go (non-cgo) implementation of LookupCNAME. 834 func (r *Resolver) goLookupCNAME(ctx context.Context, host string, order hostLookupOrder, conf *dnsConfig) (string, error) { 835 _, cname, err := r.goLookupIPCNAMEOrder(ctx, "CNAME", host, order, conf) 836 return cname.String(), err 837 } 838 839 // goLookupPTR is the native Go implementation of LookupAddr. 840 func (r *Resolver) goLookupPTR(ctx context.Context, addr string, order hostLookupOrder, conf *dnsConfig) ([]string, error) { 841 if order == hostLookupFiles || order == hostLookupFilesDNS { 842 names := lookupStaticAddr(addr) 843 if len(names) > 0 { 844 return names, nil 845 } 846 847 if order == hostLookupFiles { 848 return nil, &DNSError{Err: errNoSuchHost.Error(), Name: addr, IsNotFound: true} 849 } 850 } 851 852 arpa, err := reverseaddr(addr) 853 if err != nil { 854 return nil, err 855 } 856 p, server, err := r.lookup(ctx, arpa, dnsmessage.TypePTR, conf) 857 if err != nil { 858 var dnsErr *DNSError 859 if errors.As(err, &dnsErr) && dnsErr.IsNotFound { 860 if order == hostLookupDNSFiles { 861 names := lookupStaticAddr(addr) 862 if len(names) > 0 { 863 return names, nil 864 } 865 } 866 } 867 return nil, err 868 } 869 var ptrs []string 870 for { 871 h, err := p.AnswerHeader() 872 if err == dnsmessage.ErrSectionDone { 873 break 874 } 875 if err != nil { 876 return nil, &DNSError{ 877 Err: errCannotUnmarshalDNSMessage.Error(), 878 Name: addr, 879 Server: server, 880 } 881 } 882 if h.Type != dnsmessage.TypePTR { 883 err := p.SkipAnswer() 884 if err != nil { 885 return nil, &DNSError{ 886 Err: errCannotUnmarshalDNSMessage.Error(), 887 Name: addr, 888 Server: server, 889 } 890 } 891 continue 892 } 893 ptr, err := p.PTRResource() 894 if err != nil { 895 return nil, &DNSError{ 896 Err: errCannotUnmarshalDNSMessage.Error(), 897 Name: addr, 898 Server: server, 899 } 900 } 901 ptrs = append(ptrs, ptr.PTR.String()) 902 903 } 904 905 return ptrs, nil 906 }