Source file
src/net/dnsclient_unix.go
Documentation: net
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/itoa"
21 "io"
22 "os"
23 "runtime"
24 "sync"
25 "sync/atomic"
26 "time"
27
28 "golang.org/x/net/dns/dnsmessage"
29 )
30
31 const (
32
33 useTCPOnly = true
34 useUDPOrTCP = false
35
36
37
38 maxDNSPacketSize = 1232
39 )
40
41 var (
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
50
51
52 errServerTemporarilyMisbehaving = errors.New("server misbehaving")
53 )
54
55
56 var netedns0 = godebug.New("netedns0")
57
58 func 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
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
95 func 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
108 func 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
121
122
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
135 func 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)
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
168 func (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 if h.Truncated {
206 continue
207 }
208 return p, h, nil
209 }
210 return dnsmessage.Parser{}, dnsmessage.Header{}, errNoAnswerFromDNSServer
211 }
212
213
214 func checkHeader(p *dnsmessage.Parser, h dnsmessage.Header) error {
215 rcode := extractExtendedRCode(*p, h)
216
217 if rcode == dnsmessage.RCodeNameError {
218 return errNoSuchHost
219 }
220
221 _, err := p.AnswerHeader()
222 if err != nil && err != dnsmessage.ErrSectionDone {
223 return errCannotUnmarshalDNSMessage
224 }
225
226
227
228 if rcode == dnsmessage.RCodeSuccess && !h.Authoritative && !h.RecursionAvailable && err == dnsmessage.ErrSectionDone {
229 return errLameReferral
230 }
231
232 if rcode != dnsmessage.RCodeSuccess && rcode != dnsmessage.RCodeNameError {
233
234
235
236
237
238 if rcode == dnsmessage.RCodeServerFailure {
239 return errServerTemporarilyMisbehaving
240 }
241 return errServerMisbehaving
242 }
243
244 return nil
245 }
246
247 func skipToAnswer(p *dnsmessage.Parser, qtype dnsmessage.Type) error {
248 for {
249 h, err := p.AnswerHeader()
250 if err == dnsmessage.ErrSectionDone {
251 return errNoSuchHost
252 }
253 if err != nil {
254 return errCannotUnmarshalDNSMessage
255 }
256 if h.Type == qtype {
257 return nil
258 }
259 if err := p.SkipAnswer(); err != nil {
260 return errCannotUnmarshalDNSMessage
261 }
262 }
263 }
264
265
266
267 func extractExtendedRCode(p dnsmessage.Parser, hdr dnsmessage.Header) dnsmessage.RCode {
268 p.SkipAllAnswers()
269 p.SkipAllAuthorities()
270 for {
271 ahdr, err := p.AdditionalHeader()
272 if err != nil {
273 return hdr.RCode
274 }
275 if ahdr.Type == dnsmessage.TypeOPT {
276 return ahdr.ExtendedRCode(hdr.RCode)
277 }
278 if err := p.SkipAdditional(); err != nil {
279 return hdr.RCode
280 }
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