Source file
src/net/dnsclient_unix.go
1
2
3
4
5
6
7
8
9
10
11
12
13 package net
14
15 import (
16 "context"
17 "errors"
18 "internal/bytealg"
19 "internal/godebug"
20 "internal/strconv"
21 "internal/stringslite"
22 "io"
23 "os"
24 "runtime"
25 "sync"
26 "sync/atomic"
27 "time"
28
29 "golang.org/x/net/dns/dnsmessage"
30 )
31
32 const (
33
34 useTCPOnly = true
35 useUDPOrTCP = false
36
37
38
39 maxDNSPacketSize = 1232
40 )
41
42 var (
43 errLameReferral = errors.New("lame referral")
44 errCannotUnmarshalDNSMessage = errors.New("cannot unmarshal DNS message")
45 errCannotMarshalDNSMessage = errors.New("cannot marshal DNS message")
46 errServerMisbehaving = errors.New("server misbehaving")
47 errInvalidDNSResponse = errors.New("invalid DNS response")
48 errNoAnswerFromDNSServer = errors.New("no answer from DNS server")
49
50
51
52
53 errServerTemporarilyMisbehaving = &temporaryError{"server misbehaving"}
54 )
55
56
57 var netedns0 = godebug.New("netedns0")
58
59 func newRequest(q dnsmessage.Question, ad bool) (id uint16, udpReq, tcpReq []byte, err error) {
60 id = uint16(randInt())
61 b := dnsmessage.NewBuilder(make([]byte, 2, 514), dnsmessage.Header{ID: id, RecursionDesired: true, AuthenticData: ad})
62 if err := b.StartQuestions(); err != nil {
63 return 0, nil, nil, err
64 }
65 if err := b.Question(q); err != nil {
66 return 0, nil, nil, err
67 }
68
69 if netedns0.Value() == "0" {
70 netedns0.IncNonDefault()
71 } else {
72
73 if err := b.StartAdditionals(); err != nil {
74 return 0, nil, nil, err
75 }
76 var rh dnsmessage.ResourceHeader
77 if err := rh.SetEDNS0(maxDNSPacketSize, dnsmessage.RCodeSuccess, false); err != nil {
78 return 0, nil, nil, err
79 }
80 if err := b.OPTResource(rh, dnsmessage.OPTResource{}); err != nil {
81 return 0, nil, nil, err
82 }
83 }
84
85 tcpReq, err = b.Finish()
86 if err != nil {
87 return 0, nil, nil, err
88 }
89 udpReq = tcpReq[2:]
90 l := len(tcpReq) - 2
91 tcpReq[0] = byte(l >> 8)
92 tcpReq[1] = byte(l)
93 return id, udpReq, tcpReq, nil
94 }
95
96 func checkResponse(reqID uint16, reqQues dnsmessage.Question, respHdr dnsmessage.Header, respQues dnsmessage.Question) bool {
97 if !respHdr.Response {
98 return false
99 }
100 if reqID != respHdr.ID {
101 return false
102 }
103 if reqQues.Type != respQues.Type || reqQues.Class != respQues.Class || !equalASCIIName(reqQues.Name, respQues.Name) {
104 return false
105 }
106 return true
107 }
108
109 func dnsPacketRoundTrip(c Conn, id uint16, query dnsmessage.Question, b []byte) (dnsmessage.Parser, dnsmessage.Header, error) {
110 if _, err := c.Write(b); err != nil {
111 return dnsmessage.Parser{}, dnsmessage.Header{}, err
112 }
113
114 b = make([]byte, maxDNSPacketSize)
115 for {
116 n, err := c.Read(b)
117 if err != nil {
118 return dnsmessage.Parser{}, dnsmessage.Header{}, err
119 }
120 var p dnsmessage.Parser
121
122
123
124 h, err := p.Start(b[:n])
125 if err != nil {
126 continue
127 }
128 q, err := p.Question()
129 if err != nil || !checkResponse(id, query, h, q) {
130 continue
131 }
132 return p, h, nil
133 }
134 }
135
136 func dnsStreamRoundTrip(c Conn, id uint16, query dnsmessage.Question, b []byte) (dnsmessage.Parser, dnsmessage.Header, error) {
137 if _, err := c.Write(b); err != nil {
138 return dnsmessage.Parser{}, dnsmessage.Header{}, err
139 }
140
141 b = make([]byte, 1280)
142 if _, err := io.ReadFull(c, b[:2]); err != nil {
143 return dnsmessage.Parser{}, dnsmessage.Header{}, err
144 }
145 l := int(b[0])<<8 | int(b[1])
146 if l > len(b) {
147 b = make([]byte, l)
148 }
149 n, err := io.ReadFull(c, b[:l])
150 if err != nil {
151 return dnsmessage.Parser{}, dnsmessage.Header{}, err
152 }
153 var p dnsmessage.Parser
154 h, err := p.Start(b[:n])
155 if err != nil {
156 return dnsmessage.Parser{}, dnsmessage.Header{}, errCannotUnmarshalDNSMessage
157 }
158 q, err := p.Question()
159 if err != nil {
160 return dnsmessage.Parser{}, dnsmessage.Header{}, errCannotUnmarshalDNSMessage
161 }
162 if !checkResponse(id, query, h, q) {
163 return dnsmessage.Parser{}, dnsmessage.Header{}, errInvalidDNSResponse
164 }
165 return p, h, nil
166 }
167
168
169 func (r *Resolver) exchange(ctx context.Context, server string, q dnsmessage.Question, timeout time.Duration, useTCP, ad bool) (dnsmessage.Parser, dnsmessage.Header, error) {
170 q.Class = dnsmessage.ClassINET
171 id, udpReq, tcpReq, err := newRequest(q, ad)
172 if err != nil {
173 return dnsmessage.Parser{}, dnsmessage.Header{}, errCannotMarshalDNSMessage
174 }
175 var networks []string
176 if useTCP {
177 networks = []string{"tcp"}
178 } else {
179 networks = []string{"udp", "tcp"}
180 }
181 for _, network := range networks {
182 ctx, cancel := context.WithDeadline(ctx, time.Now().Add(timeout))
183 defer cancel()
184
185 c, err := r.dial(ctx, network, server)
186 if err != nil {
187 return dnsmessage.Parser{}, dnsmessage.Header{}, err
188 }
189 if d, ok := ctx.Deadline(); ok && !d.IsZero() {
190 c.SetDeadline(d)
191 }
192 var p dnsmessage.Parser
193 var h dnsmessage.Header
194 if _, ok := c.(PacketConn); ok {
195 p, h, err = dnsPacketRoundTrip(c, id, q, udpReq)
196 } else {
197 p, h, err = dnsStreamRoundTrip(c, id, q, tcpReq)
198 }
199 c.Close()
200 if err != nil {
201 return dnsmessage.Parser{}, dnsmessage.Header{}, mapErr(err)
202 }
203 if err := p.SkipQuestion(); err != dnsmessage.ErrSectionDone {
204 return dnsmessage.Parser{}, dnsmessage.Header{}, errInvalidDNSResponse
205 }
206
207
208
209
210
211
212
213 if h.Truncated && network == "udp" {
214 continue
215 }
216 return p, h, nil
217 }
218 return dnsmessage.Parser{}, dnsmessage.Header{}, errNoAnswerFromDNSServer
219 }
220
221
222 func checkHeader(p *dnsmessage.Parser, h dnsmessage.Header) error {
223 rcode, hasAdd := extractExtendedRCode(*p, h)
224
225 if rcode == dnsmessage.RCodeNameError {
226 return errNoSuchHost
227 }
228
229 _, err := p.AnswerHeader()
230 if err != nil && err != dnsmessage.ErrSectionDone {
231 return errCannotUnmarshalDNSMessage
232 }
233
234
235
236 if rcode == dnsmessage.RCodeSuccess && !h.Authoritative && !h.RecursionAvailable && err == dnsmessage.ErrSectionDone && !hasAdd {
237 return errLameReferral
238 }
239
240 if rcode != dnsmessage.RCodeSuccess && rcode != dnsmessage.RCodeNameError {
241
242
243
244
245
246 if rcode == dnsmessage.RCodeServerFailure {
247 return errServerTemporarilyMisbehaving
248 }
249 return errServerMisbehaving
250 }
251
252 return nil
253 }
254
255 func skipToAnswer(p *dnsmessage.Parser, qtype dnsmessage.Type) error {
256 for {
257 h, err := p.AnswerHeader()
258 if err == dnsmessage.ErrSectionDone {
259 return errNoSuchHost
260 }
261 if err != nil {
262 return errCannotUnmarshalDNSMessage
263 }
264 if h.Type == qtype {
265 return nil
266 }
267 if err := p.SkipAnswer(); err != nil {
268 return errCannotUnmarshalDNSMessage
269 }
270 }
271 }
272
273
274
275
276 func extractExtendedRCode(p dnsmessage.Parser, hdr dnsmessage.Header) (dnsmessage.RCode, bool) {
277 p.SkipAllAnswers()
278 p.SkipAllAuthorities()
279 hasAdd := false
280 for {
281 ahdr, err := p.AdditionalHeader()
282 if err != nil {
283 return hdr.RCode, hasAdd
284 }
285 hasAdd = true
286 if ahdr.Type == dnsmessage.TypeOPT {
287 return ahdr.ExtendedRCode(hdr.RCode), hasAdd
288 }
289 if err := p.SkipAdditional(); err != nil {
290 return hdr.RCode, hasAdd
291 }
292 }
293 }
294
295
296
297 func (r *Resolver) tryOneName(ctx context.Context, cfg *dnsConfig, name string, qtype dnsmessage.Type) (dnsmessage.Parser, string, error) {
298 var lastErr error
299 serverOffset := cfg.serverOffset()
300 sLen := uint32(len(cfg.servers))
301
302 n, err := dnsmessage.NewName(name)
303 if err != nil {
304 return dnsmessage.Parser{}, "", &DNSError{Err: errCannotMarshalDNSMessage.Error(), Name: name}
305 }
306 q := dnsmessage.Question{
307 Name: n,
308 Type: qtype,
309 Class: dnsmessage.ClassINET,
310 }
311
312 for i := 0; i < cfg.attempts; i++ {
313 for j := uint32(0); j < sLen; j++ {
314 server := cfg.servers[(serverOffset+j)%sLen]
315
316 p, h, err := r.exchange(ctx, server, q, cfg.timeout, cfg.useTCP, cfg.trustAD)
317 if err != nil {
318 dnsErr := newDNSError(err, name, server)
319
320
321 if _, ok := err.(*OpError); ok {
322 dnsErr.IsTemporary = true
323 }
324 lastErr = dnsErr
325 continue
326 }
327
328 if err := checkHeader(&p, h); err != nil {
329 if err == errNoSuchHost {
330
331
332 return p, server, newDNSError(errNoSuchHost, name, server)
333 }
334 lastErr = newDNSError(err, name, server)
335 continue
336 }
337
338 if err := skipToAnswer(&p, qtype); err != nil {
339 if err == errNoSuchHost {
340
341
342 return p, server, newDNSError(errNoSuchHost, name, server)
343 }
344 lastErr = newDNSError(err, name, server)
345 continue
346 }
347
348 return p, server, nil
349 }
350 }
351 return dnsmessage.Parser{}, "", lastErr
352 }
353
354
355 type resolverConfig struct {
356 initOnce sync.Once
357
358
359
360 ch chan struct{}
361 lastChecked time.Time
362
363 dnsConfig atomic.Pointer[dnsConfig]
364 }
365
366 var resolvConf resolverConfig
367
368 func getSystemDNSConfig() *dnsConfig {
369 return getSystemDNSConfigNamed("/etc/resolv.conf")
370 }
371
372 func getSystemDNSConfigNamed(path string) *dnsConfig {
373 resolvConf.tryUpdate(path)
374 return resolvConf.dnsConfig.Load()
375 }
376
377
378 func (conf *resolverConfig) init() {
379
380
381 conf.dnsConfig.Store(dnsReadConfig("/etc/resolv.conf"))
382 conf.lastChecked = time.Now()
383
384
385
386 conf.ch = make(chan struct{}, 1)
387 }
388
389
390
391 var distantFuture = time.Date(3000, 1, 2, 3, 4, 5, 6, time.UTC)
392
393
394
395
396 func (conf *resolverConfig) tryUpdate(name string) {
397 conf.initOnce.Do(conf.init)
398
399 dc := conf.dnsConfig.Load()
400
401
402
403
404
405
406 if len(dc.servers) == 0 {
407 panic("unreachable")
408 }
409
410 if dc.noReload {
411 return
412 }
413
414
415 if !conf.tryAcquireSema() {
416 return
417 }
418 defer conf.releaseSema()
419
420 now := time.Now()
421
422
423
424
425
426
427
428
429
430 expired := now.After(conf.lastChecked.Add(5 * time.Second))
431 rechecksEnabled := conf.lastChecked != distantFuture
432 recheck := (expired || dc.isDefaultNS()) && rechecksEnabled
433 if !recheck {
434 return
435 }
436 conf.lastChecked = now
437
438 switch runtime.GOOS {
439 case "windows":
440
441
442
443
444
445 default:
446 var mtime time.Time
447 if fi, err := os.Stat(name); err == nil {
448 mtime = fi.ModTime()
449 }
450 if mtime.Equal(conf.dnsConfig.Load().mtime) {
451 return
452 }
453 }
454
455 dnsConf := dnsReadConfig(name)
456 conf.dnsConfig.Store(dnsConf)
457 }
458
459 func (conf *resolverConfig) tryAcquireSema() bool {
460 select {
461 case conf.ch <- struct{}{}:
462 return true
463 default:
464 return false
465 }
466 }
467
468 func (conf *resolverConfig) releaseSema() {
469 <-conf.ch
470 }
471
472 func (r *Resolver) lookup(ctx context.Context, name string, qtype dnsmessage.Type, conf *dnsConfig) (dnsmessage.Parser, string, error) {
473 if !isDomainName(name) {
474
475
476
477
478
479 return dnsmessage.Parser{}, "", newDNSError(errNoSuchHost, name, "")
480 }
481
482 if isLocalhostName(name) {
483
484
485
486
487 return dnsmessage.Parser{}, "", newDNSError(errNoSuchHost, name, "")
488 }
489
490 if conf == nil {
491 conf = getSystemDNSConfig()
492 }
493
494 var (
495 p dnsmessage.Parser
496 server string
497 err error
498 )
499 for _, fqdn := range conf.nameList(name) {
500 p, server, err = r.tryOneName(ctx, conf, fqdn, qtype)
501 if err == nil {
502 break
503 }
504 if nerr, ok := err.(Error); ok && nerr.Temporary() && r.strictErrors() {
505
506
507 break
508 }
509 }
510 if err == nil {
511 return p, server, nil
512 }
513 if err, ok := err.(*DNSError); ok {
514
515
516
517 err.Name = name
518 }
519 return dnsmessage.Parser{}, "", err
520 }
521
522
523
524
525
526 func avoidDNS(name string) bool {
527 if name == "" {
528 return true
529 }
530 name = stringslite.TrimSuffix(name, ".")
531 return stringsHasSuffixFold(name, ".onion")
532 }
533
534
535
536
537 func isLocalhostName(name string) bool {
538 name = stringslite.TrimSuffix(name, ".")
539 return stringsEqualFold(name, "localhost") || stringsHasSuffixFold(name, ".localhost")
540 }
541
542
543 func (conf *dnsConfig) nameList(name string) []string {
544
545 rooted := len(name) > 0 && name[len(name)-1] == '.'
546 if len(name) > 254 || len(name) == 254 && !rooted {
547 return nil
548 }
549
550
551 if rooted {
552 if avoidDNS(name) {
553 return nil
554 }
555 return []string{name}
556 }
557
558 hasNdots := bytealg.CountString(name, '.') >= conf.ndots
559 name += "."
560
561
562 names := make([]string, 0, 1+len(conf.search))
563
564 if hasNdots && !avoidDNS(name) {
565 names = append(names, name)
566 }
567
568 for _, suffix := range conf.search {
569 fqdn := name + suffix
570 if !avoidDNS(fqdn) && len(fqdn) <= 254 {
571 names = append(names, fqdn)
572 }
573 }
574
575 if !hasNdots && !avoidDNS(name) {
576 names = append(names, name)
577 }
578 return names
579 }
580
581
582
583
584 type hostLookupOrder int
585
586 const (
587
588 hostLookupCgo hostLookupOrder = iota
589 hostLookupFilesDNS
590 hostLookupDNSFiles
591 hostLookupFiles
592 hostLookupDNS
593 )
594
595 var lookupOrderName = map[hostLookupOrder]string{
596 hostLookupCgo: "cgo",
597 hostLookupFilesDNS: "files,dns",
598 hostLookupDNSFiles: "dns,files",
599 hostLookupFiles: "files",
600 hostLookupDNS: "dns",
601 }
602
603 func (o hostLookupOrder) String() string {
604 if s, ok := lookupOrderName[o]; ok {
605 return s
606 }
607 return "hostLookupOrder=" + strconv.Itoa(int(o)) + "??"
608 }
609
610 func (r *Resolver) goLookupHostOrder(ctx context.Context, name string, order hostLookupOrder, conf *dnsConfig) (addrs []string, err error) {
611 if order == hostLookupFilesDNS || order == hostLookupFiles {
612
613 addrs, _ = lookupStaticHost(name)
614 if len(addrs) > 0 {
615 return
616 }
617
618
619
620
621 if order == hostLookupFiles && !isLocalhostName(name) {
622 return nil, newDNSError(errNoSuchHost, name, "")
623 }
624 }
625 ips, _, err := r.goLookupIPCNAMEOrder(ctx, "ip", name, order, conf)
626 if err != nil {
627 return
628 }
629 addrs = make([]string, 0, len(ips))
630 for _, ip := range ips {
631 addrs = append(addrs, ip.String())
632 }
633 return
634 }
635
636
637 func goLookupIPFiles(name string) (addrs []IPAddr, canonical string) {
638 addr, canonical := lookupStaticHost(name)
639 for _, haddr := range addr {
640 haddr, zone := splitHostZone(haddr)
641 if ip := ParseIP(haddr); ip != nil {
642 addr := IPAddr{IP: ip, Zone: zone}
643 addrs = append(addrs, addr)
644 }
645 }
646 sortByRFC6724(addrs)
647 return addrs, canonical
648 }
649
650
651
652 func (r *Resolver) goLookupIP(ctx context.Context, network, host string, order hostLookupOrder, conf *dnsConfig) (addrs []IPAddr, err error) {
653 addrs, _, err = r.goLookupIPCNAMEOrder(ctx, network, host, order, conf)
654 return
655 }
656
657 func (r *Resolver) goLookupIPCNAMEOrder(ctx context.Context, network, name string, order hostLookupOrder, conf *dnsConfig) (addrs []IPAddr, cname dnsmessage.Name, err error) {
658 if order == hostLookupFilesDNS || order == hostLookupFiles {
659 var canonical string
660 addrs, canonical = goLookupIPFiles(name)
661
662 if len(addrs) > 0 {
663 var err error
664 cname, err = dnsmessage.NewName(canonical)
665 if err != nil {
666 return nil, dnsmessage.Name{}, err
667 }
668 return addrs, cname, nil
669 }
670
671 if order == hostLookupFiles && !isLocalhostName(name) {
672 return nil, dnsmessage.Name{}, newDNSError(errNoSuchHost, name, "")
673 }
674 }
675
676 if !isDomainName(name) {
677
678 return nil, dnsmessage.Name{}, newDNSError(errNoSuchHost, name, "")
679 }
680
681 if isLocalhostName(name) {
682
683
684
685
686 var addrs []IPAddr
687 if ipVersion(network) != '4' {
688 addrs = append(addrs, IPAddr{IP: IPv6loopback})
689 }
690 if ipVersion(network) != '6' {
691 addrs = append(addrs, IPAddr{IP: IPv4(127, 0, 0, 1)})
692 }
693 sortByRFC6724(addrs)
694 cname, err := dnsmessage.NewName(absDomainName(name))
695 if err != nil {
696 return nil, dnsmessage.Name{}, err
697 }
698 return addrs, cname, nil
699 }
700 type result struct {
701 p dnsmessage.Parser
702 server string
703 error error
704 }
705
706 if conf == nil {
707 conf = getSystemDNSConfig()
708 }
709
710 lane := make(chan result, 1)
711 qtypes := []dnsmessage.Type{dnsmessage.TypeA, dnsmessage.TypeAAAA}
712 if network == "CNAME" {
713 qtypes = append(qtypes, dnsmessage.TypeCNAME)
714 }
715 switch ipVersion(network) {
716 case '4':
717 qtypes = []dnsmessage.Type{dnsmessage.TypeA}
718 case '6':
719 qtypes = []dnsmessage.Type{dnsmessage.TypeAAAA}
720 }
721 var queryFn func(fqdn string, qtype dnsmessage.Type)
722 var responseFn func(fqdn string, qtype dnsmessage.Type) result
723 if conf.singleRequest {
724 queryFn = func(fqdn string, qtype dnsmessage.Type) {}
725 responseFn = func(fqdn string, qtype dnsmessage.Type) result {
726 dnsWaitGroup.Add(1)
727 defer dnsWaitGroup.Done()
728 p, server, err := r.tryOneName(ctx, conf, fqdn, qtype)
729 return result{p, server, err}
730 }
731 } else {
732 queryFn = func(fqdn string, qtype dnsmessage.Type) {
733 dnsWaitGroup.Add(1)
734 go func(qtype dnsmessage.Type) {
735 p, server, err := r.tryOneName(ctx, conf, fqdn, qtype)
736 lane <- result{p, server, err}
737 dnsWaitGroup.Done()
738 }(qtype)
739 }
740 responseFn = func(fqdn string, qtype dnsmessage.Type) result {
741 return <-lane
742 }
743 }
744 var lastErr error
745 for _, fqdn := range conf.nameList(name) {
746 for _, qtype := range qtypes {
747 queryFn(fqdn, qtype)
748 }
749 hitStrictError := false
750 for _, qtype := range qtypes {
751 result := responseFn(fqdn, qtype)
752 if result.error != nil {
753 if nerr, ok := result.error.(Error); ok && nerr.Temporary() && r.strictErrors() {
754
755 hitStrictError = true
756 lastErr = result.error
757 } else if lastErr == nil || fqdn == name+"." {
758
759 lastErr = result.error
760 }
761 continue
762 }
763
764
765
766
767
768
769
770
771
772
773
774
775
776
777
778
779 loop:
780 for {
781 h, err := result.p.AnswerHeader()
782 if err != nil && err != dnsmessage.ErrSectionDone {
783 lastErr = &DNSError{
784 Err: errCannotUnmarshalDNSMessage.Error(),
785 Name: name,
786 Server: result.server,
787 }
788 }
789 if err != nil {
790 break
791 }
792 switch h.Type {
793 case dnsmessage.TypeA:
794 a, err := result.p.AResource()
795 if err != nil {
796 lastErr = &DNSError{
797 Err: errCannotUnmarshalDNSMessage.Error(),
798 Name: name,
799 Server: result.server,
800 }
801 break loop
802 }
803 addrs = append(addrs, IPAddr{IP: IP(a.A[:])})
804 if cname.Length == 0 && h.Name.Length != 0 {
805 cname = h.Name
806 }
807
808 case dnsmessage.TypeAAAA:
809 aaaa, err := result.p.AAAAResource()
810 if err != nil {
811 lastErr = &DNSError{
812 Err: errCannotUnmarshalDNSMessage.Error(),
813 Name: name,
814 Server: result.server,
815 }
816 break loop
817 }
818 addrs = append(addrs, IPAddr{IP: IP(aaaa.AAAA[:])})
819 if cname.Length == 0 && h.Name.Length != 0 {
820 cname = h.Name
821 }
822
823 case dnsmessage.TypeCNAME:
824 c, err := result.p.CNAMEResource()
825 if err != nil {
826 lastErr = &DNSError{
827 Err: errCannotUnmarshalDNSMessage.Error(),
828 Name: name,
829 Server: result.server,
830 }
831 break loop
832 }
833 if cname.Length == 0 && c.CNAME.Length > 0 {
834 cname = c.CNAME
835 }
836
837 default:
838 if err := result.p.SkipAnswer(); err != nil {
839 lastErr = &DNSError{
840 Err: errCannotUnmarshalDNSMessage.Error(),
841 Name: name,
842 Server: result.server,
843 }
844 break loop
845 }
846 continue
847 }
848 }
849 }
850 if hitStrictError {
851
852
853
854 addrs = nil
855 break
856 }
857 if len(addrs) > 0 || network == "CNAME" && cname.Length > 0 {
858 break
859 }
860 }
861 if lastErr, ok := lastErr.(*DNSError); ok {
862
863
864
865 lastErr.Name = name
866 }
867 sortByRFC6724(addrs)
868 if len(addrs) == 0 && !(network == "CNAME" && cname.Length > 0) {
869 if order == hostLookupDNSFiles {
870 var canonical string
871 addrs, canonical = goLookupIPFiles(name)
872 if len(addrs) > 0 {
873 var err error
874 cname, err = dnsmessage.NewName(canonical)
875 if err != nil {
876 return nil, dnsmessage.Name{}, err
877 }
878 return addrs, cname, nil
879 }
880 }
881 if lastErr != nil {
882 return nil, dnsmessage.Name{}, lastErr
883 }
884 }
885 return addrs, cname, nil
886 }
887
888
889 func (r *Resolver) goLookupCNAME(ctx context.Context, host string, order hostLookupOrder, conf *dnsConfig) (string, error) {
890 _, cname, err := r.goLookupIPCNAMEOrder(ctx, "CNAME", host, order, conf)
891 return cname.String(), err
892 }
893
894
895 func (r *Resolver) goLookupPTR(ctx context.Context, addr string, order hostLookupOrder, conf *dnsConfig) ([]string, error) {
896 if order == hostLookupFiles || order == hostLookupFilesDNS {
897 names := lookupStaticAddr(addr)
898 if len(names) > 0 {
899 return names, nil
900 }
901
902 if order == hostLookupFiles {
903 return nil, newDNSError(errNoSuchHost, addr, "")
904 }
905 }
906
907 arpa, err := reverseaddr(addr)
908 if err != nil {
909 return nil, err
910 }
911 p, server, err := r.lookup(ctx, arpa, dnsmessage.TypePTR, conf)
912 if err != nil {
913 if dnsErr, ok := errors.AsType[*DNSError](err); ok && dnsErr.IsNotFound {
914 if order == hostLookupDNSFiles {
915 names := lookupStaticAddr(addr)
916 if len(names) > 0 {
917 return names, nil
918 }
919 }
920 }
921 return nil, err
922 }
923 var ptrs []string
924 for {
925 h, err := p.AnswerHeader()
926 if err == dnsmessage.ErrSectionDone {
927 break
928 }
929 if err != nil {
930 return nil, &DNSError{
931 Err: errCannotUnmarshalDNSMessage.Error(),
932 Name: addr,
933 Server: server,
934 }
935 }
936 if h.Type != dnsmessage.TypePTR {
937 err := p.SkipAnswer()
938 if err != nil {
939 return nil, &DNSError{
940 Err: errCannotUnmarshalDNSMessage.Error(),
941 Name: addr,
942 Server: server,
943 }
944 }
945 continue
946 }
947 ptr, err := p.PTRResource()
948 if err != nil {
949 return nil, &DNSError{
950 Err: errCannotUnmarshalDNSMessage.Error(),
951 Name: addr,
952 Server: server,
953 }
954 }
955 ptrs = append(ptrs, ptr.PTR.String())
956
957 }
958
959 return ptrs, nil
960 }
961
View as plain text