enet-validator/docs/enet_protocol_current.md
OpenCode 9be449fda8 feat: crack all DMX/RDM frame fields; show mode now fully self-constructed
- analyze subcommand: offline replay/template field variance, diff, counter analysis
- DMX header fully decoded: port mask @0x20, port lens u16LE=512 @0x34/0x36, counter +1/frame
- RDM request frame fully decoded: counter=0, 0x20=02, 0x2A=0xCC, msgLen=24+PDL,
  checksum=0xCC+sum(0x3C..0x53+PDL) @0x53+PDL, pair copy rules
- Fix historical misreadings: RDM always starts @0x3C (not variable); no session-level
  frame check exists - earlier failures were wrong template + checksum off-by-one
- show mode: build_dmx_frame/build_rdm_frame2/rdm_pair_copy, zero template dependency
- Decode 47B register response and 42B event frames; doc enet_protocol_current.md rewritten
2026-09-11 12:53:36 +08:00

150 lines
6.4 KiB
Markdown
Raw Blame History

This file contains ambiguous Unicode characters

This file contains Unicode characters that might be confused with other characters. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.

# e:net 协议当前还原状态(截至 2026-09-11,全面逆向后)
本文档汇总基于抓包与当前程序实现的协议还原状态。
**2026-09-11 全面逆向结论:DMX 帧与 RDM 请求帧已 100% 字段破解,可零模板纯自构造。**
---
## 一、UDP/31772 通用信封(全部帧)
| 偏移 | 含义 |
|---|---|
| 0x00-0x03 | `"ENet"` magic |
| 0x04-0x07 | 帧类型 u32 LE(1=发现, 2=注册/宣告, 4=数据/RDM) |
| 0x08-0x09 | 00 00(常量) |
| 0x0A-0x0B | 目标端口 u16 LE = 31772 (0x7c1c) |
| 0x0C-0x11 | 全 0 |
| 0x12-0x13 | 01 00(常量) |
| 0x14-0x15 | 帧总长 u16 LE(如 1084=0x043c, 47=0x002f, 42=0x002a) |
| 0x16-0x17 | 00 00 |
| 0x18-0x19 | 子类型 u16 LE(01=主机→Butler 数据, 02=Butler→主机应答/注册回执) |
---
## 二、DMX 数据帧(1084B,主机→Butler,全破解)
| 偏移 | 含义 | 备注 |
|---|---|---|
| 0x00-0x19 | 通用信封 | type=4, 子类型=01 |
| 0x1A-0x1D | 帧计数器 u32 LE | **每帧 +1,任意起始值**(1031 帧实证);与 r1/r2 无关 |
| 0x1E-0x1F | 00 00 | 常量 |
| 0x20-0x21 | 01 01 | 端口使能 mask(port1+port2) |
| 0x22-0x25 | r1 u32 LE | 随机数,port1 加密种子 |
| 0x26-0x29 | r2 u32 LE | 随机数,port2 加密种子 |
| 0x2A-0x2D | 00 00 00 00 | 常量 |
| 0x2E-0x2F | 01 00 | 常量(实测 02 也被接受 → Butler 不校验) |
| 0x30-0x31 | 00 00 | 常量 |
| 0x32-0x33 | 01 00 | 常量 |
| 0x34-0x35 | 00 02 | port1 数据长度 = 512(u16 LE) |
| 0x36-0x37 | 00 02 | port2 数据长度 = 512(u16 LE) |
| 0x38-0x3B | 01 00 00 00 | 常量 |
| 0x3C-0x23B | port1 密文 512B | `agios_dmx_encrypt(p1, r1, B12)` |
| 0x23C-0x43B | port2 密文 512B | `agios_dmx_encrypt(p2, r2, B12)` |
**加密**:`rot=(B12^r)&511; out[i]=src[(i+rot)%512]^cnt[i]`(zPprv0TXRRW 序列)
---
## 三、RDM 请求帧(1084B,主机→Butler,全破解)
| 偏移 | 含义 | 备注 |
|---|---|---|
| 0x00-0x19 | 通用信封 | type=4, 子类型=01 |
| 0x1A-0x1F | **全 0** | RDM 帧计数器恒 0(424 帧实证) |
| 0x20 | **02** | RDM 请求标志(DMX 帧为 01) |
| 0x21 | 00 | 常量 |
| 0x22-0x23 | qseq u16 LE | 查询序号,逐请求 +1 |
| 0x24-0x29 | 全 0 | DMX 帧的 r1/r2 槽位,RDM 清零 |
| 0x2A | **CC** | 常量(隐式 RDM StartCode 的外显位置) |
| 0x2B-0x2D | 00 00 00 | 常量 |
| 0x2E-0x2F | 01 00 | 常量 |
| 0x30 | 00 / 01 | 成对发送标志:主帧=00,紧跟的副本=01 |
| 0x31-0x33 | 00 00 00 | 常量 |
| 0x34-0x37 | msgLen+1 u32 LE | 如 PDL=0 时 = 25 (0x19) |
| 0x38-0x3B | 01 00 00 00 | 常量 |
| 0x3C | 01 | RDM SubStartCode |
| 0x3D | msgLen | = 24+PDL(含隐式 0xCC 起始码,不含 checksum) |
| 0x3E-0x43 | 目标 UID | 广播=ff×6 |
| 0x44-0x49 | 源 UID | 主机=45 3a 7f ff ff ff(副本末字节 -1) |
| 0x4A | TN | 事务号 |
| 0x4B | port | 主帧=00,副本=01 |
| 0x4C | msgCount | 00 |
| 0x4D-0x4E | subDevice | 00 00 |
| 0x4F | CC | 命令类(0x10=Discovery, 0x20=GET, 0x30=SET) |
| 0x50-0x51 | PID | BE(0001=UNIQUE_BRANCH, 0002=MUTE, 0003=UN_MUTE, 0060=DEVICE_INFO, 00F0=DMX_START_ADDRESS…) |
| 0x52 | PDL | PD 长度 |
| 0x53.. | PD | 参数数据 |
| 0x53+PDL | checksum u16 BE | `0xCC + Σ(0x3C .. 0x53+PDL)` |
| checksum 之后 | 任意填充 | Butler 不读(实测垃圾/零均可) |
**成对副本规则**(SL 实测):主帧之后紧跟一副本,差异仅 0x30=01、0x4B=01、srcUID 末字节 -1,**checksum 不重算**。
---
## 四、RDM 应答帧(Butler→主机,已可解码)
- 信封子类型=02,0x1A-0x1D = `"Butl"` 标记。
- 0x28-0x29 = RDM 数据区长度 u16 LE;数据区 @0x2A。
- 数据区首字节 0xAA = DISC 脉冲(0xAA/0x55 位交织编码,checksum 在 17B 内);否则为标准 RDM 应答(CC@0, CC字段@0x14, PID@0x15-0x16, PDL@0x17, PD@0x18)。
- DEVICE_INFO PD 布局(19B):protocolVer(2) model(2) category(2) swVer(4) **footprint(2)@+10** personality(2)@+12 **DMX地址(2)@+14** 保留(2) **传感器数@+18**。
---
## 五、注册应答 47B(Butler→主机,线上 89B,全破解)
| 偏移 | 含义 |
|---|---|
| 0x00-0x19 | 通用信封:type=2, 子类型=02, len@0x14=47 (0x2f) |
| 0x1A-0x1D | 设备 IP(LE 逆序字节)= 192.168.123.1 |
| 0x1E-0x23 | 设备 MAC = 00 16 1c f1 2e 39 |
| 0x24 | 00 |
| 0x25-0x28 | 主机 IP(LE 逆序)= 192.168.123.113 |
| 0x29-0x2E | 主机 MAC = 30 0e d5 59 bb 36 |
## 六、42B 事件帧(Butler→主机,部分破解)
type=4, 子类型=02, len=42 (0x2a), `"Butl"`@0x1A:
- 0x20-0x23 = 事件码(已见 0x0318 / 0x0062),其余尾字节 01 00 00 00 00 00。
- 事件码语义未解码(不影响功能)。
---
## 七、AECH 认领(已破解)
`G(x) = x ^ TABLE[(x%32 + 1 + (x*13)%30) % 32]`;nonce/B12 主机自选随机;AERE 应答 @0xC0 == G(nonce)。
真机固件过滤:仅应答源 IP=192.168.123.113 的 AECH。
---
## 八、历史误区更正(2026-09-11)
1. ~~"RDM 请求消息起始位置可变 (UN_MUTE@0x3A vs BRANCH@0x3C)"~~ → **错误**。424 帧实证全部 SubSC@0x3C,结构固定。
2. ~~"Butler 帧级校验会话一致性,verbatim 才能过"~~ → **错误**。纯自构造帧全通。之前失败根因:
- `sl_get_exact.hex` 是 DMX 数据帧被误当 RDM 模板;
- 旧 `build_rdm_frame` checksum 求和范围多算 1 字节(含模板残留的旧 checksum 槽位)。
3. ~~"0x2E 是节点序号且必须为 2"~~ → 实测 SL 原帧恒为 01,设 02 也被接受,Butler 不校验此字段。
---
## 九、仍不确定(不阻塞功能)
| 项 | 状态 |
|---|---|
| 1947 端口 40B 许可令牌 | 暖会话下**非必需**(当前 show 不发也工作);Butler 冷启动/重启后是否必需未验证 |
| EUCE 6s 广播 | 暖会话下**非必需**(同上) |
| bind52 / ident102 | 暖会话下**非必需**(最小认领 announce144→AECH 即可) |
| 42B 事件码 0x0318/0x0062 语义 | 未解码 |
| NFM680S 通道数漂移(曾见 2ch/1ch) | 近期稳定 1ch,疑早期解析误判;未复现深究 |
| announce 时间戳/会话 ID 是否参与校验 | 按实测填充新鲜值即可;严格性未消融 |
---
## 十、纯自构造实现
`src/hostdemo.rs`:
- `build_dmx_frame()` — 零模板 DMX 帧
- `build_rdm_frame2()` — 零模板 RDM 请求帧
- `rdm_pair_copy()` — 成对副本
`HOSTDEMO_MODE=show` 已切换到纯自构造,**运行不再依赖 replay 文件或任何抓包模板**(除 announce144/claim 等静态注册帧,这些也可后续自构造化)。