]> git.ipfire.org Git - thirdparty/suricata.git/commitdiff
plugins: app-layer plugins
authorPhilippe Antoine <pantoine@oisf.net>
Fri, 10 Jan 2025 15:57:51 +0000 (16:57 +0100)
committerPhilippe Antoine <pantoine@oisf.net>
Mon, 13 Jan 2025 12:36:05 +0000 (13:36 +0100)
Ticket: 5053

src/app-layer-parser.c
src/app-layer-parser.h
src/app-layer-protos.c
src/detect-engine-file.h
src/detect-engine-register.c
src/detect-engine-register.h
src/detect-parse.c
src/output.c
src/output.h
src/suricata-plugin.h
src/util-plugin.c

index f2da052973222efe5a3a5a1d55eebae79cd39de9..6285b67d256cf9812caadfd1a362b0198da43efa 100644 (file)
@@ -1700,6 +1700,27 @@ static void ValidateParsers(void)
     }
 }
 
+#define ARRAY_CAP_STEP 16
+static void (**PreRegisteredCallbacks)(void) = NULL;
+static size_t preregistered_callbacks_nb = 0;
+static size_t preregistered_callbacks_cap = 0;
+
+int AppLayerParserPreRegister(void (*Register)(void))
+{
+    if (preregistered_callbacks_nb == preregistered_callbacks_cap) {
+        void *tmp = SCRealloc(PreRegisteredCallbacks,
+                sizeof(void *) * (preregistered_callbacks_cap + ARRAY_CAP_STEP));
+        if (tmp == NULL) {
+            return 1;
+        }
+        preregistered_callbacks_cap += ARRAY_CAP_STEP;
+        PreRegisteredCallbacks = tmp;
+    }
+    PreRegisteredCallbacks[preregistered_callbacks_nb] = Register;
+    preregistered_callbacks_nb++;
+    return 0;
+}
+
 void AppLayerParserRegisterProtocolParsers(void)
 {
     SCEnter();
@@ -1752,6 +1773,9 @@ void AppLayerParserRegisterProtocolParsers(void)
     } else {
         SCLogInfo("Protocol detection and parser disabled for pop3 protocol.");
     }
+    for (size_t i = 0; i < preregistered_callbacks_nb; i++) {
+        PreRegisteredCallbacks[i]();
+    }
 
     ValidateParsers();
 }
index 58ad4333563c775d2f00212bfdcf01c161fb3962..d233edf9eb1f28c6ac8d46b35e29c684c433630c 100644 (file)
@@ -158,6 +158,7 @@ typedef AppLayerGetTxIterTuple (*AppLayerGetTxIteratorFunc)
 typedef int (*AppLayerParserGetFrameIdByNameFn)(const char *frame_name);
 typedef const char *(*AppLayerParserGetFrameNameByIdFn)(const uint8_t id);
 
+int AppLayerParserPreRegister(void (*Register)(void));
 /**
  * \brief Register app layer parser for the protocol.
  *
index e2f82cce276dd62512175083f67faf28009d7435..3f991f35d40437e6ffba1f18e1e27797d493ea0c 100644 (file)
@@ -26,9 +26,9 @@
 #include "app-layer-protos.h"
 #include "rust.h"
 
-AppProto g_alproto_max = ALPROTO_MAX_STATIC + 1;
+AppProto g_alproto_max = ALPROTO_MAX_STATIC;
 #define ARRAY_CAP_STEP 16
-AppProto g_alproto_strings_cap = ALPROTO_MAX_STATIC + 1;
+AppProto g_alproto_strings_cap = ALPROTO_MAX_STATIC;
 
 typedef struct AppProtoStringTuple {
     AppProto alproto;
@@ -80,7 +80,7 @@ void AppProtoRegisterProtoString(AppProto alproto, const char *proto_name)
                 FatalError("Unable to allocate g_alproto_strings");
             }
         }
-    } else if (alproto + 1 == g_alproto_max) {
+    } else if (alproto == g_alproto_max) {
         if (g_alproto_max == g_alproto_strings_cap) {
             void *tmp = SCRealloc(g_alproto_strings,
                     sizeof(AppProtoStringTuple) * (g_alproto_strings_cap + ARRAY_CAP_STEP));
index 13aa7465f436a5118b64e8e5f927c6cfe7e11c74..10bcf5ca7dbc904a7941daff1d72f0909de55b1a 100644 (file)
@@ -28,4 +28,7 @@ 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);
 
+void DetectFileRegisterProto(
+        AppProto alproto, int direction, int to_client_progress, int to_server_progress);
+
 #endif /* SURICATA_DETECT_ENGINE_FILE_H */
index 82153807ad5823d6aa7e433cde41befd7b9602f6..e19cf7b0ffa6124f8c18cbd4ca397a3a02816cbc 100644 (file)
@@ -461,6 +461,31 @@ void SigTableCleanup(void)
     }
 }
 
+#define ARRAY_CAP_STEP 16
+static void (**PreregisteredCallbacks)(void) = NULL;
+static size_t preregistered_callbacks_nb = 0;
+static size_t preregistered_callbacks_cap = 0;
+
+// Plugins can preregister keywords with this function :
+// When an app-layer plugin is loaded, it wants to register its keywords
+// But the plugin is loaded before keywords can register
+// The preregistration callbacks will later be called by SigTableSetup
+int SigTablePreRegister(void (*KeywordsRegister)(void))
+{
+    if (preregistered_callbacks_nb == preregistered_callbacks_cap) {
+        void *tmp = SCRealloc(PreregisteredCallbacks,
+                sizeof(void *) * (preregistered_callbacks_cap + ARRAY_CAP_STEP));
+        if (tmp == NULL) {
+            return 1;
+        }
+        preregistered_callbacks_cap += ARRAY_CAP_STEP;
+        PreregisteredCallbacks = tmp;
+    }
+    PreregisteredCallbacks[preregistered_callbacks_nb] = KeywordsRegister;
+    preregistered_callbacks_nb++;
+    return 0;
+}
+
 void SigTableInit(void)
 {
     if (sigmatch_table == NULL) {
@@ -710,6 +735,10 @@ void SigTableSetup(void)
     ScDetectSipRegister();
     ScDetectTemplateRegister();
 
+    for (size_t i = 0; i < preregistered_callbacks_nb; i++) {
+        PreregisteredCallbacks[i]();
+    }
+
     /* close keyword registration */
     DetectBufferTypeCloseRegistration();
 }
index f46bf688f0f873c0f48c3230beed03c76573bbf3..3060a875167f3237cd24579637336e6948873c6d 100644 (file)
@@ -345,6 +345,7 @@ int SigTableList(const char *keyword);
 void SigTableCleanup(void);
 void SigTableInit(void);
 void SigTableSetup(void);
+int SigTablePreRegister(void (*KeywordsRegister)(void));
 void SigTableRegisterTests(void);
 bool SigTableHasKeyword(const char *keyword);
 
index 90d3b5706d3de97237c4bd698b302dbb1de332fe..10e9903e80af8147f4fe38100808da649bda5b47 100644 (file)
 #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"
 #include "util-validate.h"
 
+// file protocols with common file handling
+typedef struct {
+    AppProto alproto;
+    int direction;
+    int to_client_progress;
+    int to_server_progress;
+} DetectFileHandlerProtocol_t;
+
 /* Table with all filehandler registrations */
 DetectFileHandlerTableElmt filehandler_table[DETECT_TBLSIZE_STATIC];
 
+#define ALPROTO_WITHFILES_MAX 16
+
+// file protocols with common file handling
+DetectFileHandlerProtocol_t al_protocols[ALPROTO_WITHFILES_MAX] = {
+    { .alproto = ALPROTO_NFS, .direction = SIG_FLAG_TOSERVER | SIG_FLAG_TOCLIENT },
+    { .alproto = ALPROTO_SMB, .direction = SIG_FLAG_TOSERVER | SIG_FLAG_TOCLIENT },
+    { .alproto = ALPROTO_FTP, .direction = SIG_FLAG_TOSERVER | SIG_FLAG_TOCLIENT },
+    { .alproto = ALPROTO_FTPDATA, .direction = SIG_FLAG_TOSERVER | SIG_FLAG_TOCLIENT },
+    { .alproto = ALPROTO_HTTP1,
+            .direction = SIG_FLAG_TOSERVER | SIG_FLAG_TOCLIENT,
+            .to_client_progress = HTP_RESPONSE_BODY,
+            .to_server_progress = HTP_REQUEST_BODY },
+    { .alproto = ALPROTO_HTTP2,
+            .direction = SIG_FLAG_TOSERVER | SIG_FLAG_TOCLIENT,
+            .to_client_progress = HTTP2StateDataServer,
+            .to_server_progress = HTTP2StateDataClient },
+    { .alproto = ALPROTO_SMTP, .direction = SIG_FLAG_TOSERVER }, { .alproto = ALPROTO_UNKNOWN }
+};
+
+void DetectFileRegisterProto(
+        AppProto alproto, int direction, int to_client_progress, int to_server_progress)
+{
+    size_t i = 0;
+    while (i < ALPROTO_WITHFILES_MAX && al_protocols[i].alproto != ALPROTO_UNKNOWN) {
+        i++;
+    }
+    if (i == ALPROTO_WITHFILES_MAX) {
+        return;
+    }
+    al_protocols[i].alproto = 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].alproto = ALPROTO_UNKNOWN;
+}
+
 void DetectFileRegisterFileProtocols(DetectFileHandlerTableElmt *reg)
 {
-    // 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 }
-    };
-
-    for (size_t i = 0; i < ARRAY_SIZE(al_protocols); i++) {
+    for (size_t i = 0; i < g_alproto_max; i++) {
+        if (al_protocols[i].alproto == ALPROTO_UNKNOWN) {
+            break;
+        }
         int direction = al_protocols[i].direction == 0
                                 ? (int)(SIG_FLAG_TOSERVER | SIG_FLAG_TOCLIENT)
                                 : al_protocols[i].direction;
 
         if (direction & SIG_FLAG_TOCLIENT) {
             DetectAppLayerMpmRegister(reg->name, SIG_FLAG_TOCLIENT, reg->priority, reg->PrefilterFn,
-                    reg->GetData, al_protocols[i].al_proto, al_protocols[i].to_client_progress);
-            DetectAppLayerInspectEngineRegister(reg->name, al_protocols[i].al_proto,
+                    reg->GetData, al_protocols[i].alproto, al_protocols[i].to_client_progress);
+            DetectAppLayerInspectEngineRegister(reg->name, al_protocols[i].alproto,
                     SIG_FLAG_TOCLIENT, al_protocols[i].to_client_progress, reg->Callback,
                     reg->GetData);
         }
         if (direction & SIG_FLAG_TOSERVER) {
             DetectAppLayerMpmRegister(reg->name, SIG_FLAG_TOSERVER, reg->priority, reg->PrefilterFn,
-                    reg->GetData, al_protocols[i].al_proto, al_protocols[i].to_server_progress);
-            DetectAppLayerInspectEngineRegister(reg->name, al_protocols[i].al_proto,
+                    reg->GetData, al_protocols[i].alproto, al_protocols[i].to_server_progress);
+            DetectAppLayerInspectEngineRegister(reg->name, al_protocols[i].alproto,
                     SIG_FLAG_TOSERVER, al_protocols[i].to_server_progress, reg->Callback,
                     reg->GetData);
         }
index 15464c8d4bd33f9984233eb47779e15db19581aa..6af423fb47442298cd5b6950d67cffa7c94f8029 100644 (file)
@@ -949,6 +949,32 @@ static int JsonGenericDirFlowLogger(ThreadVars *tv, void *thread_data, const Pac
     return JsonGenericLogger(tv, thread_data, p, f, state, tx, tx_id, LOG_DIR_FLOW);
 }
 
+#define ARRAY_CAP_STEP 16
+static EveJsonTxLoggerRegistrationData *preregistered_loggers = NULL;
+static size_t preregistered_loggers_nb = 0;
+static size_t preregistered_loggers_cap = 0;
+
+// Plugins can preregister logger with this function :
+// When an app-layer plugin is loaded, it wants to register its logger
+// But the plugin is loaded before loggers can register
+// The preregistration data will later be used by OutputRegisterLoggers
+int OutputPreRegisterLogger(EveJsonTxLoggerRegistrationData reg_data)
+{
+    if (preregistered_loggers_nb == preregistered_loggers_cap) {
+        void *tmp = SCRealloc(
+                preregistered_loggers, sizeof(EveJsonTxLoggerRegistrationData) *
+                                               (preregistered_loggers_cap + ARRAY_CAP_STEP));
+        if (tmp == NULL) {
+            return 1;
+        }
+        preregistered_loggers_cap += ARRAY_CAP_STEP;
+        preregistered_loggers = tmp;
+    }
+    preregistered_loggers[preregistered_loggers_nb] = reg_data;
+    preregistered_loggers_nb++;
+    return 0;
+}
+
 /**
  * \brief Register all non-root logging modules.
  */
@@ -1105,4 +1131,15 @@ void OutputRegisterLoggers(void)
     }
     /* ARP JSON logger */
     JsonArpLogRegister();
+
+    for (size_t i = 0; i < preregistered_loggers_nb; i++) {
+        OutputRegisterTxSubModule(LOGGER_JSON_TX, "eve-log", preregistered_loggers[i].logname,
+                preregistered_loggers[i].confname, OutputJsonLogInitSub,
+                preregistered_loggers[i].alproto, JsonGenericDirFlowLogger, JsonLogThreadInit,
+                JsonLogThreadDeinit);
+        SCLogDebug(
+                "%s JSON logger registered.", AppProtoToString(preregistered_loggers[i].alproto));
+        RegisterSimpleJsonApplayerLogger(
+                preregistered_loggers[i].alproto, preregistered_loggers[i].LogTx, NULL);
+    }
 }
index 43bd9d8b8f7469881bbd5a9525fb4bd5481d4b4c..87a05adfbd79a75f653592ccf5605424451aae2f 100644 (file)
@@ -170,4 +170,13 @@ typedef struct EveJsonSimpleAppLayerLogger {
 
 EveJsonSimpleAppLayerLogger *SCEveJsonSimpleGetLogger(AppProto alproto);
 
+typedef struct EveJsonTxLoggerRegistrationData {
+    const char *confname;
+    const char *logname;
+    AppProto alproto;
+    EveJsonSimpleTxLogFunc LogTx;
+} EveJsonTxLoggerRegistrationData;
+
+int OutputPreRegisterLogger(EveJsonTxLoggerRegistrationData reg_data);
+
 #endif /* ! SURICATA_OUTPUT_H */
index 639dd7c7313e78d6f6e810f106b3f868935c1adb..8bc2183d70fd4b24c37bdf73124c1ae88751b1a4 100644 (file)
@@ -52,4 +52,20 @@ typedef struct SCCapturePlugin_ {
 
 int SCPluginRegisterCapture(SCCapturePlugin *);
 
+// Every change in the API used by plugins should change this number
+#define SC_PLUGIN_API_VERSION 8
+
+typedef struct SCAppLayerPlugin_ {
+    // versioning to check suricata/plugin API compatibility
+    uint64_t version;
+    char *name;
+    void (*Register)(void);
+    void (*KeywordsRegister)(void);
+    char *logname;
+    char *confname;
+    bool (*Logger)(void *tx, void *jb);
+} SCAppLayerPlugin;
+
+int SCPluginRegisterAppLayer(SCAppLayerPlugin *);
+
 #endif /* __SURICATA_PLUGIN_H */
index 7a9b467daaac6278081a4654cfc9e60223775a81..eb2ce7647e66d4c1be1d22b87d8ccd2006d95950 100644 (file)
 
 #ifdef HAVE_PLUGINS
 
+#include "app-layer-protos.h"
+#include "app-layer-parser.h"
+#include "detect-engine-register.h"
+#include "output.h"
+
 #include <dlfcn.h>
 
 typedef struct PluginListNode_ {
@@ -148,4 +153,35 @@ SCCapturePlugin *SCPluginFindCaptureByName(const char *name)
     }
     return plugin;
 }
+
+int SCPluginRegisterAppLayer(SCAppLayerPlugin *plugin)
+{
+    if (plugin->version != SC_PLUGIN_API_VERSION) {
+        return 1;
+    }
+    AppProto alproto = g_alproto_max;
+    AppProtoRegisterProtoString(alproto, plugin->name);
+    if (plugin->Register) {
+        if (AppLayerParserPreRegister(plugin->Register) != 0) {
+            return 1;
+        }
+    }
+    if (plugin->KeywordsRegister) {
+        if (SigTablePreRegister(plugin->KeywordsRegister) != 0) {
+            return 1;
+        }
+    }
+    if (plugin->Logger) {
+        EveJsonTxLoggerRegistrationData reg_data = {
+            .confname = plugin->confname,
+            .logname = plugin->logname,
+            .alproto = alproto,
+            .LogTx = (EveJsonSimpleTxLogFunc)plugin->Logger,
+        };
+        if (OutputPreRegisterLogger(reg_data) != 0) {
+            return 1;
+        }
+    }
+    return 0;
+}
 #endif