Source file
src/net/dnsclient_unix.go
Documentation: net
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16 package net
17
18 import (
19 "context"
20 "errors"
21 "internal/itoa"
22 "io"
23 "os"
24 "sync"
25 "time"
26
27 "golang.org/x/net/dns/dnsmessage"
28 )
29
30 const (
31
32 useTCPOnly = true
33 useUDPOrTCP = false
34 )
35
36 var (
37 errLameReferral = errors.New("lame referral")
38 errCannotUnmarshalDNSMessage = errors.New("cannot unmarshal DNS message")
39 errCannotMarshalDNSMessage = errors.New("cannot marshal DNS message")
40 errServerMisbehaving = errors.New("server misbehaving")
41 errInvalidDNSResponse = errors.New("invalid DNS response")
42 errNoAnswerFromDNSServer = errors.New("no answer from DNS server")
43
44
45
46
47 errServerTemporarilyMisbehaving = errors.New("server misbehaving")
48 )
49
50 func newRequest(q dnsmessage.Question) (id uint16, udpReq, tcpReq []byte, err error) {
51 id = uint16(randInt())
52 b := dnsmessage.NewBuilder(make([]byte, 2, 514), dnsmessage.Header{ID: id, RecursionDesired: true})
53 b.EnableCompression()
54 if err := b.StartQuestions(); err != nil {
55 return 0, nil, nil, err
56 }
57 if err := b.Question(q); err != nil {
58 return 0, nil, nil, err
59 }
60 tcpReq, err = b.Finish()
61 udpReq = tcpReq[2:]
62 l := len(tcpReq) - 2
63 tcpReq[0] = byte(l >> 8)
64 tcpReq[1] = byte(l)
65 return id, udpReq, tcpReq, err
66 }
67
68 func checkResponse(reqID uint16, reqQues dnsmessage.Question, respHdr dnsmessage.Header, respQues dnsmessage.Question) bool {
69 if !respHdr.Response {
70 return false
71 }
72 if reqID != respHdr.ID {
73 return false
74 }
75 if reqQues.Type != respQues.Type || reqQues.Class != respQues.Class || !equalASCIIName(reqQues.Name, respQues.Name) {
76 return false
77 }
78 return true
79 }
80
81 func dnsPacketRoundTrip(c Conn, id uint16, query dnsmessage.Question, b []byte) (dnsmessage.Parser, dnsmessage.Header, error) {
82 if _, err := c.Write(b); err != nil {
83 return dnsmessage.Parser{}, dnsmessage.Header{}, err
84 }
85
86 b = make([]byte, 512)
87 for {
88 n, err := c.Read(b)
89 if err != nil {
90 return dnsmessage.Parser{}, dnsmessage.Header{}, err
91 }
92 var p dnsmessage.Parser
93
94
95
96 h, err := p.Start(b[:n])
97 if err != nil {
98 continue
99 }
100 q, err := p.Question()
101 if err != nil || !checkResponse(id, query, h, q) {
102 continue
103 }
104 return p, h, nil
105 }
106 }
107
108 func dnsStreamRoundTrip(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, 1280)
114 if _, err := io.ReadFull(c, b[:2]); err != nil {
115 return dnsmessage.Parser{}, dnsmessage.Header{}, err
116 }
117 l := int(b[0])<<8 | int(b[1])
118 if l > len(b) {
119 b = make([]byte, l)
120 }
121 n, err := io.ReadFull(c, b[:l])
122 if err != nil {
123 return dnsmessage.Parser{}, dnsmessage.Header{}, err
124 }
125 var p dnsmessage.Parser
126 h, err := p.Start(b[:n])
127 if err != nil {
128 return dnsmessage.Parser{}, dnsmessage.Header{}, errCannotUnmarshalDNSMessage
129 }
130 q, err := p.Question()
131 if err != nil {
132 return dnsmessage.Parser{}, dnsmessage.Header{}, errCannotUnmarshalDNSMessage
133 }
134 if !checkResponse(id, query, h, q) {
135 return dnsmessage.Parser{}, dnsmessage.Header{}, errInvalidDNSResponse
136 }
137 return p, h, nil
138 }
139
140
141 func (r *Resolver) exchange(ctx context.Context, server string, q dnsmessage.Question, timeout time.Duration, useTCP bool) (dnsmessage.Parser, dnsmessage.Header, error) {
142 q.Class = dnsmessage.ClassINET
143 id, udpReq, tcpReq, err := newRequest(q)
144 if err != nil {
145 return dnsmessage.Parser{}, dnsmessage.Header{}, errCannotMarshalDNSMessage
146 }
147 var networks []string
148 if useTCP {
149 networks = []string{"tcp"}
150 } else {
151 networks = []string{"udp", "tcp"}
152 }
153 for _, network := range networks {
154 ctx, cancel := context.WithDeadline(ctx, time.Now().Add(timeout))
155 defer cancel()
156
157 c, err := r.dial(ctx, network, server)
158 if err != nil {
159 return dnsmessage.Parser{}, dnsmessage.Header{}, err
160 }
161 if d, ok := ctx.Deadline(); ok && !d.IsZero() {
162 c.SetDeadline(d)
163 }
164 var p dnsmessage.Parser
165 var h dnsmessage.Header
166 if _, ok := c.(PacketConn); ok {
167 p, h, err = dnsPacketRoundTrip(c, id, q, udpReq)
168 } else {
169 p, h, err = dnsStreamRoundTrip(c, id, q, tcpReq)
170 }
171 c.Close()
172 if err != nil {
173 return dnsmessage.Parser{}, dnsmessage.Header{}, mapErr(err)
174 }
175 if err := p.SkipQuestion(); err != dnsmessage.ErrSectionDone {
176 return dnsmessage.Parser{}, dnsmessage.Header{}, errInvalidDNSResponse
177 }
178 if h.Truncated {
179 continue
180 }
181 return p, h, nil
182 }
183 return dnsmessage.Parser{}, dnsmessage.Header{}, errNoAnswerFromDNSServer
184 }
185
186
187 func checkHeader(p *dnsmessage.Parser, h dnsmessage.Header) error {
188 if h.RCode == dnsmessage.RCodeNameError {
189 return errNoSuchHost
190 }
191
192 _, err := p.AnswerHeader()
193 if err != nil && err != dnsmessage.ErrSectionDone {
194 return errCannotUnmarshalDNSMessage
195 }
196
197
198
199 if h.RCode == dnsmessage.RCodeSuccess && !h.Authoritative && !h.RecursionAvailable && err == dnsmessage.ErrSectionDone {
200 return errLameReferral
201 }
202
203 if h.RCode != dnsmessage.RCodeSuccess && h.RCode != dnsmessage.RCodeNameError {
204
205
206
207
208
209 if h.RCode == dnsmessage.RCodeServerFailure {
210 return errServerTemporarilyMisbehaving
211 }
212 return errServerMisbehaving
213 }
214
215 return nil
216 }
217
218 func skipToAnswer(p *dnsmessage.Parser, qtype dnsmessage.Type) error {
219 for {
220 h, err := p.AnswerHeader()
221 if err == dnsmessage.ErrSectionDone {
222 return errNoSuchHost
223 }
224 if err != nil {
225 return errCannotUnmarshalDNSMessage
226 }
227 if h.Type == qtype {
228 return nil
229 }
230 if err := p.SkipAnswer(); err != nil {
231 return errCannotUnmarshalDNSMessage
232 }
233 }
234 }
235
236
237
238 func (r *Resolver) tryOneName(ctx context.Context, cfg *dnsConfig, name string, qtype dnsmessage.Type) (dnsmessage.Parser, string, error) {
239 var lastErr error
240 serverOffset := cfg.serverOffset()
241 sLen := uint32(len(cfg.servers))
242
243 n, err := dnsmessage.NewName(name)
244 if err != nil {
245 return dnsmessage.Parser{}, "", errCannotMarshalDNSMessage
246 }
247 q := dnsmessage.Question{
248 Name: n,
249 Type: qtype,
250 Class: dnsmessage.ClassINET,
251 }
252
253 for i := 0; i < cfg.attempts; i++ {
254 for j := uint32(0); j < sLen; j++ {
255 server := cfg.servers[(serverOffset+j)%sLen]
256
257 p, h, err := r.exchange(ctx, server, q, cfg.timeout, cfg.useTCP)
258 if err != nil {
259 dnsErr := &DNSError{
260 Err: err.Error(),
261 Name: name,
262 Server: server,
263 }
264 if nerr, ok := err.(Error); ok && nerr.Timeout() {
265 dnsErr.IsTimeout = true
266 }
267
268
269 if _, ok := err.(*OpError); ok {
270 dnsErr.IsTemporary = true
271 }
272 lastErr = dnsErr
273 continue
274 }
275
276 if err := checkHeader(&p, h); err != nil {
277 dnsErr := &DNSError{
278 Err: err.Error(),
279 Name: name,
280 Server: server,
281 }
282 if err == errServerTemporarilyMisbehaving {
283 dnsErr.IsTemporary = true
284 }
285 if err == errNoSuchHost {
286
287
288
289 dnsErr.IsNotFound = true
290 return p, server, dnsErr
291 }
292 lastErr = dnsErr
293 continue
294 }
295
296 err = skipToAnswer(&p, qtype)
297 if err == nil {
298 return p, server, nil
299 }
300 lastErr = &DNSError{
301 Err: err.Error(),
302 Name: name,
303 Server: server,
304 }
305 if err == errNoSuchHost {
306
307
308
309 lastErr.(*DNSError).IsNotFound = true
310 return p, server, lastErr
311 }
312 }
313 }
314 return dnsmessage.Parser{}, "", lastErr
315 }
316
317
318 type resolverConfig struct {
319 initOnce sync.Once
320
321
322
323 ch chan struct{}
324 lastChecked time.Time
325
326 mu sync.RWMutex
327 dnsConfig *dnsConfig
328 }
329
330 var resolvConf resolverConfig
331
332
333 func (conf *resolverConfig) init() {
334
335
336 conf.dnsConfig = systemConf().resolv
337 if conf.dnsConfig == nil {
338 conf.dnsConfig = dnsReadConfig("/etc/resolv.conf")
339 }
340 conf.lastChecked = time.Now()
341
342
343
344 conf.ch = make(chan struct{}, 1)
345 }
346
347
348
349
350 func (conf *resolverConfig) tryUpdate(name string) {
351 conf.initOnce.Do(conf.init)
352
353
354 if !conf.tryAcquireSema() {
355 return
356 }
357 defer conf.releaseSema()
358
359 now := time.Now()
360 if conf.lastChecked.After(now.Add(-5 * time.Second)) {
361 return
362 }
363 conf.lastChecked = now
364
365 var mtime time.Time
366 if fi, err := os.Stat(name); err == nil {
367 mtime = fi.ModTime()
368 }
369 if mtime.Equal(conf.dnsConfig.mtime) {
370 return
371 }
372
373 dnsConf := dnsReadConfig(name)
374 conf.mu.Lock()
375 conf.dnsConfig = dnsConf
376 conf.mu.Unlock()
377 }
378
379 func (conf *resolverConfig) tryAcquireSema() bool {
380 select {
381 case conf.ch <- struct{}{}:
382 return true
383 default:
384 return false
385 }
386 }
387
388 func (conf *resolverConfig) releaseSema() {
389 <-conf.ch
390 }
391
392 func (r *Resolver) lookup(ctx context.Context, name string, qtype dnsmessage.Type) (dnsmessage.Parser, string, error) {
393 if !isDomainName(name) {
394
395
396
397
398
399 return dnsmessage.Parser{}, "", &DNSError{Err: errNoSuchHost.Error(), Name: name, IsNotFound: true}
400 }
401 resolvConf.tryUpdate("/etc/resolv.conf")
402 resolvConf.mu.RLock()
403 conf := resolvConf.dnsConfig
404 resolvConf.mu.RUnlock()
405 var (
406 p dnsmessage.Parser
407 server string
408 err error
409 )
410 for _, fqdn := range conf.nameList(name) {
411 p, server, err = r.tryOneName(ctx, conf, fqdn, qtype)
412 if err == nil {
413 break
414 }
415 if nerr, ok := err.(Error); ok && nerr.Temporary() && r.strictErrors() {
416
417
418 break
419 }
420 }
421 if err == nil {
422 return p, server, nil
423 }
424 if err, ok := err.(*DNSError); ok {
425
426
427
428 err.Name = name
429 }
430 return dnsmessage.Parser{}, "", err
431 }
432
433
434
435
436
437 func avoidDNS(name string) bool {
438 if name == "" {
439 return true
440 }
441 if name[len(name)-1] == '.' {
442 name = name[:len(name)-1]
443 }
444 return stringsHasSuffixFold(name, ".onion")
445 }
446
447
448 func (conf *dnsConfig) nameList(name string) []string {
449 if avoidDNS(name) {
450 return nil
451 }
452
453
454 l := len(name)
455 rooted := l > 0 && name[l-1] == '.'
456 if l > 254 || l == 254 && rooted {
457 return nil
458 }
459
460
461 if rooted {
462 return []string{name}
463 }
464
465 hasNdots := count(name, '.') >= conf.ndots
466 name += "."
467 l++
468
469
470 names := make([]string, 0, 1+len(conf.search))
471
472 if hasNdots {
473 names = append(names, name)
474 }
475
476 for _, suffix := range conf.search {
477 if l+len(suffix) <= 254 {
478 names = append(names, name+suffix)
479 }
480 }
481
482 if !hasNdots {
483 names = append(names, name)
484 }
485 return names
486 }
487
488
489
490
491 type hostLookupOrder int
492
493 const (
494
495 hostLookupCgo hostLookupOrder = iota
496 hostLookupFilesDNS
497 hostLookupDNSFiles
498 hostLookupFiles
499 hostLookupDNS
500 )
501
502 var lookupOrderName = map[hostLookupOrder]string{
503 hostLookupCgo: "cgo",
504 hostLookupFilesDNS: "files,dns",
505 hostLookupDNSFiles: "dns,files",
506 hostLookupFiles: "files",
507 hostLookupDNS: "dns",
508 }
509
510 func (o hostLookupOrder) String() string {
511 if s, ok := lookupOrderName[o]; ok {
512 return s
513 }
514 return "hostLookupOrder=" + itoa.Itoa(int(o)) + "??"
515 }
516
517
518
519
520
521
522
523 func (r *Resolver) goLookupHost(ctx context.Context, name string) (addrs []string, err error) {
524 return r.goLookupHostOrder(ctx, name, hostLookupFilesDNS)
525 }
526
527 func (r *Resolver) goLookupHostOrder(ctx context.Context, name string, order hostLookupOrder) (addrs []string, err error) {
528 if order == hostLookupFilesDNS || order == hostLookupFiles {
529
530 addrs = lookupStaticHost(name)
531 if len(addrs) > 0 || order == hostLookupFiles {
532 return
533 }
534 }
535 ips, _, err := r.goLookupIPCNAMEOrder(ctx, "ip", name, order)
536 if err != nil {
537 return
538 }
539 addrs = make([]string, 0, len(ips))
540 for _, ip := range ips {
541 addrs = append(addrs, ip.String())
542 }
543 return
544 }
545
546
547 func goLookupIPFiles(name string) (addrs []IPAddr) {
548 for _, haddr := range lookupStaticHost(name) {
549 haddr, zone := splitHostZone(haddr)
550 if ip := ParseIP(haddr); ip != nil {
551 addr := IPAddr{IP: ip, Zone: zone}
552 addrs = append(addrs, addr)
553 }
554 }
555 sortByRFC6724(addrs)
556 return
557 }
558
559
560
561 func (r *Resolver) goLookupIP(ctx context.Context, network, host string) (addrs []IPAddr, err error) {
562 order := systemConf().hostLookupOrder(r, host)
563 addrs, _, err = r.goLookupIPCNAMEOrder(ctx, network, host, order)
564 return
565 }
566
567 func (r *Resolver) goLookupIPCNAMEOrder(ctx context.Context, network, name string, order hostLookupOrder) (addrs []IPAddr, cname dnsmessage.Name, err error) {
568 if order == hostLookupFilesDNS || order == hostLookupFiles {
569 addrs = goLookupIPFiles(name)
570 if len(addrs) > 0 || order == hostLookupFiles {
571 return addrs, dnsmessage.Name{}, nil
572 }
573 }
574 if !isDomainName(name) {
575
576 return nil, dnsmessage.Name{}, &DNSError{Err: errNoSuchHost.Error(), Name: name, IsNotFound: true}
577 }
578 resolvConf.tryUpdate("/etc/resolv.conf")
579 resolvConf.mu.RLock()
580 conf := resolvConf.dnsConfig
581 resolvConf.mu.RUnlock()
582 type result struct {
583 p dnsmessage.Parser
584 server string
585 error
586 }
587 lane := make(chan result, 1)
588 qtypes := []dnsmessage.Type{dnsmessage.TypeA, dnsmessage.TypeAAAA}
589 switch ipVersion(network) {
590 case '4':
591 qtypes = []dnsmessage.Type{dnsmessage.TypeA}
592 case '6':
593 qtypes = []dnsmessage.Type{dnsmessage.TypeAAAA}
594 }
595 var queryFn func(fqdn string, qtype dnsmessage.Type)
596 var responseFn func(fqdn string, qtype dnsmessage.Type) result
597 if conf.singleRequest {
598 queryFn = func(fqdn string, qtype dnsmessage.Type) {}
599 responseFn = func(fqdn string, qtype dnsmessage.Type) result {
600 dnsWaitGroup.Add(1)
601 defer dnsWaitGroup.Done()
602 p, server, err := r.tryOneName(ctx, conf, fqdn, qtype)
603 return result{p, server, err}
604 }
605 } else {
606 queryFn = func(fqdn string, qtype dnsmessage.Type) {
607 dnsWaitGroup.Add(1)
608 go func(qtype dnsmessage.Type) {
609 p, server, err := r.tryOneName(ctx, conf, fqdn, qtype)
610 lane <- result{p, server, err}
611 dnsWaitGroup.Done()
612 }(qtype)
613 }
614 responseFn = func(fqdn string, qtype dnsmessage.Type) result {
615 return <-lane
616 }
617 }
618 var lastErr error
619 for _, fqdn := range conf.nameList(name) {
620 for _, qtype := range qtypes {
621 queryFn(fqdn, qtype)
622 }
623 hitStrictError := false
624 for _, qtype := range qtypes {
625 result := responseFn(fqdn, qtype)
626 if result.error != nil {
627 if nerr, ok := result.error.(Error); ok && nerr.Temporary() && r.strictErrors() {
628
629 hitStrictError = true
630 lastErr = result.error
631 } else if lastErr == nil || fqdn == name+"." {
632
633 lastErr = result.error
634 }
635 continue
636 }
637
638
639
640
641
642
643
644
645
646
647
648
649
650
651
652
653 loop:
654 for {
655 h, err := result.p.AnswerHeader()
656 if err != nil && err != dnsmessage.ErrSectionDone {
657 lastErr = &DNSError{
658 Err: "cannot marshal DNS message",
659 Name: name,
660 Server: result.server,
661 }
662 }
663 if err != nil {
664 break
665 }
666 switch h.Type {
667 case dnsmessage.TypeA:
668 a, err := result.p.AResource()
669 if err != nil {
670 lastErr = &DNSError{
671 Err: "cannot marshal DNS message",
672 Name: name,
673 Server: result.server,
674 }
675 break loop
676 }
677 addrs = append(addrs, IPAddr{IP: IP(a.A[:])})
678
679 case dnsmessage.TypeAAAA:
680 aaaa, err := result.p.AAAAResource()
681 if err != nil {
682 lastErr = &DNSError{
683 Err: "cannot marshal DNS message",
684 Name: name,
685 Server: result.server,
686 }
687 break loop
688 }
689 addrs = append(addrs, IPAddr{IP: IP(aaaa.AAAA[:])})
690
691 default:
692 if err := result.p.SkipAnswer(); err != nil {
693 lastErr = &DNSError{
694 Err: "cannot marshal DNS message",
695 Name: name,
696 Server: result.server,
697 }
698 break loop
699 }
700 continue
701 }
702 if cname.Length == 0 && h.Name.Length != 0 {
703 cname = h.Name
704 }
705 }
706 }
707 if hitStrictError {
708
709
710
711 addrs = nil
712 break
713 }
714 if len(addrs) > 0 {
715 break
716 }
717 }
718 if lastErr, ok := lastErr.(*DNSError); ok {
719
720
721
722 lastErr.Name = name
723 }
724 sortByRFC6724(addrs)
725 if len(addrs) == 0 {
726 if order == hostLookupDNSFiles {
727 addrs = goLookupIPFiles(name)
728 }
729 if len(addrs) == 0 && lastErr != nil {
730 return nil, dnsmessage.Name{}, lastErr
731 }
732 }
733 return addrs, cname, nil
734 }
735
736
737 func (r *Resolver) goLookupCNAME(ctx context.Context, host string) (string, error) {
738 order := systemConf().hostLookupOrder(r, host)
739 _, cname, err := r.goLookupIPCNAMEOrder(ctx, "ip", host, order)
740 return cname.String(), err
741 }
742
743
744
745
746
747
748 func (r *Resolver) goLookupPTR(ctx context.Context, addr string) ([]string, error) {
749 names := lookupStaticAddr(addr)
750 if len(names) > 0 {
751 return names, nil
752 }
753 arpa, err := reverseaddr(addr)
754 if err != nil {
755 return nil, err
756 }
757 p, server, err := r.lookup(ctx, arpa, dnsmessage.TypePTR)
758 if err != nil {
759 return nil, err
760 }
761 var ptrs []string
762 for {
763 h, err := p.AnswerHeader()
764 if err == dnsmessage.ErrSectionDone {
765 break
766 }
767 if err != nil {
768 return nil, &DNSError{
769 Err: "cannot marshal DNS message",
770 Name: addr,
771 Server: server,
772 }
773 }
774 if h.Type != dnsmessage.TypePTR {
775 err := p.SkipAnswer()
776 if err != nil {
777 return nil, &DNSError{
778 Err: "cannot marshal DNS message",
779 Name: addr,
780 Server: server,
781 }
782 }
783 continue
784 }
785 ptr, err := p.PTRResource()
786 if err != nil {
787 return nil, &DNSError{
788 Err: "cannot marshal DNS message",
789 Name: addr,
790 Server: server,
791 }
792 }
793 ptrs = append(ptrs, ptr.PTR.String())
794
795 }
796 return ptrs, nil
797 }
798
View as plain text