我怎样才能以编程的方式即时管理iptables规则?

45 人关注

我需要查询现有的规则,并能够轻松地添加和删除规则。我没有发现任何用于做这个的API。有什么东西是我遗漏的吗?

我最接近的解决方案是使用 iptables-save | iptables-xml 进行查询,并手动调用iptables命令本身来添加/删除规则。我考虑的另一个解决方案是简单地从我的应用程序的数据库中重新生成整个规则集,并刷新整个链,然后再次应用它。但我想避免这样做,因为我不想丢掉任何数据包--除非有一种方法可以原子化地做到这一点。我想知道是否有一个更好的方法。

如果能有一个C语言的API就更好了;但是,由于我打算把它建成一个独立的suid程序,用任何语言做这个的库也可以。

1 个评论
显然,从XML到iptables-restore xsltproc iptables.xslt my-iptables.xml | iptables-restore 是可以的。参见 iptables-xml 的手册。
linux
api
kernel
iptables
netfilter
Ycros
Ycros
发布于 2008-09-21
9 个回答
Eric Lathrop
Eric Lathrop
发布于 2020-10-21
已采纳
0 人赞同

From the netfilter常见问题 :

遗憾的是,答案是。没有。

现在你可能会想 "但是libiptc呢?"。正如人们在邮件列表中无数次指出的那样,libiptc是 NEVER 是作为一个公共接口使用的。我们不保证有一个稳定的接口,而且计划在下一个linux包过滤的版本中删除它。

我们很清楚,这样的API根本上是缺乏的,我们正在努力改善这种情况。在那之前,建议使用system()或者在iptables-restore的stdin中开一个管道。后者会给你一个更好的性能。

我想知道为什么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,作为一个具有REST API的系统范围内的iptables防护。请看完整的答案。 stackoverflow.com/a/22647960/2184341
Jerub
Jerub
发布于 2020-10-21
0 人赞同

使用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

你可以使用ipsets,而不是每次你想改变哪些端口可以访问22号端口时都要替换这些规则(比如说,端口敲击的时候很有用)。识别。

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。
Grzegorz Luczywo
Grzegorz Luczywo
发布于 2020-10-21
0 人赞同

你可以考虑使用 rfw 这是iptables的REST API。 它从各种潜在的并发源中序列化iptables命令,并在飞行中远程执行iptables。

rfw是为分布式系统设计的,它试图在多个盒子上更新防火墙规则,但它也可以在本地主机接口的单机上运行。在这种情况下,它可以避免SSL和认证的开销,因为它可以在纯HTTP上运行。

命令样本。

PUT /drop/input/eth0/11.22.33.44

which corresponds to:

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将在很大程度上满足其安全需求。
Cold
干得好!!我认为它可以成为其他平台的 "核心 "技术。缺少一些扩展,但还行。
Cold
你对OP的回答是,我认为,"不!这是不可能的,除非你使用子进程(或直接调用操作系统)"
C. K. Young
C. K. Young
发布于 2020-10-21
0 人赞同

根据我的理解(尽管似乎没有参考资料提到), iptables-restore 是原子性的。最后,当 COMMIT 行被读取时, iptables 调用 libiptc 中的 iptc_commit (在一个内部接口中你不应该使用),然后它用你的新规则集调用 setsockopt(SO_SET_REPLACE)

这听起来就像你能得到的那样原子化:用一个内核调用。然而,请更多的知识分子对此提出异议。)

我可以确认,你的描述是正确的。替换代码0】是在内核中作为一个原子操作完成的。

To be even more specific 操作 "仅 "在每个CPU上是原子的。由于我们在每个CPU上存储整个规则集blob(由于缓存优化)。

MarkR
MarkR
发布于 2020-10-21
0 人赞同

故意没有API来管理这些规则。你不应该想这样做。或者别的什么。

如果你需要足够动态的规则,你关心执行/sbin/iptables的性能,还有其他方法可以做到。

  • Using something like the "recent" match or ip set matching, you can add/remove IP addresses from black/white lists without changing the rule set.
  • You can pass packets into userspace for filtering using NFQUEUE
  • 在我看来,没有这方面的API是愚蠢的。 我并不真正关心性能,但调用iptables感觉是一种可怕的黑客方式。
    嗯,我可以使用ipsets--从性能的角度来看,这确实是个好主意。不幸的是,我必须推出我自己的内核,而这是不可能的,因为这个软件要运行的一些地方是在虚拟机上,我不可能轻易改变内核。而且他们仍然没有提供一个好的API。
    ipt_recent是一个标准的iptables匹配目标,它允许你在不改变规则的情况下,通过写到/proc中的文件,动态地从一个集合中添加/删除IP地址。另一方面,它不打算用于大的IP集,似乎有一个固定的最大限制。
    Patrick
    Patrick
    发布于 2020-10-21
    0 人赞同

    今天早上,我醒来时发现我受到了来自俄罗斯的拒绝服务(DOS)攻击。他们从几十个IP区块中攻击我。他们肯定有一个很大的IP池,或者有某种代理列表/服务。 每当我封锁一个IP时,就会有另一个IP冒出来。 最后,我找了一个脚本,发现我需要自己写一个解决方案。 下面的内容有点激进,但他们把我的最高负载水平提高到200以上。

    这是我写的一个快速脚本,用于实时阻止DOS。

    cat  **"output of the logs"** | php ipchains.php **"something unique in the logs"**
    

    ==> PHP Script:

    $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。它应该是一样的。
    Andrew
    Andrew
    发布于 2020-10-21
    0 人赞同

    这是一个使用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列在白名单上,这些IP总是有效的,而且可能有连接问题(由于用户错误)。

    我不时地对iptables过滤器列表进行分类,并从中创建IP范围(使用一个不同的脚本--当检查时,它们通常是来自印度、中国和俄罗斯的IP范围)。因此,我的整个iptables过滤器规则集保持在50到500个条目之间;ipset在这么短的列表中并没有真正改善。

    数字123的意义是什么? 如果你想通过检查第一个八位数的值来检查你是否有一个有效的IP地址,我相信它可以是任何东西,最多223。
    这不是对任何八位数的测试。如果在解析/var/log/secure时,你最终得到一个空的或损坏的字段,你测试这个值就不会运行iptables命令。'123'这个值是很随意的。 在更多的测试中,我发现你可能应该用'1'替换'123',以包括一个完整的IP范围,虽然。 当测试IP小于'123'时,对于2.0.0.0到255.255.255.255范围内的IP地址将是真实的,所以它不会阻止1.x.x.x范围内的IP。 当测试IP小于'1'时,它匹配0.0.0.1到255.255.255.255。
    terminus
    terminus
    发布于 2020-10-21
    0 人赞同

    MarkR说的对,你不应该这样做。最简单的方法是在脚本中调用iptables,或者写下iptables的配置并 "恢复 "它。

    不过,如果你想的话,还是要读一下iptables的源代码。 iptables使用匹配和表作为共享对象。你可以使用源码或它们。

    Linux的netfilter在/usr/include/netfilter*下也有一些包含文件。这些都是有些低级的功能。它是iptables使用的东西。这是在没有iptables的情况下所能得到的最接近的API。