testsAndMisc/linux_configuration/scripts/periodic_background/hosts/guard/plugins/resolved-plugin.sh
Krzysztof kuhy Rudnicki 66c4698194
Some checks are pending
Pre-commit checks / pre-commit (push) Waiting to run
feat: migrate hosts-guard and shutdown-schedule-guard to guard-lib
Replaces the bespoke chattr/bind-mount/systemd-watcher implementations for
/etc/hosts and /etc/shutdown-schedule.conf with the new shared guard-lib
(~/guard-lib, guardctl), so screen-locker and steam-backlog-enforcer's new
block-gaming feature stop maintaining parallel copies of the same
tamper-resistance mechanism.

- pacman_wrapper.sh: pre/post hook fallbacks now call guard-lib's generic
  unlock-all/relock-all scripts (covers every registered guard instance,
  not just /etc/hosts)
- setup_midnight_shutdown.sh: installs/updates its guarded config via
  guardctl file-guard instead of hand-rolled chattr + systemd unit
  generation; the schedule ratchet logic (block-if-more-lenient) stays
  bespoke since guardctl's generic unlock can't represent it
- new hosts/guard/plugins/nsswitch-plugin.sh, resolved-plugin.sh

Also fixes, at user's request even though pre-existing: 3 shellcheck
SC2329 false positives in pacman_wrapper.sh (functions invoked indirectly
by name, not actually dead) and 1 SC2001 style warning (echo|sed VM-name
extraction replaced with parameter expansion, verified equivalent output).

Co-Authored-By: Claude Sonnet 5 <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_01AFNiYQQgSLAkiBXswyimPq
2026-07-04 11:54:08 +02:00

66 lines
2.2 KiB
Bash
Executable File

#!/bin/bash
# guard-lib plugin for the "resolved" file-guard instance.
# Ensures /etc/systemd/resolved.conf honours /etc/hosts (ReadEtcHosts=yes)
# and doesn't bypass it via DNS-over-TLS, and keeps the resolved.conf.d
# drop-in directory empty so a drop-in can't silently override these
# settings. Translated from the pre-guard-lib enforce-resolved.sh - see
# that file's git history for the original standalone version.
RESOLVED_DROPIN_DIR="/etc/systemd/resolved.conf.d"
# Called unconditionally at the start of every enforce pass (not just on
# drift), matching the original script's behavior of policing the
# drop-in directory every time regardless of resolved.conf's own state.
pre_action() {
if [[ -d "$RESOLVED_DROPIN_DIR" ]]; then
local count
count=$(find "$RESOLVED_DROPIN_DIR" -name '*.conf' -type f 2>/dev/null | wc -l)
if [[ "$count" -gt 0 ]]; then
chattr -i "$RESOLVED_DROPIN_DIR" 2>/dev/null || true
find "$RESOLVED_DROPIN_DIR" -name '*.conf' -type f -delete
fi
else
mkdir -p "$RESOLVED_DROPIN_DIR"
fi
chattr +i "$RESOLVED_DROPIN_DIR" 2>/dev/null || true
}
validate() {
local file="$1"
local read_hosts
read_hosts=$(grep -E '^\s*ReadEtcHosts\s*=' "$file" 2>/dev/null | tail -1 |
sed 's/.*=\s*//' | tr -d '[:space:]')
[[ "$read_hosts" == "yes" ]] || return 1
local dot
dot=$(grep -E '^\s*DNSOverTLS\s*=' "$file" 2>/dev/null | tail -1 |
sed 's/.*=\s*//' | tr -d '[:space:]')
if [[ -n "$dot" && "$dot" != "no" ]]; then
return 1
fi
return 0
}
# Only called when no canonical copy exists yet to restore from instead.
emergency_fix() {
chattr -i "$TARGET" 2>/dev/null || true
if grep -qE '^\s*ReadEtcHosts\s*=' "$TARGET"; then
sed -i -E 's/^\s*ReadEtcHosts\s*=.*/ReadEtcHosts=yes/' "$TARGET"
elif grep -q '^\[Resolve\]' "$TARGET"; then
sed -i '/^\[Resolve\]/a ReadEtcHosts=yes' "$TARGET"
else
printf '\n[Resolve]\nReadEtcHosts=yes\n' >>"$TARGET"
fi
if grep -qE '^\s*DNSOverTLS\s*=' "$TARGET"; then
sed -i -E 's/^\s*DNSOverTLS\s*=.*/#DNSOverTLS=no/' "$TARGET"
fi
}
post_restore_action() {
systemctl restart systemd-resolved 2>/dev/null || true
}