iptables、ipchains 和 ipfw 编程接口的历史

iptables、ipchains 和 ipfw 编程接口的历史

最近我不得不摆弄iptablesGo 的规则,我注意到码头工人的核心的包装器库exec()输出到iptables命令并屏幕抓取标准输出。这让我感到惊讶。

在Python领域,有python iptables:

与 iptables 的互操作性是通过使用 iptables C 库(libiptc、libxtables 和 iptables 扩展)实现的,而不是调用 iptables 二进制文件并解析其输出。

我猜想 Python 库允许在运行时加载 C 库,而 Go 不能[编辑:我错了],但 Go 不能静态链接到这些库吗?因为 Go 库必须libxtables.a从某个地方获取等等? (我正在Debian中dpkg -L查找相关软件包,但我只看到了s。)-dev.so

无论如何,根据网络过滤器常见问题解答:

4.5 是否有用于添加/删除规则的 C/C++ API?

不幸的是,答案是:不。

现在您可能会想“但是 libiptc 呢?”。正如邮件列表中多次指出的那样,libiptc 是绝不旨在用作公共接口。我们不保证稳定的接口,并且计划在 linux packet 的下一个版本中将其删除

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

好吧,也许您不应该将这些 C 库视为稳定的。然后我想“为什么不直接交谈/proc或其他什么?”事实证明,iptables大多数情况下不用于/proc与内核对话(只是为了读取表名?),并且主接口实际上位于getsockopt()setsockopt()绑定的套接字上。

这又是一个惊喜! (但也许只是因为我不熟悉这种代码,这似乎是一种与内核交互的有趣方式。)

iptables我从到ipchains到进行了一些考古学ipfw,发现了一个1997 年的 ipfw 手册页这让我感觉好一点:

BUGS
       The  setsockopt(2)  interface  is a crock.  This should be
       put under /proc/sys/net/ipv4 and the world would be a bet-
       ter place.

您可以在其他地方找到“The ipfw utility first comes in FreeBSD 2.0”和

HISTORY
      Initially this utility was written for BSDI by:
       Daniel Boulet    <[email protected]>
      The FreeBSD version is written completely by:
       Ugen J.S.Antsilevich <[email protected]>
      while synopsis partially compatible with old one.

ipfw这是1994 年的 FreeBSD 2.0 版本。它仍然使用setsockopt(),但似乎使用kvm_read()而不是getsockopt()

我的问题

  • 上面说的不对的地方请指正:)
  • {get,set}sockopt()他们最初为什么选择?这是不常见的,还是对我来说是新的?
  • 为什么在某个时候没有改变?就像/proc1997 年手册页所建议的那样。
  • 为什么他们从未提出一个稳定/公共的 C 接口iptables

我的后续问题

“不完全是,主要接口是netlink的NETLINK_NETFILTER家族”

感谢这位指点!

我正在看https://git.netfilter.org/iptables/tree并且似乎只libipq使用了 netlink 套接字,除非我遗漏了一些东西。

$ ick "socket\("
include/libiptc/libiptc.h
158:int iptc_get_raw_socket(void);

include/libiptc/libip6tc.h
152:int ip6tc_get_raw_socket(void);

utils/nfsynproxy.c
129:    fd = socket(AF_INET, SOCK_STREAM, 0);

libiptc/libiptc.c
1312:   sockfd = socket(TC_AF, SOCK_RAW, IPPROTO_RAW);

extensions/libxt_set.h
14: int res, sockfd = socket(AF_INET, SOCK_RAW, IPPROTO_RAW);

libipq/libipq.c
223:                h->fd = socket(PF_NETLINK, SOCK_RAW, NETLINK_FIREWALL);
225:                h->fd = socket(PF_NETLINK, SOCK_RAW, NETLINK_IP6_FW);

libxtables/xtables.c
881:    sockfd = socket(afinfo->family, SOCK_RAW, IPPROTO_RAW);

这些libipq东西对我来说看起来“正常”:创建一个套接字,用 sockaddr、 、 等绑定sendto()recvfrom()

似乎还xtables-monitor使用一些mnl_socket_*包装器来完成网络链接的工作。

但我无法弄清楚libiptc-xtables没有提到 netlink,而且它们甚至没有绑定套接字。

https://git.netfilter.org/iptables/tree/libxtables/xtables.c#n881

https://git.netfilter.org/iptables/tree/libiptc/libiptc.c#n1312

还有其他示例不(似乎?)使用 netlink,例如来自 mozilla rr 调试器的代码:https://github.com/mozilla/rr/blob/master/src/test/netfilter.c

从 2000 年(2.2)开始,netlink 只适用于 Linux,而这个{get,set}sockopt()东西(至少)ipfw更老,而且是在 BSD 领域。

bind()我不太确定我的问题是什么了:)非netlink套接字如何在没有sockaddr的情况下以某种方式与正确的内核端进行通信?

答案1

我猜Python库允许在运行时加载C库,而Go不能

使用共享 C 库。

事实证明,iptables大多数情况下不用于/proc与内核对话(只是读取表名?),并且主接口实际上是getsockopt()setsockopt()

{get,set}sockopt()他们最初为什么选择?这是不常见的,还是对我来说是新的?

(这个答案之前错误地指出,主界面是netlinkNETLINK_NETFILTER家人。)

你是对的,iptables使用对getsockopt适当类型的未绑定套接字的调用来与内核交互,最终调用内核的netfilter代码。我怀疑这是历史原因......

顺便说一句,getsockopt并且setsockopt在各种状态下的套接字上工作,包括未绑定,并且它们必须这样做,因为它们用于在连接之前设置选项。 -via-netfilter连接sockopt实际上是一个侧通道。

为什么在某个时候没有改变?就像/proc1997 年手册页所建议的那样。

原因可能有很多,但毫无疑问的是向后兼容性——在 Linux 中,用户空间界面永远不应该被破坏。因此,虽然可以提供新的界面,但现有的界面仍将保留,这减少了改进界面或重写已运行程序的动力。

只要iptables命令行工具可以不费力气地使用,而提供更好的界面需要更多的努力,改变就会很困难。适当维护的libiptc风格库也是可能的,但开发人员从来没有太多动力iptables这样做。

为什么他们从未提出一个稳定/公共的 C 接口iptables

因为“他们”从来没有抽出时间来解决这个问题。现在iptables正在逐步淘汰nftables,其中包括许多提供不同抽象级别访问的库(libnftableslibnftnllibnfnetlink)。它使用netlink,它被设计为基于套接字的接口,用于在内核和用户空间之间传输信息,并且非常适合nftables( 和iptables) 等工具。该netlink文档列出了其他可用的系列;这些涵盖了相当多的内核托管功能。netlink

你可能会发现https://github.com/vishvananda/netlinkiptables对于从 Go开始驾驶很有用。 (这需要大量的工作,但这比从头开始要好。)

相关内容