如何以编程方式动态管理 iptables 规则?

发布于 2024-07-04 21:44:51 字数 338 浏览 8 评论 0原文

我需要查询现有规则,以及能够轻松添加和删除规则。 我还没有找到任何 API 来执行此操作。 我缺少什么吗?

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

如果有 C 语言的 API 就太好了; 然而,由于我计划将其构建为独立的 suid 程序,因此以任何语言执行此操作的库也很好。

I need to query existing rules, as well as being able to easily add and delete rules. I haven't found any API's for doing this. Is there something that I'm missing?

The closest I've come to a solution is using iptables-save | iptables-xml for querying and manually calling the iptables command itself to add/delete rules. Another solution I've considered is simply regenerating the entire ruleset out of my application's database and flushing the whole chain, then applying it again. But I want to avoid this as I don't want to drop any packets -- unless there's a way to atomically do this. I'm wondering if there's a better way.

An API in C would be great; however, as I'm planning to build this into a stand-alone suid program, libraries that do this in ANY language are fine too.

如果你对这篇内容有疑问,欢迎到本站社区发帖提问 参与讨论,获取更多帮助,或者扫码二维码加入 Web 技术交流群。

扫码二维码加入Web技术交流群

发布评论

需要 登录 才能够评论, 你可以免费 注册 一个本站的账号。

评论(9

南巷近海 2024-07-11 21:44:51

我知道它是一个短期解决方案,根据 netfilter 的讨论,但在短期内,您可以使用包含在 python 中的 iptc :

https://github.com/ldx/python-iptables

我在最近的一个项目中使用了它,发现它非常有效。

I know its a short term solution, per the netfilter discussion, but in the short term you can use iptc wrapped in python with this:

https://github.com/ldx/python-iptables

I played with it some in a recent project of mine and found it quite effective.

无法回应 2024-07-11 21:44:51

MarkR 是对的,你不应该这样做。 最简单的方法是从脚本调用 iptables 或编写 iptables 配置并“恢复”它。

不过,如果您愿意,请阅读 iptables 的源代码。 iptables 使用匹配和表作为共享对象。 您可以使用来源或它们。

Linux netfilter 在 /usr/include/netfilter* 下还有一些包含文件。 这些是一些低级功能。 这就是 iptables 使用的。 这是在没有 iptables 的情况下可以获得的最接近的 API。

但这个 API 很“混乱”。 请记住,它被设计为仅供 iptables 使用。 它没有很好的文档记录,您可能会遇到非常具体的问题,API 可以相当快地更改而不会发出任何警告,因此升级可能会破坏您的代码等。

MarkR's right, you're not supposed to do this. The easiest way is to call iptables from the script or to write the iptables config and 'restore' it.

Still, if you want to, read the source of iptables. iptables uses matches and tables as shared objects. You can use the source or them.

The Linux netfilter also has some include files under /usr/include/netfilter*. These are somewhat low-level functions. It is what iptables uses. This is as near an API as one can get without iptables.

But this API is 'messy'. Bear in mind that it was designed to be used only by iptables. It's not very well documented, you can hit very specific problems, the API can change fairly quick without any warning, so an upgrade propably will break your code, etc.

只怪假的太真实 2024-07-11 21:44:51

这是在 CentOS 上使用 bash 和 iptables 动态阻止黑客滥用 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 在这么短的列表上并没有真正改进太多。

This is an example of using bash and iptables to dynamically block hackers abusing sshd on CentOS. In this case, I configured sshd to disallow password login (allows keys). I look in /var/log/secure for entries of "Bye Bye", which is sshd's polite way of saying 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

}

I run this in a loop every second, or minute, or whatever makes me happy. I test the value of $IP to verify it found a useful value, if so I invoke iptables to drop it, and I use sed to purge the log file of $IP so the entry doesn't get added again.

I do a little pre-processing (not shown) to white list some important IPs that are always valid and that might have had trouble connecting (due to user error).

From time-to-time I sort the iptables filter list and create IP ranges from them (using a different script - and when checked, they are usually IP ranges from india, china and russia). Thus, my overall iptables filter rule set stays between 50 and 500 entries; ipset doesn't really improve much on a list that short.

心是晴朗的。 2024-07-11 21:44:51

使用 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 地址,并在其记录中设置超时。 (曾经想在一个小时内添加一些东西吗?)。

甚至还有一种原子方式将一个集合与另一个集合交换,因此刷新意味着创建一个新的临时集合,然后将其交换为现有集合的名称。

Using iptables-save and iptables-restore to query and regenerate rules is easily the most efficient way of doing it. These used to, once, be shell scripts, but now they are C programs that work very efficiently.

However, I should point out that there is a tool that you can use which will make maintaining iptables much easier. Most dynamic rulesets are really the same rule repeated many times, such as:

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

Instead of replacing those rules every time you want to change what ports can access port 22 (useful for say, port knocking), you can use ipsets. Viz:

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

Sets can hold ip addresses, networks, ports, mac addresses, and have timeouts on their records. (Ever wanted to add something for just an hour?).

There is even an atomic way of swapping one set with another, so a refresh means creating a new temporary set, then swapping it in as the name of the existing set.

原谅我要高飞 2024-07-11 21:44:51

您可以考虑使用 rfw 这是 iptables 的 REST API。
它序列化来自各种潜在并发源的 iptables 命令,并动态远程执行 iptables。

rfw 专为尝试更新多个机器上的防火墙规则的分布式系统而设计,但它也可以在本地主机接口上的单台计算机上运行。 然后它可以避免 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 许可下开源的。

You may consider using rfw which is the REST API for iptables.
It is serializing iptables commands from various potentially concurrent sources and remotely executes iptables on the fly.

rfw is designed for distributed systems that try to update firewall rules on multiple boxes but it can be run also on a single machine on localhost interface. Then it allows avoiding the SSL and authentication overhead as it can be run on plain HTTP in this case.

Sample command:

PUT /drop/input/eth0/11.22.33.44

which corresponds to:

iptables -I INPUT -i eth0 -s 11.22.33.44 -j DROP

You can insert and delete rules as well as query for current status to get the existing rules in JSON format:

GET /list/input

Disclaimer: I started that project. It's open source under the MIT license.

夏至、离别 2024-07-11 21:44:51

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

这听起来就像你能得到的最原子的一样:通过一个内核调用。 然而,请更多有知识的人士对此提出异议。 :-)

编辑:
我可以确认你的描述是正确的。 iptables-restore 作为内核中的原子操作完成。

更具体地说,“仅”操作在每个 CPU 上是原子的。 因为我们存储每个 CPU 的整个规则集 blob(由于缓存优化)。

As far as I understand (although no reference seems to mention it), iptables-restore is atomic. At the end, when the COMMIT line is read, iptables calls iptc_commit in libiptc (which in an internal interface you aren't supposed to use), which then calls setsockopt(SO_SET_REPLACE) with your new rulesets.

That sounds about as atomic as you can get: with one kernel call. However, more knowledgeable parties are invited to dispute this. :-)

Edit:
I can confirm that your description is correct. iptables-restore is done as an atomic operation in the kernel.

To be even more specific the operation "only" is atomic on a per CPU basis. As we store the entire ruleset blob per CPU (due to cache optimizations).

尘世孤行 2024-07-11 21:44:51

故意没有 API 来管理这些规则。 你不应该想这样做。 或者其他的东西。

如果您需要足够动态的规则,并且关心执行 /sbin/iptables 的性能,则还有其他方法可以实现:

  • 使用“最近”匹配或 ip 集匹配之类的内容,您可以从黑色中添加/删除 IP 地址/白名单而不更改规则集。
  • 您可以使用 NFQUEUE 将数据包传递到用户空间进行过滤

There is deliberately no API to manage these rules. You're not supposed to want to do so. Or something.

If you need rules which are sufficiently dynamic you care about the performance of executing /sbin/iptables, there are other ways to do it:

  • 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
帅的被狗咬 2024-07-11 21:44:51

今天早上我醒来发现正在遭受来自俄罗斯的拒绝服务(DOS)攻击。 他们从几十个 IP 区块中攻击我。 他们必须拥有大量 IP 或某种代理列表/服务。 每次我封锁一个IP,就会弹出另一个IP。 最后,我寻找了一个脚本,发现我需要编写自己的解决方案。 下面的内容有点激进,但他们将我的最高负载级别运行到了 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.

This morning I woke up to find that was getting a Denial Of Service (DOS) attack from Russia. They were hitting me from dozens of IP blocks. They must have either had a large pool of IPs or some sort of proxy list/service. Every time I blocked an IP, another one popped up. Finally, I looked for a script, and found I needed to write my own solution. The following is a bit agressive, but they were running my TOP LOAD LEVEL to over 200.

Here is a quick script I wrote to block the DOS in realtime.

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

==> PHP Script:

<?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 );
     }
}

?>

Assumptions:

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.
花心好男孩 2024-07-11 21:44:51

来自 netfilter 常见问题解答

不幸的是,答案是:不。

现在您可能会想“但是 libiptc 呢?”。 正如邮件列表中多次指出的那样,libiptc绝不打算用作公共接口。 我们不保证稳定的接口,并且计划在 Linux 数据包过滤的下一个版本中将其删除。 libiptc 太低层了,无论如何都无法合理使用。

我们很清楚这样的 API 存在根本性的缺陷,我们正在努力改善这种情况。 在那之前,建议使用 system() 或打开一个管道进入 iptables-restore 的标准输入。 后者将为您提供更好的性能。

From the netfilter FAQ:

The answer unfortunately is: No.

Now you might think 'but what about libiptc?'. As has been pointed out numerous times on the mailinglist(s), libiptc was NEVER meant to be used as a public interface. We don't guarantee a stable interface, and it is planned to remove it in the next incarnation of linux packet filtering. libiptc is way too low-layer to be used reasonably anyway.

We are well aware that there is a fundamental lack for such an API, and we are working on improving that situation. Until then, it is recommended to either use system() or open a pipe into stdin of iptables-restore. The latter will give you a way better performance.

~没有更多了~
我们使用 Cookies 和其他技术来定制您的体验包括您的登录状态等。通过阅读我们的 隐私政策 了解更多相关信息。 单击 接受 或继续使用网站,即表示您同意使用 Cookies 和您的相关数据。
原文