iptables利用hashlimit限速
有很长一段时间,我都在查找“端口限速”的方法,以限制流量中转的速率。
然而,搜索引擎给出的答案通常是使用iptables
与tc
结合,使用iptables
做路由控制,使用tc
做流量整型。这种方法复杂且难以维护。
同时,在GitHub上也难以查询到相关开源项目。
终于,最近找到了最高效最方便且最灵活(远不只是端口限速)的限速方式,即使用iptables
的hashlimit
模块。
什么是hashlimit
hashlimit
是iptables
的一个拓展模块,其本身是一个匹配模块,不具有其他功能,需要结合其他模块来完成复杂任务。
什么是令牌桶
hashlimit
使用的算法叫做令牌桶算法。
令牌桶(token bucket),顾名思义,可以理解为有一个桶,里面装满了令牌(token)。当请求来到时,可理解为人群来到,只有拿到令牌的人才能参加活动(例如购买某种物品)。令牌桶的容量是一个固定值,且令牌桶也会在不满时以一定速率生成新的令牌,令牌的生成速率也是一个固定值。
所以,例如使用一个令牌桶来限制人群购买商品的速率,例如假设令牌桶的容量是50,生成速率是每秒100个,人群的购买欲望是无穷的(尽可能达到大的购买速率)。于是,在开放购买的瞬间,人群瞬间抢完了50个令牌(突发速率),而之后人群以每秒100人的速率购买,正好与令牌生成速度相同(限制的最高速率),同时令牌桶容量一直为0,这样一来就成功将人群购买速率限制为令牌生成速率。
实操
看过了上面什么是令牌桶的解释,相信你也意识到了,令牌桶生成速率就是我们限制的网络速率。
下面以一个简单的场景来讲解:
A(一个多个不同IP的客户端)→ B(流量中转机器)→ C(流量目标机器)
假设A、B、C的IP地址分别为1.1.1.1
,2.2.2.2
,3.3.3.3
。
在此场景中,要求限制A通过B的网络速率的总合为上下对等100Mbps。(无论多用户还是单用户,多线程还是单线程,总速率限制为100Mbps)
在B上操作:
限制C→B→A速率
1
2
3
4
5
6iptables -A INPUT -p tcp -s 3.3.3.3 -m hashlimit \
--hashlimit-name limitDownLink \
--hashlimit-upto 12500kb/s \
--hashlimit-mode srcip \
--hashlimit-burst 12500kb \
-j ACCEPT1
iptables -A INPUT -p tcp -s 3.3.3.3 -j DROP
部分解释:
--hashlimit-name
不仅是个“名字”,他是令牌桶独一无二的标志,如果两条命令用了一个名字,他们将共享这个令牌桶(可以知道速率也会共享),所以请保证使用独一无二的名字。--hashlimit-upto
制定了令牌生成速率。(这里kb/s是kByte/s)--hashlimit-mode
是匹配模式,这里指定srcip
模式则是每个源IP一个令牌桶,因为这里源IP只有C的3.3.3.3
,所以令牌桶只有一个。模式有:srcip
、srcport
、dstip
、dstport
。--hashlimit-burst
制定了令牌桶的大小(iptables规定了令牌桶大小必须大于等于生成速率(设置的不对iptables会告诉你最小值,最小值也不一定是生成速率))。为什么要两条命令?
被第一条命令匹配成功的数据报(拿到令牌的)被ACCEPT,其余的数据报被第二条匹配而丢弃。如果没有第二条规则,则数据包被INPUT链默认策略匹配(绝大多数情况以及默认情况下是ACCEPT),故而根本没有起到限速作用。
限制A→B→C速率
1
2
3
4
5
6iptables -A OUTPUT -p tcp -d 3.3.3.3 -m hashlimit \
--hashlimit-name limitUpLink \
--hashlimit-upto 12500kb/s \
--hashlimit-mode dstip \
--hashlimit-burst 12500kb \
-j ACCEPT1
iptables -A OUTUT -p tcp -d 3.3.3.3 -j DROP
其他
灵活的限速
参照实操部分的例子,你可以灵活的设置自己的规则,例如加入匹配端口等其他匹配规则
更多设置
关于
hashlimit
的更多设置可以参考文档:iptables-extensions。ctrl+f
搜索hashlimit
即可。