]> git.ipfire.org Git - thirdparty/dnspython.git/commitdiff
Fix #698 and #702, problems caused by _cmp() giving the wrong
authorBob Halley <halley@dnspython.org>
Sun, 10 Oct 2021 23:53:26 +0000 (16:53 -0700)
committerBob Halley <halley@dnspython.org>
Mon, 11 Oct 2021 22:01:03 +0000 (15:01 -0700)
result in certain comparisons of rdata with relative and absolute
names.

dns/message.py
dns/rdata.py
dns/zone.py
tests/test_rdata.py
tests/test_zonedigest.py

index 6fa90ca5bf4ab79eec8cc43d4a6dd029f534450f..2a7565a03c629b8b8473518e78e45a412e9c471a 100644 (file)
@@ -236,8 +236,7 @@ class Message:
         return not self.__eq__(other)
 
     def is_response(self, other):
-        """Is *other*, also a ``dns.message.Message``, a response to this
-        message?
+        """Is *other* a response this message?
 
         Returns a ``bool``.
         """
index 0831c414c440dc79e133673eb8bae1e5616316a3..8a79de7de9e1ec602600513e9d259f0f96e35f71 100644 (file)
@@ -39,6 +39,14 @@ import dns.ttl
 _chunksize = 32
 
 
+class NoRelativeRdataOrdering(dns.exception.DNSException):
+    """An attempt was made to do an ordered comparison of one or more
+    rdata with relative names.  The only reliable way of sorting rdata
+    is to use non-relativized rdata.
+
+    """
+
+
 def _wordbreak(data, chunksize=_chunksize, separator=b' '):
     """Break a binary string into chunks of chunksize characters separated by
     a space.
@@ -234,10 +242,12 @@ class Rdata:
 
         Return < 0 if self < other in the DNSSEC ordering, 0 if self
         == other, and > 0 if self > other.
-
         """
-        our = self.to_digestable(dns.name.root)
-        their = other.to_digestable(dns.name.root)
+        try:
+            our = self.to_digestable()
+            their = other.to_digestable()
+        except dns.name.NeedAbsoluteNameOrOrigin:
+            raise NoRelativeRdataOrdering
         if our == their:
             return 0
         elif our > their:
@@ -250,14 +260,28 @@ class Rdata:
             return False
         if self.rdclass != other.rdclass or self.rdtype != other.rdtype:
             return False
-        return self._cmp(other) == 0
+        our_relative = False
+        their_relative = False
+        try:
+            our = self.to_digestable()
+        except dns.name.NeedAbsoluteNameOrOrigin:
+            our = self.to_digestable(dns.name.root)
+            our_relative = True
+        try:
+            their = other.to_digestable()
+        except dns.name.NeedAbsoluteNameOrOrigin:
+            their = other.to_digestable(dns.name.root)
+            their_relative = True
+        if our_relative != their_relative:
+            return False
+        return our == their
 
     def __ne__(self, other):
         if not isinstance(other, Rdata):
             return True
         if self.rdclass != other.rdclass or self.rdtype != other.rdtype:
             return True
-        return self._cmp(other) != 0
+        return not self.__eq__(other)
 
     def __lt__(self, other):
         if not isinstance(other, Rdata) or \
index 9c3204b366c84b12ce4d94e6fce284f5c8c8f29a..d15492870b886e7f16549ca94087b9e8ff678842 100644 (file)
@@ -733,10 +733,11 @@ class Zone(dns.transaction.TransactionManager):
                     continue
                 rrfixed = struct.pack('!HHI', rdataset.rdtype,
                                       rdataset.rdclass, rdataset.ttl)
-                for rr in sorted(rdataset):
-                    rrdata = rr.to_digestable(self.origin)
-                    rrlen = struct.pack('!H', len(rrdata))
-                    hasher.update(rrnamebuf + rrfixed + rrlen + rrdata)
+                rdatas = [rdata.to_digestable(self.origin)
+                          for rdata in rdataset]
+                for rdata in sorted(rdatas):
+                    rrlen = struct.pack('!H', len(rdata))
+                    hasher.update(rrnamebuf + rrfixed + rrlen + rdata)
         return hasher.digest()
 
     def compute_digest(self, hash_algorithm, scheme=DigestScheme.SIMPLE):
index 05ec6caff4de6d12a0f312e2e84936ad3ea5678e..ea3e3da727168cca238dea1140d1bd1350972384 100644 (file)
@@ -696,6 +696,52 @@ class RdataTestCase(unittest.TestCase):
                     rr = dns.rdata.from_text('IN', 'DNSKEY', input_variation)
                     new_text = rr.to_text(chunksize=chunksize)
                     self.assertEqual(output, new_text)
+                    
+    def test_relative_vs_absolute_compare(self):
+        r1 = dns.rdata.from_text(dns.rdataclass.IN, dns.rdatatype.NS, 'www.')
+        r2 = dns.rdata.from_text(dns.rdataclass.IN, dns.rdatatype.NS, 'www')
+        self.assertFalse(r1 == r2)
+        self.assertTrue(r1 != r2)
+        def bad1():
+            r1 < r2
+        def bad2():
+            r1 <= r2
+        def bad3():
+            r1 > r2
+        def bad4():
+            r1 >= r2
+        self.assertRaises(dns.rdata.NoRelativeRdataOrdering, bad1)
+        self.assertRaises(dns.rdata.NoRelativeRdataOrdering, bad2)
+        self.assertRaises(dns.rdata.NoRelativeRdataOrdering, bad3)
+        self.assertRaises(dns.rdata.NoRelativeRdataOrdering, bad4)
+
+    def test_absolute_vs_absolute_compare(self):
+        r1 = dns.rdata.from_text(dns.rdataclass.IN, dns.rdatatype.NS, 'www.')
+        r2 = dns.rdata.from_text(dns.rdataclass.IN, dns.rdatatype.NS, 'xxx.')
+        self.assertFalse(r1 == r2)
+        self.assertTrue(r1 != r2)
+        self.assertTrue(r1 < r2)
+        self.assertTrue(r1 <= r2)
+        self.assertFalse(r1 > r2)
+        self.assertFalse(r1 >= r2)
+
+    def test_relative_vs_relative_compare(self):
+        r1 = dns.rdata.from_text(dns.rdataclass.IN, dns.rdatatype.NS, 'www')
+        r2 = dns.rdata.from_text(dns.rdataclass.IN, dns.rdatatype.NS, 'xxx')
+        self.assertFalse(r1 == r2)
+        self.assertTrue(r1 != r2)
+        def bad1():
+            r1 < r2
+        def bad2():
+            r1 <= r2
+        def bad3():
+            r1 > r2
+        def bad4():
+            r1 >= r2
+        self.assertRaises(dns.rdata.NoRelativeRdataOrdering, bad1)
+        self.assertRaises(dns.rdata.NoRelativeRdataOrdering, bad2)
+        self.assertRaises(dns.rdata.NoRelativeRdataOrdering, bad3)
+        self.assertRaises(dns.rdata.NoRelativeRdataOrdering, bad4)
 
 
 class UtilTestCase(unittest.TestCase):
index f98e5f7804bf4e57085d3e41b782ed6c6a116f02..d94be2491b0f9d2de7803badfc89510c12a9a344 100644 (file)
@@ -176,3 +176,18 @@ class ZoneDigestTestCase(unittest.TestCase):
         with self.assertRaises(dns.exception.SyntaxError):
             dns.rdata.from_text('IN', 'ZONEMD', '100 1 0 ' + self.sha384_hash)
 
+    sorting_zone = textwrap.dedent('''
+    @  86400  IN  SOA     ns1 admin 2018031900 (
+                                     1800 900 604800 86400 )
+              86400  IN  NS      ns1
+              86400  IN  NS      ns2
+              86400  IN  RP      n1.example. a.
+              86400  IN  RP      n1. b.
+    ''')
+    
+    def test_relative_zone_sorting(self):
+        z1 = dns.zone.from_text(self.sorting_zone, 'example.', relativize=True)
+        z2 = dns.zone.from_text(self.sorting_zone, 'example.', relativize=False)
+        zmd1 = z1.compute_digest(dns.zone.DigestHashAlgorithm.SHA384)
+        zmd2 = z2.compute_digest(dns.zone.DigestHashAlgorithm.SHA384)
+        self.assertEqual(zmd1, zmd2)