]> git.ipfire.org Git - thirdparty/dnspython.git/commitdiff
Add support for TKEY RR type
authorNick Hall <nick.hall@deshaw.com>
Sun, 3 Feb 2019 14:02:49 +0000 (14:02 +0000)
committerNick Hall <nick.hall@deshaw.com>
Fri, 7 Aug 2020 23:25:22 +0000 (00:25 +0100)
dns/rdtypes/ANY/TKEY.py [new file with mode: 0644]
dns/rdtypes/ANY/__init__.py
tests/test_rdtypeanytkey.py [new file with mode: 0644]

diff --git a/dns/rdtypes/ANY/TKEY.py b/dns/rdtypes/ANY/TKEY.py
new file mode 100644 (file)
index 0000000..959e798
--- /dev/null
@@ -0,0 +1,117 @@
+# Copyright (C) Dnspython Contributors, see LICENSE for text of ISC license
+
+# Copyright (C) 2004-2007, 2009-2011 Nominum, Inc.
+#
+# Permission to use, copy, modify, and distribute this software and its
+# documentation for any purpose with or without fee is hereby granted,
+# provided that the above copyright notice and this permission notice
+# appear in all copies.
+#
+# THE SOFTWARE IS PROVIDED "AS IS" AND NOMINUM DISCLAIMS ALL WARRANTIES
+# WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF
+# MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL NOMINUM BE LIABLE FOR
+# ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES
+# WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN
+# ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT
+# OF OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
+
+import base64
+import struct
+
+import dns.dnssec
+import dns.exception
+import dns.rdata
+
+
+class TKEY(dns.rdata.Rdata):
+
+    """TKEY Record"""
+
+    __slots__ = ['algorithm', 'inception', 'expiration', 'mode', 'error',
+                 'key', 'other']
+
+    def __init__(self, rdclass, rdtype, algorithm, inception, expiration,
+                 mode, error, key, other=b''):
+        super().__init__(rdclass, rdtype)
+        object.__setattr__(self, 'algorithm', algorithm)
+        object.__setattr__(self, 'inception', inception)
+        object.__setattr__(self, 'expiration', expiration)
+        object.__setattr__(self, 'mode', mode)
+        object.__setattr__(self, 'error', error)
+        object.__setattr__(self, 'key', dns.rdata._constify(key))
+        object.__setattr__(self, 'other', dns.rdata._constify(other))
+
+    def to_text(self, origin=None, relativize=True, **kw):
+        _algorithm = self.algorithm.choose_relativity(origin, relativize)
+        text = '%s %u %u %u %u %s' % (str(_algorithm), self.inception,
+                                      self.expiration, self.mode, self.error,
+                                      dns.rdata._base64ify(self.key, 0))
+        if len(self.other):
+            text += ' %s' % (dns.rdata._base64ify(self.other, 0))
+
+        return text
+
+    @classmethod
+    def from_text(cls, rdclass, rdtype, tok, origin=None, relativize=True,
+                  relativize_to=None):
+        algorithm = tok.get_name(relativize=False)
+        inception = tok.get_uint32()
+        expiration = tok.get_uint32()
+        mode = tok.get_uint16()
+        error = tok.get_uint16()
+        key_b64 = tok.get_string().encode()
+        key = base64.b64decode(key_b64)
+        other_b64 = tok.concatenate_remaining_identifiers().encode()
+        other = base64.b64decode(other_b64)
+
+        return cls(rdclass, rdtype, algorithm, inception, expiration, mode,
+                   error, key, other)
+
+    def _to_wire(self, file, compress=None, origin=None, canonicalize=False):
+        self.algorithm.to_wire(file, compress, origin)
+        file.write(struct.pack("!IIHH", self.inception, self.expiration,
+                               self.mode, self.error))
+        file.write(struct.pack("!H", len(self.key)))
+        file.write(self.key)
+        file.write(struct.pack("!H", len(self.other)))
+        if len(self.other):
+            file.write(self.other)
+
+    @classmethod
+    def from_wire_parser(cls, rdclass, rdtype, parser, origin=None):
+        algorithm = parser.get_name(origin)
+        inception, expiration, mode, error = parser.get_struct("!IIHH")
+        key = parser.get_counted_bytes(2)
+        other = parser.get_counted_bytes(2)
+
+        return cls(rdclass, rdtype, algorithm, inception, expiration, mode,
+                   error, key, other)
+
+    # Constants for the mode field - from RFC 2930:
+    # 2.5 The Mode Field
+    #
+    #    The mode field specifies the general scheme for key agreement or
+    #    the purpose of the TKEY DNS message.  Servers and resolvers
+    #    supporting this specification MUST implement the Diffie-Hellman key
+    #    agreement mode and the key deletion mode for queries.  All other
+    #    modes are OPTIONAL.  A server supporting TKEY that receives a TKEY
+    #    request with a mode it does not support returns the BADMODE error.
+    #    The following values of the Mode octet are defined, available, or
+    #    reserved:
+    #
+    #          Value    Description
+    #          -----    -----------
+    #           0        - reserved, see section 7
+    #           1       server assignment
+    #           2       Diffie-Hellman exchange
+    #           3       GSS-API negotiation
+    #           4       resolver assignment
+    #           5       key deletion
+    #          6-65534   - available, see section 7
+    #          65535     - reserved, see section 7
+    SERVER_ASSIGNMENT = 1
+    DIFFIE_HELLMAN_EXCHANGE = 2
+    GSSAPI_NEGOTIATION = 3
+    RESOLVER_ASSIGNMENT = 4
+    KEY_DELETION = 5
+
index ea704c8619f0218c605d7419008f82536b6c8219..0d1a7406b97bff87ddd9c4c2f91f0af67b9caffe 100644 (file)
@@ -51,6 +51,7 @@ __all__ = [
     'SOA',
     'SPF',
     'SSHFP',
+    'TKEY',
     'TLSA',
     'TSIG',
     'TXT',
diff --git a/tests/test_rdtypeanytkey.py b/tests/test_rdtypeanytkey.py
new file mode 100644 (file)
index 0000000..3a3ca57
--- /dev/null
@@ -0,0 +1,96 @@
+# -*- coding: utf-8
+# Copyright (C) Dnspython Contributors, see LICENSE for text of ISC license
+
+# Copyright (C) 2003-2007, 2009-2011 Nominum, Inc.
+#
+# Permission to use, copy, modify, and distribute this software and its
+# documentation for any purpose with or without fee is hereby granted,
+# provided that the above copyright notice and this permission notice
+# appear in all copies.
+#
+# THE SOFTWARE IS PROVIDED "AS IS" AND NOMINUM DISCLAIMS ALL WARRANTIES
+# WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF
+# MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL NOMINUM BE LIABLE FOR
+# ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES
+# WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN
+# ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT
+# OF OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
+
+import unittest
+import base64
+
+import dns.name
+import dns.zone
+import dns.rdtypes.ANY.TKEY
+from dns.rdataclass import RdataClass
+from dns.rdatatype import RdataType
+
+
+class RdtypeAnyTKeyTestCase(unittest.TestCase):
+    tkey_rdata_text = 'gss-tsig. 1594203795 1594206664 3 0 KEYKEYKEYKEYKEYKEYKEYKEYKEYKEYKEYKEY OTHEROTHEROTHEROTHEROTHEROTHEROT'
+    tkey_rdata_text_no_other = 'gss-tsig. 1594203795 1594206664 3 0 KEYKEYKEYKEYKEYKEYKEYKEYKEYKEYKEYKEY'
+
+    def testTextOptionalData(self):
+        # construct the rdata from text and extract the TKEY
+        tkey = dns.rdata.from_text(
+            RdataClass.ANY, RdataType.TKEY,
+            RdtypeAnyTKeyTestCase.tkey_rdata_text, origin='.')
+        self.assertEqual(type(tkey), dns.rdtypes.ANY.TKEY.TKEY)
+
+        # go to text and compare
+        tkey_out_text = tkey.to_text(relativize=False)
+        self.assertEqual(tkey_out_text,
+                         RdtypeAnyTKeyTestCase.tkey_rdata_text)
+
+    def testTextNoOptionalData(self):
+        # construct the rdata from text and extract the TKEY
+        tkey = dns.rdata.from_text(
+            RdataClass.ANY, RdataType.TKEY,
+            RdtypeAnyTKeyTestCase.tkey_rdata_text_no_other, origin='.')
+        self.assertEqual(type(tkey), dns.rdtypes.ANY.TKEY.TKEY)
+
+        # go to text and compare
+        tkey_out_text = tkey.to_text(relativize=False)
+        self.assertEqual(tkey_out_text,
+                         RdtypeAnyTKeyTestCase.tkey_rdata_text_no_other)
+
+    def testWireOptionalData(self):
+        key = base64.b64decode('KEYKEYKEYKEYKEYKEYKEYKEYKEYKEYKEYKEY')
+        other = base64.b64decode('OTHEROTHEROTHEROTHEROTHEROTHEROT')
+
+        # construct the TKEY and compare the text output
+        tkey = dns.rdtypes.ANY.TKEY.TKEY(dns.rdataclass.ANY,
+                                         dns.rdatatype.TKEY,
+                                         dns.name.from_text('gss-tsig.'),
+                                         1594203795, 1594206664,
+                                         3, 0, key, other)
+        self.assertEqual(tkey.to_text(relativize=False),
+                         RdtypeAnyTKeyTestCase.tkey_rdata_text)
+
+        # go to/from wire and compare the text output
+        wire = tkey.to_wire()
+        tkey_out_wire = dns.rdata.from_wire(dns.rdataclass.ANY,
+                                            dns.rdatatype.TKEY,
+                                            wire, 0, len(wire))
+        self.assertEqual(tkey_out_wire.to_text(relativize=False),
+                         RdtypeAnyTKeyTestCase.tkey_rdata_text)
+
+    def testWireNoOptionalData(self):
+        key = base64.b64decode('KEYKEYKEYKEYKEYKEYKEYKEYKEYKEYKEYKEY')
+
+        # construct the TKEY with no 'other' data and compare the text output
+        tkey = dns.rdtypes.ANY.TKEY.TKEY(dns.rdataclass.ANY,
+                                         dns.rdatatype.TKEY,
+                                         dns.name.from_text('gss-tsig.'),
+                                         1594203795, 1594206664,
+                                         3, 0, key)
+        self.assertEqual(tkey.to_text(relativize=False),
+                         RdtypeAnyTKeyTestCase.tkey_rdata_text_no_other)
+
+        # go to/from wire and compare the text output
+        wire = tkey.to_wire()
+        tkey_out_wire = dns.rdata.from_wire(dns.rdataclass.ANY,
+                                            dns.rdatatype.TKEY,
+                                            wire, 0, len(wire))
+        self.assertEqual(tkey_out_wire.to_text(relativize=False),
+                         RdtypeAnyTKeyTestCase.tkey_rdata_text_no_other)