feat(dyndns): add optional rndc journal synchronization
Add configurable post-update journal synchronization via rndc sync -clean. Separate RFC 2136 update settings from local RNDC control settings. Run synchronization only after a successful nsupdate request and only when DYNDNS_RNDC_SYNC_CLEAN is enabled. Treat RNDC synchronization failures as warnings because the DNS update has already been accepted and named retains the authoritative state in its journal.
This commit is contained in:
@@ -241,6 +241,19 @@ _vars_source_check() {
|
||||
[ -n "$DYNDNS_BIND_ZONE_DIR" ] || _die "DYNDNS_BIND_ZONE_DIR env-var undefined" 5
|
||||
[ -n "$DYNDNS_BIND_ZONE_FILE" ] || _die "DYNDNS_BIND_ZONE_FILE env-var undefined" 5
|
||||
|
||||
case "$DYNDNS_RNDC_SYNC_CLEAN" in
|
||||
0|1)
|
||||
;;
|
||||
*)
|
||||
_die "DYNDNS_RNDC_SYNC_CLEAN must be either 0 or 1" 5
|
||||
;;
|
||||
esac
|
||||
|
||||
if [ "$DYNDNS_RNDC_SYNC_CLEAN" = "1" ]; then
|
||||
[ -n "$DYNDNS_RNDC_SERVER" ] || _die "DYNDNS_RNDC_SERVER env-var undefined" 5
|
||||
[ -n "$DYNDNS_RNDC_KEY" ] || _die "DYNDNS_RNDC_KEY env-var undefined" 5
|
||||
fi
|
||||
|
||||
_log "Leave the function '_vars_source_check()'..." 1
|
||||
|
||||
return 0
|
||||
@@ -265,12 +278,15 @@ _verify_runtime_init() {
|
||||
|| command -v "$DYNDNS_DB_PROGRAM" >/dev/null 2>&1 \
|
||||
|| _die "Database client '$DYNDNS_DB_PROGRAM' not available. $help_note" 5
|
||||
|
||||
command -v rndc >/dev/null 2>&1 || _die "rndc not available. $help_note" 5
|
||||
command -v sed >/dev/null 2>&1 || _die "sed not available. $help_note" 5
|
||||
command -v grep >/dev/null 2>&1 || _die "grep not available. $help_note" 5
|
||||
command -v awk >/dev/null 2>&1 || _die "awk not available. $help_note" 5
|
||||
command -v nsupdate >/dev/null 2>&1 || _die "nsupdate not available. $help_note" 5
|
||||
|
||||
if [ "$DYNDNS_RNDC_SYNC_CLEAN" = "1" ]; then
|
||||
command -v rndc >/dev/null 2>&1 || _die "rndc not available. $help_note" 5
|
||||
fi
|
||||
|
||||
_log "Leave the function '_verify_runtime_init()'..." 1
|
||||
return 0
|
||||
} #=> _verify_runtime_init()
|
||||
@@ -371,6 +387,16 @@ _vars_setup() {
|
||||
set_var DYNDNS_BIND_ZONE_FILE_SIGNED "$DYNDNS_BIND_ZONE_DIR/$DYNDNS_BIND_ZONE.zone.signed"
|
||||
set_var DYNDNS_BIND_ZONE_TTL 300
|
||||
|
||||
# RNDC post-update zone synchronization defaults
|
||||
#
|
||||
# The RNDC control interface is separate from the authoritative DNS
|
||||
# listener used by nsupdate. Keep the default disabled so existing
|
||||
# installations do not gain a new administrative post-update action
|
||||
# unless it is explicitly enabled in their vars file.
|
||||
set_var DYNDNS_RNDC_SERVER "127.0.0.1"
|
||||
set_var DYNDNS_RNDC_KEY ""
|
||||
set_var DYNDNS_RNDC_SYNC_CLEAN 0
|
||||
|
||||
# Create a per-run temp directory name. The directory itself may be created
|
||||
# lazily later by dyndns_mktemp().
|
||||
if [ -z "$DYNDNS_TEMP_DIR_session" ]; then
|
||||
@@ -1297,26 +1323,11 @@ _zone_updates_apply() {
|
||||
return 1
|
||||
}
|
||||
|
||||
_log "Check the zone '$DYNDNS_BIND_ZONE' for DNSSEC capabilities..." 1
|
||||
if [ -f "$DYNDNS_BIND_ZONE_FILE_SIGNED" ]; then
|
||||
_log "The zone '$DYNDNS_BIND_ZONE' uses DNSSEC..." 1
|
||||
zone_uses_dnssec=1
|
||||
else
|
||||
_log "The zone '$DYNDNS_BIND_ZONE' does not use DNSSEC..." 1
|
||||
zone_uses_dnssec=0
|
||||
fi
|
||||
|
||||
{
|
||||
printf 'debug\n'
|
||||
printf 'server %s\n' "$DYNDNS_BIND_SERVER"
|
||||
printf 'zone %s.\n' "$DYNDNS_BIND_ZONE"
|
||||
|
||||
if [ "$zone_uses_dnssec" -eq 1 ]; then
|
||||
printf '; Move %s from secure to insecure temporarily\n' "$DYNDNS_BIND_ZONE_FILE"
|
||||
printf 'update delete %s. DNSKEY\n' "$DYNDNS_BIND_ZONE"
|
||||
printf 'send\n'
|
||||
fi
|
||||
|
||||
awk -F '\t' -v zone_file="$DYNDNS_BIND_ZONE_FILE" '
|
||||
$1 == "del" {
|
||||
del_owner[++del_count] = $2
|
||||
@@ -1375,9 +1386,20 @@ _zone_updates_apply() {
|
||||
|
||||
cp "$nsupdate_file" "$DYNDNS_LOG_UPDATE_FILE" 2>/dev/null || true
|
||||
|
||||
if ! nsupdate -k "$DYNDNS_BIND_ZONE_KEY" "$nsupdate_file" >/dev/null 2>&1; then
|
||||
nsupdate_output=$(nsupdate -d -k "$DYNDNS_BIND_ZONE_KEY" "$nsupdate_file" 2>&1)
|
||||
nsupdate_rc=$?
|
||||
|
||||
if [ "$nsupdate_rc" -ne 0 ]; then
|
||||
{
|
||||
printf '%s\n' "nsupdate output (exit code: $nsupdate_rc):"
|
||||
printf '%s\n' "$nsupdate_output"
|
||||
} >> "$DYNDNS_LOG_FILE"
|
||||
|
||||
cp "$nsupdate_file" \
|
||||
"$DYNDNS_LOG_UPDATE_FILE.failed" 2>/dev/null || true
|
||||
rm -f "$nsupdate_file"
|
||||
_log "Zone updates could not be applied." 4
|
||||
|
||||
_log "Zone updates could not be applied (nsupdate exit code: $nsupdate_rc)." 4
|
||||
_log "Leave the function '_zone_updates_apply()'..." 1
|
||||
return 1
|
||||
fi
|
||||
@@ -1397,20 +1419,22 @@ _zone_updates_apply() {
|
||||
rm -f "$nsupdate_file"
|
||||
_log "Zone updates were applied successfully." 2
|
||||
|
||||
if command -v rndc >/dev/null 2>&1; then
|
||||
if rndc -s "$DYNDNS_BIND_SERVER" -k "$DYNDNS_BIND_ZONE_KEY" freeze "$DYNDNS_BIND_ZONE" >/dev/null 2>&1; then
|
||||
_log "The zone '$DYNDNS_BIND_ZONE' was frozen." 2
|
||||
if rndc -s "$DYNDNS_BIND_SERVER" -k "$DYNDNS_BIND_ZONE_KEY" thaw "$DYNDNS_BIND_ZONE" >/dev/null 2>&1; then
|
||||
_log "The zone '$DYNDNS_BIND_ZONE' was reloaded." 2
|
||||
else
|
||||
_log "Couldn't reload the zone '$DYNDNS_BIND_ZONE'." 4
|
||||
_log "Leave the function '_zone_updates_apply()'..." 1
|
||||
return 1
|
||||
fi
|
||||
# Synchronize dynamic zone journal changes into the master zone file.
|
||||
#
|
||||
# BIND keeps successful RFC 2136 updates in the zone journal until a zone dump
|
||||
# occurs. sync -clean writes the active journal state to the master zone file
|
||||
# and removes the journal after a successful synchronization.
|
||||
#
|
||||
# A synchronization failure is intentionally non-fatal: nsupdate has already
|
||||
# succeeded and named keeps the authoritative runtime state in the journal.
|
||||
if [ "$DYNDNS_RNDC_SYNC_CLEAN" = "1" ]; then
|
||||
if rndc \
|
||||
-s "$DYNDNS_RNDC_SERVER" \
|
||||
-k "$DYNDNS_RNDC_KEY" \
|
||||
sync -clean "$DYNDNS_BIND_ZONE" >/dev/null 2>&1; then
|
||||
_log "The zone '$DYNDNS_BIND_ZONE' was synchronized and journals were cleaned." 2
|
||||
else
|
||||
_log "Couldn't freeze the zone '$DYNDNS_BIND_ZONE'." 4
|
||||
_log "Leave the function '_zone_updates_apply()'..." 1
|
||||
return 1
|
||||
_log "Zone update succeeded, but rndc sync -clean failed for '$DYNDNS_BIND_ZONE'." 3
|
||||
fi
|
||||
fi
|
||||
|
||||
|
||||
Reference in New Issue
Block a user