- Auto plugin loads zones-prepared/*.zone (regex zone-name extraction) - scripts/prepare-zones.sh transforms raw Vultr exports: * synthesizes SOA (omitted by Vultr; CoreDNS requires it) * prepends @ to leading-TAB apex lines to disambiguate owner inheritance * dot-terminates NS/MX/CNAME rdata so $ORIGIN doesn't double-suffix - DNS_PORT defaults to 1053 (5353=avahi, 53=libvirt dnsmasq on this host) - Forwards non-authoritative queries to 1.1.1.1/1.0.0.1/9.9.9.9 - Makefile targets: prep, up, down, reload, test, logs - 91 zones loaded
86 lines
3.1 KiB
Bash
Executable File
86 lines
3.1 KiB
Bash
Executable File
#!/usr/bin/env bash
|
|
# Injects an SOA record into each raw Vultr zone file and writes the result
|
|
# to zones-prepared/. Source files in zones/ are never modified.
|
|
#
|
|
# Two corrections applied to each zone:
|
|
# 1. Synthesize SOA — Vultr's export omits it, but CoreDNS rejects zones
|
|
# without one. Serial is YYYYMMDD01 (override via SERIAL env var).
|
|
# 2. Add trailing dots to NS/MX/CNAME rdata. Vultr exports unqualified
|
|
# hostnames (e.g. "ns1.vultr.com") which $ORIGIN then incorrectly
|
|
# suffixes with the zone name. We dot-terminate any rdata token that
|
|
# contains a "." and doesn't already end in one.
|
|
set -euo pipefail
|
|
|
|
SRC_DIR="${SRC_DIR:-zones}"
|
|
DST_DIR="${DST_DIR:-zones-prepared}"
|
|
SERIAL="${SERIAL:-$(date +%Y%m%d)01}"
|
|
ADMIN_EMAIL="${ADMIN_EMAIL:-admin}" # becomes admin.<zone>.
|
|
|
|
mkdir -p "$DST_DIR"
|
|
|
|
count=0
|
|
for src in "$SRC_DIR"/*.zone; do
|
|
fname=$(basename "$src")
|
|
zone="${fname%.zone}"
|
|
dst="$DST_DIR/$fname"
|
|
|
|
{
|
|
echo "; Auto-prepared by scripts/prepare-zones.sh on $(date -Iseconds)"
|
|
echo "; Source: $src"
|
|
echo "\$ORIGIN ${zone}."
|
|
echo "\$TTL 3600"
|
|
echo "@ 3600 IN SOA ns1.vultr.com. ${ADMIN_EMAIL}.${zone}. ("
|
|
echo " ${SERIAL} ; serial"
|
|
echo " 3600 ; refresh (1 hour)"
|
|
echo " 1800 ; retry (30 minutes)"
|
|
echo " 604800 ; expire (1 week)"
|
|
echo " 300 ; minimum (5 minutes)"
|
|
echo " )"
|
|
echo ""
|
|
|
|
# Strip source's own $ORIGIN/$TTL/comments, then apply two fixes:
|
|
#
|
|
# (a) Apex disambiguation. Vultr uses leading-TAB-then-TTL to mean
|
|
# "apex record", but RFC 1035 says lines starting with whitespace
|
|
# inherit the *previous* owner. When a non-apex record precedes
|
|
# a leading-TAB apex line, the apex line silently gets attached
|
|
# to the wrong name. Prepend "@" to make apex explicit.
|
|
#
|
|
# (b) Dot-terminate NS/MX/CNAME rdata. Vultr exports unqualified
|
|
# hostnames which $ORIGIN then incorrectly suffixes.
|
|
#
|
|
# We never re-emit via awk fields (preserves whitespace inside the
|
|
# line for owner-inheritance correctness in any unfixed lines).
|
|
grep -vE '^\$(ORIGIN|TTL)|^;' "$src" | awk '
|
|
NF == 0 { print; next }
|
|
{
|
|
# (a) Detect Vultr-style apex line: leading whitespace, then TTL,
|
|
# then "IN". Prepend "@" so the owner is explicit.
|
|
if ($0 ~ /^[[:space:]]+[0-9]+[[:space:]]+IN[[:space:]]/) {
|
|
sub(/^[[:space:]]+/, "@\t", $0)
|
|
# awk has re-split $0 — re-parse for the next step.
|
|
# (NF/$N references below are based on the modified $0.)
|
|
}
|
|
|
|
# (b) Dot-terminate trailing hostname for NS/CNAME/MX rdata.
|
|
type = ""
|
|
for (i = 1; i <= NF; i++) {
|
|
if ($i == "NS" || $i == "CNAME" || $i == "MX") { type = $i; break }
|
|
}
|
|
if (type != "") {
|
|
target = $NF
|
|
if (index(target, ".") > 0 && substr(target, length(target), 1) != ".") {
|
|
sub(/[[:space:]]+$/, "", $0)
|
|
print $0 "."
|
|
next
|
|
}
|
|
}
|
|
print
|
|
}
|
|
'
|
|
} > "$dst"
|
|
count=$((count + 1))
|
|
done
|
|
|
|
echo "Prepared ${count} zone files in ${DST_DIR}/ (serial=${SERIAL})"
|