/src/suricata7/src/output-json-frame.c
Line | Count | Source |
1 | | /* Copyright (C) 2013-2021 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 | | * Logs frames in JSON format. |
24 | | * |
25 | | */ |
26 | | |
27 | | #include "suricata-common.h" |
28 | | #include "detect.h" |
29 | | #include "flow.h" |
30 | | #include "conf.h" |
31 | | |
32 | | #include "threads.h" |
33 | | #include "tm-threads.h" |
34 | | #include "threadvars.h" |
35 | | #include "util-debug.h" |
36 | | |
37 | | #include "util-logopenfile.h" |
38 | | #include "util-misc.h" |
39 | | #include "util-unittest.h" |
40 | | #include "util-unittest-helper.h" |
41 | | |
42 | | #include "detect-parse.h" |
43 | | #include "detect-engine.h" |
44 | | #include "detect-engine-mpm.h" |
45 | | #include "detect-reference.h" |
46 | | #include "detect-metadata.h" |
47 | | #include "app-layer-parser.h" |
48 | | #include "app-layer-frames.h" |
49 | | #include "app-layer-dnp3.h" |
50 | | #include "app-layer-htp.h" |
51 | | #include "app-layer-htp-xff.h" |
52 | | #include "app-layer-ftp.h" |
53 | | #include "util-classification-config.h" |
54 | | #include "stream-tcp.h" |
55 | | |
56 | | #include "output.h" |
57 | | #include "output-json.h" |
58 | | #include "output-json-frame.h" |
59 | | |
60 | | #include "util-byte.h" |
61 | | #include "util-privs.h" |
62 | | #include "util-print.h" |
63 | | #include "util-proto-name.h" |
64 | | #include "util-optimize.h" |
65 | | #include "util-buffer.h" |
66 | | #include "util-validate.h" |
67 | | |
68 | 71 | #define MODULE_NAME "JsonFrameLog" |
69 | | |
70 | | #define JSON_STREAM_BUFFER_SIZE 4096 |
71 | | |
72 | | typedef struct FrameJsonOutputCtx_ { |
73 | | LogFileCtx *file_ctx; |
74 | | uint16_t flags; |
75 | | uint32_t payload_buffer_size; |
76 | | OutputJsonCtx *eve_ctx; |
77 | | } FrameJsonOutputCtx; |
78 | | |
79 | | typedef struct JsonFrameLogThread_ { |
80 | | MemBuffer *payload_buffer; |
81 | | FrameJsonOutputCtx *json_output_ctx; |
82 | | OutputJsonThreadCtx *ctx; |
83 | | } JsonFrameLogThread; |
84 | | |
85 | | #if 0 // TODO see if this is useful in some way |
86 | | static inline bool NeedsAsHex(uint8_t c) |
87 | | { |
88 | | if (!isprint(c)) |
89 | | return true; |
90 | | |
91 | | switch (c) { |
92 | | case '/': |
93 | | case ';': |
94 | | case ':': |
95 | | case '\\': |
96 | | case ' ': |
97 | | case '|': |
98 | | case '"': |
99 | | case '`': |
100 | | case '\'': |
101 | | return true; |
102 | | } |
103 | | return false; |
104 | | } |
105 | | |
106 | | static void PayloadAsHex(const uint8_t *data, uint32_t data_len, char *str, size_t str_len) |
107 | | { |
108 | | bool hex = false; |
109 | | for (uint32_t i = 0; i < data_len; i++) { |
110 | | if (NeedsAsHex(data[i])) { |
111 | | char hex_str[4]; |
112 | | snprintf(hex_str, sizeof(hex_str), "%s%02X", !hex ? "|" : " ", data[i]); |
113 | | strlcat(str, hex_str, str_len); |
114 | | hex = true; |
115 | | } else { |
116 | | char p_str[3]; |
117 | | snprintf(p_str, sizeof(p_str), "%s%c", hex ? "|" : "", data[i]); |
118 | | strlcat(str, p_str, str_len); |
119 | | hex = false; |
120 | | } |
121 | | } |
122 | | if (hex) { |
123 | | strlcat(str, "|", str_len); |
124 | | } |
125 | | } |
126 | | #endif |
127 | | |
128 | | struct FrameJsonStreamDataCallbackData { |
129 | | MemBuffer *payload; |
130 | | const Frame *frame; |
131 | | uint64_t last_re; /**< used to detect gaps */ |
132 | | }; |
133 | | |
134 | | static int FrameJsonStreamDataCallback( |
135 | | void *cb_data, const uint8_t *input, const uint32_t input_len, const uint64_t input_offset) |
136 | 46.8k | { |
137 | 46.8k | struct FrameJsonStreamDataCallbackData *cbd = cb_data; |
138 | 46.8k | const Frame *frame = cbd->frame; |
139 | | |
140 | 46.8k | uint32_t write_size = input_len; |
141 | 46.8k | int done = 0; |
142 | | |
143 | 46.8k | if (frame->len >= 0) { |
144 | 34.8k | const uint64_t data_re = input_offset + input_len; |
145 | 34.8k | const uint64_t frame_re = frame->offset + (uint64_t)frame->len; |
146 | | |
147 | | /* data entirely after frame, we're done */ |
148 | 34.8k | if (input_offset >= frame_re) { |
149 | 27 | return 1; |
150 | 27 | } |
151 | | /* make sure to only log data belonging to the frame */ |
152 | 34.7k | if (data_re >= frame_re) { |
153 | 21.5k | const uint64_t to_write = frame_re - input_offset; |
154 | 21.5k | if (to_write < (uint64_t)write_size) { |
155 | 1.84k | write_size = (uint32_t)to_write; |
156 | 1.84k | } |
157 | 21.5k | done = 1; |
158 | 21.5k | } |
159 | 34.7k | } |
160 | 46.8k | if (input_offset > cbd->last_re) { |
161 | 205 | MemBufferWriteString( |
162 | 205 | cbd->payload, "[%" PRIu64 " bytes missing]", input_offset - cbd->last_re); |
163 | 205 | } |
164 | | |
165 | 46.8k | if (write_size > 0) { |
166 | 46.8k | uint32_t written = MemBufferWriteRaw(cbd->payload, input, write_size); |
167 | 46.8k | if (written < write_size) |
168 | 6.49k | done = 1; |
169 | 46.8k | } |
170 | 46.8k | cbd->last_re = input_offset + write_size; |
171 | 46.8k | return done; |
172 | 46.8k | } |
173 | | |
174 | | /** \internal |
175 | | * \brief try to log frame's stream data into payload/payload_printable |
176 | | */ |
177 | | static void FrameAddPayloadTCP(Flow *f, const TcpSession *ssn, const TcpStream *stream, |
178 | | const Frame *frame, JsonBuilder *jb, MemBuffer *buffer) |
179 | 47.5k | { |
180 | 47.5k | MemBufferReset(buffer); |
181 | | |
182 | | /* consider all data, ACK'd and non-ACK'd */ |
183 | 47.5k | const uint64_t stream_data_re = StreamDataRightEdge(stream, true); |
184 | 47.5k | bool complete = false; |
185 | 47.5k | if (frame->len >= 0 && frame->offset + (uint64_t)frame->len <= stream_data_re) { |
186 | 21.5k | complete = true; |
187 | 21.5k | } |
188 | | |
189 | 47.5k | struct FrameJsonStreamDataCallbackData cbd = { |
190 | 47.5k | .payload = buffer, .frame = frame, .last_re = frame->offset |
191 | 47.5k | }; |
192 | 47.5k | uint64_t unused = 0; |
193 | 47.5k | StreamReassembleLog( |
194 | 47.5k | ssn, stream, FrameJsonStreamDataCallback, &cbd, frame->offset, &unused, false); |
195 | | /* if we have all data, but didn't log until the end of the frame, we have a gap at the |
196 | | * end of the frame |
197 | | * TODO what about not logging due to buffer full? */ |
198 | 47.5k | if (complete && frame->len >= 0 && cbd.last_re < frame->offset + (uint64_t)frame->len) { |
199 | 65 | MemBufferWriteString(cbd.payload, "[%" PRIu64 " bytes missing]", |
200 | 65 | (frame->offset + (uint64_t)frame->len) - cbd.last_re); |
201 | 65 | } |
202 | | |
203 | 47.5k | if (cbd.payload->offset) { |
204 | 46.8k | jb_set_base64(jb, "payload", cbd.payload->buffer, cbd.payload->offset); |
205 | 46.8k | SCJbSetPrintAsciiString(jb, "payload_printable", cbd.payload->buffer, cbd.payload->offset); |
206 | 46.8k | jb_set_bool(jb, "complete", complete); |
207 | 46.8k | } |
208 | 47.5k | } |
209 | | |
210 | | static void FrameAddPayloadUDP(JsonBuilder *js, const Packet *p, const Frame *frame) |
211 | 221 | { |
212 | 221 | DEBUG_VALIDATE_BUG_ON(frame->offset >= p->payload_len); |
213 | 221 | if (frame->offset >= p->payload_len) |
214 | 0 | return; |
215 | | |
216 | 221 | uint32_t frame_len; |
217 | 221 | if (frame->len == -1) { |
218 | 0 | frame_len = p->payload_len - frame->offset; |
219 | 221 | } else { |
220 | 221 | frame_len = (uint32_t)frame->len; |
221 | 221 | } |
222 | 221 | if (frame->offset + frame_len > p->payload_len) { |
223 | 0 | frame_len = p->payload_len - frame->offset; |
224 | 0 | JB_SET_FALSE(js, "complete"); |
225 | 221 | } else { |
226 | 221 | JB_SET_TRUE(js, "complete"); |
227 | 221 | } |
228 | 221 | const uint8_t *data = p->payload + frame->offset; |
229 | 221 | const uint32_t data_len = frame_len; |
230 | | |
231 | 221 | const uint32_t log_data_len = MIN(data_len, 256); |
232 | 221 | jb_set_base64(js, "payload", data, log_data_len); |
233 | | |
234 | 221 | SCJbSetPrintAsciiString(js, "payload_printable", data, log_data_len); |
235 | | #if 0 |
236 | | char pretty_buf[data_len * 4 + 1]; |
237 | | pretty_buf[0] = '\0'; |
238 | | PayloadAsHex(data, data_len, pretty_buf, data_len * 4 + 1); |
239 | | jb_set_string(js, "payload_hex", pretty_buf); |
240 | | #endif |
241 | 221 | } |
242 | | |
243 | | // TODO separate between stream_offset and frame_offset |
244 | | /** \brief log a single frame |
245 | | * \note ipproto argument is passed to assist static code analyzers |
246 | | */ |
247 | | void FrameJsonLogOneFrame(const uint8_t ipproto, const Frame *frame, Flow *f, |
248 | | const TcpStream *stream, const Packet *p, JsonBuilder *jb, MemBuffer *buffer) |
249 | 47.8k | { |
250 | 47.8k | DEBUG_VALIDATE_BUG_ON(ipproto != p->proto); |
251 | 47.8k | DEBUG_VALIDATE_BUG_ON(ipproto != f->proto); |
252 | | |
253 | 47.8k | jb_open_object(jb, "frame"); |
254 | 47.8k | if (frame->type == FRAME_STREAM_TYPE) { |
255 | 6 | jb_set_string(jb, "type", "stream"); |
256 | 47.8k | } else { |
257 | 47.8k | jb_set_string(jb, "type", AppLayerParserGetFrameNameById(ipproto, f->alproto, frame->type)); |
258 | 47.8k | } |
259 | 47.8k | jb_set_uint(jb, "id", frame->id); |
260 | 47.8k | jb_set_string(jb, "direction", PKT_IS_TOSERVER(p) ? "toserver" : "toclient"); |
261 | | |
262 | 47.8k | if (ipproto == IPPROTO_TCP) { |
263 | 47.5k | DEBUG_VALIDATE_BUG_ON(stream == NULL); |
264 | 47.5k | jb_set_uint(jb, "stream_offset", frame->offset); |
265 | | |
266 | 47.5k | if (frame->len < 0) { |
267 | 12.7k | uint64_t usable = StreamTcpGetUsable(stream, true); |
268 | 12.7k | uint64_t len = usable - frame->offset; |
269 | 12.7k | jb_set_uint(jb, "length", len); |
270 | 34.7k | } else { |
271 | 34.7k | jb_set_uint(jb, "length", frame->len); |
272 | 34.7k | } |
273 | 47.5k | FrameAddPayloadTCP(f, f->protoctx, stream, frame, jb, buffer); |
274 | 47.5k | } else { |
275 | 221 | jb_set_uint(jb, "length", frame->len); |
276 | 221 | FrameAddPayloadUDP(jb, p, frame); |
277 | 221 | } |
278 | 47.8k | if (frame->flags & FRAME_FLAG_TX_ID_SET) { |
279 | 46.3k | jb_set_uint(jb, "tx_id", frame->tx_id); |
280 | 46.3k | } |
281 | 47.8k | jb_close(jb); |
282 | 47.8k | } |
283 | | |
284 | | static int FrameJsonUdp( |
285 | | JsonFrameLogThread *aft, const Packet *p, Flow *f, FramesContainer *frames_container) |
286 | 0 | { |
287 | 0 | FrameJsonOutputCtx *json_output_ctx = aft->json_output_ctx; |
288 | |
|
289 | 0 | Frames *frames; |
290 | 0 | if (PKT_IS_TOSERVER(p)) { |
291 | 0 | frames = &frames_container->toserver; |
292 | 0 | } else { |
293 | 0 | frames = &frames_container->toclient; |
294 | 0 | } |
295 | |
|
296 | 0 | for (uint32_t idx = 0; idx < frames->cnt; idx++) { |
297 | 0 | Frame *frame = FrameGetByIndex(frames, idx); |
298 | 0 | if (frame == NULL || frame->flags & FRAME_FLAG_LOGGED) |
299 | 0 | continue; |
300 | | |
301 | | /* First initialize the address info (5-tuple). */ |
302 | 0 | JsonAddrInfo addr = json_addr_info_zero; |
303 | 0 | JsonAddrInfoInit(p, LOG_DIR_PACKET, &addr); |
304 | |
|
305 | 0 | JsonBuilder *jb = |
306 | 0 | CreateEveHeader(p, LOG_DIR_PACKET, "frame", &addr, json_output_ctx->eve_ctx); |
307 | 0 | if (unlikely(jb == NULL)) |
308 | 0 | return TM_ECODE_OK; |
309 | | |
310 | 0 | jb_set_string(jb, "app_proto", AppProtoToString(f->alproto)); |
311 | 0 | FrameJsonLogOneFrame(IPPROTO_UDP, frame, p->flow, NULL, p, jb, aft->payload_buffer); |
312 | 0 | OutputJsonBuilderBuffer(jb, aft->ctx); |
313 | 0 | jb_free(jb); |
314 | 0 | frame->flags |= FRAME_FLAG_LOGGED; |
315 | 0 | } |
316 | 0 | return TM_ECODE_OK; |
317 | 0 | } |
318 | | |
319 | | static int FrameJson(ThreadVars *tv, JsonFrameLogThread *aft, const Packet *p) |
320 | 0 | { |
321 | 0 | FrameJsonOutputCtx *json_output_ctx = aft->json_output_ctx; |
322 | |
|
323 | 0 | BUG_ON(p->flow == NULL); |
324 | | |
325 | 0 | FramesContainer *frames_container = AppLayerFramesGetContainer(p->flow); |
326 | 0 | if (frames_container == NULL) |
327 | 0 | return TM_ECODE_OK; |
328 | | |
329 | 0 | if (p->proto == IPPROTO_UDP) { |
330 | 0 | return FrameJsonUdp(aft, p, p->flow, frames_container); |
331 | 0 | } |
332 | | |
333 | 0 | BUG_ON(p->proto != IPPROTO_TCP); |
334 | 0 | BUG_ON(p->flow->protoctx == NULL); |
335 | | |
336 | | /* TODO can we set these EOF flags once per packet? We have them in detect, tx, file, filedata, |
337 | | * etc */ |
338 | 0 | const bool last_pseudo = (p->flowflags & FLOW_PKT_LAST_PSEUDO) != 0; |
339 | 0 | Frames *frames; |
340 | 0 | TcpSession *ssn = p->flow->protoctx; |
341 | 0 | bool eof = (ssn->flags & STREAMTCP_FLAG_APP_LAYER_DISABLED); |
342 | 0 | TcpStream *stream; |
343 | 0 | if (PKT_IS_TOSERVER(p)) { |
344 | 0 | stream = &ssn->client; |
345 | 0 | frames = &frames_container->toserver; |
346 | 0 | SCLogDebug("TOSERVER base %" PRIu64 ", app %" PRIu64, STREAM_BASE_OFFSET(stream), |
347 | 0 | STREAM_APP_PROGRESS(stream)); |
348 | 0 | eof |= AppLayerParserStateIssetFlag(p->flow->alparser, APP_LAYER_PARSER_EOF_TS) != 0; |
349 | 0 | } else { |
350 | 0 | stream = &ssn->server; |
351 | 0 | frames = &frames_container->toclient; |
352 | 0 | eof |= AppLayerParserStateIssetFlag(p->flow->alparser, APP_LAYER_PARSER_EOF_TC) != 0; |
353 | 0 | } |
354 | 0 | eof |= last_pseudo; |
355 | 0 | SCLogDebug("eof %s", eof ? "true" : "false"); |
356 | |
|
357 | 0 | for (uint32_t idx = 0; idx < frames->cnt; idx++) { |
358 | 0 | Frame *frame = FrameGetByIndex(frames, idx); |
359 | 0 | if (frame != NULL) { |
360 | 0 | if (frame->flags & FRAME_FLAG_LOGGED) |
361 | 0 | continue; |
362 | | |
363 | 0 | int64_t abs_offset = (int64_t)frame->offset + (int64_t)STREAM_BASE_OFFSET(stream); |
364 | 0 | int64_t win = STREAM_APP_PROGRESS(stream) - abs_offset; |
365 | |
|
366 | 0 | if (!eof && win < frame->len && win < 2500) { |
367 | 0 | SCLogDebug("frame id %" PRIi64 " len %" PRIi64 ", win %" PRIi64 |
368 | 0 | ", skipping logging", |
369 | 0 | frame->id, frame->len, win); |
370 | 0 | continue; |
371 | 0 | } |
372 | | |
373 | | /* First initialize the address info (5-tuple). */ |
374 | 0 | JsonAddrInfo addr = json_addr_info_zero; |
375 | 0 | JsonAddrInfoInit(p, LOG_DIR_PACKET, &addr); |
376 | |
|
377 | 0 | JsonBuilder *jb = |
378 | 0 | CreateEveHeader(p, LOG_DIR_PACKET, "frame", &addr, json_output_ctx->eve_ctx); |
379 | 0 | if (unlikely(jb == NULL)) |
380 | 0 | return TM_ECODE_OK; |
381 | | |
382 | 0 | jb_set_string(jb, "app_proto", AppProtoToString(p->flow->alproto)); |
383 | 0 | FrameJsonLogOneFrame(IPPROTO_TCP, frame, p->flow, stream, p, jb, aft->payload_buffer); |
384 | 0 | OutputJsonBuilderBuffer(jb, aft->ctx); |
385 | 0 | jb_free(jb); |
386 | 0 | frame->flags |= FRAME_FLAG_LOGGED; |
387 | 0 | } else if (frame != NULL) { |
388 | 0 | SCLogDebug("frame %p id %" PRIi64, frame, frame->id); |
389 | 0 | } |
390 | 0 | } |
391 | 0 | return TM_ECODE_OK; |
392 | 0 | } |
393 | | |
394 | | static int JsonFrameLogger(ThreadVars *tv, void *thread_data, const Packet *p) |
395 | 0 | { |
396 | 0 | JsonFrameLogThread *aft = thread_data; |
397 | 0 | return FrameJson(tv, aft, p); |
398 | 0 | } |
399 | | |
400 | | static int JsonFrameLogCondition(ThreadVars *tv, void *thread_data, const Packet *p) |
401 | 0 | { |
402 | 0 | if (p->flow == NULL || p->flow->alproto == ALPROTO_UNKNOWN) |
403 | 0 | return FALSE; |
404 | | |
405 | 0 | if ((p->proto == IPPROTO_TCP || p->proto == IPPROTO_UDP) && p->flow->alparser != NULL) { |
406 | 0 | FramesContainer *frames_container = AppLayerFramesGetContainer(p->flow); |
407 | 0 | if (frames_container == NULL) |
408 | 0 | return FALSE; |
409 | | |
410 | 0 | Frames *frames; |
411 | 0 | if (PKT_IS_TOSERVER(p)) { |
412 | 0 | frames = &frames_container->toserver; |
413 | 0 | } else { |
414 | 0 | frames = &frames_container->toclient; |
415 | 0 | } |
416 | 0 | return (frames->cnt != 0); |
417 | 0 | } |
418 | 0 | return FALSE; |
419 | 0 | } |
420 | | |
421 | | static TmEcode JsonFrameLogThreadInit(ThreadVars *t, const void *initdata, void **data) |
422 | 0 | { |
423 | 0 | JsonFrameLogThread *aft = SCCalloc(1, sizeof(JsonFrameLogThread)); |
424 | 0 | if (unlikely(aft == NULL)) |
425 | 0 | return TM_ECODE_FAILED; |
426 | | |
427 | 0 | if (initdata == NULL) { |
428 | 0 | SCLogDebug("Error getting context for EveLogFrame. \"initdata\" argument NULL"); |
429 | 0 | goto error_exit; |
430 | 0 | } |
431 | | |
432 | | /** Use the Output Context (file pointer and mutex) */ |
433 | 0 | FrameJsonOutputCtx *json_output_ctx = ((OutputCtx *)initdata)->data; |
434 | |
|
435 | 0 | aft->payload_buffer = MemBufferCreateNew(json_output_ctx->payload_buffer_size); |
436 | 0 | if (aft->payload_buffer == NULL) { |
437 | 0 | goto error_exit; |
438 | 0 | } |
439 | 0 | aft->ctx = CreateEveThreadCtx(t, json_output_ctx->eve_ctx); |
440 | 0 | if (!aft->ctx) { |
441 | 0 | goto error_exit; |
442 | 0 | } |
443 | | |
444 | 0 | aft->json_output_ctx = json_output_ctx; |
445 | |
|
446 | 0 | *data = (void *)aft; |
447 | 0 | return TM_ECODE_OK; |
448 | | |
449 | 0 | error_exit: |
450 | 0 | if (aft->payload_buffer != NULL) { |
451 | 0 | MemBufferFree(aft->payload_buffer); |
452 | 0 | } |
453 | 0 | SCFree(aft); |
454 | 0 | return TM_ECODE_FAILED; |
455 | 0 | } |
456 | | |
457 | | static TmEcode JsonFrameLogThreadDeinit(ThreadVars *t, void *data) |
458 | 0 | { |
459 | 0 | JsonFrameLogThread *aft = (JsonFrameLogThread *)data; |
460 | 0 | if (aft == NULL) { |
461 | 0 | return TM_ECODE_OK; |
462 | 0 | } |
463 | | |
464 | 0 | MemBufferFree(aft->payload_buffer); |
465 | 0 | FreeEveThreadCtx(aft->ctx); |
466 | | |
467 | | /* clear memory */ |
468 | 0 | memset(aft, 0, sizeof(JsonFrameLogThread)); |
469 | |
|
470 | 0 | SCFree(aft); |
471 | 0 | return TM_ECODE_OK; |
472 | 0 | } |
473 | | |
474 | | static void JsonFrameLogDeInitCtxSub(OutputCtx *output_ctx) |
475 | 0 | { |
476 | 0 | SCLogDebug("cleaning up sub output_ctx %p", output_ctx); |
477 | |
|
478 | 0 | FrameJsonOutputCtx *json_output_ctx = (FrameJsonOutputCtx *)output_ctx->data; |
479 | |
|
480 | 0 | if (json_output_ctx != NULL) { |
481 | 0 | SCFree(json_output_ctx); |
482 | 0 | } |
483 | 0 | SCFree(output_ctx); |
484 | 0 | } |
485 | | |
486 | | /** |
487 | | * \brief Create a new LogFileCtx for "fast" output style. |
488 | | * \param conf The configuration node for this output. |
489 | | * \return A LogFileCtx pointer on success, NULL on failure. |
490 | | */ |
491 | | static OutputInitResult JsonFrameLogInitCtxSub(ConfNode *conf, OutputCtx *parent_ctx) |
492 | 0 | { |
493 | 0 | OutputInitResult result = { NULL, false }; |
494 | 0 | OutputJsonCtx *ajt = parent_ctx->data; |
495 | 0 | FrameJsonOutputCtx *json_output_ctx = NULL; |
496 | |
|
497 | 0 | OutputCtx *output_ctx = SCCalloc(1, sizeof(OutputCtx)); |
498 | 0 | if (unlikely(output_ctx == NULL)) |
499 | 0 | return result; |
500 | | |
501 | 0 | json_output_ctx = SCMalloc(sizeof(FrameJsonOutputCtx)); |
502 | 0 | if (unlikely(json_output_ctx == NULL)) { |
503 | 0 | goto error; |
504 | 0 | } |
505 | 0 | memset(json_output_ctx, 0, sizeof(FrameJsonOutputCtx)); |
506 | |
|
507 | 0 | uint32_t payload_buffer_size = 4096; |
508 | 0 | if (conf != NULL) { |
509 | 0 | const char *payload_buffer_value = ConfNodeLookupChildValue(conf, "payload-buffer-size"); |
510 | 0 | if (payload_buffer_value != NULL) { |
511 | 0 | uint32_t value; |
512 | 0 | if (ParseSizeStringU32(payload_buffer_value, &value) < 0) { |
513 | 0 | SCLogError("Error parsing payload-buffer-size \"%s\"", payload_buffer_value); |
514 | 0 | goto error; |
515 | 0 | } |
516 | 0 | payload_buffer_size = value; |
517 | 0 | } |
518 | 0 | } |
519 | | |
520 | 0 | json_output_ctx->file_ctx = ajt->file_ctx; |
521 | 0 | json_output_ctx->eve_ctx = ajt; |
522 | 0 | json_output_ctx->payload_buffer_size = payload_buffer_size; |
523 | |
|
524 | 0 | output_ctx->data = json_output_ctx; |
525 | 0 | output_ctx->DeInit = JsonFrameLogDeInitCtxSub; |
526 | |
|
527 | 0 | FrameConfigEnableAll(); |
528 | |
|
529 | 0 | result.ctx = output_ctx; |
530 | 0 | result.ok = true; |
531 | 0 | return result; |
532 | | |
533 | 0 | error: |
534 | 0 | if (json_output_ctx != NULL) { |
535 | 0 | SCFree(json_output_ctx); |
536 | 0 | } |
537 | 0 | if (output_ctx != NULL) { |
538 | 0 | SCFree(output_ctx); |
539 | 0 | } |
540 | |
|
541 | 0 | return result; |
542 | 0 | } |
543 | | |
544 | | void JsonFrameLogRegister(void) |
545 | 71 | { |
546 | 71 | OutputRegisterPacketSubModule(LOGGER_JSON_FRAME, "eve-log", MODULE_NAME, "eve-log.frame", |
547 | 71 | JsonFrameLogInitCtxSub, JsonFrameLogger, JsonFrameLogCondition, JsonFrameLogThreadInit, |
548 | | JsonFrameLogThreadDeinit, NULL); |
549 | 71 | } |