Home | History | Annotate | Download | only in 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 http://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 	// TODO(bradfitz): optional interface impl override hook
    137 	// TODO(bradfitz): Timeout time.Duration?
    138 }
    139 
    140 // LookupHost looks up the given host using the local resolver.
    141 // It returns a slice of that host's addresses.
    142 func LookupHost(host string) (addrs []string, err error) {
    143 	return DefaultResolver.LookupHost(context.Background(), host)
    144 }
    145 
    146 // LookupHost looks up the given host using the local resolver.
    147 // It returns a slice of that host's addresses.
    148 func (r *Resolver) LookupHost(ctx context.Context, host string) (addrs []string, err error) {
    149 	// Make sure that no matter what we do later, host=="" is rejected.
    150 	// ParseIP, for example, does accept empty strings.
    151 	if host == "" {
    152 		return nil, &DNSError{Err: errNoSuchHost.Error(), Name: host}
    153 	}
    154 	if ip := ParseIP(host); ip != nil {
    155 		return []string{host}, nil
    156 	}
    157 	return r.lookupHost(ctx, host)
    158 }
    159 
    160 // LookupIP looks up host using the local resolver.
    161 // It returns a slice of that host's IPv4 and IPv6 addresses.
    162 func LookupIP(host string) ([]IP, error) {
    163 	addrs, err := DefaultResolver.LookupIPAddr(context.Background(), host)
    164 	if err != nil {
    165 		return nil, err
    166 	}
    167 	ips := make([]IP, len(addrs))
    168 	for i, ia := range addrs {
    169 		ips[i] = ia.IP
    170 	}
    171 	return ips, nil
    172 }
    173 
    174 // LookupIPAddr looks up host using the local resolver.
    175 // It returns a slice of that host's IPv4 and IPv6 addresses.
    176 func (r *Resolver) LookupIPAddr(ctx context.Context, host string) ([]IPAddr, 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}
    181 	}
    182 	if ip := ParseIP(host); ip != nil {
    183 		return []IPAddr{{IP: ip}}, nil
    184 	}
    185 	trace, _ := ctx.Value(nettrace.TraceKey{}).(*nettrace.Trace)
    186 	if trace != nil && trace.DNSStart != nil {
    187 		trace.DNSStart(host)
    188 	}
    189 	// The underlying resolver func is lookupIP by default but it
    190 	// can be overridden by tests. This is needed by net/http, so it
    191 	// uses a context key instead of unexported variables.
    192 	resolverFunc := r.lookupIP
    193 	if alt, _ := ctx.Value(nettrace.LookupIPAltResolverKey{}).(func(context.Context, string) ([]IPAddr, error)); alt != nil {
    194 		resolverFunc = alt
    195 	}
    196 
    197 	dnsWaitGroup.Add(1)
    198 	ch, called := lookupGroup.DoChan(host, func() (interface{}, error) {
    199 		defer dnsWaitGroup.Done()
    200 		return testHookLookupIP(ctx, resolverFunc, host)
    201 	})
    202 	if !called {
    203 		dnsWaitGroup.Done()
    204 	}
    205 
    206 	select {
    207 	case <-ctx.Done():
    208 		// If the DNS lookup timed out for some reason, force
    209 		// future requests to start the DNS lookup again
    210 		// rather than waiting for the current lookup to
    211 		// complete. See issue 8602.
    212 		ctxErr := ctx.Err()
    213 		if ctxErr == context.DeadlineExceeded {
    214 			lookupGroup.Forget(host)
    215 		}
    216 		err := mapErr(ctxErr)
    217 		if trace != nil && trace.DNSDone != nil {
    218 			trace.DNSDone(nil, false, err)
    219 		}
    220 		return nil, err
    221 	case r := <-ch:
    222 		if trace != nil && trace.DNSDone != nil {
    223 			addrs, _ := r.Val.([]IPAddr)
    224 			trace.DNSDone(ipAddrsEface(addrs), r.Shared, r.Err)
    225 		}
    226 		return lookupIPReturn(r.Val, r.Err, r.Shared)
    227 	}
    228 }
    229 
    230 // lookupGroup merges LookupIPAddr calls together for lookups
    231 // for the same host. The lookupGroup key is is the LookupIPAddr.host
    232 // argument.
    233 // The return values are ([]IPAddr, error).
    234 var lookupGroup singleflight.Group
    235 
    236 // lookupIPReturn turns the return values from singleflight.Do into
    237 // the return values from LookupIP.
    238 func lookupIPReturn(addrsi interface{}, err error, shared bool) ([]IPAddr, error) {
    239 	if err != nil {
    240 		return nil, err
    241 	}
    242 	addrs := addrsi.([]IPAddr)
    243 	if shared {
    244 		clone := make([]IPAddr, len(addrs))
    245 		copy(clone, addrs)
    246 		addrs = clone
    247 	}
    248 	return addrs, nil
    249 }
    250 
    251 // ipAddrsEface returns an empty interface slice of addrs.
    252 func ipAddrsEface(addrs []IPAddr) []interface{} {
    253 	s := make([]interface{}, len(addrs))
    254 	for i, v := range addrs {
    255 		s[i] = v
    256 	}
    257 	return s
    258 }
    259 
    260 // LookupPort looks up the port for the given network and service.
    261 func LookupPort(network, service string) (port int, err error) {
    262 	return DefaultResolver.LookupPort(context.Background(), network, service)
    263 }
    264 
    265 // LookupPort looks up the port for the given network and service.
    266 func (r *Resolver) LookupPort(ctx context.Context, network, service string) (port int, err error) {
    267 	port, needsLookup := parsePort(service)
    268 	if needsLookup {
    269 		port, err = r.lookupPort(ctx, network, service)
    270 		if err != nil {
    271 			return 0, err
    272 		}
    273 	}
    274 	if 0 > port || port > 65535 {
    275 		return 0, &AddrError{Err: "invalid port", Addr: service}
    276 	}
    277 	return port, nil
    278 }
    279 
    280 // LookupCNAME returns the canonical name for the given host.
    281 // Callers that do not care about the canonical name can call
    282 // LookupHost or LookupIP directly; both take care of resolving
    283 // the canonical name as part of the lookup.
    284 //
    285 // A canonical name is the final name after following zero
    286 // or more CNAME records.
    287 // LookupCNAME does not return an error if host does not
    288 // contain DNS "CNAME" records, as long as host resolves to
    289 // address records.
    290 func LookupCNAME(host string) (cname string, err error) {
    291 	return DefaultResolver.lookupCNAME(context.Background(), host)
    292 }
    293 
    294 // LookupCNAME returns the canonical name for the given host.
    295 // Callers that do not care about the canonical name can call
    296 // LookupHost or LookupIP directly; both take care of resolving
    297 // the canonical name as part of the lookup.
    298 //
    299 // A canonical name is the final name after following zero
    300 // or more CNAME records.
    301 // LookupCNAME does not return an error if host does not
    302 // contain DNS "CNAME" records, as long as host resolves to
    303 // address records.
    304 func (r *Resolver) LookupCNAME(ctx context.Context, host string) (cname string, err error) {
    305 	return r.lookupCNAME(ctx, host)
    306 }
    307 
    308 // LookupSRV tries to resolve an SRV query of the given service,
    309 // protocol, and domain name. The proto is "tcp" or "udp".
    310 // The returned records are sorted by priority and randomized
    311 // by weight within a priority.
    312 //
    313 // LookupSRV constructs the DNS name to look up following RFC 2782.
    314 // That is, it looks up _service._proto.name. To accommodate services
    315 // publishing SRV records under non-standard names, if both service
    316 // and proto are empty strings, LookupSRV looks up name directly.
    317 func LookupSRV(service, proto, name string) (cname string, addrs []*SRV, err error) {
    318 	return DefaultResolver.lookupSRV(context.Background(), service, proto, name)
    319 }
    320 
    321 // LookupSRV tries to resolve an SRV query of the given service,
    322 // protocol, and domain name. The proto is "tcp" or "udp".
    323 // The returned records are sorted by priority and randomized
    324 // by weight within a priority.
    325 //
    326 // LookupSRV constructs the DNS name to look up following RFC 2782.
    327 // That is, it looks up _service._proto.name. To accommodate services
    328 // publishing SRV records under non-standard names, if both service
    329 // and proto are empty strings, LookupSRV looks up name directly.
    330 func (r *Resolver) LookupSRV(ctx context.Context, service, proto, name string) (cname string, addrs []*SRV, err error) {
    331 	return r.lookupSRV(ctx, service, proto, name)
    332 }
    333 
    334 // LookupMX returns the DNS MX records for the given domain name sorted by preference.
    335 func LookupMX(name string) ([]*MX, error) {
    336 	return DefaultResolver.lookupMX(context.Background(), name)
    337 }
    338 
    339 // LookupMX returns the DNS MX records for the given domain name sorted by preference.
    340 func (r *Resolver) LookupMX(ctx context.Context, name string) ([]*MX, error) {
    341 	return r.lookupMX(ctx, name)
    342 }
    343 
    344 // LookupNS returns the DNS NS records for the given domain name.
    345 func LookupNS(name string) ([]*NS, error) {
    346 	return DefaultResolver.lookupNS(context.Background(), name)
    347 }
    348 
    349 // LookupNS returns the DNS NS records for the given domain name.
    350 func (r *Resolver) LookupNS(ctx context.Context, name string) ([]*NS, error) {
    351 	return r.lookupNS(ctx, name)
    352 }
    353 
    354 // LookupTXT returns the DNS TXT records for the given domain name.
    355 func LookupTXT(name string) ([]string, error) {
    356 	return DefaultResolver.lookupTXT(context.Background(), name)
    357 }
    358 
    359 // LookupTXT returns the DNS TXT records for the given domain name.
    360 func (r *Resolver) LookupTXT(ctx context.Context, name string) ([]string, error) {
    361 	return r.lookupTXT(ctx, name)
    362 }
    363 
    364 // LookupAddr performs a reverse lookup for the given address, returning a list
    365 // of names mapping to that address.
    366 //
    367 // When using the host C library resolver, at most one result will be
    368 // returned. To bypass the host resolver, use a custom Resolver.
    369 func LookupAddr(addr string) (names []string, err error) {
    370 	return DefaultResolver.lookupAddr(context.Background(), addr)
    371 }
    372 
    373 // LookupAddr performs a reverse lookup for the given address, returning a list
    374 // of names mapping to that address.
    375 func (r *Resolver) LookupAddr(ctx context.Context, addr string) (names []string, err error) {
    376 	return r.lookupAddr(ctx, addr)
    377 }
    378