Reverse Zone Compiler (rzc)
This is a tool to automate the process of maintaining reverse DNS zones given a collection of forward zones. Primary use case is a small operation that runs a few POPs full of VMs for researchers, friends, and various public benefit projects: keeping track of the DNS names of all of one's tenents in this case is a pain, and the desired data is already present in the forward zones, so an automatic tool to construct the reverse zone(s) may help.
Basic model is to configure this tool as a DNS XFR client for all the relevant forward zones, and to specify the reverse zones to be generated. The tool then downloads all of the specified forward zones, trawls them for A and AAAA RRs, and translates those into PTR RRs, throwing away any PTR RRs that don't fall within the specified set of reverse zones. After exhausting this process, the tool writes out a set of reverse zone files and exits.
The tool caches local copies of the downloaded forward zones, both to allow it to ride out temporary transfer failures and to allow it to use IXFR rather than AXFR to save bandwidth when conditions permit.
All of the heavy lifting is done by Bob Halley's excellent dnspython
library. You will also need the TOML library.
apt install python3-toml python3-dnspython
All configuration is stored in a TOML file. The default name of the
TOML file is the same as the tool, with the .py
suffix changed to
.toml
, but one can override this by passing the name of the
configuration file via the RZC_CONFIG
environment variable or on the
command line.
Sample configuration file:
[output]
directory = "output"
ttl = 3600
soa.mname = "localhost"
soa.rname = "ns0.example.org"
soa.refresh = 10803
soa.retry = 900
soa.expire = 604800
soa.minimum = 600
ns = [
"ns1.example.org",
"ns2.example.org",
]
zones = [
"1.0.10.in-addr.arpa",
"2.0.10.in-addr.arpa",
"3.0.10.in-addr.arpa",
"1.0.a.2.0.0.2.ip6.arpa",
"2.0.a.2.0.0.2.ip6.arpa",
"3.0.a.2.0.0.2.ip6.arpa",
]
[input]
xfr_timeout = 300
cache = "cache"
[[input.zone]]
name = "fred.example"
server = "10.100.0.1"
tsig = { "tsig.example.org" = ["hmac-sha256", "36A2xRALPymYl3Q7axrtAk1AICJyPhu2KkK7PxJhTQ8=" ] }
[[input.zone]]
name = "barney.example"
server = "10.200.0.1"
Most of this should be self-explanatory. The configuration is divided
into two sections, input
and output
: input
is about fetching the
forward zones, output
is about generating the reverse zones.
input.cache
is where cached copies of the forward zones will be
stored. output.directory
is where the reverse zones files will be
written. Both directories will be created if needed.
output.ns
is the list of nameservers to be listed in NS
RRs in the
output zones. Similarly, output.soa
gives all the parameters needed
for the SOA
rdata, except for the serial
value, which will be
generated automatically using the seconds-since-epoch convention.
output.zones
is the list of reverse zones to be generated.
Each [[input.zone]]
block defines one forward zone to be retrieved.
name
is the name of the zone, server
is the IPv4 or IPv6 address
from which to retrieve the zone. tsig
, if given, specifies the
TSIG
key data to use when retrieving this zone: the syntax is a
little weird, because it's a direct TOML representation of the form
dnspython
uses for a single-entry TSIG keyring, the general form is
tsig = { "name.of.tsig.key" = [ "tsig-key-type", "tsig-secret-encoded-as-base64" ] }
Since the TSIG secrets are embedded directly in the TOML file, you
might want to chmod
the TOML file to restrict unauthorized readers.
At some point I might add validation of the TOML via via jsonschema
,
but the schema required would nearly double the size of the program.