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 )
     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