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'. */
51
52static 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;
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
82SC_ATOMIC_DECLARE(unsigned int, g_file_store_id);
83
84static 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
112static void CloseFile(const Packet *p, Flow *f, File *file, void *txv)
113{
115
117 DEBUG_VALIDATE_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 {
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
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}
AppLayerTxData * AppLayerParserGetTxData(uint8_t ipproto, AppProto alproto, void *tx)
void FileApplyTxFlags(const AppLayerTxData *txd, const uint8_t direction, File *file)
Definition util-file.c:278
struct AppLayerGetFileState AppLayerGetFileState
struct AppLayerTxData AppLayerTxData
@ ALPROTO_SMB
uint8_t flags
Definition decode-gre.h:0
uint32_t id
ThreadVars * tv
bool g_filedata_logger_enabled
void OutputFiledataShutdown(void)
struct OutputFiledataLogger_ OutputFiledataLogger
TmEcode OutputFiledataLogThreadInit(ThreadVars *tv, OutputFiledataLoggerThreadData **data)
thread init for the filedata logger This will run the thread init functions for the individual regist...
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)
int SCOutputRegisterFiledataLogger(LoggerId id, const char *name, SCFiledataLogger LogFunc, void *initdata, ThreadInitFunc ThreadInit, ThreadDeinitFunc ThreadDeinit)
Register a file-data logger.
TmEcode OutputFiledataLogThreadDeinit(ThreadVars *tv, OutputFiledataLoggerThreadData *op_thread_data)
void OutputFiledataLoggerRegister(void)
#define OUTPUT_FILEDATA_FLAG_CLOSE
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.
#define OUTPUT_FILEDATA_FLAG_OPEN
uint64_t ts
StreamingBuffer * sb
Definition util-file.h:83
uint16_t flags
Definition util-file.h:80
FileState state
Definition util-file.h:82
struct File_ * next
Definition util-file.h:92
uint64_t content_stored
Definition util-file.h:101
uint32_t file_store_id
Definition util-file.h:85
Flow data structure.
Definition flow.h:356
uint8_t proto
Definition flow.h:378
AppProto alproto
application level protocol
Definition flow.h:450
OutputLoggerThreadStore * store
ThreadInitFunc ThreadInit
struct OutputFiledataLogger_ * next
SCFiledataLogger LogFunc
ThreadDeinitFunc ThreadDeinit
struct OutputLoggerThreadStore_ * next
Definition output.h:35
struct Flow_ * flow
Definition decode.h:546
Per thread variable structure.
Definition threadvars.h:58
#define BUG_ON(x)
TmEcode(* ThreadDeinitFunc)(ThreadVars *, void *)
Definition tm-modules.h:44
TmEcode(* ThreadInitFunc)(ThreadVars *, const void *, void **)
Definition tm-modules.h:43
@ TM_ECODE_FAILED
@ TM_ECODE_OK
const char * name
#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_SET(name, val)
Set the value for the atomic variable.
#define SCLogDebug(...)
Definition util-debug.h:275
uint64_t FileDataSize(const File *file)
get the size of the file data
Definition util-file.c:309
int FileCloseFilePtr(File *ff, const StreamingBufferConfig *sbcfg, const uint8_t *data, uint32_t data_len, uint16_t flags)
Definition util-file.c:980
int FileForceMagic(void)
Definition util-file.c:141
#define FilePrintFlags(file)
Definition util-file.h:250
#define FILE_TRUNCATED
Definition util-file.h:45
#define FILE_STORED
Definition util-file.h:56
@ FILE_STATE_CLOSED
Definition util-file.h:71
#define FILE_STORE
Definition util-file.h:55
#define SCFree(p)
Definition util-mem.h:61
#define SCCalloc(nm, sz)
Definition util-mem.h:53
#define PACKET_PROFILING_LOGGER_END(p, id)
#define PACKET_PROFILING_LOGGER_START(p, id)
int StreamingBufferGetDataAtOffset(const StreamingBuffer *sb, const uint8_t **data, uint32_t *data_len, uint64_t offset)
#define DEBUG_VALIDATE_BUG_ON(exp)