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