Files
weave/nameserver/zone.go
T
Michael Bridgen 3866bd5e63 Parse reverse address lookup IPs in the Zone
.. rather than making clients of the zone do it. At the minute there's
only one call site, but soon there will be more.
2015-01-08 13:39:33 +00:00

132 lines
2.8 KiB
Go

package nameserver
import (
"github.com/miekg/dns"
. "github.com/zettio/weave/common"
"net"
"sync"
)
const (
RDNS_DOMAIN = "in-addr.arpa."
)
// +1 to also exclude a dot
var rdnsDomainLen = len(RDNS_DOMAIN) + 1
type Zone interface {
AddRecord(ident string, name string, ip net.IP) error
DeleteRecord(ident string, ip net.IP) error
DeleteRecordsFor(ident string) error
LookupLocal(name string) (net.IP, error)
ReverseLookupLocal(inaddr string) (string, error)
}
type Record struct {
Ident string
Name string
IP net.IP
}
// Very simple data structure for now, with linear searching.
// TODO: make more sophisticated to improve performance.
type ZoneDb struct {
mx sync.RWMutex
recs []Record
}
type LookupError string
func (ops LookupError) Error() string {
return "Unable to find " + string(ops)
}
type DuplicateError struct {
}
func (dup DuplicateError) Error() string {
return "Tried to add a duplicate entry"
}
func (zone *ZoneDb) indexOf(match func(Record) bool) int {
for i, r := range zone.recs {
if match(r) {
return i
}
}
return -1
}
func (zone *ZoneDb) LookupLocal(name string) (net.IP, error) {
zone.mx.RLock()
defer zone.mx.RUnlock()
for _, r := range zone.recs {
if r.Name == name {
return r.IP, nil
}
}
return nil, LookupError(name)
}
func (zone *ZoneDb) ReverseLookupLocal(inaddr string) (string, error) {
if revIP := net.ParseIP(inaddr[:len(inaddr)-rdnsDomainLen]); revIP != nil {
revIP4 := revIP.To4()
ip := []byte{revIP4[3], revIP4[2], revIP4[1], revIP4[0]}
Debug.Printf("Looking for address: %+v", ip)
zone.mx.RLock()
defer zone.mx.RUnlock()
for _, r := range zone.recs {
if r.IP.Equal(ip) {
return r.Name, nil
}
}
return "", LookupError(inaddr)
} else {
Warning.Printf("Asked to reverse lookup %s", inaddr)
return "", LookupError(inaddr)
}
}
func (zone *ZoneDb) AddRecord(ident string, name string, ip net.IP) error {
zone.mx.Lock()
defer zone.mx.Unlock()
fqdn := dns.Fqdn(name)
if index := zone.indexOf(
func(r Record) bool {
return r.Name == fqdn && r.IP.Equal(ip) && r.Ident == ident
}); index != -1 {
return DuplicateError{}
}
zone.recs = append(zone.recs, Record{ident, fqdn, ip})
return nil
}
func (zone *ZoneDb) DeleteRecord(ident string, ip net.IP) error {
zone.mx.Lock()
defer zone.mx.Unlock()
if index := zone.indexOf(
func(r Record) bool {
return r.Ident == ident && r.IP.Equal(ip)
}); index == -1 {
return LookupError(ident)
} else {
zone.recs = append(zone.recs[:index], zone.recs[index+1:]...)
}
return nil
}
func (zone *ZoneDb) DeleteRecordsFor(ident string) error {
zone.mx.Lock()
defer zone.mx.Unlock()
w := 0 // write index
for _, r := range zone.recs {
if r.Ident != ident {
zone.recs[w] = r
w++
}
}
zone.recs = zone.recs[:w]
return nil
}