我已经将 Ubuntu PC 配置为路由器,并对具有多个输入接口的 DNAT 规则感到困惑。当我尝试 pingISP-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
答案1
规则
300: from <ISP-1 IP> lookup external_p
400: from <ISP-2 IP> lookup external_s
有效是因为回复数据包的src
IP =dst
传入数据包的 IP(但不是相同的传出接口)并且通过这些规则通过不同的接口进行路由。
使用 DNAT,你可以dst
将到达 ISP1-IP 和 ISP2-IP 的 dport 为 80 的数据包的地址更改为相同的 172.17.4.2,从而有效地打破这种行为。因此,所有传出的回复来自运动 80 的本地进程有 src 172.17.4.2,并且你的源路由规则不再起作用传出与这些相关的数据包传入连接。
并且这些数据包使用主表中具有最小度量的默认路由进一步路由。
您不需要dst
使用 DNAT 更改 icmp 传入数据包,因此 ping 回复会通过适当的接口进行路由。
你应该使用 iptables 来标记传入連接(不仅仅是数据包)带有 connmark在进行 DNAT 之前fwmark
,将 connmark 复制到传出数据包的数据包标记,并使用 selector代替 selector路由连接的回复数据包from
。
# loose reverse path check since kernel ignores fwmark doing this check
sysctl -w net.ipv4.conf.vlan_ext_p.rp_filter = 2
sysctl -w net.ipv4.conf.vlan_ext_s.rp_filter = 2
# mark incoming connections
iptables -t mangle -I PREROUTING -i vlan_ext_s -d isp2-ip -m conntrack --ctstate NEW -j CONNMARK --set-mark 2
iptables -t mangle -I PREROUTING -i vlan_ext_p -d isp1-ip -m conntrack --ctstate NEW -j CONNMARK --set-mark 1
# for reply traffic copy connection's mark into packet's mark because policy rules use packet's mark
# after this outgoing packets will have packet's mark corresponded to marks of incoming connections
iptables -t mangle -I PREROUTING -s 172.16.0.0/12 -m connmark ! --mark 0 -j CONNMARK --restore-mark
iptables -t mangle -I PREROUTING -s 172.16.0.0/12 -m connmark ! --mark 0 -j CONNMARK --restore-mark
iptables -t mangle -I OUTPUT -m connmark ! --mark 0 -j CONNMARK --restore-mark
# route packets using packet's mark
ip rule add fwmark 2 table external_s
ip rule add fwmark 1 table external_p
ip rule add table main suppress_prefixlength 0
显然,您在 docker 容器中使用了一些 http 应用程序。
因此,第二种选择是让您的应用程序直接监听主机的接口,或者让容器有两个地址,这样所有的源路由都可以正常工作。