/t/bind/ BIND Zone File Prettifier & Checker & Resolver
Some one used $ORIGIN for every subdomain and domain in a zone file and it was
impossible to read. So I told claude to make this tool.
So basically it resolves $ORIGIN and $TTL to a single definition at the
top of the file. Also Cleans up the file so it looks good
Claude Yappings
Rewrites a zone master file into a readable, canonical form: one
$TTL and one $ORIGIN at the top, every owner name
written out in full, and aligned columns.
Zone files have a lot of syntax that is valid but hard to read. An indented
line silently inherits the previous record's owner name; $ORIGIN
and $TTL can each change part-way through, so the same label or
the same bare record means different things in different places; TTL and
class can be left out entirely. This resolves all of
that, then checks the result for the usual problems β a missing or duplicated
SOA, no NS at the apex, a CNAME sharing a name with other records, unbalanced
parentheses, and domain names that lost their trailing dot and quietly
expanded into nonsense.
Locally Crunched, Like always :3
Findings
Nothing yet.
Paste a zone file above,
then press Prettify & Check.
What it changes, and what it deliberately does not
One $ORIGIN
Every name is resolved against whichever $ORIGIN was in effect
where it was written, then re-expressed relative to the first
$ORIGIN in the file. Later $ORIGIN lines are
dropped. Names in RDATA are rewritten too β the target of a CNAME, an MX
exchange, an SRV target β not just owner names, since those would otherwise
change meaning once the directive they were written under disappears.
A later $ORIGIN outside the first one's tree cannot be
expressed relative to it. Those records are written out fully qualified
instead, and a warning says so.
One $TTL
Every record is given the TTL that was in effect where it was written β
its own, or the $TTL above it. The one covering the most
records becomes the single $TTL at the top of the file (ties
go to whichever came first), and the rest of the $TTL lines
are dropped. A record matching that default is left bare; one that differs
gets its TTL written in, so no record's TTL depends on how far up the file
you look. Values are compared as durations, so 1h and
3600 count as the same TTL.
A file with no $TTL at all is left alone β every TTL stays
exactly as written, since hoisting one in would change what the bare
records mean. Records above the first $TTL are the one case
where this does change the zone: they used to fall back to the SOA minimum,
and a warning names them.
Explicit owner names
An indented record inherits the owner name of the record above it. Every output line repeats the owner explicitly, so no line depends on the one before it any more.
Explicit class
A record with no class gets one written in β inherited from the last record
that stated one, or IN if none did, which is what BIND itself
would use.
Left alone on purpose
$INCLUDE and $GENERATE are passed through
byte-for-byte: the first cannot be read (nothing is ever fetched) and the
second is not expanded, so neither is reformatted or checked.
Any record with a type this tool does not recognise is also passed through
unchanged rather than reformatted into something possibly wrong.
Index of /t/bind/
../ bindzone.js 01-Nov-2026 11:07 41Β KB