Merge branch 'master' of github.com:miekg/dns
This commit is contained in:
commit
eaaef0af9d
|
@ -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
|
||||||
}
|
}
|
||||||
|
|
19
defaults.go
19
defaults.go
|
@ -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
5
msg.go
|
@ -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.
|
||||||
|
|
|
@ -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 {
|
||||||
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
@ -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
|
||||||
}
|
}
|
||||||
|
|
2
tsig.go
2
tsig.go
|
@ -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
61
zone.go
|
@ -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
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
@ -0,0 +1,10 @@
|
||||||
|
package dns
|
||||||
|
|
||||||
|
import (
|
||||||
|
"testing"
|
||||||
|
)
|
||||||
|
|
||||||
|
func TestInsert(t *testing.T) {
|
||||||
|
}
|
||||||
|
func TestRemove(t *testing.T) {
|
||||||
|
}
|
Loading…
Reference in New Issue