跳到主要内容

VPN 在 Linux 上正常工作时,人们很容易忘记其中并没有什么魔法。系统多出一个名为 wg0 或 tun0 的网络接口,添加了几条路由,从那一刻起,内核就因为路由表的指示而把数据包送进隧道。出了问题时,比如连接后没有网络、打印机消失,或者流量仍然走错方向,答案几乎总能在路由表里找到。

本文从基础讲起,说明 Linux 上的 VPN 路由:怎样读 ip route,怎样预判全隧道 VPN 会对路由表做什么,以及现代客户端在底层使用的策略路由。内容不依赖于具体的服务商,适用于 WireGuard、OpenVPN 和其他类型的隧道。如果想先了解隧道本身的概念,可以看 什么是 VPN 隧道。

路由表到底决定什么

每个外发数据包都有一个目的地址,内核必须选择一个接口,通常还要选择下一跳。它依据路由表来做这件事。核心规则很简单:在所有目的网段包含该数据包目的地址的路由中,选最具体的那一条。/24 胜过 /16,/32 胜过一切。如果前缀长度相同,metric 较小的路由获胜。

这条规则叫作最长前缀匹配,它是 VPN 路由的全部基础。VPN 客户端并没有劫持什么,它只是添加了比原有路由更具体或更优先的路由。

连接 VPN 之前先读懂路由表

先在 VPN 关闭时查看路由表。运行 ip route show,你会看到类似下面的内容。

default via 192.168.1.1 dev wlp3s0 proto dhcp metric 600
192.168.1.0/24 dev wlp3s0 proto kernel scope link src 192.168.1.42

逐行来读。

  • default via 192.168.1.1 dev wlp3s0 表示“其他路由都匹配不上的流量,通过 Wi-Fi 接口发给 192.168.1.1 这台路由器”。
  • 192.168.1.0/24 dev wlp3s0 scope link 表示家庭网络内的地址在链路上直接可达,中间不经过路由器。
  • metric 600 在两条路由同样具体时用于决胜,数值越小越优先。

接着也要运行 ip -6 route show。很多人只保护了 IPv4,却忘了 IPv6 的路由表是独立的,这正是 IPv6 泄漏的根源。两者的区别可以参考 IPv4 与 IPv6 对 VPN 的影响。最后,最有用的命令是 ip route get 8.8.8.8,它会明确告诉你内核访问该目的地时会使用哪个接口、网关和源地址,并且已经计入了策略规则。

全隧道 VPN 会对路由表做什么

连接一个需要承载你全部流量的 VPN 时,客户端必须让隧道对每一个目的地都获胜。常见的做法有两种。

替换默认路由。 客户端删除原有默认路由,再添加 default dev tun0。这很简单,但会失去回到物理网络的通路,因此还需要为服务器本身单独处理。

半默认路由技巧。 许多客户端保留原来的默认路由,只添加两条合起来覆盖整个地址空间的路由:

0.0.0.0/1 dev tun0
128.0.0.0/1 dev tun0

每条都是 /1,比 /0 的默认路由更具体,所以都能赢得最长前缀匹配。VPN 停止时,客户端删除这两行,原来的默认路由重新生效,什么都不用恢复。你可以在自己的机器上验证:连接后运行 ip route show,找找这一对路由。

服务器端点的例外。 有一个目的地绝对不能进入隧道,那就是 VPN 服务器本身。承载你流量的加密数据包必须通过普通网络到达它。所以客户端会添加一条主机路由,例如:

203.0.113.10 via 192.168.1.1 dev wlp3s0

这里的 203.0.113.10 是文档示例地址。如果缺少这条路由,服务器地址就会匹配隧道路由,加密数据包会试图进入它所属的那条隧道,连接循环后中断。连接成功后立刻没有网络的 VPN,十有八九是缺少了这条例外。

策略路由、fwmark 与额外的路由表

现代 WireGuard 配置完全避免修改主路由表。当配置指明所有 IPv4 流量都要走隧道时,标准脚本会创建一张独立的路由表和几条规则。用 ip rule show 可以看到:

0:      from all lookup local
32764:  from all lookup main suppress_prefixlength 0
32765:  not from all fwmark 0xca6c lookup 51820
32766:  from all lookup main
32767:  from all lookup default

再用 ip route show table 51820 查看那张额外的表,里面是 default dev wg0。其中的逻辑相当精巧。

  1. 隧道软件给自己的加密数据包打上防火墙标记,这里是 0xca6c,换成十进制就是 51820。
  2. 优先级 32765 的规则规定:没有该标记的数据包要去查 51820 号表,那里的默认路由指向隧道。
  3. 带标记的数据包跳过这条规则,落到主表,于是通过真实网络到达服务器,不需要主机路由。
  4. 优先级 32764 的规则让主表先回答比默认路由更具体的路由,比如本地网络,所以局域网访问依然正常。

如果你发现某条神秘路由没有出现在 ip route show 里,请查看 ip rule show 和各编号路由表。单独的 ip route show 只打印主表。

实例:只让办公网段走隧道

并不是每条隧道都要承载一切。假设你在家办公,公司网络是 10.20.0.0/16,通过 10.8.0.1 的隧道访问。你希望公司流量走隧道,其他流量用自己的网络。相关路由如下:

10.20.0.0/16 via 10.8.0.1 dev tun0
default via 192.168.1.1 dev wlp3s0

发往 10.20.5.9 的数据包匹配 /16,进入隧道;发往公网网站的数据包只匹配默认路由,直接发出。在 WireGuard 配置里,这个想法写作 AllowedIPs = 10.20.0.0/16,它承担两项工作:告诉内核哪些目的地要送进 wg0,同时告诉 WireGuard 接受来自该对端的哪些源地址。如果设置 AllowedIPs = 0.0.0.0/0, ::/0,就是请求全隧道。针对应用而不是网段的类似思路,见 什么是分流(Split Tunneling)。

排查清单

在 Linux 上 VPN 出问题时,按这个顺序检查。

  1. 对访问失败的站点运行 ip route get 目的地,看接口是否符合预期。
  2. 如果普通路由表看起来没问题,再运行 ip rule show 和 ip route show table all。
  3. 运行 ip -6 route show,看是否有经物理链路的 IPv6 默认路由绕过了隧道。
  4. 检查端点:确认 ip route get 服务器地址 给出的是物理接口,而不是隧道。
  5. 查看是否有重叠网段。如果家里和公司都用 192.168.1.0/24,内核就无法区分。请按 RFC 1918 描述的私有地址块,给家里换一个不同的网段。
  6. 检查 sysctl net.ipv4.conf.all.rp_filter。严格的反向路径过滤可能丢弃从路由所指接口以外的接口返回的应答包。
  7. 检查 MTU。大数据包无声消失而小包正常,是隧道 MTU 偏高的典型迹象,原因可参阅 RFC 1191 中的路径 MTU 发现,并尝试调低隧道接口的数值。

症状与可能原因

症状 可能原因 先检查什么
已连接但完全没有网络 服务器地址被路由进了隧道 对服务器地址执行 ip route get
网站能打开,打印机没了 全隧道吞掉了局域网网段 对打印机执行 ip route get
有些站点卡住,有些正常 MTU 过高或 IPv6 路径异常 降低 MTU,查看 ip -6 route
公司主机访问不到 缺少通往公司网段的路由 查看该网段的 ip route show
只有重启后才能用 手动添加的路由没有持久化 把它们写进 VPN 配置
两个网络使用同一网段 地址重叠 给其中一个重新编号

常见错误

  • 用 ip route add 手动添加路由,却指望重启后仍然存在,实际上不会。
  • 为了“强制”走 VPN 而删除默认路由,结果和服务器失联。
  • 只看 ip route show,漏掉了策略规则。
  • 忘记 IPv6 路由表。
  • 家里和公司使用同一个私有网段。
  • 连接运行期间修改路由,却没有记录原始值。

总结

Linux 上的 VPN 路由归根结底是路由表、最长前缀匹配,以及现代配置里带独立路由表的防火墙标记。学会读 ip route、ip rule 和 ip route get,让服务器地址留在隧道之外,别忘了 IPv6,避免子网重叠,几乎任何走错路径的数据包你都能在一分钟内解释清楚。

如果你使用免费的 VPNclient 应用,Linux 设置指南 介绍了如何安装,准备好之后也可以在 价格页面 查看可选项。

常见问题

VPN 为什么一定要修改路由表?

内核按路由表转发每一个数据包。只有存在指向 VPN 接口的路由,它才会承载流量,所以客户端会添加路由,让隧道成为需要保护的目的地的最佳匹配。

0.0.0.0/1 和 128.0.0.0/1 这个技巧是什么意思?

这两半合起来覆盖整个 IPv4 地址空间,但比原有默认路由更具体,因此在最长前缀匹配中胜出,而无需删除原来的默认路由。VPN 停止时把它们删掉,原有行为就恢复了。

为什么 VPN 服务器自己的地址必须留在隧道之外?

承载你流量的加密数据包必须通过普通网络到达服务器。如果通往服务器的路由指向隧道,这些数据包就会试图在自己内部传输,连接随即崩溃。

怎样查看某个目的地会走哪条路由?

运行 ip route get 加上地址。它会输出内核将选择的接口、网关和源地址,并且会考虑策略规则,而普通的 ip route show 做不到这一点。

开着 VPN 时局域网打印机不能用了,为什么?

全隧道配置可能把本地网段也送进了隧道。可以为局域网添加一条经物理接口的更具体路由,或选择排除私有网段的配置。

关于作者

Bob Kanokphon Thongdee,XPASS VPN 创始人

Bob Kanokphon Thongdee

  • XPASS VPN 创始人
  • eSIMonline.asia 联合创始人
  • 7 年以上网络营销经验
  • Cojourney Visa 与 Cojourney Travel 创始人

短途出行或忙碌的一个月,需要 VPN?

XPASS 提供按天数计算的预付通行证。一次付款,不会自动续费。

查看通行证

继续阅读

VPN 基础

VPN 隧道是什么?数据是怎样被层层包起来的

VPN 隧道不是一个地方,而是一种封装方法:你的数据被包进另一层数据里送到服务器。了解它的结构、生命周期与局限。

阅读约 9 分钟

VPN 安全

什么是分流隧道(Split Tunneling)?

分流隧道让你选择哪些应用或网站走 VPN,哪些直接访问互联网。它很灵活,但也会改变被保护的范围。

阅读约 9 分钟

VPN 安全

IPv4 与 IPv6 对 VPN 用户意味着什么

你的设备很可能同时拥有 IPv4 和 IPv6 地址。本文说明这对 VPN 意味着什么、两者在隐私和安全上有何不同,以及如何检查自己的环境。

阅读约 10 分钟

VPN 基础

什么是 VPN 协议?

VPN 协议规定了你的设备与 VPN 服务器如何连接并保护流量。本文用通俗的语言讲清楚它的含义和主要取舍。

阅读约 9 分钟

VPN 安全

VPN 的 Split DNS(分流 DNS)是什么

Split DNS 让设备按域名选择不同的解析器:内部名称走 VPN,其他名称走平时的解析器。本文介绍原理、使用场景和检查方法。

阅读约 9 分钟