From: fooinha Date: Sat, 3 Dec 2016 12:22:26 +0000 (+0000) Subject: log: common custom format output X-Git-Tag: suricata-4.0.0-beta1~234 X-Git-Url: http://git.ipfire.org/gitweb.cgi?a=commitdiff_plain;h=af174c82bb127481055e7f84bf661e3b6d186ff6;p=thirdparty%2Fsuricata.git log: common custom format output --- diff --git a/src/Makefile.am b/src/Makefile.am index 26541ccedf..de7006d05f 100644 --- a/src/Makefile.am +++ b/src/Makefile.am @@ -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 index 0000000000..c85703f8af --- /dev/null +++ b/src/log-cf-common.c @@ -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 + * \author Victor Julien + * \author Ignacio Sanchez + * + * 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 index 0000000000..ad66754830 --- /dev/null +++ b/src/log-cf-common.h @@ -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 + * \author Ignacio Sanchez + * \author Paulo Pacheco + * + * 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__ */ diff --git a/src/log-httplog.c b/src/log-httplog.c index a825ae4023..a26a2f6730 100644 --- a/src/log-httplog.c +++ b/src/log-httplog.c @@ -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, ""); } - 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, ""); } - 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, ""); } - 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); diff --git a/src/output.c b/src/output.c index 3c509f2662..6ee3dc15cb 100644 --- a/src/output.c +++ b/src/output.c @@ -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(); diff --git a/src/util-error.c b/src/util-error.c index 197255bd31..7b7aa7afc3 100644 --- a/src/util-error.c +++ b/src/util-error.c @@ -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"; diff --git a/src/util-error.h b/src/util-error.h index 186133fa30..85e174abbe 100644 --- a/src/util-error.h +++ b/src/util-error.h @@ -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); diff --git a/src/util-time.c b/src/util-time.c index b1726e81c5..0dd00953a1 100644 --- a/src/util-time.c +++ b/src/util-time.c @@ -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); diff --git a/src/util-time.h b/src/util-time.h index fa71cf565b..3d76642210 100644 --- a/src/util-time.h +++ b/src/util-time.h @@ -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__ */