84 lines
10 KiB
Markdown
84 lines
10 KiB
Markdown
# SDD-003:随客户端分发 WireGuard 隧道组件
|
||
|
||
| 字段 | 内容 |
|
||
|---|---|
|
||
| 版本 / 变更级别 | 0.1 / S3(系统隧道、路由、DNS 与特权执行) |
|
||
| 设计状态 | Draft,已核对本地实现与 opsxdb / opsxapi 的桌面打包方式 |
|
||
| 实现状态 | 已引入可打包 Go 版标准 WireGuard 无特权探针和显式启停的本机 SOCKS5 模式;系统 TUN/路由/DNS 尚未完成 |
|
||
| 负责人 / 日期 | opsx-vpn / 2026-10-21 |
|
||
| 关联需求 | 企业员工安装 OpsX VPN 即可拨号,无需 Homebrew 或手动安装 wireguard-tools |
|
||
| 批准状态 | 用户已要求先评估设计后开发;具体平台发布签名尚待配置 |
|
||
|
||
## 1. 背景、目标与范围
|
||
|
||
- **当前行为与证据**:`client/src-tauri/src/tunnel.rs` 使用本机 `wg-quick` 创建接口,macOS 通过管理员授权执行,Linux 依赖 `pkexec`;`system.rs` 只检查工具位置;Windows 返回未实现。`client/src-tauri/tauri.conf.json` 未打包隧道组件。`../opsxdb/src-tauri/tauri.conf.json` 使用 `externalBin` 打包 Go sidecar,`../opsxdb/run.sh` 按目标 triple 复制二进制;`../opsxapi/src-tauri/src/lib.rs` 则在 Rust 内直接实现网络业务。两者均未实现 VPN 特权 helper。现有 `docs/specs/SDD-002-desktop-wireguard-client.md` 中普通拨号用户和设备 API 已进入第二阶段,目标 OS 的真实握手仍待验。
|
||
- **目标**:Rust 保持唯一的客户端控制面及本机私钥拥有者;按 OS 引入可随应用签名分发的隧道执行层。macOS 优先;用户不必安装 Homebrew 或 WireGuard 命令。Linux 复用内核 WireGuard,但打包必要工具与权限策略;Windows 使用专门的 Windows WireGuard 驱动/服务方案,不把 macOS 的 Go TUN 实现当通用驱动。
|
||
- **本轮实施边界**:实现可打包的 Go 用户空间 WireGuard netstack 探针和明确标注的本机 SOCKS5 应用代理;Rust 执行层仍明确报告系统工具依赖。完成可签名的特权 helper、路由/DNS 回滚和目标 OS 握手验收之前,不能在 UI 上宣称已实现免依赖系统拨号。
|
||
- **保留行为**:普通用户认证、设备公钥注册、配置领取及服务端 WireGuard UDP 协议不改;前端不接收私钥,服务端不接收客户端私钥。
|
||
|
||
## 2. 需求与约束
|
||
|
||
- FR-01:启用免安装分发通道的发布版仅在安装包内存在**正确目标架构、可校验版本**的隧道组件且系统适配就绪时报告“内置引擎就绪”;缺失时应明确报错,绝不悄悄运行 PATH 中同名程序。当前过渡版明确标记为“系统工具模式”,不得作为免安装版分发。
|
||
- FR-02:开发模式仍可使用系统 `wg-quick`,并明确标记为“系统工具模式”;二者的就绪检测和实际连接路径必须一致。
|
||
- FR-03:随包组件只接受固定动作及受约束的本机配置路径,不接受来自 WebView 的任意命令或路径;日志不可含私钥、令牌、完整配置。
|
||
- FR-04:macOS 正式接入必须完成受控提权、TUN、路由与 DNS 原值保存和恢复;授权取消、进程崩溃、升级或断开均须保持可恢复性。系统辅助程序的签名与安装按目标发行证书验收。
|
||
- FR-05:Windows/Linux 按各自系统 API 和权限交付;未验收的平台应明确“尚不支持内置隧道”,不能用模拟连接替代。
|
||
- NFR-01:正式发布不得从远程地址动态下载可执行文件、不得通过 shell 插入远端配置、不得使用旧飞连魔改 WireGuard 协议。
|
||
- NFR-02:非管理员安装包、系统提权、代码签名、升级与卸载必须分别测试;不能将可执行文件放进用户可写目录再让 root 执行。
|
||
|
||
## 3. 架构与方案
|
||
|
||
```text
|
||
React → Tauri invoke → Rust(登录、设备私钥、连接状态)
|
||
├─ 开发过渡:系统 wg-quick
|
||
└─ 发布引擎:签名的特权隧道组件
|
||
├─ macOS:WireGuard Go 引擎 + 受控网络配置/恢复
|
||
├─ Linux:内核 WireGuard + 受控配置服务
|
||
└─ Windows:WireGuardNT/官方隧道服务适配
|
||
```
|
||
|
||
- 参考 opsxdb 的按 triple 构建与 Tauri `externalBin`,**不复用**它开放 HTTP 端口的后端模型;隧道组件无需监听 TCP 端口,特权边界必须固定动作、受限 IPC 和签名校验。opsxapi 证明纯 Rust 控制面足够,不必把登录 API 搬进 Go。
|
||
- 采用标准上游 WireGuard 协议。`wireguard-go` 是用户空间引擎,不能单独完成 route/DNS/提权,必须由系统适配器完成,且需单独审查依赖版本与许可证。严禁直接移植 `PinkD/wireguard-go` 的私有扩展。
|
||
- `client/tunnel-go` 当前通过 `netstack.CreateNetTUN` 实现数据面探针,Rust `client_probe` 只对已登录用户的本机设备记录发起固定公共 TCP 目标 `1.1.1.1:443` 的连接。此模式能在无需管理员权限时检查端到端握手与网关出口;不提供系统 VPN 路由,不能作为“已连接”状态依据,也不能静默读取记录自动运行。
|
||
- 测试专线 `opsx-client-pilot` 当前给该设备下发的 `AllowedIPs` 为 `10.88.0.0/24`;服务器 `net.ipv4.ip_forward=1`,公网验证使用的临时 NAT 规则已清理。正常公网使用前需要由管理员明确更新该专线的客户端授权路由并持久化对应网段及出口网卡的 NAT。
|
||
- 本机代理固定监听 `127.0.0.1:18743`,只接受 SOCKS5 CONNECT;由 VPN 网络栈解析域名,并按服务器下发的 AllowedIPs 逐目的地址校验。前端明确显示只有配置了此代理的应用才经过 VPN;退出登录或退出应用时停止进程。此代理在本机回环端口没有额外认证,设备上的其他本地进程也可使用它,正式发行前应评估本机进程间隔离要求。
|
||
- **顺序**:先实现选择器和构建/验证契约,区分内置和系统工具;再建立 macOS 受限 helper 与网络快照/恢复;真机完成全隧道及分流、DNS、睡眠/唤醒、异常退出与真实握手;随后分别实现 Linux/Windows。未通过门槛前保持现有模式并显示准确的依赖信息。
|
||
|
||
## 4. 接口、数据与配置契约
|
||
|
||
- `get_system_readiness` 向前兼容既有 `platform/wg_found/wg_quick_found`,新增 `engine_mode`(`bundled` / `system_tools` / `unsupported`)及可读 `engine_detail`;由 Rust 而非 UI 决定。`bundled` 仅可在实际引擎、权限和系统配置均通过验收后返回。
|
||
- 内置组件的目标 triple 路径和版本由构建产物显式声明;发布流程核对哈希、签名和可执行权限。不能从用户可写数据目录或 PATH 寻找发布 helper。
|
||
- 服务端 API、数据库及客户端设备密钥数据模型不变;未来 helper 通过最小化本地 IPC 收到连接参数,不接触用户口令或管理令牌。
|
||
|
||
## 5. 风险与验收
|
||
|
||
| 风险或失败场景 | 防护 / 降级 / 恢复 | 可观察信号 |
|
||
|---|---|---|
|
||
| Go 引擎已启动但没有路由/DNS | 连接前检查系统适配就绪;握手只说明对端通信,不代表全隧道可用 | 界面报告未完成的阶段,路由/DNS 实测 |
|
||
| 提权执行用户替换的二进制 | 验证签名,固定安装路径与所有权,不在用户数据目录执行 | 签名/权限校验失败,拒绝连接 |
|
||
| 崩溃残留默认路由或 DNS | 启动前快照、事务回滚、下次启动修复 | 异常结束后系统路由/DNS 与原值一致 |
|
||
| 三平台能力误报 | 平台分别发布和验收;未支持者显示真实原因 | 每平台独立安装和断开报告 |
|
||
|
||
| AC | 对应需求 | 前置条件与操作 | 预期结果 | 验证方式 | 结果 |
|
||
|---|---|---|---|---|---|
|
||
| AC-01 | FR-01, FR-02 | 无 Homebrew 的 macOS 打开当前过渡版/未来免安装版 | 过渡版明确显示依赖;免安装版仅在组件和权限实际就绪时显示内置可用 | 单测、构建、真机 | 当前过渡版选择器单测通过;免安装版 Not Run |
|
||
| AC-01a | FR-01, NFR-01 | 构建固定版本 Go 组件,输入授权路由内/外目标 | 仅支持授权内目标,不输出密钥,打包客户端可定位正确架构组件 | Go 单测、构建和实际出口探测 | Go 单测、macOS arm64 构建、临时授权公网出口与 SOCKS5h 网页请求通过;正式安装包签名 Not Run |
|
||
| AC-02 | FR-03, NFR-01/02 | 尝试替换组件、传非法路径、控制字符 | 拒绝执行,机密不记录 | 隔离测试、签名检查 | Not Run |
|
||
| AC-03 | FR-04 | macOS 连接、断开、撤销授权、强制退出及重启 | 真实握手;路由/DNS 保持或恢复 | 两台目标机人工/自动验收 | Not Run |
|
||
| AC-04 | FR-05 | Windows/Linux 干净系统安装、拨号、卸载 | 无独立工具安装步骤,未支持平台不假装就绪 | 各平台测试 | Not Run |
|
||
|
||
## 6. 发布与恢复
|
||
|
||
- 第一阶段仅交付设计与隔离执行层的基础代码,不默认启用内置模式;持续提供现有 `wg-quick` 开发通道。切换正式引擎前收集目标架构及代码签名资料。
|
||
- 2026-10-21 用户明确授权后,使用 0600 临时设备配置将 AllowedIPs 扩为全路由,在服务器仅为 `10.88.0.0/24` 添加临时出口 NAT;Go 数据面实际连接 `223.5.5.5:443` 成功,通过 SOCKS5h 获取 `http://www.baidu.com` 返回 HTTP 200。原始设备记录仍只允许 `10.88.0.0/24`;验证后已删除唯一带 `opsx-vpn-wg4-pilot` 标记的临时 NAT 规则。服务器自身访问 `1.1.1.1:443` 也超时,客户端探测目标改为可达的 `223.5.5.5:443`。这些验证不证明系统 VPN 或路由/DNS 恢复完成。
|
||
- 先在独立试验机测试安装与签名,再验证路由/DNS 回滚与握手,然后分批发版;不能仅靠 `cargo check` 或浏览器预览宣称可分发。
|
||
- 出现网络配置残留时用保存的系统快照恢复并停用有问题的组件;保留旧安装包与开发模式供排障。服务端不变,无数据库回滚。
|
||
|
||
## 7. 待决问题
|
||
|
||
| 问题 | 是否阻塞 | 推荐方案 |
|
||
|---|---|---|
|
||
| macOS Developer ID、Network Extension entitlement 与签名/公证资源 | 阻塞 macOS 正式分发 | 评估上游官方 WireGuardKit/Network Extension 与 Go helper 两条路线;以能稳定签名、恢复网络为准 |
|
||
| 目标平台与架构矩阵 | 阻塞跨平台正式验收 | 先 macOS arm64,再 macOS x86_64、Linux、Windows 分别验收 |
|
||
| Go helper 许可证、依赖锁定及安全更新 | 阻塞打包发布 | 固定上游 tag/模块校验和、生成第三方许可清单、随应用更新 |
|