#!/bin/sh
##############################################
# 一键配置 fail2ban - SSH 防暴力破解 (终端强交互版)
# 支持系统: Debian/Ubuntu, Alpine Linux
# 用法：sudo sh setup_fail2ban.sh
##############################################

# ========== 默认参数预设 ==========
DEFAULT_PORT="22"
MAXRETRY="3"                # 最大允许失败次数
BANTIME="24h"               # 封禁时长
FINDTIME="8h"               # 统计时间窗口
IGNORE_IP="127.0.0.1/8 ::1" # 白名单IP
# ==================================

# 1. 检查 root 权限
if [ "$(id -u)" -ne 0 ]; then
   echo "❌ 错误：请使用 root 用户或 sudo 运行此脚本。" 
   exit 1
fi

# 2. 系统类型检测
if [ -f /etc/os-release ]; then
    . /etc/os-release
    OS_TYPE=$ID
else
    echo "❌ 错误：无法识别操作系统，找不到 /etc/os-release。"
    exit 1
fi

echo "🔍 检测到系统类型: ${OS_TYPE}"

# 根据系统类型设置相应的变量
if [ "$OS_TYPE" = "debian" ] || [ "$OS_TYPE" = "ubuntu" ]; then
    PKG_UPDATE="apt update"
    PKG_INSTALL="apt install -y fail2ban"
    LOG_PATH="%(sshd_log)s"
    BACKEND="systemd"
    INIT_SYSTEM="systemd"
elif [ "$OS_TYPE" = "alpine" ]; then
    PKG_UPDATE="apk update"
    PKG_INSTALL="apk add fail2ban"
    LOG_PATH="/var/log/messages"
    BACKEND="auto"
    INIT_SYSTEM="openrc"
else
    echo "❌ 错误：此脚本目前仅支持 Debian/Ubuntu 或 Alpine 系统。"
    exit 1
fi

# 3. 交互式输入端口号 (强制读取物理终端，防止被跳过)
printf "⌨️  请输入需要监控的 SSH 端口号 [默认: %s] (多个请用逗号或空格分隔): " "$DEFAULT_PORT"
read INPUT_PORTS < /dev/tty

# 如果用户直接回车（输入为空），则使用默认端口
if [ -z "$INPUT_PORTS" ]; then
    SSH_PORTS=$DEFAULT_PORT
else
    SSH_PORTS=$INPUT_PORTS
fi

# 4. 智能格式化端口号 (将空格替换为逗号，并清理多余符号)
FORMATTED_PORTS=$(echo "$SSH_PORTS" | tr ' ' ',' | tr -s ',')
FORMATTED_PORTS=$(echo "$FORMATTED_PORTS" | sed 's/^,//;s/,$//')

echo "🚀 开始配置 fail2ban... (监控端口: ${FORMATTED_PORTS})"

# 5. 安装 fail2ban
if ! command -v fail2ban-client > /dev/null 2>&1; then
    echo "📦 正在安装 fail2ban..."
    $PKG_UPDATE && $PKG_INSTALL
else
    echo "✅ fail2ban 已安装，将更新配置。"
fi

# 6. 备份现有配置
if [ -f /etc/fail2ban/jail.local ]; then
    cp /etc/fail2ban/jail.local /etc/fail2ban/jail.local.bak.$(date +%Y%m%d%H%M%S)
    echo "📁 已备份原有 jail.local"
fi

# 7. 生成 jail.local 配置
cat > /etc/fail2ban/jail.local <<EOF
[DEFAULT]
ignoreip = ${IGNORE_IP}
bantime  = ${BANTIME}
findtime = ${FINDTIME}
maxretry = ${MAXRETRY}

[sshd]
enabled  = true
port     = ${FORMATTED_PORTS}
logpath  = ${LOG_PATH}
backend  = ${BACKEND}
maxretry = ${MAXRETRY}
findtime = ${FINDTIME}
bantime  = ${BANTIME}
EOF
echo "📝 已生成 /etc/fail2ban/jail.local"

# 8. 重启服务并设置开机自启
echo "🔄 正在重启服务..."
if [ "$INIT_SYSTEM" = "systemd" ]; then
    systemctl restart fail2ban
    systemctl enable fail2ban > /dev/null 2>&1
elif [ "$INIT_SYSTEM" = "openrc" ]; then
    if ! rc-service syslog status > /dev/null 2>&1; then
        echo "⚠️  检测到 syslog 未运行，正在尝试启动..."
        rc-update add syslog boot > /dev/null 2>&1
        rc-service syslog start
    fi
    rc-update add fail2ban default > /dev/null 2>&1
    rc-service fail2ban restart
fi

# 9. 检查 Jail 状态
echo "-------------------------------------"
echo "🛡️  SSH jail 状态："
fail2ban-client status sshd

echo "-------------------------------------"
echo "🎉 配置完成！当前运行在 ${OS_TYPE} 环境。"
echo "当前拦截策略："
echo "  监控端口      : ${FORMATTED_PORTS}"
echo "  最大重试次数  : ${MAXRETRY}"
echo "  封禁时长      : ${BANTIME}"
echo "  白名单IP      : ${IGNORE_IP}"