enet-validator/docs/enet_protocol_current.md

7.7 KiB
Raw Blame History

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 输出口对序号(SL 抓包=01;实测 01/02 均被接受)

⚠ 两个 DMX 口数据区独立:port1 @0x3C、port2 @0x23C。灯具接在哪个口就吃哪个口的数据。 实测灯具在 port2 时只发 port1 会导致灯具保持旧值/兜底白色——show 模式已改为双口同时输出。 | 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。
  • 事件码语义未解码(不影响功能)。

六b、心跳 36B(主机→Butler,全破解)

type=2, 子类型=03, len@0x14=36 (0x24):

  • 0x1A-0x1D = 主机 IP(LE 逆序)
  • 0x1E-0x23 = 主机 MAC
  • 周期 ~1-6s,会话保活。

六c、发现请求 180B(部分破解)

type=1, len=180 (0xb4):0x1A 起为主机名 ASCII(如 "tony"),其余字段未解码。


七、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 广播 暖会话下非必需(同上);540B 结构未解码
bind52 / ident102 暖会话下非必需(最小认领 announce144→AECH 即可);bind flag ffff/0000 语义未知
217B 发现应答 仅知含 "Butler S2" 名 + MAC,全字段映射未解码
644B announce 除 timestamp@0x235 / 会话ID@0x21D / 主机IP@0x41 外大量字段未解码
552B AECH 认领 仅 IP@0x1A / nonce@0x88 / B12@0x8C 已知,其余未解码
552B AERE 应答 resp@0xC0=G(nonce) 已验证;0xB0-0xBF 重复值对、0xC5 起 0x0af0 重复,语义未知
42B 事件码 0x0318/0x0062 语义 未解码
Butler 冷启动是否必须完整前奏(45s 广播+bind+ident+EUCE+1947) 未验证
NFM680S 通道数漂移(曾见 2ch/1ch) 近期稳定 1ch,疑早期解析误判;未复现深究
announce 时间戳/会话 ID 是否参与校验 按实测填充新鲜值即可;严格性未消融

已证伪的旧猜测(曾列入待办,本轮排除):

  • RDM 变长起始 → 固定 0x3C
  • 会话级帧校验 → 不存在
  • 0x2E 严格校验 → 不校验(1/2 均接受)

十、纯自构造实现

src/hostdemo.rs:

  • build_dmx_frame() — 零模板 DMX 帧
  • build_rdm_frame2() — 零模板 RDM 请求帧
  • rdm_pair_copy() — 成对副本

HOSTDEMO_MODE=show 已切换到纯自构造,运行不再依赖 replay 文件或任何抓包模板(除 announce144/claim 等静态注册帧,这些也可后续自构造化)。