# Copyright (C) Dnspython Contributors, see LICENSE for text of ISC license # Copyright (C) 2003-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 unittest import binascii import socket import dns.exception import dns.ipv4 import dns.ipv6 import dns.inet # for convenience aton4 = dns.ipv4.inet_aton ntoa4 = dns.ipv4.inet_ntoa aton6 = dns.ipv6.inet_aton ntoa6 = dns.ipv6.inet_ntoa v4_bad_addrs = ['256.1.1.1', '1.1.1', '1.1.1.1.1', '+1.1.1.1', '1.1.1.1+', '1..2.3.4', '.1.2.3.4', '1.2.3.4.'] class NtoAAtoNTestCase(unittest.TestCase): def test_aton1(self): a = aton6('::') self.assertEqual(a, b'\x00' * 16) def test_aton2(self): a = aton6('::1') self.assertEqual(a, b'\x00' * 15 + b'\x01') def test_aton3(self): a = aton6('::10.0.0.1') self.assertEqual(a, b'\x00' * 12 + b'\x0a\x00\x00\x01') def test_aton4(self): a = aton6('abcd::dcba') self.assertEqual(a, b'\xab\xcd' + b'\x00' * 12 + b'\xdc\xba') def test_aton5(self): a = aton6('1:2:3:4:5:6:7:8') self.assertEqual(a, binascii.unhexlify(b'00010002000300040005000600070008')) def test_bad_aton1(self): def bad(): aton6('abcd:dcba') self.assertRaises(dns.exception.SyntaxError, bad) def test_bad_aton2(self): def bad(): aton6('abcd::dcba::1') self.assertRaises(dns.exception.SyntaxError, bad) def test_bad_aton3(self): def bad(): aton6('1:2:3:4:5:6:7:8:9') self.assertRaises(dns.exception.SyntaxError, bad) def test_bad_aton4(self): def bad(): aton4('001.002.003.004') self.assertRaises(dns.exception.SyntaxError, bad) def test_aton6(self): a = aton6('::') self.assertEqual(a, b'\x00' * 16) def test_aton7(self): a = aton6('::1') self.assertEqual(a, b'\x00' * 15 + b'\x01') def test_aton8(self): a = aton6('::10.0.0.1') self.assertEqual(a, b'\x00' * 12 + b'\x0a\x00\x00\x01') def test_aton9(self): a = aton6('abcd::dcba') self.assertEqual(a, b'\xab\xcd' + b'\x00' * 12 + b'\xdc\xba') def test_ntoa1(self): b = binascii.unhexlify(b'00010002000300040005000600070008') t = ntoa6(b) self.assertEqual(t, '1:2:3:4:5:6:7:8') def test_ntoa2(self): b = b'\x00' * 16 t = ntoa6(b) self.assertEqual(t, '::') def test_ntoa3(self): b = b'\x00' * 15 + b'\x01' t = ntoa6(b) self.assertEqual(t, '::1') def test_ntoa4(self): b = b'\x80' + b'\x00' * 15 t = ntoa6(b) self.assertEqual(t, '8000::') def test_ntoa5(self): b = b'\x01\xcd' + b'\x00' * 12 + b'\x03\xef' t = ntoa6(b) self.assertEqual(t, '1cd::3ef') def test_ntoa6(self): b = binascii.unhexlify(b'ffff00000000ffff000000000000ffff') t = ntoa6(b) self.assertEqual(t, 'ffff:0:0:ffff::ffff') def test_ntoa7(self): b = binascii.unhexlify(b'00000000ffff000000000000ffffffff') t = ntoa6(b) self.assertEqual(t, '0:0:ffff::ffff:ffff') def test_ntoa8(self): b = binascii.unhexlify(b'ffff0000ffff00000000ffff00000000') t = ntoa6(b) self.assertEqual(t, 'ffff:0:ffff::ffff:0:0') def test_ntoa9(self): b = binascii.unhexlify(b'0000000000000000000000000a000001') t = ntoa6(b) self.assertEqual(t, '::10.0.0.1') def test_ntoa10(self): b = binascii.unhexlify(b'0000000000000000000000010a000001') t = ntoa6(b) self.assertEqual(t, '::1:a00:1') def test_ntoa11(self): b = binascii.unhexlify(b'00000000000000000000ffff0a000001') t = ntoa6(b) self.assertEqual(t, '::ffff:10.0.0.1') def test_ntoa12(self): b = binascii.unhexlify(b'000000000000000000000000ffffffff') t = ntoa6(b) self.assertEqual(t, '::255.255.255.255') def test_ntoa13(self): b = binascii.unhexlify(b'00000000000000000000ffffffffffff') t = ntoa6(b) self.assertEqual(t, '::ffff:255.255.255.255') def test_ntoa14(self): b = binascii.unhexlify(b'0000000000000000000000000001ffff') t = ntoa6(b) self.assertEqual(t, '::0.1.255.255') def test_ntoa15(self): # This exercises the current_len > best_len branch in the <= case. b = binascii.unhexlify(b'0000ffff00000000ffff00000000ffff') t = ntoa6(b) self.assertEqual(t, '0:ffff::ffff:0:0:ffff') def test_bad_ntoa1(self): def bad(): ntoa6(b'') self.assertRaises(ValueError, bad) def test_bad_ntoa2(self): def bad(): ntoa6(b'\x00' * 17) self.assertRaises(ValueError, bad) def test_bad_ntoa3(self): def bad(): ntoa4(b'\x00' * 5) # Ideally we'd have been consistent and raised ValueError as # we do for IPv6, but oh well! self.assertRaises(dns.exception.SyntaxError, bad) def test_good_v4_aton(self): pairs = [('1.2.3.4', b'\x01\x02\x03\x04'), ('255.255.255.255', b'\xff\xff\xff\xff'), ('0.0.0.0', b'\x00\x00\x00\x00')] for (t, b) in pairs: b1 = aton4(t) t1 = ntoa4(b1) self.assertEqual(b1, b) self.assertEqual(t1, t) def test_bad_v4_aton(self): def make_bad(a): def bad(): return aton4(a) return bad for addr in v4_bad_addrs: self.assertRaises(dns.exception.SyntaxError, make_bad(addr)) def test_bad_v6_aton(self): addrs = ['+::0', '0::0::', '::0::', '1:2:3:4:5:6:7:8:9', ':::::::'] embedded = ['::' + x for x in v4_bad_addrs] addrs.extend(embedded) def make_bad(a): def bad(): x = aton6(a) return bad for addr in addrs: self.assertRaises(dns.exception.SyntaxError, make_bad(addr)) def test_rfc5952_section_4_2_2(self): addr = '2001:db8:0:1:1:1:1:1' b1 = aton6(addr) t1 = ntoa6(b1) self.assertEqual(t1, addr) def test_is_mapped(self): t1 = '2001:db8:0:1:1:1:1:1' t2 = '::ffff:127.0.0.1' t3 = '1::ffff:127.0.0.1' self.assertFalse(dns.ipv6.is_mapped(aton6(t1))) self.assertTrue(dns.ipv6.is_mapped(aton6(t2))) self.assertFalse(dns.ipv6.is_mapped(aton6(t3))) def test_is_multicast(self): t1 = '223.0.0.1' t2 = '240.0.0.1' t3 = '224.0.0.1' t4 = '239.0.0.1' t5 = 'fe00::1' t6 = 'ff00::1' self.assertFalse(dns.inet.is_multicast(t1)) self.assertFalse(dns.inet.is_multicast(t2)) self.assertTrue(dns.inet.is_multicast(t3)) self.assertTrue(dns.inet.is_multicast(t4)) self.assertFalse(dns.inet.is_multicast(t5)) self.assertTrue(dns.inet.is_multicast(t6)) def test_is_multicast_bad_input(self): def bad(): dns.inet.is_multicast('hello world') self.assertRaises(ValueError, bad) def test_ignore_scope(self): t1 = 'fe80::1%lo0' t2 = 'fe80::1' self.assertEqual(aton6(t1, True), aton6(t2)) def test_do_not_ignore_scope(self): def bad(): t1 = 'fe80::1%lo0' aton6(t1) self.assertRaises(dns.exception.SyntaxError, bad) def test_multiple_scopes_bad(self): def bad(): t1 = 'fe80::1%lo0%lo1' aton6(t1, True) self.assertRaises(dns.exception.SyntaxError, bad) def test_ptontop(self): for (af, a) in [(socket.AF_INET, '1.2.3.4'), (socket.AF_INET6, '2001:db8:0:1:1:1:1:1')]: self.assertEqual(dns.inet.inet_ntop(af, dns.inet.inet_pton(af, a)), a) def test_isaddress(self): for (t, e) in [('1.2.3.4', True), ('2001:db8:0:1:1:1:1:1', True), ('hello world', False), ('http://www.dnspython.org', False), ('1.2.3.4a', False), ('2001:db8:0:1:1:1:1:q1', False)]: self.assertEqual(dns.inet.is_address(t), e) def test_low_level_address_tuple(self): t = dns.inet.low_level_address_tuple(('1.2.3.4', 53)) self.assertEqual(t, ('1.2.3.4', 53)) t = dns.inet.low_level_address_tuple(('2600::1', 53)) self.assertEqual(t, ('2600::1', 53, 0, 0)) t = dns.inet.low_level_address_tuple(('1.2.3.4', 53), socket.AF_INET) self.assertEqual(t, ('1.2.3.4', 53)) t = dns.inet.low_level_address_tuple(('2600::1', 53), socket.AF_INET6) self.assertEqual(t, ('2600::1', 53, 0, 0)) t = dns.inet.low_level_address_tuple(('fd80::1%2', 53), socket.AF_INET6) self.assertEqual(t, ('fd80::1', 53, 0, 2)) try: # This can fail on windows for python < 3.8, so we tolerate # the failure and only test if we have something we can work # with. info = socket.if_nameindex() except Exception: info = [] if info: # find first thing on list that is not zero (should be first thing! pair = None for p in info: if p[0] != 0: pair = p break if pair: address = 'fd80::1%' + pair[1] t = dns.inet.low_level_address_tuple((address, 53), socket.AF_INET6) self.assertEqual(t, ('fd80::1', 53, 0, pair[0])) def bad(): bogus = socket.AF_INET + socket.AF_INET6 + 1 t = dns.inet.low_level_address_tuple(('2600::1', 53), bogus) self.assertRaises(NotImplementedError, bad) def test_bogus_family(self): self.assertRaises(NotImplementedError, lambda: dns.inet.inet_pton(12345, 'bogus')) self.assertRaises(NotImplementedError, lambda: dns.inet.inet_ntop(12345, b'bogus')) if __name__ == '__main__': unittest.main()