Merge branch 'master' of github.com:miekg/dns

This commit is contained in:
Miek Gieben 2012-08-25 22:08:22 +02:00
commit eaaef0af9d
8 changed files with 90 additions and 32 deletions

View File

@ -164,8 +164,8 @@ func (w *reply) receive() (*Msg, error) {
} }
w.rtt = time.Since(w.t) w.rtt = time.Since(w.t)
m.Size = n m.Size = n
if m.IsTsig() { if t := m.IsTsig(); t != nil {
secret := m.Extra[len(m.Extra)-1].(*RR_TSIG).Hdr.Name secret := t.Hdr.Name
if _, ok := w.client.TsigSecret[secret]; !ok { if _, ok := w.client.TsigSecret[secret]; !ok {
w.tsigStatus = ErrSecret w.tsigStatus = ErrSecret
return m, nil return m, nil
@ -249,9 +249,9 @@ func (w *reply) readClient(p []byte) (n int, err error) {
// signature is calculated. // signature is calculated.
func (w *reply) send(m *Msg) (err error) { func (w *reply) send(m *Msg) (err error) {
var out []byte var out []byte
if m.IsTsig() { if t := m.IsTsig(); t != nil {
mac := "" mac := ""
name := m.Extra[len(m.Extra)-1].(*RR_TSIG).Hdr.Name name := t.Hdr.Name
if _, ok := w.client.TsigSecret[name]; !ok { if _, ok := w.client.TsigSecret[name]; !ok {
return ErrSecret return ErrSecret
} }

View File

@ -124,23 +124,26 @@ func (dns *Msg) SetEdns0(udpsize uint16, do bool) *Msg {
} }
// IsTsig checks if the message has a TSIG record as the last record // IsTsig checks if the message has a TSIG record as the last record
// in the additional section. // in the additional section. It returns the TSIG record found or nil.
func (dns *Msg) IsTsig() (ok bool) { func (dns *Msg) IsTsig() *RR_TSIG {
if len(dns.Extra) > 0 { if len(dns.Extra) > 0 {
return dns.Extra[len(dns.Extra)-1].Header().Rrtype == TypeTSIG if dns.Extra[len(dns.Extra)-1].Header().Rrtype == TypeTSIG {
return dns.Extra[len(dns.Extra)-1].(*RR_TSIG)
}
} }
return return nil
} }
// IsEdns0 checks if the message has a EDNS0 (OPT) record, any EDNS0 // IsEdns0 checks if the message has a EDNS0 (OPT) record, any EDNS0
// record in the additional section will do. // record in the additional section will do. It returns the OPT record
func (dns *Msg) IsEdns0() (ok bool) { // found or nil.
func (dns *Msg) IsEdns0() *RR_OPT {
for _, r := range dns.Extra { for _, r := range dns.Extra {
if r.Header().Rrtype == TypeOPT { if r.Header().Rrtype == TypeOPT {
return true return r.(*RR_OPT)
} }
} }
return return nil
} }
// IsDomainName checks if s is a valid domainname, it returns // IsDomainName checks if s is a valid domainname, it returns

5
msg.go
View File

@ -79,9 +79,8 @@ type MsgHdr struct {
// The layout of a DNS message. // The layout of a DNS message.
type Msg struct { type Msg struct {
MsgHdr MsgHdr
Compress bool // If true, the message will be compressed when converted to wire format. Compress bool // If true, the message will be compressed when converted to wire format.
Size int // Number of octects in the message received from the wire. Size int // Number of octects in the message received from the wire.
// Remote addr? back
Question []Question // Holds the RR(s) of the question section. Question []Question // Holds the RR(s) of the question section.
Answer []RR // Holds the RR(s) of the answer section. Answer []RR // Holds the RR(s) of the answer section.
Ns []RR // Holds the RR(s) of the authority section. Ns []RR // Holds the RR(s) of the authority section.

View File

@ -380,14 +380,17 @@ func TestParseFailure(t *testing.T) {
// A bit useless, how to use b.N? // A bit useless, how to use b.N?
func BenchmarkZoneParsing(b *testing.B) { func BenchmarkZoneParsing(b *testing.B) {
b.StopTimer()
f, err := os.Open("t/miek.nl.signed_test") f, err := os.Open("t/miek.nl.signed_test")
if err != nil { if err != nil {
return return
} }
defer f.Close() defer f.Close()
to := ParseZone(f, "", "t/miek.nl.signed_test") b.StartTimer()
for x := range to { for i := 0; i < b.N; i++ {
x = x to := ParseZone(f, "", "t/miek.nl.signed_test")
for _ = range to {
}
} }
} }

View File

@ -330,8 +330,8 @@ func (c *conn) serve() {
} }
w.tsigStatus = nil w.tsigStatus = nil
if req.IsTsig() { if t := req.IsTsig(); t != nil {
secret := req.Extra[len(req.Extra)-1].(*RR_TSIG).Hdr.Name secret := t.Hdr.Name
if _, ok := w.conn.tsigSecret[secret]; !ok { if _, ok := w.conn.tsigSecret[secret]; !ok {
w.tsigStatus = ErrKeyAlg w.tsigStatus = ErrKeyAlg
} }
@ -360,8 +360,8 @@ func (w *response) Write(m *Msg) (err error) {
if m == nil { if m == nil {
return &Error{Err: "nil message"} return &Error{Err: "nil message"}
} }
if m.IsTsig() { if t := m.IsTsig(); t != nil {
data, w.tsigRequestMAC, err = TsigGenerate(m, w.conn.tsigSecret[m.Extra[len(m.Extra)-1].(*RR_TSIG).Hdr.Name], w.tsigRequestMAC, w.tsigTimersOnly) data, w.tsigRequestMAC, err = TsigGenerate(m, w.conn.tsigSecret[t.Hdr.Name], w.tsigRequestMAC, w.tsigTimersOnly)
if err != nil { if err != nil {
return err return err
} }

View File

@ -154,7 +154,7 @@ type timerWireFmt struct {
// timersOnly is false. // timersOnly is false.
// If something goes wrong an error is returned, otherwise it is nil. // If something goes wrong an error is returned, otherwise it is nil.
func TsigGenerate(m *Msg, secret, requestMAC string, timersOnly bool) ([]byte, string, error) { func TsigGenerate(m *Msg, secret, requestMAC string, timersOnly bool) ([]byte, string, error) {
if !m.IsTsig() { if m.IsTsig() == nil {
panic("TSIG not last RR in additional") panic("TSIG not last RR in additional")
} }
// If we barf here, the caller is to blame // If we barf here, the caller is to blame

61
zone.go
View File

@ -5,25 +5,27 @@ package dns
import ( import (
"github.com/miekg/radix" "github.com/miekg/radix"
"strings" "strings"
"sync"
) )
// Zone represents a DNS zone. Currently there is no locking implemented. // Zone represents a DNS zone. The structure is safe for concurrent access.
type Zone struct { type Zone struct {
Origin string // Origin of the zone Origin string // Origin of the zone
Wildcard int // Whenever we see a wildcard name, this is incremented Wildcard int // Whenever we see a wildcard name, this is incremented
*radix.Radix // Zone data *radix.Radix // Zone data
mutex *sync.RWMutex
} }
// ZoneData holds all the RRs having their ownername equal to Name. // ZoneData holds all the RRs having their owner name equal to Name.
type ZoneData struct { type ZoneData struct {
Name string // Domain name for this node Name string // Domain name for this node
RR map[uint16][]RR // Map of the RR type to the RR 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 Signatures map[uint16][]*RR_RRSIG // DNSSEC signatures for the RRs, stored under type covered
// Always false, except for NSsets that differ from z.Origin NonAuth bool // Always false, except for NSsets that differ from z.Origin
NonAuth bool mutex *sync.RWMutex
} }
// toRadixName reverses a domainname so that when we store it in the radix tree // toRadixName reverses a domain name so that when we store it in the radix tree
// we preserve the nsec ordering of the zone (this idea was stolen from NSD). // we preserve the nsec ordering of the zone (this idea was stolen from NSD).
// each label is also lowercased. // each label is also lowercased.
func toRadixName(d string) string { func toRadixName(d string) string {
@ -46,21 +48,24 @@ func NewZone(origin string) *Zone {
return nil return nil
} }
z := new(Zone) z := new(Zone)
z.mutex = new(sync.RWMutex)
z.Origin = Fqdn(origin) z.Origin = Fqdn(origin)
z.Radix = radix.New() z.Radix = radix.New()
return z return z
} }
// Insert inserts an RR into the zone. Duplicate data overwrites the old data without // Insert inserts an RR into the zone. There is no check for duplicate data, although
// warning. // Remove will remove all duplicates.
func (z *Zone) Insert(r RR) error { func (z *Zone) Insert(r RR) error {
if !IsSubDomain(z.Origin, r.Header().Name) { if !IsSubDomain(z.Origin, r.Header().Name) {
return &Error{Err: "out of zone data", Name: r.Header().Name} return &Error{Err: "out of zone data", Name: r.Header().Name}
} }
key := toRadixName(r.Header().Name) key := toRadixName(r.Header().Name)
z.mutex.Lock()
zd := z.Radix.Find(key) zd := z.Radix.Find(key)
if zd == nil { if zd == nil {
defer z.mutex.Unlock()
// Check if its a wildcard name // Check if its a wildcard name
if len(r.Header().Name) > 1 && r.Header().Name[0] == '*' && r.Header().Name[1] == '.' { if len(r.Header().Name) > 1 && r.Header().Name[0] == '*' && r.Header().Name[1] == '.' {
z.Wildcard++ z.Wildcard++
@ -69,6 +74,7 @@ func (z *Zone) Insert(r RR) error {
zd.Name = r.Header().Name zd.Name = r.Header().Name
zd.RR = make(map[uint16][]RR) zd.RR = make(map[uint16][]RR)
zd.Signatures = make(map[uint16][]*RR_RRSIG) zd.Signatures = make(map[uint16][]*RR_RRSIG)
zd.mutex = new(sync.RWMutex)
switch t := r.Header().Rrtype; t { switch t := r.Header().Rrtype; t {
case TypeRRSIG: case TypeRRSIG:
sigtype := r.(*RR_RRSIG).TypeCovered sigtype := r.(*RR_RRSIG).TypeCovered
@ -85,6 +91,9 @@ func (z *Zone) Insert(r RR) error {
z.Radix.Insert(key, zd) z.Radix.Insert(key, zd)
return nil return nil
} }
z.mutex.Unlock()
zd.Value.(*ZoneData).mutex.Lock()
defer zd.Value.(*ZoneData).mutex.Unlock()
// Name already there // Name already there
switch t := r.Header().Rrtype; t { switch t := r.Header().Rrtype; t {
case TypeRRSIG: case TypeRRSIG:
@ -102,9 +111,43 @@ func (z *Zone) Insert(r RR) error {
} }
// Remove removes the RR r from the zone. If there RR can not be found, // Remove removes the RR r from the zone. If there RR can not be found,
// this is a no-op. TODO(mg): not implemented. // this is a no-op.
func (z *Zone) Remove(r RR) error { func (z *Zone) Remove(r RR) error {
// Wildcards key := toRadixName(r.Header().Name)
z.mutex.Lock()
zd := z.Radix.Find(key)
if zd == nil {
defer z.mutex.Unlock()
return nil
}
z.mutex.Unlock()
zd.Value.(*ZoneData).mutex.Lock()
defer zd.Value.(*ZoneData).mutex.Unlock()
remove := false
switch t := r.Header().Rrtype; t {
case TypeRRSIG:
sigtype := r.(*RR_RRSIG).TypeCovered
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
}
}
default:
for i, zr := range zd.Value.(*ZoneData).RR[t] {
if r == zr {
zd.Value.(*ZoneData).RR[t] = append(zd.Value.(*ZoneData).RR[t][:i], zd.Value.(*ZoneData).RR[t][i+1:]...)
remove = true
}
}
}
if remove && len(r.Header().Name) > 1 && r.Header().Name[0] == '*' && r.Header().Name[1] == '.' {
z.Wildcard--
if z.Wildcard < 0 {
z.Wildcard = 0
}
}
// TODO(mg): what to do if the whole structure is empty? Set it to nil?
return nil return nil
} }

10
zone_test.go Normal file
View File

@ -0,0 +1,10 @@
package dns
import (
"testing"
)
func TestInsert(t *testing.T) {
}
func TestRemove(t *testing.T) {
}