我已将 Ubuntu pc 配置为路由器,并且对具有多个输入接口的 DNAT 规则感到困惑。当我尝试 ping ISP-1 IP时,路由器从 external_p 应答,ISP-2 IP从 external_s 应答。但是当我打开ISP-1 IP :80 或ISP-2 IP :80 时,它会从 external_p 回答两个 IP。如何使用收到请求的接口配置它对 DNAT 的应答?
ip rule show
0: from all lookup local
300: from <ISP-1 IP> lookup external_p
400: from <ISP-2 IP> lookup external_s
32766: from all lookup main
32767: from all lookup default
ip route
default via <ISP-1 GW> dev vlan_ext_p metric 100
default via <ISP-2 GW> dev vlan_ext_s metric 200
ip route show table external_p
default via <ISP-1 GW> dev vlan_ext_p proto static
ip route show table external_s
default via <ISP-2 GW> dev vlan_ext_s proto static
iptables-save
*nat
-A PREROUTING -i vlan_ext_p -p tcp -m tcp --dport 80 -j DNAT --to-destination 172.17.4.2
-A PREROUTING -i vlan_ext_s -p tcp -m tcp --dport 80 -j DNAT --to-destination 172.17.4.2
-A POSTROUTING -s 172.16.0.0/12 -o vlan_ext_p -j MASQUERADE
-A POSTROUTING -s 172.16.0.0/12 -o vlan_ext_s -j MASQUERADE
COMMIT
*filter
-A FORWARD -d 172.17.4.2/32 -i vlan_ext_p -p tcp -m tcp --dport 80 -m conntrack --ctstate NEW,ESTABLISHED -j ACCEPT
-A FORWARD -d 172.17.4.2/32 -i vlan_ext_s -p tcp -m tcp --dport 80 -m conntrack --ctstate NEW,ESTABLISHED -j ACCEPT
-A FORWARD -m conntrack --ctstate RELATED,ESTABLISHED -j ACCEPT
-A FORWARD -m conntrack --ctstate INVALID -j DROP
-A FORWARD -s 172.16.0.0/12 -j ACCEPT
规则
之所以有效,是因为回复数据包的
src
IP =dst
传入数据包的 IP(但不是相同的传出接口),并通过这些规则通过不同的接口路由。dst
使用 DNAT,您可以通过将dport 80 的数据包同时到达 ISP1-IP 和 ISP2-IP 的 adderss 更改为相同的 172.17.4.2 来有效地打破这种行为。因此,所有来自带有运动 80 的本地进程的传出回复都具有 src 172.17.4.2 并且您的源路由规则不再适用于与这些传入连接相关的传出数据包。并且这些数据包使用主表中最小度量的默认路由进一步路由。
您无需更改
dst
带有 DNAT 的 icmp 传入数据包,因此 ping 回复通过适当的接口路由。在执行 DNAT 之前,您应该使用 iptables 用 connmark 标记传入连接(不仅仅是数据包),将 connmark 复制到数据包的标记以用于传出数据包,并使用选择器而不是选择器路由连接的回复数据包。
fwmark
from
显然,您在 docker 容器中使用了一些 http 应用程序。
所以第二个选择是让你的应用程序直接监听主机的接口或者让容器有两个地址,这样所有的源路由都可以正常工作。