#!/usr/bin/env bash set -Eeuo pipefail SCRIPT_DIR=$(cd -- "$(dirname -- "${BASH_SOURCE[0]}")" && pwd) LIB_DIR=${SCRIPT_DIR}/lib # shellcheck source=lib/common.sh source "${LIB_DIR}/common.sh" on_error() { local exit_code=$1 local line_no=$2 log_err "脚本在第 ${line_no} 行发生错误,退出码 ${exit_code}。" exit "${exit_code}" } trap 'on_error "$?" "$LINENO"' ERR # shellcheck source=lib/storage.sh source "${LIB_DIR}/storage.sh" # shellcheck source=lib/persist.sh source "${LIB_DIR}/persist.sh" # shellcheck source=lib/iptables_ops.sh source "${LIB_DIR}/iptables_ops.sh" # shellcheck source=lib/env_check.sh source "${LIB_DIR}/env_check.sh" # shellcheck source=lib/rules_mgr.sh source "${LIB_DIR}/rules_mgr.sh" : "${IPF_SKIP_ENV_CHECK:=0}" usage() { cat < [desc] ./iptables-forward.sh --batch delete ./iptables-forward.sh --batch list ./iptables-forward.sh --batch save ./iptables-forward.sh --batch env ./iptables-forward.sh --help 说明: - proto: tcp / udp / both - ipver: 4 / 6 / both - 当 ipver=both 时,target_ip 需使用 IPv4,IPv6 形式,例如 127.0.0.1,::1 USAGE } MENU_LINES=( '[1] 查看所有转发规则' '[2] 添加新的转发规则' '[3] 删除现有转发规则' '[4] 查看系统环境状态' '[5] 立即保存到磁盘' '[0] 退出' ) bootstrap() { if [[ ${IPF_SKIP_ENV_CHECK} != 1 ]]; then env_check_all fi storage_init } render_main_menu() { local status persist runtime count width line status=$(env_status_summary) count=$(storage_count) runtime=$(rules_runtime_mark) if persist_available; then persist='[✓]' else persist='[!]' fi if use_box_ui; then width=$(box_width) box_top "${width}" box_line "${width}" "${IPF_APP_NAME}" box_separator "${width}" box_line "${width}" "状态: ${status} 规则数: ${count} 持久化: ${persist} 运行态: ${runtime}" box_separator "${width}" 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 | 运行态: %s\n' "${status}" "${count}" "${persist}" "${runtime}" printf '%s\n' "${MENU_LINES[@]}" fi } main_menu_loop() { local choice while true; do render_main_menu prompt_input_capture '请选择 [0-5]' '' choice=${PROMPT_INPUT_RESULT} case ${choice} in 1) cmd_list ;; 2) cmd_add ;; 3) cmd_delete ;; 4) cmd_show_env_status ;; 5) cmd_save_rules pause_return ;; 0) log_info '已退出。' return 0 ;; *) log_warn '无效选择,请输入 0-5。' ;; esac done } run_batch() { local action=${1-} shift || true case ${action} in add) if (($# < 5)); then usage return 1 fi cmd_add_batch "$@" ;; delete) if (($# != 1)); then usage return 1 fi cmd_delete_uuid "$1" ;; list) storage_list ;; save) cmd_save_rules ;; env) env_check_all ;; *) usage return 1 ;; esac } main() { case ${1-} in --help|-h) usage return 0 ;; esac require_root || return $? bootstrap if (($# == 0)); then main_menu_loop return 0 fi case ${1-} in --batch) shift run_batch "$@" ;; *) usage return 1 ;; esac } main "$@"