From 596f4114fc809845456a9595b8529994c8d625da Mon Sep 17 00:00:00 2001 From: Benjamin Bannier Date: Thu, 11 Jul 2024 13:49:57 +0200 Subject: [PATCH 01/19] Do not emit hook files for builtin modules We would previously emit a C++ file with hooks for at least the builtin `spicy` module even though that module like any other builtin module never contains implementations of hooks for types in user code. This patch adds a blocklist of builtin modules which are skipped for generating hook files. --- src/spicy/spicyz/driver.cc | 9 +++++---- 1 file changed, 5 insertions(+), 4 deletions(-) diff --git a/src/spicy/spicyz/driver.cc b/src/spicy/spicyz/driver.cc index 8a4eee216a..8e4854c298 100644 --- a/src/spicy/spicyz/driver.cc +++ b/src/spicy/spicyz/driver.cc @@ -4,10 +4,8 @@ #include -#include #include #include -#include #include #include @@ -37,12 +35,15 @@ struct VisitorTypes : public spicy::visitor::PreOrder { : driver(driver), glue(glue), is_resolved(is_resolved) {} void operator()(hilti::declaration::Module* n) final { - if ( n->uid().in_memory ) { - // Ignore modules built by us in memory. + // Ignore modules built by us in memory, or builtin modules which + // never contain implementations of hooks for user types. + if ( n->uid().in_memory || + (module == "hilti" || module == "spicy" || module == "spicy_rt" || module == "zeek_rt") ) { module = {}; return; } + module = n->scopeID(); path = n->uid().path; From 40e1e43c25b5493f516f5ba5d9df35c39c42299e Mon Sep 17 00:00:00 2001 From: Dominik Charousset Date: Tue, 9 Jul 2024 15:53:58 -0700 Subject: [PATCH 02/19] Bump Broker to pull in new Prometheus support and pass in Zeek's registry Co-authored-by: Christian Kreibich --- auxil/broker | 2 +- src/broker/Manager.cc | 2 +- 2 files changed, 2 insertions(+), 2 deletions(-) diff --git a/auxil/broker b/auxil/broker index c47de11e4b..fada26ae50 160000 --- a/auxil/broker +++ b/auxil/broker @@ -1 +1 @@ -Subproject commit c47de11e4b84f24e8b501c3b1a446ad808e4964a +Subproject commit fada26ae504981f7f5524bf2a5c82ae49acd556d diff --git a/src/broker/Manager.cc b/src/broker/Manager.cc index 3b6350bf29..015f53d10e 100644 --- a/src/broker/Manager.cc +++ b/src/broker/Manager.cc @@ -189,7 +189,7 @@ struct opt_mapping { class BrokerState { public: BrokerState(broker::configuration config, size_t congestion_queue_size) - : endpoint(std::move(config)), + : endpoint(std::move(config), telemetry_mgr->GetRegistry()), subscriber( endpoint.make_subscriber({broker::topic::statuses(), broker::topic::errors()}, congestion_queue_size)) {} From b387da348951fbb612abb4f29a8a40d796f6be31 Mon Sep 17 00:00:00 2001 From: Christian Kreibich Date: Thu, 11 Jul 2024 10:58:27 -0700 Subject: [PATCH 03/19] Revert "Temporarily disable the scripts/base/frameworks/telemetry/internal-metrics btest" This reverts commit d6e97ab3060f102097db818fa32345113c683e31. Broker's telemetry is now available again. --- .../scripts/base/frameworks/telemetry/internal-metrics.zeek | 1 - 1 file changed, 1 deletion(-) diff --git a/testing/btest/scripts/base/frameworks/telemetry/internal-metrics.zeek b/testing/btest/scripts/base/frameworks/telemetry/internal-metrics.zeek index caf1b503a4..3df5beee2b 100644 --- a/testing/btest/scripts/base/frameworks/telemetry/internal-metrics.zeek +++ b/testing/btest/scripts/base/frameworks/telemetry/internal-metrics.zeek @@ -1,7 +1,6 @@ # @TEST-DOC: Query some internal broker/caf related metrics as they use the int64_t versions, too. # Note compilable to C++ due to globals being initialized to a record that # has an opaque type as a field. -# @TEST-KNOWN-FAILURE: Implementation for prometheus-cpp missing in broker # @TEST-REQUIRES: test "${ZEEK_USE_CPP}" != "1" # @TEST-EXEC: zcat <$TRACES/echo-connections.pcap.gz | zeek -b -Cr - %INPUT > out # @TEST-EXEC: btest-diff out From 77816f9a6befcf89a8ccb0052ab1770e2f219e25 Mon Sep 17 00:00:00 2001 From: Christian Kreibich Date: Thu, 11 Jul 2024 10:58:57 -0700 Subject: [PATCH 04/19] Update the scripts.base.frameworks.telemetry.internal-metrics test This now uses different record fields, and for now we no longer have CAF telemetry. We indicate we're running under test to get reliable ordering in the baselined output. --- .../out | 63 ++++++++----------- .../telemetry/internal-metrics.zeek | 24 +++---- 2 files changed, 37 insertions(+), 50 deletions(-) diff --git a/testing/btest/Baseline/scripts.base.frameworks.telemetry.internal-metrics/out b/testing/btest/Baseline/scripts.base.frameworks.telemetry.internal-metrics/out index 9da42e1925..2b0b3fa247 100644 --- a/testing/btest/Baseline/scripts.base.frameworks.telemetry.internal-metrics/out +++ b/testing/btest/Baseline/scripts.base.frameworks.telemetry.internal-metrics/out @@ -1,40 +1,27 @@ ### BTest baseline data generated by btest-diff. Do not edit. Use "btest -U/-u" to update. Requires BTest >= 0.63. ### broker |12| -Telemetry::INT_GAUGE, broker, connections, [type], [native], 0.0 -count_value, 0 -Telemetry::INT_GAUGE, broker, connections, [type], [web-socket], 0.0 -count_value, 0 -Telemetry::INT_COUNTER, broker, processed-messages, [type], [data], 0.0 -count_value, 0 -Telemetry::INT_COUNTER, broker, processed-messages, [type], [command], 0.0 -count_value, 0 -Telemetry::INT_COUNTER, broker, processed-messages, [type], [routing-update], 0.0 -count_value, 0 -Telemetry::INT_COUNTER, broker, processed-messages, [type], [ping], 0.0 -count_value, 0 -Telemetry::INT_COUNTER, broker, processed-messages, [type], [pong], 0.0 -count_value, 0 -Telemetry::INT_GAUGE, broker, buffered-messages, [type], [data], 0.0 -count_value, 0 -Telemetry::INT_GAUGE, broker, buffered-messages, [type], [command], 0.0 -count_value, 0 -Telemetry::INT_GAUGE, broker, buffered-messages, [type], [routing-update], 0.0 -count_value, 0 -Telemetry::INT_GAUGE, broker, buffered-messages, [type], [ping], 0.0 -count_value, 0 -Telemetry::INT_GAUGE, broker, buffered-messages, [type], [pong], 0.0 -count_value, 0 -### caf |5| -Telemetry::INT_COUNTER, caf.system, rejected-messages, [], [], 0.0 -count_value, 0 -Telemetry::INT_COUNTER, caf.system, processed-messages, [], [], 7.0 -count_value, 7 -Telemetry::INT_GAUGE, caf.system, running-actors, [], [], 2.0 -count_value, 2 -Telemetry::INT_GAUGE, caf.system, queued-messages, [], [], 0.0 -count_value, 0 -Telemetry::INT_GAUGE, caf.actor, mailbox-size, [name], [broker.core], 0.0 -count_value, 0 -### caf |2| -Telemetry::DOUBLE_HISTOGRAM, caf.actor, processing-time, [0.00001, 0.0001, 0.0005, 0.001, 0.01, 0.1, 0.5, 1.0, 5.0, inf], [name], [broker.core] -Telemetry::DOUBLE_HISTOGRAM, caf.actor, mailbox-time, [0.00001, 0.0001, 0.0005, 0.001, 0.01, 0.1, 0.5, 1.0, 5.0, inf], [name], [broker.core] +Telemetry::COUNTER, broker, broker_processed_messages_total, [type], [command], 0.0 +value, 0.0 +Telemetry::GAUGE, broker, broker_buffered_messages, [type], [command], 0.0 +value, 0.0 +Telemetry::COUNTER, broker, broker_processed_messages_total, [type], [data], 0.0 +value, 0.0 +Telemetry::GAUGE, broker, broker_buffered_messages, [type], [data], 0.0 +value, 0.0 +Telemetry::GAUGE, broker, broker_connections, [type], [native], 0.0 +value, 0.0 +Telemetry::COUNTER, broker, broker_processed_messages_total, [type], [ping], 0.0 +value, 0.0 +Telemetry::GAUGE, broker, broker_buffered_messages, [type], [ping], 0.0 +value, 0.0 +Telemetry::COUNTER, broker, broker_processed_messages_total, [type], [pong], 0.0 +value, 0.0 +Telemetry::GAUGE, broker, broker_buffered_messages, [type], [pong], 0.0 +value, 0.0 +Telemetry::COUNTER, broker, broker_processed_messages_total, [type], [routing-update], 0.0 +value, 0.0 +Telemetry::GAUGE, broker, broker_buffered_messages, [type], [routing-update], 0.0 +value, 0.0 +Telemetry::GAUGE, broker, broker_connections, [type], [web-socket], 0.0 +value, 0.0 +### broker |0| diff --git a/testing/btest/scripts/base/frameworks/telemetry/internal-metrics.zeek b/testing/btest/scripts/base/frameworks/telemetry/internal-metrics.zeek index 3df5beee2b..d130a22e48 100644 --- a/testing/btest/scripts/base/frameworks/telemetry/internal-metrics.zeek +++ b/testing/btest/scripts/base/frameworks/telemetry/internal-metrics.zeek @@ -1,4 +1,4 @@ -# @TEST-DOC: Query some internal broker/caf related metrics as they use the int64_t versions, too. +# @TEST-DOC: Query Broker's telemetry to verify it ends up in Zeek's registry. # Note compilable to C++ due to globals being initialized to a record that # has an opaque type as a field. # @TEST-REQUIRES: test "${ZEEK_USE_CPP}" != "1" @@ -8,17 +8,19 @@ @load base/frameworks/telemetry +redef running_under_test = T; + function print_histogram_metrics(what: string, metrics: vector of Telemetry::HistogramMetric) { print fmt("### %s |%s|", what, |metrics|); for (i in metrics) { local m = metrics[i]; - print m$opts$metric_type, m$opts$prefix, m$opts$name, m$opts$bounds, m$opts$labels, m$labels; + print m$opts$metric_type, m$opts$prefix, m$opts$name, m$opts$bounds, m$label_names, m?$label_values ? m$label_values : vector(); # Don't output actual values as they are runtime dependent. # print m$values, m$sum, m$observations; - if ( m$opts?$count_bounds ) - print m$opts$count_bounds; + if ( m$opts?$bounds ) + print m$opts$bounds; } } @@ -28,19 +30,17 @@ function print_metrics(what: string, metrics: vector of Telemetry::Metric) for (i in metrics) { local m = metrics[i]; - print m$opts$metric_type, m$opts$prefix, m$opts$name, m$opts$labels, m$labels, m$value; + print m$opts$metric_type, m$opts$prefix, m$opts$name, m$label_names, m?$label_values ? m$label_values : vector(), m$value; - if (m?$count_value) - print "count_value", m$count_value; + if (m?$value) + print "value", m$value; } } event zeek_done() &priority=-100 { - local broker_metrics = Telemetry::collect_metrics("broker", "*"); + local broker_metrics = Telemetry::collect_metrics("broker*", "*"); print_metrics("broker", broker_metrics); - local caf_metrics = Telemetry::collect_metrics("caf*", "*"); - print_metrics("caf", caf_metrics); - local caf_histogram_metrics = Telemetry::collect_histogram_metrics("caf*", "*"); - print_histogram_metrics("caf", caf_histogram_metrics); + local broker_histogram_metrics = Telemetry::collect_histogram_metrics("broker*", "*"); + print_histogram_metrics("broker", broker_histogram_metrics); } From f124b31904a047fc46703739cae016b491402bb2 Mon Sep 17 00:00:00 2001 From: Tim Wojtulewicz Date: Thu, 11 Jul 2024 12:21:02 -0700 Subject: [PATCH 05/19] Updating submodule(s) [nomail] --- auxil/bifcl | 2 +- auxil/binpac | 2 +- auxil/gen-zam | 2 +- auxil/zeek-aux | 2 +- auxil/zeekctl | 2 +- cmake | 2 +- 6 files changed, 6 insertions(+), 6 deletions(-) diff --git a/auxil/bifcl b/auxil/bifcl index fd83a78984..7c5ccc9aa9 160000 --- a/auxil/bifcl +++ b/auxil/bifcl @@ -1 +1 @@ -Subproject commit fd83a789848b485c81f28b8a6af23d28eca7b3c7 +Subproject commit 7c5ccc9aa91466004bc4a0dbbce11a239f3e742e diff --git a/auxil/binpac b/auxil/binpac index 7db629d4e2..a5c8f19fb4 160000 --- a/auxil/binpac +++ b/auxil/binpac @@ -1 +1 @@ -Subproject commit 7db629d4e2f8128e3e27aa28200106fa6d553be0 +Subproject commit a5c8f19fb49c60171622536fa6d369fa168f19e0 diff --git a/auxil/gen-zam b/auxil/gen-zam index 396723c04b..610cf8527d 160000 --- a/auxil/gen-zam +++ b/auxil/gen-zam @@ -1 +1 @@ -Subproject commit 396723c04ba1f8f2f75555745a503b8edf353ff6 +Subproject commit 610cf8527dad7033b971595a1d556c2c95294f2b diff --git a/auxil/zeek-aux b/auxil/zeek-aux index 1478f2ee55..8a66cd60fb 160000 --- a/auxil/zeek-aux +++ b/auxil/zeek-aux @@ -1 +1 @@ -Subproject commit 1478f2ee550a0f99f5b93975c17ae814ebe515b7 +Subproject commit 8a66cd60fb29a1237b5070854cb194f43a3f7a30 diff --git a/auxil/zeekctl b/auxil/zeekctl index 7671450f34..39c0ee1e17 160000 --- a/auxil/zeekctl +++ b/auxil/zeekctl @@ -1 +1 @@ -Subproject commit 7671450f34c65259463b4fd651a18df3935f235c +Subproject commit 39c0ee1e1742bb28dff57632ee4620f905b892e7 diff --git a/cmake b/cmake index db0d52761f..690483f76c 160000 --- a/cmake +++ b/cmake @@ -1 +1 @@ -Subproject commit db0d52761f38f3602060da36adc1afff608730c1 +Subproject commit 690483f76c149ffa8e035b612b406b0964f9886f From 822102382c444679e3a63e2814e69e7effca3cd9 Mon Sep 17 00:00:00 2001 From: Tim Wojtulewicz Date: Thu, 11 Jul 2024 13:19:15 -0700 Subject: [PATCH 06/19] Start of 7.1.0 development --- NEWS | 18 ++++++++++++++++++ VERSION | 2 +- testing/btest/scripts/site/local-compat.test | 2 +- 3 files changed, 20 insertions(+), 2 deletions(-) diff --git a/NEWS b/NEWS index e526919b09..1f3488cd7f 100644 --- a/NEWS +++ b/NEWS @@ -3,6 +3,24 @@ This document summarizes the most important changes in the current Zeek release. For an exhaustive list of changes, see the ``CHANGES`` file (note that submodules, such as Broker, come with their own ``CHANGES``.) +Zeek 7.1.0 +========== + +Breaking Changes +---------------- + +New Functionality +----------------- + +Changed Functionality +--------------------- + +Removed Functionality +--------------------- + +Deprecated Functionality +------------------------ + Zeek 7.0.0 ========== diff --git a/VERSION b/VERSION index 14530a2cf8..00b65bcfed 100644 --- a/VERSION +++ b/VERSION @@ -1 +1 @@ -7.0.0-dev.467 +7.1.0-dev.0 diff --git a/testing/btest/scripts/site/local-compat.test b/testing/btest/scripts/site/local-compat.test index 0c5483b810..0d287bff2e 100644 --- a/testing/btest/scripts/site/local-compat.test +++ b/testing/btest/scripts/site/local-compat.test @@ -15,7 +15,7 @@ # # simply update this test's TEST-START-FILE with the latest contents # site/local.zeek. -@TEST-START-FILE local-7.0.zeek +@TEST-START-FILE local-7.1.zeek ##! Local site policy. Customize as appropriate. ##! ##! This file will not be overwritten when upgrading or reinstalling! From 5fd563da79b13fc439783b2bed613d533f645a4e Mon Sep 17 00:00:00 2001 From: Tim Wojtulewicz Date: Thu, 11 Jul 2024 13:45:14 -0700 Subject: [PATCH 07/19] Fix warning about grealpath when running 'make dist' on Linux --- Makefile | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/Makefile b/Makefile index 5c0f8a4b97..394a77ab8e 100644 --- a/Makefile +++ b/Makefile @@ -9,7 +9,7 @@ BUILD=build REPO=$$(cd $(CURDIR) && basename $$(git config --get remote.origin.url | sed 's/^[^:]*://g')) VERSION_FULL=$(REPO)-$$(cd $(CURDIR) && cat VERSION) GITDIR=$$(test -f .git && echo $$(cut -d" " -f2 .git) || echo .git) -REALPATH=$$($$(realpath --relative-to=$(pwd) . >/dev/null 2>&1) && echo 'realpath' || echo 'grealpath') +REALPATH=$$($$(realpath --relative-to=$(shell pwd) . >/dev/null 2>&1) && echo 'realpath' || echo 'grealpath') all: configured $(MAKE) -C $(BUILD) $@ From 24d3454d619c0c0db4b4a6c4fd91ca43c78dca81 Mon Sep 17 00:00:00 2001 From: Benjamin Bannier Date: Thu, 11 Jul 2024 13:49:57 +0200 Subject: [PATCH 08/19] Do not emit hook files for builtin modules We would previously emit a C++ file with hooks for at least the builtin `spicy` module even though that module like any other builtin module never contains implementations of hooks for types in user code. This patch prevents modules with skipped implementations (such as our builtin modules) from being added to the compilation which prevents generating their hook files. --- src/spicy/spicyz/driver.cc | 4 +--- 1 file changed, 1 insertion(+), 3 deletions(-) diff --git a/src/spicy/spicyz/driver.cc b/src/spicy/spicyz/driver.cc index 8a4eee216a..1bfcb696c8 100644 --- a/src/spicy/spicyz/driver.cc +++ b/src/spicy/spicyz/driver.cc @@ -4,10 +4,8 @@ #include -#include #include #include -#include #include #include @@ -46,7 +44,7 @@ struct VisitorTypes : public spicy::visitor::PreOrder { module = n->scopeID(); path = n->uid().path; - if ( is_resolved ) + if ( is_resolved && ! n->skipImplementation() ) glue->addSpicyModule(module, path); } From f3bcf1a55d13986ef7d6146ca26095de32c0176b Mon Sep 17 00:00:00 2001 From: Tim Wojtulewicz Date: Fri, 12 Jul 2024 10:00:13 -0700 Subject: [PATCH 09/19] Fix a broken merge I merged an old version of the branch on accident and then merged the right one over top of it, but git ended up including both versions. This fixes that mistake. --- src/spicy/spicyz/driver.cc | 8 ++------ 1 file changed, 2 insertions(+), 6 deletions(-) diff --git a/src/spicy/spicyz/driver.cc b/src/spicy/spicyz/driver.cc index 82759fbf5e..75ffd1f6fa 100644 --- a/src/spicy/spicyz/driver.cc +++ b/src/spicy/spicyz/driver.cc @@ -35,15 +35,11 @@ struct VisitorTypes : public spicy::visitor::PreOrder { : driver(driver), glue(glue), is_resolved(is_resolved) {} void operator()(hilti::declaration::Module* n) final { - // Ignore modules built by us in memory, or builtin modules which - // never contain implementations of hooks for user types. - if ( n->uid().in_memory || - (module == "hilti" || module == "spicy" || module == "spicy_rt" || module == "zeek_rt") ) { + if ( n->uid().in_memory ) { + // Ignore modules built by us in memory. module = {}; return; } - - module = n->scopeID(); path = n->uid().path; From a46be1ea29f4c35410e6b6880250078a8182fcdb Mon Sep 17 00:00:00 2001 From: Tim Wojtulewicz Date: Fri, 12 Jul 2024 13:54:18 -0700 Subject: [PATCH 10/19] Update broker and cmake submodules [nomail] --- auxil/broker | 2 +- cmake | 2 +- 2 files changed, 2 insertions(+), 2 deletions(-) diff --git a/auxil/broker b/auxil/broker index fada26ae50..4d19d25dc9 160000 --- a/auxil/broker +++ b/auxil/broker @@ -1 +1 @@ -Subproject commit fada26ae504981f7f5524bf2a5c82ae49acd556d +Subproject commit 4d19d25dc9b3d6b89ea16ae14e1100f10d156551 diff --git a/cmake b/cmake index 690483f76c..2d42baf8e6 160000 --- a/cmake +++ b/cmake @@ -1 +1 @@ -Subproject commit 690483f76c149ffa8e035b612b406b0964f9886f +Subproject commit 2d42baf8e63a7494224aa9d02afa2cb43ddb96b8 From 4757536d7df5c8d3d5c0b959baf03d3d940d47e6 Mon Sep 17 00:00:00 2001 From: Tim Wojtulewicz Date: Fri, 12 Jul 2024 13:56:11 -0700 Subject: [PATCH 11/19] CI: Set FETCH_CONTENT_FULLY_DISCONNECTED flag for configure --- .cirrus.yml | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/.cirrus.yml b/.cirrus.yml index 1323ce8e95..b96146f230 100644 --- a/.cirrus.yml +++ b/.cirrus.yml @@ -10,7 +10,7 @@ btest_jobs: &BTEST_JOBS 4 btest_retries: &BTEST_RETRIES 2 memory: &MEMORY 16GB -config: &CONFIG --build-type=release --disable-broker-tests --prefix=$CIRRUS_WORKING_DIR/install --ccache --enable-werror +config: &CONFIG --build-type=release --disable-broker-tests --prefix=$CIRRUS_WORKING_DIR/install --ccache --enable-werror -D FETCHCONTENT_FULLY_DISCONNECTED:BOOL=ON no_spicy_config: &NO_SPICY_CONFIG --build-type=release --disable-broker-tests --disable-spicy --prefix=$CIRRUS_WORKING_DIR/install --ccache --enable-werror static_config: &STATIC_CONFIG --build-type=release --disable-broker-tests --enable-static-broker --enable-static-binpac --prefix=$CIRRUS_WORKING_DIR/install --ccache --enable-werror binary_config: &BINARY_CONFIG --prefix=$CIRRUS_WORKING_DIR/install --libdir=$CIRRUS_WORKING_DIR/install/lib --binary-package --enable-static-broker --enable-static-binpac --disable-broker-tests --build-type=Release --ccache --enable-werror From 41db05238b13def2a05d6bb8eff3246ce72039b9 Mon Sep 17 00:00:00 2001 From: Benjamin Bannier Date: Tue, 16 Jul 2024 08:17:31 +0200 Subject: [PATCH 12/19] Bump auxil/spicy to latest development snapshot This patch bump Spicy to the latest development snapshot. This introduces a backwards-incompatible change in that it removes support for a never officially supported syntax to specify unit fields (so I would argue: not strictly a breaking change). --- auxil/spicy | 2 +- src/analyzer/protocol/finger/finger.spicy | 2 +- src/analyzer/protocol/syslog/syslog.spicy | 2 +- src/spicy/spicyz/glue-compiler.cc | 2 +- 4 files changed, 4 insertions(+), 4 deletions(-) diff --git a/auxil/spicy b/auxil/spicy index 6581b1855a..4a1b43ef07 160000 --- a/auxil/spicy +++ b/auxil/spicy @@ -1 +1 @@ -Subproject commit 6581b1855a5ea8cc102c66b4ac6a431fc67484a0 +Subproject commit 4a1b43ef07d1305a7e88a4f0866068dc49de9d06 diff --git a/src/analyzer/protocol/finger/finger.spicy b/src/analyzer/protocol/finger/finger.spicy index dd07dbb7c3..0d6a8da54e 100644 --- a/src/analyzer/protocol/finger/finger.spicy +++ b/src/analyzer/protocol/finger/finger.spicy @@ -15,7 +15,7 @@ public type Request = unit { switch { -> : /\/W/ { self.whois = True; } - -> void; + -> : void; }; : OptionalWhiteSpace; diff --git a/src/analyzer/protocol/syslog/syslog.spicy b/src/analyzer/protocol/syslog/syslog.spicy index fd4c845870..ba8c8a77aa 100644 --- a/src/analyzer/protocol/syslog/syslog.spicy +++ b/src/analyzer/protocol/syslog/syslog.spicy @@ -7,7 +7,7 @@ import spicy; public type Message = unit { switch { -> prio: Priority; - -> void; + -> : void; }; msg: bytes &eod; diff --git a/src/spicy/spicyz/glue-compiler.cc b/src/spicy/spicyz/glue-compiler.cc index cc17312343..e9240ed245 100644 --- a/src/spicy/spicyz/glue-compiler.cc +++ b/src/spicy/spicyz/glue-compiler.cc @@ -1375,7 +1375,7 @@ bool GlueCompiler::CreateSpicyHook(glue::Event* ev) { auto attrs = builder()->attributeSet({builder()->attribute("&priority", builder()->integer(ev->priority))}); auto parameters = hilti::util::transform(ev->parameters, [](const auto& p) { return p.get(); }); - auto unit_hook = builder()->declarationHook(parameters, body.block(), ::spicy::Engine::All, attrs, meta); + auto unit_hook = builder()->declarationHook(parameters, body.block(), attrs, meta); auto hook_decl = builder()->declarationUnitHook(ev->hook, unit_hook, meta); ev->spicy_module->spicy_module->add(context(), hook_decl); From 31122f335fc5cda627c94002a23a2170834ab560 Mon Sep 17 00:00:00 2001 From: Arne Welzel Date: Thu, 11 Jul 2024 20:09:55 +0200 Subject: [PATCH 13/19] ldap: Handle integrity-only KRB wrap tokens Mostly staring at the PCAPs and opened a few RFCs. For now, only if the MS_KRB5 OID is used and accepted in a bind response, start stripping KRB5 wrap tokens for both, client and server traffic. Would probably be nice to forward the GSS-API data to the analyzer... Closes zeek/spicy-ldap#29. --- src/analyzer/protocol/ldap/ldap.spicy | 208 +++++++++++++++++- .../conn.log | 11 + .../ldap.log | 12 + .../ldap_search.log | 14 ++ .../conn.log | 13 ++ .../ldap.log | 15 ++ .../ldap_search.log | 27 +++ .../ldap/missing_krbtgt_ldap_request.pcapng | Bin 0 -> 101144 bytes .../Traces/ldap/missing_ldap_logs.pcapng | Bin 0 -> 443684 bytes .../protocols/ldap/sasl-signed-clear-2.zeek | 11 + .../protocols/ldap/sasl-signed-clear.zeek | 11 + 11 files changed, 310 insertions(+), 12 deletions(-) create mode 100644 testing/btest/Baseline/scripts.base.protocols.ldap.sasl-signed-clear-2/conn.log create mode 100644 testing/btest/Baseline/scripts.base.protocols.ldap.sasl-signed-clear-2/ldap.log create mode 100644 testing/btest/Baseline/scripts.base.protocols.ldap.sasl-signed-clear-2/ldap_search.log create mode 100644 testing/btest/Baseline/scripts.base.protocols.ldap.sasl-signed-clear/conn.log create mode 100644 testing/btest/Baseline/scripts.base.protocols.ldap.sasl-signed-clear/ldap.log create mode 100644 testing/btest/Baseline/scripts.base.protocols.ldap.sasl-signed-clear/ldap_search.log create mode 100644 testing/btest/Traces/ldap/missing_krbtgt_ldap_request.pcapng create mode 100644 testing/btest/Traces/ldap/missing_ldap_logs.pcapng create mode 100644 testing/btest/scripts/base/protocols/ldap/sasl-signed-clear-2.zeek create mode 100644 testing/btest/scripts/base/protocols/ldap/sasl-signed-clear.zeek diff --git a/src/analyzer/protocol/ldap/ldap.spicy b/src/analyzer/protocol/ldap/ldap.spicy index 8d74b85237..5c648f2304 100644 --- a/src/analyzer/protocol/ldap/ldap.spicy +++ b/src/analyzer/protocol/ldap/ldap.spicy @@ -126,9 +126,22 @@ public type Result = unit { # https://tools.ietf.org/html/rfc4511#section-4.1.10 }; +# 1.2.840.48018.1.2.2 (MS KRB5 - Microsoft Kerberos 5) +const GSSAPI_MECH_MS_KRB5 = "1.2.840.48018.1.2.2"; + +# Supported SASL stripping modes. +type SaslStripping = enum { + MS_KRB5 = 1, # Payload starts with a 4 byte length followed by a wrap token that may or may not be sealed. +}; + +type Ctx = struct { + saslStripping: SaslStripping; # Which mode of SASL stripping to use. +}; + #----------------------------------------------------------------------------- public type Messages = unit { - : MessageWrapper[]; + %context = Ctx; + : SASLStrip(self.context())[]; }; #----------------------------------------------------------------------------- @@ -149,7 +162,76 @@ type SASLLayer = unit { }; #----------------------------------------------------------------------------- -public type MessageWrapper = unit { +public type SASLStrip = unit(ctx: Ctx&) { + switch( ctx.saslStripping ) { + SaslStripping::Undef -> :MessageWrapper(ctx); + SaslStripping::MS_KRB5 -> : SaslMsKrb5Stripper(ctx); + }; +}; + + +type KrbWrapToken = unit { + # https://datatracker.ietf.org/doc/html/rfc4121#section-4.2.6.2 + + # Number of bytes to expect *after* the payload. + var trailer_ec: uint64; + var header_ec: uint64; + + ctx_flags: bitfield(8) { + send_by_acceptor: 0; + sealed: 1; + acceptor_subkey: 2; + }; + filler: skip b"\xff"; + ec: uint16; # extra count + rrc: uint16 { # right rotation count + # Handle rrc == ec or rrc == 0. + if ( self.rrc == self.ec ) { + self.header_ec = self.ec; + } else if ( self.rrc == 0 ) { + self.trailer_ec = self.ec; + } else { + throw "Unhandled rc %s and ec %s" % (self.ec, self.rrc); + } + } + + snd_seq: uint64; + header_e: skip bytes &size=self.header_ec; +}; + +#----------------------------------------------------------------------------- +type SaslMsKrb5Stripper = unit(ctx: Ctx&) { + # This is based on Wireshark output and example traffic we have. There's always + # a 4 byte length field followed by the krb5_tok_id field in messages after + # MS_KRB5 was selected. I haven't read enough specs to understand if it's + # just this one case that works, or others could use the same stripping. + var switch_size: uint64; + + len: uint32; + krb5_tok_id: uint16; + + switch ( self.krb5_tok_id ) { + 0x0504 -> krb_wrap_token: KrbWrapToken; + * -> : void; + }; + + : skip bytes &size=0 { + self.switch_size = self.len - (self.offset() - 4); + if ( self?.krb_wrap_token ) + self.switch_size -= self.krb_wrap_token.trailer_ec; + } + + switch ( self?.krb_wrap_token && ! self.krb_wrap_token.ctx_flags.sealed ) { + True -> : Message(ctx)[] &eod; + * -> : skip bytes &eod; + } &size=self.switch_size; + + # Consume the wrap token trailer, if any. + trailer_e: skip bytes &size=self.krb_wrap_token.trailer_ec if (self?.krb_wrap_token); +}; + +#----------------------------------------------------------------------------- +public type MessageWrapper = unit(ctx: Ctx&) { # A wrapper around 'Message'. First, we try to parse a Message unit. # There are two possible outcomes: # (1) Success -> We consumed all bytes and successfully parsed a Message unit @@ -159,10 +241,10 @@ public type MessageWrapper = unit { # This success variable is different, because this keeps track of the status for the MessageWrapper object var success: bool = False; - var message: Message; + var message: optional; # Here, we try to parse the message... - : Message &try { + : Message(ctx) &try { # ... and only if the Message unit successfully parsed, we can set # the status of this MessageWrapper's success to 'True' @@ -205,7 +287,7 @@ public type MessageWrapper = unit { # Also, we could try to do this recursively or try a few iterations, but for now I would suggest # to try this extra parsing once to get the best cost/benefit tradeoff. - : Message &try &parse-from=self.remainder if ( self.success == False && self.sasl_success == True ) { + : Message(ctx) &try &parse-from=self.remainder if ( self.success == False && self.sasl_success == True ) { if ( $$.success == True ) { self.success = True; self.message = $$; @@ -218,7 +300,7 @@ public type MessageWrapper = unit { } &convert=self.message; #----------------------------------------------------------------------------- -public type Message = unit { +public type Message = unit(ctx: Ctx&) { var messageID: int64; var opcode: ProtocolOpcode = ProtocolOpcode::Undef; var applicationBytes: bytes; @@ -244,7 +326,7 @@ public type Message = unit { switch ( self.opcode ) { ProtocolOpcode::BIND_REQUEST -> BIND_REQUEST: BindRequest(self); - ProtocolOpcode::BIND_RESPONSE -> BIND_RESPONSE: BindResponse(self); + ProtocolOpcode::BIND_RESPONSE -> BIND_RESPONSE: BindResponse(self, ctx); ProtocolOpcode::UNBIND_REQUEST -> UNBIND_REQUEST: UnbindRequest(self); ProtocolOpcode::SEARCH_REQUEST -> SEARCH_REQUEST: SearchRequest(self); ProtocolOpcode::SEARCH_RESULT_ENTRY -> SEARCH_RESULT_ENTRY: SearchResultEntry(self); @@ -288,9 +370,93 @@ public type BindAuthType = enum { BIND_AUTH_SASL = 3, }; +type GSS_SPNEGO_negTokenInit = unit { + oidHeader: ASN1::ASN1Header &requires=($$.tag.class == ASN1::ASN1Class::Universal && $$.tag.type_ == ASN1::ASN1Type::ObjectIdentifier); + oid: ASN1::ASN1ObjectIdentifier(self.oidHeader.len.len) &requires=(self.oid.oidstring == "1.3.6.1.5.5.2"); + + # TODO: Parse the rest of negTokenInit. + : skip bytes &eod; +}; + +# Peak into GSS-SPNEGO payload and ensure it is indeed GSS-SPNEGO. +type GSS_SPNEGO = unit { + # This is the optional octet string in SaslCredentials. + credentialsHeader: ASN1::ASN1Header &requires=($$.tag.type_ == ASN1::ASN1Type::OctetString); + + # Now we either have the initial message as specified in RFC2743 or + # a continuation from RFC4178 + # + # 60 -> APPLICATION [0] https://datatracker.ietf.org/doc/html/rfc2743#page-81) + # a1 -> CHOICE [1] https://www.rfc-editor.org/rfc/rfc4178#section-4.2 + # + gssapiHeader: ASN1::ASN1Header &requires=( + $$.tag.class == ASN1::ASN1Class::Application && $$.tag.type_ == ASN1::ASN1Type(0) + || $$.tag.class == ASN1::ASN1Class::ContextSpecific && $$.tag.type_ == ASN1::ASN1Type(1) + ); + + switch ( self.gssapiHeader.tag.type_ ) { + ASN1::ASN1Type(0) -> initial: GSS_SPNEGO_negTokenInit; + * -> : skip bytes &eod; + } &size=self.gssapiHeader.len.len; +}; + type SaslCredentials = unit() { - mechanism: ASN1::ASN1Message(True) &convert=$$.body.str_value; - # TODO: if we want to parse the (optional) credentials string + mechanism: ASN1::ASN1Message(False) &convert=$$.body.str_value; + + # Peak into GSS-SPNEGO payload if we have any. + switch ( self.mechanism ) { + "GSS-SPNEGO" -> gss_spnego: GSS_SPNEGO; + * -> : skip bytes &eod; + }; +}; + +type NegTokenResp = unit { + var accepted: bool; + var supportedMech: ASN1::ASN1Message; + + # Parse the contained Sequence. + seq: ASN1::ASN1Message(True) { + for ( msg in $$.body.seq.submessages ) { + # https://www.rfc-editor.org/rfc/rfc4178#section-4.2.2 + if ( msg.application_id == 0 ) { + self.accepted = msg.application_data == b"\x0a\x01\x00"; + } else if ( msg.application_id == 1 ) { + self.supportedMech = msg; + } else if ( msg.application_id == 2 ) { + # ignore responseToken + } else if ( msg.application_id == 3 ) { + # ignore mechListMec + } else { + throw "unhandled NegTokenResp id %s" % msg.application_id; + } + } + } + + switch ( self?.supportedMech ) { + True -> supportedMechOid: ASN1::ASN1Message(False) &convert=$$.body.str_value; + * -> : void; + } &parse-from=self.supportedMech.application_data; +}; + +type ServerSaslCreds = unit { + serverSaslCreds: ASN1::ASN1Header &requires=($$.tag.class == ASN1::ASN1Class::ContextSpecific && $$.tag.type_ == ASN1::ASN1Type(7)); + + # The PCAP missing_ldap_logs.pcapng has a1 81 b6 here for the GSS-SPNEGO response. + # + # This is context-specific ID 1, constructed, and a length of 182 as + # specified by in 4.2 of RFC4178. + # + # https://www.rfc-editor.org/rfc/rfc4178#section-4.2 + # + # TODO: This is only valid for a GSS-SPNEGO negTokenResp. + # If you want to support something else, remove the requires + # and add more to the switch below. + choice: ASN1::ASN1Header &requires=($$.tag.class == ASN1::ASN1Class::ContextSpecific); + + switch ( self.choice.tag.type_ ) { + ASN1::ASN1Type(1) -> negTokenResp: NegTokenResp; + # ... + } &size=self.choice.len.len; }; # TODO(fox-ds): A helper unit for requests for which no handling has been implemented. @@ -324,14 +490,32 @@ type BindRequest = unit(inout message: Message) { (|self.authData| > 0)) { message.arg = self.saslCreds.mechanism; } -} &requires=((self?.authType) && (self.authType != BindAuthType::Undef)); +} &requires=(self?.authType && (self.authType != BindAuthType::Undef)); -type BindResponse = unit(inout message: Message) { +type BindResponse = unit(inout message: Message, ctx: Ctx&) { : Result { message.result_ = $$; } - # TODO: if we want to parse SASL credentials returned + # Try to parse serverSaslCreds if there's any input remaining. This + # unit is parsed with &size, so &eod here works. + # + # Technically we should be able to tell from the ASN.1 structure + # if the serverSaslCreds field exists or not. But, not sure we can + # check if there's any bytes left at this point outside of passing + # in the length and playing with offset(). + serverSaslCreds: ServerSaslCreds[] &eod { + if ( |self.serverSaslCreds| > 0 ) { + if ( self.serverSaslCreds[0]?.negTokenResp ) { + local token = self.serverSaslCreds[0].negTokenResp; + if ( token.accepted && token?.supportedMechOid ) { + if ( token.supportedMechOid == GSSAPI_MECH_MS_KRB5 ) { + ctx.saslStripping = SaslStripping::MS_KRB5; + } + } + } + } + } }; #----------------------------------------------------------------------------- diff --git a/testing/btest/Baseline/scripts.base.protocols.ldap.sasl-signed-clear-2/conn.log b/testing/btest/Baseline/scripts.base.protocols.ldap.sasl-signed-clear-2/conn.log new file mode 100644 index 0000000000..8b4c3fa573 --- /dev/null +++ b/testing/btest/Baseline/scripts.base.protocols.ldap.sasl-signed-clear-2/conn.log @@ -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 conn +#open XXXX-XX-XX-XX-XX-XX +#fields ts uid id.orig_h id.orig_p id.resp_h id.resp_p proto service duration orig_bytes resp_bytes conn_state missed_bytes history orig_pkts orig_ip_bytes resp_pkts resp_ip_bytes tunnel_parents +#types time string addr port addr port enum string interval count count string count string count count count count set[string] +XXXXXXXXXX.XXXXXX CHhAvVGS1DHFjwGM9 192.168.10.138 63815 192.168.10.186 389 tcp ldap_tcp 0.033404 3046 90400 RSTR 0 ShADdar 14 1733 68 93132 - +#close XXXX-XX-XX-XX-XX-XX diff --git a/testing/btest/Baseline/scripts.base.protocols.ldap.sasl-signed-clear-2/ldap.log b/testing/btest/Baseline/scripts.base.protocols.ldap.sasl-signed-clear-2/ldap.log new file mode 100644 index 0000000000..cce0806fc6 --- /dev/null +++ b/testing/btest/Baseline/scripts.base.protocols.ldap.sasl-signed-clear-2/ldap.log @@ -0,0 +1,12 @@ +### 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 ldap +#open XXXX-XX-XX-XX-XX-XX +#fields ts uid id.orig_h id.orig_p id.resp_h id.resp_p message_id version opcode result diagnostic_message object argument +#types time string addr port addr port int int string string string string string +XXXXXXXXXX.XXXXXX CHhAvVGS1DHFjwGM9 192.168.10.138 63815 192.168.10.186 389 3 3 bind SASL success - - GSS-SPNEGO +XXXXXXXXXX.XXXXXX CHhAvVGS1DHFjwGM9 192.168.10.138 63815 192.168.10.186 389 9 - unbind - - - - +#close XXXX-XX-XX-XX-XX-XX diff --git a/testing/btest/Baseline/scripts.base.protocols.ldap.sasl-signed-clear-2/ldap_search.log b/testing/btest/Baseline/scripts.base.protocols.ldap.sasl-signed-clear-2/ldap_search.log new file mode 100644 index 0000000000..0caeba4973 --- /dev/null +++ b/testing/btest/Baseline/scripts.base.protocols.ldap.sasl-signed-clear-2/ldap_search.log @@ -0,0 +1,14 @@ +### 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 ldap_search +#open XXXX-XX-XX-XX-XX-XX +#fields ts uid id.orig_h id.orig_p id.resp_h id.resp_p message_id scope deref_aliases base_object result_count result diagnostic_message filter attributes +#types time string addr port addr port int string string string count string string string vector[string] +XXXXXXXXXX.XXXXXX CHhAvVGS1DHFjwGM9 192.168.10.138 63815 192.168.10.186 389 1 base never - 1 success - (objectclass=*) - +XXXXXXXXXX.XXXXXX CHhAvVGS1DHFjwGM9 192.168.10.138 63815 192.168.10.186 389 4 base never - 1 success - (objectClass=*) - +XXXXXXXXXX.XXXXXX CHhAvVGS1DHFjwGM9 192.168.10.138 63815 192.168.10.186 389 6 single never CN=Schema,CN=Configuration,DC=matrix,DC=local 424 success - (&(!(isdefunct=TRUE))(|(|(|(|(|(attributeSyntax=2.5.5.17)(attributeSyntax=2.5.5.10))(attributeSyntax=2.5.5.15))(attributeSyntax=2.5.5.1))(attributeSyntax=2.5.5.7))(attributeSyntax=2.5.5.14))) - +XXXXXXXXXX.XXXXXX CHhAvVGS1DHFjwGM9 192.168.10.138 63815 192.168.10.186 389 8 tree never DC=matrix,DC=local 1 success - (samaccountname=krbtgt) - +#close XXXX-XX-XX-XX-XX-XX diff --git a/testing/btest/Baseline/scripts.base.protocols.ldap.sasl-signed-clear/conn.log b/testing/btest/Baseline/scripts.base.protocols.ldap.sasl-signed-clear/conn.log new file mode 100644 index 0000000000..d4b1e6e630 --- /dev/null +++ b/testing/btest/Baseline/scripts.base.protocols.ldap.sasl-signed-clear/conn.log @@ -0,0 +1,13 @@ +### 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 conn +#open XXXX-XX-XX-XX-XX-XX +#fields ts uid id.orig_h id.orig_p id.resp_h id.resp_p proto service duration orig_bytes resp_bytes conn_state missed_bytes history orig_pkts orig_ip_bytes resp_pkts resp_ip_bytes tunnel_parents +#types time string addr port addr port enum string interval count count string count string count count count count set[string] +XXXXXXXXXX.XXXXXX CHhAvVGS1DHFjwGM9 10.199.2.121 59327 10.199.2.111 389 tcp ldap_tcp 63.273503 3963 400107 OTH 0 Dd 12 2595 282 411387 - +XXXXXXXXXX.XXXXXX ClEkJM2Vm5giqnMf4h 10.199.2.121 59355 10.199.2.111 389 tcp ldap_tcp 0.007979 2630 3327 OTH 0 Dd 6 990 6 3567 - +XXXXXXXXXX.XXXXXX C4J4Th3PJpwUYZZ6gc 10.199.2.121 59356 10.199.2.111 389 tcp ldap_tcp 0.001925 2183 3436 OTH 0 Dd 4 463 5 3636 - +#close XXXX-XX-XX-XX-XX-XX diff --git a/testing/btest/Baseline/scripts.base.protocols.ldap.sasl-signed-clear/ldap.log b/testing/btest/Baseline/scripts.base.protocols.ldap.sasl-signed-clear/ldap.log new file mode 100644 index 0000000000..6e6fe79fd9 --- /dev/null +++ b/testing/btest/Baseline/scripts.base.protocols.ldap.sasl-signed-clear/ldap.log @@ -0,0 +1,15 @@ +### 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 ldap +#open XXXX-XX-XX-XX-XX-XX +#fields ts uid id.orig_h id.orig_p id.resp_h id.resp_p message_id version opcode result diagnostic_message object argument +#types time string addr port addr port int int string string string string string +XXXXXXXXXX.XXXXXX CHhAvVGS1DHFjwGM9 10.199.2.121 59327 10.199.2.111 389 3 3 bind SASL success - - GSS-SPNEGO +XXXXXXXXXX.XXXXXX ClEkJM2Vm5giqnMf4h 10.199.2.121 59355 10.199.2.111 389 3 3 bind SASL success - - GSS-SPNEGO +XXXXXXXXXX.XXXXXX C4J4Th3PJpwUYZZ6gc 10.199.2.121 59356 10.199.2.111 389 9 3 bind SASL success - - GSS-SPNEGO +XXXXXXXXXX.XXXXXX C4J4Th3PJpwUYZZ6gc 10.199.2.121 59356 10.199.2.111 389 12 - unbind - - - - +XXXXXXXXXX.XXXXXX ClEkJM2Vm5giqnMf4h 10.199.2.121 59355 10.199.2.111 389 13 - unbind - - - - +#close XXXX-XX-XX-XX-XX-XX diff --git a/testing/btest/Baseline/scripts.base.protocols.ldap.sasl-signed-clear/ldap_search.log b/testing/btest/Baseline/scripts.base.protocols.ldap.sasl-signed-clear/ldap_search.log new file mode 100644 index 0000000000..3ef959bcf1 --- /dev/null +++ b/testing/btest/Baseline/scripts.base.protocols.ldap.sasl-signed-clear/ldap_search.log @@ -0,0 +1,27 @@ +### 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 ldap_search +#open XXXX-XX-XX-XX-XX-XX +#fields ts uid id.orig_h id.orig_p id.resp_h id.resp_p message_id scope deref_aliases base_object result_count result diagnostic_message filter attributes +#types time string addr port addr port int string string string count string string string vector[string] +XXXXXXXXXX.XXXXXX CHhAvVGS1DHFjwGM9 10.199.2.121 59327 10.199.2.111 389 1 base never - 1 success - (objectclass=*) - +XXXXXXXXXX.XXXXXX CHhAvVGS1DHFjwGM9 10.199.2.121 59327 10.199.2.111 389 4 base never - 1 success - (objectClass=*) - +XXXXXXXXXX.XXXXXX CHhAvVGS1DHFjwGM9 10.199.2.121 59327 10.199.2.111 389 5 base never CN=Enrollment Services,CN=Public Key Services,CN=Services,CN=Configuration,DC=DMC,DC=local 1 success - (objectClass=*) - +XXXXXXXXXX.XXXXXX CHhAvVGS1DHFjwGM9 10.199.2.121 59327 10.199.2.111 389 6 base never - 1 success - (objectClass=*) - +XXXXXXXXXX.XXXXXX CHhAvVGS1DHFjwGM9 10.199.2.121 59327 10.199.2.111 389 7 tree never CN=Enrollment Services,CN=Public Key Services,CN=Services,CN=Configuration,DC=DMC,DC=local 2 success - (objectCategory=pKIEnrollmentService) - +XXXXXXXXXX.XXXXXX CHhAvVGS1DHFjwGM9 10.199.2.121 59327 10.199.2.111 389 8 base never - 1 success - (objectClass=*) - +XXXXXXXXXX.XXXXXX CHhAvVGS1DHFjwGM9 10.199.2.121 59327 10.199.2.111 389 9 base never CN=Schema,CN=Configuration,DC=DMC,DC=local 1 success - (objectClass=dMD) - +XXXXXXXXXX.XXXXXX CHhAvVGS1DHFjwGM9 10.199.2.121 59327 10.199.2.111 389 10 base never CN=Schema,CN=Configuration,DC=DMC,DC=local 1 success - (objectClass=dMD) - +XXXXXXXXXX.XXXXXX CHhAvVGS1DHFjwGM9 10.199.2.121 59327 10.199.2.111 389 11 base never CN=Aggregate,CN=Schema,CN=Configuration,DC=DMC,DC=local 1 success - (objectClass=*) - +XXXXXXXXXX.XXXXXX ClEkJM2Vm5giqnMf4h 10.199.2.121 59355 10.199.2.111 389 1 base never - 1 success - (objectclass=*) - +XXXXXXXXXX.XXXXXX ClEkJM2Vm5giqnMf4h 10.199.2.121 59355 10.199.2.111 389 4 base never CN=WS01,CN=Computers,DC=DMC,DC=local 1 success - (objectclass=*) - +XXXXXXXXXX.XXXXXX ClEkJM2Vm5giqnMf4h 10.199.2.121 59355 10.199.2.111 389 5 base never CN=WS01,CN=Computers,DC=DMC,DC=local 1 success - (objectclass=*) - +XXXXXXXXXX.XXXXXX ClEkJM2Vm5giqnMf4h 10.199.2.121 59355 10.199.2.111 389 6 base never CN=WS01,CN=Computers,DC=DMC,DC=local 1 success - (objectclass=*) - +XXXXXXXXXX.XXXXXX C4J4Th3PJpwUYZZ6gc 10.199.2.121 59356 10.199.2.111 389 10 base never - 1 success - (ObjectClass=*) - +XXXXXXXXXX.XXXXXX C4J4Th3PJpwUYZZ6gc 10.199.2.121 59356 10.199.2.111 389 11 base never CN=62a0ff2e-97b9-4513-943f-0d221bd30080,CN=Device Registration Configuration,CN=services,CN=Configuration,DC=DMC,DC=local 0 no such object 0000208D: NameErr: DSID-0310028B, problem 2001 (NO_OBJECT), data 0, best match of:??'CN=Services,CN=Configuration,DC=DMC,DC=local'?? (ObjectClass=*) - +XXXXXXXXXX.XXXXXX CHhAvVGS1DHFjwGM9 10.199.2.121 59327 10.199.2.111 389 12 base never CN=Certificate Templates,CN=Public Key Services,CN=Services,CN=Configuration,DC=DMC,DC=local 1 success - (objectClass=*) - +XXXXXXXXXX.XXXXXX CHhAvVGS1DHFjwGM9 10.199.2.121 59327 10.199.2.111 389 13 tree never CN=Certificate Templates,CN=Public Key Services,CN=Services,CN=Configuration,DC=DMC,DC=local 38 success - (objectclass=pKICertificateTemplate) - +#close XXXX-XX-XX-XX-XX-XX diff --git a/testing/btest/Traces/ldap/missing_krbtgt_ldap_request.pcapng b/testing/btest/Traces/ldap/missing_krbtgt_ldap_request.pcapng new file mode 100644 index 0000000000000000000000000000000000000000..52c52d7424acb0bc08e375854d1342398cc3885f GIT binary patch literal 101144 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 j`n=HsM{l~f*M961(J7OBN9XYo|QIa4UvySObS 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 z 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 literal 0 HcmV?d00001 diff --git a/testing/btest/scripts/base/protocols/ldap/sasl-signed-clear-2.zeek b/testing/btest/scripts/base/protocols/ldap/sasl-signed-clear-2.zeek new file mode 100644 index 0000000000..12f397a62b --- /dev/null +++ b/testing/btest/scripts/base/protocols/ldap/sasl-signed-clear-2.zeek @@ -0,0 +1,11 @@ +# Copyright (c) 2024 by the Zeek Project. See LICENSE for details. + +# @TEST-REQUIRES: have-spicy +# @TEST-EXEC: zeek -C -r ${TRACES}/ldap/missing_krbtgt_ldap_request.pcapng %INPUT +# @TEST-EXEC: cat conn.log | zeek-cut -Cn local_orig local_resp > conn.log2 && mv conn.log2 conn.log +# @TEST-EXEC: btest-diff conn.log +# @TEST-EXEC: btest-diff ldap.log +# @TEST-EXEC: btest-diff ldap_search.log +# @TEST-EXEC: ! test -f dpd.log +# +# @TEST-DOC: Test LDAP analyzer with GSS-API integrity traffic where we can still peak into LDAP wrapped into WRAP tokens. diff --git a/testing/btest/scripts/base/protocols/ldap/sasl-signed-clear.zeek b/testing/btest/scripts/base/protocols/ldap/sasl-signed-clear.zeek new file mode 100644 index 0000000000..4ae8d4b639 --- /dev/null +++ b/testing/btest/scripts/base/protocols/ldap/sasl-signed-clear.zeek @@ -0,0 +1,11 @@ +# Copyright (c) 2024 by the Zeek Project. See LICENSE for details. + +# @TEST-REQUIRES: have-spicy +# @TEST-EXEC: zeek -C -r ${TRACES}/ldap/missing_ldap_logs.pcapng %INPUT +# @TEST-EXEC: cat conn.log | zeek-cut -Cn local_orig local_resp > conn.log2 && mv conn.log2 conn.log +# @TEST-EXEC: btest-diff conn.log +# @TEST-EXEC: btest-diff ldap.log +# @TEST-EXEC: btest-diff ldap_search.log +# @TEST-EXEC: ! test -f dpd.log +# +# @TEST-DOC: Test LDAP analyzer with GSS-API integrity traffic where we can still peak into LDAP wrapped into WRAP tokens. From 0cab87c185b5b1310b6b0fe2babb2587f98491c8 Mon Sep 17 00:00:00 2001 From: Arne Welzel Date: Tue, 16 Jul 2024 21:53:05 +0200 Subject: [PATCH 14/19] ldap: Harden parsing a bit ASN1Message(True) may go off parsing arbitrary input data as "something ASN.1" This could be GBs of octet strings or just very long sequences. Avoid this by open-coding some top-level types expected. This also tries to avoid some of the &parse-from usages that result in unnecessary copies of data. Adds a locally generated PCAP with addRequest/addResponse that we don't currently handle. --- src/analyzer/protocol/ldap/ldap.spicy | 51 +++++++++--------- .../scripts.base.protocols.ldap.add/conn.log | 11 ++++ .../scripts.base.protocols.ldap.add/ldap.log | 14 +++++ testing/btest/Traces/ldap/ldap-add.pcap | Bin 0 -> 2012 bytes .../scripts/base/protocols/ldap/add.zeek | 11 ++++ 5 files changed, 63 insertions(+), 24 deletions(-) create mode 100644 testing/btest/Baseline/scripts.base.protocols.ldap.add/conn.log create mode 100644 testing/btest/Baseline/scripts.base.protocols.ldap.add/ldap.log create mode 100644 testing/btest/Traces/ldap/ldap-add.pcap create mode 100644 testing/btest/scripts/base/protocols/ldap/add.zeek diff --git a/src/analyzer/protocol/ldap/ldap.spicy b/src/analyzer/protocol/ldap/ldap.spicy index 5c648f2304..2cd108d43e 100644 --- a/src/analyzer/protocol/ldap/ldap.spicy +++ b/src/analyzer/protocol/ldap/ldap.spicy @@ -303,25 +303,30 @@ public type MessageWrapper = unit(ctx: Ctx&) { public type Message = unit(ctx: Ctx&) { var messageID: int64; var opcode: ProtocolOpcode = ProtocolOpcode::Undef; - var applicationBytes: bytes; var unsetResultDefault: Result; var result_: Result& = self.unsetResultDefault; var obj: string = ""; var arg: string = ""; - var success: bool = False; + var seqHeaderLen: uint64; + var msgLen: uint64; - : ASN1::ASN1Message(True) { - if (($$.head.tag.type_ == ASN1::ASN1Type::Sequence) && - ($$.body?.seq) && - (|$$.body.seq.submessages| >= 2)) { - if ($$.body.seq.submessages[0].body?.num_value) { - self.messageID = $$.body.seq.submessages[0].body.num_value; - } - if ($$.body.seq.submessages[1]?.application_id) { - self.opcode = cast(cast($$.body.seq.submessages[1].application_id)); - self.applicationBytes = $$.body.seq.submessages[1].application_data; - } - } + seqHeader: ASN1::ASN1Header &requires=($$.tag.class == ASN1::ASN1Class::Universal && $$.tag.type_ == ASN1::ASN1Type::Sequence) { + self.msgLen = $$.len.len; + } + + # Use offset() to determine how many bytes the seqHeader took. This + # needs to be done after the seqHeader field hook. + : void { + self.seqHeaderLen = self.offset(); + } + + messageID_header: ASN1::ASN1Header &requires=($$.tag.class == ASN1::ASN1Class::Universal && $$.tag.type_ == ASN1::ASN1Type::Integer); + : ASN1::ASN1Body(self.messageID_header, False) { + self.messageID = $$.num_value; + } + + protocolOp: ASN1::ASN1Header &requires=($$.tag.class == ASN1::ASN1Class::Application) { + self.opcode = cast(cast($$.tag.type_)); } switch ( self.opcode ) { @@ -349,17 +354,15 @@ public type Message = unit(ctx: Ctx&) { ProtocolOpcode::INTERMEDIATE_RESPONSE -> INTERMEDIATE_RESPONSE: NotImplemented(self); ProtocolOpcode::MOD_DN_REQUEST -> MOD_DN_REQUEST: NotImplemented(self); ProtocolOpcode::SEARCH_RESULT_REFERENCE -> SEARCH_RESULT_REFERENCE: NotImplemented(self); - } &parse-from=self.applicationBytes if ( self.opcode ); + } &size=self.protocolOp.len.len; - on %error { - self.backtrack(); - } + # Ensure some invariants hold after parsing the command. + : void &requires=(self.offset() >= self.seqHeaderLen); + : void &requires=(self.msgLen >= (self.offset() - self.seqHeaderLen)); - on %done { - self.success = True; - } - -} &requires=((self?.messageID) && (self?.opcode) && (self.opcode != ProtocolOpcode::Undef)); + # Eat the controls field if it exists. + : skip bytes &size=self.msgLen - (self.offset() - self.seqHeaderLen); +}; #----------------------------------------------------------------------------- # Bind Operation @@ -462,7 +465,7 @@ type ServerSaslCreds = unit { # TODO(fox-ds): A helper unit for requests for which no handling has been implemented. # Eventually all uses of this unit should be replaced with actual parsers so this unit can be removed. type NotImplemented = unit(inout message: Message) { - # Do nothing + : skip bytes &eod; }; type BindRequest = unit(inout message: Message) { diff --git a/testing/btest/Baseline/scripts.base.protocols.ldap.add/conn.log b/testing/btest/Baseline/scripts.base.protocols.ldap.add/conn.log new file mode 100644 index 0000000000..09b5614986 --- /dev/null +++ b/testing/btest/Baseline/scripts.base.protocols.ldap.add/conn.log @@ -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 conn +#open XXXX-XX-XX-XX-XX-XX +#fields ts uid id.orig_h id.orig_p id.resp_h id.resp_p proto service duration orig_bytes resp_bytes conn_state missed_bytes history orig_pkts orig_ip_bytes resp_pkts resp_ip_bytes tunnel_parents +#types time string addr port addr port enum string interval count count string count string count count count count set[string] +XXXXXXXXXX.XXXXXX CHhAvVGS1DHFjwGM9 127.0.0.1 46160 127.0.1.1 389 tcp ldap_tcp 3.537413 536 42 SF 0 ShADadFf 11 1116 6 362 - +#close XXXX-XX-XX-XX-XX-XX diff --git a/testing/btest/Baseline/scripts.base.protocols.ldap.add/ldap.log b/testing/btest/Baseline/scripts.base.protocols.ldap.add/ldap.log new file mode 100644 index 0000000000..b6de5febd9 --- /dev/null +++ b/testing/btest/Baseline/scripts.base.protocols.ldap.add/ldap.log @@ -0,0 +1,14 @@ +### 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 ldap +#open XXXX-XX-XX-XX-XX-XX +#fields ts uid id.orig_h id.orig_p id.resp_h id.resp_p message_id version opcode result diagnostic_message object argument +#types time string addr port addr port int int string string string string string +XXXXXXXXXX.XXXXXX CHhAvVGS1DHFjwGM9 127.0.0.1 46160 127.0.1.1 389 1 3 bind simple success - cn=admin,dc=example,dc=com REDACTED +XXXXXXXXXX.XXXXXX CHhAvVGS1DHFjwGM9 127.0.0.1 46160 127.0.1.1 389 2 - add success - - - +XXXXXXXXXX.XXXXXX CHhAvVGS1DHFjwGM9 127.0.0.1 46160 127.0.1.1 389 3 - add success - - - +XXXXXXXXXX.XXXXXX CHhAvVGS1DHFjwGM9 127.0.0.1 46160 127.0.1.1 389 4 - unbind - - - - +#close XXXX-XX-XX-XX-XX-XX diff --git a/testing/btest/Traces/ldap/ldap-add.pcap b/testing/btest/Traces/ldap/ldap-add.pcap new file mode 100644 index 0000000000000000000000000000000000000000..118a8c42a53f9039231ee0181f5c5e1adcfe2071 GIT binary patch literal 2012 zcmaKsPiz}S7{zCIC$a0e!EFGULQn*15?WJcO`?K|MPdjM1w~d0YPof@p2SP-S+lz) zQAO0mQb7ik3kPW7P&hR=K;cpegs22nPqkVJT2Lv0CU8R)mncQy`^JCpTG4*eNbB|b zH*em1>uVRk{8S~BG-hjy5CuNmzVP96&yNvu7_M=(PMC}l@=WFC2pQ@8;^$NFgHuFN zRx--z*qwj(KpoQ9onwT{$0RQXkEUTxEy0Q%j97}@+dirdxnA{n(h zKoo$&)jE=RymCttzuJ}3p-JbxPVS}{Go_d{| zo|!jXSAT$No?WE7ZD+<1)=9&&Y+>YI6_&@kscM(>Fzu|-*nZlT<*w;iMSMtqi0*mL z7M@`V?(|LDPG8A|3obmz;w~QW!1ZuYB(98P#2<+sfsof1Ad-pAMkGsX)#Y3iBT=nJ zB*;Gk{D4S)mj>Q!GjJUuiDM)moM;;ONGQ3q_7@Plg+@Mt{|Q{JgOMojR{lWZ=kIJw zgh;L)Z4jMVB(kzH32#KMth_`AN>(-nwhNbwL{LCwWPDE27>9i6qEEDChF>2MEo>iAv@YL+LP^=wGJLvj{I^YK* xF@7nCI9`(GzT9SRKbSkVu#0TW5BkhqLgHv3vGS+Xc)d;I7-$@jcJ})<{s*}!1=0Wj literal 0 HcmV?d00001 diff --git a/testing/btest/scripts/base/protocols/ldap/add.zeek b/testing/btest/scripts/base/protocols/ldap/add.zeek new file mode 100644 index 0000000000..fbe2c9a4ad --- /dev/null +++ b/testing/btest/scripts/base/protocols/ldap/add.zeek @@ -0,0 +1,11 @@ +# Copyright (c) 2024 by the Zeek Project. See LICENSE for details. + +# @TEST-REQUIRES: have-spicy +# @TEST-EXEC: zeek -C -r ${TRACES}/ldap/ldap-add.pcap %INPUT +# @TEST-EXEC: cat conn.log | zeek-cut -Cn local_orig local_resp > conn.log2 && mv conn.log2 conn.log +# @TEST-EXEC: btest-diff conn.log +# @TEST-EXEC: btest-diff ldap.log +# @TEST-EXEC: ! test -f dpd.log +# @TEST-EXEC: ! test -f analyzer.log +# +# @TEST-DOC: The addRequest/addResponse operation is not implemented, yet we process it. From e7aca5b38872a858776fa9c99e695f7c2f8cc157 Mon Sep 17 00:00:00 2001 From: Arne Welzel Date: Wed, 17 Jul 2024 10:03:22 +0200 Subject: [PATCH 15/19] ldap: Remove MessageWrapper with magic 0x30 searching This unit implements a heuristic to search for the 0x30 sequence byte if Message couldn't readily be parsed. Remove it with the idea of explicit and predictable support for SASL mechanisms. --- src/analyzer/protocol/ldap/ldap.spicy | 90 +-------------------------- 1 file changed, 2 insertions(+), 88 deletions(-) diff --git a/src/analyzer/protocol/ldap/ldap.spicy b/src/analyzer/protocol/ldap/ldap.spicy index 2cd108d43e..2d4f821d78 100644 --- a/src/analyzer/protocol/ldap/ldap.spicy +++ b/src/analyzer/protocol/ldap/ldap.spicy @@ -144,27 +144,10 @@ public type Messages = unit { : SASLStrip(self.context())[]; }; -#----------------------------------------------------------------------------- -type SASLLayer = unit { - # For the time being (before we support parsing the SASL layer) this unit - # is used by MessageWrapper below to strip it (SASL) so that the parser - # can attempt to resume parsing afterward. It also sets the success flag - # if '\x30' is found, otherwise backtracks so that we can deal with encrypted - # SASL payloads without raising a parse error. - var success: bool = False; - : bytes &until=b"\x30" { - self.success = True; - } - - on %error { - self.backtrack(); - } -}; - #----------------------------------------------------------------------------- public type SASLStrip = unit(ctx: Ctx&) { switch( ctx.saslStripping ) { - SaslStripping::Undef -> :MessageWrapper(ctx); + SaslStripping::Undef -> : Message(ctx); SaslStripping::MS_KRB5 -> : SaslMsKrb5Stripper(ctx); }; }; @@ -230,75 +213,6 @@ type SaslMsKrb5Stripper = unit(ctx: Ctx&) { trailer_e: skip bytes &size=self.krb_wrap_token.trailer_ec if (self?.krb_wrap_token); }; -#----------------------------------------------------------------------------- -public type MessageWrapper = unit(ctx: Ctx&) { - # A wrapper around 'Message'. First, we try to parse a Message unit. - # There are two possible outcomes: - # (1) Success -> We consumed all bytes and successfully parsed a Message unit - # (2) No success -> self.backtrack() is called in the Message unit, - # so effectively we didn't consume any bytes yet. - # The outcome can be determined by checking the `success` variable of the Message unit - - # This success variable is different, because this keeps track of the status for the MessageWrapper object - var success: bool = False; - var message: optional; - - # Here, we try to parse the message... - : Message(ctx) &try { - - # ... and only if the Message unit successfully parsed, we can set - # the status of this MessageWrapper's success to 'True' - if ( $$.success == True ) { - self.success = True; - self.message = $$; - } - } - - # If we failed to parse the message, then we're going to scan the remaining bytes for the '\x30' - # start byte and try to parse a Message starting from that byte. This effectively - # strips the SASL layer if SASL Signing was enabled. Until now, I haven't found A - # better way to scan / determine the exact SASL header length yet, so we'll stick with this - # for the time being. If the entire LDAP packet was encrypted with SASL, then we skip parsing for - # now (in the long run we need to be parsing SASL/GSSAPI instead, in which case encrypted payloads - # are just another message type). - - # SASLLayer (see unit above) just consumes bytes &until=b"\x30" or backtracks if it isn't found - # and sets a success flag we can use later to decide if those bytes contain a parsable message. - var sasl_success: bool = False; - : SASLLayer &try if ( self.success == False ) { - if ( $$.success == True ) { - self.sasl_success = True; - } - } - var remainder: bytes; - - # SASLLayer consumes the delimiter ('\x30'), and because this is the first byte of a valid LDAP message - # we should re-add it to the remainder if the delimiter was found. If the delimiter was not found, we - # leave the remainder empty, but note that the bytes must be consumed either way to avoid stalling the - # parser and causing an infinite loop error. - : bytes &eod if ( self.success == False ) { - if ( self.sasl_success == True ) { - self.remainder = b"\x30" + $$; - } - } - - # Again, try to parse a Message unit. Be aware that in this will sometimes fail if the '\x30' byte is - # also present in the SASL header. - - # Also, we could try to do this recursively or try a few iterations, but for now I would suggest - # to try this extra parsing once to get the best cost/benefit tradeoff. - : Message(ctx) &try &parse-from=self.remainder if ( self.success == False && self.sasl_success == True ) { - if ( $$.success == True ) { - self.success = True; - self.message = $$; - } - } - - # If we still didn't manage to parse a message (so the &try resulted in another backtrack()) then - # this is probably an encrypted LDAP message, so skip it - -} &convert=self.message; - #----------------------------------------------------------------------------- public type Message = unit(ctx: Ctx&) { var messageID: int64; @@ -1086,6 +1000,6 @@ type AbandonRequest = unit(inout message: Message) { # # }; -on LDAP::MessageWrapper::%done { +on LDAP::Message::%done { spicy::accept_input(); } From b51a46f94d4012119fd27d5e46328c70af7270a2 Mon Sep 17 00:00:00 2001 From: Christian Kreibich Date: Mon, 15 Jul 2024 17:50:09 -0700 Subject: [PATCH 16/19] Bump zeek-testing-cluster to pull in tee SIGPIPE fix --- testing/external/commit-hash.zeek-testing-cluster | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/testing/external/commit-hash.zeek-testing-cluster b/testing/external/commit-hash.zeek-testing-cluster index 8b8bfdc2e4..5d84d38106 100644 --- a/testing/external/commit-hash.zeek-testing-cluster +++ b/testing/external/commit-hash.zeek-testing-cluster @@ -1 +1 @@ -45582671c6715e719d91c8afde7ffb480c602441 +ded009fb7a0cdee6f36d5b40a6394788b760fa06 From 3797622152313fa022ead069d59e28dcea4686d3 Mon Sep 17 00:00:00 2001 From: Arne Welzel Date: Fri, 19 Jul 2024 10:50:56 +0200 Subject: [PATCH 17/19] input/Manager: Improve type checks of record fields with type any Calling AsRecordType() or AsFunc() on a Val of type any isn't safe. Closes #3836 --- src/input/Manager.cc | 52 ++++++++++++++++++- .../.stderr | 8 +++ .../scripts/base/frameworks/input/errors.zeek | 11 ++++ 3 files changed, 70 insertions(+), 1 deletion(-) diff --git a/src/input/Manager.cc b/src/input/Manager.cc index 2de28b3735..127bd37514 100644 --- a/src/input/Manager.cc +++ b/src/input/Manager.cc @@ -264,6 +264,15 @@ bool Manager::CreateStream(Stream* info, RecordVal* description) { return true; } +// Return true if v is a TypeVal that contains a record type, else false; +static bool is_record_type_val(const zeek::ValPtr& v) { + const auto& t = v->GetType(); + return t->Tag() == TYPE_TYPE && t->AsTypeType()->GetType()->Tag() == TYPE_RECORD; +} + +// Return true if v contains is not nil and contains a FuncVal, else false; +static bool is_func_val(const zeek::ValPtr& v) { return v->GetType()->Tag() == TYPE_FUNC; } + bool Manager::CreateEventStream(RecordVal* fval) { RecordType* rtype = fval->GetType()->AsRecordType(); if ( ! same_type(rtype, BifType::Record::Input::EventDescription, false) ) { @@ -274,11 +283,21 @@ bool Manager::CreateEventStream(RecordVal* fval) { string stream_name = fval->GetFieldOrDefault("name")->AsString()->CheckString(); auto fields_val = fval->GetFieldOrDefault("fields"); + if ( ! is_record_type_val(fields_val) ) { + reporter->Error("Input stream %s: 'idx' field is not a record type", stream_name.c_str()); + return false; + } + RecordType* fields = fields_val->AsType()->AsTypeType()->GetType()->AsRecordType(); auto want_record = fval->GetFieldOrDefault("want_record"); auto ev_val = fval->GetFieldOrDefault("ev"); + if ( ev_val && ! is_func_val(ev_val) ) { + reporter->Error("Input stream %s: 'ev' field is not an event", stream_name.c_str()); + return false; + } + Func* event = ev_val->AsFunc(); const auto& etype = event->GetType(); @@ -356,6 +375,11 @@ bool Manager::CreateEventStream(RecordVal* fval) { assert(false); auto error_event_val = fval->GetFieldOrDefault("error_ev"); + if ( error_event_val && ! is_func_val(error_event_val) ) { + reporter->Error("Input stream %s: 'error_ev' field is not an event", stream_name.c_str()); + return false; + } + Func* error_event = error_event_val ? error_event_val->AsFunc() : nullptr; if ( ! CheckErrorEventTypes(stream_name, error_event, false) ) @@ -414,15 +438,31 @@ bool Manager::CreateTableStream(RecordVal* fval) { auto pred = fval->GetFieldOrDefault("pred"); auto idx_val = fval->GetFieldOrDefault("idx"); + if ( ! is_record_type_val(idx_val) ) { + reporter->Error("Input stream %s: 'idx' field is not a record type", stream_name.c_str()); + return false; + } + RecordType* idx = idx_val->AsType()->AsTypeType()->GetType()->AsRecordType(); RecordTypePtr val; auto val_val = fval->GetFieldOrDefault("val"); - if ( val_val ) + if ( val_val ) { + if ( ! is_record_type_val(val_val) ) { + reporter->Error("Input stream %s: 'val' field is not a record type", stream_name.c_str()); + return false; + } + val = val_val->AsType()->AsTypeType()->GetType(); + } auto dst = fval->GetFieldOrDefault("destination"); + if ( ! dst->GetType()->IsSet() && ! dst->GetType()->IsTable() ) { + reporter->Error("Input stream %s: 'destination' field has type %s, expected table or set identifier", + stream_name.c_str(), obj_desc_short(dst->GetType().get()).c_str()); + return false; + } // check if index fields match table description size_t num = idx->NumFields(); @@ -497,6 +537,11 @@ bool Manager::CreateTableStream(RecordVal* fval) { } auto event_val = fval->GetFieldOrDefault("ev"); + if ( event_val && ! is_func_val(event_val) ) { + reporter->Error("Input stream %s: 'ev' field is not an event", stream_name.c_str()); + return false; + } + Func* event = event_val ? event_val->AsFunc() : nullptr; if ( event ) { @@ -572,6 +617,11 @@ bool Manager::CreateTableStream(RecordVal* fval) { } auto error_event_val = fval->GetFieldOrDefault("error_ev"); + if ( error_event_val && ! is_func_val(error_event_val) ) { + reporter->Error("Input stream %s: 'error_ev' field is not an event", stream_name.c_str()); + return false; + } + Func* error_event = error_event_val ? error_event_val->AsFunc() : nullptr; if ( ! CheckErrorEventTypes(stream_name, error_event, true) ) diff --git a/testing/btest/Baseline/scripts.base.frameworks.input.errors/.stderr b/testing/btest/Baseline/scripts.base.frameworks.input.errors/.stderr index 66a9626596..1930931919 100644 --- a/testing/btest/Baseline/scripts.base.frameworks.input.errors/.stderr +++ b/testing/btest/Baseline/scripts.base.frameworks.input.errors/.stderr @@ -40,4 +40,12 @@ error: Input stream error3: Error event's first attribute must be of type Input: error: Input stream error4: Error event's second attribute must be of type string error: Input stream error5: Error event's third attribute must be of type Reporter::Level error: Input stream error6: 'destination' field is a table, but 'val' field is not provided (did you mean to use a set instead of a table?) +error: Input stream types1: 'idx' field is not a record type +error: Input stream types2: 'val' field is not a record type +error: Input stream types3: 'destination' field has type string, expected table or set identifier +error: Input stream types4: 'ev' field is not an event +error: Input stream types5: 'error_ev' field is not an event +error: Input stream types6: 'idx' field is not a record type +error: Input stream types7: 'ev' field is not an event +error: Input stream types8: 'error_ev' field is not an event received termination signal diff --git a/testing/btest/scripts/base/frameworks/input/errors.zeek b/testing/btest/scripts/base/frameworks/input/errors.zeek index 0bd80f70e3..fe55530484 100644 --- a/testing/btest/scripts/base/frameworks/input/errors.zeek +++ b/testing/btest/scripts/base/frameworks/input/errors.zeek @@ -59,6 +59,7 @@ global val_table: table[count] of Val = table(); global val_table2: table[count, int] of Val = table(); global val_table3: table[count, int] of int = table(); global val_table4: table[count] of int; +global val_set: set[count]; event line_file(description: Input::EventDescription, tpe: Input::Event, r:FileVal) { @@ -190,5 +191,15 @@ event zeek_init() Input::add_table([$source="input.log", $name="error6", $idx=Idx, $destination=val_table]); + # Check that we do not crash when a user passes unexpected types to any fields in the description records. + Input::add_table([$source="input.log", $name="types1", $idx="string-is-not-allowed", $destination=val_set]); + Input::add_table([$source="input.log", $name="types2", $idx=Idx, $val="string-is-not-allowed", $destination=val_set]); + Input::add_table([$source="input.log", $name="types3", $idx=Idx, $destination="string-is-not-allowed"]); + Input::add_table([$source="input.log", $name="types4", $idx=Idx, $destination=val_set, $ev="not-an-event"]); + Input::add_table([$source="input.log", $name="types5", $idx=Idx, $destination=val_set, $error_ev="not-an-event"]); + Input::add_event([$source="input.log", $name="types6", $fields="string-is-not-allowed", $ev=event11]); + Input::add_event([$source="input.log", $name="types7", $fields=Val, $ev="not-an-event"]); + Input::add_event([$source="input.log", $name="types8", $fields=Val, $ev=event11, $error_ev="not-an-event"]); + schedule 3secs { kill_me() }; } From bf9704f3398229c860aca92dd45df1b2fd26f68e Mon Sep 17 00:00:00 2001 From: Arne Welzel Date: Sun, 21 Jul 2024 17:34:34 +0200 Subject: [PATCH 18/19] telemetry: Deprecate prometheus.zeek policy script With Cluster::Node$metrics_port being optional, there's not really a need for the extra script. New rule, if a metrics_port is set, the node will attempt to listen on it. Users can still redef Telemetry::metrics_port *after* base/frameworks/telemetry was loaded to change the port defined in cluster-layout.zeek. --- .../base/frameworks/telemetry/__load__.zeek | 2 -- scripts/base/frameworks/telemetry/main.zeek | 18 ++++++++++++++++ .../frameworks/telemetry/prometheus.zeek | 21 ++----------------- scripts/site/local.zeek | 4 ---- testing/btest/coverage/bare-mode-errors.test | 2 +- .../coverage/test-all-policy-cluster.test | 2 +- .../frameworks/telemetry/prometheus.zeek | 1 - 7 files changed, 22 insertions(+), 28 deletions(-) diff --git a/scripts/base/frameworks/telemetry/__load__.zeek b/scripts/base/frameworks/telemetry/__load__.zeek index 88b6dbf672..a10fe855df 100644 --- a/scripts/base/frameworks/telemetry/__load__.zeek +++ b/scripts/base/frameworks/telemetry/__load__.zeek @@ -1,3 +1 @@ @load ./main - -@load base/frameworks/cluster diff --git a/scripts/base/frameworks/telemetry/main.zeek b/scripts/base/frameworks/telemetry/main.zeek index d71a7d9783..0e5ce1b1f5 100644 --- a/scripts/base/frameworks/telemetry/main.zeek +++ b/scripts/base/frameworks/telemetry/main.zeek @@ -5,10 +5,28 @@ ##! enabled by setting :zeek:see:`Telemetry::metrics_port`. @load base/misc/version +@load base/frameworks/cluster + @load base/frameworks/telemetry/options module Telemetry; +# In a cluster configuration, open the port number for metrics +# from the cluster node configuration for exporting data to +# Prometheus. +# +# The manager node will also provide a ``/services.json`` endpoint +# for the HTTP Service Discovery system in Prometheus to use for +# configuration. This endpoint will include information for all of +# the other nodes in the cluster. +@if ( Cluster::is_enabled() ) +redef Telemetry::metrics_endpoint_name = Cluster::node; + +@if ( Cluster::local_node_metrics_port() != 0/unknown ) +redef Telemetry::metrics_port = Cluster::local_node_metrics_port(); +@endif +@endif + export { ## Alias for a vector of label values. type labels_vector: vector of string; diff --git a/scripts/policy/frameworks/telemetry/prometheus.zeek b/scripts/policy/frameworks/telemetry/prometheus.zeek index 2b2ac4d255..a7d0226d73 100644 --- a/scripts/policy/frameworks/telemetry/prometheus.zeek +++ b/scripts/policy/frameworks/telemetry/prometheus.zeek @@ -1,19 +1,2 @@ -##! In a cluster configuration, open the port number for metrics -##! from the cluster node configuration for exporting data to -##! Prometheus. -##! -##! The manager node will also provide a ``/services.json`` endpoint -##! for the HTTP Service Discovery system in Prometheus to use for -##! configuration. This endpoint will include information for all of -##! the other nodes in the cluster. -@load base/frameworks/cluster - -@if ( Cluster::is_enabled() ) - -redef Telemetry::metrics_endpoint_name = Cluster::node; - -@if ( Cluster::local_node_metrics_port() != 0/unknown ) -redef Telemetry::metrics_port = Cluster::local_node_metrics_port(); -@endif - -@endif +@deprecated "Remove in v7.1: Cluster nodes now implicitly listen on metrics port if set in cluster-layout." +@load base/frameworks/telemetry diff --git a/scripts/site/local.zeek b/scripts/site/local.zeek index 71251c0cb1..d92ccdd5a6 100644 --- a/scripts/site/local.zeek +++ b/scripts/site/local.zeek @@ -94,10 +94,6 @@ redef digest_salt = "Please change this value."; # telemetry_histogram.log. @load frameworks/telemetry/log -# Enable Prometheus metrics scraping in the cluster: each Zeek node will listen -# on the metrics port defined in its Cluster::nodes entry. -# @load frameworks/telemetry/prometheus - # Uncomment the following line to enable detection of the heartbleed attack. Enabling # this might impact performance a bit. # @load policy/protocols/ssl/heartbleed diff --git a/testing/btest/coverage/bare-mode-errors.test b/testing/btest/coverage/bare-mode-errors.test index e477140083..be243bcdc0 100644 --- a/testing/btest/coverage/bare-mode-errors.test +++ b/testing/btest/coverage/bare-mode-errors.test @@ -9,4 +9,4 @@ # # @TEST-EXEC: test -d $DIST/scripts # @TEST-EXEC: for script in `find $DIST/scripts/ -name \*\.zeek`; do zeek -b --parse-only $script >>errors 2>&1; done -# @TEST-EXEC: TEST_DIFF_CANONIFIER="grep -v -e 'load-balancing.zeek.*deprecated script loaded' | $SCRIPTS/diff-remove-abspath | $SCRIPTS/diff-sort" btest-diff errors +# @TEST-EXEC: TEST_DIFF_CANONIFIER="grep -v -e 'load-balancing.zeek.*deprecated script loaded' | grep -v -e 'prometheus.zeek.*deprecated script loaded' | $SCRIPTS/diff-remove-abspath | $SCRIPTS/diff-sort" btest-diff errors diff --git a/testing/btest/coverage/test-all-policy-cluster.test b/testing/btest/coverage/test-all-policy-cluster.test index b213b1ac26..9d88868063 100644 --- a/testing/btest/coverage/test-all-policy-cluster.test +++ b/testing/btest/coverage/test-all-policy-cluster.test @@ -9,7 +9,7 @@ # @TEST-EXEC: CLUSTER_NODE=logger-1 zeek %INPUT # @TEST-EXEC: CLUSTER_NODE=proxy-1 zeek %INPUT # @TEST-EXEC: CLUSTER_NODE=worker-1 zeek %INPUT -# @TEST-EXEC: TEST_DIFF_CANONIFIER='grep -v "load-balancing.zeek.*deprecated script" | $SCRIPTS/diff-remove-abspath' btest-diff .stderr +# @TEST-EXEC: TEST_DIFF_CANONIFIER='grep -v "load-balancing.zeek.*deprecated script" | grep -v "prometheus.zeek.*deprecated script" | $SCRIPTS/diff-remove-abspath' btest-diff .stderr @load base/frameworks/cluster @load misc/loaded-scripts diff --git a/testing/btest/scripts/policy/frameworks/telemetry/prometheus.zeek b/testing/btest/scripts/policy/frameworks/telemetry/prometheus.zeek index 0d6e7794b0..50a6fd8d2c 100644 --- a/testing/btest/scripts/policy/frameworks/telemetry/prometheus.zeek +++ b/testing/btest/scripts/policy/frameworks/telemetry/prometheus.zeek @@ -55,7 +55,6 @@ done @TEST-END-FILE @load policy/frameworks/cluster/experimental -@load policy/frameworks/telemetry/prometheus @load base/frameworks/telemetry # So the cluster nodes don't terminate right away. From f500c424fe184c3a3ea6456214c437a1577f84ef Mon Sep 17 00:00:00 2001 From: Tim Wojtulewicz Date: Mon, 22 Jul 2024 14:59:17 -0700 Subject: [PATCH 19/19] Update broker submodule [nomail] --- auxil/broker | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/auxil/broker b/auxil/broker index 4d19d25dc9..4348515873 160000 --- a/auxil/broker +++ b/auxil/broker @@ -1 +1 @@ -Subproject commit 4d19d25dc9b3d6b89ea16ae14e1100f10d156551 +Subproject commit 4348515873b4d1b0e44c7344011b18d21411accf