/src/wireshark/epan/dissectors/packet-json.c
Line | Count | Source |
1 | | /* packet-json.c |
2 | | * Routines for JSON dissection |
3 | | * References: |
4 | | * RFC 4627: https://tools.ietf.org/html/rfc4627 |
5 | | * Website: http://json.org/ |
6 | | * |
7 | | * Copyright 2010, Jakub Zawadzki <darkjames-ws@darkjames.pl> |
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 | | #include "config.h" |
16 | | |
17 | | #include <epan/packet.h> |
18 | | #include <epan/tvbparse.h> |
19 | | #include <epan/proto_data.h> |
20 | | #include <wsutil/wsjson.h> |
21 | | |
22 | | #include <wsutil/str_util.h> |
23 | | #include <wsutil/unicode-utils.h> |
24 | | |
25 | | #include <wiretap/wtap.h> |
26 | | |
27 | | #include "packet-media-type.h" |
28 | | #include "packet-acdr.h" |
29 | | #include "packet-json.h" |
30 | | |
31 | | void proto_register_json(void); |
32 | | void proto_reg_handoff_json(void); |
33 | | static char* json_string_unescape(wmem_allocator_t *scope, const char *string, size_t *length_ptr); |
34 | | static const char* get_json_string(wmem_allocator_t *scope, tvbparse_elem_t *tok, bool remove_quotes); |
35 | | |
36 | | static dissector_handle_t json_handle; |
37 | | static dissector_handle_t json_file_handle; |
38 | | |
39 | | static int proto_json; |
40 | | |
41 | | //Used to get AC DR proto data |
42 | | static int proto_acdr; |
43 | | |
44 | | static int hf_json_array; |
45 | | static int hf_json_array_compact; |
46 | | static int hf_json_array_item_compact; |
47 | | static int hf_json_array_raw; |
48 | | static int hf_json_array_item_raw; |
49 | | static int hf_json_binary_data; |
50 | | static int hf_json_ignored_leading_bytes; |
51 | | static int hf_json_key; |
52 | | static int hf_json_member; |
53 | | static int hf_json_member_compact; |
54 | | static int hf_json_member_raw; |
55 | | static int hf_json_member_with_value; |
56 | | static int hf_json_object; |
57 | | static int hf_json_object_compact; |
58 | | static int hf_json_object_raw; |
59 | | static int hf_json_path; |
60 | | static int hf_json_path_with_value; |
61 | | static int hf_json_value_false; |
62 | | static int hf_json_value_nan; |
63 | | static int hf_json_value_null; |
64 | | static int hf_json_value_number; |
65 | | static int hf_json_value_string; |
66 | | static int hf_json_value_true; |
67 | | |
68 | | static int ett_json; |
69 | | static int ett_json_array; |
70 | | static int ett_json_object; |
71 | | static int ett_json_member; |
72 | | /* Define the trees for json compact form */ |
73 | | static int ett_json_compact; |
74 | | static int ett_json_array_compact; |
75 | | static int ett_json_object_compact; |
76 | | static int ett_json_member_compact; |
77 | | /* Define the trees for json raw form */ |
78 | | static int ett_json_raw; |
79 | | static int ett_json_array_raw; |
80 | | static int ett_json_object_raw; |
81 | | static int ett_json_member_raw; |
82 | | |
83 | | /* Preferences */ |
84 | | static bool json_compact; |
85 | | |
86 | | static bool json_raw; |
87 | | |
88 | | /* Determine whether to hide the tree of original form or root item of compact or raw form |
89 | | * based on the enabled status of compact_form and raw_form preferences. |
90 | | * If the preference auto_hide is true and compact_form or raw_form is true, hide the tree of |
91 | | * original form. If the preference auto_hide is true and only one of preference of |
92 | | * compact_form or raw_form is true, then hide the root item of compact or raw form and put |
93 | | * the content of compact or raw form under the tree item of JSON protocol directly. |
94 | | */ |
95 | | static bool auto_hide; |
96 | | |
97 | | static bool ignore_leading_bytes; |
98 | | |
99 | | static bool hide_extended_path_based_filtering; |
100 | | |
101 | | static bool unescape_strings; |
102 | | |
103 | | static tvbparse_wanted_t* want; |
104 | | static tvbparse_wanted_t* want_ignore; |
105 | | |
106 | | static dissector_handle_t text_lines_handle; |
107 | | static dissector_handle_t falco_json_handle; |
108 | | |
109 | | typedef enum { |
110 | | JSON_TOKEN_INVALID = -1, |
111 | | JSON_TOKEN_NUMBER = 0, |
112 | | JSON_TOKEN_STRING, |
113 | | JSON_TOKEN_FALSE, |
114 | | JSON_TOKEN_NULL, |
115 | | JSON_TOKEN_TRUE, |
116 | | JSON_TOKEN_NAN, |
117 | | |
118 | | /* not really tokens ... */ |
119 | | JSON_OBJECT, |
120 | | JSON_ARRAY |
121 | | |
122 | | } json_token_type_t; |
123 | | |
124 | | typedef enum { |
125 | | JSON_MARK_TYPE_NONE = 0, |
126 | | JSON_MARK_TYPE_BEGIN_OBJECT, |
127 | | JSON_MARK_TYPE_END_OBJECT, |
128 | | JSON_MARK_TYPE_BEGIN_ARRAY, |
129 | | JSON_MARK_TYPE_END_ARRAY, |
130 | | JSON_MARK_TYPE_MEMBER_NAME, |
131 | | JSON_MARK_TYPE_VALUE |
132 | | } json_mark_type_t; |
133 | | |
134 | | typedef struct { |
135 | | wmem_stack_t *stack; |
136 | | wmem_stack_t *stack_compact; /* Used for compact json form only */ |
137 | | wmem_stack_t *array_idx; /* Used for compact json form only. |
138 | | Top item: -3. |
139 | | Object: < 0. |
140 | | Array -1: no key, -2: has key */ |
141 | | wmem_stack_t* stack_path; |
142 | | packet_info* pinfo; |
143 | | wmem_stack_t* stack_raw; /* Used for raw json form only */ |
144 | | json_mark_type_t prev_item_type_raw; /* Used for raw json form only */ |
145 | | proto_item* prev_item_raw; /* Used for raw json form only */ |
146 | | } json_parser_data_t; |
147 | | |
148 | | #define JSON_COMPACT_TOP_ITEM -3 |
149 | 0 | #define JSON_COMPACT_OBJECT_WITH_KEY -2 |
150 | | #define JSON_COMPACT_OBJECT_WITHOUT_KEY -1 |
151 | 0 | #define JSON_COMPACT_ARRAY 0 |
152 | | |
153 | 0 | #define JSON_ARRAY_BEGIN(json_tvbparse_data) wmem_stack_push(json_tvbparse_data->array_idx, GINT_TO_POINTER(JSON_COMPACT_ARRAY)) |
154 | 0 | #define JSON_OBJECT_BEGIN(json_tvbparse_data) wmem_stack_push(json_tvbparse_data->array_idx, GINT_TO_POINTER(JSON_COMPACT_OBJECT_WITHOUT_KEY)) |
155 | 0 | #define JSON_ARRAY_OBJECT_END(json_tvbparse_data) wmem_stack_pop(json_tvbparse_data->array_idx) |
156 | 0 | #define JSON_INSIDE_ARRAY(idx) (idx >= JSON_COMPACT_ARRAY) |
157 | 0 | #define JSON_OBJECT_SET_HAS_KEY(idx) (idx == JSON_COMPACT_OBJECT_WITH_KEY) |
158 | | |
159 | 6.88k | #define json_hide_original_tree() (auto_hide && (json_compact || json_raw)) |
160 | 0 | #define json_hide_root_item() (auto_hide && ((json_compact && !json_raw) || (!json_compact && json_raw))) |
161 | | |
162 | | static void |
163 | | json_array_index_increment(json_parser_data_t *data) |
164 | 0 | { |
165 | 0 | int idx = GPOINTER_TO_INT(wmem_stack_pop(data->array_idx)); |
166 | 0 | idx++; |
167 | 0 | wmem_stack_push(data->array_idx, GINT_TO_POINTER(idx)); |
168 | 0 | } |
169 | | |
170 | | static void |
171 | | json_object_add_key(json_parser_data_t *data) |
172 | 0 | { |
173 | 0 | wmem_stack_pop(data->array_idx); |
174 | 0 | wmem_stack_push(data->array_idx, GINT_TO_POINTER(JSON_COMPACT_OBJECT_WITH_KEY)); |
175 | 0 | } |
176 | | |
177 | | static char* |
178 | | json_string_unescape(wmem_allocator_t *scope, const char *string, size_t *length_ptr) |
179 | 0 | { |
180 | 0 | size_t read_index = 0; |
181 | 0 | size_t string_length = strlen(string); |
182 | |
|
183 | 0 | wmem_strbuf_t* output_string_buffer = wmem_strbuf_new_sized(scope, string_length); |
184 | |
|
185 | 0 | while (true) |
186 | 0 | { |
187 | | // Do not overflow input string |
188 | 0 | if (!(read_index < string_length)) |
189 | 0 | { |
190 | 0 | break; |
191 | 0 | } |
192 | | |
193 | 0 | uint8_t current_character = string[read_index]; |
194 | | |
195 | | // character that IS NOT escaped |
196 | 0 | if (current_character != '\\') |
197 | 0 | { |
198 | | // A single UTF-8 character can cover more than one byte. |
199 | | // Copy all bytes that belong to that character and forward currend_index by that amount of bytes |
200 | 0 | int utf8_character_length = ws_utf8_char_len(current_character); |
201 | |
|
202 | 0 | if (utf8_character_length <= 0) |
203 | 0 | { |
204 | 0 | break; |
205 | 0 | } |
206 | | |
207 | 0 | for (int i = 0; i < utf8_character_length; i++) |
208 | 0 | { |
209 | | // Do not overflow input string |
210 | 0 | if (!(read_index < string_length)) |
211 | 0 | { |
212 | 0 | break; |
213 | 0 | } |
214 | | |
215 | 0 | current_character = string[read_index]; |
216 | 0 | read_index++; |
217 | 0 | wmem_strbuf_append_c(output_string_buffer, current_character); |
218 | 0 | } |
219 | 0 | } |
220 | | // character that IS escaped |
221 | 0 | else |
222 | 0 | { |
223 | 0 | read_index++; |
224 | | |
225 | | // Do not overflow input string |
226 | 0 | if (!(read_index < string_length)) |
227 | 0 | { |
228 | 0 | break; |
229 | 0 | } |
230 | | |
231 | 0 | current_character = string[read_index]; |
232 | |
|
233 | 0 | if (current_character == '\"' || current_character == '\\' || current_character == '/') |
234 | 0 | { |
235 | 0 | read_index++; |
236 | 0 | wmem_strbuf_append_c(output_string_buffer, current_character); |
237 | 0 | } |
238 | 0 | else if (current_character == 'b') |
239 | 0 | { |
240 | 0 | read_index++; |
241 | 0 | wmem_strbuf_append_c(output_string_buffer, '\b'); |
242 | 0 | } |
243 | 0 | else if (current_character == 'f') |
244 | 0 | { |
245 | 0 | read_index++; |
246 | 0 | wmem_strbuf_append_c(output_string_buffer, '\f'); |
247 | 0 | } |
248 | 0 | else if (current_character == 'n') |
249 | 0 | { |
250 | 0 | read_index++; |
251 | 0 | wmem_strbuf_append_c(output_string_buffer, '\n'); |
252 | 0 | } |
253 | 0 | else if (current_character == 'r') |
254 | 0 | { |
255 | 0 | read_index++; |
256 | 0 | wmem_strbuf_append_c(output_string_buffer, '\r'); |
257 | 0 | } |
258 | 0 | else if (current_character == 't') |
259 | 0 | { |
260 | 0 | read_index++; |
261 | 0 | wmem_strbuf_append_c(output_string_buffer, '\t'); |
262 | 0 | } |
263 | 0 | else if (current_character == 'u') |
264 | 0 | { |
265 | 0 | read_index++; |
266 | |
|
267 | 0 | uint32_t code_point = 0; |
268 | 0 | bool is_valid_unicode_character = true; |
269 | |
|
270 | 0 | for (int i = 0; i < 4; i++) |
271 | 0 | { |
272 | | // Do not overflow input string |
273 | 0 | if (!(read_index < string_length)) |
274 | 0 | { |
275 | 0 | is_valid_unicode_character = false; |
276 | 0 | break; |
277 | 0 | } |
278 | | |
279 | 0 | current_character = string[read_index]; |
280 | 0 | read_index++; |
281 | |
|
282 | 0 | int nibble = ws_xton(current_character); |
283 | |
|
284 | 0 | if(nibble < 0) |
285 | 0 | { |
286 | 0 | is_valid_unicode_character = false; |
287 | 0 | break; |
288 | 0 | } |
289 | | |
290 | 0 | code_point <<= 4; |
291 | 0 | code_point |= nibble; |
292 | 0 | } |
293 | |
|
294 | 0 | if ((IS_LEAD_SURROGATE(code_point))) |
295 | 0 | { |
296 | | // Do not overflow input string |
297 | 0 | if (!(read_index < string_length)) |
298 | 0 | { |
299 | 0 | break; |
300 | 0 | } |
301 | 0 | current_character = string[read_index]; |
302 | |
|
303 | 0 | if (current_character == '\\') |
304 | 0 | { |
305 | 0 | read_index++; |
306 | | |
307 | | // Do not overflow input string |
308 | 0 | if (!(read_index < string_length)) |
309 | 0 | { |
310 | 0 | break; |
311 | 0 | } |
312 | | |
313 | 0 | current_character = string[read_index]; |
314 | 0 | if (current_character == 'u') { |
315 | 0 | uint16_t lead_surrogate = code_point; |
316 | 0 | uint16_t trail_surrogate = 0; |
317 | |
|
318 | 0 | read_index++; |
319 | |
|
320 | 0 | for (int i = 0; i < 4; i++) |
321 | 0 | { |
322 | | // Do not overflow input string |
323 | 0 | if (!(read_index < string_length)) |
324 | 0 | { |
325 | 0 | is_valid_unicode_character = false; |
326 | 0 | break; |
327 | 0 | } |
328 | | |
329 | 0 | current_character = string[read_index]; |
330 | 0 | read_index++; |
331 | |
|
332 | 0 | int nibble = ws_xton(current_character); |
333 | |
|
334 | 0 | if (nibble < 0) |
335 | 0 | { |
336 | 0 | is_valid_unicode_character = false; |
337 | 0 | break; |
338 | 0 | } |
339 | | |
340 | 0 | trail_surrogate <<= 4; |
341 | 0 | trail_surrogate |= nibble; |
342 | 0 | } |
343 | |
|
344 | 0 | if ((IS_TRAIL_SURROGATE(trail_surrogate))) |
345 | 0 | { |
346 | 0 | code_point = SURROGATE_VALUE(lead_surrogate, trail_surrogate); |
347 | 0 | } |
348 | 0 | else |
349 | 0 | { |
350 | 0 | is_valid_unicode_character = false; |
351 | 0 | } |
352 | 0 | } |
353 | 0 | else |
354 | 0 | { |
355 | 0 | read_index++; |
356 | 0 | is_valid_unicode_character = false; |
357 | 0 | } |
358 | 0 | } |
359 | 0 | else |
360 | 0 | { |
361 | 0 | read_index++; |
362 | 0 | is_valid_unicode_character = false; |
363 | 0 | } |
364 | 0 | } |
365 | 0 | else if ((IS_TRAIL_SURROGATE(code_point))) |
366 | 0 | { |
367 | 0 | is_valid_unicode_character = false; |
368 | 0 | } |
369 | | |
370 | 0 | if (is_valid_unicode_character) |
371 | 0 | { |
372 | 0 | if (g_unichar_validate(code_point) && g_unichar_isprint(code_point)) |
373 | 0 | { |
374 | 0 | char length_test_buffer[6]; |
375 | 0 | int utf8_character_length = (int)g_unichar_to_utf8(code_point, length_test_buffer); |
376 | |
|
377 | 0 | for (int i = 0; i < utf8_character_length; i++) |
378 | 0 | { |
379 | 0 | current_character = length_test_buffer[i]; |
380 | 0 | wmem_strbuf_append_c(output_string_buffer, current_character); |
381 | |
|
382 | 0 | } |
383 | 0 | } |
384 | 0 | } |
385 | 0 | else |
386 | 0 | { |
387 | 0 | wmem_strbuf_append_unichar_repl(output_string_buffer); |
388 | 0 | } |
389 | 0 | } |
390 | 0 | else |
391 | 0 | { |
392 | | /* not valid by JSON grammar (tvbparse rules should not allow it) */ |
393 | 0 | DISSECTOR_ASSERT_NOT_REACHED(); |
394 | 0 | } |
395 | 0 | } |
396 | 0 | } |
397 | |
|
398 | 0 | if (length_ptr) |
399 | 0 | *length_ptr = wmem_strbuf_get_len(output_string_buffer); |
400 | |
|
401 | 0 | return wmem_strbuf_finalize(output_string_buffer); |
402 | 0 | } |
403 | | |
404 | | /* This functions allocates memory with packet_scope but the returned pointer |
405 | | * cannot be freed. */ |
406 | | static const char* |
407 | | get_json_string(wmem_allocator_t *scope, tvbparse_elem_t *tok, bool remove_quotes) |
408 | 6.44k | { |
409 | 6.44k | char *string; |
410 | 6.44k | size_t length; |
411 | | |
412 | 6.44k | string = (char*)tvb_get_string_enc(scope, tok->tvb, tok->offset, tok->len, ENC_UTF_8); |
413 | | |
414 | 6.44k | if (unescape_strings) { |
415 | 0 | string = json_string_unescape(scope, string, &length); |
416 | 0 | } |
417 | 6.44k | else { |
418 | 6.44k | length = strlen(string); |
419 | 6.44k | } |
420 | | |
421 | 6.44k | if (remove_quotes) { |
422 | 2.39k | if (string[length - 1] == '"') { |
423 | 2.08k | string[length - 1] = '\0'; |
424 | 2.08k | } |
425 | 2.39k | if (string[0] == '"') { |
426 | 2.19k | string += 1; |
427 | 2.19k | } |
428 | 2.39k | } |
429 | | |
430 | 6.44k | return string; |
431 | 6.44k | } |
432 | | |
433 | | GHashTable* json_header_fields_hash; |
434 | | |
435 | | static proto_item* |
436 | | json_key_lookup(proto_tree* tree, tvbparse_elem_t* tok, const char* key_str, packet_info* pinfo, bool use_compact) |
437 | 3.58k | { |
438 | 3.58k | proto_item* ti; |
439 | 3.58k | int hf_id; |
440 | 3.58k | int offset, len; |
441 | | |
442 | 3.58k | json_data_decoder_t* json_data_decoder_rec = (json_data_decoder_t*)g_hash_table_lookup(json_header_fields_hash, key_str); |
443 | 3.58k | if (json_data_decoder_rec == NULL) { |
444 | 3.58k | return NULL; |
445 | 3.58k | } |
446 | | |
447 | 0 | hf_id = *json_data_decoder_rec->hf_id; |
448 | 0 | DISSECTOR_ASSERT(hf_id > 0); |
449 | |
|
450 | 0 | int proto_id = proto_registrar_is_protocol(hf_id) ? hf_id : proto_registrar_get_parent(hf_id); |
451 | 0 | if (!proto_is_protocol_enabled(find_protocol_by_id(proto_id))) { |
452 | 0 | return NULL; |
453 | 0 | } |
454 | | |
455 | | /* |
456 | | * use_compact == true: "tok is the composed element of the member" |
457 | | * This is only called from before_member when the value is a |
458 | | / JSON_TOKEN_STRING. |
459 | | * use_compact == false: "tok is the composed element whose subelement is the value" |
460 | | * For this, arrays with matching key are passed in before_array, |
461 | | * strings are passed in after_value, and other types aren't passed in. |
462 | | */ |
463 | 0 | const tvbparse_elem_t* value_tok = tok; |
464 | 0 | if (use_compact) { |
465 | | /* tok refers to the member ("key":"value") |
466 | | * tok->sub is the key string |
467 | | * tok->sub->next is the ':' |
468 | | * tok->sub->last is a set with one element |
469 | | * tok->sub->last->sub is the value |
470 | | */ |
471 | 0 | DISSECTOR_ASSERT(tok->sub); |
472 | 0 | value_tok = tok->sub->last; |
473 | 0 | } |
474 | | /* tok is a set with one element |
475 | | * tok->sub is the value |
476 | | */ |
477 | 0 | DISSECTOR_ASSERT(value_tok && value_tok->sub); |
478 | 0 | value_tok = value_tok->sub; |
479 | |
|
480 | 0 | json_token_type_t value_id = (json_token_type_t)value_tok->id; |
481 | |
|
482 | 0 | offset = value_tok->offset; |
483 | 0 | len = value_tok->len; |
484 | | /* Remove the quotation marks from strings (the decoder functions |
485 | | * apparently expect that.) |
486 | | */ |
487 | 0 | if (value_id == JSON_TOKEN_STRING && len >= 2) { |
488 | 0 | offset += 1; |
489 | 0 | len -= 2; |
490 | 0 | } |
491 | | /* XXX - Every hf_id in packet-json_3gpp.c is a FT_STRING. Should other |
492 | | * types be supported (perhaps verified against the JSON token type?) |
493 | | * Should the encoding be ENC_UTF_8? Should the string be unescaped here? |
494 | | */ |
495 | 0 | ti = proto_tree_add_item(tree, hf_id, tok->tvb, offset, len, ENC_ASCII); |
496 | 0 | if (json_data_decoder_rec->json_data_decoder) { |
497 | 0 | (*json_data_decoder_rec->json_data_decoder)(value_tok->tvb, tree, pinfo, offset, len, key_str); |
498 | 0 | } |
499 | 0 | return ti; |
500 | |
|
501 | 0 | } |
502 | | |
503 | | static char* |
504 | | join_strings(wmem_allocator_t *pool, const char* string_a, const char* string_b, char separator) |
505 | 13.2k | { |
506 | 13.2k | if (string_a == NULL) |
507 | 0 | { |
508 | 0 | return NULL; |
509 | 0 | } |
510 | 13.2k | if (string_b == NULL) |
511 | 0 | { |
512 | 0 | return NULL; |
513 | 0 | } |
514 | | |
515 | 13.2k | wmem_strbuf_t* output_string_buffer = wmem_strbuf_new(pool, string_a); |
516 | | |
517 | 13.2k | if (separator != '\0') |
518 | 13.2k | { |
519 | 13.2k | wmem_strbuf_append_c(output_string_buffer, separator); |
520 | 13.2k | } |
521 | | |
522 | 13.2k | wmem_strbuf_append(output_string_buffer, string_b); |
523 | | |
524 | 13.2k | char* output_string = wmem_strbuf_finalize(output_string_buffer); |
525 | 13.2k | return output_string; |
526 | 13.2k | } |
527 | | |
528 | | static int |
529 | | dissect_json(tvbuff_t *tvb, packet_info *pinfo, proto_tree *tree, void* data) |
530 | 2.62k | { |
531 | 2.62k | if (falco_json_handle) { |
532 | 0 | int falco_len = call_dissector_only(falco_json_handle, tvb, pinfo, tree, NULL); |
533 | 0 | if (falco_len > 0) { |
534 | 0 | return falco_len; |
535 | 0 | } |
536 | 0 | } |
537 | | |
538 | 2.62k | proto_tree *json_tree = NULL; |
539 | 2.62k | proto_item *ti = NULL; |
540 | | |
541 | 2.62k | json_parser_data_t parser_data; |
542 | 2.62k | tvbparse_t *tt; |
543 | | |
544 | 2.62k | media_content_info_t *content_info; |
545 | 2.62k | const char *data_name; |
546 | 2.62k | int offset; |
547 | | |
548 | | /* Save pinfo*/ |
549 | 2.62k | parser_data.pinfo = pinfo; |
550 | | /* JSON dissector can be called in a JSON native file or when transported |
551 | | * by another protocol; for a JSON file, this dissector is called by the |
552 | | * frame dissector, which only sets COL_PROTOCOL and COL_INFO if the |
553 | | * dissector it calls fails, so this will make the entry in the Protocol |
554 | | * column accordingly. |
555 | | */ |
556 | 2.62k | col_append_sep_str(pinfo->cinfo, COL_PROTOCOL, "/", "JSON"); |
557 | 2.62k | col_append_sep_str(pinfo->cinfo, COL_INFO, NULL, "JSON"); |
558 | | |
559 | 2.62k | data_name = pinfo->match_string; |
560 | 2.62k | if (! (data_name && data_name[0])) { |
561 | | /* |
562 | | * No information from "match_string" |
563 | | */ |
564 | 2.62k | content_info = (media_content_info_t *)data; |
565 | 2.62k | if (content_info == NULL) { |
566 | | /* |
567 | | * No information from dissector data |
568 | | */ |
569 | 2.62k | data_name = NULL; |
570 | 2.62k | } else { |
571 | 0 | data_name = content_info->media_str; |
572 | 0 | if (! (data_name && data_name[0])) { |
573 | | /* |
574 | | * No information from dissector data |
575 | | */ |
576 | 0 | data_name = NULL; |
577 | 0 | } |
578 | 0 | } |
579 | 2.62k | } |
580 | | |
581 | 2.62k | if (tree) { |
582 | 2.62k | ti = proto_tree_add_item(tree, proto_json, tvb, 0, -1, ENC_NA); |
583 | 2.62k | json_tree = proto_item_add_subtree(ti, ett_json); |
584 | | |
585 | 2.62k | if (data_name) |
586 | 0 | proto_item_append_text(ti, ": %s", data_name); |
587 | 2.62k | } |
588 | | |
589 | 2.62k | offset = 0; |
590 | | /* XXX*/ |
591 | 2.62k | p_add_proto_data(pinfo->pool, pinfo, proto_json, 0, tvb); |
592 | | |
593 | 2.62k | parser_data.stack = wmem_stack_new(pinfo->pool); |
594 | 2.62k | wmem_stack_push(parser_data.stack, json_tree); |
595 | | |
596 | | // extended path based filtering |
597 | 2.62k | parser_data.stack_path = wmem_stack_new(pinfo->pool); |
598 | 2.62k | wmem_stack_push(parser_data.stack_path, ""); |
599 | 2.62k | wmem_stack_push(parser_data.stack_path, ""); |
600 | | |
601 | 2.62k | int buffer_length = (int)tvb_captured_length(tvb); |
602 | 2.62k | if (ignore_leading_bytes) |
603 | 0 | { |
604 | 0 | while (offset < buffer_length) |
605 | 0 | { |
606 | 0 | uint8_t current_character = tvb_get_uint8(tvb, offset); |
607 | 0 | if (current_character == '[' || current_character == '{') |
608 | 0 | { |
609 | 0 | break; |
610 | 0 | } |
611 | 0 | offset++; |
612 | 0 | } |
613 | |
|
614 | 0 | if(offset > 0) |
615 | 0 | { |
616 | 0 | proto_tree_add_item(json_tree ? json_tree : tree, hf_json_ignored_leading_bytes, tvb, 0, offset, ENC_ASCII); |
617 | 0 | } |
618 | 0 | } |
619 | | |
620 | 2.62k | if (json_compact) { |
621 | 0 | proto_tree* json_tree_compact = json_hide_root_item() ? json_tree : |
622 | 0 | proto_tree_add_subtree(json_tree, tvb, 0, -1, ett_json_compact, NULL, "JSON compact form:"); |
623 | |
|
624 | 0 | parser_data.stack_compact = wmem_stack_new(pinfo->pool); |
625 | 0 | wmem_stack_push(parser_data.stack_compact, json_tree_compact); |
626 | |
|
627 | 0 | parser_data.array_idx = wmem_stack_new(pinfo->pool); |
628 | 0 | wmem_stack_push(parser_data.array_idx, GINT_TO_POINTER(JSON_COMPACT_TOP_ITEM)); /* top element */ |
629 | 0 | } |
630 | | |
631 | 2.62k | if (json_raw) { |
632 | 0 | proto_tree* json_tree_raw = json_hide_root_item() ? json_tree : |
633 | 0 | proto_tree_add_subtree(json_tree, tvb, 0, -1, ett_json_raw, NULL, "JSON raw form:"); |
634 | |
|
635 | 0 | parser_data.stack_raw = wmem_stack_new(pinfo->pool); |
636 | 0 | wmem_stack_push(parser_data.stack_raw, json_tree_raw); |
637 | |
|
638 | 0 | parser_data.prev_item_raw = NULL; |
639 | 0 | parser_data.prev_item_type_raw = JSON_MARK_TYPE_NONE; |
640 | 0 | } |
641 | | |
642 | 2.62k | tt = tvbparse_init(pinfo->pool, tvb, offset, buffer_length - offset, &parser_data, want_ignore); |
643 | | |
644 | | /* XXX, only one json in packet? */ |
645 | 5.38k | while (tvbparse_get(tt, want)) |
646 | 2.76k | { } |
647 | | |
648 | 2.62k | offset = tvbparse_curr_offset(tt); |
649 | | |
650 | 2.62k | proto_item_set_len(ti, offset); |
651 | | |
652 | | /* if we have some unparsed data, pass to data-text-lines dissector (?) */ |
653 | 2.62k | if (tvb_reported_length_remaining(tvb, offset) > 0) { |
654 | 1.94k | tvbuff_t *next_tvb; |
655 | | |
656 | 1.94k | next_tvb = tvb_new_subset_remaining(tvb, offset); |
657 | | |
658 | 1.94k | call_dissector_with_data(text_lines_handle, next_tvb, pinfo, tree, data); |
659 | 1.94k | } else if (data_name) { |
660 | 0 | col_append_sep_fstr(pinfo->cinfo, COL_INFO, " ", "(%s)", data_name); |
661 | 0 | } |
662 | | |
663 | 2.62k | return tvb_captured_length(tvb); |
664 | 2.62k | } |
665 | | |
666 | | /* |
667 | | * For dissecting JSON in a file; we don't get passed a media type. |
668 | | */ |
669 | | static int |
670 | | dissect_json_file(tvbuff_t *tvb, packet_info *pinfo, proto_tree *tree, void* data _U_) |
671 | 0 | { |
672 | 0 | return dissect_json(tvb, pinfo, tree, NULL); |
673 | 0 | } |
674 | | |
675 | | static void |
676 | 646 | before_object(void *tvbparse_data, const void *wanted_data _U_, tvbparse_elem_t *tok) { |
677 | 646 | json_parser_data_t *data = (json_parser_data_t *) tvbparse_data; |
678 | | |
679 | 646 | proto_tree *tree = (proto_tree *)wmem_stack_peek(data->stack); |
680 | 646 | proto_tree *subtree; |
681 | 646 | proto_item *ti; |
682 | | |
683 | 646 | ti = proto_tree_add_item(tree, hf_json_object, tok->tvb, tok->offset, tok->len, ENC_UTF_8); |
684 | 646 | if (json_hide_original_tree() && wmem_stack_count(data->stack) == 1) { |
685 | 0 | proto_item_set_hidden(ti); |
686 | 0 | } |
687 | | |
688 | 646 | subtree = proto_item_add_subtree(ti, ett_json_object); |
689 | 646 | wmem_stack_push(data->stack, subtree); |
690 | | |
691 | 646 | if (json_compact) { |
692 | 0 | proto_tree *tree_compact = (proto_tree *)wmem_stack_peek(data->stack_compact); |
693 | 0 | proto_tree *subtree_compact; |
694 | 0 | proto_item *ti_compact; |
695 | |
|
696 | 0 | int idx = GPOINTER_TO_INT(wmem_stack_peek(data->array_idx)); |
697 | |
|
698 | 0 | if (JSON_INSIDE_ARRAY(idx)) { |
699 | 0 | ti_compact = proto_tree_add_none_format(tree_compact, hf_json_object_compact, tok->tvb, tok->offset, tok->len, "%d:", idx); |
700 | 0 | subtree_compact = proto_item_add_subtree(ti_compact, ett_json_object_compact); |
701 | 0 | json_array_index_increment(data); |
702 | 0 | } else { |
703 | 0 | subtree_compact = tree_compact; |
704 | 0 | } |
705 | 0 | wmem_stack_push(data->stack_compact, subtree_compact); |
706 | |
|
707 | 0 | JSON_OBJECT_BEGIN(data); |
708 | 0 | } |
709 | | |
710 | 646 | if (json_raw) { |
711 | 0 | proto_tree* tree_raw = (proto_tree*)wmem_stack_peek(data->stack_raw); |
712 | 0 | proto_tree* subtree_raw; |
713 | 0 | proto_item* ti_raw; |
714 | |
|
715 | 0 | if (data->prev_item_raw && data->prev_item_type_raw == JSON_MARK_TYPE_END_OBJECT) { |
716 | 0 | proto_item_append_text(data->prev_item_raw, ","); |
717 | 0 | } |
718 | |
|
719 | 0 | if (data->prev_item_type_raw == JSON_MARK_TYPE_MEMBER_NAME) { |
720 | | /* this is an object value of an member, add the "{" just after the member name */ |
721 | 0 | ti_raw = data->prev_item_raw; |
722 | 0 | proto_item_append_text(ti_raw, " {"); |
723 | 0 | } else { |
724 | | /* this object is either the top object or an element of an array, add the "{" as a single item */ |
725 | 0 | ti_raw = proto_tree_add_none_format(tree_raw, hf_json_object_raw, tok->tvb, tok->offset, tok->len, "{"); |
726 | 0 | } |
727 | |
|
728 | 0 | subtree_raw = proto_item_add_subtree(ti_raw, ett_json_object_raw); |
729 | 0 | wmem_stack_push(data->stack_raw, subtree_raw); |
730 | |
|
731 | 0 | data->prev_item_raw = ti_raw; |
732 | 0 | data->prev_item_type_raw = JSON_MARK_TYPE_BEGIN_OBJECT; |
733 | 0 | } |
734 | 646 | } |
735 | | |
736 | | static void |
737 | 646 | after_object(void *tvbparse_data, const void *wanted_data _U_, tvbparse_elem_t* tok) { |
738 | 646 | json_parser_data_t *data = (json_parser_data_t *) tvbparse_data; |
739 | | |
740 | 646 | wmem_stack_pop(data->stack); |
741 | | |
742 | 646 | if (json_compact) { |
743 | 0 | proto_tree *tree_compact = (proto_tree *)wmem_stack_peek(data->stack_compact); |
744 | 0 | proto_item *parent_item = proto_tree_get_parent(tree_compact); |
745 | |
|
746 | 0 | int idx = GPOINTER_TO_INT(wmem_stack_peek(data->array_idx)); |
747 | |
|
748 | 0 | if (JSON_OBJECT_SET_HAS_KEY(idx)) |
749 | 0 | proto_item_append_text(parent_item, " {...}"); |
750 | 0 | else |
751 | 0 | proto_item_append_text(parent_item, " {}"); |
752 | |
|
753 | 0 | wmem_stack_pop(data->stack_compact); |
754 | |
|
755 | 0 | JSON_ARRAY_OBJECT_END(data); |
756 | 0 | } |
757 | | |
758 | 646 | if (json_raw) { |
759 | 0 | proto_tree* tree_raw = (proto_tree*)wmem_stack_peek(data->stack_raw); |
760 | 0 | proto_tree* parent_tree = proto_tree_get_parent_tree(tree_raw); |
761 | 0 | proto_item* ti_raw; |
762 | 0 | if (data->prev_item_type_raw == JSON_MARK_TYPE_BEGIN_OBJECT) { /* an empty object */ |
763 | 0 | ti_raw = data->prev_item_raw; |
764 | 0 | proto_item_append_text(ti_raw, "}"); |
765 | 0 | } else { |
766 | 0 | tvbparse_elem_t* tok_last = tok->sub->last; |
767 | 0 | ti_raw = proto_tree_add_none_format(parent_tree, hf_json_object_raw, tok_last->tvb, tok_last->offset, tok_last->len, "}"); |
768 | 0 | } |
769 | 0 | wmem_stack_pop(data->stack_raw); |
770 | |
|
771 | 0 | data->prev_item_raw = ti_raw; |
772 | 0 | data->prev_item_type_raw = JSON_MARK_TYPE_END_OBJECT; |
773 | 0 | } |
774 | 646 | } |
775 | | |
776 | | static void |
777 | 803 | before_member(void *tvbparse_data, const void *wanted_data _U_, tvbparse_elem_t *tok) { |
778 | 803 | json_parser_data_t *data = (json_parser_data_t *) tvbparse_data; |
779 | | |
780 | 803 | proto_tree *tree = (proto_tree *)wmem_stack_peek(data->stack); |
781 | 803 | proto_tree *subtree; |
782 | 803 | proto_item *ti; |
783 | | |
784 | 803 | const char* key_string_without_quotation_marks = get_json_string(data->pinfo->pool, tok->sub, true); |
785 | | |
786 | 803 | ti = proto_tree_add_string(tree, hf_json_member, tok->tvb, tok->offset, tok->len, key_string_without_quotation_marks); |
787 | | |
788 | 803 | subtree = proto_item_add_subtree(ti, ett_json_member); |
789 | 803 | wmem_stack_push(data->stack, subtree); |
790 | | |
791 | | // extended path based filtering |
792 | 803 | char* last_key_string = (char*)wmem_stack_pop(data->stack_path); |
793 | 803 | char* base_path = (char*)wmem_stack_pop(data->stack_path); |
794 | 803 | wmem_stack_push(data->stack_path, base_path); |
795 | 803 | wmem_stack_push(data->stack_path, last_key_string); |
796 | | |
797 | 803 | char* path = join_strings(data->pinfo->pool, base_path, key_string_without_quotation_marks, '/'); |
798 | 803 | wmem_stack_push(data->stack_path, path); |
799 | | /* stack won't write/free pointer. */ |
800 | 803 | wmem_stack_push(data->stack_path, (void *)key_string_without_quotation_marks); |
801 | | |
802 | 803 | if (json_compact) { |
803 | 0 | proto_tree *tree_compact = (proto_tree *)wmem_stack_peek(data->stack_compact); |
804 | 0 | proto_tree *subtree_compact; |
805 | 0 | proto_item *ti_compact = NULL; |
806 | |
|
807 | 0 | tvbparse_elem_t *key_tok = tok->sub; |
808 | |
|
809 | 0 | if (key_tok && key_tok->id == JSON_TOKEN_STRING) { |
810 | 0 | ti_compact = json_key_lookup(tree_compact, tok, key_string_without_quotation_marks, data->pinfo, true); |
811 | 0 | if (!ti_compact) { |
812 | 0 | ti_compact = proto_tree_add_none_format(tree_compact, hf_json_member_compact, tok->tvb, tok->offset, tok->len, "\"%s\":", key_string_without_quotation_marks); |
813 | 0 | } |
814 | 0 | } else { |
815 | 0 | ti_compact = proto_tree_add_item(tree_compact, hf_json_member_compact, tok->tvb, tok->offset, tok->len, ENC_NA); |
816 | 0 | } |
817 | |
|
818 | 0 | subtree_compact = proto_item_add_subtree(ti_compact, ett_json_member_compact); |
819 | 0 | wmem_stack_push(data->stack_compact, subtree_compact); |
820 | 0 | } |
821 | | |
822 | 803 | if (json_raw) { |
823 | 0 | proto_tree* tree_raw = (proto_tree*)wmem_stack_peek(data->stack_raw); |
824 | 0 | proto_tree* subtree_raw; |
825 | 0 | proto_item* ti_raw = NULL; |
826 | 0 | tvbparse_elem_t* key_tok = tok->sub; |
827 | |
|
828 | 0 | if (data->prev_item_raw && data->prev_item_type_raw != JSON_MARK_TYPE_BEGIN_OBJECT && data->prev_item_type_raw != JSON_MARK_TYPE_BEGIN_ARRAY) { |
829 | 0 | proto_item_append_text(data->prev_item_raw, ","); |
830 | 0 | } |
831 | |
|
832 | 0 | if (key_tok && key_tok->id == JSON_TOKEN_STRING) { |
833 | 0 | ti_raw = json_key_lookup(tree_raw, tok, key_string_without_quotation_marks, data->pinfo, true); |
834 | 0 | if (!ti_raw) { |
835 | 0 | ti_raw = proto_tree_add_none_format(tree_raw, hf_json_member_raw, tok->tvb, tok->offset, tok->len, "\"%s\":", key_string_without_quotation_marks); |
836 | 0 | } |
837 | 0 | } else { |
838 | 0 | ti_raw = proto_tree_add_item(tree_raw, hf_json_member_raw, tok->tvb, tok->offset, tok->len, ENC_NA); |
839 | 0 | } |
840 | |
|
841 | 0 | subtree_raw = proto_item_add_subtree(ti_raw, ett_json_member_raw); |
842 | 0 | wmem_stack_push(data->stack_raw, subtree_raw); |
843 | |
|
844 | 0 | data->prev_item_raw = ti_raw; |
845 | 0 | data->prev_item_type_raw = JSON_MARK_TYPE_MEMBER_NAME; |
846 | 0 | } |
847 | 803 | } |
848 | | |
849 | | static void |
850 | 803 | after_member(void *tvbparse_data, const void *wanted_data _U_, tvbparse_elem_t *tok) { |
851 | 803 | json_parser_data_t *data = (json_parser_data_t *) tvbparse_data; |
852 | | |
853 | 803 | proto_tree *tree = (proto_tree *)wmem_stack_pop(data->stack); |
854 | | |
855 | 803 | tvbparse_elem_t* key_tok = tok->sub; |
856 | 803 | if (tree && key_tok && key_tok->id == JSON_TOKEN_STRING) { |
857 | | |
858 | 803 | const char* key_string_without_quotation_marks = get_json_string(data->pinfo->pool, key_tok, true); |
859 | | |
860 | 803 | proto_tree_add_string(tree, hf_json_key, key_tok->tvb, key_tok->offset, key_tok->len, key_string_without_quotation_marks); |
861 | 803 | } |
862 | | |
863 | | // extended path based filtering |
864 | 803 | wmem_stack_pop(data->stack_path); // Pop key |
865 | 803 | char* path = (char*)wmem_stack_pop(data->stack_path); |
866 | 803 | if (tree) |
867 | 803 | { |
868 | 803 | proto_item* path_item = proto_tree_add_string(tree, hf_json_path, tok->tvb, tok->offset, tok->len, path); |
869 | 803 | proto_item_set_generated(path_item); |
870 | 803 | if (hide_extended_path_based_filtering) |
871 | 0 | { |
872 | 0 | proto_item_set_hidden(path_item); |
873 | 0 | } |
874 | 803 | } |
875 | | |
876 | 803 | if (json_compact) { |
877 | 0 | wmem_stack_pop(data->stack_compact); |
878 | 0 | json_object_add_key(data); |
879 | 0 | } |
880 | | |
881 | 803 | if (json_raw) { |
882 | 0 | wmem_stack_pop(data->stack_raw); |
883 | 0 | } |
884 | 803 | } |
885 | | |
886 | | static void |
887 | 2.79k | before_array(void *tvbparse_data, const void *wanted_data _U_, tvbparse_elem_t *tok) { |
888 | 2.79k | json_parser_data_t *data = (json_parser_data_t *) tvbparse_data; |
889 | | |
890 | 2.79k | proto_tree *tree = (proto_tree *)wmem_stack_peek(data->stack); |
891 | 2.79k | proto_tree *subtree; |
892 | 2.79k | proto_item *ti; |
893 | | |
894 | 2.79k | ti = proto_tree_add_item(tree, hf_json_array, tok->tvb, tok->offset, tok->len, ENC_NA); |
895 | 2.79k | if (json_hide_original_tree() && wmem_stack_count(data->stack) == 1) { |
896 | 0 | proto_item_set_hidden(ti); |
897 | 0 | } |
898 | | |
899 | 2.79k | subtree = proto_item_add_subtree(ti, ett_json_array); |
900 | 2.79k | wmem_stack_push(data->stack, subtree); |
901 | | |
902 | | // extended path based filtering |
903 | 2.79k | char* last_key_string = (char*)wmem_stack_pop(data->stack_path); |
904 | 2.79k | char* base_path = (char*)wmem_stack_pop(data->stack_path); |
905 | 2.79k | wmem_stack_push(data->stack_path, base_path); |
906 | 2.79k | wmem_stack_push(data->stack_path, last_key_string); |
907 | | |
908 | 2.79k | char* path = join_strings(data->pinfo->pool, base_path, "[]", '/'); |
909 | | |
910 | 2.79k | wmem_stack_push(data->stack_path, path); |
911 | 2.79k | wmem_stack_push(data->stack_path, "[]"); |
912 | | |
913 | | // Try key_lookup |
914 | 2.79k | json_key_lookup(tree, tok, last_key_string, data->pinfo, false); |
915 | | |
916 | 2.79k | if (json_compact) { |
917 | 0 | proto_tree* tree_compact = (proto_tree*)wmem_stack_peek(data->stack_compact); |
918 | 0 | proto_tree* subtree_compact; |
919 | 0 | proto_item* ti_compact; |
920 | |
|
921 | 0 | int idx = GPOINTER_TO_INT(wmem_stack_peek(data->array_idx)); |
922 | |
|
923 | 0 | if (JSON_INSIDE_ARRAY(idx)) { |
924 | 0 | ti_compact = proto_tree_add_none_format(tree_compact, hf_json_array_compact, tok->tvb, tok->offset, tok->len, "%d:", idx); |
925 | 0 | subtree_compact = proto_item_add_subtree(ti_compact, ett_json_array_compact); |
926 | 0 | json_array_index_increment(data); |
927 | 0 | } else { |
928 | 0 | subtree_compact = tree_compact; |
929 | 0 | } |
930 | 0 | wmem_stack_push(data->stack_compact, subtree_compact); |
931 | |
|
932 | 0 | JSON_ARRAY_BEGIN(data); |
933 | 0 | } |
934 | | |
935 | 2.79k | if (json_raw) { |
936 | 0 | proto_tree* tree_raw = (proto_tree*)wmem_stack_peek(data->stack_raw); |
937 | 0 | proto_tree* subtree_raw; |
938 | 0 | proto_item* ti_raw; |
939 | |
|
940 | 0 | if (data->prev_item_raw && data->prev_item_type_raw == JSON_MARK_TYPE_END_ARRAY) { |
941 | 0 | proto_item_append_text(data->prev_item_raw, ","); |
942 | 0 | } |
943 | |
|
944 | 0 | if (data->prev_item_type_raw == JSON_MARK_TYPE_MEMBER_NAME) { |
945 | | /* this is an array value of an member, add the "[" just after the member name */ |
946 | 0 | ti_raw = data->prev_item_raw; |
947 | 0 | proto_item_append_text(ti_raw, " ["); |
948 | 0 | } else { |
949 | | /* this array is either the top element or an element of an array, add the "[" as a single item */ |
950 | 0 | ti_raw = proto_tree_add_none_format(tree_raw, hf_json_array_raw, tok->tvb, tok->offset, tok->len, "["); |
951 | 0 | } |
952 | |
|
953 | 0 | subtree_raw = proto_item_add_subtree(ti_raw, ett_json_array_raw); |
954 | 0 | wmem_stack_push(data->stack_raw, subtree_raw); |
955 | |
|
956 | 0 | data->prev_item_raw = ti_raw; |
957 | 0 | data->prev_item_type_raw = JSON_MARK_TYPE_BEGIN_ARRAY; |
958 | 0 | } |
959 | 2.79k | } |
960 | | |
961 | | static void |
962 | 2.79k | after_array(void *tvbparse_data, const void *wanted_data _U_, tvbparse_elem_t* tok) { |
963 | 2.79k | json_parser_data_t *data = (json_parser_data_t *) tvbparse_data; |
964 | | |
965 | 2.79k | wmem_stack_pop(data->stack); |
966 | | |
967 | | // extended path based filtering |
968 | 2.79k | wmem_stack_pop(data->stack_path); // Pop key |
969 | 2.79k | wmem_stack_pop(data->stack_path); // Pop path |
970 | | |
971 | 2.79k | if (json_compact) { |
972 | 0 | proto_tree *tree_compact = (proto_tree *)wmem_stack_peek(data->stack_compact); |
973 | 0 | proto_item *parent_item = proto_tree_get_parent(tree_compact); |
974 | |
|
975 | 0 | int idx = GPOINTER_TO_INT(wmem_stack_peek(data->array_idx)); |
976 | 0 | if (idx == 0) |
977 | 0 | proto_item_append_text(parent_item, " []"); |
978 | 0 | else |
979 | 0 | proto_item_append_text(parent_item, " [...]"); |
980 | |
|
981 | 0 | wmem_stack_pop(data->stack_compact); |
982 | |
|
983 | 0 | JSON_ARRAY_OBJECT_END(data); |
984 | 0 | } |
985 | | |
986 | 2.79k | if (json_raw) { |
987 | 0 | proto_tree* tree_raw = (proto_tree*)wmem_stack_peek(data->stack_raw); |
988 | 0 | proto_tree* parent_tree = proto_tree_get_parent_tree(tree_raw); |
989 | 0 | proto_item* ti_raw; |
990 | 0 | if (data->prev_item_type_raw == JSON_MARK_TYPE_BEGIN_ARRAY) { /* an empty array */ |
991 | 0 | ti_raw = data->prev_item_raw; |
992 | 0 | proto_item_append_text(ti_raw, "]"); |
993 | 0 | } else { |
994 | 0 | tvbparse_elem_t* tok_last = tok->sub->last; |
995 | 0 | ti_raw = proto_tree_add_none_format(parent_tree, hf_json_array_raw, tok_last->tvb, tok_last->offset, tok_last->len, "]"); |
996 | 0 | } |
997 | 0 | wmem_stack_pop(data->stack_raw); |
998 | |
|
999 | 0 | data->prev_item_raw = ti_raw; |
1000 | 0 | data->prev_item_type_raw = JSON_MARK_TYPE_END_ARRAY; |
1001 | 0 | } |
1002 | 2.79k | } |
1003 | | |
1004 | | static void |
1005 | 5.51k | after_value(void *tvbparse_data, const void *wanted_data _U_, tvbparse_elem_t *tok) { |
1006 | 5.51k | json_parser_data_t *data = (json_parser_data_t *) tvbparse_data; |
1007 | | |
1008 | 5.51k | proto_tree *tree = (proto_tree *)wmem_stack_peek(data->stack); |
1009 | 5.51k | json_token_type_t value_id = tok->sub ? (json_token_type_t)tok->sub->id : JSON_TOKEN_INVALID; |
1010 | | |
1011 | 5.51k | if (!(value_id == JSON_TOKEN_STRING || value_id == JSON_TOKEN_NUMBER || value_id == JSON_TOKEN_FALSE |
1012 | 1.26k | || value_id == JSON_TOKEN_NULL || value_id == JSON_TOKEN_TRUE || value_id == JSON_TOKEN_NAN)) |
1013 | 676 | { |
1014 | 676 | return; |
1015 | 676 | } |
1016 | | |
1017 | | // extended path based filtering |
1018 | 4.83k | char* key_string = (char*)wmem_stack_pop(data->stack_path); |
1019 | 4.83k | char* path = (char*)wmem_stack_pop(data->stack_path); |
1020 | | |
1021 | 4.83k | const char* value_str = NULL; |
1022 | 4.83k | if (value_id == JSON_TOKEN_STRING && tok->len >= 2) |
1023 | 791 | { |
1024 | 791 | value_str = get_json_string(data->pinfo->pool, tok, true); |
1025 | 791 | } |
1026 | 4.04k | else |
1027 | 4.04k | { |
1028 | 4.04k | value_str = get_json_string(data->pinfo->pool, tok, false); |
1029 | 4.04k | } |
1030 | | |
1031 | 4.83k | char* path_with_value = join_strings(data->pinfo->pool, path, value_str, ':'); |
1032 | 4.83k | char* memeber_with_value = join_strings(data->pinfo->pool, key_string, value_str, ':'); |
1033 | 4.83k | proto_item* path_with_value_item = proto_tree_add_string(tree, hf_json_path_with_value, tok->tvb, tok->offset, tok->len, path_with_value); |
1034 | 4.83k | proto_item* member_with_value_item = proto_tree_add_string(tree, hf_json_member_with_value, tok->tvb, tok->offset, tok->len, memeber_with_value); |
1035 | | |
1036 | 4.83k | proto_item_set_generated(path_with_value_item); |
1037 | 4.83k | proto_item_set_generated(member_with_value_item); |
1038 | | |
1039 | 4.83k | if (hide_extended_path_based_filtering) |
1040 | 0 | { |
1041 | 0 | proto_item_set_hidden(path_with_value_item); |
1042 | 0 | proto_item_set_hidden(member_with_value_item); |
1043 | 0 | } |
1044 | | |
1045 | 4.83k | wmem_stack_push(data->stack_path, path); |
1046 | 4.83k | wmem_stack_push(data->stack_path, key_string); |
1047 | | |
1048 | 4.83k | switch (value_id) { |
1049 | 791 | case JSON_TOKEN_STRING: |
1050 | 791 | if (tok->len >= 2) { |
1051 | | // Try key_lookup |
1052 | 791 | proto_item *key_lookup = NULL; |
1053 | 791 | key_lookup = json_key_lookup(tree, tok, key_string, data->pinfo, false); |
1054 | 791 | if (!key_lookup) { |
1055 | 791 | proto_tree_add_string(tree, hf_json_value_string, tok->tvb, tok->offset, tok->len, value_str); |
1056 | 791 | } |
1057 | 791 | } |
1058 | 0 | else |
1059 | 0 | { |
1060 | 0 | proto_tree_add_item(tree, hf_json_value_string, tok->tvb, tok->offset, tok->len, ENC_ASCII | ENC_NA); |
1061 | 0 | } |
1062 | | |
1063 | 791 | break; |
1064 | | |
1065 | 3.26k | case JSON_TOKEN_NUMBER: |
1066 | 3.26k | proto_tree_add_double(tree, hf_json_value_number, tok->tvb, tok->offset, tok->len, g_ascii_strtod(value_str, NULL)); |
1067 | | |
1068 | 3.26k | break; |
1069 | | |
1070 | 194 | case JSON_TOKEN_FALSE: |
1071 | 194 | proto_tree_add_item(tree, hf_json_value_false, tok->tvb, tok->offset, tok->len, ENC_NA); |
1072 | | |
1073 | 194 | break; |
1074 | | |
1075 | 194 | case JSON_TOKEN_NULL: |
1076 | 194 | proto_tree_add_item(tree, hf_json_value_null, tok->tvb, tok->offset, tok->len, ENC_NA); |
1077 | | |
1078 | 194 | break; |
1079 | | |
1080 | 196 | case JSON_TOKEN_TRUE: |
1081 | 196 | proto_tree_add_item(tree, hf_json_value_true, tok->tvb, tok->offset, tok->len, ENC_NA); |
1082 | | |
1083 | 196 | break; |
1084 | | |
1085 | 195 | case JSON_TOKEN_NAN: |
1086 | 195 | proto_tree_add_item(tree, hf_json_value_nan, tok->tvb, tok->offset, tok->len, ENC_NA); |
1087 | | |
1088 | 195 | break; |
1089 | | |
1090 | 0 | default: |
1091 | 0 | proto_tree_add_format_text(tree, tok->tvb, tok->offset, tok->len); |
1092 | 0 | break; |
1093 | 4.83k | } |
1094 | | |
1095 | 4.83k | if (json_compact) { |
1096 | 0 | proto_tree *tree_compact = (proto_tree *)wmem_stack_peek(data->stack_compact); |
1097 | |
|
1098 | 0 | int idx = GPOINTER_TO_INT(wmem_stack_peek(data->array_idx)); |
1099 | |
|
1100 | 0 | char *val_str = (char*)tvb_get_string_enc(data->pinfo->pool, tok->tvb, tok->offset, tok->len, ENC_UTF_8); |
1101 | |
|
1102 | 0 | if (JSON_INSIDE_ARRAY(idx)) { |
1103 | 0 | proto_tree_add_none_format(tree_compact, hf_json_array_item_compact, tok->tvb, tok->offset, tok->len, "%d: %s", idx, val_str); |
1104 | 0 | json_array_index_increment(data); |
1105 | 0 | } else { |
1106 | 0 | proto_item *parent_item = proto_tree_get_parent(tree_compact); |
1107 | 0 | proto_item_append_text(parent_item, " %s", val_str); |
1108 | 0 | } |
1109 | 0 | } |
1110 | | |
1111 | 4.83k | if (json_raw) { |
1112 | 0 | proto_tree* tree_raw = (proto_tree*)wmem_stack_peek(data->stack_raw); |
1113 | 0 | proto_item* ti_raw; |
1114 | 0 | char* val_str = (char*)tvb_get_string_enc(data->pinfo->pool, tok->tvb, tok->offset, tok->len, ENC_UTF_8); |
1115 | |
|
1116 | 0 | if (data->prev_item_raw && data->prev_item_type_raw == JSON_MARK_TYPE_VALUE) { |
1117 | 0 | proto_item_append_text(data->prev_item_raw, ","); /* this value is an element of an array */ |
1118 | 0 | } |
1119 | |
|
1120 | 0 | if (data->prev_item_raw && data->prev_item_type_raw == JSON_MARK_TYPE_MEMBER_NAME) { |
1121 | 0 | ti_raw = proto_tree_get_parent(tree_raw); |
1122 | 0 | proto_item_append_text(ti_raw, " %s", val_str); |
1123 | 0 | } else { |
1124 | 0 | ti_raw = proto_tree_add_none_format(tree_raw, hf_json_array_item_raw, tok->tvb, tok->offset, tok->len, "%s", val_str); |
1125 | 0 | } |
1126 | |
|
1127 | 0 | data->prev_item_raw = ti_raw; |
1128 | 0 | data->prev_item_type_raw = JSON_MARK_TYPE_VALUE; |
1129 | 0 | } |
1130 | 4.83k | } |
1131 | | |
1132 | | static void |
1133 | 14 | init_json_parser(void) { |
1134 | 14 | static tvbparse_wanted_t _want_object; |
1135 | 14 | static tvbparse_wanted_t _want_array; |
1136 | | |
1137 | 14 | tvbparse_wanted_t *want_object, *want_array; |
1138 | 14 | tvbparse_wanted_t *want_member; |
1139 | 14 | tvbparse_wanted_t *want_string; |
1140 | 14 | tvbparse_wanted_t *want_number, *want_int; |
1141 | 14 | tvbparse_wanted_t *want_value; |
1142 | 14 | tvbparse_wanted_t *want_value_separator; |
1143 | | |
1144 | 14 | #define tvbparse_optional(id, private_data, before_cb, after_cb, wanted) \ |
1145 | 84 | tvbparse_some(id, 0, 1, private_data, before_cb, after_cb, wanted) |
1146 | | |
1147 | 14 | tvbparse_wanted_t *want_quot = tvbparse_char(-1,"\"",NULL,NULL,NULL); |
1148 | | |
1149 | 14 | want_string = tvbparse_set_seq(JSON_TOKEN_STRING, NULL, NULL, NULL, |
1150 | 14 | want_quot, |
1151 | 14 | tvbparse_some(-1, 0, INT_MAX, NULL, NULL, NULL, |
1152 | 14 | tvbparse_set_oneof(-1, NULL, NULL, NULL, |
1153 | 14 | tvbparse_not_chars(-1, 0, 0, "\"" "\\", NULL, NULL, NULL), /* XXX, without invalid unicode characters */ |
1154 | 14 | tvbparse_set_seq(-1, NULL, NULL, NULL, |
1155 | 14 | tvbparse_char(-1, "\\", NULL, NULL, NULL), |
1156 | 14 | tvbparse_set_oneof(-1, NULL, NULL, NULL, |
1157 | 14 | tvbparse_chars(-1, 0, 1, "\"" "\\" "/bfnrt", NULL, NULL, NULL), |
1158 | 14 | tvbparse_set_seq(-1, NULL, NULL, NULL, |
1159 | 14 | tvbparse_char(-1, "u", NULL, NULL, NULL), |
1160 | 14 | tvbparse_chars(-1, 4, 4, "0123456789abcdefABCDEF", NULL, NULL, NULL), |
1161 | 14 | NULL), |
1162 | 14 | NULL), |
1163 | 14 | NULL), |
1164 | 14 | NULL) |
1165 | 14 | ), |
1166 | 14 | want_quot, |
1167 | 14 | NULL); |
1168 | | |
1169 | 14 | want_value_separator = tvbparse_char(-1, ",", NULL, NULL, NULL); |
1170 | | |
1171 | | /* int = zero / ( digit1-9 *DIGIT ) */ |
1172 | 14 | want_int = tvbparse_set_oneof(-1, NULL, NULL, NULL, |
1173 | 14 | tvbparse_char(-1, "0", NULL, NULL, NULL), |
1174 | 14 | tvbparse_set_seq(-1, NULL, NULL, NULL, |
1175 | 14 | tvbparse_chars(-1, 1, 1, "123456789", NULL, NULL, NULL), |
1176 | 14 | tvbparse_optional(-1, NULL, NULL, NULL, /* tvbparse_chars() don't respect 0 as min_len ;/ */ |
1177 | 14 | tvbparse_chars(-1, 0, 0, "0123456789", NULL, NULL, NULL)), |
1178 | 14 | NULL), |
1179 | 14 | NULL); |
1180 | | |
1181 | | /* number = [ minus ] int [ frac ] [ exp ] */ |
1182 | 14 | want_number = tvbparse_set_seq(JSON_TOKEN_NUMBER, NULL, NULL, NULL, |
1183 | 14 | tvbparse_optional(-1, NULL, NULL, NULL, /* tvbparse_chars() don't respect 0 as min_len ;/ */ |
1184 | 14 | tvbparse_chars(-1, 0, 1, "-", NULL, NULL, NULL)), |
1185 | 14 | want_int, |
1186 | | /* frac = decimal-point 1*DIGIT */ |
1187 | 14 | tvbparse_optional(-1, NULL, NULL, NULL, |
1188 | 14 | tvbparse_set_seq(-1, NULL, NULL, NULL, |
1189 | 14 | tvbparse_char(-1, ".", NULL, NULL, NULL), |
1190 | 14 | tvbparse_chars(-1, 1, 0, "0123456789", NULL, NULL, NULL), |
1191 | 14 | NULL)), |
1192 | | /* exp = e [ minus / plus ] 1*DIGIT */ |
1193 | 14 | tvbparse_optional(-1, NULL, NULL, NULL, |
1194 | 14 | tvbparse_set_seq(-1, NULL, NULL, NULL, |
1195 | 14 | tvbparse_char(-1, "eE", NULL, NULL, NULL), |
1196 | 14 | tvbparse_optional(-1, NULL, NULL, NULL, /* tvbparse_chars() don't respect 0 as min_len ;/ */ |
1197 | 14 | tvbparse_chars(-1, 0, 1, "-+", NULL, NULL, NULL)), |
1198 | 14 | tvbparse_chars(-1, 1, 0, "0123456789", NULL, NULL, NULL), |
1199 | 14 | NULL)), |
1200 | 14 | NULL); |
1201 | | |
1202 | | /* value = false / null / true / object / array / number / string */ |
1203 | 14 | want_value = tvbparse_set_oneof(-1, NULL, NULL, after_value, |
1204 | 14 | tvbparse_string(JSON_TOKEN_FALSE, "false", NULL, NULL, NULL), |
1205 | 14 | tvbparse_string(JSON_TOKEN_NULL, "null", NULL, NULL, NULL), |
1206 | 14 | tvbparse_string(JSON_TOKEN_TRUE, "true", NULL, NULL, NULL), |
1207 | 14 | tvbparse_string(JSON_TOKEN_NAN, "NaN", NULL, NULL, NULL), |
1208 | 14 | &_want_object, |
1209 | 14 | &_want_array, |
1210 | 14 | want_number, |
1211 | 14 | want_string, |
1212 | 14 | NULL); |
1213 | | |
1214 | | /* array = begin-array [ value *( value-separator value ) ] end-array */ |
1215 | 14 | want_array = tvbparse_set_seq(JSON_ARRAY, NULL, before_array, after_array, |
1216 | 14 | tvbparse_char(-1, "[", NULL, NULL, NULL), |
1217 | 14 | tvbparse_optional(-1, NULL, NULL, NULL, |
1218 | 14 | tvbparse_set_seq(-1, NULL, NULL, NULL, |
1219 | 14 | want_value, |
1220 | 14 | tvbparse_some(-1, 0, INT_MAX, NULL, NULL, NULL, |
1221 | 14 | tvbparse_set_seq(-1, NULL, NULL, NULL, |
1222 | 14 | want_value_separator, |
1223 | 14 | want_value, |
1224 | 14 | NULL)), |
1225 | 14 | NULL) |
1226 | 14 | ), |
1227 | 14 | tvbparse_char(-1, "]", NULL, NULL, NULL), |
1228 | 14 | NULL); |
1229 | 14 | _want_array = *want_array; |
1230 | | |
1231 | | /* member = string name-separator value */ |
1232 | 14 | want_member = tvbparse_set_seq(-1, NULL, before_member, after_member, |
1233 | 14 | want_string, |
1234 | 14 | tvbparse_char(-1, ":", NULL, NULL, NULL), |
1235 | 14 | want_value, |
1236 | 14 | NULL); |
1237 | | |
1238 | | /* object = begin-object [ member *( value-separator member ) ] end-object */ |
1239 | 14 | want_object = tvbparse_set_seq(JSON_OBJECT, NULL, before_object, after_object, |
1240 | 14 | tvbparse_char(-1, "{", NULL, NULL, NULL), |
1241 | 14 | tvbparse_optional(-1, NULL, NULL, NULL, |
1242 | 14 | tvbparse_set_seq(-1, NULL, NULL, NULL, |
1243 | 14 | want_member, |
1244 | 14 | tvbparse_some(-1, 0, INT_MAX, NULL, NULL, NULL, |
1245 | 14 | tvbparse_set_seq(-1, NULL, NULL, NULL, |
1246 | 14 | want_value_separator, |
1247 | 14 | want_member, |
1248 | 14 | NULL)), |
1249 | 14 | NULL) |
1250 | 14 | ), |
1251 | 14 | tvbparse_char(-1, "}", NULL, NULL, NULL), |
1252 | 14 | NULL); |
1253 | 14 | _want_object = *want_object; |
1254 | | |
1255 | 14 | want_ignore = tvbparse_chars(-1, 1, 0, " \t\r\n", NULL, NULL, NULL); |
1256 | | |
1257 | | /* JSON-text = object / array */ |
1258 | 14 | want = tvbparse_set_oneof(-1, NULL, NULL, NULL, |
1259 | 14 | want_object, |
1260 | 14 | want_array, |
1261 | | /* tvbparse_not_chars(-1, 1, 0, " \t\r\n", NULL, NULL, NULL), */ |
1262 | 14 | NULL); |
1263 | | |
1264 | | /* XXX, heur? */ |
1265 | 14 | } |
1266 | | |
1267 | | /* This function tries to understand if the payload is json or not */ |
1268 | | static bool |
1269 | | dissect_json_heur(tvbuff_t *tvb, packet_info *pinfo, proto_tree *tree, void *data) |
1270 | 0 | { |
1271 | 0 | unsigned len = tvb_captured_length(tvb); |
1272 | 0 | const uint8_t* buf = tvb_get_string_enc(pinfo->pool, tvb, 0, len, ENC_ASCII); |
1273 | |
|
1274 | 0 | if (json_validate(buf, len) == false) |
1275 | 0 | return false; |
1276 | | |
1277 | 0 | return (dissect_json(tvb, pinfo, tree, data) != 0); |
1278 | 0 | } |
1279 | | |
1280 | | /* This function tries to understand if the payload is sitting on top of AC DR */ |
1281 | | static bool |
1282 | | dissect_json_acdr_heur(tvbuff_t *tvb, packet_info *pinfo, proto_tree *tree, void *data) |
1283 | 0 | { |
1284 | 0 | unsigned acdr_prot = GPOINTER_TO_UINT(p_get_proto_data(pinfo->pool, pinfo, proto_acdr, 0)); |
1285 | 0 | if (acdr_prot == ACDR_VoiceAI) |
1286 | 0 | return dissect_json_heur(tvb, pinfo, tree, data); |
1287 | 0 | return false; |
1288 | 0 | } |
1289 | | |
1290 | | static void |
1291 | 14 | register_static_headers(void) { |
1292 | | |
1293 | 14 | json_header_fields_hash = g_hash_table_new_full(g_str_hash, g_str_equal, g_free, g_free); |
1294 | | |
1295 | 14 | } |
1296 | | |
1297 | | void |
1298 | | proto_register_json(void) |
1299 | 14 | { |
1300 | 14 | static hf_register_info hf[] = { |
1301 | 14 | { &hf_json_array, |
1302 | 14 | { "Array", "json.array", |
1303 | 14 | FT_NONE, BASE_NONE, NULL, 0x00, |
1304 | 14 | "JSON array", HFILL } |
1305 | 14 | }, |
1306 | 14 | { &hf_json_object, |
1307 | 14 | { "Object", "json.object", |
1308 | 14 | FT_STRING, BASE_NONE|BASE_NO_DISPLAY_VALUE, NULL, 0x00, |
1309 | 14 | "JSON object", HFILL } |
1310 | 14 | }, |
1311 | 14 | { &hf_json_member, |
1312 | 14 | { "Member", "json.member", |
1313 | 14 | FT_STRING, BASE_NONE, NULL, 0x00, |
1314 | 14 | "JSON object member", HFILL } |
1315 | 14 | }, |
1316 | 14 | { &hf_json_key, |
1317 | 14 | { "Key", "json.key", |
1318 | 14 | FT_STRING, BASE_NONE, NULL, 0x00, |
1319 | 14 | NULL, HFILL } |
1320 | 14 | }, |
1321 | 14 | { &hf_json_path, |
1322 | 14 | { "Path", "json.path", |
1323 | 14 | FT_STRING, BASE_NONE, NULL, 0x00, |
1324 | 14 | NULL, HFILL } |
1325 | 14 | }, |
1326 | 14 | { &hf_json_path_with_value, |
1327 | 14 | { "Path with value", "json.path_with_value", |
1328 | 14 | FT_STRING, BASE_NONE, NULL, 0x00, |
1329 | 14 | NULL, HFILL } |
1330 | 14 | }, |
1331 | 14 | { &hf_json_member_with_value, |
1332 | 14 | { "Member with value", "json.member_with_value", |
1333 | 14 | FT_STRING, BASE_NONE, NULL, 0x00, |
1334 | 14 | NULL, HFILL } |
1335 | 14 | }, |
1336 | 14 | { &hf_json_value_string, |
1337 | 14 | { /* FT_STRINGZ? */ "String value", "json.value.string", |
1338 | 14 | FT_STRING, BASE_NONE, NULL, 0x00, |
1339 | 14 | "JSON string value", HFILL } |
1340 | 14 | }, |
1341 | 14 | { &hf_json_value_number, |
1342 | 14 | { "Number value", "json.value.number", |
1343 | 14 | FT_DOUBLE, BASE_NONE, NULL, 0x00, |
1344 | 14 | "JSON number value", HFILL } |
1345 | 14 | }, |
1346 | 14 | { &hf_json_value_false, |
1347 | 14 | { "False value", "json.value.false", |
1348 | 14 | FT_NONE, BASE_NONE, NULL, 0x00, |
1349 | 14 | "JSON false value", HFILL } |
1350 | 14 | }, |
1351 | 14 | { &hf_json_value_null, |
1352 | 14 | { "Null value", "json.value.null", |
1353 | 14 | FT_NONE, BASE_NONE, NULL, 0x00, |
1354 | 14 | "JSON null value", HFILL } |
1355 | 14 | }, |
1356 | 14 | { &hf_json_value_true, |
1357 | 14 | { "True value", "json.value.true", |
1358 | 14 | FT_NONE, BASE_NONE, NULL, 0x00, |
1359 | 14 | "JSON true value", HFILL } |
1360 | 14 | }, |
1361 | 14 | { &hf_json_value_nan, |
1362 | 14 | { "NaN value", "json.value.nan", |
1363 | 14 | FT_NONE, BASE_NONE, NULL, 0x00, |
1364 | 14 | "JSON NaN value", HFILL } |
1365 | 14 | }, |
1366 | 14 | { &hf_json_array_compact, |
1367 | 14 | { "Array compact", "json.array_compact", |
1368 | 14 | FT_NONE, BASE_NONE, NULL, 0x00, |
1369 | 14 | "JSON array compact", HFILL } |
1370 | 14 | }, |
1371 | 14 | { &hf_json_object_compact, |
1372 | 14 | { "Object compact", "json.object_compact", |
1373 | 14 | FT_NONE, BASE_NONE, NULL, 0x00, |
1374 | 14 | "JSON object compact", HFILL } |
1375 | 14 | }, |
1376 | 14 | { &hf_json_member_compact, |
1377 | 14 | { "Member compact", "json.member_compact", |
1378 | 14 | FT_NONE, BASE_NONE, NULL, 0x00, |
1379 | 14 | "JSON member compact", HFILL } |
1380 | 14 | }, |
1381 | 14 | { &hf_json_array_item_compact, |
1382 | 14 | { "Array item compact", "json.array_item_compact", |
1383 | 14 | FT_NONE, BASE_NONE, NULL, 0x00, |
1384 | 14 | "JSON array item compact", HFILL } |
1385 | 14 | }, |
1386 | 14 | { &hf_json_binary_data, |
1387 | 14 | { "Binary data", "json.binary_data", |
1388 | 14 | FT_BYTES, BASE_NONE, NULL, 0x00, |
1389 | 14 | "JSON binary data", HFILL } |
1390 | 14 | }, |
1391 | 14 | { &hf_json_ignored_leading_bytes, |
1392 | 14 | { "Ignored leading bytes", "json.ignored_leading_bytes", |
1393 | 14 | FT_STRING, BASE_NONE, NULL, 0x00, |
1394 | 14 | NULL, HFILL } |
1395 | 14 | }, |
1396 | 14 | { &hf_json_array_raw, |
1397 | 14 | { "Array raw", "json.array_raw", |
1398 | 14 | FT_NONE, BASE_NONE, NULL, 0x00, |
1399 | 14 | "JSON array raw", HFILL } |
1400 | 14 | }, |
1401 | 14 | { &hf_json_object_raw, |
1402 | 14 | { "Object raw", "json.object_raw", |
1403 | 14 | FT_NONE, BASE_NONE, NULL, 0x00, |
1404 | 14 | "JSON object raw", HFILL } |
1405 | 14 | }, |
1406 | 14 | { &hf_json_member_raw, |
1407 | 14 | { "Member raw", "json.member_raw", |
1408 | 14 | FT_NONE, BASE_NONE, NULL, 0x00, |
1409 | 14 | "JSON member raw", HFILL } |
1410 | 14 | }, |
1411 | 14 | { &hf_json_array_item_raw, |
1412 | 14 | { "Array item raw", "json.array_item_raw", |
1413 | 14 | FT_NONE, BASE_NONE, NULL, 0x00, |
1414 | 14 | "JSON array item raw", HFILL } |
1415 | 14 | }, |
1416 | | |
1417 | 14 | }; |
1418 | | |
1419 | 14 | static int *ett[] = { |
1420 | 14 | &ett_json, |
1421 | 14 | &ett_json_array, |
1422 | 14 | &ett_json_object, |
1423 | 14 | &ett_json_member, |
1424 | 14 | &ett_json_compact, |
1425 | 14 | &ett_json_array_compact, |
1426 | 14 | &ett_json_object_compact, |
1427 | 14 | &ett_json_member_compact, |
1428 | 14 | &ett_json_raw, |
1429 | 14 | &ett_json_array_raw, |
1430 | 14 | &ett_json_object_raw, |
1431 | 14 | &ett_json_member_raw, |
1432 | 14 | }; |
1433 | | |
1434 | 14 | module_t *json_module; |
1435 | | |
1436 | 14 | proto_json = proto_register_protocol("JavaScript Object Notation", "JSON", "json"); |
1437 | 14 | proto_register_field_array(proto_json, hf, array_length(hf)); |
1438 | 14 | proto_register_subtree_array(ett, array_length(ett)); |
1439 | | |
1440 | 14 | json_handle = register_dissector("json", dissect_json, proto_json); |
1441 | 14 | json_file_handle = register_dissector("json_file", dissect_json_file, proto_json); |
1442 | | |
1443 | 14 | init_json_parser(); |
1444 | | |
1445 | 14 | json_module = prefs_register_protocol(proto_json, NULL); |
1446 | 14 | prefs_register_bool_preference(json_module, "compact_form", |
1447 | 14 | "Display JSON in compact form", |
1448 | 14 | "Display JSON like in browsers devtool", |
1449 | 14 | &json_compact); |
1450 | | |
1451 | 14 | prefs_register_bool_preference(json_module, "raw_form", |
1452 | 14 | "Display JSON in raw form", |
1453 | 14 | "Display JSON like in vscode editor", |
1454 | 14 | &json_raw); |
1455 | | |
1456 | 14 | prefs_register_bool_preference(json_module, "auto_hide", |
1457 | 14 | "Hide tree or root item automatically", |
1458 | 14 | "Determine whether to hide the tree of original form or root item of compact or raw form" |
1459 | 14 | " based on the enabled status of compact_form and raw_form preferences.", |
1460 | 14 | &auto_hide); |
1461 | | |
1462 | 14 | prefs_register_bool_preference(json_module, "ignore_leading_bytes", |
1463 | 14 | "Ignore leading non JSON bytes", |
1464 | 14 | "Leading bytes will be ignored until first '[' or '{' is found.", |
1465 | 14 | &ignore_leading_bytes); |
1466 | | |
1467 | 14 | prefs_register_bool_preference(json_module, "hide_extended_path_based_filtering", |
1468 | 14 | "Hide extended path based filtering", |
1469 | 14 | "Hide extended path based filtering", |
1470 | 14 | &hide_extended_path_based_filtering); |
1471 | | |
1472 | 14 | prefs_register_bool_preference(json_module, "unescape_strings", |
1473 | 14 | "Replace character escapes with the escaped literal value", |
1474 | 14 | "Replace character escapes with the escaped literal value", |
1475 | 14 | &unescape_strings); |
1476 | | |
1477 | | /* Fill hash table with static headers */ |
1478 | 14 | register_static_headers(); |
1479 | 14 | } |
1480 | | |
1481 | | void |
1482 | | proto_reg_handoff_json(void) |
1483 | 14 | { |
1484 | 14 | heur_dissector_add("hpfeeds", dissect_json_heur, "JSON over HPFEEDS", "json_hpfeeds", proto_json, HEURISTIC_ENABLE); |
1485 | 14 | heur_dissector_add("db-lsp", dissect_json_heur, "JSON over DB-LSP", "json_db_lsp", proto_json, HEURISTIC_ENABLE); |
1486 | 14 | heur_dissector_add("udp", dissect_json_acdr_heur, "JSON over AC DR", "json_acdr", proto_json, HEURISTIC_ENABLE); |
1487 | 14 | dissector_add_uint("wtap_encap", WTAP_ENCAP_JSON, json_file_handle); |
1488 | | |
1489 | 14 | dissector_add_for_decode_as("udp.port", json_file_handle); |
1490 | | |
1491 | 14 | dissector_add_string("media_type", "application/json", json_handle); /* RFC 4627 */ |
1492 | 14 | dissector_add_string("media_type", "application/senml+json", json_handle); /* RFC 8428 */ |
1493 | 14 | dissector_add_string("media_type", "application/sensml+json", json_handle); /* RFC 8428 */ |
1494 | 14 | dissector_add_string("media_type", "application/json-rpc", json_handle); /* JSON-RPC over HTTP */ |
1495 | 14 | dissector_add_string("media_type", "application/jsonrequest", json_handle); /* JSON-RPC over HTTP */ |
1496 | 14 | dissector_add_string("media_type", "application/dds-web+json", json_handle); /* DDS Web Integration Service over HTTP */ |
1497 | 14 | dissector_add_string("media_type", "application/vnd.oma.lwm2m+json", json_handle); /* LWM2M JSON over CoAP */ |
1498 | 14 | dissector_add_string("media_type", "application/problem+json", json_handle); /* RFC 7807 Problem Details for HTTP APIs*/ |
1499 | 14 | dissector_add_string("media_type", "application/merge-patch+json", json_handle); /* RFC 7386 HTTP PATCH methods (RFC 5789) */ |
1500 | 14 | dissector_add_string("media_type", "application/json-patch+json", json_handle); /* RFC 6902 JavaScript Object Notation (JSON) Patch */ |
1501 | 14 | dissector_add_string("media_type", "application/x-ndjson", json_handle); |
1502 | 14 | dissector_add_string("media_type", "application/3gppHal+json", json_handle); |
1503 | 14 | dissector_add_string("media_type.suffix", "json", json_handle); /* RFC 6839 */ |
1504 | 14 | dissector_add_string("grpc_message_type", "application/grpc+json", json_handle); |
1505 | 14 | dissector_add_uint_range_with_preference("tcp.port", "", json_file_handle); /* JSON-RPC over TCP */ |
1506 | 14 | dissector_add_uint_range_with_preference("udp.port", "", json_file_handle); /* JSON-RPC over UDP */ |
1507 | | |
1508 | 14 | text_lines_handle = find_dissector_add_dependency("data-text-lines", proto_json); |
1509 | 14 | falco_json_handle = find_dissector("falcojson"); |
1510 | | |
1511 | 14 | proto_acdr = proto_get_id_by_filter_name("acdr"); |
1512 | 14 | } |
1513 | | |
1514 | | /* |
1515 | | * Editor modelines - https://www.wireshark.org/tools/modelines.html |
1516 | | * |
1517 | | * Local variables: |
1518 | | * c-basic-offset: 8 |
1519 | | * tab-width: 8 |
1520 | | * indent-tabs-mode: t |
1521 | | * End: |
1522 | | * |
1523 | | * vi: set shiftwidth=8 tabstop=8 noexpandtab: |
1524 | | * :indentSize=8:tabSize=8:noTabs=false: |
1525 | | */ |