Revert "TODO epan/dissectors/asn1/kerberos/packet-kerberos-template.c new GSS flags"
[wireshark-sm.git] / epan / dissectors / packet-json.c
blobca4223a3d520bb5bb1b2cc9e8c4ffd221616fef7
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/
7 * Copyright 2010, Jakub Zawadzki <darkjames-ws@darkjames.pl>
9 * Wireshark - Network traffic analyzer
10 * By Gerald Combs <gerald@wireshark.org>
11 * Copyright 1998 Gerald Combs
13 * SPDX-License-Identifier: GPL-2.0-or-later
15 #include "config.h"
17 #include <epan/packet.h>
18 #include <epan/tvbparse.h>
19 #include <epan/proto_data.h>
20 #include <wsutil/wsjson.h>
22 #include <wsutil/str_util.h>
23 #include <wsutil/unicode-utils.h>
25 #include <wiretap/wtap.h>
27 #include "packet-media-type.h"
28 #include "packet-acdr.h"
29 #include "packet-json.h"
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);
36 static dissector_handle_t json_handle;
37 static dissector_handle_t json_file_handle;
39 static int proto_json;
41 //Used to get AC DR proto data
42 static int proto_acdr;
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;
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;
83 /* Preferences */
84 static bool json_compact;
86 static bool json_raw;
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.
95 static bool auto_hide;
97 static bool ignore_leading_bytes;
99 static bool hide_extended_path_based_filtering;
101 static bool unescape_strings;
103 static tvbparse_wanted_t* want;
104 static tvbparse_wanted_t* want_ignore;
106 static dissector_handle_t text_lines_handle;
108 typedef enum {
109 JSON_TOKEN_INVALID = -1,
110 JSON_TOKEN_NUMBER = 0,
111 JSON_TOKEN_STRING,
112 JSON_TOKEN_FALSE,
113 JSON_TOKEN_NULL,
114 JSON_TOKEN_TRUE,
115 JSON_TOKEN_NAN,
117 /* not really tokens ... */
118 JSON_OBJECT,
119 JSON_ARRAY
121 } json_token_type_t;
123 typedef enum {
124 JSON_MARK_TYPE_NONE = 0,
125 JSON_MARK_TYPE_BEGIN_OBJECT,
126 JSON_MARK_TYPE_END_OBJECT,
127 JSON_MARK_TYPE_BEGIN_ARRAY,
128 JSON_MARK_TYPE_END_ARRAY,
129 JSON_MARK_TYPE_MEMBER_NAME,
130 JSON_MARK_TYPE_VALUE
131 } json_mark_type_t;
133 typedef struct {
134 wmem_stack_t *stack;
135 wmem_stack_t *stack_compact; /* Used for compact json form only */
136 wmem_stack_t *array_idx; /* Used for compact json form only.
137 Top item: -3.
138 Object: < 0.
139 Array -1: no key, -2: has key */
140 wmem_stack_t* stack_path;
141 packet_info* pinfo;
142 wmem_stack_t* stack_raw; /* Used for raw json form only */
143 json_mark_type_t prev_item_type_raw; /* Used for raw json form only */
144 proto_item* prev_item_raw; /* Used for raw json form only */
145 } json_parser_data_t;
147 #define JSON_COMPACT_TOP_ITEM -3
148 #define JSON_COMPACT_OBJECT_WITH_KEY -2
149 #define JSON_COMPACT_OBJECT_WITHOUT_KEY -1
150 #define JSON_COMPACT_ARRAY 0
152 #define JSON_ARRAY_BEGIN(json_tvbparse_data) wmem_stack_push(json_tvbparse_data->array_idx, GINT_TO_POINTER(JSON_COMPACT_ARRAY))
153 #define JSON_OBJECT_BEGIN(json_tvbparse_data) wmem_stack_push(json_tvbparse_data->array_idx, GINT_TO_POINTER(JSON_COMPACT_OBJECT_WITHOUT_KEY))
154 #define JSON_ARRAY_OBJECT_END(json_tvbparse_data) wmem_stack_pop(json_tvbparse_data->array_idx)
155 #define JSON_INSIDE_ARRAY(idx) (idx >= JSON_COMPACT_ARRAY)
156 #define JSON_OBJECT_SET_HAS_KEY(idx) (idx == JSON_COMPACT_OBJECT_WITH_KEY)
158 #define json_hide_original_tree() (auto_hide && (json_compact || json_raw))
159 #define json_hide_root_item() (auto_hide && ((json_compact && !json_raw) || (!json_compact && json_raw)))
161 static void
162 json_array_index_increment(json_parser_data_t *data)
164 int idx = GPOINTER_TO_INT(wmem_stack_pop(data->array_idx));
165 idx++;
166 wmem_stack_push(data->array_idx, GINT_TO_POINTER(idx));
169 static void
170 json_object_add_key(json_parser_data_t *data)
172 wmem_stack_pop(data->array_idx);
173 wmem_stack_push(data->array_idx, GINT_TO_POINTER(JSON_COMPACT_OBJECT_WITH_KEY));
176 static char*
177 json_string_unescape(wmem_allocator_t *scope, const char *string, size_t *length_ptr)
179 size_t read_index = 0;
180 size_t string_length = strlen(string);
182 wmem_strbuf_t* output_string_buffer = wmem_strbuf_new_sized(scope, string_length);
184 while (true)
186 // Do not overflow input string
187 if (!(read_index < string_length))
189 break;
192 uint8_t current_character = string[read_index];
194 // character that IS NOT escaped
195 if (current_character != '\\')
197 // A single UTF-8 character can cover more than one byte.
198 // Copy all bytes that belong to that character and forward currend_index by that amount of bytes
199 int utf8_character_length = ws_utf8_char_len(current_character);
201 if (utf8_character_length <= 0)
203 break;
206 for (int i = 0; i < utf8_character_length; i++)
208 // Do not overflow input string
209 if (!(read_index < string_length))
211 break;
214 current_character = string[read_index];
215 read_index++;
216 wmem_strbuf_append_c(output_string_buffer, current_character);
219 // character that IS escaped
220 else
222 read_index++;
224 // Do not overflow input string
225 if (!(read_index < string_length))
227 break;
230 current_character = string[read_index];
232 if (current_character == '\"' || current_character == '\\' || current_character == '/')
234 read_index++;
235 wmem_strbuf_append_c(output_string_buffer, current_character);
237 else if (current_character == 'b')
239 read_index++;
240 wmem_strbuf_append_c(output_string_buffer, '\b');
242 else if (current_character == 'f')
244 read_index++;
245 wmem_strbuf_append_c(output_string_buffer, '\f');
247 else if (current_character == 'n')
249 read_index++;
250 wmem_strbuf_append_c(output_string_buffer, '\n');
252 else if (current_character == 'r')
254 read_index++;
255 wmem_strbuf_append_c(output_string_buffer, '\r');
257 else if (current_character == 't')
259 read_index++;
260 wmem_strbuf_append_c(output_string_buffer, '\t');
262 else if (current_character == 'u')
264 read_index++;
266 uint32_t code_point = 0;
267 bool is_valid_unicode_character = true;
269 for (int i = 0; i < 4; i++)
271 // Do not overflow input string
272 if (!(read_index < string_length))
274 is_valid_unicode_character = false;
275 break;
278 current_character = string[read_index];
279 read_index++;
281 int nibble = ws_xton(current_character);
283 if(nibble < 0)
285 is_valid_unicode_character = false;
286 break;
289 code_point <<= 4;
290 code_point |= nibble;
293 if ((IS_LEAD_SURROGATE(code_point)))
295 // Do not overflow input string
296 if (!(read_index < string_length))
298 break;
300 current_character = string[read_index];
302 if (current_character == '\\')
304 read_index++;
306 // Do not overflow input string
307 if (!(read_index < string_length))
309 break;
312 current_character = string[read_index];
313 if (current_character == 'u') {
314 uint16_t lead_surrogate = code_point;
315 uint16_t trail_surrogate = 0;
317 read_index++;
319 for (int i = 0; i < 4; i++)
321 // Do not overflow input string
322 if (!(read_index < string_length))
324 is_valid_unicode_character = false;
325 break;
328 current_character = string[read_index];
329 read_index++;
331 int nibble = ws_xton(current_character);
333 if (nibble < 0)
335 is_valid_unicode_character = false;
336 break;
339 trail_surrogate <<= 4;
340 trail_surrogate |= nibble;
343 if ((IS_TRAIL_SURROGATE(trail_surrogate)))
345 code_point = SURROGATE_VALUE(lead_surrogate, trail_surrogate);
347 else
349 is_valid_unicode_character = false;
352 else
354 read_index++;
355 is_valid_unicode_character = false;
358 else
360 read_index++;
361 is_valid_unicode_character = false;
364 else if ((IS_TRAIL_SURROGATE(code_point)))
366 is_valid_unicode_character = false;
369 if (is_valid_unicode_character)
371 if (g_unichar_validate(code_point) && g_unichar_isprint(code_point))
373 char length_test_buffer[6];
374 int utf8_character_length = (int)g_unichar_to_utf8(code_point, length_test_buffer);
376 for (int i = 0; i < utf8_character_length; i++)
378 current_character = length_test_buffer[i];
379 wmem_strbuf_append_c(output_string_buffer, current_character);
384 else
386 wmem_strbuf_append_unichar_repl(output_string_buffer);
389 else
391 /* not valid by JSON grammar (tvbparse rules should not allow it) */
392 DISSECTOR_ASSERT_NOT_REACHED();
397 if (length_ptr)
398 *length_ptr = wmem_strbuf_get_len(output_string_buffer);
400 return wmem_strbuf_finalize(output_string_buffer);
403 /* This functions allocates memory with packet_scope but the returned pointer
404 * cannot be freed. */
405 static const char*
406 get_json_string(wmem_allocator_t *scope, tvbparse_elem_t *tok, bool remove_quotes)
408 char *string;
409 size_t length;
411 string = tvb_get_string_enc(scope, tok->tvb, tok->offset, tok->len, ENC_UTF_8);
413 if (unescape_strings) {
414 string = json_string_unescape(scope, string, &length);
416 else {
417 length = strlen(string);
420 if (remove_quotes) {
421 if (string[length - 1] == '"') {
422 string[length - 1] = '\0';
424 if (string[0] == '"') {
425 string += 1;
429 return string;
432 GHashTable* json_header_fields_hash;
434 static proto_item*
435 json_key_lookup(proto_tree* tree, tvbparse_elem_t* tok, const char* key_str, packet_info* pinfo, bool use_compact)
437 proto_item* ti;
438 int hf_id;
439 int offset, len;
441 json_data_decoder_t* json_data_decoder_rec = (json_data_decoder_t*)g_hash_table_lookup(json_header_fields_hash, key_str);
442 if (json_data_decoder_rec == NULL) {
443 return NULL;
446 hf_id = *json_data_decoder_rec->hf_id;
447 DISSECTOR_ASSERT(hf_id > 0);
449 int proto_id = proto_registrar_is_protocol(hf_id) ? hf_id : proto_registrar_get_parent(hf_id);
450 if (!proto_is_protocol_enabled(find_protocol_by_id(proto_id))) {
451 return NULL;
455 * use_compact == true: "tok is the composed element of the member"
456 * This is only called from before_member when the value is a
457 / JSON_TOKEN_STRING.
458 * use_compact == false: "tok is the composed element whose subelement is the value"
459 * For this, arrays with matching key are passed in before_array,
460 * strings are passed in after_value, and other types aren't passed in.
462 const tvbparse_elem_t* value_tok = tok;
463 if (use_compact) {
464 /* tok refers to the member ("key":"value")
465 * tok->sub is the key string
466 * tok->sub->next is the ':'
467 * tok->sub->last is a set with one element
468 * tok->sub->last->sub is the value
470 DISSECTOR_ASSERT(tok->sub);
471 value_tok = tok->sub->last;
473 /* tok is a set with one element
474 * tok->sub is the value
476 DISSECTOR_ASSERT(value_tok && value_tok->sub);
477 value_tok = value_tok->sub;
479 json_token_type_t value_id = (json_token_type_t)value_tok->id;
481 offset = value_tok->offset;
482 len = value_tok->len;
483 /* Remove the quotation marks from strings (the decoder functions
484 * apparently expect that.)
486 if (value_id == JSON_TOKEN_STRING && len >= 2) {
487 offset += 1;
488 len -= 2;
490 /* XXX - Every hf_id in packet-json_3gpp.c is a FT_STRING. Should other
491 * types be supported (perhaps verified against the JSON token type?)
492 * Should the encoding be ENC_UTF_8? Should the string be unescaped here?
494 ti = proto_tree_add_item(tree, hf_id, tok->tvb, offset, len, ENC_ASCII);
495 if (json_data_decoder_rec->json_data_decoder) {
496 (*json_data_decoder_rec->json_data_decoder)(value_tok->tvb, tree, pinfo, offset, len, key_str);
498 return ti;
502 static char*
503 join_strings(wmem_allocator_t *pool, const char* string_a, const char* string_b, char separator)
505 if (string_a == NULL)
507 return NULL;
509 if (string_b == NULL)
511 return NULL;
514 wmem_strbuf_t* output_string_buffer = wmem_strbuf_new(pool, string_a);
516 if (separator != '\0')
518 wmem_strbuf_append_c(output_string_buffer, separator);
521 wmem_strbuf_append(output_string_buffer, string_b);
523 char* output_string = wmem_strbuf_finalize(output_string_buffer);
524 return output_string;
527 static int
528 dissect_json(tvbuff_t *tvb, packet_info *pinfo, proto_tree *tree, void* data)
530 proto_tree *json_tree = NULL;
531 proto_item *ti = NULL;
533 json_parser_data_t parser_data;
534 tvbparse_t *tt;
536 media_content_info_t *content_info;
537 const char *data_name;
538 int offset;
540 /* Save pinfo*/
541 parser_data.pinfo = pinfo;
542 /* JSON dissector can be called in a JSON native file or when transported
543 * by another protocol, will make entry in the Protocol column on summary display accordingly
545 wmem_list_frame_t *proto = wmem_list_frame_prev(wmem_list_tail(pinfo->layers));
546 if (proto) {
547 const char *name = proto_get_protocol_filter_name(GPOINTER_TO_INT(wmem_list_frame_data(proto)));
549 if (strcmp(name, "frame")) {
550 col_append_sep_str(pinfo->cinfo, COL_PROTOCOL, "/", "JSON");
551 col_append_sep_str(pinfo->cinfo, COL_INFO, NULL, "JSON");
552 } else {
553 col_set_str(pinfo->cinfo, COL_PROTOCOL, "JSON");
554 col_set_str(pinfo->cinfo, COL_INFO, "JSON");
558 data_name = pinfo->match_string;
559 if (! (data_name && data_name[0])) {
561 * No information from "match_string"
563 content_info = (media_content_info_t *)data;
564 if (content_info == NULL) {
566 * No information from dissector data
568 data_name = NULL;
569 } else {
570 data_name = content_info->media_str;
571 if (! (data_name && data_name[0])) {
573 * No information from dissector data
575 data_name = NULL;
580 if (tree) {
581 ti = proto_tree_add_item(tree, proto_json, tvb, 0, -1, ENC_NA);
582 json_tree = proto_item_add_subtree(ti, ett_json);
584 if (data_name)
585 proto_item_append_text(ti, ": %s", data_name);
588 offset = 0;
589 /* XXX*/
590 p_add_proto_data(pinfo->pool, pinfo, proto_json, 0, tvb);
592 parser_data.stack = wmem_stack_new(pinfo->pool);
593 wmem_stack_push(parser_data.stack, json_tree);
595 // extended path based filtering
596 parser_data.stack_path = wmem_stack_new(pinfo->pool);
597 wmem_stack_push(parser_data.stack_path, "");
598 wmem_stack_push(parser_data.stack_path, "");
600 int buffer_length = (int)tvb_captured_length(tvb);
601 if (ignore_leading_bytes)
603 while (offset < buffer_length)
605 uint8_t current_character = tvb_get_uint8(tvb, offset);
606 if (current_character == '[' || current_character == '{')
608 break;
610 offset++;
613 if(offset > 0)
615 proto_tree_add_item(json_tree ? json_tree : tree, hf_json_ignored_leading_bytes, tvb, 0, offset, ENC_ASCII);
619 if (json_compact) {
620 proto_tree* json_tree_compact = json_hide_root_item() ? json_tree :
621 proto_tree_add_subtree(json_tree, tvb, 0, -1, ett_json_compact, NULL, "JSON compact form:");
623 parser_data.stack_compact = wmem_stack_new(pinfo->pool);
624 wmem_stack_push(parser_data.stack_compact, json_tree_compact);
626 parser_data.array_idx = wmem_stack_new(pinfo->pool);
627 wmem_stack_push(parser_data.array_idx, GINT_TO_POINTER(JSON_COMPACT_TOP_ITEM)); /* top element */
630 if (json_raw) {
631 proto_tree* json_tree_raw = json_hide_root_item() ? json_tree :
632 proto_tree_add_subtree(json_tree, tvb, 0, -1, ett_json_raw, NULL, "JSON raw form:");
634 parser_data.stack_raw = wmem_stack_new(pinfo->pool);
635 wmem_stack_push(parser_data.stack_raw, json_tree_raw);
637 parser_data.prev_item_raw = NULL;
638 parser_data.prev_item_type_raw = JSON_MARK_TYPE_NONE;
641 tt = tvbparse_init(pinfo->pool, tvb, offset, buffer_length - offset, &parser_data, want_ignore);
643 /* XXX, only one json in packet? */
644 while (tvbparse_get(tt, want))
647 offset = tvbparse_curr_offset(tt);
649 proto_item_set_len(ti, offset);
651 /* if we have some unparsed data, pass to data-text-lines dissector (?) */
652 if (tvb_reported_length_remaining(tvb, offset) > 0) {
653 tvbuff_t *next_tvb;
655 next_tvb = tvb_new_subset_remaining(tvb, offset);
657 call_dissector_with_data(text_lines_handle, next_tvb, pinfo, tree, data);
658 } else if (data_name) {
659 col_append_sep_fstr(pinfo->cinfo, COL_INFO, " ", "(%s)", data_name);
662 return tvb_captured_length(tvb);
666 * For dissecting JSON in a file; we don't get passed a media type.
668 static int
669 dissect_json_file(tvbuff_t *tvb, packet_info *pinfo, proto_tree *tree, void* data _U_)
671 return dissect_json(tvb, pinfo, tree, NULL);
674 static void
675 before_object(void *tvbparse_data, const void *wanted_data _U_, tvbparse_elem_t *tok) {
676 json_parser_data_t *data = (json_parser_data_t *) tvbparse_data;
678 proto_tree *tree = (proto_tree *)wmem_stack_peek(data->stack);
679 proto_tree *subtree;
680 proto_item *ti;
682 ti = proto_tree_add_item(tree, hf_json_object, tok->tvb, tok->offset, tok->len, ENC_UTF_8);
683 if (json_hide_original_tree() && wmem_stack_count(data->stack) == 1) {
684 proto_item_set_hidden(ti);
687 subtree = proto_item_add_subtree(ti, ett_json_object);
688 wmem_stack_push(data->stack, subtree);
690 if (json_compact) {
691 proto_tree *tree_compact = (proto_tree *)wmem_stack_peek(data->stack_compact);
692 proto_tree *subtree_compact;
693 proto_item *ti_compact;
695 int idx = GPOINTER_TO_INT(wmem_stack_peek(data->array_idx));
697 if (JSON_INSIDE_ARRAY(idx)) {
698 ti_compact = proto_tree_add_none_format(tree_compact, hf_json_object_compact, tok->tvb, tok->offset, tok->len, "%d:", idx);
699 subtree_compact = proto_item_add_subtree(ti_compact, ett_json_object_compact);
700 json_array_index_increment(data);
701 } else {
702 subtree_compact = tree_compact;
704 wmem_stack_push(data->stack_compact, subtree_compact);
706 JSON_OBJECT_BEGIN(data);
709 if (json_raw) {
710 proto_tree* tree_raw = (proto_tree*)wmem_stack_peek(data->stack_raw);
711 proto_tree* subtree_raw;
712 proto_item* ti_raw;
714 if (data->prev_item_raw && data->prev_item_type_raw == JSON_MARK_TYPE_END_OBJECT) {
715 proto_item_append_text(data->prev_item_raw, ",");
718 if (data->prev_item_type_raw == JSON_MARK_TYPE_MEMBER_NAME) {
719 /* this is an object value of an member, add the "{" just after the member name */
720 ti_raw = data->prev_item_raw;
721 proto_item_append_text(ti_raw, " {");
722 } else {
723 /* this object is either the top object or an element of an array, add the "{" as a single item */
724 ti_raw = proto_tree_add_none_format(tree_raw, hf_json_object_raw, tok->tvb, tok->offset, tok->len, "{");
727 subtree_raw = proto_item_add_subtree(ti_raw, ett_json_object_raw);
728 wmem_stack_push(data->stack_raw, subtree_raw);
730 data->prev_item_raw = ti_raw;
731 data->prev_item_type_raw = JSON_MARK_TYPE_BEGIN_OBJECT;
735 static void
736 after_object(void *tvbparse_data, const void *wanted_data _U_, tvbparse_elem_t* tok) {
737 json_parser_data_t *data = (json_parser_data_t *) tvbparse_data;
739 wmem_stack_pop(data->stack);
741 if (json_compact) {
742 proto_tree *tree_compact = (proto_tree *)wmem_stack_peek(data->stack_compact);
743 proto_item *parent_item = proto_tree_get_parent(tree_compact);
745 int idx = GPOINTER_TO_INT(wmem_stack_peek(data->array_idx));
747 if (JSON_OBJECT_SET_HAS_KEY(idx))
748 proto_item_append_text(parent_item, " {...}");
749 else
750 proto_item_append_text(parent_item, " {}");
752 wmem_stack_pop(data->stack_compact);
754 JSON_ARRAY_OBJECT_END(data);
757 if (json_raw) {
758 proto_tree* tree_raw = (proto_tree*)wmem_stack_peek(data->stack_raw);
759 proto_tree* parent_tree = proto_tree_get_parent_tree(tree_raw);
760 proto_item* ti_raw;
761 if (data->prev_item_type_raw == JSON_MARK_TYPE_BEGIN_OBJECT) { /* an empty object */
762 ti_raw = data->prev_item_raw;
763 proto_item_append_text(ti_raw, "}");
764 } else {
765 tvbparse_elem_t* tok_last = tok->sub->last;
766 ti_raw = proto_tree_add_none_format(parent_tree, hf_json_object_raw, tok_last->tvb, tok_last->offset, tok_last->len, "}");
768 wmem_stack_pop(data->stack_raw);
770 data->prev_item_raw = ti_raw;
771 data->prev_item_type_raw = JSON_MARK_TYPE_END_OBJECT;
775 static void
776 before_member(void *tvbparse_data, const void *wanted_data _U_, tvbparse_elem_t *tok) {
777 json_parser_data_t *data = (json_parser_data_t *) tvbparse_data;
779 proto_tree *tree = (proto_tree *)wmem_stack_peek(data->stack);
780 proto_tree *subtree;
781 proto_item *ti;
783 const char* key_string_without_quotation_marks = get_json_string(data->pinfo->pool, tok->sub, true);
785 ti = proto_tree_add_string(tree, hf_json_member, tok->tvb, tok->offset, tok->len, key_string_without_quotation_marks);
787 subtree = proto_item_add_subtree(ti, ett_json_member);
788 wmem_stack_push(data->stack, subtree);
790 // extended path based filtering
791 char* last_key_string = (char*)wmem_stack_pop(data->stack_path);
792 char* base_path = (char*)wmem_stack_pop(data->stack_path);
793 wmem_stack_push(data->stack_path, base_path);
794 wmem_stack_push(data->stack_path, last_key_string);
796 char* path = join_strings(data->pinfo->pool, base_path, key_string_without_quotation_marks, '/');
797 wmem_stack_push(data->stack_path, path);
798 /* stack won't write/free pointer. */
799 wmem_stack_push(data->stack_path, (void *)key_string_without_quotation_marks);
801 if (json_compact) {
802 proto_tree *tree_compact = (proto_tree *)wmem_stack_peek(data->stack_compact);
803 proto_tree *subtree_compact;
804 proto_item *ti_compact = NULL;
806 tvbparse_elem_t *key_tok = tok->sub;
808 if (key_tok && key_tok->id == JSON_TOKEN_STRING) {
809 ti_compact = json_key_lookup(tree_compact, tok, key_string_without_quotation_marks, data->pinfo, true);
810 if (!ti_compact) {
811 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 } else {
814 ti_compact = proto_tree_add_item(tree_compact, hf_json_member_compact, tok->tvb, tok->offset, tok->len, ENC_NA);
817 subtree_compact = proto_item_add_subtree(ti_compact, ett_json_member_compact);
818 wmem_stack_push(data->stack_compact, subtree_compact);
821 if (json_raw) {
822 proto_tree* tree_raw = (proto_tree*)wmem_stack_peek(data->stack_raw);
823 proto_tree* subtree_raw;
824 proto_item* ti_raw = NULL;
825 tvbparse_elem_t* key_tok = tok->sub;
827 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) {
828 proto_item_append_text(data->prev_item_raw, ",");
831 if (key_tok && key_tok->id == JSON_TOKEN_STRING) {
832 ti_raw = json_key_lookup(tree_raw, tok, key_string_without_quotation_marks, data->pinfo, true);
833 if (!ti_raw) {
834 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 } else {
837 ti_raw = proto_tree_add_item(tree_raw, hf_json_member_raw, tok->tvb, tok->offset, tok->len, ENC_NA);
840 subtree_raw = proto_item_add_subtree(ti_raw, ett_json_member_raw);
841 wmem_stack_push(data->stack_raw, subtree_raw);
843 data->prev_item_raw = ti_raw;
844 data->prev_item_type_raw = JSON_MARK_TYPE_MEMBER_NAME;
848 static void
849 after_member(void *tvbparse_data, const void *wanted_data _U_, tvbparse_elem_t *tok) {
850 json_parser_data_t *data = (json_parser_data_t *) tvbparse_data;
852 proto_tree *tree = (proto_tree *)wmem_stack_pop(data->stack);
854 tvbparse_elem_t* key_tok = tok->sub;
855 if (tree && key_tok && key_tok->id == JSON_TOKEN_STRING) {
857 const char* key_string_without_quotation_marks = get_json_string(data->pinfo->pool, key_tok, true);
859 proto_tree_add_string(tree, hf_json_key, key_tok->tvb, key_tok->offset, key_tok->len, key_string_without_quotation_marks);
862 // extended path based filtering
863 wmem_stack_pop(data->stack_path); // Pop key
864 char* path = (char*)wmem_stack_pop(data->stack_path);
865 if (tree)
867 proto_item* path_item = proto_tree_add_string(tree, hf_json_path, tok->tvb, tok->offset, tok->len, path);
868 proto_item_set_generated(path_item);
869 if (hide_extended_path_based_filtering)
871 proto_item_set_hidden(path_item);
875 if (json_compact) {
876 wmem_stack_pop(data->stack_compact);
877 json_object_add_key(data);
880 if (json_raw) {
881 wmem_stack_pop(data->stack_raw);
885 static void
886 before_array(void *tvbparse_data, const void *wanted_data _U_, tvbparse_elem_t *tok) {
887 json_parser_data_t *data = (json_parser_data_t *) tvbparse_data;
889 proto_tree *tree = (proto_tree *)wmem_stack_peek(data->stack);
890 proto_tree *subtree;
891 proto_item *ti;
893 ti = proto_tree_add_item(tree, hf_json_array, tok->tvb, tok->offset, tok->len, ENC_NA);
894 if (json_hide_original_tree() && wmem_stack_count(data->stack) == 1) {
895 proto_item_set_hidden(ti);
898 subtree = proto_item_add_subtree(ti, ett_json_array);
899 wmem_stack_push(data->stack, subtree);
901 // extended path based filtering
902 char* last_key_string = (char*)wmem_stack_pop(data->stack_path);
903 char* base_path = (char*)wmem_stack_pop(data->stack_path);
904 wmem_stack_push(data->stack_path, base_path);
905 wmem_stack_push(data->stack_path, last_key_string);
907 char* path = join_strings(data->pinfo->pool, base_path, "[]", '/');
909 wmem_stack_push(data->stack_path, path);
910 wmem_stack_push(data->stack_path, "[]");
912 // Try key_lookup
913 json_key_lookup(tree, tok, last_key_string, data->pinfo, false);
915 if (json_compact) {
916 proto_tree* tree_compact = (proto_tree*)wmem_stack_peek(data->stack_compact);
917 proto_tree* subtree_compact;
918 proto_item* ti_compact;
920 int idx = GPOINTER_TO_INT(wmem_stack_peek(data->array_idx));
922 if (JSON_INSIDE_ARRAY(idx)) {
923 ti_compact = proto_tree_add_none_format(tree_compact, hf_json_array_compact, tok->tvb, tok->offset, tok->len, "%d:", idx);
924 subtree_compact = proto_item_add_subtree(ti_compact, ett_json_array_compact);
925 json_array_index_increment(data);
926 } else {
927 subtree_compact = tree_compact;
929 wmem_stack_push(data->stack_compact, subtree_compact);
931 JSON_ARRAY_BEGIN(data);
934 if (json_raw) {
935 proto_tree* tree_raw = (proto_tree*)wmem_stack_peek(data->stack_raw);
936 proto_tree* subtree_raw;
937 proto_item* ti_raw;
939 if (data->prev_item_raw && data->prev_item_type_raw == JSON_MARK_TYPE_END_ARRAY) {
940 proto_item_append_text(data->prev_item_raw, ",");
943 if (data->prev_item_type_raw == JSON_MARK_TYPE_MEMBER_NAME) {
944 /* this is an array value of an member, add the "[" just after the member name */
945 ti_raw = data->prev_item_raw;
946 proto_item_append_text(ti_raw, " [");
947 } else {
948 /* this array is either the top element or an element of an array, add the "[" as a single item */
949 ti_raw = proto_tree_add_none_format(tree_raw, hf_json_array_raw, tok->tvb, tok->offset, tok->len, "[");
952 subtree_raw = proto_item_add_subtree(ti_raw, ett_json_array_raw);
953 wmem_stack_push(data->stack_raw, subtree_raw);
955 data->prev_item_raw = ti_raw;
956 data->prev_item_type_raw = JSON_MARK_TYPE_BEGIN_ARRAY;
960 static void
961 after_array(void *tvbparse_data, const void *wanted_data _U_, tvbparse_elem_t* tok) {
962 json_parser_data_t *data = (json_parser_data_t *) tvbparse_data;
964 wmem_stack_pop(data->stack);
966 // extended path based filtering
967 wmem_stack_pop(data->stack_path); // Pop key
968 wmem_stack_pop(data->stack_path); // Pop path
970 if (json_compact) {
971 proto_tree *tree_compact = (proto_tree *)wmem_stack_peek(data->stack_compact);
972 proto_item *parent_item = proto_tree_get_parent(tree_compact);
974 int idx = GPOINTER_TO_INT(wmem_stack_peek(data->array_idx));
975 if (idx == 0)
976 proto_item_append_text(parent_item, " []");
977 else
978 proto_item_append_text(parent_item, " [...]");
980 wmem_stack_pop(data->stack_compact);
982 JSON_ARRAY_OBJECT_END(data);
985 if (json_raw) {
986 proto_tree* tree_raw = (proto_tree*)wmem_stack_peek(data->stack_raw);
987 proto_tree* parent_tree = proto_tree_get_parent_tree(tree_raw);
988 proto_item* ti_raw;
989 if (data->prev_item_type_raw == JSON_MARK_TYPE_BEGIN_ARRAY) { /* an empty array */
990 ti_raw = data->prev_item_raw;
991 proto_item_append_text(ti_raw, "]");
992 } else {
993 tvbparse_elem_t* tok_last = tok->sub->last;
994 ti_raw = proto_tree_add_none_format(parent_tree, hf_json_array_raw, tok_last->tvb, tok_last->offset, tok_last->len, "]");
996 wmem_stack_pop(data->stack_raw);
998 data->prev_item_raw = ti_raw;
999 data->prev_item_type_raw = JSON_MARK_TYPE_END_ARRAY;
1003 static void
1004 after_value(void *tvbparse_data, const void *wanted_data _U_, tvbparse_elem_t *tok) {
1005 json_parser_data_t *data = (json_parser_data_t *) tvbparse_data;
1007 proto_tree *tree = (proto_tree *)wmem_stack_peek(data->stack);
1008 json_token_type_t value_id = tok->sub ? (json_token_type_t)tok->sub->id : JSON_TOKEN_INVALID;
1010 if (!(value_id == JSON_TOKEN_STRING || value_id == JSON_TOKEN_NUMBER || value_id == JSON_TOKEN_FALSE
1011 || value_id == JSON_TOKEN_NULL || value_id == JSON_TOKEN_TRUE || value_id == JSON_TOKEN_NAN))
1013 return;
1016 // extended path based filtering
1017 char* key_string = (char*)wmem_stack_pop(data->stack_path);
1018 char* path = (char*)wmem_stack_pop(data->stack_path);
1020 const char* value_str = NULL;
1021 if (value_id == JSON_TOKEN_STRING && tok->len >= 2)
1023 value_str = get_json_string(data->pinfo->pool, tok, true);
1025 else
1027 value_str = get_json_string(data->pinfo->pool, tok, false);
1030 char* path_with_value = join_strings(data->pinfo->pool, path, value_str, ':');
1031 char* memeber_with_value = join_strings(data->pinfo->pool, key_string, value_str, ':');
1032 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);
1033 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 proto_item_set_generated(path_with_value_item);
1036 proto_item_set_generated(member_with_value_item);
1038 if (hide_extended_path_based_filtering)
1040 proto_item_set_hidden(path_with_value_item);
1041 proto_item_set_hidden(member_with_value_item);
1044 wmem_stack_push(data->stack_path, path);
1045 wmem_stack_push(data->stack_path, key_string);
1047 switch (value_id) {
1048 case JSON_TOKEN_STRING:
1049 if (tok->len >= 2) {
1050 // Try key_lookup
1051 proto_item *key_lookup = NULL;
1052 key_lookup = json_key_lookup(tree, tok, key_string, data->pinfo, false);
1053 if (!key_lookup) {
1054 proto_tree_add_string(tree, hf_json_value_string, tok->tvb, tok->offset, tok->len, value_str);
1057 else
1059 proto_tree_add_item(tree, hf_json_value_string, tok->tvb, tok->offset, tok->len, ENC_ASCII | ENC_NA);
1062 break;
1064 case JSON_TOKEN_NUMBER:
1065 proto_tree_add_double(tree, hf_json_value_number, tok->tvb, tok->offset, tok->len, g_ascii_strtod(value_str, NULL));
1067 break;
1069 case JSON_TOKEN_FALSE:
1070 proto_tree_add_item(tree, hf_json_value_false, tok->tvb, tok->offset, tok->len, ENC_NA);
1072 break;
1074 case JSON_TOKEN_NULL:
1075 proto_tree_add_item(tree, hf_json_value_null, tok->tvb, tok->offset, tok->len, ENC_NA);
1077 break;
1079 case JSON_TOKEN_TRUE:
1080 proto_tree_add_item(tree, hf_json_value_true, tok->tvb, tok->offset, tok->len, ENC_NA);
1082 break;
1084 case JSON_TOKEN_NAN:
1085 proto_tree_add_item(tree, hf_json_value_nan, tok->tvb, tok->offset, tok->len, ENC_NA);
1087 break;
1089 default:
1090 proto_tree_add_format_text(tree, tok->tvb, tok->offset, tok->len);
1091 break;
1094 if (json_compact) {
1095 proto_tree *tree_compact = (proto_tree *)wmem_stack_peek(data->stack_compact);
1097 int idx = GPOINTER_TO_INT(wmem_stack_peek(data->array_idx));
1099 char *val_str = tvb_get_string_enc(data->pinfo->pool, tok->tvb, tok->offset, tok->len, ENC_UTF_8);
1101 if (JSON_INSIDE_ARRAY(idx)) {
1102 proto_tree_add_none_format(tree_compact, hf_json_array_item_compact, tok->tvb, tok->offset, tok->len, "%d: %s", idx, val_str);
1103 json_array_index_increment(data);
1104 } else {
1105 proto_item *parent_item = proto_tree_get_parent(tree_compact);
1106 proto_item_append_text(parent_item, " %s", val_str);
1110 if (json_raw) {
1111 proto_tree* tree_raw = (proto_tree*)wmem_stack_peek(data->stack_raw);
1112 proto_item* ti_raw;
1113 char* val_str = tvb_get_string_enc(data->pinfo->pool, tok->tvb, tok->offset, tok->len, ENC_UTF_8);
1115 if (data->prev_item_raw && data->prev_item_type_raw == JSON_MARK_TYPE_VALUE) {
1116 proto_item_append_text(data->prev_item_raw, ","); /* this value is an element of an array */
1119 if (data->prev_item_raw && data->prev_item_type_raw == JSON_MARK_TYPE_MEMBER_NAME) {
1120 ti_raw = proto_tree_get_parent(tree_raw);
1121 proto_item_append_text(ti_raw, " %s", val_str);
1122 } else {
1123 ti_raw = proto_tree_add_none_format(tree_raw, hf_json_array_item_raw, tok->tvb, tok->offset, tok->len, "%s", val_str);
1126 data->prev_item_raw = ti_raw;
1127 data->prev_item_type_raw = JSON_MARK_TYPE_VALUE;
1131 static void
1132 init_json_parser(void) {
1133 static tvbparse_wanted_t _want_object;
1134 static tvbparse_wanted_t _want_array;
1136 tvbparse_wanted_t *want_object, *want_array;
1137 tvbparse_wanted_t *want_member;
1138 tvbparse_wanted_t *want_string;
1139 tvbparse_wanted_t *want_number, *want_int;
1140 tvbparse_wanted_t *want_value;
1141 tvbparse_wanted_t *want_value_separator;
1143 #define tvbparse_optional(id, private_data, before_cb, after_cb, wanted) \
1144 tvbparse_some(id, 0, 1, private_data, before_cb, after_cb, wanted)
1146 tvbparse_wanted_t *want_quot = tvbparse_char(-1,"\"",NULL,NULL,NULL);
1148 want_string = tvbparse_set_seq(JSON_TOKEN_STRING, NULL, NULL, NULL,
1149 want_quot,
1150 tvbparse_some(-1, 0, INT_MAX, NULL, NULL, NULL,
1151 tvbparse_set_oneof(-1, NULL, NULL, NULL,
1152 tvbparse_not_chars(-1, 0, 0, "\"" "\\", NULL, NULL, NULL), /* XXX, without invalid unicode characters */
1153 tvbparse_set_seq(-1, NULL, NULL, NULL,
1154 tvbparse_char(-1, "\\", NULL, NULL, NULL),
1155 tvbparse_set_oneof(-1, NULL, NULL, NULL,
1156 tvbparse_chars(-1, 0, 1, "\"" "\\" "/bfnrt", NULL, NULL, NULL),
1157 tvbparse_set_seq(-1, NULL, NULL, NULL,
1158 tvbparse_char(-1, "u", NULL, NULL, NULL),
1159 tvbparse_chars(-1, 4, 4, "0123456789abcdefABCDEF", NULL, NULL, NULL),
1160 NULL),
1161 NULL),
1162 NULL),
1163 NULL)
1165 want_quot,
1166 NULL);
1168 want_value_separator = tvbparse_char(-1, ",", NULL, NULL, NULL);
1170 /* int = zero / ( digit1-9 *DIGIT ) */
1171 want_int = tvbparse_set_oneof(-1, NULL, NULL, NULL,
1172 tvbparse_char(-1, "0", NULL, NULL, NULL),
1173 tvbparse_set_seq(-1, NULL, NULL, NULL,
1174 tvbparse_chars(-1, 1, 1, "123456789", NULL, NULL, NULL),
1175 tvbparse_optional(-1, NULL, NULL, NULL, /* tvbparse_chars() don't respect 0 as min_len ;/ */
1176 tvbparse_chars(-1, 0, 0, "0123456789", NULL, NULL, NULL)),
1177 NULL),
1178 NULL);
1180 /* number = [ minus ] int [ frac ] [ exp ] */
1181 want_number = tvbparse_set_seq(JSON_TOKEN_NUMBER, NULL, NULL, NULL,
1182 tvbparse_optional(-1, NULL, NULL, NULL, /* tvbparse_chars() don't respect 0 as min_len ;/ */
1183 tvbparse_chars(-1, 0, 1, "-", NULL, NULL, NULL)),
1184 want_int,
1185 /* frac = decimal-point 1*DIGIT */
1186 tvbparse_optional(-1, NULL, NULL, NULL,
1187 tvbparse_set_seq(-1, NULL, NULL, NULL,
1188 tvbparse_char(-1, ".", NULL, NULL, NULL),
1189 tvbparse_chars(-1, 1, 0, "0123456789", NULL, NULL, NULL),
1190 NULL)),
1191 /* exp = e [ minus / plus ] 1*DIGIT */
1192 tvbparse_optional(-1, NULL, NULL, NULL,
1193 tvbparse_set_seq(-1, NULL, NULL, NULL,
1194 tvbparse_char(-1, "eE", NULL, NULL, NULL),
1195 tvbparse_optional(-1, NULL, NULL, NULL, /* tvbparse_chars() don't respect 0 as min_len ;/ */
1196 tvbparse_chars(-1, 0, 1, "-+", NULL, NULL, NULL)),
1197 tvbparse_chars(-1, 1, 0, "0123456789", NULL, NULL, NULL),
1198 NULL)),
1199 NULL);
1201 /* value = false / null / true / object / array / number / string */
1202 want_value = tvbparse_set_oneof(-1, NULL, NULL, after_value,
1203 tvbparse_string(JSON_TOKEN_FALSE, "false", NULL, NULL, NULL),
1204 tvbparse_string(JSON_TOKEN_NULL, "null", NULL, NULL, NULL),
1205 tvbparse_string(JSON_TOKEN_TRUE, "true", NULL, NULL, NULL),
1206 tvbparse_string(JSON_TOKEN_NAN, "NaN", NULL, NULL, NULL),
1207 &_want_object,
1208 &_want_array,
1209 want_number,
1210 want_string,
1211 NULL);
1213 /* array = begin-array [ value *( value-separator value ) ] end-array */
1214 want_array = tvbparse_set_seq(JSON_ARRAY, NULL, before_array, after_array,
1215 tvbparse_char(-1, "[", NULL, NULL, NULL),
1216 tvbparse_optional(-1, NULL, NULL, NULL,
1217 tvbparse_set_seq(-1, NULL, NULL, NULL,
1218 want_value,
1219 tvbparse_some(-1, 0, INT_MAX, NULL, NULL, NULL,
1220 tvbparse_set_seq(-1, NULL, NULL, NULL,
1221 want_value_separator,
1222 want_value,
1223 NULL)),
1224 NULL)
1226 tvbparse_char(-1, "]", NULL, NULL, NULL),
1227 NULL);
1228 _want_array = *want_array;
1230 /* member = string name-separator value */
1231 want_member = tvbparse_set_seq(-1, NULL, before_member, after_member,
1232 want_string,
1233 tvbparse_char(-1, ":", NULL, NULL, NULL),
1234 want_value,
1235 NULL);
1237 /* object = begin-object [ member *( value-separator member ) ] end-object */
1238 want_object = tvbparse_set_seq(JSON_OBJECT, NULL, before_object, after_object,
1239 tvbparse_char(-1, "{", NULL, NULL, NULL),
1240 tvbparse_optional(-1, NULL, NULL, NULL,
1241 tvbparse_set_seq(-1, NULL, NULL, NULL,
1242 want_member,
1243 tvbparse_some(-1, 0, INT_MAX, NULL, NULL, NULL,
1244 tvbparse_set_seq(-1, NULL, NULL, NULL,
1245 want_value_separator,
1246 want_member,
1247 NULL)),
1248 NULL)
1250 tvbparse_char(-1, "}", NULL, NULL, NULL),
1251 NULL);
1252 _want_object = *want_object;
1254 want_ignore = tvbparse_chars(-1, 1, 0, " \t\r\n", NULL, NULL, NULL);
1256 /* JSON-text = object / array */
1257 want = tvbparse_set_oneof(-1, NULL, NULL, NULL,
1258 want_object,
1259 want_array,
1260 /* tvbparse_not_chars(-1, 1, 0, " \t\r\n", NULL, NULL, NULL), */
1261 NULL);
1263 /* XXX, heur? */
1266 /* This function tries to understand if the payload is json or not */
1267 static bool
1268 dissect_json_heur(tvbuff_t *tvb, packet_info *pinfo, proto_tree *tree, void *data)
1270 unsigned len = tvb_captured_length(tvb);
1271 const uint8_t* buf = tvb_get_string_enc(pinfo->pool, tvb, 0, len, ENC_ASCII);
1273 if (json_validate(buf, len) == false)
1274 return false;
1276 return (dissect_json(tvb, pinfo, tree, data) != 0);
1279 /* This function tries to understand if the payload is sitting on top of AC DR */
1280 static bool
1281 dissect_json_acdr_heur(tvbuff_t *tvb, packet_info *pinfo, proto_tree *tree, void *data)
1283 unsigned acdr_prot = GPOINTER_TO_UINT(p_get_proto_data(pinfo->pool, pinfo, proto_acdr, 0));
1284 if (acdr_prot == ACDR_VoiceAI)
1285 return dissect_json_heur(tvb, pinfo, tree, data);
1286 return false;
1289 static void
1290 register_static_headers(void) {
1292 json_header_fields_hash = g_hash_table_new_full(g_str_hash, g_str_equal, g_free, g_free);
1296 void
1297 proto_register_json(void)
1299 static hf_register_info hf[] = {
1300 { &hf_json_array,
1301 { "Array", "json.array",
1302 FT_NONE, BASE_NONE, NULL, 0x00,
1303 "JSON array", HFILL }
1305 { &hf_json_object,
1306 { "Object", "json.object",
1307 FT_STRING, BASE_NONE|BASE_NO_DISPLAY_VALUE, NULL, 0x00,
1308 "JSON object", HFILL }
1310 { &hf_json_member,
1311 { "Member", "json.member",
1312 FT_STRING, BASE_NONE, NULL, 0x00,
1313 "JSON object member", HFILL }
1315 { &hf_json_key,
1316 { "Key", "json.key",
1317 FT_STRING, BASE_NONE, NULL, 0x00,
1318 NULL, HFILL }
1320 { &hf_json_path,
1321 { "Path", "json.path",
1322 FT_STRING, BASE_NONE, NULL, 0x00,
1323 NULL, HFILL }
1325 { &hf_json_path_with_value,
1326 { "Path with value", "json.path_with_value",
1327 FT_STRING, BASE_NONE, NULL, 0x00,
1328 NULL, HFILL }
1330 { &hf_json_member_with_value,
1331 { "Member with value", "json.member_with_value",
1332 FT_STRING, BASE_NONE, NULL, 0x00,
1333 NULL, HFILL }
1335 { &hf_json_value_string,
1336 { /* FT_STRINGZ? */ "String value", "json.value.string",
1337 FT_STRING, BASE_NONE, NULL, 0x00,
1338 "JSON string value", HFILL }
1340 { &hf_json_value_number,
1341 { "Number value", "json.value.number",
1342 FT_DOUBLE, BASE_NONE, NULL, 0x00,
1343 "JSON number value", HFILL }
1345 { &hf_json_value_false,
1346 { "False value", "json.value.false",
1347 FT_NONE, BASE_NONE, NULL, 0x00,
1348 "JSON false value", HFILL }
1350 { &hf_json_value_null,
1351 { "Null value", "json.value.null",
1352 FT_NONE, BASE_NONE, NULL, 0x00,
1353 "JSON null value", HFILL }
1355 { &hf_json_value_true,
1356 { "True value", "json.value.true",
1357 FT_NONE, BASE_NONE, NULL, 0x00,
1358 "JSON true value", HFILL }
1360 { &hf_json_value_nan,
1361 { "NaN value", "json.value.nan",
1362 FT_NONE, BASE_NONE, NULL, 0x00,
1363 "JSON NaN value", HFILL }
1365 { &hf_json_array_compact,
1366 { "Array compact", "json.array_compact",
1367 FT_NONE, BASE_NONE, NULL, 0x00,
1368 "JSON array compact", HFILL }
1370 { &hf_json_object_compact,
1371 { "Object compact", "json.object_compact",
1372 FT_NONE, BASE_NONE, NULL, 0x00,
1373 "JSON object compact", HFILL }
1375 { &hf_json_member_compact,
1376 { "Member compact", "json.member_compact",
1377 FT_NONE, BASE_NONE, NULL, 0x00,
1378 "JSON member compact", HFILL }
1380 { &hf_json_array_item_compact,
1381 { "Array item compact", "json.array_item_compact",
1382 FT_NONE, BASE_NONE, NULL, 0x00,
1383 "JSON array item compact", HFILL }
1385 { &hf_json_binary_data,
1386 { "Binary data", "json.binary_data",
1387 FT_BYTES, BASE_NONE, NULL, 0x00,
1388 "JSON binary data", HFILL }
1390 { &hf_json_ignored_leading_bytes,
1391 { "Ignored leading bytes", "json.ignored_leading_bytes",
1392 FT_STRING, BASE_NONE, NULL, 0x00,
1393 NULL, HFILL }
1395 { &hf_json_array_raw,
1396 { "Array raw", "json.array_raw",
1397 FT_NONE, BASE_NONE, NULL, 0x00,
1398 "JSON array raw", HFILL }
1400 { &hf_json_object_raw,
1401 { "Object raw", "json.object_raw",
1402 FT_NONE, BASE_NONE, NULL, 0x00,
1403 "JSON object raw", HFILL }
1405 { &hf_json_member_raw,
1406 { "Member raw", "json.member_raw",
1407 FT_NONE, BASE_NONE, NULL, 0x00,
1408 "JSON member raw", HFILL }
1410 { &hf_json_array_item_raw,
1411 { "Array item raw", "json.array_item_raw",
1412 FT_NONE, BASE_NONE, NULL, 0x00,
1413 "JSON array item raw", HFILL }
1418 static int *ett[] = {
1419 &ett_json,
1420 &ett_json_array,
1421 &ett_json_object,
1422 &ett_json_member,
1423 &ett_json_compact,
1424 &ett_json_array_compact,
1425 &ett_json_object_compact,
1426 &ett_json_member_compact,
1427 &ett_json_raw,
1428 &ett_json_array_raw,
1429 &ett_json_object_raw,
1430 &ett_json_member_raw,
1433 module_t *json_module;
1435 proto_json = proto_register_protocol("JavaScript Object Notation", "JSON", "json");
1436 proto_register_field_array(proto_json, hf, array_length(hf));
1437 proto_register_subtree_array(ett, array_length(ett));
1439 json_handle = register_dissector("json", dissect_json, proto_json);
1440 json_file_handle = register_dissector("json_file", dissect_json_file, proto_json);
1442 init_json_parser();
1444 json_module = prefs_register_protocol(proto_json, NULL);
1445 prefs_register_bool_preference(json_module, "compact_form",
1446 "Display JSON in compact form",
1447 "Display JSON like in browsers devtool",
1448 &json_compact);
1450 prefs_register_bool_preference(json_module, "raw_form",
1451 "Display JSON in raw form",
1452 "Display JSON like in vscode editor",
1453 &json_raw);
1455 prefs_register_bool_preference(json_module, "auto_hide",
1456 "Hide tree or root item automatically",
1457 "Determine whether to hide the tree of original form or root item of compact or raw form"
1458 " based on the enabled status of compact_form and raw_form preferences.",
1459 &auto_hide);
1461 prefs_register_bool_preference(json_module, "ignore_leading_bytes",
1462 "Ignore leading non JSON bytes",
1463 "Leading bytes will be ignored until first '[' or '{' is found.",
1464 &ignore_leading_bytes);
1466 prefs_register_bool_preference(json_module, "hide_extended_path_based_filtering",
1467 "Hide extended path based filtering",
1468 "Hide extended path based filtering",
1469 &hide_extended_path_based_filtering);
1471 prefs_register_bool_preference(json_module, "unescape_strings",
1472 "Replace character escapes with the escaped literal value",
1473 "Replace character escapes with the escaped literal value",
1474 &unescape_strings);
1476 /* Fill hash table with static headers */
1477 register_static_headers();
1480 void
1481 proto_reg_handoff_json(void)
1483 heur_dissector_add("hpfeeds", dissect_json_heur, "JSON over HPFEEDS", "json_hpfeeds", proto_json, HEURISTIC_ENABLE);
1484 heur_dissector_add("db-lsp", dissect_json_heur, "JSON over DB-LSP", "json_db_lsp", proto_json, HEURISTIC_ENABLE);
1485 heur_dissector_add("udp", dissect_json_acdr_heur, "JSON over AC DR", "json_acdr", proto_json, HEURISTIC_ENABLE);
1486 dissector_add_uint("wtap_encap", WTAP_ENCAP_JSON, json_file_handle);
1488 dissector_add_for_decode_as("udp.port", json_file_handle);
1490 dissector_add_string("media_type", "application/json", json_handle); /* RFC 4627 */
1491 dissector_add_string("media_type", "application/senml+json", json_handle); /* RFC 8428 */
1492 dissector_add_string("media_type", "application/sensml+json", json_handle); /* RFC 8428 */
1493 dissector_add_string("media_type", "application/json-rpc", json_handle); /* JSON-RPC over HTTP */
1494 dissector_add_string("media_type", "application/jsonrequest", json_handle); /* JSON-RPC over HTTP */
1495 dissector_add_string("media_type", "application/dds-web+json", json_handle); /* DDS Web Integration Service over HTTP */
1496 dissector_add_string("media_type", "application/vnd.oma.lwm2m+json", json_handle); /* LWM2M JSON over CoAP */
1497 dissector_add_string("media_type", "application/problem+json", json_handle); /* RFC 7807 Problem Details for HTTP APIs*/
1498 dissector_add_string("media_type", "application/merge-patch+json", json_handle); /* RFC 7386 HTTP PATCH methods (RFC 5789) */
1499 dissector_add_string("media_type", "application/json-patch+json", json_handle); /* RFC 6902 JavaScript Object Notation (JSON) Patch */
1500 dissector_add_string("media_type", "application/x-ndjson", json_handle);
1501 dissector_add_string("media_type", "application/3gppHal+json", json_handle);
1502 dissector_add_string("media_type.suffix", "json", json_handle); /* RFC 6839 */
1503 dissector_add_string("grpc_message_type", "application/grpc+json", json_handle);
1504 dissector_add_uint_range_with_preference("tcp.port", "", json_file_handle); /* JSON-RPC over TCP */
1505 dissector_add_uint_range_with_preference("udp.port", "", json_file_handle); /* JSON-RPC over UDP */
1507 text_lines_handle = find_dissector_add_dependency("data-text-lines", proto_json);
1509 proto_acdr = proto_get_id_by_filter_name("acdr");
1513 * Editor modelines - https://www.wireshark.org/tools/modelines.html
1515 * Local variables:
1516 * c-basic-offset: 8
1517 * tab-width: 8
1518 * indent-tabs-mode: t
1519 * End:
1521 * vi: set shiftwidth=8 tabstop=8 noexpandtab:
1522 * :indentSize=8:tabSize=8:noTabs=false: