dnsclient_unix.mx raw

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