suricata
log-cf-common.c
Go to the documentation of this file.
1 /* Copyright (C) 2007-2016 Open Information Security Foundation
2  *
3  * You can copy, redistribute or modify this Program under the terms of
4  * the GNU General Public License version 2 as published by the Free
5  * Software Foundation.
6  *
7  * This program is distributed in the hope that it will be useful,
8  * but WITHOUT ANY WARRANTY; without even the implied warranty of
9  * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
10  * GNU General Public License for more details.
11  *
12  * You should have received a copy of the GNU General Public License
13  * version 2 along with this program; if not, write to the Free Software
14  * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA
15  * 02110-1301, USA.
16  */
17 
18 /**
19  * \file
20  *
21  * \author Paulo Pacheco <fooinha@gmail.com>
22  * \author Victor Julien <victor@inliniac.net>
23  * \author Ignacio Sanchez <sanchezmartin.ji@gmail.com>
24  *
25  * Common custom logging format
26  */
27 
28 #include "log-cf-common.h"
29 #include "util-print.h"
30 #include "util-unittest.h"
31 
32 /**
33  * \brief Creates a custom format node
34  * \retval LogCustomFormatNode * ptr if created
35  * \retval NULL if failed to allocate
36  */
38 {
40  if (unlikely(node == NULL)) {
41  SCLogError(SC_ERR_MEM_ALLOC, "Failed to alloc custom format node");
42  return NULL;
43  }
44  return node;
45 }
46 
47 /**
48  * \brief Creates a custom format.
49  * \retval LogCustomFormat * ptr if created
50  * \retval NULL if failed to allocate
51  */
53 {
54  LogCustomFormat * cf = SCCalloc(1, sizeof(LogCustomFormat));
55  if (unlikely(cf == NULL)) {
56  SCLogError(SC_ERR_MEM_ALLOC, "Failed to alloc custom format");
57  return NULL;
58  }
59  return cf;
60 }
61 
62 /**
63  * \brief Frees memory held by a custom format node
64  * \param LogCustomFormatNode * node - node to relaease
65  */
67 {
68  if (node==NULL)
69  return;
70 
71  SCFree(node);
72 }
73 
74 /**
75  * \brief Frees memory held by a custom format
76  * \param LogCustomFormat * cf - format to relaease
77  */
79 {
80  if (cf==NULL)
81  return;
82 
83  for (size_t i = 0; i < cf->cf_n; ++i) {
85  }
86  SCFree(cf);
87 }
88 
89 /**
90  * \brief Parses and saves format nodes for custom format
91  * \param LogCustomFormat * cf - custom format to build
92  * \param const char * format - string with format specification
93  */
94 int LogCustomFormatParse(LogCustomFormat *cf, const char *format)
95 {
96  const char *p, *np;
97  uint32_t n;
98  LogCustomFormatNode *node = NULL;
99 
100  if (cf==NULL)
101  return 0;
102 
103  if (format==NULL)
104  return 0;
105 
106  p=format;
107 
108  for (cf->cf_n = 0; cf->cf_n < LOG_MAXN_NODES-1 && p && *p != '\0';){
109 
110  node = LogCustomFormatNodeAlloc();
111  if (node == NULL) {
112  goto parsererror;
113  }
114  node->maxlen = 0;
115 
116  if (*p != '%'){
117  /* Literal found in format string */
118  node->type = LOG_CF_LITERAL;
119  np = strchr(p, '%');
120  if (np == NULL){
121  n = LOG_NODE_STRLEN-2;
122  np = NULL; /* End */
123  }else{
124  n = np-p;
125  }
126  strlcpy(node->data,p,n+1);
127  p = np;
128  } else {
129  /* Non Literal found in format string */
130  p++;
131  if (*p == '[') { /* Check if maxlength has been specified (ie: [25]) */
132  p++;
133  np = strchr(p, ']');
134  if (np != NULL) {
135  if (np-p > 0 && np-p < 10){
136  long maxlen = strtol(p,NULL,10);
137  if (maxlen > 0 && maxlen < LOG_NODE_MAXOUTPUTLEN) {
138  node->maxlen = (uint32_t) maxlen;
139  }
140  } else {
141  goto parsererror;
142  }
143  p = np + 1;
144  } else {
145  goto parsererror;
146  }
147  }
148  if (*p == '{') { /* Simple format char */
149  np = strchr(p, '}');
150  if (np != NULL && np-p > 1 && np-p < LOG_NODE_STRLEN-2) {
151  p++;
152  n = np-p;
153  strlcpy(node->data, p, n+1);
154  p = np;
155  } else {
156  goto parsererror;
157  }
158  p++;
159  } else {
160  node->data[0] = '\0';
161  }
162  node->type = *p;
163  if (*p == '%'){
164  node->type = LOG_CF_LITERAL;
165  strlcpy(node->data, "%", 2);
166  }
167  p++;
168  }
169  LogCustomFormatAddNode(cf, node);
170  }
171  return 1;
172 
173 parsererror:
175  return 0;
176 }
177 
178 /**
179  * \brief Adds a node to custom format
180  * \param LogCustomFormat * cf - custom format
181  * \param LogCustomFormatNode * node - node to add
182  */
184 {
185  if (cf == NULL || node == NULL)
186  return;
187 
188  if (cf->cf_n == LOG_MAXN_NODES) {
189  SCLogWarning(SC_WARN_LOG_CF_TOO_MANY_NODES, "Too many options for custom format");
190  return;
191  }
192 
193 #ifdef DEBUG
194  SCLogDebug("%d-> n.type=[%d] n.maxlen=[%d] n.data=[%s]",
195  cf->cf_n, node->type, node->maxlen, node->data);
196 #endif
197 
198  cf->cf_nodes[cf->cf_n] = node;
199  cf->cf_n++;
200 }
201 
202 /**
203  * \brief Writes a timestamp with given format into a MemBuffer
204  * \param MemBuffer * buffer - where to write
205  * \param const char * fmt - format to be used write timestamp
206  * \param const struct timeveal *ts - the timetstamp
207  *
208  */
209 void LogCustomFormatWriteTimestamp(MemBuffer *buffer, const char *fmt, const struct timeval *ts) {
210 
211  time_t time = ts->tv_sec;
212  struct tm local_tm;
213  struct tm *timestamp = SCLocalTime(time, &local_tm);
214  char buf[128] = {0};
215  const char * fmt_to_use = TIMESTAMP_DEFAULT_FORMAT;
216 
217  if (fmt && *fmt != '\0') {
218  fmt_to_use = fmt;
219  }
220 
221  CreateFormattedTimeString (timestamp, fmt_to_use, buf, sizeof(buf));
222  PrintRawUriBuf((char *)buffer->buffer, &buffer->offset,
223  buffer->size, (uint8_t *)buf,strlen(buf));
224 }
225 
226 #ifdef UNITTESTS
227 /**
228  * \internal
229  * \brief This test tests default timestamp format
230  */
231 static int LogCustomFormatTest01(void)
232 {
233  struct tm tm;
234  tm.tm_sec = 0;
235  tm.tm_min = 30;
236  tm.tm_hour = 4;
237  tm.tm_mday = 13;
238  tm.tm_mon = 0;
239  tm.tm_year = 114;
240  tm.tm_wday = 1;
241  tm.tm_yday = 13;
242  tm.tm_isdst = 0;
243  time_t secs = mktime(&tm);
244  struct timeval ts = {secs, 0};
245 
246  MemBuffer *buffer = MemBufferCreateNew(62);
247  if (!buffer) {
248  return 0;
249  }
250 
251  LogCustomFormatWriteTimestamp(buffer, "", &ts);
252  /*
253  * {buffer = "01/13/14-04:30:00", size = 62, offset = 17}
254  */
255  FAIL_IF_NOT( buffer->offset == 17);
256  FAIL_IF(strcmp((char *)buffer->buffer, "01/13/14-04:30:00") != 0);
257 
258  MemBufferFree(buffer);
259 
260  return 1;
261 }
262 
263 static void LogCustomFormatRegisterTests(void)
264 {
265  UtRegisterTest("LogCustomFormatTest01", LogCustomFormatTest01);
266 }
267 #endif /* UNITTESTS */
268 
270 {
271 #ifdef UNITTESTS
272  LogCustomFormatRegisterTests();
273 #endif /* UNITTESTS */
274 }
MemBuffer * MemBufferCreateNew(uint32_t size)
Definition: util-buffer.c:32
void LogCustomFormatRegister(void)
#define TIMESTAMP_DEFAULT_FORMAT
Definition: log-cf-common.h:35
#define SCLogDebug(...)
Definition: util-debug.h:335
int LogCustomFormatParse(LogCustomFormat *cf, const char *format)
Parses and saves format nodes for custom format.
Definition: log-cf-common.c:94
#define LOG_CF_LITERAL
Definition: log-cf-common.h:40
char data[LOG_NODE_STRLEN]
Definition: log-cf-common.h:69
size_t strlcpy(char *dst, const char *src, size_t siz)
Definition: util-strlcpyu.c:43
#define unlikely(expr)
Definition: util-optimize.h:35
#define FAIL_IF(expr)
Fail a test if expression evaluates to false.
Definition: util-unittest.h:71
#define LOG_NODE_STRLEN
Definition: log-cf-common.h:32
#define LOG_MAXN_NODES
Definition: log-cf-common.h:31
#define SCCalloc(nm, a)
Definition: util-mem.h:253
LogCustomFormatNode * cf_nodes[LOG_MAXN_NODES]
Definition: log-cf-common.h:75
struct tm * SCLocalTime(time_t timep, struct tm *result)
Definition: util-time.c:240
uint32_t size
Definition: util-buffer.h:29
#define SCLogError(err_code,...)
Macro used to log ERROR messages.
Definition: util-debug.h:294
void UtRegisterTest(const char *name, int(*TestFn)(void))
Register unit test.
uint8_t * buffer
Definition: util-buffer.h:28
#define SCLogWarning(err_code,...)
Macro used to log WARNING messages.
Definition: util-debug.h:281
void PrintRawUriBuf(char *retbuf, uint32_t *offset, uint32_t retbuflen, uint8_t *buf, uint32_t buflen)
Definition: util-print.c:118
#define SCFree(a)
Definition: util-mem.h:322
void CreateFormattedTimeString(const struct tm *t, const char *fmt, char *str, size_t size)
Definition: util-time.c:219
uint64_t ts
void LogCustomFormatAddNode(LogCustomFormat *cf, LogCustomFormatNode *node)
Adds a node to custom format.
void LogCustomFormatNodeFree(LogCustomFormatNode *node)
Frees memory held by a custom format node.
Definition: log-cf-common.c:66
#define LOG_NODE_MAXOUTPUTLEN
Definition: log-cf-common.h:33
LogCustomFormatNode * LogCustomFormatNodeAlloc()
Creates a custom format node.
Definition: log-cf-common.c:37
void LogCustomFormatWriteTimestamp(MemBuffer *buffer, const char *fmt, const struct timeval *ts)
Writes a timestamp with given format into a MemBuffer.
uint32_t offset
Definition: util-buffer.h:30
#define FAIL_IF_NOT(expr)
Fail a test if expression to true.
Definition: util-unittest.h:82
void MemBufferFree(MemBuffer *buffer)
Definition: util-buffer.c:82
void LogCustomFormatFree(LogCustomFormat *cf)
Frees memory held by a custom format.
Definition: log-cf-common.c:78
LogCustomFormat * LogCustomFormatAlloc()
Creates a custom format.
Definition: log-cf-common.c:52