diff --git a/configure.ac b/configure.ac index 87cd6c0476..ba833fb438 100644 --- a/configure.ac +++ b/configure.ac @@ -2061,6 +2061,9 @@ fi fi +# Check for lz4 +AC_CHECK_LIB(lz4, LZ4F_createCompressionContext, , ) + # get cache line size AC_PATH_PROG(HAVE_GETCONF_CMD, getconf, "no") if test "$HAVE_GETCONF_CMD" != "no"; then diff --git a/src/log-pcap.c b/src/log-pcap.c index dacae667c3..9b882c1c84 100644 --- a/src/log-pcap.c +++ b/src/log-pcap.c @@ -26,6 +26,11 @@ */ #include "suricata-common.h" +#include "util-fmemopen.h" + +#ifdef HAVE_LIBLZ4 +#include +#endif /* HAVE_LIBLZ4 */ #if defined(HAVE_DIRENT_H) && defined(HAVE_FNMATCH_H) #define INIT_RING_BUFFER @@ -62,7 +67,7 @@ #define DEFAULT_LOG_FILENAME "pcaplog" #define MODULE_NAME "PcapLog" -#define MIN_LIMIT 1 * 1024 * 1024 +#define MIN_LIMIT 4 * 1024 * 1024 #define DEFAULT_LIMIT 100 * 1024 * 1024 #define DEFAULT_FILE_LIMIT 0 @@ -108,6 +113,26 @@ typedef struct PcapLogProfileData_ { #define MAX_TOKS 9 #define MAX_FILENAMELEN 513 +enum PcapLogCompressionFormat { + PCAP_LOG_COMPRESSION_FORMAT_NONE, + PCAP_LOG_COMPRESSION_FORMAT_LZ4, +}; + +typedef struct PcapLogCompressionData_ { + enum PcapLogCompressionFormat format; + uint8_t *buffer; + uint64_t buffer_size; +#ifdef HAVE_LIBLZ4 + LZ4F_compressionContext_t lz4f_context; + LZ4F_preferences_t lz4f_prefs; +#endif /* HAVE_LIBLZ4 */ + FILE *file; + uint8_t *pcap_buf; + uint64_t pcap_buf_size; + FILE *pcap_buf_wrapper; + uint64_t bytes_in_block; +} PcapLogCompressionData; + /** * PcapLog thread vars * @@ -145,11 +170,14 @@ typedef struct PcapLogData_ { int use_ringbuffer; /**< ring buffer mode enabled or disabled */ int timestamp_format; /**< timestamp format sec or usec */ char *prefix; /**< filename prefix */ + const char *suffix; /**< filename suffix */ char dir[PATH_MAX]; /**< pcap log directory */ int reported; int threads; /**< number of threads (only set in the global) */ char *filename_parts[MAX_TOKS]; int filename_part_cnt; + + PcapLogCompressionData compression; } PcapLogData; typedef struct PcapLogThreadData_ { @@ -213,8 +241,24 @@ static int PcapLogCloseFile(ThreadVars *t, PcapLogData *pl) if (pl != NULL) { PCAPLOG_PROFILE_START; - if (pl->pcap_dumper != NULL) + if (pl->pcap_dumper != NULL) { pcap_dump_close(pl->pcap_dumper); +#ifdef HAVE_LIBLZ4 + PcapLogCompressionData *comp = &pl->compression; + if (comp->format == PCAP_LOG_COMPRESSION_FORMAT_LZ4) { + /* pcap_dump_close() has closed its output ``file'', + * so we need to call fmemopen again. */ + + comp->pcap_buf_wrapper = SCFmemopen(comp->pcap_buf, + comp->pcap_buf_size, "w"); + if (comp->pcap_buf_wrapper == NULL) { + SCLogError(SC_ERR_FOPEN, "SCFmemopen failed: %s", + strerror(errno)); + return TM_ECODE_FAILED; + } + } +#endif /* HAVE_LIBLZ4 */ + } pl->size_current = 0; pl->pcap_dumper = NULL; @@ -222,6 +266,28 @@ static int PcapLogCloseFile(ThreadVars *t, PcapLogData *pl) pcap_close(pl->pcap_dead_handle); pl->pcap_dead_handle = NULL; +#ifdef HAVE_LIBLZ4 + PcapLogCompressionData *comp = &pl->compression; + if (comp->format == PCAP_LOG_COMPRESSION_FORMAT_LZ4) { + /* pcap_dump_close did not write any data because we call + * pcap_dump_flush() after every write when writing + * compressed output. */ + uint64_t bytes_written = LZ4F_compressEnd(comp->lz4f_context, + comp->buffer, comp->buffer_size, NULL); + if (LZ4F_isError(bytes_written)) { + SCLogError(SC_ERR_PCAP_LOG_COMPRESS, "LZ4F_compressEnd: %s", + LZ4F_getErrorName(bytes_written)); + return TM_ECODE_FAILED; + } + if (fwrite(comp->buffer, 1, bytes_written, comp->file) < bytes_written) { + SCLogError(SC_ERR_FWRITE, "fwrite failed: %s", strerror(errno)); + return TM_ECODE_FAILED; + } + fclose(comp->file); + comp->bytes_in_block = 0; + } +#endif /* HAVE_LIBLZ4 */ + PCAPLOG_PROFILE_END(pl->profile_close); } @@ -320,18 +386,50 @@ static int PcapLogOpenHandles(PcapLogData *pl, const Packet *p) if (pl->pcap_dead_handle == NULL) { if ((pl->pcap_dead_handle = pcap_open_dead(p->datalink, - PCAP_SNAPLEN)) == NULL) { + PCAP_SNAPLEN)) == NULL) { SCLogDebug("Error opening dead pcap handle"); return TM_ECODE_FAILED; } } if (pl->pcap_dumper == NULL) { - if ((pl->pcap_dumper = pcap_dump_open(pl->pcap_dead_handle, - pl->filename)) == NULL) { - SCLogInfo("Error opening dump file %s", pcap_geterr(pl->pcap_dead_handle)); - return TM_ECODE_FAILED; + if (pl->compression.format == PCAP_LOG_COMPRESSION_FORMAT_NONE) { + if ((pl->pcap_dumper = pcap_dump_open(pl->pcap_dead_handle, + pl->filename)) == NULL) { + SCLogInfo("Error opening dump file %s", pcap_geterr(pl->pcap_dead_handle)); + return TM_ECODE_FAILED; + } } +#ifdef HAVE_LIBLZ4 + else if (pl->compression.format == PCAP_LOG_COMPRESSION_FORMAT_LZ4) { + PcapLogCompressionData *comp = &pl->compression; + if ((pl->pcap_dumper = pcap_dump_fopen(pl->pcap_dead_handle, + comp->pcap_buf_wrapper)) == NULL) { + SCLogError(SC_ERR_OPENING_FILE, "Error opening dump file %s", + pcap_geterr(pl->pcap_dead_handle)); + return TM_ECODE_FAILED; + } + comp->file = fopen(pl->filename, "w"); + if (comp->file == NULL) { + SCLogError(SC_ERR_OPENING_FILE, + "Error opening file for compressed output: %s", + strerror(errno)); + return TM_ECODE_FAILED; + } + + uint64_t bytes_written = LZ4F_compressBegin(comp->lz4f_context, + comp->buffer, comp->buffer_size, NULL); + if (LZ4F_isError(bytes_written)) { + SCLogError(SC_ERR_PCAP_LOG_COMPRESS, "LZ4F_compressBegin: %s", + LZ4F_getErrorName(bytes_written)); + return TM_ECODE_FAILED; + } + if (fwrite(comp->buffer, 1, bytes_written, comp->file) < bytes_written) { + SCLogError(SC_ERR_FWRITE, "fwrite failed: %s", strerror(errno)); + return TM_ECODE_FAILED; + } + } +#endif /* HAVE_LIBLZ4 */ } PCAPLOG_PROFILE_END(pl->profile_handles); @@ -421,13 +519,34 @@ static int PcapLog (ThreadVars *t, void *thread_data, const Packet *p) } } - if ((pl->size_current + len) > pl->size_limit || rotate) { - if (PcapLogRotateFile(t,pl) < 0) { - PcapLogUnlock(pl); - SCLogDebug("rotation of pcap failed"); - return TM_ECODE_FAILED; + PcapLogCompressionData *comp = &pl->compression; + if (comp->format == PCAP_LOG_COMPRESSION_FORMAT_NONE) { + if ((pl->size_current + len) > pl->size_limit || rotate) { + if (PcapLogRotateFile(t,pl) < 0) { + PcapLogUnlock(pl); + SCLogDebug("rotation of pcap failed"); + return TM_ECODE_FAILED; + } } } +#ifdef HAVE_LIBLZ4 + else if (comp->format == PCAP_LOG_COMPRESSION_FORMAT_LZ4) { + /* When writing compressed pcap logs, we have no way of knowing + * for sure whether adding this packet would cause the current + * file to exceed the size limit. Thus, we record the number of + * bytes that have been fed into lz4 since the last write, and + * act as if they would be written uncompressed. */ + + if ((pl->size_current + comp->bytes_in_block + len) > pl->size_limit || + rotate) { + if (PcapLogRotateFile(t,pl) < 0) { + PcapLogUnlock(pl); + SCLogDebug("rotation of pcap failed"); + return TM_ECODE_FAILED; + } + } + } +#endif /* HAVE_LIBLZ4 */ /* XXX pcap handles, nfq, pfring, can only have one link type ipfw? we do * this here as we don't know the link type until we get our first packet */ @@ -440,7 +559,37 @@ static int PcapLog (ThreadVars *t, void *thread_data, const Packet *p) PCAPLOG_PROFILE_START; pcap_dump((u_char *)pl->pcap_dumper, pl->h, GET_PKT_DATA(p)); - pl->size_current += len; + if (pl->compression.format == PCAP_LOG_COMPRESSION_FORMAT_NONE) { + pl->size_current += len; + } +#ifdef HAVE_LIBLZ4 + else if (pl->compression.format == PCAP_LOG_COMPRESSION_FORMAT_LZ4) { + pcap_dump_flush(pl->pcap_dumper); + uint64_t in_size = (uint64_t)ftell(comp->pcap_buf_wrapper); + uint64_t out_size = LZ4F_compressUpdate(comp->lz4f_context, + comp->buffer, comp->buffer_size, comp->pcap_buf, in_size, NULL); + if (LZ4F_isError(len)) { + SCLogError(SC_ERR_PCAP_LOG_COMPRESS, "LZ4F_compressUpdate: %s", + LZ4F_getErrorName(len)); + return TM_ECODE_FAILED; + } + if (fseek(pl->compression.pcap_buf_wrapper, 0, SEEK_SET) != 0) { + SCLogError(SC_ERR_FSEEK, "fseek failed: %s", strerror(errno)); + return TM_ECODE_FAILED; + } + if (fwrite(comp->buffer, 1, out_size, comp->file) < out_size) { + SCLogError(SC_ERR_FWRITE, "fwrite failed: %s", strerror(errno)); + return TM_ECODE_FAILED; + } + if (out_size > 0) { + pl->size_current += out_size; + comp->bytes_in_block = len; + } else { + comp->bytes_in_block += len; + } + } +#endif /* HAVE_LIBLZ4 */ + PCAPLOG_PROFILE_END(pl->profile_write); pl->profile_data_size += len; @@ -472,6 +621,8 @@ static PcapLogData *PcapLogDataCopy(const PcapLogData *pl) return NULL; } + copy->suffix = pl->suffix; + /* settings TODO move to global cfg struct */ copy->is_private = TRUE; copy->mode = pl->mode; @@ -481,6 +632,63 @@ static PcapLogData *PcapLogDataCopy(const PcapLogData *pl) copy->use_stream_depth = pl->use_stream_depth; copy->size_limit = pl->size_limit; + const PcapLogCompressionData *comp = &pl->compression; + PcapLogCompressionData *copy_comp = ©->compression; + copy_comp->format = comp->format; +#ifdef HAVE_LIBLZ4 + if (comp->format == PCAP_LOG_COMPRESSION_FORMAT_LZ4) { + /* We need to allocate a new compression context and buffers for + * the copy. First copy the things that can simply be copied. */ + + copy_comp->buffer_size = comp->buffer_size; + copy_comp->pcap_buf_size = comp->pcap_buf_size; + copy_comp->lz4f_prefs = comp->lz4f_prefs; + + /* Allocate the buffers. */ + + copy_comp->buffer = SCMalloc(copy_comp->buffer_size); + if (copy_comp->buffer == NULL) { + SCLogError(SC_ERR_MEM_ALLOC, "SCMalloc failed: %s", + strerror(errno)); + return NULL; + } + copy_comp->pcap_buf = SCMalloc(copy_comp->pcap_buf_size); + if (copy_comp->pcap_buf == NULL) { + SCLogError(SC_ERR_MEM_ALLOC, "SCMalloc failed: %s", + strerror(errno)); + SCFree(copy_comp->buffer); + return NULL; + } + copy_comp->pcap_buf_wrapper = SCFmemopen(copy_comp->pcap_buf, + copy_comp->pcap_buf_size, "w"); + if (copy_comp->pcap_buf_wrapper == NULL) { + SCLogError(SC_ERR_FOPEN, "SCFmemopen failed: %s", strerror(errno)); + SCFree(copy_comp->buffer); + SCFree(copy_comp->pcap_buf); + return NULL; + } + + /* Initialize a new compression context. */ + + LZ4F_errorCode_t errcode = + LZ4F_createCompressionContext(©_comp->lz4f_context, 1); + if (LZ4F_isError(errcode)) { + SCLogError(SC_ERR_PCAP_LOG_COMPRESS, + "LZ4F_createCompressionContext failed: %s", + LZ4F_getErrorName(errcode)); + fclose(copy_comp->pcap_buf_wrapper); + SCFree(copy_comp->buffer); + SCFree(copy_comp->pcap_buf); + return NULL; + } + + /* Initialize the rest. */ + + copy_comp->file = NULL; + copy_comp->bytes_in_block = 0; + } +#endif /* HAVE_LIBLZ4 */ + TAILQ_INIT(©->pcap_file_list); SCMutexInit(©->plog_lock, NULL); @@ -583,6 +791,7 @@ static TmEcode PcapLogInitRingBuffer(PcapLogData *pl) strlcat(pattern, pl->prefix, PATH_MAX); strlcat(pattern, ".*", PATH_MAX); } + strlcat(pattern, pl->suffix, PATH_MAX); char *basename = strrchr(pattern, '/'); *basename++ = '\0'; @@ -791,6 +1000,19 @@ static void PcapLogDataFree(PcapLogData *pl) SCFree(pl->h); SCFree(pl->filename); SCFree(pl->prefix); + +#ifdef HAVE_LIBLZ4 + if (pl->compression.format == PCAP_LOG_COMPRESSION_FORMAT_LZ4) { + SCFree(pl->compression.buffer); + fclose(pl->compression.pcap_buf_wrapper); + SCFree(pl->compression.pcap_buf); + LZ4F_errorCode_t errcode = + LZ4F_freeCompressionContext(pl->compression.lz4f_context); + if (LZ4F_isError(errcode)) { + SCLogWarning(SC_ERR_MEM_ALLOC, "Error freeing lz4 context."); + } + } +#endif /* HAVE_LIBLZ4 */ SCFree(pl); } @@ -993,6 +1215,8 @@ static OutputInitResult PcapLogInitCtx(ConfNode *conf) exit(EXIT_FAILURE); } + pl->suffix = ""; + if (filename) { if (ParseFilename(pl, filename) != 0) exit(EXIT_FAILURE); @@ -1079,6 +1303,116 @@ static OutputInitResult PcapLogInitCtx(ConfNode *conf) } SCLogInfo("Using log dir %s", pl->dir); } + + const char *compression_str = ConfNodeLookupChildValue(conf, + "compression"); + + PcapLogCompressionData *comp = &pl->compression; + if (compression_str == NULL || strcmp(compression_str, "none") == 0) { + comp->format = PCAP_LOG_COMPRESSION_FORMAT_NONE; + comp->buffer = NULL; + comp->buffer_size = 0; + comp->file = NULL; + comp->pcap_buf = NULL; + comp->pcap_buf_size = 0; + comp->pcap_buf_wrapper = NULL; + } else if (strcmp(compression_str, "lz4") == 0) { +#ifdef HAVE_LIBLZ4 + if (pl->mode == LOGMODE_SGUIL) { + SCLogError(SC_ERR_INVALID_YAML_CONF_ENTRY, "Compressed pcap " + "logs are not possible in sguil mode"); + SCFree(pl->h); + SCFree(pl); + return result; + } + pl->compression.format = PCAP_LOG_COMPRESSION_FORMAT_LZ4; + + /* Use SCFmemopen so we can make pcap_dump write to a buffer. */ + + comp->pcap_buf_size = sizeof(struct pcap_file_header) + + sizeof(struct pcap_pkthdr) + PCAP_SNAPLEN; + comp->pcap_buf = SCMalloc(comp->pcap_buf_size); + if (comp->pcap_buf == NULL) { + SCLogError(SC_ERR_MEM_ALLOC, "SCMalloc failed: %s", + strerror(errno)); + exit(EXIT_FAILURE); + } + comp->pcap_buf_wrapper = SCFmemopen(comp->pcap_buf, + comp->pcap_buf_size, "w"); + if (comp->pcap_buf_wrapper == NULL) { + SCLogError(SC_ERR_FOPEN, "SCFmemopen failed: %s", + strerror(errno)); + exit(EXIT_FAILURE); + } + + /* Set lz4 preferences. */ + + memset(&comp->lz4f_prefs, '\0', sizeof(comp->lz4f_prefs)); + comp->lz4f_prefs.frameInfo.blockSizeID = LZ4F_max4MB; + comp->lz4f_prefs.frameInfo.blockMode = LZ4F_blockLinked; + if (ConfNodeChildValueIsTrue(conf, "lz4-checksum")) { + comp->lz4f_prefs.frameInfo.contentChecksumFlag = 1; + } + else { + comp->lz4f_prefs.frameInfo.contentChecksumFlag = 0; + } + intmax_t lvl = 0; + if (ConfGetChildValueInt(conf, "lz4-level", &lvl)) { + if (lvl > 16) { + lvl = 16; + } else if (lvl < 0) { + lvl = 0; + } + } else { + lvl = 0; + } + comp->lz4f_prefs.compressionLevel = lvl; + + /* Allocate resources for lz4. */ + + LZ4F_errorCode_t errcode = + LZ4F_createCompressionContext(&pl->compression.lz4f_context, 1); + + if (LZ4F_isError(errcode)) { + SCLogError(SC_ERR_PCAP_LOG_COMPRESS, + "LZ4F_createCompressionContext failed: %s", + LZ4F_getErrorName(errcode)); + exit(EXIT_FAILURE); + } + + /* Calculate the size of the lz4 output buffer. */ + + comp->buffer_size = LZ4F_compressBound(comp->pcap_buf_size, + &comp->lz4f_prefs); + + comp->buffer = SCMalloc(comp->buffer_size); + if (unlikely(comp->buffer == NULL)) { + SCLogError(SC_ERR_MEM_ALLOC, "Failed to allocate memory for " + "lz4 output buffer."); + exit(EXIT_FAILURE); + } + + comp->bytes_in_block = 0; + + /* Add the lz4 file extension to the log files. */ + + pl->suffix = ".lz4"; +#else + SCLogError(SC_ERR_INVALID_ARGUMENT, "lz4 compression was selected " + "in pcap-log, but suricata was not compiled with lz4 " + "support."); + return result; +#endif /* HAVE_LIBLZ4 */ + } + else { + SCLogError(SC_ERR_INVALID_ARGUMENT, "Unsupported pcap-log " + "compression format: %s", compression_str); + SCFree(pl->h); + SCFree(pl); + return result; + } + + SCLogInfo("Selected pcap-log compression method: %s", compression_str); } SCLogInfo("using %s logging", pl->mode == LOGMODE_SGUIL ? @@ -1249,11 +1583,12 @@ static int PcapLogOpenFileCtx(PcapLogData *pl) int written; if (pl->timestamp_format == TS_FORMAT_SEC) { - written = snprintf(filename, PATH_MAX, "%s/%s.%" PRIu32, dirfull, - pl->prefix, (uint32_t)ts.tv_sec); + written = snprintf(filename, PATH_MAX, "%s/%s.%" PRIu32 "%s", + dirfull, pl->prefix, (uint32_t)ts.tv_sec, pl->suffix); } else { - written = snprintf(filename, PATH_MAX, "%s/%s.%" PRIu32 ".%" PRIu32, - dirfull, pl->prefix, (uint32_t)ts.tv_sec, (uint32_t)ts.tv_usec); + written = snprintf(filename, PATH_MAX, "%s/%s.%" PRIu32 ".%" PRIu32 "%s", + dirfull, pl->prefix, (uint32_t)ts.tv_sec, + (uint32_t)ts.tv_usec, pl->suffix); } if (written == PATH_MAX) { SCLogError(SC_ERR_SPRINTF,"log-pcap path overflow"); @@ -1263,11 +1598,12 @@ static int PcapLogOpenFileCtx(PcapLogData *pl) int ret; /* create the filename to use */ if (pl->timestamp_format == TS_FORMAT_SEC) { - ret = snprintf(filename, PATH_MAX, "%s/%s.%" PRIu32, pl->dir, - pl->prefix, (uint32_t)ts.tv_sec); + ret = snprintf(filename, PATH_MAX, "%s/%s.%" PRIu32 "%s", pl->dir, + pl->prefix, (uint32_t)ts.tv_sec, pl->suffix); } else { - ret = snprintf(filename, PATH_MAX, "%s/%s.%" PRIu32 ".%" PRIu32, pl->dir, - pl->prefix, (uint32_t)ts.tv_sec, (uint32_t)ts.tv_usec); + ret = snprintf(filename, PATH_MAX, + "%s/%s.%" PRIu32 ".%" PRIu32 "%s", pl->dir, pl->prefix, + (uint32_t)ts.tv_sec, (uint32_t)ts.tv_usec, pl->suffix); } if (ret < 0 || (size_t)ret >= PATH_MAX) { SCLogError(SC_ERR_SPRINTF,"failed to construct path"); @@ -1317,15 +1653,19 @@ static int PcapLogOpenFileCtx(PcapLogData *pl) strlcat(filename, pl->filename_parts[i], PATH_MAX); } } + strlcat(filename, pl->suffix, PATH_MAX); } else { int ret; /* create the filename to use */ if (pl->timestamp_format == TS_FORMAT_SEC) { - ret = snprintf(filename, PATH_MAX, "%s/%s.%u.%" PRIu32, pl->dir, - pl->prefix, pl->thread_number, (uint32_t)ts.tv_sec); + ret = snprintf(filename, PATH_MAX, "%s/%s.%u.%" PRIu32 "%s", + pl->dir, pl->prefix, pl->thread_number, + (uint32_t)ts.tv_sec, pl->suffix); } else { - ret = snprintf(filename, PATH_MAX, "%s/%s.%u.%" PRIu32 ".%" PRIu32, pl->dir, - pl->prefix, pl->thread_number, (uint32_t)ts.tv_sec, (uint32_t)ts.tv_usec); + ret = snprintf(filename, PATH_MAX, + "%s/%s.%u.%" PRIu32 ".%" PRIu32 "%s", pl->dir, + pl->prefix, pl->thread_number, (uint32_t)ts.tv_sec, + (uint32_t)ts.tv_usec, pl->suffix); } if (ret < 0 || (size_t)ret >= PATH_MAX) { SCLogError(SC_ERR_SPRINTF,"failed to construct path"); diff --git a/src/util-error.c b/src/util-error.c index 639a6cf3cb..6a394da3fa 100644 --- a/src/util-error.c +++ b/src/util-error.c @@ -350,6 +350,9 @@ const char * SCErrorToString(SCError err) CASE_CODE (SC_ERR_SMB_CONFIG); CASE_CODE (SC_WARN_NO_JA3_SUPPORT); CASE_CODE (SC_WARN_JA3_DISABLED); + CASE_CODE (SC_ERR_PCAP_LOG_COMPRESS); + CASE_CODE (SC_ERR_FSEEK); + CASE_CODE (SC_ERR_MAX); } diff --git a/src/util-error.h b/src/util-error.h index 399e96f229..4654f046fe 100644 --- a/src/util-error.h +++ b/src/util-error.h @@ -340,7 +340,10 @@ typedef enum { SC_ERR_SMB_CONFIG, SC_WARN_NO_JA3_SUPPORT, SC_WARN_JA3_DISABLED, - SC_ERR_MAX + SC_ERR_PCAP_LOG_COMPRESS, + SC_ERR_FSEEK, + + SC_ERR_MAX, } SCError; const char *SCErrorToString(SCError); diff --git a/suricata.yaml.in b/suricata.yaml.in index cd4b15c361..634d153390 100644 --- a/suricata.yaml.in +++ b/suricata.yaml.in @@ -406,6 +406,17 @@ outputs: # If set to a value will enable ring buffer mode. Will keep Maximum of "max-files" of size "limit" max-files: 2000 + # Compression algorithm for pcap files. Possible values: none, lz4. + # Enabling compression is incompatible with the sguil mode. Note also + # that on Windows, enabling compression will *increase* disk I/O. + compression: none + + # Further options for lz4 compression. The compression level can be set + # to a value between 0 and 16, where higher values result in higher + # compression. + #lz4-checksum: no + #lz4-level: 0 + mode: normal # normal, multi or sguil. # Directory to place pcap files. If not provided the default log