NSIO Docs
NSIO Docs
首页

NSIO Next · 当前开发基线

统一 L3 + L4 架构
产品能力目录与实现闭环
功能闭环总账
产品闭环与功能实现
实施蓝图与交付契约
发行、升级与卸载
跨组件共享契约
控制资源生命周期
控制投影与 Runtime Protocol
数据面协议
Grant 与策略编译

组件实现规格

ns · 统一节点运行时
Client · App、CLI 与门户
NSD · 身份与控制面
NSGW · 增值数据面
身份、登录与会话
注册、准入与配额协议
商业模型与 Entitlement
采购、计费与发票
服务运营与 SLA
备份与灾难恢复
信任、合规与数据权利

Last Updated: 2026/8/10 09:53:04

Previous Page控制投影与 Runtime Protocol
Next PageGrant 与策略编译

#NSIO Next · Data Plane Protocol v1

本文定义 ns、Relay NSGW、Egress/Exit/Ingress NSGW 之间可独立实现和互操作的数据面契约。控制对象和投影以 Runtime Protocol v1 为权威;访问命中以 PolicyKernel 为权威。本文只固定建路、建流、凭据、本地执行、传输失败和撤销。

#1. 硬性边界

  1. NSD 不在 packet 或 flow 建立路径上;执行者只使用本地已验签且未过期的投影和凭据。
  2. 路径只决定 transport,不扩大 AccessGrant、CapabilityActivation、EdgeAuthPolicy 或本地 Manifest。
  3. 每个流必须同时通过源端投影和承载/目标端投影;源端成功不替代目标端最终校验。
  4. 凭据绑定 target audience、projection digest、generation、revision 和 expiry,不能跨资源、角色、Network 或代重放。
  5. 读取失败、过期、角色不匹配和未知安全语义均 fail-closed;不得回查 NSD 后临时放行。
  6. 编码使用 network byte order。首版公共控制消息使用 canonical CBOR;Relay 固定帧头和数据 payload 是二进制。每个协议面单独维护 major version。

#2. 六要素闭合矩阵

任一数据面只有六格全部填写并有反向测试才是 contract_closed:

数据面双端角色投影自证凭据本地最终判定Digest 绑定换代禁止跨代 union
L3 Nodesource egress / target ingress Grant + netmapPeerPathLease + Membership/key binding双端按 peer/Membership/packet 判定peer/grant revision grouppeer epoch 重叠轮换是
Routeclient / connectorRouteAccessCredentialconnector 校验 source + exact destinationroute_projection_digestsecurity-first / bounded-drain是
ServiceFlowconsumer / publisherServiceFlowCredentialpublisher 校验 source + Service + Endpoint + Manifestservice_projection_digestsecurity-first / bounded-drain是
Relaysource session / destination sessionRelayRouteLeaseRelay 只校验 opaque route/session/limitsrelay_route_digest短期 pair epoch是
Egressconsumer / egress gatewayServiceFlowCredential + EgressOriginLeaseNSGW 校验 Service + origin allowlistService + egress config digestServiceFlow 规则是
Exitclient / exit gatewayExitTunnelLeasens capture 与 NSGW scope/NAT 双端校验exit_projection_digesttunnel generation是
Ingress backendingress gateway / publisherIngressBackendCredentialpublisher 校验 Binding + Service + Endpointingress + Service digestsecurity-first revoke / bounded drain是

“角色投影”指双方收到不同的最小执行材料,不是把完整策略图复制给两端。“禁止 union”指执行者不能为了平滑升级把两代允许目标、来源或 scope 合并成更宽集合。

#3. 公共传输基座

#3.1 Carrier 与复用

用途首选 carrier回退内层安全
L3 directWireGuard UDPRelayWireGuard
RelayQUIC DATAGRAM/TLS 1.3WSS binary message/TLS 1.3WireGuard packet
ServiceFlowpeer WireGuard path 内的 runtime-only QUIC stream/datagram外层 WG 可经 Relay/WSSpeer path + flow credential
RouteFlowpeer WireGuard path 的原始 IP packet;代理型 Route 可用 runtime QUIC外层 WG 可经 Relay/WSSpeer path + route credential
ExitWireGuard tunnel被授权 Relay transportWireGuard + Exit lease
Ingress externalTLS/HTTP/QUIC listener按 PublicApplication 配置EdgeAuth + backend credential

每个 carrier 的握手能力进入已认证 transcript。声称不支持 QUIC 只能关闭该可选 carrier,不能关闭凭据、目标端校验或租约。Next v1 的 runtime QUIC 与 Relay QUIC 全部设置 early_data=false,禁止 TLS/QUIC 0-RTT;session ticket 只能做 1-RTT resume。未来开放 0-RTT 必须作为独立 capability,只允许明确幂等的 OPEN、绑定 credential/generation,并由接收端持久 replay cache,不能通过库默认值隐式开启。

每个 Membership 的 netmap 带 runtime_transport={ip, udp_port, alpn="nsio-flow/1"}。该 endpoint 只承载 daemon 内部 QUIC,不能展示为用户端口,也不能因为 Node TCP/UDP Grant 而绕过 flow credential。ServiceFlow 建立只需要为该 Service 下发的最小 peer/WG path material,不要求双方存在 Node L3 Grant,因此企业关闭横向 L3 时 L4 仍然工作。

保留 endpoint 不是靠命名约定隔离,平台实现必须选择并证明以下执行方式之一:

  1. userspace demux:ns 在 WireGuard 解密后、注入 TUN/OS 前按目标 Node IP、保留 UDP port 和 QUIC ALPN 截获;匹配 packet 永不进入 OS socket table;
  2. exclusive listener:需要内核 WireGuard/系统 socket 的平台由 daemon 在 Node IP 上独占绑定保留 port,禁用 address/port reuse,应用 target-minimal firewall/namespace 规则,并在 projection ready 前验证 listener owner、地址和规则仍属于 daemon。

Service Local Manifest、Route 和 PublicApplication API 必须把保留 port 列为 runtime_reserved_port 并拒绝发布。某平台上普通进程即使成功绑定同一数值端口也不能收到 runtime packet;若实现无法证明这一点,或独占 bind/owner/firewall 验证失败,则 runtime_transport=not_ready,不投递到该进程、不回落普通 UDP,并返回 runtime_transport_conflict。本地管理员可破坏系统网络不在应用隔离承诺内,但这种破坏必须被验证检测而不能静默旁路。

QUIC connection 绑定双方 Membership/key epoch 和共同 peer_epoch_id;双方各自使用的 netmap/projection revision 进入 transcript 供诊断,但不要求 revision 数字相同。每个 TCP ServiceFlow 使用独立 bidirectional stream,UDP 使用 QUIC DATAGRAM。所有 stream 控制记录编码为 length:u32be + canonical CBOR bytes,单条上限 64 KiB;type/version/flow_id 是必需字段,长度越界或未知必需 major 关闭 connection。外层从 direct WG 切 Relay/WSS 只迁移/重建 peer path,不把内部 runtime endpoint 注入 OS route。

#3.2 稳定 MTU

首版 active Profile 的系统 TUN MTU 固定为 1280,连接期间不因 direct、Relay、WSS、Wi-Fi 或蜂窝路径切换而改变。理由是保证 IPv6 最小 MTU,并消除“直连小包正常、切 Relay 大包黑洞”的路径相关行为。

  • Relay v1 数据帧固定头为 32 bytes;carrier 额外开销不计入内层 1280 byte packet,由 carrier 分段/重组但不得改变 packet 字节;
  • ns 不向系统栈暴露大于当前所有候选路径都可承载的 MTU;
  • 超出 carrier 单帧上限但不超过该 carrier 的有界分段总容量时,按对应协议分段并逐字节重组;超过 255 个 Relay fragment 或其他 carrier 总承载上限时返回明确 packet_too_large,不能静默丢弃;
  • 超出 1280 TUN MTU 且不可分片的内层 IP packet 由本机栈明确返回 MTU 错误,并在可构造时注入 ICMP Packet Too Big/Fragmentation Needed;
  • v1 不做路径切换时的动态 TUN MTU;未来自适应 MTU 必须是独立 capability,并通过 PMTUD、黑洞检测和漫游测试。

#3.3 Stream 与 datagram 语义

TCP flow 的 bidirectional QUIC stream 先交换一条 length-prefixed OPEN 与 ACCEPT/REJECT;ACCEPT 后该 stream 两个方向只承载原始应用 bytes,不再混入控制 record。两个方向各自独立:

  • 本端读到 FIN/EOF 后产生 FLOW_HALF_CLOSE(direction) 语义并发送该方向 QUIC FIN,不能顺带关闭反向数据;
  • 两端都 half-close 且缓冲区排空后进入 closed_clean;
  • 本端 RST、凭据撤销、协议错误或安全拒绝产生 FLOW_RESET(code) 并映射到 QUIC RESET_STREAM/STOP_SENDING application code,对端立即停止该流;
  • carrier 断开时,只允许对尚未向应用确认成功、且 request 明确幂等的建流重试;已传输任意应用字节的 TCP 流不透明重放。

UDP 使用 flow-scoped datagram。每个 datagram 头为 version:u8 | flags:u8 | flow_id:16 bytes | sequence:u64 | payload_length:u16,随后是一个完整应用 datagram;所有整数为网络字节序。双方协商相同 idle_timeout_ms,任一方达到超时都可在该 flow 的控制 stream 发送 length-prefixed flow.close;默认 30 秒,管理员可在协议允许范围内配置。Datagram 不重传、不保证顺序,超过 negotiated max datagram 返回 datagram_too_large。发送者不能以 keepalive 无限延长已撤销凭据。

#3.4 Backpressure、keepalive 与 retry

  • 每个 stream 有 byte window,每个 connection 有 stream/window 上限;接收端窗口耗尽时发送方停止读取本地 socket;
  • 控制 keepalive 不承载业务数据,默认 20 秒;连续 3 个间隔无响应进入 transport_unreachable;
  • unauthorized、credential_expired、projection_mismatch、scope_violation 不重试同一目标;
  • endpoint_unavailable、relay_capacity_limited、transport_unreachable 可在未超过 operation deadline 时换健康 endpoint;
  • 重试不得自动选择未投影的新 Service、Connector、Gateway 或 Relay。

#4. L3 Candidate 与漫游信令

#4.1 Candidate 上报

ns 通过 node.endpoint.report 上报:

{
  "membership_id": "nm_01",
  "wg_key_epoch": 7,
  "discovery_key_epoch": 12,
  "discovery_public_key": "ed25519-public-key",
  "candidate_id": "cand_01",
  "kind": "lan|reflexive|ipv6_global",
  "address": "203.0.113.8:40231",
  "network_path_id": "local-random-nonstable-id",
  "priority": 100,
  "observed_at": "...",
  "expires_at": "...",
  "signature": "node-key-signature"
}

NSD 校验 Membership、key epoch、地址格式、TTL 和限速后,只向需要该 peer 的目标投影候选。LAN candidate 只投给网络条件允许尝试的 peer;network_path_id 不跨 Profile 或重启稳定,不用于授权。

Discovery key 由节点生成、短期轮换并用当前 Node Key 对 (membership, discovery key epoch, public key, expiry) 签名。discovery_key_id = first_128_bits(SHA-256(canonical public key))。NSD 不生成私钥;目标只接收当前需要通信 peer 的 public key。Candidate delta 必须携带 candidate ID、key epoch 和 expiry,缺任一项拒绝整条候选。

#4.1.1 多反射器与 UDP 映射行为

同 socket Reflexive 观察使用一至四个由 NSD 配置的反射器。ns 在认证控制会话中声明期望数量,NSD 可按当前可用池返回不超过该数量的非空 bootstrap 集合;集合内 reflector identity 和 endpoint 必须唯一,每份 credential、session、revoke key、响应公钥和有效期独立绑定。任一项无效时拒绝整份新集合,不部分安装。单个反射器失败只影响该观察,不清除其他仍有效 Reflexive Candidate 或 Host Candidate。

所有请求必须从承载 WireGuard 的同一个 UDP socket 发出。network_path_id 绑定本地进程内的 network path generation,不绑定短期 reflector session:credential/bootstrap 正常续租不改变 path ID;平台确认网络变化时先推进 generation、清除旧 generation 的在途和分类证据,再重新观察。旧响应即使签名有效也不能进入新 generation。

ns 只输出以下本地诊断事实,不把它作为授权或跳过 direct probe 的依据:

结果必需证据
endpoint_independent同一 generation、仍有效的至少两个 reflector identity,目标为不同公网 IP,观察到完全相同的公网 IP:port
endpoint_dependent同上,但观察到不同公网 IP:port
unknown缺失、过期、混合 generation、只来自一个 reflector、或多个 endpoint 仍落在同一个目标 IP

该结果只描述已观察到的 UDP mapping behavior。它不证明 NAT filtering behavior,因此 UI、日志和控制面不得将其翻译为 full-cone、restricted-cone、port-restricted-cone 或 symmetric NAT。直连是否可用仍以认证 discovery probe 加 WireGuard 握手为最终证据;所有 direct 候选失败后才进入 Relay。

#4.2 探测与漫游

  1. source/target 从各自 target-specific netmap revision 取得对端 WG/discovery key epoch 与候选;两份投影绑定相同 peer_epoch_id,不要求 revision 数字相同;
  2. source 向候选 UDP 地址发送 canonical CBOR discovery.ping.v1:transaction_id(128-bit)、source/target discovery key ID+epoch、source candidate ID、sent_at、random nonce、Node-signed discovery-key certificate 和 discovery-key signature;probe 不携带 User/Group/Organization display data;
  3. target 先按本地 netmap 找 source discovery key,校验证书、signature、target key、10 秒时间窗和 transaction replay cache;未知 source/target、过期或签名失败静默丢弃,不产生可用于枚举的错误;
  4. target 返回等长上限内的 discovery.pong.v1,绑定 ping digest/transaction、target candidate ID、接收时观察到的 source socket address、sent_at 和 target discovery-key signature;不得向未经验证 ping 返回更大 payload;
  5. source 完整验证 pong 后才把 (peer membership, wg_key_epoch, candidate_id, observed path) 标为 probe-ready;随后必须完成标准 WireGuard 握手,probe 本身不创建数据面授权;
  6. 成功路径绑定 (peer membership, wg_key_epoch, candidate_id);endpoint 变化先探测新路径,握手成功后原子切换;旧路径短时 drain,但不复制应用 packet;
  7. 所有 direct 候选在 deadline 内失败才进入 Relay;Relay ready 后仍可低频探测 direct;
  8. endpoint report 过期只移除候选,不撤销 Membership;WG peer lease/Grant 过期才停止授权路径。

#4.3 PeerPathLease 与 Node L3 执行

PeerPathLease 是签名的 transport authorization,不是 Node AccessGrant。claims 至少为:

issuer, deployment_id, organization_id, network_id,
audience_membership_id, peer_membership_id, peer_epoch_id,
audience_wg_key_epoch, peer_wg_key_epoch,
purposes[node_l3|service_flow|route_flow], carrier_allowlist,
peer_projection_digest, issued_at, not_before, expires_at,
credential_id, revoke_key

NSD 只给确有 Node、Service 或 Route 通信必要的两端签发 target-specific lease。两端 lease 可有不同 credential ID/revision,但必须绑定同一 peer_epoch_id 和互为 audience/peer 的 key epoch。purposes 只限制 carrier 用途:存在 service_flow 不代表允许 Node L3,存在 node_l3 也不替代 egress/ingress Grant。

原始 Node packet 的执行顺序固定为:

  1. source ns 将目标 Node IP 解析为当前 peer epoch,校验未过期 PeerPathLease(purpose=node_l3);
  2. source 以生产 AccessCompiler 的本地 egress projection 校验 source Membership、目标 Membership/Node、协议、端口/ICMP action 和 constraint;无 allow 不把 packet 交给 peer path;
  3. target 从已认证 WireGuard key epoch 映射 source Membership,校验本地 lease 与 ingress projection;不信任内层 packet 自报身份;
  4. target 强制 inner source IP 等于该 source Membership 当前 Node IP,inner destination 等于本 Membership 的 Node IP 或该规则明确允许的本地目标;源地址伪造、跨 Network 地址、未声明 IP forwarding 一律丢弃并记稳定 reason;
  5. 双端通过后才注入目标 OS。普通 Node 首版默认 ip_forward=false,不能借目标节点横向转发到 LAN、Service VIP、Route 或其他 Node。

Grant 撤销先增量撤 egress/ingress projection并停止新 Node packet,再撤只为 Node L3 存在的 peer purpose;若同一 path 仍承载已授权 ServiceFlow/RouteFlow,可保留 carrier,但原始 Node packet 必须继续被拒绝。控制面断线时只在 lease 和双端 Grant projection 均未过期时继续。

#4.4 WG/Node Key 轮换

轮换对象状态为 prepared → projected → dual_accept → activated → retired|failed。新 key 由节点生成,NSD 只保存公钥和 epoch。

  • 双方投影同时携带 current 与 next key epoch;只有目标 ACK next prepared 后 NSD 才签发 activation epoch;
  • 在有界窗口内接受 current/next 握手,但每个 packet 仍映射到对应 Membership 和同一 Grant revision;
  • 窗口结束后 current 立即停止新握手,现有 session 按安全策略 drain;
  • Device/Membership revoke 跳过 drain,立即停签并触发 key/session revoke;
  • 轮换失败保留 current,不能留下一个只有单端知道的 active key。

#5. Relay Protocol v1

#5.1 隐私边界与标识

Relay 不接收稳定 Membership ID、Node ID、WG public key 或其稳定 hash。NSD 为每个短期 pair epoch 签发随机 relay_route_id,并为两端分别签发随机 relay_session_id。默认 TTL 10 分钟,可在 5 分钟撤销 SLA 内收紧;续租产生新 ID,旧新只在受控窗口重叠。

Relay 可以观察同一 epoch 内两个 opaque session 的通信关系、tenant metering bucket、时间、包长和流量;不能从协议字段把它关联到长期 Device/Node。NSD 审计保存 opaque ID 到 Membership 的受限映射。该元数据边界必须进入 Trust Center 和租户数据清单。

#5.2 RelayRouteLease

签名 claims:

issuer, relay_id, relay_tenant_id,
relay_route_id, source_relay_session_id, target_relay_session_id,
direction, carrier_allowlist, byte_rate, burst, concurrent_sessions,
relay_route_digest, issued_at, not_before, expires_at, nonce, credential_id

relay_tenant_id 是 deployment-scoped 计量假名,不是 Organization ID。两端各拿只能表达自身方向的 lease;反向通信需要双向 lease 或一份显式 direction=bidirectional lease。Relay 本地验签、校验 session/route/direction/limits/expiry,不回查 NSD。

#5.3 Session attach

  1. ns 建立 QUIC/TLS 或 WSS/TLS carrier;
  2. 发送 RELAY_ATTACH(version, relay_session_id, route_id, lease, client_nonce);token 放消息体,不放 URL/header log;
  3. Relay 验签并返回 RELAY_ATTACHED(server_nonce, max_frame, idle_timeout, lease_expiry);
  4. 目标 session 未 attach 时返回 relay_peer_not_ready,source 可等待或选择其他 Relay;
  5. attach 成功只说明可转发 opaque WG packet,不说明 L3/Service Grant 成功。

#5.4 固定帧

Relay v1 frame header 恰好 32 bytes:

version:u8 | type:u8 | flags:u16 |
target_relay_session_id:16 bytes |
packet_sequence:u64 | payload_length:u16 |
fragment_index:u8 | fragment_count:u8

type 为 DATA=1, KEEPALIVE=2, CLOSE=3, ERROR=4。非 DATA 必须使用 fragment_index=0, fragment_count=1。DATA 能完整承载一个 WireGuard packet 时同样使用 0/1;超出 negotiated max_frame_payload 时切成不超过 255 个 fragment,同一 packet 的所有 fragment 使用相同单调 packet_sequence、从 0 开始的 index 和固定 count。接收端按 (source session, packet_sequence) 有界重组,默认 2 秒超时,并限制同时重组 packet/bytes;重复、越界、count 改变或超时丢弃并记稳定 reason。packet_sequence 和重组不替代 WireGuard replay protection。Relay 不解析、合并或压缩内层 packet。

#5.5 Relay 失败与撤销

  • route/session lease revoke:立即拒绝新 DATA,已排队 frame 丢弃并发 relay_lease_revoked;
  • capacity limit:拒绝新 attach 或限速,返回 relay_capacity_limited,不返回 unauthorized;
  • target detached:返回 relay_peer_not_ready,不泄漏目标身份或是否存在;
  • carrier fail:ns 可选择另一已授权 Relay route,不能复用旧 opaque IDs;
  • Relay 日志只记录 opaque session、bucket、bytes、reason 和 request ID,按短期保留策略清理。

#6. ServiceFlow Protocol v1

#6.1 双端投影

Consumer Service projection 包含目录、VIP/FQDN、授权 frontend、健康 Endpoint 和每 Endpoint 的 ServiceFlowCredential。Publisher projection 使用 role=publisher,至少包含:

service_id, endpoint_id, publisher_membership_id,
local_manifest_id/revision/digest,
allowed credential issuers/audiences,
protocols, public/target ports, L7 enforcement mode,
generation, service_projection_digest,
input revision, kernel/evaluator/compiler provenance,
not_before, expires_at

Publisher 不接收完整 User/Group 目录。允许来源由凭据自证,并受 publisher projection 的 issuer/audience/resource/constraint 上限约束。

#6.2 ServiceFlowCredential

每个 ServiceFlow 必须携带签名 ServiceFlowCredential,claims 至少为:

issuer, deployment_id, organization_id, network_id,
source_kind, source_id,
optional source_session_key_hash,
service_id, endpoint_id, publisher_audience,
actions, protocol, allowed_public_ports,
grant_rule_id, input_revision,
kernel_version, evaluator_kind/version, compiler_version,
generation, service_projection_digest,
issued_at, not_before, expires_at, credential_id

source_kind 首版为 membership|federated_binding|ingress_binding|machine_principal。普通 membership 必须与已认证 carrier 的 source Membership/key epoch 一致;不能把从另一条 peer path 窃取的 credential 作为 bearer token 重放。federated_binding 必须带资源方签发的 opaque external subject 和 source_session_key_hash,建流 carrier transcript 证明持有对应短期会话私钥;不得携带消费方 User/Group/Device/Membership 目录 ID。凭据不含 backend origin。Publisher 使用已下发 key chain 本地验签,并校验 source kind、会话 proof、audience、Service/Endpoint、协议/端口、generation/digest、时间和本地 Manifest;每流不得查询 NSD。

#6.3 建流握手

Consumer 在已认证 peer/Relay path 上发送:

{
  "type": "service_flow.open",
  "version": 1,
  "flow_id": "random-128-bit",
  "service_id": "svc_01",
  "endpoint_id": "ep_01",
  "protocol": "tcp|udp",
  "public_port": 443,
  "credential": "signed-service-flow-credential",
  "client_nonce": "...",
  "deadline_ms": 10000
}

Publisher 返回 service_flow.accept,包含 flow_id、server_nonce、endpoint_revision、generation、idle_timeout_ms、max_datagram;或返回 service_flow.reject,包含稳定 code、retryable 和 request/flow ID。Accept 之后才把本地应用连接视为远端已建立。

校验顺序固定为:版本 → 凭据签名/expiry → audience/scope → generation/digest → Service/Endpoint → local Manifest → protocol/port/L7 constraint → backend availability → resource limits。安全错误优先于 backend 探测,避免用错误差异枚举 backend。

#6.4 数据与关闭

  • TCP 使用一个双向 stream;两个方向按 §3.3 独立 half-close;
  • UDP 使用同 flow_id 的 datagram,publisher 维护 source tuple 与 backend tuple 映射;双方执行同一 idle timeout;
  • Publisher backend connect 失败返回 service_backend_unavailable,不返回 unauthorized;
  • Endpoint 在途变 unavailable 时,新流停止;已有流按健康 drain,安全 revoke 则立即 reset;
  • Consumer 只对尚未 accept 的 flow 尝试其他健康 Endpoint;已 accept 且传输过字节后不透明重放。

#6.5 换代

Service projection 使用 current/next/optional previous generation。默认 security_first:收紧授权时先停签旧凭据并在 activation epoch 拒绝旧代;仅明确配置的 bounded_drain 可在不超过 credential TTL 的窗口继续已有流。

每代的 Service/Endpoint、来源、协议、端口、L7 constraint 和 Manifest digest 独立校验。Publisher 绝不能 union 两代。metadata-only 变更可保留 generation,但必须提升对象 revision。

#6.6 首个直接 ServiceFlow 执行切片

2026-08-09 的 ns-next@d4d8681c 提供了一个有界实现证据:两个 Linux network namespace 使用 userspace WireGuard 和 purpose=service_flow 的 PeerPath;Node projection 的 egress/ingress Grant 均为空。Source 的原始 ICMP 与任意 TCP 在封装前以 service_transport_only 拒绝,而授权 TCP Service 经 Consumer projection/credential、Publisher projection 和节点本地 Manifest 的交集校验后到达 127.0.0.1 backend。

该切片使用专用 TCP carrier 和 length:u32be + canonical CBOR 的 OPEN/ACCEPT/REJECT 子集,只证明双端授权结构、校验顺序、Manifest 上限、 generation/digest 绑定和“无 Node L3 Grant 仍可访问授权 Service”。它不 替代 §3.1 的 runtime-only QUIC 要求,也不证明完整 v1 framing、UDP、 half-close、VIP/DNS、Relay carrier、HA、生产 NSD 编译、撤销或 bounded_drain。后续实现不能把该临时 TCP carrier 固化为最终协议,亦不能 据此解除 G2、G3、G4、G7 或 G9。

六个测试构建专用单谓词翻转分别覆盖 Consumer projection、Publisher projection、credential scope、local Manifest、service_projection_digest 和 security-first generation;生产 binary 不包含这些入口。原始 manifest、 pcap、日志和 mutation 结果归档在 ns-next/evidence/service-flow/ 20260809-d4d8681c/。

同一证据包还包含 Publisher 独立拒绝场景。NSD fixture 签发一份在 Consumer projection 内有效、但与 Publisher service_projection_digest 不一致的 credential。该 OPEN 在 Publisher decrypted boundary 记录 6 个 packet,在 Publisher OS daemon carrier 记录 12 个 packet;Publisher 返回 稳定 ProjectionMismatch,客户端响应为空,loopback backend pcap 为 0。 这证明 Publisher 不依赖 Consumer 的准入结果,并在 backend dial 前执行本地 最终判定。

Publisher ServiceFlow 校验运行在 daemon 接收专用 carrier 之后,所以本场景 允许 carrier 进入 Publisher OS;它禁止的是未授权 OPEN 到达 backend。原始 Node L3 packet 的 publisher_os=0 判据属于 §4.3 的另一执行边界,不能套用到 ServiceFlow OPEN。以上补强仍只属于 authorization/admission 证据,§3.3 和 §6.3–§6.5 的最终 QUIC stream/datagram、directional half-close、reset、 no-replay、换代 drain 继续保持 evidence_blocked。

#6.7 Direct QUIC TCP 子集证据

ns-next@8af9779be95488fc208bf0fbbc8746f80b79e2d2 已将 §6.6 的临时 TCP carrier 替换为签名 PeerPath 绑定的 direct QUIC runtime。双方执行精确证书固定 的 mTLS、nsio-flow/1 ALPN、early_data=false 和 Runtime Hello;Hello 绑定 Membership、WG key epoch、共同 pair epoch、双方 transport revision 与 inner source IP。每个 TCP ServiceFlow 使用一个 bidirectional stream,OPEN 与 ACCEPT/REJECT 先于应用 bytes,Consumer 精确核对 response version、flow ID 和 generation。

focused test 已证明 Consumer/Publisher 两个方向独立 half-close、稳定 reset 收敛、ACCEPT 后传输 1 byte 再断 carrier 不重新拨 backend/不重放、nonce replay 拒绝、replay cache 容量上限,以及错误 OPEN major/超长 frame 关闭 connection 且 backend 零拨号。Linux 互操作继续证明无 Node L3 Grant 时授权 Service 可用, 以及 Publisher 在 backend dial 前独立拒绝 projection mismatch。完整证据位于 ns-next/evidence/service-flow/2026-08-09-8af9779b/,归档提交为 ns-next@e0a06e57。

该证据只解除 direct TCP 子集的证据阻塞。§3.3 的 UDP datagram/idle、经 Relay/WSS 的 runtime carrier、multi-endpoint retry、security-first/bounded-drain 代际切换、生产 revoke reset、平台 reserved-port 隔离、VIP/DNS、内核 WireGuard、NAT/漫游和移动端仍未验证,不得从本节推断整个 ServiceFlow 已完成。

#6.8 Relay-carried QUIC TCP 子集证据

ns-next@b99c93d5 在不改变 §6.7 Runtime Hello、OPEN/ACCEPT、Consumer 与 Publisher 双端授权的前提下,允许同一 runtime QUIC TCP ServiceFlow 运行在 opaque Relay 承载的 userspace WireGuard peer path 上。Runtime 启动先创建 direct-path 观察与 Relay fallback supervisor,再等待 Service runtime ready;Relay attach 只把 精确 WG peer endpoint 切到本地 shim,不把 Relay ready 当成 Service ready。

Linux 证据使用不可路由 direct endpoint 强制进入 Relay,证明原始 Node L3 仍被 Source 拒绝、精确 Service 到达唯一 backend connection、Relay 仅看见 opaque route/session 与 ciphertext。单判定伪造 direct-connected 后 Relay 被跳过,Service 与 backend 同时保持不可达,证明没有隐藏 fallback。

Relay 在 Service ACCEPT 且一个应用 payload 已被 backend 接收后被终止时,Relay 失败通过 runtime supervisor fail-closed 上送;在证据固定的 2 秒 keepalive、10 秒 idle timeout 内客户端失败,backend 不重连、不收到后续 payload,也不重放已接受 payload。本行为不是 transparent migration:v1 当前不会为已接受 TCP flow 自动换 Relay、重建 backend 或重放 bytes。

完整证据由 ns-next@d2e08c12 归档于 ns-next/evidence/service-relay/2026-08-09-b99c93d5/。它不证明真实 NAT/防火墙触发、direct↔Relay/WSS 漫游、WSS、UDP ServiceFlow、HA/drain、生产撤销、 内核 WireGuard 或移动端;这些能力继续按 §11 和 Gate 表保持阻塞。

#7. RouteFlow 公共传输补充

Route 的角色投影、凭据和换代以 Runtime Protocol 为权威,已达到授权互操作闭合。本文只补传输:

  • TUN packet 经已认证 peer path 到 Connector;Connector 从 peer session 映射 source Membership,并校验随 route session 建立发送的 RouteAccessCredential;
  • TCP/UDP/ICMP packet 保持原 IP 语义,NAT mode 只由 Connector projection 决定;
  • 代理型 application route 可以复用 ServiceFlow stream/datagram,但 resource kind 和 credential 仍是 Route,不能拿 Service credential 打 Route;
  • TCP half-close、UDP idle、MTU、backpressure 和 retry 使用 §3;
  • Route generation/digest mismatch 返回 route_projection_mismatch,不回落到普通本地路由。

#8. Gateway 派生协议

#8.1 Gateway Egress

Egress 是 publisher_audience=gateway_egress:<activation_id> 的 ServiceFlow。Consumer 用 ServiceFlowCredential 向 NSGW 自证;NSGW 另持本地 EgressOriginLease,claims 至少包含 issuer、gateway/activation、Service/Endpoint、origin allowlist digest、host/IP/port、DNS resolver/pin policy、TLS/SNI policy、source Network、generation/config digest、limits、issued/expiry、credential ID 和 revoke key。NSGW 同时校验 Capability Lease、两份凭据和实际解析/连接目标;客户端不能在 flow open 中提供超出投影的任意 origin。

EgressOriginLease 不发送给公网 origin,因为 origin 不是 NSIO executor,不会验证 NSIO credential;它是 NSGW 本地向外连接的短期授权。IngressBackendCredential 则必须在线发送给后端 publisher ns,让独立执行者验证 NSGW 身份。因此两者在安全结构上对称(均限制 NSGW 的下一跳),在线形态有意不对称,不能为了命名统一而把 Egress lease 暴露给 origin,或把 Ingress credential 降成 NSGW 自审。

Egress 停用只停止该 Endpoint 新流;内部 Service 对象和其他 Endpoint 保留。Origin/DNS 故障返回 egress_origin_unavailable,凭据/目标越界返回 egress_scope_violation。

#8.2 Gateway Exit

Client projection 至少包含 selection、gateway/profile、scope/CIDR、control/DNS/private bypass、IPv4/IPv6 policy、gateway tunnel key/endpoint、generation、exit_projection_digest 和 ExitTunnelLease。NSGW projection 至少包含 tunnel audience/source Membership、允许 key epoch、同一 scope/CIDR digest、NAT/forwarding/DNS capability、generation/digest、limits 和验签材料。两端不接收对方的完整候选或用户目录。

ExitTunnelLease claims 至少包含 issuer、deployment/organization/network、source Membership、gateway/activation/profile、scope、CIDR set digest、tunnel WG key epoch、generation、exit_projection_digest、issued/not-before/expiry、selection revision、credential ID 和 revoke key。Lease 与 client/NSGW projection 必须三方绑定同一 generation/digest;只拿到 tunnel key 或候选不构成 forwarding authorization。

执行归属固定为双端:

  • ns 负责选择对应 scope 的系统 capture、控制/DNS/private bypass、IPv6 guard 和 fail-closed;
  • NSGW 从已认证 tunnel key epoch 映射 source Membership,强制内层 source 等于分配的 tunnel identity,并按同一 scope/CIDR digest 校验 destination、NAT/forwarding;
  • 任一端 scope 不匹配都拒绝,不能以另一端“已经检查”作为放行理由。

安装顺序固定为 control/gateway bypass → tunnel/interface → IPv6 guard(需要时)→ scope capture;撤销/关闭反序执行,任何中间失败保持已有 capture/guard 的安全状态并显示具体 ownership。ns 只有在精确验证 capture、bypass、guard、tunnel 和 lease 后才能 ACK runtime ready;NSGW 只有在 listener/tunnel、scope、NAT 和 lease 验证后才能 ACK gateway ready。

Lease 续期不改变 generation。profile/scope/key 改变创建 next generation:NSGW 先 staging 并 ACK,ns 再建立 next tunnel,双方 ready 后原子切 capture;每代 scope 独立,绝不能 union current/next CIDR。additive 变更可以有界重叠,restrictive/revoke 使用 security_first,立即停签旧 lease、阻止旧代新流并按策略 reset/drain 已建流。撤权/安全收紧保持 ns capture fail-closed,只有用户明确关闭 Exit 才恢复标准连接。

候选读取失败、无授权、已授权但 unavailable、projection mismatch、tunnel unavailable、capture conflict 和 IPv6 external-managed 是不同状态。控制面断线时只在双方 projection/lease 未过期且本地真实状态仍通过时继续;过期后 NSGW 停止 NAT/新流,ns 保持已安装 capture/guard 并显示“出口范围流量已阻断”或基于真实 capture 说明未捕获,不能自动本地直出。

#8.3 Public Ingress backend

NSGW 完成 EdgeAuthPolicy 后,以 source_kind=ingress_binding 的 IngressBackendCredential 建 ServiceFlow。claims 额外绑定 application_id、binding_lease_id、edge_policy_revision、edge_identity/session/credential 的可撤销索引和允许 host/path/method 摘要。

Publisher 最终只校验 Ingress Binding 是否被其 Service projection 接受,不获得外部完整身份目录。NSGW 可向 backend 注入签名 EdgeIdentityContext,backend 应用只能用它做审计/应用内授权,不能交换成 Network Membership。

Ingress 安全 revoke 对新流立即生效,并按 application/policy/binding/identity/credential 索引 reset 在途流;普通维护 drain 使用 ServiceFlow 半关闭语义。

#9. 稳定错误

CodeRetryable含义
data_protocol_unsupportedfalse无共同安全 major/capability
credential_invalidfalse签名、audience 或 scope 无效
credential_expiredfalse服务端时间判定过期
projection_mismatchtruecredential 与本地 generation/digest 不一致,等待投影同步
flow_not_authorizedfalse本地最终授权拒绝
endpoint_unavailabletrue已授权 Endpoint 当前不可用
runtime_transport_conflicttruedaemon 无法证明保留 runtime endpoint 由自己独占执行
transport_unreachabletruecarrier/path 不可达
relay_peer_not_readytrueopaque 目标 session 未就绪
relay_capacity_limitedtrueRelay 容量/公平使用限制
packet_too_largefalsepacket 超过 carrier 的有界分段总容量,不能在 negotiated frame/fragment 空间内表示
datagram_too_largefalse超过 negotiated datagram
flow_idle_timeouttrueUDP/stream idle 到期
flow_revokedfalse权威撤销要求终止
service_backend_unavailabletrueService backend 连接/健康失败
route_projection_mismatchtrueRoute generation/digest 不一致
egress_origin_unavailabletrueEgress origin/DNS 失败
egress_scope_violationfalseorigin 超出 Egress 配置
exit_scope_violationfalseExit packet 超出 profile/scope

错误 code 进入共享 registry。对外 message 本地化,协议只传 code、retryable、flow/request ID 和不泄密 details。

#10. 撤销与控制面断线

  • 权威 revoke 事务立即停止签发新 credential/lease,并通过 reverse dependency index 生成目标 delta/tombstone;不得等待 full compile;
  • 在线执行者 99% 在 60 秒内应用;遗漏事件由所有旧 peer/flow/gateway/share lease 最迟 5 分钟失效兜底;
  • 控制面断线时只使用未过期 current projection/credential,不新造 selector、endpoint 或 scope;
  • security revoke 立即 reset 匹配在途流;availability 故障只停止新流并按能力 drain;
  • 恢复连接先校验 epoch/revision 和 tombstone,再允许 lease 续签,旧备份不能复活已撤销流。

#11. 互操作与反向验收

每个实现必须用共享 fixture 和独立进程通过:

  1. Route 六要素矩阵逐项反向删字段,双方必须拒绝;
  2. Relay QUIC/WSS carrier 使用相同 32-byte frame;完整 packet 和多 fragment 重组逐字节一致,稳定 ID/重复/越界/count 变化/重组耗尽注入必须失败;
  3. direct → Relay → WSS → direct 切换时 1280-byte packet 不黑洞,TUN MTU 不抖;
  4. TCP 双向 half-close、大文件上传、gRPC/SSE/WebSocket、RST 和 abrupt carrier loss;
  5. UDP 顺序变化、丢包、idle、datagram too large 和 NAT rebinding;
  6. Service credential 跨 Service/Endpoint/audience/generation 重放全部失败;
  7. Publisher/Connector/NSGW 在 NSD 不可达时可本地验签,过期后 fail-closed;
  8. Egress 不能任意 CONNECT,Exit 双端 scope 任一放宽注入必须失败;
  9. Ingress revoke 能按应用、策略、Binding、身份和凭据终止在途连接;
  10. 两个团队仅依赖本规格与共享 schema 分别实现 producer/consumer,golden interop 全绿。

G2、G4、G5、G7、G9 在这些证据出现前保持阻塞。文档闭合不等于 transport 性能或真机行为已经验证。