Revise Fail2Ban SSH setup script for clarity and features

Refactor Fail2Ban SSH setup script with improved functionality and structure.
This commit is contained in:
Mr.Lin
2026-05-26 19:42:25 +08:00
committed by GitHub
parent 82375b31b6
commit e9e49a8d87
+620 -119
View File
@@ -1,99 +1,430 @@
#!/bin/bash #!/bin/bash
set -euo pipefail set -euo pipefail
# Debian 12/13 Fail2Ban SSH 硬化脚本(含旧版检测/卸载/迁移白名单/封禁测试排除自己公网IP) # Debian 12/13 Fail2Ban SSH 修复/安装脚本
#
# 功能:
# - 自动识别当前 SSH 客户端 IP,并加入 ignoreip,避免误封自己
# - 检测旧版 Fail2Ban,可选择修复、删除重装、仅检测、安全测试、紧急救援
# - 使用 systemd journal backend,避免 /var/log/auth.log 不存在
# - 使用 nftables 封禁
# - 启动后等待 fail2ban socket 和 sshd jail 真正 ready
# - 安全测试只封禁文档测试 IP 203.0.113.123,并立即解封
#
# 用法: # 用法:
# bash install-fail2ban-debian.sh # bash setup_f2b_fixed.sh
# 可选白名单: #
# IGNORE_IPS="127.0.0.1/8 ::1 你的固定IP" bash install-fail2ban-debian.sh # 可选:手动追加白名单 IP
# IGNORE_IPS="127.0.0.1/8 ::1 你的公网IP" bash setup_f2b_fixed.sh
if [ "$(id -u)" -ne 0 ]; then #
echo "请以 root 权限运行" # 救援模式:
exit 1 # bash setup_f2b_fixed.sh --rescue
fi #
# 修复模式:
# bash setup_f2b_fixed.sh --repair
#
# 状态检测:
# bash setup_f2b_fixed.sh --status
#
# 安全封禁测试:
# bash setup_f2b_fixed.sh --safe-test
CONF_FILE="/etc/fail2ban/jail.d/99-sshd-hardening.local" CONF_FILE="/etc/fail2ban/jail.d/99-sshd-hardening.local"
F2B_LOCAL="/etc/fail2ban/fail2ban.local" F2B_LOCAL="/etc/fail2ban/fail2ban.local"
TS="$(date +%Y%m%d-%H%M%S)" TS="$(date +%Y%m%d-%H%M%S)"
IGNORE_IPS="${IGNORE_IPS:-127.0.0.1/8 ::1}" BACKUP_DIR="/root/fail2ban-backup-${TS}"
# 获取当前公网 IP,用于封禁测试排除 DEFAULT_IGNORE_IPS="127.0.0.1/8 ::1"
PUB_IP=$(curl -s https://ifconfig.me || true) IGNORE_IPS="${IGNORE_IPS:-$DEFAULT_IGNORE_IPS}"
if [[ -n "$PUB_IP" ]]; then PRESERVED_IGNORE_IPS=""
echo "检测到当前公网 IP: $PUB_IP (封禁测试将自动排除)"
else
PUB_IP=""
echo "未能检测公网 IP,封禁测试需手动注意不要封自己的 IP"
fi
OLD_INSTALLED=false TEST_IP="203.0.113.123"
if command -v fail2ban-client >/dev/null 2>&1; then
OLD_INSTALLED=true
echo "检测到已有 Fail2Ban 安装"
read -p "是否删除旧版并安装新版本?(y/n) " yn
case "$yn" in
[Yy]* )
echo "停止 Fail2Ban 服务..."
systemctl stop fail2ban || true
echo "备份旧配置..." need_root() {
mkdir -p /root/fail2ban-backup-${TS} if [ "$(id -u)" -ne 0 ]; then
cp -r /etc/fail2ban/* /root/fail2ban-backup-${TS}/ || true echo "请以 root 权限运行"
echo "已备份到 /root/fail2ban-backup-${TS}/" exit 1
# 自动提取旧 sshd jail ignoreip
for OLD_FILE in /etc/fail2ban/jail.local /etc/fail2ban/jail.d/sshd.local; do
if [ -f "$OLD_FILE" ]; then
OLD_IGNORE=$(grep -E '^ignoreip' "$OLD_FILE" | awk -F= '{print $2}' | xargs || true)
if [ -n "$OLD_IGNORE" ]; then
echo "检测到旧 ignoreip: $OLD_IGNORE"
IGNORE_IPS="$IGNORE_IPS $OLD_IGNORE"
fi fi
}
dedupe_words() {
echo "$*" | tr ' ' '\n' | awk 'NF && !seen[$0]++' | paste -sd' ' -
}
get_ssh_client_ip() {
if [ -n "${SSH_CONNECTION:-}" ]; then
echo "$SSH_CONNECTION" | awk '{print $1}'
return 0
fi
if [ -n "${SSH_CLIENT:-}" ]; then
echo "$SSH_CLIENT" | awk '{print $1}'
return 0
fi
echo ""
}
collect_old_ignoreips() {
if [ ! -d /etc/fail2ban ]; then
return 0
fi
find /etc/fail2ban -type f \( -name "*.local" -o -name "*.conf" \) -print0 2>/dev/null |
while IFS= read -r -d '' file; do
awk '
/^[[:space:]]*ignoreip[[:space:]]*=/ {
val=$0
sub(/^[^=]*=/, "", val)
sub(/[[:space:]]*#.*/, "", val)
gsub(/^[[:space:]]+|[[:space:]]+$/, "", val)
if (val != "") print val
}
' "$file"
done | tr '\n' ' '
}
backup_fail2ban_config() {
if [ -d /etc/fail2ban ]; then
echo "正在备份旧配置到:$BACKUP_DIR"
mkdir -p "$BACKUP_DIR"
cp -a /etc/fail2ban/. "$BACKUP_DIR/" 2>/dev/null || true
echo "备份完成:$BACKUP_DIR"
else
echo "未发现 /etc/fail2ban,跳过备份。"
fi
}
detect_ssh_unit() {
if systemctl cat ssh.service >/dev/null 2>&1; then
echo "ssh.service"
return 0
fi
if systemctl cat sshd.service >/dev/null 2>&1; then
echo "sshd.service"
return 0
fi
echo "ssh.service"
}
detect_ssh_ports() {
local sshd_bin=""
if command -v sshd >/dev/null 2>&1; then
sshd_bin="$(command -v sshd)"
elif [ -x /usr/sbin/sshd ]; then
sshd_bin="/usr/sbin/sshd"
fi
if [ -n "$sshd_bin" ]; then
"$sshd_bin" -T 2>/dev/null | awk '$1 == "port" {print $2}' | paste -sd, - || true
fi
}
clear_fail2ban_nftables() {
if ! command -v nft >/dev/null 2>&1; then
echo "未检测到 nft 命令,跳过 nftables 清理。"
return 0
fi
echo "正在清理 Fail2Ban 相关 nftables 表..."
nft list tables 2>/dev/null |
awk 'tolower($0) ~ /f2b|fail2ban/ {print $2, $3}' |
while read -r family table; do
if [ -n "${family:-}" ] && [ -n "${table:-}" ]; then
echo "删除 nftables 表:$family $table"
nft delete table "$family" "$table" 2>/dev/null || true
fi fi
done done
}
echo "卸载 Fail2Ban..." rescue_fail2ban() {
apt-get remove --purge -y fail2ban echo
rm -rf /etc/fail2ban echo "========== 紧急救援模式 =========="
;; echo "将停止并禁用 Fail2Ban,同时清理 Fail2Ban nftables 表。"
* )
echo "保留旧版 Fail2Ban"
echo "检测当前 sshd jail 状态:"
fail2ban-client status sshd || echo "未启用 sshd jail 或旧版不支持 systemd backend"
echo "查看旧封禁 IP(如有):"
fail2ban-client status sshd | grep "Banned IPs" || echo "无已封禁 IP"
exit 0
;;
esac
fi
echo "安装 Fail2Ban 与 nftables..." local ssh_client_ip
export DEBIAN_FRONTEND=noninteractive ssh_client_ip="$(get_ssh_client_ip)"
apt-get update
apt-get install -y fail2ban nftables python3-systemd
echo "检测 SSH 端口..." if command -v fail2ban-client >/dev/null 2>&1; then
SSHD_PORTS="$(sshd -T 2>/dev/null | awk '$1 == "port" {print $2}' | paste -sd, - || true)" if [ -n "$ssh_client_ip" ]; then
SSHD_PORTS="${SSHD_PORTS:-22}" echo "尝试解封当前 SSH 客户端 IP$ssh_client_ip"
echo "SSH 端口:${SSHD_PORTS}" fail2ban-client set sshd unbanip "$ssh_client_ip" 2>/dev/null || true
fi
echo "备份已有配置(如果存在)..." echo "尝试执行全局解封..."
[ -f "$CONF_FILE" ] && cp "$CONF_FILE" "${CONF_FILE}.bak.${TS}" fail2ban-client unban --all 2>/dev/null || true
[ -f "$F2B_LOCAL" ] && cp "$F2B_LOCAL" "${F2B_LOCAL}.bak.${TS}" fi
mkdir -p /etc/fail2ban/jail.d
echo "写入 Debian 12/13 兼容配置:$CONF_FILE" echo "停止 Fail2Ban..."
cat > "$CONF_FILE" <<EOF systemctl stop fail2ban 2>/dev/null || true
echo "禁用 Fail2Ban 开机启动..."
systemctl disable fail2ban 2>/dev/null || true
echo "清理旧 socket 文件..."
rm -f /run/fail2ban/fail2ban.sock
rm -f /var/run/fail2ban/fail2ban.sock
clear_fail2ban_nftables
echo
echo "救援完成。"
echo "现在可以重新尝试 SSH 登录。"
echo "恢复后建议运行:"
echo " bash setup_f2b_fixed.sh --repair"
echo "=================================="
echo
}
wait_fail2ban_ready() {
local timeout="${1:-45}"
local i=0
echo
echo "正在等待 Fail2Ban 完全启动,最多等待 ${timeout} 秒..."
while [ "$i" -lt "$timeout" ]; do
if systemctl is-active --quiet fail2ban; then
if fail2ban-client ping >/dev/null 2>&1; then
if fail2ban-client status sshd >/dev/null 2>&1; then
echo "Fail2Ban 已启动,socket 正常,sshd jail 已加载。"
return 0
fi
fi
fi
sleep 1
i=$((i + 1))
done
echo
echo "Fail2Ban 未能在 ${timeout} 秒内完全 ready。"
echo
echo "systemd 状态:"
systemctl status fail2ban --no-pager -l || true
echo
echo "socket 检测:"
if [ -S /run/fail2ban/fail2ban.sock ]; then
echo "socket 存在:/run/fail2ban/fail2ban.sock"
elif [ -S /var/run/fail2ban/fail2ban.sock ]; then
echo "socket 存在:/var/run/fail2ban/fail2ban.sock"
else
echo "socket 不存在。"
fi
echo
echo "fail2ban-client ping"
fail2ban-client ping || true
echo
echo "fail2ban-client status"
fail2ban-client status || true
echo
echo "最近 Fail2Ban 日志:"
journalctl -u fail2ban -n 100 --no-pager || true
return 1
}
show_fail2ban_status() {
echo
echo "========== Fail2Ban 当前状态 =========="
if ! command -v fail2ban-client >/dev/null 2>&1; then
echo "未检测到 fail2ban-client。"
echo "======================================"
return 0
fi
echo
echo "[1/4] systemd 服务状态:"
if systemctl is-active --quiet fail2ban; then
echo "systemd: active"
else
echo "systemd: inactive 或 failed"
fi
systemctl status fail2ban --no-pager -l || true
echo
echo "[2/4] socket 检测:"
if [ -S /run/fail2ban/fail2ban.sock ]; then
echo "socket 存在:/run/fail2ban/fail2ban.sock"
elif [ -S /var/run/fail2ban/fail2ban.sock ]; then
echo "socket 存在:/var/run/fail2ban/fail2ban.sock"
else
echo "socket 不存在:/run/fail2ban/fail2ban.sock"
echo "这通常表示 Fail2Ban 还没初始化完成,或启动后又异常退出。"
fi
echo
echo "[3/4] fail2ban-client ping"
if fail2ban-client ping >/dev/null 2>&1; then
fail2ban-client ping
else
echo "fail2ban-client 无法连接 socket。"
fi
echo
echo "[4/4] jail 状态:"
if fail2ban-client status >/dev/null 2>&1; then
fail2ban-client status
local jails
jails="$(fail2ban-client status 2>/dev/null | sed -n 's/.*Jail list:[[:space:]]*//p' | tr ',' ' ' | xargs || true)"
if [ -n "$jails" ]; then
for jail in $jails; do
echo
echo "---------- jail: $jail ----------"
fail2ban-client status "$jail" 2>/dev/null || true
done
fi
else
echo "Fail2Ban 服务可能 active,但 client/socket 尚不可用。"
echo
echo "最近 Fail2Ban 日志:"
journalctl -u fail2ban -n 80 --no-pager || true
fi
echo "======================================"
echo
}
fix_fail2ban_startup() {
echo
echo "开始修复 Fail2Ban 启动/socket 状态..."
if ! command -v fail2ban-client >/dev/null 2>&1; then
echo "未检测到 fail2ban-client,请先安装 Fail2Ban。"
return 1
fi
echo "停止 Fail2Ban..."
systemctl stop fail2ban 2>/dev/null || true
echo "清理旧 socket 文件..."
rm -f /run/fail2ban/fail2ban.sock
rm -f /var/run/fail2ban/fail2ban.sock
echo "测试配置..."
fail2ban-client -t
echo "重新启动 Fail2Ban..."
systemctl start fail2ban
wait_fail2ban_ready 45
echo "启动/socket 状态修复完成。"
}
install_packages() {
echo "正在安装 Fail2Ban 与 nftables..."
export DEBIAN_FRONTEND=noninteractive
apt-get update
apt-get install -y fail2ban nftables python3-systemd
echo "安装完成后先停止 Fail2Ban,等待写入安全配置后再启动..."
systemctl stop fail2ban 2>/dev/null || true
rm -f /run/fail2ban/fail2ban.sock
rm -f /var/run/fail2ban/fail2ban.sock
}
write_fail2ban_config() {
local ssh_client_ip
local old_ignore
local ssh_ports
local ssh_unit
local manual_ip=""
ssh_client_ip="$(get_ssh_client_ip)"
old_ignore="$(collect_old_ignoreips || true)"
if [ -n "$PRESERVED_IGNORE_IPS" ]; then
echo "检测到删除前保留的旧 ignoreip:$PRESERVED_IGNORE_IPS"
IGNORE_IPS="$IGNORE_IPS $PRESERVED_IGNORE_IPS"
fi
if [ -n "$old_ignore" ]; then
echo "检测到当前配置中的 ignoreip$old_ignore"
IGNORE_IPS="$IGNORE_IPS $old_ignore"
fi
if [ -n "$ssh_client_ip" ]; then
echo "检测到当前 SSH 客户端 IP$ssh_client_ip"
echo "会自动加入 ignoreip,避免误封当前登录来源。"
IGNORE_IPS="$IGNORE_IPS $ssh_client_ip"
else
echo "未检测到 SSH_CONNECTION,可能不是通过 SSH 执行。"
echo "强烈建议手动指定白名单,例如:"
echo ' IGNORE_IPS="127.0.0.1/8 ::1 你的公网IP" bash setup_f2b_fixed.sh'
echo
read -r -t 20 -p "请输入要追加的白名单 IP,留空跳过,20 秒后自动跳过:" manual_ip || true
manual_ip="${manual_ip:-}"
if [ -n "$manual_ip" ]; then
IGNORE_IPS="$IGNORE_IPS $manual_ip"
fi
fi
IGNORE_IPS="$(dedupe_words "$IGNORE_IPS")"
ssh_ports="$(detect_ssh_ports)"
ssh_ports="${ssh_ports:-22}"
ssh_unit="$(detect_ssh_unit)"
echo
echo "SSH 端口:$ssh_ports"
echo "SSH systemd unit$ssh_unit"
echo "最终 ignoreip$IGNORE_IPS"
echo
mkdir -p /etc/fail2ban/jail.d
if [ -f "$CONF_FILE" ]; then
cp "$CONF_FILE" "${CONF_FILE}.bak.${TS}"
fi
if [ -f "$F2B_LOCAL" ]; then
cp "$F2B_LOCAL" "${F2B_LOCAL}.bak.${TS}"
fi
echo "写入 SSH jail 配置:$CONF_FILE"
cat > "$CONF_FILE" <<EOF
[DEFAULT] [DEFAULT]
ignoreip = ${IGNORE_IPS} ignoreip = ${IGNORE_IPS}
# 使用 systemd journal,避免 /var/log/auth.log 不存在
backend = systemd backend = systemd
# 使用 nftables
banaction = nftables-multiport banaction = nftables-multiport
banaction_allports = nftables-allports banaction_allports = nftables-allports
allowipv6 = auto
# 避免反向 DNS 查询拖慢
usedns = no usedns = no
# 基础封禁时间:10 天
bantime = 10d bantime = 10d
# 统计窗口:1 小时
findtime = 1h findtime = 1h
# 1 小时内失败 3 次即封禁
maxretry = 3 maxretry = 3
# 阶梯式封禁
bantime.increment = true bantime.increment = true
bantime.factor = 1 bantime.factor = 1
bantime.maxtime = 20w bantime.maxtime = 20w
@@ -101,75 +432,245 @@ bantime.rndtime = 10m
[sshd] [sshd]
enabled = true enabled = true
port = ${SSHD_PORTS} port = ${ssh_ports}
filter = sshd[mode=aggressive] filter = sshd[mode=aggressive]
journalmatch = _SYSTEMD_UNIT=ssh.service + _COMM=sshd
# Debian 通常是 ssh.service;部分系统可能是 sshd.service
journalmatch = _SYSTEMD_UNIT=${ssh_unit}
EOF EOF
echo "写入 Fail2Ban 本地配置:$F2B_LOCAL" echo "写入 Fail2Ban 本地配置:$F2B_LOCAL"
cat > "$F2B_LOCAL" <<EOF
cat > "$F2B_LOCAL" <<EOF
[Definition] [Definition]
# IPv6 自动处理。写在 fail2ban.local,可避免 allowipv6 警告。
allowipv6 = auto
# 为阶梯式封禁保留更久历史记录
dbpurgeage = 180d dbpurgeage = 180d
EOF EOF
echo "测试 Fail2Ban 配置..." echo
fail2ban-client -t echo "测试 Fail2Ban 配置..."
fail2ban-client -t
echo "启用并重启 Fail2Ban..." echo
systemctl enable --now fail2ban echo "启用并重启 Fail2Ban..."
systemctl restart fail2ban systemctl enable fail2ban
systemctl restart fail2ban
echo "------------------------------------------------" wait_fail2ban_ready 45
echo "安装与配置完成!"
echo "已合并旧版白名单,当前 ignoreip: $IGNORE_IPS"
echo "查看 sshd jail 状态: fail2ban-client status sshd"
echo "查看 nftables 封禁规则: nft list ruleset | grep -i f2b -A20"
echo "查看 Fail2Ban 日志: journalctl -u fail2ban -n 100 --no-pager"
echo "------------------------------------------------"
# 自动封禁测试(排除当前公网 IP echo
read -p "是否进行自动封禁测试?(y/n) " testyn echo "修复/安装完成。"
if [[ "$testyn" =~ ^[Yy] ]]; then echo "当前 ignoreip$IGNORE_IPS"
NUM_IP=3 echo
echo "抓取最近 $NUM_IP 个失败登录 IP ..." }
FAILED_IPS=$(journalctl -u ssh.service -p err --no-pager \
| grep "Failed password" \
| awk '{for(i=1;i<=NF;i++){if($i ~ /^[0-9]+\.[0-9]+\.[0-9]+\.[0-9]+$/){print $i}}}' \
| sort | uniq -c | sort -nr | awk '{print $2}' | head -n $NUM_IP)
if [ -z "$FAILED_IPS" ]; then safe_ban_test() {
echo "未找到失败登录 IP,建议手动尝试几次错误密码登录后再测试" echo
exit 0 echo "========== 安全封禁测试 =========="
echo "测试 IP$TEST_IP"
echo "说明:这是文档测试网段,不是你的真实 IP。测试后会立即解封。"
if ! command -v fail2ban-client >/dev/null 2>&1; then
echo "fail2ban-client 不存在,无法测试。"
echo "================================="
return 0
fi fi
# 排除当前公网 IP if ! systemctl is-active --quiet fail2ban; then
SAFE_IPS="" echo "Fail2Ban 当前未运行,尝试启动..."
for IP in $FAILED_IPS; do systemctl start fail2ban || true
if [[ "$IP" == "$PUB_IP" ]]; then wait_fail2ban_ready 45 || true
echo "跳过封禁当前公网 IP: $IP" fi
if ! fail2ban-client status sshd >/dev/null 2>&1; then
echo "sshd jail 不存在或未启动,无法测试。"
echo "请先确认:fail2ban-client status sshd"
echo "================================="
return 0
fi
echo
echo "执行测试封禁..."
fail2ban-client set sshd banip "$TEST_IP" || true
echo
echo "封禁后 sshd jail 状态:"
fail2ban-client status sshd || true
echo
echo "立即解封测试 IP..."
fail2ban-client set sshd unbanip "$TEST_IP" || true
echo
echo "解封后 sshd jail 状态:"
fail2ban-client status sshd || true
echo
echo "安全封禁测试完成。"
echo "================================="
echo
}
ask_safe_test() {
echo
local testyn=""
read -r -t 20 -p "是否进行安全封禁测试?只封测试 IP ${TEST_IP} 并立即解封。[y/N] " testyn || true
testyn="${testyn:-n}"
if [[ "$testyn" =~ ^[Yy]$ ]]; then
safe_ban_test
else else
SAFE_IPS="$SAFE_IPS $IP" echo "已跳过安全封禁测试。"
fi fi
done }
if [[ -z "$SAFE_IPS" ]]; then repair_current_install() {
echo "没有可封禁的测试 IP(都被排除掉了),跳过封禁测试" echo
echo "准备修复当前 Fail2Ban 配置,不删除软件包..."
backup_fail2ban_config
echo "先停止 Fail2Ban,避免修复过程中误封当前连接..."
systemctl stop fail2ban 2>/dev/null || true
rm -f /run/fail2ban/fail2ban.sock
rm -f /var/run/fail2ban/fail2ban.sock
if ! command -v fail2ban-client >/dev/null 2>&1; then
install_packages
else
echo "确保 nftables 与 python3-systemd 已安装..."
export DEBIAN_FRONTEND=noninteractive
apt-get install -y nftables python3-systemd || true
fi
write_fail2ban_config
}
remove_and_reinstall() {
echo
echo "准备删除旧版 Fail2Ban 并重新安装..."
PRESERVED_IGNORE_IPS="$(collect_old_ignoreips || true)"
if [ -n "$PRESERVED_IGNORE_IPS" ]; then
echo "已保存旧版 ignoreip$PRESERVED_IGNORE_IPS"
fi
backup_fail2ban_config
echo "停止 Fail2Ban..."
systemctl stop fail2ban 2>/dev/null || true
echo "卸载 Fail2Ban..."
apt-get remove --purge -y fail2ban || true
echo "清理旧配置目录..."
rm -rf /etc/fail2ban
rm -f /run/fail2ban/fail2ban.sock
rm -f /var/run/fail2ban/fail2ban.sock
install_packages
write_fail2ban_config
}
main_menu() {
local ssh_client_ip
ssh_client_ip="$(get_ssh_client_ip)"
echo
echo "========== Fail2Ban SSH 修复/安装脚本 =========="
if [ -n "$ssh_client_ip" ]; then
echo "当前 SSH 客户端 IP$ssh_client_ip"
echo "该 IP 会自动加入 ignoreip。"
else
echo "未检测到当前 SSH 客户端 IP。"
echo "建议运行时手动指定 IGNORE_IPS。"
fi
echo "================================================"
echo
if command -v fail2ban-client >/dev/null 2>&1; then
echo "检测到系统已安装 Fail2Ban。"
echo
echo "请选择操作:"
echo " 1) 修复当前安装,不删除旧版,推荐"
echo " 2) 删除旧版 Fail2Ban 后重新安装"
echo " 3) 保留旧版,只检测状态,并可安全封禁测试"
echo " 4) 紧急救援:停止/禁用 Fail2Ban 并清理 Fail2Ban nftables 表"
echo " 5) 修复 Fail2Ban 启动/socket 状态"
echo " 0) 退出"
echo
local choice=""
read -r -p "请输入选项 [1/2/3/4/5/0],默认 1" choice
choice="${choice:-1}"
case "$choice" in
1)
repair_current_install
show_fail2ban_status
ask_safe_test
;;
2)
remove_and_reinstall
show_fail2ban_status
ask_safe_test
;;
3)
show_fail2ban_status
ask_safe_test
;;
4)
rescue_fail2ban
;;
5)
fix_fail2ban_startup
show_fail2ban_status
;;
0)
echo "已退出。"
exit 0 exit 0
;;
*)
echo "无效选项,退出。"
exit 1
;;
esac
else
echo "未检测到 Fail2Ban,将进行全新安装。"
install_packages
write_fail2ban_config
show_fail2ban_status
ask_safe_test
fi fi
}
echo "将封禁以下测试 IP $SAFE_IPS" need_root
for IP in $SAFE_IPS; do
echo "模拟封禁 IP: $IP"
fail2ban-client set sshd banip $IP
done
echo case "${1:-}" in
echo "查看 sshd jail 状态:" --rescue)
fail2ban-client status sshd rescue_fail2ban
exit 0
;;
--repair)
repair_current_install
show_fail2ban_status
ask_safe_test
exit 0
;;
--status)
show_fail2ban_status
exit 0
;;
--safe-test)
safe_ban_test
exit 0
;;
esac
echo main_menu
echo "如需解封测试 IP,可运行:"
for IP in $SAFE_IPS; do
echo " fail2ban-client set sshd unbanip $IP"
done
fi