forked from osmocom/wireshark
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>
This commit is contained in:
parent
df231d9c52
commit
c3f3bd7fa8
|
@ -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">
|
||||
|
|
160
epan/print.c
160
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);
|
||||
}
|
||||
}
|
||||
|
|
|
@ -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);
|
||||
|
|
2
file.c
2
file.c
|
@ -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:
|
||||
|
|
12
tshark.c
12
tshark.c
|
@ -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);
|
||||
}
|
||||
|
|
Loading…
Reference in New Issue