Add file analysis action to send data to script-land in chosen events.

This commit is contained in:
Jon Siwek 2013-02-22 16:49:53 -06:00
parent 85410a7657
commit 4b30cc2e24
10 changed files with 134 additions and 17 deletions

View file

@ -33,8 +33,13 @@ export {
## TODO: what's a reasonable default? ## TODO: what's a reasonable default?
const default_data_event_len: count = 1024*1024 &redef; const default_data_event_len: count = 1024*1024 &redef;
# Needed a forward declaration for event parameters...
type Info: record {};
type ActionArgs: record { type ActionArgs: record {
extract_filename: string &optional; extract_filename: string &optional;
chunk_event: event(info: Info, data: string, off: count) &optional;
stream_event: event(info: Info, data: string) &optional;
}; };
type ActionResults: record { type ActionResults: record {

View file

@ -455,6 +455,7 @@ set(bro_SRCS
file_analysis/Action.h file_analysis/Action.h
file_analysis/Extract.cc file_analysis/Extract.cc
file_analysis/Hash.cc file_analysis/Hash.cc
file_analysis/DataEvent.cc
nb_dns.c nb_dns.c
digest.h digest.h

View file

@ -61,11 +61,12 @@ enum Action %{
ACTION_MD5, ACTION_MD5,
ACTION_SHA1, ACTION_SHA1,
ACTION_SHA256, ACTION_SHA256,
ACTION_DATA_EVENT,
%} %}
function FileAnalysis::postpone_timeout%(file_id: string%): bool function FileAnalysis::postpone_timeout%(file_id: string%): bool
%{ %{
using namespace file_analysis; using file_analysis::FileID;
bool result = file_mgr->PostponeTimeout(FileID(file_id->CheckString())); bool result = file_mgr->PostponeTimeout(FileID(file_id->CheckString()));
return new Val(result, TYPE_BOOL); return new Val(result, TYPE_BOOL);
%} %}
@ -74,9 +75,9 @@ function FileAnalysis::add_action%(file_id: string,
action: FileAnalysis::Action, action: FileAnalysis::Action,
args: any%): bool args: any%): bool
%{ %{
using namespace file_analysis; using file_analysis::FileID;
RecordVal* rv = args->AsRecordVal()->CoerceTo( using BifType::Record::FileAnalysis::ActionArgs;
BifType::Record::FileAnalysis::ActionArgs); RecordVal* rv = args->AsRecordVal()->CoerceTo(ActionArgs);
bool result = file_mgr->AddAction(FileID(file_id->CheckString()), bool result = file_mgr->AddAction(FileID(file_id->CheckString()),
action->AsEnumVal(), rv); action->AsEnumVal(), rv);
Unref(rv); Unref(rv);
@ -86,7 +87,7 @@ function FileAnalysis::add_action%(file_id: string,
function FileAnalysis::remove_action%(file_id: string, function FileAnalysis::remove_action%(file_id: string,
action: FileAnalysis::Action%): bool action: FileAnalysis::Action%): bool
%{ %{
using namespace file_analysis; using file_analysis::FileID;
bool result = file_mgr->RemoveAction(FileID(file_id->CheckString()), bool result = file_mgr->RemoveAction(FileID(file_id->CheckString()),
action->AsEnumVal()); action->AsEnumVal());
return new Val(result, TYPE_BOOL); return new Val(result, TYPE_BOOL);
@ -94,7 +95,7 @@ function FileAnalysis::remove_action%(file_id: string,
function FileAnalysis::stop%(file_id: string%): bool function FileAnalysis::stop%(file_id: string%): bool
%{ %{
using namespace file_analysis; using file_analysis::FileID;
bool result = file_mgr->RemoveFile(FileID(file_id->CheckString())); bool result = file_mgr->RemoveFile(FileID(file_id->CheckString()));
return new Val(result, TYPE_BOOL); return new Val(result, TYPE_BOOL);
%} %}

View file

@ -0,0 +1,69 @@
#include <string>
#include "DataEvent.h"
#include "EventRegistry.h"
#include "Event.h"
#include "util.h"
using namespace file_analysis;
DataEvent::DataEvent(Info* arg_info, EventHandlerPtr ce, EventHandlerPtr se)
: Action(arg_info, BifEnum::FileAnalysis::ACTION_DATA_EVENT),
chunk_event(ce), stream_event(se)
{
}
Action* DataEvent::Instantiate(const RecordVal* args, Info* info)
{
using BifType::Record::FileAnalysis::ActionArgs;
const char* chunk_field = "chunk_event";
const char* stream_field = "stream_event";
int chunk_off = ActionArgs->FieldOffset(chunk_field);
int stream_off = ActionArgs->FieldOffset(stream_field);
Val* chunk_val = args->Lookup(chunk_off);
Val* stream_val = args->Lookup(stream_off);
if ( ! chunk_val && ! stream_val ) return 0;
EventHandlerPtr chunk;
EventHandlerPtr stream;
if ( chunk_val )
chunk = event_registry->Lookup(chunk_val->AsFunc()->GetID()->Name());
if ( stream_val )
stream = event_registry->Lookup(stream_val->AsFunc()->GetID()->Name());
return new DataEvent(info, chunk, stream);
}
bool DataEvent::DeliverChunk(const u_char* data, uint64 len, uint64 offset)
{
Action::DeliverChunk(data, len, offset);
if ( ! chunk_event ) return true;
val_list* args = new val_list;
args->append(info->GetVal()->Ref());
args->append(new StringVal(new BroString(data, len, 0)));
args->append(new Val(offset, TYPE_COUNT));
mgr.QueueEvent(chunk_event, args);
return true;
}
bool DataEvent::DeliverStream(const u_char* data, uint64 len)
{
Action::DeliverStream(data, len);
if ( ! stream_event ) return true;
val_list* args = new val_list;
args->append(info->GetVal()->Ref());
args->append(new StringVal(new BroString(data, len, 0)));
mgr.QueueEvent(stream_event, args);
return true;
}

View file

@ -0,0 +1,34 @@
#ifndef FILE_ANALYSIS_DATAEVENT_H
#define FILE_ANALYSIS_DATAEVENT_H
#include <string>
#include "Val.h"
#include "Info.h"
#include "Action.h"
namespace file_analysis {
/**
* An action to send file data to script-layer events.
*/
class DataEvent : public Action {
public:
static Action* Instantiate(const RecordVal* args, Info* info);
virtual bool DeliverChunk(const u_char* data, uint64 len, uint64 offset);
virtual bool DeliverStream(const u_char* data, uint64 len);
protected:
DataEvent(Info* arg_info, EventHandlerPtr ce, EventHandlerPtr se);
EventHandlerPtr chunk_event;
EventHandlerPtr stream_event;
};
} // namespace file_analysis
#endif

View file

@ -50,5 +50,5 @@ void Hash::Finalize()
if ( i < 0 ) if ( i < 0 )
reporter->InternalError("Hash Action result field not found"); reporter->InternalError("Hash Action result field not found");
info->Results()->Assign(i, sv); info->GetResults()->Assign(i, sv);
} }

View file

@ -9,6 +9,7 @@
#include "Action.h" #include "Action.h"
#include "Extract.h" #include "Extract.h"
#include "Hash.h" #include "Hash.h"
#include "DataEvent.h"
using namespace file_analysis; using namespace file_analysis;
@ -18,6 +19,7 @@ static ActionInstantiator action_factory[] = {
MD5::Instantiate, MD5::Instantiate,
SHA1::Instantiate, SHA1::Instantiate,
SHA256::Instantiate, SHA256::Instantiate,
DataEvent::Instantiate,
}; };
static TableVal* empty_conn_id_set() static TableVal* empty_conn_id_set()
@ -150,12 +152,12 @@ int Info::Idx(const string& field)
return rval; return rval;
} }
double Info::TimeoutInterval() const double Info::GetTimeoutInterval() const
{ {
return LookupFieldDefaultInterval(timeout_interval_idx); return LookupFieldDefaultInterval(timeout_interval_idx);
} }
RecordVal* Info::Results() const RecordVal* Info::GetResults() const
{ {
return val->Lookup(action_results_idx)->AsRecordVal(); return val->Lookup(action_results_idx)->AsRecordVal();
} }
@ -182,7 +184,7 @@ bool Info::IsComplete() const
void Info::ScheduleInactivityTimer() const void Info::ScheduleInactivityTimer() const
{ {
timer_mgr->Add(new InfoTimer(network_time, file_id, TimeoutInterval())); timer_mgr->Add(new InfoTimer(network_time, file_id, GetTimeoutInterval()));
} }
bool Info::AddAction(ActionTag act, RecordVal* args) bool Info::AddAction(ActionTag act, RecordVal* args)

View file

@ -19,10 +19,15 @@ public:
~Info(); ~Info();
/**
* @return the #val record.
*/
RecordVal* GetVal() const { return val; }
/** /**
* @return value (seconds) of the "timeout_interval" field from #val record. * @return value (seconds) of the "timeout_interval" field from #val record.
*/ */
double TimeoutInterval() const; double GetTimeoutInterval() const;
/** /**
* @return value of the "file_id" field from #val record. * @return value of the "file_id" field from #val record.
@ -32,17 +37,17 @@ public:
/** /**
* @return record val of the "action_results" field from #val record. * @return record val of the "action_results" field from #val record.
*/ */
RecordVal* Results() const; RecordVal* GetResults() const;
/** /**
* @return the string which uniquely identifies the file. * @return the string which uniquely identifies the file.
*/ */
string Unique() const { return unique; } string GetUnique() const { return unique; }
/** /**
* @return #last_activity_time * @return #last_activity_time
*/ */
double LastActivityTime() const { return last_activity_time; } double GetLastActivityTime() const { return last_activity_time; }
/** /**
* Refreshes #last_activity_time with current network time. * Refreshes #last_activity_time with current network time.

View file

@ -9,7 +9,7 @@ void InfoTimer::Dispatch(double t, int is_expire)
if ( ! info ) return; if ( ! info ) return;
double last_active = info->LastActivityTime(); double last_active = info->GetLastActivityTime();
double inactive_time = t > last_active ? t - last_active : 0.0; double inactive_time = t > last_active ? t - last_active : 0.0;
DBG_LOG(DBG_FILE_ANALYSIS, "Checking inactivity for %s, last active at %f, " DBG_LOG(DBG_FILE_ANALYSIS, "Checking inactivity for %s, last active at %f, "
@ -23,7 +23,7 @@ void InfoTimer::Dispatch(double t, int is_expire)
return; return;
} }
if ( inactive_time >= info->TimeoutInterval() ) if ( inactive_time >= info->GetTimeoutInterval() )
file_mgr->Timeout(file_id); file_mgr->Timeout(file_id);
else if ( ! is_expire ) else if ( ! is_expire )
info->ScheduleInactivityTimer(); info->ScheduleInactivityTimer();

View file

@ -185,7 +185,7 @@ bool Manager::RemoveFile(const FileID& file_id)
if ( it == id_map.end() ) return false; if ( it == id_map.end() ) return false;
if ( ! str_map.erase(it->second->Unique()) ) if ( ! str_map.erase(it->second->GetUnique()) )
reporter->Error("No string mapping for file ID %s", file_id.c_str()); reporter->Error("No string mapping for file ID %s", file_id.c_str());
delete it->second; delete it->second;
id_map.erase(it); id_map.erase(it);