diff --git a/doc b/doc index 1e3a30367c..48f12d4f31 160000 --- a/doc +++ b/doc @@ -1 +1 @@ -Subproject commit 1e3a30367cc36b2779be71db7076c61362e78547 +Subproject commit 48f12d4f31b0d2fde43dbf64bf1235d326444d6d diff --git a/scripts/spicy/zeek.spicy b/scripts/spicy/zeek.spicy index 9510f75eb7..f76f238b9c 100644 --- a/scripts/spicy/zeek.spicy +++ b/scripts/spicy/zeek.spicy @@ -48,6 +48,29 @@ public function number_packets(): uint64 &cxxname="zeek::spicy::rt::number_packe ## Opaque handle to a protocol analyzer. public type ProtocolHandle = __library_type("zeek::spicy::rt::ProtocolHandle"); +## Differentiates between the types of analyzers Zeek provides. +public type AnalyzerType = enum { + File, + Packet, + Protocol, +}&cxxname = "zeek::spicy::rt::AnalyzerType"; + +## Checks if there is a Zeek analyzer of a given name. +## +## analyzer: the Zeek-side name of the analyzer to check for +## if_enabled: if true, only checks for analyzers that are enabled +## +## Returns the type of the analyzer if it exists, or ``Undef`` if it does not. +public function has_analyzer(analyzer: string, if_enabled: bool = True): bool &cxxname="zeek::spicy::rt::has_analyzer"; + +## Returns the type of a Zeek analyzer of a given name. +## +## analyzer: the Zeek-side name of the analyzer to check +## if_enabled: if true, only checks for analyzers that are enabled +## +## Returns the type of the analyzer if it exists, or ``Undef`` if it does not. +public function analyzer_type(analyzer: string, if_enabled: bool = True): AnalyzerType &cxxname="zeek::spicy::rt::analyzer_type"; + ## Adds a Zeek-side child protocol analyzer to the current connection. ## ## If the same analyzer was added previously with `protocol_handle_get_or_create` or diff --git a/src/spicy/runtime-support.cc b/src/spicy/runtime-support.cc index ba321c9435..6631a4b656 100644 --- a/src/spicy/runtime-support.cc +++ b/src/spicy/runtime-support.cc @@ -10,12 +10,13 @@ #include #include -#include "net_util.h" #include "zeek/Event.h" #include "zeek/analyzer/Manager.h" #include "zeek/analyzer/protocol/pia/PIA.h" #include "zeek/file_analysis/File.h" #include "zeek/file_analysis/Manager.h" +#include "zeek/net_util.h" +#include "zeek/packet_analysis/Manager.h" #include "zeek/spicy/manager.h" using namespace zeek; @@ -108,6 +109,17 @@ std::string hilti::rt::detail::adl::to_string(const zeek::spicy::rt::ZeekTypeTag return type_name(zeekTypeForTag(v)); } +std::string hilti::rt::detail::adl::to_string(const zeek::spicy::rt::AnalyzerType& v, detail::adl::tag /* unused */) { + switch ( v.value() ) { + case zeek::spicy::rt::AnalyzerType::File: return "AnalyzerType::File"; + case zeek::spicy::rt::AnalyzerType::Packet: return "AnalyzerType::Packet"; + case zeek::spicy::rt::AnalyzerType::Protocol: return "AnalyzerType::Protocol"; + case zeek::spicy::rt::AnalyzerType::Undef: return "AnalyzerType::Undef"; + } + + hilti::rt::cannot_be_reached(); +} + TypePtr rt::create_enum_type( const std::string& ns, const std::string& id, const hilti::rt::Set, std::optional>>>& @@ -515,6 +527,25 @@ void rt::weird(const std::string& id, const std::string& addl) { throw ValueUnavailable("none of $conn, $file, or $packet available for weird reporting"); } +rt::AnalyzerType rt::analyzer_type(const std::string& analyzer, const hilti::rt::Bool& if_enabled) { + if ( auto* c = file_mgr->Lookup(analyzer.c_str()) ) { + if ( (! if_enabled) || c->Enabled() ) + return AnalyzerType::File; + } + + if ( auto* c = packet_mgr->Lookup(analyzer.c_str()) ) { + if ( (! if_enabled) || c->Enabled() ) + return AnalyzerType::Packet; + } + + if ( auto* c = analyzer_mgr->Lookup(analyzer.c_str()) ) { + if ( (! if_enabled) || c->Enabled() ) + return AnalyzerType::Protocol; + } + + return AnalyzerType::Undef; +} + void rt::protocol_begin(const std::optional& analyzer, const ::hilti::rt::Protocol& proto) { auto _ = hilti::rt::profiler::start("zeek/rt/protocol_begin"); diff --git a/src/spicy/runtime-support.h b/src/spicy/runtime-support.h index be6fcc56e7..7974981187 100644 --- a/src/spicy/runtime-support.h +++ b/src/spicy/runtime-support.h @@ -170,6 +170,8 @@ enum class ZeekTypeTag : uint8_t { Void, }; +HILTI_RT_ENUM(AnalyzerType, Undef, File, Packet, Protocol); + extern TypePtr create_base_type(ZeekTypeTag tag); extern TypePtr create_enum_type( @@ -344,6 +346,26 @@ private: ::hilti::rt::Protocol _proto = ::hilti::rt::Protocol::Undef; }; +/** + * Returns the Zeek-side type of an analyzer of a given name. + * + * @param analyzer the Zeek-side name of the analyzer to check for + * @param if_enabled if true, only checks for analyzers that are enabled + * @return the type of the analyzer if it exists, or `AnalyzerType::Undef` if it does not. + */ +AnalyzerType analyzer_type(const std::string& analyzer, const hilti::rt::Bool& if_enabled); + +/** + * Checks if there is an analyzer of a given name in Zeek. + * + * @param analyzer the Zeek-side name of the analyzer to check for + * @param if_enabled if true, only checks for analyzers that are enabled + * @return true if there is such an analyzer + */ +inline hilti::rt::Bool has_analyzer(const std::string& analyzer, const hilti::rt::Bool& if_enabled) { + return analyzer_type(analyzer, if_enabled) != AnalyzerType::Undef; +} + /** * Adds a Zeek-side child protocol analyzer to the current connection. * @@ -828,5 +850,6 @@ inline std::string to_string(const zeek::spicy::rt::ValVectorPtr& v, detail::adl } extern std::string to_string(const zeek::spicy::rt::ZeekTypeTag& v, detail::adl::tag /* unused */); +extern std::string to_string(const zeek::spicy::rt::AnalyzerType& x, adl::tag /*unused*/); } // namespace hilti::rt::detail::adl diff --git a/testing/btest/spicy/has-analyzer.spicy b/testing/btest/spicy/has-analyzer.spicy new file mode 100644 index 0000000000..eea1336e8b --- /dev/null +++ b/testing/btest/spicy/has-analyzer.spicy @@ -0,0 +1,32 @@ +# @TEST-REQUIRES: have-spicy +# +# @TEST-EXEC: spicyz -d -o test.hlto %INPUT disable_ssh.cc +# @TEST-EXEC: zeek test.hlto + +module Test; + +import zeek; + +assert zeek::has_analyzer("HTTP"); +assert ! zeek::has_analyzer("XXX"); + +assert zeek::analyzer_type("HTTP") == zeek::AnalyzerType::Protocol; +assert zeek::analyzer_type("SHA1") == zeek::AnalyzerType::File; +assert zeek::analyzer_type("VLAN") == zeek::AnalyzerType::Packet; +assert ! zeek::analyzer_type("XXX"); + +# Disable the SSH analyzer and check that we pay attention to its state. +public function disable_ssh() &cxxname="disable_ssh"; +disable_ssh(); +assert ! zeek::has_analyzer("SSH", True); +assert zeek::has_analyzer("SSH", False); + +# @TEST-START-FILE disable_ssh.cc + +#include "zeek/analyzer/Manager.h" + +void disable_ssh() { + zeek::analyzer_mgr->Lookup("SSH")->SetEnabled(false); +} + +