2012-07-15 06:01:52 +10:00
|
|
|
package dns
|
|
|
|
|
|
|
|
// A structure for handling zone data
|
|
|
|
|
|
|
|
import (
|
2012-08-08 19:08:25 +10:00
|
|
|
"github.com/miekg/radix"
|
2012-08-02 00:30:45 +10:00
|
|
|
"strings"
|
2012-08-26 03:57:25 +10:00
|
|
|
"sync"
|
2012-07-15 06:01:52 +10:00
|
|
|
)
|
|
|
|
|
2012-08-27 17:12:41 +10:00
|
|
|
// Zone represents a DNS zone. It's safe for concurrent use by
|
|
|
|
// multilpe goroutines.
|
2012-07-15 06:01:52 +10:00
|
|
|
type Zone struct {
|
2012-07-17 03:46:16 +10:00
|
|
|
Origin string // Origin of the zone
|
2012-08-17 16:29:45 +10:00
|
|
|
Wildcard int // Whenever we see a wildcard name, this is incremented
|
2012-07-16 02:11:17 +10:00
|
|
|
*radix.Radix // Zone data
|
2012-08-26 04:57:26 +10:00
|
|
|
mutex *sync.RWMutex
|
2012-07-15 06:01:52 +10:00
|
|
|
}
|
|
|
|
|
2012-08-27 17:12:41 +10:00
|
|
|
// NewZone creates an initialized zone with Origin set to origin.
|
|
|
|
func NewZone(origin string) *Zone {
|
|
|
|
if origin == "" {
|
|
|
|
origin = "."
|
|
|
|
}
|
|
|
|
if _, _, ok := IsDomainName(origin); !ok {
|
|
|
|
return nil
|
|
|
|
}
|
|
|
|
z := new(Zone)
|
|
|
|
z.mutex = new(sync.RWMutex)
|
|
|
|
z.Origin = Fqdn(origin)
|
|
|
|
z.Radix = radix.New()
|
|
|
|
return z
|
|
|
|
}
|
|
|
|
|
2012-08-26 03:38:52 +10:00
|
|
|
// ZoneData holds all the RRs having their owner name equal to Name.
|
2012-07-15 06:01:52 +10:00
|
|
|
type ZoneData struct {
|
2012-08-05 16:13:09 +10:00
|
|
|
Name string // Domain name for this node
|
|
|
|
RR map[uint16][]RR // Map of the RR type to the RR
|
2012-08-04 08:51:35 +10:00
|
|
|
Signatures map[uint16][]*RR_RRSIG // DNSSEC signatures for the RRs, stored under type covered
|
2012-08-25 22:44:51 +10:00
|
|
|
NonAuth bool // Always false, except for NSsets that differ from z.Origin
|
2012-08-26 03:57:25 +10:00
|
|
|
mutex *sync.RWMutex
|
2012-07-15 06:54:49 +10:00
|
|
|
}
|
|
|
|
|
2012-08-27 17:12:41 +10:00
|
|
|
// newZoneData creates a new zone data element
|
|
|
|
func newZoneData(s string) *ZoneData {
|
|
|
|
zd := new(ZoneData)
|
|
|
|
zd.Name = s
|
|
|
|
zd.RR = make(map[uint16][]RR)
|
|
|
|
zd.Signatures = make(map[uint16][]*RR_RRSIG)
|
|
|
|
zd.mutex = new(sync.RWMutex)
|
|
|
|
return zd
|
|
|
|
}
|
|
|
|
|
2012-08-26 03:38:52 +10:00
|
|
|
// toRadixName reverses a domain name so that when we store it in the radix tree
|
2012-08-02 00:30:45 +10:00
|
|
|
// we preserve the nsec ordering of the zone (this idea was stolen from NSD).
|
|
|
|
// each label is also lowercased.
|
|
|
|
func toRadixName(d string) string {
|
2012-08-05 16:13:09 +10:00
|
|
|
if d == "." {
|
|
|
|
return "."
|
|
|
|
}
|
2012-08-02 00:30:45 +10:00
|
|
|
s := ""
|
|
|
|
for _, l := range SplitLabels(d) {
|
2012-08-04 02:28:00 +10:00
|
|
|
s = strings.ToLower(l) + "." + s
|
2012-08-02 00:30:45 +10:00
|
|
|
}
|
2012-08-05 16:13:09 +10:00
|
|
|
return "." + s
|
2012-08-02 00:30:45 +10:00
|
|
|
}
|
|
|
|
|
2012-07-15 06:54:49 +10:00
|
|
|
|
2012-08-26 03:38:52 +10:00
|
|
|
// Insert inserts an RR into the zone. There is no check for duplicate data, although
|
2012-08-25 20:59:39 +10:00
|
|
|
// Remove will remove all duplicates.
|
2012-07-17 05:16:42 +10:00
|
|
|
func (z *Zone) Insert(r RR) error {
|
2012-08-10 05:05:20 +10:00
|
|
|
if !IsSubDomain(z.Origin, r.Header().Name) {
|
2012-07-17 05:16:42 +10:00
|
|
|
return &Error{Err: "out of zone data", Name: r.Header().Name}
|
2012-07-17 03:46:16 +10:00
|
|
|
}
|
|
|
|
|
2012-08-02 00:30:45 +10:00
|
|
|
key := toRadixName(r.Header().Name)
|
2012-08-26 03:57:25 +10:00
|
|
|
z.mutex.Lock()
|
2012-08-02 00:30:45 +10:00
|
|
|
zd := z.Radix.Find(key)
|
2012-07-16 02:11:17 +10:00
|
|
|
if zd == nil {
|
2012-08-26 03:57:25 +10:00
|
|
|
defer z.mutex.Unlock()
|
2012-08-10 07:00:51 +10:00
|
|
|
// Check if its a wildcard name
|
|
|
|
if len(r.Header().Name) > 1 && r.Header().Name[0] == '*' && r.Header().Name[1] == '.' {
|
|
|
|
z.Wildcard++
|
|
|
|
}
|
2012-08-27 17:12:41 +10:00
|
|
|
zd := newZoneData(r.Header().Name)
|
2012-07-16 02:11:17 +10:00
|
|
|
switch t := r.Header().Rrtype; t {
|
|
|
|
case TypeRRSIG:
|
2012-08-04 08:51:35 +10:00
|
|
|
sigtype := r.(*RR_RRSIG).TypeCovered
|
|
|
|
zd.Signatures[sigtype] = append(zd.Signatures[sigtype], r.(*RR_RRSIG))
|
2012-07-17 05:20:58 +10:00
|
|
|
case TypeNS:
|
|
|
|
// NS records with other names than z.Origin are non-auth
|
2012-07-17 05:24:05 +10:00
|
|
|
if r.Header().Name != z.Origin {
|
2012-07-17 05:20:58 +10:00
|
|
|
zd.NonAuth = true
|
|
|
|
}
|
|
|
|
fallthrough
|
2012-07-16 02:11:17 +10:00
|
|
|
default:
|
|
|
|
zd.RR[t] = append(zd.RR[t], r)
|
|
|
|
}
|
2012-08-02 00:30:45 +10:00
|
|
|
z.Radix.Insert(key, zd)
|
2012-07-17 05:24:05 +10:00
|
|
|
return nil
|
2012-07-16 02:11:17 +10:00
|
|
|
}
|
2012-08-26 03:57:25 +10:00
|
|
|
z.mutex.Unlock()
|
|
|
|
zd.Value.(*ZoneData).mutex.Lock()
|
|
|
|
defer zd.Value.(*ZoneData).mutex.Unlock()
|
2012-07-17 05:24:05 +10:00
|
|
|
// Name already there
|
2012-07-16 02:11:17 +10:00
|
|
|
switch t := r.Header().Rrtype; t {
|
|
|
|
case TypeRRSIG:
|
2012-08-04 08:51:35 +10:00
|
|
|
sigtype := r.(*RR_RRSIG).TypeCovered
|
|
|
|
zd.Value.(*ZoneData).Signatures[sigtype] = append(zd.Value.(*ZoneData).Signatures[sigtype], r.(*RR_RRSIG))
|
2012-07-17 05:20:58 +10:00
|
|
|
case TypeNS:
|
2012-07-17 05:24:05 +10:00
|
|
|
if r.Header().Name != z.Origin {
|
|
|
|
zd.Value.(*ZoneData).NonAuth = true
|
2012-07-17 05:20:58 +10:00
|
|
|
}
|
|
|
|
fallthrough
|
2012-07-16 02:11:17 +10:00
|
|
|
default:
|
2012-07-16 21:31:18 +10:00
|
|
|
zd.Value.(*ZoneData).RR[t] = append(zd.Value.(*ZoneData).RR[t], r)
|
2012-07-16 02:11:17 +10:00
|
|
|
}
|
2012-07-17 05:24:05 +10:00
|
|
|
return nil
|
2012-07-15 06:54:49 +10:00
|
|
|
}
|
|
|
|
|
2012-08-22 01:21:47 +10:00
|
|
|
// Remove removes the RR r from the zone. If there RR can not be found,
|
2012-08-25 20:59:39 +10:00
|
|
|
// this is a no-op.
|
2012-07-17 05:24:05 +10:00
|
|
|
func (z *Zone) Remove(r RR) error {
|
2012-08-25 20:59:39 +10:00
|
|
|
key := toRadixName(r.Header().Name)
|
2012-08-26 03:57:25 +10:00
|
|
|
z.mutex.Lock()
|
2012-08-25 20:59:39 +10:00
|
|
|
zd := z.Radix.Find(key)
|
|
|
|
if zd == nil {
|
2012-08-26 03:57:25 +10:00
|
|
|
defer z.mutex.Unlock()
|
2012-08-25 20:59:39 +10:00
|
|
|
return nil
|
|
|
|
}
|
2012-08-26 03:57:25 +10:00
|
|
|
z.mutex.Unlock()
|
|
|
|
zd.Value.(*ZoneData).mutex.Lock()
|
|
|
|
defer zd.Value.(*ZoneData).mutex.Unlock()
|
2012-08-25 22:44:51 +10:00
|
|
|
remove := false
|
2012-08-25 20:59:39 +10:00
|
|
|
switch t := r.Header().Rrtype; t {
|
|
|
|
case TypeRRSIG:
|
|
|
|
sigtype := r.(*RR_RRSIG).TypeCovered
|
2012-08-25 22:44:51 +10:00
|
|
|
for i, zr := range zd.Value.(*ZoneData).RR[sigtype] {
|
|
|
|
if r == zr {
|
|
|
|
zd.Value.(*ZoneData).RR[sigtype] = append(zd.Value.(*ZoneData).RR[sigtype][:i], zd.Value.(*ZoneData).RR[sigtype][i+1:]...)
|
|
|
|
remove = true
|
|
|
|
}
|
|
|
|
}
|
2012-08-25 20:59:39 +10:00
|
|
|
default:
|
2012-08-25 22:44:51 +10:00
|
|
|
for i, zr := range zd.Value.(*ZoneData).RR[t] {
|
2012-08-25 20:59:39 +10:00
|
|
|
if r == zr {
|
2012-08-25 22:44:51 +10:00
|
|
|
zd.Value.(*ZoneData).RR[t] = append(zd.Value.(*ZoneData).RR[t][:i], zd.Value.(*ZoneData).RR[t][i+1:]...)
|
|
|
|
remove = true
|
2012-08-25 20:59:39 +10:00
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|
2012-08-25 22:44:51 +10:00
|
|
|
if remove && len(r.Header().Name) > 1 && r.Header().Name[0] == '*' && r.Header().Name[1] == '.' {
|
2012-08-25 20:59:39 +10:00
|
|
|
z.Wildcard--
|
|
|
|
if z.Wildcard < 0 {
|
|
|
|
z.Wildcard = 0
|
|
|
|
}
|
|
|
|
}
|
2012-08-25 22:44:51 +10:00
|
|
|
// TODO(mg): what to do if the whole structure is empty? Set it to nil?
|
2012-07-17 05:24:05 +10:00
|
|
|
return nil
|
2012-07-15 06:01:52 +10:00
|
|
|
}
|
2012-08-04 02:28:00 +10:00
|
|
|
|
2012-08-22 01:21:47 +10:00
|
|
|
// Find looks up the ownername s in the zone and returns the
|
|
|
|
// data when found or nil when nothing is found.
|
2012-08-04 02:28:00 +10:00
|
|
|
func (z *Zone) Find(s string) *ZoneData {
|
2012-08-26 06:12:29 +10:00
|
|
|
z.mutex.RLock()
|
|
|
|
defer z.mutex.RUnlock()
|
2012-08-05 04:56:57 +10:00
|
|
|
zd := z.Radix.Find(toRadixName(s))
|
|
|
|
if zd == nil {
|
2012-08-04 02:28:00 +10:00
|
|
|
return nil
|
|
|
|
}
|
2012-08-05 04:56:57 +10:00
|
|
|
return zd.Value.(*ZoneData)
|
|
|
|
}
|
|
|
|
|
2012-08-22 01:21:47 +10:00
|
|
|
// Predecessor searches the zone for a name shorter than s.
|
2012-08-05 04:56:57 +10:00
|
|
|
func (z *Zone) Predecessor(s string) *ZoneData {
|
2012-08-26 06:12:29 +10:00
|
|
|
z.mutex.RLock()
|
|
|
|
defer z.mutex.RUnlock()
|
2012-08-05 04:56:57 +10:00
|
|
|
zd := z.Radix.Predecessor(toRadixName(s))
|
2012-08-04 02:28:00 +10:00
|
|
|
if zd == nil {
|
|
|
|
return nil
|
|
|
|
}
|
|
|
|
return zd.Value.(*ZoneData)
|
|
|
|
}
|