Implement iptables forward manager core
This commit is contained in:
215
lib/env_check.sh
Normal file
215
lib/env_check.sh
Normal 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
|
||||
}
|
||||
Reference in New Issue
Block a user