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