diff options
author | Daniel Baumann <daniel.baumann@progress-linux.org> | 2024-04-19 17:39:49 +0000 |
---|---|---|
committer | Daniel Baumann <daniel.baumann@progress-linux.org> | 2024-04-19 17:39:49 +0000 |
commit | a0aa2307322cd47bbf416810ac0292925e03be87 (patch) | |
tree | 37076262a026c4b48c8a0e84f44ff9187556ca35 /src/detect-app-layer-event.c | |
parent | Initial commit. (diff) | |
download | suricata-a0aa2307322cd47bbf416810ac0292925e03be87.tar.xz suricata-a0aa2307322cd47bbf416810ac0292925e03be87.zip |
Adding upstream version 1:7.0.3.upstream/1%7.0.3
Signed-off-by: Daniel Baumann <daniel.baumann@progress-linux.org>
Diffstat (limited to 'src/detect-app-layer-event.c')
-rw-r--r-- | src/detect-app-layer-event.c | 314 |
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); +} |