/* packet-json.c * Routines for JSON dissection * References: * RFC 4627: https://tools.ietf.org/html/rfc4627 * Website: http://json.org/ * * Copyright 2010, Jakub Zawadzki * * Wireshark - Network traffic analyzer * By Gerald Combs * Copyright 1998 Gerald Combs * * SPDX-License-Identifier: GPL-2.0-or-later */ #include "config.h" #include #include #include #include #include #include #include #include "packet-http.h" #include "packet-acdr.h" #include "packet-gtpv2.h" #include "packet-gsm_a_common.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 dissector_handle_t json_handle; static int proto_json = -1; static int proto_json_3gpp = -1; //Used to get AC DR proto data static int proto_acdr = -1; static int hf_json_array = -1; static int hf_json_array_compact = -1; static int hf_json_array_item_compact = -1; static int hf_json_binary_data = -1; static int hf_json_ignored_leading_bytes = -1; static int hf_json_key = -1; static int hf_json_member = -1; static int hf_json_member_compact = -1; static int hf_json_member_with_value = -1; static int hf_json_object = -1; static int hf_json_object_compact = -1; static int hf_json_path = -1; static int hf_json_path_with_value = -1; static int hf_json_value_false = -1; static int hf_json_value_nan = -1; static int hf_json_value_null = -1; static int hf_json_value_number = -1; static int hf_json_value_string = -1; static int hf_json_value_true = -1; static gint ett_json = -1; static gint ett_json_array = -1; static gint ett_json_object = -1; static gint ett_json_member = -1; /* 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 gint ett_json_base64decoded_nas5g_ie = -1; static gint ett_json_3gpp_data = -1; 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 int hf_json_3gpp_qosrules = -1; static int hf_json_3gpp_qosflowdescription = -1; static int hf_json_3gpp_suppFeat = -1; static int hf_json_3gpp_suppfeat = -1; static int hf_json_3gpp_suppfeat_npcf_1_tsc = -1; static int hf_json_3gpp_suppfeat_npcf_2_resshare = -1; static int hf_json_3gpp_suppfeat_npcf_3_3gpppsdataoff = -1; static int hf_json_3gpp_suppfeat_npcf_4_adc = -1; static int hf_json_3gpp_suppfeat_npcf_5_umc = -1; static int hf_json_3gpp_suppfeat_npcf_6_netloc = -1; static int hf_json_3gpp_suppfeat_npcf_7_rannascause = -1; static int hf_json_3gpp_suppfeat_npcf_8_provafsignalflow = -1; static int hf_json_3gpp_suppfeat_npcf_9_pcscfrestorationenhancement = -1; static int hf_json_3gpp_suppfeat_npcf_10_pra = -1; static int hf_json_3gpp_suppfeat_npcf_11_ruleversioning = -1; static int hf_json_3gpp_suppfeat_npcf_12_sponsoredconnectivity = -1; static int hf_json_3gpp_suppfeat_npcf_13_ransupportinfo = -1; static int hf_json_3gpp_suppfeat_npcf_14_policyupdatewhenuesuspends = -1; static int hf_json_3gpp_suppfeat_npcf_15_accesstypecondition = -1; static int hf_json_3gpp_suppfeat_npcf_16_multiipv6addrprefix = -1; static int hf_json_3gpp_suppfeat_npcf_17_sessionruleerrorhandling = -1; static int hf_json_3gpp_suppfeat_npcf_18_af_charging_identifier = -1; static int hf_json_3gpp_suppfeat_npcf_19_atsss = -1; static int hf_json_3gpp_suppfeat_npcf_20_pendingtransaction = -1; static int hf_json_3gpp_suppfeat_npcf_21_urllc = -1; static int hf_json_3gpp_suppfeat_npcf_22_macaddressrange = -1; static int hf_json_3gpp_suppfeat_npcf_23_wwc = -1; static int hf_json_3gpp_suppfeat_npcf_24_qosmonitoring = -1; static int hf_json_3gpp_suppfeat_npcf_25_authorizationwithrequiredqos = -1; static int hf_json_3gpp_suppfeat_npcf_26_enhancedbackgrounddatatransfer = -1; static int hf_json_3gpp_suppfeat_npcf_27_dn_authorization = -1; static int hf_json_3gpp_suppfeat_npcf_28_pdusessionrelcause = -1; static int hf_json_3gpp_suppfeat_npcf_29_samepcf = -1; static int hf_json_3gpp_suppfeat_npcf_30_adcmultiredirection = -1; static int hf_json_3gpp_suppfeat_npcf_31_respbasedsessionrel = -1; static int hf_json_3gpp_suppfeat_npcf_32_timesensitivenetworking = -1; static int hf_json_3gpp_suppfeat_npcf_33_emdbv = -1; static int hf_json_3gpp_suppfeat_npcf_34_dnnselectionmode = -1; static int hf_json_3gpp_suppfeat_npcf_35_epsfallbackreport = -1; static int hf_json_3gpp_suppfeat_npcf_36_policydecisionerrorhandling = -1; static int hf_json_3gpp_suppfeat_npcf_37_ddneventpolicycontrol = -1; static int hf_json_3gpp_suppfeat_npcf_38_reallocationofcredit = -1; static int hf_json_3gpp_suppfeat_npcf_39_bdtpolicyrenegotiation = -1; static int hf_json_3gpp_suppfeat_npcf_40_extpolicydecisionerrorhandling = -1; static int hf_json_3gpp_suppfeat_npcf_41_immediatetermination = -1; static int hf_json_3gpp_suppfeat_npcf_42_aggregateduelocchanges = -1; static int hf_json_3gpp_suppfeat_npcf_43_es3xx = -1; static int hf_json_3gpp_suppfeat_npcf_44_groupidlistchange = -1; static int hf_json_3gpp_suppfeat_npcf_45_disableuenotification = -1; static int hf_json_3gpp_suppfeat_npcf_46_offlinechonly = -1; static int hf_json_3gpp_suppfeat_npcf_47_dual_connectivity_redundant_up_paths = -1; static int hf_json_3gpp_suppfeat_npcf_48_ddneventpolicycontrol2 = -1; static int hf_json_3gpp_suppfeat_npcf_49_vplmn_qos_control = -1; static int hf_json_3gpp_suppfeat_npcf_50_2g3giwk = -1; static int hf_json_3gpp_suppfeat_npcf_51_timesensitivecommunication = -1; static int hf_json_3gpp_suppfeat_npcf_52_enedge = -1; static int hf_json_3gpp_suppfeat_npcf_53_satbackhaulcategorychg = -1; static int hf_json_3gpp_suppfeat_npcf_54_chfsetsupport = -1; static int hf_json_3gpp_suppfeat_npcf_55_enatssss = -1; static int hf_json_3gpp_suppfeat_npcf_56_mpsfordts = -1; static int hf_json_3gpp_suppfeat_npcf_57_routinginforemoval = -1; static int hf_json_3gpp_suppfeat_npcf_58_epra = -1; static int hf_json_3gpp_suppfeat_npcf_59_aminfluence = -1; static int hf_json_3gpp_suppfeat_npcf_60_pvssupport = -1; static int hf_json_3gpp_suppfeat_npcf_61_enena = -1; /* 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, char* key_str, gboolean use_compact); /* 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, char* key_str, gboolean use_compact); } 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)? */ typedef struct { int *hf_id; json_data_decoder_func json_data_decoder; } json_data_decoder_t; /* Preferences */ static gboolean json_compact = FALSE; static gboolean ignore_leading_bytes = FALSE; static gboolean hide_extended_path_based_filtering = FALSE; static tvbparse_wanted_t* want; static tvbparse_wanted_t* want_ignore; static dissector_handle_t text_lines_handle; typedef enum { JSON_TOKEN_INVALID = -1, JSON_TOKEN_NUMBER = 0, JSON_TOKEN_STRING, JSON_TOKEN_FALSE, JSON_TOKEN_NULL, JSON_TOKEN_TRUE, JSON_TOKEN_NAN, /* not really tokens ... */ JSON_OBJECT, JSON_ARRAY } json_token_type_t; typedef struct { wmem_stack_t *stack; wmem_stack_t *stack_compact; /* Used for compact json form only */ wmem_stack_t *array_idx; /* Used for compact json form only. Top item: -3. Object: < 0. Array -1: no key, -2: has key */ wmem_stack_t* stack_path; packet_info* pinfo; } json_parser_data_t; #define JSON_COMPACT_TOP_ITEM -3 #define JSON_COMPACT_OBJECT_WITH_KEY -2 #define JSON_COMPACT_OBJECT_WITHOUT_KEY -1 #define JSON_COMPACT_ARRAY 0 #define JSON_ARRAY_BEGIN(json_tvbparse_data) wmem_stack_push(json_tvbparse_data->array_idx, GINT_TO_POINTER(JSON_COMPACT_ARRAY)) #define JSON_OBJECT_BEGIN(json_tvbparse_data) wmem_stack_push(json_tvbparse_data->array_idx, GINT_TO_POINTER(JSON_COMPACT_OBJECT_WITHOUT_KEY)) #define JSON_ARRAY_OBJECT_END(json_tvbparse_data) wmem_stack_pop(json_tvbparse_data->array_idx) #define JSON_INSIDE_ARRAY(idx) (idx >= JSON_COMPACT_ARRAY) #define JSON_OBJECT_SET_HAS_KEY(idx) (idx == JSON_COMPACT_OBJECT_WITH_KEY) static void json_array_index_increment(json_parser_data_t *data) { gint idx = GPOINTER_TO_INT(wmem_stack_pop(data->array_idx)); idx++; wmem_stack_push(data->array_idx, GINT_TO_POINTER(idx)); } static void json_object_add_key(json_parser_data_t *data) { wmem_stack_pop(data->array_idx); wmem_stack_push(data->array_idx, GINT_TO_POINTER(JSON_COMPACT_OBJECT_WITH_KEY)); } static char* json_string_unescape(tvbparse_elem_t* tok, gboolean enclose_in_quotation_marks) { int read_index = 0; 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, '\"'); } 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)) { break; } guint8 current_character = tvb_get_guint8(tok->tvb, tok->offset + read_index); // character that IS NOT escaped if (current_character != '\\') { // A single UTF-8 character can cover more than one byte. // Copy all bytes that belong to that character and forward currend_index by that amount of bytes int utf8_character_length = ws_utf8_char_len(current_character); if (utf8_character_length <= 0) { break; } 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 )) { break; } current_character = tvb_get_guint8(tok->tvb, tok->offset + read_index); read_index++; wmem_strbuf_append_c(output_string_buffer, current_character); } } // character that IS escaped else { 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)) { break; } current_character = tvb_get_guint8(tok->tvb, tok->offset + read_index); if (current_character == '\"' || current_character == '\\' || current_character == '/') { read_index++; wmem_strbuf_append_c(output_string_buffer, current_character); } else if (current_character == 'b') { read_index++; wmem_strbuf_append_c(output_string_buffer, '\b'); } else if (current_character == 'f') { read_index++; wmem_strbuf_append_c(output_string_buffer, '\f'); } else if (current_character == 'n') { read_index++; wmem_strbuf_append_c(output_string_buffer, '\n'); } else if (current_character == 'r') { read_index++; wmem_strbuf_append_c(output_string_buffer, '\r'); } else if (current_character == 't') { read_index++; wmem_strbuf_append_c(output_string_buffer, '\t'); } else if (current_character == 'u') { read_index++; guint32 code_point = 0; gboolean is_valid_unicode_character = TRUE; 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)) { is_valid_unicode_character = FALSE; break; } current_character = tvb_get_guint8(tok->tvb, tok->offset + read_index); read_index++; int nibble = ws_xton(current_character); if(nibble < 0) { is_valid_unicode_character = FALSE; break; } code_point <<= 4; code_point |= nibble; } 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)) { break; } current_character = tvb_get_guint8(tok->tvb, tok->offset + 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)) { break; } current_character = tvb_get_guint8(tok->tvb, tok->offset + read_index); if (current_character == 'u') { guint16 lead_surrogate = code_point; guint16 trail_surrogate = 0; read_index++; 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)) { is_valid_unicode_character = FALSE; break; } current_character = tvb_get_guint8(tok->tvb, tok->offset + read_index); read_index++; int nibble = ws_xton(current_character); if (nibble < 0) { is_valid_unicode_character = FALSE; break; } trail_surrogate <<= 4; trail_surrogate |= nibble; } if ((IS_TRAIL_SURROGATE(trail_surrogate))) { code_point = SURROGATE_VALUE(lead_surrogate, trail_surrogate); } else { is_valid_unicode_character = FALSE; } } else { read_index++; is_valid_unicode_character = FALSE; } } else { read_index++; is_valid_unicode_character = FALSE; } } else if ((IS_TRAIL_SURROGATE(code_point))) { is_valid_unicode_character = FALSE; } if (is_valid_unicode_character) { if (g_unichar_validate(code_point) && g_unichar_isprint(code_point)) { gchar length_test_buffer[6]; int utf8_character_length = (int)g_unichar_to_utf8(code_point, length_test_buffer); 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); } } } else { wmem_strbuf_append_unichar(output_string_buffer, 0xFFFD); } } else { /* not valid by JSON grammar (tvbparse rules should not allow it) */ DISSECTOR_ASSERT_NOT_REACHED(); } } } if (enclose_in_quotation_marks == TRUE) { wmem_strbuf_append_c(output_string_buffer, '\"'); } char* output_string = wmem_strbuf_finalize(output_string_buffer); return output_string; } static GHashTable* header_fields_hash = NULL; static proto_item* json_key_lookup(proto_tree* tree, tvbparse_elem_t* tok, char* key_str, packet_info* pinfo, gboolean use_compact) { proto_item* ti; int hf_id = -1; json_data_decoder_t* json_data_decoder_rec = (json_data_decoder_t*)g_hash_table_lookup(header_fields_hash, key_str); if (json_data_decoder_rec == NULL) { return NULL; } hf_id = *json_data_decoder_rec->hf_id; DISSECTOR_ASSERT(hf_id >= 0); if (use_compact) { int str_len = (int)strlen(key_str); 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), key_str, use_compact); } } else { 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, key_str, use_compact); } } return ti; } static char* join_strings(char* string_a, char* string_b, char separator) { if (string_a == NULL) { return NULL; } if (string_b == NULL) { return NULL; } wmem_strbuf_t* output_string_buffer = wmem_strbuf_new(wmem_packet_scope(), string_a); if (separator != '\0') { wmem_strbuf_append_c(output_string_buffer, separator); } wmem_strbuf_append(output_string_buffer, string_b); char* output_string = wmem_strbuf_finalize(output_string_buffer); return output_string; } static int dissect_json(tvbuff_t *tvb, packet_info *pinfo, proto_tree *tree, void* data) { proto_tree *json_tree = NULL; proto_item *ti = NULL; json_parser_data_t parser_data; tvbparse_t *tt; http_message_info_t *message_info; const char *data_name; int offset; /* Save pinfo*/ parser_data.pinfo = pinfo; /* JSON dissector can be called in a JSON native file or when transported * by another protocol, will make entry in the Protocol column on summary display accordingly */ wmem_list_frame_t *proto = wmem_list_frame_prev(wmem_list_tail(pinfo->layers)); if (proto) { const char *name = proto_get_protocol_filter_name(GPOINTER_TO_INT(wmem_list_frame_data(proto))); 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"); } else { col_set_str(pinfo->cinfo, COL_PROTOCOL, "JSON"); col_set_str(pinfo->cinfo, COL_INFO, "JavaScript Object Notation"); } } data_name = pinfo->match_string; if (! (data_name && data_name[0])) { /* * No information from "match_string" */ message_info = (http_message_info_t *)data; if (message_info == NULL) { /* * No information from dissector data */ data_name = NULL; } else { data_name = message_info->media_str; if (! (data_name && data_name[0])) { /* * No information from dissector data */ data_name = NULL; } } } if (tree) { 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) proto_item_append_text(ti, ": %s", data_name); } offset = 0; /* XXX*/ p_add_proto_data(pinfo->pool, pinfo, proto_json, 0, tvb); parser_data.stack = wmem_stack_new(wmem_packet_scope()); wmem_stack_push(parser_data.stack, json_tree); // extended path based filtering parser_data.stack_path = wmem_stack_new(wmem_packet_scope()); wmem_stack_push(parser_data.stack_path, ""); wmem_stack_push(parser_data.stack_path, ""); int buffer_length = (int)tvb_captured_length(tvb); if (ignore_leading_bytes) { while (offset < buffer_length) { guint8 current_character = tvb_get_guint8(tvb, offset); if (current_character == '[' || current_character == '{') { break; } offset++; } if(offset > 0) { 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:"); parser_data.stack_compact = wmem_stack_new(wmem_packet_scope()); wmem_stack_push(parser_data.stack_compact, json_tree_compact); parser_data.array_idx = wmem_stack_new(wmem_packet_scope()); wmem_stack_push(parser_data.array_idx, GINT_TO_POINTER(JSON_COMPACT_TOP_ITEM)); /* top element */ } tt = tvbparse_init(pinfo->pool, tvb, offset, buffer_length - offset, &parser_data, want_ignore); /* XXX, only one json in packet? */ while (tvbparse_get(tt, want)) { } offset = tvbparse_curr_offset(tt); proto_item_set_len(ti, offset); /* if we have some unparsed data, pass to data-text-lines dissector (?) */ if (tvb_reported_length_remaining(tvb, offset) > 0) { tvbuff_t *next_tvb; next_tvb = tvb_new_subset_remaining(tvb, offset); call_dissector_with_data(text_lines_handle, next_tvb, pinfo, tree, data); } else if (data_name) { col_append_sep_fstr(pinfo->cinfo, COL_INFO, " ", "(%s)", data_name); } return tvb_captured_length(tvb); } /* * For dissecting JSON in a file; we don't get passed a media type. */ static int dissect_json_file(tvbuff_t *tvb, packet_info *pinfo, proto_tree *tree, void* data _U_) { return dissect_json(tvb, pinfo, tree, NULL); } static void before_object(void *tvbparse_data, const void *wanted_data _U_, tvbparse_elem_t *tok) { json_parser_data_t *data = (json_parser_data_t *) tvbparse_data; proto_tree *tree = (proto_tree *)wmem_stack_peek(data->stack); proto_tree *subtree; proto_item *ti; ti = proto_tree_add_item(tree, hf_json_object, tok->tvb, tok->offset, tok->len, ENC_NA); subtree = proto_item_add_subtree(ti, ett_json_object); wmem_stack_push(data->stack, subtree); 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_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 { subtree_compact = tree_compact; } wmem_stack_push(data->stack_compact, subtree_compact); JSON_OBJECT_BEGIN(data); } } static void after_object(void *tvbparse_data, const void *wanted_data _U_, tvbparse_elem_t *elem _U_) { json_parser_data_t *data = (json_parser_data_t *) tvbparse_data; wmem_stack_pop(data->stack); if (json_compact) { proto_tree *tree_compact = (proto_tree *)wmem_stack_peek(data->stack_compact); proto_item *parent_item = proto_tree_get_parent(tree_compact); gint idx = GPOINTER_TO_INT(wmem_stack_peek(data->array_idx)); if (JSON_OBJECT_SET_HAS_KEY(idx)) proto_item_append_text(parent_item, " {...}"); else proto_item_append_text(parent_item, " {}"); wmem_stack_pop(data->stack_compact); JSON_ARRAY_OBJECT_END(data); } } static void before_member(void *tvbparse_data, const void *wanted_data _U_, tvbparse_elem_t *tok) { json_parser_data_t *data = (json_parser_data_t *) tvbparse_data; proto_tree *tree = (proto_tree *)wmem_stack_peek(data->stack); 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); char* key_string_with_quotation_marks = json_string_unescape(tok->sub, FALSE); 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); // extended path based filtering char* last_key_string = (char*)wmem_stack_pop(data->stack_path); char* base_path = (char*)wmem_stack_pop(data->stack_path); 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, '/'); wmem_stack_push(data->stack_path, path); wmem_stack_push(data->stack_path, key_string_without_quotation_marks); if (json_compact) { proto_tree *tree_compact = (proto_tree *)wmem_stack_peek(data->stack_compact); proto_tree *subtree_compact; proto_item *ti_compact = NULL; tvbparse_elem_t *key_tok = tok->sub; 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, hf_json_member_compact, tok->tvb, tok->offset, tok->len, "%s:", key_string_with_quotation_marks); } } else { 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); } } static void after_member(void *tvbparse_data, const void *wanted_data _U_, tvbparse_elem_t *tok) { json_parser_data_t *data = (json_parser_data_t *) tvbparse_data; proto_tree *tree = (proto_tree *)wmem_stack_pop(data->stack); 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); 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 wmem_stack_pop(data->stack_path); // Pop key char* path = (char*)wmem_stack_pop(data->stack_path); if (tree) { 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) { proto_item_set_hidden(path_item); } } if (json_compact) { wmem_stack_pop(data->stack_compact); json_object_add_key(data); } } static void before_array(void *tvbparse_data, const void *wanted_data _U_, tvbparse_elem_t *tok) { json_parser_data_t *data = (json_parser_data_t *) tvbparse_data; proto_tree *tree = (proto_tree *)wmem_stack_peek(data->stack); proto_tree *subtree; proto_item *ti; ti = proto_tree_add_item(tree, hf_json_array, tok->tvb, tok->offset, tok->len, ENC_NA); subtree = proto_item_add_subtree(ti, ett_json_array); wmem_stack_push(data->stack, subtree); // extended path based filtering char* last_key_string = (char*)wmem_stack_pop(data->stack_path); char* base_path = (char*)wmem_stack_pop(data->stack_path); wmem_stack_push(data->stack_path, base_path); wmem_stack_push(data->stack_path, last_key_string); char* path = join_strings(base_path, "[]", '/'); wmem_stack_push(data->stack_path, path); wmem_stack_push(data->stack_path, "[]"); // Try key_lookup json_key_lookup(tree, tok, last_key_string, data->pinfo, FALSE); if (json_compact) { JSON_ARRAY_BEGIN(data); } } static void after_array(void *tvbparse_data, const void *wanted_data _U_, tvbparse_elem_t *elem _U_) { json_parser_data_t *data = (json_parser_data_t *) tvbparse_data; wmem_stack_pop(data->stack); // extended path based filtering wmem_stack_pop(data->stack_path); // Pop key wmem_stack_pop(data->stack_path); // Pop path if (json_compact) { proto_tree *tree_compact = (proto_tree *)wmem_stack_peek(data->stack_compact); proto_item *parent_item = proto_tree_get_parent(tree_compact); gint idx = GPOINTER_TO_INT(wmem_stack_peek(data->array_idx)); if (idx == 0) proto_item_append_text(parent_item, " []"); else proto_item_append_text(parent_item, " [...]"); JSON_ARRAY_OBJECT_END(data); } } static void after_value(void *tvbparse_data, const void *wanted_data _U_, tvbparse_elem_t *tok) { json_parser_data_t *data = (json_parser_data_t *) tvbparse_data; proto_tree *tree = (proto_tree *)wmem_stack_peek(data->stack); json_token_type_t value_id = tok->sub ? (json_token_type_t)tok->sub->id : JSON_TOKEN_INVALID; if (!(value_id == JSON_TOKEN_STRING || value_id == JSON_TOKEN_NUMBER || value_id == JSON_TOKEN_FALSE || value_id == JSON_TOKEN_NULL || value_id == JSON_TOKEN_TRUE || value_id == JSON_TOKEN_NAN)) { return; } // extended path based filtering char* key_string = (char*)wmem_stack_pop(data->stack_path); char* path = (char*)wmem_stack_pop(data->stack_path); 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); } else { value_str = json_string_unescape(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, 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); if (hide_extended_path_based_filtering) { proto_item_set_hidden(path_with_value_item); proto_item_set_hidden(member_with_value_item); } wmem_stack_push(data->stack_path, path); wmem_stack_push(data->stack_path, key_string); switch (value_id) { case JSON_TOKEN_STRING: if (tok->len >= 2) { // Try key_lookup 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, hf_json_value_string, tok->tvb, tok->offset, tok->len, value_str); } } else { 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, hf_json_value_number, tok->tvb, tok->offset, tok->len, ENC_ASCII); break; case JSON_TOKEN_FALSE: 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, hf_json_value_null, tok->tvb, tok->offset, tok->len, ENC_NA); break; case JSON_TOKEN_TRUE: 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, hf_json_value_nan, tok->tvb, tok->offset, tok->len, ENC_NA); break; default: proto_tree_add_format_text(tree, tok->tvb, tok->offset, tok->len); break; } if (json_compact) { proto_tree *tree_compact = (proto_tree *)wmem_stack_peek(data->stack_compact); 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); if (JSON_INSIDE_ARRAY(idx)) { 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); } } } static void init_json_parser(void) { static tvbparse_wanted_t _want_object; static tvbparse_wanted_t _want_array; tvbparse_wanted_t *want_object, *want_array; tvbparse_wanted_t *want_member; tvbparse_wanted_t *want_string; tvbparse_wanted_t *want_number, *want_int; tvbparse_wanted_t *want_value; tvbparse_wanted_t *want_value_separator; #define tvbparse_optional(id, private_data, before_cb, after_cb, wanted) \ tvbparse_some(id, 0, 1, private_data, before_cb, after_cb, wanted) tvbparse_wanted_t *want_quot = tvbparse_char(-1,"\"",NULL,NULL,NULL); want_string = tvbparse_set_seq(JSON_TOKEN_STRING, NULL, NULL, NULL, want_quot, tvbparse_some(-1, 0, G_MAXINT, NULL, NULL, NULL, tvbparse_set_oneof(-1, NULL, NULL, NULL, tvbparse_not_chars(-1, 0, 0, "\"" "\\", NULL, NULL, NULL), /* XXX, without invalid unicode characters */ tvbparse_set_seq(-1, NULL, NULL, NULL, tvbparse_char(-1, "\\", NULL, NULL, NULL), tvbparse_set_oneof(-1, NULL, NULL, NULL, tvbparse_chars(-1, 0, 1, "\"" "\\" "/bfnrt", NULL, NULL, NULL), tvbparse_set_seq(-1, NULL, NULL, NULL, tvbparse_char(-1, "u", NULL, NULL, NULL), tvbparse_chars(-1, 4, 4, "0123456789abcdefABCDEF", NULL, NULL, NULL), NULL), NULL), NULL), NULL) ), want_quot, NULL); want_value_separator = tvbparse_char(-1, ",", NULL, NULL, NULL); /* int = zero / ( digit1-9 *DIGIT ) */ want_int = tvbparse_set_oneof(-1, NULL, NULL, NULL, tvbparse_char(-1, "0", NULL, NULL, NULL), tvbparse_set_seq(-1, NULL, NULL, NULL, tvbparse_chars(-1, 1, 1, "123456789", NULL, NULL, NULL), tvbparse_optional(-1, NULL, NULL, NULL, /* tvbparse_chars() don't respect 0 as min_len ;/ */ tvbparse_chars(-1, 0, 0, "0123456789", NULL, NULL, NULL)), NULL), NULL); /* number = [ minus ] int [ frac ] [ exp ] */ want_number = tvbparse_set_seq(JSON_TOKEN_NUMBER, NULL, NULL, NULL, tvbparse_optional(-1, NULL, NULL, NULL, /* tvbparse_chars() don't respect 0 as min_len ;/ */ tvbparse_chars(-1, 0, 1, "-", NULL, NULL, NULL)), want_int, /* frac = decimal-point 1*DIGIT */ tvbparse_optional(-1, NULL, NULL, NULL, tvbparse_set_seq(-1, NULL, NULL, NULL, tvbparse_char(-1, ".", NULL, NULL, NULL), tvbparse_chars(-1, 1, 0, "0123456789", NULL, NULL, NULL), NULL)), /* exp = e [ minus / plus ] 1*DIGIT */ tvbparse_optional(-1, NULL, NULL, NULL, tvbparse_set_seq(-1, NULL, NULL, NULL, tvbparse_char(-1, "eE", NULL, NULL, NULL), tvbparse_optional(-1, NULL, NULL, NULL, /* tvbparse_chars() don't respect 0 as min_len ;/ */ tvbparse_chars(-1, 0, 1, "-+", NULL, NULL, NULL)), tvbparse_chars(-1, 1, 0, "0123456789", NULL, NULL, NULL), NULL)), NULL); /* value = false / null / true / object / array / number / string */ want_value = tvbparse_set_oneof(-1, NULL, NULL, after_value, tvbparse_string(JSON_TOKEN_FALSE, "false", NULL, NULL, NULL), tvbparse_string(JSON_TOKEN_NULL, "null", NULL, NULL, NULL), tvbparse_string(JSON_TOKEN_TRUE, "true", NULL, NULL, NULL), tvbparse_string(JSON_TOKEN_NAN, "NaN", NULL, NULL, NULL), &_want_object, &_want_array, want_number, want_string, NULL); /* array = begin-array [ value *( value-separator value ) ] end-array */ want_array = tvbparse_set_seq(JSON_ARRAY, NULL, before_array, after_array, tvbparse_char(-1, "[", NULL, NULL, NULL), tvbparse_optional(-1, NULL, NULL, NULL, tvbparse_set_seq(-1, NULL, NULL, NULL, want_value, tvbparse_some(-1, 0, G_MAXINT, NULL, NULL, NULL, tvbparse_set_seq(-1, NULL, NULL, NULL, want_value_separator, want_value, NULL)), NULL) ), tvbparse_char(-1, "]", NULL, NULL, NULL), NULL); _want_array = *want_array; /* member = string name-separator value */ want_member = tvbparse_set_seq(-1, NULL, before_member, after_member, want_string, tvbparse_char(-1, ":", NULL, NULL, NULL), want_value, NULL); /* object = begin-object [ member *( value-separator member ) ] end-object */ want_object = tvbparse_set_seq(JSON_OBJECT, NULL, before_object, after_object, tvbparse_char(-1, "{", NULL, NULL, NULL), tvbparse_optional(-1, NULL, NULL, NULL, tvbparse_set_seq(-1, NULL, NULL, NULL, want_member, tvbparse_some(-1, 0, G_MAXINT, NULL, NULL, NULL, tvbparse_set_seq(-1, NULL, NULL, NULL, want_value_separator, want_member, NULL)), NULL) ), tvbparse_char(-1, "}", NULL, NULL, NULL), NULL); _want_object = *want_object; want_ignore = tvbparse_chars(-1, 1, 0, " \t\r\n", NULL, NULL, NULL); /* JSON-text = object / array */ want = tvbparse_set_oneof(-1, NULL, NULL, NULL, want_object, want_array, /* tvbparse_not_chars(-1, 1, 0, " \t\r\n", NULL, NULL, NULL), */ NULL); /* XXX, heur? */ } /* This function tries to understand if the payload is json or not */ 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); if (json_validate(buf, len) == FALSE) return FALSE; return (dissect_json(tvb, pinfo, tree, data) != 0); } /* This function tries to understand if the payload is sitting on top of AC DR */ static gboolean dissect_json_acdr_heur(tvbuff_t *tvb, packet_info *pinfo, proto_tree *tree, void *data) { guint acdr_prot = GPOINTER_TO_UINT(p_get_proto_data(pinfo->pool, pinfo, proto_acdr, 0)); if (acdr_prot == ACDR_VoiceAI) return dissect_json_heur(tvb, pinfo, tree, data); 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, char* key_str _U_, gboolean use_compact _U_) { /* 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); int bin_tvb_length = tvb_reported_length(bin_tvb); add_new_data_source(pinfo, bin_tvb, "Base64 decoded"); ti = proto_tree_add_item(tree, hf_json_binary_data, bin_tvb, 0, bin_tvb_length, 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 dissect_base64decoded_nas5g_ie(tvbuff_t* tvb, proto_tree* tree, packet_info* pinfo, int offset, int len, char* key_str, gboolean use_compact _U_) { /* base64-encoded characters, encoding the * NAS-5G IE specified in 3GPP TS 24.501. */ proto_item* ti; proto_tree* sub_tree; tvbuff_t* bin_tvb = base64_tvb_to_new_tvb(tvb, offset, len); int bin_tvb_length = tvb_reported_length(bin_tvb); add_new_data_source(pinfo, bin_tvb, "Base64 decoded"); ti = proto_tree_add_item(tree, hf_json_binary_data, bin_tvb, 0, bin_tvb_length, ENC_NA); sub_tree = proto_item_add_subtree(ti, ett_json_base64decoded_nas5g_ie); if (strcmp(key_str, "qosRules") == 0) { /* qosRules * This IE shall contain the QoS Rule(s) associated to the QoS flow to be sent to the UE. * It shall be encoded as the Qos rules IE specified in clause 9.11.4.13 of 3GPP TS 24.501 (starting from octet 4). */ de_nas_5gs_sm_qos_rules(bin_tvb, sub_tree, pinfo, 0, bin_tvb_length, NULL, 0); } else if (strcmp(key_str, "qosFlowDescription") == 0) { /* qosFlowDescription * When present, this IE shall contain the description of the QoS Flow level Qos parameters to be sent to the UE. * It shall be encoded as the Qos flow descriptions IE specified in clause 9.11.4.12 of 3GPP TS 24.501 (starting from octet 1), * encoding one single Qos flow description for the QoS flow to be set up. */ elem_telv(bin_tvb, sub_tree, pinfo, (guint8) 0x79, 18 /* NAS_5GS_PDU_TYPE_SM */, 11 /* DE_NAS_5GS_SM_QOS_FLOW_DES */, 0, bin_tvb_length, NULL); } } static void dissect_3gpp_supportfeatures(tvbuff_t* tvb, proto_tree* tree, packet_info* pinfo _U_, int offset, int len, char* key_str _U_, gboolean use_compact) { /* TS 29.571 ch5.2.2 * A string used to indicate the features supported by an API that is used as defined in clause 6.6 in 3GPP TS 29.500 [25]. * The string shall contain a bitmask indicating supported features in hexadecimal representation: * Each character in the string shall take a value of "0" to "9", "a" to "f" or "A" to "F" and * shall represent the support of 4 features as described in table 5.2.2-3. * The most significant character representing the highest-numbered features shall appear first in the string, * and the character representing features 1 to 4 shall appear last in the string. * The list of features and their numbering (starting with 1) are defined separately for each API. * If the string contains a lower number of characters than there are defined features for an API, * all features that would be represented by characters that are not present in the string are not supported. */ proto_item* ti; proto_tree* sub_tree; tvbuff_t *suppfeat_tvb; /* Skip quotation marks */ if (!use_compact) { offset++; len = len-2; } ti = proto_tree_add_item(tree, hf_json_3gpp_suppfeat, tvb, offset, len, ENC_ASCII); sub_tree = proto_item_add_subtree(ti, ett_json_3gpp_data); suppfeat_tvb = tvb_new_subset_length(tvb, offset, len); int offset_reverse = len - 1; /* TODO add handling of different API * Idea: fetch "HTTP2 header path: /{NF}" */ static int * const json_3gpp_suppfeat_npcf_list_1[] = { &hf_json_3gpp_suppfeat_npcf_1_tsc, &hf_json_3gpp_suppfeat_npcf_2_resshare, &hf_json_3gpp_suppfeat_npcf_3_3gpppsdataoff, &hf_json_3gpp_suppfeat_npcf_4_adc, NULL }; proto_tree_add_bitmask_list(sub_tree, suppfeat_tvb, offset_reverse, 1, json_3gpp_suppfeat_npcf_list_1, ENC_UTF_8|BASE_DEC_HEX); offset_reverse--; if (offset_reverse == -1) { return; } static int * const json_3gpp_suppfeat_npcf_list_2[] = { &hf_json_3gpp_suppfeat_npcf_5_umc, &hf_json_3gpp_suppfeat_npcf_6_netloc, &hf_json_3gpp_suppfeat_npcf_7_rannascause, &hf_json_3gpp_suppfeat_npcf_8_provafsignalflow, NULL }; proto_tree_add_bitmask_list(sub_tree, suppfeat_tvb, offset_reverse, 1, json_3gpp_suppfeat_npcf_list_2, ENC_UTF_8|BASE_DEC_HEX); offset_reverse--; if (offset_reverse == -1) { return; } static int * const json_3gpp_suppfeat_npcf_list_3[] = { &hf_json_3gpp_suppfeat_npcf_9_pcscfrestorationenhancement, &hf_json_3gpp_suppfeat_npcf_10_pra, &hf_json_3gpp_suppfeat_npcf_11_ruleversioning, &hf_json_3gpp_suppfeat_npcf_12_sponsoredconnectivity, NULL }; proto_tree_add_bitmask_list(sub_tree, suppfeat_tvb, offset_reverse, 1, json_3gpp_suppfeat_npcf_list_3, ENC_UTF_8|BASE_DEC_HEX); offset_reverse--; if (offset_reverse == -1) { return; } static int * const json_3gpp_suppfeat_npcf_list_4[] = { &hf_json_3gpp_suppfeat_npcf_13_ransupportinfo, &hf_json_3gpp_suppfeat_npcf_14_policyupdatewhenuesuspends, &hf_json_3gpp_suppfeat_npcf_15_accesstypecondition, &hf_json_3gpp_suppfeat_npcf_16_multiipv6addrprefix, NULL }; proto_tree_add_bitmask_list(sub_tree, suppfeat_tvb, offset_reverse, 1, json_3gpp_suppfeat_npcf_list_4, ENC_UTF_8|BASE_DEC_HEX); offset_reverse--; if (offset_reverse == -1) { return; } static int * const json_3gpp_suppfeat_npcf_list_5[] = { &hf_json_3gpp_suppfeat_npcf_17_sessionruleerrorhandling, &hf_json_3gpp_suppfeat_npcf_18_af_charging_identifier, &hf_json_3gpp_suppfeat_npcf_19_atsss, &hf_json_3gpp_suppfeat_npcf_20_pendingtransaction, NULL }; proto_tree_add_bitmask_list(sub_tree, suppfeat_tvb, offset_reverse, 1, json_3gpp_suppfeat_npcf_list_5, ENC_UTF_8|BASE_DEC_HEX); offset_reverse--; if (offset_reverse == -1) { return; } static int * const json_3gpp_suppfeat_npcf_list_6[] = { &hf_json_3gpp_suppfeat_npcf_21_urllc, &hf_json_3gpp_suppfeat_npcf_22_macaddressrange, &hf_json_3gpp_suppfeat_npcf_23_wwc, &hf_json_3gpp_suppfeat_npcf_24_qosmonitoring, NULL }; proto_tree_add_bitmask_list(sub_tree, suppfeat_tvb, offset_reverse, 1, json_3gpp_suppfeat_npcf_list_6, ENC_UTF_8|BASE_DEC_HEX); offset_reverse--; if (offset_reverse == -1) { return; } static int * const json_3gpp_suppfeat_npcf_list_7[] = { &hf_json_3gpp_suppfeat_npcf_25_authorizationwithrequiredqos, &hf_json_3gpp_suppfeat_npcf_26_enhancedbackgrounddatatransfer, &hf_json_3gpp_suppfeat_npcf_27_dn_authorization, &hf_json_3gpp_suppfeat_npcf_28_pdusessionrelcause, NULL }; proto_tree_add_bitmask_list(sub_tree, suppfeat_tvb, offset_reverse, 1, json_3gpp_suppfeat_npcf_list_7, ENC_UTF_8|BASE_DEC_HEX); offset_reverse--; if (offset_reverse == -1) { return; } static int * const json_3gpp_suppfeat_npcf_list_8[] = { &hf_json_3gpp_suppfeat_npcf_29_samepcf, &hf_json_3gpp_suppfeat_npcf_30_adcmultiredirection, &hf_json_3gpp_suppfeat_npcf_31_respbasedsessionrel, &hf_json_3gpp_suppfeat_npcf_32_timesensitivenetworking, NULL }; proto_tree_add_bitmask_list(sub_tree, suppfeat_tvb, offset_reverse, 1, json_3gpp_suppfeat_npcf_list_8, ENC_UTF_8|BASE_DEC_HEX); offset_reverse--; if (offset_reverse == -1) { return; } static int * const json_3gpp_suppfeat_npcf_list_9[] = { &hf_json_3gpp_suppfeat_npcf_33_emdbv, &hf_json_3gpp_suppfeat_npcf_34_dnnselectionmode, &hf_json_3gpp_suppfeat_npcf_35_epsfallbackreport, &hf_json_3gpp_suppfeat_npcf_36_policydecisionerrorhandling, NULL }; proto_tree_add_bitmask_list(sub_tree, suppfeat_tvb, offset_reverse, 1, json_3gpp_suppfeat_npcf_list_9, ENC_UTF_8|BASE_DEC_HEX); offset_reverse--; if (offset_reverse == -1) { return; } static int * const json_3gpp_suppfeat_npcf_list_10[] = { &hf_json_3gpp_suppfeat_npcf_37_ddneventpolicycontrol, &hf_json_3gpp_suppfeat_npcf_38_reallocationofcredit, &hf_json_3gpp_suppfeat_npcf_39_bdtpolicyrenegotiation, &hf_json_3gpp_suppfeat_npcf_40_extpolicydecisionerrorhandling, NULL }; proto_tree_add_bitmask_list(sub_tree, suppfeat_tvb, offset_reverse, 1, json_3gpp_suppfeat_npcf_list_10, ENC_UTF_8|BASE_DEC_HEX); offset_reverse--; if (offset_reverse == -1) { return; } static int * const json_3gpp_suppfeat_npcf_list_11[] = { &hf_json_3gpp_suppfeat_npcf_41_immediatetermination, &hf_json_3gpp_suppfeat_npcf_42_aggregateduelocchanges, &hf_json_3gpp_suppfeat_npcf_43_es3xx, &hf_json_3gpp_suppfeat_npcf_44_groupidlistchange, NULL }; proto_tree_add_bitmask_list(sub_tree, suppfeat_tvb, offset_reverse, 1, json_3gpp_suppfeat_npcf_list_11, ENC_UTF_8|BASE_DEC_HEX); offset_reverse--; if (offset_reverse == -1) { return; } static int * const json_3gpp_suppfeat_npcf_list_12[] = { &hf_json_3gpp_suppfeat_npcf_45_disableuenotification, &hf_json_3gpp_suppfeat_npcf_46_offlinechonly, &hf_json_3gpp_suppfeat_npcf_47_dual_connectivity_redundant_up_paths, &hf_json_3gpp_suppfeat_npcf_48_ddneventpolicycontrol2, NULL }; proto_tree_add_bitmask_list(sub_tree, suppfeat_tvb, offset_reverse, 1, json_3gpp_suppfeat_npcf_list_12, ENC_UTF_8|BASE_DEC_HEX); offset_reverse--; if (offset_reverse == -1) { return; } static int * const json_3gpp_suppfeat_npcf_list_13[] = { &hf_json_3gpp_suppfeat_npcf_49_vplmn_qos_control, &hf_json_3gpp_suppfeat_npcf_50_2g3giwk, &hf_json_3gpp_suppfeat_npcf_51_timesensitivecommunication, &hf_json_3gpp_suppfeat_npcf_52_enedge, NULL }; proto_tree_add_bitmask_list(sub_tree, suppfeat_tvb, offset_reverse, 1, json_3gpp_suppfeat_npcf_list_13, ENC_UTF_8|BASE_DEC_HEX); offset_reverse--; if (offset_reverse == -1) { return; } static int * const json_3gpp_suppfeat_npcf_list_14[] = { &hf_json_3gpp_suppfeat_npcf_53_satbackhaulcategorychg, &hf_json_3gpp_suppfeat_npcf_54_chfsetsupport, &hf_json_3gpp_suppfeat_npcf_55_enatssss, &hf_json_3gpp_suppfeat_npcf_56_mpsfordts, NULL }; proto_tree_add_bitmask_list(sub_tree, suppfeat_tvb, offset_reverse, 1, json_3gpp_suppfeat_npcf_list_14, ENC_UTF_8|BASE_DEC_HEX); offset_reverse--; if (offset_reverse == -1) { return; } static int * const json_3gpp_suppfeat_npcf_list_15[] = { &hf_json_3gpp_suppfeat_npcf_57_routinginforemoval, &hf_json_3gpp_suppfeat_npcf_58_epra, &hf_json_3gpp_suppfeat_npcf_59_aminfluence, &hf_json_3gpp_suppfeat_npcf_60_pvssupport, NULL }; proto_tree_add_bitmask_list(sub_tree, suppfeat_tvb, offset_reverse, 1, json_3gpp_suppfeat_npcf_list_15, ENC_UTF_8|BASE_DEC_HEX); offset_reverse--; if (offset_reverse == -1) { return; } static int * const json_3gpp_suppfeat_npcf_list_16[] = { &hf_json_3gpp_suppfeat_npcf_61_enena, NULL }; proto_tree_add_bitmask_list(sub_tree, suppfeat_tvb, offset_reverse, 1, json_3gpp_suppfeat_npcf_list_16, ENC_UTF_8|BASE_DEC_HEX); offset_reverse--; if (offset_reverse == -1) { return; } if (offset_reverse > -1) { proto_tree_add_format_text(sub_tree, suppfeat_tvb, 0, (offset_reverse - len)); } } static void register_static_headers(void) { gchar* header_name; 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 */ static hf_register_info hf[] = { { &hf_json_3gpp_ueepspdnconnection, {"ueEpsPdnConnection", "json.3gpp.ueepspdnconnection", FT_STRING, BASE_NONE, NULL, 0x0, NULL, HFILL} }, { &hf_json_3gpp_bearerlevelqos, {"bearerLevelQoS", "json.3gpp.bearerlevelqos", FT_STRING, BASE_NONE, NULL, 0x0, NULL, HFILL} }, { &hf_json_3gpp_epsbearersetup, {"epsBearerSetup", "json.3gpp.epsbearersetup", FT_STRING, BASE_NONE, NULL, 0x0, NULL, HFILL} }, { &hf_json_3gpp_forwardingbearercontexts, {"forwardingBearerContexts", "json.3gpp.forwardingbearercontexts", FT_STRING, BASE_NONE, NULL, 0x0, NULL, HFILL} }, { &hf_json_3gpp_forwardingfteid, {"forwardingFTeid", "json.3gpp.forwardingfteid", FT_STRING, BASE_NONE, NULL, 0x0, NULL, HFILL} }, { &hf_json_3gpp_pgwnodename, {"pgwNodeName", "json.3gpp.pgwnodename", FT_STRING, BASE_NONE, NULL, 0x0, NULL, HFILL} }, { &hf_json_3gpp_pgws8cfteid, {"pgwS8cFteid", "json.3gpp.pgws8cfteid", FT_STRING, BASE_NONE, NULL, 0x0, NULL, HFILL} }, { &hf_json_3gpp_pgws8ufteid, {"pgwS8uFteid", "json.3gpp.pgws8ufteid", FT_STRING, BASE_NONE, NULL, 0x0, NULL, HFILL} }, { &hf_json_3gpp_qosrules, {"qosRules", "json.3gpp.qosrules", FT_STRING, BASE_NONE, NULL, 0x0, NULL, HFILL} }, { &hf_json_3gpp_qosflowdescription, {"qosFlowDescription", "json.3gpp.qosflowdescription", FT_STRING, BASE_NONE, NULL, 0x0, NULL, HFILL} }, { &hf_json_3gpp_suppFeat, {"suppFeat", "json.3gpp.suppFeat", 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, char* key_str, gboolean use_compact) = { 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 */ dissect_base64decoded_nas5g_ie, /* qosRules */ dissect_base64decoded_nas5g_ie, /* qosFlowDescription */ dissect_3gpp_supportfeatures, 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 hf_register_info hf[] = { { &hf_json_array, { "Array", "json.array", FT_NONE, BASE_NONE, NULL, 0x00, "JSON array", HFILL } }, { &hf_json_object, { "Object", "json.object", FT_NONE, BASE_NONE, NULL, 0x00, "JSON object", HFILL } }, { &hf_json_member, { "Member", "json.member", FT_STRING, BASE_NONE, NULL, 0x00, "JSON object member", HFILL } }, { &hf_json_key, { "Key", "json.key", FT_STRING, BASE_NONE, NULL, 0x00, NULL, HFILL } }, { &hf_json_path, { "Path", "json.path", FT_STRING, BASE_NONE, NULL, 0x00, NULL, HFILL } }, { &hf_json_path_with_value, { "Path with value", "json.path_with_value", FT_STRING, BASE_NONE, NULL, 0x00, 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 } }, /* 3GPP content */ { &hf_json_3gpp_suppfeat, { "Supported Features", "json.3gpp.suppfeat", FT_STRING, BASE_NONE, NULL, 0x0, NULL, HFILL } }, { &hf_json_3gpp_suppfeat_npcf_1_tsc, { "TSC", "json.3gpp.suppfeat.tsc", FT_BOOLEAN, 4, NULL, 0x1, NULL, HFILL } }, { &hf_json_3gpp_suppfeat_npcf_2_resshare, { "ResShare", "json.3gpp.suppfeat.resshare", FT_BOOLEAN, 4, NULL, 0x2, NULL, HFILL } }, { &hf_json_3gpp_suppfeat_npcf_3_3gpppsdataoff, { "3GPP-PS-Data-Off", "json.3gpp.suppfeat.3gpppsdataoff", FT_BOOLEAN, 4, NULL, 0x4, NULL, HFILL } }, { &hf_json_3gpp_suppfeat_npcf_4_adc, { "ADC", "json.3gpp.suppfeat.adc", FT_BOOLEAN, 4, NULL, 0x8, NULL, HFILL } }, { &hf_json_3gpp_suppfeat_npcf_5_umc, { "UMC", "json.3gpp.suppfeat.umc", FT_BOOLEAN, 4, NULL, 0x1, NULL, HFILL } }, { &hf_json_3gpp_suppfeat_npcf_6_netloc, { "NetLoc", "json.3gpp.suppfeat.netloc", FT_BOOLEAN, 4, NULL, 0x2, NULL, HFILL } }, { &hf_json_3gpp_suppfeat_npcf_7_rannascause, { "RAN-NAS-Cause", "json.3gpp.suppfeat.rannascause", FT_BOOLEAN, 4, NULL, 0x4, NULL, HFILL } }, { &hf_json_3gpp_suppfeat_npcf_8_provafsignalflow, { "ProvAFsignalFlow", "json.3gpp.suppfeat.provafsignalflow", FT_BOOLEAN, 4, NULL, 0x8, NULL, HFILL } }, { &hf_json_3gpp_suppfeat_npcf_9_pcscfrestorationenhancement, { "PCSCF-Restoration-Enhancement", "json.3gpp.suppfeat.pcscfrestorationenhancement", FT_BOOLEAN, 4, NULL, 0x1, NULL, HFILL } }, { &hf_json_3gpp_suppfeat_npcf_10_pra, { "PRA", "json.3gpp.suppfeat.pra", FT_BOOLEAN, 4, NULL, 0x2, NULL, HFILL } }, { &hf_json_3gpp_suppfeat_npcf_11_ruleversioning, { "RuleVersioning", "json.3gpp.suppfeat.ruleversioning", FT_BOOLEAN, 4, NULL, 0x4, NULL, HFILL } }, { &hf_json_3gpp_suppfeat_npcf_12_sponsoredconnectivity, { "SponsoredConnectivity", "json.3gpp.suppfeat.sponsoredconnectivity", FT_BOOLEAN, 4, NULL, 0x8, NULL, HFILL } }, { &hf_json_3gpp_suppfeat_npcf_13_ransupportinfo, { "RAN-Support-Info", "json.3gpp.suppfeat.ransupportinfo", FT_BOOLEAN, 4, NULL, 0x1, NULL, HFILL } }, { &hf_json_3gpp_suppfeat_npcf_14_policyupdatewhenuesuspends, { "PolicyUpdateWhenUESuspends", "json.3gpp.suppfeat.policyupdatewhenuesuspends", FT_BOOLEAN, 4, NULL, 0x2, NULL, HFILL } }, { &hf_json_3gpp_suppfeat_npcf_15_accesstypecondition, { "AccessTypeCondition", "json.3gpp.suppfeat.accesstypecondition", FT_BOOLEAN, 4, NULL, 0x4, NULL, HFILL } }, { &hf_json_3gpp_suppfeat_npcf_16_multiipv6addrprefix, { "MultiIpv6AddrPrefix", "json.3gpp.suppfeat.multiipv6addrprefix", FT_BOOLEAN, 4, NULL, 0x8, NULL, HFILL } }, { &hf_json_3gpp_suppfeat_npcf_17_sessionruleerrorhandling, { "SessionRuleErrorHandling", "json.3gpp.suppfeat.sessionruleerrorhandling", FT_BOOLEAN, 4, NULL, 0x1, NULL, HFILL } }, { &hf_json_3gpp_suppfeat_npcf_18_af_charging_identifier, { "AF_Charging_Identifier", "json.3gpp.suppfeat.af_charging_identifier", FT_BOOLEAN, 4, NULL, 0x2, NULL, HFILL } }, { &hf_json_3gpp_suppfeat_npcf_19_atsss, { "ATSSS", "json.3gpp.suppfeat.atsss", FT_BOOLEAN, 4, NULL, 0x4, NULL, HFILL } }, { &hf_json_3gpp_suppfeat_npcf_20_pendingtransaction, { "PendingTransaction", "json.3gpp.suppfeat.pendingtransaction", FT_BOOLEAN, 4, NULL, 0x8, NULL, HFILL } }, { &hf_json_3gpp_suppfeat_npcf_21_urllc, { "URLLC", "json.3gpp.suppfeat.urllc", FT_BOOLEAN, 4, NULL, 0x1, NULL, HFILL } }, { &hf_json_3gpp_suppfeat_npcf_22_macaddressrange, { "MacAddressRange", "json.3gpp.suppfeat.macaddressrange", FT_BOOLEAN, 4, NULL, 0x2, NULL, HFILL } }, { &hf_json_3gpp_suppfeat_npcf_23_wwc, { "WWC", "json.3gpp.suppfeat.wwc", FT_BOOLEAN, 4, NULL, 0x4, NULL, HFILL } }, { &hf_json_3gpp_suppfeat_npcf_24_qosmonitoring, { "QosMonitoring", "json.3gpp.suppfeat.qosmonitoring", FT_BOOLEAN, 4, NULL, 0x8, NULL, HFILL } }, { &hf_json_3gpp_suppfeat_npcf_25_authorizationwithrequiredqos, { "AuthorizationWithRequiredQoS", "json.3gpp.suppfeat.authorizationwithrequiredqos", FT_BOOLEAN, 4, NULL, 0x1, NULL, HFILL } }, { &hf_json_3gpp_suppfeat_npcf_26_enhancedbackgrounddatatransfer, { "EnhancedBackgroundDataTransfer", "json.3gpp.suppfeat.enhancedbackgrounddatatransfer", FT_BOOLEAN, 4, NULL, 0x2, NULL, HFILL } }, { &hf_json_3gpp_suppfeat_npcf_27_dn_authorization, { "DN-Authorization", "json.3gpp.suppfeat.dn_authorization", FT_BOOLEAN, 4, NULL, 0x4, NULL, HFILL } }, { &hf_json_3gpp_suppfeat_npcf_28_pdusessionrelcause, { "PDUSessionRelCause", "json.3gpp.suppfeat.pdusessionrelcause", FT_BOOLEAN, 4, NULL, 0x8, NULL, HFILL } }, { &hf_json_3gpp_suppfeat_npcf_29_samepcf, { "SamePcf", "json.3gpp.suppfeat.samepcf", FT_BOOLEAN, 4, NULL, 0x1, NULL, HFILL } }, { &hf_json_3gpp_suppfeat_npcf_30_adcmultiredirection, { "ADCmultiRedirection", "json.3gpp.suppfeat.adcmultiredirection", FT_BOOLEAN, 4, NULL, 0x2, NULL, HFILL } }, { &hf_json_3gpp_suppfeat_npcf_31_respbasedsessionrel, { "RespBasedSessionRel", "json.3gpp.suppfeat.respbasedsessionrel", FT_BOOLEAN, 4, NULL, 0x4, NULL, HFILL } }, { &hf_json_3gpp_suppfeat_npcf_32_timesensitivenetworking, { "TimeSensitiveNetworking", "json.3gpp.suppfeat.timesensitivenetworking", FT_BOOLEAN, 4, NULL, 0x8, NULL, HFILL } }, { &hf_json_3gpp_suppfeat_npcf_33_emdbv, { "EMDBV", "json.3gpp.suppfeat.emdbv", FT_BOOLEAN, 4, NULL, 0x1, NULL, HFILL } }, { &hf_json_3gpp_suppfeat_npcf_34_dnnselectionmode, { "DNNSelectionMode", "json.3gpp.suppfeat.adcmultirednnselectionmodedirection", FT_BOOLEAN, 4, NULL, 0x2, NULL, HFILL } }, { &hf_json_3gpp_suppfeat_npcf_35_epsfallbackreport, { "EPSFallbackReport", "json.3gpp.suppfeat.epsfallbackreport", FT_BOOLEAN, 4, NULL, 0x4, NULL, HFILL } }, { &hf_json_3gpp_suppfeat_npcf_36_policydecisionerrorhandling, { "PolicyDecisionErrorHandling", "json.3gpp.suppfeat.policydecisionerrorhandling", FT_BOOLEAN, 4, NULL, 0x8, NULL, HFILL } }, { &hf_json_3gpp_suppfeat_npcf_37_ddneventpolicycontrol, { "DDNEventPolicyControl", "json.3gpp.suppfeat.ddneventpolicycontrol", FT_BOOLEAN, 4, NULL, 0x1, NULL, HFILL } }, { &hf_json_3gpp_suppfeat_npcf_38_reallocationofcredit, { "ReallocationOfCredit", "json.3gpp.suppfeat.reallocationofcredit", FT_BOOLEAN, 4, NULL, 0x2, NULL, HFILL } }, { &hf_json_3gpp_suppfeat_npcf_39_bdtpolicyrenegotiation, { "BDTPolicyRenegotiation", "json.3gpp.suppfeat.bdtpolicyrenegotiation", FT_BOOLEAN, 4, NULL, 0x4, NULL, HFILL } }, { &hf_json_3gpp_suppfeat_npcf_40_extpolicydecisionerrorhandling, { "ExtPolicyDecisionErrorHandling", "json.3gpp.suppfeat.extpolicydecisionerrorhandling", FT_BOOLEAN, 4, NULL, 0x8, NULL, HFILL } }, { &hf_json_3gpp_suppfeat_npcf_41_immediatetermination, { "ImmediateTermination", "json.3gpp.suppfeat.immediatetermination", FT_BOOLEAN, 4, NULL, 0x1, NULL, HFILL } }, { &hf_json_3gpp_suppfeat_npcf_42_aggregateduelocchanges, { "AggregatedUELocChanges", "json.3gpp.suppfeat.aggregateduelocchanges", FT_BOOLEAN, 4, NULL, 0x2, NULL, HFILL } }, { &hf_json_3gpp_suppfeat_npcf_43_es3xx, { "ES3XX", "json.3gpp.suppfeat.es3xx", FT_BOOLEAN, 4, NULL, 0x4, NULL, HFILL } }, { &hf_json_3gpp_suppfeat_npcf_44_groupidlistchange, { "GroupIdListChange", "json.3gpp.suppfeat.groupidlistchange", FT_BOOLEAN, 4, NULL, 0x8, NULL, HFILL } }, { &hf_json_3gpp_suppfeat_npcf_45_disableuenotification, { "DisableUENotification", "json.3gpp.suppfeat.disableuenotification", FT_BOOLEAN, 4, NULL, 0x1, NULL, HFILL } }, { &hf_json_3gpp_suppfeat_npcf_46_offlinechonly, { "OfflineChOnly", "json.3gpp.suppfeat.offlinechonly", FT_BOOLEAN, 4, NULL, 0x2, NULL, HFILL } }, { &hf_json_3gpp_suppfeat_npcf_47_dual_connectivity_redundant_up_paths, { "Dual-Connectivity-redundant-UP-paths", "json.3gpp.suppfeat.dual_connectivity_redundant_up_paths", FT_BOOLEAN, 4, NULL, 0x4, NULL, HFILL } }, { &hf_json_3gpp_suppfeat_npcf_48_ddneventpolicycontrol2, { "DDNEventPolicyControl2", "json.3gpp.suppfeat.ddneventpolicycontrol2", FT_BOOLEAN, 4, NULL, 0x8, NULL, HFILL } }, { &hf_json_3gpp_suppfeat_npcf_49_vplmn_qos_control, { "VPLMN-QoS-Control", "json.3gpp.suppfeat.vplmn_qos_control", FT_BOOLEAN, 4, NULL, 0x1, NULL, HFILL } }, { &hf_json_3gpp_suppfeat_npcf_50_2g3giwk, { "2G3GIWK", "json.3gpp.suppfeat.2g3giwk", FT_BOOLEAN, 4, NULL, 0x2, NULL, HFILL } }, { &hf_json_3gpp_suppfeat_npcf_51_timesensitivecommunication, { "TimeSensitiveCommunication", "json.3gpp.suppfeat.timesensitivecommunication", FT_BOOLEAN, 4, NULL, 0x4, NULL, HFILL } }, { &hf_json_3gpp_suppfeat_npcf_52_enedge, { "EnEDGE", "json.3gpp.suppfeat.enedge", FT_BOOLEAN, 4, NULL, 0x8, NULL, HFILL } }, { &hf_json_3gpp_suppfeat_npcf_53_satbackhaulcategorychg, { "SatBackhaulCategoryChg", "json.3gpp.suppfeat.satbackhaulcategorychg", FT_BOOLEAN, 4, NULL, 0x1, NULL, HFILL } }, { &hf_json_3gpp_suppfeat_npcf_54_chfsetsupport, { "CHFsetSupport", "json.3gpp.suppfeat.chfsetsupport", FT_BOOLEAN, 4, NULL, 0x2, NULL, HFILL } }, { &hf_json_3gpp_suppfeat_npcf_55_enatssss, { "EnATSSS", "json.3gpp.suppfeat.enatssss", FT_BOOLEAN, 4, NULL, 0x4, NULL, HFILL } }, { &hf_json_3gpp_suppfeat_npcf_56_mpsfordts, { "MPSforDTS", "json.3gpp.suppfeat.mpsfordts", FT_BOOLEAN, 4, NULL, 0x8, NULL, HFILL } }, { &hf_json_3gpp_suppfeat_npcf_57_routinginforemoval, { "RoutingInfoRemoval", "json.3gpp.suppfeat.routinginforemoval", FT_BOOLEAN, 4, NULL, 0x1, NULL, HFILL } }, { &hf_json_3gpp_suppfeat_npcf_58_epra, { "ePRA", "json.3gpp.suppfeat.epra", FT_BOOLEAN, 4, NULL, 0x2, NULL, HFILL } }, { &hf_json_3gpp_suppfeat_npcf_59_aminfluence, { "AMInfluence", "json.3gpp.suppfeat.aminfluence", FT_BOOLEAN, 4, NULL, 0x4, NULL, HFILL } }, { &hf_json_3gpp_suppfeat_npcf_60_pvssupport, { "PvsSupport", "json.3gpp.suppfeat.pvssupport", FT_BOOLEAN, 4, NULL, 0x8, NULL, HFILL } }, { &hf_json_3gpp_suppfeat_npcf_61_enena, { "EneNA", "json.3gpp.suppfeat.enena", FT_BOOLEAN, 4, NULL, 0x1, NULL, HFILL } }, }; static gint *ett[] = { &ett_json, &ett_json_array, &ett_json_object, &ett_json_member, &ett_json_compact, &ett_json_array_compact, &ett_json_object_compact, &ett_json_member_compact, &ett_json_base64decoded_eps_ie, &ett_json_base64decoded_nas5g_ie, &ett_json_3gpp_data, }; module_t *json_module; proto_json = proto_register_protocol("JavaScript Object Notation", "JSON", "json"); 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); init_json_parser(); json_module = prefs_register_protocol(proto_json, NULL); prefs_register_bool_preference(json_module, "compact_form", "Display JSON in compact form", "Display JSON like in browsers devtool", &json_compact); prefs_register_bool_preference(json_module, "ignore_leading_bytes", "Ignore leading non JSON bytes", "Leading bytes will be ignored until first '[' or '{' is found.", &ignore_leading_bytes); prefs_register_bool_preference(json_module, "hide_extended_path_based_filtering", "Hide extended path based filtering", "Hide extended path based filtering", &hide_extended_path_based_filtering); proto_json_3gpp = proto_register_protocol("JSON 3GPP", "JSON_3GPP", "json_3gpp"); /* Fill hash table with static headers */ register_static_headers(); } 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); dissector_add_uint("wtap_encap", WTAP_ENCAP_JSON, json_file_handle); 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 */ dissector_add_string("media_type", "application/vnd.oma.lwm2m+json", json_handle); /* LWM2M JSON over CoAP */ dissector_add_string("media_type", "application/problem+json", json_handle); /* RFC 7807 Problem Details for HTTP APIs*/ 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("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 */ text_lines_handle = find_dissector_add_dependency("data-text-lines", proto_json); proto_acdr = proto_get_id_by_filter_name("acdr"); } /* * Editor modelines - https://www.wireshark.org/tools/modelines.html * * Local variables: * c-basic-offset: 8 * tab-width: 8 * indent-tabs-mode: t * End: * * vi: set shiftwidth=8 tabstop=8 noexpandtab: * :indentSize=8:tabSize=8:noTabs=false: */