GRE in IPsec Tunnel MTU Issue

最近把Raspberry Pi上的GRE tunnel套了一层IPsec,引发了一个令人蛋碎的问题。

Raspberry Pi上有一个连接国外服务器的GRE tunnel,和一个用hostapd搭建的无线AP。到国外的网络路由全部走tunnel,所以连接AP的设备都可以愉快的上Google、Facebook、 Twitter。这个AP稳定工作了很久很久… 直到几天前,我给GRE tunnel外面套了一层IPsec。

几天前就注意到用Firfox无法打开Google网页,提示解析出IP,connected,然后就没反应了。浏览Facebook等其它网页都正常。或许是路由错误,或许是DNS解析错误,或许是iptables rules错误,或许是IPv6引起的错误。 ping google.com 结果正常, traceroute google.com 结果正常。 dig google.com 结果正常。没找到iptables 错误。把IPv6关了还是没改善。程序员的经验告诉我,或许只是我运气不好,或许过几天故障就会自动消失,或许我需要烧柱香。于是我在电脑和手机上分别又套了一层proxy,继续愉快地上网。

昨天实验室的师姐说连上我的AP之后没法打开Google。为了实验室的同学正常搬砖,这个故障必须修复。所以今天中午我再次调查为什么连接Raspberry Pi的AP之后无法用浏览器打开Google。

还是像以前一样,DNS正常,ping正常,traceroute正常,iptables正常。 mtr www.google.com --tcp -P 80 正常。 mtr www.google.com --tcp -P 443 正常。 Raspberry Pi上 curl www.google.com 正常,电脑上 curl www.google.com 没反应。然后我想起来昨天在Reddit上看到的一个post Crazy issue with HTTPS over openVPN on a particular ISP, 和我遇到的情况有点像,或许我遇到的也是MTU引起的问题。于是我测试了一下, ping www.google.com -s 1490 不正常。 traceroute --mtu www.google.com 显示GRE tunnel的MTU值是1434。把电脑和Raspberry Pi的network interface MTU 修改为1400后,电脑上的Firefox可以正常访问Google,果然是个MTU引起的坑。

可是该如何修复呢?Ethernet默认的MTU是1500,电脑可以修改MTU,但是手机没法改啊。在每个连接AP的设备上修改MTU是不合适的解决方案。于是我继续上网查找关于GRE和MTU的信息。接着我注意到一个现象,Raspberry Pi上 ip link 命令显示GRE tunnel的MTU是 1476,但是 traceroute --mtu www.google.com 显示GRE tunnel的MTU是1434,这两个数值不一样。1476是以太网默认MTU 1500减去GRE封装的24Byte得到的。 ip tunnel 命令创建tunnel时自动计算并把MTU设置为这个数值。1434应该是1500减去GRE封装的 24Byte,再减去IPsec ESP transport mode封装的信息得到的。会不会是这两个数值的差别引起的故障呢。接着我把GRE tunnel两端的MTU修改为1434,把AP两端的MTU修改回 1500,又能正常浏览Google了。

总结起来,这是一个GRE in IPsec tunnel没有正确设置MTU引起的故障。