带有防火墙标记和 `rp_filter` 的高级路由

Adr*_*erc 5 linux routing

今天是路由日。您现在应该如何添加 IP 路由、基本使用ip rule以及iptables对阅读本文有很好的了解。

这是在LinuxFr上交叉发布的(法语)。

问题

我有一个桥接模式的 ADSL 调制解调器(Freebox)和一个 DMZ 模式的光纤(Livebox)。除了选定的流量外,所有流量都通过 ADSL,而另一个流量则通过光纤通道。这是我的设置,在相反的情况下,问题仍然是一样的。

为了缓解这个问题,我将讨论通过路由器、运行 Debian GNU/Linux 的流量,而不是该路由器生成的流量。

我的 ADSL 地址是 82.236.xxx.xxx,光纤是 90.76.xxx.xxx。

什么应该工作

我们理所当然地认为mangle桌子是空的。

> ip route show table livebox
default via 192.168.1.1 dev eth_livebox src 192.168.1.253 
82.236.xxx.0/24 dev eth_adsl scope link src 82.236.xxx.xxx 
192.168.0.0/24 dev bridge_local scope link src 192.168.0.253 
192.168.1.0/24 dev eth_livebox scope link src 192.168.1.253 

iptables -t mangle -I PREROUTING --destination 23.23.114.123 -j MARK --set-mark 1
ip rule add from all fwmark 0x1 lookup livebox
Run Code Online (Sandbox Code Playgroud)

这是行不通的。这意味着当我做

curl http://api.ipify.org/ --resolve api.ipify.org:80:23.23.114.123
Run Code Online (Sandbox Code Playgroud)

从 LAN 客户端,不返回任何内容。

什么有效

livebox表是不变的。但是,在刷新mangle表后,我们用以下内容填充它:

iptables -t mangle -I PREROUTING --source 23.23.114.123 -j TOS --set-tos 0x10
iptables -t mangle -I PREROUTING --destination 23.23.114.123 -j TOS --set-tos 0x10
ip rule add from all tos 0x10 lookup livebox
Run Code Online (Sandbox Code Playgroud)

进而 :

> curl http://api.ipify.org/ --resolve api.ipify.org:80:23.23.114.123
90.76.xxx.xxx
Run Code Online (Sandbox Code Playgroud)

Adr*_*erc 6

为什么?

在这两个片段之间,我更改了两件事: 1. 我使用TOS IP 标头而不是防火墙标记,由内核及其模块在内部管理。2. 我标记了返回的数据包。

我撒了谎(遗漏): rp_filter

我忘了说,在所有接口上,rp_filter都设置为 1。根据内核文档,值 1 代表RFC 3704 中定义的严格反向路径检查。

总而言之,当数据包进入接口时,内核会交换IP 地址字段sourcedestinationIP 地址字段,并尝试路由这个新的假数据包。如果选择的路由是通过数据包来自的接口出去,则检查没问题。否则,数据包将被丢弃。

因此,根据What should work,由于传入的数据包未标记为1,因此严格的反向路径检查失败。确实,返回的数据包是通过的eth_livebox,但是没有标记,它是根据main表路由的,上面写着要通过eth_adsl。这是一个失败。这就是更改编号的原因。2.

为什么是 TOS 而不是 MARK ?

是的,当然,我尝试-j MARK返回数据包。这是行不通的。经过几个小时的挖掘旧邮件列表消息后,我找到了这个

好的,看看 fib_validate_source(),看起来 rp_filter 的工作原理就是内核获取数据包,反转 src & dst 地址和接口,并尝试进行路由查找。它在构建路由密钥时完全忽略了标记,但奇怪的是,它确实检查了 TOS。

哦哦。所以我阅读了一些关于 TOS 的文档,并且由于我仍在寻找解决方案,所以我快速而肮脏地完成了。有用。这就是更改编号的原因。2.

可以更好吗?

我让你检查的代码fib_validate_source()。老实说,这对我来说太重了。

但在我看来,结果是不一致的。我知道这TOS是在IP标题内,并且防火墙标记特定于主机内部。另一方面ip rule有一个语法来在TOS标头值或防火墙标记值上查找路由fwmark

我不知道我现在真正应该做什么,这是我的结论,非排他性。

放弃rp_filter公共接口

目标rp_filter是避免 DDoS,同时也过滤直接在我自己管理的网络中伪造数据包的流氓客户端。它有点像SPF,它保护其他演员。

在我的公共接口上,我显然有一个路由条目,如default via IP,所以无论如何,rp_filter都会得出可以回答数据包的结论。实际上,如果数据包到达我的路由器之前,那是因为我的 ISP 允许它通过。他们设法路由它。

所以我可以放弃并rp_filter在所有这些接口上设置为 0(警告:应用 net.ipv4.conf.eth_livebox.rp_filter 和 net.ipv4.conf.all.rp_filter 之间的最大值)。

编辑:用户rpfilter来自iptables

LinuxFR 上的某个人让我注意到了这一点:该rp_filter控件已被弃用,或者至少处于废弃状态。确实有一个rpfilter模块for iptables,这是它的未来。作为一个例子,取自这里

iptables -A PREROUTING -t raw -m rpfilter --invert -j DROP
ip6tables -A PREROUTING -t raw -m rpfilter --invert -j DROP
Run Code Online (Sandbox Code Playgroud)

它很好地集成在防火墙中,它可以工作,并且返回的数据包甚至不需要标记,因为它们被它们的状态识别。

向内核开发人员报告这个“错误”

这对我来说似乎非常不一致,而且记录非常糟糕。一方面,ip rule让您制定适用于传入数据包但不适用于返回数据包的规则:不当行为。

但我在这里:我没有足够的时间来熟练地阅读这段代码、理解它并尝试修复它。而且我什至不知道是否有充分的理由,例如调用fib_validate_source.

但是,如果这里有人告诉我可以将其报告给关心或解释的人,并且可能会修复和改进,我会很乐意这样做。

编辑:也许rp_filter应该更新参数的文档......

  • 感谢您为我指明正确的方向!按照您的链接,我发现 [this line](https://github.com/torvalds/linux/blob/c1d61e7fe3760851319138550efb732273ab2e57/net/ipv4/fib_frontend.c#L351) 这意味着它检查 [https://valid_mark]( github.com/torvalds/linux/blob/c1d61e7fe3760851319138550efb732273ab2e57/net/ipv4/devinet.c#L2271) 在接口上,这意味着您需要将 net.ipv4.conf.all.src_valid_mark 设置为 make interface1 rp_filter 在查找 FIB 以检查路由时在此数据包上设置的尊重标记。非常感谢! (5认同)
  • 以下是 2009 年 linux net-next 中关于 `src_valid_mark` 的提交:[net: restore ip source validation](https://git.kernel.org/pub/scm/linux/kernel/git/davem/net-next. git/commit/?h=v2.6.33&id=28f6aeea3f12d37bd258b2c0d5ba891bff4ec479) (4认同)