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