]> git.ipfire.org Git - thirdparty/suricata.git/commitdiff
output/json: Refactor internal routines
authorJeff Lucovsky <jeff@lucovsky.org>
Sat, 15 May 2021 14:02:14 +0000 (10:02 -0400)
committerVictor Julien <victor@inliniac.net>
Mon, 20 Sep 2021 15:31:15 +0000 (17:31 +0200)
src/output-json.c
src/suricata-plugin.h

index 9c4d9f63bc3bccfd22b2130ada6c35ae0018fe98..20672a72aa4c1e7c4b53d187e1b93f9c709ca93c 100644 (file)
@@ -1002,6 +1002,78 @@ int OutputJsonBuilderBuffer(JsonBuilder *js, OutputJsonThreadCtx *ctx)
     return 0;
 }
 
+static inline enum LogFileType FileTypeFromConf(const char *typestr)
+{
+    enum LogFileType log_filetype = LOGFILE_TYPE_NOTSET;
+
+    if (typestr == NULL) {
+        log_filetype = LOGFILE_TYPE_FILE;
+    } else if (strcmp(typestr, "file") == 0 || strcmp(typestr, "regular") == 0) {
+        log_filetype = LOGFILE_TYPE_FILE;
+    } else if (strcmp(typestr, "unix_dgram") == 0) {
+        log_filetype = LOGFILE_TYPE_UNIX_DGRAM;
+    } else if (strcmp(typestr, "unix_stream") == 0) {
+        log_filetype = LOGFILE_TYPE_UNIX_STREAM;
+    } else if (strcmp(typestr, "redis") == 0) {
+#ifdef HAVE_LIBHIREDIS
+        log_filetype = LOGFILE_TYPE_REDIS;
+#else
+        FatalError(SC_ERR_FATAL, "redis JSON output option is not compiled");
+#endif
+    }
+    SCLogDebug("type %s, file type value %d", typestr, log_filetype);
+    return log_filetype;
+}
+
+static int LogFileTypePrepare(
+        OutputJsonCtx *json_ctx, enum LogFileType log_filetype, ConfNode *conf)
+{
+
+    if (log_filetype == LOGFILE_TYPE_FILE || log_filetype == LOGFILE_TYPE_UNIX_DGRAM ||
+            log_filetype == LOGFILE_TYPE_UNIX_STREAM) {
+        if (SCConfLogOpenGeneric(conf, json_ctx->file_ctx, DEFAULT_LOG_FILENAME, 1) < 0) {
+            return -1;
+        }
+        OutputRegisterFileRotationFlag(&json_ctx->file_ctx->rotation_flag);
+    }
+#ifdef HAVE_LIBHIREDIS
+    else if (log_filetype == LOGFILE_TYPE_REDIS) {
+        SCLogRedisInit();
+        ConfNode *redis_node = ConfNodeLookupChild(conf, "redis");
+        if (!json_ctx->file_ctx->sensor_name) {
+            char hostname[1024];
+            gethostname(hostname, 1023);
+            json_ctx->file_ctx->sensor_name = SCStrdup(hostname);
+        }
+        if (json_ctx->file_ctx->sensor_name == NULL) {
+            return -1;
+        }
+
+        if (SCConfLogOpenRedis(redis_node, json_ctx->file_ctx) < 0) {
+            return -1;
+        }
+    }
+#endif
+    else if (log_filetype == LOGFILE_TYPE_PLUGIN) {
+        if (json_ctx->file_ctx->threaded) {
+            /* Prepare for threaded log output. */
+            if (!SCLogOpenThreadedFile(NULL, NULL, json_ctx->file_ctx, 1)) {
+                return -1;
+            }
+        }
+        ConfNode *plugin_conf = ConfNodeLookupChild(conf, json_ctx->plugin->name);
+        void *init_data = NULL;
+        if (json_ctx->plugin->Init(json_ctx->plugin->internal ? conf : plugin_conf,
+                    json_ctx->file_ctx->threaded, &init_data) < 0) {
+            return -1;
+        }
+        json_ctx->file_ctx->plugin.plugin = json_ctx->plugin;
+        json_ctx->file_ctx->plugin.init_data = init_data;
+    }
+
+    return 0;
+}
+
 /**
  * \brief Create a new LogFileCtx for "fast" output style.
  * \param conf The configuration node for this output.
@@ -1010,6 +1082,7 @@ int OutputJsonBuilderBuffer(JsonBuilder *js, OutputJsonThreadCtx *ctx)
 OutputInitResult OutputJsonInitCtx(ConfNode *conf)
 {
     OutputInitResult result = { NULL, false };
+    OutputCtx *output_ctx = NULL;
 
     OutputJsonCtx *json_ctx = SCCalloc(1, sizeof(OutputJsonCtx));
     if (unlikely(json_ctx == NULL)) {
@@ -1038,20 +1111,16 @@ OutputInitResult OutputJsonInitCtx(ConfNode *conf)
 
     if (sensor_name) {
         json_ctx->file_ctx->sensor_name = SCStrdup(sensor_name);
-        if (json_ctx->file_ctx->sensor_name  == NULL) {
-            LogFileFreeCtx(json_ctx->file_ctx);
-            SCFree(json_ctx);
-            return result;
+        if (json_ctx->file_ctx->sensor_name == NULL) {
+            goto error_exit;
         }
     } else {
         json_ctx->file_ctx->sensor_name = NULL;
     }
 
-    OutputCtx *output_ctx = SCCalloc(1, sizeof(OutputCtx));
+    output_ctx = SCCalloc(1, sizeof(OutputCtx));
     if (unlikely(output_ctx == NULL)) {
-        LogFileFreeCtx(json_ctx->file_ctx);
-        SCFree(json_ctx);
-        return result;
+        goto error_exit;
     }
 
     output_ctx->data = json_ctx;
@@ -1059,45 +1128,21 @@ OutputInitResult OutputJsonInitCtx(ConfNode *conf)
 
     if (conf) {
         const char *output_s = ConfNodeLookupChildValue(conf, "filetype");
-
         // Backwards compatibility
         if (output_s == NULL) {
             output_s = ConfNodeLookupChildValue(conf, "type");
         }
 
-        if (output_s != NULL) {
-            if (strcmp(output_s, "file") == 0 ||
-                strcmp(output_s, "regular") == 0) {
-                json_ctx->json_out = LOGFILE_TYPE_FILE;
-            } else if (strcmp(output_s, "syslog") == 0) {
-                json_ctx->json_out = LOGFILE_TYPE_SYSLOG;
-            } else if (strcmp(output_s, "unix_dgram") == 0) {
-                json_ctx->json_out = LOGFILE_TYPE_UNIX_DGRAM;
-            } else if (strcmp(output_s, "unix_stream") == 0) {
-                json_ctx->json_out = LOGFILE_TYPE_UNIX_STREAM;
-            } else if (strcmp(output_s, "redis") == 0) {
-#ifdef HAVE_LIBHIREDIS
-                SCLogRedisInit();
-                json_ctx->json_out = LOGFILE_TYPE_REDIS;
-#else
-                           FatalError(SC_ERR_FATAL,
-                                      "redis JSON output option is not compiled");
-#endif
-            } else {
+        enum LogFileType log_filetype = FileTypeFromConf(output_s);
+        if (log_filetype == LOGFILE_TYPE_NOTSET) {
 #ifdef HAVE_PLUGINS
-                SCPluginFileType *plugin = SCPluginFindFileType(output_s);
-                if (plugin == NULL) {
-                    FatalError(SC_ERR_INVALID_ARGUMENT,
-                            "Invalid JSON output option: %s", output_s);
-                } else {
-                    json_ctx->json_out = LOGFILE_TYPE_PLUGIN;
-                    json_ctx->plugin = plugin;
-                }
-#else
-                FatalError(SC_ERR_INVALID_ARGUMENT,
-                        "Invalid JSON output option: %s", output_s);
+            SCPluginFileType *plugin = SCPluginFindFileType(output_s);
+            if (plugin != NULL) {
+                log_filetype = LOGFILE_TYPE_PLUGIN;
+                json_ctx->plugin = plugin;
+            } else
 #endif
-            }
+                FatalError(SC_ERR_INVALID_ARGUMENT, "Invalid JSON output option: %s", output_s);
         }
 
         const char *prefix = ConfNodeLookupChildValue(conf, "prefix");
@@ -1121,115 +1166,17 @@ OutputInitResult OutputJsonInitCtx(ConfNode *conf)
         } else {
             json_ctx->file_ctx->threaded = false;
         }
-
-        if (json_ctx->json_out == LOGFILE_TYPE_FILE ||
-            json_ctx->json_out == LOGFILE_TYPE_UNIX_DGRAM ||
-            json_ctx->json_out == LOGFILE_TYPE_UNIX_STREAM)
-        {
-
-            if (SCConfLogOpenGeneric(conf, json_ctx->file_ctx, DEFAULT_LOG_FILENAME, 1) < 0) {
-                LogFileFreeCtx(json_ctx->file_ctx);
-                SCFree(json_ctx);
-                SCFree(output_ctx);
-                return result;
-            }
-            OutputRegisterFileRotationFlag(&json_ctx->file_ctx->rotation_flag);
-
-        }
-#ifndef OS_WIN32
-       else if (json_ctx->json_out == LOGFILE_TYPE_SYSLOG) {
-            const char *facility_s = ConfNodeLookupChildValue(conf, "facility");
-            if (facility_s == NULL) {
-                facility_s = DEFAULT_ALERT_SYSLOG_FACILITY_STR;
-            }
-
-            int facility = SCMapEnumNameToValue(facility_s, SCSyslogGetFacilityMap());
-            if (facility == -1) {
-                SCLogWarning(SC_ERR_INVALID_ARGUMENT, "Invalid syslog facility: \"%s\","
-                        " now using \"%s\" as syslog facility", facility_s,
-                        DEFAULT_ALERT_SYSLOG_FACILITY_STR);
-                facility = DEFAULT_ALERT_SYSLOG_FACILITY;
-            }
-
-            const char *level_s = ConfNodeLookupChildValue(conf, "level");
-            if (level_s != NULL) {
-                int level = SCMapEnumNameToValue(level_s, SCSyslogGetLogLevelMap());
-                if (level != -1) {
-                    json_ctx->file_ctx->syslog_setup.alert_syslog_level = level;
-                }
-            }
-
-            const char *ident = ConfNodeLookupChildValue(conf, "identity");
-            /* if null we just pass that to openlog, which will then
-             * figure it out by itself. */
-
-            openlog(ident, LOG_PID|LOG_NDELAY, facility);
+        if (LogFileTypePrepare(json_ctx, log_filetype, conf) < 0) {
+            goto error_exit;
         }
-#endif
-#ifdef HAVE_LIBHIREDIS
-        else if (json_ctx->json_out == LOGFILE_TYPE_REDIS) {
-            ConfNode *redis_node = ConfNodeLookupChild(conf, "redis");
-            if (!json_ctx->file_ctx->sensor_name) {
-                char hostname[1024];
-                gethostname(hostname, 1023);
-                json_ctx->file_ctx->sensor_name = SCStrdup(hostname);
-            }
-            if (json_ctx->file_ctx->sensor_name  == NULL) {
-                LogFileFreeCtx(json_ctx->file_ctx);
-                SCFree(json_ctx);
-                SCFree(output_ctx);
-                return result;
-            }
-
-            if (SCConfLogOpenRedis(redis_node, json_ctx->file_ctx) < 0) {
-                LogFileFreeCtx(json_ctx->file_ctx);
-                SCFree(json_ctx);
-                SCFree(output_ctx);
-                return result;
-            }
-        }
-#endif
-#ifdef HAVE_PLUGINS
-        else if (json_ctx->json_out == LOGFILE_TYPE_PLUGIN) {
-            if (json_ctx->file_ctx->threaded) {
-                /* Prepare for storing per-thread data */
-                if (!SCLogOpenThreadedFile(NULL, NULL, json_ctx->file_ctx, 1)) {
-                    SCFree(json_ctx);
-                    SCFree(output_ctx);
-                    return result;
-                }
-            }
-
-            void *init_data = NULL;
-            if (json_ctx->plugin->Init(conf, json_ctx->file_ctx->threaded, &init_data) < 0) {
-                LogFileFreeCtx(json_ctx->file_ctx);
-                SCFree(json_ctx);
-                SCFree(output_ctx);
-                return result;
-            }
-
-            /* Now that initialization completed successfully, if threaded, make sure
-             * that ThreadInit and ThreadDeInit exist
-             */
-            if (json_ctx->file_ctx->threaded) {
-                if (!json_ctx->plugin->ThreadInit || !json_ctx->plugin->ThreadDeinit) {
-                    FatalError(SC_ERR_LOG_OUTPUT, "Output logger must supply ThreadInit and "
-                                                  "ThreadDeinit functions for threaded mode");
-                }
-            }
-
-            json_ctx->file_ctx->plugin.plugin = json_ctx->plugin;
-            json_ctx->file_ctx->plugin.init_data = init_data;
-        }
-#endif
 
         const char *sensor_id_s = ConfNodeLookupChildValue(conf, "sensor-id");
         if (sensor_id_s != NULL) {
             if (StringParseUint64((uint64_t *)&sensor_id, 10, 0, sensor_id_s) < 0) {
-                SCLogError(SC_ERR_INVALID_ARGUMENT,
-                           "Failed to initialize JSON output, "
-                           "invalid sensor-id: %s", sensor_id_s);
-                exit(EXIT_FAILURE);
+                FatalError(SC_ERR_INVALID_ARGUMENT,
+                        "Failed to initialize JSON output, "
+                        "invalid sensor-id: %s",
+                        sensor_id_s);
             }
         }
 
@@ -1264,10 +1211,10 @@ OutputInitResult OutputJsonInitCtx(ConfNode *conf)
             if (StringParseUint16(&json_ctx->cfg.community_id_seed,
                         10, 0, cid_seed) < 0)
             {
-                SCLogError(SC_ERR_INVALID_ARGUMENT,
-                           "Failed to initialize JSON output, "
-                           "invalid community-id-seed: %s", cid_seed);
-                exit(EXIT_FAILURE);
+                FatalError(SC_ERR_INVALID_ARGUMENT,
+                        "Failed to initialize JSON output, "
+                        "invalid community-id-seed: %s",
+                        cid_seed);
             }
         }
 
@@ -1286,8 +1233,7 @@ OutputInitResult OutputJsonInitCtx(ConfNode *conf)
                 (RunmodeGetCurrent() == RUNMODE_PCAP_FILE ||
                  RunmodeGetCurrent() == RUNMODE_UNIX_SOCKET);
         }
-
-        json_ctx->file_ctx->type = json_ctx->json_out;
+        json_ctx->file_ctx->type = log_filetype;
     }
 
     SCLogDebug("returning output_ctx %p", output_ctx);
@@ -1295,6 +1241,18 @@ OutputInitResult OutputJsonInitCtx(ConfNode *conf)
     result.ctx = output_ctx;
     result.ok = true;
     return result;
+
+error_exit:
+    if (json_ctx->file_ctx) {
+        LogFileFreeCtx(json_ctx->file_ctx);
+    }
+    if (json_ctx) {
+        SCFree(json_ctx);
+    }
+    if (output_ctx) {
+        SCFree(output_ctx);
+    }
+    return result;
 }
 
 static void OutputJsonDeInitCtx(OutputCtx *output_ctx)
index 860af8d2218ed7895dd33e7631782e392cfaa418..4be5c4aaa884b2d39cf86b8063b7f3008ccc6212 100644 (file)
@@ -36,6 +36,7 @@ typedef struct SCPlugin_ {
     const char *name;
     const char *license;
     const char *author;
+    const bool internal;
     void (*Init)(void);
 } SCPlugin;
 
@@ -48,7 +49,8 @@ typedef struct SCPlugin_ {
  * plugins: section
  */
 typedef struct SCPluginFileType_ {
-    char *name;
+    const char *name;
+    bool internal;
     /* Init Called on first access */
     int (*Init)(ConfNode *conf, bool threaded, void **init_data);
     /* Write - Called on each write to the object */