summaryrefslogtreecommitdiff
path: root/src/pkg/net/dnsclient_unix.go
diff options
context:
space:
mode:
Diffstat (limited to 'src/pkg/net/dnsclient_unix.go')
-rw-r--r--src/pkg/net/dnsclient_unix.go364
1 files changed, 0 insertions, 364 deletions
diff --git a/src/pkg/net/dnsclient_unix.go b/src/pkg/net/dnsclient_unix.go
deleted file mode 100644
index 3713efd0e..000000000
--- a/src/pkg/net/dnsclient_unix.go
+++ /dev/null
@@ -1,364 +0,0 @@
-// Copyright 2009 The Go Authors. All rights reserved.
-// Use of this source code is governed by a BSD-style
-// license that can be found in the LICENSE file.
-
-// +build darwin dragonfly freebsd linux nacl netbsd openbsd solaris
-
-// DNS client: see RFC 1035.
-// Has to be linked into package net for Dial.
-
-// TODO(rsc):
-// Could potentially handle many outstanding lookups faster.
-// Could have a small cache.
-// Random UDP source port (net.Dial should do that for us).
-// Random request IDs.
-
-package net
-
-import (
- "io"
- "math/rand"
- "os"
- "sync"
- "time"
-)
-
-// Send a request on the connection and hope for a reply.
-// Up to cfg.attempts attempts.
-func exchange(cfg *dnsConfig, c Conn, name string, qtype uint16) (*dnsMsg, error) {
- _, useTCP := c.(*TCPConn)
- if len(name) >= 256 {
- return nil, &DNSError{Err: "name too long", Name: name}
- }
- out := new(dnsMsg)
- out.id = uint16(rand.Int()) ^ uint16(time.Now().UnixNano())
- out.question = []dnsQuestion{
- {name, qtype, dnsClassINET},
- }
- out.recursion_desired = true
- msg, ok := out.Pack()
- if !ok {
- return nil, &DNSError{Err: "internal error - cannot pack message", Name: name}
- }
- if useTCP {
- mlen := uint16(len(msg))
- msg = append([]byte{byte(mlen >> 8), byte(mlen)}, msg...)
- }
- for attempt := 0; attempt < cfg.attempts; attempt++ {
- n, err := c.Write(msg)
- if err != nil {
- return nil, err
- }
-
- if cfg.timeout == 0 {
- c.SetReadDeadline(noDeadline)
- } else {
- c.SetReadDeadline(time.Now().Add(time.Duration(cfg.timeout) * time.Second))
- }
- buf := make([]byte, 2000)
- if useTCP {
- n, err = io.ReadFull(c, buf[:2])
- if err != nil {
- if e, ok := err.(Error); ok && e.Timeout() {
- continue
- }
- }
- mlen := int(buf[0])<<8 | int(buf[1])
- if mlen > len(buf) {
- buf = make([]byte, mlen)
- }
- n, err = io.ReadFull(c, buf[:mlen])
- } else {
- n, err = c.Read(buf)
- }
- if err != nil {
- if e, ok := err.(Error); ok && e.Timeout() {
- continue
- }
- return nil, err
- }
- buf = buf[:n]
- in := new(dnsMsg)
- if !in.Unpack(buf) || in.id != out.id {
- continue
- }
- return in, nil
- }
- var server string
- if a := c.RemoteAddr(); a != nil {
- server = a.String()
- }
- return nil, &DNSError{Err: "no answer from server", Name: name, Server: server, IsTimeout: true}
-}
-
-// Do a lookup for a single name, which must be rooted
-// (otherwise answer will not find the answers).
-func tryOneName(cfg *dnsConfig, name string, qtype uint16) (cname string, addrs []dnsRR, err error) {
- if len(cfg.servers) == 0 {
- return "", nil, &DNSError{Err: "no DNS servers", Name: name}
- }
- for i := 0; i < len(cfg.servers); i++ {
- // Calling Dial here is scary -- we have to be sure
- // not to dial a name that will require a DNS lookup,
- // or Dial will call back here to translate it.
- // The DNS config parser has already checked that
- // all the cfg.servers[i] are IP addresses, which
- // Dial will use without a DNS lookup.
- server := cfg.servers[i] + ":53"
- c, cerr := Dial("udp", server)
- if cerr != nil {
- err = cerr
- continue
- }
- msg, merr := exchange(cfg, c, name, qtype)
- c.Close()
- if merr != nil {
- err = merr
- continue
- }
- if msg.truncated { // see RFC 5966
- c, cerr = Dial("tcp", server)
- if cerr != nil {
- err = cerr
- continue
- }
- msg, merr = exchange(cfg, c, name, qtype)
- c.Close()
- if merr != nil {
- err = merr
- continue
- }
- }
- cname, addrs, err = answer(name, server, msg, qtype)
- if err == nil || err.(*DNSError).Err == noSuchHost {
- break
- }
- }
- return
-}
-
-func convertRR_A(records []dnsRR) []IP {
- addrs := make([]IP, len(records))
- for i, rr := range records {
- a := rr.(*dnsRR_A).A
- addrs[i] = IPv4(byte(a>>24), byte(a>>16), byte(a>>8), byte(a))
- }
- return addrs
-}
-
-func convertRR_AAAA(records []dnsRR) []IP {
- addrs := make([]IP, len(records))
- for i, rr := range records {
- a := make(IP, IPv6len)
- copy(a, rr.(*dnsRR_AAAA).AAAA[:])
- addrs[i] = a
- }
- return addrs
-}
-
-var cfg struct {
- ch chan struct{}
- mu sync.RWMutex // protects dnsConfig and dnserr
- dnsConfig *dnsConfig
- dnserr error
-}
-var onceLoadConfig sync.Once
-
-// Assume dns config file is /etc/resolv.conf here
-func loadDefaultConfig() {
- loadConfig("/etc/resolv.conf", 5*time.Second, nil)
-}
-
-func loadConfig(resolvConfPath string, reloadTime time.Duration, quit <-chan chan struct{}) {
- var mtime time.Time
- cfg.ch = make(chan struct{}, 1)
- if fi, err := os.Stat(resolvConfPath); err != nil {
- cfg.dnserr = err
- } else {
- mtime = fi.ModTime()
- cfg.dnsConfig, cfg.dnserr = dnsReadConfig(resolvConfPath)
- }
- go func() {
- for {
- time.Sleep(reloadTime)
- select {
- case qresp := <-quit:
- qresp <- struct{}{}
- return
- case <-cfg.ch:
- }
-
- // In case of error, we keep the previous config
- fi, err := os.Stat(resolvConfPath)
- if err != nil {
- continue
- }
- // If the resolv.conf mtime didn't change, do not reload
- m := fi.ModTime()
- if m.Equal(mtime) {
- continue
- }
- mtime = m
- // In case of error, we keep the previous config
- ncfg, err := dnsReadConfig(resolvConfPath)
- if err != nil || len(ncfg.servers) == 0 {
- continue
- }
- cfg.mu.Lock()
- cfg.dnsConfig = ncfg
- cfg.dnserr = nil
- cfg.mu.Unlock()
- }
- }()
-}
-
-func lookup(name string, qtype uint16) (cname string, addrs []dnsRR, err error) {
- if !isDomainName(name) {
- return name, nil, &DNSError{Err: "invalid domain name", Name: name}
- }
- onceLoadConfig.Do(loadDefaultConfig)
-
- select {
- case cfg.ch <- struct{}{}:
- default:
- }
-
- cfg.mu.RLock()
- defer cfg.mu.RUnlock()
-
- if cfg.dnserr != nil || cfg.dnsConfig == nil {
- err = cfg.dnserr
- return
- }
- // If name is rooted (trailing dot) or has enough dots,
- // try it by itself first.
- rooted := len(name) > 0 && name[len(name)-1] == '.'
- if rooted || count(name, '.') >= cfg.dnsConfig.ndots {
- rname := name
- if !rooted {
- rname += "."
- }
- // Can try as ordinary name.
- cname, addrs, err = tryOneName(cfg.dnsConfig, rname, qtype)
- if err == nil {
- return
- }
- }
- if rooted {
- return
- }
-
- // Otherwise, try suffixes.
- for i := 0; i < len(cfg.dnsConfig.search); i++ {
- rname := name + "." + cfg.dnsConfig.search[i]
- if rname[len(rname)-1] != '.' {
- rname += "."
- }
- cname, addrs, err = tryOneName(cfg.dnsConfig, rname, qtype)
- if err == nil {
- return
- }
- }
-
- // Last ditch effort: try unsuffixed.
- rname := name
- if !rooted {
- rname += "."
- }
- cname, addrs, err = tryOneName(cfg.dnsConfig, rname, qtype)
- if err == nil {
- return
- }
- if e, ok := err.(*DNSError); ok {
- // Show original name passed to lookup, not suffixed one.
- // In general we might have tried many suffixes; showing
- // just one is misleading. See also golang.org/issue/6324.
- e.Name = name
- }
- return
-}
-
-// goLookupHost is the native Go implementation of LookupHost.
-// Used only if cgoLookupHost refuses to handle the request
-// (that is, only if cgoLookupHost is the stub in cgo_stub.go).
-// Normally we let cgo use the C library resolver instead of
-// depending on our lookup code, so that Go and C get the same
-// answers.
-func goLookupHost(name string) (addrs []string, err error) {
- // Use entries from /etc/hosts if they match.
- addrs = lookupStaticHost(name)
- if len(addrs) > 0 {
- return
- }
- ips, err := goLookupIP(name)
- if err != nil {
- return
- }
- addrs = make([]string, 0, len(ips))
- for _, ip := range ips {
- addrs = append(addrs, ip.String())
- }
- return
-}
-
-// goLookupIP is the native Go implementation of LookupIP.
-// Used only if cgoLookupIP refuses to handle the request
-// (that is, only if cgoLookupIP is the stub in cgo_stub.go).
-// Normally we let cgo use the C library resolver instead of
-// depending on our lookup code, so that Go and C get the same
-// answers.
-func goLookupIP(name string) (addrs []IP, err error) {
- // Use entries from /etc/hosts if possible.
- haddrs := lookupStaticHost(name)
- if len(haddrs) > 0 {
- for _, haddr := range haddrs {
- if ip := ParseIP(haddr); ip != nil {
- addrs = append(addrs, ip)
- }
- }
- if len(addrs) > 0 {
- return
- }
- }
- var records []dnsRR
- var cname string
- var err4, err6 error
- cname, records, err4 = lookup(name, dnsTypeA)
- addrs = convertRR_A(records)
- if cname != "" {
- name = cname
- }
- _, records, err6 = lookup(name, dnsTypeAAAA)
- if err4 != nil && err6 == nil {
- // Ignore A error because AAAA lookup succeeded.
- err4 = nil
- }
- if err6 != nil && len(addrs) > 0 {
- // Ignore AAAA error because A lookup succeeded.
- err6 = nil
- }
- if err4 != nil {
- return nil, err4
- }
- if err6 != nil {
- return nil, err6
- }
-
- addrs = append(addrs, convertRR_AAAA(records)...)
- return addrs, nil
-}
-
-// goLookupCNAME is the native Go implementation of LookupCNAME.
-// Used only if cgoLookupCNAME refuses to handle the request
-// (that is, only if cgoLookupCNAME is the stub in cgo_stub.go).
-// Normally we let cgo use the C library resolver instead of
-// depending on our lookup code, so that Go and C get the same
-// answers.
-func goLookupCNAME(name string) (cname string, err error) {
- _, rr, err := lookup(name, dnsTypeCNAME)
- if err != nil {
- return
- }
- cname = rr[0].(*dnsRR_CNAME).Cname
- return
-}