zeek/src/analyzer/Manager.cc
Josh Soref cd201aa24e Spelling src
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>
2022-11-09 12:08:15 -05:00

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