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