Tailcat:不要 Tailscale 控制面的点对点加密管道
阅读时间: 大约 11 分钟
Tailcat:不要 Tailscale 控制面的点对点加密管道

如果你用过 Tailscale,大概熟悉那种体验:两台机器隔着 NAT,却像在同一个局域网里直连。但 Tailscale 的完整形态需要账号、需要登录控制面、需要在机器上装常驻代理、有时还需要管理员权限。Tailscale 在 2026 年 8 月的 TailscaleUp 大会上开源的 Tailcat,则把这套体验做了一次”减法”:口号是”Tailscale without Tailscale, by Tailscale”——只用它的数据面,不要它的控制面,工具形态退回成 netcat。本文基于官方 GitHub README,拆解它到底是什么、怎么工作、边界在哪。
一、它是什么:netcat,但跑在 WireGuard 加密隧道上
Tailcat 是 Tailscale 开源组件的一次 remix:行为像 netcat,但跑在 Tailscale 的数据面上。具体说:
- 数据面用 Tailscale 内部的 magicsock,在两台机器之间建立 点对点 WireGuard 加密隧道;
- DERP 服务器承担两件事:NAT 打洞时的通信旁路,以及打洞失败时的最终中继;
- 不连 Tailscale 控制面:所有连接元数据都带在一条短地址里,“带外交换”——你想怎么传都行。
一端跑 server(监听者),会吐出一个短 tailcat 地址;另一端把这个地址交给 client 即可连接。两端之间的流量全部由 WireGuard 端到端加密。初始引导走 DERP,随后 magicsock 做 NAT 穿透,成功后”通常”会升级成直接的点对点 UDP 连接。
它不需要 Tailscale 账号、不需要 root/管理员权限、也不改你机器的路由表和 DNS——它只是一个用户态库和 CLI。协议为 BSD-3-Clause。
二、技术栈:四个 Tailscale 组件的用户态拼装
README 的”How it works”把复用的组件列得很清楚:
- WireGuard(用户态实现):加密隧道全部流量。它不使用内核 TUN/TAP 设备,也不配置任何网络路由,因此不需要 root;
- magicsock:Tailscale 的传输层,把流量多路复用在直连 UDP 与 DERP 中继上,负责基于 STUN 的端点发现和 UDP 打洞;
- Netstack(gVisor):一个用户态 TCP/IP 协议栈,在进程内终结 TCP 连接——这正是它能在不做任何操作系统网络配置的情况下 accept 入站、dial 出站的关键;
- DERP 中继:Tailscale 的加密中继协议,用作会见过点和直连失败时的兜底数据通路。
一条 tailcat 地址长什么样? 形如 tcXYZ...,是 "tc" 前缀加 base64 编码的 CBOR 结构,内含:服务器的 WireGuard 公钥(Curve25519,32 字节)、一个独立的路径发现公钥(Curve25519,32 字节)、默认开启的独立 WireGuard 预共享密钥(256 随机位),以及 DERP 信息。只引用一个区域编号的典型地址约 140 字节。
连接流程也写得很直白:server 启动后生成/加载密钥、连上 DERP、打印地址等待;client 解析地址拿到公钥与 PSK、生成自己的临时密钥、连到同一个 DERP;client 通过 DERP 发一个 “Meow” 握手消息,server 回 “Meowed” 确认;双方配成 WireGuard 邻居后隧道建立;与此同时两边通过 DERP 互告自己的 UDP 端点(STUN 学到的公网地址 + 本地地址),打洞成功就把流量从 DERP 升级到直连 UDP,失败则 DERP 继续兜底。
三、能干什么:从管道到 SSH、文件传输
CLI 的能力面相当宽:
| 命令 | 作用 |
|---|---|
tailcat / tailcat <addr> | 两端 stdin/stdout 直接互通(netcat 本体) |
tailcat serve 8080,8443 | 把本机端口暴露进隧道 |
tailcat forward <addr> 18080:8080 | 把隧道对端端口映射成本地端口 |
tailcat browse <addr> | 自动开浏览器访问隧道后的 Web 服务 |
tailcat serve ssh / no-auth-ssh | 跑一个 SSH 服务端(可要求公钥,或仅凭隧道身份) |
tailcat serve exec -- cmd | 像 inetd 一样,每条连接跑一条命令 |
tailcat recv / cp / ls | 基于 SFTP 的收文件、发文件、列目录 |
tailcat socks <addr> curl ... | 把命令挂到隧道里的 SOCKS5 代理 |
tailcat serve exit-node | 当出口节点,让 client 访问 server 所在网络 |
tailcat perf <addr> | 类 iperf 打吞吐、测延迟 |
官方给出的一个 perf 示例很有代表性:直连路径 rtt 1.2ms,单向 10 秒打了 1.18 GB、约 943 Mbit/s;而经 DERP(sfo) 中继的 ping 是 42.1ms。需要强调:这是官方示例输出,不是跨机型的基准。
此外它还提供一个编译成 WebAssembly 的浏览器演示(tailscale.github.io/tailcat),可以在网页里直接收发文件或文本,并与 CLI 互通。但 README 明确说明:浏览器流量目前只走 DERP 中继,在 WebRTC 支持落地之前做不了直连 P2P。
四、密钥与安全:地址即凭证
Tailcat 的安全模型有几个值得专门点出的设计:
- 默认临时密钥:每次 server 运行都在内存里生成新密钥、打印一个没人见过的地址;进程退出,密钥即销毁、地址永久失效。这是安全默认值;
genkey保存密钥:地址可在重启间保持稳定,但代价是——任何你曾经分享过该地址的人,将来都能用这把密钥连上来,除非你用--allow限制客户端节点公钥;- PSK 默认开启:256 位预共享密钥让观察到双方公钥的 DERP 运营者也无法加入隧道,并提供对抗”录流量等量子计算”的后量子保护;
--psk=false会关掉它; no-auth-ssh的地址就是密码:官方反复警告——这种模式下谁拿到地址谁就能拿到一个 shell,绝不能发到公开的 DNS TXT 记录里;- DNS TXT 发布地址必须配客户端鉴权:把地址写进公开 TXT 记录后,“知道地址”不再证明身份,server 必须用
--allow或--ssh-authorized-keys自己认证 client。tailcat ssh还会先用一把全新匿名密钥试探登录一次,发现 server 不鉴权就主动拒绝连接,避免你把 shell 暴露到公网。
五、客观优势与局限
优势:
- 零账户、零 root、零常驻:单二进制/用户态库,不改路由表和 DNS,这在临时跨机传文件、临时反向暴露一个本地端口时体验非常轻;
- 端到端加密 + 自动打洞:WireGuard 加密、DERP 兜底,NAT 后两台机器也能打通,且直连成功后吞吐可达近 Gbps 量级;
- 地址即配置、可带外分享:不需要先约定一个控制面,把
tc...贴给对方即可; - 可自托管一切:DERP 中继可以自己跑,连默认 DERP map 都能换成自己的 JSON,不再依赖 Tailscale 的共享中继。
局限与官方口径:
- 无 SLA 承诺:官方明说公共 DERP 中继有限速、无 uptime SLA、可能随时被撤销;Go API、CLI 参数和线上格式都不保证稳定;
- 浏览器端只能中继:WASM 演示在 WebRTC 落地前无法直连,吞吐受限于共享中继;
- 文件传输不压缩:SFTP 协议本身无压缩,Go 的 SSH 栈也不做传输层压缩(官方称历史上传输压缩安全问题多、TLS 也已弃用),要省带宽得自己先压;
- 地址保密负担在用户身上:默认地址是一个”秘密的能力凭证”,一旦公开且没有
--allow/公钥鉴权,等于把入口拱手送人; - 它是点对点工具,不是 Tailscale 网络:没有 tailnet 那样的设备清单、ACL 集中管理、多设备编排,定位是”两台机器之间的一根加密管子”。
六、适合谁用
- 临时跨机传文件/开管道:不想开端口、不想配 SSH 隧道、不想装 Tailscale 客户端时,一条命令即可;
- 把本地服务临时暴露给指定的人:配合
--allow客户端公钥,做成”凭地址+密钥才能进”的反向暴露; - 嵌入 Go 程序:作为库 import 进来,给你的应用加一条”无需控制面的加密 outbound/inbound 通道”;
- 想体验/研究 Tailscale 数据面:它是少有的、可以单独阅读 magicsock+DERP+用户态 WireGuard 拼装方式的开源样本。