今天,咱们的一台服务器出了问题: 被若干IP地址访问某个接口,该接口会发送短信。html
因此,咱们能够作两件事: 1. nginx的层面封IP 。 2 linux server的层面封IPlinux
先看nginx : 很是简单, 加上 deny xxx.x.x.x; 就能够了。nginx
linux的层面: iptables -I INPUT -s 110.7.48.47 -j DROP程序员
就能够把某个IP封掉。bash
目测,后者更方便一些。服务器
在nginx 层面的封禁, req仍是会打进来, 让nginx 返回 403, 占用资源。app
还能够把以上步骤作成自动化的脚本,tcp
参考: http://www.cnblogs.com/huligong1234/p/7189426.html url
直接一步到位:spa
1. 修改crontab : $ crontab -e
*/2 * * * * sh /opt/check_black_ip.sh
2. 增长这个文件:
tail -n10000 /usr/local/nginx/logs/access.log | awk '{print $1,$7}' | grep send_login_token | awk '{print $1}' | sort | uniq -c | sort -rn | awk '{if($1>30)print "deny "$2";"}' > /usr/local/nginx/conf/blacklist.append.conf /usr/local/nginx/sbin/nginx -s reload
3. 确保你的nginx配置以下:
http{
# ....
include blacklist.conf;
}
下面是具体的原理和过程:
1. 肯定好nginx的日志文件的位置, 例如: /usr/local/nginx/logs/access.log ( 若是你用了logrotate, 那么这个文件多是天天更新一次 )
2. 使用命令:
$ tail -n50000 /usr/local/nginx/logs/access.log | awk '{print $1}' | sort | uniq -c | sort -rn | | awk '{if($1>100)print "deny "$2";"}'
第一部分: awk '{print $1}' 只打印出 全部log的ip (第一个被空格截断的内容)
sort 是排序(按照字母顺序)
uniq -c 是对全部内容进行去重,而且计数
sort -rn 是反向排序。 根据计数的结果。
因此,上面的命令,会给出以下结果:
182.84.132.13 117.82.174.128 182.150.146.215 182.148.58.231 116.7.219.28 182.150.28.110 36.7.122.26
最后一部分的: awk '{if($1>100) .... }'是一个bash脚本,会找到全部出现过100次的ip, 而后输出一段deny这样的文本:
deny 182.84.132.13; deny 117.82.174.128; deny 182.150.146.215; deny 182.148.58.231; deny 116.7.219.28; deny 182.150.28.110; deny 36.7.122.26; deny 110.7.48.47; deny 124.127.182.6; deny 110.188.153.219;
最后的最后,把上数的结果, 使用 ">" (覆盖文件) 或者 ">>" (追加文件) 操做符到blacklist.conf文件中。 完整命令为:
$ tail -n50000 /usr/local/nginx/logs/access.log | awk '{print $1}' | sort | uniq -c | sort -rn | awk '{if($1>100)print "deny "$2";"}' >> /usr/local/nginx/conf/blacklist.conf
nginx中的配置以下:
http{
# ....
include blacklist.conf;
}
进一步的,咱们能够只针对某个url的访问进行统计, 代码以下:
$ tail -n10000 /usr/local/nginx/logs/access.log | awk '{print $1,$7}' | grep send_login_token | awk '{print $1}' | sort | uniq -c | sort -rn | awk '{if($1>30)print "deny "$2";"}' >> /usr/local/nginx/conf/blacklist.conf
上面代码,会查看过去10000行nginx记录,找到对于访问 "/interface/..../send_login_token " 的request, 进行ip的计数,对于超过30次访问的,直接封ip
列出当前时刻, 全部的请求数大于10的ip地址: netstat -an | grep ^tcp.*:80 | egrep -v 'LISTEN|127.0.0.1' | awk -F"[ ]+|[:]" '{print $6}' | sort | uniq -c |sort -rn | awk '{ if ($1>10){print $2}}'
解释:
1. netstat -an -a 表示列出全部, -n 表示列出来的都是 数字(例如 3.3.3.4 , 而不是名称) 例如:
# netstat -an Active Internet connections (servers and established) Proto Recv-Q Send-Q Local Address Foreign Address State tcp 0 0 127.0.0.1:3306 0.0.0.0:* LISTEN tcp 0 0 0.0.0.0:3020 0.0.0.0:* LISTEN tcp 0 0 0.0.0.0:3021 0.0.0.0:* LISTEN tcp 0 0 0.0.0.0:3022 0.0.0.0:* LISTEN tcp 0 0 0.0.0.0:3023 0.0.0.0:* LISTEN tcp 0 0 0.0.0.0:80 0.0.0.0:* LISTEN tcp 0 0 0.0.0.0:35888 0.0.0.0:* LISTEN tcp 0 0 0.0.0.0:3000 0.0.0.0:* LISTEN tcp 0 0 0.0.0.0:3001 0.0.0.0:* LISTEN tcp 0 0 0.0.0.0:3002 0.0.0.0:* LISTEN tcp 0 0 0.0.0.0:443 0.0.0.0:* LISTEN tcp 0 0 0.0.0.0:3003 0.0.0.0:* LISTEN tcp 0 0 172.18.230.209:80 118.112.56.229:6785 TIME_WAIT tcp 0 0 172.18.230.209:37220 218.5.173.146:1521 ESTABLISHED tcp 0 0 172.18.230.209:80 182.84.139.53:1817 ESTABLISHED tcp 0 0 172.18.230.209:37212 218.5.173.146:1521 ESTABLISHED tcp 401 0 172.18.230.209:38086 140.205.140.205:80 CLOSE_WAIT
2. $ netstat -an |grep ^tcp.*:80 是对当前的连接中,找到全部的要访问80端口的请求. 例如:
# netstat -an | grep ^tcp.*:80 tcp 0 0 0.0.0.0:80 0.0.0.0:* LISTEN tcp 0 0 172.18.230.209:80 118.112.56.229:7873 TIME_WAIT tcp 0 0 172.18.230.209:80 118.112.56.229:7426 ESTABLISHED tcp 401 0 172.18.230.209:38086 140.205.140.205:80 CLOSE_WAIT tcp 0 0 172.18.230.209:80 182.84.139.53:49165 TIME_WAIT tcp 0 0 172.18.230.209:80 180.108.11.25:15104 TIME_WAIT
3. $ netstat -an |grep ^tcp.*:80 | egrep -v 'LISTEN|127.0.0.1' , 这句话是对 "127.0.0.1' 或者 LISTEN 作个排除. 去掉本地的请求, 去掉 正在 LISTEN的接口
4. awk -F"[ ]+|[:]" '{print $6}' 这里是对结果作个处理, 把某一行的结果, 按照 空格或者 ':' 冒号来分割,取得第六个.(起始的是第一个), 例如:
tcp 0 0 172.18.230.209:80 118.112.56.229:7873 TIME_WAIT
按照空格或者: 来分割的话,第六个就是 118.112.56.229, 这个就是正在请求的IP
5. sort: 按照字母顺序排序. uniq -c 表示 去重,而且加上 出现的次数. sort -r 表示 翻转排序. -n 表示按照数字的大小排序.
6. awk '{if ($1>$num){print $2}} 处理结果, 找到知足条件的, 而后打印出来.
完整版, 根据每秒ip的访问上线,来自动封禁的脚本 :
#!/bin/bash num=100 # 每秒某个ip的访问上限 list=`netstat -an |grep ^tcp.*:80|egrep -v 'LISTEN|127.0.0.1'|awk -F"[ ]+|[:]" '{print $6}'|sort|uniq -c|sort -rn|awk '{if ($1>$num){print $2}}'` for i in $list do iptables -I INPUT -s $i --dport 80 -j DROP done
先用这个命令看到全部被封禁的IP $ iptables -L -n -v --line-numbers
iptables -L -n -v --line-numbers Chain INPUT (policy ACCEPT 289 packets, 71013 bytes) num pkts bytes target prot opt in out source destination 0 0 DROP all -- * * 45.77.183.135 0.0.0.0/0 0 0 DROP all -- * * 120.239.199.152 0.0.0.0/0 0 0 DROP all -- * * 47.52.132.105 0.0.0.0/0
而后用这个命令恢复: iptables -D INPUT ( 例如:iptables -D INPUT 1 就是删掉上面的第一条 45.77.183.135 )
转自
linux , nginx: 封禁IP的办法 (自动化脚本封ip, 根据瞬时的请求总量,或者根据日志 - 为程序员服务 http://ju.outofmemory.cn/entry/343736