Implement CSYNC (#585)
Implement the CSYNC record. Fixes #290 Long overdue, lets add this record. Similar in vain as NSEC/NSEC3, we need to implement len() our selves. Presentation format parsing and tests are done as well. This is CoreDNS running with CSYNC support, `dig` doesn't support this at the moment, so: ~~~ ;; ->>HEADER<<- opcode: QUERY, status: NOERROR, id: 40323 ;; flags: qr aa rd ra; QUERY: 1, ANSWER: 1, AUTHORITY: 2, ADDITIONAL: 1 ;; OPT PSEUDOSECTION: ; EDNS: version: 0, flags:; udp: 4096 ;; QUESTION SECTION: ;csync.example.org. IN TYPE62 ;; ANSWER SECTION: csync.example.org. 10 IN TYPE62 \# 12 000335240042000460000008 ;; AUTHORITY SECTION: example.org. 10 IN NS a.iana-servers.net. example.org. 10 IN NS b.iana-servers.net. ~~~
This commit is contained in:
parent
e776a21550
commit
2ae4695cc7
|
@ -150,6 +150,7 @@ Example programs can be found in the `github.com/miekg/exdns` repository.
|
|||
* 6975 - Algorithm Understanding in DNSSEC
|
||||
* 7043 - EUI48/EUI64 records
|
||||
* 7314 - DNS (EDNS) EXPIRE Option
|
||||
* 7477 - CSYNC RR
|
||||
* 7828 - edns-tcp-keepalive EDNS0 Option
|
||||
* 7553 - URI record
|
||||
* 7858 - DNS over TLS: Initiation and Performance Considerations
|
||||
|
|
|
@ -1406,6 +1406,22 @@ func TestParseAVC(t *testing.T) {
|
|||
}
|
||||
}
|
||||
|
||||
func TestParseCSYNC(t *testing.T) {
|
||||
syncs := map[string]string{
|
||||
`example.com. 3600 IN CSYNC 66 3 A NS AAAA`: `example.com. 3600 IN CSYNC 66 3 A NS AAAA`,
|
||||
}
|
||||
for s, o := range syncs {
|
||||
rr, err := NewRR(s)
|
||||
if err != nil {
|
||||
t.Error("failed to parse RR: ", err)
|
||||
continue
|
||||
}
|
||||
if rr.String() != o {
|
||||
t.Errorf("`%s' should be equal to\n`%s', but is `%s'", s, o, rr.String())
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
func TestParseBadNAPTR(t *testing.T) {
|
||||
// Should look like: mplus.ims.vodafone.com. 3600 IN NAPTR 10 100 "S" "SIP+D2U" "" _sip._udp.mplus.ims.vodafone.com.
|
||||
naptr := `mplus.ims.vodafone.com. 3600 IN NAPTR 10 100 S SIP+D2U _sip._udp.mplus.ims.vodafone.com.`
|
||||
|
|
51
scan_rr.go
51
scan_rr.go
|
@ -1024,6 +1024,56 @@ func setOPENPGPKEY(h RR_Header, c chan lex, o, f string) (RR, *ParseError, strin
|
|||
return rr, nil, c1
|
||||
}
|
||||
|
||||
func setCSYNC(h RR_Header, c chan lex, o, f string) (RR, *ParseError, string) {
|
||||
rr := new(CSYNC)
|
||||
rr.Hdr = h
|
||||
|
||||
l := <-c
|
||||
if l.length == 0 { // dynamic update rr.
|
||||
return rr, nil, l.comment
|
||||
}
|
||||
j, e := strconv.ParseUint(l.token, 10, 32)
|
||||
if e != nil {
|
||||
// Serial must be a number
|
||||
return nil, &ParseError{f, "bad CSYNC serial", l}, ""
|
||||
}
|
||||
rr.Serial = uint32(j)
|
||||
|
||||
<-c // zBlank
|
||||
|
||||
l = <-c
|
||||
j, e = strconv.ParseUint(l.token, 10, 16)
|
||||
if e != nil {
|
||||
// Serial must be a number
|
||||
return nil, &ParseError{f, "bad CSYNC flags", l}, ""
|
||||
}
|
||||
rr.Flags = uint16(j)
|
||||
|
||||
rr.TypeBitMap = make([]uint16, 0)
|
||||
var (
|
||||
k uint16
|
||||
ok bool
|
||||
)
|
||||
l = <-c
|
||||
for l.value != zNewline && l.value != zEOF {
|
||||
switch l.value {
|
||||
case zBlank:
|
||||
// Ok
|
||||
case zString:
|
||||
if k, ok = StringToType[l.tokenUpper]; !ok {
|
||||
if k, ok = typeToInt(l.tokenUpper); !ok {
|
||||
return nil, &ParseError{f, "bad CSYNC TypeBitMap", l}, ""
|
||||
}
|
||||
}
|
||||
rr.TypeBitMap = append(rr.TypeBitMap, k)
|
||||
default:
|
||||
return nil, &ParseError{f, "bad CSYNC TypeBitMap", l}, ""
|
||||
}
|
||||
l = <-c
|
||||
}
|
||||
return rr, nil, l.comment
|
||||
}
|
||||
|
||||
func setSIG(h RR_Header, c chan lex, o, f string) (RR, *ParseError, string) {
|
||||
r, e, s := setRRSIG(h, c, o, f)
|
||||
if r != nil {
|
||||
|
@ -2043,6 +2093,7 @@ var typeToparserFunc = map[uint16]parserFunc{
|
|||
TypeCDNSKEY: {setCDNSKEY, true},
|
||||
TypeCERT: {setCERT, true},
|
||||
TypeCNAME: {setCNAME, false},
|
||||
TypeCSYNC: {setCSYNC, true},
|
||||
TypeDHCID: {setDHCID, true},
|
||||
TypeDLV: {setDLV, true},
|
||||
TypeDNAME: {setDNAME, false},
|
||||
|
|
31
types.go
31
types.go
|
@ -78,6 +78,7 @@ const (
|
|||
TypeCDS uint16 = 59
|
||||
TypeCDNSKEY uint16 = 60
|
||||
TypeOPENPGPKEY uint16 = 61
|
||||
TypeCSYNC uint16 = 62
|
||||
TypeSPF uint16 = 99
|
||||
TypeUINFO uint16 = 100
|
||||
TypeUID uint16 = 101
|
||||
|
@ -1267,6 +1268,36 @@ type OPENPGPKEY struct {
|
|||
|
||||
func (rr *OPENPGPKEY) String() string { return rr.Hdr.String() + rr.PublicKey }
|
||||
|
||||
// CSYNC RR. See RFC 7477.
|
||||
type CSYNC struct {
|
||||
Hdr RR_Header
|
||||
Serial uint32
|
||||
Flags uint16
|
||||
TypeBitMap []uint16 `dns:"nsec"`
|
||||
}
|
||||
|
||||
func (rr *CSYNC) String() string {
|
||||
s := rr.Hdr.String() + strconv.FormatInt(int64(rr.Serial), 10) + " " + strconv.Itoa(int(rr.Flags))
|
||||
|
||||
for i := 0; i < len(rr.TypeBitMap); i++ {
|
||||
s += " " + Type(rr.TypeBitMap[i]).String()
|
||||
}
|
||||
return s
|
||||
}
|
||||
|
||||
func (rr *CSYNC) len() int {
|
||||
l := rr.Hdr.len() + 4 + 2
|
||||
lastwindow := uint32(2 ^ 32 + 1)
|
||||
for _, t := range rr.TypeBitMap {
|
||||
window := t / 256
|
||||
if uint32(window) != lastwindow {
|
||||
l += 1 + 32
|
||||
}
|
||||
lastwindow = uint32(window)
|
||||
}
|
||||
return l
|
||||
}
|
||||
|
||||
// TimeToString translates the RRSIG's incep. and expir. times to the
|
||||
// string representation used when printing the record.
|
||||
// It takes serial arithmetic (RFC 1982) into account.
|
||||
|
|
|
@ -23,6 +23,7 @@ var skipLen = map[string]struct{}{
|
|||
"NSEC": {},
|
||||
"NSEC3": {},
|
||||
"OPT": {},
|
||||
"CSYNC": {},
|
||||
}
|
||||
|
||||
var packageHdr = `
|
||||
|
|
54
zmsg.go
54
zmsg.go
|
@ -189,6 +189,28 @@ func (rr *CNAME) pack(msg []byte, off int, compression map[string]int, compress
|
|||
return off, nil
|
||||
}
|
||||
|
||||
func (rr *CSYNC) pack(msg []byte, off int, compression map[string]int, compress bool) (int, error) {
|
||||
off, err := rr.Hdr.pack(msg, off, compression, compress)
|
||||
if err != nil {
|
||||
return off, err
|
||||
}
|
||||
headerEnd := off
|
||||
off, err = packUint32(rr.Serial, msg, off)
|
||||
if err != nil {
|
||||
return off, err
|
||||
}
|
||||
off, err = packUint16(rr.Flags, msg, off)
|
||||
if err != nil {
|
||||
return off, err
|
||||
}
|
||||
off, err = packDataNsec(rr.TypeBitMap, msg, off)
|
||||
if err != nil {
|
||||
return off, err
|
||||
}
|
||||
rr.Header().Rdlength = uint16(off - headerEnd)
|
||||
return off, nil
|
||||
}
|
||||
|
||||
func (rr *DHCID) pack(msg []byte, off int, compression map[string]int, compress bool) (int, error) {
|
||||
off, err := rr.Hdr.pack(msg, off, compression, compress)
|
||||
if err != nil {
|
||||
|
@ -1721,6 +1743,37 @@ func unpackCNAME(h RR_Header, msg []byte, off int) (RR, int, error) {
|
|||
return rr, off, err
|
||||
}
|
||||
|
||||
func unpackCSYNC(h RR_Header, msg []byte, off int) (RR, int, error) {
|
||||
rr := new(CSYNC)
|
||||
rr.Hdr = h
|
||||
if noRdata(h) {
|
||||
return rr, off, nil
|
||||
}
|
||||
var err error
|
||||
rdStart := off
|
||||
_ = rdStart
|
||||
|
||||
rr.Serial, off, err = unpackUint32(msg, off)
|
||||
if err != nil {
|
||||
return rr, off, err
|
||||
}
|
||||
if off == len(msg) {
|
||||
return rr, off, nil
|
||||
}
|
||||
rr.Flags, off, err = unpackUint16(msg, off)
|
||||
if err != nil {
|
||||
return rr, off, err
|
||||
}
|
||||
if off == len(msg) {
|
||||
return rr, off, nil
|
||||
}
|
||||
rr.TypeBitMap, off, err = unpackDataNsec(msg, off)
|
||||
if err != nil {
|
||||
return rr, off, err
|
||||
}
|
||||
return rr, off, err
|
||||
}
|
||||
|
||||
func unpackDHCID(h RR_Header, msg []byte, off int) (RR, int, error) {
|
||||
rr := new(DHCID)
|
||||
rr.Hdr = h
|
||||
|
@ -3504,6 +3557,7 @@ var typeToUnpack = map[uint16]func(RR_Header, []byte, int) (RR, int, error){
|
|||
TypeCDS: unpackCDS,
|
||||
TypeCERT: unpackCERT,
|
||||
TypeCNAME: unpackCNAME,
|
||||
TypeCSYNC: unpackCSYNC,
|
||||
TypeDHCID: unpackDHCID,
|
||||
TypeDLV: unpackDLV,
|
||||
TypeDNAME: unpackDNAME,
|
||||
|
|
|
@ -20,6 +20,7 @@ var TypeToRR = map[uint16]func() RR{
|
|||
TypeCDS: func() RR { return new(CDS) },
|
||||
TypeCERT: func() RR { return new(CERT) },
|
||||
TypeCNAME: func() RR { return new(CNAME) },
|
||||
TypeCSYNC: func() RR { return new(CSYNC) },
|
||||
TypeDHCID: func() RR { return new(DHCID) },
|
||||
TypeDLV: func() RR { return new(DLV) },
|
||||
TypeDNAME: func() RR { return new(DNAME) },
|
||||
|
@ -94,6 +95,7 @@ var TypeToString = map[uint16]string{
|
|||
TypeCDS: "CDS",
|
||||
TypeCERT: "CERT",
|
||||
TypeCNAME: "CNAME",
|
||||
TypeCSYNC: "CSYNC",
|
||||
TypeDHCID: "DHCID",
|
||||
TypeDLV: "DLV",
|
||||
TypeDNAME: "DNAME",
|
||||
|
@ -173,6 +175,7 @@ func (rr *CDNSKEY) Header() *RR_Header { return &rr.Hdr }
|
|||
func (rr *CDS) Header() *RR_Header { return &rr.Hdr }
|
||||
func (rr *CERT) Header() *RR_Header { return &rr.Hdr }
|
||||
func (rr *CNAME) Header() *RR_Header { return &rr.Hdr }
|
||||
func (rr *CSYNC) Header() *RR_Header { return &rr.Hdr }
|
||||
func (rr *DHCID) Header() *RR_Header { return &rr.Hdr }
|
||||
func (rr *DLV) Header() *RR_Header { return &rr.Hdr }
|
||||
func (rr *DNAME) Header() *RR_Header { return &rr.Hdr }
|
||||
|
@ -672,6 +675,11 @@ func (rr *CERT) copy() RR {
|
|||
func (rr *CNAME) copy() RR {
|
||||
return &CNAME{*rr.Hdr.copyHeader(), rr.Target}
|
||||
}
|
||||
func (rr *CSYNC) copy() RR {
|
||||
TypeBitMap := make([]uint16, len(rr.TypeBitMap))
|
||||
copy(TypeBitMap, rr.TypeBitMap)
|
||||
return &CSYNC{*rr.Hdr.copyHeader(), rr.Serial, rr.Flags, TypeBitMap}
|
||||
}
|
||||
func (rr *DHCID) copy() RR {
|
||||
return &DHCID{*rr.Hdr.copyHeader(), rr.Digest}
|
||||
}
|
||||
|
|
Loading…
Reference in New Issue