diff --git a/dns_test.go b/dns_test.go index 5835c13d..3ff83606 100644 --- a/dns_test.go +++ b/dns_test.go @@ -1,6 +1,7 @@ package dns import ( + "bytes" "encoding/hex" "net" "testing" @@ -317,8 +318,9 @@ func TestNoRdataPack(t *testing.T) { func TestNoRdataUnpack(t *testing.T) { data := make([]byte, 1024) for typ, fn := range TypeToRR { - if typ == TypeSOA || typ == TypeTSIG { + if typ == TypeSOA || typ == TypeTSIG || typ == TypeTKEY { // SOA, TSIG will not be seen (like this) in dyn. updates? + // TKEY requires length fields to be present for the Key and OtherData fields continue } r := fn() @@ -405,3 +407,52 @@ func TestMsgPackBuffer(t *testing.T) { } } } + +// Make sure we can decode a TKEY packet from the string, modify the RR, and then pack it again. +func TestTKEY(t *testing.T) { + // An example TKEY RR captured. There is no known accepted standard text format for a TKEY + // record so we do this from a hex string instead of from a text readable string. + tkeyStr := "0737362d6d732d370932322d3332633233332463303439663961662d633065612d313165372d363839362d6463333937396666656666640000f900ff0000000000d2086773732d747369670059fd01f359fe53730003000000b8a181b53081b2a0030a0100a10b06092a864882f712010202a2819d04819a60819706092a864886f71201020202006f8187308184a003020105a10302010fa2783076a003020112a26f046db29b1b1d2625da3b20b49dafef930dd1e9aad335e1c5f45dcd95e0005d67a1100f3e573d70506659dbed064553f1ab890f68f65ae10def0dad5b423b39f240ebe666f2886c5fe03819692d29182bbed87b83e1f9d16b7334ec16a3c4fc5ad4a990088e0be43f0c6957916f5fe60000" + tkeyBytes, err := hex.DecodeString(tkeyStr) + if err != nil { + t.Fatal("unable to decode TKEY string ", err) + } + // Decode the RR + rr, tkeyLen, unPackErr := UnpackRR(tkeyBytes, 0) + if unPackErr != nil { + t.Fatal("unable to decode TKEY RR", unPackErr) + } + // make space for it with some fudge room + msg := make([]byte, tkeyLen+1000) + offset, packErr := PackRR(rr, msg, 0, nil, false) + if packErr != nil { + t.Fatal("unable to pack TKEY RR", packErr) + } + if offset != len(tkeyBytes) { + t.Fatalf("mismatched TKEY RR size %d != %d", len(tkeyBytes), offset) + } + if bytes.Compare(tkeyBytes, msg[0:offset]) != 0 { + t.Fatal("mismatched TKEY data after rewriting bytes") + } + t.Logf("got TKEY of: " + rr.String()) + // Now add some bytes to this and make sure we can encode OtherData properly + tkey := rr.(*TKEY) + tkey.OtherData = "abcd" + tkey.OtherLen = 2 + offset, packErr = PackRR(tkey, msg, 0, nil, false) + if packErr != nil { + t.Fatal("unable to pack TKEY RR after modification", packErr) + } + if offset != (len(tkeyBytes) + 2) { + t.Fatalf("mismatched TKEY RR size %d != %d", offset, len(tkeyBytes)+2) + } + t.Logf("modified to TKEY of: " + rr.String()) + + // Make sure we can parse our string output + tkey.Hdr.Class = ClassINET // https://github.com/miekg/dns/issues/577 + newRR, newError := NewRR(tkey.String()) + if newError != nil { + t.Fatalf("unable to parse TKEY string: %s", newError) + } + t.Log("got reparsed TKEY of newRR: " + newRR.String()) +} diff --git a/scan_rr.go b/scan_rr.go index 2be6e090..26af0f0c 100644 --- a/scan_rr.go +++ b/scan_rr.go @@ -2084,6 +2084,51 @@ func setCAA(h RR_Header, c chan lex, o, f string) (RR, *ParseError, string) { return rr, nil, c1 } +func setTKEY(h RR_Header, c chan lex, o, f string) (RR, *ParseError, string) { + rr := new(TKEY) + rr.Hdr = h + + l := <-c + + // Algorithm + if l.value != zString { + return nil, &ParseError{f, "bad TKEY algorithm", l}, "" + } + rr.Algorithm = l.token + <-c // zBlank + + // Get the key length and key values + l = <-c + i, err := strconv.ParseUint(l.token, 10, 8) + if err != nil || l.err { + return nil, &ParseError{f, "bad TKEY key length", l}, "" + } + rr.KeySize = uint16(i) + <-c // zBlank + l = <-c + if l.value != zString { + return nil, &ParseError{f, "bad TKEY key", l}, "" + } + rr.Key = l.token + <-c // zBlank + + // Get the otherdata length and string data + l = <-c + i, err = strconv.ParseUint(l.token, 10, 8) + if err != nil || l.err { + return nil, &ParseError{f, "bad TKEY otherdata length", l}, "" + } + rr.OtherLen = uint16(i) + <-c // zBlank + l = <-c + if l.value != zString { + return nil, &ParseError{f, "bad TKEY otherday", l}, "" + } + rr.OtherData = l.token + + return rr, nil, "" +} + var typeToparserFunc = map[uint16]parserFunc{ TypeAAAA: {setAAAA, false}, TypeAFSDB: {setAFSDB, false}, @@ -2150,4 +2195,5 @@ var typeToparserFunc = map[uint16]parserFunc{ TypeUINFO: {setUINFO, true}, TypeURI: {setURI, true}, TypeX25: {setX25, false}, + TypeTKEY: {setTKEY, true}, } diff --git a/types.go b/types.go index fe172daa..a779ca8a 100644 --- a/types.go +++ b/types.go @@ -1013,14 +1013,18 @@ type TKEY struct { Mode uint16 Error uint16 KeySize uint16 - Key string + Key string `dns:"size-hex:KeySize"` OtherLen uint16 - OtherData string + OtherData string `dns:"size-hex:OtherLen"` } +// TKEY has no official presentation format, but this will suffice. func (rr *TKEY) String() string { - // It has no presentation format - return "" + s := "\n;; TKEY PSEUDOSECTION:\n" + s += rr.Hdr.String() + " " + rr.Algorithm + " " + + strconv.Itoa(int(rr.KeySize)) + " " + rr.Key + " " + + strconv.Itoa(int(rr.OtherLen)) + " " + rr.OtherData + return s } // RFC3597 represents an unknown/generic RR. See RFC 3597. diff --git a/zmsg.go b/zmsg.go index d60023dd..969977f8 100644 --- a/zmsg.go +++ b/zmsg.go @@ -1325,7 +1325,7 @@ func (rr *TKEY) pack(msg []byte, off int, compression map[string]int, compress b if err != nil { return off, err } - off, err = packString(rr.Key, msg, off) + off, err = packStringHex(rr.Key, msg, off) if err != nil { return off, err } @@ -1333,7 +1333,7 @@ func (rr *TKEY) pack(msg []byte, off int, compression map[string]int, compress b if err != nil { return off, err } - off, err = packString(rr.OtherData, msg, off) + off, err = packStringHex(rr.OtherData, msg, off) if err != nil { return off, err } @@ -3318,13 +3318,10 @@ func unpackTKEY(h RR_Header, msg []byte, off int) (RR, int, error) { if off == len(msg) { return rr, off, nil } - rr.Key, off, err = unpackString(msg, off) + rr.Key, off, err = unpackStringHex(msg, off, off+int(rr.KeySize)) if err != nil { return rr, off, err } - if off == len(msg) { - return rr, off, nil - } rr.OtherLen, off, err = unpackUint16(msg, off) if err != nil { return rr, off, err @@ -3332,7 +3329,7 @@ func unpackTKEY(h RR_Header, msg []byte, off int) (RR, int, error) { if off == len(msg) { return rr, off, nil } - rr.OtherData, off, err = unpackString(msg, off) + rr.OtherData, off, err = unpackStringHex(msg, off, off+int(rr.OtherLen)) if err != nil { return rr, off, err }