跳转到内容

NS · 应用模式

状态:应用会话与文件传输已接入;验收范围与延期项分别记录(2026-10-25)。 应用模式是 NS 的第三个部分:文件发送以及之后的功能、第三方应用,都作为应用运行在节点之上,而不是某种连接模式的附属功能。账户模式与 Quick 模式回答”谁是对端、经哪条路径到达”;应用回答”在隧道里做什么”。

目标设计中,每个 ns 节点只有一个 nsplane 数据面引擎。账户模式、Quick 模式、ns send 与第三方应用全部基于这一个引擎:

层组件职责
应用ns send / ns receive、第三方应用应用自己的协议、界面与输出
应用会话接口ns应用通道(会合信箱客户端、引入、按 kind 分发)、app:<session> 对端来源的生命周期、第三方应用接入
连接方式账户模式(NSD 投影的对端)/ Quick 模式(配对产生的对端)决定谁是对端、用哪个 relay、走哪条路径
数据面nsplane 引擎(每个节点一个)WireGuard、直连与 relay 路径、报文过滤;会话对端的安装与移除、隧道内连接(netstack)、按来源命名空间的 ACL 与 pinhole
会合relay 的 /rendezvous/v1与应用无关的会合信箱(会合协议)

应用不自带 WireGuard 引擎、TUN 或 relay 连接;它通过应用会话接口使用节点已有的引擎。这样直连探测、relay 转发预算、入站过滤和路径切换只有一份实现。

账户模式与 Quick 在同一个 nsplane 引擎上作为平等 membership 运行;应用会话 app:* 独立拥有授权与生命周期,复用选定 membership 的身份。应用会话基础已经接入,confirm 保持既有 Quick 配对行为;peer、relay PAKE、隧道内 PAKE 和受限 IPC 供具体应用复用。2026-10-22 应用会话阶段记录保留当时的候选和证据边界。2026-10-25 文件传输本轮范围已完成,C05 仅在用户通知后恢复且不阻塞本轮,Windows 原生验收仍为发布门;当前文件功能、固定候选证据及独立的 relay 域名迁移待办见文件发送。这些结果不替代其它应用或整个平台的发布验收。

组成说明
kind应用标签,例如文件发送为 transfer;relay 只用它做统计
应用通道应用声明一份 profile(kind、鉴权方式 confirm / pake / peer、对端生命周期、隧道内端口);会合、引入、身份交换、PSK、对端安装与隧道内入口由 ns 的应用通道统一实现,需要会合时经 relay 的 /rendezvous/v1 信箱
对端两端已是对端时使用现有对端(peer);否则经应用通道的 pake 建立仅限本次会话的对端:从不进入允许名单,不发布名字,只放行应用端口,会话结束即删除
数据始终在 WireGuard 隧道内,按端口区分应用;relay 上不承载应用数据(会合协议 §10)
界面命令行、--json 事件或嵌入方的回调

Quick 模式的配对同样是应用通道上的应用(kind = "pairing",confirm,长期对端);它是 Quick 模式建立对端的方式,因此不出现在下面的应用清单中。

应用选择明确的已连接来源,使用该来源的身份、对端与路径;仅 Quick 未配对路径可经会合建立临时会话对端,不能从 NSD 静默回退到 Quick。

节点模式已有对端没有现成对端
Quick 模式ready 的已配对对端会合信箱 + 仅限本次会话的对端,经 Quick relay 到达
账户模式精确 NSD Network 投影的 Node,受该来源策略约束首版不支持;不回退 Quick

首版覆盖 Linux、macOS、Windows daemon 的受限本地 IPC;移动端和 libns 应用入口不在范围。第三方经 ns app 管理授权,运行时只持有受限 capability,不取得 owner 管理凭据、身份私钥、PSK 或任意 peer/策略管理权。

  • 来源为精确 nsd:<uuid>/<network> 或单一 quick。仅恰好一个已连接 membership 时可省略;多来源必须明确,保存的 owner 冲突选择优先,不能按 ready 状态、排序或上次使用回退。Quick 内不细分 Network,relay/直连是传输路径,不是新授权来源。
  • app:<session> 拥有授权、密钥、flow、pinhole 与租约,复用选定来源的 I/K,不额外派生传输身份。已有 peer/PSK 保持不变;仅 Quick 未配对路径可安装会话临时 peer,不进入长期允许名单。临时身份对首版只允许一个活动会话,重复返回 busy;已有 peer 允许隔离并发。
  • owner grant 限定 app_id、kind/端口、auth/lifetime、精确来源、peer 范围、是否允许引入未知临时 peer、并发/寿命。保留 pairing/transfer 与内置/控制端口;第三方不能自行占用。接纳权限取 grant、选定来源有效策略及远端接纳的交集,不能从共享 I/K 的其它 Network 或 Quick 借权。
  • 双方各自按本地来源授权,不声称从共享 I/K 证明对端选择的 Network;本机 selector 不等于远端 selector。入站绑定 owner 批准的本地接收会话/监听上下文;同 kind/端口/peer 匹配多个不同来源上下文且无法唯一定位时拒绝,不信任 OPEN 自报来源来扩大权限。已知 channel_id 可以定位已有会话,但必须核对身份、来源与 MAC/PAKE。隧道内口令邀请的 LOCATE 只在已唯一确定的本地授权上下文内选邀请,不能消除跨来源歧义或提供额外权限,见PAKE 邀请定位。
  • 实际应用数据交付必须经过必经的会话接纳门;全局宽 ACL、pinhole、共享 label 或仅通过 WireGuard 身份认证都不能绕过 OPEN/PAKE 和 grant 校验。鉴权前到达的应用帧拒绝,不留待鉴权后交付。
  • 会话绑定本地 source、authority/install/incarnation、grant 与具体 flow。来源离开、身份替换、撤权、进程租约失效先关闭接纳,再逐 flow 撤销并等待退休回执;不能仅撤 pinhole 或删除共享 peer。同端口会话 A 取消后,B 的原连接继续;重新授权不复活旧句柄。单次普通断线不自动等同来源永久撤销,沿既有来源生命周期事实处理。
  • 每个机器仍只有一个 daemon;无来源不自动注册 NSD 或加入 Quick。第三方的同一 OS principal 内恶意代码隔离不在首版承诺,跨用户/沙箱权限仍需各平台原生证明。

已有 peer 的 IPC 使用 peer/none,来源为已运行的 Quick 或精确 NSD Network;下列契约不代表 PAKE 或三平台原生验收已经通过。移动端、libns 新入口和文件传输不在本片段范围。

  • owner 使用 ns app list、ns app authorize --grant <file>、ns app revoke <app_id>、ns app run <app_id>。授权只保存在当前 daemon 内存;修改须先撤销,不能覆盖活动授权。run 发放一次性 capability,不执行任意程序。
  • grant 的全部字段为 app_id、kind、port、source、peers、auth、lifetime、max_sessions、max_seconds;全部必填,未知字段拒绝。source 为 quick 或完整 nsd:<uuid>/<network>,固定 auth=peer、lifetime=none,不引入未知 peer。peers 是 1–32 个完整 I,使用与 ns quick peers --json 的 identity 字段一致的无填充 base64url(43 字符),不能用 node ID 或 WG key 代替。
  • app_id、kind 使用 [a-z0-9-]{1,32};pairing/transfer 保留。端口限 49152–65535,不同授权不得重复 kind 或端口。每 grant 最多 8 个未消费 capability 与活动会话之和,全 daemon 最多 32 个 grant、64 个槽。
  • NSD 接纳绑定已认证 RegistrationAuthority 的 Network、Account、credential incarnation、activation generation 与本地 I/K,并使用所选 Network 的独立策略门;不能从共享 peer 的其它 Network 借权。来源退回既有撤销路径时先关闭应用接纳并等待逐流回收,重连或 A→B→A 不恢复旧 capability。Quick 停止只撤销 Quick 应用,授权与限额仍由整个 daemon 统一管理。
  • capability 为随机 32 字节,发放后 30 秒内消费一次,范围仅为该 grant 内的 peer 和一次 connect/listen。会话寿命为 grant 规定的 1–900 秒,首片段不续期。撤权、重启或来源安装失效后旧句柄不恢复。
  • 使用现有私有 Unix socket / Windows named pipe。owner 前缀 appown\n,随后 u32be JSON长度 | JSON,请求为 {version:1,profile_id,instance_id,operation};operation 为 {op:"list"}、{op:"authorize",grant}、{op:"revoke",app_id} 或 {op:"run",app_id}。响应为 {version:1,ok,result},失败为 {version:1,ok:false,error}。profile 与 instance 必须匹配 daemon,OS 身份检查仍是必经门。
  • app 前缀 appuse\n,随后同样的 JSON 封包,请求只含 {version:1,capability,peer,listen}。请求最多 16 KiB,响应最多 128 KiB,JSON 读写各 5 秒;未知版本或字段拒绝。app 请求不接受 owner 操作。
  • 接纳先返回 state=preparing,TCP 建立与双向 OPEN 合计最多 5 秒,完成后返回 state=ready 与 channel_id。准备期间任何应用输入拒绝并回收;不缓存提前应用帧。已有 peer 继续正常重连,不重复安装。
  • ready 后用应用通道的 u32be length | class | type | payload,长度 2–1048576。只转发 class 1 数据。本地 class 0/type 2 的空 payload 为 CANCEL,绝不转发为隧道 LOCATE。回收终态用同一 class/type 携带 {version:1,ok:false,state:"closed",reason,retired}。取消及失败不是应用成功,只有退休回执与本地队列回收完成才报告 retired=true。若关闭发生在本地输出帧尚未写完时,回收后直接关闭 IPC,不把终态拼入残缺帧;消费者将截断或无终态 EOF 视为失败。进入 ready 阶段或响应写入失败后,不再追加准备阶段的 JSON 错误响应。
  • 双向均无完整帧交付达 30 秒即关闭,任一方向完成一帧可刷新空闲期限;绝对寿命仍生效。单会话每方向最多 64 个排队数据包、64 KiB TCP 缓冲,应用帧另受 1 MiB 限额约束。owner 等待撤销回收最多 5 秒,超时报告 cleanup_pending,不报告完成,底层回收继续。断连、进程退出、撤权和来源失效走相同回收路径。

原生权限、实际 daemon 与独立消费者、故障及生命周期证据按实现计划逐平台记录;同一 OS principal 内的恶意进程隔离仍不在承诺范围。

本节定义应用会话的隧道内口令门接缝;实现与原生资格按计划验证,不表示本节全部已交付。 保留 auth=peer/lifetime=none,不安装 peer 或改变已有 PSK。grant 可增加 require_pake: true;省略时为 false。该要求来自本地 owner 授权,不能由对端首帧 降低或切换。两端都须选择需要 PAKE 的本地 grant;不匹配时关闭本流。

  • capability 仍消费一次。除连接/监听外,可经 7 字节 appcfg\n 前缀和同样的 bounded JSON 封包完成一次本 grant 内的邀请操作;不能修改 grant、读取节点密钥、 安装 peer 或选择另一来源。请求为 {version:1,capability,operation},operation 为 {op:"invite",peers,context,prs,deadline} 或 {op:"revoke_invite",invitation_id}。
  • peers 是 grant 的非空子集,context 为 0..1024 原始字节,PRS 为 1..1024 原始字节;JSON 用规范无填充 base64url 表达二者,不 trim、正规化或解释内容。 deadline 是绝对 Unix 秒,须在当前时间之后且剩余不超过 grant.max_seconds。 注册返回随机 invitation_id 与 deadline,不回显 PRS。每 grant 最多 8 个邀请, daemon 最多 64 个;活动且 peer 范围重叠的邀请不得具有相同 context。
  • appuse 的连接请求可增加 pake:{context,prs,deadline};需要 PAKE 的连接必须 提供它,不需要 PAKE 的请求禁止提供。监听请求不携带 PRS,邀请预先经 appcfg 注册;双向 OPEN 后由 LOCATE 在已绑定的 grant/source/peer 范围内选择邀请。 ready 增加 context;监听侧另返回 invitation_id,使消费进程能对应已注册邀请。
  • 未知、过期、歧义或已消费邀请关闭本流;busy 和未定位不扣失败预算。成功定位后 每邀请仅一个 attempt,失败累计最多三次,连接重建不能重置。前两次在流退休后 释放 attempt 槽;第三次关闭邀请;成功消费邀请。撤销、到期、来源/grant 失效 禁止新接纳并取消相关会话,等待退休后清除材料;回收失败不能报告完成。
  • TCP 建立和双向初始 OPEN 仍受原 5 秒准备门限制;其后的 LOCATE/PAKE 受 min(邀请 deadline, 首次发送/接受 OPEN + 60 秒) 限制。ready 要等双向 OPEN、 HELLO 的签名/当前承载 I/K/记录时序校验及双向 FINISH;此前本地输入与提前应用帧 拒绝,不缓冲或回退。应用阶段的 30 秒空闲期从 ready 开始,绝对寿命还受邀请 deadline 和双方 HELLO.not_after 限制。相同当前步骤重传只回复缓存字节。

PRS 只用于内存中的邀请/attempt;请求缓冲与解析后的秘密由各自所有者清零,日志、 错误、状态列表和响应均不含 PRS。capability 的同 OS principal 边界与 §3.2 相同。 本扩展不定义文件票据或口令生成方案,不增加移动端/libns 入口。

本节承接已选的 pake/session,不改变 PAKE suite、信箱 API 或文件应用。实现与 平台资格仍按计划验证。已有 peer 的 §3.2–3.3 请求保持其原有权限边界。

  • grant 可选择 auth=pake、lifetime=session,来源必须是 quick, require_pake 为 false。allow_unknown_peer 默认 false;仅该组合可设为 true。 peers 仍为最多 32 个精确 I;仅允许未知 peer 时可为空。身份在加密 HELLO 中 认证后,须属于 peers 或通过显式未知 peer 许可,仍检查移除记录、记录时序、 地址冲突与本地 owner 来源选择。未知 NSD peer 不支持。
  • appuse 增加 relay:{code,context,prs},不得同时提供 pake。context/PRS 编码 与 §3.3 一致。创建方 listen=true 且 code 省略,使用 Quick 的 home relay; 加入方 listen=false 且 code 为目录内两位 relay 前缀加八位数字。该请求的 peer 字段为空或省略;应用不能指定任意 URL、安装参数或 PSK。
  • 一次 capability 占用一个有界会话槽,包含会合、握手、准备及数据阶段。节点最多 8 个 relay 会话;网络已有对端与预留名额之和不得超过 1024。已知容量不足在 open/lookup 前拒绝;HELLO 后、安装前再次原子检查身份对冲突和容量。
  • 创建后返回 state=inviting、code 与 expires;加入方返回 state=joining。 信箱 TTL 不超过 900 秒及本地 grant 的寿命边界,三次失败、重传与 60 秒 attempt 期限遵守精确 PAKE profile。期间本地断连、提前数据、来源失效或撤权均关闭接纳, 清理已知信箱及本地 attempt;信箱响应丢失时仍由 relay 的固定 TTL 回收。
  • 双方 FINISH 后才准备传输。已有 Quick peer 保留其 PSK,未知 peer 仅安装本次 会话 PSK、N6/128 和精确应用端口权限;不写允许名单、别名、名字或移除记录。 同一身份对的临时会话重复返回 busy。准备及双向带 MAC 的 OPEN 合计最多 5 秒; channel_id 必须等于 mailbox_id,MAC 绑定实际承载流的双方 I。
  • ready 返回 channel_id、peer 与 context;不返回密码、传输密钥或 owner 凭据。 ready 后数据、CANCEL、空闲回收及退休回执沿用 §3.2。relay grant.max_seconds 为 1–86400 秒的绝对上限;初始租约最多 900 秒,完成应用帧传输可把活动租约 推进最多 900 秒,但不得越过创建时确定的绝对上限。握手期限不随进展延长。
  • 取消先撤应用接纳并退休本流,随后关闭 pinhole、删除本会话临时 peer,等待 引擎确认后才报告 retired。已有长期 peer 保留。确认长期配对前,先退休该身份对 的临时会话;永久 PSK 重新派生。重启不恢复本节任何会话或授权。

以下是已接入 ns send / receive 的文件应用契约;实际验收范围见文件发送。它复用本机 owner 身份校验、唯一 daemon、来源绑定、通道 PAKE 和逐 flow 退休,不把第三方 ns app authorize 放开为可注册 transfer 或 47901。

  • ns send / receive 的 owner 控制请求绑定当前 profile_id/instance_id、调用 OS principal、角色、精确 source、票据模式、允许 peer 范围及显式未知 peer 许可。只能请求固定 kind=transfer、port=47901 和该角色支持的动作,不能传入任意 kind/端口、源路径、目标路径或 peer 安装参数。
  • daemon 创建私有的一次性会话 capability,绑定上述上下文及 CLI 连接的存活租约;采用既有 30 秒领取期限,一次消费,跨 owner、daemon 代际或来源不可复用。此内置接入不是可由任意第三方 grant 占用的公共扩展点,同 OS principal 内恶意隔离仍不在承诺范围。
  • 发送方控制动作是创建/撤销本次邀请、监听本次流;接收方是使用票据定位或会合并连接本次流。ticket/PRS 通过受保护的有界 IPC 输入,只保存在邀请/attempt 内存;文件数据通过既有有界流桥接,文件路径、内容索引和 checkpoint 始终由 CLI 用户进程拥有。
  • 内置服务可共享同一个 47901 监听入口,不用第三方全局 kind/端口互斥禁止所有并发。先按 source、实际 peer、owner 接收上下文确定唯一授权范围,再按已知 channel_id 或该范围内 LOCATE 定位会话;跨来源歧义直接拒绝,不能按 LOCATE、到达顺序或最宽 ACL 选来源。
  • 同一邀请最多一个 attempt、一次成功接收者;同来源不同邀请可并发并共享长期 peer;内置 capability、等待会合和活动流计入 daemon 现有 64 个会话总槽位,邀请计入全节点 64 个邀请上限,relay 路径仍服从 §3.4 的 8 个 relay 会话上限,临时 peer 容量不变。临时身份对仍只允许一个会话,拒绝重复安装或替换共享 PSK。第三方原有 grant 限制保持不变。
  • 两端分别确认自己的 source 与未知 peer 许可;NSD 只允许投影 peer。--yes 是 CLI 文件确认选项,不能进入 daemon 授权判定;同 Account、名字或票据均不能替代来源策略。
  • CLI 只向 daemon 报告本会话已接受的文件阶段、当前 index 和有界单调进展;daemon 验证 capability、阶段合法性、计数范围与绝对期限后才能推进本次活动租约。任意流量、WAIT 响应或重复计数不续期。内部控制序列化沿用 owner IPC 的版本校验、大小上限和敏感数据清理,不借此改变第三方 appuse/appcfg 的字段或含义。
  • 文件邀请与传输期限按文件发送 §5.6;FINISH 前不改变现有密码握手期限,文件阶段只采用该内置 profile 的寿命。第三方 §3.2–3.4 的行为不变。
  • 文件成功回执归 CLI 协议,daemon 的 closed/retired 只证明本地流与资源状态。主动取消或 CLI 失联都撤销本次能力并等待退休;文件暂存保留策略按文件事务规则,不能让 daemon 代替用户遍历/删除目录。
应用kind入口状态
文件发送transferns send / ns receive <票据>已实现,本轮范围完成;C05 延期不阻塞本轮,Windows 原生验收保留为发布门
第三方应用自选ns app ...(预留)与 ns 暴露的应用接口规划
语音、聊天待定待定规划;按应用通道 §9 添加

命令约定:内置的高频应用使用顶层短命令(ns send / ns receive),它们使用明确选择的来源,不依赖“当前模式”;第三方应用的列出、授权与运行统一放在预留的 ns app 命令族下。

  • 通用应用会话与具体应用分别保留候选、平台权限和验收证据;文件传输本轮完成不能替代第三方应用或全部平台的发布验收。
  • 文件事务与续传已有独立实现及验收记录;C05、Windows 原生验收和公共 relay 域名迁移保持各自延期或未完成状态,见文件发送。