1 /* print.c
2 * Routines for printing packet analysis trees.
3 *
4 * Gilbert Ramirez <gram@alumni.rice.edu>
5 *
6 * Wireshark - Network traffic analyzer
7 * By Gerald Combs <gerald@wireshark.org>
8 * Copyright 1998 Gerald Combs
9 *
10 * SPDX-License-Identifier: GPL-2.0-or-later
11 */
12
13 #include "config.h"
14
15 #include <stdio.h>
16 #include <string.h>
17
18 #include <epan/packet.h>
19 #include <epan/epan.h>
20 #include <epan/epan_dissect.h>
21 #include <epan/to_str.h>
22 #include <epan/to_str.h>
23 #include <epan/expert.h>
24 #include <epan/column.h>
25 #include <epan/column-info.h>
26 #include <epan/color_filters.h>
27 #include <epan/prefs.h>
28 #include <epan/print.h>
29 #include <epan/charsets.h>
30 #include <wsutil/json_dumper.h>
31 #include <wsutil/filesystem.h>
32 #include <wsutil/utf8_entities.h>
33 #include <wsutil/ws_assert.h>
34 #include <ftypes/ftypes-int.h>
35
36 #define PDML_VERSION "0"
37 #define PSML_VERSION "0"
38
39 typedef struct {
40 int level;
41 print_stream_t *stream;
42 gboolean success;
43 GSList *src_list;
44 print_dissections_e print_dissections;
45 gboolean print_hex_for_data;
46 packet_char_enc encoding;
47 GHashTable *output_only_tables; /* output only these protocols */
48 } print_data;
49
50 typedef struct {
51 int level;
52 FILE *fh;
53 GSList *src_list;
54 gchar **filter;
55 pf_flags filter_flags;
56 } write_pdml_data;
57
58 typedef struct {
59 GSList *src_list;
60 gchar **filter;
61 pf_flags filter_flags;
62 gboolean print_hex;
63 gboolean print_text;
64 proto_node_children_grouper_func node_children_grouper;
65 json_dumper *dumper;
66 } write_json_data;
67
68 typedef struct {
69 output_fields_t *fields;
70 epan_dissect_t *edt;
71 } write_field_data_t;
72
73 struct _output_fields {
74 gboolean print_bom;
75 gboolean print_header;
76 gchar separator;
77 gchar occurrence;
78 gchar aggregator;
79 GPtrArray *fields;
80 GHashTable *field_indicies;
81 GPtrArray **field_values;
82 gchar quote;
83 gboolean includes_col_fields;
84 };
85
86 static gchar *get_field_hex_value(GSList *src_list, field_info *fi);
87 static void proto_tree_print_node(proto_node *node, gpointer data);
88 static void proto_tree_write_node_pdml(proto_node *node, gpointer data);
89 static void proto_tree_write_node_ek(proto_node *node, write_json_data *data);
90 static const guint8 *get_field_data(GSList *src_list, field_info *fi);
91 static void pdml_write_field_hex_value(write_pdml_data *pdata, field_info *fi);
92 static void json_write_field_hex_value(write_json_data *pdata, field_info *fi);
93 static gboolean print_hex_data_buffer(print_stream_t *stream, const guchar *cp,
94 guint length, packet_char_enc encoding);
95 static void write_specified_fields(fields_format format,
96 output_fields_t *fields,
97 epan_dissect_t *edt, column_info *cinfo,
98 FILE *fh,
99 json_dumper *dumper);
100 static void print_escaped_xml(FILE *fh, const char *unescaped_string);
101 static void print_escaped_csv(FILE *fh, const char *unescaped_string);
102
103 typedef void (*proto_node_value_writer)(proto_node *, write_json_data *);
104 static void write_json_index(json_dumper *dumper, epan_dissect_t *edt);
105 static void write_json_proto_node_list(GSList *proto_node_list_head, write_json_data *data);
106 static void write_json_proto_node(GSList *node_values_head,
107 const char *suffix,
108 proto_node_value_writer value_writer,
109 write_json_data *data);
110 static void write_json_proto_node_value_list(GSList *node_values_head,
111 proto_node_value_writer value_writer,
112 write_json_data *data);
113 static void write_json_proto_node_filtered(proto_node *node, write_json_data *data);
114 static void write_json_proto_node_hex_dump(proto_node *node, write_json_data *data);
115 static void write_json_proto_node_dynamic(proto_node *node, write_json_data *data);
116 static void write_json_proto_node_children(proto_node *node, write_json_data *data);
117 static void write_json_proto_node_value(proto_node *node, write_json_data *data);
118 static void write_json_proto_node_no_value(proto_node *node, write_json_data *data);
119 static const char *proto_node_to_json_key(proto_node *node);
120
121 static void print_pdml_geninfo(epan_dissect_t *edt, FILE *fh);
122 static void write_ek_summary(column_info *cinfo, write_json_data *pdata);
123
124 static void proto_tree_get_node_field_values(proto_node *node, gpointer data);
125
126 /* Cache the protocols and field handles that the print functionality needs
127 This helps break explicit dependency on the dissectors. */
128 static int proto_data = -1;
129 static int proto_frame = -1;
130
print_cache_field_handles(void)131 void print_cache_field_handles(void)
132 {
133 proto_data = proto_get_id_by_short_name("Data");
134 proto_frame = proto_get_id_by_short_name("Frame");
135 }
136
137 gboolean
proto_tree_print(print_dissections_e print_dissections,gboolean print_hex,epan_dissect_t * edt,GHashTable * output_only_tables,print_stream_t * stream)138 proto_tree_print(print_dissections_e print_dissections, gboolean print_hex,
139 epan_dissect_t *edt, GHashTable *output_only_tables,
140 print_stream_t *stream)
141 {
142 print_data data;
143
144 /* Create the output */
145 data.level = 0;
146 data.stream = stream;
147 data.success = TRUE;
148 data.src_list = edt->pi.data_src;
149 data.encoding = (packet_char_enc)edt->pi.fd->encoding;
150 data.print_dissections = print_dissections;
151 /* If we're printing the entire packet in hex, don't
152 print uninterpreted data fields in hex as well. */
153 data.print_hex_for_data = !print_hex;
154 data.output_only_tables = output_only_tables;
155
156 proto_tree_children_foreach(edt->tree, proto_tree_print_node, &data);
157 return data.success;
158 }
159
160 /* Print a tree's data, and any child nodes. */
161 static void
proto_tree_print_node(proto_node * node,gpointer data)162 proto_tree_print_node(proto_node *node, gpointer data)
163 {
164 field_info *fi = PNODE_FINFO(node);
165 print_data *pdata = (print_data*) data;
166 const guint8 *pd;
167 gchar label_str[ITEM_LABEL_LENGTH];
168 gchar *label_ptr;
169
170 /* dissection with an invisible proto tree? */
171 ws_assert(fi);
172
173 /* Don't print invisible entries. */
174 if (proto_item_is_hidden(node) && (prefs.display_hidden_proto_items == FALSE))
175 return;
176
177 /* Give up if we've already gotten an error. */
178 if (!pdata->success)
179 return;
180
181 /* was a free format label produced? */
182 if (fi->rep) {
183 label_ptr = fi->rep->representation;
184 }
185 else { /* no, make a generic label */
186 label_ptr = label_str;
187 proto_item_fill_label(fi, label_str);
188 }
189
190 if (proto_item_is_generated(node))
191 label_ptr = g_strconcat("[", label_ptr, "]", NULL);
192
193 pdata->success = print_line(pdata->stream, pdata->level, label_ptr);
194
195 if (proto_item_is_generated(node))
196 g_free(label_ptr);
197
198 if (!pdata->success)
199 return;
200
201 /*
202 * If -O is specified, only display the protocols which are in the
203 * lookup table. Only check on the first level: once we start printing
204 * a tree, print the rest of the subtree. Otherwise we won't print
205 * subitems whose abbreviation doesn't match the protocol--for example
206 * text items (whose abbreviation is simply "text").
207 */
208 if ((pdata->output_only_tables != NULL) && (pdata->level == 0)
209 && (g_hash_table_lookup(pdata->output_only_tables, fi->hfinfo->abbrev) == NULL)) {
210 return;
211 }
212
213 /* If it's uninterpreted data, dump it (unless our caller will
214 be printing the entire packet in hex). */
215 if ((fi->hfinfo->id == proto_data) && (pdata->print_hex_for_data)) {
216 /*
217 * Find the data for this field.
218 */
219 pd = get_field_data(pdata->src_list, fi);
220 if (pd) {
221 if (!print_line(pdata->stream, 0, "")) {
222 pdata->success = FALSE;
223 return;
224 }
225 if (!print_hex_data_buffer(pdata->stream, pd,
226 fi->length, pdata->encoding)) {
227 pdata->success = FALSE;
228 return;
229 }
230 }
231 }
232
233 /* If we're printing all levels, or if this node is one with a
234 subtree and its subtree is expanded, recurse into the subtree,
235 if it exists. */
236 ws_assert((fi->tree_type >= -1) && (fi->tree_type < num_tree_types));
237 if ((pdata->print_dissections == print_dissections_expanded) ||
238 ((pdata->print_dissections == print_dissections_as_displayed) &&
239 (fi->tree_type >= 0) && tree_expanded(fi->tree_type))) {
240 if (node->first_child != NULL) {
241 pdata->level++;
242 proto_tree_children_foreach(node,
243 proto_tree_print_node, pdata);
244 pdata->level--;
245 if (!pdata->success)
246 return;
247 }
248 }
249 }
250
251 #define PDML2HTML_XSL "pdml2html.xsl"
252 void
write_pdml_preamble(FILE * fh,const gchar * filename)253 write_pdml_preamble(FILE *fh, const gchar *filename)
254 {
255 time_t t = time(NULL);
256 struct tm * timeinfo;
257 char *fmt_ts;
258 const char *ts;
259
260 /* Create the output */
261 timeinfo = localtime(&t);
262 if (timeinfo != NULL) {
263 fmt_ts = asctime(timeinfo);
264 fmt_ts[strlen(fmt_ts)-1] = 0; /* overwrite \n */
265 ts = fmt_ts;
266 } else
267 ts = "Not representable";
268
269 fprintf(fh, "<?xml version=\"1.0\" encoding=\"utf-8\"?>\n");
270 fprintf(fh, "<?xml-stylesheet type=\"text/xsl\" href=\"" PDML2HTML_XSL "\"?>\n");
271 fprintf(fh, "<!-- You can find " PDML2HTML_XSL " in %s or at https://gitlab.com/wireshark/wireshark/-/raw/master/" PDML2HTML_XSL ". -->\n", get_datafile_dir());
272 fprintf(fh, "<pdml version=\"" PDML_VERSION "\" creator=\"%s/%s\" time=\"%s\" capture_file=\"", PACKAGE, VERSION, ts);
273 if (filename) {
274 /* \todo filename should be converted to UTF-8. */
275 print_escaped_xml(fh, filename);
276 }
277 fprintf(fh, "\">\n");
278 }
279
280 /* Check if the str match the protocolfilter. json_filter is space
281 delimited string and str need to exact-match to one of the value. */
check_protocolfilter(gchar ** protocolfilter,const char * str)282 static gboolean check_protocolfilter(gchar **protocolfilter, const char *str)
283 {
284 gboolean res = FALSE;
285 gchar **ptr;
286
287 if (str == NULL || protocolfilter == NULL) {
288 return FALSE;
289 }
290
291 for (ptr = protocolfilter; *ptr; ptr++) {
292 if (strcmp(*ptr, str) == 0) {
293 res = TRUE;
294 break;
295 }
296 }
297
298 return res;
299 }
300
301 void
write_pdml_proto_tree(output_fields_t * fields,gchar ** protocolfilter,pf_flags protocolfilter_flags,epan_dissect_t * edt,column_info * cinfo,FILE * fh,gboolean use_color)302 write_pdml_proto_tree(output_fields_t* fields, gchar **protocolfilter, pf_flags protocolfilter_flags, epan_dissect_t *edt, column_info *cinfo, FILE *fh, gboolean use_color)
303 {
304 write_pdml_data data;
305 const color_filter_t *cfp;
306
307 ws_assert(edt);
308 ws_assert(fh);
309
310 cfp = edt->pi.fd->color_filter;
311
312 /* Create the output */
313 if (use_color && (cfp != NULL)) {
314 fprintf(fh, "<packet foreground='#%06x' background='#%06x'>\n",
315 color_t_to_rgb(&cfp->fg_color),
316 color_t_to_rgb(&cfp->bg_color));
317 } else {
318 fprintf(fh, "<packet>\n");
319 }
320
321 /* Print a "geninfo" protocol as required by PDML */
322 print_pdml_geninfo(edt, fh);
323
324 if (fields == NULL || fields->fields == NULL) {
325 /* Write out all fields */
326 data.level = 0;
327 data.fh = fh;
328 data.src_list = edt->pi.data_src;
329 data.filter = protocolfilter;
330 data.filter_flags = protocolfilter_flags;
331
332 proto_tree_children_foreach(edt->tree, proto_tree_write_node_pdml,
333 &data);
334 } else {
335 /* Write out specified fields */
336 write_specified_fields(FORMAT_XML, fields, edt, cinfo, fh, NULL);
337 }
338
339 fprintf(fh, "</packet>\n\n");
340 }
341
342 void
write_ek_proto_tree(output_fields_t * fields,gboolean print_summary,gboolean print_hex,gchar ** protocolfilter,pf_flags protocolfilter_flags,epan_dissect_t * edt,column_info * cinfo,FILE * fh)343 write_ek_proto_tree(output_fields_t* fields,
344 gboolean print_summary, gboolean print_hex,
345 gchar **protocolfilter,
346 pf_flags protocolfilter_flags, epan_dissect_t *edt,
347 column_info *cinfo,
348 FILE *fh)
349 {
350 ws_assert(edt);
351 ws_assert(fh);
352
353 write_json_data data;
354
355 json_dumper dumper = {
356 .output_file = fh,
357 .flags = JSON_DUMPER_DOT_TO_UNDERSCORE
358 };
359
360 data.dumper = &dumper;
361
362 json_dumper_begin_object(&dumper);
363 json_dumper_set_member_name(&dumper, "index");
364 json_dumper_begin_object(&dumper);
365 write_json_index(&dumper, edt);
366 json_dumper_set_member_name(&dumper, "_type");
367 json_dumper_value_string(&dumper, "doc");
368 json_dumper_end_object(&dumper);
369 json_dumper_end_object(&dumper);
370 json_dumper_finish(&dumper);
371 json_dumper_begin_object(&dumper);
372
373 /* Timestamp added for time indexing in Elasticsearch */
374 json_dumper_set_member_name(&dumper, "timestamp");
375 json_dumper_value_anyf(&dumper, "\"%" G_GUINT64_FORMAT "%03d\"", (guint64)edt->pi.abs_ts.secs, edt->pi.abs_ts.nsecs/1000000);
376
377 if (print_summary)
378 write_ek_summary(edt->pi.cinfo, &data);
379
380 if (edt->tree) {
381 json_dumper_set_member_name(&dumper, "layers");
382 json_dumper_begin_object(&dumper);
383
384 if (fields == NULL || fields->fields == NULL) {
385 /* Write out all fields */
386 data.src_list = edt->pi.data_src;
387 data.filter = protocolfilter;
388 data.filter_flags = protocolfilter_flags;
389 data.print_hex = print_hex;
390 proto_tree_write_node_ek(edt->tree, &data);
391 } else {
392 /* Write out specified fields */
393 write_specified_fields(FORMAT_EK, fields, edt, cinfo, NULL, data.dumper);
394 }
395
396 json_dumper_end_object(&dumper);
397 }
398 json_dumper_end_object(&dumper);
399 json_dumper_finish(&dumper);
400 }
401
402 void
write_fields_proto_tree(output_fields_t * fields,epan_dissect_t * edt,column_info * cinfo,FILE * fh)403 write_fields_proto_tree(output_fields_t* fields, epan_dissect_t *edt, column_info *cinfo, FILE *fh)
404 {
405 ws_assert(edt);
406 ws_assert(fh);
407
408 /* Create the output */
409 write_specified_fields(FORMAT_CSV, fields, edt, cinfo, fh, NULL);
410 }
411
412 /* Indent to the correct level */
print_indent(int level,FILE * fh)413 static void print_indent(int level, FILE *fh)
414 {
415 /* Use a buffer pre-filed with spaces */
416 #define MAX_INDENT 2048
417 static char spaces[MAX_INDENT];
418 static gboolean inited = FALSE;
419 if (!inited) {
420 for (int n=0; n < MAX_INDENT; n++) {
421 spaces[n] = ' ';
422 }
423 inited = TRUE;
424 }
425
426 if (fh == NULL) {
427 return;
428 }
429
430 /* Temp terminate at right length and write to fh. */
431 spaces[MIN(level*2, MAX_INDENT-1)] ='\0';
432 fputs(spaces, fh);
433 spaces[MIN(level*2, MAX_INDENT-1)] =' ';
434 }
435
436 /* Write out a tree's data, and any child nodes, as PDML */
437 static void
proto_tree_write_node_pdml(proto_node * node,gpointer data)438 proto_tree_write_node_pdml(proto_node *node, gpointer data)
439 {
440 field_info *fi = PNODE_FINFO(node);
441 write_pdml_data *pdata = (write_pdml_data*) data;
442 const gchar *label_ptr;
443 gchar label_str[ITEM_LABEL_LENGTH];
444 char *dfilter_string;
445 gboolean wrap_in_fake_protocol;
446
447 /* dissection with an invisible proto tree? */
448 ws_assert(fi);
449
450 /* Will wrap up top-level field items inside a fake protocol wrapper to
451 preserve the PDML schema */
452 wrap_in_fake_protocol =
453 (((fi->hfinfo->type != FT_PROTOCOL) ||
454 (fi->hfinfo->id == proto_data)) &&
455 (pdata->level == 0));
456
457 print_indent(pdata->level + 1, pdata->fh);
458
459 if (wrap_in_fake_protocol) {
460 /* Open fake protocol wrapper */
461 fputs("<proto name=\"fake-field-wrapper\">\n", pdata->fh);
462 pdata->level++;
463
464 print_indent(pdata->level + 1, pdata->fh);
465 }
466
467 /* Text label. It's printed as a field with no name. */
468 if (fi->hfinfo->id == hf_text_only) {
469 /* Get the text */
470 if (fi->rep) {
471 label_ptr = fi->rep->representation;
472 } else {
473 label_ptr = "";
474 }
475
476 /* Show empty name since it is a required field */
477 fputs("<field name=\"", pdata->fh);
478 fputs("\" show=\"", pdata->fh);
479 print_escaped_xml(pdata->fh, label_ptr);
480
481 fprintf(pdata->fh, "\" size=\"%d", fi->length);
482 if (node->parent && node->parent->finfo && (fi->start < node->parent->finfo->start)) {
483 fprintf(pdata->fh, "\" pos=\"%d", node->parent->finfo->start + fi->start);
484 } else {
485 fprintf(pdata->fh, "\" pos=\"%d", fi->start);
486 }
487
488 if (fi->length > 0) {
489 fputs("\" value=\"", pdata->fh);
490 pdml_write_field_hex_value(pdata, fi);
491 }
492
493 if (node->first_child != NULL) {
494 fputs("\">\n", pdata->fh);
495 } else {
496 fputs("\"/>\n", pdata->fh);
497 }
498 }
499
500 /* Uninterpreted data, i.e., the "Data" protocol, is
501 * printed as a field instead of a protocol. */
502 else if (fi->hfinfo->id == proto_data) {
503 /* Write out field with data */
504 fputs("<field name=\"data\" value=\"", pdata->fh);
505 pdml_write_field_hex_value(pdata, fi);
506 fputs("\">\n", pdata->fh);
507 } else {
508 /* Normal protocols and fields */
509 if ((fi->hfinfo->type == FT_PROTOCOL) && (fi->hfinfo->id != proto_expert)) {
510 fputs("<proto name=\"", pdata->fh);
511 } else {
512 fputs("<field name=\"", pdata->fh);
513 }
514 print_escaped_xml(pdata->fh, fi->hfinfo->abbrev);
515
516 #if 0
517 /* PDML spec, see:
518 * https://wayback.archive.org/web/20150330045501/http://www.nbee.org/doku.php?id=netpdl:pdml_specification
519 *
520 * the show fields contains things in 'human readable' format
521 * showname: contains only the name of the field
522 * show: contains only the data of the field
523 * showdtl: contains additional details of the field data
524 * showmap: contains mappings of the field data (e.g. the hostname to an IP address)
525 *
526 * XXX - the showname shouldn't contain the field data itself
527 * (like it's contained in the fi->rep->representation).
528 * Unfortunately, we don't have the field data representation for
529 * all fields, so this isn't currently possible */
530 fputs("\" showname=\"", pdata->fh);
531 print_escaped_xml(pdata->fh, fi->hfinfo->name);
532 #endif
533
534 if (fi->rep) {
535 fputs("\" showname=\"", pdata->fh);
536 print_escaped_xml(pdata->fh, fi->rep->representation);
537 } else {
538 label_ptr = label_str;
539 proto_item_fill_label(fi, label_str);
540 fputs("\" showname=\"", pdata->fh);
541 print_escaped_xml(pdata->fh, label_ptr);
542 }
543
544 if (proto_item_is_hidden(node) && (prefs.display_hidden_proto_items == FALSE))
545 fprintf(pdata->fh, "\" hide=\"yes");
546
547 fprintf(pdata->fh, "\" size=\"%d", fi->length);
548 if (node->parent && node->parent->finfo && (fi->start < node->parent->finfo->start)) {
549 fprintf(pdata->fh, "\" pos=\"%d", node->parent->finfo->start + fi->start);
550 } else {
551 fprintf(pdata->fh, "\" pos=\"%d", fi->start);
552 }
553 /* fprintf(pdata->fh, "\" id=\"%d", fi->hfinfo->id);*/
554
555 /* show, value, and unmaskedvalue attributes */
556 switch (fi->hfinfo->type)
557 {
558 case FT_PROTOCOL:
559 break;
560 case FT_NONE:
561 fputs("\" show=\"\" value=\"", pdata->fh);
562 break;
563 default:
564 dfilter_string = fvalue_to_string_repr(NULL, &fi->value, FTREPR_DISPLAY, fi->hfinfo->display);
565 if (dfilter_string != NULL) {
566
567 fputs("\" show=\"", pdata->fh);
568 print_escaped_xml(pdata->fh, dfilter_string);
569 }
570 wmem_free(NULL, dfilter_string);
571
572 /*
573 * XXX - should we omit "value" for any fields?
574 * What should we do for fields whose length is 0?
575 * They might come from a pseudo-header or from
576 * the capture header (e.g., time stamps), or
577 * they might be generated fields.
578 */
579 if (fi->length > 0) {
580 fputs("\" value=\"", pdata->fh);
581
582 if (fi->hfinfo->bitmask!=0) {
583 switch (fi->value.ftype->ftype) {
584 case FT_INT8:
585 case FT_INT16:
586 case FT_INT24:
587 case FT_INT32:
588 fprintf(pdata->fh, "%X", (guint) fvalue_get_sinteger(&fi->value));
589 break;
590 case FT_CHAR:
591 case FT_UINT8:
592 case FT_UINT16:
593 case FT_UINT24:
594 case FT_UINT32:
595 fprintf(pdata->fh, "%X", fvalue_get_uinteger(&fi->value));
596 break;
597 case FT_INT40:
598 case FT_INT48:
599 case FT_INT56:
600 case FT_INT64:
601 fprintf(pdata->fh, "%" G_GINT64_MODIFIER "X", fvalue_get_sinteger64(&fi->value));
602 break;
603 case FT_UINT40:
604 case FT_UINT48:
605 case FT_UINT56:
606 case FT_UINT64:
607 case FT_BOOLEAN:
608 fprintf(pdata->fh, "%" G_GINT64_MODIFIER "X", fvalue_get_uinteger64(&fi->value));
609 break;
610 default:
611 ws_assert_not_reached();
612 }
613 fputs("\" unmaskedvalue=\"", pdata->fh);
614 pdml_write_field_hex_value(pdata, fi);
615 } else {
616 pdml_write_field_hex_value(pdata, fi);
617 }
618 }
619 }
620
621 if (node->first_child != NULL) {
622 fputs("\">\n", pdata->fh);
623 } else if (fi->hfinfo->id == proto_data) {
624 fputs("\">\n", pdata->fh);
625 } else {
626 fputs("\"/>\n", pdata->fh);
627 }
628 }
629
630 /* We print some levels for PDML. Recurse here. */
631 if (node->first_child != NULL) {
632 if (pdata->filter == NULL || check_protocolfilter(pdata->filter, fi->hfinfo->abbrev)) {
633 gchar **_filter = NULL;
634 /* Remove protocol filter for children, if children should be included */
635 if ((pdata->filter_flags&PF_INCLUDE_CHILDREN) == PF_INCLUDE_CHILDREN) {
636 _filter = pdata->filter;
637 pdata->filter = NULL;
638 }
639
640 pdata->level++;
641 proto_tree_children_foreach(node,
642 proto_tree_write_node_pdml, pdata);
643 pdata->level--;
644
645 /* Put protocol filter back */
646 if ((pdata->filter_flags&PF_INCLUDE_CHILDREN) == PF_INCLUDE_CHILDREN) {
647 pdata->filter = _filter;
648 }
649 } else {
650 print_indent(pdata->level + 2, pdata->fh);
651
652 /* print dummy field */
653 fputs("<field name=\"filtered\" value=\"", pdata->fh);
654 print_escaped_xml(pdata->fh, fi->hfinfo->abbrev);
655 fputs("\" />\n", pdata->fh);
656 }
657 }
658
659 /* Take back the extra level we added for fake wrapper protocol */
660 if (wrap_in_fake_protocol) {
661 pdata->level--;
662 }
663
664 if (node->first_child != NULL) {
665 print_indent(pdata->level + 1, pdata->fh);
666
667 /* Close off current element */
668 /* Data and expert "protocols" use simple tags */
669 if ((fi->hfinfo->id != proto_data) && (fi->hfinfo->id != proto_expert)) {
670 if (fi->hfinfo->type == FT_PROTOCOL) {
671 fputs("</proto>\n", pdata->fh);
672 } else {
673 fputs("</field>\n", pdata->fh);
674 }
675 } else {
676 fputs("</field>\n", pdata->fh);
677 }
678 }
679
680 /* Close off fake wrapper protocol */
681 if (wrap_in_fake_protocol) {
682 print_indent(pdata->level + 1, pdata->fh);
683 fputs("</proto>\n", pdata->fh);
684 }
685 }
686
687 json_dumper
write_json_preamble(FILE * fh)688 write_json_preamble(FILE *fh)
689 {
690 json_dumper dumper = {
691 .output_file = fh,
692 .flags = JSON_DUMPER_FLAGS_PRETTY_PRINT
693 };
694 json_dumper_begin_array(&dumper);
695 return dumper;
696 }
697
698 void
write_json_finale(json_dumper * dumper)699 write_json_finale(json_dumper *dumper)
700 {
701 json_dumper_end_array(dumper);
702 json_dumper_finish(dumper);
703 }
704
705 static void
write_json_index(json_dumper * dumper,epan_dissect_t * edt)706 write_json_index(json_dumper *dumper, epan_dissect_t *edt)
707 {
708 char ts[30];
709 struct tm * timeinfo;
710 gchar* str;
711
712 timeinfo = localtime(&edt->pi.abs_ts.secs);
713 if (timeinfo != NULL) {
714 strftime(ts, sizeof(ts), "%Y-%m-%d", timeinfo);
715 } else {
716 (void) g_strlcpy(ts, "XXXX-XX-XX", sizeof(ts)); /* XXX - better way of saying "Not representable"? */
717 }
718 json_dumper_set_member_name(dumper, "_index");
719 str = g_strdup_printf("packets-%s", ts);
720 json_dumper_value_string(dumper, str);
721 g_free(str);
722 }
723
724 void
write_json_proto_tree(output_fields_t * fields,print_dissections_e print_dissections,gboolean print_hex,gchar ** protocolfilter,pf_flags protocolfilter_flags,epan_dissect_t * edt,column_info * cinfo,proto_node_children_grouper_func node_children_grouper,json_dumper * dumper)725 write_json_proto_tree(output_fields_t* fields,
726 print_dissections_e print_dissections,
727 gboolean print_hex, gchar **protocolfilter,
728 pf_flags protocolfilter_flags, epan_dissect_t *edt,
729 column_info *cinfo,
730 proto_node_children_grouper_func node_children_grouper,
731 json_dumper *dumper)
732 {
733 write_json_data data;
734
735 data.dumper = dumper;
736
737 json_dumper_begin_object(dumper);
738 write_json_index(dumper, edt);
739 json_dumper_set_member_name(dumper, "_type");
740 json_dumper_value_string(dumper, "doc");
741 json_dumper_set_member_name(dumper, "_score");
742 json_dumper_value_string(dumper, NULL);
743 json_dumper_set_member_name(dumper, "_source");
744 json_dumper_begin_object(dumper);
745 json_dumper_set_member_name(dumper, "layers");
746
747 if (fields == NULL || fields->fields == NULL) {
748 /* Write out all fields */
749 data.src_list = edt->pi.data_src;
750 data.filter = protocolfilter;
751 data.filter_flags = protocolfilter_flags;
752 data.print_hex = print_hex;
753 data.print_text = TRUE;
754 if (print_dissections == print_dissections_none) {
755 data.print_text = FALSE;
756 }
757 data.node_children_grouper = node_children_grouper;
758
759 write_json_proto_node_children(edt->tree, &data);
760 } else {
761 write_specified_fields(FORMAT_JSON, fields, edt, cinfo, NULL, dumper);
762 }
763
764 json_dumper_end_object(dumper);
765 json_dumper_end_object(dumper);
766 }
767
768 /**
769 * Returns a boolean telling us whether that node list contains any node which has children
770 */
771 static gboolean
any_has_children(GSList * node_values_list)772 any_has_children(GSList *node_values_list)
773 {
774 GSList *current_node = node_values_list;
775 while (current_node != NULL) {
776 proto_node *current_value = (proto_node *) current_node->data;
777 if (current_value->first_child != NULL) {
778 return TRUE;
779 }
780 current_node = current_node->next;
781 }
782 return FALSE;
783 }
784
785 /**
786 * Write a json object containing a list of key:value pairs where each key:value pair corresponds to a different json
787 * key and its associated nodes in the proto_tree.
788 * @param proto_node_list_head A 2-dimensional list containing a list of values for each different node json key. The
789 * elements themselves are a linked list of values associated with the same json key.
790 * @param pdata json writing metadata
791 */
792 static void
write_json_proto_node_list(GSList * proto_node_list_head,write_json_data * pdata)793 write_json_proto_node_list(GSList *proto_node_list_head, write_json_data *pdata)
794 {
795 GSList *current_node = proto_node_list_head;
796
797 json_dumper_begin_object(pdata->dumper);
798
799 // Loop over each list of nodes (differentiated by json key) and write the associated json key:value pair in the
800 // output.
801 while (current_node != NULL) {
802 // Get the list of values for the current json key.
803 GSList *node_values_list = (GSList *) current_node->data;
804
805 // Retrieve the json key from the first value.
806 proto_node *first_value = (proto_node *) node_values_list->data;
807 const char *json_key = proto_node_to_json_key(first_value);
808 // Check if the current json key is filtered from the output with the "-j" cli option.
809 gboolean is_filtered = pdata->filter != NULL && !check_protocolfilter(pdata->filter, json_key);
810
811 field_info *fi = first_value->finfo;
812 char *value_string_repr = fvalue_to_string_repr(NULL, &fi->value, FTREPR_DISPLAY, fi->hfinfo->display);
813 gboolean has_children = any_has_children(node_values_list);
814
815 // We assume all values of a json key have roughly the same layout. Thus we can use the first value to derive
816 // attributes of all the values.
817 gboolean has_value = value_string_repr != NULL;
818 gboolean is_pseudo_text_field = fi->hfinfo->id == 0;
819
820 wmem_free(NULL, value_string_repr); // fvalue_to_string_repr returns allocated buffer
821
822 // "-x" command line option. A "_raw" suffix is added to the json key so the textual value can be printed
823 // with the original json key. If both hex and text writing are enabled the raw information of fields whose
824 // length is equal to 0 is not written to the output. If the field is a special text pseudo field no raw
825 // information is written either.
826 if (pdata->print_hex && (!pdata->print_text || fi->length > 0) && !is_pseudo_text_field) {
827 write_json_proto_node(node_values_list, "_raw", write_json_proto_node_hex_dump, pdata);
828 }
829
830 if (pdata->print_text && has_value) {
831 write_json_proto_node(node_values_list, "", write_json_proto_node_value, pdata);
832 }
833
834 if (has_children) {
835 // If a node has both a value and a set of children we print the value and the children in separate
836 // key:value pairs. These can't have the same key so whenever a value is already printed with the node
837 // json key we print the children with the same key with a "_tree" suffix added.
838 char *suffix = has_value ? "_tree": "";
839
840 if (is_filtered) {
841 write_json_proto_node(node_values_list, suffix, write_json_proto_node_filtered, pdata);
842 } else {
843 // Remove protocol filter for children, if children should be included. This functionality is enabled
844 // with the "-J" command line option. We save the filter so it can be reenabled when we are done with
845 // the current key:value pair.
846 gchar **_filter = NULL;
847 if ((pdata->filter_flags&PF_INCLUDE_CHILDREN) == PF_INCLUDE_CHILDREN) {
848 _filter = pdata->filter;
849 pdata->filter = NULL;
850 }
851
852 // has_children is TRUE if any of the nodes have children. So we're not 100% sure whether this
853 // particular node has children or not => use the 'dynamic' version of 'write_json_proto_node'
854 write_json_proto_node(node_values_list, suffix, write_json_proto_node_dynamic, pdata);
855
856 // Put protocol filter back
857 if ((pdata->filter_flags&PF_INCLUDE_CHILDREN) == PF_INCLUDE_CHILDREN) {
858 pdata->filter = _filter;
859 }
860 }
861 }
862
863 if (!has_value && !has_children && (pdata->print_text || (pdata->print_hex && is_pseudo_text_field))) {
864 write_json_proto_node(node_values_list, "", write_json_proto_node_no_value, pdata);
865 }
866
867 current_node = current_node->next;
868 }
869 json_dumper_end_object(pdata->dumper);
870 }
871
872 /**
873 * Writes a single node as a key:value pair. The value_writer param can be used to specify how the node's value should
874 * be written.
875 * @param node_values_head Linked list containing all nodes associated with the same json key in this object.
876 * @param suffix Suffix that should be added to the json key.
877 * @param value_writer A function which writes the actual values of the node json key.
878 * @param pdata json writing metadata
879 */
880 static void
write_json_proto_node(GSList * node_values_head,const char * suffix,proto_node_value_writer value_writer,write_json_data * pdata)881 write_json_proto_node(GSList *node_values_head,
882 const char *suffix,
883 proto_node_value_writer value_writer,
884 write_json_data *pdata)
885 {
886 // Retrieve json key from first value.
887 proto_node *first_value = (proto_node *) node_values_head->data;
888 const char *json_key = proto_node_to_json_key(first_value);
889 gchar* json_key_suffix = g_strdup_printf("%s%s", json_key, suffix);
890 json_dumper_set_member_name(pdata->dumper, json_key_suffix);
891 g_free(json_key_suffix);
892 write_json_proto_node_value_list(node_values_head, value_writer, pdata);
893 }
894
895 /**
896 * Writes a list of values of a single json key. If multiple values are passed they are wrapped in a json array.
897 * @param node_values_head Linked list containing all values that should be written.
898 * @param value_writer Function which writes the separate values.
899 * @param pdata json writing metadata
900 */
901 static void
write_json_proto_node_value_list(GSList * node_values_head,proto_node_value_writer value_writer,write_json_data * pdata)902 write_json_proto_node_value_list(GSList *node_values_head, proto_node_value_writer value_writer, write_json_data *pdata)
903 {
904 GSList *current_value = node_values_head;
905
906 // Write directly if only a single value is passed. Wrap in json array otherwise.
907 if (current_value->next == NULL) {
908 value_writer((proto_node *) current_value->data, pdata);
909 } else {
910 json_dumper_begin_array(pdata->dumper);
911
912 while (current_value != NULL) {
913 value_writer((proto_node *) current_value->data, pdata);
914 current_value = current_value->next;
915 }
916 json_dumper_end_array(pdata->dumper);
917 }
918 }
919
920 /**
921 * Writes the value for a node that's filtered from the output.
922 */
923 static void
write_json_proto_node_filtered(proto_node * node,write_json_data * pdata)924 write_json_proto_node_filtered(proto_node *node, write_json_data *pdata)
925 {
926 const char *json_key = proto_node_to_json_key(node);
927
928 json_dumper_begin_object(pdata->dumper);
929 json_dumper_set_member_name(pdata->dumper, "filtered");
930 json_dumper_value_string(pdata->dumper, json_key);
931 json_dumper_end_object(pdata->dumper);
932 }
933
934 /**
935 * Writes the hex dump of a node. A json array is written containing the hex dump, position, length, bitmask and type of
936 * the node.
937 */
938 static void
write_json_proto_node_hex_dump(proto_node * node,write_json_data * pdata)939 write_json_proto_node_hex_dump(proto_node *node, write_json_data *pdata)
940 {
941 field_info *fi = node->finfo;
942
943 json_dumper_begin_array(pdata->dumper);
944
945 if (fi->hfinfo->bitmask!=0) {
946 switch (fi->value.ftype->ftype) {
947 case FT_INT8:
948 case FT_INT16:
949 case FT_INT24:
950 case FT_INT32:
951 json_dumper_value_anyf(pdata->dumper, "\"%X\"", (guint) fvalue_get_sinteger(&fi->value));
952 break;
953 case FT_CHAR:
954 case FT_UINT8:
955 case FT_UINT16:
956 case FT_UINT24:
957 case FT_UINT32:
958 json_dumper_value_anyf(pdata->dumper, "\"%X\"", fvalue_get_uinteger(&fi->value));
959 break;
960 case FT_INT40:
961 case FT_INT48:
962 case FT_INT56:
963 case FT_INT64:
964 json_dumper_value_anyf(pdata->dumper, "\"%" G_GINT64_MODIFIER "X\"", fvalue_get_sinteger64(&fi->value));
965 break;
966 case FT_UINT40:
967 case FT_UINT48:
968 case FT_UINT56:
969 case FT_UINT64:
970 case FT_BOOLEAN:
971 json_dumper_value_anyf(pdata->dumper, "\"%" G_GINT64_MODIFIER "X\"", fvalue_get_uinteger64(&fi->value));
972 break;
973 default:
974 ws_assert_not_reached();
975 }
976 } else {
977 json_write_field_hex_value(pdata, fi);
978 }
979
980 /* Dump raw hex-encoded dissected information including position, length, bitmask, type */
981 json_dumper_value_anyf(pdata->dumper, "%" G_GINT32_MODIFIER "d", fi->start);
982 json_dumper_value_anyf(pdata->dumper, "%" G_GINT32_MODIFIER "d", fi->length);
983 json_dumper_value_anyf(pdata->dumper, "%" G_GUINT64_FORMAT, fi->hfinfo->bitmask);
984 json_dumper_value_anyf(pdata->dumper, "%" G_GINT32_MODIFIER "d", (gint32)fi->value.ftype->ftype);
985
986 json_dumper_end_array(pdata->dumper);
987 }
988
989 /**
990 * Writes the value of a node, which may be a simple node with no value and no children,
991 * or a node with children -- this will be determined dynamically
992 */
993 static void
write_json_proto_node_dynamic(proto_node * node,write_json_data * data)994 write_json_proto_node_dynamic(proto_node *node, write_json_data *data)
995 {
996 if (node->first_child == NULL) {
997 write_json_proto_node_no_value(node, data);
998 } else {
999 write_json_proto_node_children(node, data);
1000 }
1001 }
1002
1003 /**
1004 * Writes the children of a node. Calls write_json_proto_node_list internally which recursively writes children of nodes
1005 * to the output.
1006 */
1007 static void
write_json_proto_node_children(proto_node * node,write_json_data * data)1008 write_json_proto_node_children(proto_node *node, write_json_data *data)
1009 {
1010 GSList *grouped_children_list = data->node_children_grouper(node);
1011 write_json_proto_node_list(grouped_children_list, data);
1012 g_slist_free_full(grouped_children_list, (GDestroyNotify) g_slist_free);
1013 }
1014
1015 /**
1016 * Writes the value of a node to the output.
1017 */
1018 static void
write_json_proto_node_value(proto_node * node,write_json_data * pdata)1019 write_json_proto_node_value(proto_node *node, write_json_data *pdata)
1020 {
1021 field_info *fi = node->finfo;
1022 // Get the actual value of the node as a string.
1023 char *value_string_repr = fvalue_to_string_repr(NULL, &fi->value, FTREPR_DISPLAY, fi->hfinfo->display);
1024
1025 json_dumper_value_string(pdata->dumper, value_string_repr);
1026
1027 wmem_free(NULL, value_string_repr);
1028 }
1029
1030 /**
1031 * Write the value for a node that has no value and no children. This is the empty string for all nodes except those of
1032 * type FT_PROTOCOL for which the full name is written instead.
1033 */
1034 static void
write_json_proto_node_no_value(proto_node * node,write_json_data * pdata)1035 write_json_proto_node_no_value(proto_node *node, write_json_data *pdata)
1036 {
1037 field_info *fi = node->finfo;
1038
1039 if (fi->hfinfo->type == FT_PROTOCOL) {
1040 if (fi->rep) {
1041 json_dumper_value_string(pdata->dumper, fi->rep->representation);
1042 } else {
1043 gchar label_str[ITEM_LABEL_LENGTH];
1044 proto_item_fill_label(fi, label_str);
1045 json_dumper_value_string(pdata->dumper, label_str);
1046 }
1047 } else {
1048 json_dumper_value_string(pdata->dumper, "");
1049 }
1050 }
1051
1052 /**
1053 * Groups each child of the node separately.
1054 * @return Linked list where each element is another linked list containing a single node.
1055 */
1056 GSList *
proto_node_group_children_by_unique(proto_node * node)1057 proto_node_group_children_by_unique(proto_node *node) {
1058 GSList *unique_nodes_list = NULL;
1059 proto_node *current_child = node->first_child;
1060
1061 while (current_child != NULL) {
1062 GSList *unique_node = g_slist_prepend(NULL, current_child);
1063 unique_nodes_list = g_slist_prepend(unique_nodes_list, unique_node);
1064 current_child = current_child->next;
1065 }
1066
1067 return g_slist_reverse(unique_nodes_list);
1068 }
1069
1070 /**
1071 * Groups the children of a node by their json key. Children are put in the same group if they have the same json key.
1072 * @return Linked list where each element is another linked list of nodes associated with the same json key.
1073 */
1074 GSList *
proto_node_group_children_by_json_key(proto_node * node)1075 proto_node_group_children_by_json_key(proto_node *node)
1076 {
1077 /**
1078 * For each different json key we store a linked list of values corresponding to that json key. These lists are kept
1079 * in both a linked list and a hashmap. The hashmap is used to quickly retrieve the values of a json key. The linked
1080 * list is used to preserve the ordering of keys as they are encountered which is not guaranteed when only using a
1081 * hashmap.
1082 */
1083 GSList *same_key_nodes_list = NULL;
1084 GHashTable *lookup_by_json_key = g_hash_table_new(g_str_hash, g_str_equal);
1085 proto_node *current_child = node->first_child;
1086
1087 /**
1088 * For each child of the node get the key and get the list of values already associated with that key from the
1089 * hashmap. If no list exist yet for that key create a new one and add it to both the linked list and hashmap. If a
1090 * list already exists add the node to that list.
1091 */
1092 while (current_child != NULL) {
1093 char *json_key = (char *) proto_node_to_json_key(current_child);
1094 GSList *json_key_nodes = (GSList *) g_hash_table_lookup(lookup_by_json_key, json_key);
1095
1096 if (json_key_nodes == NULL) {
1097 json_key_nodes = g_slist_append(json_key_nodes, current_child);
1098 // Prepending in single linked list is O(1), appending is O(n). Better to prepend here and reverse at the
1099 // end than potentially looping to the end of the linked list for each child.
1100 same_key_nodes_list = g_slist_prepend(same_key_nodes_list, json_key_nodes);
1101 g_hash_table_insert(lookup_by_json_key, json_key, json_key_nodes);
1102 } else {
1103 // Store and insert value again to circumvent unused_variable warning.
1104 // Append in this case since most value lists will only have a single value.
1105 json_key_nodes = g_slist_append(json_key_nodes, current_child);
1106 g_hash_table_insert(lookup_by_json_key, json_key, json_key_nodes);
1107 }
1108
1109 current_child = current_child->next;
1110 }
1111
1112 // Hash table is not needed anymore since the linked list with the correct ordering is returned.
1113 g_hash_table_destroy(lookup_by_json_key);
1114
1115 return g_slist_reverse(same_key_nodes_list);
1116 }
1117
1118 /**
1119 * Returns the json key of a node. Tries to use the node's abbreviated name. If the abbreviated name is not available
1120 * the representation is used instead.
1121 */
1122 static const char *
proto_node_to_json_key(proto_node * node)1123 proto_node_to_json_key(proto_node *node)
1124 {
1125 const char *json_key;
1126 // Check if node has abbreviated name.
1127 if (node->finfo->hfinfo->id != hf_text_only) {
1128 json_key = node->finfo->hfinfo->abbrev;
1129 } else if (node->finfo->rep != NULL) {
1130 json_key = node->finfo->rep->representation;
1131 } else {
1132 json_key = "";
1133 }
1134
1135 return json_key;
1136 }
1137
1138 static gboolean
ek_check_protocolfilter(gchar ** protocolfilter,const char * str)1139 ek_check_protocolfilter(gchar **protocolfilter, const char *str)
1140 {
1141 gchar *str_escaped = NULL;
1142 gboolean check;
1143 int i;
1144
1145 if (check_protocolfilter(protocolfilter, str))
1146 return TRUE;
1147
1148 /* to to thread the '.' and '_' equally. The '.' is replace by print_escaped_ek for '_' */
1149 if (str != NULL && strlen(str) > 0) {
1150 str_escaped = g_strdup(str);
1151
1152 i = 0;
1153 while (str_escaped[i] != '\0') {
1154 if (str_escaped[i] == '.') {
1155 str_escaped[i] = '_';
1156 }
1157 i++;
1158 }
1159 }
1160
1161 check = check_protocolfilter(protocolfilter, str_escaped);
1162 g_free(str_escaped);
1163 return check;
1164 }
1165
1166 /**
1167 * Finds a node's descendants to be printed as EK/JSON attributes.
1168 */
1169 static void
write_ek_summary(column_info * cinfo,write_json_data * pdata)1170 write_ek_summary(column_info *cinfo, write_json_data* pdata)
1171 {
1172 gint i;
1173
1174 for (i = 0; i < cinfo->num_cols; i++) {
1175 if (!get_column_visible(i))
1176 continue;
1177 json_dumper_set_member_name(pdata->dumper, g_ascii_strdown(cinfo->columns[i].col_title, -1));
1178 json_dumper_value_string(pdata->dumper, cinfo->columns[i].col_data);
1179 }
1180 }
1181
1182 /* Write out a tree's data, and any child nodes, as JSON for EK */
1183 static void
ek_fill_attr(proto_node * node,GSList ** attr_list,GHashTable * attr_table,write_json_data * pdata)1184 ek_fill_attr(proto_node *node, GSList **attr_list, GHashTable *attr_table, write_json_data *pdata)
1185 {
1186 field_info *fi = NULL;
1187 field_info *fi_parent = NULL;
1188 gchar *node_name = NULL;
1189 GSList *attr_instances = NULL;
1190
1191 proto_node *current_node = node->first_child;
1192 while (current_node != NULL) {
1193 fi = PNODE_FINFO(current_node);
1194 fi_parent = PNODE_FINFO(current_node->parent);
1195
1196 /* dissection with an invisible proto tree? */
1197 ws_assert(fi);
1198
1199 if (fi_parent == NULL) {
1200 node_name = g_strdup(fi->hfinfo->abbrev);
1201 } else {
1202 node_name = g_strconcat(fi_parent->hfinfo->abbrev, "_", fi->hfinfo->abbrev, NULL);
1203 }
1204
1205 attr_instances = (GSList *) g_hash_table_lookup(attr_table, node_name);
1206 // First time we encounter this attr
1207 if (attr_instances == NULL) {
1208 attr_instances = g_slist_append(attr_instances, current_node);
1209 *attr_list = g_slist_prepend(*attr_list, attr_instances);
1210 } else {
1211 attr_instances = g_slist_append(attr_instances, current_node);
1212 }
1213
1214 // Update instance list for this attr in hash table
1215 g_hash_table_insert(attr_table, node_name, attr_instances);
1216
1217 /* Field, recurse through children*/
1218 if (fi->hfinfo->type != FT_PROTOCOL && current_node->first_child != NULL) {
1219 if (pdata->filter != NULL) {
1220 if (ek_check_protocolfilter(pdata->filter, fi->hfinfo->abbrev)) {
1221 gchar **_filter = NULL;
1222 /* Remove protocol filter for children, if children should be included */
1223 if ((pdata->filter_flags&PF_INCLUDE_CHILDREN) == PF_INCLUDE_CHILDREN) {
1224 _filter = pdata->filter;
1225 pdata->filter = NULL;
1226 }
1227
1228 ek_fill_attr(current_node, attr_list, attr_table, pdata);
1229
1230 /* Put protocol filter back */
1231 if ((pdata->filter_flags&PF_INCLUDE_CHILDREN) == PF_INCLUDE_CHILDREN) {
1232 pdata->filter = _filter;
1233 }
1234 } else {
1235 // Don't traverse children if filtered out
1236 }
1237 } else {
1238 ek_fill_attr(current_node, attr_list, attr_table, pdata);
1239 }
1240 } else {
1241 // Will descend into object at another point
1242 }
1243
1244 current_node = current_node->next;
1245 }
1246 }
1247
1248 static void
ek_write_name(proto_node * pnode,gchar * suffix,write_json_data * pdata)1249 ek_write_name(proto_node *pnode, gchar* suffix, write_json_data* pdata)
1250 {
1251 field_info *fi = PNODE_FINFO(pnode);
1252 gchar *str;
1253
1254 if (fi->hfinfo->parent != -1) {
1255 header_field_info* parent = proto_registrar_get_nth(fi->hfinfo->parent);
1256 str = g_strdup_printf("%s_%s%s", parent->abbrev, fi->hfinfo->abbrev, suffix ? suffix : "");
1257 json_dumper_set_member_name(pdata->dumper, str);
1258 } else {
1259 str = g_strdup_printf("%s%s", fi->hfinfo->abbrev, suffix ? suffix : "");
1260 json_dumper_set_member_name(pdata->dumper, str);
1261 }
1262 g_free(str);
1263 }
1264
1265 static void
ek_write_hex(field_info * fi,write_json_data * pdata)1266 ek_write_hex(field_info *fi, write_json_data *pdata)
1267 {
1268 if (fi->hfinfo->bitmask != 0) {
1269 switch (fi->value.ftype->ftype) {
1270 case FT_INT8:
1271 case FT_INT16:
1272 case FT_INT24:
1273 case FT_INT32:
1274 json_dumper_value_anyf(pdata->dumper, "\"%X\"", (guint) fvalue_get_sinteger(&fi->value));
1275 break;
1276 case FT_CHAR:
1277 case FT_UINT8:
1278 case FT_UINT16:
1279 case FT_UINT24:
1280 case FT_UINT32:
1281 json_dumper_value_anyf(pdata->dumper, "\"%X\"", fvalue_get_uinteger(&fi->value));
1282 break;
1283 case FT_INT40:
1284 case FT_INT48:
1285 case FT_INT56:
1286 case FT_INT64:
1287 json_dumper_value_anyf(pdata->dumper, "\"%" G_GINT64_MODIFIER "X\"", fvalue_get_sinteger64(&fi->value));
1288 break;
1289 case FT_UINT40:
1290 case FT_UINT48:
1291 case FT_UINT56:
1292 case FT_UINT64:
1293 case FT_BOOLEAN:
1294 json_dumper_value_anyf(pdata->dumper, "\"%" G_GINT64_MODIFIER "X\"", fvalue_get_uinteger64(&fi->value));
1295 break;
1296 default:
1297 ws_assert_not_reached();
1298 }
1299 } else {
1300 json_write_field_hex_value(pdata, fi);
1301 }
1302 }
1303
1304 static void
ek_write_field_value(field_info * fi,write_json_data * pdata)1305 ek_write_field_value(field_info *fi, write_json_data* pdata)
1306 {
1307 gchar label_str[ITEM_LABEL_LENGTH];
1308 char *dfilter_string;
1309 const nstime_t *t;
1310 struct tm *tm;
1311 #ifndef _WIN32
1312 struct tm tm_time;
1313 #endif
1314 char time_string[sizeof("YYYY-MM-DDTHH:MM:SS")];
1315
1316 /* Text label */
1317 if (fi->hfinfo->id == hf_text_only && fi->rep) {
1318 json_dumper_value_string(pdata->dumper, fi->rep->representation);
1319 } else {
1320 /* show, value, and unmaskedvalue attributes */
1321 switch(fi->hfinfo->type) {
1322 case FT_PROTOCOL:
1323 if (fi->rep) {
1324 json_dumper_value_string(pdata->dumper, fi->rep->representation);
1325 }
1326 else {
1327 proto_item_fill_label(fi, label_str);
1328 json_dumper_value_string(pdata->dumper, label_str);
1329 }
1330 break;
1331 case FT_NONE:
1332 json_dumper_value_string(pdata->dumper, NULL);
1333 break;
1334 case FT_BOOLEAN:
1335 if (fi->value.value.uinteger64)
1336 json_dumper_value_anyf(pdata->dumper, "true");
1337 else
1338 json_dumper_value_anyf(pdata->dumper, "false");
1339 break;
1340 case FT_ABSOLUTE_TIME:
1341 t = (const nstime_t *)fvalue_get(&fi->value);
1342 #ifdef _WIN32
1343 /*
1344 * Do not use gmtime_s(), as it will call and
1345 * exception handler if the time we're providing
1346 * is < 0, and that will, by default, exit.
1347 * ("Programmers not bothering to check return
1348 * values? Try new Microsoft Visual Studio,
1349 * with Parameter Validation(R)! Kill insufficiently
1350 * careful programs - *and* the processes running them -
1351 * fast!")
1352 *
1353 * We just want to report this as an unrepresentable
1354 * time. It fills in a per-thread structure, which
1355 * is sufficiently thread-safe for our purposes.
1356 */
1357 tm = gmtime(&t->secs);
1358 #else
1359 /*
1360 * Use gmtime_r(), because the Single UNIX Specification
1361 * does *not* guarantee that gmtime() is thread-safe.
1362 * Perhaps it is on all platforms on which we run, but
1363 * this way we don't have to check.
1364 */
1365 tm = gmtime_r(&t->secs, &tm_time);
1366 #endif
1367 if (tm != NULL) {
1368 /* Some platforms (MinGW-w64) do not support %F or %T. */
1369 strftime(time_string, sizeof(time_string), "%Y-%m-%dT%H:%M:%S", tm);
1370 json_dumper_value_anyf(pdata->dumper, "\"%s.%09uZ\"", time_string, t->nsecs);
1371 } else {
1372 json_dumper_value_anyf(pdata->dumper, "\"Not representable\"");
1373 }
1374 break;
1375 default:
1376 dfilter_string = fvalue_to_string_repr(NULL, &fi->value, FTREPR_DISPLAY, fi->hfinfo->display);
1377 if (dfilter_string != NULL) {
1378 json_dumper_value_string(pdata->dumper, dfilter_string);
1379 }
1380 wmem_free(NULL, dfilter_string);
1381 break;
1382 }
1383 }
1384 }
1385
1386 static void
ek_write_attr_hex(GSList * attr_instances,write_json_data * pdata)1387 ek_write_attr_hex(GSList *attr_instances, write_json_data *pdata)
1388 {
1389 GSList *current_node = attr_instances;
1390 proto_node *pnode = (proto_node *) current_node->data;
1391 field_info *fi = NULL;
1392
1393 // Raw name
1394 ek_write_name(pnode, "_raw", pdata);
1395
1396 if (g_slist_length(attr_instances) > 1) {
1397 json_dumper_begin_array(pdata->dumper);
1398 }
1399
1400 // Raw value(s)
1401 while (current_node != NULL) {
1402 pnode = (proto_node *) current_node->data;
1403 fi = PNODE_FINFO(pnode);
1404
1405 ek_write_hex(fi, pdata);
1406
1407 current_node = current_node->next;
1408 }
1409
1410 if (g_slist_length(attr_instances) > 1) {
1411 json_dumper_end_array(pdata->dumper);
1412 }
1413 }
1414
1415 static void
ek_write_attr(GSList * attr_instances,write_json_data * pdata)1416 ek_write_attr(GSList *attr_instances, write_json_data *pdata)
1417 {
1418 GSList *current_node = attr_instances;
1419 proto_node *pnode = (proto_node *) current_node->data;
1420 field_info *fi = PNODE_FINFO(pnode);
1421
1422 // Hex dump -x
1423 if (pdata->print_hex && fi && fi->length > 0 && fi->hfinfo->id != hf_text_only) {
1424 ek_write_attr_hex(attr_instances, pdata);
1425 }
1426
1427 // Print attr name
1428 ek_write_name(pnode, NULL, pdata);
1429
1430 if (g_slist_length(attr_instances) > 1) {
1431 json_dumper_begin_array(pdata->dumper);
1432 }
1433
1434 while (current_node != NULL) {
1435 pnode = (proto_node *) current_node->data;
1436 fi = PNODE_FINFO(pnode);
1437
1438 /* Field */
1439 if (fi->hfinfo->type != FT_PROTOCOL) {
1440 if (pdata->filter != NULL
1441 && !ek_check_protocolfilter(pdata->filter, fi->hfinfo->abbrev)) {
1442
1443 /* print dummy field */
1444 json_dumper_begin_object(pdata->dumper);
1445 json_dumper_set_member_name(pdata->dumper, "filtered");
1446 json_dumper_value_string(pdata->dumper, fi->hfinfo->abbrev);
1447 json_dumper_end_object(pdata->dumper);
1448 } else {
1449 ek_write_field_value(fi, pdata);
1450 }
1451 } else {
1452 /* Object */
1453 json_dumper_begin_object(pdata->dumper);
1454
1455 if (pdata->filter != NULL) {
1456 if (ek_check_protocolfilter(pdata->filter, fi->hfinfo->abbrev)) {
1457 gchar **_filter = NULL;
1458 /* Remove protocol filter for children, if children should be included */
1459 if ((pdata->filter_flags&PF_INCLUDE_CHILDREN) == PF_INCLUDE_CHILDREN) {
1460 _filter = pdata->filter;
1461 pdata->filter = NULL;
1462 }
1463
1464 proto_tree_write_node_ek(pnode, pdata);
1465
1466 /* Put protocol filter back */
1467 if ((pdata->filter_flags&PF_INCLUDE_CHILDREN) == PF_INCLUDE_CHILDREN) {
1468 pdata->filter = _filter;
1469 }
1470 } else {
1471 /* print dummy field */
1472 json_dumper_set_member_name(pdata->dumper, "filtered");
1473 json_dumper_value_string(pdata->dumper, fi->hfinfo->abbrev);
1474 }
1475 } else {
1476 proto_tree_write_node_ek(pnode, pdata);
1477 }
1478
1479 json_dumper_end_object(pdata->dumper);
1480 }
1481
1482 current_node = current_node->next;
1483 }
1484
1485 if (g_slist_length(attr_instances) > 1) {
1486 json_dumper_end_array(pdata->dumper);
1487 }
1488 }
1489
1490 /* Write out a tree's data, and any child nodes, as JSON for EK */
1491 static void
proto_tree_write_node_ek(proto_node * node,write_json_data * pdata)1492 proto_tree_write_node_ek(proto_node *node, write_json_data *pdata)
1493 {
1494 GSList *attr_list = NULL;
1495 GHashTable *attr_table = g_hash_table_new_full(g_str_hash, g_str_equal, g_free, NULL);
1496
1497 ek_fill_attr(node, &attr_list, attr_table, pdata);
1498
1499 g_hash_table_destroy(attr_table);
1500
1501 // Print attributes
1502 attr_list = g_slist_reverse(attr_list);
1503 GSList *current_attr = attr_list;
1504 while (current_attr != NULL) {
1505 GSList *attr_instances = (GSList *) current_attr->data;
1506
1507 ek_write_attr(attr_instances, pdata);
1508
1509 current_attr = current_attr->next;
1510 }
1511
1512 g_slist_free_full(attr_list, (GDestroyNotify) g_slist_free);
1513 }
1514
1515 /* Print info for a 'geninfo' pseudo-protocol. This is required by
1516 * the PDML spec. The information is contained in Wireshark's 'frame' protocol,
1517 * but we produce a 'geninfo' protocol in the PDML to conform to spec.
1518 * The 'frame' protocol follows the 'geninfo' protocol in the PDML. */
1519 static void
print_pdml_geninfo(epan_dissect_t * edt,FILE * fh)1520 print_pdml_geninfo(epan_dissect_t *edt, FILE *fh)
1521 {
1522 guint32 num, len, caplen;
1523 GPtrArray *finfo_array;
1524 field_info *frame_finfo;
1525 gchar *tmp;
1526
1527 /* Get frame protocol's finfo. */
1528 finfo_array = proto_find_first_finfo(edt->tree, proto_frame);
1529 if (g_ptr_array_len(finfo_array) < 1) {
1530 return;
1531 }
1532 frame_finfo = (field_info *)finfo_array->pdata[0];
1533 g_ptr_array_free(finfo_array, TRUE);
1534
1535 /* frame.number, packet_info.num */
1536 num = edt->pi.num;
1537
1538 /* frame.frame_len, packet_info.frame_data->pkt_len */
1539 len = edt->pi.fd->pkt_len;
1540
1541 /* frame.cap_len --> packet_info.frame_data->cap_len */
1542 caplen = edt->pi.fd->cap_len;
1543
1544 /* Print geninfo start */
1545 fprintf(fh,
1546 " <proto name=\"geninfo\" pos=\"0\" showname=\"General information\" size=\"%d\">\n",
1547 frame_finfo->length);
1548
1549 /* Print geninfo.num */
1550 fprintf(fh,
1551 " <field name=\"num\" pos=\"0\" show=\"%u\" showname=\"Number\" value=\"%x\" size=\"%d\"/>\n",
1552 num, num, frame_finfo->length);
1553
1554 /* Print geninfo.len */
1555 fprintf(fh,
1556 " <field name=\"len\" pos=\"0\" show=\"%u\" showname=\"Frame Length\" value=\"%x\" size=\"%d\"/>\n",
1557 len, len, frame_finfo->length);
1558
1559 /* Print geninfo.caplen */
1560 fprintf(fh,
1561 " <field name=\"caplen\" pos=\"0\" show=\"%u\" showname=\"Captured Length\" value=\"%x\" size=\"%d\"/>\n",
1562 caplen, caplen, frame_finfo->length);
1563
1564 tmp = abs_time_to_str(NULL, &edt->pi.abs_ts, ABSOLUTE_TIME_LOCAL, TRUE);
1565
1566 /* Print geninfo.timestamp */
1567 fprintf(fh,
1568 " <field name=\"timestamp\" pos=\"0\" show=\"%s\" showname=\"Captured Time\" value=\"%d.%09d\" size=\"%d\"/>\n",
1569 tmp, (int)edt->pi.abs_ts.secs, edt->pi.abs_ts.nsecs, frame_finfo->length);
1570
1571 wmem_free(NULL, tmp);
1572
1573 /* Print geninfo end */
1574 fprintf(fh,
1575 " </proto>\n");
1576 }
1577
1578 void
write_pdml_finale(FILE * fh)1579 write_pdml_finale(FILE *fh)
1580 {
1581 fputs("</pdml>\n", fh);
1582 }
1583
1584 void
write_psml_preamble(column_info * cinfo,FILE * fh)1585 write_psml_preamble(column_info *cinfo, FILE *fh)
1586 {
1587 gint i;
1588
1589 fprintf(fh, "<?xml version=\"1.0\" encoding=\"utf-8\"?>\n");
1590 fprintf(fh, "<psml version=\"" PSML_VERSION "\" creator=\"%s/%s\">\n", PACKAGE, VERSION);
1591 fprintf(fh, "<structure>\n");
1592
1593 for (i = 0; i < cinfo->num_cols; i++) {
1594 if (!get_column_visible(i))
1595 continue;
1596 fprintf(fh, "<section>");
1597 print_escaped_xml(fh, cinfo->columns[i].col_title);
1598 fprintf(fh, "</section>\n");
1599 }
1600
1601 fprintf(fh, "</structure>\n\n");
1602 }
1603
1604 void
write_psml_columns(epan_dissect_t * edt,FILE * fh,gboolean use_color)1605 write_psml_columns(epan_dissect_t *edt, FILE *fh, gboolean use_color)
1606 {
1607 gint i;
1608 const color_filter_t *cfp = edt->pi.fd->color_filter;
1609
1610 if (use_color && (cfp != NULL)) {
1611 fprintf(fh, "<packet foreground='#%06x' background='#%06x'>\n",
1612 color_t_to_rgb(&cfp->fg_color),
1613 color_t_to_rgb(&cfp->bg_color));
1614 } else {
1615 fprintf(fh, "<packet>\n");
1616 }
1617
1618 for (i = 0; i < edt->pi.cinfo->num_cols; i++) {
1619 if (!get_column_visible(i))
1620 continue;
1621 fprintf(fh, "<section>");
1622 print_escaped_xml(fh, edt->pi.cinfo->columns[i].col_data);
1623 fprintf(fh, "</section>\n");
1624 }
1625
1626 fprintf(fh, "</packet>\n\n");
1627 }
1628
1629 void
write_psml_finale(FILE * fh)1630 write_psml_finale(FILE *fh)
1631 {
1632 fputs("</psml>\n", fh);
1633 }
1634
csv_massage_str(const gchar * source,const gchar * exceptions)1635 static gchar *csv_massage_str(const gchar *source, const gchar *exceptions)
1636 {
1637 gchar *csv_str;
1638 gchar *tmp_str;
1639
1640 /* In general, our output for any field can contain Unicode characters,
1641 so g_strescape (which escapes any non-ASCII) is the wrong thing to do.
1642 Unfortunately glib doesn't appear to provide g_unicode_strescape()... */
1643 csv_str = g_strescape(source, exceptions);
1644 tmp_str = csv_str;
1645 /* Locate the UTF-8 right arrow character and replace it by an ASCII equivalent */
1646 while ( (tmp_str = strstr(tmp_str, UTF8_RIGHTWARDS_ARROW)) != NULL ) {
1647 tmp_str[0] = ' ';
1648 tmp_str[1] = '>';
1649 tmp_str[2] = ' ';
1650 }
1651 tmp_str = csv_str;
1652 while ( (tmp_str = strstr(tmp_str, "\\\"")) != NULL )
1653 *tmp_str = '\"';
1654 return csv_str;
1655 }
1656
csv_write_str(const char * str,char sep,FILE * fh)1657 static void csv_write_str(const char *str, char sep, FILE *fh)
1658 {
1659 gchar *csv_str;
1660
1661 /* Do not escape the UTF-8 right arrow character */
1662 csv_str = csv_massage_str(str, UTF8_RIGHTWARDS_ARROW);
1663 fprintf(fh, "\"%s\"%c", csv_str, sep);
1664 g_free(csv_str);
1665 }
1666
1667 void
write_csv_column_titles(column_info * cinfo,FILE * fh)1668 write_csv_column_titles(column_info *cinfo, FILE *fh)
1669 {
1670 gint i;
1671
1672 for (i = 0; i < cinfo->num_cols - 1; i++) {
1673 if (!get_column_visible(i))
1674 continue;
1675 csv_write_str(cinfo->columns[i].col_title, ',', fh);
1676 }
1677 csv_write_str(cinfo->columns[i].col_title, '\n', fh);
1678 }
1679
1680 void
write_csv_columns(epan_dissect_t * edt,FILE * fh)1681 write_csv_columns(epan_dissect_t *edt, FILE *fh)
1682 {
1683 gint i;
1684
1685 for (i = 0; i < edt->pi.cinfo->num_cols - 1; i++) {
1686 if (!get_column_visible(i))
1687 continue;
1688 csv_write_str(edt->pi.cinfo->columns[i].col_data, ',', fh);
1689 }
1690 csv_write_str(edt->pi.cinfo->columns[i].col_data, '\n', fh);
1691 }
1692
1693 void
write_carrays_hex_data(guint32 num,FILE * fh,epan_dissect_t * edt)1694 write_carrays_hex_data(guint32 num, FILE *fh, epan_dissect_t *edt)
1695 {
1696 guint32 i = 0, src_num = 0;
1697 GSList *src_le;
1698 tvbuff_t *tvb;
1699 char *name;
1700 const guchar *cp;
1701 guint length;
1702 char ascii[9];
1703 struct data_source *src;
1704
1705 for (src_le = edt->pi.data_src; src_le != NULL; src_le = src_le->next) {
1706 memset(ascii, 0, sizeof(ascii));
1707 src = (struct data_source *)src_le->data;
1708 tvb = get_data_source_tvb(src);
1709 length = tvb_captured_length(tvb);
1710 if (length == 0)
1711 continue;
1712
1713 cp = tvb_get_ptr(tvb, 0, length);
1714
1715 name = get_data_source_name(src);
1716 if (name) {
1717 fprintf(fh, "/* %s */\n", name);
1718 wmem_free(NULL, name);
1719 }
1720 if (src_num) {
1721 fprintf(fh, "static const unsigned char pkt%u_%u[%u] = {\n",
1722 num, src_num, length);
1723 } else {
1724 fprintf(fh, "static const unsigned char pkt%u[%u] = {\n",
1725 num, length);
1726 }
1727 src_num++;
1728
1729 for (i = 0; i < length; i++) {
1730 fprintf(fh, "0x%02x", *(cp + i));
1731 ascii[i % 8] = g_ascii_isprint(*(cp + i)) ? *(cp + i) : '.';
1732
1733 if (i == (length - 1)) {
1734 guint rem;
1735 rem = length % 8;
1736 if (rem) {
1737 guint j;
1738 for ( j = 0; j < 8 - rem; j++ )
1739 fprintf(fh, " ");
1740 }
1741 fprintf(fh, " /* %s */\n};\n\n", ascii);
1742 break;
1743 }
1744
1745 if (!((i + 1) % 8)) {
1746 fprintf(fh, ", /* %s */\n", ascii);
1747 memset(ascii, 0, sizeof(ascii));
1748 } else {
1749 fprintf(fh, ", ");
1750 }
1751 }
1752 }
1753 }
1754
1755 /*
1756 * Find the data source for a specified field, and return a pointer
1757 * to the data in it. Returns NULL if the data is out of bounds.
1758 */
1759 /* XXX: What am I missing ?
1760 * Why bother searching for fi->ds_tvb for the matching tvb
1761 * in the data_source list ?
1762 * IOW: Why not just use fi->ds_tvb for the arg to tvb_get_ptr() ?
1763 */
1764
1765 static const guint8 *
get_field_data(GSList * src_list,field_info * fi)1766 get_field_data(GSList *src_list, field_info *fi)
1767 {
1768 GSList *src_le;
1769 tvbuff_t *src_tvb;
1770 gint length, tvbuff_length;
1771 struct data_source *src;
1772
1773 for (src_le = src_list; src_le != NULL; src_le = src_le->next) {
1774 src = (struct data_source *)src_le->data;
1775 src_tvb = get_data_source_tvb(src);
1776 if (fi->ds_tvb == src_tvb) {
1777 /*
1778 * Found it.
1779 *
1780 * XXX - a field can have a length that runs past
1781 * the end of the tvbuff. Ideally, that should
1782 * be fixed when adding an item to the protocol
1783 * tree, but checking the length when doing
1784 * that could be expensive. Until we fix that,
1785 * we'll do the check here.
1786 */
1787 tvbuff_length = tvb_captured_length_remaining(src_tvb,
1788 fi->start);
1789 if (tvbuff_length < 0) {
1790 return NULL;
1791 }
1792 length = fi->length;
1793 if (length > tvbuff_length)
1794 length = tvbuff_length;
1795 return tvb_get_ptr(src_tvb, fi->start, length);
1796 }
1797 }
1798 return NULL; /* not found */
1799 }
1800
1801 /* Print a string, escaping out certain characters that need to
1802 * escaped out for XML. */
1803 static void
print_escaped_xml(FILE * fh,const char * unescaped_string)1804 print_escaped_xml(FILE *fh, const char *unescaped_string)
1805 {
1806 const char *p;
1807
1808 #define ESCAPED_BUFFER_MAX 256
1809 static char temp_buffer[ESCAPED_BUFFER_MAX];
1810 gint offset = 0;
1811
1812 if (fh == NULL || unescaped_string == NULL) {
1813 return;
1814 }
1815
1816 for (p = unescaped_string; *p != '\0' && (offset<(ESCAPED_BUFFER_MAX-1)); p++) {
1817 switch (*p) {
1818 case '&':
1819 (void) g_strlcpy(&temp_buffer[offset], "&", ESCAPED_BUFFER_MAX-offset);
1820 offset += 5;
1821 break;
1822 case '<':
1823 (void) g_strlcpy(&temp_buffer[offset], "<", ESCAPED_BUFFER_MAX-offset);
1824 offset += 4;
1825 break;
1826 case '>':
1827 (void) g_strlcpy(&temp_buffer[offset], ">", ESCAPED_BUFFER_MAX-offset);
1828 offset += 4;
1829 break;
1830 case '"':
1831 (void) g_strlcpy(&temp_buffer[offset], """, ESCAPED_BUFFER_MAX-offset);
1832 offset += 6;
1833 break;
1834 case '\'':
1835 (void) g_strlcpy(&temp_buffer[offset], "'", ESCAPED_BUFFER_MAX-offset);
1836 offset += 6;
1837 break;
1838 default:
1839 temp_buffer[offset++] = *p;
1840 }
1841 if (offset > ESCAPED_BUFFER_MAX-8) {
1842 /* Getting close to end of buffer so flush to fh */
1843 temp_buffer[offset] = '\0';
1844 fputs(temp_buffer, fh);
1845 offset = 0;
1846 }
1847 }
1848 if (offset) {
1849 /* Flush any outstanding data */
1850 temp_buffer[offset] = '\0';
1851 fputs(temp_buffer, fh);
1852 }
1853 }
1854
1855 static void
print_escaped_csv(FILE * fh,const char * unescaped_string)1856 print_escaped_csv(FILE *fh, const char *unescaped_string)
1857 {
1858 const char *p;
1859
1860 if (fh == NULL || unescaped_string == NULL) {
1861 return;
1862 }
1863
1864 for (p = unescaped_string; *p != '\0'; p++) {
1865 switch (*p) {
1866 case '\b':
1867 fputs("\\b", fh);
1868 break;
1869 case '\f':
1870 fputs("\\f", fh);
1871 break;
1872 case '\n':
1873 fputs("\\n", fh);
1874 break;
1875 case '\r':
1876 fputs("\\r", fh);
1877 break;
1878 case '\t':
1879 fputs("\\t", fh);
1880 break;
1881 default:
1882 fputc(*p, fh);
1883 }
1884 }
1885 }
1886
1887 static void
pdml_write_field_hex_value(write_pdml_data * pdata,field_info * fi)1888 pdml_write_field_hex_value(write_pdml_data *pdata, field_info *fi)
1889 {
1890 int i;
1891 const guint8 *pd;
1892
1893 if (!fi->ds_tvb)
1894 return;
1895
1896 if (fi->length > tvb_captured_length_remaining(fi->ds_tvb, fi->start)) {
1897 fprintf(pdata->fh, "field length invalid!");
1898 return;
1899 }
1900
1901 /* Find the data for this field. */
1902 pd = get_field_data(pdata->src_list, fi);
1903
1904 if (pd) {
1905 /* Used fixed buffer where can, otherwise temp malloc */
1906 static gchar str_static[129];
1907 gchar *str = str_static;
1908 gchar* str_heap = NULL;
1909 if (fi->length > 64) {
1910 str_heap = (gchar*)g_malloc0(fi->length*2+1);
1911 str = str_heap;
1912 }
1913
1914 static const char hex[] = "0123456789abcdef";
1915
1916 /* Print a simple hex dump */
1917 for (i = 0 ; i < fi->length; i++) {
1918 str[2*i] = hex[pd[i] >> 4];
1919 str[2*i+1] = hex[pd[i] & 0xf];
1920 }
1921 str[2 * fi->length] = '\0';
1922 fputs(str, pdata->fh);
1923 g_free(str_heap);
1924
1925 }
1926 }
1927
1928 static void
json_write_field_hex_value(write_json_data * pdata,field_info * fi)1929 json_write_field_hex_value(write_json_data *pdata, field_info *fi)
1930 {
1931 const guint8 *pd;
1932
1933 if (!fi->ds_tvb)
1934 return;
1935
1936 if (fi->length > tvb_captured_length_remaining(fi->ds_tvb, fi->start)) {
1937 json_dumper_value_string(pdata->dumper, "field length invalid!");
1938 return;
1939 }
1940
1941 /* Find the data for this field. */
1942 pd = get_field_data(pdata->src_list, fi);
1943
1944 if (pd) {
1945 gint i;
1946 guint len = fi->length * 2 + 1;
1947 gchar* str = (gchar*)g_malloc0(len);
1948 static const char hex[] = "0123456789abcdef";
1949 /* Print a simple hex dump */
1950 for (i = 0; i < fi->length; i++) {
1951 guint8 c = pd[i];
1952 str[2 * i] = hex[c >> 4];
1953 str[2 * i + 1] = hex[c & 0xf];
1954 }
1955 str[2 * fi->length] = '\0';
1956 json_dumper_value_string(pdata->dumper, str);
1957 g_free(str);
1958 } else {
1959 json_dumper_value_string(pdata->dumper, "");
1960 }
1961 }
1962
1963 gboolean
print_hex_data(print_stream_t * stream,epan_dissect_t * edt)1964 print_hex_data(print_stream_t *stream, epan_dissect_t *edt)
1965 {
1966 gboolean multiple_sources;
1967 GSList *src_le;
1968 tvbuff_t *tvb;
1969 char *line, *name;
1970 const guchar *cp;
1971 guint length;
1972 struct data_source *src;
1973
1974 /*
1975 * Set "multiple_sources" iff this frame has more than one
1976 * data source; if it does, we need to print the name of
1977 * the data source before printing the data from the
1978 * data source.
1979 */
1980 multiple_sources = (edt->pi.data_src->next != NULL);
1981
1982 for (src_le = edt->pi.data_src; src_le != NULL;
1983 src_le = src_le->next) {
1984 src = (struct data_source *)src_le->data;
1985 tvb = get_data_source_tvb(src);
1986 if (multiple_sources) {
1987 name = get_data_source_name(src);
1988 line = g_strdup_printf("%s:", name);
1989 wmem_free(NULL, name);
1990 print_line(stream, 0, line);
1991 g_free(line);
1992 }
1993 length = tvb_captured_length(tvb);
1994 if (length == 0)
1995 return TRUE;
1996 cp = tvb_get_ptr(tvb, 0, length);
1997 if (!print_hex_data_buffer(stream, cp, length,
1998 (packet_char_enc)edt->pi.fd->encoding))
1999 return FALSE;
2000 }
2001 return TRUE;
2002 }
2003
2004 /*
2005 * This routine is based on a routine created by Dan Lasley
2006 * <DLASLEY@PROMUS.com>.
2007 *
2008 * It was modified for Wireshark by Gilbert Ramirez and others.
2009 */
2010
2011 #define MAX_OFFSET_LEN 8 /* max length of hex offset of bytes */
2012 #define BYTES_PER_LINE 16 /* max byte values printed on a line */
2013 #define HEX_DUMP_LEN (BYTES_PER_LINE*3)
2014 /* max number of characters hex dump takes -
2015 2 digits plus trailing blank */
2016 #define DATA_DUMP_LEN (HEX_DUMP_LEN + 2 + BYTES_PER_LINE)
2017 /* number of characters those bytes take;
2018 3 characters per byte of hex dump,
2019 2 blanks separating hex from ASCII,
2020 1 character per byte of ASCII dump */
2021 #define MAX_LINE_LEN (MAX_OFFSET_LEN + 2 + DATA_DUMP_LEN)
2022 /* number of characters per line;
2023 offset, 2 blanks separating offset
2024 from data dump, data dump */
2025
2026 static gboolean
print_hex_data_buffer(print_stream_t * stream,const guchar * cp,guint length,packet_char_enc encoding)2027 print_hex_data_buffer(print_stream_t *stream, const guchar *cp,
2028 guint length, packet_char_enc encoding)
2029 {
2030 register unsigned int ad, i, j, k, l;
2031 guchar c;
2032 gchar line[MAX_LINE_LEN + 1];
2033 unsigned int use_digits;
2034
2035 static gchar binhex[16] = {
2036 '0', '1', '2', '3', '4', '5', '6', '7',
2037 '8', '9', 'a', 'b', 'c', 'd', 'e', 'f'};
2038
2039 /*
2040 * How many of the leading digits of the offset will we supply?
2041 * We always supply at least 4 digits, but if the maximum offset
2042 * won't fit in 4 digits, we use as many digits as will be needed.
2043 */
2044 if (((length - 1) & 0xF0000000) != 0)
2045 use_digits = 8; /* need all 8 digits */
2046 else if (((length - 1) & 0x0F000000) != 0)
2047 use_digits = 7; /* need 7 digits */
2048 else if (((length - 1) & 0x00F00000) != 0)
2049 use_digits = 6; /* need 6 digits */
2050 else if (((length - 1) & 0x000F0000) != 0)
2051 use_digits = 5; /* need 5 digits */
2052 else
2053 use_digits = 4; /* we'll supply 4 digits */
2054
2055 ad = 0;
2056 i = 0;
2057 j = 0;
2058 k = 0;
2059 while (i < length) {
2060 if ((i & 15) == 0) {
2061 /*
2062 * Start of a new line.
2063 */
2064 j = 0;
2065 l = use_digits;
2066 do {
2067 l--;
2068 c = (ad >> (l*4)) & 0xF;
2069 line[j++] = binhex[c];
2070 } while (l != 0);
2071 line[j++] = ' ';
2072 line[j++] = ' ';
2073 memset(line+j, ' ', DATA_DUMP_LEN);
2074
2075 /*
2076 * Offset in line of ASCII dump.
2077 */
2078 k = j + HEX_DUMP_LEN + 2;
2079 }
2080 c = *cp++;
2081 line[j++] = binhex[c>>4];
2082 line[j++] = binhex[c&0xf];
2083 j++;
2084 if (encoding == PACKET_CHAR_ENC_CHAR_EBCDIC) {
2085 c = EBCDIC_to_ASCII1(c);
2086 }
2087 line[k++] = ((c >= ' ') && (c < 0x7f)) ? c : '.';
2088 i++;
2089 if (((i & 15) == 0) || (i == length)) {
2090 /*
2091 * We'll be starting a new line, or
2092 * we're finished printing this buffer;
2093 * dump out the line we've constructed,
2094 * and advance the offset.
2095 */
2096 line[k] = '\0';
2097 if (!print_line(stream, 0, line))
2098 return FALSE;
2099 ad += 16;
2100 }
2101 }
2102 return TRUE;
2103 }
2104
output_fields_num_fields(output_fields_t * fields)2105 gsize output_fields_num_fields(output_fields_t* fields)
2106 {
2107 ws_assert(fields);
2108
2109 if (NULL == fields->fields) {
2110 return 0;
2111 } else {
2112 return fields->fields->len;
2113 }
2114 }
2115
output_fields_free(output_fields_t * fields)2116 void output_fields_free(output_fields_t* fields)
2117 {
2118 ws_assert(fields);
2119
2120 if (NULL != fields->fields) {
2121 gsize i;
2122
2123 if (NULL != fields->field_indicies) {
2124 /* Keys are stored in fields->fields, values are
2125 * integers.
2126 */
2127 g_hash_table_destroy(fields->field_indicies);
2128 }
2129
2130 if (NULL != fields->field_values) {
2131 g_free(fields->field_values);
2132 }
2133
2134 for (i = 0; i < fields->fields->len; ++i) {
2135 gchar* field = (gchar *)g_ptr_array_index(fields->fields,i);
2136 g_free(field);
2137 }
2138 g_ptr_array_free(fields->fields, TRUE);
2139 }
2140
2141 g_free(fields);
2142 }
2143
2144 #define COLUMN_FIELD_FILTER "_ws.col."
2145
output_fields_add(output_fields_t * fields,const gchar * field)2146 void output_fields_add(output_fields_t *fields, const gchar *field)
2147 {
2148 gchar *field_copy;
2149
2150 ws_assert(fields);
2151 ws_assert(field);
2152
2153
2154 if (NULL == fields->fields) {
2155 fields->fields = g_ptr_array_new();
2156 }
2157
2158 field_copy = g_strdup(field);
2159
2160 g_ptr_array_add(fields->fields, field_copy);
2161
2162 /* See if we have a column as a field entry */
2163 if (!strncmp(field, COLUMN_FIELD_FILTER, strlen(COLUMN_FIELD_FILTER)))
2164 fields->includes_col_fields = TRUE;
2165
2166 }
2167
2168 static void
output_field_check(void * data,void * user_data)2169 output_field_check(void *data, void *user_data)
2170 {
2171 gchar *field = (gchar *)data;
2172 GSList **invalid_fields = (GSList **)user_data;
2173
2174 if (!strncmp(field, COLUMN_FIELD_FILTER, strlen(COLUMN_FIELD_FILTER)))
2175 return;
2176
2177 if (!proto_registrar_get_byname(field)) {
2178 *invalid_fields = g_slist_prepend(*invalid_fields, field);
2179 }
2180
2181 }
2182
2183 GSList *
output_fields_valid(output_fields_t * fields)2184 output_fields_valid(output_fields_t *fields)
2185 {
2186 GSList *invalid_fields = NULL;
2187 if (fields->fields == NULL) {
2188 return NULL;
2189 }
2190
2191 g_ptr_array_foreach(fields->fields, output_field_check, &invalid_fields);
2192
2193 return invalid_fields;
2194 }
2195
output_fields_set_option(output_fields_t * info,gchar * option)2196 gboolean output_fields_set_option(output_fields_t *info, gchar *option)
2197 {
2198 const gchar *option_name;
2199 const gchar *option_value;
2200
2201 ws_assert(info);
2202 ws_assert(option);
2203
2204 if ('\0' == *option) {
2205 return FALSE; /* this happens if we're called from tshark -E '' */
2206 }
2207 option_name = strtok(option, "=");
2208 if (!option_name) {
2209 return FALSE;
2210 }
2211 option_value = option + strlen(option_name) + 1;
2212 if (*option_value == '\0') {
2213 return FALSE;
2214 }
2215
2216 if (0 == strcmp(option_name, "header")) {
2217 switch (*option_value) {
2218 case 'n':
2219 info->print_header = FALSE;
2220 break;
2221 case 'y':
2222 info->print_header = TRUE;
2223 break;
2224 default:
2225 return FALSE;
2226 }
2227 return TRUE;
2228 }
2229 else if (0 == strcmp(option_name, "separator")) {
2230 switch (*option_value) {
2231 case '/':
2232 switch (*++option_value) {
2233 case 't':
2234 info->separator = '\t';
2235 break;
2236 case 's':
2237 info->separator = ' ';
2238 break;
2239 default:
2240 info->separator = '\\';
2241 }
2242 break;
2243 default:
2244 info->separator = *option_value;
2245 break;
2246 }
2247 return TRUE;
2248 }
2249 else if (0 == strcmp(option_name, "occurrence")) {
2250 switch (*option_value) {
2251 case 'f':
2252 case 'l':
2253 case 'a':
2254 info->occurrence = *option_value;
2255 break;
2256 default:
2257 return FALSE;
2258 }
2259 return TRUE;
2260 }
2261 else if (0 == strcmp(option_name, "aggregator")) {
2262 switch (*option_value) {
2263 case '/':
2264 switch (*++option_value) {
2265 case 's':
2266 info->aggregator = ' ';
2267 break;
2268 default:
2269 info->aggregator = '\\';
2270 }
2271 break;
2272 default:
2273 info->aggregator = *option_value;
2274 break;
2275 }
2276 return TRUE;
2277 }
2278 else if (0 == strcmp(option_name, "quote")) {
2279 switch (*option_value) {
2280 case 'd':
2281 info->quote = '"';
2282 break;
2283 case 's':
2284 info->quote = '\'';
2285 break;
2286 case 'n':
2287 info->quote = '\0';
2288 break;
2289 default:
2290 info->quote = '\0';
2291 return FALSE;
2292 }
2293 return TRUE;
2294 }
2295 else if (0 == strcmp(option_name, "bom")) {
2296 switch (*option_value) {
2297 case 'n':
2298 info->print_bom = FALSE;
2299 break;
2300 case 'y':
2301 info->print_bom = TRUE;
2302 break;
2303 default:
2304 return FALSE;
2305 }
2306 return TRUE;
2307 }
2308
2309 return FALSE;
2310 }
2311
output_fields_list_options(FILE * fh)2312 void output_fields_list_options(FILE *fh)
2313 {
2314 fprintf(fh, "TShark: The available options for field output \"E\" are:\n");
2315 fputs("bom=y|n Prepend output with the UTF-8 BOM (def: N: no)\n", fh);
2316 fputs("header=y|n Print field abbreviations as first line of output (def: N: no)\n", fh);
2317 fputs("separator=/t|/s|<character> Set the separator to use;\n \"/t\" = tab, \"/s\" = space (def: /t: tab)\n", fh);
2318 fputs("occurrence=f|l|a Select the occurrence of a field to use;\n \"f\" = first, \"l\" = last, \"a\" = all (def: a: all)\n", fh);
2319 fputs("aggregator=,|/s|<character> Set the aggregator to use;\n \",\" = comma, \"/s\" = space (def: ,: comma)\n", fh);
2320 fputs("quote=d|s|n Print either d: double-quotes, s: single quotes or \n n: no quotes around field values (def: n: none)\n", fh);
2321 }
2322
output_fields_has_cols(output_fields_t * fields)2323 gboolean output_fields_has_cols(output_fields_t* fields)
2324 {
2325 ws_assert(fields);
2326 return fields->includes_col_fields;
2327 }
2328
write_fields_preamble(output_fields_t * fields,FILE * fh)2329 void write_fields_preamble(output_fields_t* fields, FILE *fh)
2330 {
2331 gsize i;
2332
2333 ws_assert(fields);
2334 ws_assert(fh);
2335 ws_assert(fields->fields);
2336
2337 if (fields->print_bom) {
2338 fputs(UTF8_BOM, fh);
2339 }
2340
2341
2342 if (!fields->print_header) {
2343 return;
2344 }
2345
2346 for(i = 0; i < fields->fields->len; ++i) {
2347 const gchar* field = (const gchar *)g_ptr_array_index(fields->fields,i);
2348 if (i != 0 ) {
2349 fputc(fields->separator, fh);
2350 }
2351 fputs(field, fh);
2352 }
2353 fputc('\n', fh);
2354 }
2355
format_field_values(output_fields_t * fields,gpointer field_index,gchar * value)2356 static void format_field_values(output_fields_t* fields, gpointer field_index, gchar* value)
2357 {
2358 guint indx;
2359 GPtrArray* fv_p;
2360
2361 if (NULL == value)
2362 return;
2363
2364 /* Unwrap change made to disambiguiate zero / null */
2365 indx = GPOINTER_TO_UINT(field_index) - 1;
2366
2367 if (fields->field_values[indx] == NULL) {
2368 fields->field_values[indx] = g_ptr_array_new();
2369 }
2370
2371 /* Essentially: fieldvalues[indx] is a 'GPtrArray *' with each array entry */
2372 /* pointing to a string which is (part of) the final output string. */
2373
2374 fv_p = fields->field_values[indx];
2375
2376 switch (fields->occurrence) {
2377 case 'f':
2378 /* print the value of only the first occurrence of the field */
2379 if (g_ptr_array_len(fv_p) != 0) {
2380 /*
2381 * This isn't the first occurrence, so the value won't be used;
2382 * free it.
2383 */
2384 g_free(value);
2385 return;
2386 }
2387 break;
2388 case 'l':
2389 /* print the value of only the last occurrence of the field */
2390 if (g_ptr_array_len(fv_p) != 0) {
2391 /*
2392 * This isn't the first occurrence, so there's already a
2393 * value in the array, which won't be used; free the
2394 * first (only) element in the array, and then remove
2395 * it - this value will replace it.
2396 */
2397 g_free(g_ptr_array_index(fv_p, 0));
2398 g_ptr_array_set_size(fv_p, 0);
2399 }
2400 break;
2401 case 'a':
2402 /* print the value of all accurrences of the field */
2403 if (g_ptr_array_len(fv_p) != 0) {
2404 /*
2405 * This isn't the first occurrence. so add the "aggregator"
2406 * character as a separator between the previous element
2407 * and this element.
2408 */
2409 g_ptr_array_add(fv_p, (gpointer)g_strdup_printf("%c", fields->aggregator));
2410 }
2411 break;
2412 default:
2413 ws_assert_not_reached();
2414 break;
2415 }
2416
2417 g_ptr_array_add(fv_p, (gpointer)value);
2418 }
2419
proto_tree_get_node_field_values(proto_node * node,gpointer data)2420 static void proto_tree_get_node_field_values(proto_node *node, gpointer data)
2421 {
2422 write_field_data_t *call_data;
2423 field_info *fi;
2424 gpointer field_index;
2425
2426 call_data = (write_field_data_t *)data;
2427 fi = PNODE_FINFO(node);
2428
2429 /* dissection with an invisible proto tree? */
2430 ws_assert(fi);
2431
2432 field_index = g_hash_table_lookup(call_data->fields->field_indicies, fi->hfinfo->abbrev);
2433 if (NULL != field_index) {
2434 format_field_values(call_data->fields, field_index,
2435 get_node_field_value(fi, call_data->edt) /* g_ alloc'd string */
2436 );
2437 }
2438
2439 /* Recurse here. */
2440 if (node->first_child != NULL) {
2441 proto_tree_children_foreach(node, proto_tree_get_node_field_values,
2442 call_data);
2443 }
2444 }
2445
write_specified_fields(fields_format format,output_fields_t * fields,epan_dissect_t * edt,column_info * cinfo,FILE * fh,json_dumper * dumper)2446 static void write_specified_fields(fields_format format, output_fields_t *fields, epan_dissect_t *edt, column_info *cinfo, FILE *fh, json_dumper *dumper)
2447 {
2448 gsize i;
2449 gint col;
2450 gchar *col_name;
2451 gpointer field_index;
2452
2453 write_field_data_t data;
2454
2455 ws_assert(fields);
2456 ws_assert(fields->fields);
2457 ws_assert(edt);
2458 /* JSON formats must go through json_dumper */
2459 if (format == FORMAT_JSON || format == FORMAT_EK) {
2460 ws_assert(!fh && dumper);
2461 } else {
2462 ws_assert(fh && !dumper);
2463 }
2464
2465 data.fields = fields;
2466 data.edt = edt;
2467
2468 if (NULL == fields->field_indicies) {
2469 /* Prepare a lookup table from string abbreviation for field to its index. */
2470 fields->field_indicies = g_hash_table_new(g_str_hash, g_str_equal);
2471
2472 i = 0;
2473 while (i < fields->fields->len) {
2474 gchar *field = (gchar *)g_ptr_array_index(fields->fields, i);
2475 /* Store field indicies +1 so that zero is not a valid value,
2476 * and can be distinguished from NULL as a pointer.
2477 */
2478 ++i;
2479 g_hash_table_insert(fields->field_indicies, field, GUINT_TO_POINTER(i));
2480 }
2481 }
2482
2483 /* Array buffer to store values for this packet */
2484 /* Allocate an array for the 'GPtrarray *' the first time */
2485 /* ths function is invoked for a file; */
2486 /* Any and all 'GPtrArray *' are freed (after use) each */
2487 /* time (each packet) this function is invoked for a flle. */
2488 /* XXX: ToDo: use packet-scope'd memory & (if/when implemented) wmem ptr_array */
2489 if (NULL == fields->field_values)
2490 fields->field_values = g_new0(GPtrArray*, fields->fields->len); /* free'd in output_fields_free() */
2491
2492 proto_tree_children_foreach(edt->tree, proto_tree_get_node_field_values,
2493 &data);
2494
2495 /* Add columns to fields */
2496 if (fields->includes_col_fields) {
2497 for (col = 0; col < cinfo->num_cols; col++) {
2498 if (!get_column_visible(col))
2499 continue;
2500 /* Prepend COLUMN_FIELD_FILTER as the field name */
2501 col_name = g_strdup_printf("%s%s", COLUMN_FIELD_FILTER, cinfo->columns[col].col_title);
2502 field_index = g_hash_table_lookup(fields->field_indicies, col_name);
2503 g_free(col_name);
2504
2505 if (NULL != field_index) {
2506 format_field_values(fields, field_index, g_strdup(cinfo->columns[col].col_data));
2507 }
2508 }
2509 }
2510
2511 switch (format) {
2512 case FORMAT_CSV:
2513 for(i = 0; i < fields->fields->len; ++i) {
2514 if (0 != i) {
2515 fputc(fields->separator, fh);
2516 }
2517 if (NULL != fields->field_values[i]) {
2518 GPtrArray *fv_p;
2519 gchar * str;
2520 gsize j;
2521 fv_p = fields->field_values[i];
2522 if (fields->quote != '\0') {
2523 fputc(fields->quote, fh);
2524 }
2525
2526 /* Output the array of (partial) field values */
2527 for (j = 0; j < g_ptr_array_len(fv_p); j++ ) {
2528 str = (gchar *)g_ptr_array_index(fv_p, j);
2529 print_escaped_csv(fh, str);
2530 g_free(str);
2531 }
2532 if (fields->quote != '\0') {
2533 fputc(fields->quote, fh);
2534 }
2535 g_ptr_array_free(fv_p, TRUE); /* get ready for the next packet */
2536 fields->field_values[i] = NULL;
2537 }
2538 }
2539 break;
2540 case FORMAT_XML:
2541 for(i = 0; i < fields->fields->len; ++i) {
2542 gchar *field = (gchar *)g_ptr_array_index(fields->fields, i);
2543
2544 if (NULL != fields->field_values[i]) {
2545 GPtrArray *fv_p;
2546 gchar * str;
2547 gsize j;
2548 fv_p = fields->field_values[i];
2549
2550 /* Output the array of (partial) field values */
2551 for (j = 0; j < (g_ptr_array_len(fv_p)); j+=2 ) {
2552 str = (gchar *)g_ptr_array_index(fv_p, j);
2553
2554 fprintf(fh, " <field name=\"%s\" value=", field);
2555 fputs("\"", fh);
2556 print_escaped_xml(fh, str);
2557 fputs("\"/>\n", fh);
2558 g_free(str);
2559 }
2560 g_ptr_array_free(fv_p, TRUE); /* get ready for the next packet */
2561 fields->field_values[i] = NULL;
2562 }
2563 }
2564 break;
2565 case FORMAT_JSON:
2566 json_dumper_begin_object(dumper);
2567 for(i = 0; i < fields->fields->len; ++i) {
2568 gchar *field = (gchar *)g_ptr_array_index(fields->fields, i);
2569
2570 if (NULL != fields->field_values[i]) {
2571 GPtrArray *fv_p;
2572 gchar * str;
2573 gsize j;
2574 fv_p = fields->field_values[i];
2575
2576 json_dumper_set_member_name(dumper, field);
2577 json_dumper_begin_array(dumper);
2578
2579 /* Output the array of (partial) field values */
2580 for (j = 0; j < (g_ptr_array_len(fv_p)); j += 2) {
2581 str = (gchar *) g_ptr_array_index(fv_p, j);
2582 json_dumper_value_string(dumper, str);
2583 g_free(str);
2584 }
2585
2586 json_dumper_end_array(dumper);
2587
2588 g_ptr_array_free(fv_p, TRUE); /* get ready for the next packet */
2589 fields->field_values[i] = NULL;
2590 }
2591 }
2592 json_dumper_end_object(dumper);
2593 break;
2594 case FORMAT_EK:
2595 for(i = 0; i < fields->fields->len; ++i) {
2596 gchar *field = (gchar *)g_ptr_array_index(fields->fields, i);
2597
2598 if (NULL != fields->field_values[i]) {
2599 GPtrArray *fv_p;
2600 gchar * str;
2601 gsize j;
2602 fv_p = fields->field_values[i];
2603
2604 json_dumper_set_member_name(dumper, field);
2605 json_dumper_begin_array(dumper);
2606
2607 /* Output the array of (partial) field values */
2608 for (j = 0; j < (g_ptr_array_len(fv_p)); j += 2) {
2609 str = (gchar *)g_ptr_array_index(fv_p, j);
2610 json_dumper_value_string(dumper, str);
2611 g_free(str);
2612 }
2613
2614 json_dumper_end_array(dumper);
2615
2616 g_ptr_array_free(fv_p, TRUE); /* get ready for the next packet */
2617 fields->field_values[i] = NULL;
2618 }
2619 }
2620 break;
2621
2622 default:
2623 fprintf(stderr, "Unknown fields format %d\n", format);
2624 ws_assert_not_reached();
2625 break;
2626 }
2627 }
2628
write_fields_finale(output_fields_t * fields _U_,FILE * fh _U_)2629 void write_fields_finale(output_fields_t* fields _U_ , FILE *fh _U_)
2630 {
2631 /* Nothing to do */
2632 }
2633
2634 /* Returns an g_malloced string */
get_node_field_value(field_info * fi,epan_dissect_t * edt)2635 gchar* get_node_field_value(field_info* fi, epan_dissect_t* edt)
2636 {
2637 if (fi->hfinfo->id == hf_text_only) {
2638 /* Text label.
2639 * Get the text */
2640 if (fi->rep) {
2641 return g_strdup(fi->rep->representation);
2642 }
2643 else {
2644 return get_field_hex_value(edt->pi.data_src, fi);
2645 }
2646 }
2647 else if (fi->hfinfo->id == proto_data) {
2648 /* Uninterpreted data, i.e., the "Data" protocol, is
2649 * printed as a field instead of a protocol. */
2650 return get_field_hex_value(edt->pi.data_src, fi);
2651 }
2652 else {
2653 /* Normal protocols and fields */
2654 gchar *dfilter_string;
2655
2656 switch (fi->hfinfo->type)
2657 {
2658 case FT_PROTOCOL:
2659 /* Print out the full details for the protocol. */
2660 if (fi->rep) {
2661 return g_strdup(fi->rep->representation);
2662 } else {
2663 /* Just print out the protocol abbreviation */
2664 return g_strdup(fi->hfinfo->abbrev);
2665 }
2666 case FT_NONE:
2667 /* Return "1" so that the presence of a field of type
2668 * FT_NONE can be checked when using -T fields */
2669 return g_strdup("1");
2670 case FT_UINT_BYTES:
2671 case FT_BYTES:
2672 {
2673 gchar *ret;
2674 guint8 *bytes = (guint8 *)fvalue_get(&fi->value);
2675 if (bytes) {
2676 dfilter_string = (gchar *)wmem_alloc(NULL, 3*fvalue_length(&fi->value));
2677 switch (fi->hfinfo->display) {
2678 case SEP_DOT:
2679 ret = bytes_to_hexstr_punct(dfilter_string, bytes, fvalue_length(&fi->value), '.');
2680 break;
2681 case SEP_DASH:
2682 ret = bytes_to_hexstr_punct(dfilter_string, bytes, fvalue_length(&fi->value), '-');
2683 break;
2684 case SEP_COLON:
2685 ret = bytes_to_hexstr_punct(dfilter_string, bytes, fvalue_length(&fi->value), ':');
2686 break;
2687 case SEP_SPACE:
2688 ret = bytes_to_hexstr_punct(dfilter_string, bytes, fvalue_length(&fi->value), ' ');
2689 break;
2690 case BASE_NONE:
2691 default:
2692 ret = bytes_to_hexstr(dfilter_string, bytes, fvalue_length(&fi->value));
2693 break;
2694 }
2695 *ret = '\0';
2696 ret = g_strdup(dfilter_string);
2697 wmem_free(NULL, dfilter_string);
2698 } else {
2699 if (fi->hfinfo->display & BASE_ALLOW_ZERO) {
2700 ret = g_strdup("<none>");
2701 } else {
2702 ret = g_strdup("<MISSING>");
2703 }
2704 }
2705 return ret;
2706 }
2707 break;
2708 default:
2709 dfilter_string = fvalue_to_string_repr(NULL, &fi->value, FTREPR_DISPLAY, fi->hfinfo->display);
2710 if (dfilter_string != NULL) {
2711 gchar* ret = g_strdup(dfilter_string);
2712 wmem_free(NULL, dfilter_string);
2713 return ret;
2714 } else {
2715 return get_field_hex_value(edt->pi.data_src, fi);
2716 }
2717 }
2718 }
2719 }
2720
2721 static gchar*
get_field_hex_value(GSList * src_list,field_info * fi)2722 get_field_hex_value(GSList *src_list, field_info *fi)
2723 {
2724 const guint8 *pd;
2725
2726 if (!fi->ds_tvb)
2727 return NULL;
2728
2729 if (fi->length > tvb_captured_length_remaining(fi->ds_tvb, fi->start)) {
2730 return g_strdup("field length invalid!");
2731 }
2732
2733 /* Find the data for this field. */
2734 pd = get_field_data(src_list, fi);
2735
2736 if (pd) {
2737 int i;
2738 gchar *buffer;
2739 gchar *p;
2740 int len;
2741 const int chars_per_byte = 2;
2742
2743 len = chars_per_byte * fi->length;
2744 buffer = (gchar *)g_malloc(sizeof(gchar)*(len + 1));
2745 buffer[len] = '\0'; /* Ensure NULL termination in bad cases */
2746 p = buffer;
2747 /* Print a simple hex dump */
2748 for (i = 0 ; i < fi->length; i++) {
2749 g_snprintf(p, chars_per_byte+1, "%02x", pd[i]);
2750 p += chars_per_byte;
2751 }
2752 return buffer;
2753 } else {
2754 return NULL;
2755 }
2756 }
2757
output_fields_new(void)2758 output_fields_t* output_fields_new(void)
2759 {
2760 output_fields_t* fields = g_new(output_fields_t, 1);
2761 fields->print_bom = FALSE;
2762 fields->print_header = FALSE;
2763 fields->separator = '\t';
2764 fields->occurrence = 'a';
2765 fields->aggregator = ',';
2766 fields->fields = NULL; /*Do lazy initialisation */
2767 fields->field_indicies = NULL;
2768 fields->field_values = NULL;
2769 fields->quote ='\0';
2770 fields->includes_col_fields = FALSE;
2771 return fields;
2772 }
2773
2774 /*
2775 * Editor modelines - https://www.wireshark.org/tools/modelines.html
2776 *
2777 * Local variables:
2778 * c-basic-offset: 4
2779 * tab-width: 8
2780 * indent-tabs-mode: nil
2781 * End:
2782 *
2783 * vi: set shiftwidth=4 tabstop=8 expandtab:
2784 * :indentSize=4:tabSize=8:noTabs=true:
2785 */
2786