diff options
Diffstat (limited to 'epan/dissectors/packet-json.c')
-rw-r--r-- | epan/dissectors/packet-json.c | 868 |
1 files changed, 484 insertions, 384 deletions
diff --git a/epan/dissectors/packet-json.c b/epan/dissectors/packet-json.c index cc9670889e..4c2ed41fe5 100644 --- a/epan/dissectors/packet-json.c +++ b/epan/dissectors/packet-json.c @@ -12,9 +12,6 @@ * * SPDX-License-Identifier: GPL-2.0-or-later */ - -#define NEW_PROTO_TREE_API - #include "config.h" #include <epan/packet.h> @@ -27,135 +24,82 @@ #include <wiretap/wtap.h> -#include "packet-http.h" +#include "packet-media-type.h" #include "packet-acdr.h" -#include "packet-gtpv2.h" +#include "packet-json.h" void proto_register_json(void); void proto_reg_handoff_json(void); -static char* json_string_unescape(tvbparse_elem_t *tok, gboolean enclose_in_quotation_marks); - +static char* json_string_unescape(wmem_allocator_t *scope, const char *string, size_t *length_ptr); +static const char* get_json_string(wmem_allocator_t *scope, tvbparse_elem_t *tok, gboolean remove_quotes); static dissector_handle_t json_handle; +static dissector_handle_t json_file_handle; -static int proto_json = -1; -static int proto_json_3gpp = -1; +static int proto_json; //Used to get AC DR proto data -static int proto_acdr = -1; - -static gint ett_json = -1; -static gint ett_json_array = -1; -static gint ett_json_object = -1; -static gint ett_json_member = -1; +static int proto_acdr; + +static int hf_json_array; +static int hf_json_array_compact; +static int hf_json_array_item_compact; +static int hf_json_array_raw; +static int hf_json_array_item_raw; +static int hf_json_binary_data; +static int hf_json_ignored_leading_bytes; +static int hf_json_key; +static int hf_json_member; +static int hf_json_member_compact; +static int hf_json_member_raw; +static int hf_json_member_with_value; +static int hf_json_object; +static int hf_json_object_compact; +static int hf_json_object_raw; +static int hf_json_path; +static int hf_json_path_with_value; +static int hf_json_value_false; +static int hf_json_value_nan; +static int hf_json_value_null; +static int hf_json_value_number; +static int hf_json_value_string; +static int hf_json_value_true; + +static gint ett_json; +static gint ett_json_array; +static gint ett_json_object; +static gint ett_json_member; /* Define the trees for json compact form */ -static gint ett_json_compact = -1; -static gint ett_json_array_compact = -1; -static gint ett_json_object_compact = -1; -static gint ett_json_member_compact = -1; -static gint ett_json_base64decoded_eps_ie = -1; - -static header_field_info *hfi_json = NULL; - -#define JSON_HFI_INIT HFI_INIT(proto_json) - -static header_field_info hfi_json_array JSON_HFI_INIT = - { "Array", "json.array", FT_NONE, BASE_NONE, NULL, 0x00, "JSON array", HFILL }; - -static header_field_info hfi_json_object JSON_HFI_INIT = - { "Object", "json.object", FT_NONE, BASE_NONE, NULL, 0x00, "JSON object", HFILL }; - -static header_field_info hfi_json_member JSON_HFI_INIT = - { "Member", "json.member", FT_STRING, STR_UNICODE, NULL, 0x00, "JSON object member", HFILL }; - -static header_field_info hfi_json_key JSON_HFI_INIT = - { "Key", "json.key", FT_STRING, STR_UNICODE, NULL, 0x00, NULL, HFILL }; - -static header_field_info hfi_json_path JSON_HFI_INIT = - { "Path", "json.path", FT_STRING, STR_UNICODE, NULL, 0x00, NULL, HFILL }; - -static header_field_info hfi_json_path_with_value JSON_HFI_INIT = - { "Path with value", "json.path_with_value", FT_STRING, STR_UNICODE, NULL, 0x00, NULL, HFILL }; - -static header_field_info hfi_json_member_with_value JSON_HFI_INIT = - { "Member with value", "json.member_with_value", FT_STRING, STR_UNICODE, NULL, 0x00, NULL, HFILL }; +static gint ett_json_compact; +static gint ett_json_array_compact; +static gint ett_json_object_compact; +static gint ett_json_member_compact; +/* Define the trees for json raw form */ +static gint ett_json_raw; +static gint ett_json_array_raw; +static gint ett_json_object_raw; +static gint ett_json_member_raw; -static header_field_info hfi_json_value_string JSON_HFI_INIT = /* FT_STRINGZ? */ - { "String value", "json.value.string", FT_STRING, STR_UNICODE, NULL, 0x00, "JSON string value", HFILL }; - -static header_field_info hfi_json_value_number JSON_HFI_INIT = /* FT_DOUBLE/ FT_INT64? */ - { "Number value", "json.value.number", FT_STRING, BASE_NONE, NULL, 0x00, "JSON number value", HFILL }; - -static header_field_info hfi_json_value_false JSON_HFI_INIT = - { "False value", "json.value.false", FT_NONE, BASE_NONE, NULL, 0x00, "JSON false value", HFILL }; - -static header_field_info hfi_json_value_null JSON_HFI_INIT = - { "Null value", "json.value.null", FT_NONE, BASE_NONE, NULL, 0x00, "JSON null value", HFILL }; - -static header_field_info hfi_json_value_true JSON_HFI_INIT = - { "True value", "json.value.true", FT_NONE, BASE_NONE, NULL, 0x00, "JSON true value", HFILL }; - -static header_field_info hfi_json_value_nan JSON_HFI_INIT = - { "NaN value", "json.value.nan", FT_NONE, BASE_NONE, NULL, 0x00, "JSON NaN value", HFILL }; - -/* HFIs below are used only for compact form display */ -static header_field_info hfi_json_array_compact JSON_HFI_INIT = - { "Array compact", "json.array_compact", FT_NONE, BASE_NONE, NULL, 0x00, "JSON array compact", HFILL }; - -static header_field_info hfi_json_object_compact JSON_HFI_INIT = - { "Object compact", "json.object_compact", FT_NONE, BASE_NONE, NULL, 0x00, "JSON object compact", HFILL }; - -static header_field_info hfi_json_member_compact JSON_HFI_INIT = - { "Member compact", "json.member_compact", FT_NONE, BASE_NONE, NULL, 0x00, "JSON member compact", HFILL }; - -static header_field_info hfi_json_array_item_compact JSON_HFI_INIT = - { "Array item compact", "json.array_item_compact", FT_NONE, BASE_NONE, NULL, 0x00, "JSON array item compact", HFILL }; - -static header_field_info hfi_json_binary_data JSON_HFI_INIT = - { "Binary data", "json.binary_data", FT_BYTES, BASE_NONE, NULL, 0x00, "JSON binary data", HFILL }; - -static header_field_info hfi_json_ignored_leading_bytes JSON_HFI_INIT = - { "Ignored leading bytes", "json.ignored_leading_bytes", FT_STRING, STR_UNICODE, NULL, 0x00, NULL, HFILL }; +/* Preferences */ +static gboolean json_compact = FALSE; -static int hf_json_3gpp_ueepspdnconnection = -1; -static int hf_json_3gpp_bearerlevelqos = -1; -static int hf_json_3gpp_epsbearersetup = -1; -static int hf_json_3gpp_forwardingbearercontexts = -1; -static int hf_json_3gpp_forwardingfteid = -1; -static int hf_json_3gpp_pgwnodename = -1; -static int hf_json_3gpp_pgws8cfteid = -1; -static int hf_json_3gpp_pgws8ufteid = -1; +static gboolean json_raw = FALSE; -/* json data decoding function XXXX only works for the compact form. - * Callback function to further dissect json data - * The first implementation is a 3GPP json element which carry an Base64 encoded GTPv2 IE - * https://www.etsi.org/deliver/etsi_ts/129500_129599/129502/15.01.00_60/ts_129502v150100p.pdf - */ -typedef void(*json_data_decoder_func)(tvbuff_t* tvb, proto_tree* tree, packet_info* pinfo, int offset, int len); - -/* Array of functions to dissect IEs -*/ -typedef struct _json_ie { - void(*json_data_decoder_func)(tvbuff_t* tvb, proto_tree* tree, packet_info* pinfo, int offset, int len); -} json_ie_t; - -/* A struct to hold the hf and callback function stored in a hastable with the json key as key. - * If the callback is null NULL the filter will be used useful to create filterable items in json. - * XXX Todo: Implement hte UAT from the http dissector to enable the users to create filters? and/or - * read config from file, similar to Diameter(filter only)? +/* Determine whether to hide the tree of original form or root item of compact or raw form + * based on the enabled status of compact_form and raw_form preferences. + * If the preference auto_hide is TRUE and compact_form or raw_form is TRUE, hide the tree of + * original form. If the preference auto_hide is TRUE and only one of preference of + * compact_form or raw_form is TRUE, then hide the root item of compact or raw form and put + * the content of compact or raw form under the tree item of JSON protocol directly. */ -typedef struct { - int *hf_id; - json_data_decoder_func json_data_decoder; -} json_data_decoder_t; - -/* Preferences */ -static gboolean json_compact = FALSE; +static gboolean auto_hide = FALSE; static gboolean ignore_leading_bytes = FALSE; static gboolean hide_extended_path_based_filtering = FALSE; +static gboolean unescape_strings = FALSE; + static tvbparse_wanted_t* want; static tvbparse_wanted_t* want_ignore; @@ -176,6 +120,16 @@ typedef enum { } json_token_type_t; +typedef enum { + JSON_MARK_TYPE_NONE = 0, + JSON_MARK_TYPE_BEGIN_OBJECT, + JSON_MARK_TYPE_END_OBJECT, + JSON_MARK_TYPE_BEGIN_ARRAY, + JSON_MARK_TYPE_END_ARRAY, + JSON_MARK_TYPE_MEMBER_NAME, + JSON_MARK_TYPE_VALUE +} json_mark_type_t; + typedef struct { wmem_stack_t *stack; wmem_stack_t *stack_compact; /* Used for compact json form only */ @@ -185,6 +139,9 @@ typedef struct { Array -1: no key, -2: has key */ wmem_stack_t* stack_path; packet_info* pinfo; + wmem_stack_t* stack_raw; /* Used for raw json form only */ + json_mark_type_t prev_item_type_raw; /* Used for raw json form only */ + proto_item* prev_item_raw; /* Used for raw json form only */ } json_parser_data_t; #define JSON_COMPACT_TOP_ITEM -3 @@ -198,6 +155,9 @@ typedef struct { #define JSON_INSIDE_ARRAY(idx) (idx >= JSON_COMPACT_ARRAY) #define JSON_OBJECT_SET_HAS_KEY(idx) (idx == JSON_COMPACT_OBJECT_WITH_KEY) +#define json_hide_original_tree() (auto_hide && (json_compact || json_raw)) +#define json_hide_root_item() (auto_hide && ((json_compact && !json_raw) || (!json_compact && json_raw))) + static void json_array_index_increment(json_parser_data_t *data) { @@ -214,31 +174,22 @@ json_object_add_key(json_parser_data_t *data) } static char* -json_string_unescape(tvbparse_elem_t* tok, gboolean enclose_in_quotation_marks) +json_string_unescape(wmem_allocator_t *scope, const char *string, size_t *length_ptr) { - int read_index = 0; + size_t read_index = 0; + size_t string_length = strlen(string); - wmem_strbuf_t* output_string_buffer = wmem_strbuf_sized_new(wmem_packet_scope(), tok->len, tok->len + 2); - - if (enclose_in_quotation_marks == TRUE) - { - wmem_strbuf_append_c(output_string_buffer, '\"'); - } + wmem_strbuf_t* output_string_buffer = wmem_strbuf_new_sized(scope, string_length); while (true) { - // Do not overflow TVB - if (!tvb_offset_exists(tok->tvb, tok->offset + read_index)) - { - break; - } // Do not overflow input string - if (!(read_index < tok->len)) + if (!(read_index < string_length)) { break; } - guint8 current_character = tvb_get_guint8(tok->tvb, tok->offset + read_index); + guint8 current_character = string[read_index]; // character that IS NOT escaped if (current_character != '\\') @@ -254,20 +205,13 @@ json_string_unescape(tvbparse_elem_t* tok, gboolean enclose_in_quotation_marks) for (int i = 0; i < utf8_character_length; i++) { - // If it is a character of length 1 these checks are redundant. - // But it avoids a seperate code path since this loop works for lengths from 1 to 6 - // Do not overflow TVB - if (!tvb_offset_exists(tok->tvb, tok->offset + read_index)) - { - break; - } // Do not overflow input string - if (!(read_index < tok->len )) + if (!(read_index < string_length)) { break; } - current_character = tvb_get_guint8(tok->tvb, tok->offset + read_index); + current_character = string[read_index]; read_index++; wmem_strbuf_append_c(output_string_buffer, current_character); } @@ -277,18 +221,13 @@ json_string_unescape(tvbparse_elem_t* tok, gboolean enclose_in_quotation_marks) { read_index++; - // Do not overflow TVB - if (!tvb_offset_exists(tok->tvb, tok->offset + read_index)) - { - break; - } // Do not overflow input string - if (!(read_index < tok->len)) + if (!(read_index < string_length)) { break; } - current_character = tvb_get_guint8(tok->tvb, tok->offset + read_index); + current_character = string[read_index]; if (current_character == '\"' || current_character == '\\' || current_character == '/') { @@ -329,20 +268,14 @@ json_string_unescape(tvbparse_elem_t* tok, gboolean enclose_in_quotation_marks) for (int i = 0; i < 4; i++) { - // Do not overflow TVB - if (!tvb_offset_exists(tok->tvb, tok->offset + read_index)) - { - is_valid_unicode_character = FALSE; - break; - } // Do not overflow input string - if (!(read_index < tok->len)) + if (!(read_index < string_length)) { is_valid_unicode_character = FALSE; break; } - current_character = tvb_get_guint8(tok->tvb, tok->offset + read_index); + current_character = string[read_index]; read_index++; int nibble = ws_xton(current_character); @@ -359,34 +292,24 @@ json_string_unescape(tvbparse_elem_t* tok, gboolean enclose_in_quotation_marks) if ((IS_LEAD_SURROGATE(code_point))) { - // Do not overflow TVB - if (!tvb_offset_exists(tok->tvb, tok->offset + read_index)) - { - break; - } // Do not overflow input string - if (!(read_index < tok->len)) + if (!(read_index < string_length)) { break; } - current_character = tvb_get_guint8(tok->tvb, tok->offset + read_index); + current_character = string[read_index]; if (current_character == '\\') { read_index++; - // Do not overflow TVB - if (!tvb_offset_exists(tok->tvb, tok->offset + read_index)) - { - break; - } // Do not overflow input string - if (!(read_index < tok->len)) + if (!(read_index < string_length)) { break; } - current_character = tvb_get_guint8(tok->tvb, tok->offset + read_index); + current_character = string[read_index]; if (current_character == 'u') { guint16 lead_surrogate = code_point; guint16 trail_surrogate = 0; @@ -395,20 +318,14 @@ json_string_unescape(tvbparse_elem_t* tok, gboolean enclose_in_quotation_marks) for (int i = 0; i < 4; i++) { - // Do not overflow TVB - if (!tvb_offset_exists(tok->tvb, tok->offset + read_index)) - { - is_valid_unicode_character = FALSE; - break; - } // Do not overflow input string - if (!(read_index < tok->len)) + if (!(read_index < string_length)) { is_valid_unicode_character = FALSE; break; } - current_character = tvb_get_guint8(tok->tvb, tok->offset + read_index); + current_character = string[read_index]; read_index++; int nibble = ws_xton(current_character); @@ -458,17 +375,6 @@ json_string_unescape(tvbparse_elem_t* tok, gboolean enclose_in_quotation_marks) for (int i = 0; i < utf8_character_length; i++) { - // Do not overflow TVB - if (!tvb_offset_exists(tok->tvb, tok->offset + read_index)) - { - break; - } - // Do not overflow input string - if (!(read_index < tok->len)) - { - break; - } - current_character = length_test_buffer[i]; wmem_strbuf_append_c(output_string_buffer, current_character); @@ -477,7 +383,7 @@ json_string_unescape(tvbparse_elem_t* tok, gboolean enclose_in_quotation_marks) } else { - wmem_strbuf_append_unichar(output_string_buffer, 0xFFFD); + wmem_strbuf_append_unichar_repl(output_string_buffer); } } else @@ -488,45 +394,67 @@ json_string_unescape(tvbparse_elem_t* tok, gboolean enclose_in_quotation_marks) } } - if (enclose_in_quotation_marks == TRUE) - { - wmem_strbuf_append_c(output_string_buffer, '\"'); + if (length_ptr) + *length_ptr = wmem_strbuf_get_len(output_string_buffer); + + return wmem_strbuf_finalize(output_string_buffer); +} + +/* This functions allocates memory with packet_scope but the returned pointer + * cannot be freed. */ +static const char* +get_json_string(wmem_allocator_t *scope, tvbparse_elem_t *tok, gboolean remove_quotes) +{ + char *string; + size_t length; + + string = tvb_get_string_enc(scope, tok->tvb, tok->offset, tok->len, ENC_UTF_8); + + if (unescape_strings) { + string = json_string_unescape(scope, string, &length); + } + else { + length = strlen(string); } - char* output_string = wmem_strbuf_finalize(output_string_buffer); + if (remove_quotes) { + if (string[length - 1] == '"') { + string[length - 1] = '\0'; + } + if (string[0] == '"') { + string += 1; + } + } - return output_string; + return string; } -static GHashTable* header_fields_hash = NULL; +GHashTable* json_header_fields_hash; static proto_item* -json_key_lookup(proto_tree* tree, tvbparse_elem_t* tok, char* key_str, packet_info* pinfo, gboolean use_compact) +json_key_lookup(proto_tree* tree, tvbparse_elem_t* tok, const char* key_str, packet_info* pinfo, gboolean use_compact) { proto_item* ti; int hf_id = -1; - header_field_info* hfi; - json_data_decoder_t* json_data_decoder_rec = (json_data_decoder_t*)g_hash_table_lookup(header_fields_hash, key_str); + json_data_decoder_t* json_data_decoder_rec = (json_data_decoder_t*)g_hash_table_lookup(json_header_fields_hash, key_str); if (json_data_decoder_rec == NULL) { return NULL; } hf_id = *json_data_decoder_rec->hf_id; - - hfi = proto_registrar_get_nth(hf_id); - DISSECTOR_ASSERT(hfi != NULL); + DISSECTOR_ASSERT(hf_id > 0); if (use_compact) { int str_len = (int)strlen(key_str); - ti = proto_tree_add_item(tree, hfi, tok->tvb, tok->offset + (4 + str_len), tok->len - (5 + str_len), ENC_NA); + ti = proto_tree_add_item(tree, hf_id, tok->tvb, tok->offset + (4 + str_len), tok->len - (5 + str_len), ENC_NA); if (json_data_decoder_rec->json_data_decoder) { - (*json_data_decoder_rec->json_data_decoder)(tok->tvb, tree, pinfo, tok->offset + (4 + str_len), tok->len - (5 + str_len)); + (*json_data_decoder_rec->json_data_decoder)(tok->tvb, tree, pinfo, tok->offset + (4 + str_len), tok->len - (5 + str_len), key_str, use_compact); } } else { - ti = proto_tree_add_item(tree, hfi, tok->tvb, tok->offset, tok->len, ENC_NA); + ti = proto_tree_add_item(tree, hf_id, tok->tvb, tok->offset, tok->len, ENC_NA); if (json_data_decoder_rec->json_data_decoder) { - (*json_data_decoder_rec->json_data_decoder)(tok->tvb, tree, pinfo, tok->offset, tok->len); + (*json_data_decoder_rec->json_data_decoder)(tok->tvb, tree, pinfo, tok->offset, tok->len, key_str, use_compact); } } return ti; @@ -534,7 +462,7 @@ json_key_lookup(proto_tree* tree, tvbparse_elem_t* tok, char* key_str, packet_in } static char* -join_strings(char* string_a, char* string_b, char separator) +join_strings(wmem_allocator_t *pool, const char* string_a, const char* string_b, char separator) { if (string_a == NULL) { @@ -545,7 +473,7 @@ join_strings(char* string_a, char* string_b, char separator) return NULL; } - wmem_strbuf_t* output_string_buffer = wmem_strbuf_new(wmem_packet_scope(), string_a); + wmem_strbuf_t* output_string_buffer = wmem_strbuf_new(pool, string_a); if (separator != '\0') { @@ -567,7 +495,7 @@ dissect_json(tvbuff_t *tvb, packet_info *pinfo, proto_tree *tree, void* data) json_parser_data_t parser_data; tvbparse_t *tt; - http_message_info_t *message_info; + media_content_info_t *content_info; const char *data_name; int offset; @@ -582,10 +510,10 @@ dissect_json(tvbuff_t *tvb, packet_info *pinfo, proto_tree *tree, void* data) if (strcmp(name, "frame")) { col_append_sep_str(pinfo->cinfo, COL_PROTOCOL, "/", "JSON"); - col_append_sep_str(pinfo->cinfo, COL_INFO, NULL, "JavaScript Object Notation"); + col_append_sep_str(pinfo->cinfo, COL_INFO, NULL, "JSON"); } else { col_set_str(pinfo->cinfo, COL_PROTOCOL, "JSON"); - col_set_str(pinfo->cinfo, COL_INFO, "JavaScript Object Notation"); + col_set_str(pinfo->cinfo, COL_INFO, "JSON"); } } @@ -594,14 +522,14 @@ dissect_json(tvbuff_t *tvb, packet_info *pinfo, proto_tree *tree, void* data) /* * No information from "match_string" */ - message_info = (http_message_info_t *)data; - if (message_info == NULL) { + content_info = (media_content_info_t *)data; + if (content_info == NULL) { /* * No information from dissector data */ data_name = NULL; } else { - data_name = message_info->media_str; + data_name = content_info->media_str; if (! (data_name && data_name[0])) { /* * No information from dissector data @@ -612,7 +540,7 @@ dissect_json(tvbuff_t *tvb, packet_info *pinfo, proto_tree *tree, void* data) } if (tree) { - ti = proto_tree_add_item(tree, hfi_json, tvb, 0, -1, ENC_NA); + ti = proto_tree_add_item(tree, proto_json, tvb, 0, -1, ENC_NA); json_tree = proto_item_add_subtree(ti, ett_json); if (data_name) @@ -623,11 +551,11 @@ dissect_json(tvbuff_t *tvb, packet_info *pinfo, proto_tree *tree, void* data) /* XXX*/ p_add_proto_data(pinfo->pool, pinfo, proto_json, 0, tvb); - parser_data.stack = wmem_stack_new(wmem_packet_scope()); + parser_data.stack = wmem_stack_new(pinfo->pool); wmem_stack_push(parser_data.stack, json_tree); // extended path based filtering - parser_data.stack_path = wmem_stack_new(wmem_packet_scope()); + parser_data.stack_path = wmem_stack_new(pinfo->pool); wmem_stack_push(parser_data.stack_path, ""); wmem_stack_push(parser_data.stack_path, ""); @@ -646,21 +574,32 @@ dissect_json(tvbuff_t *tvb, packet_info *pinfo, proto_tree *tree, void* data) if(offset > 0) { - proto_tree_add_item(json_tree ? json_tree : tree, &hfi_json_ignored_leading_bytes, tvb, 0, offset, ENC_NA); + proto_tree_add_item(json_tree ? json_tree : tree, hf_json_ignored_leading_bytes, tvb, 0, offset, ENC_ASCII); } } if (json_compact) { - proto_tree* json_tree_compact = NULL; - json_tree_compact = proto_tree_add_subtree(json_tree, tvb, 0, -1, ett_json_compact, NULL, "JSON compact form:"); + proto_tree* json_tree_compact = json_hide_root_item() ? json_tree : + proto_tree_add_subtree(json_tree, tvb, 0, -1, ett_json_compact, NULL, "JSON compact form:"); - parser_data.stack_compact = wmem_stack_new(wmem_packet_scope()); + parser_data.stack_compact = wmem_stack_new(pinfo->pool); wmem_stack_push(parser_data.stack_compact, json_tree_compact); - parser_data.array_idx = wmem_stack_new(wmem_packet_scope()); + parser_data.array_idx = wmem_stack_new(pinfo->pool); wmem_stack_push(parser_data.array_idx, GINT_TO_POINTER(JSON_COMPACT_TOP_ITEM)); /* top element */ } + if (json_raw) { + proto_tree* json_tree_raw = json_hide_root_item() ? json_tree : + proto_tree_add_subtree(json_tree, tvb, 0, -1, ett_json_raw, NULL, "JSON raw form:"); + + parser_data.stack_raw = wmem_stack_new(pinfo->pool); + wmem_stack_push(parser_data.stack_raw, json_tree_raw); + + parser_data.prev_item_raw = NULL; + parser_data.prev_item_type_raw = JSON_MARK_TYPE_NONE; + } + tt = tvbparse_init(pinfo->pool, tvb, offset, buffer_length - offset, &parser_data, want_ignore); /* XXX, only one json in packet? */ @@ -702,7 +641,10 @@ before_object(void *tvbparse_data, const void *wanted_data _U_, tvbparse_elem_t proto_tree *subtree; proto_item *ti; - ti = proto_tree_add_item(tree, &hfi_json_object, tok->tvb, tok->offset, tok->len, ENC_NA); + ti = proto_tree_add_item(tree, hf_json_object, tok->tvb, tok->offset, tok->len, ENC_UTF_8); + if (json_hide_original_tree() && wmem_stack_count(data->stack) == 1) { + proto_item_set_hidden(ti); + } subtree = proto_item_add_subtree(ti, ett_json_object); wmem_stack_push(data->stack, subtree); @@ -715,7 +657,7 @@ before_object(void *tvbparse_data, const void *wanted_data _U_, tvbparse_elem_t gint idx = GPOINTER_TO_INT(wmem_stack_peek(data->array_idx)); if (JSON_INSIDE_ARRAY(idx)) { - ti_compact = proto_tree_add_none_format(tree_compact, &hfi_json_object_compact, tok->tvb, tok->offset, tok->len, "%d:", idx); + ti_compact = proto_tree_add_none_format(tree_compact, hf_json_object_compact, tok->tvb, tok->offset, tok->len, "%d:", idx); subtree_compact = proto_item_add_subtree(ti_compact, ett_json_object_compact); json_array_index_increment(data); } else { @@ -725,10 +667,35 @@ before_object(void *tvbparse_data, const void *wanted_data _U_, tvbparse_elem_t JSON_OBJECT_BEGIN(data); } + + if (json_raw) { + proto_tree* tree_raw = (proto_tree*)wmem_stack_peek(data->stack_raw); + proto_tree* subtree_raw; + proto_item* ti_raw; + + if (data->prev_item_raw && data->prev_item_type_raw == JSON_MARK_TYPE_END_OBJECT) { + proto_item_append_text(data->prev_item_raw, ","); + } + + if (data->prev_item_type_raw == JSON_MARK_TYPE_MEMBER_NAME) { + /* this is an object value of an member, add the "{" just after the member name */ + ti_raw = data->prev_item_raw; + proto_item_append_text(ti_raw, " {"); + } else { + /* this object is either the top object or an element of an array, add the "{" as a single item */ + ti_raw = proto_tree_add_none_format(tree_raw, hf_json_object_raw, tok->tvb, tok->offset, tok->len, "{"); + } + + subtree_raw = proto_item_add_subtree(ti_raw, ett_json_object_raw); + wmem_stack_push(data->stack_raw, subtree_raw); + + data->prev_item_raw = ti_raw; + data->prev_item_type_raw = JSON_MARK_TYPE_BEGIN_OBJECT; + } } static void -after_object(void *tvbparse_data, const void *wanted_data _U_, tvbparse_elem_t *elem _U_) { +after_object(void *tvbparse_data, const void *wanted_data _U_, tvbparse_elem_t* tok) { json_parser_data_t *data = (json_parser_data_t *) tvbparse_data; wmem_stack_pop(data->stack); @@ -748,6 +715,23 @@ after_object(void *tvbparse_data, const void *wanted_data _U_, tvbparse_elem_t * JSON_ARRAY_OBJECT_END(data); } + + if (json_raw) { + proto_tree* tree_raw = (proto_tree*)wmem_stack_peek(data->stack_raw); + proto_tree* parent_tree = proto_tree_get_parent_tree(tree_raw); + proto_item* ti_raw; + if (data->prev_item_type_raw == JSON_MARK_TYPE_BEGIN_OBJECT) { /* an empty object */ + ti_raw = data->prev_item_raw; + proto_item_append_text(ti_raw, "}"); + } else { + tvbparse_elem_t* tok_last = tok->sub->last; + ti_raw = proto_tree_add_none_format(parent_tree, hf_json_object_raw, tok_last->tvb, tok_last->offset, tok_last->len, "}"); + } + wmem_stack_pop(data->stack_raw); + + data->prev_item_raw = ti_raw; + data->prev_item_type_raw = JSON_MARK_TYPE_END_OBJECT; + } } static void @@ -758,15 +742,9 @@ before_member(void *tvbparse_data, const void *wanted_data _U_, tvbparse_elem_t proto_tree *subtree; proto_item *ti; - // tvb parse element covers the qutation marks which we don't want - tvbparse_elem_t key_parse_element = tok->sub[0]; - key_parse_element.offset += 1; - key_parse_element.len -= 2; - char* key_string_without_quotation_marks = json_string_unescape(&key_parse_element, FALSE); + const char* key_string_without_quotation_marks = get_json_string(data->pinfo->pool, tok->sub, TRUE); - char* key_string_with_quotation_marks = json_string_unescape(tok->sub, FALSE); - - ti = proto_tree_add_string(tree, &hfi_json_member, tok->tvb, tok->offset, tok->len, key_string_without_quotation_marks); + ti = proto_tree_add_string(tree, hf_json_member, tok->tvb, tok->offset, tok->len, key_string_without_quotation_marks); subtree = proto_item_add_subtree(ti, ett_json_member); wmem_stack_push(data->stack, subtree); @@ -777,9 +755,10 @@ before_member(void *tvbparse_data, const void *wanted_data _U_, tvbparse_elem_t wmem_stack_push(data->stack_path, base_path); wmem_stack_push(data->stack_path, last_key_string); - char* path = join_strings(base_path, key_string_without_quotation_marks, '/'); + char* path = join_strings(data->pinfo->pool, base_path, key_string_without_quotation_marks, '/'); wmem_stack_push(data->stack_path, path); - wmem_stack_push(data->stack_path, key_string_without_quotation_marks); + /* stack won't write/free pointer. */ + wmem_stack_push(data->stack_path, (void *)key_string_without_quotation_marks); if (json_compact) { proto_tree *tree_compact = (proto_tree *)wmem_stack_peek(data->stack_compact); @@ -791,15 +770,41 @@ before_member(void *tvbparse_data, const void *wanted_data _U_, tvbparse_elem_t if (key_tok && key_tok->id == JSON_TOKEN_STRING) { ti_compact = json_key_lookup(tree_compact, tok, key_string_without_quotation_marks, data->pinfo, TRUE); if (!ti_compact) { - ti_compact = proto_tree_add_none_format(tree_compact, &hfi_json_member_compact, tok->tvb, tok->offset, tok->len, "%s:", key_string_with_quotation_marks); + 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); } } else { - ti_compact = proto_tree_add_item(tree_compact, &hfi_json_member_compact, tok->tvb, tok->offset, tok->len, ENC_NA); + ti_compact = proto_tree_add_item(tree_compact, hf_json_member_compact, tok->tvb, tok->offset, tok->len, ENC_NA); } subtree_compact = proto_item_add_subtree(ti_compact, ett_json_member_compact); wmem_stack_push(data->stack_compact, subtree_compact); } + + if (json_raw) { + proto_tree* tree_raw = (proto_tree*)wmem_stack_peek(data->stack_raw); + proto_tree* subtree_raw; + proto_item* ti_raw = NULL; + tvbparse_elem_t* key_tok = tok->sub; + + 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) { + proto_item_append_text(data->prev_item_raw, ","); + } + + if (key_tok && key_tok->id == JSON_TOKEN_STRING) { + ti_raw = json_key_lookup(tree_raw, tok, key_string_without_quotation_marks, data->pinfo, TRUE); + if (!ti_raw) { + 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); + } + } else { + ti_raw = proto_tree_add_item(tree_raw, hf_json_member_raw, tok->tvb, tok->offset, tok->len, ENC_NA); + } + + subtree_raw = proto_item_add_subtree(ti_raw, ett_json_member_raw); + wmem_stack_push(data->stack_raw, subtree_raw); + + data->prev_item_raw = ti_raw; + data->prev_item_type_raw = JSON_MARK_TYPE_MEMBER_NAME; + } } static void @@ -811,12 +816,9 @@ after_member(void *tvbparse_data, const void *wanted_data _U_, tvbparse_elem_t * tvbparse_elem_t* key_tok = tok->sub; if (tree && key_tok && key_tok->id == JSON_TOKEN_STRING) { - tvbparse_elem_t key_parse_element = key_tok[0]; - key_parse_element.offset += 1; - key_parse_element.len -= 2; - char* key_string_without_quotation_marks = json_string_unescape(&key_parse_element, FALSE); + const char* key_string_without_quotation_marks = get_json_string(data->pinfo->pool, key_tok, TRUE); - proto_tree_add_string(tree, &hfi_json_key, key_tok->tvb, key_tok->offset, key_tok->len, key_string_without_quotation_marks); + proto_tree_add_string(tree, hf_json_key, key_tok->tvb, key_tok->offset, key_tok->len, key_string_without_quotation_marks); } // extended path based filtering @@ -824,7 +826,7 @@ after_member(void *tvbparse_data, const void *wanted_data _U_, tvbparse_elem_t * char* path = (char*)wmem_stack_pop(data->stack_path); if (tree) { - proto_item* path_item = proto_tree_add_string(tree, &hfi_json_path, tok->tvb, tok->offset, tok->len, path); + proto_item* path_item = proto_tree_add_string(tree, hf_json_path, tok->tvb, tok->offset, tok->len, path); proto_item_set_generated(path_item); if (hide_extended_path_based_filtering) { @@ -836,6 +838,10 @@ after_member(void *tvbparse_data, const void *wanted_data _U_, tvbparse_elem_t * wmem_stack_pop(data->stack_compact); json_object_add_key(data); } + + if (json_raw) { + wmem_stack_pop(data->stack_raw); + } } static void @@ -846,7 +852,10 @@ before_array(void *tvbparse_data, const void *wanted_data _U_, tvbparse_elem_t * proto_tree *subtree; proto_item *ti; - ti = proto_tree_add_item(tree, &hfi_json_array, tok->tvb, tok->offset, tok->len, ENC_NA); + ti = proto_tree_add_item(tree, hf_json_array, tok->tvb, tok->offset, tok->len, ENC_NA); + if (json_hide_original_tree() && wmem_stack_count(data->stack) == 1) { + proto_item_set_hidden(ti); + } subtree = proto_item_add_subtree(ti, ett_json_array); wmem_stack_push(data->stack, subtree); @@ -857,7 +866,7 @@ before_array(void *tvbparse_data, const void *wanted_data _U_, tvbparse_elem_t * wmem_stack_push(data->stack_path, base_path); wmem_stack_push(data->stack_path, last_key_string); - char* path = join_strings(base_path, "[]", '/'); + char* path = join_strings(data->pinfo->pool, base_path, "[]", '/'); wmem_stack_push(data->stack_path, path); wmem_stack_push(data->stack_path, "[]"); @@ -866,12 +875,52 @@ before_array(void *tvbparse_data, const void *wanted_data _U_, tvbparse_elem_t * json_key_lookup(tree, tok, last_key_string, data->pinfo, FALSE); if (json_compact) { + proto_tree* tree_compact = (proto_tree*)wmem_stack_peek(data->stack_compact); + proto_tree* subtree_compact; + proto_item* ti_compact; + + gint idx = GPOINTER_TO_INT(wmem_stack_peek(data->array_idx)); + + if (JSON_INSIDE_ARRAY(idx)) { + ti_compact = proto_tree_add_none_format(tree_compact, hf_json_array_compact, tok->tvb, tok->offset, tok->len, "%d:", idx); + subtree_compact = proto_item_add_subtree(ti_compact, ett_json_array_compact); + json_array_index_increment(data); + } else { + subtree_compact = tree_compact; + } + wmem_stack_push(data->stack_compact, subtree_compact); + JSON_ARRAY_BEGIN(data); } + + if (json_raw) { + proto_tree* tree_raw = (proto_tree*)wmem_stack_peek(data->stack_raw); + proto_tree* subtree_raw; + proto_item* ti_raw; + + if (data->prev_item_raw && data->prev_item_type_raw == JSON_MARK_TYPE_END_ARRAY) { + proto_item_append_text(data->prev_item_raw, ","); + } + + if (data->prev_item_type_raw == JSON_MARK_TYPE_MEMBER_NAME) { + /* this is an array value of an member, add the "[" just after the member name */ + ti_raw = data->prev_item_raw; + proto_item_append_text(ti_raw, " ["); + } else { + /* this array is either the top element or an element of an array, add the "[" as a single item */ + ti_raw = proto_tree_add_none_format(tree_raw, hf_json_array_raw, tok->tvb, tok->offset, tok->len, "["); + } + + subtree_raw = proto_item_add_subtree(ti_raw, ett_json_array_raw); + wmem_stack_push(data->stack_raw, subtree_raw); + + data->prev_item_raw = ti_raw; + data->prev_item_type_raw = JSON_MARK_TYPE_BEGIN_ARRAY; + } } static void -after_array(void *tvbparse_data, const void *wanted_data _U_, tvbparse_elem_t *elem _U_) { +after_array(void *tvbparse_data, const void *wanted_data _U_, tvbparse_elem_t* tok) { json_parser_data_t *data = (json_parser_data_t *) tvbparse_data; wmem_stack_pop(data->stack); @@ -890,8 +939,27 @@ after_array(void *tvbparse_data, const void *wanted_data _U_, tvbparse_elem_t *e else proto_item_append_text(parent_item, " [...]"); + wmem_stack_pop(data->stack_compact); + JSON_ARRAY_OBJECT_END(data); } + + if (json_raw) { + proto_tree* tree_raw = (proto_tree*)wmem_stack_peek(data->stack_raw); + proto_tree* parent_tree = proto_tree_get_parent_tree(tree_raw); + proto_item* ti_raw; + if (data->prev_item_type_raw == JSON_MARK_TYPE_BEGIN_ARRAY) { /* an empty array */ + ti_raw = data->prev_item_raw; + proto_item_append_text(ti_raw, "]"); + } else { + tvbparse_elem_t* tok_last = tok->sub->last; + ti_raw = proto_tree_add_none_format(parent_tree, hf_json_array_raw, tok_last->tvb, tok_last->offset, tok_last->len, "]"); + } + wmem_stack_pop(data->stack_raw); + + data->prev_item_raw = ti_raw; + data->prev_item_type_raw = JSON_MARK_TYPE_END_ARRAY; + } } static void @@ -911,25 +979,20 @@ after_value(void *tvbparse_data, const void *wanted_data _U_, tvbparse_elem_t *t char* key_string = (char*)wmem_stack_pop(data->stack_path); char* path = (char*)wmem_stack_pop(data->stack_path); - char* value_str = NULL; + const char* value_str = NULL; if (value_id == JSON_TOKEN_STRING && tok->len >= 2) { - // tvb parse element covers the qutation marks which we don't want - tvbparse_elem_t key_parse_element = tok[0]; - key_parse_element.offset += 1; - key_parse_element.len -= 2; - - value_str = json_string_unescape(&key_parse_element, FALSE); + value_str = get_json_string(data->pinfo->pool, tok, TRUE); } else { - value_str = json_string_unescape(tok, FALSE); + value_str = get_json_string(data->pinfo->pool, tok, FALSE); } - char* path_with_value = join_strings(path, value_str, ':'); - char* memeber_with_value = join_strings(key_string, value_str, ':'); - proto_item* path_with_value_item = proto_tree_add_string(tree, &hfi_json_path_with_value, tok->tvb, tok->offset, tok->len, path_with_value); - proto_item* member_with_value_item = proto_tree_add_string(tree, &hfi_json_member_with_value, tok->tvb, tok->offset, tok->len, memeber_with_value); + char* path_with_value = join_strings(data->pinfo->pool, path, value_str, ':'); + char* memeber_with_value = join_strings(data->pinfo->pool, key_string, value_str, ':'); + 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); + 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); proto_item_set_generated(path_with_value_item); proto_item_set_generated(member_with_value_item); @@ -950,39 +1013,39 @@ after_value(void *tvbparse_data, const void *wanted_data _U_, tvbparse_elem_t *t proto_item *key_lookup = NULL; key_lookup = json_key_lookup(tree, tok, key_string, data->pinfo, FALSE); if (!key_lookup) { - proto_tree_add_string(tree, &hfi_json_value_string, tok->tvb, tok->offset, tok->len, value_str); + proto_tree_add_string(tree, hf_json_value_string, tok->tvb, tok->offset, tok->len, value_str); } } else { - proto_tree_add_item(tree, &hfi_json_value_string, tok->tvb, tok->offset, tok->len, ENC_ASCII | ENC_NA); + proto_tree_add_item(tree, hf_json_value_string, tok->tvb, tok->offset, tok->len, ENC_ASCII | ENC_NA); } break; case JSON_TOKEN_NUMBER: /* XXX, convert to number */ - proto_tree_add_item(tree, &hfi_json_value_number, tok->tvb, tok->offset, tok->len, ENC_ASCII|ENC_NA); + proto_tree_add_item(tree, hf_json_value_number, tok->tvb, tok->offset, tok->len, ENC_ASCII); break; case JSON_TOKEN_FALSE: - proto_tree_add_item(tree, &hfi_json_value_false, tok->tvb, tok->offset, tok->len, ENC_NA); + proto_tree_add_item(tree, hf_json_value_false, tok->tvb, tok->offset, tok->len, ENC_NA); break; case JSON_TOKEN_NULL: - proto_tree_add_item(tree, &hfi_json_value_null, tok->tvb, tok->offset, tok->len, ENC_NA); + proto_tree_add_item(tree, hf_json_value_null, tok->tvb, tok->offset, tok->len, ENC_NA); break; case JSON_TOKEN_TRUE: - proto_tree_add_item(tree, &hfi_json_value_true, tok->tvb, tok->offset, tok->len, ENC_NA); + proto_tree_add_item(tree, hf_json_value_true, tok->tvb, tok->offset, tok->len, ENC_NA); break; case JSON_TOKEN_NAN: - proto_tree_add_item(tree, &hfi_json_value_nan, tok->tvb, tok->offset, tok->len, ENC_NA); + proto_tree_add_item(tree, hf_json_value_nan, tok->tvb, tok->offset, tok->len, ENC_NA); break; @@ -996,16 +1059,36 @@ after_value(void *tvbparse_data, const void *wanted_data _U_, tvbparse_elem_t *t gint idx = GPOINTER_TO_INT(wmem_stack_peek(data->array_idx)); - char *val_str = tvb_get_string_enc(wmem_packet_scope(), tok->tvb, tok->offset, tok->len, ENC_UTF_8); + char *val_str = tvb_get_string_enc(data->pinfo->pool, tok->tvb, tok->offset, tok->len, ENC_UTF_8); if (JSON_INSIDE_ARRAY(idx)) { - proto_tree_add_none_format(tree_compact, &hfi_json_array_item_compact, tok->tvb, tok->offset, tok->len, "%d: %s", idx, val_str); + proto_tree_add_none_format(tree_compact, hf_json_array_item_compact, tok->tvb, tok->offset, tok->len, "%d: %s", idx, val_str); json_array_index_increment(data); } else { proto_item *parent_item = proto_tree_get_parent(tree_compact); proto_item_append_text(parent_item, " %s", val_str); } } + + if (json_raw) { + proto_tree* tree_raw = (proto_tree*)wmem_stack_peek(data->stack_raw); + proto_item* ti_raw; + char* val_str = tvb_get_string_enc(data->pinfo->pool, tok->tvb, tok->offset, tok->len, ENC_UTF_8); + + if (data->prev_item_raw && data->prev_item_type_raw == JSON_MARK_TYPE_VALUE) { + proto_item_append_text(data->prev_item_raw, ","); /* this value is an element of an array */ + } + + if (data->prev_item_raw && data->prev_item_type_raw == JSON_MARK_TYPE_MEMBER_NAME) { + ti_raw = proto_tree_get_parent(tree_raw); + proto_item_append_text(ti_raw, " %s", val_str); + } else { + ti_raw = proto_tree_add_none_format(tree_raw, hf_json_array_item_raw, tok->tvb, tok->offset, tok->len, "%s", val_str); + } + + data->prev_item_raw = ti_raw; + data->prev_item_type_raw = JSON_MARK_TYPE_VALUE; + } } static void @@ -1148,7 +1231,7 @@ static gboolean dissect_json_heur(tvbuff_t *tvb, packet_info *pinfo, proto_tree *tree, void *data) { guint len = tvb_captured_length(tvb); - const guint8* buf = tvb_get_string_enc(wmem_packet_scope(), tvb, 0, len, ENC_ASCII); + const guint8* buf = tvb_get_string_enc(pinfo->pool, tvb, 0, len, ENC_ASCII); if (json_validate(buf, len) == FALSE) return FALSE; @@ -1166,111 +1249,135 @@ dissect_json_acdr_heur(tvbuff_t *tvb, packet_info *pinfo, proto_tree *tree, void return FALSE; } -/* Functions to sub dissect json content */ -static void -dissect_base64decoded_eps_ie(tvbuff_t* tvb, proto_tree* tree, packet_info* pinfo, int offset, int len) -{ - /* base64-encoded characters, encoding the - * EPS IE specified in 3GPP TS 29.274. - */ - proto_item* ti; - proto_tree* sub_tree; - tvbuff_t* bin_tvb = base64_tvb_to_new_tvb(tvb, offset, len); - add_new_data_source(pinfo, bin_tvb, "Base64 decoded"); - ti = proto_tree_add_item(tree, &hfi_json_binary_data, bin_tvb, 0, -1, ENC_NA); - sub_tree = proto_item_add_subtree(ti, ett_json_base64decoded_eps_ie); - dissect_gtpv2_ie_common(bin_tvb, pinfo, sub_tree, 0, 0/* Message type 0, Reserved */, NULL); -} - static void register_static_headers(void) { - gchar* header_name; + json_header_fields_hash = g_hash_table_new_full(g_str_hash, g_str_equal, g_free, g_free); - header_fields_hash = g_hash_table_new_full(g_str_hash, g_str_equal, g_free, g_free); +} - /* Here hf[x].hfinfo.name is a header method which is used as key - * for matching ids while processing HTTP2 packets */ +void +proto_register_json(void) +{ static hf_register_info hf[] = { - { - &hf_json_3gpp_ueepspdnconnection, - {"ueEpsPdnConnection", "json.3gpp.ueepspdnconnection", - FT_STRING, BASE_NONE, NULL, 0x0, - NULL, HFILL} + { &hf_json_array, + { "Array", "json.array", + FT_NONE, BASE_NONE, NULL, 0x00, + "JSON array", HFILL } }, - { - &hf_json_3gpp_bearerlevelqos, - {"bearerLevelQoS", "json.3gpp.bearerlevelqos", - FT_STRING, BASE_NONE, NULL, 0x0, - NULL, HFILL} + { &hf_json_object, + { "Object", "json.object", + FT_STRING, BASE_NONE|BASE_NO_DISPLAY_VALUE, NULL, 0x00, + "JSON object", HFILL } }, - { - &hf_json_3gpp_epsbearersetup, - {"epsBearerSetup", "json.3gpp.epsbearersetup", - FT_STRING, BASE_NONE, NULL, 0x0, - NULL, HFILL} + { &hf_json_member, + { "Member", "json.member", + FT_STRING, BASE_NONE, NULL, 0x00, + "JSON object member", HFILL } }, - { - &hf_json_3gpp_forwardingbearercontexts, - {"forwardingBearerContexts", "json.3gpp.forwardingbearercontexts", - FT_STRING, BASE_NONE, NULL, 0x0, - NULL, HFILL} + { &hf_json_key, + { "Key", "json.key", + FT_STRING, BASE_NONE, NULL, 0x00, + NULL, HFILL } }, - { - &hf_json_3gpp_forwardingfteid, - {"forwardingFTeid", "json.3gpp.forwardingfteid", - FT_STRING, BASE_NONE, NULL, 0x0, - NULL, HFILL} + { &hf_json_path, + { "Path", "json.path", + FT_STRING, BASE_NONE, NULL, 0x00, + NULL, HFILL } }, - { - &hf_json_3gpp_pgwnodename, - {"pgwNodeName", "json.3gpp.pgwnodename", - FT_STRING, BASE_NONE, NULL, 0x0, - NULL, HFILL} + { &hf_json_path_with_value, + { "Path with value", "json.path_with_value", + FT_STRING, BASE_NONE, NULL, 0x00, + NULL, HFILL } }, - { - &hf_json_3gpp_pgws8cfteid, - {"pgwS8cFteid", "json.3gpp.pgws8cfteid", - FT_STRING, BASE_NONE, NULL, 0x0, - NULL, HFILL} + { &hf_json_member_with_value, + { "Member with value", "json.member_with_value", + FT_STRING, BASE_NONE, NULL, 0x00, + NULL, HFILL } + }, + { &hf_json_value_string, + { /* FT_STRINGZ? */ "String value", "json.value.string", + FT_STRING, BASE_NONE, NULL, 0x00, + "JSON string value", HFILL } + }, + { &hf_json_value_number, + { /* FT_DOUBLE/ FT_INT64? */ "Number value", "json.value.number", + FT_STRING, BASE_NONE, NULL, 0x00, + "JSON number value", HFILL } + }, + { &hf_json_value_false, + { "False value", "json.value.false", + FT_NONE, BASE_NONE, NULL, 0x00, + "JSON false value", HFILL } + }, + { &hf_json_value_null, + { "Null value", "json.value.null", + FT_NONE, BASE_NONE, NULL, 0x00, + "JSON null value", HFILL } + }, + { &hf_json_value_true, + { "True value", "json.value.true", + FT_NONE, BASE_NONE, NULL, 0x00, + "JSON true value", HFILL } + }, + { &hf_json_value_nan, + { "NaN value", "json.value.nan", + FT_NONE, BASE_NONE, NULL, 0x00, + "JSON NaN value", HFILL } + }, + { &hf_json_array_compact, + { "Array compact", "json.array_compact", + FT_NONE, BASE_NONE, NULL, 0x00, + "JSON array compact", HFILL } + }, + { &hf_json_object_compact, + { "Object compact", "json.object_compact", + FT_NONE, BASE_NONE, NULL, 0x00, + "JSON object compact", HFILL } + }, + { &hf_json_member_compact, + { "Member compact", "json.member_compact", + FT_NONE, BASE_NONE, NULL, 0x00, + "JSON member compact", HFILL } + }, + { &hf_json_array_item_compact, + { "Array item compact", "json.array_item_compact", + FT_NONE, BASE_NONE, NULL, 0x00, + "JSON array item compact", HFILL } + }, + { &hf_json_binary_data, + { "Binary data", "json.binary_data", + FT_BYTES, BASE_NONE, NULL, 0x00, + "JSON binary data", HFILL } + }, + { &hf_json_ignored_leading_bytes, + { "Ignored leading bytes", "json.ignored_leading_bytes", + FT_STRING, BASE_NONE, NULL, 0x00, + NULL, HFILL } + }, + { &hf_json_array_raw, + { "Array raw", "json.array_raw", + FT_NONE, BASE_NONE, NULL, 0x00, + "JSON array raw", HFILL } + }, + { &hf_json_object_raw, + { "Object raw", "json.object_raw", + FT_NONE, BASE_NONE, NULL, 0x00, + "JSON object raw", HFILL } + }, + { &hf_json_member_raw, + { "Member raw", "json.member_raw", + FT_NONE, BASE_NONE, NULL, 0x00, + "JSON member raw", HFILL } + }, + { &hf_json_array_item_raw, + { "Array item raw", "json.array_item_raw", + FT_NONE, BASE_NONE, NULL, 0x00, + "JSON array item raw", HFILL } }, - { - &hf_json_3gpp_pgws8ufteid, - {"pgwS8uFteid", "json.3gpp.pgws8ufteid", - FT_STRING, BASE_NONE, NULL, 0x0, - NULL, HFILL} - } - }; - /* List of decoding functions the index matches the HF */ - static void(*json_decode_fn[])(tvbuff_t * tvb, proto_tree * tree, packet_info * pinfo, int offset, int len) = { - dissect_base64decoded_eps_ie, /* ueEpsPdnConnection */ - dissect_base64decoded_eps_ie, /* bearerLevelQoS */ - dissect_base64decoded_eps_ie, /* epsBearerSetup */ - dissect_base64decoded_eps_ie, /* forwardingBearerContexts */ - dissect_base64decoded_eps_ie, /* forwardingFTeid */ - dissect_base64decoded_eps_ie, /* pgwNodeName */ - dissect_base64decoded_eps_ie, /* pgwS8cFteid */ - dissect_base64decoded_eps_ie, /* pgwS8uFteid */ - - NULL, /* NONE */ }; - /* Hfs with functions */ - for (guint i = 0; i < G_N_ELEMENTS(hf); ++i) { - header_name = g_strdup(hf[i].hfinfo.name); - json_data_decoder_t* json_data_decoder_rec = g_new(json_data_decoder_t, 1); - json_data_decoder_rec->hf_id = &hf[i].hfinfo.id; - json_data_decoder_rec->json_data_decoder = json_decode_fn[i]; - g_hash_table_insert(header_fields_hash, header_name, json_data_decoder_rec); - } - - proto_register_field_array(proto_json_3gpp, hf, G_N_ELEMENTS(hf)); -} - -void -proto_register_json(void) -{ static gint *ett[] = { &ett_json, &ett_json_array, @@ -1280,42 +1387,20 @@ proto_register_json(void) &ett_json_array_compact, &ett_json_object_compact, &ett_json_member_compact, - &ett_json_base64decoded_eps_ie, + &ett_json_raw, + &ett_json_array_raw, + &ett_json_object_raw, + &ett_json_member_raw, }; -#ifndef HAVE_HFI_SECTION_INIT - static header_field_info *hfi[] = { - &hfi_json_array, - &hfi_json_object, - &hfi_json_member, - &hfi_json_key, - &hfi_json_path, - &hfi_json_path_with_value, - &hfi_json_member_with_value, - &hfi_json_value_string, - &hfi_json_value_number, - &hfi_json_value_false, - &hfi_json_value_null, - &hfi_json_value_true, - &hfi_json_value_nan, - &hfi_json_array_compact, - &hfi_json_object_compact, - &hfi_json_member_compact, - &hfi_json_array_item_compact, - &hfi_json_binary_data, - &hfi_json_ignored_leading_bytes - }; -#endif - module_t *json_module; proto_json = proto_register_protocol("JavaScript Object Notation", "JSON", "json"); - hfi_json = proto_registrar_get_nth(proto_json); - - proto_register_fields(proto_json, hfi, array_length(hfi)); + proto_register_field_array(proto_json, hf, array_length(hf)); proto_register_subtree_array(ett, array_length(ett)); json_handle = register_dissector("json", dissect_json, proto_json); + json_file_handle = register_dissector("json_file", dissect_json_file, proto_json); init_json_parser(); @@ -1325,6 +1410,17 @@ proto_register_json(void) "Display JSON like in browsers devtool", &json_compact); + prefs_register_bool_preference(json_module, "raw_form", + "Display JSON in raw form", + "Display JSON like in vscode editor", + &json_raw); + + prefs_register_bool_preference(json_module, "auto_hide", + "Hide tree or root item automatically", + "Determine whether to hide the tree of original form or root item of compact or raw form" + " based on the enabled status of compact_form and raw_form preferences.", + &auto_hide); + prefs_register_bool_preference(json_module, "ignore_leading_bytes", "Ignore leading non JSON bytes", "Leading bytes will be ignored until first '[' or '{' is found.", @@ -1335,7 +1431,10 @@ proto_register_json(void) "Hide extended path based filtering", &hide_extended_path_based_filtering); - proto_json_3gpp = proto_register_protocol("JSON 3GPP", "JSON_3GPP", "json_3gpp"); + prefs_register_bool_preference(json_module, "unescape_strings", + "Replace character escapes with the escaped literal value", + "Replace character escapes with the escaped literal value", + &unescape_strings); /* Fill hash table with static headers */ register_static_headers(); @@ -1344,8 +1443,6 @@ proto_register_json(void) void proto_reg_handoff_json(void) { - dissector_handle_t json_file_handle = create_dissector_handle(dissect_json_file, proto_json); - heur_dissector_add("hpfeeds", dissect_json_heur, "JSON over HPFEEDS", "json_hpfeeds", proto_json, HEURISTIC_ENABLE); heur_dissector_add("db-lsp", dissect_json_heur, "JSON over DB-LSP", "json_db_lsp", proto_json, HEURISTIC_ENABLE); heur_dissector_add("udp", dissect_json_acdr_heur, "JSON over AC DR", "json_acdr", proto_json, HEURISTIC_ENABLE); @@ -1354,6 +1451,8 @@ proto_reg_handoff_json(void) dissector_add_for_decode_as("udp.port", json_file_handle); dissector_add_string("media_type", "application/json", json_handle); /* RFC 4627 */ + dissector_add_string("media_type", "application/senml+json", json_handle); /* RFC 8428 */ + dissector_add_string("media_type", "application/sensml+json", json_handle); /* RFC 8428 */ dissector_add_string("media_type", "application/json-rpc", json_handle); /* JSON-RPC over HTTP */ dissector_add_string("media_type", "application/jsonrequest", json_handle); /* JSON-RPC over HTTP */ dissector_add_string("media_type", "application/dds-web+json", json_handle); /* DDS Web Integration Service over HTTP */ @@ -1362,6 +1461,7 @@ proto_reg_handoff_json(void) dissector_add_string("media_type", "application/merge-patch+json", json_handle); /* RFC 7386 HTTP PATCH methods (RFC 5789) */ dissector_add_string("media_type", "application/json-patch+json", json_handle); /* RFC 6902 JavaScript Object Notation (JSON) Patch */ dissector_add_string("media_type", "application/x-ndjson", json_handle); + dissector_add_string("media_type", "application/3gppHal+json", json_handle); dissector_add_string("grpc_message_type", "application/grpc+json", json_handle); dissector_add_uint_range_with_preference("tcp.port", "", json_file_handle); /* JSON-RPC over TCP */ dissector_add_uint_range_with_preference("udp.port", "", json_file_handle); /* JSON-RPC over UDP */ |