我有一个 ipip 隧道,我希望来自 ipip 设备的所有回复数据包也通过 ipip。我尝试了以下 iptables 规则
sysctl -w net.ipv4.ip_forward=1
ip rule add fwmark 1 lookup 100
ip route add default dev ipip0 table 100
iptables -t mangle -A PREROUTING -i ipip0 -j MARK --set-mark 1
iptables -t mangle -A PREROUTING -m mark --mark 0x1 -j CONNMARK --save-mark
iptables -t mangle -A OUTPUT -m connmark --mark 0x1 -j CONNMARK --restore-mark
我可以看到预路由规则运行正常,但输出规则从未触发。我不明白为什么。
答案1
出站数据包由主机生成,没有数据包标记,但肯定有连接标记。因此标记入站数据包,将数据包标记复制到连接标记,然后用连接标记标记新的出站数据包。
iptables -t mangle -A PREROUTING -i ipip0 -m conntrack --ctstate NEW -j MARK --set-mark 1
iptables -t mangle -A PREROUTING -m mark --mark 0x1 -j CONNMARK --save-mark
iptables -t mangle -A OUTPUT -j CONNMARK --restore-mark
或更短
iptables -t mangle -A PREROUTING -i ipip0 -m conntrack --ctstate NEW -j CONNMARK --set-mark 1
iptables -t mangle -A OUTPUT -j CONNMARK --restore-mark
并在 ip 规则中使用 fwmark 选择器进行基于策略的路由。
您应该放松对没有默认路由的接口的严格反向路径检查
sysctl -w net.ipv4.conf.ipip0.rp_filter=2
RFC3704 严格反向路径
对于每个入站数据包,内核都会检查“反向路径”。内核交换入站数据包的源和目标,并通过查询路由表检查它将通过哪个接口反向路由。在此检查中,内核不尊重数据包的标记 (fwmark)。
当 rp_filter=1 时,如果数据包的返回接口与数据包进入的接口不匹配,则该数据包将被丢弃。
例如,某主机有两个接口:
eth0 的 IP 地址为 192.168.37.3,
eth1 的 IP 地址为 192.168.39.5。
默认路由通过 eth0。
default via 192.168.37.1 dev eth0 onlink
192.168.37.0/24 dev eth0 proto kernel scope link src 192.168.37.3
192.168.39.0/24 dev eth1 proto kernel scope link src 192.168.39.5
根据路由表,源 ip 为 8.8.8.8 的数据包通过 eth1 进入,其返回路径将通过 eth0。eth0
和 eth1 是不同的接口,数据包将在第一次路由决策时、PREROUTING 之后和 INPUT/FORWARD 之前被丢弃,并且永远不会到达本地进程。
同时,通过 eth1 进入的源 ip 为 192.168.39.45 的数据包的返回路径将通过 eth1,因此接口匹配并且数据包的处理将继续。