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// LookupIP looks up host for the given network using the local resolver.
208// It returns a slice of that host's IP addresses of the type specified by
209// network.
210// network must be one of "ip", "ip4" or "ip6".
211func (r *Resolver) LookupIP(ctx context.Context, network, host string) ([]IP, error) {
212	afnet, _, err := parseNetwork(ctx, network, false)
213	if err != nil {
214		return nil, err
215	}
216	switch afnet {
217	case "ip", "ip4", "ip6":
218	default:
219		return nil, UnknownNetworkError(network)
220	}
221	addrs, err := r.internetAddrList(ctx, afnet, host)
222	if err != nil {
223		return nil, err
224	}
225	ips := make([]IP, 0, len(addrs))
226	for _, addr := range addrs {
227		ips = append(ips, addr.(*IPAddr).IP)
228	}
229	return ips, nil
230}
231
232// onlyValuesCtx is a context that uses an underlying context
233// for value lookup if the underlying context hasn't yet expired.
234type onlyValuesCtx struct {
235	context.Context
236	lookupValues context.Context
237}
238
239var _ context.Context = (*onlyValuesCtx)(nil)
240
241// Value performs a lookup if the original context hasn't expired.
242func (ovc *onlyValuesCtx) Value(key interface{}) interface{} {
243	select {
244	case <-ovc.lookupValues.Done():
245		return nil
246	default:
247		return ovc.lookupValues.Value(key)
248	}
249}
250
251// withUnexpiredValuesPreserved returns a context.Context that only uses lookupCtx
252// for its values, otherwise it is never canceled and has no deadline.
253// If the lookup context expires, any looked up values will return nil.
254// See Issue 28600.
255func withUnexpiredValuesPreserved(lookupCtx context.Context) context.Context {
256	return &onlyValuesCtx{Context: context.Background(), lookupValues: lookupCtx}
257}
258
259// lookupIPAddr looks up host using the local resolver and particular network.
260// It returns a slice of that host's IPv4 and IPv6 addresses.
261func (r *Resolver) lookupIPAddr(ctx context.Context, network, host string) ([]IPAddr, error) {
262	// Make sure that no matter what we do later, host=="" is rejected.
263	// parseIP, for example, does accept empty strings.
264	if host == "" {
265		return nil, &DNSError{Err: errNoSuchHost.Error(), Name: host, IsNotFound: true}
266	}
267	if ip, zone := parseIPZone(host); ip != nil {
268		return []IPAddr{{IP: ip, Zone: zone}}, nil
269	}
270	trace, _ := ctx.Value(nettrace.TraceKey{}).(*nettrace.Trace)
271	if trace != nil && trace.DNSStart != nil {
272		trace.DNSStart(host)
273	}
274	// The underlying resolver func is lookupIP by default but it
275	// can be overridden by tests. This is needed by net/http, so it
276	// uses a context key instead of unexported variables.
277	resolverFunc := r.lookupIP
278	if alt, _ := ctx.Value(nettrace.LookupIPAltResolverKey{}).(func(context.Context, string, string) ([]IPAddr, error)); alt != nil {
279		resolverFunc = alt
280	}
281
282	// We don't want a cancellation of ctx to affect the
283	// lookupGroup operation. Otherwise if our context gets
284	// canceled it might cause an error to be returned to a lookup
285	// using a completely different context. However we need to preserve
286	// only the values in context. See Issue 28600.
287	lookupGroupCtx, lookupGroupCancel := context.WithCancel(withUnexpiredValuesPreserved(ctx))
288
289	lookupKey := network + "\000" + host
290	dnsWaitGroup.Add(1)
291	ch, called := r.getLookupGroup().DoChan(lookupKey, func() (interface{}, error) {
292		defer dnsWaitGroup.Done()
293		return testHookLookupIP(lookupGroupCtx, resolverFunc, network, host)
294	})
295	if !called {
296		dnsWaitGroup.Done()
297	}
298
299	select {
300	case <-ctx.Done():
301		// Our context was canceled. If we are the only
302		// goroutine looking up this key, then drop the key
303		// from the lookupGroup and cancel the lookup.
304		// If there are other goroutines looking up this key,
305		// let the lookup continue uncanceled, and let later
306		// lookups with the same key share the result.
307		// See issues 8602, 20703, 22724.
308		if r.getLookupGroup().ForgetUnshared(lookupKey) {
309			lookupGroupCancel()
310		} else {
311			go func() {
312				<-ch
313				lookupGroupCancel()
314			}()
315		}
316		err := mapErr(ctx.Err())
317		if trace != nil && trace.DNSDone != nil {
318			trace.DNSDone(nil, false, err)
319		}
320		return nil, err
321	case r := <-ch:
322		lookupGroupCancel()
323		if trace != nil && trace.DNSDone != nil {
324			addrs, _ := r.Val.([]IPAddr)
325			trace.DNSDone(ipAddrsEface(addrs), r.Shared, r.Err)
326		}
327		return lookupIPReturn(r.Val, r.Err, r.Shared)
328	}
329}
330
331// lookupIPReturn turns the return values from singleflight.Do into
332// the return values from LookupIP.
333func lookupIPReturn(addrsi interface{}, err error, shared bool) ([]IPAddr, error) {
334	if err != nil {
335		return nil, err
336	}
337	addrs := addrsi.([]IPAddr)
338	if shared {
339		clone := make([]IPAddr, len(addrs))
340		copy(clone, addrs)
341		addrs = clone
342	}
343	return addrs, nil
344}
345
346// ipAddrsEface returns an empty interface slice of addrs.
347func ipAddrsEface(addrs []IPAddr) []interface{} {
348	s := make([]interface{}, len(addrs))
349	for i, v := range addrs {
350		s[i] = v
351	}
352	return s
353}
354
355// LookupPort looks up the port for the given network and service.
356func LookupPort(network, service string) (port int, err error) {
357	return DefaultResolver.LookupPort(context.Background(), network, service)
358}
359
360// LookupPort looks up the port for the given network and service.
361func (r *Resolver) LookupPort(ctx context.Context, network, service string) (port int, err error) {
362	port, needsLookup := parsePort(service)
363	if needsLookup {
364		switch network {
365		case "tcp", "tcp4", "tcp6", "udp", "udp4", "udp6":
366		case "": // a hint wildcard for Go 1.0 undocumented behavior
367			network = "ip"
368		default:
369			return 0, &AddrError{Err: "unknown network", Addr: network}
370		}
371		port, err = r.lookupPort(ctx, network, service)
372		if err != nil {
373			return 0, err
374		}
375	}
376	if 0 > port || port > 65535 {
377		return 0, &AddrError{Err: "invalid port", Addr: service}
378	}
379	return port, nil
380}
381
382// LookupCNAME returns the canonical name for the given host.
383// Callers that do not care about the canonical name can call
384// LookupHost or LookupIP directly; both take care of resolving
385// the canonical name as part of the lookup.
386//
387// A canonical name is the final name after following zero
388// or more CNAME records.
389// LookupCNAME does not return an error if host does not
390// contain DNS "CNAME" records, as long as host resolves to
391// address records.
392//
393// The returned canonical name is validated to be a properly
394// formatted presentation-format domain name.
395func LookupCNAME(host string) (cname string, err error) {
396	return DefaultResolver.LookupCNAME(context.Background(), host)
397}
398
399// LookupCNAME returns the canonical name for the given host.
400// Callers that do not care about the canonical name can call
401// LookupHost or LookupIP directly; both take care of resolving
402// the canonical name as part of the lookup.
403//
404// A canonical name is the final name after following zero
405// or more CNAME records.
406// LookupCNAME does not return an error if host does not
407// contain DNS "CNAME" records, as long as host resolves to
408// address records.
409//
410// The returned canonical name is validated to be a properly
411// formatted presentation-format domain name.
412func (r *Resolver) LookupCNAME(ctx context.Context, host string) (string, error) {
413	cname, err := r.lookupCNAME(ctx, host)
414	if err != nil {
415		return "", err
416	}
417	if !isDomainName(cname) {
418		return "", &DNSError{Err: "CNAME target is invalid", Name: host}
419	}
420	return cname, nil
421}
422
423// LookupSRV tries to resolve an SRV query of the given service,
424// protocol, and domain name. The proto is "tcp" or "udp".
425// The returned records are sorted by priority and randomized
426// by weight within a priority.
427//
428// LookupSRV constructs the DNS name to look up following RFC 2782.
429// That is, it looks up _service._proto.name. To accommodate services
430// publishing SRV records under non-standard names, if both service
431// and proto are empty strings, LookupSRV looks up name directly.
432//
433// The returned service names are validated to be properly
434// formatted presentation-format domain names.
435func LookupSRV(service, proto, name string) (cname string, addrs []*SRV, err error) {
436	return DefaultResolver.LookupSRV(context.Background(), service, proto, name)
437}
438
439// LookupSRV tries to resolve an SRV query of the given service,
440// protocol, and domain name. The proto is "tcp" or "udp".
441// The returned records are sorted by priority and randomized
442// by weight within a priority.
443//
444// LookupSRV constructs the DNS name to look up following RFC 2782.
445// That is, it looks up _service._proto.name. To accommodate services
446// publishing SRV records under non-standard names, if both service
447// and proto are empty strings, LookupSRV looks up name directly.
448//
449// The returned service names are validated to be properly
450// formatted presentation-format domain names.
451func (r *Resolver) LookupSRV(ctx context.Context, service, proto, name string) (string, []*SRV, error) {
452	cname, addrs, err := r.lookupSRV(ctx, service, proto, name)
453	if err != nil {
454		return "", nil, err
455	}
456	if cname != "" && !isDomainName(cname) {
457		return "", nil, &DNSError{Err: "SRV header name is invalid", Name: name}
458	}
459	for _, addr := range addrs {
460		if addr == nil {
461			continue
462		}
463		if !isDomainName(addr.Target) {
464			return "", nil, &DNSError{Err: "SRV target is invalid", Name: name}
465		}
466	}
467	return cname, addrs, nil
468}
469
470// LookupMX returns the DNS MX records for the given domain name sorted by preference.
471//
472// The returned mail server names are validated to be properly
473// formatted presentation-format domain names.
474func LookupMX(name string) ([]*MX, error) {
475	return DefaultResolver.LookupMX(context.Background(), name)
476}
477
478// LookupMX returns the DNS MX records for the given domain name sorted by preference.
479//
480// The returned mail server names are validated to be properly
481// formatted presentation-format domain names.
482func (r *Resolver) LookupMX(ctx context.Context, name string) ([]*MX, error) {
483	records, err := r.lookupMX(ctx, name)
484	if err != nil {
485		return nil, err
486	}
487	for _, mx := range records {
488		if mx == nil {
489			continue
490		}
491		if !isDomainName(mx.Host) {
492			return nil, &DNSError{Err: "MX target is invalid", Name: name}
493		}
494	}
495	return records, nil
496}
497
498// LookupNS returns the DNS NS records for the given domain name.
499//
500// The returned name server names are validated to be properly
501// formatted presentation-format domain names.
502func LookupNS(name string) ([]*NS, error) {
503	return DefaultResolver.LookupNS(context.Background(), name)
504}
505
506// LookupNS returns the DNS NS records for the given domain name.
507//
508// The returned name server names are validated to be properly
509// formatted presentation-format domain names.
510func (r *Resolver) LookupNS(ctx context.Context, name string) ([]*NS, error) {
511	records, err := r.lookupNS(ctx, name)
512	if err != nil {
513		return nil, err
514	}
515	for _, ns := range records {
516		if ns == nil {
517			continue
518		}
519		if !isDomainName(ns.Host) {
520			return nil, &DNSError{Err: "NS target is invalid", Name: name}
521		}
522	}
523	return records, nil
524}
525
526// LookupTXT returns the DNS TXT records for the given domain name.
527func LookupTXT(name string) ([]string, error) {
528	return DefaultResolver.lookupTXT(context.Background(), name)
529}
530
531// LookupTXT returns the DNS TXT records for the given domain name.
532func (r *Resolver) LookupTXT(ctx context.Context, name string) ([]string, error) {
533	return r.lookupTXT(ctx, name)
534}
535
536// LookupAddr performs a reverse lookup for the given address, returning a list
537// of names mapping to that address.
538//
539// The returned names are validated to be properly formatted presentation-format
540// domain names.
541//
542// When using the host C library resolver, at most one result will be
543// returned. To bypass the host resolver, use a custom Resolver.
544func LookupAddr(addr string) (names []string, err error) {
545	return DefaultResolver.LookupAddr(context.Background(), addr)
546}
547
548// LookupAddr performs a reverse lookup for the given address, returning a list
549// of names mapping to that address.
550//
551// The returned names are validated to be properly formatted presentation-format
552// domain names.
553func (r *Resolver) LookupAddr(ctx context.Context, addr string) ([]string, error) {
554	names, err := r.lookupAddr(ctx, addr)
555	if err != nil {
556		return nil, err
557	}
558	for _, name := range names {
559		if !isDomainName(name) {
560			return nil, &DNSError{Err: "PTR target is invalid", Name: addr}
561		}
562	}
563	return names, nil
564}
565