跳转至

抓包、解码、一致性与版本迁移

协议验证的目标不是“工具能显示”,而是让第三方能够从原始证据重现:线上发送了什么、解析器为何接受或拒绝、应用最终采取了什么动作。

协议证据与一致性闭环

证据链

固定身份和配置
→ 保存原始电气或网络捕获
→ 独立解码
→ 对照规范与固定源码
→ 检查应用状态和计数
→ 构造边界与反例
→ 修正实现
→ 回归并归档

仅保存解码文本会失去原始帧边界和错误;仅保存原始字节又无法证明字段语义和应用行为。

测试对象清单

每次捕获建立记录:

测试编号:
日期、时间和时区:
协议与规范版本:
发送端硬件、固件、提交和配置:
接收端硬件、固件、提交和配置:
消息定义、方言或数据结构描述语言(DSDL,Data Structure Description Language)提交:
接口、电压、极性、速率、字符格式和单双工:
物理连接和探测点:
捕获设备、固件、采样率和解码器版本:
测试环境:离线 / SITL / HITL / 无功率级波形负载 / 独立CAN测试总线 / 拆桨隔离台架 / 不适用
安全隔离:
预期帧和预期应用行为:
原始文件:
摘要:
结论与限制:

不能在记录中保存密钥、口令或未脱敏的敏感位置。

三类捕获

电气波形

示波器或逻辑分析仪用于证明:

  • 电平;
  • 极性;
  • 位周期;
  • 边沿;
  • UART字符格式;
  • 半双工换向;
  • 总线争用;
  • 物理错误。

采样率、探头带宽和参考地必须足够。只看自动解码结果不能证明电气质量。

原始字节或CAN帧

保存:

  • 原始时间戳;
  • 方向或接口;
  • 原始字节;
  • CAN ID、扩展标志、数据长度码(DLC,Data Length Code)和数据;
  • 丢包或捕获溢出;
  • 捕获起止时间。

文本十六进制转储适合人工核对,但长期证据应保留机器可读原件和摘要。

应用日志

保存:

  • 解析成功和错误计数;
  • 消息更新时间;
  • 队列深度和丢弃;
  • 状态转换;
  • 命令接受、拒绝和原因;
  • 重连;
  • 资源负载。

应用日志是结果证据,不能替代线上原始捕获。

时钟对齐

比较飞控、逻辑分析仪、网络抓包和地面站日志前,要记录:

  • 每个时钟的来源;
  • 时区;
  • 单调时钟还是墙上时钟;
  • 分辨率;
  • 启动后的零点;
  • 同步误差;
  • 是否发生跳变。

可以使用同一可观察事件建立对齐点,例如:

  • 一次物理开关变化;
  • 一条唯一测试消息;
  • 电源上升沿;
  • GPIO标记;
  • 同时写入多个日志的标记。

对齐误差必须进入时延结论。毫秒级日志不能支持微秒级时序声明。

独立解码

至少使用两条独立路径中的两种:

  • 项目自身解析器;
  • 官方生成库;
  • 独立脚本;
  • Wireshark或其他分析器;
  • 手工按规范重算长度和校验。

两种工具显示相同结果仍可能共享同一个错误定义,因此还要核对固定规范和至少一个已知测试向量。

黄金样本

建立最小语料库:

  • 最短合法帧;
  • 最大合法帧;
  • 每个主要消息一个正常样本;
  • 载荷全零与尾零;
  • 边界枚举和最大数值;
  • 单帧与多帧;
  • 请求、成功响应和错误响应;
  • 带签名与不带签名;
  • 协议重启后的第一帧;
  • 稳态高负载片段。

每个样本附:

  • 原始字节;
  • 来源版本;
  • 预期解码;
  • 预期校验;
  • 允许或拒绝原因;
  • 是否包含敏感数据。

黄金样本必须固定,不能在测试运行时由待测解析器同时生成预期结果。

负面语料

至少包含:

  • 每个字节位置截断;
  • 声明长度不足和超长;
  • 单比特翻转;
  • 错误CRC或校验和;
  • 未知消息;
  • 未知标志;
  • 非法枚举;
  • 重复、乱序和过期;
  • 帧头嵌入载荷;
  • 连续噪声;
  • 内外层长度或校验不一致;
  • 多帧丢中间帧、错误Toggle或错误Transfer-ID;
  • 签名错误和重放;
  • 资源上限附近的合法输入。

通过标准不仅是“不崩溃”,还包括:

  • 不越界;
  • 不死循环;
  • 不分配无界内存;
  • 不执行部分命令;
  • 错误计数正确;
  • 能在后续合法帧处恢复;
  • 不把错误日志放大为拒绝服务。

解析器单元边界

解析层只应输出:

  • 完整已验证帧;
  • 明确错误类别;
  • 消耗字节数;
  • 是否需要更多输入;
  • 重同步状态。

业务层再处理:

  • 消息版本;
  • 字段范围;
  • 来源和权限;
  • 当前系统状态;
  • 动作和响应。

将命令副作用直接放在逐字节状态机中,会使截断帧、重复帧和回滚难以测试。

模糊测试

模糊测试(Fuzz Testing)适合发现:

  • 长度计算溢出;
  • 越界访问;
  • 状态机死循环;
  • 错误重同步;
  • 大量分配;
  • 未初始化字段;
  • 罕见字段组合。

合理流程:

  1. 从合法黄金样本建立种子;
  2. 给解析器设置明确输入长度和资源上限;
  3. 禁用真实设备副作用;
  4. 加入内存和未定义行为检测;
  5. 保存最小崩溃样本;
  6. 修复后加入永久回归;
  7. 分别覆盖流式分片和完整帧入口。

模糊测试不能替代协议语义和状态机测试。

一致性矩阵

维度 发送端 接收端 工具 证据
协议版本 固定 固定 固定 版本输出
消息定义 提交 提交 提交 文件摘要
帧格式 编码器 解析器 解码器 黄金样本
字段语义 单位/比例 单位/比例 展示 对照值
错误处理 响应 拒绝 展示 负面样本
安全 签名/权限 验证/门禁 配置 反例
性能 调度 队列 捕获 时延和负载

任一列未知时,该维度不能标记通过。

版本迁移

兼容变化

可能包括:

  • 在允许位置追加可选扩展;
  • 新增接收端可忽略的消息;
  • 新增不改变旧值的枚举;
  • 提高实现容量但保持旧边界。

仍需验证旧接收端实际会忽略,而不是越界或错误解释。

不兼容变化

包括:

  • 改变已有字段单位、比例或含义;
  • 改变字段宽度或端序;
  • 重用旧消息ID;
  • 改变校验覆盖;
  • 改变默认权限;
  • 改变失联或超时语义;
  • 从一个线协议切换到另一个不兼容协议。

不兼容变化需要新版本、新消息、显式协商或网关,不能只修改说明文档。

升级流程

  1. 固定旧发送端、旧接收端和旧工具;
  2. 保存黄金样本与配置;
  3. 建立新旧能力矩阵;
  4. 测试新发送端到旧接收端;
  5. 测试旧发送端到新接收端;
  6. 测试新旧工具交叉组合;
  7. 验证未知扩展、降级和拒绝;
  8. 验证升级中断和回滚;
  9. 比较带宽、时延和资源;
  10. 记录最后兼容版本和停止支持条件。

只测试“全部升级后正常”不能证明滚动升级安全。

网关

网关不是透明电线。它可能改变:

  • 帧边界;
  • 地址;
  • 优先级;
  • 时间戳;
  • 认证状态;
  • 错误语义;
  • 数据精度;
  • 更新率;
  • 失联判断。

网关记录至少包含:

  • 两侧协议版本;
  • 完整字段映射;
  • 无法映射的字段;
  • 单位和坐标转换;
  • 队列和限速;
  • 来源身份如何保留;
  • 安全边界终止在哪里;
  • 一侧故障如何传播。

不能把未经认证一侧的消息在网关后标记为“已认证”。

结果分级

状态 含义
未测试 没有执行对应场景
受限通过 指定正常样本通过,但边界或负载未完成
一致通过 固定版本的正常、边界和恢复满足契约
安全通过 在一致通过基础上,权限、重放和资源攻击边界通过
不通过 存在可复现偏差
不适用 有明确的范围依据

“未复现问题”不等于“一致通过”。

最终归档

归档包至少包括:

  • 测试卡;
  • 版本和配置;
  • 协议定义摘要;
  • 原始捕获及散列;
  • 解码结果;
  • 自动化测试报告;
  • 性能统计;
  • 异常样本;
  • 修复差异;
  • 回归结果;
  • 已知限制;
  • 审核人和日期。

对外共享前删除密钥、精确位置、设备唯一标识和其他敏感信息,并保留原件访问控制。

检查理解

  1. 为什么应用日志不能替代原始线上捕获?
  2. 黄金样本为什么不能由待测解析器同时生成预期值?
  3. 模糊测试通过为什么仍不能证明协议语义正确?
  4. 滚动升级为什么要测试四种新旧组合?
  5. 网关为什么可能终止原有安全边界?

主要参考