Revert "TODO epan/dissectors/asn1/kerberos/packet-kerberos-template.c new GSS flags"
[wireshark-sm.git] / epan / dissectors / packet-msgpack.c
blob7a38316f2e9aa1bd1565ba9dd69be1e5d4609a04
1 /* packet-msgpack.c
3 * Routines for MsgPack dissection
4 * References:
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
16 #include "config.h"
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[] = {
59 { 0xd4, "fixext 1" },
60 { 0xd5, "fixext 2" },
61 { 0xd6, "fixext 4" },
62 { 0xd7, "fixext 8" },
63 { 0xd8, "fixext 16" },
64 { 0, NULL }
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)
71 uint8_t uint8;
72 uint16_t uint16;
73 uint32_t uint32;
74 uint64_t uint64;
75 int8_t int8;
76 int16_t int16;
77 int32_t int32;
78 int64_t int64;
79 char* label;
81 label = (data ? (char*)data : "MsgPack Integer");
83 if (type >> 7 == 0) {
84 proto_tree_add_uint_format(tree, hf_msgpack_uint_8, tvb, *offset, 1, type, "%s: %u", label, type);
85 if (value)
86 *value = wmem_strdup_printf(pinfo->pool, "%u", type);
87 *offset += 1;
88 return;
91 if (type >> 5 == 7) {
92 proto_tree_add_int_format(tree, hf_msgpack_int_8, tvb, *offset, 1, type, "%s: %u", label, type);
93 if (value)
94 *value = wmem_strdup_printf(pinfo->pool, "%d", type);
95 *offset += 1;
96 return;
99 switch (type) {
100 case 0xcc:
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);
103 if (value)
104 *value = wmem_strdup_printf(pinfo->pool, "%u", uint8);
105 *offset += 2;
106 break;
107 case 0xcd:
108 uint16 = tvb_get_ntohs(tvb, *offset + 1);
109 proto_tree_add_uint(tree, hf_msgpack_uint_16, tvb, *offset, 3, uint16);
110 if (value)
111 *value = wmem_strdup_printf(pinfo->pool, "%u", uint16);
112 *offset += 3;
113 break;
114 case 0xce:
115 uint32 = tvb_get_ntohl(tvb, *offset + 1);
116 proto_tree_add_uint(tree, hf_msgpack_uint_32, tvb, *offset, 5, uint32);
117 if (value)
118 *value = wmem_strdup_printf(pinfo->pool, "%u", uint32);
119 *offset += 5;
120 break;
121 case 0xcf:
122 uint64 = tvb_get_ntoh64(tvb, *offset + 1);
123 proto_tree_add_uint64(tree, hf_msgpack_uint_64, tvb, *offset, 9, uint64);
124 if (value)
125 *value = wmem_strdup_printf(pinfo->pool, "%" PRIu64, uint64);
126 *offset += 9;
127 break;
128 case 0xd0:
129 int8 = tvb_get_int8(tvb, *offset + 1);
130 proto_tree_add_int(tree, hf_msgpack_int_8, tvb, *offset, 2, int8);
131 if (value)
132 *value = wmem_strdup_printf(pinfo->pool, "%d", int8);
133 *offset += 2;
134 break;
135 case 0xd1:
136 int16 = tvb_get_ntohs(tvb, *offset + 1);
137 proto_tree_add_int(tree, hf_msgpack_int_16, tvb, *offset, 3, int16);
138 if (value)
139 *value = wmem_strdup_printf(pinfo->pool, "%d", int16);
140 *offset += 3;
141 break;
142 case 0xd2:
143 int32 = tvb_get_ntohl(tvb, *offset + 1);
144 proto_tree_add_int(tree, hf_msgpack_int_32, tvb, *offset, 5, int32);
145 if (value)
146 *value = wmem_strdup_printf(pinfo->pool, "%d", int32);
147 *offset += 5;
148 break;
149 case 0xd3:
150 int64 = tvb_get_ntoh64(tvb, *offset + 1);
151 proto_tree_add_int64(tree, hf_msgpack_int_64, tvb, *offset, 9, int64);
152 if (value)
153 *value = wmem_strdup_printf(pinfo->pool, "%" PRId64, int64);
154 *offset += 9;
155 break;
156 default:
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)
164 proto_tree* subtree;
165 proto_tree* map_subtree;
166 proto_item* ti;
167 uint8_t len;
168 char* label;
169 unsigned i;
171 len = type & 0x0F;
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);
177 *offset += 1;
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);
181 if (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);
185 if (value)
186 proto_item_append_text(map_subtree, " %s", *value);
189 if (value)
190 *value = label;
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)
196 proto_tree* subtree;
197 proto_item* ti;
198 uint32_t len;
199 uint32_t lensize = UINT32_MAX;
200 char* label;
201 unsigned i;
203 if (type >> 4 == 0x9) {
204 len = type & 0x0F;
205 lensize = 0;
207 if (type == 0xdc) {
208 len = tvb_get_ntohs(tvb, *offset + 1);
209 lensize = 2;
211 if (type == 0xdd) {
212 len = tvb_get_ntohl(tvb, *offset + 1);
213 lensize = 4;
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);
228 if (value)
229 *value = label;
232 static void dissect_msgpack_string(tvbuff_t* tvb, packet_info* pinfo, proto_tree* tree, int type, void* data, int* offset, char** value)
234 uint32_t len = 0;
235 uint32_t lensize = 0;
236 char* label;
237 proto_item* ti;
238 proto_tree* subtree;
239 char* lvalue;
241 if (type >> 5 == 0x5) {
242 len = type & 0x1F;
243 lensize = 0;
245 if (type == 0xd9) {
246 len = tvb_get_uint8(tvb, *offset + 1);
247 lensize = 1;
249 if (type == 0xda) {
250 len = tvb_get_ntohs(tvb, *offset + 1);
251 lensize = 2;
253 if (type == 0xdb) {
254 len = tvb_get_ntohl(tvb, *offset + 1);
255 lensize = 4;
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);
264 if (lensize == 0) {
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);
268 } else {
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;
275 if (value)
276 *value = lvalue;
279 static void dissect_msgpack_float(tvbuff_t* tvb, packet_info *pinfo, proto_tree* tree, int type, void* data, int* offset, char** value)
281 char* label;
282 char* lvalue;
284 label = (data ? (char*)data : "Float");
286 *offset += 1;
288 if (type == 0xca) {
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);
292 if (value)
293 *value = lvalue;
294 *offset += 4;
295 } else {
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);
299 if (value)
300 *value = lvalue;
301 *offset += 8;
305 static void dissect_msgpack_ext(tvbuff_t* tvb, proto_tree* tree, int type, void* data, int* offset, char** value)
307 char* label;
308 int bytes;
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);
318 *offset += 1;
320 if (type >= 0xd4 && type <= 0xd8) {
321 proto_tree_add_item(ext_tree, hf_msgpack_ext_type, tvb, *offset, 1, ENC_NA);
322 *offset += 1;
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);
326 if (value)
327 *value = bytes_to_hexstr(*value, start, bytes);
328 *offset += 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)
337 uint8_t type;
339 type = tvb_get_uint8(tvb, *offset);
341 // Nil
342 if (type == 0xc0) {
343 proto_tree_add_string_format(tree, hf_msgpack_string, tvb, *offset, 1, "nil", "nil");
344 if (value)
345 *value = "nil";
346 *offset += 1;
347 return;
350 // True/False
351 if (type == 0xc2 || type == 0xc3) {
352 proto_tree_add_boolean(tree, hf_msgpack_bool, tvb, *offset, 1, type - 0xc2);
353 if (value)
354 *value = (type - 0xc2) ? "True" : "False";
355 *offset += 1;
356 return;
359 // Integer
360 if (type >= 0xe0 || type <= 0x7f || (type >= 0xcc && type <= 0xd3)) {
361 dissect_msgpack_integer(tvb, pinfo, tree, type, data, offset, value);
362 return;
365 // Float
366 if (type == 0xca || type == 0xcb) {
367 dissect_msgpack_float(tvb, pinfo, tree, type, data, offset, value);
368 return;
371 // String
372 if (type >> 5 == 0x5 || type == 0xd9 || type == 0xda || type == 0xdb) {
373 dissect_msgpack_string(tvb, pinfo, tree, type, data, offset, value);
374 return;
377 // Array
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);
381 return;
384 // Map
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);
388 return;
391 // Ext
392 if ((type >= 0xd4 && type <= 0xd8) || (type >= 0xc7 && type <= 0xc9)) {
393 dissect_msgpack_ext(tvb, tree, type, data, offset, value);
394 return;
397 if (*offset == 0) {
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)
404 int offset = 0;
405 dissect_msgpack_object(tvb, pinfo, tree, data, &offset, NULL);
406 return offset;
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 }
417 { &hf_msgpack_type,
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 }
435 { &hf_msgpack_int_8,
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 }
447 { &hf_msgpack_bool,
448 { "Boolean", "msgpack.boolean", FT_BOOLEAN, BASE_NONE, NULL, 0x00, NULL, HFILL }
450 { &hf_msgpack_float,
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[] = {
465 &ett_msgpack,
466 &ett_msgpack_string,
467 &ett_msgpack_array,
468 &ett_msgpack_map,
469 &ett_msgpack_map_elem,
470 &ett_msgpack_ext
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
496 * Local variables:
497 * c-basic-offset: 8
498 * tab-width: 8
499 * indent-tabs-mode: t
500 * End:
502 * vi: set shiftwidth=8 tabstop=8 noexpandtab:
503 * :indentSize=8:tabSize=8:noTabs=false: