From e4ba6dbc3f1e76890b22773807ea37fe8fa2b1bc Mon Sep 17 00:00:00 2001 From: Daniel Baumann Date: Wed, 10 Apr 2024 22:34:10 +0200 Subject: Adding upstream version 4.2.2. Signed-off-by: Daniel Baumann --- mergecap.c | 428 +++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++ 1 file changed, 428 insertions(+) create mode 100644 mergecap.c (limited to 'mergecap.c') diff --git a/mergecap.c b/mergecap.c new file mode 100644 index 0000000..41be4e2 --- /dev/null +++ b/mergecap.c @@ -0,0 +1,428 @@ +/* Combine dump files, either by appending or by merging by timestamp + * + * Wireshark - Network traffic analyzer + * By Gerald Combs + * Copyright 1998 Gerald Combs + * + * SPDX-License-Identifier: GPL-2.0-or-later + * + * Mergecap written by Scott Renfro based on + * editcap by Richard Sharpe and Guy Harris + * + */ + +#include +#define WS_LOG_DOMAIN LOG_DOMAIN_MAIN + +#include +#include +#include + +#include + +#include + +#include + +#include +#include +#include +#include +#include +#include +#include +#include + +#include +#include + +#ifdef HAVE_PLUGINS +#include +#endif + +#include + +#include + +#include "ui/failure_message.h" + +/* + * Show the usage + */ +static void +print_usage(FILE *output) +{ + fprintf(output, "\n"); + fprintf(output, "Usage: mergecap [options] -w |- [ ...]\n"); + fprintf(output, "\n"); + fprintf(output, "Output:\n"); + fprintf(output, " -a concatenate rather than merge files.\n"); + fprintf(output, " default is to merge based on frame timestamps.\n"); + fprintf(output, " -s truncate packets to bytes of data.\n"); + fprintf(output, " -w |- set the output filename to or '-' for stdout.\n"); + fprintf(output, " -F set the output file type; default is pcapng.\n"); + fprintf(output, " an empty \"-F\" option will list the file types.\n"); + fprintf(output, " -I set the merge mode for Interface Description Blocks; default is 'all'.\n"); + fprintf(output, " an empty \"-I\" option will list the merge modes.\n"); + fprintf(output, "\n"); + fprintf(output, "Miscellaneous:\n"); + fprintf(output, " -h, --help display this help and exit.\n"); + fprintf(output, " -V verbose output.\n"); + fprintf(output, " -v, --version print version information and exit.\n"); +} + +/* + * Report an error in command-line arguments. + */ +static void +mergecap_cmdarg_err(const char *fmt, va_list ap) +{ + fprintf(stderr, "mergecap: "); + vfprintf(stderr, fmt, ap); + fprintf(stderr, "\n"); +} + +/* + * Report additional information for an error in command-line arguments. + */ +static void +mergecap_cmdarg_err_cont(const char *fmt, va_list ap) +{ + vfprintf(stderr, fmt, ap); + fprintf(stderr, "\n"); +} + +static void +list_capture_types(void) { + GArray *writable_type_subtypes; + + fprintf(stderr, "mergecap: The available capture file types for the \"-F\" flag are:\n"); + writable_type_subtypes = wtap_get_writable_file_types_subtypes(FT_SORT_BY_NAME); + for (guint i = 0; i < writable_type_subtypes->len; i++) { + int ft = g_array_index(writable_type_subtypes, int, i); + fprintf(stderr, " %s - %s\n", wtap_file_type_subtype_name(ft), + wtap_file_type_subtype_description(ft)); + } + g_array_free(writable_type_subtypes, TRUE); +} + +static void +list_idb_merge_modes(void) { + int i; + + fprintf(stderr, "mergecap: The available IDB merge modes for the \"-I\" flag are:\n"); + for (i = 0; i < IDB_MERGE_MODE_MAX; i++) { + fprintf(stderr, " %s\n", merge_idb_merge_mode_to_string(i)); + } +} + +static gboolean +merge_callback(merge_event event, int num, + const merge_in_file_t in_files[], const guint in_file_count, + void *data _U_) +{ + guint i; + + switch (event) { + + case MERGE_EVENT_INPUT_FILES_OPENED: + for (i = 0; i < in_file_count; i++) { + fprintf(stderr, "mergecap: %s is type %s.\n", in_files[i].filename, + wtap_file_type_subtype_description(wtap_file_type_subtype(in_files[i].wth))); + } + break; + + case MERGE_EVENT_FRAME_TYPE_SELECTED: + /* for this event, num = frame_type */ + if (num == WTAP_ENCAP_PER_PACKET) { + /* + * Find out why we had to choose WTAP_ENCAP_PER_PACKET. + */ + int first_frame_type, this_frame_type; + + first_frame_type = wtap_file_encap(in_files[0].wth); + for (i = 1; i < in_file_count; i++) { + this_frame_type = wtap_file_encap(in_files[i].wth); + if (first_frame_type != this_frame_type) { + fprintf(stderr, "mergecap: multiple frame encapsulation types detected\n"); + fprintf(stderr, " defaulting to WTAP_ENCAP_PER_PACKET\n"); + fprintf(stderr, " %s had type %s (%s)\n", + in_files[0].filename, + wtap_encap_description(first_frame_type), + wtap_encap_name(first_frame_type)); + fprintf(stderr, " %s had type %s (%s)\n", + in_files[i].filename, + wtap_encap_description(this_frame_type), + wtap_encap_name(this_frame_type)); + break; + } + } + } + fprintf(stderr, "mergecap: selected frame_type %s (%s)\n", + wtap_encap_description(num), + wtap_encap_name(num)); + break; + + case MERGE_EVENT_READY_TO_MERGE: + fprintf(stderr, "mergecap: ready to merge records\n"); + break; + + case MERGE_EVENT_RECORD_WAS_READ: + /* for this event, num = count */ + fprintf(stderr, "Record: %d\n", num); + break; + + case MERGE_EVENT_DONE: + fprintf(stderr, "mergecap: merging complete\n"); + break; + } + + /* false = do not stop merging */ + return FALSE; +} + +int +main(int argc, char *argv[]) +{ + char *configuration_init_error; + static const struct report_message_routines mergecap_report_routines = { + failure_message, + failure_message, + open_failure_message, + read_failure_message, + write_failure_message, + cfile_open_failure_message, + cfile_dump_open_failure_message, + cfile_read_failure_message, + cfile_write_failure_message, + cfile_close_failure_message + }; + int opt; + static const struct ws_option long_options[] = { + {"help", ws_no_argument, NULL, 'h'}, + {"version", ws_no_argument, NULL, 'v'}, + {0, 0, 0, 0 } + }; + gboolean do_append = FALSE; + gboolean verbose = FALSE; + int in_file_count = 0; + guint32 snaplen = 0; + int file_type = WTAP_FILE_TYPE_SUBTYPE_UNKNOWN; + int err = 0; + gchar *err_info = NULL; + int err_fileno; + guint32 err_framenum; + char *out_filename = NULL; + merge_result status = MERGE_OK; + idb_merge_mode mode = IDB_MERGE_MODE_MAX; + merge_progress_callback_t cb; + + cmdarg_err_init(mergecap_cmdarg_err, mergecap_cmdarg_err_cont); + + /* Initialize log handler early so we can have proper logging during startup. */ + ws_log_init("mergecap", vcmdarg_err); + + /* Early logging command-line initialization. */ + ws_log_parse_args(&argc, argv, vcmdarg_err, 1); + + ws_noisy("Finished log init and parsing command line log arguments"); + +#ifdef _WIN32 + create_app_running_mutex(); +#endif /* _WIN32 */ + + /* Initialize the version information. */ + ws_init_version_info("Mergecap", NULL, NULL); + + /* + * Get credential information for later use. + */ + init_process_policies(); + + /* + * Attempt to get the pathname of the directory containing the + * executable file. + */ + configuration_init_error = configuration_init(argv[0], NULL); + if (configuration_init_error != NULL) { + fprintf(stderr, + "mergecap: Can't get pathname of directory containing the mergecap program: %s.\n", + configuration_init_error); + g_free(configuration_init_error); + } + + init_report_message("mergecap", &mergecap_report_routines); + + wtap_init(TRUE); + + /* Process the options first */ + while ((opt = ws_getopt_long(argc, argv, "aF:hI:s:vVw:", long_options, NULL)) != -1) { + + switch (opt) { + case 'a': + do_append = !do_append; + break; + + case 'F': + file_type = wtap_name_to_file_type_subtype(ws_optarg); + if (file_type < 0) { + fprintf(stderr, "mergecap: \"%s\" isn't a valid capture file type\n", + ws_optarg); + list_capture_types(); + status = MERGE_ERR_INVALID_OPTION; + goto clean_exit; + } + break; + + case 'h': + show_help_header("Merge two or more capture files into one."); + print_usage(stdout); + goto clean_exit; + break; + + case 'I': + mode = merge_string_to_idb_merge_mode(ws_optarg); + if (mode == IDB_MERGE_MODE_MAX) { + fprintf(stderr, "mergecap: \"%s\" isn't a valid IDB merge mode\n", + ws_optarg); + list_idb_merge_modes(); + status = MERGE_ERR_INVALID_OPTION; + goto clean_exit; + } + break; + + case 's': + snaplen = get_nonzero_guint32(ws_optarg, "snapshot length"); + break; + + case 'V': + verbose = TRUE; + break; + + case 'v': + show_version(); + goto clean_exit; + break; + + case 'w': + out_filename = ws_optarg; + break; + + case '?': /* Bad options if GNU getopt */ + switch(ws_optopt) { + case'F': + list_capture_types(); + break; + case'I': + list_idb_merge_modes(); + break; + default: + print_usage(stderr); + } + status = MERGE_ERR_INVALID_OPTION; + goto clean_exit; + break; + } + } + + /* Default to pcapng when writing. */ + if (file_type == WTAP_FILE_TYPE_SUBTYPE_UNKNOWN) + file_type = wtap_pcapng_file_type_subtype(); + + cb.callback_func = merge_callback; + cb.data = NULL; + + /* check for proper args; at a minimum, must have an output + * filename and one input file + */ + in_file_count = argc - ws_optind; + if (!out_filename) { + fprintf(stderr, "mergecap: an output filename must be set with -w\n"); + fprintf(stderr, " run with -h for help\n"); + status = MERGE_ERR_INVALID_OPTION; + goto clean_exit; + } + if (in_file_count < 1) { + fprintf(stderr, "mergecap: No input files were specified\n"); + return 1; + } + + /* + * Setting IDB merge mode must use a file format that supports + * (and thus requires) interface ID and information blocks. + */ + if (mode != IDB_MERGE_MODE_MAX && + wtap_file_type_subtype_supports_block(file_type, WTAP_BLOCK_IF_ID_AND_INFO) == BLOCK_NOT_SUPPORTED) { + fprintf(stderr, "The IDB merge mode can only be used with an output format that identifies interfaces\n"); + status = MERGE_ERR_INVALID_OPTION; + goto clean_exit; + } + + /* if they didn't set IDB merge mode, set it to our default */ + if (mode == IDB_MERGE_MODE_MAX) { + mode = IDB_MERGE_MODE_ALL_SAME; + } + + /* open the outfile */ + if (strcmp(out_filename, "-") == 0) { + /* merge the files to the standard output */ + status = merge_files_to_stdout(file_type, + (const char *const *) &argv[ws_optind], + in_file_count, do_append, mode, snaplen, + get_appname_and_version(), + verbose ? &cb : NULL, + &err, &err_info, &err_fileno, &err_framenum); + } else { + /* merge the files to the outfile */ + status = merge_files(out_filename, file_type, + (const char *const *) &argv[ws_optind], in_file_count, + do_append, mode, snaplen, get_appname_and_version(), + verbose ? &cb : NULL, + &err, &err_info, &err_fileno, &err_framenum); + } + + switch (status) { + case MERGE_OK: + break; + + case MERGE_USER_ABORTED: + /* we don't catch SIGINT/SIGTERM (yet?), so we couldn't have aborted */ + ws_assert_not_reached(); + break; + + case MERGE_ERR_CANT_OPEN_INFILE: + cfile_open_failure_message(argv[ws_optind + err_fileno], err, err_info); + break; + + case MERGE_ERR_CANT_OPEN_OUTFILE: + cfile_dump_open_failure_message(out_filename, err, err_info, file_type); + break; + + case MERGE_ERR_CANT_READ_INFILE: + cfile_read_failure_message(argv[ws_optind + err_fileno], err, err_info); + break; + + case MERGE_ERR_BAD_PHDR_INTERFACE_ID: + cmdarg_err("Record %u of \"%s\" has an interface ID that does not match any IDB in its file.", + err_framenum, argv[ws_optind + err_fileno]); + break; + + case MERGE_ERR_CANT_WRITE_OUTFILE: + cfile_write_failure_message(argv[ws_optind + err_fileno], out_filename, + err, err_info, err_framenum, file_type); + break; + + case MERGE_ERR_CANT_CLOSE_OUTFILE: + cfile_close_failure_message(out_filename, err, err_info); + break; + + default: + cmdarg_err("Unknown merge_files error %d", status); + break; + } + +clean_exit: + wtap_cleanup(); + free_progdirs(); + return (status == MERGE_OK) ? 0 : 2; +} -- cgit v1.2.3