Merge remote-tracking branch 'origin/topic/jsiwek/supervisor'

* origin/topic/jsiwek/supervisor: (44 commits)
  Add note that Supervisor script APIs are unstable until 4.0
  Move command-line arg parsing functions to Options.{h,cc}
  Add btests for supervisor stem/leaf process revival
  Move supervisor control events into SupervisorControl namespace
  Fix supervisor "destroy" call on nodes not currently alive
  Move supervisor source files into supervisor/
  Address supervisor code re-factoring feedback from Robin
  Convert supervisor internals to rapidjson
  Add Supervisor documentation
  Add supervisor btests
  Improve logging of supervised node errors
  Fix supervised node inheritence of command-line script paths
  Improve normalize_path() util function
  Use a timer to check for death of supervised node's parent
  Improve supervisor checks for parent process termination
  Improve handling of premature supervisor stem exit
  Improve supervisor signal handler safety
  Remove unused supervisor config options
  Cleanup minor Supervisor TODOs
  Improve supervisor debug logging
  ...
This commit is contained in:
Robin Sommer 2020-01-29 12:53:32 +00:00
commit 6bcd583836
79 changed files with 4239 additions and 548 deletions

24
CHANGES
View file

@ -1,4 +1,28 @@
3.1.0-dev.458 | 2020-01-29 12:53:32 +0000
* Add a new supervisor framework that enables Zeek to operate
clusters of processes itself without any external help. (Jon
Siwek, Corelight)
The Supervisor framework provides an entirely new deployment mode
for Zeek, one that supervises a set of Zeek processes that are
meant to be persistent. A Supervisor automatically revives any
process that dies or exits prematurely and also arranges for an
ordered shutdown of the entire process tree upon its own
termination. This Supervisor mode for Zeek provides the basic
foundation for process configuration/management that could be used
to deploy a Zeek cluster similar to what ZeekControl does, but is
also simpler to integrate as a standard system service.
This mode is still experimental and will evolve over time. The
command-line argument of ``-j`` toggles Zeek to run in "Supervisor
mode" to allow for creation and management of child processes. If
you're going to test this, please note that you will need some
custom script code to configure the processes you want Zeek to
run. See the documentation for more information:
https://docs.zeek.org/en/stable/frameworks/supervisor.html
3.1.0-dev.408 | 2020-01-28 17:56:02 -0800 3.1.0-dev.408 | 2020-01-28 17:56:02 -0800
* Update Cirrus CI config to use macOS Catalina (Jon Siwek, Corelight) * Update Cirrus CI config to use macOS Catalina (Jon Siwek, Corelight)

21
NEWS
View file

@ -9,6 +9,27 @@ Zeek 3.1.0
New Functionality New Functionality
----------------- -----------------
- Add a new supervisor framework that enables Zeek to operate clusters
of processes itself without any external help.
The Supervisor framework provides an entirely new deployment mode
for Zeek, one that supervises a set of Zeek processes that are meant
to be persistent. A Supervisor automatically revives any process
that dies or exits prematurely and also arranges for an ordered
shutdown of the entire process tree upon its own termination. This
Supervisor mode for Zeek provides the basic foundation for process
configuration/management that could be used to deploy a Zeek cluster
similar to what ZeekControl does, but is also simpler to integrate
as a standard system service.
This mode is still experimental and will evolve over time. The
command-line argument of ``-j`` toggles Zeek to run in "Supervisor
mode" to allow for creation and management of child processes. If
you're going to test this, please note that you will need some
custom script code to configure the processes you want Zeek to run.
See the documentation for more information:
https://docs.zeek.org/en/stable/frameworks/supervisor.html
- Add a new option, ``dpd_late_match_stop``, which can be used in conjuction - Add a new option, ``dpd_late_match_stop``, which can be used in conjuction
with the option ``dpd_match_only_beginning`` and the new event with the option ``dpd_match_only_beginning`` and the new event
``protocol_late_match`` to help annotate the conn.log with a field ``protocol_late_match`` to help annotate the conn.log with a field

View file

@ -1 +1 @@
3.1.0-dev.408 3.1.0-dev.458

2
doc

@ -1 +1 @@
Subproject commit 7192dbedf3ca9ce49294057262074f0e888177f3 Subproject commit 3088b53e8ab5e2f35bb2bf57ef0ddbba84820ad9

View file

@ -18,7 +18,12 @@ redef Broker::log_topic = Cluster::rr_log_topic;
# Loading the cluster framework requires that a script by this name exists # Loading the cluster framework requires that a script by this name exists
# somewhere in the ZEEKPATH. The only thing in the file should be the # somewhere in the ZEEKPATH. The only thing in the file should be the
# cluster definition in the :zeek:id:`Cluster::nodes` variable. # cluster definition in the :zeek:id:`Cluster::nodes` variable.
@if ( ! Supervisor::__init_cluster() )
# When running a supervised cluster, Cluster::nodes is instead populated
# from the internal C++-layer directly via the above BIF.
@load cluster-layout @load cluster-layout
@endif
@if ( Cluster::node in Cluster::nodes ) @if ( Cluster::node in Cluster::nodes )

View file

@ -287,7 +287,13 @@ function is_enabled(): bool
function local_node_type(): NodeType function local_node_type(): NodeType
{ {
return is_enabled() ? nodes[node]$node_type : NONE; if ( ! is_enabled() )
return NONE;
if ( node !in nodes )
return NONE;
return nodes[node]$node_type;
} }
function node_topic(name: string): string function node_topic(name: string): string

View file

@ -23,4 +23,7 @@ redef Log::default_rotation_interval = 1 hrs;
redef Log::default_mail_alarms_interval = 24 hrs; redef Log::default_mail_alarms_interval = 24 hrs;
## Use the cluster's archive logging script. ## Use the cluster's archive logging script.
@if ( ! Supervisor::is_supervised() )
redef Log::default_rotation_postprocessor_cmd = "archive-log"; redef Log::default_rotation_postprocessor_cmd = "archive-log";
@endif

View file

@ -0,0 +1,3 @@
@load ./api
@load ./control
@load ./main

View file

@ -0,0 +1,120 @@
##! The Zeek process supervision API.
##! This API was introduced in Zeek 3.1.0 and considered unstable until 4.0.0.
##! That is, it may change in various incompatible ways without warning or
##! deprecation until the stable 4.0.0 release.
module Supervisor;
export {
## The role a supervised-node will play in Zeek's Cluster Framework.
type ClusterRole: enum {
NONE,
LOGGER,
MANAGER,
PROXY,
WORKER,
};
## Describes configuration of a supervised-node within Zeek's Cluster
## Framework.
type ClusterEndpoint: record {
## The role a supervised-node will play in Zeek's Cluster Framework.
role: ClusterRole;
## The host/IP at which the cluster node runs.
host: addr;
## The TCP port at which the cluster node listens for connections.
p: port;
## The interface name from which the node will read/analyze packets.
## Typically used by worker nodes.
interface: string &optional;
};
## Configuration options that influence behavior of a supervised Zeek node.
type NodeConfig: record {
## The name of the supervised node. These are unique within a given
## supervised process tree and typically human-readable.
name: string;
## The interface name from which the node will read/analyze packets.
interface: string &optional;
## The working directory that the node should use.
directory: string &optional;
## The filename/path to which the node's stdout will be redirected.
stdout_file: string &optional;
## The filename/path to which the node's stderr will be redirected.
stderr_file: string &optional;
## Additional script filenames/paths that the node should load.
scripts: vector of string &default = vector();
## A cpu/core number to which the node will try to pin itself.
cpu_affinity: int &optional;
## The Cluster Layout definition. Each node in the Cluster Framework
## knows about the full, static cluster topology to which it belongs.
## Entries use node names for keys. The Supervisor framework will
## automatically translate this table into the right Cluster Framework
## configuration when spawning supervised-nodes. E.g. it will
## populate the both the CLUSTER_NODE environment variable and
## :zeek:see:`Cluster::nodes` table.
cluster: table[string] of ClusterEndpoint &default=table();
};
## The current status of a supervised node.
type NodeStatus: record {
## The desired node configuration.
node: NodeConfig;
## The current or last known process ID of the node. This may not
## be initialized if the process has not yet started.
pid: int &optional;
};
## The current status of a set of supervised nodes.
type Status: record {
## The status of supervised nodes, keyed by node names.
nodes: table[string] of NodeStatus;
};
## Create a new supervised node process.
## It's an error to call this from a process other than a Supervisor.
##
## node: the desired configuration for the new supervised node process.
##
## Returns: an empty string on success or description of the error/failure.
global create: function(node: NodeConfig): string;
## Retrieve current status of a supervised node process.
## It's an error to call this from a process other than a Supervisor.
##
## node: the name of the node to get the status of or an empty string
## to mean "all nodes".
##
## Returns: the current status of a set of nodes.
global status: function(node: string &default=""): Status;
## Restart a supervised node process by destroying (killing) and
## re-recreating it.
## It's an error to call this from a process other than a Supervisor.
##
## node: the name of the node to restart or an empty string to mean
## "all nodes".
##
## Returns: true on success.
global restart: function(node: string &default=""): bool;
## Destroy and remove a supervised node process.
## It's an error to call this from a process other than a Supervisor.
##
## node: the name of the node to destroy or an empty string to mean
## "all nodes".
##
## Returns: true on success.
global destroy: function(node: string &default=""): bool;
## Returns: true if this is the Supervisor process.
global is_supervisor: function(): bool;
## Returns: true if this is a supervised node process.
global is_supervised: function(): bool;
## Returns: the node configuration if this is a supervised node.
## It's an error to call this function from a process other than
## a supervised one.
global node: function(): NodeConfig;
}

View file

@ -0,0 +1,89 @@
##! The Zeek process supervision (remote) control API. This defines a Broker topic
##! prefix and events that can be used to control an external Zeek supervisor process.
##! This API was introduced in Zeek 3.1.0 and considered unstable until 4.0.0.
##! That is, it may change in various incompatible ways without warning or
##! deprecation until the stable 4.0.0 release.
@load ./api
module SupervisorControl;
export {
## The Broker topic prefix to use when subscribing to Supervisor API
## requests and when publishing Supervisor API responses. If you are
## publishing Supervisor requests, this is also the prefix string to use
## for their topic names.
const topic_prefix = "zeek/supervisor" &redef;
## Send a request to a remote Supervisor process to create a node.
##
## reqid: an arbitrary string that will be directly echoed in the response
##
## node: the desired configuration for the new supervised node process.
global SupervisorControl::create_request: event(reqid: string, node: Supervisor::NodeConfig);
## Handle a response from a Supervisor process that received
## :zeek:see:`SupervisorControl::create_request`.
##
## reqid: an arbitrary string matching the value in the original request.
##
## result: the return value of the remote call to
## :zeek:see:`Supervisor::create`.
global SupervisorControl::create_response: event(reqid: string, result: string);
## Send a request to a remote Supervisor process to retrieve node status.
##
## reqid: an arbitrary string that will be directly echoed in the response
##
## node: the name of the node to get status of or empty string to mean "all
## nodes".
global SupervisorControl::status_request: event(reqid: string, node: string);
## Handle a response from a Supervisor process that received
## :zeek:see:`SupervisorControl::status_request`.
##
## reqid: an arbitrary string matching the value in the original request.
##
## result: the return value of the remote call to
## :zeek:see:`Supervisor::status`.
global SupervisorControl::status_response: event(reqid: string, result: Supervisor::Status);
## Send a request to a remote Supervisor process to restart a node.
##
## reqid: an arbitrary string that will be directly echoed in the response
##
## node: the name of the node to restart or empty string to mean "all
## nodes".
global SupervisorControl::restart_request: event(reqid: string, node: string);
## Handle a response from a Supervisor process that received
## :zeek:see:`SupervisorControl::restart_request`.
##
## reqid: an arbitrary string matching the value in the original request.
##
## result: the return value of the remote call to
## :zeek:see:`Supervisor::restart`.
global SupervisorControl::restart_response: event(reqid: string, result: bool);
## Send a request to a remote Supervisor process to destroy a node.
##
## reqid: an arbitrary string that will be directly echoed in the response
##
## node: the name of the node to destory or empty string to mean "all
## nodes".
global SupervisorControl::destroy_request: event(reqid: string, node: string);
## Handle a response from a Supervisor process that received
## :zeek:see:`SupervisorControl::destroy_request`.
##
## reqid: an arbitrary string matching the value in the original request.
##
## result: the return value of the remote call to
## :zeek:see:`Supervisor::destroy`.
global SupervisorControl::destroy_response: event(reqid: string, result: bool);
## Send a request to a remote Supervisor to stop and shutdown its
## process tree. There is no response to this message as the Supervisor
## simply terminates on receipt.
global SupervisorControl::stop_request: event();
}

View file

@ -0,0 +1,94 @@
##! Implements Zeek process supervision API and default behavior for its
##! associated (remote) control events.
@load ./api
@load ./control
@load base/frameworks/broker
function Supervisor::status(node: string): Supervisor::Status
{
return Supervisor::__status(node);
}
function Supervisor::create(node: Supervisor::NodeConfig): string
{
return Supervisor::__create(node);
}
function Supervisor::destroy(node: string): bool
{
return Supervisor::__destroy(node);
}
function Supervisor::restart(node: string): bool
{
return Supervisor::__restart(node);
}
function Supervisor::is_supervisor(): bool
{
return Supervisor::__is_supervisor();
}
function Supervisor::is_supervised(): bool
{
return Supervisor::__is_supervised();
}
function Supervisor::node(): Supervisor::NodeConfig
{
return Supervisor::__node();
}
event zeek_init() &priority=10
{
Broker::subscribe(SupervisorControl::topic_prefix);
}
event SupervisorControl::stop_request()
{
if ( ! Supervisor::is_supervisor() )
return;
terminate();
}
event SupervisorControl::status_request(reqid: string, node: string)
{
if ( ! Supervisor::is_supervisor() )
return;
local res = Supervisor::status(node);
local topic = SupervisorControl::topic_prefix + fmt("/status_response/%s", reqid);
Broker::publish(topic, SupervisorControl::status_response, reqid, res);
}
event SupervisorControl::create_request(reqid: string, node: Supervisor::NodeConfig)
{
if ( ! Supervisor::is_supervisor() )
return;
local res = Supervisor::create(node);
local topic = SupervisorControl::topic_prefix + fmt("/create_response/%s", reqid);
Broker::publish(topic, SupervisorControl::create_response, reqid, res);
}
event SupervisorControl::destroy_request(reqid: string, node: string)
{
if ( ! Supervisor::is_supervisor() )
return;
local res = Supervisor::destroy(node);
local topic = SupervisorControl::topic_prefix + fmt("/destroy_response/%s", reqid);
Broker::publish(topic, SupervisorControl::destroy_response, reqid, res);
}
event SupervisorControl::restart_request(reqid: string, node: string)
{
if ( ! Supervisor::is_supervisor() )
return;
local res = Supervisor::restart(node);
local topic = SupervisorControl::topic_prefix + fmt("/restart_response/%s", reqid);
Broker::publish(topic, SupervisorControl::restart_response, reqid, res);
}

View file

@ -1835,6 +1835,8 @@ type gtp_delete_pdp_ctx_response_elements: record {
@load base/bif/reporter.bif @load base/bif/reporter.bif
@load base/bif/strings.bif @load base/bif/strings.bif
@load base/bif/option.bif @load base/bif/option.bif
@load base/frameworks/supervisor/api
@load base/bif/supervisor.bif
global done_with_network = F; global done_with_network = F;
event net_done(t: time) { done_with_network = T; } event net_done(t: time) { done_with_network = T; }

View file

@ -5,6 +5,7 @@
# the separate file). # the separate file).
@load base/frameworks/logging @load base/frameworks/logging
@load base/frameworks/broker @load base/frameworks/broker
@load base/frameworks/supervisor
@load base/frameworks/input @load base/frameworks/input
@load base/frameworks/analyzer @load base/frameworks/analyzer
@load base/frameworks/files @load base/frameworks/files

View file

@ -107,6 +107,11 @@ set(BIF_SRCS
strings.bif strings.bif
reporter.bif reporter.bif
option.bif option.bif
# Note: the supervisor BIF file is treated like other top-level BIFs
# instead of contained in its own subdirectory CMake logic because
# subdirectory BIFs are treated differently and don't support being called
# *during* parsing (e.g. within an @if directive).
supervisor/supervisor.bif
) )
foreach (bift ${BIF_SRCS}) foreach (bift ${BIF_SRCS})
@ -203,6 +208,7 @@ set(MAIN_SRCS
net_util.cc net_util.cc
util.cc util.cc
module_util.cc module_util.cc
zeek-affinity.cc
Anon.cc Anon.cc
Attr.cc Attr.cc
Base64.cc Base64.cc
@ -245,6 +251,7 @@ set(MAIN_SRCS
NetVar.cc NetVar.cc
Obj.cc Obj.cc
OpaqueVal.cc OpaqueVal.cc
Options.cc
PacketFilter.cc PacketFilter.cc
Pipe.cc Pipe.cc
PolicyFile.cc PolicyFile.cc
@ -284,6 +291,8 @@ set(MAIN_SRCS
modp_numtoa.c modp_numtoa.c
siphash24.c siphash24.c
supervisor/Supervisor.cc
threading/BasicThread.cc threading/BasicThread.cc
threading/Formatter.cc threading/Formatter.cc
threading/Manager.cc threading/Manager.cc

View file

@ -19,7 +19,8 @@ DebugLogger::Stream DebugLogger::streams[NUM_DBGS] = {
{ "threading", 0, false }, { "file_analysis", 0, false }, { "threading", 0, false }, { "file_analysis", 0, false },
{ "plugins", 0, false }, { "zeekygen", 0, false }, { "plugins", 0, false }, { "zeekygen", 0, false },
{ "pktio", 0, false }, { "broker", 0, false }, { "pktio", 0, false }, { "broker", 0, false },
{ "scripts", 0, false} { "scripts", 0, false},
{ "supervisor", 0, false}
}; };
DebugLogger::DebugLogger() DebugLogger::DebugLogger()

View file

@ -29,6 +29,7 @@ enum DebugStream {
DBG_PKTIO, // Packet sources and dumpers. DBG_PKTIO, // Packet sources and dumpers.
DBG_BROKER, // Broker communication DBG_BROKER, // Broker communication
DBG_SCRIPTS, // Script initialization DBG_SCRIPTS, // Script initialization
DBG_SUPERVISOR, // Process supervisor
NUM_DBGS // Has to be last NUM_DBGS // Has to be last
}; };

View file

@ -13,14 +13,24 @@ Flare::Flare()
{ {
} }
static void bad_pipe_op(const char* which) static void bad_pipe_op(const char* which, bool signal_safe)
{ {
if ( signal_safe )
abort();
char buf[256]; char buf[256];
bro_strerror_r(errno, buf, sizeof(buf)); bro_strerror_r(errno, buf, sizeof(buf));
reporter->FatalErrorWithCore("unexpected pipe %s failure: %s", which, buf);
if ( reporter )
reporter->FatalErrorWithCore("unexpected pipe %s failure: %s", which, buf);
else
{
fprintf(stderr, "unexpected pipe %s failure: %s", which, buf);
abort();
}
} }
void Flare::Fire() void Flare::Fire(bool signal_safe)
{ {
char tmp = 0; char tmp = 0;
@ -42,15 +52,16 @@ void Flare::Fire()
// Interrupted: try again. // Interrupted: try again.
continue; continue;
bad_pipe_op("write"); bad_pipe_op("write", signal_safe);
} }
// No error, but didn't write a byte: try again. // No error, but didn't write a byte: try again.
} }
} }
void Flare::Extinguish() int Flare::Extinguish(bool signal_safe)
{ {
int rval = 0;
char tmp[256]; char tmp[256];
for ( ; ; ) for ( ; ; )
@ -58,8 +69,11 @@ void Flare::Extinguish()
int n = read(pipe.ReadFD(), &tmp, sizeof(tmp)); int n = read(pipe.ReadFD(), &tmp, sizeof(tmp));
if ( n >= 0 ) if ( n >= 0 )
{
rval += n;
// Pipe may not be empty yet: try again. // Pipe may not be empty yet: try again.
continue; continue;
}
if ( errno == EAGAIN ) if ( errno == EAGAIN )
// Success: pipe is now empty. // Success: pipe is now empty.
@ -69,6 +83,8 @@ void Flare::Extinguish()
// Interrupted: try again. // Interrupted: try again.
continue; continue;
bad_pipe_op("read"); bad_pipe_op("read", signal_safe);
} }
return rval;
} }

View file

@ -26,13 +26,19 @@ public:
/** /**
* Put the object in the "ready" state. * Put the object in the "ready" state.
* @param signal_safe whether to skip error-reporting functionality that
* is not async-signal-safe (errors still abort the process regardless)
*/ */
void Fire(); void Fire(bool signal_safe = false);
/** /**
* Take the object out of the "ready" state. * Take the object out of the "ready" state.
* @param signal_safe whether to skip error-reporting functionality that
* is not async-signal-safe (errors still abort the process regardless)
* @return number of bytes read from the pipe, corresponds to the number
* of times Fire() was called.
*/ */
void Extinguish(); int Extinguish(bool signal_safe = false);
private: private:
Pipe pipe; Pipe pipe;

View file

@ -743,12 +743,14 @@ void builtin_error(const char* msg, BroObj* arg)
#include "reporter.bif.func_h" #include "reporter.bif.func_h"
#include "strings.bif.func_h" #include "strings.bif.func_h"
#include "option.bif.func_h" #include "option.bif.func_h"
#include "supervisor.bif.func_h"
#include "zeek.bif.func_def" #include "zeek.bif.func_def"
#include "stats.bif.func_def" #include "stats.bif.func_def"
#include "reporter.bif.func_def" #include "reporter.bif.func_def"
#include "strings.bif.func_def" #include "strings.bif.func_def"
#include "option.bif.func_def" #include "option.bif.func_def"
#include "supervisor.bif.func_def"
#include "__all__.bif.cc" // Autogenerated for compiling in the bif_target() code. #include "__all__.bif.cc" // Autogenerated for compiling in the bif_target() code.
#include "__all__.bif.register.cc" // Autogenerated for compiling in the bif_target() code. #include "__all__.bif.register.cc" // Autogenerated for compiling in the bif_target() code.
@ -776,6 +778,7 @@ void init_builtin_funcs()
#include "reporter.bif.func_init" #include "reporter.bif.func_init"
#include "strings.bif.func_init" #include "strings.bif.func_init"
#include "option.bif.func_init" #include "option.bif.func_init"
#include "supervisor.bif.func_init"
did_builtin_init = true; did_builtin_init = true;
} }

View file

@ -145,40 +145,40 @@ void net_update_time(double new_network_time)
PLUGIN_HOOK_VOID(HOOK_UPDATE_NETWORK_TIME, HookUpdateNetworkTime(new_network_time)); PLUGIN_HOOK_VOID(HOOK_UPDATE_NETWORK_TIME, HookUpdateNetworkTime(new_network_time));
} }
void net_init(name_list& interfaces, name_list& readfiles, void net_init(const std::vector<std::string>& interfaces,
const char* writefile, int do_watchdog) const std::vector<std::string>& pcap_input_files,
const std::optional<std::string>& pcap_output_file,
bool do_watchdog)
{ {
if ( readfiles.length() > 0 ) if ( ! pcap_input_files.empty() )
{ {
reading_live = pseudo_realtime > 0.0; reading_live = pseudo_realtime > 0.0;
reading_traces = 1; reading_traces = 1;
for ( int i = 0; i < readfiles.length(); ++i ) for ( const auto& pif : pcap_input_files )
{ {
iosource::PktSrc* ps = iosource_mgr->OpenPktSrc(readfiles[i], false); iosource::PktSrc* ps = iosource_mgr->OpenPktSrc(pif, false);
assert(ps); assert(ps);
if ( ! ps->IsOpen() ) if ( ! ps->IsOpen() )
reporter->FatalError("problem with trace file %s (%s)", reporter->FatalError("problem with trace file %s (%s)",
readfiles[i], pif.data(), ps->ErrorMsg());
ps->ErrorMsg());
} }
} }
else if ( interfaces.length() > 0 ) else if ( ! interfaces.empty() )
{ {
reading_live = 1; reading_live = 1;
reading_traces = 0; reading_traces = 0;
for ( int i = 0; i < interfaces.length(); ++i ) for ( const auto& iface : interfaces )
{ {
iosource::PktSrc* ps = iosource_mgr->OpenPktSrc(interfaces[i], true); iosource::PktSrc* ps = iosource_mgr->OpenPktSrc(iface, true);
assert(ps); assert(ps);
if ( ! ps->IsOpen() ) if ( ! ps->IsOpen() )
reporter->FatalError("problem with interface %s (%s)", reporter->FatalError("problem with interface %s (%s)",
interfaces[i], iface.data(), ps->ErrorMsg());
ps->ErrorMsg());
} }
} }
@ -189,8 +189,9 @@ void net_init(name_list& interfaces, name_list& readfiles,
// a timer. // a timer.
reading_traces = reading_live = 0; reading_traces = reading_live = 0;
if ( writefile ) if ( pcap_output_file )
{ {
const char* writefile = pcap_output_file->data();
pkt_dumper = iosource_mgr->OpenPktDumper(writefile, false); pkt_dumper = iosource_mgr->OpenPktDumper(writefile, false);
assert(pkt_dumper); assert(pkt_dumper);
@ -361,13 +362,11 @@ void net_run()
current_dispatched = 0; current_dispatched = 0;
current_iosrc = 0; current_iosrc = 0;
// Should we put the signal handling into an IOSource?
extern void termination_signal();
if ( signal_val == SIGTERM || signal_val == SIGINT ) if ( signal_val == SIGTERM || signal_val == SIGINT )
// We received a signal while processing the // We received a signal while processing the
// current packet and its related events. // current packet and its related events.
termination_signal(); // Should we put the signal handling into an IOSource?
zeek_terminate_loop("received termination signal");
if ( ! reading_traces ) if ( ! reading_traces )
// Check whether we have timers scheduled for // Check whether we have timers scheduled for

View file

@ -2,6 +2,10 @@
#pragma once #pragma once
#include <vector>
#include <string>
#include <optional>
#include "net_util.h" #include "net_util.h"
#include "util.h" #include "util.h"
#include "List.h" #include "List.h"
@ -10,8 +14,10 @@
#include "iosource/PktSrc.h" #include "iosource/PktSrc.h"
#include "iosource/PktDumper.h" #include "iosource/PktDumper.h"
extern void net_init(name_list& interfaces, name_list& readfiles, extern void net_init(const std::vector<std::string>& interfaces,
const char* writefile, int do_watchdog); const std::vector<std::string>& pcap_input_files,
const std::optional<std::string>& pcap_output_file,
bool do_watchdog);
extern void net_run(); extern void net_run();
extern void net_get_final_stats(); extern void net_get_final_stats();
extern void net_finish(int drain_events); extern void net_finish(int drain_events);
@ -20,7 +26,7 @@ extern void net_update_time(double new_network_time);
extern void net_packet_dispatch(double t, const Packet* pkt, extern void net_packet_dispatch(double t, const Packet* pkt,
iosource::PktSrc* src_ps); iosource::PktSrc* src_ps);
extern void expire_timers(iosource::PktSrc* src_ps = 0); extern void expire_timers(iosource::PktSrc* src_ps = 0);
extern void termination_signal(); extern void zeek_terminate_loop(const char* reason);
// Functions to temporarily suspend processing of live input (network packets // Functions to temporarily suspend processing of live input (network packets
// and remote events/state). Turning this is on is sure to lead to data loss! // and remote events/state). Turning this is on is sure to lead to data loss!
@ -76,8 +82,6 @@ extern iosource::IOSource* current_iosrc;
extern iosource::PktDumper* pkt_dumper; // where to save packets extern iosource::PktDumper* pkt_dumper; // where to save packets
extern char* writefile;
// Script file we have already scanned (or are in the process of scanning). // Script file we have already scanned (or are in the process of scanning).
// They are identified by inode number. // They are identified by inode number.
struct ScannedFile { struct ScannedFile {

View file

@ -196,6 +196,7 @@ bro_uint_t bits_per_uid;
#include "types.bif.netvar_def" #include "types.bif.netvar_def"
#include "event.bif.netvar_def" #include "event.bif.netvar_def"
#include "reporter.bif.netvar_def" #include "reporter.bif.netvar_def"
#include "supervisor.bif.netvar_def"
void init_event_handlers() void init_event_handlers()
{ {
@ -240,6 +241,7 @@ void init_net_var()
#include "const.bif.netvar_init" #include "const.bif.netvar_init"
#include "types.bif.netvar_init" #include "types.bif.netvar_init"
#include "reporter.bif.netvar_init" #include "reporter.bif.netvar_init"
#include "supervisor.bif.netvar_init"
conn_id = internal_type("conn_id")->AsRecordType(); conn_id = internal_type("conn_id")->AsRecordType();
endpoint = internal_type("endpoint")->AsRecordType(); endpoint = internal_type("endpoint")->AsRecordType();

View file

@ -203,3 +203,4 @@ extern void init_net_var();
#include "types.bif.netvar_h" #include "types.bif.netvar_h"
#include "event.bif.netvar_h" #include "event.bif.netvar_h"
#include "reporter.bif.netvar_h" #include "reporter.bif.netvar_h"
#include "supervisor.bif.netvar_h"

460
src/Options.cc Normal file
View file

@ -0,0 +1,460 @@
// 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()
{
pcap_filter = {};
interfaces = {};
pcap_files = {};
signature_files = {};
pcap_output_file = {};
}
void zeek::Options::filter_supervised_node_options()
{
auto og = *this;
*this = {};
debug_log_streams = og.debug_log_streams;
debug_script_tracing_file = og.debug_script_tracing_file;
script_code_to_exec = og.script_code_to_exec;
script_prefixes = og.script_prefixes;
signature_re_level = og.signature_re_level;
ignore_checksums = og.ignore_checksums;
use_watchdog = og.use_watchdog;
pseudo_realtime = og.pseudo_realtime;
dns_mode = og.dns_mode;
bare_mode = og.bare_mode;
perftools_check_leaks = og.perftools_check_leaks;
perftools_profile = og.perftools_profile;
pcap_filter = og.pcap_filter;
signature_files = og.signature_files;
// TODO: These are likely to be handled in a node-specific or
// use-case-specific way. e.g. interfaces is already handled for the
// "cluster" use-case, but don't have supervised-pcap-reading
// functionality yet.
/* interfaces = og.interfaces; */
/* pcap_files = og.pcap_files; */
pcap_output_file = og.pcap_output_file;
random_seed_input_file = og.random_seed_input_file;
random_seed_output_file = og.random_seed_output_file;
process_status_file = og.process_status_file;
plugins_to_load = og.plugins_to_load;
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;
}

97
src/Options.h Normal file
View file

@ -0,0 +1,97 @@
// See the file "COPYING" in the main distribution directory for copyright.
#pragma once
#include <optional>
#include <string>
#include <vector>
#include "DNS_Mgr.h"
namespace zeek {
/**
* Options that define general Zeek processing behavior, usually determined
* from command-line arguments.
*/
struct Options {
/**
* Unset options that aren't meant to be used by the supervisor, but may
* make sense for supervised nodes to inherit (as opposed to flagging
* as an error an exiting outright if used in supervisor-mode).
*/
void filter_supervisor_options();
/**
* Inherit certain options set in the original supervisor parent process
* and discard the rest.
*/
void filter_supervised_node_options();
bool print_version = false;
bool print_usage = false;
bool print_execution_time = false;
bool print_signature_debug_info = false;
int print_plugins = 0;
std::optional<std::string> debug_log_streams;
std::optional<std::string> debug_script_tracing_file;
std::optional<std::string> identifier_to_print;
std::optional<std::string> script_code_to_exec;
std::vector<std::string> script_prefixes = { "" }; // "" = "no prefix"
int signature_re_level = 4;
bool ignore_checksums = false;
bool use_watchdog = false;
double pseudo_realtime = 0;
DNS_MgrMode dns_mode = DNS_DEFAULT;
bool supervisor_mode = false;
bool parse_only = false;
bool bare_mode = false;
bool debug_scripts = false;
bool perftools_check_leaks = false;
bool perftools_profile = false;
bool run_unit_tests = false;
std::vector<std::string> doctest_args;
std::optional<std::string> pcap_filter;
std::vector<std::string> interfaces;
std::vector<std::string> pcap_files;
std::vector<std::string> signature_files;
std::optional<std::string> pcap_output_file;
std::optional<std::string> random_seed_input_file;
std::optional<std::string> random_seed_output_file;
std::optional<std::string> process_status_file;
std::optional<std::string> zeekygen_config_file;
std::string libidmef_dtd_file = "idmef-message.dtd";
std::set<std::string> plugins_to_load;
std::vector<std::string> scripts_to_load;
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

View file

@ -13,24 +13,59 @@ static void pipe_fail(int eno)
{ {
char tmp[256]; char tmp[256];
bro_strerror_r(eno, tmp, sizeof(tmp)); bro_strerror_r(eno, tmp, sizeof(tmp));
reporter->FatalError("Pipe failure: %s", tmp);
if ( reporter )
reporter->FatalError("Pipe failure: %s", tmp);
else
fprintf(stderr, "Pipe failure: %s", tmp);
} }
static void set_flags(int fd, int flags) static int set_flags(int fd, int flags)
{ {
auto rval = fcntl(fd, F_GETFD);
if ( flags ) if ( flags )
if ( fcntl(fd, F_SETFD, fcntl(fd, F_GETFD) | flags) == -1 ) {
rval |= flags;
if ( fcntl(fd, F_SETFD, rval) == -1 )
pipe_fail(errno); pipe_fail(errno);
}
return rval;
} }
static void set_status_flags(int fd, int flags) static int unset_flags(int fd, int flags)
{ {
auto rval = fcntl(fd, F_GETFD);
if ( flags ) if ( flags )
if ( fcntl(fd, F_SETFL, fcntl(fd, F_GETFL) | flags) == -1 ) {
rval &= ~flags;
if ( fcntl(fd, F_SETFD, rval) == -1 )
pipe_fail(errno); pipe_fail(errno);
}
return rval;
} }
static int dup_or_fail(int fd, int flags) static int set_status_flags(int fd, int flags)
{
auto rval = fcntl(fd, F_GETFL);
if ( flags )
{
rval |= flags;
if ( fcntl(fd, F_SETFL, rval) == -1 )
pipe_fail(errno);
}
return rval;
}
static int dup_or_fail(int fd, int flags, int status_flags)
{ {
int rval = dup(fd); int rval = dup(fd);
@ -38,22 +73,41 @@ static int dup_or_fail(int fd, int flags)
pipe_fail(errno); pipe_fail(errno);
set_flags(fd, flags); set_flags(fd, flags);
set_status_flags(fd, status_flags);
return rval; return rval;
} }
Pipe::Pipe(int flags0, int flags1, int status_flags0, int status_flags1) Pipe::Pipe(int flags0, int flags1, int status_flags0, int status_flags1,
int* arg_fds)
{ {
// pipe2 can set flags atomically, but not yet available everywhere. if ( arg_fds )
if ( ::pipe(fds) ) {
pipe_fail(errno); fds[0] = arg_fds[0];
fds[1] = arg_fds[1];
}
else
{
// pipe2 can set flags atomically, but not yet available everywhere.
if ( ::pipe(fds) )
pipe_fail(errno);
}
flags[0] = flags0; flags[0] = set_flags(fds[0], flags[0]);
flags[1] = flags1; flags[1] = set_flags(fds[1], flags[1]);
status_flags[0] = set_status_flags(fds[0], status_flags0);
status_flags[1] = set_status_flags(fds[1], status_flags1);
}
set_flags(fds[0], flags[0]); void Pipe::SetFlags(int arg_flags)
set_flags(fds[1], flags[1]); {
set_status_flags(fds[0], status_flags0); flags[0] = set_flags(fds[0], arg_flags);
set_status_flags(fds[1], status_flags1); flags[1] = set_flags(fds[1], arg_flags);
}
void Pipe::UnsetFlags(int arg_flags)
{
flags[0] = unset_flags(fds[0], arg_flags);
flags[1] = unset_flags(fds[1], arg_flags);
} }
Pipe::~Pipe() Pipe::~Pipe()
@ -64,10 +118,12 @@ Pipe::~Pipe()
Pipe::Pipe(const Pipe& other) Pipe::Pipe(const Pipe& other)
{ {
fds[0] = dup_or_fail(other.fds[0], other.flags[0]); fds[0] = dup_or_fail(other.fds[0], other.flags[0], other.status_flags[0]);
fds[1] = dup_or_fail(other.fds[1], other.flags[1]); fds[1] = dup_or_fail(other.fds[1], other.flags[1], other.status_flags[1]);
flags[0] = other.flags[0]; flags[0] = other.flags[0];
flags[1] = other.flags[1]; flags[1] = other.flags[1];
status_flags[0] = other.status_flags[0];
status_flags[1] = other.status_flags[1];
} }
Pipe& Pipe::operator=(const Pipe& other) Pipe& Pipe::operator=(const Pipe& other)
@ -77,9 +133,17 @@ Pipe& Pipe::operator=(const Pipe& other)
close(fds[0]); close(fds[0]);
close(fds[1]); close(fds[1]);
fds[0] = dup_or_fail(other.fds[0], other.flags[0]); fds[0] = dup_or_fail(other.fds[0], other.flags[0], other.status_flags[0]);
fds[1] = dup_or_fail(other.fds[1], other.flags[1]); fds[1] = dup_or_fail(other.fds[1], other.flags[1], other.status_flags[1]);
flags[0] = other.flags[0]; flags[0] = other.flags[0];
flags[1] = other.flags[1]; flags[1] = other.flags[1];
status_flags[0] = other.status_flags[0];
status_flags[1] = other.status_flags[1];
return *this; return *this;
} }
PipePair::PipePair(int flags, int status_flags, int* fds)
: pipes{Pipe(flags, flags, status_flags, status_flags, fds ? fds + 0 : nullptr),
Pipe(flags, flags, status_flags, status_flags, fds ? fds + 2 : nullptr)}
{
}

View file

@ -13,9 +13,12 @@ public:
* @param flags1 file descriptor flags to set on write end of pipe. * @param flags1 file descriptor flags to set on write end of pipe.
* @param status_flags0 descriptor status flags to set on read end of pipe. * @param status_flags0 descriptor status flags to set on read end of pipe.
* @param status_flags1 descriptor status flags to set on write end of pipe. * @param status_flags1 descriptor status flags to set on write end of pipe.
* @param fds may be supplied to open an existing file descriptors rather
* than create ones from a new pipe. Should point to memory containing
* two consecutive file descriptors, the "read" one and then the "write" one.
*/ */
explicit Pipe(int flags0 = 0, int flags1 = 0, int status_flags0 = 0, explicit Pipe(int flags0 = 0, int flags1 = 0, int status_flags0 = 0,
int status_flags1 = 0); int status_flags1 = 0, int* fds = nullptr);
/** /**
* Close the pair of file descriptors owned by the object. * Close the pair of file descriptors owned by the object.
@ -45,9 +48,92 @@ public:
int WriteFD() const int WriteFD() const
{ return fds[1]; } { return fds[1]; }
/**
* Sets the given file descriptor flags for both the read and write end
* of the pipe.
*/
void SetFlags(int flags);
/**
* Unsets the given file descriptor flags for both the read and write end
* of the pipe.
*/
void UnsetFlags(int flags);
private: private:
int fds[2]; int fds[2];
int flags[2]; int flags[2];
int status_flags[2];
};
/**
* A pair of pipes that can be used for bi-directinoal IPC.
*/
class PipePair {
public:
/**
* Create a pair of pipes
* @param flags file descriptor flags to set on pipes
* @status_flags descriptor status flags to set on pipes
* @fds may be supplied to open existing file descriptors rather
* than create ones from a new pair of pipes. Should point to memory
* containing four consecutive file descriptors, "read" end and "write" end
* of the first pipe followed by the "read" end and "write" end of the
* second pipe.
*/
PipePair(int flags, int status_flags, int* fds = nullptr);
/**
* @return the pipe used for receiving input
*/
Pipe& In()
{ return pipes[swapped]; }
/**
* @return the pipe used for sending output
*/
Pipe& Out()
{ return pipes[!swapped]; }
/**
* @return the pipe used for receiving input
*/
const Pipe& In() const
{ return pipes[swapped]; }
/**
* @return the pipe used for sending output
*/
const Pipe& Out() const
{ return pipes[!swapped]; }
/**
* @return a file descriptor that may used for receiving messages by
* polling/reading it.
*/
int InFD() const
{ return In().ReadFD(); }
/**
* @return a file descriptor that may be used for sending messages by
* writing to it.
*/
int OutFD() const
{ return Out().WriteFD(); }
/**
* Swaps the meaning of the pipes in the pair. E.g. call this after
* fork()'ing so that the child process uses the right pipe for
* reading/writing.
*/
void Swap()
{ swapped = ! swapped; }
private:
Pipe pipes[2];
bool swapped = false;
}; };
} // namespace bro } // namespace bro

View file

@ -231,7 +231,7 @@ void RuleMatcher::Delete(RuleHdrTest* node)
delete node; delete node;
} }
bool RuleMatcher::ReadFiles(const name_list& files) bool RuleMatcher::ReadFiles(const std::vector<std::string>& files)
{ {
#ifdef USE_PERFTOOLS_DEBUG #ifdef USE_PERFTOOLS_DEBUG
HeapLeakChecker::Disabler disabler; HeapLeakChecker::Disabler disabler;
@ -239,18 +239,18 @@ bool RuleMatcher::ReadFiles(const name_list& files)
parse_error = false; parse_error = false;
for ( int i = 0; i < files.length(); ++i ) for ( const auto& f : files )
{ {
rules_in = open_file(find_file(files[i], bro_path(), ".sig")); rules_in = open_file(find_file(f, bro_path(), ".sig"));
if ( ! rules_in ) if ( ! rules_in )
{ {
reporter->Error("Can't open signature file %s", files[i]); reporter->Error("Can't open signature file %s", f.data());
return false; return false;
} }
rules_line_number = 0; rules_line_number = 0;
current_rule_file = files[i]; current_rule_file = f.data();
rules_parse(); rules_parse();
fclose(rules_in); fclose(rules_in);
} }

View file

@ -221,7 +221,7 @@ public:
~RuleMatcher(); ~RuleMatcher();
// Parse the given files and built up data structures. // Parse the given files and built up data structures.
bool ReadFiles(const name_list& files); bool ReadFiles(const std::vector<std::string>& files);
/** /**
* Inititialize a state object for matching file magic signatures. * Inititialize a state object for matching file magic signatures.

View file

@ -37,6 +37,7 @@ const char* TimerNames[] = {
"TCPConnectionPartialClose", "TCPConnectionPartialClose",
"TCPConnectionResetTimer", "TCPConnectionResetTimer",
"TriggerTimer", "TriggerTimer",
"ParentProcessIDCheck",
"TimerMgrExpireTimer", "TimerMgrExpireTimer",
}; };

View file

@ -41,6 +41,7 @@ enum TimerType : uint8_t {
TIMER_TCP_PARTIAL_CLOSE, TIMER_TCP_PARTIAL_CLOSE,
TIMER_TCP_RESET, TIMER_TCP_RESET,
TIMER_TRIGGER, TIMER_TRIGGER,
TIMER_PPID_CHECK,
TIMER_TIMERMGR_EXPIRE, TIMER_TIMERMGR_EXPIRE,
}; };
const int NUM_TIMER_TYPES = int(TIMER_TIMERMGR_EXPIRE) + 1; const int NUM_TIMER_TYPES = int(TIMER_TIMERMGR_EXPIRE) + 1;

View file

@ -37,8 +37,8 @@ extern int bro_argc;
extern char** bro_argv; extern char** bro_argv;
extern const char* prog; extern const char* prog;
extern name_list prefixes; // -p flag extern std::vector<std::string> zeek_script_prefixes; // -p flag
extern char* command_line_policy; // -e flag extern const char* command_line_policy; // -e flag
extern std::vector<std::string> params; extern std::vector<std::string> params;
class Stmt; class Stmt;

View file

@ -7,10 +7,9 @@
#include <unistd.h> #include <unistd.h>
#include <signal.h> #include <signal.h>
#include <string.h> #include <string.h>
#include <sys/types.h>
#include <list> #include <list>
#ifdef HAVE_GETOPT_H #include <optional>
#include <getopt.h>
#endif
#ifdef USE_IDMEF #ifdef USE_IDMEF
extern "C" { extern "C" {
@ -21,7 +20,7 @@ extern "C" {
#include <openssl/ssl.h> #include <openssl/ssl.h>
#include <openssl/err.h> #include <openssl/err.h>
#include "bsd-getopt-long.h" #include "Options.h"
#include "input.h" #include "input.h"
#include "DNS_Mgr.h" #include "DNS_Mgr.h"
#include "Frame.h" #include "Frame.h"
@ -43,10 +42,10 @@ extern "C" {
#include "Brofiler.h" #include "Brofiler.h"
#include "Traverse.h" #include "Traverse.h"
#include "supervisor/Supervisor.h"
#include "threading/Manager.h" #include "threading/Manager.h"
#include "input/Manager.h" #include "input/Manager.h"
#include "logging/Manager.h" #include "logging/Manager.h"
#include "logging/writers/ascii/Ascii.h"
#include "input/readers/raw/Raw.h" #include "input/readers/raw/Raw.h"
#include "analyzer/Manager.h" #include "analyzer/Manager.h"
#include "analyzer/Tag.h" #include "analyzer/Tag.h"
@ -94,10 +93,9 @@ file_analysis::Manager* file_mgr = 0;
zeekygen::Manager* zeekygen_mgr = 0; zeekygen::Manager* zeekygen_mgr = 0;
iosource::Manager* iosource_mgr = 0; iosource::Manager* iosource_mgr = 0;
bro_broker::Manager* broker_mgr = 0; bro_broker::Manager* broker_mgr = 0;
zeek::Supervisor* zeek::supervisor_mgr = 0;
const char* prog; std::vector<std::string> zeek_script_prefixes;
char* writefile = 0;
name_list prefixes;
Stmt* stmts; Stmt* stmts;
EventHandlerPtr net_done = 0; EventHandlerPtr net_done = 0;
RuleMatcher* rule_matcher = 0; RuleMatcher* rule_matcher = 0;
@ -107,10 +105,10 @@ ProfileLogger* segment_logger = 0;
SampleLogger* sample_logger = 0; SampleLogger* sample_logger = 0;
int signal_val = 0; int signal_val = 0;
extern char version[]; extern char version[];
char* command_line_policy = 0; const char* command_line_policy = 0;
vector<string> params; vector<string> params;
set<string> requested_plugins; set<string> requested_plugins;
char* proc_status_file = 0; const char* proc_status_file = 0;
OpaqueType* md5_type = 0; OpaqueType* md5_type = 0;
OpaqueType* sha1_type = 0; OpaqueType* sha1_type = 0;
@ -145,74 +143,15 @@ const char* zeek_version()
#endif #endif
} }
bool bro_dns_fake() static std::vector<const char*> to_cargs(const std::vector<std::string>& args)
{ {
return zeekenv("ZEEK_DNS_FAKE"); std::vector<const char*> rval;
} rval.reserve(args.size());
void usage(int code = 1) for ( const auto& arg : args )
{ rval.emplace_back(arg.data());
fprintf(stderr, "zeek version %s\n", zeek_version());
fprintf(stderr, "usage: %s [options] [file ...]\n", prog); return rval;
fprintf(stderr, "usage: %s --test [doctest-options] -- [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, " --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", 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) bool show_plugins(int level)
@ -359,6 +298,7 @@ void terminate_bro()
delete analyzer_mgr; delete analyzer_mgr;
delete file_mgr; delete file_mgr;
// broker_mgr is deleted via iosource_mgr // broker_mgr is deleted via iosource_mgr
// supervisor is deleted via iosource_mgr
delete iosource_mgr; delete iosource_mgr;
delete log_mgr; delete log_mgr;
delete reporter; delete reporter;
@ -369,11 +309,11 @@ void terminate_bro()
reporter = 0; reporter = 0;
} }
void termination_signal() void zeek_terminate_loop(const char* reason)
{ {
set_processing_status("TERMINATING", "termination_signal"); set_processing_status("TERMINATING", reason);
reporter->Info("%s", reason);
reporter->Info("received termination signal");
net_get_final_stats(); net_get_final_stats();
done_with_network(); done_with_network();
net_delete(); net_delete();
@ -407,327 +347,141 @@ static void bro_new_handler()
out_of_memory("new"); out_of_memory("new");
} }
static std::vector<std::string> get_script_signature_files()
{
std::vector<std::string> rval;
// Parse rule files defined on the script level.
char* script_signature_files =
copy_string(internal_val("signature_files")->AsString()->CheckString());
char* tmp = script_signature_files;
char* s;
while ( (s = strsep(&tmp, " \t")) )
if ( *s )
rval.emplace_back(s);
delete [] script_signature_files;
return rval;
}
static std::string get_exe_path(const std::string& invocation)
{
if ( invocation.empty() )
return "";
if ( invocation[0] == '/' || invocation[0] == '~' )
// Absolute path
return invocation;
if ( invocation.find('/') != std::string::npos )
{
// Relative path
char cwd[PATH_MAX];
if ( ! getcwd(cwd, sizeof(cwd)) )
{
fprintf(stderr, "failed to get current directory: %s\n",
strerror(errno));
exit(1);
}
return std::string(cwd) + "/" + invocation;
}
auto path = getenv("PATH");
if ( ! path )
return "";
return find_file(invocation, path);
}
int main(int argc, char** argv) int main(int argc, char** argv)
{ {
ZEEK_LSAN_DISABLE(); ZEEK_LSAN_DISABLE();
std::set_new_handler(bro_new_handler); std::set_new_handler(bro_new_handler);
// When running unit tests, the first argument on the command line must be auto zeek_exe_path = get_exe_path(argv[0]);
// --test, followed by doctest options. Optionally, users can use "--" as
// separator to pass Zeek options afterwards:
//
// zeek --test [doctest-options] -- [zeek-options]
if ( argc > 1 && strcmp(argv[1], "--test") == 0 ) if ( zeek_exe_path.empty() )
{ {
// Deal with CLI arguments (copy Zeek part over to bro_argv). fprintf(stderr, "failed to get path to executable '%s'", argv[0]);
auto is_separator = [](const char* cstr) exit(1);
{ }
return strcmp(cstr, "--") == 0;
};
auto first = argv;
auto last = argv + argc;
auto separator = std::find_if(first, last, is_separator);
if ( separator == last ) bro_argc = argc;
{ bro_argv = new char* [argc];
bro_argc = 1;
bro_argv = new char*[1];
bro_argv[0] = copy_string(argv[0]);
}
else
{
auto first_zeek_arg = std::next(separator);
bro_argc = 1 + std::distance(first_zeek_arg, last);
bro_argv = new char*[bro_argc];
bro_argv[0] = copy_string(argv[0]);
auto bro_argv_iter = std::next(bro_argv);
for ( auto i = first_zeek_arg; i != last; ++i )
*bro_argv_iter++ = copy_string(*i);
}
#ifdef DOCTEST_CONFIG_DISABLE for ( int i = 0; i < argc; i++ )
fprintf(stderr, "ERROR: C++ unit tests are disabled for this build.\n" bro_argv[i] = copy_string(argv[i]);
" Please re-compile with ENABLE_ZEEK_UNIT_TESTS "
"to run the C++ unit tests.\n"); auto options = zeek::parse_cmdline(argc, argv);
return EXIT_FAILURE;
#else if ( options.print_usage )
zeek::usage(argv[0], 0);
if ( options.print_version )
{
fprintf(stdout, "%s version %s\n", argv[0], zeek_version());
exit(0);
}
if ( options.run_unit_tests )
{
doctest::Context context; doctest::Context context;
context.applyCommandLine(std::distance(first, separator), argv); auto dargs = to_cargs(options.doctest_args);
context.applyCommandLine(dargs.size(), dargs.data());
ZEEK_LSAN_ENABLE(); ZEEK_LSAN_ENABLE();
return context.run(); return context.run();
#endif
} }
else
{
bro_argc = argc;
bro_argv = new char* [argc];
for ( int i = 0; i < argc; i++ ) auto stem_state = zeek::Supervisor::CreateStem(options.supervisor_mode);
bro_argv[i] = copy_string(argv[i]);
} if ( zeek::Supervisor::ThisNode() )
zeek::Supervisor::ThisNode()->Init(&options);
double time_start = current_time(true); double time_start = current_time(true);
brofiler.ReadStats(); brofiler.ReadStats();
name_list interfaces; auto dns_type = options.dns_mode;
name_list read_files;
name_list rule_files;
char* id_name = 0;
char* seed_load_file = zeekenv("ZEEK_SEED_FILE"); if ( dns_type == DNS_DEFAULT && zeek::fake_dns() )
char* seed_save_file = 0; dns_type = DNS_FAKE;
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'},
{"test", no_argument, 0, '#'},
{0, 0, 0, 0},
};
enum DNS_MgrMode dns_type = DNS_DEFAULT;
dns_type = bro_dns_fake() ? DNS_FAKE : DNS_DEFAULT;
RETSIGTYPE (*oldhandler)(int); RETSIGTYPE (*oldhandler)(int);
prog = argv[0]; zeek_script_prefixes = options.script_prefixes;
auto zeek_prefixes = zeekenv("ZEEK_PREFIXES");
prefixes.push_back(strdup("")); // "" = "no prefix" if ( zeek_prefixes )
tokenize_string(zeek_prefixes, ":", &zeek_script_prefixes);
char* p = zeekenv("ZEEK_PREFIXES"); pseudo_realtime = options.pseudo_realtime;
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 #ifdef USE_PERFTOOLS_DEBUG
strncat(opts, "mM", 2); perftools_leaks = options.perftools_check_leaks;
perftools_profile = options.perftools_profile;
#endif #endif
int op; if ( options.debug_scripts )
while ( (op = getopt_long(bro_argc, bro_argv, opts, long_opts, &long_optsind)) != EOF ) {
switch ( op ) { g_policy_debug = options.debug_scripts;
case 'a': fprintf(stderr, "Zeek script debugging ON.\n");
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.push_back(optarg);
break;
case 'p':
prefixes.push_back(optarg);
break;
case 'r':
read_files.push_back(optarg);
break;
case 's':
rule_files.push_back(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 '#':
fprintf(stderr, "ERROR: --test only allowed as first argument.\n");
usage(1);
break;
case 0:
// This happens for long options that don't have
// a short-option equivalent.
break;
case '?':
default:
usage(1);
break;
} }
if ( interfaces.length() > 0 && read_files.length() > 0 ) if ( options.script_code_to_exec )
usage(1); command_line_policy = options.script_code_to_exec->data();
if ( options.debug_script_tracing_file )
{
g_trace_state.SetTraceFile(options.debug_script_tracing_file->data());
g_trace_state.TraceOn();
}
if ( options.process_status_file )
proc_status_file = options.process_status_file->data();
atexit(atexit_handler); atexit(atexit_handler);
set_processing_status("INITIALIZING", "main"); set_processing_status("INITIALIZING", "main");
@ -741,14 +495,33 @@ int main(int argc, char** argv)
plugin_mgr = new plugin::Manager(); plugin_mgr = new plugin::Manager();
#ifdef DEBUG #ifdef DEBUG
if ( debug_streams ) if ( options.debug_log_streams )
{ {
debug_logger.EnableStreams(debug_streams); debug_logger.EnableStreams(options.debug_log_streams->data());
debug_logger.OpenDebugLog("debug");
if ( getenv("ZEEK_DEBUG_LOG_STDERR") )
debug_logger.OpenDebugLog(nullptr);
else
debug_logger.OpenDebugLog("debug");
} }
#endif #endif
init_random_seed((seed_load_file && *seed_load_file ? seed_load_file : 0) , seed_save_file); if ( options.supervisor_mode )
{
zeek::Supervisor::Config cfg = {};
cfg.zeek_exe_path = zeek_exe_path;
options.filter_supervisor_options();
zeek::supervisor_mgr = new zeek::Supervisor(std::move(cfg),
std::move(*stem_state));
}
const char* seed_load_file = zeekenv("ZEEK_SEED_FILE");
if ( options.random_seed_input_file )
seed_load_file = options.random_seed_input_file->data();
init_random_seed((seed_load_file && *seed_load_file ? seed_load_file : 0),
options.random_seed_output_file ? options.random_seed_output_file->data() : 0);
// DEBUG_MSG("HMAC key: %s\n", md5_digest_print(shared_hmac_md5_key)); // DEBUG_MSG("HMAC key: %s\n", md5_digest_print(shared_hmac_md5_key));
init_hash_function(); init_hash_function();
@ -767,9 +540,9 @@ int main(int argc, char** argv)
reporter->Error("Failed to initialize sqlite3: %s", sqlite3_errstr(r)); reporter->Error("Failed to initialize sqlite3: %s", sqlite3_errstr(r));
#ifdef USE_IDMEF #ifdef USE_IDMEF
char* libidmef_dtd_path_cstr = new char[libidmef_dtd_path.length() + 1]; char* libidmef_dtd_path_cstr = new char[options.libidmef_dtd_file.size() + 1];
safe_strncpy(libidmef_dtd_path_cstr, libidmef_dtd_path.c_str(), safe_strncpy(libidmef_dtd_path_cstr, options.libidmef_dtd_file.data(),
libidmef_dtd_path.length()); options.libidmef_dtd_file.size());
globalsInit(libidmef_dtd_path_cstr); // Init LIBIDMEF globals globalsInit(libidmef_dtd_path_cstr); // Init LIBIDMEF globals
createCurrentDoc("1.0"); // Set a global XML document createCurrentDoc("1.0"); // Set a global XML document
#endif #endif
@ -777,34 +550,34 @@ int main(int argc, char** argv)
timer_mgr = new PQ_TimerMgr("<GLOBAL>"); timer_mgr = new PQ_TimerMgr("<GLOBAL>");
// timer_mgr = new CQ_TimerMgr(); // timer_mgr = new CQ_TimerMgr();
zeekygen_mgr = new zeekygen::Manager(zeekygen_config, bro_argv[0]); auto zeekygen_cfg = options.zeekygen_config_file.value_or("");
zeekygen_mgr = new zeekygen::Manager(zeekygen_cfg, bro_argv[0]);
add_essential_input_file("base/init-bare.zeek"); add_essential_input_file("base/init-bare.zeek");
add_essential_input_file("base/init-frameworks-and-bifs.zeek"); add_essential_input_file("base/init-frameworks-and-bifs.zeek");
if ( ! bare_mode ) if ( ! options.bare_mode )
add_input_file("base/init-default.zeek"); add_input_file("base/init-default.zeek");
plugin_mgr->SearchDynamicPlugins(bro_plugin_path()); plugin_mgr->SearchDynamicPlugins(bro_plugin_path());
if ( optind == bro_argc && if ( options.plugins_to_load.empty() && options.scripts_to_load.empty() &&
read_files.length() == 0 && options.script_options_to_set.empty() &&
interfaces.length() == 0 && options.pcap_files.size() == 0 &&
! id_name && ! command_line_policy && ! print_plugins ) options.interfaces.size() == 0 &&
! options.identifier_to_print &&
! command_line_policy && ! options.print_plugins &&
! options.supervisor_mode && ! zeek::Supervisor::ThisNode() )
add_input_file("-"); add_input_file("-");
// Process remaining arguments. X=Y arguments indicate script for ( const auto& script_option : options.script_options_to_set )
// variable/parameter assignments. X::Y arguments indicate plugins to params.push_back(script_option);
// activate/query. The remainder are treated as scripts to load.
while ( optind < bro_argc ) for ( const auto& plugin : options.plugins_to_load )
{ requested_plugins.insert(plugin);
if ( strchr(bro_argv[optind], '=') )
params.push_back(bro_argv[optind++]); for ( const auto& script : options.scripts_to_load )
else if ( strstr(bro_argv[optind], "::") ) add_input_file(script.data());
requested_plugins.insert(bro_argv[optind++]);
else
add_input_file(bro_argv[optind++]);
}
push_scope(nullptr, nullptr); push_scope(nullptr, nullptr);
@ -821,7 +594,7 @@ int main(int argc, char** argv)
log_mgr = new logging::Manager(); log_mgr = new logging::Manager();
input_mgr = new input::Manager(); input_mgr = new input::Manager();
file_mgr = new file_analysis::Manager(); file_mgr = new file_analysis::Manager();
broker_mgr = new bro_broker::Manager(read_files.length() > 0); broker_mgr = new bro_broker::Manager(! options.pcap_files.empty());
plugin_mgr->InitPreScript(); plugin_mgr->InitPreScript();
analyzer_mgr->InitPreScript(); analyzer_mgr->InitPreScript();
@ -840,7 +613,7 @@ int main(int argc, char** argv)
if ( missing_plugin ) if ( missing_plugin )
reporter->FatalError("Failed to activate requested dynamic plugin(s)."); reporter->FatalError("Failed to activate requested dynamic plugin(s).");
plugin_mgr->ActivateDynamicPlugins(! bare_mode); plugin_mgr->ActivateDynamicPlugins(! options.bare_mode);
init_event_handlers(); init_event_handlers();
@ -896,9 +669,9 @@ int main(int argc, char** argv)
zeekygen_mgr->InitPostScript(); zeekygen_mgr->InitPostScript();
broker_mgr->InitPostScript(); broker_mgr->InitPostScript();
if ( print_plugins ) if ( options.print_plugins )
{ {
bool success = show_plugins(print_plugins); bool success = show_plugins(options.print_plugins);
exit(success ? 0 : 1); exit(success ? 0 : 1);
} }
@ -906,7 +679,7 @@ int main(int argc, char** argv)
file_mgr->InitPostScript(); file_mgr->InitPostScript();
dns_mgr->InitPostScript(); dns_mgr->InitPostScript();
if ( parse_only ) if ( options.parse_only )
{ {
int rc = (reporter->Errors() > 0 ? 1 : 0); int rc = (reporter->Errors() > 0 ? 1 : 0);
exit(rc); exit(rc);
@ -925,52 +698,48 @@ int main(int argc, char** argv)
reporter->InitOptions(); reporter->InitOptions();
zeekygen_mgr->GenerateDocs(); zeekygen_mgr->GenerateDocs();
if ( user_pcap_filter ) if ( options.pcap_filter )
{ {
ID* id = global_scope()->Lookup("cmd_line_bpf_filter"); ID* id = global_scope()->Lookup("cmd_line_bpf_filter");
if ( ! id ) if ( ! id )
reporter->InternalError("global cmd_line_bpf_filter not defined"); reporter->InternalError("global cmd_line_bpf_filter not defined");
id->SetVal(new StringVal(user_pcap_filter)); id->SetVal(new StringVal(*options.pcap_filter));
} }
// Parse rule files defined on the script level. auto all_signature_files = options.signature_files;
char* script_rule_files =
copy_string(internal_val("signature_files")->AsString()->CheckString());
char* tmp = script_rule_files; // Append signature files defined in "signature_files" script option
char* s; for ( auto&& sf : get_script_signature_files() )
while ( (s = strsep(&tmp, " \t")) ) all_signature_files.emplace_back(std::move(sf));
if ( *s )
rule_files.push_back(s);
// Append signature files defined in @load-sigs // Append signature files defined in @load-sigs
for ( size_t i = 0; i < sig_files.size(); ++i ) for ( const auto& sf : sig_files )
rule_files.push_back(copy_string(sig_files[i].c_str())); all_signature_files.emplace_back(sf);
if ( rule_files.length() > 0 ) if ( ! all_signature_files.empty() )
{ {
rule_matcher = new RuleMatcher(RE_level); rule_matcher = new RuleMatcher(options.signature_re_level);
if ( ! rule_matcher->ReadFiles(rule_files) ) if ( ! rule_matcher->ReadFiles(all_signature_files) )
{ {
delete dns_mgr; delete dns_mgr;
exit(1); exit(1);
} }
if ( rule_debug ) if ( options.print_signature_debug_info )
rule_matcher->PrintDebug(); rule_matcher->PrintDebug();
file_mgr->InitMagic(); file_mgr->InitMagic();
} }
delete [] script_rule_files;
if ( g_policy_debug ) if ( g_policy_debug )
// ### Add support for debug command file. // ### Add support for debug command file.
dbg_init_debugger(0); dbg_init_debugger(0);
if ( read_files.length() == 0 && interfaces.length() == 0 ) auto all_interfaces = options.interfaces;
if ( options.pcap_files.empty() && options.interfaces.empty() )
{ {
Val* interfaces_val = internal_val("interfaces"); Val* interfaces_val = internal_val("interfaces");
if ( interfaces_val ) if ( interfaces_val )
@ -979,14 +748,15 @@ int main(int argc, char** argv)
interfaces_val->AsString()->Render(); interfaces_val->AsString()->Render();
if ( interfaces_str[0] != '\0' ) if ( interfaces_str[0] != '\0' )
add_to_name_list(interfaces_str, ' ', interfaces); tokenize_string(interfaces_str, " ", &all_interfaces);
delete [] interfaces_str; delete [] interfaces_str;
} }
} }
if ( dns_type != DNS_PRIME ) if ( dns_type != DNS_PRIME )
net_init(interfaces, read_files, writefile, do_watchdog); net_init(all_interfaces, options.pcap_files,
options.pcap_output_file, options.use_watchdog);
net_done = internal_handler("net_done"); net_done = internal_handler("net_done");
@ -1015,11 +785,11 @@ int main(int argc, char** argv)
} }
// Print the ID. // Print the ID.
if ( id_name ) if ( options.identifier_to_print )
{ {
ID* id = global_scope()->Lookup(id_name); ID* id = global_scope()->Lookup(*options.identifier_to_print);
if ( ! id ) if ( ! id )
reporter->FatalError("No such ID: %s\n", id_name); reporter->FatalError("No such ID: %s\n", options.identifier_to_print->data());
ODesc desc; ODesc desc;
desc.SetQuotes(true); desc.SetQuotes(true);
@ -1082,7 +852,7 @@ int main(int argc, char** argv)
g_frame_stack.pop_back(); g_frame_stack.pop_back();
} }
if ( override_ignore_checksums ) if ( options.ignore_checksums )
ignore_checksums = 1; ignore_checksums = 1;
if ( zeek_script_loaded ) if ( zeek_script_loaded )
@ -1116,6 +886,9 @@ int main(int argc, char** argv)
iosource_mgr->Register(thread_mgr, true); iosource_mgr->Register(thread_mgr, true);
if ( zeek::supervisor_mgr )
iosource_mgr->Register(zeek::supervisor_mgr);
if ( iosource_mgr->Size() > 0 || if ( iosource_mgr->Size() > 0 ||
have_pending_timers || have_pending_timers ||
BifConst::exit_only_after_terminate ) BifConst::exit_only_after_terminate )
@ -1135,12 +908,15 @@ int main(int argc, char** argv)
#endif #endif
if ( zeek::Supervisor::ThisNode() )
timer_mgr->Add(new zeek::ParentProcessCheckTimer(1, 1));
double time_net_start = current_time(true);; double time_net_start = current_time(true);;
uint64_t mem_net_start_total; uint64_t mem_net_start_total;
uint64_t mem_net_start_malloced; uint64_t mem_net_start_malloced;
if ( time_bro ) if ( options.print_execution_time )
{ {
get_memory_usage(&mem_net_start_total, &mem_net_start_malloced); get_memory_usage(&mem_net_start_total, &mem_net_start_malloced);
@ -1158,7 +934,7 @@ int main(int argc, char** argv)
uint64_t mem_net_done_total; uint64_t mem_net_done_total;
uint64_t mem_net_done_malloced; uint64_t mem_net_done_malloced;
if ( time_bro ) if ( options.print_execution_time )
{ {
get_memory_usage(&mem_net_done_total, &mem_net_done_malloced); get_memory_usage(&mem_net_done_total, &mem_net_done_malloced);

View file

@ -434,10 +434,9 @@ when return TOK_WHEN;
pref = skip_whitespace(pref + 1); // Skip over '='. pref = skip_whitespace(pref + 1); // Skip over '='.
if ( ! append ) if ( ! append )
while ( prefixes.length() > 1 ) // don't delete "" prefix zeek_script_prefixes = { "" }; // don't delete the "" prefix
delete prefixes.remove_nth(1);
add_to_name_list(pref, ':', prefixes); tokenize_string(pref, ":", &zeek_script_prefixes);
} }
@if return TOK_ATIF; @if return TOK_ATIF;
@ -942,14 +941,14 @@ int yywrap()
it->prefixes_checked = true; it->prefixes_checked = true;
// Prefixes are pushed onto a stack, so iterate backwards. // Prefixes are pushed onto a stack, so iterate backwards.
for ( int i = prefixes.length() - 1; i >= 0; --i ) for ( int i = zeek_script_prefixes.size() - 1; i >= 0; --i )
{ {
// Don't look at empty prefixes. // Don't look at empty prefixes.
if ( ! prefixes[i][0] ) if ( ! zeek_script_prefixes[i][0] )
continue; continue;
string canon = without_bropath_component(it->name); string canon = without_bropath_component(it->name);
string flat = flatten_script_name(canon, prefixes[i]); string flat = flatten_script_name(canon, zeek_script_prefixes[i]);
string path = find_relative_script_file(flat); string path = find_relative_script_file(flat);
if ( ! path.empty() ) if ( ! path.empty() )

1409
src/supervisor/Supervisor.cc Normal file

File diff suppressed because it is too large Load diff

414
src/supervisor/Supervisor.h Normal file
View file

@ -0,0 +1,414 @@
// See the file "COPYING" in the main distribution directory for copyright.
#pragma once
#include <sys/types.h>
#include <optional>
#include <cstdint>
#include <string>
#include <string_view>
#include <vector>
#include <utility>
#include <memory>
#include <chrono>
#include <map>
#include "iosource/IOSource.h"
#include "Timer.h"
#include "Pipe.h"
#include "Flare.h"
#include "NetVar.h"
#include "IntrusivePtr.h"
#include "Options.h"
namespace zeek {
/**
* A Supervisor object manages a tree of persistent Zeek processes. If any
* child process dies it will be re-created with its original configuration.
* The Supervisor process itself actually only manages a single child process,
* called the Stem process. That Stem is created via a fork() just after the
* command-line arguments have been parsed. The Stem process is used as the
* baseline image for spawning and supervising further Zeek child nodes since
* it has the purest global state without having to risk an exec() using an
* on-disk binary that's changed in the meantime from the original Supervisor's
* version of the Zeek binary. However, if the Stem process itself dies
* prematurely, the Supervisor will have to fork() and exec() to revive it (and
* then the revived Stem will re-spawn its own children). Any node in the tree
* will self-terminate if it detects its parent has died and that detection is
* done via polling for change in parent process ID.
*/
class Supervisor : public iosource::IOSource {
public:
/**
* Configuration options that change Supervisor behavior.
*/
struct Config {
/**
* The filesystem path of the Zeek binary/executable. This is used
* if the Stem process ever dies and we need to fork() and exec() to
* re-create it.
*/
std::string zeek_exe_path;
};
/**
* Configuration options that influence how a Supervised Zeek node
* integrates into the normal Zeek Cluster Framework.
*/
struct ClusterEndpoint {
/**
* The node's role within the cluster. E.g. manager, logger, worker.
*/
BifEnum::Supervisor::ClusterRole role;
/**
* The host/IP at which the cluster node is listening for connections.
*/
std::string host;
/**
* The TCP port number at which the cluster node listens for connections.
*/
int port;
/**
* The interface name from which the node read/analyze packets.
* Typically used by worker nodes.
*/
std::optional<std::string> interface;
};
/**
* Configuration options that influence behavior of a Supervised Zeek node.
*/
struct NodeConfig {
/**
* Create configuration from script-layer record value.
* @param node_val the script-layer record value to convert.
*/
static NodeConfig FromRecord(const RecordVal* node_val);
/**
* Create configuration from JSON representation.
* @param json the JSON string to convert.
*/
static NodeConfig FromJSON(std::string_view json);
/**
* Convert this object into JSON respresentation.
* @return the JSON string representing the node config.
*/
std::string ToJSON() const;
/**
* Convert his object into script-layer record value.
* @return the script-layer record value representing the node config.
*/
IntrusivePtr<RecordVal> ToRecord() const;
/**
* The name of the supervised Zeek node. These are unique within
* a given supervised process tree and typically human-readable.
*/
std::string name;
/**
* The interface name from which the node should read/analyze packets.
*/
std::optional<std::string> interface;
/**
* The working directory that should be used by the node.
*/
std::optional<std::string> directory;
/**
* The filename/path to which the node's stdout will be redirected.
*/
std::optional<std::string> stdout_file;
/**
* The filename/path to which the node's stderr will be redirected.
*/
std::optional<std::string> stderr_file;
/**
* A cpu/core number to which the node will try to pin itself.
*/
std::optional<int> cpu_affinity;
/**
* Additional script filename/paths that the node should load.
*/
std::vector<std::string> scripts;
/**
* The Cluster Layout definition. Each node in the Cluster Framework
* knows about the full, static cluster topology to which it belongs.
* Entries in the map use node names for keys.
*/
std::map<std::string, ClusterEndpoint> cluster;
};
/**
* State which defines a Supervised node's understanding of itself.
*/
struct SupervisedNode {
/**
* Initialize the Supervised node within the Zeek Cluster Framework.
* This function populates the "Cluster::nodes" script-layer variable
* that otherwise is expected to be populated by a
* "cluster-layout.zeek" script in other context (e.g. ZeekCtl
* generates that cluster layout).
* @return true if the supervised node is using the Cluster Framework
* else false.
*/
bool InitCluster() const;
/**
* Initialize the Supervised node.
* @param options the Zeek options to extend/modify as appropriate
* for the node's configuration.
*/
void Init(zeek::Options* options) const;
/**
* The node's configuration options.
*/
NodeConfig config;
/**
* The process ID of the supervised node's parent process (i.e. the PID
* of the Stem process).
*/
pid_t parent_pid;
};
/**
* The state of a supervised node from the Supervisor's perspective.
*/
struct Node {
/**
* Convert the node into script-layer Supervisor::NodeStatus record
* representation.
*/
IntrusivePtr<RecordVal> ToRecord() const;
/**
* @return the name of the node.
*/
const std::string& Name() const
{ return config.name; }
/**
* Create a new node state from a given configuration.
* @param arg_config the configuration to use for the node.
*/
Node(NodeConfig arg_config) : config(std::move(arg_config))
{ }
/**
* The desired configuration for the node.
*/
NodeConfig config;
/**
* Process ID of the node (positive/non-zero are valid/live PIDs).
*/
pid_t pid = 0;
/**
* Whether the node is voluntarily marked for termination by the
* Supervisor.
*/
bool killed = false;
/**
* The last exit status of the node.
*/
int exit_status = 0;
/**
* The last signal which terminated the node.
*/
int signal_number = 0;
/**
* Number of process revival attempts made after the node first died
* prematurely.
*/
int revival_attempts = 0;
/**
* How many seconds to wait until the next revival attempt for the node.
*/
int revival_delay = 1;
/**
* The time at which the node's process was last spawned.
*/
std::chrono::time_point<std::chrono::steady_clock> spawn_time;
};
/**
* State used to initalialize the Stem process.
*/
struct StemState {
/**
* Bidirectional pipes that allow the Supervisor and Stem to talk.
*/
std::unique_ptr<bro::PipePair> pipe;
/**
* The Stem's parent process ID (i.e. PID of the Supervisor).
*/
pid_t parent_pid = 0;
/**
* The Stem's process ID.
*/
pid_t pid = 0;
};
/**
* Create and run the Stem process if necessary.
* @param supervisor_mode whether Zeek was invoked with the supervisor
* mode specified as command-line argument/option.
* @return state that defines the Stem process if called from the
* Supervisor process. The Stem process itself will not return from this,
* function but a node it spawns via fork() will return from it and
* information about it is available in ThisNode().
*/
static std::optional<StemState> CreateStem(bool supervisor_mode);
/**
* @return the state which describes what a supervised node should know
* about itself if this is a supervised process. If called from a process
* that is not supervised, this returns an "empty" object.
*/
static const std::optional<SupervisedNode>& ThisNode()
{ return supervised_node; }
using NodeMap = std::map<std::string, Node, std::less<>>;
/**
* Create a new Supervisor object.
* @param stem_state information about the Stem process that was already
* created via CreateStem()
*/
Supervisor(Config cfg, StemState stem_state);
/**
* Destruction also cleanly shuts down the entire supervised process tree.
*/
~Supervisor();
/**
* @return the process ID of the Stem.
*/
pid_t StemPID() const
{ return stem_pid; }
/**
* @return the state of currently supervised processes. The map uses
* node names for keys.
*/
const NodeMap& Nodes()
{ return nodes; }
/**
* Retrieve current status of a supervised node.
* @param node_name the name of the node for which to retrieve status
* or an empty string to mean "all nodes".
* @return script-layer Supervisor::Status record value describing the
* status of a node or set of nodes.
*/
RecordVal* Status(std::string_view node_name);
/**
* Create a new supervised node.
* @param node the script-layer Supervisor::NodeConfig value that
* describes the desired node configuration
* @return an empty string on success or description of the error/failure
*/
std::string Create(const RecordVal* node);
/**
* Create a new supervised node.
* @param node the desired node configuration
* @return an empty string on success or description of the error/failure
*/
std::string Create(const Supervisor::NodeConfig& node);
/**
* Destroys and removes a supervised node.
* @param node_name the name of the node to destroy or an empty string
* to mean "all nodes"
* @return true on success
*/
bool Destroy(std::string_view node_name);
/**
* Restart a supervised node process (by destroying and re-recreating).
* @param node_name the name of the node to restart or an empty string
* to mean "all nodes"
* @return true on success
*/
bool Restart(std::string_view node_name);
/**
* Not meant for public use. For use in a signal handler to tell the
* Supervisor a child process (i.e. the Stem) potentially died.
*/
void ObserveChildSignal(int signo);
private:
// IOSource interface overrides:
void GetFds(iosource::FD_Set* read, iosource::FD_Set* write,
iosource::FD_Set* except) override;
double NextTimestamp(double* local_network_time) override;
void Process() override;
size_t ProcessMessages();
void HandleChildSignal();
void ReapStem();
const char* Tag() override
{ return "zeek::Supervisor"; }
/**
* Run the Stem process. The Stem process will receive instructions from
* the Supervisor to manipulate the process hierarchy and it's in charge
* of directly monitoring for whether any nodes die premature and need
* to be revived.
* @param pipe bidirectional pipes that allow the Supervisor and Stem
* process to communicate.
* @param pid the Stem's parent process ID (i.e. the PID of the Supervisor)
* @return state which describes what a supervised node should know about
* itself. I.e. this function only returns from a fork()'d child process.
*/
static SupervisedNode RunStem(StemState stem_state);
static std::optional<SupervisedNode> supervised_node;
Config config;
pid_t stem_pid;
std::unique_ptr<bro::PipePair> stem_pipe;
int last_signal = -1;
bro::Flare signal_flare;
NodeMap nodes;
std::string msg_buffer;
};
/**
* A timer used by supervised processes to periodically check whether their
* parent (supervisor) process has died. If it has died, the supervised
* process self-terminates.
*/
class ParentProcessCheckTimer : public Timer {
public:
/**
* Create a timer to check for parent process death.
* @param t the time at which to trigger the timer's check.
* @param interval number of seconds to wait before checking again.
*/
ParentProcessCheckTimer(double t, double interval);
protected:
void Dispatch(double t, int is_expire) override;
double interval;
};
extern Supervisor* supervisor_mgr;
} // namespace zeek

View file

@ -0,0 +1,112 @@
##! The BIFs that define the Zeek supervisor control interface.
%%{
#include "supervisor/Supervisor.h"
%%}
module Supervisor;
enum ClusterRole %{
NONE,
LOGGER,
MANAGER,
PROXY,
WORKER,
%}
type Supervisor::ClusterEndpoint: record;
type Supervisor::Status: record;
type Supervisor::NodeConfig: record;
type Supervisor::NodeStatus: record;
function Supervisor::__status%(node: string%): Supervisor::Status
%{
if ( ! zeek::supervisor_mgr )
{
builtin_error("supervisor mode not enabled");
return new RecordVal(BifType::Record::Supervisor::Status);
}
return zeek::supervisor_mgr->Status(node->CheckString());
%}
function Supervisor::__create%(node: Supervisor::NodeConfig%): string
%{
if ( ! zeek::supervisor_mgr )
{
builtin_error("supervisor mode not enabled");
return new StringVal("supervisor mode not enabled");
}
auto rval = zeek::supervisor_mgr->Create(node->AsRecordVal());
return new StringVal(rval);
%}
function Supervisor::__destroy%(node: string%): bool
%{
if ( ! zeek::supervisor_mgr )
{
builtin_error("supervisor mode not enabled");
return val_mgr->GetBool(false);
}
auto rval = zeek::supervisor_mgr->Destroy(node->CheckString());
return val_mgr->GetBool(rval);
%}
function Supervisor::__restart%(node: string%): bool
%{
if ( ! zeek::supervisor_mgr )
{
builtin_error("supervisor mode not enabled");
return val_mgr->GetBool(false);
}
auto rval = zeek::supervisor_mgr->Restart(node->CheckString());
return val_mgr->GetBool(rval);
%}
function Supervisor::__init_cluster%(%): bool
%{
if ( zeek::Supervisor::ThisNode() )
return val_mgr->GetBool(zeek::Supervisor::ThisNode()->InitCluster());
return val_mgr->GetBool(false);
%}
function Supervisor::__is_supervised%(%): bool
%{
return val_mgr->GetBool(zeek::Supervisor::ThisNode().has_value());
%}
function Supervisor::__node%(%): Supervisor::NodeConfig
%{
if ( ! zeek::Supervisor::ThisNode() )
{
builtin_error("not a supervised process");
auto rt = BifType::Record::Supervisor::NodeConfig;
auto rval = make_intrusive<RecordVal>(rt);
rval->Assign(rt->FieldOffset("name"), new StringVal("<invalid>"));
return rval.detach();
}
auto rval = zeek::Supervisor::ThisNode()->config.ToRecord();
return rval.detach();
%}
function Supervisor::__is_supervisor%(%): bool
%{
return val_mgr->GetBool(zeek::supervisor_mgr != nullptr);
%}
function Supervisor::__stem_pid%(%): int
%{
if ( zeek::supervisor_mgr )
return val_mgr->GetInt(zeek::supervisor_mgr->StemPID());
if ( zeek::Supervisor::ThisNode() )
return val_mgr->GetInt(zeek::Supervisor::ThisNode()->parent_pid);
builtin_error("supervisor mode not enabled and not a supervised node");
return val_mgr->GetInt(-1);
%}

View file

@ -1,18 +1,11 @@
#include <signal.h> #include <signal.h>
#include <pthread.h>
#include "zeek-config.h" #include "zeek-config.h"
#include "BasicThread.h" #include "BasicThread.h"
#include "Manager.h" #include "Manager.h"
#include "pthread.h" #include "util.h"
#ifdef HAVE_LINUX
#include <sys/prctl.h>
#endif
#ifdef __FreeBSD__
#include <pthread_np.h>
#endif
using namespace threading; using namespace threading;
@ -54,18 +47,7 @@ void BasicThread::SetName(const char* arg_name)
void BasicThread::SetOSName(const char* arg_name) void BasicThread::SetOSName(const char* arg_name)
{ {
static_assert(std::is_same<std::thread::native_handle_type, pthread_t>::value, "libstdc++ doesn't use pthread_t"); static_assert(std::is_same<std::thread::native_handle_type, pthread_t>::value, "libstdc++ doesn't use pthread_t");
zeek::set_thread_name(arg_name, thread.native_handle());
#ifdef HAVE_LINUX
prctl(PR_SET_NAME, arg_name, 0, 0, 0);
#endif
#ifdef __APPLE__
pthread_setname_np(arg_name);
#endif
#ifdef __FreeBSD__
pthread_set_name_np(thread.native_handle(), arg_name);
#endif
} }
const char* BasicThread::Fmt(const char* format, ...) const char* BasicThread::Fmt(const char* format, ...)

View file

@ -1231,7 +1231,7 @@ string bro_prefixes()
{ {
string rval; string rval;
for ( const auto& prefix : prefixes ) for ( const auto& prefix : zeek_script_prefixes )
{ {
if ( ! rval.empty() ) if ( ! rval.empty() )
rval.append(":"); rval.append(":");
@ -1459,17 +1459,22 @@ TEST_CASE("util tokenize_string")
} }
vector<string>* tokenize_string(string input, const string& delim, vector<string>* tokenize_string(string input, const string& delim,
vector<string>* rval) vector<string>* rval, int limit)
{ {
if ( ! rval ) if ( ! rval )
rval = new vector<string>(); rval = new vector<string>();
size_t n; size_t n;
auto found = 0;
while ( (n = input.find(delim)) != string::npos ) while ( (n = input.find(delim)) != string::npos )
{ {
++found;
rval->push_back(input.substr(0, n)); rval->push_back(input.substr(0, n));
input.erase(0, n + 1); input.erase(0, n + 1);
if ( limit && found == limit )
break;
} }
rval->push_back(input); rval->push_back(input);
@ -1482,6 +1487,25 @@ TEST_CASE("util normalize_path")
CHECK(normalize_path("/1/./2/3") == "/1/2/3"); CHECK(normalize_path("/1/./2/3") == "/1/2/3");
CHECK(normalize_path("/1/2/../3") == "/1/3"); CHECK(normalize_path("/1/2/../3") == "/1/3");
CHECK(normalize_path("1/2/3/") == "1/2/3"); CHECK(normalize_path("1/2/3/") == "1/2/3");
CHECK(normalize_path("1/2//3///") == "1/2/3");
CHECK(normalize_path("~/zeek/testing") == "~/zeek/testing");
CHECK(normalize_path("~jon/zeek/testing") == "~jon/zeek/testing");
CHECK(normalize_path("~jon/./zeek/testing") == "~jon/zeek/testing");
CHECK(normalize_path("~/zeek/testing/../././.") == "~/zeek");
CHECK(normalize_path("./zeek") == "./zeek");
CHECK(normalize_path("../zeek") == "../zeek");
CHECK(normalize_path("../zeek/testing/..") == "../zeek");
CHECK(normalize_path("./zeek/..") == ".");
CHECK(normalize_path("./zeek/../..") == "..");
CHECK(normalize_path("./zeek/../../..") == "../..");
CHECK(normalize_path("./..") == "..");
CHECK(normalize_path("../..") == "../..");
CHECK(normalize_path("/..") == "/..");
CHECK(normalize_path("~/..") == "~/..");
CHECK(normalize_path("/../..") == "/../..");
CHECK(normalize_path("~/../..") == "~/../..");
CHECK(normalize_path("zeek/..") == "");
CHECK(normalize_path("zeek/../..") == "..");
} }
string normalize_path(const string& path) string normalize_path(const string& path)
@ -1503,10 +1527,30 @@ string normalize_path(const string& path)
if ( *it == "." && it != components.begin() ) if ( *it == "." && it != components.begin() )
final_components.pop_back(); final_components.pop_back();
else if ( *it == ".." && final_components[0] != ".." ) else if ( *it == ".." )
{ {
final_components.pop_back(); auto cur_idx = final_components.size() - 1;
final_components.pop_back();
if ( cur_idx != 0 )
{
auto last_idx = cur_idx - 1;
auto& last_component = final_components[last_idx];
if ( last_component == "/" || last_component == "~" ||
last_component == ".." )
continue;
if ( last_component == "." )
{
last_component = "..";
final_components.pop_back();
}
else
{
final_components.pop_back();
final_components.pop_back();
}
}
} }
} }
@ -1764,7 +1808,7 @@ void terminate_processing()
} }
extern const char* proc_status_file; extern const char* proc_status_file;
void _set_processing_status(const char* status) void set_processing_status(const char* status, const char* reason)
{ {
if ( ! proc_status_file ) if ( ! proc_status_file )
return; return;
@ -1791,20 +1835,27 @@ void _set_processing_status(const char* status)
return; return;
} }
int len = strlen(status); auto write_str = [](int fd, const char* s)
while ( len )
{ {
int n = write(fd, status, len); int len = strlen(s);
while ( len )
{
int n = write(fd, s, len);
if ( n < 0 && errno != EINTR && errno != EAGAIN ) if ( n < 0 && errno != EINTR && errno != EAGAIN )
// Ignore errors, as they're too difficult to // Ignore errors, as they're too difficult to
// safely report here. // safely report here.
break; break;
status += n; s += n;
len -= n; len -= n;
} }
};
write_str(fd, status);
write_str(fd, " [");
write_str(fd, reason);
write_str(fd, "]\n");
safe_close(fd); safe_close(fd);
errno = old_errno; errno = old_errno;
@ -2314,3 +2365,18 @@ string json_escape_utf8(const string& val)
return result; return result;
} }
void zeek::set_thread_name(const char* name, pthread_t tid)
{
#ifdef HAVE_LINUX
prctl(PR_SET_NAME, name, 0, 0, 0);
#endif
#ifdef __APPLE__
pthread_setname_np(name);
#endif
#ifdef __FreeBSD__
pthread_set_name_np(tid, name);
#endif
}

View file

@ -60,6 +60,15 @@ extern HeapLeakChecker* heap_checker;
#endif #endif
#include <stdint.h> #include <stdint.h>
#include <pthread.h>
#ifdef HAVE_LINUX
#include <sys/prctl.h>
#endif
#ifdef __FreeBSD__
#include <pthread_np.h>
#endif
ZEEK_DEPRECATED("Remove in v4.1. Use uint64_t instead.") ZEEK_DEPRECATED("Remove in v4.1. Use uint64_t instead.")
typedef uint64_t uint64; typedef uint64_t uint64;
@ -138,7 +147,7 @@ inline std::string get_escaped_string(const std::string& str, bool escape_all)
std::vector<std::string>* tokenize_string(std::string input, std::vector<std::string>* tokenize_string(std::string input,
const std::string& delim, const std::string& delim,
std::vector<std::string>* rval = 0); std::vector<std::string>* rval = 0, int limit = 0);
extern char* copy_string(const char* s); extern char* copy_string(const char* s);
extern int streq(const char* s1, const char* s2); extern int streq(const char* s1, const char* s2);
@ -402,9 +411,7 @@ void terminate_processing();
// Sets the current status of the Bro process to the given string. // Sets the current status of the Bro process to the given string.
// If the option --status-file has been set, this is written into // If the option --status-file has been set, this is written into
// the the corresponding file. Otherwise, the function is a no-op. // the the corresponding file. Otherwise, the function is a no-op.
#define set_processing_status(status, location) \ void set_processing_status(const char* status, const char* reason);
_set_processing_status(status " [" location "]\n");
void _set_processing_status(const char* status);
// Current timestamp, from a networking perspective, not a wall-clock // Current timestamp, from a networking perspective, not a wall-clock
// perspective. In particular, if we're reading from a savefile this // perspective. In particular, if we're reading from a savefile this
@ -572,3 +579,14 @@ char* zeekenv(const char* name);
* @return the escaped string * @return the escaped string
*/ */
std::string json_escape_utf8(const std::string& val); std::string json_escape_utf8(const std::string& val);
namespace zeek {
/**
* Set the process/thread name. May not be supported on all OSs.
* @param name new name for the process/thread. OS limitations typically
* truncate the name to 15 bytes maximum.
* @param tid handle of thread whose name shall change
*/
void set_thread_name(const char* name, pthread_t tid = pthread_self());
} // namespace zeek

57
src/zeek-affinity.cc Normal file
View file

@ -0,0 +1,57 @@
// See the file "COPYING" in the main distribution directory for copyright.
// This is all in its own source file primarily because the Linux
// implementation uses the _GNU_SOURCE feature test macro which must be
// defined before including any header file and lumping this together with
// other util functions makes that requirement less apparent and less
// self-contained.
#if defined(__linux__)
#if !defined(_GNU_SOURCE)
#define _GNU_SOURCE
#endif
#include <sched.h>
namespace zeek {
bool set_affinity(int core_number)
{
cpu_set_t cpus;
CPU_ZERO(&cpus);
CPU_SET(core_number, &cpus);
auto res = sched_setaffinity(0, sizeof(cpus), &cpus);
return res == 0;
}
} // namespace zeek
#elif defined(__FreeBSD__)
#include <sys/param.h>
#include <sys/cpuset.h>
namespace zeek {
bool set_affinity(int core_number)
{
cpuset_t cpus;
CPU_ZERO(&cpus);
CPU_SET(core_number, &cpus);
auto res = cpuset_setaffinity(CPU_LEVEL_WHICH, CPU_WHICH_PID, -1,
sizeof(cpus), &cpus);
return res == 0;
}
} // namespace zeek
#else
#include <cerrno>
namespace zeek {
bool set_affinity(int core_number)
{
errno = ENOTSUP;
return false;
}
} // namespace zeek
#endif

17
src/zeek-affinity.h Normal file
View file

@ -0,0 +1,17 @@
// See the file "COPYING" in the main distribution directory for copyright.
#pragma once
namespace zeek {
/**
* Set the process affinity to a given CPU. Currently only supported on
* Linux and FreeBSD.
* @param core_number the core to which this process should set its affinity.
* Cores are typically numbered 0..N.
* @return true if the affinity is successfully set and false if not with
* errno additionally being set to indicate the reason.
*/
bool set_affinity(int core_number);
} // namespace zeek

View file

@ -1,3 +1,8 @@
warning in <params>, line 1: event handler never invoked: this_is_never_used
warning in <params>, line 1: event handler never invoked: InputConfig::new_value warning in <params>, line 1: event handler never invoked: InputConfig::new_value
warning in <params>, line 1: event handler never invoked: InputRaw::process_finished warning in <params>, line 1: event handler never invoked: InputRaw::process_finished
warning in <params>, line 1: event handler never invoked: SupervisorControl::create_request
warning in <params>, line 1: event handler never invoked: SupervisorControl::destroy_request
warning in <params>, line 1: event handler never invoked: SupervisorControl::restart_request
warning in <params>, line 1: event handler never invoked: SupervisorControl::status_request
warning in <params>, line 1: event handler never invoked: SupervisorControl::stop_request
warning in <params>, line 1: event handler never invoked: this_is_never_used

View file

@ -3,7 +3,7 @@
#empty_field (empty) #empty_field (empty)
#unset_field - #unset_field -
#path loaded_scripts #path loaded_scripts
#open 2019-07-29-19-05-26 #open 2019-10-15-01-48-24
#fields name #fields name
#types string #types string
scripts/base/init-bare.zeek scripts/base/init-bare.zeek
@ -14,6 +14,8 @@ scripts/base/init-bare.zeek
build/scripts/base/bif/reporter.bif.zeek build/scripts/base/bif/reporter.bif.zeek
build/scripts/base/bif/strings.bif.zeek build/scripts/base/bif/strings.bif.zeek
build/scripts/base/bif/option.bif.zeek build/scripts/base/bif/option.bif.zeek
scripts/base/frameworks/supervisor/api.zeek
build/scripts/base/bif/supervisor.bif.zeek
build/scripts/base/bif/plugins/Zeek_SNMP.types.bif.zeek build/scripts/base/bif/plugins/Zeek_SNMP.types.bif.zeek
build/scripts/base/bif/plugins/Zeek_KRB.types.bif.zeek build/scripts/base/bif/plugins/Zeek_KRB.types.bif.zeek
build/scripts/base/bif/event.bif.zeek build/scripts/base/bif/event.bif.zeek
@ -35,6 +37,9 @@ scripts/base/init-frameworks-and-bifs.zeek
build/scripts/base/bif/data.bif.zeek build/scripts/base/bif/data.bif.zeek
build/scripts/base/bif/store.bif.zeek build/scripts/base/bif/store.bif.zeek
scripts/base/frameworks/broker/log.zeek scripts/base/frameworks/broker/log.zeek
scripts/base/frameworks/supervisor/__load__.zeek
scripts/base/frameworks/supervisor/control.zeek
scripts/base/frameworks/supervisor/main.zeek
scripts/base/frameworks/input/__load__.zeek scripts/base/frameworks/input/__load__.zeek
scripts/base/frameworks/input/main.zeek scripts/base/frameworks/input/main.zeek
build/scripts/base/bif/input.bif.zeek build/scripts/base/bif/input.bif.zeek
@ -182,4 +187,4 @@ scripts/base/init-frameworks-and-bifs.zeek
build/scripts/base/bif/plugins/Zeek_SQLiteWriter.sqlite.bif.zeek build/scripts/base/bif/plugins/Zeek_SQLiteWriter.sqlite.bif.zeek
scripts/policy/misc/loaded-scripts.zeek scripts/policy/misc/loaded-scripts.zeek
scripts/base/utils/paths.zeek scripts/base/utils/paths.zeek
#close 2019-07-29-19-05-26 #close 2019-10-15-01-48-24

View file

@ -3,7 +3,7 @@
#empty_field (empty) #empty_field (empty)
#unset_field - #unset_field -
#path loaded_scripts #path loaded_scripts
#open 2019-08-06-00-02-39 #open 2019-10-15-01-48-24
#fields name #fields name
#types string #types string
scripts/base/init-bare.zeek scripts/base/init-bare.zeek
@ -14,6 +14,8 @@ scripts/base/init-bare.zeek
build/scripts/base/bif/reporter.bif.zeek build/scripts/base/bif/reporter.bif.zeek
build/scripts/base/bif/strings.bif.zeek build/scripts/base/bif/strings.bif.zeek
build/scripts/base/bif/option.bif.zeek build/scripts/base/bif/option.bif.zeek
scripts/base/frameworks/supervisor/api.zeek
build/scripts/base/bif/supervisor.bif.zeek
build/scripts/base/bif/plugins/Zeek_SNMP.types.bif.zeek build/scripts/base/bif/plugins/Zeek_SNMP.types.bif.zeek
build/scripts/base/bif/plugins/Zeek_KRB.types.bif.zeek build/scripts/base/bif/plugins/Zeek_KRB.types.bif.zeek
build/scripts/base/bif/event.bif.zeek build/scripts/base/bif/event.bif.zeek
@ -35,6 +37,9 @@ scripts/base/init-frameworks-and-bifs.zeek
build/scripts/base/bif/data.bif.zeek build/scripts/base/bif/data.bif.zeek
build/scripts/base/bif/store.bif.zeek build/scripts/base/bif/store.bif.zeek
scripts/base/frameworks/broker/log.zeek scripts/base/frameworks/broker/log.zeek
scripts/base/frameworks/supervisor/__load__.zeek
scripts/base/frameworks/supervisor/control.zeek
scripts/base/frameworks/supervisor/main.zeek
scripts/base/frameworks/input/__load__.zeek scripts/base/frameworks/input/__load__.zeek
scripts/base/frameworks/input/main.zeek scripts/base/frameworks/input/main.zeek
build/scripts/base/bif/input.bif.zeek build/scripts/base/bif/input.bif.zeek
@ -376,4 +381,4 @@ scripts/base/init-default.zeek
scripts/base/misc/find-filtered-trace.zeek scripts/base/misc/find-filtered-trace.zeek
scripts/base/misc/version.zeek scripts/base/misc/version.zeek
scripts/policy/misc/loaded-scripts.zeek scripts/policy/misc/loaded-scripts.zeek
#close 2019-08-06-00-02-39 #close 2019-10-15-01-48-25

View file

@ -157,6 +157,8 @@
0.000000 MetaHookPost CallFunction(Analyzer::register_for_ports, <frame>, (Analyzer::ANALYZER_TEREDO, {3544/udp})) -> <no result> 0.000000 MetaHookPost CallFunction(Analyzer::register_for_ports, <frame>, (Analyzer::ANALYZER_TEREDO, {3544/udp})) -> <no result>
0.000000 MetaHookPost CallFunction(Analyzer::register_for_ports, <frame>, (Analyzer::ANALYZER_VXLAN, {4789/udp})) -> <no result> 0.000000 MetaHookPost CallFunction(Analyzer::register_for_ports, <frame>, (Analyzer::ANALYZER_VXLAN, {4789/udp})) -> <no result>
0.000000 MetaHookPost CallFunction(Analyzer::register_for_ports, <frame>, (Analyzer::ANALYZER_XMPP, {5222<...>/tcp})) -> <no result> 0.000000 MetaHookPost CallFunction(Analyzer::register_for_ports, <frame>, (Analyzer::ANALYZER_XMPP, {5222<...>/tcp})) -> <no result>
0.000000 MetaHookPost CallFunction(Broker::__subscribe, <frame>, (zeek/supervisor)) -> <no result>
0.000000 MetaHookPost CallFunction(Broker::subscribe, <frame>, (zeek/supervisor)) -> <no result>
0.000000 MetaHookPost CallFunction(Cluster::is_enabled, <frame>, ()) -> <no result> 0.000000 MetaHookPost CallFunction(Cluster::is_enabled, <frame>, ()) -> <no result>
0.000000 MetaHookPost CallFunction(Cluster::is_enabled, <null>, ()) -> <no result> 0.000000 MetaHookPost CallFunction(Cluster::is_enabled, <null>, ()) -> <no result>
0.000000 MetaHookPost CallFunction(Cluster::local_node_type, <null>, ()) -> <no result> 0.000000 MetaHookPost CallFunction(Cluster::local_node_type, <null>, ()) -> <no result>
@ -274,7 +276,7 @@
0.000000 MetaHookPost CallFunction(Log::__create_stream, <frame>, (Weird::LOG, [columns=Weird::Info, ev=Weird::log_weird, path=weird])) -> <no result> 0.000000 MetaHookPost CallFunction(Log::__create_stream, <frame>, (Weird::LOG, [columns=Weird::Info, ev=Weird::log_weird, path=weird])) -> <no result>
0.000000 MetaHookPost CallFunction(Log::__create_stream, <frame>, (X509::LOG, [columns=X509::Info, ev=X509::log_x509, path=x509])) -> <no result> 0.000000 MetaHookPost CallFunction(Log::__create_stream, <frame>, (X509::LOG, [columns=X509::Info, ev=X509::log_x509, path=x509])) -> <no result>
0.000000 MetaHookPost CallFunction(Log::__create_stream, <frame>, (mysql::LOG, [columns=MySQL::Info, ev=MySQL::log_mysql, path=mysql])) -> <no result> 0.000000 MetaHookPost CallFunction(Log::__create_stream, <frame>, (mysql::LOG, [columns=MySQL::Info, ev=MySQL::log_mysql, path=mysql])) -> <no result>
0.000000 MetaHookPost CallFunction(Log::__write, <frame>, (PacketFilter::LOG, [ts=1573527265.694831, node=zeek, filter=ip or not ip, init=T, success=T])) -> <no result> 0.000000 MetaHookPost CallFunction(Log::__write, <frame>, (PacketFilter::LOG, [ts=1579727603.636084, node=zeek, filter=ip or not ip, init=T, success=T])) -> <no result>
0.000000 MetaHookPost CallFunction(Log::add_default_filter, <frame>, (Broker::LOG)) -> <no result> 0.000000 MetaHookPost CallFunction(Log::add_default_filter, <frame>, (Broker::LOG)) -> <no result>
0.000000 MetaHookPost CallFunction(Log::add_default_filter, <frame>, (Cluster::LOG)) -> <no result> 0.000000 MetaHookPost CallFunction(Log::add_default_filter, <frame>, (Cluster::LOG)) -> <no result>
0.000000 MetaHookPost CallFunction(Log::add_default_filter, <frame>, (Config::LOG)) -> <no result> 0.000000 MetaHookPost CallFunction(Log::add_default_filter, <frame>, (Config::LOG)) -> <no result>
@ -455,7 +457,7 @@
0.000000 MetaHookPost CallFunction(Log::create_stream, <frame>, (Weird::LOG, [columns=Weird::Info, ev=Weird::log_weird, path=weird])) -> <no result> 0.000000 MetaHookPost CallFunction(Log::create_stream, <frame>, (Weird::LOG, [columns=Weird::Info, ev=Weird::log_weird, path=weird])) -> <no result>
0.000000 MetaHookPost CallFunction(Log::create_stream, <frame>, (X509::LOG, [columns=X509::Info, ev=X509::log_x509, path=x509])) -> <no result> 0.000000 MetaHookPost CallFunction(Log::create_stream, <frame>, (X509::LOG, [columns=X509::Info, ev=X509::log_x509, path=x509])) -> <no result>
0.000000 MetaHookPost CallFunction(Log::create_stream, <frame>, (mysql::LOG, [columns=MySQL::Info, ev=MySQL::log_mysql, path=mysql])) -> <no result> 0.000000 MetaHookPost CallFunction(Log::create_stream, <frame>, (mysql::LOG, [columns=MySQL::Info, ev=MySQL::log_mysql, path=mysql])) -> <no result>
0.000000 MetaHookPost CallFunction(Log::write, <frame>, (PacketFilter::LOG, [ts=1573527265.694831, node=zeek, filter=ip or not ip, init=T, success=T])) -> <no result> 0.000000 MetaHookPost CallFunction(Log::write, <frame>, (PacketFilter::LOG, [ts=1579727603.636084, node=zeek, filter=ip or not ip, init=T, success=T])) -> <no result>
0.000000 MetaHookPost CallFunction(NetControl::check_plugins, <frame>, ()) -> <no result> 0.000000 MetaHookPost CallFunction(NetControl::check_plugins, <frame>, ()) -> <no result>
0.000000 MetaHookPost CallFunction(NetControl::init, <null>, ()) -> <no result> 0.000000 MetaHookPost CallFunction(NetControl::init, <null>, ()) -> <no result>
0.000000 MetaHookPost CallFunction(Notice::want_pp, <frame>, ()) -> <no result> 0.000000 MetaHookPost CallFunction(Notice::want_pp, <frame>, ()) -> <no result>
@ -694,6 +696,7 @@
0.000000 MetaHookPost LoadFile(0, .<...>/add-geodata.zeek) -> -1 0.000000 MetaHookPost LoadFile(0, .<...>/add-geodata.zeek) -> -1
0.000000 MetaHookPost LoadFile(0, .<...>/addrs.zeek) -> -1 0.000000 MetaHookPost LoadFile(0, .<...>/addrs.zeek) -> -1
0.000000 MetaHookPost LoadFile(0, .<...>/analyzer.bif.zeek) -> -1 0.000000 MetaHookPost LoadFile(0, .<...>/analyzer.bif.zeek) -> -1
0.000000 MetaHookPost LoadFile(0, .<...>/api.zeek) -> -1
0.000000 MetaHookPost LoadFile(0, .<...>/ascii.zeek) -> -1 0.000000 MetaHookPost LoadFile(0, .<...>/ascii.zeek) -> -1
0.000000 MetaHookPost LoadFile(0, .<...>/average.zeek) -> -1 0.000000 MetaHookPost LoadFile(0, .<...>/average.zeek) -> -1
0.000000 MetaHookPost LoadFile(0, .<...>/benchmark.zeek) -> -1 0.000000 MetaHookPost LoadFile(0, .<...>/benchmark.zeek) -> -1
@ -708,6 +711,7 @@
0.000000 MetaHookPost LoadFile(0, .<...>/const.bif.zeek) -> -1 0.000000 MetaHookPost LoadFile(0, .<...>/const.bif.zeek) -> -1
0.000000 MetaHookPost LoadFile(0, .<...>/consts.zeek) -> -1 0.000000 MetaHookPost LoadFile(0, .<...>/consts.zeek) -> -1
0.000000 MetaHookPost LoadFile(0, .<...>/contents.zeek) -> -1 0.000000 MetaHookPost LoadFile(0, .<...>/contents.zeek) -> -1
0.000000 MetaHookPost LoadFile(0, .<...>/control.zeek) -> -1
0.000000 MetaHookPost LoadFile(0, .<...>/ct-list.zeek) -> -1 0.000000 MetaHookPost LoadFile(0, .<...>/ct-list.zeek) -> -1
0.000000 MetaHookPost LoadFile(0, .<...>/data.bif.zeek) -> -1 0.000000 MetaHookPost LoadFile(0, .<...>/data.bif.zeek) -> -1
0.000000 MetaHookPost LoadFile(0, .<...>/dcc-send.zeek) -> -1 0.000000 MetaHookPost LoadFile(0, .<...>/dcc-send.zeek) -> -1
@ -767,6 +771,7 @@
0.000000 MetaHookPost LoadFile(0, .<...>/store.zeek) -> -1 0.000000 MetaHookPost LoadFile(0, .<...>/store.zeek) -> -1
0.000000 MetaHookPost LoadFile(0, .<...>/strings.bif.zeek) -> -1 0.000000 MetaHookPost LoadFile(0, .<...>/strings.bif.zeek) -> -1
0.000000 MetaHookPost LoadFile(0, .<...>/sum.zeek) -> -1 0.000000 MetaHookPost LoadFile(0, .<...>/sum.zeek) -> -1
0.000000 MetaHookPost LoadFile(0, .<...>/supervisor.bif.zeek) -> -1
0.000000 MetaHookPost LoadFile(0, .<...>/thresholds.zeek) -> -1 0.000000 MetaHookPost LoadFile(0, .<...>/thresholds.zeek) -> -1
0.000000 MetaHookPost LoadFile(0, .<...>/top-k.bif.zeek) -> -1 0.000000 MetaHookPost LoadFile(0, .<...>/top-k.bif.zeek) -> -1
0.000000 MetaHookPost LoadFile(0, .<...>/topk.zeek) -> -1 0.000000 MetaHookPost LoadFile(0, .<...>/topk.zeek) -> -1
@ -788,6 +793,7 @@
0.000000 MetaHookPost LoadFile(0, base<...>/addrs.zeek) -> -1 0.000000 MetaHookPost LoadFile(0, base<...>/addrs.zeek) -> -1
0.000000 MetaHookPost LoadFile(0, base<...>/analyzer) -> -1 0.000000 MetaHookPost LoadFile(0, base<...>/analyzer) -> -1
0.000000 MetaHookPost LoadFile(0, base<...>/analyzer.bif.zeek) -> -1 0.000000 MetaHookPost LoadFile(0, base<...>/analyzer.bif.zeek) -> -1
0.000000 MetaHookPost LoadFile(0, base<...>/api.zeek) -> -1
0.000000 MetaHookPost LoadFile(0, base<...>/bif) -> -1 0.000000 MetaHookPost LoadFile(0, base<...>/bif) -> -1
0.000000 MetaHookPost LoadFile(0, base<...>/broker) -> -1 0.000000 MetaHookPost LoadFile(0, base<...>/broker) -> -1
0.000000 MetaHookPost LoadFile(0, base<...>/cluster) -> -1 0.000000 MetaHookPost LoadFile(0, base<...>/cluster) -> -1
@ -868,6 +874,8 @@
0.000000 MetaHookPost LoadFile(0, base<...>/strings.bif.zeek) -> -1 0.000000 MetaHookPost LoadFile(0, base<...>/strings.bif.zeek) -> -1
0.000000 MetaHookPost LoadFile(0, base<...>/strings.zeek) -> -1 0.000000 MetaHookPost LoadFile(0, base<...>/strings.zeek) -> -1
0.000000 MetaHookPost LoadFile(0, base<...>/sumstats) -> -1 0.000000 MetaHookPost LoadFile(0, base<...>/sumstats) -> -1
0.000000 MetaHookPost LoadFile(0, base<...>/supervisor) -> -1
0.000000 MetaHookPost LoadFile(0, base<...>/supervisor.bif.zeek) -> -1
0.000000 MetaHookPost LoadFile(0, base<...>/syslog) -> -1 0.000000 MetaHookPost LoadFile(0, base<...>/syslog) -> -1
0.000000 MetaHookPost LoadFile(0, base<...>/thresholds.zeek) -> -1 0.000000 MetaHookPost LoadFile(0, base<...>/thresholds.zeek) -> -1
0.000000 MetaHookPost LoadFile(0, base<...>/time.zeek) -> -1 0.000000 MetaHookPost LoadFile(0, base<...>/time.zeek) -> -1
@ -1053,6 +1061,8 @@
0.000000 MetaHookPre CallFunction(Analyzer::register_for_ports, <frame>, (Analyzer::ANALYZER_TEREDO, {3544/udp})) 0.000000 MetaHookPre CallFunction(Analyzer::register_for_ports, <frame>, (Analyzer::ANALYZER_TEREDO, {3544/udp}))
0.000000 MetaHookPre CallFunction(Analyzer::register_for_ports, <frame>, (Analyzer::ANALYZER_VXLAN, {4789/udp})) 0.000000 MetaHookPre CallFunction(Analyzer::register_for_ports, <frame>, (Analyzer::ANALYZER_VXLAN, {4789/udp}))
0.000000 MetaHookPre CallFunction(Analyzer::register_for_ports, <frame>, (Analyzer::ANALYZER_XMPP, {5222<...>/tcp})) 0.000000 MetaHookPre CallFunction(Analyzer::register_for_ports, <frame>, (Analyzer::ANALYZER_XMPP, {5222<...>/tcp}))
0.000000 MetaHookPre CallFunction(Broker::__subscribe, <frame>, (zeek/supervisor))
0.000000 MetaHookPre CallFunction(Broker::subscribe, <frame>, (zeek/supervisor))
0.000000 MetaHookPre CallFunction(Cluster::is_enabled, <frame>, ()) 0.000000 MetaHookPre CallFunction(Cluster::is_enabled, <frame>, ())
0.000000 MetaHookPre CallFunction(Cluster::is_enabled, <null>, ()) 0.000000 MetaHookPre CallFunction(Cluster::is_enabled, <null>, ())
0.000000 MetaHookPre CallFunction(Cluster::local_node_type, <null>, ()) 0.000000 MetaHookPre CallFunction(Cluster::local_node_type, <null>, ())
@ -1170,7 +1180,7 @@
0.000000 MetaHookPre CallFunction(Log::__create_stream, <frame>, (Weird::LOG, [columns=Weird::Info, ev=Weird::log_weird, path=weird])) 0.000000 MetaHookPre CallFunction(Log::__create_stream, <frame>, (Weird::LOG, [columns=Weird::Info, ev=Weird::log_weird, path=weird]))
0.000000 MetaHookPre CallFunction(Log::__create_stream, <frame>, (X509::LOG, [columns=X509::Info, ev=X509::log_x509, path=x509])) 0.000000 MetaHookPre CallFunction(Log::__create_stream, <frame>, (X509::LOG, [columns=X509::Info, ev=X509::log_x509, path=x509]))
0.000000 MetaHookPre CallFunction(Log::__create_stream, <frame>, (mysql::LOG, [columns=MySQL::Info, ev=MySQL::log_mysql, path=mysql])) 0.000000 MetaHookPre CallFunction(Log::__create_stream, <frame>, (mysql::LOG, [columns=MySQL::Info, ev=MySQL::log_mysql, path=mysql]))
0.000000 MetaHookPre CallFunction(Log::__write, <frame>, (PacketFilter::LOG, [ts=1573527265.694831, node=zeek, filter=ip or not ip, init=T, success=T])) 0.000000 MetaHookPre CallFunction(Log::__write, <frame>, (PacketFilter::LOG, [ts=1579727603.636084, node=zeek, filter=ip or not ip, init=T, success=T]))
0.000000 MetaHookPre CallFunction(Log::add_default_filter, <frame>, (Broker::LOG)) 0.000000 MetaHookPre CallFunction(Log::add_default_filter, <frame>, (Broker::LOG))
0.000000 MetaHookPre CallFunction(Log::add_default_filter, <frame>, (Cluster::LOG)) 0.000000 MetaHookPre CallFunction(Log::add_default_filter, <frame>, (Cluster::LOG))
0.000000 MetaHookPre CallFunction(Log::add_default_filter, <frame>, (Config::LOG)) 0.000000 MetaHookPre CallFunction(Log::add_default_filter, <frame>, (Config::LOG))
@ -1351,7 +1361,7 @@
0.000000 MetaHookPre CallFunction(Log::create_stream, <frame>, (Weird::LOG, [columns=Weird::Info, ev=Weird::log_weird, path=weird])) 0.000000 MetaHookPre CallFunction(Log::create_stream, <frame>, (Weird::LOG, [columns=Weird::Info, ev=Weird::log_weird, path=weird]))
0.000000 MetaHookPre CallFunction(Log::create_stream, <frame>, (X509::LOG, [columns=X509::Info, ev=X509::log_x509, path=x509])) 0.000000 MetaHookPre CallFunction(Log::create_stream, <frame>, (X509::LOG, [columns=X509::Info, ev=X509::log_x509, path=x509]))
0.000000 MetaHookPre CallFunction(Log::create_stream, <frame>, (mysql::LOG, [columns=MySQL::Info, ev=MySQL::log_mysql, path=mysql])) 0.000000 MetaHookPre CallFunction(Log::create_stream, <frame>, (mysql::LOG, [columns=MySQL::Info, ev=MySQL::log_mysql, path=mysql]))
0.000000 MetaHookPre CallFunction(Log::write, <frame>, (PacketFilter::LOG, [ts=1573527265.694831, node=zeek, filter=ip or not ip, init=T, success=T])) 0.000000 MetaHookPre CallFunction(Log::write, <frame>, (PacketFilter::LOG, [ts=1579727603.636084, node=zeek, filter=ip or not ip, init=T, success=T]))
0.000000 MetaHookPre CallFunction(NetControl::check_plugins, <frame>, ()) 0.000000 MetaHookPre CallFunction(NetControl::check_plugins, <frame>, ())
0.000000 MetaHookPre CallFunction(NetControl::init, <null>, ()) 0.000000 MetaHookPre CallFunction(NetControl::init, <null>, ())
0.000000 MetaHookPre CallFunction(Notice::want_pp, <frame>, ()) 0.000000 MetaHookPre CallFunction(Notice::want_pp, <frame>, ())
@ -1590,6 +1600,7 @@
0.000000 MetaHookPre LoadFile(0, .<...>/add-geodata.zeek) 0.000000 MetaHookPre LoadFile(0, .<...>/add-geodata.zeek)
0.000000 MetaHookPre LoadFile(0, .<...>/addrs.zeek) 0.000000 MetaHookPre LoadFile(0, .<...>/addrs.zeek)
0.000000 MetaHookPre LoadFile(0, .<...>/analyzer.bif.zeek) 0.000000 MetaHookPre LoadFile(0, .<...>/analyzer.bif.zeek)
0.000000 MetaHookPre LoadFile(0, .<...>/api.zeek)
0.000000 MetaHookPre LoadFile(0, .<...>/ascii.zeek) 0.000000 MetaHookPre LoadFile(0, .<...>/ascii.zeek)
0.000000 MetaHookPre LoadFile(0, .<...>/average.zeek) 0.000000 MetaHookPre LoadFile(0, .<...>/average.zeek)
0.000000 MetaHookPre LoadFile(0, .<...>/benchmark.zeek) 0.000000 MetaHookPre LoadFile(0, .<...>/benchmark.zeek)
@ -1604,6 +1615,7 @@
0.000000 MetaHookPre LoadFile(0, .<...>/const.bif.zeek) 0.000000 MetaHookPre LoadFile(0, .<...>/const.bif.zeek)
0.000000 MetaHookPre LoadFile(0, .<...>/consts.zeek) 0.000000 MetaHookPre LoadFile(0, .<...>/consts.zeek)
0.000000 MetaHookPre LoadFile(0, .<...>/contents.zeek) 0.000000 MetaHookPre LoadFile(0, .<...>/contents.zeek)
0.000000 MetaHookPre LoadFile(0, .<...>/control.zeek)
0.000000 MetaHookPre LoadFile(0, .<...>/ct-list.zeek) 0.000000 MetaHookPre LoadFile(0, .<...>/ct-list.zeek)
0.000000 MetaHookPre LoadFile(0, .<...>/data.bif.zeek) 0.000000 MetaHookPre LoadFile(0, .<...>/data.bif.zeek)
0.000000 MetaHookPre LoadFile(0, .<...>/dcc-send.zeek) 0.000000 MetaHookPre LoadFile(0, .<...>/dcc-send.zeek)
@ -1663,6 +1675,7 @@
0.000000 MetaHookPre LoadFile(0, .<...>/store.zeek) 0.000000 MetaHookPre LoadFile(0, .<...>/store.zeek)
0.000000 MetaHookPre LoadFile(0, .<...>/strings.bif.zeek) 0.000000 MetaHookPre LoadFile(0, .<...>/strings.bif.zeek)
0.000000 MetaHookPre LoadFile(0, .<...>/sum.zeek) 0.000000 MetaHookPre LoadFile(0, .<...>/sum.zeek)
0.000000 MetaHookPre LoadFile(0, .<...>/supervisor.bif.zeek)
0.000000 MetaHookPre LoadFile(0, .<...>/thresholds.zeek) 0.000000 MetaHookPre LoadFile(0, .<...>/thresholds.zeek)
0.000000 MetaHookPre LoadFile(0, .<...>/top-k.bif.zeek) 0.000000 MetaHookPre LoadFile(0, .<...>/top-k.bif.zeek)
0.000000 MetaHookPre LoadFile(0, .<...>/topk.zeek) 0.000000 MetaHookPre LoadFile(0, .<...>/topk.zeek)
@ -1684,6 +1697,7 @@
0.000000 MetaHookPre LoadFile(0, base<...>/addrs.zeek) 0.000000 MetaHookPre LoadFile(0, base<...>/addrs.zeek)
0.000000 MetaHookPre LoadFile(0, base<...>/analyzer) 0.000000 MetaHookPre LoadFile(0, base<...>/analyzer)
0.000000 MetaHookPre LoadFile(0, base<...>/analyzer.bif.zeek) 0.000000 MetaHookPre LoadFile(0, base<...>/analyzer.bif.zeek)
0.000000 MetaHookPre LoadFile(0, base<...>/api.zeek)
0.000000 MetaHookPre LoadFile(0, base<...>/bif) 0.000000 MetaHookPre LoadFile(0, base<...>/bif)
0.000000 MetaHookPre LoadFile(0, base<...>/broker) 0.000000 MetaHookPre LoadFile(0, base<...>/broker)
0.000000 MetaHookPre LoadFile(0, base<...>/cluster) 0.000000 MetaHookPre LoadFile(0, base<...>/cluster)
@ -1764,6 +1778,8 @@
0.000000 MetaHookPre LoadFile(0, base<...>/strings.bif.zeek) 0.000000 MetaHookPre LoadFile(0, base<...>/strings.bif.zeek)
0.000000 MetaHookPre LoadFile(0, base<...>/strings.zeek) 0.000000 MetaHookPre LoadFile(0, base<...>/strings.zeek)
0.000000 MetaHookPre LoadFile(0, base<...>/sumstats) 0.000000 MetaHookPre LoadFile(0, base<...>/sumstats)
0.000000 MetaHookPre LoadFile(0, base<...>/supervisor)
0.000000 MetaHookPre LoadFile(0, base<...>/supervisor.bif.zeek)
0.000000 MetaHookPre LoadFile(0, base<...>/syslog) 0.000000 MetaHookPre LoadFile(0, base<...>/syslog)
0.000000 MetaHookPre LoadFile(0, base<...>/thresholds.zeek) 0.000000 MetaHookPre LoadFile(0, base<...>/thresholds.zeek)
0.000000 MetaHookPre LoadFile(0, base<...>/time.zeek) 0.000000 MetaHookPre LoadFile(0, base<...>/time.zeek)
@ -1949,6 +1965,8 @@
0.000000 | HookCallFunction Analyzer::register_for_ports(Analyzer::ANALYZER_TEREDO, {3544/udp}) 0.000000 | HookCallFunction Analyzer::register_for_ports(Analyzer::ANALYZER_TEREDO, {3544/udp})
0.000000 | HookCallFunction Analyzer::register_for_ports(Analyzer::ANALYZER_VXLAN, {4789/udp}) 0.000000 | HookCallFunction Analyzer::register_for_ports(Analyzer::ANALYZER_VXLAN, {4789/udp})
0.000000 | HookCallFunction Analyzer::register_for_ports(Analyzer::ANALYZER_XMPP, {5222<...>/tcp}) 0.000000 | HookCallFunction Analyzer::register_for_ports(Analyzer::ANALYZER_XMPP, {5222<...>/tcp})
0.000000 | HookCallFunction Broker::__subscribe(zeek/supervisor)
0.000000 | HookCallFunction Broker::subscribe(zeek/supervisor)
0.000000 | HookCallFunction Cluster::is_enabled() 0.000000 | HookCallFunction Cluster::is_enabled()
0.000000 | HookCallFunction Cluster::local_node_type() 0.000000 | HookCallFunction Cluster::local_node_type()
0.000000 | HookCallFunction Cluster::register_pool([topic=zeek<...>/logger, node_type=Cluster::LOGGER, max_nodes=<uninitialized>, exclusive=F]) 0.000000 | HookCallFunction Cluster::register_pool([topic=zeek<...>/logger, node_type=Cluster::LOGGER, max_nodes=<uninitialized>, exclusive=F])
@ -2065,7 +2083,7 @@
0.000000 | HookCallFunction Log::__create_stream(Weird::LOG, [columns=Weird::Info, ev=Weird::log_weird, path=weird]) 0.000000 | HookCallFunction Log::__create_stream(Weird::LOG, [columns=Weird::Info, ev=Weird::log_weird, path=weird])
0.000000 | HookCallFunction Log::__create_stream(X509::LOG, [columns=X509::Info, ev=X509::log_x509, path=x509]) 0.000000 | HookCallFunction Log::__create_stream(X509::LOG, [columns=X509::Info, ev=X509::log_x509, path=x509])
0.000000 | HookCallFunction Log::__create_stream(mysql::LOG, [columns=MySQL::Info, ev=MySQL::log_mysql, path=mysql]) 0.000000 | HookCallFunction Log::__create_stream(mysql::LOG, [columns=MySQL::Info, ev=MySQL::log_mysql, path=mysql])
0.000000 | HookCallFunction Log::__write(PacketFilter::LOG, [ts=1573527265.694831, node=zeek, filter=ip or not ip, init=T, success=T]) 0.000000 | HookCallFunction Log::__write(PacketFilter::LOG, [ts=1579727603.636084, node=zeek, filter=ip or not ip, init=T, success=T])
0.000000 | HookCallFunction Log::add_default_filter(Broker::LOG) 0.000000 | HookCallFunction Log::add_default_filter(Broker::LOG)
0.000000 | HookCallFunction Log::add_default_filter(Cluster::LOG) 0.000000 | HookCallFunction Log::add_default_filter(Cluster::LOG)
0.000000 | HookCallFunction Log::add_default_filter(Config::LOG) 0.000000 | HookCallFunction Log::add_default_filter(Config::LOG)
@ -2246,7 +2264,7 @@
0.000000 | HookCallFunction Log::create_stream(Weird::LOG, [columns=Weird::Info, ev=Weird::log_weird, path=weird]) 0.000000 | HookCallFunction Log::create_stream(Weird::LOG, [columns=Weird::Info, ev=Weird::log_weird, path=weird])
0.000000 | HookCallFunction Log::create_stream(X509::LOG, [columns=X509::Info, ev=X509::log_x509, path=x509]) 0.000000 | HookCallFunction Log::create_stream(X509::LOG, [columns=X509::Info, ev=X509::log_x509, path=x509])
0.000000 | HookCallFunction Log::create_stream(mysql::LOG, [columns=MySQL::Info, ev=MySQL::log_mysql, path=mysql]) 0.000000 | HookCallFunction Log::create_stream(mysql::LOG, [columns=MySQL::Info, ev=MySQL::log_mysql, path=mysql])
0.000000 | HookCallFunction Log::write(PacketFilter::LOG, [ts=1573527265.694831, node=zeek, filter=ip or not ip, init=T, success=T]) 0.000000 | HookCallFunction Log::write(PacketFilter::LOG, [ts=1579727603.636084, node=zeek, filter=ip or not ip, init=T, success=T])
0.000000 | HookCallFunction NetControl::check_plugins() 0.000000 | HookCallFunction NetControl::check_plugins()
0.000000 | HookCallFunction NetControl::init() 0.000000 | HookCallFunction NetControl::init()
0.000000 | HookCallFunction Notice::want_pp() 0.000000 | HookCallFunction Notice::want_pp()
@ -2485,6 +2503,7 @@
0.000000 | HookLoadFile .<...>/add-geodata.zeek 0.000000 | HookLoadFile .<...>/add-geodata.zeek
0.000000 | HookLoadFile .<...>/addrs.zeek 0.000000 | HookLoadFile .<...>/addrs.zeek
0.000000 | HookLoadFile .<...>/analyzer.bif.zeek 0.000000 | HookLoadFile .<...>/analyzer.bif.zeek
0.000000 | HookLoadFile .<...>/api.zeek
0.000000 | HookLoadFile .<...>/archive.sig 0.000000 | HookLoadFile .<...>/archive.sig
0.000000 | HookLoadFile .<...>/ascii.zeek 0.000000 | HookLoadFile .<...>/ascii.zeek
0.000000 | HookLoadFile .<...>/audio.sig 0.000000 | HookLoadFile .<...>/audio.sig
@ -2501,6 +2520,7 @@
0.000000 | HookLoadFile .<...>/const.bif.zeek 0.000000 | HookLoadFile .<...>/const.bif.zeek
0.000000 | HookLoadFile .<...>/consts.zeek 0.000000 | HookLoadFile .<...>/consts.zeek
0.000000 | HookLoadFile .<...>/contents.zeek 0.000000 | HookLoadFile .<...>/contents.zeek
0.000000 | HookLoadFile .<...>/control.zeek
0.000000 | HookLoadFile .<...>/ct-list.zeek 0.000000 | HookLoadFile .<...>/ct-list.zeek
0.000000 | HookLoadFile .<...>/data.bif.zeek 0.000000 | HookLoadFile .<...>/data.bif.zeek
0.000000 | HookLoadFile .<...>/dcc-send.zeek 0.000000 | HookLoadFile .<...>/dcc-send.zeek
@ -2566,6 +2586,7 @@
0.000000 | HookLoadFile .<...>/store.zeek 0.000000 | HookLoadFile .<...>/store.zeek
0.000000 | HookLoadFile .<...>/strings.bif.zeek 0.000000 | HookLoadFile .<...>/strings.bif.zeek
0.000000 | HookLoadFile .<...>/sum.zeek 0.000000 | HookLoadFile .<...>/sum.zeek
0.000000 | HookLoadFile .<...>/supervisor.bif.zeek
0.000000 | HookLoadFile .<...>/thresholds.zeek 0.000000 | HookLoadFile .<...>/thresholds.zeek
0.000000 | HookLoadFile .<...>/top-k.bif.zeek 0.000000 | HookLoadFile .<...>/top-k.bif.zeek
0.000000 | HookLoadFile .<...>/topk.zeek 0.000000 | HookLoadFile .<...>/topk.zeek
@ -2588,6 +2609,7 @@
0.000000 | HookLoadFile base<...>/addrs.zeek 0.000000 | HookLoadFile base<...>/addrs.zeek
0.000000 | HookLoadFile base<...>/analyzer 0.000000 | HookLoadFile base<...>/analyzer
0.000000 | HookLoadFile base<...>/analyzer.bif.zeek 0.000000 | HookLoadFile base<...>/analyzer.bif.zeek
0.000000 | HookLoadFile base<...>/api.zeek
0.000000 | HookLoadFile base<...>/bif 0.000000 | HookLoadFile base<...>/bif
0.000000 | HookLoadFile base<...>/broker 0.000000 | HookLoadFile base<...>/broker
0.000000 | HookLoadFile base<...>/cluster 0.000000 | HookLoadFile base<...>/cluster
@ -2668,6 +2690,8 @@
0.000000 | HookLoadFile base<...>/strings.bif.zeek 0.000000 | HookLoadFile base<...>/strings.bif.zeek
0.000000 | HookLoadFile base<...>/strings.zeek 0.000000 | HookLoadFile base<...>/strings.zeek
0.000000 | HookLoadFile base<...>/sumstats 0.000000 | HookLoadFile base<...>/sumstats
0.000000 | HookLoadFile base<...>/supervisor
0.000000 | HookLoadFile base<...>/supervisor.bif.zeek
0.000000 | HookLoadFile base<...>/syslog 0.000000 | HookLoadFile base<...>/syslog
0.000000 | HookLoadFile base<...>/thresholds.zeek 0.000000 | HookLoadFile base<...>/thresholds.zeek
0.000000 | HookLoadFile base<...>/time.zeek 0.000000 | HookLoadFile base<...>/time.zeek
@ -2681,7 +2705,7 @@
0.000000 | HookLoadFile base<...>/xmpp 0.000000 | HookLoadFile base<...>/xmpp
0.000000 | HookLoadFile base<...>/zeek.bif.zeek 0.000000 | HookLoadFile base<...>/zeek.bif.zeek
0.000000 | HookLogInit packet_filter 1/1 {ts (time), node (string), filter (string), init (bool), success (bool)} 0.000000 | HookLogInit packet_filter 1/1 {ts (time), node (string), filter (string), init (bool), success (bool)}
0.000000 | HookLogWrite packet_filter [ts=1573527265.694831, node=zeek, filter=ip or not ip, init=T, success=T] 0.000000 | HookLogWrite packet_filter [ts=1579727603.636084, node=zeek, filter=ip or not ip, init=T, success=T]
0.000000 | HookQueueEvent NetControl::init() 0.000000 | HookQueueEvent NetControl::init()
0.000000 | HookQueueEvent filter_change_tracking() 0.000000 | HookQueueEvent filter_change_tracking()
0.000000 | HookQueueEvent zeek_init() 0.000000 | HookQueueEvent zeek_init()

View file

@ -0,0 +1,2 @@
supervised node zeek_init(), logger-1, Cluster::LOGGER
supervised node zeek_done(), logger-1, logger-1

View file

@ -0,0 +1,2 @@
supervised node zeek_init(), manager, Cluster::MANAGER
supervised node zeek_done(), manager, manager

View file

@ -0,0 +1,2 @@
supervised node zeek_init(), proxy-1, Cluster::PROXY
supervised node zeek_done(), proxy-1, proxy-1

View file

@ -0,0 +1,3 @@
supervisor zeek_init()
shutting down
supervisor zeek_done()

View file

@ -0,0 +1,2 @@
supervised node zeek_init(), worker-1, Cluster::WORKER
supervised node zeek_done(), worker-1, worker-1

View file

@ -0,0 +1,2 @@
supervised node zeek_init()
supervised node zeek_done()

View file

@ -0,0 +1,3 @@
supervisor zeek_init()
destroying node
supervisor zeek_done()

View file

@ -0,0 +1,3 @@
(stderr) supervised node zeek_init()
received termination signal
(stderr) supervised node zeek_done()

View file

@ -0,0 +1,2 @@
(stdout) supervised node zeek_init()
(stdout) supervised node zeek_done()

View file

@ -0,0 +1,3 @@
supervisor zeek_init()
destroying node
supervisor zeek_done()

View file

@ -0,0 +1,3 @@
supervised node zeek_init()
supervised node loaded qux.zeek
supervised node zeek_done()

View file

@ -0,0 +1,3 @@
supervisor zeek_init()
destroying node
supervisor zeek_done()

View file

@ -0,0 +1,2 @@
supervised node zeek_init()
supervised node zeek_done()

View file

@ -0,0 +1,2 @@
supervisor zeek_init()
supervisor zeek_done()

View file

@ -0,0 +1,2 @@
supervised node zeek_init()
supervised node zeek_done()

View file

@ -0,0 +1,3 @@
supervisor zeek_init()
destroying node
supervisor zeek_done()

View file

@ -0,0 +1,3 @@
got supervised node status, grault
got supervised node status, grault
got supervised node status, grault

View file

@ -0,0 +1,2 @@
supervised node zeek_init()
supervised node zeek_done()

View file

@ -0,0 +1,7 @@
supervisor zeek_init()
supervisor connected to peer
supervisor lost peer
supervisor connected to peer
supervisor lost peer
supervisor connected to peer
supervisor zeek_done()

View file

@ -0,0 +1,2 @@
supervised node zeek_init()
supervised node zeek_done()

View file

@ -0,0 +1,7 @@
supervisor zeek_init()
supervisor connected to peer
supervisor lost peer
supervisor connected to peer
supervisor lost peer
supervisor connected to peer
supervisor zeek_done()

View file

@ -0,0 +1 @@
got supervised node status, grault

View file

@ -1,5 +1,5 @@
[btest] [btest]
TestDirs = doc bifs language core scripts coverage signatures plugins broker TestDirs = doc bifs language core scripts coverage signatures plugins broker supervisor
TmpDir = %(testbase)s/.tmp TmpDir = %(testbase)s/.tmp
BaselineDir = %(testbase)s/Baseline BaselineDir = %(testbase)s/Baseline
IgnoreDirs = .svn CVS .tmp IgnoreDirs = .svn CVS .tmp

View file

@ -0,0 +1,89 @@
# @TEST-PORT: SUPERVISOR_PORT
# @TEST-PORT: MANAGER_PORT
# @TEST-PORT: LOGGER_PORT
# @TEST-PORT: PROXY_PORT
# @TEST-PORT: WORKER_PORT
# @TEST-EXEC: btest-bg-run zeek zeek -j -b %INPUT
# @TEST-EXEC: btest-bg-wait 20
# @TEST-EXEC: btest-diff zeek/supervisor.out
# @TEST-EXEC: btest-diff zeek/manager/stdout
# @TEST-EXEC: btest-diff zeek/logger-1/stdout
# @TEST-EXEC: btest-diff zeek/worker-1/stdout
# @TEST-EXEC: btest-diff zeek/proxy-1/stdout
@load base/frameworks/cluster
# So the supervised node doesn't terminate right away.
redef exit_only_after_terminate=T;
global supervisor_output_file: file;
global topic = "test-topic";
global peer_count = 0;
event shutdown()
{
print supervisor_output_file, "shutting down";
terminate();
}
event zeek_init()
{
if ( Supervisor::is_supervisor() )
{
Broker::subscribe(topic);
Broker::listen("127.0.0.1", to_port(getenv("SUPERVISOR_PORT")));
supervisor_output_file = open("supervisor.out");
print supervisor_output_file, "supervisor zeek_init()";
local cluster: table[string] of Supervisor::ClusterEndpoint;
cluster["manager"] = [$role=Supervisor::MANAGER, $host=127.0.0.1,
$p=to_port(getenv("MANAGER_PORT"))];
cluster["logger-1"] = [$role=Supervisor::LOGGER, $host=127.0.0.1,
$p=to_port(getenv("LOGGER_PORT"))];
cluster["proxy-1"] = [$role=Supervisor::PROXY, $host=127.0.0.1,
$p=to_port(getenv("PROXY_PORT"))];
cluster["worker-1"] = [$role=Supervisor::WORKER, $host=127.0.0.1,
$p=to_port(getenv("WORKER_PORT"))];
for ( n, ep in cluster )
{
local sn = Supervisor::NodeConfig($name = n);
sn$cluster = cluster;
sn$directory = n;
sn$stdout_file = "stdout";
sn$stderr_file = "stderr";
local res = Supervisor::create(sn);
if ( res != "" )
print fmt("failed to create node %s: %s", n, res);
}
}
else
{
Broker::peer("127.0.0.1", to_port(getenv("SUPERVISOR_PORT")));
print "supervised node zeek_init()", Cluster::node, Cluster::local_node_type();
}
}
event Broker::peer_added(endpoint: Broker::EndpointInfo, msg: string)
{
++peer_count;
if ( Supervisor::is_supervised() )
{
if ( Cluster::node == "manager" && peer_count == 4 )
Broker::publish(topic, shutdown);
}
}
event Broker::peer_lost(endpoint: Broker::EndpointInfo, msg: string)
{
}
event zeek_done()
{
if ( Supervisor::is_supervised() )
print "supervised node zeek_done()", Cluster::node, Supervisor::node()$name;
else
print supervisor_output_file, "supervisor zeek_done()";
}

View file

@ -0,0 +1,60 @@
# @TEST-PORT: BROKER_PORT
# @TEST-EXEC: btest-bg-run zeek zeek -j -b %INPUT
# @TEST-EXEC: btest-bg-wait 20
# @TEST-EXEC: btest-diff zeek/supervisor.out
# @TEST-EXEC: btest-diff zeek/qux/node.out
# So the supervised node doesn't terminate right away.
redef exit_only_after_terminate=T;
global supervisor_output_file: file;
global node_output_file: file;
global topic = "test-topic";
event do_destroy()
{
print supervisor_output_file, "destroying node";
Supervisor::destroy("grault");
}
event zeek_init()
{
if ( Supervisor::is_supervisor() )
{
Broker::subscribe(topic);
Broker::listen("127.0.0.1", to_port(getenv("BROKER_PORT")));
supervisor_output_file = open("supervisor.out");
print supervisor_output_file, "supervisor zeek_init()";
local sn = Supervisor::NodeConfig($name="grault", $directory="qux");
local res = Supervisor::create(sn);
if ( res != "" )
print supervisor_output_file, res;
}
else
{
Broker::peer("127.0.0.1", to_port(getenv("BROKER_PORT")));
node_output_file = open("node.out");
print node_output_file, "supervised node zeek_init()";
}
}
event Broker::peer_added(endpoint: Broker::EndpointInfo, msg: string)
{
if ( Supervisor::is_supervised() )
Broker::publish(topic, do_destroy);
}
event Broker::peer_lost(endpoint: Broker::EndpointInfo, msg: string)
{
# Should only be run by supervisor
terminate();
}
event zeek_done()
{
if ( Supervisor::is_supervised() )
print node_output_file, "supervised node zeek_done()";
else
print supervisor_output_file, "supervisor zeek_done()";
}

View file

@ -0,0 +1,66 @@
# @TEST-PORT: BROKER_PORT
# @TEST-EXEC: btest-bg-run zeek zeek -j -b %INPUT
# @TEST-EXEC: btest-bg-wait 20
# @TEST-EXEC: btest-diff zeek/supervisor.out
# @TEST-EXEC: btest-diff zeek/qux/grault.stdout
# @TEST-EXEC: btest-diff zeek/qux/grault.stderr
# So the supervised node doesn't terminate right away.
redef exit_only_after_terminate=T;
global supervisor_output_file: file;
global topic = "test-topic";
global stderr = open("/dev/stderr");
event do_destroy()
{
print supervisor_output_file, "destroying node";
Supervisor::destroy("grault");
}
event zeek_init()
{
if ( Supervisor::is_supervisor() )
{
Broker::subscribe(topic);
Broker::listen("127.0.0.1", to_port(getenv("BROKER_PORT")));
supervisor_output_file = open("supervisor.out");
print supervisor_output_file, "supervisor zeek_init()";
local sn = Supervisor::NodeConfig($name="grault", $directory="qux",
$stdout_file="grault.stdout",
$stderr_file="grault.stderr");
local res = Supervisor::create(sn);
if ( res != "" )
print supervisor_output_file, res;
}
else
{
Broker::peer("127.0.0.1", to_port(getenv("BROKER_PORT")));
print "(stdout) supervised node zeek_init()";
print stderr, "(stderr) supervised node zeek_init()";
}
}
event Broker::peer_added(endpoint: Broker::EndpointInfo, msg: string)
{
if ( Supervisor::is_supervised() )
Broker::publish(topic, do_destroy);
}
event Broker::peer_lost(endpoint: Broker::EndpointInfo, msg: string)
{
# Should only be run by supervisor
terminate();
}
event zeek_done()
{
if ( Supervisor::is_supervised() )
{
print "(stdout) supervised node zeek_done()";
print stderr, "(stderr) supervised node zeek_done()";
}
else
print supervisor_output_file, "supervisor zeek_done()";
}

View file

@ -0,0 +1,70 @@
# @TEST-PORT: BROKER_PORT
# @TEST-EXEC: btest-bg-run zeek zeek -j -b %INPUT
# @TEST-EXEC: btest-bg-wait 20
# @TEST-EXEC: btest-diff zeek/supervisor.out
# @TEST-EXEC: btest-diff zeek/node.out
# So the supervised node doesn't terminate right away.
redef exit_only_after_terminate=T;
global supervisor_output_file: file;
global node_output_file: file;
global topic = "test-topic";
event do_destroy()
{
print supervisor_output_file, "destroying node";
Supervisor::destroy("grault");
}
event zeek_init()
{
if ( Supervisor::is_supervisor() )
{
Broker::subscribe(topic);
Broker::listen("127.0.0.1", to_port(getenv("BROKER_PORT")));
supervisor_output_file = open("supervisor.out");
print supervisor_output_file, "supervisor zeek_init()";
local sn = Supervisor::NodeConfig($name="grault",
$scripts=vector("../qux.zeek"));
local res = Supervisor::create(sn);
if ( res != "" )
print supervisor_output_file, res;
}
else
{
Broker::peer("127.0.0.1", to_port(getenv("BROKER_PORT")));
node_output_file = open("node.out");
print node_output_file, "supervised node zeek_init()";
}
}
event Broker::peer_added(endpoint: Broker::EndpointInfo, msg: string)
{
if ( Supervisor::is_supervised() )
Broker::publish(topic, do_destroy);
}
event Broker::peer_lost(endpoint: Broker::EndpointInfo, msg: string)
{
# Should only be run by supervisor
terminate();
}
event zeek_done()
{
if ( Supervisor::is_supervised() )
print node_output_file, "supervised node zeek_done()";
else
print supervisor_output_file, "supervisor zeek_done()";
}
@TEST-START-FILE qux.zeek
event zeek_init() &priority=-10
{
print node_output_file, "supervised node loaded qux.zeek";
}
@TEST-END-FILE

View file

@ -0,0 +1,42 @@
# @TEST-EXEC: btest-bg-run zeek zeek -j -b %INPUT
# @TEST-EXEC: btest-bg-wait 20
# @TEST-EXEC: btest-diff zeek/supervisor.out
# @TEST-EXEC: btest-diff zeek/node.out
# So the supervised node doesn't terminate right away.
redef exit_only_after_terminate=T;
global supervisor_output_file: file;
global node_output_file: file;
event zeek_init()
{
local pid_file = "supervisor.pid";
if ( Supervisor::is_supervisor() )
{
supervisor_output_file = open("supervisor.out");
print supervisor_output_file, "supervisor zeek_init()";
local f = open(pid_file);
print f, getpid();
local sn = Supervisor::NodeConfig($name="grault");
local res = Supervisor::create(sn);
if ( res != "" )
print supervisor_output_file, res;
}
else
{
node_output_file = open("node.out");
print node_output_file, "supervised node zeek_init()";
system(fmt("kill `cat %s`", pid_file));
}
}
event zeek_done()
{
if ( Supervisor::is_supervised() )
print node_output_file, "supervised node zeek_done()";
else
print supervisor_output_file, "supervisor zeek_done()";
}

View file

@ -0,0 +1,60 @@
# @TEST-PORT: BROKER_PORT
# @TEST-EXEC: btest-bg-run zeek zeek -j -b %INPUT
# @TEST-EXEC: btest-bg-wait 20
# @TEST-EXEC: btest-diff zeek/supervisor.out
# @TEST-EXEC: btest-diff zeek/node.out
# So the supervised node doesn't terminate right away.
redef exit_only_after_terminate=T;
global supervisor_output_file: file;
global node_output_file: file;
global topic = "test-topic";
event do_destroy()
{
print supervisor_output_file, "destroying node";
Supervisor::destroy("grault");
}
event zeek_init()
{
if ( Supervisor::is_supervisor() )
{
Broker::subscribe(topic);
Broker::listen("127.0.0.1", to_port(getenv("BROKER_PORT")));
supervisor_output_file = open("supervisor.out");
print supervisor_output_file, "supervisor zeek_init()";
local sn = Supervisor::NodeConfig($name="grault");
local res = Supervisor::create(sn);
if ( res != "" )
print supervisor_output_file, res;
}
else
{
Broker::peer("127.0.0.1", to_port(getenv("BROKER_PORT")));
node_output_file = open("node.out");
print node_output_file, "supervised node zeek_init()";
}
}
event Broker::peer_added(endpoint: Broker::EndpointInfo, msg: string)
{
if ( Supervisor::is_supervised() )
Broker::publish(topic, do_destroy);
}
event Broker::peer_lost(endpoint: Broker::EndpointInfo, msg: string)
{
# Should only be run by supervisor
terminate();
}
event zeek_done()
{
if ( Supervisor::is_supervised() )
print node_output_file, "supervised node zeek_done()";
else
print supervisor_output_file, "supervisor zeek_done()";
}

View file

@ -0,0 +1,66 @@
# @TEST-EXEC: btest-bg-run zeek zeek -j -b %INPUT
# @TEST-EXEC: btest-bg-wait 20
# @TEST-EXEC: btest-diff zeek/.stdout
# So the supervised node doesn't terminate right away.
redef exit_only_after_terminate=T;
global node_pid: int = 0;
global status_count = 0;
global check_interval = 0.1sec;
event check_status(name: string &default="")
{
local s = Supervisor::status(name);
local ns = s$nodes["grault"];
if ( ! ns?$pid )
{
schedule check_interval { check_status() };
return;
}
if ( status_count > 0 && node_pid == ns$pid )
{
schedule check_interval { check_status() };
return;
}
print "got supervised node status", ns$node$name;
node_pid = ns$pid;
++status_count;
if ( status_count == 1 )
{
Supervisor::restart();
schedule check_interval { check_status() };
}
else if ( status_count == 2 )
{
Supervisor::restart("grault");
schedule check_interval { check_status("grault") };
}
else
terminate();
}
event zeek_init()
{
if ( Supervisor::is_supervisor() )
{
local sn = Supervisor::NodeConfig($name="grault");
local res = Supervisor::create(sn);
if ( res != "" )
print "failed to create node", res;
sn$name = "qux";
res = Supervisor::create(sn);
if ( res != "" )
print "failed to create node", res;
event check_status();
}
}

View file

@ -0,0 +1,70 @@
# @TEST-PORT: BROKER_PORT
# @TEST-EXEC: btest-bg-run zeek zeek -j -b %INPUT
# @TEST-EXEC: btest-bg-wait 20
# @TEST-EXEC: btest-diff zeek/supervisor.out
# @TEST-EXEC: btest-diff zeek/node.out
# So the supervised node doesn't terminate right away.
redef exit_only_after_terminate=T;
global supervisor_output_file: file;
global node_output_file: file;
global topic = "test-topic";
global peers_added = 0;
event kill_self()
{
system(fmt("kill %s", getpid()));
}
event zeek_init()
{
if ( Supervisor::is_supervisor() )
{
Broker::subscribe(topic);
Broker::listen("127.0.0.1", to_port(getenv("BROKER_PORT")));
supervisor_output_file = open("supervisor.out");
print supervisor_output_file, "supervisor zeek_init()";
local sn = Supervisor::NodeConfig($name="grault");
local res = Supervisor::create(sn);
if ( res != "" )
print supervisor_output_file, res;
}
else
{
Broker::subscribe(topic);
Broker::peer("127.0.0.1", to_port(getenv("BROKER_PORT")));
node_output_file = open("node.out");
print node_output_file, "supervised node zeek_init()";
}
}
event Broker::peer_added(endpoint: Broker::EndpointInfo, msg: string)
{
++peers_added;
if ( Supervisor::is_supervisor() )
{
print supervisor_output_file, "supervisor connected to peer";
if ( peers_added == 3 )
terminate();
else
Broker::publish(topic, kill_self);
}
}
event Broker::peer_lost(endpoint: Broker::EndpointInfo, msg: string)
{
if ( Supervisor::is_supervisor() )
print supervisor_output_file, "supervisor lost peer";
}
event zeek_done()
{
if ( Supervisor::is_supervisor() )
print supervisor_output_file, "supervisor zeek_done()";
else
print node_output_file, "supervised node zeek_done()";
}

View file

@ -0,0 +1,65 @@
# @TEST-PORT: BROKER_PORT
# @TEST-EXEC: btest-bg-run zeek zeek -j -b %INPUT
# @TEST-EXEC: btest-bg-wait 20
# @TEST-EXEC: btest-diff zeek/supervisor.out
# @TEST-EXEC: btest-diff zeek/node.out
# So the supervised node doesn't terminate right away.
redef exit_only_after_terminate=T;
global supervisor_output_file: file;
global node_output_file: file;
global topic = "test-topic";
global peers_added = 0;
event zeek_init()
{
if ( Supervisor::is_supervisor() )
{
Broker::subscribe(topic);
Broker::listen("127.0.0.1", to_port(getenv("BROKER_PORT")));
supervisor_output_file = open("supervisor.out");
print supervisor_output_file, "supervisor zeek_init()";
local sn = Supervisor::NodeConfig($name="grault");
local res = Supervisor::create(sn);
if ( res != "" )
print supervisor_output_file, res;
}
else
{
Broker::subscribe(topic);
Broker::peer("127.0.0.1", to_port(getenv("BROKER_PORT")));
node_output_file = open("node.out");
print node_output_file, "supervised node zeek_init()";
}
}
event Broker::peer_added(endpoint: Broker::EndpointInfo, msg: string)
{
++peers_added;
if ( Supervisor::is_supervisor() )
{
print supervisor_output_file, "supervisor connected to peer";
if ( peers_added == 3 )
terminate();
else
system(fmt("kill %s", Supervisor::__stem_pid()));
}
}
event Broker::peer_lost(endpoint: Broker::EndpointInfo, msg: string)
{
if ( Supervisor::is_supervisor() )
print supervisor_output_file, "supervisor lost peer";
}
event zeek_done()
{
if ( Supervisor::is_supervisor() )
print supervisor_output_file, "supervisor zeek_done()";
else
print node_output_file, "supervised node zeek_done()";
}

View file

@ -0,0 +1,34 @@
# @TEST-EXEC: btest-bg-run zeek zeek -j -b %INPUT
# @TEST-EXEC: btest-bg-wait 20
# @TEST-EXEC: btest-diff zeek/.stdout
# So the supervised node doesn't terminate right away.
redef exit_only_after_terminate=T;
event check_status()
{
local s = Supervisor::status();
local ns = s$nodes["grault"];
if ( ! ns?$pid )
schedule 0.25sec { check_status() };
else
{
print "got supervised node status", ns$node$name;
terminate();
}
}
event zeek_init()
{
if ( Supervisor::is_supervisor() )
{
local sn = Supervisor::NodeConfig($name="grault");
local res = Supervisor::create(sn);
if ( res != "" )
print "failed to create node", res;
event check_status();
}
}