使用IPtables或空路由黑名单约100万个IP地址?

我遇到过一种情况:客户端需要将一组不到100万个IP地址(无子网)列入黑名单,networking性能是一个问题。 虽然我会猜测IPTables规则的性能影响要比路由less,但这只是猜测。

有没有人有任何可靠的证据或其他理由来支持将IPTables或空路由作为黑名单IP地址列表的解决scheme? 在这种情况下,一切都是自动的,所以易用性并不是真正的问题。

编辑26-Nov-11

经过一些testing和开发,看来这些选项都不可行。 看起来,路由查找和iptables都是通过规则集进行线性search,并花费太长时间来处理这么多规则。 在现代硬件上,将1M项放在iptables黑名单中会使服务器速度降低到每秒大约二十个数据包。 所以IPTables和空路由都没有了。

按照Jimmy Hedman的build议, ipset会很棒,除了它不允许你跟踪一个集合中的65536个以上的地址,所以我甚至不能尝试使用它,除非有人有任何想法。

显然,阻止这么多IP的唯一解决scheme是在应用层进行索引查找。 那不是吗?


更多信息:

在这种情况下,使用情况是阻止“已知罪犯”IP地址列表访问Web服务器上的静态内容。 FWIW,通过Apache的Deny from进行阻塞同样很慢(如果不是更多的话),因为它也是一个线性扫描。


仅供参考:最终的工作解决scheme是将apache的mod_rewrite与berkeley DB映射一起使用来对黑名单进行查找。 berkeley DB的索引特性允许列表以O(log N)性能进行扩展。

尝试使用iptables并构build多级树来减less查找次数。

 iptables -N rules_0_0_0_0_2 iptables -N rules_64_0_0_0_2 iptables -N rules_128_0_0_0_2 iptables -N rules_192_0_0_0_2 iptables -N rules_0_0_0_0_4 iptables -N rules_16_0_0_0_4 iptables -A INPUT -p tcp --dport 80 -s 0.0.0.0/2 -j rules_0_0_0_0_2 iptables -A INPUT -p tcp --dport 80 -s 64.0.0.0/2 -j rules_64_0_0_0_2 iptables -A INPUT -p tcp --dport 80 -s 128.0.0.0/4 -j rules_128_0_0_0_2 iptables -A INPUT -p tcp --dport 80 -s 192.0.0.0/4 -j rules_192_0_0_0_2 iptables -A rules_0_0_0_0_2 -s 0.0.0.0/4 -j rules_0_0_0_0_4 iptables -A rules_0_0_0_0_2 -s 16.0.0.0/4 -j rules_16_0_0_0_4 

等 – 增加嵌套层次; 显然你需要一种自动的方式来build立规则,你应该为networking中的一个或多个犯罪者提供链接 – 这样你就可以减less查找的次数,而且我认为这可能会大大减less实际上工作。

这正是ipset目的。

从它的网站http://ipset.netfilter.org/

如果你想

  • 存储多个IP地址或端口号,并通过iptables一举匹配收集;
  • 根据IP地址或端口dynamic更新iptables规则,而不会影响性能;
  • 用一个iptables规则表示复杂的IP地址和基于端口的规则集,并受益于IP集的速度

那么ipset可能是适合你的工具。

它由一个netfilter核心团队成员Jozsef Kadlecsik编写(他也写了REJECT目标),所以这是我能想到的最好的select。

它甚至包含在最近的内核中。

我自己没有testing过,但是当我听到你的问题描述时,我立即想到了“ pf ”(从OpenBSD开始)。

pf有地址表的概念,这可能就是你正在寻找的东西。

根据我做的一些非常粗略的研究,看起来这有可能比ipset更好地扩展。 根据关于运行时选项的PF常见问题章节 ,pf支持总共1000个表,默认情况下,所有表中共有200,000个表项。 (如果系统具有<100MB物理内存,则为100,000)。 这使我相信,至less应该考虑尝试testing一下,看它是否适用于任何有用的级别。

当然,我假设你在Linux上运行你的服务器,所以你必须有一个单独的防火墙,运行一些带有pf的操作系统(如OpenBSD或者FreeBSD)。 你也可以通过废除任何有状态的数据包过滤来提高吞吐量。

你有没有调查使用FIB_TRIE而不是FIB_HASH。

FIB_TRIE应该比你的前缀计数好得多。 (/ 32s空路由仍然是前缀,只是非常具体)

你可能需要编译你自己的内核来使用它,但是它有帮助。

FIB_TRIE注释

对于任何人在未来遇到这个问题的一些有用的笔记:

首先,不要分析任何你不需要的stream量。 例如,如果阻止TCPstream量,则只能过滤SYN数据包,这样每个连接只能打一次filter。 如果需要,可以使用-m state ,但连接跟踪有自己的开销,如果性能是一个问题,可能需要避免。

其次,将100万条规则放入iptables需要很长时间:几分钟。 如果你需要跟踪那么多实体,你最好不要使用netfliter。 规则集的庞大规模确实有所作为。

第三,目标是避免线性扫描; 但不幸的是,iptables和iproute2本质上是线性的。 你可以把你的规则从二叉树样式中分解成大量的链,这就限制了你需要查询的规则的数量,但是即使如此,iptables也不适合这个大小的问题。 它会工作 ,但这是浪费宝贵的资源。

第四,也是最重要的,把你的工作量推到用户空间并不是一个坏主意。 这使您可以编写自己的严密代码,或使用针对问题集的现成解决scheme。 如上所述,我自己的解决scheme是使用通过Apache的mod_rewrite系统触发的BDB查找。 这还有一个好处,就是每个会话只能触发一次查询,并且只有在提交了一个有效的请求之后。 在这种情况下,性能非常快,阻止列表的成本几乎可以忽略不计。

您可以使用-j QUEUE目标与libnetfilter_queue结合使用iptables来执行类似的用户空间操作。 这个工具function强大,简单,logging不完整。 我build议尽可能多地从尽可能多的资源中进行阅读,因为networking上散布着许多有趣的材料,这些材料不是任何官方文档的一部分。

对于后人:根据ipset文档默认的大小是65536,这可以通过选项来改变。

maxelem此参数对所有散列types集的create命令有效。 它定义了可以存储在集合中的元素的最大数量,默认ipset create test hash:ip maxelem 2048. 65536.例如: ipset create test hash:ip maxelem 2048.

我把这个放在这里,因为我还不能评论。