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