如何以编程方式即时管理 iptables 规则?
Posted
技术标签:
【中文标题】如何以编程方式即时管理 iptables 规则?【英文标题】:How can I programmatically manage iptables rules on the fly? 【发布时间】:2010-09-11 16:38:48 【问题描述】:我需要查询现有规则,以及能够轻松添加和删除规则。我还没有找到任何用于执行此操作的 API。有什么我遗漏的吗?
我最接近的解决方案是使用iptables-save | iptables-xml
进行查询并手动调用 iptables 命令本身来添加/删除规则。我考虑过的另一个解决方案是简单地从我的应用程序的数据库中重新生成整个规则集并刷新整个链,然后再次应用它。但我想避免这种情况,因为我不想丢弃任何数据包——除非有一种方法可以原子地做到这一点。我想知道是否有更好的方法。
C 语言的 API 会很棒;但是,由于我打算将其构建到独立的 suid 程序中,因此使用任何语言的库也可以。
【问题讨论】:
显然可以从 XML 转到 iptables-restorexsltproc iptables.xslt my-iptables.xml | iptables-restore
。请参阅iptables-xml
的联机帮助页。
【参考方案1】:
根据 netfilter 的讨论,我知道它是一个短期解决方案,但在短期内,您可以使用用 python 包装的 iptc:
https://github.com/ldx/python-iptables
我在最近的一个项目中使用了它,发现它非常有效。
【讨论】:
此链接可能会回答问题,但最好在此处包含答案的基本部分并提供链接以供参考。如果链接页面发生更改,仅链接的答案可能会失效。【参考方案2】:您可以考虑使用rfw,它是 iptables 的 REST API。 它正在序列化来自各种潜在并发源的 iptables 命令,并即时远程执行 iptables。
rfw 专为尝试在多个机器上更新防火墙规则的分布式系统而设计,但它也可以在 localhost 接口的单台机器上运行。然后它可以避免 SSL 和身份验证开销,因为在这种情况下它可以在纯 HTTP 上运行。
示例命令:
PUT /drop/input/eth0/11.22.33.44
对应于:
iptables -I INPUT -i eth0 -s 11.22.33.44 -j DROP
您可以插入和删除规则以及查询当前状态以获取JSON格式的现有规则:
GET /list/input
免责声明:我开始了那个项目。它是在 MIT 许可下开源的。
【讨论】:
如果它是通过 HTTP 的,那不会对防火墙造成危险吗? 如上所述,默认为 HTTPS。有一个选项可以禁用 SSL 并使用纯 HTTP,这在单用户环境中在 localhost 上运行时很有用。 任何以“编程方式”/远程和/或自动操作防火墙的行为都是危险的。但是,适当的安全措施可以缓解这种情况,即 api 网关(如 kong)后面的 sso 令牌/2fa 将大大有助于满足安全需求。 干得好!!!我认为它可能是其他平台的“核心”技术。缺少一些扩展,但没关系。 您对 de OP 的回答是,我认为,“不!这是不可能的,除非您使用子进程(或直接调用操作系统)”【参考方案3】:这是一个使用 bash 和 iptables 动态阻止黑客在 CentOS 上滥用 sshd 的示例。在这种情况下,我将 sshd 配置为禁止密码登录(允许密钥)。我在 /var/log/secure 中查找“Bye Bye”的条目,这是 sshd 说 f-off 的礼貌方式......
IP=$(awk '/Bye Bye/print $9' /var/log/secure |
sed 's/://g' |sort -u | head -n 1)
[[ "$IP" < "123" ]] ||
echo "Found $IP - blocking it..." >> /var/log/hacker.log
/sbin/iptables -A INPUT -s $IP -j DROP
service iptables save
sed -i "/$IP/d" /var/log/secure
我每秒或每分钟循环运行一次,或者任何让我开心的事情。我测试了 $IP 的值以验证它是否找到了有用的值,如果是,我调用 iptables 将其删除,并使用 sed 清除 $IP 的日志文件,这样就不会再次添加该条目。
我做了一些预处理(未显示)以将一些始终有效且可能无法连接(由于用户错误)的重要 IP 列入白名单。
我不时地对 iptables 过滤器列表进行排序并从中创建 IP 范围(使用不同的脚本 - 选中时,它们通常是来自印度、中国和俄罗斯的 IP 范围)。因此,我的整体 iptables 过滤规则集保持在 50 到 500 个条目之间; ipset 在这么短的列表上并没有真正改进。
【讨论】:
123这个数字有什么意义?如果你想通过检查第一个八位字节的值来检查你是否有一个有效的 IP 地址,我相信它可能是 223 以内的任何值。 这不是对任何八位字节的测试。如果在解析 /var/log/secure 时得到一个空或损坏的字段,则测试该值以不运行 iptables 命令。 '123' 值是相当随意的。不过,在对此进行更多测试时,我发现您可能应该将 '123' 替换为 '1' 以包含完整的 IP 范围。测试小于“123”的 IP 时,2.0.0.0 到 255.255.255.255 范围内的 IP 地址为 true,因此它不会阻止 1.x.x.x 范围内的 IP。当测试IP小于'1'时,匹配0.0.0.1到255.255.255.255。【参考方案4】:今天早上我醒来发现正在受到来自俄罗斯的拒绝服务 (DOS) 攻击。他们从几十个 IP 块中攻击我。他们必须拥有大量 IP 或某种代理列表/服务。每次我屏蔽一个IP,就会弹出另一个IP。最后,我寻找了一个脚本,发现我需要编写自己的解决方案。以下内容有点激进,但他们将我的 TOP LOAD LEVEL 运行到了 200 以上。
这是我编写的用于实时阻止 DOS 的快速脚本。
cat **"output of the logs"** | php ipchains.php **"something unique in the logs"**
==> PHP 脚本:
<?php
$ip_arr = array();
while(1)
$line = trim(fgets(STDIN)); // reads one line from STDIN
$ip = trim( strtok( $line, " ") );
if( !array_key_exists( $ip, $ip_arr ) )
$ip_arr[$ip] = 0;
$regex = sprintf( "/%s/", $argv[1] );
$cnt = preg_match_all( $regex, $line );
if( $cnt < 1 ) continue;
$ip_arr[$ip] += 1;
if( $ip_arr[$ip] == 1 )
// printf( "%s\n", $argv[1] );
// printf( "%d\n", $cnt );
// printf( "%s\n", $line );
printf( "-A BLOCK1 -s %s/24 -j DROP\n", $ip );
$cmd = sprintf( "/sbin/iptables -I BLOCK1 -d %s/24 -j DROP", $ip );
system( $cmd );
?>
假设:
1) BLOCK1 is a Chain already created.
2) BLOCK1 is a Chain that is run/called from the INPUT CHAIN
3) Periodically you will need to run "ipchains -S BLOCK1" and put output in /etc/sysconfig file.
4) You are familiar with PHP
5) You understand web log line items/fields and output.
【讨论】:
看看fail2ban。应该是一样的。【参考方案5】:据我了解(尽管似乎没有提及它),iptables-restore
是原子的。最后,当读取COMMIT
行时,iptables
在libiptc
中调用iptc_commit
(在您不应该使用的内部接口中),然后使用您的新规则集调用setsockopt(SO_SET_REPLACE)
。
这听起来就像你能得到的一样原子:一个内核调用。但是,请更多知识渊博的各方对此提出异议。 :-)
编辑:
我可以确认您的描述是正确的。 iptables-restore
在内核中作为原子操作完成。
更具体操作“仅”在每个 CPU 基础上是原子的。因为我们存储每个 CPU 的整个规则集 blob(由于缓存优化)。
【讨论】:
【参考方案6】:使用 iptables-save 和 iptables-restore 查询和重新生成规则是最有效的方法。这些曾经是 shell 脚本,但现在它们是运行非常高效的 C 程序。
但是,我应该指出,您可以使用一个工具来简化 iptables 的维护。大多数动态规则集实际上都是重复多次的相同规则,例如:
iptables -A INPUT -s 1.1.1.1 -p tcp -m --dport 22 -j ACCEPT
iptables -A INPUT -s 2.2.2.0/24 -p tcp -m --dport 22 -j ACCEPT
iptables -A INPUT -p tcp -m tcp --dport 22 -j REJECT
每次您想更改哪些端口可以访问端口 22(例如,端口敲门很有用)时,您可以使用 ipsets,而不是替换这些规则。即:
ipset -N ssh_allowed nethash
iptables -A ssh_allowed -m set --set ssh_allowed src -p tcp -m --dport 22 -j ACCEPT
ipset -A ssh_allowed 1.1.1.1
ipset -A ssh_allowed 2.2.2.0/24
集合可以保存 ip 地址、网络、端口、mac 地址,并在其记录中设置超时。 (曾经想在一个小时内添加一些东西吗?)。
甚至还有一种原子方式将一个集合与另一个交换,因此刷新意味着创建一个新的临时集合,然后将其作为现有集合的名称进行交换。
【讨论】:
是的,最重要的答案提到了 ipsets,但正如我在评论中所说的那样 - 它需要一个默认情况下不在 Ubuntu 中的内核模块,而且它不是我可以安装在任何我使用的虚拟机。 是的,我在 07 年 1 月报告了这个错误。 bugs.launchpad.net/ubuntu/+source/ipset/+bug/79182 Ubuntu 现在已经足够支持 ipset 了。【参考方案7】:MarkR 说得对,你不应该这样做。最简单的方法是从脚本中调用 iptables 或编写 iptables 配置并“恢复”它。
不过,如果您愿意,请阅读 iptables 的源代码。 iptables 使用匹配项和表作为共享对象。您可以使用源或它们。
Linux 网络过滤器在 /usr/include/netfilter* 下也有一些包含文件。这些是一些低级功能。这是 iptables 使用的。这与没有 iptables 的 API 一样接近。
但是这个 API 很“混乱”。请记住,它被设计为仅供 iptables 使用。它没有很好的文档记录,您可能会遇到非常具体的问题,API 可以在没有任何警告的情况下快速更改,因此升级可能会破坏您的代码,等等。
【讨论】:
我可以接受使用内部 API 不好,但为什么会如此糟糕以至于他们故意不包含公共 API?如果我可以恢复单个链,我可能会进行恢复 - 我必须进行一些测试。 是的,您可以恢复单个链。 :-)【参考方案8】:来自netfilter FAQ:
不幸的是,答案是:不。
现在您可能会想“但是 libiptc 呢?”。正如邮件列表中多次指出的那样,libiptc 从不 打算用作公共接口。我们不保证一个稳定的接口,并计划在 linux 包过滤的下一个版本中将其删除。 libiptc 太底层了,无论如何都不能合理使用。
我们很清楚这种 API 根本就缺乏,我们正在努力改善这种情况。在此之前,建议使用 system() 或打开管道进入 iptables-restore 的标准输入。后者将为您提供更好的性能。
【讨论】:
我想知道为什么FAQ 没有解决原子性问题。这应该;为了确保它是原子的,我费尽心思查看了 iptables-restore 的实现。这对这里的 OP 很重要,而且我有一个项目也需要它。 这个 netfilter 邮件列表帖子说 iptables-restore 是原子的:mail-archive.com/netfilter-devel@lists.samba.org/msg00456.html 对于仍然想这样做的非常勇敢的人,这里有一些信息:netfilter.org/documentation/HOWTO/… 以编程方式使用 netfilter/iptables 有两个问题:缺乏 API 和并发访问缺乏原子性。这些都是即时更改规则的障碍。为了克服这个问题,我们开发了 rfw,它作为一个系统范围的 iptables 保护,带有 REST API。查看完整答案:***.com/a/22647960/2184341【参考方案9】:故意没有 API 来管理这些规则。你不应该想要这样做。什么的。
如果您需要足够动态的规则,您关心执行 /sbin/iptables 的性能,还有其他方法可以做到:
使用“最近”匹配或 ip 集匹配之类的东西,您可以在不更改规则集的情况下从黑/白名单中添加/删除 IP 地址。 您可以将数据包传递到用户空间以使用 NFQUEUE 进行过滤【讨论】:
在我看来,没有用于此的 API 似乎很愚蠢。我并不真正关心性能本身,但调用 iptables 感觉就像是一种可怕的 hacky 做事方式。 嗯,我可以使用 ipsets - 从性能的角度来看,这是一个非常好的主意。不幸的是,我必须推出自己的内核,这是不可能的,因为该软件将运行的一些地方是在我无法轻易弄乱内核的虚拟机上。而且他们仍然没有提供好的 API。 ipt_recent 是一个标准的 iptables 匹配目标,它允许您通过写入 /proc 中的文件来动态添加/删除 IP 地址,而无需更改规则。另一方面,它不适用于大量 IP,并且似乎有固定的最大限制。以上是关于如何以编程方式即时管理 iptables 规则?的主要内容,如果未能解决你的问题,请参考以下文章