Move old TCP analyzer into analyzer adapter in packet analysis tree

This commit is contained in:
Tim Wojtulewicz 2021-05-13 11:17:53 -07:00
parent b171f94729
commit f6e31107e1
25 changed files with 2243 additions and 2247 deletions

View file

@ -130,7 +130,7 @@ void Connection::Done()
// somewhere, but it's session-related, so maybe not?
if ( ConnTransport() == TRANSPORT_TCP )
{
auto ta = static_cast<analyzer::tcp::TCP_Analyzer*>(adapter);
auto* ta = static_cast<packet_analysis::TCP::TCPSessionAdapter*>(adapter);
assert(ta->IsAnalyzer("TCP"));
analyzer::tcp::TCP_Endpoint* to = ta->Orig();
analyzer::tcp::TCP_Endpoint* tr = ta->Resp();

View file

@ -30,7 +30,7 @@ bool RuleConditionTCPState::DoMatch(Rule* rule, RuleEndpointState* state,
if ( ! adapter || ! adapter->IsAnalyzer("TCP") )
return false;
auto* ta = static_cast<analyzer::tcp::TCP_Analyzer*>(adapter);
auto* ta = static_cast<packet_analysis::TCP::TCPSessionAdapter*>(adapter);
if ( tcpstates & RULE_STATE_STATELESS )
return true;

View file

@ -81,14 +81,6 @@ Manager::~Manager()
}
}
void Manager::InitPreScript()
{
// Cache these tags.
analyzer_connsize = GetComponentTag("CONNSIZE");
analyzer_stepping = GetComponentTag("STEPPINGSTONE");
analyzer_tcpstats = GetComponentTag("TCPSTATS");
}
void Manager::InitPostScript()
{
const auto& id = detail::global_scope()->Find("Tunnel::vxlan_ports");
@ -354,132 +346,6 @@ Manager::tag_set* Manager::LookupPort(TransportProto proto, uint32_t port, bool
return l;
}
bool Manager::BuildInitialAnalyzerTree(Connection* conn)
{
analyzer::tcp::TCP_Analyzer* tcp = nullptr;
packet_analysis::IP::SessionAdapter* root = nullptr;
analyzer::pia::PIA* pia = nullptr;
bool check_port = false;
switch ( conn->ConnTransport() ) {
case TRANSPORT_TCP:
root = tcp = new analyzer::tcp::TCP_Analyzer(conn);
pia = new analyzer::pia::PIA_TCP(conn);
check_port = true;
DBG_ANALYZER(conn, "activated TCP analyzer");
break;
default:
reporter->InternalWarning("unknown protocol can't build analyzer tree");
return false;
}
bool scheduled = ApplyScheduledAnalyzers(conn, false, root);
// Hmm... Do we want *just* the expected analyzer, or all
// other potential analyzers as well? For now we only take
// the scheduled ones.
if ( ! scheduled )
{ // Let's see if it's a port we know.
if ( check_port && ! zeek::detail::dpd_ignore_ports )
{
int resp_port = ntohs(conn->RespPort());
tag_set* ports = LookupPort(conn->ConnTransport(), resp_port, false);
if ( ports )
{
for ( tag_set::const_iterator j = ports->begin(); j != ports->end(); ++j )
{
Analyzer* analyzer = analyzer_mgr->InstantiateAnalyzer(*j, conn);
if ( ! analyzer )
continue;
root->AddChildAnalyzer(analyzer, false);
DBG_ANALYZER_ARGS(conn, "activated %s analyzer due to port %d",
analyzer_mgr->GetComponentName(*j).c_str(), resp_port);
}
}
}
}
if ( tcp )
{
// We have to decide whether to reassamble the stream.
// We turn it on right away if we already have an app-layer
// analyzer, reassemble_first_packets is true, or the user
// asks us to do so. In all other cases, reassembly may
// be turned on later by the TCP PIA.
bool reass = root->GetChildren().size() ||
zeek::detail::dpd_reassemble_first_packets ||
zeek::detail::tcp_content_deliver_all_orig ||
zeek::detail::tcp_content_deliver_all_resp;
if ( tcp_contents && ! reass )
{
static auto tcp_content_delivery_ports_orig = id::find_val<TableVal>("tcp_content_delivery_ports_orig");
static auto tcp_content_delivery_ports_resp = id::find_val<TableVal>("tcp_content_delivery_ports_resp");
const auto& dport = val_mgr->Port(ntohs(conn->RespPort()), TRANSPORT_TCP);
if ( ! reass )
reass = (bool)tcp_content_delivery_ports_orig->FindOrDefault(dport);
if ( ! reass )
reass = (bool)tcp_content_delivery_ports_resp->FindOrDefault(dport);
}
if ( reass )
tcp->EnableReassembly();
if ( IsEnabled(analyzer_stepping) )
{
// Add a SteppingStone analyzer if requested. The port
// should really not be hardcoded here, but as it can
// handle non-reassembled data, it doesn't really fit into
// our general framing ... Better would be to turn it
// on *after* we discover we have interactive traffic.
uint16_t resp_port = ntohs(conn->RespPort());
if ( resp_port == 22 || resp_port == 23 || resp_port == 513 )
{
static auto stp_skip_src = id::find_val<TableVal>("stp_skip_src");
auto src = make_intrusive<AddrVal>(conn->OrigAddr());
if ( ! stp_skip_src->FindOrDefault(src) )
tcp->AddChildAnalyzer(new analyzer::stepping_stone::SteppingStone_Analyzer(conn), false);
}
}
if ( IsEnabled(analyzer_tcpstats) )
// Add TCPStats analyzer. This needs to see packets so
// we cannot add it as a normal child.
tcp->AddChildPacketAnalyzer(new analyzer::tcp::TCPStats_Analyzer(conn));
if ( IsEnabled(analyzer_connsize) )
// Add ConnSize analyzer. Needs to see packets, not stream.
tcp->AddChildPacketAnalyzer(new analyzer::conn_size::ConnSize_Analyzer(conn));
}
else
{
if ( IsEnabled(analyzer_connsize) )
// Add ConnSize analyzer. Needs to see packets, not stream.
root->AddChildAnalyzer(new analyzer::conn_size::ConnSize_Analyzer(conn));
}
if ( pia )
root->AddChildAnalyzer(pia->AsAnalyzer());
conn->SetSessionAdapter(root, pia);
root->Init();
root->InitChildren();
PLUGIN_HOOK_VOID(HOOK_SETUP_ANALYZER_TREE, HookSetupAnalyzerTree(conn));
return true;
}
void Manager::ExpireScheduledAnalyzers()
{
if ( ! run_state::network_time )

View file

@ -67,12 +67,6 @@ public:
*/
~Manager();
/**
* First-stage initializion of the manager. This is called early on
* during Bro's initialization, before any scripts are processed.
*/
void InitPreScript();
/**
* Second-stage initialization of the manager. This is called late
* during Bro's initialization after any scripts are processed.
@ -246,17 +240,6 @@ public:
*/
Analyzer* InstantiateAnalyzer(const char* name, Connection* c);
/**
* Given the first packet of a connection, builds its initial
* analyzer tree.
*
* @param conn The connection to add the initial set of analyzers to.
*
* @return False if the tree cannot be built; that's usually an
* internal error.
*/
bool BuildInitialAnalyzerTree(Connection* conn);
/**
* Schedules a particular analyzer for an upcoming connection. Once
* the connection is seen, BuildInitAnalyzerTree() will add the
@ -366,10 +349,6 @@ private:
analyzer_map_by_port analyzers_by_port_tcp;
analyzer_map_by_port analyzers_by_port_udp;
Tag analyzer_connsize;
Tag analyzer_stepping;
Tag analyzer_tcpstats;
//// Data structures to track analyzed scheduled for future connections.
// The index for a scheduled connection.

View file

@ -35,7 +35,7 @@ Contents_Rsh_Analyzer::~Contents_Rsh_Analyzer()
void Contents_Rsh_Analyzer::DoDeliver(int len, const u_char* data)
{
analyzer::tcp::TCP_Analyzer* tcp = static_cast<analyzer::tcp::TCP_ApplicationAnalyzer*>(Parent())->TCP();
auto* tcp = static_cast<analyzer::tcp::TCP_ApplicationAnalyzer*>(Parent())->TCP();
assert(tcp);
int endp_state = IsOrig() ? tcp->OrigState() : tcp->RespState();

View file

@ -199,7 +199,7 @@ void PIA_TCP::Init()
if ( Parent()->IsAnalyzer("TCP") )
{
tcp::TCP_Analyzer* tcp = static_cast<tcp::TCP_Analyzer*>(Parent());
auto* tcp = static_cast<packet_analysis::TCP::TCPSessionAdapter*>(Parent());
SetTCP(tcp);
tcp->SetPIA(this);
}
@ -375,14 +375,12 @@ void PIA_TCP::ActivateAnalyzer(analyzer::Tag tag, const zeek::detail::Rule* rule
return;
}
tcp::TCP_Analyzer* tcp = (tcp::TCP_Analyzer*) Parent();
auto* tcp = static_cast<packet_analysis::TCP::TCPSessionAdapter*>(Parent());
tcp::TCP_Reassembler* reass_orig =
new tcp::TCP_Reassembler(this, tcp, tcp::TCP_Reassembler::Direct,
auto* reass_orig = new tcp::TCP_Reassembler(this, tcp, tcp::TCP_Reassembler::Direct,
tcp->Orig());
tcp::TCP_Reassembler* reass_resp =
new tcp::TCP_Reassembler(this, tcp, tcp::TCP_Reassembler::Direct,
auto* reass_resp = new tcp::TCP_Reassembler(this, tcp, tcp::TCP_Reassembler::Direct,
tcp->Resp());
uint64_t orig_seq = 0;

View file

@ -456,8 +456,7 @@ bool Contents_RPC::CheckResync(int& len, const u_char*& data, bool orig)
// is fully established we are in sync (since it's the first chunk
// of data after the SYN if its not established we need to
// resync.
analyzer::tcp::TCP_Analyzer* tcp =
static_cast<analyzer::tcp::TCP_ApplicationAnalyzer*>(Parent())->TCP();
auto* tcp = static_cast<analyzer::tcp::TCP_ApplicationAnalyzer*>(Parent())->TCP();
assert(tcp);
if ( (IsOrig() ? tcp->OrigState() : tcp->RespState()) !=

View file

@ -85,8 +85,7 @@ void ContentLine_Analyzer::DeliverStream(int len, const u_char* data,
if ( skip_partial )
{
TCP_Analyzer* tcp =
static_cast<TCP_ApplicationAnalyzer*>(Parent())->TCP();
auto* tcp = static_cast<TCP_ApplicationAnalyzer*>(Parent())->TCP();
if ( tcp && tcp->IsPartial() )
return;
@ -300,8 +299,7 @@ void ContentLine_Analyzer::CheckNUL()
// had been an initial SYN, so we check for whether
// the connection has at most two bytes so far.
TCP_Analyzer* tcp =
static_cast<TCP_ApplicationAnalyzer*>(Parent())->TCP();
auto* tcp = static_cast<TCP_ApplicationAnalyzer*>(Parent())->TCP();
if ( tcp )
{

View file

@ -10,7 +10,6 @@ class Plugin : public zeek::plugin::Plugin {
public:
zeek::plugin::Configuration Configure() override
{
AddComponent(new zeek::analyzer::Component("TCP", zeek::analyzer::tcp::TCP_Analyzer::Instantiate));
AddComponent(new zeek::analyzer::Component("TCPStats", zeek::analyzer::tcp::TCPStats_Analyzer::Instantiate));
AddComponent(new zeek::analyzer::Component("CONTENTLINE", nullptr));
AddComponent(new zeek::analyzer::Component("Contents", nullptr));

File diff suppressed because it is too large Load diff

View file

@ -6,16 +6,11 @@
#include "zeek/IPAddr.h"
#include "zeek/analyzer/protocol/tcp/TCP_Endpoint.h"
#include "zeek/analyzer/protocol/tcp/TCP_Flags.h"
#include "zeek/packet_analysis/protocol/ip/SessionAdapter.h"
#include "zeek/packet_analysis/protocol/tcp/TCPSessionAdapter.h"
#include "zeek/Conn.h"
// We define two classes here:
// - TCP_Analyzer is the analyzer for the TCP protocol itself.
// - TCP_ApplicationAnalyzer is an abstract base class for analyzers for a
// protocol running on top of TCP.
//
namespace zeek::analyzer::pia { class PIA_TCP; }
namespace zeek::packet_analysis::TCP { class TCPSessionAdapter; }
namespace zeek::analyzer::tcp {
@ -23,179 +18,13 @@ class TCP_Endpoint;
class TCP_Reassembler;
class TCP_ApplicationAnalyzer;
class TCP_Analyzer final : public packet_analysis::IP::SessionAdapter {
public:
explicit TCP_Analyzer(Connection* conn);
~TCP_Analyzer() override;
void EnableReassembly();
// Add a child analyzer that will always get the packets,
// independently of whether we do any reassembly.
void AddChildPacketAnalyzer(analyzer::Analyzer* a);
Analyzer* FindChild(analyzer::ID id) override;
Analyzer* FindChild(analyzer::Tag tag) override;
bool RemoveChildAnalyzer(analyzer::ID id) override;
// True if the connection has closed in some sense, false otherwise.
bool IsClosed() const { return orig->did_close || resp->did_close; }
bool BothClosed() const { return orig->did_close && resp->did_close; }
bool IsPartial() const { return is_partial; }
bool HadGap(bool orig) const;
TCP_Endpoint* Orig() const { return orig; }
TCP_Endpoint* Resp() const { return resp; }
int OrigState() const { return orig->state; }
int RespState() const { return resp->state; }
int OrigPrevState() const { return orig->prev_state; }
int RespPrevState() const { return resp->prev_state; }
uint32_t OrigSeq() const { return orig->LastSeq(); }
uint32_t RespSeq() const { return resp->LastSeq(); }
// True if either endpoint still has pending data. closing_endp
// is an endpoint that has indicated it is closing (i.e., for
// which we have seen a FIN) - for it, data is pending unless
// everything's been delivered up to the FIN. For its peer,
// the test is whether it has any outstanding, un-acked data.
bool DataPending(TCP_Endpoint* closing_endp);
void SetContentsFile(unsigned int direction, FilePtr f) override;
FilePtr GetContentsFile(unsigned int direction) const override;
// From Analyzer.h
void UpdateConnVal(RecordVal *conn_val) override;
int ParseTCPOptions(const struct tcphdr* tcp, bool is_orig);
static analyzer::Analyzer* Instantiate(Connection* conn)
{ return new TCP_Analyzer(conn); }
void AddExtraAnalyzers(Connection* conn) override {}
protected:
friend class TCP_ApplicationAnalyzer;
friend class TCP_Reassembler;
friend class analyzer::pia::PIA_TCP;
// Analyzer interface.
void Init() override;
void Done() override;
void DeliverPacket(int len, const u_char* data, bool orig, uint64_t seq,
const IP_Hdr* ip, int caplen) override;
void DeliverStream(int len, const u_char* data, bool orig) override;
void Undelivered(uint64_t seq, int len, bool orig) override;
void FlipRoles() override;
bool IsReuse(double t, const u_char* pkt) override;
// Returns the TCP header pointed to by data (which we assume is
// aligned), updating data, len & caplen. Returns nil if the header
// isn't fully present.
const struct tcphdr* ExtractTCP_Header(const u_char*& data, int& len,
int& caplen);
// Returns true if the checksum is valid, false if not (and in which
// case also updates the status history of the endpoint).
bool ValidateChecksum(const IP_Hdr* ip, const struct tcphdr* tp, TCP_Endpoint* endpoint,
int len, int caplen);
void SetPartialStatus(TCP_Flags flags, bool is_orig);
// Update the state machine of the TCPs based on the activity. This
// includes our pseudo-states such as TCP_ENDPOINT_PARTIAL.
//
// On return, do_close is true if we should consider the connection
// as closed, and gen_event if we shouuld generate an event about
// this fact.
void UpdateStateMachine(double t,
TCP_Endpoint* endpoint, TCP_Endpoint* peer,
uint32_t base_seq, uint32_t ack_seq,
int len, int32_t delta_last, bool is_orig, TCP_Flags flags,
bool& do_close, bool& gen_event);
void UpdateInactiveState(double t,
TCP_Endpoint* endpoint, TCP_Endpoint* peer,
uint32_t base_seq, uint32_t ack_seq,
int len, bool is_orig, TCP_Flags flags,
bool& do_close, bool& gen_event);
void UpdateSYN_SentState(TCP_Endpoint* endpoint, TCP_Endpoint* peer,
int len, bool is_orig, TCP_Flags flags,
bool& do_close, bool& gen_event);
void UpdateEstablishedState(TCP_Endpoint* endpoint, TCP_Endpoint* peer,
TCP_Flags flags, bool& do_close, bool& gen_event);
void UpdateClosedState(double t, TCP_Endpoint* endpoint,
int32_t delta_last, TCP_Flags flags,
bool& do_close);
void UpdateResetState(int len, TCP_Flags flags);
void GeneratePacketEvent(uint64_t rel_seq, uint64_t rel_ack,
const u_char* data, int len, int caplen,
bool is_orig, TCP_Flags flags);
bool DeliverData(double t, const u_char* data, int len, int caplen,
const IP_Hdr* ip, const struct tcphdr* tp,
TCP_Endpoint* endpoint, uint64_t rel_data_seq,
bool is_orig, TCP_Flags flags);
void CheckRecording(bool need_contents, TCP_Flags flags);
void CheckPIA_FirstPacket(bool is_orig, const IP_Hdr* ip);
friend class session::detail::Timer;
void AttemptTimer(double t);
void PartialCloseTimer(double t);
void ExpireTimer(double t);
void ResetTimer(double t);
void DeleteTimer(double t);
void ConnDeleteTimer(double t);
void EndpointEOF(TCP_Reassembler* endp);
void ConnectionClosed(TCP_Endpoint* endpoint,
TCP_Endpoint* peer, bool gen_event);
void ConnectionFinished(bool half_finished);
void ConnectionReset();
void PacketWithRST();
void SetReassembler(tcp::TCP_Reassembler* rorig, tcp::TCP_Reassembler* rresp);
// A couple utility functions that may also be useful to derived analyzers.
static uint64_t get_relative_seq(const TCP_Endpoint* endpoint,
uint32_t cur_base, uint32_t last,
uint32_t wraps, bool* underflow = nullptr);
static int get_segment_len(int payload_len, TCP_Flags flags);
private:
void SynWeirds(TCP_Flags flags, TCP_Endpoint* endpoint, int data_len) const;
TCP_Endpoint* orig;
TCP_Endpoint* resp;
analyzer_list packet_children;
unsigned int first_packet_seen: 2;
unsigned int reassembling: 1;
unsigned int is_partial: 1;
unsigned int is_active: 1;
unsigned int finished: 1;
// Whether we're waiting on final data delivery before closing
// this connection.
unsigned int close_deferred: 1;
// Whether to generate an event when we finally do close it.
unsigned int deferred_gen_event: 1;
// Whether we have seen the first ACK from the originator.
unsigned int seen_first_ACK: 1;
};
using TCP_Analyzer [[deprecated("Remove in v5.1. Use zeek::packet_analysis::TCP::TCPSessionAdapter.")]] =
packet_analysis::TCP::TCPSessionAdapter;
/**
* An abstract base class for analyzers for a protocol running on top
* of TCP.
*/
class TCP_ApplicationAnalyzer : public analyzer::Analyzer {
public:
TCP_ApplicationAnalyzer(const char* name, Connection* conn)
@ -208,14 +37,9 @@ public:
// This may be nil if we are not directly associated with a TCP
// analyzer (e.g., we're part of a tunnel decapsulation pipeline).
TCP_Analyzer* TCP()
{
return tcp ?
tcp :
static_cast<TCP_Analyzer*>(Conn()->FindAnalyzer("TCP"));
}
packet_analysis::TCP::TCPSessionAdapter* TCP();
void SetTCP(TCP_Analyzer* arg_tcp) { tcp = arg_tcp; }
void SetTCP(packet_analysis::TCP::TCPSessionAdapter* arg_tcp) { tcp = arg_tcp; }
// The given endpoint's data delivery is complete.
virtual void EndpointEOF(bool is_orig);
@ -225,7 +49,8 @@ public:
// is now fully closed, a connection_finished event will be
// generated; otherwise not.
virtual void ConnectionClosed(analyzer::tcp::TCP_Endpoint* endpoint,
analyzer::tcp::TCP_Endpoint* peer, bool gen_event);
analyzer::tcp::TCP_Endpoint* peer,
bool gen_event);
virtual void ConnectionFinished(bool half_finished);
virtual void ConnectionReset();
@ -247,7 +72,7 @@ public:
virtual void SetEnv(bool orig, char* name, char* val);
private:
TCP_Analyzer* tcp;
packet_analysis::TCP::TCPSessionAdapter* tcp;
};
class TCP_SupportAnalyzer : public analyzer::SupportAnalyzer {
@ -257,7 +82,7 @@ public:
~TCP_SupportAnalyzer() override {}
// These are passed on from TCP_Analyzer.
// These are passed on from TCPSessionAdapter.
virtual void EndpointEOF(bool is_orig) { }
virtual void ConnectionClosed(TCP_Endpoint* endpoint,
TCP_Endpoint* peer, bool gen_event) { }

View file

@ -18,7 +18,7 @@
namespace zeek::analyzer::tcp {
TCP_Endpoint::TCP_Endpoint(TCP_Analyzer* arg_analyzer, bool arg_is_orig)
TCP_Endpoint::TCP_Endpoint(packet_analysis::TCP::TCPSessionAdapter* arg_analyzer, bool arg_is_orig)
{
contents_processor = nullptr;
prev_state = state = TCP_ENDPOINT_INACTIVE;

View file

@ -10,9 +10,13 @@ namespace zeek {
class Connection;
class IP_Hdr;
namespace packet_analysis::TCP { class TCPSessionAdapter; }
namespace analyzer::tcp {
class TCP_Analyzer;
using TCP_Analyzer [[deprecated("Remove in v5.1. Use zeek::packet_analysis::TCP::TCPSessionAdapter.")]] =
zeek::packet_analysis::TCP::TCPSessionAdapter;
class TCP_Reassembler;
enum EndpointState {
@ -29,12 +33,12 @@ enum EndpointState {
// One endpoint of a TCP connection.
class TCP_Endpoint {
public:
TCP_Endpoint(TCP_Analyzer* analyzer, bool is_orig);
TCP_Endpoint(packet_analysis::TCP::TCPSessionAdapter* analyzer, bool is_orig);
~TCP_Endpoint();
void Done();
TCP_Analyzer* TCP() { return tcp_analyzer; }
packet_analysis::TCP::TCPSessionAdapter* TCP() { return tcp_analyzer; }
void SetPeer(TCP_Endpoint* p);
@ -212,7 +216,7 @@ public:
EndpointState state, prev_state;
TCP_Endpoint* peer;
TCP_Reassembler* contents_processor;
TCP_Analyzer* tcp_analyzer;
packet_analysis::TCP::TCPSessionAdapter* tcp_analyzer;
FilePtr contents_file;
double start_time, last_time;

View file

@ -6,6 +6,7 @@
#include "zeek/File.h"
#include "zeek/analyzer/Analyzer.h"
#include "zeek/analyzer/protocol/tcp/TCP.h"
#include "zeek/packet_analysis/protocol/tcp/TCPSessionAdapter.h"
#include "zeek/ZeekString.h"
#include "zeek/Reporter.h"
#include "zeek/RuleMatcher.h"
@ -21,7 +22,7 @@ constexpr bool DEBUG_tcp_connection_close = false;
constexpr bool DEBUG_tcp_match_undelivered = false;
TCP_Reassembler::TCP_Reassembler(analyzer::Analyzer* arg_dst_analyzer,
TCP_Analyzer* arg_tcp_analyzer,
packet_analysis::TCP::TCPSessionAdapter* arg_tcp_analyzer,
TCP_Reassembler::Type arg_type,
TCP_Endpoint* arg_endp)
: Reassembler(1, REASSEM_TCP)

View file

@ -6,6 +6,7 @@
#include "zeek/File.h"
namespace zeek {
namespace packet_analysis::TCP { class TCPSessionAdapter; }
class Connection;
@ -15,7 +16,8 @@ class Analyzer;
namespace tcp {
class TCP_Analyzer;
using TCP_Analyzer [[deprecated("Remove in v5.1. Use zeek::packet_analysis::TCP::TCPSessionAdapter.")]] =
zeek::packet_analysis::TCP::TCPSessionAdapter;
class TCP_Reassembler final : public Reassembler {
public:
@ -25,7 +27,7 @@ public:
};
TCP_Reassembler(analyzer::Analyzer* arg_dst_analyzer,
TCP_Analyzer* arg_tcp_analyzer,
packet_analysis::TCP::TCPSessionAdapter* arg_tcp_analyzer,
Type arg_type, TCP_Endpoint* arg_endp);
void Done();
@ -33,7 +35,7 @@ public:
void SetDstAnalyzer(analyzer::Analyzer* analyzer) { dst_analyzer = analyzer; }
void SetType(Type arg_type) { type = arg_type; }
TCP_Analyzer* GetTCPAnalyzer() { return tcp_analyzer; }
packet_analysis::TCP::TCPSessionAdapter* GetTCPAnalyzer() { return tcp_analyzer; }
// Returns the volume of data buffered in the reassembler.
// First parameter returns data that is above a hole, and thus is
@ -66,7 +68,7 @@ public:
void AckReceived(uint64_t seq);
// Checks if we have delivered all contents that we can possibly
// deliver for this endpoint. Calls TCP_Analyzer::EndpointEOF()
// deliver for this endpoint. Calls TCPSessionAdapter::EndpointEOF()
// when so.
void CheckEOF();
@ -113,7 +115,7 @@ private:
FilePtr record_contents_file; // file on which to reassemble contents
analyzer::Analyzer* dst_analyzer;
TCP_Analyzer* tcp_analyzer;
packet_analysis::TCP::TCPSessionAdapter* tcp_analyzer;
Type type;
};

View file

@ -27,7 +27,7 @@ function get_orig_seq%(cid: conn_id%): count
zeek::analyzer::Analyzer* tc = c->FindAnalyzer("TCP");
if ( tc )
return zeek::val_mgr->Count(static_cast<zeek::analyzer::tcp::TCP_Analyzer*>(tc)->OrigSeq());
return zeek::val_mgr->Count(static_cast<zeek::packet_analysis::TCP::TCPSessionAdapter*>(tc)->OrigSeq());
else
{
reporter->Error("connection does not have TCP analyzer");
@ -56,7 +56,7 @@ function get_resp_seq%(cid: conn_id%): count
zeek::analyzer::Analyzer* tc = c->FindAnalyzer("TCP");
if ( tc )
return zeek::val_mgr->Count(static_cast<zeek::analyzer::tcp::TCP_Analyzer*>(tc)->RespSeq());
return zeek::val_mgr->Count(static_cast<zeek::packet_analysis::TCP::TCPSessionAdapter*>(tc)->RespSeq());
else
{
reporter->Error("connection does not have TCP analyzer");

View file

@ -36,7 +36,7 @@ static zeek::Connection* add_connection()
static zeek::analyzer::Analyzer* add_analyzer(zeek::Connection* conn)
{
auto* tcp = new zeek::analyzer::tcp::TCP_Analyzer(conn);
auto* tcp = new zeek::packet_analysis::TCP::TCPSessionAdapter(conn);
auto* pia = new zeek::analyzer::pia::PIA_TCP(conn);
auto a = zeek::analyzer_mgr->InstantiateAnalyzer(ZEEK_FUZZ_ANALYZER, conn);
tcp->AddChildAnalyzer(a);

View file

@ -194,16 +194,7 @@ zeek::Connection* IPBasedAnalyzer::NewConn(const ConnTuple* id, const detail::Co
if ( flip )
conn->FlipRoles();
if ( ! new_plugin )
{
if ( ! analyzer_mgr->BuildInitialAnalyzerTree(conn) )
{
conn->Done();
Unref(conn);
return nullptr;
}
}
else if ( ! BuildSessionAnalyzerTree(conn) )
if ( ! BuildSessionAnalyzerTree(conn) )
{
conn->Done();
Unref(conn);

View file

@ -4,5 +4,5 @@ include(ZeekPlugin)
include_directories(BEFORE ${CMAKE_CURRENT_SOURCE_DIR} ${CMAKE_CURRENT_BINARY_DIR})
zeek_plugin_begin(PacketAnalyzer TCP_PKT)
zeek_plugin_cc(TCP.cc Plugin.cc)
zeek_plugin_cc(TCP.cc TCPSessionAdapter.cc Plugin.cc)
zeek_plugin_end()

View file

@ -3,6 +3,7 @@
#include "zeek/plugin/Plugin.h"
#include "zeek/packet_analysis/Component.h"
#include "zeek/packet_analysis/protocol/tcp/TCP.h"
#include "zeek/packet_analysis/protocol/tcp/TCPSessionAdapter.h"
namespace zeek::plugin::Zeek_TCP {
@ -12,6 +13,8 @@ public:
{
AddComponent(new zeek::packet_analysis::Component("TCP",
zeek::packet_analysis::TCP::TCPAnalyzer::Instantiate));
AddComponent(new zeek::analyzer::Component("TCP",
zeek::packet_analysis::TCP::TCPSessionAdapter::Instantiate));
zeek::plugin::Configuration config;
config.name = "Zeek::TCP_PKT";

View file

@ -2,18 +2,41 @@
#include "zeek/packet_analysis/protocol/tcp/TCP.h"
#include "zeek/RunState.h"
#include "zeek/analyzer/protocol/pia/PIA.h"
#include "zeek/packet_analysis/protocol/tcp/TCPSessionAdapter.h"
using namespace zeek::packet_analysis::TCP;
using namespace zeek::packet_analysis::IP;
TCPAnalyzer::TCPAnalyzer() : IPBasedAnalyzer("TCP", TRANSPORT_TCP, TCP_PORT_MASK, false)
{
new_plugin = true;
}
TCPAnalyzer::~TCPAnalyzer()
{
}
void TCPAnalyzer::Initialize()
{
}
SessionAdapter* TCPAnalyzer::MakeSessionAdapter(Connection* conn)
{
auto* root = new TCPSessionAdapter(conn);
root->SetParent(this);
conn->EnableStatusUpdateTimer();
conn->SetInactivityTimeout(zeek::detail::udp_inactivity_timeout);
return root;
}
zeek::analyzer::pia::PIA* TCPAnalyzer::MakePIA(Connection* conn)
{
return new analyzer::pia::PIA_TCP(conn);
}
bool TCPAnalyzer::BuildConnTuple(size_t len, const uint8_t* data, Packet* packet,
ConnTuple& tuple)
{
@ -74,3 +97,13 @@ bool TCPAnalyzer::WantConnection(uint16_t src_port, uint16_t dst_port,
return true;
}
void TCPAnalyzer::DeliverPacket(Connection* c, double t, bool is_orig, int remaining, Packet* pkt)
{
auto* ta = static_cast<TCPSessionAdapter*>(c->GetSessionAdapter());
const u_char* data = pkt->ip_hdr->Payload();
int len = pkt->ip_hdr->PayloadLen();
ta->DeliverPacket(len, data, is_orig, {}, pkt->ip_hdr.get(), remaining);
}

View file

@ -18,14 +18,12 @@ public:
return std::make_shared<TCPAnalyzer>();
}
/**
* Returns an adapter appropriate for this IP-based analyzer. This adapter is used to
* hook into the session analyzer framework. This function can also be used to do any
* extra initialization of connection timers, etc.
*
* TODO: this is a stub until the TCP analyzer moves to the packet analysis framework.
/*
* Initialize the analyzer. This method is called after the configuration
* was read. Derived classes can override this method to implement custom
* initialization.
*/
IP::SessionAdapter* MakeSessionAdapter(Connection* conn) override { return nullptr; }
void Initialize() override;
protected:
@ -35,6 +33,9 @@ protected:
bool BuildConnTuple(size_t len, const uint8_t* data, Packet* packet,
ConnTuple& tuple) override;
void DeliverPacket(Connection* c, double t, bool is_orig, int remaining,
Packet* pkt) override;
/**
* Upon seeing the first packet of a connection, checks whether we want
* to analyze it (e.g. we may not want to look at partial connections)
@ -49,6 +50,19 @@ protected:
*/
bool WantConnection(uint16_t src_port, uint16_t dst_port,
const u_char* data, bool& flip_roles) const override;
/**
* Returns an analyzer adapter appropriate for this IP-based analyzer. This adapter
* is used to hook into the session analyzer framework. This function can also be used
* to do any extra initialization of connection timers, etc.
*/
packet_analysis::IP::SessionAdapter* MakeSessionAdapter(Connection* conn) override;
/**
* Returns a PIA appropriate for this IP-based analyzer. This method is optional to
* override in child classes, as not all analyzers need a PIA.
*/
analyzer::pia::PIA* MakePIA(Connection* conn) override;
};
}

File diff suppressed because it is too large Load diff

View file

@ -0,0 +1,197 @@
// See the file "COPYING" in the main distribution directory for copyright.
#pragma once
#include "zeek/packet_analysis/Analyzer.h"
#include "zeek/packet_analysis/Component.h"
#include "zeek/packet_analysis/protocol/ip/SessionAdapter.h"
#include "zeek/session/Manager.h"
#include "zeek/analyzer/protocol/tcp/TCP_Flags.h"
namespace zeek::analyzer::pia { class PIA_TCP; }
namespace zeek::analyzer::tcp {
class TCP_Endpoint;
class TCP_Reassembler;
}
namespace zeek::packet_analysis::TCP {
class TCPAnalyzer;
class TCPSessionAdapter final : public packet_analysis::IP::SessionAdapter {
public:
explicit TCPSessionAdapter(Connection* conn);
~TCPSessionAdapter() override;
void EnableReassembly();
// Add a child analyzer that will always get the packets,
// independently of whether we do any reassembly.
void AddChildPacketAnalyzer(analyzer::Analyzer* a);
Analyzer* FindChild(analyzer::ID id) override;
Analyzer* FindChild(analyzer::Tag tag) override;
bool RemoveChildAnalyzer(analyzer::ID id) override;
// True if the connection has closed in some sense, false otherwise.
bool IsClosed() const { return orig->did_close || resp->did_close; }
bool BothClosed() const { return orig->did_close && resp->did_close; }
bool IsPartial() const { return is_partial; }
bool HadGap(bool orig) const;
analyzer::tcp::TCP_Endpoint* Orig() const { return orig; }
analyzer::tcp::TCP_Endpoint* Resp() const { return resp; }
int OrigState() const { return orig->state; }
int RespState() const { return resp->state; }
int OrigPrevState() const { return orig->prev_state; }
int RespPrevState() const { return resp->prev_state; }
uint32_t OrigSeq() const { return orig->LastSeq(); }
uint32_t RespSeq() const { return resp->LastSeq(); }
// True if either endpoint still has pending data. closing_endp
// is an endpoint that has indicated it is closing (i.e., for
// which we have seen a FIN) - for it, data is pending unless
// everything's been delivered up to the FIN. For its peer,
// the test is whether it has any outstanding, un-acked data.
bool DataPending(analyzer::tcp::TCP_Endpoint* closing_endp);
void SetContentsFile(unsigned int direction, FilePtr f) override;
FilePtr GetContentsFile(unsigned int direction) const override;
// From Analyzer.h
void UpdateConnVal(RecordVal *conn_val) override;
int ParseTCPOptions(const struct tcphdr* tcp, bool is_orig);
static analyzer::Analyzer* Instantiate(Connection* conn)
{ return new TCPSessionAdapter(conn); }
void AddExtraAnalyzers(Connection* conn) override;
protected:
friend class analyzer::tcp::TCP_ApplicationAnalyzer;
friend class analyzer::tcp::TCP_Reassembler;
friend class analyzer::pia::PIA_TCP;
friend class packet_analysis::TCP::TCPAnalyzer;
// Analyzer interface.
void Init() override;
void Done() override;
void DeliverPacket(int len, const u_char* data, bool orig, uint64_t seq,
const IP_Hdr* ip, int caplen) override;
void DeliverStream(int len, const u_char* data, bool orig) override;
void Undelivered(uint64_t seq, int len, bool orig) override;
void FlipRoles() override;
bool IsReuse(double t, const u_char* pkt) override;
// Returns the TCP header pointed to by data (which we assume is
// aligned), updating data, len & caplen. Returns nil if the header
// isn't fully present.
const struct tcphdr* ExtractTCP_Header(const u_char*& data, int& len,
int& caplen);
// Returns true if the checksum is valid, false if not (and in which
// case also updates the status history of the endpoint).
bool ValidateChecksum(const IP_Hdr* ip, const struct tcphdr* tp, analyzer::tcp::TCP_Endpoint* endpoint,
int len, int caplen);
void SetPartialStatus(analyzer::tcp::TCP_Flags flags, bool is_orig);
// Update the state machine of the TCPs based on the activity. This
// includes our pseudo-states such as TCP_ENDPOINT_PARTIAL.
//
// On return, do_close is true if we should consider the connection
// as closed, and gen_event if we shouuld generate an event about
// this fact.
void UpdateStateMachine(double t,
analyzer::tcp::TCP_Endpoint* endpoint, analyzer::tcp::TCP_Endpoint* peer,
uint32_t base_seq, uint32_t ack_seq,
int len, int32_t delta_last, bool is_orig, analyzer::tcp::TCP_Flags flags,
bool& do_close, bool& gen_event);
void UpdateInactiveState(double t,
analyzer::tcp::TCP_Endpoint* endpoint, analyzer::tcp::TCP_Endpoint* peer,
uint32_t base_seq, uint32_t ack_seq,
int len, bool is_orig, analyzer::tcp::TCP_Flags flags,
bool& do_close, bool& gen_event);
void UpdateSYN_SentState(analyzer::tcp::TCP_Endpoint* endpoint, analyzer::tcp::TCP_Endpoint* peer,
int len, bool is_orig, analyzer::tcp::TCP_Flags flags,
bool& do_close, bool& gen_event);
void UpdateEstablishedState(analyzer::tcp::TCP_Endpoint* endpoint, analyzer::tcp::TCP_Endpoint* peer,
analyzer::tcp::TCP_Flags flags, bool& do_close, bool& gen_event);
void UpdateClosedState(double t, analyzer::tcp::TCP_Endpoint* endpoint,
int32_t delta_last, analyzer::tcp::TCP_Flags flags,
bool& do_close);
void UpdateResetState(int len, analyzer::tcp::TCP_Flags flags);
void GeneratePacketEvent(uint64_t rel_seq, uint64_t rel_ack,
const u_char* data, int len, int caplen,
bool is_orig, analyzer::tcp::TCP_Flags flags);
bool DeliverData(double t, const u_char* data, int len, int caplen,
const IP_Hdr* ip, const struct tcphdr* tp,
analyzer::tcp::TCP_Endpoint* endpoint, uint64_t rel_data_seq,
bool is_orig, analyzer::tcp::TCP_Flags flags);
void CheckRecording(bool need_contents, analyzer::tcp::TCP_Flags flags);
void CheckPIA_FirstPacket(bool is_orig, const IP_Hdr* ip);
friend class session::detail::Timer;
void AttemptTimer(double t);
void PartialCloseTimer(double t);
void ExpireTimer(double t);
void ResetTimer(double t);
void DeleteTimer(double t);
void ConnDeleteTimer(double t);
void EndpointEOF(analyzer::tcp::TCP_Reassembler* endp);
void ConnectionClosed(analyzer::tcp::TCP_Endpoint* endpoint,
analyzer::tcp::TCP_Endpoint* peer, bool gen_event);
void ConnectionFinished(bool half_finished);
void ConnectionReset();
void PacketWithRST();
void SetReassembler(analyzer::tcp::TCP_Reassembler* rorig, analyzer::tcp::TCP_Reassembler* rresp);
// A couple utility functions that may also be useful to derived analyzers.
static uint64_t get_relative_seq(const analyzer::tcp::TCP_Endpoint* endpoint,
uint32_t cur_base, uint32_t last,
uint32_t wraps, bool* underflow = nullptr);
static int get_segment_len(int payload_len, analyzer::tcp::TCP_Flags flags);
private:
void SynWeirds(analyzer::tcp::TCP_Flags flags, analyzer::tcp::TCP_Endpoint* endpoint, int data_len) const;
analyzer::tcp::TCP_Endpoint* orig;
analyzer::tcp::TCP_Endpoint* resp;
analyzer::analyzer_list packet_children;
unsigned int first_packet_seen: 2;
unsigned int reassembling: 1;
unsigned int is_partial: 1;
unsigned int is_active: 1;
unsigned int finished: 1;
// Whether we're waiting on final data delivery before closing
// this connection.
unsigned int close_deferred: 1;
// Whether to generate an event when we finally do close it.
unsigned int deferred_gen_event: 1;
// Whether we have seen the first ACK from the originator.
unsigned int seen_first_ACK: 1;
};
} // namespace zeek::packet_analysis::tcp

View file

@ -595,7 +595,6 @@ SetupResult setup(int argc, char** argv, Options* zopts)
trigger_mgr = new trigger::Manager();
plugin_mgr->InitPreScript();
analyzer_mgr->InitPreScript();
file_mgr->InitPreScript();
zeekygen_mgr->InitPreScript();