diff options
author | Bob Halley <halley@dnspython.org> | 2020-08-25 07:32:11 -0700 |
---|---|---|
committer | Bob Halley <halley@dnspython.org> | 2020-08-25 07:32:11 -0700 |
commit | f65cd9fa9cbf8ae19bad346dcad5d90b33ed9625 (patch) | |
tree | fb2a9dc46fd2efa795ace8049866a6014f48d3ee | |
parent | 160bdf2657f673c10f64c76026007d3ce87faee2 (diff) | |
download | dnspython-f65cd9fa9cbf8ae19bad346dcad5d90b33ed9625.tar.gz |
remove _constify() uses; more complete checking of bitmap windows types like NSEC
-rw-r--r-- | dns/rdata.py | 2 | ||||
-rw-r--r-- | dns/rdtypes/ANY/CSYNC.py | 14 | ||||
-rw-r--r-- | dns/rdtypes/ANY/HIP.py | 3 | ||||
-rw-r--r-- | dns/rdtypes/ANY/LOC.py | 4 | ||||
-rw-r--r-- | dns/rdtypes/ANY/NSEC.py | 12 | ||||
-rw-r--r-- | dns/rdtypes/ANY/NSEC3.py | 14 | ||||
-rw-r--r-- | dns/rdtypes/ANY/OPT.py | 2 | ||||
-rw-r--r-- | dns/rdtypes/ANY/TSIG.py | 2 | ||||
-rw-r--r-- | dns/rdtypes/IN/APL.py | 2 | ||||
-rw-r--r-- | dns/rdtypes/IN/WKS.py | 2 | ||||
-rw-r--r-- | dns/rdtypes/txtbase.py | 2 | ||||
-rw-r--r-- | dns/rdtypes/util.py | 37 | ||||
-rw-r--r-- | tests/test_rdata.py | 38 |
13 files changed, 79 insertions, 55 deletions
diff --git a/dns/rdata.py b/dns/rdata.py index 042623d..3a49954 100644 --- a/dns/rdata.py +++ b/dns/rdata.py @@ -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: diff --git a/dns/rdtypes/ANY/CSYNC.py b/dns/rdtypes/ANY/CSYNC.py index 0c33728..268fd88 100644 --- a/dns/rdtypes/ANY/CSYNC.py +++ b/dns/rdtypes/ANY/CSYNC.py @@ -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) diff --git a/dns/rdtypes/ANY/HIP.py b/dns/rdtypes/ANY/HIP.py index 610260d..f3cb34e 100644 --- a/dns/rdtypes/ANY/HIP.py +++ b/dns/rdtypes/ANY/HIP.py @@ -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() diff --git a/dns/rdtypes/ANY/LOC.py b/dns/rdtypes/ANY/LOC.py index 60b10b9..1a4ee2b 100644 --- a/dns/rdtypes/ANY/LOC.py +++ b/dns/rdtypes/ANY/LOC.py @@ -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) diff --git a/dns/rdtypes/ANY/NSEC.py b/dns/rdtypes/ANY/NSEC.py index c1d7000..62e4499 100644 --- a/dns/rdtypes/ANY/NSEC.py +++ b/dns/rdtypes/ANY/NSEC.py @@ -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) diff --git a/dns/rdtypes/ANY/NSEC3.py b/dns/rdtypes/ANY/NSEC3.py index 7650552..48a76ee 100644 --- a/dns/rdtypes/ANY/NSEC3.py +++ b/dns/rdtypes/ANY/NSEC3.py @@ -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) diff --git a/dns/rdtypes/ANY/OPT.py b/dns/rdtypes/ANY/OPT.py index 1968ce2..cac54bd 100644 --- a/dns/rdtypes/ANY/OPT.py +++ b/dns/rdtypes/ANY/OPT.py @@ -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: diff --git a/dns/rdtypes/ANY/TSIG.py b/dns/rdtypes/ANY/TSIG.py index e49bf73..5462195 100644 --- a/dns/rdtypes/ANY/TSIG.py +++ b/dns/rdtypes/ANY/TSIG.py @@ -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) diff --git a/dns/rdtypes/IN/APL.py b/dns/rdtypes/IN/APL.py index c0cd849..5cfdc34 100644 --- a/dns/rdtypes/IN/APL.py +++ b/dns/rdtypes/IN/APL.py @@ -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)) diff --git a/dns/rdtypes/IN/WKS.py b/dns/rdtypes/IN/WKS.py index 068b1e3..0d36281 100644 --- a/dns/rdtypes/IN/WKS.py +++ b/dns/rdtypes/IN/WKS.py @@ -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 = [] diff --git a/dns/rdtypes/txtbase.py b/dns/rdtypes/txtbase.py index a170ced..37bf961 100644 --- a/dns/rdtypes/txtbase.py +++ b/dns/rdtypes/txtbase.py @@ -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 = '' diff --git a/dns/rdtypes/util.py b/dns/rdtypes/util.py index bac7e7a..03afb32 100644 --- a/dns/rdtypes/util.py +++ b/dns/rdtypes/util.py @@ -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) diff --git a/tests/test_rdata.py b/tests/test_rdata.py index 41465e0..956bec0 100644 --- a/tests/test_rdata.py +++ b/tests/test_rdata.py @@ -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) |