s-blog

Shell 脚本:根据访问日志自动封禁高频 IP

ssssmy · 2026-06-05 · 2 min · Linux

需求:根据 web 服务器访问日志,把请求量异常高的 IP 用 iptables 封禁;每隔半小时把不再请求或请求量很小的 IP 解封。一分钟内请求量高于 100 次的 IP 视为不正常。

#!/bin/bash
# 封 IP 函数
block_ip() {
    t1=`date -d "-1 min" +%Y:%H:%M`    # 上一分钟
    log=/data/logs/access_log

    # 截取上一分钟日志
    egrep "$t1:[0-9]+" $log > /tmp/tmp_last_min.log
    # 把访问超过 100 次的 IP 写入临时文件
    awk '{print $1}' /tmp/tmp_last_min.log | sort -n | uniq -c | sort -n | awk '$1>100 {print $2}' > /tmp/bad_ip.list

    n=`wc -l /tmp/bad_ip.list | awk '{print $1}'`
    if [ $n -ne 0 ]; then
        for ip in `cat /tmp/bad_ip.list`; do
            iptables -I INPUT -s $ip -j REJECT
        done
    fi
    rm -f /tmp/tmp_last_min.log /tmp/bad_ip.list
}

# 解封 IP 函数
unblock_ip() {
    # 包数少于 5 个的 IP 记入白名单
    iptables -nvL INPUT | sed '1d' | awk '$1<5 {print $8}' > /tmp/good_ip.list
    n=`wc -l /tmp/good_ip.list | awk '{print $1}'`
    if [ $n -ne 0 ]; then
        for ip in `cat /tmp/good_ip.list`; do
            iptables -D INPUT -s $ip -j REJECT
        done
    fi
    iptables -Z       # 清空计数器
    rm -f /tmp/good_ip.list
}

# 每隔半小时(分钟为 00 或 30)先解封再封,否则只封
t=`date +%M`
if [ $t == "00" ] || [ $t == "30" ]; then
    unblock_ip
    block_ip
else
    block_ip
fi

配合 crontab 每分钟执行一次。

原文链接:https://www.ssssmy.com/notes/shell-jiao-ben-gen-ju-fang-wen-ri-zhi-zi-dong-feng-jin-gao-pin-ip