Add NULL record (#840)

Sorely missing from this library. Add it. As there is no presentation
format the String method for this type puts a comment in front of it.

Signed-off-by: Miek Gieben <miek@miek.nl>
This commit is contained in:
Miek Gieben 2018-12-30 09:45:18 +00:00 committed by GitHub
parent 5f5f2380fc
commit 56516cf4de
No known key found for this signature in database
GPG Key ID: 4AEE18F83AFDEB23
8 changed files with 107 additions and 12 deletions

View File

@ -153,7 +153,8 @@ if rr.%s != "-" {
fallthrough
case st.Tag(i) == `dns:"hex"`:
o("off, err = packStringHex(rr.%s, msg, off)\n")
case st.Tag(i) == `dns:"any"`:
o("off, err = packStringAny(rr.%s, msg, off)\n")
case st.Tag(i) == `dns:"octet"`:
o("off, err = packStringOctet(rr.%s, msg, off)\n")
case st.Tag(i) == "":
@ -261,6 +262,8 @@ return rr, off, err
o("rr.%s, off, err = unpackStringBase64(msg, off, rdStart + int(rr.Hdr.Rdlength))\n")
case `dns:"hex"`:
o("rr.%s, off, err = unpackStringHex(msg, off, rdStart + int(rr.Hdr.Rdlength))\n")
case `dns:"any"`:
o("rr.%s, off, err = unpackStringAny(msg, off, rdStart + int(rr.Hdr.Rdlength))\n")
case `dns:"octet"`:
o("rr.%s, off, err = unpackStringOctet(msg, off)\n")
case "":

View File

@ -363,6 +363,22 @@ func packStringHex(s string, msg []byte, off int) (int, error) {
return off, nil
}
func unpackStringAny(msg []byte, off, end int) (string, int, error) {
if end > len(msg) {
return "", len(msg), &Error{err: "overflow unpacking anything"}
}
return string(msg[off:end]), end, nil
}
func packStringAny(s string, msg []byte, off int) (int, error) {
if off+len(s) > len(msg) {
return len(msg), &Error{err: "overflow packing anything"}
}
copy(msg[off:off+len(s)], s)
off += len(s)
return off, nil
}
func unpackStringTxt(msg []byte, off int) ([]string, int, error) {
txt, off, err := unpackTxt(msg, off)
if err != nil {

View File

@ -341,7 +341,7 @@ func TestParseDirectiveMisc(t *testing.T) {
func TestNSEC(t *testing.T) {
nsectests := map[string]string{
"nl. IN NSEC3PARAM 1 0 5 30923C44C6CBBB8F": "nl.\t3600\tIN\tNSEC3PARAM\t1 0 5 30923C44C6CBBB8F",
"nl. IN NSEC3PARAM 1 0 5 30923C44C6CBBB8F": "nl.\t3600\tIN\tNSEC3PARAM\t1 0 5 30923C44C6CBBB8F",
"p2209hipbpnm681knjnu0m1febshlv4e.nl. IN NSEC3 1 1 5 30923C44C6CBBB8F P90DG1KE8QEAN0B01613LHQDG0SOJ0TA NS SOA TXT RRSIG DNSKEY NSEC3PARAM": "p2209hipbpnm681knjnu0m1febshlv4e.nl.\t3600\tIN\tNSEC3\t1 1 5 30923C44C6CBBB8F P90DG1KE8QEAN0B01613LHQDG0SOJ0TA NS SOA TXT RRSIG DNSKEY NSEC3PARAM",
"localhost.dnssex.nl. IN NSEC www.dnssex.nl. A RRSIG NSEC": "localhost.dnssex.nl.\t3600\tIN\tNSEC\twww.dnssex.nl. A RRSIG NSEC",
"localhost.dnssex.nl. IN NSEC www.dnssex.nl. A RRSIG NSEC TYPE65534": "localhost.dnssex.nl.\t3600\tIN\tNSEC\twww.dnssex.nl. A RRSIG NSEC TYPE65534",
@ -398,16 +398,16 @@ func TestQuotes(t *testing.T) {
`t.example.com. IN TXT "a bc"`: "t.example.com.\t3600\tIN\tTXT\t\"a bc\"",
`t.example.com. IN TXT "a
bc"`: "t.example.com.\t3600\tIN\tTXT\t\"a\\010 bc\"",
`t.example.com. IN TXT ""`: "t.example.com.\t3600\tIN\tTXT\t\"\"",
`t.example.com. IN TXT "a"`: "t.example.com.\t3600\tIN\tTXT\t\"a\"",
`t.example.com. IN TXT "aa"`: "t.example.com.\t3600\tIN\tTXT\t\"aa\"",
`t.example.com. IN TXT "aaa" ;`: "t.example.com.\t3600\tIN\tTXT\t\"aaa\"",
`t.example.com. IN TXT "abc" "DEF"`: "t.example.com.\t3600\tIN\tTXT\t\"abc\" \"DEF\"",
`t.example.com. IN TXT "abc" ( "DEF" )`: "t.example.com.\t3600\tIN\tTXT\t\"abc\" \"DEF\"",
`t.example.com. IN TXT aaa ;`: "t.example.com.\t3600\tIN\tTXT\t\"aaa\"",
`t.example.com. IN TXT aaa aaa;`: "t.example.com.\t3600\tIN\tTXT\t\"aaa\" \"aaa\"",
`t.example.com. IN TXT aaa aaa`: "t.example.com.\t3600\tIN\tTXT\t\"aaa\" \"aaa\"",
`t.example.com. IN TXT aaa`: "t.example.com.\t3600\tIN\tTXT\t\"aaa\"",
`t.example.com. IN TXT ""`: "t.example.com.\t3600\tIN\tTXT\t\"\"",
`t.example.com. IN TXT "a"`: "t.example.com.\t3600\tIN\tTXT\t\"a\"",
`t.example.com. IN TXT "aa"`: "t.example.com.\t3600\tIN\tTXT\t\"aa\"",
`t.example.com. IN TXT "aaa" ;`: "t.example.com.\t3600\tIN\tTXT\t\"aaa\"",
`t.example.com. IN TXT "abc" "DEF"`: "t.example.com.\t3600\tIN\tTXT\t\"abc\" \"DEF\"",
`t.example.com. IN TXT "abc" ( "DEF" )`: "t.example.com.\t3600\tIN\tTXT\t\"abc\" \"DEF\"",
`t.example.com. IN TXT aaa ;`: "t.example.com.\t3600\tIN\tTXT\t\"aaa\"",
`t.example.com. IN TXT aaa aaa;`: "t.example.com.\t3600\tIN\tTXT\t\"aaa\" \"aaa\"",
`t.example.com. IN TXT aaa aaa`: "t.example.com.\t3600\tIN\tTXT\t\"aaa\" \"aaa\"",
`t.example.com. IN TXT aaa`: "t.example.com.\t3600\tIN\tTXT\t\"aaa\"",
"cid.urn.arpa. NAPTR 100 50 \"s\" \"z3950+I2L+I2C\" \"\" _z3950._tcp.gatech.edu.": "cid.urn.arpa.\t3600\tIN\tNAPTR\t100 50 \"s\" \"z3950+I2L+I2C\" \"\" _z3950._tcp.gatech.edu.",
"cid.urn.arpa. NAPTR 100 50 \"s\" \"rcds+I2C\" \"\" _rcds._udp.gatech.edu.": "cid.urn.arpa.\t3600\tIN\tNAPTR\t100 50 \"s\" \"rcds+I2C\" \"\" _rcds._udp.gatech.edu.",
"cid.urn.arpa. NAPTR 100 50 \"s\" \"http+I2L+I2C+I2R\" \"\" _http._tcp.gatech.edu.": "cid.urn.arpa.\t3600\tIN\tNAPTR\t100 50 \"s\" \"http+I2L+I2C+I2R\" \"\" _http._tcp.gatech.edu.",
@ -1567,3 +1567,17 @@ func TestBad(t *testing.T) {
}
}
}
func TestNULLRecord(t *testing.T) {
// packet captured from iodine
packet := `8116840000010001000000000569627a6c700474657374046d69656b026e6c00000a0001c00c000a0001000000000005497f000001`
data, _ := hex.DecodeString(packet)
msg := new(Msg)
err := msg.Unpack(data)
if err != nil {
t.Fatalf("Failed to unpack NULL record")
}
if _, ok := msg.Answer[0].(*NULL); !ok {
t.Fatalf("Expected packet to contain NULL record")
}
}

View File

@ -241,6 +241,17 @@ type ANY struct {
func (rr *ANY) String() string { return rr.Hdr.String() }
// NULL RR. See RFC 1035.
type NULL struct {
Hdr RR_Header
Anything string `dns:"any"`
}
func (rr *NULL) String() string {
// There is no presentation format; prefix string with a comment.
return ";" + rr.Hdr.String() + rr.Anything
}
// CNAME RR. See RFC 1034.
type CNAME struct {
Hdr RR_Header

View File

@ -193,6 +193,8 @@ func main() {
fallthrough
case st.Tag(i) == `dns:"hex"`:
o("l += len(rr.%s)/2 + 1\n")
case st.Tag(i) == `dns:"any"`:
o("l += len(rr.%s)\n")
case st.Tag(i) == `dns:"a"`:
o("l += net.IPv4len // %s\n")
case st.Tag(i) == `dns:"aaaa"`:

View File

@ -85,6 +85,8 @@ func isDuplicateRdata(r1, r2 RR) bool {
return isDuplicateNSEC3(r1.(*NSEC3), r2.(*NSEC3))
case TypeNSEC3PARAM:
return isDuplicateNSEC3PARAM(r1.(*NSEC3PARAM), r2.(*NSEC3PARAM))
case TypeNULL:
return isDuplicateNULL(r1.(*NULL), r2.(*NULL))
case TypeOPENPGPKEY:
return isDuplicateOPENPGPKEY(r1.(*OPENPGPKEY), r2.(*OPENPGPKEY))
case TypePTR:
@ -616,6 +618,13 @@ func isDuplicateNSEC3PARAM(r1, r2 *NSEC3PARAM) bool {
return true
}
func isDuplicateNULL(r1, r2 *NULL) bool {
if r1.Anything != r2.Anything {
return false
}
return true
}
func isDuplicateOPENPGPKEY(r1, r2 *OPENPGPKEY) bool {
if r1.PublicKey != r2.PublicKey {
return false

30
zmsg.go
View File

@ -802,6 +802,18 @@ func (rr *NSEC3PARAM) pack(msg []byte, off int, compression compressionMap, comp
return headerEnd, off, nil
}
func (rr *NULL) pack(msg []byte, off int, compression compressionMap, compress bool) (int, int, error) {
headerEnd, off, err := rr.Hdr.pack(msg, off, compression, compress)
if err != nil {
return headerEnd, off, err
}
off, err = packStringAny(rr.Anything, msg, off)
if err != nil {
return headerEnd, off, err
}
return headerEnd, off, nil
}
func (rr *OPENPGPKEY) pack(msg []byte, off int, compression compressionMap, compress bool) (int, int, error) {
headerEnd, off, err := rr.Hdr.pack(msg, off, compression, compress)
if err != nil {
@ -2549,6 +2561,23 @@ func unpackNSEC3PARAM(h RR_Header, msg []byte, off int) (RR, int, error) {
return rr, off, err
}
func unpackNULL(h RR_Header, msg []byte, off int) (RR, int, error) {
rr := new(NULL)
rr.Hdr = h
if noRdata(h) {
return rr, off, nil
}
var err error
rdStart := off
_ = rdStart
rr.Anything, off, err = unpackStringAny(msg, off, rdStart+int(rr.Hdr.Rdlength))
if err != nil {
return rr, off, err
}
return rr, off, err
}
func unpackOPENPGPKEY(h RR_Header, msg []byte, off int) (RR, int, error) {
rr := new(OPENPGPKEY)
rr.Hdr = h
@ -3448,6 +3477,7 @@ var typeToUnpack = map[uint16]func(RR_Header, []byte, int) (RR, int, error){
TypeNSEC: unpackNSEC,
TypeNSEC3: unpackNSEC3,
TypeNSEC3PARAM: unpackNSEC3PARAM,
TypeNULL: unpackNULL,
TypeOPENPGPKEY: unpackOPENPGPKEY,
TypeOPT: unpackOPT,
TypePTR: unpackPTR,

View File

@ -54,6 +54,7 @@ var TypeToRR = map[uint16]func() RR{
TypeNSEC: func() RR { return new(NSEC) },
TypeNSEC3: func() RR { return new(NSEC3) },
TypeNSEC3PARAM: func() RR { return new(NSEC3PARAM) },
TypeNULL: func() RR { return new(NULL) },
TypeOPENPGPKEY: func() RR { return new(OPENPGPKEY) },
TypeOPT: func() RR { return new(OPT) },
TypePTR: func() RR { return new(PTR) },
@ -209,6 +210,7 @@ func (rr *NSAPPTR) Header() *RR_Header { return &rr.Hdr }
func (rr *NSEC) Header() *RR_Header { return &rr.Hdr }
func (rr *NSEC3) Header() *RR_Header { return &rr.Hdr }
func (rr *NSEC3PARAM) Header() *RR_Header { return &rr.Hdr }
func (rr *NULL) Header() *RR_Header { return &rr.Hdr }
func (rr *OPENPGPKEY) Header() *RR_Header { return &rr.Hdr }
func (rr *OPT) Header() *RR_Header { return &rr.Hdr }
func (rr *PTR) Header() *RR_Header { return &rr.Hdr }
@ -473,6 +475,11 @@ func (rr *NSEC3PARAM) len(off int, compression map[string]struct{}) int {
l += len(rr.Salt) / 2
return l
}
func (rr *NULL) len(off int, compression map[string]struct{}) int {
l := rr.Hdr.len(off, compression)
l += len(rr.Anything)
return l
}
func (rr *OPENPGPKEY) len(off int, compression map[string]struct{}) int {
l := rr.Hdr.len(off, compression)
l += base64.StdEncoding.DecodedLen(len(rr.PublicKey))
@ -783,6 +790,9 @@ func (rr *NSEC3) copy() RR {
func (rr *NSEC3PARAM) copy() RR {
return &NSEC3PARAM{rr.Hdr, rr.Hash, rr.Flags, rr.Iterations, rr.SaltLength, rr.Salt}
}
func (rr *NULL) copy() RR {
return &NULL{rr.Hdr, rr.Anything}
}
func (rr *OPENPGPKEY) copy() RR {
return &OPENPGPKEY{rr.Hdr, rr.PublicKey}
}