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