#IP / Port 变化时,连接不需要重建、不中断、甚至不需要“感知恢复

#IP / Port 变化时,连接不需要重建、不中断、甚至不需要“感知恢复

这是 WireGuard 最“魔法”的地方之一
IP / Port 变化时,连接不需要重建、不中断、甚至不需要“感知恢复”。

结论先行一句话:

WireGuard 根本不把“连接”绑定在 IP/Port 上,而是绑定在密钥身份上。

下面我从 机制 → 数据路径 → 时序 → 边界条件 四个层次,把它彻底拆开。


一、WireGuard 的“连接”到底是什么?

在 WireGuard 里:

传统 VPN WireGuard
连接 = TCP/UDP 会话 连接 = 公钥身份 + 会话密钥
IP/Port 是身份的一部分 IP/Port 只是“最近一次可达路径”
断链要重连 路径变了自动学习

IP/Port 不是连接的锚点

真正的锚点是:

Peer Public Key  →  Session (Noise IK)  

二、核心设计:Endpoint 是“可学习”的

struct wg_peer 里,有一个非常关键的字段:

struct endpoint endpoint;  

这个 endpoint:

  • 不是配置死的
  • ✅ 可以被运行时更新
  • ✅ 每次收到合法数据包都可能刷新

三、IP/Port 变化时发生了什么?(完整时序)

我们假设一个最常见的场景:

手机从 Wi‑Fi → 4G
IP 变了,端口也变了


🟢 第 1 步:客户端发送任意 WireGuard 数据包

  • 可能是:
    • keepalive
    • 数据包
    • rekey 包
  • 使用 已有会话密钥 加密
  • UDP 源 IP / Port 已经变了

🟢 第 2 步:服务端收到 UDP 包

服务端做的第一件事不是

❌ “你 IP 变了,拒绝”

而是:

先尝试解密

流程是:

UDP 包 →  
  解析 WireGuard 消息类型 →  
    用所有 peer 的 key 尝试匹配 →  
      找到能成功解密的 peer  

⚠️ 这里的查找是 基于 key,而不是 IP


🟢 第 3 步:认证成功 → 更新 endpoint

一旦解密 + 认证成功:

peer->endpoint = skb->src_ip:src_port;  

endpoint 被原子性更新

这一步叫:

Endpoint Roaming

而且是:

  • 无日志
  • 无状态切换
  • 无 reconnect

🟢 第 4 步:后续所有包都走新路径

之后服务端发包:

peer->endpoint → 新 IP/Port  

旧路径自然失效。


四、为什么这样做是安全的?

关键在于这条铁律:

只有能通过 Noise 认证的包,才有资格更新 endpoint

也就是说:

  • ❌ 伪造源 IP 不行(解不开)
  • ❌ 猜端口不行
  • ❌ 重放旧包不行(counter / replay window)

五、代码层面的“无感知”来源

1️⃣ 查找 peer 不靠 IP

核心路径:

wg_receive_handshake_packet()  
wg_receive_data_packet()  

它们最终都是:

→ 根据 key 找 peer  
→ 而不是根据 src IP  

2️⃣ endpoint 更新是“副作用”

你可以理解为:

“如果你能证明你是谁,  
那你现在从哪来我就信”  

所以 endpoint 更新只是:

  • 一次 memcpy
  • 一次 RCU-safe 更新
  • 不影响 fast path

3️⃣ Keepalive 的真实意义

很多人误解 keepalive 是“保活连接”。

实际上它是:

NAT 穿透 + endpoint 探测包

  • 保证 NAT 映射不消失
  • 确保对端知道“我现在在哪”

六、为什么 TCP VPN 做不到?

因为 TCP:

  • ✅ IP/Port 是连接五元组的一部分
  • ❌ IP 变了 = 连接必断
  • ❌ NAT 变化 = RST / timeout

WireGuard:

  • ✅ UDP 无连接
  • ✅ 自己在加密层维护“逻辑会话”
  • ✅ 会话 ≠ 传输路径

七、几个非常重要的边界条件(容易踩坑)

⚠️ 1. 双方都在 NAT 后面?

  • ❌ 无法首次建立连接
  • ✅ 但一旦建立,双方 roaming 都没问题
  • 解决方案:中继 / 固定一端公网

⚠️ 2. 长时间完全静默?

  • NAT 映射过期
  • 下一包可能丢
  • PersistentKeepalive 就是为这个准备的

⚠️ 3. 同一 peer 同时从两个 IP 发包?

  • WireGuard 最后一个成功认证的 endpoint 生效
  • 不是负载均衡
  • 是“单活”

八、一句话总结“无感知恢复”的本质

WireGuard 把“身份”和“路径”彻底解耦了。

  • 身份:公钥(不可伪造)
  • 会话:Noise state
  • 路径:随时可变、随时学习

所以:

IP/Port 变化不是异常,只是一次新的事实被观察到。