diff --git a/scripts/base/frameworks/analyzer/main.zeek b/scripts/base/frameworks/analyzer/main.zeek index 54ba82178d..e4d740979a 100644 --- a/scripts/base/frameworks/analyzer/main.zeek +++ b/scripts/base/frameworks/analyzer/main.zeek @@ -9,6 +9,13 @@ ##! These tags are defined internally by ##! the analyzers themselves, and documented in their analyzer-specific ##! description along with the events that they generate. +##! +##! Analyzer tags are also inserted into a global :zeek:type:`AllAnalyzers` enum +##! type. This type contains duplicates of all of the :zeek:type:`Analyzer::Tag`, +##! :zeek:type:`PacketAnalyzer::Tag` and :zeek:type:`Files::Tag` enum values +##! and can be used for arguments to function/hook/event definitions where they +##! need to handle any analyzer type. See :zeek:id:`Analyzer::register_for_ports` +##! for an example. @load base/frameworks/packet-filter/utils @@ -186,12 +193,12 @@ function all_registered_ports(): table[Analyzer::Tag] of set[port] return ports; } -function name(atype: Analyzer::Tag) : string +function name(atype: AllAnalyzers::Tag) : string { return __name(atype); } -function get_tag(name: string): Analyzer::Tag +function get_tag(name: string): AllAnalyzers::Tag { return __tag(name); } diff --git a/src/analyzer/Manager.cc b/src/analyzer/Manager.cc index 70d4847931..ba21821a84 100644 --- a/src/analyzer/Manager.cc +++ b/src/analyzer/Manager.cc @@ -56,7 +56,10 @@ bool Manager::ConnIndex::operator<(const ConnIndex& other) const return false; } -Manager::Manager() : plugin::ComponentManager("Analyzer", "Tag") { } +Manager::Manager() + : plugin::ComponentManager("Analyzer", "Tag", "AllAnalyzers") + { + } Manager::~Manager() { diff --git a/src/analyzer/analyzer.bif b/src/analyzer/analyzer.bif index 9e8018342f..0bd666fac6 100644 --- a/src/analyzer/analyzer.bif +++ b/src/analyzer/analyzer.bif @@ -38,14 +38,31 @@ function Analyzer::__schedule_analyzer%(orig: addr, resp: addr, resp_p: port, return zeek::val_mgr->True(); %} -function __name%(atype: Analyzer::Tag%) : string +function __name%(atype: AllAnalyzers::Tag%) : string %{ - const auto& n = zeek::analyzer_mgr->GetComponentName(zeek::IntrusivePtr{zeek::NewRef{}, atype->AsEnumVal()}); - return zeek::make_intrusive(n); + auto val = atype->AsEnumVal(); + + plugin::Component* component = zeek::analyzer_mgr->Lookup(val); + if ( ! component ) + component = zeek::packet_mgr->Lookup(val); + if ( ! component ) + component = zeek::file_mgr->Lookup(val); + if ( ! component ) + return zeek::make_intrusive(""); + + return zeek::make_intrusive(component->CanonicalName()); %} -function __tag%(name: string%) : Analyzer::Tag +function __tag%(name: string%) : AllAnalyzers::Tag %{ - zeek::Tag t = zeek::analyzer_mgr->GetComponentTag(name->CheckString()); + auto val = name->CheckString(); + + plugin::Component* component = zeek::analyzer_mgr->Lookup(val); + if ( ! component ) + component = zeek::packet_mgr->Lookup(val); + if ( ! component ) + component = zeek::file_mgr->Lookup(val); + + zeek::Tag t = component ? component->Tag() : zeek::Tag(); return t.AsVal(); %} diff --git a/src/file_analysis/Manager.cc b/src/file_analysis/Manager.cc index c8a48c5802..b05545dd23 100644 --- a/src/file_analysis/Manager.cc +++ b/src/file_analysis/Manager.cc @@ -19,8 +19,8 @@ namespace zeek::file_analysis { Manager::Manager() - : plugin::ComponentManager("Files", "Tag"), current_file_id(), - magic_state(), cumulative_files(0), max_files(0) + : plugin::ComponentManager("Files", "Tag", "AllAnalyzers"), + current_file_id(), magic_state(), cumulative_files(0), max_files(0) { } diff --git a/src/packet_analysis/Manager.cc b/src/packet_analysis/Manager.cc index dfc2ac8dd9..74cb92010a 100644 --- a/src/packet_analysis/Manager.cc +++ b/src/packet_analysis/Manager.cc @@ -13,7 +13,8 @@ using namespace zeek::packet_analysis; -Manager::Manager() : plugin::ComponentManager("PacketAnalyzer", "Tag") +Manager::Manager() + : plugin::ComponentManager("PacketAnalyzer", "Tag", "AllAnalyzers") { } diff --git a/src/plugin/Component.cc b/src/plugin/Component.cc index 9a1d6d2bbd..b2fafbad0c 100644 --- a/src/plugin/Component.cc +++ b/src/plugin/Component.cc @@ -11,7 +11,7 @@ namespace zeek::plugin Tag::type_t Component::type_counter(0); Component::Component(component::Type arg_type, const std::string& arg_name, - Tag::subtype_t tag_subtype, zeek::EnumTypePtr etype) + Tag::subtype_t tag_subtype, EnumTypePtr etype) : type(arg_type), name(arg_name), tag(etype, 1, 0), etype(std::move(etype)), tag_subtype(tag_subtype) { diff --git a/src/plugin/Component.h b/src/plugin/Component.h index ba7b5d3267..c62ad88cb5 100644 --- a/src/plugin/Component.h +++ b/src/plugin/Component.h @@ -63,7 +63,7 @@ public: * script-land. */ Component(component::Type type, const std::string& name, Tag::subtype_t tag_subtype = 0, - zeek::EnumTypePtr etype = nullptr); + EnumTypePtr etype = nullptr); /** * Destructor. diff --git a/src/plugin/ComponentManager.h b/src/plugin/ComponentManager.h index c8a5b6e492..f2485ecad8 100644 --- a/src/plugin/ComponentManager.h +++ b/src/plugin/ComponentManager.h @@ -4,13 +4,16 @@ #include #include +#include "zeek/Attr.h" #include "zeek/DebugLogger.h" +#include "zeek/Expr.h" #include "zeek/Reporter.h" #include "zeek/Scope.h" #include "zeek/Tag.h" #include "zeek/Type.h" #include "zeek/Val.h" #include "zeek/Var.h" // for add_type() +#include "zeek/module_util.h" #include "zeek/zeekygen/Manager.h" namespace zeek::plugin @@ -36,7 +39,8 @@ public: * @param local_id The local part of the ID of the new enum type * (e.g., "Tag"). */ - ComponentManager(const std::string& module, const std::string& local_id); + ComponentManager(const std::string& module, const std::string& local_id, + const std::string& parent_module = ""); /** * @return The script-layer module in which the component's "Tag" ID lives. @@ -120,20 +124,45 @@ public: C* Lookup(EnumVal* val) const; private: - std::string module; /**< Script layer module in which component tags live. */ - EnumTypePtr tag_enum_type; /**< Enum type of component tags. */ + /** Script layer module in which component tags live. */ + std::string module; + std::string parent_module; + + /** Module-local type of component tags. */ + EnumTypePtr tag_enum_type; + EnumTypePtr parent_tag_enum_type; + std::map components_by_name; std::map components_by_tag; std::map components_by_val; }; template -ComponentManager::ComponentManager(const std::string& arg_module, const std::string& local_id) - : module(arg_module), tag_enum_type(make_intrusive(module + "::" + local_id)) +ComponentManager::ComponentManager(const std::string& module, const std::string& local_id, + const std::string& parent_module) + : module(module), parent_module(parent_module) { + tag_enum_type = make_intrusive(module + "::" + local_id); auto id = zeek::detail::install_ID(local_id.c_str(), module.c_str(), true, true); zeek::detail::add_type(id.get(), tag_enum_type, nullptr); zeek::detail::zeekygen_mgr->Identifier(std::move(id)); + + if ( ! parent_module.empty() ) + { + // check to see if the parent module's type has been created already + id = zeek::detail::lookup_ID(local_id.c_str(), parent_module.c_str(), false, true, false); + if ( id != zeek::detail::ID::nil ) + { + parent_tag_enum_type = id->GetType(); + } + else + { + parent_tag_enum_type = make_intrusive(parent_module + "::" + local_id); + id = zeek::detail::install_ID(local_id.c_str(), parent_module.c_str(), true, true); + zeek::detail::add_type(id.get(), parent_tag_enum_type, nullptr); + zeek::detail::zeekygen_mgr->Identifier(std::move(id)); + } + } } template const std::string& ComponentManager::GetModule() const @@ -194,19 +223,19 @@ 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 : 0; + return i != components_by_name.end() ? i->second : 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 : 0; + return i != components_by_tag.end() ? i->second : 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 : 0; + return i != components_by_val.end() ? i->second : nullptr; } template @@ -229,6 +258,13 @@ void ComponentManager::RegisterComponent(C* component, const std::string& pre std::string id = util::fmt("%s%s", prefix.c_str(), cname.c_str()); tag_enum_type->AddName(module, id.c_str(), component->Tag().AsVal()->InternalInt(), true, nullptr); + + if ( parent_tag_enum_type ) + { + std::string parent_id = util::fmt("%s_%s", util::strtoupper(module).c_str(), id.c_str()); + parent_tag_enum_type->AddName(parent_module, parent_id.c_str(), + component->Tag().AsVal()->InternalInt(), true, nullptr); + } } } // namespace zeek::plugin diff --git a/src/util.cc b/src/util.cc index f63dfdbc83..ce8026ca2e 100644 --- a/src/util.cc +++ b/src/util.cc @@ -1537,6 +1537,22 @@ std::string strtolower(const std::string& s) return t; } +TEST_CASE("util strtoupper") + { + const char* a = "aBcD"; + CHECK(strtoupper(a) == "ABCD"); + + std::string b = "aBcD"; + CHECK(strtoupper(b) == "ABCD"); + } + +std::string strtoupper(const std::string& s) + { + std::string t = s; + std::transform(t.begin(), t.end(), t.begin(), ::toupper); + return t; + } + TEST_CASE("util fmt_bytes") { const char* a = "abcd"; diff --git a/src/util.h b/src/util.h index c35da260eb..019162a7bb 100644 --- a/src/util.h +++ b/src/util.h @@ -342,6 +342,9 @@ extern std::string strstrip(std::string s); // Return a lower-cased version of the string. extern std::string strtolower(const std::string& s); +// Return a upper-cased version of the string. +extern std::string strtoupper(const std::string& s); + extern int fputs(int len, const char* s, FILE* fp); extern bool is_printable(const char* s, int len); diff --git a/testing/btest/Baseline/scripts.base.frameworks.analyzer.tags/output b/testing/btest/Baseline/scripts.base.frameworks.analyzer.tags/output new file mode 100644 index 0000000000..184cf06fa8 --- /dev/null +++ b/testing/btest/Baseline/scripts.base.frameworks.analyzer.tags/output @@ -0,0 +1,7 @@ +### BTest baseline data generated by btest-diff. Do not edit. Use "btest -U/-u" to update. Requires BTest >= 0.63. +all, Analyzer::ANALYZER_DNS +analyzer, Analyzer::ANALYZER_DNS +all, PacketAnalyzer::ANALYZER_UDP +packet analyzer, PacketAnalyzer::ANALYZER_UDP +all, Files::ANALYZER_X509 +file analyzer, Files::ANALYZER_X509 diff --git a/testing/btest/scripts/base/frameworks/analyzer/tags.zeek b/testing/btest/scripts/base/frameworks/analyzer/tags.zeek new file mode 100644 index 0000000000..66a6acfc48 --- /dev/null +++ b/testing/btest/scripts/base/frameworks/analyzer/tags.zeek @@ -0,0 +1,36 @@ +# @TEST-EXEC: zeek %INPUT > output +# @TEST-EXEC: btest-diff output + +# Validate that we can pass the individual Tag types into functions that +# take both their own Tag type as well the AllAnalyzers type. + +global test2: function(a: Analyzer::Tag); +global test3: function(a: PacketAnalyzer::Tag); +global test4: function(a: Files::Tag); + +function test1(a: AllAnalyzers::Tag) { + print "all", a; +} + +function test2(a: Analyzer::Tag) { + print "analyzer", a; +} + +function test3(a: PacketAnalyzer::Tag) { + print "packet analyzer", a; +} + +function test4(a: Files::Tag) { + print "file analyzer", a; +} + +event zeek_init() { + test1(Analyzer::ANALYZER_DNS); + test2(Analyzer::ANALYZER_DNS); + + test1(PacketAnalyzer::ANALYZER_UDP); + test3(PacketAnalyzer::ANALYZER_UDP); + + test1(Files::ANALYZER_X509); + test4(Files::ANALYZER_X509); +} \ No newline at end of file