📚 第三章 数据链路
📄 一句话概括

VPN 的原理是「把整个包再装进一个新包里」,每套一层就加一层头。 一层层扣下来,MTU 从 1500 掉到 1360——这就是「在家连公司内网打不开系统」的根源。

📝 本节和前面几节的关系

3.5.4 讲 PPPoE 时扣掉过 8 个字节,VPN 是同一件事的更狠版本。 这一节把「层层封装」的账一次算清,以后遇到 MTU 问题就有章法。

一、一层层加起来

IPsec 隧道模式下,一个包外面要套这些东西:

部分 字节 作用
外层 IP 头 20 隧道两端地址
ESP 头 8 安全参数索引、序号
IV 加密向量 8 到 16 AES-CBC 要 16,GCM 只要 8
内层 IP 头 20 原始包的
ESP 尾 2 到 11 块对齐用的填充
ICV 校验 12 到 16 SHA-1 是 12,SHA-256 是 16

加起来最少 50、最多 91 字节: 所以「IPsec 隧道的典型 MTU 是 1400」这个数,是留了余量之后的经验值。 「IV 是 8 到 16」这一行说明一件事:同样的加密强度,不同的工作模式开销不同。 GCM 是「认证加密一体」,所以向量只要 8 字节;CBC 要单独做完整性校验,向量就要 16。 选算法的时候,这个差别会直接影响 MTU。

二、MTU 一路缩下来

每过一层隧道,能装的数据就少一截:

链路 MTU TCP 的 MSS
以太网 1500 1460
PPPoE 1492 1452
IPsec 1400 1360
GRE over IPsec 1376 1336
PPPoE+GRE+IPsec 1360 1320

最后一行的 1360 是「最坏情况」的常见配置: 家庭宽带(PPPoE)里再连公司 VPN(GRE + IPsec),一层层扣下来就剩这么多。 所以「在家连公司内网,某些系统就是打不开」的老问题,根源全在这张表里。 第三列是「MSS」,等于 MTU 减 40(20 字节 IP 头加 20 字节 TCP 头)。 这两个数是联动的:MTU 变,MSS 跟着变。 而「谁来决定 MSS」是有讲究的: TCP 建连时会协商 MSS,但如果中间有个隧道把它压小了而两端不知道,就会出问题。 所以工程上有一种做法叫「MSS 钳制」:在隧道口把 MSS 改小,主动通知两端「别发那么大」。

三、小包能过、大包过不去

这个故障有个很讨厌的特点:症状是「部分能用」:

操作 包大小 结果
ping 小包 通
网页首页 小包 能开
传文件/登录 大包 卡死

第一行通、第三行不通,人就会怀疑「是不是服务器挂了」—— 其实服务器好好的,是「大包被丢在了路上」。 机制是这样的:包超过路径 MTU 时,要么被分片,要么被丢弃并回一个「需要分片」的 ICMP。 而很多防火墙把 ICMP 全屏蔽了, 于是发送方永远收不到「你发太大了」这个通知,就一直重发、一直失败。 这叫「PMTU 黑洞」,是 VPN 排障里最常见的坑。 排障办法很土但有效:用「不分片」的 ping 一点点加大包长,试到不通为止, 那个值加上 28(IP 头 20 加 ICMP 头 8)就是路径 MTU。 在 Windows 上就是 ping -f -l 1400 目标——这个命令值得背下来,它比任何图形工具都快。

四、动手 Demo:VPN 每套一层,就少一截 MTU

把 IPsec 的六段头加起来,再把五条链路的 MTU 与 MSS 一起算出来。 注意最后一行:PPPoE 加 GRE 加 IPsec,只剩 1360。

lo = 20 + 8 + 8 + 2 + 12
hi = 20 + 8 + 16 + 20 + 11 + 16
print('IPsec 一层:最少 %d 字节,最多 %d 字节' % (lo, hi))

for name, mtu in (('以太网', 1500), ('PPPoE', 1492), ('IPsec', 1400),
                  ('GRE over IPsec', 1376), ('PPPoE+GRE+IPsec', 1360)):
    print('%-16s MTU %4d  MSS %4d' % (name, mtu, mtu - 40))

实跑输出:

--------------------------------------------------------------------
VPN 每套一层,就少一截 MTU
--------------------------------------------------------------------
**VPN 的原理是「把整个包再装进一个新包里」。**
**每套一层就要加一层头,于是「能装的数据」又少一截**——这和 PPPoE 那 8 个字节是同一回事,
只是这次更狠。

  部分                        字节           说明
  --------------------------------------------------------------------------
  外层 IP 头                  20             隧道两端的地址
  ESP 头                      8              SPI + 序号
  **IV(加密向量)**          **8~16**      **AES-CBC 需要,GCM 只要 8**
  内层 IP 头                  20             原始包的
  ESP 尾(填充 + 下一头)     2~11          **块对齐用的填充**
  **ICV(完整性校验)**       **12~16**     **SHA-1 是 12,SHA-256 是 16**

**加起来最少 50、最多 91 字节**:
**所以「IPsec 隧道的典型 MTU 是 1400」这个数,是留了余量之后的经验值。**

  链路                    MTU      TCP 的 MSS
  --------------------------------------------
  以太网                  1500     1460
  PPPoE                   1492     1452
  IPsec                   1400     1360
  GRE over IPsec          1376     1336
  PPPoE + GRE + IPsec     1360     1320

**最后一行的 1360 是「最坏情况」的常见配置**:
**家庭宽带(PPPoE)里再连公司 VPN(GRE + IPsec),一层层扣下来就剩这么多。**
**所以「在家连公司内网,某些系统就是打不开」的老问题,根源全在这张表里。**
**而且这个问题有个讨厌的特点**:
**小包(ping)能过,大包(网页、文件)过不去**——**因为分片就发生在「超过 MTU」的那一刻。**
**排障办法是「ping 大包 + 不分片」,逐步试到不通为止,那个值就是路径 MTU。**

「最少 50」这个数是这么来的:外层 IP 20、ESP 头 8、IV 8、ESP 尾 2、ICV 12,合计 50。 它不含「内层 IP 头」,因为那 20 字节是你原本就要付的。 而「最多 91」把内层也算进去了, 所以这两个数严格说不是同一口径,看厂商文档时要注意它算的是哪一层。 为什么 MTU 取 1400 而不是 1450:因为「取整」比「取紧」好维护。 1400 减 40 得 1360,是个好记的数;而 1450 在某些算法组合下会不够用(IV 和 ICV 都可能变大)。 工程上「留一点余量」几乎总是对的——因为出了问题的排查成本,远高于那 50 字节的带宽。 还有一个更彻底的解法:MSS 钳制。 在隧道路由器上把所有经过的 TCP SYN 里的 MSS 改成「MTU 减 40」, 这样两端一开始就按小包发,永远不会触发分片。 代价是「所有连接都要改 SYN」,路由器要处理每一个连接建立—— 所以它一般只在接入侧开,不在骨干上开。

30 秒实验

  1. 算一下:MTU 1360 时,传一个 100 KB 的文件最少要多少个包?
  2. 想一下:为什么防火墙屏蔽 ICMP 会导致「PMTU 黑洞」?
  3. 在你电脑上试一次 ping -f -l 1400 加一个常用网站,看能不能通。

常见误区

  1. 以为「VPN 连上就应该全通」。 MTU 不够时会「部分通」,小包过、大包丢。
  2. 以为「MTU 是端到端协商出来的」。 实际靠 ICMP 通知,ICMP 被屏蔽就协商不了。
  3. 以为「隧道越多越安全」。 每多一层就少一截 MTU,超过某个点就要靠分片,性能反而更差。
自测三问(点开对答案) 1. IPsec 一层最少吃掉多少字节? —— **约 50 字节**(外层 IP 20、ESP 头 8、IV 8、ESP 尾 2、ICV 12)。 2. MSS 和 MTU 什么关系? —— **MSS 等于 MTU 减 40**,减掉的是 20 字节 IP 头和 20 字节 TCP 头。 3. 「PMTU 黑洞」是什么? —— **包太大被丢,但「需要分片」的 ICMP 被防火墙挡了**,发送方一直重发、一直失败。

下一节看公共无线 LAN:为什么咖啡馆的 WiFi 总是慢。

相关笔记