329 lines
44 KiB
Markdown
329 lines
44 KiB
Markdown
# 交接单 · 节点一键加入与分组准入(覆盖网络线 · 2026-09-18 规划棒)
|
||||
|
|
|
|||
|
|
> **归档号**:**131**(现核 04 目录最大 = 128;129 / 130 已被单 A / 单 B 两张交接单占用 ⇒ ⛔ 不补占、不重用)
|
|||
|
|
> **目标一句话**:把覆盖网络从「**两台机器手工配好的专线**」变成「**产品**」—— 任何人开一台节点服务器就能接入;节点按网分组、只允许指定节点加入;既能共建一张大网,也能各自独立组网。
|
|||
|
|
> **来源**:用户 2026-09-18 09:07 原话 ——「**b 要实现开启一台结点服务器,就能连上覆盖网络,这样做这个网络才有价值,结点可以设置分组只允许那些结点加入,既可以成为大覆盖网络也可以建立独立覆盖网络**」。
|
|||
|
|
> **性质**:**规划棒产物** —— 本单只做方案与判据,⛔ 零代码改动、⛔ 零服务器改动(规划与执行分离)。
|
|||
|
|
|
|||
|
|
---
|
|||
|
|
|
|||
|
|
## §1 用户口径(功能卡,⛔ 别改写成技术题)
|
|||
|
|
|
|||
|
|
| 问 | 答(用户原话/直接推论) |
|
|||
|
|
|---|---|
|
|||
|
|
| **谁用** | 开节点服务器的人(平台运维 / 被授权的用户) |
|
|||
|
|
| **在哪用** | 一台新机器上;以及节点自己的配置处 |
|
|||
|
|
| **要做什么** | ① 开一台节点服务器 ⇒ **就能连上覆盖网络** ② 节点**可设分组,只允许指定节点加入** ③ 既能成**大覆盖网络**,也能建**独立覆盖网络** |
|
|||
|
|
| **怎样算成功** | ① 新机器**一条命令**接入(⛔ 不是照文档改四处配置)② 名单外的节点**连不上**(结构性拒绝,不是"设了 ACL 但忘了")③ 两张网**互相看不见** ④ 大网 = 多组共用一个骨干;独立网 = 不共享任何骨干 |
|
|||
|
|
|
|||
|
|
**用户已拍板的选项**:2026-09-18 08:2x 问「要不要补、补哪个」⇒ 答复 **B(连"节点直连"一起补)**,⚠️ 且用户**明示 B 的缺点他已看到**(新增直连暴露面 = 命中 R5)。
|
|||
|
|
|
|||
|
|
---
|
|||
|
|
|
|||
|
|
## §2 只读前置(开工前必读,⛔ 别重做调研)
|
|||
|
|
|
|||
|
|
| # | 文件 | 为什么读它 |
|
|||
|
|
|---|---|---|
|
|||
|
|
| 1 | `src/net/relay/network.ts` | **网抽象唯一入口**:`ops` / `u:<userId>` / 其它显式名 三条分支;裸 `u` 是保留字 |
|
|||
|
|
| 2 | `src/net/relay/server.ts`(头部注释 + `dialers` 段) | **⑥ 网维度**:会话与端点表按 `<network>/<hostId>` 索引;`DIAL` 必须**同网 + 本网白名单** |
|
|||
|
|
| 3 | `src/net/relay/directory.ts` | 引导三级链(内置种子 → 签名目录 → 离线降级);`relays[]` 由 47 的 `127.0.0.1:3080` 签发 |
|
|||
|
|
| 4 | `src/net/relay/content/peer.ts` | `ContentPeerGroup` / `groupKeyOf` / `sameGroup`(组维度现状) |
|
|||
|
|
| 5 | `src/web/server.ts` §内容面装配段 | ⚠️ 现状:只接通 `local`;`peer` 诚实回"没有";`edge`/`region`/`origin` **未注入** |
|
|||
|
|
| 6 | `参数表_覆盖网络_20260917.md` | 唯一参数表(观测阈值 / 待测项 / 权限影响评估) |
|
|||
|
|
|
|||
|
|
> 🔬 **本棒已取证的三条硬事实**(⛔ 别当"待确认"):
|
|||
|
|
> ① **「分组准入」与「独立网络」的底层机制已在代码里** —— `dialers` 是 `Map<networkId, Set<hostId>>`,**没列到的网络一个都拨不动(默认拒绝)**,且跨网 `DIAL` **在"能不能拨"这一步就走不到**(**结构性隔离,不是策略性**)。
|
|||
|
|
> ② **「一键加入」不存在** —— 加入一台机器现在要手工做四件事(装单元 / 配密钥 / 写 `DSHS_RELAY_DIALERS` drop-in / DB 登记),全仓**无 join 类入口**。
|
|||
|
|
> ③ **「直连」与「P2P 取回」都不存在** —— `grep -i "punch|打洞|directPath"` 只命中 `addr-override.ts`(443 兜底**钉 IP**,不是打洞);内容面 `peer` 档在生产路径上**恒返回 undefined**。
|
|||
|
|
|
|||
|
|
---
|
|||
|
|
|
|||
|
|
## §3 范围与在册文件集
|
|||
|
|
|
|||
|
|
### 3.1 分期(**分期即权限分期**,⛔ 不许颠倒)
|
|||
|
|
|
|||
|
|
| 期 | 内容 | 是否命中 R5 | 为什么这么排 |
|
|||
|
|
|---|---|---|---|
|
|||
|
|
| **P1** | **一键加入** + **分组准入门面**(把已有的白名单机制产品化) | ⛔ **不命中**(零新增暴露面) | 用户要的核心价值("开一台就能连上")**全在这一期**,且能立刻开工 |
|
|||
|
|
| **P2** | **节点直连(打洞)** + **P2P 取回通道接线** | 🔴 **命中 R5**(新增直连监听/探测面) | 用户选 B 已含此项,但按 R5 须**先出评估**(见 §7);且它技术上依赖 P1 的"节点身份与准入" |
|
|||
|
|
|
|||
|
|
### 3.2 在册文件集(P1;⛔ 超出即停下报告)
|
|||
|
|
|
|||
|
|
- **新增**:`src/net/relay/join.ts`(加入流程编排:凭据校验 → 落地配置 → 注册)
|
|||
|
|
- **新增**:`src/net/relay/registry.ts`(准入凭据的签发/校验,**载荷不含密钥本体**)
|
|||
|
|
- **新增**:`scripts/overlay-node-join.cjs`(节点侧命令行入口)
|
|||
|
|
- **新增**:`scripts/overlay-node-admit.cjs`(控制面侧:签发准入凭据 / 写白名单)
|
|||
|
|
- **修改**:`src/net/relay/network.ts`(**只加** `networkId` 的形状校验与"网络注册表"读取,⛔ 不改既有三条分支语义)
|
|||
|
|
- **修改**:`src/web/routes/` 新增 `overlay-nodes.ts`(管理面 API:列出/批准/移除节点)
|
|||
|
|
- **修改**:`scripts/overlay-probe.cjs`(新增 `OBS-24` / `OBS-25`)
|
|||
|
|
- **修改**:`参数表_覆盖网络_20260917.md`(新增键与判据行)
|
|||
|
|
- **测试**:`test/overlay-join.test.mjs`(新增)
|
|||
|
|
|
|||
|
|
⛔ **P1 明确不碰**:`server.ts` 的 DIAL/白名单**语义**(只读取)、`wire.ts` 帧格式、`keys.ts` 既有语义、bwrap 参数、nginx/nft。
|
|||
|
|
|
|||
|
|
---
|
|||
|
|
|
|||
|
|
## §4 方案(技术路线)
|
|||
|
|
|
|||
|
|
### 4.1 缺口 1 · 一键加入
|
|||
|
|
|
|||
|
|
**现状**(加入一台机器的全部动作,全手工):
|
|||
|
|
① 装 relay / worker 单元 → ② 配节点密钥 → ③ drop-in 写 `DSHS_RELAY_DIALERS="<network>:<hostId>"` → ④ DB 登记 `dsh_hosts`
|
|||
|
|
|
|||
|
|
**目标形态**(一条命令):
|
|||
|
|
```
|
|||
|
|
dshs-node join --network <networkId> --invite <邀请凭据>
|
|||
|
|
```
|
|||
|
|
**内部四步(全自动)**:① 校验邀请凭据(签名 + 网络 + 有效期 + 一次性)→ ② 生成本机节点密钥(**私钥不出机**)→ ③ 落地本机配置 → ④ 向控制面注册并等待被列入白名单。
|
|||
|
|
|
|||
|
|
**关键设计(已定项,可推翻)**:
|
|||
|
|
- **控制面仍是权威单点**(用户既有口径「归属/租约/骨干资格只能控制面写」)⇒ 加入的**批准权在控制面**,节点侧只是"申请 + 自动落地"。
|
|||
|
|
- 邀请凭据 = 控制面签的 `(network, 有效期, 一次性 nonce)`,**载荷不含任何密钥本体**(照抄组密钥凭据的既有形态)。
|
|||
|
|
- **白名单由控制面派生**(不再手写 drop-in):控制面把"已批准节点集合"投影成 relay 的白名单配置并 reload ⇒ 手写 drop-in 退化为**应急通道**(保留,⛔ 不删)。
|
|||
|
|
|
|||
|
|
### 4.2 缺口 2 · 分组准入门面
|
|||
|
|
|
|||
|
|
**现状**:机制完整(按网分桶 + 默认拒绝),但**配置靠手写字符串**(如 `u:5:manager`),写错了长得像"这张网不存在"。
|
|||
|
|
|
|||
|
|
**目标**:把它变成**可管理的东西** —— ① 列出现有网与节点 ② 批准/移除节点 ③ 给节点的**分组**可改 ④ 独立网 = 新增一个 `networkId`,**零代码**(`isNetworkId` 已支持显式命名)。
|
|||
|
|
|
|||
|
|
**判据(⛔ 不许做成"策略性 ACL")**:跨网拒绝必须仍然是**结构性**的 —— 拒绝发生在"能不能拨"这一步,而不是"拨通了再查表"。
|
|||
|
|
|
|||
|
|
### 4.3 缺口 3 · 直连与 P2P(P2,命中 R5)
|
|||
|
|
|
|||
|
|
**现状**:⛔ 无打洞;内容面 `peer` 档**有账本无通道**。
|
|||
|
|
|
|||
|
|
**目标**:① 节点间交换候选地址 → 尝试直连 → 失败**判死**降级中继(⚠️ 照抄成熟做法,不发明)② 把 `peer` 档**接上真实取回通道**(这是"文件走 P2P 分发"成立的**唯一**前提)。
|
|||
|
|
|
|||
|
|
**红线**:⛔ 直连**不得**让任何节点反向进入别人的机器;直连只在**同网 + 双方都在白名单**时建立;⛔ 打洞**不得**绕过既有的身份强制与吊销。
|
|||
|
|
|
|||
|
|
---
|
|||
|
|
|
|||
|
|
## §5 判据(先红后绿;⛔ 不许事后补写)
|
|||
|
|
|
|||
|
|
| # | 判据 | 形状 | 先红腿(对**旧产物**) |
|
|||
|
|
|---|---|---|---|
|
|||
|
|
| **J1** | 邀请凭据**一次性** | 同一凭据第二次使用 ⇒ **拒绝**,原因码具名 | 旧产物无 join ⇒ 入口即缺 ⇒ **红** |
|
|||
|
|
| **J2** | 白名单**外**的节点**拨不动** | 未批准 `hostId` 拨号 ⇒ 拒绝(非超时、非静默) | 机制已存在 ⇒ 本腿**复验不新建** |
|
|||
|
|
| **J3** | **跨网结构性拒绝** | 跨网 `DIAL` 在"能不能拨"处被拒;两端观测面**零交集** | 同上 |
|
|||
|
|
| **J4** | 一条命令接入 | 新机器 `join` 后**两端观测面同时出现**该节点,且 `online=true` | 旧产物 ⇒ **红**(无入口) |
|
|||
|
|
| **J5** | **独立网零共享** | 新 `networkId` 与 `ops` 网:relay 侧**无共同 dialer 条目**、无共同会话 | 旧产物 ⇒ 用 `OBS-24` 断言 |
|
|||
|
|
| **J6** | 私钥**不出机** | 节点侧私钥文件权限 `0600`;凭据/请求载荷**逐字不含**密钥本体 | 照抄组密钥既有腿 |
|
|||
|
|
|
|||
|
|
**零回归三件套(每期收口必跑,三者都带 `--table`)**:`npm.cmd test`(Node 22)|`node scripts/overlay-failover-drill.cjs --scene all --table`|`node scripts/overlay-probe.cjs --table`(**开工基线 = 23 PASS / 0 SKIP / 0 FAIL**)。
|
|||
|
|
|
|||
|
|
---
|
|||
|
|
|
|||
|
|
## §6 步骤(每步自带验收 + 回滚)
|
|||
|
|
|
|||
|
|
### P1(⛔ 不命中 R5,可立即开工)
|
|||
|
|
|
|||
|
|
- **S1 · 网注册表与节点清单**(只读面先行):控制面能列出「有哪些网、每张网有哪些节点、谁已批准」;探针可断言。⇒ 验收 = 探针新判据绿 + 零回归。
|
|||
|
|
- **S2 · 准入凭据**(签发/校验):控制面签发 + 节点侧校验;一次性 + 有效期 + 网络绑定。⇒ 验收 = `J1` 先红后绿。
|
|||
|
|
- **S3 · join 编排**:一条命令完成四步;失败**必须具名**(⛔ 不许静默拒绝)。⇒ 验收 = `J4`。
|
|||
|
|
- **S4 · 白名单派生**:控制面把已批准集合投影成 relay 白名单并 reload;手写 drop-in 退化为应急通道。⇒ 验收 = `J2`/`J5`。
|
|||
|
|
|
|||
|
|
### P2(🔴 命中 R5,**S5 前必须先出权限影响评估并经用户点头**)
|
|||
|
|
|
|||
|
|
- **S5 · 直连候选交换 + 打洞探测**:同网 + 双向白名单前置;失败判死降级中继。
|
|||
|
|
- **S6 · `peer` 档接线**:把真实取回通道接上(⚠️ 接线后**必须复算块 id**,否则命中本线老病根"假绿")。
|
|||
|
|
- **S7 · 规模回归**:候选数、切换时间、回源字节三项复测(本线已有基线读数可比)。
|
|||
|
|
|
|||
|
|
---
|
|||
|
|
|
|||
|
|
## §7 权限影响评估(R5 · **P2 专用**;⛔ P1 不适用)
|
|||
|
|
|
|||
|
|
1. **扩了什么**:新增**节点间直连探测**(新增监听/出站探测行为)。⚠️ 具体端口/协议在 S5 设计时定,**届时逐条列出**,⛔ 不在此处含糊带过。
|
|||
|
|
2. **谁受影响**:仅**同网且双向在白名单**的节点之间;⛔ 不对公网开放、⛔ 不跨网、⛔ 不影响租户实例的既有隔离面。
|
|||
|
|
3. **有没有不扩大也能实现的方案**:**有 —— 就是本期不做直连**(跨机流量继续走中继)。⇒ 直连的**唯一收益 = 省中继带宽 + 让 P2P 成立**;⛔ 若用户不接受新增暴露面,P1 已交付的"一键加入 + 分组准入"**仍然完整可用**。
|
|||
|
|
4. **回滚方式**:删直连配置 → reload → 行为回落"全部走中继"(秒级);验收 = 探针直连判据归位 + 零回归三件套。
|
|||
|
|
|
|||
|
|
> ⚠️ **用户已知悉**:2026-09-18 08:2x 选 B 时,B 的缺点里**明确写了**"需要新开直连端口 = 扩大暴露面、命中 R5、必须单独点头"。⇒ 本单执行到 **S5 之前**会**再停一次**(给当时的具体端口/协议清单),这是 R5 的硬要求,⛔ 不是重复提问。
|
|||
|
|
|
|||
|
|
---
|
|||
|
|
|
|||
|
|
## §8 回报格式(执行棒回填;⛔ 只填空,不改小节点名)
|
|||
|
|
|
|||
|
|
### 8.1 开工门(必填)
|
|||
|
|
- 本单 §8 前前缀 = **`085e28b56a08aa1f01999bdb3e238911`**(2026-09-18 09:2x 现算;与 **§11.2 逐字一致 ✅**)
|
|||
|
|
- 抢锁结果 = **抢到**(`--claim-exec "执行棒P1-节点一键加入与分组准入-0918"`,锁空闲)|开工时刻 = 2026-09-18 09:2x|执行棒名 = **执行棒P1-节点一键加入与分组准入-0918**
|
|||
|
|
- 开工基线现核:`git rev-parse --short HEAD` = **`09ce76f`**(未提交改动 = 上棒遗留的 `_tmp_seq24/`、`_中间产物_待清理/`)|`npm.cmd test` = **201/200/0/1**|探针 = **23 PASS / 0 SKIP / 0 FAIL**
|
|||
|
|
|
|||
|
|
### 8.2 逐判据回报(J1–J6 各一条,含**原始读数**)
|
|||
|
|
- **J1 邀请凭据一次性** —— 先红腿:`lib` 里把 `consumeNonce` 的 `flag:'wx'` 改成 `'w'` ⇒ 单测 **B1/B2 双红**,原文 `⛔ 竞态未守住:ok=12(须恰好 1)`(12 进程真并发)⇒ 后绿腿:还原后 `B1/B2` 绿,且 33/33 全绿、`lib` md5 逐字一致 `951a2526789b897aa58e3abbb5dea332`。真机腿:`chain47.sh` 步(6) 原文 **`✗ apply 失败:invite-already-used — nonce d4019b3c… 已被用掉(一次性凭据,⛔ 不重复受理)`**(rc=1)⇒ **判定:绿**。
|
|||
|
|
- **J2 白名单外的节点拨不动** —— **本腿复验不新建**(机制已存在):`OBS-06` 判别器 `dial=0 dialDenied=0 dialFailed=0`(都是 number)+ `OBS-11` `relay 口绑定回环=1/1 条`。⚠️ **"新节点真机拨不动 / 批准后拨得动"这一条未在生产 relay 上执行**(见 §8.4、§8.6)。
|
|||
|
|
- **J3 跨网结构性拒绝** —— 复验:`derive` 产物按网分桶(`network.ts#normalizeDialers` 同一入口),三网原文 **`[lab-net] DSHS_RELAY_DIALERS=lab-net/lab-1`|`[ops] …=ops/lab-1`|`[u:5] …=u:5/lab-1`** ⇒ 零交集;`OBS-25` 读得 `自审 auditOk=true 跨网共享=0`。⇒ **判定:绿(结构性,非策略性 ACL)**。
|
|||
|
|
- **J4 一条命令接入** —— 先红腿 = 旧产物无 `join` 入口 ⇒ 红(具名 `missing required --file`);后绿腿 = `chain47.sh` 步(4) 原文 **`✓ join 成功:lab-net/lab-1|公钥 e18630527a6f7b5f…|四步 4/4`**,四步 `verify-invite / node-key / local-config / register` 全 `✓`。⚠️ **"两端观测面同时出现 + online=true"未在生产 relay 上执行**(同上)。
|
|||
|
|
- **J5 独立网零共享** —— 真机步(9)原文:三张网各得**自己那条**、⛔ 无共同条目;步(10) 注册表全貌 = `ops(approved 1/pending 0) · lab-net(…1/0) · u:5(…1/0)`,三条记录的键分别是 `lab-net/lab-1` / `ops/lab-1` / `u:5/lab-1`。`OBS-24` 五项:形状合法 ✅|派生自审一致 ✅|pending 未进派生 ✅|结构性错桶 **0** ✅|**派生桶数 0 ≡ 有 approved 的网数 0** ✅(生产注册表为空 ⇒ 本项在真机读的是"空表也自洽")。⇒ **判定:绿**。
|
|||
|
|
- **J6 私钥不出机** —— 真机原文:**`FLAG: 申请单里私钥出现次数(须 0)= 0`**|**`FLAG: 节点私钥权限(须 600)= 600`**|邀请 `doc` 键 = `['expiresAt','issuedAt','network','nonce','version']`(⛔ 无任何密钥)|selfcheck `application.bytes=533 / hasPrivateKey=0 / shapeOk=true / hostMatches=true`|`nodeKeyModeOk=true`(Linux 权限腿成立)。⇒ **判定:绿**。
|
|||
|
|
|
|||
|
|
### 8.3 零回归三件套(三者都带 `--table`)
|
|||
|
|
- `npm.cmd test` **201/200/0/1**(rc=0;Node 22.22.2,与开工基线**逐字一致**)|`--scene all` **12P/0S/0F**(rc=0;幕4-C 实测 19370ms / deadline 30000ms)|探针 **24P/1S/0F**(**rc=0**)
|
|||
|
|
- ⚠️ **探针与开工基线(23P/0S/0F)的差** = 本棒新增 `OBS-24`/`OBS-25` 两条 **+2P**,但 `OBS-09` 由「在册」退化为「不在册 ⇒ SKIP」**−1P/+1S**。**FAIL 数同为 0**。归因与未复原说明 ⇒ **参数表 §11.4-②**。
|
|||
|
|
|
|||
|
|
### 8.4 恢复形态核实
|
|||
|
|
- **派生侧**(真机 `/tmp` 表外链路):三张网各 1 条、零共享;批准前派生为**空**(`Environment="DSHS_RELAY_DIALERS="`)⇒ 「收单 ≠ 批准」成立。
|
|||
|
|
- 🔴 **relay 侧**:**未执行**——⛔ 未把派生产物落到生产 `50-overlay-dialers.conf`、⛔ 未 reload relay(**P1 硬门 D1「不改任何生产值」**)⇒ **"新节点加入后两端观测面同时出现 / 端点表新增条目 / `used` 变化" = 未验证**(⛔ 不编数)。
|
|||
|
|
- 参考读数(本次运行**演练后**的现网状态,⚠️ 与本棒改动无关):`capacity {max:7515, used:2, free:7513, utilPct:0}`|`online = [manager(ports= 空), w-106(ports=19000)]`|`endpoints` **1 条**(`w-106 port=19000 localPort=43061 online=true`)。
|
|||
|
|
|
|||
|
|
### 8.5 边界自证(**逐条打勾**)
|
|||
|
|
- ⛔ 未 commit / push(R7):`git rev-parse --short HEAD` = **`09ce76f`**(与开工一致)|`git status --short` = 3 个 `M`(`overlay-probe.cjs` / `index.ts` / `network.ts`)+ 5 个 `??`(`overlay-node-admit.cjs` / `overlay-node-join.cjs` / `join.ts` / `registry.ts` / `test/overlay-join.test.mjs`)—— **全部在册**,⛔ 无越界文件 ✅
|
|||
|
|
- ⛔ 未改任何生产值(D1):⛔ 无 drop-in 改动、⛔ 无 env 改动、⛔ 未 reload 任何单元**配置**。⚠️ **如实补记**:本棒**新增了状态目录** `/var/lib/dshs/overlay/`(`nodes.json` 0644 + `consumed/` + `selfcheck.json`)—— 它是 §3.10 登记的**状态**(非配置);⛔ 未覆盖任何既有文件 ✅
|
|||
|
|
- ⛔ 未新增公网监听口、未动 nft·nginx(R5):`OBS-11` PASS 原文 `nft accept 0 多出 0|relay 口绑定回环=1/1 条` ✅
|
|||
|
|
- 🔴 `RELAY_FAILOVER_COOLDOWN_MS=0` 计数 = **0**(`grep -c` 在 `overlay-node-admit.cjs` / `overlay-node-join.cjs` / `overlay-probe.cjs` / `test/overlay-join.test.mjs` / `registry.ts` / `join.ts` / `network.ts` **七个文件上全部 = 0**)✅
|
|||
|
|
- ⛔ 未改 bwrap 参数(`grep -c "bwrap\|perms"` 在 `registry.ts` / `join.ts` = **0 / 0**)✅
|
|||
|
|
- 🔴 密钥本体不经网络 / 不经 relay:申请单内私钥出现次数 **0**|邀请 `doc` 无密钥键|`OBS-25` 私钥泄露=0 ✅
|
|||
|
|
|
|||
|
|
### 8.6 如实留档(**必填,哪怕"没有"**)
|
|||
|
|
- **未做的项**:`src/web/routes/overlay-nodes.ts`(管理面 API)**未建** ⇒ 本棒**自决**移入 P2(理由:与 P1 硬门「零新增暴露面」冲突风险最高;`S1–S4`/`J1–J6` 验收均不依赖它;交接单 §7 本身即 P2 专用)。⚠️ **可推翻**。
|
|||
|
|
- **未测的项**:① 「派生落盘 ⇒ relay reload ⇒ 新节点真能拨通」这条**生产闭环**(因 D1 硬门,见 §8.4);② 另见本单 **§10 未验证项**(4 条,本棒未新增未验证项)。
|
|||
|
|
- **过程中发现的额外问题(⛔ 只报告、未顺手改)**:
|
|||
|
|
1. 🔴 **控制面 CLI `--file` 键名混用**(真机缺陷,**已修 + 已补 E10 先红后绿**):`apply --file <申请单>` 曾把注册表文件也指到申请单 ⇒ 收单炸在第 4 步而 nonce 已被占位(对外 =「收单失败 + 同一张邀请再也用不了」)。修 = 覆盖键改名 **`--registry`**。**教训**:调库式判据(E9)**抓不到**参数解析类缺陷 ⇒ 必须有**CLI 级真回环**(E10)。
|
|||
|
|
2. ⚠️ **`OBS-24` 原拟判据没有判别力**("同一 `hostId` 出现在 ≥2 张网 ⇒ FAIL"实为**合法态**)⇒ 已降级为信息项,改判「结构性错桶=0」+「派生桶数 ≡ 有 approved 的网数」。
|
|||
|
|
3. 🔴 **本次零回归演练的副作用(**本棒唯一未复原项**)**:`OBS-09` 由 PASS 变 SKIP。**归因有原文**:演练后 `OBS-01/04/08` 转红 ⇒ 执行恢复(47 `restart dshs` + 106 `restart dshs-worker`)⇒ 三者回绿,但 106 worker 重注册读数由 `accepted=[19000,21000]` 变为 `accepted=[19000]`(实例端口 21000 的注册未随进程重建)。✅ 两端实例 `:20000`/`:21000` **都在监听**、门户 **200**,**无业务中断**。**回头条件** = 下一棒收口若仍 SKIP 或出现「跨机实例面访问不通」⇒ 升级独立小项(先查"实例 → 本地 worker 端口注册"链路)。详 ⇒ 参数表 **§11.4-②**。
|
|||
|
|
|
|||
|
|
### 8.7 指纹
|
|||
|
|
- 参数表 §10 指纹(**现算并同步**)= **`695dcb4d88a778840322bc221417d339`**(口径:`sed '/^## §10 指纹/,$d' 参数表_覆盖网络_20260917.md | md5sum`)|本单全文 md5(**写入本行前现算**)= **`2344d947499745a5c1e5a5cb56d0b274`**/**236 行**(⚠️ 写入本行后即失效 ⇒ 引用前**现算**);§8 前前缀 **回填后仍 = `085e28b56a08aa1f01999bdb3e238911`**(不变量,已复算 ✅)
|
|||
|
|
|
|||
|
|
### 8.8 收口复核(**序㊱ 收口复核棒 · 2026-09-18 10:0x–10:4x**;⛔ 只复核,⛔ 未开工 P2)
|
|||
|
|
|
|||
|
|
- **开工门复核**:本单 §8 前前缀 = **`085e28b56a08aa1f01999bdb3e238911`**(现算,与 §8.1/§11.2 逐字一致 ✅)|抢锁 = **抢到**(`--claim-exec "收口复核棒-序36-P1-OBS09"`,锁空闲)|现核基线 = HEAD **`09ce76f`**、`git status --short` = **10 处**(3 `M` + 7 `??`,与 §8.5 逐数相同)
|
|||
|
|
- **① `OBS-09` 复核 + 复原(逐段原文)**
|
|||
|
|
- **开工读数**(10:1x):`SKIP OBS-09 在册实例面 无 (阈值 ∈ {200,401})|不在册 2 项:本机:20000,对端:21000`|`/status` 端点表 **1 条** = `w-106 port=19000 localPort=43061 online=true` ⇒ 与 §8.6-3 / 参数表 §11.4-② **记录一致**。
|
|||
|
|
- **链路取证(「实例 → 本地 worker 的端口注册」)**:端口集 = `staticPorts + forwarded`(`worker/agent.ts:323`)|106 `/healthz` 原文 = **`{"hostId":"w-106","instances":0,"tunnel":{"ready":true,"ports":[19000]}}`** ⇒ **worker 自己认不到实例**(`instances=0`)⇒ `reconcileTunnel()`(`agent.ts:257-263`,20 s 一跳)拿不到 `live` 端口 ⇒ **永不 `forward(21000)`**。根因链(原文级):`orchestrator.ts:558 listUserInstances() = [...this.mains.values()]`,而 `rehydrateAdoptedScopes()` 认领时**只写 `this.adopted`(:1492)⇒ ⛔ 不进 `mains`** ⇒ 09:56:28 重启后实例 scope 被认领(`[rehydrate] adopted … port=21000` + `probe OK :21000`)但**平台侧不可见** ⇒ 端口不再声明。⇒ **这是候选 B 已知边界的直接后果**("不被杀 + 访问时自然替换",⛔ 非"重启后直接可用"),**⛔ 不是 relay 侧故障**(relay 全程正常,`OBS-12` RSS 70 MB)。
|
|||
|
|
- **复原动作(设计内路径 · 零代码 / 零配置改动)**:临时 session(`/opt/dshs/mksess.cjs guest`,**R4**)⇒ 一次真实用户可见面访问(`curl -H 'Host: guest.alotbuy.com' -b sid=…`)⇒ 10:18:34 `[dsh-child main] Running as unit: dsh-100002-7d1c8cbf.scope`(旧 scope `dsh-100002-2e9202dd` 被 `cleanStaleScopes` 收掉)⇒ 新实例走**正常 launch 路径**声明端口:`/healthz` = `{"instances":1,"tunnel":{"ready":true,"ports":[19000,21001]}}`|`/status` 端点表 = `{19000 ✓, 21001 ✓}`。**用户可见面 = http 200 / 62451 B / `502` 标记 0**(与 §8.12-4 同口径)|临时 session 已删(`DELETE 1` ⇒ 余 **0**)。
|
|||
|
|
- 🔴 **复原后第一次复跑仍 SKIP 的真因 = 判据输入过期(假 SKIP)**:替换落点漂到 **21001**(`spawn.ts#findFreePortInRange` 从 `DSHS_INSTANCE_PORT_BASE` 上扫第一个空闲口;替换发起时 21000 仍被旧 scope 占着 ⇒ 顺延),而 `OBS-09` 的"在册"按**表内固定端口**取 ⇒ 对不上。
|
|||
|
|
- **处置(事实优先,⛔ 不为了迁就旧值去重启生产实例)**:参数表 `PEER_INSTANCE_PORT` **实测替换 21000 → 21001**(+ `PEER_AGENT_PORT` 出处括注同步 `ports=19000/21001`);**§10 指纹** `695dcb4d88a778840322bc221417d339` → **`2ae954e2e07b47651a84e597c19a3444`**(现算并已同步写进 §10)。
|
|||
|
|
- **复原读数**:`PASS OBS-09 在册实例面 w-106:42717=401 (阈值 ∈ {200,401})|不在册 1 项:本机:20000` ⇒ **由 SKIP 回到 PASS ✅**。⚠️ `本机:20000` 恒"不在册"是**结构性**的(47 的 worker 不是 relay 客户端,§11.1 已钉死)⇒ ⛔ 不是缺陷。
|
|||
|
|
- **② 产物可复现**:`node --test test/overlay-join.test.mjs` = **33 tests / 33 pass / 0 fail / 0 skipped**(rc=0)|探针 **0 FAIL** ⇒ 两件都成立。
|
|||
|
|
- **③ 零回归三件套**:`npm.cmd test`(Node **22.22.2**)= **201 / 200 pass / 0 fail / 0 cancelled / 1 skipped**(与基线**逐字一致**)|`overlay-failover-drill.cjs --scene all --table` = **12 PASS / 0 SKIP / 0 FAIL**(幕4-C 实测 **17375 ms** / deadline 30000 ms)|`overlay-probe.cjs --table` = **25 PASS / 0 SKIP / 0 FAIL(rc=0)**。
|
|||
|
|
- **④ 🔴 演练副作用的同型复现与处置(如实记)**:`--scene all` 跑完后 **47 中继读数 = `ep=[] / used=1 / idOk=1`** —— 演练把 106 worker 的通道逼到了 **106 自己的中继**(106 中继 `sessions=["w-106"]` 原文可证)⇒ 若就此复跑,`OBS-01/04/08/09` 会**同型转红**(与 §11.4-② 同因)。**处置(⛔ 未重启任何 worker、⛔ 未换实例)**:停 106 `dshs-relay` ⇒ 逼它按候选链回落 47(实测 **~15 s** 后 `used=2 / idOk=2 / ep={19000 ✓,21001 ✓}`)⇒ 再启 106 `dshs-relay`(`active`,⚠️ 该单元在演练前是 inactive ⇒ 本棒把它留在了 active)。⚠️ 由此**点名一条观测缺口**:**探针只读 47 的 `RELAY_STATUS_URL`**,而 worker 可能挂在 106 的中继 ⇒ 47 视角"端点表为空"**⛔ 不等于"覆盖网络断了"**(潜在**假红**)。
|
|||
|
|
- **⑤ 边界自证**:⛔ 未 commit / push(HEAD **`09ce76f`**;`git status --short` = **10** 处,与开工逐数相同)|⛔ 未改任何生产**配置值**(无 drop-in / env / nft·nginx / bwrap 改动)|🔴 `RELAY_FAILOVER_COOLDOWN_MS=0` 计数 = **0**|🔴 密钥本体不经网络 / 不经 relay|⛔ 未开工 P2(P2 仍待用户拍板权限影响评估)。
|
|||
|
|
- **⑥ 如实留档(必填)**:
|
|||
|
|
1. 🔴 **`OBS-09` 的"在册"判据钉死了两个会漂移的端口** ⇒ 每次「访问时自然替换」后都可能变成**假 SKIP**(本棒连踩两次:端点表 `[]`→`21001`;同步表值只是把**输入**改对,⛔ **判据本身的脆弱性未治**)。⇒ 已点名 = **下一棒(序㊲)**:把"在册实例面"改为**从 `/status.endpoints[]` 派生该主机名下的在线实例端点**(⛔ 本棒按"只做被明确要求的事"未改判据)。
|
|||
|
|
2. ⚠️ **本棒对生产做了 3 个动作**(均属 **R8** 开发环境、动手前已声明):① guest 实例一次「访问时自然替换」(**设计内路径**,非人工杀实例)② 106 `dshs-relay` 停 / 启各一次(逼 worker 回落 47,约 1 min 单中继运行)③ 参数表**文档**值同步。⛔ 无不可逆操作、⛔ 无用户数据改动。
|
|||
|
|
3. ⚠️ **`--scene all` 会改变通道拓扑且演练自身不复原**(把 worker 逼到 106 中继)⇒ 每次跑完都要"回落 47"才算回到**可观测基线**;这一点建议写进演练脚本头部(⛔ 本棒未改脚本)。
|
|||
|
|
|
|||
|
|
### 8.9 收口复核(**序㊲ 执行棒 · 2026-09-18 11:0x–11:2x**;⛔ 只做 §8.8-⑥ 的两条点名,⛔ 未开工 P2)
|
|||
|
|
|
|||
|
|
- **开工门**:本单 §8 前前缀 = **`085e28b56a08aa1f01999bdb3e238911`**(现算,与 §8.1/§8.7/§8.8 逐字一致 ✅;⚠️ 口径 = `sed '/^## §8 /,$d' <本单> | md5sum`)|抢锁 = **抢到**(`--claim-exec "序㊲ 执行棒(观测面去常量依赖)"`,锁空闲)|现核基线 = HEAD **`09ce76f`**、`git status --short` = **10 处**(与 §8.8 **逐数相同**)
|
|||
|
|
- **① §8.8-⑥-1 点名(`OBS-09` 的"在册"判据钉死会漂移的端口 ⇒ 假 SKIP)—— 已消除**:判据改为**从 `/status.endpoints[]` 派生**「该主机名下、非 agent 端口的在线实例端点」,**每一个都必须可达**(码 ∈ `PROBE_CODE_SET`),**派生为空 ⇒ SKIP + 留痕**。**先红后绿(原文级 · 两侧逐行 diff 只差 `OBS-09` 一行)**:红 = `SKIP OBS-09 在册实例面 无 (阈值 ∈ {200,401})|不在册 2 项(记 SKIP 的依据):本机:20000,对端:21000`(夹具 = 表值回写成漂移前的 **21000** + 真实 47 `/status`(实例在 **21001**))|绿 = `PASS OBS-09 在册实例面(派生 1 条):w-106:42717=401 (阈值 ∈ {200,401})`。🔴 旧夹具口径(位置式)**已退役并硬报错**(rc=2);🔴 派生子**缺码 ⇒ FAIL 并点名**(拿旧端口的码糊弄不过去)。**收益实测**:复原后 `localPort` 由 **42717 → 44231**,探针**无须改表值**即回绿(⚠️ 这正是 §8.8-① "同步表值只治输入、不治判据"的对照)。
|
|||
|
|
- **② §8.8-⑥-2 点名(探针只读 47 中继 ⇒ `ep=[]` 时潜在**假红**)—— 已消除(两种情形**可分**)**:新增判别源 = **对端中继的 `/status`**(`ssh <SSH_TARGET_106> curl <RELAY_STATUS_URL>`,**只读回环**;⛔ **零新增暴露面、零新增参数键**;⚠️ **只在 47 视角为空时才去读** ⇒ 正常态**零额外 ssh**)。同一份 47 空表输入 ⇒ **三种可分输出**:**(甲)** 对端中继声明了端口 ⇒ `SKIP OBS-08 端点表 0 条 ⇒ SKIP + 留痕|… 对端中继(test106)声明了端口:w-106 ports=19000/21001 ⇒ 客户端挂在**另一台中继**上(⛔ 非故障、⛔ 不判红)`(**真机 · `--scene all` 演练态实测**:47 = `ep=[] / used=1 / idOk=1`,106 = `[w-106:19000, w-106:21001]`)|**(乙)** 两台中继都无该客户端会话 ⇒ `FAIL OBS-08 …(两台中继都无该客户端会话)`|**(丙)** 对端中继读不回来 ⇒ `FAIL OBS-08 …(不可判)`(⛔ 不许静默当绿)。⚠️ **旧口径在同态下 `OBS-08` 恒 FAIL**(`eps.length > 0`)⇒ 分不出两者,**这就是被点名的假红**。
|
|||
|
|
- **③ 零回归三件套**(都在**改动之后**跑;⚠️ `npm.cmd test` 无 `--table` 参数,另两件已带):`npm.cmd test` **201/200/0/1**(rc=0,**逐字一致**)|`overlay-failover-drill.cjs --scene all --table` = **12 PASS / 0 SKIP / 0 FAIL**(rc=0;幕4-C **18353 ms** / deadline 30000)|探针 = **25 PASS / 0 SKIP / 0 FAIL**(rc=0)⇒ **与基线逐数一致**(⚠️ 探针**不在** `npm test` 覆盖内,其零回归即此行)。
|
|||
|
|
- **④ 复原(按 §8.8-④ 同款;⛔ 未重启任何 worker、⛔ 未换实例)**:停 106 `dshs-relay` ⇒ **约 15 s** 后 47 视角回落 `used=2 / 端点 = [(19000, 39815), (21001, 44231)]` ⇒ 启回 106 `dshs-relay`(`active`)⇒ 探针回绿。⚠️ **演练态下 `OBS-01` / `OBS-04` 仍红**(`used=1` / `identityOk=1` < 各自阈值 2)—— 二者是**计数**判据、**⛔ 与"端点表为空"无关**,复原后即绿(详见「参数表_覆盖网络_20260917.md」§11.5-⑤-1)。
|
|||
|
|
- **⑤ 边界自证**:⛔ 未 commit / 未 push(HEAD **`09ce76f`**;`git status --short` **10** 处与开工逐数相同;本棒只动 `scripts/overlay-probe.cjs` **一个**仓内文件)|⛔ 未改任何生产**配置值**(参数表**值格一律未动**)|⛔ 未新增暴露面(`OBS-11 多出 0 缺失 0`、relay 口仍 1/1 回环)|🔴 `RELAY_FAILOVER_COOLDOWN_MS` 命中 **0**|⛔ 未开工 P2|🔴 密钥本体不经网络 / relay。
|
|||
|
|
- **⑥ 如实留档**:**`参数表_覆盖网络_20260917.md` §11.5** 已新增小节(零回归三件套 + ①② 原红绿原文 + 可分三态 + 边界自证 + 5 条留档;🔴 **§10 指纹** `2ae954e2e07b47651a84e597c19a3444` → **`71848fad4ee0d6a574d833169e042fd1`**,**现算并已同步**)。⚠️ 本棒另发现**一条文档口径歧义**(探针文件头总括称"夹具模式…把远端原文喂进来 ⇒ 不 ssh",但 `OBS-24`/`OBS-25` 的分支**无 `fixture` 守卫** ⇒ 未给各自夹具时会真去 ssh 取**生产读数**;⚠️ 这两项**各自的用法行**与代码一致,只有文件头那句总括与事实不符)⇒ ⛔ 按"只做被明确要求的事"未改、已在 §11.5-⑤-3 登记**二选一**建议。📁 证据 = 工作区 `_tmp_seq37/`。
|
|||
|
|
|
|||
|
|
### 8.10 收口复核(**序㊳ 执行棒 · 2026-09-18 11:3x–12:0x**;⛔ 只做用户拍板的两项收口,⛔ 未开工 P2)
|
|||
|
|
|
|||
|
|
- **① 探针夹具封闭性(✅ 用户拍 A 方案)**:`OBS-24` / `OBS-25` 两处取数由 `if (<夹具> !== undefined) { 读夹具 } else { ssh }` 改为 `… else if (fixture) { SKIP + 留痕 } else { ssh }`(**守卫排在 ssh 之前**);探针文件头新增「**封闭性**」硬约束段。**先红后绿(原文级 · 两侧逐行 diff 只差这两行)** —— 两侧同一份 `--table` 副本(`SSH_TARGET_47` / `SSH_TARGET_106` → `127.0.0.1`、`SSH_PORT` → `1` ⇒ **"是否 ssh"变成可观测差异**):🔴 红腿(守卫摘掉 = 还原序㊱ 形态)= `FAIL OBS-24 ❌ 注册表**读取失败**(⛔ 与"不存在"可分):Command failed: ssh -p 1 -o BatchMode=yes 127.0.0.1 …` + `ssh: connect to host 127.0.0.1 port 1: Connection refused`(真 ssh 调用 **2** 次)|🟢 绿腿(现产物)= `SKIP OBS-24 夹具模式未给 --nodes-fixture ⇒ SKIP + 留痕(⛔ 不去 ssh 读生产)`(真 ssh 调用 **0** 次)。**可分性** = 给**不存在**的夹具路径 ⇒ `FAIL … ❌ 注册表**读取失败**…:夹具不存在:…/NO_SUCH_nodes.json`(⛔ 不是 SKIP)。
|
|||
|
|
- **② 键名对齐**:参数表 `DRILL_RELAY_UNIT` → **`RELAY_UNIT_NAME`**(**值格未动**、仍 `dshs-relay`)⇒ ⛔ **零个新增 / 改动生产 env**;引用点 **3 处全改**(`overlay-failover-drill.cjs` + 原因注释 / `overlay-probe.cjs` / 参数表 §3.9 + 小节标题注 + §11.5-⑤-4 状态)。⚠️ **文档库档案不改**(`04-调整方案/117-…` / 归档单 `T13` 记的是**当时事实**)。**真机验证** = 原样取数命令 ⇒ `__RELAY_ACTIVE__=active` ✅。
|
|||
|
|
- **③ P2 待拍板清单已登记** ⇒ 见**本节 §8.11**(只登记、⛔ 零动作)。
|
|||
|
|
- **④ 零回归三件套**(改动**之后**跑):`npm.cmd test`(Node **v22.22.2**)= **201 / 200 / 0 fail / 0 cancelled / 1 skipped**(rc=0,**逐字一致**)|`overlay-failover-drill.cjs --scene all --table` = **12 PASS / 0 SKIP / 0 FAIL**(rc=0;幕4-C **20770 ms** / deadline 30000)|`overlay-probe.cjs --table`(真机)= **25 PASS / 0 SKIP / 0 FAIL**(rc=0)。⚠️ **复原**(按 §8.8-④ 同款,⛔ 未重启任何 worker、⛔ 未换实例):演练后 47 视角确为空 ⇒ 探针呈 **21P / 2S / 2F**(2F = `OBS-01 used=1`、`OBS-04 identityOk=1`,**计数**判据、⛔ 与"端点表为空"无关)⇒ **停 / 启 106 `dshs-relay`**(约 22 s 后 47 视角回落 `used=2 / identityOk=2 / 端点 = [(19000,33213),(21001,42783)]`)⇒ 探针回绿。🔑 **顺带取得键名改名的真机端到端证据**:演练态 `SKIP OBS-08` 原文含「对端中继(test106)声明了端口…」⇒ 判别器**真的走完了**真机分支那条 ssh(内含 `systemctl is-active ${RELAY_UNIT_NAME}`)✅。
|
|||
|
|
- **⑤ 边界自证**:⛔ 未 commit / 未 push(HEAD **`09ce76f`**;`git status --short` **11** 处 = 序㊲ 的 **10** 处 + 本棒新增 `scripts/overlay-failover-drill.cjs` 一处 `M`,**逐条可解释**)|⛔ 未改任何生产**配置值**(参数表**值格一律未动**)|⛔ 零新增暴露面|🔴 `RELAY_FAILOVER_COOLDOWN_MS` 命中 **0**|⛔ 未改 bwrap / nft / nginx|⛔ 未开工 P2|🔴 密钥本体不经网络 / relay。
|
|||
|
|
- **⑥ 如实留档**:**参数表 §11.6** 已新增小节(🔴 **§10 指纹** `71848fad4ee0d6a574d833169e042fd1` → **`2275870a5a9eb1964a648f2950dee528`**,**现算并同步**)|**§8 前前缀** `085e28b56a08aa1f01999bdb3e238911` **逐字不变** ✅(本节在截断点之后)。🔬 两条口径:① 本棒"红腿"用的是**同一份"ssh 目标不可达"的表副本** ⇒ ⛔ 未碰任何生产机(真 ssh **2 次**全部打在 `127.0.0.1:1`);② 既有夹具语义(`--instance-fixture` / `--peer-status-fixture` / 序㊲ 的 `OBS-08` 三态)**未受影响**(回归自证见参数表 §11.6)。📁 证据 = 工作区 `_tmp_seq38/`。
|
|||
|
|
|
|||
|
|
---
|
|||
|
|
|
|||
|
|
### 8.11 P2 待你拍板的具体内容(R5 权限影响评估 · **序㊳ 登记,⛔ 未开工**)
|
|||
|
|
|
|||
|
|
> **起因**:序㊳ 执行棒被点名"说下要定的具体内容"。本节把 **§7-1** 那句「具体端口/协议在 S5 设计时定,**届时逐条列出**」**提前落实成清单** —— 让拍板不必先读代码。⛔ 本节只登记,**不含任何动作**。
|
|||
|
|
|
|||
|
|
**已实测的三条事实**(拍板依据,全部来自本线既有读数,⛔ 非推演):
|
|||
|
|
|
|||
|
|
1. 🔴 **47 / 106 的云安全组拦 UDP 入站**(⛔ **不是** nft:`input policy = accept`)。证据 = 序⑥ S4:47 上 `0.0.0.0:21100/21101` UDP 观察器开放 ≈ 75 s、**零收包**(连同机发出的都收不到)⇒ 已关闭(`ss -lunp` 空)。
|
|||
|
|
2. **打洞成功率(现网实测 n=3 对、2/2 可打洞)**:对端→本机方向 **10/10 收包**;**本机→云机方向取不到**(= 事实 1 的直接后果)。⚠️ 样本里云节点占 2/3,**不代表家宽场景**。
|
|||
|
|
3. **云机↔云机(47↔106)本来就是 L1 直连、不是打洞场景** ⇒ 直连的收益面**只在"用户设备 ↔ 云节点"这一段**。
|
|||
|
|
|
|||
|
|
**要你拍的只有两件事**:
|
|||
|
|
|
|||
|
|
**① 要不要为打洞开「UDP 入站」的云安全组规则?**(这是本期**唯一**真正的门禁)
|
|||
|
|
|
|||
|
|
**A. 开**
|
|||
|
|
优点:打通"云节点 → 用户设备"这一方向,配合已是 10/10 的反方向 ⇒ 直连率接近业内值(0.90–0.94);S6「P2P 取回通道」才有成立前提。
|
|||
|
|
缺点:**新增入站暴露面**(UDP 端口可被公网扫描 / 发包);且必须在**云控制台**改安全组 —— 这一步 ⛔ 本平台代码侧自决不了。
|
|||
|
|
|
|||
|
|
**B. 不开**
|
|||
|
|
优点:**零新增暴露面**;P1 交付的"一键加入 + 分组准入"**仍然完整可用**。
|
|||
|
|
缺点:链路两端只要有一端是云节点就只能走中继 ⇒ 直连率显著下降、**省不了中继带宽**;S6 的 P2P 取回**失去成立前提**(内容分发继续走中继)。
|
|||
|
|
|
|||
|
|
**② 若选 A,入站 UDP 段的"来源范围"怎么定?**
|
|||
|
|
|
|||
|
|
**甲. 固定小段 + 对 `0.0.0.0/0` 放行**
|
|||
|
|
优点:规则最少、不会因对端 IP 变化而失效;实现最简单。
|
|||
|
|
缺点:暴露面最大(全网可扫该 UDP 段)。
|
|||
|
|
|
|||
|
|
**乙. 固定小段 + 仅放行对端节点 IP**
|
|||
|
|
优点:暴露面最小(只有白名单节点能发包),与本线"权限只准收窄"一致。
|
|||
|
|
缺点:云安全组规则数有上限;家宽 / 移动 IP 会变 ⇒ 需动态维护、规则会膨胀。
|
|||
|
|
|
|||
|
|
**丙. 不开 UDP,改走已建成的 443/TCP 兜底**
|
|||
|
|
优点:复用既有收口(零新增暴露面)。
|
|||
|
|
缺点:TCP 443 打洞成功率远低于 UDP,且 `addr-override.ts` 目前只做"钉 IP"、**不是打洞** ⇒ 事实上等于**不做直连**。
|
|||
|
|
|
|||
|
|
**影响面与窗口(R8 口径)**:改动只落在 **47 / 106 的云安全组 + 两台 relay 配置**上;⛔ 不碰租户实例隔离面、⛔ 不跨网、⛔ 不影响既有 443 收口。回滚 = 删直连配置 + reload ⇒ **秒级**回落"全部走中继"(§7-4)。⚠️ 时间窗可避开用户活跃时段。
|
|||
|
|
|
|||
|
|
**本棒倾向(陈述句,可推翻)**:**先拍 ①**。若你要的是"看到线上效果",最小可验证形态 = **A + 乙**(固定小段 + 仅对端 IP)—— 它同时满足"能打洞"与"暴露面最小";**甲** 留到"直连率被证明是瓶颈"时再放开。⚠️ 若你更看重**零新增暴露面**,选 **B** 也完全不亏 —— 代价只是"直连 + P2P"这两项功能不做,P1 已交付的能力不受影响。
|
|||
|
|
|
|||
|
|
---
|
|||
|
|
|
|||
|
|
|
|||
|
|
### 8.12 拍板落地(**2026-09-18 12:22 · 序㊴ 规划棒**;⛔ 未开工)
|
|||
|
|
|
|||
|
|
- **用户原话**:`1 用户可设置,默认开启提示用户 2 乙`
|
|||
|
|
- **⇒ §8.11 的两问已闭合**:
|
|||
|
|
- **① 开不开 UDP 入站** ⇒ 「**用户可设置 + 默认开启 + 提示用户**」—— ⛔ **不是**简单的"开"或"不开",而是把**开关交给用户自己**、平台**默认开**并**必须提示**(⇒ 产品口径见新单 §1);
|
|||
|
|
- **② 入站 UDP 段的来源范围** ⇒ **乙**(固定小段、**仅放行对端节点 IP**,⛔ **非** `0.0.0.0/0`)。
|
|||
|
|
- **⇒ 产物 = 本线第一份 P2 可执行单**:工作区根 **`交接单_覆盖网络直连与P2P_20260918.md`**(**归档号 132**;**§8 前前缀 `8925c2460810c6dc5cdbc075b6cdaed2`**;239 行)。⛔ **本单正文一字未改**(§8 前前缀 `085e28b56a08aa1f01999bdb3e238911` 仍是**不变量** ✅)—— **P2 的开工依据自此移交新单**,本单 §6 的 P2 三行粗描述**退化为指针**。
|
|||
|
|
- 🔴 **一条如实登记的技术现实**(同时写在新单 §4.5):**乙**要求云安全组按"**对端节点 IP**"放行,而**家宽 / 移动节点的公网出口 IP 会变** ⇒ 规则会失效、且规则数**有上限**。序㊴ **自决(可推翻)** = **乙-1 起步**:只对**有固定公网 IP** 的节点开(云节点 / 专线);**家宽节点本期走中继**(⛔ 不影响可用性,只影响"它能不能被直连")。**乙-2**(半自动)/ **乙-3**(云 API 自动化,🔴 **需云 AK/SK**)登记为新单 **§9 回头条件** —— ⛔ **本棒未请求任何凭据**。
|
|||
|
|
- ⚠️ **一条遗留(仅报告,⛔ 未动手)**:`dsh-server-docs/04-调整方案/.lock-131` **仍在**(序㊱ P1 的占号窗口未释放)⇒ 后果 = 后续取号者**永久跳过 131**(本棒已现核 ⇒ 取 **132**)。⛔ 本棒不动他人锁类目录,登记在此待处置。
|
|||
|
|
|
|||
|
|
---
|
|||
|
|
|
|||
|
|
## §9 回头条件(**一出现必须回头**)
|
|||
|
|
|
|||
|
|
1. 🔴 **任何一棒都不许把 `RELAY_FAILOVER_COOLDOWN_MS=0` 写进回滚 / 演练 / 夹具路径**(自锁:实测 121–123 s 无切换)。
|
|||
|
|
2. **要改 `server.ts` 的 DIAL/白名单语义**(而非只读取)⇒ **停下报告**(本单只做"配置派生 + 管理面")。
|
|||
|
|
3. **P1 阶段出现任何新增暴露面** ⇒ **停下报告**(P1 的前提就是零新增暴露面)。
|
|||
|
|
4. **跨网拒绝从"结构性"退化成"策略性"**(拨通了再查表)⇒ **立刻停手回滚**。
|
|||
|
|
5. **join 流程出现静默拒绝**(配置错伪装成"网络不通")⇒ **停下修,⛔ 不许带着上线**。
|
|||
|
|
6. **`peer` 档接线后块 id 未复算** ⇒ 判据**不算通过**(会把"零回源"做成假绿)。
|
|||
|
|
7. **要动 `wire.ts` 帧格式 / `keys.ts` 既有语义** ⇒ 停下报告(R7)。
|
|||
|
|
|
|||
|
|
---
|
|||
|
|
|
|||
|
|
## §10 未验证项(**一个都不许编数**)
|
|||
|
|
|
|||
|
|
| # | 未验证项 | 怎么验(口径) |
|
|||
|
|
|---|---|---|
|
|||
|
|
| 1 | 节点直连的**成功率与收益** | 需 P2 落地后测:直连成功比例、切换耗时、省下的中继带宽(⛔ 现无数据) |
|
|||
|
|
| 2 | **一次性凭据的并发竞争** | 同一凭据被两台机器同时使用 ⇒ 必须**恰好一台成功**(需并发夹具) |
|
|||
|
|
| 3 | **多网络下的容量口径** | `--max-hosts` 是**全局**还是**按网**?⇒ 需明确并写进参数表 |
|
|||
|
|
| 4 | **节点规模上限** | 本单不测;引用既有推演值(百台:L3 需中继 40–55)时⛔ 须标明是**推演**非实测 |
|
|||
|
|
|
|||
|
|
---
|
|||
|
|
|
|||
|
|
## §11 指纹与状态
|
|||
|
|
|
|||
|
|
### 11.1 归档号
|
|||
|
|
- **现核最大号**:`ls 04-调整方案/ | grep -oE '^[0-9]+' | sort -n | tail -1` ⇒ **128**(2026-09-18 09:0x 实测)
|
|||
|
|
- **占号**:`mkdir 04-调整方案/.lock-131` ⇒ **成功** ⇒ 本单归档号 = **131**(129 / 130 = 单 A / 单 B,⛔ 不重用)
|
|||
|
|
- ⚠️ **本棒不落 04 孪生**(与本线全部 `交接单_*.md` 一致)⇒ 占号窗口在落单后即释放,执行棒收官建档案时**须重新现核取号**
|
|||
|
|
|
|||
|
|
### 11.2 指纹
|
|||
|
|
- **§8 前前缀**(口径:`sed '/^## §8 回报格式/,$d' <本单> | md5sum`)= **`085e28b56a08aa1f01999bdb3e238911`**
|
|||
|
|
- ⚠️ **§8 回填后前缀不变、全文 md5 会变** ⇒ 全文 md5 **不写死**,权威取数 = 现算
|
|||
|
|
|
|||
|
|
### 11.3 状态
|
|||
|
|
- **本单状态**:**P1 已执行收官**(2026-09-18 10:0x · 执行棒 `执行棒P1-节点一键加入与分组准入-0918`);P2(S5–S7)**未开工**(命中 R5 ⇒ 必须先出权限影响评估并经用户点头)
|
|||
|
|
- **本棒(执行棒)边界自证**:⛔ 未 commit / 未 push · ⛔ 未改任何既有 drop-in / env / nft·nginx / bwrap · ⛔ 零新增公网监听口 · ⛔ 密钥本体不经网络(详见 §8.5)
|
|||
|
|
- **P1 出口项**:`src/web/routes/overlay-nodes.ts`(管理面 API)**本棒自决移入 P2**(理由见 §8.6;⚠️ 可推翻)
|
|||
|
|
- **🔴 本棒唯一未复原项**:`OBS-09` 由 PASS 退化为 SKIP(演练副作用,已归因、有原文;回头条件见 §8.6-3 与 参数表 §11.4-②)
|
|||
|
|
|
|||
|
|
### 11.4 与既有方案的关系
|
|||
|
|
- 本单**不取代**任何既有文档;`覆盖网络_骨干层方案_20260916.md`(骨干 ≤10–20 成员 + 选择性加入)与本单的"分组准入"是**同一件事的两个层次**:那份讲"骨干怎么选",本单讲"节点怎么进来"。
|
|||
|
|
- ⚠️ 与 `会合中继拆分_取证与改造方案_20260916.md`(S0–S4,入口 §2 标注为"第一优先 · 真活")**有交集**:本单 P1 的"白名单派生"会动到 relay 侧配置投影 ⇒ **执行前须与该方案的进度对账**,⛔ 不许两条线同时改 relay 配置面。
|
|||
|
|
|
|||
|
|
### 11.5 落单后实测
|
|||
|
|
- **§8 前前缀** = **`085e28b56a08aa1f01999bdb3e238911`**(落单后实测;⚠️ 本行在截断点**之后** ⇒ 改它不影响该不变量)
|
|||
|
|
- **落单快照**:全文 md5 **`ca4ca8aad292efaf02357e1e2dacb6da`**/**214 行**(2026-09-18 09:1x;⚠️ 本行写入后即失效 ⇒ 引用前**现算**)
|