zeek/src/main.cc
Johanna Amann 5052dc03fc Remove the BroFile cache
GH-375
2019-06-26 16:32:18 -07:00

1139 lines
28 KiB
C++

// See the file "COPYING" in the main distribution directory for copyright.
#include "zeek-config.h"
#include <stdio.h>
#include <stdlib.h>
#include <unistd.h>
#include <signal.h>
#include <string.h>
#include <list>
#ifdef HAVE_GETOPT_H
#include <getopt.h>
#endif
#ifdef USE_IDMEF
extern "C" {
#include <libidmef/idmefxml.h>
}
#endif
#include <openssl/ssl.h>
#include <openssl/err.h>
#include "bsd-getopt-long.h"
#include "input.h"
#include "DNS_Mgr.h"
#include "Frame.h"
#include "Scope.h"
#include "Event.h"
#include "File.h"
#include "Reporter.h"
#include "Net.h"
#include "NetVar.h"
#include "Var.h"
#include "Timer.h"
#include "Stmt.h"
#include "Debug.h"
#include "DFA.h"
#include "RuleMatcher.h"
#include "Anon.h"
#include "EventRegistry.h"
#include "Stats.h"
#include "Brofiler.h"
#include "Traverse.h"
#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"
#include "plugin/Manager.h"
#include "file_analysis/Manager.h"
#include "zeekygen/Manager.h"
#include "iosource/Manager.h"
#include "broker/Manager.h"
#include "binpac_bro.h"
#include "3rdparty/sqlite3.h"
Brofiler brofiler;
#ifndef HAVE_STRSEP
extern "C" {
char* strsep(char**, const char*);
};
#endif
extern "C" {
#include "setsignal.h"
};
#ifdef USE_PERFTOOLS_DEBUG
HeapLeakChecker* heap_checker = 0;
int perftools_leaks = 0;
int perftools_profile = 0;
#endif
DNS_Mgr* dns_mgr;
TimerMgr* timer_mgr;
ValManager* val_mgr = 0;
PortManager* port_mgr = 0;
logging::Manager* log_mgr = 0;
threading::Manager* thread_mgr = 0;
input::Manager* input_mgr = 0;
plugin::Manager* plugin_mgr = 0;
analyzer::Manager* analyzer_mgr = 0;
file_analysis::Manager* file_mgr = 0;
zeekygen::Manager* zeekygen_mgr = 0;
iosource::Manager* iosource_mgr = 0;
bro_broker::Manager* broker_mgr = 0;
const char* prog;
char* writefile = 0;
name_list prefixes;
Stmt* stmts;
EventHandlerPtr net_done = 0;
RuleMatcher* rule_matcher = 0;
EventRegistry* event_registry = 0;
ProfileLogger* profiling_logger = 0;
ProfileLogger* segment_logger = 0;
SampleLogger* sample_logger = 0;
int signal_val = 0;
extern char version[];
char* command_line_policy = 0;
vector<string> params;
set<string> requested_plugins;
char* proc_status_file = 0;
OpaqueType* md5_type = 0;
OpaqueType* sha1_type = 0;
OpaqueType* sha256_type = 0;
OpaqueType* entropy_type = 0;
OpaqueType* cardinality_type = 0;
OpaqueType* topk_type = 0;
OpaqueType* bloomfilter_type = 0;
OpaqueType* x509_opaque_type = 0;
OpaqueType* ocsp_resp_opaque_type = 0;
OpaqueType* paraglob_type = 0;
// Keep copy of command line
int bro_argc;
char** bro_argv;
const char* zeek_version()
{
#ifdef DEBUG
static char* debug_version = 0;
if ( ! debug_version )
{
int n = strlen(version) + sizeof("-debug") + 1;
debug_version = new char[n];
snprintf(debug_version, n, "%s%s", version, "-debug");
}
return debug_version;
#else
return version;
#endif
}
bool bro_dns_fake()
{
return zeekenv("ZEEK_DNS_FAKE");
}
void usage(int code = 1)
{
fprintf(stderr, "zeek version %s\n", zeek_version());
fprintf(stderr, "usage: %s [options] [file ...]\n", prog);
fprintf(stderr, " <file> | policy 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-policy | activate policy file debugging\n");
fprintf(stderr, " -e|--exec <zeek code> | augment loaded policies 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 policy 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");
#ifdef USE_IDMEF
fprintf(stderr, " -n|--idmef-dtd <idmef-msg.dtd> | specify path to IDMEF DTD file\n");
#endif
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", bro_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, "\n");
exit(code);
}
bool show_plugins(int level)
{
plugin::Manager::plugin_list plugins = plugin_mgr->ActivePlugins();
if ( ! plugins.size() )
{
printf("No plugins registered, not even any built-ins. This is probably a bug.\n");
return false;
}
ODesc d;
if ( level == 1 )
d.SetShort();
int count = 0;
for ( plugin::Manager::plugin_list::const_iterator i = plugins.begin(); i != plugins.end(); i++ )
{
if ( requested_plugins.size()
&& requested_plugins.find((*i)->Name()) == requested_plugins.end() )
continue;
(*i)->Describe(&d);
if ( ! d.IsShort() )
d.Add("\n");
++count;
}
printf("%s", d.Description());
plugin::Manager::inactive_plugin_list inactives = plugin_mgr->InactivePlugins();
if ( inactives.size() && ! requested_plugins.size() )
{
printf("\nInactive dynamic plugins:\n");
for ( plugin::Manager::inactive_plugin_list::const_iterator i = inactives.begin(); i != inactives.end(); i++ )
{
string name = (*i).first;
string path = (*i).second;
printf(" %s (%s)\n", name.c_str(), path.c_str());
}
}
return count != 0;
}
void done_with_network()
{
set_processing_status("TERMINATING", "done_with_network");
// Cancel any pending alarms (watchdog, in particular).
(void) alarm(0);
if ( net_done )
{
mgr.Drain();
// Don't propagate this event to remote clients.
mgr.Dispatch(new Event(net_done,
{new Val(timer_mgr->Time(), TYPE_TIME)}),
true);
}
if ( profiling_logger )
profiling_logger->Log();
terminating = true;
analyzer_mgr->Done();
timer_mgr->Expire();
dns_mgr->Flush();
mgr.Drain();
mgr.Drain();
net_finish(1);
#ifdef USE_PERFTOOLS_DEBUG
if ( perftools_profile )
{
HeapProfilerDump("post net_run");
HeapProfilerStop();
}
if ( heap_checker && ! heap_checker->NoLeaks() )
{
fprintf(stderr, "Memory leaks - aborting.\n");
abort();
}
#endif
}
void terminate_bro()
{
set_processing_status("TERMINATING", "terminate_bro");
terminating = true;
// File analysis termination may produce events, so do it early on in
// the termination process.
file_mgr->Terminate();
brofiler.WriteStats();
EventHandlerPtr zeek_done = internal_handler("zeek_done");
if ( zeek_done )
mgr.QueueEventFast(zeek_done, val_list{});
timer_mgr->Expire();
mgr.Drain();
if ( profiling_logger )
{
// FIXME: There are some occasional crashes in the memory
// allocation code when killing Bro. Disabling this for now.
if ( ! (signal_val == SIGTERM || signal_val == SIGINT) )
profiling_logger->Log();
delete profiling_logger;
}
mgr.Drain();
log_mgr->Terminate();
input_mgr->Terminate();
thread_mgr->Terminate();
broker_mgr->Terminate();
mgr.Drain();
plugin_mgr->FinishPlugins();
delete zeekygen_mgr;
delete timer_mgr;
delete event_registry;
delete analyzer_mgr;
delete file_mgr;
// broker_mgr is deleted via iosource_mgr
delete iosource_mgr;
delete log_mgr;
delete reporter;
delete plugin_mgr;
delete val_mgr;
delete port_mgr;
reporter = 0;
}
void termination_signal()
{
set_processing_status("TERMINATING", "termination_signal");
reporter->Info("received termination signal");
net_get_final_stats();
done_with_network();
net_delete();
terminate_bro();
// Close files after net_delete(), because net_delete()
// might write to connection content files.
BroFile::CloseOpenFiles();
delete rule_matcher;
exit(0);
}
RETSIGTYPE sig_handler(int signo)
{
set_processing_status("TERMINATING", "sig_handler");
signal_val = signo;
return RETSIGVAL;
}
static void atexit_handler()
{
set_processing_status("TERMINATED", "atexit");
}
static void bro_new_handler()
{
out_of_memory("new");
}
int main(int argc, char** argv)
{
std::set_new_handler(bro_new_handler);
double time_start = current_time(true);
brofiler.ReadStats();
bro_argc = argc;
bro_argv = new char* [argc];
for ( int i = 0; i < argc; i++ )
bro_argv[i] = copy_string(argv[i]);
name_list interfaces;
name_list read_files;
name_list rule_files;
char* id_name = 0;
char* seed_load_file = zeekenv("ZEEK_SEED_FILE");
char* seed_save_file = 0;
char* user_pcap_filter = 0;
char* debug_streams = 0;
int parse_only = false;
int bare_mode = false;
int do_watchdog = 0;
int override_ignore_checksums = 0;
int rule_debug = 0;
int RE_level = 4;
int print_plugins = 0;
int time_bro = 0;
static struct option long_opts[] = {
{"parse-only", no_argument, 0, 'a'},
{"bare-mode", no_argument, 0, 'b'},
{"debug-policy", 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'},
{0, 0, 0, 0},
};
enum DNS_MgrMode dns_type = DNS_DEFAULT;
dns_type = bro_dns_fake() ? DNS_FAKE : DNS_DEFAULT;
RETSIGTYPE (*oldhandler)(int);
prog = argv[0];
prefixes.append(strdup("")); // "" = "no prefix"
char* p = zeekenv("ZEEK_PREFIXES");
if ( p )
add_to_name_list(p, ':', prefixes);
string zeekygen_config;
#ifdef USE_IDMEF
string libidmef_dtd_path = "idmef-message.dtd";
#endif
extern char* optarg;
extern int optind, opterr;
int long_optsind;
opterr = 0;
char opts[256];
safe_strncpy(opts, "B:e:f:G:H:I:i:n:p:r:s:T:t:U:w:X:CFNPQSWabdhv",
sizeof(opts));
#ifdef USE_PERFTOOLS_DEBUG
strncat(opts, "mM", 2);
#endif
int op;
while ( (op = getopt_long(argc, argv, opts, long_opts, &long_optsind)) != EOF )
switch ( op ) {
case 'a':
parse_only = true;
break;
case 'b':
bare_mode = true;
break;
case 'd':
fprintf(stderr, "Policy file debugging ON.\n");
g_policy_debug = true;
break;
case 'e':
command_line_policy = optarg;
break;
case 'f':
user_pcap_filter = optarg;
break;
case 'h':
usage(0);
break;
case 'i':
interfaces.append(optarg);
break;
case 'p':
prefixes.append(optarg);
break;
case 'r':
read_files.append(optarg);
break;
case 's':
rule_files.append(optarg);
break;
case 't':
g_trace_state.SetTraceFile(optarg);
g_trace_state.TraceOn();
break;
case 'v':
fprintf(stdout, "%s version %s\n", prog, zeek_version());
exit(0);
break;
case 'w':
writefile = optarg;
break;
case 'B':
debug_streams = optarg;
break;
case 'C':
override_ignore_checksums = 1;
break;
case 'E':
pseudo_realtime = 1.0;
if ( optarg )
pseudo_realtime = atof(optarg);
break;
case 'F':
if ( dns_type != DNS_DEFAULT )
usage(1);
dns_type = DNS_FORCE;
break;
case 'G':
seed_load_file = optarg;
break;
case 'H':
seed_save_file = optarg;
break;
case 'I':
id_name = optarg;
break;
case 'N':
++print_plugins;
break;
case 'P':
if ( dns_type != DNS_DEFAULT )
usage(1);
dns_type = DNS_PRIME;
break;
case 'Q':
time_bro = 1;
break;
case 'S':
rule_debug = 1;
break;
case 'T':
RE_level = atoi(optarg);
break;
case 'U':
proc_status_file = optarg;
break;
case 'W':
do_watchdog = 1;
break;
case 'X':
zeekygen_config = optarg;
break;
#ifdef USE_PERFTOOLS_DEBUG
case 'm':
perftools_leaks = 1;
break;
case 'M':
perftools_profile = 1;
break;
#endif
#ifdef USE_IDMEF
case 'n':
fprintf(stderr, "Using IDMEF XML DTD from %s\n", optarg);
libidmef_dtd_path = optarg;
break;
#endif
case 0:
// This happens for long options that don't have
// a short-option equivalent.
break;
case '?':
default:
usage(1);
break;
}
atexit(atexit_handler);
set_processing_status("INITIALIZING", "main");
bro_start_time = current_time(true);
val_mgr = new ValManager();
port_mgr = new PortManager();
reporter = new Reporter();
thread_mgr = new threading::Manager();
plugin_mgr = new plugin::Manager();
#ifdef DEBUG
if ( debug_streams )
{
debug_logger.EnableStreams(debug_streams);
debug_logger.OpenDebugLog("debug");
}
#endif
init_random_seed((seed_load_file && *seed_load_file ? seed_load_file : 0) , seed_save_file);
// DEBUG_MSG("HMAC key: %s\n", md5_digest_print(shared_hmac_md5_key));
init_hash_function();
ERR_load_crypto_strings();
OPENSSL_add_all_algorithms_conf();
SSL_library_init();
SSL_load_error_strings();
int r = sqlite3_initialize();
if ( r != SQLITE_OK )
reporter->Error("Failed to initialize sqlite3: %s", sqlite3_errstr(r));
// FIXME: On systems that don't provide /dev/urandom, OpenSSL doesn't
// seed the PRNG. We should do this here (but at least Linux, FreeBSD
// and Solaris provide /dev/urandom).
if ( interfaces.length() > 0 && read_files.length() > 0 )
usage(1);
#ifdef USE_IDMEF
char* libidmef_dtd_path_cstr = new char[libidmef_dtd_path.length() + 1];
safe_strncpy(libidmef_dtd_path_cstr, libidmef_dtd_path.c_str(),
libidmef_dtd_path.length());
globalsInit(libidmef_dtd_path_cstr); // Init LIBIDMEF globals
createCurrentDoc("1.0"); // Set a global XML document
#endif
timer_mgr = new PQ_TimerMgr("<GLOBAL>");
// timer_mgr = new CQ_TimerMgr();
zeekygen_mgr = new zeekygen::Manager(zeekygen_config, bro_argv[0]);
add_essential_input_file("base/init-bare.zeek");
add_essential_input_file("base/init-frameworks-and-bifs.zeek");
if ( ! bare_mode )
add_input_file("base/init-default.zeek");
plugin_mgr->SearchDynamicPlugins(bro_plugin_path());
if ( optind == argc &&
read_files.length() == 0 &&
interfaces.length() == 0 &&
! id_name && ! command_line_policy && ! print_plugins )
add_input_file("-");
// 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 < argc )
{
if ( strchr(argv[optind], '=') )
params.push_back(argv[optind++]);
else if ( strstr(argv[optind], "::") )
requested_plugins.insert(argv[optind++]);
else
add_input_file(argv[optind++]);
}
push_scope(nullptr, nullptr);
dns_mgr = new DNS_Mgr(dns_type);
// It would nice if this were configurable. This is similar to the
// chicken and the egg problem. It would be configurable by parsing
// policy, but we can't parse policy without DNS resolution.
dns_mgr->SetDir(".state");
iosource_mgr = new iosource::Manager();
event_registry = new EventRegistry();
analyzer_mgr = new analyzer::Manager();
log_mgr = new logging::Manager();
input_mgr = new input::Manager();
file_mgr = new file_analysis::Manager();
broker_mgr = new bro_broker::Manager(read_files.length() > 0);
plugin_mgr->InitPreScript();
analyzer_mgr->InitPreScript();
file_mgr->InitPreScript();
zeekygen_mgr->InitPreScript();
bool missing_plugin = false;
for ( set<string>::const_iterator i = requested_plugins.begin();
i != requested_plugins.end(); i++ )
{
if ( ! plugin_mgr->ActivateDynamicPlugin(*i) )
missing_plugin = true;
}
if ( missing_plugin )
reporter->FatalError("Failed to activate requested dynamic plugin(s).");
plugin_mgr->ActivateDynamicPlugins(! bare_mode);
init_event_handlers();
md5_type = new OpaqueType("md5");
sha1_type = new OpaqueType("sha1");
sha256_type = new OpaqueType("sha256");
entropy_type = new OpaqueType("entropy");
cardinality_type = new OpaqueType("cardinality");
topk_type = new OpaqueType("topk");
bloomfilter_type = new OpaqueType("bloomfilter");
x509_opaque_type = new OpaqueType("x509");
ocsp_resp_opaque_type = new OpaqueType("ocsp_resp");
paraglob_type = new OpaqueType("paraglob");
// The leak-checker tends to produce some false
// positives (memory which had already been
// allocated before we start the checking is
// nevertheless reported; see perftools docs), thus
// we suppress some messages here.
#ifdef USE_PERFTOOLS_DEBUG
{
HeapLeakChecker::Disabler disabler;
#endif
is_parsing = true;
yyparse();
is_parsing = false;
RecordVal::ResizeParseTimeRecords();
init_general_global_var();
init_net_var();
init_builtin_funcs_subdirs();
// Must come after plugin activation (and also after hash
// initialization).
binpac::FlowBuffer::Policy flowbuffer_policy;
flowbuffer_policy.max_capacity = global_scope()->Lookup(
"BinPAC::flowbuffer_capacity_max")->ID_Val()->AsCount();
flowbuffer_policy.min_capacity = global_scope()->Lookup(
"BinPAC::flowbuffer_capacity_min")->ID_Val()->AsCount();
flowbuffer_policy.contract_threshold = global_scope()->Lookup(
"BinPAC::flowbuffer_contract_threshold")->ID_Val()->AsCount();
binpac::init(&flowbuffer_policy);
plugin_mgr->InitBifs();
if ( reporter->Errors() > 0 )
exit(1);
plugin_mgr->InitPostScript();
zeekygen_mgr->InitPostScript();
broker_mgr->InitPostScript();
if ( print_plugins )
{
bool success = show_plugins(print_plugins);
exit(success ? 0 : 1);
}
analyzer_mgr->InitPostScript();
file_mgr->InitPostScript();
dns_mgr->InitPostScript();
if ( parse_only )
{
int rc = (reporter->Errors() > 0 ? 1 : 0);
exit(rc);
}
#ifdef USE_PERFTOOLS_DEBUG
}
#endif
if ( reporter->Errors() > 0 )
{
delete dns_mgr;
exit(1);
}
reporter->InitOptions();
zeekygen_mgr->GenerateDocs();
if ( user_pcap_filter )
{
ID* id = global_scope()->Lookup("cmd_line_bpf_filter");
if ( ! id )
reporter->InternalError("global cmd_line_bpf_filter not defined");
id->SetVal(new StringVal(user_pcap_filter));
}
// Parse rule files defined on the script level.
char* script_rule_files =
copy_string(internal_val("signature_files")->AsString()->CheckString());
char* tmp = script_rule_files;
char* s;
while ( (s = strsep(&tmp, " \t")) )
if ( *s )
rule_files.append(s);
// Append signature files defined in @load-sigs
for ( size_t i = 0; i < sig_files.size(); ++i )
rule_files.append(copy_string(sig_files[i].c_str()));
if ( rule_files.length() > 0 )
{
rule_matcher = new RuleMatcher(RE_level);
if ( ! rule_matcher->ReadFiles(rule_files) )
{
delete dns_mgr;
exit(1);
}
if ( rule_debug )
rule_matcher->PrintDebug();
file_mgr->InitMagic();
}
delete [] script_rule_files;
if ( g_policy_debug )
// ### Add support for debug command file.
dbg_init_debugger(0);
if ( read_files.length() == 0 && interfaces.length() == 0 )
{
Val* interfaces_val = internal_val("interfaces");
if ( interfaces_val )
{
char* interfaces_str =
interfaces_val->AsString()->Render();
if ( interfaces_str[0] != '\0' )
add_to_name_list(interfaces_str, ' ', interfaces);
delete [] interfaces_str;
}
}
if ( dns_type != DNS_PRIME )
net_init(interfaces, read_files, writefile, do_watchdog);
net_done = internal_handler("net_done");
if ( ! g_policy_debug )
{
(void) setsignal(SIGTERM, sig_handler);
(void) setsignal(SIGINT, sig_handler);
(void) setsignal(SIGPIPE, SIG_IGN);
}
// Cooperate with nohup(1).
if ( (oldhandler = setsignal(SIGHUP, sig_handler)) != SIG_DFL )
(void) setsignal(SIGHUP, oldhandler);
if ( dns_type == DNS_PRIME )
{
dns_mgr->Verify();
dns_mgr->Resolve();
if ( ! dns_mgr->Save() )
reporter->FatalError("can't update DNS cache");
mgr.Drain();
delete dns_mgr;
exit(0);
}
// Print the ID.
if ( id_name )
{
ID* id = global_scope()->Lookup(id_name);
if ( ! id )
reporter->FatalError("No such ID: %s\n", id_name);
ODesc desc;
desc.SetQuotes(true);
desc.SetIncludeStats(true);
id->DescribeExtended(&desc);
fprintf(stdout, "%s\n", desc.Description());
exit(0);
}
if ( profiling_interval > 0 )
{
profiling_logger = new ProfileLogger(profiling_file->AsFile(),
profiling_interval);
if ( segment_profiling )
segment_logger = profiling_logger;
}
if ( ! reading_live && ! reading_traces )
// Set up network_time to track real-time, since
// we don't have any other source for it.
net_update_time(current_time());
EventHandlerPtr zeek_init = internal_handler("zeek_init");
if ( zeek_init ) //### this should be a function
mgr.QueueEventFast(zeek_init, val_list{});
EventRegistry::string_list* dead_handlers =
event_registry->UnusedHandlers();
if ( dead_handlers->length() > 0 && check_for_unused_event_handlers )
{
for ( int i = 0; i < dead_handlers->length(); ++i )
reporter->Warning("event handler never invoked: %s", (*dead_handlers)[i]);
}
delete dead_handlers;
EventRegistry::string_list* alive_handlers =
event_registry->UsedHandlers();
if ( alive_handlers->length() > 0 && dump_used_event_handlers )
{
reporter->Info("invoked event handlers:");
for ( int i = 0; i < alive_handlers->length(); ++i )
reporter->Info("%s", (*alive_handlers)[i]);
}
delete alive_handlers;
if ( stmts )
{
stmt_flow_type flow;
Frame f(current_scope()->Length(), 0, 0);
g_frame_stack.push_back(&f);
try
{
stmts->Exec(&f, flow);
}
catch ( InterpreterException& )
{
reporter->FatalError("failed to execute script statements at top-level scope");
}
g_frame_stack.pop_back();
}
if ( override_ignore_checksums )
ignore_checksums = 1;
if ( zeek_script_loaded )
{
// Queue events reporting loaded scripts.
for ( std::list<ScannedFile>::iterator i = files_scanned.begin(); i != files_scanned.end(); i++ )
{
if ( i->skipped )
continue;
mgr.QueueEventFast(zeek_script_loaded, {
new StringVal(i->name.c_str()),
val_mgr->GetCount(i->include_level),
});
}
}
reporter->ReportViaEvents(true);
// Drain the event queue here to support the protocols framework configuring DPM
mgr.Drain();
if ( reporter->Errors() > 0 && ! zeekenv("ZEEK_ALLOW_INIT_ERRORS") )
reporter->FatalError("errors occurred while initializing");
broker_mgr->ZeekInitDone();
reporter->ZeekInitDone();
analyzer_mgr->DumpDebug();
have_pending_timers = ! reading_traces && timer_mgr->Size() > 0;
iosource_mgr->Register(thread_mgr, true);
if ( iosource_mgr->Size() > 0 ||
have_pending_timers ||
BifConst::exit_only_after_terminate )
{
if ( profiling_logger )
profiling_logger->Log();
#ifdef USE_PERFTOOLS_DEBUG
if ( perftools_leaks )
heap_checker = new HeapLeakChecker("net_run");
if ( perftools_profile )
{
HeapProfilerStart("heap");
HeapProfilerDump("pre net_run");
}
#endif
double time_net_start = current_time(true);;
uint64 mem_net_start_total;
uint64 mem_net_start_malloced;
if ( time_bro )
{
get_memory_usage(&mem_net_start_total, &mem_net_start_malloced);
fprintf(stderr, "# initialization %.6f\n", time_net_start - time_start);
fprintf(stderr, "# initialization %" PRIu64 "M/%" PRIu64 "M\n",
mem_net_start_total / 1024 / 1024,
mem_net_start_malloced / 1024 / 1024);
}
net_run();
double time_net_done = current_time(true);;
uint64 mem_net_done_total;
uint64 mem_net_done_malloced;
if ( time_bro )
{
get_memory_usage(&mem_net_done_total, &mem_net_done_malloced);
fprintf(stderr, "# total time %.6f, processing %.6f\n",
time_net_done - time_start, time_net_done - time_net_start);
fprintf(stderr, "# total mem %" PRId64 "M/%" PRId64 "M, processing %" PRId64 "M/%" PRId64 "M\n",
mem_net_done_total / 1024 / 1024,
mem_net_done_malloced / 1024 / 1024,
(mem_net_done_total - mem_net_start_total) / 1024 / 1024,
(mem_net_done_malloced - mem_net_start_malloced) / 1024 / 1024);
}
done_with_network();
net_delete();
terminate_bro();
sqlite3_shutdown();
ERR_free_strings();
EVP_cleanup();
CRYPTO_cleanup_all_ex_data();
// Close files after net_delete(), because net_delete()
// might write to connection content files.
BroFile::CloseOpenFiles();
}
else
{
terminate_bro();
}
delete rule_matcher;
return 0;
}