飞利浦摄像头网络协议分析

本文整理飞利浦品牌、云看看 App、FH8626V100 平台摄像头的 UDP 云协议。基于抓包分析并已在本地模拟服务器中验证云台、语音对讲、夜视、重启和移动跟踪。

本文只把抓包能够证明的行为写成结论。未确认的字段、跨型号兼容性和安全语义均明确列在文末,不能把本文视为厂商正式协议规范。

1. 协议总览

摄像头不会固定连接某一台媒体服务器。它先访问多个引导节点,再由引导节点下发动态会话 IP、UDP 端口和 4 字节令牌。摄像头每次启动或重新会合时,本地端口和远端节点都可能变化,因此实现中不能写死最终 UDP 五元组。

一个完整会话分为五层:

1
2
3
4
5
6
DNS/路由接管
-> NAT 探测与注册(F100/F101、F112/F113)
-> 下发会话端点(F182)
-> 会合握手(F183/F103/F184/反向F183)
-> 可靠通道与能力交换(F1D0/F1D1、D100)
-> 控制、视频和对讲(D100/D101/D102/D103)

已识别的逻辑通道:

通道 方向 用途
D1 00 双向 会话初始化、能力交换、云台及设备功能控制
D1 01 服务器 → 摄像头 G.711 A-law 语音对讲
D1 02 摄像头 → 服务器 H.264 视频/媒体数据
D1 03 摄像头 → 服务器 H.264 视频/媒体数据

所有多字节字段并非统一字节序:外层长度、可靠序号和 ACK 序号使用大端;地址、端口、控制命令、控制数据长度及多数命令数据使用小端。实现时应逐字段处理。

2. 引导与会合

2.1 DNS 与引导节点

抓包中摄像头向硬编码 DNS 114.114.114.114 查询:

  • p2p2.cloudbirds.cn
  • p2p3.cloudbirds.cn

摄像头还会访问未必由这两次 DNS 查询返回的备用节点,并向公网 UDP3210032102 发送引导报文。因此,仅劫持域名不足以保证离线运行;网关还需接管摄像头的 UDP/53,以及它发往公网 UDP 3210032102 的流量。

2.2 F1 00 / F1 01:NAT 映射探测

摄像头发送:

1
F1 00 00 00

引导节点回复 20 字节:

1
2
3
4
5
6
7
offset  size  endian  含义
0 2 - F1 01
2 2 BE 后续长度,固定 0x0010
4 2 - 00 02
6 2 LE 节点观察到的 UDP 源端口
8 4 LE 节点观察到的 IPv4
12 8 - 全零

2.3 F1 12 / F1 13:设备注册

  • F1 12 总长 48 字节,长度字段为 0x002C
  • 同一 UDP socket 发给多个引导节点的内容相同;切换 socket 后,末尾约 16 字节会变化。
  • F1 13 总长 12 字节,是注册确认。
  • F1 12 内部可能包含时间、随机数、签名或设备认证信息,目前尚未解出。本地模拟服务器只把它视为不透明请求并按抓包格式回应。

2.4 F1 40 / F1 41:候选地址和打洞

F1 40 是 20 字节候选地址,端口和 IPv4 的位置、字节序与 F1 01 相同。摄像头随后向公网及私网候选端口发送携带明文设备 ID 的 F1 41。这一阶段用于直连候选打洞,不是最终控制或视频通道。

2.5 F1 82 / F1 83:下发会话节点

F1 82 总长 24 字节:

1
2
3
4
5
6
7
8
offset  size  endian  含义
0 2 - F1 82
2 2 BE 后续长度,固定 0x0014
4 2 - 00 02
6 2 LE 最终节点 UDP 端口
8 4 LE 最终节点 IPv4
12 8 - 全零
20 4 - 会合令牌 token

摄像头向该地址发送 32 字节 F1 83

1
F1 83 | 00 1C | token[4] | device_id[20] | flag_le32

摄像头首次报到时 flag=1。最终节点依次返回:

  1. F1 03 00 00
  2. 携带设备 ID 的 F1 84
  3. 相同 token 和 device ID、但 flag=0 的反向 F1 83

本地服务端应保存 F1 83 的实际来源 IP 和端口,并把它作为本次会话对端。设备重启或重新会合后必须重新学习,不能沿用旧端口。

3. 会话可靠层

3.1 数据包 F1 D0

1
2
3
4
5
6
offset  size  endian  含义
0 2 - F1 D0
2 2 BE 后续长度,即 UDP 负载总长减 4
4 2 - 逻辑通道 D1 00 / D1 01 / D1 02 / D1 03
6 2 BE 该逻辑通道的 16 位序号
8 N - 通道负载

各逻辑通道独立使用序号。相同通道、相同序号再次出现表示重传,接收端应再次 ACK,但不得重复执行云台、重启等有副作用的命令。

3.2 选择确认 F1 D1

1
2
3
4
5
6
offset  size  endian  含义
0 2 - F1 D1
2 2 BE 后续长度,4 + 2×count
4 2 - 被确认的逻辑通道
6 2 BE 序号数量 count
8 2N BE count 个独立序号

确认 D1 00 序号 2 的示例:

1
F1 D1 00 06 D1 00 00 01 00 02

ACK 中的序号是集合,不是连续范围。控制通道通常逐包确认,视频和音频可以批量确认。发送端超时重试时应重发原序号,不应为同一次操作分配新序号。

4. D1 00 控制记录

F1 D0 / D1 00 的 offset 8 之后可以连续放置一条或多条控制记录:

1
2
3
4
5
6
offset  size      endian  含义
0 4 - 88 88 76 76
4 4 LE data_len
8 2 LE command
10 14 - 保留字段;已见样本中为零
24 data_len - 命令数据

已观察到的初始化和能力记录:

请求 响应 已确认信息
0x0010 0x0010 会话问候/认证交换;服务器数据含可打印令牌,语义未知
0x0330 0x0331 设备信息;响应中出现 FH8626V100 和固件能力字段
0x0608 0x0609 配置查询/响应,具体含义未知
0x0616 0x0617 配置查询/响应,具体含义未知
0x031A 0x031B 配置查询/响应,具体含义未知
0x0372 0x0373 配置查询/响应,具体含义未知
0x8164 0x8165 配置查询/响应,具体含义未知
0x0001 0x0002 媒体能力/流信息;响应中可识别 1920×1080 等参数

服务器在问候完成后发送一个 540 字节、包含 16 条记录的配置包。当前本地服务器按抓包原样发送该包,尚未证明其中哪些记录是启动媒体上传的最小必需项。

5. 已验证的设备命令

功能 请求命令 请求数据 响应命令 可靠层
云台移动/停止 0x1001 8 字节方向数据 无控制响应 摄像头 ACK
初始化对讲 0x0006 16 字节音频参数 0x0006 双方 ACK
夜视开关 0x8166 8 字节模式数据 0x8167 双方 ACK
重启 0x8114 4 字节全零 0x8115 双方 ACK
移动跟踪 0x817C 16 字节开关数据 0x817D 双方 ACK

请求收到可靠层 ACK,说明摄像头已接收该请求;对应控制响应可用于进一步确认设备处理流程。本地页面目前以请求 ACK 作为即时操作结果。

5.1 云台 0x1001

云台数据固定为 8 字节:

1
DD 08 00 00 00 00 03 00

方向映射:

DD 动作
00 停止
01
02
03
06

方向后的 7 字节在当前所有样本中保持不变。虽然第二字节为 08,但证据不足以将其正式命名为速度。

完整 40 字节模板:

1
2
3
4
5
F1 D0 00 24 D1 00 SS SS
88 88 76 76
08 00 00 00
01 10 00 00 00 00 00 00 00 00 00 00 00 00 00 00
DD 08 00 00 00 00 03 00

SS SSD1 00 的大端序号。按下方向时发送移动帧,松开时以新序号发送DD=00。若未收到 ACK,可以重发同一序号。

5.2 语音对讲 0x0006D1 01

开始对讲前,服务器通过 D1 00 发送 0x0006

1
00 00 00 00  52 00 00 00  40 01 00 00  00 00 00 00
  • 0x52:当前抓包使用的音频格式标识;
  • 0x140:每帧 320 字节;
  • 摄像头以 0x0006 和 4 字节全零数据响应;
  • D1 01 使用独立可靠序号,从 0 开始。

单个语音 UDP 负载通常为 344 字节:

1
2
3
F1 D0 | 01 54 | D1 01 | seq_be16
timestamp_le32 | 40 01 00 00 | 00 00 00 00 | 52 00 00 00
320 bytes G.711 A-law

音频为 8kHz、单声道、G.711 A-law,320 字节对应 40ms。抓包中静音码主要为0xD5timestamp 等于开始对讲时摄像头 D1 02 媒体时钟加 1,并在本次对讲期间保持不变;该字段的真实语义仍待验证。

摄像头通过 F1 D1 / D1 01 确认语音序号。停止对讲时没有观察到独立停止命令,服务器停止发送 D1 01 即可。

5.3 夜视 0x8166

请求数据固定为 8 字节:

1
2
关闭:05 00 00 00 00 00 00 00
开启:04 00 00 00 00 00 00 00

摄像头响应 0x8167,数据为 8 字节全零。

5.4 重启 0x8114

1
2
请求:0x8114,数据 00 00 00 00
响应:0x8115,数据 00 00 00 00

收到请求 ACK 后,服务端应把当前会话标为失效,清除旧对端、媒体时钟和握手去重状态。摄像头重启上线后会使用新的动态端口重新会合。

5.5 移动跟踪 0x817C

请求数据固定为 16 字节,仅首字节变化:

1
2
开启:01 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00
关闭:00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00

摄像头响应 0x817D,数据为 4 字节全零。该功能是摄像头自身的自动云台跟踪,不要与本地录像程序基于帧差实现的“移动侦测”混淆。

6. 视频通道

  • D1 02D1 03 的首批数据都能找到 Annex-B 起始码与 H.264 SPS(NAL type 7),因此两者都是视频/媒体通道,不是语音。
  • 常见 UDP 负载总长为 1032 字节,即 8 字节可靠层头加 1024 字节媒体片段;访问单元末片长度可变。
  • 两个通道的媒体前导长度不同,包含时间戳、边界或流标识,但目前尚未完整定义。
  • 现有证据不足以把 D1 02D1 03 严格命名为主码流和副码流。
  • 只做设备控制时可以丢弃媒体负载,但仍必须 ACK;要直接从云协议录像,则需要继续完成乱序重组、媒体前导和 H.264 访问单元边界分析。

另外该摄像头已开放的 RTSP协议rtsp://admin:admin123456@<camera-ip>:8554/profile0,可以不依赖云协议视频重组。

7. 本地模拟服务器状态机

最小可行实现:

  1. 在摄像头网关接管 DNS 和发往公网 UDP 3210032102 的引导请求。
  2. 监听 UDP 321003210132102:收到 F1 00 返回 F1 01;收到F1 12 返回 F1 13,随后用 F1 82 指向本机会话端口。
  3. 会话端口收到 F1 83 后,保存摄像头实际 IP、端口、token 和 device ID。
  4. 按顺序返回 F1 03F1 84、反向 F1 83(flag=0)
  5. 发送服务器问候;收到摄像头 0x0331 后发送抓包中的 540 字节配置包。
  6. 按逻辑通道和序号去重所有 F1 D0,及时返回 F1 D1
  7. 配置请求收到 ACK 后将会话标为可控制,并使用动态分配的下一 D1 00 序号发送设备命令。
  8. 会话超时、摄像头重启或出现新 F1 83 时,清除旧状态并重新握手。

实现注意事项:

  • 不要写死摄像头 DHCP 地址、本地 UDP 源端口、云端节点或会话端口。
  • 控制序号和对讲序号分别维护。
  • ACK 等待应按“通道 + 序号”匹配。
  • 同一可靠包的重传只能执行一次副作用。
  • Linux 网关上若同时通过原始链路抓包和 UDP socket 收包,可能看到同一数据报两次;只能抑制极短时间内的本机重复投递,不能误删正常协议重传。

8. 尚未确认的部分

  • F1 12 中变化字段的算法,以及服务端是否应校验设备签名或密钥。
  • F1 13F1 40F1 41 中所有字段的完整语义。
  • 0x0010 会话问候中令牌的生成方法、有效期和跨重启稳定性。
  • 540 字节配置包中每条记录的准确含义及真正的最小初始化集合。
  • D1 02D1 03 的完整媒体前导、分帧、乱序重组和双通道关系。
  • 对讲帧 timestamp 为什么取视频媒体时钟加 1,以及长时间会话是否需要更新。
  • 夜视模式值、移动跟踪和其他 0x81xx 命令在不同固件上的兼容性。
  • 摄像头控制响应只代表接受、执行完成,还是最终硬件状态;目前页面主要依赖可靠
    层 ACK,并未实现独立状态回读。

上述命令只在固件 V30023.1.145.20240716、平台 FH8626V100 的这台设备上由抓包验证。换型号或升级固件后,应重新抓包逐字节核对再发送。

>