【网络】使用 DNAT 进行负载均衡时,若未配置配套的 SNAT,回包失败
【网络】iptables 1 概念
【网络】iptables 2 查看规则
【网络】使用 DNAT 进行负载均衡时,若未配置配套的 SNAT,回包失败
【网络】回包路由原理
使用 DNAT 进行负载均衡时,若未配置配套的 SNAT,后端服务器将直接回包给客户端,导致客户端因收到源 IP 不匹配的响应而丢弃数据包,最终连接失败。
场景设定
客户端 (Client):
IP_C
负载均衡器 (Load Balancer):
IP_VIP
(虚拟服务 IP),IP_LB
(LB 的内部接口 IP)后端真实服务器 (Real Server):
IP_RS1
,IP_RS2
网络拓扑:
客户端
IP_C
可以访问IP_VIP
。负载均衡器
IP_LB
可以访问后端服务器IP_RS1/RS2
。后端服务器
IP_RS1/RS2
知道如何到达IP_C
(例如,IP_C
和IP_RS
在同一个二层网络,或者IP_RS
的默认网关指向了能到达IP_C
的路由器)。
流量路径分析
1. 请求 (Request) 路径:IP_C -> IP_VIP
客户端发送:
IP_C
发送一个请求包到IP_VIP
。到达负载均衡器: 包到达负载均衡器。此时包的源/目的为:
src=IP_C, dst=IP_VIP
。iptables DNAT 执行:
负载均衡器上的
iptables
规则(通常在PREROUTING
链的nat
表)匹配到该包。执行 DNAT,将目的 IP 从
IP_VIP
修改为某个后端服务器的 IP,例如IP_RS1
。关键: 源 IP (
IP_C
) 保持不变。包变为:
src=IP_C, dst=IP_RS1
。
负载均衡器转发: 负载均衡器根据路由表,将修改后的包转发给
IP_RS1
。
2. 响应 (Response) 路径:IP_RS1 -> IP_C
(问题发生!)
后端服务器处理:
IP_RS1
收到一个来自IP_C
的请求包(src=IP_C, dst=IP_RS1
)。它认为这是一个直接的、正常的连接。后端服务器直接回包:
IP_RS1
准备响应包。它查询自己的路由表,发现有到达
IP_C
的路由(直连或通过网关)。因此,它直接将响应包发送给
IP_C
。响应包的源/目的为:
src=IP_RS1, dst=IP_C
。
响应包绕过负载均衡器: 这个响应包直接从
IP_RS1
发往IP_C
,完全绕过了负载均衡器。
产生的问题
客户端收到“错误”的响应:
客户端
IP_C
发起的是到IP_VIP
的连接。它期望收到的响应包的源 IP 是
IP_VIP
。但它实际收到的响应包的源 IP 是
IP_RS1
。客户端的 TCP/IP 协议栈会认为这是一个不属于任何已知连接的、无效的包(因为五元组
src=IP_RS1, dst=IP_C
与它发起的src=IP_C, dst=IP_VIP
不匹配)。结果: 客户端通常会丢弃这个包,并可能发送一个
RST
(复位) 包给IP_RS1
,导致连接中断。
连接状态不完整:
负载均衡器只看到了请求包(并执行了 DNAT),但从未看到响应包。
它无法维护一个完整的连接状态(conntrack)。如果后续有同一个连接的包到达,负载均衡器可能会再次进行 DNAT 决策,导致行为不一致。
非对称路由 (Asymmetric Routing):
请求路径:
IP_C -> LB -> IP_RS1
响应路径:
IP_RS1 -> IP_C
(绕过 LB)这种进出路径不一致的情况就是非对称路由,在安全设备、状态防火墙等场景下会引发问题。
为什么需要 SNAT/MASQUERADE?
为了解决上述问题,必须确保响应包也经过负载均衡器。这就是 SNAT 或 MASQUERADE 的作用。
在 DNAT 的同时配置 SNAT:
当负载均衡器执行 DNAT (
dst=IP_VIP -> dst=IP_RS1
) 时,同时执行 SNAT,将源 IP 从IP_C
修改为负载均衡器自己的 IP (IP_LB
)。发送给后端服务器的包变为:
src=IP_LB, dst=IP_RS1
。
后端服务器回包:
IP_RS1
收到src=IP_LB, dst=IP_RS1
的包。它认为连接是
IP_LB
发起的,所以会回复IP_LB
:src=IP_RS1, dst=IP_LB
。这个包必须经过负载均衡器(因为
IP_LB
是它的直接邻居或默认网关)。
负载均衡器处理回包:
负载均衡器收到
src=IP_RS1, dst=IP_LB
的包。它查询连接跟踪表 (conntrack),找到原始连接记录(
orig=IP_C->IP_VIP, reply=IP_RS1->IP_LB
)。执行逆向转换:
将目的 IP 从
IP_LB
改回IP_C
(逆向 SNAT)。将源 IP 从
IP_RS1
改回IP_VIP
(逆向 DNAT)。
最终发给客户端的包为:
src=IP_VIP, dst=IP_C
,客户端完全满意。
总结
在 iptables
DNAT 负载均衡中,如果不配置 SNAT/MASQUERADE:
后端服务器会直接回包给客户端,绕过负载均衡器。
客户端收到源 IP 错误的响应包(是
IP_RS
而不是IP_VIP
)。客户端丢弃响应包,导致连接失败。
因此,在标准的 DNAT 负载均衡场景中,SNAT/MASQUERADE 不是“可选”,而是“必需”的,以保证流量路径的对称性和连接的完整性。