Add config framework.

The configuration framework consists of three mostly distinct parts:

* option variables
* the config reader
* the script level framework

I will describe the three elements in the following.

Internally, this commit also performs a range of changes to the Input
manager; it marks a lot of functions as const and introduces a new
ValueToVal method (which could in theory replace the already existing
one - it is a bit more powerful).

This also changes SerialTypes to have a subtype for Values, just as
Fields already have it; I think it was mostly an oversight that this was
not introduced from the beginning. This should not necessitate any code
changes for people already using SerialTypes.

option variable
===============

The option keyword allows variables to be specified as run-tine options.
Such variables cannot be changed using normal assignments. Instead, they
can be changed using Option::set. It is possible to "subscribe" to
options and be notified when an option value changes.

Change handlers can also change values before they are applied; this
gives them the opportunity to reject changes. Priorities can be
specified if there are several handlers for one option.

Example script:

option testbool: bool = T;

function option_changed(ID: string, new_value: bool): bool
  {
  print fmt("Value of %s changed from %s to %s", ID, testbool, new_value);
  return new_value;
  }

event bro_init()
  {
  print "Old value", testbool;
  Option::set_change_handler("testbool", option_changed);
  Option::set("testbool", F);
  print "New value", testbool;
  }

config reader
=============

The config reader provides a way to read configuration files back into
Bro. Most importantly it automatically converts values to the correct
types. This is important because it is at least inconvenient (and
sometimes near impossible) to perform the necessary type conversions in
Bro scripts themselves. This is especially true for sets/vectors.

Configuration generally look like this:

[option name][tab/spaces][new variable value]

so, for example:

testaddr 2607:f8b0:4005:801::200e
testinterval 60
testtime 1507321987
test_set a	b	c	d	erdbeerschnitzel

The reader uses the option name to look up the type that variable has in
the Bro core and automatically converts the value to the correct type.

Example script use:

type Idx: record {
  option_name: string;
};

type Val: record {
  option_val: string;
};

global currconfig: table[string] of string = table();

event InputConfig::new_value(name: string, source: string, id: string, value: any)
  {
  print id, value;
  }

event bro_init()
  {
  Input::add_table([$reader=Input::READER_CONFIG, $source="../configfile", $name="configuration", $idx=Idx, $val=Val, $destination=currconfig, $want_record=F]);
  }

Script-level config framework
=============================

The script-level framework ties these two features together and makes
them a bit more convenient to use. Configuration files can simply be
specified by placing them into Config::config_files. The framework also
creates a config.log that shows all value changes that took place.

Usage example:

redef Config::config_files += {configfile};

export {
  option testbool : bool = F;
}

The file is now monitored for changes; when a change occurs the
respective option values are automatically updated and the value change
is written to config.log.
This commit is contained in:
Johanna Amann 2017-11-29 13:18:46 -08:00
parent f8f343fd3a
commit db6f028003
79 changed files with 1910 additions and 111 deletions

View file

@ -14,6 +14,8 @@ Network Protocols
+============================+=======================================+=================================+
| conn.log | TCP/UDP/ICMP connections | :bro:type:`Conn::Info` |
+----------------------------+---------------------------------------+---------------------------------+
| config.log | Configuration option changes | :bro:type:`Config::Info` |
+----------------------------+---------------------------------------+---------------------------------+
| dce_rpc.log | Distributed Computing Environment/RPC | :bro:type:`DCE_RPC::Info` |
+----------------------------+---------------------------------------+---------------------------------+
| dhcp.log | DHCP leases | :bro:type:`DHCP::Info` |

View file

@ -0,0 +1,2 @@
The configuration famework provides a way to change the Bro configuration
in "option" values at run-time.

View file

@ -0,0 +1,2 @@
@load ./main
@load ./input

View file

@ -0,0 +1,76 @@
##! File input for the configuration framework using the input framework.
@load ./main
@load base/frameworks/cluster
module Config;
export {
## Configuration files that will be read off disk. Files are reread
## every time they are updated so updates should be atomic with "mv"
## instead of writing the file in place.
##
## If the same configuration option is defined in several files with
## different values, behavior is unspecified.
const config_files: set[string] = {} &redef;
## Read specified configuration file and apply values; updates to file
## are not tracked.
global read_config: function(filename: string);
}
global current_config: table[string] of string = table();
type ConfigItem: record {
option_nv: string;
};
type EventFields: record {
option_name: string;
option_val: string;
};
event config_line(description: Input::EventDescription, tpe: Input::Event, p: EventFields)
{
}
event bro_init() &priority=5
{
if ( Cluster::is_enabled() && Cluster::local_node_type() != Cluster::MANAGER )
return;
for ( fi in config_files )
Input::add_table([$reader=Input::READER_CONFIG,
$mode=Input::REREAD,
$source=fi,
$name=cat("config-", fi),
$idx=ConfigItem,
$val=ConfigItem,
$want_record=F,
$destination=current_config]);
}
event InputConfig::new_value(name: string, source: string, id: string, value: any)
{
if ( sub_bytes(name, 1, 7) != "config-" || source !in config_files )
if ( sub_bytes(name, 1, 15) != "config-oneshot-" )
return;
Option::set(id, value, source);
}
function read_config(filename: string)
{
if ( Cluster::is_enabled() && Cluster::local_node_type() != Cluster::MANAGER )
return;
local iname = cat("config-oneshot-", filename);
Input::add_event([$reader=Input::READER_CONFIG,
$mode=Input::MANUAL,
$source=filename,
$name=iname,
$fields=EventFields,
$ev=config_line]);
Input::remove(iname);
}

View file

@ -0,0 +1,77 @@
##! The configuration framework provides a way to change Bro options
##! (as specified by the option keyword) at runtime. It also logs runtime changes
##! to options to config.log.
module Config;
export {
## The config logging stream identifier.
redef enum Log::ID += { LOG };
## Represents the data in config.log.
type Info: record {
## Timestamp at which the configuration change occured.
ts: time &log;
## ID of the value that was changed.
id: string &log;
## Value before the change.
old_value: string &log;
## Value after the change.
new_value: string &log;
## Optional location that triggered the change.
location: string &optional &log;
};
## Event that can be handled to access the :bro:type:`Config::Info`
## record as it is sent on to the logging framework.
global log_config: event(rec: Info);
}
function format_value(value: any) : string
{
local tn = type_name(value);
local part: string_vec = vector();
if ( /^set/ in tn )
{
local it: set[bool] = value;
for ( sv in it )
part[|part|] = cat(sv);
return join_string_vec(part, ",");
}
else if ( /^vector/ in tn )
{
local vit: vector of any = value;
for ( i in vit )
part[|part|] = cat(vit[i]);
return join_string_vec(part, ",");
}
else if ( tn == "string" )
return value;
return cat(value);
}
function config_option_changed(ID: string, new_value: any, location: string): any
{
local log = Info($ts=network_time(), $id=ID, $old_value=format_value(lookup_ID(ID)), $new_value=format_value(new_value));
if ( location != "" )
log$location = location;
Log::write(LOG, log);
return new_value;
}
event bro_init() &priority=10
{
Log::create_stream(LOG, [$columns=Info, $ev=log_config, $path="config"]);
# Iterate over all existing options and add ourselves as change handlers with
# a low priority so that we can log the changes.
local gids = global_ids();
for ( i in gids )
{
if ( ! gids[i]$option_value )
next;
Option::set_change_handler(i, config_option_changed, -100);
}
}

View file

@ -3,4 +3,5 @@
@load ./readers/raw
@load ./readers/benchmark
@load ./readers/binary
@load ./readers/config
@load ./readers/sqlite

View file

@ -9,7 +9,7 @@ export {
## Please note that the separator has to be exactly one character long.
const separator = Input::separator &redef;
## Separator between set elements.
## Separator between set and vector elements.
## Please note that the separator has to be exactly one character long.
const set_separator = Input::set_separator &redef;

View file

@ -0,0 +1,42 @@
##! Interface for the config input reader.
module InputConfig;
export {
## Separator between set and vector elements.
## Please note that the separator has to be exactly one character long.
const set_separator = Input::set_separator &redef;
## String to use for empty fields.
const empty_field = Input::empty_field &redef;
## Fail on file read problems. If set to true, the config
## input reader will fail when encountering any problems
## while reading a file different from invalid lines.
## Examples of such problems are permission problems, or
## missing files.
## When set to false, these problems will be ignored. This
## has an especially big effect for the REREAD mode, which will
## seamlessly recover from read errors when a file is
## only temporarily inaccessible. For MANUAL or STREAM files,
## errors will most likely still be fatal since no automatic
## re-reading of the file is attempted.
## Individual readers can use a different value using
## the $config table.
const fail_on_file_problem = F &redef;
## Event that is called when a config option is added or changes.
##
## Note - this does not track the reason for a change (new, changed),
## and also does not track removals. If you need this, combine the event
## with a table reader.
##
## name: name of the input stream.
##
## source: source of the input stream.
##
## id: ID of the configuration option being set.
##
## value: new value of the configuration option being set.
global new_value: event(name: string, source: string, id: string, value: any);
}

View file

@ -631,6 +631,7 @@ type script_id: record {
exported: bool; ##< True if the identifier is exported.
constant: bool; ##< True if the identifier is a constant.
enum_constant: bool; ##< True if the identifier is an enum value.
option_value: bool; ##< True if the identifier is an option.
redefinable: bool; ##< True if the identifier is declared with the :bro:attr:`&redef` attribute.
value: any &optional; ##< The current value of the identifier.
};

View file

@ -36,6 +36,7 @@
@load base/frameworks/control
@load base/frameworks/cluster
@load base/frameworks/intel
@load base/frameworks/config
@load base/frameworks/reporter
@load base/frameworks/sumstats
@load base/frameworks/tunnels

View file

@ -124,6 +124,7 @@ set(BIF_SRCS
types.bif
strings.bif
reporter.bif
option.bif
)
foreach (bift ${BIF_SRCS})

View file

@ -283,6 +283,9 @@ Expr* NameExpr::MakeLvalue()
if ( id->IsConst() && ! in_const_init )
ExprError("const is not a modifiable lvalue");
if ( id->IsOption() && ! in_const_init )
ExprError("option is not a modifiable lvalue");
return new RefExpr(this);
}

View file

@ -647,11 +647,13 @@ void builtin_error(const char* msg, BroObj* arg)
#include "stats.bif.func_h"
#include "reporter.bif.func_h"
#include "strings.bif.func_h"
#include "option.bif.func_h"
#include "bro.bif.func_def"
#include "stats.bif.func_def"
#include "reporter.bif.func_def"
#include "strings.bif.func_def"
#include "option.bif.func_def"
#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.
@ -676,6 +678,7 @@ void init_builtin_funcs()
#include "stats.bif.func_init"
#include "reporter.bif.func_init"
#include "strings.bif.func_init"
#include "option.bif.func_init"
did_builtin_init = true;
}

View file

@ -21,12 +21,13 @@ ID::ID(const char* arg_name, IDScope arg_scope, bool arg_is_export)
name = copy_string(arg_name);
scope = arg_scope;
is_export = arg_is_export;
is_option = false;
type = 0;
val = 0;
attrs = 0;
is_const = 0;
is_enum_const = 0;
is_type = 0;
is_const = false;
is_enum_const = false;
is_type = false;
offset = 0;
infer_return_type = false;
@ -41,6 +42,8 @@ ID::~ID()
Unref(type);
Unref(attrs);
for ( auto element : option_handlers )
Unref(element.second);
if ( ! weak_ref )
Unref(val);
}
@ -772,3 +775,18 @@ void ID::UpdateValID()
}
#endif
void ID::AddOptionHandler(Func* callback, int priority)
{
option_handlers.insert({priority, callback});
}
vector<Func*> ID::GetOptionHandlers() const
{
// multimap is sorted
// It might be worth caching this if we expect it to be called
// a lot...
vector<Func*> v;
for ( auto& element : option_handlers )
v.push_back(element.second);
return v;
}

View file

@ -11,6 +11,7 @@
class Val;
class SerialInfo;
class Func;
typedef enum { INIT_NONE, INIT_FULL, INIT_EXTRA, INIT_REMOVE, } init_class;
typedef enum { SCOPE_FUNCTION, SCOPE_MODULE, SCOPE_GLOBAL } IDScope;
@ -34,7 +35,7 @@ public:
BroType* Type() { return type; }
const BroType* Type() const { return type; }
void MakeType() { is_type = 1; }
void MakeType() { is_type = true; }
BroType* AsType() { return is_type ? Type() : 0; }
const BroType* AsType() const { return is_type ? Type() : 0; }
@ -51,21 +52,24 @@ public:
void SetVal(Val* v, init_class c);
void SetVal(Expr* ev, init_class c);
int HasVal() const { return val != 0; }
bool HasVal() const { return val != 0; }
Val* ID_Val() { return val; }
const Val* ID_Val() const { return val; }
void ClearVal();
void SetConst() { is_const = 1; }
int IsConst() const { return is_const; }
void SetConst() { is_const = true; }
bool IsConst() const { return is_const; }
void SetEnumConst() { is_enum_const = 1; }
int IsEnumConst() const { return is_enum_const; }
void SetOption() { is_option = true; }
bool IsOption() const { return is_option; }
void SetEnumConst() { is_enum_const = true; }
bool IsEnumConst() const { return is_enum_const; }
void SetOffset(int arg_offset) { offset = arg_offset; }
int Offset() const { return offset; }
int IsRedefinable() const { return FindAttr(ATTR_REDEF) != 0; }
bool IsRedefinable() const { return FindAttr(ATTR_REDEF) != 0; }
// Returns true if ID is one of those internal globally unique IDs
// to which MutableVals are bound (there name start with a '#').
@ -97,12 +101,18 @@ public:
bool Serialize(SerialInfo* info) const;
static ID* Unserialize(UnserialInfo* info);
bool DoInferReturnType() { return infer_return_type; }
bool DoInferReturnType() const
{ return infer_return_type; }
void SetInferReturnType(bool infer)
{ infer_return_type = infer; }
virtual TraversalCode Traverse(TraversalCallback* cb) const;
bool HasOptionHandlers() const
{ return !option_handlers.empty(); }
void AddOptionHandler(Func* callback, int priority);
vector<Func*> GetOptionHandlers() const;
protected:
ID() { name = 0; type = 0; val = 0; attrs = 0; }
@ -119,10 +129,12 @@ protected:
IDScope scope;
bool is_export;
BroType* type;
int is_const, is_enum_const, is_type;
bool is_const, is_enum_const, is_type, is_option;
int offset;
Val* val;
Attributes* attrs;
// contains list of functions that are called when an option changes
std::multimap<int, Func*> option_handlers;
bool infer_return_type;
bool weak_ref;

View file

@ -142,6 +142,11 @@ static void make_var(ID* id, BroType* t, init_class c, Expr* init,
id->Error("&persistant/synchronized with constant");
return;
}
else if ( dt == VAR_OPTION )
{
id->Error("&persistant/synchronized with option");
return;
}
if ( ! id->IsGlobal() )
{
@ -206,6 +211,13 @@ static void make_var(ID* id, BroType* t, init_class c, Expr* init,
id->SetConst();
}
if ( dt == VAR_OPTION )
{
if ( ! init )
id->Error("option variable must be initialized");
id->SetOption();
}
id->UpdateValAttrs();

View file

@ -10,7 +10,7 @@
class Func;
class EventHandlerPtr;
typedef enum { VAR_REGULAR, VAR_CONST, VAR_REDEF, } decl_type;
typedef enum { VAR_REGULAR, VAR_CONST, VAR_REDEF, VAR_OPTION, } decl_type;
extern void add_global(ID* id, BroType* t, init_class c, Expr* init,
attr_list* attr, decl_type dt);

View file

@ -1775,13 +1775,14 @@ function global_ids%(%): id_table
rec->Assign(1, new Val(id->IsExport(), TYPE_BOOL));
rec->Assign(2, new Val(id->IsConst(), TYPE_BOOL));
rec->Assign(3, new Val(id->IsEnumConst(), TYPE_BOOL));
rec->Assign(4, new Val(id->IsRedefinable(), TYPE_BOOL));
rec->Assign(4, new Val(id->IsOption(), TYPE_BOOL));
rec->Assign(5, new Val(id->IsRedefinable(), TYPE_BOOL));
if ( id->HasVal() )
{
Val* val = id->ID_Val();
Ref(val);
rec->Assign(5, val);
rec->Assign(6, val);
}
Val* id_name = new StringVal(id->Name());

View file

@ -160,7 +160,7 @@ ScriptInfo::ScriptInfo(const string& arg_name, const string& arg_path)
name(arg_name), path(arg_path),
is_pkg_loader(SafeBasename(name).result == PACKAGE_LOADER),
dependencies(), module_usages(), comments(), id_info(),
options(), constants(), state_vars(), types(), events(), hooks(),
redef_options(), constants(), state_vars(), types(), events(), hooks(),
functions(), redefs()
{
}
@ -219,9 +219,9 @@ void ScriptInfo::DoInitPostScript()
{
if ( id->FindAttr(ATTR_REDEF) )
{
DBG_LOG(DBG_BROXYGEN, "Filter id '%s' in '%s' as an option",
DBG_LOG(DBG_BROXYGEN, "Filter id '%s' in '%s' as a redef_option",
id->Name(), name.c_str());
options.push_back(info);
redef_options.push_back(info);
}
else
{
@ -232,6 +232,14 @@ void ScriptInfo::DoInitPostScript()
continue;
}
else if ( id->IsOption() )
{
DBG_LOG(DBG_BROXYGEN, "Filter id '%s' in '%s' as a redef_option",
id->Name(), name.c_str());
options.push_back(info);
continue;
}
if ( id->Type()->Tag() == TYPE_ENUM )
// Enums are always referenced/documented from the type's
@ -309,7 +317,8 @@ string ScriptInfo::DoReStructuredText(bool roles_only) const
rval += fmt(":Source File: :download:`/scripts/%s`\n", name.c_str());
rval += "\n";
rval += broxygen::make_heading("Summary", '~');
rval += make_summary("Options", '#', '=', options);
rval += make_summary("Runtime Options", '#', '=', options);
rval += make_summary("Redefinable Options", '#', '=', redef_options);
rval += make_summary("Constants", '#', '=', constants);
rval += make_summary("State Variables", '#', '=', state_vars);
rval += make_summary("Types", '#', '=', types);
@ -319,7 +328,8 @@ string ScriptInfo::DoReStructuredText(bool roles_only) const
rval += make_summary("Functions", '#', '=', functions);
rval += "\n";
rval += broxygen::make_heading("Detailed Interface", '~');
rval += make_details("Options", '#', options);
rval += make_details("Runtime Options", '#', options);
rval += make_details("Redefinable Options", '#', redef_options);
rval += make_details("Constants", '#', constants);
rval += make_details("State Variables", '#', state_vars);
rval += make_details("Types", '#', types);

View file

@ -108,6 +108,7 @@ private:
string_set module_usages;
std::vector<std::string> comments;
id_info_map id_info;
id_info_list redef_options;
id_info_list options;
id_info_list constants;
id_info_list state_vars;

View file

@ -711,7 +711,7 @@ bool Manager::CreateTableStream(RecordVal* fval)
return true;
}
bool Manager::CheckErrorEventTypes(std::string stream_name, Func* ev, bool table)
bool Manager::CheckErrorEventTypes(std::string stream_name, const Func* ev, bool table) const
{
if ( ev == nullptr )
return true;
@ -899,7 +899,7 @@ bool Manager::RemoveStreamContinuation(ReaderFrontend* reader)
}
bool Manager::UnrollRecordType(vector<Field*> *fields, const RecordType *rec,
const string& nameprepend, bool allow_file_func)
const string& nameprepend, bool allow_file_func) const
{
for ( int i = 0; i < rec->NumFields(); i++ )
{
@ -1007,7 +1007,7 @@ bool Manager::ForceUpdate(const string &name)
}
Val* Manager::RecordValToIndexVal(RecordVal *r)
Val* Manager::RecordValToIndexVal(RecordVal *r) const
{
Val* idxval;
@ -1032,7 +1032,7 @@ Val* Manager::RecordValToIndexVal(RecordVal *r)
}
Val* Manager::ValueToIndexVal(const Stream* i, int num_fields, const RecordType *type, const Value* const *vals, bool& have_error)
Val* Manager::ValueToIndexVal(const Stream* i, int num_fields, const RecordType *type, const Value* const *vals, bool& have_error) const
{
Val* idxval;
int position = 0;
@ -1810,7 +1810,7 @@ bool Manager::Delete(ReaderFrontend* reader, Value* *vals)
return success;
}
bool Manager::CallPred(Func* pred_func, const int numvals, ...)
bool Manager::CallPred(Func* pred_func, const int numvals, ...) const
{
bool result = false;
val_list vl(numvals);
@ -1835,7 +1835,7 @@ bool Manager::CallPred(Func* pred_func, const int numvals, ...)
// Raise everything in here as warnings so it is passed to scriptland without
// looking "fatal". In addition to these warnings, ReaderBackend will queue
// one reporter message.
bool Manager::SendEvent(ReaderFrontend* reader, const string& name, const int num_vals, Value* *vals)
bool Manager::SendEvent(ReaderFrontend* reader, const string& name, const int num_vals, Value* *vals) const
{
Stream *i = FindStream(reader);
if ( i == 0 )
@ -1871,7 +1871,15 @@ bool Manager::SendEvent(ReaderFrontend* reader, const string& name, const int nu
val_list* vl = new val_list;
for ( int j = 0; j < num_vals; j++)
vl->append(ValueToVal(i, vals[j], type->FieldType(j), convert_error));
{
Val* v = ValueToVal(i, vals[j], convert_error);
vl->append(v);
if ( v && ! convert_error && ! same_type(type->FieldType(j), v->Type()) )
{
convert_error = true;
type->FieldType(j)->Error("SendEvent types do not match", v->Type());
}
}
delete_value_ptr_array(vals, num_vals);
@ -1886,7 +1894,7 @@ bool Manager::SendEvent(ReaderFrontend* reader, const string& name, const int nu
return true;
}
void Manager::SendEvent(EventHandlerPtr ev, const int numvals, ...)
void Manager::SendEvent(EventHandlerPtr ev, const int numvals, ...) const
{
val_list* vl = new val_list;
@ -1905,7 +1913,7 @@ void Manager::SendEvent(EventHandlerPtr ev, const int numvals, ...)
mgr.QueueEvent(ev, vl, SOURCE_LOCAL);
}
void Manager::SendEvent(EventHandlerPtr ev, list<Val*> events)
void Manager::SendEvent(EventHandlerPtr ev, list<Val*> events) const
{
val_list* vl = new val_list;
@ -1924,7 +1932,7 @@ void Manager::SendEvent(EventHandlerPtr ev, list<Val*> events)
// Convert a bro list value to a bro record value.
// I / we could think about moving this functionality to val.cc
RecordVal* Manager::ListValToRecordVal(ListVal* list, RecordType *request_type, int* position)
RecordVal* Manager::ListValToRecordVal(ListVal* list, RecordType *request_type, int* position) const
{
assert(position != 0 ); // we need the pointer to point to data;
@ -1954,7 +1962,7 @@ RecordVal* Manager::ListValToRecordVal(ListVal* list, RecordType *request_type,
// Convert a threading value to a record value
RecordVal* Manager::ValueToRecordVal(const Stream* stream, const Value* const *vals,
RecordType *request_type, int* position, bool& have_error)
RecordType *request_type, int* position, bool& have_error) const
{
assert(position != 0); // we need the pointer to point to data.
@ -1991,7 +1999,8 @@ RecordVal* Manager::ValueToRecordVal(const Stream* stream, const Value* const *v
// Count the length of the values used to create a correct length buffer for
// hashing later
int Manager::GetValueLength(const Value* val) {
int Manager::GetValueLength(const Value* val) const
{
assert( val->present ); // presence has to be checked elsewhere
int length = 0;
@ -2081,7 +2090,7 @@ int Manager::GetValueLength(const Value* val) {
// Given a threading::value, copy the raw data bytes into *data and return how many bytes were copied.
// Used for hashing the values for lookup in the bro table
int Manager::CopyValue(char *data, const int startpos, const Value* val)
int Manager::CopyValue(char *data, const int startpos, const Value* val) const
{
assert( val->present ); // presence has to be checked elsewhere
@ -2205,7 +2214,7 @@ int Manager::CopyValue(char *data, const int startpos, const Value* val)
}
// Hash num_elements threading values and return the HashKey for them. At least one of the vals has to be ->present.
HashKey* Manager::HashValues(const int num_elements, const Value* const *vals)
HashKey* Manager::HashValues(const int num_elements, const Value* const *vals) const
{
int length = 0;
@ -2251,19 +2260,19 @@ HashKey* Manager::HashValues(const int num_elements, const Value* const *vals)
// have_error is a reference to a boolean which is set to true as soon as an error occured.
// When have_error is set to true at the beginning of the function, it is assumed that
// an error already occured in the past and processing is aborted.
Val* Manager::ValueToVal(const Stream* i, const Value* val, BroType* request_type, bool& have_error)
Val* Manager::ValueToVal(const Stream* i, const Value* val, BroType* request_type, bool& have_error) const
{
if ( have_error )
return 0;
return nullptr;
if ( request_type->Tag() != TYPE_ANY && request_type->Tag() != val->type )
{
reporter->InternalError("Typetags don't match: %d vs %d in stream %s", request_type->Tag(), val->type, i->name.c_str());
return 0;
return nullptr;
}
if ( !val->present )
return 0; // unset field
return nullptr; // unset field
switch ( val->type ) {
case TYPE_BOOL:
@ -2312,7 +2321,7 @@ Val* Manager::ValueToVal(const Stream* i, const Value* val, BroType* request_typ
case TYPE_SUBNET:
{
IPAddr* addr = 0;
IPAddr* addr = nullptr;
switch ( val->val.subnet_val.prefix.family ) {
case IPv4:
addr = new IPAddr(val->val.subnet_val.prefix.in.in4);
@ -2359,7 +2368,7 @@ Val* Manager::ValueToVal(const Stream* i, const Value* val, BroType* request_typ
VectorVal* v = new VectorVal(vt);
for ( int j = 0; j < val->val.vector_val.size; j++ )
{
v->Assign(j, ValueToVal(i, val->val.set_val.vals[j], type, have_error));
v->Assign(j, ValueToVal(i, val->val.vector_val.vals[j], type, have_error));
}
Unref(vt);
@ -2384,7 +2393,7 @@ Val* Manager::ValueToVal(const Stream* i, const Value* val, BroType* request_typ
enum_string.c_str(), i->name.c_str());
have_error = true;
return 0;
return nullptr;
}
return new EnumVal(index, request_type->Ref()->AsEnumType());
@ -2398,9 +2407,177 @@ Val* Manager::ValueToVal(const Stream* i, const Value* val, BroType* request_typ
return NULL;
}
Manager::Stream* Manager::FindStream(const string &name)
Val* Manager::ValueToVal(const Stream* i, const Value* val, bool& have_error) const
{
for ( map<ReaderFrontend*, Stream*>::iterator s = readers.begin(); s != readers.end(); ++s )
if ( have_error )
return nullptr;
if ( !val->present )
return nullptr; // unset field
switch ( val->type ) {
case TYPE_BOOL:
case TYPE_INT:
return new Val(val->val.int_val, val->type);
break;
case TYPE_COUNT:
case TYPE_COUNTER:
return new Val(val->val.uint_val, val->type);
case TYPE_DOUBLE:
case TYPE_TIME:
case TYPE_INTERVAL:
return new Val(val->val.double_val, val->type);
case TYPE_STRING:
{
BroString *s = new BroString((const u_char*)val->val.string_val.data, val->val.string_val.length, 1);
return new StringVal(s);
}
case TYPE_PORT:
return new PortVal(val->val.port_val.port, val->val.port_val.proto);
case TYPE_ADDR:
{
IPAddr* addr = 0;
switch ( val->val.addr_val.family ) {
case IPv4:
addr = new IPAddr(val->val.addr_val.in.in4);
break;
case IPv6:
addr = new IPAddr(val->val.addr_val.in.in6);
break;
default:
assert(false);
}
AddrVal* addrval = new AddrVal(*addr);
delete addr;
return addrval;
}
case TYPE_SUBNET:
{
IPAddr* addr = nullptr;
switch ( val->val.subnet_val.prefix.family ) {
case IPv4:
addr = new IPAddr(val->val.subnet_val.prefix.in.in4);
break;
case IPv6:
addr = new IPAddr(val->val.subnet_val.prefix.in.in6);
break;
default:
assert(false);
}
SubNetVal* subnetval = new SubNetVal(*addr, val->val.subnet_val.length);
delete addr;
return subnetval;
}
case TYPE_TABLE:
{
TypeList* set_index;
if ( val->val.set_val.size == 0 && val->subtype == TYPE_VOID )
// don't know type - unspecified table.
set_index = new TypeList();
else
{
// all entries have to have the same type...
TypeTag stag = val->subtype;
if ( stag == TYPE_VOID )
TypeTag stag = val->val.set_val.vals[0]->type;
set_index = new TypeList(base_type(stag)->Ref());
set_index->Append(base_type(stag)->Ref());
}
SetType* s = new SetType(set_index, 0);
TableVal* t = new TableVal(s);
for ( int j = 0; j < val->val.set_val.size; j++ )
{
Val* assignval = ValueToVal(i, val->val.set_val.vals[j], have_error);
t->Assign(assignval, 0);
Unref(assignval); // index is not consumed by assign.
}
Unref(s);
return t;
}
case TYPE_VECTOR:
{
BroType* type;
if ( val->val.vector_val.size == 0 && val->subtype == TYPE_VOID )
// don't know type - unspecified table.
type = base_type(TYPE_ANY);
else
{
// all entries have to have the same type...
if ( val->subtype == TYPE_VOID )
type = base_type(val->val.vector_val.vals[0]->type);
else
type = base_type(val->subtype);
}
VectorType* vt = new VectorType(type->Ref());
VectorVal* v = new VectorVal(vt);
for ( int j = 0; j < val->val.vector_val.size; j++ )
{
v->Assign(j, ValueToVal(i, val->val.vector_val.vals[j], have_error));
}
Unref(vt);
return v;
}
case TYPE_ENUM: {
// Convert to string first to not have to deal with missing
// \0's...
string enum_string(val->val.string_val.data, val->val.string_val.length);
// let's try looking it up by global ID.
ID* id = lookup_ID(enum_string.c_str(), GLOBAL_MODULE_NAME);
if ( ! id || ! id->IsEnumConst() )
{
Warning(i, "Value '%s' for stream '%s' is not a valid enum.",
enum_string.c_str(), i->name.c_str());
have_error = true;
return nullptr;
}
EnumType* t = id->Type()->AsEnumType();
int intval = t->Lookup(id->ModuleName(), id->Name());
if ( intval < 0 )
{
Warning(i, "Enum value '%s' for stream '%s' not found.",
enum_string.c_str(), i->name.c_str());
have_error = true;
return nullptr;
}
return new EnumVal(intval, t);
}
default:
reporter->InternalError("Unsupported type for input_read in stream %s", i->name.c_str());
}
assert(false);
return NULL;
}
Manager::Stream* Manager::FindStream(const string &name) const
{
for ( auto s = readers.begin(); s != readers.end(); ++s )
{
if ( (*s).second->name == name )
return (*s).second;
@ -2409,9 +2586,9 @@ Manager::Stream* Manager::FindStream(const string &name)
return 0;
}
Manager::Stream* Manager::FindStream(ReaderFrontend* reader)
Manager::Stream* Manager::FindStream(ReaderFrontend* reader) const
{
map<ReaderFrontend*, Stream*>::iterator s = readers.find(reader);
auto s = readers.find(reader);
if ( s != readers.end() )
return s->second;
@ -2433,7 +2610,7 @@ void Manager::Terminate()
}
void Manager::Info(ReaderFrontend* reader, const char* msg)
void Manager::Info(ReaderFrontend* reader, const char* msg) const
{
Stream *i = FindStream(reader);
if ( !i )
@ -2445,7 +2622,7 @@ void Manager::Info(ReaderFrontend* reader, const char* msg)
ErrorHandler(i, ErrorType::INFO, false, "%s", msg);
}
void Manager::Warning(ReaderFrontend* reader, const char* msg)
void Manager::Warning(ReaderFrontend* reader, const char* msg) const
{
Stream *i = FindStream(reader);
if ( !i )
@ -2457,7 +2634,7 @@ void Manager::Warning(ReaderFrontend* reader, const char* msg)
ErrorHandler(i, ErrorType::WARNING, false, "%s", msg);
}
void Manager::Error(ReaderFrontend* reader, const char* msg)
void Manager::Error(ReaderFrontend* reader, const char* msg) const
{
Stream *i = FindStream(reader);
if ( !i )
@ -2469,7 +2646,7 @@ void Manager::Error(ReaderFrontend* reader, const char* msg)
ErrorHandler(i, ErrorType::ERROR, false, "%s", msg);
}
void Manager::Info(const Stream* i, const char* fmt, ...)
void Manager::Info(const Stream* i, const char* fmt, ...) const
{
va_list ap;
va_start(ap, fmt);
@ -2477,7 +2654,7 @@ void Manager::Info(const Stream* i, const char* fmt, ...)
va_end(ap);
}
void Manager::Warning(const Stream* i, const char* fmt, ...)
void Manager::Warning(const Stream* i, const char* fmt, ...) const
{
va_list ap;
va_start(ap, fmt);
@ -2485,7 +2662,7 @@ void Manager::Warning(const Stream* i, const char* fmt, ...)
va_end(ap);
}
void Manager::Error(const Stream* i, const char* fmt, ...)
void Manager::Error(const Stream* i, const char* fmt, ...) const
{
va_list ap;
va_start(ap, fmt);
@ -2493,7 +2670,7 @@ void Manager::Error(const Stream* i, const char* fmt, ...)
va_end(ap);
}
void Manager::ErrorHandler(const Stream* i, ErrorType et, bool reporter_send, const char* fmt, ...)
void Manager::ErrorHandler(const Stream* i, ErrorType et, bool reporter_send, const char* fmt, ...) const
{
va_list ap;
va_start(ap, fmt);
@ -2501,7 +2678,7 @@ void Manager::ErrorHandler(const Stream* i, ErrorType et, bool reporter_send, co
va_end(ap);
}
void Manager::ErrorHandler(const Stream* i, ErrorType et, bool reporter_send, const char* fmt, va_list ap)
void Manager::ErrorHandler(const Stream* i, ErrorType et, bool reporter_send, const char* fmt, va_list ap) const
{
char* buf;

View file

@ -98,6 +98,21 @@ public:
*/
void Terminate();
/**
* Checks if a Bro type can be used for data reading. Note that
* this function only applies to input streams; the logging framework
* has an equivalent function; however we support logging of a wider
* variety of types (e.g. functions).
*
* @param t The type to check.
*
* @param atomic_only Set to true to forbid non-atomic types
* (records/sets/vectors).
*
* @return True if the type is compatible with the input framework.
*/
static bool IsCompatibleType(BroType* t, bool atomic_only=false);
protected:
friend class ReaderFrontend;
friend class PutMessage;
@ -130,7 +145,7 @@ protected:
// Allows readers to directly send Bro events. The num_vals and vals
// must be the same the named event expects. Takes ownership of
// threading::Value fields.
bool SendEvent(ReaderFrontend* reader, const string& name, const int num_vals, threading::Value* *vals);
bool SendEvent(ReaderFrontend* reader, const string& name, const int num_vals, threading::Value* *vals) const;
// Instantiates a new ReaderBackend of the given type (note that
// doing so creates a new thread!).
@ -147,9 +162,9 @@ protected:
// Signal Informational messages, warnings and errors. These will be
// passed to the error function in scriptland. Note that the messages
// are not passed to reporter - this is done in ReaderBackend.
void Info(ReaderFrontend* reader, const char* msg);
void Warning(ReaderFrontend* reader, const char* msg);
void Error(ReaderFrontend* reader, const char* msg);
void Info(ReaderFrontend* reader, const char* msg) const;
void Warning(ReaderFrontend* reader, const char* msg) const;
void Error(ReaderFrontend* reader, const char* msg) const;
/**
* Deletes an existing input stream.
@ -176,7 +191,7 @@ private:
// Check if the types of the error_ev event are correct. If table is
// true, check for tablestream type, otherwhise check for eventstream
// type.
bool CheckErrorEventTypes(std::string stream_name, Func* error_event, bool table);
bool CheckErrorEventTypes(std::string stream_name, const Func* error_event, bool table) const;
// SendEntry implementation for Table stream.
int SendEntryTable(Stream* i, const threading::Value* const *vals);
@ -187,63 +202,63 @@ private:
// SendEntry and Put implementation for Event stream.
int SendEventStreamEvent(Stream* i, EnumVal* type, const threading::Value* const *vals);
// Checks that a Bro type can be used for data reading. The
// equivalend in threading cannot be used, because we have support
// different types from the log framework
bool IsCompatibleType(BroType* t, bool atomic_only=false);
// Check if a record is made up of compatible types and return a list
// of all fields that are in the record in order. Recursively unrolls
// records
bool UnrollRecordType(vector<threading::Field*> *fields, const RecordType *rec, const string& nameprepend, bool allow_file_func);
bool UnrollRecordType(vector<threading::Field*> *fields, const RecordType *rec, const string& nameprepend, bool allow_file_func) const;
// Send events
void SendEvent(EventHandlerPtr ev, const int numvals, ...);
void SendEvent(EventHandlerPtr ev, list<Val*> events);
void SendEvent(EventHandlerPtr ev, const int numvals, ...) const;
void SendEvent(EventHandlerPtr ev, list<Val*> events) const;
// Implementation of SendEndOfData (send end_of_data event).
void SendEndOfData(const Stream *i);
// Call predicate function and return result.
bool CallPred(Func* pred_func, const int numvals, ...);
bool CallPred(Func* pred_func, const int numvals, ...) const;
// Get a hashkey for a set of threading::Values.
HashKey* HashValues(const int num_elements, const threading::Value* const *vals);
HashKey* HashValues(const int num_elements, const threading::Value* const *vals) const;
// Get the memory used by a specific value.
int GetValueLength(const threading::Value* val);
int GetValueLength(const threading::Value* val) const;
// Copies the raw data in a specific threading::Value to position
// startpos.
int CopyValue(char *data, const int startpos, const threading::Value* val);
int CopyValue(char *data, const int startpos, const threading::Value* val) const;
// Convert Threading::Value to an internal Bro Type (works also with
// Records).
Val* ValueToVal(const Stream* i, const threading::Value* val, BroType* request_type, bool& have_error);
Val* ValueToVal(const Stream* i, const threading::Value* val, BroType* request_type, bool& have_error) const;
// Convert Threading::Value to an internal Bro List type.
Val* ValueToIndexVal(const Stream* i, int num_fields, const RecordType* type, const threading::Value* const *vals, bool& have_error);
// Convert Threading::Value to an internal Bro type just using the information given in the threading::Value.
// This allows more flexibility, especially given structures in script-land that contain any types.
Val* ValueToVal(const Stream* i, const threading::Value* val, bool& have_error) const;
// Convert Threading::Value to an internal Bro list type.
Val* ValueToIndexVal(const Stream* i, int num_fields, const RecordType* type, const threading::Value* const *vals, bool& have_error) const;
// Converts a threading::value to a record type. Mostly used by
// ValueToVal.
RecordVal* ValueToRecordVal(const Stream* i, const threading::Value* const *vals, RecordType *request_type, int* position, bool& have_error);
RecordVal* ValueToRecordVal(const Stream* i, const threading::Value* const *vals, RecordType *request_type, int* position, bool& have_error) const;
Val* RecordValToIndexVal(RecordVal *r);
Val* RecordValToIndexVal(RecordVal *r) const;
// Converts a Bro ListVal to a RecordVal given the record type.
RecordVal* ListValToRecordVal(ListVal* list, RecordType *request_type, int* position);
RecordVal* ListValToRecordVal(ListVal* list, RecordType *request_type, int* position) const;
// Internally signal errors, warnings, etc.
// These are sent on to input scriptland and reporter.log
void Info(const Stream* i, const char* fmt, ...) __attribute__((format(printf, 3, 4)));
void Warning(const Stream* i, const char* fmt, ...) __attribute__((format(printf, 3, 4)));
void Error(const Stream* i, const char* fmt, ...) __attribute__((format(printf, 3, 4)));
void Info(const Stream* i, const char* fmt, ...) const __attribute__((format(printf, 3, 4)));
void Warning(const Stream* i, const char* fmt, ...) const __attribute__((format(printf, 3, 4)));
void Error(const Stream* i, const char* fmt, ...) const __attribute__((format(printf, 3, 4)));
enum class ErrorType { INFO, WARNING, ERROR };
void ErrorHandler(const Stream* i, ErrorType et, bool reporter_send, const char* fmt, ...) __attribute__((format(printf, 5, 6)));
void ErrorHandler(const Stream* i, ErrorType et, bool reporter_send, const char* fmt, va_list ap) __attribute__((format(printf, 5, 0)));
void ErrorHandler(const Stream* i, ErrorType et, bool reporter_send, const char* fmt, ...) const __attribute__((format(printf, 5, 6)));
void ErrorHandler(const Stream* i, ErrorType et, bool reporter_send, const char* fmt, va_list ap) const __attribute__((format(printf, 5, 0)));
Stream* FindStream(const string &name);
Stream* FindStream(ReaderFrontend* reader);
Stream* FindStream(const string &name) const;
Stream* FindStream(ReaderFrontend* reader) const;
enum StreamType { TABLE_STREAM, EVENT_STREAM, ANALYSIS_STREAM };

View file

@ -2,5 +2,6 @@
add_subdirectory(ascii)
add_subdirectory(benchmark)
add_subdirectory(binary)
add_subdirectory(config)
add_subdirectory(raw)
add_subdirectory(sqlite)

View file

@ -125,7 +125,7 @@ bool Benchmark::DoUpdate()
threading::Value* Benchmark::EntryToVal(TypeTag type, TypeTag subtype)
{
Value* val = new Value(type, true);
Value* val = new Value(type, subtype, true);
// basically construct something random from the fields that we want.

View file

@ -0,0 +1,9 @@
include(BroPlugin)
include_directories(BEFORE ${CMAKE_CURRENT_SOURCE_DIR} ${CMAKE_CURRENT_BINARY_DIR})
bro_plugin_begin(Bro ConfigReader)
bro_plugin_cc(Config.cc Plugin.cc)
bro_plugin_bif(config.bif)
bro_plugin_end()

View file

@ -0,0 +1,310 @@
// See the file "COPYING" in the main distribution directory for copyright.
#include <sstream>
#include <unordered_set>
#include <regex>
#include <sys/types.h>
#include <sys/stat.h>
#include <unistd.h>
#include <errno.h>
#include "Config.h"
#include "config.bif.h"
#include "input/Manager.h"
#include "threading/SerialTypes.h"
using namespace input::reader;
using namespace threading;
using threading::Value;
using threading::Field;
Config::Config(ReaderFrontend *frontend) : ReaderBackend(frontend)
{
mtime = 0;
suppress_warnings = false;
fail_on_file_problem = false;
// find all option names and their types.
auto globals = global_scope()->Vars();
auto c = globals->InitForIteration();
while ( auto id = globals->NextEntry(c) )
{
if ( id->IsInternalGlobal() || ! id->IsOption() )
continue;
if ( id->Type()->Tag() == TYPE_RECORD ||
! input::Manager::IsCompatibleType(id->Type()) )
{
option_types[id->Name()] = std::make_tuple(TYPE_ERROR, id->Type()->Tag());
continue;
}
TypeTag primary = id->Type()->Tag();
TypeTag secondary = TYPE_VOID;
if ( primary == TYPE_TABLE )
secondary = id->Type()->AsSetType()->Indices()->PureType()->Tag();
else if ( primary == TYPE_VECTOR )
secondary = id->Type()->AsVectorType()->YieldType()->Tag();
option_types[id->Name()] = std::make_tuple(primary, secondary);
}
}
Config::~Config()
{
}
void Config::DoClose()
{
}
bool Config::DoInit(const ReaderInfo& info, int num_fields, const Field* const* fields)
{
fail_on_file_problem = BifConst::InputConfig::fail_on_file_problem;
set_separator.assign( (const char*) BifConst::InputConfig::set_separator->Bytes(),
BifConst::InputConfig::set_separator->Len());
empty_field.assign( (const char*) BifConst::InputConfig::empty_field->Bytes(),
BifConst::InputConfig::empty_field->Len());
formatter::Ascii::SeparatorInfo sep_info("\t", set_separator, "", empty_field);
formatter = unique_ptr<threading::formatter::Formatter>(new formatter::Ascii(this, sep_info));
return DoUpdate();
}
bool Config::OpenFile()
{
if ( file.is_open() )
return true;
file.open(Info().source);
if ( ! file.is_open() )
{
FailWarn(fail_on_file_problem, Fmt("Init: cannot open %s", Info().source), true);
return ! fail_on_file_problem;
}
suppress_warnings = false;
return true;
}
void Config::FailWarn(bool is_error, const char *msg, bool suppress_future)
{
if ( is_error )
Error(msg);
else
{
// suppress error message when we are already in error mode.
// There is no reason to repeat it every second.
if ( ! suppress_warnings )
Warning(msg);
if ( suppress_future )
suppress_warnings = true;
}
}
bool Config::GetLine(string& str)
{
while ( getline(file, str) )
{
if ( ! str.size() )
continue;
if ( str.back() == '\r' ) // deal with \r\n by removing \r
str.pop_back();
if ( str[0] != '#' )
return true;
}
return false;
}
// read the entire file and send appropriate thingies back to InputMgr
bool Config::DoUpdate()
{
if ( ! OpenFile() )
return ! fail_on_file_problem;
switch ( Info().mode ) {
case MODE_REREAD:
{
// check if the file has changed
struct stat sb;
if ( stat(Info().source, &sb) == -1 )
{
FailWarn(fail_on_file_problem, Fmt("Could not get stat for %s", Info().source), true);
file.close();
return ! fail_on_file_problem;
}
if ( sb.st_mtime <= mtime ) // no change
return true;
mtime = sb.st_mtime;
// file changed. reread.
// fallthrough
}
case MODE_MANUAL:
case MODE_STREAM:
{
// dirty, fix me. (well, apparently after trying seeking, etc
// - this is not that bad)
if ( file.is_open() )
{
if ( Info().mode == MODE_STREAM )
{
file.clear(); // remove end of file evil bits
break;
}
file.close();
}
OpenFile();
break;
}
default:
assert(false);
}
string line;
file.sync();
// keep a list of options to remove because they were no longer in the input file.
// Start out with all element and removes while going along
std::unordered_set<std::string> unseen_options;
for ( auto i : option_values )
{
unseen_options.insert(i.first);
}
while ( GetLine(line) )
{
static std::regex re("^(.*?)\\s+(.*)$");
std::smatch match;
if ( ! std::regex_search(line, match, re) )
{
Warning(Fmt("Could not parse '%s'; line has invalid format. Ignoring line.", line.c_str()));
continue;
}
string key = match[1];
string value = match[2];
auto typeit = option_types.find(key);
if ( typeit == option_types.end() )
{
Warning(Fmt("Option '%s' does not exist. Ignoring line.", key.c_str()));
continue;
}
if ( std::get<0>((*typeit).second) == TYPE_ERROR )
{
Warning(Fmt("Option '%s' has type '%s', which is not supported for file input. Ignoring line.", key.c_str(), type_name(std::get<1>((*typeit).second))));
continue;
}
Value* eventval = formatter->ParseValue(value, key, std::get<0>((*typeit).second), std::get<1>((*typeit).second));
if ( ! eventval )
{
Warning(Fmt("Could not convert line '%s' to Val. Ignoring line.", line.c_str()));
continue;
}
else if ( ! eventval->present )
{
Warning(Fmt("Line '%s' has no Value. Ignoring line.", line.c_str()));
delete eventval;
continue;
}
// we only send the event if the underlying value has changed. Let's check that.
// (Yes, this means we keep all configuration options in memory twice - once here in
// the reader and once in memory in Bro; that is difficult to change.
auto search = option_values.find(key);
if ( search != option_values.end() && search->second == value )
{
delete eventval;
continue;
}
option_values[key] = value;
unseen_options.erase(key);
{
Value** fields = new Value*[2];
Value* keyval = new threading::Value(TYPE_STRING, true);
keyval->val.string_val.length = key.size();
keyval->val.string_val.data = copy_string(key.c_str());
fields[0] = keyval;
Value* val = new threading::Value(TYPE_STRING, true);
val->val.string_val.length = value.size();
val->val.string_val.data = copy_string(value.c_str());
fields[1] = val;
if ( Info().mode == MODE_STREAM )
Put(fields);
else
SendEntry(fields);
}
{
Value** vals = new Value*[4];
vals[0] = new Value(TYPE_STRING, true);
vals[0]->val.string_val.data = copy_string(Info().name);
vals[0]->val.string_val.length = strlen(Info().name);
vals[1] = new Value(TYPE_STRING, true);
vals[1]->val.string_val.data = copy_string(Info().source);
vals[1]->val.string_val.length = strlen(Info().source);
vals[2] = new Value(TYPE_STRING, true);
vals[2]->val.string_val.data = copy_string(key.c_str());
vals[2]->val.string_val.length = key.size();
vals[3] = eventval;
SendEvent("InputConfig::new_value", 4, vals);
}
}
if ( Info().mode != MODE_STREAM )
EndCurrentSend();
// clean up all options we did not see
for ( auto i : unseen_options )
option_values.erase(i);
return true;
}
bool Config::DoHeartbeat(double network_time, double current_time)
{
switch ( Info().mode )
{
case MODE_MANUAL:
// yay, we do nothing :)
break;
case MODE_REREAD:
case MODE_STREAM:
Update(); // call update and not DoUpdate, because update
// checks disabled.
break;
default:
assert(false);
}
return true;
}

View file

@ -0,0 +1,67 @@
// See the file "COPYING" in the main distribution directory for copyright.
#ifndef INPUT_READERS_CONFIG_H
#define INPUT_READERS_CONFIG_H
#include <iostream>
#include <vector>
#include <fstream>
#include <memory>
#include <unordered_map>
#include "input/ReaderBackend.h"
#include "threading/formatters/Ascii.h"
namespace input { namespace reader {
/**
* Reader for Configuration files.
*/
class Config : public ReaderBackend {
public:
explicit Config(ReaderFrontend* frontend);
~Config();
// prohibit copying and moving
Config(const Config&) = delete;
Config(Config&&) = delete;
Config& operator=(const Config&) = delete;
Config& operator=(Config&&) = delete;
static ReaderBackend* Instantiate(ReaderFrontend* frontend) { return new Config(frontend); }
protected:
bool DoInit(const ReaderInfo& info, int arg_num_fields, const threading::Field* const* fields) override;
void DoClose() override;
bool DoUpdate() override;
bool DoHeartbeat(double network_time, double current_time) override;
private:
bool GetLine(string& str);
bool OpenFile();
// Call Warning or Error, depending on the is_error boolean.
// In case of a warning, setting suppress_future to true will suppress all future warnings
// (by setting suppress_warnings to true, until suppress_warnings is set back to false)
void FailWarn(bool is_error, const char *msg, bool suppress_future = false);
ifstream file;
time_t mtime;
bool fail_on_file_problem;
// this is an internal indicator in case the read is currently in a failed state
// it's used to suppress duplicate error messages.
bool suppress_warnings;
string set_separator;
string empty_field;
std::unique_ptr<threading::formatter::Formatter> formatter;
std::unordered_map<std::string, std::tuple<TypeTag, TypeTag>> option_types;
std::unordered_map<std::string, std::string> option_values;
};
}
}
#endif /* INPUT_READERS_CONFIG_H */

View file

@ -0,0 +1,24 @@
// See the file in the main distribution directory for copyright.
#include "plugin/Plugin.h"
#include "Config.h"
namespace plugin {
namespace Bro_ConfigReader {
class Plugin : public plugin::Plugin {
public:
plugin::Configuration Configure()
{
AddComponent(new ::input::Component("Config", ::input::reader::Config::Instantiate));
plugin::Configuration config;
config.name = "Bro::ConfigReader";
config.description = "Configuration file input reader";
return config;
}
} plugin;
}
}

View file

@ -0,0 +1,6 @@
module InputConfig;
const set_separator: string;
const empty_field: string;
const fail_on_file_problem: bool;

View file

@ -128,7 +128,7 @@ bool SQLite::DoInit(const ReaderInfo& info, int arg_num_fields, const threading:
Value* SQLite::EntryToVal(sqlite3_stmt *st, const threading::Field *field, int pos, int subpos)
{
if ( sqlite3_column_type(st, pos ) == SQLITE_NULL )
return new Value(field->type, false);
return new Value(field->type, field->subtype, false);
Value* val = new Value(field->type, true);

155
src/option.bif Normal file
View file

@ -0,0 +1,155 @@
##! The option built-in functions allow the scripting layer to
##! change the value of option-values and to be notified when
##! option values change.
module Option;
%%{
#include "NetVar.h"
%%}
## Sets an option to a new value. This change will also cause the option change handlers
## to be called.
##
## ID: The ID of the option to update.
##
## val: The new value of the option.
##
## location: optional parameter detailing where this change originated from.
##
## Returns: true on success, false when an error occured.
##
## .. bro:see:: Option::set_change_handler
function Option::set%(ID: string, val: any, location: string &default=""%): bool
%{
auto i = global_scope()->Lookup(ID->CheckString());
if ( ! i )
{
builtin_error(fmt("Could not find ID named '%s'", ID->CheckString()));
return new Val(0, TYPE_BOOL);
}
if ( ! i->HasVal() )
{
// should be impossible because initialization is enforced
builtin_error(fmt("ID '%s' has no value", ID->CheckString()));
return new Val(0, TYPE_BOOL);
}
if ( ! i->IsOption() )
{
builtin_error(fmt("ID '%s' is not an option", ID->CheckString()));
return new Val(0, TYPE_BOOL);
}
if ( ! same_type(i->Type(), val->Type()) )
{
builtin_error(fmt("Incompatible type for set of ID '%s': got '%s', need '%s'",
ID->CheckString(), type_name(val->Type()->Tag()), type_name(i->Type()->Tag())));
}
val->Ref();
if ( i->HasOptionHandlers() )
{
for ( auto handler_function : i->GetOptionHandlers() )
{
val_list vl(2);
vl.append(ID->Ref());
vl.append(val);
if ( handler_function->FType()->AsFuncType()->ArgTypes()->Types()->length() == 3 )
vl.append(location->Ref());
val = handler_function->Call(&vl); // consumed by next call.
if ( ! val )
{
// Someone messed up, don't change value and just return
return new Val(0, TYPE_BOOL);
}
}
}
// clone to prevent changes
i->SetVal(val->Clone());
Unref(val); // Either ref'd once or function call result.
return new Val(1, TYPE_BOOL);
%}
## Set the change handler for the option *ID*. The change handler will be called anytime
## :bro:id:`Option::set` is called fot *ID*.
##
## ID: The ID of the option for which change notifications are desired.
##
## on_change: The function that will be called when a change occurs. The function can choose to
## receive two or three parameters: the first parameter is a string containing *ID*,
## the second parameter is the new option value. If the third, optional, parameter is the
## location string as passed to Option::set. Note that the global value is not yet changed
## when the function is called. The passed function has to return the new value that
## it wants the option to be set to. This enables it to reject changes, or change values
## that are being set. When several change handlers are set for an option they are chained;
## the second change handler will see the return value of the first change handler as the
## "new value".
##
## priority: The priority of the function that was added; functions with higher priority are
## called first, functions with the same priority are called in the order in which
## they were added.
##
## Returns: true when the change handler was set, false when an error occurred.
##
## .. bro:see:: Option::set
function Option::set_change_handler%(ID: string, on_change: any, priority: int &default=0%): bool
%{
auto i = global_scope()->Lookup(ID->CheckString());
if ( ! i )
{
builtin_error(fmt("Could not find ID named '%s'", ID->CheckString()));
return new Val(0, TYPE_BOOL);
}
if ( ! i->IsOption() )
{
builtin_error(fmt("ID '%s' is not an option", ID->CheckString()));
return new Val(0, TYPE_BOOL);
}
if ( on_change->Type()->Tag() != TYPE_FUNC )
{
builtin_error(fmt("Option::on_change needs function argument; got '%s' for ID '%s'",
type_name(on_change->Type()->Tag()), ID->CheckString()));
return new Val(0, TYPE_BOOL);
}
if ( on_change->Type()->AsFuncType()->Flavor() != FUNC_FLAVOR_FUNCTION )
{
builtin_error("Option::on_change needs function argument; not hook or event");
return new Val(0, TYPE_BOOL);
}
const type_list* args = on_change->Type()->AsFuncType()->ArgTypes()->Types();
if ( args->length() < 2 || args->length() > 3 )
{
builtin_error(fmt("Wrong number of arguments for passed function in Option::on_change for ID '%s'; expected 2 or 3, got %d",
ID->CheckString(), args->length()));
return new Val(0, TYPE_BOOL);
}
if ( (*args)[0]->Tag() != TYPE_STRING )
{
builtin_error(fmt("First argument of passed function has to be string in Option::on_change for ID '%s'; got '%s'",
ID->CheckString(), type_name((*args)[0]->Tag())));
return new Val(0, TYPE_BOOL);
}
if ( ! same_type((*args)[1], i->Type()) )
{
builtin_error(fmt("Second argument of passed function has to be %s in Option::on_change for ID '%s'; got '%s'",
type_name(i->Type()->Tag()), ID->CheckString(), type_name((*args)[1]->Tag())));
return new Val(0, TYPE_BOOL);
}
if ( args->length() == 3 && (*args)[2]->Tag() != TYPE_STRING )
{
builtin_error(fmt("Third argument of passed function has to be string in Option::on_change for ID '%s'; got '%s'",
ID->CheckString(), type_name((*args)[2]->Tag())));
return new Val(0, TYPE_BOOL);
}
if ( ! same_type(on_change->Type()->AsFuncType()->YieldType(), i->Type()) )
{
builtin_error(fmt("Passed function needs to return type '%s' for ID '%s'; got '%s'",
type_name(i->Type()->Tag()), ID->CheckString(), type_name(on_change->Type()->AsFuncType()->YieldType()->Tag())));
return new Val(0, TYPE_BOOL);
}
i->AddOptionHandler(on_change->Ref()->AsFunc(), -priority);
return new Val(1, TYPE_BOOL);
%}

View file

@ -6,7 +6,7 @@
%token TOK_ADD TOK_ADD_TO TOK_ADDR TOK_ANY
%token TOK_ATENDIF TOK_ATELSE TOK_ATIF TOK_ATIFDEF TOK_ATIFNDEF
%token TOK_BOOL TOK_BREAK TOK_CASE TOK_CONST
%token TOK_BOOL TOK_BREAK TOK_CASE TOK_OPTION TOK_CONST
%token TOK_CONSTANT TOK_COPY TOK_COUNT TOK_COUNTER TOK_DEFAULT TOK_DELETE
%token TOK_DOUBLE TOK_ELSE TOK_ENUM TOK_EVENT TOK_EXPORT TOK_FALLTHROUGH
%token TOK_FILE TOK_FOR TOK_FUNCTION TOK_GLOBAL TOK_HOOK TOK_ID TOK_IF TOK_INT
@ -1059,6 +1059,12 @@ decl:
broxygen_mgr->Identifier($2);
}
| TOK_OPTION def_global_id opt_type init_class opt_init opt_attr ';'
{
add_global($2, $3, $4, $5, $6, VAR_OPTION);
broxygen_mgr->Identifier($2);
}
| TOK_CONST def_global_id opt_type init_class opt_init opt_attr ';'
{
add_global($2, $3, $4, $5, $6, VAR_CONST);

View file

@ -215,6 +215,7 @@ any return TOK_ANY;
bool return TOK_BOOL;
break return TOK_BREAK;
case return TOK_CASE;
option return TOK_OPTION;
const return TOK_CONST;
copy return TOK_COPY;
count return TOK_COUNT;

View file

@ -161,12 +161,13 @@ bool Value::IsCompatibleType(BroType* t, bool atomic_only)
bool Value::Read(SerializationFormat* fmt)
{
int ty;
int ty, sty;
if ( ! (fmt->Read(&ty, "type") && fmt->Read(&present, "present")) )
if ( ! (fmt->Read(&ty, "type") && fmt->Read(&sty, "subtype") && fmt->Read(&present, "present")) )
return false;
type = (TypeTag)(ty);
subtype = (TypeTag)(sty);
if ( ! present )
return true;
@ -311,6 +312,7 @@ bool Value::Read(SerializationFormat* fmt)
bool Value::Write(SerializationFormat* fmt) const
{
if ( ! (fmt->Write((int)type, "type") &&
fmt->Write((int)subtype, "subtype") &&
fmt->Write(present, "present")) )
return false;

View file

@ -26,7 +26,7 @@ struct Field {
//! port, one for the type), and this specifies the secondary name.
const char* secondary_name;
TypeTag type; //! Type of the field.
TypeTag subtype; //! Inner type for sets.
TypeTag subtype; //! Inner type for sets and vectors.
bool optional; //! True if field is optional.
/**
@ -92,6 +92,7 @@ private:
*/
struct Value {
TypeTag type; //! The type of the value.
TypeTag subtype; //! Inner type for sets and vectors.
bool present; //! False for optional record fields that are not set.
struct set_t { bro_int_t size; Value** vals; };
@ -146,7 +147,20 @@ struct Value {
* that is not set.
*/
Value(TypeTag arg_type = TYPE_ERROR, bool arg_present = true)
: type(arg_type), present(arg_present) {}
: type(arg_type), subtype(TYPE_VOID), present(arg_present) {}
/**
* Constructor.
*
* arg_type: The type of the value.
*
* arg_type: The subtype of the value for sets and vectors.
*
* arg_present: False if the value represents an optional record field
* that is not set.
*/
Value(TypeTag arg_type, TypeTag arg_subtype, bool arg_present = true)
: type(arg_type), subtype(arg_subtype), present(arg_present) {}
/**
* Destructor.
@ -185,4 +199,4 @@ private:
}
#endif /* THREADING_SERIALIZATIONTZPES_H */
#endif /* THREADING_SERIALIZATIONTYPES_H */

View file

@ -207,13 +207,14 @@ bool Ascii::Describe(ODesc* desc, threading::Value* val, const string& name) con
threading::Value* Ascii::ParseValue(const string& s, const string& name, TypeTag type, TypeTag subtype) const
{
if ( s.compare(separators.unset_field) == 0 ) // field is not set...
if ( ! separators.unset_field.empty() && s.compare(separators.unset_field) == 0 ) // field is not set...
return new threading::Value(type, false);
threading::Value* val = new threading::Value(type, true);
threading::Value* val = new threading::Value(type, subtype, true);
const char* start = s.c_str();
char* end = 0;
errno = 0;
size_t pos;
switch ( type ) {
case TYPE_ENUM:
@ -260,11 +261,21 @@ threading::Value* Ascii::ParseValue(const string& s, const string& name, TypeTag
break;
case TYPE_PORT:
val->val.port_val.proto = TRANSPORT_UNKNOWN;
pos = s.find('/');
if ( pos != std::string::npos && s.length() > pos + 1 )
{
auto proto = s.substr(pos+1);
if ( strtolower(proto) == "tcp" )
val->val.port_val.proto = TRANSPORT_TCP;
else if ( strtolower(proto) == "udp" )
val->val.port_val.proto = TRANSPORT_UDP;
else if ( strtolower(proto) == "icmp" )
val->val.port_val.proto = TRANSPORT_ICMP;
}
val->val.port_val.port = strtoull(start, &end, 10);
if ( CheckNumberError(start, end) )
goto parse_error;
val->val.port_val.proto = TRANSPORT_UNKNOWN;
break;
case TYPE_SUBNET:

View file

@ -1,2 +1,3 @@
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: InputRaw::process_finished

View file

@ -0,0 +1 @@
error in /Users/johanna/corelight/bro/testing/btest/.tmp/core.option-errors-2/option-errors.bro, line 2: option variable must be initialized (testbool)

View file

@ -0,0 +1 @@
error in /Users/johanna/corelight/bro/testing/btest/.tmp/core.option-errors-3/option-errors.bro, line 3: option is not a modifiable lvalue (testopt)

View file

@ -0,0 +1 @@
error in /Users/johanna/corelight/bro/testing/btest/.tmp/core.option-errors-4/option-errors.bro, line 2 and /Users/johanna/corelight/bro/testing/btest/.tmp/core.option-errors-4/option-errors.bro, line 3: already defined (testopt)

View file

@ -0,0 +1 @@
error in /Users/johanna/corelight/bro/testing/btest/.tmp/core.option-errors/option-errors.bro, line 4: no type given (testbool)

View file

@ -0,0 +1,6 @@
Old value, T
Higher prio - Value of testbool changed from T to F at location ''
Value of testbool changed from T to T
Higher prio - Value of testbool changed from T to F at location 'here'
Value of testbool changed from T to T
New value, T

View file

@ -0,0 +1 @@
6

View file

@ -0,0 +1 @@
error in /Users/johanna/corelight/bro/testing/btest/.tmp/core.option-runtime-errors-10/option-runtime-errors.bro, line 7: ID 'A' is not an option (Option::set_change_handler(A, option_changed, (coerce 0 to int)))

View file

@ -0,0 +1 @@
error in /Users/johanna/corelight/bro/testing/btest/.tmp/core.option-runtime-errors-11/option-runtime-errors.bro, line 4: Option::on_change needs function argument; got 'count' for ID 'A' (Option::set_change_handler(A, A, (coerce 0 to int)))

View file

@ -0,0 +1 @@
error in /Users/johanna/corelight/bro/testing/btest/.tmp/core.option-runtime-errors-12/option-runtime-errors.bro, line 7: Third argument of passed function has to be string in Option::on_change for ID 'A'; got 'count' (Option::set_change_handler(A, option_changed, (coerce 0 to int)))

View file

@ -0,0 +1 @@
error in /Users/johanna/corelight/bro/testing/btest/.tmp/core.option-runtime-errors-13/option-runtime-errors.bro, line 7: Wrong number of arguments for passed function in Option::on_change for ID 'A'; expected 2 or 3, got 4 (Option::set_change_handler(A, option_changed, (coerce 0 to int)))

View file

@ -0,0 +1 @@
error in /Users/johanna/corelight/bro/testing/btest/.tmp/core.option-runtime-errors-2/option-runtime-errors.bro, line 3: Incompatible type for set of ID 'A': got 'string', need 'count' (Option::set(A, hi, ))

View file

@ -0,0 +1 @@
error in /Users/johanna/corelight/bro/testing/btest/.tmp/core.option-runtime-errors-3/option-runtime-errors.bro, line 3: ID 'A' is not an option (Option::set(A, 6, ))

View file

@ -0,0 +1 @@
error in /Users/johanna/corelight/bro/testing/btest/.tmp/core.option-runtime-errors-4/option-runtime-errors.bro, line 7: Second argument of passed function has to be count in Option::on_change for ID 'A'; got 'bool' (Option::set_change_handler(A, option_changed, (coerce 0 to int)))

View file

@ -0,0 +1 @@
error in /Users/johanna/corelight/bro/testing/btest/.tmp/core.option-runtime-errors-5/option-runtime-errors.bro, line 7: Wrong number of arguments for passed function in Option::on_change for ID 'A'; expected 2 or 3, got 1 (Option::set_change_handler(A, option_changed, (coerce 0 to int)))

View file

@ -0,0 +1 @@
error in /Users/johanna/corelight/bro/testing/btest/.tmp/core.option-runtime-errors-6/option-runtime-errors.bro, line 7: Passed function needs to return type 'count' for ID 'A'; got 'bool' (Option::set_change_handler(A, option_changed, (coerce 0 to int)))

View file

@ -0,0 +1 @@
error in /Users/johanna/corelight/bro/testing/btest/.tmp/core.option-runtime-errors-7/option-runtime-errors.bro, line 7: Option::on_change needs function argument; not hook or event (Option::set_change_handler(A, option_changed, (coerce 0 to int)))

View file

@ -0,0 +1 @@
error in /Users/johanna/corelight/bro/testing/btest/.tmp/core.option-runtime-errors-8/option-runtime-errors.bro, line 7: Option::on_change needs function argument; not hook or event (Option::set_change_handler(A, option_changed, (coerce 0 to int)))

View file

@ -0,0 +1 @@
error in /Users/johanna/corelight/bro/testing/btest/.tmp/core.option-runtime-errors-9/option-runtime-errors.bro, line 5: Could not find ID named 'A' (Option::set_change_handler(A, option_changed, (coerce 0 to int)))

View file

@ -0,0 +1 @@
error in /Users/johanna/corelight/bro/testing/btest/.tmp/core.option-runtime-errors/option-runtime-errors.bro, line 8: Could not find ID named 'B' (Option::set(B, 6, ))

View file

@ -38,6 +38,7 @@ scripts/base/init-bare.bro
scripts/base/frameworks/input/readers/raw.bro
scripts/base/frameworks/input/readers/benchmark.bro
scripts/base/frameworks/input/readers/binary.bro
scripts/base/frameworks/input/readers/config.bro
scripts/base/frameworks/input/readers/sqlite.bro
scripts/base/frameworks/analyzer/__load__.bro
scripts/base/frameworks/analyzer/main.bro
@ -51,6 +52,7 @@ scripts/base/init-bare.bro
scripts/base/frameworks/files/magic/__load__.bro
build/scripts/base/bif/__load__.bro
build/scripts/base/bif/stats.bif.bro
build/scripts/base/bif/option.bif.bro
build/scripts/base/bif/broxygen.bif.bro
build/scripts/base/bif/pcap.bif.bro
build/scripts/base/bif/bloom-filter.bif.bro
@ -161,6 +163,7 @@ scripts/base/init-bare.bro
build/scripts/base/bif/plugins/Bro_AsciiReader.ascii.bif.bro
build/scripts/base/bif/plugins/Bro_BenchmarkReader.benchmark.bif.bro
build/scripts/base/bif/plugins/Bro_BinaryReader.binary.bif.bro
build/scripts/base/bif/plugins/Bro_ConfigReader.config.bif.bro
build/scripts/base/bif/plugins/Bro_RawReader.raw.bif.bro
build/scripts/base/bif/plugins/Bro_SQLiteReader.sqlite.bif.bro
build/scripts/base/bif/plugins/Bro_AsciiWriter.ascii.bif.bro

View file

@ -38,6 +38,7 @@ scripts/base/init-bare.bro
scripts/base/frameworks/input/readers/raw.bro
scripts/base/frameworks/input/readers/benchmark.bro
scripts/base/frameworks/input/readers/binary.bro
scripts/base/frameworks/input/readers/config.bro
scripts/base/frameworks/input/readers/sqlite.bro
scripts/base/frameworks/analyzer/__load__.bro
scripts/base/frameworks/analyzer/main.bro
@ -51,6 +52,7 @@ scripts/base/init-bare.bro
scripts/base/frameworks/files/magic/__load__.bro
build/scripts/base/bif/__load__.bro
build/scripts/base/bif/stats.bif.bro
build/scripts/base/bif/option.bif.bro
build/scripts/base/bif/broxygen.bif.bro
build/scripts/base/bif/pcap.bif.bro
build/scripts/base/bif/bloom-filter.bif.bro
@ -161,6 +163,7 @@ scripts/base/init-bare.bro
build/scripts/base/bif/plugins/Bro_AsciiReader.ascii.bif.bro
build/scripts/base/bif/plugins/Bro_BenchmarkReader.benchmark.bif.bro
build/scripts/base/bif/plugins/Bro_BinaryReader.binary.bif.bro
build/scripts/base/bif/plugins/Bro_ConfigReader.config.bif.bro
build/scripts/base/bif/plugins/Bro_RawReader.raw.bif.bro
build/scripts/base/bif/plugins/Bro_SQLiteReader.sqlite.bif.bro
build/scripts/base/bif/plugins/Bro_AsciiWriter.ascii.bif.bro
@ -238,6 +241,9 @@ scripts/base/init-default.bro
scripts/base/frameworks/intel/main.bro
scripts/base/frameworks/intel/files.bro
scripts/base/frameworks/intel/input.bro
scripts/base/frameworks/config/__load__.bro
scripts/base/frameworks/config/main.bro
scripts/base/frameworks/config/input.bro
scripts/base/frameworks/sumstats/__load__.bro
scripts/base/frameworks/sumstats/main.bro
scripts/base/frameworks/sumstats/plugins/__load__.bro

View file

@ -2,6 +2,7 @@ barnyard2
capture_loss
cluster
communication
config
conn
dce__r_pc
dhcp

View file

@ -32,8 +32,8 @@ And a custom directive does the equivalent references:
Summary
~~~~~~~
Options
#######
Redefinable Options
###################
==================================================================================== =======================================================
:bro:id:`BroxygenExample::an_option`: :bro:type:`set` :bro:attr:`&redef` Add documentation for "an_option" here.
:bro:id:`BroxygenExample::option_with_init`: :bro:type:`interval` :bro:attr:`&redef` Default initialization will be generated automatically.
@ -81,8 +81,8 @@ Functions
Detailed Interface
~~~~~~~~~~~~~~~~~~
Options
#######
Redefinable Options
###################
.. bro:id:: BroxygenExample::an_option
:Type: :bro:type:`set` [:bro:type:`addr`, :bro:type:`addr`, :bro:type:`string`]

View file

@ -172,6 +172,7 @@
0.000000 MetaHookPost CallFunction(Files::register_protocol, <frame>, (Analyzer::ANALYZER_SSL, [get_file_handle=SSL::get_file_handle{ return ()}, describe=SSL::describe_file{ <init> SSL::cid{ if (SSL::f$source != SSL || !SSL::f?$info || !SSL::f$info?$x509 || !SSL::f$info$x509?$certificate) return ()for ([SSL::cid] in SSL::f$conns) { if (SSL::f$conns[SSL::cid]?$ssl) { SSL::c = SSL::f$conns[SSL::cid]return (cat(SSL::c$id$resp_h, :, SSL::c$id$resp_p))}}return (cat(Serial: , SSL::f$info$x509$certificate$serial, Subject: , SSL::f$info$x509$certificate$subject, Issuer: , SSL::f$info$x509$certificate$issuer))}}])) -> <no result>
0.000000 MetaHookPost CallFunction(Log::__add_filter, <frame>, (Cluster::LOG, [name=default, writer=Log::WRITER_ASCII, pred=<uninitialized>, path=cluster, path_func=<uninitialized>, include=<uninitialized>, exclude=<uninitialized>, log_local=T, log_remote=T, field_name_map={}, scope_sep=., ext_prefix=_, ext_func=anonymous-function, interv=0 secs, postprocessor=<uninitialized>, config={}])) -> <no result>
0.000000 MetaHookPost CallFunction(Log::__add_filter, <frame>, (Communication::LOG, [name=default, writer=Log::WRITER_ASCII, pred=<uninitialized>, path=communication, path_func=<uninitialized>, include=<uninitialized>, exclude=<uninitialized>, log_local=T, log_remote=T, field_name_map={}, scope_sep=., ext_prefix=_, ext_func=anonymous-function, interv=0 secs, postprocessor=<uninitialized>, config={}])) -> <no result>
0.000000 MetaHookPost CallFunction(Log::__add_filter, <frame>, (Config::LOG, [name=default, writer=Log::WRITER_ASCII, pred=<uninitialized>, path=config, path_func=<uninitialized>, include=<uninitialized>, exclude=<uninitialized>, log_local=T, log_remote=T, field_name_map={}, scope_sep=., ext_prefix=_, ext_func=anonymous-function, interv=0 secs, postprocessor=<uninitialized>, config={}])) -> <no result>
0.000000 MetaHookPost CallFunction(Log::__add_filter, <frame>, (Conn::LOG, [name=default, writer=Log::WRITER_ASCII, pred=<uninitialized>, path=conn, path_func=<uninitialized>, include=<uninitialized>, exclude=<uninitialized>, log_local=T, log_remote=T, field_name_map={}, scope_sep=., ext_prefix=_, ext_func=anonymous-function, interv=0 secs, postprocessor=<uninitialized>, config={}])) -> <no result>
0.000000 MetaHookPost CallFunction(Log::__add_filter, <frame>, (DCE_RPC::LOG, [name=default, writer=Log::WRITER_ASCII, pred=<uninitialized>, path=dce_rpc, path_func=<uninitialized>, include=<uninitialized>, exclude=<uninitialized>, log_local=T, log_remote=T, field_name_map={}, scope_sep=., ext_prefix=_, ext_func=anonymous-function, interv=0 secs, postprocessor=<uninitialized>, config={}])) -> <no result>
0.000000 MetaHookPost CallFunction(Log::__add_filter, <frame>, (DHCP::LOG, [name=default, writer=Log::WRITER_ASCII, pred=<uninitialized>, path=dhcp, path_func=<uninitialized>, include=<uninitialized>, exclude=<uninitialized>, log_local=T, log_remote=T, field_name_map={}, scope_sep=., ext_prefix=_, ext_func=anonymous-function, interv=0 secs, postprocessor=<uninitialized>, config={}])) -> <no result>
@ -215,6 +216,7 @@
0.000000 MetaHookPost CallFunction(Log::__add_filter, <frame>, (mysql::LOG, [name=default, writer=Log::WRITER_ASCII, pred=<uninitialized>, path=mysql, path_func=<uninitialized>, include=<uninitialized>, exclude=<uninitialized>, log_local=T, log_remote=T, field_name_map={}, scope_sep=., ext_prefix=_, ext_func=anonymous-function, interv=0 secs, postprocessor=<uninitialized>, config={}])) -> <no result>
0.000000 MetaHookPost CallFunction(Log::__create_stream, <frame>, (Cluster::LOG, [columns=<no value description>, ev=<uninitialized>, path=cluster])) -> <no result>
0.000000 MetaHookPost CallFunction(Log::__create_stream, <frame>, (Communication::LOG, [columns=<no value description>, ev=<uninitialized>, path=communication])) -> <no result>
0.000000 MetaHookPost CallFunction(Log::__create_stream, <frame>, (Config::LOG, [columns=<no value description>, ev=Config::log_config, path=config])) -> <no result>
0.000000 MetaHookPost CallFunction(Log::__create_stream, <frame>, (Conn::LOG, [columns=<no value description>, ev=Conn::log_conn, path=conn])) -> <no result>
0.000000 MetaHookPost CallFunction(Log::__create_stream, <frame>, (DCE_RPC::LOG, [columns=<no value description>, ev=<uninitialized>, path=dce_rpc])) -> <no result>
0.000000 MetaHookPost CallFunction(Log::__create_stream, <frame>, (DHCP::LOG, [columns=<no value description>, ev=DHCP::log_dhcp, path=dhcp])) -> <no result>
@ -256,9 +258,10 @@
0.000000 MetaHookPost CallFunction(Log::__create_stream, <frame>, (Weird::LOG, [columns=<no value description>, ev=Weird::log_weird, path=weird])) -> <no result>
0.000000 MetaHookPost CallFunction(Log::__create_stream, <frame>, (X509::LOG, [columns=<no value description>, ev=X509::log_x509, path=x509])) -> <no result>
0.000000 MetaHookPost CallFunction(Log::__create_stream, <frame>, (mysql::LOG, [columns=<no value description>, ev=MySQL::log_mysql, path=mysql])) -> <no result>
0.000000 MetaHookPost CallFunction(Log::__write, <frame>, (PacketFilter::LOG, [ts=1510863910.246703, node=bro, filter=ip or not ip, init=T, success=T])) -> <no result>
0.000000 MetaHookPost CallFunction(Log::__write, <frame>, (PacketFilter::LOG, [ts=1511991433.194848, node=bro, filter=ip or not ip, init=T, success=T])) -> <no result>
0.000000 MetaHookPost CallFunction(Log::add_default_filter, <frame>, (Cluster::LOG)) -> <no result>
0.000000 MetaHookPost CallFunction(Log::add_default_filter, <frame>, (Communication::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>, (Conn::LOG)) -> <no result>
0.000000 MetaHookPost CallFunction(Log::add_default_filter, <frame>, (DCE_RPC::LOG)) -> <no result>
0.000000 MetaHookPost CallFunction(Log::add_default_filter, <frame>, (DHCP::LOG)) -> <no result>
@ -302,6 +305,7 @@
0.000000 MetaHookPost CallFunction(Log::add_default_filter, <frame>, (mysql::LOG)) -> <no result>
0.000000 MetaHookPost CallFunction(Log::add_filter, <frame>, (Cluster::LOG, [name=default, writer=Log::WRITER_ASCII, pred=<uninitialized>, path=<uninitialized>, path_func=<uninitialized>, include=<uninitialized>, exclude=<uninitialized>, log_local=T, log_remote=T, field_name_map={}, scope_sep=., ext_prefix=_, ext_func=anonymous-function, interv=0 secs, postprocessor=<uninitialized>, config={}])) -> <no result>
0.000000 MetaHookPost CallFunction(Log::add_filter, <frame>, (Communication::LOG, [name=default, writer=Log::WRITER_ASCII, pred=<uninitialized>, path=<uninitialized>, path_func=<uninitialized>, include=<uninitialized>, exclude=<uninitialized>, log_local=T, log_remote=T, field_name_map={}, scope_sep=., ext_prefix=_, ext_func=anonymous-function, interv=0 secs, postprocessor=<uninitialized>, config={}])) -> <no result>
0.000000 MetaHookPost CallFunction(Log::add_filter, <frame>, (Config::LOG, [name=default, writer=Log::WRITER_ASCII, pred=<uninitialized>, path=<uninitialized>, path_func=<uninitialized>, include=<uninitialized>, exclude=<uninitialized>, log_local=T, log_remote=T, field_name_map={}, scope_sep=., ext_prefix=_, ext_func=anonymous-function, interv=0 secs, postprocessor=<uninitialized>, config={}])) -> <no result>
0.000000 MetaHookPost CallFunction(Log::add_filter, <frame>, (Conn::LOG, [name=default, writer=Log::WRITER_ASCII, pred=<uninitialized>, path=<uninitialized>, path_func=<uninitialized>, include=<uninitialized>, exclude=<uninitialized>, log_local=T, log_remote=T, field_name_map={}, scope_sep=., ext_prefix=_, ext_func=anonymous-function, interv=0 secs, postprocessor=<uninitialized>, config={}])) -> <no result>
0.000000 MetaHookPost CallFunction(Log::add_filter, <frame>, (DCE_RPC::LOG, [name=default, writer=Log::WRITER_ASCII, pred=<uninitialized>, path=<uninitialized>, path_func=<uninitialized>, include=<uninitialized>, exclude=<uninitialized>, log_local=T, log_remote=T, field_name_map={}, scope_sep=., ext_prefix=_, ext_func=anonymous-function, interv=0 secs, postprocessor=<uninitialized>, config={}])) -> <no result>
0.000000 MetaHookPost CallFunction(Log::add_filter, <frame>, (DHCP::LOG, [name=default, writer=Log::WRITER_ASCII, pred=<uninitialized>, path=<uninitialized>, path_func=<uninitialized>, include=<uninitialized>, exclude=<uninitialized>, log_local=T, log_remote=T, field_name_map={}, scope_sep=., ext_prefix=_, ext_func=anonymous-function, interv=0 secs, postprocessor=<uninitialized>, config={}])) -> <no result>
@ -345,6 +349,7 @@
0.000000 MetaHookPost CallFunction(Log::add_filter, <frame>, (mysql::LOG, [name=default, writer=Log::WRITER_ASCII, pred=<uninitialized>, path=<uninitialized>, path_func=<uninitialized>, include=<uninitialized>, exclude=<uninitialized>, log_local=T, log_remote=T, field_name_map={}, scope_sep=., ext_prefix=_, ext_func=anonymous-function, interv=0 secs, postprocessor=<uninitialized>, config={}])) -> <no result>
0.000000 MetaHookPost CallFunction(Log::create_stream, <frame>, (Cluster::LOG, [columns=<no value description>, ev=<uninitialized>, path=cluster])) -> <no result>
0.000000 MetaHookPost CallFunction(Log::create_stream, <frame>, (Communication::LOG, [columns=<no value description>, ev=<uninitialized>, path=communication])) -> <no result>
0.000000 MetaHookPost CallFunction(Log::create_stream, <frame>, (Config::LOG, [columns=<no value description>, ev=Config::log_config, path=config])) -> <no result>
0.000000 MetaHookPost CallFunction(Log::create_stream, <frame>, (Conn::LOG, [columns=<no value description>, ev=Conn::log_conn, path=conn])) -> <no result>
0.000000 MetaHookPost CallFunction(Log::create_stream, <frame>, (DCE_RPC::LOG, [columns=<no value description>, ev=<uninitialized>, path=dce_rpc])) -> <no result>
0.000000 MetaHookPost CallFunction(Log::create_stream, <frame>, (DHCP::LOG, [columns=<no value description>, ev=DHCP::log_dhcp, path=dhcp])) -> <no result>
@ -386,7 +391,7 @@
0.000000 MetaHookPost CallFunction(Log::create_stream, <frame>, (Weird::LOG, [columns=<no value description>, ev=Weird::log_weird, path=weird])) -> <no result>
0.000000 MetaHookPost CallFunction(Log::create_stream, <frame>, (X509::LOG, [columns=<no value description>, ev=X509::log_x509, path=x509])) -> <no result>
0.000000 MetaHookPost CallFunction(Log::create_stream, <frame>, (mysql::LOG, [columns=<no value description>, ev=MySQL::log_mysql, path=mysql])) -> <no result>
0.000000 MetaHookPost CallFunction(Log::write, <frame>, (PacketFilter::LOG, [ts=1510863910.246703, node=bro, filter=ip or not ip, init=T, success=T])) -> <no result>
0.000000 MetaHookPost CallFunction(Log::write, <frame>, (PacketFilter::LOG, [ts=1511991433.194848, node=bro, 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::init, <null>, ()) -> <no result>
0.000000 MetaHookPost CallFunction(Notice::want_pp, <frame>, ()) -> <no result>
@ -415,6 +420,7 @@
0.000000 MetaHookPost CallFunction(current_time, <frame>, ()) -> <no result>
0.000000 MetaHookPost CallFunction(filter_change_tracking, <null>, ()) -> <no result>
0.000000 MetaHookPost CallFunction(getenv, <null>, (CLUSTER_NODE)) -> <no result>
0.000000 MetaHookPost CallFunction(global_ids, <frame>, ()) -> <no result>
0.000000 MetaHookPost CallFunction(network_time, <frame>, ()) -> <no result>
0.000000 MetaHookPost CallFunction(reading_live_traffic, <frame>, ()) -> <no result>
0.000000 MetaHookPost CallFunction(reading_traces, <frame>, ()) -> <no result>
@ -431,6 +437,7 @@
0.000000 MetaHookPost LoadFile(0, .<...>/Bro_BenchmarkReader.benchmark.bif.bro) -> -1
0.000000 MetaHookPost LoadFile(0, .<...>/Bro_BinaryReader.binary.bif.bro) -> -1
0.000000 MetaHookPost LoadFile(0, .<...>/Bro_BitTorrent.events.bif.bro) -> -1
0.000000 MetaHookPost LoadFile(0, .<...>/Bro_ConfigReader.config.bif.bro) -> -1
0.000000 MetaHookPost LoadFile(0, .<...>/Bro_ConnSize.events.bif.bro) -> -1
0.000000 MetaHookPost LoadFile(0, .<...>/Bro_ConnSize.functions.bif.bro) -> -1
0.000000 MetaHookPost LoadFile(0, .<...>/Bro_DCE_RPC.consts.bif.bro) -> -1
@ -550,6 +557,7 @@
0.000000 MetaHookPost LoadFile(0, .<...>/cardinality-counter.bif.bro) -> -1
0.000000 MetaHookPost LoadFile(0, .<...>/catch-and-release.bro) -> -1
0.000000 MetaHookPost LoadFile(0, .<...>/comm.bif.bro) -> -1
0.000000 MetaHookPost LoadFile(0, .<...>/config.bro) -> -1
0.000000 MetaHookPost LoadFile(0, .<...>/const-dos-error.bro) -> -1
0.000000 MetaHookPost LoadFile(0, .<...>/const-nt-status.bro) -> -1
0.000000 MetaHookPost LoadFile(0, .<...>/const.bif.bro) -> -1
@ -588,6 +596,7 @@
0.000000 MetaHookPost LoadFile(0, .<...>/non-cluster.bro) -> -1
0.000000 MetaHookPost LoadFile(0, .<...>/none.bro) -> -1
0.000000 MetaHookPost LoadFile(0, .<...>/openflow.bro) -> -1
0.000000 MetaHookPost LoadFile(0, .<...>/option.bif.bro) -> -1
0.000000 MetaHookPost LoadFile(0, .<...>/packetfilter.bro) -> -1
0.000000 MetaHookPost LoadFile(0, .<...>/page.bro) -> -1
0.000000 MetaHookPost LoadFile(0, .<...>/patterns.bro) -> -1
@ -637,6 +646,7 @@
0.000000 MetaHookPost LoadFile(0, base<...>/cluster) -> -1
0.000000 MetaHookPost LoadFile(0, base<...>/comm.bif.bro) -> -1
0.000000 MetaHookPost LoadFile(0, base<...>/communication) -> -1
0.000000 MetaHookPost LoadFile(0, base<...>/config) -> -1
0.000000 MetaHookPost LoadFile(0, base<...>/conn) -> -1
0.000000 MetaHookPost LoadFile(0, base<...>/conn-ids.bro) -> -1
0.000000 MetaHookPost LoadFile(0, base<...>/const.bif.bro) -> -1
@ -907,6 +917,7 @@
0.000000 MetaHookPre CallFunction(Files::register_protocol, <frame>, (Analyzer::ANALYZER_SSL, [get_file_handle=SSL::get_file_handle{ return ()}, describe=SSL::describe_file{ <init> SSL::cid{ if (SSL::f$source != SSL || !SSL::f?$info || !SSL::f$info?$x509 || !SSL::f$info$x509?$certificate) return ()for ([SSL::cid] in SSL::f$conns) { if (SSL::f$conns[SSL::cid]?$ssl) { SSL::c = SSL::f$conns[SSL::cid]return (cat(SSL::c$id$resp_h, :, SSL::c$id$resp_p))}}return (cat(Serial: , SSL::f$info$x509$certificate$serial, Subject: , SSL::f$info$x509$certificate$subject, Issuer: , SSL::f$info$x509$certificate$issuer))}}]))
0.000000 MetaHookPre CallFunction(Log::__add_filter, <frame>, (Cluster::LOG, [name=default, writer=Log::WRITER_ASCII, pred=<uninitialized>, path=cluster, path_func=<uninitialized>, include=<uninitialized>, exclude=<uninitialized>, log_local=T, log_remote=T, field_name_map={}, scope_sep=., ext_prefix=_, ext_func=anonymous-function, interv=0 secs, postprocessor=<uninitialized>, config={}]))
0.000000 MetaHookPre CallFunction(Log::__add_filter, <frame>, (Communication::LOG, [name=default, writer=Log::WRITER_ASCII, pred=<uninitialized>, path=communication, path_func=<uninitialized>, include=<uninitialized>, exclude=<uninitialized>, log_local=T, log_remote=T, field_name_map={}, scope_sep=., ext_prefix=_, ext_func=anonymous-function, interv=0 secs, postprocessor=<uninitialized>, config={}]))
0.000000 MetaHookPre CallFunction(Log::__add_filter, <frame>, (Config::LOG, [name=default, writer=Log::WRITER_ASCII, pred=<uninitialized>, path=config, path_func=<uninitialized>, include=<uninitialized>, exclude=<uninitialized>, log_local=T, log_remote=T, field_name_map={}, scope_sep=., ext_prefix=_, ext_func=anonymous-function, interv=0 secs, postprocessor=<uninitialized>, config={}]))
0.000000 MetaHookPre CallFunction(Log::__add_filter, <frame>, (Conn::LOG, [name=default, writer=Log::WRITER_ASCII, pred=<uninitialized>, path=conn, path_func=<uninitialized>, include=<uninitialized>, exclude=<uninitialized>, log_local=T, log_remote=T, field_name_map={}, scope_sep=., ext_prefix=_, ext_func=anonymous-function, interv=0 secs, postprocessor=<uninitialized>, config={}]))
0.000000 MetaHookPre CallFunction(Log::__add_filter, <frame>, (DCE_RPC::LOG, [name=default, writer=Log::WRITER_ASCII, pred=<uninitialized>, path=dce_rpc, path_func=<uninitialized>, include=<uninitialized>, exclude=<uninitialized>, log_local=T, log_remote=T, field_name_map={}, scope_sep=., ext_prefix=_, ext_func=anonymous-function, interv=0 secs, postprocessor=<uninitialized>, config={}]))
0.000000 MetaHookPre CallFunction(Log::__add_filter, <frame>, (DHCP::LOG, [name=default, writer=Log::WRITER_ASCII, pred=<uninitialized>, path=dhcp, path_func=<uninitialized>, include=<uninitialized>, exclude=<uninitialized>, log_local=T, log_remote=T, field_name_map={}, scope_sep=., ext_prefix=_, ext_func=anonymous-function, interv=0 secs, postprocessor=<uninitialized>, config={}]))
@ -950,6 +961,7 @@
0.000000 MetaHookPre CallFunction(Log::__add_filter, <frame>, (mysql::LOG, [name=default, writer=Log::WRITER_ASCII, pred=<uninitialized>, path=mysql, path_func=<uninitialized>, include=<uninitialized>, exclude=<uninitialized>, log_local=T, log_remote=T, field_name_map={}, scope_sep=., ext_prefix=_, ext_func=anonymous-function, interv=0 secs, postprocessor=<uninitialized>, config={}]))
0.000000 MetaHookPre CallFunction(Log::__create_stream, <frame>, (Cluster::LOG, [columns=<no value description>, ev=<uninitialized>, path=cluster]))
0.000000 MetaHookPre CallFunction(Log::__create_stream, <frame>, (Communication::LOG, [columns=<no value description>, ev=<uninitialized>, path=communication]))
0.000000 MetaHookPre CallFunction(Log::__create_stream, <frame>, (Config::LOG, [columns=<no value description>, ev=Config::log_config, path=config]))
0.000000 MetaHookPre CallFunction(Log::__create_stream, <frame>, (Conn::LOG, [columns=<no value description>, ev=Conn::log_conn, path=conn]))
0.000000 MetaHookPre CallFunction(Log::__create_stream, <frame>, (DCE_RPC::LOG, [columns=<no value description>, ev=<uninitialized>, path=dce_rpc]))
0.000000 MetaHookPre CallFunction(Log::__create_stream, <frame>, (DHCP::LOG, [columns=<no value description>, ev=DHCP::log_dhcp, path=dhcp]))
@ -991,9 +1003,10 @@
0.000000 MetaHookPre CallFunction(Log::__create_stream, <frame>, (Weird::LOG, [columns=<no value description>, ev=Weird::log_weird, path=weird]))
0.000000 MetaHookPre CallFunction(Log::__create_stream, <frame>, (X509::LOG, [columns=<no value description>, ev=X509::log_x509, path=x509]))
0.000000 MetaHookPre CallFunction(Log::__create_stream, <frame>, (mysql::LOG, [columns=<no value description>, ev=MySQL::log_mysql, path=mysql]))
0.000000 MetaHookPre CallFunction(Log::__write, <frame>, (PacketFilter::LOG, [ts=1510863910.246703, node=bro, filter=ip or not ip, init=T, success=T]))
0.000000 MetaHookPre CallFunction(Log::__write, <frame>, (PacketFilter::LOG, [ts=1511991433.194848, node=bro, filter=ip or not ip, init=T, success=T]))
0.000000 MetaHookPre CallFunction(Log::add_default_filter, <frame>, (Cluster::LOG))
0.000000 MetaHookPre CallFunction(Log::add_default_filter, <frame>, (Communication::LOG))
0.000000 MetaHookPre CallFunction(Log::add_default_filter, <frame>, (Config::LOG))
0.000000 MetaHookPre CallFunction(Log::add_default_filter, <frame>, (Conn::LOG))
0.000000 MetaHookPre CallFunction(Log::add_default_filter, <frame>, (DCE_RPC::LOG))
0.000000 MetaHookPre CallFunction(Log::add_default_filter, <frame>, (DHCP::LOG))
@ -1037,6 +1050,7 @@
0.000000 MetaHookPre CallFunction(Log::add_default_filter, <frame>, (mysql::LOG))
0.000000 MetaHookPre CallFunction(Log::add_filter, <frame>, (Cluster::LOG, [name=default, writer=Log::WRITER_ASCII, pred=<uninitialized>, path=<uninitialized>, path_func=<uninitialized>, include=<uninitialized>, exclude=<uninitialized>, log_local=T, log_remote=T, field_name_map={}, scope_sep=., ext_prefix=_, ext_func=anonymous-function, interv=0 secs, postprocessor=<uninitialized>, config={}]))
0.000000 MetaHookPre CallFunction(Log::add_filter, <frame>, (Communication::LOG, [name=default, writer=Log::WRITER_ASCII, pred=<uninitialized>, path=<uninitialized>, path_func=<uninitialized>, include=<uninitialized>, exclude=<uninitialized>, log_local=T, log_remote=T, field_name_map={}, scope_sep=., ext_prefix=_, ext_func=anonymous-function, interv=0 secs, postprocessor=<uninitialized>, config={}]))
0.000000 MetaHookPre CallFunction(Log::add_filter, <frame>, (Config::LOG, [name=default, writer=Log::WRITER_ASCII, pred=<uninitialized>, path=<uninitialized>, path_func=<uninitialized>, include=<uninitialized>, exclude=<uninitialized>, log_local=T, log_remote=T, field_name_map={}, scope_sep=., ext_prefix=_, ext_func=anonymous-function, interv=0 secs, postprocessor=<uninitialized>, config={}]))
0.000000 MetaHookPre CallFunction(Log::add_filter, <frame>, (Conn::LOG, [name=default, writer=Log::WRITER_ASCII, pred=<uninitialized>, path=<uninitialized>, path_func=<uninitialized>, include=<uninitialized>, exclude=<uninitialized>, log_local=T, log_remote=T, field_name_map={}, scope_sep=., ext_prefix=_, ext_func=anonymous-function, interv=0 secs, postprocessor=<uninitialized>, config={}]))
0.000000 MetaHookPre CallFunction(Log::add_filter, <frame>, (DCE_RPC::LOG, [name=default, writer=Log::WRITER_ASCII, pred=<uninitialized>, path=<uninitialized>, path_func=<uninitialized>, include=<uninitialized>, exclude=<uninitialized>, log_local=T, log_remote=T, field_name_map={}, scope_sep=., ext_prefix=_, ext_func=anonymous-function, interv=0 secs, postprocessor=<uninitialized>, config={}]))
0.000000 MetaHookPre CallFunction(Log::add_filter, <frame>, (DHCP::LOG, [name=default, writer=Log::WRITER_ASCII, pred=<uninitialized>, path=<uninitialized>, path_func=<uninitialized>, include=<uninitialized>, exclude=<uninitialized>, log_local=T, log_remote=T, field_name_map={}, scope_sep=., ext_prefix=_, ext_func=anonymous-function, interv=0 secs, postprocessor=<uninitialized>, config={}]))
@ -1080,6 +1094,7 @@
0.000000 MetaHookPre CallFunction(Log::add_filter, <frame>, (mysql::LOG, [name=default, writer=Log::WRITER_ASCII, pred=<uninitialized>, path=<uninitialized>, path_func=<uninitialized>, include=<uninitialized>, exclude=<uninitialized>, log_local=T, log_remote=T, field_name_map={}, scope_sep=., ext_prefix=_, ext_func=anonymous-function, interv=0 secs, postprocessor=<uninitialized>, config={}]))
0.000000 MetaHookPre CallFunction(Log::create_stream, <frame>, (Cluster::LOG, [columns=<no value description>, ev=<uninitialized>, path=cluster]))
0.000000 MetaHookPre CallFunction(Log::create_stream, <frame>, (Communication::LOG, [columns=<no value description>, ev=<uninitialized>, path=communication]))
0.000000 MetaHookPre CallFunction(Log::create_stream, <frame>, (Config::LOG, [columns=<no value description>, ev=Config::log_config, path=config]))
0.000000 MetaHookPre CallFunction(Log::create_stream, <frame>, (Conn::LOG, [columns=<no value description>, ev=Conn::log_conn, path=conn]))
0.000000 MetaHookPre CallFunction(Log::create_stream, <frame>, (DCE_RPC::LOG, [columns=<no value description>, ev=<uninitialized>, path=dce_rpc]))
0.000000 MetaHookPre CallFunction(Log::create_stream, <frame>, (DHCP::LOG, [columns=<no value description>, ev=DHCP::log_dhcp, path=dhcp]))
@ -1121,7 +1136,7 @@
0.000000 MetaHookPre CallFunction(Log::create_stream, <frame>, (Weird::LOG, [columns=<no value description>, ev=Weird::log_weird, path=weird]))
0.000000 MetaHookPre CallFunction(Log::create_stream, <frame>, (X509::LOG, [columns=<no value description>, ev=X509::log_x509, path=x509]))
0.000000 MetaHookPre CallFunction(Log::create_stream, <frame>, (mysql::LOG, [columns=<no value description>, ev=MySQL::log_mysql, path=mysql]))
0.000000 MetaHookPre CallFunction(Log::write, <frame>, (PacketFilter::LOG, [ts=1510863910.246703, node=bro, filter=ip or not ip, init=T, success=T]))
0.000000 MetaHookPre CallFunction(Log::write, <frame>, (PacketFilter::LOG, [ts=1511991433.194848, node=bro, filter=ip or not ip, init=T, success=T]))
0.000000 MetaHookPre CallFunction(NetControl::check_plugins, <frame>, ())
0.000000 MetaHookPre CallFunction(NetControl::init, <null>, ())
0.000000 MetaHookPre CallFunction(Notice::want_pp, <frame>, ())
@ -1150,6 +1165,7 @@
0.000000 MetaHookPre CallFunction(current_time, <frame>, ())
0.000000 MetaHookPre CallFunction(filter_change_tracking, <null>, ())
0.000000 MetaHookPre CallFunction(getenv, <null>, (CLUSTER_NODE))
0.000000 MetaHookPre CallFunction(global_ids, <frame>, ())
0.000000 MetaHookPre CallFunction(network_time, <frame>, ())
0.000000 MetaHookPre CallFunction(reading_live_traffic, <frame>, ())
0.000000 MetaHookPre CallFunction(reading_traces, <frame>, ())
@ -1166,6 +1182,7 @@
0.000000 MetaHookPre LoadFile(0, .<...>/Bro_BenchmarkReader.benchmark.bif.bro)
0.000000 MetaHookPre LoadFile(0, .<...>/Bro_BinaryReader.binary.bif.bro)
0.000000 MetaHookPre LoadFile(0, .<...>/Bro_BitTorrent.events.bif.bro)
0.000000 MetaHookPre LoadFile(0, .<...>/Bro_ConfigReader.config.bif.bro)
0.000000 MetaHookPre LoadFile(0, .<...>/Bro_ConnSize.events.bif.bro)
0.000000 MetaHookPre LoadFile(0, .<...>/Bro_ConnSize.functions.bif.bro)
0.000000 MetaHookPre LoadFile(0, .<...>/Bro_DCE_RPC.consts.bif.bro)
@ -1285,6 +1302,7 @@
0.000000 MetaHookPre LoadFile(0, .<...>/cardinality-counter.bif.bro)
0.000000 MetaHookPre LoadFile(0, .<...>/catch-and-release.bro)
0.000000 MetaHookPre LoadFile(0, .<...>/comm.bif.bro)
0.000000 MetaHookPre LoadFile(0, .<...>/config.bro)
0.000000 MetaHookPre LoadFile(0, .<...>/const-dos-error.bro)
0.000000 MetaHookPre LoadFile(0, .<...>/const-nt-status.bro)
0.000000 MetaHookPre LoadFile(0, .<...>/const.bif.bro)
@ -1323,6 +1341,7 @@
0.000000 MetaHookPre LoadFile(0, .<...>/non-cluster.bro)
0.000000 MetaHookPre LoadFile(0, .<...>/none.bro)
0.000000 MetaHookPre LoadFile(0, .<...>/openflow.bro)
0.000000 MetaHookPre LoadFile(0, .<...>/option.bif.bro)
0.000000 MetaHookPre LoadFile(0, .<...>/packetfilter.bro)
0.000000 MetaHookPre LoadFile(0, .<...>/page.bro)
0.000000 MetaHookPre LoadFile(0, .<...>/patterns.bro)
@ -1372,6 +1391,7 @@
0.000000 MetaHookPre LoadFile(0, base<...>/cluster)
0.000000 MetaHookPre LoadFile(0, base<...>/comm.bif.bro)
0.000000 MetaHookPre LoadFile(0, base<...>/communication)
0.000000 MetaHookPre LoadFile(0, base<...>/config)
0.000000 MetaHookPre LoadFile(0, base<...>/conn)
0.000000 MetaHookPre LoadFile(0, base<...>/conn-ids.bro)
0.000000 MetaHookPre LoadFile(0, base<...>/const.bif.bro)
@ -1641,6 +1661,7 @@
0.000000 | HookCallFunction Files::register_protocol(Analyzer::ANALYZER_SSL, [get_file_handle=SSL::get_file_handle{ return ()}, describe=SSL::describe_file{ <init> SSL::cid{ if (SSL::f$source != SSL || !SSL::f?$info || !SSL::f$info?$x509 || !SSL::f$info$x509?$certificate) return ()for ([SSL::cid] in SSL::f$conns) { if (SSL::f$conns[SSL::cid]?$ssl) { SSL::c = SSL::f$conns[SSL::cid]return (cat(SSL::c$id$resp_h, :, SSL::c$id$resp_p))}}return (cat(Serial: , SSL::f$info$x509$certificate$serial, Subject: , SSL::f$info$x509$certificate$subject, Issuer: , SSL::f$info$x509$certificate$issuer))}}])
0.000000 | HookCallFunction Log::__add_filter(Cluster::LOG, [name=default, writer=Log::WRITER_ASCII, pred=<uninitialized>, path=cluster, path_func=<uninitialized>, include=<uninitialized>, exclude=<uninitialized>, log_local=T, log_remote=T, field_name_map={}, scope_sep=., ext_prefix=_, ext_func=anonymous-function, interv=0 secs, postprocessor=<uninitialized>, config={}])
0.000000 | HookCallFunction Log::__add_filter(Communication::LOG, [name=default, writer=Log::WRITER_ASCII, pred=<uninitialized>, path=communication, path_func=<uninitialized>, include=<uninitialized>, exclude=<uninitialized>, log_local=T, log_remote=T, field_name_map={}, scope_sep=., ext_prefix=_, ext_func=anonymous-function, interv=0 secs, postprocessor=<uninitialized>, config={}])
0.000000 | HookCallFunction Log::__add_filter(Config::LOG, [name=default, writer=Log::WRITER_ASCII, pred=<uninitialized>, path=config, path_func=<uninitialized>, include=<uninitialized>, exclude=<uninitialized>, log_local=T, log_remote=T, field_name_map={}, scope_sep=., ext_prefix=_, ext_func=anonymous-function, interv=0 secs, postprocessor=<uninitialized>, config={}])
0.000000 | HookCallFunction Log::__add_filter(Conn::LOG, [name=default, writer=Log::WRITER_ASCII, pred=<uninitialized>, path=conn, path_func=<uninitialized>, include=<uninitialized>, exclude=<uninitialized>, log_local=T, log_remote=T, field_name_map={}, scope_sep=., ext_prefix=_, ext_func=anonymous-function, interv=0 secs, postprocessor=<uninitialized>, config={}])
0.000000 | HookCallFunction Log::__add_filter(DCE_RPC::LOG, [name=default, writer=Log::WRITER_ASCII, pred=<uninitialized>, path=dce_rpc, path_func=<uninitialized>, include=<uninitialized>, exclude=<uninitialized>, log_local=T, log_remote=T, field_name_map={}, scope_sep=., ext_prefix=_, ext_func=anonymous-function, interv=0 secs, postprocessor=<uninitialized>, config={}])
0.000000 | HookCallFunction Log::__add_filter(DHCP::LOG, [name=default, writer=Log::WRITER_ASCII, pred=<uninitialized>, path=dhcp, path_func=<uninitialized>, include=<uninitialized>, exclude=<uninitialized>, log_local=T, log_remote=T, field_name_map={}, scope_sep=., ext_prefix=_, ext_func=anonymous-function, interv=0 secs, postprocessor=<uninitialized>, config={}])
@ -1684,6 +1705,7 @@
0.000000 | HookCallFunction Log::__add_filter(mysql::LOG, [name=default, writer=Log::WRITER_ASCII, pred=<uninitialized>, path=mysql, path_func=<uninitialized>, include=<uninitialized>, exclude=<uninitialized>, log_local=T, log_remote=T, field_name_map={}, scope_sep=., ext_prefix=_, ext_func=anonymous-function, interv=0 secs, postprocessor=<uninitialized>, config={}])
0.000000 | HookCallFunction Log::__create_stream(Cluster::LOG, [columns=<no value description>, ev=<uninitialized>, path=cluster])
0.000000 | HookCallFunction Log::__create_stream(Communication::LOG, [columns=<no value description>, ev=<uninitialized>, path=communication])
0.000000 | HookCallFunction Log::__create_stream(Config::LOG, [columns=<no value description>, ev=Config::log_config, path=config])
0.000000 | HookCallFunction Log::__create_stream(Conn::LOG, [columns=<no value description>, ev=Conn::log_conn, path=conn])
0.000000 | HookCallFunction Log::__create_stream(DCE_RPC::LOG, [columns=<no value description>, ev=<uninitialized>, path=dce_rpc])
0.000000 | HookCallFunction Log::__create_stream(DHCP::LOG, [columns=<no value description>, ev=DHCP::log_dhcp, path=dhcp])
@ -1725,9 +1747,10 @@
0.000000 | HookCallFunction Log::__create_stream(Weird::LOG, [columns=<no value description>, ev=Weird::log_weird, path=weird])
0.000000 | HookCallFunction Log::__create_stream(X509::LOG, [columns=<no value description>, ev=X509::log_x509, path=x509])
0.000000 | HookCallFunction Log::__create_stream(mysql::LOG, [columns=<no value description>, ev=MySQL::log_mysql, path=mysql])
0.000000 | HookCallFunction Log::__write(PacketFilter::LOG, [ts=1510863910.246703, node=bro, filter=ip or not ip, init=T, success=T])
0.000000 | HookCallFunction Log::__write(PacketFilter::LOG, [ts=1511991433.194848, node=bro, filter=ip or not ip, init=T, success=T])
0.000000 | HookCallFunction Log::add_default_filter(Cluster::LOG)
0.000000 | HookCallFunction Log::add_default_filter(Communication::LOG)
0.000000 | HookCallFunction Log::add_default_filter(Config::LOG)
0.000000 | HookCallFunction Log::add_default_filter(Conn::LOG)
0.000000 | HookCallFunction Log::add_default_filter(DCE_RPC::LOG)
0.000000 | HookCallFunction Log::add_default_filter(DHCP::LOG)
@ -1771,6 +1794,7 @@
0.000000 | HookCallFunction Log::add_default_filter(mysql::LOG)
0.000000 | HookCallFunction Log::add_filter(Cluster::LOG, [name=default, writer=Log::WRITER_ASCII, pred=<uninitialized>, path=<uninitialized>, path_func=<uninitialized>, include=<uninitialized>, exclude=<uninitialized>, log_local=T, log_remote=T, field_name_map={}, scope_sep=., ext_prefix=_, ext_func=anonymous-function, interv=0 secs, postprocessor=<uninitialized>, config={}])
0.000000 | HookCallFunction Log::add_filter(Communication::LOG, [name=default, writer=Log::WRITER_ASCII, pred=<uninitialized>, path=<uninitialized>, path_func=<uninitialized>, include=<uninitialized>, exclude=<uninitialized>, log_local=T, log_remote=T, field_name_map={}, scope_sep=., ext_prefix=_, ext_func=anonymous-function, interv=0 secs, postprocessor=<uninitialized>, config={}])
0.000000 | HookCallFunction Log::add_filter(Config::LOG, [name=default, writer=Log::WRITER_ASCII, pred=<uninitialized>, path=<uninitialized>, path_func=<uninitialized>, include=<uninitialized>, exclude=<uninitialized>, log_local=T, log_remote=T, field_name_map={}, scope_sep=., ext_prefix=_, ext_func=anonymous-function, interv=0 secs, postprocessor=<uninitialized>, config={}])
0.000000 | HookCallFunction Log::add_filter(Conn::LOG, [name=default, writer=Log::WRITER_ASCII, pred=<uninitialized>, path=<uninitialized>, path_func=<uninitialized>, include=<uninitialized>, exclude=<uninitialized>, log_local=T, log_remote=T, field_name_map={}, scope_sep=., ext_prefix=_, ext_func=anonymous-function, interv=0 secs, postprocessor=<uninitialized>, config={}])
0.000000 | HookCallFunction Log::add_filter(DCE_RPC::LOG, [name=default, writer=Log::WRITER_ASCII, pred=<uninitialized>, path=<uninitialized>, path_func=<uninitialized>, include=<uninitialized>, exclude=<uninitialized>, log_local=T, log_remote=T, field_name_map={}, scope_sep=., ext_prefix=_, ext_func=anonymous-function, interv=0 secs, postprocessor=<uninitialized>, config={}])
0.000000 | HookCallFunction Log::add_filter(DHCP::LOG, [name=default, writer=Log::WRITER_ASCII, pred=<uninitialized>, path=<uninitialized>, path_func=<uninitialized>, include=<uninitialized>, exclude=<uninitialized>, log_local=T, log_remote=T, field_name_map={}, scope_sep=., ext_prefix=_, ext_func=anonymous-function, interv=0 secs, postprocessor=<uninitialized>, config={}])
@ -1814,6 +1838,7 @@
0.000000 | HookCallFunction Log::add_filter(mysql::LOG, [name=default, writer=Log::WRITER_ASCII, pred=<uninitialized>, path=<uninitialized>, path_func=<uninitialized>, include=<uninitialized>, exclude=<uninitialized>, log_local=T, log_remote=T, field_name_map={}, scope_sep=., ext_prefix=_, ext_func=anonymous-function, interv=0 secs, postprocessor=<uninitialized>, config={}])
0.000000 | HookCallFunction Log::create_stream(Cluster::LOG, [columns=<no value description>, ev=<uninitialized>, path=cluster])
0.000000 | HookCallFunction Log::create_stream(Communication::LOG, [columns=<no value description>, ev=<uninitialized>, path=communication])
0.000000 | HookCallFunction Log::create_stream(Config::LOG, [columns=<no value description>, ev=Config::log_config, path=config])
0.000000 | HookCallFunction Log::create_stream(Conn::LOG, [columns=<no value description>, ev=Conn::log_conn, path=conn])
0.000000 | HookCallFunction Log::create_stream(DCE_RPC::LOG, [columns=<no value description>, ev=<uninitialized>, path=dce_rpc])
0.000000 | HookCallFunction Log::create_stream(DHCP::LOG, [columns=<no value description>, ev=DHCP::log_dhcp, path=dhcp])
@ -1855,7 +1880,7 @@
0.000000 | HookCallFunction Log::create_stream(Weird::LOG, [columns=<no value description>, ev=Weird::log_weird, path=weird])
0.000000 | HookCallFunction Log::create_stream(X509::LOG, [columns=<no value description>, ev=X509::log_x509, path=x509])
0.000000 | HookCallFunction Log::create_stream(mysql::LOG, [columns=<no value description>, ev=MySQL::log_mysql, path=mysql])
0.000000 | HookCallFunction Log::write(PacketFilter::LOG, [ts=1510863910.246703, node=bro, filter=ip or not ip, init=T, success=T])
0.000000 | HookCallFunction Log::write(PacketFilter::LOG, [ts=1511991433.194848, node=bro, filter=ip or not ip, init=T, success=T])
0.000000 | HookCallFunction NetControl::check_plugins()
0.000000 | HookCallFunction NetControl::init()
0.000000 | HookCallFunction Notice::want_pp()
@ -1884,6 +1909,7 @@
0.000000 | HookCallFunction current_time()
0.000000 | HookCallFunction filter_change_tracking()
0.000000 | HookCallFunction getenv(CLUSTER_NODE)
0.000000 | HookCallFunction global_ids()
0.000000 | HookCallFunction network_time()
0.000000 | HookCallFunction reading_live_traffic()
0.000000 | HookCallFunction reading_traces()
@ -1900,6 +1926,7 @@
0.000000 | HookLoadFile .<...>/Bro_BenchmarkReader.benchmark.bif.bro
0.000000 | HookLoadFile .<...>/Bro_BinaryReader.binary.bif.bro
0.000000 | HookLoadFile .<...>/Bro_BitTorrent.events.bif.bro
0.000000 | HookLoadFile .<...>/Bro_ConfigReader.config.bif.bro
0.000000 | HookLoadFile .<...>/Bro_ConnSize.events.bif.bro
0.000000 | HookLoadFile .<...>/Bro_ConnSize.functions.bif.bro
0.000000 | HookLoadFile .<...>/Bro_DCE_RPC.consts.bif.bro
@ -2021,6 +2048,7 @@
0.000000 | HookLoadFile .<...>/cardinality-counter.bif.bro
0.000000 | HookLoadFile .<...>/catch-and-release.bro
0.000000 | HookLoadFile .<...>/comm.bif.bro
0.000000 | HookLoadFile .<...>/config.bro
0.000000 | HookLoadFile .<...>/const-dos-error.bro
0.000000 | HookLoadFile .<...>/const-nt-status.bro
0.000000 | HookLoadFile .<...>/const.bif.bro
@ -2065,6 +2093,7 @@
0.000000 | HookLoadFile .<...>/non-cluster.bro
0.000000 | HookLoadFile .<...>/none.bro
0.000000 | HookLoadFile .<...>/openflow.bro
0.000000 | HookLoadFile .<...>/option.bif.bro
0.000000 | HookLoadFile .<...>/packetfilter.bro
0.000000 | HookLoadFile .<...>/page.bro
0.000000 | HookLoadFile .<...>/patterns.bro
@ -2115,6 +2144,7 @@
0.000000 | HookLoadFile base<...>/cluster
0.000000 | HookLoadFile base<...>/comm.bif.bro
0.000000 | HookLoadFile base<...>/communication
0.000000 | HookLoadFile base<...>/config
0.000000 | HookLoadFile base<...>/conn
0.000000 | HookLoadFile base<...>/conn-ids.bro
0.000000 | HookLoadFile base<...>/const.bif.bro
@ -2198,7 +2228,7 @@
0.000000 | HookLoadFile base<...>/x509
0.000000 | HookLoadFile base<...>/xmpp
0.000000 | HookLogInit packet_filter 1/1 {ts (time), node (string), filter (string), init (bool), success (bool)}
0.000000 | HookLogWrite packet_filter [ts=1510863910.246703, node=bro, filter=ip or not ip, init=T, success=T]
0.000000 | HookLogWrite packet_filter [ts=1511991433.194848, node=bro, filter=ip or not ip, init=T, success=T]
0.000000 | HookQueueEvent NetControl::init()
0.000000 | HookQueueEvent bro_init()
0.000000 | HookQueueEvent filter_change_tracking()

View file

@ -0,0 +1,23 @@
#separator \x09
#set_separator ,
#empty_field (empty)
#unset_field -
#path config
#open 2017-10-11-20-23-11
#fields ts id old_value new_value location
#types time string string string string
1507753391.587107 testbool T F ../configfile
1507753391.587107 testcount 0 1 ../configfile
1507753391.587107 testcount 1 2 ../configfile
1507753391.587107 testint 0 -1 ../configfile
1507753391.587107 testenum SSH::LOG Conn::LOG ../configfile
1507753391.587107 testport 42/tcp 45/unknown ../configfile
1507753391.587107 testaddr 127.0.0.1 127.0.0.1 ../configfile
1507753391.587107 testaddr 127.0.0.1 2607:f8b0:4005:801::200e ../configfile
1507753391.587107 testinterval 1.0 sec 60.0 ../configfile
1507753391.587107 testtime 0.0 1507321987.0 ../configfile
1507753391.587107 test_set (empty) b,c,a,d,erdbeerschnitzel ../configfile
1507753391.587107 test_vector (empty) 1,2,3,4,5,6 ../configfile
1507753391.587107 test_set b,c,a,d,erdbeerschnitzel (empty) ../configfile
1507753391.587107 test_set (empty) \x2d ../configfile
#close 2017-10-11-20-23-11

View file

@ -0,0 +1,23 @@
#separator \x09
#set_separator ,
#empty_field (empty)
#unset_field -
#path config
#open 2017-10-11-20-47-09
#fields ts id old_value new_value location
#types time string string string string
1507754829.092788 testbool T F ../configfile
1507754829.092788 testcount 0 1 ../configfile
1507754829.092788 testcount 1 2 ../configfile
1507754829.092788 testint 0 -1 ../configfile
1507754829.092788 testenum SSH::LOG Conn::LOG ../configfile
1507754829.092788 testport 42/tcp 45/unknown ../configfile
1507754829.092788 testaddr 127.0.0.1 127.0.0.1 ../configfile
1507754829.092788 testaddr 127.0.0.1 2607:f8b0:4005:801::200e ../configfile
1507754829.092788 testinterval 1.0 sec 60.0 ../configfile
1507754829.092788 testtime 0.0 1507321987.0 ../configfile
1507754829.092788 test_set (empty) b,c,a,d,erdbeerschnitzel ../configfile
1507754829.092788 test_vector (empty) 1,2,3,4,5,6 ../configfile
1507754829.092788 test_set b,c,a,d,erdbeerschnitzel (empty) ../configfile
1507754829.092788 test_set (empty) \x2d ../configfile
#close 2017-10-11-20-47-09

View file

@ -0,0 +1,19 @@
#separator \x09
#set_separator ,
#empty_field (empty)
#unset_field -
#path config
#open 2017-10-11-21-01-26
#fields ts id old_value new_value location
#types time string string string string
1507755686.516466 testbool T F ../configfile1
1507755686.516466 testcount 0 2 ../configfile1
1507755686.516466 testint 0 -1 ../configfile1
1507755686.516466 testenum SSH::LOG Conn::LOG ../configfile1
1507755686.516466 test_set (empty) b,c,a,d,erdbeerschnitzel ../configfile1
1507755686.516466 test_vector (empty) 1,2,3,4,5,6 ../configfile1
1507755686.516466 testport 42/tcp 45/unknown ../configfile2
1507755686.516466 testaddr 127.0.0.1 127.0.0.1 ../configfile2
1507755686.516466 testinterval 1.0 sec 60.0 ../configfile2
1507755686.516466 testtime 0.0 1507321987.0 ../configfile2
#close 2017-10-11-21-01-26

View file

@ -0,0 +1,26 @@
#separator \x09
#set_separator ,
#empty_field (empty)
#unset_field -
#path config
#open 2017-10-11-21-00-06
#fields ts id old_value new_value location
#types time string string string string
1507755606.563360 testbool T F ../configfile
1507755606.563360 testcount 0 1 ../configfile
1507755606.563360 testcount 1 2 ../configfile
1507755606.563360 testint 0 -1 ../configfile
1507755606.563360 testenum SSH::LOG Conn::LOG ../configfile
1507755606.563360 testport 42/tcp 45/unknown ../configfile
1507755606.563360 testaddr 127.0.0.1 127.0.0.1 ../configfile
1507755606.563360 testaddr 127.0.0.1 2607:f8b0:4005:801::200e ../configfile
1507755606.563360 testinterval 1.0 sec 60.0 ../configfile
1507755606.563360 testtime 0.0 1507321987.0 ../configfile
1507755606.563360 test_set (empty) b,c,a,d,erdbeerschnitzel ../configfile
1507755606.563360 test_vector (empty) 1,2,3,4,5,6 ../configfile
1507755609.793956 testcount 2 1 ../configfile
1507755609.793956 testcount 1 2 ../configfile
1507755609.793956 testaddr 2607:f8b0:4005:801::200e 127.0.0.1 ../configfile
1507755609.793956 testaddr 127.0.0.1 2607:f8b0:4005:801::200e ../configfile
1507755609.793956 test_vector 1,2,3,4,5,6 1,2,3,4,5,9 ../configfile
#close 2017-10-11-21-00-09

View file

@ -1,5 +1,5 @@
{
[-42] = [b=T, e=SSH::LOG, c=21, p=123/unknown, sn=10.0.0.0/24, a=1.2.3.4, d=3.14, t=1315801931.273616, iv=100.0, s=hurz, ns=4242, sc={
[-42] = [b=T, e=SSH::LOG, c=21, p=123/unknown, pp=5/icmp, sn=10.0.0.0/24, a=1.2.3.4, d=3.14, t=1315801931.273616, iv=100.0, s=hurz, ns=4242, sc={
2,
4,
1,

View file

@ -0,0 +1,28 @@
testbool, F
testcount, 1
testcount, 2
testint, -1
testenum, Conn::LOG
testport, 45/unknown
testportandproto, 45/udp
testaddr, 127.0.0.1
testaddr, 2607:f8b0:4005:801::200e
testinterval, 60.0
testtime, 1507321987.0
test_set, {
b,
c,
a,
d,
erdbeerschnitzel
}
test_vector, [1, 2, 3, 4, 5, 6]
test_set, {
(empty)
}
test_set, {
}
test_set, {
-
}

View file

@ -0,0 +1,14 @@
warning: ../configfile/Input::READER_CONFIG: Field: testbool Invalid value for boolean: A
warning: ../configfile/Input::READER_CONFIG: Could not convert line 'testbool A' to Val. Ignoring line.
warning: ../configfile/Input::READER_CONFIG: Could not parse 'testtesttesttesttesttest'; line has invalid format. Ignoring line.
warning: ../configfile/Input::READER_CONFIG: Field: testbool Invalid value for boolean: A B
warning: ../configfile/Input::READER_CONFIG: Could not convert line 'testbool A B' to Val. Ignoring line.
warning: ../configfile/Input::READER_CONFIG: String 'A' contained no parseable number
warning: ../configfile/Input::READER_CONFIG: Could not convert line 'testcount A' to Val. Ignoring line.
warning: Value 'unknown' for stream 'configuration' is not a valid enum.
error: SendEvent for event InputConfig::new_value failed
warning: ../configfile/Input::READER_CONFIG: Option 'testbooool' does not exist. Ignoring line.
warning: ../configfile/Input::READER_CONFIG: Option 'test_any' has type 'any', which is not supported for file input. Ignoring line.
warning: ../configfile/Input::READER_CONFIG: Option 'test_table' has type 'table', which is not supported for file input. Ignoring line.
received termination signal
>>>

View file

@ -0,0 +1,18 @@
# @TEST-EXEC-FAIL: bro %INPUT
# @TEST-EXEC: TEST_DIFF_CANONIFIER=$SCRIPTS/diff-remove-abspath btest-diff .stderr
option testbool;
@TEST-START-NEXT
option testbool : bool;
@TEST-START-NEXT
option testopt = 5;
testopt = 6;
@TEST-START-NEXT
option testopt = 5;
redef testopt = 6;

View file

@ -0,0 +1,28 @@
# @TEST-EXEC: bro %INPUT
# @TEST-EXEC: btest-diff .stdout
export {
## Test some documentation here!
option testbool: bool = T;
}
function option_changed(ID: string, new_value: bool): bool {
print fmt("Value of %s changed from %s to %s", ID, testbool, new_value);
return new_value;
}
function option_changed_two(ID: string, new_value: bool, location: string): bool {
print fmt("Higher prio - Value of %s changed from %s to %s at location '%s'", ID, testbool, new_value, location);
return T;
}
event bro_init()
{
print "Old value", testbool;
Option::set_change_handler("testbool", option_changed);
Option::set_change_handler("testbool", option_changed_two, 99);
Option::set("testbool", F);
Option::set("testbool", F, "here");
print "New value", testbool;
}

View file

@ -0,0 +1,12 @@
# @TEST-EXEC: bro %INPUT
# @TEST-EXEC: btest-diff .stdout
# options are allowed to be redef-able.
option testopt = 5 &redef;
redef testopt = 6;
event bro_init() {
print testopt;
}

View file

@ -0,0 +1,104 @@
# @TEST-EXEC: bro %INPUT
# @TEST-EXEC: TEST_DIFF_CANONIFIER=$SCRIPTS/diff-remove-abspath btest-diff .stderr
# Errors that happen during runtime. At least at the moment we are not checking these early enough
# that Bro will bail out during startup. Perhaps we want to change this later.
option A = 5;
Option::set("B", 6);
@TEST-START-NEXT
option A = 5;
Option::set("A", "hi");
@TEST-START-NEXT
const A = 5;
Option::set("A", 6);
@TEST-START-NEXT:
option A = 5;
function option_changed(ID: string, new_value: bool): bool {
}
Option::set_change_handler("A", option_changed);
@TEST-START-NEXT:
option A = 5;
function option_changed(ID: string): bool {
}
Option::set_change_handler("A", option_changed);
@TEST-START-NEXT:
option A : count = 5;
function option_changed(ID: string, new_value: count): bool {
}
Option::set_change_handler("A", option_changed);
@TEST-START-NEXT:
option A : count = 5;
hook option_changed(ID: string, new_value: count) {
}
Option::set_change_handler("A", option_changed);
@TEST-START-NEXT:
option A : count = 5;
event option_changed(ID: string, new_value: count) {
}
Option::set_change_handler("A", option_changed);
@TEST-START-NEXT:
function option_changed(ID: string, new_value: count) : count {
}
Option::set_change_handler("A", option_changed);
@TEST-START-NEXT:
const A : count = 5;
function option_changed(ID: string, new_value: count) : count {
}
Option::set_change_handler("A", option_changed);
@TEST-START-NEXT:
option A : count = 5;
Option::set_change_handler("A", A);
@TEST-START-NEXT:
option A : count = 5;
function option_changed(ID: string, new_value: count, location: count) : count {
}
Option::set_change_handler("A", option_changed);
@TEST-START-NEXT:
option A : count = 5;
function option_changed(ID: string, new_value: count, location: string, a: count) : count {
}
Option::set_change_handler("A", option_changed);

View file

@ -0,0 +1,52 @@
# @TEST-EXEC: btest-bg-run bro bro -b %INPUT
# @TEST-EXEC: btest-bg-wait 10
# @TEST-EXEC: btest-diff bro/config.log
@load base/frameworks/config
@load base/protocols/conn
redef exit_only_after_terminate = T;
redef Config::config_files += {"../configfile"};
@TEST-START-FILE configfile
testbool F
testcount 1
testcount 2
testcount 2
testint -1
testenum Conn::LOG
testport 45
testaddr 127.0.0.1
testaddr 2607:f8b0:4005:801::200e
testinterval 60
testtime 1507321987
test_set a,b,c,d,erdbeerschnitzel
test_vector 1,2,3,4,5,6
test_set (empty)
test_set -
@TEST-END-FILE
@load base/protocols/ssh
@load base/protocols/conn
export {
option testbool: bool = T;
option testcount: count = 0;
option testint: int = 0;
option testenum = SSH::LOG;
option testport = 42/tcp;
option testaddr = 127.0.0.1;
option testtime = network_time();
option testinterval = 1sec;
option teststring = "a";
option test_set: set[string] = {};
option test_vector: vector of count = {};
}
event Input::end_of_data(name: string, source:string)
{
if ( sub_bytes(name, 1, 7) != "config-" )
return;
terminate();
}

View file

@ -0,0 +1,56 @@
# @TEST-EXEC: btest-bg-run bro bro -b %INPUT
# @TEST-EXEC: btest-bg-wait 10
# @TEST-EXEC: btest-diff bro/config.log
@load base/frameworks/config
@load base/protocols/conn
redef exit_only_after_terminate = T;
@TEST-START-FILE configfile
testbool F
testcount 1
testcount 2
testcount 2
testint -1
testenum Conn::LOG
testport 45
testaddr 127.0.0.1
testaddr 2607:f8b0:4005:801::200e
testinterval 60
testtime 1507321987
test_set a,b,c,d,erdbeerschnitzel
test_vector 1,2,3,4,5,6
test_set (empty)
test_set -
@TEST-END-FILE
@load base/protocols/ssh
@load base/protocols/conn
export {
option testbool: bool = T;
option testcount: count = 0;
option testint: int = 0;
option testenum = SSH::LOG;
option testport = 42/tcp;
option testaddr = 127.0.0.1;
option testtime = network_time();
option testinterval = 1sec;
option teststring = "a";
option test_set: set[string] = {};
option test_vector: vector of count = {};
}
event Input::end_of_data(name: string, source:string)
{
if ( sub_bytes(name, 1, 7) != "config-" )
return;
terminate();
}
event bro_init()
{
Config::read_config("../configfile");
}

View file

@ -0,0 +1,50 @@
# @TEST-EXEC: btest-bg-run bro bro -b %INPUT
# @TEST-EXEC: btest-bg-wait 10
# @TEST-EXEC: btest-diff bro/config.log
@load base/frameworks/config
@load base/protocols/conn
redef exit_only_after_terminate = T;
redef Config::config_files += {"../configfile1", "../configfile2"};
@TEST-START-FILE configfile1
testbool F
testcount 2
testint -1
testenum Conn::LOG
test_set a,b,c,d,erdbeerschnitzel
test_vector 1,2,3,4,5,6
@TEST-END-FILE
@TEST-START-FILE configfile2
testport 45
testaddr 127.0.0.1
testinterval 60
testtime 1507321987
@TEST-END-FILE
@load base/protocols/ssh
@load base/protocols/conn
export {
option testbool: bool = T;
option testcount: count = 0;
option testint: int = 0;
option testenum = SSH::LOG;
option testport = 42/tcp;
option testaddr = 127.0.0.1;
option testtime = network_time();
option testinterval = 1sec;
option teststring = "a";
option test_set: set[string] = {};
option test_vector: vector of count = {};
}
event Input::end_of_data(name: string, source:string)
{
if ( sub_bytes(name, 1, 7) != "config-" )
return;
terminate();
}

View file

@ -0,0 +1,76 @@
# @TEST-EXEC: btest-bg-run bro bro -b %INPUT
# @TEST-EXEC: sleep 2
# @TEST-EXEC: mv configfile2 configfile
# @TEST-EXEC: touch configfile
# @TEST-EXEC: btest-bg-wait 10
# @TEST-EXEC: btest-diff bro/config.log
@load base/frameworks/config
@load base/protocols/conn
@load base/frameworks/communication # let network-time run
redef exit_only_after_terminate = T;
redef Config::config_files += {"../configfile"};
@TEST-START-FILE configfile
testbool F
testcount 1
testcount 2
testcount 2
testint -1
testenum Conn::LOG
testport 45
testaddr 127.0.0.1
testaddr 2607:f8b0:4005:801::200e
testinterval 60
testtime 1507321987
test_set a,b,c,d,erdbeerschnitzel
test_vector 1,2,3,4,5,6
@TEST-END-FILE
@TEST-START-FILE configfile2
testbool F
testcount 1
testcount 2
testcount 2
testint -1
testenum Conn::LOG
testport 45
testaddr 127.0.0.1
testaddr 2607:f8b0:4005:801::200e
testinterval 60
testtime 1507321987
test_set a,b,c,d,erdbeerschnitzel
test_vector 1,2,3,4,5,9
@TEST-END-FILE
@load base/protocols/ssh
@load base/protocols/conn
export {
option testbool: bool = T;
option testcount: count = 0;
option testint: int = 0;
option testenum = SSH::LOG;
option testport = 42/tcp;
option testaddr = 127.0.0.1;
option testtime = network_time();
option testinterval = 1sec;
option teststring = "a";
option test_set: set[string] = {};
option test_vector: vector of count = {};
}
global eolcount = 0;
event Input::end_of_data(name: string, source:string)
{
print "eod";
if ( sub_bytes(name, 1, 7) != "config-" )
return;
eolcount += 1;
if ( eolcount == 2 )
terminate();
}

View file

@ -7,9 +7,9 @@ redef exit_only_after_terminate = T;
@TEST-START-FILE input.log
#separator \x09
#path ssh
#fields b i e c p sn a d t iv s sc ss se vc ve ns
#types bool int enum count port subnet addr double time interval string table table table vector vector string
T -42 SSH::LOG 21 123 10.0.0.0/24 1.2.3.4 3.14 1315801931.273616 100.000000 hurz 2,4,1,3 CC,AA,BB EMPTY 10,20,30 EMPTY 4242
#fields b i e c p pp sn a d t iv s sc ss se vc ve ns
#types bool int enum count port port subnet addr double time interval string table table table vector vector string
T -42 SSH::LOG 21 123 5/icmp 10.0.0.0/24 1.2.3.4 3.14 1315801931.273616 100.000000 hurz 2,4,1,3 CC,AA,BB EMPTY 10,20,30 EMPTY 4242
@TEST-END-FILE
@load base/protocols/ssh
@ -29,6 +29,7 @@ type Val: record {
e: Log::ID;
c: count;
p: port;
pp: port;
sn: subnet;
a: addr;
d: double;

View file

@ -0,0 +1,75 @@
# @TEST-EXEC: btest-bg-run bro bro -b %INPUT
# @TEST-EXEC: btest-bg-wait 10
# @TEST-EXEC: btest-diff out
redef exit_only_after_terminate = T;
redef InputConfig::empty_field = "EMPTY";
redef InputConfig::set_separator = "\t";
@TEST-START-FILE configfile
testbool F
testcount 1
testcount 2
testcount 2
testint -1
testenum Conn::LOG
testport 45
testportandproto 45/udp
testaddr 127.0.0.1
testaddr 2607:f8b0:4005:801::200e
testinterval 60
testtime 1507321987
test_set a b c d erdbeerschnitzel
test_vector 1 2 3 4 5 6
test_set (empty)
test_set EMPTY
test_set -
@TEST-END-FILE
@load base/protocols/ssh
@load base/protocols/conn
global outfile: file;
export {
option testbool: bool = T;
option testcount: count = 0;
option testint: int = 0;
option testenum = SSH::LOG;
option testport = 42/tcp;
option testportandproto = 42/tcp;
option testaddr = 127.0.0.1;
option testtime = network_time();
option testinterval = 1sec;
option teststring = "a";
option test_set: set[string] = {};
option test_vector: vector of count = {};
}
type Idx: record {
option_name: string;
};
type Val: record {
option_val: string;
};
global currconfig: table[string] of string = table();
event InputConfig::new_value(name: string, source: string, id: string, value: any)
{
print outfile, id, value;
}
event Input::end_of_data(name: string, source:string)
{
close(outfile);
terminate();
}
event bro_init()
{
outfile = open("../out");
Input::add_table([$reader=Input::READER_CONFIG, $source="../configfile", $name="configuration", $idx=Idx, $val=Val, $destination=currconfig, $want_record=F]);
}

View file

@ -0,0 +1,66 @@
# @TEST-EXEC: btest-bg-run bro bro -b %INPUT
# @TEST-EXEC: btest-bg-wait 10
# @TEST-EXEC: tail -n +2 .stderr > errout
# @TEST-EXEC: btest-diff errout
redef exit_only_after_terminate = T;
@TEST-START-FILE configfile
testbool A
testtesttesttesttesttest
testbool A B
testcount A
testenum unknown
testbooool T
test_any F
test_table whatever
@TEST-END-FILE
@load base/protocols/ssh
@load base/protocols/conn
global outfile: file;
export {
option testbool: bool = T;
option testcount: count = 0;
option testint: int = 0;
option testenum = SSH::LOG;
option testport = 42/tcp;
option testaddr = 127.0.0.1;
option testtime = network_time();
option testinterval = 1sec;
option teststring = "a";
option test_set: set[string] = {};
option test_vector: vector of count = {};
option test_any: any = 5;
option test_table: table[string] of string = {};
}
type Idx: record {
option_name: string;
};
type Val: record {
option_val: string;
};
global currconfig: table[string] of string = table();
event InputConfig::new_value(name: string, source: string, id: string, value: any)
{
print outfile, id, value;
}
event Input::end_of_data(name: string, source:string)
{
close(outfile);
terminate();
}
event bro_init()
{
outfile = open("../out");
Input::add_table([$reader=Input::READER_CONFIG, $source="../configfile", $name="configuration", $idx=Idx, $val=Val, $destination=currconfig, $want_record=F]);
}