/src/suricata8/src/output-file.c
Line | Count | Source |
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 File Logger Output registration functions |
24 | | */ |
25 | | |
26 | | #include "suricata-common.h" |
27 | | #include "output.h" |
28 | | #include "output-file.h" |
29 | | #if 0 |
30 | | #include "app-layer.h" |
31 | | #endif |
32 | | #include "app-layer-parser.h" // FileApplyTxFlags |
33 | | #include "detect-filemagic.h" |
34 | | #include "util-file.h" |
35 | | #include "util-magic.h" |
36 | | #include "util-profiling.h" |
37 | | #include "util-validate.h" |
38 | | |
39 | | bool g_file_logger_enabled = false; |
40 | | |
41 | | /* logger instance, a module + a output ctx, |
42 | | * it's perfectly valid that have multiple instances of the same |
43 | | * log module (e.g. http.log) with different output ctx'. */ |
44 | | typedef struct OutputFileLogger_ { |
45 | | SCFileLogger LogFunc; |
46 | | void *initdata; |
47 | | struct OutputFileLogger_ *next; |
48 | | const char *name; |
49 | | LoggerId logger_id; |
50 | | ThreadInitFunc ThreadInit; |
51 | | ThreadDeinitFunc ThreadDeinit; |
52 | | } OutputFileLogger; |
53 | | |
54 | | static OutputFileLogger *list = NULL; |
55 | | |
56 | | int SCOutputRegisterFileLogger(LoggerId id, const char *name, SCFileLogger LogFunc, void *initdata, |
57 | | ThreadInitFunc ThreadInit, ThreadDeinitFunc ThreadDeinit) |
58 | 4 | { |
59 | 4 | OutputFileLogger *op = SCCalloc(1, sizeof(*op)); |
60 | 4 | if (op == NULL) |
61 | 0 | return -1; |
62 | | |
63 | 4 | op->LogFunc = LogFunc; |
64 | 4 | op->initdata = initdata; |
65 | 4 | op->name = name; |
66 | 4 | op->logger_id = id; |
67 | 4 | op->ThreadInit = ThreadInit; |
68 | 4 | op->ThreadDeinit = ThreadDeinit; |
69 | | |
70 | 4 | if (list == NULL) |
71 | 4 | list = op; |
72 | 0 | else { |
73 | 0 | OutputFileLogger *t = list; |
74 | 0 | while (t->next) |
75 | 0 | t = t->next; |
76 | 0 | t->next = op; |
77 | 0 | } |
78 | | |
79 | 4 | SCLogDebug("OutputRegisterFileLogger happy"); |
80 | | |
81 | 4 | g_file_logger_enabled = true; |
82 | 4 | return 0; |
83 | 4 | } |
84 | | |
85 | | static void CloseFile(const Packet *p, Flow *f, AppLayerTxData *txd, File *file) |
86 | 118k | { |
87 | 118k | DEBUG_VALIDATE_BUG_ON((file->flags & FILE_LOGGED) != 0); |
88 | 118k | DEBUG_VALIDATE_BUG_ON(f->alproto == ALPROTO_SMB && txd->files_logged != 0); |
89 | 118k | DEBUG_VALIDATE_BUG_ON(f->alproto == ALPROTO_FTPDATA && txd->files_logged != 0); |
90 | 118k | txd->files_logged++; |
91 | 118k | DEBUG_VALIDATE_BUG_ON(txd->files_logged > txd->files_opened); |
92 | 118k | file->flags |= FILE_LOGGED; |
93 | 118k | SCLogDebug("ff %p FILE_LOGGED", file); |
94 | 118k | } |
95 | | |
96 | | void OutputFileLogFfc(ThreadVars *tv, OutputFileLoggerThreadData *op_thread_data, Packet *p, |
97 | | FileContainer *ffc, void *txv, const uint64_t tx_id, AppLayerTxData *txd, |
98 | | const bool file_close, const bool file_trunc, uint8_t dir) |
99 | 808k | { |
100 | 808k | if (ffc->head == NULL) |
101 | 362k | return; |
102 | | |
103 | 445k | SCLogDebug("ffc %p ffc->head %p file_close %d file_trunc %d dir %s", ffc, |
104 | 445k | ffc ? ffc->head : NULL, file_close, file_trunc, dir == STREAM_TOSERVER ? "ts" : "tc"); |
105 | 445k | File *ff; |
106 | 897k | for (ff = ffc->head; ff != NULL; ff = ff->next) { |
107 | 451k | SCLogDebug("ff %p pre-FILE_LOGGED", ff); |
108 | 451k | if (ff->flags & FILE_LOGGED) |
109 | 332 | continue; |
110 | | |
111 | 451k | FileApplyTxFlags(txd, dir, ff); |
112 | | |
113 | 451k | SCLogDebug("ff %p state %u post-FILE_LOGGED", ff, ff->state); |
114 | | |
115 | 451k | if (file_trunc && ff->state < FILE_STATE_CLOSED) { |
116 | 0 | SCLogDebug("file_trunc %d ff->state %u => FILE_STATE_TRUNCATED", file_trunc, ff->state); |
117 | 0 | ff->state = FILE_STATE_TRUNCATED; |
118 | 0 | } |
119 | | |
120 | 451k | if (file_close && ff->state < FILE_STATE_CLOSED) { |
121 | 0 | SCLogDebug("file_close %d ff->state %u => FILE_STATE_TRUNCATED", file_close, ff->state); |
122 | 0 | ff->state = FILE_STATE_TRUNCATED; |
123 | 0 | } |
124 | | |
125 | 451k | SCLogDebug("ff %p state %u", ff, ff->state); |
126 | | |
127 | 451k | if (ff->state > FILE_STATE_OPENED) { |
128 | 118k | SCLogDebug("FILE LOGGING"); |
129 | 118k | bool file_logged = false; |
130 | | #ifdef HAVE_MAGIC |
131 | | if (FileForceMagic() && ff->magic == NULL) { |
132 | | FilemagicThreadLookup(&op_thread_data->magic_ctx, ff); |
133 | | } |
134 | | #endif |
135 | 118k | const OutputFileLogger *logger = list; |
136 | 118k | const OutputLoggerThreadStore *store = op_thread_data->store; |
137 | 236k | while (logger && store) { |
138 | 118k | DEBUG_VALIDATE_BUG_ON(logger->LogFunc == NULL); |
139 | | |
140 | 118k | SCLogDebug("logger %p", logger); |
141 | 118k | PACKET_PROFILING_LOGGER_START(p, logger->logger_id); |
142 | 118k | logger->LogFunc(tv, store->thread_data, (const Packet *)p, (const File *)ff, txv, |
143 | 118k | tx_id, dir); |
144 | 118k | PACKET_PROFILING_LOGGER_END(p, logger->logger_id); |
145 | 118k | file_logged = true; |
146 | | |
147 | 118k | logger = logger->next; |
148 | 118k | store = store->next; |
149 | | |
150 | 118k | DEBUG_VALIDATE_BUG_ON(logger == NULL && store != NULL); |
151 | 118k | DEBUG_VALIDATE_BUG_ON(logger != NULL && store == NULL); |
152 | 118k | } |
153 | | |
154 | 118k | if (file_logged) { |
155 | 118k | CloseFile(p, p->flow, txd, ff); |
156 | 118k | } |
157 | 118k | } |
158 | 451k | } |
159 | 445k | } |
160 | | |
161 | | /** \brief thread init for the file logger |
162 | | * This will run the thread init functions for the individual registered |
163 | | * loggers */ |
164 | | TmEcode OutputFileLogThreadInit(ThreadVars *tv, OutputFileLoggerThreadData **data) |
165 | 4 | { |
166 | 4 | OutputFileLoggerThreadData *td = SCCalloc(1, sizeof(*td)); |
167 | 4 | if (td == NULL) |
168 | 0 | return TM_ECODE_FAILED; |
169 | 4 | *data = td; |
170 | | |
171 | | #ifdef HAVE_MAGIC |
172 | | td->magic_ctx = MagicInitContext(); |
173 | | if (td->magic_ctx == NULL) { |
174 | | SCFree(td); |
175 | | return TM_ECODE_FAILED; |
176 | | } |
177 | | #endif |
178 | | |
179 | 4 | SCLogDebug("OutputFileLogThreadInit happy (*data %p)", *data); |
180 | | |
181 | 4 | OutputFileLogger *logger = list; |
182 | 8 | while (logger) { |
183 | 4 | if (logger->ThreadInit) { |
184 | 4 | void *retptr = NULL; |
185 | 4 | if (logger->ThreadInit(tv, logger->initdata, &retptr) == TM_ECODE_OK) { |
186 | 4 | OutputLoggerThreadStore *ts = SCCalloc(1, sizeof(*ts)); |
187 | 4 | /* todo */ BUG_ON(ts == NULL); |
188 | | |
189 | | /* store thread handle */ |
190 | 4 | ts->thread_data = retptr; |
191 | | |
192 | 4 | if (td->store == NULL) { |
193 | 4 | td->store = ts; |
194 | 4 | } else { |
195 | 0 | OutputLoggerThreadStore *tmp = td->store; |
196 | 0 | while (tmp->next != NULL) |
197 | 0 | tmp = tmp->next; |
198 | 0 | tmp->next = ts; |
199 | 0 | } |
200 | | |
201 | 4 | SCLogDebug("%s is now set up", logger->name); |
202 | 4 | } |
203 | 4 | } |
204 | | |
205 | 4 | logger = logger->next; |
206 | 4 | } |
207 | | |
208 | 4 | return TM_ECODE_OK; |
209 | 4 | } |
210 | | |
211 | | TmEcode OutputFileLogThreadDeinit(ThreadVars *tv, OutputFileLoggerThreadData *op_thread_data) |
212 | 0 | { |
213 | 0 | OutputLoggerThreadStore *store = op_thread_data->store; |
214 | 0 | OutputFileLogger *logger = list; |
215 | |
|
216 | 0 | while (logger && store) { |
217 | 0 | if (logger->ThreadDeinit) { |
218 | 0 | logger->ThreadDeinit(tv, store->thread_data); |
219 | 0 | } |
220 | |
|
221 | 0 | OutputLoggerThreadStore *next_store = store->next; |
222 | 0 | SCFree(store); |
223 | 0 | store = next_store; |
224 | 0 | logger = logger->next; |
225 | 0 | } |
226 | |
|
227 | | #ifdef HAVE_MAGIC |
228 | | MagicDeinitContext(op_thread_data->magic_ctx); |
229 | | #endif |
230 | |
|
231 | 0 | SCFree(op_thread_data); |
232 | 0 | return TM_ECODE_OK; |
233 | 0 | } |
234 | | |
235 | | void OutputFileLoggerRegister(void) |
236 | 78 | { |
237 | 78 | } |
238 | | |
239 | | void OutputFileShutdown(void) |
240 | 0 | { |
241 | 0 | OutputFileLogger *logger = list; |
242 | 0 | while (logger) { |
243 | 0 | OutputFileLogger *next_logger = logger->next; |
244 | 0 | SCFree(logger); |
245 | 0 | logger = next_logger; |
246 | 0 | } |
247 | |
|
248 | | list = NULL; |
249 | 0 | } |