libgo: update to Go 1.11
[official-gcc.git] / libgo / go / net / dnsclient_unix.go
blob6ec2f44b7cb1dc19c2a2bb5851964d94af12a52a
1 // Copyright 2009 The Go Authors. All rights reserved.
2 // Use of this source code is governed by a BSD-style
3 // license that can be found in the LICENSE file.
5 // +build aix darwin dragonfly freebsd linux netbsd openbsd solaris
7 // DNS client: see RFC 1035.
8 // Has to be linked into package net for Dial.
10 // TODO(rsc):
11 // Could potentially handle many outstanding lookups faster.
12 // Could have a small cache.
13 // Random UDP source port (net.Dial should do that for us).
14 // Random request IDs.
16 package net
18 import (
19 "context"
20 "errors"
21 "io"
22 "math/rand"
23 "os"
24 "sync"
25 "time"
27 "golang_org/x/net/dns/dnsmessage"
30 func newRequest(q dnsmessage.Question) (id uint16, udpReq, tcpReq []byte, err error) {
31 id = uint16(rand.Int()) ^ uint16(time.Now().UnixNano())
32 b := dnsmessage.NewBuilder(make([]byte, 2, 514), dnsmessage.Header{ID: id, RecursionDesired: true})
33 b.EnableCompression()
34 if err := b.StartQuestions(); err != nil {
35 return 0, nil, nil, err
37 if err := b.Question(q); err != nil {
38 return 0, nil, nil, err
40 tcpReq, err = b.Finish()
41 udpReq = tcpReq[2:]
42 l := len(tcpReq) - 2
43 tcpReq[0] = byte(l >> 8)
44 tcpReq[1] = byte(l)
45 return id, udpReq, tcpReq, err
48 func checkResponse(reqID uint16, reqQues dnsmessage.Question, respHdr dnsmessage.Header, respQues dnsmessage.Question) bool {
49 if !respHdr.Response {
50 return false
52 if reqID != respHdr.ID {
53 return false
55 if reqQues.Type != respQues.Type || reqQues.Class != respQues.Class || !equalASCIIName(reqQues.Name, respQues.Name) {
56 return false
58 return true
61 func dnsPacketRoundTrip(c Conn, id uint16, query dnsmessage.Question, b []byte) (dnsmessage.Parser, dnsmessage.Header, error) {
62 if _, err := c.Write(b); err != nil {
63 return dnsmessage.Parser{}, dnsmessage.Header{}, err
66 b = make([]byte, 512) // see RFC 1035
67 for {
68 n, err := c.Read(b)
69 if err != nil {
70 return dnsmessage.Parser{}, dnsmessage.Header{}, err
72 var p dnsmessage.Parser
73 // Ignore invalid responses as they may be malicious
74 // forgery attempts. Instead continue waiting until
75 // timeout. See golang.org/issue/13281.
76 h, err := p.Start(b[:n])
77 if err != nil {
78 continue
80 q, err := p.Question()
81 if err != nil || !checkResponse(id, query, h, q) {
82 continue
84 return p, h, nil
88 func dnsStreamRoundTrip(c Conn, id uint16, query dnsmessage.Question, b []byte) (dnsmessage.Parser, dnsmessage.Header, error) {
89 if _, err := c.Write(b); err != nil {
90 return dnsmessage.Parser{}, dnsmessage.Header{}, err
93 b = make([]byte, 1280) // 1280 is a reasonable initial size for IP over Ethernet, see RFC 4035
94 if _, err := io.ReadFull(c, b[:2]); err != nil {
95 return dnsmessage.Parser{}, dnsmessage.Header{}, err
97 l := int(b[0])<<8 | int(b[1])
98 if l > len(b) {
99 b = make([]byte, l)
101 n, err := io.ReadFull(c, b[:l])
102 if err != nil {
103 return dnsmessage.Parser{}, dnsmessage.Header{}, err
105 var p dnsmessage.Parser
106 h, err := p.Start(b[:n])
107 if err != nil {
108 return dnsmessage.Parser{}, dnsmessage.Header{}, errors.New("cannot unmarshal DNS message")
110 q, err := p.Question()
111 if err != nil {
112 return dnsmessage.Parser{}, dnsmessage.Header{}, errors.New("cannot unmarshal DNS message")
114 if !checkResponse(id, query, h, q) {
115 return dnsmessage.Parser{}, dnsmessage.Header{}, errors.New("invalid DNS response")
117 return p, h, nil
120 // exchange sends a query on the connection and hopes for a response.
121 func (r *Resolver) exchange(ctx context.Context, server string, q dnsmessage.Question, timeout time.Duration) (dnsmessage.Parser, dnsmessage.Header, error) {
122 q.Class = dnsmessage.ClassINET
123 id, udpReq, tcpReq, err := newRequest(q)
124 if err != nil {
125 return dnsmessage.Parser{}, dnsmessage.Header{}, errors.New("cannot marshal DNS message")
127 for _, network := range []string{"udp", "tcp"} {
128 ctx, cancel := context.WithDeadline(ctx, time.Now().Add(timeout))
129 defer cancel()
131 c, err := r.dial(ctx, network, server)
132 if err != nil {
133 return dnsmessage.Parser{}, dnsmessage.Header{}, err
135 if d, ok := ctx.Deadline(); ok && !d.IsZero() {
136 c.SetDeadline(d)
138 var p dnsmessage.Parser
139 var h dnsmessage.Header
140 if _, ok := c.(PacketConn); ok {
141 p, h, err = dnsPacketRoundTrip(c, id, q, udpReq)
142 } else {
143 p, h, err = dnsStreamRoundTrip(c, id, q, tcpReq)
145 c.Close()
146 if err != nil {
147 return dnsmessage.Parser{}, dnsmessage.Header{}, mapErr(err)
149 if err := p.SkipQuestion(); err != dnsmessage.ErrSectionDone {
150 return dnsmessage.Parser{}, dnsmessage.Header{}, errors.New("invalid DNS response")
152 if h.Truncated { // see RFC 5966
153 continue
155 return p, h, nil
157 return dnsmessage.Parser{}, dnsmessage.Header{}, errors.New("no answer from DNS server")
160 // checkHeader performs basic sanity checks on the header.
161 func checkHeader(p *dnsmessage.Parser, h dnsmessage.Header, name, server string) error {
162 _, err := p.AnswerHeader()
163 if err != nil && err != dnsmessage.ErrSectionDone {
164 return &DNSError{
165 Err: "cannot unmarshal DNS message",
166 Name: name,
167 Server: server,
171 // libresolv continues to the next server when it receives
172 // an invalid referral response. See golang.org/issue/15434.
173 if h.RCode == dnsmessage.RCodeSuccess && !h.Authoritative && !h.RecursionAvailable && err == dnsmessage.ErrSectionDone {
174 return &DNSError{Err: "lame referral", Name: name, Server: server}
177 if h.RCode != dnsmessage.RCodeSuccess && h.RCode != dnsmessage.RCodeNameError {
178 // None of the error codes make sense
179 // for the query we sent. If we didn't get
180 // a name error and we didn't get success,
181 // the server is behaving incorrectly or
182 // having temporary trouble.
183 err := &DNSError{Err: "server misbehaving", Name: name, Server: server}
184 if h.RCode == dnsmessage.RCodeServerFailure {
185 err.IsTemporary = true
187 return err
190 return nil
193 func skipToAnswer(p *dnsmessage.Parser, qtype dnsmessage.Type, name, server string) error {
194 for {
195 h, err := p.AnswerHeader()
196 if err == dnsmessage.ErrSectionDone {
197 return &DNSError{
198 Err: errNoSuchHost.Error(),
199 Name: name,
200 Server: server,
203 if err != nil {
204 return &DNSError{
205 Err: "cannot unmarshal DNS message",
206 Name: name,
207 Server: server,
210 if h.Type == qtype {
211 return nil
213 if err := p.SkipAnswer(); err != nil {
214 return &DNSError{
215 Err: "cannot unmarshal DNS message",
216 Name: name,
217 Server: server,
223 // Do a lookup for a single name, which must be rooted
224 // (otherwise answer will not find the answers).
225 func (r *Resolver) tryOneName(ctx context.Context, cfg *dnsConfig, name string, qtype dnsmessage.Type) (dnsmessage.Parser, string, error) {
226 var lastErr error
227 serverOffset := cfg.serverOffset()
228 sLen := uint32(len(cfg.servers))
230 n, err := dnsmessage.NewName(name)
231 if err != nil {
232 return dnsmessage.Parser{}, "", errors.New("cannot marshal DNS message")
234 q := dnsmessage.Question{
235 Name: n,
236 Type: qtype,
237 Class: dnsmessage.ClassINET,
240 for i := 0; i < cfg.attempts; i++ {
241 for j := uint32(0); j < sLen; j++ {
242 server := cfg.servers[(serverOffset+j)%sLen]
244 p, h, err := r.exchange(ctx, server, q, cfg.timeout)
245 if err != nil {
246 lastErr = &DNSError{
247 Err: err.Error(),
248 Name: name,
249 Server: server,
251 if nerr, ok := err.(Error); ok && nerr.Timeout() {
252 lastErr.(*DNSError).IsTimeout = true
254 // Set IsTemporary for socket-level errors. Note that this flag
255 // may also be used to indicate a SERVFAIL response.
256 if _, ok := err.(*OpError); ok {
257 lastErr.(*DNSError).IsTemporary = true
259 continue
262 // The name does not exist, so trying another server won't help.
264 // TODO: indicate this in a more obvious way, such as a field on DNSError?
265 if h.RCode == dnsmessage.RCodeNameError {
266 return dnsmessage.Parser{}, "", &DNSError{Err: errNoSuchHost.Error(), Name: name, Server: server}
269 lastErr = checkHeader(&p, h, name, server)
270 if lastErr != nil {
271 continue
274 lastErr = skipToAnswer(&p, qtype, name, server)
275 if lastErr == nil {
276 return p, server, nil
280 return dnsmessage.Parser{}, "", lastErr
283 // A resolverConfig represents a DNS stub resolver configuration.
284 type resolverConfig struct {
285 initOnce sync.Once // guards init of resolverConfig
287 // ch is used as a semaphore that only allows one lookup at a
288 // time to recheck resolv.conf.
289 ch chan struct{} // guards lastChecked and modTime
290 lastChecked time.Time // last time resolv.conf was checked
292 mu sync.RWMutex // protects dnsConfig
293 dnsConfig *dnsConfig // parsed resolv.conf structure used in lookups
296 var resolvConf resolverConfig
298 // init initializes conf and is only called via conf.initOnce.
299 func (conf *resolverConfig) init() {
300 // Set dnsConfig and lastChecked so we don't parse
301 // resolv.conf twice the first time.
302 conf.dnsConfig = systemConf().resolv
303 if conf.dnsConfig == nil {
304 conf.dnsConfig = dnsReadConfig("/etc/resolv.conf")
306 conf.lastChecked = time.Now()
308 // Prepare ch so that only one update of resolverConfig may
309 // run at once.
310 conf.ch = make(chan struct{}, 1)
313 // tryUpdate tries to update conf with the named resolv.conf file.
314 // The name variable only exists for testing. It is otherwise always
315 // "/etc/resolv.conf".
316 func (conf *resolverConfig) tryUpdate(name string) {
317 conf.initOnce.Do(conf.init)
319 // Ensure only one update at a time checks resolv.conf.
320 if !conf.tryAcquireSema() {
321 return
323 defer conf.releaseSema()
325 now := time.Now()
326 if conf.lastChecked.After(now.Add(-5 * time.Second)) {
327 return
329 conf.lastChecked = now
331 var mtime time.Time
332 if fi, err := os.Stat(name); err == nil {
333 mtime = fi.ModTime()
335 if mtime.Equal(conf.dnsConfig.mtime) {
336 return
339 dnsConf := dnsReadConfig(name)
340 conf.mu.Lock()
341 conf.dnsConfig = dnsConf
342 conf.mu.Unlock()
345 func (conf *resolverConfig) tryAcquireSema() bool {
346 select {
347 case conf.ch <- struct{}{}:
348 return true
349 default:
350 return false
354 func (conf *resolverConfig) releaseSema() {
355 <-conf.ch
358 func (r *Resolver) lookup(ctx context.Context, name string, qtype dnsmessage.Type) (dnsmessage.Parser, string, error) {
359 if !isDomainName(name) {
360 // We used to use "invalid domain name" as the error,
361 // but that is a detail of the specific lookup mechanism.
362 // Other lookups might allow broader name syntax
363 // (for example Multicast DNS allows UTF-8; see RFC 6762).
364 // For consistency with libc resolvers, report no such host.
365 return dnsmessage.Parser{}, "", &DNSError{Err: errNoSuchHost.Error(), Name: name}
367 resolvConf.tryUpdate("/etc/resolv.conf")
368 resolvConf.mu.RLock()
369 conf := resolvConf.dnsConfig
370 resolvConf.mu.RUnlock()
371 var (
372 p dnsmessage.Parser
373 server string
374 err error
376 for _, fqdn := range conf.nameList(name) {
377 p, server, err = r.tryOneName(ctx, conf, fqdn, qtype)
378 if err == nil {
379 break
381 if nerr, ok := err.(Error); ok && nerr.Temporary() && r.strictErrors() {
382 // If we hit a temporary error with StrictErrors enabled,
383 // stop immediately instead of trying more names.
384 break
387 if err == nil {
388 return p, server, nil
390 if err, ok := err.(*DNSError); ok {
391 // Show original name passed to lookup, not suffixed one.
392 // In general we might have tried many suffixes; showing
393 // just one is misleading. See also golang.org/issue/6324.
394 err.Name = name
396 return dnsmessage.Parser{}, "", err
399 // avoidDNS reports whether this is a hostname for which we should not
400 // use DNS. Currently this includes only .onion, per RFC 7686. See
401 // golang.org/issue/13705. Does not cover .local names (RFC 6762),
402 // see golang.org/issue/16739.
403 func avoidDNS(name string) bool {
404 if name == "" {
405 return true
407 if name[len(name)-1] == '.' {
408 name = name[:len(name)-1]
410 return stringsHasSuffixFold(name, ".onion")
413 // nameList returns a list of names for sequential DNS queries.
414 func (conf *dnsConfig) nameList(name string) []string {
415 if avoidDNS(name) {
416 return nil
419 // Check name length (see isDomainName).
420 l := len(name)
421 rooted := l > 0 && name[l-1] == '.'
422 if l > 254 || l == 254 && rooted {
423 return nil
426 // If name is rooted (trailing dot), try only that name.
427 if rooted {
428 return []string{name}
431 hasNdots := count(name, '.') >= conf.ndots
432 name += "."
435 // Build list of search choices.
436 names := make([]string, 0, 1+len(conf.search))
437 // If name has enough dots, try unsuffixed first.
438 if hasNdots {
439 names = append(names, name)
441 // Try suffixes that are not too long (see isDomainName).
442 for _, suffix := range conf.search {
443 if l+len(suffix) <= 254 {
444 names = append(names, name+suffix)
447 // Try unsuffixed, if not tried first above.
448 if !hasNdots {
449 names = append(names, name)
451 return names
454 // hostLookupOrder specifies the order of LookupHost lookup strategies.
455 // It is basically a simplified representation of nsswitch.conf.
456 // "files" means /etc/hosts.
457 type hostLookupOrder int
459 const (
460 // hostLookupCgo means defer to cgo.
461 hostLookupCgo hostLookupOrder = iota
462 hostLookupFilesDNS // files first
463 hostLookupDNSFiles // dns first
464 hostLookupFiles // only files
465 hostLookupDNS // only DNS
468 var lookupOrderName = map[hostLookupOrder]string{
469 hostLookupCgo: "cgo",
470 hostLookupFilesDNS: "files,dns",
471 hostLookupDNSFiles: "dns,files",
472 hostLookupFiles: "files",
473 hostLookupDNS: "dns",
476 func (o hostLookupOrder) String() string {
477 if s, ok := lookupOrderName[o]; ok {
478 return s
480 return "hostLookupOrder=" + itoa(int(o)) + "??"
483 // goLookupHost is the native Go implementation of LookupHost.
484 // Used only if cgoLookupHost refuses to handle the request
485 // (that is, only if cgoLookupHost is the stub in cgo_stub.go).
486 // Normally we let cgo use the C library resolver instead of
487 // depending on our lookup code, so that Go and C get the same
488 // answers.
489 func (r *Resolver) goLookupHost(ctx context.Context, name string) (addrs []string, err error) {
490 return r.goLookupHostOrder(ctx, name, hostLookupFilesDNS)
493 func (r *Resolver) goLookupHostOrder(ctx context.Context, name string, order hostLookupOrder) (addrs []string, err error) {
494 if order == hostLookupFilesDNS || order == hostLookupFiles {
495 // Use entries from /etc/hosts if they match.
496 addrs = lookupStaticHost(name)
497 if len(addrs) > 0 || order == hostLookupFiles {
498 return
501 ips, _, err := r.goLookupIPCNAMEOrder(ctx, name, order)
502 if err != nil {
503 return
505 addrs = make([]string, 0, len(ips))
506 for _, ip := range ips {
507 addrs = append(addrs, ip.String())
509 return
512 // lookup entries from /etc/hosts
513 func goLookupIPFiles(name string) (addrs []IPAddr) {
514 for _, haddr := range lookupStaticHost(name) {
515 haddr, zone := splitHostZone(haddr)
516 if ip := ParseIP(haddr); ip != nil {
517 addr := IPAddr{IP: ip, Zone: zone}
518 addrs = append(addrs, addr)
521 sortByRFC6724(addrs)
522 return
525 // goLookupIP is the native Go implementation of LookupIP.
526 // The libc versions are in cgo_*.go.
527 func (r *Resolver) goLookupIP(ctx context.Context, host string) (addrs []IPAddr, err error) {
528 order := systemConf().hostLookupOrder(r, host)
529 addrs, _, err = r.goLookupIPCNAMEOrder(ctx, host, order)
530 return
533 func (r *Resolver) goLookupIPCNAMEOrder(ctx context.Context, name string, order hostLookupOrder) (addrs []IPAddr, cname dnsmessage.Name, err error) {
534 if order == hostLookupFilesDNS || order == hostLookupFiles {
535 addrs = goLookupIPFiles(name)
536 if len(addrs) > 0 || order == hostLookupFiles {
537 return addrs, dnsmessage.Name{}, nil
540 if !isDomainName(name) {
541 // See comment in func lookup above about use of errNoSuchHost.
542 return nil, dnsmessage.Name{}, &DNSError{Err: errNoSuchHost.Error(), Name: name}
544 resolvConf.tryUpdate("/etc/resolv.conf")
545 resolvConf.mu.RLock()
546 conf := resolvConf.dnsConfig
547 resolvConf.mu.RUnlock()
548 type racer struct {
549 p dnsmessage.Parser
550 server string
551 error
553 lane := make(chan racer, 1)
554 qtypes := [...]dnsmessage.Type{dnsmessage.TypeA, dnsmessage.TypeAAAA}
555 var lastErr error
556 for _, fqdn := range conf.nameList(name) {
557 for _, qtype := range qtypes {
558 dnsWaitGroup.Add(1)
559 go func(qtype dnsmessage.Type) {
560 p, server, err := r.tryOneName(ctx, conf, fqdn, qtype)
561 lane <- racer{p, server, err}
562 dnsWaitGroup.Done()
563 }(qtype)
565 hitStrictError := false
566 for range qtypes {
567 racer := <-lane
568 if racer.error != nil {
569 if nerr, ok := racer.error.(Error); ok && nerr.Temporary() && r.strictErrors() {
570 // This error will abort the nameList loop.
571 hitStrictError = true
572 lastErr = racer.error
573 } else if lastErr == nil || fqdn == name+"." {
574 // Prefer error for original name.
575 lastErr = racer.error
577 continue
580 // Presotto says it's okay to assume that servers listed in
581 // /etc/resolv.conf are recursive resolvers.
583 // We asked for recursion, so it should have included all the
584 // answers we need in this one packet.
586 // Further, RFC 1035 section 4.3.1 says that "the recursive
587 // response to a query will be... The answer to the query,
588 // possibly preface by one or more CNAME RRs that specify
589 // aliases encountered on the way to an answer."
591 // Therefore, we should be able to assume that we can ignore
592 // CNAMEs and that the A and AAAA records we requested are
593 // for the canonical name.
595 loop:
596 for {
597 h, err := racer.p.AnswerHeader()
598 if err != nil && err != dnsmessage.ErrSectionDone {
599 lastErr = &DNSError{
600 Err: "cannot marshal DNS message",
601 Name: name,
602 Server: racer.server,
605 if err != nil {
606 break
608 switch h.Type {
609 case dnsmessage.TypeA:
610 a, err := racer.p.AResource()
611 if err != nil {
612 lastErr = &DNSError{
613 Err: "cannot marshal DNS message",
614 Name: name,
615 Server: racer.server,
617 break loop
619 addrs = append(addrs, IPAddr{IP: IP(a.A[:])})
621 case dnsmessage.TypeAAAA:
622 aaaa, err := racer.p.AAAAResource()
623 if err != nil {
624 lastErr = &DNSError{
625 Err: "cannot marshal DNS message",
626 Name: name,
627 Server: racer.server,
629 break loop
631 addrs = append(addrs, IPAddr{IP: IP(aaaa.AAAA[:])})
633 default:
634 if err := racer.p.SkipAnswer(); err != nil {
635 lastErr = &DNSError{
636 Err: "cannot marshal DNS message",
637 Name: name,
638 Server: racer.server,
640 break loop
642 continue
644 if cname.Length == 0 && h.Name.Length != 0 {
645 cname = h.Name
649 if hitStrictError {
650 // If either family hit an error with StrictErrors enabled,
651 // discard all addresses. This ensures that network flakiness
652 // cannot turn a dualstack hostname IPv4/IPv6-only.
653 addrs = nil
654 break
656 if len(addrs) > 0 {
657 break
660 if lastErr, ok := lastErr.(*DNSError); ok {
661 // Show original name passed to lookup, not suffixed one.
662 // In general we might have tried many suffixes; showing
663 // just one is misleading. See also golang.org/issue/6324.
664 lastErr.Name = name
666 sortByRFC6724(addrs)
667 if len(addrs) == 0 {
668 if order == hostLookupDNSFiles {
669 addrs = goLookupIPFiles(name)
671 if len(addrs) == 0 && lastErr != nil {
672 return nil, dnsmessage.Name{}, lastErr
675 return addrs, cname, nil
678 // goLookupCNAME is the native Go (non-cgo) implementation of LookupCNAME.
679 func (r *Resolver) goLookupCNAME(ctx context.Context, host string) (string, error) {
680 order := systemConf().hostLookupOrder(r, host)
681 _, cname, err := r.goLookupIPCNAMEOrder(ctx, host, order)
682 return cname.String(), err
685 // goLookupPTR is the native Go implementation of LookupAddr.
686 // Used only if cgoLookupPTR refuses to handle the request (that is,
687 // only if cgoLookupPTR is the stub in cgo_stub.go).
688 // Normally we let cgo use the C library resolver instead of depending
689 // on our lookup code, so that Go and C get the same answers.
690 func (r *Resolver) goLookupPTR(ctx context.Context, addr string) ([]string, error) {
691 names := lookupStaticAddr(addr)
692 if len(names) > 0 {
693 return names, nil
695 arpa, err := reverseaddr(addr)
696 if err != nil {
697 return nil, err
699 p, server, err := r.lookup(ctx, arpa, dnsmessage.TypePTR)
700 if err != nil {
701 return nil, err
703 var ptrs []string
704 for {
705 h, err := p.AnswerHeader()
706 if err == dnsmessage.ErrSectionDone {
707 break
709 if err != nil {
710 return nil, &DNSError{
711 Err: "cannot marshal DNS message",
712 Name: addr,
713 Server: server,
716 if h.Type != dnsmessage.TypePTR {
717 continue
719 ptr, err := p.PTRResource()
720 if err != nil {
721 return nil, &DNSError{
722 Err: "cannot marshal DNS message",
723 Name: addr,
724 Server: server,
727 ptrs = append(ptrs, ptr.PTR.String())
730 return ptrs, nil