暑假之前我就计划着写一个协议,一方面是确实对网络协议和协议逆向感兴趣,另一方面是自身的代码水平实在堪忧,总得写点东西练练手。但是一晃俩月过去了,发现自己还什么也没干......
花了大概两天半的时间,做了一个daemon,没有数多少行,感觉其实有点简陋,没有加CRC,也没有做返回报文,查重机制也比较粗糙,不过好在我是先实现了协议,最后起的名字,所以可以先射箭后画靶:
一切都是为了轻量化和资源受限服务的,所以简陋一点也没什么!
IDCCP ---物联网设备控制指令协议
IDCCP = IoT Device Control Command Protocol
特性
- 超轻量:固定 8 字节报文头,无负载时整帧仅 8 字节,负载最长 255 字节。
- 无返回报文:纯单向通信,服务端不产生任何响应,最大限度降低设备端开销。
- 无连接:基于 UDP,无需握手与连接维护,适合网络不稳定、资源受限的 IoT 场景。
- 配置驱动:命令编号到具体动作的映射完全由配置文件定义,无需修改代码即可扩展。
- 内建去重:通过请求 ID 与客户端地址对重复报文(如 UDP 重传)进行过滤,避免命令被重复执行。
- 快速失败:拒绝任何可能的风险,在遇到配置错误,端口占用时立刻终止进程并返回错误码,而非忽略问题运行。
(这部分是AI生成的,直接复用了github上README.md对特性的介绍)
(总得吹一下嘛)
关于协议设计
一开始没想太多,出于对UDP本身的钟爱,再加上TCP的流式协议还要处理缓冲区,还要做重连机制,实在是太难写了,所以选定了UDP作为底座,设计了协议帧结构:
+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
| magic_0 | magic_1 | magic_2 | ver_flag |
+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
| length | command | req_id |
+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
| payload ...
+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
想法也很简单,我希望能通过发送IDCCP报文,来远程控制设备,但是如果写API的调用库就不能直接看到成果,而如果把一些指令硬编码进程序里,又太死板了,于是就有了这个四不像:
通过读取配置文件,获取一一对应的指令码和需要运行的命令,然后直接在服务端主机上fork子进程,执行conf里预设好的指令。
同时,支持载荷的填充,可以通过控制payload_flag,自行决定是否需要在预设的指令里做其他参数的传递。
帧头总共是8字节,魔数原本想设计成IDCC共计4字节,但4字节实在是太占地方了,如果整个帧头直接加1字节,变成9字节又感觉不太规整,所以magic只能忍痛选择了'I','D','C'的ASCII。
版本号是一定要有的,直接跟载荷的flag拼在一起,这样还能有3bit的空位,如果以后真有版本2.0,还可以加一些别的flag。
然后是length字段,占1字节,这里的length是针对载荷的,不包括帧头本身的8字节长度;指令码占1字节,从0x00到0xff,一共256个,我感觉这已经够多了。
然后是req_id,我期望的客户端会进行冗余发包(UDP协议容易丢包,如果客户端每次能发2-3个包,就能降低丢包的可能性),但冗余发包并不意味着一条指令反复执行,所以增加了去重机制,req_id就成了必不可少的。

这里我的去重表机制稍显粗糙,维护了一个结构体数组,结构体包括三个元素,分别是cli_ip,cli_port和req_id,前两者用来区分客户端,req_id负责去重。作为静态数组,它每接收64个不同的包,就会刷新一次去重表,完全丢失之前的req_id。
也就是说,如果你的客户端使用了冗余发包机制,并且发的包恰好是第64个的话,它就会在接收一次指令的情况下执行两遍......
当然,只要你的冗余发包的数量是2的倍数,出现的可能性就不会很大。
最后是payload字段,这个没什么可说的,就是查找并拼接字符串。
这里使用了conf,支持INI格式,采用的办法是,每次接收到[Command]这个字符串以后,就要收集payload_flag,cli_str,cmdnum三个key-value对,不然就会报错。
还有一些命令行参数之类的处理逻辑,不算是核心实现,这里就不一一列举了。
感觉离一个完整项目还有些许的距离,代码量目前大概四五百行吧,近期应该还会编写一个cli工具来跟它配套,后续如果闲得没事,我可能真的会做2.0版本。
下面是github仓库链接: