mirror of
https://github.com/zeek/zeek.git
synced 2025-10-02 06:38:20 +00:00

These are non-functional changes. * accounting * activation * actual * added * addresult * aggregable * aligned * alternatively * ambiguous * analysis * analyzer * anticlimactic * apparently * application * appropriate * arithmetic * assignment * assigns * associated * authentication * authoritative * barrier * boundary * broccoli * buffering * caching * called * canonicalized * capturing * certificates * ciphersuite * columns * communication * comparison * comparisons * compilation * component * concatenating * concatenation * connection * convenience * correctly * corresponding * could * counting * data * declared * decryption * defining * dependent * deprecated * detached * dictionary * directional * directly * directory * discarding * disconnecting * distinguishes * documentation * elsewhere * emitted * empty * endianness * endpoint * enumerator * essentially * evaluated * everything * exactly * execute * explicit * expressions * facilitates * fiddling * filesystem * flag * flagged * for * fragments * guarantee * guaranteed * happen * happening * hemisphere * identifier * identifies * identify * implementation * implemented * implementing * including * inconsistency * indeterminate * indices * individual * information * initial * initialization * initialize * initialized * initializes * instantiate * instantiated * instantiates * interface * internal * interpreted * interpreter * into * it * iterators * length * likely * log * longer * mainly * mark * maximum * message * minimum * module * must * name * namespace * necessary * nonexistent * not * notifications * notifier * number * objects * occurred * operations * original * otherwise * output * overridden * override * overriding * overwriting * ownership * parameters * particular * payload * persistent * potential * precision * preexisting * preservation * preserved * primarily * probably * procedure * proceed * process * processed * processes * processing * propagate * propagated * prototype * provides * publishing * purposes * queue * reached * reason * reassem * reassemble * reassembler * recommend * record * reduction * reference * regularly * representation * request * reserved * retrieve * returning * separate * should * shouldn't * significant * signing * simplified * simultaneously * single * somebody * sources * specific * specification * specified * specifies * specify * statement * subdirectories * succeeded * successful * successfully * supplied * synchronization * tag * temporarily * terminating * that * the * transmitted * true * truncated * try * understand * unescaped * unforwarding * unknown * unknowndata * unspecified * update * usually * which * wildcard Signed-off-by: Josh Soref <2119212+jsoref@users.noreply.github.com>
468 lines
11 KiB
C++
468 lines
11 KiB
C++
// See the file "COPYING" in the main distribution directory for copyright.
|
|
|
|
#include "zeek/analyzer/Manager.h"
|
|
|
|
#include "zeek/Hash.h"
|
|
#include "zeek/IntrusivePtr.h"
|
|
#include "zeek/RunState.h"
|
|
#include "zeek/Val.h"
|
|
#include "zeek/analyzer/protocol/conn-size/ConnSize.h"
|
|
#include "zeek/analyzer/protocol/pia/PIA.h"
|
|
#include "zeek/analyzer/protocol/tcp/TCP.h"
|
|
#include "zeek/analyzer/protocol/tcp/events.bif.h"
|
|
#include "zeek/packet_analysis/protocol/ip/IPBasedAnalyzer.h"
|
|
#include "zeek/packet_analysis/protocol/ip/SessionAdapter.h"
|
|
#include "zeek/plugin/Manager.h"
|
|
|
|
namespace zeek::analyzer
|
|
{
|
|
|
|
Manager::ConnIndex::ConnIndex(const IPAddr& _orig, const IPAddr& _resp, uint16_t _resp_p,
|
|
uint16_t _proto)
|
|
{
|
|
if ( _orig == IPAddr::v4_unspecified )
|
|
// don't use the IPv4 mapping, use the literal unspecified address
|
|
// to indicate a wildcard
|
|
orig = IPAddr::v6_unspecified;
|
|
else
|
|
orig = _orig;
|
|
|
|
resp = _resp;
|
|
resp_p = _resp_p;
|
|
proto = _proto;
|
|
}
|
|
|
|
Manager::ConnIndex::ConnIndex()
|
|
{
|
|
orig = resp = IPAddr::v4_unspecified;
|
|
resp_p = 0;
|
|
proto = 0;
|
|
}
|
|
|
|
bool Manager::ConnIndex::operator<(const ConnIndex& other) const
|
|
{
|
|
if ( orig != other.orig )
|
|
return orig < other.orig;
|
|
|
|
if ( resp != other.resp )
|
|
return resp < other.resp;
|
|
|
|
if ( proto != other.proto )
|
|
return proto < other.proto;
|
|
|
|
if ( resp_p != other.resp_p )
|
|
return resp_p < other.resp_p;
|
|
|
|
return false;
|
|
}
|
|
|
|
Manager::Manager()
|
|
: plugin::ComponentManager<analyzer::Component>("Analyzer", "Tag", "AllAnalyzers")
|
|
{
|
|
}
|
|
|
|
Manager::~Manager()
|
|
{
|
|
// Clean up expected-connection table.
|
|
while ( conns_by_timeout.size() )
|
|
{
|
|
ScheduledAnalyzer* a = conns_by_timeout.top();
|
|
conns_by_timeout.pop();
|
|
delete a;
|
|
}
|
|
}
|
|
|
|
void Manager::InitPostScript()
|
|
{
|
|
const auto& id = detail::global_scope()->Find("PacketAnalyzer::VXLAN::vxlan_ports");
|
|
|
|
if ( ! (id && id->GetVal()) )
|
|
reporter->FatalError("PacketAnalyzer::VXLAN::vxlan_ports not defined");
|
|
|
|
auto table_val = id->GetVal()->AsTableVal();
|
|
auto port_list = table_val->ToPureListVal();
|
|
|
|
for ( auto i = 0; i < port_list->Length(); ++i )
|
|
vxlan_ports.emplace_back(port_list->Idx(i)->AsPortVal()->Port());
|
|
|
|
for ( const auto& p : pending_analyzers_for_ports )
|
|
{
|
|
if ( ! RegisterAnalyzerForPort(p) )
|
|
reporter->Warning("cannot register analyzer for port %u", std::get<2>(p));
|
|
}
|
|
|
|
pending_analyzers_for_ports.clear();
|
|
|
|
initialized = true;
|
|
}
|
|
|
|
void Manager::DumpDebug()
|
|
{
|
|
#ifdef DEBUG
|
|
DBG_LOG(DBG_ANALYZER, "Available analyzers after zeek_init():");
|
|
std::list<Component*> all_analyzers = GetComponents();
|
|
for ( std::list<Component*>::const_iterator i = all_analyzers.begin(); i != all_analyzers.end();
|
|
++i )
|
|
DBG_LOG(DBG_ANALYZER, " %s (%s)", (*i)->Name().c_str(),
|
|
IsEnabled((*i)->Tag()) ? "enabled" : "disabled");
|
|
|
|
DBG_LOG(DBG_ANALYZER, " ");
|
|
DBG_LOG(DBG_ANALYZER, "Analyzers by port:");
|
|
|
|
if ( packet_analysis::AnalyzerPtr tcp = packet_mgr->GetAnalyzer("TCP") )
|
|
{
|
|
auto* ipba = static_cast<packet_analysis::IP::IPBasedAnalyzer*>(tcp.get());
|
|
ipba->DumpPortDebug();
|
|
}
|
|
|
|
if ( packet_analysis::AnalyzerPtr udp = packet_mgr->GetAnalyzer("UDP") )
|
|
{
|
|
auto* ipba = static_cast<packet_analysis::IP::IPBasedAnalyzer*>(udp.get());
|
|
ipba->DumpPortDebug();
|
|
}
|
|
|
|
#endif
|
|
}
|
|
|
|
void Manager::Done() { }
|
|
|
|
bool Manager::EnableAnalyzer(const zeek::Tag& tag)
|
|
{
|
|
Component* p = Lookup(tag);
|
|
|
|
if ( ! p )
|
|
return false;
|
|
|
|
DBG_LOG(DBG_ANALYZER, "Enabling analyzer %s", p->Name().c_str());
|
|
p->SetEnabled(true);
|
|
|
|
return true;
|
|
}
|
|
|
|
bool Manager::EnableAnalyzer(EnumVal* val)
|
|
{
|
|
Component* p = Lookup(val);
|
|
|
|
if ( ! p )
|
|
return false;
|
|
|
|
DBG_LOG(DBG_ANALYZER, "Enabling analyzer %s", p->Name().c_str());
|
|
p->SetEnabled(true);
|
|
|
|
return true;
|
|
}
|
|
|
|
bool Manager::DisableAnalyzer(const zeek::Tag& tag)
|
|
{
|
|
Component* p = Lookup(tag);
|
|
|
|
if ( ! p )
|
|
return false;
|
|
|
|
DBG_LOG(DBG_ANALYZER, "Disabling analyzer %s", p->Name().c_str());
|
|
p->SetEnabled(false);
|
|
|
|
return true;
|
|
}
|
|
|
|
bool Manager::DisableAnalyzer(EnumVal* val)
|
|
{
|
|
Component* p = Lookup(val);
|
|
|
|
if ( ! p )
|
|
return false;
|
|
|
|
DBG_LOG(DBG_ANALYZER, "Disabling analyzer %s", p->Name().c_str());
|
|
p->SetEnabled(false);
|
|
|
|
return true;
|
|
}
|
|
|
|
void Manager::DisableAllAnalyzers()
|
|
{
|
|
DBG_LOG(DBG_ANALYZER, "Disabling all analyzers");
|
|
|
|
std::list<Component*> all_analyzers = GetComponents();
|
|
for ( std::list<Component*>::const_iterator i = all_analyzers.begin(); i != all_analyzers.end();
|
|
++i )
|
|
(*i)->SetEnabled(false);
|
|
}
|
|
|
|
zeek::Tag Manager::GetAnalyzerTag(const char* name)
|
|
{
|
|
return GetComponentTag(name);
|
|
}
|
|
|
|
bool Manager::IsEnabled(const zeek::Tag& tag)
|
|
{
|
|
if ( ! tag )
|
|
return false;
|
|
|
|
Component* p = Lookup(tag);
|
|
|
|
if ( ! p )
|
|
return false;
|
|
|
|
return p->Enabled();
|
|
}
|
|
|
|
bool Manager::IsEnabled(EnumVal* val)
|
|
{
|
|
Component* p = Lookup(val);
|
|
|
|
if ( ! p )
|
|
return false;
|
|
|
|
return p->Enabled();
|
|
}
|
|
|
|
bool Manager::RegisterAnalyzerForPort(EnumVal* val, PortVal* port)
|
|
{
|
|
Component* p = Lookup(val);
|
|
|
|
if ( ! p )
|
|
return false;
|
|
|
|
return RegisterAnalyzerForPort(p->Tag(), port->PortType(), port->Port());
|
|
}
|
|
|
|
bool Manager::UnregisterAnalyzerForPort(EnumVal* val, PortVal* port)
|
|
{
|
|
Component* p = Lookup(val);
|
|
|
|
if ( ! p )
|
|
return false;
|
|
|
|
return UnregisterAnalyzerForPort(p->Tag(), port->PortType(), port->Port());
|
|
}
|
|
|
|
bool Manager::RegisterAnalyzerForPort(const zeek::Tag& tag, TransportProto proto, uint32_t port)
|
|
{
|
|
if ( initialized )
|
|
return RegisterAnalyzerForPort(std::make_tuple(tag, proto, port));
|
|
else
|
|
{
|
|
// Cannot register these before PostScriptInit() has run because we
|
|
// depend on packet analysis having been set up. That also means we don't have
|
|
// a reliable return value, for now we just assume it's working.
|
|
pending_analyzers_for_ports.emplace(tag, proto, port);
|
|
return true;
|
|
}
|
|
}
|
|
|
|
bool Manager::RegisterAnalyzerForPort(const std::tuple<zeek::Tag, TransportProto, uint32_t>& p)
|
|
{
|
|
const auto& [tag, proto, port] = p;
|
|
|
|
// TODO: this class is becoming more generic and removing a lot of the
|
|
// checks for protocols, but this part might need to stay like this.
|
|
packet_analysis::AnalyzerPtr analyzer;
|
|
if ( proto == TRANSPORT_TCP )
|
|
analyzer = packet_mgr->GetAnalyzer("TCP");
|
|
else if ( proto == TRANSPORT_UDP )
|
|
analyzer = packet_mgr->GetAnalyzer("UDP");
|
|
|
|
if ( ! analyzer )
|
|
return false;
|
|
|
|
auto* ipba = static_cast<packet_analysis::IP::IPBasedAnalyzer*>(analyzer.get());
|
|
|
|
return ipba->RegisterAnalyzerForPort(tag, port);
|
|
}
|
|
|
|
bool Manager::UnregisterAnalyzerForPort(const zeek::Tag& tag, TransportProto proto, uint32_t port)
|
|
{
|
|
if ( auto i = pending_analyzers_for_ports.find(std::make_tuple(tag, proto, port));
|
|
i != pending_analyzers_for_ports.end() )
|
|
pending_analyzers_for_ports.erase(i);
|
|
|
|
// TODO: this class is becoming more generic and removing a lot of the
|
|
// checks for protocols, but this part might need to stay like this.
|
|
packet_analysis::AnalyzerPtr analyzer;
|
|
if ( proto == TRANSPORT_TCP )
|
|
analyzer = packet_mgr->GetAnalyzer("TCP");
|
|
else if ( proto == TRANSPORT_UDP )
|
|
analyzer = packet_mgr->GetAnalyzer("UDP");
|
|
|
|
if ( ! analyzer )
|
|
return false;
|
|
|
|
auto* ipba = static_cast<packet_analysis::IP::IPBasedAnalyzer*>(analyzer.get());
|
|
|
|
return ipba->UnregisterAnalyzerForPort(tag, port);
|
|
}
|
|
|
|
Analyzer* Manager::InstantiateAnalyzer(const zeek::Tag& tag, Connection* conn)
|
|
{
|
|
Component* c = Lookup(tag);
|
|
|
|
if ( ! c )
|
|
{
|
|
reporter->InternalWarning("request to instantiate unknown analyzer");
|
|
return nullptr;
|
|
}
|
|
|
|
if ( ! c->Enabled() )
|
|
return nullptr;
|
|
|
|
if ( ! c->Factory() )
|
|
{
|
|
reporter->InternalWarning("analyzer %s cannot be instantiated dynamically",
|
|
GetComponentName(tag).c_str());
|
|
return nullptr;
|
|
}
|
|
|
|
Analyzer* a = c->Factory()(conn);
|
|
|
|
if ( ! a )
|
|
{
|
|
reporter->InternalWarning("analyzer instantiation failed");
|
|
return nullptr;
|
|
}
|
|
|
|
a->SetAnalyzerTag(tag);
|
|
|
|
return a;
|
|
}
|
|
|
|
Analyzer* Manager::InstantiateAnalyzer(const char* name, Connection* conn)
|
|
{
|
|
zeek::Tag tag = GetComponentTag(name);
|
|
return tag ? InstantiateAnalyzer(tag, conn) : nullptr;
|
|
}
|
|
|
|
void Manager::ExpireScheduledAnalyzers()
|
|
{
|
|
if ( ! run_state::network_time )
|
|
return;
|
|
|
|
while ( conns_by_timeout.size() )
|
|
{
|
|
ScheduledAnalyzer* a = conns_by_timeout.top();
|
|
|
|
if ( a->timeout > run_state::network_time )
|
|
return;
|
|
|
|
conns_by_timeout.pop();
|
|
|
|
std::pair<conns_map::iterator, conns_map::iterator> all = conns.equal_range(a->conn);
|
|
|
|
bool found = false;
|
|
|
|
for ( conns_map::iterator i = all.first; i != all.second; i++ )
|
|
{
|
|
if ( i->second != a )
|
|
continue;
|
|
|
|
conns.erase(i);
|
|
|
|
DBG_LOG(DBG_ANALYZER, "Expiring expected analyzer %s for connection %s",
|
|
analyzer_mgr->GetComponentName(a->analyzer).c_str(),
|
|
fmt_conn_id(a->conn.orig, 0, a->conn.resp, a->conn.resp_p));
|
|
|
|
delete a;
|
|
found = true;
|
|
break;
|
|
}
|
|
|
|
assert(found);
|
|
}
|
|
}
|
|
|
|
void Manager::ScheduleAnalyzer(const IPAddr& orig, const IPAddr& resp, uint16_t resp_p,
|
|
TransportProto proto, const zeek::Tag& analyzer, double timeout)
|
|
{
|
|
if ( ! run_state::network_time )
|
|
{
|
|
reporter->Warning("cannot schedule analyzers before processing begins; ignored");
|
|
return;
|
|
}
|
|
|
|
assert(timeout);
|
|
|
|
// Use the chance to see if the oldest entry is already expired.
|
|
ExpireScheduledAnalyzers();
|
|
|
|
ScheduledAnalyzer* a = new ScheduledAnalyzer;
|
|
a->conn = ConnIndex(orig, resp, resp_p, proto);
|
|
a->analyzer = analyzer;
|
|
a->timeout = run_state::network_time + timeout;
|
|
|
|
conns.insert(std::make_pair(a->conn, a));
|
|
conns_by_timeout.push(a);
|
|
}
|
|
|
|
void Manager::ScheduleAnalyzer(const IPAddr& orig, const IPAddr& resp, uint16_t resp_p,
|
|
TransportProto proto, const char* analyzer, double timeout)
|
|
{
|
|
zeek::Tag tag = GetComponentTag(analyzer);
|
|
|
|
if ( tag != zeek::Tag() )
|
|
ScheduleAnalyzer(orig, resp, resp_p, proto, tag, timeout);
|
|
}
|
|
|
|
void Manager::ScheduleAnalyzer(const IPAddr& orig, const IPAddr& resp, PortVal* resp_p,
|
|
Val* analyzer, double timeout)
|
|
{
|
|
EnumValPtr ev{NewRef{}, analyzer->AsEnumVal()};
|
|
return ScheduleAnalyzer(orig, resp, resp_p->Port(), resp_p->PortType(),
|
|
zeek::Tag(std::move(ev)), timeout);
|
|
}
|
|
|
|
Manager::tag_set Manager::GetScheduled(const Connection* conn)
|
|
{
|
|
ConnIndex c(conn->OrigAddr(), conn->RespAddr(), ntohs(conn->RespPort()), conn->ConnTransport());
|
|
|
|
std::pair<conns_map::iterator, conns_map::iterator> all = conns.equal_range(c);
|
|
|
|
tag_set result;
|
|
|
|
for ( conns_map::iterator i = all.first; i != all.second; i++ )
|
|
result.insert(i->second->analyzer);
|
|
|
|
// Try wildcard for originator.
|
|
c.orig = IPAddr::v6_unspecified;
|
|
all = conns.equal_range(c);
|
|
|
|
for ( conns_map::iterator i = all.first; i != all.second; i++ )
|
|
{
|
|
if ( i->second->timeout > run_state::network_time )
|
|
result.insert(i->second->analyzer);
|
|
}
|
|
|
|
// We don't delete scheduled analyzers here. They will be expired
|
|
// eventually.
|
|
return result;
|
|
}
|
|
|
|
bool Manager::ApplyScheduledAnalyzers(Connection* conn, bool init,
|
|
packet_analysis::IP::SessionAdapter* parent)
|
|
{
|
|
if ( ! parent )
|
|
parent = conn->GetSessionAdapter();
|
|
|
|
if ( ! parent )
|
|
return false;
|
|
|
|
tag_set expected = GetScheduled(conn);
|
|
|
|
for ( tag_set::iterator it = expected.begin(); it != expected.end(); ++it )
|
|
{
|
|
Analyzer* analyzer = analyzer_mgr->InstantiateAnalyzer(*it, conn);
|
|
|
|
if ( ! analyzer )
|
|
continue;
|
|
|
|
parent->AddChildAnalyzer(analyzer, init);
|
|
|
|
if ( scheduled_analyzer_applied )
|
|
conn->EnqueueEvent(scheduled_analyzer_applied, nullptr, conn->GetVal(), it->AsVal());
|
|
|
|
DBG_ANALYZER_ARGS(conn, "activated %s analyzer as scheduled",
|
|
analyzer_mgr->GetComponentName(*it).c_str());
|
|
}
|
|
|
|
return expected.size();
|
|
}
|
|
|
|
} // namespace zeek::analyzer
|