我有一个奇怪的用例,在 Azure Kubernetes 中运行的 pod 需要通过专用 VPN 隧道将流量从特定端口路由到特定目标。但是这些目标是私有 IP,因此可以为不同的目标使用相同的 IP。除了路由之外的 pod 也是目标连接的 OpenVPN 服务器。一个例子:
到达端口 10 的通信通过 VPN IP 10.118.0.2 路由到 IP 10.0.0.4:80
同时我们可以拥有:
到达端口 20 的通信通过 VPN IP 10.118.0.3 路由到 IP 10.0.0.4:80
尽管目标 IP 相同,但它们是不同的机器。所以为了实现这一点,我想出了这个可能的解决方案:
/sbin/iptables --table mangle --insert PREROUTING --destination "192.168.0.100" -i eth0 -p tcp --dport "10" --jump MARK --set-mark "10"
/sbin/iptables --table nat --insert PREROUTING --destination "192.168.0.100" -i eth0 -p tcp --dport "10" --jump DNAT --to-destination "10.0.0.4:80"
/sbin/ip rule add prio "10" from all fwmark "10" lookup "10"
/sbin/ip route add "10.0.0.4" via "10.118.0.2" table 10
这将允许两个通信同时工作,并将流量路由到正确的机器。但我看到的是数据包在 mangle 表中被标记。但是永远不会到达 NAT 表。我发现它与rt_filter有关。更多关于下面的内容。就像现在一样,它正在工作,是这样的:
/sbin/iptables --table nat --insert PREROUTING --destination "192.168.0.100" -i eth0 -p tcp --dport "10" --jump DNAT --to-destination "10.0.0.4:80"
/sbin/ip route add "10.0.0.4" via "10.118.0.2"
但是,如果建立了第二条路由,就像在第一个示例中一样,命令将如下所示:
/sbin/iptables --table nat --insert PREROUTING --destination "192.168.0.100" -i eth0 -p tcp --dport "20" --jump DNAT --to-destination "10.0.0.4:80"
/sbin/ip route add "10.0.0.4" via "10.118.0.3"
这将在主路由表中为同一目标创建另一条路由。但是,当访问 192.168.0.100 时,用户可能会被路由到与 10.118.0.3 或 10.118.0.2 连接的机器。
除了这些规则之外,对于所有这些规则,始终启用该规则以允许流量返回到与 10.118.0.X 通信的 tap0 接口:
iptables -t nat -A POSTROUTING -o tap0 -j MASQUERADE
不幸的是我不知道用户源IP,否则很容易解决。到达此端口的任何通信的源 IP 将始终相同,因为通信需要通过另一个服务来掩盖真实的源 IP。
我在其他主题中看到,为了标记容器/pod 中的传入数据包,我需要禁用 rt_filter。但是我不能这样做,它说它是一个只读文件系统,我不知道是否可以在 Azure Kubernetes 集群中更改它。
除了标记数据包,还有其他解决方案吗?还是有关数据包标记的其他内容?
所以我终于找到了解决方案。问题在于 PREROUTING 中的数据包损坏。在 POSTROUTING 中处理数据包(因此,在 eth0 的出口处),它们能够从 tap0 返回到 eth0,然后返回到客户端。最终结果如下所示: