我的服务器带宽被"偷"了,于是我写了个脚本来抓现行
前言:总有"内鬼"在搞事情
不知道你有没有遇到过这种糟心事:服务器跑得好好的,突然就卡得不行,一查监控,好家伙,出站带宽瞬间被拉满,直冲 50MB/s! 等你手忙脚乱地登上服务器,想用 iftop 看看到底是哪个孙子在搞事时,流量又"嗖"地一下没了,恢复正常。 这种瞬时高峰,就像个幽灵,想抓个现行比登天还难。手动守着?不可能,咱又不是没有生活。 行吧,既然你玩阴的,那我就写个脚本,24小时盯着你,看你能躲到几时!
目标:自动抓贼,还得留证据
我的需求很简单:
- 盯着服务器的出站流量。
- 一旦超过我设定的线(比如 30MB/s),立刻报警!
- 最重要的是,把当时是哪个内网IP、哪个端口在疯狂"偷流量"给我记下来,形成铁证!
- 脚本得靠谱,能一直在后台默默干活。
第一次踩坑:脚本是个"睁眼瞎"
很快,第一版脚本就写好了。思路很简单:每秒读一下系统网卡的总发送字节数,算个差值,不就知道速度了吗?
bash
# 伪代码
last_bytes = 读取网卡字节数()
sleep(1)
this_bytes = 读取网卡字节数()
speed = (this_bytes - last_bytes) / 1024 / 1024 # MB/s
结果一运行,傻眼了。iftop 明明显示 50MB,我的脚本却固执地显示 0.00 MB/s。 为啥? 后来才想明白,bash 默认是个整数选手,小于 1 的数它直接给你抹零!比如 0.8,它直接告诉你 0。真是个实诚的孩子。 解决办法 :找个会算小数的工具。awk 就很棒。
bash
# 用 awk 来算小数
TX_MBPS=$(awk "BEGIN {printf \"%.2f\", ($CURRENT_TX_BYTES - $LAST_TX_BYTES) / 1024 / 1024}")
第二次踩坑:只报警,不留证
修复了计算问题,脚本总算能喊"抓贼"了!每次流量一超,它就老老实实地打印 "HIGH TRAFFIC DETECTED!"。 但是......证据呢?说好的日志文件呢?我跑去日志目录一看,文件是创建了,但里面空空如也,干净得像张白纸。 这就离谱了,贼都喊抓住了,现场记录(iftop 的输出)去哪了? 后来琢磨半天,发现是 iftop 在后台运行时,它的输出重定向有点"个性",用 > 这个符号愣是抓不住它。 解决办法 :换个方式请君入瓮。不用 > 了,直接把 iftop 扔到后台跑,然后用 wait 命令在门口等着它跑完,这样它的所有输出就都能被 nohup 抓到了。
bash
# 让 iftop 在后台跑,等它跑完
iftop ... &
IFTOP_PID=$!
wait $IFTOP_PID
最终版:一个完美的"监控摄像头"
经过两次踩坑,最终版的脚本终于成型了。它现在非常完美:
- 平时静默:没贼的时候,它一句话不说,绝不刷屏。
- 贼来报警:流量一超,立刻打印带时间戳的警报。
- 全程录像 :
iftop的输出直接塞进日志,贼的IP、端口、速度,一清二楚。 - 统一管理:所有日志都记在一个文件里,查起来方便。
终极脚本代码
bash
#!/bin/bash
# --- 配置区 ---
INTERFACE="eth0" # 监控的网卡
INTERNAL_NET="10.9.0.0/16" # 内网网段
THRESHOLD_MB=30 # 告警阈值
# --- 配置区结束 ---
# 初始化上一次的字节数
LAST_TX_BYTES=$(cat /sys/class/net/$INTERFACE/statistics/tx_bytes)
while true; do
sleep 1
# 获取当前字节数并计算速率
CURRENT_TX_BYTES=$(cat /sys/class/net/$INTERFACE/statistics/tx_bytes)
TX_MBPS=$(awk "BEGIN {printf \"%.2f\", ($CURRENT_TX_BYTES - $LAST_TX_BYTES) / 1024 / 1024}")
# 检查是否超过阈值
if (( $(echo "$TX_MBPS > $THRESHOLD_MB" | bc -l) )); then
TIMESTAMP=$(date +"%Y%m%d-%H%M%S")
# 带时间戳的告警信息
echo "$(date '+%Y-%m-%d %H:%M:%S') ========================================="
echo "$(date '+%Y-%m-%d %H:%M:%S') [$TIMESTAMP] HIGH TRAFFIC DETECTED: ${TX_MBPS} MB/s!"
echo "$(date '+%Y-%m-%d %H:%M:%S') Capturing traffic details for 60 seconds..."
echo "$(date '+%Y-%m-%d %H:%M:%S') -----------------------------------------"
# 运行 iftop 捕获流量,输出将被 nohup 重定向
iftop -i $INTERFACE -n -P -t -s 60 -f "src net $INTERNAL_NET" -L 100
echo "$(date '+%Y-%m-%d %H:%M:%S') -----------------------------------------"
echo "$(date '+%Y-%m-%d %H:%M:%S') Capture finished. Continuing to monitor..."
fi
# 更新上一次的字节数
LAST_TX_BYTES=$CURRENT_TX_BYTES
done
怎么用?
-
把代码存为
monitor.sh。 -
给它执行权:
chmod +x monitor.sh。 -
甩到后台让它自己玩去:
bashnohup ./monitor.sh >> bandwidth_monitor.log 2>&1 & -
想看监控录像了,就:
bashtail -f bandwidth_monitor.log
现在,我的服务器上装了个24小时无死角的"监控摄像头",哪个"内鬼"再敢出来作妖,保证让它有来无回,当场留下证据! 希望这个小脚本能帮你解决同样的烦恼。