dns/zone.go

614 lines
18 KiB
Go
Raw Normal View History

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-09-12 20:57:50 +10:00
"math/rand"
2012-09-13 05:13:57 +10:00
"runtime"
2012-09-12 05:13:25 +10:00
"sort"
2012-08-02 00:30:45 +10:00
"strings"
2012-08-26 03:57:25 +10:00
"sync"
2012-09-02 21:04:52 +10:00
"time"
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 {
Origin string // Origin of the zone
olabels []string // origin cut up in labels, to speed up IsSubDomain function
Wildcard int // Whenever we see a wildcard name, this is incremented
*radix.Radix // Zone data
2012-08-26 04:57:26 +10:00
mutex *sync.RWMutex
2012-09-12 20:57:50 +10:00
expired bool // Slave zone is expired
// Do we need a timemodified?
2012-07-15 06:01:52 +10:00
}
2012-09-13 05:13:57 +10:00
type uint16Slice []uint16
func (p uint16Slice) Len() int { return len(p) }
func (p uint16Slice) Less(i, j int) bool { return p[i] < p[j] }
func (p uint16Slice) Swap(i, j int) { p[i], p[j] = p[j], p[i] }
2012-09-13 06:41:26 +10:00
type signData struct{ node, next *ZoneData }
2012-09-13 05:13:57 +10:00
// SignatureConfig holds the parameters for zone (re)signing. This
// is copied from OpenDNSSEC. See:
2012-09-02 21:04:52 +10:00
// https://wiki.opendnssec.org/display/DOCS/kasp.xml
type SignatureConfig struct {
2012-09-02 21:04:52 +10:00
// Validity period of the signatures, typically 2 to 4 weeks.
Validity time.Duration
// When the end of the validity approaches, how much time should remain
// before we start to resign. Typical value is 3 days.
Refresh time.Duration
2012-09-12 20:57:50 +10:00
// Jitter is an random amount of time added or subtracted from the
2012-09-02 21:04:52 +10:00
// expiration time to ensure not all signatures expire a the same time.
2012-09-12 20:57:50 +10:00
// Typical value is 12 hours, which means the actual jitter value is
// between -12..0..+12.
2012-09-02 21:04:52 +10:00
Jitter time.Duration
// InceptionOffset is subtracted from the inception time to ensure badly
// calibrated clocks on the internet can still validate a signature.
// Typical value is 300 seconds.
InceptionOffset time.Duration
// HonorSepFlag is a boolean which when try instructs the signer to use
// a KSK/ZSK split and only sign the keyset with the KSK(s). If not
// set all records are signed with all keys. If this flag is true and
// a single KSK is used for signing, only the keyset is signed.
HonorSepFlag bool
2012-09-13 05:13:57 +10:00
// SignerRoutines specifies the number of signing goroutines, if not
2012-09-18 04:01:33 +10:00
// set runtime.NumCPU() + 1 is used as the value.
2012-09-13 05:13:57 +10:00
SignerRoutines int
// SOA Minttl value must be used as the ttl on NSEC/NSEC3 records.
Minttl uint32
2012-09-02 21:04:52 +10:00
}
func newSignatureConfig() *SignatureConfig {
return &SignatureConfig{time.Duration(4*7*24) * time.Hour, time.Duration(3*24) * time.Hour, time.Duration(12) * time.Hour, time.Duration(300) * time.Second, true, runtime.NumCPU() + 1, 0}
2012-09-02 21:04:52 +10:00
}
// DefaultSignaturePolicy has the following values. Validity is 4 weeks,
// Refresh is set to 3 days, Jitter to 12 hours and InceptionOffset to 300 seconds.
// HonorSepFlag is set to true, SignerRoutines is set to runtime.NumCPU() + 1. The
// Minttl value is zero.
var DefaultSignatureConfig = newSignatureConfig()
2012-09-02 21:04: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(strings.ToLower(origin))
z.olabels = SplitLabels(z.Origin)
2012-08-27 17:12:41 +10:00
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
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-09-12 20:57:50 +10:00
mutex *sync.RWMutex
2012-07-15 06:54:49 +10:00
}
2012-09-12 20:57:50 +10:00
// NewZoneData creates a new zone data element.
func NewZoneData(s string) *ZoneData {
2012-08-27 17:12:41 +10:00
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).
2012-10-12 23:03:56 +11:00
// Each label is also lowercased.
2012-08-02 00:30:45 +10:00
func toRadixName(d string) string {
if d == "" || d == "." {
2012-08-05 16:13:09 +10:00
return "."
}
2012-08-02 00:30:45 +10:00
s := ""
ld := len(d)
if d[ld-1] != '.' {
d = d + "."
ld++
}
var lastdot int
var lastbyte byte
var lastlastbyte byte
for i := 0; i < len(d); i++ {
if d[i] == '.' {
switch {
case lastbyte != '\\':
fallthrough
case lastbyte == '\\' && lastlastbyte == '\\':
s = d[lastdot:i] + "." + s
lastdot = i + 1
continue
}
2012-09-05 04:08:55 +10:00
}
lastlastbyte = lastbyte
lastbyte = d[i]
2012-08-02 00:30:45 +10:00
}
return "." + strings.ToLower(s[:len(s)-1])
2012-08-02 00:30:45 +10:00
}
2012-09-11 21:56:50 +10:00
// String returns a string representation of a ZoneData. There is no
// String for the entire zone, because this will (most likely) take up
// a huge amount of memory. Basic use pattern for printing an entire
// zone:
//
// // z contains the zone
2012-09-13 03:37:28 +10:00
// z.Radix.DoNext(func(i interface{}) {
2012-09-11 21:56:50 +10:00
// fmt.Printf("%s", i.(*dns.ZoneData).String()) })
//
2012-09-11 21:56:50 +10:00
func (zd *ZoneData) String() string {
var (
s string
t uint16
)
// Make sure SOA is first
// There is only one SOA, but it may have multiple sigs
if soa, ok := zd.RR[TypeSOA]; ok {
s += soa[0].String() + "\n"
if _, ok := zd.Signatures[TypeSOA]; ok {
for _, sig := range zd.Signatures[TypeSOA] {
s += sig.String() + "\n"
}
}
}
2012-09-11 18:59:20 +10:00
2012-09-11 21:56:50 +10:00
Types:
for _, rrset := range zd.RR {
for _, rr := range rrset {
t = rr.Header().Rrtype
2012-09-13 06:41:26 +10:00
if t == TypeSOA || t == TypeNSEC { // Done above or below
2012-09-11 21:56:50 +10:00
continue Types
}
s += rr.String() + "\n"
}
if _, ok := zd.Signatures[t]; ok {
for _, rr := range zd.Signatures[t] {
s += rr.String() + "\n"
}
}
}
2012-09-13 06:41:26 +10:00
// Make sure NSEC is last
// There is only one NSEC, but it may have multiple sigs
if soa, ok := zd.RR[TypeNSEC]; ok {
s += soa[0].String() + "\n"
if _, ok := zd.Signatures[TypeNSEC]; ok {
for _, sig := range zd.Signatures[TypeNSEC] {
s += sig.String() + "\n"
}
}
}
2012-09-11 21:56:50 +10:00
return s
2012-09-04 03:34:09 +10:00
}
// Lock locks the zone z for writing.
2012-09-13 05:13:57 +10:00
func (z *Zone) Lock() { z.mutex.Lock() }
// Unlock unlocks the zone z for writing.
2012-09-13 05:13:57 +10:00
func (z *Zone) Unlock() { z.mutex.Unlock() }
2012-10-16 01:12:29 +11:00
// Insert inserts the RR r into the zone. There is no check for duplicate data, although
// Remove will remove all duplicates.
2012-07-17 05:16:42 +10:00
func (z *Zone) Insert(r RR) error {
if !z.isSubDomain(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-09-13 05:13:57 +10:00
z.Lock()
2012-09-08 02:48:36 +10:00
zd, exact := z.Radix.Find(key)
if !exact {
// Not an exact match, so insert new value
2012-09-13 05:13:57 +10:00
defer z.Unlock()
2012-09-03 05:22:24 +10:00
// Check if it's a wildcard name
2012-08-10 07:00:51 +10:00
if len(r.Header().Name) > 1 && r.Header().Name[0] == '*' && r.Header().Name[1] == '.' {
z.Wildcard++
}
2012-09-12 20:57:50 +10:00
zd := NewZoneData(r.Header().Name)
2012-07-16 02:11:17 +10:00
switch t := r.Header().Rrtype; t {
case TypeRRSIG:
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-09-13 05:13:57 +10:00
z.Unlock()
2012-08-26 03:57:25 +10:00
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:
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:
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-09-02 01:06:24 +10:00
// Remove removes the RR r from the zone. If the RR can not be found,
// this is a no-op.
2012-07-17 05:24:05 +10:00
func (z *Zone) Remove(r RR) error {
key := toRadixName(r.Header().Name)
2012-09-13 05:13:57 +10:00
z.Lock()
2012-09-08 02:48:36 +10:00
zd, exact := z.Radix.Find(key)
if !exact {
2012-09-13 05:13:57 +10:00
defer z.Unlock()
return nil
}
2012-09-13 05:13:57 +10:00
z.Unlock()
2012-08-26 03:57:25 +10:00
zd.Value.(*ZoneData).mutex.Lock()
defer zd.Value.(*ZoneData).mutex.Unlock()
2012-08-25 22:44:51 +10:00
remove := false
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-10-15 18:31:14 +11:00
if remove {
// If every Signature of the covering type is removed, removed the type from the map
if len(zd.Value.(*ZoneData).RR[sigtype]) == 0 {
delete(zd.Value.(*ZoneData).RR, sigtype)
}
}
default:
2012-08-25 22:44:51 +10:00
for i, zr := range zd.Value.(*ZoneData).RR[t] {
2012-10-15 18:31:14 +11:00
// Matching RR
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-10-15 18:31:14 +11:00
if remove {
// If every RR of this type is removed, removed the type from the map
if len(zd.Value.(*ZoneData).RR[t]) == 0 {
delete(zd.Value.(*ZoneData).RR, t)
}
}
}
if !remove {
return nil
}
2012-10-15 18:31:14 +11:00
if len(r.Header().Name) > 1 && r.Header().Name[0] == '*' && r.Header().Name[1] == '.' {
z.Wildcard--
if z.Wildcard < 0 {
z.Wildcard = 0
}
}
if len(zd.Value.(*ZoneData).RR) == 0 && len(zd.Value.(*ZoneData).Signatures) == 0 {
2012-10-15 18:31:14 +11:00
// Entire node is empty, remove it from the Radix tree
z.Radix.Remove(key)
}
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
// RemoveName removes all the RRs with ownername matching s from the zone. Typical use of this
// function is when processing a RemoveName dynamic update packet.
func (z *Zone) RemoveName(s string) error {
key := toRadixName(s)
z.Lock()
defer z.Unlock()
z.Radix.Remove(key)
if len(s) > 1 && s[0] == '*' && s[1] == '.' {
z.Wildcard--
if z.Wildcard < 0 {
z.Wildcard = 0
}
}
return nil
}
2012-08-22 01:21:47 +10:00
// Find looks up the ownername s in the zone and returns the
2012-09-10 07:38:01 +10:00
// data and true when an exact match is found. If an exact find isn't
// possible the first parent node with a non-nil Value is returned and
// the boolean is false.
2012-09-11 06:13:06 +10:00
func (z *Zone) Find(s string) (node *ZoneData, exact bool) {
2012-08-26 06:12:29 +10:00
z.mutex.RLock()
defer z.mutex.RUnlock()
2012-09-11 06:13:06 +10:00
n, e := z.Radix.Find(toRadixName(s))
if n == nil {
2012-09-10 07:38:01 +10:00
return nil, false
2012-08-04 02:28:00 +10:00
}
2012-09-11 06:13:06 +10:00
node = n.Value.(*ZoneData)
exact = e
return
}
2012-09-10 17:14:17 +10:00
// FindFunc works like Find, but the function f is executed on
2012-09-11 06:13:06 +10:00
// each node which has a non-nil Value during the tree traversal.
2012-09-10 17:14:17 +10:00
// If f returns true, that node is returned.
func (z *Zone) FindFunc(s string, f func(interface{}) bool) (*ZoneData, bool, bool) {
z.mutex.RLock()
defer z.mutex.RUnlock()
zd, e, b := z.Radix.FindFunc(toRadixName(s), f)
if zd == nil {
return nil, false, false
}
return zd.Value.(*ZoneData), e, b
}
func (z *Zone) isSubDomain(child string) bool {
return compareLabelsSlice(z.olabels, strings.ToLower(child)) == len(z.olabels)
}
// Sign (re)signs the zone z with the given keys.
// NSEC(3)s and RRSIGs are added as needed.
// The public keys themselves are not added to the zone.
// If config is nil DefaultSignatureConfig is used. The signatureConfig
// describes how the zone must be signed and if the SEP flag (for KSK)
// should be honored. If signatures approach their expriration time, they
// are refreshed with the current set of keys. Valid signatures are left alone.
//
2012-09-13 05:13:57 +10:00
// Basic use pattern for signing a zone with the default SignatureConfig:
//
// // A signle PublicKey/PrivateKey have been read from disk.
2012-09-13 05:13:57 +10:00
// e := z.Sign(map[*dns.RR_DNSKEY]dns.PrivateKey{pubkey.(*dns.RR_DNSKEY): privkey}, nil)
// if e != nil {
// // signing error
// }
// // Admire your signed zone...
//
// TODO(mg): resigning is not implemented
// TODO(mg): NSEC3 is not implemented
2012-09-11 18:59:20 +10:00
func (z *Zone) Sign(keys map[*RR_DNSKEY]PrivateKey, config *SignatureConfig) error {
2012-09-13 05:13:57 +10:00
z.Lock()
defer z.Unlock()
if config == nil {
config = DefaultSignatureConfig
2012-09-02 21:04:52 +10:00
}
2012-09-11 18:59:20 +10:00
// Pre-calc the key tag
keytags := make(map[*RR_DNSKEY]uint16)
for k, _ := range keys {
keytags[k] = k.KeyTag()
}
2012-09-13 05:13:57 +10:00
errChan := make(chan error)
radChan := make(chan *radix.Radix, config.SignerRoutines*2)
2012-09-13 05:13:57 +10:00
// Start the signer goroutines
2012-09-13 06:12:11 +10:00
wg := new(sync.WaitGroup)
wg.Add(config.SignerRoutines)
for i := 0; i < config.SignerRoutines; i++ {
go signerRoutine(wg, keys, keytags, config, radChan, errChan)
2012-09-13 05:13:57 +10:00
}
2012-09-13 00:30:05 +10:00
apex, e := z.Radix.Find(toRadixName(z.Origin))
2012-09-13 05:13:57 +10:00
if !e {
2012-09-13 06:12:11 +10:00
return ErrSoa
2012-09-13 05:13:57 +10:00
}
config.Minttl = apex.Value.(*ZoneData).RR[TypeSOA][0].(*RR_SOA).Minttl
2012-09-13 00:30:05 +10:00
next := apex.Next()
radChan <- apex
2012-09-13 05:13:57 +10:00
2012-09-13 05:22:28 +10:00
var err error
Sign:
2012-09-13 00:30:05 +10:00
for next.Value.(*ZoneData).Name != z.Origin {
2012-09-13 05:22:28 +10:00
select {
case err = <-errChan:
break Sign
default:
radChan <- next
2012-09-13 19:02:06 +10:00
next = next.Next()
2012-09-13 05:22:28 +10:00
}
2012-09-13 00:00:57 +10:00
}
close(radChan)
2012-09-13 05:13:57 +10:00
close(errChan)
2012-09-13 05:22:28 +10:00
if err != nil {
return err
}
2012-09-13 06:12:11 +10:00
wg.Wait()
2012-09-02 21:04:52 +10:00
return nil
}
2012-09-03 05:22:24 +10:00
// signerRoutine is a small helper routine to make the concurrent signing work.
func signerRoutine(wg *sync.WaitGroup, keys map[*RR_DNSKEY]PrivateKey, keytags map[*RR_DNSKEY]uint16, config *SignatureConfig, in chan *radix.Radix, err chan error) {
2012-09-13 06:12:11 +10:00
defer wg.Done()
2012-09-13 05:13:57 +10:00
for {
select {
case data, ok := <-in:
if !ok {
return
}
e := data.Value.(*ZoneData).Sign(data.Next().Value.(*ZoneData), keys, keytags, config)
2012-09-13 05:13:57 +10:00
if e != nil {
err <- e
return
}
}
}
}
// Sign signs a single ZoneData node. The zonedata itself is locked for writing,
// during the execution. It is important that the nodes' next record does not
2012-09-13 17:33:07 +10:00
// changes. The caller must take care that the zone itself is also locked for writing.
// For a more complete description see zone.Sign.
// NB: as this method has no (direct)
// access to the zone's SOA record, the SOA's Minttl value should be set in signatureConfig.
2012-09-13 05:13:57 +10:00
func (node *ZoneData) Sign(next *ZoneData, keys map[*RR_DNSKEY]PrivateKey, keytags map[*RR_DNSKEY]uint16, config *SignatureConfig) error {
node.mutex.Lock()
defer node.mutex.Unlock()
2012-09-13 17:33:07 +10:00
2012-09-12 01:25:12 +10:00
nsec := new(RR_NSEC)
nsec.Hdr.Rrtype = TypeNSEC
nsec.Hdr.Ttl = config.Minttl // SOA's minimum value
2012-09-12 01:25:12 +10:00
nsec.Hdr.Name = node.Name
2012-09-12 05:36:18 +10:00
nsec.NextDomain = next.Name // Only thing I need from next, actually
2012-09-12 01:25:12 +10:00
nsec.Hdr.Class = ClassINET
// Still need to add NSEC + RRSIG for this data, there might also be a DS record
2012-09-11 18:59:20 +10:00
if node.NonAuth == true {
2012-09-12 05:36:18 +10:00
for t, _ := range node.RR {
nsec.TypeBitMap = append(nsec.TypeBitMap, t)
}
2012-09-13 05:13:57 +10:00
nsec.TypeBitMap = append(nsec.TypeBitMap, TypeRRSIG) // Add sig too
nsec.TypeBitMap = append(nsec.TypeBitMap, TypeNSEC) // Add me too!
2012-09-12 05:36:18 +10:00
sort.Sort(uint16Slice(nsec.TypeBitMap))
node.RR[TypeNSEC] = []RR{nsec}
now := time.Now().UTC()
2012-09-12 05:36:18 +10:00
for k, p := range keys {
if config.HonorSepFlag && k.Flags&SEP == SEP {
// only sign keys with SEP keys
continue
}
// which sigs to check??
2012-09-12 05:36:18 +10:00
s := new(RR_RRSIG)
s.SignerName = k.Hdr.Name
s.Hdr.Ttl = k.Hdr.Ttl
s.Algorithm = k.Algorithm
s.KeyTag = keytags[k]
s.Inception = timeToUint32(now.Add(-config.InceptionOffset))
s.Expiration = timeToUint32(now.Add(jitterDuration(config.Jitter)).Add(config.Validity))
2012-09-13 05:13:57 +10:00
e := s.Sign(p, []RR{nsec})
if e != nil {
return e
}
2012-09-12 05:36:18 +10:00
node.Signatures[TypeNSEC] = append(node.Signatures[TypeNSEC], s)
2012-09-13 06:41:26 +10:00
// DS
if ds, ok := node.RR[TypeDS]; ok {
s := new(RR_RRSIG)
s.SignerName = k.Hdr.Name
s.Hdr.Ttl = k.Hdr.Ttl
s.Algorithm = k.Algorithm
s.KeyTag = keytags[k]
s.Inception = timeToUint32(now.Add(-config.InceptionOffset))
s.Expiration = timeToUint32(now.Add(jitterDuration(config.Jitter)).Add(config.Validity))
2012-09-13 06:41:26 +10:00
e := s.Sign(p, ds)
if e != nil {
return e
}
2012-09-13 07:29:19 +10:00
node.Signatures[TypeDS] = append(node.Signatures[TypeDS], s)
2012-09-13 06:41:26 +10:00
}
2012-09-12 05:36:18 +10:00
}
2012-09-13 05:13:57 +10:00
return nil
2012-09-03 05:22:24 +10:00
}
now := time.Now().UTC()
2012-09-11 18:59:20 +10:00
for k, p := range keys {
for t, rrset := range node.RR {
if k.Flags&SEP == SEP {
if _, ok := rrset[0].(*RR_DNSKEY); !ok {
// only sign keys with SEP keys
continue
}
}
2012-09-11 18:59:20 +10:00
s := new(RR_RRSIG)
s.SignerName = k.Hdr.Name
s.Hdr.Ttl = k.Hdr.Ttl
2012-09-12 01:25:12 +10:00
s.Hdr.Class = ClassINET
2012-09-11 18:59:20 +10:00
s.Algorithm = k.Algorithm
s.KeyTag = keytags[k]
s.Inception = timeToUint32(now.Add(-config.InceptionOffset))
s.Expiration = timeToUint32(now.Add(jitterDuration(config.Jitter)).Add(config.Validity))
2012-09-13 05:13:57 +10:00
e := s.Sign(p, rrset)
if e != nil {
return e
}
2012-09-11 18:59:20 +10:00
node.Signatures[t] = append(node.Signatures[t], s)
2012-09-12 01:25:12 +10:00
nsec.TypeBitMap = append(nsec.TypeBitMap, t)
2012-09-11 18:59:20 +10:00
}
2012-09-13 05:13:57 +10:00
nsec.TypeBitMap = append(nsec.TypeBitMap, TypeRRSIG) // Add sig too
nsec.TypeBitMap = append(nsec.TypeBitMap, TypeNSEC) // Add me too!
2012-09-12 05:13:25 +10:00
sort.Sort(uint16Slice(nsec.TypeBitMap))
2012-09-12 01:25:12 +10:00
node.RR[TypeNSEC] = []RR{nsec}
// NSEC
s := new(RR_RRSIG)
s.SignerName = k.Hdr.Name
s.Hdr.Ttl = k.Hdr.Ttl
s.Algorithm = k.Algorithm
s.KeyTag = keytags[k]
s.Inception = timeToUint32(now.Add(-config.InceptionOffset))
s.Expiration = timeToUint32(now.Add(jitterDuration(config.Jitter)).Add(config.Validity))
2012-09-13 05:13:57 +10:00
e := s.Sign(p, []RR{nsec})
if e != nil {
return e
}
2012-09-12 01:25:12 +10:00
node.Signatures[TypeNSEC] = append(node.Signatures[TypeNSEC], s)
2012-09-11 18:59:20 +10:00
}
2012-09-13 05:13:57 +10:00
return nil
2012-09-03 05:22:24 +10:00
}
2012-09-12 05:13:25 +10:00
2012-09-18 04:01:33 +10:00
// timeToUint32 translates a time.Time to a 32 bit value which
// can be used as the RRSIG's inception or expiration times.
func timeToUint32(t time.Time) uint32 {
2012-09-12 06:00:19 +10:00
mod := (t.Unix() / year68) - 1
if mod < 0 {
mod = 0
}
return uint32(t.Unix() - (mod * year68))
}
2012-09-12 20:57:50 +10:00
2012-09-18 04:01:33 +10:00
// uint32ToTime translates a uint32 to a time.Time
func uint32ToTime(t uint32) time.Time {
// uint32 to duration and then add it to epoch(0)
2012-09-18 04:10:09 +10:00
mod := (time.Now().Unix() / year68) - 1
2012-09-18 04:01:33 +10:00
if mod < 0 {
mod = 0
}
2012-09-18 04:10:09 +10:00
duration := time.Duration((mod * year68) * int64(t))
return time.Unix(0, 0).Add(duration)
2012-09-18 04:01:33 +10:00
}
2012-09-12 20:57:50 +10:00
// jitterTime returns a random +/- jitter
func jitterDuration(d time.Duration) time.Duration {
jitter := rand.Intn(int(d))
if rand.Intn(1) == 1 {
return time.Duration(jitter)
}
return -time.Duration(jitter)
}
// compareLabels behaves exactly as CompareLabels expect that l1 is already
// a tokenize (in labels) version of the domain name. This safe memory and is
// faster
func compareLabelsSlice(l1 []string, s2 string) (n int) {
l2 := SplitLabels(s2)
x1 := len(l1) - 1
x2 := len(l2) - 1
for {
if x1 < 0 || x2 < 0 {
break
}
if l1[x1] == l2[x2] {
n++
} else {
break
}
x1--
x2--
}
return
}