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