iptables利用hashlimit限速

有很长一段时间,我都在查找“端口限速”的方法,以限制流量中转的速率。

然而,搜索引擎给出的答案通常是使用iptablestc结合,使用iptables做路由控制,使用tc做流量整型。这种方法复杂且难以维护。

同时,在GitHub上也难以查询到相关开源项目。

终于,最近找到了最高效最方便且最灵活(远不只是端口限速)的限速方式,即使用iptableshashlimit模块。

什么是hashlimit

hashlimitiptables的一个拓展模块,其本身是一个匹配模块,不具有其他功能,需要结合其他模块来完成复杂任务。

什么是令牌桶

hashlimit使用的算法叫做令牌桶算法。

令牌桶(token bucket),顾名思义,可以理解为有一个桶,里面装满了令牌(token)。当请求来到时,可理解为人群来到,只有拿到令牌的人才能参加活动(例如购买某种物品)。令牌桶的容量是一个固定值,且令牌桶也会在不满时以一定速率生成新的令牌,令牌的生成速率也是一个固定值

所以,例如使用一个令牌桶来限制人群购买商品的速率,例如假设令牌桶的容量是50,生成速率是每秒100个,人群的购买欲望是无穷的(尽可能达到大的购买速率)。于是,在开放购买的瞬间,人群瞬间抢完了50个令牌(突发速率),而之后人群以每秒100人的速率购买,正好与令牌生成速度相同(限制的最高速率),同时令牌桶容量一直为0,这样一来就成功将人群购买速率限制为令牌生成速率。

实操

看过了上面什么是令牌桶的解释,相信你也意识到了,令牌桶生成速率就是我们限制的网络速率。

下面以一个简单的场景来讲解:

A(一个多个不同IP的客户端)→ B(流量中转机器)→ C(流量目标机器)

假设A、B、C的IP地址分别为1.1.1.12.2.2.23.3.3.3

在此场景中,要求限制A通过B的网络速率的总合为上下对等100Mbps。(无论多用户还是单用户,多线程还是单线程,总速率限制为100Mbps)

在B上操作

  • 限制C→B→A速率

    1
    2
    3
    4
    5
    6
    iptables -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 ACCEPT
    1
    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,所以令牌桶只有一个。模式有:srcipsrcportdstipdstport

    • --hashlimit-burst制定了令牌桶的大小(iptables规定了令牌桶大小必须大于等于生成速率(设置的不对iptables会告诉你最小值,最小值也不一定是生成速率))。

    • 为什么要两条命令?

      被第一条命令匹配成功的数据报(拿到令牌的)被ACCEPT,其余的数据报被第二条匹配而丢弃。如果没有第二条规则,则数据包被INPUT链默认策略匹配(绝大多数情况以及默认情况下是ACCEPT),故而根本没有起到限速作用。

  • 限制A→B→C速率

    1
    2
    3
    4
    5
    6
    iptables -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 ACCEPT
    1
    iptables -A OUTUT -p tcp -d 3.3.3.3 -j DROP

其他

  • 灵活的限速

    参照实操部分的例子,你可以灵活的设置自己的规则,例如加入匹配端口等其他匹配规则

  • 更多设置

    关于hashlimit的更多设置可以参考文档:iptables-extensions

    ctrl+f搜索hashlimit即可。