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