github.com/mtsmfm/go/src@v0.0.0-20221020090648-44bdcb9f8fde/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  //go:build !js
     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  //	Random UDP source port (net.Dial should do that for us).
    13  //	Random request IDs.
    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  	// to be used as a useTCP parameter to exchange
    32  	useTCPOnly  = true
    33  	useUDPOrTCP = false
    34  
    35  	// Maximum DNS packet size.
    36  	// Value taken from https://dnsflagday.net/2020/.
    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  	// errServerTemporarilyMisbehaving is like errServerMisbehaving, except
    49  	// that when it gets translated to a DNSError, the IsTemporary field
    50  	// gets set to true.
    51  	errServerTemporarilyMisbehaving = errors.New("server misbehaving")
    52  )
    53  
    54  func newRequest(q dnsmessage.Question, ad bool) (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, AuthenticData: ad})
    57  	if err := b.StartQuestions(); err != nil {
    58  		return 0, nil, nil, err
    59  	}
    60  	if err := b.Question(q); err != nil {
    61  		return 0, nil, nil, err
    62  	}
    63  
    64  	// Accept packets up to maxDNSPacketSize.  RFC 6891.
    65  	if err := b.StartAdditionals(); err != nil {
    66  		return 0, nil, nil, err
    67  	}
    68  	var rh dnsmessage.ResourceHeader
    69  	if err := rh.SetEDNS0(maxDNSPacketSize, dnsmessage.RCodeSuccess, false); err != nil {
    70  		return 0, nil, nil, err
    71  	}
    72  	if err := b.OPTResource(rh, dnsmessage.OPTResource{}); err != nil {
    73  		return 0, nil, nil, err
    74  	}
    75  
    76  	tcpReq, err = b.Finish()
    77  	if err != nil {
    78  		return 0, nil, nil, err
    79  	}
    80  	udpReq = tcpReq[2:]
    81  	l := len(tcpReq) - 2
    82  	tcpReq[0] = byte(l >> 8)
    83  	tcpReq[1] = byte(l)
    84  	return id, udpReq, tcpReq, nil
    85  }
    86  
    87  func checkResponse(reqID uint16, reqQues dnsmessage.Question, respHdr dnsmessage.Header, respQues dnsmessage.Question) bool {
    88  	if !respHdr.Response {
    89  		return false
    90  	}
    91  	if reqID != respHdr.ID {
    92  		return false
    93  	}
    94  	if reqQues.Type != respQues.Type || reqQues.Class != respQues.Class || !equalASCIIName(reqQues.Name, respQues.Name) {
    95  		return false
    96  	}
    97  	return true
    98  }
    99  
   100  func dnsPacketRoundTrip(c Conn, id uint16, query dnsmessage.Question, b []byte) (dnsmessage.Parser, dnsmessage.Header, error) {
   101  	if _, err := c.Write(b); err != nil {
   102  		return dnsmessage.Parser{}, dnsmessage.Header{}, err
   103  	}
   104  
   105  	b = make([]byte, maxDNSPacketSize)
   106  	for {
   107  		n, err := c.Read(b)
   108  		if err != nil {
   109  			return dnsmessage.Parser{}, dnsmessage.Header{}, err
   110  		}
   111  		var p dnsmessage.Parser
   112  		// Ignore invalid responses as they may be malicious
   113  		// forgery attempts. Instead continue waiting until
   114  		// timeout. See golang.org/issue/13281.
   115  		h, err := p.Start(b[:n])
   116  		if err != nil {
   117  			continue
   118  		}
   119  		q, err := p.Question()
   120  		if err != nil || !checkResponse(id, query, h, q) {
   121  			continue
   122  		}
   123  		return p, h, nil
   124  	}
   125  }
   126  
   127  func dnsStreamRoundTrip(c Conn, id uint16, query dnsmessage.Question, b []byte) (dnsmessage.Parser, dnsmessage.Header, error) {
   128  	if _, err := c.Write(b); err != nil {
   129  		return dnsmessage.Parser{}, dnsmessage.Header{}, err
   130  	}
   131  
   132  	b = make([]byte, 1280) // 1280 is a reasonable initial size for IP over Ethernet, see RFC 4035
   133  	if _, err := io.ReadFull(c, b[:2]); err != nil {
   134  		return dnsmessage.Parser{}, dnsmessage.Header{}, err
   135  	}
   136  	l := int(b[0])<<8 | int(b[1])
   137  	if l > len(b) {
   138  		b = make([]byte, l)
   139  	}
   140  	n, err := io.ReadFull(c, b[:l])
   141  	if err != nil {
   142  		return dnsmessage.Parser{}, dnsmessage.Header{}, err
   143  	}
   144  	var p dnsmessage.Parser
   145  	h, err := p.Start(b[:n])
   146  	if err != nil {
   147  		return dnsmessage.Parser{}, dnsmessage.Header{}, errCannotUnmarshalDNSMessage
   148  	}
   149  	q, err := p.Question()
   150  	if err != nil {
   151  		return dnsmessage.Parser{}, dnsmessage.Header{}, errCannotUnmarshalDNSMessage
   152  	}
   153  	if !checkResponse(id, query, h, q) {
   154  		return dnsmessage.Parser{}, dnsmessage.Header{}, errInvalidDNSResponse
   155  	}
   156  	return p, h, nil
   157  }
   158  
   159  // exchange sends a query on the connection and hopes for a response.
   160  func (r *Resolver) exchange(ctx context.Context, server string, q dnsmessage.Question, timeout time.Duration, useTCP, ad bool) (dnsmessage.Parser, dnsmessage.Header, error) {
   161  	q.Class = dnsmessage.ClassINET
   162  	id, udpReq, tcpReq, err := newRequest(q, ad)
   163  	if err != nil {
   164  		return dnsmessage.Parser{}, dnsmessage.Header{}, errCannotMarshalDNSMessage
   165  	}
   166  	var networks []string
   167  	if useTCP {
   168  		networks = []string{"tcp"}
   169  	} else {
   170  		networks = []string{"udp", "tcp"}
   171  	}
   172  	for _, network := range networks {
   173  		ctx, cancel := context.WithDeadline(ctx, time.Now().Add(timeout))
   174  		defer cancel()
   175  
   176  		c, err := r.dial(ctx, network, server)
   177  		if err != nil {
   178  			return dnsmessage.Parser{}, dnsmessage.Header{}, err
   179  		}
   180  		if d, ok := ctx.Deadline(); ok && !d.IsZero() {
   181  			c.SetDeadline(d)
   182  		}
   183  		var p dnsmessage.Parser
   184  		var h dnsmessage.Header
   185  		if _, ok := c.(PacketConn); ok {
   186  			p, h, err = dnsPacketRoundTrip(c, id, q, udpReq)
   187  		} else {
   188  			p, h, err = dnsStreamRoundTrip(c, id, q, tcpReq)
   189  		}
   190  		c.Close()
   191  		if err != nil {
   192  			return dnsmessage.Parser{}, dnsmessage.Header{}, mapErr(err)
   193  		}
   194  		if err := p.SkipQuestion(); err != dnsmessage.ErrSectionDone {
   195  			return dnsmessage.Parser{}, dnsmessage.Header{}, errInvalidDNSResponse
   196  		}
   197  		if h.Truncated { // see RFC 5966
   198  			continue
   199  		}
   200  		return p, h, nil
   201  	}
   202  	return dnsmessage.Parser{}, dnsmessage.Header{}, errNoAnswerFromDNSServer
   203  }
   204  
   205  // checkHeader performs basic sanity checks on the header.
   206  func checkHeader(p *dnsmessage.Parser, h dnsmessage.Header) error {
   207  	if h.RCode == dnsmessage.RCodeNameError {
   208  		return errNoSuchHost
   209  	}
   210  
   211  	_, err := p.AnswerHeader()
   212  	if err != nil && err != dnsmessage.ErrSectionDone {
   213  		return errCannotUnmarshalDNSMessage
   214  	}
   215  
   216  	// libresolv continues to the next server when it receives
   217  	// an invalid referral response. See golang.org/issue/15434.
   218  	if h.RCode == dnsmessage.RCodeSuccess && !h.Authoritative && !h.RecursionAvailable && err == dnsmessage.ErrSectionDone {
   219  		return errLameReferral
   220  	}
   221  
   222  	if h.RCode != dnsmessage.RCodeSuccess && h.RCode != dnsmessage.RCodeNameError {
   223  		// None of the error codes make sense
   224  		// for the query we sent. If we didn't get
   225  		// a name error and we didn't get success,
   226  		// the server is behaving incorrectly or
   227  		// having temporary trouble.
   228  		if h.RCode == dnsmessage.RCodeServerFailure {
   229  			return errServerTemporarilyMisbehaving
   230  		}
   231  		return errServerMisbehaving
   232  	}
   233  
   234  	return nil
   235  }
   236  
   237  func skipToAnswer(p *dnsmessage.Parser, qtype dnsmessage.Type) error {
   238  	for {
   239  		h, err := p.AnswerHeader()
   240  		if err == dnsmessage.ErrSectionDone {
   241  			return errNoSuchHost
   242  		}
   243  		if err != nil {
   244  			return errCannotUnmarshalDNSMessage
   245  		}
   246  		if h.Type == qtype {
   247  			return nil
   248  		}
   249  		if err := p.SkipAnswer(); err != nil {
   250  			return errCannotUnmarshalDNSMessage
   251  		}
   252  	}
   253  }
   254  
   255  // Do a lookup for a single name, which must be rooted
   256  // (otherwise answer will not find the answers).
   257  func (r *Resolver) tryOneName(ctx context.Context, cfg *dnsConfig, name string, qtype dnsmessage.Type) (dnsmessage.Parser, string, error) {
   258  	var lastErr error
   259  	serverOffset := cfg.serverOffset()
   260  	sLen := uint32(len(cfg.servers))
   261  
   262  	n, err := dnsmessage.NewName(name)
   263  	if err != nil {
   264  		return dnsmessage.Parser{}, "", errCannotMarshalDNSMessage
   265  	}
   266  	q := dnsmessage.Question{
   267  		Name:  n,
   268  		Type:  qtype,
   269  		Class: dnsmessage.ClassINET,
   270  	}
   271  
   272  	for i := 0; i < cfg.attempts; i++ {
   273  		for j := uint32(0); j < sLen; j++ {
   274  			server := cfg.servers[(serverOffset+j)%sLen]
   275  
   276  			p, h, err := r.exchange(ctx, server, q, cfg.timeout, cfg.useTCP, cfg.trustAD)
   277  			if err != nil {
   278  				dnsErr := &DNSError{
   279  					Err:    err.Error(),
   280  					Name:   name,
   281  					Server: server,
   282  				}
   283  				if nerr, ok := err.(Error); ok && nerr.Timeout() {
   284  					dnsErr.IsTimeout = true
   285  				}
   286  				// Set IsTemporary for socket-level errors. Note that this flag
   287  				// may also be used to indicate a SERVFAIL response.
   288  				if _, ok := err.(*OpError); ok {
   289  					dnsErr.IsTemporary = true
   290  				}
   291  				lastErr = dnsErr
   292  				continue
   293  			}
   294  
   295  			if err := checkHeader(&p, h); err != nil {
   296  				dnsErr := &DNSError{
   297  					Err:    err.Error(),
   298  					Name:   name,
   299  					Server: server,
   300  				}
   301  				if err == errServerTemporarilyMisbehaving {
   302  					dnsErr.IsTemporary = true
   303  				}
   304  				if err == errNoSuchHost {
   305  					// The name does not exist, so trying
   306  					// another server won't help.
   307  
   308  					dnsErr.IsNotFound = true
   309  					return p, server, dnsErr
   310  				}
   311  				lastErr = dnsErr
   312  				continue
   313  			}
   314  
   315  			err = skipToAnswer(&p, qtype)
   316  			if err == nil {
   317  				return p, server, nil
   318  			}
   319  			lastErr = &DNSError{
   320  				Err:    err.Error(),
   321  				Name:   name,
   322  				Server: server,
   323  			}
   324  			if err == errNoSuchHost {
   325  				// The name does not exist, so trying another
   326  				// server won't help.
   327  
   328  				lastErr.(*DNSError).IsNotFound = true
   329  				return p, server, lastErr
   330  			}
   331  		}
   332  	}
   333  	return dnsmessage.Parser{}, "", lastErr
   334  }
   335  
   336  // A resolverConfig represents a DNS stub resolver configuration.
   337  type resolverConfig struct {
   338  	initOnce sync.Once // guards init of resolverConfig
   339  
   340  	// ch is used as a semaphore that only allows one lookup at a
   341  	// time to recheck resolv.conf.
   342  	ch          chan struct{} // guards lastChecked and modTime
   343  	lastChecked time.Time     // last time resolv.conf was checked
   344  
   345  	mu        sync.RWMutex // protects dnsConfig
   346  	dnsConfig *dnsConfig   // parsed resolv.conf structure used in lookups
   347  }
   348  
   349  var resolvConf resolverConfig
   350  
   351  // init initializes conf and is only called via conf.initOnce.
   352  func (conf *resolverConfig) init() {
   353  	// Set dnsConfig and lastChecked so we don't parse
   354  	// resolv.conf twice the first time.
   355  	conf.dnsConfig = systemConf().resolv
   356  	if conf.dnsConfig == nil {
   357  		conf.dnsConfig = dnsReadConfig("/etc/resolv.conf")
   358  	}
   359  	conf.lastChecked = time.Now()
   360  
   361  	// Prepare ch so that only one update of resolverConfig may
   362  	// run at once.
   363  	conf.ch = make(chan struct{}, 1)
   364  }
   365  
   366  // tryUpdate tries to update conf with the named resolv.conf file.
   367  // The name variable only exists for testing. It is otherwise always
   368  // "/etc/resolv.conf".
   369  func (conf *resolverConfig) tryUpdate(name string) {
   370  	conf.initOnce.Do(conf.init)
   371  
   372  	// Ensure only one update at a time checks resolv.conf.
   373  	if !conf.tryAcquireSema() {
   374  		return
   375  	}
   376  	defer conf.releaseSema()
   377  
   378  	now := time.Now()
   379  	if conf.lastChecked.After(now.Add(-5 * time.Second)) {
   380  		return
   381  	}
   382  	conf.lastChecked = now
   383  
   384  	switch runtime.GOOS {
   385  	case "windows":
   386  		// There's no file on disk, so don't bother checking
   387  		// and failing.
   388  		//
   389  		// The Windows implementation of dnsReadConfig (called
   390  		// below) ignores the name.
   391  	default:
   392  		var mtime time.Time
   393  		if fi, err := os.Stat(name); err == nil {
   394  			mtime = fi.ModTime()
   395  		}
   396  		if mtime.Equal(conf.dnsConfig.mtime) {
   397  			return
   398  		}
   399  	}
   400  
   401  	dnsConf := dnsReadConfig(name)
   402  	conf.mu.Lock()
   403  	conf.dnsConfig = dnsConf
   404  	conf.mu.Unlock()
   405  }
   406  
   407  func (conf *resolverConfig) tryAcquireSema() bool {
   408  	select {
   409  	case conf.ch <- struct{}{}:
   410  		return true
   411  	default:
   412  		return false
   413  	}
   414  }
   415  
   416  func (conf *resolverConfig) releaseSema() {
   417  	<-conf.ch
   418  }
   419  
   420  func (r *Resolver) lookup(ctx context.Context, name string, qtype dnsmessage.Type) (dnsmessage.Parser, string, error) {
   421  	if !isDomainName(name) {
   422  		// We used to use "invalid domain name" as the error,
   423  		// but that is a detail of the specific lookup mechanism.
   424  		// Other lookups might allow broader name syntax
   425  		// (for example Multicast DNS allows UTF-8; see RFC 6762).
   426  		// For consistency with libc resolvers, report no such host.
   427  		return dnsmessage.Parser{}, "", &DNSError{Err: errNoSuchHost.Error(), Name: name, IsNotFound: true}
   428  	}
   429  	resolvConf.tryUpdate("/etc/resolv.conf")
   430  	resolvConf.mu.RLock()
   431  	conf := resolvConf.dnsConfig
   432  	resolvConf.mu.RUnlock()
   433  	var (
   434  		p      dnsmessage.Parser
   435  		server string
   436  		err    error
   437  	)
   438  	for _, fqdn := range conf.nameList(name) {
   439  		p, server, err = r.tryOneName(ctx, conf, fqdn, qtype)
   440  		if err == nil {
   441  			break
   442  		}
   443  		if nerr, ok := err.(Error); ok && nerr.Temporary() && r.strictErrors() {
   444  			// If we hit a temporary error with StrictErrors enabled,
   445  			// stop immediately instead of trying more names.
   446  			break
   447  		}
   448  	}
   449  	if err == nil {
   450  		return p, server, nil
   451  	}
   452  	if err, ok := err.(*DNSError); ok {
   453  		// Show original name passed to lookup, not suffixed one.
   454  		// In general we might have tried many suffixes; showing
   455  		// just one is misleading. See also golang.org/issue/6324.
   456  		err.Name = name
   457  	}
   458  	return dnsmessage.Parser{}, "", err
   459  }
   460  
   461  // avoidDNS reports whether this is a hostname for which we should not
   462  // use DNS. Currently this includes only .onion, per RFC 7686. See
   463  // golang.org/issue/13705. Does not cover .local names (RFC 6762),
   464  // see golang.org/issue/16739.
   465  func avoidDNS(name string) bool {
   466  	if name == "" {
   467  		return true
   468  	}
   469  	if name[len(name)-1] == '.' {
   470  		name = name[:len(name)-1]
   471  	}
   472  	return stringsHasSuffixFold(name, ".onion")
   473  }
   474  
   475  // nameList returns a list of names for sequential DNS queries.
   476  func (conf *dnsConfig) nameList(name string) []string {
   477  	if avoidDNS(name) {
   478  		return nil
   479  	}
   480  
   481  	// Check name length (see isDomainName).
   482  	l := len(name)
   483  	rooted := l > 0 && name[l-1] == '.'
   484  	if l > 254 || l == 254 && !rooted {
   485  		return nil
   486  	}
   487  
   488  	// If name is rooted (trailing dot), try only that name.
   489  	if rooted {
   490  		return []string{name}
   491  	}
   492  
   493  	hasNdots := count(name, '.') >= conf.ndots
   494  	name += "."
   495  	l++
   496  
   497  	// Build list of search choices.
   498  	names := make([]string, 0, 1+len(conf.search))
   499  	// If name has enough dots, try unsuffixed first.
   500  	if hasNdots {
   501  		names = append(names, name)
   502  	}
   503  	// Try suffixes that are not too long (see isDomainName).
   504  	for _, suffix := range conf.search {
   505  		if l+len(suffix) <= 254 {
   506  			names = append(names, name+suffix)
   507  		}
   508  	}
   509  	// Try unsuffixed, if not tried first above.
   510  	if !hasNdots {
   511  		names = append(names, name)
   512  	}
   513  	return names
   514  }
   515  
   516  // hostLookupOrder specifies the order of LookupHost lookup strategies.
   517  // It is basically a simplified representation of nsswitch.conf.
   518  // "files" means /etc/hosts.
   519  type hostLookupOrder int
   520  
   521  const (
   522  	// hostLookupCgo means defer to cgo.
   523  	hostLookupCgo      hostLookupOrder = iota
   524  	hostLookupFilesDNS                 // files first
   525  	hostLookupDNSFiles                 // dns first
   526  	hostLookupFiles                    // only files
   527  	hostLookupDNS                      // only DNS
   528  )
   529  
   530  var lookupOrderName = map[hostLookupOrder]string{
   531  	hostLookupCgo:      "cgo",
   532  	hostLookupFilesDNS: "files,dns",
   533  	hostLookupDNSFiles: "dns,files",
   534  	hostLookupFiles:    "files",
   535  	hostLookupDNS:      "dns",
   536  }
   537  
   538  func (o hostLookupOrder) String() string {
   539  	if s, ok := lookupOrderName[o]; ok {
   540  		return s
   541  	}
   542  	return "hostLookupOrder=" + itoa.Itoa(int(o)) + "??"
   543  }
   544  
   545  // goLookupHost is the native Go implementation of LookupHost.
   546  // Used only if cgoLookupHost refuses to handle the request
   547  // (that is, only if cgoLookupHost is the stub in cgo_stub.go).
   548  // Normally we let cgo use the C library resolver instead of
   549  // depending on our lookup code, so that Go and C get the same
   550  // answers.
   551  func (r *Resolver) goLookupHost(ctx context.Context, name string) (addrs []string, err error) {
   552  	return r.goLookupHostOrder(ctx, name, hostLookupFilesDNS)
   553  }
   554  
   555  func (r *Resolver) goLookupHostOrder(ctx context.Context, name string, order hostLookupOrder) (addrs []string, err error) {
   556  	if order == hostLookupFilesDNS || order == hostLookupFiles {
   557  		// Use entries from /etc/hosts if they match.
   558  		addrs = lookupStaticHost(name)
   559  		if len(addrs) > 0 || order == hostLookupFiles {
   560  			return
   561  		}
   562  	}
   563  	ips, _, err := r.goLookupIPCNAMEOrder(ctx, "ip", name, order)
   564  	if err != nil {
   565  		return
   566  	}
   567  	addrs = make([]string, 0, len(ips))
   568  	for _, ip := range ips {
   569  		addrs = append(addrs, ip.String())
   570  	}
   571  	return
   572  }
   573  
   574  // lookup entries from /etc/hosts
   575  func goLookupIPFiles(name string) (addrs []IPAddr) {
   576  	for _, haddr := range lookupStaticHost(name) {
   577  		haddr, zone := splitHostZone(haddr)
   578  		if ip := ParseIP(haddr); ip != nil {
   579  			addr := IPAddr{IP: ip, Zone: zone}
   580  			addrs = append(addrs, addr)
   581  		}
   582  	}
   583  	sortByRFC6724(addrs)
   584  	return
   585  }
   586  
   587  // goLookupIP is the native Go implementation of LookupIP.
   588  // The libc versions are in cgo_*.go.
   589  func (r *Resolver) goLookupIP(ctx context.Context, network, host string) (addrs []IPAddr, err error) {
   590  	order := systemConf().hostLookupOrder(r, host)
   591  	addrs, _, err = r.goLookupIPCNAMEOrder(ctx, network, host, order)
   592  	return
   593  }
   594  
   595  func (r *Resolver) goLookupIPCNAMEOrder(ctx context.Context, network, name string, order hostLookupOrder) (addrs []IPAddr, cname dnsmessage.Name, err error) {
   596  	if order == hostLookupFilesDNS || order == hostLookupFiles {
   597  		addrs = goLookupIPFiles(name)
   598  		if len(addrs) > 0 || order == hostLookupFiles {
   599  			return addrs, dnsmessage.Name{}, nil
   600  		}
   601  	}
   602  	if !isDomainName(name) {
   603  		// See comment in func lookup above about use of errNoSuchHost.
   604  		return nil, dnsmessage.Name{}, &DNSError{Err: errNoSuchHost.Error(), Name: name, IsNotFound: true}
   605  	}
   606  	resolvConf.tryUpdate("/etc/resolv.conf")
   607  	resolvConf.mu.RLock()
   608  	conf := resolvConf.dnsConfig
   609  	resolvConf.mu.RUnlock()
   610  	type result struct {
   611  		p      dnsmessage.Parser
   612  		server string
   613  		error
   614  	}
   615  	lane := make(chan result, 1)
   616  	qtypes := []dnsmessage.Type{dnsmessage.TypeA, dnsmessage.TypeAAAA}
   617  	switch ipVersion(network) {
   618  	case '4':
   619  		qtypes = []dnsmessage.Type{dnsmessage.TypeA}
   620  	case '6':
   621  		qtypes = []dnsmessage.Type{dnsmessage.TypeAAAA}
   622  	}
   623  	var queryFn func(fqdn string, qtype dnsmessage.Type)
   624  	var responseFn func(fqdn string, qtype dnsmessage.Type) result
   625  	if conf.singleRequest {
   626  		queryFn = func(fqdn string, qtype dnsmessage.Type) {}
   627  		responseFn = func(fqdn string, qtype dnsmessage.Type) result {
   628  			dnsWaitGroup.Add(1)
   629  			defer dnsWaitGroup.Done()
   630  			p, server, err := r.tryOneName(ctx, conf, fqdn, qtype)
   631  			return result{p, server, err}
   632  		}
   633  	} else {
   634  		queryFn = func(fqdn string, qtype dnsmessage.Type) {
   635  			dnsWaitGroup.Add(1)
   636  			go func(qtype dnsmessage.Type) {
   637  				p, server, err := r.tryOneName(ctx, conf, fqdn, qtype)
   638  				lane <- result{p, server, err}
   639  				dnsWaitGroup.Done()
   640  			}(qtype)
   641  		}
   642  		responseFn = func(fqdn string, qtype dnsmessage.Type) result {
   643  			return <-lane
   644  		}
   645  	}
   646  	var lastErr error
   647  	for _, fqdn := range conf.nameList(name) {
   648  		for _, qtype := range qtypes {
   649  			queryFn(fqdn, qtype)
   650  		}
   651  		hitStrictError := false
   652  		for _, qtype := range qtypes {
   653  			result := responseFn(fqdn, qtype)
   654  			if result.error != nil {
   655  				if nerr, ok := result.error.(Error); ok && nerr.Temporary() && r.strictErrors() {
   656  					// This error will abort the nameList loop.
   657  					hitStrictError = true
   658  					lastErr = result.error
   659  				} else if lastErr == nil || fqdn == name+"." {
   660  					// Prefer error for original name.
   661  					lastErr = result.error
   662  				}
   663  				continue
   664  			}
   665  
   666  			// Presotto says it's okay to assume that servers listed in
   667  			// /etc/resolv.conf are recursive resolvers.
   668  			//
   669  			// We asked for recursion, so it should have included all the
   670  			// answers we need in this one packet.
   671  			//
   672  			// Further, RFC 1034 section 4.3.1 says that "the recursive
   673  			// response to a query will be... The answer to the query,
   674  			// possibly preface by one or more CNAME RRs that specify
   675  			// aliases encountered on the way to an answer."
   676  			//
   677  			// Therefore, we should be able to assume that we can ignore
   678  			// CNAMEs and that the A and AAAA records we requested are
   679  			// for the canonical name.
   680  
   681  		loop:
   682  			for {
   683  				h, err := result.p.AnswerHeader()
   684  				if err != nil && err != dnsmessage.ErrSectionDone {
   685  					lastErr = &DNSError{
   686  						Err:    "cannot marshal DNS message",
   687  						Name:   name,
   688  						Server: result.server,
   689  					}
   690  				}
   691  				if err != nil {
   692  					break
   693  				}
   694  				switch h.Type {
   695  				case dnsmessage.TypeA:
   696  					a, err := result.p.AResource()
   697  					if err != nil {
   698  						lastErr = &DNSError{
   699  							Err:    "cannot marshal DNS message",
   700  							Name:   name,
   701  							Server: result.server,
   702  						}
   703  						break loop
   704  					}
   705  					addrs = append(addrs, IPAddr{IP: IP(a.A[:])})
   706  
   707  				case dnsmessage.TypeAAAA:
   708  					aaaa, err := result.p.AAAAResource()
   709  					if err != nil {
   710  						lastErr = &DNSError{
   711  							Err:    "cannot marshal DNS message",
   712  							Name:   name,
   713  							Server: result.server,
   714  						}
   715  						break loop
   716  					}
   717  					addrs = append(addrs, IPAddr{IP: IP(aaaa.AAAA[:])})
   718  
   719  				default:
   720  					if err := result.p.SkipAnswer(); err != nil {
   721  						lastErr = &DNSError{
   722  							Err:    "cannot marshal DNS message",
   723  							Name:   name,
   724  							Server: result.server,
   725  						}
   726  						break loop
   727  					}
   728  					continue
   729  				}
   730  				if cname.Length == 0 && h.Name.Length != 0 {
   731  					cname = h.Name
   732  				}
   733  			}
   734  		}
   735  		if hitStrictError {
   736  			// If either family hit an error with StrictErrors enabled,
   737  			// discard all addresses. This ensures that network flakiness
   738  			// cannot turn a dualstack hostname IPv4/IPv6-only.
   739  			addrs = nil
   740  			break
   741  		}
   742  		if len(addrs) > 0 {
   743  			break
   744  		}
   745  	}
   746  	if lastErr, ok := lastErr.(*DNSError); ok {
   747  		// Show original name passed to lookup, not suffixed one.
   748  		// In general we might have tried many suffixes; showing
   749  		// just one is misleading. See also golang.org/issue/6324.
   750  		lastErr.Name = name
   751  	}
   752  	sortByRFC6724(addrs)
   753  	if len(addrs) == 0 {
   754  		if order == hostLookupDNSFiles {
   755  			addrs = goLookupIPFiles(name)
   756  		}
   757  		if len(addrs) == 0 && lastErr != nil {
   758  			return nil, dnsmessage.Name{}, lastErr
   759  		}
   760  	}
   761  	return addrs, cname, nil
   762  }
   763  
   764  // goLookupCNAME is the native Go (non-cgo) implementation of LookupCNAME.
   765  func (r *Resolver) goLookupCNAME(ctx context.Context, host string) (string, error) {
   766  	order := systemConf().hostLookupOrder(r, host)
   767  	_, cname, err := r.goLookupIPCNAMEOrder(ctx, "ip", host, order)
   768  	return cname.String(), err
   769  }
   770  
   771  // goLookupPTR is the native Go implementation of LookupAddr.
   772  // Used only if cgoLookupPTR refuses to handle the request (that is,
   773  // only if cgoLookupPTR is the stub in cgo_stub.go).
   774  // Normally we let cgo use the C library resolver instead of depending
   775  // on our lookup code, so that Go and C get the same answers.
   776  func (r *Resolver) goLookupPTR(ctx context.Context, addr string) ([]string, error) {
   777  	names := lookupStaticAddr(addr)
   778  	if len(names) > 0 {
   779  		return names, nil
   780  	}
   781  	arpa, err := reverseaddr(addr)
   782  	if err != nil {
   783  		return nil, err
   784  	}
   785  	p, server, err := r.lookup(ctx, arpa, dnsmessage.TypePTR)
   786  	if err != nil {
   787  		return nil, err
   788  	}
   789  	var ptrs []string
   790  	for {
   791  		h, err := p.AnswerHeader()
   792  		if err == dnsmessage.ErrSectionDone {
   793  			break
   794  		}
   795  		if err != nil {
   796  			return nil, &DNSError{
   797  				Err:    "cannot marshal DNS message",
   798  				Name:   addr,
   799  				Server: server,
   800  			}
   801  		}
   802  		if h.Type != dnsmessage.TypePTR {
   803  			err := p.SkipAnswer()
   804  			if err != nil {
   805  				return nil, &DNSError{
   806  					Err:    "cannot marshal DNS message",
   807  					Name:   addr,
   808  					Server: server,
   809  				}
   810  			}
   811  			continue
   812  		}
   813  		ptr, err := p.PTRResource()
   814  		if err != nil {
   815  			return nil, &DNSError{
   816  				Err:    "cannot marshal DNS message",
   817  				Name:   addr,
   818  				Server: server,
   819  			}
   820  		}
   821  		ptrs = append(ptrs, ptr.PTR.String())
   822  
   823  	}
   824  	return ptrs, nil
   825  }