3 * Routines for MsgPack dissection
5 * https://github.com/msgpack/msgpack/
7 * Copyright 2018, Dario Lombardo <lomato@gmail.com>
9 * Wireshark - Network traffic analyzer
10 * By Gerald Combs <gerald@wireshark.org>
11 * Copyright 1998 Gerald Combs
13 * SPDX-License-Identifier: GPL-2.0-or-later
18 #include <wsutil/array.h>
19 #include <epan/packet.h>
20 #include <epan/expert.h>
21 #include <epan/to_str.h>
25 void proto_register_msgpack(void);
26 void proto_reg_handoff_msgpack(void);
28 dissector_handle_t msgpack_handle
;
30 static int proto_msgpack
;
32 static int hf_msgpack_string
;
33 static int hf_msgpack_type
;
34 static int hf_msgpack_string_len
;
35 static int hf_msgpack_uint_8
;
36 static int hf_msgpack_uint_16
;
37 static int hf_msgpack_uint_32
;
38 static int hf_msgpack_uint_64
;
39 static int hf_msgpack_int_8
;
40 static int hf_msgpack_int_16
;
41 static int hf_msgpack_int_32
;
42 static int hf_msgpack_int_64
;
43 static int hf_msgpack_bool
;
44 static int hf_msgpack_float
;
45 static int hf_msgpack_ext_fixext
;
46 static int hf_msgpack_ext_type
;
47 static int hf_msgpack_ext_bytes
;
49 static int ett_msgpack
;
50 static int ett_msgpack_string
;
51 static int ett_msgpack_array
;
52 static int ett_msgpack_map
;
53 static int ett_msgpack_map_elem
;
54 static int ett_msgpack_ext
;
56 static expert_field ei_msgpack_unsupported
;
58 static const value_string msgpack_ext_fixtexts
[] = {
63 { 0xd8, "fixext 16" },
67 static void dissect_msgpack_object(tvbuff_t
* tvb
, packet_info
* pinfo
, proto_tree
* tree
, void* data
, int* offset
, char** value
);
69 static void dissect_msgpack_integer(tvbuff_t
* tvb
, packet_info
*pinfo
, proto_tree
* tree
, uint8_t type
, void* data
, int* offset
, char** value
)
81 label
= (data
? (char*)data
: "MsgPack Integer");
84 proto_tree_add_uint_format(tree
, hf_msgpack_uint_8
, tvb
, *offset
, 1, type
, "%s: %u", label
, type
);
86 *value
= wmem_strdup_printf(pinfo
->pool
, "%u", type
);
92 proto_tree_add_int_format(tree
, hf_msgpack_int_8
, tvb
, *offset
, 1, type
, "%s: %u", label
, type
);
94 *value
= wmem_strdup_printf(pinfo
->pool
, "%d", type
);
101 uint8
= tvb_get_uint8(tvb
, *offset
+ 1);
102 proto_tree_add_uint_format(tree
, hf_msgpack_uint_8
, tvb
, *offset
, 2, uint8
, "%s: %u", label
, uint8
);
104 *value
= wmem_strdup_printf(pinfo
->pool
, "%u", uint8
);
108 uint16
= tvb_get_ntohs(tvb
, *offset
+ 1);
109 proto_tree_add_uint(tree
, hf_msgpack_uint_16
, tvb
, *offset
, 3, uint16
);
111 *value
= wmem_strdup_printf(pinfo
->pool
, "%u", uint16
);
115 uint32
= tvb_get_ntohl(tvb
, *offset
+ 1);
116 proto_tree_add_uint(tree
, hf_msgpack_uint_32
, tvb
, *offset
, 5, uint32
);
118 *value
= wmem_strdup_printf(pinfo
->pool
, "%u", uint32
);
122 uint64
= tvb_get_ntoh64(tvb
, *offset
+ 1);
123 proto_tree_add_uint64(tree
, hf_msgpack_uint_64
, tvb
, *offset
, 9, uint64
);
125 *value
= wmem_strdup_printf(pinfo
->pool
, "%" PRIu64
, uint64
);
129 int8
= tvb_get_int8(tvb
, *offset
+ 1);
130 proto_tree_add_int(tree
, hf_msgpack_int_8
, tvb
, *offset
, 2, int8
);
132 *value
= wmem_strdup_printf(pinfo
->pool
, "%d", int8
);
136 int16
= tvb_get_ntohs(tvb
, *offset
+ 1);
137 proto_tree_add_int(tree
, hf_msgpack_int_16
, tvb
, *offset
, 3, int16
);
139 *value
= wmem_strdup_printf(pinfo
->pool
, "%d", int16
);
143 int32
= tvb_get_ntohl(tvb
, *offset
+ 1);
144 proto_tree_add_int(tree
, hf_msgpack_int_32
, tvb
, *offset
, 5, int32
);
146 *value
= wmem_strdup_printf(pinfo
->pool
, "%d", int32
);
150 int64
= tvb_get_ntoh64(tvb
, *offset
+ 1);
151 proto_tree_add_int64(tree
, hf_msgpack_int_64
, tvb
, *offset
, 9, int64
);
153 *value
= wmem_strdup_printf(pinfo
->pool
, "%" PRId64
, int64
);
157 DISSECTOR_ASSERT_NOT_REACHED();
161 // NOLINTNEXTLINE(misc-no-recursion)
162 static void dissect_msgpack_map(tvbuff_t
* tvb
, packet_info
* pinfo
, proto_tree
* tree
, uint8_t type
, void* data
, int* offset
, char** value
)
165 proto_tree
* map_subtree
;
173 label
= wmem_strdup_printf(pinfo
->pool
, "%s: %u element%s", data
? (char*)data
: "MsgPack Map", len
, len
> 1 ? "s" : "");
175 ti
= proto_tree_add_string_format(tree
, hf_msgpack_string
, tvb
, *offset
, 1 + len
, NULL
, "%s", label
);
176 subtree
= proto_item_add_subtree(ti
, ett_msgpack_map
);
178 for (i
= 0; i
< len
; i
++) {
179 map_subtree
= proto_tree_add_subtree(subtree
, tvb
, *offset
, 0, ett_msgpack_map_elem
, NULL
, "");
180 dissect_msgpack_object(tvb
, pinfo
, map_subtree
, "Key", offset
, value
);
182 proto_item_append_text(map_subtree
, " %s:", *value
);
183 // We recurse here, but we'll run out of packet before we run out of stack.
184 dissect_msgpack_object(tvb
, pinfo
, map_subtree
, "Value", offset
, value
);
186 proto_item_append_text(map_subtree
, " %s", *value
);
193 // NOLINTNEXTLINE(misc-no-recursion)
194 static void dissect_msgpack_array(tvbuff_t
* tvb
, packet_info
* pinfo
, proto_tree
* tree
, uint8_t type
, void* data
, int* offset
, char** value
)
199 uint32_t lensize
= UINT32_MAX
;
203 if (type
>> 4 == 0x9) {
208 len
= tvb_get_ntohs(tvb
, *offset
+ 1);
212 len
= tvb_get_ntohl(tvb
, *offset
+ 1);
216 DISSECTOR_ASSERT(lensize
!= UINT32_MAX
);
218 label
= wmem_strdup_printf(pinfo
->pool
, "%s %u element%s", data
? (char*)data
: "MsgPack Array", len
, len
> 1 ? "s" : "");
220 ti
= proto_tree_add_string_format(tree
, hf_msgpack_string
, tvb
, *offset
, 1 + len
, NULL
, "%s", label
);
221 subtree
= proto_item_add_subtree(ti
, ett_msgpack_array
);
222 *offset
+= lensize
+ 1;
223 for (i
= 0; i
< len
; i
++) {
224 // We recurse here, but we'll run out of packet before we run out of stack.
225 dissect_msgpack_object(tvb
, pinfo
, subtree
, data
, offset
, value
);
232 static void dissect_msgpack_string(tvbuff_t
* tvb
, packet_info
* pinfo
, proto_tree
* tree
, int type
, void* data
, int* offset
, char** value
)
235 uint32_t lensize
= 0;
241 if (type
>> 5 == 0x5) {
246 len
= tvb_get_uint8(tvb
, *offset
+ 1);
250 len
= tvb_get_ntohs(tvb
, *offset
+ 1);
254 len
= tvb_get_ntohl(tvb
, *offset
+ 1);
258 lvalue
= (char*)tvb_get_string_enc(pinfo
->pool
, tvb
, *offset
+ 1 + lensize
, len
, ENC_NA
);
259 label
= (data
? (char*)data
: "MsgPack String");
261 ti
= proto_tree_add_string_format(tree
, hf_msgpack_string
, tvb
, *offset
, 1 + lensize
+ len
, lvalue
, "%s: %s", label
, lvalue
);
263 subtree
= proto_item_add_subtree(ti
, ett_msgpack_string
);
265 proto_tree_add_uint_format(subtree
, hf_msgpack_type
, tvb
, *offset
, 1, type
, "Type: String");
266 proto_tree_add_uint_format(subtree
, hf_msgpack_string_len
, tvb
, *offset
, 1, lensize
, "Length: 1");
267 proto_tree_add_item(subtree
, hf_msgpack_string
, tvb
, *offset
+ 1 + lensize
, len
, ENC_ASCII
);
269 proto_tree_add_item(subtree
, hf_msgpack_type
, tvb
, *offset
, 1, ENC_NA
);
270 proto_tree_add_item(subtree
, hf_msgpack_string_len
, tvb
, *offset
+ 1, lensize
, ENC_BIG_ENDIAN
);
271 proto_tree_add_item(subtree
, hf_msgpack_string
, tvb
, *offset
+ 1 + lensize
, len
, ENC_ASCII
);
273 *offset
+= 1 + lensize
+ len
;
279 static void dissect_msgpack_float(tvbuff_t
* tvb
, packet_info
*pinfo
, proto_tree
* tree
, int type
, void* data
, int* offset
, char** value
)
284 label
= (data
? (char*)data
: "Float");
289 float f
= tvb_get_ntohieee_float(tvb
, *offset
);
290 lvalue
= wmem_strdup_printf(pinfo
->pool
, "%f", f
);
291 proto_tree_add_string_format(tree
, hf_msgpack_float
, tvb
, *offset
, 4, lvalue
, "%s: %f", label
, f
);
296 double d
= tvb_get_ntohieee_double(tvb
, *offset
);
297 lvalue
= wmem_strdup_printf(pinfo
->pool
, "%f", d
);
298 proto_tree_add_string_format(tree
, hf_msgpack_float
, tvb
, *offset
, 8, lvalue
, "%s: %f", label
, d
);
305 static void dissect_msgpack_ext(tvbuff_t
* tvb
, proto_tree
* tree
, int type
, void* data
, int* offset
, char** value
)
309 const uint8_t* start
;
310 proto_tree
* ext_tree
;
311 unsigned offset_start
= *offset
;
313 label
= (data
? (char*)data
: "Ext");
315 ext_tree
= proto_tree_add_subtree(tree
, tvb
, *offset
, 0, ett_msgpack_ext
, NULL
, label
);
317 proto_tree_add_item(ext_tree
, hf_msgpack_ext_fixext
, tvb
, *offset
, 1, ENC_NA
);
320 if (type
>= 0xd4 && type
<= 0xd8) {
321 proto_tree_add_item(ext_tree
, hf_msgpack_ext_type
, tvb
, *offset
, 1, ENC_NA
);
323 bytes
= 1 << (type
- 0xd4);
324 start
= (const uint8_t*)tvb_get_ptr(tvb
, *offset
, bytes
);
325 proto_tree_add_bytes(ext_tree
, hf_msgpack_ext_bytes
, tvb
, *offset
, bytes
, start
);
327 *value
= bytes_to_hexstr(*value
, start
, bytes
);
331 proto_item_set_len(ext_tree
, *offset
- offset_start
);
334 // NOLINTNEXTLINE(misc-no-recursion)
335 static void dissect_msgpack_object(tvbuff_t
* tvb
, packet_info
* pinfo
, proto_tree
* tree
, void* data
, int* offset
, char** value
)
339 type
= tvb_get_uint8(tvb
, *offset
);
343 proto_tree_add_string_format(tree
, hf_msgpack_string
, tvb
, *offset
, 1, "nil", "nil");
351 if (type
== 0xc2 || type
== 0xc3) {
352 proto_tree_add_boolean(tree
, hf_msgpack_bool
, tvb
, *offset
, 1, type
- 0xc2);
354 *value
= (type
- 0xc2) ? "True" : "False";
360 if (type
>= 0xe0 || type
<= 0x7f || (type
>= 0xcc && type
<= 0xd3)) {
361 dissect_msgpack_integer(tvb
, pinfo
, tree
, type
, data
, offset
, value
);
366 if (type
== 0xca || type
== 0xcb) {
367 dissect_msgpack_float(tvb
, pinfo
, tree
, type
, data
, offset
, value
);
372 if (type
>> 5 == 0x5 || type
== 0xd9 || type
== 0xda || type
== 0xdb) {
373 dissect_msgpack_string(tvb
, pinfo
, tree
, type
, data
, offset
, value
);
378 if (type
>> 4 == 0x9 || type
== 0xdc || type
== 0xdd) {
379 // We recurse here, but we'll run out of packet before we run out of stack.
380 dissect_msgpack_array(tvb
, pinfo
, tree
, type
, data
, offset
, value
);
385 if (type
>> 4 == 0x8) {
386 // We recurse here, but we'll run out of packet before we run out of stack.
387 dissect_msgpack_map(tvb
, pinfo
, tree
, type
, data
, offset
, value
);
392 if ((type
>= 0xd4 && type
<= 0xd8) || (type
>= 0xc7 && type
<= 0xc9)) {
393 dissect_msgpack_ext(tvb
, tree
, type
, data
, offset
, value
);
398 expert_add_info_format(pinfo
, tree
, &ei_msgpack_unsupported
, "Type 0x%x is unsupported", type
);
402 static int dissect_msgpack(tvbuff_t
* tvb
, packet_info
* pinfo
, proto_tree
* tree
, void* data
)
405 dissect_msgpack_object(tvb
, pinfo
, tree
, data
, &offset
, NULL
);
409 void proto_register_msgpack(void)
411 expert_module_t
* expert_msgpack
;
413 static hf_register_info hf
[] = {
414 { &hf_msgpack_string
,
415 { "String", "msgpack.string", FT_STRING
, BASE_NONE
, NULL
, 0x00, NULL
, HFILL
}
418 { "Type", "msgpack.type", FT_UINT8
, BASE_HEX
, NULL
, 0x00, NULL
, HFILL
}
420 { &hf_msgpack_string_len
,
421 { "Length", "msgpack.string.len", FT_UINT16
, BASE_DEC
, NULL
, 0x00, NULL
, HFILL
}
423 { &hf_msgpack_uint_8
,
424 { "Integer", "msgpack.integer.u8", FT_UINT8
, BASE_DEC
, NULL
, 0x00, NULL
, HFILL
}
426 { &hf_msgpack_uint_16
,
427 { "Integer", "msgpack.integer.u16", FT_UINT16
, BASE_DEC
, NULL
, 0x00, NULL
, HFILL
}
429 { &hf_msgpack_uint_32
,
430 { "Integer", "msgpack.integer.u32", FT_UINT32
, BASE_DEC
, NULL
, 0x00, NULL
, HFILL
}
432 { &hf_msgpack_uint_64
,
433 { "Integer", "msgpack.integer.u64", FT_UINT64
, BASE_DEC
, NULL
, 0x00, NULL
, HFILL
}
436 { "Integer", "msgpack.integer.8", FT_INT8
, BASE_DEC
, NULL
, 0x00, NULL
, HFILL
}
438 { &hf_msgpack_int_16
,
439 { "Integer", "msgpack.integer.16", FT_INT16
, BASE_DEC
, NULL
, 0x00, NULL
, HFILL
}
441 { &hf_msgpack_int_32
,
442 { "Integer", "msgpack.integer.32", FT_INT32
, BASE_DEC
, NULL
, 0x00, NULL
, HFILL
}
444 { &hf_msgpack_int_64
,
445 { "Integer", "msgpack.integer.64", FT_INT64
, BASE_DEC
, NULL
, 0x00, NULL
, HFILL
}
448 { "Boolean", "msgpack.boolean", FT_BOOLEAN
, BASE_NONE
, NULL
, 0x00, NULL
, HFILL
}
451 { "Float", "msgpack.float", FT_STRING
, BASE_NONE
, NULL
, 0x00, NULL
, HFILL
}
453 { &hf_msgpack_ext_fixext
,
454 { "Ext fix text", "msgpack.ext.fixtext", FT_UINT8
, BASE_HEX
, VALS(msgpack_ext_fixtexts
), 0x00, NULL
, HFILL
}
456 { &hf_msgpack_ext_type
,
457 { "Ext type", "msgpack.ext.type", FT_INT8
, BASE_DEC
, NULL
, 0x00, NULL
, HFILL
}
459 { &hf_msgpack_ext_bytes
,
460 { "Ext", "msgpack.ext", FT_BYTES
, BASE_NONE
, NULL
, 0x00, NULL
, HFILL
}
464 static int* ett
[] = {
469 &ett_msgpack_map_elem
,
473 static ei_register_info ei
[] = {
474 { &ei_msgpack_unsupported
, { "msgpack.unsupported", PI_UNDECODED
, PI_WARN
, "Unsupported type", EXPFILL
}}
477 proto_msgpack
= proto_register_protocol("Message Pack", "MsgPack", "msgpack");
478 msgpack_handle
= register_dissector("msgpack", dissect_msgpack
, proto_msgpack
);
480 expert_msgpack
= expert_register_protocol(proto_msgpack
);
481 expert_register_field_array(expert_msgpack
, ei
, array_length(ei
));
483 proto_register_field_array(proto_msgpack
, hf
, array_length(hf
));
484 proto_register_subtree_array(ett
, array_length(ett
));
487 void proto_reg_handoff_msgpack(void)
489 // If this is ever streamed (transported over TCP) we need to add recursion checks
490 dissector_add_for_decode_as("udp.port", msgpack_handle
);
494 * Editor modelines - https://www.wireshark.org/tools/modelines.html
499 * indent-tabs-mode: t
502 * vi: set shiftwidth=8 tabstop=8 noexpandtab:
503 * :indentSize=8:tabSize=8:noTabs=false: