dissector/mqtt: Add partial support for MQTT v5.0

This patch adds partial support for the MQTT v5.0 protocol.
The relevant changes are:

- A new MQTT control packet: AUTH (15)
- The Variable Header is extended with a new section: 'Properties'

Currently, the 'Properties' section is not dissected although
its length is parsed.

Change-Id: I059b91304e953d69e4781b170e61057cb38dde19
Signed-off-by: Flavio Santes <flavio.santes@1byt3.com>
Reviewed-on: https://code.wireshark.org/review/24261
Reviewed-by: Anders Broman <a.broman58@gmail.com>
This commit is contained in:
Flavio Santes 2017-11-04 08:25:45 -04:00 committed by Anders Broman
parent ea97b3364c
commit e2179a2ac5
1 changed files with 126 additions and 8 deletions

View File

@ -36,6 +36,10 @@
*
* MQTT v3.1.1 specification:
* http://docs.oasis-open.org/mqtt/mqtt/v3.1.1/
*
* MQTT v5.0 specification:
* http://docs.oasis-open.org/mqtt/mqtt/v5.0/
*
*/
#include "config.h"
@ -52,6 +56,7 @@
/* MQTT Protocol Versions */
#define MQTT_PROTO_V31 3
#define MQTT_PROTO_V311 4
#define MQTT_PROTO_V50 5
#define MQTT_HDR_SIZE_BEFORE_LEN 1
@ -71,7 +76,8 @@
#define MQTT_PINGREQ 12
#define MQTT_PINGRESP 13
#define MQTT_DISCONNECT 14
#define MQTT_RESERVED_15 15
#define MQTT_AUTH 15
#define MQTT_RESERVED_16 16
/* Flag Values to extract fields */
#define MQTT_MASK_MSG_TYPE 0xF0
@ -87,6 +93,7 @@ void proto_reg_handoff_mqtt(void);
static const value_string mqtt_protocol_version_vals[] = {
{ MQTT_PROTO_V31, "MQTT v3.1" },
{ MQTT_PROTO_V311, "MQTT v3.1.1" },
{ MQTT_PROTO_V50, "MQTT v5.0" },
{ 0, NULL }
};
@ -106,7 +113,8 @@ static const value_string mqtt_msgtype_vals[] = {
{ MQTT_PINGREQ, "Ping Request" },
{ MQTT_PINGRESP, "Ping Response" },
{ MQTT_DISCONNECT, "Disconnect Req" },
{ MQTT_RESERVED_15, "Reserved" },
{ MQTT_AUTH, "Authentication Exchange" },
{ MQTT_RESERVED_16, "Reserved" },
{ 0, NULL }
};
static value_string_ext mqtt_msgtype_vals_ext = VALUE_STRING_EXT_INIT(mqtt_msgtype_vals);
@ -242,6 +250,10 @@ static int hf_mqtt_conflag_will_flag = -1;
static int hf_mqtt_conflag_clean_sess = -1;
static int hf_mqtt_conflag_reserved = -1;
static int hf_mqtt_keep_alive = -1;
static int hf_mqtt_subscription_options = -1;
static int hf_mqtt_reason_code = -1;
static int hf_mqtt_property_len = -1;
static int hf_mqtt_property = -1;
/* Initialize the subtree pointers */
static gint ett_mqtt_hdr = -1;
@ -376,12 +388,33 @@ static void mqtt_user_decode_message(proto_tree *tree, proto_tree *mqtt_tree, pa
}
}
/* MQTT v5.0: dissect the MQTT properties */
static guint32 dissect_mqtt_properties(tvbuff_t *tvb, proto_tree *mqtt_tree, guint32 offset)
{
guint32 mqtt_prop_offset;
guint32 mqtt_prop_len;
guint64 prop_len;
mqtt_prop_offset = dissect_uleb128(tvb, offset, &prop_len);
mqtt_prop_len = (guint32)prop_len;
proto_tree_add_item(mqtt_tree, hf_mqtt_property_len, tvb, offset, mqtt_prop_offset, ENC_BIG_ENDIAN);
if (mqtt_prop_len > 0)
{
proto_tree_add_item(mqtt_tree, hf_mqtt_property, tvb, offset + mqtt_prop_offset, mqtt_prop_len, ENC_UTF_8|ENC_NA);
/* In this iteration we don't dissect the MQTT properties section */
}
return mqtt_prop_offset + mqtt_prop_len;
}
/* Dissect the MQTT message */
static int dissect_mqtt(tvbuff_t *tvb, packet_info *pinfo, proto_tree *tree, void* data _U_)
{
guint8 mqtt_fixed_hdr;
guint8 mqtt_msg_type;
proto_item *ti;
int hf_version_selector;
const guint8 *topic_str;
proto_tree *mqtt_tree;
@ -394,7 +427,7 @@ static int dissect_mqtt(tvbuff_t *tvb, packet_info *pinfo, proto_tree *tree, voi
conversation_t *conv;
mqtt_conv *mqtt;
int offset = 0;
guint32 offset = 0;
static const int *publish_fields[] = {
&hf_mqtt_msg_type,
&hf_mqtt_dup_flag,
@ -502,6 +535,11 @@ static int dissect_mqtt(tvbuff_t *tvb, packet_info *pinfo, proto_tree *tree, voi
proto_tree_add_item(mqtt_tree, hf_mqtt_keep_alive, tvb, offset, 2, ENC_BIG_ENDIAN);
offset += 2;
if (mqtt->runtime_proto_version == MQTT_PROTO_V50)
{
offset += dissect_mqtt_properties(tvb, mqtt_tree, offset);
}
mqtt_str_len = tvb_get_ntohs(tvb, offset);
proto_tree_add_item(mqtt_tree, hf_mqtt_client_id_len, tvb, offset, 2, ENC_BIG_ENDIAN);
offset += 2;
@ -561,8 +599,13 @@ static int dissect_mqtt(tvbuff_t *tvb, packet_info *pinfo, proto_tree *tree, voi
offset += 1;
proto_tree_add_item(mqtt_tree, hf_mqtt_conack_code, tvb, offset, 1, ENC_BIG_ENDIAN);
break;
offset += 1;
if (mqtt->runtime_proto_version == MQTT_PROTO_V50)
{
offset += dissect_mqtt_properties(tvb, mqtt_tree, offset);
}
break;
case MQTT_PUBLISH:
/* TopicName|MsgID|Message| */
mqtt_str_len = tvb_get_ntohs(tvb, offset);
@ -582,6 +625,15 @@ static int dissect_mqtt(tvbuff_t *tvb, packet_info *pinfo, proto_tree *tree, voi
offset += 2;
mqtt_msg_len -= 2;
}
if (mqtt->runtime_proto_version == MQTT_PROTO_V50)
{
guint32 mqtt_prop_offset = dissect_mqtt_properties(tvb, mqtt_tree, offset);
offset += mqtt_prop_offset;
mqtt_msg_len -= mqtt_prop_offset;
}
proto_tree_add_item(mqtt_tree, hf_mqtt_pubmsg, tvb, offset, mqtt_msg_len, ENC_UTF_8|ENC_NA);
if (num_mqtt_message_decodes > 0)
@ -598,6 +650,17 @@ static int dissect_mqtt(tvbuff_t *tvb, packet_info *pinfo, proto_tree *tree, voi
*/
proto_tree_add_item(mqtt_tree, hf_mqtt_msgid, tvb, offset, 2, ENC_BIG_ENDIAN);
offset += 2;
if (mqtt->runtime_proto_version == MQTT_PROTO_V50)
{
offset += dissect_mqtt_properties(tvb, mqtt_tree, offset);
hf_version_selector = hf_mqtt_subscription_options;
}
else
{
hf_version_selector = hf_mqtt_sub_qos;
}
for(mqtt_msg_len -= 2; mqtt_msg_len > 0;)
{
mqtt_str_len = tvb_get_ntohs(tvb, offset);
@ -609,7 +672,7 @@ static int dissect_mqtt(tvbuff_t *tvb, packet_info *pinfo, proto_tree *tree, voi
offset += mqtt_str_len;
mqtt_msg_len -= mqtt_str_len;
proto_tree_add_item(mqtt_tree, hf_mqtt_sub_qos, tvb, offset, 1, ENC_BIG_ENDIAN);
proto_tree_add_item(mqtt_tree, hf_version_selector, tvb, offset, 1, ENC_BIG_ENDIAN);
offset += 1;
mqtt_msg_len -= 1;
}
@ -641,6 +704,12 @@ static int dissect_mqtt(tvbuff_t *tvb, packet_info *pinfo, proto_tree *tree, voi
*/
proto_tree_add_item(mqtt_tree, hf_mqtt_msgid, tvb, offset, 2, ENC_BIG_ENDIAN);
offset += 2;
if (mqtt->runtime_proto_version == MQTT_PROTO_V50)
{
offset += dissect_mqtt_properties(tvb, mqtt_tree, offset);
}
for(mqtt_msg_len -= 2; mqtt_msg_len > 0; mqtt_msg_len--)
{
proto_tree_add_item(mqtt_tree, hf_mqtt_suback_qos, tvb, offset, 1, ENC_BIG_ENDIAN);
@ -648,19 +717,51 @@ static int dissect_mqtt(tvbuff_t *tvb, packet_info *pinfo, proto_tree *tree, voi
}
break;
/* The following response code contains only msg-id */
case MQTT_PUBACK:
case MQTT_PUBREC:
case MQTT_PUBREL:
case MQTT_PUBCOMP:
proto_tree_add_item(mqtt_tree, hf_mqtt_msgid, tvb, offset, 2, ENC_BIG_ENDIAN);
offset += 2;
/* FALLTHROUGH */
case MQTT_DISCONNECT:
if (mqtt->runtime_proto_version == MQTT_PROTO_V50)
{
proto_tree_add_item(mqtt_tree, hf_mqtt_reason_code, tvb, offset, 1, ENC_BIG_ENDIAN);
offset += 1;
offset += dissect_mqtt_properties(tvb, mqtt_tree, offset);
}
break;
case MQTT_UNSUBACK:
proto_tree_add_item(mqtt_tree, hf_mqtt_msgid, tvb, offset, 2, ENC_BIG_ENDIAN);
offset += 2;
if (mqtt->runtime_proto_version == MQTT_PROTO_V50)
{
offset += dissect_mqtt_properties(tvb, mqtt_tree, offset);
}
break;
/* The following messages don't have variable header */
case MQTT_PINGREQ:
case MQTT_PINGRESP:
case MQTT_DISCONNECT:
break;
case MQTT_AUTH:
/* MQTT v5.0: The Reason Code and Property Length can be omitted if
* the Reason Code is 0x00 (Success) and there are no Properties.
* In this case the AUTH has a Remaining Length of 0.
*/
if (mqtt->runtime_proto_version == MQTT_PROTO_V50 && mqtt_msg_len > 0)
{
proto_tree_add_item(mqtt_tree, hf_mqtt_reason_code, tvb, offset, 1, ENC_BIG_ENDIAN);
offset += 1;
offset += dissect_mqtt_properties(tvb, mqtt_tree, offset);
}
break;
}
@ -870,7 +971,24 @@ void proto_register_mqtt(void)
{ &hf_mqtt_keep_alive,
{ "Keep Alive", "mqtt.kalive",
FT_UINT16, BASE_DEC, NULL, 0,
NULL, HFILL }}
NULL, HFILL }},
/* xxx */
{ &hf_mqtt_subscription_options,
{ "Subscription Options", "mqtt.subscription_options",
FT_UINT8, BASE_HEX, NULL, 0,
NULL, HFILL }},
{ &hf_mqtt_reason_code,
{ "Reason Code", "mqtt.reason_code",
FT_UINT8, BASE_DEC, NULL, 0,
NULL, HFILL }},
{ &hf_mqtt_property_len,
{ "Property Length", "mqtt.property_len",
FT_UINT64, BASE_DEC, NULL, 0,
NULL, HFILL }},
{ &hf_mqtt_property,
{ "Property", "mqtt.property",
FT_STRING, BASE_NONE, NULL, 0,
NULL, HFILL }},
};
/* Setup protocol subtree arrays */