diff options
Diffstat (limited to '')
-rw-r--r-- | src/log-cf-common.c | 276 |
1 files changed, 276 insertions, 0 deletions
diff --git a/src/log-cf-common.c b/src/log-cf-common.c new file mode 100644 index 0000000..0778135 --- /dev/null +++ b/src/log-cf-common.c @@ -0,0 +1,276 @@ +/* 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" +#include "util-time.h" +#include "util-debug.h" + +/** + * \brief Creates a custom format node + * \retval LogCustomFormatNode * ptr if created + * \retval NULL if failed to allocate + */ +LogCustomFormatNode *LogCustomFormatNodeAlloc(void) +{ + LogCustomFormatNode * node = SCCalloc(1, sizeof(LogCustomFormatNode)); + if (unlikely(node == NULL)) { + SCLogError("Failed to alloc custom format node"); + return NULL; + } + return node; +} + +/** + * \brief Creates a custom format. + * \retval LogCustomFormat * ptr if created + * \retval NULL if failed to allocate + */ +LogCustomFormat *LogCustomFormatAlloc(void) +{ + LogCustomFormat * cf = SCCalloc(1, sizeof(LogCustomFormat)); + if (unlikely(cf == NULL)) { + SCLogError("Failed to alloc custom format"); + return NULL; + } + return cf; +} + +/** + * \brief Frees memory held by a custom format node + * \param LogCustomFormatNode * node - node to release + */ +void LogCustomFormatNodeFree(LogCustomFormatNode *node) +{ + if (node==NULL) + return; + + SCFree(node); +} + +/** + * \brief Frees memory held by a custom format + * \param LogCustomFormat * cf - format to release + */ +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("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 timestamp + * + */ +void LogCustomFormatWriteTimestamp(MemBuffer *buffer, const char *fmt, const SCTime_t ts) +{ + + time_t time = SCTIME_SECS(ts); + 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; + SCTime_t ts = SCTIME_FROM_SECS(mktime(&tm)); + + 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; +} + +static void LogCustomFormatRegisterTests(void) +{ + UtRegisterTest("LogCustomFormatTest01", LogCustomFormatTest01); +} +#endif /* UNITTESTS */ + +void LogCustomFormatRegister(void) +{ +#ifdef UNITTESTS + LogCustomFormatRegisterTests(); +#endif /* UNITTESTS */ +} |