Fix registration of protocol analyzers from inside plugins.

With the recent packet manager work, it broke to register a protocol
analyzer for a specific port from inside a plugin's initialization code.
That's because that registration now depends on the packet manager being
set up, which isn't case at that time a plugin's `InitPostInit()` runs.
This fix contains two parts:

    - Initialize the packet manager before the analyzer manager, so that
      the latter's `InitPostScript()` can rely on the former being
      ready.

    - Change the analyzer manager to (only) record port registrations
      happening before it's fully initialized. Its `InitPostScript()`
      then performs the actual registrations, knowing it can use the
      packet manager now.

This comes with a `cmake/` to add a missing include directory.
This commit is contained in:
Robin Sommer 2021-07-15 09:42:34 +02:00
parent 6e3d2d4516
commit a7343ee019
9 changed files with 59 additions and 7 deletions

2
cmake

@ -1 +1 @@
Subproject commit 9d762b4cacf299a2e54e0f7f258868ee217f1d36
Subproject commit 4d1990f0e4c273cf51ec52278add6ff256f9c889

View file

@ -86,6 +86,15 @@ void Manager::InitPostScript()
for ( auto i = 0; i < port_list->Length(); ++i )
vxlan_ports.emplace_back(port_list->Idx(i)->AsPortVal()->Port());
for ( const auto& p : pending_analyzers_for_ports ) {
if ( ! RegisterAnalyzerForPort(p) )
reporter->Warning("cannot register analyzer for port %u", std::get<2>(p));
}
pending_analyzers_for_ports.clear();
initialized = true;
}
void Manager::DumpDebug()
@ -231,6 +240,22 @@ bool Manager::UnregisterAnalyzerForPort(EnumVal* val, PortVal* port)
bool Manager::RegisterAnalyzerForPort(const Tag& tag, TransportProto proto, uint32_t port)
{
if ( initialized )
return RegisterAnalyzerForPort(std::make_tuple(tag, proto, port));
else
{
// Cannot register these before PostScriptInit() has run because we
// depend on packet analyis having been set up. That also means we don't have
// a reliable return value, for now we just assume it's working.
pending_analyzers_for_ports.emplace(tag, proto, port);
return true;
}
}
bool Manager::RegisterAnalyzerForPort(const std::tuple<Tag, TransportProto, uint32_t>& p)
{
const auto& [tag, proto, port] = p;
// TODO: this class is becoming more generic and removing a lot of the
// checks for protocols, but this part might need to stay like this.
packet_analysis::AnalyzerPtr analyzer;
@ -249,6 +274,9 @@ bool Manager::RegisterAnalyzerForPort(const Tag& tag, TransportProto proto, uint
bool Manager::UnregisterAnalyzerForPort(const Tag& tag, TransportProto proto, uint32_t port)
{
if ( auto i = pending_analyzers_for_ports.find(std::make_tuple(tag, proto, port)); i != pending_analyzers_for_ports.end() )
pending_analyzers_for_ports.erase(i);
// TODO: this class is becoming more generic and removing a lot of the
// checks for protocols, but this part might need to stay like this.
packet_analysis::AnalyzerPtr analyzer;

View file

@ -335,6 +335,8 @@ public:
{ return vxlan_ports; }
private:
// Internal version that must be used only once InitPostScript has completed.
bool RegisterAnalyzerForPort(const std::tuple<Tag, TransportProto, uint32_t>& p);
friend class packet_analysis::IP::IPBasedAnalyzer;
@ -372,11 +374,16 @@ private:
};
};
using protocol_analyzers = std::set<std::tuple<Tag, TransportProto, uint32_t>>;
using conns_map = std::multimap<ConnIndex, ScheduledAnalyzer*>;
using conns_queue = std::priority_queue<ScheduledAnalyzer*,
std::vector<ScheduledAnalyzer*>,
ScheduledAnalyzer::Comparator>;
bool initialized = false;
protocol_analyzers pending_analyzers_for_ports;
conns_map conns;
conns_queue conns_by_timeout;
std::vector<uint16_t> vxlan_ports;

View file

@ -87,8 +87,8 @@ int perftools_profile = 0;
#endif
zeek::ValManager* zeek::val_mgr = nullptr;
zeek::analyzer::Manager* zeek::analyzer_mgr = nullptr;
zeek::packet_analysis::Manager* zeek::packet_mgr = nullptr;
zeek::analyzer::Manager* zeek::analyzer_mgr = nullptr;
zeek::plugin::Manager* zeek::plugin_mgr = nullptr;
zeek::detail::RuleMatcher* zeek::detail::rule_matcher = nullptr;
@ -253,8 +253,8 @@ static void done_with_network()
run_state::terminating = true;
analyzer_mgr->Done();
packet_mgr->Done();
analyzer_mgr->Done();
timer_mgr->Expire();
dns_mgr->Flush();
event_mgr.Drain();
@ -324,8 +324,8 @@ static void terminate_bro()
plugin_mgr->FinishPlugins();
delete zeekygen_mgr;
delete analyzer_mgr;
delete packet_mgr;
delete analyzer_mgr;
delete file_mgr;
// broker_mgr, timer_mgr, and supervisor are deleted via iosource_mgr
delete iosource_mgr;
@ -577,8 +577,8 @@ SetupResult setup(int argc, char** argv, Options* zopts)
iosource_mgr = new iosource::Manager();
event_registry = new EventRegistry();
analyzer_mgr = new analyzer::Manager();
packet_mgr = new packet_analysis::Manager();
analyzer_mgr = new analyzer::Manager();
log_mgr = new logging::Manager();
input_mgr = new input::Manager();
file_mgr = new file_analysis::Manager();
@ -708,8 +708,8 @@ SetupResult setup(int argc, char** argv, Options* zopts)
exit(success ? 0 : 1);
}
analyzer_mgr->InitPostScript();
packet_mgr->InitPostScript();
analyzer_mgr->InitPostScript();
file_mgr->InitPostScript();
dns_mgr->InitPostScript();
@ -916,8 +916,8 @@ SetupResult setup(int argc, char** argv, Options* zopts)
reporter->FatalError("errors occurred while initializing");
run_state::detail::zeek_init_done = true;
analyzer_mgr->DumpDebug();
packet_mgr->DumpDebug();
analyzer_mgr->DumpDebug();
run_state::detail::have_pending_timers = ! run_state::reading_traces && timer_mgr->Size() > 0;

View file

@ -5,3 +5,5 @@ Demo::Foo - A Foo test analyzer (dynamic, version 1.0.0)
===
foo_message, [orig_h=::1, orig_p=37927/tcp, resp_h=::1, resp_p=4242/tcp], Hello, Foo!\x0a
===
foo_message, [orig_h=::1, orig_p=37927/tcp, resp_h=::1, resp_p=4243/tcp], Hello, Foo!\x0a

Binary file not shown.

View file

@ -1,6 +1,7 @@
#include "Plugin.h"
#include "analyzer/Component.h"
#include "analyzer/Manager.h"
#include "Foo.h"
@ -20,3 +21,13 @@ zeek::plugin::Configuration Plugin::Configure()
config.version.patch = 0;
return config;
}
void Plugin::InitPostScript()
{
auto tag = ::zeek::analyzer_mgr->GetAnalyzerTag("Foo");
if ( ! tag )
::zeek::reporter->FatalError("cannot get analyzer Tag");
zeek::analyzer_mgr->RegisterAnalyzerForPort(tag, TransportProto::TRANSPORT_TCP, 4243);
}

View file

@ -10,6 +10,8 @@ class Plugin : public zeek::plugin::Plugin
protected:
// Overridden from zeek::plugin::Plugin.
zeek::plugin::Configuration Configure() override;
void InitPostScript() override;
};
extern Plugin plugin;

View file

@ -4,6 +4,8 @@
# @TEST-EXEC: ZEEK_PLUGIN_PATH=`pwd` zeek -NN Demo::Foo >>output
# @TEST-EXEC: echo === >>output
# @TEST-EXEC: ZEEK_PLUGIN_PATH=`pwd` zeek -r $TRACES/port4242.trace %INPUT >>output
# @TEST-EXEC: echo === >>output
# @TEST-EXEC: ZEEK_PLUGIN_PATH=`pwd` zeek -r $TRACES/port4243.trace %INPUT >>output
# @TEST-EXEC: TEST_DIFF_CANONIFIER= btest-diff output
event foo_message(c: connection, data: string)