From: Michael Tremer Date: Wed, 22 Oct 2025 20:23:00 +0000 (+0000) Subject: sources: Collect metrics from suricata X-Git-Url: http://git.ipfire.org/cgi-bin/gitweb.cgi?a=commitdiff_plain;h=9eecf65ea51cdbd9c85e5dffdd391594307af40c;p=telemetry.git sources: Collect metrics from suricata Signed-off-by: Michael Tremer --- diff --git a/Makefile.am b/Makefile.am index 3e9ae76..33ef466 100644 --- a/Makefile.am +++ b/Makefile.am @@ -175,6 +175,8 @@ dist_telemetryd_SOURCES = \ src/daemon/sources/processor.h \ src/daemon/sources/softirq.c \ src/daemon/sources/softirq.h \ + src/daemon/sources/suricata.c \ + src/daemon/sources/suricata.h \ src/daemon/sources/test-error.c \ src/daemon/sources/test-error.h \ src/daemon/sources/test-flapping.c \ diff --git a/src/daemon/sources.c b/src/daemon/sources.c index 90d024f..da920ee 100644 --- a/src/daemon/sources.c +++ b/src/daemon/sources.c @@ -42,6 +42,7 @@ #include "sources/pressure-memory.h" #include "sources/processor.h" #include "sources/softirq.h" +#include "sources/suricata.h" #include "sources/unbound.h" #include "sources/uptime.h" @@ -67,6 +68,7 @@ static const td_source_impl* source_impls[] = { &pressure_memory_source, &processor_source, &softirq_source, + &suricata_source, &unbound_source, &uptime_source, diff --git a/src/daemon/sources/suricata.c b/src/daemon/sources/suricata.c new file mode 100644 index 0000000..e317566 --- /dev/null +++ b/src/daemon/sources/suricata.c @@ -0,0 +1,213 @@ +/*############################################################################# +# # +# telemetryd - The IPFire Telemetry Collection Service # +# Copyright (C) 2025 IPFire Development Team # +# # +# This program is free software: you can redistribute it and/or modify # +# it under the terms of the GNU General Public License as published by # +# the Free Software Foundation, either version 3 of the License, or # +# (at your option) any later version. # +# # +# This program is distributed in the hope that it will be useful, # +# but WITHOUT ANY WARRANTY; without even the implied warranty of # +# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the # +# GNU General Public License for more details. # +# # +# You should have received a copy of the GNU General Public License # +# along with this program. If not, see . # +# # +#############################################################################*/ + +#include + +#include + +#include "../command.h" +#include "../ctx.h" +#include "../source.h" +#include "../string.h" +#include "suricata.h" + +static int suricata_check_result(td_ctx* ctx, sd_json_variant* json) { + sd_json_variant* ret = NULL; + const char* value = NULL; + + // Fetch the value of "return" + ret = sd_json_variant_by_key(json, "return"); + if (!ret) { + ERROR(ctx, "JSON response does not have a \"return\" field\n"); + return -EBADMSG; + } + + // Fetch the value of "return" + value = sd_json_variant_string(ret); + if (!value) + return -EBADMSG; + + // Check if the value says "OK" + if (!td_string_equals(value, "OK")) + return -EBADMSG; + + return 0; +} + +static int suricata_parse_uptime(td_ctx* ctx, td_metrics* metrics, sd_json_variant* json) { + sd_json_variant* uptime = NULL; + uint64_t value = 0; + + // Fetch the uptime + uptime = sd_json_variant_by_key(json, "uptime"); + if (!uptime) + return 0; + + // Fetch the value + value = sd_json_variant_unsigned(uptime); + + // Submit the value + return td_metrics_push_uint64(metrics, "uptime", value); +} + +static int suricata_parse_decoder(td_ctx* ctx, td_metrics* metrics, sd_json_variant* json) { + sd_json_variant* decoder = NULL; + sd_json_variant* bytes = NULL; + sd_json_variant* pkts = NULL; + uint64_t value = 0; + int r; + + // Fetch the decoder object + decoder = sd_json_variant_by_key(json, "decoder"); + if (!decoder) + return 0; + + // Fetch pkts + pkts = sd_json_variant_by_key(decoder, "pkts"); + if (pkts) { + // Fetch the value + value = sd_json_variant_unsigned(pkts); + + // Submit value + r = td_metrics_push_uint64(metrics, "decoder_pkts", value); + if (r < 0) + return r; + } + + // Fetch bytes + bytes = sd_json_variant_by_key(decoder, "bytes"); + if (bytes) { + // Fetch the value + value = sd_json_variant_unsigned(bytes); + + // Submit value + r = td_metrics_push_uint64(metrics, "decoder_bytes", value); + if (r < 0) + return r; + } + + return 0; +} + + +static int suricata_parse_message(td_ctx* ctx, td_metrics* metrics, sd_json_variant* json) { + sd_json_variant* msg = NULL; + int r; + + // Fetch the message + msg = sd_json_variant_by_key(json, "message"); + if (!msg) { + ERROR(ctx, "JSON response does not have a \"message\" field\n"); + return -EBADMSG; + } + + // Parse the uptime + r = suricata_parse_uptime(ctx, metrics, msg); + if (r < 0) + return r; + + // Parse the decoder + r = suricata_parse_decoder(ctx, metrics, msg); + if (r < 0) + return r; + + return 0; +} + +static int suricata_on_success(td_ctx* ctx, int rc, td_file* stdout, void* data) { + sd_json_variant* json = NULL; + td_metrics* metrics = NULL; + td_source* source = data; + int r; + + // Parse the output as JSON + r = td_file_parse_json(stdout, &json, 0); + if (r < 0) + goto ERROR; + + // Check the result + r = suricata_check_result(ctx, json); + if (r < 0) + goto ERROR; + + // Create a new metrics object + r = td_source_create_metrics(source, &metrics, NULL); + if (r < 0) + goto ERROR; + + // Parse the message + r = suricata_parse_message(ctx, metrics, json); + if (r < 0) + goto ERROR; + + // Submit all collected metrics + r = td_source_submit_metrics(source, metrics); + +ERROR: + if (json) + sd_json_variant_unref(json); + if (metrics) + td_metrics_unref(metrics); + + return r; +} + +static int suricata_heartbeat(td_ctx* ctx, td_source* source) { + td_command* command = NULL; + int r; + + // Run suricatasc to fetch all counters + const char* argv[] = { "suricatasc", "--command=dump-counters", NULL }; + + // Create a new command + r = td_source_create_command(source, &command); + if (r < 0) + goto ERROR; + + // Register the success callback + td_command_on_success(command, suricata_on_success, source); + + // Execute the command + r = td_command_execute(command, argv); + +ERROR: + if (command) + td_command_unref(command); + + return r; +} + +const td_source_impl suricata_source = { + .name = "suricata", + + // RRD Data Sources + .rrd_dss = { + { "uptime", "COUNTER", 0, -1, }, + + // Decoder + { "decoder_pkts", "DERIVE", 0, -1, }, + { "decoder_bytes", "DERIVE", 0, -1, }, + + { NULL }, + }, + + // Methods + .heartbeat = suricata_heartbeat, +}; diff --git a/src/daemon/sources/suricata.h b/src/daemon/sources/suricata.h new file mode 100644 index 0000000..bdf9295 --- /dev/null +++ b/src/daemon/sources/suricata.h @@ -0,0 +1,28 @@ +/*############################################################################# +# # +# telemetryd - The IPFire Telemetry Collection Service # +# Copyright (C) 2025 IPFire Development Team # +# # +# This program is free software: you can redistribute it and/or modify # +# it under the terms of the GNU General Public License as published by # +# the Free Software Foundation, either version 3 of the License, or # +# (at your option) any later version. # +# # +# This program is distributed in the hope that it will be useful, # +# but WITHOUT ANY WARRANTY; without even the implied warranty of # +# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the # +# GNU General Public License for more details. # +# # +# You should have received a copy of the GNU General Public License # +# along with this program. If not, see . # +# # +#############################################################################*/ + +#ifndef TELEMETRY_SOURCE_SURICATA_H +#define TELEMETRY_SOURCE_SURICATA_H + +#include "../source.h" + +extern const td_source_impl suricata_source; + +#endif /* TELEMETRY_SOURCE_SURICATA_H */