长期读者,第一次发帖。等等等等。
无论如何,我希望有人具有丰富的 iptables/netfilter LIMIT 或 HASHLIMIT 模块经验,并可以解释我所见证的行为。
背景: 我们有一个 Web 服务器,想要限制客户在一个月内可以建立的连接数(顺便说一下,HTTP keepalive 已关闭)。因此,我尝试使用 iptables LIMIT 模块将新连接数限制为每月固定数量(假设为 500)。iptables LIMIT 模块使用“令牌桶”算法,因此我应该能够将限制突发(桶大小)设置为 500,将限制(重新填充率)设置为 500 除以 28 天或大约 18/天。这将确保如果桶每次都完全清空,则在一个月内(4 周)重新填充桶。(我知道这实际上将允许超过 500 个,但它应该足以满足我们的需求)。
这是我的 iptables 规则(我们使用 ipset 对 IP 进行分组。LimBurTest4 包含我的源测试机器)
Chain INPUT (policy DROP 2316 packets, 186K bytes)
pkts bytes target prot opt in out source destination
2952K 626M ACCEPT all -- * * 0.0.0.0/0 0.0.0.0/0 state RELATED,ESTABLISHED /* Accept outgoing return traffic */
379 13702 ACCEPT icmp -- * * 0.0.0.0/0 0.0.0.0/0 icmptype 8 state NEW limit: avg 1/sec burst 1
377 30868 DROP icmp -- * * 0.0.0.0/0 0.0.0.0/0
0 0 DROP tcp -- * * 0.0.0.0/0 0.0.0.0/0 tcp flags:0x3F/0x00 /* Block NULL packets */
73 14728 DROP tcp -- * * 0.0.0.0/0 0.0.0.0/0 tcp flags:!0x17/0x02 state NEW /* Block SYN flood */
0 0 DROP tcp -- * * 0.0.0.0/0 0.0.0.0/0 tcp flags:0x3F/0x3F /* Block XMAS packets */
24 120 ACCEPT tcp -- * * 0.0.0.0/0 0.0.0.0/0 match-set LimBurTest4 src tcp dpt:443 limit: avg 18/day burst 500 /* LimitBurst Test */
76 30180 LOG tcp -- * * 0.0.0.0/0 0.0.0.0/0 match-set LimBurTest4 src tcp dpt:443 /* LimitBurst Testing */ LOG flags 0 level 4 prefix "LimBurTest Over Quota "
2522 138K REJECT tcp -- * * 0.0.0.0/0 0.0.0.0/0 tcp dpt:443 /* Reject queries */ reject-with tcp-reset
我添加如下 LIMIT 规则:
iptables -I INPUT 7 -m set --match-set LimBurTest4 src -p tcp --dport 443 -m limit --limit 18/day --limit-burst 500 -m comment --comment "Limit Burst Test" -j ACCEPT
测试: 然后我创建了一个简单的 shell 脚本,使用 curl 向我的 Web 服务器一个接一个地发出请求。每次成功的请求大约需要 0.20 毫秒。脚本的输出如下所示:
./limBurTest.sh
1 - 200 - 0.257 ms
2 - 200 - 0.193 ms
3 - 200 - 0.155 ms
etc.
etc.
结果: 我期望此配置能够快速(在几秒钟内)用完所有 500 个连接,然后我才会开始看到被拒绝的连接。然而,这根本没有发生。相反,我的测试脚本成功建立了 24 个连接,其余的都被拒绝了。例如,在上面的 iptables 输出中,我循环运行了 100 次 shell 脚本,您可以在 ACCEPT 规则之后看到 24 个 ACCEPT 规则匹配和 76 个 LOG 规则匹配。我已经在 CentOS 6.8 和 Ubuntu 16.04 上测试过,两者都是这样的行为,但这似乎与文档相反。为什么我不能用完 limit-burst 指定的所有 500 个连接?
是的,当然,我已经进行了大量 Google 搜索,看到很多人说 LIMIT 模块应该完全按照我描述的方式工作。而且我已经多次阅读了 netfilter 文档。
我在这里遗漏了什么?
先感谢您。
答案1
限制模块不是根据连接数进行限制,而是根据 IP 数据包(甚至是巨型数据包)的数量进行限制。因此,如果单个连接大约需要 20.8 个数据包,那么您将看到连接激增500/20.8~=24
。
有关更多信息,请参阅命令的输出man 8 iptables-extensions|grep -e '^ *limit$' -A 18
,特别是短语“最大初始数量数据包匹配: [...]”。
答案2
从 user3338098 开始,为了修复它,你只需要通过添加来匹配 SYN 数据包-m state --state NEW