summaryrefslogtreecommitdiffstats
path: root/src/detect-app-layer-event.c
diff options
context:
space:
mode:
Diffstat (limited to 'src/detect-app-layer-event.c')
-rw-r--r--src/detect-app-layer-event.c314
1 files changed, 314 insertions, 0 deletions
diff --git a/src/detect-app-layer-event.c b/src/detect-app-layer-event.c
new file mode 100644
index 0000000..bf306d3
--- /dev/null
+++ b/src/detect-app-layer-event.c
@@ -0,0 +1,314 @@
+/* Copyright (C) 2007-2023 Open Information Security Foundation
+ *
+ * You can copy, redistribute or modify this Program under the terms of
+ * the GNU General Public License version 2 as published by the Free
+ * Software Foundation.
+ *
+ * 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
+ * version 2 along with this program; if not, write to the Free Software
+ * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA
+ * 02110-1301, USA.
+ */
+
+/**
+ * \file
+ *
+ * \author Anoop Saldanha <anoopsaldanha@gmail.com>
+ */
+
+#include "suricata-common.h"
+#include "threads.h"
+#include "decode.h"
+
+#include "app-layer.h"
+#include "app-layer-protos.h"
+#include "app-layer-parser.h"
+#include "app-layer-smtp.h"
+#include "detect.h"
+#include "detect-parse.h"
+#include "detect-engine.h"
+#include "detect-engine-state.h"
+#include "detect-engine-build.h"
+#include "detect-app-layer-event.h"
+
+#include "flow.h"
+#include "flow-var.h"
+#include "flow-util.h"
+
+#include "decode-events.h"
+#include "util-byte.h"
+#include "util-debug.h"
+#include "util-enum.h"
+#include "util-profiling.h"
+#include "util-unittest.h"
+#include "util-unittest-helper.h"
+#include "stream-tcp-util.h"
+
+#define MAX_ALPROTO_NAME 50
+
+typedef struct DetectAppLayerEventData_ {
+ AppProto alproto;
+ uint8_t event_id;
+} DetectAppLayerEventData;
+
+static int DetectAppLayerEventPktMatch(DetectEngineThreadCtx *det_ctx,
+ Packet *p, const Signature *s, const SigMatchCtx *ctx);
+static int DetectAppLayerEventSetup(DetectEngineCtx *, Signature *, const char *);
+static void DetectAppLayerEventFree(DetectEngineCtx *, void *);
+static uint8_t DetectEngineAptEventInspect(DetectEngineCtx *de_ctx, DetectEngineThreadCtx *det_ctx,
+ const struct DetectEngineAppInspectionEngine_ *engine, const Signature *s, Flow *f,
+ uint8_t flags, void *alstate, void *tx, uint64_t tx_id);
+static int g_applayer_events_list_id = 0;
+
+/**
+ * \brief Registers the keyword handlers for the "app-layer-event" keyword.
+ */
+void DetectAppLayerEventRegister(void)
+{
+ sigmatch_table[DETECT_AL_APP_LAYER_EVENT].name = "app-layer-event";
+ sigmatch_table[DETECT_AL_APP_LAYER_EVENT].desc = "match on events generated by the App Layer Parsers and the protocol detection engine";
+ sigmatch_table[DETECT_AL_APP_LAYER_EVENT].url = "/rules/app-layer.html#app-layer-event";
+ sigmatch_table[DETECT_AL_APP_LAYER_EVENT].Match =
+ DetectAppLayerEventPktMatch;
+ sigmatch_table[DETECT_AL_APP_LAYER_EVENT].Setup = DetectAppLayerEventSetup;
+ sigmatch_table[DETECT_AL_APP_LAYER_EVENT].Free = DetectAppLayerEventFree;
+
+ DetectAppLayerInspectEngineRegister2("app-layer-events", ALPROTO_UNKNOWN, SIG_FLAG_TOSERVER, 0,
+ DetectEngineAptEventInspect, NULL);
+ DetectAppLayerInspectEngineRegister2("app-layer-events", ALPROTO_UNKNOWN, SIG_FLAG_TOCLIENT, 0,
+ DetectEngineAptEventInspect, NULL);
+
+ g_applayer_events_list_id = DetectBufferTypeGetByName("app-layer-events");
+}
+
+static uint8_t DetectEngineAptEventInspect(DetectEngineCtx *de_ctx, DetectEngineThreadCtx *det_ctx,
+ const struct DetectEngineAppInspectionEngine_ *engine, const Signature *s, Flow *f,
+ uint8_t flags, void *alstate, void *tx, uint64_t tx_id)
+{
+ int r = 0;
+ const AppProto alproto = f->alproto;
+ AppLayerDecoderEvents *decoder_events =
+ AppLayerParserGetEventsByTx(f->proto, alproto, tx);
+ if (decoder_events == NULL) {
+ goto end;
+ }
+ SigMatchData *smd = engine->smd;
+ while (1) {
+ DetectAppLayerEventData *aled = (DetectAppLayerEventData *)smd->ctx;
+ KEYWORD_PROFILING_START;
+
+ if (AppLayerDecoderEventsIsEventSet(decoder_events, aled->event_id)) {
+ KEYWORD_PROFILING_END(det_ctx, smd->type, 1);
+
+ if (smd->is_last)
+ break;
+ smd++;
+ continue;
+ }
+
+ KEYWORD_PROFILING_END(det_ctx, smd->type, 0);
+ goto end;
+ }
+
+ r = 1;
+
+ end:
+ if (r == 1) {
+ return DETECT_ENGINE_INSPECT_SIG_MATCH;
+ } else {
+ if (AppLayerParserGetStateProgress(f->proto, alproto, tx, flags) ==
+ AppLayerParserGetStateProgressCompletionStatus(alproto, flags))
+ {
+ return DETECT_ENGINE_INSPECT_SIG_CANT_MATCH;
+ } else {
+ return DETECT_ENGINE_INSPECT_SIG_NO_MATCH;
+ }
+ }
+}
+
+
+static int DetectAppLayerEventPktMatch(DetectEngineThreadCtx *det_ctx,
+ Packet *p, const Signature *s, const SigMatchCtx *ctx)
+{
+ const DetectAppLayerEventData *aled = (const DetectAppLayerEventData *)ctx;
+
+ return AppLayerDecoderEventsIsEventSet(p->app_layer_events,
+ aled->event_id);
+}
+
+static DetectAppLayerEventData *DetectAppLayerEventParsePkt(const char *arg,
+ AppLayerEventType *event_type)
+{
+ int event_id = 0;
+ int r = AppLayerGetPktEventInfo(arg, &event_id);
+ if (r < 0 || r > UINT8_MAX) {
+ SCLogError("app-layer-event keyword "
+ "supplied with packet based event - \"%s\" that isn't "
+ "supported yet.",
+ arg);
+ return NULL;
+ }
+
+ DetectAppLayerEventData *aled = SCCalloc(1, sizeof(DetectAppLayerEventData));
+ if (unlikely(aled == NULL))
+ return NULL;
+ aled->event_id = (uint8_t)event_id;
+ *event_type = APP_LAYER_EVENT_TYPE_PACKET;
+
+ return aled;
+}
+
+static bool OutdatedEvent(const char *raw)
+{
+ if (strcmp(raw, "tls.certificate_missing_element") == 0 ||
+ strcmp(raw, "tls.certificate_unknown_element") == 0 ||
+ strcmp(raw, "tls.certificate_invalid_string") == 0) {
+ return true;
+ }
+ return false;
+}
+
+static AppProto AppLayerEventGetProtoByName(char *alproto_name)
+{
+ AppProto alproto = AppLayerGetProtoByName(alproto_name);
+ if (alproto == ALPROTO_HTTP) {
+ // app-layer events http refer to http1
+ alproto = ALPROTO_HTTP1;
+ }
+ return alproto;
+}
+
+static int DetectAppLayerEventSetup(DetectEngineCtx *de_ctx, Signature *s, const char *arg)
+{
+ if (arg == NULL) {
+ SCLogError("app-layer-event keyword supplied "
+ "with no arguments. This keyword needs an argument.");
+ return -1;
+ }
+
+ while (*arg != '\0' && isspace((unsigned char)*arg))
+ arg++;
+
+ AppLayerEventType event_type;
+ DetectAppLayerEventData *data = NULL;
+
+ if (strchr(arg, '.') == NULL) {
+ data = DetectAppLayerEventParsePkt(arg, &event_type);
+ if (data == NULL)
+ return -1;
+ } else {
+ SCLogDebug("parsing %s", arg);
+ char alproto_name[MAX_ALPROTO_NAME];
+ bool needs_detctx = false;
+
+ const char *p_idx = strchr(arg, '.');
+ if (strlen(arg) > MAX_ALPROTO_NAME) {
+ SCLogError("app-layer-event keyword is too long or malformed");
+ return -1;
+ }
+ const char *event_name = p_idx + 1; // skip .
+ /* + 1 for trailing \0 */
+ strlcpy(alproto_name, arg, p_idx - arg + 1);
+
+ const AppProto alproto = AppLayerEventGetProtoByName(alproto_name);
+ if (alproto == ALPROTO_UNKNOWN) {
+ if (!strcmp(alproto_name, "file")) {
+ needs_detctx = true;
+ } else {
+ SCLogError("app-layer-event keyword "
+ "supplied with unknown protocol \"%s\"",
+ alproto_name);
+ return -1;
+ }
+ }
+ if (OutdatedEvent(arg)) {
+ if (SigMatchStrictEnabled(DETECT_AL_APP_LAYER_EVENT)) {
+ SCLogError("app-layer-event keyword no longer supports event \"%s\"", arg);
+ return -1;
+ } else {
+ SCLogWarning("app-layer-event keyword no longer supports event \"%s\"", arg);
+ return -3;
+ }
+ }
+
+ uint8_t ipproto = 0;
+ if (s->proto.proto[IPPROTO_TCP / 8] & 1 << (IPPROTO_TCP % 8)) {
+ ipproto = IPPROTO_TCP;
+ } else if (s->proto.proto[IPPROTO_UDP / 8] & 1 << (IPPROTO_UDP % 8)) {
+ ipproto = IPPROTO_UDP;
+ } else {
+ SCLogError("protocol %s is disabled", alproto_name);
+ return -1;
+ }
+
+ int r;
+ int event_id = 0;
+ if (!needs_detctx) {
+ r = AppLayerParserGetEventInfo(ipproto, alproto, event_name, &event_id, &event_type);
+ } else {
+ r = DetectEngineGetEventInfo(event_name, &event_id, &event_type);
+ }
+ if (r < 0) {
+ if (SigMatchStrictEnabled(DETECT_AL_APP_LAYER_EVENT)) {
+ SCLogError("app-layer-event keyword's "
+ "protocol \"%s\" doesn't have event \"%s\" registered",
+ alproto_name, event_name);
+ return -1;
+ } else {
+ SCLogWarning("app-layer-event keyword's "
+ "protocol \"%s\" doesn't have event \"%s\" registered",
+ alproto_name, event_name);
+ return -3;
+ }
+ }
+ if (event_id > UINT8_MAX) {
+ SCLogWarning("app-layer-event keyword's id has invalid value");
+ return -4;
+ }
+ data = SCCalloc(1, sizeof(*data));
+ if (unlikely(data == NULL))
+ return -1;
+ data->alproto = alproto;
+ data->event_id = (uint8_t)event_id;
+ }
+ SCLogDebug("data->event_id %u", data->event_id);
+
+ SigMatch *sm = SigMatchAlloc();
+ if (sm == NULL)
+ goto error;
+
+ sm->type = DETECT_AL_APP_LAYER_EVENT;
+ sm->ctx = (SigMatchCtx *)data;
+
+ if (event_type == APP_LAYER_EVENT_TYPE_PACKET) {
+ SigMatchAppendSMToList(s, sm, DETECT_SM_LIST_MATCH);
+ } else {
+ if (DetectSignatureSetAppProto(s, data->alproto) != 0)
+ goto error;
+
+ SigMatchAppendSMToList(s, sm, g_applayer_events_list_id);
+ s->flags |= SIG_FLAG_APPLAYER;
+ }
+
+ return 0;
+
+error:
+ if (data) {
+ DetectAppLayerEventFree(de_ctx, data);
+ }
+ if (sm) {
+ sm->ctx = NULL;
+ SigMatchFree(de_ctx, sm);
+ }
+ return -1;
+}
+
+static void DetectAppLayerEventFree(DetectEngineCtx *de_ctx, void *ptr)
+{
+ SCFree(ptr);
+}