From: Jan Vcelak Date: Sat, 31 Oct 2015 11:19:06 +0000 (+0100) Subject: Add support for CDNSKEY record type X-Git-Url: http://git.ipfire.org/cgi-bin/gitweb.cgi?a=commitdiff_plain;h=refs%2Fpull%2F127%2Fhead;p=thirdparty%2Fdnspython.git Add support for CDNSKEY record type --- diff --git a/dns/rdatatype.py b/dns/rdatatype.py index 60714064..ce496de1 100644 --- a/dns/rdatatype.py +++ b/dns/rdatatype.py @@ -81,6 +81,7 @@ NSEC3PARAM = 51 TLSA = 52 HIP = 55 CDS = 59 +CDNSKEY = 60 SPF = 99 UNSPEC = 103 TKEY = 249 @@ -146,6 +147,7 @@ _by_text = { 'TLSA' : TLSA, 'HIP' : HIP, 'CDS' : CDS, + 'CDNSKEY' : CDNSKEY, 'SPF' : SPF, 'UNSPEC' : UNSPEC, 'TKEY' : TKEY, diff --git a/dns/rdtypes/ANY/CDNSKEY.py b/dns/rdtypes/ANY/CDNSKEY.py new file mode 100644 index 00000000..25cb3d8c --- /dev/null +++ b/dns/rdtypes/ANY/CDNSKEY.py @@ -0,0 +1,20 @@ +# Copyright (C) 2004-2007, 2009-2011 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 dns.rdtypes.dnskeybase +from dns.rdtypes.dnskeybase import * + +class CDNSKEY(dns.rdtypes.dnskeybase.DNSKEYBase): + """CDNSKEY record""" diff --git a/dns/rdtypes/ANY/DNSKEY.py b/dns/rdtypes/ANY/DNSKEY.py index 0c9a42f3..cc64b6cc 100644 --- a/dns/rdtypes/ANY/DNSKEY.py +++ b/dns/rdtypes/ANY/DNSKEY.py @@ -13,121 +13,8 @@ # ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT # OF OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE. -import base64 -import struct +import dns.rdtypes.dnskeybase +from dns.rdtypes.dnskeybase import * -import dns.exception -import dns.dnssec -import dns.rdata -import dns.util - - -# flag constants -SEP = 0x0001 -REVOKE = 0x0080 -ZONE = 0x0100 - -_flag_by_text = { - 'SEP': SEP, - 'REVOKE': REVOKE, - 'ZONE': ZONE - } - -# We construct the inverse mapping programmatically to ensure that we -# cannot make any mistakes (e.g. omissions, cut-and-paste errors) that -# would cause the mapping not to be true inverse. -_flag_by_value = dict([(y, x) for x, y in _flag_by_text.items()]) - - -def flags_to_text_set(flags): - """Convert a DNSKEY flags value to set texts - @rtype: set([string])""" - - flags_set = set() - mask = 0x1 - while mask <= 0x8000: - if flags & mask: - text = _flag_by_value.get(mask) - if not text: - text = hex(mask) - flags_set.add(text) - mask <<= 1 - return flags_set - - -def flags_from_text_set(texts_set): - """Convert set of DNSKEY flag mnemonic texts to DNSKEY flag value - @rtype: int""" - - flags = 0 - for text in texts_set: - try: - flags += _flag_by_text[text] - except KeyError: - raise NotImplementedError( - "DNSKEY flag '%s' is not supported" % text) - return flags - - -class DNSKEY(dns.rdata.Rdata): - """DNSKEY record - - @ivar flags: the key flags - @type flags: int - @ivar protocol: the protocol for which this key may be used - @type protocol: int - @ivar algorithm: the algorithm used for the key - @type algorithm: int - @ivar key: the public key - @type key: string""" - - __slots__ = ['flags', 'protocol', 'algorithm', 'key'] - - def __init__(self, rdclass, rdtype, flags, protocol, algorithm, key): - super(DNSKEY, self).__init__(rdclass, rdtype) - self.flags = flags - self.protocol = protocol - self.algorithm = algorithm - self.key = key - - def to_text(self, origin=None, relativize=True, **kw): - return '%d %d %d %s' % (self.flags, self.protocol, self.algorithm, - dns.rdata._base64ify(self.key)) - - @classmethod - def from_text(cls, rdclass, rdtype, tok, origin = None, relativize = True): - flags = tok.get_uint16() - protocol = tok.get_uint8() - algorithm = dns.dnssec.algorithm_from_text(tok.get_string()) - chunks = [] - while 1: - t = tok.get().unescape() - if t.is_eol_or_eof(): - break - if not t.is_identifier(): - raise dns.exception.SyntaxError - chunks.append(t.value) - b64 = ''.join(chunks) - key = base64.b64decode(b64.encode('ascii')) - return cls(rdclass, rdtype, flags, protocol, algorithm, key) - - def to_wire(self, file, compress = None, origin = None): - header = struct.pack("!HBB", self.flags, self.protocol, self.algorithm) - file.write(header) - file.write(self.key) - - @classmethod - def from_wire(cls, rdclass, rdtype, wire, current, rdlen, origin = None): - if rdlen < 4: - raise dns.exception.FormError - header = struct.unpack('!HBB', wire[current : current + 4]) - current += 4 - rdlen -= 4 - key = wire[current : current + rdlen].unwrap() - return cls(rdclass, rdtype, header[0], header[1], header[2], - key) - - def flags_to_text_set(self): - """Convert a DNSKEY flags value to set texts - @rtype: set([string])""" - return flags_to_text_set(self.flags) +class DNSKEY(dns.rdtypes.dnskeybase.DNSKEYBase): + """DNSKEY record""" diff --git a/dns/rdtypes/ANY/__init__.py b/dns/rdtypes/ANY/__init__.py index b95048b5..2f275175 100644 --- a/dns/rdtypes/ANY/__init__.py +++ b/dns/rdtypes/ANY/__init__.py @@ -17,6 +17,7 @@ __all__ = [ 'AFSDB', + 'CDNSKEY', 'CDS', 'CERT', 'CNAME', diff --git a/dns/rdtypes/dnskeybase.py b/dns/rdtypes/dnskeybase.py new file mode 100644 index 00000000..c60b5780 --- /dev/null +++ b/dns/rdtypes/dnskeybase.py @@ -0,0 +1,132 @@ +# Copyright (C) 2004-2007, 2009-2011 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 base64 +import struct + +import dns.exception +import dns.dnssec +import dns.rdata + +# wildcard import +__all__ = [ "SEP", "REVOKE", "ZONE", "flags_to_text_set", "flags_from_text_set" ] + +# flag constants +SEP = 0x0001 +REVOKE = 0x0080 +ZONE = 0x0100 + +_flag_by_text = { + 'SEP': SEP, + 'REVOKE': REVOKE, + 'ZONE': ZONE + } + +# We construct the inverse mapping programmatically to ensure that we +# cannot make any mistakes (e.g. omissions, cut-and-paste errors) that +# would cause the mapping not to be true inverse. +_flag_by_value = dict([(y, x) for x, y in _flag_by_text.items()]) + +def flags_to_text_set(flags): + """Convert a DNSKEY flags value to set texts + @rtype: set([string])""" + + flags_set = set() + mask = 0x1 + while mask <= 0x8000: + if flags & mask: + text = _flag_by_value.get(mask) + if not text: + text = hex(mask) + flags_set.add(text) + mask <<= 1 + return flags_set + + +def flags_from_text_set(texts_set): + """Convert set of DNSKEY flag mnemonic texts to DNSKEY flag value + @rtype: int""" + + flags = 0 + for text in texts_set: + try: + flags += _flag_by_text[text] + except KeyError: + raise NotImplementedError( + "DNSKEY flag '%s' is not supported" % text) + return flags + +class DNSKEYBase(dns.rdata.Rdata): + """Base class for rdata that is like a DNSKEY record + + @ivar flags: the key flags + @type flags: int + @ivar protocol: the protocol for which this key may be used + @type protocol: int + @ivar algorithm: the algorithm used for the key + @type algorithm: int + @ivar key: the public key + @type key: string""" + + __slots__ = ['flags', 'protocol', 'algorithm', 'key'] + + def __init__(self, rdclass, rdtype, flags, protocol, algorithm, key): + super(DNSKEYBase, self).__init__(rdclass, rdtype) + self.flags = flags + self.protocol = protocol + self.algorithm = algorithm + self.key = key + + def to_text(self, origin=None, relativize=True, **kw): + return '%d %d %d %s' % (self.flags, self.protocol, self.algorithm, + dns.rdata._base64ify(self.key)) + + @classmethod + def from_text(cls, rdclass, rdtype, tok, origin = None, relativize = True): + flags = tok.get_uint16() + protocol = tok.get_uint8() + algorithm = dns.dnssec.algorithm_from_text(tok.get_string()) + chunks = [] + while 1: + t = tok.get().unescape() + if t.is_eol_or_eof(): + break + if not t.is_identifier(): + raise dns.exception.SyntaxError + chunks.append(t.value) + b64 = ''.join(chunks) + key = base64.b64decode(b64.encode('ascii')) + return cls(rdclass, rdtype, flags, protocol, algorithm, key) + + def to_wire(self, file, compress = None, origin = None): + header = struct.pack("!HBB", self.flags, self.protocol, self.algorithm) + file.write(header) + file.write(self.key) + + @classmethod + def from_wire(cls, rdclass, rdtype, wire, current, rdlen, origin = None): + if rdlen < 4: + raise dns.exception.FormError + header = struct.unpack('!HBB', wire[current : current + 4]) + current += 4 + rdlen -= 4 + key = wire[current : current + rdlen].unwrap() + return cls(rdclass, rdtype, header[0], header[1], header[2], + key) + + def flags_to_text_set(self): + """Convert a DNSKEY flags value to set texts + @rtype: set([string])""" + return flags_to_text_set(self.flags) diff --git a/tests/example b/tests/example index fca0adec..a4eb615e 100644 --- a/tests/example +++ b/tests/example @@ -212,6 +212,12 @@ dnskey02 DNSKEY 257 3 RSAMD5 ( yzWZriO6i2odGWWQVucZqKVsENW91IOW4vqudngPZsY3 GvQ/xVA8/7pyFj6b7Esga60zyGW6LFe9r8n6paHrlG5o jqf0BaqHT+8= ) +cdnskey01 CDNSKEY 256 3 8 ( + AwEAAbmiLgh411Pz3v3XCSBrvYf52A/Gv55ItN1NbOLH + Cqt3Ec3p+VB/kQ87VjjMrycanZFnZT4l9uCFuYh21Ccy + xVpcxExbM0UuhX5rJoDyeFSXoQlkHrB01osPl5Vri5Ym + KtcmqGxZ9An0VSunohkyiX1SrNRZSdQnk9/pIHDe/c8D + ) ; ; test known type using unknown RR syntax ; diff --git a/tests/example1.good b/tests/example1.good index 1e96be8f..a311f595 100644 --- a/tests/example1.good +++ b/tests/example1.good @@ -20,6 +20,7 @@ caa03 3600 IN CAA 0 iodef "http://iodef.example.com/" caa04 3600 IN CAA 0 issue "ca.example.net; account=230123" caa05 3600 IN CAA 0 issue "ca.example.net; policy=ev" caa06 3600 IN CAA 128 tbs "Unknown" +cdnskey01 3600 IN CDNSKEY 256 3 8 AwEAAbmiLgh411Pz3v3XCSBrvYf52A/G v55ItN1NbOLHCqt3Ec3p+VB/kQ87VjjM rycanZFnZT4l9uCFuYh21CcyxVpcxExb M0UuhX5rJoDyeFSXoQlkHrB01osPl5Vr i5YmKtcmqGxZ9An0VSunohkyiX1SrNRZ SdQnk9/pIHDe/c8D cds01 3600 IN CDS 12345 3 1 123456789abcdef67890123456789abcdef67890 cert01 3600 IN CERT 65534 65535 PRIVATEOID MxFcby9k/yvedMfQgKzhH5er0Mu/vILz 45IkskceFGgiWCn/GxHhai6VAuHAoNUz 4YoU1tVfSCSqQYn6//11U6Nld80jEeC8 aTrO+KKmCaY= cname01 3600 IN CNAME cname-target. diff --git a/tests/example2.good b/tests/example2.good index 5895179b..492bbb52 100644 --- a/tests/example2.good +++ b/tests/example2.good @@ -20,6 +20,7 @@ caa03.example. 3600 IN CAA 0 iodef "http://iodef.example.com/" caa04.example. 3600 IN CAA 0 issue "ca.example.net; account=230123" caa05.example. 3600 IN CAA 0 issue "ca.example.net; policy=ev" caa06.example. 3600 IN CAA 128 tbs "Unknown" +cdnskey01.example. 3600 IN CDNSKEY 256 3 8 AwEAAbmiLgh411Pz3v3XCSBrvYf52A/G v55ItN1NbOLHCqt3Ec3p+VB/kQ87VjjM rycanZFnZT4l9uCFuYh21CcyxVpcxExb M0UuhX5rJoDyeFSXoQlkHrB01osPl5Vr i5YmKtcmqGxZ9An0VSunohkyiX1SrNRZ SdQnk9/pIHDe/c8D cds01.example. 3600 IN CDS 12345 3 1 123456789abcdef67890123456789abcdef67890 cert01.example. 3600 IN CERT 65534 65535 PRIVATEOID MxFcby9k/yvedMfQgKzhH5er0Mu/vILz 45IkskceFGgiWCn/GxHhai6VAuHAoNUz 4YoU1tVfSCSqQYn6//11U6Nld80jEeC8 aTrO+KKmCaY= cname01.example. 3600 IN CNAME cname-target. diff --git a/tests/example3.good b/tests/example3.good index 1e96be8f..a311f595 100644 --- a/tests/example3.good +++ b/tests/example3.good @@ -20,6 +20,7 @@ caa03 3600 IN CAA 0 iodef "http://iodef.example.com/" caa04 3600 IN CAA 0 issue "ca.example.net; account=230123" caa05 3600 IN CAA 0 issue "ca.example.net; policy=ev" caa06 3600 IN CAA 128 tbs "Unknown" +cdnskey01 3600 IN CDNSKEY 256 3 8 AwEAAbmiLgh411Pz3v3XCSBrvYf52A/G v55ItN1NbOLHCqt3Ec3p+VB/kQ87VjjM rycanZFnZT4l9uCFuYh21CcyxVpcxExb M0UuhX5rJoDyeFSXoQlkHrB01osPl5Vr i5YmKtcmqGxZ9An0VSunohkyiX1SrNRZ SdQnk9/pIHDe/c8D cds01 3600 IN CDS 12345 3 1 123456789abcdef67890123456789abcdef67890 cert01 3600 IN CERT 65534 65535 PRIVATEOID MxFcby9k/yvedMfQgKzhH5er0Mu/vILz 45IkskceFGgiWCn/GxHhai6VAuHAoNUz 4YoU1tVfSCSqQYn6//11U6Nld80jEeC8 aTrO+KKmCaY= cname01 3600 IN CNAME cname-target.