forked from osmocom/wireshark
a4c8ebc18b
Have all dissector tables have a "supports Decode As" flag, which defaults to FALSE, and which is set to TRUE if a register_decode_as() refers to it. When adding a dissector to a dissector table with a given key, only add it for Decode As if the dissector table supports it. For non-FT_STRING dissector tables, always check for multiple entries for the same protocol with different dissectors, and report an error if we found them. This means there's no need for the creator of a dissector table to specify whether duplicates of that sort should be allowed - we always do the check when registering something for "Decode As" (in a non-FT_STRING dissector table), and just don't bother registering anything for "Decode As" if the dissector table doesn't support "Decode As", so there's no check done for those dissector tables. Change-Id: I4a1fdea3bddc2af27a65cfbca23edc99b26c0eed Reviewed-on: https://code.wireshark.org/review/17402 Petri-Dish: Guy Harris <guy@alum.mit.edu> Reviewed-by: Guy Harris <guy@alum.mit.edu>
417 lines
14 KiB
C
417 lines
14 KiB
C
/* file-file.c
|
|
*
|
|
* Top-most file dissector. Decides dissector based on Filetap Encapsulation Type.
|
|
*
|
|
* Wireshark - Network traffic analyzer
|
|
* By Gerald Combs <gerald@wireshark.org>
|
|
* Copyright 2000 Gerald Combs
|
|
*
|
|
* This program is free software; you can redistribute it and/or
|
|
* modify it under the terms of the GNU General Public License
|
|
* as published by the Free Software Foundation; either version 2
|
|
* of the License, or (at your option) any later version.
|
|
*
|
|
* This program is distributed in the hope that it will be useful,
|
|
* but WITHOUT ANY WARRANTY; without even the implied warranty of
|
|
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
|
* GNU General Public License for more details.
|
|
*
|
|
* You should have received a copy of the GNU General Public License
|
|
* along with this program; if not, write to the Free Software
|
|
* Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA.
|
|
*/
|
|
|
|
#include "config.h"
|
|
|
|
#ifdef _MSC_VER
|
|
#include <windows.h>
|
|
#endif
|
|
|
|
#include <epan/packet.h>
|
|
#include <epan/epan.h>
|
|
#include <epan/exceptions.h>
|
|
#include <epan/show_exception.h>
|
|
#include <epan/timestamp.h>
|
|
#include <epan/prefs.h>
|
|
#include <epan/to_str.h>
|
|
#include <epan/tap.h>
|
|
#include <epan/expert.h>
|
|
#include <epan/proto_data.h>
|
|
|
|
#include <wsutil/md5.h>
|
|
#include <wsutil/str_util.h>
|
|
|
|
#include <epan/color_filters.h>
|
|
|
|
#include "file-file.h"
|
|
|
|
void proto_register_file(void);
|
|
|
|
static int proto_file = -1;
|
|
static int hf_file_record_number = -1;
|
|
static int hf_file_record_len = -1;
|
|
static int hf_file_ftap_encap = -1;
|
|
static int hf_file_marked = -1;
|
|
static int hf_file_ignored = -1;
|
|
static int hf_file_protocols = -1;
|
|
static int hf_file_num_p_prot_data = -1;
|
|
static int hf_file_proto_name_and_key = -1;
|
|
static int hf_file_color_filter_name = -1;
|
|
static int hf_file_color_filter_text = -1;
|
|
|
|
static gint ett_file = -1;
|
|
|
|
static int file_tap = -1;
|
|
|
|
dissector_table_t file_encap_dissector_table;
|
|
|
|
/*
|
|
* Routine used to register record end routine. The routine should only
|
|
* be registered when the dissector is used in the record, not in the
|
|
* proto_register_XXX function.
|
|
*/
|
|
void
|
|
register_file_record_end_routine(packet_info *pinfo, void (*func)(void))
|
|
{
|
|
pinfo->frame_end_routines = g_slist_append(pinfo->frame_end_routines, (gpointer)func);
|
|
}
|
|
|
|
typedef void (*void_func_t)(void);
|
|
|
|
static void
|
|
call_file_record_end_routine(gpointer routine, gpointer dummy _U_)
|
|
{
|
|
void_func_t func = (void_func_t)routine;
|
|
(*func)();
|
|
}
|
|
|
|
/* XXX - "packet comment" is passed into dissector as data, but currently doesn't have a use */
|
|
static int
|
|
dissect_file_record(tvbuff_t *tvb, packet_info *pinfo, proto_tree *parent_tree, void* data)
|
|
{
|
|
proto_item *volatile ti = NULL;
|
|
guint cap_len = 0, frame_len = 0;
|
|
proto_tree *volatile fh_tree = NULL;
|
|
proto_tree *volatile tree;
|
|
proto_item *item;
|
|
const gchar *cap_plurality, *frame_plurality;
|
|
const color_filter_t *color_filter;
|
|
file_data_t *file_data = (file_data_t*)data;
|
|
|
|
tree=parent_tree;
|
|
|
|
pinfo->current_proto = "File";
|
|
|
|
/* if FILE is not referenced from any filters we don't need to worry about
|
|
generating any tree items. */
|
|
if(!proto_field_is_referenced(tree, proto_file)) {
|
|
tree=NULL;
|
|
} else {
|
|
/* Put in frame header information. */
|
|
cap_len = tvb_captured_length(tvb);
|
|
frame_len = tvb_reported_length(tvb);
|
|
|
|
cap_plurality = plurality(cap_len, "", "s");
|
|
frame_plurality = plurality(frame_len, "", "s");
|
|
|
|
ti = proto_tree_add_protocol_format(tree, proto_file, tvb, 0, -1,
|
|
"File record %u: %u byte%s",
|
|
pinfo->num, frame_len, frame_plurality);
|
|
proto_item_append_text(ti, ", %u byte%s",
|
|
cap_len, cap_plurality);
|
|
|
|
fh_tree = proto_item_add_subtree(ti, ett_file);
|
|
|
|
proto_tree_add_int(fh_tree, hf_file_ftap_encap, tvb, 0, 0, pinfo->pkt_encap);
|
|
|
|
proto_tree_add_uint(fh_tree, hf_file_record_number, tvb, 0, 0, pinfo->num);
|
|
|
|
proto_tree_add_uint_format(fh_tree, hf_file_record_len, tvb,
|
|
0, 0, frame_len, "Record Length: %u byte%s (%u bits)",
|
|
frame_len, frame_plurality, frame_len * 8);
|
|
|
|
ti = proto_tree_add_boolean(fh_tree, hf_file_marked, tvb, 0, 0,pinfo->fd->flags.marked);
|
|
PROTO_ITEM_SET_GENERATED(ti);
|
|
|
|
ti = proto_tree_add_boolean(fh_tree, hf_file_ignored, tvb, 0, 0,pinfo->fd->flags.ignored);
|
|
PROTO_ITEM_SET_GENERATED(ti);
|
|
|
|
if(pinfo->fd->pfd != 0){
|
|
proto_item *ppd_item;
|
|
guint num_entries = g_slist_length(pinfo->fd->pfd);
|
|
guint i;
|
|
ppd_item = proto_tree_add_uint(fh_tree, hf_file_num_p_prot_data, tvb, 0, 0, num_entries);
|
|
PROTO_ITEM_SET_GENERATED(ppd_item);
|
|
for(i=0; i<num_entries; i++){
|
|
gchar* str = p_get_proto_name_and_key(wmem_file_scope(), pinfo, i);
|
|
proto_tree_add_string_format(fh_tree, hf_file_proto_name_and_key, tvb, 0, 0, str, "%s", str);
|
|
}
|
|
}
|
|
|
|
#if 0
|
|
if (show_file_off) {
|
|
proto_tree_add_int64_format_value(fh_tree, hf_frame_file_off, tvb,
|
|
0, 0, pinfo->fd->file_off,
|
|
"%" G_GINT64_MODIFIER "d (0x%" G_GINT64_MODIFIER "x)",
|
|
pinfo->fd->file_off, pinfo->fd->file_off);
|
|
}
|
|
#endif
|
|
}
|
|
|
|
if (pinfo->fd->flags.ignored) {
|
|
/* Ignored package, stop handling here */
|
|
col_set_str(pinfo->cinfo, COL_INFO, "<Ignored>");
|
|
proto_tree_add_boolean_format(tree, hf_file_ignored, tvb, 0, -1, TRUE, "This record is marked as ignored");
|
|
return tvb_captured_length(tvb);
|
|
}
|
|
|
|
/* Portable Exception Handling to trap Wireshark specific exceptions like BoundsError exceptions */
|
|
TRY {
|
|
#ifdef _MSC_VER
|
|
/* Win32: Visual-C Structured Exception Handling (SEH) to trap hardware exceptions
|
|
like memory access violations.
|
|
(a running debugger will be called before the except part below) */
|
|
/* Note: A Windows "exceptional exception" may leave the kazlib's (Portable Exception Handling)
|
|
stack in an inconsistent state thus causing a crash at some point in the
|
|
handling of the exception.
|
|
See: https://www.wireshark.org/lists/wireshark-dev/200704/msg00243.html
|
|
*/
|
|
__try {
|
|
#endif
|
|
if (!dissector_try_uint(file_encap_dissector_table, pinfo->pkt_encap,
|
|
tvb, pinfo, parent_tree)) {
|
|
|
|
col_set_str(pinfo->cinfo, COL_PROTOCOL, "UNKNOWN");
|
|
col_add_fstr(pinfo->cinfo, COL_INFO, "FTAP_ENCAP = %d",
|
|
pinfo->pkt_encap);
|
|
call_data_dissector(tvb, pinfo, parent_tree);
|
|
}
|
|
#ifdef _MSC_VER
|
|
} __except(EXCEPTION_EXECUTE_HANDLER /* handle all exceptions */) {
|
|
switch(GetExceptionCode()) {
|
|
case(STATUS_ACCESS_VIOLATION):
|
|
show_exception(tvb, pinfo, parent_tree, DissectorError,
|
|
"STATUS_ACCESS_VIOLATION: dissector accessed an invalid memory address");
|
|
break;
|
|
case(STATUS_INTEGER_DIVIDE_BY_ZERO):
|
|
show_exception(tvb, pinfo, parent_tree, DissectorError,
|
|
"STATUS_INTEGER_DIVIDE_BY_ZERO: dissector tried an integer division by zero");
|
|
break;
|
|
case(STATUS_STACK_OVERFLOW):
|
|
show_exception(tvb, pinfo, parent_tree, DissectorError,
|
|
"STATUS_STACK_OVERFLOW: dissector overflowed the stack (e.g. endless loop)");
|
|
/* XXX - this will have probably corrupted the stack,
|
|
which makes problems later in the exception code */
|
|
break;
|
|
/* XXX - add other hardware exception codes as required */
|
|
default:
|
|
show_exception(tvb, pinfo, parent_tree, DissectorError,
|
|
g_strdup_printf("dissector caused an unknown exception: 0x%x", GetExceptionCode()));
|
|
}
|
|
}
|
|
#endif
|
|
}
|
|
CATCH_BOUNDS_AND_DISSECTOR_ERRORS {
|
|
show_exception(tvb, pinfo, parent_tree, EXCEPT_CODE, GET_MESSAGE);
|
|
}
|
|
ENDTRY;
|
|
|
|
if(proto_field_is_referenced(tree, hf_file_protocols)) {
|
|
wmem_strbuf_t *val = wmem_strbuf_new(wmem_packet_scope(), "");
|
|
wmem_list_frame_t *frame;
|
|
/* skip the first entry, it's always the "frame" protocol */
|
|
frame = wmem_list_frame_next(wmem_list_head(pinfo->layers));
|
|
if (frame) {
|
|
wmem_strbuf_append(val, proto_get_protocol_filter_name(GPOINTER_TO_UINT(wmem_list_frame_data(frame))));
|
|
frame = wmem_list_frame_next(frame);
|
|
}
|
|
while (frame) {
|
|
wmem_strbuf_append_c(val, ':');
|
|
wmem_strbuf_append(val, proto_get_protocol_filter_name(GPOINTER_TO_UINT(wmem_list_frame_data(frame))));
|
|
frame = wmem_list_frame_next(frame);
|
|
}
|
|
ti = proto_tree_add_string(fh_tree, hf_file_protocols, tvb, 0, 0, wmem_strbuf_get_str(val));
|
|
PROTO_ITEM_SET_GENERATED(ti);
|
|
}
|
|
|
|
/* Call postdissectors if we have any (while trying to avoid another
|
|
* TRY/CATCH)
|
|
*/
|
|
if (have_postdissector()) {
|
|
TRY {
|
|
#ifdef _MSC_VER
|
|
/* Win32: Visual-C Structured Exception Handling (SEH)
|
|
to trap hardware exceptions like memory access violations */
|
|
/* (a running debugger will be called before the except part below) */
|
|
/* Note: A Windows "exceptional exception" may leave the kazlib's (Portable Exception Handling)
|
|
stack in an inconsistent state thus causing a crash at some point in the
|
|
handling of the exception.
|
|
See: https://www.wireshark.org/lists/wireshark-dev/200704/msg00243.html
|
|
*/
|
|
__try {
|
|
#endif
|
|
call_all_postdissectors(tvb, pinfo, parent_tree);
|
|
#ifdef _MSC_VER
|
|
} __except(EXCEPTION_EXECUTE_HANDLER /* handle all exceptions */) {
|
|
switch(GetExceptionCode()) {
|
|
case(STATUS_ACCESS_VIOLATION):
|
|
show_exception(tvb, pinfo, parent_tree, DissectorError,
|
|
"STATUS_ACCESS_VIOLATION: dissector accessed an invalid memory address");
|
|
break;
|
|
case(STATUS_INTEGER_DIVIDE_BY_ZERO):
|
|
show_exception(tvb, pinfo, parent_tree, DissectorError,
|
|
"STATUS_INTEGER_DIVIDE_BY_ZERO: dissector tried an integer division by zero");
|
|
break;
|
|
case(STATUS_STACK_OVERFLOW):
|
|
show_exception(tvb, pinfo, parent_tree, DissectorError,
|
|
"STATUS_STACK_OVERFLOW: dissector overflowed the stack (e.g. endless loop)");
|
|
/* XXX - this will have probably corrupted the stack,
|
|
which makes problems later in the exception code */
|
|
break;
|
|
/* XXX - add other hardware exception codes as required */
|
|
default:
|
|
show_exception(tvb, pinfo, parent_tree, DissectorError,
|
|
g_strdup_printf("dissector caused an unknown exception: 0x%x", GetExceptionCode()));
|
|
}
|
|
}
|
|
#endif
|
|
}
|
|
CATCH_BOUNDS_AND_DISSECTOR_ERRORS {
|
|
show_exception(tvb, pinfo, parent_tree, EXCEPT_CODE, GET_MESSAGE);
|
|
}
|
|
ENDTRY;
|
|
}
|
|
|
|
/* Attempt to (re-)calculate color filters (if any). */
|
|
if (pinfo->fd->flags.need_colorize) {
|
|
color_filter = color_filters_colorize_packet(file_data->color_edt);
|
|
pinfo->fd->color_filter = color_filter;
|
|
pinfo->fd->flags.need_colorize = 0;
|
|
} else {
|
|
color_filter = pinfo->fd->color_filter;
|
|
}
|
|
if (color_filter) {
|
|
pinfo->fd->color_filter = color_filter;
|
|
item = proto_tree_add_string(fh_tree, hf_file_color_filter_name, tvb,
|
|
0, 0, color_filter->filter_name);
|
|
PROTO_ITEM_SET_GENERATED(item);
|
|
item = proto_tree_add_string(fh_tree, hf_file_color_filter_text, tvb,
|
|
0, 0, color_filter->filter_text);
|
|
PROTO_ITEM_SET_GENERATED(item);
|
|
}
|
|
|
|
tap_queue_packet(file_tap, pinfo, NULL);
|
|
|
|
|
|
if (pinfo->frame_end_routines) {
|
|
g_slist_foreach(pinfo->frame_end_routines, &call_file_record_end_routine, NULL);
|
|
g_slist_free(pinfo->frame_end_routines);
|
|
pinfo->frame_end_routines = NULL;
|
|
}
|
|
|
|
return tvb_captured_length(tvb);
|
|
}
|
|
|
|
void
|
|
proto_register_file(void)
|
|
{
|
|
static hf_register_info hf[] = {
|
|
{ &hf_file_record_number,
|
|
{ "Record Number", "file.record_number",
|
|
FT_UINT32, BASE_DEC, NULL, 0x0,
|
|
NULL, HFILL }},
|
|
|
|
{ &hf_file_record_len,
|
|
{ "Record length", "file.record_len",
|
|
FT_UINT32, BASE_DEC, NULL, 0x0,
|
|
NULL, HFILL }},
|
|
#if 0
|
|
{ &hf_frame_file_off,
|
|
{ "File Offset", "file.offset",
|
|
FT_INT64, BASE_DEC, NULL, 0x0,
|
|
NULL, HFILL }},
|
|
#endif
|
|
{ &hf_file_marked,
|
|
{ "File record is marked", "file.marked",
|
|
FT_BOOLEAN, BASE_NONE, NULL, 0x0,
|
|
"File record is marked in the GUI", HFILL }},
|
|
|
|
{ &hf_file_ignored,
|
|
{ "File record is ignored", "file.ignored",
|
|
FT_BOOLEAN, BASE_NONE, NULL, 0x0,
|
|
"File record is ignored by the dissectors", HFILL }},
|
|
|
|
{ &hf_file_protocols,
|
|
{ "File record types in frame", "file.record_types",
|
|
FT_STRING, BASE_NONE, NULL, 0x0,
|
|
"File record types carried by this frame", HFILL }},
|
|
|
|
{ &hf_file_color_filter_name,
|
|
{ "Coloring Rule Name", "file.coloring_rule.name",
|
|
FT_STRING, BASE_NONE, NULL, 0x0,
|
|
"The file record matched the coloring rule with this name", HFILL }},
|
|
|
|
{ &hf_file_color_filter_text,
|
|
{ "Coloring Rule String", "file.coloring_rule.string",
|
|
FT_STRING, BASE_NONE, NULL, 0x0,
|
|
"The file record matched this coloring rule string", HFILL }},
|
|
|
|
{ &hf_file_num_p_prot_data,
|
|
{ "Number of per-record-data", "file.p_record_data",
|
|
FT_UINT32, BASE_DEC, NULL, 0x0,
|
|
NULL, HFILL }},
|
|
|
|
{ &hf_file_proto_name_and_key,
|
|
{ "Protocol Name and Key", "file.proto_name_and_key",
|
|
FT_STRING, BASE_NONE, NULL, 0x0,
|
|
NULL, HFILL }},
|
|
|
|
{ &hf_file_ftap_encap,
|
|
{ "Encapsulation type", "file.encap_type",
|
|
FT_INT16, BASE_DEC, NULL, 0x0,
|
|
NULL, HFILL }},
|
|
};
|
|
|
|
static gint *ett[] = {
|
|
&ett_file
|
|
};
|
|
|
|
#if 0
|
|
module_t *file_module;
|
|
#endif
|
|
|
|
proto_file = proto_register_protocol("File", "File", "file");
|
|
proto_register_field_array(proto_file, hf, array_length(hf));
|
|
proto_register_subtree_array(ett, array_length(ett));
|
|
register_dissector("file",dissect_file_record,proto_file);
|
|
|
|
file_encap_dissector_table = register_dissector_table("ftap_encap",
|
|
"Filetap encapsulation type", proto_file, FT_UINT32, BASE_DEC);
|
|
|
|
/* You can't disable dissection of "Frame", as that would be
|
|
tantamount to not doing any dissection whatsoever. */
|
|
proto_set_cant_toggle(proto_file);
|
|
|
|
/* Our preferences */
|
|
#if 0
|
|
frame_module = prefs_register_protocol(proto_frame, NULL);
|
|
prefs_register_bool_preference(frame_module, "show_file_off",
|
|
"Show File Offset", "Show offset of frame in capture file", &show_file_off);
|
|
#endif
|
|
|
|
file_tap=register_tap("file");
|
|
}
|
|
|
|
/*
|
|
* Editor modelines - http://www.wireshark.org/tools/modelines.html
|
|
*
|
|
* Local variables:
|
|
* c-basic-offset: 8
|
|
* tab-width: 8
|
|
* indent-tabs-mode: t
|
|
* End:
|
|
*
|
|
* vi: set shiftwidth=8 tabstop=8 noexpandtab:
|
|
* :indentSize=8:tabSize=8:noTabs=false:
|
|
*/
|