nexmon – Blame information for rev 1
?pathlinks?
Rev | Author | Line No. | Line |
---|---|---|---|
1 | office | 1 | /* Combine dump files, either by appending or by merging by timestamp |
2 | * |
||
3 | * Wireshark - Network traffic analyzer |
||
4 | * By Gerald Combs <gerald@wireshark.org> |
||
5 | * Copyright 1998 Gerald Combs |
||
6 | * |
||
7 | * This program is free software; you can redistribute it and/or modify |
||
8 | * it under the terms of the GNU General Public License as published by |
||
9 | * the Free Software Foundation; either version 2 of the License, or |
||
10 | * (at your option) any later version. |
||
11 | * |
||
12 | * This program is distributed in the hope that it will be useful, |
||
13 | * but WITHOUT ANY WARRANTY; without even the implied warranty of |
||
14 | * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the |
||
15 | * GNU General Public License for more details. |
||
16 | * |
||
17 | * You should have received a copy of the GNU General Public License along |
||
18 | * with this program; if not, write to the Free Software Foundation, Inc., |
||
19 | * 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA. |
||
20 | * |
||
21 | * Mergecap written by Scott Renfro <scott@renfro.org> based on |
||
22 | * editcap by Richard Sharpe and Guy Harris |
||
23 | * |
||
24 | */ |
||
25 | |||
26 | #include <config.h> |
||
27 | |||
28 | #include <stdio.h> |
||
29 | #include <stdlib.h> |
||
30 | #include <errno.h> |
||
31 | #include <glib.h> |
||
32 | |||
33 | #ifdef HAVE_GETOPT_H |
||
34 | #include <getopt.h> |
||
35 | #endif |
||
36 | |||
37 | #include <string.h> |
||
38 | |||
39 | #include <wiretap/wtap.h> |
||
40 | |||
41 | #ifndef HAVE_GETOPT_LONG |
||
42 | #include <wsutil/wsgetopt.h> |
||
43 | #endif |
||
44 | |||
45 | #include <wsutil/clopts_common.h> |
||
46 | #include <wsutil/cmdarg_err.h> |
||
47 | #include <wsutil/crash_info.h> |
||
48 | #include <wsutil/filesystem.h> |
||
49 | #include <wsutil/file_util.h> |
||
50 | #include <wsutil/privileges.h> |
||
51 | #include <wsutil/strnatcmp.h> |
||
52 | #include <ws_version_info.h> |
||
53 | |||
54 | #ifdef HAVE_PLUGINS |
||
55 | #include <wsutil/plugins.h> |
||
56 | #endif |
||
57 | |||
58 | #include <wsutil/report_err.h> |
||
59 | |||
60 | #include <wiretap/merge.h> |
||
61 | #include <wiretap/pcap-encap.h> |
||
62 | |||
63 | #ifdef _WIN32 |
||
64 | #include <wsutil/unicode-utils.h> |
||
65 | #endif /* _WIN32 */ |
||
66 | |||
67 | /* |
||
68 | * Show the usage |
||
69 | */ |
||
70 | static void |
||
71 | print_usage(FILE *output) |
||
72 | { |
||
73 | fprintf(output, "\n"); |
||
74 | fprintf(output, "Usage: mergecap [options] -w <outfile>|- <infile> [<infile> ...]\n"); |
||
75 | fprintf(output, "\n"); |
||
76 | fprintf(output, "Output:\n"); |
||
77 | fprintf(output, " -a concatenate rather than merge files.\n"); |
||
78 | fprintf(output, " default is to merge based on frame timestamps.\n"); |
||
79 | fprintf(output, " -s <snaplen> truncate packets to <snaplen> bytes of data.\n"); |
||
80 | fprintf(output, " -w <outfile>|- set the output filename to <outfile> or '-' for stdout.\n"); |
||
81 | fprintf(output, " -F <capture type> set the output file type; default is pcapng.\n"); |
||
82 | fprintf(output, " an empty \"-F\" option will list the file types.\n"); |
||
83 | fprintf(output, " -I <IDB merge mode> set the merge mode for Interface Description Blocks; default is 'all'.\n"); |
||
84 | fprintf(output, " an empty \"-I\" option will list the merge modes.\n"); |
||
85 | fprintf(output, "\n"); |
||
86 | fprintf(output, "Miscellaneous:\n"); |
||
87 | fprintf(output, " -h display this help and exit.\n"); |
||
88 | fprintf(output, " -v verbose output.\n"); |
||
89 | } |
||
90 | |||
91 | /* |
||
92 | * Report an error in command-line arguments. |
||
93 | */ |
||
94 | static void |
||
95 | mergecap_cmdarg_err(const char *fmt, va_list ap) |
||
96 | { |
||
97 | fprintf(stderr, "mergecap: "); |
||
98 | vfprintf(stderr, fmt, ap); |
||
99 | fprintf(stderr, "\n"); |
||
100 | } |
||
101 | |||
102 | /* |
||
103 | * Report additional information for an error in command-line arguments. |
||
104 | */ |
||
105 | static void |
||
106 | mergecap_cmdarg_err_cont(const char *fmt, va_list ap) |
||
107 | { |
||
108 | vfprintf(stderr, fmt, ap); |
||
109 | fprintf(stderr, "\n"); |
||
110 | } |
||
111 | |||
112 | struct string_elem { |
||
113 | const char *sstr; /* The short string */ |
||
114 | const char *lstr; /* The long string */ |
||
115 | }; |
||
116 | |||
117 | static gint |
||
118 | string_compare(gconstpointer a, gconstpointer b) |
||
119 | { |
||
120 | return strcmp(((const struct string_elem *)a)->sstr, |
||
121 | ((const struct string_elem *)b)->sstr); |
||
122 | } |
||
123 | |||
124 | static void |
||
125 | string_elem_print(gpointer data, gpointer not_used _U_) |
||
126 | { |
||
127 | fprintf(stderr, " %s - %s\n", ((struct string_elem *)data)->sstr, |
||
128 | ((struct string_elem *)data)->lstr); |
||
129 | } |
||
130 | |||
131 | #ifdef HAVE_PLUGINS |
||
132 | /* |
||
133 | * Don't report failures to load plugins because most (non-wiretap) plugins |
||
134 | * *should* fail to load (because we're not linked against libwireshark and |
||
135 | * dissector plugins need libwireshark). |
||
136 | */ |
||
137 | static void |
||
138 | failure_message(const char *msg_format _U_, va_list ap _U_) |
||
139 | { |
||
140 | return; |
||
141 | } |
||
142 | #endif |
||
143 | |||
144 | static void |
||
145 | list_capture_types(void) { |
||
146 | int i; |
||
147 | struct string_elem *captypes; |
||
148 | GSList *list = NULL; |
||
149 | |||
150 | captypes = g_new(struct string_elem,WTAP_NUM_FILE_TYPES_SUBTYPES); |
||
151 | |||
152 | fprintf(stderr, "mergecap: The available capture file types for the \"-F\" flag are:\n"); |
||
153 | for (i = 0; i < WTAP_NUM_FILE_TYPES_SUBTYPES; i++) { |
||
154 | if (wtap_dump_can_open(i)) { |
||
155 | captypes[i].sstr = wtap_file_type_subtype_short_string(i); |
||
156 | captypes[i].lstr = wtap_file_type_subtype_string(i); |
||
157 | list = g_slist_insert_sorted(list, &captypes[i], string_compare); |
||
158 | } |
||
159 | } |
||
160 | g_slist_foreach(list, string_elem_print, NULL); |
||
161 | g_slist_free(list); |
||
162 | g_free(captypes); |
||
163 | } |
||
164 | |||
165 | static void |
||
166 | list_idb_merge_modes(void) { |
||
167 | int i; |
||
168 | |||
169 | fprintf(stderr, "mergecap: The available IDB merge modes for the \"-I\" flag are:\n"); |
||
170 | for (i = 0; i < IDB_MERGE_MODE_MAX; i++) { |
||
171 | fprintf(stderr, " %s\n", merge_idb_merge_mode_to_string(i)); |
||
172 | } |
||
173 | } |
||
174 | |||
175 | static gboolean |
||
176 | merge_callback(merge_event event, int num, |
||
177 | const merge_in_file_t in_files[], const guint in_file_count, |
||
178 | void *data _U_) |
||
179 | { |
||
180 | guint i; |
||
181 | |||
182 | switch (event) { |
||
183 | |||
184 | case MERGE_EVENT_INPUT_FILES_OPENED: |
||
185 | for (i = 0; i < in_file_count; i++) { |
||
186 | fprintf(stderr, "mergecap: %s is type %s.\n", in_files[i].filename, |
||
187 | wtap_file_type_subtype_string(wtap_file_type_subtype(in_files[i].wth))); |
||
188 | } |
||
189 | break; |
||
190 | |||
191 | case MERGE_EVENT_FRAME_TYPE_SELECTED: |
||
192 | /* for this event, num = frame_type */ |
||
193 | if (num == WTAP_ENCAP_PER_PACKET) { |
||
194 | /* |
||
195 | * Find out why we had to choose WTAP_ENCAP_PER_PACKET. |
||
196 | */ |
||
197 | int first_frame_type, this_frame_type; |
||
198 | |||
199 | first_frame_type = wtap_file_encap(in_files[0].wth); |
||
200 | for (i = 1; i < in_file_count; i++) { |
||
201 | this_frame_type = wtap_file_encap(in_files[i].wth); |
||
202 | if (first_frame_type != this_frame_type) { |
||
203 | fprintf(stderr, "mergecap: multiple frame encapsulation types detected\n"); |
||
204 | fprintf(stderr, " defaulting to WTAP_ENCAP_PER_PACKET\n"); |
||
205 | fprintf(stderr, " %s had type %s (%s)\n", |
||
206 | in_files[0].filename, |
||
207 | wtap_encap_string(first_frame_type), |
||
208 | wtap_encap_short_string(first_frame_type)); |
||
209 | fprintf(stderr, " %s had type %s (%s)\n", |
||
210 | in_files[i].filename, |
||
211 | wtap_encap_string(this_frame_type), |
||
212 | wtap_encap_short_string(this_frame_type)); |
||
213 | break; |
||
214 | } |
||
215 | } |
||
216 | } |
||
217 | fprintf(stderr, "mergecap: selected frame_type %s (%s)\n", |
||
218 | wtap_encap_string(num), |
||
219 | wtap_encap_short_string(num)); |
||
220 | break; |
||
221 | |||
222 | case MERGE_EVENT_READY_TO_MERGE: |
||
223 | fprintf(stderr, "mergecap: ready to merge records\n"); |
||
224 | break; |
||
225 | |||
226 | case MERGE_EVENT_PACKET_WAS_READ: |
||
227 | /* for this event, num = count */ |
||
228 | fprintf(stderr, "Record: %d\n", num); |
||
229 | break; |
||
230 | |||
231 | case MERGE_EVENT_DONE: |
||
232 | fprintf(stderr, "mergecap: merging complete\n"); |
||
233 | break; |
||
234 | } |
||
235 | |||
236 | /* false = do not stop merging */ |
||
237 | return FALSE; |
||
238 | } |
||
239 | |||
240 | |||
241 | int |
||
242 | main(int argc, char *argv[]) |
||
243 | { |
||
244 | GString *comp_info_str; |
||
245 | GString *runtime_info_str; |
||
246 | int opt; |
||
247 | static const struct option long_options[] = { |
||
248 | {"help", no_argument, NULL, 'h'}, |
||
249 | {"version", no_argument, NULL, 'V'}, |
||
250 | {0, 0, 0, 0 } |
||
251 | }; |
||
252 | gboolean do_append = FALSE; |
||
253 | gboolean verbose = FALSE; |
||
254 | int in_file_count = 0; |
||
255 | guint snaplen = 0; |
||
256 | #ifdef PCAP_NG_DEFAULT |
||
257 | int file_type = WTAP_FILE_TYPE_SUBTYPE_PCAPNG; /* default to pcap format */ |
||
258 | #else |
||
259 | int file_type = WTAP_FILE_TYPE_SUBTYPE_PCAP; /* default to pcapng format */ |
||
260 | #endif |
||
261 | int out_fd; |
||
262 | int err = 0; |
||
263 | gchar *err_info = NULL; |
||
264 | int err_fileno; |
||
265 | char *out_filename = NULL; |
||
266 | merge_result status; |
||
267 | idb_merge_mode mode = IDB_MERGE_MODE_MAX; |
||
268 | gboolean use_stdout = FALSE; |
||
269 | merge_progress_callback_t cb; |
||
270 | |||
271 | #ifdef HAVE_PLUGINS |
||
272 | char *init_progfile_dir_error; |
||
273 | #endif |
||
274 | |||
275 | cmdarg_err_init(mergecap_cmdarg_err, mergecap_cmdarg_err_cont); |
||
276 | |||
277 | #ifdef _WIN32 |
||
278 | arg_list_utf_16to8(argc, argv); |
||
279 | create_app_running_mutex(); |
||
280 | #endif /* _WIN32 */ |
||
281 | |||
282 | /* Get the compile-time version information string */ |
||
283 | comp_info_str = get_compiled_version_info(NULL, NULL); |
||
284 | |||
285 | /* Get the run-time version information string */ |
||
286 | runtime_info_str = get_runtime_version_info(NULL); |
||
287 | |||
288 | /* Add it to the information to be reported on a crash. */ |
||
289 | ws_add_crash_info("Mergecap (Wireshark) %s\n" |
||
290 | "\n" |
||
291 | "%s" |
||
292 | "\n" |
||
293 | "%s", |
||
294 | get_ws_vcs_version_info(), comp_info_str->str, runtime_info_str->str); |
||
295 | |||
296 | /* |
||
297 | * Get credential information for later use. |
||
298 | */ |
||
299 | init_process_policies(); |
||
300 | init_open_routines(); |
||
301 | |||
302 | #ifdef HAVE_PLUGINS |
||
303 | /* Register wiretap plugins */ |
||
304 | if ((init_progfile_dir_error = init_progfile_dir(argv[0], main))) { |
||
305 | g_warning("mergecap: init_progfile_dir(): %s", init_progfile_dir_error); |
||
306 | g_free(init_progfile_dir_error); |
||
307 | } else { |
||
308 | /* Register all the plugin types we have. */ |
||
309 | wtap_register_plugin_types(); /* Types known to libwiretap */ |
||
310 | |||
311 | init_report_err(failure_message,NULL,NULL,NULL); |
||
312 | |||
313 | /* Scan for plugins. This does *not* call their registration routines; |
||
314 | that's done later. */ |
||
315 | scan_plugins(); |
||
316 | |||
317 | /* Register all libwiretap plugin modules. */ |
||
318 | register_all_wiretap_modules(); |
||
319 | } |
||
320 | #endif |
||
321 | |||
322 | /* Process the options first */ |
||
323 | while ((opt = getopt_long(argc, argv, "aF:hI:s:vVw:", long_options, NULL)) != -1) { |
||
324 | |||
325 | switch (opt) { |
||
326 | case 'a': |
||
327 | do_append = !do_append; |
||
328 | break; |
||
329 | |||
330 | case 'F': |
||
331 | file_type = wtap_short_string_to_file_type_subtype(optarg); |
||
332 | if (file_type < 0) { |
||
333 | fprintf(stderr, "mergecap: \"%s\" isn't a valid capture file type\n", |
||
334 | optarg); |
||
335 | list_capture_types(); |
||
336 | exit(1); |
||
337 | } |
||
338 | break; |
||
339 | |||
340 | case 'h': |
||
341 | printf("Mergecap (Wireshark) %s\n" |
||
342 | "Merge two or more capture files into one.\n" |
||
343 | "See https://www.wireshark.org for more information.\n", |
||
344 | get_ws_vcs_version_info()); |
||
345 | print_usage(stdout); |
||
346 | exit(0); |
||
347 | break; |
||
348 | |||
349 | case 'I': |
||
350 | mode = merge_string_to_idb_merge_mode(optarg); |
||
351 | if (mode == IDB_MERGE_MODE_MAX) { |
||
352 | fprintf(stderr, "mergecap: \"%s\" isn't a valid IDB merge mode\n", |
||
353 | optarg); |
||
354 | list_idb_merge_modes(); |
||
355 | exit(1); |
||
356 | } |
||
357 | break; |
||
358 | |||
359 | case 's': |
||
360 | snaplen = get_positive_int(optarg, "snapshot length"); |
||
361 | break; |
||
362 | |||
363 | case 'v': |
||
364 | verbose = TRUE; |
||
365 | break; |
||
366 | |||
367 | case 'V': |
||
368 | show_version("Mergecap (Wireshark)", comp_info_str, runtime_info_str); |
||
369 | g_string_free(comp_info_str, TRUE); |
||
370 | g_string_free(runtime_info_str, TRUE); |
||
371 | exit(0); |
||
372 | break; |
||
373 | |||
374 | case 'w': |
||
375 | out_filename = optarg; |
||
376 | break; |
||
377 | |||
378 | case '?': /* Bad options if GNU getopt */ |
||
379 | switch(optopt) { |
||
380 | case'F': |
||
381 | list_capture_types(); |
||
382 | break; |
||
383 | case'I': |
||
384 | list_idb_merge_modes(); |
||
385 | break; |
||
386 | default: |
||
387 | print_usage(stderr); |
||
388 | } |
||
389 | exit(1); |
||
390 | break; |
||
391 | } |
||
392 | } |
||
393 | |||
394 | cb.callback_func = merge_callback; |
||
395 | cb.data = NULL; |
||
396 | |||
397 | /* check for proper args; at a minimum, must have an output |
||
398 | * filename and one input file |
||
399 | */ |
||
400 | in_file_count = argc - optind; |
||
401 | if (!out_filename) { |
||
402 | fprintf(stderr, "mergecap: an output filename must be set with -w\n"); |
||
403 | fprintf(stderr, " run with -h for help\n"); |
||
404 | return 1; |
||
405 | } |
||
406 | if (in_file_count < 1) { |
||
407 | fprintf(stderr, "mergecap: No input files were specified\n"); |
||
408 | return 1; |
||
409 | } |
||
410 | |||
411 | /* setting IDB merge mode must use PCAPNG output */ |
||
412 | if (mode != IDB_MERGE_MODE_MAX && file_type != WTAP_FILE_TYPE_SUBTYPE_PCAPNG) { |
||
413 | fprintf(stderr, "The IDB merge mode can only be used with PCAPNG output format\n"); |
||
414 | return 1; |
||
415 | } |
||
416 | |||
417 | /* if they didn't set IDB merge mode, set it to our default */ |
||
418 | if (mode == IDB_MERGE_MODE_MAX) { |
||
419 | mode = IDB_MERGE_MODE_ALL_SAME; |
||
420 | } |
||
421 | |||
422 | /* open the outfile */ |
||
423 | if (strcmp(out_filename, "-") == 0) { |
||
424 | /* use stdout as the outfile */ |
||
425 | use_stdout = TRUE; |
||
426 | out_fd = 1 /*stdout*/; |
||
427 | } else { |
||
428 | /* open the outfile */ |
||
429 | out_fd = ws_open(out_filename, O_WRONLY | O_CREAT | O_TRUNC | O_BINARY, 0644); |
||
430 | if (out_fd == -1) { |
||
431 | fprintf(stderr, "mergecap: Couldn't open output file %s: %s\n", |
||
432 | out_filename, g_strerror(errno)); |
||
433 | exit(1); |
||
434 | } |
||
435 | } |
||
436 | |||
437 | /* merge the files */ |
||
438 | status = merge_files(out_fd, out_filename, file_type, |
||
439 | (const char *const *) &argv[optind], in_file_count, |
||
440 | do_append, mode, snaplen, "mergecap", verbose ? &cb : NULL, |
||
441 | &err, &err_info, &err_fileno); |
||
442 | |||
443 | switch (status) { |
||
444 | case MERGE_OK: |
||
445 | break; |
||
446 | |||
447 | case MERGE_USER_ABORTED: |
||
448 | /* we don't catch SIGINT/SIGTERM (yet?), so we couldn't have aborted */ |
||
449 | g_assert(FALSE); |
||
450 | break; |
||
451 | |||
452 | case MERGE_ERR_CANT_OPEN_INFILE: |
||
453 | fprintf(stderr, "mergecap: Can't open %s: %s (%s)\n", argv[optind + err_fileno], |
||
454 | wtap_strerror(err), err_info ? err_info : "no more information"); |
||
455 | break; |
||
456 | |||
457 | case MERGE_ERR_CANT_OPEN_OUTFILE: |
||
458 | fprintf(stderr, "mergecap: Can't open or create %s: %s\n", out_filename, |
||
459 | wtap_strerror(err)); |
||
460 | if (!use_stdout) |
||
461 | ws_close(out_fd); |
||
462 | break; |
||
463 | |||
464 | case MERGE_ERR_CANT_READ_INFILE: /* fall through */ |
||
465 | case MERGE_ERR_BAD_PHDR_INTERFACE_ID: |
||
466 | case MERGE_ERR_CANT_WRITE_OUTFILE: |
||
467 | case MERGE_ERR_CANT_CLOSE_OUTFILE: |
||
468 | default: |
||
469 | fprintf(stderr, "mergecap: %s\n", err_info ? err_info : "unknown error"); |
||
470 | break; |
||
471 | } |
||
472 | |||
473 | g_free(err_info); |
||
474 | |||
475 | return (status == MERGE_OK) ? 0 : 2; |
||
476 | } |
||
477 | |||
478 | /* |
||
479 | * Editor modelines - http://www.wireshark.org/tools/modelines.html |
||
480 | * |
||
481 | * Local variables: |
||
482 | * c-basic-offset: 2 |
||
483 | * tab-width: 8 |
||
484 | * indent-tabs-mode: nil |
||
485 | * End: |
||
486 | * |
||
487 | * vi: set shiftwidth=2 tabstop=8 expandtab: |
||
488 | * :indentSize=2:tabSize=8:noTabs=true: |
||
489 | */ |
||
490 |