Updates of the dynamic plugin code.

Includes:

    - Cleanup of the plugin API, in particular generally changing
      const char* to std::string

    - Renaming environment variable BRO_PLUGINS to BRO_PLUGIN_PATH,
      defaulting to <prefix>/lib/bro/plugins

    - Reworking how dynamic plugins are searched and activated. See
      doc/devel/plugins.rst for details.

    - New @load-plugin directive to explicitly activate a plugin

    - Support for Darwin. (Linux untested right now)

    - The init-plugin updates come with support for "make test", "make
      sdist", and "make bdist" (see how-to).

    - Test updates.

Notes: The new hook mechanism, which allows plugins to hook into Bro's
core a well-defined points, is still essentially untested.
This commit is contained in:
Robin Sommer 2013-12-16 10:08:38 -08:00
parent 987452beff
commit a80dd10215
18 changed files with 257 additions and 143 deletions

View file

@ -22,10 +22,11 @@ set(BRO_SCRIPT_SOURCE_PATH ${CMAKE_CURRENT_SOURCE_DIR}/scripts)
get_filename_component(BRO_SCRIPT_INSTALL_PATH ${BRO_SCRIPT_INSTALL_PATH} get_filename_component(BRO_SCRIPT_INSTALL_PATH ${BRO_SCRIPT_INSTALL_PATH}
ABSOLUTE) ABSOLUTE)
set(BRO_PLUGIN_INSTALL_PATH ${BRO_ROOT_DIR}/lib/bro/plugins) set(BRO_PLUGIN_INSTALL_PATH ${BRO_ROOT_DIR}/lib/bro/plugins CACHE STRING "Installation path for plugins" FORCE)
set(BRO_MAGIC_INSTALL_PATH ${BRO_ROOT_DIR}/share/bro/magic) set(BRO_MAGIC_INSTALL_PATH ${BRO_ROOT_DIR}/share/bro/magic)
set(BRO_MAGIC_SOURCE_PATH ${CMAKE_CURRENT_SOURCE_DIR}/magic/database) set(BRO_MAGIC_SOURCE_PATH ${CMAKE_CURRENT_SOURCE_DIR}/magic/database)
configure_file(bro-path-dev.in ${CMAKE_CURRENT_BINARY_DIR}/bro-path-dev) configure_file(bro-path-dev.in ${CMAKE_CURRENT_BINARY_DIR}/bro-path-dev)
file(WRITE ${CMAKE_CURRENT_BINARY_DIR}/bro-path-dev.sh file(WRITE ${CMAKE_CURRENT_BINARY_DIR}/bro-path-dev.sh
"export BROPATH=`${CMAKE_CURRENT_BINARY_DIR}/bro-path-dev`\n" "export BROPATH=`${CMAKE_CURRENT_BINARY_DIR}/bro-path-dev`\n"

@ -1 +1 @@
Subproject commit 715937ad72d9158d8c3142f81ee7005601d75db8 Subproject commit f89d870437dbbbb107fd29f1085aef070e3bf373

2
cmake

@ -1 +1 @@
Subproject commit 6eb4cbfbc75f0bd13e247150b19932905a85e10c Subproject commit 763b6d2574294e62f116e167c564a6292206a655

View file

@ -214,7 +214,7 @@
#define HOST_ARCHITECTURE "@HOST_ARCHITECTURE@" #define HOST_ARCHITECTURE "@HOST_ARCHITECTURE@"
/* String with extension of dynamic libraries (e.g., ".so") */ /* String with extension of dynamic libraries (e.g., ".so") */
#define SHARED_LIBRARY_SUFFIX "@CMAKE_SHARED_LIBRARY_SUFFIX@" #define DYNAMIC_PLUGIN_SUFFIX "@CMAKE_SHARED_MODULE_SUFFIX@"
/* True if we're building outside of the main Bro source code tree. */ /* True if we're building outside of the main Bro source code tree. */
#ifndef BRO_PLUGIN_INTERNAL_BUILD #ifndef BRO_PLUGIN_INTERNAL_BUILD

View file

@ -467,7 +467,7 @@ static void WritePluginSectionHeading(FILE* f, const plugin::Plugin* p)
fprintf(f, "-"); fprintf(f, "-");
fprintf(f, "\n\n"); fprintf(f, "\n\n");
fprintf(f, "%s\n\n", p->Description()); fprintf(f, "%s\n\n", p->Description().c_str());
} }
static void WriteAnalyzerComponent(FILE* f, const analyzer::Component* c) static void WriteAnalyzerComponent(FILE* f, const analyzer::Component* c)
@ -568,7 +568,7 @@ static void WritePluginBifItems(FILE* f, const plugin::Plugin* p,
if ( o ) if ( o )
o->WriteReST(f); o->WriteReST(f);
else else
reporter->Warning("No docs for ID: %s\n", it->GetID()); reporter->Warning("No docs for ID: %s\n", it->GetID().c_str());
} }
} }

View file

@ -389,6 +389,9 @@ install(TARGETS bro DESTINATION bin)
set(BRO_EXE bro set(BRO_EXE bro
CACHE STRING "Bro executable binary" FORCE) CACHE STRING "Bro executable binary" FORCE)
set(BRO_EXE_PATH ${CMAKE_CURRENT_BINARY_DIR}/bro
CACHE STRING "Path to Bro executable binary" FORCE)
# Target to create all the autogenerated files. # Target to create all the autogenerated files.
add_custom_target(generate_outputs_stage1) add_custom_target(generate_outputs_stage1)
add_dependencies(generate_outputs_stage1 ${bro_ALL_GENERATED_OUTPUTS}) add_dependencies(generate_outputs_stage1 ${bro_ALL_GENERATED_OUTPUTS})

View file

@ -117,7 +117,7 @@ void DebugLogger::Log(const plugin::Plugin& plugin, const char* fmt, ...)
return; return;
fprintf(file, "%17.06f/%17.06f [plugin %s] ", fprintf(file, "%17.06f/%17.06f [plugin %s] ",
network_time, current_time(true), plugin.Name()); network_time, current_time(true), plugin.Name().c_str());
va_list ap; va_list ap;
va_start(ap, fmt); va_start(ap, fmt);

View file

@ -15,6 +15,7 @@ extern int brolex();
extern char last_tok[128]; extern char last_tok[128];
extern void add_input_file(const char* file); extern void add_input_file(const char* file);
extern void add_input_file_at_front(const char* file);
// Adds the substrings (using the given delimiter) in a string to the // Adds the substrings (using the given delimiter) in a string to the
// given namelist. // given namelist.

View file

@ -223,7 +223,7 @@ void usage()
fprintf(stderr, " $BROPATH | file search path (%s)\n", bro_path().c_str()); 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, " $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_PLUGIN_PATH | plugin search path (%s)\n", bro_plugin_path());
fprintf(stderr, " $BRO_PREFIXES | prefix list (%s)\n", bro_prefixes().c_str()); 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_DNS_FAKE | disable DNS lookups (%s)\n", bro_dns_fake());
fprintf(stderr, " $BRO_SEED_FILE | file to load seeds from (not set)\n"); fprintf(stderr, " $BRO_SEED_FILE | file to load seeds from (not set)\n");
@ -820,7 +820,7 @@ int main(int argc, char** argv)
if ( ! bare_mode ) if ( ! bare_mode )
add_input_file("base/init-default.bro"); add_input_file("base/init-default.bro");
plugin_mgr->LoadPluginsFrom(bro_plugin_path()); plugin_mgr->SearchDynamicPlugins(bro_plugin_path());
if ( optind == argc && if ( optind == argc &&
read_files.length() == 0 && flow_files.length() == 0 && read_files.length() == 0 && flow_files.length() == 0 &&
@ -860,6 +860,9 @@ int main(int argc, char** argv)
analyzer_mgr->InitPreScript(); analyzer_mgr->InitPreScript();
file_mgr->InitPreScript(); file_mgr->InitPreScript();
if ( ! bare_mode )
plugin_mgr->ActivateAllDynamicPlugins();
if ( events_file ) if ( events_file )
event_player = new EventPlayer(events_file); event_player = new EventPlayer(events_file);
@ -896,13 +899,14 @@ int main(int argc, char** argv)
if ( reporter->Errors() > 0 ) if ( reporter->Errors() > 0 )
exit(1); exit(1);
plugin_mgr->InitPostScript();
if ( print_plugins ) if ( print_plugins )
{ {
show_plugins(print_plugins); show_plugins(print_plugins);
exit(1); exit(1);
} }
plugin_mgr->InitPostScript();
analyzer_mgr->InitPostScript(); analyzer_mgr->InitPostScript();
file_mgr->InitPostScript(); file_mgr->InitPostScript();

View file

@ -1,6 +1,7 @@
// See the file "COPYING" in the main distribution directory for copyright. // See the file "COPYING" in the main distribution directory for copyright.
#include <sstream> #include <sstream>
#include <fstream>
#include <dirent.h> #include <dirent.h>
#include <glob.h> #include <glob.h>
#include <dlfcn.h> #include <dlfcn.h>
@ -15,6 +16,7 @@
using namespace plugin; using namespace plugin;
Plugin* Manager::current_plugin = 0;
string Manager::current_dir; string Manager::current_dir;
string Manager::current_sopath; string Manager::current_sopath;
@ -37,7 +39,7 @@ Manager::~Manager()
delete [] hooks; delete [] hooks;
} }
void Manager::LoadPluginsFrom(const string& dir) void Manager::SearchDynamicPlugins(const std::string& dir)
{ {
assert(! init); assert(! init);
@ -51,7 +53,7 @@ void Manager::LoadPluginsFrom(const string& dir)
std::string d; std::string d;
while ( std::getline(s, d, ':') ) while ( std::getline(s, d, ':') )
LoadPluginsFrom(d); SearchDynamicPlugins(d);
return; return;
} }
@ -62,12 +64,34 @@ void Manager::LoadPluginsFrom(const string& dir)
return; return;
} }
int rc = LoadPlugin(dir); // Check if it's a plugin dirctory.
if ( rc >= 0 ) const std::string magic = dir + "/__bro_plugin__";
if ( is_file(magic) )
{
// It's a plugin, get it's name.
std::ifstream in(magic);
if ( in.fail() )
reporter->FatalError("cannot open plugin magic file %s", magic.c_str());
std::string name;
std::getline(in, name);
strstrip(name);
if ( name.empty() )
reporter->FatalError("empty plugin magic file %s", magic.c_str());
// Record it, so that we can later activate it.
dynamic_plugins.insert(std::make_pair(name, dir));
DBG_LOG(DBG_PLUGINS, "Found plugin %s in %s", name.c_str(), dir.c_str());
return; return;
}
DBG_LOG(DBG_PLUGINS, "Searching directory %s recursively for plugins", dir.c_str()); // No plugin here, traverse subirectories.
DIR* d = opendir(dir.c_str()); DIR* d = opendir(dir.c_str());
@ -98,22 +122,33 @@ void Manager::LoadPluginsFrom(const string& dir)
} }
if ( st.st_mode & S_IFDIR ) if ( st.st_mode & S_IFDIR )
LoadPluginsFrom(path); SearchDynamicPlugins(path);
} }
} }
int Manager::LoadPlugin(const std::string& dir) bool Manager::ActivateDynamicPluginInternal(const std::string& name)
{ {
assert(! init); dynamic_plugin_map::iterator m = dynamic_plugins.find(name);
// Check if it's a plugin dirctory. if ( m == dynamic_plugins.end() )
if ( ! is_file(dir + "/__bro_plugin__") ) {
return -1; reporter->Error("plugin %s is not available", name.c_str());
return false;
}
DBG_LOG(DBG_PLUGINS, "Loading plugin from %s", dir.c_str()); std::string dir = m->second + "/";
if ( dir.empty() )
{
// That's our marker that we have already activated this
// plugin. Silently ignore the new request.
return true;
}
DBG_LOG(DBG_PLUGINS, "Activating plugin %s", name.c_str());
// Add the "scripts" and "bif" directories to BROPATH. // Add the "scripts" and "bif" directories to BROPATH.
string scripts = dir + "/scripts"; std::string scripts = dir + "scripts";
if ( is_dir(scripts) ) if ( is_dir(scripts) )
{ {
@ -121,44 +156,27 @@ int Manager::LoadPlugin(const std::string& dir)
add_to_bro_path(scripts); add_to_bro_path(scripts);
} }
string bif = dir + "/bif"; // Load {bif,scripts}/__load__.bro automatically.
if ( is_dir(bif) ) string init = dir + "lib/bif/__load__.bro";
{
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) ) if ( is_file(init) )
{ {
DBG_LOG(DBG_PLUGINS, " Adding %s for loading", init.c_str()); DBG_LOG(DBG_PLUGINS, " Loading %s", init.c_str());
add_input_file(init.c_str()); scripts_to_load.push_back(init);
} }
// Load bif/__load__.bro automatically. init = dir + "scripts/__load__.bro";
init = bif + "/__load__.bro";
if ( is_file(init) ) if ( is_file(init) )
{ {
DBG_LOG(DBG_PLUGINS, " Adding %s for loading", init.c_str()); DBG_LOG(DBG_PLUGINS, " Loading %s", init.c_str());
add_input_file(init.c_str()); scripts_to_load.push_back(init);
} }
// Load shared libraries. // Load shared libraries.
string dypattern = dir + "/dylib/*." + HOST_ARCHITECTURE + SHARED_LIBRARY_SUFFIX; string dypattern = dir + "/lib/*." + HOST_ARCHITECTURE + DYNAMIC_PLUGIN_SUFFIX;
DBG_LOG(DBG_PLUGINS, " Searching for shared libraries %s", dypattern.c_str()); DBG_LOG(DBG_PLUGINS, " Searching for shared libraries %s", dypattern.c_str());
@ -170,11 +188,10 @@ int Manager::LoadPlugin(const std::string& dir)
{ {
const char* path = gl.gl_pathv[i]; const char* path = gl.gl_pathv[i];
current_plugin = 0;
current_dir = dir; current_dir = dir;
current_sopath = path; current_sopath = path;
void* hdl = dlopen(path, RTLD_LAZY | RTLD_GLOBAL); void* hdl = dlopen(path, RTLD_LAZY | RTLD_GLOBAL);
current_dir.clear();
current_sopath.clear();
if ( ! hdl ) if ( ! hdl )
{ {
@ -182,6 +199,24 @@ int Manager::LoadPlugin(const std::string& dir)
reporter->FatalError("cannot load plugin library %s: %s", path, err ? err : "<unknown error>"); reporter->FatalError("cannot load plugin library %s: %s", path, err ? err : "<unknown error>");
} }
if ( ! current_plugin )
reporter->FatalError("load plugin library %s did not instantiate a plugin", path);
// We execute the pre-script initialization here; this in
// fact could be *during* script initialization if we got
// triggered via @load-plugin.
current_plugin->InitPreScript();
// Make sure the name the plugin reports is consistent with
// what we expect from its magic file.
if ( string(current_plugin->Name()) != name )
reporter->FatalError("inconsistent plugin name: %s vs %s",
current_plugin->Name().c_str(), name.c_str());
current_dir.clear();
current_sopath.clear();
current_plugin = 0;
DBG_LOG(DBG_PLUGINS, " Loaded %s", path); DBG_LOG(DBG_PLUGINS, " Loaded %s", path);
} }
} }
@ -189,10 +224,42 @@ int Manager::LoadPlugin(const std::string& dir)
else else
{ {
DBG_LOG(DBG_PLUGINS, " No shared library found"); DBG_LOG(DBG_PLUGINS, " No shared library found");
return 1;
} }
return 1; // Mark this plugin as activated by clearing the path.
m->second.clear();
return true;
}
bool Manager::ActivateDynamicPlugin(const std::string& name)
{
if ( ! ActivateDynamicPluginInternal(name) )
return false;
UpdateInputFiles();
return true;
}
bool Manager::ActivateAllDynamicPlugins()
{
for ( dynamic_plugin_map::const_iterator i = dynamic_plugins.begin();
i != dynamic_plugins.end(); i++ )
{
if ( ! ActivateDynamicPluginInternal(i->first) )
return false;
}
UpdateInputFiles();
return true;
}
void Manager::UpdateInputFiles()
{
for ( file_list::const_reverse_iterator i = scripts_to_load.rbegin();
i != scripts_to_load.rend(); i++ )
add_input_file_at_front((*i).c_str());
} }
static bool plugin_cmp(const Plugin* a, const Plugin* b) static bool plugin_cmp(const Plugin* a, const Plugin* b)
@ -205,11 +272,13 @@ bool Manager::RegisterPlugin(Plugin *plugin)
Manager::PluginsInternal()->push_back(plugin); Manager::PluginsInternal()->push_back(plugin);
if ( current_dir.size() && current_sopath.size() ) if ( current_dir.size() && current_sopath.size() )
// A dynamic plugin, record its location.
plugin->SetPluginLocation(current_dir.c_str(), current_sopath.c_str()); plugin->SetPluginLocation(current_dir.c_str(), current_sopath.c_str());
// Sort plugins by name to make sure we have a deterministic order. // Sort plugins by name to make sure we have a deterministic order.
PluginsInternal()->sort(plugin_cmp); PluginsInternal()->sort(plugin_cmp);
current_plugin = plugin;
return true; return true;
} }
@ -220,7 +289,6 @@ void Manager::InitPreScript()
for ( plugin_list::iterator i = Manager::PluginsInternal()->begin(); i != Manager::PluginsInternal()->end(); i++ ) for ( plugin_list::iterator i = Manager::PluginsInternal()->begin(); i != Manager::PluginsInternal()->end(); i++ )
{ {
Plugin* plugin = *i; Plugin* plugin = *i;
plugin->InitPreScript(); plugin->InitPreScript();
} }
@ -333,7 +401,7 @@ void Manager::DisableHook(HookType hook, Plugin* plugin)
} }
} }
int Manager::HookLoadFile(const char* file) int Manager::HookLoadFile(const string& file)
{ {
hook_list* l = hooks[HOOK_LOAD_FILE]; hook_list* l = hooks[HOOK_LOAD_FILE];

View file

@ -40,17 +40,41 @@ public:
virtual ~Manager(); virtual ~Manager();
/** /**
* Loads all plugins dynamically from a set of directories. Multiple * Searches a set of directories for plugins. If a specificed
* directories are split by ':'. If a directory does not contain a * directory does not contain a plugin itself, the method searches
* plugin itself, the method searches for plugins recursively. For * for plugins recursively. For plugins found, the method makes them
* plugins found, the method loads the plugin's shared library and * available for later activation via ActivatePlugin().
* makes its scripts available to the interpreter.
* *
* This must be called only before InitPluginsPreScript(). * This must be called only before InitPluginsPreScript().
* *
* @param dir The directory to search for plugins. * @param dir The directory to search for plugins. Multiple
* directories are split by ':'.
*/ */
void LoadPluginsFrom(const std::string& dir); void SearchDynamicPlugins(const std::string& dir);
/**
* Activates a plugin that SearchPlugins() has previously discovered.
* Activing a plugin involved loading its dynamic module, making its
* bifs available, and adding its script paths to BROPATH.
*
* @param name The name of the plugin, as determined previously by
* SearchPlugin().
*
* @return True if the plugin has been loaded successfully.
*
*/
bool ActivateDynamicPlugin(const std::string& name);
/**
* Activates all plugins that SearchPlugins() has previously
* discovered. The effect is the same all calling \a
* ActivePlugin(name) for every plugin.
*
* @return True if all plugins have been loaded successfully. If one
* fail to load, the method stops there without loading any furthers
* and returns false.
*/
bool ActivateAllDynamicPlugins();
/** /**
* First-stage initializion of the manager. This is called early on * First-stage initializion of the manager. This is called early on
@ -148,7 +172,7 @@ public:
* successfully; 0 if a plugin took over the file but had trouble * successfully; 0 if a plugin took over the file but had trouble
* loading it; and -1 if no plugin was interested in the file at all. * loading it; and -1 if no plugin was interested in the file at all.
*/ */
virtual int HookLoadFile(const char* file); virtual int HookLoadFile(const string& file);
/** /**
* Hook that filters calls to a script function/event/hook. * Hook that filters calls to a script function/event/hook.
@ -196,40 +220,37 @@ public:
*/ */
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: private:
bool ActivateDynamicPluginInternal(const std::string& name);
void UpdateInputFiles();
// All found dynamic plugins, mapping their names to base directory.
typedef std::map<std::string, std::string> dynamic_plugin_map;
dynamic_plugin_map dynamic_plugins;
// We buffer scripts to load temporarliy to get them to load in the
// right order.
typedef std::list<std::string> file_list;
file_list scripts_to_load;
bool init;
// A hook list keeps pairs of plugin and priority interested in a // A hook list keeps pairs of plugin and priority interested in a
// given hook. // given hook.
typedef std::list<std::pair<int, Plugin*> > hook_list; typedef std::list<std::pair<int, Plugin*> > hook_list;
static plugin_list* PluginsInternal();
bool init;
// An array indexed by HookType. An entry is null if there's no hook // An array indexed by HookType. An entry is null if there's no hook
// of that type enabled. // of that type enabled.
hook_list** hooks; hook_list** hooks;
static Plugin* current_plugin;
static string current_dir; static string current_dir;
static string current_sopath; static string current_sopath;
// Returns a modifiable list of all plugins, both static and dynamic.
// This is a static method so that plugins can register themselves
// even before the manager exists.
static plugin_list* PluginsInternal();
}; };
template<class T> template<class T>

View file

@ -26,15 +26,15 @@ const char* hook_name(HookType h)
return hook_names[int(h)]; return hook_names[int(h)];
} }
BifItem::BifItem(const char* arg_id, Type arg_type) BifItem::BifItem(const std::string& arg_id, Type arg_type)
{ {
id = copy_string(arg_id); id = arg_id;
type = arg_type; type = arg_type;
} }
BifItem::BifItem(const BifItem& other) BifItem::BifItem(const BifItem& other)
{ {
id = copy_string(other.id); id = other.id;
type = other.type; type = other.type;
} }
@ -42,7 +42,7 @@ BifItem& BifItem::operator=(const BifItem& other)
{ {
if ( this != &other ) if ( this != &other )
{ {
id = copy_string(other.id); id = other.id;
type = other.type; type = other.type;
} }
@ -51,20 +51,19 @@ BifItem& BifItem::operator=(const BifItem& other)
BifItem::~BifItem() BifItem::~BifItem()
{ {
delete [] id;
} }
Plugin::Plugin() Plugin::Plugin()
{ {
name = copy_string("<NAME-NOT-SET>"); name = "<NAME-NOT-SET>";
description = copy_string(""); description = "";
// These will be reset by the BRO_PLUGIN_* macros. // These will be reset by the BRO_PLUGIN_* macros.
version = -9999; version = -9999;
api_version = -9999; api_version = -9999;
dynamic = false; dynamic = false;
base_dir = 0; base_dir = "";
sopath = 0; sopath = "";
Manager::RegisterPlugin(this); Manager::RegisterPlugin(this);
} }
@ -72,33 +71,26 @@ Plugin::Plugin()
Plugin::~Plugin() Plugin::~Plugin()
{ {
Done(); Done();
delete [] name;
delete [] description;
delete [] base_dir;
delete [] sopath;
} }
const char* Plugin::Name() const const std::string& Plugin::Name() const
{ {
return name; return name;
} }
void Plugin::SetName(const char* arg_name) void Plugin::SetName(const std::string& arg_name)
{ {
delete [] name; name = arg_name;
name = copy_string(arg_name);
} }
const char* Plugin::Description() const const std::string& Plugin::Description() const
{ {
return description; return description;
} }
void Plugin::SetDescription(const char* arg_description) void Plugin::SetDescription(const std::string& arg_description)
{ {
delete [] description; description = arg_description;
description = copy_string(arg_description);
} }
int Plugin::Version() const int Plugin::Version() const
@ -121,12 +113,12 @@ bool Plugin::DynamicPlugin() const
return dynamic; return dynamic;
} }
const char* Plugin::PluginDirectory() const const std::string& Plugin::PluginDirectory() const
{ {
return base_dir; return base_dir;
} }
const char* Plugin::PluginPath() const const std::string& Plugin::PluginPath() const
{ {
return sopath; return sopath;
} }
@ -141,12 +133,10 @@ void Plugin::SetDynamicPlugin(bool arg_dynamic)
dynamic = arg_dynamic; dynamic = arg_dynamic;
} }
void Plugin::SetPluginLocation(const char* arg_dir, const char* arg_sopath) void Plugin::SetPluginLocation(const std::string& arg_dir, const std::string& arg_sopath)
{ {
delete [] base_dir; base_dir = arg_dir;
delete [] sopath; sopath = arg_sopath;
base_dir = copy_string(arg_dir);
sopath = copy_string(arg_sopath);
} }
void Plugin::InitPreScript() void Plugin::InitPreScript()
@ -197,9 +187,9 @@ static bool component_cmp(const Component* a, const Component* b)
return a->Name() < b->Name(); return a->Name() < b->Name();
} }
bool Plugin::LoadBroFile(const char* file) bool Plugin::LoadBroFile(const std::string& file)
{ {
::add_input_file(file); ::add_input_file(file.c_str());
return true; return true;
} }
@ -208,7 +198,7 @@ void Plugin::__AddBifInitFunction(bif_init_func c)
bif_inits.push_back(c); bif_inits.push_back(c);
} }
void Plugin::AddBifItem(const char* name, BifItem::Type type) void Plugin::AddBifItem(const std::string& name, BifItem::Type type)
{ {
BifItem bi(name, (BifItem::Type)type); BifItem bi(name, (BifItem::Type)type);
bif_items.push_back(bi); bif_items.push_back(bi);
@ -238,7 +228,7 @@ void Plugin::DisableHook(HookType hook)
plugin_mgr->DisableHook(hook, this); plugin_mgr->DisableHook(hook, this);
} }
int Plugin::HookLoadFile(const char* file) int Plugin::HookLoadFile(const std::string& file)
{ {
return -1; return -1;
} }
@ -266,7 +256,7 @@ void Plugin::Describe(ODesc* d) const
d->Add("Plugin: "); d->Add("Plugin: ");
d->Add(name); d->Add(name);
if ( description && *description ) if ( description.size() )
{ {
d->Add(" - "); d->Add(" - ");
d->Add(description); d->Add(description);

View file

@ -50,7 +50,7 @@ public:
* *
* @param type The type of the item. * @param type The type of the item.
*/ */
BifItem(const char* id, Type type); BifItem(const std::string& id, Type type);
/** /**
* Copy constructor. * Copy constructor.
@ -70,7 +70,7 @@ public:
/** /**
* Returns the script-level ID as passed into the constructor. * Returns the script-level ID as passed into the constructor.
*/ */
const char* GetID() const { return id; } const std::string& GetID() const { return id; }
/** /**
* Returns the type as passed into the constructor. * Returns the type as passed into the constructor.
@ -78,7 +78,7 @@ public:
Type GetType() const { return type; } Type GetType() const { return type; }
private: private:
const char* id; std::string id;
Type type; Type type;
}; };
@ -113,7 +113,7 @@ public:
typedef std::list<Component *> component_list; typedef std::list<Component *> component_list;
typedef std::list<BifItem> bif_item_list; typedef std::list<BifItem> bif_item_list;
typedef std::list<std::pair<HookType, int> > hook_list; typedef std::list<std::pair<HookType, int> > hook_list;
typedef std::list<std::pair<const char*, int> > bif_init_func_result; typedef std::list<std::pair<std::string, int> > bif_init_func_result;
typedef void (*bif_init_func)(Plugin *); typedef void (*bif_init_func)(Plugin *);
/** /**
@ -129,12 +129,12 @@ public:
/** /**
* Returns the name of the plugin. * Returns the name of the plugin.
*/ */
const char* Name() const; const std::string& Name() const;
/** /**
* Returns a short textual description of the plugin, if provided. * Returns a short textual description of the plugin, if provided.
*/ */
const char* Description() const; const std::string& Description() const;
/** /**
* Returns the version of the plugin. Version are only meaningful for * Returns the version of the plugin. Version are only meaningful for
@ -152,13 +152,13 @@ public:
* For dynamic plugins, returns the base directory from which it was * For dynamic plugins, returns the base directory from which it was
* loaded. For static plugins, returns null. * loaded. For static plugins, returns null.
**/ **/
const char* PluginDirectory() const; const std::string& PluginDirectory() const;
/** /**
* For dynamic plugins, returns the full path to the shared library * For dynamic plugins, returns the full path to the shared library
* from which it was loaded. For static plugins, returns null. * from which it was loaded. For static plugins, returns null.
**/ **/
const char* PluginPath() const; const std::string& PluginPath() const;
/** /**
* Returns the internal API version that this plugin relies on. Only * Returns the internal API version that this plugin relies on. Only
@ -225,7 +225,7 @@ public:
* *
* @param type The item's type. * @param type The item's type.
*/ */
void AddBifItem(const char* name, BifItem::Type type); void AddBifItem(const std::string& name, BifItem::Type type);
/** /**
* Adds a file to the list of files that Bro loads at startup. This * Adds a file to the list of files that Bro loads at startup. This
@ -242,7 +242,7 @@ public:
* @return True if successful (which however may only mean * @return True if successful (which however may only mean
* "successfully queued"). * "successfully queued").
*/ */
bool LoadBroFile(const char* file); bool LoadBroFile(const std::string& file);
/** /**
* Internal function adding an entry point for registering * Internal function adding an entry point for registering
@ -324,7 +324,7 @@ protected:
* printed an error message); and -1 if the plugin wasn't interested * printed an error message); and -1 if the plugin wasn't interested
* in the file at all. * in the file at all.
*/ */
virtual int HookLoadFile(const char* file); virtual int HookLoadFile(const std::string& file);
/** /**
* Hook into executing a script-level function/event/hook. Whenever * Hook into executing a script-level function/event/hook. Whenever
@ -396,7 +396,7 @@ protected:
* *
* @param name The name. Makes a copy internally. * @param name The name. Makes a copy internally.
*/ */
void SetName(const char* name); void SetName(const std::string& name);
/** /**
* Sets the plugin's textual description. * Sets the plugin's textual description.
@ -406,7 +406,7 @@ protected:
* *
* @param name The description. Makes a copy internally. * @param name The description. Makes a copy internally.
*/ */
void SetDescription(const char* descr); void SetDescription(const std::string& descr);
/** /**
* Sets the plugin's version. * Sets the plugin's version.
@ -454,7 +454,7 @@ protected:
* @param sopath The full path the shared library loaded. The * @param sopath The full path the shared library loaded. The
* functions makes an internal copy of string. * functions makes an internal copy of string.
*/ */
void SetPluginLocation(const char* dir, const char* sopath); void SetPluginLocation(const std::string& dir, const std::string& sopath);
private: private:
/** /**
@ -465,10 +465,10 @@ private:
typedef std::list<bif_init_func> bif_init_func_list; typedef std::list<bif_init_func> bif_init_func_list;
const char* name; std::string name;
const char* description; std::string description;
const char* base_dir; std::string base_dir;
const char* sopath; std::string sopath;
int version; int version;
int api_version; int api_version;
bool dynamic; bool dynamic;

View file

@ -407,6 +407,11 @@ when return TOK_WHEN;
new_sig_file); new_sig_file);
} }
@load-plugin{WS}{ID} {
const char* plugin = skip_whitespace(yytext + 12);
plugin_mgr->ActivateDynamicPlugin(plugin);
}
@unload{WS}{FILE} { @unload{WS}{FILE} {
// Skip "@unload". // Skip "@unload".
const char* new_file = skip_whitespace(yytext + 7); const char* new_file = skip_whitespace(yytext + 7);
@ -829,6 +834,17 @@ void add_input_file(const char* file)
input_files.append(copy_string(file)); input_files.append(copy_string(file));
} }
void add_input_file_at_front(const char* file)
{
if ( ! file )
reporter->InternalError("empty filename");
if ( ! filename )
(void) load_files(file);
else
input_files.insert(copy_string(file));
}
void add_to_name_list(char* s, char delim, name_list& nl) void add_to_name_list(char* s, char delim, name_list& nl)
{ {
while ( s ) while ( s )

View file

@ -664,6 +664,13 @@ string strreplace(const string& s, const string& o, const string& n)
return r; return r;
} }
std::string strstrip(std::string s)
{
s.erase(s.begin(), std::find_if(s.begin(), s.end(), std::not1(std::ptr_fun<int, int>(std::isspace))));
s.erase(std::find_if(s.rbegin(), s.rend(), std::not1(std::ptr_fun<int, int>(std::isspace))).base(), s.end());
return s;
}
int hmac_key_set = 0; int hmac_key_set = 0;
uint8 shared_hmac_md5_key[16]; uint8 shared_hmac_md5_key[16];
@ -942,7 +949,7 @@ const char* bro_magic_path()
const char* bro_plugin_path() const char* bro_plugin_path()
{ {
const char* path = getenv("BRO_PLUGINS"); const char* path = getenv("BRO_PLUGIN_PATH");
if ( ! path ) if ( ! path )
path = BRO_PLUGIN_INSTALL_PATH; path = BRO_PLUGIN_INSTALL_PATH;

View file

@ -155,6 +155,9 @@ bool is_file(const std::string& path);
// Replaces all occurences of *o* in *s* with *n*. // 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 std::string strreplace(const std::string& s, const std::string& o, const std::string& n);
// Remove all leading and trainling white space from string.
extern std::string strstrip(std::string s);
extern uint8 shared_hmac_md5_key[16]; extern uint8 shared_hmac_md5_key[16];
extern int hmac_key_set; extern int hmac_key_set;

View file

@ -1,9 +1,9 @@
# @TEST-EXEC: ${DIST}/aux/bro-aux/plugin-support/init-plugin Demo Foo # @TEST-EXEC: ${DIST}/aux/bro-aux/plugin-support/init-plugin Demo Foo
# @TEST-EXEC: cp -r %DIR/analyzer-plugin/* . # @TEST-EXEC: cp -r %DIR/analyzer-plugin/* .
# @TEST-EXEC: make BRO=${DIST} # @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: BRO_PLUGIN_PATH=`pwd` bro -NN | awk '/^Plugin:.*Demo/ {p=1; print; next} /^Plugin:/{p=0} p==1{print}' >>output
# @TEST-EXEC: echo === >>output # @TEST-EXEC: echo === >>output
# @TEST-EXEC: BROPLUGINS=`pwd` bro -r $TRACES/port4242.trace %INPUT >>output # @TEST-EXEC: BRO_PLUGIN_PATH=`pwd` bro -r $TRACES/port4242.trace %INPUT >>output
# @TEST-EXEC: btest-diff output # @TEST-EXEC: btest-diff output
event foo_message(c: connection, data: string) event foo_message(c: connection, data: string)

View file

@ -1,11 +1,11 @@
# @TEST-EXEC: ${DIST}/aux/bro-aux/plugin-support/init-plugin Demo Foo # @TEST-EXEC: ${DIST}/aux/bro-aux/plugin-support/init-plugin Demo Foo
# @TEST-EXEC: bash %INPUT # @TEST-EXEC: bash %INPUT
# @TEST-EXEC: make BRO=${DIST} # @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: BRO_PLUGIN_PATH=`pwd` bro -NN | awk '/^Plugin:.*Demo/ {p=1; print; next} /^Plugin:/{p=0} p==1{print}' >>output
# @TEST-EXEC: echo === >>output # @TEST-EXEC: echo === >>output
# @TEST-EXEC: BROPLUGINS=`pwd` bro -r $TRACES/empty.trace >>output # @TEST-EXEC: BRO_PLUGIN_PATH=`pwd` bro -r $TRACES/empty.trace >>output
# @TEST-EXEC: echo === >>output # @TEST-EXEC: echo === >>output
# @TEST-EXEC: BROPLUGINS=`pwd` bro demo/foo -r $TRACES/empty.trace >>output # @TEST-EXEC: BRO_PLUGIN_PATH=`pwd` bro demo/foo -r $TRACES/empty.trace >>output
# @TEST-EXEC: btest-diff output # @TEST-EXEC: btest-diff output
cat >scripts/__load__.bro <<EOF cat >scripts/__load__.bro <<EOF