From af871a67a34487efb818e168919e8ea836ce745f7b45afd48418919a8ec1416e Mon Sep 17 00:00:00 2001 From: ahdoawhfo Date: Fri, 17 Apr 2026 11:33:45 +0800 Subject: [PATCH] Simplify helpers under line cap --- iptables-forward.sh | 32 +++++++++--------- lib/common.sh | 61 +++++++++++++--------------------- lib/env_check.sh | 81 +++++++++++++++------------------------------ lib/persist.sh | 13 ++------ lib/storage.sh | 68 +++++++++++-------------------------- 5 files changed, 87 insertions(+), 168 deletions(-) diff --git a/iptables-forward.sh b/iptables-forward.sh index 42f86a2..d8be3bf 100644 --- a/iptables-forward.sh +++ b/iptables-forward.sh @@ -46,6 +46,15 @@ usage() { USAGE } +MENU_LINES=( + '[1] 查看所有转发规则' + '[2] 添加新的转发规则' + '[3] 删除现有转发规则' + '[4] 查看系统环境状态' + '[5] 立即保存到磁盘' + '[0] 退出' +) + bootstrap() { if [[ ${IPF_SKIP_ENV_CHECK} != 1 ]]; then env_check_all @@ -54,7 +63,7 @@ bootstrap() { } render_main_menu() { - local status persist count width + local status persist count width line status=$(env_status_summary) count=$(storage_count) if persist_available; then @@ -64,31 +73,20 @@ render_main_menu() { fi if use_box_ui; then - width=$(term_width) - if (( width > 78 )); then - width=78 - fi + width=$(box_width) box_top "${width}" box_line "${width}" "${IPF_APP_NAME}" box_separator "${width}" box_line "${width}" "状态: ${status} 规则数: ${count} 持久化: ${persist}" box_separator "${width}" - box_line "${width}" '[1] 查看所有转发规则' - box_line "${width}" '[2] 添加新的转发规则' - box_line "${width}" '[3] 删除现有转发规则' - box_line "${width}" '[4] 查看系统环境状态' - box_line "${width}" '[5] 立即保存到磁盘' - box_line "${width}" '[0] 退出' + for line in "${MENU_LINES[@]}"; do + box_line "${width}" "${line}" + done box_bottom "${width}" else printf '%s\n' "${IPF_APP_NAME}" printf '状态: %s | 规则数: %s | 持久化: %s\n' "${status}" "${count}" "${persist}" - printf '[1] 查看所有转发规则\n' - printf '[2] 添加新的转发规则\n' - printf '[3] 删除现有转发规则\n' - printf '[4] 查看系统环境状态\n' - printf '[5] 立即保存到磁盘\n' - printf '[0] 退出\n' + printf '%s\n' "${MENU_LINES[@]}" fi } diff --git a/lib/common.sh b/lib/common.sh index 4eadc4a..39f656a 100644 --- a/lib/common.sh +++ b/lib/common.sh @@ -83,19 +83,20 @@ repeat_char() { } term_width() { - if [[ -n ${COLUMNS:-} ]]; then - printf '%s\n' "${COLUMNS}" - return - fi - if command_is_available tput; then - tput cols 2>/dev/null && return - fi + [[ -n ${COLUMNS:-} ]] && { printf '%s\n' "${COLUMNS}"; return; } + command_is_available tput && tput cols 2>/dev/null && return printf '80\n' } use_box_ui() { - [[ ${IPF_FORCE_PLAIN_UI} != 1 ]] || return 1 - [[ $(term_width) -ge 60 ]] + [[ ${IPF_FORCE_PLAIN_UI} != 1 && $(term_width) -ge 60 ]] +} + +box_width() { + local width + width=$(term_width) + (( width > 78 )) && width=78 + printf '%s\n' "${width}" } pad_right() { @@ -111,20 +112,14 @@ pad_right() { printf '%s%*s' "${text}" "${padding}" '' } -box_top() { - local width=${1:-60} - printf '╔%s╗\n' "$(repeat_char '═' "$((width - 2))")" +box_border() { + local left=$1 right=$2 width=${3:-60} + printf '%s%s%s\n' "${left}" "$(repeat_char '═' "$((width - 2))")" "${right}" } -box_bottom() { - local width=${1:-60} - printf '╚%s╝\n' "$(repeat_char '═' "$((width - 2))")" -} - -box_separator() { - local width=${1:-60} - printf '╠%s╣\n' "$(repeat_char '═' "$((width - 2))")" -} +box_top() { box_border '╔' '╗' "${1:-60}"; } +box_bottom() { box_border '╚' '╝' "${1:-60}"; } +box_separator() { box_border '╠' '╣' "${1:-60}"; } box_line() { local width=${1:-60} @@ -134,19 +129,15 @@ box_line() { } print_section() { - local title=${1-} + local title=${1-} width if use_box_ui; then - local width - width=$(term_width) - if (( width > 78 )); then - width=78 - fi + width=$(box_width) box_top "${width}" box_line "${width}" "${title}" box_bottom "${width}" - else - printf '== %s ==\n' "${title}" + return fi + printf '== %s ==\n' "${title}" } read_test_input() { @@ -181,7 +172,7 @@ prompt_input() { if [[ -n ${default_value} ]]; then read -r -p "${prompt} [${default_value}]: " reply - reply=${reply:-${default_value}} + [[ -n ${reply} ]] || reply=${default_value} else read -r -p "${prompt}: " reply fi @@ -338,17 +329,11 @@ validate_port() { } validate_proto() { - case ${1-} in - tcp|udp|both) return 0 ;; - *) return 1 ;; - esac + [[ ${1-} =~ ^(tcp|udp|both)$ ]] } validate_ipver() { - case ${1-} in - 4|6|both) return 0 ;; - *) return 1 ;; - esac + [[ ${1-} =~ ^(4|6|both)$ ]] } require_root() { diff --git a/lib/env_check.sh b/lib/env_check.sh index 683269a..41d79a4 100644 --- a/lib/env_check.sh +++ b/lib/env_check.sh @@ -32,6 +32,20 @@ _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 @@ -52,30 +66,14 @@ env_check_collect_issues() { 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 - + _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 - - 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 + _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}" @@ -114,10 +112,7 @@ env_check_print_report() { } _env_install_packages() { - command_is_available "${APT_GET_BIN}" || { - log_err '缺少 apt-get,无法自动安装依赖。' - return 1 - } + 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 @@ -161,31 +156,16 @@ SYSCTL } 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_NEED_PACKAGES == 1 )) && { log_info '正在安装缺失软件包...'; _env_install_packages || return 1; } + (( ENV_CHECK_NEED_STORAGE == 1 )) && { log_info '正在创建状态目录...'; mkdir -p "${IPF_STORAGE_DIR}"; chmod 750 "${IPF_STORAGE_DIR}"; } + (( ENV_CHECK_NEED_SYSCTL == 1 )) && { log_info '正在写入 sysctl 配置并启用转发...'; _env_write_sysctl || return 1; } } env_check_all() { env_check_collect_issues env_check_print_report - if ((${#ENV_CHECK_ISSUES[@]} == 0)); then - return 0 - fi - + ((${#ENV_CHECK_ISSUES[@]} == 0)) && return 0 if [[ ${IPF_ASSUME_YES} == 1 ]]; then log_info '已启用自动确认,开始修复。' elif ! prompt_confirm '是否自动修复以上问题?' n; then @@ -197,19 +177,12 @@ env_check_all() { env_check_collect_issues env_check_print_report - if ((${#ENV_CHECK_ISSUES[@]} > 0)); then - log_err '自动修复后仍存在未解决的问题。' - return 1 - fi - - return 0 + ((${#ENV_CHECK_ISSUES[@]} == 0)) && return 0 + log_err '自动修复后仍存在未解决的问题。' + return 1 } env_status_summary() { env_check_collect_issues - if ((${#ENV_CHECK_ISSUES[@]} == 0)); then - printf '就绪\n' - else - printf '待修复(%d)\n' "${#ENV_CHECK_ISSUES[@]}" - fi + ((${#ENV_CHECK_ISSUES[@]} == 0)) && printf '就绪\n' || printf '待修复(%d)\n' "${#ENV_CHECK_ISSUES[@]}" } diff --git a/lib/persist.sh b/lib/persist.sh index a18ceaf..c23f252 100644 --- a/lib/persist.sh +++ b/lib/persist.sh @@ -9,24 +9,17 @@ IPF_PERSIST_SH_LOADED=1 : "${IPF_SKIP_PERSIST:=0}" persist_available() { - [[ ${IPF_SKIP_PERSIST} == 1 ]] && return 0 - command_is_available "${NETFILTER_PERSISTENT_BIN}" + [[ ${IPF_SKIP_PERSIST} == 1 ]] || command_is_available "${NETFILTER_PERSISTENT_BIN}" } persist_save() { [[ ${IPF_SKIP_PERSIST} == 1 ]] && return 0 - persist_available || { - log_err '未找到 netfilter-persistent,无法保存规则。' - return 1 - } + persist_available || { log_err '未找到 netfilter-persistent,无法保存规则。'; return 1; } "${NETFILTER_PERSISTENT_BIN}" save >/dev/null } persist_reload() { [[ ${IPF_SKIP_PERSIST} == 1 ]] && return 0 - persist_available || { - log_err '未找到 netfilter-persistent,无法重载规则。' - return 1 - } + persist_available || { log_err '未找到 netfilter-persistent,无法重载规则。'; return 1; } "${NETFILTER_PERSISTENT_BIN}" reload >/dev/null } diff --git a/lib/storage.sh b/lib/storage.sh index 8b19534..fcd9bbd 100644 --- a/lib/storage.sh +++ b/lib/storage.sh @@ -9,60 +9,38 @@ IPF_STORAGE_SH_LOADED=1 : "${IPF_STORAGE_DB:=${IPF_STORAGE_DIR}/rules.db}" : "${IPF_LOCK_FILE:=${IPF_STORAGE_DIR}/.lock}" -storage_dir() { - printf '%s\n' "${IPF_STORAGE_DIR}" -} - -storage_db_path() { - printf '%s\n' "${IPF_STORAGE_DB}" -} - -storage_lock_path() { - printf '%s\n' "${IPF_LOCK_FILE}" -} +storage_dir() { printf '%s\n' "${IPF_STORAGE_DIR}"; } +storage_db_path() { printf '%s\n' "${IPF_STORAGE_DB}"; } +storage_lock_path() { printf '%s\n' "${IPF_LOCK_FILE}"; } storage_init() { - local dir db lock - dir=$(storage_dir) - db=$(storage_db_path) - lock=$(storage_lock_path) - - mkdir -p "${dir}" - touch "${db}" "${lock}" - chmod 750 "${dir}" - chmod 640 "${db}" - chmod 600 "${lock}" + mkdir -p "${IPF_STORAGE_DIR}" + touch "${IPF_STORAGE_DB}" "${IPF_LOCK_FILE}" + chmod 750 "${IPF_STORAGE_DIR}" + chmod 640 "${IPF_STORAGE_DB}" + chmod 600 "${IPF_LOCK_FILE}" } storage_with_lock() { - local lock storage_init - lock=$(storage_lock_path) - ( flock -x 9 "$@" - ) 9>>"${lock}" + ) 9>>"${IPF_LOCK_FILE}" } storage_add_unlocked() { local line=${1-} - local db [[ -n ${line} ]] || return 1 storage_init - db=$(storage_db_path) - printf '%s\n' "${line}" >>"${db}" + printf '%s\n' "${line}" >>"${IPF_STORAGE_DB}" } -storage_add() { - storage_with_lock storage_add_unlocked "$@" -} +storage_add() { storage_with_lock storage_add_unlocked "$@"; } storage_list() { - local db - db=$(storage_db_path) - [[ -f ${db} ]] || return 0 - cat "${db}" + [[ -f ${IPF_STORAGE_DB} ]] || return 0 + cat "${IPF_STORAGE_DB}" } storage_parse() { @@ -95,11 +73,10 @@ storage_get() { storage_delete_unlocked() { local uuid=${1-} - local db tmp found=0 line current + local tmp found=0 line current [[ -n ${uuid} ]] || return 1 storage_init - db=$(storage_db_path) - tmp="${db}.tmp.$$" + tmp="${IPF_STORAGE_DB}.tmp.$$" : >"${tmp}" while IFS= read -r line || [[ -n ${line} ]]; do @@ -109,19 +86,12 @@ storage_delete_unlocked() { continue fi printf '%s\n' "${line}" >>"${tmp}" - done <"${db}" - - if (( found == 0 )); then - rm -f "${tmp}" - return 1 - fi - - mv "${tmp}" "${db}" + done <"${IPF_STORAGE_DB}" + (( found == 1 )) || { rm -f "${tmp}"; return 1; } + mv "${tmp}" "${IPF_STORAGE_DB}" } -storage_delete() { - storage_with_lock storage_delete_unlocked "$@" -} +storage_delete() { storage_with_lock storage_delete_unlocked "$@"; } storage_count() { local count=0 line