From 98e11ced4b5b5b976efaf7aa2e3320236e524415 Mon Sep 17 00:00:00 2001 From: Philippe Antoine Date: Fri, 5 Apr 2024 13:37:46 +0200 Subject: [PATCH 1/6] detect: helper function for multibuffer --- src/detect-engine-helper.c | 26 ++++++++++++++++++++++++++ src/detect-engine-helper.h | 6 ++++++ src/detect-http2.c | 26 ++------------------------ 3 files changed, 34 insertions(+), 24 deletions(-) diff --git a/src/detect-engine-helper.c b/src/detect-engine-helper.c index 0b7c9ccb2077..b81c5cb424be 100644 --- a/src/detect-engine-helper.c +++ b/src/detect-engine-helper.c @@ -28,6 +28,7 @@ #include "detect-engine-mpm.h" #include "detect-engine-prefilter.h" #include "detect-parse.h" +#include "detect-engine-content-inspection.h" int DetectHelperBufferRegister(const char *name, AppProto alproto, bool toclient, bool toserver) { @@ -105,3 +106,28 @@ int DetectHelperKeywordRegister(const SCSigTableElmt *kw) DETECT_TBLSIZE_IDX++; return DETECT_TBLSIZE_IDX - 1; } + +InspectionBuffer *DetectHelperGetMultiData(struct DetectEngineThreadCtx_ *det_ctx, + const DetectEngineTransforms *transforms, Flow *f, const uint8_t flow_flags, void *txv, + const int list_id, uint32_t index, + bool (*GetBuf)(void *txv, const uint8_t flow_flags, uint32_t index, const uint8_t **buf, uint32_t *buf_len)) +{ + InspectionBuffer *buffer = InspectionBufferMultipleForListGet(det_ctx, list_id, index); + if (buffer == NULL) { + return NULL; + } + if (buffer->initialized) { + return buffer; + } + + const uint8_t *data = NULL; + uint32_t data_len = 0; + + if (!GetBuf(txv, flow_flags, index, &data, &data_len)) { + InspectionBufferSetupMultiEmpty(buffer); + return NULL; + } + InspectionBufferSetupMulti(buffer, transforms, data, data_len); + buffer->flags = DETECT_CI_FLAGS_SINGLE; + return buffer; +} diff --git a/src/detect-engine-helper.h b/src/detect-engine-helper.h index bd8fe6cce5a6..5a2c49e1b059 100644 --- a/src/detect-engine-helper.h +++ b/src/detect-engine-helper.h @@ -32,10 +32,16 @@ int DetectHelperKeywordRegister(const SCSigTableElmt *kw); int DetectHelperBufferRegister(const char *name, AppProto alproto, bool toclient, bool toserver); typedef bool (*SimpleGetTxBuffer)(void *, uint8_t, const uint8_t **, uint32_t *); +typedef bool (*MultiGetTxBuffer)(void *, uint8_t, uint32_t, const uint8_t **, uint32_t *); + InspectionBuffer *DetectHelperGetData(struct DetectEngineThreadCtx_ *det_ctx, const DetectEngineTransforms *transforms, Flow *f, const uint8_t flow_flags, void *txv, const int list_id, SimpleGetTxBuffer GetBuf); int DetectHelperBufferMpmRegister(const char *name, const char *desc, AppProto alproto, bool toclient, bool toserver, InspectionBufferGetDataPtr GetData); +InspectionBuffer *DetectHelperGetMultiData(struct DetectEngineThreadCtx_ *det_ctx, + const DetectEngineTransforms *transforms, Flow *f, const uint8_t flow_flags, void *txv, + const int list_id, uint32_t index, MultiGetTxBuffer GetBuf); + #endif /* SURICATA_DETECT_ENGINE_HELPER_H */ diff --git a/src/detect-http2.c b/src/detect-http2.c index 113fb1af3f06..cf27f2fe2ce2 100644 --- a/src/detect-http2.c +++ b/src/detect-http2.c @@ -33,6 +33,7 @@ #include "detect-engine-mpm.h" #include "detect-engine-prefilter.h" #include "detect-engine-content-inspection.h" +#include "detect-engine-helper.h" #include "detect-http2.h" #include "util-byte.h" @@ -102,30 +103,7 @@ static InspectionBuffer *GetHttp2HNameData(DetectEngineThreadCtx *det_ctx, const DetectEngineTransforms *transforms, Flow *_f, const uint8_t flags, void *txv, int list_id, uint32_t local_id) { - SCEnter(); - - InspectionBuffer *buffer = InspectionBufferMultipleForListGet(det_ctx, list_id, local_id); - if (buffer == NULL) - return NULL; - if (buffer->initialized) - return buffer; - - uint32_t b_len = 0; - const uint8_t *b = NULL; - - if (rs_http2_tx_get_header_name(txv, flags, local_id, &b, &b_len) != 1) { - InspectionBufferSetupMultiEmpty(buffer); - return NULL; - } - if (b == NULL || b_len == 0) { - InspectionBufferSetupMultiEmpty(buffer); - return NULL; - } - - InspectionBufferSetupMulti(buffer, transforms, b, b_len); - buffer->flags = DETECT_CI_FLAGS_SINGLE; - - SCReturnPtr(buffer, "InspectionBuffer"); + return DetectHelperGetMultiData(det_ctx, transforms, _f, flags, txv, list_id, local_id, (MultiGetTxBuffer) rs_http2_tx_get_header_name); } void DetectHttp2Register(void) From 61ae15422947a12274eed59fadcfa5f4d256c11f Mon Sep 17 00:00:00 2001 From: Philippe Antoine Date: Thu, 16 Nov 2023 14:26:36 +0100 Subject: [PATCH 2/6] app-layer: allow at compile-time more app-layer So that we can have dynamically registered protocols. Doing it at compile time, with CFLAGS=-DALPROTO_DYNAMIC_NB=1, allows to keep the rest of the code using ALPROTO_MAX Ticket: 5053 --- rust/src/core.rs | 7 ++++ src/app-layer-detect-proto.c | 4 +-- src/app-layer-protos.c | 19 +++++++++-- src/app-layer-protos.h | 14 +++++--- src/app-layer.c | 63 +++++++++++++++++------------------- src/output.c | 2 +- 6 files changed, 67 insertions(+), 42 deletions(-) diff --git a/rust/src/core.rs b/rust/src/core.rs index abb27ea578fe..5d8de0ce1c77 100644 --- a/rust/src/core.rs +++ b/rust/src/core.rs @@ -253,6 +253,13 @@ pub extern "C" fn rs_init(context: &'static SuricataContext) init_ffi(context); } +#[no_mangle] +pub extern "C" fn rs_update_alproto_failed(alproto: AppProto) { + unsafe { + ALPROTO_FAILED = alproto; + } +} + /// DetectEngineStateFree wrapper. pub fn sc_detect_engine_state_free(state: *mut DetectEngineState) { diff --git a/src/app-layer-detect-proto.c b/src/app-layer-detect-proto.c index 68fca345f714..e80998f2960c 100644 --- a/src/app-layer-detect-proto.c +++ b/src/app-layer-detect-proto.c @@ -491,8 +491,8 @@ static inline AppProto PPGetProto(const AppLayerProtoDetectProbingParserElement if (AppProtoIsValid(alproto)) { SCReturnUInt(alproto); } - if (alproto == ALPROTO_FAILED || - (pe->max_depth != 0 && buflen > pe->max_depth)) { + if (alproto == ALPROTO_FAILED || alproto == ALPROTO_INVALID || + (pe->max_depth != 0 && buflen > pe->max_depth)) { alproto_masks[0] |= pe->alproto_mask; } pe = pe->next; diff --git a/src/app-layer-protos.c b/src/app-layer-protos.c index babe6ea83adf..7b1e6e2afb1b 100644 --- a/src/app-layer-protos.c +++ b/src/app-layer-protos.c @@ -24,13 +24,16 @@ #include "suricata-common.h" #include "app-layer-protos.h" +#include "rust.h" + +AppProto ALPROTO_FAILED = ALPROTO_MAX_STATIC; typedef struct AppProtoStringTuple { AppProto alproto; const char *str; } AppProtoStringTuple; -const AppProtoStringTuple AppProtoStrings[ALPROTO_MAX] = { +AppProtoStringTuple AppProtoStrings[ALPROTO_MAX] = { { ALPROTO_UNKNOWN, "unknown" }, { ALPROTO_HTTP1, "http1" }, { ALPROTO_FTP, "ftp" }, @@ -67,10 +70,10 @@ const AppProtoStringTuple AppProtoStrings[ALPROTO_MAX] = { { ALPROTO_BITTORRENT_DHT, "bittorrent-dht" }, { ALPROTO_POP3, "pop3" }, { ALPROTO_HTTP, "http" }, - { ALPROTO_FAILED, "failed" }, #ifdef UNITTESTS { ALPROTO_TEST, "test" }, #endif + { ALPROTO_MAX_STATIC, "failed" }, }; const char *AppProtoToString(AppProto alproto) @@ -106,3 +109,15 @@ AppProto StringToAppProto(const char *proto_name) return ALPROTO_UNKNOWN; } + +void RegisterAppProtoString(AppProto alproto, const char *proto_name) +{ + if (alproto == ALPROTO_FAILED && alproto + 1 < ALPROTO_MAX) { + AppProtoStrings[alproto].str = proto_name; + AppProtoStrings[alproto].alproto = alproto; + ALPROTO_FAILED++; + rs_update_alproto_failed(ALPROTO_FAILED); + AppProtoStrings[ALPROTO_FAILED].str = "failed"; + AppProtoStrings[ALPROTO_FAILED].alproto = ALPROTO_FAILED; + } +} diff --git a/src/app-layer-protos.h b/src/app-layer-protos.h index 00a5a54811e8..37147a0c852e 100644 --- a/src/app-layer-protos.h +++ b/src/app-layer-protos.h @@ -67,20 +67,24 @@ enum AppProtoEnum { // HTTP for any version (ALPROTO_HTTP1 (version 1) or ALPROTO_HTTP2) ALPROTO_HTTP, - /* used by the probing parser when alproto detection fails - * permanently for that particular stream */ - ALPROTO_FAILED, #ifdef UNITTESTS ALPROTO_TEST, #endif /* UNITESTS */ /* keep last */ - ALPROTO_MAX, + ALPROTO_MAX_STATIC, + ALPROTO_INVALID = 0xffff, }; // NOTE: if ALPROTO's get >= 256, update SignatureNonPrefilterStore /* not using the enum as that is a unsigned int, so 4 bytes */ typedef uint16_t AppProto; +extern AppProto ALPROTO_FAILED; +#ifdef ALPROTO_DYNAMIC_NB +#define ALPROTO_MAX (ALPROTO_MAX_STATIC + 1 + ALPROTO_DYNAMIC_NB) +#else +#define ALPROTO_MAX (ALPROTO_MAX_STATIC + 1) +#endif static inline bool AppProtoIsValid(AppProto a) { return ((a > ALPROTO_UNKNOWN && a < ALPROTO_FAILED)); @@ -119,4 +123,6 @@ const char *AppProtoToString(AppProto alproto); */ AppProto StringToAppProto(const char *proto_name); +void RegisterAppProtoString(AppProto alproto, const char *proto_name); + #endif /* SURICATA_APP_LAYER_PROTOS_H */ diff --git a/src/app-layer.c b/src/app-layer.c index 0cf8405eab0e..a7f6bafe056a 100644 --- a/src/app-layer.c +++ b/src/app-layer.c @@ -905,42 +905,39 @@ int AppLayerHandleUdp(ThreadVars *tv, AppLayerThreadCtx *tctx, Packet *p, Flow * tctx->alpd_tctx, f, p->payload, p->payload_len, IPPROTO_UDP, flags, &reverse_flow); PACKET_PROFILING_APP_PD_END(tctx); - switch (*alproto) { - case ALPROTO_UNKNOWN: - if (*alproto_otherdir != ALPROTO_UNKNOWN) { - // Use recognized side - f->alproto = *alproto_otherdir; - // do not keep ALPROTO_UNKNOWN for this side so as not to loop - *alproto = *alproto_otherdir; - if (*alproto_otherdir == ALPROTO_FAILED) { - SCLogDebug("ALPROTO_UNKNOWN flow %p", f); - } - } else { - // First side of protocol is unknown - *alproto = ALPROTO_FAILED; + if (*alproto == ALPROTO_UNKNOWN) { + if (*alproto_otherdir != ALPROTO_UNKNOWN) { + // Use recognized side + f->alproto = *alproto_otherdir; + // do not keep ALPROTO_UNKNOWN for this side so as not to loop + *alproto = *alproto_otherdir; + if (*alproto_otherdir == ALPROTO_FAILED) { + SCLogDebug("ALPROTO_UNKNOWN flow %p", f); } - break; - case ALPROTO_FAILED: - if (*alproto_otherdir != ALPROTO_UNKNOWN) { - // Use recognized side - f->alproto = *alproto_otherdir; - if (*alproto_otherdir == ALPROTO_FAILED) { - SCLogDebug("ALPROTO_UNKNOWN flow %p", f); - } + } else { + // First side of protocol is unknown + *alproto = ALPROTO_FAILED; + } + } else if (*alproto == ALPROTO_FAILED) { + if (*alproto_otherdir != ALPROTO_UNKNOWN) { + // Use recognized side + f->alproto = *alproto_otherdir; + if (*alproto_otherdir == ALPROTO_FAILED) { + SCLogDebug("ALPROTO_UNKNOWN flow %p", f); } - // else wait for second side of protocol - break; - default: - if (*alproto_otherdir != ALPROTO_UNKNOWN && *alproto_otherdir != ALPROTO_FAILED) { - if (*alproto_otherdir != *alproto) { - AppLayerDecoderEventsSetEventRaw( - &p->app_layer_events, APPLAYER_MISMATCH_PROTOCOL_BOTH_DIRECTIONS); - // data already sent to parser, we cannot change the protocol to use the one - // of the server - } - } else { - f->alproto = *alproto; + } + // else wait for second side of protocol + } else { + if (*alproto_otherdir != ALPROTO_UNKNOWN && *alproto_otherdir != ALPROTO_FAILED) { + if (*alproto_otherdir != *alproto) { + AppLayerDecoderEventsSetEventRaw( + &p->app_layer_events, APPLAYER_MISMATCH_PROTOCOL_BOTH_DIRECTIONS); + // data already sent to parser, we cannot change the protocol to use the one + // of the server } + } else { + f->alproto = *alproto; + } } if (*alproto_otherdir == ALPROTO_UNKNOWN) { if (f->alproto == ALPROTO_UNKNOWN) { diff --git a/src/output.c b/src/output.c index df58af4dc8e5..8db87f75af2f 100644 --- a/src/output.c +++ b/src/output.c @@ -1153,10 +1153,10 @@ static EveJsonSimpleAppLayerLogger simple_json_applayer_loggers[ALPROTO_MAX] = { { ALPROTO_BITTORRENT_DHT, rs_bittorrent_dht_logger_log }, { ALPROTO_POP3, NULL }, // protocol detection only { ALPROTO_HTTP, NULL }, // signature protocol, not for app-layer logging - { ALPROTO_FAILED, NULL }, #ifdef UNITTESTS { ALPROTO_TEST, NULL }, #endif /* UNITESTS */ + { ALPROTO_MAX_STATIC, NULL }, }; EveJsonSimpleAppLayerLogger *SCEveJsonSimpleGetLogger(AppProto alproto) From 7a4734cd44a6981b5c045c9f5e85c4b360c78648 Mon Sep 17 00:00:00 2001 From: Philippe Antoine Date: Thu, 16 Nov 2023 14:35:49 +0100 Subject: [PATCH 3/6] plugins: app-layer plugins Ticket: 5053 --- src/app-layer-parser.c | 13 ++++++++ src/app-layer-protos.c | 2 +- src/detect-engine-file.h | 11 +++++++ src/detect-engine-register.c | 13 ++++++++ src/detect-parse.c | 58 ++++++++++++++++++++++-------------- src/output.c | 25 ++++++++++++++++ src/output.h | 1 + src/suricata-plugin.h | 12 ++++++++ src/util-plugin.c | 29 ++++++++++++++++++ src/util-plugin.h | 2 ++ 10 files changed, 142 insertions(+), 24 deletions(-) diff --git a/src/app-layer-parser.c b/src/app-layer-parser.c index 70e4d2af2086..05e47a5f5385 100644 --- a/src/app-layer-parser.c +++ b/src/app-layer-parser.c @@ -55,6 +55,10 @@ #include "app-layer-rfb.h" #include "app-layer-http2.h" +#ifdef ALPROTO_DYNAMIC_NB +#include "util-plugin.h" +#endif + struct AppLayerParserThreadCtx_ { void *alproto_local_storage[FLOW_PROTO_MAX][ALPROTO_MAX]; }; @@ -1776,6 +1780,15 @@ void AppLayerParserRegisterProtocolParsers(void) } else { SCLogInfo("Protocol detection and parser disabled for pop3 protocol."); } +#ifdef ALPROTO_DYNAMIC_NB + for (size_t i = 0; i < ALPROTO_DYNAMIC_NB; i++) { + SCAppLayerPlugin *app_layer_plugin = SCPluginFindAppLayerByIndex(i); + if (app_layer_plugin == NULL) { + break; + } + app_layer_plugin->Register(); + } +#endif ValidateParsers(); } diff --git a/src/app-layer-protos.c b/src/app-layer-protos.c index 7b1e6e2afb1b..6169e6812034 100644 --- a/src/app-layer-protos.c +++ b/src/app-layer-protos.c @@ -103,7 +103,7 @@ AppProto StringToAppProto(const char *proto_name) // We could use a Multi Pattern Matcher for (size_t i = 0; i < ARRAY_SIZE(AppProtoStrings); i++) { - if (strcmp(proto_name, AppProtoStrings[i].str) == 0) + if (AppProtoStrings[i].str != NULL && strcmp(proto_name, AppProtoStrings[i].str) == 0) return AppProtoStrings[i].alproto; } diff --git a/src/detect-engine-file.h b/src/detect-engine-file.h index 13aa7465f436..5907f17e0807 100644 --- a/src/detect-engine-file.h +++ b/src/detect-engine-file.h @@ -28,4 +28,15 @@ uint8_t DetectFileInspectGeneric(DetectEngineCtx *de_ctx, DetectEngineThreadCtx const struct DetectEngineAppInspectionEngine_ *engine, const Signature *s, Flow *f, uint8_t flags, void *_alstate, void *tx, uint64_t tx_id); +// file protocols with common file handling +typedef struct { + AppProto al_proto; + int direction; + int to_client_progress; + int to_server_progress; +} DetectFileHandlerProtocol_t; + +void DetectFileRegisterProto( + AppProto alproto, int direction, int to_client_progress, int to_server_progress); + #endif /* SURICATA_DETECT_ENGINE_FILE_H */ diff --git a/src/detect-engine-register.c b/src/detect-engine-register.c index 5d4438485811..ec4581929b81 100644 --- a/src/detect-engine-register.c +++ b/src/detect-engine-register.c @@ -312,6 +312,7 @@ #include "util-path.h" #include "util-mpm-ac.h" #include "runmodes.h" +#include "util-plugin.h" int DETECT_TBLSIZE = 0; int DETECT_TBLSIZE_IDX = DETECT_TBLSIZE_STATIC; @@ -715,6 +716,18 @@ void SigTableSetup(void) DetectQuicCyuStringRegister(); DetectJa4HashRegister(); +#ifdef ALPROTO_DYNAMIC_NB + for (size_t i = 0; i < ALPROTO_DYNAMIC_NB; i++) { + SCAppLayerPlugin *app_layer_plugin = SCPluginFindAppLayerByIndex(i); + if (app_layer_plugin == NULL) { + break; + } + if (app_layer_plugin->KeywordsRegister != NULL) { + app_layer_plugin->KeywordsRegister(); + } + } +#endif + DetectBypassRegister(); DetectConfigRegister(); diff --git a/src/detect-parse.c b/src/detect-parse.c index 61318521f45d..8577951bf700 100644 --- a/src/detect-parse.c +++ b/src/detect-parse.c @@ -68,6 +68,7 @@ #include "string.h" #include "detect-parse.h" #include "detect-engine-iponly.h" +#include "detect-engine-file.h" #include "app-layer-detect-proto.h" #include "action-globals.h" @@ -76,32 +77,43 @@ /* Table with all filehandler registrations */ DetectFileHandlerTableElmt filehandler_table[DETECT_TBLSIZE_STATIC]; -void DetectFileRegisterFileProtocols(DetectFileHandlerTableElmt *reg) +// file protocols with common file handling +DetectFileHandlerProtocol_t al_protocols[ALPROTO_MAX] = { + { .al_proto = ALPROTO_NFS, .direction = SIG_FLAG_TOSERVER | SIG_FLAG_TOCLIENT }, + { .al_proto = ALPROTO_SMB, .direction = SIG_FLAG_TOSERVER | SIG_FLAG_TOCLIENT }, + { .al_proto = ALPROTO_FTP, .direction = SIG_FLAG_TOSERVER | SIG_FLAG_TOCLIENT }, + { .al_proto = ALPROTO_FTPDATA, .direction = SIG_FLAG_TOSERVER | SIG_FLAG_TOCLIENT }, + { .al_proto = ALPROTO_HTTP1, + .direction = SIG_FLAG_TOSERVER | SIG_FLAG_TOCLIENT, + .to_client_progress = HTP_RESPONSE_BODY, + .to_server_progress = HTP_REQUEST_BODY }, + { .al_proto = ALPROTO_HTTP2, + .direction = SIG_FLAG_TOSERVER | SIG_FLAG_TOCLIENT, + .to_client_progress = HTTP2StateDataServer, + .to_server_progress = HTTP2StateDataClient }, + { .al_proto = ALPROTO_SMTP, .direction = SIG_FLAG_TOSERVER }, { .al_proto = ALPROTO_UNKNOWN } +}; + +void DetectFileRegisterProto( + AppProto alproto, int direction, int to_client_progress, int to_server_progress) { - // file protocols with common file handling - typedef struct { - AppProto al_proto; - int direction; - int to_client_progress; - int to_server_progress; - } DetectFileHandlerProtocol_t; - static DetectFileHandlerProtocol_t al_protocols[] = { - { .al_proto = ALPROTO_NFS, .direction = SIG_FLAG_TOSERVER | SIG_FLAG_TOCLIENT }, - { .al_proto = ALPROTO_SMB, .direction = SIG_FLAG_TOSERVER | SIG_FLAG_TOCLIENT }, - { .al_proto = ALPROTO_FTP, .direction = SIG_FLAG_TOSERVER | SIG_FLAG_TOCLIENT }, - { .al_proto = ALPROTO_FTPDATA, .direction = SIG_FLAG_TOSERVER | SIG_FLAG_TOCLIENT }, - { .al_proto = ALPROTO_HTTP1, - .direction = SIG_FLAG_TOSERVER | SIG_FLAG_TOCLIENT, - .to_client_progress = HTP_RESPONSE_BODY, - .to_server_progress = HTP_REQUEST_BODY }, - { .al_proto = ALPROTO_HTTP2, - .direction = SIG_FLAG_TOSERVER | SIG_FLAG_TOCLIENT, - .to_client_progress = HTTP2StateDataServer, - .to_server_progress = HTTP2StateDataClient }, - { .al_proto = ALPROTO_SMTP, .direction = SIG_FLAG_TOSERVER } - }; + size_t i = 0; + while (al_protocols[i].al_proto != ALPROTO_UNKNOWN) { + i++; + } + al_protocols[i].al_proto = alproto; + al_protocols[i].direction = direction; + al_protocols[i].to_client_progress = to_client_progress; + al_protocols[i].to_server_progress = to_server_progress; + al_protocols[i + 1].al_proto = ALPROTO_UNKNOWN; +} +void DetectFileRegisterFileProtocols(DetectFileHandlerTableElmt *reg) +{ for (size_t i = 0; i < ARRAY_SIZE(al_protocols); i++) { + if (al_protocols[i].al_proto == ALPROTO_UNKNOWN) { + break; + } int direction = al_protocols[i].direction == 0 ? (int)(SIG_FLAG_TOSERVER | SIG_FLAG_TOCLIENT) : al_protocols[i].direction; diff --git a/src/output.c b/src/output.c index 8db87f75af2f..60f10530ffb5 100644 --- a/src/output.c +++ b/src/output.c @@ -82,6 +82,7 @@ #include "app-layer-parser.h" #include "output-filestore.h" #include "output-json-arp.h" +#include "util-plugin.h" typedef struct RootLogger_ { OutputLogFunc LogFunc; @@ -1114,6 +1115,22 @@ void OutputRegisterLoggers(void) } /* ARP JSON logger */ JsonArpLogRegister(); +#ifdef ALPROTO_DYNAMIC_NB + for (size_t i = 0; i < ALPROTO_DYNAMIC_NB; i++) { + SCAppLayerPlugin *app_layer_plugin = SCPluginFindAppLayerByIndex(i); + if (app_layer_plugin == NULL) { + break; + } + + OutputRegisterTxSubModule(LOGGER_JSON_TX, "eve-log", app_layer_plugin->logname, + app_layer_plugin->confname, OutputJsonLogInitSub, + (AppProto)(ALPROTO_MAX_STATIC + i), JsonGenericDirFlowLogger, JsonLogThreadInit, + JsonLogThreadDeinit, NULL); + SCLogNotice("%s JSON logger registered.", app_layer_plugin->name); + RegisterAppProtoAppLayerLogger((AppProto)(ALPROTO_MAX_STATIC + i), + (EveJsonSimpleTxLogFunc) app_layer_plugin->Logger); + } +#endif } static EveJsonSimpleAppLayerLogger simple_json_applayer_loggers[ALPROTO_MAX] = { @@ -1167,3 +1184,11 @@ EveJsonSimpleAppLayerLogger *SCEveJsonSimpleGetLogger(AppProto alproto) } return NULL; } + +void RegisterAppProtoAppLayerLogger(AppProto alproto, EveJsonSimpleTxLogFunc log) +{ + if (alproto < ALPROTO_MAX) { + simple_json_applayer_loggers[alproto].proto = alproto; + simple_json_applayer_loggers[alproto].LogTx = log; + } +} diff --git a/src/output.h b/src/output.h index 6c477547e66f..399d6dc0a5c3 100644 --- a/src/output.h +++ b/src/output.h @@ -197,5 +197,6 @@ typedef struct EveJsonSimpleAppLayerLogger { } EveJsonSimpleAppLayerLogger; EveJsonSimpleAppLayerLogger *SCEveJsonSimpleGetLogger(AppProto alproto); +void RegisterAppProtoAppLayerLogger(AppProto alproto, EveJsonSimpleTxLogFunc log); #endif /* ! SURICATA_OUTPUT_H */ diff --git a/src/suricata-plugin.h b/src/suricata-plugin.h index 639dd7c7313e..b3c7bd074d0e 100644 --- a/src/suricata-plugin.h +++ b/src/suricata-plugin.h @@ -52,4 +52,16 @@ typedef struct SCCapturePlugin_ { int SCPluginRegisterCapture(SCCapturePlugin *); +typedef struct SCAppLayerPlugin_ { + char *name; + char *logname; + char *confname; + void (*Register)(void); + bool (*Logger)(void *tx, void *jb); + void (*KeywordsRegister)(void); + uint32_t keywords_nb; +} SCAppLayerPlugin; + +int SCPluginRegisterAppLayer(SCAppLayerPlugin *); + #endif /* __SURICATA_PLUGIN_H */ diff --git a/src/util-plugin.c b/src/util-plugin.c index 7a9b467daaac..73ae23d7e58a 100644 --- a/src/util-plugin.c +++ b/src/util-plugin.c @@ -22,6 +22,7 @@ #include "util-plugin.h" #include "util-debug.h" #include "conf.h" +#include "app-layer-protos.h" #ifdef HAVE_PLUGINS @@ -148,4 +149,32 @@ SCCapturePlugin *SCPluginFindCaptureByName(const char *name) } return plugin; } + +#ifdef ALPROTO_DYNAMIC_NB +static SCAppLayerPlugin *app_layer_plugins[ALPROTO_DYNAMIC_NB]; +static size_t app_layer_plugins_nb = 0; +#endif + +int SCPluginRegisterAppLayer(SCAppLayerPlugin *plugin) +{ +#ifdef ALPROTO_DYNAMIC_NB + if (app_layer_plugins_nb < ALPROTO_DYNAMIC_NB) { + app_layer_plugins[app_layer_plugins_nb] = plugin; + RegisterAppProtoString((AppProto)(ALPROTO_MAX_STATIC + app_layer_plugins_nb), plugin->name); + app_layer_plugins_nb++; + return 0; + } +#endif + return 1; +} + +SCAppLayerPlugin *SCPluginFindAppLayerByIndex(size_t i) +{ +#ifdef ALPROTO_DYNAMIC_NB + if (i < ALPROTO_DYNAMIC_NB) { + return app_layer_plugins[i]; + } +#endif + return NULL; +} #endif diff --git a/src/util-plugin.h b/src/util-plugin.h index f749e287a366..0a611a1a77b2 100644 --- a/src/util-plugin.h +++ b/src/util-plugin.h @@ -25,4 +25,6 @@ SCCapturePlugin *SCPluginFindCaptureByName(const char *name); bool RegisterPlugin(SCPlugin *, void *); +SCAppLayerPlugin *SCPluginFindAppLayerByIndex(size_t i); + #endif /* SURICATA_UTIL_PLUGIN_H */ From aa910db8870f518c804ac4f4372f735ada8000fc Mon Sep 17 00:00:00 2001 From: Philippe Antoine Date: Fri, 5 Apr 2024 11:35:27 +0200 Subject: [PATCH 4/6] conf: expand api for plugins --- src/conf.c | 16 ++++++++++++++++ src/conf.h | 5 +++++ 2 files changed, 21 insertions(+) diff --git a/src/conf.c b/src/conf.c index 3cb9fd0801ae..5c90e7e48cdf 100644 --- a/src/conf.c +++ b/src/conf.c @@ -201,6 +201,22 @@ ConfNode *ConfGetNode(const char *name) return node; } +ConfNode * ConfGetFirstNode(const ConfNode *parent) { + return TAILQ_FIRST(&parent->head); +} + +ConfNode * ConfGetNextNode(const ConfNode *node) { + return TAILQ_NEXT(node, next); +} + +const char * ConfGetNameNode(const ConfNode *node) { + return node->name; +} + +const char * ConfGetValueNode(const ConfNode *node) { + return node->val; +} + /** * \brief Get the root configuration node. */ diff --git a/src/conf.h b/src/conf.h index 1857efee9879..19c968065f35 100644 --- a/src/conf.h +++ b/src/conf.h @@ -84,6 +84,11 @@ void ConfNodePrune(ConfNode *node); int ConfRemove(const char *name); bool ConfNodeHasChildren(const ConfNode *node); +ConfNode * ConfGetFirstNode(const ConfNode *parent); +ConfNode * ConfGetNextNode(const ConfNode *node); +const char * ConfGetNameNode(const ConfNode *node); +const char * ConfGetValueNode(const ConfNode *node); + ConfNode *ConfGetChildWithDefault(const ConfNode *base, const ConfNode *dflt, const char *name); ConfNode *ConfNodeLookupKeyValue(const ConfNode *base, const char *key, const char *value); int ConfGetChildValue(const ConfNode *base, const char *name, const char **vptr); From 20788fc1c4a675bee6326bec192ebf43c2cb249a Mon Sep 17 00:00:00 2001 From: Philippe Antoine Date: Fri, 5 Apr 2024 14:34:46 +0200 Subject: [PATCH 5/6] detect: offer the ability to dynamically register a transform --- src/detect-engine-helper.c | 25 ++++++++++++++++++++----- src/detect-engine-helper.h | 11 +++++++++++ 2 files changed, 31 insertions(+), 5 deletions(-) diff --git a/src/detect-engine-helper.c b/src/detect-engine-helper.c index b81c5cb424be..d5153167c278 100644 --- a/src/detect-engine-helper.c +++ b/src/detect-engine-helper.c @@ -85,28 +85,43 @@ int DetectHelperKeywordRegister(const SCSigTableElmt *kw) { if (DETECT_TBLSIZE_IDX >= DETECT_TBLSIZE) { void *tmp = SCRealloc( - sigmatch_table, (DETECT_TBLSIZE + DETECT_TBLSIZE_STEP) * sizeof(SigTableElmt)); + sigmatch_table, (DETECT_TBLSIZE + DETECT_TBLSIZE_STEP) * sizeof(SigTableElmt)); if (unlikely(tmp == NULL)) { return -1; } sigmatch_table = tmp; DETECT_TBLSIZE += DETECT_TBLSIZE_STEP; } - + sigmatch_table[DETECT_TBLSIZE_IDX].name = kw->name; sigmatch_table[DETECT_TBLSIZE_IDX].desc = kw->desc; sigmatch_table[DETECT_TBLSIZE_IDX].url = kw->url; sigmatch_table[DETECT_TBLSIZE_IDX].flags = kw->flags; sigmatch_table[DETECT_TBLSIZE_IDX].AppLayerTxMatch = - (int (*)(DetectEngineThreadCtx * det_ctx, Flow * f, uint8_t flags, void *alstate, - void *txv, const Signature *s, const SigMatchCtx *ctx)) kw->AppLayerTxMatch; + (int (*)(DetectEngineThreadCtx * det_ctx, Flow * f, uint8_t flags, void *alstate, + void *txv, const Signature *s, const SigMatchCtx *ctx)) kw->AppLayerTxMatch; sigmatch_table[DETECT_TBLSIZE_IDX].Setup = - (int (*)(DetectEngineCtx * de, Signature * s, const char *raw)) kw->Setup; + (int (*)(DetectEngineCtx * de, Signature * s, const char *raw)) kw->Setup; sigmatch_table[DETECT_TBLSIZE_IDX].Free = (void (*)(DetectEngineCtx * de, void *ptr)) kw->Free; DETECT_TBLSIZE_IDX++; return DETECT_TBLSIZE_IDX - 1; } +int DetectHelperTransformRegister(const SCPluginTransformTableElmt *kw) +{ + if (DETECT_TBLSIZE_IDX < DETECT_TBLSIZE) { + sigmatch_table[DETECT_TBLSIZE_IDX].name = kw->name; + sigmatch_table[DETECT_TBLSIZE_IDX].desc = kw->desc; + sigmatch_table[DETECT_TBLSIZE_IDX].flags = kw->flags; + sigmatch_table[DETECT_TBLSIZE_IDX].Transform = kw->Transform; + sigmatch_table[DETECT_TBLSIZE_IDX].Setup = kw->Setup; + sigmatch_table[DETECT_TBLSIZE_IDX].Free = kw->Free; + DETECT_TBLSIZE_IDX++; + return DETECT_TBLSIZE_IDX - 1; + } + return -1; +} + InspectionBuffer *DetectHelperGetMultiData(struct DetectEngineThreadCtx_ *det_ctx, const DetectEngineTransforms *transforms, Flow *f, const uint8_t flow_flags, void *txv, const int list_id, uint32_t index, diff --git a/src/detect-engine-helper.h b/src/detect-engine-helper.h index 5a2c49e1b059..892d5d64b5b5 100644 --- a/src/detect-engine-helper.h +++ b/src/detect-engine-helper.h @@ -29,6 +29,17 @@ #include "rust.h" int DetectHelperKeywordRegister(const SCSigTableElmt *kw); + +typedef struct SCPluginTransformTableElmt { + const char *name; + const char *desc; + uint16_t flags; + int (*Setup)(DetectEngineCtx *, Signature *, const char *); + void (*Free)(DetectEngineCtx *, void *); + void (*Transform)(InspectionBuffer *buffer, void *options); +} SCPluginTransformTableElmt; + +int DetectHelperTransformRegister(const SCPluginTransformTableElmt *kw); int DetectHelperBufferRegister(const char *name, AppProto alproto, bool toclient, bool toserver); typedef bool (*SimpleGetTxBuffer)(void *, uint8_t, const uint8_t **, uint32_t *); From a01b68d630e4b8ceb09619045306811f0bbab3b8 Mon Sep 17 00:00:00 2001 From: Philippe Antoine Date: Fri, 5 Apr 2024 15:07:18 +0200 Subject: [PATCH 6/6] detect: inspection buffer api for transforms in plugins --- src/detect-engine-helper.c | 8 ++++++++ src/detect-engine-helper.h | 3 +++ 2 files changed, 11 insertions(+) diff --git a/src/detect-engine-helper.c b/src/detect-engine-helper.c index d5153167c278..29311b9aff53 100644 --- a/src/detect-engine-helper.c +++ b/src/detect-engine-helper.c @@ -146,3 +146,11 @@ InspectionBuffer *DetectHelperGetMultiData(struct DetectEngineThreadCtx_ *det_ct buffer->flags = DETECT_CI_FLAGS_SINGLE; return buffer; } + +uint8_t * InspectionBufferPtr(InspectionBuffer *buf) { + return buf->inspect; +} + +uint32_t InspectionBufferLength(InspectionBuffer *buf) { + return buf->inspect_len; +} diff --git a/src/detect-engine-helper.h b/src/detect-engine-helper.h index 892d5d64b5b5..3fb4d5bef08c 100644 --- a/src/detect-engine-helper.h +++ b/src/detect-engine-helper.h @@ -55,4 +55,7 @@ InspectionBuffer *DetectHelperGetMultiData(struct DetectEngineThreadCtx_ *det_ct const DetectEngineTransforms *transforms, Flow *f, const uint8_t flow_flags, void *txv, const int list_id, uint32_t index, MultiGetTxBuffer GetBuf); +uint8_t * InspectionBufferPtr(InspectionBuffer *buf); +uint32_t InspectionBufferLength(InspectionBuffer *buf); + #endif /* SURICATA_DETECT_ENGINE_HELPER_H */