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