通过IPSec(Linux / Strongswan)的TCP连接超过PMTU后停止

通过IPSec(Debiantesting中的Strongswan)连接到存储守护进程(“B”)的我的一台服务器(“A”)的备份(通过Bacula)不能完成95%的运行时间。 显然发生的是:

  1. Bacula打开与存储守护程序的VPN IP的TCP连接。 (A→B)
  2. 由于默认设置了内核设置net.ipv4.ip_no_pmtu_disc=0 ,所以明文数据包中设置了IP Do not Fragment位。
  3. 将数据包路由到IPSec隧道时,有效载荷的DF位被复制到ESP数据包的IP报头。
  4. 经过一段时间(通常大约20分钟)以及高达数千兆字节的数据发送之后,发送稍大于ESP数据包的数据包。 (A→B)
  5. 由于存储守护程序接口的MTU比发送主机的MTU低,因此沿途的路由器向主机发送ICMPtypes3(代码为“需要分片且不分片”)ICMPtypes3。 (一些路由器→A)
  6. 连接暂停,由于某种原因,主机A将大量100个空的重复ACK发送给B(在〜20ms内)。

(ICMP数据包到达主机A,并且没有阻止ICMP的iptables规则。)

这种情况发生的可能原因,我可以想到:

  • 内核bug(Debian 3.13.7-1)
  • Linux的IPSec实现故意忽略PMTU消息作为安全措施,因为它不受保护,会影响现有的SA。 (根据RFC 4301 8.2.1似乎是有效的行为)
  • 必须与PMTU老化( RFC 4301 8.2.2 )

什么是解决这个问题的最好方法,而不是全局禁用PMTU发现或降低接口MTU? 也许像FreeBSD一样,清除DF位与ipsec.dfbit = 0 ?

您可以尝试在iptables创build一个规则,将针对VPN的stream量的TCP MSS设置为较低的值。 但是如果没有数据包捕获,很难猜测发生了什么。

如果VPN场景中的PMTU发现失败,则这通常是中间的网关或路由器的公有IP地址或过滤的ICMP消息的问题。 MSS夹紧只是一个丑陋的解决方法。