我的一台服务器(“A”)通过 IPSec(Debian 上的 Strongswan 测试)连接到存储守护进程(“B”),其备份(通过 Bacula)在 95% 的运行时间内无法完成。显然,发生的是:
- Bacula 打开与存储守护进程的 VPN IP 的 TCP 连接。(A → B)
- 由于内核设置
net.ipv4.ip_no_pmtu_disc=0
是默认的,所以在明文数据包中设置了IP Don't Fragment位。 - 将数据包路由到 IPSec 隧道时,有效负载的 DF 位被复制到 ESP 数据包的 IP 头中。
- 经过一段时间(通常大约 20 分钟)并发送多达几 GB 的数据后,将发送一个比之前的 ESP 数据包稍大的数据包。(A → B)
- 由于存储守护进程接口的 MTU 低于发送主机的 MTU,因此沿途的路由器会向主机发送 ICMP 类型 3、代码 4(需要分片但未设置分片)错误。(某些路由器 → A)
- 连接停滞,由于某种原因,主机 A 向 B 发送约 100 个空的重复 ACK(约 20 毫秒内)。
(ICMP 数据包正在到达主机 A,并且没有阻止 ICMP 的 iptables 规则。)
我能想到的发生这种情况的可能原因有:
- 内核错误(Debian 3.13.7-1)
- Linux 的 IPSec 实现有意忽略 PMTU 消息作为安全措施,因为它不受保护,并且会影响现有的 SA。(根据RFC 4301 8.2.1)
- 与 PMTU 老化有关(RFC 4301 8.2.2)
修复此问题的最佳方法是什么,无需全局禁用 PMTU 发现或降低接口 MTU?也许可以清除 DF 位,就像 FreeBSD 所做的那样ipsec.dfbit=0?
答案1
您可以尝试创建一条规则,iptables
将 VPN 目的地流量的 TCP MSS 设置为较低的值。但如果没有数据包捕获,很难猜测发生了什么。
答案2
如果 VPN 场景中的 PMTU 发现失败,这通常是网关或路由器之间的公共 IP 地址或过滤的 ICMP 消息存在问题。MSS 限制只是一个不太好的解决方法。