updating dns override
All checks were successful
Check scripts syntax / check-scripts-syntax (push) Successful in 4s
All checks were successful
Check scripts syntax / check-scripts-syntax (push) Successful in 4s
This commit is contained in:
183
dns-override.sh
183
dns-override.sh
@@ -3,7 +3,8 @@
|
||||
set -euo pipefail
|
||||
|
||||
readonly SCRIPT_NAME="dns-override.sh"
|
||||
readonly SCRIPT_VERSION="1.0.0"
|
||||
readonly SCRIPT_VERSION="1.0.2"
|
||||
readonly IMMUTABLE_PROMPT_TIMEOUT_SEC=20
|
||||
|
||||
readonly NC='\033[0m'
|
||||
readonly RED='\033[1;31m'
|
||||
@@ -22,6 +23,8 @@ readonly EMOJI_NET='🌐'
|
||||
readonly EMOJI_LOCK='🔒'
|
||||
|
||||
SUDO_BIN=""
|
||||
IS_REMOTE_SSH=0
|
||||
IMMUTABLE_LOCK_REQUESTED=0
|
||||
declare -a DNS_SERVERS=()
|
||||
declare -a DETECTED_MANAGERS=()
|
||||
declare -a ACTIONS_ATTEMPTED=()
|
||||
@@ -44,6 +47,27 @@ command_exists() {
|
||||
command -v "$1" >/dev/null 2>&1
|
||||
}
|
||||
|
||||
binary_or_path_exists() {
|
||||
local bin_name="$1"
|
||||
shift
|
||||
|
||||
if command_exists "$bin_name"; then
|
||||
return 0
|
||||
fi
|
||||
|
||||
local path_candidate
|
||||
for path_candidate in "$@"; do
|
||||
[[ -x "$path_candidate" ]] && return 0
|
||||
done
|
||||
return 1
|
||||
}
|
||||
|
||||
systemd_unit_exists() {
|
||||
local unit_name="$1"
|
||||
command_exists systemctl || return 1
|
||||
systemctl list-unit-files "$unit_name" >/dev/null 2>&1
|
||||
}
|
||||
|
||||
trim() {
|
||||
local value="$1"
|
||||
value="${value#"${value%%[![:space:]]*}"}"
|
||||
@@ -98,6 +122,15 @@ read_tty_input() {
|
||||
printf '%s' "$(trim "$value")"
|
||||
}
|
||||
|
||||
read_tty_input_timeout() {
|
||||
local prompt="$1"
|
||||
local timeout_sec="$2"
|
||||
local value
|
||||
printf "%b" "$prompt" >/dev/tty
|
||||
IFS= read -r -t "$timeout_sec" value </dev/tty || return $?
|
||||
printf '%s' "$(trim "$value")"
|
||||
}
|
||||
|
||||
run_root() {
|
||||
if [[ -n "$SUDO_BIN" ]]; then
|
||||
"$SUDO_BIN" "$@"
|
||||
@@ -144,6 +177,49 @@ ensure_root_context() {
|
||||
SUDO_BIN="sudo"
|
||||
}
|
||||
|
||||
detect_runtime_context() {
|
||||
if [[ -n "${SSH_CONNECTION:-}" || -n "${SSH_TTY:-}" ]]; then
|
||||
IS_REMOTE_SSH=1
|
||||
log_warning "SSH session detected. Using safer apply behavior to reduce connection drops."
|
||||
fi
|
||||
}
|
||||
|
||||
has_systemd_resolved() {
|
||||
binary_or_path_exists "resolvectl" "/usr/bin/resolvectl" "/bin/resolvectl" && return 0
|
||||
systemd_unit_exists "systemd-resolved.service" && return 0
|
||||
binary_or_path_exists "systemd-resolved" "/lib/systemd/systemd-resolved" "/usr/lib/systemd/systemd-resolved" && return 0
|
||||
return 1
|
||||
}
|
||||
|
||||
has_networkmanager() {
|
||||
binary_or_path_exists "nmcli" "/usr/bin/nmcli" "/bin/nmcli" && return 0
|
||||
binary_or_path_exists "NetworkManager" "/usr/sbin/NetworkManager" "/sbin/NetworkManager" && return 0
|
||||
systemd_unit_exists "NetworkManager.service" && return 0
|
||||
return 1
|
||||
}
|
||||
|
||||
has_resolvconf_openresolv() {
|
||||
binary_or_path_exists "resolvconf" "/sbin/resolvconf" "/usr/sbin/resolvconf" && return 0
|
||||
return 1
|
||||
}
|
||||
|
||||
has_dhclient() {
|
||||
binary_or_path_exists "dhclient" "/sbin/dhclient" "/usr/sbin/dhclient" && return 0
|
||||
return 1
|
||||
}
|
||||
|
||||
has_systemd_networkd() {
|
||||
systemd_unit_exists "systemd-networkd.service" && return 0
|
||||
binary_or_path_exists "systemd-networkd" "/lib/systemd/systemd-networkd" "/usr/lib/systemd/systemd-networkd" && return 0
|
||||
return 1
|
||||
}
|
||||
|
||||
has_ifupdown() {
|
||||
binary_or_path_exists "ifup" "/sbin/ifup" "/usr/sbin/ifup" && return 0
|
||||
[[ -f /etc/network/interfaces || -d /etc/network/interfaces.d ]] && return 0
|
||||
return 1
|
||||
}
|
||||
|
||||
add_manager() {
|
||||
local manager="$1"
|
||||
if ! contains_value "$manager" "${DETECTED_MANAGERS[@]}"; then
|
||||
@@ -154,31 +230,27 @@ add_manager() {
|
||||
detect_managers() {
|
||||
DETECTED_MANAGERS=()
|
||||
|
||||
if command_exists systemctl && systemctl is-active --quiet systemd-resolved 2>/dev/null; then
|
||||
add_manager "systemd-resolved"
|
||||
elif [[ -L /etc/resolv.conf ]] && readlink /etc/resolv.conf 2>/dev/null | grep -Eq 'systemd/resolve'; then
|
||||
if has_systemd_resolved; then
|
||||
add_manager "systemd-resolved"
|
||||
fi
|
||||
|
||||
if command_exists nmcli || [[ -d /etc/NetworkManager ]]; then
|
||||
if has_networkmanager; then
|
||||
add_manager "NetworkManager"
|
||||
fi
|
||||
|
||||
if command_exists resolvconf || [[ -d /etc/resolvconf ]] || [[ -f /etc/resolvconf.conf ]]; then
|
||||
if has_resolvconf_openresolv; then
|
||||
add_manager "resolvconf/openresolv"
|
||||
fi
|
||||
|
||||
if command_exists dhclient || [[ -f /etc/dhcp/dhclient.conf ]]; then
|
||||
if has_dhclient; then
|
||||
add_manager "dhclient"
|
||||
fi
|
||||
|
||||
if command_exists systemctl && systemctl is-active --quiet systemd-networkd 2>/dev/null; then
|
||||
add_manager "systemd-networkd"
|
||||
elif [[ -d /etc/systemd/network ]]; then
|
||||
if has_systemd_networkd; then
|
||||
add_manager "systemd-networkd"
|
||||
fi
|
||||
|
||||
if [[ -f /etc/network/interfaces ]] || [[ -d /etc/network/interfaces.d ]]; then
|
||||
if has_ifupdown; then
|
||||
add_manager "ifupdown"
|
||||
fi
|
||||
}
|
||||
@@ -336,7 +408,7 @@ run_action() {
|
||||
rc=$?
|
||||
if [[ "$rc" -eq 2 ]]; then
|
||||
ACTIONS_SKIPPED+=("$action")
|
||||
log_info "$action not applicable on this system"
|
||||
log_info "$action skipped: target manager is not present on this host"
|
||||
return 0
|
||||
fi
|
||||
|
||||
@@ -374,7 +446,8 @@ apply_static_resolv_conf() {
|
||||
}
|
||||
|
||||
apply_systemd_resolved() {
|
||||
if ! command_exists systemctl && ! command_exists resolvectl && [[ ! -d /etc/systemd ]]; then
|
||||
if ! has_systemd_resolved; then
|
||||
log_info "Skipping systemd-resolved override: systemd-resolved is not present."
|
||||
return 2
|
||||
fi
|
||||
|
||||
@@ -409,7 +482,8 @@ apply_systemd_resolved() {
|
||||
}
|
||||
|
||||
apply_networkmanager() {
|
||||
if ! command_exists nmcli && [[ ! -d /etc/NetworkManager ]]; then
|
||||
if ! has_networkmanager; then
|
||||
log_info "Skipping NetworkManager override: NetworkManager is not present."
|
||||
return 2
|
||||
fi
|
||||
|
||||
@@ -430,21 +504,37 @@ apply_networkmanager() {
|
||||
run_root nmcli connection modify "$conn" ipv6.ignore-auto-dns yes >/dev/null 2>&1 || true
|
||||
run_root nmcli connection modify "$conn" ipv4.dns "$dns_csv" >/dev/null 2>&1 || true
|
||||
run_root nmcli connection modify "$conn" ipv6.dns "$dns_csv" >/dev/null 2>&1 || true
|
||||
run_root nmcli connection up "$conn" >/dev/null 2>&1 || true
|
||||
done < <(nmcli -g NAME connection show --active 2>/dev/null || true)
|
||||
|
||||
run_root nmcli connection reload >/dev/null 2>&1 || true
|
||||
|
||||
if [[ "$IS_REMOTE_SSH" -eq 1 ]]; then
|
||||
log_warning "Skipping NetworkManager reconnect/restart operations in SSH session."
|
||||
local dev
|
||||
while IFS= read -r dev; do
|
||||
[[ -n "$dev" && "$dev" != "lo" ]] || continue
|
||||
run_root nmcli device reapply "$dev" >/dev/null 2>&1 || true
|
||||
done < <(nmcli -t -f DEVICE,STATE device status 2>/dev/null | awk -F: '$2=="connected" || $2=="connecting" {print $1}')
|
||||
else
|
||||
while IFS= read -r conn; do
|
||||
[[ -n "$conn" ]] || continue
|
||||
run_root nmcli connection up "$conn" >/dev/null 2>&1 || true
|
||||
done < <(nmcli -g NAME connection show --active 2>/dev/null || true)
|
||||
fi
|
||||
|
||||
run_root nmcli general reload >/dev/null 2>&1 || true
|
||||
fi
|
||||
|
||||
if command_exists systemctl; then
|
||||
run_root systemctl reload NetworkManager >/dev/null 2>&1 || run_root systemctl restart NetworkManager >/dev/null 2>&1 || true
|
||||
run_root systemctl reload NetworkManager >/dev/null 2>&1 || true
|
||||
fi
|
||||
|
||||
return 0
|
||||
}
|
||||
|
||||
apply_resolvconf_openresolv() {
|
||||
if ! command_exists resolvconf && [[ ! -d /etc/resolvconf ]] && [[ ! -f /etc/resolvconf.conf ]]; then
|
||||
if ! has_resolvconf_openresolv; then
|
||||
log_info "Skipping resolvconf/openresolv override: resolvconf/openresolv is not present."
|
||||
return 2
|
||||
fi
|
||||
|
||||
@@ -464,7 +554,8 @@ apply_resolvconf_openresolv() {
|
||||
}
|
||||
|
||||
apply_dhclient() {
|
||||
if ! command_exists dhclient && [[ ! -f /etc/dhcp/dhclient.conf ]] && [[ ! -d /etc/dhcp ]]; then
|
||||
if ! has_dhclient; then
|
||||
log_info "Skipping dhclient override: dhclient is not present."
|
||||
return 2
|
||||
fi
|
||||
|
||||
@@ -485,7 +576,8 @@ apply_dhclient() {
|
||||
}
|
||||
|
||||
apply_systemd_networkd() {
|
||||
if ! command_exists systemctl && [[ ! -d /etc/systemd/network ]]; then
|
||||
if ! has_systemd_networkd; then
|
||||
log_info "Skipping systemd-networkd override: systemd-networkd is not present."
|
||||
return 2
|
||||
fi
|
||||
|
||||
@@ -515,7 +607,18 @@ apply_systemd_networkd() {
|
||||
|
||||
if command_exists systemctl; then
|
||||
run_root systemctl daemon-reload >/dev/null 2>&1 || true
|
||||
run_root systemctl restart systemd-networkd >/dev/null 2>&1 || run_root systemctl try-restart systemd-networkd >/dev/null 2>&1 || true
|
||||
if command_exists networkctl; then
|
||||
run_root networkctl reload >/dev/null 2>&1 || true
|
||||
if [[ "$IS_REMOTE_SSH" -eq 0 ]]; then
|
||||
run_root networkctl reconfigure --all >/dev/null 2>&1 || true
|
||||
else
|
||||
log_warning "Skipping networkctl reconfigure --all in SSH session."
|
||||
fi
|
||||
elif [[ "$IS_REMOTE_SSH" -eq 0 ]]; then
|
||||
run_root systemctl restart systemd-networkd >/dev/null 2>&1 || run_root systemctl try-restart systemd-networkd >/dev/null 2>&1 || true
|
||||
else
|
||||
log_warning "Skipping systemd-networkd restart in SSH session."
|
||||
fi
|
||||
fi
|
||||
|
||||
return 0
|
||||
@@ -567,7 +670,8 @@ patch_ifupdown_file() {
|
||||
}
|
||||
|
||||
apply_ifupdown() {
|
||||
if [[ ! -f /etc/network/interfaces ]] && [[ ! -d /etc/network/interfaces.d ]]; then
|
||||
if ! has_ifupdown; then
|
||||
log_info "Skipping ifupdown override: ifupdown is not present."
|
||||
return 2
|
||||
fi
|
||||
|
||||
@@ -611,22 +715,41 @@ prompt_immutable_lock() {
|
||||
}
|
||||
|
||||
local answer
|
||||
answer="$(read_tty_input "${YELLOW}${EMOJI_LOCK} Make /etc/resolv.conf immutable with chattr +i? [y/N]: ${NC}")" || return 1
|
||||
if ! answer="$(read_tty_input_timeout "${YELLOW}${EMOJI_LOCK} Make /etc/resolv.conf immutable with chattr +i? [y/N] (auto No in ${IMMUTABLE_PROMPT_TIMEOUT_SEC}s): ${NC}" "$IMMUTABLE_PROMPT_TIMEOUT_SEC")"; then
|
||||
local rc=$?
|
||||
if [[ "$rc" -gt 128 ]]; then
|
||||
log_warning "No response received for immutable lock prompt; defaulting to No."
|
||||
IMMUTABLE_LOCK_REQUESTED=0
|
||||
return 0
|
||||
fi
|
||||
return 1
|
||||
fi
|
||||
|
||||
case "$answer" in
|
||||
y|Y|yes|YES)
|
||||
if run_root chattr +i /etc/resolv.conf; then
|
||||
log_success "Immutable lock applied to /etc/resolv.conf."
|
||||
log_warning "To edit DNS later, run: sudo chattr -i /etc/resolv.conf"
|
||||
else
|
||||
log_warning "Failed to apply immutable lock."
|
||||
fi
|
||||
IMMUTABLE_LOCK_REQUESTED=1
|
||||
log_info "Immutable lock requested. It will be applied after DNS updates."
|
||||
;;
|
||||
*)
|
||||
IMMUTABLE_LOCK_REQUESTED=0
|
||||
log_info "Immutable lock skipped."
|
||||
;;
|
||||
esac
|
||||
}
|
||||
|
||||
apply_immutable_lock_if_requested() {
|
||||
if [[ "$IMMUTABLE_LOCK_REQUESTED" -ne 1 ]]; then
|
||||
return 0
|
||||
fi
|
||||
|
||||
if run_root chattr +i /etc/resolv.conf; then
|
||||
log_success "Immutable lock applied to /etc/resolv.conf."
|
||||
log_warning "To edit DNS later, run: sudo chattr -i /etc/resolv.conf"
|
||||
else
|
||||
log_warning "Failed to apply immutable lock."
|
||||
fi
|
||||
}
|
||||
|
||||
print_summary() {
|
||||
echo
|
||||
log_step "Execution summary"
|
||||
@@ -669,7 +792,9 @@ main() {
|
||||
|
||||
require_tty
|
||||
ensure_root_context "$@"
|
||||
detect_runtime_context
|
||||
prompt_dns_servers
|
||||
prompt_immutable_lock || log_warning "Immutable lock prompt failed; defaulting to unlocked."
|
||||
run_connectivity_checks
|
||||
detect_managers
|
||||
|
||||
@@ -681,7 +806,7 @@ main() {
|
||||
run_action "Apply ifupdown override" apply_ifupdown
|
||||
run_action "Write /etc/resolv.conf directly" apply_static_resolv_conf
|
||||
|
||||
prompt_immutable_lock || log_warning "Immutable lock prompt failed; continuing."
|
||||
run_action "Apply immutable /etc/resolv.conf lock (if requested)" apply_immutable_lock_if_requested
|
||||
print_summary
|
||||
|
||||
echo
|
||||
|
||||
Reference in New Issue
Block a user