diff options
-rw-r--r-- | doc/tshark.pod | 4 | ||||
-rw-r--r-- | epan/print.c | 231 | ||||
-rw-r--r-- | epan/print.h | 13 | ||||
-rw-r--r-- | file.c | 4 | ||||
-rw-r--r-- | tfshark.c | 2 | ||||
-rw-r--r-- | tshark.c | 10 |
6 files changed, 202 insertions, 62 deletions
diff --git a/doc/tshark.pod b/doc/tshark.pod index 7e6d0247d5..5b115cd175 100644 --- a/doc/tshark.pod +++ b/doc/tshark.pod @@ -291,8 +291,8 @@ from such an account, it will not list any interfaces. =item -e E<lt>fieldE<gt> -Add a field to the list of fields to display if B<-T fields> is -selected. This option can be used multiple times on the command line. +Add a field to the list of fields to display if B<-T ek|fields|json|pdml> +is selected. This option can be used multiple times on the command line. At least one field must be provided if the B<-T fields> option is selected. Column names may be used prefixed with "_ws.col." diff --git a/epan/print.c b/epan/print.c index cf7fa148ed..db3acb3641 100644 --- a/epan/print.c +++ b/epan/print.c @@ -78,16 +78,17 @@ typedef struct { } write_field_data_t; struct _output_fields { - gboolean print_bom; - gboolean print_header; - gchar separator; - gchar occurrence; - gchar aggregator; - GPtrArray *fields; - GHashTable *field_indicies; - GPtrArray **field_values; - gchar quote; - gboolean includes_col_fields; + gboolean print_bom; + gboolean print_header; + gchar separator; + gchar occurrence; + gchar aggregator; + GPtrArray *fields; + GHashTable *field_indicies; + GPtrArray **field_values; + gchar quote; + gboolean includes_col_fields; + fields_format format; }; static gchar *get_field_hex_value(GSList *src_list, field_info *fi); @@ -285,10 +286,13 @@ static gboolean check_protocolfilter(gchar **protocolfilter, const char *str) } void -write_pdml_proto_tree(gchar **protocolfilter, epan_dissect_t *edt, FILE *fh) +write_pdml_proto_tree(output_fields_t* fields, gchar **protocolfilter, epan_dissect_t *edt, FILE *fh) { write_pdml_data data; + g_assert(edt); + g_assert(fh); + /* Create the output */ data.level = 0; data.fh = fh; @@ -301,14 +305,19 @@ write_pdml_proto_tree(gchar **protocolfilter, epan_dissect_t *edt, FILE *fh) /* Print a "geninfo" protocol as required by PDML */ print_pdml_geninfo(edt->tree, fh); - proto_tree_children_foreach(edt->tree, proto_tree_write_node_pdml, - &data); + if (fields == NULL || fields->fields == NULL) { + proto_tree_children_foreach(edt->tree, proto_tree_write_node_pdml, + &data); + } else { + fields->format = FORMAT_XML; + write_fields_proto_tree(fields, edt, NULL, fh); + } fprintf(fh, "</packet>\n\n"); } void -write_json_proto_tree(print_args_t *print_args, gchar **protocolfilter, epan_dissect_t *edt, FILE *fh) +write_json_proto_tree(output_fields_t* fields, print_args_t *print_args, gchar **protocolfilter, epan_dissect_t *edt, FILE *fh) { write_json_data data; char ts[30]; @@ -316,6 +325,9 @@ write_json_proto_tree(print_args_t *print_args, gchar **protocolfilter, epan_dis struct tm * timeinfo; static gboolean is_first = TRUE; + g_assert(edt); + g_assert(fh); + /* Create the output */ data.level = 1; data.fh = fh; @@ -339,8 +351,13 @@ write_json_proto_tree(print_args_t *print_args, gchar **protocolfilter, epan_dis fputs(" \"_source\": {\n", fh); fputs(" \"layers\": {\n", fh); - proto_tree_children_foreach(edt->tree, proto_tree_write_node_json, - &data); + if (fields == NULL || fields->fields == NULL) { + proto_tree_children_foreach(edt->tree, proto_tree_write_node_json, + &data); + } else { + fields->format = FORMAT_JSON; + write_fields_proto_tree(fields, edt, NULL, fh); + } fputs(" }\n", fh); fputs(" }\n", fh); @@ -349,7 +366,7 @@ write_json_proto_tree(print_args_t *print_args, gchar **protocolfilter, epan_dis } void -write_ek_proto_tree(print_args_t *print_args, gchar **protocolfilter, epan_dissect_t *edt, FILE *fh) +write_ek_proto_tree(output_fields_t* fields, print_args_t *print_args, gchar **protocolfilter, epan_dissect_t *edt, FILE *fh) { write_json_data data; char ts[30]; @@ -358,6 +375,9 @@ write_ek_proto_tree(print_args_t *print_args, gchar **protocolfilter, epan_disse nstime_t *timestamp; GPtrArray *finfo_array; + g_assert(edt); + g_assert(fh); + /* Create the output */ data.level = 0; data.fh = fh; @@ -366,7 +386,6 @@ write_ek_proto_tree(print_args_t *print_args, gchar **protocolfilter, epan_disse data.filter = protocolfilter; data.print_hex = print_args->print_hex; - timeinfo = localtime(&t); strftime(ts, 30, "%Y-%m-%d", timeinfo); @@ -390,8 +409,14 @@ write_ek_proto_tree(print_args_t *print_args, gchar **protocolfilter, epan_disse 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, - &data); + if (fields == NULL || fields->fields == NULL) { + proto_tree_children_foreach(edt->tree, proto_tree_write_node_ek, + &data); + } else { + fields->format = FORMAT_EK; + write_fields_proto_tree(fields, edt, NULL, fh); + } + fputs("}}\n", fh); } @@ -2048,44 +2073,152 @@ void write_fields_proto_tree(output_fields_t *fields, epan_dissect_t *edt, colum proto_tree_children_foreach(edt->tree, proto_tree_get_node_field_values, &data); - if (fields->includes_col_fields) { - for (col = 0; col < cinfo->num_cols; col++) { - /* Prepend COLUMN_FIELD_FILTER as the field name */ - col_name = g_strdup_printf("%s%s", COLUMN_FIELD_FILTER, cinfo->columns[col].col_title); - field_index = g_hash_table_lookup(fields->field_indicies, col_name); - g_free(col_name); - - if (NULL != field_index) { - format_field_values(fields, field_index, g_strdup(cinfo->columns[col].col_data)); + switch (fields->format) { + case FORMAT_CSV: + if (fields->includes_col_fields) { + for (col = 0; col < cinfo->num_cols; col++) { + /* Prepend COLUMN_FIELD_FILTER as the field name */ + col_name = g_strdup_printf("%s%s", COLUMN_FIELD_FILTER, cinfo->columns[col].col_title); + field_index = g_hash_table_lookup(fields->field_indicies, col_name); + g_free(col_name); + + if (NULL != field_index) { + format_field_values(fields, field_index, g_strdup(cinfo->columns[col].col_data)); + } } } - } - for(i = 0; i < fields->fields->len; ++i) { - if (0 != i) { - fputc(fields->separator, fh); + for(i = 0; i < fields->fields->len; ++i) { + if (0 != i) { + fputc(fields->separator, fh); + } + if (NULL != fields->field_values[i]) { + GPtrArray *fv_p; + gchar * str; + gsize j; + fv_p = fields->field_values[i]; + if (fields->quote != '\0') { + fputc(fields->quote, fh); + } + + /* Output the array of (partial) field values */ + for (j = 0; j < g_ptr_array_len(fv_p); j++ ) { + str = (gchar *)g_ptr_array_index(fv_p, j); + fputs(str, fh); + g_free(str); + } + if (fields->quote != '\0') { + fputc(fields->quote, fh); + } + g_ptr_array_free(fv_p, TRUE); /* get ready for the next packet */ + fields->field_values[i] = NULL; + } } - if (NULL != fields->field_values[i]) { - GPtrArray *fv_p; - gchar * str; - gsize j; - fv_p = fields->field_values[i]; - if (fields->quote != '\0') { - fputc(fields->quote, fh); + break; + case FORMAT_XML: + for(i = 0; i < fields->fields->len; ++i) { + gchar *field = (gchar *)g_ptr_array_index(fields->fields, i); + + if (NULL != fields->field_values[i]) { + GPtrArray *fv_p; + gchar * str; + gsize j; + fv_p = fields->field_values[i]; + + /* Output the array of (partial) field values */ + for (j = 0; j < (g_ptr_array_len(fv_p)) - 1; j+=2 ) { + str = (gchar *)g_ptr_array_index(fv_p, j); + + fprintf(fh, " <field name=\"%s\" value=", field); + fputs("\"", fh); + print_escaped_xml(fh, str); + fputs("\"/>\n", fh); + g_free(str); + } + g_ptr_array_free(fv_p, TRUE); /* get ready for the next packet */ + fields->field_values[i] = NULL; } + } + break; + case FORMAT_JSON: + for(i = 0; i < fields->fields->len; ++i) { + gchar *field = (gchar *)g_ptr_array_index(fields->fields, i); + + if (NULL != fields->field_values[i]) { + GPtrArray *fv_p; + gchar * str; + gsize j; + fv_p = fields->field_values[i]; - /* Output the array of (partial) field values */ - for (j = 0; j < g_ptr_array_len(fv_p); j++ ) { - str = (gchar *)g_ptr_array_index(fv_p, j); - fputs(str, fh); - g_free(str); + /* Output the array of (partial) field values */ + for (j = 0; j < (g_ptr_array_len(fv_p)) - 1; j+=2 ) { + str = (gchar *)g_ptr_array_index(fv_p, j); + + if (j == 0) { + fprintf(fh, " \"%s\": [", field); + } + fputs("\"", fh); + print_escaped_json(fh, str); + fputs("\"", fh); + g_free(str); + + if (j + 2 < (g_ptr_array_len(fv_p)) - 1) { + fputs(",", fh); + } else { + fputs("]", fh); + + if ( (i + 1 < fields->fields->len) && (g_ptr_array_len(fields->field_values[i + 1]) > 1) ) { + fputs(",\n", fh); + } else { + fputs("\n", fh); + } + } + } + g_ptr_array_free(fv_p, TRUE); /* get ready for the next packet */ + fields->field_values[i] = NULL; } - if (fields->quote != '\0') { - fputc(fields->quote, fh); + } + break; + case FORMAT_EK: + for(i = 0; i < fields->fields->len; ++i) { + gchar *field = (gchar *)g_ptr_array_index(fields->fields, i); + + if (NULL != fields->field_values[i]) { + GPtrArray *fv_p; + gchar * str; + gsize j; + fv_p = fields->field_values[i]; + + /* Output the array of (partial) field values */ + for (j = 0; j < (g_ptr_array_len(fv_p)) - 1; j+=2 ) { + str = (gchar *)g_ptr_array_index(fv_p, j); + + if (j == 0) { + fputs("\"", fh); + print_escaped_ek(fh, field); + fputs("\": [", fh); + } + fputs("\"", fh); + print_escaped_json(fh, str); + fputs("\"", fh); + g_free(str); + + if (j + 2 < (g_ptr_array_len(fv_p)) - 1) { + fputs(",", fh); + } else { + fputs("]", fh); + + if ( (i + 1 < fields->fields->len) && (g_ptr_array_len(fields->field_values[i + 1]) > 1) ) { + fputs(",", fh); + } else { + } + } + } + g_ptr_array_free(fv_p, TRUE); /* get ready for the next packet */ + fields->field_values[i] = NULL; } - g_ptr_array_free(fv_p, TRUE); /* get ready for the next packet */ - fields->field_values[i] = NULL; } + break; } } diff --git a/epan/print.h b/epan/print.h index c9cdda3c86..dc2c7ad081 100644 --- a/epan/print.h +++ b/epan/print.h @@ -79,6 +79,13 @@ typedef struct { * each new packet */ } print_args_t; +typedef enum { + FORMAT_CSV, /* CSV */ + FORMAT_JSON, /* JSON */ + FORMAT_EK, /* JSON bulk insert to Elasticsearch */ + FORMAT_XML, /* PDML output */ +} fields_format; + /* * Print user selected list of fields */ @@ -105,14 +112,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(gchar **protocolfilter, epan_dissect_t *edt, FILE *fh); +WS_DLL_PUBLIC void write_pdml_proto_tree(output_fields_t* fields, 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 **protocolfilter, epan_dissect_t *edt, FILE *fh); +WS_DLL_PUBLIC void write_json_proto_tree(output_fields_t* fields, 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 **protocolfilter, epan_dissect_t *edt, FILE *fh); +WS_DLL_PUBLIC void write_ek_proto_tree(output_fields_t* fields, 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(NULL, &args->edt, args->fh); + write_pdml_proto_tree(NULL, NULL, &args->edt, args->fh); epan_dissect_reset(&args->edt); @@ -2838,7 +2838,7 @@ write_json_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_json_proto_tree(args->print_args, NULL, &args->edt, args->fh); + write_json_proto_tree(NULL, args->print_args, NULL, &args->edt, args->fh); epan_dissect_reset(&args->edt); @@ -2072,7 +2072,7 @@ print_packet(capture_file *cf, epan_dissect_t *edt) break; case WRITE_XML: - write_pdml_proto_tree(NULL, edt, stdout); + write_pdml_proto_tree(NULL, NULL, edt, stdout); printf("\n"); return !ferror(stdout); case WRITE_FIELDS: @@ -1365,9 +1365,9 @@ main(int argc, char *argv[]) } /* If we specified output fields, but not the output field type... */ - if (WRITE_FIELDS != output_action && 0 != output_fields_num_fields(output_fields)) { + if ((WRITE_FIELDS != output_action && WRITE_XML != output_action && WRITE_JSON != output_action && WRITE_EK != output_action) && 0 != output_fields_num_fields(output_fields)) { cmdarg_err("Output fields were specified with \"-e\", " - "but \"-Tfields\" was not specified."); + "but \"-Tek, -Tfields, -Tjson or -Tpdml\" was not specified."); return 1; } else if (WRITE_FIELDS == output_action && 0 == output_fields_num_fields(output_fields)) { cmdarg_err("\"-Tfields\" was specified, but no fields were " @@ -3834,7 +3834,7 @@ print_packet(capture_file *cf, epan_dissect_t *edt) break; case WRITE_XML: - write_pdml_proto_tree(protocolfilter, edt, stdout); + write_pdml_proto_tree(output_fields, 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, protocolfilter, edt, stdout); + write_json_proto_tree(output_fields, &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, protocolfilter, edt, stdout); + write_ek_proto_tree(output_fields, &print_args, protocolfilter, edt, stdout); printf("\n"); return !ferror(stdout); } |