Coverage Report

Created: 2025-12-27 06:52

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