用shell脚本实现自动监控并封禁连接数超过阈值的IP
写一个 shell 脚本,创建脚本文件 /usr/local/bin/check_conn.sh
#!/bin/bash
if [[ $EUID -ne 0 ]]; then
echo "This script must be run as root." >&2
exit 1
fi
# 连接数阈值
THRESHOLD=50
# 白名单 IP(空格分隔)
WHITELIST_IPS="0.0.0.0 127.0.0.1"
# 日志文件
ABUSE_LOG="/var/log/conn_abuse.log"
# 封禁时间(秒)
BAN_TIME=86400
# 获取当前时间戳
NOW=$(date +%s)
echo "[$(date '+%Y-%m-%d %H:%M:%S')] iptables 定时任务执行" >> "$ABUSE_LOG"
# 统计连接数
netstat -ant | awk '{print $5}' | cut -d: -f1 | grep -Eo '([0-9]{1,3}\.){3}[0-9]{1,3}' | \
sort | uniq -c | sort -nr | while read count ip; do
echo "$ip $count"
# 过滤非法行或白名单 IP
[[ ! "$ip" =~ ^([0-9]{1,3}\.){3}[0-9]{1,3}$ ]] && continue
for white_ip in $WHITELIST_IPS; do
[[ "$ip" == "$white_ip" ]] && continue 2
done
# 判断是否超过阈值
if [[ "$count" -gt "$THRESHOLD" ]]; then
# 检查是否已被封禁
sudo iptables -L -n --line-numbers | grep "$ip"| grep DROP 2>/dev/null
if [[ $? -ne 0 ]]; then
echo "[$(date '+%Y-%m-%d %H:%M:%S')] Blocking $ip with $count connections" >> "$ABUSE_LOG"
echo "----$ip--------$count"
# 添加 iptables 封禁
iptables -I INPUT -s "$ip" -j DROP && echo "[debug]INPUT drop success for $ip" >> "$ABUSE_LOG"
iptables -I FORWARD -s "$ip" -j DROP && echo "[debug]FORWARD drop success for $ip" >> "$ABUSE_LOG"
iptables -I OUTPUT -d "$ip" -j DROP && echo "[debug]OUTPUT drop success for $ip" >> "$ABUSE_LOG"
# 强制断开现有连接(使用 conntrack 工具)
if command -v conntrack &>/dev/null; then
conntrack -D -s "$ip" && echo "[debug]conntrack -D -s $ip" >> "$ABUSE_LOG"
conntrack -D -d "$ip" && echo "[debug]conntrack -D -d $ip" >> "$ABUSE_LOG"
fi
# 设置定时任务自动解封
echo "iptables -D INPUT -s $ip -j DROP; iptables -D FORWARD -s $ip -j DROP; iptables -D OUTPUT -d $ip -j DROP" | \
at NOW + $((BAN_TIME / 60)) minutes 2>/dev/null
fi
fi
done
配合 cron
定时执行这个脚本:
*/2 * * * * /usr/local/bin/check_conn.sh
脚本功能介绍
-
定义变量:设置连接数阈值(200)、白名单IP、日志路径和封禁时间(24小时)。
-
统计连接数:使用
netstat
获取所有TCP连接,提取远程IP并统计连接数。 -
过滤白名单和本地IP:跳过白名单中的IP,并检查IP格式的有效性。
-
封禁处理:若IP连接数超过阈值且未被封禁,则通过
iptables
封禁,并记录日志。 -
断开现有连接:使用
conntrack
强制终止现有连接(如果可用)。 -
自动解封:使用
at
命令在封禁时间后移除iptables
规则。