mirror of
https://github.com/zeek/zeek.git
synced 2025-10-02 14:48:21 +00:00
941 lines
20 KiB
C++
941 lines
20 KiB
C++
// See the file "COPYING" in the main distribution directory for copyright.
|
|
|
|
#include <algorithm>
|
|
|
|
#include "Analyzer.h"
|
|
#include "Manager.h"
|
|
#include "binpac.h"
|
|
|
|
#include "analyzer/protocol/pia/PIA.h"
|
|
#include "../BroString.h"
|
|
#include "../Event.h"
|
|
|
|
namespace analyzer {
|
|
|
|
class AnalyzerTimer final : public Timer {
|
|
public:
|
|
AnalyzerTimer(Analyzer* arg_analyzer, analyzer_timer_func arg_timer,
|
|
double arg_t, int arg_do_expire, TimerType arg_type);
|
|
|
|
virtual ~AnalyzerTimer();
|
|
|
|
void Dispatch(double t, bool is_expire) override;
|
|
|
|
protected:
|
|
AnalyzerTimer() : analyzer(), timer(), do_expire() {}
|
|
|
|
void Init(Analyzer* analyzer, analyzer_timer_func timer, int do_expire);
|
|
|
|
Analyzer* analyzer;
|
|
analyzer_timer_func timer;
|
|
int do_expire;
|
|
};
|
|
|
|
}
|
|
|
|
using namespace analyzer;
|
|
|
|
AnalyzerTimer::AnalyzerTimer(Analyzer* arg_analyzer, analyzer_timer_func arg_timer,
|
|
double arg_t, int arg_do_expire, TimerType arg_type)
|
|
: Timer(arg_t, arg_type)
|
|
{
|
|
Init(arg_analyzer, arg_timer, arg_do_expire);
|
|
}
|
|
|
|
AnalyzerTimer::~AnalyzerTimer()
|
|
{
|
|
analyzer->RemoveTimer(this);
|
|
Unref(analyzer->Conn());
|
|
}
|
|
|
|
void AnalyzerTimer::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.
|
|
analyzer->RemoveTimer(this);
|
|
|
|
(analyzer->*timer)(t);
|
|
}
|
|
|
|
void AnalyzerTimer::Init(Analyzer* arg_analyzer, analyzer_timer_func arg_timer,
|
|
int arg_do_expire)
|
|
{
|
|
analyzer = arg_analyzer;
|
|
timer = arg_timer;
|
|
do_expire = arg_do_expire;
|
|
|
|
// We need to Ref the connection as the analyzer doesn't do it and
|
|
// we need to have it around until we expire.
|
|
Ref(analyzer->Conn());
|
|
}
|
|
|
|
analyzer::ID Analyzer::id_counter = 0;
|
|
|
|
const char* Analyzer::GetAnalyzerName() const
|
|
{
|
|
assert(tag);
|
|
return analyzer_mgr->GetComponentName(tag).c_str();
|
|
}
|
|
|
|
void Analyzer::SetAnalyzerTag(const Tag& arg_tag)
|
|
{
|
|
assert(! tag || tag == arg_tag);
|
|
tag = arg_tag;
|
|
}
|
|
|
|
bool Analyzer::IsAnalyzer(const char* name)
|
|
{
|
|
assert(tag);
|
|
return strcmp(analyzer_mgr->GetComponentName(tag).c_str(), name) == 0;
|
|
}
|
|
|
|
Analyzer::Analyzer(const char* name, Connection* conn)
|
|
{
|
|
Tag tag = analyzer_mgr->GetComponentTag(name);
|
|
|
|
if ( ! tag )
|
|
reporter->InternalError("unknown analyzer name %s; mismatch with tag analyzer::Component?", name);
|
|
|
|
CtorInit(tag, conn);
|
|
}
|
|
|
|
Analyzer::Analyzer(const Tag& tag, Connection* conn)
|
|
{
|
|
CtorInit(tag, conn);
|
|
}
|
|
|
|
Analyzer::Analyzer(Connection* conn)
|
|
{
|
|
CtorInit(Tag(), conn);
|
|
}
|
|
|
|
void Analyzer::CtorInit(const Tag& arg_tag, Connection* arg_conn)
|
|
{
|
|
// Don't Ref conn here to avoid circular ref'ing. It can't be deleted
|
|
// before us.
|
|
conn = arg_conn;
|
|
tag = arg_tag;
|
|
id = ++id_counter;
|
|
protocol_confirmed = false;
|
|
timers_canceled = false;
|
|
skip = false;
|
|
finished = false;
|
|
removing = false;
|
|
parent = nullptr;
|
|
orig_supporters = nullptr;
|
|
resp_supporters = nullptr;
|
|
signature = nullptr;
|
|
output_handler = nullptr;
|
|
}
|
|
|
|
Analyzer::~Analyzer()
|
|
{
|
|
assert(finished);
|
|
|
|
LOOP_OVER_CHILDREN(i)
|
|
delete *i;
|
|
|
|
SupportAnalyzer* next = nullptr;
|
|
|
|
for ( SupportAnalyzer* a = orig_supporters; a; a = next )
|
|
{
|
|
next = a->sibling;
|
|
delete a;
|
|
}
|
|
|
|
for ( SupportAnalyzer* a = resp_supporters; a; a = next)
|
|
{
|
|
next = a->sibling;
|
|
delete a;
|
|
}
|
|
|
|
delete output_handler;
|
|
}
|
|
|
|
void Analyzer::Init()
|
|
{
|
|
}
|
|
|
|
void Analyzer::InitChildren()
|
|
{
|
|
AppendNewChildren();
|
|
|
|
LOOP_OVER_CHILDREN(i)
|
|
{
|
|
(*i)->Init();
|
|
(*i)->InitChildren();
|
|
}
|
|
}
|
|
|
|
void Analyzer::Done()
|
|
{
|
|
assert(!finished);
|
|
|
|
if ( ! skip )
|
|
{
|
|
EndOfData(true);
|
|
EndOfData(false);
|
|
}
|
|
|
|
CancelTimers();
|
|
|
|
AppendNewChildren();
|
|
|
|
LOOP_OVER_CHILDREN(i)
|
|
if ( ! (*i)->finished )
|
|
(*i)->Done();
|
|
|
|
for ( SupportAnalyzer* a = orig_supporters; a; a = a->sibling )
|
|
if ( ! a->finished )
|
|
a->Done();
|
|
|
|
for ( SupportAnalyzer* a = resp_supporters; a; a = a->sibling )
|
|
if ( ! a->finished )
|
|
a->Done();
|
|
|
|
finished = true;
|
|
}
|
|
|
|
void Analyzer::NextPacket(int len, const u_char* data, bool is_orig, uint64_t seq,
|
|
const IP_Hdr* ip, int caplen)
|
|
{
|
|
if ( skip )
|
|
return;
|
|
|
|
SupportAnalyzer* next_sibling = FirstSupportAnalyzer(is_orig);
|
|
|
|
if ( next_sibling )
|
|
next_sibling->NextPacket(len, data, is_orig, seq, ip, caplen);
|
|
|
|
else
|
|
{
|
|
try
|
|
{
|
|
DeliverPacket(len, data, is_orig, seq, ip, caplen);
|
|
}
|
|
catch ( binpac::Exception const &e )
|
|
{
|
|
ProtocolViolation(fmt("Binpac exception: %s", e.c_msg()));
|
|
}
|
|
}
|
|
}
|
|
|
|
void Analyzer::NextStream(int len, const u_char* data, bool is_orig)
|
|
{
|
|
if ( skip )
|
|
return;
|
|
|
|
SupportAnalyzer* next_sibling = FirstSupportAnalyzer(is_orig);
|
|
|
|
if ( next_sibling )
|
|
next_sibling->NextStream(len, data, is_orig);
|
|
|
|
else
|
|
{
|
|
try
|
|
{
|
|
DeliverStream(len, data, is_orig);
|
|
}
|
|
catch ( binpac::Exception const &e )
|
|
{
|
|
ProtocolViolation(fmt("Binpac exception: %s", e.c_msg()));
|
|
}
|
|
}
|
|
}
|
|
|
|
void Analyzer::NextUndelivered(uint64_t seq, int len, bool is_orig)
|
|
{
|
|
if ( skip )
|
|
return;
|
|
|
|
SupportAnalyzer* next_sibling = FirstSupportAnalyzer(is_orig);
|
|
|
|
if ( next_sibling )
|
|
next_sibling->NextUndelivered(seq, len, is_orig);
|
|
|
|
else
|
|
{
|
|
try
|
|
{
|
|
Undelivered(seq, len, is_orig);
|
|
}
|
|
catch ( binpac::Exception const &e )
|
|
{
|
|
ProtocolViolation(fmt("Binpac exception: %s", e.c_msg()));
|
|
}
|
|
}
|
|
}
|
|
|
|
void Analyzer::NextEndOfData(bool is_orig)
|
|
{
|
|
if ( skip )
|
|
return;
|
|
|
|
SupportAnalyzer* next_sibling = FirstSupportAnalyzer(is_orig);
|
|
|
|
if ( next_sibling )
|
|
next_sibling->NextEndOfData(is_orig);
|
|
else
|
|
EndOfData(is_orig);
|
|
}
|
|
|
|
void Analyzer::ForwardPacket(int len, const u_char* data, bool is_orig,
|
|
uint64_t seq, const IP_Hdr* ip, int caplen)
|
|
{
|
|
if ( output_handler )
|
|
output_handler->DeliverPacket(len, data, is_orig, seq,
|
|
ip, caplen);
|
|
|
|
AppendNewChildren();
|
|
|
|
// Pass to all children.
|
|
analyzer_list::iterator next;
|
|
for ( analyzer_list::iterator i = children.begin();
|
|
i != children.end(); i = next )
|
|
{
|
|
Analyzer* current = *i;
|
|
next = ++i;
|
|
|
|
if ( ! (current->finished || current->removing ) )
|
|
current->NextPacket(len, data, is_orig, seq, ip, caplen);
|
|
else
|
|
DeleteChild(--i);
|
|
}
|
|
|
|
AppendNewChildren();
|
|
}
|
|
|
|
void Analyzer::ForwardStream(int len, const u_char* data, bool is_orig)
|
|
{
|
|
if ( output_handler )
|
|
output_handler->DeliverStream(len, data, is_orig);
|
|
|
|
AppendNewChildren();
|
|
|
|
analyzer_list::iterator next;
|
|
for ( analyzer_list::iterator i = children.begin();
|
|
i != children.end(); i = next )
|
|
{
|
|
Analyzer* current = *i;
|
|
next = ++i;
|
|
|
|
if ( ! (current->finished || current->removing ) )
|
|
current->NextStream(len, data, is_orig);
|
|
else
|
|
DeleteChild(--i);
|
|
}
|
|
|
|
AppendNewChildren();
|
|
}
|
|
|
|
void Analyzer::ForwardUndelivered(uint64_t seq, int len, bool is_orig)
|
|
{
|
|
if ( output_handler )
|
|
output_handler->Undelivered(seq, len, is_orig);
|
|
|
|
AppendNewChildren();
|
|
|
|
analyzer_list::iterator next;
|
|
for ( analyzer_list::iterator i = children.begin();
|
|
i != children.end(); i = next )
|
|
{
|
|
Analyzer* current = *i;
|
|
next = ++i;
|
|
|
|
if ( ! (current->finished || current->removing ) )
|
|
current->NextUndelivered(seq, len, is_orig);
|
|
else
|
|
DeleteChild(--i);
|
|
}
|
|
|
|
AppendNewChildren();
|
|
}
|
|
|
|
void Analyzer::ForwardEndOfData(bool orig)
|
|
{
|
|
AppendNewChildren();
|
|
|
|
analyzer_list::iterator next;
|
|
for ( analyzer_list::iterator i = children.begin();
|
|
i != children.end(); i = next )
|
|
{
|
|
Analyzer* current = *i;
|
|
next = ++i;
|
|
|
|
if ( ! (current->finished || current->removing ) )
|
|
current->NextEndOfData(orig);
|
|
else
|
|
DeleteChild(--i);
|
|
}
|
|
|
|
AppendNewChildren();
|
|
}
|
|
|
|
bool Analyzer::AddChildAnalyzer(Analyzer* analyzer, bool init)
|
|
{
|
|
auto t = analyzer->GetAnalyzerTag();
|
|
auto it = std::find(prevented.begin(), prevented.end(), t);
|
|
auto prevent = (it != prevented.end());
|
|
|
|
if ( HasChildAnalyzer(t) || prevent )
|
|
{
|
|
analyzer->Done();
|
|
delete analyzer;
|
|
return false;
|
|
}
|
|
|
|
// We add new children to new_children first. They are then
|
|
// later copied to the "real" child list. This is necessary
|
|
// because this method may be called while somebody is iterating
|
|
// over the children and we might confuse the caller by modifying
|
|
// the list.
|
|
|
|
analyzer->parent = this;
|
|
new_children.push_back(analyzer);
|
|
|
|
if ( init )
|
|
analyzer->Init();
|
|
|
|
DBG_LOG(DBG_ANALYZER, "%s added child %s",
|
|
fmt_analyzer(this).c_str(), fmt_analyzer(analyzer).c_str());
|
|
return true;
|
|
}
|
|
|
|
Analyzer* Analyzer::AddChildAnalyzer(const Tag& analyzer)
|
|
{
|
|
if ( HasChildAnalyzer(analyzer) )
|
|
return nullptr;
|
|
|
|
auto it = std::find(prevented.begin(), prevented.end(), analyzer);
|
|
|
|
if ( it != prevented.end() )
|
|
return nullptr;
|
|
|
|
Analyzer* a = analyzer_mgr->InstantiateAnalyzer(analyzer, conn);
|
|
|
|
if ( a && AddChildAnalyzer(a) )
|
|
return a;
|
|
|
|
return nullptr;
|
|
}
|
|
|
|
bool Analyzer::RemoveChild(const analyzer_list& children, ID id)
|
|
{
|
|
for ( const auto& i : children )
|
|
{
|
|
if ( i->id != id )
|
|
continue;
|
|
|
|
if ( i->finished || i->removing )
|
|
return false;
|
|
|
|
DBG_LOG(DBG_ANALYZER, "%s disabling child %s",
|
|
fmt_analyzer(this).c_str(), fmt_analyzer(i).c_str());
|
|
// We just flag it as being removed here but postpone
|
|
// actually doing that to later. Otherwise, we'd need
|
|
// to call Done() here, which then in turn might
|
|
// cause further code to be executed that may assume
|
|
// something not true because of a violation that
|
|
// triggered the removal in the first place.
|
|
i->removing = true;
|
|
return true;
|
|
}
|
|
|
|
return false;
|
|
}
|
|
|
|
bool Analyzer::RemoveChildAnalyzer(ID id)
|
|
{
|
|
return RemoveChild(children, id) || RemoveChild(new_children, id);
|
|
}
|
|
|
|
bool Analyzer::Remove()
|
|
{
|
|
assert(parent);
|
|
parent->RemoveChildAnalyzer(this);
|
|
return removing;
|
|
}
|
|
|
|
void Analyzer::PreventChildren(Tag tag)
|
|
{
|
|
auto it = std::find(prevented.begin(), prevented.end(), tag);
|
|
|
|
if ( it != prevented.end() )
|
|
return;
|
|
|
|
prevented.emplace_back(tag);
|
|
}
|
|
|
|
bool Analyzer::HasChildAnalyzer(Tag tag)
|
|
{
|
|
LOOP_OVER_CHILDREN(i)
|
|
if ( (*i)->tag == tag )
|
|
return true;
|
|
|
|
LOOP_OVER_GIVEN_CHILDREN(i, new_children)
|
|
if ( (*i)->tag == tag )
|
|
return true;
|
|
|
|
return false;
|
|
}
|
|
|
|
Analyzer* Analyzer::FindChild(ID arg_id)
|
|
{
|
|
if ( id == arg_id )
|
|
return this;
|
|
|
|
LOOP_OVER_CHILDREN(i)
|
|
{
|
|
Analyzer* child = (*i)->FindChild(arg_id);
|
|
if ( child )
|
|
return child;
|
|
}
|
|
|
|
LOOP_OVER_GIVEN_CHILDREN(i, new_children)
|
|
{
|
|
Analyzer* child = (*i)->FindChild(arg_id);
|
|
if ( child )
|
|
return child;
|
|
}
|
|
|
|
return nullptr;
|
|
}
|
|
|
|
Analyzer* Analyzer::FindChild(Tag arg_tag)
|
|
{
|
|
if ( tag == arg_tag )
|
|
return this;
|
|
|
|
LOOP_OVER_CHILDREN(i)
|
|
{
|
|
Analyzer* child = (*i)->FindChild(arg_tag);
|
|
if ( child )
|
|
return child;
|
|
}
|
|
|
|
LOOP_OVER_GIVEN_CHILDREN(i, new_children)
|
|
{
|
|
Analyzer* child = (*i)->FindChild(arg_tag);
|
|
if ( child )
|
|
return child;
|
|
}
|
|
|
|
return nullptr;
|
|
}
|
|
|
|
Analyzer* Analyzer::FindChild(const char* name)
|
|
{
|
|
Tag tag = analyzer_mgr->GetComponentTag(name);
|
|
return tag ? FindChild(tag) : nullptr;
|
|
}
|
|
|
|
void Analyzer::DeleteChild(analyzer_list::iterator i)
|
|
{
|
|
Analyzer* child = *i;
|
|
|
|
// Analyzer must have already been finished or marked for removal.
|
|
assert(child->finished || child->removing);
|
|
|
|
if ( child->removing )
|
|
{
|
|
child->Done();
|
|
child->removing = false;
|
|
}
|
|
|
|
DBG_LOG(DBG_ANALYZER, "%s deleted child %s 3",
|
|
fmt_analyzer(this).c_str(), fmt_analyzer(child).c_str());
|
|
|
|
children.erase(i);
|
|
delete child;
|
|
}
|
|
|
|
void Analyzer::AddSupportAnalyzer(SupportAnalyzer* analyzer)
|
|
{
|
|
if ( HasSupportAnalyzer(analyzer->GetAnalyzerTag(), analyzer->IsOrig()) )
|
|
{
|
|
DBG_LOG(DBG_ANALYZER, "%s already has %s %s",
|
|
fmt_analyzer(this).c_str(),
|
|
analyzer->IsOrig() ? "originator" : "responder",
|
|
fmt_analyzer(analyzer).c_str());
|
|
|
|
analyzer->Done();
|
|
delete analyzer;
|
|
return;
|
|
}
|
|
|
|
SupportAnalyzer** head =
|
|
analyzer->IsOrig() ? &orig_supporters : &resp_supporters;
|
|
|
|
// Find end of the list.
|
|
SupportAnalyzer* prev = nullptr;
|
|
SupportAnalyzer* s;
|
|
for ( s = *head; s; prev = s, s = s->sibling )
|
|
;
|
|
|
|
if ( prev )
|
|
prev->sibling = analyzer;
|
|
else
|
|
*head = analyzer;
|
|
|
|
analyzer->parent = this;
|
|
|
|
analyzer->Init();
|
|
|
|
DBG_LOG(DBG_ANALYZER, "%s added %s support %s",
|
|
fmt_analyzer(this).c_str(),
|
|
analyzer->IsOrig() ? "originator" : "responder",
|
|
fmt_analyzer(analyzer).c_str());
|
|
}
|
|
|
|
void Analyzer::RemoveSupportAnalyzer(SupportAnalyzer* analyzer)
|
|
{
|
|
DBG_LOG(DBG_ANALYZER, "%s disabled %s support analyzer %s",
|
|
fmt_analyzer(this).c_str(),
|
|
analyzer->IsOrig() ? "originator" : "responder",
|
|
fmt_analyzer(analyzer).c_str());
|
|
|
|
// We mark the analyzer as being removed here, which will prevent it
|
|
// from being used further. However, we don't actually delete it
|
|
// before the parent gets destroyed. While we woulc do that, it's a
|
|
// bit tricky to do at the right time and it doesn't seem worth the
|
|
// trouble.
|
|
analyzer->removing = true;
|
|
return;
|
|
}
|
|
|
|
bool Analyzer::HasSupportAnalyzer(const Tag& tag, bool orig)
|
|
{
|
|
SupportAnalyzer* s = orig ? orig_supporters : resp_supporters;
|
|
for ( ; s; s = s->sibling )
|
|
if ( s->tag == tag )
|
|
return true;
|
|
|
|
return false;
|
|
}
|
|
|
|
SupportAnalyzer* Analyzer::FirstSupportAnalyzer(bool orig)
|
|
{
|
|
SupportAnalyzer* sa = orig ? orig_supporters : resp_supporters;
|
|
|
|
if ( ! sa )
|
|
return nullptr;
|
|
|
|
if ( ! sa->Removing() )
|
|
return sa;
|
|
|
|
return sa->Sibling(true);
|
|
}
|
|
|
|
void Analyzer::DeliverPacket(int len, const u_char* data, bool is_orig,
|
|
uint64_t seq, const IP_Hdr* ip, int caplen)
|
|
{
|
|
DBG_LOG(DBG_ANALYZER, "%s DeliverPacket(%d, %s, %" PRIu64", %p, %d) [%s%s]",
|
|
fmt_analyzer(this).c_str(), len, is_orig ? "T" : "F", seq, ip, caplen,
|
|
fmt_bytes((const char*) data, min(40, len)), len > 40 ? "..." : "");
|
|
}
|
|
|
|
void Analyzer::DeliverStream(int len, const u_char* data, bool is_orig)
|
|
{
|
|
DBG_LOG(DBG_ANALYZER, "%s DeliverStream(%d, %s) [%s%s]",
|
|
fmt_analyzer(this).c_str(), len, is_orig ? "T" : "F",
|
|
fmt_bytes((const char*) data, min(40, len)), len > 40 ? "..." : "");
|
|
}
|
|
|
|
void Analyzer::Undelivered(uint64_t seq, int len, bool is_orig)
|
|
{
|
|
DBG_LOG(DBG_ANALYZER, "%s Undelivered(%" PRIu64", %d, %s)",
|
|
fmt_analyzer(this).c_str(), seq, len, is_orig ? "T" : "F");
|
|
}
|
|
|
|
void Analyzer::EndOfData(bool is_orig)
|
|
{
|
|
DBG_LOG(DBG_ANALYZER, "%s EndOfData(%s)",
|
|
fmt_analyzer(this).c_str(), is_orig ? "T" : "F");
|
|
}
|
|
|
|
void Analyzer::FlipRoles()
|
|
{
|
|
DBG_LOG(DBG_ANALYZER, "%s FlipRoles()", fmt_analyzer(this).c_str());
|
|
|
|
LOOP_OVER_CHILDREN(i)
|
|
(*i)->FlipRoles();
|
|
|
|
LOOP_OVER_GIVEN_CHILDREN(i, new_children)
|
|
(*i)->FlipRoles();
|
|
|
|
for ( SupportAnalyzer* a = orig_supporters; a; a = a->sibling )
|
|
a->FlipRoles();
|
|
|
|
for ( SupportAnalyzer* a = resp_supporters; a; a = a->sibling )
|
|
a->FlipRoles();
|
|
|
|
SupportAnalyzer* tmp = orig_supporters;
|
|
orig_supporters = resp_supporters;
|
|
resp_supporters = tmp;
|
|
}
|
|
|
|
void Analyzer::ProtocolConfirmation(Tag arg_tag)
|
|
{
|
|
if ( protocol_confirmed )
|
|
return;
|
|
|
|
protocol_confirmed = true;
|
|
|
|
if ( ! protocol_confirmation )
|
|
return;
|
|
|
|
EnumVal* tval = arg_tag ? arg_tag.AsEnumVal() : tag.AsEnumVal();
|
|
|
|
mgr.Enqueue(protocol_confirmation,
|
|
ConnVal(),
|
|
IntrusivePtr{NewRef{}, tval},
|
|
val_mgr->Count(id)
|
|
);
|
|
}
|
|
|
|
void Analyzer::ProtocolViolation(const char* reason, const char* data, int len)
|
|
{
|
|
if ( ! protocol_violation )
|
|
return;
|
|
|
|
StringVal* r;
|
|
|
|
if ( data && len )
|
|
{
|
|
const char *tmp = copy_string(reason);
|
|
r = new StringVal(fmt("%s [%s%s]", tmp,
|
|
fmt_bytes(data, min(40, len)),
|
|
len > 40 ? "..." : ""));
|
|
delete [] tmp;
|
|
}
|
|
else
|
|
r = new StringVal(reason);
|
|
|
|
EnumVal* tval = tag.AsEnumVal();
|
|
|
|
mgr.Enqueue(protocol_violation,
|
|
ConnVal(),
|
|
IntrusivePtr{NewRef{}, tval},
|
|
val_mgr->Count(id),
|
|
IntrusivePtr{AdoptRef{}, r}
|
|
);
|
|
}
|
|
|
|
void Analyzer::AddTimer(analyzer_timer_func timer, double t,
|
|
bool do_expire, TimerType type)
|
|
{
|
|
Timer* analyzer_timer = new
|
|
AnalyzerTimer(this, timer, t, do_expire, type);
|
|
|
|
timer_mgr->Add(analyzer_timer);
|
|
timers.push_back(analyzer_timer);
|
|
}
|
|
|
|
void Analyzer::RemoveTimer(Timer* t)
|
|
{
|
|
timers.remove(t);
|
|
}
|
|
|
|
void Analyzer::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.
|
|
timer_list tmp(timers.length());
|
|
std::copy(timers.begin(), timers.end(), back_inserter(tmp));
|
|
|
|
// TODO: could be a for_each
|
|
for ( auto timer : tmp )
|
|
timer_mgr->Cancel(timer);
|
|
|
|
timers_canceled = true;
|
|
timers.clear();
|
|
}
|
|
|
|
void Analyzer::AppendNewChildren()
|
|
{
|
|
LOOP_OVER_GIVEN_CHILDREN(i, new_children)
|
|
children.push_back(*i);
|
|
new_children.clear();
|
|
}
|
|
|
|
unsigned int Analyzer::MemoryAllocation() const
|
|
{
|
|
unsigned int mem = padded_sizeof(*this)
|
|
+ (timers.MemoryAllocation() - padded_sizeof(timers));
|
|
|
|
LOOP_OVER_CONST_CHILDREN(i)
|
|
mem += (*i)->MemoryAllocation();
|
|
|
|
for ( SupportAnalyzer* a = orig_supporters; a; a = a->sibling )
|
|
mem += a->MemoryAllocation();
|
|
|
|
for ( SupportAnalyzer* a = resp_supporters; a; a = a->sibling )
|
|
mem += a->MemoryAllocation();
|
|
|
|
return mem;
|
|
}
|
|
|
|
void Analyzer::UpdateConnVal(RecordVal *conn_val)
|
|
{
|
|
LOOP_OVER_CHILDREN(i)
|
|
(*i)->UpdateConnVal(conn_val);
|
|
}
|
|
|
|
RecordVal* Analyzer::BuildConnVal()
|
|
{
|
|
return conn->ConnVal()->Ref()->AsRecordVal();
|
|
}
|
|
|
|
const IntrusivePtr<RecordVal>& Analyzer::ConnVal()
|
|
{
|
|
return conn->ConnVal();
|
|
}
|
|
|
|
void Analyzer::Event(EventHandlerPtr f, const char* name)
|
|
{
|
|
conn->Event(f, this, name);
|
|
}
|
|
|
|
void Analyzer::Event(EventHandlerPtr f, Val* v1, Val* v2)
|
|
{
|
|
conn->Event(f, this, v1, v2);
|
|
}
|
|
|
|
void Analyzer::ConnectionEvent(EventHandlerPtr f, val_list* vl)
|
|
{
|
|
auto args = zeek::val_list_to_args(*vl);
|
|
|
|
if ( f )
|
|
conn->EnqueueEvent(f, this, std::move(args));
|
|
}
|
|
|
|
void Analyzer::ConnectionEvent(EventHandlerPtr f, val_list vl)
|
|
{
|
|
auto args = zeek::val_list_to_args(vl);
|
|
|
|
if ( f )
|
|
conn->EnqueueEvent(f, this, std::move(args));
|
|
}
|
|
|
|
void Analyzer::ConnectionEventFast(EventHandlerPtr f, val_list vl)
|
|
{
|
|
auto args = zeek::val_list_to_args(vl);
|
|
conn->EnqueueEvent(f, this, std::move(args));
|
|
}
|
|
|
|
void Analyzer::EnqueueConnEvent(EventHandlerPtr f, zeek::Args args)
|
|
{
|
|
conn->EnqueueEvent(f, this, std::move(args));
|
|
}
|
|
|
|
void Analyzer::Weird(const char* name, const char* addl)
|
|
{
|
|
conn->Weird(name, addl);
|
|
}
|
|
|
|
SupportAnalyzer* SupportAnalyzer::Sibling(bool only_active) const
|
|
{
|
|
if ( ! only_active )
|
|
return sibling;
|
|
|
|
SupportAnalyzer* next = sibling;
|
|
while ( next && next->Removing() )
|
|
next = next->sibling;
|
|
|
|
return next;
|
|
}
|
|
|
|
void SupportAnalyzer::ForwardPacket(int len, const u_char* data, bool is_orig,
|
|
uint64_t seq, const IP_Hdr* ip, int caplen)
|
|
{
|
|
// We do not call parent's method, as we're replacing the functionality.
|
|
|
|
if ( GetOutputHandler() )
|
|
{
|
|
GetOutputHandler()->DeliverPacket(len, data, is_orig, seq,
|
|
ip, caplen);
|
|
return;
|
|
}
|
|
|
|
SupportAnalyzer* next_sibling = Sibling(true);
|
|
|
|
if ( next_sibling )
|
|
// Pass to next in chain.
|
|
next_sibling->NextPacket(len, data, is_orig, seq, ip, caplen);
|
|
else
|
|
// Finished with preprocessing - now it's the parent's turn.
|
|
Parent()->DeliverPacket(len, data, is_orig, seq, ip, caplen);
|
|
}
|
|
|
|
void SupportAnalyzer::ForwardStream(int len, const u_char* data, bool is_orig)
|
|
{
|
|
// We do not call parent's method, as we're replacing the functionality.
|
|
|
|
if ( GetOutputHandler() )
|
|
{
|
|
GetOutputHandler()->DeliverStream(len, data, is_orig);
|
|
return;
|
|
}
|
|
|
|
SupportAnalyzer* next_sibling = Sibling(true);
|
|
|
|
if ( next_sibling )
|
|
// Pass to next in chain.
|
|
next_sibling->NextStream(len, data, is_orig);
|
|
else
|
|
// Finished with preprocessing - now it's the parent's turn.
|
|
Parent()->DeliverStream(len, data, is_orig);
|
|
}
|
|
|
|
void SupportAnalyzer::ForwardUndelivered(uint64_t seq, int len, bool is_orig)
|
|
{
|
|
// We do not call parent's method, as we're replacing the functionality.
|
|
|
|
if ( GetOutputHandler() )
|
|
{
|
|
GetOutputHandler()->Undelivered(seq, len, is_orig);
|
|
return;
|
|
}
|
|
|
|
SupportAnalyzer* next_sibling = Sibling(true);
|
|
|
|
if ( next_sibling )
|
|
// Pass to next in chain.
|
|
next_sibling->NextUndelivered(seq, len, is_orig);
|
|
else
|
|
// Finished with preprocessing - now it's the parent's turn.
|
|
Parent()->Undelivered(seq, len, is_orig);
|
|
}
|
|
|
|
|
|
void TransportLayerAnalyzer::Done()
|
|
{
|
|
Analyzer::Done();
|
|
}
|
|
|
|
void TransportLayerAnalyzer::SetContentsFile(unsigned int /* direction */,
|
|
BroFile* /* f */)
|
|
{
|
|
reporter->Error("analyzer type does not support writing to a contents file");
|
|
}
|
|
|
|
BroFile* TransportLayerAnalyzer::GetContentsFile(unsigned int /* direction */) const
|
|
{
|
|
reporter->Error("analyzer type does not support writing to a contents file");
|
|
return nullptr;
|
|
}
|
|
|
|
void TransportLayerAnalyzer::PacketContents(const u_char* data, int len)
|
|
{
|
|
if ( packet_contents && len > 0 )
|
|
{
|
|
BroString* cbs = new BroString(data, len, true);
|
|
Val* contents = new StringVal(cbs);
|
|
Event(packet_contents, contents);
|
|
}
|
|
}
|