Add reporter hook.

The hook being added is:

bool HookReporter(const std::string& prefix, const EventHandlerPtr event,
                  const Connection* conn, const val_list* addl, bool location,
                  const Location* location1, const Location* location2,
                  bool time, const std::string& buffer) override;

This hook gives access to basically all information that is available in
the function in Reporter.cc that performs the logging. The hook is
called each time when anything passes through the reporter in the cases
in which an event usually would be called. This includes weirds. The
hook can return false to prevent the normal reporter events from being
raised.
This commit is contained in:
Johanna Amann 2017-11-16 12:45:11 -08:00
parent bde4404b5e
commit b852437126
11 changed files with 275 additions and 2 deletions

View file

@ -10,6 +10,8 @@
#include "NetVar.h" #include "NetVar.h"
#include "Net.h" #include "Net.h"
#include "Conn.h" #include "Conn.h"
#include "plugin/Plugin.h"
#include "plugin/Manager.h"
#ifdef SYSLOG_INT #ifdef SYSLOG_INT
extern "C" { extern "C" {
@ -323,7 +325,24 @@ void Reporter::DoLog(const char* prefix, EventHandlerPtr event, FILE* out,
// buffer size above. // buffer size above.
safe_snprintf(buffer + strlen(buffer), size - strlen(buffer), " [%s]", postfix); safe_snprintf(buffer + strlen(buffer), size - strlen(buffer), " [%s]", postfix);
if ( event && via_events && ! in_error_handler ) bool raise_event = true;
if ( via_events && ! in_error_handler )
{
if ( locations.size() )
{
auto locs = locations.back();
raise_event = PLUGIN_HOOK_WITH_RESULT(HOOK_REPORTER,
HookReporter(prefix, event, conn, addl, location,
locs.first, locs.second, time, buffer), true);
}
else
raise_event = PLUGIN_HOOK_WITH_RESULT(HOOK_REPORTER,
HookReporter(prefix, event, conn, addl, location,
nullptr, nullptr, time, buffer), true);
}
if ( raise_event && event && via_events && ! in_error_handler )
{ {
val_list* vl = new val_list; val_list* vl = new val_list;

View file

@ -853,6 +853,52 @@ bool Manager::HookLogWrite(const std::string& writer,
return result; return result;
} }
bool Manager::HookReporter(const std::string& prefix, const EventHandlerPtr event,
const Connection* conn, const val_list* addl, bool location,
const Location* location1, const Location* location2,
bool time, const std::string& message)
{
HookArgumentList args;
if ( HavePluginForHook(META_HOOK_PRE) )
{
args.push_back(HookArgument(prefix));
args.push_back(HookArgument(conn));
args.push_back(HookArgument(addl));
args.push_back(HookArgument(location1));
args.push_back(HookArgument(location2));
args.push_back(HookArgument(location));
args.push_back(HookArgument(time));
args.push_back(HookArgument(message));
MetaHookPre(HOOK_REPORTER, args);
}
hook_list* l = hooks[HOOK_REPORTER];
bool result = true;
if ( l )
{
for ( hook_list::iterator i = l->begin(); i != l->end(); ++i )
{
Plugin* p = (*i).second;
if ( ! p->HookReporter(prefix, event, conn, addl, location, location1, location2, time, message) )
{
result = false;
break;
}
}
}
if ( HavePluginForHook(META_HOOK_POST) )
MetaHookPost(HOOK_REPORTER, args, HookArgument(result));
return result;
}
void Manager::MetaHookPre(HookType hook, const HookArgumentList& args) const void Manager::MetaHookPre(HookType hook, const HookArgumentList& args) const
{ {
hook_list* l = hooks[HOOK_CALL_FUNCTION]; hook_list* l = hooks[HOOK_CALL_FUNCTION];

View file

@ -355,6 +355,39 @@ public:
int num_fields, const threading::Field* const* fields, int num_fields, const threading::Field* const* fields,
threading::Value** vals) const; threading::Value** vals) const;
/**
* Hook into reporting. This method will be called for each reporter call
* made; this includes weirds. The method cannot manipulate the data at
* the current time; however it is possible to prevent script-side events
* from being called by returning false.
*
* @param prefix The prefix passed by the reporter framework
*
* @param event The event to be called
*
* @param conn The associated connection
*
* @param addl Additional Bro values; typically will be passed to the event
* by the reporter framework.
*
* @param location True if event expects location information
*
* @param location1 First location
*
* @param location2 Second location
*
* @param time True if event expects time information
*
* @param message Message supplied by the reporter framework
*
* @return true if event should be called by the reporter framework, false
* if the event call should be skipped
*/
bool HookReporter(const std::string& prefix, const EventHandlerPtr event,
const Connection* conn, const val_list* addl, bool location,
const Location* location1, const Location* location2,
bool time, const std::string& message);
/** /**
* Internal method that registers a freshly instantiated plugin with * Internal method that registers a freshly instantiated plugin with
* the manager. * the manager.

View file

@ -208,6 +208,16 @@ void HookArgument::Describe(ODesc* d) const
d->Add("}"); d->Add("}");
} }
break; break;
case LOCATION:
if ( arg.loc )
{
arg.loc->Describe(d);
}
else
{
d->Add("<no location>");
}
} }
} }
@ -393,6 +403,14 @@ bool Plugin::HookLogWrite(const std::string& writer, const std::string& filter,
return true; return true;
} }
bool Plugin::HookReporter(const std::string& prefix, const EventHandlerPtr event,
const Connection* conn, const val_list* addl, bool location,
const Location* location1, const Location* location2,
bool time, const std::string& message)
{
return true;
}
void Plugin::MetaHookPre(HookType hook, const HookArgumentList& args) void Plugin::MetaHookPre(HookType hook, const HookArgumentList& args)
{ {
} }

View file

@ -48,6 +48,7 @@ enum HookType {
HOOK_SETUP_ANALYZER_TREE, //< Activates Plugin::HookAddToAnalyzerTree HOOK_SETUP_ANALYZER_TREE, //< Activates Plugin::HookAddToAnalyzerTree
HOOK_LOG_INIT, //< Activates Plugin::HookLogInit HOOK_LOG_INIT, //< Activates Plugin::HookLogInit
HOOK_LOG_WRITE, //< Activates Plugin::HookLogWrite HOOK_LOG_WRITE, //< Activates Plugin::HookLogWrite
HOOK_REPORTER, //< Activates Plugin::HookReporter
// Meta hooks. // Meta hooks.
META_HOOK_PRE, //< Activates Plugin::MetaHookPre(). META_HOOK_PRE, //< Activates Plugin::MetaHookPre().
@ -172,7 +173,7 @@ public:
*/ */
enum Type { enum Type {
BOOL, DOUBLE, EVENT, FRAME, FUNC, FUNC_RESULT, INT, STRING, VAL, BOOL, DOUBLE, EVENT, FRAME, FUNC, FUNC_RESULT, INT, STRING, VAL,
VAL_LIST, VOID, VOIDP, WRITER_INFO, CONN, THREAD_FIELDS VAL_LIST, VOID, VOIDP, WRITER_INFO, CONN, THREAD_FIELDS, LOCATION
}; };
/** /**
@ -250,6 +251,11 @@ public:
*/ */
explicit HookArgument(const std::pair<int, const threading::Field* const*> fpair) { type = THREAD_FIELDS; tfields = fpair; } explicit HookArgument(const std::pair<int, const threading::Field* const*> fpair) { type = THREAD_FIELDS; tfields = fpair; }
/**
* Constructor with a location argument.
*/
explicit HookArgument(const Location* location) { type = LOCATION; arg.loc = location; }
/** /**
* Returns the value for a boolen argument. The argument's type must * Returns the value for a boolen argument. The argument's type must
* match accordingly. * match accordingly.
@ -360,6 +366,7 @@ private:
const val_list* vals; const val_list* vals;
const void* voidp; const void* voidp;
const logging::WriterBackend::WriterInfo* winfo; const logging::WriterBackend::WriterInfo* winfo;
const Location* loc;
} arg; } arg;
// Outside union because these have dtors. // Outside union because these have dtors.
@ -769,6 +776,39 @@ protected:
const threading::Field* const* fields, const threading::Field* const* fields,
threading::Value** vals); threading::Value** vals);
/**
* Hook into reporting. This method will be called for each reporter call
* made; this includes weirds. The method cannot manipulate the data at
* the current time; however it is possible to prevent script-side events
* from being called by returning false.
*
* @param prefix The prefix passed by the reporter framework
*
* @param event The event to be called
*
* @param conn The associated connection
*
* @param addl Additional Bro values; typically will be passed to the event
* by the reporter framework.
*
* @param location True if event expects location information
*
* @param location1 First location
*
* @param location2 Second location
*
* @param time True if event expects time information
*
* @param message Message supplied by the reporter framework
*
* @return true if event should be called by the reporter framework, false
* if the event call should be skipped
*/
virtual bool HookReporter(const std::string& prefix, const EventHandlerPtr event,
const Connection* conn, const val_list* addl, bool location,
const Location* location1, const Location* location2,
bool time, const std::string& message);
// Meta hooks. // Meta hooks.
/** /**

View file

@ -0,0 +1,10 @@
| Hook Some Info <...>/reporter-hook.bro, line 16
| Hook error An Error <...>/reporter-hook.bro, line 18
| Hook error An Error that does not show up in the log <...>/reporter-hook.bro, line 19
| Hook expression error field value missing [b$a] <...>/reporter-hook.bro, line 23
| Hook warning A warning <...>/reporter-hook.bro, line 17
<...>/reporter-hook.bro, line 16: Some Info
error in <...>/reporter-hook.bro, line 18: An Error
error in <...>/reporter-hook.bro, line 19: An Error that does not show up in the log
expression error in <...>/reporter-hook.bro, line 23: field value missing [b$a]
warning in <...>/reporter-hook.bro, line 17: A warning

View file

@ -0,0 +1,13 @@
#separator \x09
#set_separator ,
#empty_field (empty)
#unset_field -
#path reporter
#open 2017-07-26-17-58-52
#fields ts level message location
#types time enum string string
0.000000 Reporter::INFO Some Info /Users/johanna/corelight/bro/testing/btest/.tmp/plugins.reporter-hook/reporter-hook.bro, line 16
0.000000 Reporter::WARNING A warning /Users/johanna/corelight/bro/testing/btest/.tmp/plugins.reporter-hook/reporter-hook.bro, line 17
0.000000 Reporter::ERROR An Error /Users/johanna/corelight/bro/testing/btest/.tmp/plugins.reporter-hook/reporter-hook.bro, line 18
0.000000 Reporter::ERROR field value missing [b$a] /Users/johanna/corelight/bro/testing/btest/.tmp/plugins.reporter-hook/reporter-hook.bro, line 23
#close 2017-07-26-17-58-52

View file

@ -0,0 +1,43 @@
#include "Plugin.h"
#include <Func.h>
#include <Event.h>
#include <Conn.h>
#include <threading/Formatter.h>
namespace plugin { namespace Reporter_Hook { Plugin plugin; } }
using namespace plugin::Reporter_Hook;
plugin::Configuration Plugin::Configure()
{
EnableHook(HOOK_REPORTER);
plugin::Configuration config;
config.name = "Reporter::Hook";
config.description = "Exercise Reporter Hook";
config.version.major = 1;
config.version.minor = 0;
return config;
}
bool Plugin::HookReporter(const std::string& prefix, const EventHandlerPtr event,
const Connection* conn, const val_list* addl, bool location,
const Location* location1, const Location* location2,
bool time, const std::string& message)
{
ODesc d;
if ( location1 )
location1->Describe(&d);
if ( location2 )
location2->Describe(&d);
fprintf(stderr, " | Hook %s %s %s\n", prefix.c_str(), message.c_str(), d.Description());
if ( message == "An Error that does not show up in the log" )
return false;
return true;
}

View file

@ -0,0 +1,27 @@
#ifndef BRO_PLUGIN_Reporter_Hook
#define BRO_PLUGIN_Reporter_Hook
#include <plugin/Plugin.h>
namespace plugin {
namespace Reporter_Hook {
class Plugin : public ::plugin::Plugin
{
protected:
bool HookReporter(const std::string& prefix, const EventHandlerPtr event,
const Connection* conn, const val_list* addl, bool location,
const Location* location1, const Location* location2,
bool time, const std::string& buffer) override;
// Overridden from plugin::Plugin.
plugin::Configuration Configure() override;
};
extern Plugin plugin;
}
}
#endif

View file

@ -0,0 +1,24 @@
# @TEST-EXEC: ${DIST}/aux/bro-aux/plugin-support/init-plugin -u . Reporter Hook
# @TEST-EXEC: cp -r %DIR/reporter-hook-plugin/* .
# @TEST-EXEC: ./configure --bro-dist=${DIST} && make
# @TEST-EXEC: BRO_PLUGIN_ACTIVATE="Reporter::Hook" BRO_PLUGIN_PATH=`pwd` bro -b %INPUT 2>&1 | $SCRIPTS/diff-remove-abspath | sort | uniq >output
# @TEST-EXEC: btest-diff output
# @TEST-EXEC: TEST_DIFF_CANONIFIER="$SCRIPTS/diff-remove-abspath | $SCRIPTS/diff-remove-timestamps" btest-diff reporter.log
@load base/frameworks/reporter
type TestType: record {
a: bool &optional;
};
event bro_init()
{
Reporter::info("Some Info");
Reporter::warning("A warning");
Reporter::error("An Error");
Reporter::error("An Error that does not show up in the log");
# And just trigger a runtime problem.
local b = TestType();
print b$a;
}