diff --git a/switch-resolver-to-bind9.sh b/switch-resolver-to-bind9.sh index e54cfa9..75d3a44 100755 --- a/switch-resolver-to-bind9.sh +++ b/switch-resolver-to-bind9.sh @@ -11,7 +11,7 @@ readonly NSS=/etc/nsswitch.conf readonly EXPECTED_NSS='hosts: files myhostname dns' MODE="${1:---check}" -case "$MODE" in --check|--apply|--rollback|--help) ;; *) echo "Usage: $0 [--check|--apply|--rollback|--help]" >&2; exit 2;; esac +case "$MODE" in --check|--apply|--rollback|--repair-postfix|--help) ;; *) echo "Usage: $0 [--check|--apply|--rollback|--repair-postfix|--help]" >&2; exit 2;; esac # Colorize status labels on terminals; respect NO_COLOR and redirected output. if [[ -t 1 && ! -v NO_COLOR && "${TERM:-}" != dumb ]]; then @@ -78,6 +78,60 @@ preflight(){ if grep -q 'status: SERVFAIL' <<< "$reply"; then ok 'rejected as expected'; else echo; failed 'BIND9 does not reject invalid DNSSEC test zone'; return 1; fi } +# Debian Postfix: systemd instance startup refreshes the chroot resolver files. +# This is deliberately limited to running Postfix instances. No data_directory +# files are ever removed. A queue flush remains a separate admin decision. +postfix_units(){ + local unit + while read -r unit _; do + [[ "$unit" == postfix@*.service ]] || continue + printf '%s\n' "$unit" + done < <(systemctl list-units --type=service --state=active --no-legend --plain 'postfix@*.service' 2>/dev/null) +} + +sync_postfix(){ + local -a units=() + local unit queue_dir chroot_resolv + if ! command -v postconf >/dev/null 2>&1; then + skipped 'Postfix not installed; no MTA restart required' + return 0 + fi + mapfile -t units < <(postfix_units) + if (( ${#units[@]} == 0 )); then + if systemctl is-active --quiet postfix.service; then + units=(postfix.service) + else + skipped 'No active Postfix service; no MTA restart required' + return 0 + fi + fi + info 'Restarting active Postfix systemd service(s) to refresh chroot DNS' + for unit in "${units[@]}"; do + systemctl restart "$unit" || { failed "Postfix restart failed: $unit"; return 1; } + if ! systemctl is-active --quiet "$unit"; then + failed "Postfix service not active after restart: $unit" + return 1 + fi + ok "Postfix restarted: $unit" + done + # Only assert a chroot resolver copy when it exists; custom setups may + # use multiple queue directories or run SMTP clients without chroot. + queue_dir=$(postconf -h queue_directory 2>/dev/null || true) + if [[ -n "$queue_dir" && -f "$queue_dir/etc/resolv.conf" ]]; then + chroot_resolv="$queue_dir/etc/resolv.conf" + if cmp -s "$RESOLV" "$chroot_resolv"; then + ok "Postfix chroot resolver synchronized: $chroot_resolv" + else + failed "Postfix chroot resolver differs: $chroot_resolv" + failed 'Check Debian postfix configure-instance.sh / active instances' + return 1 + fi + else + info 'No default Postfix chroot resolv.conf found (possibly non-chroot or custom layout)' + fi + info 'Deferred mail is not flushed automatically; if appropriate run: postqueue -f' +} + show_check(){ require_root need dig; need systemctl; need getent @@ -145,6 +199,7 @@ rollback_to(){ restore_files "$path" restore_services "$path" ok 'Configuration and resolved service state restored' + sync_postfix } apply(){ @@ -166,7 +221,7 @@ apply(){ status_banner "$GREEN" 'Umstellung kann durchgeführt werden.' \ "Ausführen mit: $0 --apply" printf '\nPlanned changes:\n hosts: files myhostname dns\n resolv.conf: nameserver 127.0.0.1\n stop and disable systemd-resolved\n' - info 'Network interfaces, routes, BIND9 and MTA are not changed.' + info 'Network interfaces, routes and BIND9 are unchanged; active Postfix will restart.' confirm || { skipped 'Abbruch durch User'; exit 0; } mkdir -p "$STATE_DIR" @@ -216,11 +271,25 @@ apply(){ echononl 'systemd-resolved disabled' is_fully_switched && ok 'yes' || { echo; false; } preflight + sync_postfix trap - ERR INT TERM - ok 'Switch completed successfully' + ok 'Switch completed successfully' info "Rollback available: $0 --rollback" } +repair_postfix(){ + require_root + need systemctl; need postconf; need cmp + if ! is_direct; then + fatal 'Resolver is not configured for direct BIND9; use --check first' + fi + if ! preflight; then + fatal 'Local DNSSEC preflight failed; Postfix unchanged' + fi + sync_postfix + ok 'Postfix DNS synchronization completed' +} + rollback(){ require_root local path @@ -235,15 +304,18 @@ rollback(){ case "$MODE" in --help) cat <<'HELP' -Usage: switch-resolver-to-bind9.sh [--check|--apply|--rollback|--help] +Usage: switch-resolver-to-bind9.sh [--check|--apply|--rollback|--repair-postfix|--help] --check read-only checks (default) --apply verify BIND9 DNSSEC; back up; switch DNS/NSS; stop+disable resolved --rollback restore files and resolved service state saved before last --apply + --repair-postfix restart active Postfix instance(s) to refresh chroot DNS --help this help +After Postfix restart: consider postqueue -f to retry deferred messages. Notes: run as root; requires BIND9 already working; no package changes. HELP ;; --check) show_check ;; --apply) apply ;; --rollback) rollback ;; + --repair-postfix) repair_postfix ;; esac