diff options
author | Martin Kacer <kacer.martin@gmail.com> | 2016-06-20 11:03:40 +0200 |
---|---|---|
committer | Guy Harris <guy@alum.mit.edu> | 2016-06-21 16:57:59 +0000 |
commit | c3f3bd7fa89af1ccd15440cf401697fc32814ed6 (patch) | |
tree | 2b8ada654c02b0a59ae9eb7fde8eba7f16564eab | |
parent | df231d9c52d8e94d2ef48f83beeef1455a0e7ce9 (diff) |
tshark JSON and Elasticsearch output fix
Fixed json and ek escape function
Fixed -j protocol filter to do exact match
Fixed -T json to correctly close json
Added -j protocol filter also to pdml output
Bug: 11754
Change-Id: I02f274e4a5a02346922b37bbe946c10340c242ea
Reviewed-on: https://code.wireshark.org/review/16034
Petri-Dish: Pascal Quantin <pascal.quantin@gmail.com>
Tested-by: Petri Dish Buildbot <buildbot-no-reply@wireshark.org>
Reviewed-by: Pascal Quantin <pascal.quantin@gmail.com>
Reviewed-by: Guy Harris <guy@alum.mit.edu>
-rw-r--r-- | doc/tshark.pod | 8 | ||||
-rw-r--r-- | epan/print.c | 160 | ||||
-rw-r--r-- | epan/print.h | 6 | ||||
-rw-r--r-- | file.c | 2 | ||||
-rw-r--r-- | tfshark.c | 2 | ||||
-rw-r--r-- | tshark.c | 12 |
6 files changed, 140 insertions, 50 deletions
diff --git a/doc/tshark.pod b/doc/tshark.pod index 2ee54edbc3..7e6d0247d5 100644 --- a/doc/tshark.pod +++ b/doc/tshark.pod @@ -22,7 +22,7 @@ S<[ B<-g> ]> S<[ B<-h> ]> S<[ B<-H> E<lt>input hosts fileE<gt> ]> S<[ B<-i> E<lt>capture interfaceE<gt>|- ]> -S<[ B<-j> E<lt>json match filterE<gt> ]> +S<[ B<-j> E<lt>protocol match filterE<gt> ]> S<[ B<-I> ]> S<[ B<-K> E<lt>keytabE<gt> ]> S<[ B<-l> ]> @@ -535,10 +535,10 @@ If used after an B<-i> option, it enables the monitor mode for the interface specified by the last B<-i> option occurring before this option. -=item -j E<lt>json match filterE<gt> +=item -j E<lt>protocol match filterE<gt> -JSON match filter used for json|ek output file types. -JSON parent node containing multiple child nodes is only included, +Protocol match filter used for ek|json|pdml output file types. +Parent node containing multiple child nodes is only included, if the name is found in the filter. Example: B<-j "http tcp ip"> diff --git a/epan/print.c b/epan/print.c index 92e9bfe73d..66bc08acf3 100644 --- a/epan/print.c +++ b/epan/print.c @@ -60,6 +60,7 @@ typedef struct { FILE *fh; GSList *src_list; epan_dissect_t *edt; + gchar **filter; } write_pdml_data; typedef struct { @@ -67,7 +68,7 @@ typedef struct { FILE *fh; GSList *src_list; epan_dissect_t *edt; - gchar *filter; + gchar **filter; gboolean print_hex; } write_json_data; @@ -259,11 +260,32 @@ write_pdml_preamble(FILE *fh, const gchar *filename) void write_json_preamble(FILE *fh) { - fputs("{\n", fh); + fputs("[\n", fh); +} + +/* Check if the str match the protocolfilter. json_filter is space + delimited string and str need to exact-match to one of the value. */ +gboolean check_protocolfilter(gchar **protocolfilter, const char *str) +{ + gboolean res = FALSE; + gchar **ptr; + + if (str == NULL || protocolfilter == NULL) { + return FALSE; + } + + for (ptr = protocolfilter; *ptr; ptr++) { + if (strcmp(*ptr, str) == 0) { + res = TRUE; + break; + } + } + + return res; } void -write_pdml_proto_tree(epan_dissect_t *edt, FILE *fh) +write_pdml_proto_tree(gchar **protocolfilter, epan_dissect_t *edt, FILE *fh) { write_pdml_data data; @@ -272,6 +294,7 @@ write_pdml_proto_tree(epan_dissect_t *edt, FILE *fh) data.fh = fh; data.src_list = edt->pi.data_src; data.edt = edt; + data.filter = protocolfilter; fprintf(fh, "<packet>\n"); @@ -285,41 +308,48 @@ write_pdml_proto_tree(epan_dissect_t *edt, FILE *fh) } void -write_json_proto_tree(print_args_t *print_args, gchar *jsonfilter, epan_dissect_t *edt, FILE *fh) +write_json_proto_tree(print_args_t *print_args, gchar **protocolfilter, epan_dissect_t *edt, FILE *fh) { write_json_data data; char ts[30]; time_t t = time(NULL); struct tm * timeinfo; + static gboolean is_first = TRUE; /* Create the output */ - data.level = 0; + data.level = 1; data.fh = fh; data.src_list = edt->pi.data_src; data.edt = edt; - data.filter = jsonfilter; + data.filter = protocolfilter; data.print_hex = print_args->print_hex; timeinfo = localtime(&t); strftime(ts, 30, "%Y-%m-%d", timeinfo); - fprintf(fh, " \"_index\": \"packets-%s\",\n", ts); - fputs(" \"_type\": \"pcap_file\",\n", fh); - fputs(" \"_score\": null,\n", fh); - fputs(" \"_source\": {\n", fh); - fputs(" \"layers\": {\n", fh); + if (!is_first) + fputs(" ,\n", fh); + else + is_first = FALSE; + + fputs(" {\n", fh); + fprintf(fh, " \"_index\": \"packets-%s\",\n", ts); + fputs(" \"_type\": \"pcap_file\",\n", fh); + fputs(" \"_score\": null,\n", fh); + fputs(" \"_source\": {\n", fh); + fputs(" \"layers\": {\n", fh); proto_tree_children_foreach(edt->tree, proto_tree_write_node_json, &data); + fputs(" }\n", fh); fputs(" }\n", fh); - - fputs(" },\n", fh); + fputs(" }", fh); } void -write_ek_proto_tree(print_args_t *print_args, gchar *jsonfilter, epan_dissect_t *edt, FILE *fh) +write_ek_proto_tree(print_args_t *print_args, gchar **protocolfilter, epan_dissect_t *edt, FILE *fh) { write_json_data data; char ts[30]; @@ -333,7 +363,7 @@ write_ek_proto_tree(print_args_t *print_args, gchar *jsonfilter, epan_dissect_t data.fh = fh; data.src_list = edt->pi.data_src; data.edt = edt; - data.filter = jsonfilter; + data.filter = protocolfilter; data.print_hex = print_args->print_hex; @@ -357,7 +387,7 @@ write_ek_proto_tree(print_args_t *print_args, gchar *jsonfilter, epan_dissect_t fprintf(fh, "{\"index\" : {\"_index\": \"packets-%s\", \"_type\": \"pcap_file\", \"_score\": null}}\n", ts); /* Timestamp added for time indexing in Elasticsearch */ - fprintf(fh, "{\"timestamp\" : \"%ld%03d\", \"layers\" : {", timestamp->secs, timestamp->nsecs/1000000); + fprintf(fh, "{\"timestamp\" : \"%" G_GUINT64_FORMAT "%03d\", \"layers\" : {", (guint64)timestamp->secs, timestamp->nsecs/1000000); proto_tree_children_foreach(edt->tree, proto_tree_write_node_ek, @@ -573,12 +603,23 @@ proto_tree_write_node_pdml(proto_node *node, gpointer data) } } - /* We always print all levels for PDML. Recurse here. */ + /* We print some levels for PDML. Recurse here. */ if (node->first_child != NULL) { - pdata->level++; - proto_tree_children_foreach(node, - proto_tree_write_node_pdml, pdata); - pdata->level--; + if(check_protocolfilter(pdata->filter, fi->hfinfo->abbrev)) { + pdata->level++; + proto_tree_children_foreach(node, + proto_tree_write_node_pdml, pdata); + pdata->level--; + } else { + /* Indent to the correct level */ + for (i = -2; i < pdata->level; i++) { + fputs(" ", pdata->fh); + } + /* print dummy field */ + fputs("<field name=\"filtered\" value=\"", pdata->fh); + print_escaped_xml(pdata->fh, fi->hfinfo->abbrev); + fputs("\" />\n", pdata->fh); + } } /* Take back the extra level we added for fake wrapper protocol */ @@ -760,11 +801,20 @@ proto_tree_write_node_json(proto_node *node, gpointer data) /* We print some levels for JSON. Recurse here. */ if (node->first_child != NULL) { if (pdata->filter != NULL) { - if(strstr(pdata->filter, fi->hfinfo->abbrev) != NULL) { + if(check_protocolfilter(pdata->filter, fi->hfinfo->abbrev)) { pdata->level++; proto_tree_children_foreach(node, proto_tree_write_node_json, pdata); pdata->level--; + } else { + /* Indent to the correct level */ + for (i = -4; i < pdata->level; i++) { + fputs(" ", pdata->fh); + } + /* print dummy field */ + fputs("\"filtered\": \"", pdata->fh); + print_escaped_ek(pdata->fh, fi->hfinfo->abbrev); + fputs("\"\n", pdata->fh); } } else { pdata->level++; @@ -799,7 +849,6 @@ proto_tree_write_node_ek(proto_node *node, gpointer data) char *dfilter_string; int i; gchar *abbrev_escaped = NULL; - size_t abbrev_escaped_len = 0; /* dissection with an invisible proto tree? */ g_assert(fi); @@ -953,8 +1002,7 @@ proto_tree_write_node_ek(proto_node *node, gpointer data) /* to to thread the '.' and '_' equally. The '.' is replace by print_escaped_ek for '_' */ if (fi->hfinfo->abbrev != NULL) { - abbrev_escaped_len = strlen(fi->hfinfo->abbrev) + 1; - if (abbrev_escaped_len > 0) { + if (strlen(fi->hfinfo->abbrev) > 0) { abbrev_escaped = g_strdup(fi->hfinfo->abbrev); i = 0; @@ -968,19 +1016,20 @@ proto_tree_write_node_ek(proto_node *node, gpointer data) } } - if((strstr(pdata->filter, fi->hfinfo->abbrev) != NULL) || (strstr(pdata->filter, abbrev_escaped) != NULL)) { + if(check_protocolfilter(pdata->filter, fi->hfinfo->abbrev) || check_protocolfilter(pdata->filter, abbrev_escaped)) { pdata->level++; proto_tree_children_foreach(node, proto_tree_write_node_ek, pdata); pdata->level--; } else { /* print dummy field */ - fputs("\"filtered\": \"\"", pdata->fh); + fputs("\"filtered\": \"", pdata->fh); + print_escaped_ek(pdata->fh, fi->hfinfo->abbrev); + fputs("\"", pdata->fh); } /* release abbrev_escaped string */ if (abbrev_escaped != NULL) { - abbrev_escaped_len = 0; g_free(abbrev_escaped); } @@ -1104,8 +1153,7 @@ write_pdml_finale(FILE *fh) void write_json_finale(FILE *fh) { - fputs("}\n", fh); - + fputs("]\n", fh); } void @@ -1358,13 +1406,34 @@ print_escaped_json(FILE *fh, const char *unescaped_string) for (p = unescaped_string; *p != '\0'; p++) { switch (*p) { case '"': - fputs(""", fh); + fputs("\\\"", fh); + break; + case '\\': + fputs("\\\\", fh); + break; + case '/': + fputs("\\/", fh); + break; + case '\b': + fputs("\\b", fh); + break; + case '\f': + fputs("\\f", fh); + break; + case '\n': + fputs("\\n", fh); + break; + case '\r': + fputs("\\r", fh); + break; + case '\t': + fputs("\\t", fh); break; default: if (g_ascii_isprint(*p)) fputc(*p, fh); else { - g_snprintf(temp_str, sizeof(temp_str), "%x", (guint8)*p); + g_snprintf(temp_str, sizeof(temp_str), "\\u00%u", (guint8)*p); fputs(temp_str, fh); } } @@ -1382,8 +1451,29 @@ print_escaped_ek(FILE *fh, const char *unescaped_string) for (p = unescaped_string; *p != '\0'; p++) { switch (*p) { case '"': - fputs(""", fh); - break; + fputs("\\\"", fh); + break; + case '\\': + fputs("\\\\", fh); + break; + case '/': + fputs("\\/", fh); + break; + case '\b': + fputs("\\b", fh); + break; + case '\f': + fputs("\\f", fh); + break; + case '\n': + fputs("\\n", fh); + break; + case '\r': + fputs("\\r", fh); + break; + case '\t': + fputs("\\t", fh); + break; case '.': fputs("_", fh); break; @@ -1391,7 +1481,7 @@ print_escaped_ek(FILE *fh, const char *unescaped_string) if (g_ascii_isprint(*p)) fputc(*p, fh); else { - g_snprintf(temp_str, sizeof(temp_str), "\\x%x", (guint8)*p); + g_snprintf(temp_str, sizeof(temp_str), "\\u00%u", (guint8)*p); fputs(temp_str, fh); } } diff --git a/epan/print.h b/epan/print.h index b152ac5f7a..c9cdda3c86 100644 --- a/epan/print.h +++ b/epan/print.h @@ -105,14 +105,14 @@ WS_DLL_PUBLIC gboolean proto_tree_print(print_args_t *print_args, WS_DLL_PUBLIC gboolean print_hex_data(print_stream_t *stream, epan_dissect_t *edt); WS_DLL_PUBLIC void write_pdml_preamble(FILE *fh, const gchar* filename); -WS_DLL_PUBLIC void write_pdml_proto_tree(epan_dissect_t *edt, FILE *fh); +WS_DLL_PUBLIC void write_pdml_proto_tree(gchar **protocolfilter, epan_dissect_t *edt, FILE *fh); WS_DLL_PUBLIC void write_pdml_finale(FILE *fh); WS_DLL_PUBLIC void write_json_preamble(FILE *fh); -WS_DLL_PUBLIC void write_json_proto_tree(print_args_t *print_args, gchar *jsonfilter, epan_dissect_t *edt, FILE *fh); +WS_DLL_PUBLIC void write_json_proto_tree(print_args_t *print_args, gchar **protocolfilter, epan_dissect_t *edt, FILE *fh); WS_DLL_PUBLIC void write_json_finale(FILE *fh); -WS_DLL_PUBLIC void write_ek_proto_tree(print_args_t *print_args, gchar *jsonfilter, epan_dissect_t *edt, FILE *fh); +WS_DLL_PUBLIC void write_ek_proto_tree(print_args_t *print_args, gchar **protocolfilter, epan_dissect_t *edt, FILE *fh); WS_DLL_PUBLIC void write_psml_preamble(column_info *cinfo, FILE *fh); WS_DLL_PUBLIC void write_psml_columns(epan_dissect_t *edt, FILE *fh); @@ -2544,7 +2544,7 @@ write_pdml_packet(capture_file *cf, frame_data *fdata, epan_dissect_run(&args->edt, cf->cd_t, phdr, frame_tvbuff_new(fdata, pd), fdata, NULL); /* Write out the information in that tree. */ - write_pdml_proto_tree(&args->edt, args->fh); + write_pdml_proto_tree(NULL, &args->edt, args->fh); epan_dissect_reset(&args->edt); @@ -2074,7 +2074,7 @@ print_packet(capture_file *cf, epan_dissect_t *edt) break; case WRITE_XML: - write_pdml_proto_tree(edt, stdout); + write_pdml_proto_tree(NULL, edt, stdout); printf("\n"); return !ferror(stdout); case WRITE_FIELDS: @@ -168,7 +168,7 @@ static print_format_e print_format = PR_FMT_TEXT; static print_stream_t *print_stream; static output_fields_t* output_fields = NULL; -static gchar *jsonfilter = NULL; +static gchar **protocolfilter = NULL; /* The line separator used between packets, changeable via the -S option */ static const char *separator = ""; @@ -368,7 +368,7 @@ print_usage(FILE *output) fprintf(output, " -x add output of hex and ASCII dump (Packet Bytes)\n"); fprintf(output, " -T pdml|ps|psml|json|ek|text|fields\n"); fprintf(output, " format of text output (def: text)\n"); - fprintf(output, " -j <jsonfilter> only protocols layers to include if -Tjson, -Tek selected,\n"); + fprintf(output, " -j <protocolfilter> protocols layers filter if -T ek|pdml|json selected,\n"); fprintf(output, " (e.g. \"http tcp ip\",\n"); fprintf(output, " -e <field> field to print if -Tfields selected (e.g. tcp.port,\n"); fprintf(output, " _ws.col.Info)\n"); @@ -1070,7 +1070,7 @@ main(int argc, char *argv[]) } break; case 'j': - jsonfilter = optarg; + protocolfilter = wmem_strsplit(wmem_epan_scope(), optarg, " ", -1); break; case 'W': /* Select extra information to save in our capture file */ /* This is patterned after the -N flag which may not be the best idea. */ @@ -3834,7 +3834,7 @@ print_packet(capture_file *cf, epan_dissect_t *edt) break; case WRITE_XML: - write_pdml_proto_tree(edt, stdout); + write_pdml_proto_tree(protocolfilter, edt, stdout); printf("\n"); return !ferror(stdout); case WRITE_FIELDS: @@ -3843,12 +3843,12 @@ print_packet(capture_file *cf, epan_dissect_t *edt) return !ferror(stdout); case WRITE_JSON: print_args.print_hex = print_hex; - write_json_proto_tree(&print_args, jsonfilter, edt, stdout); + write_json_proto_tree(&print_args, protocolfilter, edt, stdout); printf("\n"); return !ferror(stdout); case WRITE_EK: print_args.print_hex = print_hex; - write_ek_proto_tree(&print_args, jsonfilter, edt, stdout); + write_ek_proto_tree(&print_args, protocolfilter, edt, stdout); printf("\n"); return !ferror(stdout); } |