mirror of
https://github.com/golang/go
synced 2024-11-25 08:57:58 -07:00
net: add LookupAddr
R=adg, rsc CC=golang-dev https://golang.org/cl/3851041
This commit is contained in:
parent
73302bc190
commit
a4f6ed3574
@ -15,6 +15,8 @@
|
|||||||
package net
|
package net
|
||||||
|
|
||||||
import (
|
import (
|
||||||
|
"bytes"
|
||||||
|
"fmt"
|
||||||
"os"
|
"os"
|
||||||
"rand"
|
"rand"
|
||||||
"sync"
|
"sync"
|
||||||
@ -357,9 +359,59 @@ func LookupMX(name string) (entries []*MX, err os.Error) {
|
|||||||
return
|
return
|
||||||
}
|
}
|
||||||
entries = make([]*MX, len(records))
|
entries = make([]*MX, len(records))
|
||||||
for i := 0; i < len(records); i++ {
|
for i := range records {
|
||||||
r := records[i].(*dnsRR_MX)
|
r := records[i].(*dnsRR_MX)
|
||||||
entries[i] = &MX{r.Mx, r.Pref}
|
entries[i] = &MX{r.Mx, r.Pref}
|
||||||
}
|
}
|
||||||
return
|
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
|
||||||
|
}
|
||||||
|
@ -19,7 +19,8 @@ var hostsPath = "/etc/hosts"
|
|||||||
// Simple cache.
|
// Simple cache.
|
||||||
var hosts struct {
|
var hosts struct {
|
||||||
sync.Mutex
|
sync.Mutex
|
||||||
data map[string][]string
|
byName map[string][]string
|
||||||
|
byAddr map[string][]string
|
||||||
time int64
|
time int64
|
||||||
path string
|
path string
|
||||||
}
|
}
|
||||||
@ -27,8 +28,9 @@ var hosts struct {
|
|||||||
func readHosts() {
|
func readHosts() {
|
||||||
now, _, _ := os.Time()
|
now, _, _ := os.Time()
|
||||||
hp := hostsPath
|
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)
|
hs := make(map[string][]string)
|
||||||
|
is := make(map[string][]string)
|
||||||
var file *file
|
var file *file
|
||||||
if file, _ = open(hp); file == nil {
|
if file, _ = open(hp); file == nil {
|
||||||
return
|
return
|
||||||
@ -45,12 +47,14 @@ func readHosts() {
|
|||||||
for i := 1; i < len(f); i++ {
|
for i := 1; i < len(f); i++ {
|
||||||
h := f[i]
|
h := f[i]
|
||||||
hs[h] = append(hs[h], f[0])
|
hs[h] = append(hs[h], f[0])
|
||||||
|
is[f[0]] = append(is[f[0]], h)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
// Update the data cache.
|
// Update the data cache.
|
||||||
hosts.time, _, _ = os.Time()
|
hosts.time, _, _ = os.Time()
|
||||||
hosts.path = hp
|
hosts.path = hp
|
||||||
hosts.data = hs
|
hosts.byName = hs
|
||||||
|
hosts.byAddr = is
|
||||||
file.close()
|
file.close()
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@ -60,10 +64,23 @@ func lookupStaticHost(host string) []string {
|
|||||||
hosts.Lock()
|
hosts.Lock()
|
||||||
defer hosts.Unlock()
|
defer hosts.Unlock()
|
||||||
readHosts()
|
readHosts()
|
||||||
if len(hosts.data) != 0 {
|
if len(hosts.byName) != 0 {
|
||||||
if ips, ok := hosts.data[host]; ok {
|
if ips, ok := hosts.byName[host]; ok {
|
||||||
return ips
|
return ips
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
return nil
|
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
|
||||||
|
}
|
||||||
|
@ -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)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
Loading…
Reference in New Issue
Block a user