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