From 6e652fa09f9b9383a34d0a91e882e28b730a4aa6 Mon Sep 17 00:00:00 2001 From: Bob Halley Date: Mon, 23 May 2016 15:18:47 -0700 Subject: [PATCH] Add CSYNC --- dns/rdatatype.py | 2 + dns/rdtypes/ANY/CSYNC.py | 124 +++++++++++++++++++++++++++++++++++++++ tests/example | 1 + tests/example1.good | 1 + tests/example2.good | 1 + tests/example3.good | 1 + 6 files changed, 130 insertions(+) create mode 100644 dns/rdtypes/ANY/CSYNC.py diff --git a/dns/rdatatype.py b/dns/rdatatype.py index f4336fca..cde1a0a1 100644 --- a/dns/rdatatype.py +++ b/dns/rdatatype.py @@ -82,6 +82,7 @@ TLSA = 52 HIP = 55 CDS = 59 CDNSKEY = 60 +CSYNC = 62 SPF = 99 UNSPEC = 103 EUI48 = 108 @@ -151,6 +152,7 @@ _by_text = { 'HIP': HIP, 'CDS': CDS, 'CDNSKEY': CDNSKEY, + 'CSYNC': CSYNC, 'SPF': SPF, 'UNSPEC': UNSPEC, 'EUI48': EUI48, diff --git a/dns/rdtypes/ANY/CSYNC.py b/dns/rdtypes/ANY/CSYNC.py new file mode 100644 index 00000000..bf95cb27 --- /dev/null +++ b/dns/rdtypes/ANY/CSYNC.py @@ -0,0 +1,124 @@ +# Copyright (C) 2004-2007, 2009-2011, 2016 Nominum, Inc. +# +# Permission to use, copy, modify, and distribute this software and its +# documentation for any purpose with or without fee is hereby granted, +# provided that the above copyright notice and this permission notice +# appear in all copies. +# +# THE SOFTWARE IS PROVIDED "AS IS" AND NOMINUM DISCLAIMS ALL WARRANTIES +# WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF +# MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL NOMINUM BE LIABLE FOR +# ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES +# WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN +# ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT +# OF OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE. + +import struct + +import dns.exception +import dns.rdata +import dns.rdatatype +import dns.name +from dns._compat import xrange + +class CSYNC(dns.rdata.Rdata): + + """CSYNC record + + @ivar serial: the SOA serial number + @type serial: int + @ivar flags: the CSYNC flags + @type flags: int + @ivar windows: the windowed bitmap list + @type windows: list of (window number, string) tuples""" + + __slots__ = ['serial', 'flags', 'windows'] + + def __init__(self, rdclass, rdtype, serial, flags, windows): + super(CSYNC, self).__init__(rdclass, rdtype) + self.serial = serial + self.flags = flags + self.windows = windows + + def to_text(self, origin=None, relativize=True, **kw): + text = '' + for (window, bitmap) in self.windows: + bits = [] + for i in xrange(0, len(bitmap)): + byte = bitmap[i] + for j in xrange(0, 8): + if byte & (0x80 >> j): + bits.append(dns.rdatatype.to_text(window * 256 + + i * 8 + j)) + text += (' ' + ' '.join(bits)) + return '%d %d%s' % (self.serial, self.flags, text) + + @classmethod + def from_text(cls, rdclass, rdtype, tok, origin=None, relativize=True): + serial = tok.get_uint32() + flags = tok.get_uint16() + rdtypes = [] + while 1: + token = tok.get().unescape() + if token.is_eol_or_eof(): + break + nrdtype = dns.rdatatype.from_text(token.value) + if nrdtype == 0: + raise dns.exception.SyntaxError("CSYNC with bit 0") + if nrdtype > 65535: + raise dns.exception.SyntaxError("CSYNC with bit > 65535") + rdtypes.append(nrdtype) + rdtypes.sort() + window = 0 + octets = 0 + prior_rdtype = 0 + bitmap = bytearray(b'\0' * 32) + windows = [] + for nrdtype in rdtypes: + if nrdtype == prior_rdtype: + continue + prior_rdtype = nrdtype + new_window = nrdtype // 256 + if new_window != window: + windows.append((window, bitmap[0:octets])) + bitmap = bytearray(b'\0' * 32) + window = new_window + offset = nrdtype % 256 + byte = offset // 8 + bit = offset % 8 + octets = byte + 1 + bitmap[byte] = bitmap[byte] | (0x80 >> bit) + + windows.append((window, bitmap[0:octets])) + return cls(rdclass, rdtype, serial, flags, windows) + + def to_wire(self, file, compress=None, origin=None): + file.write(struct.pack('!IH', self.serial, self.flags)) + for (window, bitmap) in self.windows: + file.write(struct.pack('!BB', window, len(bitmap))) + file.write(bitmap) + + @classmethod + def from_wire(cls, rdclass, rdtype, wire, current, rdlen, origin=None): + if rdlen < 6: + raise dns.exception.FormError("CSYNC too short") + (serial, flags) = struct.unpack("!IH", wire[current: current + 6]) + current += 6 + rdlen -= 6 + windows = [] + while rdlen > 0: + if rdlen < 3: + raise dns.exception.FormError("CSYNC too short") + window = wire[current] + octets = wire[current + 1] + if octets == 0 or octets > 32: + raise dns.exception.FormError("bad CSYNC octets") + current += 2 + rdlen -= 2 + if rdlen < octets: + raise dns.exception.FormError("bad CSYNC bitmap length") + bitmap = bytearray(wire[current: current + octets].unwrap()) + current += octets + rdlen -= octets + windows.append((window, bitmap)) + return cls(rdclass, rdtype, serial, flags, windows) diff --git a/tests/example b/tests/example index cef17321..5983754b 100644 --- a/tests/example +++ b/tests/example @@ -195,3 +195,4 @@ caa03 CAA 0 iodef "http://iodef.example.com/" caa04 CAA 0 issue "ca.example.net; account=230123" caa05 CAA 0 issue "ca.example.net; policy=ev" caa06 CAA 128 tbs "Unknown" +csync0 CSYNC 12345 0 A MX RRSIG NSEC TYPE1234 diff --git a/tests/example1.good b/tests/example1.good index a5f9c604..215d99f8 100644 --- a/tests/example1.good +++ b/tests/example1.good @@ -28,6 +28,7 @@ cert01 3600 IN CERT 65534 65535 PRIVATEOID MxFcby9k/yvedMfQgKzhH5er0Mu/vILz 45Ik cname01 3600 IN CNAME cname-target. cname02 3600 IN CNAME cname-target cname03 3600 IN CNAME . +csync0 3600 IN CSYNC 12345 0 A MX RRSIG NSEC TYPE1234 d 300 IN A 73.80.65.49 dhcid01 3600 IN DHCID AAIBY2/AuCccgoJbsaxcQc9TUapptP69 lOjxfNuVAA2kjEA= dhcid02 3600 IN DHCID AAEBOSD+XR3Os/0LozeXVqcNc7FwCfQd WL3b/NaiUDlW2No= diff --git a/tests/example2.good b/tests/example2.good index 8ed0b2f7..07029306 100644 --- a/tests/example2.good +++ b/tests/example2.good @@ -28,6 +28,7 @@ cert01.example. 3600 IN CERT 65534 65535 PRIVATEOID MxFcby9k/yvedMfQgKzhH5er0Mu/ cname01.example. 3600 IN CNAME cname-target. cname02.example. 3600 IN CNAME cname-target.example. cname03.example. 3600 IN CNAME . +csync0.example. 3600 IN CSYNC 12345 0 A MX RRSIG NSEC TYPE1234 d.example. 300 IN A 73.80.65.49 dhcid01.example. 3600 IN DHCID AAIBY2/AuCccgoJbsaxcQc9TUapptP69 lOjxfNuVAA2kjEA= dhcid02.example. 3600 IN DHCID AAEBOSD+XR3Os/0LozeXVqcNc7FwCfQd WL3b/NaiUDlW2No= diff --git a/tests/example3.good b/tests/example3.good index a5f9c604..215d99f8 100644 --- a/tests/example3.good +++ b/tests/example3.good @@ -28,6 +28,7 @@ cert01 3600 IN CERT 65534 65535 PRIVATEOID MxFcby9k/yvedMfQgKzhH5er0Mu/vILz 45Ik cname01 3600 IN CNAME cname-target. cname02 3600 IN CNAME cname-target cname03 3600 IN CNAME . +csync0 3600 IN CSYNC 12345 0 A MX RRSIG NSEC TYPE1234 d 300 IN A 73.80.65.49 dhcid01 3600 IN DHCID AAIBY2/AuCccgoJbsaxcQc9TUapptP69 lOjxfNuVAA2kjEA= dhcid02 3600 IN DHCID AAEBOSD+XR3Os/0LozeXVqcNc7FwCfQd WL3b/NaiUDlW2No= -- 2.47.3