为什么我的数据包被拒绝路由?

为什么我的数据包被拒绝路由?

我正在设置一个相当不寻常的网络配置,旨在为主机上运行的某些容器提供一些额外的保护。有一些外部要求超出了此请求的范围,这使得物理服务器需要将两个 IP 地址连接到同一个物理接口。对于普通数据,有一个“绿色”IP,对于来自容器的安全数据,有一个“红色”IP。

我正在设置的内容如下:

在此处输入图片描述

因此,安全进程在特殊的网络命名空间内运行,当它需要与外界通信时,它会将数据包发送到其本地接口(vethred,169.254.0.1),该接口是 veth 对的一半,另一侧是 vethhost,169.254.0.2。然后,数据包通过 redvlan 接口(而不是所有其他进程使用的默认“绿色”接口)从主机路由出去。

我已经成功地在一台机器上完成了这项工作,使用了一组相对较少的配置设置。但是,当我尝试在另一台主机上复制此配置时,它不起作用,数据包从 vethhost 出现,然后在路由之前被丢弃。我已在所有接口上禁用反向路径过滤,所以不是那样的。

描述一下我是如何设置的:

在红色网络命名空间内部,进程具有一个典型的世界观:

$ ip netns exec red ip -4 addr
1: lo: <LOOPBACK,UP,LOWER_UP> mtu 65536 qdisc noqueue state UNKNOWN group default qlen 1000
    inet 127.0.0.1/8 scope host lo
       valid_lft forever preferred_lft forever
11: vethred@if10: <BROADCAST,MULTICAST,UP,LOWER_UP> mtu 1500 qdisc noqueue state UP group default qlen 1000 link-netnsid 0
    inet 169.254.0.1/30 scope global vethred
       valid_lft forever preferred_lft forever
$ ip netns exec red ip -4 route
default via 169.254.0.2 dev vethred 
169.254.0.0/30 dev vethred proto kernel scope link src 169.254.0.1 

因此,当红色命名空间中的进程生成发往网络命名空间之外的数据包时,它会遇到默认路由并被路由到 vethhost 设备。有 iptables 规则控制数据包的行为:

# Mark packets emerging from vethhost
iptables -t mangle -A PREROUTING -i vethhost -j MARK --set-mark 2
# use a secondary routing table for packets marked with 0x2
ip rule add fwmark 2 table 2
# create the second routing table
ip route add default via ${RED_GATEWAY} table 2

# Packets are now routed to the redvlan interface, but bear an internal IP
# as the source address.  So we need to perform an SNAT.
iptables -t nat -A POSTROUTING -o redvlan \! -s 10.20.0.10 -j SNAT --to-source 10.20.0.10

还有其他规则可以使返回到 redvlan 接口的回复数据包被路由回 vethhost 设备并进入红色网络命名空间,但我将忽略这些规则,因为这些数据包甚至还没有离开主机。

通过如上所述配置主机,我能够从正常进程中将数据包从 redvlan 接口发送出去:

$ ping -c3 10.20.0.11
PING 10.20.0.11 (10.20.0.11) 56(84) bytes of data.
64 bytes from 10.20.0.11 (10.20.0.11): icmp_seq=1 ttl=64 time=1.28 ms
64 bytes from 10.20.0.11 (10.20.0.11): icmp_seq=2 ttl=64 time=0.825 ms
64 bytes from 10.20.0.11 (10.20.0.11): icmp_seq=3 ttl=64 time=0.938 ms

--- 10.20.0.11 ping statistics ---
3 packets transmitted, 3 received, 0% packet loss, time 2003ms
rtt min/avg/max/mdev = 0.825/1.016/1.285/0.195 ms

但是当我从红色命名空间执行相同操作时:

$ ip netns exec red ping -c3 10.20.0.11
PING 10.20.0.11 (10.20.0.11) 56(84) bytes of data.

--- 10.20.0.11 ping statistics ---
3 packets transmitted, 0 received, 100% packet loss, time 2054ms

如果我查看网络跟踪(为简洁起见,不相关的字段被截断):

[187669.474043] TRACE: raw:PREROUTING:policy:2 IN=vethhost OUT= SRC=169.254.0.1 DST=10.20.0.11 PROTO=ICMP ID=31570 SEQ=1 
[187669.474199] TRACE: mangle:PREROUTING:rule:1 IN=vethhost OUT= SRC=169.254.0.1 DST=10.20.0.11 PROTO=ICMP ID=31570 SEQ=1 
[187669.474352] TRACE: mangle:PREROUTING:policy:3 IN=vethhost OUT= SRC=169.254.0.1 DST=10.20.0.11 PROTO=ICMP ID=31570 SEQ=1 MARK=0x2 
[187669.474507] TRACE: nat:PREROUTING:policy:2 IN=vethhost OUT= SRC=169.254.0.1 DST=10.20.0.11  PROTO=ICMP ID=31570 SEQ=1 MARK=0x2 

数据包被标记并退出 PREROUTING 链,但从未被路由!它应该在 PREROUTING 之后遍历 FORWARD 和 POSTROUTING 链,但它没有,这意味着内核在做出路由决定时丢弃了数据包。而且它绝对应该匹配路由规则——这是路由表:

$ ip route show table 2
default via 10.20.0.1 dev redvlan 
10.20.0.0/24 dev redvlan proto kernel scope link src 10.20.0.10 
169.254.0.0/30 dev vethhost proto kernel scope link src 169.254.0.2 

数据包应该与默认路由或链路本地路由匹配。即使标记位不起作用,数据包至少应该被路由到绿色接口以退出主机(默认路由表中的默认路由)。但事实是它只是被丢弃了。

我读到的有关此类问题的所有内容都表明反向路径过滤可能会导致这种情况,因为在路由过程的这个阶段,源地址是不可路由的 IP。但如上所述,rp_filter 被禁用:

$ sysctl -a | grep \\.rp_filter
net.ipv4.conf.all.rp_filter = 1
net.ipv4.conf.eth0.rp_filter = 0
net.ipv4.conf.default.rp_filter = 0
net.ipv4.conf.lo.rp_filter = 0
net.ipv4.conf.redvlan.rp_filter = 0
net.ipv4.conf.vethhost.rp_filter = 0

因此,这不是反向路径过滤导致的数据包丢失。我甚至启用了 martians 日志记录,但没有任何日志消息表明 martians 被丢弃。

答案1

感谢@axus 向我指出这个帖子:https://unix.stackexchange.com/questions/292801/routing-between-linux-namespaces虽然没有直接解决这个问题,但确实包含了一些有用的建议:

内核将把命名空间视为单独的主机。这意味着您必须将内核配置为充当路由器。

事实上,我忘记ip_forward=1在 sysctl 中设置了。数据包被丢弃并不是因为路由表不匹配;而是因为内核没有配置为像路由器一样运行。

相关内容