github.com/c12o16h1/go/src@v0.0.0-20200114212001-5a151c0f00ed/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 // +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 15 package net 16 17 import ( 18 "context" 19 "errors" 20 "io" 21 "math/rand" 22 "os" 23 "sync" 24 "time" 25 26 "golang.org/x/net/dns/dnsmessage" 27 ) 28 29 const ( 30 // to be used as a useTCP parameter to exchange 31 useTCPOnly = true 32 useUDPOrTCP = false 33 ) 34 35 var ( 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 // errServerTemporarlyMisbehaving is like errServerMisbehaving, except 44 // that when it gets translated to a DNSError, the IsTemporary field 45 // gets set to true. 46 errServerTemporarlyMisbehaving = errors.New("server misbehaving") 47 ) 48 49 func newRequest(q dnsmessage.Question) (id uint16, udpReq, tcpReq []byte, err error) { 50 id = uint16(rand.Int()) ^ uint16(time.Now().UnixNano()) 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 67 func 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 80 func 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 107 func 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. 140 func (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. 186 func 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 errServerTemporarlyMisbehaving 210 } 211 return errServerMisbehaving 212 } 213 214 return nil 215 } 216 217 func 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). 237 func (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 == errServerTemporarlyMisbehaving { 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. 317 type 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 329 var resolvConf resolverConfig 330 331 // init initializes conf and is only called via conf.initOnce. 332 func (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". 349 func (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 378 func (conf *resolverConfig) tryAcquireSema() bool { 379 select { 380 case conf.ch <- struct{}{}: 381 return true 382 default: 383 return false 384 } 385 } 386 387 func (conf *resolverConfig) releaseSema() { 388 <-conf.ch 389 } 390 391 func (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. 436 func 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. 447 func (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. 490 type hostLookupOrder int 491 492 const ( 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 501 var lookupOrderName = map[hostLookupOrder]string{ 502 hostLookupCgo: "cgo", 503 hostLookupFilesDNS: "files,dns", 504 hostLookupDNSFiles: "dns,files", 505 hostLookupFiles: "files", 506 hostLookupDNS: "dns", 507 } 508 509 func (o hostLookupOrder) String() string { 510 if s, ok := lookupOrderName[o]; ok { 511 return s 512 } 513 return "hostLookupOrder=" + 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. 522 func (r *Resolver) goLookupHost(ctx context.Context, name string) (addrs []string, err error) { 523 return r.goLookupHostOrder(ctx, name, hostLookupFilesDNS) 524 } 525 526 func (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, 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 546 func 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. 560 func (r *Resolver) goLookupIP(ctx context.Context, host string) (addrs []IPAddr, err error) { 561 order := systemConf().hostLookupOrder(r, host) 562 addrs, _, err = r.goLookupIPCNAMEOrder(ctx, host, order) 563 return 564 } 565 566 func (r *Resolver) goLookupIPCNAMEOrder(ctx context.Context, 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 var queryFn func(fqdn string, qtype dnsmessage.Type) 589 var responseFn func(fqdn string, qtype dnsmessage.Type) result 590 if conf.singleRequest { 591 queryFn = func(fqdn string, qtype dnsmessage.Type) {} 592 responseFn = func(fqdn string, qtype dnsmessage.Type) result { 593 dnsWaitGroup.Add(1) 594 defer dnsWaitGroup.Done() 595 p, server, err := r.tryOneName(ctx, conf, fqdn, qtype) 596 return result{p, server, err} 597 } 598 } else { 599 queryFn = func(fqdn string, qtype dnsmessage.Type) { 600 dnsWaitGroup.Add(1) 601 go func(qtype dnsmessage.Type) { 602 p, server, err := r.tryOneName(ctx, conf, fqdn, qtype) 603 lane <- result{p, server, err} 604 dnsWaitGroup.Done() 605 }(qtype) 606 } 607 responseFn = func(fqdn string, qtype dnsmessage.Type) result { 608 return <-lane 609 } 610 } 611 var lastErr error 612 for _, fqdn := range conf.nameList(name) { 613 for _, qtype := range qtypes { 614 queryFn(fqdn, qtype) 615 } 616 hitStrictError := false 617 for _, qtype := range qtypes { 618 result := responseFn(fqdn, qtype) 619 if result.error != nil { 620 if nerr, ok := result.error.(Error); ok && nerr.Temporary() && r.strictErrors() { 621 // This error will abort the nameList loop. 622 hitStrictError = true 623 lastErr = result.error 624 } else if lastErr == nil || fqdn == name+"." { 625 // Prefer error for original name. 626 lastErr = result.error 627 } 628 continue 629 } 630 631 // Presotto says it's okay to assume that servers listed in 632 // /etc/resolv.conf are recursive resolvers. 633 // 634 // We asked for recursion, so it should have included all the 635 // answers we need in this one packet. 636 // 637 // Further, RFC 1035 section 4.3.1 says that "the recursive 638 // response to a query will be... The answer to the query, 639 // possibly preface by one or more CNAME RRs that specify 640 // aliases encountered on the way to an answer." 641 // 642 // Therefore, we should be able to assume that we can ignore 643 // CNAMEs and that the A and AAAA records we requested are 644 // for the canonical name. 645 646 loop: 647 for { 648 h, err := result.p.AnswerHeader() 649 if err != nil && err != dnsmessage.ErrSectionDone { 650 lastErr = &DNSError{ 651 Err: "cannot marshal DNS message", 652 Name: name, 653 Server: result.server, 654 } 655 } 656 if err != nil { 657 break 658 } 659 switch h.Type { 660 case dnsmessage.TypeA: 661 a, err := result.p.AResource() 662 if err != nil { 663 lastErr = &DNSError{ 664 Err: "cannot marshal DNS message", 665 Name: name, 666 Server: result.server, 667 } 668 break loop 669 } 670 addrs = append(addrs, IPAddr{IP: IP(a.A[:])}) 671 672 case dnsmessage.TypeAAAA: 673 aaaa, err := result.p.AAAAResource() 674 if err != nil { 675 lastErr = &DNSError{ 676 Err: "cannot marshal DNS message", 677 Name: name, 678 Server: result.server, 679 } 680 break loop 681 } 682 addrs = append(addrs, IPAddr{IP: IP(aaaa.AAAA[:])}) 683 684 default: 685 if err := result.p.SkipAnswer(); err != nil { 686 lastErr = &DNSError{ 687 Err: "cannot marshal DNS message", 688 Name: name, 689 Server: result.server, 690 } 691 break loop 692 } 693 continue 694 } 695 if cname.Length == 0 && h.Name.Length != 0 { 696 cname = h.Name 697 } 698 } 699 } 700 if hitStrictError { 701 // If either family hit an error with StrictErrors enabled, 702 // discard all addresses. This ensures that network flakiness 703 // cannot turn a dualstack hostname IPv4/IPv6-only. 704 addrs = nil 705 break 706 } 707 if len(addrs) > 0 { 708 break 709 } 710 } 711 if lastErr, ok := lastErr.(*DNSError); ok { 712 // Show original name passed to lookup, not suffixed one. 713 // In general we might have tried many suffixes; showing 714 // just one is misleading. See also golang.org/issue/6324. 715 lastErr.Name = name 716 } 717 sortByRFC6724(addrs) 718 if len(addrs) == 0 { 719 if order == hostLookupDNSFiles { 720 addrs = goLookupIPFiles(name) 721 } 722 if len(addrs) == 0 && lastErr != nil { 723 return nil, dnsmessage.Name{}, lastErr 724 } 725 } 726 return addrs, cname, nil 727 } 728 729 // goLookupCNAME is the native Go (non-cgo) implementation of LookupCNAME. 730 func (r *Resolver) goLookupCNAME(ctx context.Context, host string) (string, error) { 731 order := systemConf().hostLookupOrder(r, host) 732 _, cname, err := r.goLookupIPCNAMEOrder(ctx, host, order) 733 return cname.String(), err 734 } 735 736 // goLookupPTR is the native Go implementation of LookupAddr. 737 // Used only if cgoLookupPTR refuses to handle the request (that is, 738 // only if cgoLookupPTR is the stub in cgo_stub.go). 739 // Normally we let cgo use the C library resolver instead of depending 740 // on our lookup code, so that Go and C get the same answers. 741 func (r *Resolver) goLookupPTR(ctx context.Context, addr string) ([]string, error) { 742 names := lookupStaticAddr(addr) 743 if len(names) > 0 { 744 return names, nil 745 } 746 arpa, err := reverseaddr(addr) 747 if err != nil { 748 return nil, err 749 } 750 p, server, err := r.lookup(ctx, arpa, dnsmessage.TypePTR) 751 if err != nil { 752 return nil, err 753 } 754 var ptrs []string 755 for { 756 h, err := p.AnswerHeader() 757 if err == dnsmessage.ErrSectionDone { 758 break 759 } 760 if err != nil { 761 return nil, &DNSError{ 762 Err: "cannot marshal DNS message", 763 Name: addr, 764 Server: server, 765 } 766 } 767 if h.Type != dnsmessage.TypePTR { 768 err := p.SkipAnswer() 769 if err != nil { 770 return nil, &DNSError{ 771 Err: "cannot marshal DNS message", 772 Name: addr, 773 Server: server, 774 } 775 } 776 continue 777 } 778 ptr, err := p.PTRResource() 779 if err != nil { 780 return nil, &DNSError{ 781 Err: "cannot marshal DNS message", 782 Name: addr, 783 Server: server, 784 } 785 } 786 ptrs = append(ptrs, ptr.PTR.String()) 787 788 } 789 return ptrs, nil 790 }