mirror of
https://github.com/zeek/zeek.git
synced 2025-10-02 06:38:20 +00:00
Checkpointing the dynamic plugin code.
This is essentially the code from the dynamic-plugin branch except for some pieces that I have split out into separate, earlier commits. I'm going to updatre things in this branch going forward.
This commit is contained in:
parent
7412470d66
commit
555df1e7ea
43 changed files with 1306 additions and 110 deletions
|
@ -1,5 +1,10 @@
|
|||
project(Bro C CXX)
|
||||
|
||||
# When changing the minimum version here, also adapt
|
||||
# cmake/BroPluginDynamic and
|
||||
# aux/bro-aux/plugin-support/skeleton/CMakeLists.txt
|
||||
cmake_minimum_required(VERSION 2.6.3 FATAL_ERROR)
|
||||
|
||||
include(cmake/CommonCMakeConfig.cmake)
|
||||
|
||||
########################################################################
|
||||
|
@ -17,6 +22,7 @@ set(BRO_SCRIPT_SOURCE_PATH ${CMAKE_CURRENT_SOURCE_DIR}/scripts)
|
|||
get_filename_component(BRO_SCRIPT_INSTALL_PATH ${BRO_SCRIPT_INSTALL_PATH}
|
||||
ABSOLUTE)
|
||||
|
||||
set(BRO_PLUGIN_INSTALL_PATH ${BRO_ROOT_DIR}/share/bro/plugins)
|
||||
set(BRO_MAGIC_INSTALL_PATH ${BRO_ROOT_DIR}/share/bro/magic)
|
||||
set(BRO_MAGIC_SOURCE_PATH ${CMAKE_CURRENT_SOURCE_DIR}/magic/database)
|
||||
|
||||
|
@ -183,6 +189,10 @@ include(MiscTests)
|
|||
include(PCAPTests)
|
||||
include(OpenSSLTests)
|
||||
include(CheckNameserCompat)
|
||||
include(GetArchitecture)
|
||||
|
||||
# Tell the plugin code that we're building as part of the main tree.
|
||||
set(BRO_PLUGIN_INTERNAL_BUILD true CACHE INTERNAL "" FORCE)
|
||||
|
||||
configure_file(${CMAKE_CURRENT_SOURCE_DIR}/config.h.in
|
||||
${CMAKE_CURRENT_BINARY_DIR}/config.h)
|
||||
|
|
2
cmake
2
cmake
|
@ -1 +1 @@
|
|||
Subproject commit 0187b33a29d5ec824f940feff60dc5d8c2fe314f
|
||||
Subproject commit fc53d57770c86fbf9bd2d9694f06a1d539ebe35f
|
11
config.h.in
11
config.h.in
|
@ -209,3 +209,14 @@
|
|||
|
||||
/* Common IPv6 extension structure */
|
||||
#cmakedefine HAVE_IP6_EXT
|
||||
|
||||
/* String with host architecture (e.g., "linux-x86_64") */
|
||||
#define HOST_ARCHITECTURE "@HOST_ARCHITECTURE@"
|
||||
|
||||
/* String with extension of dynamic libraries (e.g., ".so") */
|
||||
#define SHARED_LIBRARY_SUFFIX "@CMAKE_SHARED_LIBRARY_SUFFIX@"
|
||||
|
||||
/* True if we're building outside of the main Bro source code tree. */
|
||||
#ifndef BRO_PLUGIN_INTERNAL_BUILD
|
||||
#define BRO_PLUGIN_INTERNAL_BUILD @BRO_PLUGIN_INTERNAL_BUILD@
|
||||
#endif
|
||||
|
|
|
@ -414,6 +414,17 @@ add_dependencies(bro bif_loader_plugins)
|
|||
# Install *.bif.bro.
|
||||
install(DIRECTORY ${CMAKE_BINARY_DIR}/scripts/base/bif DESTINATION ${BRO_SCRIPT_INSTALL_PATH}/base)
|
||||
|
||||
# Make clean removes the bif directory.
|
||||
set_directory_properties(PROPERTIES ADDITIONAL_MAKE_CLEAN_FILES ${CMAKE_BINARY_DIR}/scripts/base/bif)
|
||||
# Install the plugin directory with a short README.
|
||||
set(plugin_binary_dir "${CMAKE_BINARY_DIR}/plugins")
|
||||
|
||||
add_custom_command(OUTPUT ${plugin_binary_dir}/README
|
||||
COMMAND mkdir ARGS -p ${plugin_binary_dir}
|
||||
COMMAND echo ARGS "This directory holds dynamic Bro plugins." >${plugin_binary_dir}/README)
|
||||
|
||||
add_custom_target(plugin-dir DEPENDS ${plugin_binary_dir}/README)
|
||||
add_dependencies(bro plugin-dir)
|
||||
|
||||
# Make clean removes the bif and plugin directories.
|
||||
set_directory_properties(PROPERTIES ADDITIONAL_MAKE_CLEAN_FILES ${CMAKE_BINARY_DIR}/scripts/base/bif)
|
||||
set_directory_properties(PROPERTIES ADDITIONAL_MAKE_CLEAN_FILES ${plugin_binary_dir})
|
||||
|
||||
|
|
|
@ -5,6 +5,7 @@
|
|||
|
||||
#include "DebugLogger.h"
|
||||
#include "Net.h"
|
||||
#include "plugin/Plugin.h"
|
||||
|
||||
DebugLogger debug_logger("debug");
|
||||
|
||||
|
@ -73,10 +74,12 @@ void DebugLogger::EnableStreams(const char* s)
|
|||
{
|
||||
if ( strcasecmp("verbose", tok) == 0 )
|
||||
verbose = true;
|
||||
else
|
||||
else if ( strncmp(tok, "plugin-", 7) != 0 )
|
||||
reporter->FatalError("unknown debug stream %s\n", tok);
|
||||
}
|
||||
|
||||
enabled_streams.insert(tok);
|
||||
|
||||
tok = strtok(0, ",");
|
||||
}
|
||||
|
||||
|
@ -105,4 +108,24 @@ void DebugLogger::Log(DebugStream stream, const char* fmt, ...)
|
|||
fflush(file);
|
||||
}
|
||||
|
||||
void DebugLogger::Log(const plugin::Plugin& plugin, const char* fmt, ...)
|
||||
{
|
||||
string tok = string("plugin-") + plugin.Name();
|
||||
tok = strreplace(tok, "::", "-");
|
||||
|
||||
if ( enabled_streams.find(tok) == enabled_streams.end() )
|
||||
return;
|
||||
|
||||
fprintf(file, "%17.06f/%17.06f [plugin %s] ",
|
||||
network_time, current_time(true), plugin.Name());
|
||||
|
||||
va_list ap;
|
||||
va_start(ap, fmt);
|
||||
vfprintf(file, fmt, ap);
|
||||
va_end(ap);
|
||||
|
||||
fputc('\n', file);
|
||||
fflush(file);
|
||||
}
|
||||
|
||||
#endif
|
||||
|
|
|
@ -7,6 +7,8 @@
|
|||
#ifdef DEBUG
|
||||
|
||||
#include <stdio.h>
|
||||
#include <string>
|
||||
#include <set>
|
||||
|
||||
// To add a new debugging stream, add a constant here as well as
|
||||
// an entry to DebugLogger::streams in DebugLogger.cc.
|
||||
|
@ -27,7 +29,7 @@ enum DebugStream {
|
|||
DBG_INPUT, // Input streams
|
||||
DBG_THREADING, // Threading system
|
||||
DBG_FILE_ANALYSIS, // File analysis
|
||||
DBG_PLUGINS,
|
||||
DBG_PLUGINS, // Plugin support
|
||||
|
||||
NUM_DBGS // Has to be last
|
||||
};
|
||||
|
@ -39,6 +41,10 @@ enum DebugStream {
|
|||
#define DBG_PUSH(stream) debug_logger.PushIndent(stream)
|
||||
#define DBG_POP(stream) debug_logger.PopIndent(stream)
|
||||
|
||||
#define PLUGIN_DBG_LOG(plugin, args...) debug_logger.Log(plugin, args)
|
||||
|
||||
namespace plugin { class Plugin; }
|
||||
|
||||
class DebugLogger {
|
||||
public:
|
||||
// Output goes to stderr per default.
|
||||
|
@ -46,6 +52,7 @@ public:
|
|||
~DebugLogger();
|
||||
|
||||
void Log(DebugStream stream, const char* fmt, ...);
|
||||
void Log(const plugin::Plugin& plugin, const char* fmt, ...);
|
||||
|
||||
void PushIndent(DebugStream stream)
|
||||
{ ++streams[int(stream)].indent; }
|
||||
|
@ -76,6 +83,8 @@ private:
|
|||
bool enabled;
|
||||
};
|
||||
|
||||
std::set<std::string> enabled_streams;
|
||||
|
||||
static Stream streams[NUM_DBGS];
|
||||
};
|
||||
|
||||
|
@ -86,6 +95,7 @@ extern DebugLogger debug_logger;
|
|||
#define DBG_LOG_VERBOSE(args...)
|
||||
#define DBG_PUSH(stream)
|
||||
#define DBG_POP(stream)
|
||||
#define PLUGIN_DBG_LOG(plugin, args...)
|
||||
#endif
|
||||
|
||||
#endif
|
||||
|
|
|
@ -6,6 +6,7 @@
|
|||
#include "Func.h"
|
||||
#include "NetVar.h"
|
||||
#include "Trigger.h"
|
||||
#include "plugin/Manager.h"
|
||||
|
||||
EventMgr mgr;
|
||||
|
||||
|
@ -77,6 +78,9 @@ EventMgr::~EventMgr()
|
|||
|
||||
void EventMgr::QueueEvent(Event* event)
|
||||
{
|
||||
if ( plugin_mgr->QueueEvent(event) )
|
||||
return;
|
||||
|
||||
if ( ! head )
|
||||
head = tail = event;
|
||||
else
|
||||
|
@ -115,6 +119,8 @@ void EventMgr::Drain()
|
|||
|
||||
SegmentProfiler(segment_logger, "draining-events");
|
||||
|
||||
plugin_mgr->DrainEvents();
|
||||
|
||||
draining = true;
|
||||
while ( head )
|
||||
Dispatch();
|
||||
|
|
|
@ -49,7 +49,7 @@ void FlowSrc::Process()
|
|||
|
||||
// This is normally done by calling net_packet_dispatch(),
|
||||
// but as we don't have a packet to dispatch ...
|
||||
network_time = next_timestamp;
|
||||
net_update_time(next_timestamp);
|
||||
expire_timers();
|
||||
|
||||
netflow_analyzer->downflow()->set_exporter_ip(exporter_ip);
|
||||
|
|
47
src/Func.cc
47
src/Func.cc
|
@ -46,6 +46,7 @@
|
|||
#include "Event.h"
|
||||
#include "Traverse.h"
|
||||
#include "Reporter.h"
|
||||
#include "plugin/Manager.h"
|
||||
|
||||
extern RETSIGTYPE sig_handler(int signo);
|
||||
|
||||
|
@ -226,7 +227,7 @@ TraversalCode Func::Traverse(TraversalCallback* cb) const
|
|||
HANDLE_TC_STMT_PRE(tc);
|
||||
|
||||
// FIXME: Traverse arguments to builtin functions, too.
|
||||
if ( kind == BRO_FUNC )
|
||||
if ( kind == BRO_FUNC && scope )
|
||||
{
|
||||
tc = scope->Traverse(cb);
|
||||
HANDLE_TC_STMT_PRE(tc);
|
||||
|
@ -281,6 +282,50 @@ Val* BroFunc::Call(val_list* args, Frame* parent) const
|
|||
#ifdef PROFILE_BRO_FUNCTIONS
|
||||
DEBUG_MSG("Function: %s\n", id->Name());
|
||||
#endif
|
||||
|
||||
Val* plugin_result = plugin_mgr->CallFunction(this, args);
|
||||
|
||||
if ( plugin_result )
|
||||
{
|
||||
// TODO: We should factor this out into its own method.
|
||||
switch ( Flavor() ) {
|
||||
case FUNC_FLAVOR_EVENT:
|
||||
Unref(plugin_result);
|
||||
plugin_result = 0;
|
||||
break;
|
||||
|
||||
case FUNC_FLAVOR_HOOK:
|
||||
if ( plugin_result->Type()->Tag() != TYPE_BOOL )
|
||||
reporter->InternalError("plugin returned non-bool for hook");
|
||||
|
||||
break;
|
||||
|
||||
case FUNC_FLAVOR_FUNCTION:
|
||||
{
|
||||
BroType* yt = FType()->YieldType();
|
||||
|
||||
if ( (! yt) || yt->Tag() == TYPE_VOID )
|
||||
{
|
||||
Unref(plugin_result);
|
||||
plugin_result = 0;
|
||||
}
|
||||
|
||||
else
|
||||
{
|
||||
if ( plugin_result->Type()->Tag() != yt->Tag() )
|
||||
reporter->InternalError("plugin returned wrong type for function call");
|
||||
}
|
||||
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
loop_over_list(*args, i)
|
||||
Unref((*args)[i]);
|
||||
|
||||
return plugin_result;
|
||||
}
|
||||
|
||||
if ( bodies.empty() )
|
||||
{
|
||||
// Can only happen for events and hooks.
|
||||
|
|
15
src/Net.cc
15
src/Net.cc
|
@ -30,6 +30,7 @@
|
|||
#include "PacketSort.h"
|
||||
#include "Serializer.h"
|
||||
#include "PacketDumper.h"
|
||||
#include "plugin/Manager.h"
|
||||
|
||||
extern "C" {
|
||||
#include "setsignal.h"
|
||||
|
@ -144,13 +145,17 @@ RETSIGTYPE watchdog(int /* signo */)
|
|||
return RETSIGVAL;
|
||||
}
|
||||
|
||||
void net_update_time(double new_network_time)
|
||||
{
|
||||
network_time = new_network_time;
|
||||
plugin_mgr->UpdateNetworkTime(network_time);
|
||||
}
|
||||
|
||||
void net_init(name_list& interfaces, name_list& readfiles,
|
||||
name_list& netflows, name_list& flowfiles,
|
||||
const char* writefile, const char* filter,
|
||||
const char* secondary_filter, int do_watchdog)
|
||||
{
|
||||
init_net_var();
|
||||
|
||||
if ( readfiles.length() > 0 || flowfiles.length() > 0 )
|
||||
{
|
||||
reading_live = pseudo_realtime > 0.0;
|
||||
|
@ -323,7 +328,7 @@ void net_packet_dispatch(double t, const struct pcap_pkthdr* hdr,
|
|||
: timer_mgr;
|
||||
|
||||
// network_time never goes back.
|
||||
network_time = tmgr->Time() < t ? t : tmgr->Time();
|
||||
net_update_time(tmgr->Time() < t ? t : tmgr->Time());
|
||||
|
||||
current_pktsrc = src_ps;
|
||||
current_iosrc = src_ps;
|
||||
|
@ -456,7 +461,7 @@ void net_run()
|
|||
{
|
||||
// Take advantage of the lull to get up to
|
||||
// date on timers and events.
|
||||
network_time = ct;
|
||||
net_update_time(ct);
|
||||
expire_timers();
|
||||
usleep(1); // Just yield.
|
||||
}
|
||||
|
@ -478,7 +483,7 @@ void net_run()
|
|||
// date on timers and events. Because we only
|
||||
// have timers as sources, going to sleep here
|
||||
// doesn't risk blocking on other inputs.
|
||||
network_time = current_time();
|
||||
net_update_time(current_time());
|
||||
expire_timers();
|
||||
|
||||
// Avoid busy-waiting - pause for 100 ms.
|
||||
|
|
|
@ -19,6 +19,7 @@ extern void net_run();
|
|||
extern void net_get_final_stats();
|
||||
extern void net_finish(int drain_events);
|
||||
extern void net_delete(); // Reclaim all memory, etc.
|
||||
extern void net_update_time(double new_network_time);
|
||||
extern void net_packet_arrival(double t, const struct pcap_pkthdr* hdr,
|
||||
const u_char* pkt, int hdr_size,
|
||||
PktSrc* src_ps);
|
||||
|
|
|
@ -1455,7 +1455,7 @@ void RemoteSerializer::Process()
|
|||
// FIXME: The following chunk of code is copied from
|
||||
// net_packet_dispatch(). We should change that function
|
||||
// to accept an IOSource instead of the PktSrc.
|
||||
network_time = p->time;
|
||||
net_update_time(p->time);
|
||||
|
||||
SegmentProfiler(segment_logger, "expiring-timers");
|
||||
TimerMgr* tmgr = sessions->LookupTimerMgr(GetCurrentTag());
|
||||
|
|
|
@ -247,14 +247,13 @@ void init_alternative_mode()
|
|||
fprintf(fp_func_init, "\n");
|
||||
fprintf(fp_func_init, "#include <list>\n");
|
||||
fprintf(fp_func_init, "#include <string>\n");
|
||||
fprintf(fp_func_init, "#include \"plugin/Plugin.h\"\n");
|
||||
fprintf(fp_func_init, "#include \"%s.h\"\n", input_filename);
|
||||
fprintf(fp_func_init, "\n");
|
||||
fprintf(fp_func_init, "namespace plugin { namespace %s {\n", plugin);
|
||||
fprintf(fp_func_init, "\n");
|
||||
fprintf(fp_func_init, "std::list<std::pair<const char*, int> > __bif_%s_init()\n", name);
|
||||
fprintf(fp_func_init, "void __bif_%s_init(plugin::Plugin* plugin)\n", name);
|
||||
fprintf(fp_func_init, "\t{\n");
|
||||
fprintf(fp_func_init, "\tstd::list<std::pair<const char*, int> > bifs;\n");
|
||||
fprintf(fp_func_init, "\n");
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -266,7 +265,6 @@ void finish_alternative_mode()
|
|||
if ( plugin )
|
||||
{
|
||||
fprintf(fp_func_init, "\n");
|
||||
fprintf(fp_func_init, "\treturn bifs;\n");
|
||||
fprintf(fp_func_init, "\t}\n");
|
||||
fprintf(fp_func_init, "} }\n");
|
||||
fprintf(fp_func_init, "\n");
|
||||
|
|
|
@ -267,12 +267,12 @@ void print_event_c_body(FILE *fp)
|
|||
//fprintf(fp, "%s // end namespace\n", decl.generate_c_namespace_end.c_str());
|
||||
}
|
||||
|
||||
void record_bif_item(const char* id, int type)
|
||||
void record_bif_item(const char* id, const char* type)
|
||||
{
|
||||
if ( ! plugin )
|
||||
return;
|
||||
|
||||
fprintf(fp_func_init, "\tbifs.push_back(std::make_pair(\"%s\", %d));\n", id, type);
|
||||
fprintf(fp_func_init, "\tplugin->AddBifItem(\"%s\", plugin::BifItem::%s);\n", id, type);
|
||||
}
|
||||
|
||||
%}
|
||||
|
@ -358,7 +358,7 @@ type_def: TOK_TYPE opt_ws TOK_ID opt_ws ':' opt_ws type_def_types opt_ws ';'
|
|||
decl.c_fullname.c_str(), decl.bro_fullname.c_str(),
|
||||
type_name.c_str());
|
||||
|
||||
record_bif_item(decl.bro_fullname.c_str(), 5);
|
||||
record_bif_item(decl.bro_fullname.c_str(), "TYPE");
|
||||
}
|
||||
;
|
||||
|
||||
|
@ -401,7 +401,7 @@ enum_def: enum_def_1 enum_list TOK_RPB
|
|||
"\t%s = internal_type(\"%s\")->AsEnumType();\n",
|
||||
decl.c_fullname.c_str(), decl.bro_fullname.c_str());
|
||||
|
||||
record_bif_item(decl.bro_fullname.c_str(), 5);
|
||||
record_bif_item(decl.bro_fullname.c_str(), "TYPE");
|
||||
}
|
||||
;
|
||||
|
||||
|
@ -457,7 +457,7 @@ const_def: TOK_CONST opt_ws TOK_ID opt_ws ':' opt_ws TOK_ID opt_ws ';'
|
|||
decl.c_fullname.c_str(), decl.bro_fullname.c_str(),
|
||||
accessor);
|
||||
|
||||
record_bif_item(decl.bro_fullname.c_str(), 3);
|
||||
record_bif_item(decl.bro_fullname.c_str(), "CONSTANT");
|
||||
}
|
||||
|
||||
attr_list:
|
||||
|
@ -545,7 +545,7 @@ head_1: TOK_ID opt_ws arg_begin
|
|||
"Val* %s(Frame* frame, val_list* %s)",
|
||||
decl.c_fullname.c_str(), arg_list_name);
|
||||
|
||||
record_bif_item(decl.bro_fullname.c_str(), 1);
|
||||
record_bif_item(decl.bro_fullname.c_str(), "FUNCTION");
|
||||
}
|
||||
else if ( definition_type == EVENT_DEF )
|
||||
{
|
||||
|
@ -562,7 +562,7 @@ head_1: TOK_ID opt_ws arg_begin
|
|||
"\t%s = internal_handler(\"%s\");\n",
|
||||
decl.c_fullname.c_str(), decl.bro_fullname.c_str());
|
||||
|
||||
record_bif_item(decl.bro_fullname.c_str(), 2);
|
||||
record_bif_item(decl.bro_fullname.c_str(), "EVENT");
|
||||
|
||||
// C++ prototypes of bro_event_* functions will
|
||||
// be generated later.
|
||||
|
|
72
src/main.cc
72
src/main.cc
|
@ -198,6 +198,7 @@ void usage()
|
|||
fprintf(stderr, " -N|--print-plugins | print available plugins and exit (-NN for verbose)\n");
|
||||
fprintf(stderr, " -O|--optimize | optimize policy script\n");
|
||||
fprintf(stderr, " -P|--prime-dns | prime DNS\n");
|
||||
fprintf(stderr, " -Q|--time | print execution time summary to stderr\n");
|
||||
fprintf(stderr, " -R|--replay <events.bst> | replay events\n");
|
||||
fprintf(stderr, " -S|--debug-rules | enable rule debugging\n");
|
||||
fprintf(stderr, " -T|--re-level <level> | set 'RE_level' for rules\n");
|
||||
|
@ -220,8 +221,10 @@ void usage()
|
|||
fprintf(stderr, " -n|--idmef-dtd <idmef-msg.dtd> | specify path to IDMEF DTD file\n");
|
||||
#endif
|
||||
|
||||
fprintf(stderr, " $BROPATH | file search path (%s)\n", bro_path());
|
||||
fprintf(stderr, " $BROPATH | file search path (%s)\n", bro_path().c_str());
|
||||
fprintf(stderr, " $BROMAGIC | libmagic mime magic database search path (%s)\n", bro_magic_path());
|
||||
fprintf(stderr, " $BRO_PLUGINS | plugin search path (%s)\n", bro_plugin_path());
|
||||
fprintf(stderr, " $BRO_PREFIXES | prefix list (%s)\n", bro_prefixes());
|
||||
fprintf(stderr, " $BRO_PREFIXES | prefix list (%s)\n", bro_prefixes().c_str());
|
||||
fprintf(stderr, " $BRO_DNS_FAKE | disable DNS lookups (%s)\n", bro_dns_fake());
|
||||
fprintf(stderr, " $BRO_SEED_FILE | file to load seeds from (not set)\n");
|
||||
|
@ -435,6 +438,8 @@ int main(int argc, char** argv)
|
|||
{
|
||||
std::set_new_handler(bro_new_handler);
|
||||
|
||||
double time_start = current_time(true);
|
||||
|
||||
brofiler.ReadStats();
|
||||
|
||||
bro_argc = argc;
|
||||
|
@ -464,6 +469,7 @@ int main(int argc, char** argv)
|
|||
int rule_debug = 0;
|
||||
int RE_level = 4;
|
||||
int print_plugins = 0;
|
||||
int time_bro = 0;
|
||||
|
||||
static struct option long_opts[] = {
|
||||
{"bare-mode", no_argument, 0, 'b'},
|
||||
|
@ -545,7 +551,7 @@ int main(int argc, char** argv)
|
|||
opterr = 0;
|
||||
|
||||
char opts[256];
|
||||
safe_strncpy(opts, "B:D:e:f:I:i:K:l:n:p:R:r:s:T:t:U:w:x:X:y:Y:z:CFGLNOPSWbdghvZ",
|
||||
safe_strncpy(opts, "B:D:e:f:I:i:K:l:n:p:R:r:s:T:t:U:w:x:X:y:Y:z:CFGLNOPSWbdghvZQ",
|
||||
sizeof(opts));
|
||||
|
||||
#ifdef USE_PERFTOOLS_DEBUG
|
||||
|
@ -674,6 +680,10 @@ int main(int argc, char** argv)
|
|||
dns_type = DNS_PRIME;
|
||||
break;
|
||||
|
||||
case 'Q':
|
||||
time_bro = 1;
|
||||
break;
|
||||
|
||||
case 'R':
|
||||
events_file = optarg;
|
||||
break;
|
||||
|
@ -760,6 +770,7 @@ int main(int argc, char** argv)
|
|||
|
||||
reporter = new Reporter();
|
||||
thread_mgr = new threading::Manager();
|
||||
plugin_mgr = new plugin::Manager();
|
||||
|
||||
#ifdef DEBUG
|
||||
if ( debug_streams )
|
||||
|
@ -810,6 +821,8 @@ int main(int argc, char** argv)
|
|||
if ( ! bare_mode )
|
||||
add_input_file("base/init-default.bro");
|
||||
|
||||
plugin_mgr->LoadPluginsFrom(bro_plugin_path());
|
||||
|
||||
if ( optind == argc &&
|
||||
read_files.length() == 0 && flow_files.length() == 0 &&
|
||||
interfaces.length() == 0 &&
|
||||
|
@ -842,7 +855,6 @@ int main(int argc, char** argv)
|
|||
analyzer_mgr = new analyzer::Manager();
|
||||
log_mgr = new logging::Manager();
|
||||
input_mgr = new input::Manager();
|
||||
plugin_mgr = new plugin::Manager();
|
||||
file_mgr = new file_analysis::Manager();
|
||||
|
||||
plugin_mgr->InitPreScript();
|
||||
|
@ -877,9 +889,13 @@ int main(int argc, char** argv)
|
|||
|
||||
yyparse();
|
||||
|
||||
plugin_mgr->InitPostScript();
|
||||
analyzer_mgr->InitPostScript();
|
||||
file_mgr->InitPostScript();
|
||||
init_general_global_var();
|
||||
init_net_var();
|
||||
|
||||
plugin_mgr->InitBifs();
|
||||
|
||||
if ( reporter->Errors() > 0 )
|
||||
exit(1);
|
||||
|
||||
if ( print_plugins )
|
||||
{
|
||||
|
@ -887,6 +903,10 @@ int main(int argc, char** argv)
|
|||
exit(1);
|
||||
}
|
||||
|
||||
plugin_mgr->InitPostScript();
|
||||
analyzer_mgr->InitPostScript();
|
||||
file_mgr->InitPostScript();
|
||||
|
||||
#ifdef USE_PERFTOOLS_DEBUG
|
||||
}
|
||||
#endif
|
||||
|
@ -916,8 +936,6 @@ int main(int argc, char** argv)
|
|||
|
||||
reporter->InitOptions();
|
||||
|
||||
init_general_global_var();
|
||||
|
||||
if ( user_pcap_filter )
|
||||
{
|
||||
ID* id = global_scope()->Lookup("cmd_line_bpf_filter");
|
||||
|
@ -1079,7 +1097,7 @@ int main(int argc, char** argv)
|
|||
if ( ! reading_live && ! reading_traces )
|
||||
// Set up network_time to track real-time, since
|
||||
// we don't have any other source for it.
|
||||
network_time = current_time();
|
||||
net_update_time(current_time());
|
||||
|
||||
EventHandlerPtr bro_init = internal_handler("bro_init");
|
||||
if ( bro_init ) //### this should be a function
|
||||
|
@ -1165,7 +1183,43 @@ int main(int argc, char** argv)
|
|||
|
||||
#endif
|
||||
|
||||
double time_net_start = current_time(true);;
|
||||
|
||||
unsigned int mem_net_start_total;
|
||||
unsigned int mem_net_start_malloced;
|
||||
|
||||
if ( time_bro )
|
||||
{
|
||||
get_memory_usage(&mem_net_start_total, &mem_net_start_malloced);
|
||||
|
||||
fprintf(stderr, "# initialization %.6f\n", time_net_start - time_start);
|
||||
|
||||
fprintf(stderr, "# initialization %uM/%uM\n",
|
||||
mem_net_start_total / 1024 / 1024,
|
||||
mem_net_start_malloced / 1024 / 1024);
|
||||
}
|
||||
|
||||
net_run();
|
||||
|
||||
double time_net_done = current_time(true);;
|
||||
|
||||
unsigned int mem_net_done_total;
|
||||
unsigned int mem_net_done_malloced;
|
||||
|
||||
if ( time_bro )
|
||||
{
|
||||
get_memory_usage(&mem_net_done_total, &mem_net_done_malloced);
|
||||
|
||||
fprintf(stderr, "# total time %.6f, processing %.6f\n",
|
||||
time_net_done - time_start, time_net_done - time_net_start);
|
||||
|
||||
fprintf(stderr, "# total mem %uM/%uM, processing %uM/%uM\n",
|
||||
mem_net_done_total / 1024 / 1024,
|
||||
mem_net_done_malloced / 1024 / 1024,
|
||||
(mem_net_done_total - mem_net_start_total) / 1024 / 1024,
|
||||
(mem_net_done_malloced - mem_net_start_malloced) / 1024 / 1024);
|
||||
}
|
||||
|
||||
done_with_network();
|
||||
net_delete();
|
||||
|
||||
|
|
|
@ -83,8 +83,6 @@ public:
|
|||
*/
|
||||
T GetComponentTag(Val* v) const;
|
||||
|
||||
protected:
|
||||
|
||||
/**
|
||||
* Add a component the internal maps used to keep track of it and create
|
||||
* a script-layer ID for the component's enum value.
|
||||
|
|
|
@ -28,18 +28,15 @@
|
|||
* must be unique across all loaded plugins.
|
||||
*/
|
||||
#define BRO_PLUGIN_BEGIN(_ns, _name) \
|
||||
namespace plugin { namespace _ns ## _ ## _name {\
|
||||
namespace plugin { namespace _ns ## _ ## _name { \
|
||||
class Plugin : public plugin::Plugin { \
|
||||
protected: \
|
||||
void InitPreScript() \
|
||||
{ \
|
||||
SetName(#_ns "::" #_name); \
|
||||
SetVersion(-1);\
|
||||
SetAPIVersion(BRO_PLUGIN_API_VERSION);\
|
||||
SetDynamicPlugin(false);
|
||||
// TODO: The SetDynamicPlugin() call is currently hardcoded to false. Change
|
||||
// once we have dynamic plugins as well.
|
||||
|
||||
SetVersion(-1); \
|
||||
SetAPIVersion(BRO_PLUGIN_API_VERSION); \
|
||||
SetDynamicPlugin(! BRO_PLUGIN_INTERNAL_BUILD);\
|
||||
|
||||
/**
|
||||
* Ends the definition of a plugin.
|
||||
|
@ -76,8 +73,8 @@
|
|||
* interpreter.
|
||||
*/
|
||||
#define BRO_PLUGIN_BIF_FILE(file) \
|
||||
extern std::list<std::pair<const char*, int> > __bif_##file##_init(); \
|
||||
AddBifInitFunction(&__bif_##file##_init);
|
||||
extern void __bif_##file##_init(plugin::Plugin*); \
|
||||
__AddBifInitFunction(&__bif_##file##_init);
|
||||
|
||||
/**
|
||||
* Defines a component implementing a protocol analyzer.
|
||||
|
|
|
@ -1,11 +1,23 @@
|
|||
// See the file "COPYING" in the main distribution directory for copyright.
|
||||
|
||||
#include <sstream>
|
||||
#include <dirent.h>
|
||||
#include <glob.h>
|
||||
#include <dlfcn.h>
|
||||
#include <errno.h>
|
||||
#include <sys/stat.h>
|
||||
|
||||
#include "Manager.h"
|
||||
|
||||
#include "../Reporter.h"
|
||||
#include "../Func.h"
|
||||
#include "../Event.h"
|
||||
|
||||
using namespace plugin;
|
||||
|
||||
string Manager::current_dir;
|
||||
string Manager::current_sopath;
|
||||
|
||||
Manager::Manager()
|
||||
{
|
||||
init = false;
|
||||
|
@ -16,18 +28,162 @@ Manager::~Manager()
|
|||
assert(! init);
|
||||
}
|
||||
|
||||
bool Manager::LoadPlugin(const std::string& path)
|
||||
void Manager::LoadPluginsFrom(const string& dir)
|
||||
{
|
||||
assert(! init);
|
||||
reporter->InternalError("plugin::Manager::LoadPlugin not yet implemented");
|
||||
return false;
|
||||
|
||||
if ( dir.empty() )
|
||||
return;
|
||||
|
||||
if ( dir.find(":") != string::npos )
|
||||
{
|
||||
// Split at ":".
|
||||
std::stringstream s(dir);
|
||||
std::string d;
|
||||
|
||||
while ( std::getline(s, d, ':') )
|
||||
LoadPluginsFrom(d);
|
||||
|
||||
return;
|
||||
}
|
||||
|
||||
bool Manager::LoadPluginsFrom(const std::string& dir)
|
||||
if ( ! is_dir(dir) )
|
||||
{
|
||||
DBG_LOG(DBG_PLUGINS, "Not a valid plugin directory: %s", dir.c_str());
|
||||
return;
|
||||
}
|
||||
|
||||
int rc = LoadPlugin(dir);
|
||||
|
||||
if ( rc >= 0 )
|
||||
return;
|
||||
|
||||
DBG_LOG(DBG_PLUGINS, "Searching directory %s recursively for plugins", dir.c_str());
|
||||
|
||||
DIR* d = opendir(dir.c_str());
|
||||
|
||||
if ( ! d )
|
||||
{
|
||||
DBG_LOG(DBG_PLUGINS, "Cannot open directory %s", dir.c_str());
|
||||
return;
|
||||
}
|
||||
|
||||
bool found = false;
|
||||
|
||||
struct dirent *dp;
|
||||
|
||||
while ( (dp = readdir(d)) )
|
||||
{
|
||||
struct stat st;
|
||||
|
||||
if ( strcmp(dp->d_name, "..") == 0
|
||||
|| strcmp(dp->d_name, ".") == 0 )
|
||||
continue;
|
||||
|
||||
string path = dir + "/" + dp->d_name;
|
||||
|
||||
if( stat(path.c_str(), &st) < 0 )
|
||||
{
|
||||
DBG_LOG(DBG_PLUGINS, "Cannot stat %s: %s", path.c_str(), strerror(errno));
|
||||
continue;
|
||||
}
|
||||
|
||||
if ( st.st_mode & S_IFDIR )
|
||||
LoadPluginsFrom(path);
|
||||
}
|
||||
}
|
||||
|
||||
int Manager::LoadPlugin(const std::string& dir)
|
||||
{
|
||||
assert(! init);
|
||||
reporter->InternalError("plugin::Manager::LoadPluginsFrom not yet implemented");
|
||||
return false;
|
||||
|
||||
// Check if it's a plugin dirctory.
|
||||
if ( ! is_file(dir + "/__bro_plugin__") )
|
||||
return -1;
|
||||
|
||||
DBG_LOG(DBG_PLUGINS, "Loading plugin from %s", dir.c_str());
|
||||
|
||||
// Add the "scripts" and "bif" directories to BROPATH.
|
||||
string scripts = dir + "/scripts";
|
||||
|
||||
if ( is_dir(scripts) )
|
||||
{
|
||||
DBG_LOG(DBG_PLUGINS, " Adding %s to BROPATH", scripts.c_str());
|
||||
add_to_bro_path(scripts);
|
||||
}
|
||||
|
||||
string bif = dir + "/bif";
|
||||
|
||||
if ( is_dir(bif) )
|
||||
{
|
||||
DBG_LOG(DBG_PLUGINS, " Adding %s to BROPATH", bif.c_str());
|
||||
add_to_bro_path(bif);
|
||||
}
|
||||
|
||||
// Load dylib/scripts/__load__.bro automatically.
|
||||
string dyinit = dir + "/dylib/scripts/__load__.bro";
|
||||
|
||||
if ( is_file(dyinit) )
|
||||
{
|
||||
DBG_LOG(DBG_PLUGINS, " Adding %s for loading", dyinit.c_str());
|
||||
add_input_file(dyinit.c_str());
|
||||
}
|
||||
|
||||
// Load scripts/__load__.bro automatically.
|
||||
string init = scripts + "/__load__.bro";
|
||||
|
||||
if ( is_file(init) )
|
||||
{
|
||||
DBG_LOG(DBG_PLUGINS, " Adding %s for loading", init.c_str());
|
||||
add_input_file(init.c_str());
|
||||
}
|
||||
|
||||
// Load bif/__load__.bro automatically.
|
||||
init = bif + "/__load__.bro";
|
||||
|
||||
if ( is_file(init) )
|
||||
{
|
||||
DBG_LOG(DBG_PLUGINS, " Adding %s for loading", init.c_str());
|
||||
add_input_file(init.c_str());
|
||||
}
|
||||
|
||||
// Load shared libraries.
|
||||
|
||||
string dypattern = dir + "/dylib/*." + HOST_ARCHITECTURE + SHARED_LIBRARY_SUFFIX;
|
||||
|
||||
DBG_LOG(DBG_PLUGINS, " Searching for shared libraries %s", dypattern.c_str());
|
||||
|
||||
glob_t gl;
|
||||
|
||||
if ( glob(dypattern.c_str(), 0, 0, &gl) == 0 )
|
||||
{
|
||||
for ( size_t i = 0; i < gl.gl_pathc; i++ )
|
||||
{
|
||||
const char* path = gl.gl_pathv[i];
|
||||
|
||||
current_dir = dir;
|
||||
current_sopath = path;
|
||||
void* hdl = dlopen(path, RTLD_LAZY | RTLD_GLOBAL);
|
||||
current_dir.clear();
|
||||
current_sopath.clear();
|
||||
|
||||
if ( ! hdl )
|
||||
{
|
||||
const char* err = dlerror();
|
||||
reporter->FatalError("cannot load plugin library %s: %s", path, err ? err : "<unknown error>");
|
||||
}
|
||||
|
||||
DBG_LOG(DBG_PLUGINS, " Loaded %s", path);
|
||||
}
|
||||
}
|
||||
|
||||
else
|
||||
{
|
||||
DBG_LOG(DBG_PLUGINS, " No shared library found");
|
||||
return 1;
|
||||
}
|
||||
|
||||
return 1;
|
||||
}
|
||||
|
||||
static bool plugin_cmp(const Plugin* a, const Plugin* b)
|
||||
|
@ -39,22 +195,61 @@ bool Manager::RegisterPlugin(Plugin *plugin)
|
|||
{
|
||||
Manager::PluginsInternal()->push_back(plugin);
|
||||
|
||||
if ( current_dir.size() && current_sopath.size() )
|
||||
plugin->SetPluginLocation(current_dir.c_str(), current_sopath.c_str());
|
||||
|
||||
// Sort plugins by name to make sure we have a deterministic order.
|
||||
PluginsInternal()->sort(plugin_cmp);
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
static bool interpreter_plugin_cmp(const InterpreterPlugin* a, const InterpreterPlugin* b)
|
||||
{
|
||||
if ( a->Priority() == b->Priority() )
|
||||
return a->Name() < b->Name();
|
||||
|
||||
// Reverse sort.
|
||||
return a->Priority() > b->Priority();
|
||||
}
|
||||
|
||||
void Manager::InitPreScript()
|
||||
{
|
||||
assert(! init);
|
||||
|
||||
for ( plugin_list::iterator i = Manager::PluginsInternal()->begin(); i != Manager::PluginsInternal()->end(); i++ )
|
||||
(*i)->InitPreScript();
|
||||
{
|
||||
Plugin* plugin = *i;
|
||||
|
||||
if ( plugin->PluginType() == Plugin::INTERPRETER )
|
||||
interpreter_plugins.push_back(dynamic_cast<InterpreterPlugin *>(plugin));
|
||||
|
||||
plugin->InitPreScript();
|
||||
|
||||
// Track the file extensions the plugin can handle.
|
||||
std::stringstream ext(plugin->FileExtensions());
|
||||
|
||||
// Split at ":".
|
||||
std::string e;
|
||||
|
||||
while ( std::getline(ext, e, ':') )
|
||||
{
|
||||
DBG_LOG(DBG_PLUGINS, "Plugin %s handles *.%s", plugin->Name(), e.c_str());
|
||||
extensions.insert(std::make_pair(e, plugin));
|
||||
}
|
||||
}
|
||||
|
||||
interpreter_plugins.sort(interpreter_plugin_cmp);
|
||||
|
||||
init = true;
|
||||
}
|
||||
|
||||
void Manager::InitBifs()
|
||||
{
|
||||
for ( plugin_list::iterator i = Manager::PluginsInternal()->begin(); i != Manager::PluginsInternal()->end(); i++ )
|
||||
(*i)->InitBifs();
|
||||
}
|
||||
|
||||
void Manager::InitPostScript()
|
||||
{
|
||||
assert(init);
|
||||
|
@ -78,6 +273,28 @@ void Manager::FinishPlugins()
|
|||
init = false;
|
||||
}
|
||||
|
||||
int Manager::TryLoadFile(const char* file)
|
||||
{
|
||||
assert(file);
|
||||
const char* ext = strrchr(file, '.');
|
||||
|
||||
if ( ! ext )
|
||||
return -1;
|
||||
|
||||
extension_map::iterator i = extensions.find(++ext);
|
||||
if ( i == extensions.end() )
|
||||
return -1;
|
||||
|
||||
Plugin* plugin = i->second;
|
||||
|
||||
DBG_LOG(DBG_PLUGINS, "Loading %s with %s", file, plugin->Name());
|
||||
|
||||
if ( i->second->LoadFile(file) )
|
||||
return 1;
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
Manager::plugin_list Manager::Plugins() const
|
||||
{
|
||||
return *Manager::PluginsInternal();
|
||||
|
@ -92,3 +309,67 @@ Manager::plugin_list* Manager::PluginsInternal()
|
|||
|
||||
return plugins;
|
||||
}
|
||||
|
||||
Val* Manager::CallFunction(const Func* func, val_list* args) const
|
||||
{
|
||||
Val* result = 0;
|
||||
|
||||
for ( interpreter_plugin_list::const_iterator i = interpreter_plugins.begin();
|
||||
i != interpreter_plugins.end() && ! result; i++ )
|
||||
{
|
||||
result = (*i)->CallFunction(func, args);
|
||||
|
||||
if ( result )
|
||||
{
|
||||
DBG_LOG(DBG_PLUGINS, "Plugin %s replaced call to %s", (*i)->Name(), func->Name());
|
||||
return result;
|
||||
}
|
||||
}
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
bool Manager::QueueEvent(Event* event) const
|
||||
{
|
||||
for ( interpreter_plugin_list::const_iterator i = interpreter_plugins.begin();
|
||||
i != interpreter_plugins.end(); i++ )
|
||||
{
|
||||
if ( (*i)->QueueEvent(event) )
|
||||
{
|
||||
DBG_LOG(DBG_PLUGINS, "Plugin %s handled queueing of event %s", (*i)->Name(), event->Handler()->Name());
|
||||
return true;
|
||||
}
|
||||
}
|
||||
|
||||
return false;
|
||||
}
|
||||
|
||||
|
||||
void Manager::UpdateNetworkTime(double network_time) const
|
||||
{
|
||||
for ( interpreter_plugin_list::const_iterator i = interpreter_plugins.begin();
|
||||
i != interpreter_plugins.end(); i++ )
|
||||
(*i)->UpdateNetworkTime(network_time);
|
||||
}
|
||||
|
||||
void Manager::DrainEvents() const
|
||||
{
|
||||
for ( interpreter_plugin_list::const_iterator i = interpreter_plugins.begin();
|
||||
i != interpreter_plugins.end(); i++ )
|
||||
(*i)->DrainEvents();
|
||||
}
|
||||
|
||||
void Manager::DisableInterpreterPlugin(const InterpreterPlugin* plugin)
|
||||
{
|
||||
for ( interpreter_plugin_list::iterator i = interpreter_plugins.begin();
|
||||
i != interpreter_plugins.end(); i++ )
|
||||
{
|
||||
if ( *i == plugin )
|
||||
{
|
||||
interpreter_plugins.erase(i);
|
||||
return;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
|
|
|
@ -3,6 +3,8 @@
|
|||
#ifndef PLUGIN_MANAGER_H
|
||||
#define PLUGIN_MANAGER_H
|
||||
|
||||
#include <map>
|
||||
|
||||
#include "Plugin.h"
|
||||
#include "Component.h"
|
||||
|
||||
|
@ -17,6 +19,7 @@ class Manager
|
|||
{
|
||||
public:
|
||||
typedef std::list<Plugin*> plugin_list;
|
||||
typedef std::list<InterpreterPlugin*> interpreter_plugin_list;
|
||||
typedef Plugin::component_list component_list;
|
||||
|
||||
/**
|
||||
|
@ -30,24 +33,17 @@ public:
|
|||
~Manager();
|
||||
|
||||
/**
|
||||
* Loads a plugin dynamically from a file. This must be called only
|
||||
* before InitPluginsPreScript()
|
||||
* Loads all plugins dynamically from a set of directories. Multiple
|
||||
* directories are split by ':'. If a directory does not contain a
|
||||
* plugin itself, the method searches for plugins recursively. For
|
||||
* plugins found, the method loads the plugin's shared library and
|
||||
* makes its scripts available to the interpreter.
|
||||
*
|
||||
* This is not currently implemented.
|
||||
*
|
||||
* @param file The path to the plugin to load.
|
||||
*/
|
||||
bool LoadPlugin(const std::string& file);
|
||||
|
||||
/**
|
||||
* Loads plugins dynamically found in a directory. This must be
|
||||
* called only before InitPluginsPreScript().
|
||||
*
|
||||
* This is not currently implemented.
|
||||
* This must be called only before InitPluginsPreScript().
|
||||
*
|
||||
* @param dir The directory to search for plugins.
|
||||
*/
|
||||
bool LoadPluginsFrom(const std::string& dir);
|
||||
void LoadPluginsFrom(const std::string& dir);
|
||||
|
||||
/**
|
||||
* First-stage initializion of the manager. This is called early on
|
||||
|
@ -57,7 +53,13 @@ public:
|
|||
void InitPreScript();
|
||||
|
||||
/**
|
||||
* Second-stage initialization of the manager. This is called late
|
||||
* Second-stage initialization of the manager. This is called in
|
||||
* between pre- and post-script to make BiFs available.
|
||||
*/
|
||||
void InitBifs();
|
||||
|
||||
/**
|
||||
* Third-stage initialization of the manager. This is called late
|
||||
* during Bro's initialization after any scripts are processed, and
|
||||
* forwards to the corresponding Plugin methods.
|
||||
*/
|
||||
|
@ -69,6 +71,22 @@ public:
|
|||
*/
|
||||
void FinishPlugins();
|
||||
|
||||
/**
|
||||
* This tries to load the given file by searching for a plugin that
|
||||
* support that extension. If a correspondign plugin is found, it's
|
||||
* asked to loead the file. If that fails, the method reports an
|
||||
* error message.
|
||||
*
|
||||
* This method must be called only between InitPreScript() and
|
||||
* InitPostScript().
|
||||
*
|
||||
* @return 1 if the file was sucessfully loaded by a plugin; 0 if a
|
||||
* plugin was found that supports the file's extension, yet it
|
||||
* encountered a problem loading the file; and -1 if we don't have a
|
||||
* plugin that supports this extension.
|
||||
*/
|
||||
int TryLoadFile(const char* file);
|
||||
|
||||
/**
|
||||
* Returns a list of all available plugins. This includes all that
|
||||
* are compiled in statically, as well as those loaded dynamically so
|
||||
|
@ -83,6 +101,52 @@ public:
|
|||
*/
|
||||
template<class T> std::list<T *> Components() const;
|
||||
|
||||
/**
|
||||
* Filters a function/event/hook call through all interpreter plugins.
|
||||
*
|
||||
* @param func The function to be called.
|
||||
*
|
||||
* @param args The function call's arguments; they may be modified.
|
||||
*
|
||||
* @return If a plugin handled the call, a +1 Val with the result
|
||||
* value to pass back to the interpreter (for void functions and
|
||||
* events, it may be any Val and must be ignored). If no plugin
|
||||
* handled the call, the method returns null.
|
||||
*/
|
||||
Val* CallFunction(const Func* func, val_list* args) const;
|
||||
|
||||
/**
|
||||
* Filter the queuing of an event through all interpreter plugins.
|
||||
*
|
||||
* @param event The event to be queued; it may be modified.
|
||||
*
|
||||
* @return Returns true if a plugin handled the queuing; in that case the
|
||||
* plugin will have taken ownership.
|
||||
*
|
||||
*/
|
||||
bool QueueEvent(Event* event) const;
|
||||
|
||||
/**
|
||||
* Informs all interpreter plugins about an update in network time.
|
||||
*
|
||||
* @param networkt_time The new network time.
|
||||
*/
|
||||
void UpdateNetworkTime(double network_time) const;
|
||||
|
||||
/**
|
||||
* Informs all interpreter plugins that the event queue has been drained.
|
||||
*/
|
||||
void DrainEvents() const;
|
||||
|
||||
/**
|
||||
* Disables an interpreter plugin's hooking of the script interpreter.
|
||||
* The remaining functionality of the Plugin base class remains
|
||||
* available.
|
||||
*
|
||||
* @param plugin The plugin to disable.
|
||||
*/
|
||||
void DisableInterpreterPlugin(const InterpreterPlugin* plugin);
|
||||
|
||||
/**
|
||||
* Internal method that registers a freshly instantiated plugin with
|
||||
* the manager.
|
||||
|
@ -91,12 +155,38 @@ public:
|
|||
* ownership, yet assumes the pointer will stay valid at least until
|
||||
* the Manager is destroyed.
|
||||
*/
|
||||
static bool RegisterPlugin(Plugin *plugin);
|
||||
static bool RegisterPlugin(Plugin* plugin);
|
||||
|
||||
protected:
|
||||
/**
|
||||
* Loads a plugin dynamically from a given directory. It loads the
|
||||
* plugin's shared library, and makes its scripts available to the
|
||||
* interpreter. Different from LoadPluginsFrom() this method does not
|
||||
* further descend the directory tree recursively to search for
|
||||
* plugins.
|
||||
*
|
||||
* This must be called only before InitPluginsPreScript()
|
||||
*
|
||||
* @param file The path to the plugin to load.
|
||||
*
|
||||
* @return 0 if there's a plugin in this directory, but there was a
|
||||
* problem loading it; -1 if there's no plugin at all in this
|
||||
* directory; 1 if there's a plugin in this directory and we loaded
|
||||
* it successfully.
|
||||
*/
|
||||
int LoadPlugin(const std::string& dir);
|
||||
|
||||
private:
|
||||
static plugin_list* PluginsInternal();
|
||||
|
||||
bool init;
|
||||
typedef std::map<std::string, Plugin*> extension_map;
|
||||
extension_map extensions;
|
||||
|
||||
interpreter_plugin_list interpreter_plugins;
|
||||
|
||||
static string current_dir;
|
||||
static string current_sopath;
|
||||
};
|
||||
|
||||
template<class T>
|
||||
|
|
|
@ -10,9 +10,9 @@
|
|||
|
||||
using namespace plugin;
|
||||
|
||||
BifItem::BifItem(const std::string& arg_id, Type arg_type)
|
||||
BifItem::BifItem(const char* arg_id, Type arg_type)
|
||||
{
|
||||
id = copy_string(arg_id.c_str());
|
||||
id = copy_string(arg_id);
|
||||
type = arg_type;
|
||||
}
|
||||
|
||||
|
@ -47,6 +47,9 @@ Plugin::Plugin()
|
|||
version = -9999;
|
||||
api_version = -9999;
|
||||
dynamic = false;
|
||||
base_dir = 0;
|
||||
sopath = 0;
|
||||
extensions = 0;
|
||||
|
||||
Manager::RegisterPlugin(this);
|
||||
}
|
||||
|
@ -57,6 +60,14 @@ Plugin::~Plugin()
|
|||
|
||||
delete [] name;
|
||||
delete [] description;
|
||||
delete [] base_dir;
|
||||
delete [] sopath;
|
||||
delete [] extensions;
|
||||
}
|
||||
|
||||
Plugin::Type Plugin::PluginType() const
|
||||
{
|
||||
return STANDARD;
|
||||
}
|
||||
|
||||
const char* Plugin::Name() const
|
||||
|
@ -66,6 +77,7 @@ const char* Plugin::Name() const
|
|||
|
||||
void Plugin::SetName(const char* arg_name)
|
||||
{
|
||||
delete [] name;
|
||||
name = copy_string(arg_name);
|
||||
}
|
||||
|
||||
|
@ -76,6 +88,7 @@ const char* Plugin::Description() const
|
|||
|
||||
void Plugin::SetDescription(const char* arg_description)
|
||||
{
|
||||
delete [] description;
|
||||
description = copy_string(arg_description);
|
||||
}
|
||||
|
||||
|
@ -99,6 +112,16 @@ bool Plugin::DynamicPlugin() const
|
|||
return dynamic;
|
||||
}
|
||||
|
||||
const char* Plugin::PluginDirectory() const
|
||||
{
|
||||
return base_dir;
|
||||
}
|
||||
|
||||
const char* Plugin::PluginPath() const
|
||||
{
|
||||
return sopath;
|
||||
}
|
||||
|
||||
void Plugin::SetAPIVersion(int arg_version)
|
||||
{
|
||||
api_version = arg_version;
|
||||
|
@ -109,22 +132,26 @@ void Plugin::SetDynamicPlugin(bool arg_dynamic)
|
|||
dynamic = arg_dynamic;
|
||||
}
|
||||
|
||||
void Plugin::SetPluginLocation(const char* arg_dir, const char* arg_sopath)
|
||||
{
|
||||
delete [] base_dir;
|
||||
delete [] sopath;
|
||||
base_dir = copy_string(arg_dir);
|
||||
sopath = copy_string(arg_sopath);
|
||||
}
|
||||
|
||||
void Plugin::InitPreScript()
|
||||
{
|
||||
}
|
||||
|
||||
void Plugin::InitPostScript()
|
||||
{
|
||||
for ( bif_init_func_list::const_iterator f = bif_inits.begin(); f != bif_inits.end(); f++ )
|
||||
{
|
||||
bif_init_func_result items = (**f)();
|
||||
}
|
||||
|
||||
for ( bif_init_func_result::const_iterator i = items.begin(); i != items.end(); i++ )
|
||||
void Plugin::InitBifs()
|
||||
{
|
||||
BifItem bi((*i).first, (BifItem::Type)(*i).second);
|
||||
bif_items.push_back(bi);
|
||||
}
|
||||
}
|
||||
for ( bif_init_func_list::const_iterator f = bif_inits.begin(); f != bif_inits.end(); f++ )
|
||||
(**f)(this);
|
||||
}
|
||||
|
||||
Plugin::bif_item_list Plugin::BifItems() const
|
||||
|
@ -143,6 +170,22 @@ Plugin::bif_item_list Plugin::CustomBifItems() const
|
|||
return bif_item_list();
|
||||
}
|
||||
|
||||
const char* Plugin::FileExtensions() const
|
||||
{
|
||||
return extensions ? extensions : "";
|
||||
}
|
||||
|
||||
void Plugin::SetFileExtensions(const char* ext)
|
||||
{
|
||||
extensions = copy_string(ext);
|
||||
}
|
||||
|
||||
bool Plugin::LoadFile(const char* file)
|
||||
{
|
||||
reporter->InternalError("Plugin::LoadFile not overriden for %s", file);
|
||||
return false;
|
||||
}
|
||||
|
||||
void Plugin::Done()
|
||||
{
|
||||
for ( component_list::const_iterator i = components.begin(); i != components.end(); i++ )
|
||||
|
@ -170,11 +213,23 @@ void Plugin::AddComponent(Component* c)
|
|||
components.sort(component_cmp);
|
||||
}
|
||||
|
||||
void Plugin::AddBifInitFunction(bif_init_func c)
|
||||
bool Plugin::LoadBroFile(const char* file)
|
||||
{
|
||||
add_input_file(file);
|
||||
return true;
|
||||
}
|
||||
|
||||
void Plugin::__AddBifInitFunction(bif_init_func c)
|
||||
{
|
||||
bif_inits.push_back(c);
|
||||
}
|
||||
|
||||
void Plugin::AddBifItem(const char* name, BifItem::Type type)
|
||||
{
|
||||
BifItem bi(name, (BifItem::Type)type);
|
||||
bif_items.push_back(bi);
|
||||
}
|
||||
|
||||
void Plugin::Describe(ODesc* d) const
|
||||
{
|
||||
d->Add("Plugin: ");
|
||||
|
@ -190,7 +245,7 @@ void Plugin::Describe(ODesc* d) const
|
|||
{
|
||||
if ( version > 0 )
|
||||
{
|
||||
d->Add(" (version ");
|
||||
d->Add(" (dynamic, version ");
|
||||
d->Add(version);
|
||||
d->Add(")");
|
||||
}
|
||||
|
@ -201,6 +256,18 @@ void Plugin::Describe(ODesc* d) const
|
|||
else
|
||||
d->Add(" (built-in)");
|
||||
|
||||
switch ( PluginType() ) {
|
||||
case STANDARD:
|
||||
break;
|
||||
|
||||
case INTERPRETER:
|
||||
d->Add( " (interpreter plugin)");
|
||||
break;
|
||||
|
||||
default:
|
||||
reporter->InternalError("unknown plugin type in Plugin::Describe");
|
||||
}
|
||||
|
||||
d->Add("\n");
|
||||
|
||||
if ( d->IsShort() )
|
||||
|
@ -252,4 +319,46 @@ void Plugin::Describe(ODesc* d) const
|
|||
}
|
||||
}
|
||||
|
||||
InterpreterPlugin::InterpreterPlugin(int arg_priority)
|
||||
{
|
||||
priority = arg_priority;
|
||||
}
|
||||
|
||||
InterpreterPlugin::~InterpreterPlugin()
|
||||
{
|
||||
}
|
||||
|
||||
int InterpreterPlugin::Priority() const
|
||||
{
|
||||
return priority;
|
||||
}
|
||||
|
||||
Plugin::Type InterpreterPlugin::PluginType() const
|
||||
{
|
||||
return INTERPRETER;
|
||||
}
|
||||
|
||||
Val* InterpreterPlugin::CallFunction(const Func* func, val_list* args)
|
||||
{
|
||||
return 0;
|
||||
}
|
||||
|
||||
bool InterpreterPlugin::QueueEvent(Event* event)
|
||||
{
|
||||
return false;
|
||||
}
|
||||
|
||||
void InterpreterPlugin::UpdateNetworkTime(double network_time)
|
||||
{
|
||||
}
|
||||
|
||||
void InterpreterPlugin::DrainEvents()
|
||||
{
|
||||
}
|
||||
|
||||
void InterpreterPlugin::DisableInterpreterPlugin() const
|
||||
{
|
||||
plugin_mgr->DisableInterpreterPlugin(this);
|
||||
}
|
||||
|
||||
|
||||
|
|
|
@ -9,6 +9,8 @@
|
|||
#include "Macros.h"
|
||||
|
||||
class ODesc;
|
||||
class Func;
|
||||
class Event;
|
||||
|
||||
namespace plugin {
|
||||
|
||||
|
@ -22,8 +24,6 @@ class BifItem {
|
|||
public:
|
||||
/**
|
||||
* Type of the item.
|
||||
*
|
||||
* The values here must match the integers that \c bifcl generated.
|
||||
*/
|
||||
enum Type { FUNCTION = 1, EVENT = 2, CONSTANT = 3, GLOBAL = 4, TYPE = 5 };
|
||||
|
||||
|
@ -35,7 +35,7 @@ public:
|
|||
*
|
||||
* @param type The type of the item.
|
||||
*/
|
||||
BifItem(const std::string& id, Type type);
|
||||
BifItem(const char* id, Type type);
|
||||
|
||||
/**
|
||||
* Copy constructor.
|
||||
|
@ -88,6 +88,26 @@ class Plugin {
|
|||
public:
|
||||
typedef std::list<Component *> component_list;
|
||||
typedef std::list<BifItem> bif_item_list;
|
||||
typedef std::list<std::pair<const char*, int> > bif_init_func_result;
|
||||
typedef void (*bif_init_func)(Plugin *);
|
||||
|
||||
/**
|
||||
* Type of a plugin. Plugin types are set implicitly by deriving from
|
||||
* the corresponding base class. */
|
||||
enum Type {
|
||||
/**
|
||||
* A standard plugin. This is the type for all plugins
|
||||
* derived directly from \a Plugin. */
|
||||
STANDARD,
|
||||
|
||||
/**
|
||||
* An interpreter plugin. These plugins get hooked into the
|
||||
* script interpreter and can modify, or even replace, its
|
||||
* execution of Bro script code. To create an interpreter
|
||||
* plugin, derive from \aInterpreterPlugin.
|
||||
*/
|
||||
INTERPRETER
|
||||
};
|
||||
|
||||
/**
|
||||
* Constructor.
|
||||
|
@ -99,6 +119,11 @@ public:
|
|||
*/
|
||||
virtual ~Plugin();
|
||||
|
||||
/**
|
||||
* Returns the type of the plugin.
|
||||
*/
|
||||
virtual Type PluginType() const;
|
||||
|
||||
/**
|
||||
* Returns the name of the plugin.
|
||||
*/
|
||||
|
@ -121,6 +146,23 @@ public:
|
|||
*/
|
||||
bool DynamicPlugin() const;
|
||||
|
||||
/**
|
||||
* Returns a colon-separated list of file extensions the plugin handles.
|
||||
*/
|
||||
const char* FileExtensions() const;
|
||||
|
||||
/**
|
||||
* For dynamic plugins, returns the base directory from which it was
|
||||
* loaded. For static plugins, returns null.
|
||||
**/
|
||||
const char* PluginDirectory() const;
|
||||
|
||||
/**
|
||||
* For dynamic plugins, returns the full path to the shared library
|
||||
* from which it was loaded. For static plugins, returns null.
|
||||
**/
|
||||
const char* PluginPath() const;
|
||||
|
||||
/**
|
||||
* Returns the internal API version that this plugin relies on. Only
|
||||
* plugins that match Bro's current API version may be used. For
|
||||
|
@ -173,9 +215,38 @@ public:
|
|||
*/
|
||||
void Describe(ODesc* d) const;
|
||||
|
||||
/**
|
||||
* Registering an individual BiF that the plugin defines. The
|
||||
* information is for informational purpuses only and will show up in
|
||||
* the result of BifItems() as well as in the Describe() output.
|
||||
* Another way to add this information is via overriding
|
||||
* CustomBifItems().
|
||||
*
|
||||
* @param name The name of the BiF item.
|
||||
*
|
||||
* @param type The item's type.
|
||||
*/
|
||||
void AddBifItem(const char* name, BifItem::Type type);
|
||||
|
||||
/**
|
||||
* Adds a file to the list of files Bro loads at startup. This will
|
||||
* normally be a Bro script, but it passes through the plugin system
|
||||
* as well to load files with other extensions as supported by any of
|
||||
* the current plugins. In other words, calling this method is
|
||||
* similar to given a file on the command line. Note that the file
|
||||
* may be only queued for now, and actually loaded later.
|
||||
*
|
||||
* This method must not be called after InitPostScript().
|
||||
*
|
||||
* @param file The file to load. It will be searched along the standard paths.
|
||||
*
|
||||
* @return True if successful (which however may only mean
|
||||
* "successfully queued").
|
||||
*/
|
||||
bool LoadBroFile(const char* file);
|
||||
|
||||
protected:
|
||||
typedef std::list<std::pair<const char*, int> > bif_init_func_result;
|
||||
typedef bif_init_func_result (*bif_init_func)();
|
||||
friend class Manager;
|
||||
|
||||
/**
|
||||
* Sets the plugins name.
|
||||
|
@ -212,6 +283,28 @@ protected:
|
|||
*/
|
||||
void SetDynamicPlugin(bool dynamic);
|
||||
|
||||
/**
|
||||
* Reports the extensions of input files the plugin handles. If Bro
|
||||
* wants to load a file with one of these extensions it will pass
|
||||
* them to LoadFile() and then then ignore otherwise.
|
||||
*
|
||||
* ext: A list of colon-separated file extensions the plugin handles.
|
||||
*/
|
||||
void SetFileExtensions(const char* ext);
|
||||
|
||||
/**
|
||||
* Sets the base directory and shared library path from which the
|
||||
* plugin was loaded. This should be called only from the manager for
|
||||
* dynamic plugins.
|
||||
*
|
||||
* @param dir The plugin directory. The functions makes an internal
|
||||
* copy of string.
|
||||
*
|
||||
* @param sopath The full path the shared library loaded. The
|
||||
* functions makes an internal copy of string.
|
||||
*/
|
||||
void SetPluginLocation(const char* dir, const char* sopath);
|
||||
|
||||
/**
|
||||
* Takes ownership.
|
||||
*/
|
||||
|
@ -227,17 +320,41 @@ protected:
|
|||
*/
|
||||
virtual bif_item_list CustomBifItems() const;
|
||||
|
||||
/**
|
||||
* Virtual method that can be overriden by derived class to load
|
||||
* files with extensions reported via SetFileExtension().
|
||||
*
|
||||
* This method will be called between InitPreScript() and
|
||||
* InitPostScript(), but with no further order or timing guaranteed.
|
||||
* It will be called once for each file encountered with of the
|
||||
* specificed extensions (i.e., duplicates are filtered out
|
||||
* automatically).
|
||||
*
|
||||
* @return True if the file was loaded successfuly, false if not. Bro
|
||||
* will abort in the latter case.
|
||||
*/
|
||||
virtual bool LoadFile(const char* file);
|
||||
|
||||
/**
|
||||
* Initializes the BiF items added with AddBifItem(). Internal method
|
||||
* that will be called by the manager at the right time.
|
||||
*/
|
||||
void InitBifs();
|
||||
|
||||
/**
|
||||
* Internal function adding an entry point for registering
|
||||
* auto-generated BiFs.
|
||||
*/
|
||||
void AddBifInitFunction(bif_init_func c);
|
||||
void __AddBifInitFunction(bif_init_func c);
|
||||
|
||||
private:
|
||||
typedef std::list<bif_init_func> bif_init_func_list;
|
||||
|
||||
const char* name;
|
||||
const char* description;
|
||||
const char* base_dir;
|
||||
const char* sopath;
|
||||
const char* extensions;
|
||||
int version;
|
||||
int api_version;
|
||||
bool dynamic;
|
||||
|
@ -247,6 +364,105 @@ private:
|
|||
bif_init_func_list bif_inits;
|
||||
};
|
||||
|
||||
/**
|
||||
* Class for hooking into script execution. An interpreter plugin can do
|
||||
* everything a normal plugin can, yet will also be interfaced to the script
|
||||
* interpreter for learning about, modidying, or potentially replacing
|
||||
* standard functionality.
|
||||
*/
|
||||
class InterpreterPlugin : public Plugin {
|
||||
public:
|
||||
/**
|
||||
* Constructor.
|
||||
*
|
||||
* @param priority Imposes an order on InterpreterPlugins in which
|
||||
* they'll be chained. The higher the prioritu, the earlier a plugin
|
||||
* is called when the interpreter goes through the chain. */
|
||||
InterpreterPlugin(int priority);
|
||||
|
||||
/**
|
||||
* Destructor.
|
||||
*/
|
||||
virtual ~InterpreterPlugin();
|
||||
|
||||
/**
|
||||
* Returns the plugins priority.
|
||||
*/
|
||||
int Priority() const;
|
||||
|
||||
/**
|
||||
* Callback for executing a function/event/hook. Whenever the script
|
||||
* interpreter is about to execution a function, it first gives all
|
||||
* InterpreterPlugins a chance to handle the call (in the order of their
|
||||
* priorities). A plugin can either just inspect the call, or replace it
|
||||
* (i.e., prevent the interpreter from executing it). In the latter case
|
||||
* it must provide a matching return value.
|
||||
*
|
||||
* The default implementation does never handle the call in any way.
|
||||
*
|
||||
* @param func The function being called.
|
||||
*
|
||||
* @param args The function arguments. The method can modify the list
|
||||
* in place long as it ensures matching types and correct reference
|
||||
* counting.
|
||||
*
|
||||
* @return If the plugin handled the call, a +1 Val with the result
|
||||
* value to pass back to the interpreter (for void functions and
|
||||
* events any \a Val is fine; it will be ignored; best to use a \c
|
||||
* TYPE_ANY). If the plugin did not handle the call, it must return
|
||||
* null.
|
||||
*/
|
||||
virtual Val* CallFunction(const Func* func, val_list* args);
|
||||
|
||||
/**
|
||||
* Callback for raising an event. Whenever the script interpreter is
|
||||
* about to queue an event for later execution, it first gives all
|
||||
* InterpreterPlugins a chance to handle the queuing otherwise (in the
|
||||
* order of their priorities). A plugin can either just inspect the
|
||||
* event, or take it over (i.e., prevent the interpreter from queuing it
|
||||
* it).
|
||||
*
|
||||
* The default implementation does never handle the queuing in any way.
|
||||
*
|
||||
* @param event The even to be queued. The method can modify it in in
|
||||
* place long as it ensures matching types and correct reference
|
||||
* counting.
|
||||
*
|
||||
* @return True if the plugin took charge of the event; in that case it
|
||||
* must have assumed ownership of the event and the intpreter will not do
|
||||
* anything further with it. False otherwise.
|
||||
*
|
||||
*/
|
||||
virtual bool QueueEvent(Event* event);
|
||||
|
||||
/**
|
||||
* Callback for updates in network time. This method will be called
|
||||
* whenever network time is advanced.
|
||||
*
|
||||
* @param networkt_time The new network time.
|
||||
*/
|
||||
virtual void UpdateNetworkTime(double network_time);
|
||||
|
||||
/**
|
||||
* Callback for event queue draining. This method will be called
|
||||
* whenever the event manager has drained it queue.
|
||||
*/
|
||||
virtual void DrainEvents();
|
||||
|
||||
/**
|
||||
* Disables interpreter hooking. The functionality of the Plugin base
|
||||
* class remains available.
|
||||
*/
|
||||
void DisableInterpreterPlugin() const;
|
||||
|
||||
// Overridden from base class.
|
||||
virtual Type PluginType() const;
|
||||
|
||||
private:
|
||||
int priority;
|
||||
|
||||
};
|
||||
|
||||
}
|
||||
|
||||
#endif
|
||||
|
|
20
src/scan.l
20
src/scan.l
|
@ -30,6 +30,8 @@
|
|||
|
||||
#include "analyzer/Analyzer.h"
|
||||
|
||||
#include "plugin/Manager.h"
|
||||
|
||||
extern YYLTYPE yylloc; // holds start line and column of token
|
||||
extern int print_loaded_scripts;
|
||||
extern int generate_documentation;
|
||||
|
@ -579,6 +581,24 @@ YYLTYPE GetCurrentLocation()
|
|||
|
||||
static int load_files(const char* orig_file)
|
||||
{
|
||||
int rc = plugin_mgr->TryLoadFile(orig_file);
|
||||
|
||||
if ( rc == 1 )
|
||||
return 0; // A plugin took care of it, just skip.
|
||||
|
||||
if ( rc == 0 )
|
||||
{
|
||||
if ( ! reporter->Errors() )
|
||||
// This is just in case the plugin failed to report
|
||||
// the error itself, in which case we want to at
|
||||
// least tell the user that something went wrong.
|
||||
reporter->Error("Plugin reported error loading %s", orig_file);
|
||||
|
||||
exit(1);
|
||||
}
|
||||
|
||||
assert(rc == -1); // No plugin in charge of this file.
|
||||
|
||||
// Whether we pushed on a FileInfo that will restore the
|
||||
// current module after the final file has been scanned.
|
||||
bool did_module_restore = false;
|
||||
|
|
|
@ -3,3 +3,4 @@
|
|||
#define BRO_BUILD_SOURCE_PATH "@CMAKE_BINARY_DIR@/src"
|
||||
#define BRO_BUILD_SCRIPTS_PATH "@CMAKE_BINARY_DIR@/scripts"
|
||||
#define BRO_MAGIC_INSTALL_PATH "@BRO_MAGIC_INSTALL_PATH@"
|
||||
#define BRO_PLUGIN_INSTALL_PATH "@BRO_PLUGIN_INSTALL_PATH@"
|
||||
|
|
81
src/util.cc
81
src/util.cc
|
@ -619,13 +619,13 @@ bool ensure_dir(const char *dirname)
|
|||
return true;
|
||||
}
|
||||
|
||||
bool is_dir(const char* path)
|
||||
bool is_dir(const std::string& path)
|
||||
{
|
||||
struct stat st;
|
||||
if ( stat(path, &st) < 0 )
|
||||
if ( stat(path.c_str(), &st) < 0 )
|
||||
{
|
||||
if ( errno != ENOENT )
|
||||
reporter->Warning("can't stat %s: %s", path, strerror(errno));
|
||||
reporter->Warning("can't stat %s: %s", path.c_str(), strerror(errno));
|
||||
|
||||
return false;
|
||||
}
|
||||
|
@ -633,6 +633,37 @@ bool is_dir(const char* path)
|
|||
return S_ISDIR(st.st_mode);
|
||||
}
|
||||
|
||||
bool is_file(const std::string& path)
|
||||
{
|
||||
struct stat st;
|
||||
if ( stat(path.c_str(), &st) < 0 )
|
||||
{
|
||||
if ( errno != ENOENT )
|
||||
reporter->Warning("can't stat %s: %s", path.c_str(), strerror(errno));
|
||||
|
||||
return false;
|
||||
}
|
||||
|
||||
return S_ISREG(st.st_mode);
|
||||
}
|
||||
|
||||
string strreplace(const string& s, const string& o, const string& n)
|
||||
{
|
||||
string r = s;
|
||||
|
||||
while ( true )
|
||||
{
|
||||
size_t i = r.find(o);
|
||||
|
||||
if ( i == std::string::npos )
|
||||
break;
|
||||
|
||||
r.replace(i, o.size(), n);
|
||||
}
|
||||
|
||||
return r;
|
||||
}
|
||||
|
||||
int hmac_key_set = 0;
|
||||
uint8 shared_hmac_md5_key[16];
|
||||
|
||||
|
@ -872,7 +903,11 @@ int int_list_cmp(const void* v1, const void* v2)
|
|||
return 1;
|
||||
}
|
||||
|
||||
const char* bro_path()
|
||||
static string bro_path_value;
|
||||
|
||||
const std::string& bro_path()
|
||||
{
|
||||
if ( bro_path_value.empty() )
|
||||
{
|
||||
const char* path = getenv("BROPATH");
|
||||
if ( ! path )
|
||||
|
@ -881,7 +916,18 @@ const char* bro_path()
|
|||
BRO_SCRIPT_INSTALL_PATH "/policy" ":"
|
||||
BRO_SCRIPT_INSTALL_PATH "/site";
|
||||
|
||||
return path;
|
||||
bro_path_value = path;
|
||||
}
|
||||
|
||||
return bro_path_value;
|
||||
}
|
||||
|
||||
extern void add_to_bro_path(const string& dir)
|
||||
{
|
||||
// Make sure path is initialized.
|
||||
bro_path();
|
||||
|
||||
bro_path_value += string(":") + dir;
|
||||
}
|
||||
|
||||
const char* bro_magic_path()
|
||||
|
@ -894,6 +940,16 @@ const char* bro_magic_path()
|
|||
return path;
|
||||
}
|
||||
|
||||
const char* bro_plugin_path()
|
||||
{
|
||||
const char* path = getenv("BRO_PLUGINS");
|
||||
|
||||
if ( ! path )
|
||||
path = BRO_PLUGIN_INSTALL_PATH;
|
||||
|
||||
return path;
|
||||
}
|
||||
|
||||
string bro_prefixes()
|
||||
{
|
||||
string rval;
|
||||
|
@ -1089,9 +1145,9 @@ FILE* search_for_file(const char* filename, const char* ext,
|
|||
// @loads can be referenced relatively.
|
||||
if ( current_scanned_file_path != "" && filename[0] == '.' )
|
||||
safe_snprintf(path, sizeof(path), "%s:%s",
|
||||
current_scanned_file_path.c_str(), bro_path());
|
||||
current_scanned_file_path.c_str(), bro_path().c_str());
|
||||
else
|
||||
safe_strncpy(path, bro_path(), sizeof(path));
|
||||
safe_strncpy(path, bro_path().c_str(), sizeof(path));
|
||||
|
||||
char* dir_beginning = path;
|
||||
char* dir_ending = path;
|
||||
|
@ -1505,25 +1561,16 @@ void get_memory_usage(unsigned int* total, unsigned int* malloced)
|
|||
if ( malloced )
|
||||
*malloced = mi.uordblks;
|
||||
|
||||
ret_total = mi.arena;
|
||||
#endif
|
||||
|
||||
if ( total )
|
||||
*total = ret_total;
|
||||
#else
|
||||
struct rusage r;
|
||||
getrusage(RUSAGE_SELF, &r);
|
||||
|
||||
if ( malloced )
|
||||
*malloced = 0;
|
||||
|
||||
// At least on FreeBSD it's in KB.
|
||||
ret_total = r.ru_maxrss * 1024;
|
||||
|
||||
if ( total )
|
||||
*total = ret_total;
|
||||
#endif
|
||||
|
||||
// return ret_total;
|
||||
}
|
||||
|
||||
#ifdef malloc
|
||||
|
|
15
src/util.h
15
src/util.h
|
@ -147,7 +147,13 @@ extern const char* fmt_access_time(double time);
|
|||
extern bool ensure_dir(const char *dirname);
|
||||
|
||||
// Returns true if path exists and is a directory.
|
||||
bool is_dir(const char* path);
|
||||
bool is_dir(const std::string& path);
|
||||
|
||||
// Returns true if path exists and is a file.
|
||||
bool is_file(const std::string& path);
|
||||
|
||||
// Replaces all occurences of *o* in *s* with *n*.
|
||||
extern std::string strreplace(const std::string& s, const std::string& o, const std::string& n);
|
||||
|
||||
extern uint8 shared_hmac_md5_key[16];
|
||||
|
||||
|
@ -202,9 +208,12 @@ static const SourceID SOURCE_LOCAL = 0;
|
|||
extern void pinpoint();
|
||||
extern int int_list_cmp(const void* v1, const void* v2);
|
||||
|
||||
extern const char* bro_path();
|
||||
extern const std::string& bro_path();
|
||||
extern void add_to_bro_path(const std::string& dir);
|
||||
|
||||
extern const char* bro_magic_path();
|
||||
extern std::string bro_prefixes();
|
||||
extern const char* bro_plugin_path();
|
||||
extern const char* bro_prefixes();
|
||||
std::string dot_canon(std::string path, std::string file, std::string prefix = "");
|
||||
const char* normalize_path(const char* path);
|
||||
void get_script_subpath(const std::string& full_filename, const char** subpath);
|
||||
|
|
6
testing/btest/Baseline/core.plugins.analyzer/output
Normal file
6
testing/btest/Baseline/core.plugins.analyzer/output
Normal file
|
@ -0,0 +1,6 @@
|
|||
Plugin: Demo::Foo - A Foo test analyzer (dynamic, version 1)
|
||||
[Analyzer] Foo (ANALYZER_FOO, enabled)
|
||||
[Event] foo_message
|
||||
|
||||
===
|
||||
foo_message, [orig_h=::1, orig_p=37927/tcp, resp_h=::1, resp_p=4242/tcp], Hello, Foo!^J
|
11
testing/btest/Baseline/core.plugins.test-plugin/output
Normal file
11
testing/btest/Baseline/core.plugins.test-plugin/output
Normal file
|
@ -0,0 +1,11 @@
|
|||
Plugin: Demo::Foo - <Insert brief description of plugin> (dynamic, version 1)
|
||||
[Event] plugin_event
|
||||
[Function] hello_plugin_world
|
||||
|
||||
===
|
||||
plugin: automatically loaded at startup
|
||||
calling bif, Hello from the plugin!
|
||||
===
|
||||
plugin: automatically loaded at startup
|
||||
calling bif, Hello from the plugin!
|
||||
plugin: manually loaded
|
BIN
testing/btest/Traces/port4242.trace
Normal file
BIN
testing/btest/Traces/port4242.trace
Normal file
Binary file not shown.
0
testing/btest/core/plugins/analyzer-plugin/.btest-ignore
Normal file
0
testing/btest/core/plugins/analyzer-plugin/.btest-ignore
Normal file
20
testing/btest/core/plugins/analyzer-plugin/CMakeLists.txt
Normal file
20
testing/btest/core/plugins/analyzer-plugin/CMakeLists.txt
Normal file
|
@ -0,0 +1,20 @@
|
|||
|
||||
project(Bro-Plugin-Demo-Foo)
|
||||
|
||||
cmake_minimum_required(VERSION 2.6.3)
|
||||
|
||||
if ( NOT BRO_DIST )
|
||||
message(FATAL_ERROR "BRO_DIST not set")
|
||||
endif ()
|
||||
|
||||
set(CMAKE_MODULE_PATH ${BRO_DIST}/cmake)
|
||||
|
||||
include(BroPlugin)
|
||||
|
||||
bro_plugin_begin(Demo Foo)
|
||||
bro_plugin_cc(src/Plugin.cc)
|
||||
bro_plugin_cc(src/Foo.cc)
|
||||
bro_plugin_bif(src/events.bif)
|
||||
bro_plugin_bif(src/functions.bif)
|
||||
bro_plugin_pac(src/foo.pac src/foo-protocol.pac src/foo-analyzer.pac)
|
||||
bro_plugin_end()
|
|
@ -0,0 +1,2 @@
|
|||
A place-holder file that marks a directory as holding a Bro plugin.
|
||||
Content is ignored.
|
|
@ -0,0 +1,7 @@
|
|||
|
||||
const ports = { 4242/tcp };
|
||||
|
||||
event bro_init() &priority=5
|
||||
{
|
||||
Analyzer::register_for_ports(Analyzer::ANALYZER_FOO, ports);
|
||||
}
|
|
@ -0,0 +1 @@
|
|||
@load Demo/Foo/base/main
|
59
testing/btest/core/plugins/analyzer-plugin/src/Foo.cc
Normal file
59
testing/btest/core/plugins/analyzer-plugin/src/Foo.cc
Normal file
|
@ -0,0 +1,59 @@
|
|||
|
||||
#include "Foo.h"
|
||||
#include "foo_pac.h"
|
||||
#include "events.bif.h"
|
||||
|
||||
#include <analyzer/protocol/tcp/TCP_Reassembler.h>
|
||||
|
||||
using namespace analyzer::Foo;
|
||||
|
||||
Foo_Analyzer::Foo_Analyzer(Connection* conn)
|
||||
: tcp::TCP_ApplicationAnalyzer("Foo", conn)
|
||||
{
|
||||
interp = new binpac::Foo::Foo_Conn(this);
|
||||
}
|
||||
|
||||
Foo_Analyzer::~Foo_Analyzer()
|
||||
{
|
||||
delete interp;
|
||||
}
|
||||
|
||||
void Foo_Analyzer::Done()
|
||||
{
|
||||
tcp::TCP_ApplicationAnalyzer::Done();
|
||||
|
||||
interp->FlowEOF(true);
|
||||
interp->FlowEOF(false);
|
||||
}
|
||||
|
||||
void Foo_Analyzer::EndpointEOF(bool is_orig)
|
||||
{
|
||||
tcp::TCP_ApplicationAnalyzer::EndpointEOF(is_orig);
|
||||
interp->FlowEOF(is_orig);
|
||||
}
|
||||
|
||||
void Foo_Analyzer::DeliverStream(int len, const u_char* data, bool orig)
|
||||
{
|
||||
tcp::TCP_ApplicationAnalyzer::DeliverStream(len, data, orig);
|
||||
|
||||
assert(TCP());
|
||||
|
||||
if ( TCP()->IsPartial() )
|
||||
// punt on partial.
|
||||
return;
|
||||
|
||||
try
|
||||
{
|
||||
interp->NewData(orig, data, data + len);
|
||||
}
|
||||
catch ( const binpac::Exception& e )
|
||||
{
|
||||
ProtocolViolation(fmt("Binpac exception: %s", e.c_msg()));
|
||||
}
|
||||
}
|
||||
|
||||
void Foo_Analyzer::Undelivered(int seq, int len, bool orig)
|
||||
{
|
||||
tcp::TCP_ApplicationAnalyzer::Undelivered(seq, len, orig);
|
||||
interp->NewGap(orig, len);
|
||||
}
|
31
testing/btest/core/plugins/analyzer-plugin/src/Foo.h
Normal file
31
testing/btest/core/plugins/analyzer-plugin/src/Foo.h
Normal file
|
@ -0,0 +1,31 @@
|
|||
|
||||
#ifndef BRO_PLUGIN_DEMO_FOO_H
|
||||
#define BRO_PLUGIN_DEMO_FOO_H
|
||||
|
||||
#include "analyzer/protocol/tcp/TCP.h"
|
||||
#include "analyzer/protocol/pia/PIA.h"
|
||||
|
||||
namespace binpac { namespace Foo { class Foo_Conn; } }
|
||||
|
||||
namespace analyzer { namespace Foo {
|
||||
|
||||
class Foo_Analyzer : public tcp::TCP_ApplicationAnalyzer {
|
||||
public:
|
||||
Foo_Analyzer(Connection* conn);
|
||||
~Foo_Analyzer();
|
||||
|
||||
virtual void Done();
|
||||
virtual void DeliverStream(int len, const u_char* data, bool orig);
|
||||
virtual void Undelivered(int seq, int len, bool orig);
|
||||
virtual void EndpointEOF(bool is_orig);
|
||||
|
||||
static analyzer::Analyzer* InstantiateAnalyzer(Connection* conn)
|
||||
{ return new Foo_Analyzer(conn); }
|
||||
|
||||
protected:
|
||||
binpac::Foo::Foo_Conn* interp;
|
||||
};
|
||||
|
||||
} } // namespace analyzer::*
|
||||
|
||||
#endif
|
12
testing/btest/core/plugins/analyzer-plugin/src/Plugin.cc
Normal file
12
testing/btest/core/plugins/analyzer-plugin/src/Plugin.cc
Normal file
|
@ -0,0 +1,12 @@
|
|||
|
||||
#include <plugin/Plugin.h>
|
||||
|
||||
#include "Foo.h"
|
||||
|
||||
BRO_PLUGIN_BEGIN(Demo, Foo)
|
||||
BRO_PLUGIN_VERSION(1);
|
||||
BRO_PLUGIN_DESCRIPTION("A Foo test analyzer");
|
||||
BRO_PLUGIN_ANALYZER("Foo", Foo::Foo_Analyzer);
|
||||
BRO_PLUGIN_BIF_FILE(events);
|
||||
BRO_PLUGIN_BIF_FILE(functions);
|
||||
BRO_PLUGIN_END
|
|
@ -0,0 +1,2 @@
|
|||
|
||||
event foo_message%(c: connection, data: string%);
|
|
@ -0,0 +1,15 @@
|
|||
|
||||
refine connection Foo_Conn += {
|
||||
|
||||
function Foo_data(msg: Foo_Message): bool
|
||||
%{
|
||||
StringVal* data = new StringVal(${msg.data}.length(), (const char*) ${msg.data}.data());
|
||||
BifEvent::generate_foo_message(bro_analyzer(), bro_analyzer()->Conn(), data);
|
||||
return true;
|
||||
%}
|
||||
|
||||
};
|
||||
|
||||
refine typeattr Foo_Message += &let {
|
||||
proc: bool = $context.connection.Foo_data(this);
|
||||
};
|
|
@ -0,0 +1,4 @@
|
|||
|
||||
type Foo_Message(is_orig: bool) = record {
|
||||
data: bytestring &restofdata;
|
||||
};
|
26
testing/btest/core/plugins/analyzer-plugin/src/foo.pac
Normal file
26
testing/btest/core/plugins/analyzer-plugin/src/foo.pac
Normal file
|
@ -0,0 +1,26 @@
|
|||
%include binpac.pac
|
||||
%include bro.pac
|
||||
|
||||
%extern{
|
||||
#include "Foo.h"
|
||||
|
||||
#include "events.bif.h"
|
||||
%}
|
||||
|
||||
analyzer Foo withcontext {
|
||||
connection: Foo_Conn;
|
||||
flow: Foo_Flow;
|
||||
};
|
||||
|
||||
connection Foo_Conn(bro_analyzer: BroAnalyzer) {
|
||||
upflow = Foo_Flow(true);
|
||||
downflow = Foo_Flow(false);
|
||||
};
|
||||
|
||||
%include foo-protocol.pac
|
||||
|
||||
flow Foo_Flow(is_orig: bool) {
|
||||
datagram = Foo_Message(is_orig) withcontext(connection, this);
|
||||
};
|
||||
|
||||
%include foo-analyzer.pac
|
13
testing/btest/core/plugins/analyzer.bro
Normal file
13
testing/btest/core/plugins/analyzer.bro
Normal file
|
@ -0,0 +1,13 @@
|
|||
# @TEST-EXEC: ${DIST}/aux/bro-aux/plugin-support/init-plugin Demo Foo
|
||||
# @TEST-EXEC: cp -r %DIR/analyzer-plugin/* .
|
||||
# @TEST-EXEC: make BRO=${DIST}
|
||||
# @TEST-EXEC: BROPLUGINS=`pwd` bro -NN | awk '/^Plugin:.*Demo/ {p=1; print; next} /^Plugin:/{p=0} p==1{print}' >>output
|
||||
# @TEST-EXEC: echo === >>output
|
||||
# @TEST-EXEC: BROPLUGINS=`pwd` bro -r $TRACES/port4242.trace %INPUT >>output
|
||||
# @TEST-EXEC: btest-diff output
|
||||
|
||||
event foo_message(c: connection, data: string)
|
||||
{
|
||||
print "foo_message", c$id, data;
|
||||
}
|
||||
|
45
testing/btest/core/plugins/test-plugin.sh
Normal file
45
testing/btest/core/plugins/test-plugin.sh
Normal file
|
@ -0,0 +1,45 @@
|
|||
# @TEST-EXEC: ${DIST}/aux/bro-aux/plugin-support/init-plugin Demo Foo
|
||||
# @TEST-EXEC: bash %INPUT
|
||||
# @TEST-EXEC: make BRO=${DIST}
|
||||
# @TEST-EXEC: BROPLUGINS=`pwd` bro -NN | awk '/^Plugin:.*Demo/ {p=1; print; next} /^Plugin:/{p=0} p==1{print}' >>output
|
||||
# @TEST-EXEC: echo === >>output
|
||||
# @TEST-EXEC: BROPLUGINS=`pwd` bro -r $TRACES/empty.trace >>output
|
||||
# @TEST-EXEC: echo === >>output
|
||||
# @TEST-EXEC: BROPLUGINS=`pwd` bro demo/foo -r $TRACES/empty.trace >>output
|
||||
# @TEST-EXEC: btest-diff output
|
||||
|
||||
cat >scripts/__load__.bro <<EOF
|
||||
@load ./demo/foo/base/at-startup.bro
|
||||
EOF
|
||||
|
||||
cat >scripts/demo/foo/__load__.bro <<EOF
|
||||
@load ./manually.bro
|
||||
EOF
|
||||
|
||||
cat >scripts/demo/foo/manually.bro <<EOF
|
||||
event bro_init()
|
||||
{
|
||||
print "plugin: manually loaded";
|
||||
}
|
||||
EOF
|
||||
|
||||
mkdir -p scripts/demo/foo/base/
|
||||
|
||||
cat >scripts/demo/foo/base/at-startup.bro <<EOF
|
||||
event bro_init()
|
||||
{
|
||||
print "plugin: automatically loaded at startup";
|
||||
print "calling bif", hello_plugin_world();
|
||||
}
|
||||
EOF
|
||||
|
||||
cat >src/functions.bif <<EOF
|
||||
function hello_plugin_world%(%): string
|
||||
%{
|
||||
return new StringVal("Hello from the plugin!");
|
||||
%}
|
||||
EOF
|
||||
|
||||
cat >src/events.bif <<EOF
|
||||
event plugin_event%(foo: count%);
|
||||
EOF
|
Loading…
Add table
Add a link
Reference in a new issue