#!/bin/bash

# --- [0. 初始化] 权限与环境检测 ---
# 必须先确保是 Root 用户，否则后续操作无法执行
if [ "$(id -u)" != "0" ]; then
  echo -e "\033[31m[×] 错误：此脚本必须以 root 权限运行\033[0m"
  exit 1
fi

# --- [0. 初始化] 字符集修复 ---
# 强制使用 UTF-8，防止中文显示乱码或对齐错误
export LANG=C.UTF-8
export LC_ALL=C.UTF-8

# --- [1. 核心] 系统与包管理器检测 ---
check_os() {
  if [ -f /etc/os-release ]; then
    . /etc/os-release
    OS_ID=$ID
    OS_VERSION_ID=$VERSION_ID
  elif [ -f /etc/redhat-release ]; then
    OS_ID="centos" # 兼容性回退
  else
    OS_ID="unknown"
  fi

  # 归一化发行版名称与包管理器配置
  case "$OS_ID" in
  ubuntu | debian | kali)
    PKG_MANAGER="apt"
    PKG_UPDATE="apt-get update"
    PKG_INSTALL="apt-get install -y"
    PKG_REMOVE="apt-get purge -y"
    PKG_CLEAN="apt-get autoremove -y && apt-get clean"
    ;;
  centos | rhel | fedora | almalinux | rockylinux | anolis)
    if command -v dnf >/dev/null 2>&1; then
      PKG_MANAGER="dnf"
      PKG_UPDATE="dnf makecache"
      PKG_INSTALL="dnf install -y"
      PKG_REMOVE="dnf remove -y"
      PKG_CLEAN="dnf autoremove -y && dnf clean all"
    else
      PKG_MANAGER="yum"
      PKG_UPDATE="yum makecache"
      PKG_INSTALL="yum install -y"
      PKG_REMOVE="yum remove -y"
      PKG_CLEAN="yum autoremove -y && yum clean all"
    fi
    OS_FAMILY="rhel"
    ;;
  *)
    echo -e "\033[31m[×] 错误：不支持的操作系统发行版: $OS_ID\033[0m"
    exit 1
    ;;
  esac

  # 定义跨发行版服务名称
  case "$OS_ID" in
  ubuntu | debian | kali)   # [修复] 将 kali 添加到服务名定义
    SVC_CRON="cron"
    SVC_SSH="ssh"
    SVC_HTTP="apache2"
    ;;
  centos | rhel | fedora | almalinux | rockylinux | anolis)
    SVC_CRON="crond"
    SVC_SSH="sshd"
    SVC_HTTP="httpd"
    ;;
  esac
}

check_os

# --- [2. 配置] 终端配色 ---
RED='\033[31m'
GREEN='\033[32m'
YELLOW='\033[33m'
BLUE='\033[34m'
CYAN='\033[36m'
BOLD='\033[1m'
RESET='\033[0m'
GRAY='\033[90m'

# --- [2. 配置] 信号捕获 (Ctrl+C) ---
SKIP_PAUSE=false
CTRL_C_PRESSED=false

trap_ctrl_c() {
  echo -e "\n${YELLOW}[!] 用户触发中断 (Ctrl+C)，正在返回主菜单...${RESET}"
  SKIP_PAUSE=true
  CTRL_C_PRESSED=true
}
trap trap_ctrl_c SIGINT

# --- [3. 核心] 包管理器锁检测 (通用版) ---
check_pm_lock() {
  local lock_files=()
  
  if [[ "$PKG_MANAGER" == "apt" ]]; then
    lock_files=("/var/lib/dpkg/lock" "/var/lib/dpkg/lock-frontend" "/var/lib/apt/lists/lock")
  elif [[ "$PKG_MANAGER" == "yum" || "$PKG_MANAGER" == "dnf" ]]; then
    lock_files=("/var/run/yum.pid" "/var/run/dnf.pid" "/var/lib/rpm/.dbenv.lock")
  fi

  local locked=false
  local pids=""

  for lock in "${lock_files[@]}"; do
    if [ -f "$lock" ] && fuser "$lock" >/dev/null 2>&1; then
      locked=true
      local pid
      pid=$(fuser "$lock" 2>/dev/null | awk '{print $1}')
      pids="$pids $pid"
    fi
  done

  if [ "$locked" = true ]; then
    echo -e "${RED}[!] 检测到包管理器锁被占用 (PID: $pids)${RESET}"
    echo -e "${YELLOW}可能有系统自动更新正在后台运行。${RESET}"
    echo -e "请选择操作："
    echo -e "  1. 等待锁释放 (推荐)"
    echo -e "  2. 强制杀掉占用进程 (可能导致数据库损坏)"
    echo -e "  3. 取消当前操作"

    read -p "请输入选项 [1-3]: " lock_choice
    case $lock_choice in
    1)
      echo -e "${CYAN}>>> 正在等待锁释放 (按 Ctrl+C 可取消)...${RESET}"
      CTRL_C_PRESSED=false

      while true; do
        local still_locked=false
        for lock in "${lock_files[@]}"; do
           if [ -f "$lock" ] && fuser "$lock" >/dev/null 2>&1; then
             still_locked=true
             break
           fi
        done
        
        if [ "$still_locked" = false ]; then break; fi

        if [ "$CTRL_C_PRESSED" = true ]; then
          echo -e "\n${YELLOW}>>> 用户取消等待，操作终止。${RESET}"
          return 1
        fi
        echo -n "."
        sleep 2
      done

      if [ "$CTRL_C_PRESSED" = true ]; then return 1; fi
      echo -e "\n${GREEN}[√] 锁已释放${RESET}"
      ;;
    2)
      echo -e "${RED}>>> 正在强制终止占用进程...${RESET}"
      for pid in $pids; do
        kill -9 "$pid" 2>/dev/null
      done
      # 针对 APT 需要额外清理锁文件
      if [[ "$PKG_MANAGER" == "apt" ]]; then
          rm -f /var/lib/dpkg/lock /var/lib/dpkg/lock-frontend /var/lib/apt/lists/lock
          dpkg --configure -a >/dev/null 2>&1
      fi
      echo -e "${GREEN}[√] 已强制解锁${RESET}"
      ;;
    *)
      echo -e "${YELLOW}操作已取消${RESET}"
      return 1
      ;;
    esac
  fi
  return 0
}

# --- [3. 核心] 基础依赖检查与自动安装 ---
check_dependencies() {
  local commands=("curl" "wget" "grep" "awk" "sed" "ip" "ss" "lsof")
  local install_needed=false
  local missing_cmds=""

  for cmd in "${commands[@]}"; do
    if ! command -v "$cmd" &>/dev/null; then
      install_needed=true
      missing_cmds="$missing_cmds $cmd"
    fi
  done

  if [ "$install_needed" = true ]; then
    echo -e "\033[36m>>> 检测到缺失工具 ($missing_cmds)，正在自动安装...\033[0m"
    
    # 检查包管理器锁
    check_pm_lock || exit 1

    # 兼容性包名映射
    local pkg_curl="curl"
    local pkg_wget="wget"
    local pkg_grep="grep"
    local pkg_awk="gawk"
    local pkg_sed="sed"
    local pkg_lsof="lsof"
    local pkg_iproute="iproute2"

    if [[ "$PKG_MANAGER" == "yum" || "$PKG_MANAGER" == "dnf" ]]; then
       pkg_iproute="iproute" # RHEL系叫 iproute
    fi

    # [优化] 先更新包索引（精简系统可能没有缓存）
    echo -e "\033[36m>>> 更新软件源缓存...\033[0m"
    if [[ "$PKG_MANAGER" == "apt" ]]; then
       export DEBIAN_FRONTEND=noninteractive
       # 使用 apt-get update，忽略部分仓库错误
       apt-get update -qq 2>/dev/null || apt-get update 2>&1 | grep -v "^W:" || true
    else
       $PKG_UPDATE >/dev/null 2>&1
    fi

    echo -e "\033[36m>>> 安装依赖包...\033[0m"
    if [[ "$PKG_MANAGER" == "apt" ]]; then
       # [优化] 使用 --fix-broken 处理可能的依赖问题
       apt-get install -y --fix-broken $pkg_curl $pkg_wget $pkg_grep $pkg_awk $pkg_sed $pkg_iproute $pkg_lsof 2>&1 || {
         echo -e "\033[33m>>> 首次安装失败，尝试修复依赖后重试...\033[0m"
         apt-get --fix-broken install -y 2>/dev/null
         apt-get install -y $pkg_curl $pkg_wget $pkg_grep $pkg_awk $pkg_sed $pkg_iproute $pkg_lsof
       }
    else
       $PKG_INSTALL $pkg_curl $pkg_wget $pkg_grep $pkg_awk $pkg_sed $pkg_iproute $pkg_lsof
    fi

    # 二次验证
    local still_missing=""
    for cmd in "${commands[@]}"; do
      if ! command -v "$cmd" &>/dev/null; then
        still_missing="$still_missing $cmd"
      fi
    done
    
    if [ -n "$still_missing" ]; then
      echo -e "\033[31m[×] 错误：以下命令依然无法找到:$still_missing\033[0m"
      echo -e "\033[33m请尝试手动安装缺失的软件包后重新运行脚本。\033[0m"
      echo -e "\033[33m例如: apt-get update && apt-get install -y curl wget\033[0m"
      exit 1
    fi
    echo -e "\033[32m[√] 依赖安装完成\033[0m"
  fi
}

check_dependencies

# --- [4. 机制] 退出前自动清理 ---
# 创建临时文件目录
TEMP_DIR=$(mktemp -d)
CACHE_FILE="${TEMP_DIR}/sys_info_cache"

on_exit() {
  # 脚本退出时自动清理临时目录
  if [ -n "$TEMP_DIR" ] && [ -d "$TEMP_DIR" ]; then
    rm -rf "$TEMP_DIR"
  fi
}

# 注册 EXIT 信号，Ctrl+C (SIGINT) 已单独处理
trap on_exit EXIT

# --- [5. 配置] 远程脚本地址 ---
COUNT=$(curl -s -m 5 https://sh.cici.one/count.php 2>/dev/null || echo "N/A")
SCRIPT_URL="bash <(curl -sL sh.cici.one)"

# --- [工具] 辅助函数 ---
get_system_version() {
  # --- 策略说明 ---
  # 1. 优先从 /etc/os-release 读取 VERSION_ID
  # 2. 对于 Debian 系，如果 VERSION_ID 只有主版本号，尝试从 /etc/debian_version 获取更详细版本
  # 3. 对于 Kali 等滚动发行版，使用 VERSION 字段
  # 4. 兜底读取 /etc/debian_version 或 /etc/redhat-release
  
  local version_id=""
  local os_id=""
  
  if [ -f /etc/os-release ]; then
    version_id=$(grep "^VERSION_ID" /etc/os-release | cut -d'=' -f2 | tr -d '"')
    os_id=$(grep "^ID=" /etc/os-release | cut -d'=' -f2 | tr -d '"')
  fi
  
  # 对于 Debian，尝试获取更详细的版本号
  if [ "$os_id" = "debian" ] && [ -f /etc/debian_version ]; then
    local deb_ver
    deb_ver=$(cat /etc/debian_version)
    # 如果 debian_version 是数字版本格式（如 13.0），优先使用
    if [[ "$deb_ver" =~ ^[0-9]+\.[0-9]+ ]]; then
      echo "$deb_ver"
      return
    fi
    # 否则使用 VERSION_ID（避免显示 trixie/sid 等代号）
    if [ -n "$version_id" ]; then
      echo "$version_id"
      return
    fi
  fi
  
  # 对于其他发行版，直接使用 VERSION_ID
  if [ -n "$version_id" ]; then
    echo "$version_id"
    return
  fi
  
  # 尝试 VERSION 字段 (如 Kali 2024.1)
  if [ -f /etc/os-release ]; then
    local version
    version=$(grep "^VERSION=" /etc/os-release | cut -d'=' -f2 | tr -d '"')
    if [ -n "$version" ]; then
      echo "$version"
      return
    fi
  fi
  
  # RHEL/CentOS/Rocky/Alma 兜底
  if [ -f /etc/redhat-release ]; then
    grep -oE '[0-9]+\.[0-9]+' /etc/redhat-release | head -1
    return
  fi
  
  # Debian 系滚动发行版兜底 (如 Sid)
  if [ -f /etc/debian_version ]; then
    cat /etc/debian_version
    return
  fi
  
  echo "未知"
}

get_debian_major_version() {
  [ -f /etc/debian_version ] && cut -d'.' -f1 </etc/debian_version || echo "0"
}

# --- [工具] 容器环境检测 (全局公共函数) ---
# 用于检测是否运行在容器化环境中 (OpenVZ/LXC/Docker 等)
# 容器环境通常无法修改内核参数、加载模块、创建 SWAP 等
is_container_env() {
  # OpenVZ 容器
  if [ -f /proc/vz/veinfo ] && [ ! -f /proc/vz/version ]; then return 0; fi
  # LXC 容器
  if grep -qa "container=lxc" /proc/1/environ 2>/dev/null; then return 0; fi
  if grep -q "lxc" /proc/1/cgroup 2>/dev/null; then return 0; fi
  # Docker 容器 (非宿主机)
  if [ -f /.dockerenv ]; then return 0; fi
  if grep -q "docker" /proc/1/cgroup 2>/dev/null; then return 0; fi
  # systemd-detect-virt 检测容器类型
  if command -v systemd-detect-virt >/dev/null 2>&1; then
    local virt_type=$(systemd-detect-virt 2>/dev/null)
    case "$virt_type" in
      lxc|lxc-libvirt|docker|podman|openvz) return 0 ;;
    esac
  fi
  return 1
}

# --- [工具] sysctl 参数可写性检测 ---
# 检测指定的 sysctl 参数是否可写 (容器环境常为只读)
is_sysctl_writable() {
  local param="$1"
  local current_val
  current_val=$(sysctl -n "$param" 2>/dev/null)
  [ -z "$current_val" ] && return 1
  
  # 尝试写入相同值测试可写性
  sysctl -w "${param}=${current_val}" >/dev/null 2>&1
  return $?
}

# --- [工具] 信息展示 (自动对齐) ---
display_info() {
  local title="$1"
  local items=("${@:2}")

  echo -e "${BOLD}${CYAN}${title}${RESET}"

  # ---- 计算最长标签显示宽度（中文=2宽度，英文=1宽度）----
  local max_label_width=0
  for item in "${items[@]}"; do
    IFS='|' read -r label _ <<<"$item"
    # 去除颜色码
    local clean_label
    clean_label=$(echo -e "$label" | sed -E "s/\x1B\[[0-9;]*[mK]//g")
    # 计算宽度（中文算2）
    local width=0
    for ((i = 0; i < ${#clean_label}; i++)); do
      local c="${clean_label:i:1}"
      [[ "$c" =~ [\x00-\x7F] ]] && ((width += 1)) || ((width += 2))
    done
    ((width > max_label_width)) && max_label_width=$width
  done

  # ---- 输出对齐 ----
  for item in "${items[@]}"; do
    IFS='|' read -r label value <<<"$item"

    # 去除颜色计算实际宽度
    local clean_label
    clean_label=$(echo -e "$label" | sed -E "s/\x1B\[[0-9;]*[mK]//g")
    local width=0
    for ((i = 0; i < ${#clean_label}; i++)); do
      local c="${clean_label:i:1}"
      [[ "$c" =~ [\x00-\x7F] ]] && ((width += 1)) || ((width += 2))
    done

    local padding=$((max_label_width - width))
    local spaces=""
    for ((i = 0; i < padding; i++)); do
      spaces+=" "
    done

    echo -e "  ${YELLOW}${label}:${RESET}${spaces} ${value}"
  done
  echo -e "${CYAN}--------------------------------------------------${RESET}"
}

# ---------- 虚拟化检测函数 ----------
detect_virtualization() {
  local virt_type="未知"
  # 检测容器环境
  if [ -f /.dockerenv ]; then
    virt_type="Docker容器"
  elif grep -q "docker" /proc/1/cgroup 2>/dev/null; then
    virt_type="Docker容器"
  elif grep -q "lxc" /proc/1/cgroup 2>/dev/null; then
    virt_type="LXC容器"
  elif command -v systemd-detect-virt >/dev/null 2>&1; then
    local sdv
    sdv=$(systemd-detect-virt 2>/dev/null)
    [ -z "$sdv" ] && sdv="none"
    case $sdv in
    kvm) virt_type="KVM虚拟机" ;;
    qemu) virt_type="QEMU虚拟机" ;;
    vmware) virt_type="VMware虚拟机" ;;
    microsoft) virt_type="Hyper-V虚拟机" ;;
    oracle) virt_type="VirtualBox虚拟机" ;;
    xen) virt_type="Xen虚拟机" ;;
    lxc | lxc-libvirt) virt_type="LXC容器" ;;
    docker) virt_type="Docker容器" ;;
    podman) virt_type="Podman容器" ;;
    none) virt_type="物理机/未知" ;;
    *) virt_type="$sdv" ;;
    esac
  elif [ -f /proc/cpuinfo ] && grep -q "hypervisor" /proc/cpuinfo; then
    virt_type="虚拟化环境"
  elif command -v dmidecode >/dev/null 2>&1; then
    local bios_vendor
    bios_vendor=$(dmidecode -s system-manufacturer 2>/dev/null | head -1)
    case $bios_vendor in
    *[Vv][Mm][Ww]are*) virt_type="VMware虚拟机" ;;
    *[Qq][Ee][Mm][Uu]*) virt_type="QEMU虚拟机" ;;
    *[Mm]icrosoft*) virt_type="Hyper-V虚拟机" ;;
    *[Oo]racle*) virt_type="VirtualBox虚拟机" ;;
    *[Xx]en*) virt_type="Xen虚拟机" ;;
    *[Kk][Vv][Mm]*) virt_type="KVM虚拟机" ;;
    esac
  fi

  echo "$virt_type"
}

# ---------- 并行执行函数 ----------
run_parallel() {
  local funcs=("$@")
  local pids=()
  local outfiles=()

  for i in "${!funcs[@]}"; do
    outfiles[$i]="${TEMP_DIR}/parallel_result_$i"
    ${funcs[$i]} >"${outfiles[$i]}" 2>/dev/null &
    pids[$i]=$!
  done

  # 等待并读结果
  for i in "${!pids[@]}"; do
    wait "${pids[$i]}" 2>/dev/null
  done

  for i in "${!outfiles[@]}"; do
    if [ -f "${outfiles[$i]}" ]; then
      cat "${outfiles[$i]}"
      rm -f "${outfiles[$i]}"
    fi
  done
}

# ---------- 网络检测函数（用于并行执行） ----------
get_ipv4_public() {
  curl -s -4 --connect-timeout 2 ifconfig.co 2>/dev/null || echo "N/A"
}

get_ipv6_public() {
  curl -s -6 --connect-timeout 2 ifconfig.co 2>/dev/null || echo "N/A"
}

get_isp_info() {
  local ip=$1
  if [ -n "$ip" ] && [ "$ip" != "N/A" ]; then
    local result
    result=$(curl -s -4 --connect-timeout 2 "ipinfo.io/$ip/org" 2>/dev/null | head -1)
    [ -z "$result" ] && result="未知"
    echo "$result"
  else
    echo "未知"
  fi
}

get_location_info() {
  local ip=$1
  if [ -n "$ip" ] && [ "$ip" != "N/A" ]; then
    local city country
    city=$(curl -s -4 --connect-timeout 2 "ipinfo.io/$ip/city" 2>/dev/null)
    [ -z "$city" ] && city="未知"
    country=$(curl -s -4 --connect-timeout 2 "ipinfo.io/$ip/country" 2>/dev/null)
    [ -z "$country" ] && country="未知"
    echo "$city, $country"
  else
    echo "未知"
  fi
}

# ---------- 系统信息显示 (最终版：虚拟化支持检测+完美对齐) ----------
display_system_info() {
  clear
  # --- 0. 标题头 ---
  echo -e "${BOLD}${CYAN}"
  echo "============================================================================="
  echo "                         🚀 极光VPS系统管理工具"
  echo "============================================================================="
  echo -e "${RESET}${CYAN}作者: FMSO ${YELLOW}|${CYAN} 版本: v2026-03-15 ${YELLOW}|${CYAN} 调用: ${COUNT}次"
  echo -e "地址: ${SCRIPT_URL}"
  echo -e "=============================================================================${RESET}"

  # --- 1. 缓存与数据采集 ---
  local HW_CACHE="${TEMP_DIR}/hardware_cache"
  local CACHE_HIT=false

  if [ -f "$CACHE_FILE" ]; then
    source "$CACHE_FILE"
    CACHE_HIT=true
  else
    echo -e "${CYAN}正在初始化系统信息 (首次运行需检测网络)...${RESET}"
  fi

  if [ "$CACHE_HIT" = false ]; then
    tmp4="${TEMP_DIR}/get_ipv4"
    tmp6="${TEMP_DIR}/get_ipv6"
    tmp_isp="${TEMP_DIR}/isp"
    tmp_loc="${TEMP_DIR}/loc"
    get_ipv4_public >"$tmp4" 2>/dev/null &
    pid4=$!
    get_ipv6_public >"$tmp6" 2>/dev/null &
    pid6=$!
  fi

  if [ -f "$HW_CACHE" ]; then
    source "$HW_CACHE"
  else
    if command -v lsb_release >/dev/null 2>&1; then
      os_name=$(lsb_release -d | cut -f2-)
    else
      os_name=$(grep "PRETTY_NAME" /etc/os-release | cut -d'"' -f2 2>/dev/null || uname -s)
    fi
    sys_ver=$(get_system_version)
    kernel_ver=$(uname -r)
    arch_info=$(uname -m)
    virt_type=$(detect_virtualization)

    # CPU 基础信息
    cpu_model=$(grep -m1 'model name' /proc/cpuinfo 2>/dev/null | cut -d':' -f2 | xargs || echo "未知")
    [ -z "$cpu_model" ] && cpu_model="未知"
    cpu_count=$(grep -c '^processor' /proc/cpuinfo 2>/dev/null || echo "1")

    # CPU 主频
    cpu_mhz=$(grep -m1 'cpu MHz' /proc/cpuinfo 2>/dev/null | cut -d':' -f2 | xargs | awk '{printf "%.0f MHz", $1}')
    [ -z "$cpu_mhz" ] && cpu_mhz="未知"

    # [修改] 虚拟化支持检测 (替换了 CPU缓存)
    if grep -qE 'vmx|svm' /proc/cpuinfo 2>/dev/null; then
      virt_support="${GREEN}✅ 支持 (Nested)${RESET}"
    else
      virt_support="${RED}❌ 不支持${RESET}"
    fi

    # AES 指令集
    if grep -q aes /proc/cpuinfo 2>/dev/null; then
      aes_status="${GREEN}✅ 支持${RESET}"
    else
      aes_status="${RED}❌ 不支持${RESET}"
    fi

    cat >"$HW_CACHE" <<EOF
os_name="$os_name"
sys_ver="$sys_ver"
kernel_ver="$kernel_ver"
arch_info="$arch_info"
virt_type="$virt_type"
cpu_model="$cpu_model"
cpu_count="$cpu_count"
cpu_mhz="$cpu_mhz"
virt_support="$virt_support"
aes_status="$aes_status"
EOF
  fi

  if uptime -p >/dev/null 2>&1; then uptime_info=$(uptime -p | sed 's/up //'); else uptime_info=$(uptime | sed -E 's/^.* up +//; s/, *[0-9]+ users.*//; s/, *load average.*//'); fi
  boot_time=$(who -b | awk '{print $3 " " $4}')
  load_info=$(uptime | awk -F'load average:' '{print $2}' | xargs)
  current_user=$(whoami)
  hostname_info=$(hostname)

  # --- CPU 计算 ---
  get_cpu_stat() {
    read -r line </proc/stat
    echo "$line" | awk '{print $2+$3+$4+$5+$6+$7+$8+$9+$10+$11, $5+$6, $9}'
  }
  read -r cur_total cur_idle cur_steal <<<$(get_cpu_stat)
  if [ -z "$PREV_CPU_TOTAL" ]; then
    sleep 0.5
    read -r next_total next_idle next_steal <<<$(get_cpu_stat)
    diff_total=$((next_total - cur_total))
    diff_idle=$((next_idle - cur_idle))
    diff_steal=$((next_steal - cur_steal))
    cur_total=$next_total
    cur_idle=$next_idle
    cur_steal=$next_steal
  else
    diff_total=$((cur_total - PREV_CPU_TOTAL))
    diff_idle=$((cur_idle - PREV_CPU_IDLE))
    diff_steal=$((cur_steal - PREV_CPU_STEAL))
  fi
  PREV_CPU_TOTAL=$cur_total
  PREV_CPU_IDLE=$cur_idle
  PREV_CPU_STEAL=$cur_steal

  if [ "$diff_total" -gt 0 ]; then
    cpu_usage=$(awk -v i="$diff_idle" -v t="$diff_total" 'BEGIN {printf "%.1f%%", 100 - (i/t)*100}')
    cpu_st=$(awk -v s="$diff_steal" -v t="$diff_total" 'BEGIN {printf "%.1f", (s/t)*100}')
  else
    cpu_usage="0.0%"
    cpu_st="0.0"
  fi

  # Steal 颜色
  st_int=$(echo "$cpu_st" | awk -F. '{print $1}')
  if [ "$st_int" -ge 10 ]; then st_display="${RED}${cpu_st}% (严重抢占)${RESET}"; elif [ "$st_int" -gt 0 ]; then st_display="${YELLOW}${cpu_st}% (轻微争抢)${RESET}"; else st_display="${GREEN}${cpu_st}% (良好)${RESET}"; fi

  # 内存/Swap
  mem_info=$(free -h 2>/dev/null | awk '/Mem:/ {print $2, $3}')
  mem_total=$(echo "$mem_info" | awk '{print $1}')
  mem_used=$(echo "$mem_info" | awk '{print $2}')
  
  # [修复] 如果 free -h 获取失败 (为空)，尝试读取 /proc/meminfo
  if [ -z "$mem_total" ] || [ -z "$mem_used" ]; then
      if [ -f /proc/meminfo ]; then
          # 单位 kB
          total_kb=$(grep -i "MemTotal" /proc/meminfo | awk '{print $2}')
          avail_kb=$(grep -i "MemAvailable" /proc/meminfo | awk '{print $2}')
          # 若无 MemAvailable (老内核), 尝试 MemFree + Buffers + Cached
          if [ -z "$avail_kb" ]; then
             free_kb=$(grep -i "MemFree" /proc/meminfo | awk '{print $2}')
             buf_kb=$(grep -i "Buffers" /proc/meminfo | awk '{print $2}')
             cache_kb=$(grep -i "^Cached" /proc/meminfo | awk '{print $2}')
             avail_kb=$((free_kb + buf_kb + cache_kb))
          fi
          
          used_kb=$((total_kb - avail_kb))
          
          # 格式化函数
          calc_size() {
             local k=$1
             if [ "$k" -lt 1024 ]; then echo "${k}K";
             elif [ "$k" -lt 1048576 ]; then awk -v k="$k" 'BEGIN{printf "%.1fM", k/1024}';
             else awk -v k="$k" 'BEGIN{printf "%.1fG", k/1024/1024}'; fi
          }
          
          mem_total=$(calc_size "$total_kb")
          mem_used=$(calc_size "$used_kb")
          mem_percent=$(awk -v u="$used_kb" -v t="$total_kb" 'BEGIN{if(t>0) printf "%.1f%%", u/t*100; else print "0.0%"}')
      else
          mem_total="N/A"
          mem_used="N/A"
          mem_percent="0.0%"
      fi
  else
      mem_percent=$(free 2>/dev/null | awk '/Mem:/ {used=$3; total=$2; if(total>0) printf "%.1f%%", used/total*100}')
  fi

  swap_info=$(free -h 2>/dev/null | awk '/Swap:/ {print $2, $3}')
  swap_total=$(echo "$swap_info" | awk '{print $1}')
  swap_used=$(echo "$swap_info" | awk '{print $2}')
  
  # [修复] Swap 兜底检测
  if [ -z "$swap_total" ] || [ -z "$swap_used" ]; then
    if [ -f /proc/meminfo ]; then
      swap_total_kb=$(grep -i "SwapTotal" /proc/meminfo | awk '{print $2}')
      swap_free_kb=$(grep -i "SwapFree" /proc/meminfo | awk '{print $2}')
      
      if [ -n "$swap_total_kb" ] && [ "$swap_total_kb" -gt 0 ]; then
        swap_used_kb=$((swap_total_kb - swap_free_kb))
        
        # 复用 calc_size
        swap_total=$(calc_size "$swap_total_kb")
        swap_used=$(calc_size "$swap_used_kb")
        swap_percent=$(awk -v u="$swap_used_kb" -v t="$swap_total_kb" 'BEGIN{if(t>0) printf "%.1f%%", u/t*100; else print "0.0%"}')
      else
        # 确实没有 Swap
        swap_total="0B"
      fi
    else
      swap_total="0B"
    fi
  else
    swap_percent=$(free 2>/dev/null | awk '/Swap:/ {used=$3; total=$2; if(total>0) printf "%.1f%%", used/total*100}')
  fi

  if [ -z "$swap_total" ] || [ "$swap_total" = "0B" ]; then
    swap_display="${RED}未检测到SWAP分区${RESET}"
  else
    swap_display="$swap_used / $swap_total ($swap_percent)"
  fi

  # 网络处理
  if [ "$CACHE_HIT" = false ]; then
    wait $pid4 2>/dev/null
    wait $pid6 2>/dev/null
    ipv4_public=$(cat "$tmp4" 2>/dev/null || echo "N/A")
    ipv6_public=$(cat "$tmp6" 2>/dev/null || echo "N/A")
    get_isp_info "$ipv4_public" >"$tmp_isp" 2>/dev/null &
    pid_isp=$!
    get_location_info "$ipv4_public" >"$tmp_loc" 2>/dev/null &
    pid_loc=$!
    wait $pid_isp 2>/dev/null
    wait $pid_loc 2>/dev/null
    isp_info=$(cat "$tmp_isp" 2>/dev/null || echo "未知")
    location_info=$(cat "$tmp_loc" 2>/dev/null || echo "未知")
    cat >"$CACHE_FILE" <<EOF
ipv4_public="$ipv4_public"
ipv6_public="$ipv6_public"
isp_info="$isp_info"
location_info="$location_info"
EOF
  fi

  ipv4_local=$(hostname -I 2>/dev/null | awk '{print $1}')
  ipv6_local=$(ip -6 addr show 2>/dev/null | grep "inet6" | grep -v "::1" | awk '{print $2}' | cut -d'/' -f1 | head -1)
  current_time=$(date '+%Y-%m-%d %H:%M:%S')
  timezone=$(timedatectl show --property=Timezone --value 2>/dev/null || date '+%Z')
  default_interface=$(ip route get 8.8.8.8 2>/dev/null | awk '{for(i=1;i<=NF;i++) if ($i=="dev") print $(i+1)}')
  if [ -n "$default_interface" ]; then
    mac_address=$(ip link show "$default_interface" 2>/dev/null | awk '/link\/ether/ {print $2; exit}' || echo "未知")
    rx=$(cat /sys/class/net/"$default_interface"/statistics/rx_bytes 2>/dev/null || echo 0)
    tx=$(cat /sys/class/net/"$default_interface"/statistics/tx_bytes 2>/dev/null || echo 0)
    rx_h=$(awk -v b=$rx 'BEGIN{printf "%.2f GB", b/1024/1024/1024}')
    tx_h=$(awk -v b=$tx 'BEGIN{printf "%.2f GB", b/1024/1024/1024}')
  else
    default_interface="未知"
    mac_address="未知"
    rx_h="0 GB"
    tx_h="0 GB"
  fi
  # DNS 检测 (增强：处理 systemd-resolved stub resolver)
  dns_servers=$(grep -oP 'nameserver\s+\K\S+' /etc/resolv.conf 2>/dev/null | head -3 | tr '\n' ',' | sed 's/,$//')
  
  # 如果只有 127.0.0.53，尝试从 resolvectl 获取真实 DNS
  if [ "$dns_servers" = "127.0.0.53" ] && command -v resolvectl >/dev/null 2>&1; then
    local real_dns
    real_dns=$(resolvectl status 2>/dev/null | grep -oP 'DNS Servers:\s+\K\S+' | head -3 | tr '\n' ',' | sed 's/,$//')
    [ -n "$real_dns" ] && dns_servers="$real_dns"
  fi
  
  [ -z "$dns_servers" ] && dns_servers="未配置"

  display_ipv4_pub=$ipv4_public
  [ "$ipv4_public" = "N/A" ] && display_ipv4_pub="${RED}❌ 无法获取${RESET}"
  display_ipv6_pub=$ipv6_public
  [ "$ipv6_public" = "N/A" ] && display_ipv6_pub="${RED}❌ 无法获取${RESET}"

  # ==================== 全局对齐配置 ====================
  ALIGN_WIDTH=53
  LABEL_WIDTH=10

  # --- 打印函数：双列 (自动对齐) ---
  print_row() {
    local l1=$1
    local v1=$2
    local l2=$3
    local v2=$4

    # --- 左侧处理 ---
    local clean_l1=$(echo -e "$l1" | sed -r 's/\x1B\[[0-9;]*[mK]//g')
    local l1_len=$(echo -n "$clean_l1" | wc -L)
    local l1_pad_len=$((LABEL_WIDTH - l1_len))
    [ $l1_pad_len -lt 0 ] && l1_pad_len=0
    local l1_padding=$(printf "%${l1_pad_len}s" "")

    # 组合左侧: "Label:      Value"
    local left_full="${YELLOW}${l1}:${RESET}${l1_padding} ${v1}"

    # 计算左侧总视觉长度 (用于分隔符对齐)
    local clean_left="${clean_l1}:${l1_padding} $(echo -e "$v1" | sed -r 's/\x1B\[[0-9;]*[mK]//g')"
    local left_visual_len=$(echo -n "$clean_left" | wc -L)

    # 计算分隔符填充
    local sep_pad_len=$((ALIGN_WIDTH - left_visual_len))
    [ $sep_pad_len -lt 1 ] && sep_pad_len=1
    local sep_padding=$(printf "%${sep_pad_len}s" "")

    # --- 右侧处理 ---
    # 右侧也同样对齐值
    local clean_l2=$(echo -e "$l2" | sed -r 's/\x1B\[[0-9;]*[mK]//g')
    local l2_len=$(echo -n "$clean_l2" | wc -L)
    local l2_pad_len=$((LABEL_WIDTH - l2_len))
    [ $l2_pad_len -lt 0 ] && l2_pad_len=0
    local l2_padding=$(printf "%${l2_pad_len}s" "")

    # 输出完整行
    printf "  %b%s| ${YELLOW}%s:${RESET}%s %b\n" "$left_full" "$sep_padding" "$l2" "$l2_padding" "$v2"
  }

  # --- 打印函数：单列 (逻辑与 print_row 左侧一致) ---
  print_full() {
    local l1=$1
    local v1=$2
    
    local clean_l1=$(echo -e "$l1" | sed -r 's/\x1B\[[0-9;]*[mK]//g')
    local l1_len=$(echo -n "$clean_l1" | wc -L)
    local l1_pad_len=$((LABEL_WIDTH - l1_len))
    [ $l1_pad_len -lt 0 ] && l1_pad_len=0
    local l1_padding=$(printf "%${l1_pad_len}s" "")
    
    printf "  ${YELLOW}%s:${RESET}%s %b\n" "$l1" "$l1_padding" "$v1"
  }

  # --- 1. 系统信息 ---
  echo -e "${BOLD}${CYAN}🖥️  系统信息${RESET}"
  print_row "操作系统" "$os_name" "系统版本" "$sys_ver"
  print_row "内核版本" "$kernel_ver" "系统架构" "$arch_info"
  print_row "虚拟化类型" "$virt_type" "登录用户" "$current_user"
  print_row "主机名" "$hostname_info" "运行时间" "$uptime_info"
  print_row "启动时间" "$boot_time" "系统负载" "$load_info"
  echo -e "${CYAN}-----------------------------------------------------------------------------${RESET}"

  # --- 2. 硬件资源 (已更新) ---
  echo -e "${BOLD}${CYAN}⚙️  硬件资源${RESET}"
  print_full "CPU型号" "$cpu_model"
  print_row "CPU核心" "${cpu_count} 核心" "CPU频率" "$cpu_mhz"
  # [修改] 此处将 CPU缓存 替换为 虚拟化支持
  print_row "CPU使用率" "$cpu_usage" "VM-x/AMD-V" "$virt_support"
  print_row "内存使用" "${mem_used} / ${mem_total} (${mem_percent})" "AES指令集" "$aes_status"
  print_row "SWAP使用" "$swap_display" "CPU窃取" "$st_display"
  echo -e "${CYAN}-----------------------------------------------------------------------------${RESET}"

  # --- 3. 网络信息 ---
  echo -e "${BOLD}${CYAN}🌐  网络信息${RESET}"
  print_full "运营商" "$isp_info"
  print_row "地理位置" "$location_info" "公网IPv4" "$display_ipv4_pub"
  print_row "默认网卡" "${default_interface:-未知}" "内网IPv4" "${ipv4_local:-未检测到}"
  print_row "MAC地址" "$mac_address" "公网IPv6" "$display_ipv6_pub"
  print_row "入站流量" "$rx_h" "内网IPv6" "${ipv6_local:-未检测到}"
  print_row "出站流量" "$tx_h" "DNS服务器" "$dns_servers"
  print_row "系统时间" "$current_time" "时区信息" "$timezone"
  echo -e "${CYAN}-----------------------------------------------------------------------------${RESET}"

  # --- 4. 磁盘信息 ---
  echo -e "${BOLD}${CYAN}💽  磁盘使用情况${RESET}"
  df -hP 2>/dev/null | grep -vE 'overlay|tmpfs|udev|loop' | awk '
  BEGIN {
      h1="文件系统"; h2="容量"; h3="已用"; h4="可用"; h5="使用%"; h6="挂载点"
  }
  NR==1 { next }
  {
      fs=$1; size=$2; used=$3; avail=$4; use=$5; mount=$6
      len=length(fs)
      if(len>max) max=len
      
      # 保存数据
      lines[NR] = fs "|" size "|" used "|" avail "|" use "|" mount
  }

  END {
      if(max<20) max=20
      
      # 打印表头 (手动计算空格填充，规避 awk 版本差异)
      # 格式: "  " + Col1 + " " + Col2 ...
      
      # Col 1: 文件系统 (视宽8), 目标 max
      printf "  文件系统"
      for(i=0;i<max-8;i++) printf " "
      
      # Col 2: 容量 (视宽4), 目标 10
      printf " 容量      "
      
      # Col 3: 已用 (视宽4), 目标 10
      printf " 已用      "
      
      # Col 4: 可用 (视宽4), 目标 10
      printf " 可用      "
      
      # Col 5: 使用% (视宽5), 目标 10
      printf "%s", " 使用%     "
      
      # Col 6: 挂载点
      printf " 挂载点\n"
      
      # 打印数据
      data_fmt="  %-" max "s %-10s %-10s %-10s %-10s %-15s\n"
      for(i=2; i<=NR; i++) {
          if(i in lines) {
              split(lines[i], f, "|")
              printf data_fmt, f[1], f[2], f[3], f[4], f[5], f[6]
          }
      }
  }'
  echo -e "${CYAN}-----------------------------------------------------------------------------${RESET}"

  # --- 5. 服务状态 (颜色与对齐修复版) ---
  echo -e "${BOLD}${CYAN}🔧  系统服务状态${RESET}"
  # 定义要检测的服务列表 (使用变量名或通用名)
  # 注意: 数组中存放的是 "显示标签|服务名变量/真实名"
  local services_config=(
    "SSH|$SVC_SSH"
    "Nginx|nginx"
    "HTTP|$SVC_HTTP"
    "Caddy|caddy"
    "MySQL|mysql"
    "MariaDB|mariadb"
    "PostgreSQL|postgresql"
    "Redis|redis"
    "Docker|docker"
    "X-UI|x-ui"
    "UFW|ufw"
    "Fail2Ban|fail2ban"
  )

  # 临时目录
  local svc_tmp_dir="${TEMP_DIR}/svc_check"
  mkdir -p "$svc_tmp_dir"
  rm -f "$svc_tmp_dir"/*

  local svc_pids=()

  # 并行检测
  for i in "${!services_config[@]}"; do
    (
      IFS='|' read -r label svc_name <<<"${services_config[$i]}"
      local service="$svc_name"
      local value=""
      local version=""
      local status=""
      local is_installed=false

      # --- 1. 服务名修正与存在性检测 ---
      # 尝试直接检测
      if systemctl cat "$service" >/dev/null 2>&1; then
        is_installed=true
      else
        # 常见别名回退
        case "$service" in
          ssh)
            # [修复] SSH 服务在不同发行版有多种名称
            if systemctl cat "sshd" >/dev/null 2>&1; then
               service="sshd"; is_installed=true
            elif systemctl cat "ssh.service" >/dev/null 2>&1; then
               service="ssh.service"; is_installed=true
            elif systemctl cat "openssh-server" >/dev/null 2>&1; then
               service="openssh-server"; is_installed=true
            fi
            ;;
          redis)
            if systemctl cat "redis-server" >/dev/null 2>&1; then
               service="redis-server"; is_installed=true
            fi
            ;;
          mysql)
            if systemctl cat "mysqld" >/dev/null 2>&1; then
               service="mysqld"; is_installed=true
            fi
            ;;
          mariadb)
            if systemctl cat "mariadb.service" >/dev/null 2>&1; then
               service="mariadb.service"; is_installed=true
            elif systemctl cat "mariadb-server" >/dev/null 2>&1; then
               service="mariadb-server"; is_installed=true
            fi
            ;;
          postgresql)
            # PostgreSQL 在某些发行版使用带版本号的服务名
            local pg_svc
            pg_svc=$(systemctl list-unit-files 2>/dev/null | grep -E "postgresql.*\.service" | awk '{print $1}' | head -1)
            if [ -n "$pg_svc" ]; then
               service="$pg_svc"; is_installed=true
            fi
            ;;
          x-ui)
            if systemctl cat "3x-ui" >/dev/null 2>&1; then
               service="3x-ui"; label="3X-UI"; is_installed=true
            fi
            ;;
          nginx)
            if [ -f /etc/init.d/nginx ]; then
               # 非 systemd 场景或源码编译场景检测
               is_installed=true
            fi
            ;;
        esac
      fi
      
      # [修复] 命令存在性兜底检测 (适用于非 systemd 管理但已安装的情况)
      if [ "$is_installed" = false ]; then
          case "$label" in
            UFW)      command -v ufw >/dev/null 2>&1 && is_installed=true ;;
            Docker)   command -v docker >/dev/null 2>&1 && is_installed=true ;;
            Fail2Ban)
              # 使用包管理器判断，避免卸载后命令残留导致误判
              if [[ "$PKG_MANAGER" == "apt" ]]; then
                dpkg -l fail2ban 2>/dev/null | grep -q "^ii" && is_installed=true
              elif [[ "$PKG_MANAGER" == "dnf" || "$PKG_MANAGER" == "yum" ]]; then
                rpm -q fail2ban >/dev/null 2>&1 && is_installed=true
              fi
              ;;
          esac
      fi

      if [ "$is_installed" = true ]; then
        status=$(systemctl is-active "$service" 2>/dev/null || echo "inactive")
        
        # UFW 特殊检测 (命令存在且 status active)
        if [ "$label" == "UFW" ]; then
          if command -v ufw >/dev/null 2>&1 && ufw status | grep -q "Status: active"; then status="active"; else status="inactive"; fi
        fi

        # --- 2. 版本获取 (部分命令耗时) ---
        # 仅当服务安装时尝试获取
        case $label in
          SSH)  version=$(ssh -V 2>&1 | awk '{print $1}' | sed 's/^OpenSSH_//');;
          Nginx) version=$(nginx -v 2>&1 | awk -F'/' '{print $2}' | awk '{print $1}');;
          HTTP) 
             # 区分 apache2ctl 或 httpd
             if command -v apache2ctl >/dev/null 2>&1; then
                version=$(apache2ctl -v 2>&1 | grep 'Server version' | awk -F'/' '{print $2}' | awk '{print $1}')
             elif command -v httpd >/dev/null 2>&1; then
                version=$(httpd -v 2>&1 | grep 'Server version' | awk -F'/' '{print $2}' | awk '{print $1}')
             fi
             ;;
          Caddy) version=$(caddy version 2>&1 | awk '{print $1}');;
          MySQL)
             # [修复] MySQL 版本获取 - 区分真正的 MySQL 和 MariaDB 的兼容命令
             if command -v mysqld >/dev/null 2>&1; then
                local ver_out=$(mysqld --version 2>&1)
                if echo "$ver_out" | grep -qi "mariadb"; then
                   version=""  # 实际是 MariaDB，跳过
                else
                   version=$(echo "$ver_out" | grep -oE '[0-9]+\.[0-9]+\.[0-9]+' | head -1)
                fi
             elif command -v mysql >/dev/null 2>&1; then
                local ver_out=$(mysql --version 2>&1)
                if echo "$ver_out" | grep -qi "mariadb"; then
                   version=""  # 实际是 MariaDB 的 mysql 兼容命令
                else
                   version=$(echo "$ver_out" | grep -oE '[0-9]+\.[0-9]+\.[0-9]+' | head -1)
                fi
             fi
             ;;
          MariaDB)
             # [修复] MariaDB 版本获取
             if command -v mariadbd >/dev/null 2>&1; then
                version=$(mariadbd --version 2>&1 | grep -oE '[0-9]+\.[0-9]+\.[0-9]+' | head -1)
             elif command -v mariadb >/dev/null 2>&1; then
                version=$(mariadb --version 2>&1 | grep -oE '[0-9]+\.[0-9]+\.[0-9]+' | head -1)
             elif command -v mysqld >/dev/null 2>&1; then
                local ver_out=$(mysqld --version 2>&1)
                if echo "$ver_out" | grep -qi "mariadb"; then
                   version=$(echo "$ver_out" | grep -oE '[0-9]+\.[0-9]+\.[0-9]+' | head -1)
                fi
             fi
             ;;
          PostgreSQL)
             # [修复] PostgreSQL 版本 - 优先用服务端命令
             if command -v postgres >/dev/null 2>&1; then
                version=$(postgres --version 2>&1 | grep -oE '[0-9]+\.[0-9]+' | head -1)
             elif command -v psql >/dev/null 2>&1; then
                version=$(psql --version 2>&1 | grep -oE '[0-9]+\.[0-9]+' | head -1)
             fi
             ;;
          Redis) 
              if command -v redis-server >/dev/null 2>&1; then
                 version=$(redis-server --version 2>&1 | grep -oE 'v=[0-9]+\.[0-9]+\.[0-9]+' | cut -d'=' -f2)
              fi
              ;;
          Docker) version=$(docker --version 2>&1 | awk '{print $3}' | sed 's/,//');;
          UFW) version=$(ufw --version 2>&1 | awk '{print $2}');;
          Fail2Ban) version=$(fail2ban-client --version 2>&1 | grep -oE '[0-9]+\.[0-9]+\.[0-9]+' | head -1);;
        esac
        
        version=$(echo "$version" | tr -d '\n')
        [ -n "$version" ] && version="(v$version)"

        # 端口信息 (仅SSH展示)
        local port_info=""
        if [ "$label" = "SSH" ] && [ "$status" = "active" ]; then
          local cp=""
          # 尝试从 sshd_config 读取 (兼容 RHEL/Debian 路径)
          if [ -f /etc/ssh/sshd_config ]; then
              cp=$(grep -E "^Port" /etc/ssh/sshd_config 2>/dev/null | awk '{print $2}' | head -1)
          fi
          port_info="(端口:${cp:-22})"
        fi

        if [ "$status" = "active" ]; then
          value="${GREEN}✅ 运行中${RESET} $version $port_info"
        else
          value="${YELLOW}⚠️  未运行${RESET} $version"
        fi
      else
        value="${GRAY}🔘 未安装${RESET}"
      fi
      
      # 写入结果文件: label|value
      echo "$label|$value" > "${svc_tmp_dir}/${i}.res"
    ) &
    svc_pids+=($!)
  done

  # 等待所有子进程
  for pid in "${svc_pids[@]}"; do
    wait "$pid" 2>/dev/null
  done

  # 收集结果
  declare -a svc_labels
  declare -a svc_values
  for i in "${!services_config[@]}"; do
    if [ -f "${svc_tmp_dir}/${i}.res" ]; then
       IFS='|' read -r l v < "${svc_tmp_dir}/${i}.res"
       svc_labels+=("$l")
       svc_values+=("$v")
    else
       IFS='|' read -r l _ <<<"${services_config[$i]}"
       svc_labels+=("$l")
       svc_values+=("${GRAY}检测超时${RESET}")
    fi
  done
  
  # 清理
  rm -rf "$svc_tmp_dir"

  # 循环调用 print_row 进行双列打印 (完全继承上方的对齐逻辑)
  len=${#svc_labels[@]}
  for ((i=0; i<len; i+=2)); do
    l1="${svc_labels[i]}"
    v1="${svc_values[i]}"
    l2="${svc_labels[i+1]}"
    v2="${svc_values[i+1]}"
    
    if [ -n "$l2" ]; then
        # 双列显示
        print_row "$l1" "$v1" "$l2" "$v2"
    else
        # 最后一个单列显示
        print_full "$l1" "$v1"
    fi
  done
  echo -e "${CYAN}-----------------------------------------------------------------------------${RESET}"

# --- 6. BBR状态 ---
  # 检测 TCP 拥塞控制
  if sysctl net.ipv4.tcp_congestion_control 2>/dev/null | grep -q bbr; then
      bbr_base="${GREEN}已启用${RESET}"
  else
      bbr_base="${RED}未启用${RESET}"
  fi

  # 检测 BBR 模块加载情况 (lsmod 在精简系统/容器中可能不存在)
  if command -v lsmod >/dev/null 2>&1 && lsmod 2>/dev/null | grep -q tcp_bbr; then
      bbr_extra="(模块已加载)"
  elif grep -wq "bbr" /proc/sys/net/ipv4/tcp_available_congestion_control 2>/dev/null; then
      bbr_extra="(内核内置)"
  else
      bbr_extra="(模块未加载)"
  fi
  
  # 组合 BBR 显示内容
  bbr_display="${bbr_base} ${bbr_extra}"

  # 检测 Qdisc 调度算法
  qdisc_raw=$(sysctl net.core.default_qdisc 2>/dev/null | awk -F'= ' '{print $2}')
  if [[ "$qdisc_raw" == "fq" || "$qdisc_raw" == "cake" ]]; then
      qdisc_display="${GREEN}${qdisc_raw}${RESET}"
  elif [ -n "$qdisc_raw" ]; then
      qdisc_display="${YELLOW}${qdisc_raw}${RESET}"
  else
      qdisc_display="${RED}未设置${RESET}"
  fi
  
  echo -e "${BOLD}${CYAN}🚀  网络加速状态${RESET}"
  print_row "BBR状态" "$bbr_display" "BBR调度算法" "$qdisc_display"
  
  echo -e "${BOLD}${CYAN}=============================================================================${RESET}\n"
}

# ---------- [最终版] 菜单显示 (单列布局) ----------
show_menu() {
  display_system_info
  echo -e "${BOLD}${GREEN}🧭  系统管理工具菜单${RESET}"
  echo -e "${CYAN}==================================================${RESET}"

  # --- 板块 1: 系统运维 ---
  echo -e "${BOLD}${CYAN}🛠️  系统运维${RESET}"
  echo -e "  ${YELLOW} 1.${RESET} 系统升级与缓存清理"
  echo -e "  ${YELLOW} 2.${RESET} 系统清理 (日志/旧文件/Docker)"
  echo -e "  ${YELLOW} 3.${RESET} 系统内核管理"
  echo -e "  ${YELLOW} 4.${RESET} Swap 交换分区管理"
  echo -e "  ${YELLOW} 5.${RESET} 修改主机名 (Hostname)"
  echo -e "  ${YELLOW} 6.${RESET} 系统时区设置"
  echo -e "  ${YELLOW} 7.${RESET} 系统国内源切换 (Apt/Docker)"

  # --- 板块 2: 安全防护 ---
  echo -e "${BOLD}${CYAN}🛡️  安全防护${RESET}"
  echo -e "  ${YELLOW} 8.${RESET} 防火墙管理 (UFW)"
  echo -e "  ${YELLOW} 9.${RESET} Fail2Ban 防爆破管理"
  echo -e "  ${YELLOW}10.${RESET} SSH端口检测与修改"

  # --- 板块 3: 网络优化 ---
  echo -e "${BOLD}${CYAN}🌐  网络优化${RESET}"
  echo -e "  ${YELLOW}11.${RESET} 静态IP网络配置 (PVE/自建)"
  echo -e "  ${YELLOW}12.${RESET} BBR 加速管理"
  echo -e "  ${YELLOW}13.${RESET} TCP 网络调优 (BDP智能计算)"
  echo -e "  ${YELLOW}14.${RESET} IPv6 开启与关闭"
  echo -e "  ${YELLOW}15.${RESET} DNS 设置与优化"

  # --- 板块 4: 工具应用 ---
  echo -e "${BOLD}${CYAN}🔧  工具应用${RESET}"
  echo -e "  ${YELLOW}16.${RESET} 常用软件中心 (Docker)"
  echo -e "  ${YELLOW}17.${RESET} 计划任务管理 (Crontab)"
  echo -e "  ${YELLOW}18.${RESET} 系统监控中心 (端口/进程/审计)"

  # --- 板块 5: 性能测试 ---
  echo -e "${BOLD}${CYAN}🚀  性能测试${RESET}"
  echo -e "  ${YELLOW}19.${RESET} 流媒体解锁测试"
  echo -e "  ${YELLOW}20.${RESET} 网络质量测试"
  echo -e "  ${YELLOW}21.${RESET} 融合怪全面测试"
  echo -e "  ${YELLOW}22.${RESET} 服务器性能测试 (YABS)"

  # --- 板块 6: 系统控制 ---
  echo -e "${BOLD}${CYAN}⚡  系统控制${RESET}"
  echo -e "  ${YELLOW}23.${RESET} 重启系统 (Reboot)"
  echo -e "  ${YELLOW}24.${RESET} 关机 (Shutdown)"
  echo -e "  ${YELLOW}25.${RESET} 缩小虚拟机空间 (VMware Disk Shrink)"

  echo -e "${CYAN}==================================================${RESET}"
  echo -e "  ${RED}0. 退出脚本${RESET}"
  echo -e "${CYAN}==================================================${RESET}"
}

# ---------- 通用依赖安装 (整合APT锁检测) ----------
# ---------- 通用依赖安装 (支持多发行版) ----------
install_deps() {
  for dep in "$@"; do
    if ! command -v "$dep" &>/dev/null; then
      echo -e "${BLUE}[→] 安装依赖: ${dep}${RESET}"
      check_pm_lock || return 1
      $PKG_INSTALL "$dep" >/dev/null 2>&1
    fi
  done
}

# ---------- 通用清理 ----------
cleanup() {
  [ -d "$1" ] && rm -rf "$1" && echo -e "${GREEN}[√] 清理临时目录: $1${RESET}"
}

# ---------- UFW 防火墙管理 (深度修复: 状态全显 + 禁Ping智能兜底 + 交互优化) ----------
manage_ufw() {
  # [辅助] 检测安装
  check_ufw_installed() {
    if ! command -v ufw >/dev/null 2>&1; then return 1; else return 0; fi
  }

  # [辅助] 获取真实 SSH 端口
  get_actual_ssh_port() {
    local port=""
    local pid=$(pidof sshd | awk '{print $1}')
    if [ -n "$pid" ]; then
      port=$(ss -tlnp | grep "pid=$pid," | awk '{print $4}' | awk -F: '{print $NF}' | head -n 1)
    fi
    if [ -z "$port" ] || ! [[ "$port" =~ ^[0-9]+$ ]]; then
      port=$(grep -E "^Port" /etc/ssh/sshd_config 2>/dev/null | awk '{print $2}' | head -1)
    fi
    echo "${port:-22}"
  }

  # [辅助] 检查 Limit
  check_port_limit() {
    local port=$1
    if ufw status | grep -E "^$port(/tcp)? +LIMIT" >/dev/null 2>&1; then return 0; else return 1; fi
  }

  # [辅助] Ping 状态检测 (基于 DROP 关键字)
  check_ping_status() {
    # 只要检测到 explicit DROP 规则，就视为已禁用 (返回 1/False)
    # 没有 DROP 规则，视为允许 (返回 0/True)
    if grep -q "icmp-type.*echo-request.*DROP" /etc/ufw/before.rules 2>/dev/null; then
      return 1
    else
      return 0
    fi
  }

  # [辅助] 智能修改 Ping 规则 (核心修复逻辑)
  modify_ping_rule() {
    local action=$1
    local file=$2
    local proto=$3
    local type_flag="icmp-type"
    [ "$proto" == "icmpv6" ] && type_flag="icmpv6-type"

    local target="ACCEPT"
    [ "$action" == "drop" ] && target="DROP"

    if grep -q "$type_flag.*echo-request" "$file"; then
      sed -i -E "s/($type_flag.*echo-request.*-j) [A-Z]+/\1 $target/g" "$file"
      return 0
    else
      if [ "$action" == "drop" ]; then
        local chain="ufw-before-input"
        [ "$proto" == "icmpv6" ] && chain="ufw6-before-input"
        local new_rule="-A $chain -p $proto --$type_flag echo-request -j DROP"
        if ! grep -q "$new_rule" "$file"; then
          # [修复] 添加插入失败检测
          if grep -q "^# ok icmp codes" "$file"; then
            sed -i "/^# ok icmp codes/i $new_rule" "$file"
          elif grep -q "^COMMIT" "$file"; then
            sed -i "/^COMMIT/i $new_rule" "$file"
          else
            echo -e "${YELLOW}[!] 警告: 无法在 $file 中找到插入点，请手动添加规则${RESET}" >&2
            return 1
          fi
        fi
      else
        return 0
      fi
    fi
  }

  # --- 入口安装检测 ---
  if ! check_ufw_installed; then
    echo -e "${YELLOW}[!] 未检测到 UFW 防火墙。${RESET}"
    read -p "是否立即安装 UFW? [y/N]: " install_choice
    if [[ "$install_choice" =~ ^[Yy]$ ]]; then
      check_pm_lock || return 1
      # 对于 RHEL 系，EPEL 通常在这个阶段可能还未安装 (如果 ufw 在 EPEL 中)
      # 不过之前的 check_dependencies 可能已经处理了基础环境。
      # 这里使用通用变量
      $PKG_UPDATE
      $PKG_INSTALL ufw
      hash -r 2>/dev/null
    else
      return 0
    fi
  fi

  while true; do
    if ! check_ufw_installed; then
      echo -e "${RED}UFW 丢失${RESET}"
      sleep 2
      return 0
    fi

    # --- 状态检测逻辑 ---
    if ufw status 2>/dev/null | grep -q "Status: active"; then
      is_active=true
      ufw_status="${GREEN}运行中 (Active)${RESET}"
      # 获取默认策略
      default_incoming=$(ufw status verbose | grep "Default:" | awk '{print $2}')
      if [ "$default_incoming" == "deny" ]; then
        policy_display="${GREEN}拒绝入站 (Safe)${RESET}"
      else
        policy_display="${RED}允许入站 (Risk)${RESET}"
      fi
    else
      is_active=false
      ufw_status="${RED}已关闭 (Inactive)${RESET}"
      policy_display="${GRAY}未生效${RESET}"
    fi

    ssh_port=$(get_actual_ssh_port)
    if [ "$is_active" = true ]; then
      if check_port_limit "$ssh_port"; then
        limit_display="${GREEN}●${RESET} 关闭 SSH 智能防爆破 (当前: Limit模式)"
        limit_is_on=true
      else
        limit_display="${GRAY}○${RESET} 开启 SSH 智能防爆破 (当前: Allow模式)"
        limit_is_on=false
      fi
    else
      limit_display="${GRAY}○${RESET} 开启 SSH 智能防爆破 (需先开启防火墙)"
      limit_is_on=false
    fi

    # Ping 状态显示逻辑
    if check_ping_status; then
      ping_display="${GREEN}已允许${RESET}"
    else
      ping_display="${RED}已禁止${RESET}"
    fi

    if [ -f /usr/local/bin/ufw-docker ]; then
      docker_tool_display="${GREEN}已安装${RESET}"
    else
      docker_tool_display="${GRAY}未安装${RESET}"
    fi

    # --- 菜单显示 ---
    clear
    echo -e "${BOLD}${CYAN}🛡️  UFW 防火墙高级管理${RESET}"
    echo -e "${CYAN}==================================================${RESET}"
    echo -e "当前状态: $ufw_status  |  默认策略: $policy_display"
    echo -e "SSH 端口: ${YELLOW}$ssh_port${RESET}"
    echo -e "${CYAN}--------------------------------------------------${RESET}"

    if [ "$is_active" = true ]; then
      echo -e "${YELLOW}  1.${RESET} 重载配置 (Reload) ${GREEN}[自动保活SSH]${RESET}"
      echo -e "${YELLOW}  2.${RESET} 关闭防火墙 (Disable)"
      echo -e "${YELLOW}  3.${RESET} 查看规则列表 (含编号)"
    else
      echo -e "${YELLOW}  1.${RESET} 开启防火墙 (Enable)"
      echo -e "${GRAY}  2. 关闭防火墙 (当前已关闭)${RESET}"
      echo -e "${GRAY}  3. 查看规则列表 (需开启)${RESET}"
    fi

    echo -e "${CYAN}--- 规则管理 ---${RESET}"
    echo -e "${YELLOW}  4.${RESET} 放行端口 (Allow Port)"
    echo -e "${YELLOW}  5.${RESET} 放行应用 (Allow App)"
    if [ "$is_active" = true ]; then
      echo -e "${YELLOW}  6.${RESET} ${RED}删除规则 (Delete Rule)${RESET} ${GREEN}[安全交互]${RESET}"
    else
      echo -e "${GRAY}  6. 删除规则 (需开启)${RESET}"
    fi

    echo -e "${CYAN}--- 安全策略 ---${RESET}"
    echo -e "${YELLOW}  7.${RESET} 封禁 IP (Deny IP)"
    echo -e "${YELLOW}  8.${RESET} 信任 IP (Allow IP)"
    if [ "$is_active" = true ]; then
      echo -e "${YELLOW}  9.${RESET} $limit_display"
    else
      echo -e "${GRAY}  9. $limit_display${RESET}"
    fi

    echo -e "${CYAN}--- 高级功能 ---${RESET}"
    echo -e "${YELLOW} 12.${RESET} Docker 防火墙修复 (UFW-Docker) [${docker_tool_display}]"
    echo -e "${YELLOW} 13.${RESET} ICMP(Ping) 控制 (当前: ${ping_display})"
    echo -e "${YELLOW} 14.${RESET} 调整日志级别 (Log Level)"
    echo -e "${YELLOW} 15.${RESET} 备份与恢复配置 (Backup/Restore)"

    echo -e "${CYAN}--- 系统 ---${RESET}"
    echo -e "${YELLOW} 10.${RESET} ${RED}重置防火墙 (Reset) [慎用]${RESET}"
    echo -e "${YELLOW} 11.${RESET} ${RED}卸载 UFW 防火墙${RESET}"
    echo -e "${YELLOW}  0.${RESET} 返回主菜单"
    echo -e "${CYAN}==================================================${RESET}"

    read -p "请输入选项: " u_choice

    case $u_choice in
    1)
      local r_port=$(get_actual_ssh_port)
      ufw allow "$r_port/tcp" comment "SSH-Anti-Lockout" >/dev/null 2>&1
      if [ "$is_active" = true ]; then
        ufw reload
        echo -e "${GREEN}[√] 重载完成${RESET}"
      else
        ufw --force enable
        echo -e "${GREEN}[√] 防火墙已开启${RESET}"
      fi
      read -p "按 Enter 继续..."
      ;;
    2)
      if [ "$is_active" = false ]; then echo -e "${YELLOW}已关闭${RESET}"; else
        ufw disable
        echo -e "${YELLOW}[!] 已关闭${RESET}"
      fi
      read -p "按 Enter 继续..."
      ;;
    3)
      if [ "$is_active" = false ]; then echo -e "${RED}需开启${RESET}"; else ufw status numbered; fi
      read -p "按 Enter 继续..."
      ;;
    4)
      # [UX优化] 端口智能输入
      read -p "端口/范围 (例如 80 或 80/tcp) [0 返回]: " port
      [ "$port" == "0" ] || [ -z "$port" ] && continue

      # 检测用户是否已经输入了协议 (如 80/tcp)
      if [[ "$port" == *"/"* ]]; then
        arg="" # 如果带斜杠，直接作为参数
        echo -e "${GRAY}检测到已包含协议，跳过协议选择...${RESET}"
      else
        # [修复] 添加默认值提示
        read -p "协议 (1:TCP [默认] 2:UDP 3:All): " pidx
        arg="/tcp"
        [ "$pidx" == "2" ] && arg="/udp"
        [ "$pidx" == "3" ] && arg=""
        # 空输入时明确提示使用默认值
        [ -z "$pidx" ] && echo -e "${GRAY}使用默认: TCP${RESET}"
        port="${port}${arg}"
      fi

      read -p "备注: " cmt
      [ -z "$cmt" ] && cmt="Manual"
      ufw allow "$port" comment "$cmt"
      echo -e "${GREEN}[√] 添加成功: $port${RESET}"
      read -p "按 Enter 继续..."
      ;;
    5)
      ufw app list
      read -p "应用名 [0 返回]: " app
      [ "$app" != "0" ] && [ -n "$app" ] && ufw allow "$app"
      read -p "按 Enter 继续..."
      ;;
    6)
      [ "$is_active" = false ] && {
        echo -e "${RED}需开启${RESET}"
        read -p "..."
        continue
      }
      # [UX优化] 先展示列表
      echo -e "${CYAN}>>> 当前规则列表:${RESET}"
      ufw status numbered
      echo -e "${CYAN}--------------------------${RESET}"

      read -p "请输入要删除的规则编号 [0 返回]: " n
      if [[ "$n" =~ ^[0-9]+$ ]] && [ "$n" -ne 0 ]; then
        # [UX优化] 获取规则内容用于回显，防止误删
        # [修复] 使用更精确的正则匹配，避免 1 匹配到 11、21 等
        rule_content=$(ufw status numbered | grep -E "^\[\s*$n\]")

        if [ -n "$rule_content" ]; then
          echo -e "\n${YELLOW}即将删除以下规则:${RESET}"
          echo -e "${CYAN}${rule_content}${RESET}"
          read -p "请再次确认删除? [y/N]: " confirm_del
          if [[ "$confirm_del" =~ ^[Yy]$ ]]; then
            echo "y" | ufw delete "$n" >/dev/null 2>&1
            echo -e "${GREEN}[√] 规则已删除${RESET}"
            echo -e "${GRAY}提示: 后续规则编号已自动前移${RESET}"
          else
            echo -e "${YELLOW}已取消删除${RESET}"
          fi
        else
          echo -e "${RED}[!] 找不到编号为 $n 的规则${RESET}"
        fi
      fi
      read -p "按 Enter 继续..."
      ;;
    7)
      read -p "封禁 IP [0 返回]: " ip
      [ "$ip" != "0" ] && [ -n "$ip" ] && ufw deny from "$ip" && echo -e "${GREEN}[√] 已封禁${RESET}"
      read -p "按 Enter 继续..."
      ;;
    8)
      read -p "信任 IP [0 返回]: " ip
      [ "$ip" != "0" ] && [ -n "$ip" ] && ufw allow from "$ip" && echo -e "${GREEN}[√] 已信任${RESET}"
      read -p "按 Enter 继续..."
      ;;
    9)
      [ "$is_active" = false ] && {
        echo -e "${RED}需开启${RESET}"
        read -p "..."
        continue
      }
      if [ "$limit_is_on" = true ]; then
        read -p "确认关闭 Limit (回退为 Allow)? [y/N]: " c
        if [[ "$c" =~ ^[Yy]$ ]]; then
          ufw delete limit "$ssh_port/tcp" >/dev/null 2>&1
          ufw allow "$ssh_port/tcp" comment "SSH-Allow" >/dev/null 2>&1
          echo -e "${GREEN}[√] 已恢复普通放行${RESET}"
        fi
      else
        read -p "确认开启 Limit (30s/6次)? [y/N]: " c
        if [[ "$c" =~ ^[Yy]$ ]]; then
          ufw delete allow "$ssh_port/tcp" >/dev/null 2>&1
          ufw limit "$ssh_port/tcp" comment "SSH-Limit"
          echo -e "${GREEN}[√] Limit 已开启${RESET}"
        fi
      fi
      read -p "按 Enter 继续..."
      ;;
    10)
      # [UX优化] 增加对 Docker/自定义规则丢失的明确警告
      echo -e "${RED}>>> 危险警告：重置将删除所有规则！${RESET}"
      echo -e "${YELLOW}注意: 这将清除所有 UFW-Docker 规则和自定义端口，仅自动尝试放行 SSH。${RESET}"
      read -p "确认执行重置? [y/N]: " c
      if [[ "$c" =~ ^[Yy]$ ]]; then
        ufw --force reset
        ufw default deny incoming
        ufw default allow outgoing
        local rp=$(get_actual_ssh_port)
        ufw allow "$rp/tcp" comment "SSH-Anti-Lockout"
        ufw --force enable
        echo -e "${GREEN}[√] 重置完成${RESET}"
      fi
      read -p "按 Enter 继续..."
      ;;
    11)
      read -p "确认卸载 UFW? [y/N]: " c
      if [[ "$c" =~ ^[Yy]$ ]]; then
        ufw disable
        $PKG_REMOVE ufw
        rm -rf /etc/ufw
        hash -r
        # 清理 docker 工具
        [ -f /usr/local/bin/ufw-docker ] && rm -f /usr/local/bin/ufw-docker
        echo -e "${GREEN}[√] 已卸载${RESET}"
        SKIP_PAUSE=true
        return 0
      fi
      ;;
    12)
      echo -e "${CYAN}>>> Docker 防火墙修复 (UFW-Docker)${RESET}"
      if [ ! -f /usr/local/bin/ufw-docker ]; then
        echo -e "${YELLOW}正在下载工具...${RESET}"
        wget -O /usr/local/bin/ufw-docker https://github.com/chaifeng/ufw-docker/raw/master/ufw-docker
        chmod +x /usr/local/bin/ufw-docker
      fi
      echo -e "\n  1. 自动修复 (Install & Reload)"
      echo -e "  2. 检查状态"
      read -p "选项: " d_opt
      case $d_opt in
      1)
        ufw-docker install
        ufw reload
        echo -e "${GREEN}[√] 修复完成${RESET}"
        ;;
      2) ufw-docker check ;;
      esac
      read -p "按 Enter 继续..."
      ;;
    13)
      if check_ping_status; then
        # 当前状态: 允许 -> 设为禁止
        echo -e "${CYAN}当前状态: ${GREEN}允许 Ping${RESET}"
        read -p "是否【禁止】 Ping (隐藏服务器)? [y/N]: " c
        if [[ "$c" =~ ^[Yy]$ ]]; then
          # [修复] 同时备份 IPv4 和 IPv6 规则文件
          cp /etc/ufw/before.rules /etc/ufw/before.rules.bak 2>/dev/null
          cp /etc/ufw/before6.rules /etc/ufw/before6.rules.bak 2>/dev/null
          if [ -f /etc/ufw/before.rules ]; then modify_ping_rule "drop" "/etc/ufw/before.rules" "icmp"; fi
          if [ -f /etc/ufw/before6.rules ]; then modify_ping_rule "drop" "/etc/ufw/before6.rules" "icmpv6"; fi
          ufw reload >/dev/null
          echo -e "${YELLOW}[!] 已禁止 Ping (双栈生效)${RESET}"
        fi
      else
        # 当前状态: 禁止 -> 设为允许
        echo -e "${CYAN}当前状态: ${YELLOW}已禁止 Ping${RESET}"
        read -p "是否【允许】 Ping (恢复默认)? [y/N]: " c
        if [[ "$c" =~ ^[Yy]$ ]]; then
          if [ -f /etc/ufw/before.rules ]; then modify_ping_rule "accept" "/etc/ufw/before.rules" "icmp"; fi
          if [ -f /etc/ufw/before6.rules ]; then modify_ping_rule "accept" "/etc/ufw/before6.rules" "icmpv6"; fi
          ufw reload >/dev/null
          echo -e "${GREEN}[√] 已允许 Ping (恢复默认)${RESET}"
        fi
      fi
      read -p "按 Enter 继续..."
      ;;
    14)
      echo -e "当前: $(grep "LOGLEVEL" /etc/ufw/ufw.conf | cut -d= -f2)"
      echo -e "可选: off, low, medium, high"
      read -p "输入级别 [0 返回]: " lvl
      if [ "$lvl" != "0" ] && [ -n "$lvl" ]; then
        ufw logging "$lvl"
        echo -e "${GREEN}[√] 已设置${RESET}"
      fi
      read -p "按 Enter 继续..."
      ;;
    15)
      echo -e "  1. 备份配置\n  2. 恢复配置"
      read -p "选项: " bk_opt
      case $bk_opt in
      1)
        bk_file="/root/ufw_backup_$(date +%Y%m%d_%H%M%S).tar.gz"
        tar -czf "$bk_file" /etc/ufw /lib/ufw/user* 2>/dev/null
        echo -e "${GREEN}[√] 备份至: $bk_file${RESET}"
        ;;
      2)
        read -p "备份路径: " r_file
        if [ -f "$r_file" ]; then
          # [修复] 恢复前先验证备份文件内容安全性
          echo -e "${CYAN}正在验证备份文件...${RESET}"
          local unsafe_paths=$(tar -tzf "$r_file" 2>/dev/null | grep -E '^\.\./|^/')
          if [ -n "$unsafe_paths" ]; then
            echo -e "${RED}[!] 警告: 备份文件包含不安全路径，已拒绝恢复${RESET}"
            echo -e "${GRAY}检测到: $unsafe_paths${RESET}"
          else
            # 验证是否包含预期的 UFW 配置路径
            if tar -tzf "$r_file" 2>/dev/null | grep -q "etc/ufw"; then
              tar -xzf "$r_file" -C /
              ufw reload
              echo -e "${GREEN}[√] 恢复成功${RESET}"
            else
              echo -e "${RED}[!] 备份文件不包含 UFW 配置，请检查文件${RESET}"
            fi
          fi
        else
          echo -e "${RED}文件不存在${RESET}"
        fi
        ;;
      esac
      read -p "按 Enter 继续..."
      ;;
    0)
      SKIP_PAUSE=true
      break
      ;;
    *)
      echo -e "${RED}无效选项${RESET}"
      sleep 1
      ;;
    esac
  done
}

# --- [6. 系统] 软件包更新与清理 ---
system_upgrade() {
  echo -e "${CYAN}>>> 准备进行系统升级与缓存清理${RESET}"
  echo -e "${YELLOW}注意: 这将更新所有软件包，可能需要一些时间。${RESET}"
  read -p "确认继续吗? [y/N]: " confirm
  if [[ ! "$confirm" =~ ^[Yy]$ ]]; then
    echo -e "${YELLOW}操作已取消${RESET}"
    SKIP_PAUSE=true
    return 0
  fi
  
  echo -e "${CYAN}>>> 系统升级与清理开始...${RESET}"
  check_pm_lock || return 1

  if [[ "$PKG_MANAGER" == "apt" ]]; then
    export DEBIAN_FRONTEND=noninteractive
    # [修复] 添加升级失败的错误处理
    if ! apt-get update -y; then
      echo -e "${RED}[!] 软件源更新失败${RESET}"
      return 1
    fi
    apt-get dist-upgrade -y && apt-get autoremove -y && apt-get autoclean -y
  elif [[ "$PKG_MANAGER" == "dnf" ]]; then
    dnf update -y && dnf autoremove -y && dnf clean all
  elif [[ "$PKG_MANAGER" == "yum" ]]; then
    yum update -y && yum autoremove -y && yum clean all
  fi

  # [修复] 升级后清理硬件信息缓存，确保系统版本号即时更新
  rm -f "${TEMP_DIR}/hardware_cache"

  echo -e "${GREEN}[√] 系统升级与清理完成${RESET}"
}

# --- [6. 系统] BBR内核加速管理 ---
# 前置依赖: 必须先完成 check_dependencies
manage_bbr() {
  # 注: is_container_env() 已在脚本顶部定义为全局函数

  # [辅助函数] 检测 BBR 模块是否可用
  is_bbr_available() {
    # 检查内核是否内置或可加载 BBR 模块
    if grep -wq "bbr" /proc/sys/net/ipv4/tcp_available_congestion_control 2>/dev/null; then
      return 0
    fi
    # 尝试加载模块 (仅在非容器环境有效)
    modprobe tcp_bbr 2>/dev/null
    if grep -wq "bbr" /proc/sys/net/ipv4/tcp_available_congestion_control 2>/dev/null; then
      return 0
    fi
    return 1
  }

  # [辅助函数] 检测 default_qdisc 参数是否可用 (容器环境通常不可用)
  is_qdisc_configurable() {
    [ -f /proc/sys/net/core/default_qdisc ]
  }

  while true; do
    clear
    echo -e "${CYAN}>>> BBR 内核加速管理${RESET}"
    
    # --- 环境检测与警告 ---
    local is_container=false
    local container_warning=""
    if is_container_env; then
      is_container=true
      container_warning="${RED}[!] 检测到容器环境 (OpenVZ/LXC/Docker)，可能无法修改内核参数${RESET}"
    fi
    
    # 检测 BBR 模块状态
    local bbr_available=false
    local bbr_status="不可用"
    if is_bbr_available; then
      bbr_available=true
      # 进一步检测是否已加载
      if command -v lsmod >/dev/null 2>&1 && lsmod 2>/dev/null | grep -wq "tcp_bbr"; then
        bbr_status="${GREEN}已加载${RESET}"
      elif grep -wq "bbr" /proc/sys/net/ipv4/tcp_available_congestion_control 2>/dev/null; then
        bbr_status="${YELLOW}内核内置${RESET}"
      fi
    else
      bbr_status="${RED}不可用 (内核未编译/无法加载模块)${RESET}"
    fi
    
    # 检测 qdisc 状态
    local qdisc_available=false
    local qdisc_status="${RED}不可配置${RESET}"
    if is_qdisc_configurable; then
      qdisc_available=true
      qdisc_status="${GREEN}可配置${RESET}"
    fi
    
    # 检测当前状态
    local current_algo=$(sysctl net.ipv4.tcp_congestion_control 2>/dev/null | awk '{print $3}')
    local current_qdisc=$(sysctl net.core.default_qdisc 2>/dev/null | awk '{print $3}')
    
    echo -e "当前拥塞控制算法: ${GREEN}${current_algo:-未知}${RESET}"
    echo -e "当前队列管理算法: ${GREEN}${current_qdisc:-未知}${RESET}"
    echo -e "BBR 模块状态:     $bbr_status"
    echo -e "队列调度器:       $qdisc_status"
    [ -n "$container_warning" ] && echo -e "$container_warning"
    echo -e "${CYAN}--------------------------------------------------${RESET}"
    
    echo -e "  1. 开启 BBR + FQ"
    echo -e "  2. 开启 BBR + CAKE (如果不支会自动回退)"
    echo -e "  3. 关闭 BBR (恢复默认)"
    echo -e "  0. 返回上一级"
    
    read -p "请输入选项: " choice
    case $choice in
      1|2)
        # --- 前置检查: 容器环境警告 ---
        if [ "$is_container" = true ]; then
          echo -e "\n${RED}━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━${RESET}"
          echo -e "${RED}[!] 警告: 检测到容器化虚拟环境 (如 NAT VPS)${RESET}"
          echo -e "${YELLOW}容器共享宿主机内核，通常无法:${RESET}"
          echo -e "${GRAY}  • 加载内核模块 (tcp_bbr)${RESET}"
          echo -e "${GRAY}  • 修改 net.core.default_qdisc 参数${RESET}"
          echo -e "${YELLOW}BBR 需要宿主机内核已启用支持才能生效。${RESET}"
          echo -e "${RED}━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━${RESET}"
          read -p "仍要继续尝试? [y/N]: " force_continue
          if [[ ! "$force_continue" =~ ^[Yy]$ ]]; then
            continue
          fi
        fi
        
        # --- 前置检查: BBR 模块可用性 ---
        if [ "$bbr_available" = false ]; then
          echo -e "${RED}[!] BBR 模块不可用，请检查:${RESET}"
          echo -e "${GRAY}  • 内核版本是否 >= 4.9${RESET}"
          echo -e "${GRAY}  • 内核是否编译了 tcp_bbr 模块${RESET}"
          echo -e "${GRAY}  • 是否有权限加载内核模块 (非容器环境)${RESET}"
          read -p "按 Enter 继续..."
          continue
        fi
        
        # 检查内核版本
        local kernel_ver=$(uname -r | cut -d- -f1)
        # 简单比对主版本 >= 4.9
        if [[ "$(echo "$kernel_ver" | cut -d. -f1)" -lt 4 ]] || \
           ([[ "$(echo "$kernel_ver" | cut -d. -f1)" -eq 4 ]] && [[ "$(echo "$kernel_ver" | cut -d. -f2)" -lt 9 ]]); then
           echo -e "${RED}[!] 内核版本过低 ($kernel_ver)，BBR 需要 Linux Kernel 4.9+${RESET}"
           read -p "按 Enter 继续..."
           continue
        fi

        echo -e "${CYAN}>>> 正在配置系统参数...${RESET}"
        
        # [兼容性修复] 使用 /etc/sysctl.d/ 目录存储配置
        # Debian 13+ 的 systemd-sysctl 默认不读取 /etc/sysctl.conf
        local BBR_CONF="/etc/sysctl.d/99-bbr.conf"
        
        # 清理旧配置 (兼容性: 同时清理 sysctl.conf 中的遗留配置)
        if [ -f /etc/sysctl.conf ]; then
          sed -i '/net.core.default_qdisc/d' /etc/sysctl.conf
          sed -i '/net.ipv4.tcp_congestion_control/d' /etc/sysctl.conf
        fi
        
        local qdisc="fq"
        if [ "$choice" == "2" ]; then qdisc="cake"; fi
        
        # 写入新配置文件
        echo "# BBR Congestion Control - Auto generated by script" > "$BBR_CONF"
        if [ "$qdisc_available" = true ]; then
          echo "net.core.default_qdisc = $qdisc" >> "$BBR_CONF"
        fi
        echo "net.ipv4.tcp_congestion_control = bbr" >> "$BBR_CONF"
        
        # 使用 sysctl --system 加载所有配置
        sysctl --system >/dev/null 2>&1
        
        # 验证
        local verify_algo=$(sysctl net.ipv4.tcp_congestion_control 2>/dev/null | awk '{print $3}')
        local verify_qdisc=$(sysctl net.core.default_qdisc 2>/dev/null | awk '{print $3}')
        local bbr_loaded=false
        
        # 检查 BBR 是否真正生效 (模块加载或内核内置)
        if (command -v lsmod >/dev/null 2>&1 && lsmod 2>/dev/null | grep -wq "tcp_bbr") || \
           (grep -wq "bbr" /proc/sys/net/ipv4/tcp_available_congestion_control 2>/dev/null && [ "$verify_algo" = "bbr" ]); then
          bbr_loaded=true
        fi
        
        # --- 综合判断结果 ---
        if [[ "$verify_algo" == "bbr" ]] && [ "$bbr_loaded" = true ]; then
           # 检查 CAKE 是否生效，否则回退到 FQ
           if [ "$choice" == "2" ] && [ "$verify_qdisc" != "cake" ]; then
              echo -e "${YELLOW}[!] CAKE 队列不支持，已自动回退到 FQ${RESET}"
              sed -i 's/net.core.default_qdisc = cake/net.core.default_qdisc = fq/' "$BBR_CONF"
              sysctl -w net.core.default_qdisc=fq >/dev/null 2>&1
              qdisc="fq"
           fi
           
           # 检查 qdisc 是否生效
           if [ "$qdisc_available" = false ]; then
              echo -e "${YELLOW}[!] 队列调度器 (default_qdisc) 无法配置 (容器环境限制)${RESET}"
              echo -e "${GREEN}[√] BBR 拥塞控制已启用${RESET}"
           else
              echo -e "${GREEN}[√] BBR 已成功开启 ($qdisc)${RESET}"
           fi
        else
           echo -e "${RED}[!] 开启失败${RESET}"
           if [ "$is_container" = true ]; then
              echo -e "${YELLOW}原因: 容器环境无法加载 BBR 模块，需要宿主机内核支持。${RESET}"
              echo -e "${GRAY}提示: 联系您的 VPS 服务商确认宿主机是否已启用 BBR。${RESET}"
           else
              echo -e "${YELLOW}请检查内核日志: dmesg | grep -i bbr${RESET}"
           fi
           # 回滚配置
           rm -f "$BBR_CONF"
        fi
        read -p "按 Enter 继续..."
        ;;
      3)
        echo -e "${CYAN}>>> 正在移除 BBR 配置...${RESET}"
        local BBR_CONF="/etc/sysctl.d/99-bbr.conf"
        
        # 1. 删除配置文件
        rm -f "$BBR_CONF"
        
        # 2. 清理旧位置的遗留配置 (兼容性)
        if [ -f /etc/sysctl.conf ]; then
          sed -i '/net.core.default_qdisc/d' /etc/sysctl.conf
          sed -i '/net.ipv4.tcp_congestion_control/d' /etc/sysctl.conf
        fi
        
        # 3. 强制应用默认值 (因为 sysctl --system 无法重置已生效的参数)
        # 通用默认值: cubic + fq_codel
        echo -e "${YELLOW}正在重置运行状态为默认 (cubic + fq_codel)...${RESET}"
        sysctl -w net.ipv4.tcp_congestion_control=cubic 2>/dev/null
        if is_qdisc_configurable; then
          sysctl -w net.core.default_qdisc=fq_codel 2>/dev/null
        fi
        
        echo -e "${GREEN}[√] BBR 配置已移除并重置运行状态${RESET}"
        read -p "按 Enter 继续..."
        ;;
      0) return 0 ;;
      *) ;;
    esac
  done
}

# --- [6. 系统] TCP 网络调优 ---
# 基于 BDP (带宽延迟积) 理论自动计算最优 TCP 参数
manage_tcp_tuning() {
  # TCP 调优参数配置
  # 智能检测配置文件路径，确保跨发行版兼容性:
  #   - 现代 systemd 系统 (Debian 8+, RHEL 7+, Ubuntu 16+): 使用 /etc/sysctl.d/
  #   - 老旧系统或特殊环境: 回退到 /etc/sysctl.conf
  local TCP_BACKUP_TAG="# TCP_TUNING_MANAGED"
  local SYSCTL_D_CONF="/etc/sysctl.d/99-tcp-tuning.conf"
  local SYSCTL_CONF="/etc/sysctl.conf"
  
  # [智能检测] 选择配置文件路径
  local USE_SYSCTL_D=false
  local TARGET_CONF=""
  if [ -d "/etc/sysctl.d" ]; then
    # 现代 systemd 系统: 使用 sysctl.d 目录
    USE_SYSCTL_D=true
    TARGET_CONF="$SYSCTL_D_CONF"
  else
    # 老旧系统: 回退到 sysctl.conf
    TARGET_CONF="$SYSCTL_CONF"
  fi
  
  # [辅助函数] 获取当前 TCP 参数值
  get_tcp_param() {
    sysctl -n "$1" 2>/dev/null || echo "N/A"
  }
  
  # [辅助函数] 计算 BDP 并生成参数
  # 参数: $1=带宽(Mbps), $2=RTT(ms)
  calculate_bdp_params() {
    local bandwidth_mbps=$1
    local rtt_ms=$2
    
    # BDP = 带宽(Bytes/s) × RTT(s)
    # 带宽: Mbps → Bytes/s = Mbps × 1000000 / 8
    # RTT: ms → s = ms / 1000
    local bandwidth_bytes_per_sec=$(( bandwidth_mbps * 1000000 / 8 ))
    local bdp_bytes=$(( bandwidth_bytes_per_sec * rtt_ms / 1000 ))
    
    # 缓冲区最大值 = BDP × 3 (确保管道满载)
    local buffer_max=$(( bdp_bytes * 3 ))
    
    # 限制范围: 最小 4MB, 最大 128MB
    [ $buffer_max -lt 4194304 ] && buffer_max=4194304
    [ $buffer_max -gt 134217728 ] && buffer_max=134217728
    
    # 默认缓冲区 = min(BDP, 1MB), 避免缓冲膨胀
    local buffer_default=$(( bdp_bytes ))
    [ $buffer_default -lt 131072 ] && buffer_default=131072
    [ $buffer_default -gt 1048576 ] && buffer_default=1048576
    
    # 返回: buffer_max buffer_default (空格分隔)
    echo "$buffer_max $buffer_default"
  }
  
  # [辅助函数] 获取内核版本号 (用于参数兼容性检测)
  # 返回格式: MAJOR.MINOR (如 5.15)
  get_kernel_version() {
    local kver=$(uname -r | cut -d- -f1)
    local major=$(echo "$kver" | cut -d. -f1)
    local minor=$(echo "$kver" | cut -d. -f2)
    echo "${major}.${minor}"
  }
  
  # [辅助函数] 比较内核版本
  # 参数: $1=当前版本, $2=要求的最低版本
  # 返回: 0=满足要求, 1=不满足
  kernel_version_ge() {
    local current=$1
    local required=$2
    local cur_major=$(echo "$current" | cut -d. -f1)
    local cur_minor=$(echo "$current" | cut -d. -f2)
    local req_major=$(echo "$required" | cut -d. -f1)
    local req_minor=$(echo "$required" | cut -d. -f2)
    
    if [ "$cur_major" -gt "$req_major" ]; then
      return 0
    elif [ "$cur_major" -eq "$req_major" ] && [ "$cur_minor" -ge "$req_minor" ]; then
      return 0
    fi
    return 1
  }
  
  # [辅助函数] 自动检测系统参数并计算推荐值
  # 返回: buffer_max buffer_default estimated_bandwidth mem_mb estimated_rtt
  auto_detect_system_params() {
    # 获取系统内存 (KB)
    local mem_kb=$(awk '/MemTotal/{print $2}' /proc/meminfo 2>/dev/null)
    local mem_mb=$(( mem_kb / 1024 ))
    
    # 根据内存大小推算合理的带宽和延迟
    # 理论依据: 内存越大的服务器通常配置越高的带宽
    # 同时限制缓冲区不超过系统内存的合理比例 (约 1-2%)
    local estimated_bw=100   # 估算带宽 Mbps
    local estimated_rtt=50   # 估算延迟 ms
    
    if [ "$mem_mb" -lt 1024 ]; then
      # 小内存 (<1GB): 假设低带宽 VPS
      estimated_bw=50
      estimated_rtt=80
    elif [ "$mem_mb" -lt 2048 ]; then
      # 1-2GB: 入门 VPS
      estimated_bw=100
      estimated_rtt=60
    elif [ "$mem_mb" -lt 4096 ]; then
      # 2-4GB: 普通 VPS
      estimated_bw=200
      estimated_rtt=50
    elif [ "$mem_mb" -lt 8192 ]; then
      # 4-8GB: 中等配置
      estimated_bw=500
      estimated_rtt=40
    elif [ "$mem_mb" -lt 16384 ]; then
      # 8-16GB: 高配服务器
      estimated_bw=1000
      estimated_rtt=30
    else
      # >16GB: 大内存服务器
      estimated_bw=1000
      estimated_rtt=50
    fi
    
    # 使用 BDP 公式计算缓冲区 (与手动模式统一)
    local calc_result=$(calculate_bdp_params "$estimated_bw" "$estimated_rtt")
    local buffer_max=$(echo "$calc_result" | awk '{print $1}')
    local buffer_default=$(echo "$calc_result" | awk '{print $2}')
    
    # 额外限制: 缓冲区 max 不超过系统内存的 2%
    local mem_limit=$(( mem_kb * 1024 * 2 / 100 ))
    if [ "$buffer_max" -gt "$mem_limit" ]; then
      buffer_max=$mem_limit
      [ $buffer_max -lt 4194304 ] && buffer_max=4194304
    fi
    
    echo "$buffer_max $buffer_default $estimated_bw $mem_mb $estimated_rtt"
  }


  
  # [辅助函数] 清理旧的 TCP 调优参数
  # 同时清理 /etc/sysctl.d/99-tcp-tuning.conf 和 /etc/sysctl.conf 中的遗留配置
  clean_tcp_params() {
    local params=(
      "net.core.rmem_max"
      "net.core.wmem_max"
      "net.core.rmem_default"
      "net.core.wmem_default"
      "net.core.optmem_max"
      "net.ipv4.tcp_rmem"
      "net.ipv4.tcp_wmem"
      "net.core.somaxconn"
      "net.core.netdev_max_backlog"
      "net.ipv4.tcp_max_syn_backlog"
      "net.ipv4.tcp_fin_timeout"
      "net.ipv4.tcp_tw_reuse"
      "net.ipv4.tcp_keepalive_time"
      "net.ipv4.tcp_keepalive_probes"
      "net.ipv4.tcp_keepalive_intvl"
      "net.ipv4.tcp_max_tw_buckets"
      "net.ipv4.ip_local_port_range"
      "net.ipv4.tcp_fastopen"
      "net.ipv4.tcp_mtu_probing"
      "net.ipv4.tcp_slow_start_after_idle"
      "net.ipv4.tcp_timestamps"
      "net.ipv4.tcp_window_scaling"
      "net.ipv4.tcp_sack"
      "net.ipv4.tcp_ecn"
      "net.ipv4.tcp_notsent_lowat"
    )
    
    # 清理新配置文件 (删除整个文件)
    if [ -f "$SYSCTL_D_CONF" ]; then
      rm -f "$SYSCTL_D_CONF"
      echo -e "${GRAY}  已清理 $SYSCTL_D_CONF${RESET}"
    fi
    
    # 清理旧配置文件中的遗留参数 (兼容性)
    if [ -f "$SYSCTL_CONF" ]; then
      for param in "${params[@]}"; do
        sed -i "/^${param}/d" "$SYSCTL_CONF"
      done
      # 清理标记行
      sed -i "/${TCP_BACKUP_TAG}/d" "$SYSCTL_CONF"
    fi
  }
  
  # [辅助函数] 模式预览: 显示当前值 vs 新值对比
  # 参数: $1=buffer_max, $2=buffer_default, $3=scenario (balanced/throughput/latency)
  preview_tcp_changes() {
    local buffer_max=$1
    local buffer_default=$2
    local scenario=${3:-balanced}
    
    echo -e "${CYAN}━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━${RESET}"
    echo -e "${BOLD}参数预览: 当前值 → 新值${RESET}"
    echo -e "${CYAN}━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━${RESET}"
    
    # 根据场景计算目标值
    local new_somaxconn=4096
    local new_syn_backlog=8192
    local new_netdev_backlog=5000
    local new_fin_timeout=15
    local new_keepalive_time=600
    local new_notsent_lowat=16384
    local new_optmem=81920
    local new_max_tw=262144
    
    case $scenario in
      throughput)
        new_netdev_backlog=65535
        new_fin_timeout=30
        new_optmem=262144
        new_notsent_lowat=131072
        new_max_tw=400000
        ;;
      latency)
        new_fin_timeout=10
        new_keepalive_time=300
        new_notsent_lowat=4096
        ;;
    esac
    
    # 格式化函数: 字节转人类可读
    format_bytes() {
      local bytes=$1
      if [ "$bytes" -ge 1048576 ]; then
        echo "$(( bytes / 1048576 )) MB"
      elif [ "$bytes" -ge 1024 ]; then
        echo "$(( bytes / 1024 )) KB"
      else
        echo "$bytes B"
      fi
    }
    
    # 比较并显示
    show_diff() {
      local label=$1
      local param=$2
      local new_val=$3
      local is_bytes=${4:-false}
      
      local old_val=$(sysctl -n "$param" 2>/dev/null || echo "N/A")
      
      # 格式化显示
      local old_display="$old_val"
      local new_display="$new_val"
      if [ "$is_bytes" = true ] && [ "$old_val" != "N/A" ]; then
        old_display="$(format_bytes "$old_val")"
        new_display="$(format_bytes "$new_val")"
      fi
      
      # 判断是否变化
      if [ "$old_val" = "$new_val" ]; then
        printf "  ${GRAY}%-24s${RESET} %s ${GRAY}(无变化)${RESET}\n" "$label" "$old_display"
      else
        printf "  ${YELLOW}%-24s${RESET} %s → ${GREEN}%s${RESET}\n" "$label" "$old_display" "$new_display"
      fi
    }
    
    echo -e "${YELLOW}【缓冲区】${RESET}"
    show_diff "rmem_max" "net.core.rmem_max" "$buffer_max" true
    show_diff "wmem_max" "net.core.wmem_max" "$buffer_max" true
    show_diff "optmem_max" "net.core.optmem_max" "$new_optmem" true
    
    echo -e "${YELLOW}【连接队列】${RESET}"
    show_diff "somaxconn" "net.core.somaxconn" "$new_somaxconn"
    show_diff "syn_backlog" "net.ipv4.tcp_max_syn_backlog" "$new_syn_backlog"
    show_diff "netdev_backlog" "net.core.netdev_max_backlog" "$new_netdev_backlog"
    
    echo -e "${YELLOW}【连接管理】${RESET}"
    show_diff "fin_timeout" "net.ipv4.tcp_fin_timeout" "$new_fin_timeout"
    show_diff "keepalive_time" "net.ipv4.tcp_keepalive_time" "$new_keepalive_time"
    show_diff "max_tw_buckets" "net.ipv4.tcp_max_tw_buckets" "$new_max_tw"
    
    echo -e "${YELLOW}【性能增强】${RESET}"
    show_diff "tcp_notsent_lowat" "net.ipv4.tcp_notsent_lowat" "$new_notsent_lowat" true
    
    echo -e "${CYAN}━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━${RESET}"
  }
  # [辅助函数] 写入 TCP 调优参数
  # 参数: $1=模式名称, $2=buffer_max, $3=buffer_default, $4=场景或自定义参数字符串
  # 自定义参数格式: "key1=val1|key2=val2|..." 支持的 key:
  #   somaxconn, syn_backlog, netdev_backlog, fin_timeout, tw_reuse,
  #   keepalive_time, keepalive_intvl, keepalive_probes, fastopen, mtu_probing, slow_start, timestamps
  #   [新增] window_scaling, sack, ecn, notsent_lowat, optmem_max, port_range_start, port_range_end, max_tw_buckets
  write_tcp_params() {
    local mode_name=$1
    local buffer_max=$2
    local buffer_default=$3
    local params_or_scenario=${4:-balanced}
    
    # 获取内核版本用于兼容性检测
    local kver=$(get_kernel_version)
    
    # 默认参数值 (连接队列)
    local somaxconn=4096
    local syn_backlog=8192
    local netdev_backlog=5000
    
    # 默认参数值 (连接管理)
    local fin_timeout=15
    local tw_reuse=2
    local keepalive_time=600
    local keepalive_intvl=15
    local keepalive_probes=5
    local max_tw_buckets=262144
    local port_range_start=1024
    local port_range_end=65535
    
    # 默认参数值 (性能增强)
    local fastopen=3
    local mtu_probing=1
    local slow_start=0
    local timestamps=1
    local window_scaling=1
    local sack=1
    local ecn=1
    local notsent_lowat=16384
    local optmem_max=81920
    
    # 解析参数: 检查是否是自定义参数字符串 (包含 =)
    if [[ "$params_or_scenario" == *"="* ]]; then
      # 自定义参数模式
      IFS='|' read -ra param_pairs <<< "$params_or_scenario"
      for pair in "${param_pairs[@]}"; do
        local key=$(echo "$pair" | cut -d'=' -f1)
        local val=$(echo "$pair" | cut -d'=' -f2)
        case "$key" in
          somaxconn) somaxconn=$val ;;
          syn_backlog) syn_backlog=$val ;;
          netdev_backlog) netdev_backlog=$val ;;
          fin_timeout) fin_timeout=$val ;;
          tw_reuse) tw_reuse=$val ;;
          keepalive_time) keepalive_time=$val ;;
          keepalive_intvl) keepalive_intvl=$val ;;
          keepalive_probes) keepalive_probes=$val ;;
          max_tw_buckets) max_tw_buckets=$val ;;
          port_range_start) port_range_start=$val ;;
          port_range_end) port_range_end=$val ;;
          fastopen) fastopen=$val ;;
          mtu_probing) mtu_probing=$val ;;
          slow_start) slow_start=$val ;;
          timestamps) timestamps=$val ;;
          window_scaling) window_scaling=$val ;;
          sack) sack=$val ;;
          ecn) ecn=$val ;;
          notsent_lowat) notsent_lowat=$val ;;
          optmem_max) optmem_max=$val ;;
        esac
      done
    else
      # 场景模式
      local scenario=$params_or_scenario
      case $scenario in
        throughput)
          # 高吞吐: 大队列，大缓冲，慢超时
          netdev_backlog=65535
          fin_timeout=30
          optmem_max=262144
          notsent_lowat=131072
          max_tw_buckets=400000
          ;;
        latency)
          # 低延迟: 快超时，小缓冲低水位
          fin_timeout=10
          keepalive_time=300
          keepalive_intvl=10
          notsent_lowat=4096
          ;;
      esac
    fi
    
    # 参数范围限制
    [ $somaxconn -lt 128 ] && somaxconn=128
    [ $somaxconn -gt 65535 ] && somaxconn=65535
    [ $syn_backlog -gt 65535 ] && syn_backlog=65535
    [ $port_range_start -lt 1024 ] && port_range_start=1024
    [ $port_range_end -gt 65535 ] && port_range_end=65535
    
    # [兼容] 写入到检测到的配置文件路径
    # 使用覆盖模式 (>) 而非追加 (>>)，确保配置干净
    cat > "$TARGET_CONF" << EOF
${TCP_BACKUP_TAG} - ${mode_name} - $(date +%Y%m%d_%H%M%S)
# TCP 网络调优参数 - 由脚本自动生成
# 配置文件: $TARGET_CONF
# 重启后自动生效

# TCP 缓冲区 (基于 BDP 计算)
net.core.rmem_max = ${buffer_max}
net.core.wmem_max = ${buffer_max}
net.core.rmem_default = ${buffer_default}
net.core.wmem_default = ${buffer_default}
net.core.optmem_max = ${optmem_max}
net.ipv4.tcp_rmem = 4096 ${buffer_default} ${buffer_max}
net.ipv4.tcp_wmem = 4096 ${buffer_default} ${buffer_max}

# 连接队列
net.core.somaxconn = ${somaxconn}
net.core.netdev_max_backlog = ${netdev_backlog}
net.ipv4.tcp_max_syn_backlog = ${syn_backlog}

# 连接管理
net.ipv4.tcp_fin_timeout = ${fin_timeout}
net.ipv4.tcp_keepalive_time = ${keepalive_time}
net.ipv4.tcp_keepalive_probes = ${keepalive_probes}
net.ipv4.tcp_keepalive_intvl = ${keepalive_intvl}
net.ipv4.tcp_max_tw_buckets = ${max_tw_buckets}
net.ipv4.ip_local_port_range = ${port_range_start} ${port_range_end}
EOF

    # tcp_tw_reuse: 内核 4.6+ 支持值 0/1/2，老版本仅支持 0/1
    if kernel_version_ge "$kver" "4.6"; then
      echo "net.ipv4.tcp_tw_reuse = ${tw_reuse}" >> "$TARGET_CONF"
      echo -e "${GRAY}  [√] tcp_tw_reuse=${tw_reuse} (内核 $kver >= 4.6)${RESET}"
    else
      local tw_compat=$tw_reuse
      [ $tw_compat -gt 1 ] && tw_compat=1
      echo "net.ipv4.tcp_tw_reuse = ${tw_compat}" >> "$TARGET_CONF"
      echo -e "${GRAY}  [!] tcp_tw_reuse=${tw_compat} (内核 $kver < 4.6，使用兼容值)${RESET}"
    fi

    # 写入性能增强参数
    echo "" >> "$TARGET_CONF"
    echo "# 性能增强" >> "$TARGET_CONF"
    
    # tcp_fastopen: 内核 3.7+ 支持
    if kernel_version_ge "$kver" "3.7"; then
      echo "net.ipv4.tcp_fastopen = ${fastopen}" >> "$TARGET_CONF"
      echo -e "${GRAY}  [√] tcp_fastopen=${fastopen} (内核 $kver >= 3.7)${RESET}"
    else
      echo -e "${YELLOW}  [!] 跳过 tcp_fastopen (需要内核 3.7+，当前 $kver)${RESET}"
    fi
    
    echo "net.ipv4.tcp_mtu_probing = ${mtu_probing}" >> "$TARGET_CONF"
    echo "net.ipv4.tcp_slow_start_after_idle = ${slow_start}" >> "$TARGET_CONF"
    echo "net.ipv4.tcp_timestamps = ${timestamps}" >> "$TARGET_CONF"
    echo "net.ipv4.tcp_window_scaling = ${window_scaling}" >> "$TARGET_CONF"
    echo "net.ipv4.tcp_sack = ${sack}" >> "$TARGET_CONF"
    
    # tcp_ecn: 内核 2.4+ 支持，但 ECN_ENABLED (值1) 可能在部分老网络有兼容问题
    echo "net.ipv4.tcp_ecn = ${ecn}" >> "$TARGET_CONF"
    
    # tcp_notsent_lowat: 内核 3.12+ 支持
    if kernel_version_ge "$kver" "3.12"; then
      echo "net.ipv4.tcp_notsent_lowat = ${notsent_lowat}" >> "$TARGET_CONF"
      echo -e "${GRAY}  [√] tcp_notsent_lowat=${notsent_lowat} (内核 $kver >= 3.12)${RESET}"
    else
      echo -e "${YELLOW}  [!] 跳过 tcp_notsent_lowat (需要内核 3.12+，当前 $kver)${RESET}"
    fi
  }

  
  # [辅助函数] 应用并验证参数
  apply_and_verify() {
    echo -e "${CYAN}正在应用参数...${RESET}"
    
    # 执行 sysctl -p 加载新配置文件
    local sysctl_output
    sysctl_output=$(sysctl -p "$TARGET_CONF" 2>&1)
    local sysctl_ret=$?
    
    # 定义需要验证的关键参数及其预期最小值
    local verify_params=(
      "net.core.rmem_max"
      "net.core.wmem_max"
      "net.core.somaxconn"
    )
    
    local verify_failed=0
    local verify_success=0
    
    echo -e "${GRAY}正在验证关键参数...${RESET}"
    
    for param in "${verify_params[@]}"; do
      local current_val=$(sysctl -n "$param" 2>/dev/null)
      local config_val=$(grep "^${param}" "$TARGET_CONF" 2>/dev/null | tail -1 | awk -F'=' '{gsub(/^[ \t]+|[ \t]+$/, "", $2); print $2}')
      
      if [ -n "$config_val" ]; then
        # 对于多值参数 (如 tcp_rmem)，只比较第一个有效数字
        local config_first=$(echo "$config_val" | awk '{print $1}')
        local current_first=$(echo "$current_val" | awk '{print $1}')
        
        if [ "$current_first" == "$config_first" ] || [ "$current_val" == "$config_val" ]; then
          echo -e "  ${GREEN}✓${RESET} $param = $current_val"
          ((verify_success++))
        else
          echo -e "  ${RED}✗${RESET} $param: 期望 $config_val, 实际 $current_val"
          ((verify_failed++))
        fi
      fi
    done
    
    echo -e ""
    
    if [ $verify_failed -eq 0 ] && [ $sysctl_ret -eq 0 ]; then
      echo -e "${GREEN}[√] TCP 调优参数已成功应用 (${verify_success} 项验证通过)${RESET}"
      echo -e "${GRAY}当前生效的关键参数:${RESET}"
      echo -e "  接收缓冲区 max: $(get_tcp_param net.core.rmem_max) bytes"
      echo -e "  发送缓冲区 max: $(get_tcp_param net.core.wmem_max) bytes"
      echo -e "  连接队列: $(get_tcp_param net.core.somaxconn)"
      return 0
    else
      echo -e "${RED}[!] 部分参数应用失败 (${verify_failed} 项未生效)${RESET}"
      if [ -n "$sysctl_output" ]; then
        echo -e "${GRAY}sysctl 输出:${RESET}"
        echo "$sysctl_output" | head -5
      fi
      echo -e "${YELLOW}可能原因: 容器环境限制、内核不支持、或权限不足${RESET}"
      return 1
    fi
  }
  
  while true; do
    clear
    echo -e "${BOLD}${CYAN}📶 TCP 网络调优${RESET}"
    echo -e "${CYAN}==================================================${RESET}"
    
    # --- 环境检测与警告 ---
    local is_container=false
    if is_container_env; then
      is_container=true
      echo -e "${RED}[!] 检测到容器环境，部分参数可能无法修改${RESET}"
    fi
    
    # 显示当前使用的配置文件路径
    echo -e "${GRAY}配置文件: ${TARGET_CONF}${RESET}"
    
    # --- 显示当前参数 (全面显示 + 关键参数高亮) ---
    echo -e "${BOLD}${CYAN}当前 TCP 配置:${RESET}"
    
    # 获取系统内存用于参考
    local sys_mem_kb=$(awk '/MemTotal/{print $2}' /proc/meminfo 2>/dev/null)
    local sys_mem_mb=$(( sys_mem_kb / 1024 ))
    echo -e "${GRAY}系统内存: ${sys_mem_mb} MB | 内核: $(uname -r)${RESET}"
    echo -e ""
    
    # === 缓冲区参数 (关键) ===
    echo -e "${YELLOW}【缓冲区参数】${RESET} ${GRAY}(影响吞吐量)${RESET}"
    local rmem_max=$(get_tcp_param net.core.rmem_max)
    local wmem_max=$(get_tcp_param net.core.wmem_max)
    local optmem_max=$(get_tcp_param net.core.optmem_max)
    local tcp_rmem=$(get_tcp_param net.ipv4.tcp_rmem)
    local tcp_wmem=$(get_tcp_param net.ipv4.tcp_wmem)
    # 转换为人类可读格式
    local rmem_max_mb=$(( rmem_max / 1048576 ))
    local wmem_max_mb=$(( wmem_max / 1048576 ))
    local optmem_kb=$(( optmem_max / 1024 ))
    echo -e "  ${GREEN}★${RESET} rmem_max (全局接收): ${GREEN}${rmem_max_mb} MB${RESET} (${rmem_max} bytes)"
    echo -e "  ${GREEN}★${RESET} wmem_max (全局发送): ${GREEN}${wmem_max_mb} MB${RESET} (${wmem_max} bytes)"
    echo -e "    optmem_max (辅助缓冲): ${GREEN}${optmem_kb} KB${RESET}"
    echo -e "    tcp_rmem (TCP接收): ${GREEN}${tcp_rmem}${RESET}"
    echo -e "    tcp_wmem (TCP发送): ${GREEN}${tcp_wmem}${RESET}"
    
    # === 连接队列参数 ===
    echo -e "${YELLOW}【连接队列】${RESET} ${GRAY}(影响并发)${RESET}"
    echo -e "  ${GREEN}★${RESET} somaxconn (完成队列):     ${GREEN}$(get_tcp_param net.core.somaxconn)${RESET}"
    echo -e "    max_syn_backlog (SYN队列): ${GREEN}$(get_tcp_param net.ipv4.tcp_max_syn_backlog)${RESET}"
    echo -e "    netdev_max_backlog (网卡): ${GREEN}$(get_tcp_param net.core.netdev_max_backlog)${RESET}"
    
    # === 连接管理参数 ===
    echo -e "${YELLOW}【连接管理】${RESET} ${GRAY}(影响资源释放)${RESET}"
    echo -e "    fin_timeout:     ${GREEN}$(get_tcp_param net.ipv4.tcp_fin_timeout)s${RESET}"
    echo -e "    tw_reuse:        ${GREEN}$(get_tcp_param net.ipv4.tcp_tw_reuse)${RESET}"
    echo -e "    max_tw_buckets:  ${GREEN}$(get_tcp_param net.ipv4.tcp_max_tw_buckets)${RESET}"
    echo -e "    keepalive_time:  ${GREEN}$(get_tcp_param net.ipv4.tcp_keepalive_time)s${RESET}"
    echo -e "    keepalive_intvl: ${GREEN}$(get_tcp_param net.ipv4.tcp_keepalive_intvl)s${RESET}"
    echo -e "    port_range:      ${GREEN}$(get_tcp_param net.ipv4.ip_local_port_range)${RESET}"
    
    # === 性能增强参数 ===
    echo -e "${YELLOW}【性能增强】${RESET}"
    echo -e "    tcp_fastopen:    ${GREEN}$(get_tcp_param net.ipv4.tcp_fastopen)${RESET}"
    echo -e "    mtu_probing:     ${GREEN}$(get_tcp_param net.ipv4.tcp_mtu_probing)${RESET}"
    echo -e "    slow_start_idle: ${GREEN}$(get_tcp_param net.ipv4.tcp_slow_start_after_idle)${RESET}"
    echo -e "    window_scaling:  ${GREEN}$(get_tcp_param net.ipv4.tcp_window_scaling)${RESET}"
    echo -e "    sack:            ${GREEN}$(get_tcp_param net.ipv4.tcp_sack)${RESET}"
    echo -e "    ecn:             ${GREEN}$(get_tcp_param net.ipv4.tcp_ecn)${RESET}"
    echo -e "    notsent_lowat:   ${GREEN}$(get_tcp_param net.ipv4.tcp_notsent_lowat)${RESET}"
    
    # 检查是否已有调优配置
    if grep -q "$TCP_BACKUP_TAG" "$SYSCTL_CONF" 2>/dev/null; then
      echo -e ""
      echo -e "${YELLOW}[*] 已存在调优配置 (由本脚本管理)${RESET}"
    fi

    
    echo -e "${CYAN}--------------------------------------------------${RESET}"
    echo -e ""
    echo -e "${CYAN}理论依据: BDP (带宽延迟积) = 带宽 × RTT${RESET}"
    echo -e "${GRAY}缓冲区应设置为 BDP 的 2-3 倍以充分利用带宽${RESET}"
    echo -e ""
    echo -e "${YELLOW}  1.${RESET} 一键优化 (平衡模式 - 自动检测内存)"
    echo -e "${YELLOW}  2.${RESET} 高吞吐模式 (大带宽 - 自动检测内存)"
    echo -e "${YELLOW}  3.${RESET} 低延迟模式 (游戏/VoIP - 自动检测内存)"
    echo -e "${YELLOW}  4.${RESET} 自定义参数 (输入带宽/延迟自动计算)"
    echo -e "${YELLOW}  5.${RESET} ${RED}恢复默认配置${RESET}"
    echo -e "${YELLOW}  ?.${RESET} 参数帮助说明"
    echo -e "${YELLOW}  0.${RESET} 返回上一级"
    echo -e "${CYAN}==================================================${RESET}"
    
    read -p "请输入选项: " choice
    case $choice in
      1|2|3)
        # --- 容器环境警告 ---
        if [ "$is_container" = true ]; then
          echo -e "\n${RED}━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━${RESET}"
          echo -e "${RED}[!] 警告: 容器环境可能无法修改部分内核参数${RESET}"
          echo -e "${RED}━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━${RESET}"
          read -p "仍要继续? [y/N]: " force_continue
          if [[ ! "$force_continue" =~ ^[Yy]$ ]]; then
            continue
          fi
        fi
        
        # 确保配置文件存在 (Debian 13 等系统可能没有此文件)
        if [ ! -f "$SYSCTL_CONF" ]; then
          touch "$SYSCTL_CONF"
          echo -e "${YELLOW}[*] 已创建 $SYSCTL_CONF (系统原本不存在此文件)${RESET}"
        else
          # 仅当文件存在时才备份
          cp "$SYSCTL_CONF" "${SYSCTL_CONF}.tcp_bak.$(date +%Y%m%d_%H%M%S)"
        fi
        
        # 清理旧配置
        clean_tcp_params
        
        local mode_name=""
        local buffer_max=0
        local buffer_default=0
        local scenario=""
        
        # 自动检测系统参数 (使用 BDP 公式计算)
        local sys_params=$(auto_detect_system_params)
        local auto_buffer_max=$(echo "$sys_params" | awk '{print $1}')
        local auto_buffer_default=$(echo "$sys_params" | awk '{print $2}')
        local auto_estimated_bw=$(echo "$sys_params" | awk '{print $3}')
        local sys_mem_mb=$(echo "$sys_params" | awk '{print $4}')
        local auto_estimated_rtt=$(echo "$sys_params" | awk '{print $5}')
        
        # 计算 BDP 用于显示
        local bdp_bytes=$(( auto_estimated_bw * 1000000 / 8 * auto_estimated_rtt / 1000 ))
        local bdp_kb=$(( bdp_bytes / 1024 ))
        
        echo -e "${CYAN}>>> 系统检测结果 (基于 BDP 公式):${RESET}"
        echo -e "  系统内存:     ${GREEN}${sys_mem_mb} MB${RESET}"
        echo -e "  估算带宽:     ${GREEN}${auto_estimated_bw} Mbps${RESET} ${GRAY}(根据内存推算)${RESET}"
        echo -e "  估算延迟:     ${GREEN}${auto_estimated_rtt} ms${RESET}"
        echo -e "  BDP 计算值:   ${GREEN}${bdp_kb} KB${RESET} ${GRAY}(${auto_estimated_bw}Mbps × ${auto_estimated_rtt}ms)${RESET}"
        echo -e "  缓冲区 max:   ${GREEN}$(( auto_buffer_max / 1048576 )) MB${RESET} ${GRAY}(BDP × 3)${RESET}"
        echo -e "  内核版本:     ${GREEN}$(get_kernel_version)${RESET}"
        echo -e ""
        
        case $choice in
          1)
            mode_name="平衡模式 (自动检测)"
            # 使用自动检测的值
            buffer_max=$auto_buffer_max
            buffer_default=$auto_buffer_default
            scenario="balanced"
            ;;
          2)
            mode_name="高吞吐模式 (自动检测)"
            # 高吞吐模式: 在自动检测基础上增加 50% 缓冲区
            buffer_max=$(( auto_buffer_max * 3 / 2 ))
            # 限制最大 128MB
            [ $buffer_max -gt 134217728 ] && buffer_max=134217728
            buffer_default=$(( auto_buffer_default * 2 ))
            [ $buffer_default -gt 2097152 ] && buffer_default=2097152
            scenario="throughput"
            ;;
          3)
            mode_name="低延迟模式 (自动检测)"
            # 低延迟模式: 使用较小的缓冲区减少延迟
            buffer_max=$(( auto_buffer_max / 2 ))
            [ $buffer_max -lt 4194304 ] && buffer_max=4194304
            buffer_default=$(( auto_buffer_default / 2 ))
            [ $buffer_default -lt 65536 ] && buffer_default=65536
            scenario="latency"
            ;;
        esac
        
        # 显示参数预览对比
        echo -e ""
        preview_tcp_changes "$buffer_max" "$buffer_default" "$scenario"
        echo -e ""
        
        read -p "确认应用以上配置? [y/N]: " confirm
        if [[ ! "$confirm" =~ ^[Yy]$ ]]; then
          echo -e "${YELLOW}已取消${RESET}"
          read -p "按 Enter 继续..."
          continue
        fi
        
        echo -e "${CYAN}>>> 正在应用 ${mode_name}...${RESET}"
        write_tcp_params "$mode_name" "$buffer_max" "$buffer_default" "$scenario"
        apply_and_verify
        read -p "按 Enter 继续..."
        ;;
        
      4)
        # --- 自定义参数: 完全自定义所有 TCP 参数 ---
        echo -e "\n${CYAN}>>> 自定义参数模式 (完全控制)${RESET}"
        echo -e "${GRAY}━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━${RESET}"
        echo -e "${CYAN}此模式允许您精确控制所有 TCP 调优参数${RESET}"
        echo -e "${GRAY}输入 0 可随时返回上一级菜单${RESET}"
        echo -e "${GRAY}━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━${RESET}"
        echo -e ""
        
        # ====== 第1步: 基础网络参数 ======
        echo -e "${YELLOW}【第1步】基础网络参数${RESET}"
        
        echo -e "${GRAY}  带宽: 服务商承诺的网络速度，影响缓冲区计算${RESET}"
        echo -e "${GRAY}  建议: 从 speedtest 或服务商面板获取实际值${RESET}"
        read -p "VPS 带宽 (Mbps) [100]: " input_bandwidth
        if [[ "$input_bandwidth" == "0" ]]; then continue; fi
        input_bandwidth=${input_bandwidth:-100}
        if [[ ! "$input_bandwidth" =~ ^[0-9]+$ ]] || [ "$input_bandwidth" -le 0 ]; then
          echo -e "${RED}[!] 带宽必须为正整数${RESET}"; read -p "按 Enter 继续..."; continue
        fi
        
        echo -e ""
        echo -e "${GRAY}  RTT: 往返延迟，影响 BDP 和缓冲区大小${RESET}"
        echo -e "${GRAY}  建议: ping 主要用户节点，取平均值${RESET}"
        read -p "网络延迟 RTT (ms) [50]: " input_rtt
        if [[ "$input_rtt" == "0" ]]; then continue; fi
        input_rtt=${input_rtt:-50}
        if [[ ! "$input_rtt" =~ ^[0-9]+$ ]] || [ "$input_rtt" -le 0 ]; then
          echo -e "${RED}[!] 延迟必须为正整数${RESET}"; read -p "按 Enter 继续..."; continue
        fi
        
        echo -e ""
        echo -e "${GRAY}  BDP倍数: 缓冲区 = BDP × 倍数。倍数越大，吞吐越高但延迟增加${RESET}"
        echo -e "${GRAY}  建议: 测速场景=1~2, 下载=3~4, 游戏/直播=1${RESET}"
        read -p "BDP 倍数 (1-5) [2]: " input_bdp_mult
        if [[ "$input_bdp_mult" == "0" ]]; then continue; fi
        input_bdp_mult=${input_bdp_mult:-2}
        if [[ ! "$input_bdp_mult" =~ ^[0-9]+$ ]] || [ "$input_bdp_mult" -lt 1 ] || [ "$input_bdp_mult" -gt 5 ]; then
          input_bdp_mult=2
        fi
        
        # 计算 BDP 和缓冲区
        local bdp_bytes=$(( input_bandwidth * 1000000 / 8 * input_rtt / 1000 ))
        local calc_buffer_max=$(( bdp_bytes * input_bdp_mult ))
        [ $calc_buffer_max -lt 4194304 ] && calc_buffer_max=4194304
        [ $calc_buffer_max -gt 134217728 ] && calc_buffer_max=134217728
        local calc_buffer_default=$(( bdp_bytes ))
        [ $calc_buffer_default -lt 131072 ] && calc_buffer_default=131072
        [ $calc_buffer_default -gt 1048576 ] && calc_buffer_default=1048576
        
        echo -e "${GREEN}  → 计算: BDP=$(( bdp_bytes / 1024 ))KB, 缓冲区=$(( calc_buffer_max / 1048576 ))MB (×${input_bdp_mult})${RESET}"
        
        # ====== 第2步: 连接队列参数 ======
        echo -e ""
        echo -e "${YELLOW}【第2步】连接队列参数 (影响高并发能力)${RESET}"
        
        echo -e "${GRAY}  somaxconn: 完成三次握手的连接队列长度${RESET}"
        echo -e "${GRAY}  建议: Web服务=4096~65535, 普通VPS=1024~4096${RESET}"
        read -p "somaxconn [4096]: " input_somaxconn
        if [[ "$input_somaxconn" == "0" ]]; then continue; fi
        input_somaxconn=${input_somaxconn:-4096}
        
        echo -e "${GRAY}  syn_backlog: 半连接(SYN_RECV)队列，防SYN洪水攻击${RESET}"
        echo -e "${GRAY}  建议: 设为 somaxconn 的 1~2 倍${RESET}"
        read -p "syn_backlog [8192]: " input_syn_backlog
        if [[ "$input_syn_backlog" == "0" ]]; then continue; fi
        input_syn_backlog=${input_syn_backlog:-8192}
        
        echo -e "${GRAY}  netdev_backlog: 网卡接收队列，高带宽需增大${RESET}"
        echo -e "${GRAY}  建议: 100M=1000, 1G=5000, 10G=30000+${RESET}"
        read -p "netdev_max_backlog [5000]: " input_netdev_backlog
        if [[ "$input_netdev_backlog" == "0" ]]; then continue; fi
        input_netdev_backlog=${input_netdev_backlog:-5000}
        
        # ====== 第3步: 连接管理参数 ======
        echo -e ""
        echo -e "${YELLOW}【第3步】连接管理参数 (影响资源释放速度)${RESET}"
        
        echo -e "${GRAY}  fin_timeout: FIN_WAIT_2 超时，越小越快回收端口${RESET}"
        echo -e "${GRAY}  建议: 默认60过长，推荐10~30秒${RESET}"
        read -p "fin_timeout 秒 [10]: " input_fin_timeout
        if [[ "$input_fin_timeout" == "0" ]]; then continue; fi
        input_fin_timeout=${input_fin_timeout:-10}
        
        echo -e "${GRAY}  tw_reuse: TIME_WAIT端口复用 (0禁/1客户端/2全启)${RESET}"
        echo -e "${GRAY}  建议: 内核4.6+推荐=2, 老内核=1${RESET}"
        read -p "tw_reuse (0/1/2) [2]: " input_tw_reuse
        input_tw_reuse=${input_tw_reuse:-2}
        
        echo -e "${GRAY}  keepalive_time: 空闲多久后发送探活包${RESET}"
        echo -e "${GRAY}  建议: 默认7200太长，推荐300~600秒${RESET}"
        read -p "keepalive_time 秒 [300]: " input_keepalive_time
        if [[ "$input_keepalive_time" == "0" ]]; then continue; fi
        input_keepalive_time=${input_keepalive_time:-300}
        
        echo -e "${GRAY}  keepalive_intvl: 探活包发送间隔${RESET}"
        echo -e "${GRAY}  建议: 推荐10~30秒${RESET}"
        read -p "keepalive_intvl 秒 [10]: " input_keepalive_intvl
        if [[ "$input_keepalive_intvl" == "0" ]]; then continue; fi
        input_keepalive_intvl=${input_keepalive_intvl:-10}
        
        echo -e "${GRAY}  keepalive_probes: 探活失败多少次后断开${RESET}"
        echo -e "${GRAY}  建议: 推荐3~5次${RESET}"
        read -p "keepalive_probes [5]: " input_keepalive_probes
        input_keepalive_probes=${input_keepalive_probes:-5}
        
        # ====== 第4步: 性能增强参数 ======
        echo -e ""
        echo -e "${YELLOW}【第4步】性能增强参数${RESET}"
        
        echo -e "${GRAY}  tcp_fastopen: TFO 减少握手延迟 (需内核3.7+)${RESET}"
        echo -e "${GRAY}  建议: 3=客户端+服务端都启用${RESET}"
        read -p "tcp_fastopen (0/1/2/3) [3]: " input_fastopen
        input_fastopen=${input_fastopen:-3}
        
        echo -e "${GRAY}  mtu_probing: 自动探测最佳MTU，避免分片${RESET}"
        echo -e "${GRAY}  建议: 1=检测到黑洞时启用${RESET}"
        read -p "mtu_probing (0/1/2) [1]: " input_mtu_probing
        input_mtu_probing=${input_mtu_probing:-1}
        
        echo -e "${GRAY}  slow_start_after_idle: 空闲后是否重新慢启动${RESET}"
        echo -e "${GRAY}  建议: 0=禁用，长连接更快恢复速度${RESET}"
        read -p "slow_start_after_idle (0/1) [0]: " input_slow_start
        input_slow_start=${input_slow_start:-0}
        
        echo -e "${GRAY}  tcp_timestamps: 时间戳，用于RTT计算和PAWS${RESET}"
        echo -e "${GRAY}  建议: 1=启用 (禁用可能影响性能)${RESET}"
        read -p "tcp_timestamps (0/1) [1]: " input_timestamps
        input_timestamps=${input_timestamps:-1}
        
        # ====== 显示配置摘要 ======
        echo -e ""
        echo -e "${CYAN}━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━${RESET}"
        echo -e "${GREEN}配置摘要:${RESET}"
        echo -e "  ${YELLOW}【缓冲区】${RESET} (BDP×${input_bdp_mult})"
        echo -e "    buffer_max:     $(( calc_buffer_max / 1048576 )) MB"
        echo -e "    buffer_default: $(( calc_buffer_default / 1024 )) KB"
        echo -e "  ${YELLOW}【连接队列】${RESET}"
        echo -e "    somaxconn:      $input_somaxconn"
        echo -e "    syn_backlog:    $input_syn_backlog"
        echo -e "    netdev_backlog: $input_netdev_backlog"
        echo -e "  ${YELLOW}【连接管理】${RESET}"
        echo -e "    fin_timeout:    ${input_fin_timeout}s"
        echo -e "    tw_reuse:       $input_tw_reuse"
        echo -e "    keepalive:      ${input_keepalive_time}s / ${input_keepalive_intvl}s × ${input_keepalive_probes}"
        echo -e "  ${YELLOW}【性能增强】${RESET}"
        echo -e "    fastopen:       $input_fastopen"
        echo -e "    mtu_probing:    $input_mtu_probing"
        echo -e "    slow_start:     $input_slow_start"
        echo -e "    timestamps:     $input_timestamps"
        echo -e "${CYAN}━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━${RESET}"
        
        read -p "确认应用以上配置? [y/N]: " confirm
        if [[ ! "$confirm" =~ ^[Yy]$ ]]; then
          echo -e "${YELLOW}已取消${RESET}"
          read -p "按 Enter 继续..."
          continue
        fi
        
        # 容器环境警告
        if [ "$is_container" = true ]; then
          echo -e "${YELLOW}[!] 容器环境，部分参数可能不生效${RESET}"
        fi
        
        # 备份
        cp "$SYSCTL_CONF" "${SYSCTL_CONF}.tcp_bak.$(date +%Y%m%d_%H%M%S)"
        
        # 清理旧配置
        clean_tcp_params
        
        # 构建自定义参数字符串
        local custom_params="somaxconn=${input_somaxconn}|syn_backlog=${input_syn_backlog}|netdev_backlog=${input_netdev_backlog}"
        custom_params="${custom_params}|fin_timeout=${input_fin_timeout}|tw_reuse=${input_tw_reuse}"
        custom_params="${custom_params}|keepalive_time=${input_keepalive_time}|keepalive_intvl=${input_keepalive_intvl}|keepalive_probes=${input_keepalive_probes}"
        custom_params="${custom_params}|fastopen=${input_fastopen}|mtu_probing=${input_mtu_probing}|slow_start=${input_slow_start}|timestamps=${input_timestamps}"
        
        # 写入配置
        local mode_name="自定义 (${input_bandwidth}Mbps/${input_rtt}ms/×${input_bdp_mult})"
        write_tcp_params "$mode_name" "$calc_buffer_max" "$calc_buffer_default" "$custom_params"
        apply_and_verify
        read -p "按 Enter 继续..."
        ;;
        
      5)
        # --- 恢复默认配置 ---
        echo -e "\n${CYAN}>>> 恢复默认 TCP 配置${RESET}"
        echo -e "${YELLOW}将移除所有由本脚本添加的 TCP 调优参数${RESET}"
        read -p "确认恢复默认? [y/N]: " confirm
        if [[ ! "$confirm" =~ ^[Yy]$ ]]; then
          continue
        fi
        
        # 备份当前配置文件 (如果存在)
        if [ -f "$TARGET_CONF" ]; then
          cp "$TARGET_CONF" "${TARGET_CONF}.bak.$(date +%Y%m%d_%H%M%S)"
          echo -e "${GRAY}  已备份 $TARGET_CONF${RESET}"
        fi
        
        # 清理调优参数 (同时清理新旧配置文件)
        clean_tcp_params
        
        # 重新加载配置 (清理后将使用内核编译默认值)
        echo -e "${CYAN}正在重置运行时参数...${RESET}"
        
        # 根据系统类型选择重载命令
        if [ "$USE_SYSCTL_D" = true ]; then
          # systemd 系统: 使用 --system 重载所有配置
          sysctl --system >/dev/null 2>&1
        else
          # 老旧系统: 使用 -p 重载 sysctl.conf
          sysctl -p >/dev/null 2>&1
        fi
        
        # 显示恢复后的关键参数值
        echo -e "${GRAY}恢复后的参数值 (内核当前值):${RESET}"
        echo -e "  rmem_max:  $(sysctl -n net.core.rmem_max 2>/dev/null) bytes"
        echo -e "  wmem_max:  $(sysctl -n net.core.wmem_max 2>/dev/null) bytes"
        echo -e "  somaxconn: $(sysctl -n net.core.somaxconn 2>/dev/null)"
        echo -e ""
        
        echo -e "${GREEN}[√] 已清理脚本配置，系统将使用内核默认值${RESET}"
        echo -e "${GRAY}注: 如需完全恢复编译时默认值，可重启系统${RESET}"
        read -p "按 Enter 继续..."
        ;;
        
      "?"|"？")
        # --- 参数帮助说明 ---
        clear
        echo -e "${BOLD}${CYAN}📖 TCP 调优参数帮助说明${RESET}"
        echo -e "${CYAN}==================================================${RESET}"
        echo -e ""
        echo -e "${YELLOW}【缓冲区参数】${RESET}"
        echo -e "  ${GREEN}rmem_max/wmem_max${RESET}"
        echo -e "    最大接收/发送缓冲区大小。决定单个连接能使用的最大内存。"
        echo -e "    计算公式: BDP (带宽×延迟) × 2~3 倍"
        echo -e ""
        echo -e "  ${GREEN}tcp_rmem/tcp_wmem${RESET}"
        echo -e "    格式: 最小值 默认值 最大值"
        echo -e "    TCP 自动调节的缓冲区范围。"
        echo -e ""
        echo -e "  ${GREEN}optmem_max${RESET}"
        echo -e "    辅助缓冲区上限，用于 socket 选项内存。高吞吐场景需增大。"
        echo -e ""
        echo -e "${YELLOW}【连接队列参数】${RESET}"
        echo -e "  ${GREEN}somaxconn${RESET}"
        echo -e "    完成三次握手的连接队列长度。高并发服务需增大。"
        echo -e ""
        echo -e "  ${GREEN}tcp_max_syn_backlog${RESET}"
        echo -e "    半连接队列 (SYN_RECV 状态) 长度。防 SYN 洪水攻击。"
        echo -e ""
        echo -e "${YELLOW}【连接管理参数】${RESET}"
        echo -e "  ${GREEN}tcp_fin_timeout${RESET}"
        echo -e "    FIN_WAIT_2 状态超时时间 (秒)。减小可更快释放资源。"
        echo -e ""
        echo -e "  ${GREEN}tcp_tw_reuse${RESET}"
        echo -e "    TIME_WAIT 状态端口复用: 0=禁用, 1=客户端启用, 2=全启用"
        echo -e ""
        echo -e "  ${GREEN}tcp_max_tw_buckets${RESET}"
        echo -e "    TIME_WAIT 状态最大数量。防止资源耗尽，高并发需增大。"
        echo -e ""
        echo -e "  ${GREEN}ip_local_port_range${RESET}"
        echo -e "    本地端口范围 (起始 结束)。短连接多时可扩展范围。"
        echo -e ""
        echo -e "  ${GREEN}tcp_keepalive_time/intvl/probes${RESET}"
        echo -e "    保活探测: 空闲时间/探测间隔/探测次数。"
        echo -e ""
        echo -e "${YELLOW}【性能增强参数】${RESET}"
        echo -e "  ${GREEN}tcp_fastopen${RESET}"
        echo -e "    TFO 快速打开: 0=禁用, 1=客户端, 2=服务端, 3=都启用"
        echo -e ""
        echo -e "  ${GREEN}tcp_mtu_probing${RESET}"
        echo -e "    MTU 路径发现: 0=禁用, 1=黑洞时启用, 2=始终启用"
        echo -e ""
        echo -e "  ${GREEN}tcp_slow_start_after_idle${RESET}"
        echo -e "    空闲后慢启动: 0=禁用 (长连接推荐), 1=启用"
        echo -e ""
        echo -e "  ${GREEN}tcp_window_scaling${RESET}"
        echo -e "    窗口缩放 (RFC 1323): 高带宽链路必需，建议=1 启用"
        echo -e ""
        echo -e "  ${GREEN}tcp_sack${RESET}"
        echo -e "    选择性确认: 减少丢包时重传量，建议=1 启用"
        echo -e ""
        echo -e "  ${GREEN}tcp_ecn${RESET}"
        echo -e "    显式拥塞通知: 0=禁用, 1=按需, 2=始终。现代网络建议=1"
        echo -e ""
        echo -e "  ${GREEN}tcp_notsent_lowat${RESET}"
        echo -e "    发送缓冲区低水位: 减少延迟，游戏/VoIP 推荐 4096~16384"
        echo -e "${CYAN}==================================================${RESET}"
        read -p "按 Enter 返回..."
        ;;
        
      0)
        return 0
        ;;
      *)
        echo -e "${RED}无效选项${RESET}"
        sleep 1
        ;;
    esac
  done
}

# --- [6. 系统] 系统内核管理 ---

manage_kernels() {
  while true; do
    clear
    echo -e "${BOLD}${CYAN}🐧 系统内核管理${RESET}"
    echo -e "${CYAN}==================================================${RESET}"
    echo -e "当前运行内核: ${GREEN}$(uname -r)${RESET}"
    echo -e "${CYAN}--------------------------------------------------${RESET}"
    echo -e "  ${YELLOW}1.${RESET} 显示所有已安装内核"
    echo -e "  ${YELLOW}2.${RESET} 清理多余内核 (保留当前及必要旧核)"
    echo -e "  ${YELLOW}0.${RESET} 返回主菜单"
    echo -e "${CYAN}==================================================${RESET}"
    read -p "请输入选项: " choice
    case $choice in
      1)
         echo -e "${CYAN}>>> 系统已安装的内核列表:${RESET}"
         if [[ "$PKG_MANAGER" == "apt" ]]; then
             dpkg -l | grep -E "^ii  linux-.*-[0-9]" | awk '{print $2, $3}'
         elif [[ "$PKG_MANAGER" == "dnf" || "$PKG_MANAGER" == "yum" ]]; then
             rpm -qa | grep "^kernel" | sort -V
         elif [[ "$PKG_MANAGER" == "pacman" ]]; then
             pacman -Q | grep -E "^linux"
         elif [[ "$PKG_MANAGER" == "apk" ]]; then
             apk info -v | grep -E "^linux-(lts|virt|edge|-)"
         elif [[ "$PKG_MANAGER" == "zypper" ]]; then
             zypper search -i --type package kernel | awk 'NR>4 {print $2, $5}'
         else
             echo -e "${YELLOW}[?] 包管理器未知，尝试读取 /boot 目录:${RESET}"
             ls -1 /boot/vmlinuz-* 2>/dev/null | sed 's|/boot/vmlinuz-||' || echo -e "${RED}[!] 未找到内核镜像${RESET}"
         fi
         read -p "按 Enter 继续..."
         ;;
      2)
         clean_kernels
         read -p "按 Enter 继续..."
         ;;
      0) return 0 ;;
      *) echo -e "${RED}无效选项${RESET}"; sleep 1 ;;
    esac
  done
}

# --- [子功能] 旧内核清理 ---

clean_kernels() {
  # [容器适配] 容器共享宿主机内核，无独立安装的内核包
  if is_container_env; then
    echo -e "${YELLOW}[!] 检测到容器环境 (OpenVZ/LXC/Docker)${RESET}"
    echo -e "${GRAY}容器共享宿主机内核，无需清理独立内核包。${RESET}"
    return 0
  fi
  
  echo -e "${CYAN}>>> 扫描可清理内核...${RESET}"
  
  if [[ "$PKG_MANAGER" == "apt" ]]; then
      # --- Debian/Ubuntu 清理逻辑 ---
      # 1. 优先清理残留配置 (rc 状态)
      local rc_kernels=$(dpkg -l | grep "^rc" | grep "linux-" | awk '{print $2}')
      if [ -n "$rc_kernels" ]; then
        echo -e "${YELLOW}发现已卸载内核的残留配置，正在自动清理...${RESET}"
        check_pm_lock || return 1
        echo "$rc_kernels" | xargs apt-get -y purge
      fi

      # 2. 扫描已安装的内核并分类
      local current_ver=$(uname -r)
      echo -e "当前运行内核: ${GREEN}$current_ver${RESET}"

      # 获取所有已安装的内核包 (排除元包)
      local all_kernels=$(dpkg -l | grep "^ii" | awk '{print $2}' | grep -E "^linux-(image|headers)-[0-9]+\.[0-9]+" | grep -vE "^linux-(image|headers)-(generic|amd64|cloud)$")
      
      local old_kernels=""
      local newer_kernels=""
      
      for k in $all_kernels; do
          # 提取版本号部分 (例如 linux-image-6.1.0-18-amd64 -> 6.1.0-18-amd64)
          local k_ver=$(echo "$k" | sed -E 's/^linux-(image|headers)-//')
          
          if [[ "$k_ver" == "$current_ver" ]]; then
              continue
          fi
          
          # 使用 sort -V 比较版本
          # 将当前版本和包版本一起排序，看谁排在前面
          if [[ $(echo -e "$k_ver\n$current_ver" | sort -V | tail -n1) == "$k_ver" ]]; then
              # k_ver >= current_ver
              newer_kernels="$newer_kernels $k"
          else
              # k_ver < current_ver
              old_kernels="$old_kernels $k"
          fi
      done

      if [ -n "$newer_kernels" ]; then
          echo -e "${YELLOW}警告: 发现比当前运行版本更${RED}新${YELLOW}的内核 (可能刚安装未重启):${RESET}"
          echo "$newer_kernels"
          echo -e "${CYAN}建议: 若要应用这些新版本，请先重启系统再进行清理。${RESET}"
          echo ""
      fi

      if [ -z "$old_kernels" ]; then
        echo -e "${GREEN}[√] 未发现比当前运行版本更旧的内核。${RESET}"
        return 0
      fi

      echo -e "${YELLOW}发现以下${RED}旧${YELLOW}内核版本 (可安全清理):${RESET}"
      echo "$old_kernels"
      echo -e "${RED}警告: 请确保当前系统已通过当前运行内核 ($current_ver) 成功启动并运行正常。${RESET}"

      read -p "确认清理上述所有旧内核? [y/N]: " k_choice
      if [[ "$k_choice" =~ ^[Yy]$ ]]; then
         check_pm_lock || return 1
         echo -e "${CYAN}正在清理旧内核...${RESET}"
         echo "$old_kernels" | xargs apt-get -y purge
         apt-get -y autoremove
         # 更新 GRUB 配置 (发行版适配)
         if command -v update-grub >/dev/null 2>&1; then
             update-grub
         elif [ -f /boot/grub2/grub.cfg ]; then
             grub2-mkconfig -o /boot/grub2/grub.cfg
         elif [ -d /boot/efi/EFI ]; then
             # EFI 系统
             local efi_grub=$(find /boot/efi/EFI -name "grub.cfg" 2>/dev/null | head -1)
             [ -n "$efi_grub" ] && grub2-mkconfig -o "$efi_grub"
         fi
         echo -e "${GREEN}[√] 内核清理完成${RESET}"
      else
         echo -e "${YELLOW}已取消清理操作${RESET}"
         SKIP_PAUSE=true
      fi

  elif [[ "$PKG_MANAGER" == "dnf" || "$PKG_MANAGER" == "yum" ]]; then
      # --- CentOS/RHEL 清理逻辑 ---
      # 使用 package-cleanup (yum-utils) 或 dnf 自带功能
      # 强制保留 2 个内核
      
      echo -e "${CYAN}正在检查旧内核...${RESET}"
      local count_limit=2
      
      if [[ "$PKG_MANAGER" == "dnf" ]]; then
          # DNF 方式
          echo -e "${YELLOW}将使用 dnf remove --oldinstallonly (保留最近 $count_limit 个)${RESET}"
          read -p "确认清理? [y/N]: " k_choice
          if [[ "$k_choice" =~ ^[Yy]$ ]]; then
             dnf remove --oldinstallonly --setopt installonly_limit=$count_limit -y
             echo -e "${GREEN}[√] 清理完成${RESET}"
          else
             SKIP_PAUSE=true
          fi
      else
          # YUM 方式 (需要 yum-utils)
          if ! command -v package-cleanup &>/dev/null; then
             $PKG_INSTALL yum-utils
          fi
          echo -e "${YELLOW}将使用 package-cleanup --oldkernels (保留最近 $count_limit 个)${RESET}"
          read -p "确认清理? [y/N]: " k_choice
          if [[ "$k_choice" =~ ^[Yy]$ ]]; then
             package-cleanup --oldkernels --count=$count_limit -y
             echo -e "${GREEN}[√] 清理完成${RESET}"
          else
             SKIP_PAUSE=true
          fi
      fi
  else
      echo -e "${RED}[!] 当前系统不支持此脚本的内核清理功能${RESET}"
  fi
}

# --- [6. 系统] SWAP 虚拟内存管理 ---
manage_swap() {
  while true; do
    clear
    echo -e "${BOLD}${CYAN}🧠 SWAP 虚拟内存管理${RESET}"
    echo -e "${CYAN}==================================================${RESET}"

    # 获取当前 Swap 信息
    local swap_total=$(free -m | awk '/Swap:/ {print $2}')
    local swap_used=$(free -m | awk '/Swap:/ {print $3}')
    local swap_file_exists=false
    if [ -f /swapfile ] || grep -q "/swapfile" /etc/fstab; then
      swap_file_exists=true
    fi

    echo -e "当前 Swap 总量: ${GREEN}${swap_total} MB${RESET}"
    echo -e "当前 Swap 已用: ${YELLOW}${swap_used} MB${RESET}"
    
    if [ "$swap_file_exists" = true ]; then
      echo -e "检测到交换文件: ${GREEN}/swapfile (由脚本管理)${RESET}"
    else
      echo -e "检测到交换文件: ${GRAY}无 (或非标准路径)${RESET}"
    fi
    echo -e "${CYAN}--------------------------------------------------${RESET}"

    echo -e "${YELLOW}  1.${RESET} 添加/扩容 Swap (自动创建 /swapfile)"
    echo -e "${YELLOW}  2.${RESET} 调整 Swappiness (优化小内存)"
    echo -e "${YELLOW}  3.${RESET} ${RED}删除/关闭 Swap (清理 /swapfile)${RESET}"
    echo -e "${YELLOW}  0.${RESET} 返回主菜单"
    echo -e "${CYAN}==================================================${RESET}"

    read -p "请输入选项: " choice
    case $choice in
    1)
      echo -e "\n${CYAN}>>> 设置 Swap 大小${RESET}"
      echo -e "${GRAY}提示: 输入 0 可返回上一级菜单${RESET}"
      echo -e "请输入需要的大小 (单位: MB)，例如 1024, 2048, 4096"
      read -p "大小 (MB): " swap_size
      
      if [[ "$swap_size" == "0" ]]; then continue; fi

      if [[ ! "$swap_size" =~ ^[0-9]+$ ]]; then
        echo -e "${RED}[!] 输入无效，请输入数字。${RESET}"
        read -p "Wait..."
        continue
      fi

      echo -e "${CYAN}正在清理旧的 Swap...${RESET}"
      swapoff /swapfile >/dev/null 2>&1
      sed -i '/\/swapfile/d' /etc/fstab
      rm -f /swapfile
      
      # [容器环境检测]
      local is_container=false
      if [ -f /.dockerenv ] || grep -q "docker\|lxc" /proc/1/cgroup 2>/dev/null || \
         ([ -f /proc/vz/veinfo ] && [ ! -f /proc/vz/version ]); then
        is_container=true
        echo -e "${YELLOW}[!] 检测到容器环境，SWAP 支持可能受限${RESET}"
      fi
      
      # [检测文件系统类型] 获取根文件系统信息
      local root_fstype=$(df -T / 2>/dev/null | awk 'NR==2 {print $2}')
      
      echo -e "${CYAN}正在创建 ${swap_size}MB 的 Swap 文件...${RESET}"
      
      # [修复] 使用 dd 的 conv=fsync 确保数据完全写入磁盘，避免空洞
      # 对于某些文件系统需要特殊处理
      local dd_success=false
      
      if [[ "$root_fstype" == "btrfs" ]]; then
        # Btrfs 需要先创建空文件并禁用 CoW
        truncate -s 0 /swapfile 2>/dev/null || touch /swapfile
        chattr +C /swapfile 2>/dev/null
        dd if=/dev/zero of=/swapfile bs=1M count="$swap_size" conv=notrunc,fsync status=progress
        [ $? -eq 0 ] && dd_success=true
      elif [[ "$root_fstype" == "xfs" ]]; then
        # XFS 可以使用 fallocate，但需要禁用 reflink
        if command -v fallocate >/dev/null 2>&1; then
          fallocate -l "${swap_size}M" /swapfile 2>/dev/null
          if [ $? -eq 0 ]; then
            dd_success=true
          fi
        fi
        # fallocate 失败则回退到 dd
        if [ "$dd_success" = false ]; then
          dd if=/dev/zero of=/swapfile bs=1M count="$swap_size" conv=fsync status=progress
          [ $? -eq 0 ] && dd_success=true
        fi
      else
        # ext4 及其他文件系统 - 使用 dd + conv=fsync
        dd if=/dev/zero of=/swapfile bs=1M count="$swap_size" conv=fsync status=progress
        [ $? -eq 0 ] && dd_success=true
      fi
      
      if [ "$dd_success" = false ]; then
        echo -e "${RED}[!] 无法创建 Swap 文件${RESET}"
        rm -f /swapfile
        read -p "按 Enter 继续..."
        continue
      fi

      chmod 600 /swapfile
      
      # mkswap
      if ! mkswap /swapfile; then
        echo -e "${RED}[!] mkswap 失败，无法格式化交换文件${RESET}"
        rm -f /swapfile
        read -p "按 Enter 继续..."
        continue
      fi
      
      # [关键修复] 检查 swapon 返回值
      local swapon_output
      swapon_output=$(swapon /swapfile 2>&1)
      local swapon_ret=$?
      
      if [ $swapon_ret -ne 0 ]; then
        echo -e "${RED}[!] swapon 失败: ${RESET}"
        echo -e "${GRAY}$swapon_output${RESET}"
        
        # 分析错误原因并给出建议
        if echo "$swapon_output" | grep -q "holes"; then
          echo -e "${YELLOW}原因: 交换文件包含空洞 (holes)，这通常发生在:${RESET}"
          echo -e "${GRAY}  • 容器化环境 (LXC/OpenVZ/Docker) 的 overlay 文件系统${RESET}"
          echo -e "${GRAY}  • 某些特殊配置的存储后端${RESET}"
          echo -e "${YELLOW}建议: 联系 VPS 服务商确认是否支持 SWAP，或使用 zram 作为替代${RESET}"
        elif echo "$swapon_output" | grep -qi "operation not permitted\|permission denied"; then
          echo -e "${YELLOW}原因: 权限不足 (可能是容器环境限制)${RESET}"
          echo -e "${GRAY}建议: 容器环境通常不允许创建 SWAP，需要宿主机支持${RESET}"
        fi
        
        # 回滚清理
        rm -f /swapfile
        read -p "按 Enter 继续..."
        continue
      fi
      
      # 验证 SWAP 是否真正生效
      local verify_swap=$(free -m | awk '/Swap:/ {print $2}')
      if [ "$verify_swap" -eq 0 ] 2>/dev/null; then
        echo -e "${RED}[!] SWAP 激活验证失败，实际大小为 0${RESET}"
        swapoff /swapfile 2>/dev/null
        rm -f /swapfile
        read -p "按 Enter 继续..."
        continue
      fi
      
      # 持久化 (仅在确认成功后写入)
      echo "/swapfile none swap sw 0 0" >>/etc/fstab
      
      echo -e "${GREEN}[√] Swap 设置成功！${RESET}"
      free -h
      read -p "按 Enter 继续..."
      ;;
    2)
      echo -e "\n${CYAN}>>> 调整 vm.swappiness (虚拟内存积极度)${RESET}"
      
      # 智能检测与推荐逻辑
      local current_swap=$(cat /proc/sys/vm/swappiness 2>/dev/null)
      local mem_kb=$(awk '/MemTotal/ {print $2}' /proc/meminfo)
      local mem_gb=$(awk "BEGIN {printf \"%.1f\", $mem_kb/1024/1024}")
      
      local rec_val=60
      local rec_msg="内存充裕 (>8GB)，保持默认平衡策略 (60)"
      
      if [ "$mem_kb" -lt 2097152 ]; then # < 2GB
          rec_val=1
          rec_msg="小内存 (<2GB)，建议设为 1 以最大程度避免 IO 卡顿"
      elif [ "$mem_kb" -lt 8388608 ]; then # < 8GB
          rec_val=10
          rec_msg="中等内存 (<8GB)，建议设为 10 以优先使用物理内存"
      fi

      echo -e "当前系统内存: ${YELLOW}${mem_gb} GB${RESET}"
      echo -e "当前 Swappiness: ${GREEN}$current_swap${RESET}"
      echo -e "推荐设置值: ${GREEN}$rec_val${RESET} (${GRAY}$rec_msg${RESET})"
      
      echo -e "${GRAY}--------------------------------------------------${RESET}"
      echo -e "输入 0 返回，直接回车使用推荐值 ($rec_val)"
      read -p "请输入新值 (0-100): " new_swap_val
      
      if [[ "$new_swap_val" == "0" ]]; then continue; fi
      if [ -z "$new_swap_val" ]; then new_swap_val=$rec_val; fi

      if [[ ! "$new_swap_val" =~ ^[0-9]+$ ]] || [ "$new_swap_val" -gt 100 ]; then
         echo -e "${RED}[!] 输入无效${RESET}"
      else
         # [修复] 检查 sysctl 写入是否成功 (容器环境可能只读)
         if ! sysctl -w vm.swappiness="$new_swap_val" >/dev/null 2>&1; then
           echo -e "${RED}[!] 无法修改 swappiness${RESET}"
           if is_container_env; then
             echo -e "${YELLOW}原因: 容器环境可能限制了内核参数修改${RESET}"
           else
             echo -e "${YELLOW}请检查是否有足够权限${RESET}"
           fi
         else
           # 永久生效
           if grep -q "^vm.swappiness" /etc/sysctl.conf; then
              sed -i "s/^vm.swappiness.*/vm.swappiness = $new_swap_val/" /etc/sysctl.conf
           else
              echo "vm.swappiness = $new_swap_val" >> /etc/sysctl.conf
           fi
           echo -e "${GREEN}[√] Swappiness 已设置为 $new_swap_val${RESET}"
         fi
      fi
      read -p "按 Enter 继续..."
      ;;
    3)
      echo -e "\n${CYAN}>>> 正在删除 Swap...${RESET}"
      swapoff /swapfile >/dev/null 2>&1
      # 这里的 /swapfile 是特指本脚本创建的，但也尝试关闭其他
      sed -i '/\/swapfile/d' /etc/fstab
      rm -f /swapfile
      
      echo -e "${GREEN}[√] Swap 已关闭并清理 /swapfile${RESET}"
      free -h
      read -p "按 Enter 继续..."
      ;;
    0)
      SKIP_PAUSE=true
      return 0
      ;;
    *)
      echo -e "${RED}无效选项${RESET}"
      sleep 1
      ;;
    esac
  done
}

# ---------- 修改 SSH 端口 (增强版: 增加恢复默认提示) ----------
change_ssh_port() {
  echo -e "${CYAN}>>> 正在修改 SSH 端口...${RESET}"

  local CURRENT_PORT=$(grep -E "^Port" /etc/ssh/sshd_config | awk '{print $2}' | head -n 1)
  if [[ -z "$CURRENT_PORT" ]]; then CURRENT_PORT="22"; fi
  echo -e "${CYAN}当前SSH端口: ${YELLOW}$CURRENT_PORT${RESET}"

  while true; do
    while true; do
      # --- [增强] 提示文本优化 ---
      echo -ne "${CYAN}请输入新的SSH端口号 (输入 22 恢复默认, 0 退出): ${RESET}"
      read -r NEW_PORT

      if [ "$NEW_PORT" == "0" ]; then
        SKIP_PAUSE=true
        return 0
      fi

      if [[ ! $NEW_PORT =~ ^[0-9]+$ ]]; then
        echo -e "${RED}错误：端口号必须是数字${RESET}"
        continue
      fi

      if [[ $NEW_PORT -eq $CURRENT_PORT ]]; then
        echo -e "${YELLOW}[!] 新端口与当前端口相同，无需修改${RESET}"
        return 1
      fi

      if ss -tuln | grep -q ":${NEW_PORT} "; then
        echo -e "${YELLOW}[!] 警告: 端口 $NEW_PORT 已被其他服务使用${RESET}"
        echo -ne "${YELLOW}是否继续？(y/N): ${RESET}"
        read -r FORCE_CONTINUE
        if [[ ! $FORCE_CONTINUE =~ ^[Yy]$ ]]; then continue; fi
      fi
      break
    done

    # --- [增强] 确认逻辑区分 ---
    if [ "$NEW_PORT" == "22" ]; then
      echo -e "\n${CYAN}即将恢复默认 SSH 端口 (22)${RESET}"
    else
      echo -e "\n${CYAN}即将修改SSH端口: ${YELLOW}$CURRENT_PORT -> $NEW_PORT${RESET}"
    fi

    echo -ne "${YELLOW}确认修改？(y/N): ${RESET}"
    read -r CONFIRM
    if [[ ! $CONFIRM =~ ^[Yy]$ ]]; then
      echo -e "${YELLOW}[!] 操作已取消，请重新输入端口号${RESET}"
      continue
    else
      break
    fi
  done

  local backup_file="/etc/ssh/sshd_config.backup.$(date +%Y%m%d%H%M%S)"
  cp /etc/ssh/sshd_config "$backup_file"
  echo -e "${GREEN}[√] 已备份SSH配置文件: $backup_file${RESET}"

  if grep -E "^#? *Port " /etc/ssh/sshd_config >/dev/null; then
    sed -i -E "s/^#? *Port [0-9]+/Port $NEW_PORT/" /etc/ssh/sshd_config
  else
    echo "Port $NEW_PORT" >>/etc/ssh/sshd_config
  fi
  echo -e "${GREEN}[√] SSH配置已更新${RESET}"

  # [RHEL/CentOS] SELinux 端口上下文处理
  if command -v semanage >/dev/null 2>&1 && command -v getenforce >/dev/null 2>&1; then
      if [ "$(getenforce)" != "Disabled" ]; then
          echo -e "${CYAN}检测到 SELinux 开启，正在添加端口上下文...${RESET}"
          # 尝试添加，如果已存在则尝试修改
          semanage port -a -t ssh_port_t -p tcp "$NEW_PORT" 2>/dev/null || \
          semanage port -m -t ssh_port_t -p tcp "$NEW_PORT" 2>/dev/null
          echo -e "${GREEN}[√] SELinux 端口规则已更新${RESET}"
      fi
  fi

  local firewall_configured=false
  if command -v ufw >/dev/null 2>&1 && ufw status | grep -q "active"; then
    echo -e "${CYAN}检测到 UFW 防火墙正在运行，正在放行端口...${RESET}"
    ufw allow "$NEW_PORT/tcp"
    echo -e "${GREEN}[√] 已添加 UFW 规则: allow $NEW_PORT/tcp${RESET}"
    firewall_configured=true
  fi
  if command -v firewall-cmd >/dev/null 2>&1 && systemctl is-active firewalld >/dev/null 2>&1; then
    firewall-cmd --zone=public --add-port=$NEW_PORT/tcp --permanent >/dev/null
    firewall-cmd --reload >/dev/null
    echo -e "${GREEN}[√] 已添加 Firewalld 规则${RESET}"
    firewall_configured=true
  fi
  if [ "$firewall_configured" = false ] && command -v iptables >/dev/null 2>&1; then
    if iptables -L INPUT | grep -qE "DROP|REJECT"; then
      iptables -I INPUT -p tcp --dport $NEW_PORT -j ACCEPT
      echo -e "${GREEN}[√] 已添加 iptables 临时规则${RESET}"
    fi
  fi

  if [ "$firewall_configured" = false ]; then
    echo -e "${YELLOW}======================================================${RESET}"
    echo -e "${RED}[!] 警告：未检测到受支持的防火墙 (ufw/firewalld)${RESET}"
    echo -e "${YELLOW}请务必手动放行端口 ${NEW_PORT}，否则无法连接！${RESET}"
    echo -e "${YELLOW}======================================================${RESET}"
    read -p "我已确认防火墙设置无误 [按回车继续]"
  fi

  echo -e "\n${CYAN}是否立即重启SSH服务以使更改生效？${RESET}"
  echo -ne "${YELLOW}请输入选择 (Y/n): ${RESET}"
  read -r RESTART_SSH

  if [[ $RESTART_SSH =~ ^[Nn]$ ]]; then
    echo -e "${YELLOW}[!] 请稍后手动执行: systemctl restart ssh${RESET}"
    return 0
  else
    echo -e "${CYAN}正在重启SSH服务...${RESET}"
    if sshd -t; then
      # [修复] 使用 $SVC_SSH 变量适配不同发行版 (Debian: ssh, RHEL: sshd)
      systemctl restart $SVC_SSH 2>/dev/null || service $SVC_SSH restart 2>/dev/null
      sleep 2
      if systemctl is-active --quiet $SVC_SSH || service $SVC_SSH status >/dev/null 2>&1; then
        echo -e "${GREEN}[√] SSH服务重启成功${RESET}"
        rm -f "$backup_file"
        echo -e "\n${GREEN}端口已修改为 $NEW_PORT${RESET}"
        echo -e "${YELLOW}请新开窗口测试: ssh -p $NEW_PORT root@<IP>${RESET}"
      else
        echo -e "${RED}[!] 警告：SSH启动失败，正在还原备份...${RESET}"
        cp "$backup_file" /etc/ssh/sshd_config
        systemctl restart $SVC_SSH
        return 1
      fi
    else
      echo -e "${RED}[!] 错误：SSH配置语法检查失败，已还原备份${RESET}"
      cp "$backup_file" /etc/ssh/sshd_config
      return 1
    fi
  fi
}

modify_dns() {
  echo -e "${CYAN}>>> 修改系统DNS地址...${RESET}"

  # 检查权限
  if [ $EUID -ne 0 ]; then
    echo -e "${RED}错误: 此功能需要root权限执行${RESET}"
    return 1
  fi

  # 常用DNS服务器列表 (保持原样)
  common_dns=(
    # IPv4
    "8.8.8.8|Google Public DNS (IPv4)"
    "8.8.4.4|Google Public DNS 备用 (IPv4)"
    "1.1.1.1|Cloudflare DNS (IPv4)"
    "1.0.0.1|Cloudflare DNS 备用 (IPv4)"
    "208.67.222.222|OpenDNS (IPv4)"
    "208.67.220.220|OpenDNS 备用 (IPv4)"
    "9.9.9.9|Quad9 DNS (IPv4)"
    "149.112.112.112|Quad9 DNS 备用 (IPv4)"
    "94.140.14.14|AdGuard DNS (IPv4)"
    "94.140.15.15|AdGuard DNS 备用 (IPv4)"
    "223.5.5.5|阿里 AliDNS (IPv4)"
    "223.6.6.6|阿里 AliDNS 备用 (IPv4)"
    "119.29.29.29|腾讯 DNSPod (IPv4)"
    "180.76.76.76|百度 BaiduDNS (IPv4)"
    # IPv6
    "2001:4860:4860::8888|Google Public DNS (IPv6)"
    "2001:4860:4860::8844|Google Public DNS 备用 (IPv6)"
    "2606:4700:4700::1111|Cloudflare DNS (IPv6)"
    "2606:4700:4700::1001|Cloudflare DNS 备用 (IPv6)"
    "2620:119:35::35|OpenDNS (IPv6)"
    "2620:119:53::53|OpenDNS 备用 (IPv6)"
    "2620:fe::fe|Quad9 DNS (IPv6)"
    "2a10:50c0::ad1:ff|AdGuard DNS (IPv6)"
    "2400:3200::1|阿里 AliDNS (IPv6)"
    "2400:da00::6666|百度 BaiduDNS (IPv6)"
  )

  # 全局变量，用于接收子函数返回的 IP 列表
  SELECTED_IPS=()

  # 显示当前DNS配置
  echo -e "${YELLOW}当前DNS配置:${RESET}"
  if [ -f /etc/resolv.conf ]; then
    grep -E '^nameserver' /etc/resolv.conf | while read line; do
      echo -e "  ${GREEN}✓${RESET} $line"
    done
  fi

  # 使用循环包裹菜单
  while true; do
    # 每次循环清空选择
    SELECTED_IPS=()

    echo -e "\n${CYAN}请选择操作方式:${RESET}"
    echo -e "  ${GREEN}1${RESET}) 自动测试并手动选择 (支持多选，含IPv6)"
    echo -e "  ${GREEN}2${RESET}) 手动输入DNS地址 (支持连续输入，含IPv6)"
    echo -e "  ${GREEN}3${RESET}) 从常用DNS列表选择 (支持多选，含IPv6)"
    # --- 新增选项 ---
    echo -e "  ${RED}4${RESET}) 恢复 DHCP/系统默认 (清除静态配置)"
    echo -e "  ${YELLOW}0.${RESET} 取消操作/返回"

    read -p "请输入选择 [0-4]: " choice

    case $choice in
    1)
      auto_test_dns
      ;;
    2)
      manual_input_dns
      ;;
    3)
      select_from_list
      ;;
    4)
      # --- 恢复默认逻辑 ---
      echo -e "${CYAN}>>> 正在恢复系统默认 DNS...${RESET}"

      # 1. 解锁文件 (如果之前被锁定)
      chattr -i /etc/resolv.conf 2>/dev/null

      # 2. 删除静态文件
      rm -f /etc/resolv.conf

      # 3. 清理 systemd-resolved 全局配置 (如果之前脚本修改过)
      if [ -f /etc/systemd/resolved.conf ]; then
        sed -i '/^DNS=/d' /etc/systemd/resolved.conf
        sed -i '/^FallbackDNS=/d' /etc/systemd/resolved.conf
        sed -i '/^#DNS=/d' /etc/systemd/resolved.conf
        sed -i '/^#FallbackDNS=/d' /etc/systemd/resolved.conf
      fi

      # 4. 恢复系统默认行为
      # 如果存在 systemd-resolved (Debian 10+/Ubuntu)，恢复软链接
      if [ -d /run/systemd/resolve ]; then
        ln -sf /run/systemd/resolve/stub-resolv.conf /etc/resolv.conf
        systemctl restart systemd-resolved 2>/dev/null
      else
        # 传统环境，重启网络服务让 DHCP 客户端重新生成配置
        systemctl restart networking 2>/dev/null || systemctl restart NetworkManager 2>/dev/null
      fi

      echo -e "${GREEN}[√] 已恢复系统默认设置 (交由 DHCP/Systemd 接管)${RESET}"
      echo -e "${YELLOW}当前状态:${RESET}"
      sleep 1
      ls -l /etc/resolv.conf 2>/dev/null

      SKIP_PAUSE=true
      return 0
      ;;
    0)
      echo -e "${YELLOW}已取消DNS修改操作${RESET}"
      SKIP_PAUSE=true
      return 0
      ;;
    *)
      echo -e "${RED}无效选择，请重新输入${RESET}"
      continue
      ;;
    esac

    # 检查是否有选中的 IP (仅针对 1-3 选项)
    if [ ${#SELECTED_IPS[@]} -eq 0 ]; then
      echo -e "${YELLOW}未选择任何 DNS，返回上一级菜单...${RESET}"
      continue # 继续循环
    fi

    # 如果选择了IP，则跳出循环，继续执行应用逻辑
    break
  done

  # === 下方为应用新DNS的逻辑 (仅针对 1-3 选项) ===

  # 数组去重
  # [修复] 使用更兼容的方法 (mawk/gawk 都支持)
  local unique_ips=""
  for ip in "${SELECTED_IPS[@]}"; do
    if [[ ! " $unique_ips " =~ " $ip " ]]; then
      unique_ips="$unique_ips $ip"
    fi
  done
  SELECTED_IPS=($unique_ips)

  echo -e "\n${CYAN}准备应用新的 DNS 配置: ${SELECTED_IPS[*]}${RESET}"

  # --- 1. 备份配置 ---
  local backup_file="/etc/resolv.conf.backup.$(date +%Y%m%d_%H%M%S)"
  local backup_systemd=""

  # 尝试备份
  if cp -P /etc/resolv.conf "$backup_file" 2>/dev/null; then
    echo -e "${GREEN}[√] 已备份原配置到: $backup_file${RESET}"
  else
    touch "$backup_file"
    echo -e "${YELLOW}[!] 原配置不存在或无法备份，将创建新配置...${RESET}"
  fi

  # 如果存在 systemd-resolved，也备份它的配置
  if [ -f /etc/systemd/resolved.conf ]; then
    backup_systemd="/etc/systemd/resolved.conf.backup.$(date +%Y%m%d_%H%M%S)"
    cp /etc/systemd/resolved.conf "$backup_systemd" 2>/dev/null
  fi

  # --- 2. 写入新配置 (先清理后应用) ---
  write_dns_config "${SELECTED_IPS[@]}"

  # --- 3. 验证与回滚 ---
  if verify_dns_config; then
    echo -e "${GREEN}[√] DNS修改成功且验证通过${RESET}"
    echo -e "${YELLOW}新的DNS配置:${RESET}"
    grep -E '^nameserver' /etc/resolv.conf | while read line; do
      echo -e "  ${GREEN}✓${RESET} $line"
    done

    # 验证成功，删除备份文件
    echo -e "${CYAN}>>> 正在清理备份文件...${RESET}"
    [ -f "$backup_file" ] && rm -f "$backup_file"
    [ -n "$backup_systemd" ] && [ -f "$backup_systemd" ] && rm -f "$backup_systemd"
    echo -e "${GREEN}[√] 备份文件已删除${RESET}"

  else
    echo -e "${RED}[×] DNS配置验证失败，正在还原配置...${RESET}"

    # 还原 resolv.conf
    if [ -f "$backup_file" ]; then
      chattr -i /etc/resolv.conf 2>/dev/null
      rm -f /etc/resolv.conf
      cp -P "$backup_file" /etc/resolv.conf 2>/dev/null || cp "$backup_file" /etc/resolv.conf
      echo -e "${YELLOW}[!] 已还原 /etc/resolv.conf${RESET}"
    fi

    # 还原 systemd-resolved
    if [ -n "$backup_systemd" ] && [ -f "$backup_systemd" ]; then
      cp "$backup_systemd" /etc/systemd/resolved.conf
      systemctl restart systemd-resolved 2>/dev/null
      echo -e "${YELLOW}[!] 已还原 /etc/systemd/resolved.conf${RESET}"
    fi

    return 1
  fi
}

auto_test_dns() {
  echo -e "${CYAN}>>> 正在测试常用DNS速度 (IPv4/IPv6 并行测试)...${RESET}"

  # 测试的DNS服务器 (混合v4和v6)
  local test_dns=(
    "8.8.8.8|Google IPv4"
    "1.1.1.1|Cloudflare IPv4"
    "208.67.222.222|OpenDNS IPv4"
    "9.9.9.9|Quad9 IPv4"
    "223.5.5.5|AliDNS IPv4"
    "119.29.29.29|DNSPod IPv4"
    "180.76.76.76|Baidu IPv4"
    "2001:4860:4860::8888|Google IPv6"
    "2606:4700:4700::1111|Cloudflare IPv6"
    "2400:3200::1|AliDNS IPv6"
    "2400:da00::6666|Baidu IPv6"
  )

  # 临时目录存放结果
  local dns_tmp_dir="${TEMP_DIR}/dns_test"
  mkdir -p "$dns_tmp_dir"
  rm -f "$dns_tmp_dir"/*

  # 并行测试
  local pids=()
  for i in "${!test_dns[@]}"; do
    (
      local info="${test_dns[$i]}"
      IFS='|' read -r dns_ip dns_name <<<"$info"
      
      # 判断 ping 命令
      local ping_cmd="ping"
      [[ "$dns_ip" == *":"* ]] && ping_cmd="ping6"
      # 部分系统 ping6 是 ping -6 的软链或不存在，做兼容检测
      if [[ "$ping_cmd" == "ping6" ]]; then
        if ! command -v ping6 &>/dev/null; then ping_cmd="ping -6"; fi
      fi

      # 执行 Ping (2次, 超时2秒)
      # 结果输出格式: latency(ms) 或 9999
      local lat="9999"
      if res=$(LC_ALL=C $ping_cmd -c 2 -W 2 "$dns_ip" 2>/dev/null | grep -i 'avg'); then
         lat=$(echo "$res" | awk -F'/' '{print $5}')
      fi
      
      echo "$lat" > "${dns_tmp_dir}/${i}.res"
    ) &
    pids+=($!)
  done

  # 显示进度条动画 (简单版)
  local spin='-\|/'
  local active=1
  while [ $active -gt 0 ]; do
    active=0
    for pid in "${pids[@]}"; do
      if kill -0 "$pid" 2>/dev/null; then
        ((active++))
      fi
    done
    if [ $active -gt 0 ]; then
       # 打印旋转动画
       local i=$(( (i+1) %4 ))
       printf "\r${CYAN}>>> 正在测试中... [%c] ${RESET}" "${spin:$i:1}"
       sleep 0.1
    fi
  done
  printf "\r${CYAN}>>> 测试完成！                   ${RESET}\n"

  # 收集结果
  declare -a dns_results
  for i in "${!test_dns[@]}"; do
    local latency="9999"
    if [ -f "${dns_tmp_dir}/${i}.res" ]; then
      latency=$(cat "${dns_tmp_dir}/${i}.res")
    fi
    local info="${test_dns[$i]}"
    IFS='|' read -r dns_ip dns_name <<<"$info"
    # 存入格式： latency|ip|name
    dns_results[$i]="$latency|$dns_ip|$dns_name"
  done

  # 清理
  rm -rf "$dns_tmp_dir"

  # 分离 v4 / v6
  local v4_list=()
  local v6_list=()
  for res in "${dns_results[@]}"; do
    IFS='|' read -r lat ip nm <<<"$res"
    if [[ "$ip" == *":"* ]]; then
      v6_list+=("$res")
    else
      v4_list+=("$res")
    fi
  done

  # 排序
  local sorted_v4=()
  local sorted_v6=()
  if [ ${#v4_list[@]} -gt 0 ]; then
    IFS=$'\n' sorted_v4=($(printf "%s\n" "${v4_list[@]}" | sort -n -t'|' -k1))
    unset IFS
  fi
  if [ ${#v6_list[@]} -gt 0 ]; then
    IFS=$'\n' sorted_v6=($(printf "%s\n" "${v6_list[@]}" | sort -n -t'|' -k1))
    unset IFS
  fi

  local valid_options=()
  local display_index=1

  # Display IPv4
  echo -e "\n${CYAN}IPv4 DNS 延迟排名:${RESET}"
  local v4_count=0
  for item in "${sorted_v4[@]}"; do
    IFS='|' read -r latency ip name <<<"$item"
    if [ "$latency" != "9999" ] && [ -n "$latency" ]; then
      echo -e "  ${GREEN}${display_index}${RESET}. ${BOLD}$name${RESET} ($ip) - ${YELLOW}${latency}ms${RESET}"
      valid_options[$display_index]="$ip"
      display_index=$((display_index + 1))
      ((v4_count++))
    fi
  done
  [ $v4_count -eq 0 ] && echo -e "  ${GRAY}无可用 IPv4 结果${RESET}"

  # Display IPv6
  echo -e "\n${CYAN}IPv6 DNS 延迟排名:${RESET}"
  local v6_count=0
  for item in "${sorted_v6[@]}"; do
    IFS='|' read -r latency ip name <<<"$item"
    if [ "$latency" != "9999" ] && [ -n "$latency" ]; then
      echo -e "  ${GREEN}${display_index}${RESET}. ${BOLD}$name${RESET} ($ip) - ${YELLOW}${latency}ms${RESET}"
      valid_options[$display_index]="$ip"
      display_index=$((display_index + 1))
      ((v6_count++))
    fi
  done
  [ $v6_count -eq 0 ] && echo -e "  ${GRAY}无可用 IPv6 结果${RESET}"

  # Check validation
  if [ ${#valid_options[@]} -eq 0 ]; then
    echo -e "${RED}所有DNS测试均超时，请检查网络连接${RESET}"
    return 1
  fi

  echo -e "\n${YELLOW}提示：可以输入多个编号进行组合（例如：1 3）(输入 0 退出)${RESET}"
  read -p "请输入要使用的DNS编号 (用空格分隔): " user_choices

  # 处理用户输入
  for choice in $user_choices; do
    if [ "$choice" == "0" ]; then return 0; fi
    if [ -n "${valid_options[$choice]}" ]; then
      SELECTED_IPS+=("${valid_options[$choice]}")
    fi
  done
}

manual_input_dns() {
  echo -e "${CYAN}>>> 手动输入DNS地址${RESET}"
  echo -e "${YELLOW}提示：支持输入多个IP地址(IPv4/IPv6)，用空格分隔 (输入 0 返回)${RESET}" # [修改] 提示文本

  read -p "请输入DNS服务器地址: " input_dns
  if [ "$input_dns" == "0" ]; then return 0; fi

  for ip in $input_dns; do
    if validate_ip "$ip"; then
      SELECTED_IPS+=("$ip")
    else
      echo -e "${RED}忽略无效的IP地址格式: $ip${RESET}"
    fi
  done
}

select_from_list() {
  echo -e "${CYAN}>>> 从常用DNS列表选择${RESET}"

  echo -e "${YELLOW}常用DNS服务器列表:${RESET}"
  for i in "${!common_dns[@]}"; do
    IFS='|' read -r ip name <<<"${common_dns[$i]}"
    echo -e "  ${GREEN}$((i + 1))${RESET}) $name - ${YELLOW}$ip${RESET}"
  done

  echo -e "\n${YELLOW}提示：可以输入多个编号进行组合（例如：1 2）(输入 0 退出)${RESET}"
  read -p "请选择DNS服务器编号 [用空格分隔]: " user_choices

  for choice in $user_choices; do
    if [ "$choice" == "0" ]; then return 0; fi

    if [[ "$choice" =~ ^[0-9]+$ ]] && [ "$choice" -ge 1 ] && [ "$choice" -le "${#common_dns[@]}" ]; then
      index=$((choice - 1))
      IFS='|' read -r selected_ip selected_name <<<"${common_dns[$index]}"
      SELECTED_IPS+=("$selected_ip")
    else
      echo -e "${RED}忽略无效选择: $choice${RESET}"
    fi
  done
}

# 辅助函数 (支持IPv4和IPv6)
validate_ip() {
  local ip=$1
  # IPv4 check
  if [[ $ip =~ ^[0-9]+\.[0-9]+\.[0-9]+\.[0-9]+$ ]]; then
    return 0
  # IPv6 check (simplified regex)
  elif [[ $ip =~ ^([0-9a-fA-F]{0,4}:){1,7}[0-9a-fA-F]{0,4}$ ]]; then
    return 0
  else
    return 1
  fi
}

write_dns_config() {
  local dns_list=("$@")

  echo -e "${CYAN}正在重写 /etc/resolv.conf 以确保无多余DNS残留...${RESET}"

  # 1. 强制覆盖 /etc/resolv.conf
  # 尝试解锁文件
  chattr -i /etc/resolv.conf 2>/dev/null

  # [核心操作] 强制删除原文件/软链接
  rm -f /etc/resolv.conf

  # 创建新文件
  touch /etc/resolv.conf
  chmod 644 /etc/resolv.conf

  # 写入文件头
  cat >/etc/resolv.conf <<EOF
# Generated by VPS Management Script
# Last update: $(date)
EOF

  # 循环写入所有选中的 IP
  for ip in "${dns_list[@]}"; do
    echo "nameserver $ip" >>/etc/resolv.conf
  done

  echo -e "${GREEN}[√] /etc/resolv.conf 已重写为静态文件${RESET}"

  # 2. 如果检测到 systemd-resolved，也同步修改其配置
  if systemctl is-active systemd-resolved >/dev/null 2>&1; then
    echo -e "${CYAN}检测到 systemd-resolved，正在同步 Global 配置...${RESET}"

    local dns_string="${dns_list[*]}"

    # 彻底清理旧配置
    sed -i '/^DNS=/d' /etc/systemd/resolved.conf
    sed -i '/^#DNS=/d' /etc/systemd/resolved.conf
    sed -i '/^FallbackDNS=/d' /etc/systemd/resolved.conf
    sed -i '/^#FallbackDNS=/d' /etc/systemd/resolved.conf

    # 插入新配置
    if grep -q "\[Resolve\]" /etc/systemd/resolved.conf; then
      sed -i "/\[Resolve\]/a DNS=$dns_string" /etc/systemd/resolved.conf
      sed -i "/\[Resolve\]/a FallbackDNS=8.8.8.8 1.1.1.1" /etc/systemd/resolved.conf
    else
      echo "[Resolve]" >>/etc/systemd/resolved.conf
      echo "DNS=$dns_string" >>/etc/systemd/resolved.conf
      echo "FallbackDNS=8.8.8.8 1.1.1.1" >>/etc/systemd/resolved.conf
    fi

    systemctl restart systemd-resolved
    echo -e "${GREEN}[√] systemd-resolved 全局配置已更新${RESET}"
  fi

  # 3. 询问锁定
  echo -e "${YELLOW}是否锁定 DNS 配置文件以防止系统重启或 DHCP 再次修改?${RESET}"
  read -p "锁定 /etc/resolv.conf? [y/N]: " lock_choice
  if [[ "$lock_choice" =~ ^[Yy]$ ]]; then
    if command -v chattr >/dev/null 2>&1; then
      chattr +i /etc/resolv.conf
      echo -e "${GREEN}[√] 文件已锁定 (+i)${RESET}"
    else
      echo -e "${RED}[!] 错误：未找到 chattr 命令，无法锁定${RESET}"
    fi
  fi
}

verify_dns_config() {
  echo -e "\n${CYAN}>>> 验证DNS配置...${RESET}"

  if [ ! -f /etc/resolv.conf ]; then
    echo -e "${RED}错误: /etc/resolv.conf 文件不存在${RESET}"
    return 1
  fi

  local dns_servers=$(grep -E '^nameserver' /etc/resolv.conf | awk '{print $2}')
  if [ -z "$dns_servers" ]; then
    # 如果是 systemd-resolved，resolv.conf 可能是存根，需要检查 resolvectl
    if systemctl is-active systemd-resolved >/dev/null 2>&1; then
      echo -e "${GRAY}使用 systemd-resolved，尝试解析验证...${RESET}"
    else
      echo -e "${RED}错误: 未找到有效的DNS服务器配置${RESET}"
      return 1
    fi
  fi

  # 进行实际解析测试
  echo -ne "  正在测试解析 google.com ... "
  if nslookup -timeout=5 google.com >/dev/null 2>&1 || ping -c 1 -W 2 google.com >/dev/null 2>&1; then
    echo -e "${GREEN}成功${RESET}"
    return 0
  else
    echo -e "${RED}失败${RESET}"
    return 1
  fi
}

manage_ipv6() {
  echo -e "${CYAN}>>> 管理 IPv6 配置...${RESET}"

  # [容器适配] 检测并警告容器环境限制
  local is_container=false
  local ipv6_sysctl_writable=true
  
  if is_container_env; then
    is_container=true
    echo -e "${YELLOW}[!] 检测到容器环境，IPv6 配置可能受限${RESET}"
  fi
  
  # 检测 sysctl 是否可写
  if ! is_sysctl_writable "net.ipv6.conf.all.disable_ipv6"; then
    ipv6_sysctl_writable=false
    echo -e "${YELLOW}[!] IPv6 sysctl 参数不可修改 (只读)${RESET}"
  fi

  # 检测当前内核 IPv6 状态
  local ipv6_disabled_status=$(sysctl -n net.ipv6.conf.all.disable_ipv6 2>/dev/null)
  local has_ipv6_addr=$(ip -6 addr show | grep -v "::1" | grep -q "inet6" && echo "yes" || echo "no")

  echo -ne "当前状态: "
  if [ "$ipv6_disabled_status" = "1" ]; then
    echo -e "${RED}已禁用${RESET}"
  else
    if [ "$has_ipv6_addr" = "yes" ]; then
      echo -e "${GREEN}已开启 (且检测到IPv6地址)${RESET}"
    else
      echo -e "${YELLOW}已开启 (但未检测到IPv6地址，可能网络不支持)${RESET}"
    fi
  fi

  echo -e "\n${CYAN}请选择操作:${RESET}"
  echo -e "  ${GREEN}1${RESET}) 开启 IPv6"
  echo -e "  ${GREEN}2${RESET}) 关闭 IPv6 (永久生效)"
  echo -e "  ${YELLOW}0.${RESET} 取消/返回"

  read -p "请输入选项 [0-2]: " ipv6_choice

  local ver_major=$(get_debian_major_version)
  local sysctl_conf="/etc/sysctl.conf"
  [ "$ver_major" -ge 13 ] && sysctl_conf="/etc/sysctl.d/sysctl.conf"

  if [ ! -f "$sysctl_conf" ]; then
    mkdir -p "$(dirname "$sysctl_conf")"
    touch "$sysctl_conf"
  fi

  local disable_conf="/etc/sysctl.d/99-ipv6-disable.conf"
  local grub_file="/etc/default/grub"

  case $ipv6_choice in
  1)
    echo -e "${CYAN}>>> 正在开启 IPv6...${RESET}"

    local reboot_required=false

    # 1. GRUB 配置清理
    if [ -f "$grub_file" ]; then
      if grep -q "ipv6.disable=1" "$grub_file"; then
        echo -e "${CYAN}发现 GRUB 内核禁用参数，正在移除...${RESET}"
        sed -i 's/ipv6.disable=1//g' "$grub_file"
        sed -i 's/  / /g' "$grub_file" # 清理空格
        # [修复] GRUB 更新命令适配不同发行版
        if command -v update-grub >/dev/null 2>&1; then
          update-grub
        elif [ -f /boot/grub2/grub.cfg ]; then
          grub2-mkconfig -o /boot/grub2/grub.cfg
        elif [ -d /boot/efi/EFI ] && command -v grub2-mkconfig >/dev/null 2>&1; then
          local efi_grub=$(find /boot/efi/EFI -name "grub.cfg" 2>/dev/null | head -1)
          [ -n "$efi_grub" ] && grub2-mkconfig -o "$efi_grub"
        fi
        echo -e "${GREEN}[√] GRUB 配置已更新${RESET}"
        reboot_required=true
      fi
    fi

    # 2. 删除专门的禁用配置文件
    if [ -f "$disable_conf" ]; then
      rm -f "$disable_conf"
      echo -e "${YELLOW}[-] 已删除禁用配置文件: $disable_conf${RESET}"
    fi

    # 3. 清理主配置文件中的禁用项
    sed -i '/net.ipv6.conf.all.disable_ipv6/d' "$sysctl_conf"
    sed -i '/net.ipv6.conf.default.disable_ipv6/d' "$sysctl_conf"
    sed -i '/net.ipv6.conf.lo.disable_ipv6/d' "$sysctl_conf"

    # 4. 尝试动态启用
    if [ -d "/proc/sys/net/ipv6" ]; then
      sysctl -w net.ipv6.conf.all.disable_ipv6=0 >/dev/null 2>&1
      sysctl -w net.ipv6.conf.default.disable_ipv6=0 >/dev/null 2>&1
      sysctl -w net.ipv6.conf.lo.disable_ipv6=0 >/dev/null 2>&1
      sysctl -p >/dev/null 2>&1
      echo -e "${GREEN}[√] IPv6 参数已动态启用${RESET}"
    else
      echo -e "${YELLOW}[!] 检测到 IPv6 内核模块未加载${RESET}"
      reboot_required=true
    fi

    if [ "$reboot_required" = true ]; then
      echo -e "${RED}[!] 必须重启系统才能重新加载 IPv6 模块！${RESET}"
      read -p "是否立即重启? [y/N]: " restart_choice
      if [[ "$restart_choice" =~ ^[Yy]$ ]]; then
        reboot
      fi
    else
      echo -e "${GREEN}[√] IPv6 已开启${RESET}"
    fi
    ;;

  2)
    echo -e "${CYAN}>>> 正在关闭 IPv6...${RESET}"

    # 写入禁用配置到独立文件
    cat >"$disable_conf" <<EOF
# Disable IPv6
net.ipv6.conf.all.disable_ipv6 = 1
net.ipv6.conf.default.disable_ipv6 = 1
net.ipv6.conf.lo.disable_ipv6 = 1
EOF
    echo -e "${GREEN}[+] 已创建禁用配置: $disable_conf${RESET}"
    sysctl -p "$disable_conf" >/dev/null

    # GRUB 禁用
    if [ -f "$grub_file" ]; then
      echo -e "${CYAN}正在修改 GRUB 配置以彻底禁用 IPv6...${RESET}"
      if ! grep -q "ipv6.disable=1" "$grub_file"; then
        sed -i 's/GRUB_CMDLINE_LINUX_DEFAULT="/GRUB_CMDLINE_LINUX_DEFAULT="ipv6.disable=1 /' "$grub_file"
        sed -i 's/GRUB_CMDLINE_LINUX="/GRUB_CMDLINE_LINUX="ipv6.disable=1 /' "$grub_file"
        # [修复] GRUB 更新命令适配不同发行版
        if command -v update-grub >/dev/null 2>&1; then
          update-grub
        elif [ -f /boot/grub2/grub.cfg ]; then
          grub2-mkconfig -o /boot/grub2/grub.cfg
        elif [ -d /boot/efi/EFI ] && command -v grub2-mkconfig >/dev/null 2>&1; then
          local efi_grub=$(find /boot/efi/EFI -name "grub.cfg" 2>/dev/null | head -1)
          [ -n "$efi_grub" ] && grub2-mkconfig -o "$efi_grub"
        fi
        echo -e "${GREEN}[√] GRUB 配置已更新${RESET}"
      fi
    fi

    echo -e "${GREEN}[√] IPv6 已永久关闭${RESET}"
    echo -e "${YELLOW}注意: 建议重启系统以确保 GRUB 配置生效${RESET}"
    ;;

  0)
    SKIP_PAUSE=true
    return 0
    ;;

  *)
    echo -e "${RED}无效选项${RESET}"
    ;;
  esac
}

# ---------- [新增] 静态网络配置 (PVE/自建) ----------
# ---------- [新增] 静态网络配置 (支持 Debian系 与 RHEL系) ----------
configure_network_static() {
  install_deps "iproute2" "grep" "awk"

  while true; do
    clear
    echo -e "${CYAN}>>> 静态IP网络配置${RESET}"
    echo -e "${RED}警告：修改网络配置有风险，可能导致 SSH 断连！${RESET}"
    
    # [容器适配] 检测并警告容器环境
    if is_container_env; then
      echo -e "${YELLOW}━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━${RESET}"
      echo -e "${YELLOW}[!] 检测到容器环境 (NAT VPS/LXC/Docker)${RESET}"
      echo -e "${GRAY}  • 容器网络通常由宿主机或编排系统管理${RESET}"
      echo -e "${GRAY}  • 手动修改可能被覆盖或导致网络中断${RESET}"
      echo -e "${GRAY}  • 建议通过 VPS 控制面板配置网络${RESET}"
      echo -e "${YELLOW}━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━${RESET}"
    fi
    
    echo -e "${YELLOW}支持: Debian(interfaces) / RHEL(ifcfg)${RESET}"
    echo -e "${GRAY}对于 Netplan (Ubuntu 18.04+)，仅提供有限支持或警告。${RESET}"
    echo -e "${CYAN}--------------------------------------------------${RESET}"

    # 1. 检测网卡
    local interfaces
    interfaces=$(ip -o link show | awk -F': ' '{print $2}' | grep -vE "^(lo|docker|veth|cali|tun|wg|br)")

    if [ -z "$interfaces" ]; then
      echo -e "${RED}未检测到常规物理网卡，请尝试手动编辑。${RESET}"
      read -p "按 Enter 返回..."
      return 1
    fi

    local i=1
    local iface_list=()
    echo -e "请选择要配置的网卡:"
    for iface in $interfaces; do
      echo -e "  ${GREEN}$i${RESET}) $iface"
      iface_list+=("$iface")
      ((i++))
    done
    echo -e "  ${YELLOW}0.${RESET} 返回主菜单"

    echo -e "${CYAN}==================================================${RESET}"
    read -p "请输入选项: " if_idx

    if [[ "$if_idx" == "0" ]]; then return 0; fi

    if [[ ! "$if_idx" =~ ^[0-9]+$ ]] || [ "$if_idx" -lt 1 ] || [ "$if_idx" -gt "${#iface_list[@]}" ]; then
      echo -e "${RED}无效选择${RESET}"
      sleep 1
      continue
    fi

    local target_iface="${iface_list[$((if_idx - 1))]}"

    # --- 2. 获取信息 ---
    local curr_ip_cidr
    curr_ip_cidr=$(ip -4 addr show "$target_iface" | grep -oP '(?<=inet\s)\d+(\.\d+){3}/\d+' | head -1)
    local curr_ip="${curr_ip_cidr%/*}"
    local curr_gw
    curr_gw=$(ip route | grep default | grep "$target_iface" | awk '{print $3}' | head -1)
    local curr_dns
    curr_dns=$(grep -E '^nameserver' /etc/resolv.conf | awk '{print $2}' | tr '\n' ' ')

    echo -e "\n${BOLD}${CYAN}网卡 [${target_iface}] 当前状态:${RESET}"
    echo -e "  IP地址:   ${GREEN}${curr_ip:-未配置}${RESET} (CIDR: ${curr_ip_cidr})"
    echo -e "  默认网关: ${GREEN}${curr_gw:-未知}${RESET}"
    echo -e "  DNS服务器:${GREEN}${curr_dns:-未知}${RESET}"
    echo -e "${CYAN}--------------------------------------------------${RESET}"

    echo -e "请选择操作:"
    echo -e "  ${GREEN}1${RESET}) 修改静态 IP 配置"
    echo -e "  ${YELLOW}0${RESET}) 返回网卡列表"
    read -p "选项: " sub_choice

    if [[ "$sub_choice" == "0" ]]; then continue; fi
    if [[ "$sub_choice" != "1" ]]; then continue; fi

    # --- 3. 输入新配置 ---
    echo -e "\n${CYAN}>>> 请输入新的配置 (输入 0 返回):${RESET}"

    # IP
    while true; do
      read -p "IP 地址 (例如 192.168.1.10): " new_ip
      if [[ "$new_ip" == "0" ]]; then continue 2; fi
      if validate_ip "$new_ip"; then break; else echo -e "${RED}格式错误${RESET}"; fi
    done

    # Netmask
    while true; do
      read -p "子网掩码 (默认 255.255.255.0): " new_mask
      if [[ "$new_mask" == "0" ]]; then continue 2; fi
      [ -z "$new_mask" ] && new_mask="255.255.255.0"
      if validate_ip "$new_mask"; then break; else echo -e "${RED}格式错误${RESET}"; fi
    done

    # Gateway
    while true; do
      read -p "网关地址 (例如 192.168.1.1): " new_gw
      if [[ "$new_gw" == "0" ]]; then continue 2; fi
      if validate_ip "$new_gw"; then break; else echo -e "${RED}格式错误${RESET}"; fi
    done

    # DNS
    read -p "DNS服务器 (空格分隔, 默认 223.5.5.5): " new_dns
    if [[ "$new_dns" == "0" ]]; then continue 2; fi
    [ -z "$new_dns" ] && new_dns="223.5.5.5 8.8.8.8"

    # --- 4. 确认写入 ---
    echo -e "\n${YELLOW}即将写入以下配置:${RESET}"
    echo -e "Interface: $target_iface"
    echo -e "Address:   $new_ip"
    echo -e "Netmask:   $new_mask"
    echo -e "Gateway:   $new_gw"
    echo -e "DNS:       $new_dns"

    read -p "确认写入? [y/N]: " confirm_write
    if [[ ! "$confirm_write" =~ ^[Yy]$ ]]; then continue; fi

    # -------------------------------------------------------------
    # 分支处理：Debian/Ubuntu(legacy) vs RHEL/CentOS
    # -------------------------------------------------------------
    
    # 检测 Netplan (Ubuntu 18.04+)
    if command -v netplan >/dev/null 2>&1 && [ -d /etc/netplan ]; then
       echo -e "${RED}[!] 检测到 Netplan 环境。脚本暂不支持自动修改 Netplan YAML 文件，请手动修改 /etc/netplan/ 下的配置。${RESET}"
       read -p "按 Enter 返回..."
       continue
    fi

    if [[ "$PKG_MANAGER" == "apt" ]]; then
        # --- Debian / Old Ubuntu (/etc/network/interfaces) ---
        if [ ! -f /etc/network/interfaces ]; then
           echo -e "${RED}[!] /etc/network/interfaces 不存在，这可能是一个非标准系统。${RESET}"
           read -p "按 Enter 返回..."
           continue
        fi

        cp /etc/network/interfaces "/etc/network/interfaces.bak.$(date +%Y%m%d%H%M%S)"
        
        # 注释旧配置
        sed -i "s/^auto $target_iface/#auto $target_iface/g" /etc/network/interfaces
        sed -i "s/^iface $target_iface/#iface $target_iface/g" /etc/network/interfaces
        
        # 追加新配置
        echo -e "\n# Generated by VpsTool" >>/etc/network/interfaces
        echo "auto $target_iface" >>/etc/network/interfaces
        echo "iface $target_iface inet static" >>/etc/network/interfaces
        echo "    address $new_ip" >>/etc/network/interfaces
        echo "    netmask $new_mask" >>/etc/network/interfaces
        echo "    gateway $new_gw" >>/etc/network/interfaces
        echo "    dns-nameservers $new_dns" >>/etc/network/interfaces
        
        echo -e "${GREEN}[√] 配置已写入 /etc/network/interfaces${RESET}"
        
        # 重启网络
        read -p "立即重启网络? [y/N]: " r_net
        if [[ "$r_net" =~ ^[Yy]$ ]]; then
           if systemctl restart networking; then
              echo -e "${GREEN}[√] 网络已重启${RESET}"
           else
              echo -e "${RED}[!] 网络重启失败，请检查配置${RESET}"
           fi
        fi

    elif [[ "$PKG_MANAGER" == "yum" || "$PKG_MANAGER" == "dnf" ]]; then
        # --- RHEL / CentOS (/etc/sysconfig/network-scripts/ifcfg-*) ---
        local ifcfg="/etc/sysconfig/network-scripts/ifcfg-$target_iface"
        
        # 如果是 NetworkManager 管理，且没有 ifcfg 文件，可能需要 nmcli
        if [ ! -f "$ifcfg" ]; then
           echo -e "${YELLOW}[!] 未找到 $ifcfg，尝试使用 nmcli 配置...${RESET}"
           if command -v nmcli >/dev/null 2>&1; then
              # [修复] 将子网掩码转换为 CIDR 前缀
              local cidr_prefix="24"
              case "$new_mask" in
                "255.255.255.0")   cidr_prefix="24" ;;
                "255.255.0.0")     cidr_prefix="16" ;;
                "255.0.0.0")       cidr_prefix="8" ;;
                "255.255.255.128") cidr_prefix="25" ;;
                "255.255.255.192") cidr_prefix="26" ;;
                "255.255.255.224") cidr_prefix="27" ;;
                "255.255.255.240") cidr_prefix="28" ;;
                "255.255.255.248") cidr_prefix="29" ;;
                "255.255.255.252") cidr_prefix="30" ;;
                "255.255.254.0")   cidr_prefix="23" ;;
                "255.255.252.0")   cidr_prefix="22" ;;
                "255.255.248.0")   cidr_prefix="21" ;;
                "255.255.240.0")   cidr_prefix="20" ;;
                *) echo -e "${YELLOW}[!] 未知子网掩码，默认使用 /24${RESET}" ;;
              esac
              # 使用 nmcli 修改
              nmcli con mod "$target_iface" ipv4.addresses "$new_ip/$cidr_prefix" ipv4.gateway "$new_gw" ipv4.dns "${new_dns// /,}" ipv4.method manual
              echo -e "${GREEN}[√] nmcli 命令已执行${RESET}"
              nmcli con up "$target_iface"
           else
              echo -e "${RED}[!] 未找到 ifcfg 文件且无 nmcli 工具，无法配置。${RESET}"
           fi
        else
           # 修改 ifcfg 文件
           cp "$ifcfg" "${ifcfg}.bak.$(date +%Y%m%d%H%M%S)"
           
           # 使用 sed 修改关键项，如果不存在则追加
           # 辅助函数
           set_kv() {
             local k=$1
             local v=$2
             if grep -q "^$k=" "$ifcfg"; then
                sed -i "s|^$k=.*|$k=\"$v\"|g" "$ifcfg"
             else
                echo "$k=\"$v\"" >>"$ifcfg"
             fi
           }
           
           set_kv "BOOTPROTO" "static"
           set_kv "ONBOOT" "yes"
           set_kv "IPADDR" "$new_ip"
           set_kv "NETMASK" "$new_mask"
           set_kv "GATEWAY" "$new_gw"
           
           # DNS 处理
           local dns_idx=1
           for d in $new_dns; do
             set_kv "DNS$dns_idx" "$d"
             ((dns_idx++))
           done
           
           echo -e "${GREEN}[√] 配置已写入 $ifcfg${RESET}"
           
           read -p "立即重启网络? [y/N]: " r_net
           if [[ "$r_net" =~ ^[Yy]$ ]]; then
              if systemctl restart network 2>/dev/null || systemctl restart NetworkManager 2>/dev/null; then
                 echo -e "${GREEN}[√] 网络已重启${RESET}"
              else
                 echo -e "${RED}[!] 网络重启失败${RESET}"
              fi
           fi
        fi
    fi
    
    read -p "按 Enter 返回网卡列表..."
  done
}


# --- [8. 应用] 软件安装中心 (Docker/Shell) ---
# --- [8.1] Docker 基础环境管理 ---
ensure_docker() {
  if ! command -v docker >/dev/null 2>&1; then
    echo -e "${YELLOW}[!] 检测到系统未安装 Docker 环境。${RESET}"
    read -p "是否立即安装 Docker? [y/N]: " install_choice
    if [[ "$install_choice" =~ ^[Yy]$ ]]; then
      do_install_docker
      # 安装后再次检测
      if ! command -v docker >/dev/null 2>&1; then
        echo -e "${RED}[×] Docker 安装失败或已取消，无法继续部署容器。${RESET}"
        return 1
      fi
    else
      echo -e "${YELLOW}[!] 已取消操作，需要 Docker 环境才能继续。${RESET}"
      return 1
    fi
  fi
  # 确保 docker 服务运行
  systemctl start docker >/dev/null 2>&1
  return 0
}

# 独立安装 Docker 函数
do_install_docker() {
  if command -v docker >/dev/null 2>&1; then
    echo -e "${YELLOW}[!] Docker 已安装，无需重复操作。${RESET}"
    return 0
  fi

  echo -e "${CYAN}>>> 准备安装 Docker 环境 (官方源)...${RESET}"
  read -p "确认开始安装吗? [y/N]: " confirm
  if [[ ! "$confirm" =~ ^[Yy]$ ]]; then
    echo -e "${YELLOW}已取消${RESET}"
    return 0
  fi

  install_deps "curl"
  check_pm_lock || return 1
  if curl -fsSL https://get.docker.com | sh; then
    echo -e "${GREEN}[√] Docker 安装完成${RESET}"
    systemctl enable --now docker
    
    # [新增] 安装官方 Docker Compose
    echo -e "${CYAN}>>> 正在安装最新版 Docker Compose ...${RESET}"
    if curl -L "https://github.com/docker/compose/releases/latest/download/docker-compose-$(uname -s)-$(uname -m)" -o /usr/local/bin/docker-compose; then
        chmod +x /usr/local/bin/docker-compose
        echo -e "${GREEN}[√] Docker Compose 安装完成${RESET}"
    else
        echo -e "${RED}[!] Docker Compose 下载失败${RESET}"
    fi
  else
    echo -e "${RED}[×] Docker 安装失败，请检查网络${RESET}"
  fi
}

# 独立卸载 Docker 函数
do_uninstall_docker() {
  if ! command -v docker >/dev/null 2>&1; then
    echo -e "${YELLOW}[!] 系统未安装 Docker。${RESET}"
    return 0
  fi

  echo -e "${RED}>>> 警告: 即将卸载 Docker 环境及所有容器数据/镜像!${RESET}"
  read -p "确认彻底卸载吗? [y/N]: " confirm
  if [[ ! "$confirm" =~ ^[Yy]$ ]]; then
    echo -e "${YELLOW}已取消${RESET}"
    return 0
  fi

  echo -e "${CYAN}>>> 正在卸载 Docker...${RESET}"
  check_pm_lock || return 1
  
  if [[ "$PKG_MANAGER" == "apt" ]]; then
     $PKG_REMOVE docker-ce docker-ce-cli containerd.io docker-buildx-plugin docker-compose-plugin docker-ce-rootless-extras
  elif [[ "$PKG_MANAGER" == "dnf" || "$PKG_MANAGER" == "yum" ]]; then
     $PKG_REMOVE docker-ce docker-ce-cli containerd.io docker-buildx-plugin docker-compose-plugin docker-ce-rootless-extras
  fi
  
  rm -rf /var/lib/docker
  rm -rf /var/lib/containerd
  rm -f /usr/local/bin/docker-compose
  echo -e "${GREEN}[√] Docker 已卸载完成${RESET}"
}

# --- [8.2] 面板类应用安装 ---
install_xui() {
  echo -e "${CYAN}>>> 准备安装 X-UI 面板 (官方脚本)${RESET}"
  read -p "确认开始安装吗? [y/N]: " confirm
  if [[ ! "$confirm" =~ ^[Yy]$ ]]; then
    echo -e "${YELLOW}已取消${RESET}"
    return 0
  fi

  install_deps "curl"
  bash <(curl -Ls https://raw.githubusercontent.com/FranzKafkaYu/x-ui/master/install.sh)
}

install_3xui() {
  echo -e "${CYAN}>>> 准备安装 3X-UI 面板 (官方脚本)${RESET}"
  read -p "确认开始安装吗? [y/N]: " confirm
  if [[ ! "$confirm" =~ ^[Yy]$ ]]; then
    echo -e "${YELLOW}已取消${RESET}"
    return 0
  fi

  install_deps "curl"
  bash <(curl -Ls https://raw.githubusercontent.com/mhsanaei/3x-ui/master/install.sh)
}

install_portainer() {
  ensure_docker || return 1

  echo -e "${CYAN}>>> 准备安装 Portainer CE (可视化管理)${RESET}"
  read -p "确认开始部署吗? [y/N]: " confirm
  if [[ ! "$confirm" =~ ^[Yy]$ ]]; then
    echo -e "${YELLOW}已取消${RESET}"
    return 0
  fi

  echo -e "${CYAN}>>> 正在拉取并启动 Portainer...${RESET}"
  docker volume create portainer_data
  docker run -d \
    -p 8000:8000 \
    -p 9443:9443 \
    -p 9000:9000 \
    --name portainer \
    --restart=always \
    -v /var/run/docker.sock:/var/run/docker.sock \
    -v portainer_data:/data \
    portainer/portainer-ce:latest

  echo -e "${GREEN}[√] Portainer 已部署。${RESET}"
  echo -e "${YELLOW}访问地址 (HTTPS - 推荐): https://<IP>:9443${RESET}"
  echo -e "${YELLOW}访问地址 (HTTP): http://<IP>:9000${RESET}"
}

install_npm() {
  ensure_docker || return 1

  echo -e "${CYAN}>>> 准备安装 Nginx Proxy Manager${RESET}"
  read -p "确认开始部署吗? [y/N]: " confirm
  if [[ ! "$confirm" =~ ^[Yy]$ ]]; then
    echo -e "${YELLOW}已取消${RESET}"
    return 0
  fi

  local install_dir="/root/npm"
  mkdir -p "$install_dir"

  cat >"$install_dir/docker-compose.yml" <<EOF
services:
  app:
    image: 'jc21/nginx-proxy-manager:latest'
    restart: unless-stopped
    ports:
      - '80:80'
      - '81:81'
      - '443:443'
    volumes:
      - ./data:/data
      - ./letsencrypt:/etc/letsencrypt
EOF

  echo -e "${CYAN}正在启动容器...${RESET}"
  cd "$install_dir" && docker compose up -d

  if [ $? -eq 0 ]; then
    echo -e "${GREEN}[√] NPM 已部署。${RESET}"
    echo -e "${YELLOW}管理后台: http://<IP>:81 (admin@example.com / changeme)${RESET}"
  else
    echo -e "${RED}[×] 启动失败。${RESET}"
  fi
}

install_filecodebox() {
  ensure_docker || return 1

  echo -e "${CYAN}>>> 准备安装 FileCodeBox (文件快递柜)${RESET}"
  read -p "确认开始部署吗? [y/N]: " confirm
  if [[ ! "$confirm" =~ ^[Yy]$ ]]; then
    echo -e "${YELLOW}已取消${RESET}"
    return 0
  fi

  local data_dir="/opt/filecodebox"
  mkdir -p "$data_dir"

  docker run -d \
    --name filecodebox \
    --restart=always \
    -p 12345:12345 \
    -v "$data_dir":/app/data \
    lanol/filecodebox:latest

  echo -e "${GREEN}[√] FileCodeBox 已部署。${RESET}"
  echo -e "${YELLOW}访问地址: http://<IP>:12345${RESET}"
}

install_1panel() {
  echo -e "${CYAN}>>> 准备安装 1Panel (现代化运维面板)${RESET}"
  echo -e "${GRAY}注意: 1Panel 安装脚本会自动管理 Docker 环境。${RESET}"
  read -p "确认开始安装吗? [y/N]: " confirm
  if [[ ! "$confirm" =~ ^[Yy]$ ]]; then
    echo -e "${YELLOW}已取消${RESET}"
    return 0
  fi

  install_deps "curl"
  check_pm_lock || return 1
  bash -c "$(curl -sSL https://resource.fit2cloud.com/1panel/package/v2/quick_start.sh)"
  rm -f quick_start.sh
}

install_n8n() {
  ensure_docker || return 1

  echo -e "${CYAN}>>> 准备安装 n8n (自动化工作流)${RESET}"
  read -p "确认开始部署吗? [y/N]: " confirm
  if [[ ! "$confirm" =~ ^[Yy]$ ]]; then
    echo -e "${YELLOW}已取消${RESET}"
    return 0
  fi

  docker volume create n8n_data
  docker run -d \
    --name n8n \
    --restart unless-stopped \
    --shm-size 2g \
    -p 5678:5678 \
    -e N8N_SECURE_COOKIE=false \
    -v n8n_data:/home/node/.n8n \
    n8nio/n8n:latest

  echo -e "${GREEN}[√] n8n 已部署。${RESET}"
  echo -e "${YELLOW}访问地址: http://<IP>:5678${RESET}"
}

install_uptime_kuma() {
  ensure_docker || return 1

  echo -e "${CYAN}>>> 准备安装 Uptime Kuma (在线状态监控)${RESET}"
  read -p "确认开始部署吗? [y/N]: " confirm
  if [[ ! "$confirm" =~ ^[Yy]$ ]]; then
    echo -e "${YELLOW}已取消${RESET}"
    return 0
  fi

  docker run -d \
    --restart=always \
    -p 3001:3001 \
    -v uptime-kuma:/app/data \
    --name uptime-kuma \
    louislam/uptime-kuma:1

  echo -e "${GREEN}[√] Uptime Kuma 已部署。${RESET}"
  echo -e "${YELLOW}访问地址: http://<IP>:3001${RESET}"
}

install_netdata() {
  ensure_docker || return 1

  echo -e "${CYAN}>>> 准备安装 Netdata (实时性能监控)${RESET}"
  read -p "确认开始部署吗? [y/N]: " confirm
  if [[ ! "$confirm" =~ ^[Yy]$ ]]; then
    echo -e "${YELLOW}已取消${RESET}"
    return 0
  fi

  docker run -d --name=netdata \
    -p 19999:19999 \
    -v netdataconfig:/etc/netdata \
    -v netdatalib:/var/lib/netdata \
    -v netdatacache:/var/cache/netdata \
    -v /etc/passwd:/host/etc/passwd:ro \
    -v /etc/group:/host/etc/group:ro \
    -v /proc:/host/proc:ro \
    -v /sys:/host/sys:ro \
    -v /etc/os-release:/host/etc/os-release:ro \
    --restart unless-stopped \
    --cap-add SYS_PTRACE \
    --security-opt apparmor=unconfined \
    netdata/netdata

  echo -e "${GREEN}[√] Netdata 已部署。${RESET}"
  echo -e "${YELLOW}访问地址: http://<IP>:19999${RESET}"
}

install_prom_grafana() {
  ensure_docker || return 1

  echo -e "${CYAN}>>> 准备安装 Prometheus + Grafana${RESET}"
  read -p "确认开始部署吗? [y/N]: " confirm
  if [[ ! "$confirm" =~ ^[Yy]$ ]]; then
    echo -e "${YELLOW}已取消${RESET}"
    return 0
  fi

  local install_dir="/opt/monitoring"
  mkdir -p "$install_dir/prometheus"
  mkdir -p "$install_dir/grafana/provisioning/datasources"

  # 配置文件生成逻辑保持不变，此处省略详细生成过程以节省篇幅，实际运行时会执行
  cat >"$install_dir/prometheus/prometheus.yml" <<EOF
global:
  scrape_interval: 15s
scrape_configs:
  - job_name: 'prometheus'
    static_configs:
      - targets: ['localhost:9090']
EOF

  cat >"$install_dir/grafana/provisioning/datasources/datasource.yml" <<EOF
apiVersion: 1
datasources:
  - name: Prometheus
    type: prometheus
    access: proxy
    url: http://prometheus:9090
    isDefault: true
EOF

  cat >"$install_dir/docker-compose.yml" <<EOF
services:
  prometheus:
    image: prom/prometheus
    container_name: prometheus
    restart: unless-stopped
    volumes:
      - ./prometheus/prometheus.yml:/etc/prometheus/prometheus.yml
    ports:
      - 9090:9090
    networks:
      - monitoring
  grafana:
    image: grafana/grafana
    container_name: grafana
    restart: unless-stopped
    ports:
      - 3000:3000
    volumes:
      - grafana_data:/var/lib/grafana
      - ./grafana/provisioning:/etc/grafana/provisioning
    depends_on:
      - prometheus
    networks:
      - monitoring
volumes:
  grafana_data:
networks:
  monitoring:
EOF

  echo -e "${CYAN}正在启动监控容器...${RESET}"
  cd "$install_dir" && docker compose up -d

  if [ $? -eq 0 ]; then
    echo -e "${GREEN}[√] 监控平台已部署。${RESET}"
    echo -e "${YELLOW}Grafana: http://<IP>:3000 (admin/admin)${RESET}"
  else
    echo -e "${RED}[×] 启动失败。${RESET}"
  fi
}

software_hub() {
  while true; do
    clear
    echo -e "${BOLD}${GREEN}📦 常用软件安装中心 (Docker/Panel)${RESET}"
    echo -e "${CYAN}==================================================${RESET}"

    # 简易检测 Docker 状态
    if command -v docker >/dev/null 2>&1; then
      echo -e "Docker状态: ${GREEN}已安装 $(docker --version | awk '{print $3}' | sed 's/,//')${RESET}"
    else
      echo -e "Docker状态: ${RED}未安装${RESET}"
    fi

    # 检测 Docker Compose 状态
    if command -v docker-compose >/dev/null 2>&1; then
      echo -e "Compose状态: ${GREEN}已安装 $(docker-compose version --short 2>/dev/null || echo '未知')${RESET}"
    else
      echo -e "Compose状态: ${RED}未安装${RESET}"
    fi
    echo -e "${CYAN}--------------------------------------------------${RESET}"

    echo -e "${CYAN}--- 环境管理 ---${RESET}"
    echo -e "${YELLOW}  1.${RESET} 安装 Docker 环境"
    echo -e "${YELLOW}  2.${RESET} 卸载 Docker 环境"
    echo -e "${CYAN}--- 面板类 (Script) ---${RESET}"
    echo -e "${YELLOW}  3.${RESET} 安装 X-UI 面板"
    echo -e "${YELLOW}  4.${RESET} 安装 3X-UI 面板"
    echo -e "${CYAN}--- 容器类 (Docker) ---${RESET}"
    echo -e "${YELLOW}  5.${RESET} 安装 Portainer (可视化容器管理)"
    echo -e "${YELLOW}  6.${RESET} 安装 Nginx Proxy Manager (反代神器)"
    echo -e "${YELLOW}  7.${RESET} 安装 FileCodeBox (文件快递柜)"
    echo -e "${YELLOW}  8.${RESET} 安装 1Panel (现代化运维面板)"
    echo -e "${YELLOW}  9.${RESET} 安装 N8n (工作流自动化)"
    echo -e "${CYAN}--- 监控类 (Monitoring) ---${RESET}"
    echo -e "${YELLOW} 10.${RESET} 安装 Uptime Kuma (在线状态监控)"
    echo -e "${YELLOW} 11.${RESET} 安装 Netdata (实时性能监控)"
    echo -e "${YELLOW} 12.${RESET} 安装 Prometheus + Grafana (可视化平台)"
    echo -e "${YELLOW}  0.${RESET} 返回主菜单"
    echo -e "${CYAN}==================================================${RESET}"

    read -p "请输入选项: " sw_choice
    case $sw_choice in
    1) do_install_docker ;;
    2) do_uninstall_docker ;;
    3) install_xui ;;
    4) install_3xui ;;
    5) install_portainer ;;
    6) install_npm ;;
    7) install_filecodebox ;;
    8) install_1panel ;;
    9) install_n8n ;;
    10) install_uptime_kuma ;;
    11) install_netdata ;;
    12) install_prom_grafana ;;
    0)
      SKIP_PAUSE=true
      return 0
      ;;
    *) echo -e "${RED}无效选项${RESET}" ;;
    esac

    # 子菜单操作完后暂停，方便看日志
    if [ "$SKIP_PAUSE" = false ]; then
      echo -e ""
      read -p "按 Enter 继续..."
    else
      SKIP_PAUSE=false
    fi
  done
}

stream_test() {
  echo -e "${CYAN}>>> 准备运行流媒体解锁测试${RESET}"
  read -p "确认开始测试吗? [y/N]: " confirm
  if [[ ! "$confirm" =~ ^[Yy]$ ]]; then
    echo -e "${YELLOW}操作已取消${RESET}"
    SKIP_PAUSE=true
    return 0
  fi
  install_deps "curl"
  local temp
  temp=$(mktemp -d)
  echo -e "${CYAN}>>> 开始流媒体解锁测试...${RESET}"
  cd "$temp" && bash <(curl -Ls https://Check.Place) -I
  cd - >/dev/null
  rm -rf "$temp" 2>/dev/null
  echo -e "${GREEN}[√] 流媒体测试完成${RESET}"
}

net_test() {
  echo -e "${CYAN}>>> 准备运行网络质量测试${RESET}"
  read -p "确认开始测试吗? [y/N]: " confirm
  if [[ ! "$confirm" =~ ^[Yy]$ ]]; then
    echo -e "${YELLOW}操作已取消${RESET}"
    SKIP_PAUSE=true
    return 0
  fi
  install_deps "curl"
  local temp
  temp=$(mktemp -d)
  echo -e "${CYAN}>>> 开始网络质量测试...${RESET}"
  cd "$temp" && bash <(curl -Ls https://Check.Place) -N
  cd - >/dev/null
  rm -rf "$temp" 2>/dev/null
  echo -e "${GREEN}[√] 网络质量测试完成${RESET}"
}

full_test() {
  echo -e "${CYAN}>>> 准备运行融合怪全面测试${RESET}"
  read -p "确认开始测试吗? [y/N]: " confirm
  if [[ ! "$confirm" =~ ^[Yy]$ ]]; then
    echo -e "${YELLOW}操作已取消${RESET}"
    SKIP_PAUSE=true
    return 0
  fi
  install_deps "curl"
  
  # [重要] 融合怪包含 fio 磁盘测试，必须在真实磁盘分区运行
  local temp
  temp=$(mktemp -d -p /root)
  
  echo -e "${CYAN}>>> 开始融合怪全面测试...${RESET}"
  cd "$temp" && curl -L https://gitlab.com/spiritysdx/za/-/raw/main/ecs.sh -o ecs.sh && chmod +x ecs.sh && bash ecs.sh
  cd - >/dev/null
  rm -rf "$temp" 2>/dev/null
  echo -e "${GREEN}[√] 融合怪测试完成${RESET}"
}

benchmark() {
  echo -e "${CYAN}>>> 准备运行服务器性能测试${RESET}"
  read -p "确认开始测试吗? [y/N]: " confirm
  if [[ ! "$confirm" =~ ^[Yy]$ ]]; then
    echo -e "${YELLOW}操作已取消${RESET}"
    SKIP_PAUSE=true
    return 0
  fi
  install_deps "curl"
  
  # [重要] yabs.sh 的 fio 测试会检测当前工作目录所在的分区
  # 必须在真实磁盘分区(如 /root)下运行，而非 /tmp (通常是 tmpfs 内存文件系统)
  # 否则 fio 测试结果将是内存速度而非磁盘速度，导致结果偏差巨大
  local temp
  temp=$(mktemp -d -p /root)
  
  echo -e "${CYAN}>>> 开始服务器性能测试...${RESET}"
  cd "$temp" && curl -sL yabs.sh -o yabs.sh && chmod +x yabs.sh && bash yabs.sh
  cd - >/dev/null
  
  # 清理临时目录
  rm -rf "$temp" 2>/dev/null
  
  echo -e "${GREEN}[√] 性能测试完成${RESET}"
}

# --- [9. 系统] 深度清理与优化 ---
system_cleanup() {
  echo -e "${CYAN}>>> 准备执行深度系统清理${RESET}"
  echo -e "${YELLOW}将清理: 日志、软件包缓存、孤立包、Docker缓存、临时文件等。${RESET}"
  read -p "确认执行清理吗? [y/N]: " confirm
  if [[ ! "$confirm" =~ ^[Yy]$ ]]; then
    echo -e "${YELLOW}操作已取消${RESET}"
    SKIP_PAUSE=true
    return 0
  fi
  echo -e "${BOLD}${CYAN}>>> 正在执行深度系统清理...${RESET}"

  # 初始化总清理大小 (KB)
  total_freed_kb=0

  # 辅助函数：获取目录大小 (KB)
  get_dir_size_kb() {
    local path="$1"
    if [ -d "$path" ]; then
      du -sk "$path" 2>/dev/null | awk '{print $1}'
    else
      echo 0
    fi
  }

  # 辅助函数：格式化大小显示 (KB -> Human Readable)
  format_size() {
    local kb=$1
    if [ "$kb" -lt 1024 ]; then
      echo "${kb}KB"
    elif [ "$kb" -lt 1048576 ]; then
      awk -v k="$kb" 'BEGIN{printf "%.2fMB", k/1024}'
    else
      awk -v k="$kb" 'BEGIN{printf "%.2fGB", k/1024/1024}'
    fi
  }

  # --- [清理 1/7] 包管理器缓存 ---
  echo -e "${YELLOW}[1/7] 清理软件包缓存与残留...${RESET}"
  check_pm_lock || return 1
  
  # [修复] 使用 清理前-清理后 差值计算真实释放量
  local pkg_freed=0
  if [[ "$PKG_MANAGER" == "apt" ]]; then
     local cache_path="/var/cache/apt/archives"
     local size_before=$(get_dir_size_kb "$cache_path")
     $PKG_CLEAN >/dev/null 2>&1
     local size_after=$(get_dir_size_kb "$cache_path")
     pkg_freed=$((size_before - size_after))
     [ "$pkg_freed" -lt 0 ] && pkg_freed=0
  elif [[ "$PKG_MANAGER" == "dnf" || "$PKG_MANAGER" == "yum" ]]; then
     local cache_path="/var/cache/yum"
     [ "$PKG_MANAGER" == "dnf" ] && cache_path="/var/cache/dnf"
     local size_before=$(get_dir_size_kb "$cache_path")
     $PKG_CLEAN >/dev/null 2>&1
     local size_after=$(get_dir_size_kb "$cache_path")
     pkg_freed=$((size_before - size_after))
     [ "$pkg_freed" -lt 0 ] && pkg_freed=0
  fi
  
  # 其他通用系统临时目录 (同样使用差值计算)
  sys_dirs=("/var/tmp" "/var/crash")
  sys_cleaned=0
  for dir in "${sys_dirs[@]}"; do
    local dir_before=$(get_dir_size_kb "$dir")
    rm -rf "${dir:?}"/* 2>/dev/null
    local dir_after=$(get_dir_size_kb "$dir")
    local dir_freed=$((dir_before - dir_after))
    [ "$dir_freed" -lt 0 ] && dir_freed=0
    sys_cleaned=$((sys_cleaned + dir_freed))
  done
  
  # 合计本项
  step1_total=$((pkg_freed + sys_cleaned))
  total_freed_kb=$((total_freed_kb + step1_total))
  echo -e "  ${GREEN}✓ 包管理器及临时文件已清理 (释放: $(format_size $step1_total))${RESET}"

  # --- [清理 2/7] 残留配置 (仅Debian系) ---
  if [[ "$PKG_MANAGER" == "apt" ]]; then
      echo -e "${YELLOW}[2/7] 扫描已卸载软件的残留配置(RC)...${RESET}"
      rc_count=$(dpkg -l | grep "^rc" | wc -l)
      if [ "$rc_count" -gt 0 ]; then
        dpkg -l | grep "^rc" | awk '{print $2}' | xargs -r apt-get -y purge >/dev/null 2>&1
        echo -e "  ${GREEN}✓ 清理了 $rc_count 个残留配置${RESET}"
      else
        echo -e "  ${GRAY}✓ 无残留配置需清理${RESET}"
      fi
  else
      echo -e "${YELLOW}[2/7] 残留配置清理 (非APT系统跳过)${RESET}"
  fi

  # --- [清理 3/7] 日志文件深度清理 ---
  echo -e "${YELLOW}[3/7] 深度清理系统日志...${RESET}"
  log_freed=0

  # 3.1 截断大日志 (>50MB) - 使用 Delta 计算
  # [说明] 使用 truncate 而非删除，可保持文件句柄，避免影响正在运行的服务
  large_logs=$(find /var/log -type f -name "*.log" -size +50M 2>/dev/null)
  if [ -n "$large_logs" ]; then
    size_before=$(find /var/log -type f -name "*.log" -size +50M -print0 | xargs -0 du -ck 2>/dev/null | tail -1 | awk '{print $1}')
    find /var/log -type f -name "*.log" -size +50M -exec truncate -s 0 {} \; 2>/dev/null
    size_after=$(find /var/log -type f -name "*.log" -size +50M -print0 | xargs -0 du -ck 2>/dev/null | tail -1 | awk '{print $1}')
    
    # 防止空值运算
    : ${size_before:=0} ${size_after:=0}
    
    real_freed=$((size_before - size_after))
    if [ "$real_freed" -gt 0 ]; then
       log_freed=$((log_freed + real_freed))
       echo -e "  ${GREEN}✓ 已截断过大的活动日志文件 (释放: $(format_size $real_freed))${RESET}"
    else
       echo -e "  ${YELLOW}! 大日志截断失败或无需释放${RESET}"
    fi
  fi

  # 3.2 Systemd Journal 优化
  if command -v journalctl >/dev/null 2>&1; then
    # Journalctl vacuum 实际上很难精确计算释放量，因为它管理的是自己的二进制格式
    # 通常 vacuum 会提示 freed amount，但捕获解析比较繁琐。这里保留定性提示。
    journalctl --vacuum-time=1d >/dev/null 2>&1
    echo -e "  ${GREEN}✓ Systemd 日志已优化 (保留最近1天)${RESET}"
  fi

  # 3.3 归档日志清理 (*.gz, *.old) - 使用 Delta 计算
  # 先计算目标文件列表
  target_files=$(find /var/log -type f \( -name "*.gz" -o -name "*.old" -o -name "*.log.*" \))
  if [ -n "$target_files" ]; then
    size_before=$(echo "$target_files" | tr '\n' '\0' | xargs -0 du -ck 2>/dev/null | tail -1 | awk '{print $1}')
    
    # 执行删除
    find /var/log -type f \( -name "*.gz" -o -name "*.old" -o -name "*.log.*" \) -delete 2>/dev/null
    
    # 再次检查剩余文件 (理论上应为空，或者是删不掉的文件)
    files_remaining=$(find /var/log -type f \( -name "*.gz" -o -name "*.old" -o -name "*.log.*" \))
    if [ -n "$files_remaining" ]; then
        size_after=$(echo "$files_remaining" | tr '\n' '\0' | xargs -0 du -ck 2>/dev/null | tail -1 | awk '{print $1}')
    else
        size_after=0
    fi
    
    : ${size_before:=0} ${size_after:=0}
    real_freed=$((size_before - size_after))
    
    if [ "$real_freed" -gt 0 ]; then
        log_freed=$((log_freed + real_freed)) 
        echo -e "  ${GREEN}✓ 归档旧日志已清理 (释放: $(format_size $real_freed))${RESET}"
    elif [ "$size_before" -gt 0 ]; then
        echo -e "  ${RED}! 归档日志清理失败 (权限不足或文件被锁定)${RESET}"
    fi
  fi

  # 3.4 清理/tmp (24小时前) - 使用 Delta 计算
  target_tmp=$(find /tmp -type f -mtime +1 2>/dev/null)
  if [ -n "$target_tmp" ]; then
      size_before=$(echo "$target_tmp" | tr '\n' '\0' | xargs -0 du -ck 2>/dev/null | tail -1 | awk '{print $1}')
      
      find /tmp -type f -mtime +1 -delete 2>/dev/null
      find /tmp -type d -empty -delete 2>/dev/null
      
      tmp_remaining=$(find /tmp -type f -mtime +1 2>/dev/null)
      if [ -n "$tmp_remaining" ]; then
         size_after=$(echo "$tmp_remaining" | tr '\n' '\0' | xargs -0 du -ck 2>/dev/null | tail -1 | awk '{print $1}')
      else
         size_after=0
      fi
      
      : ${size_before:=0} ${size_after:=0}
      real_freed=$((size_before - size_after))
      
      if [ "$real_freed" -gt 0 ]; then
         log_freed=$((log_freed + real_freed))
      fi
  fi

  total_freed_kb=$((total_freed_kb + log_freed))
  echo -e "  ${GREEN}✓ 日志与临时文件清理完成 (释放: $(format_size $log_freed))${RESET}"

  # --- [清理 4/7] Snap清理  ---
  if command -v snap >/dev/null 2>&1; then
    echo -e "${YELLOW}[4/7] 正在清理 Snap 旧版本缓存...${RESET}"
    snap_before=$(get_dir_size_kb "/var/lib/snapd/snaps")
    snap set system refresh.retain=2 2>/dev/null
    snap list --all | awk '/disabled/{print $1, $3}' |
      while read snapname revision; do
        snap remove "$snapname" --revision="$revision" >/dev/null 2>&1
      done
    snap_after=$(get_dir_size_kb "/var/lib/snapd/snaps")
    snap_freed=$((snap_before - snap_after))
    if [ "$snap_freed" -lt 0 ]; then snap_freed=0; fi
    total_freed_kb=$((total_freed_kb + snap_freed))
    echo -e "  ${GREEN}✓ Snap 缓存清理完成 (释放: $(format_size $snap_freed))${RESET}"
  else
    echo -e "${YELLOW}[4/7] Snap 未安装，跳过${RESET}"
  fi

  # --- [清理 5/7] 语言环境缓存  ---
  echo -e "${YELLOW}[5/7] 检查编程语言与开发缓存...${RESET}"
  lang_freed=0

  cache_checks=(
    "NPM|npm|$HOME/.npm"
    "Yarn|yarn|$HOME/.cache/yarn"
    "Pip|pip|$HOME/.cache/pip"
    "Go|go|$HOME/go/pkg/mod"
  )

  for check in "${cache_checks[@]}"; do
    IFS='|' read -r name cmd path <<<"$check"
    if command -v "$cmd" >/dev/null 2>&1 && [ -d "$path" ]; then
      size=$(get_dir_size_kb "$path")
      if [ "$size" -gt 0 ]; then
        lang_freed=$((lang_freed + size))
        rm -rf "${path:?}"/* 2>/dev/null
        echo -e "  ${GREEN}✓ 清理 $name 缓存 ($(format_size $size))${RESET}"
      fi
    fi
  done

  total_freed_kb=$((total_freed_kb + lang_freed))
  if [ "$lang_freed" -eq 0 ]; then
    echo -e "  ${GRAY}✓ 无开发环境缓存需清理${RESET}"
  fi

  # --- [清理 6/7] 用户级缓存  ---
  echo -e "${YELLOW}[6/7] 清理用户缩略图缓存...${RESET}"
  user_freed=0
  for user_home in /home/*; do
    [ -d "$user_home" ] || continue
    cache_dir="$user_home/.cache"

    if [ -d "$cache_dir" ]; then
      s1=$(get_dir_size_kb "$cache_dir")
      user_freed=$((user_freed + s1))
      rm -rf "$cache_dir"/* 2>/dev/null
    fi
  done
  # root 的缓存
  if [ -d "/root/.cache" ]; then
    s_root=$(get_dir_size_kb "/root/.cache")
    user_freed=$((user_freed + s_root))
    rm -rf "/root/.cache"/* 2>/dev/null
  fi

  total_freed_kb=$((total_freed_kb + user_freed))
  echo -e "  ${GREEN}✓ 用户缓存清理完成 (释放: $(format_size $user_freed))${RESET}"
  
  # --- [清理 7/7] Docker 构建缓存 ---
  echo -e "${YELLOW}[7/7] 检查 Docker 构建缓存...${RESET}"
  if command -v docker >/dev/null 2>&1 && systemctl is-active docker >/dev/null 2>&1; then
     # 辅助函数：将 Docker 输出的大小转换为 KB
     parse_size_to_kb() {
       local size_str="$1"
       [ -z "$size_str" ] && echo 0 && return
       local num=$(echo "$size_str" | grep -oE '[0-9]+\.?[0-9]*')
       local unit=$(echo "$size_str" | grep -oE '[A-Za-z]+')
       [ -z "$num" ] && echo 0 && return
       case "$unit" in
         B|b|Bytes)   awk -v n="$num" 'BEGIN{printf "%.0f", n/1024}' ;;
         KB|kB|KiB)   awk -v n="$num" 'BEGIN{printf "%.0f", n}' ;;
         MB|mB|MiB)   awk -v n="$num" 'BEGIN{printf "%.0f", n*1024}' ;;
         GB|gB|GiB)   awk -v n="$num" 'BEGIN{printf "%.0f", n*1024*1024}' ;;
         *)           awk -v n="$num" 'BEGIN{printf "%.0f", n}' ;;
       esac
     }
     
     local docker_freed=0
     
     echo -e "  ${CYAN}正在执行 docker builder prune (构建缓存)...${RESET}"
     builder_out=$(docker builder prune --all --force 2>&1)
     builder_reclaimed=$(echo "$builder_out" | grep "Total reclaimed space" | awk -F': ' '{print $2}')
     if [ -n "$builder_reclaimed" ]; then
        echo -e "    -> 释放: ${GREEN}${builder_reclaimed}${RESET}"
        docker_freed=$((docker_freed + $(parse_size_to_kb "$builder_reclaimed")))
     fi
     
     echo -e "  ${CYAN}正在执行 docker image prune (悬空镜像)...${RESET}"
     image_out=$(docker image prune --force 2>&1)
     image_reclaimed=$(echo "$image_out" | grep "Total reclaimed space" | awk -F': ' '{print $2}')
     if [ -n "$image_reclaimed" ]; then
        echo -e "    -> 释放: ${GREEN}${image_reclaimed}${RESET}"
        docker_freed=$((docker_freed + $(parse_size_to_kb "$image_reclaimed")))
     fi
     
     total_freed_kb=$((total_freed_kb + docker_freed))
     echo -e "  ${GREEN}✓ Docker 清理完成${RESET}"
  else
     echo -e "  ${GRAY}✓ Docker 未运行或未安装，跳过${RESET}"
  fi

  # --- 总结报告 ---
  echo -e "${BOLD}${CYAN}--------------------------------------------------${RESET}"
  echo -e "${BOLD}${GREEN}🎉 系统清理全部完成！${RESET}"
  echo -e "${BOLD}共计释放空间: ${YELLOW}$(format_size $total_freed_kb)${RESET}"

  df -h / | tail -1 | awk -v G="${GREEN}" -v R="${RESET}" '{printf "%s当前磁盘剩余空间: %s (使用率: %s)%s\n", G, $4, $5, R}'
  echo -e "${BOLD}${CYAN}--------------------------------------------------${RESET}"
}

# ---------- Fail2Ban 管理 (逻辑闭环: 白名单子菜单 + 状态全显 + 交互优化) ----------
manage_fail2ban() {
  # [逻辑] 检测 Fail2Ban 是否已安装 (使用包管理器判断避免残留误判)
  check_f2b_installed() {
    if [[ "$PKG_MANAGER" == "apt" ]]; then
      dpkg -l fail2ban 2>/dev/null | grep -q "^ii" && return 0
    elif [[ "$PKG_MANAGER" == "dnf" || "$PKG_MANAGER" == "yum" ]]; then
      rpm -q fail2ban >/dev/null 2>&1 && return 0
    fi
    # 兜底：检查服务单元文件是否存在
    systemctl cat fail2ban >/dev/null 2>&1 && return 0
    return 1
  }

  # [逻辑] 检测服务守护进程状态
  check_f2b_running() {
    check_f2b_installed || return 1
    systemctl is-active fail2ban >/dev/null 2>&1
  }

  # [逻辑] 检测特定 Jail 运行状态
  check_jail_status() {
    local jail_name=$1
    if check_f2b_running; then
      if fail2ban-client status "$jail_name" >/dev/null 2>&1; then return 0; fi
    fi
    return 1
  }

  # [逻辑] 配置文件写入函数
  set_jail_config() {
    local jail=$1
    local state=$2
    local file="/etc/fail2ban/jail.local"
    [ ! -f "$file" ] && { cp /etc/fail2ban/jail.conf "$file" 2>/dev/null || touch "$file"; }
    # 确保段落存在
    if ! grep -q "^\[$jail\]" "$file"; then echo -e "\n[$jail]" >>"$file"; fi
    # 修改或添加 enabled
    local has_key=$(sed -n "/^\[$jail\]/,/^\[/p" "$file" | grep "enabled")
    if [ -n "$has_key" ]; then
      sed -i "/^\[$jail\]/,/^\[/{s/enabled[[:space:]]*=.*/enabled = $state/}" "$file"
    else
      sed -i "/^\[$jail\]/a enabled = $state" "$file"
    fi
  }

  # [逻辑] 补全缺失参数
  ensure_jail_params() {
    local jail=$1
    local file="/etc/fail2ban/jail.local"
    
    # [修复] 根据系统类型选择正确的日志路径
    local ssh_logpath="/var/log/auth.log"
    if [[ "$OS_ID" == "centos" || "$OS_ID" == "rhel" || "$OS_ID" == "fedora" || "$OS_ID" == "almalinux" || "$OS_ID" == "rockylinux" || "$OS_ID" == "anolis" ]]; then
      ssh_logpath="/var/log/secure"
    fi
    
    case $jail in
    "sshd")
      if ! sed -n "/^\[sshd\]/,/^\[/p" "$file" | grep -q "logpath"; then
        sed -i "/^\[sshd\]/a logpath = $ssh_logpath\nport = ssh\nmaxretry = 5\nbantime = 10m\nfilter = sshd" "$file"
      fi
      ;;
    "recidive")
      if ! sed -n "/^\[recidive\]/,/^\[/p" "$file" | grep -q "banaction"; then
        sed -i "/^\[recidive\]/a logpath = /var/log/fail2ban.log\nbanaction = iptables-allports\nbantime = 1w\nfindtime = 1d\nmaxretry = 3" "$file"
      fi
      ;;
    esac
  }

  while true; do
    clear

    # --- 状态检测逻辑 (区分: 未安装 / 未运行 / 运行中) ---
    local is_installed=true
    if ! check_f2b_installed; then
      # 未安装
      f2b_state="${GRAY}未安装${RESET}"
      is_running=false
      is_installed=false
      ssh_display="${GRAY}○${RESET} 开启 SSH 保护 (需先安装)"
      rec_display="${GRAY}○${RESET} 开启 顽固监狱 (需先安装)"
    elif check_f2b_running; then
      # 运行中
      f2b_state="${GREEN}运行中 (Active)${RESET}"
      is_running=true

      # SSH 保护状态
      if check_jail_status "sshd"; then
        ssh_display="${GREEN}●${RESET} 关闭 SSH 保护"
        ssh_status="on"
      else
        ssh_display="${GRAY}○${RESET} 开启 SSH 保护"
        ssh_status="off"
      fi

      # 顽固监狱状态
      if check_jail_status "recidive"; then
        rec_display="${GREEN}●${RESET} 关闭 顽固监狱 (Recidive)"
        rec_status="on"
      else
        rec_display="${GRAY}○${RESET} 开启 顽固监狱 (Recidive)"
        rec_status="off"
      fi
    else
      # 已安装但未运行
      f2b_state="${YELLOW}未运行${RESET}"
      is_running=false
      ssh_display="${GRAY}○${RESET} 开启 SSH 保护 (需启动服务)"
      rec_display="${GRAY}○${RESET} 开启 顽固监狱 (需启动服务)"
    fi

    db_file="/var/lib/fail2ban/fail2ban.sqlite3"
    db_size="N/A"
    [ -f "$db_file" ] && db_size=$(ls -lh "$db_file" | awk '{print $5}')

    # --- 菜单显示 ---
    echo -e "${BOLD}${CYAN}🛡️  Fail2Ban 防爆破高级管理${RESET}"
    echo -e "${CYAN}==================================================${RESET}"
    echo -e "Fail2Ban状态: $f2b_state"
    echo -e "数据库占用: ${YELLOW}$db_size${RESET}"
    echo -e "${CYAN}--------------------------------------------------${RESET}"

    if [ "$is_installed" = false ]; then
      echo -e "${YELLOW}  1.${RESET} 安装 Fail2Ban"
      echo -e "${GRAY}  2. 停用服务 (需先安装)${RESET}"
    elif [ "$is_running" = true ]; then
      echo -e "${GREEN}  1.${RESET} 重启 Fail2Ban 服务"
      echo -e "${YELLOW}  2.${RESET} 停用 Fail2Ban 服务"
    else
      echo -e "${YELLOW}  1.${RESET} 启动 Fail2Ban 服务"
      echo -e "${GRAY}  2. 停用服务 (已停用)${RESET}"
    fi
    echo -e "${YELLOW}  3.${RESET} ${RED}卸载 Fail2Ban${RESET}"

    echo -e "${CYAN}--- 监控与操作 ---${RESET}"
    echo -e "${YELLOW}  4.${RESET} 查看 SSH 封禁列表"
    echo -e "${YELLOW}  5.${RESET} 手动封禁 IP (Ban IP) ${GREEN}[增强版]${RESET}"
    echo -e "${YELLOW}  6.${RESET} 手动解封 IP (Unban) ${GREEN}[列表回显]${RESET}"
    echo -e "${YELLOW}  7.${RESET} 白名单管理 (Whitelist) ${GREEN}[独立子菜单]${RESET}"
    echo -e "${YELLOW}  8.${RESET} 查看详细运行日志"

    echo -e "${CYAN}--- 策略与维护 ---${RESET}"
    if [ "$is_running" = true ]; then
      echo -e "${YELLOW}  9.${RESET} 修改 SSH 封禁策略 (次数/时长)"
      echo -e "${YELLOW} 10.${RESET} $rec_display"
      echo -e "${YELLOW} 11.${RESET} $ssh_display"
      echo -e "${YELLOW} 12.${RESET} ${RED}清理数据库 (当前: $db_size)${RESET}"
    else
      echo -e "${GRAY}  9. 修改封禁策略 (需启动服务)${RESET}"
      echo -e "${GRAY} 10. $rec_display${RESET}"
      echo -e "${GRAY} 11. $ssh_display${RESET}"
      echo -e "${GRAY} 12. 清理数据库 (需启动服务)${RESET}"
    fi

    echo -e "${YELLOW}  0.${RESET} 返回主菜单"
    echo -e "${CYAN}==================================================${RESET}"

    read -p "请输入选项: " f_choice

    case $f_choice in
    1)
      if [ "$is_installed" = false ]; then
        # 未安装 -> 安装
        check_pm_lock || return 1
        echo -e "${CYAN}正在安装 Fail2Ban...${RESET}"
        $PKG_UPDATE
        $PKG_INSTALL fail2ban
        set_jail_config "sshd" "true"
        ensure_jail_params "sshd"
        systemctl enable fail2ban
        systemctl restart fail2ban
        echo -e "${GREEN}[√] 安装并启动成功${RESET}"
        sleep 3
      elif [ "$is_running" = true ]; then
        # 运行中 -> 重启
        echo -e "${CYAN}正在重启服务...${RESET}"
        systemctl restart fail2ban
        echo -e "${GREEN}[√] 服务已重启${RESET}"
        sleep 2
      else
        # 已安装未运行 -> 启动
        echo -e "${CYAN}正在启动服务...${RESET}"
        systemctl start fail2ban
        echo -e "${GREEN}[√] 服务已启动${RESET}"
        sleep 2
      fi
      ;;
    2)
      # 停用服务
      if [ "$is_installed" = false ]; then
        echo -e "${YELLOW}[!] Fail2Ban 尚未安装${RESET}"
        sleep 1
        continue
      fi
      if [ "$is_running" = false ]; then
        echo -e "${YELLOW}[!] 服务已是停用状态${RESET}"
        sleep 1
        continue
      fi
      echo -e "${CYAN}正在停用服务...${RESET}"
      systemctl stop fail2ban
      echo -e "${GREEN}[√] 服务已停用 (配置保留)${RESET}"
      sleep 2
      ;;
    3)
      if [ "$is_installed" = false ]; then
        echo -e "${YELLOW}[!] Fail2Ban 尚未安装${RESET}"
        sleep 1
        continue
      fi
      echo -e "${RED}警告: 即将完全卸载 Fail2Ban (包括所有配置和数据)。${RESET}"
      read -p "确认? [y/N]: " c
      if [[ "$c" =~ ^[Yy]$ ]]; then
        echo -e "${CYAN}正在停止服务...${RESET}"
        systemctl stop fail2ban 2>/dev/null
        systemctl disable fail2ban 2>/dev/null
        check_pm_lock || return 1
        echo -e "${CYAN}正在卸载软件包...${RESET}"
        # 使用 purge 彻底清除 (apt) 或标准 remove (yum/dnf)
        if [[ "$PKG_MANAGER" == "apt" ]]; then
          apt-get purge -y fail2ban 2>/dev/null
          apt-get autoremove -y 2>/dev/null
        else
          $PKG_REMOVE fail2ban
        fi
        echo -e "${CYAN}正在清理残留文件...${RESET}"
        rm -rf /etc/fail2ban /var/lib/fail2ban /var/log/fail2ban.log*
        # 刷新命令缓存，避免 command -v 误判
        hash -r 2>/dev/null
        echo -e "${GREEN}[√] 卸载完成，已清理所有配置和数据${RESET}"
        sleep 2
      fi
      ;;
    4)
      # [修复] 添加服务未运行的反馈提示
      if ! check_f2b_running; then
        echo -e "${RED}[!] Fail2Ban 服务未运行，请先启动服务${RESET}"
        sleep 1
        continue
      fi
      echo -e "${CYAN}SSH 监狱:${RESET}"
      fail2ban-client status sshd 2>/dev/null || echo "未启动"
      if check_jail_status "recidive"; then
        echo -e "\n${CYAN}顽固监狱:${RESET}"
        fail2ban-client status recidive
      fi
      read -p "按 Enter 继续..."
      ;;
    5)
      # [修复] 添加服务未运行的反馈提示
      if ! check_f2b_running; then
        echo -e "${RED}[!] Fail2Ban 服务未运行，请先启动服务${RESET}"
        sleep 1
        continue
      fi
      read -p "封禁 IP [0 返回]: " ip
      [ "$ip" == "0" ] || [ -z "$ip" ] && continue
      echo -e "  1. 临时封禁 (Fail2Ban)\n  2. 永久封禁 (hosts.deny)"
      read -p "选择: " m
      case $m in
      1) fail2ban-client set sshd banip "$ip" && echo -e "${GREEN}[√] 已加入 Jail${RESET}" ;;
      2) 
        # [修复] 检查IP是否已存在于 hosts.deny
        local escaped_ip=$(echo "$ip" | sed 's/\./\\./g')
        if grep -q "ALL:.*$escaped_ip" /etc/hosts.deny 2>/dev/null; then
          echo -e "${YELLOW}[!] IP $ip 已存在于黑名单中${RESET}"
        else
          echo "ALL: $ip" >>/etc/hosts.deny && echo -e "${GREEN}[√] 已加入黑名单${RESET}"
        fi
        ;;
      esac
      read -p "按 Enter 继续..."
      ;;
    6)
      check_f2b_running || continue
      # [UX优化] 先展示当前封禁列表，方便复制
      echo -e "${CYAN}>>> 当前被封禁的 IP (SSH):${RESET}"
      fail2ban-client status sshd 2>/dev/null | grep "Banned IP list:" | sed 's/Banned IP list://g' | xargs -n 5
      echo -e "${CYAN}--------------------------${RESET}"

      read -p "请输入要解封的 IP [0 返回]: " ip
      [ "$ip" != "0" ] && [ -n "$ip" ] && {
        fail2ban-client set sshd unbanip "$ip" 2>/dev/null
        fail2ban-client set recidive unbanip "$ip" 2>/dev/null
        # [修复] 使用转义处理IP中的特殊字符 (如 .)
        if [ -f /etc/hosts.deny ]; then
          local escaped_ip=$(echo "$ip" | sed 's/\./\\./g')
          sed -i "/ALL:.*$escaped_ip/d" /etc/hosts.deny
        fi
        echo -e "${GREEN}[√] 已解封${RESET}"
      }
      read -p "按 Enter 继续..."
      ;;
    7)
      # [修复] 添加服务未运行的反馈提示
      if ! check_f2b_running; then
        echo -e "${RED}[!] Fail2Ban 服务未运行，请先启动服务${RESET}"
        sleep 1
        continue
      fi
      # --- 白名单子菜单循环 ---
      while true; do
        clear
        echo -e "${BOLD}${CYAN}📋 Fail2Ban 白名单管理${RESET}"
        echo -e "${CYAN}==================================================${RESET}"

        # 实时获取列表
        cur_runtime_list=$(fail2ban-client get sshd ignoreip 2>/dev/null)
        cur_file_list=$(grep "^ignoreip" /etc/fail2ban/jail.local | cut -d= -f2 | xargs)

        echo -e "当前生效(Runtime): ${GREEN}${cur_runtime_list:-无}${RESET}"
        echo -e "配置文件(Config):  ${YELLOW}${cur_file_list:-无}${RESET}"
        echo -e "${CYAN}--------------------------------------------------${RESET}"
        echo -e "${YELLOW}  1.${RESET} 添加 IP (Add IP) ${GRAY}[智能建议]${RESET}"
        echo -e "${YELLOW}  2.${RESET} 删除 IP (Remove IP)"
        echo -e "${YELLOW}  0.${RESET} 返回上一级"
        echo -e "${CYAN}==================================================${RESET}"

        read -p "请输入选项: " wl_choice
        case $wl_choice in
        1)
          # 智能获取建议 IP
          suggest_ip=$(echo "${SSH_CLIENT%% *}")
          [ -z "$suggest_ip" ] && suggest_ip=$(echo "${SSH_CONNECTION%% *}")
          read -p "请输入要添加的 IP (默认 $suggest_ip): " add_ip
          [ -z "$add_ip" ] && add_ip="$suggest_ip"

          if [ -n "$add_ip" ]; then
            # 1. 运行时添加
            fail2ban-client set sshd addignoreip "$add_ip" >/dev/null 2>&1

            # 2. 写入配置文件 (持久化)
            if grep -q "ignoreip =" /etc/fail2ban/jail.local; then
              # 防止重复添加
              if ! grep "^ignoreip" /etc/fail2ban/jail.local | grep -q "$add_ip"; then
                sed -i "/ignoreip =/s/$/ $add_ip/" /etc/fail2ban/jail.local
              fi
            else
              # 如果没有 ignoreip 行，插入一行
              sed -i "/^\[DEFAULT\]/a ignoreip = 127.0.0.1/8 $add_ip" /etc/fail2ban/jail.local
            fi
            echo -e "${GREEN}[√] 添加成功: $add_ip${RESET}"
            sleep 1
          fi
          ;;
        2)
          read -p "请输入要删除的 IP: " del_ip
          if [ -n "$del_ip" ]; then
            # 1. 运行时删除
            fail2ban-client set sshd delignoreip "$del_ip" >/dev/null 2>&1

            # 2. [修复] 配置文件删除，转义特殊字符 (如 . 和 /)
            if [ -f /etc/fail2ban/jail.local ]; then
              local escaped_del_ip=$(echo "$del_ip" | sed 's/\./\\./g; s/\//\\\//g')
              sed -i "s/ $escaped_del_ip//g" /etc/fail2ban/jail.local
              # 处理行首的IP (紧跟 = 的情况)
              sed -i "s/=$escaped_del_ip /= /g" /etc/fail2ban/jail.local
            fi
            echo -e "${GREEN}[√] 删除操作已执行: $del_ip${RESET}"
            sleep 1
          fi
          ;;
        0) break ;; # 退出子菜单
        *)
          echo -e "${RED}无效选项${RESET}"
          sleep 1
          ;;
        esac
      done
      ;;
    8)
      # [修复] 添加服务未运行的反馈提示
      if ! check_f2b_running; then
        echo -e "${RED}[!] Fail2Ban 服务未运行，请先启动服务${RESET}"
        sleep 1
        continue
      fi
      echo -e "${CYAN}>>> 最后 20 条日志:${RESET}"
      tail -n 20 /var/log/fail2ban.log 2>/dev/null
      echo -e "${CYAN}--------------------------------------------------${RESET}"
      read -p "是否进入实时监控模式 (按 Ctrl+C 退出)? [y/N]: " view_live
      if [[ "$view_live" =~ ^[Yy]$ ]]; then
        tail -f /var/log/fail2ban.log
      fi
      ;;
    9)
      # [修复] 添加服务未运行的反馈提示
      if ! check_f2b_running; then
        echo -e "${RED}[!] Fail2Ban 服务未运行，请先启动服务${RESET}"
        sleep 1
        continue
      fi
      
      # [修复] 获取当前配置作为默认值
      local cur_maxretry=$(sed -n '/^\[sshd\]/,/^\[/{/maxretry/p}' /etc/fail2ban/jail.local 2>/dev/null | tail -1 | awk -F= '{print $2}' | xargs)
      local cur_bantime=$(sed -n '/^\[sshd\]/,/^\[/{/bantime/p}' /etc/fail2ban/jail.local 2>/dev/null | tail -1 | awk -F= '{print $2}' | xargs)
      [ -z "$cur_maxretry" ] && cur_maxretry="5"
      [ -z "$cur_bantime" ] && cur_bantime="10m"
      
      echo -e "当前配置: 最大失败=${YELLOW}$cur_maxretry${RESET}, 封禁时长=${YELLOW}$cur_bantime${RESET}"
      echo -e "${GRAY}提示: 输入 0 可返回上一级菜单${RESET}"
      read -p "最大失败次数 (留空保持 $cur_maxretry): " mr
      if [[ "$mr" == "0" ]]; then continue; fi
      read -p "封禁时长 (留空保持 $cur_bantime): " bt
      if [[ "$bt" == "0" ]]; then continue; fi
      
      # 使用原值作为默认
      [ -z "$mr" ] && mr="$cur_maxretry"
      [ -z "$bt" ] && bt="$cur_bantime"
      
      if [[ "$mr" =~ ^[0-9]+$ ]]; then
        sed -i '/^\[sshd\]/,/^\[/ { /maxretry/d; /bantime/d }' /etc/fail2ban/jail.local
        sed -i "/^\[sshd\]/a maxretry = $mr\nbantime = $bt" /etc/fail2ban/jail.local
        echo -e "${CYAN}正在应用策略...${RESET}"
        systemctl restart fail2ban
        echo -e "${GREEN}[√] 已更新${RESET}"
      else
        echo -e "${RED}[!] 最大失败次数必须是数字${RESET}"
      fi
      read -p "按 Enter 继续..."
      ;;
    10)
      # [修复] 添加服务未运行的反馈提示
      if ! check_f2b_running; then
        echo -e "${RED}[!] Fail2Ban 服务未运行，请先启动服务${RESET}"
        sleep 1
        continue
      fi
      if [ "$rec_status" == "on" ]; then
        read -p "确认关闭 顽固监狱 (Recidive)? [y/N]: " c
        if [[ "$c" =~ ^[Yy]$ ]]; then
          set_jail_config "recidive" "false"
          systemctl restart fail2ban
          sleep 2
          echo -e "${YELLOW}[!] 已关闭${RESET}"
        else
          echo -e "${YELLOW}操作已取消${RESET}"
        fi
      else
        set_jail_config "recidive" "true"
        ensure_jail_params "recidive"
        systemctl restart fail2ban
        sleep 2
        echo -e "${GREEN}[√] 已开启${RESET}"
      fi
      ;;
    11)
      # [修复] 添加服务未运行的反馈提示
      if ! check_f2b_running; then
        echo -e "${RED}[!] Fail2Ban 服务未运行，请先启动服务${RESET}"
        sleep 1
        continue
      fi
      if [ "$ssh_status" == "on" ]; then
        read -p "确认关闭 SSH 保护? [y/N]: " c
        [[ "$c" =~ ^[Yy]$ ]] && {
          set_jail_config "sshd" "false"
          systemctl restart fail2ban
          sleep 2
          echo -e "${YELLOW}[!] 已关闭${RESET}"
        }
      else
        set_jail_config "sshd" "true"
        ensure_jail_params "sshd"
        systemctl restart fail2ban
        sleep 2
        echo -e "${GREEN}[√] 已开启${RESET}"
      fi
      ;;
    12)
      if [ -f "$db_file" ]; then
        # [修复] 增强数据库清理的风险警告
        echo -e "${RED}========== 警告 ===========${RESET}"
        echo -e "${YELLOW}此操作将清除 Fail2Ban 数据库，包括:${RESET}"
        echo -e "  - 所有封禁记录和历史"
        echo -e "  - Jail 统计信息"
        echo -e "  - 当前数据库大小: ${YELLOW}$db_size${RESET}"
        echo -e "${RED}============================${RESET}"
        read -p "确认清理数据库? 输入 'yes' 确认: " c
        if [ "$c" == "yes" ]; then
          systemctl stop fail2ban
          rm -f "$db_file"
          if systemctl start fail2ban; then
            echo -e "${GREEN}[√] 数据库已清理，服务已重启${RESET}"
          else
            echo -e "${RED}[!] 警告: 服务启动失败，请检查配置${RESET}"
          fi
        else
          echo -e "${YELLOW}已取消${RESET}"
        fi
      else echo -e "${YELLOW}文件不存在${RESET}"; fi
      read -p "按 Enter 继续..."
      ;;
    0)
      SKIP_PAUSE=true
      break
      ;;
    *)
      echo -e "${RED}无效选项${RESET}"
      sleep 1
      ;;
    esac
  done
}

change_timezone() {
  echo -e "${CYAN}>>> 修改系统时区...${RESET}"

  local target_tz=""

  while true; do
    current_tz=$(timedatectl show --property=Timezone --value 2>/dev/null || cat /etc/timezone)
    current_time=$(date '+%Y-%m-%d %H:%M:%S')
    echo -e "当前时区: ${GREEN}$current_tz${RESET}"
    echo -e "当前时间: ${GREEN}$current_time${RESET}"

    echo -e "\n${CYAN}请选择目标时区:${RESET}"
    echo -e "  ${GREEN}1${RESET}) 亚洲/上海 (Beijing/Shanghai, UTC+8)"
    echo -e "  ${GREEN}2${RESET}) 亚洲/香港 (Hong Kong, UTC+8)"
    echo -e "  ${GREEN}3${RESET}) 亚洲/台北 (Taipei, UTC+8)"
    echo -e "  ${GREEN}4${RESET}) 亚洲/东京 (Tokyo, UTC+9)"
    echo -e "  ${GREEN}5${RESET}) 美国/纽约 (New York, UTC-5/UTC-4)"
    echo -e "  ${GREEN}6${RESET}) 欧洲/伦敦 (London, UTC+0/UTC+1)"
    echo -e "  ${GREEN}7${RESET}) 交互式选择 (Region -> City)"
    echo -e "  ${GREEN}8${RESET}) 恢复默认时区 (UTC)"
    echo -e "  ${YELLOW}0.${RESET} 取消/返回"

    read -p "请输入选项 [0-8]: " tz_choice

    case $tz_choice in
    1)
      target_tz="Asia/Shanghai"
      break
      ;;
    2)
      target_tz="Asia/Hong_Kong"
      break
      ;;
    3)
      target_tz="Asia/Taipei"
      break
      ;;
    4)
      target_tz="Asia/Tokyo"
      break
      ;;
    5)
      target_tz="America/New_York"
      break
      ;;
    6)
      target_tz="Europe/London"
      break
      ;;
    7)
      # 交互式选择逻辑
      while true; do
        echo -e "\n${CYAN}>>> 区域选择 (输入 0 退出):${RESET}"
        regions=($(find /usr/share/zoneinfo -maxdepth 1 -type d | sed 's|/usr/share/zoneinfo/||' | grep -v "^\." | grep -v "^posix" | grep -v "^right" | grep -E "^[A-Z]" | sort))

        for i in "${!regions[@]}"; do
          printf "  ${GREEN}%-2d${RESET}) %s\n" "$((i + 1))" "${regions[$i]}"
        done
        echo -e "  ${YELLOW}0.${RESET} 返回上一级"

        read -p "请输入区域编号: " region_idx

        if [[ "$region_idx" == "0" ]]; then break; fi

        if [[ "$region_idx" =~ ^[0-9]+$ ]] && [ "$region_idx" -ge 1 ] && [ "$region_idx" -le "${#regions[@]}" ]; then
          selected_region="${regions[$((region_idx - 1))]}"
          echo -e "${YELLOW}已选择区域: $selected_region${RESET}"

          while true; do
            echo -e "\n${CYAN}>>> 城市选择 (输入 0 返回区域列表):${RESET}"
            cities=($(ls "/usr/share/zoneinfo/$selected_region" | grep -v "^posix" | grep -v "^right" | sort))

            local total_cities=${#cities[@]}
            local num_cols=3
            local rows=$(((total_cities + num_cols - 1) / num_cols))

            for ((r = 0; r < rows; r++)); do
              idx1=$r
              if [ $idx1 -lt $total_cities ]; then
                printf "${GREEN}%-3d${RESET}) %-20s" "$((idx1 + 1))" "${cities[$idx1]}"
              fi
              idx2=$((r + rows))
              if [ $idx2 -lt $total_cities ]; then
                printf "${GREEN}%-3d${RESET}) %-20s" "$((idx2 + 1))" "${cities[$idx2]}"
              fi
              idx3=$((r + rows * 2))
              if [ $idx3 -lt $total_cities ]; then
                printf "${GREEN}%-3d${RESET}) %-20s" "$((idx3 + 1))" "${cities[$idx3]}"
              fi
              echo ""
            done

            echo -e "  ${YELLOW}0.${RESET} 返回上一级"

            read -p "请输入城市编号: " city_idx

            if [[ "$city_idx" == "0" ]]; then break; fi

            if [[ "$city_idx" =~ ^[0-9]+$ ]] && [ "$city_idx" -ge 1 ] && [ "$city_idx" -le "${#cities[@]}" ]; then
              selected_city="${cities[$((city_idx - 1))]}"
              target_tz="$selected_region/$selected_city"
              # 跳出两层循环 (City 和 Region)
              break 2
            else
              echo -e "${RED}无效的城市编号${RESET}"
            fi
          done
        else
          echo -e "${RED}无效的区域编号${RESET}"
        fi
      done

      # 如果在交互模式中未选择(直接返回了)，则 continue 重新显示主菜单
      if [ -z "$target_tz" ]; then continue; fi
      # 如果选择了，则 break 跳出主菜单循环去执行应用逻辑
      break
      ;;
    8)
      target_tz="Etc/UTC"
      echo -e "${CYAN}准备将时区重置为默认值 (Etc/UTC)...${RESET}"
      break
      ;;
    0)
      # 取消操作，直接退出函数
      SKIP_PAUSE=true
      return 0
      ;;
    *)
      echo -e "${RED}无效选项${RESET}"
      sleep 1
      continue
      ;;
    esac
  done

  # ---------- 应用逻辑移至循环外 ----------
  if [ -n "$target_tz" ]; then
    echo -e "${CYAN}>>> 正在应用时区设置: $target_tz ...${RESET}"
    if [ -f "/usr/share/zoneinfo/$target_tz" ]; then
      if command -v timedatectl >/dev/null 2>&1; then
        timedatectl set-timezone "$target_tz"
      else
        ln -sf "/usr/share/zoneinfo/$target_tz" /etc/localtime
        echo "$target_tz" >/etc/timezone
      fi

      # 同步硬件时间
      hwclock --systohc 2>/dev/null

      echo -e "${GREEN}[√] 时区已修改为: $target_tz${RESET}"
      echo -e "当前时间: $(date '+%Y-%m-%d %H:%M:%S')"
    else
      echo -e "${RED}[!] 错误: 未找到时区文件 /usr/share/zoneinfo/$target_tz${RESET}"
    fi
  fi
}

# ---------- 修改主机名 ----------
change_hostname() {
  while true; do
    clear
    echo -e "${CYAN}>>> 修改系统主机名 (Hostname)${RESET}"

    local current_hostname=$(hostname)
    echo -e "当前主机名: ${GREEN}${current_hostname}${RESET}"
    echo -e "${CYAN}--------------------------------------------------${RESET}"

    # --- 步骤 1: 输入阶段 (支持返回) ---
    echo -e "${GRAY}提示: 建议使用英文、数字和连字符(-)，例如: vps-hk-01${RESET}"
    read -p "请输入新的主机名 (输入 0 取消): " new_hostname

    # 返回主菜单逻辑
    if [ "$new_hostname" == "0" ]; then
      SKIP_PAUSE=true
      return 0
    fi

    # 空值检查 -> 返回重输
    if [ -z "$new_hostname" ]; then
      echo -e "${RED}[!] 错误：主机名不能为空，请重新输入。${RESET}"
      sleep 1
      continue
    fi

    # 格式检查 (简单正则) -> 返回重输
    if [[ ! "$new_hostname" =~ ^[a-zA-Z0-9.-]+$ ]]; then
      echo -e "${RED}[!] 错误：主机名包含非法字符，仅支持字母、数字、点和横杠。${RESET}"
      sleep 2
      continue
    fi

    # 一致性检查 -> 返回重输
    if [ "$new_hostname" == "$current_hostname" ]; then
      echo -e "${YELLOW}[!] 新主机名与当前一致，无需修改。${RESET}"
      read -p "按 Enter 返回..."
      return 0
    fi

    # --- 步骤 2: 确认阶段 (支持“反悔”返回上一步) ---
    echo -e "\n${CYAN}即将执行以下变更:${RESET}"
    echo -e "  旧主机名: ${RED}${current_hostname}${RESET}"
    echo -e "  新主机名: ${GREEN}${new_hostname}${RESET}"

    echo -e "\n${YELLOW}确认修改吗?${RESET}"
    echo -e "  [y] 确认修改"
    echo -e "  [n] 重新输入 (返回上一步)"
    echo -e "  [0] 取消并退出"

    read -p "请输入选项: " confirm_choice

    case $confirm_choice in
    [yY] | [yY][eE][sS])
      # 用户确认，跳出循环执行修改
      break
      ;;
    0)
      # 用户取消
      SKIP_PAUSE=true
      return 0
      ;;
    *)
      # 用户选 n 或其他，循环继续，回到“输入阶段”
      continue
      ;;
    esac
  done

  # --- 步骤 3: 执行阶段 ---
  echo -e "\n${CYAN}>>> 正在应用修改...${RESET}"

  # 3.1 修改主机名
  if command -v hostnamectl >/dev/null 2>&1; then
    hostnamectl set-hostname "$new_hostname"
  else
    hostname "$new_hostname"
    [ -f /etc/hostname ] && echo "$new_hostname" >/etc/hostname
  fi

  # 3.2 同步修改 /etc/hosts
  # [修复] 使用更精确的匹配，避免替换注释行或部分匹配
  if [ -f /etc/hosts ]; then
    # 只替换独立的主机名 (空格/Tab分隔或行尾)
    if grep -qE "(^|\s)${current_hostname}(\s|$)" /etc/hosts; then
      sed -i "s/\(^\|[[:space:]]\)${current_hostname}\([[:space:]]\|$\)/\1${new_hostname}\2/g" /etc/hosts
      echo -e "${GREEN}[√] 已更新 /etc/hosts 映射${RESET}"
    else
      # 如果找不到旧名，追加新的一行
      if ! grep -qE "(^|\s)${new_hostname}(\s|$)" /etc/hosts; then
        echo "127.0.1.1 $new_hostname" >>/etc/hosts
        echo -e "${GREEN}[√] 已添加 /etc/hosts 映射${RESET}"
      fi
    fi
  fi

  # --- 步骤 4: 结果验证 ---
  local verify_name=$(hostname)
  if [ "$verify_name" == "$new_hostname" ]; then
    echo -e "${GREEN}[√] 主机名修改成功!${RESET}"
    echo -e "${YELLOW}注意: 请重新连接 SSH (断开重连) 以使终端提示符更新。${RESET}"
  else
    echo -e "${RED}[!] 修改可能未完全生效，检测到的主机名为: $verify_name${RESET}"
  fi
}

# ---------- [增强] 端口占用速查 (内部函数) ----------
sub_port_usage() {
  while true; do
    clear
    echo -e "${BOLD}${CYAN}🔌 端口占用情况速查 (TCP/UDP)${RESET}"
    echo -e "${CYAN}========================================================================${RESET}"
    echo -e "${YELLOW}Proto  Local Address             Port    PID/Process Name${RESET}"
    echo -e "${CYAN}------------------------------------------------------------------------${RESET}"

    ss -tulnp | sed '1d' | awk '{
            proto = $1
            local_addr = $5
            process_raw = $7
            n = split(local_addr, a, ":")
            port = a[n]
            ip = ""
            for(i=1; i<n; i++){
                ip = ip a[i]
                if(i < n-1) ip = ip ":"
            }
            proc_info = "未知"
            idx = index(process_raw, "users:((\"")
            if (idx > 0) {
                raw_str = substr(process_raw, idx + 9)
                split(raw_str, p_arr, ",")
                p_name = p_arr[1]
                gsub(/"/, "", p_name)
                p_pid = ""
                for(k in p_arr) {
                    if(index(p_arr[k], "pid=") > 0) {
                        split(p_arr[k], pid_arr, "=")
                        p_pid = pid_arr[2]
                        break
                    }
                }
                proc_info = p_name "(" p_pid ")"
            }
            print proto "|" ip "|" port "|" proc_info
        }' | sort -k3 -n | head -n 30 |
      while IFS='|' read -r proto ip port proc_info; do
        current_color=""
        if [[ "$ip" == "127.0.0.1" ]] || [[ "$ip" == "[::1]" ]]; then
          current_color="${GREEN}"
        elif [[ "$ip" == "0.0.0.0" ]] || [[ "$ip" == "*" ]] || [[ "$ip" == "[::]" ]]; then
          current_color="${RED}"
        else
          current_color="${RESET}"
        fi
        printf "%-6s ${current_color}%-25s${RESET} %-7s %s\n" "$proto" "$ip" "$port" "$proc_info"
      done

    echo -e "${CYAN}========================================================================${RESET}"
    echo -e "${YELLOW}功能菜单:${RESET}"
    echo -e "  ${GREEN}1${RESET}) 刷新列表 (Refresh)"
    echo -e "  ${GREEN}2${RESET}) 强制结束进程 (Kill PID)"
    echo -e "  ${YELLOW}0${RESET}) 返回上一级"

    read -p "请输入选项: " choice
    case $choice in
    1) continue ;;
    2)
      read -p "请输入要结束的 PID (数字, 输入 0 返回): " kill_pid
      if [ "$kill_pid" == "0" ]; then continue; fi
      if [[ "$kill_pid" =~ ^[0-9]+$ ]]; then
        proc_name=$(ps -p "$kill_pid" -o comm= 2>/dev/null)
        if [ -z "$proc_name" ]; then
          echo -e "${RED}[!] 找不到 PID 为 $kill_pid 的进程${RESET}"
        else
          echo -e "${YELLOW}警告: 即将结束进程: $proc_name (PID: $kill_pid)${RESET}"
          read -p "确认执行吗? [y/N]: " confirm_kill
          if [[ "$confirm_kill" =~ ^[Yy]$ ]]; then
            kill -9 "$kill_pid"
            echo -e "${GREEN}[√] 进程已结束${RESET}"
          fi
        fi
      else
        echo -e "${RED}[!] PID 必须是数字${RESET}"
      fi
      read -p "按 Enter 继续..."
      ;;
    0) return 0 ;;
    *) echo -e "${RED}无效选项${RESET}"; sleep 1 ;;
    esac
  done
}

# --- [新增] 进程资源占用 (Top 5) ---
sub_process_top() {
    clear
    echo -e "${BOLD}${CYAN}📊 进程资源占用分析 (Top 5)${RESET}"
    echo -e "${CYAN}--------------------------------------------------${RESET}"
    
    echo -e "${YELLOW}💾 内存占用前 5 名:${RESET}"
    printf "%-8s %-8s %-6s %-6s %s\n" "PID" "USER" "%MEM" "%CPU" "COMMAND"
    ps -eo pid,user,%mem,%cpu,comm --sort=-%mem | head -n 6 | tail -n 5 | \
    while read -r p u m c cmd; do
        printf "${GREEN}%-8s${RESET} %-8s ${YELLOW}%-6s${RESET} %-6s %s\n" "$p" "$u" "$m" "$c" "$cmd"
    done
    
    echo -e "\n${YELLOW}🐢 CPU 占用前 5 名:${RESET}"
    printf "%-8s %-8s %-6s %-6s %s\n" "PID" "USER" "%MEM" "%CPU" "COMMAND"
    ps -eo pid,user,%mem,%cpu,comm --sort=-%cpu | head -n 6 | tail -n 5 | \
    while read -r p u m c cmd; do
        printf "${GREEN}%-8s${RESET} %-8s %-6s ${RED}%-6s${RESET} %s\n" "$p" "$u" "$m" "$c" "$cmd"
    done
    
    echo -e "\n${CYAN}--------------------------------------------------${RESET}"
    read -p "按 Enter 返回..."
}

# --- [新增] 登录安全审计 ---
sub_login_audit() {
    clear
    # 依赖按需安装 (交互式)
    if ! command -v last >/dev/null 2>&1 && ! command -v wtmpdb >/dev/null 2>&1; then
        echo -e "${YELLOW}检测到缺少审计工具 (last/lastb)${RESET}"
        read -p "是否尝试自动安装所需组件 (util-linux/wtmpdb)? [y/N]: " install_choice
        if [[ "$install_choice" =~ ^[Yy]$ ]]; then
            check_pm_lock
            
            # 尝试安装 util-linux (标准)
            echo -e "${CYAN}Attempting to install util-linux...${RESET}"
            $PKG_INSTALL util-linux
            
            # 检测是否安装成功，若无则尝试其他
            if ! command -v last >/dev/null 2>&1 && [[ "$PKG_MANAGER" == "apt" ]]; then
                 echo -e "${CYAN}Attempting to install sysvinit-utils (Debian Legacy)...${RESET}"
                 $PKG_INSTALL sysvinit-utils
            fi

            # [针对新版发行版] util-linux v2.40+ 可能移除了 last，尝试 wtmpdb
            if ! command -v last >/dev/null 2>&1 && [[ "$PKG_MANAGER" == "apt" ]]; then
                 echo -e "${CYAN}Attempting to install wtmpdb (Newer Debian/Kali)...${RESET}"
                 $PKG_INSTALL wtmpdb
            fi
            
            if command -v last >/dev/null 2>&1 || command -v wtmpdb >/dev/null 2>&1; then
                echo -e "${GREEN}[√] 组件安装成功${RESET}"
            else
                echo -e "${RED}[!] 安装尝试结束，未能找回 last 命令。${RESET}"
            fi
        else
            echo -e "${GRAY}已跳过安装，仅显示现有日志文件情况。${RESET}"
        fi
    fi
    
    # 确保日志文件存在
    if [ ! -f /var/log/wtmp ]; then touch /var/log/wtmp; fi
    if [ ! -f /var/log/btmp ]; then
        touch /var/log/btmp
        chmod 600 /var/log/btmp
        chown root:utmp /var/log/btmp 2>/dev/null || chown root:root /var/log/btmp
    fi

    # 动态检测可用命令 (增加绝对路径扫描)
    local LAST_CMD=""
    local LASTB_CMD=""

    # 1. 寻找 last
    if command -v last >/dev/null 2>&1; then LAST_CMD="last";
    elif [ -x /usr/bin/last ]; then LAST_CMD="/usr/bin/last";
    elif [ -x /sbin/last ]; then LAST_CMD="/sbin/last";
    elif [ -x /usr/sbin/last ]; then LAST_CMD="/usr/sbin/last";
    elif command -v wtmpdb >/dev/null 2>&1; then LAST_CMD="wtmpdb last";
    fi

    # 2. 寻找 lastb
    if command -v lastb >/dev/null 2>&1; then LASTB_CMD="lastb";
    elif [ -x /usr/sbin/lastb ]; then LASTB_CMD="/usr/sbin/lastb";
    elif [ -x /sbin/lastb ]; then LASTB_CMD="/sbin/lastb";
    elif [ -n "$LAST_CMD" ] && [[ "$LAST_CMD" != *"wtmpdb"* ]]; then
        # 注意: wtmpdb 不支持 -f 读取 btmp (它是 sqlite)，所以只有传统 last 支持
        LASTB_CMD="$LAST_CMD -f /var/log/btmp"
    fi

    echo -e "${BOLD}${CYAN}🕵️  登录安全审计${RESET}"
    echo -e "${CYAN}--------------------------------------------------${RESET}"
    
    # 成功登录
    echo -e "${GREEN}✅ 最近 5 次成功登录:${RESET}"
    if [ -n "$LAST_CMD" ]; then
        $LAST_CMD -n 5 -a | grep -v "reboot" | grep -v "wtmp" | head -n 5
    else
        echo -e "${GRAY}未找到 'last' 或 'wtmpdb' 命令${RESET}"
    fi

    echo -e "\n${RED}⛔ 最近失败尝试统计 (前 5 个 IP):${RESET}"
    
    # 物理文件检查
    if [ ! -f /var/log/btmp ]; then
        echo -e "${GRAY}无法读取 /var/log/btmp (文件不存在)${RESET}"
    elif [ ! -s /var/log/btmp ]; then
         echo -e "${GREEN}恭喜，btmp 日志文件大小为 0 (确实无记录)${RESET}"
    elif [ -z "$LASTB_CMD" ]; then
         echo -e "${RED}[!] btmp 文件有内容，但未找到 lastb 解析工具${RESET}"
         echo -e "${GRAY}    (wtmpdb 暂不支持解析 btmp)${RESET}"
    else
        # 尝试执行
        # 捕获输出
        local fail_out=$($LASTB_CMD 2>/dev/null | head -1)
        if [ -z "$fail_out" ]; then
             # 命令执行了单输出为空? 可能是格式不兼容或者真没数据
             if [ -s /var/log/btmp ]; then
                echo -e "${YELLOW}[?] 文件非空但命令无输出，可能格式不兼容${RESET}"
             else
                echo -e "${GREEN}恭喜，暂无失败记录${RESET}"
             fi
        else
             $LASTB_CMD | awk '{print $3}' | grep -E '[0-9]{1,3}\.' | sort | uniq -c | sort -nr | head -n 5 | \
            while read count ip; do
                printf "  ${RED}%-4s${RESET} 次来自 ${YELLOW}%s${RESET}\n" "$count" "$ip"
            done
        fi
    fi
    
    echo -e "\n${CYAN}--------------------------------------------------${RESET}"
    read -p "按 Enter 返回..."
}

# ---------- [重构] 系统监控中心 (入口) ----------
show_sys_monitor() {
  install_deps "ss" "awk" "ps"
  
  while true; do
    clear
    echo -e "${BOLD}${CYAN}📊 系统监控中心${RESET}"
    echo -e "${CYAN}==================================================${RESET}"
    
    echo -e "  ${YELLOW}1.${RESET} 端口占用情况速查 (Port Usage)"
    echo -e "  ${YELLOW}2.${RESET} 进程资源占用分析 (Top 5 Resource)"
    echo -e "  ${YELLOW}3.${RESET} 登录安全审计 (Last Login/Fail)"
    echo -e "  ${YELLOW}0.${RESET} 返回主菜单"
    echo -e "${CYAN}==================================================${RESET}"

    read -p "请输入选项: " choice
    case $choice in
      1) sub_port_usage ;;
      2) sub_process_top ;;
      3) sub_login_audit ;;
      0) return 0 ;;
      *) echo -e "${RED}无效选项${RESET}"; sleep 1 ;;
    esac
  done
}

# ---------- 计划任务管理 (增强版: 增加脚本权限自动检测 + 向导退出逻辑) ----------
manage_crontab() {
  # --- 1. 入口检测 ---
  if ! command -v crontab >/dev/null 2>&1; then
    echo -e "${YELLOW}[!] 未检测到 Crontab 服务。${RESET}"
    read -p "是否立即安装 Cron? [y/N]: " install_choice
    if [[ "$install_choice" =~ ^[Yy]$ ]]; then
      check_pm_lock || return 1
      
      # 区分包名
      local cron_pkg="cron"
      if [[ "$PKG_MANAGER" == "yum" || "$PKG_MANAGER" == "dnf" ]]; then
          cron_pkg="cronie"
      fi
      
      echo -e "${CYAN}正在安装 $cron_pkg ...${RESET}"
      $PKG_UPDATE
      $PKG_INSTALL "$cron_pkg"
      
      systemctl enable $SVC_CRON
      systemctl start $SVC_CRON
      echo -e "${GREEN}[√] Cron 安装成功${RESET}"
    else
      return 0
    fi
  fi

  if ! systemctl is-active $SVC_CRON >/dev/null 2>&1; then
    systemctl start $SVC_CRON 2>/dev/null
    sleep 1
  fi

  while true; do
    clear
    echo -e "${BOLD}${CYAN}⏰ 计划任务管理 (Crontab)${RESET}"
    echo -e "${CYAN}==================================================${RESET}"

    if command -v crontab >/dev/null 2>&1; then
      if systemctl is-active $SVC_CRON >/dev/null 2>&1; then
        cron_status="${GREEN}运行中 (Active)${RESET}"
      else
        cron_status="${RED}未运行 (Inactive)${RESET}"
      fi
      task_count=$(crontab -l 2>/dev/null | grep -v "^#" | grep -v "^$" | wc -l)
    else
      cron_status="${RED}未安装${RESET}"
      task_count="N/A"
    fi

    echo -e "服务状态: $cron_status | 当前任务数: ${GREEN}$task_count${RESET}"
    echo -e "${CYAN}--------------------------------------------------${RESET}"

    if [[ "$task_count" != "N/A" ]] && [ "$task_count" -gt 0 ]; then
      echo -e "${YELLOW}任务预览:${RESET}"
      crontab -l 2>/dev/null | grep -v "^#" | grep -v "^$" | head -n 3 | awk '{print "  " $0}'
      if [ "$task_count" -gt 3 ]; then echo -e "  ${GRAY}... (还有 $((task_count - 3)) 条)${RESET}"; fi
      echo -e "${CYAN}--------------------------------------------------${RESET}"
    fi

    echo -e "${YELLOW}  1.${RESET} 查看完整任务列表"
    echo -e "${YELLOW}  2.${RESET} 添加: 每日凌晨 3 点自动重启 (快捷)"
    echo -e "${YELLOW}  3.${RESET} 添加: 每周一凌晨 4 点清理日志 (快捷)"
    echo -e "${YELLOW}  4.${RESET} 添加: 自定义计划任务 ${GREEN}[向导模式]${RESET}"
    echo -e "${CYAN}--- 管理 ---${RESET}"
    echo -e "${YELLOW}  5.${RESET} 编辑: 手动编辑文件 (vi/nano)"
    echo -e "${YELLOW}  6.${RESET} ${RED}删除: 删除指定任务 [便捷]${RESET}"
    echo -e "${YELLOW}  7.${RESET} ${RED}清空: 删除所有任务${RESET}"
    echo -e "${CYAN}--- 维护 ---${RESET}"
    echo -e "${YELLOW}  8.${RESET} 备份: 导出当前任务列表"
    echo -e "${YELLOW}  9.${RESET} 恢复: 从备份文件导入"
    echo -e "${YELLOW} 10.${RESET} 日志: 查看 Crontab 运行日志"
    echo -e "${CYAN}--- 危险区域 ---${RESET}"
    echo -e "${YELLOW} 11.${RESET} ${RED}卸载 Cron 服务${RESET}"
    echo -e "${YELLOW}  0.${RESET} 返回主菜单"
    echo -e "${CYAN}==================================================${RESET}"

    read -p "请输入选项: " c_choice

    if [[ "$task_count" == "N/A" ]] && [[ "$c_choice" != "0" ]] && [[ "$c_choice" != "11" ]]; then
      echo -e "${RED}[!] 服务缺失，请选择卸载或返回。${RESET}"
      read -p "Wait..."
      continue
    fi

    case $c_choice in
    1)
      echo -e "${CYAN}>>> 完整任务列表:${RESET}"
      [ "$task_count" -eq 0 ] && echo -e "${GRAY}(无任务)${RESET}" || crontab -l 2>/dev/null | grep -v "^#" | grep -v "^$" | nl -w2 -s'. '
      read -p "按 Enter 继续..."
      ;;
    2)
      (
        crontab -l 2>/dev/null
        echo "0 3 * * * /sbin/reboot"
      ) | grep -v "^$" | sort -u | crontab -
      echo -e "${GREEN}[√] 已添加${RESET}"
      read -p "按 Enter 继续..."
      ;;
    3)
      cmd="apt-get autoremove -y && apt-get clean && journalctl --vacuum-time=3d"
      (
        crontab -l 2>/dev/null
        echo "0 4 * * 1 $cmd"
      ) | grep -v "^$" | sort -u | crontab -
      echo -e "${GREEN}[√] 已添加${RESET}"
      read -p "按 Enter 继续..."
      ;;
    4)
      echo -e "${CYAN}>>> 添加自定义任务 (向导模式)${RESET}"
      echo -e "  ${GREEN}1.${RESET} 每分钟 (* * * * *)"
      echo -e "  ${GREEN}2.${RESET} 每小时 (0 * * * *)"
      echo -e "  ${GREEN}3.${RESET} 每天 (0 0 * * *)"
      echo -e "  ${GREEN}4.${RESET} 每周 (0 0 * * 0)  ${GRAY}# 0=周日, 1=周一...${RESET}"
      echo -e "  ${GREEN}5.${RESET} 每月 (0 0 1 * *)"
      echo -e "  ${GREEN}6.${RESET} 重启时 (@reboot)"
      echo -e "  ${YELLOW}7.${RESET} 手动输入"
      echo -e "  ${YELLOW}0.${RESET} 返回"

      read -p "频率编号: " cron_type
      local cron_time=""

      # [修改] 重写辅助函数，支持 q 退出
      read_range() {
        local p="$1"
        local min="$2"
        local max="$3"
        local v
        while true; do
          read -p "$p ($min-$max) [q 退出]: " v
          # [新增] 退出检测
          if [[ "$v" == "q" ]]; then
            echo "QUIT"
            return 0
          fi

          if [[ "$v" =~ ^[0-9]+$ ]] && [ "$v" -ge "$min" ] && [ "$v" -le "$max" ]; then
            echo "$v"
            return 0
          fi
          echo -e "${RED}无效输入，请输入 $min-$max 之间的数字或 q 退出${RESET}" >&2
        done
      }

      case $cron_type in
      1) cron_time="* * * * *" ;;
      2)
        m=$(read_range "第几分钟" 0 59)
        if [ "$m" == "QUIT" ]; then continue; fi # [新增] 检测退出
        cron_time="$m * * * *"
        ;;
      3)
        h=$(read_range "小时" 0 23)
        if [ "$h" == "QUIT" ]; then continue; fi
        m=$(read_range "分钟" 0 59)
        if [ "$m" == "QUIT" ]; then continue; fi
        cron_time="$m $h * * *"
        ;;
      4)
        w=$(read_range "星期(0-6)" 0 6)
        if [ "$w" == "QUIT" ]; then continue; fi
        h=$(read_range "小时" 0 23)
        if [ "$h" == "QUIT" ]; then continue; fi
        m=$(read_range "分钟" 0 59)
        if [ "$m" == "QUIT" ]; then continue; fi
        cron_time="$m $h * * $w"
        ;;
      5)
        d=$(read_range "日期(1-31)" 1 31)
        if [ "$d" == "QUIT" ]; then continue; fi
        h=$(read_range "小时" 0 23)
        if [ "$h" == "QUIT" ]; then continue; fi
        m=$(read_range "分钟" 0 59)
        if [ "$m" == "QUIT" ]; then continue; fi
        cron_time="$m $h $d * *"
        ;;
      6) cron_time="@reboot" ;;
      7)
        read -p "输入表达式 (输入 0 返回): " cron_time
        if [ "$cron_time" == "0" ]; then continue; fi
        ;;
      0) continue ;;
      *)
        echo -e "${RED}无效选择${RESET}"
        sleep 1
        continue
        ;;
      esac

      echo -e "时间: ${YELLOW}$cron_time${RESET}"
      read -p "请输入命令 (绝对路径, 输入 0 返回): " cron_cmd
      if [ "$cron_cmd" == "0" ] || [ -z "$cron_cmd" ]; then continue; fi

      # --- [增强] 脚本权限自动检测 ---
      # 简单提取第一个字段作为文件路径
      cmd_path=$(echo "$cron_cmd" | awk '{print $1}')
      if [ -f "$cmd_path" ]; then
        if [ ! -x "$cmd_path" ]; then
          echo -e "${YELLOW}警告: 脚本 $cmd_path 没有执行权限 (x)${RESET}"
          read -p "是否自动赋予执行权限? [y/N]: " chmod_confirm
          if [[ "$chmod_confirm" =~ ^[Yy]$ ]]; then
            chmod +x "$cmd_path"
            echo -e "${GREEN}[√] 已赋予 +x 权限${RESET}"
          else
            echo -e "${RED}[!] 任务可能无法运行，请注意。${RESET}"
          fi
        fi
      fi
      # ------------------------------

      echo -e "${CYAN}添加任务: ${GREEN}$cron_time $cron_cmd${RESET}"
      read -p "确认? [y/N]: " confirm_add
      if [[ "$confirm_add" =~ ^[Yy]$ ]]; then
        (
          crontab -l 2>/dev/null
          echo "$cron_time $cron_cmd"
        ) | grep -v "^$" | sort -u | crontab -
        echo -e "${GREEN}[√] 成功${RESET}"
      fi
      read -p "按 Enter 继续..."
      ;;
    5)
      if command -v nano >/dev/null; then export EDITOR=nano; else export EDITOR=vi; fi
      crontab -e
      ;;
    6)
      if [ "$task_count" -gt 0 ]; then
        local tmp="${TEMP_DIR}/cron.tmp"
        crontab -l 2>/dev/null | grep -v "^#" | grep -v "^$" >"$tmp"
        nl -w2 -s'. ' "$tmp"
        read -p "删除编号 (0返回): " dn
        if [[ "$dn" =~ ^[0-9]+$ ]] && [ "$dn" -gt 0 ]; then
          sed -i "${dn}d" "$tmp"
          crontab "$tmp"
          echo -e "${GREEN}[√] 删除成功${RESET}"
        fi
        rm -f "$tmp"
      else echo -e "${YELLOW}无任务${RESET}"; fi
      read -p "按 Enter 继续..."
      ;;
    7)
      read -p "确认清空? [y/N]: " c
      [[ "$c" =~ ^[Yy]$ ]] && crontab -r && echo -e "${GREEN}[√] 已清空${RESET}"
      read -p "按 Enter 继续..."
      ;;
    8)
      bf="/root/cron_bak_$(date +%Y%m%d).txt"
      crontab -l >"$bf" 2>/dev/null
      echo -e "${GREEN}[√] 备份至 $bf${RESET}"
      read -p "按 Enter 继续..."
      ;;
    9)
      read -p "备份文件路径: " rf
      [ -f "$rf" ] && crontab "$rf" && echo -e "${GREEN}[√] 恢复成功${RESET}" || echo -e "${RED}文件不存在${RESET}"
      read -p "按 Enter 继续..."
      ;;
    10)
      if [ -f /var/log/syslog ]; then
        grep "CRON" /var/log/syslog | tail -20
      elif [ -f /var/log/cron.log ]; then
        tail -20 /var/log/cron.log
      else journalctl -u $SVC_CRON -n 20 --no-pager 2>/dev/null; fi
      read -p "按 Enter 继续..."
      ;;
    11)
      read -p "⚠️  确定卸载 Cron 服务? [y/N]: " un_c
      if [[ "$un_c" =~ ^[Yy]$ ]]; then
        systemctl stop $SVC_CRON
        # 发行版适配包名
        local cron_pkg="cron"
        if [[ "$PKG_MANAGER" == "yum" || "$PKG_MANAGER" == "dnf" ]]; then
            cron_pkg="cronie"
        fi
        $PKG_REMOVE "$cron_pkg"
        rm -rf /var/spool/cron/crontabs
        echo -e "${GREEN}[√] 已卸载${RESET}"
        SKIP_PAUSE=true
        return 0
      fi
      ;;
    0)
      SKIP_PAUSE=true
      return 0
      ;;
    *)
      echo -e "${RED}无效${RESET}"
      sleep 1
      ;;
    esac
  done
}

# --- [10. 工具] 系统软件源切换 ---
change_mirror() {
  while true; do
    clear
    echo -e "${BOLD}${CYAN}📦 系统国内源切换${RESET}"
    echo -e "${CYAN}==================================================${RESET}"
    echo -e "  ${GREEN}1${RESET}) 切换 系统软件源 (APT/YUM/DNF)"
    echo -e "  ${GREEN}2${RESET}) 切换 Docker 镜像源"
    echo -e "  ${YELLOW}0.${RESET} 返回主菜单"
    echo -e "${CYAN}==================================================${RESET}"
    read -p "请输入选项: " choice
    case $choice in
    1)
      while true; do
        clear
        echo -e "${CYAN}>>> 切换系统软件源 (System Repos)${RESET}"
        echo -e "检测到系统: ${GREEN}$OS_ID${RESET} (包管理器: $PKG_MANAGER)"
        
        # --- 检测当前源 ---
        current_source="未知/混合"
        if [[ "$PKG_MANAGER" == "apt" ]]; then
           if grep -q "aliyun.com" /etc/apt/sources.list; then current_source="阿里云 (Aliyun)";
           elif grep -q "tsinghua.edu.cn" /etc/apt/sources.list; then current_source="清华大学 (Tsinghua)";
           elif grep -q "tencent.com" /etc/apt/sources.list; then current_source="腾讯云 (Tencent)";
           elif grep -q "deb.debian.org" /etc/apt/sources.list || grep -q "archive.ubuntu.com" /etc/apt/sources.list; then current_source="官方源 (Official)";
           fi
        elif [[ "$PKG_MANAGER" == "yum" || "$PKG_MANAGER" == "dnf" ]]; then
           # 简单检测 CentOS-Base 或对应主repo
           repo_file=$(find /etc/yum.repos.d -name "CentOS-Base.repo" -o -name "CentOS-Stream-BaseOS.repo" -o -name "*.repo" | head -1)
           if [ -f "$repo_file" ]; then
               if grep -q "aliyun.com" "$repo_file"; then current_source="阿里云 (Aliyun)";
               elif grep -q "tsinghua.edu.cn" "$repo_file"; then current_source="清华大学 (Tsinghua)";
               elif grep -q "tencent.com" "$repo_file"; then current_source="腾讯云 (Tencent)";
               elif grep -q "mirror.centos.org" "$repo_file" || grep -q "fedoraproject.org" "$repo_file"; then current_source="官方源 (Official)";
               fi
           fi
        fi
        echo -e "当前识别源: ${YELLOW}$current_source${RESET}"
        # ------------------

        echo -e "${CYAN}--------------------------------------------------${RESET}"
        echo -e "  ${GREEN}1${RESET}) 阿里云 (Alibaba Cloud) [推荐]"
        echo -e "  ${GREEN}2${RESET}) 清华大学 (Tsinghua University)"
        echo -e "  ${GREEN}3${RESET}) 腾讯云 (Tencent Cloud)"
        echo -e "  ${GREEN}4${RESET}) ${RED}恢复官方默认源${RESET}"
        echo -e "  ${YELLOW}0.${RESET} 返回上一级"
        echo -e "${CYAN}==================================================${RESET}"
        
        read -p "请选择源提供商: " mirror_provider
        
        if [ "$mirror_provider" == "0" ]; then break; fi
        
        # 验证输入有效性
        if [[ ! "$mirror_provider" =~ ^[1-4]$ ]]; then
            echo -e "${RED}无效选项${RESET}"
            sleep 1
            continue
        fi

        # 处理 Debian/Ubuntu (APT)
        if [[ "$PKG_MANAGER" == "apt" ]]; then
            # 获取系统代号 (codename), e.g., bookworm, jammy, focal, trixie
            if [ -z "$codename" ]; then 
                codename=$(lsb_release -cs 2>/dev/null)
                if [ -z "$codename" ] && [ -f /etc/os-release ]; then
                    codename=$(grep VERSION_CODENAME /etc/os-release | cut -d= -f2)
                fi
                # 如果依然获取不到 (如 Debian Testing/Sid 有时会有问题)，尝试 fallback
                if [ -z "$codename" ]; then
                    if [ "$OS_ID" == "debian" ]; then codename="bookworm"; fi
                    if [ "$OS_ID" == "ubuntu" ]; then codename="jammy"; fi
                fi
            fi
            
            local url=""
            local security_url=""
            
            # 定义源地址
            case $mirror_provider in
              1) # 阿里云
                 if [ "$OS_ID" == "debian" ]; then url="https://mirrors.aliyun.com/debian"; security_url="https://mirrors.aliyun.com/debian-security"; fi
                 if [ "$OS_ID" == "ubuntu" ]; then url="https://mirrors.aliyun.com/ubuntu"; security_url="https://mirrors.aliyun.com/ubuntu"; fi # Ubuntu security usually same base
                 ;;
              2) # 清华
                 if [ "$OS_ID" == "debian" ]; then url="https://mirrors.tuna.tsinghua.edu.cn/debian"; security_url="https://mirrors.tuna.tsinghua.edu.cn/debian-security"; fi
                 if [ "$OS_ID" == "ubuntu" ]; then url="https://mirrors.tuna.tsinghua.edu.cn/ubuntu"; security_url="https://mirrors.tuna.tsinghua.edu.cn/ubuntu"; fi
                 ;;
              3) # 腾讯
                 if [ "$OS_ID" == "debian" ]; then url="https://mirrors.cloud.tencent.com/debian"; security_url="https://mirrors.cloud.tencent.com/debian-security"; fi
                 if [ "$OS_ID" == "ubuntu" ]; then url="https://mirrors.cloud.tencent.com/ubuntu"; security_url="https://mirrors.cloud.tencent.com/ubuntu"; fi
                 ;;
              4) # 官方
                 if [ "$OS_ID" == "debian" ]; then url="http://deb.debian.org/debian"; security_url="http://security.debian.org/debian-security"; fi
                 if [ "$OS_ID" == "ubuntu" ]; then url="http://archive.ubuntu.com/ubuntu"; security_url="http://security.ubuntu.com/ubuntu"; fi
                 ;;
            esac

            # 备份
            cp /etc/apt/sources.list "/etc/apt/sources.list.bak.$(date +%Y%m%d%H%M%S)"
            
            echo -e "${CYAN}正在重写 sources.list (代号: $codename)...${RESET}"
            
            # 重写文件内容
            if [ "$OS_ID" == "debian" ]; then
                # Debian components
                # 检测是否为 testing/unstable 或者是新版 debian，加上 non-free-firmware
                local components="main contrib non-free"
                if [[ "$codename" == "bookworm" || "$codename" == "trixie" || "$codename" == "sid" ]]; then
                    components="main contrib non-free non-free-firmware"
                fi
                
                cat >/etc/apt/sources.list <<EOF
# Generated by VPS Script
deb $url $codename $components
deb $url $codename-updates $components
deb $url $codename-backports $components
deb $security_url $codename-security $components
EOF
            elif [ "$OS_ID" == "ubuntu" ]; then
                # Ubuntu components
                local components="main restricted universe multiverse"
                cat >/etc/apt/sources.list <<EOF
# Generated by VPS Script
deb $url $codename $components
deb $url $codename-updates $components
deb $url $codename-backports $components
deb $security_url $codename-security $components
EOF
            fi
            
            echo -e "${CYAN}>>> 更新 APT 缓存...${RESET}"
            check_pm_lock || return 1
            apt-get update

        # 处理 CentOS/RHEL (YUM/DNF)
        elif [[ "$PKG_MANAGER" == "yum" || "$PKG_MANAGER" == "dnf" ]]; then
            if [ "$mirror_provider" == "4" ]; then
               echo -e "${YELLOW}RHEL系系统暂不支持一键恢复默认源，建议手动恢复 /etc/yum.repos.d/ 下的备份${RESET}"
               read -p "按 Enter 继续..."
               continue
            fi

            local mirror_host=""
            case $mirror_provider in
               1) mirror_host="mirrors.aliyun.com" ;;
               2) mirror_host="mirrors.tuna.tsinghua.edu.cn" ;;
               3) mirror_host="mirrors.cloud.tencent.com" ;;
            esac

            echo -e "${CYAN}>>> 正在备份并替换 Repo 文件...${RESET}"
            mkdir -p /etc/yum.repos.d/backup
            cp /etc/yum.repos.d/*.repo /etc/yum.repos.d/backup/ 2>/dev/null
            
            sed -i -e "s|^mirrorlist=|#mirrorlist=|g" \
                   -e "s|^#baseurl=http://mirror.centos.org|baseurl=http://${mirror_host}|g" \
                   /etc/yum.repos.d/CentOS-*.repo 2>/dev/null
            
            echo -e "${GREEN}[√] Repo 文件修改尝试完毕${RESET}"
            echo -e "${CYAN}>>> 更新元数据缓存...${RESET}"
            check_pm_lock || return 1
            $PKG_UPDATE
        else
            echo -e "${RED}[!] 暂不支持此系统的软件源切换${RESET}"
        fi
        
        echo -e "${GREEN}[√] 切换完成${RESET}"
        read -p "按 Enter 继续..."
      done
      ;;
    2)
      ensure_docker || continue
      while true; do
        clear
        echo -e "${CYAN}>>> 切换 Docker 镜像源${RESET}"
        echo -e "当前 Docker 状态: ${GREEN}$(systemctl is-active docker)${RESET}"
        
        # --- 检测当前 Docker 源 ---
        docker_source="官方源 (Official)"
        if [ -f /etc/docker/daemon.json ]; then
            if grep -q "registry-mirrors" /etc/docker/daemon.json; then
                # 简单粗暴显示第一个镜像，或者直接显示“自定义”
                local first_mirror=$(grep -oP 'https://[^"]+' /etc/docker/daemon.json | head -1)
                if [ -n "$first_mirror" ]; then
                    docker_source="自定义/加速源 ($first_mirror ...)"
                else
                    docker_source="自定义配置 (Custom)"
                fi
            fi
        fi
        echo -e "当前检测源: ${YELLOW}$docker_source${RESET}"
        # ------------------------

        echo -e "${CYAN}--------------------------------------------------${RESET}"
        echo -e "  ${GREEN}1${RESET}) 设置/更新 国内加速镜像源 (DaoCloud/Proxy等)"
        echo -e "  ${GREEN}2${RESET}) ${RED}恢复 Docker 官方源 (清除加速配置)${RESET}"
        echo -e "  ${YELLOW}0.${RESET} 返回上一级"
        echo -e "${CYAN}==================================================${RESET}"
        
        read -p "请输入选项: " docker_choice
        case $docker_choice in
        1)
          mkdir -p /etc/docker
          if [ -f /etc/docker/daemon.json ]; then
            cp /etc/docker/daemon.json "/etc/docker/daemon.json.bak.$(date +%Y%m%d%H%M%S)"
          fi
          
          echo -e "${CYAN}写入加速源配置...${RESET}"
          cat >/etc/docker/daemon.json <<EOF
{
  "registry-mirrors": [
    "https://docker.m.daocloud.io",
    "https://dockerproxy.com",
    "https://mirror.baidubce.com",
    "https://docker.nju.edu.cn"
  ]
}
EOF
          echo -e "${GREEN}[√] 配置已更新${RESET}"
          echo -e "${CYAN}正在重启 Docker 服务...${RESET}"
          systemctl daemon-reload
          systemctl restart docker
          echo -e "${GREEN}[√] Docker 已重启生效${RESET}"
          read -p "按 Enter 继续..."
          ;;
        2)
          echo -e "${YELLOW}即将清除 Docker 镜像加速配置，恢复默认为官方源。${RESET}"
          read -p "确认执行吗? [y/N]: " confirm_reset
          if [[ "$confirm_reset" =~ ^[Yy]$ ]]; then
             if [ -f /etc/docker/daemon.json ]; then
                 mv /etc/docker/daemon.json "/etc/docker/daemon.json.bak.reset.$(date +%Y%m%d%H%M%S)"
                 echo -e "${GREEN}[√] 已备份并移除 daemon.json${RESET}"
                 
                 echo -e "${CYAN}正在重启 Docker 服务...${RESET}"
                 systemctl daemon-reload
                 systemctl restart docker
                 echo -e "${GREEN}[√] Docker 恢复官方源完成${RESET}"
             else
                 echo -e "${GRAY}未发现 daemon.json 配置文件，无需操作。${RESET}"
             fi
          else
             echo -e "${YELLOW}已取消${RESET}"
          fi
          read -p "按 Enter 继续..."
          ;;
        0) break ;; # 退出 Docker 子菜单
        *) 
          echo -e "${RED}无效选项${RESET}"
          sleep 1 
          ;;
        esac
      done
      ;;
    0) return 0 ;; # 返回主菜单
    *) ;;
    esac
  done
}

# --- [11. 核心] 主菜单逻辑 ---
while true; do
  show_menu
  SKIP_PAUSE=false

  read -p "请输入选项编号: " choice
  case $choice in
  # [板块 1] 系统运维
  1) system_upgrade ;;
  2) system_cleanup ;;
  3) manage_kernels ;;
  4) manage_swap ;;
  5) change_hostname ;;
  6) change_timezone ;;
  7) change_mirror ;;

  # [板块 2] 安全防护
  8) manage_ufw ;;
  9) manage_fail2ban ;;
  10) change_ssh_port ;;

  # [板块 3] 网络优化
  11) configure_network_static ;;
  12) manage_bbr ;;
  13) manage_tcp_tuning ;;
  14) manage_ipv6 ;;
  15) modify_dns ;;

  # [板块 4] 工具应用
  16) software_hub ;;
  17) manage_crontab ;;
  18) show_sys_monitor ;;

  # [板块 5] 性能测试
  19) stream_test ;;
  20) net_test ;;
  21) full_test ;;
  22) benchmark ;;

  # [板块 6] 系统控制
  23)
    echo -e "${YELLOW}即将重启系统...${RESET}"
    read -p "确认执行吗? [y/N]: " confirm
    [[ "$confirm" =~ ^[Yy]$ ]] && reboot
    ;;
  24)
    echo -e "${YELLOW}即将关机...${RESET}"
    read -p "确认执行吗? [y/N]: " confirm
    [[ "$confirm" =~ ^[Yy]$ ]] && poweroff
    ;;
  25)
    echo -e "${YELLOW}此操作将尝试缩小 VMware 虚拟机磁盘占用空间。${RESET}"
    echo -e "${YELLOW}提示: 过程可能耗时较长，请确保系统有足够运行时间。${RESET}"
    read -p "确认执行吗? [y/N]: " confirm
    if [[ "$confirm" =~ ^[Yy]$ ]]; then
      if command -v vmware-toolbox-cmd >/dev/null 2>&1 || [ -x /usr/bin/vmware-toolbox-cmd ]; then
        sudo /usr/bin/vmware-toolbox-cmd disk shrink /
      else
        echo -e "${RED}[!] 未找到 vmware-toolbox-cmd 命令，请确认是否安装了 open-vm-tools。${RESET}"
      fi
    fi
    ;;

  0)
    echo -e "${GREEN}已退出脚本，再见！${RESET}"
    exit 0
    ;;
  *)
    echo -e "${RED}[×] 无效选项，请重新输入${RESET}"
    SKIP_PAUSE=true
    sleep 1
    ;;
  esac

  if [ "$SKIP_PAUSE" = false ]; then
    echo -e ""
    read -p "按 Enter 返回主菜单..."
  fi
done