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