Add an option for compressing pcap-log files

Introduces the option 'outputs.pcap-log.compression' which can be set
to 'none' or 'lz4', plus options to set the compression level and to
enable checksums. SCFmemopen is used to make pcap_dump() write to a
buffer which is then compressed using liblz4.
pull/3368/head
Max Fillinger 7 years ago committed by Victor Julien
parent 6062c27eb7
commit b85a0b188b

@ -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

@ -26,6 +26,11 @@
*/
#include "suricata-common.h"
#include "util-fmemopen.h"
#ifdef HAVE_LIBLZ4
#include <lz4frame.h>
#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 = &copy->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(&copy_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(&copy->pcap_file_list);
SCMutexInit(&copy->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");

@ -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);
}

@ -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);

@ -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

Loading…
Cancel
Save