suricata
output-filedata.c
Go to the documentation of this file.
1 /* Copyright (C) 2007-2024 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 Victor Julien <victor@inliniac.net>
22  *
23  * AppLayer Filedata Logger Output registration functions
24  */
25 
26 #include "suricata-common.h"
27 #include "output.h"
28 #include "output-filedata.h"
29 #include "app-layer-parser.h"
30 #include "detect-filemagic.h"
31 #include "conf.h"
32 #include "util-profiling.h"
33 #include "util-validate.h"
34 #include "util-magic.h"
35 #include "util-path.h"
36 
38 
39 /* logger instance, a module + a output ctx,
40  * it's perfectly valid that have multiple instances of the same
41  * log module (e.g. http.log) with different output ctx'. */
42 typedef struct OutputFiledataLogger_ {
44  void *initdata;
46  const char *name;
51 
52 static OutputFiledataLogger *list = NULL;
53 
56 {
57  OutputFiledataLogger *op = SCCalloc(1, sizeof(*op));
58  if (op == NULL)
59  return -1;
60 
61  op->LogFunc = LogFunc;
62  op->initdata = initdata;
63  op->name = name;
64  op->logger_id = id;
65  op->ThreadInit = ThreadInit;
67 
68  if (list == NULL)
69  list = op;
70  else {
71  OutputFiledataLogger *t = list;
72  while (t->next)
73  t = t->next;
74  t->next = op;
75  }
76 
77  SCLogDebug("OutputRegisterFiledataLogger happy");
79  return 0;
80 }
81 
82 SC_ATOMIC_DECLARE(unsigned int, g_file_store_id);
83 
84 static int CallLoggers(ThreadVars *tv, OutputLoggerThreadStore *store_list, Packet *p, File *ff,
85  void *tx, const uint64_t tx_id, const uint8_t *data, uint32_t data_len, uint8_t flags,
86  uint8_t dir)
87 {
88  OutputFiledataLogger *logger = list;
89  OutputLoggerThreadStore *store = store_list;
90  int file_logged = 0;
91 
92  while (logger && store) {
93  DEBUG_VALIDATE_BUG_ON(logger->LogFunc == NULL);
94 
95  SCLogDebug("logger %p", logger);
97  logger->LogFunc(tv, store->thread_data, (const Packet *)p, ff, tx, tx_id, data, data_len,
98  flags, dir);
100 
101  file_logged = 1;
102 
103  logger = logger->next;
104  store = store->next;
105 
106  DEBUG_VALIDATE_BUG_ON(logger == NULL && store != NULL);
107  DEBUG_VALIDATE_BUG_ON(logger != NULL && store == NULL);
108  }
109  return file_logged;
110 }
111 
112 static void CloseFile(const Packet *p, Flow *f, File *file, void *txv)
113 {
114  DEBUG_VALIDATE_BUG_ON((file->flags & FILE_STORED) != 0);
115 
117  BUG_ON(f->alproto == ALPROTO_SMB && txd->files_logged != 0);
118  txd->files_stored++;
119  file->flags |= FILE_STORED;
120 }
121 
123  AppLayerGetFileState files, void *txv, const uint64_t tx_id, AppLayerTxData *txd,
124  const uint8_t call_flags, const bool file_close, const bool file_trunc, const uint8_t dir)
125 {
126  SCLogDebug("ffc %p", files.fc);
127 
128  OutputLoggerThreadStore *store = td->store;
129  for (File *ff = files.fc->head; ff != NULL; ff = ff->next) {
130  FileApplyTxFlags(txd, dir, ff);
131  FilePrintFlags(ff);
132 
133  uint8_t file_flags = call_flags;
134 #ifdef HAVE_MAGIC
135  if (FileForceMagic() && ff->magic == NULL) {
136  FilemagicThreadLookup(&td->magic_ctx, ff);
137  }
138 #endif
139  if (ff->flags & FILE_STORED) {
140  continue;
141  }
142 
143  if (!(ff->flags & FILE_STORE)) {
144  continue;
145  }
146 
147  /* if file_store_id == 0, this is the first store of this file */
148  if (ff->file_store_id == 0) {
149  /* new file */
150  ff->file_store_id = SC_ATOMIC_ADD(g_file_store_id, 1);
151  file_flags |= OUTPUT_FILEDATA_FLAG_OPEN;
152  }
153 
154  /* if we have no data chunks left to log, we should still
155  * close the logger(s) */
156  if (FileDataSize(ff) == ff->content_stored && (file_trunc || file_close)) {
157  if (ff->state < FILE_STATE_CLOSED) {
158  FileCloseFilePtr(ff, files.cfg, NULL, 0, FILE_TRUNCATED);
159  }
160  file_flags |= OUTPUT_FILEDATA_FLAG_CLOSE;
161  CallLoggers(tv, store, p, ff, txv, tx_id, NULL, 0, file_flags, dir);
162  CloseFile(p, p->flow, ff, txv);
163  continue;
164  }
165 
166  /* if file needs to be closed or truncated, inform
167  * loggers */
168  if ((file_close || file_trunc) && ff->state < FILE_STATE_CLOSED) {
169  FileCloseFilePtr(ff, files.cfg, NULL, 0, FILE_TRUNCATED);
170  }
171 
172  /* tell the logger we're closing up */
173  if (ff->state >= FILE_STATE_CLOSED)
174  file_flags |= OUTPUT_FILEDATA_FLAG_CLOSE;
175 
176  /* do the actual logging */
177  const uint8_t *data = NULL;
178  uint32_t data_len = 0;
179 
180  StreamingBufferGetDataAtOffset(ff->sb, &data, &data_len, ff->content_stored);
181 
182  const int file_logged =
183  CallLoggers(tv, store, p, ff, txv, tx_id, data, data_len, file_flags, dir);
184  if (file_logged) {
185  ff->content_stored += data_len;
186 
187  /* all done */
188  if (file_flags & OUTPUT_FILEDATA_FLAG_CLOSE) {
189  CloseFile(p, p->flow, ff, txv);
190  }
191  }
192  }
193 }
194 
195 /** \brief thread init for the filedata logger
196  * This will run the thread init functions for the individual registered
197  * loggers */
199 {
200  OutputFiledataLoggerThreadData *td = SCCalloc(1, sizeof(*td));
201  if (td == NULL)
202  return TM_ECODE_FAILED;
203  *data = td;
204 
205 #ifdef HAVE_MAGIC
206  td->magic_ctx = MagicInitContext();
207  if (td->magic_ctx == NULL) {
208  SCFree(td);
209  return TM_ECODE_FAILED;
210  }
211 #endif
212 
213  SCLogDebug("OutputFiledataLogThreadInit happy (*data %p)", *data);
214 
215  OutputFiledataLogger *logger = list;
216  while (logger) {
217  if (logger->ThreadInit) {
218  void *retptr = NULL;
219  if (logger->ThreadInit(tv, logger->initdata, &retptr) == TM_ECODE_OK) {
220  OutputLoggerThreadStore *ts = SCCalloc(1, sizeof(*ts));
221  /* todo */ BUG_ON(ts == NULL);
222 
223  /* store thread handle */
224  ts->thread_data = retptr;
225 
226  if (td->store == NULL) {
227  td->store = ts;
228  } else {
229  OutputLoggerThreadStore *tmp = td->store;
230  while (tmp->next != NULL)
231  tmp = tmp->next;
232  tmp->next = ts;
233  }
234 
235  SCLogDebug("%s is now set up", logger->name);
236  }
237  }
238 
239  logger = logger->next;
240  }
241  return TM_ECODE_OK;
242 }
243 
245  ThreadVars *tv, OutputFiledataLoggerThreadData *op_thread_data)
246 {
247  OutputLoggerThreadStore *store = op_thread_data->store;
248  OutputFiledataLogger *logger = list;
249 
250  while (logger && store) {
251  if (logger->ThreadDeinit) {
252  logger->ThreadDeinit(tv, store->thread_data);
253  }
254 
255  OutputLoggerThreadStore *next_store = store->next;
256  SCFree(store);
257  store = next_store;
258  logger = logger->next;
259  }
260 
261 #ifdef HAVE_MAGIC
262  MagicDeinitContext(op_thread_data->magic_ctx);
263 #endif
264 
265  SCFree(op_thread_data);
266  return TM_ECODE_OK;
267 }
268 
270 {
271  SC_ATOMIC_INIT(g_file_store_id);
272  SC_ATOMIC_SET(g_file_store_id, 1);
273 }
274 
276 {
277  OutputFiledataLogger *logger = list;
278  while (logger) {
279  OutputFiledataLogger *next_logger = logger->next;
280  SCFree(logger);
281  logger = next_logger;
282  }
283 
284  list = NULL;
285 }
OutputFiledataLogThreadInit
TmEcode OutputFiledataLogThreadInit(ThreadVars *tv, OutputFiledataLoggerThreadData **data)
thread init for the filedata logger This will run the thread init functions for the individual regist...
Definition: output-filedata.c:198
FILE_TRUNCATED
#define FILE_TRUNCATED
Definition: util-file.h:45
ts
uint64_t ts
Definition: source-erf-file.c:55
OutputLoggerThreadStore_
Definition: output.h:33
OutputFiledataLogger_::name
const char * name
Definition: output-filedata.c:46
OutputFiledataLoggerThreadData_::store
OutputLoggerThreadStore * store
Definition: output-filedata.h:35
SC_ATOMIC_INIT
#define SC_ATOMIC_INIT(name)
wrapper for initializing an atomic variable.
Definition: util-atomic.h:314
SC_ATOMIC_SET
#define SC_ATOMIC_SET(name, val)
Set the value for the atomic variable.
Definition: util-atomic.h:386
output-filedata.h
OutputFiledataLogger_::ThreadDeinit
ThreadDeinitFunc ThreadDeinit
Definition: output-filedata.c:49
OutputFiledataLogger_::logger_id
LoggerId logger_id
Definition: output-filedata.c:47
SCLogDebug
#define SCLogDebug(...)
Definition: util-debug.h:269
OutputFiledataLogger_::initdata
void * initdata
Definition: output-filedata.c:44
Flow_::proto
uint8_t proto
Definition: flow.h:378
Flow_
Flow data structure.
Definition: flow.h:356
OutputFiledataLogThreadDeinit
TmEcode OutputFiledataLogThreadDeinit(ThreadVars *tv, OutputFiledataLoggerThreadData *op_thread_data)
Definition: output-filedata.c:244
File_::state
FileState state
Definition: util-file.h:82
OutputFiledataLogger_::LogFunc
SCFiledataLogger LogFunc
Definition: output-filedata.c:43
LoggerId
LoggerId
Definition: suricata-common.h:469
SC_ATOMIC_ADD
#define SC_ATOMIC_ADD(name, val)
add a value to our atomic variable
Definition: util-atomic.h:332
OutputFiledataShutdown
void OutputFiledataShutdown(void)
Definition: output-filedata.c:275
FILE_STORE
#define FILE_STORE
Definition: util-file.h:55
File_::file_store_id
uint32_t file_store_id
Definition: util-file.h:85
OutputLoggerThreadStore_::next
struct OutputLoggerThreadStore_ * next
Definition: output.h:35
OutputFiledataLogger_::next
struct OutputFiledataLogger_ * next
Definition: output-filedata.c:45
SCFiledataLogger
int(* SCFiledataLogger)(ThreadVars *, void *thread_data, const Packet *, File *, void *tx, const uint64_t tx_id, const uint8_t *, uint32_t, uint8_t, uint8_t dir)
File-data logger function pointer type.
Definition: output-filedata.h:51
StreamingBufferGetDataAtOffset
int StreamingBufferGetDataAtOffset(const StreamingBuffer *sb, const uint8_t **data, uint32_t *data_len, uint64_t offset)
Definition: util-streaming-buffer.c:1830
TM_ECODE_FAILED
@ TM_ECODE_FAILED
Definition: tm-threads-common.h:82
OUTPUT_FILEDATA_FLAG_CLOSE
#define OUTPUT_FILEDATA_FLAG_CLOSE
Definition: output-filedata.h:30
TM_ECODE_OK
@ TM_ECODE_OK
Definition: tm-threads-common.h:81
File_::sb
StreamingBuffer * sb
Definition: util-file.h:83
SC_ATOMIC_DECLARE
SC_ATOMIC_DECLARE(unsigned int, g_file_store_id)
OutputLoggerThreadStore_::thread_data
void * thread_data
Definition: output.h:34
FileApplyTxFlags
void FileApplyTxFlags(const AppLayerTxData *txd, const uint8_t direction, File *file)
Definition: util-file.c:295
FileForceMagic
int FileForceMagic(void)
Definition: util-file.c:141
detect-filemagic.h
ThreadVars_
Per thread variable structure.
Definition: threadvars.h:58
ThreadInitFunc
TmEcode(* ThreadInitFunc)(ThreadVars *, const void *, void **)
Definition: tm-modules.h:39
app-layer-parser.h
BUG_ON
#define BUG_ON(x)
Definition: suricata-common.h:309
util-profiling.h
Packet_
Definition: decode.h:484
OutputFiledataLogger_
Definition: output-filedata.c:42
conf.h
util-magic.h
TmEcode
TmEcode
Definition: tm-threads-common.h:80
name
const char * name
Definition: tm-threads.c:2135
OutputFiledataLoggerThreadData_
Definition: output-filedata.h:34
FileCloseFilePtr
int FileCloseFilePtr(File *ff, const StreamingBufferConfig *sbcfg, const uint8_t *data, uint32_t data_len, uint16_t flags)
Definition: util-file.c:997
OutputFiledataLogFfc
void OutputFiledataLogFfc(ThreadVars *tv, OutputFiledataLoggerThreadData *td, Packet *p, AppLayerGetFileState files, void *txv, const uint64_t tx_id, AppLayerTxData *txd, const uint8_t call_flags, const bool file_close, const bool file_trunc, const uint8_t dir)
Definition: output-filedata.c:122
FileDataSize
uint64_t FileDataSize(const File *file)
get the size of the file data
Definition: util-file.c:326
File_::flags
uint16_t flags
Definition: util-file.h:80
PACKET_PROFILING_LOGGER_END
#define PACKET_PROFILING_LOGGER_END(p, id)
Definition: util-profiling.h:240
FILE_STATE_CLOSED
@ FILE_STATE_CLOSED
Definition: util-file.h:71
File_
Definition: util-file.h:79
File_::content_stored
uint64_t content_stored
Definition: util-file.h:101
AppLayerTxData
struct AppLayerTxData AppLayerTxData
Definition: detect.h:1468
Packet_::flow
struct Flow_ * flow
Definition: decode.h:529
flags
uint8_t flags
Definition: decode-gre.h:0
suricata-common.h
util-path.h
OutputFiledataLogger
struct OutputFiledataLogger_ OutputFiledataLogger
FILE_STORED
#define FILE_STORED
Definition: util-file.h:56
OUTPUT_FILEDATA_FLAG_OPEN
#define OUTPUT_FILEDATA_FLAG_OPEN
Definition: output-filedata.h:29
File_::next
struct File_ * next
Definition: util-file.h:92
AppLayerParserGetTxData
AppLayerTxData * AppLayerParserGetTxData(uint8_t ipproto, AppProto alproto, void *tx)
Definition: app-layer-parser.c:1182
tv
ThreadVars * tv
Definition: fuzz_decodepcapfile.c:32
FilePrintFlags
#define FilePrintFlags(file)
Definition: util-file.h:250
util-validate.h
SCFree
#define SCFree(p)
Definition: util-mem.h:61
PACKET_PROFILING_LOGGER_START
#define PACKET_PROFILING_LOGGER_START(p, id)
Definition: util-profiling.h:233
SCOutputRegisterFiledataLogger
int SCOutputRegisterFiledataLogger(LoggerId id, const char *name, SCFiledataLogger LogFunc, void *initdata, ThreadInitFunc ThreadInit, ThreadDeinitFunc ThreadDeinit)
Register a file-data logger.
Definition: output-filedata.c:54
g_filedata_logger_enabled
bool g_filedata_logger_enabled
Definition: output-filedata.c:37
ALPROTO_SMB
@ ALPROTO_SMB
Definition: app-layer-protos.h:43
OutputFiledataLogger_::ThreadInit
ThreadInitFunc ThreadInit
Definition: output-filedata.c:48
id
uint32_t id
Definition: detect-flowbits.c:933
Flow_::alproto
AppProto alproto
application level protocol
Definition: flow.h:450
SCCalloc
#define SCCalloc(nm, sz)
Definition: util-mem.h:53
OutputFiledataLoggerRegister
void OutputFiledataLoggerRegister(void)
Definition: output-filedata.c:269
DEBUG_VALIDATE_BUG_ON
#define DEBUG_VALIDATE_BUG_ON(exp)
Definition: util-validate.h:102
output.h
ThreadDeinitFunc
TmEcode(* ThreadDeinitFunc)(ThreadVars *, void *)
Definition: tm-modules.h:40