nexmon – Blame information for rev 1
?pathlinks?
Rev | Author | Line No. | Line |
---|---|---|---|
1 | office | 1 | /* tfshark.c |
2 | * |
||
3 | * Text-mode variant of Fileshark, based off of TShark, |
||
4 | * |
||
5 | * Wireshark - Network traffic analyzer |
||
6 | * By Gerald Combs <gerald@wireshark.org> |
||
7 | * Copyright 1998 Gerald Combs |
||
8 | * |
||
9 | * This program is free software; you can redistribute it and/or |
||
10 | * modify it under the terms of the GNU General Public License |
||
11 | * as published by the Free Software Foundation; either version 2 |
||
12 | * of the License, or (at your option) any later version. |
||
13 | * |
||
14 | * This program is distributed in the hope that it will be useful, |
||
15 | * but WITHOUT ANY WARRANTY; without even the implied warranty of |
||
16 | * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the |
||
17 | * GNU General Public License for more details. |
||
18 | * |
||
19 | * You should have received a copy of the GNU General Public License |
||
20 | * along with this program; if not, write to the Free Software |
||
21 | * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA. |
||
22 | */ |
||
23 | |||
24 | #include <config.h> |
||
25 | |||
26 | #include <stdlib.h> |
||
27 | #include <stdio.h> |
||
28 | #include <string.h> |
||
29 | #include <locale.h> |
||
30 | #include <limits.h> |
||
31 | |||
32 | #ifdef HAVE_GETOPT_H |
||
33 | #include <getopt.h> |
||
34 | #endif |
||
35 | |||
36 | #include <errno.h> |
||
37 | |||
38 | #ifndef HAVE_GETOPT_LONG |
||
39 | #include "wsutil/wsgetopt.h" |
||
40 | #endif |
||
41 | |||
42 | #include <glib.h> |
||
43 | |||
44 | #include <epan/exceptions.h> |
||
45 | #include <epan/epan-int.h> |
||
46 | #include <epan/epan.h> |
||
47 | |||
48 | #include <wsutil/clopts_common.h> |
||
49 | #include <wsutil/cmdarg_err.h> |
||
50 | #include <wsutil/crash_info.h> |
||
51 | #include <wsutil/filesystem.h> |
||
52 | #include <wsutil/file_util.h> |
||
53 | #include <wsutil/privileges.h> |
||
54 | #include <wsutil/report_err.h> |
||
55 | #include <ws_version_info.h> |
||
56 | |||
57 | #include "globals.h" |
||
58 | #include <epan/timestamp.h> |
||
59 | #include <epan/packet.h> |
||
60 | #ifdef HAVE_LUA |
||
61 | #include <epan/wslua/init_wslua.h> |
||
62 | #endif |
||
63 | #include "file.h" |
||
64 | #include "frame_tvbuff.h" |
||
65 | #include <epan/disabled_protos.h> |
||
66 | #include <epan/prefs.h> |
||
67 | #include <epan/column.h> |
||
68 | #include <epan/print.h> |
||
69 | #include <epan/addr_resolv.h> |
||
70 | #include "ui/util.h" |
||
71 | #include "ui/decode_as_utils.h" |
||
72 | #include "register.h" |
||
73 | #include <epan/epan_dissect.h> |
||
74 | #include <epan/tap.h> |
||
75 | #include <epan/stat_tap_ui.h> |
||
76 | #include <epan/ex-opt.h> |
||
77 | |||
78 | #if defined(HAVE_HEIMDAL_KERBEROS) || defined(HAVE_MIT_KERBEROS) |
||
79 | #include <epan/asn1.h> |
||
80 | #include <epan/dissectors/packet-kerberos.h> |
||
81 | #endif |
||
82 | |||
83 | #ifdef HAVE_EXTCAP |
||
84 | #include "extcap.h" |
||
85 | #endif |
||
86 | |||
87 | #include <wiretap/wtap-int.h> |
||
88 | #include <wiretap/file_wrappers.h> |
||
89 | |||
90 | #ifdef _WIN32 |
||
91 | #include <wsutil/unicode-utils.h> |
||
92 | #endif /* _WIN32 */ |
||
93 | |||
94 | #include "log.h" |
||
95 | #include <epan/funnel.h> |
||
96 | |||
97 | #ifdef HAVE_PLUGINS |
||
98 | #include <wsutil/plugins.h> |
||
99 | #endif |
||
100 | |||
101 | static guint32 cum_bytes; |
||
102 | static const frame_data *ref; |
||
103 | static frame_data ref_frame; |
||
104 | static frame_data *prev_dis; |
||
105 | static frame_data prev_dis_frame; |
||
106 | static frame_data *prev_cap; |
||
107 | static frame_data prev_cap_frame; |
||
108 | |||
109 | static gboolean perform_two_pass_analysis; |
||
110 | |||
111 | /* |
||
112 | * The way the packet decode is to be written. |
||
113 | */ |
||
114 | typedef enum { |
||
115 | WRITE_TEXT, /* summary or detail text */ |
||
116 | WRITE_XML, /* PDML or PSML */ |
||
117 | WRITE_FIELDS /* User defined list of fields */ |
||
118 | /* Add CSV and the like here */ |
||
119 | } output_action_e; |
||
120 | |||
121 | static output_action_e output_action; |
||
122 | static gboolean do_dissection; /* TRUE if we have to dissect each packet */ |
||
123 | static gboolean print_packet_info; /* TRUE if we're to print packet information */ |
||
124 | static gint print_summary = -1; /* TRUE if we're to print packet summary information */ |
||
125 | static gboolean print_details; /* TRUE if we're to print packet details information */ |
||
126 | static gboolean print_hex; /* TRUE if we're to print hex/ascci information */ |
||
127 | static gboolean line_buffered; |
||
128 | static gboolean really_quiet = FALSE; |
||
129 | |||
130 | static print_format_e print_format = PR_FMT_TEXT; |
||
131 | static print_stream_t *print_stream; |
||
132 | |||
133 | static output_fields_t* output_fields = NULL; |
||
134 | |||
135 | /* The line separator used between packets, changeable via the -S option */ |
||
136 | static const char *separator = ""; |
||
137 | |||
138 | static int load_cap_file(capture_file *, int, gint64); |
||
139 | static gboolean process_packet(capture_file *cf, epan_dissect_t *edt, gint64 offset, |
||
140 | struct wtap_pkthdr *whdr, const guchar *pd, guint tap_flags); |
||
141 | static void show_print_file_io_error(int err); |
||
142 | static gboolean write_preamble(capture_file *cf); |
||
143 | static gboolean print_packet(capture_file *cf, epan_dissect_t *edt); |
||
144 | static gboolean write_finale(void); |
||
145 | static const char *cf_open_error_message(int err, gchar *err_info, |
||
146 | gboolean for_writing, int file_type); |
||
147 | |||
148 | static void open_failure_message(const char *filename, int err, |
||
149 | gboolean for_writing); |
||
150 | static void failure_message(const char *msg_format, va_list ap); |
||
151 | static void read_failure_message(const char *filename, int err); |
||
152 | static void write_failure_message(const char *filename, int err); |
||
153 | static void failure_message_cont(const char *msg_format, va_list ap); |
||
154 | |||
155 | capture_file cfile; |
||
156 | |||
157 | static GHashTable *output_only_tables = NULL; |
||
158 | |||
159 | #if 0 |
||
160 | struct string_elem { |
||
161 | const char *sstr; /* The short string */ |
||
162 | const char *lstr; /* The long string */ |
||
163 | }; |
||
164 | |||
165 | static gint |
||
166 | string_compare(gconstpointer a, gconstpointer b) |
||
167 | { |
||
168 | return strcmp(((const struct string_elem *)a)->sstr, |
||
169 | ((const struct string_elem *)b)->sstr); |
||
170 | } |
||
171 | |||
172 | static void |
||
173 | string_elem_print(gpointer data, gpointer not_used _U_) |
||
174 | { |
||
175 | fprintf(stderr, " %s - %s\n", |
||
176 | ((struct string_elem *)data)->sstr, |
||
177 | ((struct string_elem *)data)->lstr); |
||
178 | } |
||
179 | #endif |
||
180 | |||
181 | static void |
||
182 | print_usage(FILE *output) |
||
183 | { |
||
184 | fprintf(output, "\n"); |
||
185 | fprintf(output, "Usage: tfshark [options] ...\n"); |
||
186 | fprintf(output, "\n"); |
||
187 | |||
188 | /*fprintf(output, "\n");*/ |
||
189 | fprintf(output, "Input file:\n"); |
||
190 | fprintf(output, " -r <infile> set the filename to read from (no pipes or stdin!)\n"); |
||
191 | |||
192 | fprintf(output, "\n"); |
||
193 | fprintf(output, "Processing:\n"); |
||
194 | fprintf(output, " -2 perform a two-pass analysis\n"); |
||
195 | fprintf(output, " -R <read filter> packet Read filter in Wireshark display filter syntax\n"); |
||
196 | fprintf(output, " -Y <display filter> packet displaY filter in Wireshark display filter\n"); |
||
197 | fprintf(output, " syntax\n"); |
||
198 | fprintf(output, " -d %s ...\n", DECODE_AS_ARG_TEMPLATE); |
||
199 | fprintf(output, " \"Decode As\", see the man page for details\n"); |
||
200 | fprintf(output, " Example: tcp.port==8888,http\n"); |
||
201 | |||
202 | /*fprintf(output, "\n");*/ |
||
203 | fprintf(output, "Output:\n"); |
||
204 | fprintf(output, " -C <config profile> start with specified configuration profile\n"); |
||
205 | fprintf(output, " -V add output of packet tree (Packet Details)\n"); |
||
206 | fprintf(output, " -O <protocols> Only show packet details of these protocols, comma\n"); |
||
207 | fprintf(output, " separated\n"); |
||
208 | fprintf(output, " -S <separator> the line separator to print between packets\n"); |
||
209 | fprintf(output, " -x add output of hex and ASCII dump (Packet Bytes)\n"); |
||
210 | fprintf(output, " -T pdml|ps|psml|text|fields\n"); |
||
211 | fprintf(output, " format of text output (def: text)\n"); |
||
212 | fprintf(output, " -e <field> field to print if -Tfields selected (e.g. tcp.port,\n"); |
||
213 | fprintf(output, " _ws.col.Info)\n"); |
||
214 | fprintf(output, " this option can be repeated to print multiple fields\n"); |
||
215 | fprintf(output, " -E<fieldsoption>=<value> set options for output when -Tfields selected:\n"); |
||
216 | fprintf(output, " header=y|n switch headers on and off\n"); |
||
217 | fprintf(output, " separator=/t|/s|<char> select tab, space, printable character as separator\n"); |
||
218 | fprintf(output, " occurrence=f|l|a print first, last or all occurrences of each field\n"); |
||
219 | fprintf(output, " aggregator=,|/s|<char> select comma, space, printable character as\n"); |
||
220 | fprintf(output, " aggregator\n"); |
||
221 | fprintf(output, " quote=d|s|n select double, single, no quotes for values\n"); |
||
222 | fprintf(output, " -t a|ad|d|dd|e|r|u|ud output format of time stamps (def: r: rel. to first)\n"); |
||
223 | fprintf(output, " -u s|hms output format of seconds (def: s: seconds)\n"); |
||
224 | fprintf(output, " -l flush standard output after each packet\n"); |
||
225 | fprintf(output, " -q be more quiet on stdout (e.g. when using statistics)\n"); |
||
226 | fprintf(output, " -Q only log true errors to stderr (quieter than -q)\n"); |
||
227 | fprintf(output, " -X <key>:<value> eXtension options, see the man page for details\n"); |
||
228 | fprintf(output, " -z <statistics> various statistics, see the man page for details\n"); |
||
229 | |||
230 | fprintf(output, "\n"); |
||
231 | fprintf(output, "Miscellaneous:\n"); |
||
232 | fprintf(output, " -h display this help and exit\n"); |
||
233 | fprintf(output, " -v display version info and exit\n"); |
||
234 | fprintf(output, " -o <name>:<value> ... override preference setting\n"); |
||
235 | fprintf(output, " -K <keytab> keytab file to use for kerberos decryption\n"); |
||
236 | fprintf(output, " -G [report] dump one of several available reports and exit\n"); |
||
237 | fprintf(output, " default report=\"fields\"\n"); |
||
238 | fprintf(output, " use \"-G ?\" for more help\n"); |
||
239 | } |
||
240 | |||
241 | static void |
||
242 | glossary_option_help(void) |
||
243 | { |
||
244 | FILE *output; |
||
245 | |||
246 | output = stdout; |
||
247 | |||
248 | fprintf(output, "TFShark (Wireshark) %s\n", get_ws_vcs_version_info()); |
||
249 | |||
250 | fprintf(output, "\n"); |
||
251 | fprintf(output, "Usage: tfshark -G [report]\n"); |
||
252 | fprintf(output, "\n"); |
||
253 | fprintf(output, "Glossary table reports:\n"); |
||
254 | fprintf(output, " -G column-formats dump column format codes and exit\n"); |
||
255 | fprintf(output, " -G decodes dump \"layer type\"/\"decode as\" associations and exit\n"); |
||
256 | fprintf(output, " -G dissector-tables dump dissector table names, types, and properties\n"); |
||
257 | fprintf(output, " -G fields dump fields glossary and exit\n"); |
||
258 | fprintf(output, " -G ftypes dump field type basic and descriptive names\n"); |
||
259 | fprintf(output, " -G heuristic-decodes dump heuristic dissector tables\n"); |
||
260 | fprintf(output, " -G plugins dump installed plugins and exit\n"); |
||
261 | fprintf(output, " -G protocols dump protocols in registration database and exit\n"); |
||
262 | fprintf(output, " -G values dump value, range, true/false strings and exit\n"); |
||
263 | fprintf(output, "\n"); |
||
264 | fprintf(output, "Preference reports:\n"); |
||
265 | fprintf(output, " -G currentprefs dump current preferences and exit\n"); |
||
266 | fprintf(output, " -G defaultprefs dump default preferences and exit\n"); |
||
267 | fprintf(output, "\n"); |
||
268 | } |
||
269 | |||
270 | static void |
||
271 | tfshark_log_handler (const gchar *log_domain, GLogLevelFlags log_level, |
||
272 | const gchar *message, gpointer user_data) |
||
273 | { |
||
274 | /* ignore log message, if log_level isn't interesting based |
||
275 | upon the console log preferences. |
||
276 | If the preferences haven't been loaded loaded yet, display the |
||
277 | message anyway. |
||
278 | |||
279 | The default console_log_level preference value is such that only |
||
280 | ERROR, CRITICAL and WARNING level messages are processed; |
||
281 | MESSAGE, INFO and DEBUG level messages are ignored. |
||
282 | |||
283 | XXX: Aug 07, 2009: Prior tshark g_log code was hardwired to process only |
||
284 | ERROR and CRITICAL level messages so the current code is a behavioral |
||
285 | change. The current behavior is the same as in Wireshark. |
||
286 | */ |
||
287 | if ((log_level & G_LOG_LEVEL_MASK & prefs.console_log_level) == 0 && |
||
288 | prefs.console_log_level != 0) { |
||
289 | return; |
||
290 | } |
||
291 | |||
292 | g_log_default_handler(log_domain, log_level, message, user_data); |
||
293 | |||
294 | } |
||
295 | |||
296 | static void |
||
297 | print_current_user(void) { |
||
298 | gchar *cur_user, *cur_group; |
||
299 | |||
300 | if (started_with_special_privs()) { |
||
301 | cur_user = get_cur_username(); |
||
302 | cur_group = get_cur_groupname(); |
||
303 | fprintf(stderr, "Running as user \"%s\" and group \"%s\".", |
||
304 | cur_user, cur_group); |
||
305 | g_free(cur_user); |
||
306 | g_free(cur_group); |
||
307 | if (running_with_special_privs()) { |
||
308 | fprintf(stderr, " This could be dangerous."); |
||
309 | } |
||
310 | fprintf(stderr, "\n"); |
||
311 | } |
||
312 | } |
||
313 | |||
314 | static void |
||
315 | get_tfshark_runtime_version_info(GString *str) |
||
316 | { |
||
317 | /* stuff used by libwireshark */ |
||
318 | epan_get_runtime_version_info(str); |
||
319 | } |
||
320 | |||
321 | int |
||
322 | main(int argc, char *argv[]) |
||
323 | { |
||
324 | GString *comp_info_str; |
||
325 | GString *runtime_info_str; |
||
326 | char *init_progfile_dir_error; |
||
327 | int opt; |
||
328 | static const struct option long_options[] = { |
||
329 | {"help", no_argument, NULL, 'h'}, |
||
330 | {"version", no_argument, NULL, 'v'}, |
||
331 | {0, 0, 0, 0 } |
||
332 | }; |
||
333 | gboolean arg_error = FALSE; |
||
334 | |||
335 | char *gpf_path, *pf_path; |
||
336 | char *gdp_path, *dp_path; |
||
337 | int gpf_open_errno, gpf_read_errno; |
||
338 | int pf_open_errno, pf_read_errno; |
||
339 | int gdp_open_errno, gdp_read_errno; |
||
340 | int dp_open_errno, dp_read_errno; |
||
341 | int err; |
||
342 | volatile int exit_status = 0; |
||
343 | gboolean quiet = FALSE; |
||
344 | gchar *volatile cf_name = NULL; |
||
345 | gchar *rfilter = NULL; |
||
346 | gchar *dfilter = NULL; |
||
347 | dfilter_t *rfcode = NULL; |
||
348 | dfilter_t *dfcode = NULL; |
||
349 | gchar *err_msg; |
||
350 | e_prefs *prefs_p; |
||
351 | int log_flags; |
||
352 | gchar *output_only = NULL; |
||
353 | |||
354 | /* |
||
355 | * The leading + ensures that getopt_long() does not permute the argv[] |
||
356 | * entries. |
||
357 | * |
||
358 | * We have to make sure that the first getopt_long() preserves the content |
||
359 | * of argv[] for the subsequent getopt_long() call. |
||
360 | * |
||
361 | * We use getopt_long() in both cases to ensure that we're using a routine |
||
362 | * whose permutation behavior we can control in the same fashion on all |
||
363 | * platforms, and so that, if we ever need to process a long argument before |
||
364 | * doing further initialization, we can do so. |
||
365 | * |
||
366 | * Glibc and Solaris libc document that a leading + disables permutation |
||
367 | * of options, regardless of whether POSIXLY_CORRECT is set or not; *BSD |
||
368 | * and OS X don't document it, but do so anyway. |
||
369 | * |
||
370 | * We do *not* use a leading - because the behavior of a leading - is |
||
371 | * platform-dependent. |
||
372 | */ |
||
373 | #define OPTSTRING "+2C:d:e:E:hK:lo:O:qQr:R:S:t:T:u:vVxX:Y:z:" |
||
374 | |||
375 | static const char optstring[] = OPTSTRING; |
||
376 | |||
377 | /* Set the C-language locale to the native environment. */ |
||
378 | setlocale(LC_ALL, ""); |
||
379 | |||
380 | cmdarg_err_init(failure_message, failure_message_cont); |
||
381 | |||
382 | #ifdef _WIN32 |
||
383 | arg_list_utf_16to8(argc, argv); |
||
384 | create_app_running_mutex(); |
||
385 | #if !GLIB_CHECK_VERSION(2,31,0) |
||
386 | g_thread_init(NULL); |
||
387 | #endif |
||
388 | #endif /* _WIN32 */ |
||
389 | |||
390 | /* |
||
391 | * Get credential information for later use, and drop privileges |
||
392 | * before doing anything else. |
||
393 | * Let the user know if anything happened. |
||
394 | */ |
||
395 | init_process_policies(); |
||
396 | relinquish_special_privs_perm(); |
||
397 | print_current_user(); |
||
398 | |||
399 | /* |
||
400 | * Attempt to get the pathname of the executable file. |
||
401 | */ |
||
402 | init_progfile_dir_error = init_progfile_dir(argv[0], main); |
||
403 | if (init_progfile_dir_error != NULL) { |
||
404 | fprintf(stderr, "tfshark: Can't get pathname of tfshark program: %s.\n", |
||
405 | init_progfile_dir_error); |
||
406 | } |
||
407 | |||
408 | initialize_funnel_ops(); |
||
409 | |||
410 | /* Get the compile-time version information string */ |
||
411 | comp_info_str = get_compiled_version_info(NULL, epan_get_compiled_version_info); |
||
412 | |||
413 | /* Get the run-time version information string */ |
||
414 | runtime_info_str = get_runtime_version_info(get_tfshark_runtime_version_info); |
||
415 | |||
416 | /* Add it to the information to be reported on a crash. */ |
||
417 | ws_add_crash_info("TFShark (Wireshark) %s\n" |
||
418 | "\n" |
||
419 | "%s" |
||
420 | "\n" |
||
421 | "%s", |
||
422 | get_ws_vcs_version_info(), comp_info_str->str, runtime_info_str->str); |
||
423 | |||
424 | /* |
||
425 | * In order to have the -X opts assigned before the wslua machine starts |
||
426 | * we need to call getopts before epan_init() gets called. |
||
427 | * |
||
428 | * In order to handle, for example, -o options, we also need to call it |
||
429 | * *after* epan_init() gets called, so that the dissectors have had a |
||
430 | * chance to register their preferences. |
||
431 | * |
||
432 | * XXX - can we do this all with one getopt_long() call, saving the |
||
433 | * arguments we can't handle until after initializing libwireshark, |
||
434 | * and then process them after initializing libwireshark? |
||
435 | */ |
||
436 | opterr = 0; |
||
437 | |||
438 | while ((opt = getopt_long(argc, argv, optstring, long_options, NULL)) != -1) { |
||
439 | switch (opt) { |
||
440 | case 'C': /* Configuration Profile */ |
||
441 | if (profile_exists (optarg, FALSE)) { |
||
442 | set_profile_name (optarg); |
||
443 | } else { |
||
444 | cmdarg_err("Configuration Profile \"%s\" does not exist", optarg); |
||
445 | return 1; |
||
446 | } |
||
447 | break; |
||
448 | case 'O': /* Only output these protocols */ |
||
449 | output_only = g_strdup(optarg); |
||
450 | /* FALLTHROUGH */ |
||
451 | case 'V': /* Verbose */ |
||
452 | print_details = TRUE; |
||
453 | print_packet_info = TRUE; |
||
454 | break; |
||
455 | case 'x': /* Print packet data in hex (and ASCII) */ |
||
456 | print_hex = TRUE; |
||
457 | /* The user asked for hex output, so let's ensure they get it, |
||
458 | * even if they're writing to a file. |
||
459 | */ |
||
460 | print_packet_info = TRUE; |
||
461 | break; |
||
462 | case 'X': |
||
463 | ex_opt_add(optarg); |
||
464 | break; |
||
465 | default: |
||
466 | break; |
||
467 | } |
||
468 | } |
||
469 | |||
470 | /* |
||
471 | * Print packet summary information is the default, unless either -V or -x |
||
472 | * were specified. Note that this is new behavior, which |
||
473 | * allows for the possibility of printing only hex/ascii output without |
||
474 | * necessarily requiring that either the summary or details be printed too. |
||
475 | */ |
||
476 | if (print_summary == -1) |
||
477 | print_summary = (print_details || print_hex) ? FALSE : TRUE; |
||
478 | |||
479 | /** Send All g_log messages to our own handler **/ |
||
480 | |||
481 | log_flags = |
||
482 | G_LOG_LEVEL_ERROR| |
||
483 | G_LOG_LEVEL_CRITICAL| |
||
484 | G_LOG_LEVEL_WARNING| |
||
485 | G_LOG_LEVEL_MESSAGE| |
||
486 | G_LOG_LEVEL_INFO| |
||
487 | G_LOG_LEVEL_DEBUG| |
||
488 | G_LOG_FLAG_FATAL|G_LOG_FLAG_RECURSION; |
||
489 | |||
490 | g_log_set_handler(NULL, |
||
491 | (GLogLevelFlags)log_flags, |
||
492 | tfshark_log_handler, NULL /* user_data */); |
||
493 | g_log_set_handler(LOG_DOMAIN_MAIN, |
||
494 | (GLogLevelFlags)log_flags, |
||
495 | tfshark_log_handler, NULL /* user_data */); |
||
496 | |||
497 | init_report_err(failure_message, open_failure_message, read_failure_message, |
||
498 | write_failure_message); |
||
499 | |||
500 | timestamp_set_type(TS_RELATIVE); |
||
501 | timestamp_set_precision(TS_PREC_AUTO); |
||
502 | timestamp_set_seconds_type(TS_SECONDS_DEFAULT); |
||
503 | |||
504 | init_open_routines(); |
||
505 | |||
506 | #ifdef HAVE_PLUGINS |
||
507 | /* Register all the plugin types we have. */ |
||
508 | epan_register_plugin_types(); /* Types known to libwireshark */ |
||
509 | |||
510 | /* Scan for plugins. This does *not* call their registration routines; |
||
511 | that's done later. */ |
||
512 | scan_plugins(); |
||
513 | |||
514 | #endif |
||
515 | |||
516 | /* Register all dissectors; we must do this before checking for the |
||
517 | "-G" flag, as the "-G" flag dumps information registered by the |
||
518 | dissectors, and we must do it before we read the preferences, in |
||
519 | case any dissectors register preferences. */ |
||
520 | if (!epan_init(register_all_protocols, register_all_protocol_handoffs, NULL, |
||
521 | NULL)) |
||
522 | return 2; |
||
523 | |||
524 | /* Register all tap listeners; we do this before we parse the arguments, |
||
525 | as the "-z" argument can specify a registered tap. */ |
||
526 | |||
527 | /* we register the plugin taps before the other taps because |
||
528 | stats_tree taps plugins will be registered as tap listeners |
||
529 | by stats_tree_stat.c and need to registered before that */ |
||
530 | |||
531 | /* XXX Disable tap registration for now until we can get tfshark set up with |
||
532 | * its own set of taps and the necessary registration function etc. |
||
533 | #ifdef HAVE_PLUGINS |
||
534 | register_all_plugin_tap_listeners(); |
||
535 | #endif |
||
536 | register_all_tap_listeners(); |
||
537 | */ |
||
538 | |||
539 | /* If invoked with the "-G" flag, we dump out information based on |
||
540 | the argument to the "-G" flag; if no argument is specified, |
||
541 | for backwards compatibility we dump out a glossary of display |
||
542 | filter symbols. |
||
543 | |||
544 | XXX - we do this here, for now, to support "-G" with no arguments. |
||
545 | If none of our build or other processes uses "-G" with no arguments, |
||
546 | we can just process it with the other arguments. */ |
||
547 | if (argc >= 2 && strcmp(argv[1], "-G") == 0) { |
||
548 | proto_initialize_all_prefixes(); |
||
549 | |||
550 | if (argc == 2) |
||
551 | proto_registrar_dump_fields(); |
||
552 | else { |
||
553 | if (strcmp(argv[2], "column-formats") == 0) |
||
554 | column_dump_column_formats(); |
||
555 | else if (strcmp(argv[2], "currentprefs") == 0) { |
||
556 | read_prefs(&gpf_open_errno, &gpf_read_errno, &gpf_path, |
||
557 | &pf_open_errno, &pf_read_errno, &pf_path); |
||
558 | write_prefs(NULL); |
||
559 | } |
||
560 | else if (strcmp(argv[2], "decodes") == 0) |
||
561 | dissector_dump_decodes(); |
||
562 | else if (strcmp(argv[2], "defaultprefs") == 0) |
||
563 | write_prefs(NULL); |
||
564 | else if (strcmp(argv[2], "dissector-tables") == 0) |
||
565 | dissector_dump_dissector_tables(); |
||
566 | else if (strcmp(argv[2], "fields") == 0) |
||
567 | proto_registrar_dump_fields(); |
||
568 | else if (strcmp(argv[2], "ftypes") == 0) |
||
569 | proto_registrar_dump_ftypes(); |
||
570 | else if (strcmp(argv[2], "heuristic-decodes") == 0) |
||
571 | dissector_dump_heur_decodes(); |
||
572 | else if (strcmp(argv[2], "plugins") == 0) { |
||
573 | #ifdef HAVE_PLUGINS |
||
574 | plugins_dump_all(); |
||
575 | #endif |
||
576 | #ifdef HAVE_LUA |
||
577 | wslua_plugins_dump_all(); |
||
578 | #endif |
||
579 | } |
||
580 | else if (strcmp(argv[2], "protocols") == 0) |
||
581 | proto_registrar_dump_protocols(); |
||
582 | else if (strcmp(argv[2], "values") == 0) |
||
583 | proto_registrar_dump_values(); |
||
584 | else if (strcmp(argv[2], "?") == 0) |
||
585 | glossary_option_help(); |
||
586 | else if (strcmp(argv[2], "-?") == 0) |
||
587 | glossary_option_help(); |
||
588 | else { |
||
589 | cmdarg_err("Invalid \"%s\" option for -G flag, enter -G ? for more help.", argv[2]); |
||
590 | return 1; |
||
591 | } |
||
592 | } |
||
593 | return 0; |
||
594 | } |
||
595 | |||
596 | prefs_p = read_prefs(&gpf_open_errno, &gpf_read_errno, &gpf_path, |
||
597 | &pf_open_errno, &pf_read_errno, &pf_path); |
||
598 | if (gpf_path != NULL) { |
||
599 | if (gpf_open_errno != 0) { |
||
600 | cmdarg_err("Can't open global preferences file \"%s\": %s.", |
||
601 | pf_path, g_strerror(gpf_open_errno)); |
||
602 | } |
||
603 | if (gpf_read_errno != 0) { |
||
604 | cmdarg_err("I/O error reading global preferences file \"%s\": %s.", |
||
605 | pf_path, g_strerror(gpf_read_errno)); |
||
606 | } |
||
607 | } |
||
608 | if (pf_path != NULL) { |
||
609 | if (pf_open_errno != 0) { |
||
610 | cmdarg_err("Can't open your preferences file \"%s\": %s.", pf_path, |
||
611 | g_strerror(pf_open_errno)); |
||
612 | } |
||
613 | if (pf_read_errno != 0) { |
||
614 | cmdarg_err("I/O error reading your preferences file \"%s\": %s.", |
||
615 | pf_path, g_strerror(pf_read_errno)); |
||
616 | } |
||
617 | g_free(pf_path); |
||
618 | pf_path = NULL; |
||
619 | } |
||
620 | |||
621 | /* Read the disabled protocols file. */ |
||
622 | read_disabled_protos_list(&gdp_path, &gdp_open_errno, &gdp_read_errno, |
||
623 | &dp_path, &dp_open_errno, &dp_read_errno); |
||
624 | read_disabled_heur_dissector_list(&gdp_path, &gdp_open_errno, &gdp_read_errno, |
||
625 | &dp_path, &dp_open_errno, &dp_read_errno); |
||
626 | if (gdp_path != NULL) { |
||
627 | if (gdp_open_errno != 0) { |
||
628 | cmdarg_err("Could not open global disabled protocols file\n\"%s\": %s.", |
||
629 | gdp_path, g_strerror(gdp_open_errno)); |
||
630 | } |
||
631 | if (gdp_read_errno != 0) { |
||
632 | cmdarg_err("I/O error reading global disabled protocols file\n\"%s\": %s.", |
||
633 | gdp_path, g_strerror(gdp_read_errno)); |
||
634 | } |
||
635 | g_free(gdp_path); |
||
636 | } |
||
637 | if (dp_path != NULL) { |
||
638 | if (dp_open_errno != 0) { |
||
639 | cmdarg_err( |
||
640 | "Could not open your disabled protocols file\n\"%s\": %s.", dp_path, |
||
641 | g_strerror(dp_open_errno)); |
||
642 | } |
||
643 | if (dp_read_errno != 0) { |
||
644 | cmdarg_err( |
||
645 | "I/O error reading your disabled protocols file\n\"%s\": %s.", dp_path, |
||
646 | g_strerror(dp_read_errno)); |
||
647 | } |
||
648 | g_free(dp_path); |
||
649 | } |
||
650 | |||
651 | cap_file_init(&cfile); |
||
652 | |||
653 | /* Print format defaults to this. */ |
||
654 | print_format = PR_FMT_TEXT; |
||
655 | |||
656 | output_fields = output_fields_new(); |
||
657 | |||
658 | /* |
||
659 | * To reset the options parser, set optreset to 1 on platforms that |
||
660 | * have optreset (documented in *BSD and OS X, apparently present but |
||
661 | * not documented in Solaris - the Illumos repository seems to |
||
662 | * suggest that the first Solaris getopt_long(), at least as of 2004, |
||
663 | * was based on the NetBSD one, it had optreset) and set optind to 1, |
||
664 | * and set optind to 0 otherwise (documented as working in the GNU |
||
665 | * getopt_long(). Setting optind to 0 didn't originally work in the |
||
666 | * NetBSD one, but that was added later - we don't want to depend on |
||
667 | * it if we have optreset). |
||
668 | * |
||
669 | * Also reset opterr to 1, so that error messages are printed by |
||
670 | * getopt_long(). |
||
671 | */ |
||
672 | #ifdef HAVE_OPTRESET |
||
673 | optreset = 1; |
||
674 | optind = 1; |
||
675 | #else |
||
676 | optind = 0; |
||
677 | #endif |
||
678 | opterr = 1; |
||
679 | |||
680 | /* Now get our args */ |
||
681 | while ((opt = getopt_long(argc, argv, optstring, long_options, NULL)) != -1) { |
||
682 | switch (opt) { |
||
683 | case '2': /* Perform two pass analysis */ |
||
684 | perform_two_pass_analysis = TRUE; |
||
685 | break; |
||
686 | case 'C': |
||
687 | /* already processed; just ignore it now */ |
||
688 | break; |
||
689 | case 'd': /* Decode as rule */ |
||
690 | if (!decode_as_command_option(optarg)) |
||
691 | return 1; |
||
692 | break; |
||
693 | #if defined(HAVE_HEIMDAL_KERBEROS) || defined(HAVE_MIT_KERBEROS) |
||
694 | case 'K': /* Kerberos keytab file */ |
||
695 | read_keytab_file(optarg); |
||
696 | break; |
||
697 | #endif |
||
698 | case 'e': |
||
699 | /* Field entry */ |
||
700 | output_fields_add(output_fields, optarg); |
||
701 | break; |
||
702 | case 'E': |
||
703 | /* Field option */ |
||
704 | if (!output_fields_set_option(output_fields, optarg)) { |
||
705 | cmdarg_err("\"%s\" is not a valid field output option=value pair.", optarg); |
||
706 | output_fields_list_options(stderr); |
||
707 | return 1; |
||
708 | } |
||
709 | break; |
||
710 | |||
711 | case 'h': /* Print help and exit */ |
||
712 | printf("TFShark (Wireshark) %s\n" |
||
713 | "Dump and analyze network traffic.\n" |
||
714 | "See https://www.wireshark.org for more information.\n", |
||
715 | get_ws_vcs_version_info()); |
||
716 | print_usage(stdout); |
||
717 | return 0; |
||
718 | break; |
||
719 | case 'l': /* "Line-buffer" standard output */ |
||
720 | /* This isn't line-buffering, strictly speaking, it's just |
||
721 | flushing the standard output after the information for |
||
722 | each packet is printed; however, that should be good |
||
723 | enough for all the purposes to which "-l" is put (and |
||
724 | is probably actually better for "-V", as it does fewer |
||
725 | writes). |
||
726 | |||
727 | See the comment in "process_packet()" for an explanation of |
||
728 | why we do that, and why we don't just use "setvbuf()" to |
||
729 | make the standard output line-buffered (short version: in |
||
730 | Windows, "line-buffered" is the same as "fully-buffered", |
||
731 | and the output buffer is only flushed when it fills up). */ |
||
732 | line_buffered = TRUE; |
||
733 | break; |
||
734 | case 'o': /* Override preference from command line */ |
||
735 | switch (prefs_set_pref(optarg)) { |
||
736 | |||
737 | case PREFS_SET_OK: |
||
738 | break; |
||
739 | |||
740 | case PREFS_SET_SYNTAX_ERR: |
||
741 | cmdarg_err("Invalid -o flag \"%s\"", optarg); |
||
742 | return 1; |
||
743 | break; |
||
744 | |||
745 | case PREFS_SET_NO_SUCH_PREF: |
||
746 | case PREFS_SET_OBSOLETE: |
||
747 | cmdarg_err("-o flag \"%s\" specifies unknown preference", optarg); |
||
748 | return 1; |
||
749 | break; |
||
750 | } |
||
751 | break; |
||
752 | case 'q': /* Quiet */ |
||
753 | quiet = TRUE; |
||
754 | break; |
||
755 | case 'Q': /* Really quiet */ |
||
756 | quiet = TRUE; |
||
757 | really_quiet = TRUE; |
||
758 | break; |
||
759 | case 'r': /* Read capture file x */ |
||
760 | cf_name = g_strdup(optarg); |
||
761 | break; |
||
762 | case 'R': /* Read file filter */ |
||
763 | rfilter = optarg; |
||
764 | break; |
||
765 | case 'S': /* Set the line Separator to be printed between packets */ |
||
766 | separator = g_strdup(optarg); |
||
767 | break; |
||
768 | case 't': /* Time stamp type */ |
||
769 | if (strcmp(optarg, "r") == 0) |
||
770 | timestamp_set_type(TS_RELATIVE); |
||
771 | else if (strcmp(optarg, "a") == 0) |
||
772 | timestamp_set_type(TS_ABSOLUTE); |
||
773 | else if (strcmp(optarg, "ad") == 0) |
||
774 | timestamp_set_type(TS_ABSOLUTE_WITH_YMD); |
||
775 | else if (strcmp(optarg, "adoy") == 0) |
||
776 | timestamp_set_type(TS_ABSOLUTE_WITH_YDOY); |
||
777 | else if (strcmp(optarg, "d") == 0) |
||
778 | timestamp_set_type(TS_DELTA); |
||
779 | else if (strcmp(optarg, "dd") == 0) |
||
780 | timestamp_set_type(TS_DELTA_DIS); |
||
781 | else if (strcmp(optarg, "e") == 0) |
||
782 | timestamp_set_type(TS_EPOCH); |
||
783 | else if (strcmp(optarg, "u") == 0) |
||
784 | timestamp_set_type(TS_UTC); |
||
785 | else if (strcmp(optarg, "ud") == 0) |
||
786 | timestamp_set_type(TS_UTC_WITH_YMD); |
||
787 | else if (strcmp(optarg, "udoy") == 0) |
||
788 | timestamp_set_type(TS_UTC_WITH_YDOY); |
||
789 | else { |
||
790 | cmdarg_err("Invalid time stamp type \"%s\"; it must be one of:", optarg); |
||
791 | cmdarg_err_cont("\t\"a\" for absolute\n" |
||
792 | "\t\"ad\" for absolute with YYYY-MM-DD date\n" |
||
793 | "\t\"adoy\" for absolute with YYYY/DOY date\n" |
||
794 | "\t\"d\" for delta\n" |
||
795 | "\t\"dd\" for delta displayed\n" |
||
796 | "\t\"e\" for epoch\n" |
||
797 | "\t\"r\" for relative\n" |
||
798 | "\t\"u\" for absolute UTC\n" |
||
799 | "\t\"ud\" for absolute UTC with YYYY-MM-DD date\n" |
||
800 | "\t\"udoy\" for absolute UTC with YYYY/DOY date"); |
||
801 | return 1; |
||
802 | } |
||
803 | break; |
||
804 | case 'T': /* printing Type */ |
||
805 | if (strcmp(optarg, "text") == 0) { |
||
806 | output_action = WRITE_TEXT; |
||
807 | print_format = PR_FMT_TEXT; |
||
808 | } else if (strcmp(optarg, "ps") == 0) { |
||
809 | output_action = WRITE_TEXT; |
||
810 | print_format = PR_FMT_PS; |
||
811 | } else if (strcmp(optarg, "pdml") == 0) { |
||
812 | output_action = WRITE_XML; |
||
813 | print_details = TRUE; /* Need details */ |
||
814 | print_summary = FALSE; /* Don't allow summary */ |
||
815 | } else if (strcmp(optarg, "psml") == 0) { |
||
816 | output_action = WRITE_XML; |
||
817 | print_details = FALSE; /* Don't allow details */ |
||
818 | print_summary = TRUE; /* Need summary */ |
||
819 | } else if (strcmp(optarg, "fields") == 0) { |
||
820 | output_action = WRITE_FIELDS; |
||
821 | print_details = TRUE; /* Need full tree info */ |
||
822 | print_summary = FALSE; /* Don't allow summary */ |
||
823 | } else { |
||
824 | cmdarg_err("Invalid -T parameter \"%s\"; it must be one of:", optarg); /* x */ |
||
825 | cmdarg_err_cont("\t\"fields\" The values of fields specified with the -e option, in a form\n" |
||
826 | "\t specified by the -E option.\n" |
||
827 | "\t\"pdml\" Packet Details Markup Language, an XML-based format for the\n" |
||
828 | "\t details of a decoded packet. This information is equivalent to\n" |
||
829 | "\t the packet details printed with the -V flag.\n" |
||
830 | "\t\"ps\" PostScript for a human-readable one-line summary of each of\n" |
||
831 | "\t the packets, or a multi-line view of the details of each of\n" |
||
832 | "\t the packets, depending on whether the -V flag was specified.\n" |
||
833 | "\t\"psml\" Packet Summary Markup Language, an XML-based format for the\n" |
||
834 | "\t summary information of a decoded packet. This information is\n" |
||
835 | "\t equivalent to the information shown in the one-line summary\n" |
||
836 | "\t printed by default.\n" |
||
837 | "\t\"text\" Text of a human-readable one-line summary of each of the\n" |
||
838 | "\t packets, or a multi-line view of the details of each of the\n" |
||
839 | "\t packets, depending on whether the -V flag was specified.\n" |
||
840 | "\t This is the default."); |
||
841 | return 1; |
||
842 | } |
||
843 | break; |
||
844 | case 'u': /* Seconds type */ |
||
845 | if (strcmp(optarg, "s") == 0) |
||
846 | timestamp_set_seconds_type(TS_SECONDS_DEFAULT); |
||
847 | else if (strcmp(optarg, "hms") == 0) |
||
848 | timestamp_set_seconds_type(TS_SECONDS_HOUR_MIN_SEC); |
||
849 | else { |
||
850 | cmdarg_err("Invalid seconds type \"%s\"; it must be one of:", optarg); |
||
851 | cmdarg_err_cont("\t\"s\" for seconds\n" |
||
852 | "\t\"hms\" for hours, minutes and seconds"); |
||
853 | return 1; |
||
854 | } |
||
855 | break; |
||
856 | case 'v': /* Show version and exit */ |
||
857 | { |
||
858 | show_version("TFShark (Wireshark)", comp_info_str, runtime_info_str); |
||
859 | g_string_free(comp_info_str, TRUE); |
||
860 | g_string_free(runtime_info_str, TRUE); |
||
861 | /* We don't really have to cleanup here, but it's a convenient way to test |
||
862 | * start-up and shut-down of the epan library without any UI-specific |
||
863 | * cruft getting in the way. Makes the results of running |
||
864 | * $ ./tools/valgrind-wireshark -n |
||
865 | * much more useful. */ |
||
866 | epan_cleanup(); |
||
867 | #ifdef HAVE_EXTCAP |
||
868 | extcap_cleanup(); |
||
869 | #endif |
||
870 | return 0; |
||
871 | } |
||
872 | case 'O': /* Only output these protocols */ |
||
873 | /* already processed; just ignore it now */ |
||
874 | break; |
||
875 | case 'V': /* Verbose */ |
||
876 | /* already processed; just ignore it now */ |
||
877 | break; |
||
878 | case 'x': /* Print packet data in hex (and ASCII) */ |
||
879 | /* already processed; just ignore it now */ |
||
880 | break; |
||
881 | case 'X': |
||
882 | /* already processed; just ignore it now */ |
||
883 | break; |
||
884 | case 'Y': |
||
885 | dfilter = optarg; |
||
886 | break; |
||
887 | case 'z': |
||
888 | /* We won't call the init function for the stat this soon |
||
889 | as it would disallow MATE's fields (which are registered |
||
890 | by the preferences set callback) from being used as |
||
891 | part of a tap filter. Instead, we just add the argument |
||
892 | to a list of stat arguments. */ |
||
893 | if (strcmp("help", optarg) == 0) { |
||
894 | fprintf(stderr, "tfshark: The available statistics for the \"-z\" option are:\n"); |
||
895 | list_stat_cmd_args(); |
||
896 | return 0; |
||
897 | } |
||
898 | if (!process_stat_cmd_arg(optarg)) { |
||
899 | cmdarg_err("Invalid -z argument \"%s\"; it must be one of:", optarg); |
||
900 | list_stat_cmd_args(); |
||
901 | return 1; |
||
902 | } |
||
903 | break; |
||
904 | default: |
||
905 | case '?': /* Bad flag - print usage message */ |
||
906 | print_usage(stderr); |
||
907 | return 1; |
||
908 | break; |
||
909 | } |
||
910 | } |
||
911 | |||
912 | /* If we specified output fields, but not the output field type... */ |
||
913 | if (WRITE_FIELDS != output_action && 0 != output_fields_num_fields(output_fields)) { |
||
914 | cmdarg_err("Output fields were specified with \"-e\", " |
||
915 | "but \"-Tfields\" was not specified."); |
||
916 | return 1; |
||
917 | } else if (WRITE_FIELDS == output_action && 0 == output_fields_num_fields(output_fields)) { |
||
918 | cmdarg_err("\"-Tfields\" was specified, but no fields were " |
||
919 | "specified with \"-e\"."); |
||
920 | |||
921 | return 1; |
||
922 | } |
||
923 | |||
924 | /* If no capture filter or display filter has been specified, and there are |
||
925 | still command-line arguments, treat them as the tokens of a capture |
||
926 | filter (if no "-r" flag was specified) or a display filter (if a "-r" |
||
927 | flag was specified. */ |
||
928 | if (optind < argc) { |
||
929 | if (cf_name != NULL) { |
||
930 | if (dfilter != NULL) { |
||
931 | cmdarg_err("Display filters were specified both with \"-d\" " |
||
932 | "and with additional command-line arguments."); |
||
933 | return 1; |
||
934 | } |
||
935 | dfilter = get_args_as_string(argc, argv, optind); |
||
936 | } |
||
937 | } |
||
938 | |||
939 | /* if "-q" wasn't specified, we should print packet information */ |
||
940 | if (!quiet) |
||
941 | print_packet_info = TRUE; |
||
942 | |||
943 | if (arg_error) { |
||
944 | print_usage(stderr); |
||
945 | return 1; |
||
946 | } |
||
947 | |||
948 | if (print_hex) { |
||
949 | if (output_action != WRITE_TEXT) { |
||
950 | cmdarg_err("Raw packet hex data can only be printed as text or PostScript"); |
||
951 | return 1; |
||
952 | } |
||
953 | } |
||
954 | |||
955 | if (output_only != NULL) { |
||
956 | char *ps; |
||
957 | |||
958 | if (!print_details) { |
||
959 | cmdarg_err("-O requires -V"); |
||
960 | return 1; |
||
961 | } |
||
962 | |||
963 | output_only_tables = g_hash_table_new (g_str_hash, g_str_equal); |
||
964 | for (ps = strtok (output_only, ","); ps; ps = strtok (NULL, ",")) { |
||
965 | g_hash_table_insert(output_only_tables, (gpointer)ps, (gpointer)ps); |
||
966 | } |
||
967 | } |
||
968 | |||
969 | if (rfilter != NULL && !perform_two_pass_analysis) { |
||
970 | cmdarg_err("-R without -2 is deprecated. For single-pass filtering use -Y."); |
||
971 | return 1; |
||
972 | } |
||
973 | |||
974 | /* Notify all registered modules that have had any of their preferences |
||
975 | changed either from one of the preferences file or from the command |
||
976 | line that their preferences have changed. */ |
||
977 | prefs_apply_all(); |
||
978 | |||
979 | /* At this point MATE will have registered its field array so we can |
||
980 | have a tap filter with one of MATE's late-registered fields as part |
||
981 | of the filter. We can now process all the "-z" arguments. */ |
||
982 | start_requested_stats(); |
||
983 | |||
984 | /* disabled protocols as per configuration file */ |
||
985 | if (gdp_path == NULL && dp_path == NULL) { |
||
986 | set_disabled_protos_list(); |
||
987 | set_disabled_heur_dissector_list(); |
||
988 | } |
||
989 | |||
990 | /* Build the column format array */ |
||
991 | build_column_format_array(&cfile.cinfo, prefs_p->num_cols, TRUE); |
||
992 | |||
993 | if (rfilter != NULL) { |
||
994 | if (!dfilter_compile(rfilter, &rfcode, &err_msg)) { |
||
995 | cmdarg_err("%s", err_msg); |
||
996 | g_free(err_msg); |
||
997 | epan_cleanup(); |
||
998 | #ifdef HAVE_EXTCAP |
||
999 | extcap_cleanup(); |
||
1000 | #endif |
||
1001 | return 2; |
||
1002 | } |
||
1003 | } |
||
1004 | cfile.rfcode = rfcode; |
||
1005 | |||
1006 | if (dfilter != NULL) { |
||
1007 | if (!dfilter_compile(dfilter, &dfcode, &err_msg)) { |
||
1008 | cmdarg_err("%s", err_msg); |
||
1009 | g_free(err_msg); |
||
1010 | epan_cleanup(); |
||
1011 | #ifdef HAVE_EXTCAP |
||
1012 | extcap_cleanup(); |
||
1013 | #endif |
||
1014 | return 2; |
||
1015 | } |
||
1016 | } |
||
1017 | cfile.dfcode = dfcode; |
||
1018 | |||
1019 | if (print_packet_info) { |
||
1020 | /* If we're printing as text or PostScript, we have |
||
1021 | to create a print stream. */ |
||
1022 | if (output_action == WRITE_TEXT) { |
||
1023 | switch (print_format) { |
||
1024 | |||
1025 | case PR_FMT_TEXT: |
||
1026 | print_stream = print_stream_text_stdio_new(stdout); |
||
1027 | break; |
||
1028 | |||
1029 | case PR_FMT_PS: |
||
1030 | print_stream = print_stream_ps_stdio_new(stdout); |
||
1031 | break; |
||
1032 | |||
1033 | default: |
||
1034 | g_assert_not_reached(); |
||
1035 | } |
||
1036 | } |
||
1037 | } |
||
1038 | |||
1039 | /* We have to dissect each packet if: |
||
1040 | |||
1041 | we're printing information about each packet; |
||
1042 | |||
1043 | we're using a read filter on the packets; |
||
1044 | |||
1045 | we're using a display filter on the packets; |
||
1046 | |||
1047 | we're using any taps that need dissection. */ |
||
1048 | do_dissection = print_packet_info || rfcode || dfcode || tap_listeners_require_dissection(); |
||
1049 | |||
1050 | if (cf_name) { |
||
1051 | /* |
||
1052 | * We're reading a capture file. |
||
1053 | */ |
||
1054 | |||
1055 | /* TODO: if tfshark is ever changed to give the user a choice of which |
||
1056 | open_routine reader to use, then the following needs to change. */ |
||
1057 | if (cf_open(&cfile, cf_name, WTAP_TYPE_AUTO, FALSE, &err) != CF_OK) { |
||
1058 | epan_cleanup(); |
||
1059 | #ifdef HAVE_EXTCAP |
||
1060 | extcap_cleanup(); |
||
1061 | #endif |
||
1062 | return 2; |
||
1063 | } |
||
1064 | |||
1065 | /* Process the packets in the file */ |
||
1066 | TRY { |
||
1067 | /* XXX - for now there is only 1 packet */ |
||
1068 | err = load_cap_file(&cfile, 1, 0); |
||
1069 | } |
||
1070 | CATCH(OutOfMemoryError) { |
||
1071 | fprintf(stderr, |
||
1072 | "Out Of Memory!\n" |
||
1073 | "\n" |
||
1074 | "Sorry, but TFShark has to terminate now!\n" |
||
1075 | "\n" |
||
1076 | "Some infos / workarounds can be found at:\n" |
||
1077 | "https://wiki.wireshark.org/KnownBugs/OutOfMemory\n"); |
||
1078 | err = ENOMEM; |
||
1079 | } |
||
1080 | ENDTRY; |
||
1081 | |||
1082 | if (err != 0) { |
||
1083 | /* We still dump out the results of taps, etc., as we might have |
||
1084 | read some packets; however, we exit with an error status. */ |
||
1085 | exit_status = 2; |
||
1086 | } |
||
1087 | } |
||
1088 | |||
1089 | g_free(cf_name); |
||
1090 | |||
1091 | if (cfile.frames != NULL) { |
||
1092 | free_frame_data_sequence(cfile.frames); |
||
1093 | cfile.frames = NULL; |
||
1094 | } |
||
1095 | |||
1096 | draw_tap_listeners(TRUE); |
||
1097 | funnel_dump_all_text_windows(); |
||
1098 | epan_free(cfile.epan); |
||
1099 | epan_cleanup(); |
||
1100 | #ifdef HAVE_EXTCAP |
||
1101 | extcap_cleanup(); |
||
1102 | #endif |
||
1103 | |||
1104 | output_fields_free(output_fields); |
||
1105 | output_fields = NULL; |
||
1106 | |||
1107 | return exit_status; |
||
1108 | } |
||
1109 | |||
1110 | static const nstime_t * |
||
1111 | tfshark_get_frame_ts(void *data, guint32 frame_num) |
||
1112 | { |
||
1113 | capture_file *cf = (capture_file *) data; |
||
1114 | |||
1115 | if (ref && ref->num == frame_num) |
||
1116 | return &ref->abs_ts; |
||
1117 | |||
1118 | if (prev_dis && prev_dis->num == frame_num) |
||
1119 | return &prev_dis->abs_ts; |
||
1120 | |||
1121 | if (prev_cap && prev_cap->num == frame_num) |
||
1122 | return &prev_cap->abs_ts; |
||
1123 | |||
1124 | if (cf->frames) { |
||
1125 | frame_data *fd = frame_data_sequence_find(cf->frames, frame_num); |
||
1126 | |||
1127 | return (fd) ? &fd->abs_ts : NULL; |
||
1128 | } |
||
1129 | |||
1130 | return NULL; |
||
1131 | } |
||
1132 | |||
1133 | static const char * |
||
1134 | no_interface_name(void *data _U_, guint32 interface_id _U_) |
||
1135 | { |
||
1136 | return ""; |
||
1137 | } |
||
1138 | |||
1139 | static epan_t * |
||
1140 | tfshark_epan_new(capture_file *cf) |
||
1141 | { |
||
1142 | epan_t *epan = epan_new(); |
||
1143 | |||
1144 | epan->data = cf; |
||
1145 | epan->get_frame_ts = tfshark_get_frame_ts; |
||
1146 | epan->get_interface_name = no_interface_name; |
||
1147 | epan->get_user_comment = NULL; |
||
1148 | |||
1149 | return epan; |
||
1150 | } |
||
1151 | |||
1152 | static gboolean |
||
1153 | process_packet_first_pass(capture_file *cf, epan_dissect_t *edt, |
||
1154 | gint64 offset, struct wtap_pkthdr *whdr, |
||
1155 | const guchar *pd) |
||
1156 | { |
||
1157 | frame_data fdlocal; |
||
1158 | guint32 framenum; |
||
1159 | gboolean passed; |
||
1160 | |||
1161 | /* The frame number of this packet is one more than the count of |
||
1162 | frames in this packet. */ |
||
1163 | framenum = cf->count + 1; |
||
1164 | |||
1165 | /* If we're not running a display filter and we're not printing any |
||
1166 | packet information, we don't need to do a dissection. This means |
||
1167 | that all packets can be marked as 'passed'. */ |
||
1168 | passed = TRUE; |
||
1169 | |||
1170 | frame_data_init(&fdlocal, framenum, whdr, offset, cum_bytes); |
||
1171 | |||
1172 | /* If we're going to print packet information, or we're going to |
||
1173 | run a read filter, or display filter, or we're going to process taps, set up to |
||
1174 | do a dissection and do so. */ |
||
1175 | if (edt) { |
||
1176 | /* If we're running a read filter, prime the epan_dissect_t with that |
||
1177 | filter. */ |
||
1178 | if (cf->rfcode) |
||
1179 | epan_dissect_prime_dfilter(edt, cf->rfcode); |
||
1180 | |||
1181 | frame_data_set_before_dissect(&fdlocal, &cf->elapsed_time, |
||
1182 | &ref, prev_dis); |
||
1183 | if (ref == &fdlocal) { |
||
1184 | ref_frame = fdlocal; |
||
1185 | ref = &ref_frame; |
||
1186 | } |
||
1187 | |||
1188 | epan_dissect_file_run(edt, whdr, file_tvbuff_new(&fdlocal, pd), &fdlocal, NULL); |
||
1189 | |||
1190 | /* Run the read filter if we have one. */ |
||
1191 | if (cf->rfcode) |
||
1192 | passed = dfilter_apply_edt(cf->rfcode, edt); |
||
1193 | } |
||
1194 | |||
1195 | if (passed) { |
||
1196 | frame_data_set_after_dissect(&fdlocal, &cum_bytes); |
||
1197 | prev_cap = prev_dis = frame_data_sequence_add(cf->frames, &fdlocal); |
||
1198 | |||
1199 | /* If we're not doing dissection then there won't be any dependent frames. |
||
1200 | * More importantly, edt.pi.dependent_frames won't be initialized because |
||
1201 | * epan hasn't been initialized. |
||
1202 | */ |
||
1203 | if (edt) { |
||
1204 | g_slist_foreach(edt->pi.dependent_frames, find_and_mark_frame_depended_upon, cf->frames); |
||
1205 | } |
||
1206 | |||
1207 | cf->count++; |
||
1208 | } else { |
||
1209 | /* if we don't add it to the frame_data_sequence, clean it up right now |
||
1210 | * to avoid leaks */ |
||
1211 | frame_data_destroy(&fdlocal); |
||
1212 | } |
||
1213 | |||
1214 | if (edt) |
||
1215 | epan_dissect_reset(edt); |
||
1216 | |||
1217 | return passed; |
||
1218 | } |
||
1219 | |||
1220 | static gboolean |
||
1221 | process_packet_second_pass(capture_file *cf, epan_dissect_t *edt, frame_data *fdata, |
||
1222 | struct wtap_pkthdr *phdr, Buffer *buf, |
||
1223 | guint tap_flags) |
||
1224 | { |
||
1225 | column_info *cinfo; |
||
1226 | gboolean passed; |
||
1227 | |||
1228 | /* If we're not running a display filter and we're not printing any |
||
1229 | packet information, we don't need to do a dissection. This means |
||
1230 | that all packets can be marked as 'passed'. */ |
||
1231 | passed = TRUE; |
||
1232 | |||
1233 | /* If we're going to print packet information, or we're going to |
||
1234 | run a read filter, or we're going to process taps, set up to |
||
1235 | do a dissection and do so. */ |
||
1236 | if (edt) { |
||
1237 | |||
1238 | /* If we're running a display filter, prime the epan_dissect_t with that |
||
1239 | filter. */ |
||
1240 | if (cf->dfcode) |
||
1241 | epan_dissect_prime_dfilter(edt, cf->dfcode); |
||
1242 | |||
1243 | col_custom_prime_edt(edt, &cf->cinfo); |
||
1244 | |||
1245 | /* We only need the columns if either |
||
1246 | 1) some tap needs the columns |
||
1247 | or |
||
1248 | 2) we're printing packet info but we're *not* verbose; in verbose |
||
1249 | mode, we print the protocol tree, not the protocol summary. |
||
1250 | */ |
||
1251 | if ((tap_flags & TL_REQUIRES_COLUMNS) || (print_packet_info && print_summary)) |
||
1252 | cinfo = &cf->cinfo; |
||
1253 | else |
||
1254 | cinfo = NULL; |
||
1255 | |||
1256 | frame_data_set_before_dissect(fdata, &cf->elapsed_time, |
||
1257 | &ref, prev_dis); |
||
1258 | if (ref == fdata) { |
||
1259 | ref_frame = *fdata; |
||
1260 | ref = &ref_frame; |
||
1261 | } |
||
1262 | |||
1263 | epan_dissect_file_run_with_taps(edt, phdr, file_tvbuff_new_buffer(fdata, buf), fdata, cinfo); |
||
1264 | |||
1265 | /* Run the read/display filter if we have one. */ |
||
1266 | if (cf->dfcode) |
||
1267 | passed = dfilter_apply_edt(cf->dfcode, edt); |
||
1268 | } |
||
1269 | |||
1270 | if (passed) { |
||
1271 | frame_data_set_after_dissect(fdata, &cum_bytes); |
||
1272 | /* Process this packet. */ |
||
1273 | if (print_packet_info) { |
||
1274 | /* We're printing packet information; print the information for |
||
1275 | this packet. */ |
||
1276 | print_packet(cf, edt); |
||
1277 | |||
1278 | /* The ANSI C standard does not appear to *require* that a line-buffered |
||
1279 | stream be flushed to the host environment whenever a newline is |
||
1280 | written, it just says that, on such a stream, characters "are |
||
1281 | intended to be transmitted to or from the host environment as a |
||
1282 | block when a new-line character is encountered". |
||
1283 | |||
1284 | The Visual C++ 6.0 C implementation doesn't do what is intended; |
||
1285 | even if you set a stream to be line-buffered, it still doesn't |
||
1286 | flush the buffer at the end of every line. |
||
1287 | |||
1288 | So, if the "-l" flag was specified, we flush the standard output |
||
1289 | at the end of a packet. This will do the right thing if we're |
||
1290 | printing packet summary lines, and, as we print the entire protocol |
||
1291 | tree for a single packet without waiting for anything to happen, |
||
1292 | it should be as good as line-buffered mode if we're printing |
||
1293 | protocol trees. (The whole reason for the "-l" flag in either |
||
1294 | tcpdump or TShark is to allow the output of a live capture to |
||
1295 | be piped to a program or script and to have that script see the |
||
1296 | information for the packet as soon as it's printed, rather than |
||
1297 | having to wait until a standard I/O buffer fills up. */ |
||
1298 | if (line_buffered) |
||
1299 | fflush(stdout); |
||
1300 | |||
1301 | if (ferror(stdout)) { |
||
1302 | show_print_file_io_error(errno); |
||
1303 | exit(2); |
||
1304 | } |
||
1305 | } |
||
1306 | prev_dis = fdata; |
||
1307 | } |
||
1308 | prev_cap = fdata; |
||
1309 | |||
1310 | if (edt) { |
||
1311 | epan_dissect_reset(edt); |
||
1312 | } |
||
1313 | return passed || fdata->flags.dependent_of_displayed; |
||
1314 | } |
||
1315 | |||
1316 | static gboolean |
||
1317 | local_wtap_read(capture_file *cf, struct wtap_pkthdr* file_phdr _U_, int *err, gchar **err_info _U_, gint64 *data_offset _U_, guint8** data_buffer) |
||
1318 | { |
||
1319 | /* int bytes_read; */ |
||
1320 | gint64 packet_size = wtap_file_size(cf->wth, err); |
||
1321 | |||
1322 | *data_buffer = (guint8*)g_malloc((gsize)packet_size); |
||
1323 | /* bytes_read =*/ file_read(*data_buffer, (unsigned int)packet_size, cf->wth->fh); |
||
1324 | |||
1325 | #if 0 /* no more filetap */ |
||
1326 | if (bytes_read < 0) { |
||
1327 | *err = file_error(cf->wth->fh, err_info); |
||
1328 | if (*err == 0) |
||
1329 | *err = FTAP_ERR_SHORT_READ; |
||
1330 | return FALSE; |
||
1331 | } else if (bytes_read == 0) { |
||
1332 | /* Done with file, no error */ |
||
1333 | return FALSE; |
||
1334 | } |
||
1335 | |||
1336 | |||
1337 | /* XXX - SET FRAME SIZE EQUAL TO TOTAL FILE SIZE */ |
||
1338 | file_phdr->caplen = (guint32)packet_size; |
||
1339 | file_phdr->len = (guint32)packet_size; |
||
1340 | |||
1341 | /* |
||
1342 | * Set the packet encapsulation to the file's encapsulation |
||
1343 | * value; if that's not WTAP_ENCAP_PER_PACKET, it's the |
||
1344 | * right answer (and means that the read routine for this |
||
1345 | * capture file type doesn't have to set it), and if it |
||
1346 | * *is* WTAP_ENCAP_PER_PACKET, the caller needs to set it |
||
1347 | * anyway. |
||
1348 | */ |
||
1349 | wth->phdr.pkt_encap = wth->file_encap; |
||
1350 | |||
1351 | if (!wth->subtype_read(wth, err, err_info, data_offset)) { |
||
1352 | /* |
||
1353 | * If we didn't get an error indication, we read |
||
1354 | * the last packet. See if there's any deferred |
||
1355 | * error, as might, for example, occur if we're |
||
1356 | * reading a compressed file, and we got an error |
||
1357 | * reading compressed data from the file, but |
||
1358 | * got enough compressed data to decompress the |
||
1359 | * last packet of the file. |
||
1360 | */ |
||
1361 | if (*err == 0) |
||
1362 | *err = file_error(wth->fh, err_info); |
||
1363 | return FALSE; /* failure */ |
||
1364 | } |
||
1365 | |||
1366 | /* |
||
1367 | * It makes no sense for the captured data length to be bigger |
||
1368 | * than the actual data length. |
||
1369 | */ |
||
1370 | if (wth->phdr.caplen > wth->phdr.len) |
||
1371 | wth->phdr.caplen = wth->phdr.len; |
||
1372 | |||
1373 | /* |
||
1374 | * Make sure that it's not WTAP_ENCAP_PER_PACKET, as that |
||
1375 | * probably means the file has that encapsulation type |
||
1376 | * but the read routine didn't set this packet's |
||
1377 | * encapsulation type. |
||
1378 | */ |
||
1379 | g_assert(wth->phdr.pkt_encap != WTAP_ENCAP_PER_PACKET); |
||
1380 | #endif |
||
1381 | |||
1382 | return TRUE; /* success */ |
||
1383 | } |
||
1384 | |||
1385 | static int |
||
1386 | load_cap_file(capture_file *cf, int max_packet_count, gint64 max_byte_count) |
||
1387 | { |
||
1388 | guint32 framenum; |
||
1389 | int err; |
||
1390 | gchar *err_info = NULL; |
||
1391 | gint64 data_offset = 0; |
||
1392 | gboolean filtering_tap_listeners; |
||
1393 | guint tap_flags; |
||
1394 | Buffer buf; |
||
1395 | epan_dissect_t *edt = NULL; |
||
1396 | struct wtap_pkthdr file_phdr; |
||
1397 | guint8* raw_data; |
||
1398 | |||
1399 | if (print_packet_info) { |
||
1400 | if (!write_preamble(cf)) { |
||
1401 | err = errno; |
||
1402 | show_print_file_io_error(err); |
||
1403 | goto out; |
||
1404 | } |
||
1405 | } |
||
1406 | |||
1407 | /* Do we have any tap listeners with filters? */ |
||
1408 | filtering_tap_listeners = have_filtering_tap_listeners(); |
||
1409 | |||
1410 | /* Get the union of the flags for all tap listeners. */ |
||
1411 | tap_flags = union_of_tap_listener_flags(); |
||
1412 | |||
1413 | wtap_phdr_init(&file_phdr); |
||
1414 | |||
1415 | /* XXX - TEMPORARY HACK TO ELF DISSECTOR */ |
||
1416 | file_phdr.pkt_encap = 1234; |
||
1417 | |||
1418 | if (perform_two_pass_analysis) { |
||
1419 | frame_data *fdata; |
||
1420 | |||
1421 | /* Allocate a frame_data_sequence for all the frames. */ |
||
1422 | cf->frames = new_frame_data_sequence(); |
||
1423 | |||
1424 | if (do_dissection) { |
||
1425 | gboolean create_proto_tree = FALSE; |
||
1426 | |||
1427 | /* If we're going to be applying a filter, we'll need to |
||
1428 | create a protocol tree against which to apply the filter. */ |
||
1429 | if (cf->rfcode) |
||
1430 | create_proto_tree = TRUE; |
||
1431 | |||
1432 | /* We're not going to display the protocol tree on this pass, |
||
1433 | so it's not going to be "visible". */ |
||
1434 | edt = epan_dissect_new(cf->epan, create_proto_tree, FALSE); |
||
1435 | } |
||
1436 | while (local_wtap_read(cf, &file_phdr, &err, &err_info, &data_offset, &raw_data)) { |
||
1437 | if (process_packet_first_pass(cf, edt, data_offset, &file_phdr/*wtap_phdr(cf->wth)*/, |
||
1438 | wtap_buf_ptr(cf->wth))) { |
||
1439 | |||
1440 | /* Stop reading if we have the maximum number of packets; |
||
1441 | * When the -c option has not been used, max_packet_count |
||
1442 | * starts at 0, which practically means, never stop reading. |
||
1443 | * (unless we roll over max_packet_count ?) |
||
1444 | */ |
||
1445 | if ( (--max_packet_count == 0) || (max_byte_count != 0 && data_offset >= max_byte_count)) { |
||
1446 | err = 0; /* This is not an error */ |
||
1447 | break; |
||
1448 | } |
||
1449 | } |
||
1450 | } |
||
1451 | |||
1452 | if (edt) { |
||
1453 | epan_dissect_free(edt); |
||
1454 | edt = NULL; |
||
1455 | } |
||
1456 | |||
1457 | #if 0 |
||
1458 | /* Close the sequential I/O side, to free up memory it requires. */ |
||
1459 | wtap_sequential_close(cf->wth); |
||
1460 | #endif |
||
1461 | |||
1462 | /* Allow the protocol dissectors to free up memory that they |
||
1463 | * don't need after the sequential run-through of the packets. */ |
||
1464 | postseq_cleanup_all_protocols(); |
||
1465 | |||
1466 | prev_dis = NULL; |
||
1467 | prev_cap = NULL; |
||
1468 | ws_buffer_init(&buf, 1500); |
||
1469 | |||
1470 | if (do_dissection) { |
||
1471 | gboolean create_proto_tree; |
||
1472 | |||
1473 | if (cf->dfcode || print_details || filtering_tap_listeners || |
||
1474 | (tap_flags & TL_REQUIRES_PROTO_TREE) || have_custom_cols(&cf->cinfo)) |
||
1475 | create_proto_tree = TRUE; |
||
1476 | else |
||
1477 | create_proto_tree = FALSE; |
||
1478 | |||
1479 | /* The protocol tree will be "visible", i.e., printed, only if we're |
||
1480 | printing packet details, which is true if we're printing stuff |
||
1481 | ("print_packet_info" is true) and we're in verbose mode |
||
1482 | ("packet_details" is true). */ |
||
1483 | edt = epan_dissect_new(cf->epan, create_proto_tree, print_packet_info && print_details); |
||
1484 | } |
||
1485 | |||
1486 | for (framenum = 1; err == 0 && framenum <= cf->count; framenum++) { |
||
1487 | fdata = frame_data_sequence_find(cf->frames, framenum); |
||
1488 | #if 0 |
||
1489 | if (wtap_seek_read(cf->wth, fdata->file_off, |
||
1490 | &buf, fdata->cap_len, &err, &err_info)) { |
||
1491 | process_packet_second_pass(cf, edt, fdata, &cf->phdr, &buf, tap_flags); |
||
1492 | } |
||
1493 | #else |
||
1494 | process_packet_second_pass(cf, edt, fdata, &cf->phdr, &buf, tap_flags); |
||
1495 | #endif |
||
1496 | } |
||
1497 | |||
1498 | if (edt) { |
||
1499 | epan_dissect_free(edt); |
||
1500 | edt = NULL; |
||
1501 | } |
||
1502 | |||
1503 | ws_buffer_free(&buf); |
||
1504 | } |
||
1505 | else { |
||
1506 | framenum = 0; |
||
1507 | |||
1508 | if (do_dissection) { |
||
1509 | gboolean create_proto_tree; |
||
1510 | |||
1511 | if (cf->rfcode || cf->dfcode || print_details || filtering_tap_listeners || |
||
1512 | (tap_flags & TL_REQUIRES_PROTO_TREE) || have_custom_cols(&cf->cinfo)) |
||
1513 | create_proto_tree = TRUE; |
||
1514 | else |
||
1515 | create_proto_tree = FALSE; |
||
1516 | |||
1517 | /* The protocol tree will be "visible", i.e., printed, only if we're |
||
1518 | printing packet details, which is true if we're printing stuff |
||
1519 | ("print_packet_info" is true) and we're in verbose mode |
||
1520 | ("packet_details" is true). */ |
||
1521 | edt = epan_dissect_new(cf->epan, create_proto_tree, print_packet_info && print_details); |
||
1522 | } |
||
1523 | |||
1524 | while (local_wtap_read(cf, &file_phdr, &err, &err_info, &data_offset, &raw_data)) { |
||
1525 | |||
1526 | framenum++; |
||
1527 | |||
1528 | process_packet(cf, edt, data_offset, &file_phdr/*wtap_phdr(cf->wth)*/, |
||
1529 | raw_data, tap_flags); |
||
1530 | |||
1531 | /* Stop reading if we have the maximum number of packets; |
||
1532 | * When the -c option has not been used, max_packet_count |
||
1533 | * starts at 0, which practically means, never stop reading. |
||
1534 | * (unless we roll over max_packet_count ?) |
||
1535 | */ |
||
1536 | if ( (--max_packet_count == 0) || (max_byte_count != 0 && data_offset >= max_byte_count)) { |
||
1537 | err = 0; /* This is not an error */ |
||
1538 | break; |
||
1539 | } |
||
1540 | } |
||
1541 | |||
1542 | if (edt) { |
||
1543 | epan_dissect_free(edt); |
||
1544 | edt = NULL; |
||
1545 | } |
||
1546 | } |
||
1547 | |||
1548 | wtap_phdr_cleanup(&file_phdr); |
||
1549 | |||
1550 | if (err != 0) { |
||
1551 | /* |
||
1552 | * Print a message noting that the read failed somewhere along the line. |
||
1553 | * |
||
1554 | * If we're printing packet data, and the standard output and error are |
||
1555 | * going to the same place, flush the standard output, so everything |
||
1556 | * buffered up is written, and then print a newline to the standard error |
||
1557 | * before printing the error message, to separate it from the packet |
||
1558 | * data. (Alas, that only works on UN*X; st_dev is meaningless, and |
||
1559 | * the _fstat() documentation at Microsoft doesn't indicate whether |
||
1560 | * st_ino is even supported.) |
||
1561 | */ |
||
1562 | #ifndef _WIN32 |
||
1563 | if (print_packet_info) { |
||
1564 | ws_statb64 stat_stdout, stat_stderr; |
||
1565 | |||
1566 | if (ws_fstat64(1, &stat_stdout) == 0 && ws_fstat64(2, &stat_stderr) == 0) { |
||
1567 | if (stat_stdout.st_dev == stat_stderr.st_dev && |
||
1568 | stat_stdout.st_ino == stat_stderr.st_ino) { |
||
1569 | fflush(stdout); |
||
1570 | fprintf(stderr, "\n"); |
||
1571 | } |
||
1572 | } |
||
1573 | } |
||
1574 | #endif |
||
1575 | #if 0 |
||
1576 | switch (err) { |
||
1577 | |||
1578 | case FTAP_ERR_UNSUPPORTED: |
||
1579 | cmdarg_err("The file \"%s\" contains record data that TFShark doesn't support.\n(%s)", |
||
1580 | cf->filename, err_info); |
||
1581 | g_free(err_info); |
||
1582 | break; |
||
1583 | |||
1584 | case FTAP_ERR_UNSUPPORTED_ENCAP: |
||
1585 | cmdarg_err("The file \"%s\" has a packet with a network type that TFShark doesn't support.\n(%s)", |
||
1586 | cf->filename, err_info); |
||
1587 | g_free(err_info); |
||
1588 | break; |
||
1589 | |||
1590 | case FTAP_ERR_CANT_READ: |
||
1591 | cmdarg_err("An attempt to read from the file \"%s\" failed for some unknown reason.", |
||
1592 | cf->filename); |
||
1593 | break; |
||
1594 | |||
1595 | case FTAP_ERR_SHORT_READ: |
||
1596 | cmdarg_err("The file \"%s\" appears to have been cut short in the middle of a packet.", |
||
1597 | cf->filename); |
||
1598 | break; |
||
1599 | |||
1600 | case FTAP_ERR_BAD_FILE: |
||
1601 | cmdarg_err("The file \"%s\" appears to be damaged or corrupt.\n(%s)", |
||
1602 | cf->filename, err_info); |
||
1603 | g_free(err_info); |
||
1604 | break; |
||
1605 | |||
1606 | case FTAP_ERR_DECOMPRESS: |
||
1607 | cmdarg_err("The compressed file \"%s\" appears to be damaged or corrupt.\n" |
||
1608 | "(%s)", cf->filename, err_info); |
||
1609 | break; |
||
1610 | |||
1611 | default: |
||
1612 | cmdarg_err("An error occurred while reading the file \"%s\": %s.", |
||
1613 | cf->filename, ftap_strerror(err)); |
||
1614 | break; |
||
1615 | } |
||
1616 | #endif |
||
1617 | } else { |
||
1618 | if (print_packet_info) { |
||
1619 | if (!write_finale()) { |
||
1620 | err = errno; |
||
1621 | show_print_file_io_error(err); |
||
1622 | } |
||
1623 | } |
||
1624 | } |
||
1625 | |||
1626 | out: |
||
1627 | wtap_close(cf->wth); |
||
1628 | cf->wth = NULL; |
||
1629 | |||
1630 | return err; |
||
1631 | } |
||
1632 | |||
1633 | static gboolean |
||
1634 | process_packet(capture_file *cf, epan_dissect_t *edt, gint64 offset, |
||
1635 | struct wtap_pkthdr *whdr, const guchar *pd, guint tap_flags) |
||
1636 | { |
||
1637 | frame_data fdata; |
||
1638 | column_info *cinfo; |
||
1639 | gboolean passed; |
||
1640 | |||
1641 | /* Count this packet. */ |
||
1642 | cf->count++; |
||
1643 | |||
1644 | /* If we're not running a display filter and we're not printing any |
||
1645 | packet information, we don't need to do a dissection. This means |
||
1646 | that all packets can be marked as 'passed'. */ |
||
1647 | passed = TRUE; |
||
1648 | |||
1649 | frame_data_init(&fdata, cf->count, whdr, offset, cum_bytes); |
||
1650 | |||
1651 | /* If we're going to print packet information, or we're going to |
||
1652 | run a read filter, or we're going to process taps, set up to |
||
1653 | do a dissection and do so. */ |
||
1654 | if (edt) { |
||
1655 | /* If we're running a filter, prime the epan_dissect_t with that |
||
1656 | filter. */ |
||
1657 | if (cf->dfcode) |
||
1658 | epan_dissect_prime_dfilter(edt, cf->dfcode); |
||
1659 | |||
1660 | col_custom_prime_edt(edt, &cf->cinfo); |
||
1661 | |||
1662 | /* We only need the columns if either |
||
1663 | 1) some tap needs the columns |
||
1664 | or |
||
1665 | 2) we're printing packet info but we're *not* verbose; in verbose |
||
1666 | mode, we print the protocol tree, not the protocol summary. |
||
1667 | or |
||
1668 | 3) there is a column mapped as an individual field */ |
||
1669 | if ((tap_flags & TL_REQUIRES_COLUMNS) || (print_packet_info && print_summary) || output_fields_has_cols(output_fields)) |
||
1670 | cinfo = &cf->cinfo; |
||
1671 | else |
||
1672 | cinfo = NULL; |
||
1673 | |||
1674 | frame_data_set_before_dissect(&fdata, &cf->elapsed_time, |
||
1675 | &ref, prev_dis); |
||
1676 | if (ref == &fdata) { |
||
1677 | ref_frame = fdata; |
||
1678 | ref = &ref_frame; |
||
1679 | } |
||
1680 | |||
1681 | epan_dissect_file_run_with_taps(edt, whdr, frame_tvbuff_new(&fdata, pd), &fdata, cinfo); |
||
1682 | |||
1683 | /* Run the filter if we have it. */ |
||
1684 | if (cf->dfcode) |
||
1685 | passed = dfilter_apply_edt(cf->dfcode, edt); |
||
1686 | } |
||
1687 | |||
1688 | if (passed) { |
||
1689 | frame_data_set_after_dissect(&fdata, &cum_bytes); |
||
1690 | |||
1691 | /* Process this packet. */ |
||
1692 | if (print_packet_info) { |
||
1693 | /* We're printing packet information; print the information for |
||
1694 | this packet. */ |
||
1695 | print_packet(cf, edt); |
||
1696 | |||
1697 | /* The ANSI C standard does not appear to *require* that a line-buffered |
||
1698 | stream be flushed to the host environment whenever a newline is |
||
1699 | written, it just says that, on such a stream, characters "are |
||
1700 | intended to be transmitted to or from the host environment as a |
||
1701 | block when a new-line character is encountered". |
||
1702 | |||
1703 | The Visual C++ 6.0 C implementation doesn't do what is intended; |
||
1704 | even if you set a stream to be line-buffered, it still doesn't |
||
1705 | flush the buffer at the end of every line. |
||
1706 | |||
1707 | So, if the "-l" flag was specified, we flush the standard output |
||
1708 | at the end of a packet. This will do the right thing if we're |
||
1709 | printing packet summary lines, and, as we print the entire protocol |
||
1710 | tree for a single packet without waiting for anything to happen, |
||
1711 | it should be as good as line-buffered mode if we're printing |
||
1712 | protocol trees. (The whole reason for the "-l" flag in either |
||
1713 | tcpdump or TShark is to allow the output of a live capture to |
||
1714 | be piped to a program or script and to have that script see the |
||
1715 | information for the packet as soon as it's printed, rather than |
||
1716 | having to wait until a standard I/O buffer fills up. */ |
||
1717 | if (line_buffered) |
||
1718 | fflush(stdout); |
||
1719 | |||
1720 | if (ferror(stdout)) { |
||
1721 | show_print_file_io_error(errno); |
||
1722 | exit(2); |
||
1723 | } |
||
1724 | } |
||
1725 | |||
1726 | /* this must be set after print_packet() [bug #8160] */ |
||
1727 | prev_dis_frame = fdata; |
||
1728 | prev_dis = &prev_dis_frame; |
||
1729 | } |
||
1730 | |||
1731 | prev_cap_frame = fdata; |
||
1732 | prev_cap = &prev_cap_frame; |
||
1733 | |||
1734 | if (edt) { |
||
1735 | epan_dissect_reset(edt); |
||
1736 | frame_data_destroy(&fdata); |
||
1737 | } |
||
1738 | return passed; |
||
1739 | } |
||
1740 | |||
1741 | static gboolean |
||
1742 | write_preamble(capture_file *cf) |
||
1743 | { |
||
1744 | switch (output_action) { |
||
1745 | |||
1746 | case WRITE_TEXT: |
||
1747 | return print_preamble(print_stream, cf->filename, get_ws_vcs_version_info()); |
||
1748 | |||
1749 | case WRITE_XML: |
||
1750 | if (print_details) |
||
1751 | write_pdml_preamble(stdout, cf->filename); |
||
1752 | else |
||
1753 | write_psml_preamble(&cf->cinfo, stdout); |
||
1754 | return !ferror(stdout); |
||
1755 | |||
1756 | case WRITE_FIELDS: |
||
1757 | write_fields_preamble(output_fields, stdout); |
||
1758 | return !ferror(stdout); |
||
1759 | |||
1760 | default: |
||
1761 | g_assert_not_reached(); |
||
1762 | return FALSE; |
||
1763 | } |
||
1764 | } |
||
1765 | |||
1766 | static char * |
||
1767 | get_line_buf(size_t len) |
||
1768 | { |
||
1769 | static char *line_bufp = NULL; |
||
1770 | static size_t line_buf_len = 256; |
||
1771 | size_t new_line_buf_len; |
||
1772 | |||
1773 | for (new_line_buf_len = line_buf_len; len > new_line_buf_len; |
||
1774 | new_line_buf_len *= 2) |
||
1775 | ; |
||
1776 | if (line_bufp == NULL) { |
||
1777 | line_buf_len = new_line_buf_len; |
||
1778 | line_bufp = (char *)g_malloc(line_buf_len + 1); |
||
1779 | } else { |
||
1780 | if (new_line_buf_len > line_buf_len) { |
||
1781 | line_buf_len = new_line_buf_len; |
||
1782 | line_bufp = (char *)g_realloc(line_bufp, line_buf_len + 1); |
||
1783 | } |
||
1784 | } |
||
1785 | return line_bufp; |
||
1786 | } |
||
1787 | |||
1788 | static inline void |
||
1789 | put_string(char *dest, const char *str, size_t str_len) |
||
1790 | { |
||
1791 | memcpy(dest, str, str_len); |
||
1792 | dest[str_len] = '\0'; |
||
1793 | } |
||
1794 | |||
1795 | static inline void |
||
1796 | put_spaces_string(char *dest, const char *str, size_t str_len, size_t str_with_spaces) |
||
1797 | { |
||
1798 | size_t i; |
||
1799 | |||
1800 | for (i = str_len; i < str_with_spaces; i++) |
||
1801 | *dest++ = ' '; |
||
1802 | |||
1803 | put_string(dest, str, str_len); |
||
1804 | } |
||
1805 | |||
1806 | static inline void |
||
1807 | put_string_spaces(char *dest, const char *str, size_t str_len, size_t str_with_spaces) |
||
1808 | { |
||
1809 | size_t i; |
||
1810 | |||
1811 | memcpy(dest, str, str_len); |
||
1812 | for (i = str_len; i < str_with_spaces; i++) |
||
1813 | dest[i] = ' '; |
||
1814 | |||
1815 | dest[str_with_spaces] = '\0'; |
||
1816 | } |
||
1817 | |||
1818 | static gboolean |
||
1819 | print_columns(capture_file *cf) |
||
1820 | { |
||
1821 | char *line_bufp; |
||
1822 | int i; |
||
1823 | size_t buf_offset; |
||
1824 | size_t column_len; |
||
1825 | size_t col_len; |
||
1826 | col_item_t* col_item; |
||
1827 | |||
1828 | line_bufp = get_line_buf(256); |
||
1829 | buf_offset = 0; |
||
1830 | *line_bufp = '\0'; |
||
1831 | for (i = 0; i < cf->cinfo.num_cols; i++) { |
||
1832 | col_item = &cf->cinfo.columns[i]; |
||
1833 | /* Skip columns not marked as visible. */ |
||
1834 | if (!get_column_visible(i)) |
||
1835 | continue; |
||
1836 | switch (col_item->col_fmt) { |
||
1837 | case COL_NUMBER: |
||
1838 | column_len = col_len = strlen(col_item->col_data); |
||
1839 | if (column_len < 3) |
||
1840 | column_len = 3; |
||
1841 | line_bufp = get_line_buf(buf_offset + column_len); |
||
1842 | put_spaces_string(line_bufp + buf_offset, col_item->col_data, col_len, column_len); |
||
1843 | break; |
||
1844 | |||
1845 | case COL_CLS_TIME: |
||
1846 | case COL_REL_TIME: |
||
1847 | case COL_ABS_TIME: |
||
1848 | case COL_ABS_YMD_TIME: /* XXX - wider */ |
||
1849 | case COL_ABS_YDOY_TIME: /* XXX - wider */ |
||
1850 | case COL_UTC_TIME: |
||
1851 | case COL_UTC_YMD_TIME: /* XXX - wider */ |
||
1852 | case COL_UTC_YDOY_TIME: /* XXX - wider */ |
||
1853 | column_len = col_len = strlen(col_item->col_data); |
||
1854 | if (column_len < 10) |
||
1855 | column_len = 10; |
||
1856 | line_bufp = get_line_buf(buf_offset + column_len); |
||
1857 | put_spaces_string(line_bufp + buf_offset, col_item->col_data, col_len, column_len); |
||
1858 | break; |
||
1859 | |||
1860 | case COL_DEF_SRC: |
||
1861 | case COL_RES_SRC: |
||
1862 | case COL_UNRES_SRC: |
||
1863 | case COL_DEF_DL_SRC: |
||
1864 | case COL_RES_DL_SRC: |
||
1865 | case COL_UNRES_DL_SRC: |
||
1866 | case COL_DEF_NET_SRC: |
||
1867 | case COL_RES_NET_SRC: |
||
1868 | case COL_UNRES_NET_SRC: |
||
1869 | column_len = col_len = strlen(col_item->col_data); |
||
1870 | if (column_len < 12) |
||
1871 | column_len = 12; |
||
1872 | line_bufp = get_line_buf(buf_offset + column_len); |
||
1873 | put_spaces_string(line_bufp + buf_offset, col_item->col_data, col_len, column_len); |
||
1874 | break; |
||
1875 | |||
1876 | case COL_DEF_DST: |
||
1877 | case COL_RES_DST: |
||
1878 | case COL_UNRES_DST: |
||
1879 | case COL_DEF_DL_DST: |
||
1880 | case COL_RES_DL_DST: |
||
1881 | case COL_UNRES_DL_DST: |
||
1882 | case COL_DEF_NET_DST: |
||
1883 | case COL_RES_NET_DST: |
||
1884 | case COL_UNRES_NET_DST: |
||
1885 | column_len = col_len = strlen(col_item->col_data); |
||
1886 | if (column_len < 12) |
||
1887 | column_len = 12; |
||
1888 | line_bufp = get_line_buf(buf_offset + column_len); |
||
1889 | put_string_spaces(line_bufp + buf_offset, col_item->col_data, col_len, column_len); |
||
1890 | break; |
||
1891 | |||
1892 | default: |
||
1893 | column_len = strlen(col_item->col_data); |
||
1894 | line_bufp = get_line_buf(buf_offset + column_len); |
||
1895 | put_string(line_bufp + buf_offset, col_item->col_data, column_len); |
||
1896 | break; |
||
1897 | } |
||
1898 | buf_offset += column_len; |
||
1899 | if (i != cf->cinfo.num_cols - 1) { |
||
1900 | /* |
||
1901 | * This isn't the last column, so we need to print a |
||
1902 | * separator between this column and the next. |
||
1903 | * |
||
1904 | * If we printed a network source and are printing a |
||
1905 | * network destination of the same type next, separate |
||
1906 | * them with " -> "; if we printed a network destination |
||
1907 | * and are printing a network source of the same type |
||
1908 | * next, separate them with " <- "; otherwise separate them |
||
1909 | * with a space. |
||
1910 | * |
||
1911 | * We add enough space to the buffer for " <- " or " -> ", |
||
1912 | * even if we're only adding " ". |
||
1913 | */ |
||
1914 | line_bufp = get_line_buf(buf_offset + 4); |
||
1915 | switch (col_item->col_fmt) { |
||
1916 | |||
1917 | case COL_DEF_SRC: |
||
1918 | case COL_RES_SRC: |
||
1919 | case COL_UNRES_SRC: |
||
1920 | switch (cf->cinfo.columns[i+1].col_fmt) { |
||
1921 | |||
1922 | case COL_DEF_DST: |
||
1923 | case COL_RES_DST: |
||
1924 | case COL_UNRES_DST: |
||
1925 | put_string(line_bufp + buf_offset, " -> ", 4); |
||
1926 | buf_offset += 4; |
||
1927 | break; |
||
1928 | |||
1929 | default: |
||
1930 | put_string(line_bufp + buf_offset, " ", 1); |
||
1931 | buf_offset += 1; |
||
1932 | break; |
||
1933 | } |
||
1934 | break; |
||
1935 | |||
1936 | case COL_DEF_DL_SRC: |
||
1937 | case COL_RES_DL_SRC: |
||
1938 | case COL_UNRES_DL_SRC: |
||
1939 | switch (cf->cinfo.columns[i+1].col_fmt) { |
||
1940 | |||
1941 | case COL_DEF_DL_DST: |
||
1942 | case COL_RES_DL_DST: |
||
1943 | case COL_UNRES_DL_DST: |
||
1944 | put_string(line_bufp + buf_offset, " -> ", 4); |
||
1945 | buf_offset += 4; |
||
1946 | break; |
||
1947 | |||
1948 | default: |
||
1949 | put_string(line_bufp + buf_offset, " ", 1); |
||
1950 | buf_offset += 1; |
||
1951 | break; |
||
1952 | } |
||
1953 | break; |
||
1954 | |||
1955 | case COL_DEF_NET_SRC: |
||
1956 | case COL_RES_NET_SRC: |
||
1957 | case COL_UNRES_NET_SRC: |
||
1958 | switch (cf->cinfo.columns[i+1].col_fmt) { |
||
1959 | |||
1960 | case COL_DEF_NET_DST: |
||
1961 | case COL_RES_NET_DST: |
||
1962 | case COL_UNRES_NET_DST: |
||
1963 | put_string(line_bufp + buf_offset, " -> ", 4); |
||
1964 | buf_offset += 4; |
||
1965 | break; |
||
1966 | |||
1967 | default: |
||
1968 | put_string(line_bufp + buf_offset, " ", 1); |
||
1969 | buf_offset += 1; |
||
1970 | break; |
||
1971 | } |
||
1972 | break; |
||
1973 | |||
1974 | case COL_DEF_DST: |
||
1975 | case COL_RES_DST: |
||
1976 | case COL_UNRES_DST: |
||
1977 | switch (cf->cinfo.columns[i+1].col_fmt) { |
||
1978 | |||
1979 | case COL_DEF_SRC: |
||
1980 | case COL_RES_SRC: |
||
1981 | case COL_UNRES_SRC: |
||
1982 | put_string(line_bufp + buf_offset, " <- ", 4); |
||
1983 | buf_offset += 4; |
||
1984 | break; |
||
1985 | |||
1986 | default: |
||
1987 | put_string(line_bufp + buf_offset, " ", 1); |
||
1988 | buf_offset += 1; |
||
1989 | break; |
||
1990 | } |
||
1991 | break; |
||
1992 | |||
1993 | case COL_DEF_DL_DST: |
||
1994 | case COL_RES_DL_DST: |
||
1995 | case COL_UNRES_DL_DST: |
||
1996 | switch (cf->cinfo.columns[i+1].col_fmt) { |
||
1997 | |||
1998 | case COL_DEF_DL_SRC: |
||
1999 | case COL_RES_DL_SRC: |
||
2000 | case COL_UNRES_DL_SRC: |
||
2001 | put_string(line_bufp + buf_offset, " <- ", 4); |
||
2002 | buf_offset += 4; |
||
2003 | break; |
||
2004 | |||
2005 | default: |
||
2006 | put_string(line_bufp + buf_offset, " ", 1); |
||
2007 | buf_offset += 1; |
||
2008 | break; |
||
2009 | } |
||
2010 | break; |
||
2011 | |||
2012 | case COL_DEF_NET_DST: |
||
2013 | case COL_RES_NET_DST: |
||
2014 | case COL_UNRES_NET_DST: |
||
2015 | switch (cf->cinfo.columns[i+1].col_fmt) { |
||
2016 | |||
2017 | case COL_DEF_NET_SRC: |
||
2018 | case COL_RES_NET_SRC: |
||
2019 | case COL_UNRES_NET_SRC: |
||
2020 | put_string(line_bufp + buf_offset, " <- ", 4); |
||
2021 | buf_offset += 4; |
||
2022 | break; |
||
2023 | |||
2024 | default: |
||
2025 | put_string(line_bufp + buf_offset, " ", 1); |
||
2026 | buf_offset += 1; |
||
2027 | break; |
||
2028 | } |
||
2029 | break; |
||
2030 | |||
2031 | default: |
||
2032 | put_string(line_bufp + buf_offset, " ", 1); |
||
2033 | buf_offset += 1; |
||
2034 | break; |
||
2035 | } |
||
2036 | } |
||
2037 | } |
||
2038 | return print_line(print_stream, 0, line_bufp); |
||
2039 | } |
||
2040 | |||
2041 | static gboolean |
||
2042 | print_packet(capture_file *cf, epan_dissect_t *edt) |
||
2043 | { |
||
2044 | print_args_t print_args; |
||
2045 | |||
2046 | if (print_summary || output_fields_has_cols(output_fields)) { |
||
2047 | /* Just fill in the columns. */ |
||
2048 | epan_dissect_fill_in_columns(edt, FALSE, TRUE); |
||
2049 | |||
2050 | if (print_summary) { |
||
2051 | /* Now print them. */ |
||
2052 | switch (output_action) { |
||
2053 | |||
2054 | case WRITE_TEXT: |
||
2055 | if (!print_columns(cf)) |
||
2056 | return FALSE; |
||
2057 | break; |
||
2058 | |||
2059 | case WRITE_XML: |
||
2060 | write_psml_columns(edt, stdout); |
||
2061 | return !ferror(stdout); |
||
2062 | case WRITE_FIELDS: /*No non-verbose "fields" format */ |
||
2063 | g_assert_not_reached(); |
||
2064 | break; |
||
2065 | } |
||
2066 | } |
||
2067 | } |
||
2068 | if (print_details) { |
||
2069 | /* Print the information in the protocol tree. */ |
||
2070 | switch (output_action) { |
||
2071 | |||
2072 | case WRITE_TEXT: |
||
2073 | /* Only initialize the fields that are actually used in proto_tree_print. |
||
2074 | * This is particularly important for .range, as that's heap memory which |
||
2075 | * we would otherwise have to g_free(). |
||
2076 | print_args.to_file = TRUE; |
||
2077 | print_args.format = print_format; |
||
2078 | print_args.print_summary = print_summary; |
||
2079 | print_args.print_formfeed = FALSE; |
||
2080 | packet_range_init(&print_args.range, &cfile); |
||
2081 | */ |
||
2082 | print_args.print_hex = print_hex; |
||
2083 | print_args.print_dissections = print_details ? print_dissections_expanded : print_dissections_none; |
||
2084 | |||
2085 | if (!proto_tree_print(&print_args, edt, output_only_tables, print_stream)) |
||
2086 | return FALSE; |
||
2087 | if (!print_hex) { |
||
2088 | if (!print_line(print_stream, 0, separator)) |
||
2089 | return FALSE; |
||
2090 | } |
||
2091 | break; |
||
2092 | |||
2093 | case WRITE_XML: |
||
2094 | write_pdml_proto_tree(NULL, NULL, edt, stdout); |
||
2095 | printf("\n"); |
||
2096 | return !ferror(stdout); |
||
2097 | case WRITE_FIELDS: |
||
2098 | write_fields_proto_tree(output_fields, edt, &cf->cinfo, stdout); |
||
2099 | printf("\n"); |
||
2100 | return !ferror(stdout); |
||
2101 | } |
||
2102 | } |
||
2103 | if (print_hex) { |
||
2104 | if (print_summary || print_details) { |
||
2105 | if (!print_line(print_stream, 0, "")) |
||
2106 | return FALSE; |
||
2107 | } |
||
2108 | if (!print_hex_data(print_stream, edt)) |
||
2109 | return FALSE; |
||
2110 | if (!print_line(print_stream, 0, separator)) |
||
2111 | return FALSE; |
||
2112 | } |
||
2113 | return TRUE; |
||
2114 | } |
||
2115 | |||
2116 | static gboolean |
||
2117 | write_finale(void) |
||
2118 | { |
||
2119 | switch (output_action) { |
||
2120 | |||
2121 | case WRITE_TEXT: |
||
2122 | return print_finale(print_stream); |
||
2123 | |||
2124 | case WRITE_XML: |
||
2125 | if (print_details) |
||
2126 | write_pdml_finale(stdout); |
||
2127 | else |
||
2128 | write_psml_finale(stdout); |
||
2129 | return !ferror(stdout); |
||
2130 | |||
2131 | case WRITE_FIELDS: |
||
2132 | write_fields_finale(output_fields, stdout); |
||
2133 | return !ferror(stdout); |
||
2134 | |||
2135 | default: |
||
2136 | g_assert_not_reached(); |
||
2137 | return FALSE; |
||
2138 | } |
||
2139 | } |
||
2140 | |||
2141 | cf_status_t |
||
2142 | cf_open(capture_file *cf, const char *fname, unsigned int type, gboolean is_tempfile, int *err) |
||
2143 | { |
||
2144 | gchar *err_info; |
||
2145 | char err_msg[2048+1]; |
||
2146 | |||
2147 | /* The open isn't implemented yet. Fill in the information for this file. */ |
||
2148 | |||
2149 | /* Create new epan session for dissection. */ |
||
2150 | epan_free(cf->epan); |
||
2151 | cf->epan = tfshark_epan_new(cf); |
||
2152 | |||
2153 | cf->wth = NULL; /**** XXX - DOESN'T WORK RIGHT NOW!!!! */ |
||
2154 | cf->f_datalen = 0; /* not used, but set it anyway */ |
||
2155 | |||
2156 | /* Set the file name because we need it to set the follow stream filter. |
||
2157 | XXX - is that still true? We need it for other reasons, though, |
||
2158 | in any case. */ |
||
2159 | cf->filename = g_strdup(fname); |
||
2160 | |||
2161 | /* Indicate whether it's a permanent or temporary file. */ |
||
2162 | cf->is_tempfile = is_tempfile; |
||
2163 | |||
2164 | /* No user changes yet. */ |
||
2165 | cf->unsaved_changes = FALSE; |
||
2166 | |||
2167 | cf->cd_t = 0; /**** XXX - DOESN'T WORK RIGHT NOW!!!! */ |
||
2168 | cf->open_type = type; |
||
2169 | cf->count = 0; |
||
2170 | cf->drops_known = FALSE; |
||
2171 | cf->drops = 0; |
||
2172 | cf->snap = 0; /**** XXX - DOESN'T WORK RIGHT NOW!!!! */ |
||
2173 | if (cf->snap == 0) { |
||
2174 | /* Snapshot length not known. */ |
||
2175 | cf->has_snap = FALSE; |
||
2176 | cf->snap = 0; |
||
2177 | } else |
||
2178 | cf->has_snap = TRUE; |
||
2179 | nstime_set_zero(&cf->elapsed_time); |
||
2180 | ref = NULL; |
||
2181 | prev_dis = NULL; |
||
2182 | prev_cap = NULL; |
||
2183 | |||
2184 | cf->state = FILE_READ_IN_PROGRESS; |
||
2185 | |||
2186 | return CF_OK; |
||
2187 | |||
2188 | /* fail: */ |
||
2189 | g_snprintf(err_msg, sizeof err_msg, |
||
2190 | cf_open_error_message(*err, err_info, FALSE, cf->cd_t), fname); |
||
2191 | cmdarg_err("%s", err_msg); |
||
2192 | return CF_ERROR; |
||
2193 | } |
||
2194 | |||
2195 | static void |
||
2196 | show_print_file_io_error(int err) |
||
2197 | { |
||
2198 | switch (err) { |
||
2199 | |||
2200 | case ENOSPC: |
||
2201 | cmdarg_err("Not all the packets could be printed because there is " |
||
2202 | "no space left on the file system."); |
||
2203 | break; |
||
2204 | |||
2205 | #ifdef EDQUOT |
||
2206 | case EDQUOT: |
||
2207 | cmdarg_err("Not all the packets could be printed because you are " |
||
2208 | "too close to, or over your disk quota."); |
||
2209 | break; |
||
2210 | #endif |
||
2211 | |||
2212 | default: |
||
2213 | cmdarg_err("An error occurred while printing packets: %s.", |
||
2214 | g_strerror(err)); |
||
2215 | break; |
||
2216 | } |
||
2217 | } |
||
2218 | |||
2219 | static const char * |
||
2220 | cf_open_error_message(int err, gchar *err_info _U_, gboolean for_writing, |
||
2221 | int file_type _U_) |
||
2222 | { |
||
2223 | const char *errmsg; |
||
2224 | /* static char errmsg_errno[1024+1]; */ |
||
2225 | |||
2226 | #if 0 |
||
2227 | if (err < 0) { |
||
2228 | /* Wiretap error. */ |
||
2229 | switch (err) { |
||
2230 | |||
2231 | case FTAP_ERR_NOT_REGULAR_FILE: |
||
2232 | errmsg = "The file \"%s\" is a \"special file\" or socket or other non-regular file."; |
||
2233 | break; |
||
2234 | |||
2235 | case FTAP_ERR_RANDOM_OPEN_PIPE: |
||
2236 | /* Seen only when opening a capture file for reading. */ |
||
2237 | errmsg = "The file \"%s\" is a pipe or FIFO; TFShark can't read pipe or FIFO files in two-pass mode."; |
||
2238 | break; |
||
2239 | |||
2240 | case FTAP_ERR_FILE_UNKNOWN_FORMAT: |
||
2241 | /* Seen only when opening a capture file for reading. */ |
||
2242 | errmsg = "The file \"%s\" isn't a capture file in a format TFShark understands."; |
||
2243 | break; |
||
2244 | |||
2245 | case FTAP_ERR_UNSUPPORTED: |
||
2246 | /* Seen only when opening a capture file for reading. */ |
||
2247 | g_snprintf(errmsg_errno, sizeof(errmsg_errno), |
||
2248 | "The file \"%%s\" isn't a capture file in a format TFShark understands.\n" |
||
2249 | "(%s)", err_info); |
||
2250 | g_free(err_info); |
||
2251 | errmsg = errmsg_errno; |
||
2252 | break; |
||
2253 | |||
2254 | case FTAP_ERR_CANT_WRITE_TO_PIPE: |
||
2255 | /* Seen only when opening a capture file for writing. */ |
||
2256 | g_snprintf(errmsg_errno, sizeof(errmsg_errno), |
||
2257 | "The file \"%%s\" is a pipe, and \"%s\" capture files can't be " |
||
2258 | "written to a pipe.", ftap_file_type_subtype_short_string(file_type)); |
||
2259 | errmsg = errmsg_errno; |
||
2260 | break; |
||
2261 | |||
2262 | case FTAP_ERR_UNSUPPORTED_FILE_TYPE: |
||
2263 | /* Seen only when opening a capture file for writing. */ |
||
2264 | errmsg = "TFShark doesn't support writing capture files in that format."; |
||
2265 | break; |
||
2266 | |||
2267 | case FTAP_ERR_UNSUPPORTED_ENCAP: |
||
2268 | if (for_writing) { |
||
2269 | g_snprintf(errmsg_errno, sizeof(errmsg_errno), |
||
2270 | "TFShark can't save this capture as a \"%s\" file.", |
||
2271 | ftap_file_type_subtype_short_string(file_type)); |
||
2272 | } else { |
||
2273 | g_snprintf(errmsg_errno, sizeof(errmsg_errno), |
||
2274 | "The file \"%%s\" is a capture for a network type that TFShark doesn't support.\n" |
||
2275 | "(%s)", err_info); |
||
2276 | g_free(err_info); |
||
2277 | } |
||
2278 | errmsg = errmsg_errno; |
||
2279 | break; |
||
2280 | |||
2281 | case FTAP_ERR_ENCAP_PER_RECORD_UNSUPPORTED: |
||
2282 | if (for_writing) { |
||
2283 | g_snprintf(errmsg_errno, sizeof(errmsg_errno), |
||
2284 | "TFShark can't save this capture as a \"%s\" file.", |
||
2285 | ftap_file_type_subtype_short_string(file_type)); |
||
2286 | errmsg = errmsg_errno; |
||
2287 | } else |
||
2288 | errmsg = "The file \"%s\" is a capture for a network type that TFShark doesn't support."; |
||
2289 | break; |
||
2290 | |||
2291 | case FTAP_ERR_BAD_FILE: |
||
2292 | /* Seen only when opening a capture file for reading. */ |
||
2293 | g_snprintf(errmsg_errno, sizeof(errmsg_errno), |
||
2294 | "The file \"%%s\" appears to be damaged or corrupt.\n" |
||
2295 | "(%s)", err_info); |
||
2296 | g_free(err_info); |
||
2297 | errmsg = errmsg_errno; |
||
2298 | break; |
||
2299 | |||
2300 | case FTAP_ERR_CANT_OPEN: |
||
2301 | if (for_writing) |
||
2302 | errmsg = "The file \"%s\" could not be created for some unknown reason."; |
||
2303 | else |
||
2304 | errmsg = "The file \"%s\" could not be opened for some unknown reason."; |
||
2305 | break; |
||
2306 | |||
2307 | case FTAP_ERR_SHORT_READ: |
||
2308 | errmsg = "The file \"%s\" appears to have been cut short" |
||
2309 | " in the middle of a packet or other data."; |
||
2310 | break; |
||
2311 | |||
2312 | case FTAP_ERR_SHORT_WRITE: |
||
2313 | errmsg = "A full header couldn't be written to the file \"%s\"."; |
||
2314 | break; |
||
2315 | |||
2316 | case FTAP_ERR_COMPRESSION_NOT_SUPPORTED: |
||
2317 | errmsg = "This file type cannot be written as a compressed file."; |
||
2318 | break; |
||
2319 | |||
2320 | case FTAP_ERR_DECOMPRESS: |
||
2321 | /* Seen only when opening a capture file for reading. */ |
||
2322 | g_snprintf(errmsg_errno, sizeof(errmsg_errno), |
||
2323 | "The compressed file \"%%s\" appears to be damaged or corrupt.\n" |
||
2324 | "(%s)", err_info); |
||
2325 | g_free(err_info); |
||
2326 | errmsg = errmsg_errno; |
||
2327 | break; |
||
2328 | |||
2329 | default: |
||
2330 | g_snprintf(errmsg_errno, sizeof(errmsg_errno), |
||
2331 | "The file \"%%s\" could not be %s: %s.", |
||
2332 | for_writing ? "created" : "opened", |
||
2333 | ftap_strerror(err)); |
||
2334 | errmsg = errmsg_errno; |
||
2335 | break; |
||
2336 | } |
||
2337 | } else |
||
2338 | #endif |
||
2339 | errmsg = file_open_error_message(err, for_writing); |
||
2340 | return errmsg; |
||
2341 | } |
||
2342 | |||
2343 | /* |
||
2344 | * Open/create errors are reported with an console message in TFShark. |
||
2345 | */ |
||
2346 | static void |
||
2347 | open_failure_message(const char *filename, int err, gboolean for_writing) |
||
2348 | { |
||
2349 | fprintf(stderr, "tfshark: "); |
||
2350 | fprintf(stderr, file_open_error_message(err, for_writing), filename); |
||
2351 | fprintf(stderr, "\n"); |
||
2352 | } |
||
2353 | |||
2354 | |||
2355 | /* |
||
2356 | * General errors are reported with an console message in TFShark. |
||
2357 | */ |
||
2358 | static void |
||
2359 | failure_message(const char *msg_format, va_list ap) |
||
2360 | { |
||
2361 | fprintf(stderr, "tfshark: "); |
||
2362 | vfprintf(stderr, msg_format, ap); |
||
2363 | fprintf(stderr, "\n"); |
||
2364 | } |
||
2365 | |||
2366 | /* |
||
2367 | * Read errors are reported with an console message in TFShark. |
||
2368 | */ |
||
2369 | static void |
||
2370 | read_failure_message(const char *filename, int err) |
||
2371 | { |
||
2372 | cmdarg_err("An error occurred while reading from the file \"%s\": %s.", |
||
2373 | filename, g_strerror(err)); |
||
2374 | } |
||
2375 | |||
2376 | /* |
||
2377 | * Write errors are reported with an console message in TFShark. |
||
2378 | */ |
||
2379 | static void |
||
2380 | write_failure_message(const char *filename, int err) |
||
2381 | { |
||
2382 | cmdarg_err("An error occurred while writing to the file \"%s\": %s.", |
||
2383 | filename, g_strerror(err)); |
||
2384 | } |
||
2385 | |||
2386 | /* |
||
2387 | * Report additional information for an error in command-line arguments. |
||
2388 | */ |
||
2389 | static void |
||
2390 | failure_message_cont(const char *msg_format, va_list ap) |
||
2391 | { |
||
2392 | vfprintf(stderr, msg_format, ap); |
||
2393 | fprintf(stderr, "\n"); |
||
2394 | } |
||
2395 | |||
2396 | /* |
||
2397 | * Editor modelines - https://www.wireshark.org/tools/modelines.html |
||
2398 | * |
||
2399 | * Local variables: |
||
2400 | * c-basic-offset: 2 |
||
2401 | * tab-width: 8 |
||
2402 | * indent-tabs-mode: nil |
||
2403 | * End: |
||
2404 | * |
||
2405 | * vi: set shiftwidth=2 tabstop=8 expandtab: |
||
2406 | * :indentSize=2:tabSize=8:noTabs=true: |
||
2407 | */ |