From 29bc84e1d64a9550fe0e95eb580bc422de1539b4 Mon Sep 17 00:00:00 2001 From: Jan Grashoefer Date: Mon, 12 Aug 2024 11:59:30 +0200 Subject: [PATCH] Add packet analyzer history --- scripts/policy/misc/unknown-protocols.zeek | 9 ++++++++- src/event.bif | 6 +++++- src/packet_analysis/Analyzer.cc | 2 ++ src/packet_analysis/Manager.cc | 14 +++++++++++++- src/packet_analysis/Manager.h | 17 +++++++++++++++++ 5 files changed, 45 insertions(+), 3 deletions(-) diff --git a/scripts/policy/misc/unknown-protocols.zeek b/scripts/policy/misc/unknown-protocols.zeek index df510d9846..c532f7b0f5 100644 --- a/scripts/policy/misc/unknown-protocols.zeek +++ b/scripts/policy/misc/unknown-protocols.zeek @@ -25,16 +25,23 @@ export { ## A certain number of bytes at the start of the unknown protocol's ## header. first_bytes: string &log; + + ## The chain of packet analyzers that processed the packet up to this + ## point. This includes the history of encapsulating packets in case + ## of tunneling. + analyzer_history: vector of string &log; }; } -event unknown_protocol(analyzer_name: string, protocol: count, first_bytes: string) +event unknown_protocol(analyzer_name: string, protocol: count, first_bytes: string, + analyzer_history: string_vec) { local info : Info; info$ts = network_time(); info$analyzer = analyzer_name; info$protocol_id = fmt("0x%x", protocol); info$first_bytes = bytestring_to_hexstr(first_bytes); + info$analyzer_history = analyzer_history; Log::write(LOG, info); } diff --git a/src/event.bif b/src/event.bif index 38e15bf09f..b925f02144 100644 --- a/src/event.bif +++ b/src/event.bif @@ -885,8 +885,12 @@ event Pcap::file_done%(path: string%); ## ## first_bytes: A certain number of bytes at the start of the unknown protocol's header. ## +## analyzer_history: The chain of packet analyzers that processed the packet up to this +## point. This includes the history of encapsulating packets in case +## of tunneling. +## ## .. zeek:see:: UnknownProtocol::first_bytes_count -event unknown_protocol%(analyzer_name: string, protocol: count, first_bytes: string%); +event unknown_protocol%(analyzer_name: string, protocol: count, first_bytes: string, analyzer_history: string_vec%); ## An event for handling packets that reached the end of processing without ## being marked as processed. Note that this event may lead to unpredictable diff --git a/src/packet_analysis/Analyzer.cc b/src/packet_analysis/Analyzer.cc index ee067e4513..b272ec4965 100644 --- a/src/packet_analysis/Analyzer.cc +++ b/src/packet_analysis/Analyzer.cc @@ -114,6 +114,7 @@ bool Analyzer::ForwardPacket(size_t len, const uint8_t* data, Packet* packet, ui DBG_LOG(DBG_PACKET_ANALYSIS, "Analysis in %s succeeded, next layer identifier is %#x.", GetAnalyzerName(), identifier); + packet_mgr->TrackAnalyzer(inner_analyzer); return inner_analyzer->AnalyzePacket(len, data, packet); } @@ -129,6 +130,7 @@ bool Analyzer::ForwardPacket(size_t len, const uint8_t* data, Packet* packet) co return false; } + packet_mgr->TrackAnalyzer(inner_analyzer); return inner_analyzer->AnalyzePacket(len, data, packet); } diff --git a/src/packet_analysis/Manager.cc b/src/packet_analysis/Manager.cc index 259aefd37d..c04cb7b17e 100644 --- a/src/packet_analysis/Manager.cc +++ b/src/packet_analysis/Manager.cc @@ -113,6 +113,7 @@ void Manager::ProcessPacket(Packet* packet) { } // Start packet analysis + analyzer_stack.clear(); root_analyzer->ForwardPacket(packet->cap_len, packet->data, packet, packet->link_type); if ( ! packet->processed ) { @@ -227,13 +228,24 @@ bool Manager::PermitUnknownProtocol(const std::string& analyzer, uint32_t protoc return false; } +zeek::VectorValPtr Manager::BuildAnalyzerHistory() const { + auto history = zeek::make_intrusive(zeek::id::string_vec); + + for ( unsigned int i = 0; i < analyzer_stack.size(); i++ ) { + auto analyzer_name = analyzer_stack[i]->GetAnalyzerName(); + history->Assign(i, make_intrusive(analyzer_name)); + } + + return history; +} + void Manager::ReportUnknownProtocol(const std::string& analyzer, uint32_t protocol, const uint8_t* data, size_t len) { if ( unknown_protocol ) { if ( PermitUnknownProtocol(analyzer, protocol) ) { int bytes_len = std::min(unknown_first_bytes_count, static_cast(len)); event_mgr.Enqueue(unknown_protocol, make_intrusive(analyzer), val_mgr->Count(protocol), - make_intrusive(bytes_len, (const char*)data)); + make_intrusive(bytes_len, (const char*)data), BuildAnalyzerHistory()); } } } diff --git a/src/packet_analysis/Manager.h b/src/packet_analysis/Manager.h index dac81c99d9..833c7ccde2 100644 --- a/src/packet_analysis/Manager.h +++ b/src/packet_analysis/Manager.h @@ -176,6 +176,13 @@ public: */ uint64_t GetUnprocessedCount() const { return total_not_processed; } + /** + * Tracks the given analyzer for the current packet's analyzer history. + * The packet analyzer history is implemented in form of a stack, which is reset on a + * call to ProcessPacket() but maintained throughout calls to ProcessInnerPacket(). + */ + void TrackAnalyzer(AnalyzerPtr analyzer) { analyzer_stack.push_back(std::move(analyzer)); } + private: /** * Instantiates a new analyzer instance. @@ -197,6 +204,14 @@ private: */ AnalyzerPtr InstantiateAnalyzer(const std::string& name); + /** + * Generates a string vector that represents the analyzer history of the + * current packet based on the analyzers' tags. + * + * @return A vector of strings representing the packet analyzer history. + */ + VectorValPtr BuildAnalyzerHistory() const; + bool PermitUnknownProtocol(const std::string& analyzer, uint32_t protocol); std::map analyzers; @@ -216,6 +231,8 @@ private: uint64_t total_not_processed = 0; iosource::PktDumper* unprocessed_dumper = nullptr; + + std::vector analyzer_stack; }; } // namespace packet_analysis