Refine WireGuard client routing and authentication UI
This commit is contained in:
1 parent
eabb3e4472
commit
41fb9d5631
33 files changed
+1709
-469
No files matched your search
@@ -2,27 +2,28 @@
|
||||
|
||||
| 字段 | 内容 |
|
||||
|---|---|
|
||||
| 版本 / 变更级别 | 0.1 / S3(系统隧道、路由、DNS 与特权执行) |
|
||||
| 版本 / 变更级别 | 0.3 / S3(内置 Go 系统隧道、路由、DNS 与特权执行) |
|
||||
| 设计状态 | Draft,已核对本地实现与 opsxdb / opsxapi 的桌面打包方式 |
|
||||
| 实现状态 | 已引入可打包 Go 版标准 WireGuard 无特权探针和显式启停的本机 SOCKS5 模式;系统 TUN/路由/DNS 尚未完成 |
|
||||
| 实现状态 | Go 探针、SOCKS5 与 macOS 原生 `utun` 数据面、Rust 受限子进程桥接代码已实现;系统工具调用路径已移除,内置直连尚不可用;拨号用户可自动登记至代理启动;macOS 系统 SOCKS 开关已实现,真机验收待办;系统接口地址/路由/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 的真实握手仍待验。
|
||||
- **当前行为与证据**:`client/src-tauri/src/tunnel.rs` 只管理本机密钥与设备记录;此前的 `wg-quick` 执行和 PATH 检测已按用户要求移除。`system.rs` 在特权网络服务完成前始终报告直连未就绪;Go 探针及应用代理仍可用。`client/src-tauri/tauri.conf.json` 打包 Go sidecar;`../opsxdb/src-tauri/tauri.conf.json` 使用 `externalBin` 打包 Go sidecar。现有 `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 上宣称已实现免依赖系统拨号。
|
||||
- **本轮实施边界**:保留可打包的 Go netstack 探针与本机 SOCKS5 应用代理;客户端不再执行系统 WireGuard 命令。完成特权 helper、路由/DNS 回滚和目标 OS 握手验收之前,UI 只报告内置直连未就绪。
|
||||
- **保留行为**:普通用户认证、设备公钥注册、配置领取及服务端 WireGuard UDP 协议不改;前端不接收私钥,服务端不接收客户端私钥。
|
||||
|
||||
## 2. 需求与约束
|
||||
|
||||
- FR-01:启用免安装分发通道的发布版仅在安装包内存在**正确目标架构、可校验版本**的隧道组件且系统适配就绪时报告“内置引擎就绪”;缺失时应明确报错,绝不悄悄运行 PATH 中同名程序。当前过渡版明确标记为“系统工具模式”,不得作为免安装版分发。
|
||||
- FR-02:开发模式仍可使用系统 `wg-quick`,并明确标记为“系统工具模式”;二者的就绪检测和实际连接路径必须一致。
|
||||
- FR-01:启用免安装分发通道的发布版仅在安装包内存在**正确目标架构、可校验版本**的隧道组件且系统适配就绪时报告“内置引擎就绪”;缺失时应明确报错,绝不运行 PATH 中同名程序。
|
||||
- FR-02:所有模式均不调用本机 `wg` / `wg-quick`;内置网络服务未就绪时直连明确不可用,应用代理单独可用。
|
||||
- FR-03:随包组件只接受固定动作及受约束的本机配置路径,不接受来自 WebView 的任意命令或路径;日志不可含私钥、令牌、完整配置。
|
||||
- FR-04:macOS 正式接入必须完成受控提权、TUN、路由与 DNS 原值保存和恢复;授权取消、进程崩溃、升级或断开均须保持可恢复性。系统辅助程序的签名与安装按目标发行证书验收。
|
||||
- FR-05:Windows/Linux 按各自系统 API 和权限交付;未验收的平台应明确“尚不支持内置隧道”,不能用模拟连接替代。
|
||||
- FR-06:无系统工具的用户登录后可从概览启动 Go 应用代理:先校验最新线路授权、自动登记/刷新本机设备、使用实际 WireGuard 参数启动本机 SOCKS5。UI 必须将代理状态与整机 VPN 状态分开;退出、撤销设备、进程停止后不可仍报代理在线。
|
||||
- NFR-01:正式发布不得从远程地址动态下载可执行文件、不得通过 shell 插入远端配置、不得使用旧飞连魔改 WireGuard 协议。
|
||||
- NFR-02:非管理员安装包、系统提权、代码签名、升级与卸载必须分别测试;不能将可执行文件放进用户可写目录再让 root 执行。
|
||||
|
||||
@@ -30,8 +31,8 @@
|
||||
|
||||
```text
|
||||
React → Tauri invoke → Rust(登录、设备私钥、连接状态)
|
||||
├─ 开发过渡:系统 wg-quick
|
||||
└─ 发布引擎:签名的特权隧道组件
|
||||
├─ 当前:Go 应用代理;直连未就绪
|
||||
└─ 目标:签名的特权隧道组件
|
||||
├─ macOS:WireGuard Go 引擎 + 受控网络配置/恢复
|
||||
├─ Linux:内核 WireGuard + 受控配置服务
|
||||
└─ Windows:WireGuardNT/官方隧道服务适配
|
||||
@@ -46,9 +47,30 @@ React → Tauri invoke → Rust(登录、设备私钥、连接状态)
|
||||
|
||||
## 4. 接口、数据与配置契约
|
||||
|
||||
- `get_system_readiness` 向前兼容既有 `platform/wg_found/wg_quick_found`,新增 `engine_mode`(`bundled` / `system_tools` / `unsupported`)及可读 `engine_detail`;由 Rust 而非 UI 决定。`bundled` 仅可在实际引擎、权限和系统配置均通过验收后返回。
|
||||
### 无 `wg` / `wg-quick` 的 macOS 直连实现
|
||||
|
||||
- Go 子进程在用户权限下使用上游 `tun.CreateTUN("utun", mtu)` 创建接口、启动 WireGuard,并通过一次性 stdout 消息把系统分配的 `utunN` 回传 Rust;本机配置保持 0600。Go 子进程不能仅因为接口创建成功就报告已联网;Rust 完成 IP、路由、DNS 设置后才允许控制面查询真实握手。
|
||||
- 对照 `../demo/clash-verge-rev`:它的 `config/clash.rs` 为 Go 核心 Mihomo 配置 `tun.auto-route/auto-detect-interface/dns-hijack`,`core/service.rs` 由经管理员确认的安装器将核心发布到服务拥有的路径,再用受限 IPC 启动;`feat/tun.rs` 在服务未就绪时停用 TUN。其“rule/global”是 Mihomo 的流量策略,不等于 WireGuard 的 AllowedIPs。OpsX 不直接复用 Mihomo 的代理规则或服务 IPC 协议。
|
||||
- 其他参考边界:corplink-rs 的飞连私有协议字段不适用于本项目标准 WireGuard;Tailscale/NetBird 可以参考服务化与网络生命周期,但不能据此假设它们的路由/DNS 实现已经被本项目核对或移植;AmneziaWG-go 的混淆需服务端同时支持,当前服务端未采用该协议。本机只核对过 Clash Verge Rev 的源码,其他项目目前属于候选参考。
|
||||
- 已核对本地 `../demo/vpn/wireguard-go`(提交 `2631ce9`),与客户端 `go.mod` 锁定的上游模块版本一致。其 `tun/tun_darwin.go` 中 `CreateTUN("utun", mtu)` 让内核分配真实接口名,且可选环境变量 `WG_TUN_NAME_FILE` 会写文件;本项目禁用这一额外写入,仅通过 JSON 回传真实名称。其 `main.go` 用 `device.Wait`、终止信号和 `device.Close` 管理生命周期,但没有替应用设置地址、路由或 DNS;`device/uapi.go` 的 `IpcGet` 会包含私钥,必须在 Go 进程内过滤后才返回 Rust。
|
||||
- Go `tun` 命令仅在 macOS 运行,读取 0600 本机记录,创建接口后只输出 `interface_created` 和系统分配的 `utunN`;其标准输入仅接受 `status`、`stop`,关闭输入、父进程退出或接口关闭时终止。`status` 仅输出握手秒数与收发字节数,不透传包含私钥的 WireGuard UAPI 原文;首次接口事件**不是**握手或路由就绪。普通登录进程不得因为收到这个消息就更新 UI 为已连接。
|
||||
- `interface_created` 同时携带不含密钥的 IPv4 路由计划:先在原物理出口固定网关 endpoint `/32`(如果授权路由覆盖它),再按授权网段安装 TUN 路由;`0.0.0.0/0` 展开为两个 `/1`。域名 endpoint 在动路由前解析成一个 IP,WireGuard Device 使用同一个解析结果,防止多个 DNS 地址导致绕行规则与实际发送目标不一致。若需网关绕行,Go 在启动前只读调用 `/sbin/route -n get` 并提取物理接口和网关;已走 `utun`、无接口或格式非法则拒绝。此结果是快照,特权服务实际安装路由前仍须复核物理出口,防止检查后网络切换。当前只规划 IPv4,出现 IPv6 授权立即拒绝,不把未接管的 IPv6 流量误称为全局模式。仍需特权服务安全执行和恢复,此计划本身不会改变系统路由。
|
||||
- `client/src-tauri/src/native_tunnel.rs` 已能在 macOS 启动 Go 子进程、限制启动与查询等待时长、解析非机密计划与握手计数,断开或 Rust 对象销毁时终止子进程;字段在 Rust 侧再次校验。该模块先保持脱离 UI 的直连路径,待特权服务完成网络事务与恢复并通过握手/流量验收才启用,防止接口创建事件被 UI 当作可联网状态。
|
||||
- Rust 只允许经校验的 IPv4、合法 `utunN`、服务端 `AllowedIPs` 及固定动作传给受控系统服务;服务安装到管理员拥有的固定位置,验签/校验所有权,使用受限本地 IPC 更新路由和 DNS,不能从用户可写路径提权运行 Go 核心,也不通过临时拼接的 AppleScript/shell 命令充当发布版特权服务。专线 endpoint 需为物理网络出口保留路由,防止全局路由自吞。
|
||||
- 系统配置事务顺序:解析 endpoint 的实际地址并记录原物理出口与 DNS 状态;先持久化带有接口名和拥有者标识的恢复记录,再设置接口地址和路由、受控 DNS;核对网络栈实际状态、服务端新握手和授权目标连通性后才发布连接状态。全局路由应避开 VPN endpoint,网络切换时重新计算出口。若启动中途失败,按逆序恢复,只撤回自身仍持有的设置;恢复失败保留记录并提示人工修复,不覆盖后续第三方改动。服务重启时扫描自己的未完成事务并恢复。
|
||||
- 路由/DNS 变更前写入只属于本应用的恢复记录。部分失败立即回滚;断开、注销、设备撤销、Go 进程意外退出、应用退出或下次启动重试恢复,只清理与当前接口/目标一致的配置。恢复失败时明确报告,并阻止把连接显示为成功。网络切换、休眠唤醒、DNS 原值和抢占冲突需要 macOS 真机验证。
|
||||
- 本轮优先 macOS;Linux/Windows 需要独立系统权限与适配,未实现时不得显示内置直连可用。现有 SOCKS5 应用代理保留;任何平台均不回退到系统 WireGuard 工具。
|
||||
|
||||
- `get_system_readiness` 报告平台、Go 代理组件、`engine_mode` 和可读 `engine_detail`;不再检测或展示系统 WireGuard 命令。`bundled` 仅可在实际引擎、权限和系统配置均通过验收后返回。
|
||||
- 内置组件的目标 triple 路径和版本由构建产物显式声明;发布流程核对哈希、签名和可执行权限。不能从用户可写数据目录或 PATH 寻找发布 helper。
|
||||
- 服务端 API、数据库及客户端设备密钥数据模型不变;未来 helper 通过最小化本地 IPC 收到连接参数,不接触用户口令或管理令牌。
|
||||
- 本轮 Go 代理继续显式开启,不自动修改系统代理、路由或 DNS。Rust 将设备准备与整机拨号分离;代理路径复用同一设备授权流程,启动时重新查授权,失败时不遗留假在线状态。试验用户的 `AllowedIPs=10.88.0.0/24` 只可代理该网段,不能宣称可经 VPN 浏览公网。
|
||||
|
||||
### macOS 系统代理扩展(S3,2026-10-21)
|
||||
|
||||
- 用户显式启动应用代理后可单独启用系统 SOCKS 代理。仅当设备配置实际包含 `0.0.0.0/0` 时允许开启;当前私网试验专线应拒绝,避免把普通网页发送到不允许公网访问的隧道。系统代理只影响遵循 macOS 代理设置的应用,不等同于整机 TUN,也不能保证所有 UDP 或 DNS 走隧道。
|
||||
- 启用前枚举网络服务、检查 HTTP/HTTPS/SOCKS/PAC/自动发现是否已有代理;已有代理时拒绝接管。持久记录将要更改的服务与原 SOCKS 配置;启用失败逐项回滚。关闭时只恢复仍指向自身监听端口的服务,绝不覆盖其他程序随后修改的代理。进程意外退出或下次启动应尝试清理残留;无法安全恢复时给出错误并保留恢复记录。网络服务新增或切换不能自动把未授权服务纳入代理范围。
|
||||
- 启用、关闭、注销、退出与隧道切换均需串行操作。恢复失败不得悄悄关闭仍被系统代理引用的本地监听;手动改动代理后状态显示为冲突。验收包括私网路由拒绝、已有代理拒绝、启停还原、部分失败回滚、异常退出后重启恢复及更换网络服务。正式真机验收前不把此能力描述为跨平台整机 VPN。
|
||||
|
||||
## 5. 风险与验收
|
||||
|
||||
@@ -61,16 +83,20 @@ React → Tauri invoke → Rust(登录、设备私钥、连接状态)
|
||||
|
||||
| AC | 对应需求 | 前置条件与操作 | 预期结果 | 验证方式 | 结果 |
|
||||
|---|---|---|---|---|---|
|
||||
| AC-01 | FR-01, FR-02 | 无 Homebrew 的 macOS 打开当前过渡版/未来免安装版 | 过渡版明确显示依赖;免安装版仅在组件和权限实际就绪时显示内置可用 | 单测、构建、真机 | 当前过渡版选择器单测通过;免安装版 Not Run |
|
||||
| AC-01 | FR-01, FR-02 | macOS/Linux 上有或没有系统 WireGuard 命令时打开客户端 | 两种环境均报告内置直连未就绪;客户端不运行系统命令,Go 代理独立可用 | Rust 单测、构建、静态调用核查、真机 | Rust 单测与静态核查通过;真机 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-03a | FR-03/04 | 数据面收到格式错误、过大、符号链接设备记录;模拟全局/分流路由、物理出口与 `utun` 出口;父进程退出或接口意外关闭 | 拒绝错误输入与非物理出口;进程退出并释放接口;接口创建事件不冒充联网完成 | Go 单测、跨平台构建、macOS 故障注入 | 输入与物理出口解析单测、构建通过;macOS 故障注入 Not Run |
|
||||
| AC-04 | FR-05 | Windows/Linux 干净系统安装、拨号、卸载 | 无独立工具安装步骤,未支持平台不假装就绪 | 各平台测试 | Not Run |
|
||||
| AC-05 | FR-06 | 无 `wg-quick`、有拨号用户授权时点击“应用代理” | 自动登记设备并启动 Go 代理;界面展示应用代理地址且整机 VPN 仍未连接;撤销/退出后代理停止 | Rust/Go 单测、macOS 实机检查 | Rust 模拟服务端首次登记/刷新测试通过;Go 私网探测成功,本机代理监听/私网 SOCKS 握手通过;GUI 拨号用户与撤销验收待运行 |
|
||||
| AC-06 | macOS 系统代理扩展 | 私网路由/已有代理拒绝;全局路由下启停、断网、异常退出 | 已占用设置不覆盖;仅恢复自身代理;不把 SOCKS 宣称为所有流量经过 VPN | macOS 真机逐项验收 | Rust 构建/静态状态解析通过;系统设置与公网网页真机验收 Not Run |
|
||||
|
||||
## 6. 发布与恢复
|
||||
|
||||
- 第一阶段仅交付设计与隔离执行层的基础代码,不默认启用内置模式;持续提供现有 `wg-quick` 开发通道。切换正式引擎前收集目标架构及代码签名资料。
|
||||
- 第一阶段关闭系统工具直连,仅交付隔离执行层和 Go 代理;特权网络服务与恢复通过验收后才启用内置直连。切换正式引擎前收集目标架构及代码签名资料。
|
||||
- 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 恢复完成。
|
||||
- 2026-10-21 只读复核运行中的 wg4、IPv4 转发与 NAT:IPv4 转发已开启,POSTROUTING 仅有 OpenVPN `10.10.0.0/24` 规则,WireGuard `10.88.0.0/24` 没有持久出口 NAT。全局线路上线需先通过管理后台启用该专线的出口 NAT 并下发经授权的全局 IPv4 路由,再实测浏览器访问;当前不能标为公网验收通过。
|
||||
- 先在独立试验机测试安装与签名,再验证路由/DNS 回滚与握手,然后分批发版;不能仅靠 `cargo check` 或浏览器预览宣称可分发。
|
||||
- 出现网络配置残留时用保存的系统快照恢复并停用有问题的组件;保留旧安装包与开发模式供排障。服务端不变,无数据库回滚。
|
||||
|
||||
|
||||
Reference in new issue
Block a user