]> git.ipfire.org Git - thirdparty/dnspython.git/commitdiff
Allow relative rdata comparisons for now, but disallow in the future.
authorBob Halley <halley@dnspython.org>
Thu, 14 Oct 2021 16:14:23 +0000 (09:14 -0700)
committerBob Halley <halley@dnspython.org>
Thu, 14 Oct 2021 16:14:23 +0000 (09:14 -0700)
dns/rdata.py
tests/test_rdata.py

index 8a79de7de9e1ec602600513e9d259f0f96e35f71..1917ecd48f3f59760a2e8839137cec8d8dcdb715 100644 (file)
@@ -38,6 +38,14 @@ import dns.ttl
 
 _chunksize = 32
 
+# We currently allow comparisons for rdata with relative names for backwards
+# compatibility, but in the future we will not, as these kinds of comparisons
+# can lead to subtle bugs if code is not carefully written.
+#
+# This switch allows the future behavior to be turned on so code can be
+# tested with it.
+_allow_relative_comparisons = True
+
 
 class NoRelativeRdataOrdering(dns.exception.DNSException):
     """An attempt was made to do an ordered comparison of one or more
@@ -240,13 +248,39 @@ class Rdata:
         """Compare an rdata with another rdata of the same rdtype and
         rdclass.
 
-        Return < 0 if self < other in the DNSSEC ordering, 0 if self
-        == other, and > 0 if self > other.
+        For rdata with only absolute names:
+            Return < 0 if self < other in the DNSSEC ordering, 0 if self
+            == other, and > 0 if self > other.
+        For rdata with at least one relative names:
+            The rdata sorts before any rdata with only absolute names.
+            When compared with another relative rdata, all names are
+            made absolute as if they were relative to the root, as the
+            proper origin is not available.  While this creates a stable
+            ordering, it is NOT guaranteed to be the DNSSEC ordering.
+            In the future, all ordering comparisons for rdata with
+            relative names will be disallowed.
         """
         try:
             our = self.to_digestable()
+            our_relative = False
+        except dns.name.NeedAbsoluteNameOrOrigin:
+            our = self.to_digestable(dns.name.root)
+            our_relative = True
+        try:
             their = other.to_digestable()
+            their_relative = False
         except dns.name.NeedAbsoluteNameOrOrigin:
+            their = other.to_digestable(dns.name.root)
+            their_relative = True
+        if _allow_relative_comparisons:
+            if our_relative != their_relative:
+                # For the purpose of comparison, all rdata with at least one
+                # relative name is less than an rdata with only absolute names.
+                if our_relative:
+                    return -1
+                else:
+                    return 1
+        else:
             raise NoRelativeRdataOrdering
         if our == their:
             return 0
index ea3e3da727168cca238dea1140d1bd1350972384..f87ff5608af4c02520679512a7ca813cbb165d44 100644 (file)
@@ -697,23 +697,47 @@ class RdataTestCase(unittest.TestCase):
                     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_relative_vs_absolute_compare_unstrict(self):
+        try:
+            saved = dns.rdata._allow_relative_comparisons
+            dns.rdata._allow_relative_comparisons = True
+            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)
+            self.assertFalse(r1 < r2)
+            self.assertFalse(r1 <= r2)
+            self.assertTrue(r1 > r2)
+            self.assertTrue(r1 >= r2)
+            self.assertTrue(r2 < r1)
+            self.assertTrue(r2 <= r1)
+            self.assertFalse(r2 > r1)
+            self.assertFalse(r2 >= r1)
+        finally:
+            dns.rdata._allow_relative_comparisons = saved
+
+    def test_relative_vs_absolute_compare_strict(self):
+        try:
+            saved = dns.rdata._allow_relative_comparisons
+            dns.rdata._allow_relative_comparisons = False
+            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)
+        finally:
+            dns.rdata._allow_relative_comparisons = saved
 
     def test_absolute_vs_absolute_compare(self):
         r1 = dns.rdata.from_text(dns.rdataclass.IN, dns.rdatatype.NS, 'www.')
@@ -725,24 +749,43 @@ class RdataTestCase(unittest.TestCase):
         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)
-
+    def test_relative_vs_relative_compare_unstrict(self):
+        try:
+            saved = dns.rdata._allow_relative_comparisons
+            dns.rdata._allow_relative_comparisons = True
+            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)
+        finally:
+            dns.rdata._allow_relative_comparisons = saved
+
+    def test_relative_vs_relative_compare_strict(self):
+        try:
+            saved = dns.rdata._allow_relative_comparisons
+            dns.rdata._allow_relative_comparisons = False
+            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)
+        finally:
+            dns.rdata._allow_relative_comparisons = saved
 
 class UtilTestCase(unittest.TestCase):