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