diff --git a/src/Options.cc b/src/Options.cc index 5c43b13477..6143657967 100644 --- a/src/Options.cc +++ b/src/Options.cc @@ -1,5 +1,16 @@ // See the file "COPYING" in the main distribution directory for copyright. +#include + +#include "zeek-config.h" + +#ifdef HAVE_GETOPT_H +#include +#endif + +#include "bsd-getopt-long.h" +#include "logging/writers/ascii/Ascii.h" + #include "Options.h" void zeek::Options::filter_supervisor_options() @@ -50,3 +61,400 @@ void zeek::Options::filter_supervised_node_options() scripts_to_load = og.scripts_to_load; script_options_to_set = og.script_options_to_set; } + +bool zeek::fake_dns() + { + return zeekenv("ZEEK_DNS_FAKE"); + } + +extern const char* zeek_version(); + +void zeek::usage(const char* prog, int code) + { + fprintf(stderr, "zeek version %s\n", zeek_version()); + + fprintf(stderr, "usage: %s [options] [file ...]\n", prog); + fprintf(stderr, "usage: %s --test [doctest-options] -- [options] [file ...]\n", prog); + fprintf(stderr, " | Zeek script file, or read stdin\n"); + fprintf(stderr, " -a|--parse-only | exit immediately after parsing scripts\n"); + fprintf(stderr, " -b|--bare-mode | don't load scripts from the base/ directory\n"); + fprintf(stderr, " -d|--debug-script | activate Zeek script debugging\n"); + fprintf(stderr, " -e|--exec | augment loaded scripts by given code\n"); + fprintf(stderr, " -f|--filter | tcpdump filter\n"); + fprintf(stderr, " -h|--help | command line help\n"); + fprintf(stderr, " -i|--iface | read from given interface\n"); + fprintf(stderr, " -p|--prefix | add given prefix to Zeek script file resolution\n"); + fprintf(stderr, " -r|--readfile | read from given tcpdump file\n"); + fprintf(stderr, " -s|--rulefile | read rules from given file\n"); + fprintf(stderr, " -t|--tracefile | activate execution tracing\n"); + fprintf(stderr, " -v|--version | print version and exit\n"); + fprintf(stderr, " -w|--writefile | write to given tcpdump file\n"); +#ifdef DEBUG + fprintf(stderr, " -B|--debug | Enable debugging output for selected streams ('-B help' for help)\n"); +#endif + fprintf(stderr, " -C|--no-checksums | ignore checksums\n"); + fprintf(stderr, " -F|--force-dns | force DNS\n"); + fprintf(stderr, " -G|--load-seeds | load seeds from given file\n"); + fprintf(stderr, " -H|--save-seeds | save seeds to given file\n"); + fprintf(stderr, " -I|--print-id | print out given ID\n"); + fprintf(stderr, " -N|--print-plugins | print available plugins and exit (-NN for verbose)\n"); + fprintf(stderr, " -P|--prime-dns | prime DNS\n"); + fprintf(stderr, " -Q|--time | print execution time summary to stderr\n"); + fprintf(stderr, " -S|--debug-rules | enable rule debugging\n"); + fprintf(stderr, " -T|--re-level | set 'RE_level' for rules\n"); + fprintf(stderr, " -U|--status-file | Record process status in file\n"); + fprintf(stderr, " -W|--watchdog | activate watchdog timer\n"); + fprintf(stderr, " -X|--zeekygen | generate documentation based on config file\n"); + +#ifdef USE_PERFTOOLS_DEBUG + fprintf(stderr, " -m|--mem-leaks | show leaks [perftools]\n"); + fprintf(stderr, " -M|--mem-profile | record heap [perftools]\n"); +#endif + fprintf(stderr, " --pseudo-realtime[=] | enable pseudo-realtime for performance evaluation (default 1)\n"); + fprintf(stderr, " -j|--jobs | enable supervisor mode\n"); + +#ifdef USE_IDMEF + fprintf(stderr, " -n|--idmef-dtd | specify path to IDMEF DTD file\n"); +#endif + + fprintf(stderr, " --test | run unit tests ('--test -h' for help, only when compiling with ENABLE_ZEEK_UNIT_TESTS)\n"); + fprintf(stderr, " $ZEEKPATH | file search path (%s)\n", bro_path().c_str()); + fprintf(stderr, " $ZEEK_PLUGIN_PATH | plugin search path (%s)\n", bro_plugin_path()); + fprintf(stderr, " $ZEEK_PLUGIN_ACTIVATE | plugins to always activate (%s)\n", bro_plugin_activate()); + fprintf(stderr, " $ZEEK_PREFIXES | prefix list (%s)\n", bro_prefixes().c_str()); + fprintf(stderr, " $ZEEK_DNS_FAKE | disable DNS lookups (%s)\n", zeek::fake_dns() ? "on" : "off"); + fprintf(stderr, " $ZEEK_SEED_FILE | file to load seeds from (not set)\n"); + fprintf(stderr, " $ZEEK_LOG_SUFFIX | ASCII log file extension (.%s)\n", logging::writer::Ascii::LogExt().c_str()); + fprintf(stderr, " $ZEEK_PROFILER_FILE | Output file for script execution statistics (not set)\n"); + fprintf(stderr, " $ZEEK_DISABLE_ZEEKYGEN | Disable Zeekygen documentation support (%s)\n", zeekenv("ZEEK_DISABLE_ZEEKYGEN") ? "set" : "not set"); + fprintf(stderr, " $ZEEK_DNS_RESOLVER | IPv4/IPv6 address of DNS resolver to use (%s)\n", zeekenv("ZEEK_DNS_RESOLVER") ? zeekenv("ZEEK_DNS_RESOLVER") : "not set, will use first IPv4 address from /etc/resolv.conf"); + fprintf(stderr, " $ZEEK_DEBUG_LOG_STDERR | Use stderr for debug logs generated via the -B flag"); + + fprintf(stderr, "\n"); + + exit(code); + } + +zeek::Options zeek::parse_cmdline(int argc, char** argv) + { + zeek::Options rval; + + // When running unit tests, the first argument on the command line must be + // --test, followed by doctest options. Optionally, users can use "--" as + // separator to pass Zeek options afterwards: + // + // zeek --test [doctest-options] -- [zeek-options] + + // Just locally filtering out the args for Zeek usage from doctest args. + std::vector zeek_args; + + if ( argc > 1 && strcmp(argv[1], "--test") == 0 ) + { + #ifdef DOCTEST_CONFIG_DISABLE + fprintf(stderr, "ERROR: C++ unit tests are disabled for this build.\n" + " Please re-compile with ENABLE_ZEEK_UNIT_TESTS " + "to run the C++ unit tests.\n"); + usage(argv[0], 1); + #endif + + auto is_separator = [](const char* cstr) + { + return strcmp(cstr, "--") == 0; + }; + auto first = argv; + auto last = argv + argc; + auto separator = std::find_if(first, last, is_separator); + zeek_args.emplace_back(argv[0]); + + if ( separator != last ) + { + auto first_zeek_arg = std::next(separator); + + for ( auto i = first_zeek_arg; i != last; ++i ) + zeek_args.emplace_back(*i); + } + + rval.run_unit_tests = true; + + for ( auto i = 0; i < std::distance(first, separator); ++i ) + rval.doctest_args.emplace_back(argv[i]); + } + else + { + for ( auto i = 0; i < argc; ++i ) + zeek_args.emplace_back(argv[i]); + } + + constexpr struct option long_opts[] = { + {"parse-only", no_argument, 0, 'a'}, + {"bare-mode", no_argument, 0, 'b'}, + {"debug-script", no_argument, 0, 'd'}, + {"exec", required_argument, 0, 'e'}, + {"filter", required_argument, 0, 'f'}, + {"help", no_argument, 0, 'h'}, + {"iface", required_argument, 0, 'i'}, + {"zeekygen", required_argument, 0, 'X'}, + {"prefix", required_argument, 0, 'p'}, + {"readfile", required_argument, 0, 'r'}, + {"rulefile", required_argument, 0, 's'}, + {"tracefile", required_argument, 0, 't'}, + {"writefile", required_argument, 0, 'w'}, + {"version", no_argument, 0, 'v'}, + {"no-checksums", no_argument, 0, 'C'}, + {"force-dns", no_argument, 0, 'F'}, + {"load-seeds", required_argument, 0, 'G'}, + {"save-seeds", required_argument, 0, 'H'}, + {"print-plugins", no_argument, 0, 'N'}, + {"prime-dns", no_argument, 0, 'P'}, + {"time", no_argument, 0, 'Q'}, + {"debug-rules", no_argument, 0, 'S'}, + {"re-level", required_argument, 0, 'T'}, + {"watchdog", no_argument, 0, 'W'}, + {"print-id", required_argument, 0, 'I'}, + {"status-file", required_argument, 0, 'U'}, + +#ifdef DEBUG + {"debug", required_argument, 0, 'B'}, +#endif +#ifdef USE_IDMEF + {"idmef-dtd", required_argument, 0, 'n'}, +#endif +#ifdef USE_PERFTOOLS_DEBUG + {"mem-leaks", no_argument, 0, 'm'}, + {"mem-profile", no_argument, 0, 'M'}, +#endif + + {"pseudo-realtime", optional_argument, 0, 'E'}, + {"jobs", optional_argument, 0, 'j'}, + {"test", no_argument, 0, '#'}, + + {0, 0, 0, 0}, + }; + + char opts[256]; + safe_strncpy(opts, "B:e:f:G:H:I:i:j::n:p:r:s:T:t:U:w:X:CFNPQSWabdhv", + sizeof(opts)); + +#ifdef USE_PERFTOOLS_DEBUG + strncat(opts, "mM", 2); +#endif + + int op; + int long_optsind; + opterr = 0; + + // getopt may permute the array, so need yet another array + auto zargs = std::make_unique(zeek_args.size()); + + for ( auto i = 0u; i < zeek_args.size(); ++i ) + zargs[i] = zeek_args[i].data(); + + while ( (op = getopt_long(zeek_args.size(), zargs.get(), opts, long_opts, &long_optsind)) != EOF ) + switch ( op ) { + case 'a': + rval.parse_only = true; + break; + case 'b': + rval.bare_mode = true; + break; + case 'd': + rval.debug_scripts = true; + break; + case 'e': + rval.script_code_to_exec = optarg; + break; + case 'f': + rval.pcap_filter = optarg; + break; + case 'h': + rval.print_usage = true; + break; + case 'i': + if ( ! rval.pcap_files.empty() ) + { + fprintf(stderr, "Using -i is not allowed when reading pcap files"); + exit(1); + } + rval.interfaces.emplace_back(optarg); + break; + case 'j': + rval.supervisor_mode = true; + if ( optarg ) + { + // TODO: for supervised offline pcap reading, the argument is + // expected to be number of workers like "-j 4" or possibly a + // list of worker/proxy/logger counts like "-j 4,2,1" + } + break; + case 'p': + rval.script_prefixes.emplace_back(optarg); + break; + case 'r': + if ( ! rval.interfaces.empty() ) + { + fprintf(stderr, "Using -r is not allowed when reading a live interface"); + exit(1); + } + rval.pcap_files.emplace_back(optarg); + break; + case 's': + rval.signature_files.emplace_back(optarg); + break; + case 't': + rval.debug_script_tracing_file = optarg; + break; + case 'v': + rval.print_version = true; + break; + case 'w': + rval.pcap_output_file = optarg; + break; + case 'B': + rval.debug_log_streams = optarg; + break; + case 'C': + rval.ignore_checksums = true; + break; + case 'E': + rval.pseudo_realtime = 1.0; + if ( optarg ) + rval.pseudo_realtime = atof(optarg); + break; + case 'F': + if ( rval.dns_mode != DNS_DEFAULT ) + usage(zargs[0], 1); + rval.dns_mode = DNS_FORCE; + break; + case 'G': + rval.random_seed_input_file = optarg; + break; + case 'H': + rval.random_seed_output_file = optarg; + break; + case 'I': + rval.identifier_to_print = optarg; + break; + case 'N': + ++rval.print_plugins; + break; + case 'P': + if ( rval.dns_mode != DNS_DEFAULT ) + usage(zargs[0], 1); + rval.dns_mode = DNS_PRIME; + break; + case 'Q': + rval.print_execution_time = true; + break; + case 'S': + rval.print_signature_debug_info = true; + break; + case 'T': + rval.signature_re_level = atoi(optarg); + break; + case 'U': + rval.process_status_file = optarg; + break; + case 'W': + rval.use_watchdog = true; + break; + case 'X': + rval.zeekygen_config_file = optarg; + break; + +#ifdef USE_PERFTOOLS_DEBUG + case 'm': + rval.perftools_check_leaks = 1; + break; + case 'M': + rval.perftools_profile = 1; + break; +#endif + +#ifdef USE_IDMEF + case 'n': + rval.libidmef_dtd_path = optarg; + break; +#endif + + case '#': + fprintf(stderr, "ERROR: --test only allowed as first argument.\n"); + usage(zargs[0], 1); + break; + + case 0: + // This happens for long options that don't have + // a short-option equivalent. + break; + + case '?': + default: + usage(zargs[0], 1); + break; + } + + // Process remaining arguments. X=Y arguments indicate script + // variable/parameter assignments. X::Y arguments indicate plugins to + // activate/query. The remainder are treated as scripts to load. + while ( optind < static_cast(zeek_args.size()) ) + { + if ( strchr(zargs[optind], '=') ) + rval.script_options_to_set.emplace_back(zargs[optind++]); + else if ( strstr(zargs[optind], "::") ) + rval.plugins_to_load.emplace(zargs[optind++]); + else + rval.scripts_to_load.emplace_back(zargs[optind++]); + } + + auto canonify_script_path = [](std::string* path) + { + if ( path->empty() ) + return; + + *path = normalize_path(*path); + + if ( (*path)[0] == '/' || (*path)[0] == '~' ) + // Absolute path + return; + + if ( (*path)[0] != '.' ) + { + // Look up file in ZEEKPATH + auto res = find_script_file(*path, bro_path()); + + if ( res.empty() ) + { + fprintf(stderr, "failed to locate script: %s\n", path->data()); + exit(1); + } + + *path = res; + + if ( (*path)[0] == '/' || (*path)[0] == '~' ) + // Now an absolute path + return; + } + + // Need to translate relative path to absolute. + char cwd[PATH_MAX]; + + if ( ! getcwd(cwd, sizeof(cwd)) ) + { + fprintf(stderr, "failed to get current directory: %s\n", + strerror(errno)); + exit(1); + } + + *path = std::string(cwd) + "/" + *path; + }; + + if ( rval.supervisor_mode ) + { + // Translate any relative paths supplied to supervisor into absolute + // paths for use by supervised nodes since they have the option to + // operate out of a different working directory. + for ( auto& s : rval.scripts_to_load ) + canonify_script_path(&s); + } + + return rval; + } diff --git a/src/Options.h b/src/Options.h index 72d0389c74..01711481d9 100644 --- a/src/Options.h +++ b/src/Options.h @@ -74,4 +74,24 @@ struct Options { std::vector script_options_to_set; }; +/** + * Parse Zeek command-line arguments. + * @param argc argument count (same semantics as arguments to main()) + * @param argv argument strings (same semantics as arguments to main()) + * @return the parsed command-line options + */ +zeek::Options parse_cmdline(int argc, char** argv); + +/** + * Print command-line Zeek usage information and exit. + * @param prog the name/path of the Zeek command-line invocation + * @code the exit code to use + */ +void usage(const char* prog, int code = 1); + +/** + * @return true if zeek is running a "fake" DNS resolver, else false. + */ +bool fake_dns(); + } // namespace zeek diff --git a/src/main.cc b/src/main.cc index 98661df2ea..46618108c1 100644 --- a/src/main.cc +++ b/src/main.cc @@ -10,9 +10,6 @@ #include #include #include -#ifdef HAVE_GETOPT_H -#include -#endif #ifdef USE_IDMEF extern "C" { @@ -24,7 +21,6 @@ extern "C" { #include #include "Options.h" -#include "bsd-getopt-long.h" #include "input.h" #include "DNS_Mgr.h" #include "Frame.h" @@ -50,7 +46,6 @@ extern "C" { #include "threading/Manager.h" #include "input/Manager.h" #include "logging/Manager.h" -#include "logging/writers/ascii/Ascii.h" #include "input/readers/raw/Raw.h" #include "analyzer/Manager.h" #include "analyzer/Tag.h" @@ -148,77 +143,6 @@ const char* zeek_version() #endif } -static bool zeek_dns_fake() - { - return zeekenv("ZEEK_DNS_FAKE"); - } - -static void usage(const char* prog, int code = 1) - { - fprintf(stderr, "zeek version %s\n", zeek_version()); - - fprintf(stderr, "usage: %s [options] [file ...]\n", prog); - fprintf(stderr, "usage: %s --test [doctest-options] -- [options] [file ...]\n", prog); - fprintf(stderr, " | Zeek script file, or read stdin\n"); - fprintf(stderr, " -a|--parse-only | exit immediately after parsing scripts\n"); - fprintf(stderr, " -b|--bare-mode | don't load scripts from the base/ directory\n"); - fprintf(stderr, " -d|--debug-script | activate Zeek script debugging\n"); - fprintf(stderr, " -e|--exec | augment loaded scripts by given code\n"); - fprintf(stderr, " -f|--filter | tcpdump filter\n"); - fprintf(stderr, " -h|--help | command line help\n"); - fprintf(stderr, " -i|--iface | read from given interface\n"); - fprintf(stderr, " -p|--prefix | add given prefix to Zeek script file resolution\n"); - fprintf(stderr, " -r|--readfile | read from given tcpdump file\n"); - fprintf(stderr, " -s|--rulefile | read rules from given file\n"); - fprintf(stderr, " -t|--tracefile | activate execution tracing\n"); - fprintf(stderr, " -v|--version | print version and exit\n"); - fprintf(stderr, " -w|--writefile | write to given tcpdump file\n"); -#ifdef DEBUG - fprintf(stderr, " -B|--debug | Enable debugging output for selected streams ('-B help' for help)\n"); -#endif - fprintf(stderr, " -C|--no-checksums | ignore checksums\n"); - fprintf(stderr, " -F|--force-dns | force DNS\n"); - fprintf(stderr, " -G|--load-seeds | load seeds from given file\n"); - fprintf(stderr, " -H|--save-seeds | save seeds to given file\n"); - fprintf(stderr, " -I|--print-id | print out given ID\n"); - fprintf(stderr, " -N|--print-plugins | print available plugins and exit (-NN for verbose)\n"); - fprintf(stderr, " -P|--prime-dns | prime DNS\n"); - fprintf(stderr, " -Q|--time | print execution time summary to stderr\n"); - fprintf(stderr, " -S|--debug-rules | enable rule debugging\n"); - fprintf(stderr, " -T|--re-level | set 'RE_level' for rules\n"); - fprintf(stderr, " -U|--status-file | Record process status in file\n"); - fprintf(stderr, " -W|--watchdog | activate watchdog timer\n"); - fprintf(stderr, " -X|--zeekygen | generate documentation based on config file\n"); - -#ifdef USE_PERFTOOLS_DEBUG - fprintf(stderr, " -m|--mem-leaks | show leaks [perftools]\n"); - fprintf(stderr, " -M|--mem-profile | record heap [perftools]\n"); -#endif - fprintf(stderr, " --pseudo-realtime[=] | enable pseudo-realtime for performance evaluation (default 1)\n"); - fprintf(stderr, " -j|--jobs | enable supervisor mode\n"); - -#ifdef USE_IDMEF - fprintf(stderr, " -n|--idmef-dtd | specify path to IDMEF DTD file\n"); -#endif - - fprintf(stderr, " --test | run unit tests ('--test -h' for help, only when compiling with ENABLE_ZEEK_UNIT_TESTS)\n"); - fprintf(stderr, " $ZEEKPATH | file search path (%s)\n", bro_path().c_str()); - fprintf(stderr, " $ZEEK_PLUGIN_PATH | plugin search path (%s)\n", bro_plugin_path()); - fprintf(stderr, " $ZEEK_PLUGIN_ACTIVATE | plugins to always activate (%s)\n", bro_plugin_activate()); - fprintf(stderr, " $ZEEK_PREFIXES | prefix list (%s)\n", bro_prefixes().c_str()); - fprintf(stderr, " $ZEEK_DNS_FAKE | disable DNS lookups (%s)\n", zeek_dns_fake() ? "on" : "off"); - fprintf(stderr, " $ZEEK_SEED_FILE | file to load seeds from (not set)\n"); - fprintf(stderr, " $ZEEK_LOG_SUFFIX | ASCII log file extension (.%s)\n", logging::writer::Ascii::LogExt().c_str()); - fprintf(stderr, " $ZEEK_PROFILER_FILE | Output file for script execution statistics (not set)\n"); - fprintf(stderr, " $ZEEK_DISABLE_ZEEKYGEN | Disable Zeekygen documentation support (%s)\n", zeekenv("ZEEK_DISABLE_ZEEKYGEN") ? "set" : "not set"); - fprintf(stderr, " $ZEEK_DNS_RESOLVER | IPv4/IPv6 address of DNS resolver to use (%s)\n", zeekenv("ZEEK_DNS_RESOLVER") ? zeekenv("ZEEK_DNS_RESOLVER") : "not set, will use first IPv4 address from /etc/resolv.conf"); - fprintf(stderr, " $ZEEK_DEBUG_LOG_STDERR | Use stderr for debug logs generated via the -B flag"); - - fprintf(stderr, "\n"); - - exit(code); - } - static std::vector to_cargs(const std::vector& args) { std::vector rval; @@ -230,330 +154,6 @@ static std::vector to_cargs(const std::vector& args) return rval; } -static zeek::Options parse_cmdline(int argc, char** argv) - { - zeek::Options rval; - - // When running unit tests, the first argument on the command line must be - // --test, followed by doctest options. Optionally, users can use "--" as - // separator to pass Zeek options afterwards: - // - // zeek --test [doctest-options] -- [zeek-options] - - // Just locally filtering out the args for Zeek usage from doctest args. - std::vector zeek_args; - - if ( argc > 1 && strcmp(argv[1], "--test") == 0 ) - { - #ifdef DOCTEST_CONFIG_DISABLE - fprintf(stderr, "ERROR: C++ unit tests are disabled for this build.\n" - " Please re-compile with ENABLE_ZEEK_UNIT_TESTS " - "to run the C++ unit tests.\n"); - usage(argv[0], 1); - #endif - - auto is_separator = [](const char* cstr) - { - return strcmp(cstr, "--") == 0; - }; - auto first = argv; - auto last = argv + argc; - auto separator = std::find_if(first, last, is_separator); - zeek_args.emplace_back(argv[0]); - - if ( separator != last ) - { - auto first_zeek_arg = std::next(separator); - - for ( auto i = first_zeek_arg; i != last; ++i ) - zeek_args.emplace_back(*i); - } - - rval.run_unit_tests = true; - - for ( auto i = 0; i < std::distance(first, separator); ++i ) - rval.doctest_args.emplace_back(argv[i]); - } - else - { - for ( auto i = 0; i < argc; ++i ) - zeek_args.emplace_back(argv[i]); - } - - constexpr struct option long_opts[] = { - {"parse-only", no_argument, 0, 'a'}, - {"bare-mode", no_argument, 0, 'b'}, - {"debug-script", no_argument, 0, 'd'}, - {"exec", required_argument, 0, 'e'}, - {"filter", required_argument, 0, 'f'}, - {"help", no_argument, 0, 'h'}, - {"iface", required_argument, 0, 'i'}, - {"zeekygen", required_argument, 0, 'X'}, - {"prefix", required_argument, 0, 'p'}, - {"readfile", required_argument, 0, 'r'}, - {"rulefile", required_argument, 0, 's'}, - {"tracefile", required_argument, 0, 't'}, - {"writefile", required_argument, 0, 'w'}, - {"version", no_argument, 0, 'v'}, - {"no-checksums", no_argument, 0, 'C'}, - {"force-dns", no_argument, 0, 'F'}, - {"load-seeds", required_argument, 0, 'G'}, - {"save-seeds", required_argument, 0, 'H'}, - {"print-plugins", no_argument, 0, 'N'}, - {"prime-dns", no_argument, 0, 'P'}, - {"time", no_argument, 0, 'Q'}, - {"debug-rules", no_argument, 0, 'S'}, - {"re-level", required_argument, 0, 'T'}, - {"watchdog", no_argument, 0, 'W'}, - {"print-id", required_argument, 0, 'I'}, - {"status-file", required_argument, 0, 'U'}, - -#ifdef DEBUG - {"debug", required_argument, 0, 'B'}, -#endif -#ifdef USE_IDMEF - {"idmef-dtd", required_argument, 0, 'n'}, -#endif -#ifdef USE_PERFTOOLS_DEBUG - {"mem-leaks", no_argument, 0, 'm'}, - {"mem-profile", no_argument, 0, 'M'}, -#endif - - {"pseudo-realtime", optional_argument, 0, 'E'}, - {"jobs", optional_argument, 0, 'j'}, - {"test", no_argument, 0, '#'}, - - {0, 0, 0, 0}, - }; - - char opts[256]; - safe_strncpy(opts, "B:e:f:G:H:I:i:j::n:p:r:s:T:t:U:w:X:CFNPQSWabdhv", - sizeof(opts)); - -#ifdef USE_PERFTOOLS_DEBUG - strncat(opts, "mM", 2); -#endif - - int op; - int long_optsind; - opterr = 0; - - // getopt may permute the array, so need yet another array - auto zargs = std::make_unique(zeek_args.size()); - - for ( auto i = 0u; i < zeek_args.size(); ++i ) - zargs[i] = zeek_args[i].data(); - - while ( (op = getopt_long(zeek_args.size(), zargs.get(), opts, long_opts, &long_optsind)) != EOF ) - switch ( op ) { - case 'a': - rval.parse_only = true; - break; - case 'b': - rval.bare_mode = true; - break; - case 'd': - rval.debug_scripts = true; - break; - case 'e': - rval.script_code_to_exec = optarg; - break; - case 'f': - rval.pcap_filter = optarg; - break; - case 'h': - rval.print_usage = true; - break; - case 'i': - if ( ! rval.pcap_files.empty() ) - { - fprintf(stderr, "Using -i is not allowed when reading pcap files"); - exit(1); - } - rval.interfaces.emplace_back(optarg); - break; - case 'j': - rval.supervisor_mode = true; - if ( optarg ) - { - // TODO: for supervised offline pcap reading, the argument is - // expected to be number of workers like "-j 4" or possibly a - // list of worker/proxy/logger counts like "-j 4,2,1" - } - break; - case 'p': - rval.script_prefixes.emplace_back(optarg); - break; - case 'r': - if ( ! rval.interfaces.empty() ) - { - fprintf(stderr, "Using -r is not allowed when reading a live interface"); - exit(1); - } - rval.pcap_files.emplace_back(optarg); - break; - case 's': - rval.signature_files.emplace_back(optarg); - break; - case 't': - rval.debug_script_tracing_file = optarg; - break; - case 'v': - rval.print_version = true; - break; - case 'w': - rval.pcap_output_file = optarg; - break; - case 'B': - rval.debug_log_streams = optarg; - break; - case 'C': - rval.ignore_checksums = true; - break; - case 'E': - rval.pseudo_realtime = 1.0; - if ( optarg ) - rval.pseudo_realtime = atof(optarg); - break; - case 'F': - if ( rval.dns_mode != DNS_DEFAULT ) - usage(zargs[0], 1); - rval.dns_mode = DNS_FORCE; - break; - case 'G': - rval.random_seed_input_file = optarg; - break; - case 'H': - rval.random_seed_output_file = optarg; - break; - case 'I': - rval.identifier_to_print = optarg; - break; - case 'N': - ++rval.print_plugins; - break; - case 'P': - if ( rval.dns_mode != DNS_DEFAULT ) - usage(zargs[0], 1); - rval.dns_mode = DNS_PRIME; - break; - case 'Q': - rval.print_execution_time = true; - break; - case 'S': - rval.print_signature_debug_info = true; - break; - case 'T': - rval.signature_re_level = atoi(optarg); - break; - case 'U': - rval.process_status_file = optarg; - break; - case 'W': - rval.use_watchdog = true; - break; - case 'X': - rval.zeekygen_config_file = optarg; - break; - -#ifdef USE_PERFTOOLS_DEBUG - case 'm': - rval.perftools_check_leaks = 1; - break; - case 'M': - rval.perftools_profile = 1; - break; -#endif - -#ifdef USE_IDMEF - case 'n': - rval.libidmef_dtd_path = optarg; - break; -#endif - - case '#': - fprintf(stderr, "ERROR: --test only allowed as first argument.\n"); - usage(zargs[0], 1); - break; - - case 0: - // This happens for long options that don't have - // a short-option equivalent. - break; - - case '?': - default: - usage(zargs[0], 1); - break; - } - - // Process remaining arguments. X=Y arguments indicate script - // variable/parameter assignments. X::Y arguments indicate plugins to - // activate/query. The remainder are treated as scripts to load. - while ( optind < static_cast(zeek_args.size()) ) - { - if ( strchr(zargs[optind], '=') ) - rval.script_options_to_set.emplace_back(zargs[optind++]); - else if ( strstr(zargs[optind], "::") ) - rval.plugins_to_load.emplace(zargs[optind++]); - else - rval.scripts_to_load.emplace_back(zargs[optind++]); - } - - auto canonify_script_path = [](std::string* path) - { - if ( path->empty() ) - return; - - *path = normalize_path(*path); - - if ( (*path)[0] == '/' || (*path)[0] == '~' ) - // Absolute path - return; - - if ( (*path)[0] != '.' ) - { - // Look up file in ZEEKPATH - auto res = find_script_file(*path, bro_path()); - - if ( res.empty() ) - { - fprintf(stderr, "failed to locate script: %s\n", path->data()); - exit(1); - } - - *path = res; - - if ( (*path)[0] == '/' || (*path)[0] == '~' ) - // Now an absolute path - return; - } - - // Need to translate relative path to absolute. - char cwd[PATH_MAX]; - - if ( ! getcwd(cwd, sizeof(cwd)) ) - { - fprintf(stderr, "failed to get current directory: %s\n", - strerror(errno)); - exit(1); - } - - *path = std::string(cwd) + "/" + *path; - }; - - if ( rval.supervisor_mode ) - { - // Translate any relative paths supplied to supervisor into absolute - // paths for use by supervised nodes since they have the option to - // operate out of a different working directory. - for ( auto& s : rval.scripts_to_load ) - canonify_script_path(&s); - } - - return rval; - } - bool show_plugins(int level) { plugin::Manager::plugin_list plugins = plugin_mgr->ActivePlugins(); @@ -816,10 +416,10 @@ int main(int argc, char** argv) for ( int i = 0; i < argc; i++ ) bro_argv[i] = copy_string(argv[i]); - auto options = parse_cmdline(argc, argv); + auto options = zeek::parse_cmdline(argc, argv); if ( options.print_usage ) - usage(argv[0], 0); + zeek::usage(argv[0], 0); if ( options.print_version ) { @@ -847,7 +447,7 @@ int main(int argc, char** argv) auto dns_type = options.dns_mode; - if ( dns_type == DNS_DEFAULT && zeek_dns_fake() ) + if ( dns_type == DNS_DEFAULT && zeek::fake_dns() ) dns_type = DNS_FAKE; RETSIGTYPE (*oldhandler)(int);