...

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		"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	// 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	func LookupHost(host string) (addrs []string, err error) {
   171		return DefaultResolver.LookupHost(context.Background(), host)
   172	}
   173	
   174	// LookupHost looks up the given host using the local resolver.
   175	// It returns a slice of that host's addresses.
   176	func (r *Resolver) LookupHost(ctx context.Context, host string) (addrs []string, err error) {
   177		// Make sure that no matter what we do later, host=="" is rejected.
   178		// parseIP, for example, does accept empty strings.
   179		if host == "" {
   180			return nil, &DNSError{Err: errNoSuchHost.Error(), Name: host, IsNotFound: true}
   181		}
   182		if ip, _ := parseIPZone(host); ip != nil {
   183			return []string{host}, nil
   184		}
   185		return r.lookupHost(ctx, host)
   186	}
   187	
   188	// LookupIP looks up host using the local resolver.
   189	// It returns a slice of that host's IPv4 and IPv6 addresses.
   190	func LookupIP(host string) ([]IP, error) {
   191		addrs, err := DefaultResolver.LookupIPAddr(context.Background(), host)
   192		if err != nil {
   193			return nil, err
   194		}
   195		ips := make([]IP, len(addrs))
   196		for i, ia := range addrs {
   197			ips[i] = ia.IP
   198		}
   199		return ips, nil
   200	}
   201	
   202	// LookupIPAddr looks up host using the local resolver.
   203	// It returns a slice of that host's IPv4 and IPv6 addresses.
   204	func (r *Resolver) LookupIPAddr(ctx context.Context, host string) ([]IPAddr, error) {
   205		return r.lookupIPAddr(ctx, "ip", host)
   206	}
   207	
   208	// onlyValuesCtx is a context that uses an underlying context
   209	// for value lookup if the underlying context hasn't yet expired.
   210	type onlyValuesCtx struct {
   211		context.Context
   212		lookupValues context.Context
   213	}
   214	
   215	var _ context.Context = (*onlyValuesCtx)(nil)
   216	
   217	// Value performs a lookup if the original context hasn't expired.
   218	func (ovc *onlyValuesCtx) Value(key interface{}) interface{} {
   219		select {
   220		case <-ovc.lookupValues.Done():
   221			return nil
   222		default:
   223			return ovc.lookupValues.Value(key)
   224		}
   225	}
   226	
   227	// withUnexpiredValuesPreserved returns a context.Context that only uses lookupCtx
   228	// for its values, otherwise it is never canceled and has no deadline.
   229	// If the lookup context expires, any looked up values will return nil.
   230	// See Issue 28600.
   231	func withUnexpiredValuesPreserved(lookupCtx context.Context) context.Context {
   232		return &onlyValuesCtx{Context: context.Background(), lookupValues: lookupCtx}
   233	}
   234	
   235	// lookupIPAddr looks up host using the local resolver and particular network.
   236	// It returns a slice of that host's IPv4 and IPv6 addresses.
   237	func (r *Resolver) lookupIPAddr(ctx context.Context, network, host string) ([]IPAddr, error) {
   238		// Make sure that no matter what we do later, host=="" is rejected.
   239		// parseIP, for example, does accept empty strings.
   240		if host == "" {
   241			return nil, &DNSError{Err: errNoSuchHost.Error(), Name: host, IsNotFound: true}
   242		}
   243		if ip, zone := parseIPZone(host); ip != nil {
   244			return []IPAddr{{IP: ip, Zone: zone}}, nil
   245		}
   246		trace, _ := ctx.Value(nettrace.TraceKey{}).(*nettrace.Trace)
   247		if trace != nil && trace.DNSStart != nil {
   248			trace.DNSStart(host)
   249		}
   250		// The underlying resolver func is lookupIP by default but it
   251		// can be overridden by tests. This is needed by net/http, so it
   252		// uses a context key instead of unexported variables.
   253		resolverFunc := r.lookupIP
   254		if alt, _ := ctx.Value(nettrace.LookupIPAltResolverKey{}).(func(context.Context, string, string) ([]IPAddr, error)); alt != nil {
   255			resolverFunc = alt
   256		}
   257	
   258		// We don't want a cancellation of ctx to affect the
   259		// lookupGroup operation. Otherwise if our context gets
   260		// canceled it might cause an error to be returned to a lookup
   261		// using a completely different context. However we need to preserve
   262		// only the values in context. See Issue 28600.
   263		lookupGroupCtx, lookupGroupCancel := context.WithCancel(withUnexpiredValuesPreserved(ctx))
   264	
   265		lookupKey := network + "\000" + host
   266		dnsWaitGroup.Add(1)
   267		ch, called := r.getLookupGroup().DoChan(lookupKey, func() (interface{}, error) {
   268			defer dnsWaitGroup.Done()
   269			return testHookLookupIP(lookupGroupCtx, resolverFunc, network, host)
   270		})
   271		if !called {
   272			dnsWaitGroup.Done()
   273		}
   274	
   275		select {
   276		case <-ctx.Done():
   277			// Our context was canceled. If we are the only
   278			// goroutine looking up this key, then drop the key
   279			// from the lookupGroup and cancel the lookup.
   280			// If there are other goroutines looking up this key,
   281			// let the lookup continue uncanceled, and let later
   282			// lookups with the same key share the result.
   283			// See issues 8602, 20703, 22724.
   284			if r.getLookupGroup().ForgetUnshared(lookupKey) {
   285				lookupGroupCancel()
   286			} else {
   287				go func() {
   288					<-ch
   289					lookupGroupCancel()
   290				}()
   291			}
   292			err := mapErr(ctx.Err())
   293			if trace != nil && trace.DNSDone != nil {
   294				trace.DNSDone(nil, false, err)
   295			}
   296			return nil, err
   297		case r := <-ch:
   298			lookupGroupCancel()
   299			if trace != nil && trace.DNSDone != nil {
   300				addrs, _ := r.Val.([]IPAddr)
   301				trace.DNSDone(ipAddrsEface(addrs), r.Shared, r.Err)
   302			}
   303			return lookupIPReturn(r.Val, r.Err, r.Shared)
   304		}
   305	}
   306	
   307	// lookupIPReturn turns the return values from singleflight.Do into
   308	// the return values from LookupIP.
   309	func lookupIPReturn(addrsi interface{}, err error, shared bool) ([]IPAddr, error) {
   310		if err != nil {
   311			return nil, err
   312		}
   313		addrs := addrsi.([]IPAddr)
   314		if shared {
   315			clone := make([]IPAddr, len(addrs))
   316			copy(clone, addrs)
   317			addrs = clone
   318		}
   319		return addrs, nil
   320	}
   321	
   322	// ipAddrsEface returns an empty interface slice of addrs.
   323	func ipAddrsEface(addrs []IPAddr) []interface{} {
   324		s := make([]interface{}, len(addrs))
   325		for i, v := range addrs {
   326			s[i] = v
   327		}
   328		return s
   329	}
   330	
   331	// LookupPort looks up the port for the given network and service.
   332	func LookupPort(network, service string) (port int, err error) {
   333		return DefaultResolver.LookupPort(context.Background(), network, service)
   334	}
   335	
   336	// LookupPort looks up the port for the given network and service.
   337	func (r *Resolver) LookupPort(ctx context.Context, network, service string) (port int, err error) {
   338		port, needsLookup := parsePort(service)
   339		if needsLookup {
   340			switch network {
   341			case "tcp", "tcp4", "tcp6", "udp", "udp4", "udp6":
   342			case "": // a hint wildcard for Go 1.0 undocumented behavior
   343				network = "ip"
   344			default:
   345				return 0, &AddrError{Err: "unknown network", Addr: network}
   346			}
   347			port, err = r.lookupPort(ctx, network, service)
   348			if err != nil {
   349				return 0, err
   350			}
   351		}
   352		if 0 > port || port > 65535 {
   353			return 0, &AddrError{Err: "invalid port", Addr: service}
   354		}
   355		return port, nil
   356	}
   357	
   358	// LookupCNAME returns the canonical name for the given host.
   359	// Callers that do not care about the canonical name can call
   360	// LookupHost or LookupIP directly; both take care of resolving
   361	// the canonical name as part of the lookup.
   362	//
   363	// A canonical name is the final name after following zero
   364	// or more CNAME records.
   365	// LookupCNAME does not return an error if host does not
   366	// contain DNS "CNAME" records, as long as host resolves to
   367	// address records.
   368	func LookupCNAME(host string) (cname string, err error) {
   369		return DefaultResolver.lookupCNAME(context.Background(), host)
   370	}
   371	
   372	// LookupCNAME returns the canonical name for the given host.
   373	// Callers that do not care about the canonical name can call
   374	// LookupHost or LookupIP directly; both take care of resolving
   375	// the canonical name as part of the lookup.
   376	//
   377	// A canonical name is the final name after following zero
   378	// or more CNAME records.
   379	// LookupCNAME does not return an error if host does not
   380	// contain DNS "CNAME" records, as long as host resolves to
   381	// address records.
   382	func (r *Resolver) LookupCNAME(ctx context.Context, host string) (cname string, err error) {
   383		return r.lookupCNAME(ctx, host)
   384	}
   385	
   386	// LookupSRV tries to resolve an SRV query of the given service,
   387	// protocol, and domain name. The proto is "tcp" or "udp".
   388	// The returned records are sorted by priority and randomized
   389	// by weight within a priority.
   390	//
   391	// LookupSRV constructs the DNS name to look up following RFC 2782.
   392	// That is, it looks up _service._proto.name. To accommodate services
   393	// publishing SRV records under non-standard names, if both service
   394	// and proto are empty strings, LookupSRV looks up name directly.
   395	func LookupSRV(service, proto, name string) (cname string, addrs []*SRV, err error) {
   396		return DefaultResolver.lookupSRV(context.Background(), service, proto, name)
   397	}
   398	
   399	// LookupSRV tries to resolve an SRV query of the given service,
   400	// protocol, and domain name. The proto is "tcp" or "udp".
   401	// The returned records are sorted by priority and randomized
   402	// by weight within a priority.
   403	//
   404	// LookupSRV constructs the DNS name to look up following RFC 2782.
   405	// That is, it looks up _service._proto.name. To accommodate services
   406	// publishing SRV records under non-standard names, if both service
   407	// and proto are empty strings, LookupSRV looks up name directly.
   408	func (r *Resolver) LookupSRV(ctx context.Context, service, proto, name string) (cname string, addrs []*SRV, err error) {
   409		return r.lookupSRV(ctx, service, proto, name)
   410	}
   411	
   412	// LookupMX returns the DNS MX records for the given domain name sorted by preference.
   413	func LookupMX(name string) ([]*MX, error) {
   414		return DefaultResolver.lookupMX(context.Background(), name)
   415	}
   416	
   417	// LookupMX returns the DNS MX records for the given domain name sorted by preference.
   418	func (r *Resolver) LookupMX(ctx context.Context, name string) ([]*MX, error) {
   419		return r.lookupMX(ctx, name)
   420	}
   421	
   422	// LookupNS returns the DNS NS records for the given domain name.
   423	func LookupNS(name string) ([]*NS, error) {
   424		return DefaultResolver.lookupNS(context.Background(), name)
   425	}
   426	
   427	// LookupNS returns the DNS NS records for the given domain name.
   428	func (r *Resolver) LookupNS(ctx context.Context, name string) ([]*NS, error) {
   429		return r.lookupNS(ctx, name)
   430	}
   431	
   432	// LookupTXT returns the DNS TXT records for the given domain name.
   433	func LookupTXT(name string) ([]string, error) {
   434		return DefaultResolver.lookupTXT(context.Background(), name)
   435	}
   436	
   437	// LookupTXT returns the DNS TXT records for the given domain name.
   438	func (r *Resolver) LookupTXT(ctx context.Context, name string) ([]string, error) {
   439		return r.lookupTXT(ctx, name)
   440	}
   441	
   442	// LookupAddr performs a reverse lookup for the given address, returning a list
   443	// of names mapping to that address.
   444	//
   445	// When using the host C library resolver, at most one result will be
   446	// returned. To bypass the host resolver, use a custom Resolver.
   447	func LookupAddr(addr string) (names []string, err error) {
   448		return DefaultResolver.lookupAddr(context.Background(), addr)
   449	}
   450	
   451	// LookupAddr performs a reverse lookup for the given address, returning a list
   452	// of names mapping to that address.
   453	func (r *Resolver) LookupAddr(ctx context.Context, addr string) (names []string, err error) {
   454		return r.lookupAddr(ctx, addr)
   455	}
   456	

View as plain text