mirror of
https://github.com/zeek/zeek.git
synced 2025-10-04 15:48:19 +00:00
Add file analysis action to send data to script-land in chosen events.
This commit is contained in:
parent
85410a7657
commit
4b30cc2e24
10 changed files with 134 additions and 17 deletions
|
@ -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 {
|
||||||
|
|
|
@ -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
|
||||||
|
|
|
@ -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);
|
||||||
%}
|
%}
|
||||||
|
|
69
src/file_analysis/DataEvent.cc
Normal file
69
src/file_analysis/DataEvent.cc
Normal 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;
|
||||||
|
}
|
34
src/file_analysis/DataEvent.h
Normal file
34
src/file_analysis/DataEvent.h
Normal 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
|
|
@ -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);
|
||||||
}
|
}
|
||||||
|
|
|
@ -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)
|
||||||
|
|
|
@ -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.
|
||||||
|
|
|
@ -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();
|
||||||
|
|
|
@ -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);
|
||||||
|
|
Loading…
Add table
Add a link
Reference in a new issue