diff --git a/scripts/base/init-bare.zeek b/scripts/base/init-bare.zeek index 5c86024202..dd21ff686a 100644 --- a/scripts/base/init-bare.zeek +++ b/scripts/base/init-bare.zeek @@ -5357,8 +5357,9 @@ export { parent : PacketAnalyzer::Tag &optional; # A numeric identifier, which can be found in the packet data, that denotes the - # encapsulated protocol. - identifier : count; + # encapsulated protocol. This field is optional. If it is not included, the + # configured child analyzer will be used as default analyzer. + identifier : count &optional; # The analyzer that corresponds to the above identifier. analyzer : PacketAnalyzer::Tag; diff --git a/scripts/base/packet-protocols/__load__.zeek b/scripts/base/packet-protocols/__load__.zeek index c64d5442a4..75055a3e47 100644 --- a/scripts/base/packet-protocols/__load__.zeek +++ b/scripts/base/packet-protocols/__load__.zeek @@ -1,4 +1,4 @@ -#@load base/packet-protocols/default +@load base/packet-protocols/default @load base/packet-protocols/ethernet #@load base/packet-protocols/fddi #@load base/packet-protocols/ieee802_11 diff --git a/scripts/base/packet-protocols/default/main.zeek b/scripts/base/packet-protocols/default/main.zeek index 2d0d451d3f..12c8099b2d 100644 --- a/scripts/base/packet-protocols/default/main.zeek +++ b/scripts/base/packet-protocols/default/main.zeek @@ -1,6 +1,7 @@ module LL_DEFAULT; redef PacketAnalyzer::config_map += { + PacketAnalyzer::ConfigEntry($analyzer=PacketAnalyzer::ANALYZER_DEFAULTANALYZER), PacketAnalyzer::ConfigEntry($parent=PacketAnalyzer::ANALYZER_DEFAULTANALYZER, $identifier=4, $analyzer=PacketAnalyzer::ANALYZER_IPV4), PacketAnalyzer::ConfigEntry($parent=PacketAnalyzer::ANALYZER_DEFAULTANALYZER, $identifier=6, $analyzer=PacketAnalyzer::ANALYZER_IPV6) }; diff --git a/scripts/base/packet-protocols/ethernet/main.zeek b/scripts/base/packet-protocols/ethernet/main.zeek index b7a242efb0..217780423e 100644 --- a/scripts/base/packet-protocols/ethernet/main.zeek +++ b/scripts/base/packet-protocols/ethernet/main.zeek @@ -12,5 +12,6 @@ redef PacketAnalyzer::config_map += { #PacketAnalyzer::ConfigEntry($parent=PacketAnalyzer::ANALYZER_ETHERNET, $identifier=0x8100, $analyzer=PacketAnalyzer::ANALYZER_VLAN), #PacketAnalyzer::ConfigEntry($parent=PacketAnalyzer::ANALYZER_ETHERNET, $identifier=0x88A8, $analyzer=PacketAnalyzer::ANALYZER_VLAN), #PacketAnalyzer::ConfigEntry($parent=PacketAnalyzer::ANALYZER_ETHERNET, $identifier=0x9100, $analyzer=PacketAnalyzer::ANALYZER_VLAN), - #PacketAnalyzer::ConfigEntry($parent=PacketAnalyzer::ANALYZER_ETHERNET, $identifier=0x8864, $analyzer=PacketAnalyzer::ANALYZER_PPPOE) + #PacketAnalyzer::ConfigEntry($parent=PacketAnalyzer::ANALYZER_ETHERNET, $identifier=0x8864, $analyzer=PacketAnalyzer::ANALYZER_PPPOE), + PacketAnalyzer::ConfigEntry($parent=PacketAnalyzer::ANALYZER_ETHERNET, $analyzer=PacketAnalyzer::ANALYZER_DEFAULTANALYZER) }; diff --git a/src/packet_analysis/Analyzer.cc b/src/packet_analysis/Analyzer.cc index 05fdccd416..3aeeea9d75 100644 --- a/src/packet_analysis/Analyzer.cc +++ b/src/packet_analysis/Analyzer.cc @@ -47,14 +47,24 @@ bool Analyzer::RegisterAnalyzerMapping(uint32_t identifier, AnalyzerPtr analyzer return dispatcher.Register(identifier, std::move(analyzer)); } +void Analyzer::RegisterDefaultAnalyzer(AnalyzerPtr default_analyzer) + { + this->default_analyzer = std::move(default_analyzer); + } + +AnalyzerPtr Analyzer::Lookup(uint32_t identifier) const + { + return dispatcher.Lookup(identifier); + } + AnalyzerResult Analyzer::AnalyzeInnerPacket(Packet* packet, const uint8_t*& data, uint32_t identifier) const { - auto inner_analyzer = dispatcher.Lookup(identifier); + auto inner_analyzer = Lookup(identifier); + inner_analyzer = inner_analyzer ? inner_analyzer : default_analyzer; if ( inner_analyzer == nullptr ) { - //TODO: Handle default analysis here DBG_LOG(DBG_PACKET_ANALYSIS, "Analysis in %s failed, could not find analyzer for identifier %#x.", GetAnalyzerName(), identifier); packet->Weird("no_suitable_analyzer_found"); diff --git a/src/packet_analysis/Analyzer.h b/src/packet_analysis/Analyzer.h index 4cc32243ea..80191d61fe 100644 --- a/src/packet_analysis/Analyzer.h +++ b/src/packet_analysis/Analyzer.h @@ -74,10 +74,17 @@ public: * * @param identifier The identifier an analyzer should be called for. * @param analyzer The analyzer that should be called. - * @return True if the registration was successfull. + * @return True if the registration was successful. */ bool RegisterAnalyzerMapping(uint32_t identifier, AnalyzerPtr analyzer); + /** + * Registers a default analyzer. + * + * @param default_analyzer The analyzer to use as default. + */ + void RegisterDefaultAnalyzer(AnalyzerPtr default_analyzer); + /** * Analyzes the given packet. The data reference points to the part of the * raw packet to be analyzed. If the analyzed protocol encapsulates another @@ -95,6 +102,16 @@ public: protected: friend class Manager; + /** + * Looks up the analyzer for the encapsulated protocol based on the given + * identifier. + * + * @param identifier Identifier for the encapsulated protocol. + * @return The analyzer registered for the given identifier. Returns a + * nullptr if no analyzer is registered. + */ + AnalyzerPtr Lookup(uint32_t identifier) const; + /** * Triggers analysis of the encapsulated packet. The encapsulated protocol * is determined using the given identifier. @@ -105,12 +122,13 @@ protected: * * @return The outcome of the analysis. */ - AnalyzerResult AnalyzeInnerPacket(Packet* packet, const uint8_t*& data, - uint32_t identifier) const; + virtual AnalyzerResult AnalyzeInnerPacket(Packet* packet, const uint8_t*& data, + uint32_t identifier) const; private: Tag tag; Dispatcher dispatcher; + AnalyzerPtr default_analyzer = nullptr; void Init(const Tag& tag); }; diff --git a/src/packet_analysis/Manager.cc b/src/packet_analysis/Manager.cc index f7c97d89b4..b17911bcc4 100644 --- a/src/packet_analysis/Manager.cc +++ b/src/packet_analysis/Manager.cc @@ -36,9 +36,9 @@ void Manager::InitPostScript() auto* rv = mapping_val->At(i)->AsRecordVal(); //TODO: Make that field a string for usability reasons //TODO: Check error handling when fields are omitted - auto& parent_tag = rv->GetField("parent"); - std::string parent_name = parent_tag ? Lookup(parent_tag->AsEnumVal())->Name() : "ROOT"; - auto identifier = rv->GetField("identifier")->AsCount(); + auto& parent_val = rv->GetField("parent"); + std::string parent_name = parent_val ? Lookup(parent_val->AsEnumVal())->Name() : "ROOT"; + auto& identifier_val = rv->GetField("identifier"); auto analyzer_tag = rv->GetField("analyzer")->AsEnumVal(); auto analyzer_name = Lookup(analyzer_tag)->Name(); @@ -50,7 +50,11 @@ void Manager::InitPostScript() if ( parent_name == "ROOT" ) { - root_dispatcher.Register(identifier, analyzers[analyzer_name]); + if ( identifier_val ) + root_dispatcher.Register(identifier_val->AsCount(), + analyzers[analyzer_name]); + else + default_analyzer = analyzers[analyzer_name]; continue; } @@ -61,15 +65,13 @@ void Manager::InitPostScript() } auto& parent_analyzer = analyzers[parent_name]; - parent_analyzer->RegisterAnalyzerMapping(identifier, analyzers[analyzer_name]); + if ( identifier_val ) + parent_analyzer->RegisterAnalyzerMapping(identifier_val->AsCount(), + analyzers[analyzer_name]); + else + parent_analyzer->RegisterDefaultAnalyzer(analyzers[analyzer_name]); } - // Set default analyzer - auto da_it = analyzers.find("DefaultAnalyzer"); - if ( da_it == analyzers.end() ) - reporter->InternalError("DefaultAnalyzer not found."); - default_analyzer = da_it->second; - // Initialize all analyzers for ( auto& [name, analyzer] : analyzers ) analyzer->Initialize(); @@ -139,7 +141,12 @@ void Manager::ProcessPacket(Packet* packet) const uint8_t* data = packet->data; auto root_analyzer = root_dispatcher.Lookup(packet->link_type); - auto analyzer = root_analyzer == nullptr ? default_analyzer : root_analyzer; + auto analyzer = root_analyzer ? root_analyzer : default_analyzer; + if ( !analyzer ) + { + reporter->InternalWarning("No analyzer for link type %#x", packet->link_type); + return; + } auto result = analyzer->Analyze(packet, data); if (result == AnalyzerResult::Terminate) diff --git a/src/packet_analysis/protocol/default/Default.cc b/src/packet_analysis/protocol/default/Default.cc index 2b5c433ab1..de904f9ad7 100644 --- a/src/packet_analysis/protocol/default/Default.cc +++ b/src/packet_analysis/protocol/default/Default.cc @@ -24,3 +24,21 @@ zeek::packet_analysis::AnalyzerResult DefaultAnalyzer::Analyze(Packet* packet, c return AnalyzeInnerPacket(packet, data, protocol); } + +zeek::packet_analysis::AnalyzerResult DefaultAnalyzer::AnalyzeInnerPacket(Packet* packet, + const uint8_t*& data, uint32_t identifier) const + { + auto inner_analyzer = Lookup(identifier); + + if ( inner_analyzer == nullptr ) + { + DBG_LOG(DBG_PACKET_ANALYSIS, "Default analysis in %s failed, could not find analyzer for identifier %#x.", + GetAnalyzerName(), identifier); + packet->Weird("no_suitable_analyzer_found"); + return AnalyzerResult::Failed; + } + + DBG_LOG(DBG_PACKET_ANALYSIS, "Default analysis in %s succeeded, next layer identifier is %#x.", + GetAnalyzerName(), identifier); + return inner_analyzer->Analyze(packet, data); + } \ No newline at end of file diff --git a/src/packet_analysis/protocol/default/Default.h b/src/packet_analysis/protocol/default/Default.h index fbe03a83fc..9a37a11a44 100644 --- a/src/packet_analysis/protocol/default/Default.h +++ b/src/packet_analysis/protocol/default/Default.h @@ -18,6 +18,10 @@ public: { return std::make_shared(); } + +protected: + AnalyzerResult AnalyzeInnerPacket(Packet* packet, const uint8_t*& data, + uint32_t identifier) const override; }; }