Source file src/net/lookup.go

     1  // Copyright 2012 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  package net
     6  
     7  import (
     8  	"context"
     9  	"errors"
    10  	"internal/nettrace"
    11  	"internal/singleflight"
    12  	"net/netip"
    13  	"sync"
    14  
    15  	"golang.org/x/net/dns/dnsmessage"
    16  )
    17  
    18  // protocols contains minimal mappings between internet protocol
    19  // names and numbers for platforms that don't have a complete list of
    20  // protocol numbers.
    21  //
    22  // See https://www.iana.org/assignments/protocol-numbers
    23  //
    24  // On Unix, this map is augmented by readProtocols via lookupProtocol.
    25  var protocols = map[string]int{
    26  	"icmp":      1,
    27  	"igmp":      2,
    28  	"tcp":       6,
    29  	"udp":       17,
    30  	"ipv6-icmp": 58,
    31  }
    32  
    33  // services contains minimal mappings between services names and port
    34  // numbers for platforms that don't have a complete list of port numbers.
    35  //
    36  // See https://www.iana.org/assignments/service-names-port-numbers
    37  //
    38  // On Unix, this map is augmented by readServices via goLookupPort.
    39  var services = map[string]map[string]int{
    40  	"udp": {
    41  		"domain": 53,
    42  	},
    43  	"tcp": {
    44  		"ftp":    21,
    45  		"ftps":   990,
    46  		"gopher": 70, // ʕ◔ϖ◔ʔ
    47  		"http":   80,
    48  		"https":  443,
    49  		"imap2":  143,
    50  		"imap3":  220,
    51  		"imaps":  993,
    52  		"pop3":   110,
    53  		"pop3s":  995,
    54  		"smtp":   25,
    55  		"ssh":    22,
    56  		"telnet": 23,
    57  	},
    58  }
    59  
    60  // dnsWaitGroup can be used by tests to wait for all DNS goroutines to
    61  // complete. This avoids races on the test hooks.
    62  var dnsWaitGroup sync.WaitGroup
    63  
    64  const maxProtoLength = len("RSVP-E2E-IGNORE") + 10 // with room to grow
    65  
    66  func lookupProtocolMap(name string) (int, error) {
    67  	var lowerProtocol [maxProtoLength]byte
    68  	n := copy(lowerProtocol[:], name)
    69  	lowerASCIIBytes(lowerProtocol[:n])
    70  	proto, found := protocols[string(lowerProtocol[:n])]
    71  	if !found || n != len(name) {
    72  		return 0, &AddrError{Err: "unknown IP protocol specified", Addr: name}
    73  	}
    74  	return proto, nil
    75  }
    76  
    77  // maxPortBufSize is the longest reasonable name of a service
    78  // (non-numeric port).
    79  // Currently the longest known IANA-unregistered name is
    80  // "mobility-header", so we use that length, plus some slop in case
    81  // something longer is added in the future.
    82  const maxPortBufSize = len("mobility-header") + 10
    83  
    84  func lookupPortMap(network, service string) (port int, error error) {
    85  	switch network {
    86  	case "tcp4", "tcp6":
    87  		network = "tcp"
    88  	case "udp4", "udp6":
    89  		network = "udp"
    90  	}
    91  
    92  	if m, ok := services[network]; ok {
    93  		var lowerService [maxPortBufSize]byte
    94  		n := copy(lowerService[:], service)
    95  		lowerASCIIBytes(lowerService[:n])
    96  		if port, ok := m[string(lowerService[:n])]; ok && n == len(service) {
    97  			return port, nil
    98  		}
    99  	}
   100  	return 0, &AddrError{Err: "unknown port", Addr: network + "/" + service}
   101  }
   102  
   103  // ipVersion returns the provided network's IP version: '4', '6' or 0
   104  // if network does not end in a '4' or '6' byte.
   105  func ipVersion(network string) byte {
   106  	if network == "" {
   107  		return 0
   108  	}
   109  	n := network[len(network)-1]
   110  	if n != '4' && n != '6' {
   111  		n = 0
   112  	}
   113  	return n
   114  }
   115  
   116  // DefaultResolver is the resolver used by the package-level Lookup
   117  // functions and by Dialers without a specified Resolver.
   118  var DefaultResolver = &Resolver{}
   119  
   120  // A Resolver looks up names and numbers.
   121  //
   122  // A nil *Resolver is equivalent to a zero Resolver.
   123  type Resolver struct {
   124  	// PreferGo controls whether Go's built-in DNS resolver is preferred
   125  	// on platforms where it's available. It is equivalent to setting
   126  	// GODEBUG=netdns=go, but scoped to just this resolver.
   127  	PreferGo bool
   128  
   129  	// StrictErrors controls the behavior of temporary errors
   130  	// (including timeout, socket errors, and SERVFAIL) when using
   131  	// Go's built-in resolver. For a query composed of multiple
   132  	// sub-queries (such as an A+AAAA address lookup, or walking the
   133  	// DNS search list), this option causes such errors to abort the
   134  	// whole query instead of returning a partial result. This is
   135  	// not enabled by default because it may affect compatibility
   136  	// with resolvers that process AAAA queries incorrectly.
   137  	StrictErrors bool
   138  
   139  	// Dial optionally specifies an alternate dialer for use by
   140  	// Go's built-in DNS resolver to make TCP and UDP connections
   141  	// to DNS services. The host in the address parameter will
   142  	// always be a literal IP address and not a host name, and the
   143  	// port in the address parameter will be a literal port number
   144  	// and not a service name.
   145  	// If the Conn returned is also a PacketConn, sent and received DNS
   146  	// messages must adhere to RFC 1035 section 4.2.1, "UDP usage".
   147  	// Otherwise, DNS messages transmitted over Conn must adhere
   148  	// to RFC 7766 section 5, "Transport Protocol Selection".
   149  	// If nil, the default dialer is used.
   150  	Dial func(ctx context.Context, network, address string) (Conn, error)
   151  
   152  	// lookupGroup merges LookupIPAddr calls together for lookups for the same
   153  	// host. The lookupGroup key is the LookupIPAddr.host argument.
   154  	// The return values are ([]IPAddr, error).
   155  	lookupGroup singleflight.Group
   156  
   157  	// TODO(bradfitz): optional interface impl override hook
   158  	// TODO(bradfitz): Timeout time.Duration?
   159  }
   160  
   161  func (r *Resolver) preferGo() bool     { return r != nil && r.PreferGo }
   162  func (r *Resolver) strictErrors() bool { return r != nil && r.StrictErrors }
   163  
   164  func (r *Resolver) getLookupGroup() *singleflight.Group {
   165  	if r == nil {
   166  		return &DefaultResolver.lookupGroup
   167  	}
   168  	return &r.lookupGroup
   169  }
   170  
   171  // LookupHost looks up the given host using the local resolver.
   172  // It returns a slice of that host's addresses.
   173  //
   174  // LookupHost uses context.Background internally; to specify the context, use
   175  // Resolver.LookupHost.
   176  func LookupHost(host string) (addrs []string, err error) {
   177  	return DefaultResolver.LookupHost(context.Background(), host)
   178  }
   179  
   180  // LookupHost looks up the given host using the local resolver.
   181  // It returns a slice of that host's addresses.
   182  func (r *Resolver) LookupHost(ctx context.Context, host string) (addrs []string, err error) {
   183  	// Make sure that no matter what we do later, host=="" is rejected.
   184  	// parseIP, for example, does accept empty strings.
   185  	if host == "" {
   186  		return nil, &DNSError{Err: errNoSuchHost.Error(), Name: host, IsNotFound: true}
   187  	}
   188  	if ip, _ := parseIPZone(host); ip != nil {
   189  		return []string{host}, nil
   190  	}
   191  	return r.lookupHost(ctx, host)
   192  }
   193  
   194  // LookupIP looks up host using the local resolver.
   195  // It returns a slice of that host's IPv4 and IPv6 addresses.
   196  func LookupIP(host string) ([]IP, error) {
   197  	addrs, err := DefaultResolver.LookupIPAddr(context.Background(), host)
   198  	if err != nil {
   199  		return nil, err
   200  	}
   201  	ips := make([]IP, len(addrs))
   202  	for i, ia := range addrs {
   203  		ips[i] = ia.IP
   204  	}
   205  	return ips, nil
   206  }
   207  
   208  // LookupIPAddr looks up host using the local resolver.
   209  // It returns a slice of that host's IPv4 and IPv6 addresses.
   210  func (r *Resolver) LookupIPAddr(ctx context.Context, host string) ([]IPAddr, error) {
   211  	return r.lookupIPAddr(ctx, "ip", host)
   212  }
   213  
   214  // LookupIP looks up host for the given network using the local resolver.
   215  // It returns a slice of that host's IP addresses of the type specified by
   216  // network.
   217  // network must be one of "ip", "ip4" or "ip6".
   218  func (r *Resolver) LookupIP(ctx context.Context, network, host string) ([]IP, error) {
   219  	afnet, _, err := parseNetwork(ctx, network, false)
   220  	if err != nil {
   221  		return nil, err
   222  	}
   223  	switch afnet {
   224  	case "ip", "ip4", "ip6":
   225  	default:
   226  		return nil, UnknownNetworkError(network)
   227  	}
   228  
   229  	if host == "" {
   230  		return nil, &DNSError{Err: errNoSuchHost.Error(), Name: host, IsNotFound: true}
   231  	}
   232  	addrs, err := r.internetAddrList(ctx, afnet, host)
   233  	if err != nil {
   234  		return nil, err
   235  	}
   236  
   237  	ips := make([]IP, 0, len(addrs))
   238  	for _, addr := range addrs {
   239  		ips = append(ips, addr.(*IPAddr).IP)
   240  	}
   241  	return ips, nil
   242  }
   243  
   244  // LookupNetIP looks up host using the local resolver.
   245  // It returns a slice of that host's IP addresses of the type specified by
   246  // network.
   247  // The network must be one of "ip", "ip4" or "ip6".
   248  func (r *Resolver) LookupNetIP(ctx context.Context, network, host string) ([]netip.Addr, error) {
   249  	// TODO(bradfitz): make this efficient, making the internal net package
   250  	// type throughout be netip.Addr and only converting to the net.IP slice
   251  	// version at the edge. But for now (2021-10-20), this is a wrapper around
   252  	// the old way.
   253  	ips, err := r.LookupIP(ctx, network, host)
   254  	if err != nil {
   255  		return nil, err
   256  	}
   257  	ret := make([]netip.Addr, 0, len(ips))
   258  	for _, ip := range ips {
   259  		if a, ok := netip.AddrFromSlice(ip); ok {
   260  			ret = append(ret, a)
   261  		}
   262  	}
   263  	return ret, nil
   264  }
   265  
   266  // onlyValuesCtx is a context that uses an underlying context
   267  // for value lookup if the underlying context hasn't yet expired.
   268  type onlyValuesCtx struct {
   269  	context.Context
   270  	lookupValues context.Context
   271  }
   272  
   273  var _ context.Context = (*onlyValuesCtx)(nil)
   274  
   275  // Value performs a lookup if the original context hasn't expired.
   276  func (ovc *onlyValuesCtx) Value(key any) any {
   277  	select {
   278  	case <-ovc.lookupValues.Done():
   279  		return nil
   280  	default:
   281  		return ovc.lookupValues.Value(key)
   282  	}
   283  }
   284  
   285  // withUnexpiredValuesPreserved returns a context.Context that only uses lookupCtx
   286  // for its values, otherwise it is never canceled and has no deadline.
   287  // If the lookup context expires, any looked up values will return nil.
   288  // See Issue 28600.
   289  func withUnexpiredValuesPreserved(lookupCtx context.Context) context.Context {
   290  	return &onlyValuesCtx{Context: context.Background(), lookupValues: lookupCtx}
   291  }
   292  
   293  // lookupIPAddr looks up host using the local resolver and particular network.
   294  // It returns a slice of that host's IPv4 and IPv6 addresses.
   295  func (r *Resolver) lookupIPAddr(ctx context.Context, network, host string) ([]IPAddr, error) {
   296  	// Make sure that no matter what we do later, host=="" is rejected.
   297  	// parseIPZone, for example, does accept empty strings.
   298  	if host == "" {
   299  		return nil, &DNSError{Err: errNoSuchHost.Error(), Name: host, IsNotFound: true}
   300  	}
   301  	if ip, zone := parseIPZone(host); ip != nil {
   302  		return []IPAddr{{IP: ip, Zone: zone}}, nil
   303  	}
   304  	trace, _ := ctx.Value(nettrace.TraceKey{}).(*nettrace.Trace)
   305  	if trace != nil && trace.DNSStart != nil {
   306  		trace.DNSStart(host)
   307  	}
   308  	// The underlying resolver func is lookupIP by default but it
   309  	// can be overridden by tests. This is needed by net/http, so it
   310  	// uses a context key instead of unexported variables.
   311  	resolverFunc := r.lookupIP
   312  	if alt, _ := ctx.Value(nettrace.LookupIPAltResolverKey{}).(func(context.Context, string, string) ([]IPAddr, error)); alt != nil {
   313  		resolverFunc = alt
   314  	}
   315  
   316  	// We don't want a cancellation of ctx to affect the
   317  	// lookupGroup operation. Otherwise if our context gets
   318  	// canceled it might cause an error to be returned to a lookup
   319  	// using a completely different context. However we need to preserve
   320  	// only the values in context. See Issue 28600.
   321  	lookupGroupCtx, lookupGroupCancel := context.WithCancel(withUnexpiredValuesPreserved(ctx))
   322  
   323  	lookupKey := network + "\000" + host
   324  	dnsWaitGroup.Add(1)
   325  	ch := r.getLookupGroup().DoChan(lookupKey, func() (any, error) {
   326  		return testHookLookupIP(lookupGroupCtx, resolverFunc, network, host)
   327  	})
   328  
   329  	dnsWaitGroupDone := func(ch <-chan singleflight.Result, cancelFn context.CancelFunc) {
   330  		<-ch
   331  		dnsWaitGroup.Done()
   332  		cancelFn()
   333  	}
   334  	select {
   335  	case <-ctx.Done():
   336  		// Our context was canceled. If we are the only
   337  		// goroutine looking up this key, then drop the key
   338  		// from the lookupGroup and cancel the lookup.
   339  		// If there are other goroutines looking up this key,
   340  		// let the lookup continue uncanceled, and let later
   341  		// lookups with the same key share the result.
   342  		// See issues 8602, 20703, 22724.
   343  		if r.getLookupGroup().ForgetUnshared(lookupKey) {
   344  			lookupGroupCancel()
   345  			go dnsWaitGroupDone(ch, func() {})
   346  		} else {
   347  			go dnsWaitGroupDone(ch, lookupGroupCancel)
   348  		}
   349  		ctxErr := ctx.Err()
   350  		err := &DNSError{
   351  			Err:       mapErr(ctxErr).Error(),
   352  			Name:      host,
   353  			IsTimeout: ctxErr == context.DeadlineExceeded,
   354  		}
   355  		if trace != nil && trace.DNSDone != nil {
   356  			trace.DNSDone(nil, false, err)
   357  		}
   358  		return nil, err
   359  	case r := <-ch:
   360  		dnsWaitGroup.Done()
   361  		lookupGroupCancel()
   362  		err := r.Err
   363  		if err != nil {
   364  			if _, ok := err.(*DNSError); !ok {
   365  				isTimeout := false
   366  				if err == context.DeadlineExceeded {
   367  					isTimeout = true
   368  				} else if terr, ok := err.(timeout); ok {
   369  					isTimeout = terr.Timeout()
   370  				}
   371  				err = &DNSError{
   372  					Err:       err.Error(),
   373  					Name:      host,
   374  					IsTimeout: isTimeout,
   375  				}
   376  			}
   377  		}
   378  		if trace != nil && trace.DNSDone != nil {
   379  			addrs, _ := r.Val.([]IPAddr)
   380  			trace.DNSDone(ipAddrsEface(addrs), r.Shared, err)
   381  		}
   382  		return lookupIPReturn(r.Val, err, r.Shared)
   383  	}
   384  }
   385  
   386  // lookupIPReturn turns the return values from singleflight.Do into
   387  // the return values from LookupIP.
   388  func lookupIPReturn(addrsi any, err error, shared bool) ([]IPAddr, error) {
   389  	if err != nil {
   390  		return nil, err
   391  	}
   392  	addrs := addrsi.([]IPAddr)
   393  	if shared {
   394  		clone := make([]IPAddr, len(addrs))
   395  		copy(clone, addrs)
   396  		addrs = clone
   397  	}
   398  	return addrs, nil
   399  }
   400  
   401  // ipAddrsEface returns an empty interface slice of addrs.
   402  func ipAddrsEface(addrs []IPAddr) []any {
   403  	s := make([]any, len(addrs))
   404  	for i, v := range addrs {
   405  		s[i] = v
   406  	}
   407  	return s
   408  }
   409  
   410  // LookupPort looks up the port for the given network and service.
   411  //
   412  // LookupPort uses context.Background internally; to specify the context, use
   413  // Resolver.LookupPort.
   414  func LookupPort(network, service string) (port int, err error) {
   415  	return DefaultResolver.LookupPort(context.Background(), network, service)
   416  }
   417  
   418  // LookupPort looks up the port for the given network and service.
   419  func (r *Resolver) LookupPort(ctx context.Context, network, service string) (port int, err error) {
   420  	port, needsLookup := parsePort(service)
   421  	if needsLookup {
   422  		switch network {
   423  		case "tcp", "tcp4", "tcp6", "udp", "udp4", "udp6":
   424  		case "": // a hint wildcard for Go 1.0 undocumented behavior
   425  			network = "ip"
   426  		default:
   427  			return 0, &AddrError{Err: "unknown network", Addr: network}
   428  		}
   429  		port, err = r.lookupPort(ctx, network, service)
   430  		if err != nil {
   431  			return 0, err
   432  		}
   433  	}
   434  	if 0 > port || port > 65535 {
   435  		return 0, &AddrError{Err: "invalid port", Addr: service}
   436  	}
   437  	return port, nil
   438  }
   439  
   440  // LookupCNAME returns the canonical name for the given host.
   441  // Callers that do not care about the canonical name can call
   442  // LookupHost or LookupIP directly; both take care of resolving
   443  // the canonical name as part of the lookup.
   444  //
   445  // A canonical name is the final name after following zero
   446  // or more CNAME records.
   447  // LookupCNAME does not return an error if host does not
   448  // contain DNS "CNAME" records, as long as host resolves to
   449  // address records.
   450  //
   451  // The returned canonical name is validated to be a properly
   452  // formatted presentation-format domain name.
   453  //
   454  // LookupCNAME uses context.Background internally; to specify the context, use
   455  // Resolver.LookupCNAME.
   456  func LookupCNAME(host string) (cname string, err error) {
   457  	return DefaultResolver.LookupCNAME(context.Background(), host)
   458  }
   459  
   460  // LookupCNAME returns the canonical name for the given host.
   461  // Callers that do not care about the canonical name can call
   462  // LookupHost or LookupIP directly; both take care of resolving
   463  // the canonical name as part of the lookup.
   464  //
   465  // A canonical name is the final name after following zero
   466  // or more CNAME records.
   467  // LookupCNAME does not return an error if host does not
   468  // contain DNS "CNAME" records, as long as host resolves to
   469  // address records.
   470  //
   471  // The returned canonical name is validated to be a properly
   472  // formatted presentation-format domain name.
   473  func (r *Resolver) LookupCNAME(ctx context.Context, host string) (string, error) {
   474  	cname, err := r.lookupCNAME(ctx, host)
   475  	if err != nil {
   476  		return "", err
   477  	}
   478  	if !isDomainName(cname) {
   479  		return "", &DNSError{Err: errMalformedDNSRecordsDetail, Name: host}
   480  	}
   481  	return cname, nil
   482  }
   483  
   484  // LookupSRV tries to resolve an SRV query of the given service,
   485  // protocol, and domain name. The proto is "tcp" or "udp".
   486  // The returned records are sorted by priority and randomized
   487  // by weight within a priority.
   488  //
   489  // LookupSRV constructs the DNS name to look up following RFC 2782.
   490  // That is, it looks up _service._proto.name. To accommodate services
   491  // publishing SRV records under non-standard names, if both service
   492  // and proto are empty strings, LookupSRV looks up name directly.
   493  //
   494  // The returned service names are validated to be properly
   495  // formatted presentation-format domain names. If the response contains
   496  // invalid names, those records are filtered out and an error
   497  // will be returned alongside the remaining results, if any.
   498  func LookupSRV(service, proto, name string) (cname string, addrs []*SRV, err error) {
   499  	return DefaultResolver.LookupSRV(context.Background(), service, proto, name)
   500  }
   501  
   502  // LookupSRV tries to resolve an SRV query of the given service,
   503  // protocol, and domain name. The proto is "tcp" or "udp".
   504  // The returned records are sorted by priority and randomized
   505  // by weight within a priority.
   506  //
   507  // LookupSRV constructs the DNS name to look up following RFC 2782.
   508  // That is, it looks up _service._proto.name. To accommodate services
   509  // publishing SRV records under non-standard names, if both service
   510  // and proto are empty strings, LookupSRV looks up name directly.
   511  //
   512  // The returned service names are validated to be properly
   513  // formatted presentation-format domain names. If the response contains
   514  // invalid names, those records are filtered out and an error
   515  // will be returned alongside the remaining results, if any.
   516  func (r *Resolver) LookupSRV(ctx context.Context, service, proto, name string) (string, []*SRV, error) {
   517  	cname, addrs, err := r.lookupSRV(ctx, service, proto, name)
   518  	if err != nil {
   519  		return "", nil, err
   520  	}
   521  	if cname != "" && !isDomainName(cname) {
   522  		return "", nil, &DNSError{Err: "SRV header name is invalid", Name: name}
   523  	}
   524  	filteredAddrs := make([]*SRV, 0, len(addrs))
   525  	for _, addr := range addrs {
   526  		if addr == nil {
   527  			continue
   528  		}
   529  		if !isDomainName(addr.Target) {
   530  			continue
   531  		}
   532  		filteredAddrs = append(filteredAddrs, addr)
   533  	}
   534  	if len(addrs) != len(filteredAddrs) {
   535  		return cname, filteredAddrs, &DNSError{Err: errMalformedDNSRecordsDetail, Name: name}
   536  	}
   537  	return cname, filteredAddrs, nil
   538  }
   539  
   540  // LookupMX returns the DNS MX records for the given domain name sorted by preference.
   541  //
   542  // The returned mail server names are validated to be properly
   543  // formatted presentation-format domain names. If the response contains
   544  // invalid names, those records are filtered out and an error
   545  // will be returned alongside the remaining results, if any.
   546  //
   547  // LookupMX uses context.Background internally; to specify the context, use
   548  // Resolver.LookupMX.
   549  func LookupMX(name string) ([]*MX, error) {
   550  	return DefaultResolver.LookupMX(context.Background(), name)
   551  }
   552  
   553  // LookupMX returns the DNS MX records for the given domain name sorted by preference.
   554  //
   555  // The returned mail server names are validated to be properly
   556  // formatted presentation-format domain names. If the response contains
   557  // invalid names, those records are filtered out and an error
   558  // will be returned alongside the remaining results, if any.
   559  func (r *Resolver) LookupMX(ctx context.Context, name string) ([]*MX, error) {
   560  	records, err := r.lookupMX(ctx, name)
   561  	if err != nil {
   562  		return nil, err
   563  	}
   564  	filteredMX := make([]*MX, 0, len(records))
   565  	for _, mx := range records {
   566  		if mx == nil {
   567  			continue
   568  		}
   569  		if !isDomainName(mx.Host) {
   570  			continue
   571  		}
   572  		filteredMX = append(filteredMX, mx)
   573  	}
   574  	if len(records) != len(filteredMX) {
   575  		return filteredMX, &DNSError{Err: errMalformedDNSRecordsDetail, Name: name}
   576  	}
   577  	return filteredMX, nil
   578  }
   579  
   580  // LookupNS returns the DNS NS records for the given domain name.
   581  //
   582  // The returned name server names are validated to be properly
   583  // formatted presentation-format domain names. If the response contains
   584  // invalid names, those records are filtered out and an error
   585  // will be returned alongside the remaining results, if any.
   586  //
   587  // LookupNS uses context.Background internally; to specify the context, use
   588  // Resolver.LookupNS.
   589  func LookupNS(name string) ([]*NS, error) {
   590  	return DefaultResolver.LookupNS(context.Background(), name)
   591  }
   592  
   593  // LookupNS returns the DNS NS records for the given domain name.
   594  //
   595  // The returned name server names are validated to be properly
   596  // formatted presentation-format domain names. If the response contains
   597  // invalid names, those records are filtered out and an error
   598  // will be returned alongside the remaining results, if any.
   599  func (r *Resolver) LookupNS(ctx context.Context, name string) ([]*NS, error) {
   600  	records, err := r.lookupNS(ctx, name)
   601  	if err != nil {
   602  		return nil, err
   603  	}
   604  	filteredNS := make([]*NS, 0, len(records))
   605  	for _, ns := range records {
   606  		if ns == nil {
   607  			continue
   608  		}
   609  		if !isDomainName(ns.Host) {
   610  			continue
   611  		}
   612  		filteredNS = append(filteredNS, ns)
   613  	}
   614  	if len(records) != len(filteredNS) {
   615  		return filteredNS, &DNSError{Err: errMalformedDNSRecordsDetail, Name: name}
   616  	}
   617  	return filteredNS, nil
   618  }
   619  
   620  // LookupTXT returns the DNS TXT records for the given domain name.
   621  //
   622  // LookupTXT uses context.Background internally; to specify the context, use
   623  // Resolver.LookupTXT.
   624  func LookupTXT(name string) ([]string, error) {
   625  	return DefaultResolver.lookupTXT(context.Background(), name)
   626  }
   627  
   628  // LookupTXT returns the DNS TXT records for the given domain name.
   629  func (r *Resolver) LookupTXT(ctx context.Context, name string) ([]string, error) {
   630  	return r.lookupTXT(ctx, name)
   631  }
   632  
   633  // LookupAddr performs a reverse lookup for the given address, returning a list
   634  // of names mapping to that address.
   635  //
   636  // The returned names are validated to be properly formatted presentation-format
   637  // domain names. If the response contains invalid names, those records are filtered
   638  // out and an error will be returned alongside the remaining results, if any.
   639  //
   640  // When using the host C library resolver, at most one result will be
   641  // returned. To bypass the host resolver, use a custom Resolver.
   642  //
   643  // LookupAddr uses context.Background internally; to specify the context, use
   644  // Resolver.LookupAddr.
   645  func LookupAddr(addr string) (names []string, err error) {
   646  	return DefaultResolver.LookupAddr(context.Background(), addr)
   647  }
   648  
   649  // LookupAddr performs a reverse lookup for the given address, returning a list
   650  // of names mapping to that address.
   651  //
   652  // The returned names are validated to be properly formatted presentation-format
   653  // domain names. If the response contains invalid names, those records are filtered
   654  // out and an error will be returned alongside the remaining results, if any.
   655  func (r *Resolver) LookupAddr(ctx context.Context, addr string) ([]string, error) {
   656  	names, err := r.lookupAddr(ctx, addr)
   657  	if err != nil {
   658  		return nil, err
   659  	}
   660  	filteredNames := make([]string, 0, len(names))
   661  	for _, name := range names {
   662  		if isDomainName(name) {
   663  			filteredNames = append(filteredNames, name)
   664  		}
   665  	}
   666  	if len(names) != len(filteredNames) {
   667  		return filteredNames, &DNSError{Err: errMalformedDNSRecordsDetail, Name: addr}
   668  	}
   669  	return filteredNames, nil
   670  }
   671  
   672  // errMalformedDNSRecordsDetail is the DNSError detail which is returned when a Resolver.Lookup...
   673  // method receives DNS records which contain invalid DNS names. This may be returned alongside
   674  // results which have had the malformed records filtered out.
   675  var errMalformedDNSRecordsDetail = "DNS response contained records which contain invalid names"
   676  
   677  // dial makes a new connection to the provided server (which must be
   678  // an IP address) with the provided network type, using either r.Dial
   679  // (if both r and r.Dial are non-nil) or else Dialer.DialContext.
   680  func (r *Resolver) dial(ctx context.Context, network, server string) (Conn, error) {
   681  	// Calling Dial here is scary -- we have to be sure not to
   682  	// dial a name that will require a DNS lookup, or Dial will
   683  	// call back here to translate it. The DNS config parser has
   684  	// already checked that all the cfg.servers are IP
   685  	// addresses, which Dial will use without a DNS lookup.
   686  	var c Conn
   687  	var err error
   688  	if r != nil && r.Dial != nil {
   689  		c, err = r.Dial(ctx, network, server)
   690  	} else {
   691  		var d Dialer
   692  		c, err = d.DialContext(ctx, network, server)
   693  	}
   694  	if err != nil {
   695  		return nil, mapErr(err)
   696  	}
   697  	return c, nil
   698  }
   699  
   700  // goLookupSRV returns the SRV records for a target name, built either
   701  // from its component service ("sip"), protocol ("tcp"), and name
   702  // ("example.com."), or from name directly (if service and proto are
   703  // both empty).
   704  //
   705  // In either case, the returned target name ("_sip._tcp.example.com.")
   706  // is also returned on success.
   707  //
   708  // The records are sorted by weight.
   709  func (r *Resolver) goLookupSRV(ctx context.Context, service, proto, name string) (target string, srvs []*SRV, err error) {
   710  	if service == "" && proto == "" {
   711  		target = name
   712  	} else {
   713  		target = "_" + service + "._" + proto + "." + name
   714  	}
   715  	p, server, err := r.lookup(ctx, target, dnsmessage.TypeSRV, nil)
   716  	if err != nil {
   717  		return "", nil, err
   718  	}
   719  	var cname dnsmessage.Name
   720  	for {
   721  		h, err := p.AnswerHeader()
   722  		if err == dnsmessage.ErrSectionDone {
   723  			break
   724  		}
   725  		if err != nil {
   726  			return "", nil, &DNSError{
   727  				Err:    "cannot unmarshal DNS message",
   728  				Name:   name,
   729  				Server: server,
   730  			}
   731  		}
   732  		if h.Type != dnsmessage.TypeSRV {
   733  			if err := p.SkipAnswer(); err != nil {
   734  				return "", nil, &DNSError{
   735  					Err:    "cannot unmarshal DNS message",
   736  					Name:   name,
   737  					Server: server,
   738  				}
   739  			}
   740  			continue
   741  		}
   742  		if cname.Length == 0 && h.Name.Length != 0 {
   743  			cname = h.Name
   744  		}
   745  		srv, err := p.SRVResource()
   746  		if err != nil {
   747  			return "", nil, &DNSError{
   748  				Err:    "cannot unmarshal DNS message",
   749  				Name:   name,
   750  				Server: server,
   751  			}
   752  		}
   753  		srvs = append(srvs, &SRV{Target: srv.Target.String(), Port: srv.Port, Priority: srv.Priority, Weight: srv.Weight})
   754  	}
   755  	byPriorityWeight(srvs).sort()
   756  	return cname.String(), srvs, nil
   757  }
   758  
   759  // goLookupMX returns the MX records for name.
   760  func (r *Resolver) goLookupMX(ctx context.Context, name string) ([]*MX, error) {
   761  	p, server, err := r.lookup(ctx, name, dnsmessage.TypeMX, nil)
   762  	if err != nil {
   763  		return nil, err
   764  	}
   765  	var mxs []*MX
   766  	for {
   767  		h, err := p.AnswerHeader()
   768  		if err == dnsmessage.ErrSectionDone {
   769  			break
   770  		}
   771  		if err != nil {
   772  			return nil, &DNSError{
   773  				Err:    "cannot unmarshal DNS message",
   774  				Name:   name,
   775  				Server: server,
   776  			}
   777  		}
   778  		if h.Type != dnsmessage.TypeMX {
   779  			if err := p.SkipAnswer(); err != nil {
   780  				return nil, &DNSError{
   781  					Err:    "cannot unmarshal DNS message",
   782  					Name:   name,
   783  					Server: server,
   784  				}
   785  			}
   786  			continue
   787  		}
   788  		mx, err := p.MXResource()
   789  		if err != nil {
   790  			return nil, &DNSError{
   791  				Err:    "cannot unmarshal DNS message",
   792  				Name:   name,
   793  				Server: server,
   794  			}
   795  		}
   796  		mxs = append(mxs, &MX{Host: mx.MX.String(), Pref: mx.Pref})
   797  
   798  	}
   799  	byPref(mxs).sort()
   800  	return mxs, nil
   801  }
   802  
   803  // goLookupNS returns the NS records for name.
   804  func (r *Resolver) goLookupNS(ctx context.Context, name string) ([]*NS, error) {
   805  	p, server, err := r.lookup(ctx, name, dnsmessage.TypeNS, nil)
   806  	if err != nil {
   807  		return nil, err
   808  	}
   809  	var nss []*NS
   810  	for {
   811  		h, err := p.AnswerHeader()
   812  		if err == dnsmessage.ErrSectionDone {
   813  			break
   814  		}
   815  		if err != nil {
   816  			return nil, &DNSError{
   817  				Err:    "cannot unmarshal DNS message",
   818  				Name:   name,
   819  				Server: server,
   820  			}
   821  		}
   822  		if h.Type != dnsmessage.TypeNS {
   823  			if err := p.SkipAnswer(); err != nil {
   824  				return nil, &DNSError{
   825  					Err:    "cannot unmarshal DNS message",
   826  					Name:   name,
   827  					Server: server,
   828  				}
   829  			}
   830  			continue
   831  		}
   832  		ns, err := p.NSResource()
   833  		if err != nil {
   834  			return nil, &DNSError{
   835  				Err:    "cannot unmarshal DNS message",
   836  				Name:   name,
   837  				Server: server,
   838  			}
   839  		}
   840  		nss = append(nss, &NS{Host: ns.NS.String()})
   841  	}
   842  	return nss, nil
   843  }
   844  
   845  // goLookupTXT returns the TXT records from name.
   846  func (r *Resolver) goLookupTXT(ctx context.Context, name string) ([]string, error) {
   847  	p, server, err := r.lookup(ctx, name, dnsmessage.TypeTXT, nil)
   848  	if err != nil {
   849  		return nil, err
   850  	}
   851  	var txts []string
   852  	for {
   853  		h, err := p.AnswerHeader()
   854  		if err == dnsmessage.ErrSectionDone {
   855  			break
   856  		}
   857  		if err != nil {
   858  			return nil, &DNSError{
   859  				Err:    "cannot unmarshal DNS message",
   860  				Name:   name,
   861  				Server: server,
   862  			}
   863  		}
   864  		if h.Type != dnsmessage.TypeTXT {
   865  			if err := p.SkipAnswer(); err != nil {
   866  				return nil, &DNSError{
   867  					Err:    "cannot unmarshal DNS message",
   868  					Name:   name,
   869  					Server: server,
   870  				}
   871  			}
   872  			continue
   873  		}
   874  		txt, err := p.TXTResource()
   875  		if err != nil {
   876  			return nil, &DNSError{
   877  				Err:    "cannot unmarshal DNS message",
   878  				Name:   name,
   879  				Server: server,
   880  			}
   881  		}
   882  		// Multiple strings in one TXT record need to be
   883  		// concatenated without separator to be consistent
   884  		// with previous Go resolver.
   885  		n := 0
   886  		for _, s := range txt.TXT {
   887  			n += len(s)
   888  		}
   889  		txtJoin := make([]byte, 0, n)
   890  		for _, s := range txt.TXT {
   891  			txtJoin = append(txtJoin, s...)
   892  		}
   893  		if len(txts) == 0 {
   894  			txts = make([]string, 0, 1)
   895  		}
   896  		txts = append(txts, string(txtJoin))
   897  	}
   898  	return txts, nil
   899  }
   900  
   901  func parseCNAMEFromResources(resources []dnsmessage.Resource) (string, error) {
   902  	if len(resources) == 0 {
   903  		return "", errors.New("no CNAME record received")
   904  	}
   905  	c, ok := resources[0].Body.(*dnsmessage.CNAMEResource)
   906  	if !ok {
   907  		return "", errors.New("could not parse CNAME record")
   908  	}
   909  	return c.CNAME.String(), nil
   910  }
   911  

View as plain text