tshark: Add new long option --hexdump <hexoption>

This commit is contained in:
Jim Young 2022-01-13 01:18:38 +00:00 committed by A Wireshark GitLab Utility
parent fdc5166234
commit b5f89dbe2d
6 changed files with 178 additions and 14 deletions

View File

@ -1025,6 +1025,76 @@ Cause *TShark* to print a hex and ASCII dump of the packet data
after printing the summary and/or details, if either are also being displayed.
--
--hexdump <hexoption>::
+
--
Cause *TShark* to print a hex and ASCII dump of the packet data
with the ability to select which data sources to dump and how to
format or exclude the ASCII dump text.
This option can be used multiple times where the data source *<hexoption>*
is *all* or *frames* and the ASCII dump text *<hexoption>* is *ascii*,
*delimit*, *noascii*.
Example: tshark ... --hexdump frames --hexdump delimit ...
*all*::
Enable hexdump, generate hexdump blocks for all data sources associated
with each frame. Used to negate earlier use of `--hexdump frames`.
The *-x* option displays all data sources by default.
*frames*::
Enable hexdump, generate hexdump blocks only for the frame data. Use
this option to exclude, from hexdump output, any hexdump blocks for
secondary data sources such as 'Bitstring tvb', 'Reassembled TCP',
'De-chunked entity body', etc.
*ascii*::
Enable hexdump, with undelimited ASCII dump text. Used to negate earlier
use of `--hexdump delimit` or `--hexdump noascii`. The *-x* option
displays undelimited ASCII dump text by default.
*delimit*::
Enable hexdump with the ASCII dump text delimited with '|' characters.
This is useful to unambigiously determine the last of the hex byte text
and start of the ASCII dump text.
*noascii*::
Enable hexdump without printing any ASCII dump text.
*help*::
Display --hexdump specific help then exit.
The use of *--hexdump <hexoption>* is particularly useful to generate output
that can be used to create a pcap or pcapng file from a capture file type such
as Microsoft NetMon 2.x which *TShark* and *Wireshark* can read but can not
directly do a "Save as" nor export packets from.
Examples:
Generate hexdump output, with only the frame data source, with delimited ASCII
dump text, with each frame hex block preceeded by a human readable timestamp that
is directly usable by the *text2pcap* utility:
tshark ... --hexdump frames --hexdump delimit \
-P -t ad -o gui.column.format:"Time","%t" \
| text2pcap -n -t '%F %T.%f' - MYNEWPCAPNG
Generate hexdump output, with only the frame data source, with no ASCII dump text,
with each frame hex block preceeded by an epoch timestamp that is directly
usable by the *text2pcap* utility:
tshark ... --hexdump frames --hexdump noascii \
-P -t e -o gui.column.format:"Time","%t" \
| text2pcap -n -t %s.%f - MYNEWPCAPNG
--
-X <eXtension options>::
+
--

View File

@ -91,7 +91,8 @@ static const guint8 *get_field_data(GSList *src_list, field_info *fi);
static void pdml_write_field_hex_value(write_pdml_data *pdata, field_info *fi);
static void json_write_field_hex_value(write_json_data *pdata, field_info *fi);
static gboolean print_hex_data_buffer(print_stream_t *stream, const guchar *cp,
guint length, packet_char_enc encoding);
guint length, packet_char_enc encoding,
guint hexdump_options);
static void write_specified_fields(fields_format format,
output_fields_t *fields,
epan_dissect_t *edt, column_info *cinfo,
@ -223,7 +224,7 @@ proto_tree_print_node(proto_node *node, gpointer data)
return;
}
if (!print_hex_data_buffer(pdata->stream, pd,
fi->length, pdata->encoding)) {
fi->length, pdata->encoding, HEXDUMP_ASCII_INCLUDE)) {
pdata->success = FALSE;
return;
}
@ -1961,7 +1962,7 @@ json_write_field_hex_value(write_json_data *pdata, field_info *fi)
}
gboolean
print_hex_data(print_stream_t *stream, epan_dissect_t *edt)
print_hex_data(print_stream_t *stream, epan_dissect_t *edt, guint hexdump_options)
{
gboolean multiple_sources;
GSList *src_le;
@ -1983,7 +1984,7 @@ print_hex_data(print_stream_t *stream, epan_dissect_t *edt)
src_le = src_le->next) {
src = (struct data_source *)src_le->data;
tvb = get_data_source_tvb(src);
if (multiple_sources) {
if (multiple_sources && (HEXDUMP_SOURCE_OPTION(hexdump_options) == HEXDUMP_SOURCE_MULTI)) {
name = get_data_source_name(src);
line = ws_strdup_printf("%s:", name);
wmem_free(NULL, name);
@ -1995,8 +1996,12 @@ print_hex_data(print_stream_t *stream, epan_dissect_t *edt)
return TRUE;
cp = tvb_get_ptr(tvb, 0, length);
if (!print_hex_data_buffer(stream, cp, length,
(packet_char_enc)edt->pi.fd->encoding))
(packet_char_enc)edt->pi.fd->encoding,
HEXDUMP_ASCII_OPTION(hexdump_options)))
return FALSE;
if (HEXDUMP_SOURCE_OPTION(hexdump_options) == HEXDUMP_SOURCE_PRIMARY) {
return TRUE;
}
}
return TRUE;
}
@ -2013,10 +2018,11 @@ print_hex_data(print_stream_t *stream, epan_dissect_t *edt)
#define HEX_DUMP_LEN (BYTES_PER_LINE*3)
/* max number of characters hex dump takes -
2 digits plus trailing blank */
#define DATA_DUMP_LEN (HEX_DUMP_LEN + 2 + BYTES_PER_LINE)
#define DATA_DUMP_LEN (HEX_DUMP_LEN + 2 + 2 + BYTES_PER_LINE)
/* number of characters those bytes take;
3 characters per byte of hex dump,
2 blanks separating hex from ASCII,
2 optional ASCII dump delimiters,
1 character per byte of ASCII dump */
#define MAX_LINE_LEN (MAX_OFFSET_LEN + 2 + DATA_DUMP_LEN)
/* number of characters per line;
@ -2025,7 +2031,7 @@ print_hex_data(print_stream_t *stream, epan_dissect_t *edt)
static gboolean
print_hex_data_buffer(print_stream_t *stream, const guchar *cp,
guint length, packet_char_enc encoding)
guint length, packet_char_enc encoding, guint ascii_option)
{
register unsigned int ad, i, j, k, l;
guchar c;
@ -2076,15 +2082,19 @@ print_hex_data_buffer(print_stream_t *stream, const guchar *cp,
* Offset in line of ASCII dump.
*/
k = j + HEX_DUMP_LEN + 2;
if (ascii_option == HEXDUMP_ASCII_DELIMIT)
line[k++] = '|';
}
c = *cp++;
line[j++] = binhex[c>>4];
line[j++] = binhex[c&0xf];
j++;
if (encoding == PACKET_CHAR_ENC_CHAR_EBCDIC) {
c = EBCDIC_to_ASCII1(c);
if (ascii_option != HEXDUMP_ASCII_EXCLUDE ) {
if (encoding == PACKET_CHAR_ENC_CHAR_EBCDIC) {
c = EBCDIC_to_ASCII1(c);
}
line[k++] = ((c >= ' ') && (c < 0x7f)) ? c : '.';
}
line[k++] = ((c >= ' ') && (c < 0x7f)) ? c : '.';
i++;
if (((i & 15) == 0) || (i == length)) {
/*
@ -2093,6 +2103,8 @@ print_hex_data_buffer(print_stream_t *stream, const guchar *cp,
* dump out the line we've constructed,
* and advance the offset.
*/
if (ascii_option == HEXDUMP_ASCII_DELIMIT)
line[k++] = '|';
line[k] = '\0';
if (!print_line(stream, 0, line))
return FALSE;

View File

@ -80,7 +80,29 @@ WS_DLL_PUBLIC gboolean proto_tree_print(print_dissections_e print_dissections,
epan_dissect_t *edt,
GHashTable *output_only_tables,
print_stream_t *stream);
WS_DLL_PUBLIC gboolean print_hex_data(print_stream_t *stream, epan_dissect_t *edt);
/*
* Hexdump options for ASCII:
*/
#define HEXDUMP_ASCII_MASK (0x0003U)
#define HEXDUMP_ASCII_OPTION(option) ((option) & HEXDUMP_ASCII_MASK)
#define HEXDUMP_ASCII_INCLUDE (0x0000U) /* include ASCII section no delimiters (legacy tshark behavior) */
#define HEXDUMP_ASCII_DELIMIT (0x0001U) /* include ASCII section with delimiters, useful for reliable detection of last hexdata */
#define HEXDUMP_ASCII_EXCLUDE (0x0002U) /* exclude ASCII section from hexdump reports, if we really don't want or need it */
/*
* Hexdump option for displaying data sources:
*/
#define HEXDUMP_SOURCE_MASK (0x0004U)
#define HEXDUMP_SOURCE_OPTION(option) ((option) & HEXDUMP_SOURCE_MASK)
#define HEXDUMP_SOURCE_MULTI (0x0000U) /* create hexdumps for all data sources assigned to a frame (legacy tshark behavor) */
#define HEXDUMP_SOURCE_PRIMARY (0x0004U) /* create hexdumps for only the frame data */
WS_DLL_PUBLIC gboolean print_hex_data(print_stream_t *stream, epan_dissect_t *edt, guint hexdump_options);
WS_DLL_PUBLIC void write_pdml_preamble(FILE *fh, const gchar* filename);
WS_DLL_PUBLIC void write_pdml_proto_tree(output_fields_t* fields, gchar **protocolfilter, pf_flags protocolfilter_flags, epan_dissect_t *edt, column_info *cinfo, FILE *fh, gboolean use_color);

2
file.c
View File

@ -2467,7 +2467,7 @@ print_packet(capture_file *cf, frame_data *fdata, wtap_rec *rec, Buffer *buf,
goto fail;
}
/* Print the full packet data as hex. */
if (!print_hex_data(args->print_args->stream, &args->edt))
if (!print_hex_data(args->print_args->stream, &args->edt, HEXDUMP_SOURCE_MULTI | HEXDUMP_ASCII_INCLUDE))
goto fail;
/* Print a blank line if we print anything after this (aka more than one packet). */

View File

@ -1962,7 +1962,7 @@ print_packet(capture_file *cf, epan_dissect_t *edt)
if (!print_line(print_stream, 0, ""))
return FALSE;
}
if (!print_hex_data(print_stream, edt))
if (!print_hex_data(print_stream, edt, HEXDUMP_SOURCE_MULTI | HEXDUMP_ASCII_INCLUDE))
return FALSE;
if (!print_line(print_stream, 0, separator))
return FALSE;

View File

@ -134,6 +134,7 @@
#define LONGOPT_ELASTIC_MAPPING_FILTER LONGOPT_BASE_APPLICATION+4
#define LONGOPT_EXPORT_TLS_SESSION_KEYS LONGOPT_BASE_APPLICATION+5
#define LONGOPT_CAPTURE_COMMENT LONGOPT_BASE_APPLICATION+6
#define LONGOPT_HEXDUMP LONGOPT_BASE_APPLICATION+7
capture_file cfile;
@ -171,6 +172,8 @@ static gboolean quiet = FALSE;
static gboolean really_quiet = FALSE;
static gchar* delimiter_char = " ";
static gboolean dissect_color = FALSE;
static guint hexdump_source_option = HEXDUMP_SOURCE_MULTI; /* Default - Enable legacy multi-source mode */
static guint hexdump_ascii_option = HEXDUMP_ASCII_INCLUDE; /* Default - Enable legacy undelimited ASCII dump */
static print_format_e print_format = PR_FMT_TEXT;
static print_stream_t *print_stream = NULL;
@ -428,6 +431,13 @@ print_usage(FILE *output)
fprintf(output, " -P, --print print packet summary even when writing to a file\n");
fprintf(output, " -S <separator> the line separator to print between packets\n");
fprintf(output, " -x add output of hex and ASCII dump (Packet Bytes)\n");
fprintf(output, " --hexdump <hexoption> add hexdump, set options for data source and ASCII dump\n");
fprintf(output, " all dump all data sources (-x default)\n");
fprintf(output, " frames dump only frame data source\n");
fprintf(output, " ascii include ASCII dump text (-x default)\n");
fprintf(output, " delimit delimit ASCII dump text with '|' characters\n");
fprintf(output, " noascii exclude ASCII dump text\n");
fprintf(output, " help display help for --hexdump and exit\n");
fprintf(output, " -T pdml|ps|psml|json|jsonraw|ek|tabs|text|fields|?\n");
fprintf(output, " format of text output (def: text)\n");
fprintf(output, " -j <protocolfilter> protocols layers filter if -T ek|pdml|json selected\n");
@ -527,6 +537,31 @@ glossary_option_help(void)
fprintf(output, "\n");
}
static void
hexdump_option_help(FILE *output)
{
fprintf(output, "%s\n", get_appname_and_version());
fprintf(output, "\n");
fprintf(output, "tshark: Valid --hexdump <hexoption> values include:\n");
fprintf(output, "\n");
fprintf(output, "Data source options:\n");
fprintf(output, " all add hexdump, dump all data sources (-x default)\n");
fprintf(output, " frames add hexdump, dump only frame data source\n");
fprintf(output, "\n");
fprintf(output, "ASCII options:\n");
fprintf(output, " ascii add hexdump, include ASCII dump text (-x default)\n");
fprintf(output, " delimit add hexdump, delimit ASCII dump text with '|' characters\n");
fprintf(output, " noascii add hexdump, exclude ASCII dump text\n");
fprintf(output, "\n");
fprintf(output, "Miscellaneous:\n");
fprintf(output, " help display this help and exit\n");
fprintf(output, "\n");
fprintf(output, "Example:\n");
fprintf(output, "\n");
fprintf(output, " $ tshark ... --hexdump frames --hexdump delimit ...\n");
fprintf(output, "\n");
}
static void
print_current_user(void) {
gchar *cur_user, *cur_group;
@ -701,6 +736,7 @@ main(int argc, char *argv[])
{"no-duplicate-keys", ws_no_argument, NULL, LONGOPT_NO_DUPLICATE_KEYS},
{"elastic-mapping-filter", ws_required_argument, NULL, LONGOPT_ELASTIC_MAPPING_FILTER},
{"capture-comment", ws_required_argument, NULL, LONGOPT_CAPTURE_COMMENT},
{"hexdump", ws_required_argument, NULL, LONGOPT_HEXDUMP},
{0, 0, 0, 0 }
};
gboolean arg_error = FALSE;
@ -1476,6 +1512,30 @@ main(int argc, char *argv[])
}
g_ptr_array_add(capture_comments, g_strdup(ws_optarg));
break;
case LONGOPT_HEXDUMP:
print_hex = TRUE;
print_packet_info = TRUE;
if (strcmp(ws_optarg, "all") == 0)
hexdump_source_option = HEXDUMP_SOURCE_MULTI;
else if (strcmp(ws_optarg, "frames") == 0)
hexdump_source_option = HEXDUMP_SOURCE_PRIMARY;
else if (strcmp(ws_optarg, "ascii") == 0)
hexdump_ascii_option = HEXDUMP_ASCII_INCLUDE;
else if (strcmp(ws_optarg, "delimit") == 0)
hexdump_ascii_option = HEXDUMP_ASCII_DELIMIT;
else if (strcmp(ws_optarg, "noascii") == 0)
hexdump_ascii_option = HEXDUMP_ASCII_EXCLUDE;
else if (strcmp("help", ws_optarg) == 0) {
hexdump_option_help(stdout);
exit_status = EXIT_SUCCESS;
goto clean_exit;
} else {
fprintf(stderr, "tshark: \"%s\" is an invalid value for --hexdump <hexoption>\n", ws_optarg);
fprintf(stderr, "For valid <hexoption> values enter: tshark --hexdump help\n");
exit_status = INVALID_OPTION;
goto clean_exit;
}
break;
default:
case '?': /* Bad flag - print usage message */
switch(ws_optopt) {
@ -4315,7 +4375,7 @@ print_packet(capture_file *cf, epan_dissect_t *edt)
if (!print_line(print_stream, 0, ""))
return FALSE;
}
if (!print_hex_data(print_stream, edt))
if (!print_hex_data(print_stream, edt, hexdump_source_option | hexdump_ascii_option))
return FALSE;
if (!print_line(print_stream, 0, separator))
return FALSE;