使用iptables recent+quota 根据访问源地址进行流量限制
由于服务器没有ipset tc,就用recent+quota来实现了一个根据访问ip下行流量实现的限制。
1,在INPUT链构建规则获得访问IP的源地址列表squota
2,在INPUT链预先构建一条使用bquota(流量上限被封的ip)列表DROP的规则
3,脚本主要通过cron 每3分钟调用 */3 * * * * /quota.sh
4,在系统时间每天的17:01分钟清空列表,开始新的一天计数
5,排除一些无需受限ip
6,根据squota列表处理获得源ip地址,然后构建quota限制规则,并添加上一条用于生成bquota的规则
7,根据bquota列表重新处理获得已经封锁的ip,将这些ip从OUTPUT链上删除,以避免遍历OUTPUT导致的无谓性能下降
8,构建一个40gbit的表quota40g用于计数用途,当quota40g里的DROP产生计数时,就是当天服务器端40G流量用光时,重新用iptables规则丢弃所有的服务访问。
#/bin/sh
PATH=/bin:/usr/bin:/sbin
perip_traffic=2147483648 #2Gbytes
IPT=$(which iptables)
#squota记录访问源ip bquota在INPUT链预先DROP以节省流量开支。
#iptables -I INPUT -p tcp -m multiport –dport 80,443,1723,8080,8443,8843 -d XXX.XXX.XXX.XXX -m recent –name squota –rsource –set
#iptables -I INPUT -p tcp -m multiport –dport 80,443,1723,8080,8443,8843 -d XXX.XXX.XXX.XXX -m recent –update –name bquota –rsource -j DROP
if [ $(date +”%H%M”) = 1701 ];then
total_traffic=42949672960 #40Gbytes
#建立每天总流量40G限制
iptables -N quota40g
iptables -F quota40g #iptables -Z quota40g
iptables -Z OUTPUT
iptables -A quota40g -m quota –quota $total_traffic -j ACCEPT
iptables -A quota40g -j DROP
#去除过期限制
echo / >/proc/net/xt_recent/squota
echo / >/proc/net/xt_recent/bquota
>/da/log/quota40g.txt
echo “`(date +”%m/%d/%Y %T”)` iptables_quota clear successfully_” >> /tmp/log
fi
#排除一些IP,主机IP
echo -XXX.XXX.XXX.XXX >/proc/net/xt_recent/squota
echo -45.78.0.25 >/proc/net/xt_recent/squota
cat /proc/net/xt_recent/squota|awk ‘{print $1}’ |awk -F”=” ‘{print $2}’|awk ‘!i[$1]++’>/tmp/squota.tmp
$IPT -S OUTPUT>/tmp/iptables.quota
for i in `cat /tmp/squota.tmp`;
do grep -q $i /tmp/iptables.quota
if [ $? -gt 0 ];then
#流出方向以及端口
#a=”`$IPT -vnL OUTPUT –line-numbers | grep “61234” | cut -c1-5` + 1″;a=`expr $a`;
#a=5
#$IPT -A OUTPUT -p tcp -m multiport –sport 80,443,1723,8080,8443,8843 -d $i -j REJECT
#$IPT -I OUTPUT $a -p tcp -m multiport –sport 80,443,1723,8080,8443,8843 -d $i -m recent –name bquota –rdest –set
#$IPT -I OUTPUT $a -p tcp -m multiport –sport 80,443,1723,8080,8443,8843 -d $i -m quota –quota $perip_traffic -j ACCEPT
#注意顺序不然可能会导致立刻quota又被立刻unquota
$IPT -I OUTPUT 5 -o venet0 -d $i -m quota –quota $perip_traffic -j quota40g
$IPT -A OUTPUT -o venet0 -d $i -m recent –name bquota –rdest –set
$IPT -A OUTPUT -o venet0 -d $i -j REJECT
echo “$i”>>/da/log/quota.tmp
echo “`(date +”%m/%d/%Y %T”)` iptables_quota $i successfully_” >> /tmp/log
fi;done
cat /da/log/quota.tmp | awk ‘!i[$1]++’ > /da/log/quota.txt
#根据bquota列表解除OUTPUT链规则以避免浪费性能
cat /proc/net/xt_recent/bquota|awk ‘{print $1}’ |awk -F”=” ‘{print $2}’|awk ‘!i[$1]++’>/tmp/bquota.tmp;
for i in `cat /tmp/bquota.tmp`;
do while true;do b=`$IPT -vnL OUTPUT –line-numbers | grep “$i” | cut -c1-4 | awk ‘{printf “%s “,$1}’|awk ‘{print $NF}’`
if [ -z “$b” ];then break;else $IPT -D OUTPUT $b;fi;echo “$i”>>/da/log/quota40g.txt;echo “`(date +”%m/%d/%Y %T”)` iptables_unquota $i successfully_” >> /tmp/log;
done;
echo -“$i” >/proc/net/xt_recent/squota
done
#计算已经消耗的流量,当超过40(上面计数有问题每次产生3条)当天所有服务停止
#a=`wc -l < /da/log/quota40g.txt`;
#if [ $a -ge 120 ];then
#iptables -I INPUT -p tcp -m multiport –dport 80,443,1723,8080,8443,8843 -d XXX.XXX.XXX.XXX -j DROP;
#ip6tables -I INPUT -p tcp -m multiport –dport 80,443,1723,8080,8443,8843 -d 2607:8700:101:808f:1:: -j DROP;
#ip6tables -I INPUT -p tcp -m multiport –dport 80,443,1723,8080,8443,8843 -d 2002:2d4e:214a::1 -j DROP;
#iptables -D INPUT -p tcp -m multiport –dport 80,443,1723,8080,8443,8843 -d XXX.XXX.XXX.XXX -m recent –update –name bquota –rsource -j DROP
#iptables -D INPUT -p tcp -m multiport –dport 80,443,1723,8080,8443,8843 -d XXX.XXX.XXX.XXX -m hashlimit –hashlimit-name obfs –hashlimit 80/sec –hashlimit-burst 350 –hashlimit-mode srcip,srcport –hashlimit-htable-expire 300000 -j ACCEPT
#iptables -D INPUT -p tcp -m multiport –dport 80,443,1723,8080,8443,8843 -d XXX.XXX.XXX.XXX -m recent –name squota –rsource –set
#iptables -D INPUT -p tcp -m multiport –dport 80,443,1723,8080,8443,8843 -d XXX.XXX.XXX.XXX -j REJECT
#echo “`(date +”%m/%d/%Y %T”)` iptables_stop all service successfully_” >> /tmp/log
#fi
a=`iptables -vnL quota40g|grep DROP|awk ‘BEGIN{ORS=””}{ print$1″\012″;}’`
if [ $a -gt 0 ];then
iptables -I INPUT -p tcp -m multiport –dport 80,443,1723,8080,8443,8843 -d XXX.XXX.XXX.XXX -j DROP;
iptables -D INPUT -p tcp -m multiport –dport 80,443,1723,8080,8443,8843 -d XXX.XXX.XXX.XXX -m recent –update –name bquota –rsource -j DROP
iptables -D INPUT -p tcp -m multiport –dport 80,443,1723,8080,8443,8843 -d XXX.XXX.XXX.XXX -m recent –name squota –rsource –set
echo “`(date +”%m/%d/%Y %T”)` iptables_stop all service successfully_” >> /tmp/log
fi
#debug
#iptables -vnL OUTPUT
#iptables -vnL INPUT
#cat /proc/net/xt_recent/squota
#cat /proc/net/xt_recent/bquota
最终规则应该看起来像这样
default:/da# iptables -S INPUT|head -n 5
-P INPUT DROP
-A INPUT -d XXX.XXX.XXX.XXX/32 -p tcp -m multiport –dports 80,1723,8080,8443,8843 -m recent –update –name bquota –rsource -j DROP
-A INPUT -d XXX.XXX.XXX.XXX/32 -p tcp -m multiport –dports 80,1723,8080,8443,8843 -m hashlimit –hashlimit-upto 80/sec –hashlimit-burst 350 –hashlimit-mode srcip,srcport –hashlimit-name obfs –hashlimit-htable-expire 300000 -j ACCEPT
-A INPUT -d XXX.XXX.XXX.XXX/32 -p tcp -m multiport –dports 80,1723,8080,8443,8843 -m recent –set –name squota –rsource
-A INPUT -d XXX.XXX.XXX.XXX/32 -p tcp -m multiport –dports 80,1723,8080,8443,8843 -j REJECT –reject-with icmp-port-unreachable
default:/da# iptables -S OUTPUT|head -n 5
-P OUTPUT ACCEPT
-A OUTPUT -d XXX.XXX.184.64/32 -o venet0 -m quota –quota 1228479159 -j quota40g
-A OUTPUT -d XXX.XXX.184.64/32 -o venet0 -m recent –set –name bquota –rdest
-A OUTPUT -d XXX.XXX.184.64/32 -o venet0 -j REJECT –reject-with icmp-port-unreachable