mirror of
https://github.com/zeek/zeek.git
synced 2025-10-17 05:58:20 +00:00
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:
parent
56325d1412
commit
dc904b2216
11 changed files with 355 additions and 5 deletions
|
@ -13,6 +13,7 @@
|
|||
#include "zeek/analyzer/Manager.h"
|
||||
#include "zeek/packet_analysis/protocol/icmp/ICMPSessionAdapter.h"
|
||||
#include "zeek/packet_analysis/protocol/icmp/events.bif.h"
|
||||
#include "zeek/packet_analysis/protocol/ip/SessionAdapter.h"
|
||||
#include "zeek/session/Manager.h"
|
||||
|
||||
using namespace zeek::packet_analysis::ICMP;
|
||||
|
@ -80,6 +81,7 @@ void ICMPAnalyzer::DeliverPacket(Connection* c, double t, bool is_orig, int rema
|
|||
|
||||
if ( chksum != 0xffff ) {
|
||||
adapter->Weird("bad_ICMP_checksum");
|
||||
adapter->TapPacket(pkt, PacketAction::Skip, SkipReason::BadChecksum);
|
||||
return;
|
||||
}
|
||||
}
|
||||
|
@ -112,6 +114,9 @@ void ICMPAnalyzer::DeliverPacket(Connection* c, double t, bool is_orig, int rema
|
|||
|
||||
ForwardPacket(std::min(len, remaining), data, pkt);
|
||||
|
||||
// Tap the packet before sending it to protocol analysis.
|
||||
adapter->TapPacket(pkt);
|
||||
|
||||
if ( remaining >= len )
|
||||
adapter->ForwardPacket(len, data, is_orig, -1, ip.get(), remaining);
|
||||
|
||||
|
|
|
@ -8,7 +8,14 @@
|
|||
|
||||
using namespace zeek::packet_analysis::IP;
|
||||
|
||||
void SessionAdapter::Done() { Analyzer::Done(); }
|
||||
void SessionAdapter::Done() {
|
||||
Analyzer::Done();
|
||||
for ( const auto& ta : tap_analyzers )
|
||||
ta->Done();
|
||||
|
||||
// Ensure no more TapPacket() calls after Done() on TapAnalyzer instances.
|
||||
tap_analyzers.clear();
|
||||
}
|
||||
|
||||
bool SessionAdapter::IsReuse(double t, const u_char* pkt) { return parent->IsReuse(t, pkt); }
|
||||
|
||||
|
@ -28,3 +35,37 @@ void SessionAdapter::PacketContents(const u_char* data, int len) {
|
|||
EnqueueConnEvent(packet_contents, ConnVal(), std::move(contents));
|
||||
}
|
||||
}
|
||||
|
||||
void SessionAdapter::AddTapAnalyzer(TapAnalyzerPtr ta) {
|
||||
assert(! IsFinished());
|
||||
tap_analyzers.push_back(std::move(ta));
|
||||
tap_analyzers.back()->Init();
|
||||
}
|
||||
|
||||
bool SessionAdapter::RemoveTapAnalyzer(const TapAnalyzer* ta) {
|
||||
// Find the raw pointer, call Done(), remove it, thereby destructing it.
|
||||
for ( auto it = tap_analyzers.begin(); it != tap_analyzers.end(); ++it ) {
|
||||
if ( it->get() == ta ) {
|
||||
// Ensure Done() is called only after removal from tap_analyzers.
|
||||
auto ptr{std::move(*it)};
|
||||
tap_analyzers.erase(it);
|
||||
ptr->Done();
|
||||
ptr.reset();
|
||||
return true;
|
||||
}
|
||||
}
|
||||
|
||||
return false;
|
||||
}
|
||||
|
||||
void SessionAdapter::TapPacket(const Packet* pkt, PacketAction action, SkipReason skip_reason) const {
|
||||
for ( const auto& ta : tap_analyzers )
|
||||
ta->TapPacket(*pkt, action, skip_reason);
|
||||
}
|
||||
|
||||
void SessionAdapter::UpdateConnVal(RecordVal* conn_val) {
|
||||
Analyzer::UpdateConnVal(conn_val);
|
||||
|
||||
for ( const auto& ta : tap_analyzers )
|
||||
ta->UpdateConnVal(conn_val);
|
||||
}
|
||||
|
|
|
@ -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
|
||||
|
|
|
@ -4,6 +4,7 @@
|
|||
|
||||
#include "zeek/RunState.h"
|
||||
#include "zeek/analyzer/protocol/pia/PIA.h"
|
||||
#include "zeek/packet_analysis/protocol/ip/SessionAdapter.h"
|
||||
#include "zeek/packet_analysis/protocol/tcp/TCPSessionAdapter.h"
|
||||
|
||||
using namespace zeek;
|
||||
|
@ -83,8 +84,10 @@ void TCPAnalyzer::DeliverPacket(Connection* c, double t, bool is_orig, int remai
|
|||
auto* adapter = static_cast<TCPSessionAdapter*>(c->GetSessionAdapter());
|
||||
|
||||
const struct tcphdr* tp = ExtractTCP_Header(data, len, remaining, adapter);
|
||||
if ( ! tp )
|
||||
if ( ! tp ) {
|
||||
adapter->TapPacket(pkt, PacketAction::Skip, SkipReason::BadProtoHeader);
|
||||
return;
|
||||
}
|
||||
|
||||
// We need the min() here because Ethernet frame padding can lead to
|
||||
// remaining > len.
|
||||
|
@ -95,8 +98,10 @@ void TCPAnalyzer::DeliverPacket(Connection* c, double t, bool is_orig, int remai
|
|||
analyzer::tcp::TCP_Endpoint* peer = endpoint->peer;
|
||||
const std::shared_ptr<IP_Hdr>& ip = pkt->ip_hdr;
|
||||
|
||||
if ( ! ValidateChecksum(ip.get(), tp, endpoint, len, remaining, adapter) )
|
||||
if ( ! ValidateChecksum(ip.get(), tp, endpoint, len, remaining, adapter) ) {
|
||||
adapter->TapPacket(pkt, PacketAction::Skip, SkipReason::BadChecksum);
|
||||
return;
|
||||
}
|
||||
|
||||
adapter->Process(is_orig, tp, len, ip, data, remaining);
|
||||
|
||||
|
@ -107,6 +112,9 @@ void TCPAnalyzer::DeliverPacket(Connection* c, double t, bool is_orig, int remai
|
|||
// Send the packet back into the packet analysis framework.
|
||||
ForwardPacket(std::min(len, remaining), data, pkt);
|
||||
|
||||
// Tap the packet before sending it to session analysis.
|
||||
adapter->TapPacket(pkt);
|
||||
|
||||
// Call DeliverPacket on the adapter directly here. Normally we'd call ForwardPacket
|
||||
// but this adapter does some other things in its DeliverPacket with the packet children
|
||||
// analyzers.
|
||||
|
|
|
@ -8,6 +8,7 @@
|
|||
#include "zeek/RunState.h"
|
||||
#include "zeek/analyzer/Manager.h"
|
||||
#include "zeek/analyzer/protocol/pia/PIA.h"
|
||||
#include "zeek/packet_analysis/protocol/ip/SessionAdapter.h"
|
||||
#include "zeek/packet_analysis/protocol/udp/UDPSessionAdapter.h"
|
||||
#include "zeek/packet_analysis/protocol/udp/events.bif.h"
|
||||
#include "zeek/session/Manager.h"
|
||||
|
@ -126,6 +127,7 @@ void UDPAnalyzer::DeliverPacket(Connection* c, double t, bool is_orig, int remai
|
|||
|
||||
if ( bad ) {
|
||||
adapter->HandleBadChecksum(is_orig);
|
||||
adapter->TapPacket(pkt, PacketAction::Skip, SkipReason::BadChecksum);
|
||||
return;
|
||||
}
|
||||
}
|
||||
|
@ -194,6 +196,9 @@ void UDPAnalyzer::DeliverPacket(Connection* c, double t, bool is_orig, int remai
|
|||
// detection has to be used.
|
||||
ForwardPacket(std::min(len, remaining), data, pkt, ntohs(c->RespPort()));
|
||||
|
||||
// Tap the packet before sending it to session analysis.
|
||||
adapter->TapPacket(pkt);
|
||||
|
||||
// Forward any data through session-analysis, too.
|
||||
adapter->ForwardPacket(std::min(len, remaining), data, is_orig, -1, ip.get(), pkt->cap_len);
|
||||
}
|
||||
|
|
Loading…
Add table
Add a link
Reference in a new issue