# 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()