--- /dev/null
+# 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)
--- /dev/null
+# 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()