From df386bb9b22d68a69dabbac09fab40395c352628 Mon Sep 17 00:00:00 2001 From: Christian Kreibich Date: Wed, 9 Apr 2025 18:49:25 -0700 Subject: [PATCH] Establish plugin infrastructure for connection tuple "builders". Builders are intermediaries that encapsulate the details of how to instantiate connection tuples & keys. By virtualizing those data structures, builder implementations can adapt Zeek's notion of connection tuples. --- scripts/base/init-bare.zeek | 13 ++++++++ src/CMakeLists.txt | 1 + src/conntuple/Builder.cc | 23 +++++++++++++ src/conntuple/Builder.h | 35 ++++++++++++++++++++ src/conntuple/CMakeLists.txt | 11 ++++++ src/conntuple/Component.cc | 28 ++++++++++++++++ src/conntuple/Component.h | 46 ++++++++++++++++++++++++++ src/conntuple/Manager.cc | 37 +++++++++++++++++++++ src/conntuple/Manager.h | 33 ++++++++++++++++++ src/conntuple/fivetuple/CMakeLists.txt | 3 ++ src/conntuple/fivetuple/Plugin.cc | 25 ++++++++++++++ src/plugin/Component.cc | 2 ++ src/plugin/Component.h | 1 + src/zeek-setup.cc | 5 +++ 14 files changed, 263 insertions(+) create mode 100644 src/conntuple/Builder.cc create mode 100644 src/conntuple/Builder.h create mode 100644 src/conntuple/CMakeLists.txt create mode 100644 src/conntuple/Component.cc create mode 100644 src/conntuple/Component.h create mode 100644 src/conntuple/Manager.cc create mode 100644 src/conntuple/Manager.h create mode 100644 src/conntuple/fivetuple/CMakeLists.txt create mode 100644 src/conntuple/fivetuple/Plugin.cc diff --git a/scripts/base/init-bare.zeek b/scripts/base/init-bare.zeek index 98b16e103e..d246717b9e 100644 --- a/scripts/base/init-bare.zeek +++ b/scripts/base/init-bare.zeek @@ -579,6 +579,19 @@ const io_poll_interval_live = 10 &redef; ## while testing, but should be used sparingly. const running_under_test: bool = F &redef; +module ConnTuple; + +export { + ## The connection tuple builder to use for Zeek's internal flow + ## tracking. This is a ``ConnTuple::Tag`` plugin component enum value, + ## and the default is 5-tuple-tracking based on IP/port endpoint pairs, + ## plus transport protocol. Plugins can provide their own + ## implementation. You'll usually not adjust this value in isolation, + ## but with a corresponding redef of the :zeek:type:`conn_id` record to + ## represent additional tuple members. + const builder = ConnTuple::CONNTUPLE_FIVETUPLE &redef; +} + module FTP; export { diff --git a/src/CMakeLists.txt b/src/CMakeLists.txt index 67347bafca..6bf3d8752e 100644 --- a/src/CMakeLists.txt +++ b/src/CMakeLists.txt @@ -194,6 +194,7 @@ gen_zam_target(${GEN_ZAM_SRC_DIR}) option(USE_SQLITE "Should Zeek use SQLite?" ON) add_subdirectory(analyzer) +add_subdirectory(conntuple) add_subdirectory(cluster) add_subdirectory(packet_analysis) add_subdirectory(broker) diff --git a/src/conntuple/Builder.cc b/src/conntuple/Builder.cc new file mode 100644 index 0000000000..4e23e5ae2c --- /dev/null +++ b/src/conntuple/Builder.cc @@ -0,0 +1,23 @@ +// See the file "COPYING" in the main distribution directory for copyright. + +#include "zeek/conntuple/Builder.h" + +#include "zeek/Conn.h" +#include "zeek/ID.h" +#include "zeek/IPAddr.h" +#include "zeek/session/Session.h" + +namespace zeek::conntuple { + +Builder::Builder() {} +Builder::~Builder() {} + +ConnTuplePtr Builder::GetTuple(const Packet* pkt) { return std::make_shared(); } + +zeek::detail::ConnKeyPtr Builder::GetKey(const ConnTuple& tuple) { + return std::make_shared(tuple); +} + +zeek::detail::ConnKeyPtr Builder::GetKey(Val* v) { return std::make_shared(v); } + +} // namespace zeek::conntuple diff --git a/src/conntuple/Builder.h b/src/conntuple/Builder.h new file mode 100644 index 0000000000..4b9550e429 --- /dev/null +++ b/src/conntuple/Builder.h @@ -0,0 +1,35 @@ +// See the file "COPYING" in the main distribution directory for copyright. +#pragma once + +#include "zeek/Conn.h" +#include "zeek/IPAddr.h" +#include "zeek/conntuple/Manager.h" + +namespace zeek { + +class Packet; +class RecordVal; +using RecordValPtr = IntrusivePtr; + +namespace conntuple { + +class Builder; +using BuilderPtr = std::unique_ptr; + +class Builder { +public: + Builder(); + virtual ~Builder(); + + virtual ConnTuplePtr GetTuple(const Packet* pkt); + + virtual zeek::detail::ConnKeyPtr GetKey(const ConnTuple& tuple); + virtual zeek::detail::ConnKeyPtr GetKey(Val* v); + + virtual void FillConnIdVal(detail::ConnKeyPtr key, RecordValPtr& tuple) {}; + + static zeek::conntuple::BuilderPtr Instantiate() { return std::make_unique(); } +}; + +} // namespace conntuple +} // namespace zeek diff --git a/src/conntuple/CMakeLists.txt b/src/conntuple/CMakeLists.txt new file mode 100644 index 0000000000..df478d7f0c --- /dev/null +++ b/src/conntuple/CMakeLists.txt @@ -0,0 +1,11 @@ +zeek_add_subdir_library( + conntuple + INCLUDE_DIRS + ${CMAKE_CURRENT_SOURCE_DIR} + ${CMAKE_CURRENT_BINARY_DIR} + SOURCES + Builder.cc + Component.cc + Manager.cc) + +add_subdirectory(fivetuple) diff --git a/src/conntuple/Component.cc b/src/conntuple/Component.cc new file mode 100644 index 0000000000..d452d78128 --- /dev/null +++ b/src/conntuple/Component.cc @@ -0,0 +1,28 @@ +// See the file "COPYING" in the main distribution directory for copyright. + +#include "zeek/conntuple/Component.h" + +#include "zeek/Desc.h" +#include "zeek/conntuple/Builder.h" +#include "zeek/conntuple/Manager.h" + +using namespace zeek::conntuple; + +Component::Component(const std::string& name, factory_callback arg_factory, Tag::subtype_t arg_subtype) + : plugin::Component(plugin::component::CONNTUPLE, name, arg_subtype, conntuple_mgr->GetTagType()), + factory(std::move(arg_factory)) {} + +void Component::Initialize() { + InitializeTag(); + conntuple_mgr->RegisterComponent(this, "CONNTUPLE_"); +} + +void Component::DoDescribe(ODesc* d) const { + if ( factory ) { + d->Add("CONNTUPLE_"); + d->Add(CanonicalName()); + d->Add(", "); + } + + d->Add(Enabled() ? "enabled" : "disabled"); +} diff --git a/src/conntuple/Component.h b/src/conntuple/Component.h new file mode 100644 index 0000000000..7638abea6a --- /dev/null +++ b/src/conntuple/Component.h @@ -0,0 +1,46 @@ +// See the file "COPYING" in the main distribution directory for copyright. + +#pragma once + +#include "zeek/zeek-config.h" + +#include + +#include "zeek/Tag.h" +#include "zeek/plugin/Component.h" + +namespace zeek::conntuple { + +class Builder; +using BuilderPtr = std::unique_ptr; + +class Component : public plugin::Component { +public: + using factory_callback = std::function; + + Component(const std::string& name, factory_callback factory, zeek::Tag::subtype_t subtype = 0); + ~Component() override = default; + + /** + * Initialization function. This function has to be called before any + * plugin component functionality is used; it is used to add the + * plugin component to the list of components and to initialize tags + */ + void Initialize() override; + + /** + * Returns the analyzer's factory function. + */ + factory_callback Factory() const { return factory; } + +protected: + /** + * Overridden from plugin::Component. + */ + void DoDescribe(ODesc* d) const override; + +private: + factory_callback factory; // The tuple builder's factory callback. +}; + +} // namespace zeek::conntuple diff --git a/src/conntuple/Manager.cc b/src/conntuple/Manager.cc new file mode 100644 index 0000000000..1e4e09bf09 --- /dev/null +++ b/src/conntuple/Manager.cc @@ -0,0 +1,37 @@ +// See the file "COPYING" in the main distribution directory for copyright. + +#include "zeek/conntuple/Manager.h" + +using namespace zeek::conntuple; + +Manager::Manager() : plugin::ComponentManager("ConnTuple", "Tag") {} + +void Manager::InitPostScript() { + const auto& builder_val = id::find_val("ConnTuple::builder"); + builder = InstantiateBuilder(builder_val); +} + +BuilderPtr Manager::InstantiateBuilder(const zeek::EnumValPtr& tag) { + Component* c = Lookup(tag); + + if ( ! c ) { + reporter->FatalError( + "request to instantiate unknown connection tuple builder %s, please review ConnTuple::builder value", + tag->GetType()->AsEnumType()->Lookup(tag->Get())); + } + + if ( ! c->Factory() ) { + reporter->FatalError("builder %s cannot be instantiated dynamically", GetComponentName(tag).c_str()); + } + + BuilderPtr builder = c->Factory()(); + + if ( ! builder ) { + reporter->FatalError("builder instantiation failed"); + } + + // Could add validation of actual tag vs obtained one here, as we do e.g. in + // the packet_analysis Manager. + + return builder; +} diff --git a/src/conntuple/Manager.h b/src/conntuple/Manager.h new file mode 100644 index 0000000000..7c0a8c01b1 --- /dev/null +++ b/src/conntuple/Manager.h @@ -0,0 +1,33 @@ +// See the file "COPYING" in the main distribution directory for copyright. + +#pragma once + +#include "zeek/Tag.h" +#include "zeek/conntuple/Builder.h" +#include "zeek/conntuple/Component.h" +#include "zeek/plugin/ComponentManager.h" + +namespace zeek { + +namespace conntuple { + +class Manager : public plugin::ComponentManager { +public: + Manager(); + ~Manager() {}; + + void InitPostScript(); + + Builder& GetBuilder() { return *builder; } + +private: + BuilderPtr InstantiateBuilder(const EnumValPtr& tag); + + BuilderPtr builder; // The currently active conn tuple builder. +}; + +} // namespace conntuple + +extern zeek::conntuple::Manager* conntuple_mgr; + +} // namespace zeek diff --git a/src/conntuple/fivetuple/CMakeLists.txt b/src/conntuple/fivetuple/CMakeLists.txt new file mode 100644 index 0000000000..738de294f6 --- /dev/null +++ b/src/conntuple/fivetuple/CMakeLists.txt @@ -0,0 +1,3 @@ +zeek_add_plugin( + Zeek Conntuple_Fivetuple + SOURCES Plugin.cc) diff --git a/src/conntuple/fivetuple/Plugin.cc b/src/conntuple/fivetuple/Plugin.cc new file mode 100644 index 0000000000..7881014ed0 --- /dev/null +++ b/src/conntuple/fivetuple/Plugin.cc @@ -0,0 +1,25 @@ +// See the file "COPYING" in the main distribution directory for copyright. + +#include "zeek/plugin/Plugin.h" + +#include "zeek/conntuple/Builder.h" +#include "zeek/conntuple/Component.h" + +namespace zeek::plugin::Zeek_Conntuple_Fivetuple { + +class Plugin : public zeek::plugin::Plugin { +public: + zeek::plugin::Configuration Configure() { + // The conntuple::Builder already has the default five-tuple behavior. + AddComponent(new conntuple::Component("Fivetuple", zeek::conntuple::Builder::Instantiate)); + + zeek::plugin::Configuration config; + config.name = "Zeek::Conntuple_Fivetuple"; + config.description = "Conntuple builder for Zeek's default five-tuples"; + return config; + } +}; + +Plugin plugin; + +} // namespace zeek::plugin::Zeek_Conntuple_Fivetuple diff --git a/src/plugin/Component.cc b/src/plugin/Component.cc index 7374622910..800b9575b4 100644 --- a/src/plugin/Component.cc +++ b/src/plugin/Component.cc @@ -47,6 +47,8 @@ void Component::Describe(ODesc* d) const { case component::STORAGE_BACKEND: d->Add("Storage Backend"); break; + case component::CONNTUPLE: d->Add("Conntuple Builder"); break; + default: reporter->InternalWarning("unknown component type in plugin::Component::Describe"); d->Add(""); diff --git a/src/plugin/Component.h b/src/plugin/Component.h index 259fc4ebc8..f32012a2e4 100644 --- a/src/plugin/Component.h +++ b/src/plugin/Component.h @@ -34,6 +34,7 @@ enum Type { EVENT_SERIALIZER, /// A serializer for events, used by cluster backends. LOG_SERIALIZER, /// A serializer for log batches, used by cluster backends. STORAGE_BACKEND, /// A backend for the storage framework. + CONNTUPLE, /// A builder for connection tuples. }; } // namespace component diff --git a/src/zeek-setup.cc b/src/zeek-setup.cc index d08d21ef88..5200b84bc7 100644 --- a/src/zeek-setup.cc +++ b/src/zeek-setup.cc @@ -52,6 +52,7 @@ #include "zeek/broker/Manager.h" #include "zeek/cluster/Backend.h" #include "zeek/cluster/Manager.h" +#include "zeek/conntuple/Manager.h" #include "zeek/file_analysis/Manager.h" #include "zeek/input.h" #include "zeek/input/Manager.h" @@ -159,6 +160,7 @@ void do_ssl_deinit() { zeek::ValManager* zeek::val_mgr = nullptr; zeek::packet_analysis::Manager* zeek::packet_mgr = nullptr; +zeek::conntuple::Manager* zeek::conntuple_mgr = nullptr; zeek::analyzer::Manager* zeek::analyzer_mgr = nullptr; zeek::plugin::Manager* zeek::plugin_mgr = nullptr; @@ -400,6 +402,7 @@ static void terminate_zeek() { delete zeekygen_mgr; delete packet_mgr; + delete conntuple_mgr; delete analyzer_mgr; delete file_mgr; delete cluster::manager; @@ -678,6 +681,7 @@ SetupResult setup(int argc, char** argv, Options* zopts) { iosource_mgr = new iosource::Manager(); event_registry = new EventRegistry(); packet_mgr = new packet_analysis::Manager(); + conntuple_mgr = new conntuple::Manager(); analyzer_mgr = new analyzer::Manager(); log_mgr = new logging::Manager(); input_mgr = new input::Manager(); @@ -826,6 +830,7 @@ SetupResult setup(int argc, char** argv, Options* zopts) { RecordType::InitPostScript(); + conntuple_mgr->InitPostScript(); telemetry_mgr->InitPostScript(); thread_mgr->InitPostScript(); iosource_mgr->InitPostScript();