Implement iptables forward manager core

This commit is contained in:
2026-04-17 09:36:40 +08:00
parent d1a5392476
commit 28960eee03
20 changed files with 2047 additions and 0 deletions

215
lib/env_check.sh Normal file
View File

@@ -0,0 +1,215 @@
#!/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_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
if ! command_is_available "${IPF_CHECK_IPTABLES_CMD}"; then
_env_add_issue '缺少 iptables 命令。'
ENV_CHECK_NEED_PACKAGES=1
fi
if ! command_is_available "${IPF_CHECK_IP6TABLES_CMD}"; then
_env_add_issue '缺少 ip6tables 命令。'
ENV_CHECK_NEED_PACKAGES=1
fi
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
if [[ $(_env_file_value "${IPF_IPV4_FORWARD_FILE}" 2>/dev/null || printf '0') != 1 ]]; then
_env_add_issue 'IPv4 转发未开启。'
ENV_CHECK_NEED_SYSCTL=1
fi
if [[ $(_env_file_value "${IPF_IPV6_FORWARD_FILE}" 2>/dev/null || printf '0') != 1 ]]; then
_env_add_issue 'IPv6 转发未开启。'
ENV_CHECK_NEED_SYSCTL=1
fi
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
}
env_check_all() {
env_check_collect_issues
env_check_print_report
if ((${#ENV_CHECK_ISSUES[@]} == 0)); then
return 0
fi
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
if ((${#ENV_CHECK_ISSUES[@]} > 0)); then
log_err '自动修复后仍存在未解决的问题。'
return 1
fi
return 0
}
env_status_summary() {
env_check_collect_issues
if ((${#ENV_CHECK_ISSUES[@]} == 0)); then
printf '就绪\n'
else
printf '待修复(%d)\n' "${#ENV_CHECK_ISSUES[@]}"
fi
}