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