1// Copyright 2009 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// +build darwin dragonfly freebsd linux netbsd openbsd solaris
6
7// DNS client: see RFC 1035.
8// Has to be linked into package net for Dial.
9
10// TODO(rsc):
11//	Could potentially handle many outstanding lookups faster.
12//	Could have a small cache.
13//	Random UDP source port (net.Dial should do that for us).
14//	Random request IDs.
15
16package net
17
18import (
19	"errors"
20	"io"
21	"math/rand"
22	"os"
23	"strconv"
24	"sync"
25	"time"
26)
27
28// A dnsConn represents a DNS transport endpoint.
29type dnsConn interface {
30	Conn
31
32	// readDNSResponse reads a DNS response message from the DNS
33	// transport endpoint and returns the received DNS response
34	// message.
35	readDNSResponse() (*dnsMsg, error)
36
37	// writeDNSQuery writes a DNS query message to the DNS
38	// connection endpoint.
39	writeDNSQuery(*dnsMsg) error
40}
41
42func (c *UDPConn) readDNSResponse() (*dnsMsg, error) {
43	b := make([]byte, 512) // see RFC 1035
44	n, err := c.Read(b)
45	if err != nil {
46		return nil, err
47	}
48	msg := &dnsMsg{}
49	if !msg.Unpack(b[:n]) {
50		return nil, errors.New("cannot unmarshal DNS message")
51	}
52	return msg, nil
53}
54
55func (c *UDPConn) writeDNSQuery(msg *dnsMsg) error {
56	b, ok := msg.Pack()
57	if !ok {
58		return errors.New("cannot marshal DNS message")
59	}
60	if _, err := c.Write(b); err != nil {
61		return err
62	}
63	return nil
64}
65
66func (c *TCPConn) readDNSResponse() (*dnsMsg, error) {
67	b := make([]byte, 1280) // 1280 is a reasonable initial size for IP over Ethernet, see RFC 4035
68	if _, err := io.ReadFull(c, b[:2]); err != nil {
69		return nil, err
70	}
71	l := int(b[0])<<8 | int(b[1])
72	if l > len(b) {
73		b = make([]byte, l)
74	}
75	n, err := io.ReadFull(c, b[:l])
76	if err != nil {
77		return nil, err
78	}
79	msg := &dnsMsg{}
80	if !msg.Unpack(b[:n]) {
81		return nil, errors.New("cannot unmarshal DNS message")
82	}
83	return msg, nil
84}
85
86func (c *TCPConn) writeDNSQuery(msg *dnsMsg) error {
87	b, ok := msg.Pack()
88	if !ok {
89		return errors.New("cannot marshal DNS message")
90	}
91	l := uint16(len(b))
92	b = append([]byte{byte(l >> 8), byte(l)}, b...)
93	if _, err := c.Write(b); err != nil {
94		return err
95	}
96	return nil
97}
98
99func (d *Dialer) dialDNS(network, server string) (dnsConn, error) {
100	switch network {
101	case "tcp", "tcp4", "tcp6", "udp", "udp4", "udp6":
102	default:
103		return nil, UnknownNetworkError(network)
104	}
105	// Calling Dial here is scary -- we have to be sure not to
106	// dial a name that will require a DNS lookup, or Dial will
107	// call back here to translate it. The DNS config parser has
108	// already checked that all the cfg.servers[i] are IP
109	// addresses, which Dial will use without a DNS lookup.
110	c, err := d.Dial(network, server)
111	if err != nil {
112		return nil, err
113	}
114	switch network {
115	case "tcp", "tcp4", "tcp6":
116		return c.(*TCPConn), nil
117	case "udp", "udp4", "udp6":
118		return c.(*UDPConn), nil
119	}
120	panic("unreachable")
121}
122
123// exchange sends a query on the connection and hopes for a response.
124func exchange(server, name string, qtype uint16, timeout time.Duration) (*dnsMsg, error) {
125	d := Dialer{Timeout: timeout}
126	out := dnsMsg{
127		dnsMsgHdr: dnsMsgHdr{
128			recursion_desired: true,
129		},
130		question: []dnsQuestion{
131			{name, qtype, dnsClassINET},
132		},
133	}
134	for _, network := range []string{"udp", "tcp"} {
135		c, err := d.dialDNS(network, server)
136		if err != nil {
137			return nil, err
138		}
139		defer c.Close()
140		if timeout > 0 {
141			c.SetDeadline(time.Now().Add(timeout))
142		}
143		out.id = uint16(rand.Int()) ^ uint16(time.Now().UnixNano())
144		if err := c.writeDNSQuery(&out); err != nil {
145			return nil, err
146		}
147		in, err := c.readDNSResponse()
148		if err != nil {
149			return nil, err
150		}
151		if in.id != out.id {
152			return nil, errors.New("DNS message ID mismatch")
153		}
154		if in.truncated { // see RFC 5966
155			continue
156		}
157		return in, nil
158	}
159	return nil, errors.New("no answer from DNS server")
160}
161
162// Do a lookup for a single name, which must be rooted
163// (otherwise answer will not find the answers).
164func tryOneName(cfg *dnsConfig, name string, qtype uint16) (string, []dnsRR, error) {
165	if len(cfg.servers) == 0 {
166		return "", nil, &DNSError{Err: "no DNS servers", Name: name}
167	}
168	if len(name) >= 256 {
169		return "", nil, &DNSError{Err: "DNS name too long", Name: name}
170	}
171	timeout := time.Duration(cfg.timeout) * time.Second
172	var lastErr error
173	for i := 0; i < cfg.attempts; i++ {
174		for _, server := range cfg.servers {
175			server = JoinHostPort(server, "53")
176			msg, err := exchange(server, name, qtype, timeout)
177			if err != nil {
178				lastErr = &DNSError{
179					Err:    err.Error(),
180					Name:   name,
181					Server: server,
182				}
183				if nerr, ok := err.(Error); ok && nerr.Timeout() {
184					lastErr.(*DNSError).IsTimeout = true
185				}
186				continue
187			}
188			cname, rrs, err := answer(name, server, msg, qtype)
189			if err == nil || msg.rcode == dnsRcodeSuccess || msg.rcode == dnsRcodeNameError && msg.recursion_available {
190				return cname, rrs, err
191			}
192			lastErr = err
193		}
194	}
195	return "", nil, lastErr
196}
197
198// addrRecordList converts and returns a list of IP addresses from DNS
199// address records (both A and AAAA). Other record types are ignored.
200func addrRecordList(rrs []dnsRR) []IPAddr {
201	addrs := make([]IPAddr, 0, 4)
202	for _, rr := range rrs {
203		switch rr := rr.(type) {
204		case *dnsRR_A:
205			addrs = append(addrs, IPAddr{IP: IPv4(byte(rr.A>>24), byte(rr.A>>16), byte(rr.A>>8), byte(rr.A))})
206		case *dnsRR_AAAA:
207			ip := make(IP, IPv6len)
208			copy(ip, rr.AAAA[:])
209			addrs = append(addrs, IPAddr{IP: ip})
210		}
211	}
212	return addrs
213}
214
215// A resolverConfig represents a DNS stub resolver configuration.
216type resolverConfig struct {
217	initOnce sync.Once // guards init of resolverConfig
218
219	// ch is used as a semaphore that only allows one lookup at a
220	// time to recheck resolv.conf.
221	ch          chan struct{} // guards lastChecked and modTime
222	lastChecked time.Time     // last time resolv.conf was checked
223	modTime     time.Time     // time of resolv.conf modification
224
225	mu        sync.RWMutex // protects dnsConfig
226	dnsConfig *dnsConfig   // parsed resolv.conf structure used in lookups
227}
228
229var resolvConf resolverConfig
230
231// init initializes conf and is only called via conf.initOnce.
232func (conf *resolverConfig) init() {
233	// Set dnsConfig, modTime, and lastChecked so we don't parse
234	// resolv.conf twice the first time.
235	conf.dnsConfig = systemConf().resolv
236	if conf.dnsConfig == nil {
237		conf.dnsConfig = dnsReadConfig("/etc/resolv.conf")
238	}
239
240	if fi, err := os.Stat("/etc/resolv.conf"); err == nil {
241		conf.modTime = fi.ModTime()
242	}
243	conf.lastChecked = time.Now()
244
245	// Prepare ch so that only one update of resolverConfig may
246	// run at once.
247	conf.ch = make(chan struct{}, 1)
248}
249
250// tryUpdate tries to update conf with the named resolv.conf file.
251// The name variable only exists for testing. It is otherwise always
252// "/etc/resolv.conf".
253func (conf *resolverConfig) tryUpdate(name string) {
254	conf.initOnce.Do(conf.init)
255
256	// Ensure only one update at a time checks resolv.conf.
257	if !conf.tryAcquireSema() {
258		return
259	}
260	defer conf.releaseSema()
261
262	now := time.Now()
263	if conf.lastChecked.After(now.Add(-5 * time.Second)) {
264		return
265	}
266	conf.lastChecked = now
267
268	if fi, err := os.Stat(name); err == nil {
269		if fi.ModTime().Equal(conf.modTime) {
270			return
271		}
272		conf.modTime = fi.ModTime()
273	} else {
274		// If modTime wasn't set prior, assume nothing has changed.
275		if conf.modTime.IsZero() {
276			return
277		}
278		conf.modTime = time.Time{}
279	}
280
281	dnsConf := dnsReadConfig(name)
282	conf.mu.Lock()
283	conf.dnsConfig = dnsConf
284	conf.mu.Unlock()
285}
286
287func (conf *resolverConfig) tryAcquireSema() bool {
288	select {
289	case conf.ch <- struct{}{}:
290		return true
291	default:
292		return false
293	}
294}
295
296func (conf *resolverConfig) releaseSema() {
297	<-conf.ch
298}
299
300func lookup(name string, qtype uint16) (cname string, rrs []dnsRR, err error) {
301	if !isDomainName(name) {
302		return "", nil, &DNSError{Err: "invalid domain name", Name: name}
303	}
304	resolvConf.tryUpdate("/etc/resolv.conf")
305	resolvConf.mu.RLock()
306	conf := resolvConf.dnsConfig
307	resolvConf.mu.RUnlock()
308	for _, fqdn := range conf.nameList(name) {
309		cname, rrs, err = tryOneName(conf, fqdn, qtype)
310		if err == nil {
311			break
312		}
313	}
314	if err, ok := err.(*DNSError); ok {
315		// Show original name passed to lookup, not suffixed one.
316		// In general we might have tried many suffixes; showing
317		// just one is misleading. See also golang.org/issue/6324.
318		err.Name = name
319	}
320	return
321}
322
323// nameList returns a list of names for sequential DNS queries.
324func (conf *dnsConfig) nameList(name string) []string {
325	// If name is rooted (trailing dot), try only that name.
326	rooted := len(name) > 0 && name[len(name)-1] == '.'
327	if rooted {
328		return []string{name}
329	}
330	// Build list of search choices.
331	names := make([]string, 0, 1+len(conf.search))
332	// If name has enough dots, try unsuffixed first.
333	if count(name, '.') >= conf.ndots {
334		names = append(names, name+".")
335	}
336	// Try suffixes.
337	for _, suffix := range conf.search {
338		suffixed := name + "." + suffix
339		if suffixed[len(suffixed)-1] != '.' {
340			suffixed += "."
341		}
342		names = append(names, suffixed)
343	}
344	// Try unsuffixed, if not tried first above.
345	if count(name, '.') < conf.ndots {
346		names = append(names, name+".")
347	}
348	return names
349}
350
351// hostLookupOrder specifies the order of LookupHost lookup strategies.
352// It is basically a simplified representation of nsswitch.conf.
353// "files" means /etc/hosts.
354type hostLookupOrder int
355
356const (
357	// hostLookupCgo means defer to cgo.
358	hostLookupCgo      hostLookupOrder = iota
359	hostLookupFilesDNS                 // files first
360	hostLookupDNSFiles                 // dns first
361	hostLookupFiles                    // only files
362	hostLookupDNS                      // only DNS
363)
364
365var lookupOrderName = map[hostLookupOrder]string{
366	hostLookupCgo:      "cgo",
367	hostLookupFilesDNS: "files,dns",
368	hostLookupDNSFiles: "dns,files",
369	hostLookupFiles:    "files",
370	hostLookupDNS:      "dns",
371}
372
373func (o hostLookupOrder) String() string {
374	if s, ok := lookupOrderName[o]; ok {
375		return s
376	}
377	return "hostLookupOrder=" + strconv.Itoa(int(o)) + "??"
378}
379
380// goLookupHost is the native Go implementation of LookupHost.
381// Used only if cgoLookupHost refuses to handle the request
382// (that is, only if cgoLookupHost is the stub in cgo_stub.go).
383// Normally we let cgo use the C library resolver instead of
384// depending on our lookup code, so that Go and C get the same
385// answers.
386func goLookupHost(name string) (addrs []string, err error) {
387	return goLookupHostOrder(name, hostLookupFilesDNS)
388}
389
390func goLookupHostOrder(name string, order hostLookupOrder) (addrs []string, err error) {
391	if order == hostLookupFilesDNS || order == hostLookupFiles {
392		// Use entries from /etc/hosts if they match.
393		addrs = lookupStaticHost(name)
394		if len(addrs) > 0 || order == hostLookupFiles {
395			return
396		}
397	}
398	ips, err := goLookupIPOrder(name, order)
399	if err != nil {
400		return
401	}
402	addrs = make([]string, 0, len(ips))
403	for _, ip := range ips {
404		addrs = append(addrs, ip.String())
405	}
406	return
407}
408
409// lookup entries from /etc/hosts
410func goLookupIPFiles(name string) (addrs []IPAddr) {
411	for _, haddr := range lookupStaticHost(name) {
412		haddr, zone := splitHostZone(haddr)
413		if ip := ParseIP(haddr); ip != nil {
414			addr := IPAddr{IP: ip, Zone: zone}
415			addrs = append(addrs, addr)
416		}
417	}
418	sortByRFC6724(addrs)
419	return
420}
421
422// goLookupIP is the native Go implementation of LookupIP.
423// The libc versions are in cgo_*.go.
424func goLookupIP(name string) (addrs []IPAddr, err error) {
425	return goLookupIPOrder(name, hostLookupFilesDNS)
426}
427
428func goLookupIPOrder(name string, order hostLookupOrder) (addrs []IPAddr, err error) {
429	if order == hostLookupFilesDNS || order == hostLookupFiles {
430		addrs = goLookupIPFiles(name)
431		if len(addrs) > 0 || order == hostLookupFiles {
432			return addrs, nil
433		}
434	}
435	if !isDomainName(name) {
436		return nil, &DNSError{Err: "invalid domain name", Name: name}
437	}
438	resolvConf.tryUpdate("/etc/resolv.conf")
439	resolvConf.mu.RLock()
440	conf := resolvConf.dnsConfig
441	resolvConf.mu.RUnlock()
442	type racer struct {
443		rrs []dnsRR
444		error
445	}
446	lane := make(chan racer, 1)
447	qtypes := [...]uint16{dnsTypeA, dnsTypeAAAA}
448	var lastErr error
449	for _, fqdn := range conf.nameList(name) {
450		for _, qtype := range qtypes {
451			go func(qtype uint16) {
452				_, rrs, err := tryOneName(conf, fqdn, qtype)
453				lane <- racer{rrs, err}
454			}(qtype)
455		}
456		for range qtypes {
457			racer := <-lane
458			if racer.error != nil {
459				lastErr = racer.error
460				continue
461			}
462			addrs = append(addrs, addrRecordList(racer.rrs)...)
463		}
464		if len(addrs) > 0 {
465			break
466		}
467	}
468	if lastErr, ok := lastErr.(*DNSError); ok {
469		// Show original name passed to lookup, not suffixed one.
470		// In general we might have tried many suffixes; showing
471		// just one is misleading. See also golang.org/issue/6324.
472		lastErr.Name = name
473	}
474	sortByRFC6724(addrs)
475	if len(addrs) == 0 {
476		if lastErr != nil {
477			return nil, lastErr
478		}
479		if order == hostLookupDNSFiles {
480			addrs = goLookupIPFiles(name)
481		}
482	}
483	return addrs, nil
484}
485
486// goLookupCNAME is the native Go implementation of LookupCNAME.
487// Used only if cgoLookupCNAME refuses to handle the request
488// (that is, only if cgoLookupCNAME is the stub in cgo_stub.go).
489// Normally we let cgo use the C library resolver instead of
490// depending on our lookup code, so that Go and C get the same
491// answers.
492func goLookupCNAME(name string) (cname string, err error) {
493	_, rrs, err := lookup(name, dnsTypeCNAME)
494	if err != nil {
495		return
496	}
497	cname = rrs[0].(*dnsRR_CNAME).Cname
498	return
499}
500
501// goLookupPTR is the native Go implementation of LookupAddr.
502// Used only if cgoLookupPTR refuses to handle the request (that is,
503// only if cgoLookupPTR is the stub in cgo_stub.go).
504// Normally we let cgo use the C library resolver instead of depending
505// on our lookup code, so that Go and C get the same answers.
506func goLookupPTR(addr string) ([]string, error) {
507	names := lookupStaticAddr(addr)
508	if len(names) > 0 {
509		return names, nil
510	}
511	arpa, err := reverseaddr(addr)
512	if err != nil {
513		return nil, err
514	}
515	_, rrs, err := lookup(arpa, dnsTypePTR)
516	if err != nil {
517		return nil, err
518	}
519	ptrs := make([]string, len(rrs))
520	for i, rr := range rrs {
521		ptrs[i] = rr.(*dnsRR_PTR).Ptr
522	}
523	return ptrs, nil
524}
525