流量监控脚本+只允许中国IP访问
功能简介
本教程分为两个脚本,可单独使用或组合使用。
流量监控脚本
该脚本可用于监控Linux服务器的网络流量,并根据设定的流量阈值自动执行相应操作:
- 流量达到限制时,仅允许SSH(端口22)访问;
- 流量达到更高阈值时,自动关机;
- 支持每日自动流量重置;
- 支持多种流量检查方式。
所有参数均为可选,未指定时将使用默认值。
参数说明
| 参数名 | 作用说明 | 默认值 |
|---|---|---|
| LIMIT\_GB | 流量限制(仅允许SSH),单位GB | 190 |
| LIMIT\_GB\_POWEROFF | 流量限制(达到阈值关机),单位GB | 195 |
| reset\_day | 流量重置日(每月第几天重置) | 1 |
| CHECK\_TYPE | 流量检查类型(见下方详细说明) | 3 |
| INTERFACE | 网络接口(如 eth0),默认自动检测 | 系统默认 |
流量检查类型说明:
- 1:只检查上传流量
- 2:只检查下载流量
- 3:检查上传和下载流量中的最大值
- 4:检查上传和下载流量的总和
依赖安装
脚本运行需依赖以下工具:
- vnstat:网络流量监控工具
- iptables:Linux防火墙配置工具
- bc:任意精度计算器语言
说明:
- -y 参数表示在安装过程中自动回答所有提示为 'yes'
Debian/Ubuntu系统:
apt update && apt install -y iptables bc vnstatCentOS/RPM系统:
yum update && yum install iptables bc vnstat创建脚本文件并编辑
以 /root/ 目录为例,脚本名建议设置为 traffic\_monitor.sh。
cd /root && vim traffic_monitor.sh脚本源码示例
以下为完整脚本源码,建议根据实际需求修改部分参数(如Bark通知KEY等)。
#!/bin/bash
LIMIT_GB=${1:-1950}
LIMIT_GB_POWEROFF=${2:-1980}
reset_day=${3:-1}
CHECK_TYPE=${4:-3}
INTERFACE=${5:-$(ip route | grep default | awk '{print $5}')}
LIMIT=$(echo "$LIMIT_GB * 1024" | bc)
LIMIT_POWEROFF=$(echo "$LIMIT_GB_POWEROFF * 1024" | bc)
echo "防火墙流量限制:$LIMIT MiB"
echo "关机流量限制:$LIMIT_POWEROFF MiB"
echo "流量将在每月的第 $reset_day 天重置"
current_day=$(date +'%-d')
last_day_of_month=$(date -d "$(date +'%Y%m01') +1 month -1 day" +%d)
# Bark设备的服务器地址及唯一key,需要替换成你自己的服务器地址及key
BARK_KEY="http://api.day.app/xxxxxxxxxxxxx"
# 流量达到阈值时创建临时文件目录
NOTIFY_FILE="/tmp/traffic_limit_notified"
if [ "$current_day" -eq "$reset_day" ] || ([ "$reset_day" -gt "$last_day_of_month" ] && [ "$current_day" -eq "$last_day_of_month" ]); then
if [ ! -f "/tmp/vnstat_reset" ]; then
touch /tmp/vnstat_reset
rm /var/lib/vnstat/*
sudo systemctl restart vnstat
echo "流量已经重置,下次重置将在下个月的第 $reset_day 天"
else
echo "今天已经进行过流量重置,无需再次重置"
fi
else
if [ -f "/tmp/vnstat_reset" ]; then
rm /tmp/vnstat_reset
fi
if [ "$current_day" -lt "$reset_day" ]; then
days_until_reset=$(($reset_day - $current_day))
echo "还有 $days_until_reset 天流量将会重置"
else
days_until_reset=$(( $last_day_of_month - $current_day + $reset_day ))
echo "还有 $days_until_reset 天流量将会重置"
fi
fi
if [ -z "$INTERFACE" ]; then
echo "错误:无法自动检测网络接口。请手动指定。"
exit 1
fi
echo "正在监控的网络接口:$INTERFACE"
DATA=$(vnstat -i $INTERFACE --oneline)
CURRENT_DATE=$(echo $DATA | cut -d ';' -f 8)
TRAFFIC_RX=$(echo $DATA | cut -d ';' -f 13 | tr -d ' ' | sed 's/MiB//;s/GiB/*1024/;s/KiB/\/1024/' | bc)
TRAFFIC_TX=$(echo $DATA | cut -d ';' -f 14 | tr -d ' ' | sed 's/MiB//;s/GiB/*1024/;s/KiB/\/1024/' | bc)
echo "当前月份:$CURRENT_DATE"
if [ "$CHECK_TYPE" = "1" ]; then
TRAFFIC_TO_CHECK=$TRAFFIC_TX
echo "只检查上传流量。当前上传流量为:$TRAFFIC_TX MiB。"
elif [ "$CHECK_TYPE" = "2" ]; then
TRAFFIC_TO_CHECK=$TRAFFIC_RX
echo "只检查下载流量。当前下载流量为:$TRAFFIC_RX MiB。"
elif [ "$CHECK_TYPE" = "3" ]; then
TRAFFIC_TO_CHECK=$(echo "$TRAFFIC_TX $TRAFFIC_RX" | awk '{print ($1>$2)?$1:$2}')
if [ "$TRAFFIC_TO_CHECK" = "$TRAFFIC_TX" ]; then
echo "当前上传流量为:$TRAFFIC_TX MiB,下载流量为:$TRAFFIC_RX MiB。"
echo "当前最大的流量是:上传流量。"
else
echo "当前上传流量为:$TRAFFIC_TX MiB,下载流量为:$TRAFFIC_RX MiB。"
echo "当前最大的流量是:下载流量。"
fi
elif [ "$CHECK_TYPE" = "4" ]; then
TRAFFIC_TO_CHECK=$(echo "$TRAFFIC_TX + $TRAFFIC_RX" | bc)
echo "检查上传和下载流量的总和。当前上传流量为:$TRAFFIC_TX MiB,下载流量为:$TRAFFIC_RX MiB。"
echo "上传和下载流量的总和($TRAFFIC_TO_CHECK MiB)。"
else
echo "错误:未提供有效的流量检查参数。参数应为1(只检查上传流量)、2(只检查下载流量)、3(检查上传和下载流量中的最大值)或4(检查上传和下载流量的总和)。"
exit 1
fi
# 固定时间发送当前流量通知
send_daily_traffic_notification() {
local current_hour=$(date +'%H')
local current_minute=$(date +'%M')
# 检查当前时间是否为 18:00
if [ "$current_hour" -eq "18" ] && [ "$current_minute" -eq "00" ]; then
local TRAFFIC_RX_MB=$(echo "scale=2; $TRAFFIC_RX / 1024" | bc)
local TRAFFIC_TX_MB=$(echo "scale=2; $TRAFFIC_TX / 1024" | bc)
curl -s -X POST "${BARK_KEY}/华为SG111/每日流量汇报:当前上传流量为%20$TRAFFIC_TX_MB%20GiB,下载流量为%20$TRAFFIC_RX_MB%20GiB。?group=VPS&icon=https://pic2.ziyuan.wang/user/biu/2024/09/icon_cloud_cfb765ae0df8b.jpg"
echo "每日流量通知已发送:上传流量 $TRAFFIC_TX_MB GiB,下载流量 $TRAFFIC_RX_MB GiB。"
fi
}
# 调用函数发送流量通知
send_daily_traffic_notification
if (( $(echo "$TRAFFIC_TO_CHECK > $LIMIT" | bc -l) )); then
if [ ! -f "$NOTIFY_FILE" ]; then
curl -s -X POST "${BARK_KEY}/华为SG111/警告:流量已超出限制!除SSH(端口22)外,所有端口已被阻止!?group=VPS&icon=https://pic2.ziyuan.wang/user/biu/2024/09/icon_cloud_cfb765ae0df8b.jpg"
echo "已发送流量超出通知。"
touch "$NOTIFY_FILE" # 创建通知文件,避免重复发送
else
echo "流量超出通知已发送,不再重复发送。"
fi
# --- 修改部分:流量超限开启“铁桶阵” ---
BLOCK_CHAIN="STRICT_TRAFFIC_BLOCK"
/usr/sbin/iptables -N "$BLOCK_CHAIN" 2>/dev/null
/usr/sbin/iptables -F "$BLOCK_CHAIN"
/usr/sbin/iptables -A "$BLOCK_CHAIN" -i lo -j ACCEPT
/usr/sbin/iptables -A "$BLOCK_CHAIN" -o lo -j ACCEPT
/usr/sbin/iptables -A "$BLOCK_CHAIN" -p tcp --dport 22 -j ACCEPT
/usr/sbin/iptables -A "$BLOCK_CHAIN" -p tcp --sport 22 -j ACCEPT
/usr/sbin/iptables -A "$BLOCK_CHAIN" -j DROP
/usr/sbin/iptables -C INPUT -j "$BLOCK_CHAIN" 2>/dev/null || /usr/sbin/iptables -I INPUT 1 -j "$BLOCK_CHAIN"
/usr/sbin/iptables -C OUTPUT -j "$BLOCK_CHAIN" 2>/dev/null || /usr/sbin/iptables -I OUTPUT 1 -j "$BLOCK_CHAIN"
/usr/sbin/iptables -C FORWARD -j "$BLOCK_CHAIN" 2>/dev/null || /usr/sbin/iptables -I FORWARD 1 -j "$BLOCK_CHAIN"
# ----------------------------------------------------------
echo "警告:流量已超出限制!除SSH(端口22)外,所有端口已被阻止。"
else
if [ -f "$NOTIFY_FILE" ]; then
rm "$NOTIFY_FILE" # 如果流量回到限制内,删除通知文件
curl -s -X POST "${BARK_KEY}/华为SG111/警告:流量已回到限制内!放开所有限制!?group=VPS&icon=https://pic2.ziyuan.wang/user/biu/2024/09/icon_cloud_cfb765ae0df8b.jpg"
echo "流量已回到限制内,移除通知文件。"
fi
# --- 修改部分:流量恢复正常,撤销拦截开关,执行防护脚本 ---
BLOCK_CHAIN="STRICT_TRAFFIC_BLOCK"
/usr/sbin/iptables -D INPUT -j "$BLOCK_CHAIN" 2>/dev/null
/usr/sbin/iptables -D OUTPUT -j "$BLOCK_CHAIN" 2>/dev/null
/usr/sbin/iptables -D FORWARD -j "$BLOCK_CHAIN" 2>/dev/null
/usr/sbin/iptables -F "$BLOCK_CHAIN" 2>/dev/null
/usr/sbin/iptables -X "$BLOCK_CHAIN" 2>/dev/null
# 执行同目录下的地区防护脚本
SCRIPT_DIR=$(cd $(dirname $0); pwd)
FIREWALL_SCRIPT="$SCRIPT_DIR/secure_firewall.sh"
if [ -f "$FIREWALL_SCRIPT" ]; then
bash "$FIREWALL_SCRIPT" > /dev/null
echo "流量在限制内,已应用地区防护规则。"
else
echo "流量在设定的限制内,所有流量都被允许。"
fi
# ----------------------------------------------------------
fi
if (( $(echo "$TRAFFIC_TO_CHECK > $LIMIT_POWEROFF" | bc -l) )); then
curl -s -X POST "${BARK_KEY}/华为SG111/警告:流量已超出最大限制!将立即关机!?group=VPS&icon=https://pic2.ziyuan.wang/user/biu/2024/09/icon_cloud_cfb765ae0df8b.jpg"
echo "已发送流量超出通知。"
echo "警告:流量已超出限制!立即关机"
/usr/sbin/shutdown -h now
fi脚本权限设置
运行前需为脚本添加执行权限:
chmod +x traffic_monitor.sh使用示例
- 使用所有默认参数运行:
./traffic_monitor.sh- 设置流量限制为500GB,其他参数默认:
./traffic_monitor.sh 500- 设置流量限制为500GB,关机阈值510GB,每月10号重置:
./traffic_monitor.sh 500 510 10- 设置流量限制为500GB,关机阈值510GB,每月10号重置,只检查下载流量,并指定网络接口为eth0:
./traffic_monitor.sh 500 510 10 2 eth0自动定时运行
可通过 crontab 实现脚本定时运行。例如每分钟执行一次,并将脚本输出重定向到 /root/traffic\_monitor.log 文件:
(crontab -l ; echo "* * * * * /bin/bash /root/traffic_monitor.sh 190 195 1 3 eth0 >> /root/traffic_monitor.log 2>&1") | crontab -- * * * * *:每分钟执行一次
- 可修改为 */5 * * * *(每5分钟)或 30 * * * *(每小时第30分钟)
- 日志输出至 /root/traffic\_monitor.log
补充说明
- crontab目录(Debian): 编辑定时任务可通过
vim /var/spool/cron/crontabs/root - 查看iptables路径: 使用
which iptables,一般为/usr/sbin/iptables - 脚本建议放置于root目录下,如
/root/traffic_monitor.sh
地区限制脚本(如不需要,可以不加)
设置只允许中国IP、白名单IP访问,其他丢弃。
安装依赖
apt update && apt install -y ipset curl iptables kmod grep gawk创建脚本文件并编辑
cd /root && vim secure_firewall.sh脚本源码示例
#!/bin/bash
# 修复 Cron 环境下找不到命令的问题
export PATH=/usr/local/sbin:/usr/local/bin:/usr/sbin:/usr/bin:/sbin:/bin
# =========================================================
# 配置项
# =========================================================
# 建议加入你目前操作这台电脑的公网 IP,防止误杀
WHITELIST="127.0.0.1,1.203.149.102"
# 定义所有需要保护的端口(包含 Docker 映射端口 和 宿主机SSH 端口)
PROTECTED_PORTS="80,443,22"
# =========================================================
echo "正在初始化环境..."
# 1. 确保 ipset 已安装
if ! command -v ipset &> /dev/null; then
apt-get update && apt-get install -y ipset
fi
# 2. 建立集合
ipset create china hash:net maxelem 100000 2>/dev/null
ipset create whitelist hash:ip 2>/dev/null
# 3. 更新白名单
echo "正在更新白名单..."
ipset flush whitelist
IFS=',' read -ra ADDR <<< "$WHITELIST"
for ip in "${ADDR[@]}"; do
ipset add whitelist $ip 2>/dev/null
done
# =========================================================
#【新增:看大门检测】如果发现已经下载过IP规则,直接退出,避免重复拉取
# =========================================================
FLAG_FILE="/var/run/guard_applied.flag"
if [ -f "$FLAG_FILE" ]; then
echo "白名单已动态更新。中国 IP 库与核心规则已在内核中,跳过重复写入。"
exit 0
fi
# =========================================================
# 4. 获取并更新中国 IP 段
echo "正在下载中国 IP 库..."
curl -s --connect-timeout 10 https://ispip.clang.cn/all_cn.txt > /tmp/china_ip.txt
if [ -s /tmp/china_ip.txt ] && grep -qE '[0-9]{1,3}\.[0-9]{1,3}' /tmp/china_ip.txt; then
echo "下载成功,正在应用到内核..."
ipset flush china
grep -E '^[0-9]' /tmp/china_ip.txt | sed -e 's/^/add china /' | ipset restore -!
COUNT=$(ipset list china | grep 'Number of entries' | awk '{print $4}')
echo "成功载入 $COUNT 条中国网段数据。"
else
echo "------------------------------------------------------"
echo "【错误】下载的 IP 库内容不合法(可能是 404 页面或网络连接被拦截)。"
echo "脚本已紧急停止执行,未修改防火墙规则,防止误杀自己。"
echo "------------------------------------------------------"
exit 1
fi
# 5. 【智能状态防护】注入 Filter 表相关链
echo "正在应用 Filter 表状态防火墙规则..."
iptables -t raw -F PREROUTING 2>/dev/null
iptables -N DOCKER_GUARD 2>/dev/null
iptables -F DOCKER_GUARD
iptables -A DOCKER_GUARD -m conntrack --ctstate RELATED,ESTABLISHED -j RETURN
iptables -A DOCKER_GUARD -s 172.16.0.0/12 -j RETURN
iptables -A DOCKER_GUARD -d 172.16.0.0/12 -j RETURN
iptables -A DOCKER_GUARD -m set --match-set whitelist src -j RETURN
iptables -A DOCKER_GUARD -m set --match-set china src -j RETURN
iptables -A DOCKER_GUARD -j DROP
iptables -D INPUT -p tcp -m multiport --dports $PROTECTED_PORTS -j DOCKER_GUARD 2>/dev/null
iptables -D FORWARD -p tcp -m multiport --dports $PROTECTED_PORTS -j DOCKER_GUARD 2>/dev/null
iptables -D INPUT -p udp -m multiport --dports $PROTECTED_PORTS -j DOCKER_GUARD 2>/dev/null
iptables -D FORWARD -p udp -m multiport --dports $PROTECTED_PORTS -j DOCKER_GUARD 2>/dev/null
iptables -I INPUT 1 -p tcp -m multiport --dports $PROTECTED_PORTS -j DOCKER_GUARD
iptables -I FORWARD 1 -p tcp -m multiport --dports $PROTECTED_PORTS -j DOCKER_GUARD
iptables -I INPUT 1 -p udp -m multiport --dports $PROTECTED_PORTS -j DOCKER_GUARD
iptables -I FORWARD 1 -p udp -m multiport --dports $PROTECTED_PORTS -j DOCKER_GUARD
# =========================================================
# 创建拉取IP库规则标记文件
touch "$FLAG_FILE"
# =========================================================
echo "------------------------------------------------------"
echo "【全方位防护已开启 (Smart Mode)】"
echo "保护端口: $PROTECTED_PORTS"
echo "拦截逻辑: 允许 [中国 IP]、[白名单] 和 [Docker 内部/回程流量] 访问,其余丢弃。"
echo "------------------------------------------------------"
echo "验证方法: iptables -L DOCKER_GUARD -v -n"脚本权限设置
chmod +x secure_firewall.sh使用示例
手动执行脚本:
./secure_firewall.sh成功输出示例:
正在初始化环境...
正在更新白名单...
正在下载中国 IP 库...
下载成功,正在应用到内核...
成功载入 4210 条中国网段数据。
正在应用 Filter 表状态防火墙规则...
------------------------------------------------------
【全方位防护已开启 (Smart Mode)】
保护端口: 80,443,22
拦截逻辑: 允许 [中国 IP]、[白名单] 和 [Docker 内部/回程流量] 访问,其余丢弃。
------------------------------------------------------
验证方法: iptables -L DOCKER_GUARD -v -n自动定时运行
可通过 crontab 实现脚本定时运行。例如每分钟执行一次。
(crontab -l ; echo "* * * * * /bin/bash /root/secure_firewall.sh") | crontab -[!TIP] 💡 注意
- 单独使用此脚本时使用
- 与流量监控脚本联合使用时,不需要加定时运行
常用操作
- 检查某个 IP 是否属于中国IP或白名单:
ipset test china x.x.x.x ipset test whitelist x.x.x.x- 查看端口防护规则及拦截统计信息:
iptables -t raw -L PREROUTING -v -n[!TIP] 💡 注意事项
- 如遇自动检测网络接口失败,请手动指定 INTERFACE 参数。
- Bark 通知 KEY 需替换为个人设备的 KEY,否则无法收到推送。
- 本配置仅禁止除中国 IP 外的地址通过 22、80 和 443 端口访问服务器。
- 其他端口并未做任何干预。
- 请根据实际需求修改 WHITELIST 配置项增加白名单IP地址。
- 如需保护更多端口,请根据实际需求修改PROTECTED\_PORTS 配置项。
如果有更多疑问,欢迎留言交流!