suricata
log-pcap.c
Go to the documentation of this file.
1 /* Copyright (C) 2007-2021 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 William Metcalf <William.Metcalf@gmail.com>
22  * \author Victor Julien <victor@inliniac.net>
23  *
24  * Pcap packet logging module.
25  */
26 
27 #include "suricata-common.h"
28 #include "util-buffer.h"
29 #include "util-fmemopen.h"
30 #include "util-datalink.h"
31 #include "stream-tcp-util.h"
32 #include "stream.h"
33 
34 #ifdef HAVE_LIBLZ4
35 #include <lz4frame.h>
36 #endif /* HAVE_LIBLZ4 */
37 
38 #if defined(HAVE_DIRENT_H) && defined(HAVE_FNMATCH_H)
39 #define INIT_RING_BUFFER
40 #include <dirent.h>
41 #include <fnmatch.h>
42 #endif
43 
44 #include "debug.h"
45 #include "detect.h"
46 #include "flow.h"
47 #include "conf.h"
48 
49 #include "threads.h"
50 #include "threadvars.h"
51 #include "tm-threads.h"
52 
53 #include "util-unittest.h"
54 #include "log-pcap.h"
55 #include "decode-ipv4.h"
56 
57 #include "util-error.h"
58 #include "util-debug.h"
59 #include "util-time.h"
60 #include "util-byte.h"
61 #include "util-misc.h"
62 #include "util-cpu.h"
63 #include "util-atomic.h"
64 
65 #include "source-pcap.h"
66 
67 #include "output.h"
68 
69 #include "queue.h"
70 
71 #define DEFAULT_LOG_FILENAME "pcaplog"
72 #define MODULE_NAME "PcapLog"
73 #define MIN_LIMIT 4 * 1024 * 1024
74 #define DEFAULT_LIMIT 100 * 1024 * 1024
75 #define DEFAULT_FILE_LIMIT 0
76 
77 #define LOGMODE_NORMAL 0
78 #define LOGMODE_SGUIL 1
79 #define LOGMODE_MULTI 2
80 
86 
87 #define RING_BUFFER_MODE_DISABLED 0
88 #define RING_BUFFER_MODE_ENABLED 1
89 
90 #define TS_FORMAT_SEC 0
91 #define TS_FORMAT_USEC 1
92 
93 #define USE_STREAM_DEPTH_DISABLED 0
94 #define USE_STREAM_DEPTH_ENABLED 1
95 
96 #define HONOR_PASS_RULES_DISABLED 0
97 #define HONOR_PASS_RULES_ENABLED 1
98 
99 #define PCAP_SNAPLEN 262144
100 #define PCAP_BUFFER_TIMEOUT 1000000 // microseconds
101 
102 SC_ATOMIC_DECLARE(uint32_t, thread_cnt);
103 
104 typedef struct PcapFileName_ {
105  char *filename;
106  char *dirname;
107 
108  /* Like a struct timeval, but with fixed size. This is only used when
109  * seeding the ring buffer on start. */
110  struct {
111  uint64_t secs;
112  uint32_t usecs;
113  };
114 
115  TAILQ_ENTRY(PcapFileName_) next; /**< Pointer to next Pcap File for tailq. */
117 
118 thread_local char *pcap_file_thread = NULL;
119 
120 typedef struct PcapLogProfileData_ {
121  uint64_t total;
122  uint64_t cnt;
124 
125 #define MAX_TOKS 9
126 #define MAX_FILENAMELEN 513
127 
131 };
132 
133 typedef struct PcapLogCompressionData_ {
135  uint8_t *buffer;
136  uint64_t buffer_size;
137 #ifdef HAVE_LIBLZ4
138  LZ4F_compressionContext_t lz4f_context;
139  LZ4F_preferences_t lz4f_prefs;
140 #endif /* HAVE_LIBLZ4 */
141  FILE *file;
142  uint8_t *pcap_buf;
143  uint64_t pcap_buf_size;
145  uint64_t bytes_in_block;
147 
148 /**
149  * PcapLog thread vars
150  *
151  * Used for storing file options.
152  */
153 typedef struct PcapLogData_ {
154  int use_stream_depth; /**< use stream depth i.e. ignore packets that reach limit */
155  int honor_pass_rules; /**< don't log if pass rules have matched */
156  int is_private; /**< TRUE if ctx is thread local */
158  uint64_t pkt_cnt; /**< total number of packets */
159  struct pcap_pkthdr *h; /**< pcap header struct */
160  char *filename; /**< current filename */
161  int mode; /**< normal or sguil */
162  int prev_day; /**< last day, for finding out when */
163  uint64_t size_current; /**< file current size */
164  uint64_t size_limit; /**< file size limit */
165  pcap_t *pcap_dead_handle; /**< pcap_dumper_t needs a handle */
166  pcap_dumper_t *pcap_dumper; /**< actually writes the packets */
167  uint64_t profile_data_size; /**< track in bytes how many bytes we wrote */
168  uint32_t file_cnt; /**< count of pcap files we currently have */
169  uint32_t max_files; /**< maximum files to use in ring buffer mode */
171  conditional; /**< log all packets or just packets and flows with alerts */
172 
180 
181  TAILQ_HEAD(, PcapFileName_) pcap_file_list;
182 
183  uint32_t thread_number; /**< thread number, first thread is 1, second 2, etc */
184  int use_ringbuffer; /**< ring buffer mode enabled or disabled */
185  int timestamp_format; /**< timestamp format sec or usec */
186  char *prefix; /**< filename prefix */
187  const char *suffix; /**< filename suffix */
188  char dir[PATH_MAX]; /**< pcap log directory */
189  int reported;
190  int threads; /**< number of threads (only set in the global) */
191  char *filename_parts[MAX_TOKS];
192  int filename_part_cnt;
193  struct timeval last_pcap_dump;
194 
195  PcapLogCompressionData compression;
197 
198 typedef struct PcapLogThreadData_ {
202 
203 /* Pattern for extracting timestamp from pcap log files. */
204 static const char timestamp_pattern[] = ".*?(\\d+)(\\.(\\d+))?";
205 static pcre2_code *pcre_timestamp_code = NULL;
206 static pcre2_match_data *pcre_timestamp_match = NULL;
207 
208 /* global pcap data for when we're using multi mode. At exit we'll
209  * merge counters into this one and then report counters. */
210 static PcapLogData *g_pcap_data = NULL;
211 
212 static int PcapLogOpenFileCtx(PcapLogData *);
213 static int PcapLog(ThreadVars *, void *, const Packet *);
214 static TmEcode PcapLogDataInit(ThreadVars *, const void *, void **);
215 static TmEcode PcapLogDataDeinit(ThreadVars *, void *);
216 static void PcapLogFileDeInitCtx(OutputCtx *);
217 static OutputInitResult PcapLogInitCtx(ConfNode *);
218 static void PcapLogProfilingDump(PcapLogData *);
219 static int PcapLogCondition(ThreadVars *, void *, const Packet *);
220 
221 void PcapLogRegister(void)
222 {
224  PcapLogInitCtx, PcapLog, PcapLogCondition, PcapLogDataInit,
225  PcapLogDataDeinit, NULL);
227  SC_ATOMIC_INIT(thread_cnt);
228  SC_ATOMIC_SET(thread_cnt, 1); /* first id is 1 */
229  return;
230 }
231 
232 #define PCAPLOG_PROFILE_START \
233  uint64_t pcaplog_profile_ticks = UtilCpuGetTicks()
234 
235 #define PCAPLOG_PROFILE_END(prof) \
236  (prof).total += (UtilCpuGetTicks() - pcaplog_profile_ticks); \
237  (prof).cnt++
238 
239 static int PcapLogCondition(ThreadVars *tv, void *thread_data, const Packet *p)
240 {
241  PcapLogThreadData *ptd = (PcapLogThreadData *)thread_data;
242 
243  /* Log alerted flow or tagged flow */
244  switch (ptd->pcap_log->conditional) {
245  case LOGMODE_COND_ALL:
246  break;
247  case LOGMODE_COND_ALERTS:
248  if (p->alerts.cnt || (p->flow && FlowHasAlerts(p->flow))) {
249  return TRUE;
250  } else {
251  return FALSE;
252  }
253  break;
254  case LOGMODE_COND_TAG:
255  if (p->flags & (PKT_HAS_TAG | PKT_FIRST_TAG)) {
256  return TRUE;
257  } else {
258  return FALSE;
259  }
260  break;
261  }
262 
263  if (p->flags & PKT_PSEUDO_STREAM_END) {
264  return FALSE;
265  }
266 
267  if (IS_TUNNEL_PKT(p) && !IS_TUNNEL_ROOT_PKT(p)) {
268  return FALSE;
269  }
270  return TRUE;
271 }
272 
273 /**
274  * \brief Function to close pcaplog file
275  *
276  * \param t Thread Variable containing input/output queue, cpu affinity etc.
277  * \param pl PcapLog thread variable.
278  */
279 static int PcapLogCloseFile(ThreadVars *t, PcapLogData *pl)
280 {
281  if (pl != NULL) {
283 
284  if (pl->pcap_dumper != NULL) {
285  pcap_dump_close(pl->pcap_dumper);
286 #ifdef HAVE_LIBLZ4
287  PcapLogCompressionData *comp = &pl->compression;
289  /* pcap_dump_close() has closed its output ``file'',
290  * so we need to call fmemopen again. */
291 
292  comp->pcap_buf_wrapper = SCFmemopen(comp->pcap_buf,
293  comp->pcap_buf_size, "w");
294  if (comp->pcap_buf_wrapper == NULL) {
295  SCLogError(SC_ERR_FOPEN, "SCFmemopen failed: %s",
296  strerror(errno));
297  return TM_ECODE_FAILED;
298  }
299  }
300 #endif /* HAVE_LIBLZ4 */
301  }
302  pl->size_current = 0;
303  pl->pcap_dumper = NULL;
304 
305  if (pl->pcap_dead_handle != NULL)
306  pcap_close(pl->pcap_dead_handle);
307  pl->pcap_dead_handle = NULL;
308 
309 #ifdef HAVE_LIBLZ4
310  PcapLogCompressionData *comp = &pl->compression;
312  /* pcap_dump_close did not write any data because we call
313  * pcap_dump_flush() after every write when writing
314  * compressed output. */
315  uint64_t bytes_written = LZ4F_compressEnd(comp->lz4f_context,
316  comp->buffer, comp->buffer_size, NULL);
317  if (LZ4F_isError(bytes_written)) {
318  SCLogError(SC_ERR_PCAP_LOG_COMPRESS, "LZ4F_compressEnd: %s",
319  LZ4F_getErrorName(bytes_written));
320  return TM_ECODE_FAILED;
321  }
322  if (fwrite(comp->buffer, 1, bytes_written, comp->file) < bytes_written) {
323  SCLogError(SC_ERR_FWRITE, "fwrite failed: %s", strerror(errno));
324  return TM_ECODE_FAILED;
325  }
326  fclose(comp->file);
327  comp->bytes_in_block = 0;
328  }
329 #endif /* HAVE_LIBLZ4 */
330 
332  }
333 
334  return 0;
335 }
336 
337 static void PcapFileNameFree(PcapFileName *pf)
338 {
339  if (pf != NULL) {
340  if (pf->filename != NULL) {
341  SCFree(pf->filename);
342  }
343  if (pf->dirname != NULL) {
344  SCFree(pf->dirname);
345  }
346  SCFree(pf);
347  }
348 
349  return;
350 }
351 
352 /**
353  * \brief Function to rotate pcaplog file
354  *
355  * \param t Thread Variable containing input/output queue, cpu affinity etc.
356  * \param pl PcapLog thread variable.
357  *
358  * \retval 0 on succces
359  * \retval -1 on failure
360  */
361 static int PcapLogRotateFile(ThreadVars *t, PcapLogData *pl)
362 {
363  PcapFileName *pf;
364  PcapFileName *pfnext;
365 
367 
368  if (PcapLogCloseFile(t,pl) < 0) {
369  SCLogDebug("PcapLogCloseFile failed");
370  return -1;
371  }
372 
373  if (pl->use_ringbuffer == RING_BUFFER_MODE_ENABLED && pl->file_cnt >= pl->max_files) {
374  pf = TAILQ_FIRST(&pl->pcap_file_list);
375  SCLogDebug("Removing pcap file %s", pf->filename);
376 
377  if (remove(pf->filename) != 0) {
378  // VJ remove can fail because file is already gone
379  //LogWarning(SC_ERR_PCAP_FILE_DELETE_FAILED,
380  // "failed to remove log file %s: %s",
381  // pf->filename, strerror( errno ));
382  }
383 
384  /* Remove directory if Sguil mode and no files left in sguil dir */
385  if (pl->mode == LOGMODE_SGUIL) {
386  pfnext = TAILQ_NEXT(pf,next);
387 
388  if (strcmp(pf->dirname, pfnext->dirname) == 0) {
389  SCLogDebug("Current entry dir %s and next entry %s "
390  "are equal: not removing dir",
391  pf->dirname, pfnext->dirname);
392  } else {
393  SCLogDebug("current entry %s and %s are "
394  "not equal: removing dir",
395  pf->dirname, pfnext->dirname);
396 
397  if (remove(pf->dirname) != 0) {
399  "failed to remove sguil log %s: %s",
400  pf->dirname, strerror( errno ));
401  }
402  }
403  }
404 
405  TAILQ_REMOVE(&pl->pcap_file_list, pf, next);
406  PcapFileNameFree(pf);
407  pl->file_cnt--;
408  }
409 
410  if (PcapLogOpenFileCtx(pl) < 0) {
411  SCLogError(SC_ERR_FOPEN, "opening new pcap log file failed");
412  return -1;
413  }
414  pl->file_cnt++;
415  SCLogDebug("file_cnt %u", pl->file_cnt);
416 
418  return 0;
419 }
420 
421 static int PcapLogOpenHandles(PcapLogData *pl, const Packet *p)
422 {
424 
425  int datalink = p->datalink;
426  if (IS_TUNNEL_PKT(p) && !IS_TUNNEL_ROOT_PKT(p)) {
427  Packet *real_p = p->root;
428  datalink = real_p->datalink;
429  }
430  if (pl->pcap_dead_handle == NULL) {
431  SCLogDebug("Setting pcap-log link type to %u", datalink);
432  if ((pl->pcap_dead_handle = pcap_open_dead(datalink, PCAP_SNAPLEN)) == NULL) {
433  SCLogDebug("Error opening dead pcap handle");
434  return TM_ECODE_FAILED;
435  }
436  }
437 
438  if (pl->pcap_dumper == NULL) {
439  if (pl->compression.format == PCAP_LOG_COMPRESSION_FORMAT_NONE) {
440  if ((pl->pcap_dumper = pcap_dump_open(pl->pcap_dead_handle,
441  pl->filename)) == NULL) {
442  SCLogInfo("Error opening dump file %s", pcap_geterr(pl->pcap_dead_handle));
443  return TM_ECODE_FAILED;
444  }
445  }
446 #ifdef HAVE_LIBLZ4
447  else if (pl->compression.format == PCAP_LOG_COMPRESSION_FORMAT_LZ4) {
448  PcapLogCompressionData *comp = &pl->compression;
449  if ((pl->pcap_dumper = pcap_dump_fopen(pl->pcap_dead_handle,
450  comp->pcap_buf_wrapper)) == NULL) {
451  SCLogError(SC_ERR_OPENING_FILE, "Error opening dump file %s",
452  pcap_geterr(pl->pcap_dead_handle));
453  return TM_ECODE_FAILED;
454  }
455  comp->file = fopen(pl->filename, "w");
456  if (comp->file == NULL) {
458  "Error opening file for compressed output: %s",
459  strerror(errno));
460  return TM_ECODE_FAILED;
461  }
462 
463  uint64_t bytes_written = LZ4F_compressBegin(comp->lz4f_context,
464  comp->buffer, comp->buffer_size, NULL);
465  if (LZ4F_isError(bytes_written)) {
466  SCLogError(SC_ERR_PCAP_LOG_COMPRESS, "LZ4F_compressBegin: %s",
467  LZ4F_getErrorName(bytes_written));
468  return TM_ECODE_FAILED;
469  }
470  if (fwrite(comp->buffer, 1, bytes_written, comp->file) < bytes_written) {
471  SCLogError(SC_ERR_FWRITE, "fwrite failed: %s", strerror(errno));
472  return TM_ECODE_FAILED;
473  }
474  }
475 #endif /* HAVE_LIBLZ4 */
476  }
477 
479  return TM_ECODE_OK;
480 }
481 
482 /** \internal
483  * \brief lock wrapper for main PcapLog() function
484  * NOTE: only meant for use in main PcapLog() function.
485  */
486 static void PcapLogLock(PcapLogData *pl)
487 {
488  if (!(pl->is_private)) {
490  SCMutexLock(&pl->plog_lock);
492  }
493 }
494 
495 /** \internal
496  * \brief unlock wrapper for main PcapLog() function
497  * NOTE: only meant for use in main PcapLog() function.
498  */
499 static void PcapLogUnlock(PcapLogData *pl)
500 {
501  if (!(pl->is_private)) {
503  SCMutexUnlock(&pl->plog_lock);
505  }
506 }
507 
508 static inline int PcapWrite(
509  PcapLogData *pl, PcapLogCompressionData *comp, uint8_t *data, size_t len)
510 {
511  struct timeval current_dump;
512  gettimeofday(&current_dump, NULL);
513  pcap_dump((u_char *)pl->pcap_dumper, pl->h, data);
514  if (pl->compression.format == PCAP_LOG_COMPRESSION_FORMAT_NONE) {
515  pl->size_current += len;
516  }
517 #ifdef HAVE_LIBLZ4
518  else if (pl->compression.format == PCAP_LOG_COMPRESSION_FORMAT_LZ4) {
519  pcap_dump_flush(pl->pcap_dumper);
520  uint64_t in_size = (uint64_t)ftell(comp->pcap_buf_wrapper);
521  uint64_t out_size = LZ4F_compressUpdate(
522  comp->lz4f_context, comp->buffer, comp->buffer_size, comp->pcap_buf, in_size, NULL);
523  if (LZ4F_isError(len)) {
524  SCLogError(SC_ERR_PCAP_LOG_COMPRESS, "LZ4F_compressUpdate: %s", LZ4F_getErrorName(len));
525  return TM_ECODE_FAILED;
526  }
527  if (fseek(pl->compression.pcap_buf_wrapper, 0, SEEK_SET) != 0) {
528  SCLogError(SC_ERR_FSEEK, "fseek failed: %s", strerror(errno));
529  return TM_ECODE_FAILED;
530  }
531  if (fwrite(comp->buffer, 1, out_size, comp->file) < out_size) {
532  SCLogError(SC_ERR_FWRITE, "fwrite failed: %s", strerror(errno));
533  return TM_ECODE_FAILED;
534  }
535  if (out_size > 0) {
536  pl->size_current += out_size;
537  comp->bytes_in_block = len;
538  } else {
539  comp->bytes_in_block += len;
540  }
541  }
542 #endif /* HAVE_LIBLZ4 */
543  if (TimeDifferenceMicros(pl->last_pcap_dump, current_dump) >= PCAP_BUFFER_TIMEOUT) {
544  pcap_dump_flush(pl->pcap_dumper);
545  }
546  pl->last_pcap_dump = current_dump;
547  return TM_ECODE_OK;
548 }
549 
554 };
555 
556 static int PcapLogSegmentCallback(
557  const Packet *p, TcpSegment *seg, void *data, const uint8_t *buf, uint32_t buflen)
558 {
559  struct PcapLogCallbackContext *pctx = (struct PcapLogCallbackContext *)data;
560 
561  if (seg->pcap_hdr_storage->pktlen) {
562  pctx->pl->h->ts.tv_sec = seg->pcap_hdr_storage->ts.tv_sec;
563  pctx->pl->h->ts.tv_usec = seg->pcap_hdr_storage->ts.tv_usec;
564  pctx->pl->h->len = seg->pcap_hdr_storage->pktlen + buflen;
565  pctx->pl->h->caplen = seg->pcap_hdr_storage->pktlen + buflen;
566  MemBufferReset(pctx->buf);
568  MemBufferWriteRaw(pctx->buf, buf, buflen);
569 
570  PcapWrite(pctx->pl, pctx->connp, (uint8_t *)pctx->buf->buffer, pctx->pl->h->len);
571  }
572  return 1;
573 }
574 
575 static void PcapLogDumpSegments(
577 {
578  uint8_t flag;
579  flag = STREAM_DUMP_HEADERS;
580 
581  /* Loop on segment from this side */
582  struct PcapLogCallbackContext data = { td->pcap_log, connp, td->buf };
583  StreamSegmentForSession(p, flag, PcapLogSegmentCallback, (void *)&data);
584 }
585 
586 /**
587  * \brief Pcap logging main function
588  *
589  * \param t threadvar
590  * \param p packet
591  * \param thread_data thread module specific data
592  *
593  * \retval TM_ECODE_OK on succes
594  * \retval TM_ECODE_FAILED on serious error
595  */
596 static int PcapLog (ThreadVars *t, void *thread_data, const Packet *p)
597 {
598  size_t len;
599  int rotate = 0;
600  int ret = 0;
601  Packet *rp = NULL;
602 
603  PcapLogThreadData *td = (PcapLogThreadData *)thread_data;
604  PcapLogData *pl = td->pcap_log;
605 
608  return TM_ECODE_OK;
609  }
610 
611  PcapLogLock(pl);
612 
613  pl->pkt_cnt++;
614  pl->h->ts.tv_sec = p->ts.tv_sec;
615  pl->h->ts.tv_usec = p->ts.tv_usec;
616  if (IS_TUNNEL_PKT(p) && !IS_TUNNEL_ROOT_PKT(p)) {
617  rp = p->root;
618  pl->h->caplen = GET_PKT_LEN(rp);
619  pl->h->len = GET_PKT_LEN(rp);
620  len = sizeof(*pl->h) + GET_PKT_LEN(rp);
621  } else {
622  pl->h->caplen = GET_PKT_LEN(p);
623  pl->h->len = GET_PKT_LEN(p);
624  len = sizeof(*pl->h) + GET_PKT_LEN(p);
625  }
626 
627  if (pl->filename == NULL) {
628  ret = PcapLogOpenFileCtx(pl);
629  if (ret < 0) {
630  PcapLogUnlock(pl);
631  return TM_ECODE_FAILED;
632  }
633  SCLogDebug("Opening PCAP log file %s", pl->filename);
634  }
635 
636  if (pl->mode == LOGMODE_SGUIL) {
637  struct tm local_tm;
638  struct tm *tms = SCLocalTime(p->ts.tv_sec, &local_tm);
639  if (tms->tm_mday != pl->prev_day) {
640  rotate = 1;
641  pl->prev_day = tms->tm_mday;
642  }
643  }
644 
645  PcapLogCompressionData *comp = &pl->compression;
647  if ((pl->size_current + len) > pl->size_limit || rotate) {
648  if (PcapLogRotateFile(t,pl) < 0) {
649  PcapLogUnlock(pl);
650  SCLogDebug("rotation of pcap failed");
651  return TM_ECODE_FAILED;
652  }
653  }
654  }
655 #ifdef HAVE_LIBLZ4
656  else if (comp->format == PCAP_LOG_COMPRESSION_FORMAT_LZ4) {
657  /* When writing compressed pcap logs, we have no way of knowing
658  * for sure whether adding this packet would cause the current
659  * file to exceed the size limit. Thus, we record the number of
660  * bytes that have been fed into lz4 since the last write, and
661  * act as if they would be written uncompressed. */
662 
663  if ((pl->size_current + comp->bytes_in_block + len) > pl->size_limit ||
664  rotate) {
665  if (PcapLogRotateFile(t,pl) < 0) {
666  PcapLogUnlock(pl);
667  SCLogDebug("rotation of pcap failed");
668  return TM_ECODE_FAILED;
669  }
670  }
671  }
672 #endif /* HAVE_LIBLZ4 */
673 
674  /* XXX pcap handles, nfq, pfring, can only have one link type ipfw? we do
675  * this here as we don't know the link type until we get our first packet */
676  if (pl->pcap_dead_handle == NULL || pl->pcap_dumper == NULL) {
677  if (PcapLogOpenHandles(pl, p) != TM_ECODE_OK) {
678  PcapLogUnlock(pl);
679  return TM_ECODE_FAILED;
680  }
681  }
682 
684 
685  /* if we are using alerted logging and if packet is first one with alert in flow
686  * then we need to dump in the pcap the stream acked by the packet */
687  if ((p->flags & PKT_FIRST_ALERTS) && (td->pcap_log->conditional != LOGMODE_COND_ALL)) {
688  if (PKT_IS_TCP(p)) {
689  /* dump fake packets for all segments we have on acked by packet */
690 #ifdef HAVE_LIBLZ4
691  PcapLogDumpSegments(td, comp, p);
692 #else
693  PcapLogDumpSegments(td, NULL, p);
694 #endif
695  if (p->flags & PKT_PSEUDO_STREAM_END) {
696  PcapLogUnlock(pl);
697  return TM_ECODE_OK;
698  }
699 
700  /* PcapLogDumpSegment has writtens over the PcapLogData variables so need to update */
701  pl->h->ts.tv_sec = p->ts.tv_sec;
702  pl->h->ts.tv_usec = p->ts.tv_usec;
703  if (IS_TUNNEL_PKT(p) && !IS_TUNNEL_ROOT_PKT(p)) {
704  rp = p->root;
705  pl->h->caplen = GET_PKT_LEN(rp);
706  pl->h->len = GET_PKT_LEN(rp);
707  len = sizeof(*pl->h) + GET_PKT_LEN(rp);
708  } else {
709  pl->h->caplen = GET_PKT_LEN(p);
710  pl->h->len = GET_PKT_LEN(p);
711  len = sizeof(*pl->h) + GET_PKT_LEN(p);
712  }
713  }
714  }
715 
716  if (IS_TUNNEL_PKT(p) && !IS_TUNNEL_ROOT_PKT(p)) {
717  rp = p->root;
718 #ifdef HAVE_LIBLZ4
719  ret = PcapWrite(pl, comp, GET_PKT_DATA(rp), len);
720 #else
721  ret = PcapWrite(pl, NULL, GET_PKT_DATA(rp), len);
722 #endif
723  } else {
724 #ifdef HAVE_LIBLZ4
725  ret = PcapWrite(pl, comp, GET_PKT_DATA(p), len);
726 #else
727  ret = PcapWrite(pl, NULL, GET_PKT_DATA(p), len);
728 #endif
729  }
730  if (ret != TM_ECODE_OK) {
732  PcapLogUnlock(pl);
733  return ret;
734  }
735 
737  pl->profile_data_size += len;
738 
739  SCLogDebug("pl->size_current %"PRIu64", pl->size_limit %"PRIu64,
740  pl->size_current, pl->size_limit);
741 
742  PcapLogUnlock(pl);
743  return TM_ECODE_OK;
744 }
745 
746 static PcapLogData *PcapLogDataCopy(const PcapLogData *pl)
747 {
748  BUG_ON(pl->mode != LOGMODE_MULTI);
749  PcapLogData *copy = SCCalloc(1, sizeof(*copy));
750  if (unlikely(copy == NULL)) {
751  return NULL;
752  }
753 
754  copy->h = SCCalloc(1, sizeof(*copy->h));
755  if (unlikely(copy->h == NULL)) {
756  SCFree(copy);
757  return NULL;
758  }
759 
760  copy->prefix = SCStrdup(pl->prefix);
761  if (unlikely(copy->prefix == NULL)) {
762  SCFree(copy->h);
763  SCFree(copy);
764  return NULL;
765  }
766 
767  copy->suffix = pl->suffix;
768 
769  /* settings TODO move to global cfg struct */
770  copy->is_private = TRUE;
771  copy->mode = pl->mode;
772  copy->max_files = pl->max_files;
773  copy->use_ringbuffer = pl->use_ringbuffer;
774  copy->timestamp_format = pl->timestamp_format;
776  copy->size_limit = pl->size_limit;
777  copy->conditional = pl->conditional;
778 
779  const PcapLogCompressionData *comp = &pl->compression;
780  PcapLogCompressionData *copy_comp = &copy->compression;
781  copy_comp->format = comp->format;
782 #ifdef HAVE_LIBLZ4
784  /* We need to allocate a new compression context and buffers for
785  * the copy. First copy the things that can simply be copied. */
786 
787  copy_comp->buffer_size = comp->buffer_size;
788  copy_comp->pcap_buf_size = comp->pcap_buf_size;
789  copy_comp->lz4f_prefs = comp->lz4f_prefs;
790 
791  /* Allocate the buffers. */
792 
793  copy_comp->buffer = SCMalloc(copy_comp->buffer_size);
794  if (copy_comp->buffer == NULL) {
795  SCLogError(SC_ERR_MEM_ALLOC, "SCMalloc failed: %s",
796  strerror(errno));
797  SCFree(copy->h);
798  SCFree(copy);
799  return NULL;
800  }
801  copy_comp->pcap_buf = SCMalloc(copy_comp->pcap_buf_size);
802  if (copy_comp->pcap_buf == NULL) {
803  SCLogError(SC_ERR_MEM_ALLOC, "SCMalloc failed: %s",
804  strerror(errno));
805  SCFree(copy_comp->buffer);
806  SCFree(copy->h);
807  SCFree(copy);
808  return NULL;
809  }
810  copy_comp->pcap_buf_wrapper = SCFmemopen(copy_comp->pcap_buf,
811  copy_comp->pcap_buf_size, "w");
812  if (copy_comp->pcap_buf_wrapper == NULL) {
813  SCLogError(SC_ERR_FOPEN, "SCFmemopen failed: %s", strerror(errno));
814  SCFree(copy_comp->buffer);
815  SCFree(copy_comp->pcap_buf);
816  SCFree(copy->h);
817  SCFree(copy);
818  return NULL;
819  }
820 
821  /* Initialize a new compression context. */
822 
823  LZ4F_errorCode_t errcode =
824  LZ4F_createCompressionContext(&copy_comp->lz4f_context, 1);
825  if (LZ4F_isError(errcode)) {
827  "LZ4F_createCompressionContext failed: %s",
828  LZ4F_getErrorName(errcode));
829  fclose(copy_comp->pcap_buf_wrapper);
830  SCFree(copy_comp->buffer);
831  SCFree(copy_comp->pcap_buf);
832  SCFree(copy->h);
833  SCFree(copy);
834  return NULL;
835  }
836 
837  /* Initialize the rest. */
838 
839  copy_comp->file = NULL;
840  copy_comp->bytes_in_block = 0;
841  }
842 #endif /* HAVE_LIBLZ4 */
843 
844  TAILQ_INIT(&copy->pcap_file_list);
845  SCMutexInit(&copy->plog_lock, NULL);
846 
847  strlcpy(copy->dir, pl->dir, sizeof(copy->dir));
848 
849  int i;
850  for (i = 0; i < pl->filename_part_cnt && i < MAX_TOKS; i++)
851  copy->filename_parts[i] = pl->filename_parts[i];
852  copy->filename_part_cnt = pl->filename_part_cnt;
853 
854  /* set thread number, first thread is 1 */
855  copy->thread_number = SC_ATOMIC_ADD(thread_cnt, 1);
856 
857  SCLogDebug("copied, returning %p", copy);
858  return copy;
859 }
860 
861 #ifdef INIT_RING_BUFFER
862 static int PcapLogGetTimeOfFile(const char *filename, uint64_t *secs,
863  uint32_t *usecs)
864 {
865  char buf[PATH_MAX];
866  size_t copylen;
867 
868  int n = pcre2_match(pcre_timestamp_code, (PCRE2_SPTR8)filename, strlen(filename), 0, 0,
869  pcre_timestamp_match, NULL);
870  if (n != 2 && n != 4) {
871  /* No match. */
872  return 0;
873  }
874 
875  if (n >= 2) {
876  /* Extract seconds. */
877  copylen = sizeof(buf);
878  if (pcre2_substring_copy_bynumber(pcre_timestamp_match, 1, (PCRE2_UCHAR8 *)buf, &copylen) <
879  0) {
880  return 0;
881  }
882  if (StringParseUint64(secs, 10, 0, buf) < 0) {
883  return 0;
884  }
885  }
886  if (n == 4) {
887  /* Extract microseconds. */
888  copylen = sizeof(buf);
889  if (pcre2_substring_copy_bynumber(pcre_timestamp_match, 3, (PCRE2_UCHAR8 *)buf, &copylen) <
890  0) {
891  return 0;
892  }
893  if (StringParseUint32(usecs, 10, 0, buf) < 0) {
894  return 0;
895  }
896  }
897 
898  return 1;
899 }
900 
901 static TmEcode PcapLogInitRingBuffer(PcapLogData *pl)
902 {
903  char pattern[PATH_MAX];
904 
905  SCLogInfo("Initializing PCAP ring buffer for %s/%s.",
906  pl->dir, pl->prefix);
907 
908  strlcpy(pattern, pl->dir, PATH_MAX);
909  if (pattern[strlen(pattern) - 1] != '/') {
910  strlcat(pattern, "/", PATH_MAX);
911  }
912  if (pl->mode == LOGMODE_MULTI) {
913  for (int i = 0; i < pl->filename_part_cnt; i++) {
914  char *part = pl->filename_parts[i];
915  if (part == NULL || strlen(part) == 0) {
916  continue;
917  }
918  if (part[0] != '%' || strlen(part) < 2) {
919  strlcat(pattern, part, PATH_MAX);
920  continue;
921  }
922  switch (part[1]) {
923  case 'i':
924  SCLogError(
925  SC_ERR_INVALID_ARGUMENT, "Thread ID not allowed in ring buffer mode.");
926  return TM_ECODE_FAILED;
927  case 'n': {
928  char tmp[PATH_MAX];
929  snprintf(tmp, PATH_MAX, "%"PRIu32, pl->thread_number);
930  strlcat(pattern, tmp, PATH_MAX);
931  break;
932  }
933  case 't':
934  strlcat(pattern, "*", PATH_MAX);
935  break;
936  default:
938  "Unsupported format character: %%%s", part);
939  return TM_ECODE_FAILED;
940  }
941  }
942  } else {
943  strlcat(pattern, pl->prefix, PATH_MAX);
944  strlcat(pattern, ".*", PATH_MAX);
945  }
946  strlcat(pattern, pl->suffix, PATH_MAX);
947 
948  char *basename = strrchr(pattern, '/');
949  *basename++ = '\0';
950 
951  /* Pattern is now just the directory name. */
952  DIR *dir = opendir(pattern);
953  if (dir == NULL) {
954  SCLogWarning(SC_ERR_DIR_OPEN, "Failed to open directory %s: %s",
955  pattern, strerror(errno));
956  return TM_ECODE_FAILED;
957  }
958 
959  for (;;) {
960  struct dirent *entry = readdir(dir);
961  if (entry == NULL) {
962  break;
963  }
964  if (fnmatch(basename, entry->d_name, 0) != 0) {
965  continue;
966  }
967 
968  uint64_t secs = 0;
969  uint32_t usecs = 0;
970 
971  if (!PcapLogGetTimeOfFile(entry->d_name, &secs, &usecs)) {
972  /* Failed to get time stamp out of file name. Not necessarily a
973  * failure as the file might just not be a pcap log file. */
974  continue;
975  }
976 
977  PcapFileName *pf = SCCalloc(sizeof(*pf), 1);
978  if (unlikely(pf == NULL)) {
979  goto fail;
980  }
981  char path[PATH_MAX];
982  if (snprintf(path, PATH_MAX, "%s/%s", pattern, entry->d_name) == PATH_MAX)
983  goto fail;
984 
985  if ((pf->filename = SCStrdup(path)) == NULL) {
986  goto fail;
987  }
988  if ((pf->dirname = SCStrdup(pattern)) == NULL) {
989  goto fail;
990  }
991  pf->secs = secs;
992  pf->usecs = usecs;
993 
994  if (TAILQ_EMPTY(&pl->pcap_file_list)) {
995  TAILQ_INSERT_TAIL(&pl->pcap_file_list, pf, next);
996  } else {
997  /* Ordered insert. */
998  PcapFileName *it = NULL;
999  TAILQ_FOREACH(it, &pl->pcap_file_list, next) {
1000  if (pf->secs < it->secs) {
1001  break;
1002  } else if (pf->secs == it->secs && pf->usecs < it->usecs) {
1003  break;
1004  }
1005  }
1006  if (it == NULL) {
1007  TAILQ_INSERT_TAIL(&pl->pcap_file_list, pf, next);
1008  } else {
1009  TAILQ_INSERT_BEFORE(it, pf, next);
1010  }
1011  }
1012  pl->file_cnt++;
1013  continue;
1014 
1015  fail:
1016  if (pf != NULL) {
1017  if (pf->filename != NULL) {
1018  SCFree(pf->filename);
1019  }
1020  if (pf->dirname != NULL) {
1021  SCFree(pf->dirname);
1022  }
1023  SCFree(pf);
1024  }
1025  break;
1026  }
1027 
1028  if (pl->file_cnt > pl->max_files) {
1029  PcapFileName *pf = TAILQ_FIRST(&pl->pcap_file_list);
1030  while (pf != NULL && pl->file_cnt > pl->max_files) {
1031  SCLogDebug("Removing PCAP file %s", pf->filename);
1032  if (remove(pf->filename) != 0) {
1034  "Failed to remove PCAP file %s: %s", pf->filename,
1035  strerror(errno));
1036  }
1037  TAILQ_REMOVE(&pl->pcap_file_list, pf, next);
1038  PcapFileNameFree(pf);
1039  pf = TAILQ_FIRST(&pl->pcap_file_list);
1040  pl->file_cnt--;
1041  }
1042  }
1043 
1044  closedir(dir);
1045 
1046  /* For some reason file count is initialized at one, instead of 0. */
1047  SCLogNotice("Ring buffer initialized with %d files.", pl->file_cnt - 1);
1048 
1049  return TM_ECODE_OK;
1050 }
1051 #endif /* INIT_RING_BUFFER */
1052 
1053 static TmEcode PcapLogDataInit(ThreadVars *t, const void *initdata, void **data)
1054 {
1055  if (initdata == NULL) {
1056  SCLogDebug("Error getting context for LogPcap. \"initdata\" argument NULL");
1057  return TM_ECODE_FAILED;
1058  }
1059 
1060  PcapLogData *pl = ((OutputCtx *)initdata)->data;
1061 
1062  PcapLogThreadData *td = SCCalloc(1, sizeof(*td));
1063  if (unlikely(td == NULL))
1064  return TM_ECODE_FAILED;
1065 
1066  if (pl->mode == LOGMODE_MULTI)
1067  td->pcap_log = PcapLogDataCopy(pl);
1068  else
1069  td->pcap_log = pl;
1070  BUG_ON(td->pcap_log == NULL);
1071 
1072  if (DatalinkHasMultipleValues()) {
1073  if (pl->mode != LOGMODE_MULTI) {
1075  "Pcap logging with multiple link type is not supported.");
1076  } else {
1077  /* In multi mode, only pcap conditional is not supported as a flow timeout
1078  * will trigger packet logging with potentially invalid datalink. In regular
1079  * pcap logging, the logging should be done in the same thread if we
1080  * have a proper load balancing. So no mix of datalink should occur. But we need a
1081  * proper load balancing so this needs at least a warning.
1082  */
1083  switch (pl->conditional) {
1084  case LOGMODE_COND_ALERTS:
1085  case LOGMODE_COND_TAG:
1087  "Can't have multiple link types in pcap conditional mode.");
1088  break;
1089  default:
1091  "Using multiple link types can result in invalid pcap output");
1092  }
1093  }
1094  }
1095 
1096  PcapLogLock(td->pcap_log);
1097 
1098  /** Use the Ouptut Context (file pointer and mutex) */
1099  td->pcap_log->pkt_cnt = 0;
1100  td->pcap_log->pcap_dead_handle = NULL;
1101  td->pcap_log->pcap_dumper = NULL;
1102  if (td->pcap_log->file_cnt < 1) {
1103  td->pcap_log->file_cnt = 1;
1104  }
1105 
1106  struct timeval ts;
1107  memset(&ts, 0x00, sizeof(struct timeval));
1108  TimeGet(&ts);
1109  struct tm local_tm;
1110  struct tm *tms = SCLocalTime(ts.tv_sec, &local_tm);
1111  td->pcap_log->prev_day = tms->tm_mday;
1112 
1113  PcapLogUnlock(td->pcap_log);
1114 
1115  /* count threads in the global structure */
1116  SCMutexLock(&pl->plog_lock);
1117  pl->threads++;
1118  SCMutexUnlock(&pl->plog_lock);
1119 
1120  *data = (void *)td;
1121 
1124  } else {
1125  td->buf = NULL;
1126  }
1127 
1128  if (pl->max_files && (pl->mode == LOGMODE_MULTI || pl->threads == 1)) {
1129 #ifdef INIT_RING_BUFFER
1130  if (PcapLogInitRingBuffer(td->pcap_log) == TM_ECODE_FAILED) {
1131  return TM_ECODE_FAILED;
1132  }
1133 #else
1134  SCLogInfo("Unable to initialize ring buffer on this platform.");
1135 #endif /* INIT_RING_BUFFER */
1136  }
1137 
1138  if (pl->mode == LOGMODE_MULTI) {
1139  PcapLogOpenFileCtx(td->pcap_log);
1140  } else {
1141  if (pl->filename == NULL) {
1142  PcapLogOpenFileCtx(pl);
1143  }
1144  }
1145 
1146  return TM_ECODE_OK;
1147 }
1148 
1149 static void StatsMerge(PcapLogData *dst, PcapLogData *src)
1150 {
1151  dst->profile_open.total += src->profile_open.total;
1152  dst->profile_open.cnt += src->profile_open.cnt;
1153 
1154  dst->profile_close.total += src->profile_close.total;
1155  dst->profile_close.cnt += src->profile_close.cnt;
1156 
1157  dst->profile_write.total += src->profile_write.total;
1158  dst->profile_write.cnt += src->profile_write.cnt;
1159 
1160  dst->profile_rotate.total += src->profile_rotate.total;
1161  dst->profile_rotate.cnt += src->profile_rotate.cnt;
1162 
1163  dst->profile_handles.total += src->profile_handles.total;
1164  dst->profile_handles.cnt += src->profile_handles.cnt;
1165 
1166  dst->profile_lock.total += src->profile_lock.total;
1167  dst->profile_lock.cnt += src->profile_lock.cnt;
1168 
1169  dst->profile_unlock.total += src->profile_unlock.total;
1170  dst->profile_unlock.cnt += src->profile_unlock.cnt;
1171 
1172  dst->profile_data_size += src->profile_data_size;
1173 }
1174 
1175 static void PcapLogDataFree(PcapLogData *pl)
1176 {
1177 
1178  PcapFileName *pf;
1179  while ((pf = TAILQ_FIRST(&pl->pcap_file_list)) != NULL) {
1180  TAILQ_REMOVE(&pl->pcap_file_list, pf, next);
1181  PcapFileNameFree(pf);
1182  }
1183  if (pl == g_pcap_data) {
1184  for (int i = 0; i < MAX_TOKS; i++) {
1185  if (pl->filename_parts[i] != NULL) {
1186  SCFree(pl->filename_parts[i]);
1187  }
1188  }
1189  }
1190  SCFree(pl->h);
1191  SCFree(pl->filename);
1192  SCFree(pl->prefix);
1193 
1194 #ifdef HAVE_LIBLZ4
1195  if (pl->compression.format == PCAP_LOG_COMPRESSION_FORMAT_LZ4) {
1196  SCFree(pl->compression.buffer);
1197  fclose(pl->compression.pcap_buf_wrapper);
1198  SCFree(pl->compression.pcap_buf);
1199  LZ4F_errorCode_t errcode =
1200  LZ4F_freeCompressionContext(pl->compression.lz4f_context);
1201  if (LZ4F_isError(errcode)) {
1202  SCLogWarning(SC_ERR_MEM_ALLOC, "Error freeing lz4 context.");
1203  }
1204  }
1205 #endif /* HAVE_LIBLZ4 */
1206  SCFree(pl);
1207 }
1208 
1209 /**
1210  * \brief Thread deinit function.
1211  *
1212  * \param t Thread Variable containing input/output queue, cpu affinity etc.
1213  * \param data PcapLog thread data.
1214  * \retval TM_ECODE_OK on succces
1215  * \retval TM_ECODE_FAILED on failure
1216  */
1217 static TmEcode PcapLogDataDeinit(ThreadVars *t, void *thread_data)
1218 {
1219  PcapLogThreadData *td = (PcapLogThreadData *)thread_data;
1220  PcapLogData *pl = td->pcap_log;
1221 
1222  if (pl->pcap_dumper != NULL) {
1223  if (PcapLogCloseFile(t,pl) < 0) {
1224  SCLogDebug("PcapLogCloseFile failed");
1225  }
1226  }
1227 
1228  if (pl->mode == LOGMODE_MULTI) {
1229  SCMutexLock(&g_pcap_data->plog_lock);
1230  StatsMerge(g_pcap_data, pl);
1231  g_pcap_data->reported++;
1232  if (g_pcap_data->threads == g_pcap_data->reported)
1233  PcapLogProfilingDump(g_pcap_data);
1234  SCMutexUnlock(&g_pcap_data->plog_lock);
1235  } else {
1236  if (pl->reported == 0) {
1237  PcapLogProfilingDump(pl);
1238  pl->reported = 1;
1239  }
1240  }
1241 
1242  if (pl != g_pcap_data) {
1243  PcapLogDataFree(pl);
1244  }
1245 
1246  if (td->buf)
1247  MemBufferFree(td->buf);
1248 
1249  SCFree(td);
1250  return TM_ECODE_OK;
1251 }
1252 
1253 
1254 static int ParseFilename(PcapLogData *pl, const char *filename)
1255 {
1256  char *toks[MAX_TOKS] = { NULL };
1257  int tok = 0;
1258  char str[MAX_FILENAMELEN] = "";
1259  int s = 0;
1260  int i, x;
1261  char *p = NULL;
1262  size_t filename_len = 0;
1263 
1264  if (filename) {
1265  filename_len = strlen(filename);
1266  if (filename_len > (MAX_FILENAMELEN-1)) {
1267  SCLogError(SC_ERR_INVALID_ARGUMENT, "invalid filename option. Max filename-length: %d",MAX_FILENAMELEN-1);
1268  goto error;
1269  }
1270 
1271  for (i = 0; i < (int)strlen(filename); i++) {
1272  if (tok >= MAX_TOKS) {
1274  "invalid filename option. Max 2 %%-sign options");
1275  goto error;
1276  }
1277 
1278  str[s++] = filename[i];
1279 
1280  if (filename[i] == '%') {
1281  str[s-1] = '\0';
1282  SCLogDebug("filename with %%-sign: %s", str);
1283 
1284  p = SCStrdup(str);
1285  if (p == NULL)
1286  goto error;
1287  toks[tok++] = p;
1288 
1289  s = 0;
1290 
1291  if (i+1 < (int)strlen(filename)) {
1292  if (tok >= MAX_TOKS) {
1294  "invalid filename option. Max 2 %%-sign options");
1295  goto error;
1296  }
1297 
1298  if (filename[i+1] != 'n' && filename[i+1] != 't' && filename[i+1] != 'i') {
1300  "invalid filename option. Valid %%-sign options: %%n, %%i and %%t");
1301  goto error;
1302  }
1303  str[0] = '%';
1304  str[1] = filename[i+1];
1305  str[2] = '\0';
1306  p = SCStrdup(str);
1307  if (p == NULL)
1308  goto error;
1309  toks[tok++] = p;
1310  i++;
1311  }
1312  }
1313  }
1314 
1315  if ((tok == 0) && (pl->mode == LOGMODE_MULTI)) {
1317  "Invalid filename for multimode. Need at list one %%-sign option");
1318  goto error;
1319  }
1320 
1321  if (s) {
1322  if (tok >= MAX_TOKS) {
1324  "invalid filename option. Max 3 %%-sign options");
1325  goto error;
1326 
1327  }
1328  str[s++] = '\0';
1329  p = SCStrdup(str);
1330  if (p == NULL)
1331  goto error;
1332  toks[tok++] = p;
1333  }
1334 
1335  /* finally, store tokens in the pl */
1336  for (i = 0; i < tok; i++) {
1337  if (toks[i] == NULL)
1338  goto error;
1339 
1340  SCLogDebug("toks[%d] %s", i, toks[i]);
1341  pl->filename_parts[i] = toks[i];
1342  }
1343  pl->filename_part_cnt = tok;
1344  }
1345  return 0;
1346 error:
1347  for (x = 0; x < MAX_TOKS; x++) {
1348  if (toks[x] != NULL)
1349  SCFree(toks[x]);
1350  }
1351  return -1;
1352 }
1353 
1354 /** \brief Fill in pcap logging struct from the provided ConfNode.
1355  * \param conf The configuration node for this output.
1356  * \retval output_ctx
1357  * */
1358 static OutputInitResult PcapLogInitCtx(ConfNode *conf)
1359 {
1360  OutputInitResult result = { NULL, false };
1361  int en;
1362  PCRE2_SIZE eo = 0;
1363 
1364  PcapLogData *pl = SCMalloc(sizeof(PcapLogData));
1365  if (unlikely(pl == NULL)) {
1366  FatalError(SC_ERR_FATAL, "Failed to allocate Memory for PcapLogData");
1367  }
1368  memset(pl, 0, sizeof(PcapLogData));
1369 
1370  pl->h = SCMalloc(sizeof(*pl->h));
1371  if (pl->h == NULL) {
1373  "Failed to allocate Memory for pcap header struct");
1374  }
1375 
1376  /* Set the defaults */
1377  pl->mode = LOGMODE_NORMAL;
1379  pl->use_ringbuffer = RING_BUFFER_MODE_DISABLED;
1380  pl->timestamp_format = TS_FORMAT_SEC;
1384 
1385  TAILQ_INIT(&pl->pcap_file_list);
1386 
1387  SCMutexInit(&pl->plog_lock, NULL);
1388 
1389  /* Initialize PCREs. */
1390  pcre_timestamp_code =
1391  pcre2_compile((PCRE2_SPTR8)timestamp_pattern, PCRE2_ZERO_TERMINATED, 0, &en, &eo, NULL);
1392  if (pcre_timestamp_code == NULL) {
1393  PCRE2_UCHAR errbuffer[256];
1394  pcre2_get_error_message(en, errbuffer, sizeof(errbuffer));
1395  FatalError(SC_ERR_PCRE_COMPILE, "Failed to compile \"%s\" at offset %d: %s",
1396  timestamp_pattern, (int)eo, errbuffer);
1397  }
1398  pcre_timestamp_match = pcre2_match_data_create_from_pattern(pcre_timestamp_code, NULL);
1399 
1400  /* conf params */
1401 
1402  const char *filename = NULL;
1403 
1404  if (conf != NULL) { /* To faciliate unit tests. */
1405  filename = ConfNodeLookupChildValue(conf, "filename");
1406  }
1407 
1408  if (filename == NULL)
1409  filename = DEFAULT_LOG_FILENAME;
1410 
1411  if ((pl->prefix = SCStrdup(filename)) == NULL) {
1412  exit(EXIT_FAILURE);
1413  }
1414 
1415  pl->suffix = "";
1416 
1417  pl->size_limit = DEFAULT_LIMIT;
1418  if (conf != NULL) {
1419  const char *s_limit = NULL;
1420  s_limit = ConfNodeLookupChildValue(conf, "limit");
1421  if (s_limit != NULL) {
1422  if (ParseSizeStringU64(s_limit, &pl->size_limit) < 0) {
1424  "Failed to initialize pcap output, invalid limit: %s",
1425  s_limit);
1426  exit(EXIT_FAILURE);
1427  }
1428  if (pl->size_limit < 4096) {
1429  SCLogInfo("pcap-log \"limit\" value of %"PRIu64" assumed to be pre-1.2 "
1430  "style: setting limit to %"PRIu64"mb", pl->size_limit, pl->size_limit);
1431  uint64_t size = pl->size_limit * 1024 * 1024;
1432  pl->size_limit = size;
1433  } else if (pl->size_limit < MIN_LIMIT) {
1435  "Fail to initialize pcap-log output, limit less than "
1436  "allowed minimum.");
1437  }
1438  }
1439  }
1440 
1441  if (conf != NULL) {
1442  const char *s_mode = NULL;
1443  s_mode = ConfNodeLookupChildValue(conf, "mode");
1444  if (s_mode != NULL) {
1445  if (strcasecmp(s_mode, "sguil") == 0) {
1446  pl->mode = LOGMODE_SGUIL;
1447  } else if (strcasecmp(s_mode, "multi") == 0) {
1448  pl->mode = LOGMODE_MULTI;
1449  } else if (strcasecmp(s_mode, "normal") != 0) {
1451  "log-pcap: invalid mode \"%s\". Valid options: \"normal\", "
1452  "\"sguil\", or \"multi\" mode ", s_mode);
1453  exit(EXIT_FAILURE);
1454  }
1455  }
1456 
1457  const char *s_dir = NULL;
1458  s_dir = ConfNodeLookupChildValue(conf, "dir");
1459  if (s_dir == NULL) {
1460  s_dir = ConfNodeLookupChildValue(conf, "sguil-base-dir");
1461  }
1462  if (s_dir == NULL) {
1463  if (pl->mode == LOGMODE_SGUIL) {
1465  "log-pcap \"sguil\" mode requires \"sguil-base-dir\" "
1466  "option to be set.");
1467  } else {
1468  const char *log_dir = NULL;
1469  log_dir = ConfigGetLogDirectory();
1470 
1471  strlcpy(pl->dir,
1472  log_dir, sizeof(pl->dir));
1473  SCLogInfo("Using log dir %s", pl->dir);
1474  }
1475  } else {
1476  if (PathIsAbsolute(s_dir)) {
1477  strlcpy(pl->dir,
1478  s_dir, sizeof(pl->dir));
1479  } else {
1480  const char *log_dir = NULL;
1481  log_dir = ConfigGetLogDirectory();
1482 
1483  snprintf(pl->dir, sizeof(pl->dir), "%s/%s",
1484  log_dir, s_dir);
1485  }
1486 
1487  struct stat stat_buf;
1488  if (stat(pl->dir, &stat_buf) != 0) {
1489  SCLogError(SC_ERR_LOGDIR_CONFIG, "The sguil-base-dir directory \"%s\" "
1490  "supplied doesn't exist. Shutting down the engine",
1491  pl->dir);
1492  exit(EXIT_FAILURE);
1493  }
1494  SCLogInfo("Using log dir %s", pl->dir);
1495  }
1496 
1497  const char *compression_str = ConfNodeLookupChildValue(conf,
1498  "compression");
1499 
1500  PcapLogCompressionData *comp = &pl->compression;
1501  if (compression_str == NULL || strcmp(compression_str, "none") == 0) {
1503  comp->buffer = NULL;
1504  comp->buffer_size = 0;
1505  comp->file = NULL;
1506  comp->pcap_buf = NULL;
1507  comp->pcap_buf_size = 0;
1508  comp->pcap_buf_wrapper = NULL;
1509  } else if (strcmp(compression_str, "lz4") == 0) {
1510 #ifdef HAVE_LIBLZ4
1511  if (pl->mode == LOGMODE_SGUIL) {
1512  SCLogError(SC_ERR_INVALID_YAML_CONF_ENTRY, "Compressed pcap "
1513  "logs are not possible in sguil mode");
1514  SCFree(pl->h);
1515  SCFree(pl);
1516  return result;
1517  }
1518  pl->compression.format = PCAP_LOG_COMPRESSION_FORMAT_LZ4;
1519 
1520  /* Use SCFmemopen so we can make pcap_dump write to a buffer. */
1521 
1522  comp->pcap_buf_size = sizeof(struct pcap_file_header) +
1523  sizeof(struct pcap_pkthdr) + PCAP_SNAPLEN;
1524  comp->pcap_buf = SCMalloc(comp->pcap_buf_size);
1525  if (comp->pcap_buf == NULL) {
1526  SCLogError(SC_ERR_MEM_ALLOC, "SCMalloc failed: %s",
1527  strerror(errno));
1528  exit(EXIT_FAILURE);
1529  }
1530  comp->pcap_buf_wrapper = SCFmemopen(comp->pcap_buf,
1531  comp->pcap_buf_size, "w");
1532  if (comp->pcap_buf_wrapper == NULL) {
1533  SCLogError(SC_ERR_FOPEN, "SCFmemopen failed: %s",
1534  strerror(errno));
1535  exit(EXIT_FAILURE);
1536  }
1537 
1538  /* Set lz4 preferences. */
1539 
1540  memset(&comp->lz4f_prefs, '\0', sizeof(comp->lz4f_prefs));
1541  comp->lz4f_prefs.frameInfo.blockSizeID = LZ4F_max4MB;
1542  comp->lz4f_prefs.frameInfo.blockMode = LZ4F_blockLinked;
1543  if (ConfNodeChildValueIsTrue(conf, "lz4-checksum")) {
1544  comp->lz4f_prefs.frameInfo.contentChecksumFlag = 1;
1545  }
1546  else {
1547  comp->lz4f_prefs.frameInfo.contentChecksumFlag = 0;
1548  }
1549  intmax_t lvl = 0;
1550  if (ConfGetChildValueInt(conf, "lz4-level", &lvl)) {
1551  if (lvl > 16) {
1552  lvl = 16;
1553  } else if (lvl < 0) {
1554  lvl = 0;
1555  }
1556  } else {
1557  lvl = 0;
1558  }
1559  comp->lz4f_prefs.compressionLevel = lvl;
1560 
1561  /* Allocate resources for lz4. */
1562 
1563  LZ4F_errorCode_t errcode =
1564  LZ4F_createCompressionContext(&pl->compression.lz4f_context, 1);
1565 
1566  if (LZ4F_isError(errcode)) {
1568  "LZ4F_createCompressionContext failed: %s",
1569  LZ4F_getErrorName(errcode));
1570  exit(EXIT_FAILURE);
1571  }
1572 
1573  /* Calculate the size of the lz4 output buffer. */
1574 
1575  comp->buffer_size = LZ4F_compressBound(comp->pcap_buf_size,
1576  &comp->lz4f_prefs);
1577 
1578  comp->buffer = SCMalloc(comp->buffer_size);
1579  if (unlikely(comp->buffer == NULL)) {
1580  FatalError(SC_ERR_FATAL, "Failed to allocate memory for "
1581  "lz4 output buffer.");
1582  }
1583 
1584  comp->bytes_in_block = 0;
1585 
1586  /* Add the lz4 file extension to the log files. */
1587 
1588  pl->suffix = ".lz4";
1589 #else
1590  SCLogError(SC_ERR_INVALID_ARGUMENT, "lz4 compression was selected "
1591  "in pcap-log, but suricata was not compiled with lz4 "
1592  "support.");
1593  PcapLogDataFree(pl);
1594  return result;
1595 #endif /* HAVE_LIBLZ4 */
1596  }
1597  else {
1598  SCLogError(SC_ERR_INVALID_ARGUMENT, "Unsupported pcap-log "
1599  "compression format: %s", compression_str);
1600  PcapLogDataFree(pl);
1601  return result;
1602  }
1603 
1604  SCLogInfo("Selected pcap-log compression method: %s",
1605  compression_str ? compression_str : "none");
1606 
1607  const char *s_conditional = ConfNodeLookupChildValue(conf, "conditional");
1608  if (s_conditional != NULL) {
1609  if (strcasecmp(s_conditional, "alerts") == 0) {
1612  } else if (strcasecmp(s_conditional, "tag") == 0) {
1615  } else if (strcasecmp(s_conditional, "all") != 0) {
1617  "log-pcap: invalid conditional \"%s\". Valid options: \"all\", "
1618  "\"alerts\", or \"tag\" mode ",
1619  s_conditional);
1620  }
1621  }
1622 
1623  SCLogInfo(
1624  "Selected pcap-log conditional logging: %s", s_conditional ? s_conditional : "all");
1625  }
1626 
1627  if (ParseFilename(pl, filename) != 0)
1628  exit(EXIT_FAILURE);
1629 
1630  SCLogInfo("using %s logging", pl->mode == LOGMODE_SGUIL ?
1631  "Sguil compatible" : (pl->mode == LOGMODE_MULTI ? "multi" : "normal"));
1632 
1633  uint32_t max_file_limit = DEFAULT_FILE_LIMIT;
1634  if (conf != NULL) {
1635  const char *max_number_of_files_s = NULL;
1636  max_number_of_files_s = ConfNodeLookupChildValue(conf, "max-files");
1637  if (max_number_of_files_s != NULL) {
1638  if (StringParseUint32(&max_file_limit, 10, 0,
1639  max_number_of_files_s) == -1) {
1640  SCLogError(SC_ERR_INVALID_ARGUMENT, "Failed to initialize "
1641  "pcap-log output, invalid number of files limit: %s",
1642  max_number_of_files_s);
1643  exit(EXIT_FAILURE);
1644  } else if (max_file_limit < 1) {
1646  "Failed to initialize pcap-log output, limit less than "
1647  "allowed minimum.");
1648  } else {
1649  pl->max_files = max_file_limit;
1650  pl->use_ringbuffer = RING_BUFFER_MODE_ENABLED;
1651  }
1652  }
1653  }
1654 
1655  const char *ts_format = NULL;
1656  if (conf != NULL) { /* To faciliate unit tests. */
1657  ts_format = ConfNodeLookupChildValue(conf, "ts-format");
1658  }
1659  if (ts_format != NULL) {
1660  if (strcasecmp(ts_format, "usec") == 0) {
1661  pl->timestamp_format = TS_FORMAT_USEC;
1662  } else if (strcasecmp(ts_format, "sec") != 0) {
1664  "log-pcap ts_format specified %s is invalid must be"
1665  " \"sec\" or \"usec\"", ts_format);
1666  exit(EXIT_FAILURE);
1667  }
1668  }
1669 
1670  const char *use_stream_depth = NULL;
1671  if (conf != NULL) { /* To faciliate unit tests. */
1672  use_stream_depth = ConfNodeLookupChildValue(conf, "use-stream-depth");
1673  }
1674  if (use_stream_depth != NULL) {
1675  if (ConfValIsFalse(use_stream_depth)) {
1677  } else if (ConfValIsTrue(use_stream_depth)) {
1679  } else {
1681  "log-pcap use_stream_depth specified is invalid must be");
1682  }
1683  }
1684 
1685  const char *honor_pass_rules = NULL;
1686  if (conf != NULL) { /* To faciliate unit tests. */
1687  honor_pass_rules = ConfNodeLookupChildValue(conf, "honor-pass-rules");
1688  }
1689  if (honor_pass_rules != NULL) {
1690  if (ConfValIsFalse(honor_pass_rules)) {
1692  } else if (ConfValIsTrue(honor_pass_rules)) {
1694  } else {
1696  "log-pcap honor-pass-rules specified is invalid");
1697  }
1698  }
1699 
1700  /* create the output ctx and send it back */
1701 
1702  OutputCtx *output_ctx = SCCalloc(1, sizeof(OutputCtx));
1703  if (unlikely(output_ctx == NULL)) {
1704  FatalError(SC_ERR_FATAL, "Failed to allocate memory for OutputCtx.");
1705  }
1706  output_ctx->data = pl;
1707  output_ctx->DeInit = PcapLogFileDeInitCtx;
1708  g_pcap_data = pl;
1709 
1710  result.ctx = output_ctx;
1711  result.ok = true;
1712  return result;
1713 }
1714 
1715 static void PcapLogFileDeInitCtx(OutputCtx *output_ctx)
1716 {
1717  if (output_ctx == NULL)
1718  return;
1719 
1720  PcapLogData *pl = output_ctx->data;
1721 
1722  PcapFileName *pf = NULL;
1723  TAILQ_FOREACH(pf, &pl->pcap_file_list, next) {
1724  SCLogDebug("PCAP files left at exit: %s\n", pf->filename);
1725  }
1726  PcapLogDataFree(pl);
1727  SCFree(output_ctx);
1728 
1729  pcre2_code_free(pcre_timestamp_code);
1730  pcre2_match_data_free(pcre_timestamp_match);
1731 
1732  return;
1733 }
1734 
1735 /**
1736  * \brief Read the config set the file pointer, open the file
1737  *
1738  * \param PcapLogData.
1739  *
1740  * \retval -1 if failure
1741  * \retval 0 if succesful
1742  */
1743 static int PcapLogOpenFileCtx(PcapLogData *pl)
1744 {
1745  char *filename = NULL;
1746 
1748 
1749  if (pl->filename != NULL)
1750  filename = pl->filename;
1751  else {
1752  filename = SCMalloc(PATH_MAX);
1753  if (unlikely(filename == NULL)) {
1754  return -1;
1755  }
1756  pl->filename = filename;
1757  }
1758 
1759  /** get the time so we can have a filename with seconds since epoch */
1760  struct timeval ts;
1761  memset(&ts, 0x00, sizeof(struct timeval));
1762  TimeGet(&ts);
1763 
1764  /* Place to store the name of our PCAP file */
1765  PcapFileName *pf = SCMalloc(sizeof(PcapFileName));
1766  if (unlikely(pf == NULL)) {
1767  return -1;
1768  }
1769  memset(pf, 0, sizeof(PcapFileName));
1770 
1771  if (pl->mode == LOGMODE_SGUIL) {
1772  struct tm local_tm;
1773  struct tm *tms = SCLocalTime(ts.tv_sec, &local_tm);
1774 
1775  char dirname[32], dirfull[PATH_MAX] = "";
1776 
1777  snprintf(dirname, sizeof(dirname), "%04d-%02d-%02d",
1778  tms->tm_year + 1900, tms->tm_mon + 1, tms->tm_mday);
1779 
1780  /* create the filename to use */
1781  int ret = snprintf(dirfull, sizeof(dirfull), "%s/%s", pl->dir, dirname);
1782  if (ret < 0 || (size_t)ret >= sizeof(dirfull)) {
1783  SCLogError(SC_ERR_SPRINTF,"failed to construct path");
1784  goto error;
1785  }
1786 
1787  /* if mkdir fails file open will fail, so deal with errors there */
1788  (void)SCMkDir(dirfull, 0700);
1789 
1790  if ((pf->dirname = SCStrdup(dirfull)) == NULL) {
1791  SCLogError(SC_ERR_MEM_ALLOC, "Error allocating memory for "
1792  "directory name");
1793  goto error;
1794  }
1795 
1796  int written;
1797  if (pl->timestamp_format == TS_FORMAT_SEC) {
1798  written = snprintf(filename, PATH_MAX, "%s/%s.%" PRIu32 "%s",
1799  dirfull, pl->prefix, (uint32_t)ts.tv_sec, pl->suffix);
1800  } else {
1801  written = snprintf(filename, PATH_MAX, "%s/%s.%" PRIu32 ".%" PRIu32 "%s",
1802  dirfull, pl->prefix, (uint32_t)ts.tv_sec,
1803  (uint32_t)ts.tv_usec, pl->suffix);
1804  }
1805  if (written == PATH_MAX) {
1806  SCLogError(SC_ERR_SPRINTF,"log-pcap path overflow");
1807  goto error;
1808  }
1809  } else if (pl->mode == LOGMODE_NORMAL) {
1810  int ret;
1811  /* create the filename to use */
1812  if (pl->timestamp_format == TS_FORMAT_SEC) {
1813  ret = snprintf(filename, PATH_MAX, "%s/%s.%" PRIu32 "%s", pl->dir,
1814  pl->prefix, (uint32_t)ts.tv_sec, pl->suffix);
1815  } else {
1816  ret = snprintf(filename, PATH_MAX,
1817  "%s/%s.%" PRIu32 ".%" PRIu32 "%s", pl->dir, pl->prefix,
1818  (uint32_t)ts.tv_sec, (uint32_t)ts.tv_usec, pl->suffix);
1819  }
1820  if (ret < 0 || (size_t)ret >= PATH_MAX) {
1821  SCLogError(SC_ERR_SPRINTF,"failed to construct path");
1822  goto error;
1823  }
1824  } else if (pl->mode == LOGMODE_MULTI) {
1825  if (pl->filename_part_cnt > 0) {
1826  /* assemble filename from stored tokens */
1827 
1828  strlcpy(filename, pl->dir, PATH_MAX);
1829  strlcat(filename, "/", PATH_MAX);
1830 
1831  int i;
1832  for (i = 0; i < pl->filename_part_cnt; i++) {
1833  if (pl->filename_parts[i] == NULL ||strlen(pl->filename_parts[i]) == 0)
1834  continue;
1835 
1836  /* handle variables */
1837  if (pl->filename_parts[i][0] == '%') {
1838  char str[64] = "";
1839  if (strlen(pl->filename_parts[i]) < 2)
1840  continue;
1841 
1842  switch(pl->filename_parts[i][1]) {
1843  case 'n':
1844  snprintf(str, sizeof(str), "%u", pl->thread_number);
1845  break;
1846  case 'i':
1847  {
1848  long thread_id = SCGetThreadIdLong();
1849  snprintf(str, sizeof(str), "%"PRIu64, (uint64_t)thread_id);
1850  break;
1851  }
1852  case 't':
1853  /* create the filename to use */
1854  if (pl->timestamp_format == TS_FORMAT_SEC) {
1855  snprintf(str, sizeof(str), "%"PRIu32, (uint32_t)ts.tv_sec);
1856  } else {
1857  snprintf(str, sizeof(str), "%"PRIu32".%"PRIu32,
1858  (uint32_t)ts.tv_sec, (uint32_t)ts.tv_usec);
1859  }
1860  }
1861  strlcat(filename, str, PATH_MAX);
1862 
1863  /* copy the rest over */
1864  } else {
1865  strlcat(filename, pl->filename_parts[i], PATH_MAX);
1866  }
1867  }
1868  strlcat(filename, pl->suffix, PATH_MAX);
1869  } else {
1870  int ret;
1871  /* create the filename to use */
1872  if (pl->timestamp_format == TS_FORMAT_SEC) {
1873  ret = snprintf(filename, PATH_MAX, "%s/%s.%u.%" PRIu32 "%s",
1874  pl->dir, pl->prefix, pl->thread_number,
1875  (uint32_t)ts.tv_sec, pl->suffix);
1876  } else {
1877  ret = snprintf(filename, PATH_MAX,
1878  "%s/%s.%u.%" PRIu32 ".%" PRIu32 "%s", pl->dir,
1879  pl->prefix, pl->thread_number, (uint32_t)ts.tv_sec,
1880  (uint32_t)ts.tv_usec, pl->suffix);
1881  }
1882  if (ret < 0 || (size_t)ret >= PATH_MAX) {
1883  SCLogError(SC_ERR_SPRINTF,"failed to construct path");
1884  goto error;
1885  }
1886  }
1887  SCLogDebug("multi-mode: filename %s", filename);
1888  }
1889 
1890  if ((pf->filename = SCStrdup(pl->filename)) == NULL) {
1891  SCLogError(SC_ERR_MEM_ALLOC, "Error allocating memory. For filename");
1892  goto error;
1893  }
1894  SCLogDebug("Opening pcap file log %s", pf->filename);
1895  TAILQ_INSERT_TAIL(&pl->pcap_file_list, pf, next);
1896 
1897  if (pl->mode == LOGMODE_MULTI || pl->mode == LOGMODE_NORMAL) {
1898  pcap_file_thread = pl->filename;
1899  }
1901  return 0;
1902 
1903 error:
1904  PcapFileNameFree(pf);
1905  return -1;
1906 }
1907 
1909 {
1910  /* return pcap filename per thread */
1911  if (pcap_file_thread != NULL) {
1912  return pcap_file_thread;
1913  }
1914  return NULL;
1915 }
1916 
1917 static int profiling_pcaplog_enabled = 0;
1918 static int profiling_pcaplog_output_to_file = 0;
1919 static char *profiling_pcaplog_file_name = NULL;
1920 static const char *profiling_pcaplog_file_mode = "a";
1921 
1922 static void FormatNumber(uint64_t num, char *str, size_t size)
1923 {
1924  if (num < 1000UL)
1925  snprintf(str, size, "%"PRIu64, num);
1926  else if (num < 1000000UL)
1927  snprintf(str, size, "%3.1fk", (float)num/1000UL);
1928  else if (num < 1000000000UL)
1929  snprintf(str, size, "%3.1fm", (float)num/1000000UL);
1930  else
1931  snprintf(str, size, "%3.1fb", (float)num/1000000000UL);
1932 }
1933 
1934 static void ProfileReportPair(FILE *fp, const char *name, PcapLogProfileData *p)
1935 {
1936  char ticks_str[32] = "n/a";
1937  char cnt_str[32] = "n/a";
1938  char avg_str[32] = "n/a";
1939 
1940  FormatNumber((uint64_t)p->cnt, cnt_str, sizeof(cnt_str));
1941  FormatNumber((uint64_t)p->total, ticks_str, sizeof(ticks_str));
1942  if (p->cnt && p->total)
1943  FormatNumber((uint64_t)(p->total/p->cnt), avg_str, sizeof(avg_str));
1944 
1945  fprintf(fp, "%-28s %-10s %-10s %-10s\n", name, cnt_str, avg_str, ticks_str);
1946 }
1947 
1948 static void ProfileReport(FILE *fp, PcapLogData *pl)
1949 {
1950  ProfileReportPair(fp, "open", &pl->profile_open);
1951  ProfileReportPair(fp, "close", &pl->profile_close);
1952  ProfileReportPair(fp, "write", &pl->profile_write);
1953  ProfileReportPair(fp, "rotate (incl open/close)", &pl->profile_rotate);
1954  ProfileReportPair(fp, "handles", &pl->profile_handles);
1955  ProfileReportPair(fp, "lock", &pl->profile_lock);
1956  ProfileReportPair(fp, "unlock", &pl->profile_unlock);
1957 }
1958 
1959 static void FormatBytes(uint64_t num, char *str, size_t size)
1960 {
1961  if (num < 1000UL)
1962  snprintf(str, size, "%"PRIu64, num);
1963  else if (num < 1048576UL)
1964  snprintf(str, size, "%3.1fKiB", (float)num/1000UL);
1965  else if (num < 1073741824UL)
1966  snprintf(str, size, "%3.1fMiB", (float)num/1000000UL);
1967  else
1968  snprintf(str, size, "%3.1fGiB", (float)num/1000000000UL);
1969 }
1970 
1971 static void PcapLogProfilingDump(PcapLogData *pl)
1972 {
1973  FILE *fp = NULL;
1974 
1975  if (profiling_pcaplog_enabled == 0)
1976  return;
1977 
1978  if (profiling_pcaplog_output_to_file == 1) {
1979  fp = fopen(profiling_pcaplog_file_name, profiling_pcaplog_file_mode);
1980  if (fp == NULL) {
1981  SCLogError(SC_ERR_FOPEN, "failed to open %s: %s",
1982  profiling_pcaplog_file_name, strerror(errno));
1983  return;
1984  }
1985  } else {
1986  fp = stdout;
1987  }
1988 
1989  /* counters */
1990  fprintf(fp, "\n\nOperation Cnt Avg ticks Total ticks\n");
1991  fprintf(fp, "---------------------------- ---------- ---------- -----------\n");
1992 
1993  ProfileReport(fp, pl);
1994  uint64_t total = pl->profile_write.total + pl->profile_rotate.total +
1997  pl->profile_unlock.total;
1998 
1999  /* overall stats */
2000  fprintf(fp, "\nOverall: %"PRIu64" bytes written, average %d bytes per write.\n",
2002  (int)(pl->profile_data_size / pl->profile_write.cnt) : 0);
2003  fprintf(fp, " PCAP data structure overhead: %"PRIuMAX" per write.\n",
2004  (uintmax_t)sizeof(struct pcap_pkthdr));
2005 
2006  /* print total bytes written */
2007  char bytes_str[32];
2008  FormatBytes(pl->profile_data_size, bytes_str, sizeof(bytes_str));
2009  fprintf(fp, " Size written: %s\n", bytes_str);
2010 
2011  /* ticks per MiB and GiB */
2012  uint64_t ticks_per_mib = 0, ticks_per_gib = 0;
2013  uint64_t mib = pl->profile_data_size/(1024*1024);
2014  if (mib)
2015  ticks_per_mib = total/mib;
2016  char ticks_per_mib_str[32] = "n/a";
2017  if (ticks_per_mib > 0)
2018  FormatNumber(ticks_per_mib, ticks_per_mib_str, sizeof(ticks_per_mib_str));
2019  fprintf(fp, " Ticks per MiB: %s\n", ticks_per_mib_str);
2020 
2021  uint64_t gib = pl->profile_data_size/(1024*1024*1024);
2022  if (gib)
2023  ticks_per_gib = total/gib;
2024  char ticks_per_gib_str[32] = "n/a";
2025  if (ticks_per_gib > 0)
2026  FormatNumber(ticks_per_gib, ticks_per_gib_str, sizeof(ticks_per_gib_str));
2027  fprintf(fp, " Ticks per GiB: %s\n", ticks_per_gib_str);
2028 
2029  if (fp != stdout)
2030  fclose(fp);
2031 }
2032 
2034 {
2035  ConfNode *conf = ConfGetNode("profiling.pcap-log");
2036  if (conf != NULL && ConfNodeChildValueIsTrue(conf, "enabled")) {
2037  profiling_pcaplog_enabled = 1;
2038  SCLogInfo("pcap-log profiling enabled");
2039 
2040  const char *filename = ConfNodeLookupChildValue(conf, "filename");
2041  if (filename != NULL) {
2042  const char *log_dir;
2043  log_dir = ConfigGetLogDirectory();
2044 
2045  profiling_pcaplog_file_name = SCMalloc(PATH_MAX);
2046  if (unlikely(profiling_pcaplog_file_name == NULL)) {
2047  FatalError(SC_ERR_FATAL, "can't duplicate file name");
2048  }
2049 
2050  snprintf(profiling_pcaplog_file_name, PATH_MAX, "%s/%s", log_dir, filename);
2051 
2052  const char *v = ConfNodeLookupChildValue(conf, "append");
2053  if (v == NULL || ConfValIsTrue(v)) {
2054  profiling_pcaplog_file_mode = "a";
2055  } else {
2056  profiling_pcaplog_file_mode = "w";
2057  }
2058 
2059  profiling_pcaplog_output_to_file = 1;
2060  SCLogInfo("pcap-log profiling output goes to %s (mode %s)",
2061  profiling_pcaplog_file_name, profiling_pcaplog_file_mode);
2062  }
2063  }
2064 }
SC_ERR_FWRITE
@ SC_ERR_FWRITE
Definition: util-error.h:129
util-byte.h
PcapLogCompressionData_::pcap_buf_size
uint64_t pcap_buf_size
Definition: log-pcap.c:143
ConfGetChildValueInt
int ConfGetChildValueInt(const ConfNode *base, const char *name, intmax_t *val)
Definition: conf.c:424
tm-threads.h
PcapLogData
struct PcapLogData_ PcapLogData
PcapLogProfileData_
Definition: log-pcap.c:120
LOGMODE_COND_ALL
@ LOGMODE_COND_ALL
Definition: log-pcap.c:82
len
uint8_t len
Definition: app-layer-dnp3.h:2
ts
uint64_t ts
Definition: source-erf-file.c:55
SC_ERR_PCRE_COMPILE
@ SC_ERR_PCRE_COMPILE
Definition: util-error.h:35
PcapLogData_::conditional
LogModeConditionalType conditional
Definition: log-pcap.c:171
source-pcap.h
PcapLogThreadData
struct PcapLogThreadData_ PcapLogThreadData
ConfNodeChildValueIsTrue
int ConfNodeChildValueIsTrue(const ConfNode *node, const char *key)
Test if a configuration node has a true value.
Definition: conf.c:843
IsTcpSessionDumpingEnabled
bool IsTcpSessionDumpingEnabled(void)
Definition: stream-tcp-reassemble.c:89
util-fmemopen.h
TAILQ_INIT
#define TAILQ_INIT(head)
Definition: queue.h:262
SC_ATOMIC_INIT
#define SC_ATOMIC_INIT(name)
wrapper for initializing an atomic variable.
Definition: util-atomic.h:315
USE_STREAM_DEPTH_DISABLED
#define USE_STREAM_DEPTH_DISABLED
Definition: log-pcap.c:93
PcapFileName_::secs
uint64_t secs
Definition: log-pcap.c:111
unlikely
#define unlikely(expr)
Definition: util-optimize.h:35
SC_ATOMIC_SET
#define SC_ATOMIC_SET(name, val)
Set the value for the atomic variable.
Definition: util-atomic.h:387
PcapLogData_::pcap_dumper
pcap_dumper_t * pcap_dumper
Definition: log-pcap.c:166
TS_FORMAT_SEC
#define TS_FORMAT_SEC
Definition: log-pcap.c:90
SCLogDebug
#define SCLogDebug(...)
Definition: util-debug.h:296
ParseSizeStringU64
int ParseSizeStringU64(const char *size, uint64_t *res)
Definition: util-misc.c:200
PcapFileName_::usecs
uint32_t usecs
Definition: log-pcap.c:112
next
struct HtpBodyChunk_ * next
Definition: app-layer-htp.h:0
PcapLogData_::filename
char * filename
Definition: log-pcap.c:160
PacketAlerts_::cnt
uint16_t cnt
Definition: decode.h:297
HONOR_PASS_RULES_ENABLED
#define HONOR_PASS_RULES_ENABLED
Definition: log-pcap.c:97
Packet_::flags
uint32_t flags
Definition: decode.h:468
ConfGetNode
ConfNode * ConfGetNode(const char *name)
Get a ConfNode by name.
Definition: conf.c:175
DEFAULT_LOG_FILENAME
#define DEFAULT_LOG_FILENAME
Definition: log-pcap.c:71
threads.h
SC_ATOMIC_ADD
#define SC_ATOMIC_ADD(name, val)
add a value to our atomic variable
Definition: util-atomic.h:333
RING_BUFFER_MODE_ENABLED
#define RING_BUFFER_MODE_ENABLED
Definition: log-pcap.c:88
PcapLogData_::mode
int mode
Definition: log-pcap.c:161
SC_ERR_PCAP_FILE_DELETE_FAILED
@ SC_ERR_PCAP_FILE_DELETE_FAILED
Definition: util-error.h:226
IS_TUNNEL_ROOT_PKT
#define IS_TUNNEL_ROOT_PKT(p)
Definition: decode.h:973
TAILQ_EMPTY
#define TAILQ_EMPTY(head)
Definition: queue.h:248
PcapLogData_::pkt_cnt
uint64_t pkt_cnt
Definition: log-pcap.c:158
HONOR_PASS_RULES_DISABLED
#define HONOR_PASS_RULES_DISABLED
Definition: log-pcap.c:96
TAILQ_FOREACH
#define TAILQ_FOREACH(var, head, field)
Definition: queue.h:252
SCMutexLock
#define SCMutexLock(mut)
Definition: threads-debug.h:117
PcapLogData_::use_stream_depth
int use_stream_depth
Definition: log-pcap.c:154
PcapLogCompressionData_::format
enum PcapLogCompressionFormat format
Definition: log-pcap.c:134
PcapLogProfileData
struct PcapLogProfileData_ PcapLogProfileData
PcapLogData_::profile_handles
PcapLogProfileData profile_handles
Definition: log-pcap.c:176
LOGMODE_MULTI
#define LOGMODE_MULTI
Definition: log-pcap.c:79
TAILQ_INSERT_TAIL
#define TAILQ_INSERT_TAIL(head, elm, field)
Definition: queue.h:294
PcapLogRegister
void PcapLogRegister(void)
Definition: log-pcap.c:221
SCFmemopen
#define SCFmemopen
Definition: util-fmemopen.h:52
SC_WARN_COMPATIBILITY
@ SC_WARN_COMPATIBILITY
Definition: util-error.h:193
PcapLogCompressionData_::buffer
uint8_t * buffer
Definition: log-pcap.c:135
DEFAULT_LIMIT
#define DEFAULT_LIMIT
Definition: log-pcap.c:74
PcapLogCallbackContext::connp
PcapLogCompressionData * connp
Definition: log-pcap.c:552
TM_ECODE_FAILED
@ TM_ECODE_FAILED
Definition: tm-threads-common.h:83
PcapLogData_::pcap_dead_handle
pcap_t * pcap_dead_handle
Definition: log-pcap.c:165
Packet_::alerts
PacketAlerts alerts
Definition: decode.h:588
util-unittest.h
TcpSegmentPcapHdrStorage_::pktlen
uint32_t pktlen
Definition: stream-tcp-private.h:67
PcapLogData_::size_current
uint64_t size_current
Definition: log-pcap.c:163
ConfValIsTrue
int ConfValIsTrue(const char *val)
Check if a value is true.
Definition: conf.c:521
PcapLogData_::profile_rotate
PcapLogProfileData profile_rotate
Definition: log-pcap.c:179
OutputCtx_::data
void * data
Definition: tm-modules.h:81
PcapLogCompressionData_
Definition: log-pcap.c:133
TM_ECODE_OK
@ TM_ECODE_OK
Definition: tm-threads-common.h:82
PCAPLOG_PROFILE_END
#define PCAPLOG_PROFILE_END(prof)
Definition: log-pcap.c:235
PcapLogGetFilename
char * PcapLogGetFilename(void)
Definition: log-pcap.c:1908
OutputCtx_
Definition: tm-modules.h:78
LogModeConditionalType_
LogModeConditionalType_
Definition: log-pcap.c:81
strlcpy
size_t strlcpy(char *dst, const char *src, size_t siz)
Definition: util-strlcpyu.c:43
PcapLogCompressionData_::bytes_in_block
uint64_t bytes_in_block
Definition: log-pcap.c:145
TAILQ_ENTRY
#define TAILQ_ENTRY(type)
Definition: queue.h:239
Packet_::datalink
int datalink
Definition: decode.h:607
PcapLogData_::size_limit
uint64_t size_limit
Definition: log-pcap.c:164
PKT_IS_TCP
#define PKT_IS_TCP(p)
Definition: decode.h:255
PcapLogProfileData_::cnt
uint64_t cnt
Definition: log-pcap.c:122
PcapLogData_::max_files
uint32_t max_files
Definition: log-pcap.c:169
PcapLogCompressionData_::file
FILE * file
Definition: log-pcap.c:141
TAILQ_REMOVE
#define TAILQ_REMOVE(head, elm, field)
Definition: queue.h:312
util-debug.h
TAILQ_FIRST
#define TAILQ_FIRST(head)
Definition: queue.h:250
util-error.h
OutputInitResult_::ctx
OutputCtx * ctx
Definition: output.h:45
PCAP_LOG_COMPRESSION_FORMAT_NONE
@ PCAP_LOG_COMPRESSION_FORMAT_NONE
Definition: log-pcap.c:129
strlcat
size_t strlcat(char *, const char *src, size_t siz)
Definition: util-strlcatu.c:45
util-cpu.h
SCMutexUnlock
#define SCMutexUnlock(mut)
Definition: threads-debug.h:119
MemBufferWriteRaw
#define MemBufferWriteRaw(dst, raw_buffer, raw_buffer_len)
Write a raw buffer to the MemBuffer dst.
Definition: util-buffer.h:133
PKT_PSEUDO_STREAM_END
#define PKT_PSEUDO_STREAM_END
Definition: decode.h:1178
PCAP_LOG_COMPRESSION_FORMAT_LZ4
@ PCAP_LOG_COMPRESSION_FORMAT_LZ4
Definition: log-pcap.c:130
EnableTcpSessionDumping
void EnableTcpSessionDumping(void)
Definition: stream-tcp-reassemble.c:94
STREAM_DUMP_HEADERS
#define STREAM_DUMP_HEADERS
Definition: stream.h:33
GET_PKT_DATA
#define GET_PKT_DATA(p)
Definition: decode.h:227
detect.h
ThreadVars_
Per thread variable structure.
Definition: threadvars.h:56
PcapLogProfileData_::total
uint64_t total
Definition: log-pcap.c:121
util-atomic.h
StringParseUint32
int StringParseUint32(uint32_t *res, int base, size_t len, const char *str)
Definition: util-byte.c:313
util-time.h
OutputInitResult_::ok
bool ok
Definition: output.h:46
SC_ERR_INVALID_ARGUMENT
@ SC_ERR_INVALID_ARGUMENT
Definition: util-error.h:43
TRUE
#define TRUE
Definition: suricata-common.h:33
PcapFileName_::dirname
char * dirname
Definition: log-pcap.c:106
PcapLogData_::file_cnt
uint32_t file_cnt
Definition: log-pcap.c:168
BUG_ON
#define BUG_ON(x)
Definition: suricata-common.h:281
FALSE
#define FALSE
Definition: suricata-common.h:34
PCAP_OUTPUT_BUFFER_SIZE
#define PCAP_OUTPUT_BUFFER_SIZE
Definition: log-pcap.h:31
stream.h
SC_ERR_FOPEN
@ SC_ERR_FOPEN
Definition: util-error.h:74
PcapLogCallbackContext::buf
MemBuffer * buf
Definition: log-pcap.c:553
TcpSegment
Definition: stream-tcp-private.h:72
Packet_
Definition: decode.h:433
SC_ERR_SPRINTF
@ SC_ERR_SPRINTF
Definition: util-error.h:42
SCLocalTime
struct tm * SCLocalTime(time_t timep, struct tm *result)
Definition: util-time.c:273
GET_PKT_LEN
#define GET_PKT_LEN(p)
Definition: decode.h:226
conf.h
DEFAULT_FILE_LIMIT
#define DEFAULT_FILE_LIMIT
Definition: log-pcap.c:75
TmEcode
TmEcode
Definition: tm-threads-common.h:81
RING_BUFFER_MODE_DISABLED
#define RING_BUFFER_MODE_DISABLED
Definition: log-pcap.c:87
PcapLogThreadData_::buf
MemBuffer * buf
Definition: log-pcap.c:200
PCAP_SNAPLEN
#define PCAP_SNAPLEN
Definition: log-pcap.c:99
PcapLogData_::plog_lock
SCMutex plog_lock
Definition: log-pcap.c:157
PcapLogData_::h
struct pcap_pkthdr * h
Definition: log-pcap.c:159
IS_TUNNEL_PKT
#define IS_TUNNEL_PKT(p)
Definition: decode.h:970
queue.h
PcapLogCompressionData_::pcap_buf
uint8_t * pcap_buf
Definition: log-pcap.c:142
MemBuffer_
Definition: util-buffer.h:27
LOGMODE_COND_TAG
@ LOGMODE_COND_TAG
Definition: log-pcap.c:84
SC_WARN_REMOVE_FILE
@ SC_WARN_REMOVE_FILE
Definition: util-error.h:325
StreamSegmentForSession
int StreamSegmentForSession(const Packet *p, uint8_t flag, StreamSegmentCallback CallbackFunc, void *data)
Run callback for all segments on both directions of the session.
Definition: stream.c:64
SCLogInfo
#define SCLogInfo(...)
Macro used to log INFORMATIONAL messages.
Definition: util-debug.h:215
PcapLogCallbackContext::pl
PcapLogData * pl
Definition: log-pcap.c:551
SC_ERR_INVALID_YAML_CONF_ENTRY
@ SC_ERR_INVALID_YAML_CONF_ENTRY
Definition: util-error.h:169
PcapLogData_::prev_day
int prev_day
Definition: log-pcap.c:162
PKT_FIRST_TAG
#define PKT_FIRST_TAG
Definition: decode.h:1226
SCMutexInit
#define SCMutexInit(mut, mutattrs)
Definition: threads-debug.h:116
PCAPLOG_PROFILE_START
#define PCAPLOG_PROFILE_START
Definition: log-pcap.c:232
log-pcap.h
SCGetThreadIdLong
#define SCGetThreadIdLong(...)
Definition: threads.h:260
PcapLogData_::honor_pass_rules
int honor_pass_rules
Definition: log-pcap.c:155
decode-ipv4.h
MemBufferReset
#define MemBufferReset(mem_buffer)
Reset the mem buffer.
Definition: util-buffer.h:42
pcap_file_thread
thread_local char * pcap_file_thread
Definition: log-pcap.c:118
PcapLogData_::profile_open
PcapLogProfileData profile_open
Definition: log-pcap.c:178
PcapLogData_::profile_lock
PcapLogProfileData profile_lock
Definition: log-pcap.c:173
OutputInitResult_
Definition: output.h:44
Packet_::flow
struct Flow_ * flow
Definition: decode.h:470
StringParseUint64
int StringParseUint64(uint64_t *res, int base, size_t len, const char *str)
Definition: util-byte.c:308
TimeDifferenceMicros
uint64_t TimeDifferenceMicros(struct timeval t0, struct timeval t1)
Definition: util-time.c:653
LOGGER_PCAP
@ LOGGER_PCAP
Definition: suricata-common.h:489
Packet_::ts
struct timeval ts
Definition: decode.h:476
suricata-common.h
OutputCtx_::DeInit
void(* DeInit)(struct OutputCtx_ *)
Definition: tm-modules.h:84
TcpSegmentPcapHdrStorage_::ts
struct timeval ts
Definition: stream-tcp-private.h:66
LOGMODE_NORMAL
#define LOGMODE_NORMAL
Definition: log-pcap.c:77
MemBufferFree
void MemBufferFree(MemBuffer *buffer)
Definition: util-buffer.c:82
PKT_STREAM_NOPCAPLOG
#define PKT_STREAM_NOPCAPLOG
Definition: decode.h:1186
PcapLogData_::profile_data_size
uint64_t profile_data_size
Definition: log-pcap.c:167
TAILQ_NEXT
#define TAILQ_NEXT(elm, field)
Definition: queue.h:307
PathIsAbsolute
int PathIsAbsolute(const char *path)
Check if a path is absolute.
Definition: util-path.c:45
SCLogError
#define SCLogError(err_code,...)
Macro used to log ERROR messages.
Definition: util-debug.h:255
PcapLogProfileSetup
void PcapLogProfileSetup(void)
Definition: log-pcap.c:2033
SCMkDir
#define SCMkDir(a, b)
Definition: util-path.h:29
SCStrdup
#define SCStrdup(s)
Definition: util-mem.h:56
FatalError
#define FatalError(x,...)
Definition: util-debug.h:530
PcapLogCallbackContext
Definition: log-pcap.c:550
PcapLogCompressionData_::buffer_size
uint64_t buffer_size
Definition: log-pcap.c:136
SC_ERR_FSEEK
@ SC_ERR_FSEEK
Definition: util-error.h:344
tv
ThreadVars * tv
Definition: fuzz_decodepcapfile.c:31
OutputRegisterPacketModule
void OutputRegisterPacketModule(LoggerId id, const char *name, const char *conf_name, OutputInitFunc InitFunc, PacketLogger PacketLogFunc, PacketLogCondition PacketConditionFunc, ThreadInitFunc ThreadInit, ThreadDeinitFunc ThreadDeinit, ThreadExitPrintStatsFunc ThreadExitPrintStats)
Register a packet output module.
Definition: output.c:177
PcapLogThreadData_
Definition: log-pcap.c:198
threadvars.h
SCMalloc
#define SCMalloc(sz)
Definition: util-mem.h:47
SC_ERR_PCAP_LOG_COMPRESS
@ SC_ERR_PCAP_LOG_COMPRESS
Definition: util-error.h:343
LOGMODE_COND_ALERTS
@ LOGMODE_COND_ALERTS
Definition: log-pcap.c:83
PcapFileName_::filename
char * filename
Definition: log-pcap.c:105
Packet_::root
struct Packet_ * root
Definition: decode.h:618
TcpSegmentPcapHdrStorage_::pkt_hdr
uint8_t * pkt_hdr
Definition: stream-tcp-private.h:69
str
#define str(s)
Definition: suricata-common.h:272
MAX_TOKS
#define MAX_TOKS
Definition: log-pcap.c:125
PcapLogCompressionData
struct PcapLogCompressionData_ PcapLogCompressionData
ConfigGetLogDirectory
const char * ConfigGetLogDirectory()
Definition: util-conf.c:36
SCLogWarning
#define SCLogWarning(err_code,...)
Macro used to log WARNING messages.
Definition: util-debug.h:242
MODULE_NAME
#define MODULE_NAME
Definition: log-pcap.c:72
TcpSegment::pcap_hdr_storage
TcpSegmentPcapHdrStorage * pcap_hdr_storage
Definition: stream-tcp-private.h:78
SCFree
#define SCFree(p)
Definition: util-mem.h:61
ConfNode_
Definition: conf.h:32
SC_ATOMIC_DECLARE
SC_ATOMIC_DECLARE(uint32_t, thread_cnt)
SC_ERR_FATAL
@ SC_ERR_FATAL
Definition: util-error.h:203
PcapLogCompressionData_::pcap_buf_wrapper
FILE * pcap_buf_wrapper
Definition: log-pcap.c:144
src
uint16_t src
Definition: app-layer-dnp3.h:5
util-buffer.h
PcapFileName_
Definition: log-pcap.c:104
ConfValIsFalse
int ConfValIsFalse(const char *val)
Check if a value is false.
Definition: conf.c:546
TAILQ_HEAD
#define TAILQ_HEAD(name, type)
Definition: queue.h:230
stream-tcp-util.h
PcapLogData_::profile_unlock
PcapLogProfileData profile_unlock
Definition: log-pcap.c:175
TimeGet
void TimeGet(struct timeval *tv)
Definition: util-time.c:155
USE_STREAM_DEPTH_ENABLED
#define USE_STREAM_DEPTH_ENABLED
Definition: log-pcap.c:94
SC_ERR_MEM_ALLOC
@ SC_ERR_MEM_ALLOC
Definition: util-error.h:31
PcapLogData_::profile_close
PcapLogProfileData profile_close
Definition: log-pcap.c:177
PKT_NOPACKET_INSPECTION
#define PKT_NOPACKET_INSPECTION
Definition: decode.h:1161
FlowHasAlerts
int FlowHasAlerts(const Flow *f)
Check if flow has alerts.
Definition: flow.c:181
PcapFileName
struct PcapFileName_ PcapFileName
PCAP_BUFFER_TIMEOUT
#define PCAP_BUFFER_TIMEOUT
Definition: log-pcap.c:100
MIN_LIMIT
#define MIN_LIMIT
Definition: log-pcap.c:73
dst
uint16_t dst
Definition: app-layer-dnp3.h:4
MemBuffer_::buffer
uint8_t * buffer
Definition: util-buffer.h:28
util-misc.h
PKT_HAS_TAG
#define PKT_HAS_TAG
Definition: decode.h:1169
PcapLogData_
Definition: log-pcap.c:153
flow.h
PcapLogThreadData_::pcap_log
PcapLogData * pcap_log
Definition: log-pcap.c:199
PKT_FIRST_ALERTS
#define PKT_FIRST_ALERTS
Definition: decode.h:1225
SCLogNotice
#define SCLogNotice(...)
Macro used to log NOTICE messages.
Definition: util-debug.h:230
TAILQ_INSERT_BEFORE
#define TAILQ_INSERT_BEFORE(listelm, elm, field)
Definition: queue.h:277
PcapLogData_::profile_write
PcapLogProfileData profile_write
Definition: log-pcap.c:174
SCCalloc
#define SCCalloc(nm, sz)
Definition: util-mem.h:53
TS_FORMAT_USEC
#define TS_FORMAT_USEC
Definition: log-pcap.c:91
SC_ERR_PCAP_MULTI_DEV_NO_SUPPORT
@ SC_ERR_PCAP_MULTI_DEV_NO_SUPPORT
Definition: util-error.h:210
SC_ERR_DIR_OPEN
@ SC_ERR_DIR_OPEN
Definition: util-error.h:324
SC_ERR_LOGDIR_CONFIG
@ SC_ERR_LOGDIR_CONFIG
Definition: util-error.h:146
SCMutex
#define SCMutex
Definition: threads-debug.h:114
PcapLogData_::is_private
int is_private
Definition: log-pcap.c:156
LOGMODE_SGUIL
#define LOGMODE_SGUIL
Definition: log-pcap.c:78
MAX_FILENAMELEN
#define MAX_FILENAMELEN
Definition: log-pcap.c:126
SC_ERR_OPENING_FILE
@ SC_ERR_OPENING_FILE
Definition: util-error.h:70
MemBufferCreateNew
MemBuffer * MemBufferCreateNew(uint32_t size)
Definition: util-buffer.c:32
debug.h
output.h
LogModeConditionalType
enum LogModeConditionalType_ LogModeConditionalType
PcapLogCompressionFormat
PcapLogCompressionFormat
Definition: log-pcap.c:128
ConfNodeLookupChildValue
const char * ConfNodeLookupChildValue(const ConfNode *node, const char *name)
Lookup the value of a child configuration node by name.
Definition: conf.c:798