我在很多地方都看到过这个 iptables 规则iptables -A FORWARD -p tcp --tcp-flags SYN,RST SYN -j TCPMSS --clamp-mss-to-pmtu
来处理路径 MTU 发现问题。
据我所知,PMTU 可能在多条路径上有所不同(例如 A->B 的 PMTU 为 1400,A->C 的 PMTU 为 1350)。那么 iptables/kernel 如何计算 PMTU?
答案1
它询问路由表。
通常,该规则应该在与是位于具有较低 MTU 的路径的边缘。
例如,如果您的路由器具有 PPPoE 接口或站点到站点 GRE 隧道(具有较低的 MTU),那么您将在该特定路由器上而不是在原始主机上制定此规则,并且它会根据即将通过哪个接口发送 SYN 数据包来调整通告的 MSS。
调整 MSS 以适应更窄的链路实际上不在本模块的讨论范围内,实际上它适用于标准 PMTUD 不可用的情况不是为有问题的路径工作,因此远程主机无法找到正确的 MTU。(通常,它是为了解决在链接另一端发生的 PMTUD 问题,即远程主机试图向您发送过大的数据包。)
(理论上,该模块还可以查询内核的“路由缓存”,该缓存会记住它最近与之通信的每个地址的发现路径 MTU,但这当然依赖于 PMTUD 正常工作和“太大”错误到达,而这个 netfilter 模块的全部目的就是处理 PMTUD 的情况不是根本沒有工作。
答案2
它并不计算 PMTU,而是发现它。
PMTUD 是一种协议,要求发送方通过重复发送较小的数据包来发现最大的 MTU,直到它不再收到 ICMP“目标无法到达”响应。这种协议效率低下,但可以避免发酵。
TCP MSS 是一种较新的协议,与 TCP 在第 4 层一起使用。
在建立新的 TCP 连接时,会进行三次握手。每台设备都会将其 MSS 插入到 TCP 标头中,因此从这个意义上讲,它会向远程设备宣布其 MSS,而无需协商双方均可接受的值。
需要解决的问题是,设备只知道其本地链路的 MTU 和 MSS,但不知道路径上某处链路上的较低 MSS。
解决方案是配置路由器来重写 MSS。
例如,Cisco 路由器将在隧道上配置此命令:
ip tcp adjust mss 1436
当 TCP 流量(例如三次握手)通过隧道时,路由器将看到 TCP 标头中的 MSS 设置为 1460,并将其重写为 1436,另一端的主机将相应地调整此连接的最大有效负载。
以前需要通过直接 iptables 规则启用此选项。但是,例如,firewalld 现在将其作为自动应用于所有规则的选项启用。
这仅适用于 TCP,而不适用于 UDP,并且需要路由器参与消息路由。
参考 : 防火墙中的 TCP MSS 限制。