我们来深入讲解一下 Tailscale 的源码。这是一个非常优秀的项目,代码质量很高,结构清晰,是学习 Go 语言、网络编程和系统设计的绝佳范例。

我会从高到低,分层次地为你解析这个项目。

1. 核心思想与技术栈 (The Big Picture)

在深入代码之前,先理解 Tailscale 是什么,以及它解决了什么问题。

  • 它是什么? Tailscale 是一个“零配置 VPN”(Zero-config VPN)。它基于 WireGuard® 协议,为你所有的设备(电脑、手机、服务器等)创建一个安全、扁平的私有网络,无论这些设备身处何方。

  • 核心优势?

    1. 简单易用:不需要复杂的防火墙配置、证书管理和 IP 地址规划。通过 SSO(如 Google, GitHub)登录即可。

    2. 点对点连接:尽可能在设备之间建立直接的加密连接,延迟低、速度快。

    3. NAT 穿越:这是 Tailscale 的技术精髓之一。它能神奇地穿透大多数家庭/公司路由器和防火墙,实现设备间的直接通信。

    4. 身份认证:它不是基于传统的 IP 地址或密钥文件来认证,而是基于你的身份(Identity Provider)。

  • 技术栈

    • 语言:绝大部分代码使用 Go 语言编写。这使得它天生具备高并发、跨平台和优秀的网络库支持。

    • 核心隧道协议WireGuard。Tailscale 负责自动化的密钥交换、配置和连接管理,而底层的加密和隧道传输则完全依赖 WireGuard。

    • NAT 穿越:使用 STUN 协议和自定义的 DERP(Detoured Encrypted Routing Protocol)协议。

2. 项目架构:三大组成部分

Tailscale 的系统可以分为三个主要部分:

  1. 客户端 (Client):就是你在 github.com/tailscale/tailscale 这个仓库里看到的主要代码。它运行在你每一台设备上,通常以后台服务/守护进程(tailscaled)的形式存在。

  2. 协调服务器 (Coordination Server / Control Plane):这是 Tailscale 的“大脑”。它是一个中心化的服务,这部分代码是闭源的,不包含在这个 GitHub 仓库里。它负责:

    • 用户认证(通过 Google, Microsoft, GitHub 等)。

    • 公钥交换。

    • 网络拓扑管理(生成“网络地图” Netmap)。

    • 分发 IP 地址(在 100.x.x.x CGNAT 地址空间内)。

    • 协调 NAT 穿越。

    • 注意:开源社区实现了一个兼容的协调服务器叫 Headscale,可以用于自建。

  3. DERP 中继服务器 (Relay Servers):当两个设备无法建立点对点连接时(例如在严格的对称 NAT 后面),它们的流量会通过 DERP 服务器进行加密中继。DERP 服务器是全球分布的,其代码是开源的,就在这个仓库的 derp/ 目录下

关键交互流程:你的设备上的客户端 (tailscaled) 只会和协调服务器交换控制信息(公钥、IP 等),而数据流量会尝试直接点对点传输。只有在直连失败时,数据流量才会走 DERP 中继服务器。所有数据流量始终是端到端加密的,协调服务器和 DERP 服务器都无法解密你的流量。


3. 源码目录结构导览 (Diving into the Code)

现在我们来看 github.com/tailscale/tailscale 这个仓库的核心目录:

cmd/ - 入口程序

这是所有可执行文件的入口。Go 项目的标准布局。

  • cmd/tailscale/:命令行工具 tailscale 的源码。这是用户交互的前端,它通过本地 IPC 与后台的 tailscaled 进程通信。例如,你运行 tailscale up 或 tailscale status,就是这个程序在工作。

  • cmd/tailscaled/:核心的守护进程 tailscaled 的源码。这是 Tailscale 的心脏,它在后台持续运行,负责管理 WireGuard 接口、与协调服务器通信、处理 NAT 穿越等所有核心逻辑。

  • cmd/derper/:DERP 中继服务器的源码。如果你想自己搭建一个 DERP 服务器,就会用到它。

ipn/ - 核心状态机与后端逻辑

ipn 代表 "Inter-Process Networking"(进程间网络)或者 "IP-level Networking"。这是客户端的核心逻辑层状态管理

  • 它定义了客户端的状态(如 Running, Starting, Stopped)。

  • 处理来自协调服务器的指令(比如更新网络地图 Netmap)。

  • 管理偏好设置(如是否接受子网路由、是否作为出口节点等)。

  • 它是 tailscaled 和具体平台实现之间的桥梁。

wgengine/ - WireGuard 引擎

这是对 WireGuard 的封装层。Tailscale 需要在不同的操作系统上与 WireGuard 交互(有的是内核模块,有的是用户态实现),这个目录就是为了提供一个统一的接口。

  • wgengine/router/:负责配置操作系统的路由表,将发往 Tailscale IP 的流量导入 WireGuard 隧道。

  • wgengine/netstack/:一个非常酷的部分。它集成了一个用户态网络协议栈 (gvisor/netstack)。这使得 Tailscale 可以在不获取管理员权限的情况下,通过拦截特定应用的流量来工作(例如 tailscale ssh)。

net/ - 网络魔法的聚集地

所有与网络连接、NAT 穿越相关的底层代码都在这里。

  • net/stun/:STUN (Session Traversal Utilities for NAT) 协议的实现。tailscaled 用它来向 STUN 服务器发送请求,以发现自己在外网的公网 IP 和端口。

  • net/derp/:DERP 协议的客户端和服务器端实现。这是 Tailscale 的备用方案。如果 STUN 失败,流量就通过它来中继。

  • net/dns/:MagicDNS 的实现。它负责拦截 DNS 请求,并将 *.ts.net 格式的域名解析为对应的 Tailscale IP 地址。

  • net/netcheck/:网络状况探测。客户端启动时,它会运行一系列检查,探测网络的类型、是否支持 Hairpinning、IPv6 等,并将报告发送给协调服务器,以便更好地进行 NAT 穿越。

control/ - 与协调服务器的通信

这是客户端与协调服务器通信的客户端实现。

  • 它负责使用 Noise 协议(和 WireGuard 使用的加密协议同源)与协调服务器建立一个安全的长时间连接。

  • 通过这个连接,客户端进行登录、发送公钥、上报网络状况,并接收协调服务器下发的网络地图 (Netmap)。

  • 注意:这里是客户端代码,不是服务器代码。

tsnet/ - 将 Tailscale 嵌入你的应用

这是一个非常强大的库。它允许你将整个 Tailscale 网络栈直接嵌入到你的 Go 应用程序中。你的应用程序不需要 tailscaled 在后台运行,就可以直接监听一个 Tailscale IP 地址,或者连接到你私有网络中的其他服务。这对于构建安全的内部服务非常有用。

types/ - 公共数据结构

定义了整个项目中广泛使用的核心数据结构。

  • netmap/ (types/netmap/netmap.go): 定义了 NetMap 结构。这是协调服务器下发的最重要的数据,包含了你网络中所有节点(Peers)的公钥、IP 地址、允许的 IP、DERP 区域信息等。tailscaled 根据这个“地图”来配置 WireGuard。

  • key/:定义了各种类型的密钥(公钥、私钥等)。


4. 一个典型的连接流程 (Putting It All Together)

为了更好地理解代码是如何协同工作的,我们来看一下当一个新设备 tailscale up 时发生了什么:

  1. 启动与认证 (cmd/tailscale, cmd/tailscaled, control/)

    • 用户运行 tailscale up。

    • tailscale CLI 程序通过 IPC 通知后台的 tailscaled 守护进程。

    • tailscaled 生成一对新的公私钥。

    • tailscaled 中的 control 客户端向协调服务器发起连接,并发送一个登录请求。

    • 协调服务器返回一个认证 URL。CLI 将此 URL 显示给用户。

    • 用户在浏览器中打开 URL,通过 Google/GitHub 等登录。

    • 登录成功后,协调服务器将 tailscaled 的公钥与用户的身份关联起来。

  2. 获取网络地图 (control/, types/netmap/)

    • 认证成功后,tailscaled 会收到协调服务器下发的 NetMap。

    • 这个 NetMap 包含了网络中所有其他设备的信息:它们的公钥、已知的公网 IP(Endpoint)、允许的 DERP 区域等。

  3. 配置 WireGuard (wgengine/)

    • tailscaled 解析 NetMap。

    • 它调用 wgengine,使用自己的私钥和网络中其他设备(Peers)的公钥来配置本地的 WireGuard 接口(tailscale0)。

    • 同时,wgengine/router 会配置系统的路由表,将流向 100.x.x.x 地址段的流量都指向 tailscale0 接口。

  4. 建立点对点连接 (net/netcheck/, net/stun/, net/derp/)

    • 现在,假设你想 ping 你的另一台设备 peer-B。

    • 你的设备 peer-A 的 tailscaled 从 NetMap 中查找 peer-B 的信息。

    • peer-A 会并行地尝试多种方式联系 peer-B:

      • 直接向 peer-B 在 NetMap 中记录的所有已知 IP 地址(内网 IP、公网 IP)发送加密的 WireGuard 握手包。

      • 如果直连失败,peer-A 和 peer-B 都会通过 STUN 协议发现各自的公网 IP 和端口,并将这些新发现的“候选地址”报告给协调服务器。协调服务器再将这些地址广播给网络中的其他节点。然后双方会根据这些新的地址再次尝试直连。这个过程就是 NAT 穿越。

      • 如果所有直连尝试都失败了,peer-A 会将加密的 WireGuard 数据包封装在 DERP 协议里,发送给离它最近的 DERP 中继服务器。DERP 服务器再将数据包转发给 peer-B。

  5. 通信

    • 一旦路径建立(无论是直连还是通过 DERP),两台设备之间的 WireGuard 隧道就打通了。

    • 所有后续流量都在这个加密隧道中传输,实现了安全通信。

总结

  • 核心是 tailscaled:这个守护进程是所有逻辑的中心。

  • 分层清晰:cmd (入口) -> ipn (状态机) -> wgengine (隧道) / control (控制) / net (连接)。

  • NAT 穿越是关键技术:net/stun 和 net/derp 是 Tailscale 能够在复杂网络环境下工作的“魔法”所在。

  • 控制平面与数据平面分离:协调服务器只处理元数据和信令,不碰用户流量,保证了性能和隐私。

如果你想开始阅读代码,我建议从 cmd/tailscaled/main.go 开始,然后跟进到 ipn 包和 wgengine 包,这会让你对它的核心运作有一个很好的了解。

Logo

有“AI”的1024 = 2048,欢迎大家加入2048 AI社区

更多推荐