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	"errors"
10	"internal/nettrace"
11	"internal/singleflight"
12	"net/netip"
13	"sync"
14
15	"golang.org/x/net/dns/dnsmessage"
16)
17
18// protocols contains minimal mappings between internet protocol
19// names and numbers for platforms that don't have a complete list of
20// protocol numbers.
21//
22// See https://www.iana.org/assignments/protocol-numbers
23//
24// On Unix, this map is augmented by readProtocols via lookupProtocol.
25var protocols = map[string]int{
26	"icmp":      1,
27	"igmp":      2,
28	"tcp":       6,
29	"udp":       17,
30	"ipv6-icmp": 58,
31}
32
33// services contains minimal mappings between services names and port
34// numbers for platforms that don't have a complete list of port numbers.
35//
36// See https://www.iana.org/assignments/service-names-port-numbers
37//
38// On Unix, this map is augmented by readServices via goLookupPort.
39var services = map[string]map[string]int{
40	"udp": {
41		"domain": 53,
42	},
43	"tcp": {
44		"ftp":         21,
45		"ftps":        990,
46		"gopher":      70, // ʕ◔ϖ◔ʔ
47		"http":        80,
48		"https":       443,
49		"imap2":       143,
50		"imap3":       220,
51		"imaps":       993,
52		"pop3":        110,
53		"pop3s":       995,
54		"smtp":        25,
55		"submissions": 465,
56		"ssh":         22,
57		"telnet":      23,
58	},
59}
60
61// dnsWaitGroup can be used by tests to wait for all DNS goroutines to
62// complete. This avoids races on the test hooks.
63var dnsWaitGroup sync.WaitGroup
64
65const maxProtoLength = len("RSVP-E2E-IGNORE") + 10 // with room to grow
66
67func lookupProtocolMap(name string) (int, error) {
68	var lowerProtocol [maxProtoLength]byte
69	n := copy(lowerProtocol[:], name)
70	lowerASCIIBytes(lowerProtocol[:n])
71	proto, found := protocols[string(lowerProtocol[:n])]
72	if !found || n != len(name) {
73		return 0, &AddrError{Err: "unknown IP protocol specified", Addr: name}
74	}
75	return proto, nil
76}
77
78// maxPortBufSize is the longest reasonable name of a service
79// (non-numeric port).
80// Currently the longest known IANA-unregistered name is
81// "mobility-header", so we use that length, plus some slop in case
82// something longer is added in the future.
83const maxPortBufSize = len("mobility-header") + 10
84
85func lookupPortMap(network, service string) (port int, error error) {
86	switch network {
87	case "ip": // no hints
88		if p, err := lookupPortMapWithNetwork("tcp", "ip", service); err == nil {
89			return p, nil
90		}
91		return lookupPortMapWithNetwork("udp", "ip", service)
92	case "tcp", "tcp4", "tcp6":
93		return lookupPortMapWithNetwork("tcp", "tcp", service)
94	case "udp", "udp4", "udp6":
95		return lookupPortMapWithNetwork("udp", "udp", service)
96	}
97	return 0, &DNSError{Err: "unknown network", Name: network + "/" + service}
98}
99
100func lookupPortMapWithNetwork(network, errNetwork, service string) (port int, error error) {
101	if m, ok := services[network]; ok {
102		var lowerService [maxPortBufSize]byte
103		n := copy(lowerService[:], service)
104		lowerASCIIBytes(lowerService[:n])
105		if port, ok := m[string(lowerService[:n])]; ok && n == len(service) {
106			return port, nil
107		}
108		return 0, newDNSError(errUnknownPort, errNetwork+"/"+service, "")
109	}
110	return 0, &DNSError{Err: "unknown network", Name: errNetwork + "/" + service}
111}
112
113// ipVersion returns the provided network's IP version: '4', '6' or 0
114// if network does not end in a '4' or '6' byte.
115func ipVersion(network string) byte {
116	if network == "" {
117		return 0
118	}
119	n := network[len(network)-1]
120	if n != '4' && n != '6' {
121		n = 0
122	}
123	return n
124}
125
126// DefaultResolver is the resolver used by the package-level Lookup
127// functions and by Dialers without a specified Resolver.
128var DefaultResolver = &Resolver{}
129
130// A Resolver looks up names and numbers.
131//
132// A nil *Resolver is equivalent to a zero Resolver.
133type Resolver struct {
134	// PreferGo controls whether Go's built-in DNS resolver is preferred
135	// on platforms where it's available. It is equivalent to setting
136	// GODEBUG=netdns=go, but scoped to just this resolver.
137	PreferGo bool
138
139	// StrictErrors controls the behavior of temporary errors
140	// (including timeout, socket errors, and SERVFAIL) when using
141	// Go's built-in resolver. For a query composed of multiple
142	// sub-queries (such as an A+AAAA address lookup, or walking the
143	// DNS search list), this option causes such errors to abort the
144	// whole query instead of returning a partial result. This is
145	// not enabled by default because it may affect compatibility
146	// with resolvers that process AAAA queries incorrectly.
147	StrictErrors bool
148
149	// Dial optionally specifies an alternate dialer for use by
150	// Go's built-in DNS resolver to make TCP and UDP connections
151	// to DNS services. The host in the address parameter will
152	// always be a literal IP address and not a host name, and the
153	// port in the address parameter will be a literal port number
154	// and not a service name.
155	// If the Conn returned is also a PacketConn, sent and received DNS
156	// messages must adhere to RFC 1035 section 4.2.1, "UDP usage".
157	// Otherwise, DNS messages transmitted over Conn must adhere
158	// to RFC 7766 section 5, "Transport Protocol Selection".
159	// If nil, the default dialer is used.
160	Dial func(ctx context.Context, network, address string) (Conn, error)
161
162	// lookupGroup merges LookupIPAddr calls together for lookups for the same
163	// host. The lookupGroup key is the LookupIPAddr.host argument.
164	// The return values are ([]IPAddr, error).
165	lookupGroup singleflight.Group
166
167	// TODO(bradfitz): optional interface impl override hook
168	// TODO(bradfitz): Timeout time.Duration?
169}
170
171func (r *Resolver) preferGo() bool     { return r != nil && r.PreferGo }
172func (r *Resolver) strictErrors() bool { return r != nil && r.StrictErrors }
173
174func (r *Resolver) getLookupGroup() *singleflight.Group {
175	if r == nil {
176		return &DefaultResolver.lookupGroup
177	}
178	return &r.lookupGroup
179}
180
181// LookupHost looks up the given host using the local resolver.
182// It returns a slice of that host's addresses.
183//
184// LookupHost uses [context.Background] internally; to specify the context, use
185// [Resolver.LookupHost].
186func LookupHost(host string) (addrs []string, err error) {
187	return DefaultResolver.LookupHost(context.Background(), host)
188}
189
190// LookupHost looks up the given host using the local resolver.
191// It returns a slice of that host's addresses.
192func (r *Resolver) LookupHost(ctx context.Context, host string) (addrs []string, err error) {
193	// Make sure that no matter what we do later, host=="" is rejected.
194	if host == "" {
195		return nil, newDNSError(errNoSuchHost, host, "")
196	}
197	if _, err := netip.ParseAddr(host); err == nil {
198		return []string{host}, nil
199	}
200	return r.lookupHost(ctx, host)
201}
202
203// LookupIP looks up host using the local resolver.
204// It returns a slice of that host's IPv4 and IPv6 addresses.
205func LookupIP(host string) ([]IP, error) {
206	addrs, err := DefaultResolver.LookupIPAddr(context.Background(), host)
207	if err != nil {
208		return nil, err
209	}
210	ips := make([]IP, len(addrs))
211	for i, ia := range addrs {
212		ips[i] = ia.IP
213	}
214	return ips, nil
215}
216
217// LookupIPAddr looks up host using the local resolver.
218// It returns a slice of that host's IPv4 and IPv6 addresses.
219func (r *Resolver) LookupIPAddr(ctx context.Context, host string) ([]IPAddr, error) {
220	return r.lookupIPAddr(ctx, "ip", host)
221}
222
223// LookupIP looks up host for the given network using the local resolver.
224// It returns a slice of that host's IP addresses of the type specified by
225// network.
226// network must be one of "ip", "ip4" or "ip6".
227func (r *Resolver) LookupIP(ctx context.Context, network, host string) ([]IP, error) {
228	afnet, _, err := parseNetwork(ctx, network, false)
229	if err != nil {
230		return nil, err
231	}
232	switch afnet {
233	case "ip", "ip4", "ip6":
234	default:
235		return nil, UnknownNetworkError(network)
236	}
237
238	if host == "" {
239		return nil, newDNSError(errNoSuchHost, host, "")
240	}
241	addrs, err := r.internetAddrList(ctx, afnet, host)
242	if err != nil {
243		return nil, err
244	}
245
246	ips := make([]IP, 0, len(addrs))
247	for _, addr := range addrs {
248		ips = append(ips, addr.(*IPAddr).IP)
249	}
250	return ips, nil
251}
252
253// LookupNetIP looks up host using the local resolver.
254// It returns a slice of that host's IP addresses of the type specified by
255// network.
256// The network must be one of "ip", "ip4" or "ip6".
257func (r *Resolver) LookupNetIP(ctx context.Context, network, host string) ([]netip.Addr, error) {
258	// TODO(bradfitz): make this efficient, making the internal net package
259	// type throughout be netip.Addr and only converting to the net.IP slice
260	// version at the edge. But for now (2021-10-20), this is a wrapper around
261	// the old way.
262	ips, err := r.LookupIP(ctx, network, host)
263	if err != nil {
264		return nil, err
265	}
266	ret := make([]netip.Addr, 0, len(ips))
267	for _, ip := range ips {
268		if a, ok := netip.AddrFromSlice(ip); ok {
269			ret = append(ret, a)
270		}
271	}
272	return ret, nil
273}
274
275// onlyValuesCtx is a context that uses an underlying context
276// for value lookup if the underlying context hasn't yet expired.
277type onlyValuesCtx struct {
278	context.Context
279	lookupValues context.Context
280}
281
282var _ context.Context = (*onlyValuesCtx)(nil)
283
284// Value performs a lookup if the original context hasn't expired.
285func (ovc *onlyValuesCtx) Value(key any) any {
286	select {
287	case <-ovc.lookupValues.Done():
288		return nil
289	default:
290		return ovc.lookupValues.Value(key)
291	}
292}
293
294// withUnexpiredValuesPreserved returns a context.Context that only uses lookupCtx
295// for its values, otherwise it is never canceled and has no deadline.
296// If the lookup context expires, any looked up values will return nil.
297// See Issue 28600.
298func withUnexpiredValuesPreserved(lookupCtx context.Context) context.Context {
299	return &onlyValuesCtx{Context: context.Background(), lookupValues: lookupCtx}
300}
301
302// lookupIPAddr looks up host using the local resolver and particular network.
303// It returns a slice of that host's IPv4 and IPv6 addresses.
304func (r *Resolver) lookupIPAddr(ctx context.Context, network, host string) ([]IPAddr, error) {
305	// Make sure that no matter what we do later, host=="" is rejected.
306	if host == "" {
307		return nil, newDNSError(errNoSuchHost, host, "")
308	}
309	if ip, err := netip.ParseAddr(host); err == nil {
310		return []IPAddr{{IP: IP(ip.AsSlice()).To16(), Zone: ip.Zone()}}, nil
311	}
312	trace, _ := ctx.Value(nettrace.TraceKey{}).(*nettrace.Trace)
313	if trace != nil && trace.DNSStart != nil {
314		trace.DNSStart(host)
315	}
316	// The underlying resolver func is lookupIP by default but it
317	// can be overridden by tests. This is needed by net/http, so it
318	// uses a context key instead of unexported variables.
319	resolverFunc := r.lookupIP
320	if alt, _ := ctx.Value(nettrace.LookupIPAltResolverKey{}).(func(context.Context, string, string) ([]IPAddr, error)); alt != nil {
321		resolverFunc = alt
322	}
323
324	// We don't want a cancellation of ctx to affect the
325	// lookupGroup operation. Otherwise if our context gets
326	// canceled it might cause an error to be returned to a lookup
327	// using a completely different context. However we need to preserve
328	// only the values in context. See Issue 28600.
329	lookupGroupCtx, lookupGroupCancel := context.WithCancel(withUnexpiredValuesPreserved(ctx))
330
331	lookupKey := network + "\000" + host
332	dnsWaitGroup.Add(1)
333	ch := r.getLookupGroup().DoChan(lookupKey, func() (any, error) {
334		return testHookLookupIP(lookupGroupCtx, resolverFunc, network, host)
335	})
336
337	dnsWaitGroupDone := func(ch <-chan singleflight.Result, cancelFn context.CancelFunc) {
338		<-ch
339		dnsWaitGroup.Done()
340		cancelFn()
341	}
342	select {
343	case <-ctx.Done():
344		// Our context was canceled. If we are the only
345		// goroutine looking up this key, then drop the key
346		// from the lookupGroup and cancel the lookup.
347		// If there are other goroutines looking up this key,
348		// let the lookup continue uncanceled, and let later
349		// lookups with the same key share the result.
350		// See issues 8602, 20703, 22724.
351		if r.getLookupGroup().ForgetUnshared(lookupKey) {
352			lookupGroupCancel()
353			go dnsWaitGroupDone(ch, func() {})
354		} else {
355			go dnsWaitGroupDone(ch, lookupGroupCancel)
356		}
357		err := newDNSError(mapErr(ctx.Err()), host, "")
358		if trace != nil && trace.DNSDone != nil {
359			trace.DNSDone(nil, false, err)
360		}
361		return nil, err
362	case r := <-ch:
363		dnsWaitGroup.Done()
364		lookupGroupCancel()
365		err := r.Err
366		if err != nil {
367			if _, ok := err.(*DNSError); !ok {
368				err = newDNSError(mapErr(err), host, "")
369			}
370		}
371		if trace != nil && trace.DNSDone != nil {
372			addrs, _ := r.Val.([]IPAddr)
373			trace.DNSDone(ipAddrsEface(addrs), r.Shared, err)
374		}
375		return lookupIPReturn(r.Val, err, r.Shared)
376	}
377}
378
379// lookupIPReturn turns the return values from singleflight.Do into
380// the return values from LookupIP.
381func lookupIPReturn(addrsi any, err error, shared bool) ([]IPAddr, error) {
382	if err != nil {
383		return nil, err
384	}
385	addrs := addrsi.([]IPAddr)
386	if shared {
387		clone := make([]IPAddr, len(addrs))
388		copy(clone, addrs)
389		addrs = clone
390	}
391	return addrs, nil
392}
393
394// ipAddrsEface returns an empty interface slice of addrs.
395func ipAddrsEface(addrs []IPAddr) []any {
396	s := make([]any, len(addrs))
397	for i, v := range addrs {
398		s[i] = v
399	}
400	return s
401}
402
403// LookupPort looks up the port for the given network and service.
404//
405// LookupPort uses [context.Background] internally; to specify the context, use
406// [Resolver.LookupPort].
407func LookupPort(network, service string) (port int, err error) {
408	return DefaultResolver.LookupPort(context.Background(), network, service)
409}
410
411// LookupPort looks up the port for the given network and service.
412//
413// The network must be one of "tcp", "tcp4", "tcp6", "udp", "udp4", "udp6" or "ip".
414func (r *Resolver) LookupPort(ctx context.Context, network, service string) (port int, err error) {
415	port, needsLookup := parsePort(service)
416	if needsLookup {
417		switch network {
418		case "tcp", "tcp4", "tcp6", "udp", "udp4", "udp6", "ip":
419		case "": // a hint wildcard for Go 1.0 undocumented behavior
420			network = "ip"
421		default:
422			return 0, &AddrError{Err: "unknown network", Addr: network}
423		}
424		port, err = r.lookupPort(ctx, network, service)
425		if err != nil {
426			return 0, err
427		}
428	}
429	if 0 > port || port > 65535 {
430		return 0, &AddrError{Err: "invalid port", Addr: service}
431	}
432	return port, nil
433}
434
435// LookupCNAME returns the canonical name for the given host.
436// Callers that do not care about the canonical name can call
437// [LookupHost] or [LookupIP] directly; both take care of resolving
438// the canonical name as part of the lookup.
439//
440// A canonical name is the final name after following zero
441// or more CNAME records.
442// LookupCNAME does not return an error if host does not
443// contain DNS "CNAME" records, as long as host resolves to
444// address records.
445//
446// The returned canonical name is validated to be a properly
447// formatted presentation-format domain name.
448//
449// LookupCNAME uses [context.Background] internally; to specify the context, use
450// [Resolver.LookupCNAME].
451func LookupCNAME(host string) (cname string, err error) {
452	return DefaultResolver.LookupCNAME(context.Background(), host)
453}
454
455// LookupCNAME returns the canonical name for the given host.
456// Callers that do not care about the canonical name can call
457// [LookupHost] or [LookupIP] directly; both take care of resolving
458// the canonical name as part of the lookup.
459//
460// A canonical name is the final name after following zero
461// or more CNAME records.
462// LookupCNAME does not return an error if host does not
463// contain DNS "CNAME" records, as long as host resolves to
464// address records.
465//
466// The returned canonical name is validated to be a properly
467// formatted presentation-format domain name.
468func (r *Resolver) LookupCNAME(ctx context.Context, host string) (string, error) {
469	cname, err := r.lookupCNAME(ctx, host)
470	if err != nil {
471		return "", err
472	}
473	if !isDomainName(cname) {
474		return "", &DNSError{Err: errMalformedDNSRecordsDetail, Name: host}
475	}
476	return cname, nil
477}
478
479// LookupSRV tries to resolve an [SRV] query of the given service,
480// protocol, and domain name. The proto is "tcp" or "udp".
481// The returned records are sorted by priority and randomized
482// by weight within a priority.
483//
484// LookupSRV constructs the DNS name to look up following RFC 2782.
485// That is, it looks up _service._proto.name. To accommodate services
486// publishing SRV records under non-standard names, if both service
487// and proto are empty strings, LookupSRV looks up name directly.
488//
489// The returned service names are validated to be properly
490// formatted presentation-format domain names. If the response contains
491// invalid names, those records are filtered out and an error
492// will be returned alongside the remaining results, if any.
493func LookupSRV(service, proto, name string) (cname string, addrs []*SRV, err error) {
494	return DefaultResolver.LookupSRV(context.Background(), service, proto, name)
495}
496
497// LookupSRV tries to resolve an [SRV] query of the given service,
498// protocol, and domain name. The proto is "tcp" or "udp".
499// The returned records are sorted by priority and randomized
500// by weight within a priority.
501//
502// LookupSRV constructs the DNS name to look up following RFC 2782.
503// That is, it looks up _service._proto.name. To accommodate services
504// publishing SRV records under non-standard names, if both service
505// and proto are empty strings, LookupSRV looks up name directly.
506//
507// The returned service names are validated to be properly
508// formatted presentation-format domain names. If the response contains
509// invalid names, those records are filtered out and an error
510// will be returned alongside the remaining results, if any.
511func (r *Resolver) LookupSRV(ctx context.Context, service, proto, name string) (string, []*SRV, error) {
512	cname, addrs, err := r.lookupSRV(ctx, service, proto, name)
513	if err != nil {
514		return "", nil, err
515	}
516	if cname != "" && !isDomainName(cname) {
517		return "", nil, &DNSError{Err: "SRV header name is invalid", Name: name}
518	}
519	filteredAddrs := make([]*SRV, 0, len(addrs))
520	for _, addr := range addrs {
521		if addr == nil {
522			continue
523		}
524		if !isDomainName(addr.Target) {
525			continue
526		}
527		filteredAddrs = append(filteredAddrs, addr)
528	}
529	if len(addrs) != len(filteredAddrs) {
530		return cname, filteredAddrs, &DNSError{Err: errMalformedDNSRecordsDetail, Name: name}
531	}
532	return cname, filteredAddrs, nil
533}
534
535// LookupMX returns the DNS MX records for the given domain name sorted by preference.
536//
537// The returned mail server names are validated to be properly
538// formatted presentation-format domain names. If the response contains
539// invalid names, those records are filtered out and an error
540// will be returned alongside the remaining results, if any.
541//
542// LookupMX uses [context.Background] internally; to specify the context, use
543// [Resolver.LookupMX].
544func LookupMX(name string) ([]*MX, error) {
545	return DefaultResolver.LookupMX(context.Background(), name)
546}
547
548// LookupMX returns the DNS MX records for the given domain name sorted by preference.
549//
550// The returned mail server names are validated to be properly
551// formatted presentation-format domain names. If the response contains
552// invalid names, those records are filtered out and an error
553// will be returned alongside the remaining results, if any.
554func (r *Resolver) LookupMX(ctx context.Context, name string) ([]*MX, error) {
555	records, err := r.lookupMX(ctx, name)
556	if err != nil {
557		return nil, err
558	}
559	filteredMX := make([]*MX, 0, len(records))
560	for _, mx := range records {
561		if mx == nil {
562			continue
563		}
564		if !isDomainName(mx.Host) {
565			continue
566		}
567		filteredMX = append(filteredMX, mx)
568	}
569	if len(records) != len(filteredMX) {
570		return filteredMX, &DNSError{Err: errMalformedDNSRecordsDetail, Name: name}
571	}
572	return filteredMX, nil
573}
574
575// LookupNS returns the DNS NS records for the given domain name.
576//
577// The returned name server names are validated to be properly
578// formatted presentation-format domain names. If the response contains
579// invalid names, those records are filtered out and an error
580// will be returned alongside the remaining results, if any.
581//
582// LookupNS uses [context.Background] internally; to specify the context, use
583// [Resolver.LookupNS].
584func LookupNS(name string) ([]*NS, error) {
585	return DefaultResolver.LookupNS(context.Background(), name)
586}
587
588// LookupNS returns the DNS NS records for the given domain name.
589//
590// The returned name server names are validated to be properly
591// formatted presentation-format domain names. If the response contains
592// invalid names, those records are filtered out and an error
593// will be returned alongside the remaining results, if any.
594func (r *Resolver) LookupNS(ctx context.Context, name string) ([]*NS, error) {
595	records, err := r.lookupNS(ctx, name)
596	if err != nil {
597		return nil, err
598	}
599	filteredNS := make([]*NS, 0, len(records))
600	for _, ns := range records {
601		if ns == nil {
602			continue
603		}
604		if !isDomainName(ns.Host) {
605			continue
606		}
607		filteredNS = append(filteredNS, ns)
608	}
609	if len(records) != len(filteredNS) {
610		return filteredNS, &DNSError{Err: errMalformedDNSRecordsDetail, Name: name}
611	}
612	return filteredNS, nil
613}
614
615// LookupTXT returns the DNS TXT records for the given domain name.
616//
617// LookupTXT uses [context.Background] internally; to specify the context, use
618// [Resolver.LookupTXT].
619func LookupTXT(name string) ([]string, error) {
620	return DefaultResolver.lookupTXT(context.Background(), name)
621}
622
623// LookupTXT returns the DNS TXT records for the given domain name.
624func (r *Resolver) LookupTXT(ctx context.Context, name string) ([]string, error) {
625	return r.lookupTXT(ctx, name)
626}
627
628// LookupAddr performs a reverse lookup for the given address, returning a list
629// of names mapping to that address.
630//
631// The returned names are validated to be properly formatted presentation-format
632// domain names. If the response contains invalid names, those records are filtered
633// out and an error will be returned alongside the remaining results, if any.
634//
635// When using the host C library resolver, at most one result will be
636// returned. To bypass the host resolver, use a custom [Resolver].
637//
638// LookupAddr uses [context.Background] internally; to specify the context, use
639// [Resolver.LookupAddr].
640func LookupAddr(addr string) (names []string, err error) {
641	return DefaultResolver.LookupAddr(context.Background(), addr)
642}
643
644// LookupAddr performs a reverse lookup for the given address, returning a list
645// of names mapping to that address.
646//
647// The returned names are validated to be properly formatted presentation-format
648// domain names. If the response contains invalid names, those records are filtered
649// out and an error will be returned alongside the remaining results, if any.
650func (r *Resolver) LookupAddr(ctx context.Context, addr string) ([]string, error) {
651	names, err := r.lookupAddr(ctx, addr)
652	if err != nil {
653		return nil, err
654	}
655	filteredNames := make([]string, 0, len(names))
656	for _, name := range names {
657		if isDomainName(name) {
658			filteredNames = append(filteredNames, name)
659		}
660	}
661	if len(names) != len(filteredNames) {
662		return filteredNames, &DNSError{Err: errMalformedDNSRecordsDetail, Name: addr}
663	}
664	return filteredNames, nil
665}
666
667// errMalformedDNSRecordsDetail is the DNSError detail which is returned when a Resolver.Lookup...
668// method receives DNS records which contain invalid DNS names. This may be returned alongside
669// results which have had the malformed records filtered out.
670var errMalformedDNSRecordsDetail = "DNS response contained records which contain invalid names"
671
672// dial makes a new connection to the provided server (which must be
673// an IP address) with the provided network type, using either r.Dial
674// (if both r and r.Dial are non-nil) or else Dialer.DialContext.
675func (r *Resolver) dial(ctx context.Context, network, server string) (Conn, error) {
676	// Calling Dial here is scary -- we have to be sure not to
677	// dial a name that will require a DNS lookup, or Dial will
678	// call back here to translate it. The DNS config parser has
679	// already checked that all the cfg.servers are IP
680	// addresses, which Dial will use without a DNS lookup.
681	var c Conn
682	var err error
683	if r != nil && r.Dial != nil {
684		c, err = r.Dial(ctx, network, server)
685	} else {
686		var d Dialer
687		c, err = d.DialContext(ctx, network, server)
688	}
689	if err != nil {
690		return nil, mapErr(err)
691	}
692	return c, nil
693}
694
695// goLookupSRV returns the SRV records for a target name, built either
696// from its component service ("sip"), protocol ("tcp"), and name
697// ("example.com."), or from name directly (if service and proto are
698// both empty).
699//
700// In either case, the returned target name ("_sip._tcp.example.com.")
701// is also returned on success.
702//
703// The records are sorted by weight.
704func (r *Resolver) goLookupSRV(ctx context.Context, service, proto, name string) (target string, srvs []*SRV, err error) {
705	if service == "" && proto == "" {
706		target = name
707	} else {
708		target = "_" + service + "._" + proto + "." + name
709	}
710	p, server, err := r.lookup(ctx, target, dnsmessage.TypeSRV, nil)
711	if err != nil {
712		return "", nil, err
713	}
714	var cname dnsmessage.Name
715	for {
716		h, err := p.AnswerHeader()
717		if err == dnsmessage.ErrSectionDone {
718			break
719		}
720		if err != nil {
721			return "", nil, &DNSError{
722				Err:    "cannot unmarshal DNS message",
723				Name:   name,
724				Server: server,
725			}
726		}
727		if h.Type != dnsmessage.TypeSRV {
728			if err := p.SkipAnswer(); err != nil {
729				return "", nil, &DNSError{
730					Err:    "cannot unmarshal DNS message",
731					Name:   name,
732					Server: server,
733				}
734			}
735			continue
736		}
737		if cname.Length == 0 && h.Name.Length != 0 {
738			cname = h.Name
739		}
740		srv, err := p.SRVResource()
741		if err != nil {
742			return "", nil, &DNSError{
743				Err:    "cannot unmarshal DNS message",
744				Name:   name,
745				Server: server,
746			}
747		}
748		srvs = append(srvs, &SRV{Target: srv.Target.String(), Port: srv.Port, Priority: srv.Priority, Weight: srv.Weight})
749	}
750	byPriorityWeight(srvs).sort()
751	return cname.String(), srvs, nil
752}
753
754// goLookupMX returns the MX records for name.
755func (r *Resolver) goLookupMX(ctx context.Context, name string) ([]*MX, error) {
756	p, server, err := r.lookup(ctx, name, dnsmessage.TypeMX, nil)
757	if err != nil {
758		return nil, err
759	}
760	var mxs []*MX
761	for {
762		h, err := p.AnswerHeader()
763		if err == dnsmessage.ErrSectionDone {
764			break
765		}
766		if err != nil {
767			return nil, &DNSError{
768				Err:    "cannot unmarshal DNS message",
769				Name:   name,
770				Server: server,
771			}
772		}
773		if h.Type != dnsmessage.TypeMX {
774			if err := p.SkipAnswer(); err != nil {
775				return nil, &DNSError{
776					Err:    "cannot unmarshal DNS message",
777					Name:   name,
778					Server: server,
779				}
780			}
781			continue
782		}
783		mx, err := p.MXResource()
784		if err != nil {
785			return nil, &DNSError{
786				Err:    "cannot unmarshal DNS message",
787				Name:   name,
788				Server: server,
789			}
790		}
791		mxs = append(mxs, &MX{Host: mx.MX.String(), Pref: mx.Pref})
792
793	}
794	byPref(mxs).sort()
795	return mxs, nil
796}
797
798// goLookupNS returns the NS records for name.
799func (r *Resolver) goLookupNS(ctx context.Context, name string) ([]*NS, error) {
800	p, server, err := r.lookup(ctx, name, dnsmessage.TypeNS, nil)
801	if err != nil {
802		return nil, err
803	}
804	var nss []*NS
805	for {
806		h, err := p.AnswerHeader()
807		if err == dnsmessage.ErrSectionDone {
808			break
809		}
810		if err != nil {
811			return nil, &DNSError{
812				Err:    "cannot unmarshal DNS message",
813				Name:   name,
814				Server: server,
815			}
816		}
817		if h.Type != dnsmessage.TypeNS {
818			if err := p.SkipAnswer(); err != nil {
819				return nil, &DNSError{
820					Err:    "cannot unmarshal DNS message",
821					Name:   name,
822					Server: server,
823				}
824			}
825			continue
826		}
827		ns, err := p.NSResource()
828		if err != nil {
829			return nil, &DNSError{
830				Err:    "cannot unmarshal DNS message",
831				Name:   name,
832				Server: server,
833			}
834		}
835		nss = append(nss, &NS{Host: ns.NS.String()})
836	}
837	return nss, nil
838}
839
840// goLookupTXT returns the TXT records from name.
841func (r *Resolver) goLookupTXT(ctx context.Context, name string) ([]string, error) {
842	p, server, err := r.lookup(ctx, name, dnsmessage.TypeTXT, nil)
843	if err != nil {
844		return nil, err
845	}
846	var txts []string
847	for {
848		h, err := p.AnswerHeader()
849		if err == dnsmessage.ErrSectionDone {
850			break
851		}
852		if err != nil {
853			return nil, &DNSError{
854				Err:    "cannot unmarshal DNS message",
855				Name:   name,
856				Server: server,
857			}
858		}
859		if h.Type != dnsmessage.TypeTXT {
860			if err := p.SkipAnswer(); err != nil {
861				return nil, &DNSError{
862					Err:    "cannot unmarshal DNS message",
863					Name:   name,
864					Server: server,
865				}
866			}
867			continue
868		}
869		txt, err := p.TXTResource()
870		if err != nil {
871			return nil, &DNSError{
872				Err:    "cannot unmarshal DNS message",
873				Name:   name,
874				Server: server,
875			}
876		}
877		// Multiple strings in one TXT record need to be
878		// concatenated without separator to be consistent
879		// with previous Go resolver.
880		n := 0
881		for _, s := range txt.TXT {
882			n += len(s)
883		}
884		txtJoin := make([]byte, 0, n)
885		for _, s := range txt.TXT {
886			txtJoin = append(txtJoin, s...)
887		}
888		if len(txts) == 0 {
889			txts = make([]string, 0, 1)
890		}
891		txts = append(txts, string(txtJoin))
892	}
893	return txts, nil
894}
895
896func parseCNAMEFromResources(resources []dnsmessage.Resource) (string, error) {
897	if len(resources) == 0 {
898		return "", errors.New("no CNAME record received")
899	}
900	c, ok := resources[0].Body.(*dnsmessage.CNAMEResource)
901	if !ok {
902		return "", errors.New("could not parse CNAME record")
903	}
904	return c.CNAME.String(), nil
905}
906