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  if (txd) {
118  BUG_ON(f->alproto == ALPROTO_SMB && txd->files_logged != 0);
119  txd->files_stored++;
120  }
121  file->flags |= FILE_STORED;
122 }
123 
125  AppLayerGetFileState files, void *txv, const uint64_t tx_id, AppLayerTxData *txd,
126  const uint8_t call_flags, const bool file_close, const bool file_trunc, const uint8_t dir)
127 {
128  SCLogDebug("ffc %p", files.fc);
129 
130  OutputLoggerThreadStore *store = td->store;
131  for (File *ff = files.fc->head; ff != NULL; ff = ff->next) {
132  FileApplyTxFlags(txd, dir, ff);
133  FilePrintFlags(ff);
134 
135  uint8_t file_flags = call_flags;
136 #ifdef HAVE_MAGIC
137  if (FileForceMagic() && ff->magic == NULL) {
138  FilemagicThreadLookup(&td->magic_ctx, ff);
139  }
140 #endif
141  if (ff->flags & FILE_STORED) {
142  continue;
143  }
144 
145  if (!(ff->flags & FILE_STORE)) {
146  continue;
147  }
148 
149  /* if file_store_id == 0, this is the first store of this file */
150  if (ff->file_store_id == 0) {
151  /* new file */
152  ff->file_store_id = SC_ATOMIC_ADD(g_file_store_id, 1);
153  file_flags |= OUTPUT_FILEDATA_FLAG_OPEN;
154  }
155 
156  /* if we have no data chunks left to log, we should still
157  * close the logger(s) */
158  if (FileDataSize(ff) == ff->content_stored && (file_trunc || file_close)) {
159  if (ff->state < FILE_STATE_CLOSED) {
160  FileCloseFilePtr(ff, files.cfg, NULL, 0, FILE_TRUNCATED);
161  }
162  file_flags |= OUTPUT_FILEDATA_FLAG_CLOSE;
163  CallLoggers(tv, store, p, ff, txv, tx_id, NULL, 0, file_flags, dir);
164  CloseFile(p, p->flow, ff, txv);
165  continue;
166  }
167 
168  /* if file needs to be closed or truncated, inform
169  * loggers */
170  if ((file_close || file_trunc) && ff->state < FILE_STATE_CLOSED) {
171  FileCloseFilePtr(ff, files.cfg, NULL, 0, FILE_TRUNCATED);
172  }
173 
174  /* tell the logger we're closing up */
175  if (ff->state >= FILE_STATE_CLOSED)
176  file_flags |= OUTPUT_FILEDATA_FLAG_CLOSE;
177 
178  /* do the actual logging */
179  const uint8_t *data = NULL;
180  uint32_t data_len = 0;
181 
182  StreamingBufferGetDataAtOffset(ff->sb, &data, &data_len, ff->content_stored);
183 
184  const int file_logged =
185  CallLoggers(tv, store, p, ff, txv, tx_id, data, data_len, file_flags, dir);
186  if (file_logged) {
187  ff->content_stored += data_len;
188 
189  /* all done */
190  if (file_flags & OUTPUT_FILEDATA_FLAG_CLOSE) {
191  CloseFile(p, p->flow, ff, txv);
192  }
193  }
194  }
195 }
196 
197 /** \brief thread init for the filedata logger
198  * This will run the thread init functions for the individual registered
199  * loggers */
201 {
202  OutputFiledataLoggerThreadData *td = SCCalloc(1, sizeof(*td));
203  if (td == NULL)
204  return TM_ECODE_FAILED;
205  *data = td;
206 
207 #ifdef HAVE_MAGIC
208  td->magic_ctx = MagicInitContext();
209  if (td->magic_ctx == NULL) {
210  SCFree(td);
211  return TM_ECODE_FAILED;
212  }
213 #endif
214 
215  SCLogDebug("OutputFiledataLogThreadInit happy (*data %p)", *data);
216 
217  OutputFiledataLogger *logger = list;
218  while (logger) {
219  if (logger->ThreadInit) {
220  void *retptr = NULL;
221  if (logger->ThreadInit(tv, logger->initdata, &retptr) == TM_ECODE_OK) {
222  OutputLoggerThreadStore *ts = SCCalloc(1, sizeof(*ts));
223  /* todo */ BUG_ON(ts == NULL);
224 
225  /* store thread handle */
226  ts->thread_data = retptr;
227 
228  if (td->store == NULL) {
229  td->store = ts;
230  } else {
231  OutputLoggerThreadStore *tmp = td->store;
232  while (tmp->next != NULL)
233  tmp = tmp->next;
234  tmp->next = ts;
235  }
236 
237  SCLogDebug("%s is now set up", logger->name);
238  }
239  }
240 
241  logger = logger->next;
242  }
243  return TM_ECODE_OK;
244 }
245 
247  ThreadVars *tv, OutputFiledataLoggerThreadData *op_thread_data)
248 {
249  OutputLoggerThreadStore *store = op_thread_data->store;
250  OutputFiledataLogger *logger = list;
251 
252  while (logger && store) {
253  if (logger->ThreadDeinit) {
254  logger->ThreadDeinit(tv, store->thread_data);
255  }
256 
257  OutputLoggerThreadStore *next_store = store->next;
258  SCFree(store);
259  store = next_store;
260  logger = logger->next;
261  }
262 
263 #ifdef HAVE_MAGIC
264  MagicDeinitContext(op_thread_data->magic_ctx);
265 #endif
266 
267  SCFree(op_thread_data);
268  return TM_ECODE_OK;
269 }
270 
272 {
273  SC_ATOMIC_INIT(g_file_store_id);
274  SC_ATOMIC_SET(g_file_store_id, 1);
275 }
276 
278 {
279  OutputFiledataLogger *logger = list;
280  while (logger) {
281  OutputFiledataLogger *next_logger = logger->next;
282  SCFree(logger);
283  logger = next_logger;
284  }
285 
286  list = NULL;
287 }
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:200
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:246
File_::state
FileState state
Definition: util-file.h:82
OutputFiledataLogger_::LogFunc
SCFiledataLogger LogFunc
Definition: output-filedata.c:43
LoggerId
LoggerId
Definition: suricata-common.h:460
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:277
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:1803
TM_ECODE_FAILED
@ TM_ECODE_FAILED
Definition: tm-threads-common.h:81
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:80
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:300
util-profiling.h
Packet_
Definition: decode.h:473
OutputFiledataLogger_
Definition: output-filedata.c:42
conf.h
util-magic.h
TmEcode
TmEcode
Definition: tm-threads-common.h:79
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:124
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:1367
Packet_::flow
struct Flow_ * flow
Definition: decode.h:512
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:1157
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:37
OutputFiledataLogger_::ThreadInit
ThreadInitFunc ThreadInit
Definition: output-filedata.c:48
Flow_::alproto
AppProto alproto
application level protocol
Definition: flow.h:455
SCCalloc
#define SCCalloc(nm, sz)
Definition: util-mem.h:53
OutputFiledataLoggerRegister
void OutputFiledataLoggerRegister(void)
Definition: output-filedata.c:271
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