aboutsummaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorKyle Lemons <kyle@kylelemons.net>2011-01-19 15:11:03 -0500
committerRuss Cox <rsc@golang.org>2011-01-19 15:11:03 -0500
commita4f6ed3574c7c6edc673346c0629d866108ace7e (patch)
treeba406e02ba294951221a7355be9c6d205581b1a6
parent73302bc190a13100b7b1ceccd158fc37aa3d4a6f (diff)
downloadgo-a4f6ed3574c7c6edc673346c0629d866108ace7e.tar.gz
go-a4f6ed3574c7c6edc673346c0629d866108ace7e.zip
net: add LookupAddr
R=adg, rsc CC=golang-dev https://golang.org/cl/3851041
-rw-r--r--src/pkg/net/dnsclient.go54
-rw-r--r--src/pkg/net/hosts.go31
-rw-r--r--src/pkg/net/net_test.go37
3 files changed, 114 insertions, 8 deletions
diff --git a/src/pkg/net/dnsclient.go b/src/pkg/net/dnsclient.go
index f1cd47bb19..87d76261f8 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"
@@ -357,9 +359,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
+}
diff --git a/src/pkg/net/hosts.go b/src/pkg/net/hosts.go
index 556d57f112..8525f578d7 100644
--- a/src/pkg/net/hosts.go
+++ b/src/pkg/net/hosts.go
@@ -19,16 +19,18 @@ var hostsPath = "/etc/hosts"
// Simple cache.
var hosts struct {
sync.Mutex
- data map[string][]string
- time int64
- path string
+ byName map[string][]string
+ byAddr map[string][]string
+ time int64
+ path string
}
func readHosts() {
now, _, _ := os.Time()
hp := hostsPath
- if len(hosts.data) == 0 || hosts.time+cacheMaxAge <= now || hosts.path != hp {
+ if len(hosts.byName) == 0 || hosts.time+cacheMaxAge <= now || hosts.path != hp {
hs := make(map[string][]string)
+ is := make(map[string][]string)
var file *file
if file, _ = open(hp); file == nil {
return
@@ -45,12 +47,14 @@ func readHosts() {
for i := 1; i < len(f); i++ {
h := f[i]
hs[h] = append(hs[h], f[0])
+ is[f[0]] = append(is[f[0]], h)
}
}
// Update the data cache.
hosts.time, _, _ = os.Time()
hosts.path = hp
- hosts.data = hs
+ hosts.byName = hs
+ hosts.byAddr = is
file.close()
}
}
@@ -60,10 +64,23 @@ func lookupStaticHost(host string) []string {
hosts.Lock()
defer hosts.Unlock()
readHosts()
- if len(hosts.data) != 0 {
- if ips, ok := hosts.data[host]; ok {
+ if len(hosts.byName) != 0 {
+ if ips, ok := hosts.byName[host]; ok {
return ips
}
}
return nil
}
+
+// rlookupStaticHosts looks up the hosts for the given address from /etc/hosts.
+func lookupStaticAddr(addr string) []string {
+ hosts.Lock()
+ defer hosts.Unlock()
+ readHosts()
+ if len(hosts.byAddr) != 0 {
+ if hosts, ok := hosts.byAddr[addr]; ok {
+ return hosts
+ }
+ }
+ return nil
+}
diff --git a/src/pkg/net/net_test.go b/src/pkg/net/net_test.go
index 1de7a856a7..5f60972ace 100644
--- a/src/pkg/net/net_test.go
+++ b/src/pkg/net/net_test.go
@@ -83,3 +83,40 @@ func TestDialError(t *testing.T) {
}
}
}
+
+var revAddrTests = []struct {
+ Addr string
+ Reverse string
+ ErrPrefix string
+}{
+ {"1.2.3.4", "4.3.2.1.in-addr.arpa.", ""},
+ {"245.110.36.114", "114.36.110.245.in-addr.arpa.", ""},
+ {"::ffff:12.34.56.78", "78.56.34.12.in-addr.arpa.", ""},
+ {"::1", "1.0.0.0.0.0.0.0.0.0.0.0.0.0.0.0.0.0.0.0.0.0.0.0.0.0.0.0.0.0.0.0.ip6.arpa.", ""},
+ {"1::", "0.0.0.0.0.0.0.0.0.0.0.0.0.0.0.0.0.0.0.0.0.0.0.0.0.0.0.0.1.0.0.0.ip6.arpa.", ""},
+ {"1234:567::89a:bcde", "e.d.c.b.a.9.8.0.0.0.0.0.0.0.0.0.0.0.0.0.0.0.0.0.7.6.5.0.4.3.2.1.ip6.arpa.", ""},
+ {"1234:567:fefe:bcbc:adad:9e4a:89a:bcde", "e.d.c.b.a.9.8.0.a.4.e.9.d.a.d.a.c.b.c.b.e.f.e.f.7.6.5.0.4.3.2.1.ip6.arpa.", ""},
+ {"1.2.3", "", "unrecognized address"},
+ {"1.2.3.4.5", "", "unrecognized address"},
+ {"1234:567:bcbca::89a:bcde", "", "unrecognized address"},
+ {"1234:567::bcbc:adad::89a:bcde", "", "unrecognized address"},
+}
+
+func TestReverseAddress(t *testing.T) {
+ for i, tt := range revAddrTests {
+ a, e := reverseaddr(tt.Addr)
+ if len(tt.ErrPrefix) > 0 && e == nil {
+ t.Errorf("#%d: expected %q, got <nil> (error)", i, tt.ErrPrefix)
+ continue
+ }
+ if len(tt.ErrPrefix) == 0 && e != nil {
+ t.Errorf("#%d: expected <nil>, got %q (error)", i, e)
+ }
+ if e != nil && e.(*DNSError).Error != tt.ErrPrefix {
+ t.Errorf("#%d: expected %q, got %q (mismatched error)", i, tt.ErrPrefix, e.(*DNSError).Error)
+ }
+ if a != tt.Reverse {
+ t.Errorf("#%d: expected %q, got %q (reverse address)", i, tt.Reverse, a)
+ }
+ }
+}