diff --git a/README.md b/README.md index b09cb4cf..3ef388c2 100644 --- a/README.md +++ b/README.md @@ -118,6 +118,7 @@ Example programs can be found in the `github.com/miekg/exdns` repository. * 6605 - ECDSA * 6725 - IANA Registry Update * 6742 - ILNP DNS +* 6844 - CAA record * 6891 - EDNS0 update * 6895 - DNS IANA considerations * 6975 - Algorithm Understanding in DNSSEC @@ -138,6 +139,5 @@ Example programs can be found in the `github.com/miekg/exdns` repository. * privatekey.Precompute() when signing? * Last remaining RRs: APL, ATMA, A6 and NXT and IPSECKEY; * Missing in parsing: ISDN, UNSPEC, ATMA; -* CAA parsing is broken; * NSEC(3) cover/match/closest enclose; * Replies with TC bit are not parsed to the end; diff --git a/dns_test.go b/dns_test.go index d16fe09f..7cf810ea 100644 --- a/dns_test.go +++ b/dns_test.go @@ -429,9 +429,6 @@ func TestToRFC3597(t *testing.T) { func TestNoRdataPack(t *testing.T) { data := make([]byte, 1024) for typ, fn := range typeToRR { - if typ == TypeCAA { - continue // TODO(miek): known omission - } r := fn() *r.Header() = RR_Header{Name: "miek.nl.", Rrtype: typ, Class: ClassINET, Ttl: 3600} _, err := PackRR(r, data, 0, nil, false) diff --git a/msg.go b/msg.go index 7ccd5319..31b1558a 100644 --- a/msg.go +++ b/msg.go @@ -100,7 +100,7 @@ var TypeToString = map[uint16]string{ TypeANY: "ANY", // Meta RR TypeATMA: "ATMA", TypeAXFR: "AXFR", // Meta RR - TypeCAA: "CAA", + TypeCAA: "TYPE257", TypeCDNSKEY: "CDNSKEY", TypeCDS: "CDS", TypeCERT: "CERT", diff --git a/types.go b/types.go index bd95fd9a..1e826cbe 100644 --- a/types.go +++ b/types.go @@ -1527,25 +1527,25 @@ func (rr *EUI64) copy() RR { return &EUI64{*rr.Hdr.copyHeader(), rr.Ad func (rr *EUI64) String() string { return rr.Hdr.String() + euiToString(rr.Address, 64) } func (rr *EUI64) len() int { return rr.Hdr.len() + 8 } -// Support in incomplete - just handle it as unknown record -/* type CAA struct { Hdr RR_Header Flag uint8 Tag string - Value string `dns:"octet"` + Value string `dns:"hex"` } func (rr *CAA) Header() *RR_Header { return &rr.Hdr } func (rr *CAA) copy() RR { return &CAA{*rr.Hdr.copyHeader(), rr.Flag, rr.Tag, rr.Value} } -func (rr *CAA) len() int { return rr.Hdr.len() + 1 + len(rr.Tag) + 1 + len(rr.Value) } +func (rr *CAA) len() int { return rr.Hdr.len() + 1 + len(rr.Tag) + len(rr.Value)/2 } func (rr *CAA) String() string { - s := rr.Hdr.String() + strconv.FormatInt(int64(rr.Flag), 10) + " " + rr.Tag - s += strconv.QuoteToASCII(rr.Value) + s := rr.Hdr.String() + + s += "\\# " + strconv.Itoa(2 + len(rr.Tag) + len(rr.Value)) + " " + s += fmt.Sprintf("%02X%02X%X%s", rr.Flag, len(rr.Tag), rr.Tag, strings.ToUpper(rr.Value)) return s } -*/ + type UID struct { Hdr RR_Header @@ -1668,10 +1668,10 @@ func copyIP(ip net.IP) net.IP { // Map of constructors for each RR type. var typeToRR = map[uint16]func() RR{ - TypeA: func() RR { return new(A) }, - TypeAAAA: func() RR { return new(AAAA) }, - TypeAFSDB: func() RR { return new(AFSDB) }, - // TypeCAA: func() RR { return new(CAA) }, + TypeA: func() RR { return new(A) }, + TypeAAAA: func() RR { return new(AAAA) }, + TypeAFSDB: func() RR { return new(AFSDB) }, + TypeCAA: func() RR { return new(CAA) }, TypeCDS: func() RR { return new(CDS) }, TypeCERT: func() RR { return new(CERT) }, TypeCNAME: func() RR { return new(CNAME) }, diff --git a/update_test.go b/update_test.go index 0c6d1e23..2a5a2347 100644 --- a/update_test.go +++ b/update_test.go @@ -8,7 +8,7 @@ import ( func TestDynamicUpdateParsing(t *testing.T) { prefix := "example.com. IN " for _, typ := range TypeToString { - if typ == "CAA" || typ == "OPT" || typ == "AXFR" || typ == "IXFR" || typ == "ANY" || typ == "TKEY" || + if typ == "TYPE257" || typ == "OPT" || typ == "AXFR" || typ == "IXFR" || typ == "ANY" || typ == "TKEY" || typ == "TSIG" || typ == "ISDN" || typ == "UNSPEC" || typ == "NULL" || typ == "ATMA" { continue } diff --git a/zscan_rr.go b/zscan_rr.go index e5ca2615..66cfbed5 100644 --- a/zscan_rr.go +++ b/zscan_rr.go @@ -2,6 +2,7 @@ package dns import ( "encoding/base64" + "encoding/hex" "net" "strconv" "strings" @@ -2170,10 +2171,57 @@ func setIPSECKEY(h RR_Header, c chan lex, o, f string) (RR, *ParseError, string) return rr, nil, c1 } +func setCAA(h RR_Header, c chan lex, o, f string) (RR, *ParseError, string) { + rr := new(CAA) + rr.Hdr = h + l := <-c + if l.token != "\\#" { + return nil, &ParseError{f, "bad CAA Rdata", l}, "" + } + <-c // zBlank + l = <-c + rdlength, e := strconv.Atoi(l.token) + if e != nil { + return nil, &ParseError{f, "bad CAA Rdata", l}, "" + } + s, e1, c1 := endingToString(c, "bad CAA Rdata", f) + if e1 != nil { + return nil, e1, c1 + } + if rdlength*2 != len(s) || rdlength*2 < 4 { + return nil, &ParseError{f, "bad CAA Rdata", l}, "" + } + + flagbyte, e := hex.DecodeString(s[0:2]) + if e != nil { + return nil, &ParseError{f, "bad CAA Flag", l}, "" + } + rr.Flag = uint8(flagbyte[0]) + + tagbyte, e := hex.DecodeString(s[2:4]) + if e != nil { + return nil, &ParseError{f, "bad CAA Tag length", l}, "" + } + taglength := int(tagbyte[0]) + + if rdlength*2 < (4 + taglength) { + return nil, &ParseError{f, "bad CAA Tag length", l}, "" + } + + tag, e := hex.DecodeString(s[4:4+taglength]) + if e != nil { + return nil, &ParseError{f, "bad CAA Tag", l}, "" + } + rr.Tag = string(tag) + + return rr, nil, c1 +} + var typeToparserFunc = map[uint16]parserFunc{ TypeAAAA: parserFunc{setAAAA, false}, TypeAFSDB: parserFunc{setAFSDB, false}, TypeA: parserFunc{setA, false}, + TypeCAA: parserFunc{setCAA, true}, TypeCDS: parserFunc{setCDS, true}, TypeCDNSKEY: parserFunc{setCDNSKEY, true}, TypeCERT: parserFunc{setCERT, true},