物联网防火墙himqtt源码之MQTT协议分析
物联网防火墙himqtt源码之MQTT协议分析
himqtt是首款完整源码的高性能MQTT物联网防火墙 - MQTT Application FireWall,C语言编写,采用epoll模式支持数十万的高并发连接,并且兼容ModSecurity部分规则。 代码非常优秀,非常值得收藏和学习,今天笔者就从结合himqtt的源码来进行MQTT协议分析。
一、MQTT协议指令汇总
MQTT协议一共有14个指令,如下表所示:其中有9个报文都是固定的2~4个字节,非常简单适合小型物联网设备。
名字 |
值 |
固定报文 |
描述 |
CONNECT |
1 |
否 |
客户端请求与服务端建立连接 |
CONNACK |
2 |
是 |
服务端确认连接建立 |
PUBLISH |
3 |
否 |
发布消息 |
PUBACK |
4 |
是 |
收到发布消息确认 |
PUBREC |
5 |
是 |
发布消息收到 |
PUBREL |
6 |
是 |
发布消息释放 |
PUBCOMP |
7 |
是 |
发布消息完成 |
SUBSCRIBE |
8 |
否 |
订阅请求 |
SUBACK |
9 |
否 |
订阅确认 |
UNSUBSCRIBE |
10 |
否 |
取消订阅 |
UNSUBACK |
11 |
是 |
取消订阅确认 |
PING |
12 |
是 |
客户端发送PING(连接保活)命令 |
PINGRSP |
13 |
是 |
PING命令回复 |
DISCONNECT |
14 |
是 |
断开连接 |
MQTT协议由指令号(1字节)+长度(1-4字节不定)+内容组成,比如下面第一个字节0x30表示publish发布消息指令,0x26表示后面的内容长度就是38个字节。
---------------MQTT PUBLISH- ------40bytes-------------------------------------------
| 30 26 00 14 68 6f 6d 65 2f 67 61 72 64 65 6e 2f |0&..home/garden/|
| 66 6f 75 6e 74 61 69 6e 31 32 33 34 35 36 37 38 |fountain12345678|
| 39 30 61 62 63 64 65 66 |90abcdef
先到github上下载himqtt最新源码,https://github.com/qq4108863/himqtt/ ,打开src/waf/mqtt.c文件。
特别注意的是:长度占用的字节数是可变的(1-4字节),具体的计算方法在process_mqtt_msg这个函数里面,理论上这种算法后续消息内容是最大长度是268435455字节(约255M)。
static void process_mqtt_msg(mqtt_waf_msg *req)
{
......
/* decode mqtt variable length */
len = len_len = 0;
p = req->buf + 1;
eop = &req->buf[req->pos];
while (p < eop) {
lc = *((const unsigned char *) p++);
len += (lc & 0x7f) << 7 * len_len;
len_len++;
if (!(lc & 0x80)) break;
if (len_len > 4){
req->msg_state = MQTT_MSG_ERROR;
return;
}
}
.....
}
......
长度和协议校验正确后,根据收到的消息类型,以此对不同的指令进行处理,代码逻辑非常清晰:
switch (mqtt_msg_type)
{
case MQTT_CONNECT:
req->msg_state = mqtt_connect(req,p,end,&mm);
break;
case MQTT_CONNACK:
break;
case MQTT_PUBLISH:
req->msg_state = mqtt_publish(req,p,end,&mm);
break;
case MQTT_SUBSCRIBE:
req->msg_state = mqtt_subscribe(req,p,end,&mm);
break;
case MQTT_UNSUBSCRIBE:
req->msg_state = mqtt_unsubscribe(req,p,end,&mm);
......
下面我们主要CONNECT、PUBLISH、SUBSCRIBE、UNSUBSCRIBE这几个复杂一点的报文协议内容。
二、HiMQTT协议分析
1、CONNECT连接服务端
CONNECT是客户端到服务端的网络连接建立后,客户端发送给服务端的第一个报文必须是CONNECT报文,其中登录的身份认证如用户名、密码就在这个指令里面。报文协议如下:
--------------MQTT CONNECT-----105bytes-----------------------------
| 10 67 00 04 4d 51 54 54 04 c2 00 3c 00 19 4d 51 |.g..MQTT...<..MQ|
| 54 54 5f 46 58 5f 43 6c 69 65 6e 74 5f 39 69 75 |TT_FX_Client_9iu|
| 79 38 37 36 35 35 35 00 12 69 6f 74 66 72 65 65 |y876555..iotfree|
| 74 65 73 74 2f 74 68 69 6e 67 30 00 2c 59 55 37 |test/thing0.,YU7|
| 54 6f 76 38 7a 46 57 2b 57 75 61 4c 78 39 73 39 |Tov8zFW+WuaLx9s9|
| 49 33 4d 4b 79 63 6c 69 65 39 53 47 44 75 75 4e |I3MKyclie9SGDuuN|
| 6b 6c 36 6f 39 4c 58 6f 3d |kl6o9LXo=
10 //CONNECT指令号
67 //长度103字节
00 04 //MQTT协议长度为4字节
4d 51 54 54 //MQTT固定字符串
04 //版本3.1.1
c2 //连接标记,是否由用户名/密码等
00 3c //心跳间隔时间60秒
00 19 //用户名长度25字节,后面是用户名
4d 51 54 54 5f 46 58 5f 43 6c 69 65 6e 74 5f 39 69 75 79 38 37 36 35 35 35
00 12 //密码18字节
69 6f 74 66 72 65 65 74 65 73 74 2f 74 68 69 6e 67 30//密码
00 2c //will message长度。
59 55 37 ......6f 3d//will message内容
2、PUBLISH发布消息
PUBLISH 是从客户端向服务端或者服务端向客户端传输一个应用消息,这是通信的最重点,就像HTTP协议的GET一样。报文协议分析如下:
/*
---------------MQTT PUBLISH-------40bytes-----------------------------
| 30 26 00 14 68 6f 6d 65 2f 67 61 72 64 65 6e 2f |0&..home/garden/|
| 66 6f 75 6e 74 61 69 6e 31 32 33 34 35 36 37 38 |fountain12345678|
| 39 30 61 62 63 64 65 66 |90abcdef
*/
30 //PUBLISH指令号
26 //长度39字节
00 14 //TOPIC长度20字节
68 6f 6d 65 2f 67 61 72 64 65 6e 2f 66 6f 75 6e //TOPIC
31 32 33 34 35 36 37 38 39 30 61 62 63 64 65 66 //发布的消息
在实际编程中,这个地方大多是json格式提交给服务器,SQL注入/XSS攻击很可能从这里对物联网设备发起攻击,所以一定要做攻击检查,himqtt不知道什么原因把ngx_http_dummy_json_parse解析json格式的函数注释掉了。
3、SUBSCRIBE订阅消息
SUBSCRIBE是由客户端向服务端发送的,用于创建一个或多个订阅。每个订阅是该客户端关注的一个或多个主题。服务端依据客户端的订阅来匹配主题,然后将对应的PUBLISH报文发送给客户端。报文协议分析如下:
---------------MQTT SUBSCRIBE------33bytes-----------------------------
| 82 1f 00 01 00 1a 68 6f 6d 65 2f 67 61 72 64 65 |......home/garde|
| 6e 2f 66 6f 75 6e 74 61 69 6e 64 65 6c 65 74 65 |n/fountaindelete|
| 00
82 //SUBSCRIBE指令
1f //长度31字节
00 01 //Message Identifier
00 1a //TOPIC长度26
68 6f 6d 65 2f 67 61 72 64 65 6e 2f 66 6f 75 6e 74 61 69 6e 64 65 6c 65 74 65 //TOPIC
00 //request QOS
4、UNSUBSCRIBE取消订阅消息
UNSUBSCRIBE是客户端发送本报文给服务端,用于取消订阅主题。报文协议分析如下:
---------------MQTT UNSUBSCRIBE-------32bytes-----------------------------
| a2 1e 00 02 00 1a 68 6f 6d 65 2f 67 61 72 64 65 |......home/garde|
| 6e 2f 66 6f 75 6e 74 61 69 6e 64 65 6c 65 74 65 |n/fountaindelete|
a2 //SUBSCRIBE指令
1e //长度30字节
00 02 //Message Identifier
00 1a //TOPIC长度26
68 6f 6d 65 2f 67 61 72 64 65 6e 2f 66 6f 75 6e 74 61 69 6e 64 65 6c 65 74 65 //TOPIC
总体来说,MQTT协议比HTTP协议简单多了,非常适合物联网设备。另外himqtt其实也是一款功能强大的WEB应用防火墙,其他源码我们在另外的文章中再介绍。
也许未来几年IPV6普及后,很可能几百亿带电的物体都会联网哦,期待himqtt这类高并发的物联网防火墙能扛起信息安全的大旗,彻底阻挡黑客攻击。
物联网防火墙himqtt源码之MQTT协议分析的更多相关文章
- 从物联网防火墙himqtt源码谈哈希和红黑树的应用场景区别
从物联网防火墙himqtt源码谈哈希和红黑树的应用场景区别 himqtt是首款完整源码的高性能MQTT物联网防火墙 - MQTT Application FireWall,C语言编写,很多数据结构适合 ...
- 物联网MQTT协议分析和开源Mosquitto部署验证
在<物联网核心协议—消息推送技术演进>一文中已向读者介绍了多种消息推送技术的情况,包括HTTP单向通信.Ajax轮询.Websocket.MQTT.CoAP等,其中MQTT协议为IBM制定 ...
- ArrayList源码和多线程安全问题分析
1.ArrayList源码和多线程安全问题分析 在分析ArrayList线程安全问题之前,我们线对此类的源码进行分析,找出可能出现线程安全问题的地方,然后代码进行验证和分析. 1.1 数据结构 Arr ...
- Okhttp3源码解析(3)-Call分析(整体流程)
### 前言 前面我们讲了 [Okhttp的基本用法](https://www.jianshu.com/p/8e404d9c160f) [Okhttp3源码解析(1)-OkHttpClient分析]( ...
- Okhttp3源码解析(2)-Request分析
### 前言 前面我们讲了 [Okhttp的基本用法](https://www.jianshu.com/p/8e404d9c160f) [Okhttp3源码解析(1)-OkHttpClient分析]( ...
- Spring mvc之源码 handlerMapping和handlerAdapter分析
Spring mvc之源码 handlerMapping和handlerAdapter分析 本篇并不是具体分析Spring mvc,所以好多细节都是一笔带过,主要是带大家梳理一下整个Spring mv ...
- HashMap的源码学习以及性能分析
HashMap的源码学习以及性能分析 一).Map接口的实现类 HashTable.HashMap.LinkedHashMap.TreeMap 二).HashMap和HashTable的区别 1).H ...
- ThreadLocal源码及相关问题分析
前言 在高并发的环境下,当我们使用一个公共的变量时如果不加锁会出现并发问题,例如SimpleDateFormat,但是加锁的话会影响性能,对于这种情况我们可以使用ThreadLocal.ThreadL ...
- Netty 源码学习——客户端流程分析
Netty 源码学习--客户端流程分析 友情提醒: 需要观看者具备一些 NIO 的知识,否则看起来有的地方可能会不明白. 使用版本依赖 <dependency> <groupId&g ...
随机推荐
- 在jQuery中使用自定义属性
在jquery中 自定义属性及值默认以下都是在class='acitve'对象中 进行自定义属性操作:1,自定义属性格式:data-xxxx2,获取该属性值: $('.active').data('x ...
- Linux 文件系统缓存dirty_ratio与dirty_background_ratio两个参数区别
文件系统缓存dirty_ratio与dirty_background_ratio两个参数区别 (2014-03-16 17:54:32) 转载▼ 标签: linux 文件系统缓存 cache dirt ...
- Ubuntu 18.04安装NVIDIA显卡驱动教程
最近遇到了在Ubuntu 18.04上安装NVIDIA显卡驱动的情况,看到一篇教程讲解的很好,拿来收藏. 安装NVIDIA显卡驱动风险极大,新手注意. 在Ubuntu 18.04上安装 ...
- Python解释器安装问题-windows
问题一-更新问题(update your machine) 解决方案 1 搜索 windows update 2 检查更新 3 安装更新重启 问题二-0x80072efd错误 问题原因: 安装包需要在 ...
- properties的编码问题
1.在eclipse中,如果不专门设置,properties文件的编码是ISO-8859-1,最好将其改为UTF-8 2.当properties文件的编码改为UTF-8还不够,Spring的conte ...
- hadoop3.1.1:找不到或无法加载主类 org.apache.hadoop.mapreduce.v2.app.MRAppMaster
yarn执行MapReduce任务时,找不到主类导致的 解决: 1.在命令行输入:hadoop classpath [hadoop@localhost ~]$ hadoop classpath /da ...
- docker安装ubuntu以后无ifconfig命令解决办法
解决: 1.apt-get update 2.apt install net-tools #ifcongig 3.apt install iputils-ping # ping
- faster-rcnn CUDA8.0编译错误
之前编译Faster-RCNN的时候用的都是CUDA7.5,最近换了机器,变成了CUDA8.0,果然编译出现错误了…… 参考下面这篇博客解决了问题: http://blog.csdn.net/kexi ...
- mac使用xposed超详细入门级教程Android Studio-20190930
工具 这里我使用的工具是Android Studio3.4.1,电脑环境mac os mojave 10.14.6(这个应该问题不大) 创建项目 1.打开Android Studio,看到这个界面,并 ...
- 利用iis创建网站后为什么不能设置主机名
主机名 主机名就是网站的域名,通俗说就是网站地址(如:www.baidu.com). 设置了主机名,而IIS确不知道主机名对应的地址在哪里. 举个例子,把www.baidu.com做为IIS网站的主机 ...