suricata
log-tcp-data.c
Go to the documentation of this file.
1 /* Copyright (C) 2014 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 Victor Julien <victor@inliniac.net>
22  */
23 
24 #include "suricata-common.h"
25 #include "debug.h"
26 #include "detect.h"
27 #include "pkt-var.h"
28 #include "conf.h"
29 
30 #include "threads.h"
31 #include "threadvars.h"
32 #include "tm-threads.h"
33 
34 #include "util-print.h"
35 #include "util-unittest.h"
36 
37 #include "util-debug.h"
38 
39 #include "output.h"
40 #include "log-tcp-data.h"
41 #include "app-layer-htp.h"
42 #include "app-layer.h"
43 #include "app-layer-parser.h"
44 #include "util-privs.h"
45 #include "util-buffer.h"
46 
47 #include "util-logopenfile.h"
48 #include "util-time.h"
49 
50 #define DEFAULT_LOG_FILENAME "tcp-data.log"
51 
52 #define MODULE_NAME "LogTcpDataLog"
53 
54 #define OUTPUT_BUFFER_SIZE 65535
55 
56 TmEcode LogTcpDataLogThreadInit(ThreadVars *, const void *, void **);
58 static void LogTcpDataLogDeInitCtx(OutputCtx *);
59 
60 int LogTcpDataLogger(ThreadVars *tv, void *thread_data, const Flow *f, const uint8_t *data, uint32_t data_len, uint64_t tx_id, uint8_t flags);
61 
62 void LogTcpDataLogRegister (void) {
69 }
70 
71 typedef struct LogTcpDataFileCtx_ {
74  const char *log_dir;
75  int file;
76  int dir;
78 
79 typedef struct LogTcpDataLogThread_ {
81  /** LogFileCtx has the pointer to the file and a mutex to allow multithreading */
84 
85 static int LogTcpDataLoggerDir(ThreadVars *tv, void *thread_data, const Flow *f,
86  const uint8_t *data, uint32_t data_len, uint64_t tx_id, uint8_t flags)
87 {
88  SCEnter();
89  LogTcpDataLogThread *aft = thread_data;
91  const char *mode = "a";
92 
93  if (flags & OUTPUT_STREAMING_FLAG_OPEN)
94  mode = "w";
95 
96  if (data && data_len) {
97  char srcip[46] = "", dstip[46] = "";
98  if (FLOW_IS_IPV4(f)) {
99  PrintInet(AF_INET, (const void *)&f->src.addr_data32[0], srcip, sizeof(srcip));
100  PrintInet(AF_INET, (const void *)&f->dst.addr_data32[0], dstip, sizeof(dstip));
101  } else if (FLOW_IS_IPV6(f)) {
102  PrintInet(AF_INET6, (const void *)f->src.addr_data32, srcip, sizeof(srcip));
103  PrintInet(AF_INET6, (const void *)f->dst.addr_data32, dstip, sizeof(dstip));
104  }
105 
106  char name[PATH_MAX];
107 
108  char tx[64] = { 0 };
109  if (flags & OUTPUT_STREAMING_FLAG_TRANSACTION) {
110  snprintf(tx, sizeof(tx), "%"PRIu64, tx_id);
111  }
112 
113  snprintf(name, sizeof(name), "%s/%s/%s_%u-%s_%u-%s-%s.data",
114  td->log_dir,
115  td->type == STREAMING_HTTP_BODIES ? "http" : "tcp",
116  srcip, f->sp, dstip, f->dp, tx,
117  flags & OUTPUT_STREAMING_FLAG_TOSERVER ? "ts" : "tc");
118 
119  FILE *fp = fopen(name, mode);
120  BUG_ON(fp == NULL);
121 
122  // PrintRawDataFp(stdout, (uint8_t *)data, data_len);
123  fwrite(data, data_len, 1, fp);
124 
125  fclose(fp);
126  }
128 }
129 
130 static int LogTcpDataLoggerFile(ThreadVars *tv, void *thread_data, const Flow *f,
131  const uint8_t *data, uint32_t data_len, uint64_t tx_id, uint8_t flags)
132 {
133  SCEnter();
134  LogTcpDataLogThread *aft = thread_data;
136 
137  if (data && data_len) {
138  MemBufferReset(aft->buffer);
139 
140  char srcip[46] = "", dstip[46] = "";
141  if (FLOW_IS_IPV4(f)) {
142  PrintInet(AF_INET, (const void *)&f->src.addr_data32[0], srcip, sizeof(srcip));
143  PrintInet(AF_INET, (const void *)&f->dst.addr_data32[0], dstip, sizeof(dstip));
144  } else if (FLOW_IS_IPV6(f)) {
145  PrintInet(AF_INET6, (const void *)f->src.addr_data32, srcip, sizeof(srcip));
146  PrintInet(AF_INET6, (const void *)f->dst.addr_data32, dstip, sizeof(dstip));
147  }
148 
149  char name[PATH_MAX];
150  snprintf(name, sizeof(name), "%s_%u-%s_%u-%s:",
151  srcip, f->sp, dstip, f->dp,
152  flags & OUTPUT_STREAMING_FLAG_TOSERVER ? "ts" : "tc");
153 
154  PrintRawUriBuf((char *)aft->buffer->buffer, &aft->buffer->offset,
155  aft->buffer->size, (uint8_t *)name,strlen(name));
156  MemBufferWriteString(aft->buffer, "\n");
157 
159  aft->buffer->size, (uint8_t *)data,data_len);
160 
161  td->file_ctx->Write((const char *)MEMBUFFER_BUFFER(aft->buffer),
162  MEMBUFFER_OFFSET(aft->buffer), td->file_ctx);
163  }
165 }
166 
167 int LogTcpDataLogger(ThreadVars *tv, void *thread_data, const Flow *f,
168  const uint8_t *data, uint32_t data_len, uint64_t tx_id, uint8_t flags)
169 {
170  SCEnter();
171  LogTcpDataLogThread *aft = thread_data;
173 
174  if (td->dir == 1)
175  LogTcpDataLoggerDir(tv, thread_data, f, data, data_len, tx_id, flags);
176  if (td->file == 1)
177  LogTcpDataLoggerFile(tv, thread_data, f, data, data_len, tx_id, flags);
178 
180 }
181 
182 TmEcode LogTcpDataLogThreadInit(ThreadVars *t, const void *initdata, void **data)
183 {
185  if (unlikely(aft == NULL))
186  return TM_ECODE_FAILED;
187  memset(aft, 0, sizeof(LogTcpDataLogThread));
188 
189  if(initdata == NULL)
190  {
191  SCLogDebug("Error getting context. \"initdata\" argument NULL");
192  SCFree(aft);
193  return TM_ECODE_FAILED;
194  }
195 
197  if (aft->buffer == NULL) {
198  SCFree(aft);
199  return TM_ECODE_FAILED;
200  }
201 
202  /* Use the Ouptut Context (file pointer and mutex) */
203  aft->tcpdatalog_ctx= ((OutputCtx *)initdata)->data;
204 
205  *data = (void *)aft;
206  return TM_ECODE_OK;
207 }
208 
210 {
212  if (aft == NULL) {
213  return TM_ECODE_OK;
214  }
215 
216  MemBufferFree(aft->buffer);
217  /* clear memory */
218  memset(aft, 0, sizeof(LogTcpDataLogThread));
219 
220  SCFree(aft);
221  return TM_ECODE_OK;
222 }
223 
224 /** \brief Create a new http log LogFileCtx.
225  * \param conf Pointer to ConfNode containing this loggers configuration.
226  * \return NULL if failure, LogFileCtx* to the file_ctx if succesful
227  * */
229 {
230  OutputInitResult result = { NULL, false };
231  char filename[PATH_MAX] = "";
232  char dirname[32] = "";
233  strlcpy(filename, DEFAULT_LOG_FILENAME, sizeof(filename));
234 
236  if(file_ctx == NULL) {
237  SCLogError(SC_ERR_TCPDATA_LOG_GENERIC, "couldn't create new file_ctx");
238  return result;
239  }
240 
241  LogTcpDataFileCtx *tcpdatalog_ctx = SCMalloc(sizeof(LogTcpDataFileCtx));
242  if (unlikely(tcpdatalog_ctx == NULL)) {
243  LogFileFreeCtx(file_ctx);
244  return result;
245  }
246  memset(tcpdatalog_ctx, 0x00, sizeof(LogTcpDataFileCtx));
247 
248  tcpdatalog_ctx->file_ctx = file_ctx;
249 
250  if (conf) {
251  if (conf->name) {
252  if (strcmp(conf->name, "tcp-data") == 0) {
253  tcpdatalog_ctx->type = STREAMING_TCP_DATA;
254  snprintf(filename, sizeof(filename), "%s.log", conf->name);
255  strlcpy(dirname, "tcp", sizeof(dirname));
256  } else if (strcmp(conf->name, "http-body-data") == 0) {
257  tcpdatalog_ctx->type = STREAMING_HTTP_BODIES;
258  snprintf(filename, sizeof(filename), "%s.log", conf->name);
259  strlcpy(dirname, "http", sizeof(dirname));
260  }
261  }
262 
263  const char *logtype = ConfNodeLookupChildValue(conf, "type");
264  if (logtype == NULL)
265  logtype = "file";
266 
267  if (strcmp(logtype, "file") == 0) {
268  tcpdatalog_ctx->file = 1;
269  } else if (strcmp(logtype, "dir") == 0) {
270  tcpdatalog_ctx->dir = 1;
271  } else if (strcmp(logtype, "both") == 0) {
272  tcpdatalog_ctx->file = 1;
273  tcpdatalog_ctx->dir = 1;
274  }
275  } else {
276  tcpdatalog_ctx->file = 1;
277  tcpdatalog_ctx->dir = 0;
278  }
279 
280  if (tcpdatalog_ctx->file == 1) {
281  SCLogInfo("opening logfile");
282  if (SCConfLogOpenGeneric(conf, file_ctx, filename, 1) < 0) {
283  LogFileFreeCtx(file_ctx);
284  SCFree(tcpdatalog_ctx);
285  return result;
286  }
287  }
288 
289  if (tcpdatalog_ctx->dir == 1) {
290  tcpdatalog_ctx->log_dir = ConfigGetLogDirectory();
291  char dirfull[PATH_MAX];
292 
293  /* create the filename to use */
294  snprintf(dirfull, PATH_MAX, "%s/%s", tcpdatalog_ctx->log_dir, dirname);
295 
296  SCLogInfo("using directory %s", dirfull);
297 
298  /* if mkdir fails file open will fail, so deal with errors there */
299  (void)SCMkDir(dirfull, 0700);
300  }
301 
302  OutputCtx *output_ctx = SCCalloc(1, sizeof(OutputCtx));
303  if (unlikely(output_ctx == NULL)) {
304  goto parsererror;
305  }
306 
307  output_ctx->data = tcpdatalog_ctx;
308  output_ctx->DeInit = LogTcpDataLogDeInitCtx;
309 
310  SCLogDebug("Streaming log output initialized");
311  result.ctx = output_ctx;
312  result.ok = true;
313  return result;
314 
315 parsererror:
316  LogFileFreeCtx(file_ctx);
317  SCFree(tcpdatalog_ctx);
318  SCLogError(SC_ERR_INVALID_ARGUMENT,"Syntax error in custom http log format string.");
319  return result;
320 
321 }
322 
323 static void LogTcpDataLogDeInitCtx(OutputCtx *output_ctx)
324 {
325  LogTcpDataFileCtx *tcpdatalog_ctx = (LogTcpDataFileCtx *)output_ctx->data;
326  LogFileFreeCtx(tcpdatalog_ctx->file_ctx);
327  SCFree(tcpdatalog_ctx);
328  SCFree(output_ctx);
329 }
MemBuffer * MemBufferCreateNew(uint32_t size)
Definition: util-buffer.c:32
#define FLOW_IS_IPV4(f)
Definition: flow.h:134
uint16_t flags
TmEcode LogTcpDataLogThreadInit(ThreadVars *, const void *, void **)
Definition: log-tcp-data.c:182
#define SCLogDebug(...)
Definition: util-debug.h:335
#define MemBufferWriteString(dst,...)
Write a string buffer to the Membuffer dst.
Definition: util-buffer.h:162
size_t strlcpy(char *dst, const char *src, size_t siz)
Definition: util-strlcpyu.c:43
MemBuffer * buffer
Definition: log-tcp-data.c:82
#define OUTPUT_STREAMING_FLAG_OPEN
#define BUG_ON(x)
Port sp
Definition: flow.h:331
struct LogTcpDataFileCtx_ LogTcpDataFileCtx
#define SCMkDir(a, b)
Definition: util-path.h:29
#define unlikely(expr)
Definition: util-optimize.h:35
void PrintRawDataToBuffer(uint8_t *dst_buf, uint32_t *dst_buf_offset_ptr, uint32_t dst_buf_size, const uint8_t *src_buf, uint32_t src_buf_len)
Definition: util-print.c:175
#define MemBufferReset(mem_buffer)
Reset the mem buffer.
Definition: util-buffer.h:42
int LogTcpDataLogger(ThreadVars *tv, void *thread_data, const Flow *f, const uint8_t *data, uint32_t data_len, uint64_t tx_id, uint8_t flags)
Definition: log-tcp-data.c:167
void OutputRegisterStreamingModule(LoggerId id, const char *name, const char *conf_name, OutputInitFunc InitFunc, StreamingLogger StreamingLogFunc, enum OutputStreamingType stream_type, ThreadInitFunc ThreadInit, ThreadDeinitFunc ThreadDeinit, ThreadExitPrintStatsFunc ThreadExitPrintStats)
Register a streaming data output module.
Definition: output.c:657
void(* DeInit)(struct OutputCtx_ *)
Definition: tm-modules.h:84
OutputStreamingType
TmEcode LogTcpDataLogThreadDeinit(ThreadVars *, void *)
Definition: log-tcp-data.c:209
#define OUTPUT_BUFFER_SIZE
Definition: log-tcp-data.c:54
enum OutputStreamingType type
Definition: log-tcp-data.c:73
FlowAddress dst
Definition: flow.h:329
LogTcpDataFileCtx * tcpdatalog_ctx
Definition: log-tcp-data.c:80
const char * log_dir
Definition: log-tcp-data.c:74
#define SCCalloc(nm, a)
Definition: util-mem.h:197
const char * ConfNodeLookupChildValue(const ConfNode *node, const char *name)
Lookup the value of a child configuration node by name.
Definition: conf.c:843
OutputInitResult LogTcpDataLogInitCtx(ConfNode *conf)
Create a new http log LogFileCtx.
Definition: log-tcp-data.c:228
#define DEFAULT_LOG_FILENAME
Definition: log-tcp-data.c:50
uint32_t size
Definition: util-buffer.h:29
#define SCLogError(err_code,...)
Macro used to log ERROR messages.
Definition: util-debug.h:294
#define SCEnter(...)
Definition: util-debug.h:337
LogFileCtx * LogFileNewCtx(void)
LogFileNewCtx() Get a new LogFileCtx.
uint8_t * buffer
Definition: util-buffer.h:28
int SCConfLogOpenGeneric(ConfNode *conf, LogFileCtx *log_ctx, const char *default_filename, int rotate)
open a generic output "log file", which may be a regular file or a socket
const char * PrintInet(int af, const void *src, char *dst, socklen_t size)
Definition: util-print.c:267
void LogTcpDataLogRegister(void)
Definition: log-tcp-data.c:62
#define SCReturnInt(x)
Definition: util-debug.h:341
#define MEMBUFFER_BUFFER(mem_buffer)
Get the MemBuffers underlying buffer.
Definition: util-buffer.h:50
void PrintRawUriBuf(char *retbuf, uint32_t *offset, uint32_t retbuflen, uint8_t *buf, uint32_t buflen)
Definition: util-print.c:118
Definition: conf.h:32
int(* Write)(const char *buffer, int buffer_len, struct LogFileCtx_ *fp)
OutputCtx * ctx
Definition: output.h:42
const char * ConfigGetLogDirectory()
Definition: util-conf.c:36
#define SCMalloc(a)
Definition: util-mem.h:166
int LogFileFreeCtx(LogFileCtx *lf_ctx)
LogFileFreeCtx() Destroy a LogFileCtx (Close the file and free memory)
#define SCLogInfo(...)
Macro used to log INFORMATIONAL messages.
Definition: util-debug.h:254
#define SCFree(a)
Definition: util-mem.h:228
Port dp
Definition: flow.h:338
#define FLOW_IS_IPV6(f)
Definition: flow.h:136
LogFileCtx * file_ctx
Definition: log-tcp-data.c:72
struct LogTcpDataLogThread_ LogTcpDataLogThread
uint16_t tx_id
#define MEMBUFFER_OFFSET(mem_buffer)
Get the MemBuffers current offset.
Definition: util-buffer.h:55
char * name
Definition: conf.h:33
void * data
Definition: tm-modules.h:81
#define MODULE_NAME
Definition: log-tcp-data.c:52
FlowAddress src
Definition: flow.h:329
#define OUTPUT_STREAMING_FLAG_TRANSACTION
Per thread variable structure.
Definition: threadvars.h:57
uint32_t offset
Definition: util-buffer.h:30
Flow data structure.
Definition: flow.h:325
#define OUTPUT_STREAMING_FLAG_TOSERVER
void MemBufferFree(MemBuffer *buffer)
Definition: util-buffer.c:82