带有 hashlimit 和“--state NEW”的 iptables 阻止了太多新连接

Tom*_*ski 2 iptables linux-networking

我已经设置了速率限制来阻止对我的 ssh 服务器的暴力攻击。我使用以下 iptables 规则:

iptables -A INPUT -p tcp -m tcp --dport 22 -m hashlimit --hashlimit-upto 4/min
--hashlimit-burst 6 --hashlimit-mode srcip --hashlimit-name ssh
--hashlimit-htable-expire 60000 -m state --state NEW -j ACCEPT

iptables -A INPUT -m tcp -p tcp --dport 22 -m state --state NEW -j REJECT
Run Code Online (Sandbox Code Playgroud)

当我打开一个 SSH 连接(例如通过 PuTTY),然后一分钟后尝试打开另一个连接(例如,传输文件)时,第二个连接有时会被拒绝,服务器没有响应。如果我设法打开第二个 SSH 连接,然后尝试打开第三个连接,它会变得更加困难(很可能没有响应)。

我已经验证,当我禁用上述规则时,一切正常。增加--hashlimit-upto和/或--hashlimit-burst有帮助,但并不能完全解决问题——它只会降低问题发生的可能性。有时仍然会发生拒绝,但如果我禁用 iptables 规则,则永远不会发生。

到底是怎么回事?上述 iptables 规则规定,与新连接相关的 TCP 数据包应限制为每分钟 4 个。所以我应该能够轻松地每分钟打开最多 4 个连接。

Tom*_*ski 7

(回答我自己的问题,为其他人留下记录。)

你的第一条规则:

iptables -A INPUT -p tcp -m tcp --dport 22 -m hashlimit --hashlimit-upto 4/min
--hashlimit-burst 6 --hashlimit-mode srcip --hashlimit-name ssh 
--hashlimit-htable-expire 60000 -m state --state NEW -j ACCEPT
Run Code Online (Sandbox Code Playgroud)

没有做你认为它正在做的事情。当您说-m tcp-m hashlimit和 时-m state,您将调用三个 iptables 模块。您认为哈希限制仅适用于满足规则中所有其他条件的数据包。但事实并非如此。相反,模块按照规则中给出的顺序执行。(据我所知,这一事实在直觉上并不明显,也没有在任何地方明确记录。)

在上述规则中,-m hashlimit出现在 之前-m state。这意味着每个 TCP 数据包(不仅仅是新数据包)将首先发送到 hashlimit 模块。Hashlimit 会对这个数据包进行计数,如果在4/min限制之内,它将被传递到-m state. 直到现在,state模块才开始查看数据包并检查它是否代表新连接。

因此,在您的情况下,您打开第一个 SSH 连接,该连接会不时传输一些数据包。这些数据包不是“新”数据包,因此它们不会被丢弃(--state NEW不满足第二条规则中的条件)。但它们是由 hashlimit 处理的,并且会会计入您的4/min限制。如果它们来得足够快,它们将用完配额,如果您随后尝试打开另一个连接,则该连接的第一个数据包将达到配额,并且您的第一个规则将不匹配。

显而易见的解决方案是更改顺序:

iptables -A INPUT -p tcp -m tcp --dport 22 -m state --state NEW -m hashlimit
--hashlimit-upto 4/min --hashlimit-burst 6 --hashlimit-mode srcip --hashlimit-name ssh 
--hashlimit-htable-expire 60000 -j ACCEPT
Run Code Online (Sandbox Code Playgroud)

一般来说,我认为一个好的经验法则是始终-m hashlimit将 iptables 规则放在最后

  • 一般来说,更好的经验法则是将“-m conntrack --ctstate ESTABLISHED -j ACCEPT”放在第一位。这样做的另一个好处是,来自现有连接的数据包遍历的规则更少,从而加快处理速度并占用更少的 CPU。 (2认同)