def test_sorts_output_by_hostname(self): network = IPNetwork("10.0.0.1/23") domain = factory.make_string() expected_hostname = "10-0-%s-$." + domain + "." expected_rdns = "$.%s.0.10.in-addr.arpa." directives = list( DNSReverseZoneConfig.get_GENERATE_directives( network, domain, DomainInfo(IPNetwork("10.0.0.0/24"), "0.0.10.in-addr.arpa"), )) self.expectThat( directives[0], Equals(("0-255", expected_rdns % "0", expected_hostname % "0")), ) expected_hostname = "10-0-%s-$." + domain + "." expected_rdns = "$.%s.0.10.in-addr.arpa." directives = list( DNSReverseZoneConfig.get_GENERATE_directives( network, domain, DomainInfo(IPNetwork("10.0.1.0/24"), "1.0.10.in-addr.arpa"), )) self.expectThat( directives[0], Equals(("0-255", expected_rdns % "1", expected_hostname % "1")), )
def test_writes_reverse_dns_zone_config_for_small_network(self): target_dir = patch_dns_config_path(self) domain = factory.make_string() ns_host_name = factory.make_name("ns") network = IPNetwork("192.168.0.1/26") dynamic_network = IPNetwork("192.168.0.1/28") dns_zone_config = DNSReverseZoneConfig( domain, serial=random.randint(1, 100), network=network, ns_host_name=ns_host_name, dynamic_ranges=[ IPRange(dynamic_network.first, dynamic_network.last) ], ) dns_zone_config.write_config() reverse_zone_name = "0-26.0.168.192.in-addr.arpa" reverse_file_name = "zone.0-26.0.168.192.in-addr.arpa" expected_GEN_direct = dns_zone_config.get_GENERATE_directives( dynamic_network, domain, DomainInfo(network, reverse_zone_name)) expected = ContainsAll(["30 IN NS %s." % ns_host_name] + [ "$GENERATE %s %s IN PTR %s" % (iterator_values, reverse_dns, hostname) for iterator_values, reverse_dns, hostname in expected_GEN_direct ]) self.assertThat( os.path.join(target_dir, reverse_file_name), FileContains(matcher=expected), )
def test_returns_single_entry_for_weird_small_range(self): ip_range = IPRange('10.0.0.1', '10.0.0.255') domain = factory.make_string() directives = DNSReverseZoneConfig.get_GENERATE_directives( ip_range, domain, DomainInfo(IPNetwork('10.0.0.0/24'), '0.0.10.in-addr.arpa')) self.expectThat(directives, HasLength(1))
def test_writes_reverse_dns_zone_config(self): target_dir = patch_dns_config_path(self) domain = factory.make_string() ns_host_name = factory.make_name("ns") network = IPNetwork('192.168.0.1/22') dynamic_network = IPNetwork('192.168.0.1/28') dns_zone_config = DNSReverseZoneConfig(domain, serial=random.randint(1, 100), network=network, ns_host_name=ns_host_name, dynamic_ranges=[ IPRange( dynamic_network.first, dynamic_network.last) ]) dns_zone_config.write_config() for sub in range(4): reverse_file_name = 'zone.%d.168.192.in-addr.arpa' % sub expected_GEN_direct = dns_zone_config.get_GENERATE_directives( dynamic_network, domain, DomainInfo(IPNetwork('192.168.%d.0/24' % sub), "%d.168.192.in-addr.arpa" % sub)) expected = ContainsAll(['30 IN NS %s.' % ns_host_name] + [ '$GENERATE %s %s IN PTR %s' % (iterator_values, reverse_dns, hostname) for iterator_values, reverse_dns, hostname in expected_GEN_direct ]) self.assertThat(os.path.join(target_dir, reverse_file_name), FileContains(matcher=expected))
def test_ignores_networks_that_span_slash_16s(self): # If the upper and lower bounds of a range span two /16 networks # (but contain between them no more than 65536 addresses), # get_GENERATE_directives() will return early ip_range = IPRange('10.0.0.55', '10.1.0.54') directives = DNSReverseZoneConfig.get_GENERATE_directives( ip_range, factory.make_string(), DomainInfo(IPNetwork('10.0.0.0/15'), "do not care")) self.assertEqual([], directives)
def test_ignores_network_larger_than_slash_16(self): network = IPNetwork("%s/15" % factory.make_ipv4_address()) self.assertEqual( [], DNSReverseZoneConfig.get_GENERATE_directives( network, factory.make_string(), DomainInfo(network, "do not care"), ), )
def test_returns_single_entry_for_slash_24_network(self): network = IPNetwork("%s/24" % factory.make_ipv4_address()) reverse = ".".join(IPAddress(network).reverse_dns.split(".")[1:-1]) domain = factory.make_string() expected_generate_directives = self.get_expected_generate_directives( network, domain) directives = DNSReverseZoneConfig.get_GENERATE_directives( network, domain, DomainInfo(network, reverse)) self.expectThat(directives, HasLength(1)) self.assertItemsEqual(expected_generate_directives, directives)
def test_returns_256_entries_for_slash_16_network(self): network = IPNetwork(factory.make_ipv4_network(slash=16)) reverse = IPAddress(network.first).reverse_dns.split(".")[2:-1] reverse = ".".join(reverse) domain = factory.make_string() expected_generate_directives = self.get_expected_generate_directives( network, domain) directives = DNSReverseZoneConfig.get_GENERATE_directives( network, domain, DomainInfo(network, reverse)) self.expectThat(directives, HasLength(256)) self.assertItemsEqual(expected_generate_directives, directives)
def test_excplicitly(self): # The other tests in this TestCase rely on # get_expected_generate_directives(), which is quite dense. Here # we test get_GENERATE_directives() explicitly. ip_range = IPRange('192.168.0.55', '192.168.2.128') expected_directives = [ ("55-255", "$.0.168.192.in-addr.arpa.", "192-168-0-$.domain."), ("0-255", "$.1.168.192.in-addr.arpa.", "192-168-1-$.domain."), ("0-128", "$.2.168.192.in-addr.arpa.", "192-168-2-$.domain."), ] self.assertItemsEqual( expected_directives, DNSReverseZoneConfig.get_GENERATE_directives( ip_range, domain="domain", zone_info=DomainInfo(IPNetwork('192.168.0.0/16'), "168.192.in-addr.arpa")))
def test_reverse_zone_file(self): # DNSReverseZoneConfig calculates the reverse zone file name # correctly for IPv4 and IPv6 networks. # As long as the network size ends on a "nice" boundary (multiple of # 8 for IPv4, multiple of 4 for IPv6), then there will be one reverse # zone for the subnet. When it isn't, then there will be 2-128 # individual reverse zones for the subnet. # A special case is the small subnet (less than 256 hosts for IPv4, # less than 16 hosts for IPv6), in which case, we follow RFC2317 with # the modern adjustment of using '-' instead of '/'. zn = "%d.0.0.0.0.0.0.0.0.0.0.0.4.0.1.f.1.0.8.a.b.0.1.0.0.2.ip6.arpa" expected = [ # IPv4 networks. # /22 ==> 4 /24 reverse zones ( IPNetwork("192.168.0.1/22"), [ DomainInfo( IPNetwork("192.168.%d.0/24" % i), "%d.168.192.in-addr.arpa" % i, ) for i in range(4) ], ), # /24 ==> 1 reverse zone ( IPNetwork("192.168.0.1/24"), [ DomainInfo(IPNetwork("192.168.0.0/24"), "0.168.192.in-addr.arpa") ], ), # /29 ==> 1 reverse zones, per RFC2317 ( IPNetwork("192.168.0.241/29"), [ DomainInfo( IPNetwork("192.168.0.240/29"), "240-29.0.168.192.in-addr.arpa", ) ], ), # IPv6 networks. # /32, 48, 56, 64 ==> 1 reverse zones ( IPNetwork("3ffe:801::/32"), [ DomainInfo(IPNetwork("3ffe:801::32"), "1.0.8.0.e.f.f.3.ip6.arpa") ], ), ( IPNetwork("2001:db8:0::/48"), [ DomainInfo( IPNetwork("2001:db8:0::/48"), "0.0.0.0.8.b.d.0.1.0.0.2.ip6.arpa", ) ], ), ( IPNetwork("2001:ba8:1f1:400::/56"), [ DomainInfo( IPNetwork("2001:ba8:1f1:400::/56"), "4.0.1.f.1.0.8.a.b.0.1.0.0.2.ip6.arpa", ) ], ), ( IPNetwork("2610:8:6800:1::/64"), [ DomainInfo( IPNetwork("2610:8:6800:1::/64"), "1.0.0.0.0.0.8.6.8.0.0.0.0.1.6.2.ip6.arpa", ) ], ), # /2 with hex digits ==> 4 /4 reverse zones ( IPNetwork("8000::/2"), [ DomainInfo(IPNetwork("8000::/4"), "8.ip6.arpa"), DomainInfo(IPNetwork("9000::/4"), "9.ip6.arpa"), DomainInfo(IPNetwork("a000::/4"), "a.ip6.arpa"), DomainInfo(IPNetwork("b000::/4"), "b.ip6.arpa"), ], ), # /103 ==> 2 /104 reverse zones ( IPNetwork("2001:ba8:1f1:400::/103"), [ DomainInfo( IPNetwork("2001:ba8:1f1:400:0:0:%d00:0000/104" % i), zn % i, ) for i in range(2) ], ), # /125 ==> 1 reverse zone, based on RFC2317 ( IPNetwork("2001:ba8:1f1:400::/125"), [ DomainInfo( IPNetwork("2001:ba8:1f1:400::/125"), "0-125.%s" % (IPAddress("2001:ba8:1f1:400::").reverse_dns[2:-1]), ) ], ), ] results = [] for network, _ in expected: domain = factory.make_name("zone") dns_zone_config = DNSReverseZoneConfig(domain, network=network) results.append((network, dns_zone_config.zone_info)) # Make sure we have the right number of elements. self.assertEqual(len(expected), len(results)) # And that the zone names chosen for each element are correct. for net in range(len(expected)): for zi in range(len(expected[net][1])): self.assertItemsEqual( expected[net][1][zi].zone_name, results[net][1][zi].zone_name, )