aboutsummaryrefslogtreecommitdiffstats
path: root/epan/dissectors/packet-json.c
diff options
context:
space:
mode:
authorDeveloper Alexander <dev@alex-mails.de>2021-06-30 08:16:42 +0200
committerDeveloper Alexander <dev@alex-mails.de>2021-07-06 19:16:29 +0000
commit8a630ad6d069c9c191f33732e479b83b0e8dd811 (patch)
tree34870d174382c816df95da615fe52090b72b06e8 /epan/dissectors/packet-json.c
parent43077b96e894adc75bc958cf3a1e41d2e3e3b737 (diff)
json: improved path based filtering
It is the intention to enable more precise filtering for json. 6 changes were made for this: - 'json.member' becomes filterable as a string field with the key of the member. Before the key was only appended as text but was not filterable. - Every item gets a field 'path' which allows to filter for elments which are at a specific position within the json. To make anonymous arrays visible (no member key) they appear as '[]' in the path. (For example arrays in arrays) - Every string, number, true, false, true or null item gets a field 'path_with_value' which combines the path of this element with its value. This allows a filtering for values of elements at a specific position within the json. - Every string, number, true, false, true or null item gets a field 'member_with_value' which combines the key of this element with its value. This allows a filtering for specific key-values-pairs independently of the position within the json. -It is possible to hide 'path', 'path_with_value', 'member_with_value' by a preference called 'Hide extended path based filtering'. - If the provided buffer does not start with the json object but has some leading bytes which does not belong to the json object there is a new option to ignore these bytes. This behaviour can be enabled by the newly introduced preference 'Ignore leading non JSON bytes'.
Diffstat (limited to 'epan/dissectors/packet-json.c')
-rw-r--r--epan/dissectors/packet-json.c610
1 files changed, 390 insertions, 220 deletions
diff --git a/epan/dissectors/packet-json.c b/epan/dissectors/packet-json.c
index 19559f38ed..64d395385c 100644
--- a/epan/dissectors/packet-json.c
+++ b/epan/dissectors/packet-json.c
@@ -33,7 +33,8 @@
void proto_register_json(void);
void proto_reg_handoff_json(void);
-static char *json_string_unescape(tvbparse_elem_t *tok);
+static char* json_string_unescape(tvbparse_elem_t *tok, gboolean keep_outer_parentheses);
+
static dissector_handle_t json_handle;
@@ -65,11 +66,20 @@ 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_NONE, BASE_NONE, NULL, 0x00, "JSON object member", HFILL };
+ { "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 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 };
@@ -104,6 +114,9 @@ static header_field_info hfi_json_array_item_compact JSON_HFI_INIT =
static header_field_info hfi_json_binary_data_compact JSON_HFI_INIT =
{ "Binary data compact", "json.binary_data_compact", FT_BYTES, BASE_NONE, NULL, 0x00, "JSON binary data compact", 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 };
+
static int hf_json_3gpp_ueepspdnconnection = -1;
/* json data decoding function XXXX only works for the compact form.
@@ -126,6 +139,10 @@ typedef struct {
/* 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;
@@ -153,6 +170,7 @@ typedef struct {
Top item: -3.
Object: < 0.
Array -1: no key, -2: has key */
+ wmem_stack_t* stack_path;
packet_info* pinfo;
} json_parser_data_t;
@@ -183,6 +201,238 @@ json_object_add_key(json_parser_data_t *data)
}
static int
+json_tvb_memcpy_utf8(char* buf, tvbuff_t* tvb, int offset, int offset_max)
+{
+ int len = ws_utf8_char_len((guint8)*buf);
+
+ /* XXX, before moving to core API check if it's off-by-one safe.
+ * For JSON analyzer it's not a problem
+ * (string always terminated by ", which is not valid UTF-8 continuation character) */
+ if (len == -1 || ((guint)(offset + len)) >= (guint)offset_max) {
+ *buf = '?';
+ return 1;
+ }
+
+ /* assume it's valid UTF-8 */
+ tvb_memcpy(tvb, buf + 1, offset + 1, (size_t)len - 1);
+
+ if (!g_utf8_validate(buf, len, NULL)) {
+ *buf = '?';
+ return 1;
+ }
+
+ return len;
+}
+
+static char*
+json_string_unescape(tvbparse_elem_t* tok, gboolean keep_outer_parentheses)
+{
+ int j = 0;
+ int i = keep_outer_parentheses == TRUE ? 0 : 1;
+ int length = keep_outer_parentheses == TRUE ? tok->len : tok->len - 1;
+
+ if (keep_outer_parentheses == FALSE)
+ {
+ i = i;
+ }
+
+ char* str = (char*)wmem_alloc(wmem_packet_scope(), (size_t)length);
+
+ for (; i < length; i++) {
+ guint8 ch = tvb_get_guint8(tok->tvb, tok->offset + i);
+ int bin;
+
+ if (ch == '\\') {
+ i++;
+
+ ch = tvb_get_guint8(tok->tvb, tok->offset + i);
+ switch (ch) {
+ case '\"':
+ case '\\':
+ case '/':
+ str[j++] = ch;
+ break;
+
+ case 'b':
+ str[j++] = '\b';
+ break;
+ case 'f':
+ str[j++] = '\f';
+ break;
+ case 'n':
+ str[j++] = '\n';
+ break;
+ case 'r':
+ str[j++] = '\r';
+ break;
+ case 't':
+ str[j++] = '\t';
+ break;
+
+ case 'u':
+ {
+ guint32 unicode_hex = 0;
+ gboolean valid = TRUE;
+ int k;
+
+ for (k = 0; k < 4; k++) {
+ i++;
+ unicode_hex <<= 4;
+
+ ch = tvb_get_guint8(tok->tvb, tok->offset + i);
+ bin = ws_xton(ch);
+ if (bin == -1) {
+ valid = FALSE;
+ break;
+ }
+ unicode_hex |= bin;
+ }
+
+ if ((IS_LEAD_SURROGATE(unicode_hex))) {
+ ch = tvb_get_guint8(tok->tvb, tok->offset + i + 1);
+
+ if (ch == '\\') {
+ i++;
+ ch = tvb_get_guint8(tok->tvb, tok->offset + i + 1);
+ if (ch == 'u') {
+ guint16 lead_surrogate = unicode_hex;
+ guint16 trail_surrogate = 0;
+ i++;
+
+ for (k = 0; k < 4; k++) {
+ i++;
+ trail_surrogate <<= 4;
+
+ ch = tvb_get_guint8(tok->tvb, tok->offset + i);
+ bin = ws_xton(ch);
+ if (bin == -1) {
+ valid = FALSE;
+ break;
+ }
+ trail_surrogate |= bin;
+ }
+
+ if ((IS_TRAIL_SURROGATE(trail_surrogate))) {
+ unicode_hex = SURROGATE_VALUE(lead_surrogate, trail_surrogate);
+ }
+ else {
+ valid = FALSE;
+ }
+ }
+ else {
+ valid = FALSE;
+ }
+ }
+ else {
+ valid = FALSE;
+ }
+ }
+ else if ((IS_TRAIL_SURROGATE(unicode_hex))) {
+ i++;
+ valid = FALSE;
+ }
+
+ if (valid && g_unichar_validate(unicode_hex) && g_unichar_isprint(unicode_hex)) {
+ /* \uXXXX => 6 bytes */
+ int charlen = g_unichar_to_utf8(unicode_hex, &str[j]);
+ j += charlen;
+ }
+ else
+ {
+ str[j++] = '?';
+ }
+ break;
+ }
+ default:
+ /* not valid by JSON grammar (also tvbparse rules should not allow it) */
+ DISSECTOR_ASSERT_NOT_REACHED();
+ break;
+ }
+ }
+ else
+ {
+ int utf_len;
+
+ str[j] = ch;
+ /* XXX if it's not valid UTF-8 character, add some expert info? (it violates JSON grammar) */
+ utf_len = json_tvb_memcpy_utf8(&str[j], tok->tvb, tok->offset + i, tok->offset + length + 1);
+ j += utf_len;
+ i += (utf_len - 1);
+ }
+ }
+ str[j] = '\0';
+
+ return str;
+}
+
+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)
+{
+ proto_item* ti;
+ int hf_id = -1;
+ header_field_info* hfi;
+ int str_len = (int)strlen(key_str);
+
+ 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;
+
+ hfi = proto_registrar_get_nth(hf_id);
+ DISSECTOR_ASSERT(hfi != NULL);
+
+ ti = proto_tree_add_item(tree, hfi, 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));
+ }
+ return ti;
+
+}
+
+static char*
+join_strings(char* a, char* b, char separator)
+{
+ size_t joined_string_length = separator == '\0' ? 1 : 2;
+ joined_string_length += strlen(a);
+ joined_string_length += strlen(b);
+
+ char* joined_string = (char*)wmem_alloc(wmem_packet_scope(), joined_string_length);
+
+ if (joined_string == NULL)
+ {
+ return NULL;
+ }
+
+ int i = 0;
+ while (a[i] != '\0')
+ {
+ joined_string[i] = a[i];
+ i++;
+ }
+
+ if (separator != '\n')
+ {
+ joined_string[i++] = separator;
+ }
+
+ int offset = i;
+ i = 0;
+ while (b[i] != '\0')
+ {
+ joined_string[offset + i] = b[i];
+ i++;
+ }
+
+ joined_string[joined_string_length - 1] = '\0';
+
+ return joined_string;
+}
+
+static int
dissect_json(tvbuff_t *tvb, packet_info *pinfo, proto_tree *tree, void* data)
{
proto_tree *json_tree = NULL;
@@ -250,8 +500,32 @@ dissect_json(tvbuff_t *tvb, packet_info *pinfo, proto_tree *tree, void* data)
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, &hfi_json_ignored_leading_bytes, tvb, 0, offset, ENC_NA);
+ }
+ }
+
if (json_compact) {
- proto_tree *json_tree_compact = NULL;
+ 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());
@@ -261,12 +535,11 @@ dissect_json(tvbuff_t *tvb, packet_info *pinfo, proto_tree *tree, void* data)
wmem_stack_push(parser_data.array_idx, GINT_TO_POINTER(JSON_COMPACT_TOP_ITEM)); /* top element */
}
-
- tt = tvbparse_init(tvb, offset, -1, &parser_data, want_ignore);
+ tt = tvbparse_init(tvb, offset, buffer_length - offset, &parser_data, want_ignore);
/* XXX, only one json in packet? */
- while ((tvbparse_get(tt, want)))
- ;
+ while (tvbparse_get(tt, want))
+ { }
offset = tvbparse_curr_offset(tt);
@@ -295,7 +568,8 @@ dissect_json_file(tvbuff_t *tvb, packet_info *pinfo, proto_tree *tree, void* dat
return dissect_json(tvb, pinfo, tree, NULL);
}
-static void before_object(void *tvbparse_data, const void *wanted_data _U_, tvbparse_elem_t *tok) {
+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);
@@ -327,7 +601,8 @@ static void before_object(void *tvbparse_data, const void *wanted_data _U_, tvbp
}
}
-static void after_object(void *tvbparse_data, const void *wanted_data _U_, tvbparse_elem_t *elem _U_) {
+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);
@@ -349,45 +624,30 @@ static void after_object(void *tvbparse_data, const void *wanted_data _U_, tvbpa
}
}
-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)
-{
- proto_item* ti;
- int hf_id = -1;
- header_field_info* hfi;
- int str_len = (int)strlen(key_str);
-
- 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;
-
- hfi = proto_registrar_get_nth(hf_id);
- DISSECTOR_ASSERT(hfi != NULL);
-
- ti = proto_tree_add_item(tree, hfi, 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));
- }
- return ti;
-
-}
-static void before_member(void *tvbparse_data, const void *wanted_data _U_, tvbparse_elem_t *tok) {
+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;
- ti = proto_tree_add_item(tree, &hfi_json_member, tok->tvb, tok->offset, tok->len, ENC_NA);
+ char* key_string = json_string_unescape(tok->sub, FALSE);
+ ti = proto_tree_add_string(tree, &hfi_json_member, tok->tvb, tok->offset, tok->len, key_string);
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, '/');
+ wmem_stack_push(data->stack_path, path);
+ wmem_stack_push(data->stack_path, key_string);
+
if (json_compact) {
proto_tree *tree_compact = (proto_tree *)wmem_stack_peek(data->stack_compact);
proto_tree *subtree_compact;
@@ -396,10 +656,9 @@ static void before_member(void *tvbparse_data, const void *wanted_data _U_, tvbp
tvbparse_elem_t *key_tok = tok->sub;
if (key_tok && key_tok->id == JSON_TOKEN_STRING) {
- char *key_str = json_string_unescape(key_tok);
- ti_compact = json_key_lookup(tree_compact, tok, key_str, data->pinfo);
+ ti_compact = json_key_lookup(tree_compact, tok, key_string, data->pinfo);
if (!ti_compact) {
- ti_compact = proto_tree_add_none_format(tree_compact, &hfi_json_member_compact, tok->tvb, tok->offset, tok->len, "%s:", key_str);
+ ti_compact = proto_tree_add_none_format(tree_compact, &hfi_json_member_compact, tok->tvb, tok->offset, tok->len, "%s:", key_string);
}
} else {
ti_compact = proto_tree_add_item(tree_compact, &hfi_json_member_compact, tok->tvb, tok->offset, tok->len, ENC_NA);
@@ -410,19 +669,32 @@ static void before_member(void *tvbparse_data, const void *wanted_data _U_, tvbp
}
}
-static void after_member(void *tvbparse_data, const void *wanted_data _U_, tvbparse_elem_t *tok) {
+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);
if (tree) {
- tvbparse_elem_t *key_tok = tok->sub;
+ tvbparse_elem_t* key_tok = tok->sub;
if (key_tok && key_tok->id == JSON_TOKEN_STRING) {
- char *key = json_string_unescape(key_tok);
+ char* key = json_string_unescape(key_tok, FALSE);
proto_tree_add_string(tree, &hfi_json_key, key_tok->tvb, key_tok->offset, key_tok->len, key);
- proto_item_append_text(tree, " Key: %s", key);
+ }
+ }
+
+ // 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, &hfi_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);
}
}
@@ -432,7 +704,8 @@ static void after_member(void *tvbparse_data, const void *wanted_data _U_, tvbpa
}
}
-static void before_array(void *tvbparse_data, const void *wanted_data _U_, tvbparse_elem_t *tok) {
+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);
@@ -444,16 +717,32 @@ static void before_array(void *tvbparse_data, const void *wanted_data _U_, tvbpa
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, "[]");
+
if (json_compact) {
JSON_ARRAY_BEGIN(data);
}
}
-static void after_array(void *tvbparse_data, const void *wanted_data _U_, tvbparse_elem_t *elem _U_) {
+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);
@@ -468,198 +757,79 @@ static void after_array(void *tvbparse_data, const void *wanted_data _U_, tvbpar
}
}
-static int
-json_tvb_memcpy_utf8(char *buf, tvbuff_t *tvb, int offset, int offset_max)
-{
- int len = ws_utf8_char_len((guint8) *buf);
-
- /* XXX, before moving to core API check if it's off-by-one safe.
- * For JSON analyzer it's not a problem
- * (string always terminated by ", which is not valid UTF-8 continuation character) */
- if (len == -1 || ((guint) (offset + len)) >= (guint) offset_max) {
- *buf = '?';
- return 1;
- }
+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;
- /* assume it's valid UTF-8 */
- tvb_memcpy(tvb, buf + 1, offset + 1, (size_t)len - 1);
+ 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 (!g_utf8_validate(buf, len, NULL)) {
- *buf = '?';
- return 1;
+ 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;
}
- return len;
-}
-
-static char *json_string_unescape(tvbparse_elem_t *tok)
-{
- char *str = (char *)wmem_alloc(wmem_packet_scope(), (size_t)tok->len - 1);
- int i, j;
-
- j = 0;
- for (i = 1; i < tok->len - 1; i++) {
- guint8 ch = tvb_get_guint8(tok->tvb, tok->offset + i);
- int bin;
-
- if (ch == '\\') {
- i++;
-
- ch = tvb_get_guint8(tok->tvb, tok->offset + i);
- switch (ch) {
- case '\"':
- case '\\':
- case '/':
- str[j++] = ch;
- break;
-
- case 'b':
- str[j++] = '\b';
- break;
- case 'f':
- str[j++] = '\f';
- break;
- case 'n':
- str[j++] = '\n';
- break;
- case 'r':
- str[j++] = '\r';
- break;
- case 't':
- str[j++] = '\t';
- break;
-
- case 'u':
- {
- guint32 unicode_hex = 0;
- gboolean valid = TRUE;
- int k;
-
- for (k = 0; k < 4; k++) {
- i++;
- unicode_hex <<= 4;
-
- ch = tvb_get_guint8(tok->tvb, tok->offset + i);
- bin = ws_xton(ch);
- if (bin == -1) {
- valid = FALSE;
- break;
- }
- unicode_hex |= bin;
- }
-
- if ((IS_LEAD_SURROGATE(unicode_hex))) {
- ch = tvb_get_guint8(tok->tvb, tok->offset + i + 1);
-
- if (ch == '\\') {
- i++;
- ch = tvb_get_guint8(tok->tvb, tok->offset + i + 1);
- if (ch == 'u') {
- guint16 lead_surrogate = unicode_hex;
- guint16 trail_surrogate = 0;
- i++;
-
- for (k = 0; k < 4; k++) {
- i++;
- trail_surrogate <<= 4;
-
- ch = tvb_get_guint8(tok->tvb, tok->offset + i);
- bin = ws_xton(ch);
- if (bin == -1) {
- valid = FALSE;
- break;
- }
- trail_surrogate |= bin;
- }
-
- if ((IS_TRAIL_SURROGATE(trail_surrogate))) {
- unicode_hex = SURROGATE_VALUE(lead_surrogate,trail_surrogate);
- } else {
- valid = FALSE;
- }
- } else {
- valid = FALSE;
- }
- } else {
- valid = FALSE;
- }
- } else if ((IS_TRAIL_SURROGATE(unicode_hex))) {
- i++;
- valid = FALSE;
- }
-
- if (valid && g_unichar_validate(unicode_hex) && g_unichar_isprint(unicode_hex)) {
- /* \uXXXX => 6 bytes */
- int charlen = g_unichar_to_utf8(unicode_hex, &str[j]);
- j += charlen;
- } else
- str[j++] = '?';
- break;
- }
+ // extended path based filtering
+ char* key_string = (char*)wmem_stack_pop(data->stack_path);
+ char* path = (char*)wmem_stack_pop(data->stack_path);
- default:
- /* not valid by JSON grammar (also tvbparse rules should not allow it) */
- DISSECTOR_ASSERT_NOT_REACHED();
- break;
- }
+ char* value_str = json_string_unescape(tok, TRUE);
+ 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);
- } else {
- int utf_len;
-
- str[j] = ch;
- /* XXX if it's not valid UTF-8 character, add some expert info? (it violates JSON grammar) */
- utf_len = json_tvb_memcpy_utf8(&str[j], tok->tvb, tok->offset + i, tok->offset + tok->len);
- j += utf_len;
- i += (utf_len - 1);
- }
+ 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);
}
- str[j] = '\0';
-
- return str;
-}
-
-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 = JSON_TOKEN_INVALID;
- if (tok->sub)
- value_id = (json_token_type_t)tok->sub->id;
+ 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)
- proto_tree_add_string(tree, &hfi_json_value_string, tok->tvb, tok->offset, tok->len, json_string_unescape(tok));
+ {
+ char* value_string_without_quotation_marks = json_string_unescape(tok, FALSE);
+ proto_tree_add_string(tree, &hfi_json_value_string, tok->tvb, tok->offset, tok->len, value_string_without_quotation_marks);
+ }
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, &hfi_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);
+
break;
case JSON_TOKEN_FALSE:
proto_tree_add_item(tree, &hfi_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);
+
break;
case JSON_TOKEN_TRUE:
proto_tree_add_item(tree, &hfi_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);
- break;
- case JSON_OBJECT:
- case JSON_ARRAY:
- /* already added */
break;
default:
@@ -674,10 +844,6 @@ static void after_value(void *tvbparse_data, const void *wanted_data _U_, tvbpar
char *val_str = tvb_get_string_enc(wmem_packet_scope(), tok->tvb, tok->offset, tok->len, ENC_UTF_8);
- if (value_id == JSON_OBJECT || value_id == JSON_ARRAY) {
- return;
- }
-
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);
json_array_index_increment(data);
@@ -688,7 +854,8 @@ static void after_value(void *tvbparse_data, const void *wanted_data _U_, tvbpar
}
}
-static void init_json_parser(void) {
+static void
+init_json_parser(void) {
static tvbparse_wanted_t _want_object;
static tvbparse_wanted_t _want_array;
@@ -886,19 +1053,9 @@ register_static_headers(void) {
json_data_decoder_rec->json_data_decoder = dissect_ueepspdnconnection;
g_hash_table_insert(header_fields_hash, header_name, json_data_decoder_rec);
-#define JSON_NUM_HF_WITH_FUNCTION 1
-
- //for (guint i = JSON_NUM_HF_WITH_FUNCTION; 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 = NULL;
- // 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)
{
@@ -920,6 +1077,9 @@ proto_register_json(void)
&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,
@@ -930,7 +1090,8 @@ proto_register_json(void)
&hfi_json_object_compact,
&hfi_json_member_compact,
&hfi_json_array_item_compact,
- &hfi_json_binary_data_compact
+ &hfi_json_binary_data_compact,
+ &hfi_json_ignored_leading_bytes
};
#endif
@@ -952,11 +1113,20 @@ proto_register_json(void)
"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