Add parsing of the root-anchor (as XML)

This commit is contained in:
Miek Gieben 2012-06-03 21:01:39 +02:00
parent 53b065793b
commit 96076ad9a1
2 changed files with 109 additions and 10 deletions

99
anchor.go Normal file
View File

@ -0,0 +1,99 @@
package dns
import (
"encoding/xml"
"fmt"
"io"
"time"
)
// Interally used for parsing from and to the XML
type XMLKeyDigest struct {
Id string `xml:"id,attr"`
ValidFrom string `xml:"validFrom,attr"`
ValidUntil string `xml:"validUntil,attr,omitempty"`
KeyTag uint16 `xml:"KeyTag"`
Algorithm uint8 `xml:"Algorithm"`
DigestType uint8 `xml:"DigestType"`
Digest string `xml:"Digest"`
}
// Interally used for parsing from and to the XML
type XMLTrustAnchor struct {
Id string `xml:"id,attr,omitempty"`
Source string `xml:"source,attr,omitempty"`
Zone string `xml:"Zone"`
KeyDigest []*XMLKeyDigest `xml:"KeyDigest"`
}
// A TrustAnchor represents the trust anchors used in the DNS root.
type TrustAnchor struct {
Id string // TrustAnchor id attribute
Source string // TrustAnchor source attribute
AnchorId string // KeyDigest id
Anchor *RR_DS // The digest encoded as an DS record
ValidFrom time.Time // Validity specification
ValidUntil time.Time
}
// TrustAnchorString convert a TrustAnchor to a string encoded as XML.
func TrustAnchorString(t []*TrustAnchor) string {
xta := new(XMLTrustAnchor)
xta.KeyDigest = make([]*XMLKeyDigest, 0)
for _, ta := range t {
xta.Id = ta.Id // Sets the everytime, but that is OK.
xta.Source = ta.Source
xta.Zone = ta.Anchor.Hdr.Name
xkd := new(XMLKeyDigest)
xkd.Id = ta.AnchorId
xkd.ValidFrom = ta.ValidFrom.Format("2006-01-02T15:04:05-07:00")
if !ta.ValidUntil.IsZero() {
xkd.ValidUntil = ta.ValidUntil.Format("2006-01-02T15:04:05-07:00")
}
xkd.KeyTag = ta.Anchor.KeyTag
xkd.Algorithm = ta.Anchor.Algorithm
xkd.DigestType = ta.Anchor.DigestType
xkd.Digest = ta.Anchor.Digest
xta.KeyDigest = append(xta.KeyDigest, xkd)
}
b, _ := xml.MarshalIndent(xta, "", "\t")
return string(b)
}
// ReadTrustAnchor read a root trust anchor from: http://data.iana.org/root-anchors/root-anchors.xml
// and return the data or an error.
func ReadTrustAnchor(q io.Reader) ([]*TrustAnchor, error) {
d := xml.NewDecoder(q)
t := new(XMLTrustAnchor)
e := d.Decode(t)
if e != nil {
println(e.Error())
}
ta := make([]*TrustAnchor, 0)
var err error
for _, digest := range t.KeyDigest {
t1 := new(TrustAnchor)
t1.Id = t.Id
t1.Source = t.Source
t1.AnchorId = digest.Id
if t1.ValidFrom, err = time.Parse("2006-01-02T15:04:05-07:00", digest.ValidFrom); err != nil {
return nil, err
}
if digest.ValidUntil != "" {
if t1.ValidUntil, err = time.Parse("2006-01-02T15:04:05-07:00", digest.ValidUntil); err != nil {
return nil, err
}
}
d := new(RR_DS)
d.Hdr = RR_Header{Name: t.Zone, Class: ClassINET, Rrtype: TypeDS}
d.KeyTag = digest.KeyTag
d.Algorithm = digest.Algorithm
d.DigestType = digest.DigestType
d.Digest = digest.Digest
t1.Anchor = d
// Some checks here too?
ta = append(ta, t1)
}
fmt.Printf("%+v %+v\n", t, t.KeyDigest[0])
return ta, nil
}

20
xfr.go
View File

@ -45,16 +45,16 @@ func (w *reply) axfrReceive(c chan *Exchange) {
for {
in, err := w.Receive()
if err != nil {
c <- &Exchange{w.req, in, w.rtt, w.conn.RemoteAddr(), err}
c <- &Exchange{Request: w.req, Reply: in, Rtt: w.rtt, RemoteAddr: w.conn.RemoteAddr(), Error: err}
return
}
if w.req.Id != in.Id {
c <- &Exchange{w.req, in, w.rtt, w.conn.RemoteAddr(), ErrId}
c <- &Exchange{Request: w.req, Reply: in, Rtt: w.rtt, RemoteAddr: w.conn.RemoteAddr(), Error: ErrId}
return
}
if first {
if !checkXfrSOA(in, true) {
c <- &Exchange{w.req, in, w.rtt, w.conn.RemoteAddr(), ErrXfrSoa}
c <- &Exchange{Request: w.req, Reply: in, Rtt: w.rtt, RemoteAddr: w.conn.RemoteAddr(), Error: ErrXfrSoa}
return
}
first = !first
@ -63,7 +63,7 @@ func (w *reply) axfrReceive(c chan *Exchange) {
if !first {
w.tsigTimersOnly = true // Subsequent envelopes use this.
if checkXfrSOA(in, false) {
c <- &Exchange{w.req, in, w.rtt, w.conn.RemoteAddr(), nil}
c <- &Exchange{Request: w.req, Reply: in, Rtt: w.rtt, RemoteAddr: w.conn.RemoteAddr(), Error: nil}
return
}
c <- &Exchange{Request: w.req, Reply: in, Rtt: w.rtt, RemoteAddr: w.conn.RemoteAddr(), Error: nil}
@ -80,23 +80,23 @@ func (w *reply) ixfrReceive(c chan *Exchange) {
for {
in, err := w.Receive()
if err != nil {
c <- &Exchange{w.req, in, w.rtt, w.conn.RemoteAddr(), err}
c <- &Exchange{Request: w.req, Reply: in, Rtt: w.rtt, RemoteAddr: w.conn.RemoteAddr(), Error: err}
return
}
if w.req.Id != in.Id {
c <- &Exchange{w.req, in, w.rtt, w.conn.RemoteAddr(), ErrId}
c <- &Exchange{Request: w.req, Reply: in, Rtt: w.rtt, RemoteAddr: w.conn.RemoteAddr(), Error: ErrId}
return
}
if first {
// A single SOA RR signals "no changes"
if len(in.Answer) == 1 && checkXfrSOA(in, true) {
c <- &Exchange{w.req, in, w.rtt, w.conn.RemoteAddr(), nil}
c <- &Exchange{Request: w.req, Reply: in, Rtt: w.rtt, RemoteAddr: w.conn.RemoteAddr(), Error: nil}
return
}
// Check if the returned answer is ok
if !checkXfrSOA(in, true) {
c <- &Exchange{w.req, in, w.rtt, w.conn.RemoteAddr(), ErrXfrSoa}
c <- &Exchange{Request: w.req, Reply: in, Rtt: w.rtt, RemoteAddr: w.conn.RemoteAddr(), Error: ErrXfrSoa}
return
}
// This serial is important
@ -110,11 +110,11 @@ func (w *reply) ixfrReceive(c chan *Exchange) {
// If the last record in the IXFR contains the servers' SOA, we should quit
if v, ok := in.Answer[len(in.Answer)-1].(*RR_SOA); ok {
if v.Serial == serial {
c <- &Exchange{w.req, in, w.rtt, w.conn.RemoteAddr(), nil}
c <- &Exchange{Request: w.req, Reply: in, Rtt: w.rtt, RemoteAddr: w.conn.RemoteAddr(), Error: nil}
return
}
}
c <- &Exchange{Request: w.req, Reply: in}
c <- &Exchange{Request: w.req, Reply: in, Rtt: w.rtt, RemoteAddr: w.conn.RemoteAddr()}
}
}
panic("not reached")