...
Run Format

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  	"sync"
    12  )
    13  
    14  // protocols contains minimal mappings between internet protocol
    15  // names and numbers for platforms that don't have a complete list of
    16  // protocol numbers.
    17  //
    18  // See https://www.iana.org/assignments/protocol-numbers
    19  //
    20  // On Unix, this map is augmented by readProtocols via lookupProtocol.
    21  var protocols = map[string]int{
    22  	"icmp":      1,
    23  	"igmp":      2,
    24  	"tcp":       6,
    25  	"udp":       17,
    26  	"ipv6-icmp": 58,
    27  }
    28  
    29  // services contains minimal mappings between services names and port
    30  // numbers for platforms that don't have a complete list of port numbers
    31  // (some Solaris distros, nacl, etc).
    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  // DefaultResolver is the resolver used by the package-level Lookup
   101  // functions and by Dialers without a specified Resolver.
   102  var DefaultResolver = &Resolver{}
   103  
   104  // A Resolver looks up names and numbers.
   105  //
   106  // A nil *Resolver is equivalent to a zero Resolver.
   107  type Resolver struct {
   108  	// PreferGo controls whether Go's built-in DNS resolver is preferred
   109  	// on platforms where it's available. It is equivalent to setting
   110  	// GODEBUG=netdns=go, but scoped to just this resolver.
   111  	PreferGo bool
   112  
   113  	// StrictErrors controls the behavior of temporary errors
   114  	// (including timeout, socket errors, and SERVFAIL) when using
   115  	// Go's built-in resolver. For a query composed of multiple
   116  	// sub-queries (such as an A+AAAA address lookup, or walking the
   117  	// DNS search list), this option causes such errors to abort the
   118  	// whole query instead of returning a partial result. This is
   119  	// not enabled by default because it may affect compatibility
   120  	// with resolvers that process AAAA queries incorrectly.
   121  	StrictErrors bool
   122  
   123  	// Dial optionally specifies an alternate dialer for use by
   124  	// Go's built-in DNS resolver to make TCP and UDP connections
   125  	// to DNS services. The host in the address parameter will
   126  	// always be a literal IP address and not a host name, and the
   127  	// port in the address parameter will be a literal port number
   128  	// and not a service name.
   129  	// If the Conn returned is also a PacketConn, sent and received DNS
   130  	// messages must adhere to RFC 1035 section 4.2.1, "UDP usage".
   131  	// Otherwise, DNS messages transmitted over Conn must adhere
   132  	// to RFC 7766 section 5, "Transport Protocol Selection".
   133  	// If nil, the default dialer is used.
   134  	Dial func(ctx context.Context, network, address string) (Conn, error)
   135  
   136  	// lookupGroup merges LookupIPAddr calls together for lookups for the same
   137  	// host. The lookupGroup key is the LookupIPAddr.host argument.
   138  	// The return values are ([]IPAddr, error).
   139  	lookupGroup singleflight.Group
   140  
   141  	// TODO(bradfitz): optional interface impl override hook
   142  	// TODO(bradfitz): Timeout time.Duration?
   143  }
   144  
   145  func (r *Resolver) preferGo() bool     { return r != nil && r.PreferGo }
   146  func (r *Resolver) strictErrors() bool { return r != nil && r.StrictErrors }
   147  
   148  func (r *Resolver) getLookupGroup() *singleflight.Group {
   149  	if r == nil {
   150  		return &DefaultResolver.lookupGroup
   151  	}
   152  	return &r.lookupGroup
   153  }
   154  
   155  // LookupHost looks up the given host using the local resolver.
   156  // It returns a slice of that host's addresses.
   157  func LookupHost(host string) (addrs []string, err error) {
   158  	return DefaultResolver.LookupHost(context.Background(), host)
   159  }
   160  
   161  // LookupHost looks up the given host using the local resolver.
   162  // It returns a slice of that host's addresses.
   163  func (r *Resolver) LookupHost(ctx context.Context, host string) (addrs []string, err error) {
   164  	// Make sure that no matter what we do later, host=="" is rejected.
   165  	// parseIP, for example, does accept empty strings.
   166  	if host == "" {
   167  		return nil, &DNSError{Err: errNoSuchHost.Error(), Name: host}
   168  	}
   169  	if ip, _ := parseIPZone(host); ip != nil {
   170  		return []string{host}, nil
   171  	}
   172  	return r.lookupHost(ctx, host)
   173  }
   174  
   175  // LookupIP looks up host using the local resolver.
   176  // It returns a slice of that host's IPv4 and IPv6 addresses.
   177  func LookupIP(host string) ([]IP, error) {
   178  	addrs, err := DefaultResolver.LookupIPAddr(context.Background(), host)
   179  	if err != nil {
   180  		return nil, err
   181  	}
   182  	ips := make([]IP, len(addrs))
   183  	for i, ia := range addrs {
   184  		ips[i] = ia.IP
   185  	}
   186  	return ips, nil
   187  }
   188  
   189  // LookupIPAddr looks up host using the local resolver.
   190  // It returns a slice of that host's IPv4 and IPv6 addresses.
   191  func (r *Resolver) LookupIPAddr(ctx context.Context, host string) ([]IPAddr, error) {
   192  	// Make sure that no matter what we do later, host=="" is rejected.
   193  	// parseIP, for example, does accept empty strings.
   194  	if host == "" {
   195  		return nil, &DNSError{Err: errNoSuchHost.Error(), Name: host}
   196  	}
   197  	if ip, zone := parseIPZone(host); ip != nil {
   198  		return []IPAddr{{IP: ip, Zone: zone}}, nil
   199  	}
   200  	trace, _ := ctx.Value(nettrace.TraceKey{}).(*nettrace.Trace)
   201  	if trace != nil && trace.DNSStart != nil {
   202  		trace.DNSStart(host)
   203  	}
   204  	// The underlying resolver func is lookupIP by default but it
   205  	// can be overridden by tests. This is needed by net/http, so it
   206  	// uses a context key instead of unexported variables.
   207  	resolverFunc := r.lookupIP
   208  	if alt, _ := ctx.Value(nettrace.LookupIPAltResolverKey{}).(func(context.Context, string) ([]IPAddr, error)); alt != nil {
   209  		resolverFunc = alt
   210  	}
   211  
   212  	// We don't want a cancelation of ctx to affect the
   213  	// lookupGroup operation. Otherwise if our context gets
   214  	// canceled it might cause an error to be returned to a lookup
   215  	// using a completely different context.
   216  	lookupGroupCtx, lookupGroupCancel := context.WithCancel(context.Background())
   217  
   218  	dnsWaitGroup.Add(1)
   219  	ch, called := r.getLookupGroup().DoChan(host, func() (interface{}, error) {
   220  		defer dnsWaitGroup.Done()
   221  		return testHookLookupIP(lookupGroupCtx, resolverFunc, host)
   222  	})
   223  	if !called {
   224  		dnsWaitGroup.Done()
   225  	}
   226  
   227  	select {
   228  	case <-ctx.Done():
   229  		// Our context was canceled. If we are the only
   230  		// goroutine looking up this key, then drop the key
   231  		// from the lookupGroup and cancel the lookup.
   232  		// If there are other goroutines looking up this key,
   233  		// let the lookup continue uncanceled, and let later
   234  		// lookups with the same key share the result.
   235  		// See issues 8602, 20703, 22724.
   236  		if r.getLookupGroup().ForgetUnshared(host) {
   237  			lookupGroupCancel()
   238  		} else {
   239  			go func() {
   240  				<-ch
   241  				lookupGroupCancel()
   242  			}()
   243  		}
   244  		err := mapErr(ctx.Err())
   245  		if trace != nil && trace.DNSDone != nil {
   246  			trace.DNSDone(nil, false, err)
   247  		}
   248  		return nil, err
   249  	case r := <-ch:
   250  		lookupGroupCancel()
   251  		if trace != nil && trace.DNSDone != nil {
   252  			addrs, _ := r.Val.([]IPAddr)
   253  			trace.DNSDone(ipAddrsEface(addrs), r.Shared, r.Err)
   254  		}
   255  		return lookupIPReturn(r.Val, r.Err, r.Shared)
   256  	}
   257  }
   258  
   259  // lookupIPReturn turns the return values from singleflight.Do into
   260  // the return values from LookupIP.
   261  func lookupIPReturn(addrsi interface{}, err error, shared bool) ([]IPAddr, error) {
   262  	if err != nil {
   263  		return nil, err
   264  	}
   265  	addrs := addrsi.([]IPAddr)
   266  	if shared {
   267  		clone := make([]IPAddr, len(addrs))
   268  		copy(clone, addrs)
   269  		addrs = clone
   270  	}
   271  	return addrs, nil
   272  }
   273  
   274  // ipAddrsEface returns an empty interface slice of addrs.
   275  func ipAddrsEface(addrs []IPAddr) []interface{} {
   276  	s := make([]interface{}, len(addrs))
   277  	for i, v := range addrs {
   278  		s[i] = v
   279  	}
   280  	return s
   281  }
   282  
   283  // LookupPort looks up the port for the given network and service.
   284  func LookupPort(network, service string) (port int, err error) {
   285  	return DefaultResolver.LookupPort(context.Background(), network, service)
   286  }
   287  
   288  // LookupPort looks up the port for the given network and service.
   289  func (r *Resolver) LookupPort(ctx context.Context, network, service string) (port int, err error) {
   290  	port, needsLookup := parsePort(service)
   291  	if needsLookup {
   292  		port, err = r.lookupPort(ctx, network, service)
   293  		if err != nil {
   294  			return 0, err
   295  		}
   296  	}
   297  	if 0 > port || port > 65535 {
   298  		return 0, &AddrError{Err: "invalid port", Addr: service}
   299  	}
   300  	return port, nil
   301  }
   302  
   303  // LookupCNAME returns the canonical name for the given host.
   304  // Callers that do not care about the canonical name can call
   305  // LookupHost or LookupIP directly; both take care of resolving
   306  // the canonical name as part of the lookup.
   307  //
   308  // A canonical name is the final name after following zero
   309  // or more CNAME records.
   310  // LookupCNAME does not return an error if host does not
   311  // contain DNS "CNAME" records, as long as host resolves to
   312  // address records.
   313  func LookupCNAME(host string) (cname string, err error) {
   314  	return DefaultResolver.lookupCNAME(context.Background(), host)
   315  }
   316  
   317  // LookupCNAME returns the canonical name for the given host.
   318  // Callers that do not care about the canonical name can call
   319  // LookupHost or LookupIP directly; both take care of resolving
   320  // the canonical name as part of the lookup.
   321  //
   322  // A canonical name is the final name after following zero
   323  // or more CNAME records.
   324  // LookupCNAME does not return an error if host does not
   325  // contain DNS "CNAME" records, as long as host resolves to
   326  // address records.
   327  func (r *Resolver) LookupCNAME(ctx context.Context, host string) (cname string, err error) {
   328  	return r.lookupCNAME(ctx, host)
   329  }
   330  
   331  // LookupSRV tries to resolve an SRV query of the given service,
   332  // protocol, and domain name. The proto is "tcp" or "udp".
   333  // The returned records are sorted by priority and randomized
   334  // by weight within a priority.
   335  //
   336  // LookupSRV constructs the DNS name to look up following RFC 2782.
   337  // That is, it looks up _service._proto.name. To accommodate services
   338  // publishing SRV records under non-standard names, if both service
   339  // and proto are empty strings, LookupSRV looks up name directly.
   340  func LookupSRV(service, proto, name string) (cname string, addrs []*SRV, err error) {
   341  	return DefaultResolver.lookupSRV(context.Background(), service, proto, name)
   342  }
   343  
   344  // LookupSRV tries to resolve an SRV query of the given service,
   345  // protocol, and domain name. The proto is "tcp" or "udp".
   346  // The returned records are sorted by priority and randomized
   347  // by weight within a priority.
   348  //
   349  // LookupSRV constructs the DNS name to look up following RFC 2782.
   350  // That is, it looks up _service._proto.name. To accommodate services
   351  // publishing SRV records under non-standard names, if both service
   352  // and proto are empty strings, LookupSRV looks up name directly.
   353  func (r *Resolver) LookupSRV(ctx context.Context, service, proto, name string) (cname string, addrs []*SRV, err error) {
   354  	return r.lookupSRV(ctx, service, proto, name)
   355  }
   356  
   357  // LookupMX returns the DNS MX records for the given domain name sorted by preference.
   358  func LookupMX(name string) ([]*MX, error) {
   359  	return DefaultResolver.lookupMX(context.Background(), name)
   360  }
   361  
   362  // LookupMX returns the DNS MX records for the given domain name sorted by preference.
   363  func (r *Resolver) LookupMX(ctx context.Context, name string) ([]*MX, error) {
   364  	return r.lookupMX(ctx, name)
   365  }
   366  
   367  // LookupNS returns the DNS NS records for the given domain name.
   368  func LookupNS(name string) ([]*NS, error) {
   369  	return DefaultResolver.lookupNS(context.Background(), name)
   370  }
   371  
   372  // LookupNS returns the DNS NS records for the given domain name.
   373  func (r *Resolver) LookupNS(ctx context.Context, name string) ([]*NS, error) {
   374  	return r.lookupNS(ctx, name)
   375  }
   376  
   377  // LookupTXT returns the DNS TXT records for the given domain name.
   378  func LookupTXT(name string) ([]string, error) {
   379  	return DefaultResolver.lookupTXT(context.Background(), name)
   380  }
   381  
   382  // LookupTXT returns the DNS TXT records for the given domain name.
   383  func (r *Resolver) LookupTXT(ctx context.Context, name string) ([]string, error) {
   384  	return r.lookupTXT(ctx, name)
   385  }
   386  
   387  // LookupAddr performs a reverse lookup for the given address, returning a list
   388  // of names mapping to that address.
   389  //
   390  // When using the host C library resolver, at most one result will be
   391  // returned. To bypass the host resolver, use a custom Resolver.
   392  func LookupAddr(addr string) (names []string, err error) {
   393  	return DefaultResolver.lookupAddr(context.Background(), addr)
   394  }
   395  
   396  // LookupAddr performs a reverse lookup for the given address, returning a list
   397  // of names mapping to that address.
   398  func (r *Resolver) LookupAddr(ctx context.Context, addr string) (names []string, err error) {
   399  	return r.lookupAddr(ctx, addr)
   400  }
   401  

View as plain text