]> git.ipfire.org Git - thirdparty/dnspython.git/commitdiff
Fix remaining canonical form problems, and add a test. [Issue #496]
authorBob Halley <halley@dnspython.org>
Mon, 1 Jun 2020 15:23:03 +0000 (08:23 -0700)
committerBob Halley <halley@dnspython.org>
Mon, 1 Jun 2020 15:23:03 +0000 (08:23 -0700)
dns/rdtypes/ANY/NSEC.py
dns/rdtypes/IN/KX.py
dns/rdtypes/IN/NAPTR.py
dns/rdtypes/IN/PX.py
dns/rdtypes/IN/SRV.py
tests/test_rdata.py

index 63203b5d42292b2cef5f3d9d68b187f46ff034c2..7da00e9ea141c40aa78103e2ca99e3edf4845399 100644 (file)
@@ -15,6 +15,7 @@
 # ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT
 # OF OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
 
+import io
 import struct
 
 import dns.exception
@@ -92,6 +93,14 @@ class NSEC(dns.rdata.Rdata):
             file.write(struct.pack('!BB', window, len(bitmap)))
             file.write(bitmap)
 
+    def to_digestable(self, origin=None):
+        file = io.BytesIO()
+        file.write(self.next.to_digestable(origin))
+        for (window, bitmap) in self.windows:
+            file.write(struct.pack('!BB', window, len(bitmap)))
+            file.write(bitmap)
+        return file.getvalue()
+
     @classmethod
     def from_wire(cls, rdclass, rdtype, wire, current, rdlen, origin=None):
         (next, cused) = dns.name.from_wire(wire[: current + rdlen], current)
index 1318a582e70320f9369d6bc7fcea9df05834f10e..ebf8fd77debdeb849e302eaacc3df05b4ea5dc7a 100644 (file)
@@ -18,6 +18,6 @@
 import dns.rdtypes.mxbase
 
 
-class KX(dns.rdtypes.mxbase.UncompressedMX):
+class KX(dns.rdtypes.mxbase.UncompressedDowncasingMX):
 
     """KX record"""
index 9668dce22359073ace90f9a0025d1a21e2075cb4..c68efc3845e1442afdded85a1420c0c8df9732dd 100644 (file)
@@ -15,6 +15,7 @@
 # ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT
 # OF OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
 
+import io
 import struct
 
 import dns.exception
@@ -84,6 +85,15 @@ class NAPTR(dns.rdata.Rdata):
         _write_string(file, self.regexp)
         self.replacement.to_wire(file, compress, origin)
 
+    def to_digestable(self, origin=None):
+        file = io.BytesIO()
+        two_ints = struct.pack("!HH", self.order, self.preference)
+        file.write(two_ints)
+        _write_string(file, self.flags)
+        _write_string(file, self.service)
+        _write_string(file, self.regexp)
+        return file.getvalue() + self.replacement.to_digestable(origin)
+
     @classmethod
     def from_wire(cls, rdclass, rdtype, wire, current, rdlen, origin=None):
         (order, preference) = struct.unpack('!HH', wire[current: current + 4])
index 109a873e712694f08cbfb8b66deb9fa59cef8c37..e11f26554838191a4c9f7a4f1dc37c39ae906583 100644 (file)
@@ -56,6 +56,11 @@ class PX(dns.rdata.Rdata):
         self.map822.to_wire(file, None, origin)
         self.mapx400.to_wire(file, None, origin)
 
+    def to_digestable(self, origin=None):
+        return struct.pack("!H", self.preference) + \
+            self.map822.to_digestable(origin) + \
+            self.mapx400.to_digestable(origin)
+
     @classmethod
     def from_wire(cls, rdclass, rdtype, wire, current, rdlen, origin=None):
         (preference, ) = struct.unpack('!H', wire[current: current + 2])
index bfd25ea6f9774c04cbed1f7599d779e3a7f43bdb..8c08f0b01e3fafbd8fcbd4d6c010112c33be76a4 100644 (file)
@@ -59,7 +59,6 @@ class SRV(dns.rdata.Rdata):
         self.target.to_wire(file, compress, origin)
 
     def to_digestable(self, origin=None):
-        # TODO how to avoid code duplication here? This is mostly identical to self.to_wire.
         f = io.BytesIO()
         f.write(struct.pack("!HHH", self.priority, self.weight, self.port))
         f.write(self.target.to_digestable(origin))
index b994a6256718b0fcb1e93af7ed9b498f4f160b69..a88b977d14dd1addf6170e7eaf6f1ac61a2efdd7 100644 (file)
 # ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT
 # OF OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
 
+import io
 import unittest
 
 import dns.name
 import dns.rdata
 import dns.rdataclass
+import dns.rdataset
 import dns.rdatatype
 
 import tests.stxt_module
@@ -128,5 +130,48 @@ class RdataTestCase(unittest.TestCase):
                                     idna_codec=dns.name.IDNA_2008)
         self.assertEqual(str(rdata.target), 'xn--knigsgchen-b4a3dun')
 
+    def test_digestable_downcasing(self):
+        # Make sure all the types listed in RFC 4034 section 6.2 are
+        # downcased properly, except for:
+        #
+        #   types we don't implement:  MD, MF, MB, MG, MR, MINFO, SIG,
+        #                              NXT, A6
+        #
+        #   types that don't have names: HINFO
+        #
+        #   types where the canonical form isn't relevant: RRSIG
+        #
+        cases = [
+            ('SOA', 'NAME NAME 1 2 3 4 5'),
+            ('AFSDB', '0 NAME'),
+            ('CNAME', 'NAME'),
+            ('DNAME', 'NAME'),
+            ('KX', '10 NAME'),
+            ('MX', '10 NAME'),
+            ('NS', 'NAME'),
+            ('NSEC', 'NAME A'),
+            ('NAPTR', '0 0 a B c NAME'),
+            ('PTR', 'NAME'),
+            ('PX', '65535 NAME NAME'),
+            ('RP', 'NAME NAME'),
+            ('RT', '0 NAME'),
+            ('SRV', '0 0 0 NAME'),
+        ]
+        for rdtype, text in cases:
+            upper_origin = dns.name.from_text('EXAMPLE')
+            lower_origin = dns.name.from_text('example')
+            canonical_text = text.replace('NAME', 'name')
+            rdata = dns.rdata.from_text(dns.rdataclass.IN, rdtype, text,
+                                        origin=upper_origin, relativize=False)
+            canonical_rdata = dns.rdata.from_text(dns.rdataclass.IN, rdtype,
+                                                  canonical_text,
+                                                  origin=lower_origin,
+                                                  relativize=False)
+            digestable_wire = rdata.to_digestable()
+            f = io.BytesIO()
+            canonical_rdata.to_wire(f)
+            expected_wire = f.getvalue()
+            self.assertEqual(digestable_wire, expected_wire)
+
 if __name__ == '__main__':
     unittest.main()