github.com/hlts2/go@v0.0.0-20170904000733-812b34efaed8/src/net/lookup.go (about)

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