]> git.ipfire.org Git - thirdparty/suricata.git/commitdiff
log: common custom format output
authorfooinha <fooinha@gmail.com>
Sat, 3 Dec 2016 12:22:26 +0000 (12:22 +0000)
committerVictor Julien <victor@inliniac.net>
Thu, 6 Apr 2017 08:13:22 +0000 (10:13 +0200)
src/Makefile.am
src/log-cf-common.c [new file with mode: 0644]
src/log-cf-common.h [new file with mode: 0644]
src/log-httplog.c
src/output.c
src/util-error.c
src/util-error.h
src/util-time.c
src/util-time.h

index 26541ccedfdbbe7af3ceafa929522fc82e1c0e87..de7006d05f0ff8d0e92d256ab9dab2f42d3665e7 100644 (file)
@@ -261,6 +261,7 @@ log-dnslog.c log-dnslog.h \
 log-droplog.c log-droplog.h \
 log-file.c log-file.h \
 log-filestore.c log-filestore.h \
+log-cf-common.c log-cf-common.h \
 log-httplog.c log-httplog.h \
 log-pcap.c log-pcap.h \
 log-stats.c log-stats.h \
diff --git a/src/log-cf-common.c b/src/log-cf-common.c
new file mode 100644 (file)
index 0000000..c85703f
--- /dev/null
@@ -0,0 +1,283 @@
+/* Copyright (C) 2007-2016 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 Paulo Pacheco <fooinha@gmail.com>
+ * \author Victor Julien <victor@inliniac.net>
+ * \author Ignacio Sanchez <sanchezmartin.ji@gmail.com>
+ *
+ * Common custom logging format
+ */
+
+#include "log-cf-common.h"
+#include "util-print.h"
+#include "util-unittest.h"
+
+/**
+ *  \brief Creates a custom format node
+ *  \retval LogCustomFormatNode * ptr if created
+ *  \retval NULL if failed to allocate
+ */
+LogCustomFormatNode * LogCustomFormatNodeAlloc()
+{
+    LogCustomFormatNode * node = SCMalloc(sizeof(LogCustomFormatNode));
+    if (unlikely(node == NULL)) {
+        SCLogError(SC_ERR_MEM_ALLOC, "Failed to alloc custom format node");
+        return NULL;
+    }
+    memset(node, '\0', sizeof(LogCustomFormatNode));
+    memset(node->data, '\0', LOG_NODE_STRLEN);
+
+    return node;
+}
+
+/**
+ *  \brief Creates a custom format.
+ *  \retval LogCustomFormat * ptr if created
+ *  \retval NULL if failed to allocate
+ */
+LogCustomFormat * LogCustomFormatAlloc()
+{
+    LogCustomFormat * cf = SCMalloc(sizeof(LogCustomFormat));
+    if (unlikely(cf == NULL)) {
+        SCLogError(SC_ERR_MEM_ALLOC, "Failed to alloc custom format");
+        return NULL;
+    }
+    memset(cf, '\0', sizeof(LogCustomFormat));
+
+    return cf;
+}
+
+/**
+ *  \brief Frees memory held by a custom format node
+ *  \param LogCustomFormatNode * node - node to relaease
+ */
+void LogCustomFormatNodeFree(LogCustomFormatNode *node)
+{
+    if (node==NULL)
+        return;
+
+    SCFree(node);
+}
+
+/**
+ *  \brief Frees memory held by a custom format
+ *  \param LogCustomFormat * cf - format to relaease
+ */
+void LogCustomFormatFree(LogCustomFormat *cf)
+{
+    if (cf==NULL)
+        return;
+
+    for (size_t i = 0; i < cf->cf_n; ++i) {
+        LogCustomFormatNodeFree(cf->cf_nodes[i]);
+    }
+    SCFree(cf);
+}
+
+/**
+ *  \brief Parses and saves format nodes for custom format
+ *  \param LogCustomFormat * cf - custom format to build
+ *  \param const char * format - string with format specification
+ */
+int LogCustomFormatParse(LogCustomFormat *cf, const char *format)
+{
+    const char *p, *np;
+    uint32_t n;
+    LogCustomFormatNode *node = NULL;
+
+    if (cf==NULL)
+        return 0;
+
+    if (format==NULL)
+        return 0;
+
+    p=format;
+
+    for (cf->cf_n = 0; cf->cf_n < LOG_MAXN_NODES-1 && p && *p != '\0';){
+
+        node = LogCustomFormatNodeAlloc();
+        if (node == NULL) {
+            goto parsererror;
+        }
+        node->maxlen = 0;
+
+        if (*p != '%'){
+            /* Literal found in format string */
+            node->type = LOG_CF_LITERAL;
+            np = strchr(p, '%');
+            if (np == NULL){
+                n = LOG_NODE_STRLEN-2;
+                np = NULL; /* End */
+            }else{
+                n = np-p;
+            }
+            strlcpy(node->data,p,n+1);
+            p = np;
+        } else {
+            /* Non Literal found in format string */
+            p++;
+            if (*p == '[') { /* Check if maxlength has been specified (ie: [25]) */
+                p++;
+                np = strchr(p, ']');
+                if (np != NULL) {
+                    if (np-p > 0 && np-p < 10){
+                        long maxlen = strtol(p,NULL,10);
+                        if (maxlen > 0 && maxlen < LOG_NODE_MAXOUTPUTLEN) {
+                            node->maxlen = (uint32_t) maxlen;
+                        }
+                    } else {
+                        goto parsererror;
+                    }
+                    p = np + 1;
+                } else {
+                    goto parsererror;
+                }
+            }
+            if (*p == '{') { /* Simple format char */
+                np = strchr(p, '}');
+                if (np != NULL && np-p > 1 && np-p < LOG_NODE_STRLEN-2) {
+                    p++;
+                    n = np-p;
+                    strlcpy(node->data, p, n+1);
+                    p = np;
+                } else {
+                    goto parsererror;
+                }
+                p++;
+            } else {
+                node->data[0] = '\0';
+            }
+            node->type = *p;
+            if (*p == '%'){
+                node->type = LOG_CF_LITERAL;
+                strlcpy(node->data, "%", 2);
+            }
+            p++;
+        }
+        LogCustomFormatAddNode(cf, node);
+
+    }
+    return 1;
+
+parsererror:
+    LogCustomFormatNodeFree(node);
+    return 0;
+
+}
+
+/**
+ *  \brief Adds a node to custom format
+ *  \param LogCustomFormat * cf - custom format
+ *  \param LogCustomFormatNode * node - node to add
+ */
+void LogCustomFormatAddNode(LogCustomFormat *cf, LogCustomFormatNode *node)
+{
+    if (cf == NULL || node == NULL)
+        return;
+
+    if (cf->cf_n == LOG_MAXN_NODES) {
+        SCLogWarning(SC_WARN_LOG_CF_TOO_MANY_NODES, "Too many options for custom format");
+        return;
+    }
+
+#ifdef DEBUG
+    SCLogDebug("%d-> n.type=[%d] n.maxlen=[%d] n.data=[%s]",
+            cf->cf_n, node->type, node->maxlen, node->data);
+#endif
+
+    cf->cf_nodes[cf->cf_n] = node;
+    cf->cf_n++;
+}
+
+/**
+ *  \brief Writes a timestamp with given format into a MemBuffer
+ *  \param MemBuffer * buffer - where to write
+ *  \param const char * fmt - format to be used write timestamp
+ *  \param const struct timeveal *ts  - the timetstamp
+ *
+ */
+void LogCustomFormatWriteTimestamp(MemBuffer *buffer, const char *fmt, const struct timeval *ts) {
+
+    time_t time = ts->tv_sec;
+    struct tm local_tm;
+    struct tm *timestamp = SCLocalTime(time, &local_tm);
+    char buf[128] = {0};
+    const char * fmt_to_use = TIMESTAMP_DEFAULT_FORMAT;
+
+    if (fmt && *fmt != '\0') {
+        fmt_to_use = fmt;
+    }
+
+    CreateFormattedTimeString (timestamp, fmt_to_use, buf, sizeof(buf));
+    PrintRawUriBuf((char *)buffer->buffer, &buffer->offset,
+                   buffer->size, (uint8_t *)buf,strlen(buf));
+}
+
+
+#ifdef UNITTESTS
+/**
+ * \internal
+ * \brief This test tests default timestamp format
+ */
+static int LogCustomFormatTest01(void)
+{
+
+    struct tm tm;
+    tm.tm_sec = 0;
+    tm.tm_min = 30;
+    tm.tm_hour = 4;
+    tm.tm_mday = 13;
+    tm.tm_mon = 0;
+    tm.tm_year = 114;
+    tm.tm_wday = 1;
+    tm.tm_yday = 13;
+    tm.tm_isdst = 0;
+    time_t secs = mktime(&tm);
+    struct timeval ts = {secs, 0};
+
+    MemBuffer *buffer = MemBufferCreateNew(62);
+    if (!buffer) {
+        return 0;
+    }
+
+    LogCustomFormatWriteTimestamp(buffer, "", &ts);
+    /*
+     * {buffer = "01/13/14-04:30:00", size = 62, offset = 17}
+     */
+    FAIL_IF_NOT( buffer->offset == 17);
+    FAIL_IF(strcmp((char *)buffer->buffer, "01/13/14-04:30:00") != 0);
+
+    MemBufferFree(buffer);
+
+    return 1;
+}
+
+void LogCustomFormatRegisterTests(void)
+{
+    UtRegisterTest("LogCustomFormatTest01", LogCustomFormatTest01);
+}
+#endif /* UNITTESTS */
+
+void LogCustomFormatRegister(void)
+{
+#ifdef UNITTESTS
+    LogCustomFormatRegisterTests();
+#endif /* UNITTESTS */
+}
diff --git a/src/log-cf-common.h b/src/log-cf-common.h
new file mode 100644 (file)
index 0000000..ad66754
--- /dev/null
@@ -0,0 +1,81 @@
+/* Copyright (C) 2016 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 Victor Julien <victor@inliniac.net>
+ * \author Ignacio Sanchez <sanchezmartin.ji@gmail.com>
+ * \author Paulo Pacheco <fooinha@gmail.com>
+ *
+ * Common custom loggging format
+ */
+
+#ifndef __LOG_CF_COMMON_H__
+#define __LOG_CF_COMMON_H__
+
+#define LOG_MAXN_NODES 64
+#define LOG_NODE_STRLEN 256
+#define LOG_NODE_MAXOUTPUTLEN 8192
+
+#define TIMESTAMP_DEFAULT_FORMAT "%D-%H:%M:%S"
+#define TIMESTAMP_DEFAULT_FORMAT_LEN 62
+
+/* Common format nodes */
+#define LOG_CF_NONE "-"
+#define LOG_CF_LITERAL '%'
+#define LOG_CF_TIMESTAMP 't'
+#define LOG_CF_TIMESTAMP_U 'z'
+#define LOG_CF_CLIENT_IP 'a'
+#define LOG_CF_SERVER_IP 'A'
+#define LOG_CF_CLIENT_PORT 'p'
+#define LOG_CF_SERVER_PORT 'P'
+
+/* Line log common separators **/
+#define LOG_CF_STAR_SEPARATOR "[**]"
+#define LOG_CF_WRITE_STAR_SEPATATOR(buffer) \
+    MemBufferWriteString(buffer, LOG_CF_STAR_SEPARATOR);
+
+/* Include */
+#include "suricata-common.h"
+#include "util-buffer.h"
+
+typedef struct LogCustomFormatNode_ {
+    uint32_t type;              /**< Node format type. ie: LOG_CF_LITERAL, ... */
+    uint32_t maxlen;            /**< Maximun length of the data */
+    char data[LOG_NODE_STRLEN]; /**< optional data. ie: http header name */
+} LogCustomFormatNode;
+
+
+typedef struct LogCustomFormat_ {
+    uint32_t cf_n;                                  /**< Total number of custom string format nodes */
+    LogCustomFormatNode *cf_nodes[LOG_MAXN_NODES];  /**< Custom format string nodes */
+} LogCustomFormat;
+
+LogCustomFormatNode * LogCustomFormatNodeAlloc(void);
+LogCustomFormat * LogCustomFormatAlloc(void);
+
+void LogCustomFormatNodeFree(LogCustomFormatNode *node);
+void LogCustomFormatFree(LogCustomFormat *cf);
+
+void LogCustomFormatAddNode(LogCustomFormat *cf, LogCustomFormatNode *node);
+int LogCustomFormatParse(LogCustomFormat *cf, const char *format);
+
+void LogCustomFormatWriteTimestamp(MemBuffer *buffer, const char *fmt, const struct timeval *ts);
+void LogCustomFormatRegister(void);
+
+#endif /* __LOG_CF_COMMON_H__ */
index a825ae40232fa61a0aed3b814145e53e200b9d03..a26a2f6730239dc425662328833ea3bdefff0da6 100644 (file)
@@ -49,6 +49,7 @@
 
 #include "util-logopenfile.h"
 #include "util-time.h"
+#include "log-cf-common.h"
 
 #define DEFAULT_LOG_FILENAME "http.log"
 
@@ -69,13 +70,6 @@ void LogHttpLogRegister (void)
         LogHttpLogThreadDeinit, NULL);
 }
 
-#define LOG_HTTP_MAXN_NODES 64
-#define LOG_HTTP_NODE_STRLEN 256
-#define LOG_HTTP_NODE_MAXOUTPUTLEN 8192
-
-#define TIMESTAMP_DEFAULT_FORMAT "%b %d, %Y; %H:%M:%S"
-#define LOG_HTTP_CF_NONE "-"
-#define LOG_HTTP_CF_LITERAL '%'
 #define LOG_HTTP_CF_REQUEST_HOST 'h'
 #define LOG_HTTP_CF_REQUEST_PROTOCOL 'H'
 #define LOG_HTTP_CF_REQUEST_METHOD 'm'
@@ -87,24 +81,12 @@ void LogHttpLogRegister (void)
 #define LOG_HTTP_CF_RESPONSE_STATUS 's'
 #define LOG_HTTP_CF_RESPONSE_HEADER 'o'
 #define LOG_HTTP_CF_RESPONSE_LEN 'B'
-#define LOG_HTTP_CF_TIMESTAMP 't'
-#define LOG_HTTP_CF_TIMESTAMP_U 'z'
-#define LOG_HTTP_CF_CLIENT_IP 'a'
-#define LOG_HTTP_CF_SERVER_IP 'A'
-#define LOG_HTTP_CF_CLIENT_PORT 'p'
-#define LOG_HTTP_CF_SERVER_PORT 'P'
-
-typedef struct LogHttpCustomFormatNode_ {
-    uint32_t type; /** Node format type. ie: LOG_HTTP_CF_LITERAL, LOG_HTTP_CF_REQUEST_HEADER */
-    uint32_t maxlen; /** Maximun length of the data */
-    char data[LOG_HTTP_NODE_STRLEN]; /** optional data. ie: http header name */
-} LogHttpCustomFormatNode;
+
 
 typedef struct LogHttpFileCtx_ {
     LogFileCtx *file_ctx;
     uint32_t flags; /** Store mode */
-    uint32_t cf_n; /** Total number of custom string format nodes */
-    LogHttpCustomFormatNode *cf_nodes[LOG_HTTP_MAXN_NODES]; /** Custom format string nodes */
+    LogCustomFormat *cf;
 } LogHttpFileCtx;
 
 #define LOG_HTTP_DEFAULT 0
@@ -160,49 +142,44 @@ static void LogHttpLogCustom(LogHttpLogThread *aft, htp_tx_t *tx, const struct t
     htp_header_t *h_request_hdr;
     htp_header_t *h_response_hdr;
 
-    time_t time = ts->tv_sec;
-    struct tm local_tm;
-    struct tm *timestamp = SCLocalTime(time, &local_tm);
-
-    for (i = 0; i < httplog_ctx->cf_n; i++) {
+    for (i = 0; i < httplog_ctx->cf->cf_n; i++) {
         h_request_hdr = NULL;
         h_response_hdr = NULL;
-        switch (httplog_ctx->cf_nodes[i]->type){
-            case LOG_HTTP_CF_LITERAL:
+
+        LogCustomFormatNode * node = httplog_ctx->cf->cf_nodes[i];
+        if (! node) /* Should never happen */
+            continue;
+
+        switch (node->type){
+            case LOG_CF_LITERAL:
             /* LITERAL */
-                MemBufferWriteString(aft->buffer, "%s", httplog_ctx->cf_nodes[i]->data);
+                MemBufferWriteString(aft->buffer, "%s", node->data);
                 break;
-            case LOG_HTTP_CF_TIMESTAMP:
+            case LOG_CF_TIMESTAMP:
             /* TIMESTAMP */
-                if (httplog_ctx->cf_nodes[i]->data[0] == '\0') {
-                    strftime(buf, 62, TIMESTAMP_DEFAULT_FORMAT, timestamp);
-                } else {
-                    strftime(buf, 62, httplog_ctx->cf_nodes[i]->data, timestamp);
-                }
-                PrintRawUriBuf((char *)aft->buffer->buffer, &aft->buffer->offset,
-                            aft->buffer->size, (uint8_t *)buf,strlen(buf));
+                LogCustomFormatWriteTimestamp(aft->buffer, node->data, ts);
                 break;
-            case LOG_HTTP_CF_TIMESTAMP_U:
+            case LOG_CF_TIMESTAMP_U:
             /* TIMESTAMP USECONDS */
-                snprintf(buf, 62, "%06u", (unsigned int) ts->tv_usec);
+                snprintf(buf, 6, "%06u", (unsigned int) ts->tv_usec);
                 PrintRawUriBuf((char *)aft->buffer->buffer, &aft->buffer->offset,
                             aft->buffer->size, (uint8_t *)buf,strlen(buf));
                 break;
-            case LOG_HTTP_CF_CLIENT_IP:
+            case LOG_CF_CLIENT_IP:
             /* CLIENT IP ADDRESS */
                 PrintRawUriBuf((char *)aft->buffer->buffer, &aft->buffer->offset,
                             aft->buffer->size, (uint8_t *)srcip,strlen(srcip));
                 break;
-            case LOG_HTTP_CF_SERVER_IP:
+            case LOG_CF_SERVER_IP:
             /* SERVER IP ADDRESS */
                 PrintRawUriBuf((char *)aft->buffer->buffer, &aft->buffer->offset,
                             aft->buffer->size, (uint8_t *)dstip,strlen(dstip));
                 break;
-            case LOG_HTTP_CF_CLIENT_PORT:
+            case LOG_CF_CLIENT_PORT:
             /* CLIENT PORT */
                 MemBufferWriteString(aft->buffer, "%" PRIu16 "", sp);
                 break;
-            case LOG_HTTP_CF_SERVER_PORT:
+            case LOG_CF_SERVER_PORT:
             /* SERVER PORT */
                 MemBufferWriteString(aft->buffer, "%" PRIu16 "", dp);
                 break;
@@ -213,13 +190,13 @@ static void LogHttpLogCustom(LogHttpLogThread *aft, htp_tx_t *tx, const struct t
                                 aft->buffer->size, (uint8_t *)bstr_ptr(tx->request_method),
                                 bstr_len(tx->request_method));
                 } else {
-                    MemBufferWriteString(aft->buffer, LOG_HTTP_CF_NONE);
+                    MemBufferWriteString(aft->buffer, LOG_CF_NONE);
                 }
                 break;
             case LOG_HTTP_CF_REQUEST_URI:
             /* URI */
                 if (tx->request_uri != NULL) {
-                    datalen = httplog_ctx->cf_nodes[i]->maxlen;
+                    datalen = node->maxlen;
                     if (datalen == 0 || datalen > bstr_len(tx->request_uri)) {
                         datalen = bstr_len(tx->request_uri);
                     }
@@ -227,14 +204,14 @@ static void LogHttpLogCustom(LogHttpLogThread *aft, htp_tx_t *tx, const struct t
                                 aft->buffer->size, (uint8_t *)bstr_ptr(tx->request_uri),
                                 datalen);
                 } else {
-                    MemBufferWriteString(aft->buffer, LOG_HTTP_CF_NONE);
+                    MemBufferWriteString(aft->buffer, LOG_CF_NONE);
                 }
                 break;
             case LOG_HTTP_CF_REQUEST_HOST:
             /* HOSTNAME */
                 if (tx->request_hostname != NULL)
                 {
-                    datalen = httplog_ctx->cf_nodes[i]->maxlen;
+                    datalen = node->maxlen;
                     if (datalen == 0 || datalen > bstr_len(tx->request_hostname)) {
                         datalen = bstr_len(tx->request_hostname);
                     }
@@ -242,7 +219,7 @@ static void LogHttpLogCustom(LogHttpLogThread *aft, htp_tx_t *tx, const struct t
                                 aft->buffer->size, (uint8_t *)bstr_ptr(tx->request_hostname),
                                 datalen);
                 } else {
-                    MemBufferWriteString(aft->buffer, LOG_HTTP_CF_NONE);
+                    MemBufferWriteString(aft->buffer, LOG_CF_NONE);
                 }
                 break;
             case LOG_HTTP_CF_REQUEST_PROTOCOL:
@@ -252,16 +229,16 @@ static void LogHttpLogCustom(LogHttpLogThread *aft, htp_tx_t *tx, const struct t
                                     aft->buffer->size, (uint8_t *)bstr_ptr(tx->request_protocol),
                                     bstr_len(tx->request_protocol));
                 } else {
-                    MemBufferWriteString(aft->buffer, LOG_HTTP_CF_NONE);
+                    MemBufferWriteString(aft->buffer, LOG_CF_NONE);
                 }
                 break;
             case LOG_HTTP_CF_REQUEST_HEADER:
             /* REQUEST HEADER */
                 if (tx->request_headers != NULL) {
-                    h_request_hdr = htp_table_get_c(tx->request_headers, httplog_ctx->cf_nodes[i]->data);
+                    h_request_hdr = htp_table_get_c(tx->request_headers, node->data);
                 }
                 if (h_request_hdr != NULL) {
-                    datalen = httplog_ctx->cf_nodes[i]->maxlen;
+                    datalen = node->maxlen;
                     if (datalen == 0 || datalen > bstr_len(h_request_hdr->value)) {
                         datalen = bstr_len(h_request_hdr->value);
                     }
@@ -269,7 +246,7 @@ static void LogHttpLogCustom(LogHttpLogThread *aft, htp_tx_t *tx, const struct t
                                     aft->buffer->size, (uint8_t *)bstr_ptr(h_request_hdr->value),
                                     datalen);
                 } else {
-                    MemBufferWriteString(aft->buffer, LOG_HTTP_CF_NONE);
+                    MemBufferWriteString(aft->buffer, LOG_CF_NONE);
                 }
                 break;
             case LOG_HTTP_CF_REQUEST_COOKIE:
@@ -278,19 +255,19 @@ static void LogHttpLogCustom(LogHttpLogThread *aft, htp_tx_t *tx, const struct t
                     h_request_hdr = htp_table_get_c(tx->request_headers, "Cookie");
                     if (h_request_hdr != NULL) {
                         cvalue_len = GetCookieValue((uint8_t *) bstr_ptr(h_request_hdr->value),
-                                    bstr_len(h_request_hdr->value), (char *) httplog_ctx->cf_nodes[i]->data,
+                                    bstr_len(h_request_hdr->value), (char *) node->data,
                                     &cvalue);
                     }
                 }
                 if (cvalue_len > 0 && cvalue != NULL) {
-                    datalen = httplog_ctx->cf_nodes[i]->maxlen;
+                    datalen = node->maxlen;
                     if (datalen == 0 || datalen > cvalue_len) {
                         datalen = cvalue_len;
                     }
                     PrintRawUriBuf((char *)aft->buffer->buffer, &aft->buffer->offset,
                                     aft->buffer->size, cvalue, datalen);
                 } else {
-                    MemBufferWriteString(aft->buffer, LOG_HTTP_CF_NONE);
+                    MemBufferWriteString(aft->buffer, LOG_CF_NONE);
                 }
                 break;
             case LOG_HTTP_CF_REQUEST_LEN:
@@ -304,17 +281,17 @@ static void LogHttpLogCustom(LogHttpLogThread *aft, htp_tx_t *tx, const struct t
                                     aft->buffer->size, (uint8_t *)bstr_ptr(tx->response_status),
                                     bstr_len(tx->response_status));
                 } else {
-                    MemBufferWriteString(aft->buffer, LOG_HTTP_CF_NONE);
+                    MemBufferWriteString(aft->buffer, LOG_CF_NONE);
                 }
                 break;
             case LOG_HTTP_CF_RESPONSE_HEADER:
             /* RESPONSE HEADER */
                 if (tx->response_headers != NULL) {
                     h_response_hdr = htp_table_get_c(tx->response_headers,
-                                    httplog_ctx->cf_nodes[i]->data);
+                                    node->data);
                 }
                 if (h_response_hdr != NULL) {
-                    datalen = httplog_ctx->cf_nodes[i]->maxlen;
+                    datalen = node->maxlen;
                     if (datalen == 0 || datalen > bstr_len(h_response_hdr->value)) {
                         datalen = bstr_len(h_response_hdr->value);
                     }
@@ -322,7 +299,7 @@ static void LogHttpLogCustom(LogHttpLogThread *aft, htp_tx_t *tx, const struct t
                                     aft->buffer->size, (uint8_t *)bstr_ptr(h_response_hdr->value),
                                     datalen);
                 } else {
-                    MemBufferWriteString(aft->buffer, LOG_HTTP_CF_NONE);
+                    MemBufferWriteString(aft->buffer, LOG_CF_NONE);
                 }
                 break;
             case LOG_HTTP_CF_RESPONSE_LEN:
@@ -331,8 +308,8 @@ static void LogHttpLogCustom(LogHttpLogThread *aft, htp_tx_t *tx, const struct t
                 break;
             default:
             /* NO MATCH */
-                MemBufferWriteString(aft->buffer, LOG_HTTP_CF_NONE);
-                SCLogDebug("No matching parameter %%%c for custom http log.", httplog_ctx->cf_nodes[i]->type);
+                MemBufferWriteString(aft->buffer, LOG_CF_NONE);
+                SCLogDebug("No matching parameter %%%c for custom http log.", node->type);
                 break;
         }
     }
@@ -341,7 +318,7 @@ static void LogHttpLogCustom(LogHttpLogThread *aft, htp_tx_t *tx, const struct t
 
 static void LogHttpLogExtended(LogHttpLogThread *aft, htp_tx_t *tx)
 {
-    MemBufferWriteString(aft->buffer, " [**] ");
+    LOG_CF_WRITE_STAR_SEPATATOR(aft->buffer);
 
     /* referer */
     htp_header_t *h_referer = NULL;
@@ -355,7 +332,8 @@ static void LogHttpLogExtended(LogHttpLogThread *aft, htp_tx_t *tx)
     } else {
         MemBufferWriteString(aft->buffer, "<no referer>");
     }
-    MemBufferWriteString(aft->buffer, " [**] ");
+
+    LOG_CF_WRITE_STAR_SEPATATOR(aft->buffer);
 
     /* method */
     if (tx->request_method != NULL) {
@@ -363,7 +341,7 @@ static void LogHttpLogExtended(LogHttpLogThread *aft, htp_tx_t *tx)
                        (uint8_t *)bstr_ptr(tx->request_method),
                        bstr_len(tx->request_method));
     }
-    MemBufferWriteString(aft->buffer, " [**] ");
+    LOG_CF_WRITE_STAR_SEPATATOR(aft->buffer);
 
     /* protocol */
     if (tx->request_protocol != NULL) {
@@ -373,7 +351,7 @@ static void LogHttpLogExtended(LogHttpLogThread *aft, htp_tx_t *tx)
     } else {
         MemBufferWriteString(aft->buffer, "<no protocol>");
     }
-    MemBufferWriteString(aft->buffer, " [**] ");
+    LOG_CF_WRITE_STAR_SEPATATOR(aft->buffer);
 
     /* response status */
     if (tx->response_status != NULL) {
@@ -396,7 +374,8 @@ static void LogHttpLogExtended(LogHttpLogThread *aft, htp_tx_t *tx)
     }
 
     /* length */
-    MemBufferWriteString(aft->buffer, " [**] %"PRIuMAX" bytes", (uintmax_t)tx->response_message_len);
+    LOG_CF_WRITE_STAR_SEPATATOR(aft->buffer);
+    MemBufferWriteString(aft->buffer, "%"PRIuMAX" bytes", (uintmax_t)tx->response_message_len);
 }
 
 static TmEcode LogHttpLogIPWrapper(ThreadVars *tv, void *data, const Packet *p, Flow *f, HtpState *htp_state, htp_tx_t *tx, uint64_t tx_id, int ipproto)
@@ -463,7 +442,7 @@ static TmEcode LogHttpLogIPWrapper(ThreadVars *tv, void *data, const Packet *p,
         } else {
             MemBufferWriteString(aft->buffer, "<hostname unknown>");
         }
-        MemBufferWriteString(aft->buffer, " [**] ");
+        LOG_CF_WRITE_STAR_SEPATATOR(aft->buffer);
 
         /* uri */
         if (tx->request_uri != NULL) {
@@ -471,7 +450,7 @@ static TmEcode LogHttpLogIPWrapper(ThreadVars *tv, void *data, const Packet *p,
                     (uint8_t *)bstr_ptr(tx->request_uri),
                     bstr_len(tx->request_uri));
         }
-        MemBufferWriteString(aft->buffer, " [**] ");
+        LOG_CF_WRITE_STAR_SEPATATOR(aft->buffer);
 
         /* user agent */
         htp_header_t *h_user_agent = NULL;
@@ -490,8 +469,9 @@ static TmEcode LogHttpLogIPWrapper(ThreadVars *tv, void *data, const Packet *p,
         }
 
         /* ip/tcp header info */
+        LOG_CF_WRITE_STAR_SEPATATOR(aft->buffer);
         MemBufferWriteString(aft->buffer,
-                " [**] %s:%" PRIu16 " -> %s:%" PRIu16 "\n",
+                "%s:%" PRIu16 " -> %s:%" PRIu16 "\n",
                 srcip, sp, dstip, dp);
     }
 
@@ -572,8 +552,6 @@ TmEcode LogHttpLogThreadDeinit(ThreadVars *t, void *data)
 OutputCtx *LogHttpLogInitCtx(ConfNode *conf)
 {
     LogFileCtx* file_ctx = LogFileNewCtx();
-    const char *p, *np;
-    uint32_t n;
     if(file_ctx == NULL) {
         SCLogError(SC_ERR_HTTP_LOG_GENERIC, "couldn't create new file_ctx");
         return NULL;
@@ -592,7 +570,6 @@ OutputCtx *LogHttpLogInitCtx(ConfNode *conf)
     memset(httplog_ctx, 0x00, sizeof(LogHttpFileCtx));
 
     httplog_ctx->file_ctx = file_ctx;
-    httplog_ctx->cf_n=0;
 
     const char *extended = ConfNodeLookupChildValue(conf, "extended");
     const char *custom = ConfNodeLookupChildValue(conf, "custom");
@@ -600,74 +577,17 @@ OutputCtx *LogHttpLogInitCtx(ConfNode *conf)
 
     /* If custom logging format is selected, lets parse it */
     if (custom != NULL && customformat != NULL && ConfValIsTrue(custom)) {
-        p=customformat;
+
+        httplog_ctx->cf = LogCustomFormatAlloc();
+        if (!httplog_ctx->cf) {
+            goto errorfree;
+        }
+
         httplog_ctx->flags |= LOG_HTTP_CUSTOM;
-        for (httplog_ctx->cf_n = 0; httplog_ctx->cf_n < LOG_HTTP_MAXN_NODES-1 && p && *p != '\0';
-                                                    httplog_ctx->cf_n++){
-            httplog_ctx->cf_nodes[httplog_ctx->cf_n] = SCMalloc(sizeof(LogHttpCustomFormatNode));
-            if (httplog_ctx->cf_nodes[httplog_ctx->cf_n] == NULL) {
-                for (n = 0; n < httplog_ctx->cf_n; n++) {
-                    SCFree(httplog_ctx->cf_nodes[n]);
-                }
-                LogFileFreeCtx(file_ctx);
-                SCFree(httplog_ctx);
-                return NULL;
-            }
-            httplog_ctx->cf_nodes[httplog_ctx->cf_n]->maxlen = 0;
-
-            if (*p != '%'){
-                /* Literal found in format string */
-                httplog_ctx->cf_nodes[httplog_ctx->cf_n]->type = LOG_HTTP_CF_LITERAL;
-                np = strchr(p, '%');
-                if (np == NULL){
-                    n = LOG_HTTP_NODE_STRLEN-2;
-                    np = NULL; /* End */
-                }else{
-                    n = np-p;
-                }
-                strlcpy(httplog_ctx->cf_nodes[httplog_ctx->cf_n]->data,p,n+1);
-                p = np;
-            } else {
-                /* Non Literal found in format string */
-                p++;
-                if (*p == '[') { /* Check if maxlength has been specified (ie: [25]) */
-                    p++;
-                    np = strchr(p, ']');
-                    if (np != NULL) {
-                        if (np-p > 0 && np-p < 10){
-                            long maxlen = strtol(p,NULL,10);
-                            if (maxlen > 0 && maxlen < LOG_HTTP_NODE_MAXOUTPUTLEN) {
-                                httplog_ctx->cf_nodes[httplog_ctx->cf_n]->maxlen = (uint32_t) maxlen;
-                            }
-                        } else {
-                            goto parsererror;
-                        }
-                        p = np + 1;
-                    } else {
-                        goto parsererror;
-                    }
-                }
-                if (*p == '{') { /* Simple format char */
-                    np = strchr(p, '}');
-                    if (np != NULL && np-p > 1 && np-p < LOG_HTTP_NODE_STRLEN-2) {
-                        p++;
-                        n = np-p;
-                        strlcpy(httplog_ctx->cf_nodes[httplog_ctx->cf_n]->data, p, n+1);
-                        p = np;
-                    } else {
-                        goto parsererror;
-                    }
-                    p++;
-                } else {
-                    httplog_ctx->cf_nodes[httplog_ctx->cf_n]->data[0] = '\0';
-                }
-                httplog_ctx->cf_nodes[httplog_ctx->cf_n]->type = *p;
-                if (*p == '%'){
-                    httplog_ctx->cf_nodes[httplog_ctx->cf_n]->type = LOG_HTTP_CF_LITERAL;
-                    strlcpy(httplog_ctx->cf_nodes[httplog_ctx->cf_n]->data, "%", 2);
-                }
-                p++;
-            }
+
+        /* Parsing */
+        if ( ! LogCustomFormatParse(httplog_ctx->cf, customformat)) {
+            goto parsererror;
         }
     } else {
         if (extended == NULL) {
@@ -695,12 +615,11 @@ OutputCtx *LogHttpLogInitCtx(ConfNode *conf)
     return output_ctx;
 
 parsererror:
-    for (n = 0;n < httplog_ctx->cf_n;n++) {
-        SCFree(httplog_ctx->cf_nodes[n]);
-    }
+    SCLogError(SC_ERR_INVALID_ARGUMENT,"Syntax error in custom http log format string.");
+errorfree:
+    LogCustomFormatFree(httplog_ctx->cf);
     LogFileFreeCtx(file_ctx);
     SCFree(httplog_ctx);
-    SCLogError(SC_ERR_INVALID_ARGUMENT,"Syntax error in custom http log format string.");
     return NULL;
 
 }
@@ -708,10 +627,7 @@ parsererror:
 static void LogHttpLogDeInitCtx(OutputCtx *output_ctx)
 {
     LogHttpFileCtx *httplog_ctx = (LogHttpFileCtx *)output_ctx->data;
-    uint32_t i;
-    for (i = 0; i < httplog_ctx->cf_n; i++) {
-        SCFree(httplog_ctx->cf_nodes[i]);
-    }
+    LogCustomFormatFree(httplog_ctx->cf);
     LogFileFreeCtx(httplog_ctx->file_ctx);
     SCFree(httplog_ctx);
     SCFree(output_ctx);
index 3c509f2662464cd2fb5eb601d777daa27878344e..6ee3dc15cbaa570a6705adffccf4d5294480392b 100644 (file)
@@ -48,6 +48,7 @@
 #include "output-json-alert.h"
 #include "output-json-flow.h"
 #include "output-json-netflow.h"
+#include "log-cf-common.h"
 #include "log-droplog.h"
 #include "output-json-drop.h"
 #include "log-httplog.h"
@@ -1025,6 +1026,9 @@ void OutputRegisterRootLoggers(void)
  */
 void OutputRegisterLoggers(void)
 {
+    /* custom format log*/
+    LogCustomFormatRegister();
+
     LuaLogRegister();
     /* fast log */
     AlertFastLogRegister();
index 197255bd3126b8db25af57387a1939b8df840fcc..7b7aa7afc352b586804a17732f1bc4aa96b81595 100644 (file)
@@ -338,6 +338,7 @@ const char * SCErrorToString(SCError err)
         CASE_CODE (SC_ERR_REDIS);
         CASE_CODE (SC_ERR_VAR_LIMIT);
         CASE_CODE (SC_WARN_CHMOD);
+        CASE_CODE (SC_WARN_LOG_CF_TOO_MANY_NODES);
     }
 
     return "UNKNOWN_ERROR";
index 186133fa30a75f3d937d9863685a98e9dcadcd14..85e174abbe0746d2844d5caf9ce41d5b53b314c0 100644 (file)
@@ -328,6 +328,7 @@ typedef enum {
     SC_ERR_VAR_LIMIT,
     SC_WARN_DUPLICATE_OUTPUT,
     SC_WARN_CHMOD,
+    SC_WARN_LOG_CF_TOO_MANY_NODES,
 } SCError;
 
 const char *SCErrorToString(SCError);
index b1726e81c5781f5d2337c60532ed2559cf579167..0dd00953a1ca577a3c2d04c64f10d28347480bfa 100644 (file)
@@ -208,6 +208,15 @@ void CreateUtcIsoTimeString (const struct timeval *ts, char *str, size_t size)
     }
 }
 
+void CreateFormattedTimeString (const struct tm *t, const char *fmt, char *str, size_t size)
+{
+    if (likely(t != NULL) && likely(fmt != NULL) && likely(str != NULL) ) {
+        strftime(str, size, fmt, t);
+    } else {
+        snprintf(str, size, "ts-error");
+    }
+}
+
 struct tm *SCUtcTime(time_t timep, struct tm *result)
 {
     return gmtime_r(&timep, result);
index fa71cf565b4b468945faa6f21fb8f96acd08d27a..3d76642210c1097f43fc466fda32bea6557d0d96 100644 (file)
@@ -51,11 +51,12 @@ void TimeModeSetOffline (void);
 int TimeModeIsLive(void);
 
 struct tm *SCLocalTime(time_t timep, struct tm *result);
-void CreateTimeString (const struct timeval *ts, char *str, size_t size);
-void CreateIsoTimeString (const struct timeval *ts, char *str, size_t size);
-void CreateUtcIsoTimeString (const struct timeval *ts, char *str, size_t size);
-time_t SCMkTimeUtc (struct tm *tp);
-int SCStringPatternToTime (char *string, char **patterns,
+void CreateTimeString(const struct timeval *ts, char *str, size_t size);
+void CreateIsoTimeString(const struct timeval *ts, char *str, size_t size);
+void CreateUtcIsoTimeString(const struct timeval *ts, char *str, size_t size);
+void CreateFormattedTimeString(const struct tm *t, const char * fmt, char *str, size_t size);
+time_t SCMkTimeUtc(struct tm *tp);
+int SCStringPatternToTime(char *string, char **patterns,
                            int num_patterns, struct tm *time);
 
 #endif /* __UTIL_TIME_H__ */