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 = &temporaryError{"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 if err := p.SkipAdditional(); err != nil {
281 return hdr.RCode, hasAdd
282 }
283 }
284 }
285
286
287
288 func (r *Resolver) tryOneName(ctx context.Context, cfg *dnsConfig, name string, qtype dnsmessage.Type) (dnsmessage.Parser, string, error) {
289 var lastErr error
290 serverOffset := cfg.serverOffset()
291 sLen := uint32(len(cfg.servers))
292
293 n, err := dnsmessage.NewName(name)
294 if err != nil {
295 return dnsmessage.Parser{}, "", &DNSError{Err: errCannotMarshalDNSMessage.Error(), Name: name}
296 }
297 q := dnsmessage.Question{
298 Name: n,
299 Type: qtype,
300 Class: dnsmessage.ClassINET,
301 }
302
303 for i := 0; i < cfg.attempts; i++ {
304 for j := uint32(0); j < sLen; j++ {
305 server := cfg.servers[(serverOffset+j)%sLen]
306
307 p, h, err := r.exchange(ctx, server, q, cfg.timeout, cfg.useTCP, cfg.trustAD)
308 if err != nil {
309 dnsErr := newDNSError(err, name, server)
310
311
312 if _, ok := err.(*OpError); ok {
313 dnsErr.IsTemporary = true
314 }
315 lastErr = dnsErr
316 continue
317 }
318
319 if err := checkHeader(&p, h); err != nil {
320 if err == errNoSuchHost {
321
322
323 return p, server, newDNSError(errNoSuchHost, name, server)
324 }
325 lastErr = newDNSError(err, name, server)
326 continue
327 }
328
329 if err := skipToAnswer(&p, qtype); err != nil {
330 if err == errNoSuchHost {
331
332
333 return p, server, newDNSError(errNoSuchHost, name, server)
334 }
335 lastErr = newDNSError(err, name, server)
336 continue
337 }
338
339 return p, server, nil
340 }
341 }
342 return dnsmessage.Parser{}, "", lastErr
343 }
344
345
346 type resolverConfig struct {
347 initOnce sync.Once
348
349
350
351 ch chan struct{}
352 lastChecked time.Time
353
354 dnsConfig atomic.Pointer[dnsConfig]
355 }
356
357 var resolvConf resolverConfig
358
359 func getSystemDNSConfig() *dnsConfig {
360 resolvConf.tryUpdate("/etc/resolv.conf")
361 return resolvConf.dnsConfig.Load()
362 }
363
364
365 func (conf *resolverConfig) init() {
366
367
368 conf.dnsConfig.Store(dnsReadConfig("/etc/resolv.conf"))
369 conf.lastChecked = time.Now()
370
371
372
373 conf.ch = make(chan struct{}, 1)
374 }
375
376
377
378
379 func (conf *resolverConfig) tryUpdate(name string) {
380 conf.initOnce.Do(conf.init)
381
382 if conf.dnsConfig.Load().noReload {
383 return
384 }
385
386
387 if !conf.tryAcquireSema() {
388 return
389 }
390 defer conf.releaseSema()
391
392 now := time.Now()
393 if conf.lastChecked.After(now.Add(-5 * time.Second)) {
394 return
395 }
396 conf.lastChecked = now
397
398 switch runtime.GOOS {
399 case "windows":
400
401
402
403
404
405 default:
406 var mtime time.Time
407 if fi, err := os.Stat(name); err == nil {
408 mtime = fi.ModTime()
409 }
410 if mtime.Equal(conf.dnsConfig.Load().mtime) {
411 return
412 }
413 }
414
415 dnsConf := dnsReadConfig(name)
416 conf.dnsConfig.Store(dnsConf)
417 }
418
419 func (conf *resolverConfig) tryAcquireSema() bool {
420 select {
421 case conf.ch <- struct{}{}:
422 return true
423 default:
424 return false
425 }
426 }
427
428 func (conf *resolverConfig) releaseSema() {
429 <-conf.ch
430 }
431
432 func (r *Resolver) lookup(ctx context.Context, name string, qtype dnsmessage.Type, conf *dnsConfig) (dnsmessage.Parser, string, error) {
433 if !isDomainName(name) {
434
435
436
437
438
439 return dnsmessage.Parser{}, "", newDNSError(errNoSuchHost, name, "")
440 }
441
442 if conf == nil {
443 conf = getSystemDNSConfig()
444 }
445
446 var (
447 p dnsmessage.Parser
448 server string
449 err error
450 )
451 for _, fqdn := range conf.nameList(name) {
452 p, server, err = r.tryOneName(ctx, conf, fqdn, qtype)
453 if err == nil {
454 break
455 }
456 if nerr, ok := err.(Error); ok && nerr.Temporary() && r.strictErrors() {
457
458
459 break
460 }
461 }
462 if err == nil {
463 return p, server, nil
464 }
465 if err, ok := err.(*DNSError); ok {
466
467
468
469 err.Name = name
470 }
471 return dnsmessage.Parser{}, "", err
472 }
473
474
475
476
477
478 func avoidDNS(name string) bool {
479 if name == "" {
480 return true
481 }
482 if name[len(name)-1] == '.' {
483 name = name[:len(name)-1]
484 }
485 return stringsHasSuffixFold(name, ".onion")
486 }
487
488
489 func (conf *dnsConfig) nameList(name string) []string {
490
491 l := len(name)
492 rooted := l > 0 && name[l-1] == '.'
493 if l > 254 || l == 254 && !rooted {
494 return nil
495 }
496
497
498 if rooted {
499 if avoidDNS(name) {
500 return nil
501 }
502 return []string{name}
503 }
504
505 hasNdots := bytealg.CountString(name, '.') >= conf.ndots
506 name += "."
507 l++
508
509
510 names := make([]string, 0, 1+len(conf.search))
511
512 if hasNdots && !avoidDNS(name) {
513 names = append(names, name)
514 }
515
516 for _, suffix := range conf.search {
517 fqdn := name + suffix
518 if !avoidDNS(fqdn) && len(fqdn) <= 254 {
519 names = append(names, fqdn)
520 }
521 }
522
523 if !hasNdots && !avoidDNS(name) {
524 names = append(names, name)
525 }
526 return names
527 }
528
529
530
531
532 type hostLookupOrder int
533
534 const (
535
536 hostLookupCgo hostLookupOrder = iota
537 hostLookupFilesDNS
538 hostLookupDNSFiles
539 hostLookupFiles
540 hostLookupDNS
541 )
542
543 var lookupOrderName = map[hostLookupOrder]string{
544 hostLookupCgo: "cgo",
545 hostLookupFilesDNS: "files,dns",
546 hostLookupDNSFiles: "dns,files",
547 hostLookupFiles: "files",
548 hostLookupDNS: "dns",
549 }
550
551 func (o hostLookupOrder) String() string {
552 if s, ok := lookupOrderName[o]; ok {
553 return s
554 }
555 return "hostLookupOrder=" + itoa.Itoa(int(o)) + "??"
556 }
557
558 func (r *Resolver) goLookupHostOrder(ctx context.Context, name string, order hostLookupOrder, conf *dnsConfig) (addrs []string, err error) {
559 if order == hostLookupFilesDNS || order == hostLookupFiles {
560
561 addrs, _ = lookupStaticHost(name)
562 if len(addrs) > 0 {
563 return
564 }
565
566 if order == hostLookupFiles {
567 return nil, newDNSError(errNoSuchHost, name, "")
568 }
569 }
570 ips, _, err := r.goLookupIPCNAMEOrder(ctx, "ip", name, order, conf)
571 if err != nil {
572 return
573 }
574 addrs = make([]string, 0, len(ips))
575 for _, ip := range ips {
576 addrs = append(addrs, ip.String())
577 }
578 return
579 }
580
581
582 func goLookupIPFiles(name string) (addrs []IPAddr, canonical string) {
583 addr, canonical := lookupStaticHost(name)
584 for _, haddr := range addr {
585 haddr, zone := splitHostZone(haddr)
586 if ip := ParseIP(haddr); ip != nil {
587 addr := IPAddr{IP: ip, Zone: zone}
588 addrs = append(addrs, addr)
589 }
590 }
591 sortByRFC6724(addrs)
592 return addrs, canonical
593 }
594
595
596
597 func (r *Resolver) goLookupIP(ctx context.Context, network, host string, order hostLookupOrder, conf *dnsConfig) (addrs []IPAddr, err error) {
598 addrs, _, err = r.goLookupIPCNAMEOrder(ctx, network, host, order, conf)
599 return
600 }
601
602 func (r *Resolver) goLookupIPCNAMEOrder(ctx context.Context, network, name string, order hostLookupOrder, conf *dnsConfig) (addrs []IPAddr, cname dnsmessage.Name, err error) {
603 if order == hostLookupFilesDNS || order == hostLookupFiles {
604 var canonical string
605 addrs, canonical = goLookupIPFiles(name)
606
607 if len(addrs) > 0 {
608 var err error
609 cname, err = dnsmessage.NewName(canonical)
610 if err != nil {
611 return nil, dnsmessage.Name{}, err
612 }
613 return addrs, cname, nil
614 }
615
616 if order == hostLookupFiles {
617 return nil, dnsmessage.Name{}, newDNSError(errNoSuchHost, name, "")
618 }
619 }
620
621 if !isDomainName(name) {
622
623 return nil, dnsmessage.Name{}, newDNSError(errNoSuchHost, name, "")
624 }
625 type result struct {
626 p dnsmessage.Parser
627 server string
628 error
629 }
630
631 if conf == nil {
632 conf = getSystemDNSConfig()
633 }
634
635 lane := make(chan result, 1)
636 qtypes := []dnsmessage.Type{dnsmessage.TypeA, dnsmessage.TypeAAAA}
637 if network == "CNAME" {
638 qtypes = append(qtypes, dnsmessage.TypeCNAME)
639 }
640 switch ipVersion(network) {
641 case '4':
642 qtypes = []dnsmessage.Type{dnsmessage.TypeA}
643 case '6':
644 qtypes = []dnsmessage.Type{dnsmessage.TypeAAAA}
645 }
646 var queryFn func(fqdn string, qtype dnsmessage.Type)
647 var responseFn func(fqdn string, qtype dnsmessage.Type) result
648 if conf.singleRequest {
649 queryFn = func(fqdn string, qtype dnsmessage.Type) {}
650 responseFn = func(fqdn string, qtype dnsmessage.Type) result {
651 dnsWaitGroup.Add(1)
652 defer dnsWaitGroup.Done()
653 p, server, err := r.tryOneName(ctx, conf, fqdn, qtype)
654 return result{p, server, err}
655 }
656 } else {
657 queryFn = func(fqdn string, qtype dnsmessage.Type) {
658 dnsWaitGroup.Add(1)
659 go func(qtype dnsmessage.Type) {
660 p, server, err := r.tryOneName(ctx, conf, fqdn, qtype)
661 lane <- result{p, server, err}
662 dnsWaitGroup.Done()
663 }(qtype)
664 }
665 responseFn = func(fqdn string, qtype dnsmessage.Type) result {
666 return <-lane
667 }
668 }
669 var lastErr error
670 for _, fqdn := range conf.nameList(name) {
671 for _, qtype := range qtypes {
672 queryFn(fqdn, qtype)
673 }
674 hitStrictError := false
675 for _, qtype := range qtypes {
676 result := responseFn(fqdn, qtype)
677 if result.error != nil {
678 if nerr, ok := result.error.(Error); ok && nerr.Temporary() && r.strictErrors() {
679
680 hitStrictError = true
681 lastErr = result.error
682 } else if lastErr == nil || fqdn == name+"." {
683
684 lastErr = result.error
685 }
686 continue
687 }
688
689
690
691
692
693
694
695
696
697
698
699
700
701
702
703
704 loop:
705 for {
706 h, err := result.p.AnswerHeader()
707 if err != nil && err != dnsmessage.ErrSectionDone {
708 lastErr = &DNSError{
709 Err: errCannotUnmarshalDNSMessage.Error(),
710 Name: name,
711 Server: result.server,
712 }
713 }
714 if err != nil {
715 break
716 }
717 switch h.Type {
718 case dnsmessage.TypeA:
719 a, err := result.p.AResource()
720 if err != nil {
721 lastErr = &DNSError{
722 Err: errCannotUnmarshalDNSMessage.Error(),
723 Name: name,
724 Server: result.server,
725 }
726 break loop
727 }
728 addrs = append(addrs, IPAddr{IP: IP(a.A[:])})
729 if cname.Length == 0 && h.Name.Length != 0 {
730 cname = h.Name
731 }
732
733 case dnsmessage.TypeAAAA:
734 aaaa, err := result.p.AAAAResource()
735 if err != nil {
736 lastErr = &DNSError{
737 Err: errCannotUnmarshalDNSMessage.Error(),
738 Name: name,
739 Server: result.server,
740 }
741 break loop
742 }
743 addrs = append(addrs, IPAddr{IP: IP(aaaa.AAAA[:])})
744 if cname.Length == 0 && h.Name.Length != 0 {
745 cname = h.Name
746 }
747
748 case dnsmessage.TypeCNAME:
749 c, err := result.p.CNAMEResource()
750 if err != nil {
751 lastErr = &DNSError{
752 Err: errCannotUnmarshalDNSMessage.Error(),
753 Name: name,
754 Server: result.server,
755 }
756 break loop
757 }
758 if cname.Length == 0 && c.CNAME.Length > 0 {
759 cname = c.CNAME
760 }
761
762 default:
763 if err := result.p.SkipAnswer(); err != nil {
764 lastErr = &DNSError{
765 Err: errCannotUnmarshalDNSMessage.Error(),
766 Name: name,
767 Server: result.server,
768 }
769 break loop
770 }
771 continue
772 }
773 }
774 }
775 if hitStrictError {
776
777
778
779 addrs = nil
780 break
781 }
782 if len(addrs) > 0 || network == "CNAME" && cname.Length > 0 {
783 break
784 }
785 }
786 if lastErr, ok := lastErr.(*DNSError); ok {
787
788
789
790 lastErr.Name = name
791 }
792 sortByRFC6724(addrs)
793 if len(addrs) == 0 && !(network == "CNAME" && cname.Length > 0) {
794 if order == hostLookupDNSFiles {
795 var canonical string
796 addrs, canonical = goLookupIPFiles(name)
797 if len(addrs) > 0 {
798 var err error
799 cname, err = dnsmessage.NewName(canonical)
800 if err != nil {
801 return nil, dnsmessage.Name{}, err
802 }
803 return addrs, cname, nil
804 }
805 }
806 if lastErr != nil {
807 return nil, dnsmessage.Name{}, lastErr
808 }
809 }
810 return addrs, cname, nil
811 }
812
813
814 func (r *Resolver) goLookupCNAME(ctx context.Context, host string, order hostLookupOrder, conf *dnsConfig) (string, error) {
815 _, cname, err := r.goLookupIPCNAMEOrder(ctx, "CNAME", host, order, conf)
816 return cname.String(), err
817 }
818
819
820 func (r *Resolver) goLookupPTR(ctx context.Context, addr string, order hostLookupOrder, conf *dnsConfig) ([]string, error) {
821 if order == hostLookupFiles || order == hostLookupFilesDNS {
822 names := lookupStaticAddr(addr)
823 if len(names) > 0 {
824 return names, nil
825 }
826
827 if order == hostLookupFiles {
828 return nil, newDNSError(errNoSuchHost, addr, "")
829 }
830 }
831
832 arpa, err := reverseaddr(addr)
833 if err != nil {
834 return nil, err
835 }
836 p, server, err := r.lookup(ctx, arpa, dnsmessage.TypePTR, conf)
837 if err != nil {
838 var dnsErr *DNSError
839 if errors.As(err, &dnsErr) && dnsErr.IsNotFound {
840 if order == hostLookupDNSFiles {
841 names := lookupStaticAddr(addr)
842 if len(names) > 0 {
843 return names, nil
844 }
845 }
846 }
847 return nil, err
848 }
849 var ptrs []string
850 for {
851 h, err := p.AnswerHeader()
852 if err == dnsmessage.ErrSectionDone {
853 break
854 }
855 if err != nil {
856 return nil, &DNSError{
857 Err: errCannotUnmarshalDNSMessage.Error(),
858 Name: addr,
859 Server: server,
860 }
861 }
862 if h.Type != dnsmessage.TypePTR {
863 err := p.SkipAnswer()
864 if err != nil {
865 return nil, &DNSError{
866 Err: errCannotUnmarshalDNSMessage.Error(),
867 Name: addr,
868 Server: server,
869 }
870 }
871 continue
872 }
873 ptr, err := p.PTRResource()
874 if err != nil {
875 return nil, &DNSError{
876 Err: errCannotUnmarshalDNSMessage.Error(),
877 Name: addr,
878 Server: server,
879 }
880 }
881 ptrs = append(ptrs, ptr.PTR.String())
882
883 }
884
885 return ptrs, nil
886 }
887
View as plain text