mirror of
https://github.com/zeek/zeek.git
synced 2025-10-02 14:48:21 +00:00
FileAnalysis: insert explicit event queue flush points.
And added an event called "event_queue_flush_point" to mark where that occured in the event stream. The FAF now uses an explicit event queue flush instead of buffering input in order to wait for a file handle to be returned from script-layer.
This commit is contained in:
parent
d9321e2203
commit
2747e839fb
15 changed files with 128 additions and 382 deletions
|
@ -5,22 +5,21 @@
|
||||||
module FTP;
|
module FTP;
|
||||||
|
|
||||||
export {
|
export {
|
||||||
## Determines whether the default :bro:see:`get_file_handle` handler
|
|
||||||
## is used to return file handles to the file analysis framework.
|
|
||||||
## Redefine to true in order to provide a custom handler which overrides
|
|
||||||
## the default for FTP.
|
|
||||||
const disable_default_file_handle_provider: bool = F &redef;
|
|
||||||
|
|
||||||
## Default file handle provider for FTP.
|
## Default file handle provider for FTP.
|
||||||
function get_file_handle(c: connection, is_orig: bool): string
|
global get_file_handle: function(c: connection, is_orig: bool): string;
|
||||||
|
}
|
||||||
|
|
||||||
|
function get_handle_string(c: connection): string
|
||||||
|
{
|
||||||
|
return fmt("%s %s %s", ANALYZER_FTP_DATA, c$start_time, id_string(c$id));
|
||||||
|
}
|
||||||
|
|
||||||
|
function get_file_handle(c: connection, is_orig: bool): string
|
||||||
{
|
{
|
||||||
if ( [c$id$resp_h, c$id$resp_p] !in ftp_data_expected ) return "";
|
if ( [c$id$resp_h, c$id$resp_p] !in ftp_data_expected ) return "";
|
||||||
|
|
||||||
local info: FTP::Info = ftp_data_expected[c$id$resp_h, c$id$resp_p];
|
local info: FTP::Info = ftp_data_expected[c$id$resp_h, c$id$resp_p];
|
||||||
|
|
||||||
local rval = fmt("%s %s %s", ANALYZER_FTP_DATA, c$start_time,
|
|
||||||
id_string(c$id));
|
|
||||||
|
|
||||||
if ( info$passive )
|
if ( info$passive )
|
||||||
# FTP client initiates data channel.
|
# FTP client initiates data channel.
|
||||||
if ( is_orig )
|
if ( is_orig )
|
||||||
|
@ -28,23 +27,21 @@ export {
|
||||||
return "";
|
return "";
|
||||||
else
|
else
|
||||||
# Do care about FTP server data.
|
# Do care about FTP server data.
|
||||||
return rval;
|
return get_handle_string(c);
|
||||||
else
|
else
|
||||||
# FTP server initiates dta channel.
|
# FTP server initiates dta channel.
|
||||||
if ( is_orig )
|
if ( is_orig )
|
||||||
# Do care about FTP server data.
|
# Do care about FTP server data.
|
||||||
return rval;
|
return get_handle_string(c);
|
||||||
else
|
else
|
||||||
# Don't care about FTP client data.
|
# Don't care about FTP client data.
|
||||||
return "";
|
return "";
|
||||||
}
|
}
|
||||||
}
|
|
||||||
|
|
||||||
module GLOBAL;
|
module GLOBAL;
|
||||||
|
|
||||||
event get_file_handle(tag: AnalyzerTag, c: connection, is_orig: bool)
|
event get_file_handle(tag: AnalyzerTag, c: connection, is_orig: bool)
|
||||||
{
|
{
|
||||||
if ( tag != ANALYZER_FTP_DATA ) return;
|
if ( tag != ANALYZER_FTP_DATA ) return;
|
||||||
if ( FTP::disable_default_file_handle_provider ) return;
|
set_file_handle(FTP::get_file_handle(c, is_orig));
|
||||||
return_file_handle(FTP::get_file_handle(c, is_orig));
|
|
||||||
}
|
}
|
||||||
|
|
|
@ -6,14 +6,11 @@
|
||||||
module HTTP;
|
module HTTP;
|
||||||
|
|
||||||
export {
|
export {
|
||||||
## Determines whether the default :bro:see:`get_file_handle` handler
|
|
||||||
## is used to return file handles to the file analysis framework.
|
|
||||||
## Redefine to true in order to provide a custom handler which overrides
|
|
||||||
## the default HTTP.
|
|
||||||
const disable_default_file_handle_provider: bool = F &redef;
|
|
||||||
|
|
||||||
## Default file handle provider for HTTP.
|
## Default file handle provider for HTTP.
|
||||||
function get_file_handle(c: connection, is_orig: bool): string
|
global get_file_handle: function(c: connection, is_orig: bool): string;
|
||||||
|
}
|
||||||
|
|
||||||
|
function get_file_handle(c: connection, is_orig: bool): string
|
||||||
{
|
{
|
||||||
if ( ! c?$http ) return "";
|
if ( ! c?$http ) return "";
|
||||||
|
|
||||||
|
@ -24,13 +21,11 @@ export {
|
||||||
return fmt("%s %s %s %s %s", ANALYZER_HTTP, c$start_time, is_orig,
|
return fmt("%s %s %s %s %s", ANALYZER_HTTP, c$start_time, is_orig,
|
||||||
c$http$trans_depth, id_string(c$id));
|
c$http$trans_depth, id_string(c$id));
|
||||||
}
|
}
|
||||||
}
|
|
||||||
|
|
||||||
module GLOBAL;
|
module GLOBAL;
|
||||||
|
|
||||||
event get_file_handle(tag: AnalyzerTag, c: connection, is_orig: bool)
|
event get_file_handle(tag: AnalyzerTag, c: connection, is_orig: bool)
|
||||||
{
|
{
|
||||||
if ( tag != ANALYZER_HTTP ) return;
|
if ( tag != ANALYZER_HTTP ) return;
|
||||||
if ( HTTP::disable_default_file_handle_provider ) return;
|
set_file_handle(HTTP::get_file_handle(c, is_orig));
|
||||||
return_file_handle(HTTP::get_file_handle(c, is_orig));
|
|
||||||
}
|
}
|
||||||
|
|
|
@ -5,26 +5,20 @@
|
||||||
module IRC;
|
module IRC;
|
||||||
|
|
||||||
export {
|
export {
|
||||||
## Determines whether the default :bro:see:`get_file_handle` handler
|
|
||||||
## is used to return file handles to the file analysis framework.
|
|
||||||
## Redefine to true in order to provide a custom handler which overrides
|
|
||||||
## the default for IRC.
|
|
||||||
const disable_default_file_handle_provider: bool = F &redef;
|
|
||||||
|
|
||||||
## Default file handle provider for IRC.
|
## Default file handle provider for IRC.
|
||||||
function get_file_handle(c: connection, is_orig: bool): string
|
global get_file_handle: function(c: connection, is_orig: bool): string;
|
||||||
|
}
|
||||||
|
|
||||||
|
function get_file_handle(c: connection, is_orig: bool): string
|
||||||
{
|
{
|
||||||
if ( is_orig ) return "";
|
if ( is_orig ) return "";
|
||||||
return fmt("%s %s %s", ANALYZER_IRC_DATA, c$start_time,
|
return fmt("%s %s %s", ANALYZER_IRC_DATA, c$start_time, id_string(c$id));
|
||||||
id_string(c$id));
|
|
||||||
}
|
}
|
||||||
}
|
|
||||||
|
|
||||||
module GLOBAL;
|
module GLOBAL;
|
||||||
|
|
||||||
event get_file_handle(tag: AnalyzerTag, c: connection, is_orig: bool)
|
event get_file_handle(tag: AnalyzerTag, c: connection, is_orig: bool)
|
||||||
{
|
{
|
||||||
if ( tag != ANALYZER_IRC_DATA ) return;
|
if ( tag != ANALYZER_IRC_DATA ) return;
|
||||||
if ( IRC::disable_default_file_handle_provider ) return;
|
set_file_handle(IRC::get_file_handle(c, is_orig));
|
||||||
return_file_handle(IRC::get_file_handle(c, is_orig));
|
|
||||||
}
|
}
|
||||||
|
|
|
@ -6,27 +6,21 @@
|
||||||
module SMTP;
|
module SMTP;
|
||||||
|
|
||||||
export {
|
export {
|
||||||
## Determines whether the default :bro:see:`get_file_handle` handler
|
|
||||||
## is used to return file handles to the file analysis framework.
|
|
||||||
## Redefine to true in order to provide a custom handler which overrides
|
|
||||||
## the default for SMTP.
|
|
||||||
const disable_default_file_handle_provider: bool = F &redef;
|
|
||||||
|
|
||||||
## Default file handle provider for SMTP.
|
## Default file handle provider for SMTP.
|
||||||
function get_file_handle(c: connection, is_orig: bool): string
|
global get_file_handle: function(c: connection, is_orig: bool): string;
|
||||||
|
}
|
||||||
|
|
||||||
|
function get_file_handle(c: connection, is_orig: bool): string
|
||||||
{
|
{
|
||||||
if ( ! c?$smtp ) return "";
|
if ( ! c?$smtp ) return "";
|
||||||
|
|
||||||
return fmt("%s %s %s %s", ANALYZER_SMTP, c$start_time,
|
return fmt("%s %s %s %s", ANALYZER_SMTP, c$start_time,
|
||||||
c$smtp$trans_depth, c$smtp_state$mime_level);
|
c$smtp$trans_depth, c$smtp_state$mime_level);
|
||||||
}
|
}
|
||||||
}
|
|
||||||
|
|
||||||
module GLOBAL;
|
module GLOBAL;
|
||||||
|
|
||||||
event get_file_handle(tag: AnalyzerTag, c: connection, is_orig: bool)
|
event get_file_handle(tag: AnalyzerTag, c: connection, is_orig: bool)
|
||||||
{
|
{
|
||||||
if ( tag != ANALYZER_SMTP ) return;
|
if ( tag != ANALYZER_SMTP ) return;
|
||||||
if ( SMTP::disable_default_file_handle_provider ) return;
|
set_file_handle(SMTP::get_file_handle(c, is_orig));
|
||||||
return_file_handle(SMTP::get_file_handle(c, is_orig));
|
|
||||||
}
|
}
|
||||||
|
|
|
@ -452,7 +452,6 @@ set(bro_SRCS
|
||||||
file_analysis/Manager.cc
|
file_analysis/Manager.cc
|
||||||
file_analysis/File.cc
|
file_analysis/File.cc
|
||||||
file_analysis/FileTimer.cc
|
file_analysis/FileTimer.cc
|
||||||
file_analysis/PendingFile.cc
|
|
||||||
file_analysis/FileID.h
|
file_analysis/FileID.h
|
||||||
file_analysis/Action.h
|
file_analysis/Action.h
|
||||||
file_analysis/ActionSet.cc
|
file_analysis/ActionSet.cc
|
||||||
|
|
|
@ -6,7 +6,6 @@
|
||||||
#include "Func.h"
|
#include "Func.h"
|
||||||
#include "NetVar.h"
|
#include "NetVar.h"
|
||||||
#include "Trigger.h"
|
#include "Trigger.h"
|
||||||
#include "file_analysis/Manager.h"
|
|
||||||
|
|
||||||
EventMgr mgr;
|
EventMgr mgr;
|
||||||
|
|
||||||
|
@ -111,6 +110,9 @@ void EventMgr::Dispatch()
|
||||||
|
|
||||||
void EventMgr::Drain()
|
void EventMgr::Drain()
|
||||||
{
|
{
|
||||||
|
if ( event_queue_flush_point )
|
||||||
|
QueueEvent(event_queue_flush_point, new val_list());
|
||||||
|
|
||||||
SegmentProfiler(segment_logger, "draining-events");
|
SegmentProfiler(segment_logger, "draining-events");
|
||||||
|
|
||||||
draining = true;
|
draining = true;
|
||||||
|
@ -125,8 +127,6 @@ void EventMgr::Drain()
|
||||||
// processing, we ensure that it's done at a regular basis by checking
|
// processing, we ensure that it's done at a regular basis by checking
|
||||||
// them here.
|
// them here.
|
||||||
Trigger::EvaluatePending();
|
Trigger::EvaluatePending();
|
||||||
|
|
||||||
file_mgr->EventDrainDone();
|
|
||||||
}
|
}
|
||||||
|
|
||||||
void EventMgr::Describe(ODesc* d) const
|
void EventMgr::Describe(ODesc* d) const
|
||||||
|
|
|
@ -6981,12 +6981,15 @@ event reporter_error%(t: time, msg: string, location: string%) &error_handler;
|
||||||
## recursively for each ``@load``.
|
## recursively for each ``@load``.
|
||||||
event bro_script_loaded%(path: string, level: count%);
|
event bro_script_loaded%(path: string, level: count%);
|
||||||
|
|
||||||
|
## Marks a point in the event stream at which the event queue started flushing.
|
||||||
|
event event_queue_flush_point%(%);
|
||||||
|
|
||||||
## This event is handled to provide feedback to the file analysis framework
|
## This event is handled to provide feedback to the file analysis framework
|
||||||
## about how to identify the logical "file" to which some data/input
|
## about how to identify the logical "file" to which some data/input
|
||||||
## belongs. All incoming data to the framework is buffered, and depends
|
## belongs. All incoming data to the framework is buffered, and depends
|
||||||
## on a handler for this event to return a string value that uniquely
|
## on a handler for this event to return a string value that uniquely
|
||||||
## identifies a file. Among all handlers of this event, exactly one must
|
## identifies a file. Among all handlers of this event, the last one to
|
||||||
## call :bro:see:`return_file_handle`.
|
## call :bro:see:`set_file_handle` will "win".
|
||||||
##
|
##
|
||||||
## tag: The analyzer which is carrying the file data.
|
## tag: The analyzer which is carrying the file data.
|
||||||
##
|
##
|
||||||
|
@ -6994,7 +6997,7 @@ event bro_script_loaded%(path: string, level: count%);
|
||||||
##
|
##
|
||||||
## is_orig: The direction the file data is flowing over the connection.
|
## is_orig: The direction the file data is flowing over the connection.
|
||||||
##
|
##
|
||||||
## .. bro:see:: return_file_handle
|
## .. bro:see:: set_file_handle
|
||||||
event get_file_handle%(tag: count, c: connection, is_orig: bool%);
|
event get_file_handle%(tag: count, c: connection, is_orig: bool%);
|
||||||
|
|
||||||
# TODO: document
|
# TODO: document
|
||||||
|
|
|
@ -92,8 +92,8 @@ module GLOBAL;
|
||||||
## handle: A string that uniquely identifies a file.
|
## handle: A string that uniquely identifies a file.
|
||||||
##
|
##
|
||||||
## .. bro:see:: get_file_handle FileAnalysis::policy
|
## .. bro:see:: get_file_handle FileAnalysis::policy
|
||||||
function return_file_handle%(handle: string%): any
|
function set_file_handle%(handle: string%): any
|
||||||
%{
|
%{
|
||||||
file_mgr->ReceiveHandle(handle->CheckString());
|
file_mgr->SetHandle(handle->CheckString());
|
||||||
return 0;
|
return 0;
|
||||||
%}
|
%}
|
||||||
|
|
|
@ -47,7 +47,8 @@ bool DataEvent::DeliverChunk(const u_char* data, uint64 len, uint64 offset)
|
||||||
args->append(file->GetVal()->Ref());
|
args->append(file->GetVal()->Ref());
|
||||||
args->append(new StringVal(new BroString(data, len, 0)));
|
args->append(new StringVal(new BroString(data, len, 0)));
|
||||||
args->append(new Val(offset, TYPE_COUNT));
|
args->append(new Val(offset, TYPE_COUNT));
|
||||||
mgr.Dispatch(new Event(chunk_event, args));
|
|
||||||
|
mgr.QueueEvent(chunk_event, args);
|
||||||
|
|
||||||
return true;
|
return true;
|
||||||
}
|
}
|
||||||
|
@ -59,7 +60,8 @@ bool DataEvent::DeliverStream(const u_char* data, uint64 len)
|
||||||
val_list* args = new val_list;
|
val_list* args = new val_list;
|
||||||
args->append(file->GetVal()->Ref());
|
args->append(file->GetVal()->Ref());
|
||||||
args->append(new StringVal(new BroString(data, len, 0)));
|
args->append(new StringVal(new BroString(data, len, 0)));
|
||||||
mgr.Dispatch(new Event(stream_event, args));
|
|
||||||
|
mgr.QueueEvent(stream_event, args);
|
||||||
|
|
||||||
return true;
|
return true;
|
||||||
}
|
}
|
||||||
|
|
|
@ -267,7 +267,7 @@ void File::ReplayBOF()
|
||||||
DetectTypes(bs->Bytes(), bs->Len());
|
DetectTypes(bs->Bytes(), bs->Len());
|
||||||
|
|
||||||
file_mgr->FileEvent(file_new, this);
|
file_mgr->FileEvent(file_new, this);
|
||||||
//mgr.Drain();
|
mgr.Drain(); // need immediate feedback about actions to add
|
||||||
|
|
||||||
for ( size_t i = 0; i < bof_buffer.chunks.size(); ++i )
|
for ( size_t i = 0; i < bof_buffer.chunks.size(); ++i )
|
||||||
DataIn(bof_buffer.chunks[i]->Bytes(), bof_buffer.chunks[i]->Len());
|
DataIn(bof_buffer.chunks[i]->Bytes(), bof_buffer.chunks[i]->Len());
|
||||||
|
@ -282,7 +282,7 @@ void File::DataIn(const u_char* data, uint64 len, uint64 offset)
|
||||||
// TODO: this should all really be delayed until we attempt reassembly
|
// TODO: this should all really be delayed until we attempt reassembly
|
||||||
DetectTypes(data, len);
|
DetectTypes(data, len);
|
||||||
file_mgr->FileEvent(file_new, this);
|
file_mgr->FileEvent(file_new, this);
|
||||||
//mgr.Drain();
|
mgr.Drain(); // need immediate feedback about actions to add
|
||||||
actions.DrainModifications();
|
actions.DrainModifications();
|
||||||
first_chunk = false;
|
first_chunk = false;
|
||||||
}
|
}
|
||||||
|
@ -319,7 +319,7 @@ void File::DataIn(const u_char* data, uint64 len)
|
||||||
{
|
{
|
||||||
DetectTypes(data, len);
|
DetectTypes(data, len);
|
||||||
file_mgr->FileEvent(file_new, this);
|
file_mgr->FileEvent(file_new, this);
|
||||||
//mgr.Drain();
|
mgr.Drain(); // need immediate feedback about actions to add
|
||||||
actions.DrainModifications();
|
actions.DrainModifications();
|
||||||
missed_bof = false;
|
missed_bof = false;
|
||||||
}
|
}
|
||||||
|
|
|
@ -48,5 +48,5 @@ void Hash::Finalize()
|
||||||
vl->append(new StringVal(kind));
|
vl->append(new StringVal(kind));
|
||||||
vl->append(hash->Get());
|
vl->append(hash->Get());
|
||||||
|
|
||||||
mgr.Dispatch(new Event(file_hash, vl));
|
mgr.QueueEvent(file_hash, vl);
|
||||||
}
|
}
|
||||||
|
|
|
@ -29,38 +29,18 @@ void Manager::Terminate()
|
||||||
Timeout(keys[i], true);
|
Timeout(keys[i], true);
|
||||||
}
|
}
|
||||||
|
|
||||||
void Manager::ReceiveHandle(const string& handle)
|
void Manager::SetHandle(const string& handle)
|
||||||
{
|
{
|
||||||
if ( pending.empty() )
|
current_handle = handle;
|
||||||
reporter->InternalError("File analysis underflow");
|
|
||||||
|
|
||||||
PendingFile* pf = pending.front();
|
|
||||||
if ( ! handle.empty() )
|
|
||||||
pf->Finish(handle);
|
|
||||||
delete pf;
|
|
||||||
pending.pop();
|
|
||||||
}
|
|
||||||
|
|
||||||
void Manager::EventDrainDone()
|
|
||||||
{
|
|
||||||
if ( pending.empty() ) return;
|
|
||||||
|
|
||||||
reporter->Error("Too few return_file_handle() calls, discarding pending"
|
|
||||||
" file analysis input.");
|
|
||||||
|
|
||||||
while ( ! pending.empty() )
|
|
||||||
{
|
|
||||||
delete pending.front();
|
|
||||||
pending.pop();
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
||||||
void Manager::DataIn(const u_char* data, uint64 len, uint64 offset,
|
void Manager::DataIn(const u_char* data, uint64 len, uint64 offset,
|
||||||
AnalyzerTag::Tag tag, Connection* conn, bool is_orig)
|
AnalyzerTag::Tag tag, Connection* conn, bool is_orig)
|
||||||
{
|
{
|
||||||
if ( IsDisabled(tag) ) return;
|
if ( IsDisabled(tag) ) return;
|
||||||
if ( ! QueueHandleEvent(tag, conn, is_orig) ) return;
|
|
||||||
pending.push(new PendingDataInChunk(data, len, offset, tag, conn));
|
GetFileHandle(tag, conn, is_orig);
|
||||||
|
DataIn(data, len, offset, GetFile(current_handle, conn, tag));
|
||||||
}
|
}
|
||||||
|
|
||||||
void Manager::DataIn(const u_char* data, uint64 len, uint64 offset,
|
void Manager::DataIn(const u_char* data, uint64 len, uint64 offset,
|
||||||
|
@ -84,8 +64,8 @@ void Manager::DataIn(const u_char* data, uint64 len, AnalyzerTag::Tag tag,
|
||||||
Connection* conn, bool is_orig)
|
Connection* conn, bool is_orig)
|
||||||
{
|
{
|
||||||
if ( IsDisabled(tag) ) return;
|
if ( IsDisabled(tag) ) return;
|
||||||
if ( ! QueueHandleEvent(tag, conn, is_orig) ) return;
|
GetFileHandle(tag, conn, is_orig);
|
||||||
pending.push(new PendingDataInStream(data, len, tag, conn));
|
DataIn(data, len, GetFile(current_handle, conn, tag));
|
||||||
}
|
}
|
||||||
|
|
||||||
void Manager::DataIn(const u_char* data, uint64 len, const string& unique)
|
void Manager::DataIn(const u_char* data, uint64 len, const string& unique)
|
||||||
|
@ -112,8 +92,9 @@ void Manager::EndOfFile(AnalyzerTag::Tag tag, Connection* conn)
|
||||||
void Manager::EndOfFile(AnalyzerTag::Tag tag, Connection* conn, bool is_orig)
|
void Manager::EndOfFile(AnalyzerTag::Tag tag, Connection* conn, bool is_orig)
|
||||||
{
|
{
|
||||||
if ( IsDisabled(tag) ) return;
|
if ( IsDisabled(tag) ) return;
|
||||||
if ( ! QueueHandleEvent(tag, conn, is_orig) ) return;
|
|
||||||
pending.push(new PendingEOF(tag, conn));
|
GetFileHandle(tag, conn, is_orig);
|
||||||
|
EndOfFile(current_handle);
|
||||||
}
|
}
|
||||||
|
|
||||||
void Manager::EndOfFile(const string& unique)
|
void Manager::EndOfFile(const string& unique)
|
||||||
|
@ -125,8 +106,9 @@ void Manager::Gap(uint64 offset, uint64 len, AnalyzerTag::Tag tag,
|
||||||
Connection* conn, bool is_orig)
|
Connection* conn, bool is_orig)
|
||||||
{
|
{
|
||||||
if ( IsDisabled(tag) ) return;
|
if ( IsDisabled(tag) ) return;
|
||||||
if ( ! QueueHandleEvent(tag, conn, is_orig) ) return;
|
|
||||||
pending.push(new PendingGap(offset, len, tag, conn));
|
GetFileHandle(tag, conn, is_orig);
|
||||||
|
Gap(offset, len, GetFile(current_handle, conn, tag));
|
||||||
}
|
}
|
||||||
|
|
||||||
void Manager::Gap(uint64 offset, uint64 len, const string& unique)
|
void Manager::Gap(uint64 offset, uint64 len, const string& unique)
|
||||||
|
@ -145,8 +127,9 @@ void Manager::SetSize(uint64 size, AnalyzerTag::Tag tag, Connection* conn,
|
||||||
bool is_orig)
|
bool is_orig)
|
||||||
{
|
{
|
||||||
if ( IsDisabled(tag) ) return;
|
if ( IsDisabled(tag) ) return;
|
||||||
if ( ! QueueHandleEvent(tag, conn, is_orig) ) return;
|
|
||||||
pending.push(new PendingSize(size, tag, conn));
|
GetFileHandle(tag, conn, is_orig);
|
||||||
|
SetSize(size, GetFile(current_handle, conn, tag));
|
||||||
}
|
}
|
||||||
|
|
||||||
void Manager::SetSize(uint64 size, const string& unique)
|
void Manager::SetSize(uint64 size, const string& unique)
|
||||||
|
@ -166,12 +149,13 @@ void Manager::SetSize(uint64 size, File* file)
|
||||||
|
|
||||||
void Manager::FileEvent(EventHandlerPtr h, File* file)
|
void Manager::FileEvent(EventHandlerPtr h, File* file)
|
||||||
{
|
{
|
||||||
if ( IsIgnored(file->GetUnique()) ) return;
|
|
||||||
if ( ! h ) return;
|
if ( ! h ) return;
|
||||||
|
if ( IsIgnored(file->GetUnique()) ) return;
|
||||||
|
|
||||||
val_list * vl = new val_list();
|
val_list * vl = new val_list();
|
||||||
vl->append(file->GetVal()->Ref());
|
vl->append(file->GetVal()->Ref());
|
||||||
mgr.Dispatch(new Event(h, vl));
|
|
||||||
|
mgr.QueueEvent(h, vl);
|
||||||
}
|
}
|
||||||
|
|
||||||
bool Manager::PostponeTimeout(const FileID& file_id) const
|
bool Manager::PostponeTimeout(const FileID& file_id) const
|
||||||
|
@ -205,6 +189,7 @@ bool Manager::RemoveAction(const FileID& file_id, const RecordVal* args) const
|
||||||
File* Manager::GetFile(const string& unique, Connection* conn,
|
File* Manager::GetFile(const string& unique, Connection* conn,
|
||||||
AnalyzerTag::Tag tag)
|
AnalyzerTag::Tag tag)
|
||||||
{
|
{
|
||||||
|
if ( unique.empty() ) return 0;
|
||||||
if ( IsIgnored(unique) ) return 0;
|
if ( IsIgnored(unique) ) return 0;
|
||||||
|
|
||||||
File* rval = str_map[unique];
|
File* rval = str_map[unique];
|
||||||
|
@ -251,6 +236,7 @@ void Manager::Timeout(const FileID& file_id, bool is_terminating)
|
||||||
file->postpone_timeout = false;
|
file->postpone_timeout = false;
|
||||||
|
|
||||||
FileEvent(file_timeout, file);
|
FileEvent(file_timeout, file);
|
||||||
|
mgr.Drain(); // need immediate feedback about whether to postpone
|
||||||
|
|
||||||
if ( file->postpone_timeout && ! is_terminating )
|
if ( file->postpone_timeout && ! is_terminating )
|
||||||
{
|
{
|
||||||
|
@ -306,6 +292,21 @@ bool Manager::IsIgnored(const string& unique)
|
||||||
return ignored.find(unique) != ignored.end();
|
return ignored.find(unique) != ignored.end();
|
||||||
}
|
}
|
||||||
|
|
||||||
|
void Manager::GetFileHandle(AnalyzerTag::Tag tag, Connection* c, bool is_orig)
|
||||||
|
{
|
||||||
|
current_handle.clear();
|
||||||
|
|
||||||
|
if ( ! get_file_handle ) return;
|
||||||
|
|
||||||
|
val_list* vl = new val_list();
|
||||||
|
vl->append(new Val(tag, TYPE_COUNT));
|
||||||
|
vl->append(c->BuildConnVal());
|
||||||
|
vl->append(new Val(is_orig, TYPE_BOOL));
|
||||||
|
|
||||||
|
mgr.QueueEvent(get_file_handle, vl);
|
||||||
|
mgr.Drain(); // need file handle immediately so we don't have to buffer data
|
||||||
|
}
|
||||||
|
|
||||||
bool Manager::IsDisabled(AnalyzerTag::Tag tag)
|
bool Manager::IsDisabled(AnalyzerTag::Tag tag)
|
||||||
{
|
{
|
||||||
if ( ! disabled )
|
if ( ! disabled )
|
||||||
|
@ -322,17 +323,3 @@ bool Manager::IsDisabled(AnalyzerTag::Tag tag)
|
||||||
|
|
||||||
return rval;
|
return rval;
|
||||||
}
|
}
|
||||||
|
|
||||||
bool Manager::QueueHandleEvent(AnalyzerTag::Tag tag, Connection* conn,
|
|
||||||
bool is_orig)
|
|
||||||
{
|
|
||||||
if ( ! get_file_handle ) return false;
|
|
||||||
|
|
||||||
val_list* vl = new val_list();
|
|
||||||
vl->append(new Val(tag, TYPE_COUNT));
|
|
||||||
vl->append(conn->BuildConnVal());
|
|
||||||
vl->append(new Val(is_orig, TYPE_BOOL));
|
|
||||||
|
|
||||||
mgr.QueueEvent(get_file_handle, vl);
|
|
||||||
return true;
|
|
||||||
}
|
|
||||||
|
|
|
@ -17,7 +17,6 @@
|
||||||
#include "File.h"
|
#include "File.h"
|
||||||
#include "FileTimer.h"
|
#include "FileTimer.h"
|
||||||
#include "FileID.h"
|
#include "FileID.h"
|
||||||
#include "PendingFile.h"
|
|
||||||
|
|
||||||
namespace file_analysis {
|
namespace file_analysis {
|
||||||
|
|
||||||
|
@ -26,7 +25,6 @@ namespace file_analysis {
|
||||||
*/
|
*/
|
||||||
class Manager {
|
class Manager {
|
||||||
friend class FileTimer;
|
friend class FileTimer;
|
||||||
friend class PendingFile;
|
|
||||||
|
|
||||||
public:
|
public:
|
||||||
|
|
||||||
|
@ -40,17 +38,9 @@ public:
|
||||||
void Terminate();
|
void Terminate();
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Associates a handle with the next element in the #pending queue, which
|
* Take in a unique file handle string to identifiy incoming file data.
|
||||||
* will immediately push that element all the way through the file analysis
|
|
||||||
* framework, possibly evaluating any policy hooks.
|
|
||||||
*/
|
*/
|
||||||
void ReceiveHandle(const string& handle);
|
void SetHandle(const string& handle);
|
||||||
|
|
||||||
/**
|
|
||||||
* Called when all events have been drained from the event queue.
|
|
||||||
* There should be no pending file input/data at this point.
|
|
||||||
*/
|
|
||||||
void EventDrainDone();
|
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Pass in non-sequential file data.
|
* Pass in non-sequential file data.
|
||||||
|
@ -121,7 +111,7 @@ public:
|
||||||
bool RemoveAction(const FileID& file_id, const RecordVal* args) const;
|
bool RemoveAction(const FileID& file_id, const RecordVal* args) const;
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Dispatches an event related to the file's life-cycle.
|
* Queues an event related to the file's life-cycle.
|
||||||
*/
|
*/
|
||||||
void FileEvent(EventHandlerPtr h, File* file);
|
void FileEvent(EventHandlerPtr h, File* file);
|
||||||
|
|
||||||
|
@ -130,7 +120,6 @@ protected:
|
||||||
typedef map<string, File*> StrMap;
|
typedef map<string, File*> StrMap;
|
||||||
typedef set<string> StrSet;
|
typedef set<string> StrSet;
|
||||||
typedef map<FileID, File*> IDMap;
|
typedef map<FileID, File*> IDMap;
|
||||||
typedef queue<PendingFile*> PendingQueue;
|
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* @return the File object mapped to \a unique or a null pointer if analysis
|
* @return the File object mapped to \a unique or a null pointer if analysis
|
||||||
|
@ -165,22 +154,22 @@ protected:
|
||||||
*/
|
*/
|
||||||
bool IsIgnored(const string& unique);
|
bool IsIgnored(const string& unique);
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Sets #current_handle to a unique file handle string based on what the
|
||||||
|
* \c get_file_handle event derives from the connection params. The
|
||||||
|
* event queue is flushed so that we can get the handle value immediately.
|
||||||
|
*/
|
||||||
|
void GetFileHandle(AnalyzerTag::Tag tag, Connection* c, bool is_orig);
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* @return whether file analysis is disabled for the given analyzer.
|
* @return whether file analysis is disabled for the given analyzer.
|
||||||
*/
|
*/
|
||||||
static bool IsDisabled(AnalyzerTag::Tag tag);
|
static bool IsDisabled(AnalyzerTag::Tag tag);
|
||||||
|
|
||||||
/**
|
|
||||||
* Queues \c get_file_handle event in order to retrieve unique file handle.
|
|
||||||
* @return true if there is a handler for the event, else false.
|
|
||||||
*/
|
|
||||||
static bool QueueHandleEvent(AnalyzerTag::Tag tag, Connection* conn,
|
|
||||||
bool is_orig);
|
|
||||||
|
|
||||||
StrMap str_map; /**< Map unique string to file_analysis::File. */
|
StrMap str_map; /**< Map unique string to file_analysis::File. */
|
||||||
IDMap id_map; /**< Map file ID to file_analysis::File records. */
|
IDMap id_map; /**< Map file ID to file_analysis::File records. */
|
||||||
StrSet ignored; /**< Ignored files. Will be finally removed on EOF. */
|
StrSet ignored; /**< Ignored files. Will be finally removed on EOF. */
|
||||||
PendingQueue pending; /**< Files awaiting a unique handle. */
|
string current_handle; /**< Last file handle set by get_file_handle event.*/
|
||||||
|
|
||||||
static TableVal* disabled; /**< Table of disabled analyzers. */
|
static TableVal* disabled; /**< Table of disabled analyzers. */
|
||||||
};
|
};
|
||||||
|
|
|
@ -1,111 +0,0 @@
|
||||||
#include "PendingFile.h"
|
|
||||||
#include "Manager.h"
|
|
||||||
|
|
||||||
using namespace file_analysis;
|
|
||||||
|
|
||||||
static void copy_data(const u_char** dst, const u_char* src, uint64 len)
|
|
||||||
{
|
|
||||||
u_char* tmp = new u_char[len];
|
|
||||||
memcpy(tmp, src, len);
|
|
||||||
*dst = tmp;
|
|
||||||
}
|
|
||||||
|
|
||||||
static string conn_str(Connection* c)
|
|
||||||
{
|
|
||||||
char op[256], rp[256];
|
|
||||||
modp_ulitoa10(ntohs(c->OrigPort()), op);
|
|
||||||
modp_ulitoa10(ntohs(c->RespPort()), rp);
|
|
||||||
string rval = c->OrigAddr().AsString() + ":" + op + "->" +
|
|
||||||
c->RespAddr().AsString() + ":" + rp;
|
|
||||||
return rval;
|
|
||||||
}
|
|
||||||
|
|
||||||
PendingFile::PendingFile(Connection* arg_conn, AnalyzerTag::Tag arg_tag)
|
|
||||||
: conn(arg_conn), tag(arg_tag)
|
|
||||||
{
|
|
||||||
Ref(conn);
|
|
||||||
DBG_LOG(DBG_FILE_ANALYSIS, "New pending file: %s", conn_str(conn).c_str());
|
|
||||||
}
|
|
||||||
|
|
||||||
PendingFile::~PendingFile()
|
|
||||||
{
|
|
||||||
Unref(conn);
|
|
||||||
DBG_LOG(DBG_FILE_ANALYSIS, "Delete pending file: %s",
|
|
||||||
conn_str(conn).c_str());
|
|
||||||
}
|
|
||||||
|
|
||||||
File* PendingFile::GetFile(const string& handle) const
|
|
||||||
{
|
|
||||||
return file_mgr->GetFile(handle, conn, tag);
|
|
||||||
}
|
|
||||||
|
|
||||||
PendingDataInChunk::PendingDataInChunk(const u_char* arg_data, uint64 arg_len,
|
|
||||||
uint64 arg_offset,
|
|
||||||
AnalyzerTag::Tag arg_tag,
|
|
||||||
Connection* arg_conn)
|
|
||||||
: PendingFile(arg_conn, arg_tag), len(arg_len),
|
|
||||||
offset(arg_offset)
|
|
||||||
{
|
|
||||||
copy_data(&data, arg_data, len);
|
|
||||||
}
|
|
||||||
|
|
||||||
void PendingDataInChunk::Finish(const string& handle) const
|
|
||||||
{
|
|
||||||
file_mgr->DataIn(data, len, offset, GetFile(handle));
|
|
||||||
}
|
|
||||||
|
|
||||||
PendingDataInChunk::~PendingDataInChunk()
|
|
||||||
{
|
|
||||||
delete [] data;
|
|
||||||
}
|
|
||||||
|
|
||||||
PendingDataInStream::PendingDataInStream(const u_char* arg_data, uint64 arg_len,
|
|
||||||
AnalyzerTag::Tag arg_tag,
|
|
||||||
Connection* arg_conn)
|
|
||||||
: PendingFile(arg_conn, arg_tag), len(arg_len)
|
|
||||||
{
|
|
||||||
copy_data(&data, arg_data, len);
|
|
||||||
}
|
|
||||||
|
|
||||||
void PendingDataInStream::Finish(const string& handle) const
|
|
||||||
{
|
|
||||||
file_mgr->DataIn(data, len, GetFile(handle));
|
|
||||||
}
|
|
||||||
|
|
||||||
PendingDataInStream::~PendingDataInStream()
|
|
||||||
{
|
|
||||||
delete [] data;
|
|
||||||
}
|
|
||||||
|
|
||||||
PendingGap::PendingGap(uint64 arg_offset, uint64 arg_len,
|
|
||||||
AnalyzerTag::Tag arg_tag, Connection* arg_conn)
|
|
||||||
: PendingFile(arg_conn, arg_tag), offset(arg_offset),
|
|
||||||
len(arg_len)
|
|
||||||
{
|
|
||||||
}
|
|
||||||
|
|
||||||
void PendingGap::Finish(const string& handle) const
|
|
||||||
{
|
|
||||||
file_mgr->Gap(offset, len, GetFile(handle));
|
|
||||||
}
|
|
||||||
|
|
||||||
PendingEOF::PendingEOF(AnalyzerTag::Tag arg_tag, Connection* arg_conn)
|
|
||||||
: PendingFile(arg_conn, arg_tag)
|
|
||||||
{
|
|
||||||
}
|
|
||||||
|
|
||||||
void PendingEOF::Finish(const string& handle) const
|
|
||||||
{
|
|
||||||
file_mgr->EndOfFile(handle);
|
|
||||||
}
|
|
||||||
|
|
||||||
PendingSize::PendingSize(uint64 arg_size, AnalyzerTag::Tag arg_tag,
|
|
||||||
Connection* arg_conn)
|
|
||||||
: PendingFile(arg_conn, arg_tag), size(arg_size)
|
|
||||||
{
|
|
||||||
}
|
|
||||||
|
|
||||||
void PendingSize::Finish(const string& handle) const
|
|
||||||
{
|
|
||||||
file_mgr->SetSize(size, GetFile(handle));
|
|
||||||
}
|
|
|
@ -1,103 +0,0 @@
|
||||||
#ifndef FILE_ANALYSIS_PENDINGFILE_H
|
|
||||||
#define FILE_ANALYSIS_PENDINGFILE_H
|
|
||||||
|
|
||||||
#include "AnalyzerTags.h"
|
|
||||||
#include "Conn.h"
|
|
||||||
#include "File.h"
|
|
||||||
|
|
||||||
namespace file_analysis {
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Provides buffering for file contents until the script-layer is able to
|
|
||||||
* return a unique file handle for it.
|
|
||||||
*/
|
|
||||||
class PendingFile {
|
|
||||||
public:
|
|
||||||
|
|
||||||
virtual ~PendingFile();
|
|
||||||
|
|
||||||
virtual void Finish(const string& handle) const = 0;
|
|
||||||
|
|
||||||
protected:
|
|
||||||
|
|
||||||
PendingFile(Connection* arg_conn,
|
|
||||||
AnalyzerTag::Tag arg_tag = AnalyzerTag::Error);
|
|
||||||
|
|
||||||
File* GetFile(const string& handle) const;
|
|
||||||
|
|
||||||
Connection* conn;
|
|
||||||
AnalyzerTag::Tag tag;
|
|
||||||
};
|
|
||||||
|
|
||||||
class PendingDataInChunk : public PendingFile {
|
|
||||||
public:
|
|
||||||
|
|
||||||
PendingDataInChunk(const u_char* arg_data, uint64 arg_len,
|
|
||||||
uint64 arg_offset, AnalyzerTag::Tag arg_tag,
|
|
||||||
Connection* arg_conn);
|
|
||||||
|
|
||||||
virtual ~PendingDataInChunk();
|
|
||||||
|
|
||||||
virtual void Finish(const string& handle) const;
|
|
||||||
|
|
||||||
protected:
|
|
||||||
|
|
||||||
const u_char* data;
|
|
||||||
uint64 len;
|
|
||||||
uint64 offset;
|
|
||||||
};
|
|
||||||
|
|
||||||
class PendingDataInStream : public PendingFile {
|
|
||||||
public:
|
|
||||||
|
|
||||||
PendingDataInStream(const u_char* arg_data, uint64 arg_len,
|
|
||||||
AnalyzerTag::Tag arg_tag, Connection* arg_conn);
|
|
||||||
|
|
||||||
virtual ~PendingDataInStream();
|
|
||||||
|
|
||||||
virtual void Finish(const string& handle) const;
|
|
||||||
|
|
||||||
protected:
|
|
||||||
|
|
||||||
const u_char* data;
|
|
||||||
uint64 len;
|
|
||||||
};
|
|
||||||
|
|
||||||
class PendingGap : public PendingFile {
|
|
||||||
public:
|
|
||||||
|
|
||||||
PendingGap(uint64 arg_offset, uint64 arg_len, AnalyzerTag::Tag arg_tag,
|
|
||||||
Connection* arg_conn);
|
|
||||||
|
|
||||||
virtual void Finish(const string& handle) const;
|
|
||||||
|
|
||||||
protected:
|
|
||||||
|
|
||||||
uint64 offset;
|
|
||||||
uint64 len;
|
|
||||||
};
|
|
||||||
|
|
||||||
class PendingEOF : public PendingFile {
|
|
||||||
public:
|
|
||||||
|
|
||||||
PendingEOF(AnalyzerTag::Tag arg_tag, Connection* arg_conn);
|
|
||||||
|
|
||||||
virtual void Finish(const string& handle) const;
|
|
||||||
};
|
|
||||||
|
|
||||||
class PendingSize : public PendingFile {
|
|
||||||
public:
|
|
||||||
|
|
||||||
PendingSize(uint64 arg_size, AnalyzerTag::Tag arg_tag,
|
|
||||||
Connection* arg_conn);
|
|
||||||
|
|
||||||
virtual void Finish(const string& handle) const;
|
|
||||||
|
|
||||||
protected:
|
|
||||||
|
|
||||||
uint64 size;
|
|
||||||
};
|
|
||||||
|
|
||||||
} // namespace file_analysis
|
|
||||||
|
|
||||||
#endif
|
|
Loading…
Add table
Add a link
Reference in a new issue