/src/wireshark/epan/dissectors/packet-msgpack.c
Line | Count | Source |
1 | | /* packet-msgpack.c |
2 | | * |
3 | | * Routines for MsgPack dissection |
4 | | * References: |
5 | | * https://github.com/msgpack/msgpack/blob/master/spec.md |
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 | | #include <epan/proto_data.h> |
23 | | |
24 | | |
25 | | |
26 | | void proto_register_msgpack(void); |
27 | | void proto_reg_handoff_msgpack(void); |
28 | | |
29 | | static dissector_handle_t msgpack_handle; |
30 | | |
31 | | static int proto_msgpack; |
32 | | |
33 | | static int hf_msgpack_string; |
34 | | static int hf_msgpack_bin; |
35 | | static int hf_msgpack_type; |
36 | | static int hf_msgpack_string_len; |
37 | | static int hf_msgpack_bin_len; |
38 | | static int hf_msgpack_uint_fix; |
39 | | static int hf_msgpack_uint_8; |
40 | | static int hf_msgpack_uint_16; |
41 | | static int hf_msgpack_uint_32; |
42 | | static int hf_msgpack_uint_64; |
43 | | static int hf_msgpack_int_fix; |
44 | | static int hf_msgpack_int_8; |
45 | | static int hf_msgpack_int_16; |
46 | | static int hf_msgpack_int_32; |
47 | | static int hf_msgpack_int_64; |
48 | | static int hf_msgpack_bool; |
49 | | static int hf_msgpack_float; |
50 | | static int hf_msgpack_double; |
51 | | static int hf_msgpack_ext_type; |
52 | | static int hf_msgpack_ext_len; |
53 | | static int hf_msgpack_ext_bytes; |
54 | | |
55 | | static int ett_msgpack; |
56 | | static int ett_msgpack_num; |
57 | | static int ett_msgpack_string; |
58 | | static int ett_msgpack_bin; |
59 | | static int ett_msgpack_array; |
60 | | static int ett_msgpack_map; |
61 | | static int ett_msgpack_map_elem; |
62 | | static int ett_msgpack_ext; |
63 | | |
64 | | static expert_field ei_msgpack_unsupported; |
65 | | static expert_field ei_msgpack_too_deep; |
66 | | |
67 | 0 | #define MSGPACK_MAX_NESTING 32 |
68 | | |
69 | | /* names and ranges from https://github.com/msgpack/msgpack/blob/master/spec.md#formats */ |
70 | | static const range_string msgpack_types[] = { |
71 | | {0x00, 0x7F, "positive fixint"}, |
72 | | {0x80, 0x8F, "fixmap"}, |
73 | | {0x90, 0x9F, "fixarray"}, |
74 | | {0xA0, 0xBF, "fixstr"}, |
75 | | {0xC0, 0xC0, "nil"}, |
76 | | {0xC1, 0xC1, "(never used)"}, |
77 | | {0xC2, 0xC2, "false"}, |
78 | | {0xC3, 0xC3, "true"}, |
79 | | {0xC4, 0xC4, "bin 8"}, |
80 | | {0xC5, 0xC5, "bin 16"}, |
81 | | {0xC6, 0xC6, "bin 32"}, |
82 | | {0xC7, 0xC7, "ext 8"}, |
83 | | {0xC8, 0xC8, "ext 16"}, |
84 | | {0xC9, 0xC9, "ext 32"}, |
85 | | {0xCA, 0xCA, "float 32"}, |
86 | | {0xCB, 0xCB, "float 64"}, |
87 | | {0xCC, 0xCC, "uint 8"}, |
88 | | {0xCD, 0xCD, "uint 16"}, |
89 | | {0xCE, 0xCE, "uint 32"}, |
90 | | {0xCF, 0xCF, "uint 64"}, |
91 | | {0xD0, 0xD0, "int 8"}, |
92 | | {0xD1, 0xD1, "int 16"}, |
93 | | {0xD2, 0xD2, "int 32"}, |
94 | | {0xD3, 0xD3, "int 64"}, |
95 | | {0xD4, 0xD4, "fixext 1"}, |
96 | | {0xD5, 0xD5, "fixext 2"}, |
97 | | {0xD6, 0xD6, "fixext 4"}, |
98 | | {0xD7, 0xD7, "fixext 8"}, |
99 | | {0xD8, 0xD8, "fixext 16"}, |
100 | | {0xD9, 0xD9, "str 8"}, |
101 | | {0xDA, 0xDA, "str 16"}, |
102 | | {0xDB, 0xDB, "str 32"}, |
103 | | {0xDC, 0xDC, "array 16"}, |
104 | | {0xDD, 0xDD, "array 32"}, |
105 | | {0xDE, 0xDE, "map 16"}, |
106 | | {0xDF, 0xDF, "map 32"}, |
107 | | {0xE0, 0xFF, "negative fixint"}, |
108 | | {0x00, 0x00, NULL} |
109 | | }; |
110 | | |
111 | | static void dissect_msgpack_object(tvbuff_t* tvb, packet_info* pinfo, proto_tree* tree, void* data, unsigned* offset, char** value); |
112 | | |
113 | | static void dissect_msgpack_integer(tvbuff_t* tvb, packet_info *pinfo, proto_tree* tree, uint8_t type, void* data, unsigned* offset, char** value) |
114 | 0 | { |
115 | 0 | uint8_t uint8; |
116 | 0 | uint16_t uint16; |
117 | 0 | uint32_t uint32; |
118 | 0 | uint64_t uint64; |
119 | 0 | int8_t int8; |
120 | 0 | int16_t int16; |
121 | 0 | int32_t int32; |
122 | 0 | int64_t int64; |
123 | 0 | char* label; |
124 | 0 | proto_tree* subtree; |
125 | 0 | proto_item* ti; |
126 | 0 | int t_offset = *offset; |
127 | |
|
128 | 0 | label = (data ? (char*)data : "MsgPack Integer"); |
129 | |
|
130 | 0 | if (type >> 7 == 0) { |
131 | 0 | ti = proto_tree_add_uint_format(tree, hf_msgpack_uint_fix, tvb, *offset, 1, type, "%s: %u", label, type); |
132 | 0 | subtree = proto_item_add_subtree(ti, ett_msgpack_num); |
133 | 0 | proto_tree_add_item(subtree, hf_msgpack_type, tvb, *offset, 1, ENC_NA); |
134 | |
|
135 | 0 | if (value) |
136 | 0 | *value = wmem_strdup_printf(pinfo->pool, "%u", type); |
137 | 0 | *offset += 1; |
138 | 0 | return; |
139 | 0 | } |
140 | | |
141 | 0 | if (type >> 5 == 7) { |
142 | 0 | int8_t stype = (int8_t)type; |
143 | 0 | ti = proto_tree_add_int_format(tree, hf_msgpack_int_fix, tvb, *offset, 1, stype, "%s: %d", label, stype); |
144 | 0 | subtree = proto_item_add_subtree(ti, ett_msgpack_num); |
145 | 0 | proto_tree_add_item(subtree, hf_msgpack_type, tvb, *offset, 1, ENC_NA); |
146 | |
|
147 | 0 | if (value) |
148 | 0 | *value = wmem_strdup_printf(pinfo->pool, "%d", stype); |
149 | 0 | *offset += 1; |
150 | 0 | return; |
151 | 0 | } |
152 | | |
153 | 0 | switch (type) { |
154 | 0 | case 0xcc: |
155 | 0 | uint8 = tvb_get_uint8(tvb, *offset + 1); |
156 | 0 | ti = proto_tree_add_uint_format(tree, hf_msgpack_uint_8, tvb, *offset, 2, uint8, "%s: %u", label, uint8); |
157 | 0 | if (value) |
158 | 0 | *value = wmem_strdup_printf(pinfo->pool, "%u", uint8); |
159 | 0 | *offset += 2; |
160 | 0 | break; |
161 | 0 | case 0xcd: |
162 | 0 | uint16 = tvb_get_ntohs(tvb, *offset + 1); |
163 | 0 | ti = proto_tree_add_uint_format(tree, hf_msgpack_uint_16, tvb, *offset, 3, uint16, "%s: %u", label, uint16); |
164 | 0 | if (value) |
165 | 0 | *value = wmem_strdup_printf(pinfo->pool, "%u", uint16); |
166 | 0 | *offset += 3; |
167 | 0 | break; |
168 | 0 | case 0xce: |
169 | 0 | uint32 = tvb_get_ntohl(tvb, *offset + 1); |
170 | 0 | ti = proto_tree_add_uint_format(tree, hf_msgpack_uint_32, tvb, *offset, 5, uint32, "%s: %u", label, uint32); |
171 | 0 | if (value) |
172 | 0 | *value = wmem_strdup_printf(pinfo->pool, "%u", uint32); |
173 | 0 | *offset += 5; |
174 | 0 | break; |
175 | 0 | case 0xcf: |
176 | 0 | uint64 = tvb_get_ntoh64(tvb, *offset + 1); |
177 | 0 | ti = proto_tree_add_uint64_format(tree, hf_msgpack_uint_64, tvb, *offset, 9, uint64, "%s: %" PRIu64, label, uint64); |
178 | 0 | if (value) |
179 | 0 | *value = wmem_strdup_printf(pinfo->pool, "%" PRIu64, uint64); |
180 | 0 | *offset += 9; |
181 | 0 | break; |
182 | 0 | case 0xd0: |
183 | 0 | int8 = tvb_get_int8(tvb, *offset + 1); |
184 | 0 | ti = proto_tree_add_int_format(tree, hf_msgpack_int_8, tvb, *offset, 2, int8, "%s: %d", label, int8); |
185 | 0 | if (value) |
186 | 0 | *value = wmem_strdup_printf(pinfo->pool, "%d", int8); |
187 | 0 | *offset += 2; |
188 | 0 | break; |
189 | 0 | case 0xd1: |
190 | 0 | int16 = tvb_get_ntohs(tvb, *offset + 1); |
191 | 0 | ti = proto_tree_add_int_format(tree, hf_msgpack_int_16, tvb, *offset, 3, int16, "%s: %d", label, int16); |
192 | 0 | if (value) |
193 | 0 | *value = wmem_strdup_printf(pinfo->pool, "%d", int16); |
194 | 0 | *offset += 3; |
195 | 0 | break; |
196 | 0 | case 0xd2: |
197 | 0 | int32 = tvb_get_ntohl(tvb, *offset + 1); |
198 | 0 | ti = proto_tree_add_int_format(tree, hf_msgpack_int_32, tvb, *offset, 5, int32, "%s: %d", label, int32); |
199 | 0 | if (value) |
200 | 0 | *value = wmem_strdup_printf(pinfo->pool, "%d", int32); |
201 | 0 | *offset += 5; |
202 | 0 | break; |
203 | 0 | case 0xd3: |
204 | 0 | int64 = tvb_get_ntoh64(tvb, *offset + 1); |
205 | 0 | ti = proto_tree_add_int64_format(tree, hf_msgpack_int_64, tvb, *offset, 9, int64, "%s: %" PRId64, label, int64); |
206 | 0 | if (value) |
207 | 0 | *value = wmem_strdup_printf(pinfo->pool, "%" PRId64, int64); |
208 | 0 | *offset += 9; |
209 | 0 | break; |
210 | 0 | default: |
211 | 0 | DISSECTOR_ASSERT_NOT_REACHED(); |
212 | 0 | break; |
213 | 0 | } |
214 | 0 | subtree = proto_item_add_subtree(ti, ett_msgpack_num); |
215 | 0 | proto_tree_add_item(subtree, hf_msgpack_type, tvb, t_offset, 1, ENC_NA); |
216 | 0 | } |
217 | | |
218 | | // NOLINTNEXTLINE(misc-no-recursion) |
219 | | static void dissect_msgpack_map(tvbuff_t* tvb, packet_info* pinfo, proto_tree* tree, uint8_t type, void* data, unsigned* offset, char** value) |
220 | 0 | { |
221 | 0 | unsigned depth = p_get_proto_depth(pinfo, proto_msgpack); |
222 | 0 | if (depth >= MSGPACK_MAX_NESTING) { |
223 | 0 | expert_add_info(pinfo, tree, &ei_msgpack_too_deep); |
224 | 0 | *offset += 1; |
225 | 0 | return; |
226 | 0 | } |
227 | 0 | proto_tree* subtree; |
228 | 0 | proto_tree* map_subtree; |
229 | 0 | proto_item* ti; |
230 | 0 | uint32_t len = 0; |
231 | 0 | uint8_t lensize = 0; |
232 | 0 | char* label; |
233 | 0 | unsigned i; |
234 | |
|
235 | 0 | if (type >> 4 == 0x8) { |
236 | 0 | len = type & 0x0F; |
237 | 0 | lensize = 0; |
238 | 0 | } |
239 | 0 | else if (type == 0xde) { |
240 | 0 | len = tvb_get_ntohs(tvb, *offset + 1); |
241 | 0 | lensize = 2; |
242 | 0 | } |
243 | 0 | else if (type == 0xdf) { |
244 | 0 | len = tvb_get_ntohl(tvb, *offset + 1); |
245 | 0 | lensize = 4; |
246 | 0 | } |
247 | 0 | else { |
248 | 0 | DISSECTOR_ASSERT_NOT_REACHED(); |
249 | 0 | } |
250 | |
|
251 | 0 | label = wmem_strdup_printf(pinfo->pool, "%s: %u element%s", data ? (char*)data : "MsgPack Map", len, len > 1 ? "s" : ""); |
252 | |
|
253 | 0 | ti = proto_tree_add_string_format(tree, hf_msgpack_string, tvb, *offset, 1 + lensize, NULL, "%s", label); |
254 | 0 | subtree = proto_item_add_subtree(ti, ett_msgpack_map); |
255 | 0 | proto_tree_add_item(subtree, hf_msgpack_type, tvb, *offset, 1, ENC_NA); |
256 | 0 | *offset += lensize + 1; |
257 | 0 | p_set_proto_depth(pinfo, proto_msgpack, depth + 1); |
258 | 0 | for (i = 0; i < len; i++) { |
259 | | // We recurse here, but we'll run out of packet before we run out of stack. |
260 | 0 | map_subtree = proto_tree_add_subtree(subtree, tvb, *offset, 0, ett_msgpack_map_elem, NULL, ""); |
261 | 0 | dissect_msgpack_object(tvb, pinfo, map_subtree, "Key", offset, value); |
262 | 0 | if (value) |
263 | 0 | proto_item_append_text(map_subtree, " %s:", *value); |
264 | 0 | dissect_msgpack_object(tvb, pinfo, map_subtree, "Value", offset, value); |
265 | 0 | if (value) |
266 | 0 | proto_item_append_text(map_subtree, " %s", *value); |
267 | 0 | } |
268 | 0 | p_set_proto_depth(pinfo, proto_msgpack, depth); |
269 | |
|
270 | 0 | if (value) |
271 | 0 | *value = label; |
272 | 0 | } |
273 | | |
274 | | // NOLINTNEXTLINE(misc-no-recursion) |
275 | | static void dissect_msgpack_array(tvbuff_t* tvb, packet_info* pinfo, proto_tree* tree, uint8_t type, void* data, unsigned* offset, char** value) |
276 | 0 | { |
277 | 0 | unsigned depth = p_get_proto_depth(pinfo, proto_msgpack); |
278 | 0 | if (depth >= MSGPACK_MAX_NESTING) { |
279 | 0 | expert_add_info(pinfo, tree, &ei_msgpack_too_deep); |
280 | 0 | *offset += 1; |
281 | 0 | return; |
282 | 0 | } |
283 | 0 | proto_tree* subtree; |
284 | 0 | proto_item* ti; |
285 | 0 | uint32_t len = 0; |
286 | 0 | uint8_t lensize = 0; |
287 | 0 | char* label; |
288 | 0 | unsigned i; |
289 | |
|
290 | 0 | if (type >> 4 == 0x9) { |
291 | 0 | len = type & 0x0F; |
292 | 0 | lensize = 0; |
293 | 0 | } |
294 | 0 | else if (type == 0xdc) { |
295 | 0 | len = tvb_get_ntohs(tvb, *offset + 1); |
296 | 0 | lensize = 2; |
297 | 0 | } |
298 | 0 | else if (type == 0xdd) { |
299 | 0 | len = tvb_get_ntohl(tvb, *offset + 1); |
300 | 0 | lensize = 4; |
301 | 0 | } |
302 | 0 | else { |
303 | 0 | DISSECTOR_ASSERT_NOT_REACHED(); |
304 | 0 | } |
305 | |
|
306 | 0 | label = wmem_strdup_printf(pinfo->pool, "%s %u element%s", data ? (char*)data : "MsgPack Array", len, len > 1 ? "s" : ""); |
307 | |
|
308 | 0 | ti = proto_tree_add_string_format(tree, hf_msgpack_string, tvb, *offset, 1 + lensize, NULL, "%s", label); |
309 | 0 | subtree = proto_item_add_subtree(ti, ett_msgpack_array); |
310 | 0 | proto_tree_add_item(subtree, hf_msgpack_type, tvb, *offset, 1, ENC_NA); |
311 | 0 | *offset += lensize + 1; |
312 | 0 | p_set_proto_depth(pinfo, proto_msgpack, depth + 1); |
313 | 0 | for (i = 0; i < len; i++) { |
314 | | // We recurse here, but we'll run out of packet before we run out of stack. |
315 | 0 | dissect_msgpack_object(tvb, pinfo, subtree, data, offset, value); |
316 | 0 | } |
317 | 0 | p_set_proto_depth(pinfo, proto_msgpack, depth); |
318 | |
|
319 | 0 | if (value) |
320 | 0 | *value = label; |
321 | 0 | } |
322 | | |
323 | | static void dissect_msgpack_string(tvbuff_t* tvb, packet_info* pinfo, proto_tree* tree, int type, void* data, unsigned* offset, char** value) |
324 | 0 | { |
325 | 0 | uint32_t len = 0; |
326 | 0 | uint8_t lensize = 0; |
327 | 0 | char* label; |
328 | 0 | proto_item* ti; |
329 | 0 | proto_tree* subtree; |
330 | 0 | char* lvalue; |
331 | |
|
332 | 0 | if (type >> 5 == 0x5) { |
333 | 0 | len = type & 0x1F; |
334 | 0 | lensize = 0; |
335 | 0 | } |
336 | 0 | else if (type == 0xd9) { |
337 | 0 | len = tvb_get_uint8(tvb, *offset + 1); |
338 | 0 | lensize = 1; |
339 | 0 | } |
340 | 0 | else if (type == 0xda) { |
341 | 0 | len = tvb_get_ntohs(tvb, *offset + 1); |
342 | 0 | lensize = 2; |
343 | 0 | } |
344 | 0 | else if (type == 0xdb) { |
345 | 0 | len = tvb_get_ntohl(tvb, *offset + 1); |
346 | 0 | lensize = 4; |
347 | 0 | } |
348 | 0 | else { |
349 | 0 | DISSECTOR_ASSERT_NOT_REACHED(); |
350 | 0 | } |
351 | |
|
352 | 0 | lvalue = (char*)tvb_get_string_enc(pinfo->pool, tvb, *offset + 1 + lensize, len, ENC_UTF_8); |
353 | 0 | label = (data ? (char*)data : "MsgPack String"); |
354 | |
|
355 | 0 | ti = proto_tree_add_string_format(tree, hf_msgpack_string, tvb, *offset, 1 + lensize + len, lvalue, "%s: %s", label, lvalue); |
356 | 0 | subtree = proto_item_add_subtree(ti, ett_msgpack_string); |
357 | 0 | proto_tree_add_item(subtree, hf_msgpack_type, tvb, *offset, 1, ENC_NA); |
358 | |
|
359 | 0 | if (lensize == 0) { |
360 | 0 | proto_tree_add_uint(subtree, hf_msgpack_string_len, tvb, *offset, 1, len); |
361 | 0 | *offset += 1; |
362 | 0 | } |
363 | 0 | else { |
364 | 0 | *offset += 1; |
365 | 0 | proto_tree_add_item(subtree, hf_msgpack_string_len, tvb, *offset, lensize, ENC_BIG_ENDIAN); |
366 | 0 | *offset += lensize; |
367 | 0 | } |
368 | 0 | proto_tree_add_item(subtree, hf_msgpack_string, tvb, *offset, len, ENC_UTF_8); |
369 | 0 | *offset += len; |
370 | |
|
371 | 0 | if (value) |
372 | 0 | *value = lvalue; |
373 | 0 | } |
374 | | |
375 | | static void dissect_msgpack_bin(tvbuff_t* tvb, packet_info* pinfo, proto_tree* tree, int type, void* data, unsigned* offset, char** value) |
376 | 0 | { |
377 | 0 | uint32_t len = 0; |
378 | 0 | uint8_t lensize = 0; |
379 | 0 | char* label; |
380 | 0 | proto_item* ti; |
381 | 0 | proto_tree* subtree; |
382 | 0 | char* lvalue; |
383 | |
|
384 | 0 | switch (type) { |
385 | 0 | case 0xc4: |
386 | 0 | len = tvb_get_uint8(tvb, *offset + 1); |
387 | 0 | lensize = 1; |
388 | 0 | break; |
389 | 0 | case 0xc5: |
390 | 0 | len = tvb_get_ntohs(tvb, *offset + 1); |
391 | 0 | lensize = 2; |
392 | 0 | break; |
393 | 0 | case 0xc6: |
394 | 0 | len = tvb_get_ntohl(tvb, *offset + 1); |
395 | 0 | lensize = 4; |
396 | 0 | break; |
397 | 0 | default: |
398 | 0 | DISSECTOR_ASSERT_NOT_REACHED(); |
399 | 0 | break; |
400 | 0 | } |
401 | | |
402 | 0 | lvalue = (char*)tvb_bytes_to_str(pinfo->pool, tvb, *offset + 1 + lensize, len); |
403 | 0 | label = (data ? (char*)data : "MsgPack Bytes"); |
404 | |
|
405 | 0 | ti = proto_tree_add_bytes_format(tree, hf_msgpack_bin, tvb, *offset, 1 + lensize + len, NULL, "%s: %s", label, lvalue); |
406 | 0 | subtree = proto_item_add_subtree(ti, ett_msgpack_bin); |
407 | 0 | proto_tree_add_item(subtree, hf_msgpack_type, tvb, *offset, 1, ENC_NA); |
408 | |
|
409 | 0 | *offset += 1; |
410 | 0 | proto_tree_add_item(subtree, hf_msgpack_bin_len, tvb, *offset, lensize, ENC_BIG_ENDIAN); |
411 | 0 | *offset += lensize; |
412 | |
|
413 | 0 | proto_tree_add_item(subtree, hf_msgpack_bin, tvb, *offset, len, ENC_NA); |
414 | 0 | *offset += len; |
415 | |
|
416 | 0 | if (value) |
417 | 0 | *value = lvalue; |
418 | 0 | } |
419 | | |
420 | | static void dissect_msgpack_float(tvbuff_t* tvb, packet_info *pinfo, proto_tree* tree, int type, void* data, unsigned* offset, char** value) |
421 | 0 | { |
422 | 0 | char* label; |
423 | 0 | char* lvalue; |
424 | 0 | proto_item* ti; |
425 | 0 | proto_tree* subtree; |
426 | 0 | int s_offset = *offset; |
427 | |
|
428 | 0 | *offset += 1; |
429 | |
|
430 | 0 | if (type == 0xca) { |
431 | 0 | label = (data ? (char*)data : "MsgPack Float"); |
432 | 0 | float f = tvb_get_ntohieee_float(tvb, *offset); |
433 | 0 | lvalue = wmem_strdup_printf(pinfo->pool, "%f", f); |
434 | 0 | ti = proto_tree_add_float_format(tree, hf_msgpack_float, tvb, *offset, 4, f, "%s: %f", label, f); |
435 | 0 | if (value) |
436 | 0 | *value = lvalue; |
437 | 0 | *offset += 4; |
438 | 0 | } |
439 | 0 | else if (type == 0xcb) { |
440 | 0 | label = (data ? (char*)data : "MsgPack Double"); |
441 | 0 | double d = tvb_get_ntohieee_double(tvb, *offset); |
442 | 0 | lvalue = wmem_strdup_printf(pinfo->pool, "%lf", d); |
443 | 0 | ti = proto_tree_add_double_format(tree, hf_msgpack_double, tvb, *offset, 8, d, "%s: %lf", label, d); |
444 | 0 | if (value) |
445 | 0 | *value = lvalue; |
446 | 0 | *offset += 8; |
447 | 0 | } |
448 | 0 | else { |
449 | 0 | DISSECTOR_ASSERT_NOT_REACHED(); |
450 | 0 | } |
451 | 0 | subtree = proto_item_add_subtree(ti, ett_msgpack_num); |
452 | 0 | proto_tree_add_item(subtree, hf_msgpack_type, tvb, s_offset, 1, ENC_NA); |
453 | 0 | } |
454 | | |
455 | | static void dissect_msgpack_ext(tvbuff_t* tvb, packet_info *pinfo, proto_tree* tree, int type, void* data, unsigned* offset, char** value) |
456 | 0 | { |
457 | 0 | char* label; |
458 | 0 | uint32_t len = 0; |
459 | 0 | uint8_t lensize = 0; |
460 | 0 | proto_tree* subtree; |
461 | 0 | unsigned offset_start = *offset; |
462 | |
|
463 | 0 | label = (data ? (char*)data : "Ext"); |
464 | |
|
465 | 0 | subtree = proto_tree_add_subtree(tree, tvb, *offset, 0, ett_msgpack_ext, NULL, label); |
466 | |
|
467 | 0 | proto_tree_add_item(subtree, hf_msgpack_type, tvb, *offset, 1, ENC_NA); |
468 | 0 | if (type >= 0xd4 && type <= 0xd8) { |
469 | 0 | len = 1 << (type - 0xd4); |
470 | 0 | proto_tree_add_uint(subtree, hf_msgpack_ext_len, tvb, *offset, 1, len); |
471 | 0 | } |
472 | 0 | else if (type == 0xc7) { |
473 | 0 | len = tvb_get_uint8(tvb, *offset + 2); |
474 | 0 | lensize = 1; |
475 | 0 | } |
476 | 0 | else if (type == 0xc8) { |
477 | 0 | len = tvb_get_ntohs(tvb, *offset + 2); |
478 | 0 | lensize = 2; |
479 | 0 | } |
480 | 0 | else if (type == 0xc9) { |
481 | 0 | len = tvb_get_ntohl(tvb, *offset + 2); |
482 | 0 | lensize = 4; |
483 | 0 | } |
484 | 0 | else { |
485 | 0 | DISSECTOR_ASSERT_NOT_REACHED(); |
486 | 0 | } |
487 | 0 | *offset += 1; |
488 | |
|
489 | 0 | proto_tree_add_item(subtree, hf_msgpack_ext_type, tvb, *offset, 1, ENC_NA); |
490 | 0 | *offset += 1; |
491 | |
|
492 | 0 | if (lensize > 0) { |
493 | 0 | proto_tree_add_item(subtree, hf_msgpack_ext_len, tvb, *offset, lensize, ENC_BIG_ENDIAN); |
494 | 0 | *offset += lensize; |
495 | 0 | } |
496 | 0 | proto_tree_add_item(subtree, hf_msgpack_ext_bytes, tvb, *offset, len, ENC_NA); |
497 | 0 | if (value) { |
498 | 0 | *value = tvb_bytes_to_str(pinfo->pool, tvb, *offset, len); |
499 | 0 | } |
500 | 0 | *offset += len; |
501 | |
|
502 | 0 | proto_item_set_len(subtree, *offset - offset_start); |
503 | 0 | } |
504 | | |
505 | | // NOLINTNEXTLINE(misc-no-recursion) |
506 | | static void dissect_msgpack_object(tvbuff_t* tvb, packet_info* pinfo, proto_tree* tree, void* data, unsigned* offset, char** value) |
507 | 0 | { |
508 | 0 | uint8_t type; |
509 | |
|
510 | 0 | type = tvb_get_uint8(tvb, *offset); |
511 | |
|
512 | 0 | col_append_fstr(pinfo->cinfo, COL_INFO, "%s ", rval_to_str_const(type, msgpack_types, " Unknown Msg Type")); |
513 | | |
514 | | // Nil |
515 | 0 | if (type == 0xc0) { |
516 | 0 | proto_tree_add_string_format(tree, hf_msgpack_string, tvb, *offset, 1, "nil", "nil"); |
517 | 0 | if (value) |
518 | 0 | *value = "nil"; |
519 | 0 | *offset += 1; |
520 | 0 | return; |
521 | 0 | } |
522 | | |
523 | | // True/False |
524 | 0 | if (type == 0xc2 || type == 0xc3) { |
525 | 0 | proto_tree_add_boolean(tree, hf_msgpack_bool, tvb, *offset, 1, type - 0xc2); |
526 | 0 | if (value) |
527 | 0 | *value = (type - 0xc2) ? "True" : "False"; |
528 | 0 | *offset += 1; |
529 | 0 | return; |
530 | 0 | } |
531 | | |
532 | | // Integer |
533 | 0 | if (type >= 0xe0 || type <= 0x7f || (type >= 0xcc && type <= 0xd3)) { |
534 | 0 | dissect_msgpack_integer(tvb, pinfo, tree, type, data, offset, value); |
535 | 0 | return; |
536 | 0 | } |
537 | | |
538 | | // Float |
539 | 0 | if (type == 0xca || type == 0xcb) { |
540 | 0 | dissect_msgpack_float(tvb, pinfo, tree, type, data, offset, value); |
541 | 0 | return; |
542 | 0 | } |
543 | | |
544 | | // String |
545 | 0 | if (type >> 5 == 0x5 || type == 0xd9 || type == 0xda || type == 0xdb) { |
546 | 0 | dissect_msgpack_string(tvb, pinfo, tree, type, data, offset, value); |
547 | 0 | return; |
548 | 0 | } |
549 | | |
550 | | // Bin |
551 | 0 | if (type == 0xc4 || type == 0xc5 || type == 0xc6) { |
552 | 0 | dissect_msgpack_bin(tvb, pinfo, tree, type, data, offset, value); |
553 | 0 | return; |
554 | 0 | } |
555 | | |
556 | | // Array |
557 | 0 | if (type >> 4 == 0x9 || type == 0xdc || type == 0xdd) { |
558 | | // We recurse here, but we'll run out of packet before we run out of stack. |
559 | 0 | dissect_msgpack_array(tvb, pinfo, tree, type, data, offset, value); |
560 | 0 | return; |
561 | 0 | } |
562 | | |
563 | | // Map |
564 | 0 | if (type >> 4 == 0x8 || type == 0xde || type == 0xdf) { |
565 | | // We recurse here, but we'll run out of packet before we run out of stack. |
566 | 0 | dissect_msgpack_map(tvb, pinfo, tree, type, data, offset, value); |
567 | 0 | return; |
568 | 0 | } |
569 | | |
570 | | // Ext |
571 | 0 | if ((type >= 0xd4 && type <= 0xd8) || (type >= 0xc7 && type <= 0xc9)) { |
572 | 0 | dissect_msgpack_ext(tvb, pinfo, tree, type, data, offset, value); |
573 | 0 | return; |
574 | 0 | } |
575 | | |
576 | 0 | expert_add_info_format(pinfo, tree, &ei_msgpack_unsupported, "Type 0x%x is unsupported", type); |
577 | 0 | *offset += 1; |
578 | 0 | } |
579 | | |
580 | | static int dissect_msgpack(tvbuff_t* tvb, packet_info* pinfo, proto_tree* tree, void* data) |
581 | 0 | { |
582 | 0 | unsigned offset = 0; |
583 | |
|
584 | 0 | col_set_str(pinfo->cinfo, COL_PROTOCOL, "MsgPack"); |
585 | 0 | col_clear(pinfo->cinfo, COL_INFO); |
586 | |
|
587 | 0 | dissect_msgpack_object(tvb, pinfo, tree, data, &offset, NULL); |
588 | 0 | return offset; |
589 | 0 | } |
590 | | |
591 | | void proto_register_msgpack(void) |
592 | 16 | { |
593 | 16 | expert_module_t* expert_msgpack; |
594 | | |
595 | 16 | static hf_register_info hf[] = { |
596 | 16 | { &hf_msgpack_string, |
597 | 16 | { "String", "msgpack.string", FT_STRING, BASE_NONE, NULL, 0x00, NULL, HFILL } |
598 | 16 | }, |
599 | 16 | { &hf_msgpack_type, |
600 | 16 | { "Type", "msgpack.type", FT_UINT8, BASE_HEX|BASE_RANGE_STRING, RVALS(msgpack_types), 0x00, NULL, HFILL } |
601 | 16 | }, |
602 | 16 | { &hf_msgpack_string_len, |
603 | 16 | { "Length", "msgpack.string.len", FT_UINT32, BASE_DEC, NULL, 0x00, NULL, HFILL } |
604 | 16 | }, |
605 | 16 | { &hf_msgpack_bin, |
606 | 16 | { "Bytes", "msgpack.bin", FT_BYTES, BASE_NONE, NULL, 0x00, NULL, HFILL } |
607 | 16 | }, |
608 | 16 | { &hf_msgpack_bin_len, |
609 | 16 | { "Length", "msgpack.bin.len", FT_UINT32, BASE_DEC, NULL, 0x00, NULL, HFILL } |
610 | 16 | }, |
611 | 16 | { &hf_msgpack_uint_fix, |
612 | 16 | { "Integer", "msgpack.integer.fixint", FT_UINT8, BASE_DEC, NULL, 0x7F, NULL, HFILL } |
613 | 16 | }, |
614 | 16 | { &hf_msgpack_uint_8, |
615 | 16 | { "Integer", "msgpack.integer.u8", FT_UINT8, BASE_DEC, NULL, 0x00, NULL, HFILL } |
616 | 16 | }, |
617 | 16 | { &hf_msgpack_uint_16, |
618 | 16 | { "Integer", "msgpack.integer.u16", FT_UINT16, BASE_DEC, NULL, 0x00, NULL, HFILL } |
619 | 16 | }, |
620 | 16 | { &hf_msgpack_uint_32, |
621 | 16 | { "Integer", "msgpack.integer.u32", FT_UINT32, BASE_DEC, NULL, 0x00, NULL, HFILL } |
622 | 16 | }, |
623 | 16 | { &hf_msgpack_uint_64, |
624 | 16 | { "Integer", "msgpack.integer.u64", FT_UINT64, BASE_DEC, NULL, 0x00, NULL, HFILL } |
625 | 16 | }, |
626 | 16 | { &hf_msgpack_int_fix, |
627 | 16 | { "Integer", "msgpack.integer.negfixint", FT_INT8, BASE_DEC, NULL, 0x1F, NULL, HFILL } |
628 | 16 | }, |
629 | 16 | { &hf_msgpack_int_8, |
630 | 16 | { "Integer", "msgpack.integer.8", FT_INT8, BASE_DEC, NULL, 0x00, NULL, HFILL } |
631 | 16 | }, |
632 | 16 | { &hf_msgpack_int_16, |
633 | 16 | { "Integer", "msgpack.integer.16", FT_INT16, BASE_DEC, NULL, 0x00, NULL, HFILL } |
634 | 16 | }, |
635 | 16 | { &hf_msgpack_int_32, |
636 | 16 | { "Integer", "msgpack.integer.32", FT_INT32, BASE_DEC, NULL, 0x00, NULL, HFILL } |
637 | 16 | }, |
638 | 16 | { &hf_msgpack_int_64, |
639 | 16 | { "Integer", "msgpack.integer.64", FT_INT64, BASE_DEC, NULL, 0x00, NULL, HFILL } |
640 | 16 | }, |
641 | 16 | { &hf_msgpack_bool, |
642 | 16 | { "Boolean", "msgpack.boolean", FT_BOOLEAN, BASE_NONE, NULL, 0x00, NULL, HFILL } |
643 | 16 | }, |
644 | 16 | { &hf_msgpack_float, |
645 | 16 | { "Float", "msgpack.float", FT_FLOAT, BASE_NONE, NULL, 0x00, NULL, HFILL } |
646 | 16 | }, |
647 | 16 | { &hf_msgpack_double, |
648 | 16 | { "Double", "msgpack.double", FT_DOUBLE, BASE_NONE, NULL, 0x00, NULL, HFILL } |
649 | 16 | }, |
650 | 16 | { &hf_msgpack_ext_type, |
651 | 16 | { "Ext type", "msgpack.ext.type", FT_INT8, BASE_DEC, NULL, 0x00, NULL, HFILL } |
652 | 16 | }, |
653 | 16 | { &hf_msgpack_ext_len, |
654 | 16 | { "Length", "msgpack.ext.len", FT_UINT32, BASE_DEC, NULL, 0x00, NULL, HFILL } |
655 | 16 | }, |
656 | 16 | { &hf_msgpack_ext_bytes, |
657 | 16 | { "Ext", "msgpack.ext", FT_BYTES, BASE_NONE, NULL, 0x00, NULL, HFILL } |
658 | 16 | } |
659 | 16 | }; |
660 | | |
661 | 16 | static int* ett[] = { |
662 | 16 | &ett_msgpack, |
663 | 16 | &ett_msgpack_num, |
664 | 16 | &ett_msgpack_string, |
665 | 16 | &ett_msgpack_bin, |
666 | 16 | &ett_msgpack_array, |
667 | 16 | &ett_msgpack_map, |
668 | 16 | &ett_msgpack_map_elem, |
669 | 16 | &ett_msgpack_ext |
670 | 16 | }; |
671 | | |
672 | 16 | static ei_register_info ei[] = { |
673 | 16 | { &ei_msgpack_unsupported, { "msgpack.unsupported", PI_UNDECODED, PI_WARN, "Unsupported type", EXPFILL }}, |
674 | 16 | { &ei_msgpack_too_deep, { "msgpack.too_deep", PI_PROTOCOL, PI_WARN, "Nesting too deep", EXPFILL }} |
675 | 16 | }; |
676 | | |
677 | 16 | proto_msgpack = proto_register_protocol("Message Pack", "MsgPack", "msgpack"); |
678 | 16 | msgpack_handle = register_dissector("msgpack", dissect_msgpack, proto_msgpack); |
679 | | |
680 | 16 | expert_msgpack = expert_register_protocol(proto_msgpack); |
681 | 16 | expert_register_field_array(expert_msgpack, ei, array_length(ei)); |
682 | | |
683 | 16 | proto_register_field_array(proto_msgpack, hf, array_length(hf)); |
684 | 16 | proto_register_subtree_array(ett, array_length(ett)); |
685 | 16 | } |
686 | | |
687 | | void proto_reg_handoff_msgpack(void) |
688 | 16 | { |
689 | | // If this is ever streamed (transported over TCP) we need to add recursion checks |
690 | 16 | dissector_add_for_decode_as("udp.port", msgpack_handle); |
691 | 16 | } |
692 | | |
693 | | /* |
694 | | * Editor modelines - https://www.wireshark.org/tools/modelines.html |
695 | | * |
696 | | * Local variables: |
697 | | * c-basic-offset: 8 |
698 | | * tab-width: 8 |
699 | | * indent-tabs-mode: t |
700 | | * End: |
701 | | * |
702 | | * vi: set shiftwidth=8 tabstop=8 noexpandtab: |
703 | | * :indentSize=8:tabSize=8:noTabs=false: |
704 | | */ |