github.com/zxy12/golang151_with_comment@v0.0.0-20190507085033-721809559d3c/net/dnsclient_unix.go (about)

     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.
     4  
     5  // +build darwin dragonfly freebsd linux netbsd openbsd solaris
     6  
     7  // DNS client: see RFC 1035.
     8  // Has to be linked into package net for Dial.
     9  
    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.
    15  
    16  package net
    17  
    18  import (
    19  	"errors"
    20  	"io"
    21  	"math/rand"
    22  	"os"
    23  	"strconv"
    24  	"sync"
    25  	"time"
    26  )
    27  
    28  // A dnsConn represents a DNS transport endpoint.
    29  type dnsConn interface {
    30  	Conn
    31  
    32  	// readDNSResponse reads a DNS response message from the DNS
    33  	// transport endpoint and returns the received DNS response
    34  	// message.
    35  	readDNSResponse() (*dnsMsg, error)
    36  
    37  	// writeDNSQuery writes a DNS query message to the DNS
    38  	// connection endpoint.
    39  	writeDNSQuery(*dnsMsg) error
    40  }
    41  
    42  func (c *UDPConn) readDNSResponse() (*dnsMsg, error) {
    43  	b := make([]byte, 512) // see RFC 1035
    44  	n, err := c.Read(b)
    45  	if err != nil {
    46  		return nil, err
    47  	}
    48  	msg := &dnsMsg{}
    49  	if !msg.Unpack(b[:n]) {
    50  		return nil, errors.New("cannot unmarshal DNS message")
    51  	}
    52  	return msg, nil
    53  }
    54  
    55  func (c *UDPConn) writeDNSQuery(msg *dnsMsg) error {
    56  	b, ok := msg.Pack()
    57  	if !ok {
    58  		return errors.New("cannot marshal DNS message")
    59  	}
    60  	if _, err := c.Write(b); err != nil {
    61  		return err
    62  	}
    63  	return nil
    64  }
    65  
    66  func (c *TCPConn) readDNSResponse() (*dnsMsg, error) {
    67  	b := make([]byte, 1280) // 1280 is a reasonable initial size for IP over Ethernet, see RFC 4035
    68  	if _, err := io.ReadFull(c, b[:2]); err != nil {
    69  		return nil, err
    70  	}
    71  	l := int(b[0])<<8 | int(b[1])
    72  	if l > len(b) {
    73  		b = make([]byte, l)
    74  	}
    75  	n, err := io.ReadFull(c, b[:l])
    76  	if err != nil {
    77  		return nil, err
    78  	}
    79  	msg := &dnsMsg{}
    80  	if !msg.Unpack(b[:n]) {
    81  		return nil, errors.New("cannot unmarshal DNS message")
    82  	}
    83  	return msg, nil
    84  }
    85  
    86  func (c *TCPConn) writeDNSQuery(msg *dnsMsg) error {
    87  	b, ok := msg.Pack()
    88  	if !ok {
    89  		return errors.New("cannot marshal DNS message")
    90  	}
    91  	l := uint16(len(b))
    92  	b = append([]byte{byte(l >> 8), byte(l)}, b...)
    93  	if _, err := c.Write(b); err != nil {
    94  		return err
    95  	}
    96  	return nil
    97  }
    98  
    99  func (d *Dialer) dialDNS(network, server string) (dnsConn, error) {
   100  	switch network {
   101  	case "tcp", "tcp4", "tcp6", "udp", "udp4", "udp6":
   102  	default:
   103  		return nil, UnknownNetworkError(network)
   104  	}
   105  	// Calling Dial here is scary -- we have to be sure not to
   106  	// dial a name that will require a DNS lookup, or Dial will
   107  	// call back here to translate it. The DNS config parser has
   108  	// already checked that all the cfg.servers[i] are IP
   109  	// addresses, which Dial will use without a DNS lookup.
   110  	c, err := d.Dial(network, server)
   111  	if err != nil {
   112  		return nil, err
   113  	}
   114  	switch network {
   115  	case "tcp", "tcp4", "tcp6":
   116  		return c.(*TCPConn), nil
   117  	case "udp", "udp4", "udp6":
   118  		return c.(*UDPConn), nil
   119  	}
   120  	panic("unreachable")
   121  }
   122  
   123  // exchange sends a query on the connection and hopes for a response.
   124  func exchange(server, name string, qtype uint16, timeout time.Duration) (*dnsMsg, error) {
   125  	d := Dialer{Timeout: timeout}
   126  	out := dnsMsg{
   127  		dnsMsgHdr: dnsMsgHdr{
   128  			recursion_desired: true,
   129  		},
   130  		question: []dnsQuestion{
   131  			{name, qtype, dnsClassINET},
   132  		},
   133  	}
   134  	for _, network := range []string{"udp", "tcp"} {
   135  		c, err := d.dialDNS(network, server)
   136  		if err != nil {
   137  			return nil, err
   138  		}
   139  		defer c.Close()
   140  		if timeout > 0 {
   141  			c.SetDeadline(time.Now().Add(timeout))
   142  		}
   143  		out.id = uint16(rand.Int()) ^ uint16(time.Now().UnixNano())
   144  		if err := c.writeDNSQuery(&out); err != nil {
   145  			return nil, err
   146  		}
   147  		in, err := c.readDNSResponse()
   148  		if err != nil {
   149  			return nil, err
   150  		}
   151  		if in.id != out.id {
   152  			return nil, errors.New("DNS message ID mismatch")
   153  		}
   154  		if in.truncated { // see RFC 5966
   155  			continue
   156  		}
   157  		return in, nil
   158  	}
   159  	return nil, errors.New("no answer from DNS server")
   160  }
   161  
   162  // Do a lookup for a single name, which must be rooted
   163  // (otherwise answer will not find the answers).
   164  func tryOneName(cfg *dnsConfig, name string, qtype uint16) (string, []dnsRR, error) {
   165  	if len(cfg.servers) == 0 {
   166  		return "", nil, &DNSError{Err: "no DNS servers", Name: name}
   167  	}
   168  	if len(name) >= 256 {
   169  		return "", nil, &DNSError{Err: "DNS name too long", Name: name}
   170  	}
   171  	timeout := time.Duration(cfg.timeout) * time.Second
   172  	var lastErr error
   173  	for i := 0; i < cfg.attempts; i++ {
   174  		for _, server := range cfg.servers {
   175  			server = JoinHostPort(server, "53")
   176  			msg, err := exchange(server, name, qtype, timeout)
   177  			if err != nil {
   178  				lastErr = &DNSError{
   179  					Err:    err.Error(),
   180  					Name:   name,
   181  					Server: server,
   182  				}
   183  				if nerr, ok := err.(Error); ok && nerr.Timeout() {
   184  					lastErr.(*DNSError).IsTimeout = true
   185  				}
   186  				continue
   187  			}
   188  			cname, rrs, err := answer(name, server, msg, qtype)
   189  			if err == nil || msg.rcode == dnsRcodeSuccess || msg.rcode == dnsRcodeNameError && msg.recursion_available {
   190  				return cname, rrs, err
   191  			}
   192  			lastErr = err
   193  		}
   194  	}
   195  	return "", nil, lastErr
   196  }
   197  
   198  // addrRecordList converts and returns a list of IP addresses from DNS
   199  // address records (both A and AAAA). Other record types are ignored.
   200  func addrRecordList(rrs []dnsRR) []IPAddr {
   201  	addrs := make([]IPAddr, 0, 4)
   202  	for _, rr := range rrs {
   203  		switch rr := rr.(type) {
   204  		case *dnsRR_A:
   205  			addrs = append(addrs, IPAddr{IP: IPv4(byte(rr.A>>24), byte(rr.A>>16), byte(rr.A>>8), byte(rr.A))})
   206  		case *dnsRR_AAAA:
   207  			ip := make(IP, IPv6len)
   208  			copy(ip, rr.AAAA[:])
   209  			addrs = append(addrs, IPAddr{IP: ip})
   210  		}
   211  	}
   212  	return addrs
   213  }
   214  
   215  // A resolverConfig represents a DNS stub resolver configuration.
   216  type resolverConfig struct {
   217  	initOnce sync.Once // guards init of resolverConfig
   218  
   219  	// ch is used as a semaphore that only allows one lookup at a
   220  	// time to recheck resolv.conf.
   221  	ch          chan struct{} // guards lastChecked and modTime
   222  	lastChecked time.Time     // last time resolv.conf was checked
   223  	modTime     time.Time     // time of resolv.conf modification
   224  
   225  	mu        sync.RWMutex // protects dnsConfig
   226  	dnsConfig *dnsConfig   // parsed resolv.conf structure used in lookups
   227  }
   228  
   229  var resolvConf resolverConfig
   230  
   231  // init initializes conf and is only called via conf.initOnce.
   232  func (conf *resolverConfig) init() {
   233  	// Set dnsConfig, modTime, and lastChecked so we don't parse
   234  	// resolv.conf twice the first time.
   235  	conf.dnsConfig = systemConf().resolv
   236  	if conf.dnsConfig == nil {
   237  		conf.dnsConfig = dnsReadConfig("/etc/resolv.conf")
   238  	}
   239  
   240  	if fi, err := os.Stat("/etc/resolv.conf"); err == nil {
   241  		conf.modTime = fi.ModTime()
   242  	}
   243  	conf.lastChecked = time.Now()
   244  
   245  	// Prepare ch so that only one update of resolverConfig may
   246  	// run at once.
   247  	conf.ch = make(chan struct{}, 1)
   248  }
   249  
   250  // tryUpdate tries to update conf with the named resolv.conf file.
   251  // The name variable only exists for testing. It is otherwise always
   252  // "/etc/resolv.conf".
   253  func (conf *resolverConfig) tryUpdate(name string) {
   254  	conf.initOnce.Do(conf.init)
   255  
   256  	// Ensure only one update at a time checks resolv.conf.
   257  	if !conf.tryAcquireSema() {
   258  		return
   259  	}
   260  	defer conf.releaseSema()
   261  
   262  	now := time.Now()
   263  	if conf.lastChecked.After(now.Add(-5 * time.Second)) {
   264  		return
   265  	}
   266  	conf.lastChecked = now
   267  
   268  	if fi, err := os.Stat(name); err == nil {
   269  		if fi.ModTime().Equal(conf.modTime) {
   270  			return
   271  		}
   272  		conf.modTime = fi.ModTime()
   273  	} else {
   274  		// If modTime wasn't set prior, assume nothing has changed.
   275  		if conf.modTime.IsZero() {
   276  			return
   277  		}
   278  		conf.modTime = time.Time{}
   279  	}
   280  
   281  	dnsConf := dnsReadConfig(name)
   282  	conf.mu.Lock()
   283  	conf.dnsConfig = dnsConf
   284  	conf.mu.Unlock()
   285  }
   286  
   287  func (conf *resolverConfig) tryAcquireSema() bool {
   288  	select {
   289  	case conf.ch <- struct{}{}:
   290  		return true
   291  	default:
   292  		return false
   293  	}
   294  }
   295  
   296  func (conf *resolverConfig) releaseSema() {
   297  	<-conf.ch
   298  }
   299  
   300  func lookup(name string, qtype uint16) (cname string, rrs []dnsRR, err error) {
   301  	if !isDomainName(name) {
   302  		return "", nil, &DNSError{Err: "invalid domain name", Name: name}
   303  	}
   304  	resolvConf.tryUpdate("/etc/resolv.conf")
   305  	resolvConf.mu.RLock()
   306  	conf := resolvConf.dnsConfig
   307  	resolvConf.mu.RUnlock()
   308  	for _, fqdn := range conf.nameList(name) {
   309  		cname, rrs, err = tryOneName(conf, fqdn, qtype)
   310  		if err == nil {
   311  			break
   312  		}
   313  	}
   314  	if err, ok := err.(*DNSError); ok {
   315  		// Show original name passed to lookup, not suffixed one.
   316  		// In general we might have tried many suffixes; showing
   317  		// just one is misleading. See also golang.org/issue/6324.
   318  		err.Name = name
   319  	}
   320  	return
   321  }
   322  
   323  // nameList returns a list of names for sequential DNS queries.
   324  func (conf *dnsConfig) nameList(name string) []string {
   325  	// If name is rooted (trailing dot), try only that name.
   326  	rooted := len(name) > 0 && name[len(name)-1] == '.'
   327  	if rooted {
   328  		return []string{name}
   329  	}
   330  	// Build list of search choices.
   331  	names := make([]string, 0, 1+len(conf.search))
   332  	// If name has enough dots, try unsuffixed first.
   333  	if count(name, '.') >= conf.ndots {
   334  		names = append(names, name+".")
   335  	}
   336  	// Try suffixes.
   337  	for _, suffix := range conf.search {
   338  		suffixed := name + "." + suffix
   339  		if suffixed[len(suffixed)-1] != '.' {
   340  			suffixed += "."
   341  		}
   342  		names = append(names, suffixed)
   343  	}
   344  	// Try unsuffixed, if not tried first above.
   345  	if count(name, '.') < conf.ndots {
   346  		names = append(names, name+".")
   347  	}
   348  	return names
   349  }
   350  
   351  // hostLookupOrder specifies the order of LookupHost lookup strategies.
   352  // It is basically a simplified representation of nsswitch.conf.
   353  // "files" means /etc/hosts.
   354  type hostLookupOrder int
   355  
   356  const (
   357  	// hostLookupCgo means defer to cgo.
   358  	hostLookupCgo      hostLookupOrder = iota
   359  	hostLookupFilesDNS                 // files first
   360  	hostLookupDNSFiles                 // dns first
   361  	hostLookupFiles                    // only files
   362  	hostLookupDNS                      // only DNS
   363  )
   364  
   365  var lookupOrderName = map[hostLookupOrder]string{
   366  	hostLookupCgo:      "cgo",
   367  	hostLookupFilesDNS: "files,dns",
   368  	hostLookupDNSFiles: "dns,files",
   369  	hostLookupFiles:    "files",
   370  	hostLookupDNS:      "dns",
   371  }
   372  
   373  func (o hostLookupOrder) String() string {
   374  	if s, ok := lookupOrderName[o]; ok {
   375  		return s
   376  	}
   377  	return "hostLookupOrder=" + strconv.Itoa(int(o)) + "??"
   378  }
   379  
   380  // goLookupHost is the native Go implementation of LookupHost.
   381  // Used only if cgoLookupHost refuses to handle the request
   382  // (that is, only if cgoLookupHost is the stub in cgo_stub.go).
   383  // Normally we let cgo use the C library resolver instead of
   384  // depending on our lookup code, so that Go and C get the same
   385  // answers.
   386  func goLookupHost(name string) (addrs []string, err error) {
   387  	return goLookupHostOrder(name, hostLookupFilesDNS)
   388  }
   389  
   390  func goLookupHostOrder(name string, order hostLookupOrder) (addrs []string, err error) {
   391  	if order == hostLookupFilesDNS || order == hostLookupFiles {
   392  		// Use entries from /etc/hosts if they match.
   393  		addrs = lookupStaticHost(name)
   394  		if len(addrs) > 0 || order == hostLookupFiles {
   395  			return
   396  		}
   397  	}
   398  	ips, err := goLookupIPOrder(name, order)
   399  	if err != nil {
   400  		return
   401  	}
   402  	addrs = make([]string, 0, len(ips))
   403  	for _, ip := range ips {
   404  		addrs = append(addrs, ip.String())
   405  	}
   406  	return
   407  }
   408  
   409  // lookup entries from /etc/hosts
   410  func goLookupIPFiles(name string) (addrs []IPAddr) {
   411  	for _, haddr := range lookupStaticHost(name) {
   412  		haddr, zone := splitHostZone(haddr)
   413  		if ip := ParseIP(haddr); ip != nil {
   414  			addr := IPAddr{IP: ip, Zone: zone}
   415  			addrs = append(addrs, addr)
   416  		}
   417  	}
   418  	sortByRFC6724(addrs)
   419  	return
   420  }
   421  
   422  // goLookupIP is the native Go implementation of LookupIP.
   423  // The libc versions are in cgo_*.go.
   424  func goLookupIP(name string) (addrs []IPAddr, err error) {
   425  	return goLookupIPOrder(name, hostLookupFilesDNS)
   426  }
   427  
   428  func goLookupIPOrder(name string, order hostLookupOrder) (addrs []IPAddr, err error) {
   429  	if order == hostLookupFilesDNS || order == hostLookupFiles {
   430  		addrs = goLookupIPFiles(name)
   431  		if len(addrs) > 0 || order == hostLookupFiles {
   432  			return addrs, nil
   433  		}
   434  	}
   435  	if !isDomainName(name) {
   436  		return nil, &DNSError{Err: "invalid domain name", Name: name}
   437  	}
   438  	resolvConf.tryUpdate("/etc/resolv.conf")
   439  	resolvConf.mu.RLock()
   440  	conf := resolvConf.dnsConfig
   441  	resolvConf.mu.RUnlock()
   442  	type racer struct {
   443  		rrs []dnsRR
   444  		error
   445  	}
   446  	lane := make(chan racer, 1)
   447  	qtypes := [...]uint16{dnsTypeA, dnsTypeAAAA}
   448  	var lastErr error
   449  	for _, fqdn := range conf.nameList(name) {
   450  		for _, qtype := range qtypes {
   451  			go func(qtype uint16) {
   452  				_, rrs, err := tryOneName(conf, fqdn, qtype)
   453  				lane <- racer{rrs, err}
   454  			}(qtype)
   455  		}
   456  		for range qtypes {
   457  			racer := <-lane
   458  			if racer.error != nil {
   459  				lastErr = racer.error
   460  				continue
   461  			}
   462  			addrs = append(addrs, addrRecordList(racer.rrs)...)
   463  		}
   464  		if len(addrs) > 0 {
   465  			break
   466  		}
   467  	}
   468  	if lastErr, ok := lastErr.(*DNSError); ok {
   469  		// Show original name passed to lookup, not suffixed one.
   470  		// In general we might have tried many suffixes; showing
   471  		// just one is misleading. See also golang.org/issue/6324.
   472  		lastErr.Name = name
   473  	}
   474  	sortByRFC6724(addrs)
   475  	if len(addrs) == 0 {
   476  		if lastErr != nil {
   477  			return nil, lastErr
   478  		}
   479  		if order == hostLookupDNSFiles {
   480  			addrs = goLookupIPFiles(name)
   481  		}
   482  	}
   483  	return addrs, nil
   484  }
   485  
   486  // goLookupCNAME is the native Go implementation of LookupCNAME.
   487  // Used only if cgoLookupCNAME refuses to handle the request
   488  // (that is, only if cgoLookupCNAME is the stub in cgo_stub.go).
   489  // Normally we let cgo use the C library resolver instead of
   490  // depending on our lookup code, so that Go and C get the same
   491  // answers.
   492  func goLookupCNAME(name string) (cname string, err error) {
   493  	_, rrs, err := lookup(name, dnsTypeCNAME)
   494  	if err != nil {
   495  		return
   496  	}
   497  	cname = rrs[0].(*dnsRR_CNAME).Cname
   498  	return
   499  }
   500  
   501  // goLookupPTR is the native Go implementation of LookupAddr.
   502  // Used only if cgoLookupPTR refuses to handle the request (that is,
   503  // only if cgoLookupPTR is the stub in cgo_stub.go).
   504  // Normally we let cgo use the C library resolver instead of depending
   505  // on our lookup code, so that Go and C get the same answers.
   506  func goLookupPTR(addr string) ([]string, error) {
   507  	names := lookupStaticAddr(addr)
   508  	if len(names) > 0 {
   509  		return names, nil
   510  	}
   511  	arpa, err := reverseaddr(addr)
   512  	if err != nil {
   513  		return nil, err
   514  	}
   515  	_, rrs, err := lookup(arpa, dnsTypePTR)
   516  	if err != nil {
   517  		return nil, err
   518  	}
   519  	ptrs := make([]string, len(rrs))
   520  	for i, rr := range rrs {
   521  		ptrs[i] = rr.(*dnsRR_PTR).Ptr
   522  	}
   523  	return ptrs, nil
   524  }