lookup.mx raw

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