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

View as plain text