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