mirror of
https://github.com/zeek/zeek.git
synced 2025-10-02 14:48:21 +00:00
Add new hook HookLoadFileExtended
that allows plugins to supply Zeek script code to parse.
The new hooks works similar to the existing `HookLoadFile` but, additionally, allows the plugin to return a string that contains the code to be used for the file being loaded. If the plugin does so, the content of any actual file on disk will be ignored (in fact, there doesn't even need to be a file on disk in that case). This works for both Zeek scripts and signatures. There's a new test that covers the new functionality, testing loading both scripts and signatures from memory. I also manually tested that the debugger integration works, but I don't see much of a way to add a regression test for that part. We keep the existing hook as well for backwards compatibility. We could decide to deprecate it, but not sure that buys us much, so left that out. Closes #1757.
This commit is contained in:
parent
1efaf8d7a4
commit
34eaf42b92
21 changed files with 1525 additions and 92 deletions
|
@ -72,49 +72,60 @@ int how_many_lines_in(const char* policy_filename)
|
|||
return pf->lines.size();
|
||||
}
|
||||
|
||||
bool LoadPolicyFileText(const char* policy_filename)
|
||||
bool LoadPolicyFileText(const char* policy_filename,
|
||||
const std::optional<std::string>& preloaded_content)
|
||||
{
|
||||
if ( ! policy_filename )
|
||||
return true;
|
||||
|
||||
FILE* f = fopen(policy_filename, "r");
|
||||
|
||||
if ( ! f )
|
||||
{
|
||||
debug_msg("No such policy file: %s.\n", policy_filename);
|
||||
return false;
|
||||
}
|
||||
|
||||
PolicyFile* pf = new PolicyFile;
|
||||
|
||||
if ( policy_files.find(policy_filename) != policy_files.end() )
|
||||
debug_msg("Policy file %s already loaded\n", policy_filename);
|
||||
|
||||
PolicyFile* pf = new PolicyFile;
|
||||
policy_files.insert(PolicyFileMap::value_type(policy_filename, pf));
|
||||
|
||||
struct stat st;
|
||||
if ( fstat(fileno(f), &st) != 0 )
|
||||
if ( preloaded_content )
|
||||
{
|
||||
char buf[256];
|
||||
util::zeek_strerror_r(errno, buf, sizeof(buf));
|
||||
reporter->Error("fstat failed on %s: %s", policy_filename, buf);
|
||||
fclose(f);
|
||||
return false;
|
||||
auto size = preloaded_content->size();
|
||||
pf->filedata = new char[size + 1];
|
||||
memcpy(pf->filedata, preloaded_content->data(), size);
|
||||
pf->filedata[size] = '\0';
|
||||
}
|
||||
else
|
||||
{
|
||||
FILE* f = fopen(policy_filename, "r");
|
||||
|
||||
pf->lmtime = st.st_mtime;
|
||||
off_t size = st.st_size;
|
||||
if ( ! f )
|
||||
{
|
||||
debug_msg("No such policy file: %s.\n", policy_filename);
|
||||
return false;
|
||||
}
|
||||
|
||||
// ### This code is not necessarily Unicode safe!
|
||||
// (probably fine with UTF-8)
|
||||
pf->filedata = new char[size + 1];
|
||||
if ( fread(pf->filedata, size, 1, f) != 1 )
|
||||
reporter->InternalError("Failed to fread() file data");
|
||||
pf->filedata[size] = 0;
|
||||
fclose(f);
|
||||
struct stat st;
|
||||
if ( fstat(fileno(f), &st) != 0 )
|
||||
{
|
||||
char buf[256];
|
||||
util::zeek_strerror_r(errno, buf, sizeof(buf));
|
||||
reporter->Error("fstat failed on %s: %s", policy_filename, buf);
|
||||
fclose(f);
|
||||
return false;
|
||||
}
|
||||
|
||||
pf->lmtime = st.st_mtime;
|
||||
off_t size = st.st_size;
|
||||
|
||||
// ### This code is not necessarily Unicode safe!
|
||||
// (probably fine with UTF-8)
|
||||
pf->filedata = new char[size + 1];
|
||||
if ( fread(pf->filedata, size, 1, f) != 1 )
|
||||
reporter->InternalError("Failed to fread() file data");
|
||||
pf->filedata[size] = 0;
|
||||
fclose(f);
|
||||
}
|
||||
|
||||
// Separate the string by newlines.
|
||||
pf->lines.push_back(pf->filedata);
|
||||
|
||||
for ( char* iter = pf->filedata; *iter; ++iter )
|
||||
{
|
||||
if ( *iter == '\n' )
|
||||
|
|
|
@ -14,12 +14,16 @@
|
|||
// policy_filename arguments should be absolute or relative paths;
|
||||
// no expansion is done.
|
||||
|
||||
#include <optional>
|
||||
#include <string>
|
||||
|
||||
namespace zeek::detail
|
||||
{
|
||||
|
||||
int how_many_lines_in(const char* policy_filename);
|
||||
|
||||
bool LoadPolicyFileText(const char* policy_filename);
|
||||
bool LoadPolicyFileText(const char* policy_filename,
|
||||
const std::optional<std::string>& preloaded_content = {});
|
||||
|
||||
// start_line is 1-based (the intuitive way)
|
||||
bool PrintLines(const char* policy_filename, unsigned int start_line, unsigned int how_many_lines,
|
||||
|
|
|
@ -24,10 +24,14 @@
|
|||
#include "zeek/ZeekString.h"
|
||||
#include "zeek/analyzer/Analyzer.h"
|
||||
#include "zeek/module_util.h"
|
||||
#include "zeek/plugin/Manager.h"
|
||||
|
||||
using namespace std;
|
||||
|
||||
// Functions exposed by rule-scan.l
|
||||
extern void rules_set_input_from_buffer(const char* data, size_t size);
|
||||
extern void rules_set_input_from_file(FILE* f);
|
||||
extern void rules_parse_input();
|
||||
|
||||
namespace zeek::detail
|
||||
{
|
||||
|
||||
|
@ -262,11 +266,18 @@ bool RuleMatcher::ReadFiles(const std::vector<SignatureFile>& files)
|
|||
if ( ! f.full_path )
|
||||
f.full_path = util::find_file(f.file, util::zeek_path(), ".sig");
|
||||
|
||||
int rc = PLUGIN_HOOK_WITH_RESULT(
|
||||
std::pair<int, std::optional<std::string>> rc = {-1, std::nullopt};
|
||||
rc.first = PLUGIN_HOOK_WITH_RESULT(
|
||||
HOOK_LOAD_FILE, HookLoadFile(zeek::plugin::Plugin::SIGNATURES, f.file, *f.full_path),
|
||||
-1);
|
||||
|
||||
switch ( rc )
|
||||
if ( rc.first < 0 )
|
||||
rc = PLUGIN_HOOK_WITH_RESULT(
|
||||
HOOK_LOAD_FILE_EXT,
|
||||
HookLoadFileExtended(zeek::plugin::Plugin::SIGNATURES, f.file, *f.full_path),
|
||||
std::make_pair(-1, std::nullopt));
|
||||
|
||||
switch ( rc.first )
|
||||
{
|
||||
case -1:
|
||||
// No plugin in charge of this file.
|
||||
|
@ -287,26 +298,45 @@ bool RuleMatcher::ReadFiles(const std::vector<SignatureFile>& files)
|
|||
break;
|
||||
|
||||
case 1:
|
||||
// A plugin took care of it, just skip.
|
||||
continue;
|
||||
if ( ! rc.second )
|
||||
// A plugin took care of it, just skip.
|
||||
continue;
|
||||
|
||||
break;
|
||||
|
||||
default:
|
||||
assert(false);
|
||||
break;
|
||||
}
|
||||
|
||||
rules_in = util::open_file(*f.full_path);
|
||||
FILE* rules_in = nullptr;
|
||||
|
||||
if ( ! rules_in )
|
||||
if ( rc.first == 1 )
|
||||
{
|
||||
reporter->Error("Can't open signature file %s", f.file.c_str());
|
||||
return false;
|
||||
// Parse code provided by plugin.
|
||||
assert(rc.second);
|
||||
rules_set_input_from_buffer(rc.second->data(), rc.second->size());
|
||||
}
|
||||
else
|
||||
{
|
||||
// Parse from file.
|
||||
rules_in = util::open_file(*f.full_path);
|
||||
|
||||
if ( ! rules_in )
|
||||
{
|
||||
reporter->Error("Can't open signature file %s", f.file.c_str());
|
||||
return false;
|
||||
}
|
||||
|
||||
rules_set_input_from_file(rules_in);
|
||||
}
|
||||
|
||||
rules_line_number = 0;
|
||||
current_rule_file = f.full_path->c_str();
|
||||
rules_parse();
|
||||
fclose(rules_in);
|
||||
rules_parse_input();
|
||||
|
||||
if ( rules_in )
|
||||
fclose(rules_in);
|
||||
}
|
||||
|
||||
if ( parse_error )
|
||||
|
|
|
@ -12,6 +12,7 @@
|
|||
#include "zeek/RE.h"
|
||||
#include "zeek/Rule.h"
|
||||
#include "zeek/ScannedFile.h"
|
||||
#include "zeek/plugin/Manager.h"
|
||||
|
||||
//#define MATCHER_PRINT_STATS
|
||||
|
||||
|
@ -23,7 +24,6 @@ extern void rules_error(zeek::detail::Rule* id, const char* msg);
|
|||
extern int rules_lex(void);
|
||||
extern int rules_parse(void);
|
||||
extern "C" int rules_wrap(void);
|
||||
extern FILE* rules_in;
|
||||
extern int rules_line_number;
|
||||
extern const char* current_rule_file;
|
||||
|
||||
|
|
|
@ -47,10 +47,7 @@ bool ScannedFile::AlreadyScanned() const
|
|||
return rval;
|
||||
}
|
||||
|
||||
SignatureFile::SignatureFile(std::string file)
|
||||
: file(std::move(file))
|
||||
{
|
||||
}
|
||||
SignatureFile::SignatureFile(std::string file) : file(std::move(file)) { }
|
||||
|
||||
SignatureFile::SignatureFile(std::string file, std::string full_path)
|
||||
: file(std::move(file)), full_path(std::move(full_path))
|
||||
|
|
|
@ -692,6 +692,41 @@ int Manager::HookLoadFile(const Plugin::LoadType type, const string& file, const
|
|||
return rc;
|
||||
}
|
||||
|
||||
std::pair<int, std::optional<std::string>>
|
||||
Manager::HookLoadFileExtended(const Plugin::LoadType type, const string& file,
|
||||
const string& resolved)
|
||||
{
|
||||
HookArgumentList args;
|
||||
|
||||
if ( HavePluginForHook(META_HOOK_PRE) )
|
||||
{
|
||||
args.push_back(HookArgument(type));
|
||||
args.push_back(HookArgument(file));
|
||||
args.push_back(HookArgument(resolved));
|
||||
MetaHookPre(HOOK_LOAD_FILE_EXT, args);
|
||||
}
|
||||
|
||||
hook_list* l = hooks[HOOK_LOAD_FILE_EXT];
|
||||
|
||||
std::pair<int, std::optional<std::string>> rc = {-1, std::nullopt};
|
||||
|
||||
if ( l )
|
||||
for ( hook_list::iterator i = l->begin(); i != l->end(); ++i )
|
||||
{
|
||||
Plugin* p = (*i).second;
|
||||
|
||||
rc = p->HookLoadFileExtended(type, file, resolved);
|
||||
|
||||
if ( rc.first >= 0 )
|
||||
break;
|
||||
}
|
||||
|
||||
if ( HavePluginForHook(META_HOOK_POST) )
|
||||
MetaHookPost(HOOK_LOAD_FILE_EXT, args, HookArgument(rc));
|
||||
|
||||
return rc;
|
||||
}
|
||||
|
||||
std::pair<bool, ValPtr> Manager::HookCallFunction(const Func* func, zeek::detail::Frame* parent,
|
||||
Args* vecargs) const
|
||||
{
|
||||
|
|
|
@ -245,6 +245,32 @@ public:
|
|||
virtual int HookLoadFile(const Plugin::LoadType type, const std::string& file,
|
||||
const std::string& resolved);
|
||||
|
||||
/**
|
||||
* Hook that gives plugins a chance to take over loading an input file,
|
||||
* including replacing the file's content. This method must be called
|
||||
* between InitPreScript() and InitPostScript() for each input file Bro is
|
||||
* about to load, either given on the command line or via @load script
|
||||
* directives. The hook can take over the file, in which case Bro must not
|
||||
* further process it otherwise; or provide its content, in which case Bro
|
||||
* must use that and ignore the original file.
|
||||
*
|
||||
* @return tuple where the first element is 1 if a plugin took over the
|
||||
* file; 0 if a plugin took over the file but had trouble loading it; and
|
||||
* -1 if no plugin was interested in the file at all.
|
||||
*
|
||||
* If the plugins takes over by returning 1, there are two cases: if the
|
||||
* second tuple element remains unset, the plugin handled the loading
|
||||
* completely internally; the caller must not process it any further.
|
||||
* Alternatively, the plugin may optionally return the acutal content to
|
||||
* use for the file as a string through the tuple's second element. If so,
|
||||
* the caller must ignore the file on disk and use that provided content
|
||||
* instead (including when there's actually no physical file in place on
|
||||
* disk at all).
|
||||
*/
|
||||
virtual std::pair<int, std::optional<std::string>>
|
||||
HookLoadFileExtended(const Plugin::LoadType type, const std::string& file,
|
||||
const std::string& resolved);
|
||||
|
||||
/**
|
||||
* Hook that filters calls to a script function/event/hook.
|
||||
*
|
||||
|
|
|
@ -22,6 +22,7 @@ const char* hook_name(HookType h)
|
|||
static constexpr const char* hook_names[int(NUM_HOOKS) + 1] = {
|
||||
// Order must match that of HookType.
|
||||
"LoadFile",
|
||||
"LoadFileExtended",
|
||||
"CallFunction",
|
||||
"QueueEvent",
|
||||
"DrainEvents",
|
||||
|
@ -230,6 +231,21 @@ void HookArgument::Describe(ODesc* d) const
|
|||
{
|
||||
d->Add("<no location>");
|
||||
}
|
||||
break;
|
||||
|
||||
case INPUT_FILE:
|
||||
{
|
||||
d->Add("(");
|
||||
d->Add(input_file.first);
|
||||
d->Add(", ");
|
||||
if ( input_file.second )
|
||||
d->Add(input_file.second->substr(0, 20)); // cut content off
|
||||
else
|
||||
d->Add("<no content>");
|
||||
|
||||
d->Add(")");
|
||||
}
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -368,6 +384,13 @@ int Plugin::HookLoadFile(const LoadType type, const std::string& file, const std
|
|||
return -1;
|
||||
}
|
||||
|
||||
std::pair<int, std::optional<std::string>> Plugin::HookLoadFileExtended(const LoadType type,
|
||||
const std::string& file,
|
||||
const std::string& resolved)
|
||||
{
|
||||
return std::make_pair(-1, std::nullopt);
|
||||
}
|
||||
|
||||
std::pair<bool, ValPtr> Plugin::HookFunctionCall(const Func* func, zeek::detail::Frame* parent,
|
||||
Args* args)
|
||||
{
|
||||
|
|
|
@ -5,6 +5,7 @@
|
|||
#include "zeek/zeek-config.h"
|
||||
|
||||
#include <list>
|
||||
#include <optional>
|
||||
#include <string>
|
||||
#include <utility>
|
||||
|
||||
|
@ -57,6 +58,7 @@ enum HookType
|
|||
{
|
||||
// Note: when changing this table, update hook_name() in Plugin.cc.
|
||||
HOOK_LOAD_FILE, //< Activates Plugin::HookLoadFile().
|
||||
HOOK_LOAD_FILE_EXT, //< Activates Plugin::HookLoadFileExtended().
|
||||
HOOK_CALL_FUNCTION, //< Activates Plugin::HookCallFunction().
|
||||
HOOK_QUEUE_EVENT, //< Activates Plugin::HookQueueEvent().
|
||||
HOOK_DRAIN_EVENTS, //< Activates Plugin::HookDrainEvents()
|
||||
|
@ -205,7 +207,8 @@ public:
|
|||
CONN,
|
||||
THREAD_FIELDS,
|
||||
LOCATION,
|
||||
ARG_LIST
|
||||
ARG_LIST,
|
||||
INPUT_FILE
|
||||
};
|
||||
|
||||
/**
|
||||
|
@ -357,6 +360,15 @@ public:
|
|||
arg.args = args;
|
||||
}
|
||||
|
||||
/**
|
||||
* Constructor with HookLoadFileExtended result describing an input file.
|
||||
*/
|
||||
explicit HookArgument(std::pair<int, std::optional<std::string>> file)
|
||||
{
|
||||
type = INPUT_FILE;
|
||||
input_file = std::move(file);
|
||||
}
|
||||
|
||||
/**
|
||||
* Returns the value for a boolen argument. The argument's type must
|
||||
* match accordingly.
|
||||
|
@ -540,6 +552,7 @@ private:
|
|||
std::pair<bool, Val*> func_result;
|
||||
std::pair<int, const threading::Field* const*> tfields;
|
||||
std::string arg_string;
|
||||
std::pair<int, std::optional<std::string>> input_file;
|
||||
};
|
||||
|
||||
using HookArgumentList = std::list<HookArgument>;
|
||||
|
@ -815,6 +828,43 @@ protected:
|
|||
virtual int HookLoadFile(const LoadType type, const std::string& file,
|
||||
const std::string& resolved);
|
||||
|
||||
/**
|
||||
* Hook into loading input files, with extended capabilities. This method
|
||||
* will be called between InitPreScript() and InitPostScript(), but with no
|
||||
* further order or timing guaranteed. It will be called once for each
|
||||
* input file Bro is about to load, either given on the command line or via
|
||||
* @load script directives. The hook can take over the file, in which case
|
||||
* Bro will not further process it otherwise. It can, alternatively, also
|
||||
* provide the file content as a string, which Bro will then process just
|
||||
* as if it had read it from a file.
|
||||
*
|
||||
* @param type The type of load encountered: script load, signatures load,
|
||||
* or plugin load.
|
||||
*
|
||||
* @param file The filename that was passed to @load. Only includes
|
||||
* an extension if it was given in @load.
|
||||
*
|
||||
* @param resolved The file or directory name Bro resolved from
|
||||
* the given path and is going to load. Empty string
|
||||
* if Bro was not able to resolve a path.
|
||||
*
|
||||
* @return tuple of an integer and an optional string, where: the integer
|
||||
* must be 1 if the plugin takes over loading the file (see below); 0 if
|
||||
* the plugin wanted to take over the file but had trouble loading it
|
||||
* (processing will abort in this case, and the plugin should have printed
|
||||
* an error message); and -1 if the plugin wants Bro to proceeed processing
|
||||
* the file normally. If the plugins takes over by returning 1, there are
|
||||
* two cases: if the second tuple element remains unset, the plugin handled
|
||||
* the loading completely internally; Bro will not do anything further with
|
||||
* it. Alternatively, the plugin may optionally return the acutal content
|
||||
* to use for the file as a string through the tuple's second element. If
|
||||
* so, Bro will ignore the file on disk and use that provided content
|
||||
* instead (including when there's actually no physical file in place on
|
||||
* disk at all, and loading would have hence failed otherwise).
|
||||
*/
|
||||
virtual std::pair<int, std::optional<std::string>>
|
||||
HookLoadFileExtended(const LoadType type, const std::string& file, const std::string& resolved);
|
||||
|
||||
/**
|
||||
* Hook into executing a script-level function/event/hook. Whenever
|
||||
* the script interpreter is about to execution a function, it first
|
||||
|
|
|
@ -228,3 +228,23 @@ void end_PS()
|
|||
{
|
||||
BEGIN(INITIAL);
|
||||
}
|
||||
|
||||
static YY_BUFFER_STATE rules_buffer;
|
||||
|
||||
void rules_set_input_from_buffer(const char* data, size_t size)
|
||||
{
|
||||
rules_buffer = yy_scan_bytes(data, size); // this copies the data
|
||||
}
|
||||
|
||||
void rules_set_input_from_file(FILE* f)
|
||||
{
|
||||
rules_buffer = yy_create_buffer(f, YY_BUF_SIZE);
|
||||
}
|
||||
|
||||
void rules_parse_input()
|
||||
{
|
||||
yy_switch_to_buffer(rules_buffer);
|
||||
rules_parse();
|
||||
yy_delete_buffer(rules_buffer);
|
||||
}
|
||||
|
||||
|
|
104
src/scan.l
104
src/scan.l
|
@ -353,11 +353,14 @@ when return TOK_WHEN;
|
|||
|
||||
@load-plugin{WS}{ID} {
|
||||
const char* plugin = zeek::util::skip_whitespace(yytext + 12);
|
||||
int rc = PLUGIN_HOOK_WITH_RESULT(HOOK_LOAD_FILE, HookLoadFile(zeek::plugin::Plugin::PLUGIN, plugin, ""), -1);
|
||||
std::pair<int, std::optional<std::string>> rc;
|
||||
rc.first = PLUGIN_HOOK_WITH_RESULT(HOOK_LOAD_FILE, HookLoadFile(zeek::plugin::Plugin::PLUGIN, plugin, ""), -1);
|
||||
if ( rc.first < 0 )
|
||||
rc = PLUGIN_HOOK_WITH_RESULT(HOOK_LOAD_FILE_EXT, HookLoadFileExtended(zeek::plugin::Plugin::PLUGIN, plugin, ""), std::make_pair(-1, std::nullopt));
|
||||
|
||||
switch ( rc ) {
|
||||
switch ( rc.first ) {
|
||||
case -1:
|
||||
// No plugin in charge of this file.
|
||||
// No plugin in charge of this file. (We ignore any returned content.)
|
||||
zeek::plugin_mgr->ActivateDynamicPlugin(plugin);
|
||||
break;
|
||||
|
||||
|
@ -560,12 +563,13 @@ YYLTYPE zeek::detail::GetCurrentLocation()
|
|||
static int load_files(const char* orig_file)
|
||||
{
|
||||
std::string file_path = find_relative_script_file(orig_file);
|
||||
int rc = PLUGIN_HOOK_WITH_RESULT(HOOK_LOAD_FILE, HookLoadFile(zeek::plugin::Plugin::SCRIPT, orig_file, file_path), -1);
|
||||
|
||||
if ( rc == 1 )
|
||||
return 0; // A plugin took care of it, just skip.
|
||||
std::pair<int, std::optional<std::string>> rc = {-1, std::nullopt};
|
||||
rc.first = PLUGIN_HOOK_WITH_RESULT(HOOK_LOAD_FILE, HookLoadFile(zeek::plugin::Plugin::SCRIPT, orig_file, file_path), -1);
|
||||
if ( rc.first < 0 )
|
||||
rc = PLUGIN_HOOK_WITH_RESULT(HOOK_LOAD_FILE_EXT, HookLoadFileExtended(zeek::plugin::Plugin::SCRIPT, orig_file, file_path), std::make_pair(-1, std::nullopt));
|
||||
|
||||
if ( rc == 0 )
|
||||
if ( rc.first == 0 )
|
||||
{
|
||||
if ( ! zeek::reporter->Errors() )
|
||||
// This is just in case the plugin failed to report
|
||||
|
@ -576,55 +580,57 @@ static int load_files(const char* orig_file)
|
|||
exit(1);
|
||||
}
|
||||
|
||||
assert(rc == -1); // No plugin in charge of this file.
|
||||
if ( rc.first == 1 && ! rc.second )
|
||||
return 0; // A plugin took care of it, just skip.
|
||||
|
||||
FILE* f = nullptr;
|
||||
|
||||
if ( zeek::util::streq(orig_file, "-") )
|
||||
if ( rc.first == -1 )
|
||||
{
|
||||
f = stdin;
|
||||
file_path = zeek::detail::ScannedFile::canonical_stdin_path;
|
||||
|
||||
if ( zeek::detail::g_policy_debug )
|
||||
if ( zeek::util::streq(orig_file, "-") )
|
||||
{
|
||||
zeek::detail::debug_msg("Warning: can't use debugger while reading policy from stdin; turning off debugging.\n");
|
||||
zeek::detail::g_policy_debug = false;
|
||||
f = stdin;
|
||||
file_path = zeek::detail::ScannedFile::canonical_stdin_path;
|
||||
|
||||
if ( zeek::detail::g_policy_debug )
|
||||
{
|
||||
zeek::detail::debug_msg("Warning: can't use debugger while reading policy from stdin; turning off debugging.\n");
|
||||
zeek::detail::g_policy_debug = false;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
else
|
||||
{
|
||||
if ( file_path.empty() )
|
||||
zeek::reporter->FatalError("can't find %s", orig_file);
|
||||
|
||||
if ( zeek::util::is_dir(file_path.c_str()) )
|
||||
f = zeek::util::detail::open_package(file_path);
|
||||
else
|
||||
f = zeek::util::open_file(file_path);
|
||||
{
|
||||
if ( file_path.empty() )
|
||||
zeek::reporter->FatalError("can't find %s", orig_file);
|
||||
|
||||
if ( ! f )
|
||||
zeek::reporter->FatalError("can't open %s", file_path.c_str());
|
||||
if ( zeek::util::is_dir(file_path.c_str()) )
|
||||
f = zeek::util::detail::open_package(file_path);
|
||||
else
|
||||
f = zeek::util::open_file(file_path);
|
||||
|
||||
if ( ! f )
|
||||
zeek::reporter->FatalError("can't open %s", file_path.c_str());
|
||||
}
|
||||
|
||||
zeek::detail::ScannedFile sf(file_stack.length(), file_path);
|
||||
if ( sf.AlreadyScanned() )
|
||||
{
|
||||
if ( rc.first == -1 && f != stdin )
|
||||
fclose(f);
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
zeek::detail::files_scanned.push_back(std::move(sf));
|
||||
}
|
||||
|
||||
zeek::detail::ScannedFile sf(file_stack.length(), file_path);
|
||||
|
||||
if ( sf.AlreadyScanned() )
|
||||
{
|
||||
if ( f != stdin )
|
||||
fclose(f);
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
zeek::detail::files_scanned.push_back(std::move(sf));
|
||||
|
||||
if ( zeek::detail::g_policy_debug && ! file_path.empty() )
|
||||
{
|
||||
// Add the filename to the file mapping table (Debug.h).
|
||||
zeek::detail::Filemap* map = new zeek::detail::Filemap;
|
||||
zeek::detail::HashKey* key = new zeek::detail::HashKey(file_path.c_str());
|
||||
zeek::detail::g_dbgfilemaps.emplace(file_path, map);
|
||||
LoadPolicyFileText(file_path.c_str());
|
||||
LoadPolicyFileText(file_path.c_str(), rc.second);
|
||||
}
|
||||
|
||||
// Remember where we were to restore the module scope in which
|
||||
|
@ -633,12 +639,24 @@ static int load_files(const char* orig_file)
|
|||
|
||||
zeek::detail::zeekygen_mgr->Script(file_path);
|
||||
|
||||
DBG_LOG(zeek::DBG_SCRIPTS, "Loading %s", file_path.c_str());
|
||||
|
||||
// "orig_file", could be an alias for yytext, which is ephemeral
|
||||
// and will be zapped after the yy_switch_to_buffer() below.
|
||||
yy_switch_to_buffer(yy_create_buffer(f, YY_BUF_SIZE));
|
||||
YY_BUFFER_STATE buffer;
|
||||
|
||||
if ( rc.first == 1 ) {
|
||||
// Parse code provided by plugin.
|
||||
assert(rc.second);
|
||||
DBG_LOG(zeek::DBG_SCRIPTS, "Loading %s from code supplied by plugin ", file_path.c_str());
|
||||
buffer = yy_scan_bytes(rc.second->data(), rc.second->size()); // this copies the data
|
||||
}
|
||||
else {
|
||||
// Parse from file.
|
||||
assert(f);
|
||||
DBG_LOG(zeek::DBG_SCRIPTS, "Loading %s", file_path.c_str());
|
||||
buffer = yy_create_buffer(f, YY_BUF_SIZE);
|
||||
}
|
||||
|
||||
yy_switch_to_buffer(buffer);
|
||||
yylloc.first_line = yylloc.last_line = line_number = 1;
|
||||
|
||||
// Don't delete the old filename - it's pointed to by
|
||||
|
|
|
@ -741,15 +741,15 @@ SetupResult setup(int argc, char** argv, Options* zopts)
|
|||
|
||||
// Append signature files given on the command line
|
||||
for ( const auto& sf : options.signature_files )
|
||||
all_signature_files.push_back(sf);
|
||||
all_signature_files.emplace_back(sf);
|
||||
|
||||
// Append signature files defined in "signature_files" script option
|
||||
for ( auto&& sf : get_script_signature_files() )
|
||||
all_signature_files.push_back(std::move(sf));
|
||||
all_signature_files.emplace_back(std::move(sf));
|
||||
|
||||
// Append signature files defined in @load-sigs
|
||||
for ( const auto& sf : zeek::detail::sig_files )
|
||||
all_signature_files.push_back(sf);
|
||||
all_signature_files.emplace_back(sf);
|
||||
|
||||
if ( ! all_signature_files.empty() )
|
||||
{
|
||||
|
|
|
@ -1,2 +1,2 @@
|
|||
### BTest baseline data generated by btest-diff. Do not edit. Use "btest -U/-u" to update. Requires BTest >= 0.63.
|
||||
error: Can't open signature file nope
|
||||
error: failed to find file associated with @load-sigs nope
|
||||
|
|
File diff suppressed because it is too large
Load diff
|
@ -0,0 +1,7 @@
|
|||
### BTest baseline data generated by btest-diff. Do not edit. Use "btest -U/-u" to update. Requires BTest >= 0.63.
|
||||
HookLoadExtended/script: file=|xxx| resolved=|./xxx.zeek|
|
||||
HookLoadExtended/script: file=|yyy| resolved=||
|
||||
HookLoadExtended/signature: file=|abc.sig| resolved=|./abc.sig|
|
||||
new zeek_init(): script has been replaced
|
||||
new zeek_init(): script has been added
|
||||
signature works!
|
|
@ -15,6 +15,7 @@ using namespace btest::plugin::Demo_Hooks;
|
|||
zeek::plugin::Configuration Plugin::Configure()
|
||||
{
|
||||
EnableHook(zeek::plugin::HOOK_LOAD_FILE);
|
||||
EnableHook(zeek::plugin::HOOK_LOAD_FILE_EXT);
|
||||
EnableHook(zeek::plugin::HOOK_CALL_FUNCTION);
|
||||
EnableHook(zeek::plugin::HOOK_QUEUE_EVENT);
|
||||
EnableHook(zeek::plugin::HOOK_DRAIN_EVENTS);
|
||||
|
@ -56,6 +57,13 @@ int Plugin::HookLoadFile(const LoadType type, const std::string& file, const std
|
|||
return -1;
|
||||
}
|
||||
|
||||
std::pair<int, std::optional<std::string>> Plugin::HookLoadFileExtended(const LoadType type, const std::string& file, const std::string& resolved)
|
||||
{
|
||||
fprintf(stderr, "%.6f %-15s %s %s\n", zeek::run_state::network_time, "| HookLoadFileExtended",
|
||||
file.c_str(), resolved.c_str());
|
||||
return std::make_pair(-1, std::nullopt);
|
||||
}
|
||||
|
||||
std::pair<bool, zeek::ValPtr> Plugin::HookFunctionCall(const zeek::Func* func, zeek::detail::Frame* frame,
|
||||
zeek::Args* args)
|
||||
{
|
||||
|
|
|
@ -9,6 +9,7 @@ class Plugin : public zeek::plugin::Plugin
|
|||
{
|
||||
protected:
|
||||
int HookLoadFile(const LoadType type, const std::string& file, const std::string& resolved) override;
|
||||
std::pair<int, std::optional<std::string>> HookLoadFileExtended(const LoadType type, const std::string& file, const std::string& resolved) override;
|
||||
std::pair<bool, zeek::ValPtr> HookFunctionCall(const zeek::Func* func, zeek::detail::Frame* parent,
|
||||
zeek::Args* args) override;
|
||||
bool HookQueueEvent(zeek::Event* event) override;
|
||||
|
|
17
testing/btest/plugins/plugin-load-file-extended.zeek
Normal file
17
testing/btest/plugins/plugin-load-file-extended.zeek
Normal file
|
@ -0,0 +1,17 @@
|
|||
# @TEST-EXEC: ${DIST}/auxil/zeek-aux/plugin-support/init-plugin -u . Testing LoadFileExtended
|
||||
# @TEST-EXEC: cp -r %DIR/plugin-load-file-extended/* .
|
||||
# @TEST-EXEC: ./configure --zeek-dist=${DIST} && make
|
||||
# @TEST-EXEC: ZEEK_PLUGIN_PATH=$(pwd) zeek -r $TRACES/wikipedia.trace -b Testing::LoadFileExtended xxx yyy -s abc.sig >> output
|
||||
# @TEST-EXEC: btest-diff output
|
||||
|
||||
# @TEST-START-FILE xxx.zeek
|
||||
|
||||
event zeek_init() {
|
||||
print "original script";
|
||||
}
|
||||
|
||||
# @TEST-END-FILE
|
||||
|
||||
# @TEST-START-FILE abc.sig
|
||||
# empty
|
||||
# @TEST-END-FILE
|
|
@ -0,0 +1,70 @@
|
|||
|
||||
#include "Plugin.h"
|
||||
|
||||
namespace btest::plugin::Testing_LoadFileExtended
|
||||
{
|
||||
Plugin plugin;
|
||||
}
|
||||
|
||||
using namespace btest::plugin::Testing_LoadFileExtended;
|
||||
|
||||
zeek::plugin::Configuration Plugin::Configure()
|
||||
{
|
||||
EnableHook(zeek::plugin::HOOK_LOAD_FILE_EXT);
|
||||
|
||||
zeek::plugin::Configuration config;
|
||||
config.name = "Testing::LoadFileExtended";
|
||||
config.version.major = 0;
|
||||
config.version.minor = 1;
|
||||
config.version.patch = 4;
|
||||
return config;
|
||||
}
|
||||
|
||||
#include <iostream>
|
||||
|
||||
std::pair<int, std::optional<std::string>> Plugin::HookLoadFileExtended(const LoadType type,
|
||||
const std::string& file,
|
||||
const std::string& resolved)
|
||||
{
|
||||
if ( type == LoadType::SCRIPT && file == "xxx" )
|
||||
{
|
||||
printf("HookLoadExtended/script: file=|%s| resolved=|%s|\n", file.c_str(), resolved.c_str());
|
||||
|
||||
return std::make_pair(1, R"(
|
||||
event zeek_init() {
|
||||
print "new zeek_init(): script has been replaced";
|
||||
}
|
||||
|
||||
event signature_match(state: signature_state, msg: string, data: string) {
|
||||
print msg;
|
||||
}
|
||||
)");
|
||||
}
|
||||
|
||||
if ( type == LoadType::SCRIPT && file == "yyy" )
|
||||
{
|
||||
printf("HookLoadExtended/script: file=|%s| resolved=|%s|\n", file.c_str(), resolved.c_str());
|
||||
|
||||
return std::make_pair(1, R"(
|
||||
event zeek_init() {
|
||||
print "new zeek_init(): script has been added";
|
||||
}
|
||||
)");
|
||||
}
|
||||
|
||||
if ( type == LoadType::SIGNATURES && file == "abc.sig" )
|
||||
{
|
||||
printf("HookLoadExtended/signature: file=|%s| resolved=|%s|\n", file.c_str(), resolved.c_str());
|
||||
|
||||
return std::make_pair(1, R"(
|
||||
signature my-sig {
|
||||
ip-proto == tcp
|
||||
payload /GET \/images/
|
||||
event "signature works!"
|
||||
}
|
||||
)");
|
||||
}
|
||||
|
||||
return std::make_pair(-1, std::nullopt);
|
||||
}
|
||||
|
18
testing/btest/plugins/plugin-load-file-extended/src/Plugin.h
Normal file
18
testing/btest/plugins/plugin-load-file-extended/src/Plugin.h
Normal file
|
@ -0,0 +1,18 @@
|
|||
|
||||
#pragma once
|
||||
|
||||
#include <zeek/plugin/Plugin.h>
|
||||
|
||||
namespace btest::plugin::Testing_LoadFileExtended {
|
||||
|
||||
class Plugin : public zeek::plugin::Plugin
|
||||
{
|
||||
protected:
|
||||
// Overridden from zeek::plugin::Plugin.
|
||||
zeek::plugin::Configuration Configure() override;
|
||||
std::pair<int, std::optional<std::string>> HookLoadFileExtended(const Plugin::LoadType type, const std::string& file, const std::string& resolved) override;
|
||||
};
|
||||
|
||||
extern Plugin plugin;
|
||||
|
||||
}
|
Loading…
Add table
Add a link
Reference in a new issue