自动网络:建连流水线
当前状态
M1 在 Linux 上实现了这条流水线的主干:认证、端点探测、打洞对时、中继先行、按探测结果选路。 测试里用 Linux 模拟了两种 NAT:普通 NAT 后面打洞成功,对称 NAT 后面回退中继。 还没有的:局域网组播探测(同一局域网的两个节点目前靠上报的局域网地址直连); 经协调服务的打洞还没在真实网络里(家用路由器、运营商的 NAT)验证过;不用服务器的直连模式在真实网络里打通过(两台用移动流量的手机,经公网 IPv6)。
两个素未谋面的节点,从接入到通信,要走完这六步:
下面逐步拆开。
1. 节点发现
新节点启动后向控制面注册,拿到网络里其他节点的清单:公钥、声明的能力、已知端点。
同时它在本地网段发一轮组播探测 —— 同一个局域网内的两台设备不该绕公网。 局域网直连的延迟通常在 1ms 以内,比任何穿透结果都好。
2. 身份认证
节点拿 WireGuard 用的那对静态密钥,和控制面跑一次 Noise IK 握手。 握手能完成,就证明它持有这把公钥对应的私钥;节点事先知道控制面的公钥,所以同一次握手也认证了控制面。
这里没有密码,也没有证书链。公钥就是身份, 和 WireGuard 数据面用的是同一对密钥 —— 认证通过的那一刻,加密通道的材料也已经就位。
为什么不是"用私钥对挑战签名":WireGuard 的密钥是 X25519,只能做密钥交换,不能直接签名。 取舍见威胁模型。
3. NAT 穿透
最难的一步。目标是让两个都在 NAT 后面的节点,各自在自己的 NAT 上打出一个可用的映射。
第一步是搞清楚自己在公网上长什么样。 节点向控制面的探测端点发包, 对方回报"我看到你来自 1.2.3.4:51820"。对多个探测点重复这个过程,就能推断出 NAT 的行为:
| NAT 类型 | 外部端口行为 | 打洞难度 |
|---|---|---|
| 全锥形 / 受限锥形 | 同一内部端口 → 固定外部端口 | 容易 |
| 端口受限锥形 | 同上,但要求先向对方发过包 | 中等 |
| 对称型 | 每个目标地址用不同外部端口 | 困难,端口需要预测 |
第二步是对时。 控制面同时通知双方"现在向对方的这个端点发包"。 两边几乎同时发出的包,会在各自的 NAT 上凿出映射,于是后到的对方报文就能被放行。
双方都是对称型 NAT 时,打洞成功率会明显下降 —— 这种情况必须有第 5 步兜底。
M1 做到了哪
M1 还不做端口预测。测试里用 Linux 模拟了两种情况:两边都是端口受限锥形 NAT(家用路由器最常见的配置)时, 打洞成功;把其中一边换成对称型,打洞打不通,回退中继,照样能通。
4. P2P 建连
打洞成功后,把对端的 endpoint 写进 WireGuard 的 peer 配置,握手随即开始。
此后流量走设备之间的直接路径,不经过任何第三方。中继此时完全不参与,也不消耗带宽。
5. Relay 回退
打洞失败、或者还在尝试的过程中,流量先走中继。
需要强调的是回退的时序:连接不会先卡在打洞上,等超时了才退而求其次。 合理的做法是中继先行 —— 立刻经中继把连接建起来保证可用,打洞在后台继续尝试, 成功了再无缝切到直连。用户感知到的是"马上就通了",而不是"转了五秒圈"。
中继转发的是密文,见架构。
6. 路径选择
连接建立后,探测不会停。系统持续测量每条候选路径的:
- 延迟(RTT)
- 丢包率
- 抖动(延迟的稳定程度 —— 对游戏和语音比绝对延迟更重要)
- 可用带宽
然后据此选路。切换是无缝的:WireGuard 的会话绑定在密钥上,不绑在 IP 和端口上, 所以换路径不需要重新握手,上层的 TCP 连接也不会断。
网络变了怎么办
从 Wi-Fi 切到蜂窝网、笔记本合盖再打开、运营商重新分配地址 —— 这些都会让端点失效。
处理方式是把它当成流水线的一次局部重入:端点变化被检测到后, 节点重新走探测和穿透(第 3 步起),期间流量回落到中继,新的直连路径可用后再切回去。
对用户来说,整个过程应该是察觉不到的。这正是"自动网络"想兑现的承诺。
M1 做到了哪
测试里,两个节点在 NAT 后面打洞成功之后:
- 掐断两个 NAT 之间的 UDP:约 8 秒后两边回落中继;恢复后几秒切回直连。切换前后 ping 都通,也没有来回切
- 一边的路由器换了公网地址(运营商重新分配):这台机器经路由器的连接全断了。它重连协调服务、 重新探测到新的公网端点、重新打洞,十来秒后两边回到直连
- 一台机器换了网络(从一个路由器后面换到另一个后面,本机地址、公网地址全变了):它发现本机地址变了, 立刻重连协调服务、重新探测、重新打洞,约 8 秒后两边回到直连。它到中继的旧连接也死了, 靠保活发现、重连 —— 到协调服务和中继的连接都是 10 秒一次保活,25 秒听不到回音就重连, 不等 TCP 自己发现(那要十几分钟)
回落之前的那一小段里报文仍会丢。正在用的直连每 2 秒探测一次、连丢两次就算断,大约 3~4 秒; 本机换了网络则立刻切到中继,不等超时。离"察觉不到"还有距离,但比最早的 6.5 秒短了不少。 (这两条是后来加的,上面场景里的秒数是加之前量的。)
下一步:局域网联机:1.0.0 做什么 讲在这条流水线之上,游戏联机还要多过哪几关。