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
|
* 6975 - Algorithm Understanding in DNSSEC
|
||||||
* 7043 - EUI48/EUI64 records
|
* 7043 - EUI48/EUI64 records
|
||||||
* 7314 - DNS (EDNS) EXPIRE Option
|
* 7314 - DNS (EDNS) EXPIRE Option
|
||||||
|
* 7477 - CSYNC RR
|
||||||
* 7828 - edns-tcp-keepalive EDNS0 Option
|
* 7828 - edns-tcp-keepalive EDNS0 Option
|
||||||
* 7553 - URI record
|
* 7553 - URI record
|
||||||
* 7858 - DNS over TLS: Initiation and Performance Considerations
|
* 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) {
|
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.
|
// 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.`
|
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
|
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) {
|
func setSIG(h RR_Header, c chan lex, o, f string) (RR, *ParseError, string) {
|
||||||
r, e, s := setRRSIG(h, c, o, f)
|
r, e, s := setRRSIG(h, c, o, f)
|
||||||
if r != nil {
|
if r != nil {
|
||||||
|
@ -2043,6 +2093,7 @@ var typeToparserFunc = map[uint16]parserFunc{
|
||||||
TypeCDNSKEY: {setCDNSKEY, true},
|
TypeCDNSKEY: {setCDNSKEY, true},
|
||||||
TypeCERT: {setCERT, true},
|
TypeCERT: {setCERT, true},
|
||||||
TypeCNAME: {setCNAME, false},
|
TypeCNAME: {setCNAME, false},
|
||||||
|
TypeCSYNC: {setCSYNC, true},
|
||||||
TypeDHCID: {setDHCID, true},
|
TypeDHCID: {setDHCID, true},
|
||||||
TypeDLV: {setDLV, true},
|
TypeDLV: {setDLV, true},
|
||||||
TypeDNAME: {setDNAME, false},
|
TypeDNAME: {setDNAME, false},
|
||||||
|
|
31
types.go
31
types.go
|
@ -78,6 +78,7 @@ const (
|
||||||
TypeCDS uint16 = 59
|
TypeCDS uint16 = 59
|
||||||
TypeCDNSKEY uint16 = 60
|
TypeCDNSKEY uint16 = 60
|
||||||
TypeOPENPGPKEY uint16 = 61
|
TypeOPENPGPKEY uint16 = 61
|
||||||
|
TypeCSYNC uint16 = 62
|
||||||
TypeSPF uint16 = 99
|
TypeSPF uint16 = 99
|
||||||
TypeUINFO uint16 = 100
|
TypeUINFO uint16 = 100
|
||||||
TypeUID uint16 = 101
|
TypeUID uint16 = 101
|
||||||
|
@ -1267,6 +1268,36 @@ type OPENPGPKEY struct {
|
||||||
|
|
||||||
func (rr *OPENPGPKEY) String() string { return rr.Hdr.String() + rr.PublicKey }
|
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
|
// TimeToString translates the RRSIG's incep. and expir. times to the
|
||||||
// string representation used when printing the record.
|
// string representation used when printing the record.
|
||||||
// It takes serial arithmetic (RFC 1982) into account.
|
// It takes serial arithmetic (RFC 1982) into account.
|
||||||
|
|
|
@ -23,6 +23,7 @@ var skipLen = map[string]struct{}{
|
||||||
"NSEC": {},
|
"NSEC": {},
|
||||||
"NSEC3": {},
|
"NSEC3": {},
|
||||||
"OPT": {},
|
"OPT": {},
|
||||||
|
"CSYNC": {},
|
||||||
}
|
}
|
||||||
|
|
||||||
var packageHdr = `
|
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
|
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) {
|
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)
|
off, err := rr.Hdr.pack(msg, off, compression, compress)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
|
@ -1721,6 +1743,37 @@ func unpackCNAME(h RR_Header, msg []byte, off int) (RR, int, error) {
|
||||||
return rr, off, err
|
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) {
|
func unpackDHCID(h RR_Header, msg []byte, off int) (RR, int, error) {
|
||||||
rr := new(DHCID)
|
rr := new(DHCID)
|
||||||
rr.Hdr = h
|
rr.Hdr = h
|
||||||
|
@ -3504,6 +3557,7 @@ var typeToUnpack = map[uint16]func(RR_Header, []byte, int) (RR, int, error){
|
||||||
TypeCDS: unpackCDS,
|
TypeCDS: unpackCDS,
|
||||||
TypeCERT: unpackCERT,
|
TypeCERT: unpackCERT,
|
||||||
TypeCNAME: unpackCNAME,
|
TypeCNAME: unpackCNAME,
|
||||||
|
TypeCSYNC: unpackCSYNC,
|
||||||
TypeDHCID: unpackDHCID,
|
TypeDHCID: unpackDHCID,
|
||||||
TypeDLV: unpackDLV,
|
TypeDLV: unpackDLV,
|
||||||
TypeDNAME: unpackDNAME,
|
TypeDNAME: unpackDNAME,
|
||||||
|
|
|
@ -20,6 +20,7 @@ var TypeToRR = map[uint16]func() RR{
|
||||||
TypeCDS: func() RR { return new(CDS) },
|
TypeCDS: func() RR { return new(CDS) },
|
||||||
TypeCERT: func() RR { return new(CERT) },
|
TypeCERT: func() RR { return new(CERT) },
|
||||||
TypeCNAME: func() RR { return new(CNAME) },
|
TypeCNAME: func() RR { return new(CNAME) },
|
||||||
|
TypeCSYNC: func() RR { return new(CSYNC) },
|
||||||
TypeDHCID: func() RR { return new(DHCID) },
|
TypeDHCID: func() RR { return new(DHCID) },
|
||||||
TypeDLV: func() RR { return new(DLV) },
|
TypeDLV: func() RR { return new(DLV) },
|
||||||
TypeDNAME: func() RR { return new(DNAME) },
|
TypeDNAME: func() RR { return new(DNAME) },
|
||||||
|
@ -94,6 +95,7 @@ var TypeToString = map[uint16]string{
|
||||||
TypeCDS: "CDS",
|
TypeCDS: "CDS",
|
||||||
TypeCERT: "CERT",
|
TypeCERT: "CERT",
|
||||||
TypeCNAME: "CNAME",
|
TypeCNAME: "CNAME",
|
||||||
|
TypeCSYNC: "CSYNC",
|
||||||
TypeDHCID: "DHCID",
|
TypeDHCID: "DHCID",
|
||||||
TypeDLV: "DLV",
|
TypeDLV: "DLV",
|
||||||
TypeDNAME: "DNAME",
|
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 *CDS) Header() *RR_Header { return &rr.Hdr }
|
||||||
func (rr *CERT) 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 *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 *DHCID) Header() *RR_Header { return &rr.Hdr }
|
||||||
func (rr *DLV) Header() *RR_Header { return &rr.Hdr }
|
func (rr *DLV) Header() *RR_Header { return &rr.Hdr }
|
||||||
func (rr *DNAME) 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 {
|
func (rr *CNAME) copy() RR {
|
||||||
return &CNAME{*rr.Hdr.copyHeader(), rr.Target}
|
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 {
|
func (rr *DHCID) copy() RR {
|
||||||
return &DHCID{*rr.Hdr.copyHeader(), rr.Digest}
|
return &DHCID{*rr.Hdr.copyHeader(), rr.Digest}
|
||||||
}
|
}
|
||||||
|
|
Loading…
Reference in New Issue