// See the file "COPYING" in the main distribution directory for copyright. #include "zeek/plugin/Manager.h" #include #ifndef _MSC_VER #include #include #endif #include #include #include // for PATH_MAX #include #include #include #include #include #include "zeek/Event.h" #include "zeek/Func.h" #include "zeek/Reporter.h" #include "zeek/Val.h" #include "zeek/input.h" #include "zeek/util.h" using namespace std; namespace zeek::plugin { Plugin* Manager::current_plugin = nullptr; const char* Manager::current_dir = nullptr; const char* Manager::current_sopath = nullptr; Manager::Manager() { init = false; hooks = new hook_list*[NUM_HOOKS]; for ( int i = 0; i < NUM_HOOKS; i++ ) hooks[i] = nullptr; } Manager::~Manager() { assert(! init); for ( int i = 0; i < NUM_HOOKS; i++ ) delete hooks[i]; delete[] hooks; } void Manager::SearchDynamicPlugins(const std::string& dir) { assert(! init); if ( dir.empty() ) return; if ( dir.find(path_list_separator) != string::npos ) { // Split at ":". std::stringstream s(dir); std::string d; while ( std::getline(s, d, path_list_separator[0]) ) SearchDynamicPlugins(d); return; } if ( ! util::is_dir(dir) ) { DBG_LOG(DBG_PLUGINS, "Not a valid plugin directory: %s", dir.c_str()); return; } std::error_code ec; auto canon = filesystem::canonical(dir, ec); if ( ec ) { DBG_LOG(DBG_PLUGINS, "skip dynamic plugin search in %s, making path canonical failed: %s", dir.data(), ec.message().c_str()); return; } std::string canon_path = canon.string(); if ( searched_dirs.count(canon_path) ) return; searched_dirs.emplace(canon_path); // Check if it's a plugin directory. const std::string magic = dir + "/__zeek_plugin__"; if ( util::is_file(magic) ) { // It's a plugin, get it's name. std::ifstream in(magic.c_str()); if ( in.fail() ) reporter->FatalError("cannot open plugin magic file %s", magic.c_str()); std::string name; std::getline(in, name); util::strstrip(name); string lower_name = util::strtolower(name); if ( name.empty() ) reporter->FatalError("empty plugin magic file %s", magic.c_str()); if ( const auto& other = dynamic_plugins.find(lower_name); other != dynamic_plugins.end() ) { reporter->Warning("ignoring dynamic plugin %s from %s, already found in %s", name.c_str(), dir.c_str(), other->second.c_str()); return; } // Record it, so that we can later activate it. dynamic_plugins.insert(std::make_pair(lower_name, dir)); DBG_LOG(DBG_PLUGINS, "Found plugin %s in %s", name.c_str(), dir.c_str()); return; } // No plugin here, traverse subdirectories. 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; // We do not search plugins in discovered dot directories. if ( (dp->d_name[0] == '.') && dp->d_type == DT_DIR ) 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 ) SearchDynamicPlugins(path); } closedir(d); } bool Manager::ActivateDynamicPluginInternal(const std::string& name, bool ok_if_not_found, std::vector* errors) { // Loading dynamic plugins is not currently supported on Windows platform. #ifdef _MSC_VER return false; #else errors->clear(); // caller should pass it in empty, but just to be sure dynamic_plugin_map::iterator m = dynamic_plugins.find(util::strtolower(name)); plugin_list* all_plugins = Manager::ActivePluginsInternal(); if ( m == dynamic_plugins.end() ) { if ( ok_if_not_found ) return true; // Check if it's a static built-in plugin; they are always // active, so just ignore. Not the most efficient way, but // this should be rare to begin with. for ( const auto& p : *all_plugins ) { if ( p->Name() == name ) return true; } errors->emplace_back(util::fmt("plugin %s is not available", name.c_str())); return false; } if ( m->second.empty() ) { // That's our marker that we have already activated this // plugin. Silently ignore the new request. return true; } std::string dir = m->second + "/"; DBG_LOG(DBG_PLUGINS, "Activating plugin %s", name.c_str()); // If there's a plugin with the same name already, report an error and let // the user do the conflict resolution. auto lower_name = util::strtolower(name); for ( const auto& p : *all_plugins ) { if ( util::strtolower(p->Name()) == lower_name ) { auto v = p->Version(); auto error = util::fmt("dynamic plugin %s from directory %s conflicts with %s plugin %s (%d.%d.%d)", name.c_str(), dir.c_str(), p->DynamicPlugin() ? "dynamic" : "built-in", p->Name().c_str(), v.major, v.minor, v.patch); errors->emplace_back(error); return false; } } // Load shared libraries. string dypattern = dir + "/lib/*." + HOST_ARCHITECTURE + DYNAMIC_PLUGIN_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_plugin = nullptr; current_dir = dir.c_str(); current_sopath = path; void* hdl = dlopen(path, RTLD_NOW | RTLD_GLOBAL); current_dir = nullptr; current_sopath = nullptr; if ( ! hdl ) { const char* err = dlerror(); errors->emplace_back( util::fmt("cannot load plugin library %s: %s", path, err ? err : "")); continue; } if ( ! current_plugin ) { errors->emplace_back(util::fmt("load plugin library %s did not instantiate a plugin", path)); dlclose(hdl); continue; } current_plugin->SetDynamic(true); current_plugin->DoConfigure(); DBG_LOG(DBG_PLUGINS, " InitializingComponents"); current_plugin->InitializeComponents(); plugins_by_path.insert(std::make_pair(util::detail::normalize_path(dir), current_plugin)); // 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 ( util::strtolower(current_plugin->Name()) != util::strtolower(name) ) { errors->emplace_back( util::fmt("inconsistent plugin name: %s vs %s", current_plugin->Name().c_str(), name.c_str())); continue; } current_plugin = nullptr; DBG_LOG(DBG_PLUGINS, " Loaded %s", path); } globfree(&gl); if ( ! errors->empty() ) return false; } else { DBG_LOG(DBG_PLUGINS, " No shared library found"); } // Add the "scripts" and "bif" directories to ZEEKPATH. std::string scripts = dir + "scripts"; if ( util::is_dir(scripts) ) { DBG_LOG(DBG_PLUGINS, " Adding %s to ZEEKPATH", scripts.c_str()); util::detail::add_to_zeek_path(scripts); } string init; // First load {scripts}/__preload__.zeek automatically. init = dir + "scripts/__preload__.zeek"; if ( util::is_file(init) ) { DBG_LOG(DBG_PLUGINS, " Loading %s", init.c_str()); scripts_to_load.push_back(std::move(init)); } // Load {bif,scripts}/__load__.zeek automatically. init = dir + "lib/bif/__load__.zeek"; if ( util::is_file(init) ) { DBG_LOG(DBG_PLUGINS, " Loading %s", init.c_str()); scripts_to_load.push_back(std::move(init)); } init = dir + "scripts/__load__.zeek"; if ( util::is_file(init) ) { DBG_LOG(DBG_PLUGINS, " Loading %s", init.c_str()); scripts_to_load.push_back(std::move(init)); } // Mark this plugin as activated by clearing the path. m->second.clear(); return true; #endif } void Manager::ActivateDynamicPlugin(const std::string& name) { std::vector errors; if ( ActivateDynamicPluginInternal(name, false, &errors) ) UpdateInputFiles(); else // Reschedule for another attempt later. requested_plugins.insert(std::move(name)); } void Manager::ActivateDynamicPlugins(bool all) { // Tracks plugins we need to activate as pairs of their names and booleans // indicating whether an activation failure is to be deemed a fatal error. std::set> plugins_to_activate; // Activate plugins that were specifically requested. for ( const auto& x : requested_plugins ) { if ( ! x.empty() ) plugins_to_activate.emplace(x, false); } // Activate plugins that our environment tells us to. vector p; std::string plugin_activate = util::zeek_plugin_activate(); if ( ! plugin_activate.empty() ) { util::tokenize_string(util::zeek_plugin_activate(), ",", &p); for ( const auto& x : p ) plugins_to_activate.emplace(x, true); } if ( all ) { // Activate all other ones we discovered. for ( const auto& x : dynamic_plugins ) plugins_to_activate.emplace(x.first, false); } // Now we keep iterating over all the plugins, trying to load them, for as // long as we're successful for at least one further of them each round. // Doing so ensures that we can resolve (non-cyclic) load dependencies // independent of any particular order. while ( ! plugins_to_activate.empty() ) { std::vector errors; auto plugins_left = plugins_to_activate; for ( const auto& x : plugins_to_activate ) { if ( ActivateDynamicPluginInternal(x.first, x.second, &errors) ) plugins_left.erase(x); } if ( plugins_left.size() == plugins_to_activate.size() ) { // Could not load a single further plugin this round, that's fatal. for ( const auto& msg : errors ) reporter->Error("%s", msg.c_str()); reporter->FatalError("aborting after plugin errors"); } plugins_to_activate = std::move(plugins_left); } UpdateInputFiles(); } 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()); scripts_to_load.clear(); } static bool plugin_cmp(const Plugin* a, const Plugin* b) { return util::strtolower(a->Name()) < util::strtolower(b->Name()); } void Manager::RegisterPlugin(Plugin* plugin) { Manager::ActivePluginsInternal()->push_back(plugin); if ( current_dir && current_sopath ) // A dynamic plugin, record its location. plugin->SetPluginLocation(util::detail::normalize_path(current_dir), current_sopath); current_plugin = plugin; } void Manager::RegisterBifFile(const char* plugin, bif_init_func c) { bif_init_func_map* bifs = BifFilesInternal(); std::string lower_plugin = util::strtolower(plugin); bif_init_func_map::iterator i = bifs->find(lower_plugin); if ( i == bifs->end() ) i = bifs->insert(std::make_pair(lower_plugin, new bif_init_func_list())).first; i->second->push_back(c); } void Manager::ExtendZeekPathForPlugins() { // Extend the path outside of the loop to avoid looking through a longer path for each plugin vector path_additions; for ( const auto& p : Manager::ActivePlugins() ) { if ( p->DynamicPlugin() || p->Name().empty() ) continue; try { string canon = std::regex_replace(p->Name(), std::regex("::"), "_"); string dir = "builtin-plugins/" + canon; // Use find_file to find the directory in the path. string script_dir = util::find_file(dir, util::zeek_path()); if ( script_dir.empty() || ! util::is_dir(script_dir) ) continue; DBG_LOG(DBG_PLUGINS, " Adding %s to ZEEKPATH", script_dir.c_str()); path_additions.push_back(std::move(script_dir)); } catch ( const std::regex_error& e ) { // This really shouldn't ever happen, but we do need to catch the exception. // Report a fatal error because something is wrong if this occurs. reporter->FatalError("Failed to replace colons in plugin name %s: %s", p->Name().c_str(), e.what()); } } for ( const auto& plugin_path : path_additions ) util::detail::add_to_zeek_path(plugin_path); } void Manager::InitPreScript() { assert(! init); for ( plugin_list::iterator i = Manager::ActivePluginsInternal()->begin(); i != Manager::ActivePluginsInternal()->end(); i++ ) { (*i)->DoConfigure(); } // Sort plugins by name to make sure we have a deterministic order. // We cannot do this before, because the plugin name (used for plugin_cmp) is only // set in DoConfigure. // We need things sorted to generate the tags (in InitializeComponents) in a deterministic // order. ActivePluginsInternal()->sort(plugin_cmp); for ( plugin_list::iterator i = Manager::ActivePluginsInternal()->begin(); i != Manager::ActivePluginsInternal()->end(); i++ ) { (*i)->InitializeComponents(); (*i)->InitPreScript(); } init = true; } void Manager::InitBifs() { bif_init_func_map* bifs = BifFilesInternal(); for ( plugin_list::iterator i = Manager::ActivePluginsInternal()->begin(); i != Manager::ActivePluginsInternal()->end(); i++ ) { bif_init_func_map::const_iterator b = bifs->find(util::strtolower((*i)->Name())); if ( b != bifs->end() ) { for ( bif_init_func_list::const_iterator j = b->second->begin(); j != b->second->end(); ++j ) (**j)(*i); } } } void Manager::InitPostScript() { assert(init); for ( plugin_list::iterator i = Manager::ActivePluginsInternal()->begin(); i != Manager::ActivePluginsInternal()->end(); i++ ) (*i)->InitPostScript(); } void Manager::InitPreExecution() { assert(init); for ( plugin_list::iterator i = Manager::ActivePluginsInternal()->begin(); i != Manager::ActivePluginsInternal()->end(); i++ ) (*i)->InitPreExecution(); } void Manager::FinishPlugins() { assert(init); for ( plugin_list::iterator i = Manager::ActivePluginsInternal()->begin(); i != Manager::ActivePluginsInternal()->end(); i++ ) (*i)->Done(); Manager::ActivePluginsInternal()->clear(); init = false; } Manager::plugin_list Manager::ActivePlugins() const { return *Manager::ActivePluginsInternal(); } Manager::inactive_plugin_list Manager::InactivePlugins() const { plugin_list* all = ActivePluginsInternal(); inactive_plugin_list inactives; for ( dynamic_plugin_map::const_iterator i = dynamic_plugins.begin(); i != dynamic_plugins.end(); i++ ) { bool found = false; for ( plugin_list::const_iterator j = all->begin(); j != all->end(); j++ ) { if ( (*i).first == util::strtolower((*j)->Name()) ) { found = true; break; } } if ( ! found ) inactives.emplace_back(*i); } return inactives; } Manager::plugin_list* Manager::ActivePluginsInternal() { static plugin_list* plugins = nullptr; if ( ! plugins ) plugins = new plugin_list; return plugins; } Manager::bif_init_func_map* Manager::BifFilesInternal() { static bif_init_func_map* bifs = nullptr; if ( ! bifs ) bifs = new bif_init_func_map; return bifs; } Plugin* Manager::LookupPluginByPath(std::string_view _path) { auto path = util::detail::normalize_path(_path); if ( util::is_file(path) ) path = util::SafeDirname(path).result; while ( path.size() ) { auto i = plugins_by_path.find(path); if ( i != plugins_by_path.end() ) return i->second; auto j = path.rfind('/'); if ( j == std::string::npos ) break; path.erase(j); } return nullptr; } static bool hook_cmp(std::pair a, std::pair b) { if ( a.first == b.first ) return util::strtolower(a.second->Name()) < util::strtolower(b.second->Name()); // Reverse sort. return a.first > b.first; } std::list> Manager::HooksEnabledForPlugin(const Plugin* plugin) const { std::list> enabled; for ( int i = 0; i < NUM_HOOKS; i++ ) { if ( hook_list* l = hooks[i] ) for ( const auto& [hook, hook_plugin] : *l ) if ( hook_plugin == plugin ) enabled.emplace_back(static_cast(i), hook); } return enabled; } void Manager::EnableHook(HookType hook, Plugin* plugin, int prio) { if ( ! hooks[hook] ) hooks[hook] = new hook_list; hook_list* l = hooks[hook]; for ( hook_list::iterator i = l->begin(); i != l->end(); i++ ) { // Already enabled for this plugin. if ( (*i).second == plugin ) return; } l->emplace_back(prio, plugin); l->sort(hook_cmp); } void Manager::DisableHook(HookType hook, Plugin* plugin) { hook_list* l = hooks[hook]; if ( ! l ) return; for ( hook_list::iterator i = l->begin(); i != l->end(); i++ ) { if ( (*i).second == plugin ) { l->erase(i); break; } } if ( l->empty() ) { delete l; hooks[hook] = nullptr; } } void Manager::RequestEvent(EventHandlerPtr handler, Plugin* plugin) { DBG_LOG(DBG_PLUGINS, "Plugin %s requested event %s", plugin->Name().c_str(), handler->Name()); handler->SetGenerateAlways(); } void Manager::RequestObjDtor(Obj* obj, Plugin* plugin) { obj->NotifyPluginsOnDtor(); } int Manager::HookLoadFile(const Plugin::LoadType type, const string& file, const string& resolved) { HookArgumentList args; if ( HavePluginForHook(META_HOOK_PRE) ) { args.emplace_back(type); args.emplace_back(file); args.emplace_back(resolved); MetaHookPre(HOOK_LOAD_FILE, args); } hook_list* l = hooks[HOOK_LOAD_FILE]; int rc = -1; if ( l ) for ( hook_list::iterator i = l->begin(); i != l->end(); ++i ) { Plugin* p = (*i).second; rc = p->HookLoadFile(type, file, resolved); if ( rc >= 0 ) break; } if ( HavePluginForHook(META_HOOK_POST) ) MetaHookPost(HOOK_LOAD_FILE, args, HookArgument(rc)); return rc; } std::pair> Manager::HookLoadFileExtended(const Plugin::LoadType type, const string& file, const string& resolved) { HookArgumentList args; if ( HavePluginForHook(META_HOOK_PRE) ) { args.emplace_back(type); args.emplace_back(file); args.emplace_back(resolved); MetaHookPre(HOOK_LOAD_FILE_EXT, args); } hook_list* l = hooks[HOOK_LOAD_FILE_EXT]; std::pair> rc = {-1, std::nullopt}; if ( l ) for ( hook_list::iterator i = l->begin(); i != l->end(); ++i ) { Plugin* p = (*i).second; rc = p->HookLoadFileExtended(type, file, resolved); if ( rc.first >= 0 ) break; } if ( HavePluginForHook(META_HOOK_POST) ) MetaHookPost(HOOK_LOAD_FILE_EXT, args, HookArgument(rc)); return rc; } std::pair Manager::HookCallFunction(const Func* func, zeek::detail::Frame* parent, Args* vecargs) const { HookArgumentList args; ValPList vargs; if ( HavePluginForHook(META_HOOK_PRE) ) { vargs.resize(vecargs->size()); for ( const auto& v : *vecargs ) vargs.push_back(v.get()); args.emplace_back(func); args.emplace_back(parent); args.emplace_back(&vargs); MetaHookPre(HOOK_CALL_FUNCTION, args); } hook_list* l = hooks[HOOK_CALL_FUNCTION]; std::pair rval{false, nullptr}; if ( l ) { for ( hook_list::iterator i = l->begin(); i != l->end(); ++i ) { Plugin* p = (*i).second; rval = p->HookFunctionCall(func, parent, vecargs); if ( rval.first ) break; } } if ( HavePluginForHook(META_HOOK_POST) ) MetaHookPost(HOOK_CALL_FUNCTION, args, HookArgument(std::make_pair(rval.first, rval.second.get()))); return rval; } bool Manager::HookQueueEvent(Event* event) const { HookArgumentList args; if ( HavePluginForHook(META_HOOK_PRE) ) { args.emplace_back(event); MetaHookPre(HOOK_QUEUE_EVENT, args); } hook_list* l = hooks[HOOK_QUEUE_EVENT]; bool result = false; if ( l ) for ( hook_list::iterator i = l->begin(); i != l->end(); ++i ) { Plugin* p = (*i).second; if ( p->HookQueueEvent(event) ) { result = true; break; } } if ( HavePluginForHook(META_HOOK_POST) ) MetaHookPost(HOOK_QUEUE_EVENT, args, HookArgument(result)); return result; } void Manager::HookDrainEvents() const { HookArgumentList args; if ( HavePluginForHook(META_HOOK_PRE) ) MetaHookPre(HOOK_DRAIN_EVENTS, args); hook_list* l = hooks[HOOK_DRAIN_EVENTS]; if ( l ) for ( hook_list::iterator i = l->begin(); i != l->end(); ++i ) { Plugin* p = (*i).second; p->HookDrainEvents(); } if ( HavePluginForHook(META_HOOK_POST) ) MetaHookPost(HOOK_DRAIN_EVENTS, args, HookArgument()); } void Manager::HookSetupAnalyzerTree(Connection* conn) const { HookArgumentList args; if ( HavePluginForHook(META_HOOK_PRE) ) { args.emplace_back(conn); MetaHookPre(HOOK_SETUP_ANALYZER_TREE, args); } hook_list* l = hooks[HOOK_SETUP_ANALYZER_TREE]; if ( l ) { for ( hook_list::iterator i = l->begin(); i != l->end(); ++i ) { Plugin* p = (*i).second; p->HookSetupAnalyzerTree(conn); } } if ( HavePluginForHook(META_HOOK_POST) ) { MetaHookPost(HOOK_SETUP_ANALYZER_TREE, args, HookArgument()); } } void Manager::HookUpdateNetworkTime(double network_time) const { HookArgumentList args; if ( HavePluginForHook(META_HOOK_PRE) ) { args.emplace_back(network_time); MetaHookPre(HOOK_UPDATE_NETWORK_TIME, args); } hook_list* l = hooks[HOOK_UPDATE_NETWORK_TIME]; if ( l ) for ( hook_list::iterator i = l->begin(); i != l->end(); ++i ) { Plugin* p = (*i).second; p->HookUpdateNetworkTime(network_time); } if ( HavePluginForHook(META_HOOK_POST) ) MetaHookPost(HOOK_UPDATE_NETWORK_TIME, args, HookArgument()); } void Manager::HookObjDtor(void* obj) const { HookArgumentList args; if ( HavePluginForHook(META_HOOK_PRE) ) { args.emplace_back(obj); MetaHookPre(HOOK_OBJ_DTOR, args); } hook_list* l = hooks[HOOK_OBJ_DTOR]; if ( l ) for ( hook_list::iterator i = l->begin(); i != l->end(); ++i ) { Plugin* p = (*i).second; p->HookObjDtor(obj); } if ( HavePluginForHook(META_HOOK_POST) ) MetaHookPost(HOOK_OBJ_DTOR, args, HookArgument()); } void Manager::HookLogInit(const std::string& writer, const std::string& instantiating_filter, bool local, bool remote, const logging::WriterBackend::WriterInfo& info, int num_fields, const threading::Field* const* fields) const { HookArgumentList args; if ( HavePluginForHook(META_HOOK_PRE) ) { args.emplace_back(writer); args.emplace_back(instantiating_filter); args.emplace_back(local); args.emplace_back(remote); args.emplace_back(&info); args.emplace_back(num_fields); args.emplace_back(std::make_pair(num_fields, fields)); MetaHookPre(HOOK_LOG_INIT, args); } hook_list* l = hooks[HOOK_LOG_INIT]; if ( l ) for ( hook_list::iterator i = l->begin(); i != l->end(); ++i ) { Plugin* p = (*i).second; p->HookLogInit(writer, instantiating_filter, local, remote, info, num_fields, fields); } if ( HavePluginForHook(META_HOOK_POST) ) MetaHookPost(HOOK_LOG_INIT, args, HookArgument()); } bool Manager::HookLogWrite(const std::string& writer, const std::string& filter, const logging::WriterBackend::WriterInfo& info, int num_fields, const threading::Field* const* fields, threading::Value** vals) const { HookArgumentList args; if ( HavePluginForHook(META_HOOK_PRE) ) { args.emplace_back(writer); args.emplace_back(filter); args.emplace_back(&info); args.emplace_back(num_fields); args.emplace_back(std::make_pair(num_fields, fields)); args.emplace_back(vals); MetaHookPre(HOOK_LOG_WRITE, args); } hook_list* l = hooks[HOOK_LOG_WRITE]; bool result = true; if ( l ) for ( hook_list::iterator i = l->begin(); i != l->end(); ++i ) { Plugin* p = (*i).second; if ( ! p->HookLogWrite(writer, filter, info, num_fields, fields, vals) ) { result = false; break; } } if ( HavePluginForHook(META_HOOK_POST) ) MetaHookPost(HOOK_LOG_WRITE, args, HookArgument(result)); return result; } bool Manager::HookReporter(const std::string& prefix, const EventHandlerPtr event, const Connection* conn, const ValPList* addl, bool location, const zeek::detail::Location* location1, const zeek::detail::Location* location2, bool time, const std::string& message) { HookArgumentList args; if ( HavePluginForHook(META_HOOK_PRE) ) { args.emplace_back(prefix); args.emplace_back(conn); args.emplace_back(addl); args.emplace_back(location1); args.emplace_back(location2); args.emplace_back(location); args.emplace_back(time); args.emplace_back(message); MetaHookPre(HOOK_REPORTER, args); } hook_list* l = hooks[HOOK_REPORTER]; bool result = true; if ( l ) { for ( hook_list::iterator i = l->begin(); i != l->end(); ++i ) { Plugin* p = (*i).second; if ( ! p->HookReporter(prefix, event, conn, addl, location, location1, location2, time, message) ) { result = false; break; } } } if ( HavePluginForHook(META_HOOK_POST) ) MetaHookPost(HOOK_REPORTER, args, HookArgument(result)); return result; } void Manager::HookUnprocessedPacket(const Packet* packet) const { HookArgumentList args; if ( HavePluginForHook(META_HOOK_PRE) ) { args.emplace_back(packet); MetaHookPre(HOOK_UNPROCESSED_PACKET, args); } hook_list* l = hooks[HOOK_UNPROCESSED_PACKET]; if ( l ) for ( hook_list::iterator i = l->begin(); i != l->end(); ++i ) { Plugin* p = (*i).second; p->HookUnprocessedPacket(packet); } if ( HavePluginForHook(META_HOOK_POST) ) MetaHookPost(HOOK_UNPROCESSED_PACKET, args, HookArgument()); } void Manager::MetaHookPre(HookType hook, const HookArgumentList& args) const { if ( hook_list* l = hooks[META_HOOK_PRE] ) for ( const auto& [hook_type, plugin] : *l ) plugin->MetaHookPre(hook, args); } void Manager::MetaHookPost(HookType hook, const HookArgumentList& args, const HookArgument& result) const { if ( hook_list* l = hooks[META_HOOK_POST] ) for ( const auto& [hook_type, plugin] : *l ) plugin->MetaHookPost(hook, args, result); } } // namespace zeek::plugin