blob: 7511083f7955e6304230038893a8785853b90aaf [file] [log] [blame]
Alex Brainman9ded9542011-06-13 10:22:31 +10001// 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
Mikio Hara484cc672014-09-18 19:17:55 +09005// +build darwin dragonfly freebsd linux netbsd openbsd solaris
Russ Cox27159562011-09-15 16:48:57 -04006
Alex Brainman9ded9542011-06-13 10:22:31 +10007// DNS client: see RFC 1035.
8// Has to be linked into package net for Dial.
9
10// TODO(rsc):
Alex Brainman9ded9542011-06-13 10:22:31 +100011// 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 (
Mikio Hara48e75332014-08-06 09:58:47 +090019 "errors"
Alex A Skinner0a3cb7e2013-08-13 09:44:12 -070020 "io"
Rob Pike45e3bcb2011-11-08 15:41:54 -080021 "math/rand"
Guillaume J. Charmesbf1d4002014-05-14 17:11:00 -070022 "os"
Alex Brainman9ded9542011-06-13 10:22:31 +100023 "sync"
24 "time"
25)
26
Mikio Hara48e75332014-08-06 09:58:47 +090027// A dnsConn represents a DNS transport endpoint.
28type dnsConn interface {
29 Conn
Alex Brainman9ded9542011-06-13 10:22:31 +100030
Mikio Hara48e75332014-08-06 09:58:47 +090031 // readDNSResponse reads a DNS response message from the DNS
32 // transport endpoint and returns the received DNS response
33 // message.
34 readDNSResponse() (*dnsMsg, error)
35
36 // writeDNSQuery writes a DNS query message to the DNS
37 // connection endpoint.
38 writeDNSQuery(*dnsMsg) error
39}
40
41func (c *UDPConn) readDNSResponse() (*dnsMsg, error) {
42 b := make([]byte, 512) // see RFC 1035
43 n, err := c.Read(b)
44 if err != nil {
45 return nil, err
46 }
47 msg := &dnsMsg{}
48 if !msg.Unpack(b[:n]) {
49 return nil, errors.New("cannot unmarshal DNS message")
50 }
51 return msg, nil
52}
53
54func (c *UDPConn) writeDNSQuery(msg *dnsMsg) error {
55 b, ok := msg.Pack()
56 if !ok {
57 return errors.New("cannot marshal DNS message")
58 }
59 if _, err := c.Write(b); err != nil {
60 return err
61 }
62 return nil
63}
64
65func (c *TCPConn) readDNSResponse() (*dnsMsg, error) {
66 b := make([]byte, 1280) // 1280 is a reasonable initial size for IP over Ethernet, see RFC 4035
67 if _, err := io.ReadFull(c, b[:2]); err != nil {
68 return nil, err
69 }
70 l := int(b[0])<<8 | int(b[1])
71 if l > len(b) {
72 b = make([]byte, l)
73 }
74 n, err := io.ReadFull(c, b[:l])
75 if err != nil {
76 return nil, err
77 }
78 msg := &dnsMsg{}
79 if !msg.Unpack(b[:n]) {
80 return nil, errors.New("cannot unmarshal DNS message")
81 }
82 return msg, nil
83}
84
85func (c *TCPConn) writeDNSQuery(msg *dnsMsg) error {
86 b, ok := msg.Pack()
87 if !ok {
88 return errors.New("cannot marshal DNS message")
89 }
90 l := uint16(len(b))
91 b = append([]byte{byte(l >> 8), byte(l)}, b...)
92 if _, err := c.Write(b); err != nil {
93 return err
94 }
95 return nil
96}
97
98func (d *Dialer) dialDNS(network, server string) (dnsConn, error) {
99 switch network {
100 case "tcp", "tcp4", "tcp6", "udp", "udp4", "udp6":
101 default:
102 return nil, UnknownNetworkError(network)
103 }
104 // Calling Dial here is scary -- we have to be sure not to
105 // dial a name that will require a DNS lookup, or Dial will
106 // call back here to translate it. The DNS config parser has
107 // already checked that all the cfg.servers[i] are IP
108 // addresses, which Dial will use without a DNS lookup.
109 c, err := d.Dial(network, server)
110 if err != nil {
111 return nil, err
112 }
113 switch network {
114 case "tcp", "tcp4", "tcp6":
115 return c.(*TCPConn), nil
116 case "udp", "udp4", "udp6":
117 return c.(*UDPConn), nil
118 }
119 panic("unreachable")
120}
121
122// exchange sends a query on the connection and hopes for a response.
123func exchange(server, name string, qtype uint16, timeout time.Duration) (*dnsMsg, error) {
124 d := Dialer{Timeout: timeout}
125 out := dnsMsg{
126 dnsMsgHdr: dnsMsgHdr{
127 recursion_desired: true,
128 },
129 question: []dnsQuestion{
130 {name, qtype, dnsClassINET},
131 },
132 }
133 for _, network := range []string{"udp", "tcp"} {
134 c, err := d.dialDNS(network, server)
Alex Brainman9ded9542011-06-13 10:22:31 +1000135 if err != nil {
Alex Brainman9ded9542011-06-13 10:22:31 +1000136 return nil, err
137 }
Mikio Hara48e75332014-08-06 09:58:47 +0900138 defer c.Close()
139 if timeout > 0 {
140 c.SetDeadline(time.Now().Add(timeout))
141 }
142 out.id = uint16(rand.Int()) ^ uint16(time.Now().UnixNano())
143 if err := c.writeDNSQuery(&out); err != nil {
144 return nil, err
145 }
146 in, err := c.readDNSResponse()
147 if err != nil {
148 return nil, err
149 }
150 if in.id != out.id {
151 return nil, errors.New("DNS message ID mismatch")
152 }
153 if in.truncated { // see RFC 5966
Alex Brainman9ded9542011-06-13 10:22:31 +1000154 continue
155 }
156 return in, nil
157 }
Mikio Hara48e75332014-08-06 09:58:47 +0900158 return nil, errors.New("no answer from DNS server")
Alex Brainman9ded9542011-06-13 10:22:31 +1000159}
160
Alex Brainman9ded9542011-06-13 10:22:31 +1000161// Do a lookup for a single name, which must be rooted
162// (otherwise answer will not find the answers).
Mikio Hara48e75332014-08-06 09:58:47 +0900163func tryOneName(cfg *dnsConfig, name string, qtype uint16) (string, []dnsRR, error) {
Alex Brainman9ded9542011-06-13 10:22:31 +1000164 if len(cfg.servers) == 0 {
Russ Coxeb692922011-11-01 22:05:34 -0400165 return "", nil, &DNSError{Err: "no DNS servers", Name: name}
Alex Brainman9ded9542011-06-13 10:22:31 +1000166 }
Mikio Hara48e75332014-08-06 09:58:47 +0900167 if len(name) >= 256 {
168 return "", nil, &DNSError{Err: "DNS name too long", Name: name}
169 }
170 timeout := time.Duration(cfg.timeout) * time.Second
171 var lastErr error
Alex A Skinner39a021b2014-08-30 13:12:28 +0900172 for i := 0; i < cfg.attempts; i++ {
173 for _, server := range cfg.servers {
174 server = JoinHostPort(server, "53")
Mikio Hara48e75332014-08-06 09:58:47 +0900175 msg, err := exchange(server, name, qtype, timeout)
176 if err != nil {
Mikio Hara48e75332014-08-06 09:58:47 +0900177 lastErr = &DNSError{
178 Err: err.Error(),
179 Name: name,
180 Server: server,
181 }
Alex A Skinner39a021b2014-08-30 13:12:28 +0900182 if nerr, ok := err.(Error); ok && nerr.Timeout() {
183 lastErr.(*DNSError).IsTimeout = true
184 }
185 continue
Alex A Skinner0a3cb7e2013-08-13 09:44:12 -0700186 }
Mikio Hara48e75332014-08-06 09:58:47 +0900187 cname, addrs, err := answer(name, server, msg, qtype)
188 if err == nil || err.(*DNSError).Err == noSuchHost {
189 return cname, addrs, err
Alex A Skinner0a3cb7e2013-08-13 09:44:12 -0700190 }
Mikio Hara48e75332014-08-06 09:58:47 +0900191 lastErr = err
Alex Brainman9ded9542011-06-13 10:22:31 +1000192 }
193 }
Mikio Hara48e75332014-08-06 09:58:47 +0900194 return "", nil, lastErr
Alex Brainman9ded9542011-06-13 10:22:31 +1000195}
196
197func convertRR_A(records []dnsRR) []IP {
198 addrs := make([]IP, len(records))
199 for i, rr := range records {
200 a := rr.(*dnsRR_A).A
201 addrs[i] = IPv4(byte(a>>24), byte(a>>16), byte(a>>8), byte(a))
202 }
203 return addrs
204}
205
206func convertRR_AAAA(records []dnsRR) []IP {
207 addrs := make([]IP, len(records))
208 for i, rr := range records {
Mikio Hara80f79ad2011-08-24 13:59:33 -0400209 a := make(IP, IPv6len)
Alex Brainman9ded9542011-06-13 10:22:31 +1000210 copy(a, rr.(*dnsRR_AAAA).AAAA[:])
211 addrs[i] = a
212 }
213 return addrs
214}
215
Guillaume J. Charmesbf1d4002014-05-14 17:11:00 -0700216var cfg struct {
217 ch chan struct{}
218 mu sync.RWMutex // protects dnsConfig and dnserr
219 dnsConfig *dnsConfig
220 dnserr error
221}
222var onceLoadConfig sync.Once
Alex Brainman9ded9542011-06-13 10:22:31 +1000223
Anfernee Yongkun Guib3f38b42013-12-18 08:26:36 -0800224// Assume dns config file is /etc/resolv.conf here
Guillaume J. Charmesbf1d4002014-05-14 17:11:00 -0700225func loadDefaultConfig() {
226 loadConfig("/etc/resolv.conf", 5*time.Second, nil)
227}
Alex Brainman9ded9542011-06-13 10:22:31 +1000228
Guillaume J. Charmesbf1d4002014-05-14 17:11:00 -0700229func loadConfig(resolvConfPath string, reloadTime time.Duration, quit <-chan chan struct{}) {
230 var mtime time.Time
231 cfg.ch = make(chan struct{}, 1)
232 if fi, err := os.Stat(resolvConfPath); err != nil {
233 cfg.dnserr = err
234 } else {
235 mtime = fi.ModTime()
236 cfg.dnsConfig, cfg.dnserr = dnsReadConfig(resolvConfPath)
237 }
238 go func() {
239 for {
240 time.Sleep(reloadTime)
241 select {
242 case qresp := <-quit:
243 qresp <- struct{}{}
244 return
245 case <-cfg.ch:
246 }
247
248 // In case of error, we keep the previous config
249 fi, err := os.Stat(resolvConfPath)
250 if err != nil {
251 continue
252 }
253 // If the resolv.conf mtime didn't change, do not reload
254 m := fi.ModTime()
255 if m.Equal(mtime) {
256 continue
257 }
258 mtime = m
259 // In case of error, we keep the previous config
260 ncfg, err := dnsReadConfig(resolvConfPath)
261 if err != nil || len(ncfg.servers) == 0 {
262 continue
263 }
264 cfg.mu.Lock()
265 cfg.dnsConfig = ncfg
266 cfg.dnserr = nil
267 cfg.mu.Unlock()
268 }
269 }()
270}
Alex Brainman9ded9542011-06-13 10:22:31 +1000271
Russ Coxeb692922011-11-01 22:05:34 -0400272func lookup(name string, qtype uint16) (cname string, addrs []dnsRR, err error) {
Alex Brainman9ded9542011-06-13 10:22:31 +1000273 if !isDomainName(name) {
Russ Coxeb692922011-11-01 22:05:34 -0400274 return name, nil, &DNSError{Err: "invalid domain name", Name: name}
Alex Brainman9ded9542011-06-13 10:22:31 +1000275 }
Guillaume J. Charmesbf1d4002014-05-14 17:11:00 -0700276 onceLoadConfig.Do(loadDefaultConfig)
277
278 select {
279 case cfg.ch <- struct{}{}:
280 default:
281 }
282
283 cfg.mu.RLock()
284 defer cfg.mu.RUnlock()
285
286 if cfg.dnserr != nil || cfg.dnsConfig == nil {
287 err = cfg.dnserr
Alex Brainman9ded9542011-06-13 10:22:31 +1000288 return
289 }
290 // If name is rooted (trailing dot) or has enough dots,
291 // try it by itself first.
292 rooted := len(name) > 0 && name[len(name)-1] == '.'
Guillaume J. Charmesbf1d4002014-05-14 17:11:00 -0700293 if rooted || count(name, '.') >= cfg.dnsConfig.ndots {
Alex Brainman9ded9542011-06-13 10:22:31 +1000294 rname := name
295 if !rooted {
296 rname += "."
297 }
298 // Can try as ordinary name.
Guillaume J. Charmesbf1d4002014-05-14 17:11:00 -0700299 cname, addrs, err = tryOneName(cfg.dnsConfig, rname, qtype)
Alex A Skinner854dbb72014-08-30 07:50:50 +0900300 if rooted || err == nil {
Alex Brainman9ded9542011-06-13 10:22:31 +1000301 return
302 }
303 }
Alex Brainman9ded9542011-06-13 10:22:31 +1000304
305 // Otherwise, try suffixes.
Guillaume J. Charmesbf1d4002014-05-14 17:11:00 -0700306 for i := 0; i < len(cfg.dnsConfig.search); i++ {
307 rname := name + "." + cfg.dnsConfig.search[i]
Alex Brainman9ded9542011-06-13 10:22:31 +1000308 if rname[len(rname)-1] != '.' {
309 rname += "."
310 }
Guillaume J. Charmesbf1d4002014-05-14 17:11:00 -0700311 cname, addrs, err = tryOneName(cfg.dnsConfig, rname, qtype)
Alex Brainman9ded9542011-06-13 10:22:31 +1000312 if err == nil {
313 return
314 }
315 }
316
Alex A Skinner854dbb72014-08-30 07:50:50 +0900317 // Last ditch effort: try unsuffixed only if we haven't already,
318 // that is, name is not rooted and has less than ndots dots.
319 if count(name, '.') < cfg.dnsConfig.ndots {
320 cname, addrs, err = tryOneName(cfg.dnsConfig, name+".", qtype)
321 if err == nil {
322 return
323 }
Alex Brainman9ded9542011-06-13 10:22:31 +1000324 }
Alex A Skinner854dbb72014-08-30 07:50:50 +0900325
Russ Cox94a65112013-10-02 22:09:54 -0400326 if e, ok := err.(*DNSError); ok {
327 // Show original name passed to lookup, not suffixed one.
328 // In general we might have tried many suffixes; showing
329 // just one is misleading. See also golang.org/issue/6324.
330 e.Name = name
331 }
Alex Brainman9ded9542011-06-13 10:22:31 +1000332 return
333}
334
335// goLookupHost is the native Go implementation of LookupHost.
336// Used only if cgoLookupHost refuses to handle the request
337// (that is, only if cgoLookupHost is the stub in cgo_stub.go).
338// Normally we let cgo use the C library resolver instead of
339// depending on our lookup code, so that Go and C get the same
340// answers.
Russ Coxeb692922011-11-01 22:05:34 -0400341func goLookupHost(name string) (addrs []string, err error) {
Alex Brainman9ded9542011-06-13 10:22:31 +1000342 // Use entries from /etc/hosts if they match.
343 addrs = lookupStaticHost(name)
344 if len(addrs) > 0 {
345 return
346 }
Alex Brainman9ded9542011-06-13 10:22:31 +1000347 ips, err := goLookupIP(name)
348 if err != nil {
349 return
350 }
351 addrs = make([]string, 0, len(ips))
352 for _, ip := range ips {
353 addrs = append(addrs, ip.String())
354 }
355 return
356}
357
358// goLookupIP is the native Go implementation of LookupIP.
359// Used only if cgoLookupIP refuses to handle the request
360// (that is, only if cgoLookupIP is the stub in cgo_stub.go).
361// Normally we let cgo use the C library resolver instead of
362// depending on our lookup code, so that Go and C get the same
363// answers.
Russ Coxeb692922011-11-01 22:05:34 -0400364func goLookupIP(name string) (addrs []IP, err error) {
Andrey Mirtchovski003bfa02011-09-19 11:50:31 -0400365 // Use entries from /etc/hosts if possible.
366 haddrs := lookupStaticHost(name)
367 if len(haddrs) > 0 {
368 for _, haddr := range haddrs {
369 if ip := ParseIP(haddr); ip != nil {
370 addrs = append(addrs, ip)
371 }
372 }
373 if len(addrs) > 0 {
374 return
375 }
376 }
Alex A Skinner39a021b2014-08-30 13:12:28 +0900377 type racer struct {
378 qtype uint16
379 rrs []dnsRR
380 error
Alex Brainman9ded9542011-06-13 10:22:31 +1000381 }
Alex A Skinner39a021b2014-08-30 13:12:28 +0900382 lane := make(chan racer, 1)
383 qtypes := [...]uint16{dnsTypeA, dnsTypeAAAA}
384 for _, qtype := range qtypes {
385 go func(qtype uint16) {
386 _, rrs, err := lookup(name, qtype)
387 lane <- racer{qtype, rrs, err}
388 }(qtype)
Alex Brainman9ded9542011-06-13 10:22:31 +1000389 }
Alex A Skinner39a021b2014-08-30 13:12:28 +0900390 var lastErr error
391 for range qtypes {
392 racer := <-lane
393 if racer.error != nil {
394 lastErr = racer.error
395 continue
396 }
397 switch racer.qtype {
398 case dnsTypeA:
399 addrs = append(addrs, convertRR_A(racer.rrs)...)
400 case dnsTypeAAAA:
401 addrs = append(addrs, convertRR_AAAA(racer.rrs)...)
402 }
Alex Brainman9ded9542011-06-13 10:22:31 +1000403 }
Alex A Skinner39a021b2014-08-30 13:12:28 +0900404 if len(addrs) == 0 && lastErr != nil {
405 return nil, lastErr
Michael Stapelbergdfbd42e2012-06-25 17:32:39 -0400406 }
Michael Stapelbergdfbd42e2012-06-25 17:32:39 -0400407 return addrs, nil
Alex Brainman9ded9542011-06-13 10:22:31 +1000408}
409
410// goLookupCNAME is the native Go implementation of LookupCNAME.
411// Used only if cgoLookupCNAME refuses to handle the request
412// (that is, only if cgoLookupCNAME is the stub in cgo_stub.go).
413// Normally we let cgo use the C library resolver instead of
414// depending on our lookup code, so that Go and C get the same
415// answers.
Russ Coxeb692922011-11-01 22:05:34 -0400416func goLookupCNAME(name string) (cname string, err error) {
Alex Brainman9ded9542011-06-13 10:22:31 +1000417 _, rr, err := lookup(name, dnsTypeCNAME)
418 if err != nil {
419 return
420 }
421 cname = rr[0].(*dnsRR_CNAME).Cname
422 return
423}