aboutsummaryrefslogtreecommitdiff

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.