SessionAdapter: Introduce TapAnalyzer for session adapter

This commit introduces a mechanism to attach light weight analyzers to
the root analyzer of sessions in order to tap into the packets delivered
to child analyzer.
This commit is contained in:
Arne Welzel 2025-08-02 12:32:32 +02:00
parent 56325d1412
commit dc904b2216
11 changed files with 355 additions and 5 deletions

View file

@ -2,13 +2,90 @@
#pragma once
#include <memory>
#include "zeek/analyzer/Analyzer.h"
#include "zeek/iosource/Packet.h"
namespace zeek::analyzer::pia {
class PIA;
}
namespace zeek::packet_analysis::IP {
namespace zeek::packet_analysis {
/**
* Indicator for a TapAnalyzer to determine what will happen to a packet.
*/
enum class PacketAction : uint8_t {
Deliver, ///< Packet will be delivered to child protocol analyzers.
Skip, ///< Processing of this packet will be skipped.
};
/**
* Reason why delivery of a packet would be skipped.
*/
enum class SkipReason : uint8_t {
None, ///< None is used when the verdict is Deliver.
Unknown, ///< Placeholder if no other value fits.
BadChecksum, ///< The packet's checksum is invalid and ignore_checksums is false.
BadProtoHeader, ///< Something was off with the lengths or offsets in the protocol header.
};
/**
* A lightweight analyzer that receives all packets passing through session adapters.
*
* A use case of tap analyzers is to attach them during HookSetupAnalyzerTree() to
* observe all raw packets of a session, including those that are invalid or corrupt
* and aren't delivered to child protocol analyzers.
*
* The Packet class has an *is_orig* field if directionality is required. Additionally,
* the Connection instance available during HookSetupAnalyzerTree() can be stored into
* a custom TapAnalyzer, allowing to associate packets with a given Connection. However,
* the TapAnalyzer interface itself does not provide provisions for this use case.
*/
class TapAnalyzer {
public:
virtual ~TapAnalyzer() = default;
/**
* Hook of a tap analyzer for receiving packet data.
*
* @param pkt The packet being processed.
* @param action Either Deliver or Skip as determined by session analyzers.
* @param skip_reason If verdict is Skip, an indication why this packet is skipped, otherwise None.
*/
virtual void TapPacket(const Packet& pkt, PacketAction action, SkipReason skip_reason) = 0;
/**
* Hook for when the script-level connection record is updated.
*
* This is invoked when the session's UpdateConnVal() method has invoked UpdateConnVal()
* on all protocol analyzers attached to the session.
*
* @param conn_val The script-level connection record associated with the
* Connection this TapAnalyzer is attached to.
*/
virtual void UpdateConnVal(RecordVal* conn_val) {}
/**
* Hook for initialization before tapping begins.
*
* This method is invoked after a tap analyzer has been added to a SessionAdapter.
*/
virtual void Init() {};
/**
* Hook for when this analyzer is about to be removed and destructed.
*
* This is invoked when the session's Done() method is invoked, just before
* the TapAnalyzer instance is destroyed.
*/
virtual void Done() {};
};
using TapAnalyzerPtr = std::unique_ptr<TapAnalyzer>;
namespace IP {
class IPBasedAnalyzer;
@ -94,9 +171,45 @@ public:
*/
void PacketContents(const u_char* data, int len);
/**
* Adds a TapAnalyzer instance to this session adapter.
*
* @param ta The TapAnalyzer instance to attach.
*/
void AddTapAnalyzer(TapAnalyzerPtr ta);
/**
* Remove a TapAnalyzer instance by raw pointer.
*
* Note that the TapAnalyzer instance \a ta is pointing at will be destroyed
* during the call to RemoveTapAanalyzer() and should be discarded by the caller
* immediately. If you call RemoveTapAnalyzer() from within a TapAnalyzer's member
* function, ensure not accessing \a this afterwards.
*
* @param ta The raw pointer to the TapAnalyzer instance to remove.
*/
bool RemoveTapAnalyzer(const TapAnalyzer* ta);
/**
* Helper to forward a packet to all attached TapAnalyzer instances.
*
* @param pkt The packet.
* @param verdict Whether the packet will be delivered or skipped.
* @param skip_reason If verdict is Skip, should be an indication why this packet is skipped.
*/
void TapPacket(const Packet* pkt, PacketAction verdict = PacketAction::Deliver,
SkipReason skip_reason = SkipReason::None) const;
/**
* Overridden from parent class, calling UpdateConnVal() on TapAnalyzer instances, too.
*/
void UpdateConnVal(RecordVal* conn_val) override;
protected:
IPBasedAnalyzer* parent = nullptr;
analyzer::pia::PIA* pia = nullptr;
std::vector<TapAnalyzerPtr> tap_analyzers;
};
} // namespace zeek::packet_analysis::IP
} // namespace IP
} // namespace zeek::packet_analysis