diff --git a/src/analyzer/Analyzer.cc b/src/analyzer/Analyzer.cc index 898d0aa8b9..f662ad69ce 100644 --- a/src/analyzer/Analyzer.cc +++ b/src/analyzer/Analyzer.cc @@ -801,4 +801,30 @@ TEST_SUITE("Analyzer management") { CHECK(conn->FindAnalyzer("IMAP")); conn->Done(); } + + TEST_CASE("Analyzer mapping") { + REQUIRE(zeek::analyzer_mgr); + + zeek::Packet p; + zeek::ConnTuple t; + auto conn = std::make_unique(zeek::detail::ConnKey(t), 0, &t, 0, &p); + + auto ssh = zeek::analyzer_mgr->InstantiateAnalyzer("SSH", conn.get()); + REQUIRE(ssh); + auto imap = zeek::analyzer_mgr->InstantiateAnalyzer("IMAP", conn.get()); + REQUIRE(imap); + + zeek::analyzer_mgr->AddComponentMapping(ssh->GetAnalyzerTag(), imap->GetAnalyzerTag()); + zeek::analyzer_mgr->DisableAnalyzer(ssh->GetAnalyzerTag()); // needs to be disabled for mapping to take effect + auto ssh_is_imap = zeek::analyzer_mgr->InstantiateAnalyzer("SSH", conn.get()); + CHECK_EQ(ssh_is_imap->GetAnalyzerTag(), imap->GetAnalyzerTag()); // SSH is now IMAP + + // orderly cleanup through connection + auto* tcp = new zeek::packet_analysis::TCP::TCPSessionAdapter(conn.get()); + conn->SetSessionAdapter(tcp, nullptr); + tcp->AddChildAnalyzer(ssh); + tcp->AddChildAnalyzer(imap); + tcp->AddChildAnalyzer(ssh_is_imap); + conn->Done(); + } } diff --git a/src/analyzer/Manager.cc b/src/analyzer/Manager.cc index 181e6496d2..cf63c18717 100644 --- a/src/analyzer/Manager.cc +++ b/src/analyzer/Manager.cc @@ -110,7 +110,7 @@ void Manager::DumpDebug() { void Manager::Done() {} bool Manager::EnableAnalyzer(const zeek::Tag& tag) { - Component* p = Lookup(tag); + Component* p = Lookup(tag, false); if ( ! p ) return false; @@ -122,7 +122,7 @@ bool Manager::EnableAnalyzer(const zeek::Tag& tag) { } bool Manager::EnableAnalyzer(EnumVal* val) { - Component* p = Lookup(val); + Component* p = Lookup(val, false); if ( ! p ) return false; @@ -134,7 +134,7 @@ bool Manager::EnableAnalyzer(EnumVal* val) { } bool Manager::DisableAnalyzer(const zeek::Tag& tag) { - Component* p = Lookup(tag); + Component* p = Lookup(tag, false); if ( ! p ) return false; diff --git a/src/file_analysis/file_analysis.bif b/src/file_analysis/file_analysis.bif index 8f427a8fec..bd1825386a 100644 --- a/src/file_analysis/file_analysis.bif +++ b/src/file_analysis/file_analysis.bif @@ -41,7 +41,7 @@ function Files::__set_reassembly_buffer%(file_id: string, max: count%): bool ## :zeek:see:`Files::enable_analyzer`. function Files::__enable_analyzer%(tag: Files::Tag%) : bool %{ - auto c = zeek::file_mgr->Lookup(tag->AsEnumVal()); + auto c = zeek::file_mgr->Lookup(tag->AsEnumVal(), false); if ( ! c ) return zeek::val_mgr->False(); @@ -53,7 +53,7 @@ function Files::__enable_analyzer%(tag: Files::Tag%) : bool ## :zeek:see:`Files::disable_analyzer`. function Files::__disable_analyzer%(tag: Files::Tag%) : bool %{ - auto c = zeek::file_mgr->Lookup(tag->AsEnumVal()); + auto c = zeek::file_mgr->Lookup(tag->AsEnumVal(), false); if ( ! c ) return zeek::val_mgr->False(); diff --git a/src/packet_analysis/Component.cc b/src/packet_analysis/Component.cc index fc9137a5b5..cc9ae997e7 100644 --- a/src/packet_analysis/Component.cc +++ b/src/packet_analysis/Component.cc @@ -21,7 +21,7 @@ void Component::SetEnabled(bool arg_enabled) { plugin::Component::SetEnabled(arg_enabled); // If we already have instantiated an analyzer, update its state. - if ( auto analyzer = packet_mgr->Lookup(Tag().AsVal().get()) ) + if ( auto analyzer = packet_mgr->Lookup(Tag().AsVal().get(), false) ) analyzer->SetEnabled(arg_enabled); } diff --git a/src/packet_analysis/Manager.cc b/src/packet_analysis/Manager.cc index 87a7d5cb62..d16e6afda9 100644 --- a/src/packet_analysis/Manager.cc +++ b/src/packet_analysis/Manager.cc @@ -82,14 +82,14 @@ AnalyzerPtr Manager::GetAnalyzer(const std::string& name) { } bool Manager::EnableAnalyzer(EnumVal* tag) { - Component* c = Lookup(tag); + Component* c = Lookup(tag, false); c->SetEnabled(true); return true; } bool Manager::DisableAnalyzer(EnumVal* tag) { - Component* c = Lookup(tag); + Component* c = Lookup(tag, false); c->SetEnabled(false); return true; diff --git a/src/plugin/ComponentManager.h b/src/plugin/ComponentManager.h index 9a22521831..098ecd6bed 100644 --- a/src/plugin/ComponentManager.h +++ b/src/plugin/ComponentManager.h @@ -119,24 +119,59 @@ public: /** * @param name The canonical name of a component. + * @param consider_remappings If true, component mappings will be honored + * if the original component is disabled. * @return The component associated with the name or a null pointer if no * such component exists. */ - C* Lookup(const std::string& name) const; + C* Lookup(const std::string& name, bool consider_remappings = true) const; /** * @param name A component tag. + * @param consider_remappings If true, component mappings will be honored + * if the original component is disabled. * @return The component associated with the tag or a null pointer if no * such component exists. */ - C* Lookup(const zeek::Tag& tag) const; + C* Lookup(const zeek::Tag& tag, bool consider_remappings = true) const; /** * @param name A component's enum value. + * @param consider_remappings If true, component mappings will be honored + * if the original component is disabled. * @return The component associated with the value or a null pointer if no * such component exists. */ - C* Lookup(EnumVal* val) const; + C* Lookup(EnumVal* val, bool consider_remappings = true) const; + + /** + * Registers a mapping of a component to another one that will be honored + * by the `Lookup()` methods if (and only if) the original is currently + * disabled. + * + * @param old The original component tag. + * @param new_ The new component tag. + */ + void AddComponentMapping(const zeek::Tag& old, const zeek::Tag& new_) { + if ( old != new_ ) { + component_mapping_by_src[old] = new_; + component_mapping_by_dst[new_] = old; + } + } + + /** + * Returns true if a given component has a mapping to different one in place. + * + * @param tag The component tag to check. + */ + auto HasComponentMapping(const zeek::Tag& tag) const { return component_mapping_by_src.count(tag); } + + /** + * Returns true if a given component is mapped to from a different one. + * + * @param tag The component tag to check. + */ + bool ProvidesComponentMapping(const zeek::Tag& tag) const { return component_mapping_by_dst.count(tag); } private: /** Script layer module in which component tags live. */ @@ -150,6 +185,8 @@ private: std::map components_by_name; std::map components_by_tag; std::map components_by_val; + std::map component_mapping_by_src; + std::map component_mapping_by_dst; }; template @@ -204,7 +241,7 @@ const std::string& ComponentManager::GetComponentName(zeek::Tag tag) const { if ( ! tag ) return error; - if ( C* c = Lookup(tag) ) + if ( C* c = Lookup(tag, false) ) // use actual, not remapped name return c->CanonicalName(); reporter->InternalWarning("requested name of unknown component tag %s", tag.AsString().c_str()); @@ -266,21 +303,48 @@ zeek::Tag ComponentManager::GetComponentTag(Val* v) const { } template -C* ComponentManager::Lookup(const std::string& name) const { - typename std::map::const_iterator i = components_by_name.find(util::to_upper(name)); - return i != components_by_name.end() ? i->second : nullptr; +C* ComponentManager::Lookup(const std::string& name, bool consider_remappings) const { + if ( auto i = components_by_name.find(util::to_upper(name)); i != components_by_name.end() ) { + auto c = (*i).second; + if ( consider_remappings && ! c->Enabled() ) { + if ( auto j = component_mapping_by_src.find(c->Tag()); j != component_mapping_by_src.end() ) + return Lookup(j->second, false); + } + + return c; + } + else + return nullptr; } template -C* ComponentManager::Lookup(const zeek::Tag& tag) const { - typename std::map::const_iterator i = components_by_tag.find(tag); - return i != components_by_tag.end() ? i->second : nullptr; +C* ComponentManager::Lookup(const zeek::Tag& tag, bool consider_remappings) const { + if ( auto i = components_by_tag.find(tag); i != components_by_tag.end() ) { + auto c = (*i).second; + if ( consider_remappings && ! c->Enabled() ) { + if ( auto j = component_mapping_by_src.find(c->Tag()); j != component_mapping_by_src.end() ) + return Lookup(j->second, false); + } + + return c; + } + else + return nullptr; } template -C* ComponentManager::Lookup(EnumVal* val) const { - typename std::map::const_iterator i = components_by_val.find(val->InternalInt()); - return i != components_by_val.end() ? i->second : nullptr; +C* ComponentManager::Lookup(EnumVal* val, bool consider_remappings) const { + if ( auto i = components_by_val.find(val->InternalInt()); i != components_by_val.end() ) { + auto c = (*i).second; + if ( consider_remappings && ! c->Enabled() ) { + if ( auto j = component_mapping_by_src.find(c->Tag()); j != component_mapping_by_src.end() ) + return Lookup(j->second, false); + } + + return c; + } + else + return nullptr; } template diff --git a/src/spicy/manager.cc b/src/spicy/manager.cc index 87543e33aa..86f9a8c28e 100644 --- a/src/spicy/manager.cc +++ b/src/spicy/manager.cc @@ -375,8 +375,9 @@ bool Manager::toggleFileAnalyzer(const Tag& tag, bool enable) { // not set -> not ours return false; - file_analysis::Component* component = file_mgr->Lookup(tag); - file_analysis::Component* component_replaces = analyzer.replaces ? file_mgr->Lookup(analyzer.replaces) : nullptr; + file_analysis::Component* component = file_mgr->Lookup(tag, false); + file_analysis::Component* component_replaces = + analyzer.replaces ? file_mgr->Lookup(analyzer.replaces, false) : nullptr; if ( ! component ) { // Shouldn't really happen. @@ -418,9 +419,9 @@ bool Manager::togglePacketAnalyzer(const Tag& tag, bool enable) { // not set -> not ours return false; - packet_analysis::Component* component = packet_mgr->Lookup(tag); + packet_analysis::Component* component = packet_mgr->Lookup(tag, false); packet_analysis::Component* component_replaces = - analyzer.replaces ? packet_mgr->Lookup(analyzer.replaces) : nullptr; + analyzer.replaces ? packet_mgr->Lookup(analyzer.replaces, false) : nullptr; if ( ! component ) { // Shouldn't really happen. @@ -452,21 +453,21 @@ bool Manager::togglePacketAnalyzer(const Tag& tag, bool enable) { bool Manager::toggleAnalyzer(EnumVal* tag, bool enable) { if ( tag->GetType() == analyzer_mgr->GetTagType() ) { - if ( auto analyzer = analyzer_mgr->Lookup(tag) ) + if ( auto analyzer = analyzer_mgr->Lookup(tag, false) ) return toggleProtocolAnalyzer(analyzer->Tag(), enable); else return false; } if ( tag->GetType() == file_mgr->GetTagType() ) { - if ( auto analyzer = file_mgr->Lookup(tag) ) + if ( auto analyzer = file_mgr->Lookup(tag, false) ) return toggleFileAnalyzer(analyzer->Tag(), enable); else return false; } if ( tag->GetType() == packet_mgr->GetTagType() ) { - if ( auto analyzer = packet_mgr->Lookup(tag) ) + if ( auto analyzer = packet_mgr->Lookup(tag, false) ) return togglePacketAnalyzer(analyzer->Tag(), enable); else return false; @@ -893,7 +894,7 @@ void Manager::disableReplacedAnalyzers() { auto replaces = info.name_replaces.c_str(); - if ( file_mgr->Lookup(replaces) || packet_mgr->Lookup(replaces) ) + if ( file_mgr->Lookup(replaces, false) || packet_mgr->Lookup(replaces, false) ) reporter->FatalError("cannot replace '%s' analyzer with a protocol analyzer", replaces); auto tag = analyzer_mgr->GetAnalyzerTag(replaces); @@ -915,10 +916,10 @@ void Manager::disableReplacedAnalyzers() { auto replaces = info.name_replaces.c_str(); - if ( analyzer_mgr->Lookup(replaces) || packet_mgr->Lookup(replaces) ) + if ( analyzer_mgr->Lookup(replaces, false) || packet_mgr->Lookup(replaces, false) ) reporter->FatalError("cannot replace '%s' analyzer with a file analyzer", replaces); - auto component = file_mgr->Lookup(replaces); + auto component = file_mgr->Lookup(replaces, false); if ( ! component ) { SPICY_DEBUG(hilti::rt::fmt("%s is supposed to replace file analyzer %s, but that does not exist", info.name_analyzer, replaces)); @@ -937,7 +938,7 @@ void Manager::disableReplacedAnalyzers() { auto replaces = info.name_replaces.c_str(); - auto component = packet_mgr->Lookup(replaces); + auto component = packet_mgr->Lookup(replaces, false); if ( ! component ) { SPICY_DEBUG(hilti::rt::fmt("%s is supposed to replace packet analyzer %s, but that does not exist", info.name_analyzer, replaces));