33#define MODULE_NAME "OutputFilestore"
37#define SHA256_STRING_LEN (SC_SHA256_LEN * 2)
38#define LEAF_DIR_MAX_LEN 4
39#define FILESTORE_PREFIX_MAX (PATH_MAX - SHA256_STRING_LEN - LEAF_DIR_MAX_LEN)
43static const char *default_log_dir =
"filestore";
73static thread_local bool once_errs[
WOT_MAX];
75#define WARN_ONCE(wot_type, ...) \
77 if (!once_errs[wot_type]) { \
78 once_errs[wot_type] = true; \
79 SCLogWarning(__VA_ARGS__); \
83static uint64_t OutputFilestoreOpenFilesCounter(
void)
88static uint32_t g_file_store_max_open_files = 0;
90static void FileSetMaxOpenFiles(uint32_t count)
92 g_file_store_max_open_files = count;
95static uint32_t FileGetMaxOpenFiles(
void)
97 return g_file_store_max_open_files;
107static void OutputFilestoreUpdateFileTime(
const char *src_filename,
108 const char *filename)
111 if (stat(src_filename, &sb) != 0) {
112 SCLogDebug(
"Failed to stat %s: %s", filename, strerror(errno));
115 struct utimbuf utimbuf = {
116 .actime = sb.st_atime,
117 .modtime = sb.st_mtime,
119 if (utime(filename, &utimbuf) != 0) {
120 SCLogDebug(
"Failed to update file timestamps: %s: %s", filename,
135 char tmp_filename[PATH_MAX] =
"";
136 snprintf(tmp_filename,
sizeof(tmp_filename),
"%s/file.%u",
ctx->tmpdir,
139 char final_filename[PATH_MAX] =
"";
140 snprintf(final_filename,
sizeof(final_filename),
"%s/%c%c/%s",
141 ctx->prefix, sha256string[0], sha256string[1], sha256string);
144 OutputFilestoreUpdateFileTime(tmp_filename, final_filename);
145 if (unlink(tmp_filename) != 0) {
150 }
else if (rename(tmp_filename, final_filename) != 0) {
154 if (unlink(tmp_filename) != 0) {
163 char js_metadata_filename[PATH_MAX];
164 if (snprintf(js_metadata_filename,
sizeof(js_metadata_filename),
"%s.%" PRIuMAX
".%u.json",
169 SCJsonBuilder *js_fileinfo =
171 if (
likely(js_fileinfo != NULL)) {
172 SCJbClose(js_fileinfo);
173 FILE *out = fopen(js_metadata_filename,
"w");
175 size_t js_len = SCJbLen(js_fileinfo);
176 fwrite(SCJbPtr(js_fileinfo), js_len, 1, out);
179 SCJbFree(js_fileinfo);
186 void *tx,
const uint64_t tx_id,
const uint8_t *data, uint32_t data_len, uint8_t
flags,
192 char filename[PATH_MAX] =
"";
195 SCLogDebug(
"ff %p, data %p, data_len %u", ff, data, data_len);
198 snprintf(filename,
sizeof(filename),
"%s/file.%u",
ctx->tmpdir, ff->
file_store_id);
199 file_fd = open(filename, O_CREAT | O_TRUNC |
O_NOFOLLOW | O_WRONLY,
203 SCLogWarning(
"Filestore (v2) failed to create %s: %s", filename, strerror(errno));
207 if (
SC_ATOMIC_GET(filestore_open_file_cnt) < FileGetMaxOpenFiles()) {
211 if (FileGetMaxOpenFiles() > 0) {
217 }
else if (data != NULL) {
219 snprintf(filename,
sizeof(filename),
"%s/file.%u",
ctx->tmpdir, ff->
file_store_id);
220 file_fd = open(filename, O_APPEND |
O_NOFOLLOW | O_WRONLY);
233 ssize_t r = write(file_fd, (
const void *)data, (
size_t)data_len);
235 snprintf(filename,
sizeof(filename),
"%s/file.%u",
ctx->tmpdir, ff->
file_store_id);
255 OutputFilestoreFinalizeFiles(
tv, aft,
ctx, p, ff, tx, tx_id, dir);
268 if (initdata == NULL) {
269 SCLogDebug(
"Error getting context for LogFileStore. \"initdata\" argument NULL");
303static void OutputFilestoreLogDeInitCtx(
OutputCtx *output_ctx)
306 if (
ctx->xff_cfg != NULL) {
313static void GetLogDirectory(
const SCConfNode *conf,
char *out,
size_t out_size)
316 if (log_base_dir == NULL) {
317 SCLogConfig(
"Filestore (v2) default log directory %s", default_log_dir);
318 log_base_dir = default_log_dir;
321 strlcpy(out, log_base_dir, out_size);
324 snprintf(out, out_size,
"%s/%s", default_log_prefix, log_base_dir);
328static bool InitFilestoreDirectory(
const char *dir)
330 const uint8_t dir_count = 0xff;
333 SCLogInfo(
"Filestore (v2) creating directory %s", dir);
335 SCLogError(
"Filestore (v2) failed to create directory %s: %s", dir, strerror(errno));
340 for (
int i = 0; i <= dir_count; i++) {
342 int n = snprintf(leaf,
sizeof(leaf),
"%s/%02x", dir, i);
343 if (n < 0 || n >= PATH_MAX) {
344 SCLogError(
"Filestore (v2) failed to create leaf directory: "
349 SCLogInfo(
"Filestore (v2) creating directory %s", leaf);
352 "Filestore (v2) failed to create directory %s: %s", leaf, strerror(errno));
359 char tmpdir[PATH_MAX];
360 int n = snprintf(tmpdir,
sizeof(tmpdir),
"%s/tmp", dir);
361 if (n < 0 || n >= PATH_MAX) {
362 SCLogError(
"Filestore (v2) failed to create tmp directory: path too long");
366 SCLogInfo(
"Filestore (v2) creating directory %s", tmpdir);
368 SCLogError(
"Filestore (v2) failed to create directory %s: %s", tmpdir, strerror(errno));
386 SCLogWarning(
"File-store v1 has been removed. Please update to file-store v2.");
391 SCLogWarning(
"A file data logger is already enabled. Filestore (v2) "
392 "will not be enabled.");
396 char log_directory[PATH_MAX] =
"";
397 GetLogDirectory(conf, log_directory,
sizeof(log_directory));
398 if (!InitFilestoreDirectory(log_directory)) {
408 int written = snprintf(
ctx->tmpdir,
sizeof(
ctx->tmpdir) - 1,
"%s/tmp",
410 if (written ==
sizeof(
ctx->tmpdir)) {
411 SCLogError(
"File-store output directory overflow.");
417 if (
ctx->xff_cfg != NULL) {
429 output_ctx->
DeInit = OutputFilestoreLogDeInitCtx;
433 SCLogConfig(
"Filestore (v2) will output fileinfo records.");
434 ctx->fileinfo =
true;
440 SCLogInfo(
"forcing filestore of all files");
446 SCLogConfig(
"Filestore (v2) forcing magic lookup for stored files");
457 if (stream_depth_str != NULL && strcmp(stream_depth_str,
"no")) {
458 uint32_t stream_depth = 0;
460 &stream_depth) < 0) {
462 "file-store.stream-depth "
463 "from conf file - %s. Killing engine",
469 SCLogWarning(
"file-store.stream-depth value %" PRIu32
" has "
470 "no effect since it's less than stream.reassembly.depth "
480 if (file_count_str != NULL) {
481 uint32_t file_count = 0;
485 "file-store.max-open-files "
486 "from conf file - %s. Killing engine",
490 if (file_count != 0) {
491 FileSetMaxOpenFiles(file_count);
492 SCLogConfig(
"Filestore (v2) will keep a max of %d "
493 "simultaneously open files", file_count);
498 result.
ctx = output_ctx;
506 OutputFilestoreLogInitCtx, OutputFilestoreLogger, OutputFilestoreLogThreadInit,
507 OutputFilestoreLogThreadDeinit);
void HttpXFFGetCfg(SCConfNode *conf, HttpXFFCfg *result)
Function to return XFF configuration from a configuration node.
int SCConfValIsTrue(const char *val)
Check if a value is true.
int SCConfGetChildValueInt(const SCConfNode *base, const char *name, intmax_t *val)
const char * SCConfNodeLookupChildValue(const SCConfNode *node, const char *name)
Lookup the value of a child configuration node by name.
uint16_t StatsRegisterGlobalCounter(const char *name, uint64_t(*Func)(void))
Registers a counter, which represents a global value.
uint16_t StatsRegisterCounter(const char *name, struct ThreadVars_ *tv)
Registers a normal, unqualified counter.
void StatsIncr(ThreadVars *tv, uint16_t id)
Increments the local counter.
void ProvidesFeature(const char *feature_name)
#define FEATURE_OUTPUT_FILESTORE
TcpStreamCnf stream_config
#define OUTPUT_FILEDATA_FLAG_CLOSE
#define OUTPUT_FILEDATA_FLAG_OPEN
#define FILESTORE_PREFIX_MAX
#define WARN_ONCE(wot_type,...)
struct OutputFilestoreLogThread_ OutputFilestoreLogThread
void OutputFilestoreRegister(void)
struct OutputFilestoreCtx_ OutputFilestoreCtx
void OutputFilestoreRegisterGlobalCounters(void)
SCJsonBuilder * JsonBuildFileInfoRecord(const Packet *p, const File *ff, void *tx, const uint64_t tx_id, const bool stored, uint8_t dir, HttpXFFCfg *xff_cfg, OutputJsonCtx *eve_ctx)
void OutputRegisterFiledataModule(LoggerId id, const char *name, const char *conf_name, OutputInitFunc InitFunc, SCFiledataLogger FiledataLogFunc, ThreadInitFunc ThreadInit, ThreadDeinitFunc ThreadDeinit)
Register a file data output module.
int RunModeOutputFiledataEnabled(void)
uint8_t sha256[SC_SHA256_LEN]
void(* DeInit)(struct OutputCtx_ *)
char tmpdir[FILESTORE_PREFIX_MAX]
char prefix[FILESTORE_PREFIX_MAX]
uint16_t counter_max_hits
uint16_t fs_error_counter
uint32_t reassembly_depth
Per thread variable structure.
size_t strlcpy(char *dst, const char *src, size_t siz)
#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_SUB(name, val)
sub a value from our atomic variable
#define SC_ATOMIC_GET(name)
Get the value from the atomic variable.
#define SC_ATOMIC_SET(name, val)
Set the value for the atomic variable.
const char * SCConfigGetLogDirectory(void)
#define SCReturnCT(x, type)
#define SCLogWarning(...)
Macro used to log WARNING messages.
#define SCLogInfo(...)
Macro used to log INFORMATIONAL messages.
#define SCLogError(...)
Macro used to log ERROR messages.
void FileForceSha256Enable(void)
void FileForceMagicEnable(void)
void FileReassemblyDepthEnable(uint32_t size)
void FileForceFilestoreEnable(void)
void FileForceHashParseCfg(SCConfNode *conf)
Function to parse forced file hashing configuration.
int ParseSizeStringU32(const char *size, uint32_t *res)
bool SCPathExists(const char *path)
Check if a path exists.
int PathIsAbsolute(const char *path)
Check if a path is absolute.
int SCCreateDirectoryTree(const char *path, const bool final)
Recursively create a directory.
int SCDefaultMkDir(const char *path)
Wrapper around SCMkDir with default mode arguments.
void PrintHexString(char *str, size_t size, uint8_t *buf, size_t buf_len)