From: Bob Halley Date: Thu, 14 Oct 2021 16:14:23 +0000 (-0700) Subject: Allow relative rdata comparisons for now, but disallow in the future. X-Git-Tag: v2.2.0rc1~49^2~1 X-Git-Url: http://git.ipfire.org/cgi-bin/gitweb.cgi?a=commitdiff_plain;h=c80d40a8b9b5788f98af9782afb72f09c00e268a;p=thirdparty%2Fdnspython.git Allow relative rdata comparisons for now, but disallow in the future. --- diff --git a/dns/rdata.py b/dns/rdata.py index 8a79de7d..1917ecd4 100644 --- a/dns/rdata.py +++ b/dns/rdata.py @@ -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 diff --git a/tests/test_rdata.py b/tests/test_rdata.py index ea3e3da7..f87ff560 100644 --- a/tests/test_rdata.py +++ b/tests/test_rdata.py @@ -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):