客户端显示已连接,锁标记也在,网站却仍然记录着你家的地址。什么都没有坏。隧道并不取代你的 Wi-Fi 或移动链路;它给特定数据包套上第二层信封,再把信封沿着你原有的网络发出去。理解这套把戏,主要是跟踪一个请求,并注意信封在哪里被打开,因为几乎所有令人困惑的症状,从家庭地址泄露到大文件下载卡住,都来自那道边界。

两个信封,一条物理链路

笔记本保持着到路由器的正常连接,路由器也保持着到运营商的正常连接。隧道建立时,这条路径上的任何东西都没有改变。改变的是:被选中的数据包交给一个虚拟接口,包进一个以 VPN 对端为目标的新数据包,再作为普通流量从物理链路发出去。

接收端是一台设备,它拆开信封,把原始数据包转发向目的地。在两端之间,观察者只看得到外层包头,看不到内层的内容——除非协议对其实施加密,多数消费级协议都会加密,而通用技术本身并不要求。

这就是虚拟接口既真实又具有误导性的原因。它作为内核对象存在,有地址和最大传输单元,操作系统像对待其他接口一样把流量路由进去。它不是一根网线,它的存在只能证明某个组件已经安装。浏览器是否使用它由路由决定,而不是由接口是否处于开启状态决定。

观察一个请求的旅程

选一个目的地,问内核会走哪个接口。这一条命令就能解决大多数关于隧道是否起作用的争论:

ip route get 203.0.113.7
ip -brief addr show
ip -4 addr show dev wg0

如果路由输出指出隧道接口,数据包就会被封装。如果指出物理接口,就不会被封装,客户端重启多少次都改变不了。第二条命令把两个接口并排显示出来,你正是这样发现一个没有地址、或者地址属于错误协议族的隧道。

接着看信封内部的第一跳,并与外部的第一跳作对比:

traceroute -n -m 3 203.0.113.7
sudo tcpdump -ni wg0 -c 5

在隧道内部,第一跳是对端的内部地址,而不是你的路由器。在隧道接口上抓包,看到的是内层数据包,也就是应用以为自己正在发送的流量。同时在物理接口上抓包,看到的是外层数据包,两者合在一起,就是对隧道究竟做了什么的最清楚演示。

三个地址,网站只看得到其中一个

人们经常把这些混为一谈,混淆又会制造虚假的泄漏报告。它们是不同报头里的不同字段,生命周期也不同。

AddressWhere it appearsWho can see it
Endpoint addressOuter header, the peer you connect toYour access network and the path to it
Inner tunnel addressInside the envelope, on the virtual interfaceThe peer, and anything the peer routes to
Exit addressSource of the packet that reaches the websiteThe website and its upstream

虚拟适配器旁边的数字是第二行。它不是网站记录的地址,把它说成你的公网 IP 完全是错的。网站看到的地址由出口分配,而在通往私有网络的隧道里,可能根本没有公网出口,因为目的地位于组织内部,而不是互联网上。

站点到站点的隧道是同一套机制,只是端点不同。两台路由器在两张网络之间封装流量,没有任何一台单独设备安装了客户端。信封在原理上相同,而管理边界不同。

信封在哪里被打开,以及什么能穿过它

隧道终止于它的对端。如果应用自身的加密延伸得更远,它就能穿过那道边界,这正是 HTTPS 的常态:浏览器的会话终止在网站,因此出口转发的是它读不懂的密文。

默认情况下别的都穿不过去。未加密的请求在出口可读,和它在咖啡馆 Wi-Fi 上一样可读,隧道并没有增加应用从来没有过的保护。同样,出口的防火墙规则和转发策略决定接下来发生什么;握手成功只是关于对端连接的事实,与旅程的其余部分无关。

开销是另一个可见后果。每个数据包都多带一个报头,外层传输还可能再加一个,于是每个包的可用载荷变小。在最大传输单元固定的路径上,隧道能通过 ping 却卡住大文件上传,原因正在于此。

核实应用实际走过的路径

最后一步是确认具体的应用,而不是整台机器。解析目的地,查看该地址的路由,然后在连接打开时观察它:

getent hosts example.com
ip route get "$(getent hosts example.com | awk '{print $1; exit}')"
ss -tnp state established '( dport = :443 )'

如果路由指出隧道,但套接字列表显示的连接源地址来自物理接口,那么应用绑定到了某个具体对象,或者有第二条隧道在争抢默认路由。这是路由问题,靠这三条输出就能回答,而不必看客户端的状态界面。

RFC 4301 安全架构描述了这种封装在 IPsec 中的 IP 层版本,同样的分层逻辑也适用于 WireGuard 和 OpenVPN。一旦你能把内层数据包和外层数据包当作两个独立对象指出,隧道的大部分行为就不再神秘,而变成一张你读得懂的路由表。

相关文章