3 * Top-most file dissector. Decides dissector based on Filetap Encapsulation Type.
5 * Wireshark - Network traffic analyzer
6 * By Gerald Combs <gerald@wireshark.org>
7 * Copyright 2000 Gerald Combs
9 * SPDX-License-Identifier: GPL-2.0-or-later
18 #include <epan/packet.h>
19 #include <epan/exceptions.h>
20 #include <epan/show_exception.h>
22 #include <epan/proto_data.h>
23 #include <epan/color_filters.h>
24 #include <wiretap/wtap.h>
25 #include <wsutil/str_util.h>
26 #include <wsutil/array.h>
28 #include "file-file.h"
30 void proto_register_file(void);
32 static int proto_file
;
33 static int hf_file_record_number
;
34 static int hf_file_record_len
;
35 static int hf_file_ftap_encap
;
36 static int hf_file_marked
;
37 static int hf_file_ignored
;
38 static int hf_file_protocols
;
39 static int hf_file_num_p_prot_data
;
40 static int hf_file_proto_name_and_key
;
41 static int hf_file_color_filter_name
;
42 static int hf_file_color_filter_text
;
48 dissector_table_t file_encap_dissector_table
;
51 * Routine used to register record end routine. The routine should only
52 * be registered when the dissector is used in the record, not in the
53 * proto_register_XXX function.
56 register_file_record_end_routine(packet_info
*pinfo
, void (*func
)(void))
58 pinfo
->frame_end_routines
= g_slist_append(pinfo
->frame_end_routines
, (void *)func
);
61 typedef void (*void_func_t
)(void);
64 call_file_record_end_routine(void *routine
, void *dummy _U_
)
66 void_func_t func
= (void_func_t
)routine
;
70 /* XXX - "packet comment" is passed into dissector as data, but currently doesn't have a use */
72 dissect_file_record(tvbuff_t
*tvb
, packet_info
*pinfo
, proto_tree
*parent_tree
, void* data
)
74 proto_item
*volatile ti
= NULL
;
75 proto_tree
*volatile fh_tree
= NULL
;
76 proto_tree
*volatile tree
;
78 const char *cap_plurality
, *frame_plurality
;
79 const color_filter_t
*color_filter
;
80 file_data_t
*file_data
= (file_data_t
*)data
;
84 pinfo
->current_proto
= "File";
86 /* if FILE is not referenced from any filters we don't need to worry about
87 generating any tree items. */
88 if(!proto_field_is_referenced(tree
, proto_file
)) {
91 unsigned cap_len
, frame_len
;
93 /* Put in frame header information. */
94 cap_len
= tvb_captured_length(tvb
);
95 frame_len
= tvb_reported_length(tvb
);
97 cap_plurality
= plurality(cap_len
, "", "s");
98 frame_plurality
= plurality(frame_len
, "", "s");
100 ti
= proto_tree_add_protocol_format(tree
, proto_file
, tvb
, 0, -1,
101 "File record %u: %u byte%s",
102 pinfo
->num
, frame_len
, frame_plurality
);
103 proto_item_append_text(ti
, ", %u byte%s",
104 cap_len
, cap_plurality
);
106 fh_tree
= proto_item_add_subtree(ti
, ett_file
);
108 if (pinfo
->rec
->rec_type
== REC_TYPE_PACKET
)
109 proto_tree_add_int(fh_tree
, hf_file_ftap_encap
, tvb
, 0, 0, pinfo
->rec
->rec_header
.packet_header
.pkt_encap
);
111 proto_tree_add_uint(fh_tree
, hf_file_record_number
, tvb
, 0, 0, pinfo
->num
);
113 proto_tree_add_uint_format(fh_tree
, hf_file_record_len
, tvb
,
114 0, 0, frame_len
, "Record Length: %u byte%s (%u bits)",
115 frame_len
, frame_plurality
, frame_len
* 8);
117 ti
= proto_tree_add_boolean(fh_tree
, hf_file_marked
, tvb
, 0, 0,pinfo
->fd
->marked
);
118 proto_item_set_generated(ti
);
120 ti
= proto_tree_add_boolean(fh_tree
, hf_file_ignored
, tvb
, 0, 0,pinfo
->fd
->ignored
);
121 proto_item_set_generated(ti
);
123 if(pinfo
->fd
->pfd
!= 0){
124 proto_item
*ppd_item
;
125 unsigned num_entries
= g_slist_length(pinfo
->fd
->pfd
);
127 ppd_item
= proto_tree_add_uint(fh_tree
, hf_file_num_p_prot_data
, tvb
, 0, 0, num_entries
);
128 proto_item_set_generated(ppd_item
);
129 for(i
=0; i
<num_entries
; i
++){
130 char* str
= p_get_proto_name_and_key(wmem_file_scope(), pinfo
, i
);
131 proto_tree_add_string_format(fh_tree
, hf_file_proto_name_and_key
, tvb
, 0, 0, str
, "%s", str
);
137 proto_tree_add_int64_format_value(fh_tree
, hf_frame_file_off
, tvb
,
138 0, 0, pinfo
->fd
->file_off
,
139 "%" PRId64
" (0x%" PRIx64
")",
140 pinfo
->fd
->file_off
, pinfo
->fd
->file_off
);
145 if (pinfo
->fd
->ignored
) {
146 /* Ignored package, stop handling here */
147 col_set_str(pinfo
->cinfo
, COL_INFO
, "<Ignored>");
148 proto_tree_add_boolean_format(tree
, hf_file_ignored
, tvb
, 0, -1, true, "This record is marked as ignored");
149 return tvb_captured_length(tvb
);
152 /* Portable Exception Handling to trap Wireshark specific exceptions like BoundsError exceptions */
155 /* Win32: Visual-C Structured Exception Handling (SEH) to trap hardware exceptions
156 like memory access violations.
157 (a running debugger will be called before the except part below) */
158 /* Note: A Windows "exceptional exception" may leave the kazlib's (Portable Exception Handling)
159 stack in an inconsistent state thus causing a crash at some point in the
160 handling of the exception.
161 See: https://lists.wireshark.org/archives/wireshark-dev/200704/msg00243.html
165 if (pinfo
->rec
->rec_type
!= REC_TYPE_PACKET
||
166 !dissector_try_uint(file_encap_dissector_table
, pinfo
->rec
->rec_header
.packet_header
.pkt_encap
,
167 tvb
, pinfo
, parent_tree
)) {
169 col_set_str(pinfo
->cinfo
, COL_PROTOCOL
, "UNKNOWN");
170 col_add_fstr(pinfo
->cinfo
, COL_INFO
, "FTAP_ENCAP = %d",
171 pinfo
->rec
->rec_header
.packet_header
.pkt_encap
);
172 call_data_dissector(tvb
, pinfo
, parent_tree
);
175 } __except(EXCEPTION_EXECUTE_HANDLER
/* handle all exceptions */) {
176 switch(GetExceptionCode()) {
177 case(STATUS_ACCESS_VIOLATION
):
178 show_exception(tvb
, pinfo
, parent_tree
, DissectorError
,
179 "STATUS_ACCESS_VIOLATION: dissector accessed an invalid memory address");
181 case(STATUS_INTEGER_DIVIDE_BY_ZERO
):
182 show_exception(tvb
, pinfo
, parent_tree
, DissectorError
,
183 "STATUS_INTEGER_DIVIDE_BY_ZERO: dissector tried an integer division by zero");
185 case(STATUS_STACK_OVERFLOW
):
186 show_exception(tvb
, pinfo
, parent_tree
, DissectorError
,
187 "STATUS_STACK_OVERFLOW: dissector overflowed the stack (e.g. endless loop)");
188 /* XXX - this will have probably corrupted the stack,
189 which makes problems later in the exception code */
191 /* XXX - add other hardware exception codes as required */
193 show_exception(tvb
, pinfo
, parent_tree
, DissectorError
,
194 ws_strdup_printf("dissector caused an unknown exception: 0x%x", GetExceptionCode()));
199 CATCH_BOUNDS_AND_DISSECTOR_ERRORS
{
200 show_exception(tvb
, pinfo
, parent_tree
, EXCEPT_CODE
, GET_MESSAGE
);
204 if(proto_field_is_referenced(tree
, hf_file_protocols
)) {
205 wmem_strbuf_t
*val
= wmem_strbuf_new(pinfo
->pool
, "");
206 wmem_list_frame_t
*frame
;
207 /* skip the first entry, it's always the "frame" protocol */
208 frame
= wmem_list_frame_next(wmem_list_head(pinfo
->layers
));
210 wmem_strbuf_append(val
, proto_get_protocol_filter_name(GPOINTER_TO_UINT(wmem_list_frame_data(frame
))));
211 frame
= wmem_list_frame_next(frame
);
214 wmem_strbuf_append_c(val
, ':');
215 wmem_strbuf_append(val
, proto_get_protocol_filter_name(GPOINTER_TO_UINT(wmem_list_frame_data(frame
))));
216 frame
= wmem_list_frame_next(frame
);
218 ti
= proto_tree_add_string(fh_tree
, hf_file_protocols
, tvb
, 0, 0, wmem_strbuf_get_str(val
));
219 proto_item_set_generated(ti
);
222 /* Call postdissectors if we have any (while trying to avoid another
225 if (have_postdissector()) {
228 /* Win32: Visual-C Structured Exception Handling (SEH)
229 to trap hardware exceptions like memory access violations */
230 /* (a running debugger will be called before the except part below) */
231 /* Note: A Windows "exceptional exception" may leave the kazlib's (Portable Exception Handling)
232 stack in an inconsistent state thus causing a crash at some point in the
233 handling of the exception.
234 See: https://lists.wireshark.org/archives/wireshark-dev/200704/msg00243.html
238 call_all_postdissectors(tvb
, pinfo
, parent_tree
);
240 } __except(EXCEPTION_EXECUTE_HANDLER
/* handle all exceptions */) {
241 switch(GetExceptionCode()) {
242 case(STATUS_ACCESS_VIOLATION
):
243 show_exception(tvb
, pinfo
, parent_tree
, DissectorError
,
244 "STATUS_ACCESS_VIOLATION: dissector accessed an invalid memory address");
246 case(STATUS_INTEGER_DIVIDE_BY_ZERO
):
247 show_exception(tvb
, pinfo
, parent_tree
, DissectorError
,
248 "STATUS_INTEGER_DIVIDE_BY_ZERO: dissector tried an integer division by zero");
250 case(STATUS_STACK_OVERFLOW
):
251 show_exception(tvb
, pinfo
, parent_tree
, DissectorError
,
252 "STATUS_STACK_OVERFLOW: dissector overflowed the stack (e.g. endless loop)");
253 /* XXX - this will have probably corrupted the stack,
254 which makes problems later in the exception code */
256 /* XXX - add other hardware exception codes as required */
258 show_exception(tvb
, pinfo
, parent_tree
, DissectorError
,
259 ws_strdup_printf("dissector caused an unknown exception: 0x%x", GetExceptionCode()));
264 CATCH_BOUNDS_AND_DISSECTOR_ERRORS
{
265 show_exception(tvb
, pinfo
, parent_tree
, EXCEPT_CODE
, GET_MESSAGE
);
270 /* Attempt to (re-)calculate color filters (if any). */
271 if (pinfo
->fd
->need_colorize
) {
272 color_filter
= color_filters_colorize_packet(file_data
->color_edt
);
273 pinfo
->fd
->color_filter
= color_filter
;
274 pinfo
->fd
->need_colorize
= 0;
276 color_filter
= pinfo
->fd
->color_filter
;
279 pinfo
->fd
->color_filter
= color_filter
;
280 item
= proto_tree_add_string(fh_tree
, hf_file_color_filter_name
, tvb
,
281 0, 0, color_filter
->filter_name
);
282 proto_item_set_generated(item
);
283 item
= proto_tree_add_string(fh_tree
, hf_file_color_filter_text
, tvb
,
284 0, 0, color_filter
->filter_text
);
285 proto_item_set_generated(item
);
288 tap_queue_packet(file_tap
, pinfo
, NULL
);
291 if (pinfo
->frame_end_routines
) {
292 g_slist_foreach(pinfo
->frame_end_routines
, &call_file_record_end_routine
, NULL
);
293 g_slist_free(pinfo
->frame_end_routines
);
294 pinfo
->frame_end_routines
= NULL
;
297 return tvb_captured_length(tvb
);
301 proto_register_file(void)
303 static hf_register_info hf
[] = {
304 { &hf_file_record_number
,
305 { "Record Number", "file.record_number",
306 FT_UINT32
, BASE_DEC
, NULL
, 0x0,
309 { &hf_file_record_len
,
310 { "Record length", "file.record_len",
311 FT_UINT32
, BASE_DEC
, NULL
, 0x0,
314 { &hf_frame_file_off
,
315 { "File Offset", "file.offset",
316 FT_INT64
, BASE_DEC
, NULL
, 0x0,
320 { "File record is marked", "file.marked",
321 FT_BOOLEAN
, BASE_NONE
, NULL
, 0x0,
322 "File record is marked in the GUI", HFILL
}},
325 { "File record is ignored", "file.ignored",
326 FT_BOOLEAN
, BASE_NONE
, NULL
, 0x0,
327 "File record is ignored by the dissectors", HFILL
}},
329 { &hf_file_protocols
,
330 { "File record types in frame", "file.record_types",
331 FT_STRING
, BASE_NONE
, NULL
, 0x0,
332 "File record types carried by this frame", HFILL
}},
334 { &hf_file_color_filter_name
,
335 { "Coloring Rule Name", "file.coloring_rule.name",
336 FT_STRING
, BASE_NONE
, NULL
, 0x0,
337 "The file record matched the coloring rule with this name", HFILL
}},
339 { &hf_file_color_filter_text
,
340 { "Coloring Rule String", "file.coloring_rule.string",
341 FT_STRING
, BASE_NONE
, NULL
, 0x0,
342 "The file record matched this coloring rule string", HFILL
}},
344 { &hf_file_num_p_prot_data
,
345 { "Number of per-record-data", "file.p_record_data",
346 FT_UINT32
, BASE_DEC
, NULL
, 0x0,
349 { &hf_file_proto_name_and_key
,
350 { "Protocol Name and Key", "file.proto_name_and_key",
351 FT_STRING
, BASE_NONE
, NULL
, 0x0,
354 { &hf_file_ftap_encap
,
355 { "Encapsulation type", "file.encap_type",
356 FT_INT16
, BASE_DEC
, NULL
, 0x0,
360 static int *ett
[] = {
365 module_t
*file_module
;
368 proto_file
= proto_register_protocol("File", "File", "file");
369 proto_register_field_array(proto_file
, hf
, array_length(hf
));
370 proto_register_subtree_array(ett
, array_length(ett
));
371 register_dissector("file",dissect_file_record
,proto_file
);
373 file_encap_dissector_table
= register_dissector_table("ftap_encap",
374 "Filetap encapsulation type", proto_file
, FT_UINT32
, BASE_DEC
);
376 /* You can't disable dissection of "Frame", as that would be
377 tantamount to not doing any dissection whatsoever. */
378 proto_set_cant_toggle(proto_file
);
380 /* Our preferences */
382 frame_module
= prefs_register_protocol(proto_frame
, NULL
);
383 prefs_register_bool_preference(frame_module
, "show_file_off",
384 "Show File Offset", "Show offset of frame in capture file", &show_file_off
);
387 file_tap
=register_tap("file");
391 * Editor modelines - https://www.wireshark.org/tools/modelines.html
396 * indent-tabs-mode: t
399 * vi: set shiftwidth=8 tabstop=8 noexpandtab:
400 * :indentSize=8:tabSize=8:noTabs=false: