From 704f75a214313c30abbd660afbae8d930aec10b9 Mon Sep 17 00:00:00 2001 From: Arne Welzel Date: Wed, 21 Feb 2024 15:22:42 +0100 Subject: [PATCH 1/3] zeek.bif: Add find_in_zeekpath() helper Relates to #3594. This helper can be used to determine the path that will be used by @load, if at all. --- src/zeek.bif | 32 ++++++++++ .../Baseline/bifs.find_in_zeekpath/.stderr | 1 + .../bifs.find_in_zeekpath/errors.stderr | 3 + .../bifs.find_in_zeekpath/errors.stdout | 3 + .../btest/Baseline/bifs.find_in_zeekpath/out | 10 ++++ testing/btest/bifs/find_in_zeekpath.zeek | 59 +++++++++++++++++++ 6 files changed, 108 insertions(+) create mode 100644 testing/btest/Baseline/bifs.find_in_zeekpath/.stderr create mode 100644 testing/btest/Baseline/bifs.find_in_zeekpath/errors.stderr create mode 100644 testing/btest/Baseline/bifs.find_in_zeekpath/errors.stdout create mode 100644 testing/btest/Baseline/bifs.find_in_zeekpath/out create mode 100644 testing/btest/bifs/find_in_zeekpath.zeek diff --git a/src/zeek.bif b/src/zeek.bif index e3b1f5caa6..18ffb101bd 100644 --- a/src/zeek.bif +++ b/src/zeek.bif @@ -5328,3 +5328,35 @@ function table_pattern_matcher_stats%(tbl: any%) : MatcherStats return std::move(result); %} + +## Determine the path used by a non-relative @load directive. +## +## This function is package aware: Passing *package* will yield the +## path to *package.zeek*, *package/__load__.zeek* or an empty string +## if neither can be found. Note that passing a relative path or absolute +## path is an error. +## +## path: The filename, package or path to search for in ZEEKPATH. +## +## Returns: Path of script file that would be loaded by an @load directive. +function find_in_zeekpath%(p: string%): string + %{ + auto path = p->ToStdString(); + if ( ! path.empty() && (path[0] == '.' || path[0] == '/') ) + { + zeek::reporter->Error("find_in_zeek_path: path must be relative or absolute"); + return zeek::val_mgr->EmptyString(); + } + + auto resolved = zeek::util::find_script_file(path, zeek::util::zeek_path()); + if ( ! resolved.empty() && zeek::util::is_dir(resolved.c_str()) ) + { + // If it's a directory, try opening the package using + // the absolute path. This is zeek::util::open_package() + // without the noisy error log. + resolved.append("/__load__.zeek"); + resolved = zeek::util::find_file(resolved, ""); + } + + return zeek::make_intrusive(resolved.c_str()); + %} diff --git a/testing/btest/Baseline/bifs.find_in_zeekpath/.stderr b/testing/btest/Baseline/bifs.find_in_zeekpath/.stderr new file mode 100644 index 0000000000..49d861c74c --- /dev/null +++ b/testing/btest/Baseline/bifs.find_in_zeekpath/.stderr @@ -0,0 +1 @@ +### BTest baseline data generated by btest-diff. Do not edit. Use "btest -U/-u" to update. Requires BTest >= 0.63. diff --git a/testing/btest/Baseline/bifs.find_in_zeekpath/errors.stderr b/testing/btest/Baseline/bifs.find_in_zeekpath/errors.stderr new file mode 100644 index 0000000000..6ac968308b --- /dev/null +++ b/testing/btest/Baseline/bifs.find_in_zeekpath/errors.stderr @@ -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: find_in_zeek_path: path must be relative or absolute +error: find_in_zeek_path: path must be relative or absolute diff --git a/testing/btest/Baseline/bifs.find_in_zeekpath/errors.stdout b/testing/btest/Baseline/bifs.find_in_zeekpath/errors.stdout new file mode 100644 index 0000000000..0c8d6fd0fd --- /dev/null +++ b/testing/btest/Baseline/bifs.find_in_zeekpath/errors.stdout @@ -0,0 +1,3 @@ +### BTest baseline data generated by btest-diff. Do not edit. Use "btest -U/-u" to update. Requires BTest >= 0.63. +relative, +absolute, diff --git a/testing/btest/Baseline/bifs.find_in_zeekpath/out b/testing/btest/Baseline/bifs.find_in_zeekpath/out new file mode 100644 index 0000000000..878b9c6d19 --- /dev/null +++ b/testing/btest/Baseline/bifs.find_in_zeekpath/out @@ -0,0 +1,10 @@ +### BTest baseline data generated by btest-diff. Do not edit. Use "btest -U/-u" to update. Requires BTest >= 0.63. +find_in_zeekpath base/protocols/conn, base/protocols/conn/__load__.zeek +find_in_zeekpath protocols/conn (empty expected, no __load__.zeek), +find_in_zeekpath protocols/conn/vlan-logging, policy/protocols/conn/vlan-logging.zeek +find_in_zeekpath pkg1, ./pkg1.zeek +find_in_zeekpath pkg1.zeek, ./pkg1.zeek +find_in_zeekpath pkg2, ./pkg2/__load__.zeek +find_in_zeekpath pkg3, +pkg1! +pkg2! diff --git a/testing/btest/bifs/find_in_zeekpath.zeek b/testing/btest/bifs/find_in_zeekpath.zeek new file mode 100644 index 0000000000..bc212cb15c --- /dev/null +++ b/testing/btest/bifs/find_in_zeekpath.zeek @@ -0,0 +1,59 @@ +# @TEST-DOC: Test find_in_zeekpath() and demo conditional @load'ing. +# +# @TEST-EXEC: zeek -b %INPUT >out +# @TEST-EXEC: btest-diff out +# @TEST-EXEC: btest-diff .stderr +# +# @TEST-EXEC: zeek -b errors.zeek >errors.stdout 2>errors.stderr +# @TEST-EXEC: btest-diff errors.stdout +# @TEST-EXEC: btest-diff errors.stderr + + +@if ( find_in_zeekpath("pkg1") != "" ) +@load pkg1 +@endif + +@if ( find_in_zeekpath("pkg2") != "" ) +@load pkg2 +@endif + +@if ( find_in_zeekpath("pkg3") != "" ) +@load pkg3 +@endif + +function path_tail(r: string): string + { + if ( |r| == 0 ) + return r; + local parts = split_string(r, /\//); + return join_string_vec(parts[-4:], "/"); + } + +print "find_in_zeekpath base/protocols/conn", path_tail(find_in_zeekpath("base/protocols/conn")); +print "find_in_zeekpath protocols/conn (empty expected, no __load__.zeek)", find_in_zeekpath("protocols/conn"); +print "find_in_zeekpath protocols/conn/vlan-logging", path_tail(find_in_zeekpath("protocols/conn/vlan-logging")); + +print "find_in_zeekpath pkg1", find_in_zeekpath("pkg1"); +print "find_in_zeekpath pkg1.zeek", find_in_zeekpath("pkg1.zeek"); +print "find_in_zeekpath pkg2", find_in_zeekpath("pkg2"); +print "find_in_zeekpath pkg3", find_in_zeekpath("pkg3"); + +@TEST-START-FILE pkg1.zeek +event zeek_init() + { + print "pkg1!"; + } +@TEST-END-FILE + +@TEST-START-FILE pkg2/__load__.zeek +event zeek_init() + { + print "pkg2!"; + } +@TEST-END-FILE + +@TEST-START-FILE errors.zeek +# Using relative and absolute paths is an error (empty string) +print "relative", find_in_zeekpath("./pkg1.zeek"); +print "absolute", find_in_zeekpath("/pkg1"); +@TEST-END-FILE From 947294efaba4c5801c565ec1a1ae5325f7d52950 Mon Sep 17 00:00:00 2001 From: Arne Welzel Date: Thu, 22 Feb 2024 09:53:12 +0100 Subject: [PATCH 2/3] utils: Introduce packages.zeek with can_load() helper --- scripts/base/init-default.zeek | 1 + scripts/base/utils/packages.zeek | 16 ++++++++++ .../canonified_loaded_scripts.log | 1 + .../scripts.base.utils.packages/output | 4 +++ .../btest/scripts/base/utils/packages.zeek | 32 +++++++++++++++++++ 5 files changed, 54 insertions(+) create mode 100644 scripts/base/utils/packages.zeek create mode 100644 testing/btest/Baseline/scripts.base.utils.packages/output create mode 100644 testing/btest/scripts/base/utils/packages.zeek diff --git a/scripts/base/init-default.zeek b/scripts/base/init-default.zeek index 3a3efb6853..3c65158182 100644 --- a/scripts/base/init-default.zeek +++ b/scripts/base/init-default.zeek @@ -17,6 +17,7 @@ @load base/utils/geoip-distance @load base/utils/hash_hrw @load base/utils/numbers +@load base/utils/packages @load base/utils/paths @load base/utils/patterns @load base/utils/queue diff --git a/scripts/base/utils/packages.zeek b/scripts/base/utils/packages.zeek new file mode 100644 index 0000000000..24d6197bbd --- /dev/null +++ b/scripts/base/utils/packages.zeek @@ -0,0 +1,16 @@ +##! Rudimentary functions for helping with Zeek packages. + +## Checks whether @load of a given package name could +## be successful. +## +## This tests for the existence of corresponding script files +## in ZEEKPATH. It does not attempt to parse and validate +## any actual Zeek script code. +## +## path: The filename, package or path to test. +## +## Returns: T if the given filename, package or path may load. +function can_load(p: string): bool + { + return find_in_zeekpath(p) != ""; + } diff --git a/testing/btest/Baseline/coverage.default-load-baseline/canonified_loaded_scripts.log b/testing/btest/Baseline/coverage.default-load-baseline/canonified_loaded_scripts.log index 77e4e88706..a34d335a26 100644 --- a/testing/btest/Baseline/coverage.default-load-baseline/canonified_loaded_scripts.log +++ b/testing/btest/Baseline/coverage.default-load-baseline/canonified_loaded_scripts.log @@ -290,6 +290,7 @@ scripts/base/init-default.zeek scripts/base/utils/files.zeek scripts/base/utils/geoip-distance.zeek scripts/base/utils/numbers.zeek + scripts/base/utils/packages.zeek scripts/base/utils/queue.zeek scripts/base/utils/strings.zeek scripts/base/utils/thresholds.zeek diff --git a/testing/btest/Baseline/scripts.base.utils.packages/output b/testing/btest/Baseline/scripts.base.utils.packages/output new file mode 100644 index 0000000000..459feb4f3f --- /dev/null +++ b/testing/btest/Baseline/scripts.base.utils.packages/output @@ -0,0 +1,4 @@ +### BTest baseline data generated by btest-diff. Do not edit. Use "btest -U/-u" to update. Requires BTest >= 0.63. +no pkg3 +pkg1! +pkg2! diff --git a/testing/btest/scripts/base/utils/packages.zeek b/testing/btest/scripts/base/utils/packages.zeek new file mode 100644 index 0000000000..f9636def0a --- /dev/null +++ b/testing/btest/scripts/base/utils/packages.zeek @@ -0,0 +1,32 @@ +# @TEST-EXEC: zeek -b %INPUT >output +# @TEST-EXEC: btest-diff output + +@load base/utils/packages + +@if ( can_load("pkg1") ) +@load pkg1 +@endif + +@if ( can_load("pkg2") ) +@load pkg2 +@endif + +@if ( can_load("pkg3") ) +@load pkg3 +@else +print "no pkg3"; +@endif + +@TEST-START-FILE pkg1.zeek +event zeek_init() + { + print "pkg1!"; + } +@TEST-END-FILE + +@TEST-START-FILE pkg2/__load__.zeek +event zeek_init() + { + print "pkg2!"; + } +@TEST-END-FILE From 83bbcc12697d2dbc8a3e6e3cfa77ac0ae3f98f12 Mon Sep 17 00:00:00 2001 From: Arne Welzel Date: Thu, 22 Feb 2024 11:35:00 +0100 Subject: [PATCH 3/3] NEWS: Mention can_load() and find_in_zeekpath() --- NEWS | 9 +++++++++ 1 file changed, 9 insertions(+) diff --git a/NEWS b/NEWS index d23275ac78..db6ec2ba25 100644 --- a/NEWS +++ b/NEWS @@ -12,6 +12,15 @@ Breaking Changes New Functionality ----------------- +- A helper ``can_load()`` backed by a new bif ``find_in_zeekpath()`` was added + to determine if a non-relative ``@load`` directive might work. This can be + used to guard ``@load`` directives when script packages may or may not be + installed. + + @if ( can_load("my-package") ) + @load my-package + @endif + Changed Functionality ---------------------