...
Run Format

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	)
    12	
    13	// protocols contains minimal mappings between internet protocol
    14	// names and numbers for platforms that don't have a complete list of
    15	// protocol numbers.
    16	//
    17	// See http://www.iana.org/assignments/protocol-numbers
    18	//
    19	// On Unix, this map is augmented by readProtocols via lookupProtocol.
    20	var protocols = map[string]int{
    21		"icmp":      1,
    22		"igmp":      2,
    23		"tcp":       6,
    24		"udp":       17,
    25		"ipv6-icmp": 58,
    26	}
    27	
    28	// services contains minimal mappings between services names and port
    29	// numbers for platforms that don't have a complete list of port numbers
    30	// (some Solaris distros, nacl, etc).
    31	// On Unix, this map is augmented by readServices via goLookupPort.
    32	var services = map[string]map[string]int{
    33		"udp": {
    34			"domain": 53,
    35		},
    36		"tcp": {
    37			"ftp":    21,
    38			"ftps":   990,
    39			"gopher": 70, // ʕ◔ϖ◔ʔ
    40			"http":   80,
    41			"https":  443,
    42			"imap2":  143,
    43			"imap3":  220,
    44			"imaps":  993,
    45			"pop3":   110,
    46			"pop3s":  995,
    47			"smtp":   25,
    48			"ssh":    22,
    49			"telnet": 23,
    50		},
    51	}
    52	
    53	const maxProtoLength = len("RSVP-E2E-IGNORE") + 10 // with room to grow
    54	
    55	func lookupProtocolMap(name string) (int, error) {
    56		var lowerProtocol [maxProtoLength]byte
    57		n := copy(lowerProtocol[:], name)
    58		lowerASCIIBytes(lowerProtocol[:n])
    59		proto, found := protocols[string(lowerProtocol[:n])]
    60		if !found || n != len(name) {
    61			return 0, &AddrError{Err: "unknown IP protocol specified", Addr: name}
    62		}
    63		return proto, nil
    64	}
    65	
    66	const maxServiceLength = len("mobility-header") + 10 // with room to grow
    67	
    68	func lookupPortMap(network, service string) (port int, error error) {
    69		switch network {
    70		case "tcp4", "tcp6":
    71			network = "tcp"
    72		case "udp4", "udp6":
    73			network = "udp"
    74		}
    75	
    76		if m, ok := services[network]; ok {
    77			var lowerService [maxServiceLength]byte
    78			n := copy(lowerService[:], service)
    79			lowerASCIIBytes(lowerService[:n])
    80			if port, ok := m[string(lowerService[:n])]; ok && n == len(service) {
    81				return port, nil
    82			}
    83		}
    84		return 0, &AddrError{Err: "unknown port", Addr: network + "/" + service}
    85	}
    86	
    87	// DefaultResolver is the resolver used by the package-level Lookup
    88	// functions and by Dialers without a specified Resolver.
    89	var DefaultResolver = &Resolver{}
    90	
    91	// A Resolver looks up names and numbers.
    92	//
    93	// A nil *Resolver is equivalent to a zero Resolver.
    94	type Resolver struct {
    95		// PreferGo controls whether Go's built-in DNS resolver is preferred
    96		// on platforms where it's available. It is equivalent to setting
    97		// GODEBUG=netdns=go, but scoped to just this resolver.
    98		PreferGo bool
    99	
   100		// TODO(bradfitz): optional interface impl override hook
   101		// TODO(bradfitz): Timeout time.Duration?
   102	}
   103	
   104	// LookupHost looks up the given host using the local resolver.
   105	// It returns a slice of that host's addresses.
   106	func LookupHost(host string) (addrs []string, err error) {
   107		return DefaultResolver.LookupHost(context.Background(), host)
   108	}
   109	
   110	// LookupHost looks up the given host using the local resolver.
   111	// It returns a slice of that host's addresses.
   112	func (r *Resolver) LookupHost(ctx context.Context, host string) (addrs []string, err error) {
   113		// Make sure that no matter what we do later, host=="" is rejected.
   114		// ParseIP, for example, does accept empty strings.
   115		if host == "" {
   116			return nil, &DNSError{Err: errNoSuchHost.Error(), Name: host}
   117		}
   118		if ip := ParseIP(host); ip != nil {
   119			return []string{host}, nil
   120		}
   121		return r.lookupHost(ctx, host)
   122	}
   123	
   124	// LookupIP looks up host using the local resolver.
   125	// It returns a slice of that host's IPv4 and IPv6 addresses.
   126	func LookupIP(host string) ([]IP, error) {
   127		addrs, err := DefaultResolver.LookupIPAddr(context.Background(), host)
   128		if err != nil {
   129			return nil, err
   130		}
   131		ips := make([]IP, len(addrs))
   132		for i, ia := range addrs {
   133			ips[i] = ia.IP
   134		}
   135		return ips, nil
   136	}
   137	
   138	// LookupIPAddr looks up host using the local resolver.
   139	// It returns a slice of that host's IPv4 and IPv6 addresses.
   140	func (r *Resolver) LookupIPAddr(ctx context.Context, host string) ([]IPAddr, error) {
   141		// Make sure that no matter what we do later, host=="" is rejected.
   142		// ParseIP, for example, does accept empty strings.
   143		if host == "" {
   144			return nil, &DNSError{Err: errNoSuchHost.Error(), Name: host}
   145		}
   146		if ip := ParseIP(host); ip != nil {
   147			return []IPAddr{{IP: ip}}, nil
   148		}
   149		trace, _ := ctx.Value(nettrace.TraceKey{}).(*nettrace.Trace)
   150		if trace != nil && trace.DNSStart != nil {
   151			trace.DNSStart(host)
   152		}
   153		// The underlying resolver func is lookupIP by default but it
   154		// can be overridden by tests. This is needed by net/http, so it
   155		// uses a context key instead of unexported variables.
   156		resolverFunc := r.lookupIP
   157		if alt, _ := ctx.Value(nettrace.LookupIPAltResolverKey{}).(func(context.Context, string) ([]IPAddr, error)); alt != nil {
   158			resolverFunc = alt
   159		}
   160	
   161		ch := lookupGroup.DoChan(host, func() (interface{}, error) {
   162			return testHookLookupIP(ctx, resolverFunc, host)
   163		})
   164	
   165		select {
   166		case <-ctx.Done():
   167			// The DNS lookup timed out for some reason. Force
   168			// future requests to start the DNS lookup again
   169			// rather than waiting for the current lookup to
   170			// complete. See issue 8602.
   171			err := mapErr(ctx.Err())
   172			lookupGroup.Forget(host)
   173			if trace != nil && trace.DNSDone != nil {
   174				trace.DNSDone(nil, false, err)
   175			}
   176			return nil, err
   177		case r := <-ch:
   178			if trace != nil && trace.DNSDone != nil {
   179				addrs, _ := r.Val.([]IPAddr)
   180				trace.DNSDone(ipAddrsEface(addrs), r.Shared, r.Err)
   181			}
   182			return lookupIPReturn(r.Val, r.Err, r.Shared)
   183		}
   184	}
   185	
   186	// lookupGroup merges LookupIPAddr calls together for lookups
   187	// for the same host. The lookupGroup key is is the LookupIPAddr.host
   188	// argument.
   189	// The return values are ([]IPAddr, error).
   190	var lookupGroup singleflight.Group
   191	
   192	// lookupIPReturn turns the return values from singleflight.Do into
   193	// the return values from LookupIP.
   194	func lookupIPReturn(addrsi interface{}, err error, shared bool) ([]IPAddr, error) {
   195		if err != nil {
   196			return nil, err
   197		}
   198		addrs := addrsi.([]IPAddr)
   199		if shared {
   200			clone := make([]IPAddr, len(addrs))
   201			copy(clone, addrs)
   202			addrs = clone
   203		}
   204		return addrs, nil
   205	}
   206	
   207	// ipAddrsEface returns an empty interface slice of addrs.
   208	func ipAddrsEface(addrs []IPAddr) []interface{} {
   209		s := make([]interface{}, len(addrs))
   210		for i, v := range addrs {
   211			s[i] = v
   212		}
   213		return s
   214	}
   215	
   216	// LookupPort looks up the port for the given network and service.
   217	func LookupPort(network, service string) (port int, err error) {
   218		return DefaultResolver.LookupPort(context.Background(), network, service)
   219	}
   220	
   221	// LookupPort looks up the port for the given network and service.
   222	func (r *Resolver) LookupPort(ctx context.Context, network, service string) (port int, err error) {
   223		port, needsLookup := parsePort(service)
   224		if needsLookup {
   225			port, err = r.lookupPort(ctx, network, service)
   226			if err != nil {
   227				return 0, err
   228			}
   229		}
   230		if 0 > port || port > 65535 {
   231			return 0, &AddrError{Err: "invalid port", Addr: service}
   232		}
   233		return port, nil
   234	}
   235	
   236	// LookupCNAME returns the canonical name for the given host.
   237	// Callers that do not care about the canonical name can call
   238	// LookupHost or LookupIP directly; both take care of resolving
   239	// the canonical name as part of the lookup.
   240	//
   241	// A canonical name is the final name after following zero
   242	// or more CNAME records.
   243	// LookupCNAME does not return an error if host does not
   244	// contain DNS "CNAME" records, as long as host resolves to
   245	// address records.
   246	func LookupCNAME(host string) (cname string, err error) {
   247		return DefaultResolver.lookupCNAME(context.Background(), host)
   248	}
   249	
   250	// LookupCNAME returns the canonical name for the given host.
   251	// Callers that do not care about the canonical name can call
   252	// LookupHost or LookupIP directly; both take care of resolving
   253	// the canonical name as part of the lookup.
   254	//
   255	// A canonical name is the final name after following zero
   256	// or more CNAME records.
   257	// LookupCNAME does not return an error if host does not
   258	// contain DNS "CNAME" records, as long as host resolves to
   259	// address records.
   260	func (r *Resolver) LookupCNAME(ctx context.Context, host string) (cname string, err error) {
   261		return r.lookupCNAME(ctx, host)
   262	}
   263	
   264	// LookupSRV tries to resolve an SRV query of the given service,
   265	// protocol, and domain name. The proto is "tcp" or "udp".
   266	// The returned records are sorted by priority and randomized
   267	// by weight within a priority.
   268	//
   269	// LookupSRV constructs the DNS name to look up following RFC 2782.
   270	// That is, it looks up _service._proto.name. To accommodate services
   271	// publishing SRV records under non-standard names, if both service
   272	// and proto are empty strings, LookupSRV looks up name directly.
   273	func LookupSRV(service, proto, name string) (cname string, addrs []*SRV, err error) {
   274		return DefaultResolver.lookupSRV(context.Background(), service, proto, name)
   275	}
   276	
   277	// LookupSRV tries to resolve an SRV query of the given service,
   278	// protocol, and domain name. The proto is "tcp" or "udp".
   279	// The returned records are sorted by priority and randomized
   280	// by weight within a priority.
   281	//
   282	// LookupSRV constructs the DNS name to look up following RFC 2782.
   283	// That is, it looks up _service._proto.name. To accommodate services
   284	// publishing SRV records under non-standard names, if both service
   285	// and proto are empty strings, LookupSRV looks up name directly.
   286	func (r *Resolver) LookupSRV(ctx context.Context, service, proto, name string) (cname string, addrs []*SRV, err error) {
   287		return r.lookupSRV(ctx, service, proto, name)
   288	}
   289	
   290	// LookupMX returns the DNS MX records for the given domain name sorted by preference.
   291	func LookupMX(name string) ([]*MX, error) {
   292		return DefaultResolver.lookupMX(context.Background(), name)
   293	}
   294	
   295	// LookupMX returns the DNS MX records for the given domain name sorted by preference.
   296	func (r *Resolver) LookupMX(ctx context.Context, name string) ([]*MX, error) {
   297		return r.lookupMX(ctx, name)
   298	}
   299	
   300	// LookupNS returns the DNS NS records for the given domain name.
   301	func LookupNS(name string) ([]*NS, error) {
   302		return DefaultResolver.lookupNS(context.Background(), name)
   303	}
   304	
   305	// LookupNS returns the DNS NS records for the given domain name.
   306	func (r *Resolver) LookupNS(ctx context.Context, name string) ([]*NS, error) {
   307		return r.lookupNS(ctx, name)
   308	}
   309	
   310	// LookupTXT returns the DNS TXT records for the given domain name.
   311	func LookupTXT(name string) ([]string, error) {
   312		return DefaultResolver.lookupTXT(context.Background(), name)
   313	}
   314	
   315	// LookupTXT returns the DNS TXT records for the given domain name.
   316	func (r *Resolver) LookupTXT(ctx context.Context, name string) ([]string, error) {
   317		return r.lookupTXT(ctx, name)
   318	}
   319	
   320	// LookupAddr performs a reverse lookup for the given address, returning a list
   321	// of names mapping to that address.
   322	//
   323	// When using the host C library resolver, at most one result will be
   324	// returned. To bypass the host resolver, use a custom Resolver.
   325	func LookupAddr(addr string) (names []string, err error) {
   326		return DefaultResolver.lookupAddr(context.Background(), addr)
   327	}
   328	
   329	// LookupAddr performs a reverse lookup for the given address, returning a list
   330	// of names mapping to that address.
   331	func (r *Resolver) LookupAddr(ctx context.Context, addr string) (names []string, err error) {
   332		return r.lookupAddr(ctx, addr)
   333	}
   334	

View as plain text