summaryrefslogtreecommitdiff
path: root/src/pkg/net/dnsclient.go
diff options
context:
space:
mode:
authorOndřej Surý <ondrej@sury.org>2011-02-14 13:23:51 +0100
committerOndřej Surý <ondrej@sury.org>2011-02-14 13:23:51 +0100
commit758ff64c69e34965f8af5b2d6ffd65e8d7ab2150 (patch)
tree6d6b34f8c678862fe9b56c945a7b63f68502c245 /src/pkg/net/dnsclient.go
parent3e45412327a2654a77944249962b3652e6142299 (diff)
downloadgolang-upstream/2011-02-01.1.tar.gz
Imported Upstream version 2011-02-01.1upstream/2011-02-01.1
Diffstat (limited to 'src/pkg/net/dnsclient.go')
-rw-r--r--src/pkg/net/dnsclient.go81
1 files changed, 65 insertions, 16 deletions
diff --git a/src/pkg/net/dnsclient.go b/src/pkg/net/dnsclient.go
index f1cd47bb1..3252dd454 100644
--- a/src/pkg/net/dnsclient.go
+++ b/src/pkg/net/dnsclient.go
@@ -15,6 +15,8 @@
package net
import (
+ "bytes"
+ "fmt"
"os"
"rand"
"sync"
@@ -96,18 +98,18 @@ func exchange(cfg *dnsConfig, c Conn, name string, qtype uint16) (*dnsMsg, os.Er
// Find answer for name in dns message.
// On return, if err == nil, addrs != nil.
-func answer(name, server string, dns *dnsMsg, qtype uint16) (addrs []dnsRR, err os.Error) {
+func answer(name, server string, dns *dnsMsg, qtype uint16) (cname string, addrs []dnsRR, err os.Error) {
addrs = make([]dnsRR, 0, len(dns.answer))
if dns.rcode == dnsRcodeNameError && dns.recursion_available {
- return nil, &DNSError{Error: noSuchHost, Name: name}
+ return "", nil, &DNSError{Error: noSuchHost, Name: name}
}
if dns.rcode != dnsRcodeSuccess {
// None of the error codes make sense
// for the query we sent. If we didn't get
// a name error and we didn't get success,
// the server is behaving incorrectly.
- return nil, &DNSError{Error: "server misbehaving", Name: name, Server: server}
+ return "", nil, &DNSError{Error: "server misbehaving", Name: name, Server: server}
}
// Look for the name.
@@ -135,19 +137,19 @@ Cname:
}
}
if len(addrs) == 0 {
- return nil, &DNSError{Error: noSuchHost, Name: name, Server: server}
+ return "", nil, &DNSError{Error: noSuchHost, Name: name, Server: server}
}
- return addrs, nil
+ return name, addrs, nil
}
- return nil, &DNSError{Error: "too many redirects", Name: name, Server: server}
+ return "", nil, &DNSError{Error: "too many redirects", Name: name, Server: server}
}
// 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) (addrs []dnsRR, err os.Error) {
+func tryOneName(cfg *dnsConfig, name string, qtype uint16) (cname string, addrs []dnsRR, err os.Error) {
if len(cfg.servers) == 0 {
- return nil, &DNSError{Error: "no DNS servers", Name: name}
+ return "", nil, &DNSError{Error: "no DNS servers", Name: name}
}
for i := 0; i < len(cfg.servers); i++ {
// Calling Dial here is scary -- we have to be sure
@@ -168,7 +170,7 @@ func tryOneName(cfg *dnsConfig, name string, qtype uint16) (addrs []dnsRR, err o
err = merr
continue
}
- addrs, err = answer(name, server, msg, qtype)
+ cname, addrs, err = answer(name, server, msg, qtype)
if err == nil || err.(*DNSError).Error == noSuchHost {
break
}
@@ -259,9 +261,8 @@ func lookup(name string, qtype uint16) (cname string, addrs []dnsRR, err os.Erro
rname += "."
}
// Can try as ordinary name.
- addrs, err = tryOneName(cfg, rname, qtype)
+ cname, addrs, err = tryOneName(cfg, rname, qtype)
if err == nil {
- cname = rname
return
}
}
@@ -275,9 +276,8 @@ func lookup(name string, qtype uint16) (cname string, addrs []dnsRR, err os.Erro
if rname[len(rname)-1] != '.' {
rname += "."
}
- addrs, err = tryOneName(cfg, rname, qtype)
+ cname, addrs, err = tryOneName(cfg, rname, qtype)
if err == nil {
- cname = rname
return
}
}
@@ -287,9 +287,8 @@ func lookup(name string, qtype uint16) (cname string, addrs []dnsRR, err os.Erro
if !rooted {
rname += "."
}
- addrs, err = tryOneName(cfg, rname, qtype)
+ cname, addrs, err = tryOneName(cfg, rname, qtype)
if err == nil {
- cname = rname
return
}
return
@@ -357,9 +356,59 @@ func LookupMX(name string) (entries []*MX, err os.Error) {
return
}
entries = make([]*MX, len(records))
- for i := 0; i < len(records); i++ {
+ for i := range records {
r := records[i].(*dnsRR_MX)
entries[i] = &MX{r.Mx, r.Pref}
}
return
}
+
+// reverseaddr returns the in-addr.arpa. or ip6.arpa. hostname of the IP
+// address addr suitable for rDNS (PTR) record lookup or an error if it fails
+// to parse the IP address.
+func reverseaddr(addr string) (arpa string, err os.Error) {
+ ip := ParseIP(addr)
+ if ip == nil {
+ return "", &DNSError{Error: "unrecognized address", Name: addr}
+ }
+ if ip.To4() != nil {
+ return fmt.Sprintf("%d.%d.%d.%d.in-addr.arpa.", ip[15], ip[14], ip[13], ip[12]), nil
+ }
+ // Must be IPv6
+ var buf bytes.Buffer
+ // Add it, in reverse, to the buffer
+ for i := len(ip) - 1; i >= 0; i-- {
+ s := fmt.Sprintf("%02x", ip[i])
+ buf.WriteByte(s[1])
+ buf.WriteByte('.')
+ buf.WriteByte(s[0])
+ buf.WriteByte('.')
+ }
+ // Append "ip6.arpa." and return (buf already has the final .)
+ return buf.String() + "ip6.arpa.", nil
+}
+
+// LookupAddr performs a reverse lookup for the given address, returning a list
+// of names mapping to that address.
+func LookupAddr(addr string) (name []string, err os.Error) {
+ name = lookupStaticAddr(addr)
+ if len(name) > 0 {
+ return
+ }
+ var arpa string
+ arpa, err = reverseaddr(addr)
+ if err != nil {
+ return
+ }
+ var records []dnsRR
+ _, records, err = lookup(arpa, dnsTypePTR)
+ if err != nil {
+ return
+ }
+ name = make([]string, len(records))
+ for i := range records {
+ r := records[i].(*dnsRR_PTR)
+ name[i] = r.Ptr
+ }
+ return
+}