summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorPetr Spacek <pspacek@redhat.com>2015-12-03 13:07:41 +0100
committerBob Halley <halley@play-bow.org>2015-12-03 07:53:12 -0800
commitdb37d614fe07f6a20dc5e032024848daa65ac423 (patch)
tree66098167fc7261589fb5a6e9dbb143e3fcb6d0ff
parent2f815a32a43fb09e206dd53aeb64beac6ce6b543 (diff)
downloaddnspython-db37d614fe07f6a20dc5e032024848daa65ac423.tar.gz
Add support for EUI48 and EUI64 RR types
-rw-r--r--dns/rdatatype.py4
-rw-r--r--dns/rdtypes/ANY/EUI48.py28
-rw-r--r--dns/rdtypes/ANY/EUI64.py28
-rw-r--r--dns/rdtypes/ANY/__init__.py2
-rw-r--r--dns/rdtypes/__init__.py1
-rw-r--r--dns/rdtypes/euibase.py71
-rw-r--r--tests/test_rdtypeanyeui.py223
7 files changed, 357 insertions, 0 deletions
diff --git a/dns/rdatatype.py b/dns/rdatatype.py
index ce496de..d54b704 100644
--- a/dns/rdatatype.py
+++ b/dns/rdatatype.py
@@ -84,6 +84,8 @@ CDS = 59
CDNSKEY = 60
SPF = 99
UNSPEC = 103
+EUI48 = 108
+EUI64 = 109
TKEY = 249
TSIG = 250
IXFR = 251
@@ -150,6 +152,8 @@ _by_text = {
'CDNSKEY' : CDNSKEY,
'SPF' : SPF,
'UNSPEC' : UNSPEC,
+ 'EUI48': EUI48,
+ 'EUI64': EUI64,
'TKEY' : TKEY,
'TSIG' : TSIG,
'IXFR' : IXFR,
diff --git a/dns/rdtypes/ANY/EUI48.py b/dns/rdtypes/ANY/EUI48.py
new file mode 100644
index 0000000..6ddfa6a
--- /dev/null
+++ b/dns/rdtypes/ANY/EUI48.py
@@ -0,0 +1,28 @@
+# Copyright (C) 2015 Red Hat, Inc.
+# Author: Petr Spacek <pspacek@redhat.com>
+#
+# 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 RED HAT 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.euibase
+
+
+class EUI48(dns.rdtypes.euibase.EUIBase):
+ """EUI48 record
+
+ @ivar fingerprint: 48-bit Extended Unique Identifier (EUI-48)
+ @type fingerprint: string
+ @see: rfc7043.txt"""
+
+ byte_len = 6 # 0123456789ab (in hex)
+ text_len = byte_len * 3 - 1 # 01-23-45-67-89-ab
diff --git a/dns/rdtypes/ANY/EUI64.py b/dns/rdtypes/ANY/EUI64.py
new file mode 100644
index 0000000..41abd7b
--- /dev/null
+++ b/dns/rdtypes/ANY/EUI64.py
@@ -0,0 +1,28 @@
+# Copyright (C) 2015 Red Hat, Inc.
+# Author: Petr Spacek <pspacek@redhat.com>
+#
+# 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 RED HAT 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.euibase
+
+
+class EUI64(dns.rdtypes.euibase.EUIBase):
+ """EUI64 record
+
+ @ivar fingerprint: 64-bit Extended Unique Identifier (EUI-64)
+ @type fingerprint: string
+ @see: rfc7043.txt"""
+
+ byte_len = 8 # 0123456789abcdef (in hex)
+ text_len = byte_len * 3 - 1 # 01-23-45-67-89-ab-cd-ef
diff --git a/dns/rdtypes/ANY/__init__.py b/dns/rdtypes/ANY/__init__.py
index 2f27517..cb52822 100644
--- a/dns/rdtypes/ANY/__init__.py
+++ b/dns/rdtypes/ANY/__init__.py
@@ -25,6 +25,8 @@ __all__ = [
'DNAME',
'DNSKEY',
'DS',
+ 'EUI48',
+ 'EUI64',
'GPOS',
'HINFO',
'HIP',
diff --git a/dns/rdtypes/__init__.py b/dns/rdtypes/__init__.py
index 49db5a3..826efbb 100644
--- a/dns/rdtypes/__init__.py
+++ b/dns/rdtypes/__init__.py
@@ -18,6 +18,7 @@
__all__ = [
'ANY',
'IN',
+ 'euibase',
'mxbase',
'nsbase',
]
diff --git a/dns/rdtypes/euibase.py b/dns/rdtypes/euibase.py
new file mode 100644
index 0000000..2af018d
--- /dev/null
+++ b/dns/rdtypes/euibase.py
@@ -0,0 +1,71 @@
+# Copyright (C) 2015 Red Hat, Inc.
+# Author: Petr Spacek <pspacek@redhat.com>
+#
+# 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 RED HAT 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 binascii
+
+import dns.rdata
+
+
+class EUIBase(dns.rdata.Rdata):
+ """EUIxx record
+
+ @ivar fingerprint: xx-bit Extended Unique Identifier (EUI-xx)
+ @type fingerprint: string
+ @see: rfc7043.txt"""
+
+ __slots__ = ['eui']
+ # define these in subclasses
+ # byte_len = 6 # 0123456789ab (in hex)
+ # text_len = byte_len * 3 - 1 # 01-23-45-67-89-ab
+
+ def __init__(self, rdclass, rdtype, eui):
+ super(EUIBase, self).__init__(rdclass, rdtype)
+ if len(eui) != self.byte_len:
+ raise dns.exception.FormError('EUI%s rdata has to have %s bytes'
+ % (self.byte_len * 8, self.byte_len))
+ self.eui = eui
+
+ def to_text(self, origin=None, relativize=True, **kw):
+ return dns.rdata._hexify(self.eui, chunksize=2).replace(' ', '-')
+
+ def from_text(cls, rdclass, rdtype, tok, origin=None, relativize=True):
+ text = tok.get_string()
+ tok.get_eol()
+ if len(text) != cls.text_len:
+ raise dns.exception.SyntaxError(
+ 'Input text must have %s characters' % cls.text_len)
+ expected_dash_idxs = range(2, cls.byte_len * 3 - 1, 3)
+ for i in expected_dash_idxs:
+ if text[i] != '-':
+ raise dns.exception.SyntaxError('Dash expected at position %s'
+ % i)
+ text = text.replace('-', '')
+ try:
+ data = binascii.unhexlify(text)
+ except (ValueError, TypeError) as ex:
+ raise dns.exception.SyntaxError('Hex decoding error: %s' % str(ex))
+ return cls(rdclass, rdtype, data)
+
+ from_text = classmethod(from_text)
+
+ def to_wire(self, file, compress=None, origin=None):
+ file.write(self.eui)
+
+ def from_wire(cls, rdclass, rdtype, wire, current, rdlen, origin=None):
+ eui = wire[current:current + rdlen].unwrap()
+ return cls(rdclass, rdtype, eui)
+
+ from_wire = classmethod(from_wire)
diff --git a/tests/test_rdtypeanyeui.py b/tests/test_rdtypeanyeui.py
new file mode 100644
index 0000000..800d103
--- /dev/null
+++ b/tests/test_rdtypeanyeui.py
@@ -0,0 +1,223 @@
+# Copyright (C) 2015 Red Hat, Inc.
+# Author: Petr Spacek <pspacek@redhat.com>
+#
+# 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 RED HAT 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 unittest
+try:
+ from StringIO import StringIO
+except ImportError:
+ from io import BytesIO as StringIO
+
+import dns.rrset
+import dns.rdtypes.ANY.EUI48
+import dns.exception
+
+
+class RdtypeAnyEUI48TestCase(unittest.TestCase):
+ def testInstOk(self):
+ '''Valid binary input.'''
+ eui = b'\x01\x23\x45\x67\x89\xab'
+ inst = dns.rdtypes.ANY.EUI48.EUI48(dns.rdataclass.IN,
+ dns.rdatatype.EUI48,
+ eui)
+ self.assertEqual(inst.eui, eui)
+
+ def testInstLength(self):
+ '''Incorrect input length.'''
+ eui = b'\x01\x23\x45\x67\x89\xab\xcd'
+ with self.assertRaises(dns.exception.FormError):
+ dns.rdtypes.ANY.EUI48.EUI48(dns.rdataclass.IN,
+ dns.rdatatype.EUI48,
+ eui)
+
+ def testFromTextOk(self):
+ '''Valid text input.'''
+ r1 = dns.rrset.from_text('foo', 300, 'IN', 'EUI48',
+ '01-23-45-67-89-ab')
+ eui = b'\x01\x23\x45\x67\x89\xab'
+ self.assertEqual(r1[0].eui, eui)
+
+ def testFromTextLength(self):
+ '''Invalid input length.'''
+ with self.assertRaises(dns.exception.SyntaxError):
+ dns.rrset.from_text('foo', 300, 'IN', 'EUI48',
+ '00-01-23-45-67-89-ab')
+
+ def testFromTextDelim(self):
+ '''Invalid delimiter.'''
+ with self.assertRaises(dns.exception.SyntaxError):
+ dns.rrset.from_text('foo', 300, 'IN', 'EUI48', '01_23-45-67-89-ab')
+
+ def testFromTextExtraDash(self):
+ '''Extra dash instead of hex digit.'''
+ with self.assertRaises(dns.exception.SyntaxError):
+ dns.rrset.from_text('foo', 300, 'IN', 'EUI48', '0--23-45-67-89-ab')
+
+ def testFromTextMultipleTokens(self):
+ '''Invalid input divided to multiple tokens.'''
+ with self.assertRaises(dns.exception.SyntaxError):
+ dns.rrset.from_text('foo', 300, 'IN', 'EUI48', '01 23-45-67-89-ab')
+
+ def testFromTextInvalidHex(self):
+ '''Invalid hexadecimal input.'''
+ with self.assertRaises(dns.exception.SyntaxError):
+ dns.rrset.from_text('foo', 300, 'IN', 'EUI48', 'g0-23-45-67-89-ab')
+
+ def testToTextOk(self):
+ '''Valid text output.'''
+ eui = b'\x01\x23\x45\x67\x89\xab'
+ exp_text = '01-23-45-67-89-ab'
+ inst = dns.rdtypes.ANY.EUI48.EUI48(dns.rdataclass.IN,
+ dns.rdatatype.EUI48,
+ eui)
+ text = inst.to_text()
+ self.assertEqual(exp_text, text)
+
+ def testToWire(self):
+ '''Valid wire format.'''
+ eui = b'\x01\x23\x45\x67\x89\xab'
+ inst = dns.rdtypes.ANY.EUI48.EUI48(dns.rdataclass.IN,
+ dns.rdatatype.EUI48,
+ eui)
+ buff = StringIO()
+ inst.to_wire(buff)
+ self.assertEqual(buff.getvalue(), eui)
+
+ def testFromWireOk(self):
+ '''Valid wire format.'''
+ eui = b'\x01\x23\x45\x67\x89\xab'
+ pad_len = 100
+ wire = dns.wiredata.WireData(b'x' * pad_len + eui + b'y' * pad_len * 2)
+ inst = dns.rdtypes.ANY.EUI48.EUI48.from_wire(dns.rdataclass.IN,
+ dns.rdatatype.EUI48,
+ wire,
+ pad_len,
+ len(eui))
+ self.assertEqual(inst.eui, eui)
+
+ def testFromWireLength(self):
+ '''Valid wire format.'''
+ eui = b'\x01\x23\x45\x67\x89'
+ pad_len = 100
+ wire = dns.wiredata.WireData(b'x' * pad_len + eui + b'y' * pad_len * 2)
+ with self.assertRaises(dns.exception.FormError):
+ dns.rdtypes.ANY.EUI48.EUI48.from_wire(dns.rdataclass.IN,
+ dns.rdatatype.EUI48,
+ wire,
+ pad_len,
+ len(eui))
+
+
+class RdtypeAnyEUI64TestCase(unittest.TestCase):
+ def testInstOk(self):
+ '''Valid binary input.'''
+ eui = b'\x01\x23\x45\x67\x89\xab\xcd\xef'
+ inst = dns.rdtypes.ANY.EUI64.EUI64(dns.rdataclass.IN,
+ dns.rdatatype.EUI64,
+ eui)
+ self.assertEqual(inst.eui, eui)
+
+ def testInstLength(self):
+ '''Incorrect input length.'''
+ eui = b'\x01\x23\x45\x67\x89\xab'
+ with self.assertRaises(dns.exception.FormError):
+ dns.rdtypes.ANY.EUI64.EUI64(dns.rdataclass.IN,
+ dns.rdatatype.EUI64,
+ eui)
+
+ def testFromTextOk(self):
+ '''Valid text input.'''
+ r1 = dns.rrset.from_text('foo', 300, 'IN', 'EUI64',
+ '01-23-45-67-89-ab-cd-ef')
+ eui = b'\x01\x23\x45\x67\x89\xab\xcd\xef'
+ self.assertEqual(r1[0].eui, eui)
+
+ def testFromTextLength(self):
+ '''Invalid input length.'''
+ with self.assertRaises(dns.exception.SyntaxError):
+ dns.rrset.from_text('foo', 300, 'IN', 'EUI64',
+ '01-23-45-67-89-ab')
+
+ def testFromTextDelim(self):
+ '''Invalid delimiter.'''
+ with self.assertRaises(dns.exception.SyntaxError):
+ dns.rrset.from_text('foo', 300, 'IN', 'EUI64',
+ '01_23-45-67-89-ab-cd-ef')
+
+ def testFromTextExtraDash(self):
+ '''Extra dash instead of hex digit.'''
+ with self.assertRaises(dns.exception.SyntaxError):
+ dns.rrset.from_text('foo', 300, 'IN', 'EUI64',
+ '0--23-45-67-89-ab-cd-ef')
+
+ def testFromTextMultipleTokens(self):
+ '''Invalid input divided to multiple tokens.'''
+ with self.assertRaises(dns.exception.SyntaxError):
+ dns.rrset.from_text('foo', 300, 'IN', 'EUI64',
+ '01 23-45-67-89-ab-cd-ef')
+
+ def testFromTextInvalidHex(self):
+ '''Invalid hexadecimal input.'''
+ with self.assertRaises(dns.exception.SyntaxError):
+ dns.rrset.from_text('foo', 300, 'IN', 'EUI64',
+ 'g0-23-45-67-89-ab-cd-ef')
+
+ def testToTextOk(self):
+ '''Valid text output.'''
+ eui = b'\x01\x23\x45\x67\x89\xab\xcd\xef'
+ exp_text = '01-23-45-67-89-ab-cd-ef'
+ inst = dns.rdtypes.ANY.EUI64.EUI64(dns.rdataclass.IN,
+ dns.rdatatype.EUI64,
+ eui)
+ text = inst.to_text()
+ self.assertEqual(exp_text, text)
+
+ def testToWire(self):
+ '''Valid wire format.'''
+ eui = b'\x01\x23\x45\x67\x89\xab\xcd\xef'
+ inst = dns.rdtypes.ANY.EUI64.EUI64(dns.rdataclass.IN,
+ dns.rdatatype.EUI64,
+ eui)
+ buff = StringIO()
+ inst.to_wire(buff)
+ self.assertEqual(buff.getvalue(), eui)
+
+ def testFromWireOk(self):
+ '''Valid wire format.'''
+ eui = b'\x01\x23\x45\x67\x89\xab\xcd\xef'
+ pad_len = 100
+ wire = dns.wiredata.WireData(b'x' * pad_len + eui + b'y' * pad_len * 2)
+ inst = dns.rdtypes.ANY.EUI64.EUI64.from_wire(dns.rdataclass.IN,
+ dns.rdatatype.EUI64,
+ wire,
+ pad_len,
+ len(eui))
+ self.assertEqual(inst.eui, eui)
+
+ def testFromWireLength(self):
+ '''Valid wire format.'''
+ eui = b'\x01\x23\x45\x67\x89'
+ pad_len = 100
+ wire = dns.wiredata.WireData(b'x' * pad_len + eui + b'y' * pad_len * 2)
+ with self.assertRaises(dns.exception.FormError):
+ dns.rdtypes.ANY.EUI64.EUI64.from_wire(dns.rdataclass.IN,
+ dns.rdatatype.EUI64,
+ wire,
+ pad_len,
+ len(eui))
+
+
+if __name__ == '__main__':
+ unittest.main()