mirror of
https://github.com/zeek/zeek.git
synced 2025-10-02 14:48:21 +00:00
Move command-line arg parsing functions to Options.{h,cc}
This commit is contained in:
parent
5fb01caee6
commit
53363a9bd3
3 changed files with 431 additions and 403 deletions
408
src/Options.cc
408
src/Options.cc
|
@ -1,5 +1,16 @@
|
|||
// See the file "COPYING" in the main distribution directory for copyright.
|
||||
|
||||
#include <unistd.h>
|
||||
|
||||
#include "zeek-config.h"
|
||||
|
||||
#ifdef HAVE_GETOPT_H
|
||||
#include <getopt.h>
|
||||
#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, " <file> | 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 <zeek code> | augment loaded scripts by given code\n");
|
||||
fprintf(stderr, " -f|--filter <filter> | tcpdump filter\n");
|
||||
fprintf(stderr, " -h|--help | command line help\n");
|
||||
fprintf(stderr, " -i|--iface <interface> | read from given interface\n");
|
||||
fprintf(stderr, " -p|--prefix <prefix> | add given prefix to Zeek script file resolution\n");
|
||||
fprintf(stderr, " -r|--readfile <readfile> | read from given tcpdump file\n");
|
||||
fprintf(stderr, " -s|--rulefile <rulefile> | read rules from given file\n");
|
||||
fprintf(stderr, " -t|--tracefile <tracefile> | activate execution tracing\n");
|
||||
fprintf(stderr, " -v|--version | print version and exit\n");
|
||||
fprintf(stderr, " -w|--writefile <writefile> | write to given tcpdump file\n");
|
||||
#ifdef DEBUG
|
||||
fprintf(stderr, " -B|--debug <dbgstreams> | 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 <file> | load seeds from given file\n");
|
||||
fprintf(stderr, " -H|--save-seeds <file> | save seeds to given file\n");
|
||||
fprintf(stderr, " -I|--print-id <ID name> | 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 <level> | set 'RE_level' for rules\n");
|
||||
fprintf(stderr, " -U|--status-file <file> | Record process status in file\n");
|
||||
fprintf(stderr, " -W|--watchdog | activate watchdog timer\n");
|
||||
fprintf(stderr, " -X|--zeekygen <cfgfile> | 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[=<speedup>] | 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 <idmef-msg.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<std::string> 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<char*[]>(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<int>(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;
|
||||
}
|
||||
|
|
|
@ -74,4 +74,24 @@ struct Options {
|
|||
std::vector<std::string> 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
|
||||
|
|
406
src/main.cc
406
src/main.cc
|
@ -10,9 +10,6 @@
|
|||
#include <sys/types.h>
|
||||
#include <list>
|
||||
#include <optional>
|
||||
#ifdef HAVE_GETOPT_H
|
||||
#include <getopt.h>
|
||||
#endif
|
||||
|
||||
#ifdef USE_IDMEF
|
||||
extern "C" {
|
||||
|
@ -24,7 +21,6 @@ extern "C" {
|
|||
#include <openssl/err.h>
|
||||
|
||||
#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, " <file> | 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 <zeek code> | augment loaded scripts by given code\n");
|
||||
fprintf(stderr, " -f|--filter <filter> | tcpdump filter\n");
|
||||
fprintf(stderr, " -h|--help | command line help\n");
|
||||
fprintf(stderr, " -i|--iface <interface> | read from given interface\n");
|
||||
fprintf(stderr, " -p|--prefix <prefix> | add given prefix to Zeek script file resolution\n");
|
||||
fprintf(stderr, " -r|--readfile <readfile> | read from given tcpdump file\n");
|
||||
fprintf(stderr, " -s|--rulefile <rulefile> | read rules from given file\n");
|
||||
fprintf(stderr, " -t|--tracefile <tracefile> | activate execution tracing\n");
|
||||
fprintf(stderr, " -v|--version | print version and exit\n");
|
||||
fprintf(stderr, " -w|--writefile <writefile> | write to given tcpdump file\n");
|
||||
#ifdef DEBUG
|
||||
fprintf(stderr, " -B|--debug <dbgstreams> | 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 <file> | load seeds from given file\n");
|
||||
fprintf(stderr, " -H|--save-seeds <file> | save seeds to given file\n");
|
||||
fprintf(stderr, " -I|--print-id <ID name> | 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 <level> | set 'RE_level' for rules\n");
|
||||
fprintf(stderr, " -U|--status-file <file> | Record process status in file\n");
|
||||
fprintf(stderr, " -W|--watchdog | activate watchdog timer\n");
|
||||
fprintf(stderr, " -X|--zeekygen <cfgfile> | 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[=<speedup>] | 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 <idmef-msg.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<const char*> to_cargs(const std::vector<std::string>& args)
|
||||
{
|
||||
std::vector<const char*> rval;
|
||||
|
@ -230,330 +154,6 @@ static std::vector<const char*> to_cargs(const std::vector<std::string>& 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<std::string> 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<char*[]>(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<int>(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);
|
||||
|
|
Loading…
Add table
Add a link
Reference in a new issue