From 767422ac12884e2baed0afd7303cf06cff90fef6 Mon Sep 17 00:00:00 2001 From: Miek Gieben Date: Wed, 29 Mar 2017 22:17:13 +0200 Subject: [PATCH] Add AVC record (#480) See https://www.iana.org/assignments/dns-parameters/AVC/avc-completed-template for the template, a new record that is (again) a mirror of the TXT record. For lack of a better name, name the rdata Txt - as we do in SPF and TXT. --- parse_test.go | 18 +++++++ scan_rr.go | 13 +++++ types.go | 8 +++ zcompress.go | 146 +++++++++++++++++++++++++------------------------- zmsg.go | 32 +++++++++++ ztypes.go | 15 ++++++ 6 files changed, 159 insertions(+), 73 deletions(-) diff --git a/parse_test.go b/parse_test.go index c727c130..2622318d 100644 --- a/parse_test.go +++ b/parse_test.go @@ -1509,3 +1509,21 @@ func TestParseURI(t *testing.T) { } } } + +func TestParseAVC(t *testing.T) { + avcs := map[string]string{ + `example.org. IN AVC "app-name:WOLFGANG|app-class:OAM|business=yes"`: `example.org. 3600 IN AVC "app-name:WOLFGANG|app-class:OAM|business=yes"`, + } + for avc, o := range avcs { + rr, err := NewRR(avc) + 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'", avc, o, rr.String()) + } else { + t.Logf("RR is OK: `%s'", rr.String()) + } + } +} diff --git a/scan_rr.go b/scan_rr.go index f4c0d376..b8b18fd7 100644 --- a/scan_rr.go +++ b/scan_rr.go @@ -1807,6 +1807,18 @@ func setSPF(h RR_Header, c chan lex, o, f string) (RR, *ParseError, string) { return rr, nil, c1 } +func setAVC(h RR_Header, c chan lex, o, f string) (RR, *ParseError, string) { + rr := new(AVC) + rr.Hdr = h + + s, e, c1 := endingToTxtSlice(c, "bad AVC Txt", f) + if e != nil { + return nil, e, "" + } + rr.Txt = s + return rr, nil, c1 +} + func setTXT(h RR_Header, c chan lex, o, f string) (RR, *ParseError, string) { rr := new(TXT) rr.Hdr = h @@ -2158,6 +2170,7 @@ var typeToparserFunc = map[uint16]parserFunc{ TypeSMIMEA: {setSMIMEA, true}, TypeSOA: {setSOA, false}, TypeSPF: {setSPF, true}, + TypeAVC: {setAVC, true}, TypeSRV: {setSRV, false}, TypeSSHFP: {setSSHFP, true}, TypeTALINK: {setTALINK, false}, diff --git a/types.go b/types.go index c17251cb..53da4755 100644 --- a/types.go +++ b/types.go @@ -91,6 +91,7 @@ const ( TypeEUI64 uint16 = 109 TypeURI uint16 = 256 TypeCAA uint16 = 257 + TypeAVC uint16 = 258 TypeTKEY uint16 = 249 TypeTSIG uint16 = 250 @@ -530,6 +531,13 @@ type SPF struct { func (rr *SPF) String() string { return rr.Hdr.String() + sprintTxt(rr.Txt) } +type AVC struct { + Hdr RR_Header + Txt []string `dns:"txt"` +} + +func (rr *AVC) String() string { return rr.Hdr.String() + sprintTxt(rr.Txt) } + type SRV struct { Hdr RR_Header Priority uint16 diff --git a/zcompress.go b/zcompress.go index 86a31a91..b277978b 100644 --- a/zcompress.go +++ b/zcompress.go @@ -5,99 +5,95 @@ package dns func compressionLenHelperType(c map[string]int, r RR) { switch x := r.(type) { - case *KX: - compressionLenHelper(c, x.Exchanger) - case *MX: - compressionLenHelper(c, x.Mx) - case *NSEC: - compressionLenHelper(c, x.NextDomain) - case *DNAME: - compressionLenHelper(c, x.Target) - case *HIP: - for i := range x.RendezvousServers { - compressionLenHelper(c, x.RendezvousServers[i]) - } - case *CNAME: - compressionLenHelper(c, x.Target) - case *MR: - compressionLenHelper(c, x.Mr) - case *PX: - compressionLenHelper(c, x.Map822) - compressionLenHelper(c, x.Mapx400) - case *SIG: - compressionLenHelper(c, x.SignerName) - case *SRV: - compressionLenHelper(c, x.Target) - case *TALINK: - compressionLenHelper(c, x.PreviousName) - compressionLenHelper(c, x.NextName) - case *LP: - compressionLenHelper(c, x.Fqdn) - case *NAPTR: - compressionLenHelper(c, x.Replacement) - case *NS: - compressionLenHelper(c, x.Ns) - case *RP: - compressionLenHelper(c, x.Mbox) - compressionLenHelper(c, x.Txt) - case *RRSIG: - compressionLenHelper(c, x.SignerName) - case *TKEY: - compressionLenHelper(c, x.Algorithm) - case *TSIG: - compressionLenHelper(c, x.Algorithm) - case *AFSDB: - compressionLenHelper(c, x.Hostname) - case *MF: - compressionLenHelper(c, x.Mf) - case *RT: - compressionLenHelper(c, x.Host) - case *MINFO: - compressionLenHelper(c, x.Rmail) - compressionLenHelper(c, x.Email) case *PTR: compressionLenHelper(c, x.Ptr) case *SOA: compressionLenHelper(c, x.Ns) compressionLenHelper(c, x.Mbox) - case *MD: - compressionLenHelper(c, x.Md) - case *NSAPPTR: - compressionLenHelper(c, x.Ptr) - case *MG: - compressionLenHelper(c, x.Mg) + case *AFSDB: + compressionLenHelper(c, x.Hostname) + case *HIP: + for i := range x.RendezvousServers { + compressionLenHelper(c, x.RendezvousServers[i]) + } + case *LP: + compressionLenHelper(c, x.Fqdn) + case *CNAME: + compressionLenHelper(c, x.Target) case *MB: compressionLenHelper(c, x.Mb) + case *RP: + compressionLenHelper(c, x.Mbox) + compressionLenHelper(c, x.Txt) + case *RRSIG: + compressionLenHelper(c, x.SignerName) + case *MF: + compressionLenHelper(c, x.Mf) + case *MINFO: + compressionLenHelper(c, x.Rmail) + compressionLenHelper(c, x.Email) + case *SIG: + compressionLenHelper(c, x.SignerName) + case *SRV: + compressionLenHelper(c, x.Target) + case *TSIG: + compressionLenHelper(c, x.Algorithm) + case *KX: + compressionLenHelper(c, x.Exchanger) + case *MG: + compressionLenHelper(c, x.Mg) + case *NSAPPTR: + compressionLenHelper(c, x.Ptr) + case *PX: + compressionLenHelper(c, x.Map822) + compressionLenHelper(c, x.Mapx400) + case *DNAME: + compressionLenHelper(c, x.Target) + case *MR: + compressionLenHelper(c, x.Mr) + case *MX: + compressionLenHelper(c, x.Mx) + case *TKEY: + compressionLenHelper(c, x.Algorithm) + case *NSEC: + compressionLenHelper(c, x.NextDomain) + case *TALINK: + compressionLenHelper(c, x.PreviousName) + compressionLenHelper(c, x.NextName) + case *MD: + compressionLenHelper(c, x.Md) + case *NAPTR: + compressionLenHelper(c, x.Replacement) + case *NS: + compressionLenHelper(c, x.Ns) + case *RT: + compressionLenHelper(c, x.Host) } } func compressionLenSearchType(c map[string]int, r RR) (int, bool) { switch x := r.(type) { - case *MF: - k1, ok1 := compressionLenSearch(c, x.Mf) - return k1, ok1 case *MG: k1, ok1 := compressionLenSearch(c, x.Mg) return k1, ok1 - case *MINFO: - k1, ok1 := compressionLenSearch(c, x.Rmail) - k2, ok2 := compressionLenSearch(c, x.Email) - return k1 + k2, ok1 && ok2 - case *MR: - k1, ok1 := compressionLenSearch(c, x.Mr) - return k1, ok1 case *PTR: k1, ok1 := compressionLenSearch(c, x.Ptr) return k1, ok1 case *AFSDB: k1, ok1 := compressionLenSearch(c, x.Hostname) return k1, ok1 - case *CNAME: - k1, ok1 := compressionLenSearch(c, x.Target) + case *MB: + k1, ok1 := compressionLenSearch(c, x.Mb) return k1, ok1 case *MD: k1, ok1 := compressionLenSearch(c, x.Md) return k1, ok1 + case *MF: + k1, ok1 := compressionLenSearch(c, x.Mf) + return k1, ok1 + case *NS: + k1, ok1 := compressionLenSearch(c, x.Ns) + return k1, ok1 case *RT: k1, ok1 := compressionLenSearch(c, x.Host) return k1, ok1 @@ -105,15 +101,19 @@ func compressionLenSearchType(c map[string]int, r RR) (int, bool) { k1, ok1 := compressionLenSearch(c, x.Ns) k2, ok2 := compressionLenSearch(c, x.Mbox) return k1 + k2, ok1 && ok2 - case *MB: - k1, ok1 := compressionLenSearch(c, x.Mb) + case *CNAME: + k1, ok1 := compressionLenSearch(c, x.Target) + return k1, ok1 + case *MINFO: + k1, ok1 := compressionLenSearch(c, x.Rmail) + k2, ok2 := compressionLenSearch(c, x.Email) + return k1 + k2, ok1 && ok2 + case *MR: + k1, ok1 := compressionLenSearch(c, x.Mr) return k1, ok1 case *MX: k1, ok1 := compressionLenSearch(c, x.Mx) return k1, ok1 - case *NS: - k1, ok1 := compressionLenSearch(c, x.Ns) - return k1, ok1 } return 0, false } diff --git a/zmsg.go b/zmsg.go index 9b98e1bb..418fb1fe 100644 --- a/zmsg.go +++ b/zmsg.go @@ -61,6 +61,20 @@ func (rr *ANY) pack(msg []byte, off int, compression map[string]int, compress bo return off, nil } +func (rr *AVC) 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 = packStringTxt(rr.Txt, msg, off) + if err != nil { + return off, err + } + rr.Header().Rdlength = uint16(off - headerEnd) + return off, nil +} + func (rr *CAA) 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 { @@ -1528,6 +1542,23 @@ func unpackANY(h RR_Header, msg []byte, off int) (RR, int, error) { return rr, off, err } +func unpackAVC(h RR_Header, msg []byte, off int) (RR, int, error) { + rr := new(AVC) + rr.Hdr = h + if noRdata(h) { + return rr, off, nil + } + var err error + rdStart := off + _ = rdStart + + rr.Txt, off, err = unpackStringTxt(msg, off) + if err != nil { + return rr, off, err + } + return rr, off, err +} + func unpackCAA(h RR_Header, msg []byte, off int) (RR, int, error) { rr := new(CAA) rr.Hdr = h @@ -3467,6 +3498,7 @@ var typeToUnpack = map[uint16]func(RR_Header, []byte, int) (RR, int, error){ TypeAAAA: unpackAAAA, TypeAFSDB: unpackAFSDB, TypeANY: unpackANY, + TypeAVC: unpackAVC, TypeCAA: unpackCAA, TypeCDNSKEY: unpackCDNSKEY, TypeCDS: unpackCDS, diff --git a/ztypes.go b/ztypes.go index 311b8243..3e534f12 100644 --- a/ztypes.go +++ b/ztypes.go @@ -14,6 +14,7 @@ var TypeToRR = map[uint16]func() RR{ TypeAAAA: func() RR { return new(AAAA) }, TypeAFSDB: func() RR { return new(AFSDB) }, TypeANY: func() RR { return new(ANY) }, + TypeAVC: func() RR { return new(AVC) }, TypeCAA: func() RR { return new(CAA) }, TypeCDNSKEY: func() RR { return new(CDNSKEY) }, TypeCDS: func() RR { return new(CDS) }, @@ -86,6 +87,7 @@ var TypeToString = map[uint16]string{ TypeAFSDB: "AFSDB", TypeANY: "ANY", TypeATMA: "ATMA", + TypeAVC: "AVC", TypeAXFR: "AXFR", TypeCAA: "CAA", TypeCDNSKEY: "CDNSKEY", @@ -166,6 +168,7 @@ func (rr *A) Header() *RR_Header { return &rr.Hdr } func (rr *AAAA) Header() *RR_Header { return &rr.Hdr } func (rr *AFSDB) Header() *RR_Header { return &rr.Hdr } func (rr *ANY) Header() *RR_Header { return &rr.Hdr } +func (rr *AVC) Header() *RR_Header { return &rr.Hdr } func (rr *CAA) Header() *RR_Header { return &rr.Hdr } func (rr *CDNSKEY) Header() *RR_Header { return &rr.Hdr } func (rr *CDS) Header() *RR_Header { return &rr.Hdr } @@ -252,6 +255,13 @@ func (rr *ANY) len() int { l := rr.Hdr.len() return l } +func (rr *AVC) len() int { + l := rr.Hdr.len() + for _, x := range rr.Txt { + l += len(x) + 1 + } + return l +} func (rr *CAA) len() int { l := rr.Hdr.len() l++ // Flag @@ -649,6 +659,11 @@ func (rr *AFSDB) copy() RR { func (rr *ANY) copy() RR { return &ANY{*rr.Hdr.copyHeader()} } +func (rr *AVC) copy() RR { + Txt := make([]string, len(rr.Txt)) + copy(Txt, rr.Txt) + return &AVC{*rr.Hdr.copyHeader(), Txt} +} func (rr *CAA) copy() RR { return &CAA{*rr.Hdr.copyHeader(), rr.Flag, rr.Tag, rr.Value} }