Coverage Report

Created: 2025-02-15 06:25

/src/wireshark/epan/dissectors/packet-msgpack.c
Line
Count
Source (jump to first uncovered line)
1
/* packet-msgpack.c
2
 *
3
 * Routines for MsgPack dissection
4
 * References:
5
 *   https://github.com/msgpack/msgpack/
6
 *
7
 * Copyright 2018, Dario Lombardo <lomato@gmail.com>
8
 *
9
 * Wireshark - Network traffic analyzer
10
 * By Gerald Combs <gerald@wireshark.org>
11
 * Copyright 1998 Gerald Combs
12
 *
13
 * SPDX-License-Identifier: GPL-2.0-or-later
14
 */
15
16
#include "config.h"
17
18
#include <wsutil/array.h>
19
#include <epan/packet.h>
20
#include <epan/expert.h>
21
#include <epan/to_str.h>
22
23
24
25
void proto_register_msgpack(void);
26
void proto_reg_handoff_msgpack(void);
27
28
dissector_handle_t msgpack_handle;
29
30
static int proto_msgpack;
31
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;
48
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;
55
56
static expert_field ei_msgpack_unsupported;
57
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 }
65
};
66
67
static void dissect_msgpack_object(tvbuff_t* tvb, packet_info* pinfo, proto_tree* tree, void* data, int* offset, char** value);
68
69
static void dissect_msgpack_integer(tvbuff_t* tvb, packet_info *pinfo, proto_tree* tree, uint8_t type, void* data, int* offset, char** value)
70
0
{
71
0
  uint8_t uint8;
72
0
  uint16_t uint16;
73
0
  uint32_t uint32;
74
0
  uint64_t uint64;
75
0
  int8_t int8;
76
0
  int16_t int16;
77
0
  int32_t int32;
78
0
  int64_t int64;
79
0
  char* label;
80
81
0
  label = (data ? (char*)data : "MsgPack Integer");
82
83
0
  if (type >> 7 == 0) {
84
0
    proto_tree_add_uint_format(tree, hf_msgpack_uint_8, tvb, *offset, 1, type, "%s: %u", label, type);
85
0
    if (value)
86
0
      *value = wmem_strdup_printf(pinfo->pool, "%u", type);
87
0
    *offset += 1;
88
0
    return;
89
0
  }
90
91
0
  if (type >> 5 == 7) {
92
0
    proto_tree_add_int_format(tree, hf_msgpack_int_8, tvb, *offset, 1, type, "%s: %u", label, type);
93
0
    if (value)
94
0
      *value = wmem_strdup_printf(pinfo->pool, "%d", type);
95
0
    *offset += 1;
96
0
    return;
97
0
  }
98
99
0
  switch (type) {
100
0
    case 0xcc:
101
0
      uint8 = tvb_get_uint8(tvb, *offset + 1);
102
0
      proto_tree_add_uint_format(tree, hf_msgpack_uint_8, tvb, *offset, 2, uint8, "%s: %u", label, uint8);
103
0
      if (value)
104
0
        *value = wmem_strdup_printf(pinfo->pool, "%u", uint8);
105
0
      *offset += 2;
106
0
      break;
107
0
    case 0xcd:
108
0
      uint16 = tvb_get_ntohs(tvb, *offset + 1);
109
0
      proto_tree_add_uint(tree, hf_msgpack_uint_16, tvb, *offset, 3, uint16);
110
0
      if (value)
111
0
        *value = wmem_strdup_printf(pinfo->pool, "%u", uint16);
112
0
      *offset += 3;
113
0
      break;
114
0
    case 0xce:
115
0
      uint32 = tvb_get_ntohl(tvb, *offset + 1);
116
0
      proto_tree_add_uint(tree, hf_msgpack_uint_32, tvb, *offset, 5, uint32);
117
0
      if (value)
118
0
        *value = wmem_strdup_printf(pinfo->pool, "%u", uint32);
119
0
      *offset += 5;
120
0
      break;
121
0
    case 0xcf:
122
0
      uint64 = tvb_get_ntoh64(tvb, *offset + 1);
123
0
      proto_tree_add_uint64(tree, hf_msgpack_uint_64, tvb, *offset, 9, uint64);
124
0
      if (value)
125
0
        *value = wmem_strdup_printf(pinfo->pool, "%" PRIu64, uint64);
126
0
      *offset += 9;
127
0
      break;
128
0
    case 0xd0:
129
0
      int8 = tvb_get_int8(tvb, *offset + 1);
130
0
      proto_tree_add_int(tree, hf_msgpack_int_8, tvb, *offset, 2, int8);
131
0
      if (value)
132
0
        *value = wmem_strdup_printf(pinfo->pool, "%d", int8);
133
0
      *offset += 2;
134
0
      break;
135
0
    case 0xd1:
136
0
      int16 = tvb_get_ntohs(tvb, *offset + 1);
137
0
      proto_tree_add_int(tree, hf_msgpack_int_16, tvb, *offset, 3, int16);
138
0
      if (value)
139
0
        *value = wmem_strdup_printf(pinfo->pool, "%d", int16);
140
0
      *offset += 3;
141
0
      break;
142
0
    case 0xd2:
143
0
      int32 = tvb_get_ntohl(tvb, *offset + 1);
144
0
      proto_tree_add_int(tree, hf_msgpack_int_32, tvb, *offset, 5, int32);
145
0
      if (value)
146
0
        *value = wmem_strdup_printf(pinfo->pool, "%d", int32);
147
0
      *offset += 5;
148
0
      break;
149
0
    case 0xd3:
150
0
      int64 = tvb_get_ntoh64(tvb, *offset + 1);
151
0
      proto_tree_add_int64(tree, hf_msgpack_int_64, tvb, *offset, 9, int64);
152
0
      if (value)
153
0
        *value = wmem_strdup_printf(pinfo->pool, "%" PRId64, int64);
154
0
      *offset += 9;
155
0
      break;
156
0
    default:
157
0
      DISSECTOR_ASSERT_NOT_REACHED();
158
0
  }
159
0
}
160
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)
163
0
{
164
0
  proto_tree* subtree;
165
0
  proto_tree* map_subtree;
166
0
  proto_item* ti;
167
0
  uint8_t len;
168
0
  char* label;
169
0
  unsigned i;
170
171
0
  len = type & 0x0F;
172
173
0
  label = wmem_strdup_printf(pinfo->pool, "%s: %u element%s", data ? (char*)data : "MsgPack Map", len, len > 1 ? "s" : "");
174
175
0
  ti = proto_tree_add_string_format(tree, hf_msgpack_string, tvb, *offset, 1 + len, NULL, "%s", label);
176
0
  subtree = proto_item_add_subtree(ti, ett_msgpack_map);
177
0
  *offset += 1;
178
0
  for (i = 0; i < len; i++) {
179
0
    map_subtree = proto_tree_add_subtree(subtree, tvb, *offset, 0, ett_msgpack_map_elem, NULL, "");
180
0
    dissect_msgpack_object(tvb, pinfo, map_subtree, "Key", offset, value);
181
0
    if (value)
182
0
      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
0
    dissect_msgpack_object(tvb, pinfo, map_subtree, "Value", offset, value);
185
0
    if (value)
186
0
      proto_item_append_text(map_subtree, " %s", *value);
187
0
  }
188
189
0
  if (value)
190
0
    *value = label;
191
0
}
192
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)
195
0
{
196
0
  proto_tree* subtree;
197
0
  proto_item* ti;
198
0
  uint32_t len;
199
0
  uint32_t lensize = UINT32_MAX;
200
0
  char* label;
201
0
  unsigned i;
202
203
0
  if (type >> 4 == 0x9) {
204
0
    len = type & 0x0F;
205
0
    lensize = 0;
206
0
  }
207
0
  if (type == 0xdc) {
208
0
    len = tvb_get_ntohs(tvb, *offset + 1);
209
0
    lensize = 2;
210
0
  }
211
0
  if (type == 0xdd) {
212
0
    len = tvb_get_ntohl(tvb, *offset + 1);
213
0
    lensize = 4;
214
0
  }
215
216
0
  DISSECTOR_ASSERT(lensize != UINT32_MAX);
217
218
0
  label = wmem_strdup_printf(pinfo->pool, "%s %u element%s", data ? (char*)data : "MsgPack Array", len, len > 1 ? "s" : "");
219
220
0
  ti = proto_tree_add_string_format(tree, hf_msgpack_string, tvb, *offset, 1 + len, NULL, "%s", label);
221
0
  subtree = proto_item_add_subtree(ti, ett_msgpack_array);
222
0
  *offset += lensize + 1;
223
0
  for (i = 0; i < len; i++) {
224
    // We recurse here, but we'll run out of packet before we run out of stack.
225
0
    dissect_msgpack_object(tvb, pinfo, subtree, data, offset, value);
226
0
  }
227
228
0
  if (value)
229
0
    *value = label;
230
0
}
231
232
static void dissect_msgpack_string(tvbuff_t* tvb, packet_info* pinfo, proto_tree* tree, int type, void* data, int* offset, char** value)
233
0
{
234
0
  uint32_t len = 0;
235
0
  uint32_t lensize = 0;
236
0
  char* label;
237
0
  proto_item* ti;
238
0
  proto_tree* subtree;
239
0
  char* lvalue;
240
241
0
  if (type >> 5 == 0x5) {
242
0
    len = type & 0x1F;
243
0
    lensize = 0;
244
0
  }
245
0
  if (type == 0xd9) {
246
0
    len = tvb_get_uint8(tvb, *offset + 1);
247
0
    lensize = 1;
248
0
  }
249
0
  if (type == 0xda) {
250
0
    len = tvb_get_ntohs(tvb, *offset + 1);
251
0
    lensize = 2;
252
0
  }
253
0
  if (type == 0xdb) {
254
0
    len = tvb_get_ntohl(tvb, *offset + 1);
255
0
    lensize = 4;
256
0
  }
257
258
0
  lvalue = (char*)tvb_get_string_enc(pinfo->pool, tvb, *offset + 1 + lensize, len, ENC_NA);
259
0
  label = (data ? (char*)data : "MsgPack String");
260
261
0
  ti = proto_tree_add_string_format(tree, hf_msgpack_string, tvb, *offset, 1 + lensize + len, lvalue, "%s: %s", label, lvalue);
262
263
0
  subtree = proto_item_add_subtree(ti, ett_msgpack_string);
264
0
  if (lensize == 0) {
265
0
    proto_tree_add_uint_format(subtree, hf_msgpack_type, tvb, *offset, 1, type, "Type: String");
266
0
    proto_tree_add_uint_format(subtree, hf_msgpack_string_len, tvb, *offset, 1, lensize, "Length: 1");
267
0
    proto_tree_add_item(subtree, hf_msgpack_string, tvb, *offset + 1 + lensize, len, ENC_ASCII);
268
0
  } else {
269
0
    proto_tree_add_item(subtree, hf_msgpack_type, tvb, *offset, 1, ENC_NA);
270
0
    proto_tree_add_item(subtree, hf_msgpack_string_len, tvb, *offset + 1, lensize, ENC_BIG_ENDIAN);
271
0
    proto_tree_add_item(subtree, hf_msgpack_string, tvb, *offset + 1 + lensize, len, ENC_ASCII);
272
0
  }
273
0
  *offset += 1 + lensize + len;
274
275
0
  if (value)
276
0
    *value = lvalue;
277
0
}
278
279
static void dissect_msgpack_float(tvbuff_t* tvb, packet_info *pinfo, proto_tree* tree, int type, void* data, int* offset, char** value)
280
0
{
281
0
  char* label;
282
0
  char* lvalue;
283
284
0
  label = (data ? (char*)data : "Float");
285
286
0
  *offset += 1;
287
288
0
  if (type == 0xca) {
289
0
    float f = tvb_get_ntohieee_float(tvb, *offset);
290
0
    lvalue = wmem_strdup_printf(pinfo->pool, "%f", f);
291
0
    proto_tree_add_string_format(tree, hf_msgpack_float, tvb, *offset, 4, lvalue, "%s: %f", label, f);
292
0
    if (value)
293
0
      *value = lvalue;
294
0
    *offset += 4;
295
0
  } else {
296
0
    double d = tvb_get_ntohieee_double(tvb, *offset);
297
0
    lvalue = wmem_strdup_printf(pinfo->pool, "%f", d);
298
0
    proto_tree_add_string_format(tree, hf_msgpack_float, tvb, *offset, 8, lvalue, "%s: %f", label, d);
299
0
    if (value)
300
0
      *value = lvalue;
301
0
    *offset += 8;
302
0
  }
303
0
}
304
305
static void dissect_msgpack_ext(tvbuff_t* tvb, proto_tree* tree, int type, void* data, int* offset, char** value)
306
0
{
307
0
  char* label;
308
0
  int bytes;
309
0
  const uint8_t* start;
310
0
  proto_tree* ext_tree;
311
0
  unsigned offset_start = *offset;
312
313
0
  label = (data ? (char*)data : "Ext");
314
315
0
  ext_tree = proto_tree_add_subtree(tree, tvb, *offset, 0, ett_msgpack_ext, NULL, label);
316
317
0
  proto_tree_add_item(ext_tree, hf_msgpack_ext_fixext, tvb, *offset, 1, ENC_NA);
318
0
  *offset += 1;
319
320
0
  if (type >= 0xd4 && type <= 0xd8) {
321
0
    proto_tree_add_item(ext_tree, hf_msgpack_ext_type, tvb, *offset, 1, ENC_NA);
322
0
    *offset += 1;
323
0
    bytes = 1 << (type - 0xd4);
324
0
    start = (const uint8_t*)tvb_get_ptr(tvb, *offset, bytes);
325
0
    proto_tree_add_bytes(ext_tree, hf_msgpack_ext_bytes, tvb, *offset, bytes, start);
326
0
    if (value)
327
0
      *value = bytes_to_hexstr(*value, start, bytes);
328
0
    *offset += bytes;
329
0
  }
330
331
0
  proto_item_set_len(ext_tree, *offset - offset_start);
332
0
}
333
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)
336
0
{
337
0
  uint8_t type;
338
339
0
  type = tvb_get_uint8(tvb, *offset);
340
341
  // Nil
342
0
  if (type == 0xc0) {
343
0
    proto_tree_add_string_format(tree, hf_msgpack_string, tvb, *offset, 1, "nil", "nil");
344
0
    if (value)
345
0
      *value = "nil";
346
0
    *offset += 1;
347
0
    return;
348
0
  }
349
350
  // True/False
351
0
  if (type == 0xc2 || type == 0xc3) {
352
0
    proto_tree_add_boolean(tree, hf_msgpack_bool, tvb, *offset, 1, type - 0xc2);
353
0
    if (value)
354
0
      *value = (type - 0xc2) ? "True" : "False";
355
0
    *offset += 1;
356
0
    return;
357
0
  }
358
359
  // Integer
360
0
  if (type >= 0xe0 || type <= 0x7f || (type >= 0xcc && type <= 0xd3)) {
361
0
    dissect_msgpack_integer(tvb, pinfo, tree, type, data, offset, value);
362
0
    return;
363
0
  }
364
365
  // Float
366
0
  if (type == 0xca || type == 0xcb) {
367
0
    dissect_msgpack_float(tvb, pinfo, tree, type, data, offset, value);
368
0
    return;
369
0
  }
370
371
  // String
372
0
  if (type >> 5 == 0x5 || type == 0xd9 || type == 0xda || type == 0xdb) {
373
0
    dissect_msgpack_string(tvb, pinfo, tree, type, data, offset, value);
374
0
    return;
375
0
  }
376
377
  // Array
378
0
  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
0
    dissect_msgpack_array(tvb, pinfo, tree, type, data, offset, value);
381
0
    return;
382
0
  }
383
384
  // Map
385
0
  if (type >> 4 == 0x8) {
386
    // We recurse here, but we'll run out of packet before we run out of stack.
387
0
    dissect_msgpack_map(tvb, pinfo, tree, type, data, offset, value);
388
0
    return;
389
0
  }
390
391
  // Ext
392
0
  if ((type >= 0xd4 && type <= 0xd8) || (type >= 0xc7 && type <= 0xc9)) {
393
0
    dissect_msgpack_ext(tvb, tree, type, data, offset, value);
394
0
    return;
395
0
  }
396
397
0
  if (*offset == 0) {
398
0
    expert_add_info_format(pinfo, tree, &ei_msgpack_unsupported, "Type 0x%x is unsupported", type);
399
0
  }
400
0
}
401
402
static int dissect_msgpack(tvbuff_t* tvb, packet_info* pinfo, proto_tree* tree, void* data)
403
0
{
404
0
  int offset = 0;
405
0
  dissect_msgpack_object(tvb, pinfo, tree, data, &offset, NULL);
406
0
  return offset;
407
0
}
408
409
void proto_register_msgpack(void)
410
14
{
411
14
  expert_module_t* expert_msgpack;
412
413
14
  static hf_register_info hf[] = {
414
14
    { &hf_msgpack_string,
415
14
      { "String", "msgpack.string", FT_STRING, BASE_NONE, NULL, 0x00, NULL, HFILL }
416
14
    },
417
14
    { &hf_msgpack_type,
418
14
      { "Type", "msgpack.type", FT_UINT8, BASE_HEX, NULL, 0x00, NULL, HFILL }
419
14
    },
420
14
    { &hf_msgpack_string_len,
421
14
      { "Length", "msgpack.string.len", FT_UINT16, BASE_DEC, NULL, 0x00, NULL, HFILL }
422
14
    },
423
14
    { &hf_msgpack_uint_8,
424
14
      { "Integer", "msgpack.integer.u8", FT_UINT8, BASE_DEC, NULL, 0x00, NULL, HFILL }
425
14
    },
426
14
    { &hf_msgpack_uint_16,
427
14
      { "Integer", "msgpack.integer.u16", FT_UINT16, BASE_DEC, NULL, 0x00, NULL, HFILL }
428
14
    },
429
14
    { &hf_msgpack_uint_32,
430
14
      { "Integer", "msgpack.integer.u32", FT_UINT32, BASE_DEC, NULL, 0x00, NULL, HFILL }
431
14
    },
432
14
    { &hf_msgpack_uint_64,
433
14
      { "Integer", "msgpack.integer.u64", FT_UINT64, BASE_DEC, NULL, 0x00, NULL, HFILL }
434
14
    },
435
14
    { &hf_msgpack_int_8,
436
14
      { "Integer", "msgpack.integer.8", FT_INT8, BASE_DEC, NULL, 0x00, NULL, HFILL }
437
14
    },
438
14
    { &hf_msgpack_int_16,
439
14
      { "Integer", "msgpack.integer.16", FT_INT16, BASE_DEC, NULL, 0x00, NULL, HFILL }
440
14
    },
441
14
    { &hf_msgpack_int_32,
442
14
      { "Integer", "msgpack.integer.32", FT_INT32, BASE_DEC, NULL, 0x00, NULL, HFILL }
443
14
    },
444
14
    { &hf_msgpack_int_64,
445
14
      { "Integer", "msgpack.integer.64", FT_INT64, BASE_DEC, NULL, 0x00, NULL, HFILL }
446
14
    },
447
14
    { &hf_msgpack_bool,
448
14
      { "Boolean", "msgpack.boolean", FT_BOOLEAN, BASE_NONE, NULL, 0x00, NULL, HFILL }
449
14
    },
450
14
    { &hf_msgpack_float,
451
14
      { "Float", "msgpack.float", FT_STRING, BASE_NONE, NULL, 0x00, NULL, HFILL }
452
14
    },
453
14
    { &hf_msgpack_ext_fixext,
454
14
      { "Ext fix text", "msgpack.ext.fixtext", FT_UINT8, BASE_HEX, VALS(msgpack_ext_fixtexts), 0x00, NULL, HFILL }
455
14
    },
456
14
    { &hf_msgpack_ext_type,
457
14
      { "Ext type", "msgpack.ext.type", FT_INT8, BASE_DEC, NULL, 0x00, NULL, HFILL }
458
14
    },
459
14
    { &hf_msgpack_ext_bytes,
460
14
      { "Ext", "msgpack.ext", FT_BYTES, BASE_NONE, NULL, 0x00, NULL, HFILL }
461
14
    }
462
14
  };
463
464
14
  static int* ett[] = {
465
14
    &ett_msgpack,
466
14
    &ett_msgpack_string,
467
14
    &ett_msgpack_array,
468
14
    &ett_msgpack_map,
469
14
    &ett_msgpack_map_elem,
470
14
    &ett_msgpack_ext
471
14
  };
472
473
14
  static ei_register_info ei[] = {
474
14
    { &ei_msgpack_unsupported, { "msgpack.unsupported", PI_UNDECODED, PI_WARN, "Unsupported type", EXPFILL }}
475
14
  };
476
477
14
  proto_msgpack = proto_register_protocol("Message Pack", "MsgPack", "msgpack");
478
14
  msgpack_handle = register_dissector("msgpack", dissect_msgpack, proto_msgpack);
479
480
14
  expert_msgpack = expert_register_protocol(proto_msgpack);
481
14
  expert_register_field_array(expert_msgpack, ei, array_length(ei));
482
483
14
  proto_register_field_array(proto_msgpack, hf, array_length(hf));
484
14
  proto_register_subtree_array(ett, array_length(ett));
485
14
}
486
487
void proto_reg_handoff_msgpack(void)
488
14
{
489
  // If this is ever streamed (transported over TCP) we need to add recursion checks
490
14
  dissector_add_for_decode_as("udp.port", msgpack_handle);
491
14
}
492
493
/*
494
 * Editor modelines  -  https://www.wireshark.org/tools/modelines.html
495
 *
496
 * Local variables:
497
 * c-basic-offset: 8
498
 * tab-width: 8
499
 * indent-tabs-mode: t
500
 * End:
501
 *
502
 * vi: set shiftwidth=8 tabstop=8 noexpandtab:
503
 * :indentSize=8:tabSize=8:noTabs=false:
504
 */