Add new Session base class

This is mostly code copied from the existing Connection class, as that class now
inherits from Session.
This commit is contained in:
Tim Wojtulewicz 2021-03-08 12:34:45 -07:00
parent c752d76052
commit 8fbab9408a
8 changed files with 618 additions and 319 deletions

View file

@ -286,6 +286,7 @@ set(MAIN_SRCS
Scope.cc
ScriptCoverageManager.cc
SerializationFormat.cc
Session.cc
Sessions.cc
SmithWaterman.cc
Stats.cc

View file

@ -21,53 +21,18 @@
#include "zeek/iosource/IOSource.h"
namespace zeek {
namespace detail {
void ConnectionTimer::Init(Connection* arg_conn, timer_func arg_timer,
bool arg_do_expire)
{
conn = arg_conn;
timer = arg_timer;
do_expire = arg_do_expire;
Ref(conn);
}
ConnectionTimer::~ConnectionTimer()
{
if ( conn->RefCnt() < 1 )
reporter->InternalError("reference count inconsistency in ~ConnectionTimer");
conn->RemoveTimer(this);
Unref(conn);
}
void ConnectionTimer::Dispatch(double t, bool is_expire)
{
if ( is_expire && ! do_expire )
return;
// Remove ourselves from the connection's set of timers so
// it doesn't try to cancel us.
conn->RemoveTimer(this);
(conn->*timer)(t);
if ( conn->RefCnt() < 1 )
reporter->InternalError("reference count inconsistency in ConnectionTimer::Dispatch");
}
} // namespace detail
uint64_t Connection::total_connections = 0;
uint64_t Connection::current_connections = 0;
Connection::Connection(NetSessions* s, const detail::ConnIDKey& k, double t,
const ConnID* id, uint32_t flow, const Packet* pkt)
: Session(t, connection_timeout, connection_status_update,
detail::connection_status_update_interval)
{
sessions = s;
key = k;
key_valid = true;
start_time = last_time = t;
orig_addr = id->src_addr;
resp_addr = id->dst_addr;
@ -92,19 +57,11 @@ Connection::Connection(NetSessions* s, const detail::ConnIDKey& k, double t,
vlan = pkt->vlan;
inner_vlan = pkt->inner_vlan;
is_active = 1;
skip = 0;
weird = 0;
suppress_event = 0;
record_contents = record_packets = 1;
record_current_packet = record_current_content = 0;
timers_canceled = 0;
inactivity_timeout = 0;
installed_status_timer = 0;
finished = 0;
hist_seen = 0;
@ -217,12 +174,6 @@ void Connection::NextPacket(double t, bool is_orig,
run_state::current_pkt = nullptr;
}
void Connection::SetLifetime(double lifetime)
{
ADD_TIMER(&Connection::DeleteTimer, run_state::network_time + lifetime, 0,
detail::TIMER_CONN_DELETE);
}
bool Connection::IsReuse(double t, const u_char* pkt)
{
return root_analyzer && root_analyzer->IsReuse(t, pkt);
@ -271,76 +222,6 @@ void Connection::HistoryThresholdEvent(EventHandlerPtr e, bool is_orig,
);
}
void Connection::DeleteTimer(double /* t */)
{
if ( is_active )
Event(connection_timeout, nullptr);
sessions->Remove(this);
}
void Connection::InactivityTimer(double t)
{
if ( last_time + inactivity_timeout <= t )
{
Event(connection_timeout, nullptr);
sessions->Remove(this);
++detail::killed_by_inactivity;
}
else
ADD_TIMER(&Connection::InactivityTimer,
last_time + inactivity_timeout, 0,
detail::TIMER_CONN_INACTIVITY);
}
void Connection::RemoveConnectionTimer(double t)
{
RemovalEvent();
sessions->Remove(this);
}
void Connection::SetInactivityTimeout(double timeout)
{
if ( timeout == inactivity_timeout )
return;
// First cancel and remove any existing inactivity timer.
for ( const auto& timer : timers )
if ( timer->Type() == detail::TIMER_CONN_INACTIVITY )
{
detail::timer_mgr->Cancel(timer);
break;
}
if ( timeout )
ADD_TIMER(&Connection::InactivityTimer,
last_time + timeout, 0, detail::TIMER_CONN_INACTIVITY);
inactivity_timeout = timeout;
}
void Connection::EnableStatusUpdateTimer()
{
if ( installed_status_timer )
return;
if ( connection_status_update && zeek::detail::connection_status_update_interval )
{
ADD_TIMER(&Connection::StatusUpdateTimer,
run_state::network_time + detail::connection_status_update_interval, 0,
detail::TIMER_CONN_STATUS_UPDATE);
installed_status_timer = 1;
}
}
void Connection::StatusUpdateTimer(double t)
{
EnqueueEvent(connection_status_update, nullptr, ConnVal());
ADD_TIMER(&Connection::StatusUpdateTimer,
run_state::network_time + detail::connection_status_update_interval, 0,
detail::TIMER_CONN_STATUS_UPDATE);
}
const RecordValPtr& Connection::ConnVal()
{
if ( ! conn_val )
@ -460,68 +341,12 @@ void Connection::RemovalEvent()
EnqueueEvent(connection_state_remove, nullptr, ConnVal());
}
void Connection::Event(EventHandlerPtr f, analyzer::Analyzer* analyzer, const char* name)
{
if ( ! f )
return;
if ( name )
EnqueueEvent(f, analyzer, make_intrusive<StringVal>(name), ConnVal());
else
EnqueueEvent(f, analyzer, ConnVal());
}
void Connection::EnqueueEvent(EventHandlerPtr f, analyzer::Analyzer* a,
Args args)
{
// "this" is passed as a cookie for the event
event_mgr.Enqueue(f, std::move(args), util::detail::SOURCE_LOCAL, a ? a->GetID() : 0, this);
}
void Connection::Weird(const char* name, const char* addl, const char* source)
{
weird = 1;
reporter->Weird(this, name, addl ? addl : "", source ? source : "");
}
void Connection::AddTimer(timer_func timer, double t, bool do_expire,
detail::TimerType type)
{
if ( timers_canceled )
return;
// If the key is cleared, the connection isn't stored in the connection
// table anymore and will soon be deleted. We're not installing new
// timers anymore then.
if ( ! key_valid )
return;
detail::Timer* conn_timer = new detail::ConnectionTimer(this, timer, t, do_expire, type);
detail::timer_mgr->Add(conn_timer);
timers.push_back(conn_timer);
}
void Connection::RemoveTimer(detail::Timer* t)
{
timers.remove(t);
}
void Connection::CancelTimers()
{
// We are going to cancel our timers which, in turn, may cause them to
// call RemoveTimer(), which would then modify the list we're just
// traversing. Thus, we first make a copy of the list which we then
// iterate through.
TimerPList tmp(timers.length());
std::copy(timers.begin(), timers.end(), std::back_inserter(tmp));
for ( const auto& timer : tmp )
detail::timer_mgr->Cancel(timer);
timers_canceled = 1;
timers.clear();
}
void Connection::FlipRoles()
{
IPAddr tmp_addr = resp_addr;
@ -558,7 +383,7 @@ void Connection::FlipRoles()
unsigned int Connection::MemoryAllocation() const
{
return padded_sizeof(*this)
return Session::MemoryAllocation() + padded_sizeof(*this)
+ (timers.MemoryAllocation() - padded_sizeof(timers))
+ (conn_val ? conn_val->MemoryAllocation() : 0)
+ (root_analyzer ? root_analyzer->MemoryAllocation(): 0)
@ -573,10 +398,7 @@ unsigned int Connection::MemoryAllocationConnVal() const
void Connection::Describe(ODesc* d) const
{
d->Add(start_time);
d->Add("(");
d->Add(last_time);
d->AddSP(")");
Session::Describe(d);
switch ( proto ) {
case TRANSPORT_TCP:

View file

@ -16,6 +16,7 @@
#include "zeek/WeirdState.h"
#include "zeek/ZeekArgs.h"
#include "zeek/IntrusivePtr.h"
#include "zeek/Session.h"
#include "zeek/iosource/Packet.h"
#include "zeek/analyzer/Tag.h"
@ -34,7 +35,6 @@ using RecordValPtr = IntrusivePtr<RecordVal>;
namespace detail {
class ConnectionTimer;
class Specific_RE_Matcher;
class RuleEndpointState;
class RuleHdrTest;
@ -55,8 +55,6 @@ enum ConnEventToFlag {
NUM_EVENTS_TO_FLAG,
};
typedef void (Connection::*timer_func)(double t);
struct ConnID {
IPAddr src_addr;
IPAddr dst_addr;
@ -71,25 +69,29 @@ static inline int addr_port_canon_lt(const IPAddr& addr1, uint32_t p1,
return addr1 < addr2 || (addr1 == addr2 && p1 < p2);
}
class Connection final : public Obj {
class Connection final : public Session {
public:
Connection(NetSessions* s, const detail::ConnIDKey& k, double t, const ConnID* id,
uint32_t flow, const Packet* pkt);
~Connection() override;
// Invoked when an encapsulation is discovered. It records the
// encapsulation with the connection and raises a "tunnel_changed"
// event if it's different from the previous encapsulation (or the
// first encountered). encap can be null to indicate no
// encapsulation.
/**
* Invoked when an encapsulation is discovered. It records the encapsulation
* with the connection and raises a "tunnel_changed" event if it's different
* from the previous encapsulation or if it's the first one encountered.
*
* @param encap The new encapsulation. Can be set to null to indicated no
* encapsulation or clear an old one.
*/
void CheckEncapsulation(const std::shared_ptr<EncapsulationStack>& encap);
// Invoked when connection is about to be removed. Use Ref(this)
// inside Done to keep the connection object around (though it'll
// no longer be accessible from the dictionary of active
// connections).
void Done();
/**
* Invoked when the session is about to be removed. Use Ref(this)
* inside Done to keep the session object around, though it'll
* no longer be accessible from the SessionManager.
*/
void Done() override;
// Process the connection's next packet. "data" points just
// beyond the IP header. It's updated to point just beyond
@ -111,13 +113,10 @@ public:
// connection is in the session map. If it is removed, the key
// should be marked invalid.
const detail::ConnIDKey& Key() const { return key; }
void ClearKey() { key_valid = false; }
bool IsKeyValid() const { return key_valid; }
double StartTime() const { return start_time; }
void SetStartTime(double t) { start_time = t; }
double LastTime() const { return last_time; }
void SetLastTime(double t) { last_time = t; }
detail::SessionKey SessionKey(bool copy) const override
{ return detail::SessionKey{&key, sizeof(key), copy}; }
void ClearKey() override { key_valid = false; }
bool IsKeyValid() const override { return key_valid; }
const IPAddr& OrigAddr() const { return orig_addr; }
const IPAddr& RespAddr() const { return resp_addr; }
@ -133,23 +132,6 @@ public:
TransportProto ConnTransport() const { return proto; }
// True if we should record subsequent packets (either headers or
// in their entirety, depending on record_contents). We still
// record subsequent SYN/FIN/RST, regardless of how this is set.
bool RecordPackets() const { return record_packets; }
void SetRecordPackets(bool do_record) { record_packets = do_record ? 1 : 0; }
// True if we should record full packets for this connection,
// false if we should just record headers.
bool RecordContents() const { return record_contents; }
void SetRecordContents(bool do_record) { record_contents = do_record ? 1 : 0; }
// Set whether to record *current* packet header/full.
void SetRecordCurrentPacket(bool do_record)
{ record_current_packet = do_record ? 1 : 0; }
void SetRecordCurrentContent(bool do_record)
{ record_current_content = do_record ? 1 : 0; }
// FIXME: Now this is in Analyzer and should eventually be removed here.
//
// If true, skip processing of remainder of connection. Note
@ -158,26 +140,19 @@ public:
void SetSkip(bool do_skip) { skip = do_skip ? 1 : 0; }
bool Skipping() const { return skip; }
// Arrange for the connection to expire after the given amount of time.
void SetLifetime(double lifetime);
// Returns true if the packet reflects a reuse of this
// connection (i.e., not a continuation but the beginning of
// a new connection).
bool IsReuse(double t, const u_char* pkt);
// Get/set the inactivity timeout for this connection.
void SetInactivityTimeout(double timeout);
double InactivityTimeout() const { return inactivity_timeout; }
// Activate connection_status_update timer.
void EnableStatusUpdateTimer();
/**
* Returns the associated "connection" record.
*/
const RecordValPtr& ConnVal();
const RecordValPtr& ConnVal() override;
/**
* Append additional entries to the history field in the connection record.
*/
void AppendAddl(const char* str);
void Match(detail::Rule::PatternType type, const u_char* data, int len,
@ -186,36 +161,11 @@ public:
/**
* Generates connection removal event(s).
*/
void RemovalEvent();
// If a handler exists for 'f', an event will be generated. If 'name' is
// given that event's first argument will be it, and it's second will be
// the connection value. If 'name' is null, then the event's first
// argument is the connection value.
void Event(EventHandlerPtr f, analyzer::Analyzer* analyzer, const char* name = nullptr);
/**
* Enqueues an event associated with this connection and given analyzer.
*/
void EnqueueEvent(EventHandlerPtr f, analyzer::Analyzer* analyzer,
Args args);
/**
* A version of EnqueueEvent() taking a variable number of arguments.
*/
template <class... Args>
std::enable_if_t<
std::is_convertible_v<
std::tuple_element_t<0, std::tuple<Args...>>, ValPtr>>
EnqueueEvent(EventHandlerPtr h, analyzer::Analyzer* analyzer, Args&&... args)
{ return EnqueueEvent(h, analyzer, zeek::Args{std::forward<Args>(args)...}); }
void RemovalEvent() override;
void Weird(const char* name, const char* addl = "", const char* source = "");
bool DidWeird() const { return weird != 0; }
// Cancel all associated timers.
void CancelTimers();
inline bool FlagEvent(ConnEventToFlag e)
{
if ( e >= 0 && e < NUM_EVENTS_TO_FLAG )
@ -234,8 +184,8 @@ public:
// Statistics.
// Just a lower bound.
unsigned int MemoryAllocation() const;
unsigned int MemoryAllocationConnVal() const;
unsigned int MemoryAllocation() const override;
unsigned int MemoryAllocationConnVal() const override;
static uint64_t TotalConnections()
{ return total_connections; }
@ -268,8 +218,6 @@ public:
void AddHistory(char code) { history += code; }
void DeleteTimer(double t);
// Sets the root of the analyzer tree as well as the primary PIA.
void SetRootAnalyzer(analyzer::TransportLayerAnalyzer* analyzer, analyzer::pia::PIA* pia);
analyzer::TransportLayerAnalyzer* GetRootAnalyzer() { return root_analyzer; }
@ -295,26 +243,10 @@ public:
protected:
// Add the given timer to expire at time t. If do_expire
// is true, then the timer is also evaluated when Bro terminates,
// otherwise not.
void AddTimer(timer_func timer, double t, bool do_expire,
detail::TimerType type);
void RemoveTimer(detail::Timer* t);
// Allow other classes to access pointers to these:
friend class detail::ConnectionTimer;
void InactivityTimer(double t);
void StatusUpdateTimer(double t);
void RemoveConnectionTimer(double t);
friend class detail::SessionTimer;
NetSessions* sessions;
detail::ConnIDKey key;
bool key_valid;
TimerPList timers;
IPAddr orig_addr;
IPAddr resp_addr;
@ -324,59 +256,30 @@ protected:
uint32_t vlan, inner_vlan; // VLAN this connection traverses, if available
u_char orig_l2_addr[Packet::L2_ADDR_LEN]; // Link-layer originator address, if available
u_char resp_l2_addr[Packet::L2_ADDR_LEN]; // Link-layer responder address, if available
double start_time, last_time;
double inactivity_timeout;
int suppress_event; // suppress certain events to once per conn.
RecordValPtr conn_val;
std::shared_ptr<EncapsulationStack> encapsulation; // tunnels
int suppress_event; // suppress certain events to once per conn.
unsigned int installed_status_timer:1;
unsigned int timers_canceled:1;
unsigned int is_active:1;
detail::ConnIDKey key;
bool key_valid;
unsigned int skip:1;
unsigned int weird:1;
unsigned int finished:1;
unsigned int record_packets:1, record_contents:1;
unsigned int record_current_packet:1, record_current_content:1;
unsigned int saw_first_orig_packet:1, saw_first_resp_packet:1;
// Count number of connections.
static uint64_t total_connections;
static uint64_t current_connections;
std::string history;
uint32_t hist_seen;
std::string history;
analyzer::TransportLayerAnalyzer* root_analyzer;
analyzer::pia::PIA* primary_PIA;
UID uid; // Globally unique connection ID.
detail::WeirdStateMap weird_state;
// Count number of connections.
static uint64_t total_connections;
static uint64_t current_connections;
};
namespace detail {
class ConnectionTimer final : public Timer {
public:
ConnectionTimer(Connection* arg_conn, timer_func arg_timer,
double arg_t, bool arg_do_expire, TimerType arg_type)
: Timer(arg_t, arg_type)
{ Init(arg_conn, arg_timer, arg_do_expire); }
~ConnectionTimer() override;
void Dispatch(double t, bool is_expire) override;
protected:
void Init(Connection* conn, timer_func timer, bool do_expire);
Connection* conn;
timer_func timer;
bool do_expire;
};
} // namespace detail
} // namespace zeek
#define ADD_TIMER(timer, t, do_expire, type) \
AddTimer(timer_func(timer), (t), (do_expire), (type))

273
src/Session.cc Normal file
View file

@ -0,0 +1,273 @@
// See the file "COPYING" in the main distribution directory for copyright.
#include "zeek/Session.h"
#include "zeek/Reporter.h"
#include "zeek/analyzer/Analyzer.h"
#include "zeek/Val.h"
#include "zeek/Event.h"
#include "zeek/Desc.h"
#include "zeek/Sessions.h"
#include "zeek/IP.h"
namespace zeek {
namespace detail {
void SessionTimer::Init(Session* arg_conn, timer_func arg_timer,
bool arg_do_expire)
{
conn = arg_conn;
timer = arg_timer;
do_expire = arg_do_expire;
Ref(conn);
}
SessionTimer::~SessionTimer()
{
if ( conn->RefCnt() < 1 )
reporter->InternalError("reference count inconsistency in ~SessionTimer");
conn->RemoveTimer(this);
Unref(conn);
}
void SessionTimer::Dispatch(double t, bool is_expire)
{
if ( is_expire && ! do_expire )
return;
// Remove ourselves from the connection's set of timers so
// it doesn't try to cancel us.
conn->RemoveTimer(this);
(conn->*timer)(t);
if ( conn->RefCnt() < 1 )
reporter->InternalError("reference count inconsistency in SessionTimer::Dispatch");
}
SessionKey::SessionKey(const void* session, size_t size, bool copy) : size(size)
{
data = reinterpret_cast<const uint8_t*>(session);
if ( copy )
CopyData();
}
SessionKey::SessionKey(SessionKey&& rhs)
{
data = rhs.data;
size = rhs.size;
copied = rhs.copied;
rhs.data = nullptr;
rhs.size = 0;
rhs.copied = false;
}
SessionKey& SessionKey::operator=(SessionKey&& rhs)
{
if ( this != &rhs )
{
data = rhs.data;
size = rhs.size;
copied = rhs.copied;
rhs.data = nullptr;
rhs.size = 0;
rhs.copied = false;
}
return *this;
}
SessionKey::~SessionKey()
{
if ( copied )
delete [] data;
}
void SessionKey::CopyData()
{
if ( copied )
return;
copied = true;
uint8_t *temp = new uint8_t[size];
memcpy(temp, data, size);
data = temp;
}
bool SessionKey::operator<(const SessionKey& rhs) const
{
if ( size != rhs.size )
return size < rhs.size;
return memcmp(data, rhs.data, size) < 0;
}
} // namespace detail
Session::Session(double t,
EventHandlerPtr timeout_event,
EventHandlerPtr status_update_event,
double status_update_interval)
: start_time(t), last_time(t),
session_timeout_event(timeout_event),
session_status_update_event(status_update_event),
session_status_update_interval(status_update_interval)
{
record_contents = record_packets = 1;
record_current_packet = record_current_content = 0;
is_active = 1;
timers_canceled = 0;
inactivity_timeout = 0;
installed_status_timer = 0;
}
unsigned int Session::MemoryAllocation() const
{
return 0;
}
void Session::Event(EventHandlerPtr f, analyzer::Analyzer* analyzer, const char* name)
{
if ( ! f )
return;
if ( name )
EnqueueEvent(f, analyzer, make_intrusive<StringVal>(name), ConnVal());
else
EnqueueEvent(f, analyzer, ConnVal());
}
void Session::EnqueueEvent(EventHandlerPtr f, analyzer::Analyzer* a, Args args)
{
// "this" is passed as a cookie for the event
event_mgr.Enqueue(f, std::move(args), util::detail::SOURCE_LOCAL, a ? a->GetID() : 0, this);
}
void Session::Describe(ODesc* d) const
{
d->Add(start_time);
d->Add("(");
d->Add(last_time);
d->AddSP(")");
}
void Session::SetLifetime(double lifetime)
{
ADD_TIMER(&Session::DeleteTimer, run_state::network_time + lifetime, 0,
detail::TIMER_CONN_DELETE);
}
void Session::SetInactivityTimeout(double timeout)
{
if ( timeout == inactivity_timeout )
return;
// First cancel and remove any existing inactivity timer.
for ( const auto& timer : timers )
if ( timer->Type() == detail::TIMER_CONN_INACTIVITY )
{
detail::timer_mgr->Cancel(timer);
break;
}
if ( timeout )
ADD_TIMER(&Session::InactivityTimer,
last_time + timeout, 0, detail::TIMER_CONN_INACTIVITY);
inactivity_timeout = timeout;
}
void Session::EnableStatusUpdateTimer()
{
if ( installed_status_timer )
return;
if ( session_status_update_event && session_status_update_interval )
{
ADD_TIMER(&Session::StatusUpdateTimer,
run_state::network_time + session_status_update_interval, 0,
detail::TIMER_CONN_STATUS_UPDATE);
installed_status_timer = 1;
}
}
void Session::CancelTimers()
{
// We are going to cancel our timers which, in turn, may cause them to
// call RemoveTimer(), which would then modify the list we're just
// traversing. Thus, we first make a copy of the list which we then
// iterate through.
TimerPList tmp(timers.length());
std::copy(timers.begin(), timers.end(), std::back_inserter(tmp));
for ( const auto& timer : tmp )
detail::timer_mgr->Cancel(timer);
timers_canceled = 1;
timers.clear();
}
void Session::DeleteTimer(double /* t */)
{
if ( is_active )
Event(session_timeout_event, nullptr);
sessions->Remove(this);
}
void Session::AddTimer(timer_func timer, double t, bool do_expire,
detail::TimerType type)
{
if ( timers_canceled )
return;
// If the key is cleared, the session isn't stored in the session table
// anymore and will soon be deleted. We're not installed new timers
// anymore then.
if ( ! IsKeyValid() )
return;
detail::Timer* conn_timer = new detail::SessionTimer(this, timer, t, do_expire, type);
detail::timer_mgr->Add(conn_timer);
timers.push_back(conn_timer);
}
void Session::RemoveTimer(detail::Timer* t)
{
timers.remove(t);
}
void Session::InactivityTimer(double t)
{
if ( last_time + inactivity_timeout <= t )
{
Event(session_timeout_event, nullptr);
sessions->Remove(this);
++detail::killed_by_inactivity;
}
else
ADD_TIMER(&Session::InactivityTimer,
last_time + inactivity_timeout, 0,
detail::TIMER_CONN_INACTIVITY);
}
void Session::StatusUpdateTimer(double t)
{
EnqueueEvent(session_status_update_event, nullptr, ConnVal());
ADD_TIMER(&Session::StatusUpdateTimer,
run_state::network_time + session_status_update_interval, 0,
detail::TIMER_CONN_STATUS_UPDATE);
}
void Session::RemoveConnectionTimer(double t)
{
RemovalEvent();
sessions->Remove(this);
}
} // namespace zeek

287
src/Session.h Normal file
View file

@ -0,0 +1,287 @@
// See the file "COPYING" in the main distribution directory for copyright.
#pragma once
#include <memory>
#include "zeek/Hash.h"
#include "zeek/Obj.h"
#include "zeek/EventHandler.h"
#include "zeek/Timer.h"
namespace zeek {
class RecordVal;
using RecordValPtr = IntrusivePtr<RecordVal>;
class Session;
namespace analyzer { class Analyzer; }
namespace detail {
class SessionTimer;
class SessionKey;
}
typedef void (Session::*timer_func)(double t);
class Session : public Obj {
public:
/**
* Construct a new session.
*
* @param t The timestamp for the start and end of the session when it's initially
* created. The end time will be updated as later packets are processed.
* @param timeout_event The event that will be emitted when the session times out.
* @param status_update_event The event that will be emitted for session status
* updates. This can be set to null to disable status updates. This event also
* won't be emitted unless the EnableStatusUpdateTimer() method is called on the
* session, and the interval is set to a non-zero value.
* @param status_update_interval The interval in seconds for the status update
* event to be emitted. Setting this to zero disables the status update timer.
*/
Session(double t, EventHandlerPtr timeout_event,
EventHandlerPtr status_update_event = nullptr,
double status_update_interval = 0);
virtual ~Session() {}
/**
* Invoked when the session is about to be removed. Use Ref(this)
* inside Done to keep the session object around, though it'll
* no longer be accessible from the SessionManager.
*/
virtual void Done() = 0;
/**
* Returns a key for the session. This is used as the key for storing
* the session in SessionManager.
*
* @param copy Flag to indicate that the key returned has a copy of the
* key data instead of just a pointer to it.
*/
virtual detail::SessionKey SessionKey(bool copy) const = 0;
/**
* Set the key as invalid.
*/
virtual void ClearKey() = 0;
/**
* Return whether the key is valid.
*/
virtual bool IsKeyValid() const = 0;
double StartTime() const { return start_time; }
void SetStartTime(double t) { start_time = t; }
double LastTime() const { return last_time; }
void SetLastTime(double t) { last_time = t; }
// True if we should record subsequent packets (either headers or
// in their entirety, depending on record_contents). We still
// record subsequent SYN/FIN/RST, regardless of how this is set.
bool RecordPackets() const { return record_packets; }
void SetRecordPackets(bool do_record) { record_packets = do_record ? 1 : 0; }
// True if we should record full packets for this connection,
// false if we should just record headers.
bool RecordContents() const { return record_contents; }
void SetRecordContents(bool do_record) { record_contents = do_record ? 1 : 0; }
// Set whether to record *current* packet header/full.
void SetRecordCurrentPacket(bool do_record)
{ record_current_packet = do_record ? 1 : 0; }
void SetRecordCurrentContent(bool do_record)
{ record_current_content = do_record ? 1 : 0; }
/**
* Returns the associated "session" record.
* TODO: rename this to SessionVal(). This requires a swath of other changes.
*/
virtual const RecordValPtr& ConnVal() = 0;
/**
* Return the memory allocation required by the session record. This requires at
* least one call to ConnVal() first in order to setup the record object.
*/
virtual unsigned int MemoryAllocationConnVal() const = 0;
/**
* A lower-bound calculation of how much memory a session object is using.
*/
virtual unsigned int MemoryAllocation() const;
/**
* Generates session removal event(s). Must be overridden by child classes to
* provide specific removal events.
*/
virtual void RemovalEvent() = 0;
/**
* Generate an event for this session.
*
* @param f The handler for the event to be generated. If the handler doesn't
* exist, this method doesn't generate anything.
* @param analyzer
* @param name If given, this will be passed as the first argument to the
* handler, followed by the session value. If null, then the event's first
* argument is the session value.
*/
void Event(EventHandlerPtr f, analyzer::Analyzer* analyzer = nullptr,
const char* name = nullptr);
/**
* Enqueues an event associated with this connection and given analyzer.
*/
void EnqueueEvent(EventHandlerPtr f, analyzer::Analyzer* analyzer, Args args);
/**
* A version of EnqueueEvent() taking a variable number of arguments.
*/
template <class... Args>
std::enable_if_t<
std::is_convertible_v<
std::tuple_element_t<0, std::tuple<Args...>>, ValPtr>>
EnqueueEvent(EventHandlerPtr h, analyzer::Analyzer* analyzer, Args&&... args)
{ return EnqueueEvent(h, analyzer, zeek::Args{std::forward<Args>(args)...}); }
virtual void Describe(ODesc* d) const override;
/**
* Sets the session to expire after a given amount of time.
*
* @param lifetime The amount of time in seconds from the current network time.
*/
void SetLifetime(double lifetime);
/**
* Sets the inactivity timeout for this session.
*
* @param timeout The number of seconds of inactivity allowed for this session
* before it times out.
*/
void SetInactivityTimeout(double timeout);
/**
* Returns the inactivity timeout for the session.
*/
double InactivityTimeout() const { return inactivity_timeout; }
/**
* Activates the timer for the status update event.
*/
void EnableStatusUpdateTimer();
/**
* Cancels all timers associated with this session.
*/
void CancelTimers();
/**
* Called when the lifetime of the session expires. Fires a timeout event and
* removes the session from the manager.
* TODO: This function has a terrible name considering there's an AddTimer() and
* a RemoveTimer() method in this class as well.
*
* @param t This argument is ignored.
*/
void DeleteTimer(double t);
protected:
friend class detail::SessionTimer;
/**
* Add a given timer to expire at a specific time.
*
* @param timer A pointer to a method that will be called when the timer expires.
* @param t The time when the timer expires. This is an absolute time, not a time
* relative to the current network time.
* @param do_expire If set to true, the timer is also evaluated when Zeek
* terminates.
* @param type The type of timer being added.
*/
void AddTimer(timer_func timer, double t, bool do_expire,
detail::TimerType type);
/**
* Remove a specific timer from firing.
*/
void RemoveTimer(detail::Timer* t);
/**
* The handler method for inactivity timers.
*/
void InactivityTimer(double t);
/**
* The handler method for status update timers.
*/
void StatusUpdateTimer(double t);
// TODO: is this method used by anyone?
void RemoveConnectionTimer(double t);
double start_time, last_time;
TimerPList timers;
double inactivity_timeout;
EventHandlerPtr session_timeout_event;
EventHandlerPtr session_status_update_event;
double session_status_update_interval;
unsigned int installed_status_timer:1;
unsigned int timers_canceled:1;
unsigned int is_active:1;
unsigned int record_packets:1, record_contents:1;
unsigned int record_current_packet:1, record_current_content:1;
};
namespace detail {
class SessionTimer final : public Timer {
public:
SessionTimer(Session* arg_conn, timer_func arg_timer,
double arg_t, bool arg_do_expire, TimerType arg_type)
: Timer(arg_t, arg_type)
{ Init(arg_conn, arg_timer, arg_do_expire); }
~SessionTimer() override;
void Dispatch(double t, bool is_expire) override;
protected:
void Init(Session* conn, timer_func timer, bool do_expire);
Session* conn;
timer_func timer;
bool do_expire;
};
class SessionKey final {
public:
SessionKey(const void* session, size_t size, bool copy=false);
~SessionKey();
// Implement move semantics for SessionKey, since they're used as keys
// in a map and copying them would cause double-free issues. Adding this
// constructor and operator explicitly disables the equivalent copy
// operations.
SessionKey(SessionKey&& rhs);
SessionKey& operator=(SessionKey&& rhs);
void CopyData();
bool operator<(const SessionKey& rhs) const;
private:
const uint8_t* data = nullptr;
size_t size = 0;
bool copied = false;
};
} // namespace detail
} // namespace zeek
#define ADD_TIMER(timer, t, do_expire, type) \
AddTimer(timer_func(timer), (t), (do_expire), (type))

View file

@ -18,6 +18,7 @@
#include "zeek/NetVar.h"
#include "zeek/Reporter.h"
#include "zeek/RuleMatcher.h"
#include "zeek/Session.h"
#include "zeek/TunnelEncapsulation.h"
#include "zeek/analyzer/protocol/icmp/ICMP.h"
@ -363,8 +364,10 @@ Connection* NetSessions::FindConnection(Val* v)
return conn;
}
void NetSessions::Remove(Connection* c)
void NetSessions::Remove(Session* s)
{
Connection* c = static_cast<Connection*>(s);
if ( c->IsKeyValid() )
{
const detail::ConnIDKey& key = c->Key();

View file

@ -17,6 +17,7 @@ namespace detail { class PacketFilter; }
class EncapsulationStack;
class Packet;
class Connection;
class Session;
struct ConnID;
struct SessionStats {
@ -49,7 +50,16 @@ public:
// no such connection or the Val is ill-formed.
Connection* FindConnection(Val* v);
void Remove(Connection* c);
/**
* Looks up the connection referred to by a given key.
*
* @param key The key for the connection to search for.
* @param proto The transport protocol for the connection.
* @return The connection, or nullptr if one doesn't exist.
*/
Connection* FindConnection(const detail::ConnIDKey& key, TransportProto proto);
void Remove(Session* s);
void Insert(Connection* c);
// Generating connection_pending events for all connections

View file

@ -143,7 +143,7 @@ protected:
void CheckRecording(bool need_contents, TCP_Flags flags);
void CheckPIA_FirstPacket(bool is_orig, const IP_Hdr* ip);
friend class detail::ConnectionTimer;
friend class detail::SessionTimer;
void AttemptTimer(double t);
void PartialCloseTimer(double t);
void ExpireTimer(double t);