aboutsummaryrefslogtreecommitdiffstats
path: root/framework/src/suricata/src/util-logopenfile.c
diff options
context:
space:
mode:
Diffstat (limited to 'framework/src/suricata/src/util-logopenfile.c')
-rw-r--r--framework/src/suricata/src/util-logopenfile.c646
1 files changed, 0 insertions, 646 deletions
diff --git a/framework/src/suricata/src/util-logopenfile.c b/framework/src/suricata/src/util-logopenfile.c
deleted file mode 100644
index 84e5d2fe..00000000
--- a/framework/src/suricata/src/util-logopenfile.c
+++ /dev/null
@@ -1,646 +0,0 @@
-/* vi: set et ts=4: */
-/* Copyright (C) 2007-2014 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 Mike Pomraning <mpomraning@qualys.com>
- *
- * File-like output for logging: regular files and sockets.
- */
-#include <sys/types.h>
-#include <sys/socket.h>
-#include <sys/un.h>
-
-#include "suricata-common.h" /* errno.h, string.h, etc. */
-#include "tm-modules.h" /* LogFileCtx */
-#include "conf.h" /* ConfNode, etc. */
-#include "output.h" /* DEFAULT_LOG_* */
-#include "util-logopenfile.h"
-#include "util-logopenfile-tile.h"
-
-const char * redis_push_cmd = "LPUSH";
-const char * redis_publish_cmd = "PUBLISH";
-
-/** \brief connect to the indicated local stream socket, logging any errors
- * \param path filesystem path to connect to
- * \param log_err, non-zero if connect failure should be logged.
- * \retval FILE* on success (fdopen'd wrapper of underlying socket)
- * \retval NULL on error
- */
-static FILE *
-SCLogOpenUnixSocketFp(const char *path, int sock_type, int log_err)
-{
- struct sockaddr_un sun;
- int s = -1;
- FILE * ret = NULL;
-
- memset(&sun, 0x00, sizeof(sun));
-
- s = socket(PF_UNIX, sock_type, 0);
- if (s < 0) goto err;
-
- sun.sun_family = AF_UNIX;
- strlcpy(sun.sun_path, path, sizeof(sun.sun_path));
-
- if (connect(s, (const struct sockaddr *)&sun, sizeof(sun)) < 0)
- goto err;
-
- ret = fdopen(s, "w");
- if (ret == NULL)
- goto err;
-
- return ret;
-
-err:
- if (log_err)
- SCLogWarning(SC_ERR_SOCKET,
- "Error connecting to socket \"%s\": %s (will keep trying)",
- path, strerror(errno));
-
- if (s >= 0)
- close(s);
-
- return NULL;
-}
-
-/**
- * \brief Attempt to reconnect a disconnected (or never-connected) Unix domain socket.
- * \retval 1 if it is now connected; otherwise 0
- */
-static int SCLogUnixSocketReconnect(LogFileCtx *log_ctx)
-{
- int disconnected = 0;
- if (log_ctx->fp) {
- SCLogWarning(SC_ERR_SOCKET,
- "Write error on Unix socket \"%s\": %s; reconnecting...",
- log_ctx->filename, strerror(errno));
- fclose(log_ctx->fp);
- log_ctx->fp = NULL;
- log_ctx->reconn_timer = 0;
- disconnected = 1;
- }
-
- struct timeval tv;
- uint64_t now;
- gettimeofday(&tv, NULL);
- now = (uint64_t)tv.tv_sec * 1000;
- now += tv.tv_usec / 1000; /* msec resolution */
- if (log_ctx->reconn_timer != 0 &&
- (now - log_ctx->reconn_timer) < LOGFILE_RECONN_MIN_TIME) {
- /* Don't bother to try reconnecting too often. */
- return 0;
- }
- log_ctx->reconn_timer = now;
-
- log_ctx->fp = SCLogOpenUnixSocketFp(log_ctx->filename, log_ctx->sock_type, 0);
- if (log_ctx->fp) {
- /* Connected at last (or reconnected) */
- SCLogNotice("Reconnected socket \"%s\"", log_ctx->filename);
- } else if (disconnected) {
- SCLogWarning(SC_ERR_SOCKET, "Reconnect failed: %s (will keep trying)",
- strerror(errno));
- }
-
- return log_ctx->fp ? 1 : 0;
-}
-
-/**
- * \brief Write buffer to log file.
- * \retval 0 on failure; otherwise, the return value of fwrite (number of
- * characters successfully written).
- */
-static int SCLogFileWrite(const char *buffer, int buffer_len, LogFileCtx *log_ctx)
-{
- /* Check for rotation. */
- if (log_ctx->rotation_flag) {
- log_ctx->rotation_flag = 0;
- SCConfLogReopen(log_ctx);
- }
-
- int ret = 0;
-
- if (log_ctx->fp == NULL && log_ctx->is_sock)
- SCLogUnixSocketReconnect(log_ctx);
-
- if (log_ctx->fp) {
- clearerr(log_ctx->fp);
- ret = fwrite(buffer, buffer_len, 1, log_ctx->fp);
- fflush(log_ctx->fp);
-
- if (ferror(log_ctx->fp) && log_ctx->is_sock) {
- /* Error on Unix socket, maybe needs reconnect */
- if (SCLogUnixSocketReconnect(log_ctx)) {
- ret = fwrite(buffer, buffer_len, 1, log_ctx->fp);
- fflush(log_ctx->fp);
- }
- }
- }
-
- return ret;
-}
-
-static void SCLogFileClose(LogFileCtx *log_ctx)
-{
- if (log_ctx->fp)
- fclose(log_ctx->fp);
-}
-
-/** \brief open the indicated file, logging any errors
- * \param path filesystem path to open
- * \param append_setting open file with O_APPEND: "yes" or "no"
- * \retval FILE* on success
- * \retval NULL on error
- */
-static FILE *
-SCLogOpenFileFp(const char *path, const char *append_setting)
-{
- FILE *ret = NULL;
-
- if (strcasecmp(append_setting, "yes") == 0) {
- ret = fopen(path, "a");
- } else {
- ret = fopen(path, "w");
- }
-
- if (ret == NULL)
- SCLogError(SC_ERR_FOPEN, "Error opening file: \"%s\": %s",
- path, strerror(errno));
- return ret;
-}
-
-/** \brief open the indicated file remotely over PCIe to a host
- * \param path filesystem path to open
- * \param append_setting open file with O_APPEND: "yes" or "no"
- * \retval FILE* on success
- * \retval NULL on error
- */
-static PcieFile *SCLogOpenPcieFp(LogFileCtx *log_ctx, const char *path,
- const char *append_setting)
-{
-#ifndef __tile__
- SCLogError(SC_ERR_INVALID_YAML_CONF_ENTRY,
- "PCIe logging only supported on Tile-Gx Architecture.");
- return NULL;
-#else
- return TileOpenPcieFp(log_ctx, path, append_setting);
-#endif
-}
-
-/** \brief open a generic output "log file", which may be a regular file or a socket
- * \param conf ConfNode structure for the output section in question
- * \param log_ctx Log file context allocated by caller
- * \param default_filename Default name of file to open, if not specified in ConfNode
- * \param rotate Register the file for rotation in HUP.
- * \retval 0 on success
- * \retval -1 on error
- */
-int
-SCConfLogOpenGeneric(ConfNode *conf,
- LogFileCtx *log_ctx,
- const char *default_filename,
- int rotate)
-{
- char log_path[PATH_MAX];
- char *log_dir;
- const char *filename, *filetype;
-
- // Arg check
- if (conf == NULL || log_ctx == NULL || default_filename == NULL) {
- SCLogError(SC_ERR_INVALID_ARGUMENT,
- "SCConfLogOpenGeneric(conf %p, ctx %p, default %p) "
- "missing an argument",
- conf, log_ctx, default_filename);
- return -1;
- }
- if (log_ctx->fp != NULL) {
- SCLogError(SC_ERR_INVALID_ARGUMENT,
- "SCConfLogOpenGeneric: previously initialized Log CTX "
- "encountered");
- return -1;
- }
-
- // Resolve the given config
- filename = ConfNodeLookupChildValue(conf, "filename");
- if (filename == NULL)
- filename = default_filename;
-
- log_dir = ConfigGetLogDirectory();
-
- if (PathIsAbsolute(filename)) {
- snprintf(log_path, PATH_MAX, "%s", filename);
- } else {
- snprintf(log_path, PATH_MAX, "%s/%s", log_dir, filename);
- }
-
- filetype = ConfNodeLookupChildValue(conf, "filetype");
- if (filetype == NULL)
- filetype = DEFAULT_LOG_FILETYPE;
-
- const char *append = ConfNodeLookupChildValue(conf, "append");
- if (append == NULL)
- append = DEFAULT_LOG_MODE_APPEND;
-
- // Now, what have we been asked to open?
- if (strcasecmp(filetype, "unix_stream") == 0) {
- /* Don't bail. May be able to connect later. */
- log_ctx->is_sock = 1;
- log_ctx->sock_type = SOCK_STREAM;
- log_ctx->fp = SCLogOpenUnixSocketFp(log_path, SOCK_STREAM, 1);
- } else if (strcasecmp(filetype, "unix_dgram") == 0) {
- /* Don't bail. May be able to connect later. */
- log_ctx->is_sock = 1;
- log_ctx->sock_type = SOCK_DGRAM;
- log_ctx->fp = SCLogOpenUnixSocketFp(log_path, SOCK_DGRAM, 1);
- } else if (strcasecmp(filetype, DEFAULT_LOG_FILETYPE) == 0 ||
- strcasecmp(filetype, "file") == 0) {
- log_ctx->fp = SCLogOpenFileFp(log_path, append);
- if (log_ctx->fp == NULL)
- return -1; // Error already logged by Open...Fp routine
- log_ctx->is_regular = 1;
- if (rotate) {
- OutputRegisterFileRotationFlag(&log_ctx->rotation_flag);
- }
- } else if (strcasecmp(filetype, "pcie") == 0) {
- log_ctx->pcie_fp = SCLogOpenPcieFp(log_ctx, log_path, append);
- if (log_ctx->pcie_fp == NULL)
- return -1; // Error already logged by Open...Fp routine
- } else {
- SCLogError(SC_ERR_INVALID_YAML_CONF_ENTRY, "Invalid entry for "
- "%s.filetype. Expected \"regular\" (default), \"unix_stream\", "
- "\"pcie\" "
- "or \"unix_dgram\"",
- conf->name);
- }
- log_ctx->filename = SCStrdup(log_path);
- if (unlikely(log_ctx->filename == NULL)) {
- SCLogError(SC_ERR_MEM_ALLOC,
- "Failed to allocate memory for filename");
- return -1;
- }
-
- SCLogInfo("%s output device (%s) initialized: %s", conf->name, filetype,
- filename);
-
- return 0;
-}
-
-/**
- * \brief Reopen a regular log file with the side-affect of truncating it.
- *
- * This is useful to clear the log file and start a new one, or to
- * re-open the file after its been moved by something external
- * (eg. logrotate).
- */
-int SCConfLogReopen(LogFileCtx *log_ctx)
-{
- if (!log_ctx->is_regular) {
- /* Not supported and not needed on non-regular files. */
- return 0;
- }
-
- if (log_ctx->filename == NULL) {
- SCLogWarning(SC_ERR_INVALID_ARGUMENT,
- "Can't re-open LogFileCtx without a filename.");
- return -1;
- }
-
- fclose(log_ctx->fp);
-
- /* Reopen the file. Append is forced in case the file was not
- * moved as part of a rotation process. */
- SCLogDebug("Reopening log file %s.", log_ctx->filename);
- log_ctx->fp = SCLogOpenFileFp(log_ctx->filename, "yes");
- if (log_ctx->fp == NULL) {
- return -1; // Already logged by Open..Fp routine.
- }
-
- return 0;
-}
-
-
-#ifdef HAVE_LIBHIREDIS
-
-static void SCLogFileCloseRedis(LogFileCtx *log_ctx)
-{
- if (log_ctx->redis) {
- redisReply *reply;
- int i;
- for (i = 0; i < log_ctx->redis_setup.batch_count; i++) {
- redisGetReply(log_ctx->redis, (void **)&reply);
- if (reply)
- freeReplyObject(reply);
- }
- redisFree(log_ctx->redis);
- log_ctx->redis = NULL;
- }
- log_ctx->redis_setup.tried = 0;
- log_ctx->redis_setup.batch_count = 0;
-}
-
-int SCConfLogOpenRedis(ConfNode *redis_node, LogFileCtx *log_ctx)
-{
- const char *redis_server = NULL;
- const char *redis_port = NULL;
- const char *redis_mode = NULL;
- const char *redis_key = NULL;
-
- if (redis_node) {
- redis_server = ConfNodeLookupChildValue(redis_node, "server");
- redis_port = ConfNodeLookupChildValue(redis_node, "port");
- redis_mode = ConfNodeLookupChildValue(redis_node, "mode");
- redis_key = ConfNodeLookupChildValue(redis_node, "key");
- }
- if (!redis_server) {
- redis_server = "127.0.0.1";
- SCLogInfo("Using default redis server (127.0.0.1)");
- }
- if (!redis_port)
- redis_port = "6379";
- if (!redis_mode)
- redis_mode = "list";
- if (!redis_key)
- redis_key = "suricata";
- log_ctx->redis_setup.key = SCStrdup(redis_key);
-
- if (!log_ctx->redis_setup.key) {
- SCLogError(SC_ERR_MEM_ALLOC, "Unable to allocate redis key name");
- exit(EXIT_FAILURE);
- }
-
- log_ctx->redis_setup.batch_size = 0;
-
- ConfNode *pipelining = ConfNodeLookupChild(redis_node, "pipelining");
- if (pipelining) {
- int enabled = 0;
- int ret;
- intmax_t val;
- ret = ConfGetChildValueBool(pipelining, "enabled", &enabled);
- if (ret && enabled) {
- ret = ConfGetChildValueInt(pipelining, "batch-size", &val);
- if (ret) {
- log_ctx->redis_setup.batch_size = val;
- } else {
- log_ctx->redis_setup.batch_size = 10;
- }
- }
- }
-
- if (!strcmp(redis_mode, "list")) {
- log_ctx->redis_setup.command = redis_push_cmd;
- if (!log_ctx->redis_setup.command) {
- SCLogError(SC_ERR_MEM_ALLOC, "Unable to allocate redis key command");
- exit(EXIT_FAILURE);
- }
- } else {
- log_ctx->redis_setup.command = redis_publish_cmd;
- if (!log_ctx->redis_setup.command) {
- SCLogError(SC_ERR_MEM_ALLOC, "Unable to allocate redis key command");
- exit(EXIT_FAILURE);
- }
- }
- redisContext *c = redisConnect(redis_server, atoi(redis_port));
- if (c != NULL && c->err) {
- SCLogError(SC_ERR_SOCKET, "Error connecting to redis server: %s", c->errstr);
- exit(EXIT_FAILURE);
- }
-
- /* store server params for reconnection */
- log_ctx->redis_setup.server = SCStrdup(redis_server);
- if (!log_ctx->redis_setup.server) {
- SCLogError(SC_ERR_MEM_ALLOC, "Error allocating redis server string");
- exit(EXIT_FAILURE);
- }
- log_ctx->redis_setup.port = atoi(redis_port);
- log_ctx->redis_setup.tried = 0;
-
- log_ctx->redis = c;
-
- log_ctx->Close = SCLogFileCloseRedis;
-
- return 0;
-}
-
-int SCConfLogReopenRedis(LogFileCtx *log_ctx)
-{
- if (log_ctx->redis != NULL) {
- redisFree(log_ctx->redis);
- log_ctx->redis = NULL;
- }
-
- /* only try to reconnect once per second */
- if (log_ctx->redis_setup.tried >= time(NULL)) {
- return -1;
- }
-
- redisContext *c = redisConnect(log_ctx->redis_setup.server, log_ctx->redis_setup.port);
- if (c != NULL && c->err) {
- if (log_ctx->redis_setup.tried == 0) {
- SCLogError(SC_ERR_SOCKET, "Error connecting to redis server: %s\n", c->errstr);
- }
- redisFree(c);
- log_ctx->redis_setup.tried = time(NULL);
- return -1;
- }
- log_ctx->redis = c;
- log_ctx->redis_setup.tried = 0;
- log_ctx->redis_setup.batch_count = 0;
- return 0;
-}
-
-#endif
-
-/** \brief LogFileNewCtx() Get a new LogFileCtx
- * \retval LogFileCtx * pointer if succesful, NULL if error
- * */
-LogFileCtx *LogFileNewCtx(void)
-{
- LogFileCtx* lf_ctx;
- lf_ctx = (LogFileCtx*)SCMalloc(sizeof(LogFileCtx));
-
- if (lf_ctx == NULL)
- return NULL;
- memset(lf_ctx, 0, sizeof(LogFileCtx));
-
- SCMutexInit(&lf_ctx->fp_mutex,NULL);
-
- // Default Write and Close functions
- lf_ctx->Write = SCLogFileWrite;
- lf_ctx->Close = SCLogFileClose;
-
-#ifdef HAVE_LIBHIREDIS
- lf_ctx->redis_setup.batch_count = 0;
-#endif
-
- return lf_ctx;
-}
-
-/** \brief LogFileFreeCtx() Destroy a LogFileCtx (Close the file and free memory)
- * \param motcx pointer to the OutputCtx
- * \retval int 1 if succesful, 0 if error
- * */
-int LogFileFreeCtx(LogFileCtx *lf_ctx)
-{
- if (lf_ctx == NULL) {
- SCReturnInt(0);
- }
-
- if (lf_ctx->fp != NULL) {
- SCMutexLock(&lf_ctx->fp_mutex);
- lf_ctx->Close(lf_ctx);
- SCMutexUnlock(&lf_ctx->fp_mutex);
- }
-
-#ifdef HAVE_LIBHIREDIS
- if (lf_ctx->type == LOGFILE_TYPE_REDIS) {
- if (lf_ctx->redis)
- redisFree(lf_ctx->redis);
- if (lf_ctx->redis_setup.server)
- SCFree(lf_ctx->redis_setup.server);
- if (lf_ctx->redis_setup.key)
- SCFree(lf_ctx->redis_setup.key);
- }
-#endif
-
- SCMutexDestroy(&lf_ctx->fp_mutex);
-
- if (lf_ctx->prefix != NULL) {
- SCFree(lf_ctx->prefix);
- lf_ctx->prefix_len = 0;
- }
-
- if(lf_ctx->filename != NULL)
- SCFree(lf_ctx->filename);
-
- if (lf_ctx->sensor_name)
- SCFree(lf_ctx->sensor_name);
-
- OutputUnregisterFileRotationFlag(&lf_ctx->rotation_flag);
-
- SCFree(lf_ctx);
-
- SCReturnInt(1);
-}
-
-#ifdef HAVE_LIBHIREDIS
-static int LogFileWriteRedis(LogFileCtx *file_ctx, char *string, size_t string_len)
-{
- if (file_ctx->redis == NULL) {
- SCConfLogReopenRedis(file_ctx);
- if (file_ctx->redis == NULL) {
- return -1;
- } else {
- SCLogInfo("Reconnected to redis server");
- }
- }
- /* TODO go async here ? */
- if (file_ctx->redis_setup.batch_size) {
- redisAppendCommand(file_ctx->redis, "%s %s %s",
- file_ctx->redis_setup.command,
- file_ctx->redis_setup.key,
- string);
- if (file_ctx->redis_setup.batch_count == file_ctx->redis_setup.batch_size) {
- redisReply *reply;
- int i;
- file_ctx->redis_setup.batch_count = 0;
- for (i = 0; i <= file_ctx->redis_setup.batch_size; i++) {
- if (redisGetReply(file_ctx->redis, (void **)&reply) == REDIS_OK) {
- freeReplyObject(reply);
- } else {
- if (file_ctx->redis->err) {
- SCLogInfo("Error when fetching reply: %s (%d)",
- file_ctx->redis->errstr,
- file_ctx->redis->err);
- }
- switch (file_ctx->redis->err) {
- case REDIS_ERR_EOF:
- case REDIS_ERR_IO:
- SCLogInfo("Reopening connection to redis server");
- SCConfLogReopenRedis(file_ctx);
- if (file_ctx->redis) {
- SCLogInfo("Reconnected to redis server");
- return 0;
- } else {
- SCLogInfo("Unable to reconnect to redis server");
- return 0;
- }
- break;
- default:
- SCLogWarning(SC_ERR_INVALID_VALUE,
- "Unsupported error code %d",
- file_ctx->redis->err);
- return 0;
- }
- }
- }
- } else {
- file_ctx->redis_setup.batch_count++;
- }
- } else {
- redisReply *reply = redisCommand(file_ctx->redis, "%s %s %s",
- file_ctx->redis_setup.command,
- file_ctx->redis_setup.key,
- string);
-
- switch (reply->type) {
- case REDIS_REPLY_ERROR:
- SCLogWarning(SC_ERR_SOCKET, "Redis error: %s", reply->str);
- SCConfLogReopenRedis(file_ctx);
- break;
- case REDIS_REPLY_INTEGER:
- SCLogDebug("Redis integer %lld", reply->integer);
- break;
- default:
- SCLogError(SC_ERR_INVALID_VALUE,
- "Redis default triggered with %d", reply->type);
- SCConfLogReopenRedis(file_ctx);
- break;
- }
- freeReplyObject(reply);
- }
- return 0;
-}
-#endif
-
-int LogFileWrite(LogFileCtx *file_ctx, MemBuffer *buffer)
-{
- if (file_ctx->type == LOGFILE_TYPE_SYSLOG) {
- syslog(file_ctx->syslog_setup.alert_syslog_level, "%s",
- (const char *)MEMBUFFER_BUFFER(buffer));
- } else if (file_ctx->type == LOGFILE_TYPE_FILE ||
- file_ctx->type == LOGFILE_TYPE_UNIX_DGRAM ||
- file_ctx->type == LOGFILE_TYPE_UNIX_STREAM)
- {
- /* append \n for files only */
- MemBufferWriteString(buffer, "\n");
- SCMutexLock(&file_ctx->fp_mutex);
- file_ctx->Write((const char *)MEMBUFFER_BUFFER(buffer),
- MEMBUFFER_OFFSET(buffer), file_ctx);
- SCMutexUnlock(&file_ctx->fp_mutex);
- }
-#ifdef HAVE_LIBHIREDIS
- else if (file_ctx->type == LOGFILE_TYPE_REDIS) {
- SCMutexLock(&file_ctx->fp_mutex);
- LogFileWriteRedis(file_ctx, (const char *)MEMBUFFER_BUFFER(buffer),
- MEMBUFFER_OFFSET(buffer));
- SCMutexUnlock(&file_ctx->fp_mutex);
- }
-#endif
-
- return 0;
-}