...

Source file src/net/lookup.go

Documentation: net

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

View as plain text