- Blackhole zones
- DNSSEC
- Logging
+- fix parse_name to know @
from nsconfig import Nsc
+import nsconfig.sink
from nsconfig.daemon.bind import NscDaemonBind
nsc = Nsc(
daemon=NscDaemonBind(control_command='echo'),
)
+nsconfig.sink.generate_localhost(nsc)
+nsconfig.sink.generate_blackhole(nsc)
+
for rev in ['10.1.0.0/16', '10.2.0.0/16', 'fd12:3456:789a::/48']:
rz = nsc.add_zone(reverse_for=rev)
rz[""].NS('ns1.example.org', 'ns2.example.org')
import argparse
+from argparse import Namespace
from pathlib import Path
from texttable import Texttable
nsc.daemon.dump_config(file=f)
-def do_status(nsc: Nsc) -> None:
+def do_status(nsc: Nsc, args: Namespace) -> None:
table = Texttable(max_width=0)
- table.header(['Zone', 'Old serial', 'Old hash', 'New serial', 'New hash', 'S'])
- table.set_cols_dtype(['t', 'i', 't', 'i', 't', 't'])
+ table.header(['S', 'Zone', 'Type', 'Status'])
table.set_deco(Texttable.HEADER)
for z in nsc.get_zones():
action = '*'
else:
action = ""
+ do_show = args.all
if isinstance(z, NscZonePrimary):
- table.add_row([
- z.name,
- z.prev_state.serial,
- z.prev_state.hash,
- z.state.serial,
- z.state.hash,
- action,
- ])
+ status = f'serial {z.prev_state.serial}'
+ if z.is_changed():
+ status += f' -> {z.state.serial}'
+ do_show = True
elif isinstance(z, NscZoneSecondary):
- table.add_row([z.name, 'secondary', "", "", "", action])
+ status = f'from {z.primary_server}'
elif isinstance(z, NscZoneAlias):
- table.add_row([z.name, 'alias', "", "", "", action])
+ status = f'to {z.alias_for.name}'
else:
raise NotImplementedError()
+ if do_show:
+ table.add_row([action, z.name, z.zone_type.name, status])
print(table.draw())
test_parser = subparsers.add_parser('test', help='test new configuration', description='Test new configuration')
status_parser = subparsers.add_parser('status', help='list status of zones', description='List status of zones')
+ status_parser.add_argument('-a', '--all', default=False, action='store_true', help='show non-primary zones')
update_parser = subparsers.add_parser('update', help='update configuration', description='Update zone files and daemon configuration as needed')
if args.action == 'test':
do_test(nsc)
elif args.action == 'status':
- do_status(nsc)
+ do_status(nsc, args)
elif args.action == 'update':
do_update(nsc)
else:
self._add(dns.rdtypes.IN.AAAA.AAAA(RdataClass.IN, RdataType.AAAA, str(a)))
if reverse:
- self.nsc_zone.nsc._add_reverse_mapping(a, parse_name(self.name + '.' + self.nsc_zone.name))
+ self.nsc_zone.nsc._add_reverse_mapping(a, parse_name(self.name + '.' + self.nsc_zone.name) if self.name != "" else parse_name(self.nsc_zone.name + '.'))
return self
def MX(self, pri: int, name: str) -> Self:
--- /dev/null
+from typing import List, Optional
+
+from nsconfig.core import Nsc, NscZonePrimary
+from nsconfig.util import IPNetwork, parse_network
+
+# Networks which should have blackhole reverse zones as recommended by RFC 6303
+BLACKHOLE_NETWORKS = [
+ '0.0.0.0/8', # IPv4 reserved
+ '10.0.0.0/8', # IPv4 private
+ '169.254.0.0/16', # IPv4 link-local
+ '192.0.2.0/24', # IPv4 test
+ '192.168.0.0/16', # IPv4 private
+ '198.51.100.0/24', # IPv4 test
+ '203.0.113.0/24', # IPv4 test
+ '255.255.255.255/32', # IPv4 broadcast
+ '::0/128', # IPv6 unspecified
+ '2001:0db8::/32', # IPv6 example
+ 'fd00::/8', # IPv6 unique local
+ 'fe80::/12', # IPv6 link-local
+ 'fe90::/12',
+ 'fea0::/12',
+ 'feb0::/12',
+] + [f'172.{i}.0.0/16' for i in range(16, 32)] # IPv4 private
+
+
+def generate_localhost(nsc) -> None:
+ z = nsc.add_zone('localhost')
+ (z[""]
+ .NS(z.config.origin_server)
+ .A('127.0.0.1', '::1'))
+
+ r4 = nsc.add_zone(reverse_for='127.0.0.0/8')
+ r4[""].NS(z.config.origin_server)
+
+ r6 = nsc.add_zone(reverse_for='::1/128')
+ r6[""].NS(z.config.origin_server)
+
+
+def generate_blackhole(nsc: Nsc,
+ use_zone: Optional[NscZonePrimary] = None,
+ skip_networks: List[IPNetwork] = [],
+ ) -> None:
+ if use_zone is None:
+ use_zone = nsc.add_zone('invalid')
+ assert isinstance(use_zone, NscZonePrimary)
+ for raw_net in BLACKHOLE_NETWORKS:
+ net = parse_network(raw_net)
+ if net not in skip_networks:
+ z = nsc.add_zone(reverse_for=net, alias_for=use_zone)