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