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
5package net
6
7import (
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.
21var 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.
36var 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.
59var dnsWaitGroup sync.WaitGroup
60
61const maxProtoLength = len("RSVP-E2E-IGNORE") + 10 // with room to grow
62
63func 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.
79const maxPortBufSize = len("mobility-header") + 10
80
81func 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.
102func 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.
115var DefaultResolver = &Resolver{}
116
117// A Resolver looks up names and numbers.
118//
119// A nil *Resolver is equivalent to a zero Resolver.
120type 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
158func (r *Resolver) preferGo() bool     { return r != nil && r.PreferGo }
159func (r *Resolver) strictErrors() bool { return r != nil && r.StrictErrors }
160
161func (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.
170func 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.
176func (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}
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.
190func 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.
204func (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.
210type onlyValuesCtx struct {
211	context.Context
212	lookupValues context.Context
213}
214
215var _ context.Context = (*onlyValuesCtx)(nil)
216
217// Value performs a lookup if the original context hasn't expired.
218func (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.
231func 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.
237func (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}
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 cancelation 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.
309func 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.
323func 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.
332func 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.
337func (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.
368func 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.
382func (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.
395func 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.
408func (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.
413func 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.
418func (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.
423func 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.
428func (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.
433func 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.
438func (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.
447func 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.
453func (r *Resolver) LookupAddr(ctx context.Context, addr string) (names []string, err error) {
454	return r.lookupAddr(ctx, addr)
455}
456