Lots of cleanup and API documentation for the analyzer/* classes.

I've used the opportunity to also cleanup DPD's expect_connection()
infrastructure, and renamed that bif to schedule_analyzer(), which
seems more appropiate. One can now also schedule more than one
analyzer per connection.

TODOs:
        - "make install" is probably broken.
        - Broxygen is probably broken for plugin-defined events.
        - event groups are broken (do we want to keep them?)
        - parallel btest is broken, but I'm not sure why ...
          (tests all pass individually, but lots of error when running
          in parallel; must be related to *.bif restructuring).
        - Document API for src/plugin/*
        - Document API for src/analyzer/Analyzer.h
        - Document API for scripts/base/frameworks/analyzer
This commit is contained in:
Robin Sommer 2013-03-30 19:29:20 -07:00
parent e532aff687
commit e0c4bd1a82
32 changed files with 994 additions and 550 deletions

View file

@ -22,6 +22,9 @@ rest_target(${CMAKE_BINARY_DIR}/src base/const.bif.bro)
rest_target(${CMAKE_BINARY_DIR}/src base/event.bif.bro) rest_target(${CMAKE_BINARY_DIR}/src base/event.bif.bro)
rest_target(${CMAKE_BINARY_DIR}/src base/input.bif.bro) rest_target(${CMAKE_BINARY_DIR}/src base/input.bif.bro)
rest_target(${CMAKE_BINARY_DIR}/src base/logging.bif.bro) rest_target(${CMAKE_BINARY_DIR}/src base/logging.bif.bro)
rest_target(${CMAKE_BINARY_DIR}/src base/protocols/http/events.bif.bro)
rest_target(${CMAKE_BINARY_DIR}/src base/protocols/http/functions.bif.bro)
rest_target(${CMAKE_BINARY_DIR}/src base/protocols/ssl/events.bif.bro)
rest_target(${CMAKE_BINARY_DIR}/src base/reporter.bif.bro) rest_target(${CMAKE_BINARY_DIR}/src base/reporter.bif.bro)
rest_target(${CMAKE_BINARY_DIR}/src base/strings.bif.bro) rest_target(${CMAKE_BINARY_DIR}/src base/strings.bif.bro)
rest_target(${CMAKE_BINARY_DIR}/src base/types.bif.bro) rest_target(${CMAKE_BINARY_DIR}/src base/types.bif.bro)

View file

@ -45,7 +45,7 @@ export {
## tout: The timeout interval after which to ignore the scheduling request. ## tout: The timeout interval after which to ignore the scheduling request.
## ##
## Returns: True if succesful. ## Returns: True if succesful.
global expect_connection: function(orig: addr, resp: addr, resp_p: port, global schedule_analyzer: function(orig: addr, resp: addr, resp_p: port,
analyzer: Analyzer::Tag, tout: interval) : bool; analyzer: Analyzer::Tag, tout: interval) : bool;
## Analyzers to disable at startup. ## Analyzers to disable at startup.
@ -119,9 +119,9 @@ function name(atype: Analyzer::Tag) : string
return __name(atype); return __name(atype);
} }
function expect_connection(orig: addr, resp: addr, resp_p: port, function schedule_analyzer(orig: addr, resp: addr, resp_p: port,
analyzer: Analyzer::Tag, tout: interval) : bool analyzer: Analyzer::Tag, tout: interval) : bool
{ {
return __expect_connection(orig, resp, resp_p, analyzer, tout); return __schedule_analyzer(orig, resp, resp_p, analyzer, tout);
} }

View file

@ -228,7 +228,7 @@ event ftp_request(c: connection, command: string, arg: string) &priority=5
{ {
c$ftp$passive=F; c$ftp$passive=F;
ftp_data_expected[data$h, data$p] = c$ftp; ftp_data_expected[data$h, data$p] = c$ftp;
Analyzer::expect_connection(id$resp_h, data$h, data$p, Analyzer::ANALYZER_FILE, 5mins); Analyzer::schedule_analyzer(id$resp_h, data$h, data$p, Analyzer::ANALYZER_FILE, 5mins);
} }
else else
{ {
@ -281,7 +281,7 @@ event ftp_reply(c: connection, code: count, msg: string, cont_resp: bool) &prior
data$h = id$resp_h; data$h = id$resp_h;
ftp_data_expected[data$h, data$p] = c$ftp; ftp_data_expected[data$h, data$p] = c$ftp;
Analyzer::expect_connection(id$orig_h, data$h, data$p, Analyzer::ANALYZER_FILE, 5mins); Analyzer::schedule_analyzer(id$orig_h, data$h, data$p, Analyzer::ANALYZER_FILE, 5mins);
} }
else else
{ {
@ -312,7 +312,7 @@ event ftp_reply(c: connection, code: count, msg: string, cont_resp: bool) &prior
} }
event expected_connection_seen(c: connection, a: count) &priority=10 event scheduled_analyzer_applied(c: connection, a: Analyzer::Tag) &priority=10
{ {
local id = c$id; local id = c$id;
if ( [id$resp_h, id$resp_p] in ftp_data_expected ) if ( [id$resp_h, id$resp_p] in ftp_data_expected )

View file

@ -104,7 +104,7 @@ event irc_dcc_message(c: connection, is_orig: bool,
c$irc$dcc_file_name = argument; c$irc$dcc_file_name = argument;
c$irc$dcc_file_size = size; c$irc$dcc_file_size = size;
local p = count_to_port(dest_port, tcp); local p = count_to_port(dest_port, tcp);
Analyzer::expect_connection(to_addr("0.0.0.0"), address, p, Analyzer::ANALYZER_FILE, 5 min); Analyzer::schedule_analyzer(to_addr("0.0.0.0"), address, p, Analyzer::ANALYZER_FILE, 5 min);
dcc_expected_transfers[address, p] = c$irc; dcc_expected_transfers[address, p] = c$irc;
} }

View file

@ -400,7 +400,7 @@ set(bro_SRCS
analyzer/Analyzer.cc analyzer/Analyzer.cc
analyzer/Manager.cc analyzer/Manager.cc
analyzer/PluginComponent.cc analyzer/Component.cc
analyzer/Tag.cc analyzer/Tag.cc
protocols/BuiltInAnalyzers.cc protocols/BuiltInAnalyzers.cc

View file

@ -161,8 +161,8 @@ static void add_dce_rpc_endpoint(const dce_rpc_endpoint_addr& addr,
// of the dce_rpc_endpoints table. // of the dce_rpc_endpoints table.
// FIXME: Don't hard-code the timeout. // FIXME: Don't hard-code the timeout.
analyzer_mgr->ExpectConnection(IPAddr(), addr.addr, addr.port, addr.proto, analyzer_mgr->ScheduleAnalyzer(IPAddr(), addr.addr, addr.port, addr.proto,
"DCE_RPC", 5 * 60, 0); "DCE_RPC", 5 * 60);
} }
DCE_RPC_Header::DCE_RPC_Header(analyzer::Analyzer* a, const u_char* b) DCE_RPC_Header::DCE_RPC_Header(analyzer::Analyzer* a, const u_char* b)

View file

@ -21,7 +21,7 @@ enum DebugStream {
DBG_STRING, // String code DBG_STRING, // String code
DBG_NOTIFIERS, // Notifiers (see StateAccess.h) DBG_NOTIFIERS, // Notifiers (see StateAccess.h)
DBG_MAINLOOP, // Main IOSource loop DBG_MAINLOOP, // Main IOSource loop
DBG_DPD, // Dynamic application detection framework DBG_ANALYZER, // Analyzer framework
DBG_TM, // Time-machine packet input via Brocolli DBG_TM, // Time-machine packet input via Brocolli
DBG_LOGGING, // Logging streams DBG_LOGGING, // Logging streams
DBG_INPUT, // Input streams DBG_INPUT, // Input streams

View file

@ -45,23 +45,6 @@ HashKey* BuildConnIDHashKey(const ConnID& id)
return new HashKey(&key, sizeof(key)); return new HashKey(&key, sizeof(key));
} }
HashKey* BuildExpectedConnHashKey(const analyzer::ExpectedConn& c)
{
struct {
in6_addr orig;
in6_addr resp;
uint16 resp_p;
uint16 proto;
} key;
key.orig = c.orig.in6;
key.resp = c.resp.in6;
key.resp_p = c.resp_p;
key.proto = c.proto;
return new HashKey(&key, sizeof(key));
}
void IPAddr::Mask(int top_bits_to_keep) void IPAddr::Mask(int top_bits_to_keep)
{ {
if ( top_bits_to_keep < 0 || top_bits_to_keep > 128 ) if ( top_bits_to_keep < 0 || top_bits_to_keep > 128 )

View file

@ -363,7 +363,6 @@ public:
void ConvertToThreadingValue(threading::Value::addr_t* v) const; void ConvertToThreadingValue(threading::Value::addr_t* v) const;
friend HashKey* BuildConnIDHashKey(const ConnID& id); friend HashKey* BuildConnIDHashKey(const ConnID& id);
friend HashKey* BuildExpectedConnHashKey(const analyzer::ExpectedConn& c);
unsigned int MemoryAllocation() const { return padded_sizeof(*this); } unsigned int MemoryAllocation() const { return padded_sizeof(*this); }

View file

@ -63,7 +63,7 @@ void PIA::AddToBuffer(Buffer* buffer, int len, const u_char* data, bool is_orig)
void PIA::ReplayPacketBuffer(analyzer::Analyzer* analyzer) void PIA::ReplayPacketBuffer(analyzer::Analyzer* analyzer)
{ {
DBG_LOG(DBG_DPD, "PIA replaying %d total packet bytes", pkt_buffer.size); DBG_LOG(DBG_ANALYZER, "PIA replaying %d total packet bytes", pkt_buffer.size);
for ( DataBlock* b = pkt_buffer.head; b; b = b->next ) for ( DataBlock* b = pkt_buffer.head; b; b = b->next )
analyzer->DeliverPacket(b->len, b->data, b->is_orig, -1, 0, 0); analyzer->DeliverPacket(b->len, b->data, b->is_orig, -1, 0, 0);
@ -133,7 +133,7 @@ void PIA_UDP::ActivateAnalyzer(analyzer::Tag tag, const Rule* rule)
{ {
if ( pkt_buffer.state == MATCHING_ONLY ) if ( pkt_buffer.state == MATCHING_ONLY )
{ {
DBG_LOG(DBG_DPD, "analyzer found but buffer already exceeded"); DBG_LOG(DBG_ANALYZER, "analyzer found but buffer already exceeded");
// FIXME: This is where to check whether an analyzer // FIXME: This is where to check whether an analyzer
// supports partial connections once we get such. // supports partial connections once we get such.
return; return;
@ -180,7 +180,7 @@ void PIA_TCP::FirstPacket(bool is_orig, const IP_Hdr* ip)
static struct tcphdr* tcp4 = 0; static struct tcphdr* tcp4 = 0;
static IP_Hdr* ip4_hdr = 0; static IP_Hdr* ip4_hdr = 0;
DBG_LOG(DBG_DPD, "PIA_TCP[%d] FirstPacket(%s)", GetID(), (is_orig ? "T" : "F")); DBG_LOG(DBG_ANALYZER, "PIA_TCP[%d] FirstPacket(%s)", GetID(), (is_orig ? "T" : "F"));
if ( ! ip ) if ( ! ip )
{ {
@ -266,7 +266,7 @@ void PIA_TCP::ActivateAnalyzer(analyzer::Tag tag, const Rule* rule)
{ {
if ( stream_buffer.state == MATCHING_ONLY ) if ( stream_buffer.state == MATCHING_ONLY )
{ {
DBG_LOG(DBG_DPD, "analyzer found but buffer already exceeded"); DBG_LOG(DBG_ANALYZER, "analyzer found but buffer already exceeded");
// FIXME: This is where to check whether an analyzer supports // FIXME: This is where to check whether an analyzer supports
// partial connections once we get such. // partial connections once we get such.
return; return;
@ -305,7 +305,7 @@ void PIA_TCP::ActivateAnalyzer(analyzer::Tag tag, const Rule* rule)
// (4) We hand the two reassemblers to the TCP Analyzer (our parent), // (4) We hand the two reassemblers to the TCP Analyzer (our parent),
// turning reassembly now on for all subsequent data. // turning reassembly now on for all subsequent data.
DBG_LOG(DBG_DPD, "PIA_TCP switching from packet-mode to stream-mode"); DBG_LOG(DBG_ANALYZER, "PIA_TCP switching from packet-mode to stream-mode");
stream_mode = true; stream_mode = true;
// FIXME: The reassembler will query the endpoint for state. Not sure // FIXME: The reassembler will query the endpoint for state. Not sure
@ -378,7 +378,7 @@ void PIA_TCP::DeactivateAnalyzer(analyzer::Tag tag)
void PIA_TCP::ReplayStreamBuffer(analyzer::Analyzer* analyzer) void PIA_TCP::ReplayStreamBuffer(analyzer::Analyzer* analyzer)
{ {
DBG_LOG(DBG_DPD, "PIA_TCP replaying %d total stream bytes", stream_buffer.size); DBG_LOG(DBG_ANALYZER, "PIA_TCP replaying %d total stream bytes", stream_buffer.size);
for ( DataBlock* b = stream_buffer.head; b; b = b->next ) for ( DataBlock* b = stream_buffer.head; b; b = b->next )
{ {

View file

@ -54,15 +54,12 @@ RuleActionAnalyzer::RuleActionAnalyzer(const char* arg_analyzer)
reporter->Warning("unknown analyzer '%s' specified in rule", arg.c_str()); reporter->Warning("unknown analyzer '%s' specified in rule", arg.c_str());
} }
else else
child_analyzer = analyzer::Tag::ERROR; child_analyzer = analyzer::Tag();
if ( analyzer != analyzer::Tag::ERROR )
analyzer_mgr->ActivateSigs();
} }
void RuleActionAnalyzer::PrintDebug() void RuleActionAnalyzer::PrintDebug()
{ {
if ( child_analyzer == analyzer::Tag::ERROR ) if ( ! child_analyzer )
fprintf(stderr, "|%s|\n", analyzer_mgr->GetAnalyzerName(analyzer).c_str()); fprintf(stderr, "|%s|\n", analyzer_mgr->GetAnalyzerName(analyzer).c_str());
else else
fprintf(stderr, "|%s:%s|\n", fprintf(stderr, "|%s:%s|\n",
@ -74,7 +71,7 @@ void RuleActionAnalyzer::PrintDebug()
void RuleActionEnable::DoAction(const Rule* parent, RuleEndpointState* state, void RuleActionEnable::DoAction(const Rule* parent, RuleEndpointState* state,
const u_char* data, int len) const u_char* data, int len)
{ {
if ( ChildAnalyzer() == analyzer::Tag::ERROR ) if ( ! ChildAnalyzer() )
{ {
if ( ! analyzer_mgr->IsEnabled(Analyzer()) ) if ( ! analyzer_mgr->IsEnabled(Analyzer()) )
return; return;
@ -103,7 +100,7 @@ void RuleActionEnable::PrintDebug()
void RuleActionDisable::DoAction(const Rule* parent, RuleEndpointState* state, void RuleActionDisable::DoAction(const Rule* parent, RuleEndpointState* state,
const u_char* data, int len) const u_char* data, int len)
{ {
if ( ChildAnalyzer() == analyzer::Tag::ERROR ) if ( ! ChildAnalyzer() )
{ {
if ( state->PIA() ) if ( state->PIA() )
state->PIA()->DeactivateAnalyzer(Analyzer()); state->PIA()->DeactivateAnalyzer(Analyzer());

View file

@ -1178,7 +1178,7 @@ Connection* NetSessions::NewConn(HashKey* k, double t, const ConnID* id,
Connection* conn = new Connection(this, k, t, id, flow_label, encapsulation); Connection* conn = new Connection(this, k, t, id, flow_label, encapsulation);
conn->SetTransport(tproto); conn->SetTransport(tproto);
analyzer_mgr->BuildInitialAnalyzerTree(tproto, conn, data); analyzer_mgr->BuildInitialAnalyzerTree(conn);
bool external = conn->IsExternal(); bool external = conn->IsExternal();

View file

@ -1874,7 +1874,7 @@ void TCP_ApplicationAnalyzer::DeliverPacket(int len, const u_char* data,
const IP_Hdr* ip, int caplen) const IP_Hdr* ip, int caplen)
{ {
Analyzer::DeliverPacket(len, data, is_orig, seq, ip, caplen); Analyzer::DeliverPacket(len, data, is_orig, seq, ip, caplen);
DBG_LOG(DBG_DPD, "TCP_ApplicationAnalyzer ignoring DeliverPacket(%d, %s, %d, %p, %d) [%s%s]", DBG_LOG(DBG_ANALYZER, "TCP_ApplicationAnalyzer ignoring DeliverPacket(%d, %s, %d, %p, %d) [%s%s]",
len, is_orig ? "T" : "F", seq, ip, caplen, len, is_orig ? "T" : "F", seq, ip, caplen,
fmt_bytes((const char*) data, min(40, len)), len > 40 ? "..." : ""); fmt_bytes((const char*) data, min(40, len)), len > 40 ? "..." : "");
} }

View file

@ -26,10 +26,10 @@ function Analyzer::__register_for_port%(id: Analyzer::Tag, p: port%) : bool
return new Val(result, TYPE_BOOL); return new Val(result, TYPE_BOOL);
%} %}
function Analyzer::__expect_connection%(orig: addr, resp: addr, resp_p: port, function Analyzer::__schedule_analyzer%(orig: addr, resp: addr, resp_p: port,
analyzer: Analyzer::Tag, tout: interval%) : bool analyzer: Analyzer::Tag, tout: interval%) : bool
%{ %{
analyzer_mgr->ExpectConnection(orig->AsAddr(), resp->AsAddr(), resp_p, analyzer->AsEnumVal(), tout, 0); analyzer_mgr->ScheduleAnalyzer(orig->AsAddr(), resp->AsAddr(), resp_p, analyzer->AsEnumVal(), tout);
return new Val(true, TYPE_BOOL); return new Val(true, TYPE_BOOL);
%} %}

View file

@ -75,7 +75,7 @@ Analyzer::Analyzer(const char* name, Connection* arg_conn)
output_handler = 0; output_handler = 0;
if ( ! tag ) if ( ! tag )
reporter->InternalError("unknown analyzer name %s; mismatch with tag analyzer::PluginComponent?", name); reporter->InternalError("unknown analyzer name %s; mismatch with tag analyzer::Component?", name);
} }
@ -344,7 +344,7 @@ void Analyzer::AddChildAnalyzer(Analyzer* analyzer, bool init)
if ( init ) if ( init )
analyzer->Init(); analyzer->Init();
DBG_LOG(DBG_DPD, "%s added child %s", DBG_LOG(DBG_ANALYZER, "%s added child %s",
fmt_analyzer(this).c_str(), fmt_analyzer(analyzer).c_str()); fmt_analyzer(this).c_str(), fmt_analyzer(analyzer).c_str());
} }
@ -368,7 +368,7 @@ void Analyzer::RemoveChildAnalyzer(Analyzer* analyzer)
LOOP_OVER_CHILDREN(i) LOOP_OVER_CHILDREN(i)
if ( *i == analyzer && ! (analyzer->finished || analyzer->removing) ) if ( *i == analyzer && ! (analyzer->finished || analyzer->removing) )
{ {
DBG_LOG(DBG_DPD, "%s disabling child %s", DBG_LOG(DBG_ANALYZER, "%s disabling child %s",
fmt_analyzer(this).c_str(), fmt_analyzer(*i).c_str()); fmt_analyzer(this).c_str(), fmt_analyzer(*i).c_str());
// We just flag it as being removed here but postpone // We just flag it as being removed here but postpone
// actually doing that to later. Otherwise, we'd need // actually doing that to later. Otherwise, we'd need
@ -386,7 +386,7 @@ void Analyzer::RemoveChildAnalyzer(ID id)
LOOP_OVER_CHILDREN(i) LOOP_OVER_CHILDREN(i)
if ( (*i)->id == id && ! ((*i)->finished || (*i)->removing) ) if ( (*i)->id == id && ! ((*i)->finished || (*i)->removing) )
{ {
DBG_LOG(DBG_DPD, "%s disabling child %s", GetAnalyzerName().c_str(), id, DBG_LOG(DBG_ANALYZER, "%s disabling child %s", GetAnalyzerName().c_str(), id,
fmt_analyzer(this).c_str(), fmt_analyzer(*i).c_str()); fmt_analyzer(this).c_str(), fmt_analyzer(*i).c_str());
// See comment above. // See comment above.
(*i)->removing = true; (*i)->removing = true;
@ -440,7 +440,7 @@ Analyzer* Analyzer::FindChild(Tag arg_tag)
Analyzer* Analyzer::FindChild(const string& name) Analyzer* Analyzer::FindChild(const string& name)
{ {
Tag tag = analyzer_mgr->GetAnalyzerTag(name); Tag tag = analyzer_mgr->GetAnalyzerTag(name);
return tag != Tag::ERROR ? FindChild(tag) : 0; return tag ? FindChild(tag) : 0;
} }
void Analyzer::DeleteChild(analyzer_list::iterator i) void Analyzer::DeleteChild(analyzer_list::iterator i)
@ -456,7 +456,7 @@ void Analyzer::DeleteChild(analyzer_list::iterator i)
child->removing = false; child->removing = false;
} }
DBG_LOG(DBG_DPD, "%s deleted child %s 3", DBG_LOG(DBG_ANALYZER, "%s deleted child %s 3",
fmt_analyzer(this).c_str(), fmt_analyzer(child).c_str()); fmt_analyzer(this).c_str(), fmt_analyzer(child).c_str());
children.erase(i); children.erase(i);
@ -467,7 +467,7 @@ void Analyzer::AddSupportAnalyzer(SupportAnalyzer* analyzer)
{ {
if ( HasSupportAnalyzer(analyzer->GetAnalyzerTag(), analyzer->IsOrig()) ) if ( HasSupportAnalyzer(analyzer->GetAnalyzerTag(), analyzer->IsOrig()) )
{ {
DBG_LOG(DBG_DPD, "%s already has %s %s", DBG_LOG(DBG_ANALYZER, "%s already has %s %s",
fmt_analyzer(this).c_str(), fmt_analyzer(this).c_str(),
analyzer->IsOrig() ? "originator" : "responder", analyzer->IsOrig() ? "originator" : "responder",
fmt_analyzer(analyzer).c_str()); fmt_analyzer(analyzer).c_str());
@ -495,7 +495,7 @@ void Analyzer::AddSupportAnalyzer(SupportAnalyzer* analyzer)
analyzer->Init(); analyzer->Init();
DBG_LOG(DBG_DPD, "%s added %s support %s", DBG_LOG(DBG_ANALYZER, "%s added %s support %s",
fmt_analyzer(this).c_str(), fmt_analyzer(this).c_str(),
analyzer->IsOrig() ? "originator" : "responder", analyzer->IsOrig() ? "originator" : "responder",
fmt_analyzer(analyzer).c_str()); fmt_analyzer(analyzer).c_str());
@ -519,7 +519,7 @@ void Analyzer::RemoveSupportAnalyzer(SupportAnalyzer* analyzer)
else else
*head = s->sibling; *head = s->sibling;
DBG_LOG(DBG_DPD, "%s removed support %s", DBG_LOG(DBG_ANALYZER, "%s removed support %s",
fmt_analyzer(this).c_str(), fmt_analyzer(this).c_str(),
analyzer->IsOrig() ? "originator" : "responder", analyzer->IsOrig() ? "originator" : "responder",
fmt_analyzer(analyzer).c_str()); fmt_analyzer(analyzer).c_str());
@ -544,33 +544,33 @@ bool Analyzer::HasSupportAnalyzer(Tag tag, bool orig)
void Analyzer::DeliverPacket(int len, const u_char* data, bool is_orig, void Analyzer::DeliverPacket(int len, const u_char* data, bool is_orig,
int seq, const IP_Hdr* ip, int caplen) int seq, const IP_Hdr* ip, int caplen)
{ {
DBG_LOG(DBG_DPD, "%s DeliverPacket(%d, %s, %d, %p, %d) [%s%s]", DBG_LOG(DBG_ANALYZER, "%s DeliverPacket(%d, %s, %d, %p, %d) [%s%s]",
fmt_analyzer(this).c_str(), len, is_orig ? "T" : "F", seq, ip, caplen, fmt_analyzer(this).c_str(), len, is_orig ? "T" : "F", seq, ip, caplen,
fmt_bytes((const char*) data, min(40, len)), len > 40 ? "..." : ""); fmt_bytes((const char*) data, min(40, len)), len > 40 ? "..." : "");
} }
void Analyzer::DeliverStream(int len, const u_char* data, bool is_orig) void Analyzer::DeliverStream(int len, const u_char* data, bool is_orig)
{ {
DBG_LOG(DBG_DPD, "%s DeliverStream(%d, %s) [%s%s]", DBG_LOG(DBG_ANALYZER, "%s DeliverStream(%d, %s) [%s%s]",
fmt_analyzer(this).c_str(), len, is_orig ? "T" : "F", fmt_analyzer(this).c_str(), len, is_orig ? "T" : "F",
fmt_bytes((const char*) data, min(40, len)), len > 40 ? "..." : ""); fmt_bytes((const char*) data, min(40, len)), len > 40 ? "..." : "");
} }
void Analyzer::Undelivered(int seq, int len, bool is_orig) void Analyzer::Undelivered(int seq, int len, bool is_orig)
{ {
DBG_LOG(DBG_DPD, "%s Undelivered(%d, %d, %s)", DBG_LOG(DBG_ANALYZER, "%s Undelivered(%d, %d, %s)",
fmt_analyzer(this).c_str(), seq, len, is_orig ? "T" : "F"); fmt_analyzer(this).c_str(), seq, len, is_orig ? "T" : "F");
} }
void Analyzer::EndOfData(bool is_orig) void Analyzer::EndOfData(bool is_orig)
{ {
DBG_LOG(DBG_DPD, "%s EndOfData(%s)", DBG_LOG(DBG_ANALYZER, "%s EndOfData(%s)",
fmt_analyzer(this).c_str(), is_orig ? "T" : "F"); fmt_analyzer(this).c_str(), is_orig ? "T" : "F");
} }
void Analyzer::FlipRoles() void Analyzer::FlipRoles()
{ {
DBG_LOG(DBG_DPD, "%s FlipRoles()"); DBG_LOG(DBG_ANALYZER, "%s FlipRoles()");
LOOP_OVER_CHILDREN(i) LOOP_OVER_CHILDREN(i)
(*i)->FlipRoles(); (*i)->FlipRoles();
@ -596,7 +596,7 @@ void Analyzer::ProtocolConfirmation()
val_list* vl = new val_list; val_list* vl = new val_list;
vl->append(BuildConnVal()); vl->append(BuildConnVal());
vl->append(tag.Val()); vl->append(tag.AsEnumVal());
vl->append(new Val(id, TYPE_COUNT)); vl->append(new Val(id, TYPE_COUNT));
// We immediately raise the event so that the analyzer can quickly // We immediately raise the event so that the analyzer can quickly
@ -624,7 +624,7 @@ void Analyzer::ProtocolViolation(const char* reason, const char* data, int len)
val_list* vl = new val_list; val_list* vl = new val_list;
vl->append(BuildConnVal()); vl->append(BuildConnVal());
vl->append(tag.Val()); vl->append(tag.AsEnumVal());
vl->append(new Val(id, TYPE_COUNT)); vl->append(new Val(id, TYPE_COUNT));
vl->append(r); vl->append(r);

29
src/analyzer/Component.cc Normal file
View file

@ -0,0 +1,29 @@
#include "Component.h"
#include "../Desc.h"
using namespace analyzer;
Tag::type_t Component::type_counter = 0;
Component::Component(std::string arg_name, factory_callback arg_factory, Tag::subtype_t arg_subtype, bool arg_enabled, bool arg_partial)
: plugin::Component(plugin::component::ANALYZER)
{
name = arg_name;
factory = arg_factory;
enabled = arg_enabled;
partial = arg_partial;
tag = analyzer::Tag(++type_counter, arg_subtype);
}
void Component::Describe(ODesc* d)
{
plugin::Component::Describe(d);
d->Add(name);
d->Add(" (");
d->Add(enabled ? "enabled" : "disabled");
d->Add(")");
}

121
src/analyzer/Component.h Normal file
View file

@ -0,0 +1,121 @@
#ifndef ANALYZER_PLUGIN_COMPONENT_H
#define ANALYZER_PLUGIN_COMPONENT_H
#include <string>
#include "Tag.h"
#include "plugin/Component.h"
#include "../config.h"
#include "../util.h"
class Connection;
namespace analyzer {
class Analyzer;
/**
* Component description for plugins providing analyzers.
*
* A plugin can provide a specific protocol analyzer by registering this
* analyzer component, describing the analyzer.
*
* This class is safe to copy by value.
*/
class Component : public plugin::Component {
public:
typedef bool (*available_callback)();
typedef Analyzer* (*factory_callback)(Connection* conn);
/**
* Constructor.
*
* @param name The name of the provided analyzer. This name is used
* across the system to identify the analyzer, e.g., when calling
* analyzer::Manager::InstantiateAnalyzer with a name.
*
* @param factory A factory function to instantiate instances of the
* analyzer's class, which must be derived directly or indirectly
* from analyzer::Analyzer. This is typically a static \c
* Instatiate() method inside the class that just allocates and
* returns a new instance.
*
* @param subtype A subtype associated with this component that
* further. The subtype will be integrated into the analyzer::Tag
* that the manager associates with this analyzer, and analyzer
* instances can accordingly access it via analyzer::Tag(). If not
* used, leave at zero.
*
* @param enabled If false the analyzer starts out as disabled and
* hence won't be used. It can still be enabled later via the
* manager, including from script-land.
*
* @param partial If true, the analyzer can deal with payload from
* partial connections, i.e., when Bro enters the stream mid-way
* after not seeing the beginning. Note that handling of partial
* connections has generally not seen much testing yet as virtually
* no existing analyzer supports it.
*/
Component(std::string name, factory_callback factory, Tag::subtype_t subtype = 0, bool enabled = true, bool partial = false);
/**
* Returns the name of the analyzer. This name is unique across all
* analyzers and used to identify it.
*/
const std::string& Name() const { return name; }
/**
* Returns the analyzer's factory function.
*/
factory_callback Factory() const { return factory; }
/**
* Returns whether the analyzer supports partial connections. Partial
* connections are those where Bro starts processing payload
* mid-stream, after missing the beginning.
*/
bool Partial() const { return partial; }
/**
* Returns true if the analyzer is currently enabled and hence
* available for use.
*/
bool Enabled() const { return enabled; }
/**
* Returns the analyzer's tag. Note that this is automatically
* generated for each new Components, and hence unique across all of
* them.
*/
analyzer::Tag Tag() const { return tag; }
/**
* Enables or disables this analyzer.
*
* @param arg_enabled True to enabled, false to disable.
*
*/
void SetEnabled(bool arg_enabled) { enabled = arg_enabled; }
/**
* Generates a human-readable description of the component's main
* parameters. This goes into the output of \c "bro -NN".
*/
virtual void Describe(ODesc* d);
private:
std::string name; // The analyzer's name.
factory_callback factory; // The analyzer's factory callback.
bool partial; // True if the analyzer supports partial connections.
analyzer::Tag tag; // The automatically assigned analyzer tag.
bool enabled; // True if the analyzer is enabled.
// Global counter used to generate unique tags.
static analyzer::Tag::type_t type_counter;
};
}
#endif

View file

@ -16,8 +16,8 @@
using namespace analyzer; using namespace analyzer;
ExpectedConn::ExpectedConn(const IPAddr& _orig, const IPAddr& _resp, Manager::ConnIndex::ConnIndex(const IPAddr& _orig, const IPAddr& _resp,
uint16 _resp_p, uint16 _proto) uint16 _resp_p, uint16 _proto)
{ {
if ( _orig == IPAddr(string("0.0.0.0")) ) if ( _orig == IPAddr(string("0.0.0.0")) )
// don't use the IPv4 mapping, use the literal unspecified address // don't use the IPv4 mapping, use the literal unspecified address
@ -25,21 +25,37 @@ ExpectedConn::ExpectedConn(const IPAddr& _orig, const IPAddr& _resp,
orig = IPAddr(string("::")); orig = IPAddr(string("::"));
else else
orig = _orig; orig = _orig;
resp = _resp; resp = _resp;
resp_p = _resp_p; resp_p = _resp_p;
proto = _proto; proto = _proto;
} }
ExpectedConn::ExpectedConn(const ExpectedConn& c) Manager::ConnIndex::ConnIndex()
{ {
orig = c.orig; orig = resp = IPAddr("0.0.0.0");
resp = c.resp; resp_p = 0;
resp_p = c.resp_p; proto = 0;
proto = c.proto; }
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() Manager::Manager()
: expected_conns_queue(AssignedAnalyzer::compare)
{ {
tag_enum_type = new EnumType("Analyzer::Tag"); tag_enum_type = new EnumType("Analyzer::Tag");
::ID* id = install_ID("Tag", "Analyzer", true, true); ::ID* id = install_ID("Tag", "Analyzer", true, true);
@ -58,26 +74,19 @@ Manager::~Manager()
analyzers_by_port_tcp.clear(); analyzers_by_port_tcp.clear();
// Clean up expected-connection table. // Clean up expected-connection table.
while ( expected_conns_queue.size() ) while ( conns_by_timeout.size() )
{ {
AssignedAnalyzer* a = expected_conns_queue.top(); ScheduledAnalyzer* a = conns_by_timeout.top();
if ( ! a->deleted ) conns_by_timeout.pop();
{
HashKey* key = BuildExpectedConnHashKey(a->conn);
expected_conns.Remove(key);
delete key;
}
expected_conns_queue.pop();
delete a; delete a;
} }
} }
void Manager::Init() void Manager::Init()
{ {
std::list<PluginComponent*> analyzers = plugin_mgr->Components<PluginComponent>(plugin::component::ANALYZER); std::list<Component*> analyzers = plugin_mgr->Components<Component>(plugin::component::ANALYZER);
for ( std::list<PluginComponent*>::const_iterator i = analyzers.begin(); i != analyzers.end(); i++ ) for ( std::list<Component*>::const_iterator i = analyzers.begin(); i != analyzers.end(); i++ )
RegisterAnalyzerComponent(*i); RegisterAnalyzerComponent(*i);
// Caache these tags. // Caache these tags.
@ -91,12 +100,12 @@ void Manager::Init()
void Manager::DumpDebug() void Manager::DumpDebug()
{ {
#ifdef DEBUG #ifdef DEBUG
DBG_LOG(DBG_DPD, "Available analyzers after bro_init():"); DBG_LOG(DBG_ANALYZER, "Available analyzers after bro_init():");
for ( analyzer_map_by_name::const_iterator i = analyzers_by_name.begin(); i != analyzers_by_name.end(); i++ ) for ( analyzer_map_by_name::const_iterator i = analyzers_by_name.begin(); i != analyzers_by_name.end(); i++ )
DBG_LOG(DBG_DPD, " %s (%s)", i->second->Name().c_str(), IsEnabled(i->second->Tag()) ? "enabled" : "disabled"); DBG_LOG(DBG_ANALYZER, " %s (%s)", i->second->Name().c_str(), IsEnabled(i->second->Tag()) ? "enabled" : "disabled");
DBG_LOG(DBG_DPD, ""); DBG_LOG(DBG_ANALYZER, "");
DBG_LOG(DBG_DPD, "Analyzers by port:"); DBG_LOG(DBG_ANALYZER, "Analyzers by port:");
for ( analyzer_map_by_port::const_iterator i = analyzers_by_port_tcp.begin(); i != analyzers_by_port_tcp.end(); i++ ) for ( analyzer_map_by_port::const_iterator i = analyzers_by_port_tcp.begin(); i != analyzers_by_port_tcp.end(); i++ )
{ {
@ -105,7 +114,7 @@ void Manager::DumpDebug()
for ( tag_set::const_iterator j = i->second->begin(); j != i->second->end(); j++ ) for ( tag_set::const_iterator j = i->second->begin(); j != i->second->end(); j++ )
s += GetAnalyzerName(*j) + " "; s += GetAnalyzerName(*j) + " ";
DBG_LOG(DBG_DPD, " %d/tcp: %s", i->first, s.c_str()); DBG_LOG(DBG_ANALYZER, " %d/tcp: %s", i->first, s.c_str());
} }
for ( analyzer_map_by_port::const_iterator i = analyzers_by_port_udp.begin(); i != analyzers_by_port_udp.end(); i++ ) for ( analyzer_map_by_port::const_iterator i = analyzers_by_port_udp.begin(); i != analyzers_by_port_udp.end(); i++ )
@ -115,15 +124,15 @@ void Manager::DumpDebug()
for ( tag_set::const_iterator j = i->second->begin(); j != i->second->end(); j++ ) for ( tag_set::const_iterator j = i->second->begin(); j != i->second->end(); j++ )
s += GetAnalyzerName(*j) + " "; s += GetAnalyzerName(*j) + " ";
DBG_LOG(DBG_DPD, " %d/udp: %s", i->first, s.c_str()); DBG_LOG(DBG_ANALYZER, " %d/udp: %s", i->first, s.c_str());
} }
#if 0 #if 0
ODesc d; ODesc d;
tag_enum_type->Describe(&d); tag_enum_type->Describe(&d);
DBG_LOG(DBG_DPD, ""); DBG_LOG(DBG_ANALYZER, "");
DBG_LOG(DBG_DPD, "Analyzer::Tag type: %s", d.Description()); DBG_LOG(DBG_ANALYZER, "Analyzer::Tag type: %s", d.Description());
#endif #endif
#endif #endif
@ -133,35 +142,35 @@ void Manager::Done()
{ {
} }
void Manager::RegisterAnalyzerComponent(PluginComponent* component) void Manager::RegisterAnalyzerComponent(Component* component)
{ {
if ( Lookup(component->Name()) ) if ( Lookup(component->Name()) )
reporter->FatalError("Analyzer %s defined more than once", component->Name().c_str()); reporter->FatalError("Analyzer %s defined more than once", component->Name().c_str());
DBG_LOG(DBG_DPD, "Registering analyzer %s (tag %s)", DBG_LOG(DBG_ANALYZER, "Registering analyzer %s (tag %s)",
component->Name().c_str(), component->Tag().AsString().c_str()); component->Name().c_str(), component->Tag().AsString().c_str());
analyzers_by_name.insert(std::make_pair(component->Name(), component)); analyzers_by_name.insert(std::make_pair(component->Name(), component));
analyzers_by_tag.insert(std::make_pair(component->Tag(), component)); analyzers_by_tag.insert(std::make_pair(component->Tag(), component));
analyzers_by_val.insert(std::make_pair(component->Tag().Val()->InternalInt(), component)); analyzers_by_val.insert(std::make_pair(component->Tag().AsEnumVal()->InternalInt(), component));
// Install enum "Analyzer::ANALYZER_*" // Install enum "Analyzer::ANALYZER_*"
string name = to_upper(component->Name()); string name = to_upper(component->Name());
string id = fmt("ANALYZER_%s", name.c_str()); string id = fmt("ANALYZER_%s", name.c_str());
tag_enum_type->AddName("Analyzer", id.c_str(), component->Tag().Val()->InternalInt(), true); tag_enum_type->AddName("Analyzer", id.c_str(), component->Tag().AsEnumVal()->InternalInt(), true);
} }
bool Manager::EnableAnalyzer(Tag tag) bool Manager::EnableAnalyzer(Tag tag)
{ {
PluginComponent* p = Lookup(tag); Component* p = Lookup(tag);
if ( ! p ) if ( ! p )
{ {
DBG_LOG(DBG_DPD, "Asked to enable non-existing analyzer"); DBG_LOG(DBG_ANALYZER, "Asked to enable non-existing analyzer");
return false; return false;
} }
DBG_LOG(DBG_DPD, "Enabling analyzer %s", p->Name().c_str()); DBG_LOG(DBG_ANALYZER, "Enabling analyzer %s", p->Name().c_str());
p->SetEnabled(true); p->SetEnabled(true);
return true; return true;
@ -169,15 +178,15 @@ bool Manager::EnableAnalyzer(Tag tag)
bool Manager::EnableAnalyzer(EnumVal* val) bool Manager::EnableAnalyzer(EnumVal* val)
{ {
PluginComponent* p = Lookup(val); Component* p = Lookup(val);
if ( ! p ) if ( ! p )
{ {
DBG_LOG(DBG_DPD, "Asked to enable non-existing analyzer"); DBG_LOG(DBG_ANALYZER, "Asked to enable non-existing analyzer");
return false; return false;
} }
DBG_LOG(DBG_DPD, "Enabling analyzer %s", p->Name().c_str()); DBG_LOG(DBG_ANALYZER, "Enabling analyzer %s", p->Name().c_str());
p->SetEnabled(true); p->SetEnabled(true);
return true; return true;
@ -185,15 +194,15 @@ bool Manager::EnableAnalyzer(EnumVal* val)
bool Manager::DisableAnalyzer(Tag tag) bool Manager::DisableAnalyzer(Tag tag)
{ {
PluginComponent* p = Lookup(tag); Component* p = Lookup(tag);
if ( ! p ) if ( ! p )
{ {
DBG_LOG(DBG_DPD, "Asked to disable non-existing analyzer"); DBG_LOG(DBG_ANALYZER, "Asked to disable non-existing analyzer");
return false; return false;
} }
DBG_LOG(DBG_DPD, "Disabling analyzer %s", p->Name().c_str()); DBG_LOG(DBG_ANALYZER, "Disabling analyzer %s", p->Name().c_str());
p->SetEnabled(false); p->SetEnabled(false);
return true; return true;
@ -201,15 +210,15 @@ bool Manager::DisableAnalyzer(Tag tag)
bool Manager::DisableAnalyzer(EnumVal* val) bool Manager::DisableAnalyzer(EnumVal* val)
{ {
PluginComponent* p = Lookup(val); Component* p = Lookup(val);
if ( ! p ) if ( ! p )
{ {
DBG_LOG(DBG_DPD, "Asked to disable non-existing analyzer"); DBG_LOG(DBG_ANALYZER, "Asked to disable non-existing analyzer");
return false; return false;
} }
DBG_LOG(DBG_DPD, "Disabling analyzer %s", p->Name().c_str()); DBG_LOG(DBG_ANALYZER, "Disabling analyzer %s", p->Name().c_str());
p->SetEnabled(false); p->SetEnabled(false);
return true; return true;
@ -220,11 +229,11 @@ bool Manager::IsEnabled(Tag tag)
if ( ! tag ) if ( ! tag )
return false; return false;
PluginComponent* p = Lookup(tag); Component* p = Lookup(tag);
if ( ! p ) if ( ! p )
{ {
DBG_LOG(DBG_DPD, "Asked to check non-existing analyzer"); DBG_LOG(DBG_ANALYZER, "Asked to check non-existing analyzer");
return false; return false;
} }
@ -233,11 +242,11 @@ bool Manager::IsEnabled(Tag tag)
bool Manager::IsEnabled(EnumVal* val) bool Manager::IsEnabled(EnumVal* val)
{ {
PluginComponent* p = Lookup(val); Component* p = Lookup(val);
if ( ! p ) if ( ! p )
{ {
DBG_LOG(DBG_DPD, "Asked to check non-existing analyzer"); DBG_LOG(DBG_ANALYZER, "Asked to check non-existing analyzer");
return false; return false;
} }
@ -247,11 +256,11 @@ bool Manager::IsEnabled(EnumVal* val)
bool Manager::RegisterAnalyzerForPort(EnumVal* val, PortVal* port) bool Manager::RegisterAnalyzerForPort(EnumVal* val, PortVal* port)
{ {
PluginComponent* p = Lookup(val); Component* p = Lookup(val);
if ( ! p ) if ( ! p )
{ {
DBG_LOG(DBG_DPD, "Asked to register port for non-existing analyzer"); DBG_LOG(DBG_ANALYZER, "Asked to register port for non-existing analyzer");
return false; return false;
} }
@ -260,11 +269,11 @@ bool Manager::RegisterAnalyzerForPort(EnumVal* val, PortVal* port)
bool Manager::UnregisterAnalyzerForPort(EnumVal* val, PortVal* port) bool Manager::UnregisterAnalyzerForPort(EnumVal* val, PortVal* port)
{ {
PluginComponent* p = Lookup(val); Component* p = Lookup(val);
if ( ! p ) if ( ! p )
{ {
DBG_LOG(DBG_DPD, "Asked to unregister port fork non-existing analyzer"); DBG_LOG(DBG_ANALYZER, "Asked to unregister port fork non-existing analyzer");
return false; return false;
} }
@ -277,7 +286,7 @@ bool Manager::RegisterAnalyzerForPort(Tag tag, TransportProto proto, uint32 port
#ifdef DEBUG #ifdef DEBUG
std::string name = GetAnalyzerName(tag); std::string name = GetAnalyzerName(tag);
DBG_LOG(DBG_DPD, "Registering analyzer %s for port %" PRIu32 "/%d", name.c_str(), port, proto); DBG_LOG(DBG_ANALYZER, "Registering analyzer %s for port %" PRIu32 "/%d", name.c_str(), port, proto);
#endif #endif
l->insert(tag); l->insert(tag);
@ -290,7 +299,7 @@ bool Manager::UnregisterAnalyzerForPort(Tag tag, TransportProto proto, uint32 po
#ifdef DEBUG #ifdef DEBUG
std::string name = GetAnalyzerName(tag); std::string name = GetAnalyzerName(tag);
DBG_LOG(DBG_DPD, "Unregistering analyzer %s for port %" PRIu32 "/%d", name.c_str(), port, proto); DBG_LOG(DBG_ANALYZER, "Unregistering analyzer %s for port %" PRIu32 "/%d", name.c_str(), port, proto);
#endif #endif
l->erase(tag); l->erase(tag);
@ -299,7 +308,7 @@ bool Manager::UnregisterAnalyzerForPort(Tag tag, TransportProto proto, uint32 po
Analyzer* Manager::InstantiateAnalyzer(Tag tag, Connection* conn) Analyzer* Manager::InstantiateAnalyzer(Tag tag, Connection* conn)
{ {
PluginComponent* c = Lookup(tag); Component* c = Lookup(tag);
if ( ! c ) if ( ! c )
reporter->InternalError("request to instantiate unknown analyzer"); reporter->InternalError("request to instantiate unknown analyzer");
@ -329,7 +338,7 @@ const string& Manager::GetAnalyzerName(Tag tag)
if ( ! tag ) if ( ! tag )
return error; return error;
PluginComponent* c = Lookup(tag); Component* c = Lookup(tag);
if ( ! c ) if ( ! c )
reporter->InternalError("request for name of unknown analyzer tag %s", tag.AsString().c_str()); reporter->InternalError("request for name of unknown analyzer tag %s", tag.AsString().c_str());
@ -344,14 +353,14 @@ const string& Manager::GetAnalyzerName(Val* val)
Tag Manager::GetAnalyzerTag(const string& name) Tag Manager::GetAnalyzerTag(const string& name)
{ {
PluginComponent* c = Lookup(name); Component* c = Lookup(name);
return c ? c->Tag() : Tag::ERROR; return c ? c->Tag() : Tag();
} }
Tag Manager::GetAnalyzerTag(const char* name) Tag Manager::GetAnalyzerTag(const char* name)
{ {
PluginComponent* c = Lookup(name); Component* c = Lookup(name);
return c ? c->Tag() : Tag::ERROR; return c ? c->Tag() : Tag();
} }
EnumType* Manager::GetTagEnumType() EnumType* Manager::GetTagEnumType()
@ -359,26 +368,25 @@ EnumType* Manager::GetTagEnumType()
return tag_enum_type; return tag_enum_type;
} }
Component* Manager::Lookup(const string& name)
PluginComponent* Manager::Lookup(const string& name)
{ {
analyzer_map_by_name::const_iterator i = analyzers_by_name.find(to_upper(name)); analyzer_map_by_name::const_iterator i = analyzers_by_name.find(to_upper(name));
return i != analyzers_by_name.end() ? i->second : 0; return i != analyzers_by_name.end() ? i->second : 0;
} }
PluginComponent* Manager::Lookup(const char* name) Component* Manager::Lookup(const char* name)
{ {
analyzer_map_by_name::const_iterator i = analyzers_by_name.find(to_upper(name)); analyzer_map_by_name::const_iterator i = analyzers_by_name.find(to_upper(name));
return i != analyzers_by_name.end() ? i->second : 0; return i != analyzers_by_name.end() ? i->second : 0;
} }
PluginComponent* Manager::Lookup(const Tag& tag) Component* Manager::Lookup(const Tag& tag)
{ {
analyzer_map_by_tag::const_iterator i = analyzers_by_tag.find(tag); analyzer_map_by_tag::const_iterator i = analyzers_by_tag.find(tag);
return i != analyzers_by_tag.end() ? i->second : 0; return i != analyzers_by_tag.end() ? i->second : 0;
} }
PluginComponent* Manager::Lookup(EnumVal* val) Component* Manager::Lookup(EnumVal* val)
{ {
analyzer_map_by_val::const_iterator i = analyzers_by_val.find(val->InternalInt()); analyzer_map_by_val::const_iterator i = analyzers_by_val.find(val->InternalInt());
return i != analyzers_by_val.end() ? i->second : 0; return i != analyzers_by_val.end() ? i->second : 0;
@ -419,69 +427,39 @@ Manager::tag_set* Manager::LookupPort(PortVal* val, bool add_if_not_found)
return LookupPort(val->PortType(), val->Port(), add_if_not_found); return LookupPort(val->PortType(), val->Port(), add_if_not_found);
} }
Tag Manager::GetExpected(int proto, const Connection* conn) bool Manager::BuildInitialAnalyzerTree(Connection* conn)
{
if ( ! expected_conns.Length() )
return Tag::ERROR;
ExpectedConn c(conn->OrigAddr(), conn->RespAddr(),
ntohs(conn->RespPort()), proto);
HashKey* key = BuildExpectedConnHashKey(c);
AssignedAnalyzer* a = expected_conns.Lookup(key);
delete key;
if ( ! a )
{
// Wildcard for originator.
c.orig = IPAddr(string("::"));
HashKey* key = BuildExpectedConnHashKey(c);
a = expected_conns.Lookup(key);
delete key;
}
if ( ! a )
return Tag::ERROR;
// We don't delete it here. It will be expired eventually.
return a->analyzer;
}
bool Manager::BuildInitialAnalyzerTree(TransportProto proto, Connection* conn,
const u_char* data)
{ {
Analyzer* analyzer = 0; Analyzer* analyzer = 0;
TCP_Analyzer* tcp = 0; TCP_Analyzer* tcp = 0;
UDP_Analyzer* udp = 0; UDP_Analyzer* udp = 0;
ICMP_Analyzer* icmp = 0; ICMP_Analyzer* icmp = 0;
TransportLayerAnalyzer* root = 0; TransportLayerAnalyzer* root = 0;
Tag expected = Tag::ERROR; tag_set expected;
PIA* pia = 0; PIA* pia = 0;
bool analyzed = false; bool analyzed = false;
bool check_port = false; bool check_port = false;
switch ( proto ) { switch ( conn->ConnTransport() ) {
case TRANSPORT_TCP: case TRANSPORT_TCP:
root = tcp = new TCP_Analyzer(conn); root = tcp = new TCP_Analyzer(conn);
pia = new PIA_TCP(conn); pia = new PIA_TCP(conn);
expected = GetExpected(proto, conn); expected = GetScheduled(conn);
check_port = true; check_port = true;
DBG_DPD(conn, "activated TCP analyzer"); DBG_ANALYZER(conn, "activated TCP analyzer");
break; break;
case TRANSPORT_UDP: case TRANSPORT_UDP:
root = udp = new UDP_Analyzer(conn); root = udp = new UDP_Analyzer(conn);
pia = new PIA_UDP(conn); pia = new PIA_UDP(conn);
expected = GetExpected(proto, conn); expected = GetScheduled(conn);
check_port = true; check_port = true;
DBG_DPD(conn, "activated UDP analyzer"); DBG_ANALYZER(conn, "activated UDP analyzer");
break; break;
case TRANSPORT_ICMP: { case TRANSPORT_ICMP: {
root = icmp = new ICMP_Analyzer(conn); root = icmp = new ICMP_Analyzer(conn);
DBG_DPD(conn, "activated ICMP analyzer"); DBG_ANALYZER(conn, "activated ICMP analyzer");
analyzed = true; analyzed = true;
break; break;
} }
@ -492,34 +470,34 @@ bool Manager::BuildInitialAnalyzerTree(TransportProto proto, Connection* conn,
if ( ! root ) if ( ! root )
{ {
DBG_DPD(conn, "cannot build analyzer tree"); DBG_ANALYZER(conn, "cannot build analyzer tree");
return false; return false;
} }
// Any scheduled analyzer? // Any scheduled analyzer?
if ( expected ) for ( tag_set::iterator i = expected.begin(); i != expected.end(); i++ )
{ {
Analyzer* analyzer = analyzer_mgr->InstantiateAnalyzer(expected, conn); Analyzer* analyzer = analyzer_mgr->InstantiateAnalyzer(*i, conn);
if ( analyzer ) if ( analyzer )
{ {
root->AddChildAnalyzer(analyzer, false); root->AddChildAnalyzer(analyzer, false);
DBG_DPD_ARGS(conn, "activated %s analyzer as scheduled", DBG_ANALYZER_ARGS(conn, "activated %s analyzer as scheduled",
analyzer_mgr->GetAnalyzerName(expected).c_str()); analyzer_mgr->GetAnalyzerName(*i).c_str());
} }
// Hmm... Do we want *just* the expected analyzer, or all
// other potential analyzers as well? For now we only take
// the scheduled one.
} }
else // Hmm... Do we want *just* the expected analyzer, or all
// other potential analyzers as well? For now we only take
// the scheduled ones.
if ( expected.size() == 0 )
{ // Let's see if it's a port we know. { // Let's see if it's a port we know.
if ( check_port && ! dpd_ignore_ports ) if ( check_port && ! dpd_ignore_ports )
{ {
int resp_port = ntohs(conn->RespPort()); int resp_port = ntohs(conn->RespPort());
tag_set* ports = LookupPort(proto, resp_port, false); tag_set* ports = LookupPort(conn->ConnTransport(), resp_port, false);
if ( ports ) if ( ports )
{ {
@ -531,7 +509,7 @@ bool Manager::BuildInitialAnalyzerTree(TransportProto proto, Connection* conn,
continue; continue;
root->AddChildAnalyzer(analyzer, false); root->AddChildAnalyzer(analyzer, false);
DBG_DPD_ARGS(conn, "activated %s analyzer due to port %d", DBG_ANALYZER_ARGS(conn, "activated %s analyzer due to port %d",
analyzer_mgr->GetAnalyzerName(*j).c_str(), resp_port); analyzer_mgr->GetAnalyzerName(*j).c_str(), resp_port);
} }
} }
@ -622,78 +600,116 @@ bool Manager::BuildInitialAnalyzerTree(TransportProto proto, Connection* conn,
if ( ! analyzed ) if ( ! analyzed )
conn->SetLifetime(non_analyzed_lifetime); conn->SetLifetime(non_analyzed_lifetime);
if ( expected != Tag::ERROR ) for ( tag_set::iterator i = expected.begin(); i != expected.end(); i++ )
conn->Event(expected_connection_seen, 0, conn->Event(scheduled_analyzer_applied, 0, i->AsEnumVal());
new Val(expected, TYPE_COUNT));
return true; return true;
} }
void Manager::ExpectConnection(const IPAddr& orig, const IPAddr& resp, void Manager::ExpireScheduledAnalyzers()
uint16 resp_p,
TransportProto proto, Tag analyzer,
double timeout, void* cookie)
{ {
// Use the chance to see if the oldest entry is already expired. if ( ! network_time )
if ( expected_conns_queue.size() ) return;
while ( conns_by_timeout.size() )
{ {
AssignedAnalyzer* a = expected_conns_queue.top(); ScheduledAnalyzer* a = conns_by_timeout.top();
if ( a->timeout < network_time )
if ( a->timeout > 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 ( ! a->deleted ) if ( i->second != a )
{ continue;
HashKey* key = BuildExpectedConnHashKey(a->conn);
expected_conns.Remove(key);
delete key;
}
expected_conns_queue.pop(); conns.erase(i);
DBG_LOG(DBG_DPD, "Expired expected %s analyzer for %s", DBG_LOG(DBG_ANALYZER, "Expiring expected analyzer %s for connection %s",
analyzer_mgr->GetAnalyzerName(analyzer).c_str(), analyzer_mgr->GetAnalyzerName(a->analyzer).c_str(),
fmt_conn_id(a->conn.orig, 0, fmt_conn_id(a->conn.orig, 0, a->conn.resp, a->conn.resp_p));
a->conn.resp,
a->conn.resp_p));
delete a; delete a;
found = true;
break;
} }
assert(found);
} }
ExpectedConn c(orig, resp, resp_p, proto);
HashKey* key = BuildExpectedConnHashKey(c);
AssignedAnalyzer* a = expected_conns.Lookup(key);
if ( a )
a->deleted = true;
a = new AssignedAnalyzer(c);
a->analyzer = analyzer;
a->cookie = cookie;
a->timeout = network_time + timeout;
a->deleted = false;
expected_conns.Insert(key, a);
expected_conns_queue.push(a);
delete key;
} }
void Manager::ExpectConnection(const IPAddr& orig, const IPAddr& resp, void Manager::ScheduleAnalyzer(const IPAddr& orig, const IPAddr& resp,
uint16 resp_p,
TransportProto proto, Tag analyzer,
double timeout)
{
if ( ! 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 = 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 resp_p, uint16 resp_p,
TransportProto proto, const string& analyzer, TransportProto proto, const string& analyzer,
double timeout, void* cookie) double timeout)
{ {
Tag tag = GetAnalyzerTag(analyzer); Tag tag = GetAnalyzerTag(analyzer);
if ( tag != Tag::ERROR ) if ( tag != Tag() )
ExpectConnection(orig, resp, resp_p, proto, tag, timeout, cookie); ScheduleAnalyzer(orig, resp, resp_p, proto, tag, timeout);
} }
void Manager::ExpectConnection(const IPAddr& orig, const IPAddr& resp, PortVal* resp_p, void Manager::ScheduleAnalyzer(const IPAddr& orig, const IPAddr& resp, PortVal* resp_p,
Val* analyzer, double timeout, void* cookie) Val* analyzer, double timeout)
{ {
EnumVal* ev = analyzer->AsEnumVal(); EnumVal* ev = analyzer->AsEnumVal();
return ExpectConnection(orig, resp, resp_p->Port(), resp_p->PortType(), Tag(ev), timeout, cookie); return ScheduleAnalyzer(orig, resp, resp_p->Port(), resp_p->PortType(), Tag(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(string("::"));
all = conns.equal_range(c);
for ( conns_map::iterator i = all.first; i != all.second; i++ )
{
if ( i->second->timeout > network_time )
result.insert(i->second->analyzer);
}
// We don't delete scheduled analyzers here. They will be expired
// eventually.
return result;
} }

View file

@ -1,12 +1,28 @@
// The central management unit for dynamic analyzer selection. /**
* The central management unit for registering and instantiating analyzers.
*
* For each protocol that Bro supports, there's one class derived from
* analyzer::Analyzer. Once we have decided that a connection's payload is to
* be parsed as a given protocol, we instantiate the corresponding
* analyzer-derived class and add the new instance as a child node into the
* connection's analyzer tree.
*
* In addition to the analyzer-derived class itself, for each protocol
* there's also "meta-class" derived from analyzer::Component that describes
* the analyzer, including status information on if that particular protocol
* analysis is currently enabled.
*
* To identify an analyzer (or to be precise: a component), the manager
* maintains mappings of (1) analyzer::Tag to component, and (2)
* human-readable analyzer name to component.
*/
#ifndef ANALYZER_MANAGER_H #ifndef ANALYZER_MANAGER_H
#define ANALYZER_MANAGER_H #define ANALYZER_MANAGER_H
#include <queue> #include <queue>
#include "Analyzer.h" #include "Analyzer.h"
#include "PluginComponent.h" #include "Component.h"
#include "Tag.h" #include "Tag.h"
#include "../Dict.h" #include "../Dict.h"
@ -15,139 +31,333 @@
namespace analyzer { namespace analyzer {
// Manager debug logging, which includes the connection id into the message. /**
#ifdef DEBUG * Class maintaining and scheduling available protocol analyzers.
# define DBG_DPD(conn, txt) \ *
DBG_LOG(DBG_DPD, "%s " txt, \ * The manager maintains a registry of all available protocol analyzers,
fmt_conn_id(conn->OrigAddr(), ntohs(conn->OrigPort()), \ * including a mapping between their textual names and analyzer::Tag. It
conn->RespAddr(), ntohs(conn->RespPort()))); * instantantiates new analyzers on demand. For new connections, the manager
# define DBG_DPD_ARGS(conn, fmt, args...) \ * sets up their initial analyzer tree, including adding the right \c PIA,
DBG_LOG(DBG_DPD, "%s " fmt, \ * respecting well-known ports, and tracking any analyzers specifically
fmt_conn_id(conn->OrigAddr(), ntohs(conn->OrigPort()), \ * scheduled for individidual connections.
conn->RespAddr(), ntohs(conn->RespPort())), ##args); */
#else
# define DBG_DPD(conn, txt)
# define DBG_DPD_ARGS(conn, fmt, args...)
#endif
// Map index to assign expected connections to analyzers.
class ExpectedConn {
public:
ExpectedConn(const IPAddr& _orig, const IPAddr& _resp,
uint16 _resp_p, uint16 _proto);
ExpectedConn(const ExpectedConn& c);
IPAddr orig;
IPAddr resp;
uint16 resp_p;
uint16 proto;
};
// Associates an analyzer for an expected future connection.
class AssignedAnalyzer {
public:
AssignedAnalyzer(const ExpectedConn& c)
: conn(c) { }
ExpectedConn conn;
Tag analyzer;
double timeout;
void* cookie;
bool deleted;
static bool compare(const AssignedAnalyzer* a1, const AssignedAnalyzer* a2)
{ return a1->timeout > a2->timeout; }
};
declare(PDict, AssignedAnalyzer);
class Manager { class Manager {
public: public:
/**
* Constructor.
*/
Manager(); Manager();
/**
* Destructor.
*/
~Manager(); ~Manager();
void Init(); // Called before script's are parsed. /**
* Initializes the manager's operation. Must be called before scripts
* are parsed.
*/
void Init();
/**
* Finished the manager's operations.
*/
void Done(); void Done();
/**
* Dumps out the state of all registered analyzers to the \c analyzer
* debug stream. Should be called only after any \c bro_init events
* have executed to ensure that any of their changes are applied.
*/
void DumpDebug(); // Called after bro_init() events. void DumpDebug(); // Called after bro_init() events.
/**
* Enables an analyzer type. Only enabled analyzers will be
* instantiated for new connections.
*
* @param tag The analyzer's tag.
*
* @return True if sucessful.
*/
bool EnableAnalyzer(Tag tag); bool EnableAnalyzer(Tag tag);
/**
* Enables an analyzer type. Only enabled analyzers will be
* instantiated for new connections.
*
* @param tag The analyzer's tag as an enum of script type \c
* Analyzer::Tag.
*
* @return True if sucessful.
*/
bool EnableAnalyzer(EnumVal* tag); bool EnableAnalyzer(EnumVal* tag);
/**
* Enables an analyzer type. Disabled analyzers will not be
* instantiated for new connections.
*
* @param tag The analyzer's tag.
*
* @return True if sucessful.
*/
bool DisableAnalyzer(Tag tag); bool DisableAnalyzer(Tag tag);
/**
* Enables an analyzer type. Disabled analyzers will not be
* instantiated for new connections.
*
* @param tag The analyzer's tag as an enum of script type \c
* Analyzer::Tag.
*
* @return True if sucessful.
*/
bool DisableAnalyzer(EnumVal* tag); bool DisableAnalyzer(EnumVal* tag);
/**
* Returns true if an analyzer is enabled.
*
* @param tag The analyzer's tag.
*/
bool IsEnabled(Tag tag); bool IsEnabled(Tag tag);
/**
* Returns true if an analyzer is enabled.
*
* @param tag The analyzer's tag as an enum of script type \c
* Analyzer::Tag.
*/
bool IsEnabled(EnumVal* tag); bool IsEnabled(EnumVal* tag);
/**
* Registers a well-known port for an analyzer. Once registered,
* connection on that port will start with a corresponding analyzer
* assigned.
*
* @param tag The analyzer's tag as an enum of script type \c
* Analyzer::Tag.
*
* @param port The well-known port.
*
* @return True if sucessful.
*/
bool RegisterAnalyzerForPort(EnumVal* tag, PortVal* port); bool RegisterAnalyzerForPort(EnumVal* tag, PortVal* port);
/**
* Registers a well-known port for an analyzer. Once registered,
* connection on that port will start with a corresponding analyzer
* assigned.
*
* @param tag The analyzer's tag.
*
* @param proto The port's protocol.
*
* @param port The port's number.
*
* @return True if sucessful.
*/
bool RegisterAnalyzerForPort(Tag tag, TransportProto proto, uint32 port); bool RegisterAnalyzerForPort(Tag tag, TransportProto proto, uint32 port);
/**
* Unregisters a well-known port for an anlyzers.
*
* @param tag The analyzer's tag as an enum of script type \c
* Analyzer::Tag.
*
* @param port The well-known port.
*
* @return True if sucessful (incl. when the port wasn't actually
* registered for the analyzer).
*
*/
bool UnregisterAnalyzerForPort(EnumVal* tag, PortVal* port); bool UnregisterAnalyzerForPort(EnumVal* tag, PortVal* port);
/**
* Unregisters a well-known port for an anlyzers.
*
* @param tag The analyzer's tag.
*
* @param proto The port's protocol.
*
* @param port The port's number.
*
* @param tag The analyzer's tag as an enum of script type \c
* Analyzer::Tag.
*/
bool UnregisterAnalyzerForPort(Tag tag, TransportProto proto, uint32 port); bool UnregisterAnalyzerForPort(Tag tag, TransportProto proto, uint32 port);
/**
* Instantiates a new analyzer instance for a connection.
*
* @param tag The analyzer's tag.
*
* @param conn The connection the analyzer is to be associated with.
*
* @return The new analyzer instance. Note that the analyzer will not
* have been added to the connection's analyzer tree yet. Returns
* null if tag is invalid or the requested analyzer is disabled.
*/
Analyzer* InstantiateAnalyzer(Tag tag, Connection* c); // Null if disabled or not available. Analyzer* InstantiateAnalyzer(Tag tag, Connection* c); // Null if disabled or not available.
/**
* Instantiates a new analyzer instance for a connection.
*
* @param name The name of the analyzer.
*
* @param conn The connection the analyzer is to be associated with.
*
* @return The new analyzer instance. Note that the analyzer will not
* have been added to the connection's analyzer tree yet. Returns
* null if the name is not known or if the requested analyzer that is
* disabled.
*/
Analyzer* InstantiateAnalyzer(const char* name, Connection* c); // Null if disabled or not available. Analyzer* InstantiateAnalyzer(const char* name, Connection* c); // Null if disabled or not available.
/**
* Translates an analyzer tag into corresponding analyzer name.
*
* @param tag The analyzer tag.
*
* @return The name, or an empty string if the tag is invalid.
*/
const string& GetAnalyzerName(Tag tag); const string& GetAnalyzerName(Tag tag);
const string& GetAnalyzerName(Val* val);
Tag GetAnalyzerTag(const string& name); // Tag::ERROR when not known.
Tag GetAnalyzerTag(const char* name); // Tag::ERROR when not known.
/**
* Translates an script-level analyzer tag into corresponding
* analyzer name.
*
* @param val The analyzer tag as an script-level enum value of type
* \c Analyzer::Tag.
*
* @return The name, or an empty string if the tag is invalid.
*/
const string& GetAnalyzerName(Val* val);
/**
* Translates an analyzer name into the corresponding tag.
*
* @param name The name.
*
* @return The tag. If the name does not correspond to a valid
* analyzer, the returned tag will evaluate to false.
*/
Tag GetAnalyzerTag(const string& name);
/**
* Translates an analyzer name into the corresponding tag.
*
* @param name The name.
*
* @return The tag. If the name does not correspond to a valid
* analyzer, the returned tag will evaluate to false.
*/
Tag GetAnalyzerTag(const char* name);
/**
* Returns the enum type that corresponds to the script-level type \c
* Analyzer::Tag.
*/
EnumType* GetTagEnumType(); EnumType* GetTagEnumType();
// Given info about the first packet, build initial analyzer tree. /**
// * Given the first packet of a connection, builds its initial
// It would be more flexible if we simply pass in the IP header and * analyzer tree.
// then extract the information we need. However, when this method *
// is called from the session management, protocol and ports have * @param conn The connection to add the initial set of analyzers to.
// already been extracted there and it would be a waste to do it *
// again. * @return False if the tree cannot be build; that's usually an
// * internally error.
// Returns 0 if we can't build a tree (e.g., because the necessary */
// analyzers have not been converted to the Manager framework yet...) bool BuildInitialAnalyzerTree(Connection* conn);
bool BuildInitialAnalyzerTree(TransportProto proto, Connection* conn,
const u_char* data);
// Schedules a particular analyzer for an upcoming connection. 0 acts /**
// as a wildcard for orig. (Cookie is currently unused. Eventually, * Schedules a particular analyzer for an upcoming connection. Once
// we may pass it on to the analyzer). * the connection is seen, BuildInitAnalyzerTree() will add the
void ExpectConnection(const IPAddr& orig, const IPAddr& resp, uint16 resp_p, * specified analyzer to its tree.
TransportProto proto, Tag analyzer, *
double timeout, void* cookie); * @param orig The connection's anticipated originator address.
* 0.0.0.0 can be used as a wildcard matching any originator.
*
* @param resp The connection's anticipated responder address (no
* wilcard).
*
* @param resp_p The connection's anticipated responder port.
*
* @param proto The connection's anticipated transport protocol.
*
* @param analyzer The analyzer to use once the connection is seen.
*
* @param timeout An interval after which to timeout the request to
* schedule this analyzer. Must be non-zero.
*/
void ScheduleAnalyzer(const IPAddr& orig, const IPAddr& resp, uint16 resp_p,
TransportProto proto, Tag analyzer, double timeout);
void ExpectConnection(const IPAddr& orig, const IPAddr& resp, uint16 resp_p, /**
* Schedules a particular analyzer for an upcoming connection. Once
* the connection is seen, BuildInitAnalyzerTree() will add the
* specified analyzer to its tree.
*
* @param orig The connection's anticipated originator address. 0 can
* be used as a wildcard matching any originator.
*
* @param resp The The connection's anticipated responder address (no
* wilcard).
*
* @param resp_p The connection's anticipated responder port.
*
* @param proto The connection's anticipated transport protocol.
*
* @param analyzer The name of the analyzer to use once the
* connection is seen.
*
* @param timeout An interval after which to timeout the request to
* schedule this analyzer. Must be non-zero.
*/
void ScheduleAnalyzer(const IPAddr& orig, const IPAddr& resp, uint16 resp_p,
TransportProto proto, const string& analyzer, TransportProto proto, const string& analyzer,
double timeout, void* cookie); double timeout);
void ExpectConnection(const IPAddr& orig, const IPAddr& resp, PortVal* resp_p, /**
Val* val, double timeout, void* cookie); * Schedules a particular analyzer for an upcoming connection. Once
* the connection is seen, BuildInitAnalyzerTree() will add the
// Activates signature matching for protocol detection. (Called when * specified analyzer to its tree.
// an Manager signatures is found.) *
void ActivateSigs() { sigs_activated = true; } * @param orig The connection's anticipated originator address. 0 can
bool SigsActivated() const { return sigs_activated; } * be used as a wildcard matching any originator.
*
* @param resp The connection's anticipated responder address (no
* wilcard).
*
* @param resp_p The connection's anticipated responder port.
*
* @param analyzer The analyzer to use once the connection is seen as
* an enum value of script-type \c Analyzer::Tag.
*
* @param timeout An interval after which to timeout the request to
* schedule this analyzer. Must be non-zero.
*/
void ScheduleAnalyzer(const IPAddr& orig, const IPAddr& resp, PortVal* resp_p,
Val* analyzer, double timeout);
private: private:
typedef set<Tag> tag_set; typedef set<Tag> tag_set;
typedef map<string, PluginComponent*> analyzer_map_by_name; typedef map<string, Component*> analyzer_map_by_name;
typedef map<Tag, PluginComponent*> analyzer_map_by_tag; typedef map<Tag, Component*> analyzer_map_by_tag;
typedef map<int, PluginComponent*> analyzer_map_by_val; typedef map<int, Component*> analyzer_map_by_val;
typedef map<uint32, tag_set*> analyzer_map_by_port; typedef map<uint32, tag_set*> analyzer_map_by_port;
void RegisterAnalyzerComponent(PluginComponent* component); // Takes ownership. void RegisterAnalyzerComponent(Component* component); // Takes ownership.
PluginComponent* Lookup(const string& name); Component* Lookup(const string& name);
PluginComponent* Lookup(const char* name); Component* Lookup(const char* name);
PluginComponent* Lookup(const Tag& tag); Component* Lookup(const Tag& tag);
PluginComponent* Lookup(EnumVal* val); Component* Lookup(EnumVal* val);
tag_set* LookupPort(PortVal* val, bool add_if_not_found); tag_set* LookupPort(PortVal* val, bool add_if_not_found);
tag_set* LookupPort(TransportProto proto, uint32 port, bool add_if_not_found); tag_set* LookupPort(TransportProto proto, uint32 port, bool add_if_not_found);
// Return analyzer if any has been scheduled with ExpectConnection() tag_set GetScheduled(const Connection* conn);
// Tag::::Error if none. void ExpireScheduledAnalyzers();
Tag GetExpected(int proto, const Connection* conn);
analyzer_map_by_port analyzers_by_port_tcp; analyzer_map_by_port analyzers_by_port_tcp;
analyzer_map_by_port analyzers_by_port_udp; analyzer_map_by_port analyzers_by_port_udp;
@ -163,21 +373,62 @@ private:
EnumType* tag_enum_type; EnumType* tag_enum_type;
// True if signature-matching has been activated. //// Data structures to track analyzed scheduled for future connections.
bool sigs_activated;
PDict(AssignedAnalyzer) expected_conns; // The index for a scheduled connection.
struct ConnIndex {
IPAddr orig;
IPAddr resp;
uint16 resp_p;
uint16 proto;
typedef priority_queue< ConnIndex(const IPAddr& _orig, const IPAddr& _resp,
AssignedAnalyzer*, uint16 _resp_p, uint16 _proto);
vector<AssignedAnalyzer*>, ConnIndex();
bool (*)(const AssignedAnalyzer*,
const AssignedAnalyzer*)> conn_queue; bool operator<(const ConnIndex& other) const;
conn_queue expected_conns_queue; };
// Information associated with a scheduled connection.
struct ScheduledAnalyzer {
ConnIndex conn;
Tag analyzer;
double timeout;
struct Comparator {
bool operator() (ScheduledAnalyzer* a, ScheduledAnalyzer* b) {
return a->timeout > b->timeout;
}
};
};
typedef std::multimap<ConnIndex, ScheduledAnalyzer*> conns_map;
typedef std::priority_queue<ScheduledAnalyzer*,
vector<ScheduledAnalyzer*>,
ScheduledAnalyzer::Comparator> conns_queue;
conns_map conns;
conns_queue conns_by_timeout;
}; };
} }
extern analyzer::Manager* analyzer_mgr; extern analyzer::Manager* analyzer_mgr;
// Macros for anayzer debug logging which include the connection id into the
// message.
#ifdef DEBUG
# define DBG_ANALYZER(conn, txt) \
DBG_LOG(DBG_ANALYZER, "%s " txt, \
fmt_conn_id(conn->OrigAddr(), ntohs(conn->OrigPort()), \
conn->RespAddr(), ntohs(conn->RespPort())));
# define DBG_ANALYZER_ARGS(conn, fmt, args...) \
DBG_LOG(DBG_ANALYZER, "%s " fmt, \
fmt_conn_id(conn->OrigAddr(), ntohs(conn->OrigPort()), \
conn->RespAddr(), ntohs(conn->RespPort())), ##args);
#else
# define DBG_ANALYZER(conn, txt)
# define DBG_ANALYZER_ARGS(conn, fmt, args...)
#endif
#endif #endif

View file

@ -1,37 +0,0 @@
#include "PluginComponent.h"
#include "../Desc.h"
using namespace analyzer;
Tag::type_t PluginComponent::type_counter = 0;
PluginComponent::PluginComponent(std::string arg_name, factory_callback arg_factory, bool arg_enabled, bool arg_partial)
: Component(plugin::component::ANALYZER)
{
name = arg_name;
factory = arg_factory;
enabled = arg_enabled;
partial = arg_partial;
tag = analyzer::Tag(++type_counter, 0);
}
PluginComponent::PluginComponent(std::string arg_name, Tag::subtype_t arg_stype, factory_callback arg_factory, bool arg_enabled, bool arg_partial)
: Component(plugin::component::ANALYZER)
{
name = arg_name;
factory = arg_factory;
enabled = arg_enabled;
partial = arg_partial;
tag = analyzer::Tag(++type_counter, arg_stype);
}
void PluginComponent::Describe(ODesc* d)
{
plugin::Component::Describe(d);
d->Add(name);
}

View file

@ -1,51 +0,0 @@
#ifndef ANALYZER_PLUGIN_COMPONENT_H
#define ANALYZER_PLUGIN_COMPONENT_H
#include <string>
#include "../config.h"
#include "../util.h"
#include "plugin/Component.h"
#include "Tag.h"
class Connection;
namespace analyzer {
class Analyzer;
// This can be copied by value.
class PluginComponent : public plugin::Component {
public:
typedef bool (*available_callback)();
typedef Analyzer* (*factory_callback)(Connection* conn);
PluginComponent(std::string name, factory_callback factory, bool enabled, bool partial);
PluginComponent(std::string name, Tag::subtype_t subtype, factory_callback factory, bool enabled, bool partial);
const std::string& Name() const { return name; }
factory_callback Factory() const { return factory; }
bool Partial() const { return partial; }
bool Enabled() const { return enabled; }
analyzer::Tag Tag() const { return tag; }
void SetEnabled(bool arg_enabled) { enabled = arg_enabled; }
virtual void Describe(ODesc* d);
private:
std::string name;
factory_callback factory;
bool partial;
analyzer::Tag tag;
bool enabled;
static analyzer::Tag::type_t type_counter;
};
}
#endif

View file

@ -6,11 +6,10 @@
using namespace analyzer; using namespace analyzer;
Tag Tag::ERROR;
Tag::Tag(type_t arg_type, subtype_t arg_subtype) Tag::Tag(type_t arg_type, subtype_t arg_subtype)
{ {
assert(arg_type > 0); assert(arg_type > 0);
type = arg_type; type = arg_type;
subtype = arg_subtype; subtype = arg_subtype;
int64_t i = (int64)(type) | ((int64)subtype << 31); int64_t i = (int64)(type) | ((int64)subtype << 31);
@ -23,6 +22,7 @@ Tag::Tag(type_t arg_type, subtype_t arg_subtype)
Tag::Tag(EnumVal* arg_val) Tag::Tag(EnumVal* arg_val)
{ {
assert(val); assert(val);
val = arg_val; val = arg_val;
Ref(val); Ref(val);
@ -37,7 +37,7 @@ Tag::Tag(const Tag& other) : type(other.type), subtype(other.subtype)
subtype = other.subtype; subtype = other.subtype;
val = other.val; val = other.val;
if ( val ) if ( val )
Ref(val); Ref(val);
} }
@ -48,7 +48,7 @@ Tag::Tag()
val = 0; val = 0;
} }
EnumVal* Tag::Val() EnumVal* Tag::AsEnumVal() const
{ {
if ( ! val ) if ( ! val )
{ {
@ -66,4 +66,3 @@ std::string Tag::AsString() const
{ {
return fmt("%" PRIu32 "/%" PRIu32, type, subtype); return fmt("%" PRIu32 "/%" PRIu32, type, subtype);
} }

View file

@ -2,14 +2,6 @@
#ifndef ANALYZER_TAG_H #ifndef ANALYZER_TAG_H
#define ANALYZER_TAG_H #define ANALYZER_TAG_H
// Each kind of analyzer gets a tag consisting of a main type and subtype.
// The former is an identifier that's unique all analyzer classes. The latter
// is passed through analyzer instances, yet not further interpreted by the
// analyzer infrastructure; it allows an analyzer to branch out into a set of
// sub-analyzers internally. Jointly, main type and subtype form an analyzer
// "tag". Each unique tag corresponds to a single "analyzer" from the user's
// perspective.
#include "config.h" #include "config.h"
#include "util.h" #include "util.h"
@ -17,41 +9,129 @@ class EnumVal;
namespace analyzer { namespace analyzer {
/// This has supports all operations to be used as a map index. class Manager;
class Component;
/**
* Class to identify an analyzdr type.
*
* Each analyzer type gets a tag consisting of a main type and subtype. The
* former is an identifier that's unique all analyzer classes. The latter is
* passed through to the analyzer instances for their use, yet not further
* interpreted by the analyzer infrastructure; it allows an analyzer to
* branch out into a set of sub-analyzers internally. Jointly, main type and
* subtype form an analyzer "tag". Each unique tag corresponds to a single
* "analyzer" from the user's perspective. At the script layer, these tags
* are mapped into enums of type \c Analyzer::Tag. Internally, the
* analyzer::Mangager maintains the mapping of tag to analyzer (and it also
* assigns them their main types), and analyzer::Component creates new
* tags.
*
* The Tag class supports all operations necessary to act at the index in a
* \c std::map.
*/
class Tag { class Tag {
public: public:
/**
* Type for the analyzer's main type.
*/
typedef uint32 type_t; typedef uint32 type_t;
/**
* Type for the analyzer's subtype.
*/
typedef uint32 subtype_t; typedef uint32 subtype_t;
Tag(type_t type, subtype_t subtype = 0); /*
Tag(EnumVal* val); * Copy constructor.
*/
Tag(const Tag& other); Tag(const Tag& other);
Tag(); // Tag::ERROR value
/**
* Default constructor. This initializes the tag with an error value
* that will make \c operator \c bool return false.
*/
Tag();
/**
* Returns the tag's main type.
*/
type_t Type() const { return type; } type_t Type() const { return type; }
/**
* Returns the tag's subtype.
*/
subtype_t Subtype() const { return subtype; } subtype_t Subtype() const { return subtype; }
// Returns an identifying integer for this tag that's guaranteed to /**
// be unique across all tags. * Returns the \c Analyzer::Tag enum that corresponds to this tag.
EnumVal* Val(); * The returned value is \a does not have its ref-count increased.
*/
EnumVal* AsEnumVal() const;
/**
* Returns the numerical values for main and subtype inside a string
* suitable for printing. This is primarily for debugging.
*/
std::string AsString() const; std::string AsString() const;
/**
* Returns false if the tag represents an error value rather than a
* legal analyzer type.
*/
operator bool() const { return *this != Tag(); } operator bool() const { return *this != Tag(); }
bool operator==(const Tag& other) const { return type == other.type && subtype == other.subtype; }
bool operator!=(const Tag& other) const { return type != other.type || subtype != other.subtype; } /**
* Compares two tags for equality.
*/
bool operator==(const Tag& other) const
{
return type == other.type && subtype == other.subtype;
}
/**
* Compares two tags for inequality.
*/
bool operator!=(const Tag& other) const
{
return type != other.type || subtype != other.subtype;
}
/**
* Compares two tags for less-than relationship.
*/
bool operator<(const Tag& other) const bool operator<(const Tag& other) const
{ {
return type != other.type ? type < other.type : (subtype < other.subtype); return type != other.type ? type < other.type : (subtype < other.subtype);
} }
protected:
friend class analyzer::Manager;
friend class analyzer::Component;
static Tag ERROR; /**
* Constructor. Note
*
* @param type The main type. Note that the \a analyzer::Manager
* manages the value space internally, so noone else should assign
* any main tyoes.
*
* @param subtype The sub type, which is left to an analyzer for
* interpretation. By default it's set to zero.
*/
Tag(type_t type, subtype_t subtype = 0);
/**
* Constructor.
*
* @param val An enuam value of script type \c Analyzer::Tag.
*/
Tag(EnumVal* val);
private: private:
type_t type; type_t type; // Main type.
subtype_t subtype; subtype_t subtype; // Subtype.
EnumVal* val; mutable EnumVal* val; // Analyzer::Tag value.
}; };
} }

View file

@ -134,7 +134,7 @@ event dns_mapping_altered%(dm: dns_mapping, old_addrs: addr_set, new_addrs: addr
## connection_first_ACK connection_half_finished connection_partial_close ## connection_first_ACK connection_half_finished connection_partial_close
## connection_pending connection_rejected connection_reset connection_reused ## connection_pending connection_rejected connection_reset connection_reused
## connection_state_remove connection_status_update connection_timeout ## connection_state_remove connection_status_update connection_timeout
## expected_connection_seen new_connection_contents partial_connection ## scheduled_analyzer_applied new_connection_contents partial_connection
## ##
## .. note:: ## .. note::
## ##
@ -168,7 +168,7 @@ event tunnel_changed%(c: connection, e: EncapsulatingConnVector%);
## connection_first_ACK connection_half_finished connection_partial_close ## connection_first_ACK connection_half_finished connection_partial_close
## connection_pending connection_rejected connection_reset connection_reused ## connection_pending connection_rejected connection_reset connection_reused
## connection_state_remove connection_status_update connection_timeout ## connection_state_remove connection_status_update connection_timeout
## expected_connection_seen new_connection partial_connection ## scheduled_analyzer_applied new_connection partial_connection
event new_connection_contents%(c: connection%); event new_connection_contents%(c: connection%);
## Generated for an unsuccessful connection attempt. This event is raised when ## Generated for an unsuccessful connection attempt. This event is raised when
@ -183,7 +183,7 @@ event new_connection_contents%(c: connection%);
## connection_external connection_finished connection_first_ACK ## connection_external connection_finished connection_first_ACK
## connection_half_finished connection_partial_close connection_pending ## connection_half_finished connection_partial_close connection_pending
## connection_rejected connection_reset connection_reused connection_state_remove ## connection_rejected connection_reset connection_reused connection_state_remove
## connection_status_update connection_timeout expected_connection_seen ## connection_status_update connection_timeout scheduled_analyzer_applied
## new_connection new_connection_contents partial_connection ## new_connection new_connection_contents partial_connection
event connection_attempt%(c: connection%); event connection_attempt%(c: connection%);
@ -199,7 +199,7 @@ event connection_attempt%(c: connection%);
## connection_external connection_finished connection_first_ACK ## connection_external connection_finished connection_first_ACK
## connection_half_finished connection_partial_close connection_pending ## connection_half_finished connection_partial_close connection_pending
## connection_rejected connection_reset connection_reused connection_state_remove ## connection_rejected connection_reset connection_reused connection_state_remove
## connection_status_update connection_timeout expected_connection_seen ## connection_status_update connection_timeout scheduled_analyzer_applied
## new_connection new_connection_contents partial_connection ## new_connection new_connection_contents partial_connection
event connection_established%(c: connection%); event connection_established%(c: connection%);
@ -215,7 +215,7 @@ event connection_established%(c: connection%);
## connection_first_ACK connection_half_finished connection_partial_close ## connection_first_ACK connection_half_finished connection_partial_close
## connection_pending connection_rejected connection_reset connection_reused ## connection_pending connection_rejected connection_reset connection_reused
## connection_state_remove connection_status_update connection_timeout ## connection_state_remove connection_status_update connection_timeout
## expected_connection_seen new_connection new_connection_contents ## scheduled_analyzer_applied new_connection new_connection_contents
## ##
event partial_connection%(c: connection%); event partial_connection%(c: connection%);
@ -231,7 +231,7 @@ event partial_connection%(c: connection%);
## connection_established connection_external connection_finished ## connection_established connection_external connection_finished
## connection_first_ACK connection_half_finished connection_pending ## connection_first_ACK connection_half_finished connection_pending
## connection_rejected connection_reset connection_reused connection_state_remove ## connection_rejected connection_reset connection_reused connection_state_remove
## connection_status_update connection_timeout expected_connection_seen ## connection_status_update connection_timeout scheduled_analyzer_applied
## new_connection new_connection_contents partial_connection ## new_connection new_connection_contents partial_connection
event connection_partial_close%(c: connection%); event connection_partial_close%(c: connection%);
@ -244,7 +244,7 @@ event connection_partial_close%(c: connection%);
## connection_established connection_external connection_first_ACK ## connection_established connection_external connection_first_ACK
## connection_half_finished connection_partial_close connection_pending ## connection_half_finished connection_partial_close connection_pending
## connection_rejected connection_reset connection_reused connection_state_remove ## connection_rejected connection_reset connection_reused connection_state_remove
## connection_status_update connection_timeout expected_connection_seen ## connection_status_update connection_timeout scheduled_analyzer_applied
## new_connection new_connection_contents partial_connection ## new_connection new_connection_contents partial_connection
event connection_finished%(c: connection%); event connection_finished%(c: connection%);
@ -258,7 +258,7 @@ event connection_finished%(c: connection%);
## connection_established connection_external connection_finished ## connection_established connection_external connection_finished
## connection_first_ACK connection_partial_close connection_pending ## connection_first_ACK connection_partial_close connection_pending
## connection_rejected connection_reset connection_reused connection_state_remove ## connection_rejected connection_reset connection_reused connection_state_remove
## connection_status_update connection_timeout expected_connection_seen ## connection_status_update connection_timeout scheduled_analyzer_applied
## new_connection new_connection_contents partial_connection ## new_connection new_connection_contents partial_connection
event connection_half_finished%(c: connection%); event connection_half_finished%(c: connection%);
@ -270,7 +270,7 @@ event connection_half_finished%(c: connection%);
## connection_established connection_external connection_finished ## connection_established connection_external connection_finished
## connection_first_ACK connection_half_finished connection_partial_close ## connection_first_ACK connection_half_finished connection_partial_close
## connection_pending connection_reset connection_reused connection_state_remove ## connection_pending connection_reset connection_reused connection_state_remove
## connection_status_update connection_timeout expected_connection_seen ## connection_status_update connection_timeout scheduled_analyzer_applied
## new_connection new_connection_contents partial_connection ## new_connection new_connection_contents partial_connection
## ##
## c: The connection. ## c: The connection.
@ -294,7 +294,7 @@ event connection_rejected%(c: connection%);
## connection_first_ACK connection_half_finished connection_partial_close ## connection_first_ACK connection_half_finished connection_partial_close
## connection_pending connection_rejected connection_reused ## connection_pending connection_rejected connection_reused
## connection_state_remove connection_status_update connection_timeout ## connection_state_remove connection_status_update connection_timeout
## expected_connection_seen new_connection new_connection_contents ## scheduled_analyzer_applied new_connection new_connection_contents
## partial_connection ## partial_connection
event connection_reset%(c: connection%); event connection_reset%(c: connection%);
@ -306,7 +306,7 @@ event connection_reset%(c: connection%);
## connection_established connection_external connection_finished ## connection_established connection_external connection_finished
## connection_first_ACK connection_half_finished connection_partial_close ## connection_first_ACK connection_half_finished connection_partial_close
## connection_rejected connection_reset connection_reused connection_state_remove ## connection_rejected connection_reset connection_reused connection_state_remove
## connection_status_update connection_timeout expected_connection_seen ## connection_status_update connection_timeout scheduled_analyzer_applied
## new_connection new_connection_contents partial_connection bro_done ## new_connection new_connection_contents partial_connection bro_done
event connection_pending%(c: connection%); event connection_pending%(c: connection%);
@ -323,7 +323,7 @@ event connection_pending%(c: connection%);
## connection_established connection_external connection_finished ## connection_established connection_external connection_finished
## connection_first_ACK connection_half_finished connection_partial_close ## connection_first_ACK connection_half_finished connection_partial_close
## connection_pending connection_rejected connection_reset connection_reused ## connection_pending connection_rejected connection_reset connection_reused
## connection_status_update connection_timeout expected_connection_seen ## connection_status_update connection_timeout scheduled_analyzer_applied
## new_connection new_connection_contents partial_connection udp_inactivity_timeout ## new_connection new_connection_contents partial_connection udp_inactivity_timeout
## tcp_inactivity_timeout icmp_inactivity_timeout conn_stats ## tcp_inactivity_timeout icmp_inactivity_timeout conn_stats
event connection_state_remove%(c: connection%); event connection_state_remove%(c: connection%);
@ -339,7 +339,7 @@ event connection_state_remove%(c: connection%);
## connection_external connection_finished connection_first_ACK ## connection_external connection_finished connection_first_ACK
## connection_half_finished connection_partial_close connection_pending ## connection_half_finished connection_partial_close connection_pending
## connection_rejected connection_reset connection_reused connection_state_remove ## connection_rejected connection_reset connection_reused connection_state_remove
## connection_status_update connection_timeout expected_connection_seen ## connection_status_update connection_timeout scheduled_analyzer_applied
## new_connection new_connection_contents partial_connection ## new_connection new_connection_contents partial_connection
## ##
## .. note:: ## .. note::
@ -360,7 +360,7 @@ event connection_SYN_packet%(c: connection, pkt: SYN_packet%);
## connection_established connection_external connection_finished ## connection_established connection_external connection_finished
## connection_half_finished connection_partial_close connection_pending ## connection_half_finished connection_partial_close connection_pending
## connection_rejected connection_reset connection_reused connection_state_remove ## connection_rejected connection_reset connection_reused connection_state_remove
## connection_status_update connection_timeout expected_connection_seen ## connection_status_update connection_timeout scheduled_analyzer_applied
## new_connection new_connection_contents partial_connection ## new_connection new_connection_contents partial_connection
## ##
## .. note:: ## .. note::
@ -379,7 +379,7 @@ event connection_first_ACK%(c: connection%);
## connection_established connection_external connection_finished ## connection_established connection_external connection_finished
## connection_first_ACK connection_half_finished connection_partial_close ## connection_first_ACK connection_half_finished connection_partial_close
## connection_pending connection_rejected connection_reset connection_reused ## connection_pending connection_rejected connection_reset connection_reused
## connection_state_remove connection_status_update expected_connection_seen ## connection_state_remove connection_status_update scheduled_analyzer_applied
## new_connection new_connection_contents partial_connection ## new_connection new_connection_contents partial_connection
## ##
## .. note:: ## .. note::
@ -402,7 +402,7 @@ event connection_timeout%(c: connection%);
## connection_established connection_external connection_finished ## connection_established connection_external connection_finished
## connection_first_ACK connection_half_finished connection_partial_close ## connection_first_ACK connection_half_finished connection_partial_close
## connection_pending connection_rejected connection_reset connection_state_remove ## connection_pending connection_rejected connection_reset connection_state_remove
## connection_status_update connection_timeout expected_connection_seen ## connection_status_update connection_timeout scheduled_analyzer_applied
## new_connection new_connection_contents partial_connection ## new_connection new_connection_contents partial_connection
event connection_reused%(c: connection%); event connection_reused%(c: connection%);
@ -416,7 +416,7 @@ event connection_reused%(c: connection%);
## connection_established connection_external connection_finished ## connection_established connection_external connection_finished
## connection_first_ACK connection_half_finished connection_partial_close ## connection_first_ACK connection_half_finished connection_partial_close
## connection_pending connection_rejected connection_reset connection_reused ## connection_pending connection_rejected connection_reset connection_reused
## connection_state_remove connection_timeout expected_connection_seen ## connection_state_remove connection_timeout scheduled_analyzer_applied
## new_connection new_connection_contents partial_connection ## new_connection new_connection_contents partial_connection
event connection_status_update%(c: connection%); event connection_status_update%(c: connection%);
@ -446,7 +446,7 @@ event connection_flow_label_changed%(c: connection, is_orig: bool, old_label: co
## connection_external connection_finished connection_first_ACK ## connection_external connection_finished connection_first_ACK
## connection_half_finished connection_partial_close connection_pending ## connection_half_finished connection_partial_close connection_pending
## connection_rejected connection_reset connection_reused connection_state_remove ## connection_rejected connection_reset connection_reused connection_state_remove
## connection_status_update connection_timeout expected_connection_seen ## connection_status_update connection_timeout scheduled_analyzer_applied
## new_connection new_connection_contents partial_connection ## new_connection new_connection_contents partial_connection
event connection_EOF%(c: connection, is_orig: bool%); event connection_EOF%(c: connection, is_orig: bool%);
@ -481,7 +481,7 @@ event connection_external%(c: connection, tag: string%);
## ##
## .. todo:: We don't have a good way to document the automatically generated ## .. todo:: We don't have a good way to document the automatically generated
## ``ANALYZER_*`` constants right now. ## ``ANALYZER_*`` constants right now.
event expected_connection_seen%(c: connection, a: count%); event scheduled_analyzer_applied%(c: connection, a: Analyzer::Tag%);
## Generated for every packet Bro sees. This is a very low-level and expensive ## Generated for every packet Bro sees. This is a very low-level and expensive
## event that should be avoided when at all possible. It's usually infeasible to ## event that should be avoided when at all possible. It's usually infeasible to

View file

@ -2,7 +2,7 @@
#ifndef PLUGIN_MACROS_H #ifndef PLUGIN_MACROS_H
#define PLUGIN_MACROS_H #define PLUGIN_MACROS_H
#include "analyzer/PluginComponent.h" #include "analyzer/Component.h"
#define BRO_PLUGIN_VERSION_BUILTIN -1 #define BRO_PLUGIN_VERSION_BUILTIN -1
#define BRO_PLUGIN_API_VERSION 1 #define BRO_PLUGIN_API_VERSION 1
@ -36,7 +36,10 @@
std::list<std::pair<std::string, int> > __bif_##file##_init(); \ std::list<std::pair<std::string, int> > __bif_##file##_init(); \
AddBifInitFunction(&__bif_##file##_init); AddBifInitFunction(&__bif_##file##_init);
#define BRO_PLUGIN_ANALYZER(tag, factory, enabled, partial) \ #define BRO_PLUGIN_ANALYZER(tag, factory) \
AddComponent(new ::analyzer::PluginComponent(tag, factory, enabled, partial)); AddComponent(new ::analyzer::Component(tag, factory));
#define BRO_PLUGIN_ANALYZER_EXT(tag, factory, enabled, partial) \
AddComponent(new ::analyzer::Component(tag, factory, 0, enabled, partial));
#endif #endif

View file

@ -3,7 +3,7 @@
// analyzers into separate plugins. // analyzers into separate plugins.
#include "BuiltInAnalyzers.h" #include "BuiltInAnalyzers.h"
#include "analyzer/PluginComponent.h" #include "analyzer/Component.h"
#include "../binpac_bro.h" #include "../binpac_bro.h"
@ -47,8 +47,13 @@ using namespace analyzer;
BuiltinAnalyzers builtin_analyzers; BuiltinAnalyzers builtin_analyzers;
#define DEFINE_ANALYZER(name, factory, enabled, partial) \ #define DEFINE_ANALYZER(name, factory) \
AddComponent(new PluginComponent(name, factory, enabled, partial)) AddComponent(new Component(name, factory))
#define DEFINE_ANALYZER_VERSION_BINPAC(name, factory) \
AddComponent(new Component(name, factory, 0, FLAGS_use_binpac))
#define DEFINE_ANALYZER_VERSION_NON_BINPAC(name, factory) \
AddComponent(new Component(name, factory, 0, ! FLAGS_use_binpac))
void BuiltinAnalyzers::Init() void BuiltinAnalyzers::Init()
{ {
@ -58,72 +63,69 @@ void BuiltinAnalyzers::Init()
desc.version = BRO_PLUGIN_VERSION_BUILTIN; desc.version = BRO_PLUGIN_VERSION_BUILTIN;
SetDescription(desc); SetDescription(desc);
DEFINE_ANALYZER("PIA_TCP", PIA_TCP::InstantiateAnalyzer, true, false); DEFINE_ANALYZER("PIA_TCP", PIA_TCP::InstantiateAnalyzer);
DEFINE_ANALYZER("PIA_UDP", PIA_UDP::InstantiateAnalyzer, true, false); DEFINE_ANALYZER("PIA_UDP", PIA_UDP::InstantiateAnalyzer);
DEFINE_ANALYZER("ICMP", ICMP_Analyzer::InstantiateAnalyzer, true, false); DEFINE_ANALYZER("ICMP", ICMP_Analyzer::InstantiateAnalyzer);
DEFINE_ANALYZER("TCP", TCP_Analyzer::InstantiateAnalyzer, true, false); DEFINE_ANALYZER("TCP", TCP_Analyzer::InstantiateAnalyzer);
DEFINE_ANALYZER("UDP", UDP_Analyzer::InstantiateAnalyzer, true, false); DEFINE_ANALYZER("UDP", UDP_Analyzer::InstantiateAnalyzer);
DEFINE_ANALYZER("BITTORRENT", BitTorrent_Analyzer::InstantiateAnalyzer, true, false); DEFINE_ANALYZER("BITTORRENT", BitTorrent_Analyzer::InstantiateAnalyzer);
DEFINE_ANALYZER("BITTORRENTTRACKER", BitTorrentTracker_Analyzer::InstantiateAnalyzer, true, false); DEFINE_ANALYZER("BITTORRENTTRACKER", BitTorrentTracker_Analyzer::InstantiateAnalyzer);
DEFINE_ANALYZER("DCE_RPC", DCE_RPC_Analyzer::InstantiateAnalyzer, true, false); DEFINE_ANALYZER("DCE_RPC", DCE_RPC_Analyzer::InstantiateAnalyzer);
DEFINE_ANALYZER("DNS", DNS_Analyzer::InstantiateAnalyzer, ! FLAGS_use_binpac, false); DEFINE_ANALYZER_VERSION_NON_BINPAC("DNS", DNS_Analyzer::InstantiateAnalyzer);
DEFINE_ANALYZER("FINGER", Finger_Analyzer::InstantiateAnalyzer, true, false); DEFINE_ANALYZER("FINGER", Finger_Analyzer::InstantiateAnalyzer);
DEFINE_ANALYZER("FTP", FTP_Analyzer::InstantiateAnalyzer, true, false); DEFINE_ANALYZER("FTP", FTP_Analyzer::InstantiateAnalyzer);
DEFINE_ANALYZER("GNUTELLA", Gnutella_Analyzer::InstantiateAnalyzer, true, false); DEFINE_ANALYZER("GNUTELLA", Gnutella_Analyzer::InstantiateAnalyzer);
// DEFINE_ANALYZER("HTTP", HTTP_Analyzer::InstantiateAnalyzer, ! FLAGS_use_binpac, false); DEFINE_ANALYZER("IDENT", Ident_Analyzer::InstantiateAnalyzer);
DEFINE_ANALYZER("IDENT", Ident_Analyzer::InstantiateAnalyzer, true, false); DEFINE_ANALYZER("IRC", IRC_Analyzer::InstantiateAnalyzer);
DEFINE_ANALYZER("IRC", IRC_Analyzer::InstantiateAnalyzer, true, false); DEFINE_ANALYZER("LOGIN", 0); // just a base class
DEFINE_ANALYZER("LOGIN", 0, true, false); // just a base class DEFINE_ANALYZER("NCP", NCP_Analyzer::InstantiateAnalyzer);
DEFINE_ANALYZER("NCP", NCP_Analyzer::InstantiateAnalyzer, true, false); DEFINE_ANALYZER("NETBIOSSSN", NetbiosSSN_Analyzer::InstantiateAnalyzer);
DEFINE_ANALYZER("NETBIOSSSN", NetbiosSSN_Analyzer::InstantiateAnalyzer, true, false); DEFINE_ANALYZER("NFS", NFS_Analyzer::InstantiateAnalyzer);
DEFINE_ANALYZER("NFS", NFS_Analyzer::InstantiateAnalyzer, true, false); DEFINE_ANALYZER("NTP", NTP_Analyzer::InstantiateAnalyzer);
DEFINE_ANALYZER("NTP", NTP_Analyzer::InstantiateAnalyzer, true, false); DEFINE_ANALYZER("POP3", POP3_Analyzer::InstantiateAnalyzer);
DEFINE_ANALYZER("POP3", POP3_Analyzer::InstantiateAnalyzer, true, false); DEFINE_ANALYZER("PORTMAPPER", Portmapper_Analyzer::InstantiateAnalyzer);
DEFINE_ANALYZER("PORTMAPPER", Portmapper_Analyzer::InstantiateAnalyzer, true, false); DEFINE_ANALYZER("RLOGIN", Rlogin_Analyzer::InstantiateAnalyzer);
DEFINE_ANALYZER("RLOGIN", Rlogin_Analyzer::InstantiateAnalyzer, true, false); DEFINE_ANALYZER("RPC", 0);
DEFINE_ANALYZER("RPC", 0, true, false); DEFINE_ANALYZER("RSH", Rsh_Analyzer::InstantiateAnalyzer);
DEFINE_ANALYZER("RSH", Rsh_Analyzer::InstantiateAnalyzer, true, false); DEFINE_ANALYZER("SMB", SMB_Analyzer::InstantiateAnalyzer);
DEFINE_ANALYZER("SMB", SMB_Analyzer::InstantiateAnalyzer, true, false); DEFINE_ANALYZER("SMTP", SMTP_Analyzer::InstantiateAnalyzer);
DEFINE_ANALYZER("SMTP", SMTP_Analyzer::InstantiateAnalyzer, true, false); DEFINE_ANALYZER("SSH", SSH_Analyzer::InstantiateAnalyzer);
DEFINE_ANALYZER("SSH", SSH_Analyzer::InstantiateAnalyzer, true, false); DEFINE_ANALYZER("TELNET", Telnet_Analyzer::InstantiateAnalyzer);
DEFINE_ANALYZER("TELNET", Telnet_Analyzer::InstantiateAnalyzer, true, false);
DEFINE_ANALYZER("DHCP_BINPAC", DHCP_Analyzer_binpac::InstantiateAnalyzer, true, false); DEFINE_ANALYZER("DHCP_BINPAC", DHCP_Analyzer_binpac::InstantiateAnalyzer);
DEFINE_ANALYZER("DNS_TCP_BINPAC", DNS_TCP_Analyzer_binpac::InstantiateAnalyzer, FLAGS_use_binpac, false); DEFINE_ANALYZER_VERSION_BINPAC("DNS_TCP_BINPAC", DNS_TCP_Analyzer_binpac::InstantiateAnalyzer);
DEFINE_ANALYZER("DNS_UDP_BINPAC", DNS_UDP_Analyzer_binpac::InstantiateAnalyzer, FLAGS_use_binpac, false); DEFINE_ANALYZER_VERSION_BINPAC("DNS_UDP_BINPAC", DNS_UDP_Analyzer_binpac::InstantiateAnalyzer);
// DEFINE_ANALYZER("HTTP_BINPAC", HTTP_Analyzer_binpac::InstantiateAnalyzer, FLAGS_use_binpac, false); DEFINE_ANALYZER("SYSLOG_BINPAC", Syslog_Analyzer_binpac::InstantiateAnalyzer);
// DEFINE_ANALYZER("SSL", SSL_Analyzer::InstantiateAnalyzer, true, false); DEFINE_ANALYZER("MODBUS", ModbusTCP_Analyzer::InstantiateAnalyzer);
DEFINE_ANALYZER("SYSLOG_BINPAC", Syslog_Analyzer_binpac::InstantiateAnalyzer, true, false);
DEFINE_ANALYZER("MODBUS", ModbusTCP_Analyzer::InstantiateAnalyzer, true, false);
DEFINE_ANALYZER("AYIYA", AYIYA_Analyzer::InstantiateAnalyzer, true, false); DEFINE_ANALYZER("AYIYA", AYIYA_Analyzer::InstantiateAnalyzer);
DEFINE_ANALYZER("SOCKS", SOCKS_Analyzer::InstantiateAnalyzer, true, false); DEFINE_ANALYZER("SOCKS", SOCKS_Analyzer::InstantiateAnalyzer);
DEFINE_ANALYZER("TEREDO", Teredo_Analyzer::InstantiateAnalyzer, true, false); DEFINE_ANALYZER("TEREDO", Teredo_Analyzer::InstantiateAnalyzer);
DEFINE_ANALYZER("GTPV1", GTPv1_Analyzer::InstantiateAnalyzer, true, false); DEFINE_ANALYZER("GTPV1", GTPv1_Analyzer::InstantiateAnalyzer);
DEFINE_ANALYZER("FILE", File_Analyzer::InstantiateAnalyzer, true, false); DEFINE_ANALYZER("FILE", File_Analyzer::InstantiateAnalyzer);
DEFINE_ANALYZER("BACKDOOR", BackDoor_Analyzer::InstantiateAnalyzer, true, false); DEFINE_ANALYZER("BACKDOOR", BackDoor_Analyzer::InstantiateAnalyzer);
DEFINE_ANALYZER("INTERCONN", InterConn_Analyzer::InstantiateAnalyzer, true, false); DEFINE_ANALYZER("INTERCONN", InterConn_Analyzer::InstantiateAnalyzer);
DEFINE_ANALYZER("STEPPINGSTONE", SteppingStone_Analyzer::InstantiateAnalyzer, true, false); DEFINE_ANALYZER("STEPPINGSTONE", SteppingStone_Analyzer::InstantiateAnalyzer);
DEFINE_ANALYZER("TCPSTATS", TCPStats_Analyzer::InstantiateAnalyzer, true, false); DEFINE_ANALYZER("TCPSTATS", TCPStats_Analyzer::InstantiateAnalyzer);
DEFINE_ANALYZER("CONNSIZE", ConnSize_Analyzer::InstantiateAnalyzer, true, false); DEFINE_ANALYZER("CONNSIZE", ConnSize_Analyzer::InstantiateAnalyzer);
DEFINE_ANALYZER("CONTENTS", 0, true, false); DEFINE_ANALYZER("CONTENTS", 0);
DEFINE_ANALYZER("CONTENTLINE", 0, true, false); DEFINE_ANALYZER("CONTENTLINE", 0);
DEFINE_ANALYZER("NVT", 0, true, false); DEFINE_ANALYZER("NVT", 0);
DEFINE_ANALYZER("ZIP", 0, true, false); DEFINE_ANALYZER("ZIP", 0);
DEFINE_ANALYZER("CONTENTS_DNS", 0, true, false); DEFINE_ANALYZER("CONTENTS_DNS", 0);
DEFINE_ANALYZER("CONTENTS_NETBIOSSSN", 0, true, false); DEFINE_ANALYZER("CONTENTS_NETBIOSSSN", 0);
DEFINE_ANALYZER("CONTENTS_NCP", 0, true, false); DEFINE_ANALYZER("CONTENTS_NCP", 0);
DEFINE_ANALYZER("CONTENTS_RLOGIN", 0, true, false); DEFINE_ANALYZER("CONTENTS_RLOGIN", 0);
DEFINE_ANALYZER("CONTENTS_RSH", 0, true, false); DEFINE_ANALYZER("CONTENTS_RSH", 0);
DEFINE_ANALYZER("CONTENTS_DCE_RPC", 0, true, false); DEFINE_ANALYZER("CONTENTS_DCE_RPC", 0);
DEFINE_ANALYZER("CONTENTS_SMB", 0, true, false); DEFINE_ANALYZER("CONTENTS_SMB", 0);
DEFINE_ANALYZER("CONTENTS_RPC", 0, true, false); DEFINE_ANALYZER("CONTENTS_RPC", 0);
DEFINE_ANALYZER("CONTENTS_NFS", 0, true, false); DEFINE_ANALYZER("CONTENTS_NFS", 0);
DEFINE_ANALYZER("FTP_ADAT", 0, true, false); DEFINE_ANALYZER("FTP_ADAT", 0);
} }

View file

@ -17,7 +17,7 @@
BRO_PLUGIN_BEGIN(HTTP) BRO_PLUGIN_BEGIN(HTTP)
BRO_PLUGIN_DESCRIPTION = "HTTP Analyzer"; BRO_PLUGIN_DESCRIPTION = "HTTP Analyzer";
BRO_PLUGIN_ANALYZER("HTTP", HTTP_Analyzer::InstantiateAnalyzer, true, false); BRO_PLUGIN_ANALYZER("HTTP", HTTP_Analyzer::InstantiateAnalyzer);
BRO_PLUGIN_BIF_FILE(events); BRO_PLUGIN_BIF_FILE(events);
BRO_PLUGIN_BIF_FILE(functions); BRO_PLUGIN_BIF_FILE(functions);
BRO_PLUGIN_END BRO_PLUGIN_END

View file

@ -5,6 +5,6 @@
BRO_PLUGIN_BEGIN(SSL) BRO_PLUGIN_BEGIN(SSL)
BRO_PLUGIN_DESCRIPTION = "SSL Analyzer"; BRO_PLUGIN_DESCRIPTION = "SSL Analyzer";
BRO_PLUGIN_ANALYZER("SSL", SSL_Analyzer::InstantiateAnalyzer, true, false); BRO_PLUGIN_ANALYZER("SSL", SSL_Analyzer::InstantiateAnalyzer);
BRO_PLUGIN_BIF_FILE(events); BRO_PLUGIN_BIF_FILE(events);
BRO_PLUGIN_END BRO_PLUGIN_END

View file

@ -3,19 +3,19 @@
#empty_field (empty) #empty_field (empty)
#unset_field - #unset_field -
#path loaded_scripts #path loaded_scripts
#open 2013-03-26-20-58-03 #open 2013-04-01-19-44-31
#fields name #fields name
#types string #types string
scripts/base/init-bare.bro scripts/base/init-bare.bro
build/src/base/const.bif.bro build/scripts/base/bif/const.bif.bro
build/src/base/types.bif.bro build/scripts/base/bif/types.bif.bro
build/src/base/strings.bif.bro build/scripts/base/bif/strings.bif.bro
build/src/base/bro.bif.bro build/scripts/base/bif/bro.bif.bro
build/src/base/reporter.bif.bro build/scripts/base/bif/reporter.bif.bro
build/src/base/event.bif.bro build/scripts/base/bif/event.bif.bro
scripts/base/frameworks/logging/__load__.bro scripts/base/frameworks/logging/__load__.bro
scripts/base/frameworks/logging/./main.bro scripts/base/frameworks/logging/./main.bro
build/src/base/logging.bif.bro build/scripts/base/bif/logging.bif.bro
scripts/base/frameworks/logging/./postprocessors/__load__.bro scripts/base/frameworks/logging/./postprocessors/__load__.bro
scripts/base/frameworks/logging/./postprocessors/./scp.bro scripts/base/frameworks/logging/./postprocessors/./scp.bro
scripts/base/frameworks/logging/./postprocessors/./sftp.bro scripts/base/frameworks/logging/./postprocessors/./sftp.bro
@ -25,12 +25,16 @@ scripts/base/init-bare.bro
scripts/base/frameworks/logging/./writers/none.bro scripts/base/frameworks/logging/./writers/none.bro
scripts/base/frameworks/input/__load__.bro scripts/base/frameworks/input/__load__.bro
scripts/base/frameworks/input/./main.bro scripts/base/frameworks/input/./main.bro
build/src/base/input.bif.bro build/scripts/base/bif/input.bif.bro
scripts/base/frameworks/input/./readers/ascii.bro scripts/base/frameworks/input/./readers/ascii.bro
scripts/base/frameworks/input/./readers/raw.bro scripts/base/frameworks/input/./readers/raw.bro
scripts/base/frameworks/input/./readers/benchmark.bro scripts/base/frameworks/input/./readers/benchmark.bro
scripts/base/frameworks/analyzer/__load__.bro scripts/base/frameworks/analyzer/__load__.bro
scripts/base/frameworks/analyzer/./main.bro scripts/base/frameworks/analyzer/./main.bro
build/src/base/analyzer.bif.bro build/scripts/base/bif/analyzer.bif.bro
build/scripts/base/bif/plugins/__load__.bro
build/scripts/base/bif/plugins/./HTTP.events.bif.bro
build/scripts/base/bif/plugins/./HTTP.functions.bif.bro
build/scripts/base/bif/plugins/./SSL.events.bif.bro
scripts/policy/misc/loaded-scripts.bro scripts/policy/misc/loaded-scripts.bro
#close 2013-03-26-20-58-03 #close 2013-04-01-19-44-31

View file

@ -3,19 +3,19 @@
#empty_field (empty) #empty_field (empty)
#unset_field - #unset_field -
#path loaded_scripts #path loaded_scripts
#open 2013-03-26-20-58-16 #open 2013-04-01-19-44-38
#fields name #fields name
#types string #types string
scripts/base/init-bare.bro scripts/base/init-bare.bro
build/src/base/const.bif.bro build/scripts/base/bif/const.bif.bro
build/src/base/types.bif.bro build/scripts/base/bif/types.bif.bro
build/src/base/strings.bif.bro build/scripts/base/bif/strings.bif.bro
build/src/base/bro.bif.bro build/scripts/base/bif/bro.bif.bro
build/src/base/reporter.bif.bro build/scripts/base/bif/reporter.bif.bro
build/src/base/event.bif.bro build/scripts/base/bif/event.bif.bro
scripts/base/frameworks/logging/__load__.bro scripts/base/frameworks/logging/__load__.bro
scripts/base/frameworks/logging/./main.bro scripts/base/frameworks/logging/./main.bro
build/src/base/logging.bif.bro build/scripts/base/bif/logging.bif.bro
scripts/base/frameworks/logging/./postprocessors/__load__.bro scripts/base/frameworks/logging/./postprocessors/__load__.bro
scripts/base/frameworks/logging/./postprocessors/./scp.bro scripts/base/frameworks/logging/./postprocessors/./scp.bro
scripts/base/frameworks/logging/./postprocessors/./sftp.bro scripts/base/frameworks/logging/./postprocessors/./sftp.bro
@ -25,13 +25,17 @@ scripts/base/init-bare.bro
scripts/base/frameworks/logging/./writers/none.bro scripts/base/frameworks/logging/./writers/none.bro
scripts/base/frameworks/input/__load__.bro scripts/base/frameworks/input/__load__.bro
scripts/base/frameworks/input/./main.bro scripts/base/frameworks/input/./main.bro
build/src/base/input.bif.bro build/scripts/base/bif/input.bif.bro
scripts/base/frameworks/input/./readers/ascii.bro scripts/base/frameworks/input/./readers/ascii.bro
scripts/base/frameworks/input/./readers/raw.bro scripts/base/frameworks/input/./readers/raw.bro
scripts/base/frameworks/input/./readers/benchmark.bro scripts/base/frameworks/input/./readers/benchmark.bro
scripts/base/frameworks/analyzer/__load__.bro scripts/base/frameworks/analyzer/__load__.bro
scripts/base/frameworks/analyzer/./main.bro scripts/base/frameworks/analyzer/./main.bro
build/src/base/analyzer.bif.bro build/scripts/base/bif/analyzer.bif.bro
build/scripts/base/bif/plugins/__load__.bro
build/scripts/base/bif/plugins/./HTTP.events.bif.bro
build/scripts/base/bif/plugins/./HTTP.functions.bif.bro
build/scripts/base/bif/plugins/./SSL.events.bif.bro
scripts/base/init-default.bro scripts/base/init-default.bro
scripts/base/utils/site.bro scripts/base/utils/site.bro
scripts/base/utils/./patterns.bro scripts/base/utils/./patterns.bro
@ -122,4 +126,4 @@ scripts/base/init-default.bro
scripts/base/protocols/syslog/./main.bro scripts/base/protocols/syslog/./main.bro
scripts/base/misc/find-checksum-offloading.bro scripts/base/misc/find-checksum-offloading.bro
scripts/policy/misc/loaded-scripts.bro scripts/policy/misc/loaded-scripts.bro
#close 2013-03-26-20-58-16 #close 2013-04-01-19-44-38

View file

@ -0,0 +1,5 @@
APPLIED:, 1299491995.0, [orig_h=10.0.0.2, orig_p=20/tcp, resp_h=10.0.0.3, resp_p=6/tcp], Analyzer::ANALYZER_DNS
APPLIED:, 1299491995.0, [orig_h=10.0.0.2, orig_p=20/tcp, resp_h=10.0.0.3, resp_p=6/tcp], Analyzer::ANALYZER_FTP
APPLIED:, 1299491995.0, [orig_h=10.0.0.2, orig_p=20/tcp, resp_h=10.0.0.3, resp_p=6/tcp], Analyzer::ANALYZER_SSH
APPLIED:, 1299491995.0, [orig_h=10.0.0.2, orig_p=20/tcp, resp_h=10.0.0.3, resp_p=6/tcp], Analyzer::ANALYZER_HTTP
APPLIED:, 1299499195.0, [orig_h=10.0.0.2, orig_p=20/tcp, resp_h=10.0.0.3, resp_p=8/tcp], Analyzer::ANALYZER_DNS

View file

@ -0,0 +1,36 @@
#
# @TEST-EXEC: bro -b -r ${TRACES}/rotation.trace %INPUT >output
# @TEST-EXEC: btest-diff output
global x = 0;
event new_connection(c: connection)
{
# Make sure expiration executes.
Analyzer::schedule_analyzer(1.2.3.4, 1.2.3.4, 8/tcp, Analyzer::ANALYZER_MODBUS, 100hrs);
if ( x > 0 )
return;
x = 1;
Analyzer::schedule_analyzer(10.0.0.2, 10.0.0.3, 6/tcp, Analyzer::ANALYZER_SSH, 100hrs);
Analyzer::schedule_analyzer(10.0.0.2, 10.0.0.3, 6/tcp, Analyzer::ANALYZER_HTTP, 100hrs);
Analyzer::schedule_analyzer(10.0.0.2, 10.0.0.3, 6/tcp, Analyzer::ANALYZER_DNS, 100hrs);
Analyzer::schedule_analyzer(0.0.0.0, 10.0.0.3, 6/tcp, Analyzer::ANALYZER_FTP, 100hrs);
Analyzer::schedule_analyzer(10.0.0.2, 10.0.0.3, 7/tcp, Analyzer::ANALYZER_SSH, 1sec);
Analyzer::schedule_analyzer(10.0.0.2, 10.0.0.3, 8/tcp, Analyzer::ANALYZER_HTTP, 1sec);
Analyzer::schedule_analyzer(10.0.0.2, 10.0.0.3, 8/tcp, Analyzer::ANALYZER_DNS, 100hrs);
Analyzer::schedule_analyzer(10.0.0.2, 10.0.0.3, 9/tcp, Analyzer::ANALYZER_FTP, 1sec);
}
event scheduled_analyzer_applied(c: connection, a: Analyzer::Tag)
{
print "APPLIED:", network_time(), c$id, a;
}