From 69df23fc40951556d2f9f303944f943547c31ac0 Mon Sep 17 00:00:00 2001 From: Paul Offord Date: Mon, 8 Feb 2021 10:27:18 +0000 Subject: [PATCH] sharkd: Add configuration profile and other options This change adds code to allow the selection of a configuration profile during sharkd start by adding a -C command line option. A new -a option has been added to specify the api service endpoint e.g. tcp:127.0.0.1:4446 The change also adds version display (-v) and help display (-h) options. These additions have been made in a way to ensure that the original command line options still work correctly to maintain backward compatibility. The new options have been added using the getopt_long(...) function that is used by tshark to simplify the addition of further command line options. Closes #17222 --- sharkd.c | 2 +- sharkd.h | 9 +- sharkd_daemon.c | 233 ++++++++++++++++++++++++++++++++++++++++------- sharkd_session.c | 7 +- 4 files changed, 215 insertions(+), 36 deletions(-) diff --git a/sharkd.c b/sharkd.c index 467e3c330a..91ca5892e6 100644 --- a/sharkd.c +++ b/sharkd.c @@ -187,7 +187,7 @@ main(int argc, char *argv[]) uat_clear(uat_get_table_by_name("MaxMind Database Paths")); #endif - ret = sharkd_loop(); + ret = sharkd_loop(argc, argv); clean_exit: col_cleanup(&cfile.cinfo); free_filter_lists(); diff --git a/sharkd.h b/sharkd.h index cac4018104..3c45f8330c 100644 --- a/sharkd.h +++ b/sharkd.h @@ -20,6 +20,11 @@ #define SHARKD_DISSECT_FLAG_PROTO_TREE 0x04u #define SHARKD_DISSECT_FLAG_COLOR 0x08u +#define SHARKD_MODE_CLASSIC_CONSOLE 1 +#define SHARKD_MODE_CLASSIC_DAEMON 2 +#define SHARKD_MODE_GOLD_CONSOLE 3 +#define SHARKD_MODE_GOLD_DAEMON 4 + typedef void (*sharkd_dissect_func_t)(epan_dissect_t *edt, proto_tree *tree, struct epan_column_info *cinfo, const GSList *data_src, void *data); /* sharkd.c */ @@ -36,10 +41,10 @@ const char *sharkd_version(void); /* sharkd_daemon.c */ int sharkd_init(int argc, char **argv); -int sharkd_loop(void); +int sharkd_loop(int argc _U_, char* argv[] _U_); /* sharkd_session.c */ -int sharkd_session_main(void); +int sharkd_session_main(int mode_setting); #endif /* __SHARKD_H */ diff --git a/sharkd_daemon.c b/sharkd_daemon.c index a50d50a7c6..57ad3aecfd 100644 --- a/sharkd_daemon.c +++ b/sharkd_daemon.c @@ -19,19 +19,16 @@ #include #include -#ifdef HAVE_UNISTD_H -#include -#endif - #ifdef _WIN32 #include -#include #include #endif +#include #include #include #include +#include #ifndef _WIN32 #include @@ -39,6 +36,7 @@ #endif #include +#include #include "sharkd.h" @@ -50,7 +48,7 @@ # define SHARKD_UNIX_SUPPORT #endif -static int _use_stdinout = 0; +static int mode = 0; static socket_handle_t _server_fd = INVALID_SOCKET; static socket_handle_t @@ -157,47 +155,186 @@ socket_init(char *path) return fd; } +static void +print_usage(FILE* output) +{ + fprintf(output, "\n"); + fprintf(output, "Usage: sharkd [|]\n"); + + fprintf(output, "\n"); + fprintf(output, "Classic (classic_options):\n"); + fprintf(output, " [-|]\n"); + fprintf(output, "\n"); + fprintf(output, " examples:\n"); +#ifdef SHARKD_UNIX_SUPPORT + fprintf(output, " - unix:/tmp/sharkd.sock - listen on unix file /tmp/sharkd.sock\n"); +#endif +#ifdef SHARKD_TCP_SUPPORT + fprintf(output, " - tcp:127.0.0.1:4446 - listen on TCP port 4446\n"); +#endif + + fprintf(output, "\n"); + fprintf(output, "Gold (gold_options):\n"); + fprintf(output, " -a , --api \n"); + fprintf(output, " listen on this socket\n"); + fprintf(output, " -h, --help show this help information\n"); + fprintf(output, " -v, --version show version information\n"); + fprintf(output, " -C , --config-profile \n"); + fprintf(output, " start with specified configuration profile\n"); + + fprintf(output, "\n"); + fprintf(output, " Examples:\n"); + fprintf(output, " sharkd -C myprofile\n"); + fprintf(output, " sharkd -a tcp:127.0.0.1:4446 -C myprofile\n"); + + fprintf(output, "\n"); + fprintf(output, "See the sharkd page of the Wireshark wiki for full details.\n"); + fprintf(output, "\n"); +} + int sharkd_init(int argc, char **argv) { + /* + * The leading + ensures that getopt_long() does not permute the argv[] + * entries. + * + * We have to make sure that the first getopt_long() preserves the content + * of argv[] for the subsequent getopt_long() call. + * + * We use getopt_long() in both cases to ensure that we're using a routine + * whose permutation behavior we can control in the same fashion on all + * platforms, and so that, if we ever need to process a long argument before + * doing further initialization, we can do so. + * + * Glibc and Solaris libc document that a leading + disables permutation + * of options, regardless of whether POSIXLY_CORRECT is set or not; *BSD + * and macOS don't document it, but do so anyway. + * + * We do *not* use a leading - because the behavior of a leading - is + * platform-dependent. + */ + +#define OPTSTRING "+" "a:hmvC:" + + static const char optstring[] = OPTSTRING; + + // right now we don't have any long options + static const struct option long_options[] = { + {"api", required_argument, NULL, 'a'}, + {"help", no_argument, NULL, 'h'}, + {"version", no_argument, NULL, 'v'}, + {"config-profile", required_argument, NULL, 'C'}, + {0, 0, 0, 0 } + }; + + int opt; + #ifndef _WIN32 pid_t pid; #endif socket_handle_t fd; - if (argc != 2) + if (argc < 2) { - fprintf(stderr, "Usage: %s <-|socket>\n", argv[0]); - fprintf(stderr, "\n"); - - fprintf(stderr, " examples:\n"); -#ifdef SHARKD_UNIX_SUPPORT - fprintf(stderr, " - unix:/tmp/sharkd.sock - listen on unix file /tmp/sharkd.sock\n"); -#endif -#ifdef SHARKD_TCP_SUPPORT - fprintf(stderr, " - tcp:127.0.0.1:4446 - listen on TCP port 4446\n"); -#endif - fprintf(stderr, "\n"); + print_usage(stderr); return -1; } + // check for classic command line + if (!strcmp(argv[1], "-") || argv[1][0] == 't' || argv[1][0] == 'u') + { + mode = SHARKD_MODE_CLASSIC_CONSOLE; + #ifndef _WIN32 - signal(SIGCHLD, SIG_IGN); + signal(SIGCHLD, SIG_IGN); #endif - if (!strcmp(argv[1], "-")) - { - _use_stdinout = 1; + if (!strcmp(argv[1], "-")) + { + mode = SHARKD_MODE_CLASSIC_CONSOLE; + } + else + { + fd = socket_init(argv[1]); + if (fd == INVALID_SOCKET) + return -1; + _server_fd = fd; + mode = SHARKD_MODE_CLASSIC_DAEMON; + } } else + mode = SHARKD_MODE_GOLD_CONSOLE; // assume we are running as gold console + + if (mode >= SHARKD_MODE_GOLD_CONSOLE) { - fd = socket_init(argv[1]); - if (fd == INVALID_SOCKET) - return -1; - _server_fd = fd; + /* + In Daemon Mode, we will come through here twice; once when we start the Daemon and + once again after we have forked the session process. The second time through, the + session process has already had its stdin and stdout wired up to the TCP or UNIX + socket and so in the orignal version of sharkd the session process is invoked with + the command line: sharkd - + + When not using the classic command line, we want to spawn the session process with + the complete command line with all the new options but with the -a option and + parameter removed. Invoking a second time with the -a option will cause a loop + where we repeatedly spawn a new session process. + */ + + do { + if (optind > (argc - 1)) + break; + + opt = getopt_long(argc, argv, optstring, long_options, NULL); + + switch (opt) { + case 'C': /* Configuration Profile */ + if (profile_exists(optarg, FALSE)) { + set_profile_name(optarg); // In Daemon Mode, we may need to do this again in the child process + } + else { + fprintf(stderr, "Configuration Profile \"%s\" does not exist\n", optarg); + return -1; + } + break; + + case 'a': + fd = socket_init(optarg); + if (fd == INVALID_SOCKET) + return -1; + _server_fd = fd; + + fprintf(stderr, "Sharkd listening on: %s\n", optarg); + + mode = SHARKD_MODE_GOLD_DAEMON; + break; + + case 'h': + print_usage(stderr); + exit(0); + break; + + case 'm': + // m is an internal-only option used when the daemon session process is created + mode = SHARKD_MODE_GOLD_CONSOLE; + break; + + case 'v': /* Show version and exit */ + show_version(); + exit(0); + break; + + default: + if (!optopt) + fprintf(stderr, "This option isn't supported: %s\n", argv[optind]); + fprintf(stderr, "Use sharkd -h for details of supported options\n"); + exit(0); + break; + } + } while (opt != -1); } - if (!_use_stdinout) + if (mode == SHARKD_MODE_CLASSIC_DAEMON || mode == SHARKD_MODE_GOLD_DAEMON) { /* all good - try to daemonize */ #ifndef _WIN32 @@ -217,11 +354,11 @@ sharkd_init(int argc, char **argv) } int -sharkd_loop(void) +sharkd_loop(int argc _U_, char* argv[]) { - if (_use_stdinout) + if (mode == SHARKD_MODE_CLASSIC_CONSOLE || mode == SHARKD_MODE_GOLD_CONSOLE) { - return sharkd_session_main(); + return sharkd_session_main(mode); } while (1) @@ -232,6 +369,7 @@ sharkd_loop(void) PROCESS_INFORMATION pi; STARTUPINFO si; char *exename; + char command_line[2048]; #endif socket_handle_t fd; @@ -253,7 +391,7 @@ sharkd_loop(void) dup2(fd, 1); close(fd); - exit(sharkd_session_main()); + exit(sharkd_session_main(mode)); } if (pid == -1) @@ -273,7 +411,38 @@ sharkd_loop(void) exename = g_strdup_printf("%s\\%s", get_progfile_dir(), "sharkd.exe"); - if (!win32_create_process(exename, "sharkd.exe -", NULL, NULL, TRUE, 0, NULL, NULL, &si, &pi)) + // we need to pass in all of the command line parameters except the -a parameter + // passing in -a at this point would could a loop, each iteration of which would generate a new session process + memset(&command_line, 0, sizeof(command_line)); + + if (mode <= SHARKD_MODE_CLASSIC_DAEMON) + { + g_strlcat(command_line, "sharkd.exe -", sizeof(command_line)); + } + else + { + // The -m option used here is an internal-only option that notifies the child process that it should + // run in Gold Console mode + g_strlcat(command_line, "sharkd.exe -m", sizeof(command_line)); + + for (size_t i = 1; i < argc; i++) + { + if ( + !g_ascii_strncasecmp(argv[i], "-a", (guint)strlen(argv[i])) + || !g_ascii_strncasecmp(argv[i], "--api", (guint)strlen(argv[i])) + ) + { + i++; // skip the socket details + } + else + { + g_strlcat(command_line, " ", sizeof(command_line)); + g_strlcat(command_line, argv[i], sizeof(command_line)); + } + } + } + + if (!win32_create_process(exename, command_line, NULL, NULL, TRUE, 0, NULL, NULL, &si, &pi)) { fprintf(stderr, "win32_create_process(%s) failed\n", exename); } diff --git a/sharkd_session.c b/sharkd_session.c index dfb7945e1e..653bcdf840 100644 --- a/sharkd_session.c +++ b/sharkd_session.c @@ -80,6 +80,9 @@ struct sharkd_filter_item static GHashTable *filter_table = NULL; +static int mode; +gboolean extended_log = FALSE; + static json_dumper dumper = {0}; static const char * @@ -4251,12 +4254,14 @@ sharkd_session_process(char *buf, const jsmntok_t *tokens, int count) } int -sharkd_session_main(void) +sharkd_session_main(int mode_setting) { char buf[2 * 1024]; jsmntok_t *tokens = NULL; int tokens_max = -1; + mode = mode_setting; + fprintf(stderr, "Hello in child.\n"); dumper.output_file = stdout;