suricata
output-tx.c
Go to the documentation of this file.
1 /* Copyright (C) 2007-2013 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  * AppLayer TX Logger Output registration functions
24  */
25 
26 #include "suricata-common.h"
27 #include "tm-modules.h"
28 #include "output.h"
29 #include "output-tx.h"
30 #include "app-layer.h"
31 #include "app-layer-parser.h"
32 #include "util-profiling.h"
33 
34 typedef struct OutputLoggerThreadStore_ {
35  void *thread_data;
38 
39 /** per thread data for this module, contains a list of per thread
40  * data for the packet loggers. */
41 typedef struct OutputLoggerThreadData_ {
44 
45 /* logger instance, a module + a output ctx,
46  * it's perfectly valid that have multiple instances of the same
47  * log module (e.g. http.log) with different output ctx'. */
48 typedef struct OutputTxLogger_ {
54  const char *name;
56  uint32_t id;
59  TmEcode (*ThreadInit)(ThreadVars *, const void *, void **);
61  void (*ThreadExitPrintStats)(ThreadVars *, void *);
63 
64 static OutputTxLogger *list = NULL;
65 
72  void (*ThreadExitPrintStats)(ThreadVars *, void *))
73 {
74  if (!(AppLayerParserIsTxAware(alproto))) {
75  SCLogNotice("%s logger not enabled: protocol %s is disabled",
76  name, AppProtoToString(alproto));
77  return -1;
78  }
79 
80  OutputTxLogger *op = SCMalloc(sizeof(*op));
81  if (op == NULL)
82  return -1;
83  memset(op, 0x00, sizeof(*op));
84 
85  op->alproto = alproto;
86  op->LogFunc = LogFunc;
88  op->output_ctx = output_ctx;
89  op->name = name;
90  op->logger_id = id;
91  op->ThreadInit = ThreadInit;
94 
95  if (tc_log_progress < 0) {
96  op->tc_log_progress =
99  } else {
101  }
102 
103  if (ts_log_progress < 0) {
104  op->ts_log_progress =
107  } else {
109  }
110 
111  if (list == NULL) {
112  op->id = 1;
113  list = op;
114  } else {
115  OutputTxLogger *t = list;
116  while (t->next)
117  t = t->next;
118  if (t->id * 2 > UINT32_MAX) {
119  SCLogError(SC_ERR_FATAL, "Too many loggers registered.");
120  exit(EXIT_FAILURE);
121  }
122  op->id = t->id * 2;
123  t->next = op;
124  }
125 
126  SCLogDebug("OutputRegisterTxLogger happy");
127  return 0;
128 }
129 
130 static TmEcode OutputTxLog(ThreadVars *tv, Packet *p, void *thread_data)
131 {
132  BUG_ON(thread_data == NULL);
133  if (list == NULL) {
134  /* No child loggers registered. */
135  return TM_ECODE_OK;
136  }
137 
138  OutputLoggerThreadData *op_thread_data = (OutputLoggerThreadData *)thread_data;
139  if (p->flow == NULL)
140  return TM_ECODE_OK;
141 
142  Flow * const f = p->flow;
143  const uint8_t ipproto = f->proto;
144  const AppProto alproto = f->alproto;
145 
146  if (AppLayerParserProtocolIsTxAware(p->proto, alproto) == 0)
147  goto end;
148  if (AppLayerParserProtocolHasLogger(p->proto, alproto) == 0)
149  goto end;
150  const LoggerId logger_expectation = AppLayerParserProtocolGetLoggerBits(p->proto, alproto);
151  if (logger_expectation == 0)
152  goto end;
153 
154  void *alstate = f->alstate;
155  if (alstate == NULL) {
156  SCLogDebug("no alstate");
157  goto end;
158  }
159 
160  const uint8_t ts_disrupt_flags = FlowGetDisruptionFlags(f, STREAM_TOSERVER);
161  const uint8_t tc_disrupt_flags = FlowGetDisruptionFlags(f, STREAM_TOCLIENT);
162  const uint64_t total_txs = AppLayerParserGetTxCnt(f, alstate);
164  uint64_t max_id = tx_id;
165  int logged = 0;
166  int gap = 0;
167 
168  AppLayerGetTxIteratorFunc IterFunc = AppLayerGetTxIterator(ipproto, alproto);
170  memset(&state, 0, sizeof(state));
171 
172  while (1) {
173  AppLayerGetTxIterTuple ires = IterFunc(ipproto, alproto, alstate, tx_id, total_txs, &state);
174  if (ires.tx_ptr == NULL)
175  break;
176  void * const tx = ires.tx_ptr;
177  tx_id = ires.tx_id;
178 
179  LoggerId tx_logged = AppLayerParserGetTxLogged(f, alstate, tx);
180  const LoggerId tx_logged_old = tx_logged;
181  SCLogDebug("logger: expect %08x, have %08x", logger_expectation, tx_logged);
182  if (tx_logged == logger_expectation) {
183  /* tx already fully logged */
184  goto next_tx;
185  }
186 
187  int tx_progress_ts = AppLayerParserGetStateProgress(p->proto, alproto,
188  tx, ts_disrupt_flags);
189  int tx_progress_tc = AppLayerParserGetStateProgress(p->proto, alproto,
190  tx, tc_disrupt_flags);
191  SCLogDebug("tx_progress_ts %d tx_progress_tc %d",
192  tx_progress_ts, tx_progress_tc);
193 
194  const OutputTxLogger *logger = list;
195  const OutputLoggerThreadStore *store = op_thread_data->store;
196 #ifdef DEBUG_VALIDATION
197  BUG_ON(logger == NULL && store != NULL);
198  BUG_ON(logger != NULL && store == NULL);
199  BUG_ON(logger == NULL && store == NULL);
200 #endif
201  while (logger && store) {
202  BUG_ON(logger->LogFunc == NULL);
203 
204  SCLogDebug("logger %p, LogCondition %p, ts_log_progress %d "
205  "tc_log_progress %d", logger, logger->LogCondition,
206  logger->ts_log_progress, logger->tc_log_progress);
207  if (logger->alproto == alproto &&
208  (tx_logged_old & (1<<logger->logger_id)) == 0)
209  {
210  SCLogDebug("alproto match, logging tx_id %"PRIu64, tx_id);
211 
214  if (logger->LogCondition) {
215  int r = logger->LogCondition(tv, p, alstate, tx, tx_id);
216  if (r == FALSE) {
217  SCLogDebug("conditions not met, not logging");
218  goto next_logger;
219  }
220  } else {
221  if (tx_progress_tc < logger->tc_log_progress) {
222  SCLogDebug("progress not far enough, not logging");
223  goto next_logger;
224  }
225 
226  if (tx_progress_ts < logger->ts_log_progress) {
227  SCLogDebug("progress not far enough, not logging");
228  goto next_logger;
229  }
230  }
231  }
232 
233  SCLogDebug("Logging tx_id %"PRIu64" to logger %d", tx_id,
234  logger->logger_id);
236  logger->LogFunc(tv, store->thread_data, p, f, alstate, tx, tx_id);
238 
239  tx_logged |= (1<<logger->logger_id);
240  }
241 
242 next_logger:
243  logger = logger->next;
244  store = store->next;
245 #ifdef DEBUG_VALIDATION
246  BUG_ON(logger == NULL && store != NULL);
247  BUG_ON(logger != NULL && store == NULL);
248 #endif
249  }
250 
251  if (tx_logged != tx_logged_old) {
252  SCLogDebug("logger: storing %08x (was %08x)",
253  tx_logged, tx_logged_old);
254  AppLayerParserSetTxLogged(p->proto, alproto, alstate, tx,
255  tx_logged);
256  }
257 
258  /* If all loggers logged set a flag and update the last tx_id
259  * that was logged.
260  *
261  * If not all loggers were logged we flag that there was a gap
262  * so any subsequent transactions in this loop don't increase
263  * the maximum ID that was logged. */
264  if (!gap && tx_logged == logger_expectation) {
265  logged = 1;
266  max_id = tx_id;
267  } else {
268  gap = 1;
269  }
270 next_tx:
271  if (!ires.has_next)
272  break;
273  tx_id++;
274  }
275 
276  /* Update the the last ID that has been logged with all
277  * transactions before it. */
278  if (logged) {
279  SCLogDebug("updating log tx_id %"PRIu64, max_id);
281  }
282 
283 end:
284  return TM_ECODE_OK;
285 }
286 
287 /** \brief thread init for the tx logger
288  * This will run the thread init functions for the individual registered
289  * loggers */
290 static TmEcode OutputTxLogThreadInit(ThreadVars *tv, const void *initdata, void **data)
291 {
292  OutputLoggerThreadData *td = SCMalloc(sizeof(*td));
293  if (td == NULL)
294  return TM_ECODE_FAILED;
295  memset(td, 0x00, sizeof(*td));
296 
297  *data = (void *)td;
298  SCLogDebug("OutputTxLogThreadInit happy (*data %p)", *data);
299 
300  OutputTxLogger *logger = list;
301  while (logger) {
302  if (logger->ThreadInit) {
303  void *retptr = NULL;
304  if (logger->ThreadInit(tv, (void *)logger->output_ctx, &retptr) == TM_ECODE_OK) {
305  OutputLoggerThreadStore *ts = SCMalloc(sizeof(*ts));
306 /* todo */ BUG_ON(ts == NULL);
307  memset(ts, 0x00, sizeof(*ts));
308 
309  /* store thread handle */
310  ts->thread_data = retptr;
311 
312  if (td->store == NULL) {
313  td->store = ts;
314  } else {
315  OutputLoggerThreadStore *tmp = td->store;
316  while (tmp->next != NULL)
317  tmp = tmp->next;
318  tmp->next = ts;
319  }
320 
321  SCLogDebug("%s is now set up", logger->name);
322  }
323  }
324 
325  logger = logger->next;
326  }
327 
328  return TM_ECODE_OK;
329 }
330 
331 static TmEcode OutputTxLogThreadDeinit(ThreadVars *tv, void *thread_data)
332 {
333  OutputLoggerThreadData *op_thread_data = (OutputLoggerThreadData *)thread_data;
334  OutputLoggerThreadStore *store = op_thread_data->store;
335  OutputTxLogger *logger = list;
336 
337  while (logger && store) {
338  if (logger->ThreadDeinit) {
339  logger->ThreadDeinit(tv, store->thread_data);
340  }
341 
342  OutputLoggerThreadStore *next_store = store->next;
343  SCFree(store);
344  store = next_store;
345  logger = logger->next;
346  }
347 
348  SCFree(op_thread_data);
349  return TM_ECODE_OK;
350 }
351 
352 static void OutputTxLogExitPrintStats(ThreadVars *tv, void *thread_data)
353 {
354  OutputLoggerThreadData *op_thread_data = (OutputLoggerThreadData *)thread_data;
355  OutputLoggerThreadStore *store = op_thread_data->store;
356  OutputTxLogger *logger = list;
357 
358  while (logger && store) {
359  if (logger->ThreadExitPrintStats) {
360  logger->ThreadExitPrintStats(tv, store->thread_data);
361  }
362 
363  logger = logger->next;
364  store = store->next;
365  }
366 }
367 
369 {
370  OutputRegisterRootLogger(OutputTxLogThreadInit, OutputTxLogThreadDeinit,
371  OutputTxLogExitPrintStats, OutputTxLog);
372 }
373 
375 {
376  OutputTxLogger *logger = list;
377  while (logger) {
378  OutputTxLogger *next_logger = logger->next;
379  SCFree(logger);
380  logger = next_logger;
381  }
382  list = NULL;
383 }
LoggerId AppLayerParserGetTxLogged(const Flow *f, void *alstate, void *tx)
#define PACKET_PROFILING_LOGGER_START(p, id)
struct OutputTxLogger_ OutputTxLogger
int OutputRegisterTxLogger(LoggerId id, const char *name, AppProto alproto, TxLogger LogFunc, OutputCtx *output_ctx, int tc_log_progress, int ts_log_progress, TxLoggerCondition LogCondition, ThreadInitFunc ThreadInit, ThreadDeinitFunc ThreadDeinit, void(*ThreadExitPrintStats)(ThreadVars *, void *))
Definition: output-tx.c:66
#define SCLogDebug(...)
Definition: util-debug.h:335
struct Flow_ * flow
Definition: decode.h:443
int AppLayerParserProtocolHasLogger(uint8_t ipproto, AppProto alproto)
#define BUG_ON(x)
void AppLayerParserSetTransactionLogId(AppLayerParserState *pstate, uint64_t tx_id)
uint8_t proto
Definition: flow.h:343
int AppLayerParserGetStateProgressCompletionStatus(AppProto alproto, uint8_t direction)
int AppLayerParserIsTxAware(AppProto alproto)
simpler way to globally test if a alproto is registered and fully enabled in the configuration.
#define FALSE
struct OutputLoggerThreadStore_ OutputLoggerThreadStore
LoggerId
int AppLayerParserGetStateProgress(uint8_t ipproto, AppProto alproto, void *alstate, uint8_t flags)
get the progress value for a tx/protocol
int logged
uint64_t AppLayerParserGetTxCnt(const Flow *f, void *alstate)
int AppLayerParserStateIssetFlag(AppLayerParserState *pstate, uint8_t flag)
OutputLoggerThreadStore * store
Definition: output-file.c:44
AppLayerGetTxIteratorFunc AppLayerGetTxIterator(const uint8_t ipproto, const AppProto alproto)
uint16_t AppProto
TmEcode(* ThreadDeinit)(ThreadVars *, void *)
Definition: output-tx.c:60
uint8_t FlowGetDisruptionFlags(const Flow *f, uint8_t flags)
get &#39;disruption&#39; flags: GAP/DEPTH/PASS
Definition: flow.c:1077
TmEcode(* ThreadInit)(ThreadVars *, const void *, void **)
Definition: output-tx.c:59
LoggerId logger_id
Definition: output-tx.c:55
TmEcode(* ThreadDeinitFunc)(ThreadVars *, void *)
Definition: tm-modules.h:40
void * alstate
Definition: flow.h:433
uint64_t AppLayerParserGetTransactionLogId(AppLayerParserState *pstate)
uint8_t proto
Definition: decode.h:428
OutputCtx * output_ctx
Definition: output-tx.c:52
const char * AppProtoToString(AppProto alproto)
Maps the ALPROTO_*, to its string equivalent.
struct OutputLoggerThreadStore_ * next
Definition: output-file.c:38
int ts_log_progress
Definition: output-tx.c:58
#define SCLogError(err_code,...)
Macro used to log ERROR messages.
Definition: util-debug.h:294
struct OutputLoggerThreadData_ OutputLoggerThreadData
int(* TxLogger)(ThreadVars *, void *thread_data, const Packet *, Flow *f, void *state, void *tx, uint64_t tx_id)
Definition: output-tx.h:32
void OutputRegisterRootLogger(ThreadInitFunc ThreadInit, ThreadDeinitFunc ThreadDeinit, ThreadExitPrintStatsFunc ThreadExitPrintStats, OutputLogFunc LogFunc)
Definition: output.c:999
#define STREAM_TOCLIENT
Definition: stream.h:32
void OutputTxLoggerRegister(void)
Definition: output-tx.c:368
struct OutputTxLogger_ * next
Definition: output-tx.c:53
void OutputTxShutdown(void)
Definition: output-tx.c:374
#define SCMalloc(a)
Definition: util-mem.h:166
#define SCFree(a)
Definition: util-mem.h:228
#define SCLogNotice(...)
Macro used to log NOTICE messages.
Definition: util-debug.h:269
void(* ThreadExitPrintStats)(ThreadVars *, void *)
Definition: output-tx.c:61
uint16_t tx_id
TxLogger LogFunc
Definition: output-tx.c:50
TxLoggerCondition LogCondition
Definition: output-tx.c:51
uint64_t ts
#define STREAM_TOSERVER
Definition: stream.h:31
int(* TxLoggerCondition)(ThreadVars *, const Packet *, void *state, void *tx, uint64_t tx_id)
Definition: output-tx.h:37
void AppLayerParserSetTxLogged(uint8_t ipproto, AppProto alproto, void *alstate, void *tx, LoggerId logger)
#define APP_LAYER_PARSER_EOF
Per thread variable structure.
Definition: threadvars.h:57
TmEcode(* ThreadInitFunc)(ThreadVars *, const void *, void **)
Definition: tm-modules.h:39
AppProto alproto
application level protocol
Definition: flow.h:404
AppProto alproto
Definition: output-tx.c:49
LoggerId AppLayerParserProtocolGetLoggerBits(uint8_t ipproto, AppProto alproto)
const char * name
Definition: output-tx.c:54
#define PACKET_PROFILING_LOGGER_END(p, id)
uint32_t id
Definition: output-tx.c:56
int AppLayerParserProtocolIsTxAware(uint8_t ipproto, AppProto alproto)
Flow data structure.
Definition: flow.h:324
AppLayerParserState * alparser
Definition: flow.h:432
int tc_log_progress
Definition: output-tx.c:57
AppLayerGetTxIterTuple(* AppLayerGetTxIteratorFunc)(const uint8_t ipproto, const AppProto alproto, void *alstate, uint64_t min_tx_id, uint64_t max_tx_id, AppLayerGetTxIterState *state)
tx iterator prototype