Files
IPTables-Management/lib/env_check.sh
ahdoawhfo ec1a37d18f Fix env_check_apply_fixes under partial fix needs
The function used a chain of `(( NEED_X == 1 )) && { ... }` statements.
When the last flag is 0 the trailing arithmetic evaluates to false and
bash returns 1 from the function. Under the main script's `set -e` that
propagates up to bootstrap which exits with the misleading "line 60"
ERR trap right after the installer announces it is going to create the
state directory.

Rewrite the body as plain `if` blocks and return 0 explicitly. Add two
regression assertions that exercise the "only some flags set" and
"nothing to do" paths so the class of bug is caught in CI.

Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
2026-04-17 14:11:53 +08:00

200 lines
5.6 KiB
Bash
Raw Permalink Blame History

This file contains ambiguous Unicode characters
This file contains Unicode characters that might be confused with other characters. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.
#!/usr/bin/env bash
if [[ -n ${IPF_ENV_CHECK_SH_LOADED:-} ]]; then
return 0
fi
IPF_ENV_CHECK_SH_LOADED=1
: "${IPF_CHECK_IPTABLES_CMD:=iptables}"
: "${IPF_CHECK_IP6TABLES_CMD:=ip6tables}"
: "${IPF_CHECK_PERSIST_CMD:=netfilter-persistent}"
: "${DPKG_BIN:=dpkg}"
: "${APT_GET_BIN:=apt-get}"
: "${DEBCONF_SET_SELECTIONS_BIN:=debconf-set-selections}"
: "${SYSCTL_BIN:=sysctl}"
: "${SYSTEMCTL_BIN:=systemctl}"
: "${IPF_SYSCTL_FILE:=/etc/sysctl.d/99-iptables-forward.conf}"
: "${IPF_IPV4_FORWARD_FILE:=/proc/sys/net/ipv4/ip_forward}"
: "${IPF_IPV6_FORWARD_FILE:=/proc/sys/net/ipv6/conf/all/forwarding}"
: "${IPF_ASSUME_YES:=0}"
ENV_CHECK_ISSUES=()
ENV_CHECK_WARNINGS=()
ENV_CHECK_NEED_PACKAGES=0
ENV_CHECK_NEED_SYSCTL=0
ENV_CHECK_NEED_STORAGE=0
_env_add_issue() {
ENV_CHECK_ISSUES+=("$1")
}
_env_add_warning() {
ENV_CHECK_WARNINGS+=("$1")
}
_env_require_cmd() {
local cmd=$1 issue=$2
command_is_available "${cmd}" && return 0
_env_add_issue "${issue}"
ENV_CHECK_NEED_PACKAGES=1
}
_env_require_forward() {
local file=$1 issue=$2
[[ $(_env_file_value "${file}" 2>/dev/null || printf '0') == 1 ]] && return 0
_env_add_issue "${issue}"
ENV_CHECK_NEED_SYSCTL=1
}
_env_file_value() {
local file=$1
[[ -f ${file} ]] || return 1
tr -d '[:space:]' <"${file}"
}
_env_package_installed() {
if ! command_is_available "${DPKG_BIN}"; then
return 1
fi
"${DPKG_BIN}" -s iptables-persistent >/dev/null 2>&1
}
env_check_collect_issues() {
ENV_CHECK_ISSUES=()
ENV_CHECK_WARNINGS=()
ENV_CHECK_NEED_PACKAGES=0
ENV_CHECK_NEED_SYSCTL=0
ENV_CHECK_NEED_STORAGE=0
_env_require_cmd "${IPF_CHECK_IPTABLES_CMD}" '缺少 iptables 命令。'
_env_require_cmd "${IPF_CHECK_IP6TABLES_CMD}" '缺少 ip6tables 命令。'
if ! _env_package_installed || ! command_is_available "${IPF_CHECK_PERSIST_CMD}"; then
_env_add_issue '缺少 iptables-persistent / netfilter-persistent。'
ENV_CHECK_NEED_PACKAGES=1
fi
_env_require_forward "${IPF_IPV4_FORWARD_FILE}" 'IPv4 转发未开启。'
_env_require_forward "${IPF_IPV6_FORWARD_FILE}" 'IPv6 转发未开启。'
if [[ ! -d ${IPF_STORAGE_DIR} || ! -w ${IPF_STORAGE_DIR} ]]; then
_env_add_issue "状态目录不可用: ${IPF_STORAGE_DIR}"
ENV_CHECK_NEED_STORAGE=1
fi
if command_is_available "${SYSTEMCTL_BIN}"; then
if "${SYSTEMCTL_BIN}" is-active --quiet ufw 2>/dev/null; then
_env_add_warning '检测到 ufw 正在运行,可能会影响转发规则。'
fi
if "${SYSTEMCTL_BIN}" is-active --quiet firewalld 2>/dev/null; then
_env_add_warning '检测到 firewalld 正在运行,可能会影响转发规则。'
fi
fi
return 0
}
env_check_print_report() {
local issue
if ((${#ENV_CHECK_ISSUES[@]} == 0)); then
log_ok '环境检查通过。'
else
log_warn '发现以下待修复项:'
for issue in "${ENV_CHECK_ISSUES[@]}"; do
printf ' - %s\n' "${issue}" >&2
done
fi
if ((${#ENV_CHECK_WARNINGS[@]} > 0)); then
log_warn '附加警告:'
for issue in "${ENV_CHECK_WARNINGS[@]}"; do
printf ' - %s\n' "${issue}" >&2
done
fi
}
_env_install_packages() {
command_is_available "${APT_GET_BIN}" || { log_err '缺少 apt-get无法自动安装依赖。'; return 1; }
command_is_available "${DEBCONF_SET_SELECTIONS_BIN}" || {
log_err '缺少 debconf-set-selections无法预置安装选项。'
return 1
}
printf 'iptables-persistent iptables-persistent/autosave_v4 boolean true\n' | "${DEBCONF_SET_SELECTIONS_BIN}"
printf 'iptables-persistent iptables-persistent/autosave_v6 boolean true\n' | "${DEBCONF_SET_SELECTIONS_BIN}"
DEBIAN_FRONTEND=noninteractive "${APT_GET_BIN}" update -qq
DEBIAN_FRONTEND=noninteractive "${APT_GET_BIN}" install -y -qq iptables iptables-persistent
}
_env_write_sysctl() {
local backup=''
if [[ -f ${IPF_SYSCTL_FILE} ]]; then
backup=$(cat "${IPF_SYSCTL_FILE}")
fi
cat >"${IPF_SYSCTL_FILE}" <<SYSCTL
net.ipv4.ip_forward=1
net.ipv6.conf.all.forwarding=1
SYSCTL
if ! command_is_available "${SYSCTL_BIN}"; then
log_err '缺少 sysctl无法应用转发设置。'
if [[ -n ${backup} ]]; then
printf '%s' "${backup}" >"${IPF_SYSCTL_FILE}"
else
rm -f "${IPF_SYSCTL_FILE}"
fi
return 1
fi
if ! "${SYSCTL_BIN}" --system >/dev/null; then
if [[ -n ${backup} ]]; then
printf '%s' "${backup}" >"${IPF_SYSCTL_FILE}"
else
rm -f "${IPF_SYSCTL_FILE}"
fi
return 1
fi
}
env_check_apply_fixes() {
if (( ENV_CHECK_NEED_PACKAGES == 1 )); then
log_info '正在安装缺失软件包...'
_env_install_packages || return 1
fi
if (( ENV_CHECK_NEED_STORAGE == 1 )); then
log_info '正在创建状态目录...'
mkdir -p "${IPF_STORAGE_DIR}"
chmod 750 "${IPF_STORAGE_DIR}"
fi
if (( ENV_CHECK_NEED_SYSCTL == 1 )); then
log_info '正在写入 sysctl 配置并启用转发...'
_env_write_sysctl || return 1
fi
return 0
}
env_check_all() {
env_check_collect_issues
env_check_print_report
((${#ENV_CHECK_ISSUES[@]} == 0)) && return 0
if [[ ${IPF_ASSUME_YES} == 1 ]]; then
log_info '已启用自动确认,开始修复。'
elif ! prompt_confirm '是否自动修复以上问题?' n; then
log_err '用户取消自动修复,请根据提示手动安装依赖并重试。'
return 3
fi
env_check_apply_fixes || return 1
env_check_collect_issues
env_check_print_report
((${#ENV_CHECK_ISSUES[@]} == 0)) && return 0
log_err '自动修复后仍存在未解决的问题。'
return 1
}
env_status_summary() {
env_check_collect_issues
((${#ENV_CHECK_ISSUES[@]} == 0)) && printf '就绪\n' || printf '待修复(%d)\n' "${#ENV_CHECK_ISSUES[@]}"
}