]> Cypherpunks.ru repositories - gostls13.git/blob - src/net/dnsclient_unix.go
cmd/compile/internal/inline: score call sites exposed by inlines
[gostls13.git] / src / net / dnsclient_unix.go
1 // Copyright 2009 The Go Authors. All rights reserved.
2 // Use of this source code is governed by a BSD-style
3 // license that can be found in the LICENSE file.
4
5 // DNS client: see RFC 1035.
6 // Has to be linked into package net for Dial.
7
8 // TODO(rsc):
9 //      Could potentially handle many outstanding lookups faster.
10 //      Random UDP source port (net.Dial should do that for us).
11 //      Random request IDs.
12
13 package net
14
15 import (
16         "context"
17         "errors"
18         "internal/bytealg"
19         "internal/itoa"
20         "io"
21         "os"
22         "runtime"
23         "sync"
24         "sync/atomic"
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         rcode := extractExtendedRCode(*p, h)
208
209         if rcode == dnsmessage.RCodeNameError {
210                 return errNoSuchHost
211         }
212
213         _, err := p.AnswerHeader()
214         if err != nil && err != dnsmessage.ErrSectionDone {
215                 return errCannotUnmarshalDNSMessage
216         }
217
218         // libresolv continues to the next server when it receives
219         // an invalid referral response. See golang.org/issue/15434.
220         if rcode == dnsmessage.RCodeSuccess && !h.Authoritative && !h.RecursionAvailable && err == dnsmessage.ErrSectionDone {
221                 return errLameReferral
222         }
223
224         if rcode != dnsmessage.RCodeSuccess && rcode != dnsmessage.RCodeNameError {
225                 // None of the error codes make sense
226                 // for the query we sent. If we didn't get
227                 // a name error and we didn't get success,
228                 // the server is behaving incorrectly or
229                 // having temporary trouble.
230                 if rcode == dnsmessage.RCodeServerFailure {
231                         return errServerTemporarilyMisbehaving
232                 }
233                 return errServerMisbehaving
234         }
235
236         return nil
237 }
238
239 func skipToAnswer(p *dnsmessage.Parser, qtype dnsmessage.Type) error {
240         for {
241                 h, err := p.AnswerHeader()
242                 if err == dnsmessage.ErrSectionDone {
243                         return errNoSuchHost
244                 }
245                 if err != nil {
246                         return errCannotUnmarshalDNSMessage
247                 }
248                 if h.Type == qtype {
249                         return nil
250                 }
251                 if err := p.SkipAnswer(); err != nil {
252                         return errCannotUnmarshalDNSMessage
253                 }
254         }
255 }
256
257 // extractExtendedRCode extracts the extended RCode from the OPT resource (EDNS(0))
258 // If an OPT record is not found, the RCode from the hdr is returned.
259 func extractExtendedRCode(p dnsmessage.Parser, hdr dnsmessage.Header) dnsmessage.RCode {
260         p.SkipAllAnswers()
261         p.SkipAllAuthorities()
262         for {
263                 ahdr, err := p.AdditionalHeader()
264                 if err != nil {
265                         return hdr.RCode
266                 }
267                 if ahdr.Type == dnsmessage.TypeOPT {
268                         return ahdr.ExtendedRCode(hdr.RCode)
269                 }
270                 p.SkipAdditional()
271         }
272 }
273
274 // Do a lookup for a single name, which must be rooted
275 // (otherwise answer will not find the answers).
276 func (r *Resolver) tryOneName(ctx context.Context, cfg *dnsConfig, name string, qtype dnsmessage.Type) (dnsmessage.Parser, string, error) {
277         var lastErr error
278         serverOffset := cfg.serverOffset()
279         sLen := uint32(len(cfg.servers))
280
281         n, err := dnsmessage.NewName(name)
282         if err != nil {
283                 return dnsmessage.Parser{}, "", errCannotMarshalDNSMessage
284         }
285         q := dnsmessage.Question{
286                 Name:  n,
287                 Type:  qtype,
288                 Class: dnsmessage.ClassINET,
289         }
290
291         for i := 0; i < cfg.attempts; i++ {
292                 for j := uint32(0); j < sLen; j++ {
293                         server := cfg.servers[(serverOffset+j)%sLen]
294
295                         p, h, err := r.exchange(ctx, server, q, cfg.timeout, cfg.useTCP, cfg.trustAD)
296                         if err != nil {
297                                 dnsErr := &DNSError{
298                                         Err:    err.Error(),
299                                         Name:   name,
300                                         Server: server,
301                                 }
302                                 if nerr, ok := err.(Error); ok && nerr.Timeout() {
303                                         dnsErr.IsTimeout = true
304                                 }
305                                 // Set IsTemporary for socket-level errors. Note that this flag
306                                 // may also be used to indicate a SERVFAIL response.
307                                 if _, ok := err.(*OpError); ok {
308                                         dnsErr.IsTemporary = true
309                                 }
310                                 lastErr = dnsErr
311                                 continue
312                         }
313
314                         if err := checkHeader(&p, h); err != nil {
315                                 dnsErr := &DNSError{
316                                         Err:    err.Error(),
317                                         Name:   name,
318                                         Server: server,
319                                 }
320                                 if err == errServerTemporarilyMisbehaving {
321                                         dnsErr.IsTemporary = true
322                                 }
323                                 if err == errNoSuchHost {
324                                         // The name does not exist, so trying
325                                         // another server won't help.
326
327                                         dnsErr.IsNotFound = true
328                                         return p, server, dnsErr
329                                 }
330                                 lastErr = dnsErr
331                                 continue
332                         }
333
334                         err = skipToAnswer(&p, qtype)
335                         if err == nil {
336                                 return p, server, nil
337                         }
338                         lastErr = &DNSError{
339                                 Err:    err.Error(),
340                                 Name:   name,
341                                 Server: server,
342                         }
343                         if err == errNoSuchHost {
344                                 // The name does not exist, so trying another
345                                 // server won't help.
346
347                                 lastErr.(*DNSError).IsNotFound = true
348                                 return p, server, lastErr
349                         }
350                 }
351         }
352         return dnsmessage.Parser{}, "", lastErr
353 }
354
355 // A resolverConfig represents a DNS stub resolver configuration.
356 type resolverConfig struct {
357         initOnce sync.Once // guards init of resolverConfig
358
359         // ch is used as a semaphore that only allows one lookup at a
360         // time to recheck resolv.conf.
361         ch          chan struct{} // guards lastChecked and modTime
362         lastChecked time.Time     // last time resolv.conf was checked
363
364         dnsConfig atomic.Pointer[dnsConfig] // parsed resolv.conf structure used in lookups
365 }
366
367 var resolvConf resolverConfig
368
369 func getSystemDNSConfig() *dnsConfig {
370         resolvConf.tryUpdate("/etc/resolv.conf")
371         return resolvConf.dnsConfig.Load()
372 }
373
374 // init initializes conf and is only called via conf.initOnce.
375 func (conf *resolverConfig) init() {
376         // Set dnsConfig and lastChecked so we don't parse
377         // resolv.conf twice the first time.
378         conf.dnsConfig.Store(dnsReadConfig("/etc/resolv.conf"))
379         conf.lastChecked = time.Now()
380
381         // Prepare ch so that only one update of resolverConfig may
382         // run at once.
383         conf.ch = make(chan struct{}, 1)
384 }
385
386 // tryUpdate tries to update conf with the named resolv.conf file.
387 // The name variable only exists for testing. It is otherwise always
388 // "/etc/resolv.conf".
389 func (conf *resolverConfig) tryUpdate(name string) {
390         conf.initOnce.Do(conf.init)
391
392         if conf.dnsConfig.Load().noReload {
393                 return
394         }
395
396         // Ensure only one update at a time checks resolv.conf.
397         if !conf.tryAcquireSema() {
398                 return
399         }
400         defer conf.releaseSema()
401
402         now := time.Now()
403         if conf.lastChecked.After(now.Add(-5 * time.Second)) {
404                 return
405         }
406         conf.lastChecked = now
407
408         switch runtime.GOOS {
409         case "windows":
410                 // There's no file on disk, so don't bother checking
411                 // and failing.
412                 //
413                 // The Windows implementation of dnsReadConfig (called
414                 // below) ignores the name.
415         default:
416                 var mtime time.Time
417                 if fi, err := os.Stat(name); err == nil {
418                         mtime = fi.ModTime()
419                 }
420                 if mtime.Equal(conf.dnsConfig.Load().mtime) {
421                         return
422                 }
423         }
424
425         dnsConf := dnsReadConfig(name)
426         conf.dnsConfig.Store(dnsConf)
427 }
428
429 func (conf *resolverConfig) tryAcquireSema() bool {
430         select {
431         case conf.ch <- struct{}{}:
432                 return true
433         default:
434                 return false
435         }
436 }
437
438 func (conf *resolverConfig) releaseSema() {
439         <-conf.ch
440 }
441
442 func (r *Resolver) lookup(ctx context.Context, name string, qtype dnsmessage.Type, conf *dnsConfig) (dnsmessage.Parser, string, error) {
443         if !isDomainName(name) {
444                 // We used to use "invalid domain name" as the error,
445                 // but that is a detail of the specific lookup mechanism.
446                 // Other lookups might allow broader name syntax
447                 // (for example Multicast DNS allows UTF-8; see RFC 6762).
448                 // For consistency with libc resolvers, report no such host.
449                 return dnsmessage.Parser{}, "", &DNSError{Err: errNoSuchHost.Error(), Name: name, IsNotFound: true}
450         }
451
452         if conf == nil {
453                 conf = getSystemDNSConfig()
454         }
455
456         var (
457                 p      dnsmessage.Parser
458                 server string
459                 err    error
460         )
461         for _, fqdn := range conf.nameList(name) {
462                 p, server, err = r.tryOneName(ctx, conf, fqdn, qtype)
463                 if err == nil {
464                         break
465                 }
466                 if nerr, ok := err.(Error); ok && nerr.Temporary() && r.strictErrors() {
467                         // If we hit a temporary error with StrictErrors enabled,
468                         // stop immediately instead of trying more names.
469                         break
470                 }
471         }
472         if err == nil {
473                 return p, server, nil
474         }
475         if err, ok := err.(*DNSError); ok {
476                 // Show original name passed to lookup, not suffixed one.
477                 // In general we might have tried many suffixes; showing
478                 // just one is misleading. See also golang.org/issue/6324.
479                 err.Name = name
480         }
481         return dnsmessage.Parser{}, "", err
482 }
483
484 // avoidDNS reports whether this is a hostname for which we should not
485 // use DNS. Currently this includes only .onion, per RFC 7686. See
486 // golang.org/issue/13705. Does not cover .local names (RFC 6762),
487 // see golang.org/issue/16739.
488 func avoidDNS(name string) bool {
489         if name == "" {
490                 return true
491         }
492         if name[len(name)-1] == '.' {
493                 name = name[:len(name)-1]
494         }
495         return stringsHasSuffixFold(name, ".onion")
496 }
497
498 // nameList returns a list of names for sequential DNS queries.
499 func (conf *dnsConfig) nameList(name string) []string {
500         // Check name length (see isDomainName).
501         l := len(name)
502         rooted := l > 0 && name[l-1] == '.'
503         if l > 254 || l == 254 && !rooted {
504                 return nil
505         }
506
507         // If name is rooted (trailing dot), try only that name.
508         if rooted {
509                 if avoidDNS(name) {
510                         return nil
511                 }
512                 return []string{name}
513         }
514
515         hasNdots := bytealg.CountString(name, '.') >= conf.ndots
516         name += "."
517         l++
518
519         // Build list of search choices.
520         names := make([]string, 0, 1+len(conf.search))
521         // If name has enough dots, try unsuffixed first.
522         if hasNdots && !avoidDNS(name) {
523                 names = append(names, name)
524         }
525         // Try suffixes that are not too long (see isDomainName).
526         for _, suffix := range conf.search {
527                 fqdn := name + suffix
528                 if !avoidDNS(fqdn) && len(fqdn) <= 254 {
529                         names = append(names, fqdn)
530                 }
531         }
532         // Try unsuffixed, if not tried first above.
533         if !hasNdots && !avoidDNS(name) {
534                 names = append(names, name)
535         }
536         return names
537 }
538
539 // hostLookupOrder specifies the order of LookupHost lookup strategies.
540 // It is basically a simplified representation of nsswitch.conf.
541 // "files" means /etc/hosts.
542 type hostLookupOrder int
543
544 const (
545         // hostLookupCgo means defer to cgo.
546         hostLookupCgo      hostLookupOrder = iota
547         hostLookupFilesDNS                 // files first
548         hostLookupDNSFiles                 // dns first
549         hostLookupFiles                    // only files
550         hostLookupDNS                      // only DNS
551 )
552
553 var lookupOrderName = map[hostLookupOrder]string{
554         hostLookupCgo:      "cgo",
555         hostLookupFilesDNS: "files,dns",
556         hostLookupDNSFiles: "dns,files",
557         hostLookupFiles:    "files",
558         hostLookupDNS:      "dns",
559 }
560
561 func (o hostLookupOrder) String() string {
562         if s, ok := lookupOrderName[o]; ok {
563                 return s
564         }
565         return "hostLookupOrder=" + itoa.Itoa(int(o)) + "??"
566 }
567
568 func (r *Resolver) goLookupHostOrder(ctx context.Context, name string, order hostLookupOrder, conf *dnsConfig) (addrs []string, err error) {
569         if order == hostLookupFilesDNS || order == hostLookupFiles {
570                 // Use entries from /etc/hosts if they match.
571                 addrs, _ = lookupStaticHost(name)
572                 if len(addrs) > 0 {
573                         return
574                 }
575
576                 if order == hostLookupFiles {
577                         return nil, &DNSError{Err: errNoSuchHost.Error(), Name: name, IsNotFound: true}
578                 }
579         }
580         ips, _, err := r.goLookupIPCNAMEOrder(ctx, "ip", name, order, conf)
581         if err != nil {
582                 return
583         }
584         addrs = make([]string, 0, len(ips))
585         for _, ip := range ips {
586                 addrs = append(addrs, ip.String())
587         }
588         return
589 }
590
591 // lookup entries from /etc/hosts
592 func goLookupIPFiles(name string) (addrs []IPAddr, canonical string) {
593         addr, canonical := lookupStaticHost(name)
594         for _, haddr := range addr {
595                 haddr, zone := splitHostZone(haddr)
596                 if ip := ParseIP(haddr); ip != nil {
597                         addr := IPAddr{IP: ip, Zone: zone}
598                         addrs = append(addrs, addr)
599                 }
600         }
601         sortByRFC6724(addrs)
602         return addrs, canonical
603 }
604
605 // goLookupIP is the native Go implementation of LookupIP.
606 // The libc versions are in cgo_*.go.
607 func (r *Resolver) goLookupIP(ctx context.Context, network, host string, order hostLookupOrder, conf *dnsConfig) (addrs []IPAddr, err error) {
608         addrs, _, err = r.goLookupIPCNAMEOrder(ctx, network, host, order, conf)
609         return
610 }
611
612 func (r *Resolver) goLookupIPCNAMEOrder(ctx context.Context, network, name string, order hostLookupOrder, conf *dnsConfig) (addrs []IPAddr, cname dnsmessage.Name, err error) {
613         if order == hostLookupFilesDNS || order == hostLookupFiles {
614                 var canonical string
615                 addrs, canonical = goLookupIPFiles(name)
616
617                 if len(addrs) > 0 {
618                         var err error
619                         cname, err = dnsmessage.NewName(canonical)
620                         if err != nil {
621                                 return nil, dnsmessage.Name{}, err
622                         }
623                         return addrs, cname, nil
624                 }
625
626                 if order == hostLookupFiles {
627                         return nil, dnsmessage.Name{}, &DNSError{Err: errNoSuchHost.Error(), Name: name, IsNotFound: true}
628                 }
629         }
630
631         if !isDomainName(name) {
632                 // See comment in func lookup above about use of errNoSuchHost.
633                 return nil, dnsmessage.Name{}, &DNSError{Err: errNoSuchHost.Error(), Name: name, IsNotFound: true}
634         }
635         type result struct {
636                 p      dnsmessage.Parser
637                 server string
638                 error
639         }
640
641         if conf == nil {
642                 conf = getSystemDNSConfig()
643         }
644
645         lane := make(chan result, 1)
646         qtypes := []dnsmessage.Type{dnsmessage.TypeA, dnsmessage.TypeAAAA}
647         if network == "CNAME" {
648                 qtypes = append(qtypes, dnsmessage.TypeCNAME)
649         }
650         switch ipVersion(network) {
651         case '4':
652                 qtypes = []dnsmessage.Type{dnsmessage.TypeA}
653         case '6':
654                 qtypes = []dnsmessage.Type{dnsmessage.TypeAAAA}
655         }
656         var queryFn func(fqdn string, qtype dnsmessage.Type)
657         var responseFn func(fqdn string, qtype dnsmessage.Type) result
658         if conf.singleRequest {
659                 queryFn = func(fqdn string, qtype dnsmessage.Type) {}
660                 responseFn = func(fqdn string, qtype dnsmessage.Type) result {
661                         dnsWaitGroup.Add(1)
662                         defer dnsWaitGroup.Done()
663                         p, server, err := r.tryOneName(ctx, conf, fqdn, qtype)
664                         return result{p, server, err}
665                 }
666         } else {
667                 queryFn = func(fqdn string, qtype dnsmessage.Type) {
668                         dnsWaitGroup.Add(1)
669                         go func(qtype dnsmessage.Type) {
670                                 p, server, err := r.tryOneName(ctx, conf, fqdn, qtype)
671                                 lane <- result{p, server, err}
672                                 dnsWaitGroup.Done()
673                         }(qtype)
674                 }
675                 responseFn = func(fqdn string, qtype dnsmessage.Type) result {
676                         return <-lane
677                 }
678         }
679         var lastErr error
680         for _, fqdn := range conf.nameList(name) {
681                 for _, qtype := range qtypes {
682                         queryFn(fqdn, qtype)
683                 }
684                 hitStrictError := false
685                 for _, qtype := range qtypes {
686                         result := responseFn(fqdn, qtype)
687                         if result.error != nil {
688                                 if nerr, ok := result.error.(Error); ok && nerr.Temporary() && r.strictErrors() {
689                                         // This error will abort the nameList loop.
690                                         hitStrictError = true
691                                         lastErr = result.error
692                                 } else if lastErr == nil || fqdn == name+"." {
693                                         // Prefer error for original name.
694                                         lastErr = result.error
695                                 }
696                                 continue
697                         }
698
699                         // Presotto says it's okay to assume that servers listed in
700                         // /etc/resolv.conf are recursive resolvers.
701                         //
702                         // We asked for recursion, so it should have included all the
703                         // answers we need in this one packet.
704                         //
705                         // Further, RFC 1034 section 4.3.1 says that "the recursive
706                         // response to a query will be... The answer to the query,
707                         // possibly preface by one or more CNAME RRs that specify
708                         // aliases encountered on the way to an answer."
709                         //
710                         // Therefore, we should be able to assume that we can ignore
711                         // CNAMEs and that the A and AAAA records we requested are
712                         // for the canonical name.
713
714                 loop:
715                         for {
716                                 h, err := result.p.AnswerHeader()
717                                 if err != nil && err != dnsmessage.ErrSectionDone {
718                                         lastErr = &DNSError{
719                                                 Err:    errCannotUnmarshalDNSMessage.Error(),
720                                                 Name:   name,
721                                                 Server: result.server,
722                                         }
723                                 }
724                                 if err != nil {
725                                         break
726                                 }
727                                 switch h.Type {
728                                 case dnsmessage.TypeA:
729                                         a, err := result.p.AResource()
730                                         if err != nil {
731                                                 lastErr = &DNSError{
732                                                         Err:    errCannotUnmarshalDNSMessage.Error(),
733                                                         Name:   name,
734                                                         Server: result.server,
735                                                 }
736                                                 break loop
737                                         }
738                                         addrs = append(addrs, IPAddr{IP: IP(a.A[:])})
739                                         if cname.Length == 0 && h.Name.Length != 0 {
740                                                 cname = h.Name
741                                         }
742
743                                 case dnsmessage.TypeAAAA:
744                                         aaaa, err := result.p.AAAAResource()
745                                         if err != nil {
746                                                 lastErr = &DNSError{
747                                                         Err:    errCannotUnmarshalDNSMessage.Error(),
748                                                         Name:   name,
749                                                         Server: result.server,
750                                                 }
751                                                 break loop
752                                         }
753                                         addrs = append(addrs, IPAddr{IP: IP(aaaa.AAAA[:])})
754                                         if cname.Length == 0 && h.Name.Length != 0 {
755                                                 cname = h.Name
756                                         }
757
758                                 case dnsmessage.TypeCNAME:
759                                         c, err := result.p.CNAMEResource()
760                                         if err != nil {
761                                                 lastErr = &DNSError{
762                                                         Err:    errCannotUnmarshalDNSMessage.Error(),
763                                                         Name:   name,
764                                                         Server: result.server,
765                                                 }
766                                                 break loop
767                                         }
768                                         if cname.Length == 0 && c.CNAME.Length > 0 {
769                                                 cname = c.CNAME
770                                         }
771
772                                 default:
773                                         if err := result.p.SkipAnswer(); err != nil {
774                                                 lastErr = &DNSError{
775                                                         Err:    errCannotUnmarshalDNSMessage.Error(),
776                                                         Name:   name,
777                                                         Server: result.server,
778                                                 }
779                                                 break loop
780                                         }
781                                         continue
782                                 }
783                         }
784                 }
785                 if hitStrictError {
786                         // If either family hit an error with StrictErrors enabled,
787                         // discard all addresses. This ensures that network flakiness
788                         // cannot turn a dualstack hostname IPv4/IPv6-only.
789                         addrs = nil
790                         break
791                 }
792                 if len(addrs) > 0 || network == "CNAME" && cname.Length > 0 {
793                         break
794                 }
795         }
796         if lastErr, ok := lastErr.(*DNSError); ok {
797                 // Show original name passed to lookup, not suffixed one.
798                 // In general we might have tried many suffixes; showing
799                 // just one is misleading. See also golang.org/issue/6324.
800                 lastErr.Name = name
801         }
802         sortByRFC6724(addrs)
803         if len(addrs) == 0 && !(network == "CNAME" && cname.Length > 0) {
804                 if order == hostLookupDNSFiles {
805                         var canonical string
806                         addrs, canonical = goLookupIPFiles(name)
807                         if len(addrs) > 0 {
808                                 var err error
809                                 cname, err = dnsmessage.NewName(canonical)
810                                 if err != nil {
811                                         return nil, dnsmessage.Name{}, err
812                                 }
813                                 return addrs, cname, nil
814                         }
815                 }
816                 if lastErr != nil {
817                         return nil, dnsmessage.Name{}, lastErr
818                 }
819         }
820         return addrs, cname, nil
821 }
822
823 // goLookupCNAME is the native Go (non-cgo) implementation of LookupCNAME.
824 func (r *Resolver) goLookupCNAME(ctx context.Context, host string, order hostLookupOrder, conf *dnsConfig) (string, error) {
825         _, cname, err := r.goLookupIPCNAMEOrder(ctx, "CNAME", host, order, conf)
826         return cname.String(), err
827 }
828
829 // goLookupPTR is the native Go implementation of LookupAddr.
830 func (r *Resolver) goLookupPTR(ctx context.Context, addr string, order hostLookupOrder, conf *dnsConfig) ([]string, error) {
831         if order == hostLookupFiles || order == hostLookupFilesDNS {
832                 names := lookupStaticAddr(addr)
833                 if len(names) > 0 {
834                         return names, nil
835                 }
836
837                 if order == hostLookupFiles {
838                         return nil, &DNSError{Err: errNoSuchHost.Error(), Name: addr, IsNotFound: true}
839                 }
840         }
841
842         arpa, err := reverseaddr(addr)
843         if err != nil {
844                 return nil, err
845         }
846         p, server, err := r.lookup(ctx, arpa, dnsmessage.TypePTR, conf)
847         if err != nil {
848                 var dnsErr *DNSError
849                 if errors.As(err, &dnsErr) && dnsErr.IsNotFound {
850                         if order == hostLookupDNSFiles {
851                                 names := lookupStaticAddr(addr)
852                                 if len(names) > 0 {
853                                         return names, nil
854                                 }
855                         }
856                 }
857                 return nil, err
858         }
859         var ptrs []string
860         for {
861                 h, err := p.AnswerHeader()
862                 if err == dnsmessage.ErrSectionDone {
863                         break
864                 }
865                 if err != nil {
866                         return nil, &DNSError{
867                                 Err:    errCannotUnmarshalDNSMessage.Error(),
868                                 Name:   addr,
869                                 Server: server,
870                         }
871                 }
872                 if h.Type != dnsmessage.TypePTR {
873                         err := p.SkipAnswer()
874                         if err != nil {
875                                 return nil, &DNSError{
876                                         Err:    errCannotUnmarshalDNSMessage.Error(),
877                                         Name:   addr,
878                                         Server: server,
879                                 }
880                         }
881                         continue
882                 }
883                 ptr, err := p.PTRResource()
884                 if err != nil {
885                         return nil, &DNSError{
886                                 Err:    errCannotUnmarshalDNSMessage.Error(),
887                                 Name:   addr,
888                                 Server: server,
889                         }
890                 }
891                 ptrs = append(ptrs, ptr.PTR.String())
892
893         }
894
895         return ptrs, nil
896 }