技术指南
WireGuard 大包卡住:定位 MTU 与 PMTU 黑洞
从握手成功但大传输卡住出发,用分档探测区分外层路径与隧道 MTU,再做单变量修正和可验证回滚。
WireGuard 已握手、短 ping 或小请求正常,但 SSH 交互停顿、HTTPS 上传下载卡住、文件只传一小段时,先验证是否存在按包大小触发的路径故障。不要直接抄一个 MTU 数字:要分别证明外层 UDP 路径、隧道接口和隧道内业务在哪个尺寸开始失败,再只调整拥有该封装边界的一层。
用现象先区分五条路径
| 观察 | 优先解释 | 下一步 |
|---|---|---|
| 没有近期握手,小包也不通 | 端点、密钥、监听、防火墙或基础路由故障 | 先恢复 WireGuard 基本连通,不进入 MTU 调整 |
| 小包双向成功,超过某一尺寸稳定失败 | PMTU、封装开销或 Packet Too Big 反馈异常 | 固定地址族与方向,分档收敛失败边界 |
| 外层受控目标也在同一尺寸失败 | VPS 到端点之间的承载路径有更小 MTU | 核对云网络、上游隧道、PPPoE/VLAN 与 ICMP 返回路径 |
| 外层路径正常,只有 wg0 内层失败 | 隧道接口 MTU 或嵌套封装预算不匹配 | 临时降低一个接口,双向复测后再持久化 |
| 定长探测都成功,只有某个应用失败 | 应用、代理、TLS、拥塞、重传或协议自身问题 | 用真实业务请求取证,不把所有卡顿归因于 MTU |
先保存接口、路由和握手现场
tunnel=wg0
peer_inner=10.0.0.2
date --utc --iso-8601=seconds
uname -r
wg --version
ip -details link show dev "$tunnel"
ip -s link show dev "$tunnel"
ip route get "$peer_inner"
sudo wg show "$tunnel"
sysctl net.ipv4.tcp_mtu_probing先确认失败流量确实经过预期接口。`ip route get` 输出的是内核解析后的单条路径;策略路由、网络命名空间、容器或应用绑定源地址时,应从实际发起请求的环境重复查询。近期握手只证明控制报文有往返,不能证明更大的隧道内数据包可用。
用总包长分档复现,而不是猜一个魔法值
target4=10.0.0.2
for total in 1280 1320 1360 1400 1420; do
payload=$((total - 28))
printf '\nIPv4 total=%s payload=%s\n' "$total" "$payload"
ping -4 -n -c 2 -W 2 -M do -s "$payload" "$target4"
done
target6=fd00::2
for total in 1280 1320 1360 1400 1420; do
payload=$((total - 48))
printf '\nIPv6 total=%s payload=%s\n' "$total" "$payload"
ping -6 -n -c 2 -W 2 -M do -s "$payload" "$target6"
doneiputils 的 `-M do` 会设置禁止分片并让内核执行 PMTU 检查,过大的包可能在本机就被拒绝;`-s` 只计算 ICMP 数据字节。分别记录成功、超时和本地 `message too long`,在两端、两个方向和实际使用的地址族重复。找到相邻的成功/失败尺寸即可,不需要用大量探测追求单字节精度。
把外层承载和隧道内层分开
| 层 | 应固定的对象 | 可回答的问题 |
|---|---|---|
| 外层承载 | WireGuard 端点地址、出口接口、云路由和中间封装 | UDP 封装包能否到达对端;基础路径是否已经小于预期 |
| WireGuard 接口 | wg0 的 MTU、AllowedIPs 与实际解析路由 | 内层 IP 包在加上 WireGuard/UDP/IP 开销后是否超出承载能力 |
| 隧道内业务 | 真实 TCP/UDP 协议、方向、请求大小和时间窗 | 应用是否真的按尺寸失败,修正后是否恢复 |
封装开销取决于外层 IPv4/IPv6 和是否还叠加其他隧道、VLAN 或云网络,不能永远按一个固定差值计算。当前 `wg-quick` 在未显式设置 MTU 时会根据端点路由或默认路由自动推导;显式 `MTU =` 会覆盖自动选择。旧发行版可能打包不同实现,因此要同时记录 `wg --version`、实际接口值和配置管理器。
用 tracepath 交叉检查,不把沉默当结论
tracepath -4 -n 10.0.0.2
tracepath -6 -n fd00::2tracepath 使用 Linux 错误队列观察路径与 PMTU 变化,输出中的 `pmtu N` 对应收到的 message-too-long 线索。没有显示更小 PMTU 不等于路径支持当前尺寸:Packet Too Big 可能在回程被过滤,路径可能不对称,或探测协议与业务走了不同策略。
修复 Packet Too Big 返回路径,而不是全面放行或全面丢弃
经典 IPv4 PMTUD 依赖 ICMP Destination Unreachable/fragmentation needed,IPv6 PMTUD 依赖 ICMPv6 Packet Too Big。RFC 8201 明确描述了反馈丢失时 TCP 三次握手成功、传输阶段挂起的黑洞现象。核对云防火墙、主机规则、容器/转发链和对端策略是否允许相关错误返回,并保留限速与状态边界;不要把允许必要 ICMP 误写成对公网开放所有控制面。
先做一个临时接口 MTU 变更
tunnel=wg0
old_mtu=$(cat "/sys/class/net/${tunnel}/mtu")
candidate=1380 # 仅示例:替换为双向分档测试得到的候选值
printf 'old_mtu=%s candidate=%s\n' "$old_mtu" "$candidate"
sudo ip link set dev "$tunnel" mtu "$candidate"
ip link show dev "$tunnel"
# 验收失败时立即恢复
# sudo ip link set dev "$tunnel" mtu "$old_mtu"候选值应不高于已稳定成功的内层总包长,并通过两个方向、真实地址族和真实业务验证。降低过多虽然可能掩盖黑洞,却会增加包数与协议开销;一次成功传输也不能证明长期最优。先把临时变更作为因果实验,确认失败边界随接口 MTU 移动且业务恢复,再决定是否持久化。
按真正的接口所有者持久化
若接口由 `wg-quick` 管理,在受控的 `/etc/wireguard/<interface>.conf` 的 `[Interface]` 中写入已经验证的 `MTU =`,保护包含私钥的配置,并在维护窗口按该管理器的停启流程验证。NetworkManager、systemd-networkd、容器编排和云代理有各自的配置入口;不要同时让两个管理器争用接口,也不要只修改运行时后假定重启会保留。`SaveConfig = true` 还可能在关闭时覆盖文件,变更前必须核对。
TCP MTU probing 只是一条受限缓解路径
before=$(sysctl -n net.ipv4.tcp_mtu_probing)
printf 'tcp_mtu_probing_before=%s\n' "$before"
sudo sysctl -w net.ipv4.tcp_mtu_probing=1
# 只用新建 TCP 连接验证;失败或无收益时恢复
# sudo sysctl -w net.ipv4.tcp_mtu_probing="$before"这个 sysctl 控制 Linux TCP 的 Packetization-Layer PMTU Discovery,不修复 WireGuard 的 UDP 封装,也不能帮助不具备相应探测机制的 UDP 应用。只有实际失败集中在 TCP、接口与 ICMP 边界暂时不能立刻修复,并且新连接的对照测试显示收益时,才把值 1 当临时缓解;值 2、MSS clamp 和路由级 MTU 都会扩大影响面,应单独评审。
用双向尺寸和真实业务共同验收
- 两端都保存原始接口 MTU、版本、路由和 UTC 时间;候选变更只有一个变量。
- 分档 ICMP 探测在实际 IPv4/IPv6 与两个方向达到预期边界,没有新的本地 message-too-long 或稳定超时。
- 真实 SSH、HTTPS 上传/下载和实际 UDP 业务按使用项完成大于原失败点的传输,并核对内容完整性与应用错误。
- WireGuard 握手、transfer 计数、接口丢包/错误和业务延迟在观察窗内没有退化;路径切换或漫游后重复检查。
- 重启接口或主机后,配置管理器恢复同一 MTU,独立管理入口仍可用,回滚值和操作人保持可追溯。
回滚 MTU 与配置,不同时撤销证据
候选导致吞吐下降、其他地址族失败、路径切换后复发或业务仍卡住时,先恢复两端保存的接口 MTU 和对应持久配置,再用相同矩阵复测。若同时临时启用了 `tcp_mtu_probing`,恢复原值并用新连接验证。不要用删除日志、清空路由缓存或重启所有网络服务替代精确回滚。
把 MTU 当作路径属性持续复验
云网络、家庭宽带、移动网络、对端地址族、嵌套 VPN 和 WireGuard 工具版本变化都可能改变可用 PMTU。监控应保留真实业务失败、地址族、方向、端点与包长相关性,而不是只看隧道是否握手。发生迁移、增加一层封装或升级网络管理器后,重新执行低频分档和真实业务验收。
本文命令在 2026-08-18 按 WireGuard tools、Linux 内核、iproute2、iputils 与 IETF 当前上游文档完成语义和语法审阅,没有在读者的 VPS、WireGuard 对端或生产网络上执行。BSD/macOS/Windows、旧版 iputils、用户态 WireGuard、容器网络和托管 VPN 的命令与自动 MTU 逻辑可能不同;执行前先确认本机版本、帮助文本、实际接口所有者和独立恢复路径。