]> git.ipfire.org Git - thirdparty/dnspython.git/commitdiff
remove _constify() uses; more complete checking of bitmap windows types like NSEC
authorBob Halley <halley@dnspython.org>
Tue, 25 Aug 2020 14:32:11 +0000 (07:32 -0700)
committerBob Halley <halley@dnspython.org>
Tue, 25 Aug 2020 14:32:11 +0000 (07:32 -0700)
13 files changed:
dns/rdata.py
dns/rdtypes/ANY/CSYNC.py
dns/rdtypes/ANY/HIP.py
dns/rdtypes/ANY/LOC.py
dns/rdtypes/ANY/NSEC.py
dns/rdtypes/ANY/NSEC3.py
dns/rdtypes/ANY/OPT.py
dns/rdtypes/ANY/TSIG.py
dns/rdtypes/IN/APL.py
dns/rdtypes/IN/WKS.py
dns/rdtypes/txtbase.py
dns/rdtypes/util.py
tests/test_rdata.py

index 042623daae57c72dee5256d2b6d44ca7d7f690c7..3a4995486a29753134a3ce783684bf8a25bd6714 100644 (file)
@@ -350,6 +350,8 @@ class Rdata:
     def _as_bytes(cls, value, encode=False, max_length=None):
         if encode and isinstance(value, str):
             value = value.encode()
+        elif isinstance(value, bytearray):
+            value = bytes(value)
         elif not isinstance(value, bytes):
             raise ValueError('not bytes')
         if max_length is not None and len(value) > max_length:
index 0c33728593779f2a496fa40246a6b412df51b9b8..268fd88ee27a2a24868d0eda7c22630292febb14 100644 (file)
@@ -41,7 +41,11 @@ class CSYNC(dns.rdata.Rdata):
         super().__init__(rdclass, rdtype)
         self.serial = self._as_uint32(serial)
         self.flags = self._as_uint16(flags)
-        self.windows = dns.rdata._constify(windows)
+        if isinstance(windows, Bitmap):
+            bitmap = windows
+        else:
+            bitmap = Bitmap(windows)
+        self.windows = tuple(bitmap.windows)
 
     def to_text(self, origin=None, relativize=True, **kw):
         text = Bitmap(self.windows).to_text()
@@ -52,8 +56,8 @@ class CSYNC(dns.rdata.Rdata):
                   relativize_to=None):
         serial = tok.get_uint32()
         flags = tok.get_uint16()
-        windows = Bitmap().from_text(tok)
-        return cls(rdclass, rdtype, serial, flags, windows)
+        bitmap = Bitmap.from_text(tok)
+        return cls(rdclass, rdtype, serial, flags, bitmap)
 
     def _to_wire(self, file, compress=None, origin=None, canonicalize=False):
         file.write(struct.pack('!IH', self.serial, self.flags))
@@ -62,5 +66,5 @@ class CSYNC(dns.rdata.Rdata):
     @classmethod
     def from_wire_parser(cls, rdclass, rdtype, parser, origin=None):
         (serial, flags) = parser.get_struct("!IH")
-        windows = Bitmap().from_wire_parser(parser)
-        return cls(rdclass, rdtype, serial, flags, windows)
+        bitmap = Bitmap.from_wire_parser(parser)
+        return cls(rdclass, rdtype, serial, flags, bitmap)
index 610260d4024e5682a91f58d0d67ab77346ee8a19..f3cb34eaabf63cd5598c7446ee3a1ccbe88dddaf 100644 (file)
@@ -39,8 +39,7 @@ class HIP(dns.rdata.Rdata):
         self.hit = self._as_bytes(hit, True, 255)
         self.algorithm = self._as_uint8(algorithm)
         self.key = self._as_bytes(key, True)
-        self.servers = dns.rdata._constify([dns.rdata.Rdata._as_name(s)
-                                            for s in servers])
+        self.servers = tuple([dns.rdata.Rdata._as_name(s) for s in servers])
 
     def to_text(self, origin=None, relativize=True, **kw):
         hit = binascii.hexlify(self.hit).decode()
index 60b10b917f9320e73bf46dd1c50f44e9a9eccf95..1a4ee2bdbbbe9c5c6b6c6dde9718ad62056554f7 100644 (file)
@@ -131,13 +131,13 @@ class LOC(dns.rdata.Rdata):
         if isinstance(latitude, float):
             latitude = _float_to_tuple(latitude)
         _check_coordinate_list(latitude, -90, 90)
-        self.latitude = dns.rdata._constify(latitude)
+        self.latitude = tuple(latitude)
         if isinstance(longitude, int):
             longitude = float(longitude)
         if isinstance(longitude, float):
             longitude = _float_to_tuple(longitude)
         _check_coordinate_list(longitude, -180, 180)
-        self.longitude = dns.rdata._constify(longitude)
+        self.longitude = tuple(longitude)
         self.altitude = float(altitude)
         self.size = float(size)
         self.horizontal_precision = float(hprec)
index c1d70006ed750341ac29528f04b06606dec5ee0f..62e449993bd653a7ebeffd3d6661eb137487b049 100644 (file)
@@ -38,7 +38,11 @@ class NSEC(dns.rdata.Rdata):
     def __init__(self, rdclass, rdtype, next, windows):
         super().__init__(rdclass, rdtype)
         self.next = self._as_name(next)
-        self.windows = dns.rdata._constify(windows)
+        if isinstance(windows, Bitmap):
+            bitmap = windows
+        else:
+            bitmap = Bitmap(windows)
+        self.windows = tuple(bitmap.windows)
 
     def to_text(self, origin=None, relativize=True, **kw):
         next = self.next.choose_relativity(origin, relativize)
@@ -49,7 +53,7 @@ class NSEC(dns.rdata.Rdata):
     def from_text(cls, rdclass, rdtype, tok, origin=None, relativize=True,
                   relativize_to=None):
         next = tok.get_name(origin, relativize, relativize_to)
-        windows = Bitmap().from_text(tok)
+        windows = Bitmap.from_text(tok)
         return cls(rdclass, rdtype, next, windows)
 
     def _to_wire(self, file, compress=None, origin=None, canonicalize=False):
@@ -59,5 +63,5 @@ class NSEC(dns.rdata.Rdata):
     @classmethod
     def from_wire_parser(cls, rdclass, rdtype, parser, origin=None):
         next = parser.get_name(origin)
-        windows = Bitmap().from_wire_parser(parser)
-        return cls(rdclass, rdtype, next, windows)
+        bitmap = Bitmap.from_wire_parser(parser)
+        return cls(rdclass, rdtype, next, bitmap)
index 7650552d38da490d9457959dc3f56e488ffedc10..48a76eebf4a699ecfd38f5e579f8677a2be250de 100644 (file)
@@ -58,7 +58,11 @@ class NSEC3(dns.rdata.Rdata):
         self.iterations = self._as_uint16(iterations)
         self.salt = self._as_bytes(salt, True, 255)
         self.next = self._as_bytes(next, True, 255)
-        self.windows = dns.rdata._constify(windows)
+        if isinstance(windows, Bitmap):
+            bitmap = windows
+        else:
+            bitmap = Bitmap(windows)
+        self.windows = tuple(bitmap.windows)
 
     def to_text(self, origin=None, relativize=True, **kw):
         next = base64.b32encode(self.next).translate(
@@ -85,9 +89,9 @@ class NSEC3(dns.rdata.Rdata):
         next = tok.get_string().encode(
             'ascii').upper().translate(b32_hex_to_normal)
         next = base64.b32decode(next)
-        windows = Bitmap().from_text(tok)
+        bitmap = Bitmap.from_text(tok)
         return cls(rdclass, rdtype, algorithm, flags, iterations, salt, next,
-                   windows)
+                   bitmap)
 
     def _to_wire(self, file, compress=None, origin=None, canonicalize=False):
         l = len(self.salt)
@@ -104,6 +108,6 @@ class NSEC3(dns.rdata.Rdata):
         (algorithm, flags, iterations) = parser.get_struct('!BBH')
         salt = parser.get_counted_bytes()
         next = parser.get_counted_bytes()
-        windows = Bitmap().from_wire_parser(parser)
+        bitmap = Bitmap.from_wire_parser(parser)
         return cls(rdclass, rdtype, algorithm, flags, iterations, salt, next,
-                   windows)
+                   bitmap)
index 1968ce26264f08cf6ddabb12c3a9e3796d3aa29a..cac54bd8aef5b4fd0b16ac356acb5a9dcd5bf100 100644 (file)
@@ -48,7 +48,7 @@ class OPT(dns.rdata.Rdata):
         for option in options:
             if not isinstance(option, dns.edns.Option):
                 raise ValueError('option is not a dns.edns.option')
-        self.options = dns.rdata._constify(options)
+        self.options = tuple(options)
 
     def _to_wire(self, file, compress=None, origin=None, canonicalize=False):
         for opt in self.options:
index e49bf73a7086da7a5228b405638a7e85f423ece4..546219578af49979b4ab7e28c9e3bf42fe93bbed 100644 (file)
@@ -59,7 +59,7 @@ class TSIG(dns.rdata.Rdata):
         self.algorithm = self._as_name(algorithm)
         self.time_signed = self._as_uint48(time_signed)
         self.fudge = self._as_uint16(fudge)
-        self.mac = dns.rdata._constify(self._as_bytes(mac))
+        self.mac = self._as_bytes(mac)
         self.original_id = self._as_uint16(original_id)
         self.error = dns.rcode.Rcode.make(error)
         self.other = self._as_bytes(other)
index c0cd849175b59a3b5753cb2c91ab00267a8531ee..5cfdc344416a0c8d2045f2a186fe56b64e8cf0c9 100644 (file)
@@ -91,7 +91,7 @@ class APL(dns.rdata.Rdata):
         for item in items:
             if not isinstance(item, APLItem):
                 raise ValueError('item not an APLItem')
-        self.items = dns.rdata._constify(items)
+        self.items = tuple(items)
 
     def to_text(self, origin=None, relativize=True, **kw):
         return ' '.join(map(str, self.items))
index 068b1e3dcfdb1a79791d040f0e2a9fdc00df5270..0d36281788563e220c93ef5a5155c6b492a06fc2 100644 (file)
@@ -39,7 +39,7 @@ class WKS(dns.rdata.Rdata):
         super().__init__(rdclass, rdtype)
         self.address = self._as_ipv4_address(address)
         self.protocol = self._as_uint8(protocol)
-        self.bitmap = self._as_bytes(dns.rdata._constify(bitmap))
+        self.bitmap = self._as_bytes(bitmap)
 
     def to_text(self, origin=None, relativize=True, **kw):
         bits = []
index a170ced36551b683c914c68006dd9374ddf39611..37bf96170f67abbb5bb51ef795b05b2ebbace4ff 100644 (file)
@@ -48,7 +48,7 @@ class TXTBase(dns.rdata.Rdata):
         for string in strings:
             string = self._as_bytes(string, True, 255)
             encoded_strings.append(string)
-        self.strings = dns.rdata._constify(encoded_strings)
+        self.strings = tuple(encoded_strings)
 
     def to_text(self, origin=None, relativize=True, **kw):
         txt = ''
index bac7e7a7e89f4db2bf0bb5c77dd7138db335c9d8..03afb32e6b80a309567ce732a546ace2290e9a30 100644 (file)
@@ -99,7 +99,22 @@ class Bitmap:
     type_name = ""
 
     def __init__(self, windows=None):
+        last_window = -1
         self.windows = windows
+        for (window, bitmap) in self.windows:
+            if not isinstance(window, int):
+                raise ValueError(f"bad {self.type_name} window type")
+            if not isinstance(window, int):
+                raise ValueError(f"bad {self.type_name} window type")
+            if window <= last_window:
+                raise ValueError(f"bad {self.type_name} window order")
+            if window > 256:
+                raise ValueError(f"bad {self.type_name} window number")
+            last_window = window
+            if not isinstance(bitmap, bytes):
+                raise ValueError(f"bad {self.type_name} octets type")
+            if len(bitmap) == 0 or len(bitmap) > 32:
+                raise ValueError(f"bad {self.type_name} octets")
 
     def to_text(self):
         text = ""
@@ -113,12 +128,13 @@ class Bitmap:
             text += (' ' + ' '.join(bits))
         return text
 
-    def from_text(self, tok):
+    @classmethod
+    def from_text(cls, tok):
         rdtypes = []
         for token in tok.get_remaining():
             rdtype = dns.rdatatype.from_text(token.unescape().value)
             if rdtype == 0:
-                raise dns.exception.SyntaxError(f"{self.type_name} with bit 0")
+                raise dns.exception.SyntaxError(f"{cls.type_name} with bit 0")
             rdtypes.append(rdtype)
         rdtypes.sort()
         window = 0
@@ -133,7 +149,7 @@ class Bitmap:
             new_window = rdtype // 256
             if new_window != window:
                 if octets != 0:
-                    windows.append((window, bitmap[0:octets]))
+                    windows.append((window, bytes(bitmap[0:octets])))
                 bitmap = bytearray(b'\0' * 32)
                 window = new_window
             offset = rdtype % 256
@@ -142,24 +158,19 @@ class Bitmap:
             octets = byte + 1
             bitmap[byte] = bitmap[byte] | (0x80 >> bit)
         if octets != 0:
-            windows.append((window, bitmap[0:octets]))
-        return windows
+            windows.append((window, bytes(bitmap[0:octets])))
+        return cls(windows)
 
     def to_wire(self, file):
         for (window, bitmap) in self.windows:
             file.write(struct.pack('!BB', window, len(bitmap)))
             file.write(bitmap)
 
-    def from_wire_parser(self, parser):
+    @classmethod
+    def from_wire_parser(cls, parser):
         windows = []
-        last_window = -1
         while parser.remaining() > 0:
             window = parser.get_uint8()
-            if window <= last_window:
-                raise dns.exception.FormError(f"bad {self.type_name} bitmap")
             bitmap = parser.get_counted_bytes()
-            if len(bitmap) == 0 or len(bitmap) > 32:
-                raise dns.exception.FormError(f"bad {self.type_name} octets")
             windows.append((window, bitmap))
-            last_window = window
-        return windows
+        return cls(windows)
index 41465e002a9385d191adab4a0ddd87d199d7ca08..956bec0d9682b1fd3e4f3b368a953dba91c00813 100644 (file)
@@ -667,73 +667,73 @@ class UtilTestCase(unittest.TestCase):
             g.from_wire_parser(None)
 
     def test_Bitmap(self):
-        b = dns.rdtypes.util.Bitmap([])
+        b = dns.rdtypes.util.Bitmap
         tok = dns.tokenizer.Tokenizer('A MX')
-        windows = b.from_text(tok)
+        windows = b.from_text(tok).windows
         ba = bytearray()
         ba.append(0x40)  # bit 1, for A
         ba.append(0x01)  # bit 15, for MX
-        self.assertEqual(windows, [(0, ba)])
+        self.assertEqual(windows, [(0, bytes(ba))])
 
     def test_Bitmap_with_duplicate_types(self):
-        b = dns.rdtypes.util.Bitmap([])
+        b = dns.rdtypes.util.Bitmap
         tok = dns.tokenizer.Tokenizer('A MX A A MX')
-        windows = b.from_text(tok)
+        windows = b.from_text(tok).windows
         ba = bytearray()
         ba.append(0x40)  # bit 1, for A
         ba.append(0x01)  # bit 15, for MX
-        self.assertEqual(windows, [(0, ba)])
+        self.assertEqual(windows, [(0, bytes(ba))])
 
     def test_Bitmap_with_out_of_order_types(self):
-        b = dns.rdtypes.util.Bitmap([])
+        b = dns.rdtypes.util.Bitmap
         tok = dns.tokenizer.Tokenizer('MX A')
-        windows = b.from_text(tok)
+        windows = b.from_text(tok).windows
         ba = bytearray()
         ba.append(0x40)  # bit 1, for A
         ba.append(0x01)  # bit 15, for MX
-        self.assertEqual(windows, [(0, ba)])
+        self.assertEqual(windows, [(0, bytes(ba))])
 
     def test_Bitmap_zero_padding_works(self):
-        b = dns.rdtypes.util.Bitmap([])
+        b = dns.rdtypes.util.Bitmap
         tok = dns.tokenizer.Tokenizer('SRV')
-        windows = b.from_text(tok)
+        windows = b.from_text(tok).windows
         ba = bytearray()
         ba.append(0)
         ba.append(0)
         ba.append(0)
         ba.append(0)
         ba.append(0x40)  # bit 33, for SRV
-        self.assertEqual(windows, [(0, ba)])
+        self.assertEqual(windows, [(0, bytes(ba))])
 
     def test_Bitmap_has_type_0_set(self):
-        b = dns.rdtypes.util.Bitmap([])
+        b = dns.rdtypes.util.Bitmap
         with self.assertRaises(dns.exception.SyntaxError):
             tok = dns.tokenizer.Tokenizer('NONE A MX')
             b.from_text(tok)
 
     def test_Bitmap_empty_window_not_written(self):
-        b = dns.rdtypes.util.Bitmap([])
+        b = dns.rdtypes.util.Bitmap
         tok = dns.tokenizer.Tokenizer('URI CAA')  # types 256 and 257
-        windows = b.from_text(tok)
+        windows = b.from_text(tok).windows
         ba = bytearray()
         ba.append(0xc0)  # bits 0 and 1 in window 1
-        self.assertEqual(windows, [(1, ba)])
+        self.assertEqual(windows, [(1, bytes(ba))])
 
     def test_Bitmap_ok_parse(self):
         parser = dns.wire.Parser(b'\x00\x01\x40')
         b = dns.rdtypes.util.Bitmap([])
-        windows = b.from_wire_parser(parser)
+        windows = b.from_wire_parser(parser).windows
         self.assertEqual(windows, [(0, b'@')])
 
     def test_Bitmap_0_length_window_parse(self):
         parser = dns.wire.Parser(b'\x00\x00')
-        with self.assertRaises(dns.exception.FormError):
+        with self.assertRaises(ValueError):
             b = dns.rdtypes.util.Bitmap([])
             b.from_wire_parser(parser)
 
     def test_Bitmap_too_long_parse(self):
         parser = dns.wire.Parser(b'\x00\x21' + b'\x01' * 33)
-        with self.assertRaises(dns.exception.FormError):
+        with self.assertRaises(ValueError):
             b = dns.rdtypes.util.Bitmap([])
             b.from_wire_parser(parser)