From 87eaa27c4ce445f45bd406f6d38ce49cd2199792 Mon Sep 17 00:00:00 2001 From: Ryan Malloy Date: Sat, 16 May 2026 16:25:53 -0600 Subject: [PATCH] coredns: auto-bump SOA serial (NN counter) on every `make prep` MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Previously: `SERIAL=$(date +%Y%m%d)01` โ€” same-day re-runs produced the same serial. HE polled, saw no change, never pulled the update. Now: scan zones-prepared/ for the highest `YYYYMMDDNN` matching today's date and increment the NN counter. First run of the day starts at NN=01. Caps at NN=99 with a clear error message (set SERIAL manually if you genuinely need >99 changes per day). `SERIAL= make prep` still overrides the auto-detection, useful for forcing a specific serial during recovery or for testing. Verified end-to-end on dell01: prep bumped 2026051601 โ†’ 2026051602, CoreDNS auto-reload picked it up within 30s, all queried zones serve the new serial. HE will pull on its next refresh poll (SOA refresh = 3600s, so worst case 1 hour). --- scripts/prepare-zones.sh | 30 +++++++++++++++++++++++++++++- 1 file changed, 29 insertions(+), 1 deletion(-) diff --git a/scripts/prepare-zones.sh b/scripts/prepare-zones.sh index da09310..e2f088a 100755 --- a/scripts/prepare-zones.sh +++ b/scripts/prepare-zones.sh @@ -17,9 +17,37 @@ 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.. +# Serial number generation โ€” YYYYMMDDNN format (RFC 1912 ยง2.2). +# +# Strategy: every `make prep` run produces a strictly-increasing serial +# so that HE slaves notice the change on their next poll. If today's +# previous serials exist in zones-prepared/, increment the 2-digit +# counter. Otherwise start at NN=01. +# +# Honors an explicit override: `SERIAL=2026051699 make prep` skips the +# auto-detection. +TODAY=$(date +%Y%m%d) +if [[ -z "${SERIAL:-}" ]]; then + # Pull the highest YYYYMMDDNN serial from currently-prepared zones + # that starts with today's date. If none, default to NN=01. + highest=$(grep -hE '^[[:space:]]+'"${TODAY}"'[0-9]{2}[[:space:]]+;' "$DST_DIR"/*.zone 2>/dev/null \ + | awk '{print $1}' | sort -un | tail -1) + if [[ -n "$highest" ]]; then + nn=$((10#${highest:8:2})) + next_nn=$((nn + 1)) + if (( next_nn > 99 )); then + echo "ERROR: serial counter exhausted for ${TODAY} (NN=99 reached)." >&2 + echo "Set SERIAL manually or wait until tomorrow." >&2 + exit 1 + fi + SERIAL=$(printf "%s%02d" "$TODAY" "$next_nn") + else + SERIAL="${TODAY}01" + fi +fi + # Public-facing nameservers (Hurricane Electric free secondary service). # These appear in NS records inside every zone so that recursive # resolvers fetching the zone learn the correct delegation.