注:本文为 " IPv6 间接性连接异常" 相关文章合辑。
略作重排,未去重。
如有内容异常,请看原文。
IPv6 间接性连接异常?尝试调整路由器的 MTU 设置
Nero978
2024-1-29 17:54
背景
2024 年 1 月 29 日,因寒假返家,发现家中宽带已由父亲升级至 1000M。为获得更优的学习与娱乐体验,基于"买新不买旧"的原则,将家中老旧的 Wifi 5 路由器更换为最新的 Wifi 7 路由器(TP-Link BE5100,型号为 TL-7DR5130)。在设置新路由器时,看到 IPv6 的设置选项,便顺手将其开启。

然而,开启 IPv6 后出现了网络连接问题,无法正常上网。具体表现为:访问 baidu.com、fanyi.baidu.com 以及个人网站 www.rxgzs.cn、nero978.top 时,均显示连接超时(TIMED OUT)。
解决思路
由于个人网站支持 IPv6 访问,因此首先怀疑是路由器 IPv6 设置存在问题。为验证这一猜测,尝试访问一些 IPv4 网站,结果显示访问正常(可通过打开浏览器的 F12
键,进入开发者工具中的网络选项进行查看,返回状态码为 200 OK)。
通过上述测试,基本可以确定是 IPv6 方面的问题。随后查看了电脑本地的网络连接,确认已获取到 IPv6 地址,这表明从路由器到电脑的 IPv6 链路已成功建立。
接着,将路由器的 IPv6 设置关闭,再次尝试访问之前无法打开的网站,此时通过 IPv4 访问,网站均能正常打开(状态码为 200 OK)。至此,可以确定问题出在 IPv6 设置上。
针对 IPv6 出现的问题,访问了 test-ipv6.com 检测网站进行测试,测试得分为 10 分。

进一步分析发现,并非所有的 IPv6 网站都无法访问。例如,test-ipv6 网站本身就是基于 IPv6 的,且能够检测到本地的 IPv6 IP 地址,这说明本地的 IPv6 网络实际上是连通的。
由于部分 IPv6 网站无法访问,推测可能是 DNS 污染问题。于是更换为阿里的公共 DNS,但问题依然存在。
随后咨询了中国电信客服,得知截至当时,湖南电信已全面支持 IPv6。
在尝试了多种方法仍未解决问题后,浏览相关技术论坛(贴吧),从中获取了一些解决思路。
终极方案
经过在技术论坛上的研究,发现问题的根源在于 MTU(最大传输单元)设置。
将路由器的 MTU 设置为 1432 后,网络连接问题得到完美解决(TP 路由器的默认 MTU 为 1500)。

什么是 MTU ?
最大传输单元(Maximum Transmission Unit,MTU)是指在网络通信中,用于通知对方所能接受数据服务单元的最大尺寸,它规定了发送方能够发送的有效载荷的最大大小。MTU 表示的是数据包或帧的最大长度,通常以字节为单位。若 MTU 设置过大,数据包在经过路由器时可能会因超出其处理能力而被拒绝转发;若 MTU 设置过小,由于协议需要在数据包(或帧)上添加包头,实际传输的数据量会相应减少,从而降低传输效率。大多数操作系统会为用户提供一个默认的 MTU 值,该值一般能满足用户的常规需求。
为什么 IPv6 设置之后需要重新设置 MTU?
由于 IPv6 协议对 MTU 长度的要求与 IPv4 不同,在使用 IPv6 时,可能会出现某些网站偶尔无法访问的情况。其原因在于 MTU 设置过大,当数据包需要进行分包时,网络中一些不支持分包的设备会将这些数据包丢弃,导致网站无法访问。解决这一问题的方法是将路由器的 MTU 设置为较小的值(比 IPv4 的 MTU 小 20 字节,例如 1432 字节)。
什么是 PMTU 黑洞?
终端设备在发送数据包时,可以设置 DF(Don't Fragment)标记,以告知路由器不要对数据包进行分片。当中间路由器接收到超过 MTU 的数据包时,会将其丢弃,并回复一条 ICMP Fragmentation Needed 消息。发送者收到该消息后,会在下次发送较小的数据包,这一过程称为 PMTU Discovery(路径最大传输单元发现)。在实际网络中,HTTPS(TLS)的流量大多带有 DF 标记。
然而,互联网上存在大量中间设备,由于安全考虑或配置不当,这些设备不会回应 ICMP Fragmentation Needed 包。这就导致在访问某些网站时,如果数据包的大小超过了 PMTU,数据包会被无声地丢弃,直到 TCP 协议检测到超时丢包并进行重传,这一过程会严重影响网络访问速度。当出现这种情况时,可以认为在本地与目标服务器之间的路径上存在 PMTU 黑洞。
由于本地到目标服务器之间的网络链路是动态变化的,在链路节点中,如果遇到配置错误的设备,就可能导致无法访问目标网站。
目前,国内 ISP(互联网服务提供商)一般通过 PPPoE 虚拟拨号建立 WAN 口连接。Ethernet 的默认 MTU 为 1500 字节,但 PPPoE 隧道会产生 8 个字节的开销,因此 PPPoE 虚连接的 MTU 为 (1500 - 8 = 1492) 字节。在 IPv4 协议下,减去 IPv4 包头(20 字节)和 TCP 包头(20 字节)后,可以得知需要将 MSS(最大段大小)设置为 1452 字节以下;在 IPv6 协议下,由于 IPv6 的包头为 40 字节,所以需要将 MSS 设置为 1432 字节以下。
由此可见,可能是家庭网络中的某台设备未能正确执行分包策略(即当数据包过大时,未发送要求分包的信息),导致 TCP 协议不断发送请求,最终出现连接超时(TIMED OUT)的情况。
使用 IPv6 后部分网站无法访问的问题解决方案
作者:neucrack
创建日期:2022 年 01 月 05 日
由于 IPv6 协议对 MTU 长度的要求与 IPv4 不同,在使用 IPv6 时,可能会出现某些网站偶尔无法访问的情况。其原因在于 MTU 设置过大,当数据包需要进行分包时,网络中一些不支持分包且不会响应请求设备分包需求的设备会将这些数据包丢弃,导致网站无法访问。解决这一问题的方法是将路由器的 MTU 设置为较小的值(比 IPv4 的 MTU 小 20 字节,例如 1432 字节)。
在公司网络支持 IPv6 后,访问一些网站时出现了无法访问或访问速度极慢的问题。经过 @vowstar 的排查,发现问题根源并成功解决。
相关解决方案如下:
之前在 IPv6 环境下,简书时而可以访问时而无法访问的根本原因已找到,是由于 PMTU 黑洞导致的,具体细节如下:
终端设备在发送数据包时,也可以设置 DF(Don't Fragment)标记,以告知路由器不要对数据包进行分片。当中间路由器接收到超过 MTU 的数据包时,会将其丢弃,并回复一条 ICMP Fragmentation Needed 消息。发送者收到该消息后,会在下次发送较小的数据包,这一过程称为 PMTU Discovery(路径最大传输单元发现)。在实际网络中,HTTPS(TLS)的流量大多带有 DF 标记。
然而,互联网上存在大量中间设备,由于安全考虑或配置不当,这些设备不会回应 ICMP Fragmentation Needed 包。这就导致在访问某些网站时,如果数据包的大小超过了 PMTU,数据包会被无声地丢弃,直到 TCP 协议检测到超时丢包并进行重传,这一过程会严重影响网络访问速度。当出现这种情况时,可以认为在本地与目标服务器之间的路径上存在 PMTU 黑洞。
由于本地到简书之间的网络链路是动态变化的,在链路节点中,如果遇到配置错误的设备,就可能导致无法访问简书。
目前,国内 ISP(互联网服务提供商)一般通过 PPPoE 虚拟拨号建立 WAN 口连接。Ethernet 的默认 MTU 为 1500 字节,但 PPPoE 隧道会产生 8 个字节的开销,因此 PPPoE 虚连接的 MTU 为 (1500 - 8 = 1492) 字节。在 IPv4 协议下,减去 IPv4 包头(20 字节)和 TCP 包头(20 字节)后,可以得知需要将 MSS(最大段大小)设置为 1452 字节以下;在 IPv6 协议下,由于 IPv6 的包头为 40 字节,所以需要将 MSS 设置为 1432 字节以下。
解决方法:
bash
#set security flow tcp-mss all-tcp mss 1452
#set security flow tcp-mss all-tcp mss 1432
将原先的设置值 1452 更改为 1432 后,强制丢包现象消失,原先无法访问的简书可以正常访问了。
路由器后台一般可以直接进行更改,在电脑的 Linux 系统中,可临时执行以下命令:
bash
sudo ifconfig enp7s0 mtu 1432 up
从原理到实践,彻底解决 IPv6 上网不稳定的问题
作者:折腾总匠 _zhihu
发布于 2023 - 04 - 12 22:01・IP 属地广东
许多用户在开启 IPv6 后,遇到了网页加载缓慢、无法打开,视频卡顿,手机 App 运行不流畅等问题。本文将从原理层面深入分析这些问题,帮助读者理解问题产生的原因,并提供有效的解决方案。
前言
当前,私有云 NAS 在家中部署日益流行,但一般家庭或企业宽带通常没有公网 IP,在外访问 NAS 需通过 NAS 或第三方服务器进行中转,而这些中转服务提供的带宽往往较小,远不及公有云(如各种网盘)的带宽,严重限制了 NAS 的使用范围。
得益于国家对 IPv6 的大力推广,截至 2023 年,各大电信运营商已在局端默认向终端用户开通了公网 IPv6。然而,由于接入路由器的多样性和技术复杂性,运营商的安装维护人员通常未在拨号路由器上启用 IPv6,且对外宣称不支持公网 IPv6。许多技术爱好者自行登录光猫,将其更改为桥接模式,并使其支持 v4/v6 双协议,然后在自己的路由器上启用 IPv6,从而使 NAS 获得了公网 IPv6 地址,实现了在外全速访问 NAS。
但随之而来的是,家庭网络出现了变慢的情况,具体表现为部分网页加载缓慢或无法打开,视频卡顿甚至停止播放,手机 App 也存在类似问题。关闭路由器的 IPv6 功能后,网络恢复正常。咨询运营商的安装人员,得到的建议是关闭 IPv6,理由是目前 IPv6 技术尚不成熟。通过网络查找资料,发现许多文章讲解不全面,概念模糊,按照这些文章的方法操作后,问题仍未得到解决。
实际上,问题的根本原因在于 PMTU 分片缺陷。本文将从原理出发,深入分析这一问题,力求做到通俗易懂,帮助读者理解问题的本质,并提供有效的解决方案。阅读本文需要具备一定的网络知识,了解 TCP/IP/ 以太网分层模型及相关概念。
为什么 IPv4 没有这个问题?
有人认为 IPv6 技术不成熟,但这种观点是错误的。IPv6 已经推广运行多年,骨干网和城域网都已稳定运行,各大互联网公司也均支持 IPv6 访问,至少在普通互联网应用方面已相当成熟。我们的手机默认开启 IPv6,也并未出现明显的不稳定情况。如果说存在不成熟的地方,那主要是在网络的"最后一公里",即家庭拨号路由器或接入的第三方宽带存在问题,可能是 IPv6 功能不完善或配置不正确,未能解决 PMTU 分片缺陷问题。
那么,为什么 IPv4 没有出现类似的问题呢?
- IPv4 支持分片功能,这使得大多数允许分片的互联网应用能够正常运行,尽管分片会导致一定的效率下降。
- 大多数家用路由器默认对 IPv4 开启了 MSS Clamping(最大段大小钳制)功能,但对 IPv6 却未默认开启。
因此,对于 IPv6 网络中出现的问题,可以尝试打开 MSS Clamping 功能来解决。
怎么判断 PMTU 分片缺陷问题?
如果网络在开启 IPv6 后出现上述问题,虽然有较大可能是 PMTU 分片缺陷导致的,但为了准确定位和诊断问题,还需要进行一些测试。
需要下载抓包工具 Wireshark,用于捕获电脑上网时的网络连接数据包。为了便于查看,只需捕获电脑访问服务器时 TCP 连接建立的瞬间数据包。首先,通过 ping 命令(如 ping 知乎网站 http://www.zhihu.com) ,在 IPv6 DNS 优先解析的情况下会得到 IPv6 地址)获取服务器的 IPv6 地址,然后在 Wireshark 的【捕获】【选项】中设置过滤器为 src host [你电脑 IP] || dst host [服务器 IP]
,开始捕获数据包。如果捕获到的 [SYN, ACK]
回包的 MSS 值比 [SYN]
去包小 8 字节,说明路由器已正确配置了 MSS Clamping;如果回包的 MSS 值与去包一致(均为 1440),则表明存在 PMTU 分片问题,需要进行相应的配置。
要深入理解这一问题,还需要了解 MSS Clamping、PMTU 分片缺陷、数据包分片以及 IPv6 不支持分片的原因等相关概念,这些都与 MTU 密切相关。
从 MTU 说起
最大传输单元 MTU(Maximum Transmission Unit)是指网络能够传输的最大数据包大小,以字节为单位。MTU 的大小决定了发送端一次能够发送报文的最大字节数。如果 MTU 超过了接收端或传输路径上设备的承受能力,会导致报文分片甚至丢弃,增加网络传输负担;如果 MTU 过小,则会降低实际传输的数据量,影响传输效率。
MTU 描述了数据链路层的收发能力,IP 层也需要依据 MTU 进行正确的分片逻辑,因此 MTU 是链路层和 IP 层之间的一种约定。它规定从网络层发到二层的数据(IP 头 + IP Payload)不能大于 MTU,否则会被丢弃,这就要求数据包在网络层进行分片,以符合 MTU 的大小要求。
MTU 对 IP 协议进行约束的原因在于二层网络信道的多样性,不同的二层网络所能传输的最大有效载荷不同。例如,常规以太网数据包的有效负载最长可达 1500 字节;增强版的以太网巨型帧可将最大帧长扩展到 9K;令牌环和 FDDI 能够传输更大的数据包,并且有时使用更大的数据包来减少高速或大容量数据传输的开销。
此外,隧道技术的应用也会影响 MTU 的大小。隧道技术是指网关设备将一种协议的数据包封装到另一个协议中,以便在网络中传输到另一个网关的过程。隧道技术本质上是一种数据包封装技术,在底层协议 MTU 不变的情况下,被封装的协议由于增加了额外的报文头部,其支持的数据净荷会相应减小。常见的隧道技术包括 xDSL 的 PPPoE、IPSec/L2TP 等 VPN、通用路由封装 (GRE) 协议等。
以 PPPoE 拨号为例,它在以太网帧中插入了 8 个字节的 PPP 头部,导致以太网的有效负载减少了 8 字节,为第三层仅保留了 1492 字节的传输空间。同样,通用路由封装 (GRE) 使用 24 字节头部,将 GRE 隧道上的 MTU 减少到 1476 字节。显然,多种封装技术的组合会进一步减小 MTU 的大小,如 ADSL 上运行的 GRE 隧道的 MTU 仅为 1468 字节。
在 Linux 系统中,可以使用 ifconfig 命令查看某个网络接口的 MTU 大小,示例如下:
bash
# ifconfig
ppp0 Link encap:Point-to-Point Protocol
inet addr:112.91.246.207 P-t-P:113.90.244.1 Mask:255.255.255.255
UP POINTOPOINT RUNNING NOARP MULTICAST MTU:1492 Metric:1
RX packets:339211 errors:0 dropped:0 overruns:0 frame:0
TX packets:352650 errors:0 dropped:0 overruns:0 carrier:0
collisions:0 txqueuelen:3
RX bytes:165885364 (158.2 MiB) TX bytes:78543988 (74.9 MiB)
eth2 Link encap:Ethernet HWaddr 20:76:93:53:E0:93
UP BROADCAST RUNNING MULTICAST MTU:1500 Metric:1
RX packets:2732205 errors:0 dropped:0 overruns:0 frame:0
TX packets:2311855 errors:0 dropped:0 overruns:0 carrier:0
collisions:0 txqueuelen:1000
RX bytes:2931869236 (2.7 GiB) TX bytes:1896190225 (1.7 GiB)
Interrupt:11
在 Windows 系统中,查看网络接口 MTU 的命令如下:
text
C:\> netsh interface ipv4 show subinterfaces
MTU MediaSenseState 传入字节 传出字节 接口
------ --------------- --------- --------- -------------
4294967295 1 0 1039833 Loopback Pseudo-Interface 1
1500 2 116351254 52169177 WLAN
1500 1 29136662 9016213 以太网
在 Windows 系统中设置 MTU 的命令(需以管理员身份运行命令提示符):
text
netsh interface ipv4 set subinterface "需修改的连接名" mtu = 值 store=persistent
例如,将 WLAN 连接的 MTU 设置为 1492,命令如下:
text
netsh interface ipv4 set subinterface "WLAN" mtu=1492 store=persistent
MTU 与 IP 分片
IPv4 的分片功能位于网络层,是网络层的重要特性。当源节点收到上层下发的 IP 包,或者中间路由器收到需要转发的 IP 包时,如果包大小大于设定的 MTU,就需要对该 IP 包进行分片,将其分成两个或多个 IP 包依次发送。每个分片所承载数据的首字节在原包中的索引会记录在包头的偏移字段中(以 8 字节为单位),并且只要不是最后一片,包头的 MF (More Fragment) 标记都会设为 1,以便目标端对这些分片进行正确重组。
一个已经分片的 IP 包,如果在传输过程中遇到 MTU 更小的节点,还会进行二次分片或多次分片,这会进一步降低通信效率,如下图所示:
以一个较为常见的两次分片场景为例,假设源端 PC 网卡的 MTU 为 1500,经过家用路由器拨号(MTU 为 1492)连接到城域网,最后经过某机房的路由器接入到服务器。由于该机房采用了某种隧道技术,机房路由器的 MTU 被设置为 1484。假设源端要发送一个 1500 字节的 IP 数据包,该数据包到达家用路由器后会被分片成 1492B 和 28B(IP 头部增加了 20B)两个 IP 包,1492B 的包到达机房路由器后会进一步分片为 1484B 和 28B 两个 IP 包,最后这三个 IP 包到达服务器后进行重组,解析出上层 TCP 报文。从数据效率来看,经过两次分片,多传输了 40 个字节。从网络资源消耗角度来看,一个包变成 3 个包,中间的每个路由器都需要分出计算资源进行解析、选路和转发,目标服务器端也需要进行重组,这些都是额外开销。如果源端发送一个大文件,被分段成 1 万个 1500B 的 IP 包,那么整个网络就要额外承载 2 万个小包。
有两种情况不允许分片:
- 发送方应用程序设置了不允许分片(如 ICMP 的 PMTU 探测报文)。
- IPv6 数据包不允许任何中间路径节点分片,只允许源节点分片。
正常情况下,IPv4 包大于 MTU 时会被分片。但有些上层报文(如 ICMP、TCP、UDP)为了保证数据的完整性,不希望在网络层因 MTU 的原因进行分片,它们宁愿丢弃数据包也不愿意分片后发送,比如下文将提及的 ICMP 的 PMTU 动态探测技术就是利用了这一特性。因此,IPv4 包头部的标志位除了 MF 外,还有一位是 DF (Don't Fragment),如果发送端不希望报文被分片,可将 DF 设为 1,以阻止 IP 节点对 IP 包进行分片。下图为 IPv4 的包头格式:

IPv6 报文的基本头部没有分片标记和分片偏移字段,这些字段被移到了扩展头部,而中间路由器不会处理扩展头部(有 1 个例外),所以 IPv6 不允许任何中间节点对其进行分片。通过分段扩展首部,IPv6 允许源节点在发送时分片,经过中间节点的直接路由转发后,在目标节点对这些分片进行重组,这一过程与 IPv4 类似。下图描述了 IPv6 的包头相对 IPv4 的变化:

IPv6 被设计为不支持中间节点分片,主要原因有:
- 提升效率:在 IPv4 中,中间路由器的分片功能对路由器来说较为复杂且耗时,分成多片后显著增加了后续所有路由器的转发开销,对整个网络的通信效率产生了一定影响。IPv6 作为 IPv4 的升级协议,将分片功能移到源端和目标端进行,有效提升了中间路由器的转发效率。
- 提升安全性:分片一直是 IPv4 中安全漏洞的常见来源。对于分片的 IPv4 数据包,第 4 层报头信息(如 TCP)在第 2 个到最后一个分片中不可用。分片和分片重组的过程可能会在中间节点(如防火墙和路由器)和终端节点(如用户计算机)中产生意外和有害的行为。
PMTU (Path MTU) 及动态探测
Path MTU 即传输路径的 MTU,指无需分片就能穿过某路径的数据包最大长度。在从发送端到接收端的传输路径上,如果网元的 MTU 设置不一致,那么决定该路径可用 MTU 的是整条路径上的最小 MTU 值。以 Path MTU 作为 IP 包长发送数据,既能保证高效传输,又能避免分片,如下图所示:
PMTU 是一个动态概念,互联网上两台主机之间的 PMTU 并非固定值,它取决于当时所选择的路径,而且路由选择不一定是对称的(从 A 到 B 的路由可能与从 B 到 A 的路由不同),因此,PMTU 在两个方向上不一定一致。
RFC 1191 (IPv4) 和 RFC 1981 (IPv6) 定义了动态探测 PMTU 的技术 ------ PMTUD (Path MTU Discovery),用于确定两个 IP 主机之间的 Path MTU。首先,源节点假设 Path MTU 就是其出接口的 MTU,发出一个试探性的报文,并设置该报文不允许被分片。当转发路径上存在一个小于当前假设的 Path MTU 时,转发设备就会向源节点发送回应的 ICMP 报文,并且携带自己的 MTU 值,此后源节点将 Path MTU 的假设值更改为新收到的 MTU 值继续发送报文。如此反复,直到报文到达目的地之后,源节点就能知道到达目的地的 Path MTU 了。
目前 IPv4 网络在发现 PMTU 方面存在困难,主要原因是:
- 某些运营商或网站出于网络安全或其他考虑,过滤掉了 ICMP 探测报文。
- Path MTU 需要主机和互联网上的各种网络设备(交换机、路由器、防火墙等)的配合,但有些网络设备不遵从 RFC 1191 协议。
IPv6 由于不支持中间路由节点分片,PMTU 发现机制就显得至关重要。如果源节点不执行 PMTU 发现,它必须发送不大于 1280 字节的最小 IPv6 MTU 大小的数据包。如果【数据包过大】的 ICMPv6 回传报文被某一路由器过滤掉,源节点将无法获知数据包被丢,这对于 IPv6 网络通信来说是极为严重的问题。
ping 程序的 ICMP 不可到达错误,采用的就是 PMTU 动态探测的方法,traceroute 程序也是利用这种方法来确定到达目的节点的 PMT。
我们可以使用 ping -f -l [SIZE] [目标 IP 或域名]
命令来探测到指定目的节点的 PMTU,其中 -f
表示强制不分片,-l
用于指定 ping 数据包的大小,最大能正常 ping 通的 SIZE 加上 ICMP 包头的 28 字节即为 MTU,示例如下:
text
C:\> ping -f -l 1465 www.baidu.com
正在 Ping www.a.shifen.com [14.119.104.254] 具有 1465 字节的数据:
需要拆分数据包但是设置 DF。
......
C:\> ping -f -l 1464 www.baidu.com
正在 Ping www.a.shifen.com [14.119.104.254] 具有 1464 字节的数据:
来自 14.119.104.254 的回复:字节 = 1464 时间 = 7ms TTL=56
实际环境下捕获的 ICMP 需要分片但 DF 位置一的差错报文,其解码格式如下图所示:
我们可以看到其差错类型为 3,代码为 4,并且告知了下一跳的 MTU 值为 1478。在 ICMP 差错报文里封装了导致此差错的原始 IP 报文的报头(包含 IP 报头和四层报头)。
PMTU 黑洞
在整个互联网网络中,虽然上层运行的都是 TCP/IP 协议,但由于底层通信媒介的多样性(以太网、无线、PPPoE 等)以及核心路由器和各级接入路由器配置的差异(即每个网元的链路层收发能力(MTU)不同),同时客户端 PC 到服务器之间的路由选路每次都可能不同,数据包的去程和回程路径也可能不同(非对称),因此每次路由的 PMTU 也不尽相同。
如果源发送端的 MTU 设置过大,而某次路由路径中的某个中间节点的 MTU 过小,且数据包被应用层设置了不允许分片,或者这是一个 IPv6 数据包,那么这个节点只能将该包丢弃,同时产生一条【数据包过大】的 ICMP 报文,告知源端自己能处理的 MTU。
不幸的是,这个 ICMP 报文不一定能回传到源端,因为回程的某个中间节点可能因安全原因禁用了 ICMP,将其丢弃。最终结果是,源发送端的上层不知道数据被丢,只能通过超时重传来尝试解决。然而,发送端判断超时的时间通常较长,在一个报文未发送完成的情况下,后续的所有报文都需要等待。更糟糕的是,发送端即使超时重传,重传的数据包仍有可能走同一条路径,同样被那个节点丢弃,最终导致上层业务阻塞,网页或视频一直处于加载状态。只有当路由选路避开那个节点时(这取决于网络的动态变化和运气),网络才能恢复正常。
这个导致数据包被丢弃且 ICMP 报文无法回传的节点就如同黑洞一般,隐藏在网络深处,悄无声息地吞噬大数据包,对上层通信业务造成严重影响。由于所有的 IPv6 数据包都不允许路由器分片,而 IPv4 只有部分应用不允许分片,因此 PMTU 黑洞对 IPv6 网络的影响尤为明显。
如何正确配置 MTU
MTU 的配置既不能过大,否则会造成分片,影响传输效率,甚至可能形成 PMTU 黑洞;也不能过小,过小会降低通信效率。需要根据不同场景和设备(源端、接入网络、骨干网、城域网络),配置一个合适的值。
需要特别注意的是,MTU 大小的选择与 IPv6 无关,因为 MTU 是数据链路层(二层)对上层的约束,无论第三层使用的是 IPv4 还是 IPv6,都需要遵守相同的 MTU 规定。不能因为上层使用 IPv6,其包头比 IPv4 大 20 字节,就认为 MTU 要相应减小。至于后面提到的防火墙的 --clamp-mss-to-pmtu 选项,那是 iptables 把 MSS 修改为 MTU,属于强行关联到 MTU,概念不可混淆。
MTU 大小选择的一个最基本的原则是,对接的两个三层设备以太网接口 MTU 配置需要保持一致。同时还需要考虑多种场景下各种封装标签对报文大小的影响,例如封装 MPLS 标签,每层标签会增加 4 字节,增加 MPLS 标签后,报文长度也可能超过链路层允许发送的范围,导致报文无法转发。
骨干 / 城域 / 接入网络 MTU 的配置
作为普通用户,可以信任骨干网、城域网和国内三大运营商提供的接入网络,其配置的路由设备通常较为可靠,由专业工程师进行配置,最低能保证最小 1500 的 MTU 设置。
为确保骨干网络、城域网络、接入网络的高效运行,MTU 通常被设置为远大于以太网标准的基本要求 1500 字节。现有的大型路由器、交换机设备一般都支持 9000 以上的大数据报文,但各厂商设备的缺省配置不尽相同,很多厂商设备的缺省 MTU 配置仍然是 1500 字节。并且由于网络中可能运行 OSPF、ISIS 等需要协商 MTU 的路由协议,因此互相对接的不同厂商设备的 MTU 也需要调整为相同。所以,在满足网络和运营商规范且各个厂商都支持的情况下,应尽量将 MTU 配置得大一些。
不过,一些小型接入网络服务提供商或个人提供的接入服务,由于技术水平参差不齐,其配置的 MTU 有可能小于 1500 字节。
数据中心 / 机房等服务器网络 MTU 的配置
作为服务器端的运维工程师,也需要关注 MTU 的配置。在数据中心等网络建设中,需要确定 MTU 的配置规范,在各个厂商都支持的情况下,尽量将 MTU 配置得大一些。
在目前大规模建设的数据中心等网络中,通常没有对 MTU 进行统一调整。随着新技术的应用,MTU 的问题会逐渐暴露出来。例如,为实现大二层扩展而采用的各类隧道技术(如 VPLS、VXLAN 等),这些技术都会使用额外的封装,形成超大报文,例如 VXLAN 会在原始报文基础上增加 50 字节。如果不统一规划 MTU,会导致传输效率低下,甚至业务中断。
家庭 / 企业终端网络 MTU 的配置
对于普通家庭或企业网络这些终端网络的配置,路由器的配置要与接入网端设备相对应。例如,国内常用的 PPPoE 拨号接入,路由器 MTU 配置为 1492 ,比以太网少 8 字节即可。
如果局域网上的 PC 主要用于访问公网,那么将这些 PC 的 MTU 设置为与拨号路由器一致,能够避免拨号路由器进行 IP 分片。因为 PC 默认的 MTU 为 1500,比 PPPoE 多 8 字节。
在以下情况下,可以设置更小的 MTU 以提升通信效率,否则尽量保持默认或最大:
- 通过
ping -f -l 14xx [IP]
确定了到某一服务器的 PMTU 为更小值。 - 使用了 L2TP、IPSec 等 VPN 隧道,需要减去新增字段的大小。
为什么 IPv6 路由器不能随意减小 MTU
网上有些文章认为,由于 IPv6 包头多 20 字节,就要在路由器上设置更小的 MTU(比如 1432/1452/1472),但这种做法并不能解决问题。
我们知道,MTU 是第二层数据链路层定义的规范,表征的是数据链路层的数据收发能力,是对第三层的约束,与第三层使用的协议无关。单纯在路由器上减小 MTU 无法解决 IPv6 访问不稳定的问题(除非防火墙还开启了 MSS 钳制为 PMTU,这一点将在下文阐述),反而可能使问题恶化。例如,若将拨号路由器的 MTU 设置为 1432,而 PC 仍使用默认的 1500,那么大数据包到达路由器时就会被丢弃,因为 IPv6 不支持中间路由器分片。
当然,如果在源端 PC 上减小 MTU 到合适大小,是能够解决问题的。因为数据包在源端就被分成小片,中间路由器无需进行分片操作。
MSS 与 TCP 报文分段
MSS(Maximum Segment Size,最大报文长度)是指 TCP 提交给 IP 层的最大数据段大小,不包含 TCP Header 和 TCP Option,仅指 TCP Payload 的字节数。因此,MSS 是 TCP 用来限制应用层最大发送字节数的参数。
在 TCP 连接建立时,收发双方会协商后续通信时使用的 MSS(附在 SYN/ACK 报文头部的可选字段中),指示每一个报文段所能承载的最大数据长度。
在以太网环境下,MSS = MTU - 20 字节 TCP 报头 - 20 字节 IP 报头,若使用 PPPoE 还需再减去 8 字节帧头。MSS 值只会出现在 SYN 报文中,即当 SYN = 1 时,才会有 MSS 字段值。
PC 访问某网站时进行 TCP 三次握手的流程如下图所示:
- 首先客户端会发送一个 SYN 请求报文,该 SYN 报文的 "选项" 字段中会有 MSS 值(MSS = MTU - IP 首部长度 - TCP 首部长度)。此 MSS 值用于告知对方自己能够接受的最大发送数据大小。
- 当服务器端收到 SYN 报文后,会向请求端返回 SYN + ACK(同步确认报文),其中的 "选项" 字段同样会有 MSS 值。
- 通信双方选择 SYN 和 SYN + ACK 报文中较小的 MSS 作为此次 TCP 连接的 MSS,从而实现通信双方对 MSS 的协商。
双方在后续通信时,如果上层(应用层)下发的数据过长,超过 MSS,将按 MSS 的长度进行 TCP 报文的分段,分段后的报文再提交给 IP 层。由于 MSS 仅仅是源端和目标端双方协商的结果(还处于第四层),它们并不清楚中间节点的 PMTU,所以 MSS 只是描述了通信双方在 TCP 层的收发能力。源端和目标端之间的所有中间路由节点,对这个上层协商的 MSS 并不知晓。因此,在源端按 MSS 进行 TCP 报文分段后,如果 IP 报文长度超过 MTU,IP 层协议仍然会对其进行分片。可见,分段和分片是相互独立的过程。
由此可知,MSS 并不能从根本上解决 PMTU 黑洞问题,也无法解决因底层(IP)分片造成的传输效率问题。
MTU 和 MSS 的联系与区别
MTU 和 MSS 的相同点在于,它们均用于约束或协商通信双方的最大数据包长度。虽然 MSS 和 MTU 没有必然的直接联系,但是,对于通信发起方的源站点来说,为了在本机达到最高效率,MSS 应设置为本机 MTU - IP - Header (20) - TCP - Header (20) ,这样可以在最大长度的情况下,避免同一 TCP 报文被分成多个 IP 包 ------ 但这仅适用于本机,中间路由节点仍会根据自身的 MTU 进行分片操作。
在以太网中,本机 MTU 与 MSS 的最佳关系如下图所示:
MTU 和 MSS 的主要区别如下:
- 协议层次不同:MTU 表征 OSI 模型的第二层数据链路层的通信能力,而 MSS 表征第四层传输层 TCP 的通信能力。
- 实现方式不同:MTU 仅仅是一个规范,是第二层对第三层的约束;而 MSS 不仅包含约束,还定义了 TCP 连接建立时关于收发能力的协商过程。
- 影响范围不同:MSS 仅影响源端和目标端,而 MTU 影响整个路由路径上的所有节点。
绝招:MSS Clamping
由上文可知,设置一个理想的 PMTU 几乎是不可能的,因为每次路由路径都可能不同,难以确定一个固定的理想值。我们最多只能根据经验设置一个相对合适的值,以降低分片或丢失的概率。MSS 仅用于通信双方的协商,中间节点对此并不了解,无法解决本质问题。虽然 PMTUD(PMTU 探测)机制有望解决这个问题,但由于网络上大量节点关闭了 ICMP,导致该机制难以发挥作用。
MSS 的最大优势在于,它具有连接建立时的协商机制,能够约束源端高层(TCP)发送数据段的大小。然而,其协商出的值不准确,不能反映整个路由路径的传输能力,从而限制了其效能。假如这个数值能够由整个路由路径上的每一个节点参与协商,那么得出的 MSS 值将与 PMTU 一样准确。此时,源端高层按照这个数值进行 TCP 分段,那么源端发出的每一个 IP 包的大小都将恰到好处,只要路由路径不变,这些 IP 包都将被正确转发且无需分片。这是一种非常完美的机制!
MSS Clamping(MSS 钳制)就是这样一种打破层级界限的解决方案。它运行在路由器上,对经过的每一个包(无论是转发的包还是上层提交的包)进行嗅探。如果发现某一包是 TCP 连接建立的握手包,就会查看其中正在协商的 MSS 值(SYN/ACK 包中的 MSS 字段)。一旦发现该值比本机的 MTU 换算出来的 MSS 值大,就会修改包中的 MSS,将其调整为本机换算的 MSS 值(即:本机 MTU - IP 头 - TCP 头)。而通信双方并不知晓这一操作,它们仍以为包中的 MSS 值就是对方的 MSS,并将本次连接的 MSS 修改为这个更小的值。如果经过的所有路由器都开启了 MSS 钳制,那么到达源端/终端的 SYN/ACK 包中的 MSS 值就一定是整个路由路径中所有节点最小的 PMTU,这是一种非常完美的机制!
下图详细解释了 MSS Clamping 的整个流程,以及后续的数据收发细节:
从通信协议设计的角度来看,MSS Clamping 打破了传统的分层设计。整个 TCP/IP 协议栈采用分层设计,而它工作在第三层,却强行修改第四层的数据包。并且,MSS 协商机制原本仅用于通信双方交流收发能力,而它却允许中间节点查看甚至篡改协商内容。但从更高的层面来看,这种打破层级思维界限、敢于推翻旧秩序、建立新秩序的方式,在解决网络问题上具有重要意义。
看到这里,可能会产生一个疑问:TCP 连接建立后,路由路径不可能一直保持不变,那么连接建立时钳制出来的 MSS,在后续是否还准确?从理论上讲,确实存在不准确的情况。但在实际应用中,骨干/城域/接入网络通常能够保障 MTU ≥ 1500,互联网服务商的路由设备也由专业网管人员维护,一般也能达到这一标准。问题更多地出现在用户端的内部设备和拨号出口路由上,这些网络设备大多为中低端产品,其 MTU 往往是整条链路中最小的(如 PPPoE 的 1492)。此外,这些设备的功能是否完善、技术人员的专业水平如何,都存在不确定性。因此,PMTU 黑洞问题并非难以解决,关键在于解决网络的"最后一公里"问题。
我们再回过头来看整个路由路径,虽然骨干网、城域网和运营商的接入网可能会改变路径,但这些网络通常具有较高的稳定性和技术保障(MTU ≥ 1500)。而用户端路径和服务器端 IDC 机房路径相对固定,且技术保障相对较弱。因此,MSS Clamping 方案是解决 PMTU 分片和 IPv6 黑洞问题最为有效的方案。
还有一个问题,如何保证 TCP 通信途经的所有路由器都开启了 MSS Clamping 呢?实际上,我们并不需要所有路由器都开启该功能。根据木桶理论,最短的木板往往在技术保障最弱的用户端设备(也是路由选路的必经之路)。只要在这些设备的接入路由器上正确配置了 MSS Clamping,就能保证所钳制的 MSS 是全路径最小的。
哪些设备需要开启 MSS Clamping
从上文可知,骨干网、城域网、运营商的接入网络和 IDC 机房的内部网络,其二层大多运行以太网,能够保证 ≥ 1500 的有效负载。即使这些网络使用了不同的二层网络或复杂的隧道技术,由于有专业技术人员支持,即便无法达到 1500 的 MTU,也会正确配置 MSS Clamping。作为普通用户,无需过于关注这些网络。我们只需关注自己这边的通信设施。
引起 PMTU 变化的关键节点是那些连接不同网络进行转换的网关路由器,包括使用了隧道封装技术的各种网关(如 IPSec、L2TP 等 VPN、IPv6 - over - IPv4 或 IPv4 - over - IPv6 等)。我们需要特别关注这些设备,为其配置正确的 MSS Clamping。
例如,典型的 PPPoE 拨号路由器,它一端连接 MTU = 1500 的内网以太网,另一端连接 MTU = 1492 的 PPPoE 链路。如果没有正确配置 MSS,未开启 MSS Clamping,那么内网 PC 上发出的 IPv6 数据包很可能会被它丢弃。
正确设置 MSS Clamping
专业的路由器一般都支持 MSS Clamping。例如,Cisco 路由器的配置命令为 ip tcp adjust - mss [size]
,需要注意的是,该命令是双向的,会在所配置接口的入站和出站的 SYN / ACK 数据包中都进行钳制。
家用路由器如果采用拨号上网,厂商为了保证网络稳定,一般会默认开启 MSS Clamping。例如,基于华硕系统修改的 Padavan ,执行命令 iptables - L
可以看到这样一条转发规则:
text
[XXX - Router / home / root]# iptables - L
...
Chain FORWARD (policy DROP)
...
TCPMSS tcp -- anywhere anywhere tcp flags:SYN,RST/SYN TCPMSS clamp to PMTU
Linux 的 iptables / ip6tables 也支持 MSS Clamping,可以通过创建基于 mangle 表的 forward 链,并使用 --set - mss [size]
或 --clamp - mss - to - pmtu
选项的规则来启用 MSS 钳制。既可以指定具体的 MSS 值,也可以直接钳制到 PMTU(实际上就是本机的 MTU)。例如:
text
# 下面命令钳制到 1452,适合 PPPoE 用户
iptables - t mangle - A FORWARD - p tcp --tcp - flags SYN,RST SYN - j TCPMSS --set - mss 1452
ip6tables - t mangle - A FORWARD - p tcp --tcp - flags SYN,RST SYN - j TCPMSS --set - mss 1452
# 下面命令是自动钳制到 PMTU,此时应设置本机正确的 MTU,如 PPPoE 为 1492
iptables - t mangle - A FORWARD - p tcp --tcp - flags SYN,RST SYN - j TCPMSS --clamp - mss - to - pmtu
ip6tables - t mangle - A FORWARD - p tcp --tcp - flags SYN,RST SYN - j TCPMSS --clamp - mss - to - pmtu
如果要指定只对某一网络接口进行钳制,而不是对所有转发的包都钳制,可以操作 PREROUTING 表,并指定拨号的接口名称(ppp0)。例如:
text
ip6tables - t mangle - A POSTROUTING - p tcp --tcp - flags SYN,RST SYN - o ppp0 - j TCPMSS --clamp - mss - to - pmtu
需要注意的是,IPv4 和 IPv6 要分别进行配置。其他基于 iptables 的路由器(如 Padavan)都可以参考这种方法。
在 OpenWrt 路由器上,除了通过修改 iptables 规则的方法,还可以通过 Luci 界面进行配置:在【网络】【防火墙】【基本设置】【区域】处,在对应接口上勾选【MSS 钳制】即可。
RouterOS 路由器设置 MSS Clamping 的命令如下(其中 pppoe - out1 是 wan 口,1432 是要设置的 MSS 值,请根据实际需求修改):
text
/ ipv6 firewall mangle add chain = forward out - interface = pppoe - out1 protocol = tcp tcp - flags = syn action = change - mss new - mss = 1432
UBNT Edgerouter 系列设备设置 MSS Clamping 的命令如下:
text
set firewall options mss - clamp6 interface - type pppoe
set firewall options mss - clamp6 mss 1432
其他中低端的路由器,配置界面上可能无法直接看到相关设置信息。但一般来说,IPv4 通常默认开启了 MSS Clamping,而 IPv6 则不一定。
蜂窝 4G 网络的 MSS 分析
我们知道,手机的数据网络早已采用 IPv6,并且默认优先使用 IPv6,但其上网一直稳定流畅。那么,移动运营商的 4G 网关是如何处理 IPv6 碎片问题的呢?为了探究这个问题,使用电信手机(MIUI 系统、4G 数据)开启热点,电脑(Windows 10)连接该热点,并使用 Wireshark 进行抓包分析。
这是 4G 网络下访问知乎 IPv6 服务器的截图:
这是 4G 网络下访问百度 IPv4 服务器的截图:
此时,Windows 电脑上 WLAN 连接的 MTU 被改为 1410:
text
C:\> netsh interface ipv6 show subinterfaces
MTU MediaSenseState 传入字节 传出字节 接口
------ --------------- --------- --------- -------------
1410 1 117539374 58911024 WLAN
1500 5 0 152 本地连接 * 1
作为对比,这是同一台电脑连接 PPPoE 拨号路由器的 WIFI 后,访问知乎 IPv6 服务器的截图:
这是宽带 PPPoE 拨号访问百度 IPv4 服务器的截图:
此时,Windows 电脑上 WLAN 连接的 MTU 恢复为正常的 1500:
text
C:\> netsh interface ipv6 show subinterfaces
MTU MediaSenseState 传入字节 传出字节 接口
------ --------------- --------- --------- -------------
1500 1 118029364 62131090 WLAN
1500 5 0 152 本地连接 * 1
通过分析可以发现,安卓系统 AP 程序或运营商的 4G 网关将 IPv6 的 MSS 调整为 1300,将 IPv4 的 MSS 调整为 1370,均比 PPPoE 拨号网络的 MSS 小很多。
这里存在几个尚未明确的问题:
- 电脑连接手机热点后,其 MTU 被调整为 1410,比正常的 1500 少了 90 字节。手机热点是如何更改电脑 MTU 的呢?是否通过 DHCP 实现?
- 安卓系统 AP 程序或运营商的 4G 网关为何采用更小的 MSS?是蜂窝网络自身的 MTU 更小,还是 4G 接入网络采用了其他隧道技术,亦或是特意调小以增强 IPv6 的适应性?综合其他网友的实验,不同品牌手机的 MTU 各不相同,有的为 1432,而 iPhone 的 MTU 仅 1280。由此推测,更大的可能性是手机为提升 IPv6 的适应性,特意将 MSS 调小。
不管怎样,如果在拨号路由器开启 MSS Clamping 的情况下,将 MTU 设为 1492 仍无法保证网络稳定,可考虑借鉴 4G 网络的设置,将 IPv6 的 MSS 也调整为 1300,或把 MTU 设置为 1368。
双栈 DNS 优化
在双栈环境下,究竟使用哪个协议栈?是否有优先顺序可供设置?是由客户应用程序、底层操作系统,还是 DNS 服务器决定优先采用哪个协议栈呢?
答案是由应用程序自行决策。标准的 DNS 服务器无法控制程序优先使用哪个协议,它只能同时提供 IPv4 和 IPv6 的域名记录供客户端查询。客户端应用程序在建立 TCP 连接前,首先要将域名转换为 IP 地址,这通过向域名服务器发起 DNS 查询请求来实现。在 DNS 请求时,需要指定查询类型,IPv4 地址对应的查询类型为 A,IPv6 地址对应的查询类型为 AAAA。应用程序既可以只查询其中一种地址,也可以同时查询两种地址,然后依据自身逻辑选择使用哪个地址。对于绝大多数使用 BSD socket API 的应用程序,会通过 getaddrinfo
函数来解析域名,然后依次尝试连接,此时优先使用哪种协议由底层系统控制,getaddrinfo
函数将哪种协议排在前面,程序就会优先连接该协议。还有一些经过特殊设计的程序,比如 curl 以及各种浏览器,则具有其他逻辑。例如,它们会先检查本机的 IPv6 地址,如果是内网地址则会放弃使用 IPv6;如果是公网地址,会同时解析 IPv4 和 IPv6 地址,然后优先连接 IPv6,如果在较短时间内(如 1 秒)未能连接成功,则会继续尝试连接 IPv4,最终使用最早建立的连接。【本段内容摘自 Richard Yu 的评论,特此感谢】
目前,大多数终端设备(包括 PC 和手机)的知名应用程序(如浏览器)和操作系统默认都支持 IPv6,能够同时运行 v4/v6 双栈网络。如果路由器开启了 IPv6 DHCP,终端设备就能自动获取运营商提供的 IPv6 DNS 服务器地址。该 DNS 服务器不仅包含传统的 IPv4 记录,还拥有 IPv6 记录。而应用程序(通过 getaddrinfo
函数)通常会优先查询到 IPv6 地址,并使用该地址建立 TCP 连接,数据自然会通过 IPv6 协议栈传输。
例如,当我们访问知乎时,由于知乎服务器开启了双栈支持,在 IPv6 DNS 上,域名 www.zhihu.com
同时指向了知乎的 IPv6 和 IPv4 服务器地址。因此,浏览器在解析域名时会同时获取这两个地址,并且通常会优先使用 IPv6 地址建立连接,后续的 Web 流量也就通过 IPv6 协议栈传输。
这种 IPv6 优先的策略本身并无问题,但在当前的互联网环境中,多数互联网服务(网站)的 IPv4 网络性能优于 IPv6,少数互联网服务则可能出现 IPv6 网络性能优于 IPv4 的情况。如果存在这样一种 DNS 服务器,我们可以自行指定其优先返回 IPv4 地址或 IPv6 地址,甚至更智能地,它能从多个 IPv4 和 IPv6 地址中筛选出访问速度最快的 IP 地址返回给客户端。
SmartDNS 就是这样一款神器,它是一个运行在本地的 DNS 服务器,能够接收本地客户端的 DNS 查询请求,然后从多个上游 DNS 服务器获取 DNS 查询结果,并将访问速度最快的结果返回给客户端,从而提高网络访问速度。
SmartDNS 的架构和运行原理如下:
- SmartDNS 接收本地网络设备(如 PC、手机)的 DNS 查询请求。
- 将查询请求发送到多个上游 DNS 服务器,支持 UDP 标准端口或非标准端口查询,以及 TCP 查询。
- 上游 DNS 服务器返回域名对应的服务器 IP 地址列表,SmartDNS 则检测从本地网络访问这些服务器 IP 的速度。
- 最后将访问速度最快的服务器 IP 返回给本地客户端。

借助 SmartDNS,我们可以在本地搭建自己的智能 DNS 服务器,以优化网络。例如,可以将其以插件形式安装在 OpenWRT 路由器上,具体安装过程在此不再赘述。
总结
综上所述,开启 IPv6 后网络出现的不稳定问题,很大程度上可能是由 PMTU 黑洞导致的。解决这一问题的关键在于在拨号路由器上开启 MSS Clamping 功能,在传输层将数据分段为最合适的大小,避免中间路由器进行 IP 分片操作。
本文参考文章:
-
华为 IP 百科 什么是 MTU
-
小菜学编程 IP 分片
-
大西洋里的鱼 MTU TCP-MSS 详解
-
raysonx 开启 IPv6 后网速变得很慢?可能是 PMTU 黑洞的问题
-
SmartDNS SmartDNS (pymumu.github.io)
via:
-
IPv6 间接性抽风?试试路由器的 MTU 设置。 -- Nero978 的日记
https://nero978.top/archives/204 -
使用 IPv6 后一些网站无法访问,有时能访问有时无法访问问题解决 - 次世代 BUG 池
https://neucrack.com/p/400 -
从原理到实践,彻底告别 IPv6 上网不稳定的问题 - 知乎
https://zhuanlan.zhihu.com/p/621371177