mirror of
https://github.com/zeek/zeek.git
synced 2025-10-02 06:38:20 +00:00
Integrate the Spicy plugin into Zeek proper.
This reflects the `spicy-plugin` code as of `d8c296b81cc2a11`. In addition to moving the code into Zeek's source tree, this comes with a couple small functional changes: - `spicyz` no longer tries to infer if it's running from the build directory. Instead `ZEEK_SPICY_LIBRARY` can be set to a custom location. `zeek-set-path.sh` does that now. - ZEEK_CONFIG can be set to change what `spicyz -z` print out. This is primarily for backwards compatibility. Some further notes on specifics: - We raise the minimum Spicy version to 1.8 (i.e., current `main` branch). - Renamed the `compiler/` subdirectory to `spicyz` to avoid include-path conflicts with the Spicy headers. - In `cmake/`, the corresponding PR brings a new/extended version of `FindZeek`, which Spicy analyzer packages need. We also now install some of the files that the Spicy plugin used to bring for testing, so that existing packages keep working. - For now, this all remains backwards compatible with the current `zkg` analyzer templates so that they work with both external and integrated Spicy support. Later, once we don't need to support any external Spicy plugin versions anymore, we can clean up the templates as well. - All the plugin's tests have moved into the standard test suite. They are skipped if configure with `--disable-spicy`. This holds off on adapting the new code further to Zeek's coding conventions, so that it remains easier to maintain it in parallel to the (now legacy) external plugin. We'll make a pass over the formatting for (presumable) Zeek 6.1.
This commit is contained in:
parent
d8f7329227
commit
0040111955
209 changed files with 10406 additions and 160 deletions
3
.gitmodules
vendored
3
.gitmodules
vendored
|
@ -58,9 +58,6 @@
|
|||
[submodule "auxil/out_ptr"]
|
||||
path = auxil/out_ptr
|
||||
url = https://github.com/soasis/out_ptr.git
|
||||
[submodule "auxil/spicy-plugin"]
|
||||
path = auxil/spicy-plugin
|
||||
url = https://github.com/zeek/spicy-plugin
|
||||
[submodule "auxil/spicy"]
|
||||
path = auxil/spicy/spicy
|
||||
url = https://github.com/zeek/spicy
|
||||
|
|
|
@ -497,17 +497,19 @@ file(
|
|||
WRITE ${CMAKE_CURRENT_BINARY_DIR}/zeek-path-dev.sh
|
||||
"export ZEEKPATH=`${cmake_binary_dir}/zeek-path-dev`\n"
|
||||
"export ZEEK_PLUGIN_PATH=\"${cmake_binary_dir}/src\":$\{ZEEK_PLUGIN_PATH\}\n"
|
||||
"export PATH=\"${cmake_binary_dir}\":\"${cmake_binary_dir}/src\":\"${cmake_binary_dir}/auxil/spicy/spicy/bin\":\"${cmake_binary_dir}/src/builtin-plugins/spicy-plugin/bin\":$\{PATH\}\n"
|
||||
"export PATH=\"${cmake_binary_dir}\":\"${cmake_binary_dir}/src\":\"${cmake_binary_dir}/auxil/spicy/spicy/bin\":\"${cmake_binary_dir}/src/spicy/spicyz\":$\{PATH\}\n"
|
||||
"export SPICY_PATH=`${cmake_binary_dir}/spicy-path`\n"
|
||||
"export HILTI_CXX_INCLUDE_DIRS=`${cmake_binary_dir}/hilti-cxx-include-dirs`\n")
|
||||
"export HILTI_CXX_INCLUDE_DIRS=`${cmake_binary_dir}/hilti-cxx-include-dirs`\n"
|
||||
"export ZEEK_SPICY_LIBRARY_PATH=${cmake_source_dir}/scripts/spicy\n")
|
||||
|
||||
file(
|
||||
WRITE ${CMAKE_CURRENT_BINARY_DIR}/zeek-path-dev.csh
|
||||
"setenv ZEEKPATH `${cmake_binary_dir}/zeek-path-dev`\n"
|
||||
"setenv ZEEK_PLUGIN_PATH \"${cmake_binary_dir}/src\":$\{ZEEK_PLUGIN_PATH\}\n"
|
||||
"setenv PATH \"${cmake_binary_dir}\":\"${cmake_binary_dir}/src\":\"${cmake_binary_dir}/auxil/spicy/spicy/bin\":\"${cmake_binary_dir}/src/builtin-plugins/spicy-plugin/bin\":$\{PATH\}\n"
|
||||
"setenv PATH \"${cmake_binary_dir}\":\"${cmake_binary_dir}/src\":\"${cmake_binary_dir}/auxil/spicy/spicy/bin\":\"${cmake_binary_dir}/src/spicy/spicyz\":$\{PATH\}\n"
|
||||
"setenv SPICY_PATH \"`${cmake_binary_dir}/spicy-path`\"\n"
|
||||
"setenv HILTI_CXX_INCLUDE_DIRS \"`${cmake_binary_dir}/hilti-cxx-include-dirs`\"\n")
|
||||
"setenv HILTI_CXX_INCLUDE_DIRS \"`${cmake_binary_dir}/hilti-cxx-include-dirs`\"\n"
|
||||
"setenv ZEEK_SPICY_LIBRARY_PATH \"${cmake_source_dir}/scripts/spicy\"\n")
|
||||
|
||||
file(STRINGS "${CMAKE_CURRENT_SOURCE_DIR}/VERSION" VERSION LIMIT_COUNT 1)
|
||||
execute_process(
|
||||
|
@ -887,53 +889,28 @@ else ()
|
|||
endif ()
|
||||
|
||||
if (NOT DISABLE_SPICY)
|
||||
set(USE_SPICY_ANALYZERS yes)
|
||||
if (SPICY_ROOT_DIR)
|
||||
find_package(Spicy REQUIRED) # will set HAVE_SPICY
|
||||
spicy_require_version("1.8.0")
|
||||
|
||||
if (NOT SPICY_ROOT_DIR)
|
||||
set(HAVE_SPICY yes) # evaluated by Spicy plugin build
|
||||
if (NOT SPICY_HAVE_TOOLCHAIN)
|
||||
message(FATAL_ERROR "Spicy not built with toolchain support")
|
||||
endif ()
|
||||
|
||||
spicy_print_summary()
|
||||
else ()
|
||||
set(HAVE_SPICY yes)
|
||||
add_subdirectory(auxil/spicy)
|
||||
zeek_add_dependencies(spicy)
|
||||
|
||||
# Set variables used by the spicy-plugin build since we are building Spicy
|
||||
# as part of Zeek so spicy-plugin cannot use `spicy-config` at configure
|
||||
# time to set these.
|
||||
set(SPICY_CONFIG "<builtin>")
|
||||
set(SPICY_HAVE_TOOLCHAIN "YES")
|
||||
set(SPICY_INCLUDE_DIRS_RUNTIME
|
||||
${PROJECT_SOURCE_DIR}/auxil/spicy/spicy/hilti/runtime/include
|
||||
${PROJECT_SOURCE_DIR}/auxil/spicy/spicy/spicy/runtime/include
|
||||
${PROJECT_BINARY_DIR}/auxil/spicy/spicy/include)
|
||||
set(SPICY_INCLUDE_DIRS_TOOLCHAIN
|
||||
${PROJECT_SOURCE_DIR}/auxil/spicy/spicy/hilti/toolchain/include
|
||||
${PROJECT_SOURCE_DIR}/auxil/spicy/spicy/spicy/toolchain/include)
|
||||
set(SPICY_LIBRARY spicy)
|
||||
set(HILTI_LIBRARY_RT hilti-rt)
|
||||
set(HILTI_LIBRARY_RT_DEBUG hilti-rt-debug)
|
||||
set(SPICY_LIBRARY_RT spicy-rt)
|
||||
set(SPICY_LIBRARY_RT_DEBUG spicy-rt-debug)
|
||||
|
||||
# Needed only for logging from CMake configure phase.
|
||||
get_directory_property(SPICY_VERSION DIRECTORY ${PROJECT_SOURCE_DIR}/auxil/spicy/spicy
|
||||
DEFINITION SPICY_VERSION)
|
||||
get_directory_property(
|
||||
SPICY_VERSION_NUMBER DIRECTORY ${PROJECT_SOURCE_DIR}/auxil/spicy/spicy DEFINITION
|
||||
SPICY_VERSION_NUMBER)
|
||||
get_directory_property(SPICY_PREFIX DIRECTORY ${PROJECT_SOURCE_DIR}/auxil/spicy/spicy
|
||||
DEFINITION CMAKE_INSTALL_PREFIX)
|
||||
get_directory_property(SPICY_BUILD_MODE DIRECTORY ${PROJECT_SOURCE_DIR}/auxil/spicy/spicy
|
||||
DEFINITION CMAKE_BUILD_TYPE)
|
||||
set(SPICYC "<bundled>")
|
||||
endif ()
|
||||
|
||||
if (NOT SPICY_PLUGIN_PATH)
|
||||
set(_spicy_plugin "included")
|
||||
set(SPICY_PLUGIN_PATH ${CMAKE_SOURCE_DIR}/auxil/spicy-plugin)
|
||||
endif ()
|
||||
|
||||
set(SPICY_PLUGIN_BINARY_PATH ${CMAKE_BINARY_DIR}/src/builtin-plugins/spicy-plugin)
|
||||
list(APPEND ZEEK_INCLUDE_PLUGINS ${SPICY_PLUGIN_PATH})
|
||||
set(USE_SPICY_ANALYZERS yes)
|
||||
else ()
|
||||
set(HAVE_SPICY no) # evaluated by Spicy plugin build
|
||||
set(HAVE_SPICY no)
|
||||
set(USE_SPICY_ANALYZERS no)
|
||||
endif ()
|
||||
|
||||
|
@ -1255,6 +1232,10 @@ add_subdirectory(scripts)
|
|||
add_subdirectory(man)
|
||||
add_subdirectory(testing)
|
||||
|
||||
if (NOT DISABLE_SPICY)
|
||||
zeek_add_dependencies(spicyz)
|
||||
endif ()
|
||||
|
||||
include(CheckOptionalBuildSources)
|
||||
|
||||
checkoptionalbuildsources(auxil/btest BTest INSTALL_BTEST)
|
||||
|
@ -1264,26 +1245,6 @@ checkoptionalbuildsources(auxil/zeek-aux Zeek-Aux INSTALL_AUX_TOOLS)
|
|||
checkoptionalbuildsources(auxil/zeek-archiver ZeekArchiver INSTALL_ZEEK_ARCHIVER)
|
||||
checkoptionalbuildsources(auxil/zeek-client ZeekClient INSTALL_ZEEK_CLIENT)
|
||||
|
||||
if (NOT DISABLE_SPICY)
|
||||
# The `zeek` binary implicitly depends on the driver object file built as part
|
||||
# of `spicy`; make that dependency explicit.
|
||||
zeek_add_dependencies(spicyz)
|
||||
|
||||
if (NOT SPICY_ROOT_DIR)
|
||||
# Make sure we build targets of spicy-plugin after the `spicy` target.
|
||||
add_dependencies(plugin-Zeek-Spicy spicy)
|
||||
add_dependencies(spicyz spicy)
|
||||
|
||||
# Also install spicy-plugin's CMake files into Zeek's global `cmake/`
|
||||
# folder.
|
||||
#
|
||||
# NOTE: We do not install spicy-plugin's `FindZeek.cmake` since another
|
||||
# version of this file is already provided by Zeek.
|
||||
install(FILES auxil/spicy-plugin/cmake/ZeekSpicyAnalyzerSupport.cmake
|
||||
auxil/spicy-plugin/cmake/FindSpicy.cmake DESTINATION share/zeek/cmake)
|
||||
endif ()
|
||||
endif ()
|
||||
|
||||
# Always generate helper scripts referenced in e.g., `zeek-path-dev.*` so the
|
||||
# scripts work in any build configuration. If we do not include Spicy these
|
||||
# files have no actual effect.
|
||||
|
@ -1295,6 +1256,8 @@ endif ()
|
|||
# we generate shell definitions to support running and using Spicy or
|
||||
# spicy-plugin functionality in the build tree, including JIT'ing directly from
|
||||
# Zeek.
|
||||
#
|
||||
# TODO: Do we still need these?
|
||||
configure_file(${CMAKE_SOURCE_DIR}/auxil/spicy/spicy-path.in ${CMAKE_BINARY_DIR}/spicy-path @ONLY)
|
||||
configure_file(${CMAKE_SOURCE_DIR}/auxil/spicy/hilti-cxx-include-dirs.in
|
||||
${CMAKE_BINARY_DIR}/hilti-cxx-include-dirs @ONLY)
|
||||
|
@ -1375,12 +1338,6 @@ elseif (SPICY_ROOT_DIR)
|
|||
set(_spicy "external (${SPICY_ROOT_DIR})")
|
||||
endif ()
|
||||
|
||||
if (DISABLE_SPICY)
|
||||
set(_spicy_plugin "disabled")
|
||||
elseif ("${_spicy_plugin}" STREQUAL "")
|
||||
set(_spicy_plugin "external (${SPICY_PLUGIN_PATH})")
|
||||
endif ()
|
||||
|
||||
if (ZEEK_LEGACY_ANALYZERS)
|
||||
list(JOIN ZEEK_LEGACY_ANALYZERS ", " _legacy_analyzers)
|
||||
set(_legacy_analyzers
|
||||
|
@ -1394,7 +1351,7 @@ endif ()
|
|||
|
||||
if (ZEEK_LEGACY_ANALYZERS OR ZEEK_SKIPPED_ANALYZERS)
|
||||
set(_analyzer_warning
|
||||
"\n\n[Warning] Some analyzers are not available due to lack of built-in Spicy support:${_legacy_analyzers}${_skipped_analyzers}"
|
||||
"\n\n[Warning] Some analyzers are not available due to lack of Spicy support:${_legacy_analyzers}${_skipped_analyzers}"
|
||||
)
|
||||
endif ()
|
||||
|
||||
|
@ -1412,6 +1369,7 @@ message(
|
|||
"\nScript dir: ${ZEEK_SCRIPT_INSTALL_PATH}"
|
||||
"\nSpool dir: ${ZEEK_SPOOL_DIR}"
|
||||
"\nState dir: ${ZEEK_STATE_DIR}"
|
||||
"\nSpicy modules dir: ${ZEEK_SPICY_MODULE_PATH}"
|
||||
"\n"
|
||||
"\nDebug mode: ${ENABLE_DEBUG}"
|
||||
"\nUnit tests: ${ENABLE_ZEEK_UNIT_TESTS}"
|
||||
|
@ -1433,7 +1391,6 @@ message(
|
|||
"\nGen-ZAM: ${_gen_zam_exe_path}"
|
||||
"\nzkg: ${INSTALL_ZKG}"
|
||||
"\nSpicy: ${_spicy}"
|
||||
"\nSpicy plugin: ${_spicy_plugin}"
|
||||
"\nSpicy analyzers: ${USE_SPICY_ANALYZERS}"
|
||||
"\nJavaScript: ${ZEEK_HAVE_JAVASCRIPT}"
|
||||
"\n"
|
||||
|
|
|
@ -1 +0,0 @@
|
|||
Subproject commit a618f2ce0831c311f9bcff5d020b85fc44345221
|
|
@ -1 +1 @@
|
|||
Subproject commit 64de5d0ef323428452827469f07b0a1da8e65e16
|
||||
Subproject commit ec87b43037dba50648cb93be8940a4db23658905
|
2
cmake
2
cmake
|
@ -1 +1 @@
|
|||
Subproject commit a90d69179607c5083158f926be6d37f3db18f110
|
||||
Subproject commit ac0529be3d1e14eba426c2e516c4a9c9971be40b
|
4
configure
vendored
4
configure
vendored
|
@ -104,7 +104,6 @@ Usage: $0 [OPTION]... [VAR=VALUE]...
|
|||
--with-python-inc=PATH path to Python headers
|
||||
--with-python-lib=PATH path to libpython
|
||||
--with-spicy=PATH path to Spicy install root
|
||||
--with-spicy-plugin=PATH path to Spicy plugin source tree
|
||||
--with-swig=PATH path to SWIG executable
|
||||
|
||||
Packaging Options (for developers):
|
||||
|
@ -378,9 +377,6 @@ while [ $# -ne 0 ]; do
|
|||
--with-spicy=*)
|
||||
append_cache_entry SPICY_ROOT_DIR PATH $optarg
|
||||
;;
|
||||
--with-spicy-plugin=*)
|
||||
append_cache_entry SPICY_PLUGIN_PATH PATH $optarg
|
||||
;;
|
||||
--with-swig=*)
|
||||
append_cache_entry SWIG_EXECUTABLE PATH $optarg
|
||||
;;
|
||||
|
|
1
scripts/base/frameworks/spicy/__load__.zeek
Normal file
1
scripts/base/frameworks/spicy/__load__.zeek
Normal file
|
@ -0,0 +1 @@
|
|||
@load ./main.zeek
|
37
scripts/base/frameworks/spicy/init-bare.zeek
Normal file
37
scripts/base/frameworks/spicy/init-bare.zeek
Normal file
|
@ -0,0 +1,37 @@
|
|||
|
||||
module Spicy;
|
||||
|
||||
export {
|
||||
# doc-options-start
|
||||
## Constant for testing if Spicy is available.
|
||||
const available = T;
|
||||
|
||||
## Show output of Spicy print statements.
|
||||
const enable_print = F &redef;
|
||||
|
||||
# Record and display profiling information, if compiled into analyzer.
|
||||
const enable_profiling = F &redef;
|
||||
|
||||
## abort() instead of throwing HILTI exceptions.
|
||||
const abort_on_exceptions = F &redef;
|
||||
|
||||
## Include backtraces when reporting unhandled exceptions.
|
||||
const show_backtraces = F &redef;
|
||||
|
||||
## Maximum depth of recursive file analysis (Spicy analyzers only)
|
||||
const max_file_depth: count = 5 &redef;
|
||||
# doc-options-end
|
||||
|
||||
# doc-types-start
|
||||
## Result type for `Spicy::resource_usage()`.
|
||||
type ResourceUsage: record {
|
||||
user_time : interval; ##< user CPU time of the Zeek process
|
||||
system_time :interval; ##< system CPU time of the Zeek process
|
||||
memory_heap : count; ##< memory allocated on the heap by the Zeek process
|
||||
num_fibers : count; ##< number of fibers currently in use
|
||||
max_fibers: count; ##< maximum number of fibers ever in use
|
||||
max_fiber_stack_size: count; ##< maximum fiber stack size ever in use
|
||||
cached_fibers: count; ##< number of fibers currently cached
|
||||
};
|
||||
# doc-types-end
|
||||
}
|
81
scripts/base/frameworks/spicy/init-framework.zeek
Normal file
81
scripts/base/frameworks/spicy/init-framework.zeek
Normal file
|
@ -0,0 +1,81 @@
|
|||
@load base/misc/version
|
||||
|
||||
# doc-common-start
|
||||
module Spicy;
|
||||
|
||||
export {
|
||||
# doc-functions-start
|
||||
## Enable a specific Spicy protocol analyzer if not already active. If this
|
||||
## analyzer replaces an standard analyzer, that one will automatically be
|
||||
## disabled.
|
||||
##
|
||||
## tag: analyzer to toggle
|
||||
##
|
||||
## Returns: true if the operation succeeded
|
||||
global enable_protocol_analyzer: function(tag: Analyzer::Tag) : bool;
|
||||
|
||||
## Disable a specific Spicy protocol analyzer if not already inactive. If
|
||||
## this analyzer replaces an standard analyzer, that one will automatically
|
||||
## be re-enabled.
|
||||
##
|
||||
## tag: analyzer to toggle
|
||||
##
|
||||
## Returns: true if the operation succeeded
|
||||
global disable_protocol_analyzer: function(tag: Analyzer::Tag) : bool;
|
||||
|
||||
|
||||
## Enable a specific Spicy file analyzer if not already active. If this
|
||||
## analyzer replaces an standard analyzer, that one will automatically be
|
||||
## disabled.
|
||||
##
|
||||
## tag: analyzer to toggle
|
||||
##
|
||||
## Returns: true if the operation succeeded
|
||||
global enable_file_analyzer: function(tag: Files::Tag) : bool;
|
||||
|
||||
## Disable a specific Spicy file analyzer if not already inactive. If
|
||||
## this analyzer replaces an standard analyzer, that one will automatically
|
||||
## be re-enabled.
|
||||
##
|
||||
## tag: analyzer to toggle
|
||||
##
|
||||
## Returns: true if the operation succeeded
|
||||
global disable_file_analyzer: function(tag: Files::Tag) : bool;
|
||||
|
||||
## Returns current resource usage as reported by the Spicy runtime system.
|
||||
global resource_usage: function() : ResourceUsage;
|
||||
# doc-functions-end
|
||||
}
|
||||
|
||||
# Marked with &is_used to suppress complaints when there aren't any
|
||||
# Spicy file analyzers loaded, and hence this event can't be generated.
|
||||
# The attribute is only supported for Zeek 5.0 and higher.
|
||||
event spicy_analyzer_for_mime_type(a: Files::Tag, mt: string) &is_used
|
||||
{
|
||||
Files::register_for_mime_type(a, mt);
|
||||
}
|
||||
|
||||
function enable_protocol_analyzer(tag: Analyzer::Tag) : bool
|
||||
{
|
||||
return Spicy::__toggle_analyzer(tag, T);
|
||||
}
|
||||
|
||||
function disable_protocol_analyzer(tag: Analyzer::Tag) : bool
|
||||
{
|
||||
return Spicy::__toggle_analyzer(tag, F);
|
||||
}
|
||||
|
||||
function enable_file_analyzer(tag: Files::Tag) : bool
|
||||
{
|
||||
return Spicy::__toggle_analyzer(tag, T);
|
||||
}
|
||||
|
||||
function disable_file_analyzer(tag: Files::Tag) : bool
|
||||
{
|
||||
return Spicy::__toggle_analyzer(tag, F);
|
||||
}
|
||||
|
||||
function resource_usage() : ResourceUsage
|
||||
{
|
||||
return Spicy::__resource_usage();
|
||||
}
|
15
scripts/base/frameworks/spicy/main.zeek
Normal file
15
scripts/base/frameworks/spicy/main.zeek
Normal file
|
@ -0,0 +1,15 @@
|
|||
@load base/frameworks/notice
|
||||
|
||||
module Spicy;
|
||||
|
||||
export {
|
||||
redef enum Notice::Type += { Spicy_Max_File_Depth_Exceeded };
|
||||
}
|
||||
|
||||
event max_file_depth_exceeded(f: fa_file, args: Files::AnalyzerArgs, limit: count)
|
||||
{
|
||||
NOTICE([
|
||||
$note=Spicy::Spicy_Max_File_Depth_Exceeded,
|
||||
$msg=fmt("Maximum file depth exceeded for file %s", f$id)
|
||||
]);
|
||||
}
|
90
scripts/base/frameworks/spicy/misc/record-spicy-batch.zeek
Normal file
90
scripts/base/frameworks/spicy/misc/record-spicy-batch.zeek
Normal file
|
@ -0,0 +1,90 @@
|
|||
# Saves all input traffic in Spicy's batch format.
|
||||
|
||||
module SpicyBatch;
|
||||
|
||||
export {
|
||||
const filename = "batch.dat" &redef;
|
||||
}
|
||||
|
||||
redef tcp_content_deliver_all_orig=T;
|
||||
redef tcp_content_deliver_all_resp=T;
|
||||
redef udp_content_deliver_all_orig=T;
|
||||
redef udp_content_deliver_all_resp=T;
|
||||
|
||||
global output: file;
|
||||
global conns: set[conn_id];
|
||||
global num_conns = 0;
|
||||
|
||||
function id(c: connection) : string
|
||||
{
|
||||
local cid = c$id;
|
||||
local proto = "???";
|
||||
|
||||
if ( is_tcp_port(cid$orig_p) )
|
||||
proto = "tcp";
|
||||
else if ( is_udp_port(cid$orig_p) )
|
||||
proto = "udp";
|
||||
else if ( is_icmp_port(cid$orig_p) )
|
||||
proto = "icmp";
|
||||
|
||||
return fmt("%s-%d-%s-%d-%s", cid$orig_h, cid$orig_p, cid$resp_h, cid$resp_p, proto);
|
||||
}
|
||||
|
||||
function begin(c: connection, type_: string)
|
||||
{
|
||||
add conns[c$id];
|
||||
++num_conns;
|
||||
print fmt("tracking %s", c$id);
|
||||
|
||||
local id_ = id(c);
|
||||
print output, fmt("@begin-conn %s %s %s-orig %s%%orig %s-resp %s%%resp\n", id_, type_, id_, c$id$resp_p, id_, c$id$resp_p);
|
||||
}
|
||||
|
||||
event zeek_init()
|
||||
{
|
||||
output = open(filename);
|
||||
enable_raw_output(output);
|
||||
print output, "!spicy-batch v2\n";
|
||||
}
|
||||
|
||||
event new_connection_contents(c: connection)
|
||||
{
|
||||
begin(c, "stream");
|
||||
}
|
||||
|
||||
event tcp_contents(c: connection, is_orig: bool, seq: count, contents: string)
|
||||
{
|
||||
print output, fmt("@data %s-%s %d\n", id(c), (is_orig ? "orig" : "resp"), |contents|);
|
||||
print output, contents;
|
||||
print output, "\n";
|
||||
}
|
||||
|
||||
event content_gap(c: connection, is_orig: bool, seq: count, length: count)
|
||||
{
|
||||
print output, fmt("@gap %s-%s %d\n", id(c), (is_orig ? "orig" : "resp"), length);
|
||||
}
|
||||
|
||||
event udp_contents(c: connection, is_orig: bool, contents: string)
|
||||
{
|
||||
if ( c$id !in conns )
|
||||
begin(c, "block");
|
||||
|
||||
print output, fmt("@data %s-%s %d\n", id(c), (is_orig ? "orig" : "resp"), |contents|);
|
||||
print output, contents;
|
||||
print output, "\n";
|
||||
}
|
||||
|
||||
event connection_state_remove(c: connection)
|
||||
{
|
||||
if ( c$id !in conns )
|
||||
return;
|
||||
|
||||
print output, fmt("@end-conn %s\n", id(c));
|
||||
}
|
||||
|
||||
event zeek_done()
|
||||
{
|
||||
close(output);
|
||||
print fmt("recorded %d session%s total", num_conns, (num_conns > 1 ? "s" : ""));
|
||||
print fmt("output in %s", filename);
|
||||
}
|
18
scripts/base/frameworks/spicy/misc/resource-usage.zeek
Normal file
18
scripts/base/frameworks/spicy/misc/resource-usage.zeek
Normal file
|
@ -0,0 +1,18 @@
|
|||
module Spicy;
|
||||
|
||||
event print_usage()
|
||||
{
|
||||
local r = Spicy::resource_usage();
|
||||
|
||||
print fmt("%.6f Spicy user=%f sys=%f heap=%d current_fibers=%d cached_fibers=%d max_fibers=%d max_stack=%d",
|
||||
network_time(), r$user_time, r$system_time, r$memory_heap,
|
||||
r$num_fibers, r$cached_fibers, r$max_fibers,
|
||||
r$max_fiber_stack_size);
|
||||
|
||||
schedule 1 min { print_usage() };
|
||||
}
|
||||
|
||||
event zeek_init()
|
||||
{
|
||||
schedule 1 min { print_usage() };
|
||||
}
|
|
@ -5702,3 +5702,4 @@ event net_done(t: time)
|
|||
@endif
|
||||
|
||||
@load base/packet-protocols
|
||||
@load base/frameworks/spicy/init-bare
|
||||
|
|
|
@ -43,6 +43,7 @@
|
|||
@load base/frameworks/openflow
|
||||
@load base/frameworks/netcontrol
|
||||
@load base/frameworks/telemetry
|
||||
@load base/frameworks/spicy
|
||||
|
||||
@load base/protocols/conn
|
||||
@load base/protocols/dce-rpc
|
||||
|
|
|
@ -17,6 +17,8 @@
|
|||
# Load BiFs defined by plugins.
|
||||
@load base/bif/plugins
|
||||
|
||||
@load base/frameworks/spicy/init-framework
|
||||
|
||||
# This sets up secondary/subdir BIFs such that they can be used by any
|
||||
# further scripts within their global initializations and is intended to be
|
||||
# the last thing done within this script. It's called within @if simply so
|
||||
|
|
157
scripts/spicy/zeek.spicy
Normal file
157
scripts/spicy/zeek.spicy
Normal file
|
@ -0,0 +1,157 @@
|
|||
# Copyright (c) 2020-2021 by the Zeek Project. See LICENSE for details.
|
||||
|
||||
module zeek;
|
||||
|
||||
# Note: Retain the formatting here, doc/scripts/autogen-spicy-lib is picking up on that.
|
||||
|
||||
%cxx-include = "zeek/spicy/runtime-support.h";
|
||||
|
||||
## [Deprecated] Triggers a DPD protocol confirmation for the current connection.
|
||||
##
|
||||
## This function has been deprecated and will be removed. Use ``spicy::accept_input``
|
||||
## instead, which will have the same effect with Zeek.
|
||||
public function confirm_protocol() : void &cxxname="zeek::spicy::rt::confirm_protocol";
|
||||
|
||||
## [Deprecated] Triggers a DPD protocol violation for the current connection.
|
||||
##
|
||||
## This function has been deprecated and will be removed. Use ``spicy::decline_input``
|
||||
## instead, which will have the same effect with Zeek.
|
||||
public function reject_protocol(reason: string) : void &cxxname="zeek::spicy::rt::reject_protocol";
|
||||
|
||||
## Reports a "weird" to Zeek. This should be used with similar semantics as in
|
||||
## Zeek: something quite unexpected happening at the protocol level, which however
|
||||
## does not prevent us from continuing to process the connection.
|
||||
##
|
||||
## id: the name of the weird, which (just like in Zeek) should be a *static*
|
||||
## string identifying the situation reported (e.g., ``unexpected_command``).
|
||||
##
|
||||
## addl: additional information to record along with the weird
|
||||
public function weird(id: string, addl: string = "") &cxxname="zeek::spicy::rt::weird";
|
||||
|
||||
## Returns true if we're currently parsing the originator side of a connection.
|
||||
public function is_orig() : bool &cxxname="zeek::spicy::rt::is_orig";
|
||||
|
||||
## Returns the current connection's UID.
|
||||
public function uid() : string &cxxname="zeek::spicy::rt::uid";
|
||||
|
||||
## Returns the current connection's 4-tuple ID.
|
||||
public function conn_id() : tuple<orig_h: addr, orig_p: port, resp_h: addr, resp_p: port> &cxxname="zeek::spicy::rt::conn_id";
|
||||
|
||||
## Instructs Zeek to flip the directionality of the current connection.
|
||||
public function flip_roles() : void &cxxname="zeek::spicy::rt::flip_roles";
|
||||
|
||||
## Returns the number of packets seen so far on the current side of the current connection.
|
||||
public function number_packets() : uint64 &cxxname="zeek::spicy::rt::number_packets";
|
||||
|
||||
## Opaque handle to a protocol analyzer.
|
||||
public type ProtocolHandle = __library_type("zeek::spicy::rt::ProtocolHandle");
|
||||
|
||||
## Adds a Zeek-side child protocol analyzer to the current connection.
|
||||
##
|
||||
## If the same analyzer was added previously with protocol_handle_get_or_create or
|
||||
## protocol_begin with same argument, and not closed with protocol_handle_close
|
||||
## or protocol_end, no new analyzer will be added.
|
||||
##
|
||||
## See `protocol_handle_get_or_create` for the error semantics of this function.
|
||||
##
|
||||
## analyzer: type of analyzer to instantiate, specified through its Zeek-side
|
||||
## name (similar to what Zeek's signature action `enable` takes); if not
|
||||
## specified, Zeek will perform its usual dynamic protocol detection to figure
|
||||
## out how to parse the data (the latter will work only for TCP protocols, though.)
|
||||
public function protocol_begin(analyzer: optional<string> = Null) : void &cxxname="zeek::spicy::rt::protocol_begin";
|
||||
|
||||
## Gets a handle to a Zeek-side child protocol analyzer for the current connection.
|
||||
##
|
||||
## If no such child exists it will be added; otherwise a handle to the
|
||||
## existing child protocol analyzer will be returned.
|
||||
##
|
||||
## This function will return an error
|
||||
##
|
||||
## - if not called from a protocol analyzer, or
|
||||
## - the requested child protocol analyzer is unknown, or
|
||||
## - creation of a child analyzer of the requested type was prevented by a
|
||||
## previous call of `disable_analyzer` with `prevent=T`
|
||||
##
|
||||
## analyzer: type of analyzer to instantiate, specified through its Zeek-side
|
||||
## name (similar to what Zeek's signature action `enable` takes).
|
||||
public function protocol_handle_get_or_create(analyzer: string) : ProtocolHandle &cxxname="zeek::spicy::rt::protocol_handle_get_or_create";
|
||||
|
||||
## Forwards protocol data to all previously instantiated Zeek-side child protocol analyzers.
|
||||
##
|
||||
## is_orig: true to feed the data to the child's originator side, false for the responder
|
||||
## data: chunk of data to forward to child analyzer
|
||||
## h: optional handle to the child analyzer to forward data into, else forward to all child analyzers
|
||||
public function protocol_data_in(is_orig: bool, data: bytes, h: optional<ProtocolHandle> = Null) : void &cxxname="zeek::spicy::rt::protocol_data_in";
|
||||
|
||||
## Signals a gap in input data to all previously instantiated Zeek-side child protocol analyzers.
|
||||
##
|
||||
## is_orig: true to signal gap to the child's originator side, false for the responder
|
||||
## offset: start offset of gap in input stream
|
||||
## len: size of gap
|
||||
## h: optional handle to the child analyzer signal a gap to, else signal to all child analyzers
|
||||
public function protocol_gap(is_orig: bool, offset: uint64, len: uint64, h: optional<ProtocolHandle> = Null) : void &cxxname="zeek::spicy::rt::protocol_gap";
|
||||
|
||||
## Signals end-of-data to all previously instantiated Zeek-side child protocol
|
||||
## analyzers and removes them.
|
||||
public function protocol_end() : void &cxxname="zeek::spicy::rt::protocol_end";
|
||||
|
||||
## Signals end-of-data to the given child analyzer and removes it.
|
||||
##
|
||||
## The given handle must be live, i.e., it must not have been used in a
|
||||
## previous protocol_handle_close call, and must not have been live when
|
||||
## protocol_end was called. If the handle is not live a runtime error will
|
||||
## be triggered.
|
||||
##
|
||||
## handle: handle to the child analyzer to remove
|
||||
public function protocol_handle_close(handle: ProtocolHandle): void &cxxname="zeek::spicy::rt::protocol_handle_close";
|
||||
|
||||
## Signals the beginning of a file to Zeek's file analysis, associating it with the current connection.
|
||||
## Optionally, a mime type can be provided. It will be passed on to Zeek's file analysis framework.
|
||||
## Returns the Zeek-side file ID of the new file.
|
||||
public function file_begin(mime_type: optional<string> = Null) : string &cxxname="zeek::spicy::rt::file_begin";
|
||||
|
||||
## Returns the current file's FUID.
|
||||
public function fuid() : string &cxxname="zeek::spicy::rt::fuid";
|
||||
|
||||
## Terminates the currently active Zeek-side session, flushing all state. Any
|
||||
## subsequent activity will start a new session from scratch. This can only be
|
||||
## called from inside a protocol analyzer.
|
||||
public function terminate_session() : void &cxxname="zeek::spicy::rt::terminate_session";
|
||||
|
||||
## Signals the expected size of a file to Zeek's file analysis.
|
||||
##
|
||||
## size: expected size of file
|
||||
## fid: Zeek-side ID of the file to operate on; if not given, the file started by the most recent file_begin() will be used
|
||||
public function file_set_size(size: uint64, fid: optional<string> = Null) : void &cxxname="zeek::spicy::rt::file_set_size";
|
||||
|
||||
## Passes file content on to Zeek's file analysis.
|
||||
##
|
||||
## data: chunk of raw data to pass into analysis
|
||||
## fid: Zeek-side ID of the file to operate on; if not given, the file started by the most recent file_begin() will be used
|
||||
public function file_data_in(data: bytes, fid: optional<string> = Null) : void &cxxname="zeek::spicy::rt::file_data_in";
|
||||
|
||||
## Passes file content at a specific offset on to Zeek's file analysis.
|
||||
##
|
||||
## data: chunk of raw data to pass into analysis
|
||||
## offset: position in file where data starts
|
||||
## fid: Zeek-side ID of the file to operate on; if not given, the file started by the most recent file_begin() will be used
|
||||
public function file_data_in_at_offset(data: bytes, offset: uint64, fid: optional<string> = Null) : void &cxxname="zeek::spicy::rt::file_data_in_at_offset";
|
||||
|
||||
## Signals a gap in a file to Zeek's file analysis.
|
||||
##
|
||||
## offset: position in file where gap starts
|
||||
## len: size of gap
|
||||
## fid: Zeek-side ID of the file to operate on; if not given, the file started by the most recent file_begin() will be used
|
||||
public function file_gap(offset: uint64, len: uint64, fid: optional<string> = Null) : void &cxxname="zeek::spicy::rt::file_gap";
|
||||
|
||||
## Signals the end of a file to Zeek's file analysis.
|
||||
##
|
||||
## fid: Zeek-side ID of the file to operate on; if not given, the file started by the most recent file_begin() will be used
|
||||
public function file_end(fid: optional<string> = Null) : void &cxxname="zeek::spicy::rt::file_end";
|
||||
|
||||
## Inside a packet analyzer, forwards what data remains after parsing the top-level unit
|
||||
## on to another analyzer. The index specifies the target, per the current dispatcher table.
|
||||
public function forward_packet(identifier: uint32) : void &cxxname="zeek::spicy::rt::forward_packet";
|
||||
|
||||
## Gets the network time from Zeek.
|
||||
public function network_time() : time &cxxname="zeek::spicy::rt::network_time";
|
31
scripts/spicy/zeek_file.spicy
Normal file
31
scripts/spicy/zeek_file.spicy
Normal file
|
@ -0,0 +1,31 @@
|
|||
# Copyright (c) 2020-2021 by the Zeek Project. See LICENSE for details.
|
||||
#
|
||||
# TODO: This code would ideally just be a part of zeek.spicy, but that would
|
||||
# come with compilation overhead currently even if not used, see
|
||||
# https://github.com/zeek/spicy/issues/301.
|
||||
|
||||
module zeek_file;
|
||||
|
||||
import zeek;
|
||||
|
||||
## Convenience wrapper for passing content into Zeek's file analysis.
|
||||
## After connecting an instance of this unit type to a sink, all data
|
||||
## sent to the sink will be passed on to Zeek as a file.
|
||||
##
|
||||
## mime_type: MIME type of the file's content, if known; will be passed on to Zeek
|
||||
## size: Total number of bytes the file contains, if known; will be passed on to Zeek
|
||||
public type File = unit(mime_type: optional<string> = Null, size: optional<uint64> = Null) {
|
||||
on %init {
|
||||
self.fid = zeek::file_begin(mime_type);
|
||||
|
||||
if ( size )
|
||||
zeek::file_set_size(*size, self.fid);
|
||||
}
|
||||
|
||||
: bytes &chunked &eod { zeek::file_data_in($$, self.fid); }
|
||||
|
||||
on %finally { zeek::file_end(self.fid); }
|
||||
|
||||
## Zeek-side file ID
|
||||
var fid: string;
|
||||
};
|
43
scripts/spicy/zeek_rt.hlt
Normal file
43
scripts/spicy/zeek_rt.hlt
Normal file
|
@ -0,0 +1,43 @@
|
|||
|
||||
module zeek_rt {
|
||||
|
||||
import hilti;
|
||||
|
||||
%cxx-include = "zeek/spicy/runtime-support.h";
|
||||
|
||||
public type Val = __library_type("::zeek::ValPtr");
|
||||
public type BroType = __library_type("::zeek::TypePtr");
|
||||
public type EventHandlerPtr = __library_type("::zeek::EventHandlerPtr");
|
||||
|
||||
type ZeekTypeTag = enum {
|
||||
Addr, Any, Bool, Count, Double, Enum, Error, File, Func, Int, Interval, List, Opaque, Pattern, Port, Record, String, Subnet, Table, Time, Type, Vector, Void
|
||||
} &cxxname="::zeek::spicy::rt::ZeekTypeTag";
|
||||
|
||||
declare public void register_protocol_analyzer(string name, hilti::Protocol protocol, vector<port> ports, string parser_orig, string parser_resp, string replaces, string linker_scope) &cxxname="zeek::spicy::rt::register_protocol_analyzer" &have_prototype;
|
||||
declare public void register_file_analyzer(string name, vector<string> mime_types, string parser, string replaces, string linker_scope) &cxxname="zeek::spicy::rt::register_file_analyzer" &have_prototype;
|
||||
declare public void register_packet_analyzer(string name, string parser, string replaces, string linker_scope) &cxxname="zeek::spicy::rt::register_packet_analyzer" &have_prototype;
|
||||
declare public void register_type(string ns, string id, BroType t) &cxxname="zeek::spicy::rt::register_type" &have_prototype;
|
||||
|
||||
declare public bool have_handler(EventHandlerPtr handler) &cxxname="zeek::spicy::rt::have_handler" &have_prototype;
|
||||
declare public EventHandlerPtr internal_handler(string event) &cxxname="zeek::spicy::rt::internal_handler" &have_prototype;
|
||||
declare public void install_handler(string event) &cxxname="zeek::spicy::rt::install_handler" &have_prototype;
|
||||
|
||||
declare public void raise_event(EventHandlerPtr handler, vector<Val> args) &cxxname="zeek::spicy::rt::raise_event" &have_prototype;
|
||||
declare public BroType event_arg_type(EventHandlerPtr handler, uint<64> idx) &cxxname="zeek::spicy::rt::event_arg_type" &have_prototype;
|
||||
declare public Val to_val(any x, BroType target) &cxxname="zeek::spicy::rt::to_val" &have_prototype;
|
||||
|
||||
type RecordField = tuple<string, BroType, bool>; # (ID, type, optional)
|
||||
declare public BroType create_base_type(ZeekTypeTag tag) &cxxname="zeek::spicy::rt::create_base_type" &have_prototype;
|
||||
declare public BroType create_enum_type(string ns, string id, vector<tuple<string, int<64>>> labels) &cxxname="zeek::spicy::rt::create_enum_type" &have_prototype;
|
||||
declare public BroType create_record_type(string ns, string id, vector<RecordField> fields) &cxxname="zeek::spicy::rt::create_record_type" &have_prototype;
|
||||
declare public BroType create_table_type(BroType key, optional<BroType> value = Null) &cxxname="zeek::spicy::rt::create_table_type" &have_prototype;
|
||||
declare public BroType create_vector_type(BroType elem) &cxxname="zeek::spicy::rt::create_vector_type" &have_prototype;
|
||||
|
||||
declare public Val current_conn() &cxxname="zeek::spicy::rt::current_conn" &have_prototype;
|
||||
declare public Val current_file() &cxxname="zeek::spicy::rt::current_file" &have_prototype;
|
||||
declare public Val current_packet() &cxxname="zeek::spicy::rt::current_packet" &have_prototype;
|
||||
declare public Val current_is_orig() &cxxname="zeek::spicy::rt::current_is_orig" &have_prototype;
|
||||
|
||||
declare public void debug(string msg) &cxxname="zeek::spicy::rt::debug" &have_prototype;
|
||||
|
||||
}
|
|
@ -172,6 +172,10 @@ add_subdirectory(logging)
|
|||
add_subdirectory(probabilistic)
|
||||
add_subdirectory(session)
|
||||
|
||||
if (HAVE_SPICY)
|
||||
add_subdirectory(spicy)
|
||||
endif ()
|
||||
|
||||
# ##############################################################################
|
||||
# Build in the discovered external plugins and create the autogenerated scripts.
|
||||
|
||||
|
@ -512,6 +516,10 @@ add_dependencies(zeek_objs zeek_autogen_files)
|
|||
add_clang_tidy_files(${zeek_SRCS})
|
||||
zeek_target_link_libraries(zeek_objs)
|
||||
|
||||
if (HAVE_SPICY)
|
||||
target_link_libraries(zeek_objs PRIVATE hilti spicy)
|
||||
endif ()
|
||||
|
||||
if (TARGET zeek_exe)
|
||||
target_sources(zeek_exe PRIVATE main.cc ${zeek_HEADERS})
|
||||
|
||||
|
|
|
@ -22,8 +22,7 @@ DebugLogger::Stream DebugLogger::streams[NUM_DBGS] = {
|
|||
{"logging", 0, false}, {"input", 0, false}, {"threading", 0, false},
|
||||
{"plugins", 0, false}, {"zeekygen", 0, false}, {"pktio", 0, false},
|
||||
{"broker", 0, false}, {"scripts", 0, false}, {"supervisor", 0, false},
|
||||
{"hashkey", 0, false},
|
||||
};
|
||||
{"hashkey", 0, false}, {"spicy", 0, false}};
|
||||
|
||||
DebugLogger::DebugLogger()
|
||||
{
|
||||
|
|
|
@ -57,6 +57,7 @@ enum DebugStream
|
|||
DBG_SCRIPTS, // Script initialization
|
||||
DBG_SUPERVISOR, // Process supervisor
|
||||
DBG_HASHKEY, // HashKey buffers
|
||||
DBG_SPICY, // Spicy functionality
|
||||
|
||||
NUM_DBGS // Has to be last
|
||||
};
|
||||
|
|
|
@ -809,6 +809,13 @@ public:
|
|||
*/
|
||||
void Describe(ODesc* d) const;
|
||||
|
||||
/**
|
||||
* Registers a component.
|
||||
*
|
||||
* @param c The component. The method takes ownership.
|
||||
*/
|
||||
void AddComponent(Component* c);
|
||||
|
||||
/**
|
||||
* Registers an individual BiF that the plugin defines. The
|
||||
* information is for informational purposes only and will show up in
|
||||
|
@ -878,13 +885,6 @@ protected:
|
|||
*/
|
||||
virtual void Done();
|
||||
|
||||
/**
|
||||
* Registers a component.
|
||||
*
|
||||
* @param c The component. The method takes ownership.
|
||||
*/
|
||||
void AddComponent(Component* c);
|
||||
|
||||
/**
|
||||
* Calls the Initialize() function of all components.
|
||||
*/
|
||||
|
|
132
src/spicy/.clang-format
Normal file
132
src/spicy/.clang-format
Normal file
|
@ -0,0 +1,132 @@
|
|||
---
|
||||
Language: Cpp
|
||||
AccessModifierOffset: -4
|
||||
AlignAfterOpenBracket: Align
|
||||
AlignConsecutiveAssignments: false
|
||||
AlignConsecutiveDeclarations: false
|
||||
AlignEscapedNewlines: Right
|
||||
AlignOperands: true
|
||||
AlignTrailingComments: true
|
||||
AllowAllParametersOfDeclarationOnNextLine: false
|
||||
AllowShortBlocksOnASingleLine: false
|
||||
AllowShortCaseLabelsOnASingleLine: true
|
||||
AllowShortFunctionsOnASingleLine: true
|
||||
AllowShortIfStatementsOnASingleLine: false
|
||||
AllowShortLoopsOnASingleLine: false
|
||||
AlwaysBreakAfterDefinitionReturnType: None
|
||||
AlwaysBreakAfterReturnType: None
|
||||
AlwaysBreakBeforeMultilineStrings: true
|
||||
AlwaysBreakTemplateDeclarations: Yes
|
||||
BinPackArguments: true
|
||||
BinPackParameters: true
|
||||
BraceWrapping:
|
||||
AfterClass: false
|
||||
AfterControlStatement: false
|
||||
AfterEnum: false
|
||||
AfterFunction: false
|
||||
AfterNamespace: false
|
||||
AfterObjCDeclaration: false
|
||||
AfterStruct: false
|
||||
AfterUnion: false
|
||||
AfterExternBlock: false
|
||||
BeforeCatch: false
|
||||
BeforeElse: true
|
||||
IndentBraces: false
|
||||
SplitEmptyFunction: false
|
||||
SplitEmptyRecord: false
|
||||
SplitEmptyNamespace: false
|
||||
BreakBeforeBinaryOperators: None
|
||||
BreakBeforeBraces: Custom
|
||||
BreakBeforeInheritanceComma: false
|
||||
BreakInheritanceList: BeforeColon
|
||||
BreakBeforeTernaryOperators: false
|
||||
BreakConstructorInitializersBeforeComma: false
|
||||
BreakConstructorInitializers: BeforeColon
|
||||
BreakAfterJavaFieldAnnotations: false
|
||||
BreakStringLiterals: true
|
||||
ColumnLimit: 120
|
||||
CommentPragmas: 'NOLINT'
|
||||
CompactNamespaces: false
|
||||
ConstructorInitializerAllOnOneLineOrOnePerLine: true
|
||||
ConstructorInitializerIndentWidth: 4
|
||||
ContinuationIndentWidth: 4
|
||||
Cpp11BracedListStyle: true
|
||||
DerivePointerAlignment: false
|
||||
DisableFormat: false
|
||||
ExperimentalAutoDetectBinPacking: false
|
||||
FixNamespaceComments: true
|
||||
ForEachMacros:
|
||||
- foreach
|
||||
- Q_FOREACH
|
||||
- BOOST_FOREACH
|
||||
IncludeBlocks: Regroup
|
||||
IncludeCategories:
|
||||
- Regex: 'hilti/rt.*\.(h|hpp)>'
|
||||
Priority: 5
|
||||
- Regex: 'spicy/rt.*\.(h|hpp)>'
|
||||
Priority: 6
|
||||
- Regex: 'hilti.*\.(h|hpp)>'
|
||||
Priority: 7
|
||||
- Regex: 'spicy.*\.(h|hpp)>'
|
||||
Priority: 8
|
||||
- Regex: '<zeek-spicy\/'
|
||||
Priority: 9
|
||||
- Regex: '<zeek\/'
|
||||
Priority: 10
|
||||
- Regex: '^<([[:alnum:]]|_)+>'
|
||||
Priority: 2
|
||||
- Regex: '^<.*\.h>'
|
||||
Priority: 1
|
||||
- Regex: '.*'
|
||||
Priority: 11
|
||||
IncludeIsMainRegex: '$'
|
||||
IndentCaseLabels: true
|
||||
IndentPPDirectives: None
|
||||
IndentWidth: 4
|
||||
IndentWrappedFunctionNames: false
|
||||
JavaScriptQuotes: Leave
|
||||
JavaScriptWrapImports: true
|
||||
KeepEmptyLinesAtTheStartOfBlocks: false
|
||||
MacroBlockBegin: '^BEGIN_'
|
||||
MacroBlockEnd: '^END_'
|
||||
MaxEmptyLinesToKeep: 2
|
||||
NamespaceIndentation: None
|
||||
ObjCBinPackProtocolList: Auto
|
||||
ObjCBlockIndentWidth: 2
|
||||
ObjCSpaceAfterProperty: false
|
||||
ObjCSpaceBeforeProtocolList: true
|
||||
PenaltyBreakAssignment: 2
|
||||
PenaltyBreakBeforeFirstCallParameter: 500
|
||||
PenaltyBreakComment: 300
|
||||
PenaltyBreakFirstLessLess: 120
|
||||
PenaltyBreakString: 1000
|
||||
PenaltyBreakTemplateDeclaration: 10
|
||||
PenaltyExcessCharacter: 1000000
|
||||
PenaltyReturnTypeOnItsOwnLine: 1000
|
||||
PointerAlignment: Left
|
||||
ReflowComments: true
|
||||
SortIncludes: true
|
||||
SortUsingDeclarations: true
|
||||
SpaceAfterCStyleCast: false
|
||||
SpaceAfterTemplateKeyword: false
|
||||
SpaceAfterLogicalNot: true
|
||||
SpaceBeforeAssignmentOperators: true
|
||||
SpaceBeforeCpp11BracedList: false
|
||||
SpaceBeforeCtorInitializerColon: true
|
||||
SpaceBeforeInheritanceColon: true
|
||||
SpaceBeforeParens: ControlStatements
|
||||
SpaceBeforeRangeBasedForLoopColon: true
|
||||
SpaceInEmptyParentheses: false
|
||||
SpacesBeforeTrailingComments: 1
|
||||
SpacesInAngles: false
|
||||
SpacesInContainerLiterals: true
|
||||
SpacesInCStyleCastParentheses: false
|
||||
SpacesInParentheses: false
|
||||
SpacesInSquareBrackets: false
|
||||
SpacesInConditionalStatement: true
|
||||
Standard: Cpp11
|
||||
StatementMacros:
|
||||
- STANDARD_OPERATOR_1
|
||||
TabWidth: 4
|
||||
UseTab: Never
|
||||
...
|
29
src/spicy/CMakeLists.txt
Normal file
29
src/spicy/CMakeLists.txt
Normal file
|
@ -0,0 +1,29 @@
|
|||
# See the file "COPYING" in the main distribution directory for copyright.
|
||||
|
||||
add_subdirectory(spicyz)
|
||||
|
||||
zeek_add_subdir_library(
|
||||
spicy
|
||||
INTERNAL_DEPENDENCIES
|
||||
${BIF_BUILD_TARGET}
|
||||
INCLUDE_DIRS
|
||||
${CMAKE_CURRENT_SOURCE_DIR}
|
||||
${CMAKE_CURRENT_BINARY_DIR}
|
||||
SOURCES
|
||||
manager.cc
|
||||
file-analyzer.cc
|
||||
packet-analyzer.cc
|
||||
protocol-analyzer.cc
|
||||
runtime-support.cc
|
||||
BIFS
|
||||
spicy.bif)
|
||||
|
||||
target_link_libraries(zeek_spicy_obj PRIVATE hilti spicy)
|
||||
|
||||
set(ZEEK_SPICY_MODULE_PATH "${CMAKE_INSTALL_FULL_LIBDIR}/zeek/spicy" CACHE PATH "")
|
||||
install(DIRECTORY DESTINATION "${ZEEK_SPICY_MODULE_PATH}")
|
||||
|
||||
set(ZEEK_SPICY_LIBRARY_PATH "${CMAKE_INSTALL_FULL_DATADIR}/zeek/spicy" CACHE PATH "")
|
||||
install(DIRECTORY "${PROJECT_SOURCE_DIR}/scripts/spicy/" DESTINATION "${ZEEK_SPICY_LIBRARY_PATH}")
|
||||
|
||||
set(ZEEK_SPICY_DATA_PATH "${CMAKE_INSTALL_FULL_DATADIR}/zeek" CACHE PATH "")
|
233
src/spicy/cookie.h
Normal file
233
src/spicy/cookie.h
Normal file
|
@ -0,0 +1,233 @@
|
|||
// See the file "COPYING" in the main distribution directory for copyright.
|
||||
|
||||
/**
|
||||
* Cookie types that's stored in the HILTI context to provide access to the
|
||||
* current analyzer.
|
||||
*/
|
||||
|
||||
#pragma once
|
||||
|
||||
#include <memory>
|
||||
#include <optional>
|
||||
#include <string>
|
||||
#include <utility>
|
||||
#include <variant>
|
||||
#include <vector>
|
||||
|
||||
#include "zeek/Val.h"
|
||||
#include "zeek/analyzer/Analyzer.h"
|
||||
#include "zeek/analyzer/protocol/tcp/TCP.h"
|
||||
#include "zeek/file_analysis/Analyzer.h"
|
||||
#include "zeek/packet_analysis/Analyzer.h"
|
||||
|
||||
namespace zeek::spicy::rt {
|
||||
|
||||
namespace cookie {
|
||||
|
||||
/** State representing analysis of one file. */
|
||||
struct FileState {
|
||||
FileState(std::string fid) : fid(std::move(fid)) {}
|
||||
std::string fid; /**< unique Zeek-side file ID */
|
||||
std::optional<std::string> mime_type; /**< MIME type, if explicitly set */
|
||||
};
|
||||
|
||||
/**
|
||||
* State stored inside protocol/file analyzer cookies retaining file analysis
|
||||
* state.
|
||||
*
|
||||
* Internally, this maintains a stack of state objects representing individual
|
||||
* files that are currently in-flight.
|
||||
*/
|
||||
class FileStateStack {
|
||||
public:
|
||||
/**
|
||||
* Constructor.
|
||||
*
|
||||
* @param analyzer_id unique ID string representing parent connection/file analyzer
|
||||
*/
|
||||
FileStateStack(std::string analyzer_id) : _analyzer_id(std::move(analyzer_id)) {}
|
||||
|
||||
/**
|
||||
* Begins analysis for a new file, pushing a new state object onto the
|
||||
* stack.
|
||||
*/
|
||||
FileState* push();
|
||||
|
||||
/** Returns true if the stack is currently empty. */
|
||||
bool isEmpty() const { return _stack.empty(); }
|
||||
|
||||
/**
|
||||
* Removes an object from the stack.
|
||||
*
|
||||
* @param fid ID of file to remove state for; no-op if not found
|
||||
*/
|
||||
void remove(const std::string& fid);
|
||||
|
||||
/**
|
||||
* Returns a pointer to the state of the most recently pushed file. Must not
|
||||
* be called on an empty stack.
|
||||
**/
|
||||
const FileState* current() const {
|
||||
assert(_stack.size());
|
||||
return &_stack.back();
|
||||
}
|
||||
|
||||
/**
|
||||
* Returns the state of a given file currently on the stack.
|
||||
*
|
||||
* @param fid ID of file to find
|
||||
* @returns pointer to the file's state, or null if not found
|
||||
*/
|
||||
const FileState* find(const std::string& fid) const;
|
||||
|
||||
private:
|
||||
std::vector<FileState> _stack; // stack of files in flight
|
||||
std::string _analyzer_id; // unique ID string of parent analyzer, as passed into ctor
|
||||
uint64_t _id_counter = 0; // counter incremented for each file added to this stack
|
||||
};
|
||||
|
||||
/** State on the current protocol analyzer. */
|
||||
struct ProtocolAnalyzer {
|
||||
analyzer::Analyzer* analyzer = nullptr; /**< current analyzer */
|
||||
bool is_orig = false; /**< direction of the connection */
|
||||
uint64_t num_packets = 0; /**< number of packets seen so far */
|
||||
FileStateStack fstate_orig; /**< file analysis state for originator side */
|
||||
FileStateStack fstate_resp; /**< file analysis state for responder side */
|
||||
std::shared_ptr<packet_analysis::TCP::TCPSessionAdapter> fake_tcp; /**< fake TPC analyzer created internally */
|
||||
};
|
||||
|
||||
/** State on the current file analyzer. */
|
||||
struct FileAnalyzer {
|
||||
file_analysis::Analyzer* analyzer = nullptr; /**< current analyzer */
|
||||
uint64_t depth = 0; /**< recursive depth of file analysis (Spicy-side file analysis only) */
|
||||
FileStateStack fstate; /**< file analysis state for nested files */
|
||||
};
|
||||
|
||||
/** State on the current file analyzer. */
|
||||
struct PacketAnalyzer {
|
||||
packet_analysis::Analyzer* analyzer = nullptr; /**< current analyzer */
|
||||
Packet* packet = nullptr; /**< current packet */
|
||||
ValPtr packet_val = nullptr; /**< cached "raw_pkt_hdr" val for packet */
|
||||
std::optional<uint32_t> next_analyzer;
|
||||
};
|
||||
|
||||
} // namespace cookie
|
||||
|
||||
/**
|
||||
* Type of state stored in HILTI's execution context during Spicy processing.
|
||||
* This is optimized for fast access and small size.
|
||||
*/
|
||||
struct Cookie {
|
||||
// Exactly one of these pointers is non-null at any time. In that way, the
|
||||
// pointers provide the semantics of a tagged union. Internals are bit
|
||||
// tricky because the union itself cannot be copied/moved.
|
||||
cookie::ProtocolAnalyzer* protocol = nullptr;
|
||||
cookie::FileAnalyzer* file = nullptr;
|
||||
cookie::PacketAnalyzer* packet = nullptr;
|
||||
|
||||
Cookie(cookie::ProtocolAnalyzer&& c) : data(std::move(c)) { protocol = &data.protocol; }
|
||||
Cookie(cookie::FileAnalyzer&& c) : data(std::move(c)) { file = &data.file; }
|
||||
Cookie(cookie::PacketAnalyzer&& c) : data(std::move(c)) { packet = &data.packet; }
|
||||
Cookie(Cookie&& other) noexcept : data(other.tag(), std::move(other.data)) { _initLike(other); }
|
||||
~Cookie() { _delete(); }
|
||||
|
||||
Cookie& operator=(Cookie&& other) noexcept {
|
||||
if ( this == &other )
|
||||
return *this;
|
||||
|
||||
_delete();
|
||||
_initLike(other);
|
||||
|
||||
new (&data) Data(tag(), std::move(other.data));
|
||||
return *this;
|
||||
}
|
||||
|
||||
// Cache of values that can be expensive to compute.
|
||||
struct {
|
||||
ValPtr conn = nullptr; // valid only for protocol analyzers
|
||||
ValPtr is_orig = nullptr; // valid only for protocol analyzers
|
||||
bool confirmed = false; // valid only for protocol analyzers;
|
||||
} cache;
|
||||
|
||||
enum Tag { Protocol, File, Packet };
|
||||
|
||||
/** Returns the type of cookie currently stored. */
|
||||
Tag tag() const {
|
||||
if ( protocol )
|
||||
return Tag::Protocol;
|
||||
else if ( file )
|
||||
return Tag::File;
|
||||
else if ( packet )
|
||||
return Tag::Packet;
|
||||
else
|
||||
throw std::runtime_error("invalid cookie");
|
||||
}
|
||||
|
||||
private:
|
||||
union Data {
|
||||
cookie::ProtocolAnalyzer protocol;
|
||||
cookie::FileAnalyzer file;
|
||||
cookie::PacketAnalyzer packet;
|
||||
|
||||
Data(cookie::ProtocolAnalyzer&& protocol) : protocol(std::move(protocol)) {}
|
||||
Data(cookie::FileAnalyzer&& file) : file(std::move(file)) {}
|
||||
Data(cookie::PacketAnalyzer&& packet) : packet(std::move(packet)) {}
|
||||
Data(Tag tag, Data&& other) {
|
||||
switch ( tag ) {
|
||||
case Tag::Protocol: new (&protocol) cookie::ProtocolAnalyzer(std::move(other.protocol)); break;
|
||||
case Tag::File: new (&file) cookie::FileAnalyzer(std::move(other.file)); break;
|
||||
case Tag::Packet: new (&packet) cookie::PacketAnalyzer(std::move(other.packet)); break;
|
||||
}
|
||||
}
|
||||
|
||||
~Data() {
|
||||
// don't delete anything, Cookie is in charge.
|
||||
}
|
||||
|
||||
Data(const Data& other) = delete;
|
||||
Data& operator=(const Data& other) = delete;
|
||||
Data& operator=(Data&& other) = delete;
|
||||
} data;
|
||||
|
||||
void _delete() {
|
||||
if ( protocol ) {
|
||||
data.protocol.~ProtocolAnalyzer();
|
||||
protocol = nullptr;
|
||||
cache.conn = nullptr;
|
||||
cache.is_orig = nullptr;
|
||||
cache.confirmed = false;
|
||||
}
|
||||
else if ( file ) {
|
||||
data.file.~FileAnalyzer();
|
||||
file = nullptr;
|
||||
}
|
||||
else if ( packet ) {
|
||||
data.packet.~PacketAnalyzer();
|
||||
packet = nullptr;
|
||||
}
|
||||
}
|
||||
|
||||
void _initLike(const Cookie& other) {
|
||||
if ( other.protocol ) {
|
||||
protocol = &data.protocol;
|
||||
cache.confirmed = other.cache.confirmed;
|
||||
}
|
||||
|
||||
else if ( other.file )
|
||||
file = &data.file;
|
||||
|
||||
else if ( other.packet )
|
||||
packet = &data.packet;
|
||||
}
|
||||
|
||||
Cookie(const Cookie& other) = delete;
|
||||
Cookie& operator=(const Cookie& other) = delete;
|
||||
|
||||
friend inline void swap(Cookie& lhs, Cookie& rhs) {
|
||||
Cookie tmp = std::move(lhs);
|
||||
lhs = std::move(rhs);
|
||||
rhs = std::move(tmp);
|
||||
}
|
||||
};
|
||||
|
||||
} // namespace zeek::spicy::rt
|
0
src/spicy/debug.h
Normal file
0
src/spicy/debug.h
Normal file
2
src/spicy/empty.cc
Normal file
2
src/spicy/empty.cc
Normal file
|
@ -0,0 +1,2 @@
|
|||
|
||||
int main() { return 1; }
|
138
src/spicy/file-analyzer.cc
Normal file
138
src/spicy/file-analyzer.cc
Normal file
|
@ -0,0 +1,138 @@
|
|||
// See the file "COPYING" in the main distribution directory for copyright.
|
||||
|
||||
#include "file-analyzer.h"
|
||||
|
||||
#include <utility>
|
||||
|
||||
#include "spicy.bif.h"
|
||||
#include "zeek/file_analysis/File.h"
|
||||
#include "zeek/spicy/manager.h"
|
||||
#include "zeek/spicy/runtime-support.h"
|
||||
|
||||
using namespace zeek;
|
||||
using namespace zeek::spicy;
|
||||
using namespace zeek::spicy::rt;
|
||||
|
||||
#ifdef DEBUG
|
||||
#define STATE_DEBUG_MSG(...) DebugMsg(__VA_ARGS__)
|
||||
#else
|
||||
#define STATE_DEBUG_MSG(...)
|
||||
#endif
|
||||
|
||||
void FileState::debug(const std::string& msg) { spicy::rt::debug(_cookie, msg); }
|
||||
|
||||
static auto create_file_state(FileAnalyzer* analyzer) {
|
||||
uint64_t depth = 0;
|
||||
if ( auto current_cookie = static_cast<Cookie*>(hilti::rt::context::cookie()) ) {
|
||||
if ( const auto f = current_cookie->file )
|
||||
depth = f->depth + 1;
|
||||
}
|
||||
|
||||
cookie::FileAnalyzer cookie{.analyzer = analyzer,
|
||||
.depth = depth,
|
||||
.fstate = cookie::FileStateStack(analyzer->GetFile()->GetID())};
|
||||
return FileState(std::move(cookie));
|
||||
}
|
||||
|
||||
FileAnalyzer::FileAnalyzer(RecordValPtr args, file_analysis::File* file)
|
||||
: file_analysis::Analyzer(std::move(args), file), _state(create_file_state(this)) {}
|
||||
|
||||
FileAnalyzer::~FileAnalyzer() {}
|
||||
|
||||
void FileAnalyzer::Init() {}
|
||||
|
||||
void FileAnalyzer::Done() { Finish(); }
|
||||
|
||||
bool FileAnalyzer::DeliverStream(const u_char* data, uint64_t len) {
|
||||
file_analysis::Analyzer::DeliverStream(data, len);
|
||||
|
||||
return Process(len, data);
|
||||
}
|
||||
|
||||
bool FileAnalyzer::Undelivered(uint64_t offset, uint64_t len) {
|
||||
file_analysis::Analyzer::Undelivered(offset, len);
|
||||
|
||||
STATE_DEBUG_MSG("undelivered data, skipping further originator payload");
|
||||
_state.skipRemaining();
|
||||
return false;
|
||||
}
|
||||
|
||||
bool FileAnalyzer::EndOfFile() {
|
||||
file_analysis::Analyzer::EndOfFile();
|
||||
Finish();
|
||||
return false;
|
||||
}
|
||||
|
||||
bool FileAnalyzer::Process(int len, const u_char* data) {
|
||||
if ( ! _state.hasParser() && ! _state.isSkipping() ) {
|
||||
auto parser = spicy_mgr->parserForFileAnalyzer(_state.file().analyzer->Tag());
|
||||
if ( parser )
|
||||
_state.setParser(parser);
|
||||
else {
|
||||
STATE_DEBUG_MSG("no unit specified for parsing");
|
||||
_state.skipRemaining();
|
||||
return false;
|
||||
}
|
||||
}
|
||||
|
||||
auto* file = _state.file().analyzer->GetFile();
|
||||
|
||||
const auto& max_file_depth = BifConst::Spicy::max_file_depth;
|
||||
|
||||
if ( _state.file().depth >= max_file_depth ) {
|
||||
const auto& file_val = file->ToVal();
|
||||
|
||||
const auto analyzer_args = _state.file().analyzer->GetArgs();
|
||||
|
||||
file->FileEvent(Spicy::max_file_depth_exceeded, {file_val, analyzer_args, val_mgr->Count(_state.file().depth)});
|
||||
|
||||
auto tag = spicy_mgr->tagForFileAnalyzer(_state.file().analyzer->Tag());
|
||||
#if ZEEK_VERSION_NUMBER >= 50200
|
||||
AnalyzerViolation("maximal file depth exceeded", reinterpret_cast<const char*>(data), len, tag);
|
||||
#else
|
||||
// We don't have an an appropriate way to report this with older Zeeks.
|
||||
#endif
|
||||
return false;
|
||||
}
|
||||
|
||||
try {
|
||||
hilti::rt::context::CookieSetter _(_state.cookie());
|
||||
_state.process(len, reinterpret_cast<const char*>(data));
|
||||
} catch ( const hilti::rt::RuntimeError& e ) {
|
||||
STATE_DEBUG_MSG(hilti::rt::fmt("error during parsing, triggering analyzer violation: %s", e.what()));
|
||||
auto tag = spicy_mgr->tagForFileAnalyzer(_state.file().analyzer->Tag());
|
||||
#if ZEEK_VERSION_NUMBER >= 50200
|
||||
AnalyzerViolation(e.what(), reinterpret_cast<const char*>(data), len, tag);
|
||||
#else
|
||||
// We don't have an an appropriate way to report this with older Zeeks.
|
||||
#endif
|
||||
} catch ( const hilti::rt::Exception& e ) {
|
||||
STATE_DEBUG_MSG(e.what());
|
||||
spicy_mgr->analyzerError(_state.file().analyzer, e.description(),
|
||||
e.location()); // this sets Zeek to skip sending any further input
|
||||
}
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
void FileAnalyzer::Finish() {
|
||||
try {
|
||||
hilti::rt::context::CookieSetter _(_state.cookie());
|
||||
_state.finish();
|
||||
} catch ( const hilti::rt::RuntimeError& e ) {
|
||||
STATE_DEBUG_MSG(hilti::rt::fmt("error during parsing, triggering analyzer violation: %s", e.what()));
|
||||
auto tag = spicy_mgr->tagForFileAnalyzer(_state.file().analyzer->Tag());
|
||||
#if ZEEK_VERSION_NUMBER >= 50200
|
||||
AnalyzerViolation(e.what(), "", 0, tag);
|
||||
#else
|
||||
// We don't have an an appropriate way to report this with older Zeeks.
|
||||
#endif
|
||||
} catch ( const hilti::rt::Exception& e ) {
|
||||
spicy_mgr->analyzerError(_state.file().analyzer, e.description(),
|
||||
e.location()); // this sets Zeek to skip sending any further input
|
||||
}
|
||||
}
|
||||
|
||||
file_analysis::Analyzer* FileAnalyzer::InstantiateAnalyzer(RecordValPtr args, file_analysis::File* file) {
|
||||
return new FileAnalyzer(std::move(args), file);
|
||||
}
|
91
src/spicy/file-analyzer.h
Normal file
91
src/spicy/file-analyzer.h
Normal file
|
@ -0,0 +1,91 @@
|
|||
// See the file "COPYING" in the main distribution directory for copyright.
|
||||
|
||||
#pragma once
|
||||
|
||||
#include <optional>
|
||||
#include <string>
|
||||
#include <utility>
|
||||
|
||||
#include <hilti/rt/types/stream.h>
|
||||
|
||||
#include <spicy/rt/driver.h>
|
||||
#include <spicy/rt/parser.h>
|
||||
|
||||
#include "zeek/spicy/cookie.h"
|
||||
|
||||
namespace zeek::spicy::rt {
|
||||
|
||||
/** Parsing state for a file. */
|
||||
class FileState : public ::spicy::rt::driver::ParsingState {
|
||||
public:
|
||||
/**
|
||||
* Constructor.
|
||||
*
|
||||
* @param cookie cookie to associated with the file
|
||||
*/
|
||||
FileState(Cookie cookie) : ParsingState(::spicy::rt::driver::ParsingType::Stream), _cookie(std::move(cookie)) {}
|
||||
|
||||
/** Returns the cookie pointer to use with the runtime library during analysis. */
|
||||
auto* cookie() { return &_cookie; }
|
||||
|
||||
/** Returns the file-specific cookie state associated with the endpoint. */
|
||||
auto& file() {
|
||||
assert(_cookie.file);
|
||||
return *_cookie.file;
|
||||
}
|
||||
|
||||
/**
|
||||
* Records a debug message pertaining to the specific file.
|
||||
*
|
||||
* @param msg message to record
|
||||
*/
|
||||
void DebugMsg(const std::string& msg) { debug(msg); }
|
||||
|
||||
protected:
|
||||
// Overridden from driver::ParsingState.
|
||||
void debug(const std::string& msg) override;
|
||||
|
||||
private:
|
||||
Cookie _cookie;
|
||||
};
|
||||
|
||||
/** A Spicy file analyzer. */
|
||||
class FileAnalyzer : public file_analysis::Analyzer {
|
||||
public:
|
||||
FileAnalyzer(RecordValPtr arg_args, file_analysis::File* arg_file);
|
||||
virtual ~FileAnalyzer();
|
||||
|
||||
static file_analysis::Analyzer* InstantiateAnalyzer(RecordValPtr args, file_analysis::File* file);
|
||||
|
||||
protected:
|
||||
// Overridden from Zeek's file analyzer.
|
||||
void Init() override;
|
||||
void Done() override;
|
||||
bool DeliverStream(const u_char* data, uint64_t len) override;
|
||||
bool Undelivered(uint64_t offset, uint64_t len) override;
|
||||
bool EndOfFile() override;
|
||||
|
||||
/**
|
||||
* Feeds a chunk of data into parsing.
|
||||
*
|
||||
* @param len number of bytes valid in *data*
|
||||
* @param data pointer to data
|
||||
* @return true if processing succeeded, false if an error occurred that
|
||||
* stopped parsing
|
||||
*/
|
||||
bool Process(int len, const u_char* data);
|
||||
|
||||
/**
|
||||
* Finalizes parsing. After calling this, no more data can be passed into
|
||||
* Process().
|
||||
*/
|
||||
void Finish();
|
||||
|
||||
/** Records a debug message. */
|
||||
void DebugMsg(const std::string& msg) { _state.DebugMsg(msg); }
|
||||
|
||||
private:
|
||||
FileState _state;
|
||||
};
|
||||
|
||||
} // namespace zeek::spicy::rt
|
920
src/spicy/manager.cc
Normal file
920
src/spicy/manager.cc
Normal file
|
@ -0,0 +1,920 @@
|
|||
// See the file "COPYING" in the main distribution directory for copyright.
|
||||
|
||||
#include "zeek/spicy/manager.h"
|
||||
|
||||
#include <dlfcn.h>
|
||||
#include <glob.h>
|
||||
|
||||
#include <exception>
|
||||
#include <utility>
|
||||
|
||||
#include <hilti/rt/autogen/version.h>
|
||||
#include <hilti/rt/configuration.h>
|
||||
#include <hilti/rt/filesystem.h>
|
||||
#include <hilti/rt/fmt.h>
|
||||
#include <hilti/rt/init.h>
|
||||
#include <hilti/rt/library.h>
|
||||
#include <hilti/rt/logging.h>
|
||||
#include <hilti/rt/types/vector.h>
|
||||
#include <hilti/rt/util.h>
|
||||
|
||||
#include <spicy/rt/configuration.h>
|
||||
#include <spicy/rt/init.h>
|
||||
#include <spicy/rt/parser.h>
|
||||
|
||||
#include <hilti/autogen/config.h>
|
||||
|
||||
#include <zeek/analyzer/Manager.h>
|
||||
#include <zeek/file_analysis/Manager.h>
|
||||
#include <zeek/packet_analysis/Manager.h>
|
||||
|
||||
#include "zeek/DebugLogger.h"
|
||||
#include "zeek/spicy/file-analyzer.h"
|
||||
#include "zeek/spicy/packet-analyzer.h"
|
||||
#include "zeek/spicy/protocol-analyzer.h"
|
||||
#include "zeek/util-config.h"
|
||||
|
||||
using namespace zeek;
|
||||
using namespace zeek::spicy;
|
||||
|
||||
// Split an potentially scoped ID into namespace and local part.
|
||||
static std::pair<std::string, std::string> parseID(const std::string& s) {
|
||||
if ( auto i = s.rfind("::"); i != std::string::npos )
|
||||
return std::make_pair(s.substr(0, i), s.substr(i + 2));
|
||||
else
|
||||
return std::make_pair("", s);
|
||||
}
|
||||
|
||||
Manager::~Manager() {}
|
||||
|
||||
void Manager::registerProtocolAnalyzer(const std::string& name, hilti::rt::Protocol proto,
|
||||
const hilti::rt::Vector<hilti::rt::Port>& ports, const std::string& parser_orig,
|
||||
const std::string& parser_resp, const std::string& replaces,
|
||||
const std::string& linker_scope) {
|
||||
SPICY_DEBUG(hilti::rt::fmt("Have Spicy protocol analyzer %s", name));
|
||||
|
||||
ProtocolAnalyzerInfo info;
|
||||
info.name_analyzer = name;
|
||||
info.name_parser_orig = parser_orig;
|
||||
info.name_parser_resp = parser_resp;
|
||||
info.name_replaces = replaces;
|
||||
info.name_zeek = hilti::rt::replace(name, "::", "_");
|
||||
info.name_zeekygen = hilti::rt::fmt("<Spicy-%s>", name);
|
||||
info.protocol = proto;
|
||||
info.ports = ports;
|
||||
info.linker_scope = linker_scope;
|
||||
|
||||
// We may have that analyzer already iff it was previously pre-registered
|
||||
// without a linker scope. We'll then only set the scope now.
|
||||
if ( auto t = _analyzer_name_to_tag_type.find(info.name_zeek); t != _analyzer_name_to_tag_type.end() ) {
|
||||
SPICY_DEBUG(hilti::rt::fmt("Updating already registered protocol analyzer %s", name));
|
||||
|
||||
auto& existing = _protocol_analyzers_by_type.at(t->second);
|
||||
assert(existing.name_analyzer == name);
|
||||
existing.linker_scope = info.linker_scope;
|
||||
|
||||
// If the infos don't match now, we have two separate definitions.
|
||||
if ( info != existing )
|
||||
reporter->FatalError("redefinition of protocol analyzer %s", info.name_analyzer.c_str());
|
||||
|
||||
return;
|
||||
}
|
||||
|
||||
analyzer::Component::factory_callback factory = nullptr;
|
||||
|
||||
#if SPICY_VERSION_NUMBER >= 10700
|
||||
auto proto_ = proto.value();
|
||||
#else
|
||||
auto proto_ = proto;
|
||||
#endif
|
||||
|
||||
switch ( proto_ ) {
|
||||
case hilti::rt::Protocol::TCP: factory = spicy::rt::TCP_Analyzer::InstantiateAnalyzer; break;
|
||||
case hilti::rt::Protocol::UDP: factory = spicy::rt::UDP_Analyzer::InstantiateAnalyzer; break;
|
||||
default: reporter->Error("unsupported protocol in analyzer"); return;
|
||||
}
|
||||
|
||||
auto c = new ::zeek::analyzer::Component(info.name_zeek, factory, 0);
|
||||
AddComponent(c);
|
||||
|
||||
// Hack to prevent Zeekygen from reporting the ID as not having a
|
||||
// location during the following initialization step.
|
||||
::zeek::detail::zeekygen_mgr->Script(info.name_zeekygen);
|
||||
::zeek::detail::set_location(makeLocation(info.name_zeekygen));
|
||||
|
||||
// TODO: Should Zeek do this? It has run component intiialization at
|
||||
// this point already, so ours won't get initialized anymore.
|
||||
c->Initialize();
|
||||
|
||||
trackComponent(c, c->Tag().Type()); // Must come after Initialize().
|
||||
|
||||
info.type = c->Tag().Type();
|
||||
_protocol_analyzers_by_type.resize(info.type + 1);
|
||||
_protocol_analyzers_by_type[info.type] = info;
|
||||
}
|
||||
|
||||
void Manager::registerFileAnalyzer(const std::string& name, const hilti::rt::Vector<std::string>& mime_types,
|
||||
const std::string& parser, const std::string& replaces,
|
||||
const std::string& linker_scope) {
|
||||
SPICY_DEBUG(hilti::rt::fmt("Have Spicy file analyzer %s", name));
|
||||
|
||||
FileAnalyzerInfo info;
|
||||
info.name_analyzer = name;
|
||||
info.name_parser = parser;
|
||||
info.name_replaces = replaces;
|
||||
info.name_zeek = hilti::rt::replace(name, "::", "_");
|
||||
info.name_zeekygen = hilti::rt::fmt("<Spicy-%s>", name);
|
||||
info.mime_types = mime_types;
|
||||
info.linker_scope = linker_scope;
|
||||
|
||||
// We may have that analyzer already iff it was previously pre-registered
|
||||
// without a linker scope. We'll then only set the scope now.
|
||||
if ( auto t = _analyzer_name_to_tag_type.find(info.name_zeek); t != _analyzer_name_to_tag_type.end() ) {
|
||||
SPICY_DEBUG(hilti::rt::fmt("Updating already registered packet analyzer %s", name));
|
||||
|
||||
auto& existing = _file_analyzers_by_type.at(t->second);
|
||||
existing.linker_scope = info.linker_scope;
|
||||
|
||||
// If the infos don't match now, we have two separate definitions.
|
||||
if ( info != existing )
|
||||
reporter->FatalError("redefinition of file analyzer %s", info.name_analyzer.c_str());
|
||||
|
||||
return;
|
||||
}
|
||||
|
||||
auto c = new ::zeek::file_analysis::Component(info.name_zeek, spicy::rt::FileAnalyzer::InstantiateAnalyzer, 0);
|
||||
AddComponent(c);
|
||||
|
||||
// Hack to prevent Zeekygen from reporting the ID as not having a
|
||||
// location during the following initialization step.
|
||||
::zeek::detail::zeekygen_mgr->Script(info.name_zeekygen);
|
||||
::zeek::detail::set_location(makeLocation(info.name_zeekygen));
|
||||
|
||||
// TODO: Should Zeek do this? It has run component intiialization at
|
||||
// this point already, so ours won't get initialized anymore.
|
||||
c->Initialize();
|
||||
|
||||
trackComponent(c, c->Tag().Type()); // Must come after Initialize().
|
||||
|
||||
info.type = c->Tag().Type();
|
||||
_file_analyzers_by_type.resize(info.type + 1);
|
||||
_file_analyzers_by_type[info.type] = info;
|
||||
}
|
||||
|
||||
void Manager::registerPacketAnalyzer(const std::string& name, const std::string& parser, const std::string& replaces,
|
||||
const std::string& linker_scope) {
|
||||
SPICY_DEBUG(hilti::rt::fmt("Have Spicy packet analyzer %s", name));
|
||||
|
||||
PacketAnalyzerInfo info;
|
||||
info.name_analyzer = name;
|
||||
info.name_replaces = replaces;
|
||||
info.name_parser = parser;
|
||||
info.name_zeek = hilti::rt::replace(name, "::", "_");
|
||||
info.name_zeekygen = hilti::rt::fmt("<Spicy-%s>", info.name_zeek);
|
||||
info.linker_scope = linker_scope;
|
||||
|
||||
// We may have that analyzer already iff it was previously pre-registered
|
||||
// without a linker scope. We'll then set the scope now.
|
||||
if ( auto t = _analyzer_name_to_tag_type.find(info.name_zeek); t != _analyzer_name_to_tag_type.end() ) {
|
||||
SPICY_DEBUG(hilti::rt::fmt("Updating already registered packet analyzer %s", name));
|
||||
|
||||
auto& existing = _packet_analyzers_by_type.at(t->second);
|
||||
assert(existing.name_analyzer == name);
|
||||
existing.linker_scope = info.linker_scope;
|
||||
|
||||
// If the infos don't match now, we have two separate definitions.
|
||||
if ( info != existing )
|
||||
reporter->FatalError("redefinition of packet analyzer %s", info.name_analyzer.c_str());
|
||||
|
||||
return;
|
||||
}
|
||||
|
||||
auto instantiate = [info]() -> packet_analysis::AnalyzerPtr {
|
||||
return spicy::rt::PacketAnalyzer::Instantiate(info.name_zeek);
|
||||
};
|
||||
|
||||
auto c = new ::zeek::packet_analysis::Component(info.name_zeek, instantiate, 0);
|
||||
AddComponent(c);
|
||||
|
||||
// Hack to prevent Zeekygen from reporting the ID as not having a
|
||||
// location during the following initialization step.
|
||||
::zeek::detail::zeekygen_mgr->Script(info.name_zeekygen);
|
||||
::zeek::detail::set_location(makeLocation(info.name_zeekygen));
|
||||
|
||||
// TODO: Should Zeek do this? It has run component intialization at
|
||||
// this point already, so ours won't get initialized anymore.
|
||||
c->Initialize();
|
||||
|
||||
trackComponent(c, c->Tag().Type()); // Must come after Initialize().
|
||||
|
||||
info.type = c->Tag().Type();
|
||||
_packet_analyzers_by_type.resize(info.type + 1);
|
||||
_packet_analyzers_by_type[info.type] = info;
|
||||
}
|
||||
|
||||
void Manager::registerType(const std::string& id, const TypePtr& type) {
|
||||
auto [ns, local] = parseID(id);
|
||||
|
||||
if ( const auto& old = detail::lookup_ID(local.c_str(), ns.c_str()) ) {
|
||||
// This is most likely to trigger for IDs that other Spicy modules
|
||||
// register. If we two Spicy modules need the same type, that's ok as
|
||||
// long as they match.
|
||||
if ( ! old->IsType() ) {
|
||||
reporter->Error("Zeek type registration failed for '%s': ID already exists, but is not a type", id.c_str());
|
||||
return;
|
||||
}
|
||||
|
||||
if ( ! zeek::same_type(type, old->GetType()) ) {
|
||||
reporter->Error("Zeek type registration failed for '%s': Type already exists, but differs", id.c_str());
|
||||
}
|
||||
|
||||
SPICY_DEBUG(hilti::rt::fmt("Not re-registering Zeek type %s: identical type already exists", id));
|
||||
return;
|
||||
}
|
||||
|
||||
SPICY_DEBUG(hilti::rt::fmt("Registering Zeek type %s", id));
|
||||
auto zeek_id = detail::install_ID(local.c_str(), ns.c_str(), true, true);
|
||||
zeek_id->SetType(type);
|
||||
zeek_id->MakeType();
|
||||
AddBifItem(id, ::zeek::plugin::BifItem::TYPE);
|
||||
}
|
||||
|
||||
TypePtr Manager::findType(const std::string& id) const {
|
||||
auto [ns, local] = parseID(id);
|
||||
|
||||
auto zid = detail::lookup_ID(local.c_str(), ns.c_str());
|
||||
if ( ! zid )
|
||||
return nullptr;
|
||||
|
||||
if ( ! zid->IsType() )
|
||||
return nullptr;
|
||||
|
||||
return zid->GetType();
|
||||
}
|
||||
|
||||
void Manager::registerEvent(const std::string& name) {
|
||||
// Create a Zeek handler for the event.
|
||||
event_registry->Register(name);
|
||||
|
||||
// Install the ID into the corresponding namespace and export it.
|
||||
auto n = ::hilti::rt::split(name, "::");
|
||||
std::string mod;
|
||||
|
||||
if ( n.size() > 1 )
|
||||
mod = n.front();
|
||||
else
|
||||
mod = detail::GLOBAL_MODULE_NAME;
|
||||
|
||||
if ( auto id = detail::lookup_ID(name.c_str(), mod.c_str(), false, false, false) ) {
|
||||
// Auto-export IDs that already exist.
|
||||
id->SetExport();
|
||||
_events[name] = id;
|
||||
}
|
||||
else
|
||||
// This installs & exports the ID, but it doesn't set its type yet.
|
||||
// That will happen as handlers get defined. If there are no handlers,
|
||||
// we set a dummy type in the plugin's InitPostScript
|
||||
_events[name] = detail::install_ID(name.c_str(), mod.c_str(), false, true);
|
||||
}
|
||||
|
||||
const ::spicy::rt::Parser* Manager::parserForProtocolAnalyzer(const Tag& tag, bool is_orig) {
|
||||
if ( is_orig )
|
||||
return _protocol_analyzers_by_type[tag.Type()].parser_orig;
|
||||
else
|
||||
return _protocol_analyzers_by_type[tag.Type()].parser_resp;
|
||||
}
|
||||
|
||||
const ::spicy::rt::Parser* Manager::parserForFileAnalyzer(const Tag& tag) {
|
||||
return _file_analyzers_by_type[tag.Type()].parser;
|
||||
}
|
||||
|
||||
const ::spicy::rt::Parser* Manager::parserForPacketAnalyzer(const Tag& tag) {
|
||||
return _packet_analyzers_by_type[tag.Type()].parser;
|
||||
}
|
||||
|
||||
Tag Manager::tagForProtocolAnalyzer(const Tag& tag) {
|
||||
if ( auto r = _protocol_analyzers_by_type[tag.Type()].replaces )
|
||||
return r;
|
||||
else
|
||||
return tag;
|
||||
}
|
||||
|
||||
Tag Manager::tagForFileAnalyzer(const Tag& tag) {
|
||||
if ( auto r = _file_analyzers_by_type[tag.Type()].replaces )
|
||||
return r;
|
||||
else
|
||||
return tag;
|
||||
}
|
||||
|
||||
Tag Manager::tagForPacketAnalyzer(const Tag& tag) {
|
||||
if ( auto r = _packet_analyzers_by_type[tag.Type()].replaces )
|
||||
return r;
|
||||
else
|
||||
return tag;
|
||||
}
|
||||
|
||||
bool Manager::toggleProtocolAnalyzer(const Tag& tag, bool enable) {
|
||||
auto type = tag.Type();
|
||||
|
||||
if ( type >= _protocol_analyzers_by_type.size() )
|
||||
return false;
|
||||
|
||||
const auto& analyzer = _protocol_analyzers_by_type[type];
|
||||
|
||||
if ( ! analyzer.type )
|
||||
// not set -> not ours
|
||||
return false;
|
||||
|
||||
if ( enable ) {
|
||||
SPICY_DEBUG(hilti::rt::fmt("Enabling Spicy protocol analyzer %s", analyzer.name_analyzer));
|
||||
analyzer_mgr->EnableAnalyzer(tag);
|
||||
|
||||
if ( analyzer.replaces ) {
|
||||
SPICY_DEBUG(hilti::rt::fmt("Disabling standard protocol analyzer %s", analyzer.name_analyzer));
|
||||
analyzer_mgr->DisableAnalyzer(analyzer.replaces);
|
||||
}
|
||||
}
|
||||
else {
|
||||
SPICY_DEBUG(hilti::rt::fmt("Disabling Spicy protocol analyzer %s", analyzer.name_analyzer));
|
||||
analyzer_mgr->DisableAnalyzer(tag);
|
||||
|
||||
if ( analyzer.replaces ) {
|
||||
SPICY_DEBUG(hilti::rt::fmt("Re-enabling standard protocol analyzer %s", analyzer.name_analyzer));
|
||||
analyzer_mgr->EnableAnalyzer(analyzer.replaces);
|
||||
}
|
||||
}
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
bool Manager::toggleFileAnalyzer(const Tag& tag, bool enable) {
|
||||
auto type = tag.Type();
|
||||
|
||||
if ( type >= _file_analyzers_by_type.size() )
|
||||
return false;
|
||||
|
||||
const auto& analyzer = _file_analyzers_by_type[type];
|
||||
|
||||
if ( ! analyzer.type )
|
||||
// not set -> not ours
|
||||
return false;
|
||||
|
||||
file_analysis::Component* component = file_mgr->Lookup(tag);
|
||||
file_analysis::Component* component_replaces = analyzer.replaces ? file_mgr->Lookup(analyzer.replaces) : nullptr;
|
||||
|
||||
if ( ! component ) {
|
||||
// Shouldn't really happen.
|
||||
reporter->InternalError("failed to lookup file analyzer component");
|
||||
return false;
|
||||
}
|
||||
|
||||
if ( enable ) {
|
||||
SPICY_DEBUG(hilti::rt::fmt("Enabling Spicy file analyzer %s", analyzer.name_analyzer));
|
||||
component->SetEnabled(true);
|
||||
|
||||
if ( component_replaces ) {
|
||||
SPICY_DEBUG(hilti::rt::fmt("Disabling standard file analyzer %s", analyzer.name_analyzer));
|
||||
component_replaces->SetEnabled(false);
|
||||
}
|
||||
}
|
||||
else {
|
||||
SPICY_DEBUG(hilti::rt::fmt("Disabling Spicy file analyzer %s", analyzer.name_analyzer));
|
||||
component->SetEnabled(false);
|
||||
|
||||
if ( component_replaces ) {
|
||||
SPICY_DEBUG(hilti::rt::fmt("Enabling standard file analyzer %s", analyzer.name_analyzer));
|
||||
component_replaces->SetEnabled(true);
|
||||
}
|
||||
}
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
bool Manager::togglePacketAnalyzer(const Tag& tag, bool enable) {
|
||||
auto type = tag.Type();
|
||||
|
||||
if ( type >= _packet_analyzers_by_type.size() )
|
||||
return false;
|
||||
|
||||
const auto& analyzer = _packet_analyzers_by_type[type];
|
||||
|
||||
if ( ! analyzer.type )
|
||||
// not set -> not ours
|
||||
return false;
|
||||
|
||||
packet_analysis::Component* component = packet_mgr->Lookup(tag);
|
||||
packet_analysis::Component* component_replaces =
|
||||
analyzer.replaces ? packet_mgr->Lookup(analyzer.replaces) : nullptr;
|
||||
|
||||
if ( ! component ) {
|
||||
// Shouldn't really happen.
|
||||
reporter->InternalError("failed to lookup packet analyzer component");
|
||||
return false;
|
||||
}
|
||||
|
||||
if ( enable ) {
|
||||
SPICY_DEBUG(hilti::rt::fmt("Enabling Spicy packet analyzer %s", analyzer.name_analyzer));
|
||||
component->SetEnabled(true);
|
||||
|
||||
if ( component_replaces ) {
|
||||
SPICY_DEBUG(hilti::rt::fmt("Disabling standard packet analyzer %s", analyzer.name_analyzer));
|
||||
component_replaces->SetEnabled(false);
|
||||
}
|
||||
}
|
||||
else {
|
||||
SPICY_DEBUG(hilti::rt::fmt("Disabling Spicy packet analyzer %s", analyzer.name_analyzer));
|
||||
component->SetEnabled(false);
|
||||
|
||||
if ( component_replaces ) {
|
||||
SPICY_DEBUG(hilti::rt::fmt("Enabling standard packet analyzer %s", analyzer.name_analyzer));
|
||||
component_replaces->SetEnabled(true);
|
||||
}
|
||||
}
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
bool Manager::toggleAnalyzer(EnumVal* tag, bool enable) {
|
||||
if ( tag->GetType() == analyzer_mgr->GetTagType() ) {
|
||||
if ( auto analyzer = analyzer_mgr->Lookup(tag) )
|
||||
return toggleProtocolAnalyzer(analyzer->Tag(), enable);
|
||||
else
|
||||
return false;
|
||||
}
|
||||
|
||||
if ( tag->GetType() == file_mgr->GetTagType() ) {
|
||||
if ( auto analyzer = file_mgr->Lookup(tag) )
|
||||
return toggleFileAnalyzer(analyzer->Tag(), enable);
|
||||
else
|
||||
return false;
|
||||
}
|
||||
|
||||
if ( tag->GetType() == packet_mgr->GetTagType() ) {
|
||||
if ( auto analyzer = packet_mgr->Lookup(tag) )
|
||||
return togglePacketAnalyzer(analyzer->Tag(), enable);
|
||||
else
|
||||
return false;
|
||||
}
|
||||
|
||||
return false;
|
||||
}
|
||||
|
||||
static std::unique_ptr<detail::Location> _makeLocation(const std::string& location) {
|
||||
static std::set<std::string> filenames; // see comment below in parse_location
|
||||
|
||||
auto parse_location = [](const auto& s) -> std::unique_ptr<detail::Location> {
|
||||
// This is not so great; In the HILTI runtome we pass locations
|
||||
// around as string. To pass them to Zeek, we need to unsplit the
|
||||
// strings into file name and line number. Zeek also won't clean up
|
||||
// the file names, so we need to track them ourselves.
|
||||
auto x = hilti::rt::split(s, ":");
|
||||
if ( x[0].empty() )
|
||||
return nullptr;
|
||||
|
||||
auto loc = std::make_unique<detail::Location>();
|
||||
loc->filename = filenames.insert(std::string(x[0])).first->c_str(); // we retain ownership
|
||||
|
||||
if ( x.size() >= 2 ) {
|
||||
auto y = hilti::rt::split(x[1], "-");
|
||||
if ( y.size() >= 2 ) {
|
||||
loc->first_line = std::stoi(std::string(y[0]));
|
||||
loc->last_line = std::stoi(std::string(y[1]));
|
||||
}
|
||||
else if ( y[0].size() )
|
||||
loc->first_line = loc->last_line = std::stoi(std::string(y[0]));
|
||||
}
|
||||
|
||||
return loc;
|
||||
};
|
||||
|
||||
if ( location.size() )
|
||||
return parse_location(location);
|
||||
else if ( auto hilti_location = hilti::rt::debug::location() )
|
||||
return parse_location(hilti_location);
|
||||
else
|
||||
return nullptr;
|
||||
}
|
||||
|
||||
void Manager::analyzerError(analyzer::Analyzer* a, const std::string& msg, const std::string& location) {
|
||||
auto zeek_location = _makeLocation(location);
|
||||
reporter->PushLocation(zeek_location.get());
|
||||
reporter->AnalyzerError(a, "%s", msg.c_str());
|
||||
reporter->PopLocation();
|
||||
}
|
||||
|
||||
void Manager::analyzerError(file_analysis::Analyzer* a, const std::string& msg, const std::string& location) {
|
||||
auto zeek_location = _makeLocation(location);
|
||||
reporter->PushLocation(zeek_location.get());
|
||||
|
||||
// We don't have an reporter error for file analyzers, so we log this as a
|
||||
// weird instead.
|
||||
if ( a && a->GetFile() )
|
||||
reporter->Weird(a->GetFile(), "file_error", msg.c_str());
|
||||
else
|
||||
reporter->Weird("file_error", msg.c_str());
|
||||
|
||||
reporter->PopLocation();
|
||||
|
||||
if ( a )
|
||||
a->SetSkip(1); // Imitate what AnalyzerError() does for protocol analyzers.
|
||||
}
|
||||
|
||||
void Manager::analyzerError(packet_analysis::Analyzer* a, const std::string& msg, const std::string& location) {
|
||||
auto zeek_location = _makeLocation(location);
|
||||
reporter->PushLocation(zeek_location.get());
|
||||
// We don't have an reporter error for packet analyzers, so we log
|
||||
// this as a weird instead.
|
||||
reporter->Weird("packet_error", msg.c_str());
|
||||
reporter->PopLocation();
|
||||
}
|
||||
|
||||
plugin::Configuration Manager::Configure() {
|
||||
::zeek::plugin::Configuration config;
|
||||
config.name = "Zeek::Spicy";
|
||||
config.description = "Support for Spicy parsers (*.hlto)";
|
||||
|
||||
EnableHook(::zeek::plugin::HOOK_LOAD_FILE);
|
||||
|
||||
return config;
|
||||
}
|
||||
|
||||
void Manager::InitPreScript() {
|
||||
SPICY_DEBUG("Beginning pre-script initialization");
|
||||
|
||||
#if SPICY_VERSION_NUMBER >= 10700
|
||||
hilti::rt::executeManualPreInits();
|
||||
#endif
|
||||
|
||||
autoDiscoverModules();
|
||||
|
||||
SPICY_DEBUG("Done with pre-script initialization");
|
||||
}
|
||||
|
||||
// Returns a port's Zeek-side transport protocol.
|
||||
static ::TransportProto transport_protocol(const hilti::rt::Port port) {
|
||||
#if SPICY_VERSION_NUMBER >= 10700
|
||||
auto proto = port.protocol().value();
|
||||
#else
|
||||
auto proto = port.protocol();
|
||||
#endif
|
||||
|
||||
switch ( proto ) {
|
||||
case hilti::rt::Protocol::TCP: return ::TransportProto::TRANSPORT_TCP;
|
||||
case hilti::rt::Protocol::UDP: return ::TransportProto::TRANSPORT_UDP;
|
||||
case hilti::rt::Protocol::ICMP: return ::TransportProto::TRANSPORT_ICMP;
|
||||
default:
|
||||
reporter->InternalError("unsupported transport protocol in port '%s' for Zeek conversion",
|
||||
std::string(port).c_str());
|
||||
return ::TransportProto::TRANSPORT_UNKNOWN;
|
||||
}
|
||||
}
|
||||
|
||||
static void hook_accept_input() {
|
||||
auto cookie = static_cast<rt::Cookie*>(hilti::rt::context::cookie());
|
||||
assert(cookie);
|
||||
|
||||
if ( auto x = cookie->protocol ) {
|
||||
auto tag = spicy_mgr->tagForProtocolAnalyzer(x->analyzer->GetAnalyzerTag());
|
||||
SPICY_DEBUG(hilti::rt::fmt("confirming protocol %s", tag.AsString()));
|
||||
return x->analyzer->AnalyzerConfirmation(tag);
|
||||
}
|
||||
}
|
||||
|
||||
static void hook_decline_input(const std::string& reason) {
|
||||
auto cookie = static_cast<rt::Cookie*>(hilti::rt::context::cookie());
|
||||
assert(cookie);
|
||||
|
||||
if ( auto x = cookie->protocol ) {
|
||||
auto tag = spicy_mgr->tagForProtocolAnalyzer(x->analyzer->GetAnalyzerTag());
|
||||
SPICY_DEBUG(hilti::rt::fmt("rejecting protocol %s", tag.AsString()));
|
||||
return x->analyzer->AnalyzerViolation("protocol rejected", nullptr, 0, tag);
|
||||
}
|
||||
}
|
||||
|
||||
void Manager::InitPostScript() {
|
||||
SPICY_DEBUG("Beginning post-script initialization");
|
||||
|
||||
disableReplacedAnalyzers();
|
||||
|
||||
// If there's no handler for one of our events, it won't have received a
|
||||
// type. Give it a dummy event type in that case, so that we don't walk
|
||||
// around with a nullptr.
|
||||
for ( const auto& [name, id] : _events ) {
|
||||
if ( ! id->GetType() ) {
|
||||
auto args = make_intrusive<RecordType>(new type_decl_list());
|
||||
auto et = make_intrusive<FuncType>(std::move(args), base_type(TYPE_VOID), FUNC_FLAVOR_EVENT);
|
||||
id->SetType(std::move(et));
|
||||
}
|
||||
}
|
||||
|
||||
// Init runtime, which will trigger all initialization code to execute.
|
||||
SPICY_DEBUG("Initializing Spicy runtime");
|
||||
|
||||
auto hilti_config = hilti::rt::configuration::get();
|
||||
|
||||
if ( id::find_const("Spicy::enable_print")->AsBool() ) // NOLINT(clang-analyzer-cplusplus.NewDeleteLeaks)
|
||||
hilti_config.cout = std::cout;
|
||||
else
|
||||
hilti_config.cout.reset();
|
||||
|
||||
if ( id::find_const("Spicy::enable_profiling")->AsBool() )
|
||||
#if SPICY_VERSION_NUMBER >= 10800
|
||||
hilti_config.enable_profiling = true;
|
||||
#else
|
||||
std::cerr << "Profiling is not supported with this version of Spicy, ignoring "
|
||||
"'Spicy::enable_profiling'\n";
|
||||
#endif
|
||||
|
||||
hilti_config.abort_on_exceptions = id::find_const("Spicy::abort_on_exceptions")->AsBool();
|
||||
hilti_config.show_backtraces = id::find_const("Spicy::show_backtraces")->AsBool();
|
||||
|
||||
hilti::rt::configuration::set(hilti_config);
|
||||
|
||||
#if SPICY_VERSION_NUMBER >= 10700
|
||||
auto spicy_config = ::spicy::rt::configuration::get();
|
||||
spicy_config.hook_accept_input = hook_accept_input;
|
||||
spicy_config.hook_decline_input = hook_decline_input;
|
||||
::spicy::rt::configuration::set(std::move(spicy_config));
|
||||
#endif
|
||||
|
||||
try {
|
||||
::hilti::rt::init();
|
||||
::spicy::rt::init();
|
||||
} catch ( const hilti::rt::Exception& e ) {
|
||||
std::cerr << hilti::rt::fmt("uncaught runtime exception %s during initialization: %s",
|
||||
hilti::rt::demangle(typeid(e).name()), e.what())
|
||||
<< std::endl;
|
||||
exit(1);
|
||||
} catch ( const std::runtime_error& e ) {
|
||||
std::cerr << hilti::rt::fmt("uncaught C++ exception %s during initialization: %s",
|
||||
hilti::rt::demangle(typeid(e).name()), e.what())
|
||||
<< std::endl;
|
||||
exit(1);
|
||||
}
|
||||
|
||||
// Fill in the parser information now that we derived from the ASTs.
|
||||
auto find_parser = [](const std::string& analyzer, const std::string& parser,
|
||||
const std::string& linker_scope) -> const ::spicy::rt::Parser* {
|
||||
if ( parser.empty() )
|
||||
return nullptr;
|
||||
|
||||
for ( auto p : ::spicy::rt::parsers() ) {
|
||||
if ( p->name == parser && p->linker_scope == linker_scope )
|
||||
return p;
|
||||
}
|
||||
|
||||
reporter->InternalError("Unknown Spicy parser '%s' requested by analyzer '%s'", parser.c_str(),
|
||||
analyzer.c_str());
|
||||
|
||||
return nullptr; // cannot be reached
|
||||
};
|
||||
|
||||
for ( auto& p : _protocol_analyzers_by_type ) {
|
||||
if ( p.type == 0 )
|
||||
// vector element not set
|
||||
continue;
|
||||
|
||||
SPICY_DEBUG(hilti::rt::fmt("Registering %s protocol analyzer %s with Zeek", p.protocol, p.name_analyzer));
|
||||
|
||||
p.parser_orig = find_parser(p.name_analyzer, p.name_parser_orig, p.linker_scope);
|
||||
p.parser_resp = find_parser(p.name_analyzer, p.name_parser_resp, p.linker_scope);
|
||||
|
||||
// Register analyzer for its well-known ports.
|
||||
auto tag = analyzer_mgr->GetAnalyzerTag(p.name_zeek.c_str());
|
||||
if ( ! tag )
|
||||
reporter->InternalError("cannot get analyzer tag for '%s'", p.name_analyzer.c_str());
|
||||
|
||||
for ( auto port : p.ports ) {
|
||||
SPICY_DEBUG(hilti::rt::fmt(" Scheduling analyzer for port %s", port));
|
||||
analyzer_mgr->RegisterAnalyzerForPort(tag, transport_protocol(port), port.port());
|
||||
}
|
||||
|
||||
if ( p.parser_resp ) {
|
||||
for ( auto port : p.parser_resp->ports ) {
|
||||
if ( port.direction != ::spicy::rt::Direction::Both &&
|
||||
port.direction != ::spicy::rt::Direction::Responder )
|
||||
continue;
|
||||
|
||||
SPICY_DEBUG(hilti::rt::fmt(" Scheduling analyzer for port %s", port.port));
|
||||
analyzer_mgr->RegisterAnalyzerForPort(tag, transport_protocol(port.port), port.port.port());
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
for ( auto& p : _file_analyzers_by_type ) {
|
||||
if ( p.type == 0 )
|
||||
// vector element not set
|
||||
continue;
|
||||
|
||||
SPICY_DEBUG(hilti::rt::fmt("Registering file analyzer %s with Zeek", p.name_analyzer.c_str()));
|
||||
|
||||
p.parser = find_parser(p.name_analyzer, p.name_parser, p.linker_scope);
|
||||
|
||||
// Register analyzer for its MIME types.
|
||||
auto tag = file_mgr->GetComponentTag(p.name_zeek.c_str());
|
||||
if ( ! tag )
|
||||
reporter->InternalError("cannot get analyzer tag for '%s'", p.name_analyzer.c_str());
|
||||
|
||||
auto register_analyzer_for_mime_type = [&](auto tag, const std::string& mt) {
|
||||
SPICY_DEBUG(hilti::rt::fmt(" Scheduling analyzer for MIME type %s", mt));
|
||||
|
||||
// MIME types are registered in scriptland, so we'll raise an
|
||||
// event that will do it for us through a predefined handler.
|
||||
zeek::Args vals = Args();
|
||||
vals.emplace_back(tag.AsVal());
|
||||
vals.emplace_back(make_intrusive<StringVal>(mt));
|
||||
EventHandlerPtr handler = event_registry->Register("spicy_analyzer_for_mime_type");
|
||||
event_mgr.Enqueue(handler, vals);
|
||||
};
|
||||
|
||||
for ( const auto& mt : p.mime_types )
|
||||
register_analyzer_for_mime_type(tag, mt);
|
||||
|
||||
if ( p.parser ) {
|
||||
for ( const auto& mt : p.parser->mime_types )
|
||||
register_analyzer_for_mime_type(tag, mt);
|
||||
}
|
||||
}
|
||||
|
||||
for ( auto& p : _packet_analyzers_by_type ) {
|
||||
if ( p.type == 0 )
|
||||
// vector element not set
|
||||
continue;
|
||||
|
||||
SPICY_DEBUG(hilti::rt::fmt("Registering packet analyzer %s with Zeek", p.name_analyzer.c_str()));
|
||||
p.parser = find_parser(p.name_analyzer, p.name_parser, p.linker_scope);
|
||||
}
|
||||
|
||||
SPICY_DEBUG("Done with post-script initialization");
|
||||
}
|
||||
|
||||
void Manager::Done() {
|
||||
SPICY_DEBUG("Shutting down Spicy runtime");
|
||||
::spicy::rt::done();
|
||||
hilti::rt::done();
|
||||
}
|
||||
|
||||
void Manager::loadModule(const hilti::rt::filesystem::path& path) {
|
||||
try {
|
||||
// If our auto discovery ends up finding the same module multiple times,
|
||||
// we ignore subsequent requests.
|
||||
std::error_code ec;
|
||||
auto canonical_path = hilti::rt::filesystem::canonical(path, ec);
|
||||
if ( ec )
|
||||
hilti::rt::fatalError(hilti::rt::fmt("could not compute canonical path for %s: %s", path, ec.message()));
|
||||
|
||||
if ( auto [library, inserted] = _libraries.insert({canonical_path, hilti::rt::Library(canonical_path)});
|
||||
inserted ) {
|
||||
SPICY_DEBUG(hilti::rt::fmt("Loading %s", canonical_path.native()));
|
||||
if ( auto load = library->second.open(); ! load )
|
||||
hilti::rt::fatalError(
|
||||
hilti::rt::fmt("could not open library path %s: %s", canonical_path, load.error()));
|
||||
}
|
||||
else {
|
||||
SPICY_DEBUG(hilti::rt::fmt("Ignoring duplicate loading request for %s", canonical_path.native()));
|
||||
}
|
||||
#if SPICY_VERSION_NUMBER >= 10700
|
||||
} catch ( const ::hilti::rt::UsageError& e ) {
|
||||
#else
|
||||
} catch ( const ::hilti::rt::UserException& e ) {
|
||||
#endif
|
||||
hilti::rt::fatalError(e.what());
|
||||
}
|
||||
}
|
||||
|
||||
int Manager::HookLoadFile(const LoadType type, const std::string& file, const std::string& resolved) {
|
||||
auto ext = hilti::rt::filesystem::path(file).extension();
|
||||
|
||||
if ( ext == ".hlto" ) {
|
||||
loadModule(file);
|
||||
return 1;
|
||||
}
|
||||
|
||||
if ( ext == ".spicy" || ext == ".evt" || ext == ".hlt" )
|
||||
reporter->FatalError("cannot load '%s': analyzers need to be precompiled with 'spicyz' ", file.c_str());
|
||||
|
||||
return -1;
|
||||
}
|
||||
|
||||
void Manager::searchModules(const std::string& paths) {
|
||||
for ( const auto& dir : hilti::rt::split(paths, ":") ) {
|
||||
auto trimmed_dir = hilti::rt::trim(dir);
|
||||
if ( trimmed_dir.empty() )
|
||||
continue;
|
||||
|
||||
std::error_code ec;
|
||||
if ( auto is_directory = hilti::rt::filesystem::is_directory(trimmed_dir, ec); ec || ! is_directory ) {
|
||||
SPICY_DEBUG(hilti::rt::fmt("Module directory %s cannot be read, skipping", trimmed_dir));
|
||||
continue;
|
||||
}
|
||||
|
||||
SPICY_DEBUG(hilti::rt::fmt("Searching %s for *.hlto", trimmed_dir));
|
||||
|
||||
auto it = hilti::rt::filesystem::recursive_directory_iterator(trimmed_dir, ec);
|
||||
if ( ! ec ) {
|
||||
while ( it != hilti::rt::filesystem::recursive_directory_iterator() ) {
|
||||
if ( it->is_regular_file() && it->path().extension() == ".hlto" )
|
||||
loadModule(it->path());
|
||||
|
||||
if ( it.increment(ec); ec ) {
|
||||
hilti::rt::warning(hilti::rt::fmt("Error iterating over %s, skipping any remaining files: %s",
|
||||
trimmed_dir, ec.message()));
|
||||
break;
|
||||
}
|
||||
}
|
||||
}
|
||||
else
|
||||
hilti::rt::warning(hilti::rt::fmt("Cannot iterate over %s, skipping: %s", trimmed_dir, ec.message()));
|
||||
}
|
||||
};
|
||||
|
||||
detail::Location Manager::makeLocation(const std::string& fname) {
|
||||
auto x = _locations.insert(fname);
|
||||
return detail::Location(x.first->c_str(), 0, 0, 0, 0);
|
||||
}
|
||||
|
||||
void Manager::autoDiscoverModules() {
|
||||
// Always search Zeek's plugin path for modules, that's where zkg puts
|
||||
// them.
|
||||
searchModules(util::zeek_plugin_path());
|
||||
|
||||
if ( auto search_paths = hilti::rt::getenv("ZEEK_SPICY_MODULE_PATH"); search_paths && search_paths->size() )
|
||||
// This overrides all other paths.
|
||||
searchModules(*search_paths);
|
||||
else
|
||||
searchModules(ZEEK_SPICY_MODULE_PATH);
|
||||
}
|
||||
|
||||
void Manager::disableReplacedAnalyzers() {
|
||||
for ( auto& info : _protocol_analyzers_by_type ) {
|
||||
if ( info.name_replaces.empty() )
|
||||
continue;
|
||||
|
||||
auto replaces = info.name_replaces.c_str();
|
||||
|
||||
if ( file_mgr->Lookup(replaces) || packet_mgr->Lookup(replaces) )
|
||||
reporter->FatalError("cannot replace '%s' analyzer with a protocol analyzer", replaces);
|
||||
|
||||
auto tag = analyzer_mgr->GetAnalyzerTag(replaces);
|
||||
if ( ! tag ) {
|
||||
SPICY_DEBUG(hilti::rt::fmt("%s is supposed to replace protocol analyzer %s, but that does not exist",
|
||||
info.name_analyzer, replaces));
|
||||
|
||||
continue;
|
||||
}
|
||||
|
||||
SPICY_DEBUG(hilti::rt::fmt("%s replaces existing protocol analyzer %s", info.name_analyzer, replaces));
|
||||
info.replaces = tag;
|
||||
analyzer_mgr->DisableAnalyzer(tag);
|
||||
}
|
||||
|
||||
for ( auto& info : _file_analyzers_by_type ) {
|
||||
if ( info.name_replaces.empty() )
|
||||
continue;
|
||||
|
||||
auto replaces = info.name_replaces.c_str();
|
||||
|
||||
if ( analyzer_mgr->Lookup(replaces) || packet_mgr->Lookup(replaces) )
|
||||
reporter->FatalError("cannot replace '%s' analyzer with a file analyzer", replaces);
|
||||
|
||||
auto component = file_mgr->Lookup(replaces);
|
||||
if ( ! component ) {
|
||||
SPICY_DEBUG(hilti::rt::fmt("%s is supposed to replace file analyzer %s, but that does not exist",
|
||||
info.name_analyzer, replaces));
|
||||
|
||||
continue;
|
||||
}
|
||||
|
||||
SPICY_DEBUG(hilti::rt::fmt("%s replaces existing file analyzer %s", info.name_analyzer, replaces));
|
||||
info.replaces = component->Tag();
|
||||
component->SetEnabled(false);
|
||||
}
|
||||
|
||||
for ( auto& info : _packet_analyzers_by_type ) {
|
||||
if ( info.name_replaces.empty() )
|
||||
continue;
|
||||
|
||||
auto replaces = info.name_replaces.c_str();
|
||||
|
||||
auto component = packet_mgr->Lookup(replaces);
|
||||
if ( ! component ) {
|
||||
SPICY_DEBUG(hilti::rt::fmt("%s is supposed to replace packet analyzer %s, but that does not exist",
|
||||
info.name_analyzer, replaces));
|
||||
|
||||
continue;
|
||||
}
|
||||
|
||||
SPICY_DEBUG(hilti::rt::fmt("%s replaces existing packet analyzer %s", info.name_analyzer, replaces));
|
||||
info.replaces = component->Tag();
|
||||
component->SetEnabled(false);
|
||||
}
|
||||
}
|
||||
|
||||
void Manager::trackComponent(plugin::Component* c, int32_t tag_type) {
|
||||
auto i = _analyzer_name_to_tag_type.insert({c->Name(), tag_type});
|
||||
if ( ! i.second )
|
||||
// We enforce on our end that an analyzer name can appear only once
|
||||
// across all types of analyzers. Makes things easier and avoids
|
||||
// confusion.
|
||||
reporter->FatalError("duplicate analyzer name '%s'", c->Name().c_str());
|
||||
}
|
413
src/spicy/manager.h
Normal file
413
src/spicy/manager.h
Normal file
|
@ -0,0 +1,413 @@
|
|||
// See the file "COPYING" in the main distribution directory for copyright.
|
||||
|
||||
#pragma once
|
||||
|
||||
#include <memory>
|
||||
#include <set>
|
||||
#include <string>
|
||||
#include <tuple>
|
||||
#include <unordered_map>
|
||||
#include <vector>
|
||||
|
||||
#include <hilti/rt/library.h>
|
||||
#include <hilti/rt/logging.h>
|
||||
#include <hilti/rt/types/port.h>
|
||||
|
||||
#include "zeek/Scope.h"
|
||||
#include "zeek/Tag.h"
|
||||
#include "zeek/plugin/Component.h"
|
||||
#include "zeek/plugin/Plugin.h"
|
||||
|
||||
// Macro helper to report Spicy debug messages. This forwards to
|
||||
// to both the Zeek logger and the Spicy runtime logger.
|
||||
#define SPICY_DEBUG(msg) ::zeek::spicy::log(msg);
|
||||
|
||||
namespace hilti::rt {
|
||||
class Port;
|
||||
struct Protocol;
|
||||
} // namespace hilti::rt
|
||||
|
||||
namespace spicy::rt {
|
||||
struct Parser;
|
||||
}
|
||||
|
||||
namespace zeek {
|
||||
|
||||
namespace analyzer {
|
||||
class Analyzer;
|
||||
}
|
||||
|
||||
namespace file_analysis {
|
||||
class Analyzer;
|
||||
}
|
||||
|
||||
namespace packet_analysis {
|
||||
class Analyzer;
|
||||
}
|
||||
|
||||
namespace spicy {
|
||||
|
||||
// Backend to log debug messages.
|
||||
inline void log(const std::string& msg) {
|
||||
DBG_LOG(DBG_SPICY, "%s", msg.c_str());
|
||||
|
||||
if ( hilti::rt::isInitialized() )
|
||||
HILTI_RT_DEBUG("zeek", msg);
|
||||
}
|
||||
|
||||
|
||||
/* Top-level entry point for Spicy functionality. */
|
||||
class Manager : public zeek::plugin::Plugin {
|
||||
public:
|
||||
Manager() {}
|
||||
virtual ~Manager();
|
||||
|
||||
/**
|
||||
* Runtime method to register a protocol analyzer with its Zeek-side
|
||||
* configuration. This is called at startup by generated Spicy code for
|
||||
* each protocol analyzer defined in an EVT file.
|
||||
*
|
||||
* @param name name of the analyzer as defined in its EVT file
|
||||
* @param proto analyzer's transport-layer protocol
|
||||
* @param prts well-known ports for the analyzer; it'll be activated automatically for these
|
||||
* @param parser_orig name of the Spicy parser for the originator side; must match the name that
|
||||
* Spicy registers the unit's parser with
|
||||
* @param parser_resp name of the Spicy parser for the originator side; must match the name that
|
||||
* Spicy registers the unit's parser with
|
||||
* @param replaces optional name of existing Zeek analyzer that this one replaces; the Zeek
|
||||
* analyzer will automatically be disabled
|
||||
* @param linker_scope scope of current HLTO file, which will restrict visibility of the
|
||||
* registration
|
||||
*/
|
||||
void registerProtocolAnalyzer(const std::string& name, hilti::rt::Protocol proto,
|
||||
const hilti::rt::Vector<hilti::rt::Port>& ports, const std::string& parser_orig,
|
||||
const std::string& parser_resp, const std::string& replaces,
|
||||
const std::string& linker_scope);
|
||||
|
||||
/**
|
||||
* Runtime method to register a file analyzer with its Zeek-side
|
||||
* configuration. This is called at startup by generated Spicy code for
|
||||
* each file analyzer defined in an EVT file
|
||||
*
|
||||
* @param name name of the analyzer as defined in its EVT file
|
||||
* @param mime_types list of MIME types the analyzer handles; it'll be automatically used for
|
||||
* all files of matching types
|
||||
* @param parser name of the Spicy parser for parsing the file; must match the name that Spicy
|
||||
* registers the unit's parser with
|
||||
* @param replaces optional name of existing Zeek analyzer that this one replaces; the Zeek
|
||||
* analyzer will automatically be disabled
|
||||
* @param linker_scope scope of current HLTO file, which will restrict visibility of the
|
||||
* registration
|
||||
*/
|
||||
void registerFileAnalyzer(const std::string& name, const hilti::rt::Vector<std::string>& mime_types,
|
||||
const std::string& parser, const std::string& replaces, const std::string& linker_scope);
|
||||
|
||||
/**
|
||||
* Runtime method to register a packet analyzer with its Zeek-side
|
||||
* configuration. This is called at startup by generated Spicy code for
|
||||
* each packet analyzer defined in an EVT file.
|
||||
*
|
||||
* @param name name of the analyzer as defined in its EVT file
|
||||
* @param parser name of the Spicy parser for parsing the packet; must
|
||||
* match the name that Spicy registers the unit's
|
||||
* parser with.
|
||||
* @param replaces optional name of existing Zeek analyzer that this one
|
||||
* replaces; the Zeek analyzer will automatically be disabled
|
||||
* @param linker_scope scope of current HLTO file, which will restrict visibility of the
|
||||
* registration
|
||||
*/
|
||||
void registerPacketAnalyzer(const std::string& name, const std::string& parser, const std::string& replaces,
|
||||
const std::string& linker_scope);
|
||||
|
||||
/**
|
||||
* Runtime method to register a Spicy-generated type with Zeek. The type
|
||||
* must have been encountered during AST traversal already, so that its ID
|
||||
* is known. The corresponding Zeek type will be created and registered with Zeek.
|
||||
*
|
||||
* @param id fully-qualified ID of the type
|
||||
* @return error if the type could not be registered
|
||||
*/
|
||||
hilti::rt::Result<hilti::rt::Nothing> registerType(const std::string& id);
|
||||
|
||||
/**
|
||||
* Runtime method to register an already converted Spicy-generated type
|
||||
* with Zeek.
|
||||
*
|
||||
* @param id fully-qualified ID of the type
|
||||
* @param type Zeek-side type to register
|
||||
*/
|
||||
void registerType(const std::string& id, const TypePtr& type);
|
||||
|
||||
/**
|
||||
* Looks up a global type by its ID with Zeek.
|
||||
*
|
||||
* @param id fully-qualified Zeek-side ID of the type
|
||||
* @return Zeek-side type, or null if not found
|
||||
*/
|
||||
TypePtr findType(const std::string& id) const;
|
||||
|
||||
/**
|
||||
* Runtime method to register a Spicy-generated event. The installs the ID
|
||||
* Zeek-side and is called at startup by generated Spicy code for each
|
||||
* event defined in an EVT file.
|
||||
*
|
||||
* @param name fully scoped name of the event
|
||||
*/
|
||||
void registerEvent(const std::string& name);
|
||||
|
||||
/**
|
||||
* Runtime method to retrieve the Spicy parser for a given Zeek protocol analyzer tag.
|
||||
*
|
||||
* @param analyzer requested protocol analyzer
|
||||
* @param is_orig true if requesting the parser parser for a sessions' originator side, false
|
||||
* for the responder
|
||||
* @return parser, or null if we don't have one for this tag. The pointer will remain valid for
|
||||
* the life-time of the process.
|
||||
*/
|
||||
const ::spicy::rt::Parser* parserForProtocolAnalyzer(const Tag& tag, bool is_orig);
|
||||
|
||||
/**
|
||||
* Runtime method to retrieve the Spicy parser for a given Zeek file analyzer tag.
|
||||
*
|
||||
* @param analyzer requested file analyzer.
|
||||
* @return parser, or null if we don't have one for this tag. The pointer will remain valid for
|
||||
* the life-time of the process.
|
||||
*/
|
||||
const ::spicy::rt::Parser* parserForFileAnalyzer(const Tag& tag);
|
||||
|
||||
/**
|
||||
* Runtime method to retrieve the Spicy parser for a given Zeek packet analyzer tag.
|
||||
*
|
||||
* @param analyzer requested packet analyzer.
|
||||
* @return parser, or null if we don't have one for this tag. The pointer will remain
|
||||
* valid for the life-time of the process.
|
||||
*/
|
||||
const ::spicy::rt::Parser* parserForPacketAnalyzer(const Tag& tag);
|
||||
|
||||
/**
|
||||
* Runtime method to retrieve the analyzer tag that should be passed to
|
||||
* script-land when talking about a protocol analyzer. This is normally
|
||||
* the analyzer's standard tag, but may be replaced with something else
|
||||
* if the analyzer substitutes for an existing one.
|
||||
*
|
||||
* @param tag original tag we query for how to pass it to script-land.
|
||||
* @return desired tag for passing to script-land.
|
||||
*/
|
||||
Tag tagForProtocolAnalyzer(const Tag& tag);
|
||||
|
||||
/**
|
||||
* Runtime method to retrieve the analyzer tag that should be passed to
|
||||
* script-land when talking about a file analyzer. This is normally the
|
||||
* analyzer's standard tag, but may be replaced with something else if
|
||||
* the analyzer substitutes for an existing one.
|
||||
*
|
||||
* @param tag original tag we query for how to pass it to script-land.
|
||||
* @return desired tag for passing to script-land.
|
||||
*/
|
||||
Tag tagForFileAnalyzer(const Tag& tag);
|
||||
|
||||
/**
|
||||
* Runtime method to retrieve the analyzer tag that should be passed to
|
||||
* script-land when talking about a packet analyzer. This is normally the
|
||||
* analyzer's standard tag, but may be replaced with something else if
|
||||
* the analyzer substitutes for an existing one.
|
||||
*
|
||||
* @param tag original tag we query for how to pass it to script-land.
|
||||
* @return desired tag for passing to script-land.
|
||||
*/
|
||||
Tag tagForPacketAnalyzer(const Tag& tag);
|
||||
|
||||
/**
|
||||
* Explicitly enable/disable a protocol analyzer. By default, all analyzers
|
||||
* loaded will also be activated. By calling this method, an analyzer can
|
||||
* toggled.
|
||||
*
|
||||
* @param analyzer tag of analyzer
|
||||
* @param enable true to enable, false to disable
|
||||
*/
|
||||
bool toggleProtocolAnalyzer(const Tag& tag, bool enable);
|
||||
|
||||
/**
|
||||
* Explicitly enable/disable a file analyzer. By default, all analyzers
|
||||
* loaded will also be activated. By calling this method, an analyzer can
|
||||
* toggled.
|
||||
*
|
||||
* @param analyzer tag of analyzer
|
||||
* @param enable true to enable, false to disable
|
||||
*/
|
||||
bool toggleFileAnalyzer(const Tag& tag, bool enable);
|
||||
|
||||
/**
|
||||
* Explicitly enable/disable a packet analyzer. By default, all analyzers
|
||||
* loaded will also be activated. By calling this method, an analyzer can
|
||||
* toggled.
|
||||
*
|
||||
* @note This is currently not supported because Zeek does not provide the
|
||||
* necessary API.
|
||||
*
|
||||
* @param analyzer tag of analyzer
|
||||
* @param enable true to enable, false to disable
|
||||
*/
|
||||
bool togglePacketAnalyzer(const Tag& tag, bool enable);
|
||||
|
||||
/**
|
||||
* Explicitly enable/disable an analyzer. By default, all analyzers
|
||||
* loaded will also be activated. By calling this method, an analyzer can
|
||||
* toggled.
|
||||
*
|
||||
* This method is frontend for the versions specific to
|
||||
* protocol/file/packet analyzers. It takes an enum corresponding to either
|
||||
* kind and branches out accordingly.
|
||||
*
|
||||
* @param analyzer tag of analyzer
|
||||
* @param enable true to enable, false to disable
|
||||
*/
|
||||
bool toggleAnalyzer(EnumVal* tag, bool enable);
|
||||
|
||||
/** Report an error and disable a protocol analyzer's input processing */
|
||||
void analyzerError(analyzer::Analyzer* a, const std::string& msg, const std::string& location);
|
||||
|
||||
/** Report an error and disable a file analyzer's input processing */
|
||||
void analyzerError(file_analysis::Analyzer* a, const std::string& msg, const std::string& location);
|
||||
|
||||
/** Report an error and disable a packet analyzer's input processing. */
|
||||
void analyzerError(packet_analysis::Analyzer* a, const std::string& msg, const std::string& location);
|
||||
|
||||
/** Returns the number of errors recorded by the Zeek reporter. */
|
||||
int numberErrors();
|
||||
|
||||
protected:
|
||||
// Overriding method from Zeek's plugin API.
|
||||
zeek::plugin::Configuration Configure() override;
|
||||
|
||||
// Overriding method from Zeek's plugin API.
|
||||
void InitPreScript() override;
|
||||
|
||||
// Overriding method from Zeek's plugin API.
|
||||
void InitPostScript() override;
|
||||
|
||||
// Overriding method from Zeek's plugin API.
|
||||
void Done() override;
|
||||
|
||||
// Overriding method from Zeek's plugin API.
|
||||
int HookLoadFile(const LoadType type, const std::string& file, const std::string& resolved) override;
|
||||
|
||||
private:
|
||||
// Load one *.hlto module.
|
||||
void loadModule(const hilti::rt::filesystem::path& path);
|
||||
|
||||
// Search ZEEK_SPICY_MODULE_PATH for pre-compiled *.hlto modules and load them.
|
||||
void autoDiscoverModules();
|
||||
|
||||
// Recursively search pre-compiled *.hlto in colon-separated paths.
|
||||
void searchModules(const std::string& paths);
|
||||
|
||||
// Return a Zeek location object for the given file name that will stay valid.
|
||||
detail::Location makeLocation(const std::string& fname);
|
||||
|
||||
// Disable any Zeek-side analyzers that are replaced by one of ours.
|
||||
void disableReplacedAnalyzers();
|
||||
|
||||
/**
|
||||
* Internal callback that records the component-to-tag-type mapping for plugin's analyzer.
|
||||
*
|
||||
* @param c component to track
|
||||
* @param tag_type tag type to associate with component
|
||||
*/
|
||||
void trackComponent(plugin::Component* c, int32_t tag_type);
|
||||
|
||||
/** Captures a registered protocol analyzer. */
|
||||
struct ProtocolAnalyzerInfo {
|
||||
// Provided when registering the analyzer.
|
||||
std::string name_analyzer;
|
||||
std::string name_parser_orig;
|
||||
std::string name_parser_resp;
|
||||
std::string name_replaces;
|
||||
hilti::rt::Protocol protocol = hilti::rt::Protocol::Undef;
|
||||
hilti::rt::Vector<hilti::rt::Port> ports;
|
||||
std::string linker_scope;
|
||||
|
||||
// Computed and available once the analyzer has been registered.
|
||||
std::string name_zeek;
|
||||
std::string name_zeekygen;
|
||||
Tag::type_t type;
|
||||
const ::spicy::rt::Parser* parser_orig;
|
||||
const ::spicy::rt::Parser* parser_resp;
|
||||
Tag replaces;
|
||||
|
||||
bool operator==(const ProtocolAnalyzerInfo& other) const {
|
||||
return name_analyzer == other.name_analyzer && name_parser_orig == other.name_parser_orig &&
|
||||
name_parser_resp == other.name_parser_resp && name_replaces == other.name_replaces &&
|
||||
protocol == other.protocol && ports == other.ports && linker_scope == other.linker_scope;
|
||||
}
|
||||
|
||||
bool operator!=(const ProtocolAnalyzerInfo& other) const { return ! (*this == other); }
|
||||
};
|
||||
|
||||
/** Captures a registered file analyzer. */
|
||||
struct FileAnalyzerInfo {
|
||||
// Provided when registering the analyzer.
|
||||
std::string name_analyzer;
|
||||
std::string name_parser;
|
||||
std::string name_replaces;
|
||||
hilti::rt::Vector<std::string> mime_types;
|
||||
std::string linker_scope;
|
||||
|
||||
// Computed and available once the analyzer has been registered.
|
||||
std::string name_zeek;
|
||||
std::string name_zeekygen;
|
||||
Tag::type_t type;
|
||||
const ::spicy::rt::Parser* parser;
|
||||
Tag replaces;
|
||||
|
||||
bool operator==(const FileAnalyzerInfo& other) const {
|
||||
return name_analyzer == other.name_analyzer && name_parser == other.name_parser &&
|
||||
name_replaces == other.name_replaces && mime_types == other.mime_types &&
|
||||
linker_scope == other.linker_scope;
|
||||
}
|
||||
|
||||
bool operator!=(const FileAnalyzerInfo& other) const { return ! (*this == other); }
|
||||
};
|
||||
|
||||
/** Captures a registered file analyzer. */
|
||||
struct PacketAnalyzerInfo {
|
||||
// Provided when registering the analyzer.
|
||||
std::string name_analyzer;
|
||||
std::string name_parser;
|
||||
std::string name_replaces;
|
||||
std::string linker_scope;
|
||||
|
||||
// Computed and available once the analyzer has been registered.
|
||||
std::string name_zeek;
|
||||
std::string name_zeekygen;
|
||||
Tag::type_t type;
|
||||
const ::spicy::rt::Parser* parser;
|
||||
Tag replaces;
|
||||
|
||||
// Compares only the provided attributes, as that's what defines us.
|
||||
bool operator==(const PacketAnalyzerInfo& other) const {
|
||||
return name_analyzer == other.name_analyzer && name_parser == other.name_parser &&
|
||||
name_replaces == other.name_replaces && linker_scope == other.linker_scope;
|
||||
}
|
||||
|
||||
bool operator!=(const PacketAnalyzerInfo& other) const { return ! (*this == other); }
|
||||
};
|
||||
|
||||
std::string _spicy_version;
|
||||
|
||||
std::vector<ProtocolAnalyzerInfo> _protocol_analyzers_by_type;
|
||||
std::vector<FileAnalyzerInfo> _file_analyzers_by_type;
|
||||
std::vector<PacketAnalyzerInfo> _packet_analyzers_by_type;
|
||||
std::unordered_map<std::string, hilti::rt::Library> _libraries;
|
||||
std::set<std::string> _locations;
|
||||
std::unordered_map<std::string, detail::IDPtr> _events;
|
||||
|
||||
// Mapping of component names to tag types. We use this to ensure analyzer uniqueness.
|
||||
std::unordered_map<std::string, int32_t> _analyzer_name_to_tag_type;
|
||||
};
|
||||
|
||||
} // namespace spicy
|
||||
|
||||
extern spicy::Manager* spicy_mgr;
|
||||
|
||||
} // namespace zeek
|
73
src/spicy/packet-analyzer.cc
Normal file
73
src/spicy/packet-analyzer.cc
Normal file
|
@ -0,0 +1,73 @@
|
|||
// See the file "COPYING" in the main distribution directory for copyright.
|
||||
|
||||
#include "zeek/spicy/packet-analyzer.h"
|
||||
|
||||
#include "zeek/spicy/manager.h"
|
||||
#include "zeek/spicy/runtime-support.h"
|
||||
|
||||
using namespace zeek;
|
||||
using namespace zeek::spicy;
|
||||
using namespace zeek::spicy::rt;
|
||||
|
||||
#ifdef DEBUG
|
||||
#define STATE_DEBUG_MSG(...) DebugMsg(__VA_ARGS__)
|
||||
#else
|
||||
#define STATE_DEBUG_MSG(...)
|
||||
#endif
|
||||
|
||||
void PacketState::debug(const std::string& msg) { spicy::rt::debug(_cookie, msg); }
|
||||
|
||||
static auto create_packet_state(PacketAnalyzer* analyzer) {
|
||||
cookie::PacketAnalyzer cookie;
|
||||
cookie.analyzer = analyzer;
|
||||
return PacketState(std::move(cookie));
|
||||
}
|
||||
|
||||
PacketAnalyzer::PacketAnalyzer(std::string name)
|
||||
: packet_analysis::Analyzer(std::move(name)), _state(create_packet_state(this)) {}
|
||||
|
||||
PacketAnalyzer::~PacketAnalyzer() = default;
|
||||
|
||||
bool PacketAnalyzer::AnalyzePacket(size_t len, const uint8_t* data, Packet* packet) {
|
||||
if ( auto parser = spicy_mgr->parserForPacketAnalyzer(_state.packet().analyzer->GetAnalyzerTag()) )
|
||||
_state.setParser(parser);
|
||||
else
|
||||
reporter->FatalError("no valid unit specified for parsing");
|
||||
|
||||
try {
|
||||
hilti::rt::context::CookieSetter _(_state.cookie());
|
||||
_state.packet().next_analyzer.reset();
|
||||
_state.packet().packet = packet;
|
||||
_state.process(len, reinterpret_cast<const char*>(data));
|
||||
auto offset = _state.finish();
|
||||
assert(offset);
|
||||
_state.packet().packet = nullptr;
|
||||
_state.packet().packet_val = nullptr;
|
||||
_state.reset();
|
||||
auto num_processed = offset->Ref();
|
||||
const auto& next_analyzer = _state.packet().next_analyzer;
|
||||
STATE_DEBUG_MSG(hilti::rt::fmt("processed %" PRIu64 " out of %" PRIu64 " bytes, %s", num_processed, len,
|
||||
(next_analyzer ? hilti::rt::fmt("next analyzer is 0x%" PRIx32, *next_analyzer) :
|
||||
std::string("no next analyzer"))));
|
||||
if ( next_analyzer )
|
||||
return ForwardPacket(len - num_processed, data + num_processed, packet, *next_analyzer);
|
||||
else
|
||||
return true;
|
||||
} catch ( const hilti::rt::RuntimeError& e ) {
|
||||
STATE_DEBUG_MSG(hilti::rt::fmt("error during parsing, triggering analyzer violation: %s", e.what()));
|
||||
auto tag = _state.packet().analyzer->GetAnalyzerTag();
|
||||
|
||||
if ( auto* session = packet->session )
|
||||
_state.packet().analyzer->AnalyzerViolation(e.what(), session, reinterpret_cast<const char*>(data), len,
|
||||
tag);
|
||||
|
||||
_state.reset();
|
||||
return false;
|
||||
} catch ( const hilti::rt::Exception& e ) {
|
||||
STATE_DEBUG_MSG(e.what());
|
||||
spicy_mgr->analyzerError(_state.packet().analyzer, e.description(),
|
||||
e.location()); // this sets Zeek to skip sending any further input
|
||||
_state.reset();
|
||||
return false;
|
||||
}
|
||||
}
|
75
src/spicy/packet-analyzer.h
Normal file
75
src/spicy/packet-analyzer.h
Normal file
|
@ -0,0 +1,75 @@
|
|||
// See the file "COPYING" in the main distribution directory for copyright.
|
||||
|
||||
#pragma once
|
||||
|
||||
#include <memory>
|
||||
#include <optional>
|
||||
#include <string>
|
||||
#include <utility>
|
||||
|
||||
#include <hilti/rt/types/stream.h>
|
||||
|
||||
#include <spicy/rt/driver.h>
|
||||
#include <spicy/rt/parser.h>
|
||||
|
||||
#include "zeek/spicy/cookie.h"
|
||||
|
||||
namespace zeek::spicy::rt {
|
||||
|
||||
/** Parsing state for a packet. */
|
||||
class PacketState : public ::spicy::rt::driver::ParsingState {
|
||||
public:
|
||||
/**
|
||||
* Constructor.
|
||||
*
|
||||
* @param cookie cookie to associated with the packet
|
||||
*/
|
||||
PacketState(Cookie cookie) : ParsingState(::spicy::rt::driver::ParsingType::Block), _cookie(std::move(cookie)) {}
|
||||
|
||||
/** Returns the cookie pointer to use with the runtime library during analysis. */
|
||||
auto* cookie() { return &_cookie; }
|
||||
|
||||
/** Returns the packet-specific cookie state associated with the endpoint. */
|
||||
auto& packet() {
|
||||
assert(_cookie.packet);
|
||||
return *_cookie.packet;
|
||||
}
|
||||
|
||||
/**
|
||||
* Records a debug message pertaining to the specific file.
|
||||
*
|
||||
* @param msg message to record
|
||||
*/
|
||||
void DebugMsg(const std::string& msg) { debug(msg); }
|
||||
|
||||
protected:
|
||||
// Overridden from driver::ParsingState.
|
||||
void debug(const std::string& msg) override;
|
||||
|
||||
private:
|
||||
Cookie _cookie;
|
||||
};
|
||||
|
||||
/** A Spicy file analyzer. */
|
||||
class PacketAnalyzer : public packet_analysis::Analyzer {
|
||||
public:
|
||||
PacketAnalyzer(std::string name);
|
||||
virtual ~PacketAnalyzer();
|
||||
|
||||
/** Records a debug message. */
|
||||
void DebugMsg(const std::string& msg) { _state.DebugMsg(msg); }
|
||||
|
||||
static packet_analysis::AnalyzerPtr Instantiate(std::string name) {
|
||||
name = util::canonify_name(name);
|
||||
return std::make_shared<PacketAnalyzer>(name);
|
||||
}
|
||||
|
||||
protected:
|
||||
// Overridden from Zeek's packet analyzer.
|
||||
bool AnalyzePacket(size_t len, const uint8_t* data, Packet* packet) override;
|
||||
|
||||
private:
|
||||
PacketState _state;
|
||||
};
|
||||
|
||||
} // namespace zeek::spicy::rt
|
231
src/spicy/protocol-analyzer.cc
Normal file
231
src/spicy/protocol-analyzer.cc
Normal file
|
@ -0,0 +1,231 @@
|
|||
// See the file "COPYING" in the main distribution directory for copyright.
|
||||
|
||||
#include "zeek/spicy/protocol-analyzer.h"
|
||||
|
||||
#include "zeek/spicy/manager.h"
|
||||
#include "zeek/spicy/runtime-support.h"
|
||||
|
||||
using namespace zeek;
|
||||
using namespace zeek::spicy;
|
||||
using namespace zeek::spicy::rt;
|
||||
|
||||
#ifdef DEBUG
|
||||
#define STATE_DEBUG_MSG(...) DebugMsg(__VA_ARGS__)
|
||||
#else
|
||||
#define STATE_DEBUG_MSG(...)
|
||||
#endif
|
||||
|
||||
void EndpointState::debug(const std::string& msg) { spicy::rt::debug(_cookie, msg); }
|
||||
|
||||
static auto create_endpoint(bool is_orig, analyzer::Analyzer* analyzer, ::spicy::rt::driver::ParsingType type) {
|
||||
cookie::ProtocolAnalyzer cookie{.analyzer = analyzer,
|
||||
.is_orig = is_orig,
|
||||
.fstate_orig = cookie::FileStateStack(hilti::rt::fmt("%x.orig", analyzer->GetID())),
|
||||
.fstate_resp =
|
||||
cookie::FileStateStack(hilti::rt::fmt("%x.resp", analyzer->GetID()))};
|
||||
|
||||
// Cannot get parser here yet, analyzer may not have been fully set up.
|
||||
return EndpointState(std::move(cookie), type);
|
||||
}
|
||||
|
||||
ProtocolAnalyzer::ProtocolAnalyzer(analyzer::Analyzer* analyzer, ::spicy::rt::driver::ParsingType type)
|
||||
: _originator(create_endpoint(true, analyzer, type)), _responder(create_endpoint(false, analyzer, type)) {}
|
||||
|
||||
ProtocolAnalyzer::~ProtocolAnalyzer() {}
|
||||
|
||||
void ProtocolAnalyzer::Init() {}
|
||||
|
||||
void ProtocolAnalyzer::Done() {
|
||||
Finish(true);
|
||||
Finish(false);
|
||||
}
|
||||
|
||||
void ProtocolAnalyzer::Process(bool is_orig, int len, const u_char* data) {
|
||||
auto* endp = is_orig ? &_originator : &_responder;
|
||||
|
||||
if ( endp->protocol().analyzer->Skipping() )
|
||||
return;
|
||||
|
||||
if ( ! endp->hasParser() && ! endp->isSkipping() ) {
|
||||
auto parser = spicy_mgr->parserForProtocolAnalyzer(endp->protocol().analyzer->GetAnalyzerTag(), is_orig);
|
||||
if ( parser ) {
|
||||
if ( ! _context )
|
||||
_context = parser->createContext();
|
||||
|
||||
endp->setParser(parser, _context);
|
||||
}
|
||||
else {
|
||||
STATE_DEBUG_MSG(is_orig, "no unit specified for parsing");
|
||||
endp->skipRemaining();
|
||||
return;
|
||||
}
|
||||
}
|
||||
|
||||
try {
|
||||
hilti::rt::context::CookieSetter _(endp->cookie());
|
||||
endp->process(len, reinterpret_cast<const char*>(data));
|
||||
} catch ( const hilti::rt::RuntimeError& e ) {
|
||||
STATE_DEBUG_MSG(is_orig, hilti::rt::fmt("error during parsing, triggering analyzer violation: %s", e.what()));
|
||||
auto tag = spicy_mgr->tagForProtocolAnalyzer(endp->protocol().analyzer->GetAnalyzerTag());
|
||||
endp->protocol().analyzer->AnalyzerViolation(e.what(), reinterpret_cast<const char*>(data), len, tag);
|
||||
originator().skipRemaining();
|
||||
responder().skipRemaining();
|
||||
endp->protocol().analyzer->SetSkip(true);
|
||||
} catch ( const hilti::rt::Exception& e ) {
|
||||
spicy_mgr->analyzerError(endp->protocol().analyzer, e.description(),
|
||||
e.location()); // this sets Zeek to skip sending any further input
|
||||
}
|
||||
}
|
||||
|
||||
void ProtocolAnalyzer::Finish(bool is_orig) {
|
||||
auto* endp = is_orig ? &_originator : &_responder;
|
||||
|
||||
if ( endp->protocol().analyzer->Skipping() )
|
||||
return;
|
||||
|
||||
try {
|
||||
hilti::rt::context::CookieSetter _(endp->cookie());
|
||||
endp->finish();
|
||||
} catch ( const hilti::rt::RuntimeError& e ) {
|
||||
STATE_DEBUG_MSG(is_orig, hilti::rt::fmt("error during parsing, triggering analyzer violation: %s", e.what()));
|
||||
auto tag = spicy_mgr->tagForProtocolAnalyzer(endp->protocol().analyzer->GetAnalyzerTag());
|
||||
endp->protocol().analyzer->AnalyzerViolation(e.what(), nullptr, 0, tag);
|
||||
endp->skipRemaining();
|
||||
} catch ( const hilti::rt::Exception& e ) {
|
||||
spicy_mgr->analyzerError(endp->protocol().analyzer, e.description(),
|
||||
e.location()); // this sets Zeek to skip sending any further input
|
||||
}
|
||||
}
|
||||
|
||||
cookie::ProtocolAnalyzer& ProtocolAnalyzer::cookie(bool is_orig) {
|
||||
if ( is_orig )
|
||||
return _originator.protocol();
|
||||
else
|
||||
return _responder.protocol();
|
||||
}
|
||||
|
||||
void ProtocolAnalyzer::DebugMsg(bool is_orig, const std::string& msg) {
|
||||
if ( is_orig )
|
||||
_originator.DebugMsg(msg);
|
||||
else
|
||||
_responder.DebugMsg(msg);
|
||||
}
|
||||
|
||||
void ProtocolAnalyzer::FlipRoles() { std::swap(_originator, _responder); }
|
||||
|
||||
analyzer::Analyzer* TCP_Analyzer::InstantiateAnalyzer(Connection* conn) { return new TCP_Analyzer(conn); }
|
||||
|
||||
TCP_Analyzer::TCP_Analyzer(Connection* conn)
|
||||
: ProtocolAnalyzer(this, ::spicy::rt::driver::ParsingType::Stream), analyzer::tcp::TCP_ApplicationAnalyzer(conn) {}
|
||||
|
||||
TCP_Analyzer::~TCP_Analyzer() {}
|
||||
|
||||
void TCP_Analyzer::Init() {
|
||||
analyzer::tcp::TCP_ApplicationAnalyzer::Init();
|
||||
ProtocolAnalyzer::Init();
|
||||
}
|
||||
|
||||
void TCP_Analyzer::Done() {
|
||||
analyzer::tcp::TCP_ApplicationAnalyzer::Done();
|
||||
ProtocolAnalyzer::Done();
|
||||
|
||||
EndOfData(true);
|
||||
EndOfData(false);
|
||||
}
|
||||
|
||||
void TCP_Analyzer::DeliverStream(int len, const u_char* data, bool is_orig) {
|
||||
analyzer::tcp::TCP_ApplicationAnalyzer::DeliverStream(len, data, is_orig);
|
||||
|
||||
Process(is_orig, len, data);
|
||||
|
||||
if ( originator().isFinished() && responder().isFinished() &&
|
||||
(! originator().isSkipping() || ! responder().isSkipping()) ) {
|
||||
STATE_DEBUG_MSG(is_orig, "both endpoints finished, skipping all further TCP processing");
|
||||
originator().skipRemaining();
|
||||
responder().skipRemaining();
|
||||
|
||||
if ( is_orig ) // doesn't really matter which endpoint here.
|
||||
originator().protocol().analyzer->SetSkip(true);
|
||||
else
|
||||
responder().protocol().analyzer->SetSkip(true);
|
||||
}
|
||||
}
|
||||
|
||||
void TCP_Analyzer::Undelivered(uint64_t seq, int len, bool is_orig) {
|
||||
analyzer::tcp::TCP_ApplicationAnalyzer::Undelivered(seq, len, is_orig);
|
||||
|
||||
Process(is_orig, len, nullptr);
|
||||
}
|
||||
|
||||
void TCP_Analyzer::EndOfData(bool is_orig) {
|
||||
analyzer::tcp::TCP_ApplicationAnalyzer::EndOfData(is_orig);
|
||||
|
||||
if ( TCP() && TCP()->IsPartial() ) {
|
||||
STATE_DEBUG_MSG(is_orig, "skipping end-of-data delivery on partial TCP connection");
|
||||
return;
|
||||
}
|
||||
|
||||
Finish(is_orig);
|
||||
}
|
||||
|
||||
void TCP_Analyzer::FlipRoles() {
|
||||
analyzer::tcp::TCP_ApplicationAnalyzer::FlipRoles();
|
||||
ProtocolAnalyzer::FlipRoles();
|
||||
}
|
||||
|
||||
void TCP_Analyzer::EndpointEOF(bool is_orig) {
|
||||
analyzer::tcp::TCP_ApplicationAnalyzer::EndpointEOF(is_orig);
|
||||
Finish(is_orig);
|
||||
}
|
||||
|
||||
void TCP_Analyzer::ConnectionClosed(analyzer::tcp::TCP_Endpoint* endpoint, analyzer::tcp::TCP_Endpoint* peer,
|
||||
bool gen_event) {
|
||||
analyzer::tcp::TCP_ApplicationAnalyzer::ConnectionClosed(endpoint, peer, gen_event);
|
||||
}
|
||||
|
||||
void TCP_Analyzer::ConnectionFinished(bool half_finished) {
|
||||
analyzer::tcp::TCP_ApplicationAnalyzer::ConnectionFinished(half_finished);
|
||||
}
|
||||
|
||||
void TCP_Analyzer::ConnectionReset() { analyzer::tcp::TCP_ApplicationAnalyzer::ConnectionReset(); }
|
||||
|
||||
void TCP_Analyzer::PacketWithRST() { analyzer::tcp::TCP_ApplicationAnalyzer::PacketWithRST(); }
|
||||
|
||||
analyzer::Analyzer* UDP_Analyzer::InstantiateAnalyzer(Connection* conn) { return new UDP_Analyzer(conn); }
|
||||
|
||||
UDP_Analyzer::UDP_Analyzer(Connection* conn)
|
||||
: ProtocolAnalyzer(this, ::spicy::rt::driver::ParsingType::Block), analyzer::Analyzer(conn) {}
|
||||
|
||||
UDP_Analyzer::~UDP_Analyzer() {}
|
||||
|
||||
void UDP_Analyzer::Init() {
|
||||
analyzer::Analyzer::Init();
|
||||
ProtocolAnalyzer::Init();
|
||||
}
|
||||
|
||||
void UDP_Analyzer::Done() {
|
||||
analyzer::Analyzer::Done();
|
||||
ProtocolAnalyzer::Done();
|
||||
}
|
||||
|
||||
void UDP_Analyzer::DeliverPacket(int len, const u_char* data, bool is_orig, uint64_t seq, const IP_Hdr* ip,
|
||||
int caplen) {
|
||||
analyzer::Analyzer::DeliverPacket(len, data, is_orig, seq, ip, caplen);
|
||||
|
||||
++cookie(is_orig).num_packets;
|
||||
Process(is_orig, len, data);
|
||||
}
|
||||
|
||||
void UDP_Analyzer::Undelivered(uint64_t seq, int len, bool is_orig) {
|
||||
analyzer::Analyzer::Undelivered(seq, len, is_orig);
|
||||
}
|
||||
|
||||
void UDP_Analyzer::EndOfData(bool is_orig) {
|
||||
analyzer::Analyzer::EndOfData(is_orig);
|
||||
Finish(is_orig);
|
||||
}
|
||||
|
||||
void UDP_Analyzer::FlipRoles() {
|
||||
analyzer::Analyzer::FlipRoles();
|
||||
ProtocolAnalyzer::FlipRoles();
|
||||
}
|
166
src/spicy/protocol-analyzer.h
Normal file
166
src/spicy/protocol-analyzer.h
Normal file
|
@ -0,0 +1,166 @@
|
|||
// See the file "COPYING" in the main distribution directory for copyright.
|
||||
|
||||
#pragma once
|
||||
|
||||
#include <optional>
|
||||
#include <string>
|
||||
#include <utility>
|
||||
|
||||
#include <hilti/rt/types/stream.h>
|
||||
|
||||
#include <spicy/rt/driver.h>
|
||||
#include <spicy/rt/parser.h>
|
||||
|
||||
#include "zeek/spicy/cookie.h"
|
||||
|
||||
namespace zeek::spicy::rt {
|
||||
|
||||
/** Parsing state for one endpoint of the connection. */
|
||||
class EndpointState : public ::spicy::rt::driver::ParsingState {
|
||||
public:
|
||||
/**
|
||||
* Constructor.
|
||||
*
|
||||
* @param cookie cookie to associated with the endpoint
|
||||
* @param type type of parsing, depending on whether it's a stream- or
|
||||
* packet-based protocol
|
||||
*/
|
||||
EndpointState(Cookie cookie, ::spicy::rt::driver::ParsingType type)
|
||||
: ParsingState(type), _cookie(std::move(cookie)) {}
|
||||
|
||||
/** Returns the protocol-specific cookie state associated with the endpoint. */
|
||||
auto& protocol() {
|
||||
assert(_cookie.protocol);
|
||||
return *_cookie.protocol;
|
||||
}
|
||||
|
||||
/** Returns the cookie pointer to use with the runtime library during analysis. */
|
||||
auto* cookie() { return &_cookie; }
|
||||
|
||||
/**
|
||||
* Records a debug message pertaining to this specific endpoint.
|
||||
*
|
||||
* @param msg message to record
|
||||
*/
|
||||
void DebugMsg(const std::string& msg) { debug(msg); }
|
||||
|
||||
protected:
|
||||
// Overridden from driver::ParsingState.
|
||||
void debug(const std::string& msg) override;
|
||||
|
||||
private:
|
||||
Cookie _cookie;
|
||||
};
|
||||
|
||||
/** Base clase for Spicy protocol analyzers. */
|
||||
class ProtocolAnalyzer {
|
||||
public:
|
||||
ProtocolAnalyzer(analyzer::Analyzer* analyzer, ::spicy::rt::driver::ParsingType type);
|
||||
virtual ~ProtocolAnalyzer();
|
||||
|
||||
/** Returns the originator-side parsing state. */
|
||||
auto& originator() { return _originator; }
|
||||
|
||||
/** Returns the responder-side parsing state. */
|
||||
auto& responder() { return _responder; }
|
||||
|
||||
protected:
|
||||
/** Initialize analyzer. */
|
||||
void Init();
|
||||
|
||||
/** Shutdown analyzer. */
|
||||
void Done();
|
||||
|
||||
/**
|
||||
* Signal that Zeek has flipped the direction of the connection, meaning
|
||||
* that originator and responder state need to be swapped.
|
||||
*/
|
||||
void FlipRoles();
|
||||
|
||||
/**
|
||||
* Feeds a chunk of data into one side's parsing.
|
||||
*
|
||||
* @param is_orig true to use originator-side endpoint state, false for responder
|
||||
* @param len number of bytes valid in *data*
|
||||
* @param data pointer to data
|
||||
*/
|
||||
void Process(bool is_orig, int len, const u_char* data);
|
||||
|
||||
/**
|
||||
* Finalizes parsing. After calling this, no more data must be passed
|
||||
* into Process() for the corresponding side.
|
||||
*
|
||||
* @param is_orig true to finish originator-side parsing, false for responder
|
||||
*/
|
||||
void Finish(bool is_orig);
|
||||
|
||||
/**
|
||||
* Helper returning the protocol analyzer cookie for the requested side.
|
||||
*
|
||||
* @param is_orig tru to return the originator's state, false for the
|
||||
* responder.
|
||||
* @return protocol analyzer cookie for the requested side
|
||||
*/
|
||||
cookie::ProtocolAnalyzer& cookie(bool is_orig);
|
||||
|
||||
/**
|
||||
* Records a debug message. This forwards to `DebugMsg()` for the
|
||||
* corresponding `EndpointState`.
|
||||
*/
|
||||
void DebugMsg(bool is_orig, const std::string& msg);
|
||||
|
||||
private:
|
||||
EndpointState _originator; /**< Originator-side state. */
|
||||
EndpointState _responder; /**< Responder-side state. */
|
||||
std::optional<::spicy::rt::UnitContext> _context;
|
||||
};
|
||||
|
||||
/**
|
||||
* Spicy analyzer for TCP application-layer protocols. Implements the
|
||||
* standard Zeek API.
|
||||
*/
|
||||
class TCP_Analyzer : public ProtocolAnalyzer, public analyzer::tcp::TCP_ApplicationAnalyzer {
|
||||
public:
|
||||
TCP_Analyzer(Connection* conn);
|
||||
virtual ~TCP_Analyzer();
|
||||
|
||||
// Overridden from Spicy's Analyzer.
|
||||
void Init() override;
|
||||
void Done() override;
|
||||
void DeliverStream(int len, const u_char* data, bool orig) override;
|
||||
void Undelivered(uint64_t seq, int len, bool orig) override;
|
||||
void EndOfData(bool is_orig) override;
|
||||
void FlipRoles() override;
|
||||
|
||||
// Overridden from Zeek's TCP_ApplicationAnalyzer.
|
||||
void EndpointEOF(bool is_orig) override;
|
||||
void ConnectionClosed(analyzer::tcp::TCP_Endpoint* endpoint, analyzer::tcp::TCP_Endpoint* peer,
|
||||
bool gen_event) override;
|
||||
void ConnectionFinished(bool half_finished) override;
|
||||
void ConnectionReset() override;
|
||||
void PacketWithRST() override;
|
||||
|
||||
static analyzer::Analyzer* InstantiateAnalyzer(Connection* conn);
|
||||
};
|
||||
|
||||
/**
|
||||
* Spicy analyzer for UDP application-layer protocols. Implements the
|
||||
* standard Zeek API.
|
||||
*/
|
||||
class UDP_Analyzer : public ProtocolAnalyzer, public analyzer::Analyzer {
|
||||
public:
|
||||
UDP_Analyzer(Connection* conn);
|
||||
virtual ~UDP_Analyzer();
|
||||
|
||||
// Overridden from Spicy's Analyzer.
|
||||
void Init() override;
|
||||
void Done() override;
|
||||
void DeliverPacket(int len, const u_char* data, bool orig, uint64_t seq, const IP_Hdr* ip, int caplen) override;
|
||||
void Undelivered(uint64_t seq, int len, bool orig) override;
|
||||
void EndOfData(bool is_orig) override;
|
||||
void FlipRoles() override;
|
||||
|
||||
static analyzer::Analyzer* InstantiateAnalyzer(Connection* conn);
|
||||
};
|
||||
|
||||
} // namespace zeek::spicy::rt
|
842
src/spicy/runtime-support.cc
Normal file
842
src/spicy/runtime-support.cc
Normal file
|
@ -0,0 +1,842 @@
|
|||
// See the file "COPYING" in the main distribution directory for copyright.
|
||||
|
||||
#include "zeek/spicy/runtime-support.h"
|
||||
|
||||
#include <algorithm>
|
||||
#include <memory>
|
||||
|
||||
#include <hilti/rt/exception.h>
|
||||
#include <hilti/rt/profiler.h>
|
||||
#include <hilti/rt/types/port.h>
|
||||
#include <hilti/rt/util.h>
|
||||
|
||||
#include "zeek/Event.h"
|
||||
#include "zeek/analyzer/Manager.h"
|
||||
#include "zeek/analyzer/protocol/pia/PIA.h"
|
||||
#include "zeek/file_analysis/File.h"
|
||||
#include "zeek/file_analysis/Manager.h"
|
||||
#include "zeek/spicy/manager.h"
|
||||
|
||||
using namespace zeek;
|
||||
using namespace zeek::spicy;
|
||||
|
||||
void rt::register_protocol_analyzer(const std::string& name, hilti::rt::Protocol proto,
|
||||
const hilti::rt::Vector<hilti::rt::Port>& ports, const std::string& parser_orig,
|
||||
const std::string& parser_resp, const std::string& replaces,
|
||||
const std::string& linker_scope) {
|
||||
auto _ = hilti::rt::profiler::start("zeek/rt/register_protocol_analyzer");
|
||||
spicy_mgr->registerProtocolAnalyzer(name, proto, ports, parser_orig, parser_resp, replaces, linker_scope);
|
||||
}
|
||||
|
||||
void rt::register_file_analyzer(const std::string& name, const hilti::rt::Vector<std::string>& mime_types,
|
||||
const std::string& parser, const std::string& replaces,
|
||||
const std::string& linker_scope) {
|
||||
auto _ = hilti::rt::profiler::start("zeek/rt/register_file_analyzer");
|
||||
spicy_mgr->registerFileAnalyzer(name, mime_types, parser, replaces, linker_scope);
|
||||
}
|
||||
|
||||
void rt::register_packet_analyzer(const std::string& name, const std::string& parser, const std::string& replaces,
|
||||
const std::string& linker_scope) {
|
||||
auto _ = hilti::rt::profiler::start("zeek/rt/register_packet_analyzer");
|
||||
spicy_mgr->registerPacketAnalyzer(name, parser, replaces, linker_scope);
|
||||
}
|
||||
|
||||
void rt::register_type(const std::string& ns, const std::string& id, const TypePtr& type) {
|
||||
auto _ = hilti::rt::profiler::start("zeek/rt/register_type");
|
||||
spicy_mgr->registerType(hilti::rt::fmt("%s::%s", (! ns.empty() ? ns : std::string("GLOBAL")), id), type);
|
||||
}
|
||||
|
||||
// Helper to look up a global Zeek-side type, enforcing that it's of the expected type.
|
||||
static TypePtr findType(TypeTag tag, const std::string& ns, const std::string& id) {
|
||||
auto id_ = hilti::rt::fmt("%s::%s", ns, id);
|
||||
auto type = spicy_mgr->findType(id_);
|
||||
|
||||
if ( ! type )
|
||||
return nullptr;
|
||||
|
||||
if ( type->Tag() != tag )
|
||||
reporter->FatalError("ID %s is not of expected type %s", id_.c_str(), type_name(tag));
|
||||
|
||||
return type;
|
||||
}
|
||||
|
||||
TypePtr rt::create_base_type(ZeekTypeTag tag) {
|
||||
auto _ = hilti::rt::profiler::start("zeek/rt/create_base_type");
|
||||
TypeTag ztag;
|
||||
|
||||
switch ( tag ) {
|
||||
case ZeekTypeTag::Addr: ztag = TYPE_ADDR; break;
|
||||
case ZeekTypeTag::Any: ztag = TYPE_ANY; break;
|
||||
case ZeekTypeTag::Bool: ztag = TYPE_BOOL; break;
|
||||
case ZeekTypeTag::Count: ztag = TYPE_COUNT; break;
|
||||
case ZeekTypeTag::Double: ztag = TYPE_DOUBLE; break;
|
||||
case ZeekTypeTag::Enum: ztag = TYPE_ENUM; break;
|
||||
case ZeekTypeTag::Error: ztag = TYPE_ERROR; break;
|
||||
case ZeekTypeTag::File: ztag = TYPE_FILE; break;
|
||||
case ZeekTypeTag::Func: ztag = TYPE_FUNC; break;
|
||||
case ZeekTypeTag::List: ztag = TYPE_LIST; break;
|
||||
case ZeekTypeTag::Int: ztag = TYPE_INT; break;
|
||||
case ZeekTypeTag::Interval: ztag = TYPE_INTERVAL; break;
|
||||
case ZeekTypeTag::Opaque: ztag = TYPE_OPAQUE; break;
|
||||
case ZeekTypeTag::Pattern: ztag = TYPE_PATTERN; break;
|
||||
case ZeekTypeTag::Port: ztag = TYPE_PORT; break;
|
||||
case ZeekTypeTag::Record: ztag = TYPE_RECORD; break;
|
||||
case ZeekTypeTag::String: ztag = TYPE_STRING; break;
|
||||
case ZeekTypeTag::Subnet: ztag = TYPE_SUBNET; break;
|
||||
case ZeekTypeTag::Table: ztag = TYPE_TABLE; break;
|
||||
case ZeekTypeTag::Time: ztag = TYPE_TIME; break;
|
||||
case ZeekTypeTag::Type: ztag = TYPE_TYPE; break;
|
||||
case ZeekTypeTag::Vector: ztag = TYPE_VECTOR; break;
|
||||
case ZeekTypeTag::Void: ztag = TYPE_VOID; break;
|
||||
default: hilti::rt::cannot_be_reached();
|
||||
}
|
||||
|
||||
return base_type(ztag);
|
||||
}
|
||||
|
||||
TypePtr rt::create_enum_type(
|
||||
const std::string& ns, const std::string& id,
|
||||
const hilti::rt::Vector<std::tuple<std::string, hilti::rt::integer::safe<int64_t>>>& labels) {
|
||||
auto _ = hilti::rt::profiler::start("zeek/rt/create_enum_type");
|
||||
|
||||
if ( auto t = findType(TYPE_ENUM, ns, id) )
|
||||
return t;
|
||||
|
||||
auto etype = make_intrusive<EnumType>(ns + "::" + id);
|
||||
|
||||
for ( auto [lid, lval] : labels ) {
|
||||
auto name = ::hilti::rt::fmt("%s_%s", id, lid);
|
||||
|
||||
if ( lval == -1 )
|
||||
// Zeek's enum can't be negative, so swap in max_int for our Undef.
|
||||
lval = std::numeric_limits<::zeek_int_t>::max();
|
||||
|
||||
etype->AddName(ns, name.c_str(), lval, true);
|
||||
}
|
||||
|
||||
return etype;
|
||||
}
|
||||
|
||||
TypePtr rt::create_record_type(const std::string& ns, const std::string& id,
|
||||
const hilti::rt::Vector<RecordField>& fields) {
|
||||
auto _ = hilti::rt::profiler::start("zeek/rt/create_record_type");
|
||||
|
||||
if ( auto t = findType(TYPE_RECORD, ns, id) )
|
||||
return t;
|
||||
|
||||
auto decls = std::make_unique<type_decl_list>();
|
||||
|
||||
for ( const auto& [id, type, optional] : fields ) {
|
||||
auto attrs = make_intrusive<detail::Attributes>(nullptr, true, false);
|
||||
|
||||
if ( optional ) {
|
||||
auto optional_ = make_intrusive<detail::Attr>(detail::ATTR_OPTIONAL);
|
||||
attrs->AddAttr(optional_);
|
||||
}
|
||||
|
||||
decls->append(new TypeDecl(util::copy_string(id.c_str()), type, std::move(attrs)));
|
||||
}
|
||||
|
||||
return make_intrusive<RecordType>(decls.release());
|
||||
}
|
||||
|
||||
TypePtr rt::create_table_type(TypePtr key, std::optional<TypePtr> value) {
|
||||
auto _ = hilti::rt::profiler::start("zeek/rt/create_table_type");
|
||||
auto idx = make_intrusive<TypeList>();
|
||||
idx->Append(std::move(key));
|
||||
return make_intrusive<TableType>(std::move(idx), value ? *value : nullptr);
|
||||
}
|
||||
|
||||
TypePtr rt::create_vector_type(const TypePtr& elem) {
|
||||
auto _ = hilti::rt::profiler::start("zeek/rt/create_vector_type");
|
||||
return make_intrusive<VectorType>(elem);
|
||||
}
|
||||
|
||||
void rt::install_handler(const std::string& name) {
|
||||
auto _ = hilti::rt::profiler::start("zeek/rt/install_handler");
|
||||
spicy_mgr->registerEvent(name);
|
||||
}
|
||||
|
||||
EventHandlerPtr rt::internal_handler(const std::string& name) {
|
||||
auto _ = hilti::rt::profiler::start("zeek/rt/internal_handler");
|
||||
auto handler = event_registry->Lookup(name);
|
||||
|
||||
if ( ! handler )
|
||||
reporter->InternalError("Spicy event %s was not installed", name.c_str());
|
||||
|
||||
return handler;
|
||||
}
|
||||
|
||||
void rt::raise_event(const EventHandlerPtr& handler, const hilti::rt::Vector<ValPtr>& args) {
|
||||
auto _ = hilti::rt::profiler::start("zeek/rt/raise_event");
|
||||
|
||||
// Caller must have checked already that there's a handler available.
|
||||
assert(handler);
|
||||
|
||||
const auto& zeek_args = const_cast<EventHandlerPtr&>(handler)->GetType()->ParamList()->GetTypes();
|
||||
if ( args.size() != static_cast<uint64_t>(zeek_args.size()) )
|
||||
throw TypeMismatch(hilti::rt::fmt("expected %" PRIu64 " parameters, but got %zu",
|
||||
static_cast<uint64_t>(zeek_args.size()), args.size()));
|
||||
|
||||
Args vl = Args();
|
||||
vl.reserve(args.size());
|
||||
for ( const auto& v : args ) {
|
||||
if ( v )
|
||||
vl.emplace_back(v);
|
||||
else
|
||||
// Shouldn't happen here, but we have to_vals() that
|
||||
// (legitimately) return null in certain contexts.
|
||||
throw InvalidValue("null value encountered after conversion");
|
||||
}
|
||||
|
||||
event_mgr.Enqueue(handler, std::move(vl));
|
||||
}
|
||||
|
||||
TypePtr rt::event_arg_type(const EventHandlerPtr& handler, const hilti::rt::integer::safe<uint64_t>& idx) {
|
||||
auto _ = hilti::rt::profiler::start("zeek/rt/event_arg_type");
|
||||
assert(handler);
|
||||
|
||||
const auto& zeek_args = const_cast<EventHandlerPtr&>(handler)->GetType()->ParamList()->GetTypes();
|
||||
if ( idx >= static_cast<uint64_t>(zeek_args.size()) )
|
||||
throw TypeMismatch(hilti::rt::fmt("more parameters given than the %" PRIu64 " that the Zeek event expects",
|
||||
static_cast<uint64_t>(zeek_args.size())));
|
||||
|
||||
return zeek_args[idx];
|
||||
}
|
||||
|
||||
ValPtr& rt::current_conn() {
|
||||
auto _ = hilti::rt::profiler::start("zeek/rt/current_conn");
|
||||
auto cookie = static_cast<Cookie*>(hilti::rt::context::cookie());
|
||||
assert(cookie);
|
||||
|
||||
if ( cookie->cache.conn )
|
||||
return cookie->cache.conn;
|
||||
|
||||
if ( auto x = cookie->protocol ) {
|
||||
cookie->cache.conn = x->analyzer->Conn()->GetVal();
|
||||
return cookie->cache.conn;
|
||||
}
|
||||
else
|
||||
throw ValueUnavailable("$conn not available");
|
||||
}
|
||||
|
||||
ValPtr& rt::current_is_orig() {
|
||||
auto _ = hilti::rt::profiler::start("zeek/rt/current_is_orig");
|
||||
auto cookie = static_cast<Cookie*>(hilti::rt::context::cookie());
|
||||
assert(cookie);
|
||||
|
||||
if ( cookie->cache.is_orig )
|
||||
return cookie->cache.is_orig;
|
||||
|
||||
if ( auto x = cookie->protocol ) {
|
||||
cookie->cache.is_orig = val_mgr->Bool(x->is_orig);
|
||||
return cookie->cache.is_orig;
|
||||
}
|
||||
else
|
||||
throw ValueUnavailable("$is_orig not available");
|
||||
}
|
||||
|
||||
void rt::debug(const std::string& msg) {
|
||||
auto _ = hilti::rt::profiler::start("zeek/rt/debug");
|
||||
auto cookie = static_cast<Cookie*>(hilti::rt::context::cookie());
|
||||
assert(cookie);
|
||||
rt::debug(*cookie, msg);
|
||||
}
|
||||
|
||||
void rt::debug(const Cookie& cookie, const std::string& msg) {
|
||||
auto _ = hilti::rt::profiler::start("zeek/rt/debug");
|
||||
std::string name;
|
||||
std::string id;
|
||||
|
||||
if ( const auto p = cookie.protocol ) {
|
||||
auto name = p->analyzer->GetAnalyzerName();
|
||||
SPICY_DEBUG(
|
||||
hilti::rt::fmt("[%s/%" PRIu32 "/%s] %s", name, p->analyzer->GetID(), (p->is_orig ? "orig" : "resp"), msg));
|
||||
}
|
||||
else if ( const auto f = cookie.file ) {
|
||||
auto name = file_mgr->GetComponentName(f->analyzer->Tag());
|
||||
SPICY_DEBUG(hilti::rt::fmt("[%s/%" PRIu32 "] %s", name, f->analyzer->GetID(), msg));
|
||||
}
|
||||
else if ( const auto f = cookie.packet ) {
|
||||
auto name = packet_mgr->GetComponentName(f->analyzer->GetAnalyzerTag());
|
||||
SPICY_DEBUG(hilti::rt::fmt("[%s] %s", name, msg));
|
||||
}
|
||||
else
|
||||
throw ValueUnavailable("neither $conn nor $file nor packet analyzer available for debug logging");
|
||||
}
|
||||
|
||||
inline rt::cookie::FileStateStack* _file_state_stack(rt::Cookie* cookie) {
|
||||
auto _ = hilti::rt::profiler::start("zeek/rt/file_state_stack");
|
||||
|
||||
if ( auto c = cookie->protocol )
|
||||
return c->is_orig ? &c->fstate_orig : &c->fstate_resp;
|
||||
else if ( auto f = cookie->file )
|
||||
return &f->fstate;
|
||||
else
|
||||
throw rt::ValueUnavailable("no current connection or file available");
|
||||
}
|
||||
|
||||
inline const rt::cookie::FileState* _file_state(rt::Cookie* cookie, std::optional<std::string> fid) {
|
||||
auto _ = hilti::rt::profiler::start("zeek/rt/file_state");
|
||||
|
||||
auto* stack = _file_state_stack(cookie);
|
||||
if ( fid ) {
|
||||
if ( auto* fstate = stack->find(*fid) )
|
||||
return fstate;
|
||||
else
|
||||
throw rt::ValueUnavailable(hilti::rt::fmt("no file analysis currently in flight for file ID %s", fid));
|
||||
}
|
||||
else {
|
||||
if ( stack->isEmpty() )
|
||||
throw rt::ValueUnavailable("no file analysis currently in flight");
|
||||
|
||||
return stack->current();
|
||||
}
|
||||
}
|
||||
|
||||
ValPtr rt::current_file() {
|
||||
auto _ = hilti::rt::profiler::start("zeek/rt/current_file");
|
||||
auto cookie = static_cast<Cookie*>(hilti::rt::context::cookie());
|
||||
assert(cookie);
|
||||
|
||||
if ( auto x = cookie->file )
|
||||
return x->analyzer->GetFile()->ToVal();
|
||||
else if ( auto* fstate = _file_state(cookie, {}) ) {
|
||||
if ( auto* f = file_mgr->LookupFile(fstate->fid) )
|
||||
return f->ToVal();
|
||||
}
|
||||
|
||||
throw ValueUnavailable("$file not available");
|
||||
}
|
||||
|
||||
ValPtr rt::current_packet() {
|
||||
auto _ = hilti::rt::profiler::start("zeek/rt/current_packet");
|
||||
auto cookie = static_cast<Cookie*>(hilti::rt::context::cookie());
|
||||
assert(cookie);
|
||||
|
||||
if ( auto c = cookie->packet ) {
|
||||
if ( ! c->packet_val )
|
||||
// We cache the built value in case we need it multiple times.
|
||||
c->packet_val = c->packet->ToRawPktHdrVal();
|
||||
|
||||
return c->packet_val;
|
||||
}
|
||||
else
|
||||
throw ValueUnavailable("$packet not available");
|
||||
}
|
||||
|
||||
hilti::rt::Bool rt::is_orig() {
|
||||
auto _ = hilti::rt::profiler::start("zeek/rt/is_orig");
|
||||
auto cookie = static_cast<Cookie*>(hilti::rt::context::cookie());
|
||||
assert(cookie);
|
||||
|
||||
if ( auto x = cookie->protocol )
|
||||
return x->is_orig;
|
||||
else
|
||||
throw ValueUnavailable("is_orig() not available in current context");
|
||||
}
|
||||
|
||||
std::string rt::uid() {
|
||||
auto _ = hilti::rt::profiler::start("zeek/rt/uid");
|
||||
auto cookie = static_cast<Cookie*>(hilti::rt::context::cookie());
|
||||
assert(cookie);
|
||||
|
||||
if ( auto c = cookie->protocol ) {
|
||||
// Retrieve the ConnVal() so that we ensure the UID has been set.
|
||||
c->analyzer->ConnVal();
|
||||
return c->analyzer->Conn()->GetUID().Base62("C");
|
||||
}
|
||||
else
|
||||
throw ValueUnavailable("uid() not available in current context");
|
||||
}
|
||||
|
||||
std::tuple<hilti::rt::Address, hilti::rt::Port, hilti::rt::Address, hilti::rt::Port> rt::conn_id() {
|
||||
auto _ = hilti::rt::profiler::start("zeek/rt/conn_id");
|
||||
|
||||
static auto convert_address = [](const IPAddr& zaddr) -> hilti::rt::Address {
|
||||
const uint32_t* bytes = nullptr;
|
||||
if ( auto n = zaddr.GetBytes(&bytes); n == 1 )
|
||||
// IPv4
|
||||
return hilti::rt::Address(*reinterpret_cast<const struct in_addr*>(bytes));
|
||||
else if ( n == 4 )
|
||||
// IPv6
|
||||
return hilti::rt::Address(*reinterpret_cast<const struct in6_addr*>(bytes));
|
||||
else
|
||||
throw ValueUnavailable("unexpected IP address side from Zeek"); // shouldn't really be able to happen
|
||||
};
|
||||
|
||||
static auto convert_port = [](uint32_t port, TransportProto proto) -> hilti::rt::Port {
|
||||
auto p = ntohs(static_cast<uint16_t>(port));
|
||||
|
||||
switch ( proto ) {
|
||||
case TransportProto::TRANSPORT_ICMP: return {p, hilti::rt::Protocol::ICMP};
|
||||
case TransportProto::TRANSPORT_TCP: return {p, hilti::rt::Protocol::TCP};
|
||||
case TransportProto::TRANSPORT_UDP: return {p, hilti::rt::Protocol::UDP};
|
||||
case TransportProto::TRANSPORT_UNKNOWN: return {p, hilti::rt::Protocol::Undef};
|
||||
}
|
||||
|
||||
hilti::rt::cannot_be_reached();
|
||||
};
|
||||
|
||||
auto cookie = static_cast<Cookie*>(hilti::rt::context::cookie());
|
||||
assert(cookie);
|
||||
|
||||
if ( auto c = cookie->protocol ) {
|
||||
const auto* conn = c->analyzer->Conn();
|
||||
return std::make_tuple(convert_address(conn->OrigAddr()), convert_port(conn->OrigPort(), conn->ConnTransport()),
|
||||
convert_address(conn->RespAddr()),
|
||||
convert_port(conn->RespPort(), conn->ConnTransport()));
|
||||
}
|
||||
else
|
||||
throw ValueUnavailable("conn_id() not available in current context");
|
||||
}
|
||||
|
||||
void rt::flip_roles() {
|
||||
auto _ = hilti::rt::profiler::start("zeek/rt/flip_roles");
|
||||
auto cookie = static_cast<Cookie*>(hilti::rt::context::cookie());
|
||||
assert(cookie);
|
||||
|
||||
rt::debug(*cookie, "flipping roles");
|
||||
|
||||
if ( auto x = cookie->protocol )
|
||||
x->analyzer->Conn()->FlipRoles();
|
||||
else
|
||||
throw ValueUnavailable("flip_roles() not available in current context");
|
||||
}
|
||||
|
||||
hilti::rt::integer::safe<uint64_t> rt::number_packets() {
|
||||
auto _ = hilti::rt::profiler::start("zeek/rt/number_packets");
|
||||
auto cookie = static_cast<Cookie*>(hilti::rt::context::cookie());
|
||||
assert(cookie);
|
||||
|
||||
if ( auto x = cookie->protocol ) {
|
||||
return x->num_packets;
|
||||
}
|
||||
else
|
||||
throw ValueUnavailable("number_packets() not available in current context");
|
||||
}
|
||||
|
||||
void rt::confirm_protocol() {
|
||||
auto _ = hilti::rt::profiler::start("zeek/rt/confirm_protocol");
|
||||
auto cookie = static_cast<Cookie*>(hilti::rt::context::cookie());
|
||||
assert(cookie);
|
||||
|
||||
if ( cookie->cache.confirmed )
|
||||
return;
|
||||
|
||||
if ( auto x = cookie->protocol ) {
|
||||
auto tag = spicy_mgr->tagForProtocolAnalyzer(x->analyzer->GetAnalyzerTag());
|
||||
SPICY_DEBUG(hilti::rt::fmt("confirming protocol %s", tag.AsString()));
|
||||
cookie->cache.confirmed = true;
|
||||
return x->analyzer->AnalyzerConfirmation(tag);
|
||||
}
|
||||
throw ValueUnavailable("no current connection available");
|
||||
}
|
||||
|
||||
void rt::reject_protocol(const std::string& reason) {
|
||||
auto _ = hilti::rt::profiler::start("zeek/rt/reject_protocol");
|
||||
auto cookie = static_cast<Cookie*>(hilti::rt::context::cookie());
|
||||
assert(cookie);
|
||||
|
||||
if ( auto x = cookie->protocol ) {
|
||||
auto tag = spicy_mgr->tagForProtocolAnalyzer(x->analyzer->GetAnalyzerTag());
|
||||
SPICY_DEBUG(hilti::rt::fmt("rejecting protocol %s", tag.AsString()));
|
||||
return x->analyzer->AnalyzerViolation("protocol rejected", nullptr, 0, tag);
|
||||
}
|
||||
else
|
||||
throw ValueUnavailable("no current connection available");
|
||||
}
|
||||
|
||||
void rt::weird(const std::string& id, const std::string& addl) {
|
||||
auto _ = hilti::rt::profiler::start("zeek/rt/weird");
|
||||
auto cookie = static_cast<Cookie*>(hilti::rt::context::cookie());
|
||||
assert(cookie);
|
||||
|
||||
if ( const auto x = cookie->protocol )
|
||||
x->analyzer->Weird(id.c_str(), addl.data());
|
||||
else if ( const auto x = cookie->file )
|
||||
zeek::reporter->Weird(x->analyzer->GetFile(), id.c_str(), addl.data());
|
||||
else if ( const auto x = cookie->packet ) {
|
||||
x->analyzer->Weird(id.c_str(), x->packet, addl.c_str());
|
||||
}
|
||||
else
|
||||
throw ValueUnavailable("none of $conn, $file, or $packet available for weird reporting");
|
||||
}
|
||||
|
||||
void rt::protocol_begin(const std::optional<std::string>& analyzer) {
|
||||
auto _ = hilti::rt::profiler::start("zeek/rt/protocol_begin");
|
||||
|
||||
if ( analyzer ) {
|
||||
protocol_handle_get_or_create(*analyzer);
|
||||
return;
|
||||
}
|
||||
|
||||
// Instantiate a DPD analyzer.
|
||||
auto cookie = static_cast<Cookie*>(hilti::rt::context::cookie());
|
||||
assert(cookie);
|
||||
|
||||
auto c = cookie->protocol;
|
||||
if ( ! c )
|
||||
throw ValueUnavailable("no current connection available");
|
||||
|
||||
// Use a Zeek PIA stream analyzer performing DPD.
|
||||
auto pia_tcp = std::make_unique<analyzer::pia::PIA_TCP>(c->analyzer->Conn());
|
||||
|
||||
// Forward empty payload to trigger lifecycle management in this analyzer tree.
|
||||
c->analyzer->ForwardStream(0, reinterpret_cast<const u_char*>(c->analyzer), true);
|
||||
c->analyzer->ForwardStream(0, reinterpret_cast<const u_char*>(c->analyzer), false);
|
||||
|
||||
// Direct child of this type already exists. We ignore this silently
|
||||
// because that makes usage nicer if either side of the connection
|
||||
// might end up creating the analyzer; this way the user doesn't
|
||||
// need to track what the other side already did.
|
||||
//
|
||||
// We inspect the children directly to work around zeek/zeek#2899.
|
||||
const auto& children = c->analyzer->GetChildren();
|
||||
if ( auto it = std::find_if(children.begin(), children.end(),
|
||||
[&](const auto& it) {
|
||||
return ! it->Removing() && ! it->IsFinished() &&
|
||||
it->GetAnalyzerTag() == pia_tcp->GetAnalyzerTag();
|
||||
});
|
||||
it != children.end() )
|
||||
return;
|
||||
|
||||
auto child = pia_tcp.release();
|
||||
c->analyzer->AddChildAnalyzer(child);
|
||||
|
||||
child->FirstPacket(true, nullptr);
|
||||
child->FirstPacket(false, nullptr);
|
||||
}
|
||||
|
||||
rt::ProtocolHandle rt::protocol_handle_get_or_create(const std::string& analyzer) {
|
||||
auto _ = hilti::rt::profiler::start("zeek/rt/protocol_handle_get_or_create");
|
||||
auto cookie = static_cast<Cookie*>(hilti::rt::context::cookie());
|
||||
assert(cookie);
|
||||
|
||||
auto c = cookie->protocol;
|
||||
if ( ! c )
|
||||
throw ValueUnavailable("no current connection available");
|
||||
|
||||
// Forward empty payload to trigger lifecycle management in this analyzer tree.
|
||||
c->analyzer->ForwardStream(0, reinterpret_cast<const u_char*>(c->analyzer), true);
|
||||
c->analyzer->ForwardStream(0, reinterpret_cast<const u_char*>(c->analyzer), false);
|
||||
|
||||
// If the child already exists, do not add it again so this function is idempotent.
|
||||
//
|
||||
// We inspect the children directly to work around zeek/zeek#2899.
|
||||
const auto& children = c->analyzer->GetChildren();
|
||||
if ( auto it = std::find_if(children.begin(), children.end(),
|
||||
[&](const auto& it) {
|
||||
return ! it->Removing() && ! it->IsFinished() && it->GetAnalyzerName() == analyzer;
|
||||
});
|
||||
it != children.end() )
|
||||
return rt::ProtocolHandle((*it)->GetID());
|
||||
|
||||
auto child = analyzer_mgr->InstantiateAnalyzer(analyzer.c_str(), c->analyzer->Conn());
|
||||
if ( ! child )
|
||||
throw ZeekError(::hilti::rt::fmt("unknown analyzer '%s' requested", analyzer));
|
||||
|
||||
// If we had no such child before but cannot add it the analyzer was prevented.
|
||||
//
|
||||
// NOTE: We make this a hard error since returning e.g., an empty optional
|
||||
// here would make it easy to incorrectly use the return value with e.g.,
|
||||
// `protocol_data_in` or `protocol_gap`.
|
||||
if ( ! c->analyzer->AddChildAnalyzer(child) )
|
||||
throw ZeekError(::hilti::rt::fmt("creation of child analyzer %s was prevented", analyzer));
|
||||
|
||||
if ( c->analyzer->Conn()->ConnTransport() != TRANSPORT_TCP ) {
|
||||
// Some TCP application analyzer may expect to have access to a TCP
|
||||
// analyzer. To make that work, we'll create a fake TCP analyzer,
|
||||
// just so that they have something to access. It won't
|
||||
// semantically have any "TCP" to analyze obviously.
|
||||
c->fake_tcp = std::make_shared<packet_analysis::TCP::TCPSessionAdapter>(c->analyzer->Conn());
|
||||
static_cast<analyzer::Analyzer*>(c->fake_tcp.get())
|
||||
->Done(); // will never see packets; cast to get around protected inheritance
|
||||
}
|
||||
|
||||
auto* child_as_tcp = dynamic_cast<analyzer::tcp::TCP_ApplicationAnalyzer*>(child);
|
||||
if ( ! child_as_tcp )
|
||||
throw ZeekError(
|
||||
::hilti::rt::fmt("could not add analyzer '%s' to connection; not a TCP-based analyzer", analyzer));
|
||||
|
||||
if ( c->fake_tcp )
|
||||
child_as_tcp->SetTCP(c->fake_tcp.get());
|
||||
|
||||
return rt::ProtocolHandle(child->GetID());
|
||||
}
|
||||
|
||||
void rt::protocol_data_in(const hilti::rt::Bool& is_orig, const hilti::rt::Bytes& data,
|
||||
const std::optional<rt::ProtocolHandle>& h) {
|
||||
auto _ = hilti::rt::profiler::start("zeek/rt/protocol_data_in");
|
||||
auto cookie = static_cast<Cookie*>(hilti::rt::context::cookie());
|
||||
assert(cookie);
|
||||
|
||||
auto c = cookie->protocol;
|
||||
if ( ! c )
|
||||
throw ValueUnavailable("no current connection available");
|
||||
|
||||
auto len = data.size();
|
||||
auto* data_ = reinterpret_cast<const u_char*>(data.data());
|
||||
|
||||
if ( h ) {
|
||||
if ( auto* output_handler = c->analyzer->GetOutputHandler() )
|
||||
output_handler->DeliverStream(len, data_, is_orig);
|
||||
|
||||
auto* child = c->analyzer->FindChild(h->id());
|
||||
if ( ! child )
|
||||
throw ValueUnavailable(hilti::rt::fmt("unknown child analyzer %s", *h));
|
||||
|
||||
if ( child->IsFinished() || child->Removing() )
|
||||
throw ValueUnavailable(hilti::rt::fmt("child analyzer %s no longer exist", *h));
|
||||
|
||||
child->NextStream(len, data_, is_orig);
|
||||
}
|
||||
|
||||
else
|
||||
c->analyzer->ForwardStream(len, data_, is_orig);
|
||||
}
|
||||
|
||||
void rt::protocol_gap(const hilti::rt::Bool& is_orig, const hilti::rt::integer::safe<uint64_t>& offset,
|
||||
const hilti::rt::integer::safe<uint64_t>& len, const std::optional<rt::ProtocolHandle>& h) {
|
||||
auto _ = hilti::rt::profiler::start("zeek/rt/protocol_gap");
|
||||
auto cookie = static_cast<Cookie*>(hilti::rt::context::cookie());
|
||||
assert(cookie);
|
||||
|
||||
auto c = cookie->protocol;
|
||||
if ( ! c )
|
||||
throw ValueUnavailable("no current connection available");
|
||||
|
||||
if ( h ) {
|
||||
if ( auto* output_handler = c->analyzer->GetOutputHandler() )
|
||||
output_handler->Undelivered(offset, len, is_orig);
|
||||
|
||||
auto* child = c->analyzer->FindChild(h->id());
|
||||
if ( ! child )
|
||||
throw ValueUnavailable(hilti::rt::fmt("unknown child analyzer %s", *h));
|
||||
|
||||
if ( child->IsFinished() || child->Removing() )
|
||||
throw ValueUnavailable(hilti::rt::fmt("child analyzer %s no longer exist", *h));
|
||||
|
||||
child->NextUndelivered(offset, len, is_orig);
|
||||
}
|
||||
|
||||
else
|
||||
c->analyzer->ForwardUndelivered(offset, len, is_orig);
|
||||
}
|
||||
|
||||
void rt::protocol_end() {
|
||||
auto _ = hilti::rt::profiler::start("zeek/rt/protocol_end");
|
||||
auto cookie = static_cast<Cookie*>(hilti::rt::context::cookie());
|
||||
assert(cookie);
|
||||
|
||||
auto c = cookie->protocol;
|
||||
if ( ! c )
|
||||
throw ValueUnavailable("no current connection available");
|
||||
|
||||
for ( const auto& i : c->analyzer->GetChildren() )
|
||||
c->analyzer->RemoveChildAnalyzer(i);
|
||||
}
|
||||
|
||||
void rt::protocol_handle_close(const ProtocolHandle& handle) {
|
||||
auto _ = hilti::rt::profiler::start("zeek/rt/protocol_handle_close");
|
||||
auto cookie = static_cast<Cookie*>(hilti::rt::context::cookie());
|
||||
assert(cookie);
|
||||
|
||||
auto c = cookie->protocol;
|
||||
if ( ! c )
|
||||
throw ValueUnavailable("no current connection available");
|
||||
|
||||
auto child = c->analyzer->FindChild(handle.id());
|
||||
if ( ! child )
|
||||
throw ValueUnavailable(hilti::rt::fmt("unknown child analyzer %s", handle));
|
||||
|
||||
if ( child->IsFinished() || child->Removing() )
|
||||
throw ValueUnavailable(hilti::rt::fmt("child analyzer %s no longer exist", handle));
|
||||
|
||||
child->NextEndOfData(true);
|
||||
child->NextEndOfData(false);
|
||||
|
||||
c->analyzer->RemoveChildAnalyzer(handle.id());
|
||||
}
|
||||
|
||||
rt::cookie::FileState* rt::cookie::FileStateStack::push() {
|
||||
auto _ = hilti::rt::profiler::start("zeek/rt/file-stack-push");
|
||||
auto fid = file_mgr->HashHandle(hilti::rt::fmt("%s.%d", _analyzer_id, ++_id_counter));
|
||||
_stack.emplace_back(fid);
|
||||
return &_stack.back();
|
||||
}
|
||||
|
||||
const rt::cookie::FileState* rt::cookie::FileStateStack::find(const std::string& fid) const {
|
||||
auto _ = hilti::rt::profiler::start("zeek/rt/file-stack-find");
|
||||
|
||||
// Reverse search as the default state would be on top of the stack.
|
||||
for ( auto i = _stack.rbegin(); i != _stack.rend(); i++ ) {
|
||||
if ( i->fid == fid )
|
||||
return &*i;
|
||||
}
|
||||
|
||||
return nullptr;
|
||||
}
|
||||
|
||||
void rt::cookie::FileStateStack::remove(const std::string& fid) {
|
||||
auto _ = hilti::rt::profiler::start("zeek/rt/file-stack-remove");
|
||||
|
||||
// Reverse search as the default state would be on top of the stack.
|
||||
for ( auto i = _stack.rbegin(); i != _stack.rend(); i++ ) {
|
||||
if ( i->fid == fid ) {
|
||||
_stack.erase((i + 1).base()); // https://stackoverflow.com/a/1830240
|
||||
return;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
static void _data_in(const char* data, uint64_t len, std::optional<uint64_t> offset,
|
||||
const std::optional<std::string>& fid) {
|
||||
auto cookie = static_cast<rt::Cookie*>(hilti::rt::context::cookie());
|
||||
auto* fstate = _file_state(cookie, fid);
|
||||
auto data_ = reinterpret_cast<const unsigned char*>(data);
|
||||
auto mime_type = (fstate->mime_type ? *fstate->mime_type : std::string());
|
||||
|
||||
if ( auto c = cookie->protocol ) {
|
||||
auto tag = spicy_mgr->tagForProtocolAnalyzer(c->analyzer->GetAnalyzerTag());
|
||||
|
||||
if ( offset )
|
||||
file_mgr->DataIn(data_, len, *offset, tag, c->analyzer->Conn(), c->is_orig, fstate->fid, mime_type);
|
||||
else
|
||||
file_mgr->DataIn(data_, len, tag, c->analyzer->Conn(), c->is_orig, fstate->fid, mime_type);
|
||||
}
|
||||
else {
|
||||
if ( offset )
|
||||
file_mgr->DataIn(data_, len, *offset, Tag(), nullptr, false, fstate->fid, mime_type);
|
||||
else
|
||||
file_mgr->DataIn(data_, len, Tag(), nullptr, false, fstate->fid, mime_type);
|
||||
}
|
||||
}
|
||||
|
||||
void rt::terminate_session() {
|
||||
auto _ = hilti::rt::profiler::start("zeek/rt/terminate_session");
|
||||
auto cookie = static_cast<Cookie*>(hilti::rt::context::cookie());
|
||||
assert(cookie);
|
||||
|
||||
if ( auto c = cookie->protocol ) {
|
||||
assert(session_mgr);
|
||||
session_mgr->Remove(c->analyzer->Conn());
|
||||
}
|
||||
else
|
||||
throw spicy::rt::ValueUnavailable("terminate_session() not available in the current context");
|
||||
}
|
||||
|
||||
std::string rt::fuid() {
|
||||
auto _ = hilti::rt::profiler::start("zeek/rt/fuid");
|
||||
auto cookie = static_cast<Cookie*>(hilti::rt::context::cookie());
|
||||
assert(cookie);
|
||||
|
||||
if ( auto f = cookie->file ) {
|
||||
if ( auto file = f->analyzer->GetFile() )
|
||||
return file->GetID();
|
||||
}
|
||||
|
||||
throw ValueUnavailable("fuid() not available in current context");
|
||||
}
|
||||
|
||||
std::string rt::file_begin(const std::optional<std::string>& mime_type) {
|
||||
auto _ = hilti::rt::profiler::start("zeek/rt/file_begin");
|
||||
auto cookie = static_cast<Cookie*>(hilti::rt::context::cookie());
|
||||
auto* fstate = _file_state_stack(cookie)->push();
|
||||
fstate->mime_type = mime_type;
|
||||
|
||||
// Feed an empty chunk into the analysis to force creating the file state inside Zeek.
|
||||
_data_in("", 0, {}, {});
|
||||
|
||||
auto file = file_mgr->LookupFile(fstate->fid);
|
||||
assert(file); // passing in empty data ensures that this is now available
|
||||
|
||||
if ( auto f = cookie->file ) {
|
||||
// We need to initialize some fa_info fields ourselves that would
|
||||
// normally be inferred from the connection.
|
||||
|
||||
// Set the source to the current file analyzer.
|
||||
file->SetSource(file_mgr->GetComponentName(f->analyzer->Tag()));
|
||||
|
||||
// There are some fields inside the new fa_info record that we want to
|
||||
// set, but don't have a Zeek API for. Hence, we need to play some
|
||||
// tricks: we can get to the fa_info value, but read-only; const_cast
|
||||
// comes to our rescue. And then we just write directly into the
|
||||
// record fields.
|
||||
auto rval = file->ToVal()->AsRecordVal();
|
||||
auto current = f->analyzer->GetFile()->ToVal()->AsRecordVal();
|
||||
rval->Assign(id::fa_file->FieldOffset("parent_id"),
|
||||
current->GetField("id")); // set to parent
|
||||
rval->Assign(id::fa_file->FieldOffset("conns"),
|
||||
current->GetField("conns")); // copy from parent
|
||||
rval->Assign(id::fa_file->FieldOffset("is_orig"),
|
||||
current->GetField("is_orig")); // copy from parent
|
||||
}
|
||||
|
||||
// Double check everybody agrees on the file ID.
|
||||
assert(fstate->fid == file->GetID());
|
||||
return fstate->fid;
|
||||
}
|
||||
|
||||
void rt::file_set_size(const hilti::rt::integer::safe<uint64_t>& size, const std::optional<std::string>& fid) {
|
||||
auto _ = hilti::rt::profiler::start("zeek/rt/file_set_size");
|
||||
auto cookie = static_cast<Cookie*>(hilti::rt::context::cookie());
|
||||
auto* fstate = _file_state(cookie, fid);
|
||||
|
||||
if ( auto c = cookie->protocol ) {
|
||||
auto tag = spicy_mgr->tagForProtocolAnalyzer(c->analyzer->GetAnalyzerTag());
|
||||
file_mgr->SetSize(size, tag, c->analyzer->Conn(), c->is_orig, fstate->fid);
|
||||
}
|
||||
else
|
||||
file_mgr->SetSize(size, Tag(), nullptr, false, fstate->fid);
|
||||
}
|
||||
|
||||
void rt::file_data_in(const hilti::rt::Bytes& data, const std::optional<std::string>& fid) {
|
||||
auto _ = hilti::rt::profiler::start("zeek/rt/file_data_in");
|
||||
_data_in(data.data(), data.size(), {}, fid);
|
||||
}
|
||||
|
||||
void rt::file_data_in_at_offset(const hilti::rt::Bytes& data, const hilti::rt::integer::safe<uint64_t>& offset,
|
||||
const std::optional<std::string>& fid) {
|
||||
auto _ = hilti::rt::profiler::start("zeek/rt/file_data_in_at_offset");
|
||||
_data_in(data.data(), data.size(), offset, fid);
|
||||
}
|
||||
|
||||
void rt::file_gap(const hilti::rt::integer::safe<uint64_t>& offset, const hilti::rt::integer::safe<uint64_t>& len,
|
||||
const std::optional<std::string>& fid) {
|
||||
auto _ = hilti::rt::profiler::start("zeek/rt/file_gap");
|
||||
auto cookie = static_cast<Cookie*>(hilti::rt::context::cookie());
|
||||
auto* fstate = _file_state(cookie, fid);
|
||||
|
||||
if ( auto c = cookie->protocol ) {
|
||||
auto tag = spicy_mgr->tagForProtocolAnalyzer(c->analyzer->GetAnalyzerTag());
|
||||
file_mgr->Gap(offset, len, tag, c->analyzer->Conn(), c->is_orig, fstate->fid);
|
||||
}
|
||||
else
|
||||
file_mgr->Gap(offset, len, Tag(), nullptr, false, fstate->fid);
|
||||
}
|
||||
|
||||
void rt::file_end(const std::optional<std::string>& fid) {
|
||||
auto _ = hilti::rt::profiler::start("zeek/rt/file_end");
|
||||
auto cookie = static_cast<Cookie*>(hilti::rt::context::cookie());
|
||||
auto* fstate = _file_state(cookie, fid);
|
||||
|
||||
file_mgr->EndOfFile(fstate->fid);
|
||||
_file_state_stack(cookie)->remove(fstate->fid);
|
||||
}
|
||||
|
||||
void rt::forward_packet(const hilti::rt::integer::safe<uint32_t>& identifier) {
|
||||
auto _ = hilti::rt::profiler::start("zeek/rt/forward_packet");
|
||||
auto cookie = static_cast<Cookie*>(hilti::rt::context::cookie());
|
||||
assert(cookie);
|
||||
|
||||
if ( auto c = cookie->packet )
|
||||
c->next_analyzer = identifier;
|
||||
else
|
||||
throw ValueUnavailable("no current packet analyzer available");
|
||||
}
|
||||
|
||||
hilti::rt::Time rt::network_time() {
|
||||
auto _ = hilti::rt::profiler::start("zeek/rt/network_time");
|
||||
return hilti::rt::Time(run_state::network_time, hilti::rt::Time::SecondTag());
|
||||
}
|
889
src/spicy/runtime-support.h
Normal file
889
src/spicy/runtime-support.h
Normal file
|
@ -0,0 +1,889 @@
|
|||
// See the file "COPYING" in the main distribution directory for copyright.
|
||||
|
||||
/**
|
||||
* Functions and types available to generated Spicy/Zeek glue code.
|
||||
*/
|
||||
|
||||
#pragma once
|
||||
|
||||
#include <limits>
|
||||
#include <memory>
|
||||
#include <optional>
|
||||
#include <ostream>
|
||||
#include <string>
|
||||
#include <tuple>
|
||||
#include <utility>
|
||||
|
||||
#include <hilti/rt/deferred-expression.h>
|
||||
#include <hilti/rt/exception.h>
|
||||
#include <hilti/rt/extension-points.h>
|
||||
#include <hilti/rt/fmt.h>
|
||||
#include <hilti/rt/types/all.h>
|
||||
|
||||
#include "zeek/Desc.h"
|
||||
#include "zeek/spicy/cookie.h"
|
||||
|
||||
namespace zeek::spicy::rt {
|
||||
|
||||
// Adapt to rename of exception.
|
||||
#if SPICY_VERSION_NUMBER >= 10700
|
||||
using UsageError = ::hilti::rt::UsageError;
|
||||
#else
|
||||
using UsageError = ::hilti::rt::UserException;
|
||||
#endif
|
||||
|
||||
/**
|
||||
* Exception thrown by event generation code if the value of an `$...`
|
||||
* expression isn't available.
|
||||
*/
|
||||
class ValueUnavailable : public UsageError {
|
||||
public:
|
||||
using UsageError::UsageError;
|
||||
};
|
||||
|
||||
/**
|
||||
* Exception thrown by event generation code if the values can't be converted
|
||||
* to Zeek.
|
||||
*/
|
||||
class InvalidValue : public UsageError {
|
||||
public:
|
||||
using UsageError::UsageError;
|
||||
};
|
||||
|
||||
/**
|
||||
* Exception thrown by event generation code if functionality is used
|
||||
* that the current build does not support.
|
||||
*/
|
||||
class Unsupported : public UsageError {
|
||||
public:
|
||||
using UsageError::UsageError;
|
||||
};
|
||||
|
||||
/**
|
||||
* Exception thrown by event generation code if there's a type mismatch
|
||||
* between the Spicy-side value and what the Zeek event expects.
|
||||
*/
|
||||
class TypeMismatch : public UsageError {
|
||||
public:
|
||||
TypeMismatch(const std::string_view& msg, std::string_view location = "")
|
||||
: UsageError(hilti::rt::fmt("Event parameter mismatch, %s", msg)) {}
|
||||
TypeMismatch(const std::string_view& have, TypePtr want, std::string_view location = "")
|
||||
: TypeMismatch(_fmt(have, want)) {}
|
||||
|
||||
private:
|
||||
std::string _fmt(const std::string_view& have, TypePtr want) {
|
||||
ODesc d;
|
||||
want->Describe(&d);
|
||||
return hilti::rt::fmt("cannot convert Spicy value of type '%s' to Zeek value of type '%s'", have,
|
||||
d.Description());
|
||||
}
|
||||
};
|
||||
|
||||
/**
|
||||
* Exception thrown by the runtime library when Zeek has flagged a problem.
|
||||
*/
|
||||
class ZeekError : public UsageError {
|
||||
public:
|
||||
using UsageError::UsageError;
|
||||
};
|
||||
|
||||
/**
|
||||
* Registers a Spicy protocol analyzer with its EVT meta information with the
|
||||
* plugin's runtime.
|
||||
*/
|
||||
void register_protocol_analyzer(const std::string& name, hilti::rt::Protocol proto,
|
||||
const hilti::rt::Vector<hilti::rt::Port>& ports, const std::string& parser_orig,
|
||||
const std::string& parser_resp, const std::string& replaces,
|
||||
const std::string& linker_scope);
|
||||
|
||||
/**
|
||||
* Registers a Spicy file analyzer with its EVT meta information with the
|
||||
* plugin's runtime.
|
||||
*/
|
||||
void register_file_analyzer(const std::string& name, const hilti::rt::Vector<std::string>& mime_types,
|
||||
const std::string& parser, const std::string& replaces, const std::string& linker_scope);
|
||||
|
||||
/** Reports a Zeek-side "weird". */
|
||||
void weird(const std::string& id, const std::string& addl);
|
||||
|
||||
/**
|
||||
* Registers a Spicy packet analyzer with its EVT meta information with the
|
||||
* plugin's runtime.
|
||||
*/
|
||||
void register_packet_analyzer(const std::string& name, const std::string& parser, const std::string& replaces,
|
||||
const std::string& linker_scope);
|
||||
|
||||
/** Registers a Spicy-generated type to make it available inside Zeek. */
|
||||
void register_type(const std::string& ns, const std::string& id, const TypePtr& type);
|
||||
|
||||
/** Identifies a Zeek-side type. */
|
||||
enum class ZeekTypeTag : uint64_t {
|
||||
Addr,
|
||||
Any,
|
||||
Bool,
|
||||
Count,
|
||||
Double,
|
||||
Enum,
|
||||
Error,
|
||||
File,
|
||||
Func,
|
||||
Int,
|
||||
Interval,
|
||||
List,
|
||||
Opaque,
|
||||
Pattern,
|
||||
Port,
|
||||
Record,
|
||||
String,
|
||||
Subnet,
|
||||
Table,
|
||||
Time,
|
||||
Type,
|
||||
Vector,
|
||||
Void,
|
||||
};
|
||||
|
||||
extern TypePtr create_base_type(ZeekTypeTag tag);
|
||||
|
||||
extern TypePtr create_enum_type(
|
||||
const std::string& ns, const std::string& id,
|
||||
const hilti::rt::Vector<std::tuple<std::string, hilti::rt::integer::safe<int64_t>>>& labels);
|
||||
|
||||
using RecordField = std::tuple<std::string, TypePtr, hilti::rt::Bool>; // (ID, type, optional)
|
||||
extern TypePtr create_record_type(const std::string& ns, const std::string& id,
|
||||
const hilti::rt::Vector<RecordField>& fields);
|
||||
|
||||
extern TypePtr create_table_type(TypePtr key, std::optional<TypePtr> value);
|
||||
extern TypePtr create_vector_type(const TypePtr& elem);
|
||||
|
||||
/** Returns true if an event has at least one handler defined. */
|
||||
inline hilti::rt::Bool have_handler(const EventHandlerPtr& handler) { return static_cast<bool>(handler); }
|
||||
|
||||
/**
|
||||
* Creates a new event handler under the given name.
|
||||
*/
|
||||
void install_handler(const std::string& name);
|
||||
|
||||
/**
|
||||
* Looks up an event handler by name. The handler must have been installed
|
||||
* before through `install_handler()`.
|
||||
*/
|
||||
EventHandlerPtr internal_handler(const std::string& name);
|
||||
|
||||
/** Raises a Zeek event, given the handler and arguments. */
|
||||
void raise_event(const EventHandlerPtr& handler, const hilti::rt::Vector<ValPtr>& args);
|
||||
|
||||
/**
|
||||
* Returns the Zeek type of an event's i'th argument. The result's ref count
|
||||
* is not increased.
|
||||
*/
|
||||
TypePtr event_arg_type(const EventHandlerPtr& handler, const hilti::rt::integer::safe<uint64_t>& idx);
|
||||
|
||||
/**
|
||||
* Retrieves the connection ID for the currently processed Zeek connection.
|
||||
* Assumes that the HILTI context's cookie value has been set accordingly.
|
||||
*
|
||||
* @return Zeek value of record type
|
||||
*/
|
||||
ValPtr& current_conn();
|
||||
|
||||
/**
|
||||
* Retrieves the direction of the currently processed Zeek connection.
|
||||
* Assumes that the HILTI context's cookie value has been set accordingly.
|
||||
*
|
||||
* @return Zeek value of boolean type
|
||||
*/
|
||||
ValPtr& current_is_orig();
|
||||
|
||||
/**
|
||||
* Logs a string through the Spicy plugin's debug output.
|
||||
*
|
||||
* @param cookie refers to the connection or file that the message is associated with
|
||||
* @param msg message to log
|
||||
*/
|
||||
void debug(const Cookie& cookie, const std::string& msg);
|
||||
|
||||
/**
|
||||
* Logs a string through the Spicy plugin's debug output. This version logs
|
||||
* the information the currently processed connection or file.
|
||||
*
|
||||
* @param msg message to log
|
||||
*/
|
||||
void debug(const std::string& msg);
|
||||
|
||||
/**
|
||||
* Retrieves the fa_file instance for the currently processed Zeek file.
|
||||
* Assumes that the HILTI context's cookie value has been set accordingly.
|
||||
*
|
||||
* @return Zeek value of record type
|
||||
*/
|
||||
ValPtr current_file();
|
||||
|
||||
/**
|
||||
* Retrieves a `raw_pkt_hdr` instance for the currently processed Zeek packet.
|
||||
* Assumes that the HILTI context's cookie value has been set accordingly.
|
||||
*
|
||||
* @return Zeek value of record type
|
||||
*/
|
||||
ValPtr current_packet();
|
||||
|
||||
/**
|
||||
* Returns true if we're currently parsing the originator side of a
|
||||
* connection.
|
||||
*/
|
||||
hilti::rt::Bool is_orig();
|
||||
|
||||
/**
|
||||
* Returns the current connection's UID.
|
||||
*/
|
||||
std::string uid();
|
||||
|
||||
/**
|
||||
* Returns the current connection's ID tuple.
|
||||
*/
|
||||
std::tuple<hilti::rt::Address, hilti::rt::Port, hilti::rt::Address, hilti::rt::Port> conn_id();
|
||||
|
||||
/** Instructs to Zeek to flip the directionality of the current connecction. */
|
||||
void flip_roles();
|
||||
|
||||
/**
|
||||
* Returns the number of packets seen so far on the current side of the
|
||||
* current connection.
|
||||
*/
|
||||
hilti::rt::integer::safe<uint64_t> number_packets();
|
||||
|
||||
/**
|
||||
* Triggers a DPD protocol confirmation for the currently processed
|
||||
* connection. Assumes that the HILTI context's cookie value has been set
|
||||
* accordingly.
|
||||
*/
|
||||
void confirm_protocol();
|
||||
|
||||
/**
|
||||
* Triggers a DPD protocol violation for the currently processed connection.
|
||||
* Assumes that the HILTI context's cookie value has been set accordingly.
|
||||
*
|
||||
* @param reason short description of what went wrong
|
||||
*/
|
||||
void reject_protocol(const std::string& reason);
|
||||
|
||||
/**
|
||||
* Opaque handle to a protocol analyzer.
|
||||
*/
|
||||
class ProtocolHandle {
|
||||
public:
|
||||
ProtocolHandle() {}
|
||||
explicit ProtocolHandle(uint64_t id) : _id(id) {}
|
||||
|
||||
uint64_t id() const {
|
||||
if ( ! _id )
|
||||
throw ValueUnavailable("uninitialized protocol handle");
|
||||
|
||||
return *_id;
|
||||
}
|
||||
|
||||
friend std::string to_string(const ProtocolHandle& h, ::hilti::rt::detail::adl::tag) {
|
||||
if ( ! h._id )
|
||||
return "(uninitialized protocol handle)";
|
||||
|
||||
return std::to_string(*h._id);
|
||||
}
|
||||
|
||||
friend std::ostream& operator<<(std::ostream& stream, const ProtocolHandle& h) {
|
||||
return stream << ::hilti::rt::to_string(h);
|
||||
}
|
||||
|
||||
private:
|
||||
std::optional<uint64_t> _id;
|
||||
};
|
||||
|
||||
/**
|
||||
* Adds a Zeek-side child protocol analyzer to the current connection.
|
||||
*
|
||||
* @param analyzer if given, the Zeek-side name of the analyzer to instantiate;
|
||||
* if not given, DPD will be used
|
||||
*/
|
||||
void protocol_begin(const std::optional<std::string>& analyzer);
|
||||
|
||||
/**
|
||||
* Gets a handle to a child analyzer of a given type. If a child of that type
|
||||
* does not yet exist it will be created.
|
||||
*
|
||||
* @param analyzer the Zeek-side name of the analyzer to get (e.g., `HTTP`)
|
||||
*
|
||||
* @return a handle to the child analyzer. When done, the handle should be
|
||||
* closed, either explicitly with protocol_handle_close or implicitly with
|
||||
* protocol_end.
|
||||
*/
|
||||
ProtocolHandle protocol_handle_get_or_create(const std::string& analyzer);
|
||||
|
||||
/**
|
||||
* Forwards data to all previously instantiated Zeek-side child protocol
|
||||
* analyzers.
|
||||
*
|
||||
* @param is_orig true to feed data to originator side, false for responder
|
||||
* @param data next chunk of stream data for child analyzer to process
|
||||
* @param h optional handle to the child analyzer to stream data into
|
||||
*/
|
||||
void protocol_data_in(const hilti::rt::Bool& is_orig, const hilti::rt::Bytes& data,
|
||||
const std::optional<ProtocolHandle>& h = {});
|
||||
|
||||
/**
|
||||
* Signals a gap in input data to all previously instantiated Zeek-side child
|
||||
* protocol analyzers.
|
||||
*
|
||||
* @param is_orig true to signal gap to originator side, false for responder
|
||||
* @param offset of the gap inside the protocol stream
|
||||
* @param length of the gap
|
||||
* @param h optional handle to the child analyzer to signal a gap to
|
||||
*/
|
||||
void protocol_gap(const hilti::rt::Bool& is_orig, const hilti::rt::integer::safe<uint64_t>& offset,
|
||||
const hilti::rt::integer::safe<uint64_t>& len, const std::optional<ProtocolHandle>& h = {});
|
||||
|
||||
/**
|
||||
* Signals EOD to all previously instantiated Zeek-side child protocol
|
||||
* analyzers and removes them.
|
||||
*/
|
||||
void protocol_end();
|
||||
|
||||
/**
|
||||
* Closes a protocol handle.
|
||||
*
|
||||
* @param handle handle of the protocol analyzer to close.
|
||||
*/
|
||||
void protocol_handle_close(const ProtocolHandle& handle);
|
||||
|
||||
/**
|
||||
* Signals the beginning of a file to Zeek's file analysis, associating it
|
||||
* with the current connection.
|
||||
*
|
||||
* param mime_type optional mime type passed to Zeek
|
||||
* @returns Zeek-side file ID of the new file
|
||||
*/
|
||||
std::string file_begin(const std::optional<std::string>& mime_type);
|
||||
|
||||
/**
|
||||
* Returns the current file's FUID.
|
||||
*/
|
||||
std::string fuid();
|
||||
|
||||
/**
|
||||
* Terminates the currently active Zeek-side session, flushing all state. Any
|
||||
* subsequent activity will start a new session from scratch.
|
||||
*/
|
||||
void terminate_session();
|
||||
|
||||
/**
|
||||
* Signals the expected size of a file to Zeek's file analysis.
|
||||
*
|
||||
* @param size expected final size of the file
|
||||
* @param fid ID of the file to operate on; if unset, the most recently begun file is used
|
||||
*/
|
||||
void file_set_size(const hilti::rt::integer::safe<uint64_t>& size, const std::optional<std::string>& fid = {});
|
||||
|
||||
/**
|
||||
* Passes file content on to Zeek's file analysis.
|
||||
*
|
||||
* @param data next chunk of data
|
||||
* @param fid ID of the file to operate on; if unset, the most recently begun file is used
|
||||
*/
|
||||
void file_data_in(const hilti::rt::Bytes& data, const std::optional<std::string>& fid = {});
|
||||
|
||||
/**
|
||||
* Passes file content at a specific offset on to Zeek's file analysis.
|
||||
*
|
||||
* @param data next chunk of data
|
||||
* @param offset file offset of the data geing passed in
|
||||
* @param fid ID of the file to operate on; if unset, the most recently begun file is used
|
||||
*/
|
||||
void file_data_in_at_offset(const hilti::rt::Bytes& data, const hilti::rt::integer::safe<uint64_t>& offset,
|
||||
const std::optional<std::string>& fid = {});
|
||||
|
||||
/**
|
||||
* Signals a gap in a file to Zeek's file analysis.
|
||||
*
|
||||
* @param offset of the gap
|
||||
* @param length of the gap
|
||||
* @param fid ID of the file to operate on; if unset, the most recently begun file is used
|
||||
*/
|
||||
void file_gap(const hilti::rt::integer::safe<uint64_t>& offset, const hilti::rt::integer::safe<uint64_t>& len,
|
||||
const std::optional<std::string>& fid = {});
|
||||
|
||||
/**
|
||||
* Signals the end of a file to Zeek's file analysis.
|
||||
*
|
||||
* @param fid ID of the file to operate on; if unset, the most recently begun file is used
|
||||
*/
|
||||
void file_end(const std::optional<std::string>& fid = {});
|
||||
|
||||
/** Specifies the next-layer packet analyzer. */
|
||||
void forward_packet(const hilti::rt::integer::safe<uint32_t>& identifier);
|
||||
|
||||
/** Gets the network time from Zeek. */
|
||||
hilti::rt::Time network_time();
|
||||
|
||||
// Forward-declare to_val() functions.
|
||||
template<typename T, typename std::enable_if_t<hilti::rt::is_tuple<T>::value>* = nullptr>
|
||||
ValPtr to_val(const T& t, TypePtr target);
|
||||
template<typename T, typename std::enable_if_t<std::is_base_of<::hilti::rt::trait::isStruct, T>::value>* = nullptr>
|
||||
ValPtr to_val(const T& t, TypePtr target);
|
||||
template<typename T, typename std::enable_if_t<std::is_enum<typename T::Value>::value>* = nullptr>
|
||||
ValPtr to_val(const T& t, TypePtr target);
|
||||
template<typename T, typename std::enable_if_t<std::is_enum<T>::value>* = nullptr>
|
||||
ValPtr to_val(const T& t, TypePtr target);
|
||||
template<typename K, typename V>
|
||||
ValPtr to_val(const hilti::rt::Map<K, V>& s, TypePtr target);
|
||||
template<typename T>
|
||||
ValPtr to_val(const hilti::rt::Set<T>& s, TypePtr target);
|
||||
template<typename T>
|
||||
ValPtr to_val(const hilti::rt::Vector<T>& v, TypePtr target);
|
||||
template<typename T>
|
||||
ValPtr to_val(const std::optional<T>& t, TypePtr target);
|
||||
template<typename T>
|
||||
ValPtr to_val(const hilti::rt::DeferredExpression<T>& t, TypePtr target);
|
||||
template<typename T>
|
||||
ValPtr to_val(hilti::rt::integer::safe<T> i, TypePtr target);
|
||||
template<typename T>
|
||||
ValPtr to_val(const hilti::rt::ValueReference<T>& t, TypePtr target);
|
||||
|
||||
inline ValPtr to_val(const hilti::rt::Bool& b, TypePtr target);
|
||||
inline ValPtr to_val(const hilti::rt::Address& d, TypePtr target);
|
||||
inline ValPtr to_val(const hilti::rt::Bytes& b, TypePtr target);
|
||||
inline ValPtr to_val(const hilti::rt::Interval& t, TypePtr target);
|
||||
inline ValPtr to_val(const hilti::rt::Port& d, TypePtr target);
|
||||
inline ValPtr to_val(const hilti::rt::Time& t, TypePtr target);
|
||||
inline ValPtr to_val(const std::string& s, TypePtr target);
|
||||
inline ValPtr to_val(double r, TypePtr target);
|
||||
|
||||
/**
|
||||
* Converts a Spicy-side optional value to a Zeek value. This assumes the
|
||||
* optional is set, and will throw an exception if not. The result is
|
||||
* returned with ref count +1.
|
||||
*/
|
||||
template<typename T>
|
||||
inline ValPtr to_val(const std::optional<T>& t, TypePtr target) {
|
||||
if ( t.has_value() )
|
||||
return to_val(hilti::rt::optional::value(t), target);
|
||||
|
||||
return nullptr;
|
||||
}
|
||||
|
||||
/**
|
||||
* Converts a Spicy-side DeferredExpression<T> value to a Zeek value. Such
|
||||
* result values are returned by the ``.?`` operator. If the result is not
|
||||
* set, this will convert into nullptr (which the tuple-to-record to_val()
|
||||
* picks up on).
|
||||
*/
|
||||
template<typename T>
|
||||
inline ValPtr to_val(const hilti::rt::DeferredExpression<T>& t, TypePtr target) {
|
||||
try {
|
||||
return to_val(t(), target);
|
||||
} catch ( const hilti::rt::AttributeNotSet& ) {
|
||||
return nullptr;
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Converts a Spicy-side string to a Zeek value. The result is returned with
|
||||
* ref count +1.
|
||||
*/
|
||||
inline ValPtr to_val(const std::string& s, TypePtr target) {
|
||||
if ( target->Tag() != TYPE_STRING )
|
||||
throw TypeMismatch("string", target);
|
||||
|
||||
return make_intrusive<StringVal>(s);
|
||||
}
|
||||
|
||||
/**
|
||||
* Converts a Spicy-side bytes instance to a Zeek value. The result is returned with
|
||||
* ref count +1.
|
||||
*/
|
||||
inline ValPtr to_val(const hilti::rt::Bytes& b, TypePtr target) {
|
||||
if ( target->Tag() != TYPE_STRING )
|
||||
throw TypeMismatch("string", target);
|
||||
|
||||
return make_intrusive<StringVal>(b.str());
|
||||
}
|
||||
|
||||
/**
|
||||
* Converts a Spicy-side integer to a Zeek value. The result is
|
||||
* returned with ref count +1.
|
||||
*/
|
||||
template<typename T>
|
||||
inline ValPtr to_val(hilti::rt::integer::safe<T> i, TypePtr target) {
|
||||
ValPtr v = nullptr;
|
||||
if constexpr ( std::is_unsigned<T>::value ) {
|
||||
if ( target->Tag() == TYPE_COUNT )
|
||||
return val_mgr->Count(i);
|
||||
|
||||
if ( target->Tag() == TYPE_INT )
|
||||
return val_mgr->Int(i);
|
||||
|
||||
throw TypeMismatch("uint64", target);
|
||||
}
|
||||
else {
|
||||
if ( target->Tag() == TYPE_INT )
|
||||
return val_mgr->Int(i);
|
||||
|
||||
if ( target->Tag() == TYPE_COUNT ) {
|
||||
if ( i >= 0 )
|
||||
return val_mgr->Count(i);
|
||||
else
|
||||
throw TypeMismatch("negative int64", target);
|
||||
}
|
||||
|
||||
throw TypeMismatch("int64", target);
|
||||
}
|
||||
}
|
||||
|
||||
template<typename T>
|
||||
ValPtr to_val(const hilti::rt::ValueReference<T>& t, TypePtr target) {
|
||||
if ( auto* x = t.get() )
|
||||
return to_val(*x, target);
|
||||
|
||||
return nullptr;
|
||||
}
|
||||
|
||||
/**
|
||||
* Converts a Spicy-side signed bool to a Zeek value. The result is
|
||||
* returned with ref count +1.
|
||||
*/
|
||||
inline ValPtr to_val(const hilti::rt::Bool& b, TypePtr target) {
|
||||
if ( target->Tag() != TYPE_BOOL )
|
||||
throw TypeMismatch("bool", target);
|
||||
|
||||
return val_mgr->Bool(b);
|
||||
}
|
||||
|
||||
/**
|
||||
* Converts a Spicy-side real to a Zeek value. The result is returned with
|
||||
* ref count +1.
|
||||
*/
|
||||
inline ValPtr to_val(double r, TypePtr target) {
|
||||
if ( target->Tag() != TYPE_DOUBLE )
|
||||
throw TypeMismatch("double", target);
|
||||
|
||||
return make_intrusive<DoubleVal>(r);
|
||||
}
|
||||
|
||||
/**
|
||||
* Converts a Spicy-side address to a Zeek value. The result is returned with
|
||||
* ref count +1.
|
||||
*/
|
||||
inline ValPtr to_val(const hilti::rt::Address& d, TypePtr target) {
|
||||
if ( target->Tag() != TYPE_ADDR )
|
||||
throw TypeMismatch("addr", target);
|
||||
|
||||
auto in_addr = d.asInAddr();
|
||||
if ( auto v4 = std::get_if<struct in_addr>(&in_addr) )
|
||||
return make_intrusive<AddrVal>(IPAddr(*v4));
|
||||
else {
|
||||
auto v6 = std::get<struct in6_addr>(in_addr);
|
||||
return make_intrusive<AddrVal>(IPAddr(v6));
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Converts a Spicy-side address to a Zeek value. The result is returned with
|
||||
* ref count +1.
|
||||
*/
|
||||
inline ValPtr to_val(const hilti::rt::Port& p, TypePtr target) {
|
||||
if ( target->Tag() != TYPE_PORT )
|
||||
throw TypeMismatch("port", target);
|
||||
|
||||
#if SPICY_VERSION_NUMBER >= 10700
|
||||
auto proto = p.protocol().value();
|
||||
#else
|
||||
auto proto = p.protocol();
|
||||
#endif
|
||||
|
||||
switch ( proto ) {
|
||||
case hilti::rt::Protocol::TCP: return val_mgr->Port(p.port(), ::TransportProto::TRANSPORT_TCP);
|
||||
|
||||
case hilti::rt::Protocol::UDP: return val_mgr->Port(p.port(), ::TransportProto::TRANSPORT_UDP);
|
||||
|
||||
case hilti::rt::Protocol::ICMP: return val_mgr->Port(p.port(), ::TransportProto::TRANSPORT_ICMP);
|
||||
|
||||
default: throw InvalidValue("port value with undefined protocol");
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Converts a Spicy-side time to a Zeek value. The result is returned with
|
||||
* ref count +1.
|
||||
*/
|
||||
inline ValPtr to_val(const hilti::rt::Interval& i, TypePtr target) {
|
||||
if ( target->Tag() != TYPE_INTERVAL )
|
||||
throw TypeMismatch("interval", target);
|
||||
|
||||
return make_intrusive<IntervalVal>(i.seconds());
|
||||
}
|
||||
|
||||
/**
|
||||
* Converts a Spicy-side time to a Zeek value. The result is returned with
|
||||
* ref count +1.
|
||||
*/
|
||||
inline ValPtr to_val(const hilti::rt::Time& t, TypePtr target) {
|
||||
if ( target->Tag() != TYPE_TIME )
|
||||
throw TypeMismatch("time", target);
|
||||
|
||||
return make_intrusive<TimeVal>(t.seconds());
|
||||
}
|
||||
|
||||
/**
|
||||
* Converts a Spicy-side vector to a Zeek value. The result is returned with
|
||||
* ref count +1.
|
||||
*/
|
||||
template<typename T>
|
||||
inline ValPtr to_val(const hilti::rt::Vector<T>& v, TypePtr target) {
|
||||
if ( target->Tag() != TYPE_VECTOR && target->Tag() != TYPE_LIST )
|
||||
throw TypeMismatch("expected vector or list", target);
|
||||
|
||||
auto vt = cast_intrusive<VectorType>(target);
|
||||
auto zv = make_intrusive<VectorVal>(vt);
|
||||
for ( const auto& i : v )
|
||||
zv->Assign(zv->Size(), to_val(i, vt->Yield()));
|
||||
|
||||
return zv;
|
||||
}
|
||||
|
||||
/**
|
||||
* Converts a Spicy-side map to a Zeek value. The result is returned with
|
||||
* ref count +1.
|
||||
*/
|
||||
template<typename K, typename V>
|
||||
inline ValPtr to_val(const hilti::rt::Map<K, V>& m, TypePtr target) {
|
||||
if constexpr ( hilti::rt::is_tuple<K>::value )
|
||||
throw TypeMismatch("internal error: sets with tuples not yet supported in to_val()");
|
||||
|
||||
if ( target->Tag() != TYPE_TABLE )
|
||||
throw TypeMismatch("map", target);
|
||||
|
||||
auto tt = cast_intrusive<TableType>(target);
|
||||
if ( tt->IsSet() )
|
||||
throw TypeMismatch("map", target);
|
||||
|
||||
if ( tt->GetIndexTypes().size() != 1 )
|
||||
throw TypeMismatch("map with non-tuple elements", target);
|
||||
|
||||
auto zv = make_intrusive<TableVal>(tt);
|
||||
|
||||
for ( const auto& i : m ) {
|
||||
auto k = to_val(i.first, tt->GetIndexTypes()[0]);
|
||||
auto v = to_val(i.second, tt->Yield());
|
||||
zv->Assign(std::move(k), std::move(v));
|
||||
}
|
||||
|
||||
return zv;
|
||||
} // namespace spicy::rt
|
||||
|
||||
/**
|
||||
* Converts a Spicy-side set to a Zeek value. The result is returned with
|
||||
* ref count +1.
|
||||
*/
|
||||
template<typename T>
|
||||
inline ValPtr to_val(const hilti::rt::Set<T>& s, TypePtr target) {
|
||||
if ( target->Tag() != TYPE_TABLE )
|
||||
throw TypeMismatch("set", target);
|
||||
|
||||
auto tt = cast_intrusive<TableType>(target);
|
||||
if ( ! tt->IsSet() )
|
||||
throw TypeMismatch("set", target);
|
||||
|
||||
auto zv = make_intrusive<TableVal>(tt);
|
||||
|
||||
for ( const auto& i : s ) {
|
||||
if constexpr ( hilti::rt::is_tuple<T>::value )
|
||||
throw TypeMismatch("internal error: sets with tuples not yet supported in to_val()");
|
||||
else {
|
||||
if ( tt->GetIndexTypes().size() != 1 )
|
||||
throw TypeMismatch("set with non-tuple elements", target);
|
||||
|
||||
auto idx = to_val(i, tt->GetIndexTypes()[0]);
|
||||
zv->Assign(std::move(idx), nullptr);
|
||||
}
|
||||
}
|
||||
|
||||
return zv;
|
||||
}
|
||||
|
||||
namespace {
|
||||
template<typename, template<typename...> typename>
|
||||
struct is_instance_impl : std::false_type {};
|
||||
|
||||
template<template<typename...> typename U, typename... Ts>
|
||||
struct is_instance_impl<U<Ts...>, U> : std::true_type {};
|
||||
} // namespace
|
||||
|
||||
template<typename T, template<typename...> typename U>
|
||||
using is_instance = is_instance_impl<std::remove_cv_t<T>, U>;
|
||||
|
||||
template<typename T>
|
||||
inline void set_record_field(RecordVal* rval, const IntrusivePtr<RecordType>& rtype, int idx, const T& x) {
|
||||
using NoConversionNeeded = std::integral_constant<
|
||||
bool, std::is_same_v<T, int8_t> || std::is_same_v<T, int16_t> || std::is_same_v<T, int32_t> ||
|
||||
std::is_same_v<T, int64_t> || std::is_same_v<T, uint8_t> || std::is_same_v<T, uint16_t> ||
|
||||
std::is_same_v<T, uint32_t> || std::is_same_v<T, uint64_t> || std::is_same_v<T, double> ||
|
||||
std::is_same_v<T, std::string> || std::is_same_v<T, bool>>;
|
||||
|
||||
using IsSignedInteger = std::integral_constant<bool, std::is_same_v<T, hilti::rt::integer::safe<int8_t>> ||
|
||||
std::is_same_v<T, hilti::rt::integer::safe<int16_t>> ||
|
||||
std::is_same_v<T, hilti::rt::integer::safe<int32_t>> ||
|
||||
std::is_same_v<T, hilti::rt::integer::safe<int64_t>>>;
|
||||
|
||||
using IsUnsignedInteger = std::integral_constant<bool, std::is_same_v<T, hilti::rt::integer::safe<uint8_t>> ||
|
||||
std::is_same_v<T, hilti::rt::integer::safe<uint16_t>> ||
|
||||
std::is_same_v<T, hilti::rt::integer::safe<uint32_t>> ||
|
||||
std::is_same_v<T, hilti::rt::integer::safe<uint64_t>>>;
|
||||
|
||||
if constexpr ( NoConversionNeeded::value )
|
||||
rval->Assign(idx, x);
|
||||
else if constexpr ( IsSignedInteger::value )
|
||||
#if ZEEK_VERSION_NUMBER >= 50200
|
||||
rval->Assign(idx, static_cast<int64_t>(x.Ref()));
|
||||
#else
|
||||
rval->Assign(idx, static_cast<int>(x.Ref()));
|
||||
#endif
|
||||
else if constexpr ( IsUnsignedInteger::value )
|
||||
rval->Assign(idx, static_cast<uint64_t>(x.Ref()));
|
||||
else if constexpr ( std::is_same_v<T, hilti::rt::Bytes> )
|
||||
rval->Assign(idx, x.str());
|
||||
else if constexpr ( std::is_same_v<T, hilti::rt::Bool> )
|
||||
rval->Assign(idx, static_cast<bool>(x));
|
||||
else if constexpr ( std::is_same_v<T, std::string> )
|
||||
rval->Assign(idx, x);
|
||||
else if constexpr ( std::is_same_v<T, hilti::rt::Time> )
|
||||
rval->AssignTime(idx, x.seconds());
|
||||
else if constexpr ( std::is_same_v<T, hilti::rt::Interval> )
|
||||
rval->AssignInterval(idx, x.seconds());
|
||||
else if constexpr ( std::is_same_v<T, hilti::rt::Null> ) {
|
||||
// "Null" turns into an unset optional record field.
|
||||
}
|
||||
else if constexpr ( is_instance<T, std::optional>::value ) {
|
||||
if ( x.has_value() )
|
||||
set_record_field(rval, rtype, idx, *x);
|
||||
}
|
||||
else if constexpr ( is_instance<T, hilti::rt::DeferredExpression>::value ) {
|
||||
try {
|
||||
set_record_field(rval, rtype, idx, x());
|
||||
} catch ( const hilti::rt::AttributeNotSet& ) {
|
||||
// leave unset
|
||||
}
|
||||
}
|
||||
else {
|
||||
ValPtr v = nullptr;
|
||||
|
||||
// This may return a nullptr in cases where the field is to be left unset.
|
||||
v = to_val(x, rtype->GetFieldType(idx));
|
||||
|
||||
if ( v )
|
||||
rval->Assign(idx, v);
|
||||
else {
|
||||
// Field must be &optional or &default.
|
||||
if ( auto attrs = rtype->FieldDecl(idx)->attrs;
|
||||
! attrs || ! (attrs->Find(detail::ATTR_DEFAULT) || attrs->Find(detail::ATTR_OPTIONAL)) )
|
||||
throw TypeMismatch(hilti::rt::fmt("missing initialization for field '%s'", rtype->FieldName(idx)));
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Converts a Spicy-side tuple to a Zeek record value. The result is returned
|
||||
* with ref count +1.
|
||||
*/
|
||||
template<typename T, typename std::enable_if_t<hilti::rt::is_tuple<T>::value>*>
|
||||
inline ValPtr to_val(const T& t, TypePtr target) {
|
||||
if ( target->Tag() != TYPE_RECORD )
|
||||
throw TypeMismatch("tuple", target);
|
||||
|
||||
auto rtype = cast_intrusive<RecordType>(target);
|
||||
|
||||
if ( std::tuple_size<T>::value != rtype->NumFields() )
|
||||
throw TypeMismatch("tuple", target);
|
||||
|
||||
auto rval = make_intrusive<RecordVal>(rtype);
|
||||
int idx = 0;
|
||||
hilti::rt::tuple_for_each(t, [&](const auto& x) { set_record_field(rval.get(), rtype, idx++, x); });
|
||||
|
||||
return rval;
|
||||
}
|
||||
|
||||
/**
|
||||
* Converts Spicy-side struct to a Zeek record value. The result is returned
|
||||
* with a ref count +1.
|
||||
*/
|
||||
template<typename T, typename std::enable_if_t<std::is_base_of<::hilti::rt::trait::isStruct, T>::value>*>
|
||||
inline ValPtr to_val(const T& t, TypePtr target) {
|
||||
if ( target->Tag() != TYPE_RECORD )
|
||||
throw TypeMismatch("struct", target);
|
||||
|
||||
auto rtype = cast_intrusive<RecordType>(target);
|
||||
|
||||
auto rval = make_intrusive<RecordVal>(rtype);
|
||||
int idx = 0;
|
||||
|
||||
auto num_fields = rtype->NumFields();
|
||||
|
||||
t.__visit([&](const auto& name, const auto& val) {
|
||||
if ( idx >= num_fields )
|
||||
throw TypeMismatch(hilti::rt::fmt("no matching record field for field '%s'", name));
|
||||
|
||||
auto field = rtype->GetFieldType(idx);
|
||||
std::string field_name = rtype->FieldName(idx);
|
||||
|
||||
if ( field_name != name )
|
||||
throw TypeMismatch(hilti::rt::fmt("mismatch in field name: expected '%s', found '%s'", name, field_name));
|
||||
|
||||
set_record_field(rval.get(), rtype, idx++, val);
|
||||
});
|
||||
|
||||
// We already check above that all Spicy-side fields are mapped so we
|
||||
// can only hit this if there are uninitialized Zeek-side fields left.
|
||||
if ( idx != num_fields )
|
||||
throw TypeMismatch(hilti::rt::fmt("missing initialization for field '%s'", rtype->FieldName(idx + 1)));
|
||||
|
||||
return rval;
|
||||
}
|
||||
|
||||
/**
|
||||
* Converts a Spicy-side enum to a Zeek record value. The result is returned
|
||||
* with ref count +1.
|
||||
*/
|
||||
template<typename T, typename std::enable_if_t<std::is_enum<typename T::Value>::value>*>
|
||||
inline ValPtr to_val(const T& t, TypePtr target) {
|
||||
#if SPICY_VERSION_NUMBER >= 10700
|
||||
auto proto = typename T::Value(t.value());
|
||||
#else
|
||||
auto proto = t;
|
||||
#endif
|
||||
|
||||
return to_val(proto, target);
|
||||
}
|
||||
|
||||
/**
|
||||
* Converts a C++ Spicy-side enum to a Zeek record value. The result is returned
|
||||
* with ref count +1. This specialization is provided for compatibility with <spicy-1.7.0.
|
||||
*
|
||||
* TODO(bbannier): remove this once we drop support for Spicy versions before 1.7.0.
|
||||
*/
|
||||
template<typename T, typename std::enable_if_t<std::is_enum<T>::value>*>
|
||||
inline ValPtr to_val(const T& t, TypePtr target) {
|
||||
if ( target->Tag() != TYPE_ENUM )
|
||||
throw TypeMismatch("enum", target);
|
||||
|
||||
// We'll usually be getting an int64_t for T, but allow other signed ints
|
||||
// as well.
|
||||
static_assert(std::is_signed<std::underlying_type_t<T>>{});
|
||||
auto it = static_cast<int64_t>(t);
|
||||
|
||||
// Zeek's enum can't be negative, so we swap in max_int for our Undef (-1).
|
||||
if ( it == std::numeric_limits<int64_t>::max() )
|
||||
// can't allow this ...
|
||||
throw InvalidValue("enum values with value max_int not supported by Zeek integration");
|
||||
|
||||
zeek_int_t bt = (it >= 0 ? it : std::numeric_limits<::zeek_int_t>::max());
|
||||
|
||||
return target->AsEnumType()->GetEnumVal(bt);
|
||||
}
|
||||
|
||||
} // namespace zeek::spicy::rt
|
62
src/spicy/spicy.bif
Normal file
62
src/spicy/spicy.bif
Normal file
|
@ -0,0 +1,62 @@
|
|||
# See the file "COPYING" in the main distribution directory for copyright.
|
||||
|
||||
module Spicy;
|
||||
|
||||
%%{
|
||||
#include "zeek/spicy/manager.h"
|
||||
%%}
|
||||
|
||||
# Constant for testing if Spicy is available.
|
||||
const available: bool;
|
||||
|
||||
# Show output of Spicy print statements.
|
||||
const enable_print: bool;
|
||||
|
||||
# Record and display profiling information.
|
||||
const enable_profiling: bool;
|
||||
|
||||
# abort() instead of throwing HILTI # exceptions.
|
||||
const abort_on_exceptions: bool;
|
||||
|
||||
# Include backtraces when reporting unhandled exceptions.
|
||||
const show_backtraces: bool;
|
||||
|
||||
# Maximum depth of recursive file analysis.
|
||||
const max_file_depth: count;
|
||||
|
||||
event max_file_depth_exceeded%(f: fa_file, args: Files::AnalyzerArgs, limit: count%);
|
||||
|
||||
function Spicy::__toggle_analyzer%(tag: any, enable: bool%) : bool
|
||||
%{
|
||||
if ( tag->GetType()->Tag() != TYPE_ENUM ) {
|
||||
zeek::reporter->Warning("Spicy::disable_analyzer() must receive an analyzer tag");
|
||||
return val_mgr->Bool(false);
|
||||
}
|
||||
|
||||
bool result = spicy_mgr->toggleAnalyzer(tag->AsEnumVal(), enable);
|
||||
if ( ! result )
|
||||
zeek::reporter->Warning("could not toggle Spicy analyzer");
|
||||
|
||||
return val_mgr->Bool(result);
|
||||
%}
|
||||
|
||||
type ResourceUsage: record;
|
||||
|
||||
function Spicy::__resource_usage%(%) : Spicy::ResourceUsage
|
||||
%{
|
||||
auto ru = hilti::rt::resource_usage();
|
||||
|
||||
auto r = zeek::make_intrusive<zeek::RecordVal>(BifType::Record::Spicy::ResourceUsage);
|
||||
int n = 0;
|
||||
r->Assign(n++, ru.user_time);
|
||||
r->Assign(n++, ru.system_time);
|
||||
r->Assign(n++, ru.memory_heap);
|
||||
r->Assign(n++, ru.num_fibers);
|
||||
r->Assign(n++, ru.max_fibers);
|
||||
#if SPICY_VERSION_NUMBER >= 10800
|
||||
r->Assign(n++, ru.max_fiber_stack_size);
|
||||
#endif
|
||||
r->Assign(n++, ru.cached_fibers);
|
||||
|
||||
return r;
|
||||
%}
|
10
src/spicy/spicyz/CMakeLists.txt
Normal file
10
src/spicy/spicyz/CMakeLists.txt
Normal file
|
@ -0,0 +1,10 @@
|
|||
# See the file "COPYING" in the main distribution directory for copyright.
|
||||
|
||||
configure_file(config.h.in config.h)
|
||||
|
||||
add_executable(spicyz driver.cc glue-compiler.cc main.cc)
|
||||
target_compile_options(spicyz PRIVATE "-Wall")
|
||||
target_include_directories(spicyz PRIVATE ${CMAKE_CURRENT_BINARY_DIR})
|
||||
target_link_libraries(spicyz PRIVATE hilti spicy)
|
||||
|
||||
install(TARGETS spicyz DESTINATION ${CMAKE_INSTALL_BINDIR})
|
67
src/spicy/spicyz/config.h.in
Normal file
67
src/spicy/spicyz/config.h.in
Normal file
|
@ -0,0 +1,67 @@
|
|||
// See the file "COPYING" in the main distribution directory for copyright.
|
||||
|
||||
#pragma once
|
||||
|
||||
#include "zeek/util-config.h"
|
||||
|
||||
#include <string>
|
||||
|
||||
#include <hilti/rt/filesystem.h>
|
||||
|
||||
namespace zeek::spicy::configuration {
|
||||
|
||||
using path = hilti::rt::filesystem::path;
|
||||
|
||||
namespace {
|
||||
|
||||
// This mimics zeek-config to get the Zeek include directories.
|
||||
static inline void add_path(std::string& old_path, const path& new_path) {
|
||||
if ( new_path.empty() )
|
||||
return;
|
||||
|
||||
if ( ! old_path.empty() )
|
||||
old_path += ":";
|
||||
|
||||
old_path += new_path.native();
|
||||
}
|
||||
} // namespace
|
||||
|
||||
inline const auto InstallBinDir() { return path("${CMAKE_INSTALL_PREFIX}") / "${CMAKE_INSTALL_BINDIR}"; }
|
||||
|
||||
inline const auto LibraryPath() {
|
||||
path base;
|
||||
|
||||
if ( auto custom_base = getenv("ZEEK_SPICY_LIBRARY_PATH"); custom_base && *custom_base )
|
||||
base = path(custom_base);
|
||||
else
|
||||
base = path("@ZEEK_SPICY_LIBRARY_PATH@");
|
||||
|
||||
return hilti::rt::filesystem::weakly_canonical(base);
|
||||
}
|
||||
|
||||
inline const auto ModulePath() { return path("@ZEEK_SPICY_MODULE_PATH@"); }
|
||||
inline const auto DataPath() { return path("@ZEEK_SPICY_DATA_PATH@"); }
|
||||
|
||||
inline const auto CxxZeekIncludesDirectories() {
|
||||
std::string includes;
|
||||
add_path(includes, path("${CMAKE_INSTALL_PREFIX}") / "${CMAKE_INSTALL_INCLUDEDIR}");
|
||||
|
||||
// When changing any of the following, also update "zeek-config.in".
|
||||
add_path(includes, "${ZEEK_CONFIG_PCAP_INCLUDE_DIR}");
|
||||
add_path(includes, "${ZEEK_CONFIG_ZLIB_INCLUDE_DIR}");
|
||||
add_path(includes, "${ZEEK_CONFIG_OPENSSL_INCLUDE_DIR}");
|
||||
add_path(includes, "${ZEEK_CONFIG_LibKrb5_INCLUDE_DIR}");
|
||||
add_path(includes, "${ZEEK_CONFIG_GooglePerftools_INCLUDE_DIR}");
|
||||
|
||||
return includes;
|
||||
}
|
||||
|
||||
// Version of Spicy that we are compiling against.
|
||||
#cmakedefine SPICY_VERSION_NUMBER ${SPICY_VERSION_NUMBER}
|
||||
#cmakedefine ZEEK_VERSION_NUMBER ${ZEEK_VERSION_NUMBER}
|
||||
|
||||
inline const auto SpicyVersion = "${SPICY_VERSION}";
|
||||
inline const auto ZeekVersion = "${VERSION}";
|
||||
inline const auto InstallPrefix = path("${CMAKE_INSTALL_PREFIX}");
|
||||
|
||||
} // namespace zeek::spicy::configuration
|
301
src/spicy/spicyz/driver.cc
Normal file
301
src/spicy/spicyz/driver.cc
Normal file
|
@ -0,0 +1,301 @@
|
|||
// See the file "COPYING" in the main distribution directory for copyright.
|
||||
|
||||
#include "driver.h"
|
||||
|
||||
#include <getopt.h>
|
||||
|
||||
#include <algorithm>
|
||||
#include <memory>
|
||||
#include <string>
|
||||
#include <type_traits>
|
||||
#include <utility>
|
||||
#include <vector>
|
||||
|
||||
#include <spicy/rt/libspicy.h>
|
||||
|
||||
#include <hilti/ast/declarations/type.h>
|
||||
#include <hilti/compiler/init.h>
|
||||
|
||||
#include <spicy/ast/detail/visitor.h>
|
||||
#include <spicy/ast/types/unit.h>
|
||||
#include <spicy/autogen/config.h>
|
||||
#include <spicy/compiler/init.h>
|
||||
|
||||
#include "config.h"
|
||||
#include "glue-compiler.h"
|
||||
|
||||
using namespace zeek::spicy;
|
||||
using Driver = ::zeek::spicy::Driver;
|
||||
|
||||
/**
|
||||
* Visitor to type information from a HILTI AST. This extracts user-visible
|
||||
* types only, we skip any internal ones.
|
||||
*/
|
||||
struct VisitorTypes : public hilti::visitor::PreOrder<void, VisitorTypes> {
|
||||
explicit VisitorTypes(Driver* driver, hilti::ID module, hilti::rt::filesystem::path path, bool is_resolved)
|
||||
: driver(driver), module(std::move(module)), path(std::move(path)), is_resolved(is_resolved) {}
|
||||
|
||||
void operator()(const hilti::declaration::Type& t) {
|
||||
assert(! t.type().typeID() || *t.type().typeID() == hilti::ID(module, t.id())); // ensure consistent IDs
|
||||
|
||||
if ( module == hilti::ID("hilti") || module == hilti::ID("spicy_rt") || module == hilti::ID("zeek_rt") )
|
||||
return;
|
||||
|
||||
types.emplace_back(TypeInfo{
|
||||
.id = hilti::ID(module, t.id()),
|
||||
.type = t.type()._clone().as<hilti::Type>(),
|
||||
.linkage = t.linkage(),
|
||||
.is_resolved = is_resolved,
|
||||
.module_id = module,
|
||||
.module_path = path,
|
||||
.location = t.meta().location(),
|
||||
});
|
||||
}
|
||||
|
||||
Driver* driver;
|
||||
hilti::ID module;
|
||||
hilti::rt::filesystem::path path;
|
||||
bool is_resolved;
|
||||
std::vector<TypeInfo> types;
|
||||
};
|
||||
|
||||
Driver::Driver(std::unique_ptr<GlueCompiler> glue, const char* argv0, hilti::rt::filesystem::path lib_path,
|
||||
int zeek_version)
|
||||
: ::spicy::Driver("<Spicy Plugin for Zeek>"), _glue(std::move(glue)) {
|
||||
_glue->Init(this, zeek_version);
|
||||
|
||||
::spicy::Configuration::extendHiltiConfiguration();
|
||||
auto options = hiltiOptions();
|
||||
|
||||
// Note that, different from Spicy's own SPICY_PATH, this extends the
|
||||
// search path, it doesn't replace it.
|
||||
if ( auto path = hilti::rt::getenv("ZEEK_SPICY_PATH") ) {
|
||||
for ( const auto& dir : hilti::rt::split(*path, ":") ) {
|
||||
if ( dir.size() )
|
||||
options.library_paths.emplace_back(dir);
|
||||
}
|
||||
}
|
||||
|
||||
try {
|
||||
lib_path = hilti::rt::filesystem::weakly_canonical(lib_path);
|
||||
|
||||
// We make our search paths relative to the plugin library, so that the
|
||||
// plugin installation can move around.
|
||||
options.library_paths.push_back(lib_path);
|
||||
} catch ( const hilti::rt::filesystem::filesystem_error& e ) {
|
||||
::hilti::logger().warning(
|
||||
hilti::util::fmt("invalid plugin base directory %s: %s", lib_path.native(), e.what()));
|
||||
}
|
||||
|
||||
for ( const auto& i : hilti::util::split(configuration::CxxZeekIncludesDirectories(), ":") ) {
|
||||
if ( i.size() )
|
||||
options.cxx_include_paths.emplace_back(i);
|
||||
}
|
||||
|
||||
#ifdef DEBUG
|
||||
SPICY_DEBUG("Search paths:");
|
||||
|
||||
auto hilti_options = hiltiOptions();
|
||||
for ( const auto& x : hilti_options.library_paths ) {
|
||||
SPICY_DEBUG(hilti::rt::fmt(" %s", x.native()));
|
||||
}
|
||||
#endif
|
||||
|
||||
setCompilerOptions(std::move(options));
|
||||
|
||||
auto& config = ::spicy::configuration();
|
||||
config.preprocessor_constants["HAVE_ZEEK"] = 1;
|
||||
config.preprocessor_constants["ZEEK_VERSION"] = zeek_version;
|
||||
|
||||
#if SPICY_VERSION_NUMBER >= 10500
|
||||
::hilti::init();
|
||||
::spicy::init();
|
||||
#endif
|
||||
}
|
||||
|
||||
Driver::~Driver() {}
|
||||
|
||||
hilti::Result<hilti::Nothing> Driver::loadFile(hilti::rt::filesystem::path file,
|
||||
const hilti::rt::filesystem::path& relative_to) {
|
||||
std::error_code ec;
|
||||
if ( ! relative_to.empty() && file.is_relative() ) {
|
||||
auto p = relative_to / file;
|
||||
auto exists = hilti::rt::filesystem::exists(p, ec);
|
||||
|
||||
if ( ec )
|
||||
return hilti::rt::result::Error(
|
||||
hilti::util::fmt("error computing path of %s relative to %s: %s", file, relative_to, ec.message()));
|
||||
|
||||
if ( exists )
|
||||
file = p;
|
||||
}
|
||||
|
||||
auto exists = hilti::rt::filesystem::exists(file, ec);
|
||||
|
||||
if ( ec )
|
||||
return hilti::rt::result::Error(
|
||||
hilti::util::fmt("cannot check whether file %s exists: %s", file, ec.message()));
|
||||
|
||||
if ( ! exists ) {
|
||||
if ( auto path = hilti::util::findInPaths(file, hiltiOptions().library_paths) )
|
||||
file = *path;
|
||||
else
|
||||
return hilti::result::Error(hilti::util::fmt("Spicy plugin cannot find file %s", file));
|
||||
}
|
||||
|
||||
auto rpath = hilti::util::normalizePath(file);
|
||||
auto ext = rpath.extension();
|
||||
|
||||
if ( ext == ".evt" ) {
|
||||
SPICY_DEBUG(hilti::util::fmt("Loading EVT file %s", rpath));
|
||||
if ( _glue->loadEvtFile(rpath) )
|
||||
return hilti::Nothing();
|
||||
else
|
||||
return hilti::result::Error(hilti::util::fmt("error loading EVT file %s", rpath));
|
||||
}
|
||||
|
||||
if ( ext == ".spicy" ) {
|
||||
SPICY_DEBUG(hilti::util::fmt("Loading Spicy file %s", rpath));
|
||||
if ( auto rc = addInput(rpath); ! rc )
|
||||
return rc.error();
|
||||
|
||||
return hilti::Nothing();
|
||||
}
|
||||
|
||||
if ( ext == ".hlt" ) {
|
||||
SPICY_DEBUG(hilti::util::fmt("Loading HILTI file %s", rpath));
|
||||
if ( auto rc = addInput(rpath) )
|
||||
return hilti::Nothing();
|
||||
else
|
||||
return rc.error();
|
||||
}
|
||||
|
||||
if ( ext == ".hlto" ) {
|
||||
SPICY_DEBUG(hilti::util::fmt("Loading precompiled HILTI code %s", rpath));
|
||||
if ( auto rc = addInput(rpath) )
|
||||
return hilti::Nothing();
|
||||
else
|
||||
return rc.error();
|
||||
}
|
||||
|
||||
if ( ext == ".cc" || ext == ".cxx" ) {
|
||||
SPICY_DEBUG(hilti::util::fmt("Loading C++ code %s", rpath));
|
||||
if ( auto rc = addInput(rpath) )
|
||||
return hilti::Nothing();
|
||||
else
|
||||
return rc.error();
|
||||
}
|
||||
|
||||
return hilti::result::Error(hilti::util::fmt("unknown file type passed to Spicy loader: %s", rpath));
|
||||
}
|
||||
|
||||
hilti::Result<hilti::Nothing> Driver::compile() {
|
||||
if ( ! hasInputs() )
|
||||
return hilti::Nothing();
|
||||
|
||||
SPICY_DEBUG("Running Spicy driver");
|
||||
|
||||
if ( auto x = ::spicy::Driver::compile(); ! x )
|
||||
return x.error();
|
||||
|
||||
SPICY_DEBUG("Done with Spicy driver");
|
||||
return hilti::Nothing();
|
||||
}
|
||||
|
||||
hilti::Result<TypeInfo> Driver::lookupType(const hilti::ID& id) {
|
||||
if ( auto x = _types.find(id); x != _types.end() )
|
||||
return x->second;
|
||||
else
|
||||
return hilti::result::Error(hilti::util::fmt("unknown type '%s'", id));
|
||||
}
|
||||
|
||||
std::vector<TypeInfo> Driver::types() const {
|
||||
std::vector<TypeInfo> result;
|
||||
result.reserve(_types.size());
|
||||
|
||||
for ( const auto& t : _types )
|
||||
result.push_back(t.second);
|
||||
|
||||
return result;
|
||||
}
|
||||
|
||||
std::vector<std::pair<TypeInfo, hilti::ID>> Driver::exportedTypes() const {
|
||||
std::vector<std::pair<TypeInfo, hilti::ID>> result;
|
||||
|
||||
for ( const auto& [spicy_id, zeek_id, _] : _glue->exportedIDs() ) {
|
||||
if ( auto t = _types.find(spicy_id); t != _types.end() )
|
||||
result.emplace_back(t->second, zeek_id);
|
||||
else {
|
||||
hilti::logger().error(hilti::rt::fmt("unknown type '%s' exported", spicy_id));
|
||||
continue;
|
||||
}
|
||||
}
|
||||
|
||||
// Automatically export public enums for backwards compatibility.
|
||||
for ( const auto& t : _public_enums )
|
||||
result.emplace_back(t, t.id);
|
||||
|
||||
return result;
|
||||
}
|
||||
|
||||
void Driver::hookNewASTPreCompilation(std::shared_ptr<hilti::Unit> unit) {
|
||||
if ( unit->extension() != ".spicy" )
|
||||
return;
|
||||
|
||||
if ( unit->path().empty() )
|
||||
// Ignore modules constructed in memory.
|
||||
return;
|
||||
|
||||
auto v = VisitorTypes(this, unit->id(), unit->path(), false);
|
||||
for ( auto i : v.walk(unit->module()) )
|
||||
v.dispatch(i);
|
||||
|
||||
for ( const auto& ti : v.types ) {
|
||||
SPICY_DEBUG(hilti::util::fmt(" Got type '%s' (pre-compile)", ti.id));
|
||||
_types[ti.id] = ti;
|
||||
|
||||
if ( auto et = ti.type.tryAs<hilti::type::Enum>(); et && ti.linkage == hilti::declaration::Linkage::Public ) {
|
||||
SPICY_DEBUG(" Automatically exporting public enum for backwards compatibility");
|
||||
_public_enums.push_back(ti);
|
||||
}
|
||||
|
||||
hookNewType(ti);
|
||||
}
|
||||
}
|
||||
|
||||
void Driver::hookNewASTPostCompilation(std::shared_ptr<hilti::Unit> unit) {
|
||||
if ( unit->extension() != ".spicy" )
|
||||
return;
|
||||
|
||||
if ( unit->path().empty() )
|
||||
// Ignore modules constructed in memory.
|
||||
return;
|
||||
|
||||
auto v = VisitorTypes(this, unit->id(), unit->path(), true);
|
||||
for ( auto i : v.walk(unit->module()) )
|
||||
v.dispatch(i);
|
||||
|
||||
for ( auto&& t : v.types ) {
|
||||
SPICY_DEBUG(hilti::util::fmt(" Got type '%s' (post-compile)", t.id));
|
||||
_types[t.id] = t;
|
||||
hookNewType(t);
|
||||
}
|
||||
|
||||
_glue->addSpicyModule(unit->id(), unit->path());
|
||||
}
|
||||
|
||||
hilti::Result<hilti::Nothing> Driver::hookCompilationFinished(const hilti::Plugin& plugin) {
|
||||
if ( ! _need_glue )
|
||||
return hilti::Nothing();
|
||||
|
||||
_need_glue = false;
|
||||
|
||||
if ( _glue->compile() )
|
||||
return hilti::Nothing();
|
||||
else
|
||||
return hilti::result::Error("glue compilation failed");
|
||||
}
|
||||
|
||||
void Driver::hookInitRuntime() { ::spicy::rt::init(); }
|
||||
|
||||
void Driver::hookFinishRuntime() { ::spicy::rt::done(); }
|
199
src/spicy/spicyz/driver.h
Normal file
199
src/spicy/spicyz/driver.h
Normal file
|
@ -0,0 +1,199 @@
|
|||
// See the file "COPYING" in the main distribution directory for copyright.
|
||||
|
||||
#pragma once
|
||||
|
||||
#include <memory>
|
||||
#include <string>
|
||||
#include <unordered_map>
|
||||
#include <utility>
|
||||
#include <vector>
|
||||
|
||||
#include <hilti/rt/filesystem.h>
|
||||
|
||||
#include <spicy/rt/driver.h>
|
||||
|
||||
#include <hilti/ast/declaration.h>
|
||||
#include <hilti/ast/id.h>
|
||||
#include <hilti/ast/type.h>
|
||||
#include <hilti/base/logger.h>
|
||||
#include <hilti/compiler/driver.h>
|
||||
|
||||
#include <spicy/compiler/driver.h>
|
||||
|
||||
// Debug stream for compiler messages.
|
||||
static const ::hilti::logging::DebugStream ZeekPlugin("zeek");
|
||||
|
||||
// Macro helper to report debug messages.
|
||||
#define SPICY_DEBUG(msg) HILTI_DEBUG(ZeekPlugin, std::string(msg));
|
||||
|
||||
namespace zeek::spicy {
|
||||
|
||||
class GlueCompiler;
|
||||
|
||||
struct TypeInfo {
|
||||
hilti::ID id; /**< fully-qualified name of the type */
|
||||
hilti::Type type; /**< the type itself */
|
||||
hilti::declaration::Linkage linkage; /**< linkage of of the type's declaration */
|
||||
bool is_resolved = false; /**< true if we are far enough in processing that the type has been fully resolved */
|
||||
hilti::ID module_id; /**< name of module type is defined in */
|
||||
hilti::rt::filesystem::path module_path; /**< path of module that type is defined in */
|
||||
hilti::Location location; /**< location of type's declaration */
|
||||
};
|
||||
|
||||
/** Spicy compilation driver. */
|
||||
class Driver : public ::spicy::Driver {
|
||||
public:
|
||||
/**
|
||||
* Constructor.
|
||||
*
|
||||
* @param argv0 path to current executable, or empty to determine automatically
|
||||
* @param lib_path Path to library files the Spicy support needs
|
||||
* @param zeek_version Version number of Zeek we're working with
|
||||
*/
|
||||
Driver(std::unique_ptr<GlueCompiler> glue, const char* argv0, hilti::rt::filesystem::path lib_path,
|
||||
int zeek_version);
|
||||
|
||||
/** Destructor. */
|
||||
~Driver();
|
||||
|
||||
/**
|
||||
* Schedules an *.spicy, *.evt, or *.hlt file for loading. Note that it
|
||||
* won't necessarily load them all immediately, but may queue some for
|
||||
* later processing.
|
||||
*
|
||||
* @param file file to load, which will be searched across all current search paths
|
||||
* @param relative_to if given, relative paths will be interpreted as relative to this directory
|
||||
*/
|
||||
hilti::Result<hilti::Nothing> loadFile(hilti::rt::filesystem::path file,
|
||||
const hilti::rt::filesystem::path& relative_to = {});
|
||||
|
||||
/**
|
||||
* After user scripts have been read, compiles and links all resulting
|
||||
* Spicy code. Note that compiler and driver options must have been set
|
||||
* before calling this.
|
||||
*
|
||||
* Must be called before any packet processing starts.
|
||||
*
|
||||
* @return False if an error occurred. It will have been reported already.
|
||||
*/
|
||||
hilti::Result<hilti::Nothing> compile();
|
||||
|
||||
/**
|
||||
* Returns meta information for a type. The Spicy module defining the type
|
||||
* must have been compiled already for it to be found.
|
||||
*
|
||||
* @param id fully qualified name of type to look up
|
||||
* @return meta data, or an error if the type is not (yet) known
|
||||
*/
|
||||
hilti::Result<TypeInfo> lookupType(const hilti::ID& id);
|
||||
|
||||
/**
|
||||
* Returns meta information for a type, enforcing it to be a of a certain
|
||||
* kind. The Spicy module defining the type must have been compiled already
|
||||
* for it to be found.
|
||||
*
|
||||
* @tparam T type to enforce; method will return an error if type is not of this class
|
||||
* @param id fully qualified name of type to look up
|
||||
* @return meta data, or an error if the type is not (yet) known
|
||||
*/
|
||||
template<typename T>
|
||||
hilti::Result<TypeInfo> lookupType(const hilti::ID& id) {
|
||||
auto ti = lookupType(id);
|
||||
if ( ! ti )
|
||||
return ti.error();
|
||||
|
||||
if ( ! ti->type.isA<T>() )
|
||||
return hilti::result::Error(hilti::util::fmt("'%s' is not of expected type", id));
|
||||
|
||||
return ti;
|
||||
}
|
||||
|
||||
/**
|
||||
* Returns all types seen so far during processing of Spicy files.
|
||||
* Depending on where we are at with processing, these may or may not be
|
||||
* resolved yet (as indicated by their `is_resolved` field).
|
||||
|
||||
* @return list of types
|
||||
*/
|
||||
std::vector<TypeInfo> types() const;
|
||||
|
||||
/**
|
||||
* Returns all *exported* types seen so far during processing of Spicy
|
||||
* files, including their desired Zeek-side names. Depending on where we
|
||||
* are at with processing, these may or may not be resolved yet (as
|
||||
* indicated by their `is_resolved` field).
|
||||
*
|
||||
* @return list of pairs of type and Zeek-side name
|
||||
*/
|
||||
std::vector<std::pair<TypeInfo, hilti::ID>> exportedTypes() const;
|
||||
|
||||
/** Returns true if we're running out of the plugin's build directory. */
|
||||
bool usingBuildDirectory() const { return _using_build_directory; }
|
||||
|
||||
/** Returns the glue compiler in use by the driver. */
|
||||
const auto* glueCompiler() const { return _glue.get(); }
|
||||
|
||||
/**
|
||||
* Parses some options command-line style *before* Zeek-side scripts have
|
||||
* been processed. Most of the option processing happens in
|
||||
* `parseOptionsPostScript()` instead, except for things that must be in
|
||||
* place already before script processing.
|
||||
*
|
||||
* @param options space-separated string of command line argument to parse
|
||||
* @return success if all argument could be parsed, or a suitable error message
|
||||
*/
|
||||
static hilti::Result<hilti::Nothing> parseOptionsPreScript(const std::string& options);
|
||||
|
||||
/**
|
||||
* Parses options command-line style after Zeek-side scripts have been
|
||||
* fully procssed. Most of the option processing happens here (vs. in
|
||||
* `parseOptionsPreScript()`) except for things that must be in place
|
||||
* already before script processing.
|
||||
*
|
||||
* @param options space-separated string of command line argument to parse
|
||||
* @param driver_options instance of options to update per parsed arguments
|
||||
* @param compiler_options instance of options to update per parsed arguments
|
||||
* @return success if all argument could be parsed, or a suitable error message
|
||||
*/
|
||||
static hilti::Result<hilti::Nothing> parseOptionsPostScript(const std::string& options,
|
||||
hilti::driver::Options* driver_options,
|
||||
hilti::Options* compiler_options);
|
||||
|
||||
/** Prints a usage message for options supported by `parseOptions{Pre,Post}Script()`. */
|
||||
static void usage(std::ostream& out);
|
||||
|
||||
protected:
|
||||
/**
|
||||
* Hook executed for all type declarations encountered in a Spicy module.
|
||||
* Derived classes may override this to add custom processing. This hooks
|
||||
* executes twices for each declaration: once before we compile the AST
|
||||
* (meaning types have not been resolved yet), and once after. The type
|
||||
* info's `is_resolved` field indicates which of the two we're in.
|
||||
*
|
||||
* @param t type's meta information
|
||||
*/
|
||||
virtual void hookNewType(const TypeInfo& ti) {}
|
||||
|
||||
/** Overridden from HILTI driver. */
|
||||
void hookNewASTPreCompilation(std::shared_ptr<hilti::Unit> unit) override;
|
||||
|
||||
/** Overridden from HILTI driver. */
|
||||
void hookNewASTPostCompilation(std::shared_ptr<hilti::Unit> unit) override;
|
||||
|
||||
/** Overridden from HILTI driver. */
|
||||
hilti::Result<hilti::Nothing> hookCompilationFinished(const hilti::Plugin& plugin) override;
|
||||
|
||||
/** Overridden from HILTI driver. */
|
||||
void hookInitRuntime() override;
|
||||
|
||||
/** Overridden from HILTI driver. */
|
||||
void hookFinishRuntime() override;
|
||||
|
||||
std::unique_ptr<GlueCompiler> _glue; // glue compiler in use
|
||||
std::unordered_map<hilti::ID, TypeInfo> _types; // map of Spicy type declarations encountered so far
|
||||
std::vector<TypeInfo> _public_enums; // tracks Spicy enum types declared public, for automatic export
|
||||
bool _using_build_directory = false; // true if we're running out of the plugin's build directory
|
||||
bool _need_glue = true; // true if glue code has not yet been generated
|
||||
};
|
||||
|
||||
} // namespace zeek::spicy
|
1352
src/spicy/spicyz/glue-compiler.cc
Normal file
1352
src/spicy/spicyz/glue-compiler.cc
Normal file
File diff suppressed because it is too large
Load diff
242
src/spicy/spicyz/glue-compiler.h
Normal file
242
src/spicy/spicyz/glue-compiler.h
Normal file
|
@ -0,0 +1,242 @@
|
|||
// See the file "COPYING" in the main distribution directory for copyright.
|
||||
|
||||
#pragma once
|
||||
|
||||
#include <map>
|
||||
#include <memory>
|
||||
#include <set>
|
||||
#include <string>
|
||||
#include <tuple>
|
||||
#include <utility>
|
||||
#include <vector>
|
||||
|
||||
#include <hilti/rt/filesystem.h>
|
||||
#include <hilti/rt/types/port.h>
|
||||
#include <hilti/rt/util.h>
|
||||
|
||||
#include <spicy/rt/mime.h>
|
||||
|
||||
#include <hilti/ast/declarations/function.h>
|
||||
#include <hilti/ast/expression.h>
|
||||
#include <hilti/ast/module.h>
|
||||
#include <hilti/ast/type.h>
|
||||
#include <hilti/compiler/context.h>
|
||||
#include <hilti/compiler/driver.h>
|
||||
|
||||
#include <spicy/ast/declarations/unit-hook.h>
|
||||
#include <spicy/ast/types/unit.h>
|
||||
|
||||
#include "driver.h"
|
||||
|
||||
namespace spicy::rt {
|
||||
struct Parser;
|
||||
}
|
||||
|
||||
namespace zeek::spicy {
|
||||
|
||||
namespace glue {
|
||||
|
||||
/** Representation of a Spicy protocol analyzer, parsed from an EVT file. */
|
||||
struct ProtocolAnalyzer {
|
||||
// Information parsed directly from the *.evt file.
|
||||
hilti::Location location; /**< Location where the analyzer was defined. */
|
||||
hilti::ID name; /**< Name of the analyzer. */
|
||||
hilti::rt::Protocol protocol = hilti::rt::Protocol::Undef; /**< The transport layer the analyzer uses. */
|
||||
std::vector<hilti::rt::Port> ports; /**< The ports associated with the analyzer. */
|
||||
hilti::ID unit_name_orig; /**< The fully-qualified name of the unit type to parse the originator
|
||||
side. */
|
||||
hilti::ID unit_name_resp; /**< The fully-qualified name of the unit type to parse the originator
|
||||
side. */
|
||||
std::string replaces; /**< Name of another analyzer this one replaces. */
|
||||
|
||||
// Computed information.
|
||||
std::optional<TypeInfo> unit_orig; /**< The type of the unit to parse the originator side. */
|
||||
std::optional<TypeInfo> unit_resp; /**< The type of the unit to parse the originator side. */
|
||||
};
|
||||
|
||||
/** Representation of a Spicy file analyzer, parsed from an EVT file. */
|
||||
struct FileAnalyzer {
|
||||
// Information parsed directly from the *.evt file.
|
||||
hilti::Location location; /**< Location where the analyzer was defined. */
|
||||
hilti::ID name; /**< Name of the analyzer. */
|
||||
std::vector<std::string> mime_types; /**< The mime_types associated with the analyzer. */
|
||||
hilti::ID unit_name; /**< The fully-qualified name of the unit type to parse with. */
|
||||
std::string replaces; /**< Name of another analyzer this one replaces. */
|
||||
|
||||
// Computed information.
|
||||
std::optional<TypeInfo> unit; /**< The type of the unit to parse the originator side. */
|
||||
};
|
||||
|
||||
/** Representation of a Spicy packet analyzer, parsed from an EVT file. */
|
||||
struct PacketAnalyzer {
|
||||
// Information parsed directly from the *.evt file.
|
||||
hilti::Location location; /**< Location where the analyzer was defined. */
|
||||
hilti::ID name; /**< Name of the analyzer. */
|
||||
hilti::ID unit_name; /**< The fully-qualified name of the unit type to parse with. */
|
||||
std::string replaces; /**< Name of another analyzer this one replaces. */
|
||||
|
||||
// Computed information.
|
||||
std::optional<TypeInfo> unit; /**< The type of the unit to parse the originator side. */
|
||||
};
|
||||
|
||||
/**
|
||||
* Representation of an expression computing the value of a parameter passed
|
||||
* to Spicy-generated events.
|
||||
*/
|
||||
struct ExpressionAccessor {
|
||||
// Information parsed directly from the *.evt file.
|
||||
int nr; /**< Position of this expression in argument list. */
|
||||
std::string expression; /**< The original string representation of the expression. */
|
||||
hilti::Location location; /**< Location where the expression was defined. */
|
||||
};
|
||||
|
||||
/** Representation of a compiled Spicy module. */
|
||||
struct SpicyModule {
|
||||
// Provided.
|
||||
hilti::ID id; /**< Name of the module */
|
||||
hilti::rt::filesystem::path file; /**< The path the module was read from. */
|
||||
std::set<hilti::rt::filesystem::path> evts; /**< EVT files that refer to this module. */
|
||||
|
||||
// Generated code.
|
||||
std::optional<hilti::Module> spicy_module; /**< the ``BroHooks_*.spicy`` module. */
|
||||
};
|
||||
|
||||
/** Representation of an event parsed from an EVT file. */
|
||||
struct Event {
|
||||
// Information parsed directly from the *.evt file.
|
||||
hilti::rt::filesystem::path file; /**< The path of the *.evt file we parsed this from. */
|
||||
hilti::ID name; /**< The name of the event. */
|
||||
hilti::ID path; /**< The hook path as specified in the evt file. */
|
||||
std::vector<hilti::type::function::Parameter> parameters; /**< Event parameters specified in the evt file. */
|
||||
std::string condition; /**< Condition that must be true for the event to trigger. */
|
||||
std::vector<std::string> exprs; /**< The argument expressions. */
|
||||
int priority; /**< Event/hook priority. */
|
||||
hilti::Location location; /**< Location where event is defined. */
|
||||
|
||||
// Computed information.
|
||||
hilti::ID hook; /**< The name of the hook triggering the event. */
|
||||
hilti::ID unit; /**< The fully qualified name of the unit type. */
|
||||
std::optional<::spicy::type::Unit> unit_type; /**< The Spicy type of referenced unit. */
|
||||
hilti::ID unit_module_id; /**< The name of the module the referenced unit is defined in. */
|
||||
hilti::rt::filesystem::path unit_module_path; /**< The path of the module that the referenced unit is defined in. */
|
||||
std::shared_ptr<glue::SpicyModule>
|
||||
spicy_module; /**< State for the Spichy module the referenced unit is defined in. */
|
||||
|
||||
// TODO: The following aren't set yet.
|
||||
|
||||
// Code generation.
|
||||
std::optional<::spicy::declaration::UnitHook> spicy_hook; /**< The generated Spicy hook. */
|
||||
std::optional<hilti::declaration::Function> hilti_raise; /**< The generated HILTI raise() function. */
|
||||
std::vector<ExpressionAccessor> expression_accessors; /**< One HILTI function per expression to access the value. */
|
||||
};
|
||||
|
||||
} // namespace glue
|
||||
|
||||
/** Generates the glue code between Zeek and Spicy based on *.evt files. */
|
||||
class GlueCompiler {
|
||||
public:
|
||||
/** Constructor. */
|
||||
GlueCompiler() {}
|
||||
|
||||
/** Destructor. */
|
||||
virtual ~GlueCompiler();
|
||||
|
||||
/** Parses an `*.evt` file, without generating any code yet. */
|
||||
bool loadEvtFile(hilti::rt::filesystem::path& path);
|
||||
|
||||
/**
|
||||
* Registers a Spicy file to generate glue code for, without generating
|
||||
* any code yet.
|
||||
*
|
||||
* @param id ID of the module
|
||||
* @param file path the module is loaded from
|
||||
*/
|
||||
void addSpicyModule(const hilti::ID& id, const hilti::rt::filesystem::path& file);
|
||||
|
||||
/**
|
||||
* Generates all glue code based on previously registered `*.evt` and
|
||||
* Spicy files.
|
||||
*/
|
||||
bool compile();
|
||||
|
||||
/** Returns all IDs that have been exported so far. */
|
||||
const auto& exportedIDs() const { return _exports; }
|
||||
|
||||
/** Generates code to convert a HILTI type to a corresponding Zeek type at runtime. */
|
||||
hilti::Result<hilti::Expression> createZeekType(const hilti::Type& t, const hilti::ID& id) const;
|
||||
|
||||
using RecordField = std::tuple<std::string, hilti::Type, bool>; /**< (ID, type, optional) */
|
||||
|
||||
/**
|
||||
* Helper to retrieve a list of Zeek-side record fields that converting a
|
||||
* Spicy unit to a Zeek record will yield.
|
||||
*
|
||||
* @param unit the unit type to retrieve fields for
|
||||
* @return list of fields
|
||||
*/
|
||||
static std::vector<RecordField> recordFields(const ::spicy::type::Unit& unit);
|
||||
|
||||
protected:
|
||||
friend class Driver;
|
||||
|
||||
/** Called by driver to initialized a provided glue compiler. */
|
||||
void Init(Driver* driver, int zeek_version);
|
||||
|
||||
private:
|
||||
/**
|
||||
* Filters input EVT file by applying preprocessor directives.
|
||||
*/
|
||||
void preprocessEvtFile(hilti::rt::filesystem::path& path, std::istream& in, std::ostream& out);
|
||||
|
||||
/**
|
||||
* Extracts the next semicolon-terminated block from an input stream,
|
||||
* accounting for special EVT constructs like strings and comments.
|
||||
*
|
||||
* @param in stream to read from
|
||||
* @param lineno pointer to integer that will be increased with line breaks
|
||||
* @return the read block of data, with comments removed, and empty if end of
|
||||
* data has been reached; error will be set if parsing failed
|
||||
*/
|
||||
hilti::Result<std::string> getNextEvtBlock(std::istream& in, int* lineno) const;
|
||||
|
||||
// Parsers for parts from EVT files.
|
||||
glue::ProtocolAnalyzer parseProtocolAnalyzer(const std::string& chunk);
|
||||
glue::FileAnalyzer parseFileAnalyzer(const std::string& chunk);
|
||||
glue::PacketAnalyzer parsePacketAnalyzer(const std::string& chunk);
|
||||
glue::Event parseEvent(const std::string& chunk);
|
||||
|
||||
/** Computes the missing pieces for all `Event` instances. */
|
||||
bool PopulateEvents();
|
||||
|
||||
/**
|
||||
* Create the Spicy hook for an event that triggers a corresponding Zeek
|
||||
* event.
|
||||
*/
|
||||
bool CreateSpicyHook(glue::Event* ev);
|
||||
|
||||
Driver* _driver = nullptr; /**< driver provided to Init() */
|
||||
std::optional<int> _zeek_version; /**< Zeek version provided to Init() */
|
||||
|
||||
std::map<hilti::ID, std::shared_ptr<glue::SpicyModule>> _spicy_modules;
|
||||
|
||||
std::vector<std::pair<hilti::ID, std::optional<hilti::ID>>>
|
||||
_imports; /**< imports from EVT files, with ID and optional scope */
|
||||
std::vector<std::tuple<hilti::ID, hilti::ID, hilti::Location>> _exports; /**< exports from EVT files */
|
||||
std::vector<glue::Event> _events; /**< events parsed from EVT files */
|
||||
std::vector<glue::ProtocolAnalyzer> _protocol_analyzers; /**< protocol analyzers parsed from EVT files */
|
||||
std::vector<glue::FileAnalyzer> _file_analyzers; /**< file analyzers parsed from EVT files */
|
||||
std::vector<glue::PacketAnalyzer> _packet_analyzers; /**< file analyzers parsed from EVT files */
|
||||
std::vector<hilti::Location> _locations; /**< location stack during parsing EVT files */
|
||||
};
|
||||
} // namespace zeek::spicy
|
||||
|
||||
namespace std {
|
||||
template<>
|
||||
struct hash<zeek::spicy::glue::Event> {
|
||||
std::size_t operator()(const zeek::spicy::glue::Event& e) {
|
||||
// We only hash enough information here to unique identify the event.
|
||||
return hilti::rt::hashCombine(std::hash<std::string>()(e.file), std::hash<std::string>()(e.name),
|
||||
std::hash<std::string>()(e.path), std::hash<std::string>()(e.location));
|
||||
}
|
||||
};
|
||||
} // namespace std
|
282
src/spicy/spicyz/main.cc
Normal file
282
src/spicy/spicyz/main.cc
Normal file
|
@ -0,0 +1,282 @@
|
|||
// See the file "COPYING" in the main distribution directory for copyright.
|
||||
|
||||
#include <getopt.h>
|
||||
|
||||
#include <hilti/base/result.h>
|
||||
#include <hilti/base/util.h>
|
||||
|
||||
#include "config.h"
|
||||
#include "driver.h"
|
||||
#include "glue-compiler.h"
|
||||
|
||||
using namespace zeek::spicy;
|
||||
|
||||
constexpr int OPT_CXX_LINK = 1000;
|
||||
|
||||
static struct option long_driver_options[] = {{"abort-on-exceptions", required_argument, nullptr, 'A'},
|
||||
{"show-backtraces", required_argument, nullptr, 'B'},
|
||||
{"compiler-debug", required_argument, nullptr, 'D'},
|
||||
{"cxx-link", required_argument, nullptr, OPT_CXX_LINK},
|
||||
{"debug", no_argument, nullptr, 'd'},
|
||||
{"debug-addl", required_argument, nullptr, 'X'},
|
||||
{"disable-optimizations", no_argument, nullptr, 'g'},
|
||||
{"dump-code", no_argument, nullptr, 'C'},
|
||||
{"enable-profiling", no_argument, nullptr, 'Z'},
|
||||
{"help", no_argument, nullptr, 'h'},
|
||||
{"keep-tmps", no_argument, nullptr, 'T'},
|
||||
{"library-path", required_argument, nullptr, 'L'},
|
||||
{"output", required_argument, nullptr, 'o'},
|
||||
{"output-c++", required_argument, nullptr, 'c'},
|
||||
{"output-c++-files", no_argument, nullptr, 'x'},
|
||||
{"print-module-path", no_argument, nullptr, 'M'},
|
||||
{"print-plugin-path", no_argument, nullptr,
|
||||
'P'}, // for backwards compatiblity
|
||||
{"print-prefix-path", no_argument, nullptr, 'p'},
|
||||
{"print-zeek-config", no_argument, nullptr, 'z'},
|
||||
{"report-times", required_argument, nullptr, 'R'},
|
||||
{"print-scripts-path", no_argument, nullptr, 'S'},
|
||||
{"skip-validation", no_argument, nullptr, '!'},
|
||||
{"version", no_argument, nullptr, 'v'},
|
||||
{"version-number", no_argument, nullptr, 'V'},
|
||||
{nullptr, 0, nullptr, 0}};
|
||||
|
||||
static void usage() {
|
||||
std::cerr << "Usage: spicyz [options] <inputs>\n"
|
||||
"\n"
|
||||
" -c | --output-c++ <prefix> Output generated C++ code.\n"
|
||||
" -d | --debug Include debug instrumentation into generated code.\n"
|
||||
" -g | --disable-optimizations Disable HILTI-side optimizations of the generated "
|
||||
"code.\n"
|
||||
" -o | --output-to <path> Path for saving output.\n"
|
||||
" -v | --version Print version information.\n"
|
||||
" -x | --output-c++ <prefix> Output generated C++ code into set of files.\n"
|
||||
" -z | --print-zeek-config Print path to zeek-config.\n"
|
||||
" -A | --abort-on-exceptions When executing compiled code, abort() instead of "
|
||||
"throwing HILTI "
|
||||
"exceptions.\n"
|
||||
" -B | --show-backtraces Include backtraces when reporting unhandled "
|
||||
"exceptions.\n"
|
||||
" -C | --dump-code Dump all generated code to disk for debugging.\n"
|
||||
" -D | --compiler-debug <streams> Activate compile-time debugging output for given "
|
||||
"debug streams "
|
||||
"(comma-separated; 'help' for list).\n"
|
||||
" -L | --library-path <path> Add path to list of directories to search when "
|
||||
"importing modules.\n"
|
||||
" -M | --print-module-path Print the Zeek's search path for compiled Spicy modules.\n"
|
||||
" -p | --print-prefix-path Print installation prefix path.\n"
|
||||
" -R | --report-times Report a break-down of compiler's execution time.\n"
|
||||
" -T | --keep-tmps Do not delete any temporary files created.\n"
|
||||
" --skip-validation Don't validate ASTs (for debugging only).\n"
|
||||
" -X | --debug-addl <addl> Implies -d and adds selected additional "
|
||||
"instrumentation."
|
||||
"(comma-separated; see 'help' for list).\n"
|
||||
" --cxx-link <lib> Link specified static archive or shared library "
|
||||
"during JIT or to "
|
||||
" -Z | --enable-profiling Report profiling statistics after execution.\n"
|
||||
"\n"
|
||||
"Inputs can be *.spicy, *.evt, *.hlt, .cc/.cxx\n"
|
||||
"\n";
|
||||
}
|
||||
|
||||
using hilti::Nothing;
|
||||
|
||||
static hilti::Result<Nothing> parseOptions(int argc, char** argv, hilti::driver::Options* driver_options,
|
||||
hilti::Options* compiler_options) {
|
||||
while ( true ) {
|
||||
int c = getopt_long(argc, argv, "ABc:Cdgx:X:D:L:Mo:pPRSTvhzZ", long_driver_options, nullptr);
|
||||
|
||||
if ( c == -1 )
|
||||
break;
|
||||
|
||||
switch ( c ) {
|
||||
case 'A': driver_options->abort_on_exceptions = true; break;
|
||||
|
||||
case 'B': driver_options->show_backtraces = true; break;
|
||||
|
||||
case 'c':
|
||||
driver_options->output_cxx = true;
|
||||
driver_options->output_cxx_prefix = optarg;
|
||||
driver_options->execute_code = false;
|
||||
compiler_options->cxx_namespace_extern =
|
||||
hilti::util::fmt("hlt_%s", hilti::rt::filesystem::path(optarg).stem().string());
|
||||
compiler_options->cxx_namespace_intern =
|
||||
hilti::util::fmt("__hlt_%s", hilti::rt::filesystem::path(optarg).stem().string());
|
||||
break;
|
||||
|
||||
case 'C': {
|
||||
driver_options->dump_code = true;
|
||||
break;
|
||||
}
|
||||
|
||||
case 'd': {
|
||||
compiler_options->debug = true;
|
||||
break;
|
||||
}
|
||||
|
||||
case 'g': {
|
||||
driver_options->global_optimizations = false;
|
||||
break;
|
||||
}
|
||||
|
||||
case 'p': std::cout << configuration::InstallPrefix.native() << std::endl; return Nothing();
|
||||
|
||||
case 'P':
|
||||
// For backwards compatibility with older plugins, print
|
||||
// the path where the `cmake/` folder is located.
|
||||
std::cout << configuration::DataPath().native() << std::endl;
|
||||
return Nothing();
|
||||
|
||||
case 'x':
|
||||
driver_options->output_cxx = true;
|
||||
driver_options->output_cxx_prefix = optarg;
|
||||
driver_options->execute_code = false;
|
||||
driver_options->include_linker = true;
|
||||
compiler_options->cxx_namespace_extern =
|
||||
hilti::util::fmt("hlt_%s", hilti::rt::filesystem::path(optarg).stem().string());
|
||||
compiler_options->cxx_namespace_intern =
|
||||
hilti::util::fmt("__hlt_%s", hilti::rt::filesystem::path(optarg).stem().string());
|
||||
break;
|
||||
|
||||
case 'X': {
|
||||
auto arg = std::string(optarg);
|
||||
|
||||
if ( arg == "help" ) {
|
||||
std::cerr << "Additional debug instrumentation:\n";
|
||||
std::cerr << " flow: log function calls to debug stream \"hilti-flow\"\n";
|
||||
std::cerr << " location: track current source code location for error reporting\n";
|
||||
std::cerr << " trace: log statements to debug stream \"hilti-trace\"\n";
|
||||
std::cerr << "\n";
|
||||
exit(0);
|
||||
}
|
||||
|
||||
compiler_options->debug = true;
|
||||
|
||||
if ( auto r = compiler_options->parseDebugAddl(arg); ! r )
|
||||
return hilti::result::Error("nothing to do");
|
||||
|
||||
break;
|
||||
}
|
||||
|
||||
case 'D': {
|
||||
auto arg = std::string(optarg);
|
||||
|
||||
if ( arg == "help" ) {
|
||||
std::cerr << "Debug streams:\n";
|
||||
|
||||
for ( const auto& s : hilti::logging::DebugStream::all() )
|
||||
std::cerr << " " << s << "\n";
|
||||
|
||||
std::cerr << "\n";
|
||||
return Nothing();
|
||||
}
|
||||
|
||||
for ( const auto& s : hilti::util::split(arg, ",") ) {
|
||||
if ( ! driver_options->logger->debugEnable(s) )
|
||||
return hilti::result::Error(
|
||||
hilti::util::fmt("Unknown debug stream '%s', use 'help' for list", arg));
|
||||
}
|
||||
|
||||
break;
|
||||
}
|
||||
|
||||
case 'L': compiler_options->library_paths.emplace_back(std::string(optarg)); break;
|
||||
|
||||
case 'M': std::cout << configuration::ModulePath().native() << std::endl; return Nothing();
|
||||
|
||||
case 'o': driver_options->output_path = std::string(optarg); break;
|
||||
|
||||
case 'R': driver_options->report_times = true; break;
|
||||
|
||||
case 'S': std::cout << "" << std::endl; return Nothing(); // No longer needed, but left for compatibility.
|
||||
|
||||
case 'T':
|
||||
driver_options->keep_tmps = true;
|
||||
compiler_options->keep_tmps = true;
|
||||
break;
|
||||
|
||||
case 'v': std::cout << configuration::ZeekVersion << std::endl; return Nothing();
|
||||
|
||||
case 'V': std::cout << ZEEK_VERSION_NUMBER << std::endl; return Nothing();
|
||||
|
||||
case 'z': {
|
||||
if ( auto zcfg = getenv("ZEEK_CONFIG"); zcfg && *zcfg )
|
||||
std::cout << zcfg << std::endl;
|
||||
else
|
||||
std::cout << configuration::InstallBinDir().native() << std::endl;
|
||||
|
||||
return Nothing();
|
||||
}
|
||||
|
||||
case 'Z':
|
||||
#if SPICY_VERSION_NUMBER >= 10800
|
||||
driver_options->enable_profiling = true;
|
||||
compiler_options->enable_profiling = true;
|
||||
#else
|
||||
std::cerr << "Profiling is not supported with this version of Spicy, ignoring '-Z'\n";
|
||||
#endif
|
||||
break;
|
||||
|
||||
case OPT_CXX_LINK:
|
||||
#if SPICY_VERSION_NUMBER >= 10600
|
||||
compiler_options->cxx_link.emplace_back(optarg);
|
||||
#else
|
||||
return hilti::result::Error("option '--cxx-link' is only supported for Spicy 1.6 or newer");
|
||||
#endif
|
||||
break;
|
||||
|
||||
case 'h': usage(); return Nothing();
|
||||
|
||||
case '!': compiler_options->skip_validation = true; break;
|
||||
|
||||
default: usage(); return hilti::result::Error("could not parse options");
|
||||
}
|
||||
}
|
||||
|
||||
while ( optind < argc )
|
||||
driver_options->inputs.emplace_back(argv[optind++]);
|
||||
|
||||
if ( driver_options->inputs.empty() )
|
||||
return hilti::result::Error("no input file given");
|
||||
|
||||
if ( driver_options->output_path.empty() && ! driver_options->output_cxx )
|
||||
return hilti::result::Error("no output file for object code given, use -o <file>.hlto");
|
||||
|
||||
return Nothing();
|
||||
}
|
||||
|
||||
int main(int argc, char** argv) {
|
||||
Driver driver(std::make_unique<GlueCompiler>(), "", configuration::LibraryPath(), ZEEK_VERSION_NUMBER);
|
||||
|
||||
hilti::driver::Options driver_options;
|
||||
driver_options.execute_code = true;
|
||||
driver_options.include_linker = true;
|
||||
|
||||
auto compiler_options = driver.hiltiOptions();
|
||||
|
||||
if ( auto rc = parseOptions(argc, argv, &driver_options, &compiler_options); ! rc ) {
|
||||
hilti::logger().error(rc.error().description());
|
||||
return 1;
|
||||
}
|
||||
|
||||
driver.setDriverOptions(std::move(driver_options));
|
||||
driver.setCompilerOptions(std::move(compiler_options));
|
||||
driver.initialize();
|
||||
|
||||
for ( const auto& p : driver.driverOptions().inputs ) {
|
||||
if ( auto rc = driver.loadFile(p); ! rc ) {
|
||||
hilti::logger().error(rc.error().description());
|
||||
return 1;
|
||||
}
|
||||
}
|
||||
|
||||
if ( auto rc = driver.compile(); ! rc ) {
|
||||
hilti::logger().error(rc.error().description());
|
||||
|
||||
if ( rc.error().context().size() )
|
||||
hilti::logger().error(rc.error().context());
|
||||
|
||||
return 1;
|
||||
}
|
||||
|
||||
return 0;
|
||||
}
|
|
@ -1,3 +1,7 @@
|
|||
#define ZEEK_SCRIPT_INSTALL_PATH "@ZEEK_SCRIPT_INSTALL_PATH@"
|
||||
#define BRO_PLUGIN_INSTALL_PATH "@ZEEK_PLUGIN_DIR@"
|
||||
#define ZEEK_PLUGIN_INSTALL_PATH "@ZEEK_PLUGIN_DIR@"
|
||||
#define DEFAULT_ZEEKPATH "@DEFAULT_ZEEKPATH@"
|
||||
#define ZEEK_SPICY_MODULE_PATH "@ZEEK_SPICY_MODULE_PATH@"
|
||||
#define ZEEK_SPICY_LIBRARY_PATH "@ZEEK_SPICY_LIBRARY_PATH@"
|
||||
#define ZEEK_SPICY_DATA_PATH "@ZEEK_SPICY_DATA_PATH@"
|
||||
|
|
|
@ -65,6 +65,9 @@
|
|||
#include "zeek/plugin/Manager.h"
|
||||
#include "zeek/script_opt/ScriptOpt.h"
|
||||
#include "zeek/session/Manager.h"
|
||||
#ifdef HAVE_SPICY
|
||||
#include "zeek/spicy/manager.h"
|
||||
#endif
|
||||
#include "zeek/supervisor/Supervisor.h"
|
||||
#include "zeek/telemetry/Manager.h"
|
||||
#include "zeek/threading/Manager.h"
|
||||
|
@ -191,6 +194,9 @@ zeek::Broker::Manager* zeek::broker_mgr = nullptr;
|
|||
zeek::telemetry::Manager* zeek::telemetry_mgr = nullptr;
|
||||
zeek::Supervisor* zeek::supervisor_mgr = nullptr;
|
||||
zeek::detail::trigger::Manager* zeek::detail::trigger_mgr = nullptr;
|
||||
#ifdef HAVE_SPICY
|
||||
zeek::spicy::Manager* zeek::spicy_mgr = nullptr;
|
||||
#endif
|
||||
|
||||
std::vector<std::string> zeek::detail::zeek_script_prefixes;
|
||||
zeek::detail::Stmt* zeek::detail::stmts = nullptr;
|
||||
|
@ -437,6 +443,9 @@ static void terminate_zeek()
|
|||
delete session_mgr;
|
||||
delete fragment_mgr;
|
||||
delete telemetry_mgr;
|
||||
#ifdef HAVE_SPICY
|
||||
delete spicy_mgr;
|
||||
#endif
|
||||
|
||||
// free the global scope
|
||||
pop_scope();
|
||||
|
@ -719,6 +728,9 @@ SetupResult setup(int argc, char** argv, Options* zopts)
|
|||
auto broker_real_time = ! options.pcap_file && ! options.deterministic_mode;
|
||||
broker_mgr = new Broker::Manager(broker_real_time);
|
||||
trigger_mgr = new trigger::Manager();
|
||||
#ifdef HAVE_SPICY
|
||||
spicy_mgr = new spicy::Manager(); // registers as plugin with the plugin manager
|
||||
#endif
|
||||
|
||||
plugin_mgr->InitPreScript();
|
||||
file_mgr->InitPreScript();
|
||||
|
|
|
@ -8,3 +8,14 @@ install(FILES btest/random.seed DESTINATION ${ZEEK_CONFIG_BTEST_TOOLS_DIR}/data)
|
|||
if (INSTALL_BTEST_PCAPS)
|
||||
install(DIRECTORY btest/Traces/ DESTINATION ${ZEEK_CONFIG_BTEST_TOOLS_DIR}/data/pcaps)
|
||||
endif ()
|
||||
|
||||
# The remainder is for backwards-compatability with existing Spicy zkg packages.
|
||||
install(
|
||||
CODE "execute_process( \
|
||||
COMMAND ${CMAKE_COMMAND} -E create_symlink \
|
||||
${ZEEK_CONFIG_BTEST_TOOLS_DIR}/data \
|
||||
${CMAKE_INSTALL_PREFIX}/share/zeek/tests \
|
||||
)")
|
||||
|
||||
install(DIRECTORY scripts/spicy/ DESTINATION ${ZEEK_CONFIG_BTEST_TOOLS_DIR}/data/Scripts
|
||||
USE_SOURCE_PERMISSIONS)
|
||||
|
|
|
@ -91,8 +91,8 @@ scripts/base/init-bare.zeek
|
|||
scripts/base/packet-protocols/gtpv1/__load__.zeek
|
||||
scripts/base/packet-protocols/gtpv1/main.zeek
|
||||
build/scripts/base/bif/plugins/Zeek_GTPv1.functions.bif.zeek
|
||||
scripts/base/frameworks/spicy/init-bare.zeek
|
||||
build/scripts/builtin-plugins/__preload__.zeek
|
||||
build/scripts/builtin-plugins/Zeek_Spicy/__preload__.zeek
|
||||
scripts/base/init-frameworks-and-bifs.zeek
|
||||
scripts/base/frameworks/logging/__load__.zeek
|
||||
scripts/base/frameworks/logging/main.zeek
|
||||
|
@ -148,6 +148,7 @@ scripts/base/init-frameworks-and-bifs.zeek
|
|||
build/scripts/base/bif/bloom-filter.bif.zeek
|
||||
build/scripts/base/bif/cardinality-counter.bif.zeek
|
||||
build/scripts/base/bif/top-k.bif.zeek
|
||||
build/scripts/base/bif/spicy.bif.zeek
|
||||
build/scripts/base/bif/plugins/__load__.zeek
|
||||
build/scripts/base/bif/plugins/Zeek_BitTorrent.events.bif.zeek
|
||||
build/scripts/base/bif/plugins/Zeek_ConnSize.events.bif.zeek
|
||||
|
@ -264,16 +265,12 @@ scripts/base/init-frameworks-and-bifs.zeek
|
|||
build/scripts/base/bif/plugins/Zeek_AsciiWriter.ascii.bif.zeek
|
||||
build/scripts/base/bif/plugins/Zeek_NoneWriter.none.bif.zeek
|
||||
build/scripts/base/bif/plugins/Zeek_SQLiteWriter.sqlite.bif.zeek
|
||||
build/scripts/base/bif/plugins/Zeek_Spicy.consts.bif.zeek
|
||||
build/scripts/base/bif/plugins/Zeek_Spicy.events.bif.zeek
|
||||
build/scripts/base/bif/plugins/Zeek_Spicy.functions.bif.zeek
|
||||
scripts/base/frameworks/spicy/init-framework.zeek
|
||||
scripts/base/misc/version.zeek
|
||||
scripts/base/frameworks/reporter/__load__.zeek
|
||||
scripts/base/frameworks/reporter/main.zeek
|
||||
scripts/base/utils/strings.zeek
|
||||
build/scripts/builtin-plugins/__load__.zeek
|
||||
build/scripts/builtin-plugins/Zeek_Spicy/__load__.zeek
|
||||
build/scripts/builtin-plugins/Zeek_Spicy/Zeek/Spicy/bare.zeek
|
||||
scripts/base/misc/version.zeek
|
||||
scripts/base/frameworks/reporter/__load__.zeek
|
||||
scripts/base/frameworks/reporter/main.zeek
|
||||
scripts/base/utils/strings.zeek
|
||||
scripts/policy/misc/loaded-scripts.zeek
|
||||
scripts/base/utils/paths.zeek
|
||||
#close XXXX-XX-XX-XX-XX-XX
|
||||
|
|
|
@ -91,8 +91,8 @@ scripts/base/init-bare.zeek
|
|||
scripts/base/packet-protocols/gtpv1/__load__.zeek
|
||||
scripts/base/packet-protocols/gtpv1/main.zeek
|
||||
build/scripts/base/bif/plugins/Zeek_GTPv1.functions.bif.zeek
|
||||
scripts/base/frameworks/spicy/init-bare.zeek
|
||||
build/scripts/builtin-plugins/__preload__.zeek
|
||||
build/scripts/builtin-plugins/Zeek_Spicy/__preload__.zeek
|
||||
scripts/base/init-frameworks-and-bifs.zeek
|
||||
scripts/base/frameworks/logging/__load__.zeek
|
||||
scripts/base/frameworks/logging/main.zeek
|
||||
|
@ -148,6 +148,7 @@ scripts/base/init-frameworks-and-bifs.zeek
|
|||
build/scripts/base/bif/bloom-filter.bif.zeek
|
||||
build/scripts/base/bif/cardinality-counter.bif.zeek
|
||||
build/scripts/base/bif/top-k.bif.zeek
|
||||
build/scripts/base/bif/spicy.bif.zeek
|
||||
build/scripts/base/bif/plugins/__load__.zeek
|
||||
build/scripts/base/bif/plugins/Zeek_BitTorrent.events.bif.zeek
|
||||
build/scripts/base/bif/plugins/Zeek_ConnSize.events.bif.zeek
|
||||
|
@ -264,9 +265,11 @@ scripts/base/init-frameworks-and-bifs.zeek
|
|||
build/scripts/base/bif/plugins/Zeek_AsciiWriter.ascii.bif.zeek
|
||||
build/scripts/base/bif/plugins/Zeek_NoneWriter.none.bif.zeek
|
||||
build/scripts/base/bif/plugins/Zeek_SQLiteWriter.sqlite.bif.zeek
|
||||
build/scripts/base/bif/plugins/Zeek_Spicy.consts.bif.zeek
|
||||
build/scripts/base/bif/plugins/Zeek_Spicy.events.bif.zeek
|
||||
build/scripts/base/bif/plugins/Zeek_Spicy.functions.bif.zeek
|
||||
scripts/base/frameworks/spicy/init-framework.zeek
|
||||
scripts/base/misc/version.zeek
|
||||
scripts/base/frameworks/reporter/__load__.zeek
|
||||
scripts/base/frameworks/reporter/main.zeek
|
||||
scripts/base/utils/strings.zeek
|
||||
scripts/base/init-default.zeek
|
||||
scripts/base/utils/active-http.zeek
|
||||
scripts/base/utils/exec.zeek
|
||||
|
@ -274,8 +277,6 @@ scripts/base/init-default.zeek
|
|||
scripts/base/utils/backtrace.zeek
|
||||
scripts/base/utils/conn-ids.zeek
|
||||
scripts/base/utils/dir.zeek
|
||||
scripts/base/frameworks/reporter/__load__.zeek
|
||||
scripts/base/frameworks/reporter/main.zeek
|
||||
scripts/base/utils/paths.zeek
|
||||
scripts/base/utils/directions-and-hosts.zeek
|
||||
scripts/base/utils/email.zeek
|
||||
|
@ -283,7 +284,6 @@ scripts/base/init-default.zeek
|
|||
scripts/base/utils/geoip-distance.zeek
|
||||
scripts/base/utils/numbers.zeek
|
||||
scripts/base/utils/queue.zeek
|
||||
scripts/base/utils/strings.zeek
|
||||
scripts/base/utils/thresholds.zeek
|
||||
scripts/base/utils/time.zeek
|
||||
scripts/base/utils/urls.zeek
|
||||
|
@ -347,7 +347,8 @@ scripts/base/init-default.zeek
|
|||
scripts/base/frameworks/netcontrol/non-cluster.zeek
|
||||
scripts/base/frameworks/telemetry/__load__.zeek
|
||||
scripts/base/frameworks/telemetry/main.zeek
|
||||
scripts/base/misc/version.zeek
|
||||
scripts/base/frameworks/spicy/__load__.zeek
|
||||
scripts/base/frameworks/spicy/main.zeek
|
||||
scripts/base/protocols/conn/__load__.zeek
|
||||
scripts/base/protocols/conn/main.zeek
|
||||
scripts/base/protocols/conn/contents.zeek
|
||||
|
@ -463,8 +464,5 @@ scripts/base/init-default.zeek
|
|||
scripts/base/misc/find-filtered-trace.zeek
|
||||
build/scripts/base/misc/installation.zeek
|
||||
build/scripts/builtin-plugins/__load__.zeek
|
||||
build/scripts/builtin-plugins/Zeek_Spicy/__load__.zeek
|
||||
build/scripts/builtin-plugins/Zeek_Spicy/Zeek/Spicy/bare.zeek
|
||||
build/scripts/builtin-plugins/Zeek_Spicy/Zeek/Spicy/default.zeek
|
||||
scripts/policy/misc/loaded-scripts.zeek
|
||||
#close XXXX-XX-XX-XX-XX-XX
|
||||
|
|
|
@ -10,6 +10,8 @@
|
|||
-./frameworks/netcontrol/cluster.zeek
|
||||
-./frameworks/openflow/cluster.zeek
|
||||
-./frameworks/packet-filter/cluster.zeek
|
||||
-./frameworks/spicy/misc/record-spicy-batch.zeek
|
||||
-./frameworks/spicy/misc/resource-usage.zeek
|
||||
-./frameworks/sumstats/cluster.zeek
|
||||
-./frameworks/telemetry/cluster.zeek
|
||||
-./init-supervisor.zeek
|
||||
|
|
|
@ -790,7 +790,6 @@
|
|||
0.000000 MetaHookPost CallFunction(Version::parse, ..., ...) -> <no result>
|
||||
0.000000 MetaHookPost CallFunction(__init_primary_bifs, <null>, ()) -> <no result>
|
||||
0.000000 MetaHookPost CallFunction(__init_secondary_bifs, <null>, ()) -> <no result>
|
||||
0.000000 MetaHookPost CallFunction(bare_mode, <null>, ()) -> <no result>
|
||||
0.000000 MetaHookPost CallFunction(cat, ..., ...) -> <no result>
|
||||
0.000000 MetaHookPost CallFunction(current_time, <frame>, ()) -> <no result>
|
||||
0.000000 MetaHookPost CallFunction(disable_event_group, <frame>, (Analyzer::Logging::include_confirmations)) -> <no result>
|
||||
|
@ -938,9 +937,6 @@
|
|||
0.000000 MetaHookPost LoadFile(0, ./Zeek_SSL.events.bif.zeek, <...>/Zeek_SSL.events.bif.zeek) -> -1
|
||||
0.000000 MetaHookPost LoadFile(0, ./Zeek_SSL.functions.bif.zeek, <...>/Zeek_SSL.functions.bif.zeek) -> -1
|
||||
0.000000 MetaHookPost LoadFile(0, ./Zeek_SSL.types.bif.zeek, <...>/Zeek_SSL.types.bif.zeek) -> -1
|
||||
0.000000 MetaHookPost LoadFile(0, ./Zeek_Spicy.consts.bif.zeek, <...>/Zeek_Spicy.consts.bif.zeek) -> -1
|
||||
0.000000 MetaHookPost LoadFile(0, ./Zeek_Spicy.events.bif.zeek, <...>/Zeek_Spicy.events.bif.zeek) -> -1
|
||||
0.000000 MetaHookPost LoadFile(0, ./Zeek_Spicy.functions.bif.zeek, <...>/Zeek_Spicy.functions.bif.zeek) -> -1
|
||||
0.000000 MetaHookPost LoadFile(0, ./Zeek_TCP.events.bif.zeek, <...>/Zeek_TCP.events.bif.zeek) -> -1
|
||||
0.000000 MetaHookPost LoadFile(0, ./Zeek_TCP.functions.bif.zeek, <...>/Zeek_TCP.functions.bif.zeek) -> -1
|
||||
0.000000 MetaHookPost LoadFile(0, ./Zeek_TCP.types.bif.zeek, <...>/Zeek_TCP.types.bif.zeek) -> -1
|
||||
|
@ -1024,6 +1020,7 @@
|
|||
0.000000 MetaHookPost LoadFile(0, ./smb1-main, <...>/smb1-main.zeek) -> -1
|
||||
0.000000 MetaHookPost LoadFile(0, ./smb2-main, <...>/smb2-main.zeek) -> -1
|
||||
0.000000 MetaHookPost LoadFile(0, ./spicy-events, <...>/spicy-events.zeek) -> -1
|
||||
0.000000 MetaHookPost LoadFile(0, ./spicy.bif.zeek, <...>/spicy.bif.zeek) -> -1
|
||||
0.000000 MetaHookPost LoadFile(0, ./stats.bif.zeek, <...>/stats.bif.zeek) -> -1
|
||||
0.000000 MetaHookPost LoadFile(0, ./std-dev, <...>/std-dev.zeek) -> -1
|
||||
0.000000 MetaHookPost LoadFile(0, ./store, <...>/store.zeek) -> -1
|
||||
|
@ -1058,10 +1055,6 @@
|
|||
0.000000 MetaHookPost LoadFile(0, <...>/__load__.zeek, <...>/__load__.zeek) -> -1
|
||||
0.000000 MetaHookPost LoadFile(0, <...>/__preload__.zeek, <...>/__preload__.zeek) -> -1
|
||||
0.000000 MetaHookPost LoadFile(0, <...>/hooks.zeek, <...>/hooks.zeek) -> -1
|
||||
0.000000 MetaHookPost LoadFile(0, Zeek<...>/bare.zeek, <...>/bare.zeek) -> -1
|
||||
0.000000 MetaHookPost LoadFile(0, Zeek<...>/default.zeek, <...>/default.zeek) -> -1
|
||||
0.000000 MetaHookPost LoadFile(0, Zeek_Spicy/__load__.zeek, <...>/__load__.zeek) -> -1
|
||||
0.000000 MetaHookPost LoadFile(0, Zeek_Spicy/__preload__.zeek, <...>/__preload__.zeek) -> -1
|
||||
0.000000 MetaHookPost LoadFile(0, base/bif, <...>/bif) -> -1
|
||||
0.000000 MetaHookPost LoadFile(0, base/init-default.zeek, <...>/init-default.zeek) -> -1
|
||||
0.000000 MetaHookPost LoadFile(0, base/init-frameworks-and-bifs.zeek, <...>/init-frameworks-and-bifs.zeek) -> -1
|
||||
|
@ -1119,6 +1112,8 @@
|
|||
0.000000 MetaHookPost LoadFile(0, base<...>/ieee802_11, <...>/ieee802_11) -> -1
|
||||
0.000000 MetaHookPost LoadFile(0, base<...>/ieee802_11_radio, <...>/ieee802_11_radio) -> -1
|
||||
0.000000 MetaHookPost LoadFile(0, base<...>/imap, <...>/imap) -> -1
|
||||
0.000000 MetaHookPost LoadFile(0, base<...>/init-bare, <...>/init-bare.zeek) -> -1
|
||||
0.000000 MetaHookPost LoadFile(0, base<...>/init-framework, <...>/init-framework.zeek) -> -1
|
||||
0.000000 MetaHookPost LoadFile(0, base<...>/input, <...>/input) -> -1
|
||||
0.000000 MetaHookPost LoadFile(0, base<...>/input.bif, <...>/input.bif.zeek) -> -1
|
||||
0.000000 MetaHookPost LoadFile(0, base<...>/installation, <...>/installation.zeek) -> -1
|
||||
|
@ -1177,6 +1172,7 @@
|
|||
0.000000 MetaHookPost LoadFile(0, base<...>/snmp, <...>/snmp) -> -1
|
||||
0.000000 MetaHookPost LoadFile(0, base<...>/socks, <...>/socks) -> -1
|
||||
0.000000 MetaHookPost LoadFile(0, base<...>/software, <...>/software) -> -1
|
||||
0.000000 MetaHookPost LoadFile(0, base<...>/spicy, <...>/spicy) -> -1
|
||||
0.000000 MetaHookPost LoadFile(0, base<...>/ssh, <...>/ssh) -> -1
|
||||
0.000000 MetaHookPost LoadFile(0, base<...>/ssl, <...>/ssl) -> -1
|
||||
0.000000 MetaHookPost LoadFile(0, base<...>/stats.bif, <...>/stats.bif.zeek) -> -1
|
||||
|
@ -1331,9 +1327,6 @@
|
|||
0.000000 MetaHookPost LoadFileExtended(0, ./Zeek_SSL.events.bif.zeek, <...>/Zeek_SSL.events.bif.zeek) -> (-1, <no content>)
|
||||
0.000000 MetaHookPost LoadFileExtended(0, ./Zeek_SSL.functions.bif.zeek, <...>/Zeek_SSL.functions.bif.zeek) -> (-1, <no content>)
|
||||
0.000000 MetaHookPost LoadFileExtended(0, ./Zeek_SSL.types.bif.zeek, <...>/Zeek_SSL.types.bif.zeek) -> (-1, <no content>)
|
||||
0.000000 MetaHookPost LoadFileExtended(0, ./Zeek_Spicy.consts.bif.zeek, <...>/Zeek_Spicy.consts.bif.zeek) -> (-1, <no content>)
|
||||
0.000000 MetaHookPost LoadFileExtended(0, ./Zeek_Spicy.events.bif.zeek, <...>/Zeek_Spicy.events.bif.zeek) -> (-1, <no content>)
|
||||
0.000000 MetaHookPost LoadFileExtended(0, ./Zeek_Spicy.functions.bif.zeek, <...>/Zeek_Spicy.functions.bif.zeek) -> (-1, <no content>)
|
||||
0.000000 MetaHookPost LoadFileExtended(0, ./Zeek_TCP.events.bif.zeek, <...>/Zeek_TCP.events.bif.zeek) -> (-1, <no content>)
|
||||
0.000000 MetaHookPost LoadFileExtended(0, ./Zeek_TCP.functions.bif.zeek, <...>/Zeek_TCP.functions.bif.zeek) -> (-1, <no content>)
|
||||
0.000000 MetaHookPost LoadFileExtended(0, ./Zeek_TCP.types.bif.zeek, <...>/Zeek_TCP.types.bif.zeek) -> (-1, <no content>)
|
||||
|
@ -1417,6 +1410,7 @@
|
|||
0.000000 MetaHookPost LoadFileExtended(0, ./smb1-main, <...>/smb1-main.zeek) -> (-1, <no content>)
|
||||
0.000000 MetaHookPost LoadFileExtended(0, ./smb2-main, <...>/smb2-main.zeek) -> (-1, <no content>)
|
||||
0.000000 MetaHookPost LoadFileExtended(0, ./spicy-events, <...>/spicy-events.zeek) -> (-1, <no content>)
|
||||
0.000000 MetaHookPost LoadFileExtended(0, ./spicy.bif.zeek, <...>/spicy.bif.zeek) -> (-1, <no content>)
|
||||
0.000000 MetaHookPost LoadFileExtended(0, ./stats.bif.zeek, <...>/stats.bif.zeek) -> (-1, <no content>)
|
||||
0.000000 MetaHookPost LoadFileExtended(0, ./std-dev, <...>/std-dev.zeek) -> (-1, <no content>)
|
||||
0.000000 MetaHookPost LoadFileExtended(0, ./store, <...>/store.zeek) -> (-1, <no content>)
|
||||
|
@ -1451,10 +1445,6 @@
|
|||
0.000000 MetaHookPost LoadFileExtended(0, <...>/__load__.zeek, <...>/__load__.zeek) -> (-1, <no content>)
|
||||
0.000000 MetaHookPost LoadFileExtended(0, <...>/__preload__.zeek, <...>/__preload__.zeek) -> (-1, <no content>)
|
||||
0.000000 MetaHookPost LoadFileExtended(0, <...>/hooks.zeek, <...>/hooks.zeek) -> (-1, <no content>)
|
||||
0.000000 MetaHookPost LoadFileExtended(0, Zeek<...>/bare.zeek, <...>/bare.zeek) -> (-1, <no content>)
|
||||
0.000000 MetaHookPost LoadFileExtended(0, Zeek<...>/default.zeek, <...>/default.zeek) -> (-1, <no content>)
|
||||
0.000000 MetaHookPost LoadFileExtended(0, Zeek_Spicy/__load__.zeek, <...>/__load__.zeek) -> (-1, <no content>)
|
||||
0.000000 MetaHookPost LoadFileExtended(0, Zeek_Spicy/__preload__.zeek, <...>/__preload__.zeek) -> (-1, <no content>)
|
||||
0.000000 MetaHookPost LoadFileExtended(0, base/bif, <...>/bif) -> (-1, <no content>)
|
||||
0.000000 MetaHookPost LoadFileExtended(0, base/init-default.zeek, <...>/init-default.zeek) -> (-1, <no content>)
|
||||
0.000000 MetaHookPost LoadFileExtended(0, base/init-frameworks-and-bifs.zeek, <...>/init-frameworks-and-bifs.zeek) -> (-1, <no content>)
|
||||
|
@ -1512,6 +1502,8 @@
|
|||
0.000000 MetaHookPost LoadFileExtended(0, base<...>/ieee802_11, <...>/ieee802_11) -> (-1, <no content>)
|
||||
0.000000 MetaHookPost LoadFileExtended(0, base<...>/ieee802_11_radio, <...>/ieee802_11_radio) -> (-1, <no content>)
|
||||
0.000000 MetaHookPost LoadFileExtended(0, base<...>/imap, <...>/imap) -> (-1, <no content>)
|
||||
0.000000 MetaHookPost LoadFileExtended(0, base<...>/init-bare, <...>/init-bare.zeek) -> (-1, <no content>)
|
||||
0.000000 MetaHookPost LoadFileExtended(0, base<...>/init-framework, <...>/init-framework.zeek) -> (-1, <no content>)
|
||||
0.000000 MetaHookPost LoadFileExtended(0, base<...>/input, <...>/input) -> (-1, <no content>)
|
||||
0.000000 MetaHookPost LoadFileExtended(0, base<...>/input.bif, <...>/input.bif.zeek) -> (-1, <no content>)
|
||||
0.000000 MetaHookPost LoadFileExtended(0, base<...>/installation, <...>/installation.zeek) -> (-1, <no content>)
|
||||
|
@ -1570,6 +1562,7 @@
|
|||
0.000000 MetaHookPost LoadFileExtended(0, base<...>/snmp, <...>/snmp) -> (-1, <no content>)
|
||||
0.000000 MetaHookPost LoadFileExtended(0, base<...>/socks, <...>/socks) -> (-1, <no content>)
|
||||
0.000000 MetaHookPost LoadFileExtended(0, base<...>/software, <...>/software) -> (-1, <no content>)
|
||||
0.000000 MetaHookPost LoadFileExtended(0, base<...>/spicy, <...>/spicy) -> (-1, <no content>)
|
||||
0.000000 MetaHookPost LoadFileExtended(0, base<...>/ssh, <...>/ssh) -> (-1, <no content>)
|
||||
0.000000 MetaHookPost LoadFileExtended(0, base<...>/ssl, <...>/ssl) -> (-1, <no content>)
|
||||
0.000000 MetaHookPost LoadFileExtended(0, base<...>/stats.bif, <...>/stats.bif.zeek) -> (-1, <no content>)
|
||||
|
@ -2410,7 +2403,6 @@
|
|||
0.000000 MetaHookPre CallFunction(Version::parse, ..., ...)
|
||||
0.000000 MetaHookPre CallFunction(__init_primary_bifs, <null>, ())
|
||||
0.000000 MetaHookPre CallFunction(__init_secondary_bifs, <null>, ())
|
||||
0.000000 MetaHookPre CallFunction(bare_mode, <null>, ())
|
||||
0.000000 MetaHookPre CallFunction(cat, ..., ...)
|
||||
0.000000 MetaHookPre CallFunction(current_time, <frame>, ())
|
||||
0.000000 MetaHookPre CallFunction(disable_event_group, <frame>, (Analyzer::Logging::include_confirmations))
|
||||
|
@ -2558,9 +2550,6 @@
|
|||
0.000000 MetaHookPre LoadFile(0, ./Zeek_SSL.events.bif.zeek, <...>/Zeek_SSL.events.bif.zeek)
|
||||
0.000000 MetaHookPre LoadFile(0, ./Zeek_SSL.functions.bif.zeek, <...>/Zeek_SSL.functions.bif.zeek)
|
||||
0.000000 MetaHookPre LoadFile(0, ./Zeek_SSL.types.bif.zeek, <...>/Zeek_SSL.types.bif.zeek)
|
||||
0.000000 MetaHookPre LoadFile(0, ./Zeek_Spicy.consts.bif.zeek, <...>/Zeek_Spicy.consts.bif.zeek)
|
||||
0.000000 MetaHookPre LoadFile(0, ./Zeek_Spicy.events.bif.zeek, <...>/Zeek_Spicy.events.bif.zeek)
|
||||
0.000000 MetaHookPre LoadFile(0, ./Zeek_Spicy.functions.bif.zeek, <...>/Zeek_Spicy.functions.bif.zeek)
|
||||
0.000000 MetaHookPre LoadFile(0, ./Zeek_TCP.events.bif.zeek, <...>/Zeek_TCP.events.bif.zeek)
|
||||
0.000000 MetaHookPre LoadFile(0, ./Zeek_TCP.functions.bif.zeek, <...>/Zeek_TCP.functions.bif.zeek)
|
||||
0.000000 MetaHookPre LoadFile(0, ./Zeek_TCP.types.bif.zeek, <...>/Zeek_TCP.types.bif.zeek)
|
||||
|
@ -2644,6 +2633,7 @@
|
|||
0.000000 MetaHookPre LoadFile(0, ./smb1-main, <...>/smb1-main.zeek)
|
||||
0.000000 MetaHookPre LoadFile(0, ./smb2-main, <...>/smb2-main.zeek)
|
||||
0.000000 MetaHookPre LoadFile(0, ./spicy-events, <...>/spicy-events.zeek)
|
||||
0.000000 MetaHookPre LoadFile(0, ./spicy.bif.zeek, <...>/spicy.bif.zeek)
|
||||
0.000000 MetaHookPre LoadFile(0, ./stats.bif.zeek, <...>/stats.bif.zeek)
|
||||
0.000000 MetaHookPre LoadFile(0, ./std-dev, <...>/std-dev.zeek)
|
||||
0.000000 MetaHookPre LoadFile(0, ./store, <...>/store.zeek)
|
||||
|
@ -2678,10 +2668,6 @@
|
|||
0.000000 MetaHookPre LoadFile(0, <...>/__load__.zeek, <...>/__load__.zeek)
|
||||
0.000000 MetaHookPre LoadFile(0, <...>/__preload__.zeek, <...>/__preload__.zeek)
|
||||
0.000000 MetaHookPre LoadFile(0, <...>/hooks.zeek, <...>/hooks.zeek)
|
||||
0.000000 MetaHookPre LoadFile(0, Zeek<...>/bare.zeek, <...>/bare.zeek)
|
||||
0.000000 MetaHookPre LoadFile(0, Zeek<...>/default.zeek, <...>/default.zeek)
|
||||
0.000000 MetaHookPre LoadFile(0, Zeek_Spicy/__load__.zeek, <...>/__load__.zeek)
|
||||
0.000000 MetaHookPre LoadFile(0, Zeek_Spicy/__preload__.zeek, <...>/__preload__.zeek)
|
||||
0.000000 MetaHookPre LoadFile(0, base/bif, <...>/bif)
|
||||
0.000000 MetaHookPre LoadFile(0, base/init-default.zeek, <...>/init-default.zeek)
|
||||
0.000000 MetaHookPre LoadFile(0, base/init-frameworks-and-bifs.zeek, <...>/init-frameworks-and-bifs.zeek)
|
||||
|
@ -2739,6 +2725,8 @@
|
|||
0.000000 MetaHookPre LoadFile(0, base<...>/ieee802_11, <...>/ieee802_11)
|
||||
0.000000 MetaHookPre LoadFile(0, base<...>/ieee802_11_radio, <...>/ieee802_11_radio)
|
||||
0.000000 MetaHookPre LoadFile(0, base<...>/imap, <...>/imap)
|
||||
0.000000 MetaHookPre LoadFile(0, base<...>/init-bare, <...>/init-bare.zeek)
|
||||
0.000000 MetaHookPre LoadFile(0, base<...>/init-framework, <...>/init-framework.zeek)
|
||||
0.000000 MetaHookPre LoadFile(0, base<...>/input, <...>/input)
|
||||
0.000000 MetaHookPre LoadFile(0, base<...>/input.bif, <...>/input.bif.zeek)
|
||||
0.000000 MetaHookPre LoadFile(0, base<...>/installation, <...>/installation.zeek)
|
||||
|
@ -2797,6 +2785,7 @@
|
|||
0.000000 MetaHookPre LoadFile(0, base<...>/snmp, <...>/snmp)
|
||||
0.000000 MetaHookPre LoadFile(0, base<...>/socks, <...>/socks)
|
||||
0.000000 MetaHookPre LoadFile(0, base<...>/software, <...>/software)
|
||||
0.000000 MetaHookPre LoadFile(0, base<...>/spicy, <...>/spicy)
|
||||
0.000000 MetaHookPre LoadFile(0, base<...>/ssh, <...>/ssh)
|
||||
0.000000 MetaHookPre LoadFile(0, base<...>/ssl, <...>/ssl)
|
||||
0.000000 MetaHookPre LoadFile(0, base<...>/stats.bif, <...>/stats.bif.zeek)
|
||||
|
@ -2951,9 +2940,6 @@
|
|||
0.000000 MetaHookPre LoadFileExtended(0, ./Zeek_SSL.events.bif.zeek, <...>/Zeek_SSL.events.bif.zeek)
|
||||
0.000000 MetaHookPre LoadFileExtended(0, ./Zeek_SSL.functions.bif.zeek, <...>/Zeek_SSL.functions.bif.zeek)
|
||||
0.000000 MetaHookPre LoadFileExtended(0, ./Zeek_SSL.types.bif.zeek, <...>/Zeek_SSL.types.bif.zeek)
|
||||
0.000000 MetaHookPre LoadFileExtended(0, ./Zeek_Spicy.consts.bif.zeek, <...>/Zeek_Spicy.consts.bif.zeek)
|
||||
0.000000 MetaHookPre LoadFileExtended(0, ./Zeek_Spicy.events.bif.zeek, <...>/Zeek_Spicy.events.bif.zeek)
|
||||
0.000000 MetaHookPre LoadFileExtended(0, ./Zeek_Spicy.functions.bif.zeek, <...>/Zeek_Spicy.functions.bif.zeek)
|
||||
0.000000 MetaHookPre LoadFileExtended(0, ./Zeek_TCP.events.bif.zeek, <...>/Zeek_TCP.events.bif.zeek)
|
||||
0.000000 MetaHookPre LoadFileExtended(0, ./Zeek_TCP.functions.bif.zeek, <...>/Zeek_TCP.functions.bif.zeek)
|
||||
0.000000 MetaHookPre LoadFileExtended(0, ./Zeek_TCP.types.bif.zeek, <...>/Zeek_TCP.types.bif.zeek)
|
||||
|
@ -3037,6 +3023,7 @@
|
|||
0.000000 MetaHookPre LoadFileExtended(0, ./smb1-main, <...>/smb1-main.zeek)
|
||||
0.000000 MetaHookPre LoadFileExtended(0, ./smb2-main, <...>/smb2-main.zeek)
|
||||
0.000000 MetaHookPre LoadFileExtended(0, ./spicy-events, <...>/spicy-events.zeek)
|
||||
0.000000 MetaHookPre LoadFileExtended(0, ./spicy.bif.zeek, <...>/spicy.bif.zeek)
|
||||
0.000000 MetaHookPre LoadFileExtended(0, ./stats.bif.zeek, <...>/stats.bif.zeek)
|
||||
0.000000 MetaHookPre LoadFileExtended(0, ./std-dev, <...>/std-dev.zeek)
|
||||
0.000000 MetaHookPre LoadFileExtended(0, ./store, <...>/store.zeek)
|
||||
|
@ -3071,10 +3058,6 @@
|
|||
0.000000 MetaHookPre LoadFileExtended(0, <...>/__load__.zeek, <...>/__load__.zeek)
|
||||
0.000000 MetaHookPre LoadFileExtended(0, <...>/__preload__.zeek, <...>/__preload__.zeek)
|
||||
0.000000 MetaHookPre LoadFileExtended(0, <...>/hooks.zeek, <...>/hooks.zeek)
|
||||
0.000000 MetaHookPre LoadFileExtended(0, Zeek<...>/bare.zeek, <...>/bare.zeek)
|
||||
0.000000 MetaHookPre LoadFileExtended(0, Zeek<...>/default.zeek, <...>/default.zeek)
|
||||
0.000000 MetaHookPre LoadFileExtended(0, Zeek_Spicy/__load__.zeek, <...>/__load__.zeek)
|
||||
0.000000 MetaHookPre LoadFileExtended(0, Zeek_Spicy/__preload__.zeek, <...>/__preload__.zeek)
|
||||
0.000000 MetaHookPre LoadFileExtended(0, base/bif, <...>/bif)
|
||||
0.000000 MetaHookPre LoadFileExtended(0, base/init-default.zeek, <...>/init-default.zeek)
|
||||
0.000000 MetaHookPre LoadFileExtended(0, base/init-frameworks-and-bifs.zeek, <...>/init-frameworks-and-bifs.zeek)
|
||||
|
@ -3132,6 +3115,8 @@
|
|||
0.000000 MetaHookPre LoadFileExtended(0, base<...>/ieee802_11, <...>/ieee802_11)
|
||||
0.000000 MetaHookPre LoadFileExtended(0, base<...>/ieee802_11_radio, <...>/ieee802_11_radio)
|
||||
0.000000 MetaHookPre LoadFileExtended(0, base<...>/imap, <...>/imap)
|
||||
0.000000 MetaHookPre LoadFileExtended(0, base<...>/init-bare, <...>/init-bare.zeek)
|
||||
0.000000 MetaHookPre LoadFileExtended(0, base<...>/init-framework, <...>/init-framework.zeek)
|
||||
0.000000 MetaHookPre LoadFileExtended(0, base<...>/input, <...>/input)
|
||||
0.000000 MetaHookPre LoadFileExtended(0, base<...>/input.bif, <...>/input.bif.zeek)
|
||||
0.000000 MetaHookPre LoadFileExtended(0, base<...>/installation, <...>/installation.zeek)
|
||||
|
@ -3190,6 +3175,7 @@
|
|||
0.000000 MetaHookPre LoadFileExtended(0, base<...>/snmp, <...>/snmp)
|
||||
0.000000 MetaHookPre LoadFileExtended(0, base<...>/socks, <...>/socks)
|
||||
0.000000 MetaHookPre LoadFileExtended(0, base<...>/software, <...>/software)
|
||||
0.000000 MetaHookPre LoadFileExtended(0, base<...>/spicy, <...>/spicy)
|
||||
0.000000 MetaHookPre LoadFileExtended(0, base<...>/ssh, <...>/ssh)
|
||||
0.000000 MetaHookPre LoadFileExtended(0, base<...>/ssl, <...>/ssl)
|
||||
0.000000 MetaHookPre LoadFileExtended(0, base<...>/stats.bif, <...>/stats.bif.zeek)
|
||||
|
@ -4029,7 +4015,6 @@
|
|||
0.000000 | HookCallFunction Version::parse(...)
|
||||
0.000000 | HookCallFunction __init_primary_bifs()
|
||||
0.000000 | HookCallFunction __init_secondary_bifs()
|
||||
0.000000 | HookCallFunction bare_mode()
|
||||
0.000000 | HookCallFunction cat(...)
|
||||
0.000000 | HookCallFunction current_time()
|
||||
0.000000 | HookCallFunction disable_event_group(Analyzer::Logging::include_confirmations)
|
||||
|
@ -4177,9 +4162,6 @@
|
|||
0.000000 | HookLoadFile ./Zeek_SSL.events.bif.zeek <...>/Zeek_SSL.events.bif.zeek
|
||||
0.000000 | HookLoadFile ./Zeek_SSL.functions.bif.zeek <...>/Zeek_SSL.functions.bif.zeek
|
||||
0.000000 | HookLoadFile ./Zeek_SSL.types.bif.zeek <...>/Zeek_SSL.types.bif.zeek
|
||||
0.000000 | HookLoadFile ./Zeek_Spicy.consts.bif.zeek <...>/Zeek_Spicy.consts.bif.zeek
|
||||
0.000000 | HookLoadFile ./Zeek_Spicy.events.bif.zeek <...>/Zeek_Spicy.events.bif.zeek
|
||||
0.000000 | HookLoadFile ./Zeek_Spicy.functions.bif.zeek <...>/Zeek_Spicy.functions.bif.zeek
|
||||
0.000000 | HookLoadFile ./Zeek_TCP.events.bif.zeek <...>/Zeek_TCP.events.bif.zeek
|
||||
0.000000 | HookLoadFile ./Zeek_TCP.functions.bif.zeek <...>/Zeek_TCP.functions.bif.zeek
|
||||
0.000000 | HookLoadFile ./Zeek_TCP.types.bif.zeek <...>/Zeek_TCP.types.bif.zeek
|
||||
|
@ -4274,6 +4256,7 @@
|
|||
0.000000 | HookLoadFile ./smb1-main <...>/smb1-main.zeek
|
||||
0.000000 | HookLoadFile ./smb2-main <...>/smb2-main.zeek
|
||||
0.000000 | HookLoadFile ./spicy-events <...>/spicy-events.zeek
|
||||
0.000000 | HookLoadFile ./spicy.bif.zeek <...>/spicy.bif.zeek
|
||||
0.000000 | HookLoadFile ./stats.bif.zeek <...>/stats.bif.zeek
|
||||
0.000000 | HookLoadFile ./std-dev <...>/std-dev.zeek
|
||||
0.000000 | HookLoadFile ./store <...>/store.zeek
|
||||
|
@ -4309,10 +4292,6 @@
|
|||
0.000000 | HookLoadFile <...>/__load__.zeek <...>/__load__.zeek
|
||||
0.000000 | HookLoadFile <...>/__preload__.zeek <...>/__preload__.zeek
|
||||
0.000000 | HookLoadFile <...>/hooks.zeek <...>/hooks.zeek
|
||||
0.000000 | HookLoadFile Zeek<...>/bare.zeek <...>/bare.zeek
|
||||
0.000000 | HookLoadFile Zeek<...>/default.zeek <...>/default.zeek
|
||||
0.000000 | HookLoadFile Zeek_Spicy/__load__.zeek <...>/__load__.zeek
|
||||
0.000000 | HookLoadFile Zeek_Spicy/__preload__.zeek <...>/__preload__.zeek
|
||||
0.000000 | HookLoadFile base/bif <...>/bif
|
||||
0.000000 | HookLoadFile base/init-default.zeek <...>/init-default.zeek
|
||||
0.000000 | HookLoadFile base/init-frameworks-and-bifs.zeek <...>/init-frameworks-and-bifs.zeek
|
||||
|
@ -4370,6 +4349,8 @@
|
|||
0.000000 | HookLoadFile base<...>/ieee802_11 <...>/ieee802_11
|
||||
0.000000 | HookLoadFile base<...>/ieee802_11_radio <...>/ieee802_11_radio
|
||||
0.000000 | HookLoadFile base<...>/imap <...>/imap
|
||||
0.000000 | HookLoadFile base<...>/init-bare <...>/init-bare.zeek
|
||||
0.000000 | HookLoadFile base<...>/init-framework <...>/init-framework.zeek
|
||||
0.000000 | HookLoadFile base<...>/input <...>/input
|
||||
0.000000 | HookLoadFile base<...>/input.bif <...>/input.bif.zeek
|
||||
0.000000 | HookLoadFile base<...>/installation <...>/installation.zeek
|
||||
|
@ -4428,6 +4409,7 @@
|
|||
0.000000 | HookLoadFile base<...>/snmp <...>/snmp
|
||||
0.000000 | HookLoadFile base<...>/socks <...>/socks
|
||||
0.000000 | HookLoadFile base<...>/software <...>/software
|
||||
0.000000 | HookLoadFile base<...>/spicy <...>/spicy
|
||||
0.000000 | HookLoadFile base<...>/ssh <...>/ssh
|
||||
0.000000 | HookLoadFile base<...>/ssl <...>/ssl
|
||||
0.000000 | HookLoadFile base<...>/stats.bif <...>/stats.bif.zeek
|
||||
|
@ -4570,9 +4552,6 @@
|
|||
0.000000 | HookLoadFileExtended ./Zeek_SSL.events.bif.zeek <...>/Zeek_SSL.events.bif.zeek
|
||||
0.000000 | HookLoadFileExtended ./Zeek_SSL.functions.bif.zeek <...>/Zeek_SSL.functions.bif.zeek
|
||||
0.000000 | HookLoadFileExtended ./Zeek_SSL.types.bif.zeek <...>/Zeek_SSL.types.bif.zeek
|
||||
0.000000 | HookLoadFileExtended ./Zeek_Spicy.consts.bif.zeek <...>/Zeek_Spicy.consts.bif.zeek
|
||||
0.000000 | HookLoadFileExtended ./Zeek_Spicy.events.bif.zeek <...>/Zeek_Spicy.events.bif.zeek
|
||||
0.000000 | HookLoadFileExtended ./Zeek_Spicy.functions.bif.zeek <...>/Zeek_Spicy.functions.bif.zeek
|
||||
0.000000 | HookLoadFileExtended ./Zeek_TCP.events.bif.zeek <...>/Zeek_TCP.events.bif.zeek
|
||||
0.000000 | HookLoadFileExtended ./Zeek_TCP.functions.bif.zeek <...>/Zeek_TCP.functions.bif.zeek
|
||||
0.000000 | HookLoadFileExtended ./Zeek_TCP.types.bif.zeek <...>/Zeek_TCP.types.bif.zeek
|
||||
|
@ -4667,6 +4646,7 @@
|
|||
0.000000 | HookLoadFileExtended ./smb1-main <...>/smb1-main.zeek
|
||||
0.000000 | HookLoadFileExtended ./smb2-main <...>/smb2-main.zeek
|
||||
0.000000 | HookLoadFileExtended ./spicy-events <...>/spicy-events.zeek
|
||||
0.000000 | HookLoadFileExtended ./spicy.bif.zeek <...>/spicy.bif.zeek
|
||||
0.000000 | HookLoadFileExtended ./stats.bif.zeek <...>/stats.bif.zeek
|
||||
0.000000 | HookLoadFileExtended ./std-dev <...>/std-dev.zeek
|
||||
0.000000 | HookLoadFileExtended ./store <...>/store.zeek
|
||||
|
@ -4702,10 +4682,6 @@
|
|||
0.000000 | HookLoadFileExtended <...>/__load__.zeek <...>/__load__.zeek
|
||||
0.000000 | HookLoadFileExtended <...>/__preload__.zeek <...>/__preload__.zeek
|
||||
0.000000 | HookLoadFileExtended <...>/hooks.zeek <...>/hooks.zeek
|
||||
0.000000 | HookLoadFileExtended Zeek<...>/bare.zeek <...>/bare.zeek
|
||||
0.000000 | HookLoadFileExtended Zeek<...>/default.zeek <...>/default.zeek
|
||||
0.000000 | HookLoadFileExtended Zeek_Spicy/__load__.zeek <...>/__load__.zeek
|
||||
0.000000 | HookLoadFileExtended Zeek_Spicy/__preload__.zeek <...>/__preload__.zeek
|
||||
0.000000 | HookLoadFileExtended base/bif <...>/bif
|
||||
0.000000 | HookLoadFileExtended base/init-default.zeek <...>/init-default.zeek
|
||||
0.000000 | HookLoadFileExtended base/init-frameworks-and-bifs.zeek <...>/init-frameworks-and-bifs.zeek
|
||||
|
@ -4763,6 +4739,8 @@
|
|||
0.000000 | HookLoadFileExtended base<...>/ieee802_11 <...>/ieee802_11
|
||||
0.000000 | HookLoadFileExtended base<...>/ieee802_11_radio <...>/ieee802_11_radio
|
||||
0.000000 | HookLoadFileExtended base<...>/imap <...>/imap
|
||||
0.000000 | HookLoadFileExtended base<...>/init-bare <...>/init-bare.zeek
|
||||
0.000000 | HookLoadFileExtended base<...>/init-framework <...>/init-framework.zeek
|
||||
0.000000 | HookLoadFileExtended base<...>/input <...>/input
|
||||
0.000000 | HookLoadFileExtended base<...>/input.bif <...>/input.bif.zeek
|
||||
0.000000 | HookLoadFileExtended base<...>/installation <...>/installation.zeek
|
||||
|
@ -4821,6 +4799,7 @@
|
|||
0.000000 | HookLoadFileExtended base<...>/snmp <...>/snmp
|
||||
0.000000 | HookLoadFileExtended base<...>/socks <...>/socks
|
||||
0.000000 | HookLoadFileExtended base<...>/software <...>/software
|
||||
0.000000 | HookLoadFileExtended base<...>/spicy <...>/spicy
|
||||
0.000000 | HookLoadFileExtended base<...>/ssh <...>/ssh
|
||||
0.000000 | HookLoadFileExtended base<...>/ssl <...>/ssl
|
||||
0.000000 | HookLoadFileExtended base<...>/stats.bif <...>/stats.bif.zeek
|
||||
|
|
6
testing/btest/Baseline/spicy.analyzer-tag/output
Normal file
6
testing/btest/Baseline/spicy.analyzer-tag/output
Normal file
|
@ -0,0 +1,6 @@
|
|||
### BTest baseline data generated by btest-diff. Do not edit. Use "btest -U/-u" to update. Requires BTest >= 0.63.
|
||||
Have analyzer!
|
||||
tag: Analyzer::ANALYZER_SPICY_SSH
|
||||
name: SPICY_SSH
|
||||
|
||||
Do not have analyzer!
|
3
testing/btest/Baseline/spicy.conn-id/output
Normal file
3
testing/btest/Baseline/spicy.conn-id/output
Normal file
|
@ -0,0 +1,3 @@
|
|||
### BTest baseline data generated by btest-diff. Do not edit. Use "btest -U/-u" to update. Requires BTest >= 0.63.
|
||||
(192.150.186.169, 49244/tcp, 131.159.14.23, 22/tcp)
|
||||
(2001:470:1f11:81f:c999:d94:aa7c:2e3e, 49185/tcp, 2001:470:4867:99::21, 21/tcp)
|
2
testing/btest/Baseline/spicy.context/output
Normal file
2
testing/btest/Baseline/spicy.context/output
Normal file
|
@ -0,0 +1,2 @@
|
|||
### BTest baseline data generated by btest-diff. Do not edit. Use "btest -U/-u" to update. Requires BTest >= 0.63.
|
||||
(b"2.0", b"1.99")
|
3
testing/btest/Baseline/spicy.dns/output
Normal file
3
testing/btest/Baseline/spicy.dns/output
Normal file
|
@ -0,0 +1,3 @@
|
|||
[orig_h=192.150.186.169, orig_p=55587/udp, resp_h=192.150.186.8, resp_p=53/udp], [id=29622, opcode=0, rcode=0, QR=F, AA=F, TC=F, RD=T, RA=F, Z=0, num_queries=1, num_answers=0, num_auth=0, num_addl=0], www.heise.de, 1, 1
|
||||
[orig_h=192.150.186.169, orig_p=55588/udp, resp_h=192.150.186.8, resp_p=53/udp], [id=15429, opcode=0, rcode=0, QR=F, AA=F, TC=F, RD=T, RA=F, Z=0, num_queries=1, num_answers=0, num_auth=0, num_addl=0], www.google.com, 1, 1
|
||||
[orig_h=192.150.186.169, orig_p=55589/udp, resp_h=192.150.186.8, resp_p=53/udp], [id=27360, opcode=0, rcode=0, QR=F, AA=F, TC=F, RD=T, RA=F, Z=0, num_queries=1, num_answers=0, num_auth=0, num_addl=0], www.net.in.tum.de, 1, 1
|
5
testing/btest/Baseline/spicy.double-event/output
Normal file
5
testing/btest/Baseline/spicy.double-event/output
Normal file
|
@ -0,0 +1,5 @@
|
|||
### BTest baseline data generated by btest-diff. Do not edit. Use "btest -U/-u" to update. Requires BTest >= 0.63.
|
||||
1, OpenSSH_3.8.1p1
|
||||
1, OpenSSH_3.9p1
|
||||
2, OpenSSH_3.8.1p1
|
||||
2, OpenSSH_3.9p1
|
4
testing/btest/Baseline/spicy.double-types/output
Normal file
4
testing/btest/Baseline/spicy.double-types/output
Normal file
|
@ -0,0 +1,4 @@
|
|||
### BTest baseline data generated by btest-diff. Do not edit. Use "btest -U/-u" to update. Requires BTest >= 0.63.
|
||||
dtest_message, dtest::FUNCS_YES
|
||||
dtest_result, dtest::RESULT_YES_AGAIN
|
||||
dtest_result_tuple, dtest::FUNCS_YES, dtest::RESULT_YES_AGAIN
|
3
testing/btest/Baseline/spicy.event-args-fail-2/output
Normal file
3
testing/btest/Baseline/spicy.event-args-fail-2/output
Normal file
|
@ -0,0 +1,3 @@
|
|||
### BTest baseline data generated by btest-diff. Do not edit. Use "btest -U/-u" to update. Requires BTest >= 0.63.
|
||||
[error] <...>/event-args-fail.evt:2: signature for hook must be: %error or %error(err: string)
|
||||
[error] <Spicy Plugin for Zeek>: aborting after errors
|
3
testing/btest/Baseline/spicy.event-args-fail-3/output
Normal file
3
testing/btest/Baseline/spicy.event-args-fail-3/output
Normal file
|
@ -0,0 +1,3 @@
|
|||
### BTest baseline data generated by btest-diff. Do not edit. Use "btest -U/-u" to update. Requires BTest >= 0.63.
|
||||
[error] <...>/event-args-fail.evt:2: signature for hook must be: %error or %error(err: string)
|
||||
[error] <Spicy Plugin for Zeek>: aborting after errors
|
3
testing/btest/Baseline/spicy.event-args-fail-4/output
Normal file
3
testing/btest/Baseline/spicy.event-args-fail-4/output
Normal file
|
@ -0,0 +1,3 @@
|
|||
### BTest baseline data generated by btest-diff. Do not edit. Use "btest -U/-u" to update. Requires BTest >= 0.63.
|
||||
[error] <...>/event-args-fail.evt:2: expected id
|
||||
[error] error loading EVT file "<...>/event-args-fail.evt"
|
3
testing/btest/Baseline/spicy.event-args-fail-5/output
Normal file
3
testing/btest/Baseline/spicy.event-args-fail-5/output
Normal file
|
@ -0,0 +1,3 @@
|
|||
### BTest baseline data generated by btest-diff. Do not edit. Use "btest -U/-u" to update. Requires BTest >= 0.63.
|
||||
[error] <...>/event-args-fail.evt:2: expected id
|
||||
[error] error loading EVT file "<...>/event-args-fail.evt"
|
3
testing/btest/Baseline/spicy.event-args-fail-6/output
Normal file
3
testing/btest/Baseline/spicy.event-args-fail-6/output
Normal file
|
@ -0,0 +1,3 @@
|
|||
### BTest baseline data generated by btest-diff. Do not edit. Use "btest -U/-u" to update. Requires BTest >= 0.63.
|
||||
[error] <...>/event-args-fail.evt:2: expected ':'
|
||||
[error] error loading EVT file "<...>/event-args-fail.evt"
|
3
testing/btest/Baseline/spicy.event-args-fail/output
Normal file
3
testing/btest/Baseline/spicy.event-args-fail/output
Normal file
|
@ -0,0 +1,3 @@
|
|||
### BTest baseline data generated by btest-diff. Do not edit. Use "btest -U/-u" to update. Requires BTest >= 0.63.
|
||||
[error] <...>/event-args-fail.evt:10: mismatching type
|
||||
[error] error loading EVT file "<...>/event-args-fail.evt"
|
2
testing/btest/Baseline/spicy.event-args-mismatch/output
Normal file
2
testing/btest/Baseline/spicy.event-args-mismatch/output
Normal file
|
@ -0,0 +1,2 @@
|
|||
### BTest baseline data generated by btest-diff. Do not edit. Use "btest -U/-u" to update. Requires BTest >= 0.63.
|
||||
XXXXXXXXXX.XXXXXX analyzer error in <...>/test.evt, line 6: Event parameter mismatch, cannot convert Spicy value of type 'string' to Zeek value of type 'count'
|
3
testing/btest/Baseline/spicy.event-args/output
Normal file
3
testing/btest/Baseline/spicy.event-args/output
Normal file
|
@ -0,0 +1,3 @@
|
|||
### BTest baseline data generated by btest-diff. Do not edit. Use "btest -U/-u" to update. Requires BTest >= 0.63.
|
||||
Error message: failed to match regular expression (<...>/test.spicy:7:15)
|
||||
Error message: n/a
|
6
testing/btest/Baseline/spicy.event-cond/output
Normal file
6
testing/btest/Baseline/spicy.event-cond/output
Normal file
|
@ -0,0 +1,6 @@
|
|||
### BTest baseline data generated by btest-diff. Do not edit. Use "btest -U/-u" to update. Requires BTest >= 0.63.
|
||||
1, OpenSSH_3.8.1p1
|
||||
1, OpenSSH_3.9p1
|
||||
3, OpenSSH_3.9p1
|
||||
4, OpenSSH_3.8.1p1
|
||||
5, OpenSSH_3.8.1p1
|
5
testing/btest/Baseline/spicy.event-user-type/output
Normal file
5
testing/btest/Baseline/spicy.event-user-type/output
Normal file
|
@ -0,0 +1,5 @@
|
|||
### BTest baseline data generated by btest-diff. Do not edit. Use "btest -U/-u" to update. Requires BTest >= 0.63.
|
||||
is_orig=1 y=[n=1, y=12345]
|
||||
is_orig=0 y=[n=2, y=ABCDE]
|
||||
is_orig=1 y=[n=3, y=67890]
|
||||
is_orig=0 y=[n=4, y=FGHIJ]
|
4
testing/btest/Baseline/spicy.export-enum/output
Normal file
4
testing/btest/Baseline/spicy.export-enum/output
Normal file
|
@ -0,0 +1,4 @@
|
|||
### BTest baseline data generated by btest-diff. Do not edit. Use "btest -U/-u" to update. Requires BTest >= 0.63.
|
||||
TupleEnum::TestEnum_A
|
||||
TupleEnum::TestEnum_Undef
|
||||
[Type] TupleEnum::TestEnum
|
6
testing/btest/Baseline/spicy.export-type-fail/output
Normal file
6
testing/btest/Baseline/spicy.export-type-fail/output
Normal file
|
@ -0,0 +1,6 @@
|
|||
### BTest baseline data generated by btest-diff. Do not edit. Use "btest -U/-u" to update. Requires BTest >= 0.63.
|
||||
[error] unknown type 'Test::DOES_NOT_EXIST' exported
|
||||
[error] unknown type 'NOT_SCOPED' exported
|
||||
[error] <...>/foo.spicy:1:13-5:3: cannot export Spicy type 'Test::X': type is self-recursive
|
||||
[error] <...>/foo.spicy:9:3-13:3: cannot export Spicy type 'Test::Z': can only convert tuple types with all-named fields to Zeek
|
||||
[error] <Spicy Plugin for Zeek>: aborting after errors
|
42
testing/btest/Baseline/spicy.export-types/output
Normal file
42
testing/btest/Baseline/spicy.export-types/output
Normal file
|
@ -0,0 +1,42 @@
|
|||
### BTest baseline data generated by btest-diff. Do not edit. Use "btest -U/-u" to update. Requires BTest >= 0.63.
|
||||
Test::e
|
||||
Test::s
|
||||
Test::type_enum
|
||||
Test::type_enum_A
|
||||
Test::type_enum_B
|
||||
Test::type_enum_C
|
||||
Test::type_enum_Undef
|
||||
Test::type_record_u, {
|
||||
[s] = [type_name=string, log=F, value=<uninitialized>, default_val=<uninitialized>],
|
||||
[u2] = [type_name=record , log=F, value=<uninitialized>, default_val=<uninitialized>],
|
||||
[b] = [type_name=bool, log=F, value=<uninitialized>, default_val=<uninitialized>]
|
||||
}
|
||||
Test::u
|
||||
Test::u2
|
||||
XYZ::type_record_sss, {
|
||||
[a] = [type_name=addr, log=F, value=<uninitialized>, default_val=<uninitialized>],
|
||||
[v] = [type_name=vector of string, log=F, value=<uninitialized>, default_val=<uninitialized>],
|
||||
[iv] = [type_name=interval, log=F, value=<uninitialized>, default_val=<uninitialized>],
|
||||
[t] = [type_name=time, log=F, value=<uninitialized>, default_val=<uninitialized>],
|
||||
[s] = [type_name=set[enum], log=F, value=<uninitialized>, default_val=<uninitialized>],
|
||||
[p] = [type_name=port, log=F, value=<uninitialized>, default_val=<uninitialized>],
|
||||
[b] = [type_name=string, log=F, value=<uninitialized>, default_val=<uninitialized>],
|
||||
[i] = [type_name=int, log=F, value=<uninitialized>, default_val=<uninitialized>],
|
||||
[o] = [type_name=string, log=F, value=<uninitialized>, default_val=<uninitialized>],
|
||||
[m] = [type_name=table[addr] of string, log=F, value=<uninitialized>, default_val=<uninitialized>],
|
||||
[u] = [type_name=record , log=F, value=<uninitialized>, default_val=<uninitialized>],
|
||||
[j] = [type_name=count, log=F, value=<uninitialized>, default_val=<uninitialized>],
|
||||
[e] = [type_name=enum, log=F, value=<uninitialized>, default_val=<uninitialized>],
|
||||
[r] = [type_name=double, log=F, value=<uninitialized>, default_val=<uninitialized>]
|
||||
}
|
||||
type_record_u2, {
|
||||
[t] = [type_name=record , log=F, value=<uninitialized>, default_val=<uninitialized>]
|
||||
}
|
||||
---
|
||||
[a=1.2.3.4, b=bytes, e=Test::type_enum_B, i=-10, iv=5.0 secs, j=10, m={
|
||||
[4.3.2.1] = addr1,
|
||||
[4.3.2.2] = addr2
|
||||
}, o=string, p=42/tcp, r=3.14, s={
|
||||
Test::type_enum_A,
|
||||
Test::type_enum_B
|
||||
}, t=0.0, u=[s=S, b=T, u2=[t=[x=S, y=T]]], v=[1, 2, 3]]
|
|
@ -0,0 +1,4 @@
|
|||
### BTest baseline data generated by btest-diff. Do not edit. Use "btest -U/-u" to update. Requires BTest >= 0.63.
|
||||
123456
|
||||
AAABBBCCC
|
||||
!@#$
|
|
@ -0,0 +1,3 @@
|
|||
### BTest baseline data generated by btest-diff. Do not edit. Use "btest -U/-u" to update. Requires BTest >= 0.63.
|
||||
dfe2070c79e7ff36a925ffa327ffe3deecf8f9c2 foo-1.txt
|
||||
dfe2070c79e7ff36a925ffa327ffe3deecf8f9c2 foo-2.txt
|
|
@ -0,0 +1,3 @@
|
|||
### BTest baseline data generated by btest-diff. Do not edit. Use "btest -U/-u" to update. Requires BTest >= 0.63.
|
||||
FL4lmy3f7owPUUoQ8l
|
||||
FhCRq1oIy2uDU8rog
|
|
@ -0,0 +1,3 @@
|
|||
### BTest baseline data generated by btest-diff. Do not edit. Use "btest -U/-u" to update. Requires BTest >= 0.63.
|
||||
01E3B49AA18D8AA981256950B8 CN=GTS CA 1O1,O=Google Trust Services,C=US
|
||||
01E3B49AA18D8AA981256950B8 CN=GTS CA 1O1,O=Google Trust Services,C=US
|
6
testing/btest/Baseline/spicy.file-analyzer-nested/files
Normal file
6
testing/btest/Baseline/spicy.file-analyzer-nested/files
Normal file
|
@ -0,0 +1,6 @@
|
|||
### BTest baseline data generated by btest-diff. Do not edit. Use "btest -U/-u" to update. Requires BTest >= 0.63.
|
||||
SPICY_TEXT2 SPICY_TEXT3 - text/plain3
|
||||
SPICY_TEXT2 SPICY_TEXT3 - text/plain3
|
||||
SPICY_TEXT1 SPICY_TEXT2 - text/plain2
|
||||
HTTP SPICY_TEXT1 - text/plain
|
||||
HTTP (empty) - text/json
|
5
testing/btest/Baseline/spicy.file-analyzer-nested/output
Normal file
5
testing/btest/Baseline/spicy.file-analyzer-nested/output
Normal file
|
@ -0,0 +1,5 @@
|
|||
### BTest baseline data generated by btest-diff. Do not edit. Use "btest -U/-u" to update. Requires BTest >= 0.63.
|
||||
data2, F2Qpmk14ATv4vFSEsi, from 1:hello world
|
||||
data3, FyjjRu4ARLzpsPLhNh, from 2a:from 1:hello world
|
||||
data3, Fz3QLf4Bn4qaQwyUdk, from 2b:from 1:hello world
|
||||
data1, FcRmxz1fPbKQEgGGUi, hello world
|
|
@ -0,0 +1,7 @@
|
|||
### BTest baseline data generated by btest-diff. Do not edit. Use "btest -U/-u" to update. Requires BTest >= 0.63.
|
||||
data3, FyjjRu4ARLzpsPLhNh,
|
||||
data3, Fz3QLf4Bn4qaQwyUdk,
|
||||
depth warning, FyjjRu4ARLzpsPLhNh, [chunk_event=<uninitialized>, stream_event=<uninitialized>, extract_filename=<uninitialized>, extract_limit=0], 2
|
||||
depth warning, Fz3QLf4Bn4qaQwyUdk, [chunk_event=<uninitialized>, stream_event=<uninitialized>, extract_filename=<uninitialized>, extract_limit=0], 2
|
||||
data2, F2Qpmk14ATv4vFSEsi, from 1:hello world
|
||||
data1, FcRmxz1fPbKQEgGGUi, hello world
|
|
@ -0,0 +1,2 @@
|
|||
### BTest baseline data generated by btest-diff. Do not edit. Use "btest -U/-u" to update. Requires BTest >= 0.63.
|
||||
text data, FcRmxz1fPbKQEgGGUi, hello world
|
3
testing/btest/Baseline/spicy.file-analyzer/output
Normal file
3
testing/btest/Baseline/spicy.file-analyzer/output
Normal file
|
@ -0,0 +1,3 @@
|
|||
### BTest baseline data generated by btest-diff. Do not edit. Use "btest -U/-u" to update. Requires BTest >= 0.63.
|
||||
Files::ANALYZER_SPICY_TEXT
|
||||
text data, FcRmxz1fPbKQEgGGUi, hello world
|
11
testing/btest/Baseline/spicy.file-analyzer/weird.log
Normal file
11
testing/btest/Baseline/spicy.file-analyzer/weird.log
Normal file
|
@ -0,0 +1,11 @@
|
|||
### BTest baseline data generated by btest-diff. Do not edit. Use "btest -U/-u" to update. Requires BTest >= 0.63.
|
||||
#separator \x09
|
||||
#set_separator ,
|
||||
#empty_field (empty)
|
||||
#unset_field -
|
||||
#path weird
|
||||
#open XXXX-XX-XX-XX-XX-XX
|
||||
#fields ts uid id.orig_h id.orig_p id.resp_h id.resp_p name addl notice peer source
|
||||
#types time string addr port addr port string string bool string string
|
||||
XXXXXXXXXX.XXXXXX - - - - - test_weird FcRmxz1fPbKQEgGGUi F zeek -
|
||||
#close XXXX-XX-XX-XX-XX-XX
|
|
@ -0,0 +1,3 @@
|
|||
### BTest baseline data generated by btest-diff. Do not edit. Use "btest -U/-u" to update. Requires BTest >= 0.63.
|
||||
FL4lmy3f7owPUUoQ8l
|
||||
FhCRq1oIy2uDU8rog
|
|
@ -0,0 +1,3 @@
|
|||
### BTest baseline data generated by btest-diff. Do not edit. Use "btest -U/-u" to update. Requires BTest >= 0.63.
|
||||
01E3B49AA18D8AA981256950B8 CN=GTS CA 1O1,O=Google Trust Services,C=US
|
||||
01E3B49AA18D8AA981256950B8 CN=GTS CA 1O1,O=Google Trust Services,C=US
|
3
testing/btest/Baseline/spicy.file-replaces/output
Normal file
3
testing/btest/Baseline/spicy.file-replaces/output
Normal file
|
@ -0,0 +1,3 @@
|
|||
### BTest baseline data generated by btest-diff. Do not edit. Use "btest -U/-u" to update. Requires BTest >= 0.63.
|
||||
FTP_DATA SPICY_PE - application/x-dosexec
|
||||
FTP_DATA PE - application/x-dosexec
|
3
testing/btest/Baseline/spicy.gap-recovery/output
Normal file
3
testing/btest/Baseline/spicy.gap-recovery/output
Normal file
|
@ -0,0 +1,3 @@
|
|||
### BTest baseline data generated by btest-diff. Do not edit. Use "btest -U/-u" to update. Requires BTest >= 0.63.
|
||||
[$responses=[[$marker=b"HTTP", $len=3070], [$marker=b"HTTP", $len=3070], [$marker=b"HTTP", $len=21999], [$marker=b"HTTP", $len=3070], [$marker=b"HTTP", $len=21999], [$marker=b"HTTP", $len=3070], [$marker=b"HTTP", $len=21999], [$marker=b"HTTP", $len=3070], [$marker=b"HTTP", $len=21999]]]
|
||||
[$requests=[[$marker=b"GET"], [$marker=b"GET"], [$marker=b"GET"], [$marker=b"GET"], [$marker=b"GET"], [$marker=b"GET"], [$marker=b"GET"], [$marker=b"GET"], [$marker=b"GET"], [$marker=b"GET"]]]
|
|
@ -0,0 +1,3 @@
|
|||
### BTest baseline data generated by btest-diff. Do not edit. Use "btest -U/-u" to update. Requires BTest >= 0.63.
|
||||
[$responses=[[$marker=b"HTTP", $len=3070], [$marker=b"HTTP", $len=3070], [$marker=b"HTTP", $len=21999], [$marker=b"HTTP", $len=3070], [$marker=b"HTTP", $len=21999], [$marker=b"HTTP", $len=3070], [$marker=b"HTTP", $len=21999]]]
|
||||
[$requests=[[$marker=b"GET"], [$marker=b"GET"], [$marker=b"GET"], [$marker=b"GET"], [$marker=b"GET"], [$marker=b"GET"], [$marker=b"GET"], [$marker=b"GET"], [$marker=b"GET"], [$marker=b"GET"]]]
|
3
testing/btest/Baseline/spicy.import-from/output
Normal file
3
testing/btest/Baseline/spicy.import-from/output
Normal file
|
@ -0,0 +1,3 @@
|
|||
### BTest baseline data generated by btest-diff. Do not edit. Use "btest -U/-u" to update. Requires BTest >= 0.63.
|
||||
Foo::x, Foo::y
|
||||
Foo::x, Foo::y
|
6
testing/btest/Baseline/spicy.list-conversion/output
Normal file
6
testing/btest/Baseline/spicy.list-conversion/output
Normal file
|
@ -0,0 +1,6 @@
|
|||
### BTest baseline data generated by btest-diff. Do not edit. Use "btest -U/-u" to update. Requires BTest >= 0.63.
|
||||
[orig_h=192.150.186.169, orig_p=49244/tcp, resp_h=131.159.14.23, resp_p=22/tcp]
|
||||
T
|
||||
[[a=83, b=84], [a=83, b=84], [a=72, b=73], [a=45, b=46], [a=50, b=51]]
|
||||
11824
|
||||
11599
|
3
testing/btest/Baseline/spicy.module-path/output
Normal file
3
testing/btest/Baseline/spicy.module-path/output
Normal file
|
@ -0,0 +1,3 @@
|
|||
### BTest baseline data generated by btest-diff. Do not edit. Use "btest -U/-u" to update. Requires BTest >= 0.63.
|
||||
Got it
|
||||
Got it
|
2
testing/btest/Baseline/spicy.multiple-enum/output
Normal file
2
testing/btest/Baseline/spicy.multiple-enum/output
Normal file
|
@ -0,0 +1,2 @@
|
|||
### BTest baseline data generated by btest-diff. Do not edit. Use "btest -U/-u" to update. Requires BTest >= 0.63.
|
||||
one, dtest::RESULT_B
|
5
testing/btest/Baseline/spicy.network-time/output
Normal file
5
testing/btest/Baseline/spicy.network-time/output
Normal file
|
@ -0,0 +1,5 @@
|
|||
### BTest baseline data generated by btest-diff. Do not edit. Use "btest -U/-u" to update. Requires BTest >= 0.63.
|
||||
1584014617531080960
|
||||
1584014621661943040
|
||||
1584014625494254080
|
||||
1584014635499969024
|
2
testing/btest/Baseline/spicy.optional/output
Normal file
2
testing/btest/Baseline/spicy.optional/output
Normal file
|
@ -0,0 +1,2 @@
|
|||
### BTest baseline data generated by btest-diff. Do not edit. Use "btest -U/-u" to update. Requires BTest >= 0.63.
|
||||
[x=<uninitialized>]
|
|
@ -0,0 +1,4 @@
|
|||
### BTest baseline data generated by btest-diff. Do not edit. Use "btest -U/-u" to update. Requires BTest >= 0.63.
|
||||
MACs: src=00:d0:b7:1e:be:20 dst=00:10:dc:72:4c:5f
|
||||
IPs : src=207.158.192.40 dst=10.20.1.31
|
||||
raw bytes: 441
|
|
@ -0,0 +1,2 @@
|
|||
### BTest baseline data generated by btest-diff. Do not edit. Use "btest -U/-u" to update. Requires BTest >= 0.63.
|
||||
My Ethernet:, \x00\x10\xdcrL_\x00\xd0\xb7\x1e\xbe \x08\x00
|
|
@ -0,0 +1,2 @@
|
|||
### BTest baseline data generated by btest-diff. Do not edit. Use "btest -U/-u" to update. Requires BTest >= 0.63.
|
||||
[spicy] test::Foo
|
3
testing/btest/Baseline/spicy.packet-analyzer/output
Normal file
3
testing/btest/Baseline/spicy.packet-analyzer/output
Normal file
|
@ -0,0 +1,3 @@
|
|||
### BTest baseline data generated by btest-diff. Do not edit. Use "btest -U/-u" to update. Requires BTest >= 0.63.
|
||||
MACs: src=c8:5b:76:bd:77:ab dst=ff:ff:ff:ff:ff:ff
|
||||
raw data, I am encapsulating
|
11
testing/btest/Baseline/spicy.packet-analyzer/weird.log
Normal file
11
testing/btest/Baseline/spicy.packet-analyzer/weird.log
Normal file
|
@ -0,0 +1,11 @@
|
|||
### BTest baseline data generated by btest-diff. Do not edit. Use "btest -U/-u" to update. Requires BTest >= 0.63.
|
||||
#separator \x09
|
||||
#set_separator ,
|
||||
#empty_field (empty)
|
||||
#unset_field -
|
||||
#path weird
|
||||
#open XXXX-XX-XX-XX-XX-XX
|
||||
#fields ts uid id.orig_h id.orig_p id.resp_h id.resp_p name addl notice peer source
|
||||
#types time string addr port addr port string string bool string string
|
||||
XXXXXXXXXX.XXXXXX - - - - - test_weird - F zeek SPICY_RAWLAYER
|
||||
#close XXXX-XX-XX-XX-XX-XX
|
11
testing/btest/Baseline/spicy.parse-error/dpd.log
Normal file
11
testing/btest/Baseline/spicy.parse-error/dpd.log
Normal file
|
@ -0,0 +1,11 @@
|
|||
### BTest baseline data generated by btest-diff. Do not edit. Use "btest -U/-u" to update. Requires BTest >= 0.63.
|
||||
#separator \x09
|
||||
#set_separator ,
|
||||
#empty_field (empty)
|
||||
#unset_field -
|
||||
#path dpd
|
||||
#open XXXX-XX-XX-XX-XX-XX
|
||||
#fields ts uid id.orig_h id.orig_p id.resp_h id.resp_p proto analyzer failure_reason
|
||||
#types time string addr port addr port enum string string
|
||||
XXXXXXXXXX.XXXXXX CHhAvVGS1DHFjwGM9 192.150.186.169 49244 131.159.14.23 22 tcp SPICY_SSH failed to match regular expression (<...>/test.spicy:9:15) [SSH-2.0-OpenSSH_3.8.1p1\x0a]
|
||||
#close XXXX-XX-XX-XX-XX-XX
|
3
testing/btest/Baseline/spicy.port-fail-2/output
Normal file
3
testing/btest/Baseline/spicy.port-fail-2/output
Normal file
|
@ -0,0 +1,3 @@
|
|||
### BTest baseline data generated by btest-diff. Do not edit. Use "btest -U/-u" to update. Requires BTest >= 0.63.
|
||||
[error] <...>/port-fail.evt:3: cannot parse port specification
|
||||
[error] error loading EVT file "<...>/port-fail.evt"
|
3
testing/btest/Baseline/spicy.port-fail-3/output
Normal file
3
testing/btest/Baseline/spicy.port-fail-3/output
Normal file
|
@ -0,0 +1,3 @@
|
|||
### BTest baseline data generated by btest-diff. Do not edit. Use "btest -U/-u" to update. Requires BTest >= 0.63.
|
||||
[error] <...>/port-fail.evt:3: start and end of port range must have same protocol
|
||||
[error] error loading EVT file "<...>/port-fail.evt"
|
Some files were not shown because too many files have changed in this diff Show more
Loading…
Add table
Add a link
Reference in a new issue