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