2 * Routines for JSON dissection
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
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
;
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
;
84 static bool json_compact
;
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
;
109 JSON_TOKEN_INVALID
= -1,
110 JSON_TOKEN_NUMBER
= 0,
117 /* not really tokens ... */
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
,
135 wmem_stack_t
*stack_compact
; /* Used for compact json form only */
136 wmem_stack_t
*array_idx
; /* Used for compact json form only.
139 Array -1: no key, -2: has key */
140 wmem_stack_t
* stack_path
;
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)))
162 json_array_index_increment(json_parser_data_t
*data
)
164 int idx
= GPOINTER_TO_INT(wmem_stack_pop(data
->array_idx
));
166 wmem_stack_push(data
->array_idx
, GINT_TO_POINTER(idx
));
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
));
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
);
186 // Do not overflow input string
187 if (!(read_index
< string_length
))
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)
206 for (int i
= 0; i
< utf8_character_length
; i
++)
208 // Do not overflow input string
209 if (!(read_index
< string_length
))
214 current_character
= string
[read_index
];
216 wmem_strbuf_append_c(output_string_buffer
, current_character
);
219 // character that IS escaped
224 // Do not overflow input string
225 if (!(read_index
< string_length
))
230 current_character
= string
[read_index
];
232 if (current_character
== '\"' || current_character
== '\\' || current_character
== '/')
235 wmem_strbuf_append_c(output_string_buffer
, current_character
);
237 else if (current_character
== 'b')
240 wmem_strbuf_append_c(output_string_buffer
, '\b');
242 else if (current_character
== 'f')
245 wmem_strbuf_append_c(output_string_buffer
, '\f');
247 else if (current_character
== 'n')
250 wmem_strbuf_append_c(output_string_buffer
, '\n');
252 else if (current_character
== 'r')
255 wmem_strbuf_append_c(output_string_buffer
, '\r');
257 else if (current_character
== 't')
260 wmem_strbuf_append_c(output_string_buffer
, '\t');
262 else if (current_character
== 'u')
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;
278 current_character
= string
[read_index
];
281 int nibble
= ws_xton(current_character
);
285 is_valid_unicode_character
= false;
290 code_point
|= nibble
;
293 if ((IS_LEAD_SURROGATE(code_point
)))
295 // Do not overflow input string
296 if (!(read_index
< string_length
))
300 current_character
= string
[read_index
];
302 if (current_character
== '\\')
306 // Do not overflow input string
307 if (!(read_index
< string_length
))
312 current_character
= string
[read_index
];
313 if (current_character
== 'u') {
314 uint16_t lead_surrogate
= code_point
;
315 uint16_t trail_surrogate
= 0;
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;
328 current_character
= string
[read_index
];
331 int nibble
= ws_xton(current_character
);
335 is_valid_unicode_character
= false;
339 trail_surrogate
<<= 4;
340 trail_surrogate
|= nibble
;
343 if ((IS_TRAIL_SURROGATE(trail_surrogate
)))
345 code_point
= SURROGATE_VALUE(lead_surrogate
, trail_surrogate
);
349 is_valid_unicode_character
= false;
355 is_valid_unicode_character
= false;
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
);
386 wmem_strbuf_append_unichar_repl(output_string_buffer
);
391 /* not valid by JSON grammar (tvbparse rules should not allow it) */
392 DISSECTOR_ASSERT_NOT_REACHED();
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. */
406 get_json_string(wmem_allocator_t
*scope
, tvbparse_elem_t
*tok
, bool remove_quotes
)
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
);
417 length
= strlen(string
);
421 if (string
[length
- 1] == '"') {
422 string
[length
- 1] = '\0';
424 if (string
[0] == '"') {
432 GHashTable
* json_header_fields_hash
;
435 json_key_lookup(proto_tree
* tree
, tvbparse_elem_t
* tok
, const char* key_str
, packet_info
* pinfo
, bool use_compact
)
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
) {
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
))) {
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
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
;
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) {
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
);
503 join_strings(wmem_allocator_t
*pool
, const char* string_a
, const char* string_b
, char separator
)
505 if (string_a
== NULL
)
509 if (string_b
== 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
;
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
;
536 media_content_info_t
*content_info
;
537 const char *data_name
;
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
));
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");
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
570 data_name
= content_info
->media_str
;
571 if (! (data_name
&& data_name
[0])) {
573 * No information from dissector data
581 ti
= proto_tree_add_item(tree
, proto_json
, tvb
, 0, -1, ENC_NA
);
582 json_tree
= proto_item_add_subtree(ti
, ett_json
);
585 proto_item_append_text(ti
, ": %s", data_name
);
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
== '{')
615 proto_tree_add_item(json_tree
? json_tree
: tree
, hf_json_ignored_leading_bytes
, tvb
, 0, offset
, ENC_ASCII
);
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 */
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) {
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.
669 dissect_json_file(tvbuff_t
*tvb
, packet_info
*pinfo
, proto_tree
*tree
, void* data _U_
)
671 return dissect_json(tvb
, pinfo
, tree
, NULL
);
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
);
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
);
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
);
702 subtree_compact
= tree_compact
;
704 wmem_stack_push(data
->stack_compact
, subtree_compact
);
706 JSON_OBJECT_BEGIN(data
);
710 proto_tree
* tree_raw
= (proto_tree
*)wmem_stack_peek(data
->stack_raw
);
711 proto_tree
* subtree_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
, " {");
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
;
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
);
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
, " {...}");
750 proto_item_append_text(parent_item
, " {}");
752 wmem_stack_pop(data
->stack_compact
);
754 JSON_ARRAY_OBJECT_END(data
);
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
);
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
, "}");
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
;
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
);
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
);
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);
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
);
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
);
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);
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
);
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
;
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
);
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
);
876 wmem_stack_pop(data
->stack_compact
);
877 json_object_add_key(data
);
881 wmem_stack_pop(data
->stack_raw
);
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
);
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
, "[]");
913 json_key_lookup(tree
, tok
, last_key_string
, data
->pinfo
, false);
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
);
927 subtree_compact
= tree_compact
;
929 wmem_stack_push(data
->stack_compact
, subtree_compact
);
931 JSON_ARRAY_BEGIN(data
);
935 proto_tree
* tree_raw
= (proto_tree
*)wmem_stack_peek(data
->stack_raw
);
936 proto_tree
* subtree_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
, " [");
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
;
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
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
));
976 proto_item_append_text(parent_item
, " []");
978 proto_item_append_text(parent_item
, " [...]");
980 wmem_stack_pop(data
->stack_compact
);
982 JSON_ARRAY_OBJECT_END(data
);
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
);
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
, "]");
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
;
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
))
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);
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
);
1048 case JSON_TOKEN_STRING
:
1049 if (tok
->len
>= 2) {
1051 proto_item
*key_lookup
= NULL
;
1052 key_lookup
= json_key_lookup(tree
, tok
, key_string
, data
->pinfo
, false);
1054 proto_tree_add_string(tree
, hf_json_value_string
, tok
->tvb
, tok
->offset
, tok
->len
, value_str
);
1059 proto_tree_add_item(tree
, hf_json_value_string
, tok
->tvb
, tok
->offset
, tok
->len
, ENC_ASCII
| ENC_NA
);
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
));
1069 case JSON_TOKEN_FALSE
:
1070 proto_tree_add_item(tree
, hf_json_value_false
, tok
->tvb
, tok
->offset
, tok
->len
, ENC_NA
);
1074 case JSON_TOKEN_NULL
:
1075 proto_tree_add_item(tree
, hf_json_value_null
, tok
->tvb
, tok
->offset
, tok
->len
, ENC_NA
);
1079 case JSON_TOKEN_TRUE
:
1080 proto_tree_add_item(tree
, hf_json_value_true
, tok
->tvb
, tok
->offset
, tok
->len
, ENC_NA
);
1084 case JSON_TOKEN_NAN
:
1085 proto_tree_add_item(tree
, hf_json_value_nan
, tok
->tvb
, tok
->offset
, tok
->len
, ENC_NA
);
1090 proto_tree_add_format_text(tree
, tok
->tvb
, tok
->offset
, tok
->len
);
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
);
1105 proto_item
*parent_item
= proto_tree_get_parent(tree_compact
);
1106 proto_item_append_text(parent_item
, " %s", val_str
);
1111 proto_tree
* tree_raw
= (proto_tree
*)wmem_stack_peek(data
->stack_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
);
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
;
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
,
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
),
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
)),
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
)),
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
),
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
),
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
),
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
,
1219 tvbparse_some(-1, 0, INT_MAX
, NULL
, NULL
, NULL
,
1220 tvbparse_set_seq(-1, NULL
, NULL
, NULL
,
1221 want_value_separator
,
1226 tvbparse_char(-1, "]", NULL
, NULL
, NULL
),
1228 _want_array
= *want_array
;
1230 /* member = string name-separator value */
1231 want_member
= tvbparse_set_seq(-1, NULL
, before_member
, after_member
,
1233 tvbparse_char(-1, ":", NULL
, NULL
, 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
,
1243 tvbparse_some(-1, 0, INT_MAX
, NULL
, NULL
, NULL
,
1244 tvbparse_set_seq(-1, NULL
, NULL
, NULL
,
1245 want_value_separator
,
1250 tvbparse_char(-1, "}", NULL
, NULL
, 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
,
1260 /* tvbparse_not_chars(-1, 1, 0, " \t\r\n", NULL, NULL, NULL), */
1266 /* This function tries to understand if the payload is json or not */
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)
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 */
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
);
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
);
1297 proto_register_json(void)
1299 static hf_register_info hf
[] = {
1301 { "Array", "json.array",
1302 FT_NONE
, BASE_NONE
, NULL
, 0x00,
1303 "JSON array", HFILL
}
1306 { "Object", "json.object",
1307 FT_STRING
, BASE_NONE
|BASE_NO_DISPLAY_VALUE
, NULL
, 0x00,
1308 "JSON object", HFILL
}
1311 { "Member", "json.member",
1312 FT_STRING
, BASE_NONE
, NULL
, 0x00,
1313 "JSON object member", HFILL
}
1316 { "Key", "json.key",
1317 FT_STRING
, BASE_NONE
, NULL
, 0x00,
1321 { "Path", "json.path",
1322 FT_STRING
, BASE_NONE
, NULL
, 0x00,
1325 { &hf_json_path_with_value
,
1326 { "Path with value", "json.path_with_value",
1327 FT_STRING
, BASE_NONE
, NULL
, 0x00,
1330 { &hf_json_member_with_value
,
1331 { "Member with value", "json.member_with_value",
1332 FT_STRING
, BASE_NONE
, NULL
, 0x00,
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,
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
[] = {
1424 &ett_json_array_compact
,
1425 &ett_json_object_compact
,
1426 &ett_json_member_compact
,
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
);
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",
1450 prefs_register_bool_preference(json_module
, "raw_form",
1451 "Display JSON in raw form",
1452 "Display JSON like in vscode editor",
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.",
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",
1476 /* Fill hash table with static headers */
1477 register_static_headers();
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
1518 * indent-tabs-mode: t
1521 * vi: set shiftwidth=8 tabstop=8 noexpandtab:
1522 * :indentSize=8:tabSize=8:noTabs=false: