Add concept of "parent" tag namespaces

This allows us to create an EnumType that groups all of the analyzer
tag values into a single type, while still having the existing types
that split them up. We can then use this for certain events that benefit
from taking all of the tag types at once.
This commit is contained in:
Tim Wojtulewicz 2021-10-01 12:54:27 -07:00
parent 7d66f4252f
commit a7d3cb48ef
12 changed files with 147 additions and 21 deletions

View file

@ -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);
}

View file

@ -56,7 +56,10 @@ bool Manager::ConnIndex::operator<(const ConnIndex& other) const
return false;
}
Manager::Manager() : plugin::ComponentManager<analyzer::Component>("Analyzer", "Tag") { }
Manager::Manager()
: plugin::ComponentManager<analyzer::Component>("Analyzer", "Tag", "AllAnalyzers")
{
}
Manager::~Manager()
{

View file

@ -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<zeek::StringVal>(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<zeek::StringVal>("<error>");
return zeek::make_intrusive<zeek::StringVal>(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();
%}

View file

@ -19,8 +19,8 @@ namespace zeek::file_analysis
{
Manager::Manager()
: plugin::ComponentManager<file_analysis::Component>("Files", "Tag"), current_file_id(),
magic_state(), cumulative_files(0), max_files(0)
: plugin::ComponentManager<file_analysis::Component>("Files", "Tag", "AllAnalyzers"),
current_file_id(), magic_state(), cumulative_files(0), max_files(0)
{
}

View file

@ -13,7 +13,8 @@
using namespace zeek::packet_analysis;
Manager::Manager() : plugin::ComponentManager<packet_analysis::Component>("PacketAnalyzer", "Tag")
Manager::Manager()
: plugin::ComponentManager<packet_analysis::Component>("PacketAnalyzer", "Tag", "AllAnalyzers")
{
}

View file

@ -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)
{

View file

@ -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.

View file

@ -4,13 +4,16 @@
#include <map>
#include <string>
#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<std::string, C*> components_by_name;
std::map<zeek::Tag, C*> components_by_tag;
std::map<int, C*> components_by_val;
};
template <class C>
ComponentManager<C>::ComponentManager(const std::string& arg_module, const std::string& local_id)
: module(arg_module), tag_enum_type(make_intrusive<EnumType>(module + "::" + local_id))
ComponentManager<C>::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<EnumType>(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<EnumType>();
}
else
{
parent_tag_enum_type = make_intrusive<EnumType>(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 <class C> const std::string& ComponentManager<C>::GetModule() const
@ -194,19 +223,19 @@ template <class C> C* ComponentManager<C>::Lookup(const std::string& name) const
{
typename std::map<std::string, C*>::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 <class C> C* ComponentManager<C>::Lookup(const zeek::Tag& tag) const
{
typename std::map<zeek::Tag, C*>::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 <class C> C* ComponentManager<C>::Lookup(EnumVal* val) const
{
typename std::map<int, C*>::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 <class C>
@ -229,6 +258,13 @@ void ComponentManager<C>::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

View file

@ -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";

View file

@ -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);

View file

@ -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

View file

@ -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);
}