为什么 GitHub 不喜欢我的 MTU

让我来告诉你我花了一整天与我的 WireGuard VPN 搏斗的挫败经历, 以及为什么 GitHub 成了唯一一个不配合的网站。我希望我的经验, 特别是如果你像我一样在 microk8s 环境中运行 WireGuard,能帮你省去一些麻烦。

环境:microk8s、Ubuntu 和 WireGuard

我的环境有点复杂。 我有一个运行在 Ubuntu 24.04.2 LTS 服务器节点(GNU/Linux 6.8.0-54-generic x86_64)上的 microk8s 集群。 我将我的 WireGuard VPN 服务器作为 pod 在这个 microk8s 集群中运行。这增加了一层我最初没有考虑到的网络复杂性。

问题:GitHub 无法访问(但其他一切都很好)

一切似乎都很好。我可以通过我的 WireGuard VPN 访问大多数网站。 Google、YouTube、Twitter——都没问题。但是 https://github.com 就是无法加载。

curl https://github.com 无限期地挂起。我挠着头,想知道是 DNS 问题、防火墙问题,还是其他什么问题。

调试:深入网络

  1. 初始测试:

     1
     2
     3
     4
     5
     6
     7
     8
     9
    10
    11
    12
    13
    14
    15
    16
    17
    18
    
    curl github.com # 有效!返回 301 重定向到 HTTPS
    curl -v github.com
    * Host github.com:80 was resolved.
    * IPv4: 20.27.177.113
    * Trying 20.27.177.113:80...
    * Connected to github.com (20.27.177.113) port 80
    > GET / HTTP/1.1
    > Host: github.com
    > User-Agent: curl/8.5.0
    > Accept: */*
    >
    < HTTP/1.1 301 Moved Permanently
    < Content-Length: 0
    < Location: [https://github.com/](https://github.com/)
    <
    * Connection #0 to host github.com left intact
    
    curl [https://github.com](https://github.com) # 挂起...
    

    这令人难以置信地困惑。HTTP 有效,但 HTTPS 无效。 但是 Google 和 Twitter 等其他 HTTPS 网站都很好。这表明问题特定于 HTTPS,并且可能与 GitHub 有关。

  2. MTU 调查:罪魁祸首出现

    我怀疑是 MTU 问题,因为 HTTPS 连接存在问题。因此,我检查了我的 WireGuard 客户端接口:

    1
    2
    3
    
    ip l show wg-client0
    6: wg-client0: <POINTOPOINT,NOARP,UP,LOWER_UP> mtu 1420 qdisc noqueue state UNKNOWN mode DEFAULT group default qlen 1000
        link/none
    

    然后,我连接到在我的 microk8s 集群中运行的 WireGuard pod,并检查了服务器端接口:

    1
    2
    3
    
    ip l show wg0
    3: wg0: <POINTOPOINT,NOARP,UP,LOWER_UP> mtu 1370 qdisc noqueue state UNKNOWN mode DEFAULT group default qlen 1000
        link/none
    

    发现不同的 MTU,这很可能是问题的根源。

  3. MTU 调整和测试:解决方案

    我开始系统地降低客户端配置上的 MTU,以匹配 pod 内服务器端 MTU。

     1
     2
     3
     4
     5
     6
     7
     8
     9
    10
    11
    
    [Interface]
    PrivateKey = ...
    Address = ...
    DNS = ...
    MTU = 1370 # 匹配 pod 中的服务器端 MTU
    
    [Peer]
    PublicKey = ...
    AllowedIPs = 0.0.0.0/0
    Endpoint = your-server-ip:your-port
    PersistentKeepalive = 25
    

    重新启动我的 WireGuard 连接后,我再次尝试 curl https://github.com

    1
    
    curl -v [https://github.com](https://github.com) # 成功!
    

    GitHub 在浏览器中也可以正常加载。

为什么会发生这种情况:深入了解网络

  • 路径分片和 microk8s: microk8s 网络设置与 WireGuard 的封装相结合,增加了潜在分片的层数。
  • TLS 握手和 GitHub: GitHub 的 TLS 握手,可能由于其大小或网络路径,对路径分片特别敏感。
  • 本地与路径分片: 通过降低 MTU,我强制进行本地分片(由我的操作系统控制),而不是依赖不可预测的路径分片。

理解 MTU 和分片

MTU 是可以在网络接口上传输的最大 IP 数据包大小,而无需分片。当数据包超过网络链路的 MTU 时,会发生分片,导致其被分成更小的片段。虽然本地分片(发送设备进行的分片)通常是可管理的,但路径分片(网络路径上的路由器进行的分片)可能导致数据包丢失、重新排序,甚至被防火墙阻止。

分片对 TLS 握手的影响

TLS 握手是建立客户端和服务器之间安全加密连接的关键过程。它涉及交换消息,包括证书和加密密钥。如果由于分片而丢失了握手数据包的任何部分,则整个握手都可能失败,从而导致连接问题。

为什么 GitHub 受到影响而其他网站没有

估计是因为不同的网站具有不同的特性,包括:

  • 数据包大小: 具有较大内容(如 GitHub)的网站更有可能生成较大的数据包,从而增加分片的风险。
  • CDN 和服务器差异: 不同的网站使用不同的 CDN 和服务器,它们可能具有不同的 MTU 设置和网络路径。
  • TLS 握手差异: 网站之间的 TLS 握手过程可能不同,从而影响数据包大小和对分片的敏感性。

解决问题:降低 MTU

根本原因是我的 WireGuard 客户端和在我的 microk8s 集群中作为 pod 运行的 WireGuard 服务器之间的 MTU 不匹配。 通过将客户端的 MTU 设置为与服务器相同的值(1370),我解决了问题。

通过降低 WireGuard 客户端和服务器上的 MTU,用户可以控制分片发生的位置。 本地分片通常比路径分片更可靠,因为它由发送设备处理。这确保数据包被分片成可以遍历网络路径而无需进一步分片的大小,防止数据包丢失并确保成功的 TLS 握手。

主要收获

  • MTU 和分片会显著影响网络性能和可靠性,尤其是对于 TLS 等敏感协议。
  • 理解 MTU 和分片的细微差别对于排除网络连接问题至关重要。
  • 通过仔细调整 MTU 设置和控制分片,可以确保平稳可靠的网络通信。
  • 如果你在像 microk8s 这样的容器化环境中运行 WireGuard,请密切关注 MTU 设置。
  • 始终检查并匹配 WireGuard 客户端和在其容器环境中的服务器之间的 MTU 设置。
  • 使用 curl -vip link showtcpdump(如果需要)来调试网络问题。
  • 请记住,你的客户端、你的 microk8s 服务器节点和 Internet 之间的网络路径可能具有许多不同的 MTU 值。

我希望这篇博文能为你提供有关排除与 MTU 和分片相关的 WireGuard VPN 问题的思路.