Linux IPsec 网关上的 TCP MSS 钳制:它修复了什么
小请求正常,大响应卡住。检查内部 TCP 路径上的 MSS 规则是否是正确的修复,以及它应该放在哪里。
Ping 能通,SSH 能通,小页面能加载,然后每个大响应都卡住直到超时。这种典型模式指向的是包大小而不是可达性:路径能承载握手和最初几 KB,随后一个全尺寸分片就消失了。在 Linux IPsec 网关上,TCP MSS 规则常常就是修复办法,但前提是你理解它改变了什么,以及它触及的包实际在哪里。下面的顺序沿包从症状走到规则放置位置,因此一旦解释不再吻合,你就可以停下。
提示 MSS 的症状
TCP 在握手中协商最大分片大小。如果该值大于路径在封装后能承载的大小,发送方就会继续产生永远到不了的分片,连接在第一轮之后就停滞。小响应放得下;大响应放不下。
ICMP 反馈可以通过路径 MTU 发现来挽救连接,而丢弃这些消息的防火墙会把停滞变成静默黑洞。这就是为什么同一条隧道对某个应用有效,对另一个应用却在配置看不出明显差别的情况下失败。
TCPMSS 规则做什么、不做什么
该规则会在 TCP 握手包经过时改写其中的 MSS 选项。它不设置隧道接口的 MTU,不改变 IPsec 策略,在当前内核上它只会下调通告值,而不会上调已经更小的值。它也只触及 TCP;UDP 载荷、DNS 行为以及协商出的流量选择器都在它的作用范围之外。
由于改变发生在握手期间,规则之前建立的现有连接会保留旧值。用新连接去测试,并且要预期:改变之后的第一次尝试才是能告诉你点什么的那次。规则里的任何东西都到不了已经打开的连接。这就是为什么在事故中途应用的修复看起来像是什么都没做。
把规则放在内部 TCP 路径上
在基于策略的 Linux 网关上,被转发的包在防火墙看来仍然是普通 TCP。IPsec 策略决定这个包会被保护;防火墙看不到内部流的 ESP 头,所以在这里匹配 ESP 描述的是完全另一个包。正是这种错位,让一些规则看起来正确却永远匹配不上。
用 iptables 的话说,规则属于转发路径上的 mangle 表,并且只限握手包:iptables -t mangle -A FORWARD -p tcp --tcp-flags SYN,RST SYN -j TCPMSS --set-mss 1270。这个数字只是示例,不是通用常量;应当根据封装开销和路径的真实 MTU 推导出来。nftables 的等价写法是在 forward 或 postrouting 链中设置最大分片大小。
把 IKE 和 ESP 的外部监听规则与内部转发规则分开。试图同时授权应用流和外部协议的单条规则,最终两者都不能可靠匹配。
尊重防火墙的归属和 NAT 顺序
如果 UFW 掌管主机防火墙,就通过它支持的持久配置来添加 mangle 和转发改动,而不是敲一条下次重载就会消失的命令。插入错误表或在终止规则之后的规则没有效果,而活动表会把这一点瞒过你。
源地址转换是另一个决定,常常与这一个相互作用。放在通用 masquerade 规则之前的例外,可以避免受保护流量丢失其策略所要求的源;它修不了大小问题,而大小规则也修不了转换问题。
窄范围验证,然后停下
对失败的服务打开一个新连接,同时观察应用和规则计数器。如果停滞消失,你就有了关于那条 TCP 路径和那种封装的证据。你并没有证据证明每种 VPN 协议都合适、每个 UDP 应用都已修复,或某个特定上游服务就是最初原因。
在策略允许的地方让 ICMP 大小反馈继续工作,并且在外层 IPsec 路径没有被内层路由表示时,谨慎对待基于路由 MTU 的自动钳制。结论越窄,下一次事故就越容易诊断。