Esempio n. 1
0
 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))
Esempio n. 2
0
 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),
     )
Esempio n. 3
0
    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")),
        )
Esempio n. 4
0
 def test_reverse_config_file_is_world_readable(self):
     patch_dns_config_path(self)
     dns_zone_config = DNSReverseZoneConfig(
         factory.make_string(),
         serial=random.randint(1, 100),
         network=factory.make_ipv4_network())
     dns_zone_config.write_config()
     for tgt in [zi.target_path for zi in dns_zone_config.zone_info]:
         filepath = FilePath(tgt)
         self.assertTrue(filepath.getPermissions().other.read)
Esempio n. 5
0
 def test_writes_dns_zone_config_with_NS_record(self):
     target_dir = patch_dns_config_path(self)
     network = factory.make_ipv4_network()
     ns_host_name = factory.make_name("ns")
     dns_zone_config = DNSReverseZoneConfig(factory.make_string(),
                                            serial=random.randint(1, 100),
                                            ns_host_name=ns_host_name,
                                            network=network)
     dns_zone_config.write_config()
     for zone_name in [zi.zone_name for zi in dns_zone_config.zone_info]:
         self.assertThat(
             os.path.join(target_dir, 'zone.%s' % zone_name),
             FileContains(matcher=Contains('30 IN NS %s.' % ns_host_name)))
Esempio n. 6
0
 def test_bind_write_configuration_writes_file(self):
     domain = factory.make_string()
     zones = [
         DNSReverseZoneConfig(domain,
                              serial=random.randint(1, 100),
                              network=factory.make_ipv4_network()),
         DNSReverseZoneConfig(domain,
                              serial=random.randint(1, 100),
                              network=factory.make_ipv6_network()),
     ]
     actions.bind_write_configuration(zones=zones, trusted_networks=[])
     self.assertThat(os.path.join(self.dns_conf_dir, MAAS_NAMED_CONF_NAME),
                     FileExists())
Esempio n. 7
0
    def test_bind_write_zones_writes_file(self):
        domain = factory.make_string()
        network = IPNetwork("192.168.0.3/24")
        dns_ip_list = [factory.pick_ip_in_network(network)]
        ip = factory.pick_ip_in_network(network)
        ttl = random.randint(10, 1000)
        forward_zone = DNSForwardZoneConfig(
            domain,
            serial=random.randint(1, 100),
            mapping={
                factory.make_string(): HostnameIPMapping(None, ttl, {ip})
            },
            dns_ip_list=dns_ip_list,
        )
        reverse_zone = DNSReverseZoneConfig(
            domain, serial=random.randint(1, 100), network=network
        )
        actions.bind_write_zones(zones=[forward_zone, reverse_zone])

        forward_file_name = "zone.%s" % domain
        reverse_file_name = "zone.0.168.192.in-addr.arpa"
        expected_files = [
            join(self.dns_conf_dir, forward_file_name),
            join(self.dns_conf_dir, reverse_file_name),
        ]
        self.assertThat(expected_files, AllMatch(FileExists()))
Esempio n. 8
0
 def test_get_ptr_mapping_drops_IPs_not_in_network(self):
     name = factory.make_string()
     network = IPNetwork("192.12.0.1/30")
     in_network_mapping = {
         factory.make_string(): factory.pick_ip_in_network(network),
         factory.make_string(): factory.pick_ip_in_network(network),
     }
     expected = [
         (
             IPAddress(ip).reverse_dns.split(".")[0],
             30,
             "%s.%s." % (hostname, name),
         )
         for hostname, ip in in_network_mapping.items()
     ]
     mapping = {
         "%s.%s" % (hostname, name): HostnameIPMapping(None, 30, [ip])
         for hostname, ip in in_network_mapping.items()
     }
     extra_mapping = {
         factory.make_string(): HostnameIPMapping(None, 30, ["192.50.0.2"]),
         factory.make_string(): HostnameIPMapping(None, 30, ["192.70.0.2"]),
     }
     mapping.update(extra_mapping)
     self.assertItemsEqual(
         expected, DNSReverseZoneConfig.get_PTR_mapping(mapping, network)
     )
Esempio n. 9
0
 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))
Esempio n. 10
0
 def test_computes_dns_config_file_paths_for_small_network(self):
     domain = factory.make_name('zone')
     reverse_file_name = 'zone.192-27.0.168.192.in-addr.arpa'
     dns_zone_config = DNSReverseZoneConfig(
         domain, network=IPNetwork("192.168.0.192/27"))
     self.assertEqual(1, len(dns_zone_config.zone_info))
     self.assertEqual(os.path.join(get_dns_config_dir(), reverse_file_name),
                      dns_zone_config.zone_info[0].target_path)
Esempio n. 11
0
 def test_ignores_generate_directives_for_v6_dynamic_ranges(self):
     patch_dns_config_path(self)
     domain = factory.make_string()
     network = IPNetwork("192.168.0.1/22")
     dynamic_network = IPNetwork("%s/64" % factory.make_ipv6_address())
     dns_zone_config = DNSReverseZoneConfig(
         domain,
         serial=random.randint(1, 100),
         network=network,
         dynamic_ranges=[
             IPRange(dynamic_network.first, dynamic_network.last)
         ],
     )
     get_generate_directives = self.patch(dns_zone_config,
                                          "get_GENERATE_directives")
     dns_zone_config.write_config()
     self.assertThat(get_generate_directives, MockNotCalled())
Esempio n. 12
0
 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)
Esempio n. 13
0
 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"),
         ),
     )
Esempio n. 14
0
 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)
Esempio n. 15
0
 def test_computes_dns_config_file_paths(self):
     domain = factory.make_name('zone')
     reverse_file_name = [
         'zone.%d.168.192.in-addr.arpa' % i for i in range(4)
     ]
     dns_zone_config = DNSReverseZoneConfig(
         domain, network=IPNetwork("192.168.0.0/22"))
     for i in range(4):
         self.assertEqual(
             os.path.join(get_dns_config_dir(), reverse_file_name[i]),
             dns_zone_config.zone_info[i].target_path)
Esempio n. 16
0
    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)
Esempio n. 17
0
 def test_fields(self):
     domain = factory.make_string()
     serial = random.randint(1, 200)
     network = factory.make_ipv4_network()
     dns_zone_config = DNSReverseZoneConfig(domain,
                                            serial=serial,
                                            network=network)
     self.assertThat(
         dns_zone_config,
         MatchesStructure.byEquality(domain=domain,
                                     serial=serial,
                                     _network=network),
     )
Esempio n. 18
0
 def test_get_ptr_mapping(self):
     name = factory.make_string()
     network = IPNetwork('192.12.0.1/30')
     hosts = {
         factory.make_string(): factory.pick_ip_in_network(network),
         factory.make_string(): factory.pick_ip_in_network(network),
     }
     expected = [(IPAddress(ip).reverse_dns.split('.')[0], 30,
                  '%s.%s.' % (hostname, name))
                 for hostname, ip in hosts.items()]
     mapping = {
         "%s.%s" % (hostname, name): HostnameIPMapping(None, 30, {ip})
         for hostname, ip in hosts.items()
     }
     self.assertItemsEqual(
         expected, DNSReverseZoneConfig.get_PTR_mapping(mapping, network))
Esempio n. 19
0
 def test_write_config_writes_config(self):
     target_dir = patch_dns_config_path(self)
     domain = factory.make_string()
     network = IPNetwork('192.168.0.3/24')
     ip = factory.pick_ip_in_network(network)
     forward_zone = DNSForwardZoneConfig(
         domain, mapping={factory.make_string(): ip})
     reverse_zone = DNSReverseZoneConfig(domain, network=network)
     dnsconfig = DNSConfig((forward_zone, reverse_zone))
     dnsconfig.write_config()
     self.assertThat(
         os.path.join(target_dir, MAAS_NAMED_CONF_NAME),
         FileContains(matcher=ContainsAll([
             'zone.%s' % domain,
             'zone.0.168.192.in-addr.arpa',
             MAAS_NAMED_RNDC_CONF_NAME,
         ])))
Esempio n. 20
0
 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")))
Esempio n. 21
0
 def test_no_overlap(self):
     expected = [
         (
             [(
                 IPNetwork("10.232.32.0/21"),
                 [IPNetwork("10.232.36.0/24")],
             )],
             [
                 {
                     "excludes": [
                         "36.232.10.in-addr.arpa",
                     ],
                     "includes": [
                         "32.232.10.in-addr.arpa",
                     ],
                 },
             ],
         ),
         (
             [(
                 IPNetwork("10.232.36.0/24"),
                 [IPNetwork("10.232.32.0/21")],
             )],
             [
                 {
                     "includes": [
                         "36.232.10.in-addr.arpa",
                     ],
                 },
             ],
         ),
         (
             [(
                 IPNetwork("10.232.32.0/21"),
                 [
                     IPNetwork("10.232.35.0/24"),
                     IPNetwork("10.232.36.0/24"),
                 ],
             )],
             [
                 {
                     "excludes": [
                         "35.232.10.in-addr.arpa",
                         "36.232.10.in-addr.arpa",
                     ],
                     "includes": [
                         "32.232.10.in-addr.arpa",
                     ],
                 },
             ],
         ),
     ]
     for t_case in expected:
         nets = t_case[0]
         expected = t_case[1]
         domain = factory.make_name("zone")
         for (idx, net) in enumerate(nets):
             network = net[0]
             other_subnets = net[1]
             dns_zone_config = DNSReverseZoneConfig(domain,
                                                    network=network,
                                                    exclude=other_subnets)
             zone_names = set(
                 [z.zone_name for z in dns_zone_config.zone_info])
             for exclude in expected[idx].get("excludes", []):
                 self.assertFalse(exclude in zone_names)
             for include in expected[idx].get("includes", []):
                 self.assertTrue(include in zone_names)
Esempio n. 22
0
 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,
             )
Esempio n. 23
0
    def _gen_reverse_zones(subnets, serial, ns_host_name, mappings,
                           default_ttl):
        """Generator of reverse zones, sorted by network."""

        subnets = set(subnets)
        # Generate the list of parent networks for rfc2317 glue.  Note that we
        # need to handle the case where we are controlling both the small net
        # and a bigger network containing the /24, not just a /24 network.
        rfc2317_glue = {}
        for subnet in subnets:
            network = IPNetwork(subnet.cidr)
            if subnet.rdns_mode == RDNS_MODE.RFC2317:
                # If this is a small subnet and  we are doing RFC2317 glue for
                # it, then we need to combine that with any other such subnets
                # We need to know this before we start creating reverse DNS
                # zones.
                if network.version == 4 and network.prefixlen > 24:
                    # Turn 192.168.99.32/29 into 192.168.99.0/24
                    basenet = IPNetwork(
                        "%s/24" % IPNetwork("%s/24" % network.network).network)
                    rfc2317_glue.setdefault(basenet, set()).add(network)
                elif network.version == 6 and network.prefixlen > 124:
                    basenet = IPNetwork(
                        "%s/124" %
                        IPNetwork("%s/124" % network.network).network)
                    rfc2317_glue.setdefault(basenet, set()).add(network)

        # Since get_hostname_ip_mapping(Subnet) ignores Subnet.id, so we can
        # just do it once and be happy.  LP#1600259
        if len(subnets):
            mappings['reverse'] = mappings[Subnet.objects.first()]

        # For each of the zones that we are generating (one or more per
        # subnet), compile the zone from:
        # 1. Dynamic ranges on this subnet.
        # 2. Node: ip mapping(subnet), including DNSResource records for
        #    StaticIPAddresses in this subnet.
        # All of this needs to be done smallest to largest so that we can
        # correctly gather the rfc2317 glue that we need.  Failure to sort
        # means that we wind up grabbing (and deleting) the rfc2317 glue info
        # while processing the wrong network.
        for subnet in sorted(
                subnets,
                key=lambda subnet: IPNetwork(subnet.cidr).prefixlen,
                reverse=True):
            network = IPNetwork(subnet.cidr)
            if subnet.rdns_mode == RDNS_MODE.DISABLED:
                # If we are not doing reverse dns for this subnet, then just
                # skip to the next subnet.
                logger.debug("%s disabled subnet in DNS config list" %
                             subnet.cidr)
                continue

            # 1. Figure out the dynamic ranges.
            dynamic_ranges = [
                ip_range.netaddr_iprange
                for ip_range in subnet.get_dynamic_ranges()
            ]

            # 2. Start with the map of all of the nodes, including all
            # DNSResource-associated addresses.  We will prune this to just
            # entries for the subnet when we actually generate the zonefile.
            # If we get here, then we have subnets, so we noticed that above
            # and created mappings['reverse'].  LP#1600259
            mapping = mappings['reverse']

            # Use the default_domain as the name for the NS host in the reverse
            # zones.  If this network is actually a parent rfc2317 glue
            # network, then we need to generate the glue records.
            # We need to detect the need for glue in our networks that are
            # big.
            if ((network.version == 6 and network.prefixlen < 124)
                    or network.prefixlen < 24):
                glue = set()
                # This is the reason for needing the subnets sorted in
                # increasing order of size.
                for net in rfc2317_glue.copy().keys():
                    if net in network:
                        glue.update(rfc2317_glue[net])
                        del (rfc2317_glue[net])
            elif network in rfc2317_glue:
                glue = rfc2317_glue[network]
                del (rfc2317_glue[network])
            else:
                glue = set()
            yield DNSReverseZoneConfig(
                ns_host_name,
                serial=serial,
                default_ttl=default_ttl,
                ns_host_name=ns_host_name,
                mapping=mapping,
                network=IPNetwork(subnet.cidr),
                dynamic_ranges=dynamic_ranges,
                rfc2317_ranges=glue,
            )
        # Now provide any remaining rfc2317 glue networks.
        for network, ranges in rfc2317_glue.items():
            yield DNSReverseZoneConfig(
                ns_host_name,
                serial=serial,
                default_ttl=default_ttl,
                network=network,
                ns_host_name=ns_host_name,
                rfc2317_ranges=ranges,
            )