natmap icon indicating copy to clipboard operation
natmap copied to clipboard

[Feature Request] iptables / nftables forwarding

Open MikeWang000000 opened this issue 11 months ago • 6 comments

Natter 在 v2.0 版本中新增了 iptables / nftables 转发功能,通过 -m 选项可指定转发的方法。

可以考虑在 NATMap 添加同样的功能。

考虑设计此功能的原因是:

  • 省去手动设置防火墙端口转发的步骤。虽然不同发行版的防火墙各不相同,但都以 iptables / nftables 作为后端。由 NATMap 设置可一步到位;
  • BT 类程序打洞需要保持内外部端口号一致,需要 NATMap 动态调整端口转发规则;
  • 虽然通过通知脚本能达到类似目的,但是在 NATMap 退出时会有规则残留。

对于 NATMap : - 可以考虑使用 libiptc (iptables (legacy))、libnftl (nftables) 提供的 API,这样比直接调用命令行再解析文本更科学; - 可以考虑使用宏隔离,不编译不支持的平台,如 FreeBSD / macOS

放弃了使用 libiptc 的想法,首先是 NATMap 使用静态编译,加入依赖会使得体积膨胀;其次是 libiptc 也没有提供静态链接的方法;最后是根据 netfilter FAQ §4.5,官方不推荐。

实现方式与 Natter 相同,直接调用 iptables 二进制。


Natter 参考:

https://github.com/MikeWang000000/Natter/blob/6e1c66db06e1bb746e55288da1b9fb012bf701b5/natter.py#L479-L637

一些经验:

几乎所有 Linux 发行版包括 OpenWRT、CentOS、Debian、Alpine Linux 还有一些 NAS 专用系统例如威联通的 QTS、QuTS 都可以顺利自动设置转发。这些都通过了测试。

部分系统会存在一些问题,例如群晖 DSM,还有跑在光猫里的嵌入式定制Linux。它们的 iptables 内核模块是修剪过的,不认识规则的 --comment 备注。但是去除后也能正常转发。

所以考虑仅设置最简单的 NAT 转发规则即可。因为经过裁剪的系统也会保留最基本的 NAT 功能,系统本身会用到。


这个坑有点大,先提出来看看可行性。

MikeWang000000 avatar Mar 09 '24 19:03 MikeWang000000

一些参考(来自 miniupnp):

  • https://github.com/miniupnp/miniupnp/blob/master/miniupnpd/netfilter/iptcrdr.c
  • https://github.com/miniupnp/miniupnp/blob/master/miniupnpd/netfilter_nft/nftnlrdr.c

MikeWang000000 avatar Mar 09 '24 19:03 MikeWang000000

感谢就此话题展开讨论~

我比较倾向于使用通知脚本实现这一目的,程序内置的功能会比较单一,相比脚本缺少灵活性,比如需要根据外部环境适配的情况。对于当前通知脚本缺少程序退出时的清理功能,我提议增加 -q 参数指定另一个通知脚本,调用时机是:

  1. 程序退出时。
  2. 端口变化时,先调 -q 脚本通知清理,再调 -e 脚本通知配置。

为了使用便利性集成一些常用系统上的基础配置脚本在程序的源代码中。

请问这样怎么样,是否还有不完备的地方?谢谢~

heiher avatar Mar 10 '24 01:03 heiher

感谢答复。

至于灵活性问题:

  • 此项功能本身单一,用途就是将本机接收到 -b 端口的数据,修改目的地址重定向至 -t 的 IP 地址和 -p 的端口,作为当前使用应用层面 socket 转发的替代;
  • 适用于几乎所有 Linux 发行版。

当然,此项需求本身也是出于便利性考虑,减少用户编写防火墙规则的负担。


如果觉得没有内置的必要,保持现状就可以:

非持久化的规则会在重启时消失;持久化的规则也可以通过设置在规则链中,下次调用通知脚本时,可清理上次的规则。

只不过内置处理可以顺便提前一步。特地添加第二个通知脚本反而更复杂了(我觉得会用的人并不多)


这是一个提议,供参考~

MikeWang000000 avatar Mar 10 '24 02:03 MikeWang000000

因为iptables/nftables的流量都是链式通过的,不同系统的基础规则不同,natmap的匹配规则插在链中的哪个位置可能是需要适配的,尤其是当用户还部署了透明代理时。所以我在想将配置放在脚本里可能会比较容易处理一些。内置方式我也再研究研究,当我们归纳出一些很常见的配置后,那时再实现可能适用面会更广一些。谢谢~

heiher avatar Mar 10 '24 03:03 heiher

因为iptables/nftables的流量都是链式通过的,不同系统的基础规则不同,natmap的匹配规则插在链中的哪个位置可能是需要适配的,尤其是当用户还部署了透明代理时。所以我在想将配置放在脚本里可能会比较容易处理一些。内置方式我也再研究研究,当我们归纳出一些很常见的配置后,那时再实现可能适用面会更广一些。谢谢~

大佬看下我这个OpenWrt的实现怎么样,可以的话可以整合进/usr/lib/natmap/update.sh,然后在luci里做个选项。 https://github.com/heiher/natmap/issues/12#issuecomment-2078551805

cwbsw avatar Apr 26 '24 03:04 cwbsw

提交了一个 PR,实现了通过 iptables 转发的功能。该功能期望在全部 Linux 发行版中适用。 不过还需要充分测试。

MikeWang000000 avatar May 03 '24 11:05 MikeWang000000