NSC · 演进路线与开发计划
本页融合 NSC 的设计差距、改造主题与企业级演进方向,作为路线规划的输入。架构概念见 architecture.md。
1. 不可放弃的差异点
NSC 的演进必须保留以下产品差异化:
- 不需要 TUN / 不需要管理员权限 —— 默认形态下不创建虚拟网卡、不修改路由表,可在普通用户、CI runner、容器、移动 App 沙箱内运行。
.ns 命名空间 + 环回 VIP —— 服务被映射到本机 127.127.x.x 段,操作系统层无需 NAT 或路由配置。
- 本地 DNS 即查即用 —— 对
*.n.ns 域名的解析就近发生在本机,既不依赖系统 DNS 也不污染上游。
- HTTP/CONNECT 代理替代品 —— 浏览器场景下可通过本地 HTTP 代理直连,完全绕过 VIP 监听器,实现单入口多目标。
- 与 NSN 共享栈、方向相反 —— 控制面、机器身份、协议栈、proxy / ACL 子模块复用,降低代码维护成本。
2. 开放差距(按主题)
2.1 把"接收的"变成"生效的"(主题 E)—— P1 必修
NSC 主循环目前只 select! 3 路 SSE,其余 4 路接收器用下划线显式丢弃。这是"零信任客户端"设计的结构性缺口。
| ID | 现状 | 目标 |
|---|
E.1 接管 _acl_rx | 收到 ACL 配置即丢弃,出站方向无策略 | 复用 acl::AclEngine(与 NSN 同源);在 router.resolve_* 路径加 ACL 检查;fail-CLOSED 启动窗口 |
E.2 接管 _token_rx | NSD 推送 token_refresh 不被消费,proxy_mgr 的 token 永远是初始空字符串 | 主循环加 Some(new_token) = token_rx.recv() => proxy_mgr.set_token(new_token);ProxyManager 加 async fn set_token |
E.3 接管 _wg_rx | NSD 推送的 wg 配置在 NSC 侧无消费 | 关联 TUN 模式真实化(F.1) |
E.4 接管 _proxy_rx | proxy 规则 NSC 侧不消费(NSN 才需要) | 评估是否需要客户端预检;若需要则与 ACL 一起评估 |
2.2 把"声明的"变成"真实的"(主题 F)—— P1
NSC 的 CLI 表面承诺了 3 种 data plane、2 种注册方式、1 个 status 子命令。其中 tun 模式是假的、--device-flow 是假的、status 是假的。
| ID | 现状 | 目标 |
|---|
| F.1 TUN 数据面真实化 + 寻址模型抉择 | DataPlane::Tun 仅触发 new_tun() 切到 100.64/16,无 TUN 设备、无 ip route、无 root 检查;且当前默认仍是 VIP 寻址,passthrough 方案未表达 | (a) 设备真实化:用 tun-rs / gotatun::tun 真正建设备 + ip route add + packet-level routing(或选 (A) 路线删除 DataPlane::Tun);(b) 寻址模型抉择:支持 VIP(100.64/16)与 passthrough(直接路由到站点 CIDR)两种模型共存,由服务声明端(NSN services.toml 增 addressing = "vip" | "passthrough")决定;GatewayExit(exit node)必须 TUN 真实化为前置;架构对比见 architecture §2.8.1 |
F.2 --device-flow | NSC 入口尚未实现 device flow 注册,但底层 device flow 客户端模块已完整,NSN 已在用 | 参照 NSN 调用 request_user_code → show_to_user → poll_until_authorized → register_with_token 流程 |
F.3 nsc status 子命令 | 仅 println!("Sites:"); println!("(connect to a running 'nsc' daemon to see live status)") | daemon 内启动 UNIX socket({state_dir}/nsc.sock)或 127.0.0.1:9091 HTTP,暴露 sites / vips / dns_records / tunnel_state JSON |
| F.4 WSS-only 强约束 | 当前与 userspace 行为等价 | 实现"绝不尝试 UDP",在 UDP 可达时也不切换 |
2.3 把"个人工具"变成"企业入口"(主题 G)—— P2
| ID | 现状 | 目标 |
|---|
G.1 /metrics 端点 | 无,无 OTel pipeline 初始化 | minimal /metrics 监听 127.0.0.1,暴露 dns_queries_total / vip_ports_active / nsgw_rtt / proxy_connections / ws_reconnects_total |
| G.2 SOCKS5 入口 | 无 | 与 HTTP 代理并列,服务"不能配 HTTP 代理但可配 SOCKS"的应用 |
| G.3 PAC 自动配置 | 无 | 生成动态 PAC 文件,浏览器选 http://127.0.0.1:9091/proxy.pac |
| G.4 split DNS / 条件转发 / 系统 DNS 接续 | 上游硬编码 1.1.1.1:53,无按域转发,接管本地 DNS 后顶替原系统上游(破坏性集成) | (a) 接管前先快照系统 DNS —— 读 resolv.conf / resolvectl / scutil --dns / Win API,作为默认上游;读取必须在写入之前,避免自循环;(b) 订阅网络变化事件刷新快照(Linux netlink、macOS SCDynamicStore、Windows NotifyAddrChange);(c) 默认上游优先级 dns_config 显式 > 系统快照 > CLI --upstream-dns > 硬编码;(d) 按域后缀转发表(最长匹配)沿用 dns_config;(e) DNS 模块只看上游地址,不感知是否走隧道——内网 DNS 在 NSN 端注册为普通 service,自动获得 dns.<site>.n.ns + VIP,转发表上游写该 FQDN/TCP 即可;架构见 architecture §2.4.0–§2.4.6 |
| G.5 双栈域名 / 公网域名遮蔽完善 | dns_config 已能把 git.company.com 重定向到 VIP,但隧道故障无 fallback、缺少健康降级、缺少 DoH 兼容指引 | (a) 隧道健康度感知:VIP listener 多次握手失败时把该域名转入"穿透"窗口,改返公网真实 A 记录;(b) 客户端 posture 上报"DoH 状态",NSD 在策略侧告警遮蔽可能失效;(c) 出文档化的客户端配置 SOP(关闭 DoH / flush DNS / per-domain resolver) |
| G.6 IPv6 支持 | 不支持 AAAA 命中 | 与 NSN IPv6 同步 milestone |
| G.7 移动 / 嵌入式形态 | 仅桌面端 | Android App 内嵌(SOCKS / HTTP CONNECT)、iOS 普通 App |
2.4 共享栈缺陷(NSN 主导,NSC 受影响)
以下缺陷由 NSN 侧为主修复,但 NSC 部署形态受其影响,需在同一节奏推进:
| 项 | 一句话 | 对 NSC 的影响 |
|---|
to_http_base() 改写 | 仍把 noise:// / quic:// 写为明文 http:// | NSC register/heartbeat 同样走明文 |
| auth challenge-response | authenticate 签名仅含本地时间戳,无 server nonce | NSC 注册阶段同受影响 |
| 私钥加密落盘 | machinekey.json 明文 hex JSON | NSC state dir(/var/lib/nsio-nsc)同样明文 |
| token 脱敏 | Bearer token format!() 拼接可能进日志 | NSC 的 control plane 代码同栈 |
| QUIC 公钥治理 | 信任完全基于 SHA-256 fingerprint pinning | 若 NSC 启用 QUIC 同样中招 |
| WSS 单 TCP HOL | 所有流共享一条 TCP | NSC 多 site 并发打流时明显 |
| 控制面 backoff | 指数退避时 token 可能过期,重连 401 再退避 | NSC 长跑后更易触发 |
| WSS data 帧零拷贝 | 每次 Vec::to_vec() | NSC 打流同样受益 |
| OAuth2 access_token 持久化 | device_flow access_token 仅内存 | 用户侧进程经常重启,每次都要粘 user_code |
3. 阶段排期
NSC 改造与 NSN 主线协同推进,优先级以"诚实接口表面 + 接管丢弃通道"为先:
Phase 1 · 诚实接口表面 + 接管 token (E.2 + F.1/2/3) — 1~2 周,无外部依赖
Phase 2 · 接管 ACL + minimal /metrics (E.1 + G.1) — 2~3 周,需 NSN ACL 主题先行
Phase 3 · 共享栈安全主题(密钥加密 / https / challenge) — 与 NSN B 主题并行
Phase 4 · 数据面健壮性(WSS 多 TCP / 零拷贝 / HOL 缓解) — 与 NSN D 主题并行
Phase 5 · TUN 真实化(若选 B 路线)+ SOCKS5 + PAC — 与 NSN F.4 并行
Phase 6 · 移动 / 嵌入式形态 — 企业级
Phase 1 · 诚实接口表面
目标:CLI 承诺与实际能力一致。
| 改动 | 验收 |
|---|
| F.1 TUN 模式选择 (A) 删除 或 (B) 实现 | 选 (A) 时 CLI --data-plane tun 在 parse 阶段报 "not supported" 早失败;选 (B) 时 e2e 验证从 NSC 出站包真实经 TUN 设备 |
| F.2 device-flow 接通 | --device-flow 不再 bail!,e2e 通过浏览器 user_code 完成注册 |
F.3 nsc status 真实状态 | UNIX socket 暴露 sites / vips / dns / gateway 等 JSON 字段 |
| E.2 token 接管 | NSD 端轮转 token 后,NSC 立即用新 token 打 WSS,无 401 重试风暴 |
Phase 2 · ACL 接管 + 可观测
前置:NSN A 主题完成(单一 ArcSwapOption<AclEngine> + 合并语义稳定)。
| 改动 | 验收 |
|---|
E.1 NSC 内嵌 Option<AclEngine> | _acl_rx → acl_handle.store;HTTP CONNECT / VIP listener 入口检查 ACL;fail-CLOSED |
G.1 minimal /metrics | 至少 5 个指标:dns_queries_total / vip_ports_active / nsgw_rtt / proxy_connections_total / ws_reconnects_total |
| 启动 OTel pipeline | 与 NSN 共享 init_telemetry() 装配 |
Phase 3+ · 与 NSN 共享栈主题并行
详见 NSN roadmap §3;NSC 端同步改造,所有共享 crate 的修复对 NSC 自动生效。
4. NSC 独有的演进方向
| 演进 | 价值 |
|---|
| 客户端 posture 上报 | NSC 上报 OS / 磁盘加密 / 2FA / DoH 状态等,NSD 据此应用条件策略 |
| 双栈域名(公网 + 隧道) | 同一公网域名(git.company.com 等)在客户端被遮蔽到 VIP,流量走隧道;不修改企业 DNS、不污染上游、卸载即恢复 |
| 企业 split DNS / 条件转发 | .corp 域名走企业上游(经隧道访问内网 AD)、*.n.ns 走 NSC 命中表、其他走默认公网上游;按域后缀的最长匹配优先 |
| PAC 自动配置 | 浏览器零配置,自动按域名分流 |
| VIP 持久化 | 重启后 VIP ↔ site 映射稳定,SSH 配置 / bookmark 长期可用 |
| 移动端(Android App / iOS App) | 利用"不需要 TUN / 不需要 root"的差异化优势 |
5. 风险与回滚预案
| 高风险改造 | 风险 | 回滚预案 |
|---|
| TUN 真实化 | 系统级影响,可能破坏现有路由 | feature flag 默认 off;只在 --data-plane tun 显式开启 |
| ACL fail-CLOSED 启动窗口 | 启动期短暂连接失败,用户感受到"卡顿" | 配置 acl_required = false 临时关闭 |
_token_rx 接管 | 旧版本 NSD 不发 token_refresh → NSC token 永远空 | 兼容旧 NSD:无 token_refresh 事件时维持现状 |
CLI --data-plane tun 删除 | 用户脚本中可能写死 tun | parse 阶段输出明确错误 + 升级文档说明 |
6. 不在路线图内(明确放弃 / 延后)
| 事项 | 理由 |
|---|
| Windows 客户端 | 暂未在 GA 范围 |
| 完整 GUI | 命令行 + system tray 已能覆盖核心场景 |
| WireGuard 内核模式 | 与 TUN 真实化(F.1)同节奏决策;若 F.1 选 (A) 删除路线则永远不做 |
| IPv6 全栈 | 与 NSN IPv6 同步,单独 milestone |
7. 跨团队协调点
| 改造 | NSC 改动 | NSD / NSN / NSGW 配套 |
|---|
_acl_rx 接管 | 复用 acl::AclEngine | NSD 推送的 ACL 必须包含出站维度 |
| device-flow 落地 | 调用 device flow 客户端模块 | NSD 已有 /device/code/token 端点(已具备) |
| posture 上报 | POST /api/v1/machine/posture | NSD 实现 posture 接收与条件策略匹配 |
| token 接管 | 主循环加 token_rx.recv() | NSD 实现 token 轮转(NSN 已配套) |
| 企业 split DNS | 上游 DNS 可配置 | 企业 DNS 提供方负责 .corp 解析 |