本文定义 ns、Relay NSGW、Egress/Exit/Ingress NSGW 之间可独立实现和互操作的数据面契约。控制对象和投影以 Runtime Protocol v1 为权威;访问命中以 PolicyKernel 为权威。本文只固定建路、建流、凭据、本地执行、传输失败和撤销。
network byte order。首版公共控制消息使用 canonical CBOR;Relay 固定帧头和数据 payload 是二进制。每个协议面单独维护 major version。任一数据面只有六格全部填写并有反向测试才是 contract_closed:
| 数据面 | 双端角色投影 | 自证凭据 | 本地最终判定 | Digest 绑定 | 换代 | 禁止跨代 union |
|---|---|---|---|---|---|---|
| L3 Node | source egress / target ingress Grant + netmap | PeerPathLease + Membership/key binding | 双端按 peer/Membership/packet 判定 | peer/grant revision group | peer epoch 重叠轮换 | 是 |
| Route | client / connector | RouteAccessCredential | connector 校验 source + exact destination | route_projection_digest | security-first / bounded-drain | 是 |
| ServiceFlow | consumer / publisher | ServiceFlowCredential | publisher 校验 source + Service + Endpoint + Manifest | service_projection_digest | security-first / bounded-drain | 是 |
| Relay | source session / destination session | RelayRouteLease | Relay 只校验 opaque route/session/limits | relay_route_digest | 短期 pair epoch | 是 |
| Egress | consumer / egress gateway | ServiceFlowCredential + EgressOriginLease | NSGW 校验 Service + origin allowlist | Service + egress config digest | ServiceFlow 规则 | 是 |
| Exit | client / exit gateway | ExitTunnelLease | ns capture 与 NSGW scope/NAT 双端校验 | exit_projection_digest | tunnel generation | 是 |
| Ingress backend | ingress gateway / publisher | IngressBackendCredential | publisher 校验 Binding + Service + Endpoint | ingress + Service digest | security-first revoke / bounded drain | 是 |
“角色投影”指双方收到不同的最小执行材料,不是把完整策略图复制给两端。“禁止 union”指执行者不能为了平滑升级把两代允许目标、来源或 scope 合并成更宽集合。
| 用途 | 首选 carrier | 回退 | 内层安全 |
|---|---|---|---|
| L3 direct | WireGuard UDP | Relay | WireGuard |
| Relay | QUIC DATAGRAM/TLS 1.3 | WSS binary message/TLS 1.3 | WireGuard packet |
| ServiceFlow | peer WireGuard path 内的 runtime-only QUIC stream/datagram | 外层 WG 可经 Relay/WSS | peer path + flow credential |
| RouteFlow | peer WireGuard path 的原始 IP packet;代理型 Route 可用 runtime QUIC | 外层 WG 可经 Relay/WSS | peer path + route credential |
| Exit | WireGuard tunnel | 被授权 Relay transport | WireGuard + Exit lease |
| Ingress external | TLS/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 不是靠命名约定隔离,平台实现必须选择并证明以下执行方式之一:
ns 在 WireGuard 解密后、注入 TUN/OS 前按目标 Node IP、保留 UDP port 和 QUIC ALPN 截获;匹配 packet 永不进入 OS socket table;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。
首版 active Profile 的系统 TUN MTU 固定为 1280,连接期间不因 direct、Relay、WSS、Wi-Fi 或蜂窝路径切换而改变。理由是保证 IPv6 最小 MTU,并消除“直连小包正常、切 Relay 大包黑洞”的路径相关行为。
ns 不向系统栈暴露大于当前所有候选路径都可承载的 MTU;packet_too_large,不能静默丢弃;TCP flow 的 bidirectional QUIC stream 先交换一条 length-prefixed OPEN 与 ACCEPT/REJECT;ACCEPT 后该 stream 两个方向只承载原始应用 bytes,不再混入控制 record。两个方向各自独立:
FLOW_HALF_CLOSE(direction) 语义并发送该方向 QUIC FIN,不能顺带关闭反向数据;closed_clean;FLOW_RESET(code) 并映射到 QUIC RESET_STREAM/STOP_SENDING application code,对端立即停止该流;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 无限延长已撤销凭据。
transport_unreachable;unauthorized、credential_expired、projection_mismatch、scope_violation 不重试同一目标;endpoint_unavailable、relay_capacity_limited、transport_unreachable 可在未超过 operation deadline 时换健康 endpoint;ns 通过 node.endpoint.report 上报:
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,缺任一项拒绝整条候选。
同 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。
peer_epoch_id,不要求 revision 数字相同;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;discovery.pong.v1,绑定 ping digest/transaction、target candidate ID、接收时观察到的 source socket address、sent_at 和 target discovery-key signature;不得向未经验证 ping 返回更大 payload;(peer membership, wg_key_epoch, candidate_id, observed path) 标为 probe-ready;随后必须完成标准 WireGuard 握手,probe 本身不创建数据面授权;(peer membership, wg_key_epoch, candidate_id);endpoint 变化先探测新路径,握手成功后原子切换;旧路径短时 drain,但不复制应用 packet;PeerPathLease 是签名的 transport authorization,不是 Node AccessGrant。claims 至少为:
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 的执行顺序固定为:
ns 将目标 Node IP 解析为当前 peer epoch,校验未过期 PeerPathLease(purpose=node_l3);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 均未过期时继续。
轮换对象状态为 prepared → projected → dual_accept → activated → retired|failed。新 key 由节点生成,NSD 只保存公钥和 epoch。
next prepared 后 NSD 才签发 activation epoch;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 和租户数据清单。
签名 claims:
relay_tenant_id 是 deployment-scoped 计量假名,不是 Organization ID。两端各拿只能表达自身方向的 lease;反向通信需要双向 lease 或一份显式 direction=bidirectional lease。Relay 本地验签、校验 session/route/direction/limits/expiry,不回查 NSD。
ns 建立 QUIC/TLS 或 WSS/TLS carrier;RELAY_ATTACH(version, relay_session_id, route_id, lease, client_nonce);token 放消息体,不放 URL/header log;RELAY_ATTACHED(server_nonce, max_frame, idle_timeout, lease_expiry);relay_peer_not_ready,source 可等待或选择其他 Relay;Relay v1 frame header 恰好 32 bytes:
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。
relay_lease_revoked;relay_capacity_limited,不返回 unauthorized;relay_peer_not_ready,不泄漏目标身份或是否存在;ns 可选择另一已授权 Relay route,不能复用旧 opaque IDs;Consumer Service projection 包含目录、VIP/FQDN、授权 frontend、健康 Endpoint 和每 Endpoint 的 ServiceFlowCredential。Publisher projection 使用 role=publisher,至少包含:
Publisher 不接收完整 User/Group 目录。允许来源由凭据自证,并受 publisher projection 的 issuer/audience/resource/constraint 上限约束。
每个 ServiceFlow 必须携带签名 ServiceFlowCredential,claims 至少为:
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。
Consumer 在已认证 peer/Relay path 上发送:
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。
flow_id 的 datagram,publisher 维护 source tuple 与 backend tuple 映射;双方执行同一 idle timeout;service_backend_unavailable,不返回 unauthorized;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。
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。
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 已完成。
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 表保持阻塞。
Route 的角色投影、凭据和换代以 Runtime Protocol 为权威,已达到授权互操作闭合。本文只补传输:
RouteAccessCredential;route_projection_mismatch,不回落到普通本地路由。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。
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;安装顺序固定为 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 说明未捕获,不能自动本地直出。
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 半关闭语义。
| Code | Retryable | 含义 |
|---|---|---|
data_protocol_unsupported | false | 无共同安全 major/capability |
credential_invalid | false | 签名、audience 或 scope 无效 |
credential_expired | false | 服务端时间判定过期 |
projection_mismatch | true | credential 与本地 generation/digest 不一致,等待投影同步 |
flow_not_authorized | false | 本地最终授权拒绝 |
endpoint_unavailable | true | 已授权 Endpoint 当前不可用 |
runtime_transport_conflict | true | daemon 无法证明保留 runtime endpoint 由自己独占执行 |
transport_unreachable | true | carrier/path 不可达 |
relay_peer_not_ready | true | opaque 目标 session 未就绪 |
relay_capacity_limited | true | Relay 容量/公平使用限制 |
packet_too_large | false | packet 超过 carrier 的有界分段总容量,不能在 negotiated frame/fragment 空间内表示 |
datagram_too_large | false | 超过 negotiated datagram |
flow_idle_timeout | true | UDP/stream idle 到期 |
flow_revoked | false | 权威撤销要求终止 |
service_backend_unavailable | true | Service backend 连接/健康失败 |
route_projection_mismatch | true | Route generation/digest 不一致 |
egress_origin_unavailable | true | Egress origin/DNS 失败 |
egress_scope_violation | false | origin 超出 Egress 配置 |
exit_scope_violation | false | Exit packet 超出 profile/scope |
错误 code 进入共享 registry。对外 message 本地化,协议只传 code、retryable、flow/request ID 和不泄密 details。
每个实现必须用共享 fixture 和独立进程通过:
G2、G4、G5、G7、G9 在这些证据出现前保持阻塞。文档闭合不等于 transport 性能或真机行为已经验证。