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//
32// See https://www.iana.org/assignments/service-names-port-numbers
33//
34// On Unix, this map is augmented by readServices via goLookupPort.
35var 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// dnsWaitGroup can be used by tests to wait for all DNS goroutines to
57// complete. This avoids races on the test hooks.
58var dnsWaitGroup sync.WaitGroup
59
60const maxProtoLength = len("RSVP-E2E-IGNORE") + 10 // with room to grow
61
62func lookupProtocolMap(name string) (int, error) {
63	var lowerProtocol [maxProtoLength]byte
64	n := copy(lowerProtocol[:], name)
65	lowerASCIIBytes(lowerProtocol[:n])
66	proto, found := protocols[string(lowerProtocol[:n])]
67	if !found || n != len(name) {
68		return 0, &AddrError{Err: "unknown IP protocol specified", Addr: name}
69	}
70	return proto, nil
71}
72
73// maxPortBufSize is the longest reasonable name of a service
74// (non-numeric port).
75// Currently the longest known IANA-unregistered name is
76// "mobility-header", so we use that length, plus some slop in case
77// something longer is added in the future.
78const maxPortBufSize = len("mobility-header") + 10
79
80func lookupPortMap(network, service string) (port int, error error) {
81	switch network {
82	case "tcp4", "tcp6":
83		network = "tcp"
84	case "udp4", "udp6":
85		network = "udp"
86	}
87
88	if m, ok := services[network]; ok {
89		var lowerService [maxPortBufSize]byte
90		n := copy(lowerService[:], service)
91		lowerASCIIBytes(lowerService[:n])
92		if port, ok := m[string(lowerService[:n])]; ok && n == len(service) {
93			return port, nil
94		}
95	}
96	return 0, &AddrError{Err: "unknown port", Addr: network + "/" + service}
97}
98
99// ipVersion returns the provided network's IP version: '4', '6' or 0
100// if network does not end in a '4' or '6' byte.
101func ipVersion(network string) byte {
102	if network == "" {
103		return 0
104	}
105	n := network[len(network)-1]
106	if n != '4' && n != '6' {
107		n = 0
108	}
109	return n
110}
111
112// DefaultResolver is the resolver used by the package-level Lookup
113// functions and by Dialers without a specified Resolver.
114var DefaultResolver = &Resolver{}
115
116// A Resolver looks up names and numbers.
117//
118// A nil *Resolver is equivalent to a zero Resolver.
119type Resolver struct {
120	// PreferGo controls whether Go's built-in DNS resolver is preferred
121	// on platforms where it's available. It is equivalent to setting
122	// GODEBUG=netdns=go, but scoped to just this resolver.
123	PreferGo bool
124
125	// StrictErrors controls the behavior of temporary errors
126	// (including timeout, socket errors, and SERVFAIL) when using
127	// Go's built-in resolver. For a query composed of multiple
128	// sub-queries (such as an A+AAAA address lookup, or walking the
129	// DNS search list), this option causes such errors to abort the
130	// whole query instead of returning a partial result. This is
131	// not enabled by default because it may affect compatibility
132	// with resolvers that process AAAA queries incorrectly.
133	StrictErrors bool
134
135	// Dial optionally specifies an alternate dialer for use by
136	// Go's built-in DNS resolver to make TCP and UDP connections
137	// to DNS services. The host in the address parameter will
138	// always be a literal IP address and not a host name, and the
139	// port in the address parameter will be a literal port number
140	// and not a service name.
141	// If the Conn returned is also a PacketConn, sent and received DNS
142	// messages must adhere to RFC 1035 section 4.2.1, "UDP usage".
143	// Otherwise, DNS messages transmitted over Conn must adhere
144	// to RFC 7766 section 5, "Transport Protocol Selection".
145	// If nil, the default dialer is used.
146	Dial func(ctx context.Context, network, address string) (Conn, error)
147
148	// lookupGroup merges LookupIPAddr calls together for lookups for the same
149	// host. The lookupGroup key is the LookupIPAddr.host argument.
150	// The return values are ([]IPAddr, error).
151	lookupGroup singleflight.Group
152
153	// TODO(bradfitz): optional interface impl override hook
154	// TODO(bradfitz): Timeout time.Duration?
155}
156
157func (r *Resolver) preferGo() bool     { return r != nil && r.PreferGo }
158func (r *Resolver) strictErrors() bool { return r != nil && r.StrictErrors }
159
160func (r *Resolver) getLookupGroup() *singleflight.Group {
161	if r == nil {
162		return &DefaultResolver.lookupGroup
163	}
164	return &r.lookupGroup
165}
166
167// LookupHost looks up the given host using the local resolver.
168// It returns a slice of that host's addresses.
169func LookupHost(host string) (addrs []string, err error) {
170	return DefaultResolver.LookupHost(context.Background(), host)
171}
172
173// LookupHost looks up the given host using the local resolver.
174// It returns a slice of that host's addresses.
175func (r *Resolver) LookupHost(ctx context.Context, host string) (addrs []string, err error) {
176	// Make sure that no matter what we do later, host=="" is rejected.
177	// parseIP, for example, does accept empty strings.
178	if host == "" {
179		return nil, &DNSError{Err: errNoSuchHost.Error(), Name: host, IsNotFound: true}
180	}
181	if ip, _ := parseIPZone(host); ip != nil {
182		return []string{host}, nil
183	}
184	return r.lookupHost(ctx, host)
185}
186
187// LookupIP looks up host using the local resolver.
188// It returns a slice of that host's IPv4 and IPv6 addresses.
189func LookupIP(host string) ([]IP, error) {
190	addrs, err := DefaultResolver.LookupIPAddr(context.Background(), host)
191	if err != nil {
192		return nil, err
193	}
194	ips := make([]IP, len(addrs))
195	for i, ia := range addrs {
196		ips[i] = ia.IP
197	}
198	return ips, nil
199}
200
201// LookupIPAddr looks up host using the local resolver.
202// It returns a slice of that host's IPv4 and IPv6 addresses.
203func (r *Resolver) LookupIPAddr(ctx context.Context, host string) ([]IPAddr, error) {
204	return r.lookupIPAddr(ctx, "ip", host)
205}
206
207// onlyValuesCtx is a context that uses an underlying context
208// for value lookup if the underlying context hasn't yet expired.
209type onlyValuesCtx struct {
210	context.Context
211	lookupValues context.Context
212}
213
214var _ context.Context = (*onlyValuesCtx)(nil)
215
216// Value performs a lookup if the original context hasn't expired.
217func (ovc *onlyValuesCtx) Value(key interface{}) interface{} {
218	select {
219	case <-ovc.lookupValues.Done():
220		return nil
221	default:
222		return ovc.lookupValues.Value(key)
223	}
224}
225
226// withUnexpiredValuesPreserved returns a context.Context that only uses lookupCtx
227// for its values, otherwise it is never canceled and has no deadline.
228// If the lookup context expires, any looked up values will return nil.
229// See Issue 28600.
230func withUnexpiredValuesPreserved(lookupCtx context.Context) context.Context {
231	return &onlyValuesCtx{Context: context.Background(), lookupValues: lookupCtx}
232}
233
234// lookupIPAddr looks up host using the local resolver and particular network.
235// It returns a slice of that host's IPv4 and IPv6 addresses.
236func (r *Resolver) lookupIPAddr(ctx context.Context, network, host string) ([]IPAddr, error) {
237	// Make sure that no matter what we do later, host=="" is rejected.
238	// parseIP, for example, does accept empty strings.
239	if host == "" {
240		return nil, &DNSError{Err: errNoSuchHost.Error(), Name: host, IsNotFound: true}
241	}
242	if ip, zone := parseIPZone(host); ip != nil {
243		return []IPAddr{{IP: ip, Zone: zone}}, nil
244	}
245	trace, _ := ctx.Value(nettrace.TraceKey{}).(*nettrace.Trace)
246	if trace != nil && trace.DNSStart != nil {
247		trace.DNSStart(host)
248	}
249	// The underlying resolver func is lookupIP by default but it
250	// can be overridden by tests. This is needed by net/http, so it
251	// uses a context key instead of unexported variables.
252	resolverFunc := r.lookupIP
253	if alt, _ := ctx.Value(nettrace.LookupIPAltResolverKey{}).(func(context.Context, string, string) ([]IPAddr, error)); alt != nil {
254		resolverFunc = alt
255	}
256
257	// We don't want a cancellation of ctx to affect the
258	// lookupGroup operation. Otherwise if our context gets
259	// canceled it might cause an error to be returned to a lookup
260	// using a completely different context. However we need to preserve
261	// only the values in context. See Issue 28600.
262	lookupGroupCtx, lookupGroupCancel := context.WithCancel(withUnexpiredValuesPreserved(ctx))
263
264	lookupKey := network + "\000" + host
265	dnsWaitGroup.Add(1)
266	ch, called := r.getLookupGroup().DoChan(lookupKey, func() (interface{}, error) {
267		defer dnsWaitGroup.Done()
268		return testHookLookupIP(lookupGroupCtx, resolverFunc, network, host)
269	})
270	if !called {
271		dnsWaitGroup.Done()
272	}
273
274	select {
275	case <-ctx.Done():
276		// Our context was canceled. If we are the only
277		// goroutine looking up this key, then drop the key
278		// from the lookupGroup and cancel the lookup.
279		// If there are other goroutines looking up this key,
280		// let the lookup continue uncanceled, and let later
281		// lookups with the same key share the result.
282		// See issues 8602, 20703, 22724.
283		if r.getLookupGroup().ForgetUnshared(lookupKey) {
284			lookupGroupCancel()
285		} else {
286			go func() {
287				<-ch
288				lookupGroupCancel()
289			}()
290		}
291		err := mapErr(ctx.Err())
292		if trace != nil && trace.DNSDone != nil {
293			trace.DNSDone(nil, false, err)
294		}
295		return nil, err
296	case r := <-ch:
297		lookupGroupCancel()
298		if trace != nil && trace.DNSDone != nil {
299			addrs, _ := r.Val.([]IPAddr)
300			trace.DNSDone(ipAddrsEface(addrs), r.Shared, r.Err)
301		}
302		return lookupIPReturn(r.Val, r.Err, r.Shared)
303	}
304}
305
306// lookupIPReturn turns the return values from singleflight.Do into
307// the return values from LookupIP.
308func lookupIPReturn(addrsi interface{}, err error, shared bool) ([]IPAddr, error) {
309	if err != nil {
310		return nil, err
311	}
312	addrs := addrsi.([]IPAddr)
313	if shared {
314		clone := make([]IPAddr, len(addrs))
315		copy(clone, addrs)
316		addrs = clone
317	}
318	return addrs, nil
319}
320
321// ipAddrsEface returns an empty interface slice of addrs.
322func ipAddrsEface(addrs []IPAddr) []interface{} {
323	s := make([]interface{}, len(addrs))
324	for i, v := range addrs {
325		s[i] = v
326	}
327	return s
328}
329
330// LookupPort looks up the port for the given network and service.
331func LookupPort(network, service string) (port int, err error) {
332	return DefaultResolver.LookupPort(context.Background(), network, service)
333}
334
335// LookupPort looks up the port for the given network and service.
336func (r *Resolver) LookupPort(ctx context.Context, network, service string) (port int, err error) {
337	port, needsLookup := parsePort(service)
338	if needsLookup {
339		switch network {
340		case "tcp", "tcp4", "tcp6", "udp", "udp4", "udp6":
341		case "": // a hint wildcard for Go 1.0 undocumented behavior
342			network = "ip"
343		default:
344			return 0, &AddrError{Err: "unknown network", Addr: network}
345		}
346		port, err = r.lookupPort(ctx, network, service)
347		if err != nil {
348			return 0, err
349		}
350	}
351	if 0 > port || port > 65535 {
352		return 0, &AddrError{Err: "invalid port", Addr: service}
353	}
354	return port, nil
355}
356
357// LookupCNAME returns the canonical name for the given host.
358// Callers that do not care about the canonical name can call
359// LookupHost or LookupIP directly; both take care of resolving
360// the canonical name as part of the lookup.
361//
362// A canonical name is the final name after following zero
363// or more CNAME records.
364// LookupCNAME does not return an error if host does not
365// contain DNS "CNAME" records, as long as host resolves to
366// address records.
367func LookupCNAME(host string) (cname string, err error) {
368	return DefaultResolver.lookupCNAME(context.Background(), host)
369}
370
371// LookupCNAME returns the canonical name for the given host.
372// Callers that do not care about the canonical name can call
373// LookupHost or LookupIP directly; both take care of resolving
374// the canonical name as part of the lookup.
375//
376// A canonical name is the final name after following zero
377// or more CNAME records.
378// LookupCNAME does not return an error if host does not
379// contain DNS "CNAME" records, as long as host resolves to
380// address records.
381func (r *Resolver) LookupCNAME(ctx context.Context, host string) (cname string, err error) {
382	return r.lookupCNAME(ctx, host)
383}
384
385// LookupSRV tries to resolve an SRV query of the given service,
386// protocol, and domain name. The proto is "tcp" or "udp".
387// The returned records are sorted by priority and randomized
388// by weight within a priority.
389//
390// LookupSRV constructs the DNS name to look up following RFC 2782.
391// That is, it looks up _service._proto.name. To accommodate services
392// publishing SRV records under non-standard names, if both service
393// and proto are empty strings, LookupSRV looks up name directly.
394func LookupSRV(service, proto, name string) (cname string, addrs []*SRV, err error) {
395	return DefaultResolver.lookupSRV(context.Background(), service, proto, name)
396}
397
398// LookupSRV tries to resolve an SRV query of the given service,
399// protocol, and domain name. The proto is "tcp" or "udp".
400// The returned records are sorted by priority and randomized
401// by weight within a priority.
402//
403// LookupSRV constructs the DNS name to look up following RFC 2782.
404// That is, it looks up _service._proto.name. To accommodate services
405// publishing SRV records under non-standard names, if both service
406// and proto are empty strings, LookupSRV looks up name directly.
407func (r *Resolver) LookupSRV(ctx context.Context, service, proto, name string) (cname string, addrs []*SRV, err error) {
408	return r.lookupSRV(ctx, service, proto, name)
409}
410
411// LookupMX returns the DNS MX records for the given domain name sorted by preference.
412func LookupMX(name string) ([]*MX, error) {
413	return DefaultResolver.lookupMX(context.Background(), name)
414}
415
416// LookupMX returns the DNS MX records for the given domain name sorted by preference.
417func (r *Resolver) LookupMX(ctx context.Context, name string) ([]*MX, error) {
418	return r.lookupMX(ctx, name)
419}
420
421// LookupNS returns the DNS NS records for the given domain name.
422func LookupNS(name string) ([]*NS, error) {
423	return DefaultResolver.lookupNS(context.Background(), name)
424}
425
426// LookupNS returns the DNS NS records for the given domain name.
427func (r *Resolver) LookupNS(ctx context.Context, name string) ([]*NS, error) {
428	return r.lookupNS(ctx, name)
429}
430
431// LookupTXT returns the DNS TXT records for the given domain name.
432func LookupTXT(name string) ([]string, error) {
433	return DefaultResolver.lookupTXT(context.Background(), name)
434}
435
436// LookupTXT returns the DNS TXT records for the given domain name.
437func (r *Resolver) LookupTXT(ctx context.Context, name string) ([]string, error) {
438	return r.lookupTXT(ctx, name)
439}
440
441// LookupAddr performs a reverse lookup for the given address, returning a list
442// of names mapping to that address.
443//
444// When using the host C library resolver, at most one result will be
445// returned. To bypass the host resolver, use a custom Resolver.
446func LookupAddr(addr string) (names []string, err error) {
447	return DefaultResolver.lookupAddr(context.Background(), addr)
448}
449
450// LookupAddr performs a reverse lookup for the given address, returning a list
451// of names mapping to that address.
452func (r *Resolver) LookupAddr(ctx context.Context, addr string) (names []string, err error) {
453	return r.lookupAddr(ctx, addr)
454}
455