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