背景
#169 新增的 docs/CONTROL-PROTOCOL.md(v1 控制面协议)§3.1 将 --target 描述为 forward 动作的必填项:
--target — required for forward: the destination peer id (the id of a configured peer). Ignored for drop.
但守护进程的命令解析器 parseCommand(src/uds.zig)并不强制 --target。当 --action forward 而缺失 --target 时,PolicyEntry.target 取结构体默认值 0,而 0 == LOCAL_TARGET(本地 TUN 交付)。因此一条「本应转发到某 peer」的规则会被静默安装成「本地交付」规则;又因 policy add 是 fire-and-forget、无任何错误回包,调用方拿不到任何反馈。
证据(文件:行)
- 文档断言:
docs/CONTROL-PROTOCOL.md §3.1 "--target — required for forward"。
- 解析器不校验 target:
src/uds.zig:168-199 —— policy add 仅在 --src/--dst 缺失时返回 MissingArgument;--action forward 缺 --target 不报错,直接返回 .policy_add。
- target 默认 0:
src/policy.zig:20 target: u32 = 0。
- 0 即本地交付:
src/policy.zig:76-80 pub const LOCAL_TARGET: u32 = 0;(注释:"A PolicyEntry.target of 0 is local delivery")。
- peer id 必须非零:
src/config.zig:298-300(local_id/peer id 须非零且互不相同),故 0 不会是任何真实 peer,0 即 LOCAL_TARGET 这一语义无歧义。
applyAdd 不二次校验 target:src/uds.zig:654-665(仅检查容量后原样追加,不比对 peer 注册表)。
- CLI 无二次校验:
src/subnetra.zig:90 复用同一 parseCommand,故 subnetra CLI 同样不拦截(不会以 exit 2 退出)。
- 回显可见:
src/uds.zig:374-376 forward 规则序列化为 ... --action forward --target {d},policy show 会回显 --target 0。
复现
对运行中的 daemon 发送(任意语言/CLI 均可,下面用 CLI):
subnetra policy add --src 10.0.0.0/24 --dst 10.0.1.0/24 --action forward
subnetra policy show
# 输出: policy add --src 10.0.0.0/24 --dst 10.0.1.0/24 --action forward --target 0
命中 10.0.1.0/24 的报文随后会被交付到本地 TUN(LOCAL_TARGET),而非转发到目标 peer。
预期 vs 实际
- 预期(按文档「required」):缺
--target 的 forward 命令被拒绝(missing-argument / CLI exit 2),或文档明确说明守护进程不强制、缺省即本地交付。
- 实际:命令被静默接受,安装成
target=0(本地交付)规则;无回包、无 CLI 报错。
影响范围
建议(二选一)
- 代码侧(更贴合文档、更防误用,倾向此项):在
parseCommand 中,当 action == .forward 且未显式提供 --target 时返回 ParseError.MissingArgument(CLI 随即 exit 2,daemon 端按既有约定静默丢弃该行)。补一条解析单测覆盖 forward 缺 target。
- 文档侧(若刻意保留隐式默认):修订 §3.1,明确守护进程不强制
--target,缺省 target=0 表示本地交付(LOCAL_TARGET),并提示用 policy show 复核。
倾向方案 1:与文档「required」表述一致,杜绝「应转发却静默本地交付」的隐性误配。
严重度
Low(功能一致性 / 健壮性;无安全越权)。
由每周架构与安全评审(自动化)发现 · 评审日期 2026-06-29 · 基线 commit de42f8f · zig build test 全绿。
背景
#169 新增的
docs/CONTROL-PROTOCOL.md(v1 控制面协议)§3.1 将--target描述为forward动作的必填项:但守护进程的命令解析器
parseCommand(src/uds.zig)并不强制--target。当--action forward而缺失--target时,PolicyEntry.target取结构体默认值0,而0 == LOCAL_TARGET(本地 TUN 交付)。因此一条「本应转发到某 peer」的规则会被静默安装成「本地交付」规则;又因policy add是 fire-and-forget、无任何错误回包,调用方拿不到任何反馈。证据(文件:行)
docs/CONTROL-PROTOCOL.md§3.1 "--target— required forforward"。src/uds.zig:168-199——policy add仅在--src/--dst缺失时返回MissingArgument;--action forward缺--target不报错,直接返回.policy_add。src/policy.zig:20target: u32 = 0。src/policy.zig:76-80pub const LOCAL_TARGET: u32 = 0;(注释:"APolicyEntry.targetof 0 is local delivery")。src/config.zig:298-300(local_id/peerid须非零且互不相同),故0不会是任何真实 peer,0即 LOCAL_TARGET 这一语义无歧义。applyAdd不二次校验 target:src/uds.zig:654-665(仅检查容量后原样追加,不比对 peer 注册表)。src/subnetra.zig:90复用同一parseCommand,故subnetraCLI 同样不拦截(不会以 exit 2 退出)。src/uds.zig:374-376forward 规则序列化为... --action forward --target {d},policy show会回显--target 0。复现
对运行中的 daemon 发送(任意语言/CLI 均可,下面用 CLI):
subnetra policy add --src 10.0.0.0/24 --dst 10.0.1.0/24 --action forward subnetra policy show # 输出: policy add --src 10.0.0.0/24 --dst 10.0.1.0/24 --action forward --target 0命中
10.0.1.0/24的报文随后会被交付到本地 TUN(LOCAL_TARGET),而非转发到目标 peer。预期 vs 实际
--target的 forward 命令被拒绝(missing-argument / CLIexit 2),或文档明确说明守护进程不强制、缺省即本地交付。target=0(本地交付)规则;无回包、无 CLI 报错。影响范围
--target是强校验项,构造 forward 规则时漏传/取值失败将得不到任何错误,却静默改变路由——本应转发的目的网段被本地交付,造成黑洞或误交付,且只能靠policy show事后发现--target 0。建议(二选一)
parseCommand中,当action == .forward且未显式提供--target时返回ParseError.MissingArgument(CLI 随即exit 2,daemon 端按既有约定静默丢弃该行)。补一条解析单测覆盖forward 缺 target。--target,缺省target=0表示本地交付(LOCAL_TARGET),并提示用policy show复核。倾向方案 1:与文档「required」表述一致,杜绝「应转发却静默本地交付」的隐性误配。
严重度
Low(功能一致性 / 健壮性;无安全越权)。
由每周架构与安全评审(自动化)发现 · 评审日期 2026-06-29 · 基线 commit
de42f8f·zig build test全绿。