Coverage Report

Created: 2026-05-16 07:38

next uncovered line (L), next uncovered region (R), next uncovered branch (B)
/src/suricata7/src/output-json-flow.c
Line
Count
Source
1
/* Copyright (C) 2007-2025 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
 * Implements Flow JSON logging portion of the engine.
24
 */
25
26
#include "suricata-common.h"
27
#include "detect.h"
28
#include "pkt-var.h"
29
#include "conf.h"
30
31
#include "threads.h"
32
#include "threadvars.h"
33
#include "tm-threads.h"
34
35
#include "util-print.h"
36
#include "util-unittest.h"
37
38
#include "util-debug.h"
39
40
#include "output.h"
41
#include "util-privs.h"
42
#include "util-buffer.h"
43
#include "util-device.h"
44
#include "util-proto-name.h"
45
#include "util-logopenfile.h"
46
#include "util-time.h"
47
#include "output-json.h"
48
#include "output-json-flow.h"
49
50
#include "stream-tcp.h"
51
#include "stream-tcp-private.h"
52
#include "flow-storage.h"
53
#include "util-exception-policy.h"
54
55
typedef struct LogFlowCtx_ {
56
    bool log_exception_policies;
57
    OutputJsonCtx *eve_ctx;
58
} LogFlowCtx;
59
60
typedef struct LogFlowLogThread_ {
61
    LogFlowCtx *flowlog_ctx;
62
    OutputJsonThreadCtx *output_ctx;
63
} LogFlowLogThread;
64
65
static void OutputFlowLogDeInitCtxSub(OutputCtx *output_ctx)
66
0
{
67
0
    LogFlowCtx *flow_ctx = output_ctx->data;
68
0
    SCFree(flow_ctx);
69
0
    SCFree(output_ctx);
70
0
}
71
72
static void JsonFlowLogParseConfig(ConfNode *conf, LogFlowCtx *flow_ctx)
73
2
{
74
    /* by default, don't log exception policies */
75
2
    flow_ctx->log_exception_policies = false;
76
77
2
    if (conf != NULL) {
78
0
        if (ConfNodeChildValueIsTrue(conf, "exception-policy")) {
79
0
            flow_ctx->log_exception_policies = true;
80
0
        }
81
0
    }
82
2
    SCLogDebug("Exception policy logging for flow %s",
83
2
            flow_ctx->log_exception_policies ? "enabled" : "disabled");
84
2
}
85
86
static OutputInitResult OutputFlowLogInitSub(ConfNode *conf, OutputCtx *parent_ctx)
87
2
{
88
2
    OutputInitResult result = { NULL, false };
89
2
    OutputJsonCtx *ojc = parent_ctx->data;
90
91
2
    LogFlowCtx *flow_ctx = SCCalloc(1, sizeof(LogFlowCtx));
92
2
    if (unlikely(flow_ctx == NULL)) {
93
0
        return result;
94
0
    }
95
96
2
    OutputCtx *output_ctx = SCCalloc(1, sizeof(OutputCtx));
97
2
    if (unlikely(output_ctx == NULL)) {
98
0
        SCFree(flow_ctx);
99
0
        return result;
100
0
    }
101
102
2
    flow_ctx->eve_ctx = ojc;
103
104
2
    output_ctx->data = flow_ctx;
105
2
    output_ctx->DeInit = OutputFlowLogDeInitCtxSub;
106
2
    JsonFlowLogParseConfig(conf, flow_ctx);
107
108
2
    result.ctx = output_ctx;
109
2
    result.ok = true;
110
111
2
    return result;
112
2
}
113
114
static TmEcode JsonFlowLogThreadInit(ThreadVars *tv, const void *initdata, void **data)
115
6
{
116
6
    LogFlowLogThread *thread = SCCalloc(1, sizeof(LogFlowLogThread));
117
6
    if (unlikely(thread == NULL)) {
118
0
        return TM_ECODE_FAILED;
119
0
    }
120
121
6
    if (initdata == NULL) {
122
0
        SCLogDebug("Error getting context for EveLogFlow. \"initdata\" argument NULL");
123
0
        goto error_exit;
124
0
    }
125
126
6
    thread->flowlog_ctx = ((OutputCtx *)initdata)->data;
127
6
    thread->output_ctx = CreateEveThreadCtx(tv, thread->flowlog_ctx->eve_ctx);
128
6
    if (!thread->output_ctx) {
129
0
        goto error_exit;
130
0
    }
131
132
6
    *data = (void *)thread;
133
6
    return TM_ECODE_OK;
134
135
0
error_exit:
136
0
    SCFree(thread);
137
0
    return TM_ECODE_FAILED;
138
6
}
139
140
static TmEcode JsonFlowLogThreadDeInit(ThreadVars *tv, void *data)
141
0
{
142
0
    LogFlowLogThread *thread = (LogFlowLogThread *)data;
143
0
    if (thread == NULL) {
144
0
        return TM_ECODE_FAILED;
145
0
    }
146
147
0
    FreeEveThreadCtx(thread->output_ctx);
148
0
    SCFree(thread);
149
0
    return TM_ECODE_OK;
150
0
}
151
152
static JsonBuilder *CreateEveHeaderFromFlow(const Flow *f)
153
102k
{
154
102k
    char timebuf[64];
155
102k
    char srcip[46] = {0}, dstip[46] = {0};
156
102k
    Port sp, dp;
157
158
102k
    JsonBuilder *jb = jb_new_object();
159
102k
    if (unlikely(jb == NULL)) {
160
0
        return NULL;
161
0
    }
162
163
102k
    SCTime_t ts = TimeGet();
164
165
102k
    CreateIsoTimeString(ts, timebuf, sizeof(timebuf));
166
167
102k
    if ((f->flags & FLOW_DIR_REVERSED) == 0) {
168
51.7k
        if (FLOW_IS_IPV4(f)) {
169
47.5k
            PrintInet(AF_INET, (const void *)&(f->src.addr_data32[0]), srcip, sizeof(srcip));
170
47.5k
            PrintInet(AF_INET, (const void *)&(f->dst.addr_data32[0]), dstip, sizeof(dstip));
171
47.5k
        } else if (FLOW_IS_IPV6(f)) {
172
4.21k
            PrintInet(AF_INET6, (const void *)&(f->src.address), srcip, sizeof(srcip));
173
4.21k
            PrintInet(AF_INET6, (const void *)&(f->dst.address), dstip, sizeof(dstip));
174
4.21k
        }
175
51.7k
        sp = f->sp;
176
51.7k
        dp = f->dp;
177
51.7k
    } else {
178
50.2k
        if (FLOW_IS_IPV4(f)) {
179
48.4k
            PrintInet(AF_INET, (const void *)&(f->dst.addr_data32[0]), srcip, sizeof(srcip));
180
48.4k
            PrintInet(AF_INET, (const void *)&(f->src.addr_data32[0]), dstip, sizeof(dstip));
181
48.4k
        } else if (FLOW_IS_IPV6(f)) {
182
1.82k
            PrintInet(AF_INET6, (const void *)&(f->dst.address), srcip, sizeof(srcip));
183
1.82k
            PrintInet(AF_INET6, (const void *)&(f->src.address), dstip, sizeof(dstip));
184
1.82k
        }
185
50.2k
        sp = f->dp;
186
50.2k
        dp = f->sp;
187
50.2k
    }
188
189
    /* time */
190
102k
    jb_set_string(jb, "timestamp", timebuf);
191
192
102k
    CreateEveFlowId(jb, (const Flow *)f);
193
194
#if 0 // TODO
195
    /* sensor id */
196
    if (sensor_id >= 0)
197
        json_object_set_new(js, "sensor_id", json_integer(sensor_id));
198
#endif
199
200
    /* input interface */
201
102k
    if (f->livedev) {
202
0
        jb_set_string(jb, "in_iface", f->livedev->dev);
203
0
    }
204
205
102k
    JB_SET_STRING(jb, "event_type", "flow");
206
207
    /* vlan */
208
102k
    if (f->vlan_idx > 0) {
209
1.38k
        jb_open_array(jb, "vlan");
210
1.38k
        jb_append_uint(jb, f->vlan_id[0]);
211
1.38k
        if (f->vlan_idx > 1) {
212
12
            jb_append_uint(jb, f->vlan_id[1]);
213
12
        }
214
1.38k
        if (f->vlan_idx > 2) {
215
0
            jb_append_uint(jb, f->vlan_id[2]);
216
0
        }
217
1.38k
        jb_close(jb);
218
1.38k
    }
219
220
    /* tuple */
221
102k
    jb_set_string(jb, "src_ip", srcip);
222
102k
    switch(f->proto) {
223
483
        case IPPROTO_ICMP:
224
483
            break;
225
1.40k
        case IPPROTO_UDP:
226
99.6k
        case IPPROTO_TCP:
227
99.6k
        case IPPROTO_SCTP:
228
99.6k
            jb_set_uint(jb, "src_port", sp);
229
99.6k
            break;
230
102k
    }
231
102k
    jb_set_string(jb, "dest_ip", dstip);
232
102k
    switch(f->proto) {
233
483
        case IPPROTO_ICMP:
234
483
            break;
235
1.40k
        case IPPROTO_UDP:
236
99.6k
        case IPPROTO_TCP:
237
99.6k
        case IPPROTO_SCTP:
238
99.6k
            jb_set_uint(jb, "dest_port", dp);
239
99.6k
            break;
240
102k
    }
241
242
102k
    if (SCProtoNameValid(f->proto)) {
243
102k
        jb_set_string(jb, "proto", known_proto[f->proto]);
244
102k
    } else {
245
0
        char proto[4];
246
0
        snprintf(proto, sizeof(proto), "%"PRIu8"", f->proto);
247
0
        jb_set_string(jb, "proto", proto);
248
0
    }
249
250
102k
    switch (f->proto) {
251
483
        case IPPROTO_ICMP:
252
836
        case IPPROTO_ICMPV6:
253
836
            jb_set_uint(jb, "icmp_type", f->icmp_s.type);
254
836
            jb_set_uint(jb, "icmp_code", f->icmp_s.code);
255
836
            if (f->tosrcpktcnt) {
256
9
                jb_set_uint(jb, "response_icmp_type", f->icmp_d.type);
257
9
                jb_set_uint(jb, "response_icmp_code", f->icmp_d.code);
258
9
            }
259
836
            break;
260
1.53k
        case IPPROTO_ESP:
261
1.53k
            jb_set_uint(jb, "spi", f->esp.spi);
262
1.53k
            break;
263
102k
    }
264
102k
    return jb;
265
102k
}
266
267
void EveAddAppProto(Flow *f, JsonBuilder *js)
268
965k
{
269
965k
    if (f->alproto) {
270
660k
        jb_set_string(js, "app_proto", AppProtoToString(f->alproto));
271
660k
    }
272
965k
    if (f->alproto_ts && f->alproto_ts != f->alproto) {
273
65.9k
        jb_set_string(js, "app_proto_ts", AppProtoToString(f->alproto_ts));
274
65.9k
    }
275
965k
    if (f->alproto_tc && f->alproto_tc != f->alproto) {
276
119k
        jb_set_string(js, "app_proto_tc", AppProtoToString(f->alproto_tc));
277
119k
    }
278
965k
    if (f->alproto_orig != f->alproto && f->alproto_orig != ALPROTO_UNKNOWN) {
279
7.16k
        jb_set_string(js, "app_proto_orig", AppProtoToString(f->alproto_orig));
280
7.16k
    }
281
965k
    if (f->alproto_expect != f->alproto && f->alproto_expect != ALPROTO_UNKNOWN) {
282
16.7k
        jb_set_string(js, "app_proto_expected",
283
16.7k
                AppProtoToString(f->alproto_expect));
284
16.7k
    }
285
286
965k
}
287
288
void EveAddFlow(Flow *f, JsonBuilder *js)
289
965k
{
290
965k
    FlowBypassInfo *fc = FlowGetStorageById(f, GetFlowBypassInfoID());
291
965k
    if (fc) {
292
0
        jb_set_uint(js, "pkts_toserver", f->todstpktcnt + fc->todstpktcnt);
293
0
        jb_set_uint(js, "pkts_toclient", f->tosrcpktcnt + fc->tosrcpktcnt);
294
0
        jb_set_uint(js, "bytes_toserver", f->todstbytecnt + fc->todstbytecnt);
295
0
        jb_set_uint(js, "bytes_toclient", f->tosrcbytecnt + fc->tosrcbytecnt);
296
297
0
        jb_open_object(js, "bypassed");
298
0
        jb_set_uint(js, "pkts_toserver", fc->todstpktcnt);
299
0
        jb_set_uint(js, "pkts_toclient", fc->tosrcpktcnt);
300
0
        jb_set_uint(js, "bytes_toserver", fc->todstbytecnt);
301
0
        jb_set_uint(js, "bytes_toclient", fc->tosrcbytecnt);
302
0
        jb_close(js);
303
965k
    } else {
304
965k
        jb_set_uint(js, "pkts_toserver", f->todstpktcnt);
305
965k
        jb_set_uint(js, "pkts_toclient", f->tosrcpktcnt);
306
965k
        jb_set_uint(js, "bytes_toserver", f->todstbytecnt);
307
965k
        jb_set_uint(js, "bytes_toclient", f->tosrcbytecnt);
308
965k
    }
309
310
965k
    char timebuf1[64];
311
965k
    CreateIsoTimeString(f->startts, timebuf1, sizeof(timebuf1));
312
965k
    jb_set_string(js, "start", timebuf1);
313
965k
}
314
315
static void EveExceptionPolicyLog(JsonBuilder *js, uint16_t flag)
316
87.6k
{
317
87.6k
    if (flag & EXCEPTION_TARGET_FLAG_DEFRAG_MEMCAP) {
318
0
        jb_start_object(js);
319
0
        jb_set_string(js, "target",
320
0
                ExceptionPolicyTargetFlagToString(EXCEPTION_TARGET_FLAG_DEFRAG_MEMCAP));
321
0
        jb_set_string(js, "policy",
322
0
                ExceptionPolicyEnumToString(
323
0
                        ExceptionPolicyTargetPolicy(EXCEPTION_TARGET_FLAG_DEFRAG_MEMCAP), true));
324
0
        jb_close(js);
325
0
    }
326
87.6k
    if (flag & EXCEPTION_TARGET_FLAG_SESSION_MEMCAP) {
327
0
        jb_start_object(js);
328
0
        jb_set_string(js, "target",
329
0
                ExceptionPolicyTargetFlagToString(EXCEPTION_TARGET_FLAG_SESSION_MEMCAP));
330
0
        jb_set_string(js, "policy",
331
0
                ExceptionPolicyEnumToString(
332
0
                        ExceptionPolicyTargetPolicy(EXCEPTION_TARGET_FLAG_SESSION_MEMCAP), true));
333
0
        jb_close(js);
334
0
    }
335
87.6k
    if (flag & EXCEPTION_TARGET_FLAG_REASSEMBLY_MEMCAP) {
336
0
        jb_start_object(js);
337
0
        jb_set_string(js, "target",
338
0
                ExceptionPolicyTargetFlagToString(EXCEPTION_TARGET_FLAG_REASSEMBLY_MEMCAP));
339
0
        jb_set_string(js, "policy",
340
0
                ExceptionPolicyEnumToString(
341
0
                        ExceptionPolicyTargetPolicy(EXCEPTION_TARGET_FLAG_REASSEMBLY_MEMCAP),
342
0
                        true));
343
0
        jb_close(js);
344
0
    }
345
87.6k
    if (flag & EXCEPTION_TARGET_FLAG_FLOW_MEMCAP) {
346
0
        jb_start_object(js);
347
0
        jb_set_string(
348
0
                js, "target", ExceptionPolicyTargetFlagToString(EXCEPTION_TARGET_FLAG_FLOW_MEMCAP));
349
0
        jb_set_string(js, "policy",
350
0
                ExceptionPolicyEnumToString(
351
0
                        ExceptionPolicyTargetPolicy(EXCEPTION_TARGET_FLAG_FLOW_MEMCAP), true));
352
0
        jb_close(js);
353
0
    }
354
87.6k
    if (flag & EXCEPTION_TARGET_FLAG_MIDSTREAM) {
355
86.9k
        jb_start_object(js);
356
86.9k
        jb_set_string(
357
86.9k
                js, "target", ExceptionPolicyTargetFlagToString(EXCEPTION_TARGET_FLAG_MIDSTREAM));
358
86.9k
        jb_set_string(js, "policy",
359
86.9k
                ExceptionPolicyEnumToString(
360
86.9k
                        ExceptionPolicyTargetPolicy(EXCEPTION_TARGET_FLAG_MIDSTREAM), true));
361
86.9k
        jb_close(js);
362
86.9k
    }
363
87.6k
    if (flag & EXCEPTION_TARGET_FLAG_APPLAYER_ERROR) {
364
25.6k
        jb_start_object(js);
365
25.6k
        jb_set_string(js, "target",
366
25.6k
                ExceptionPolicyTargetFlagToString(EXCEPTION_TARGET_FLAG_APPLAYER_ERROR));
367
25.6k
        jb_set_string(js, "policy",
368
25.6k
                ExceptionPolicyEnumToString(
369
25.6k
                        ExceptionPolicyTargetPolicy(EXCEPTION_TARGET_FLAG_APPLAYER_ERROR), true));
370
25.6k
        jb_close(js);
371
25.6k
    }
372
87.6k
}
373
374
/* Eve format logging */
375
static void EveFlowLogJSON(LogFlowLogThread *ft, JsonBuilder *jb, Flow *f)
376
102k
{
377
102k
    EveAddAppProto(f, jb);
378
102k
    jb_open_object(jb, "flow");
379
102k
    EveAddFlow(f, jb);
380
381
102k
    char timebuf2[64];
382
102k
    CreateIsoTimeString(f->lastts, timebuf2, sizeof(timebuf2));
383
102k
    jb_set_string(jb, "end", timebuf2);
384
385
102k
    int32_t age = SCTIME_SECS(f->lastts) - SCTIME_SECS(f->startts);
386
102k
    jb_set_uint(jb, "age", age);
387
388
102k
    if (f->flow_end_flags & FLOW_END_FLAG_EMERGENCY)
389
0
        JB_SET_TRUE(jb, "emergency");
390
102k
    const char *state = NULL;
391
102k
    if (f->flow_end_flags & FLOW_END_FLAG_STATE_NEW)
392
29.7k
        state = "new";
393
72.2k
    else if (f->flow_end_flags & FLOW_END_FLAG_STATE_ESTABLISHED)
394
36.1k
        state = "established";
395
36.1k
    else if (f->flow_end_flags & FLOW_END_FLAG_STATE_CLOSED)
396
36.1k
        state = "closed";
397
0
    else if (f->flow_end_flags & FLOW_END_FLAG_STATE_BYPASSED) {
398
0
        state = "bypassed";
399
0
        int flow_state = f->flow_state;
400
0
        switch (flow_state) {
401
0
            case FLOW_STATE_LOCAL_BYPASSED:
402
0
                JB_SET_STRING(jb, "bypass", "local");
403
0
                break;
404
#ifdef CAPTURE_OFFLOAD
405
            case FLOW_STATE_CAPTURE_BYPASSED:
406
                JB_SET_STRING(jb, "bypass", "capture");
407
                break;
408
#endif
409
0
            default:
410
0
                SCLogError("Invalid flow state: %d, contact developers", flow_state);
411
0
        }
412
0
    }
413
414
102k
    jb_set_string(jb, "state", state);
415
416
102k
    const char *reason = NULL;
417
102k
    if (f->flow_end_flags & FLOW_END_FLAG_FORCED)
418
0
        reason = "forced";
419
102k
    else if (f->flow_end_flags & FLOW_END_FLAG_SHUTDOWN)
420
0
        reason = "shutdown";
421
102k
    else if (f->flow_end_flags & FLOW_END_FLAG_TIMEOUT)
422
102k
        reason = "timeout";
423
0
    else
424
0
        reason = "unknown";
425
426
102k
    jb_set_string(jb, "reason", reason);
427
428
102k
    jb_set_bool(jb, "alerted", FlowHasAlerts(f));
429
102k
    if (f->flags & FLOW_WRONG_THREAD)
430
0
        JB_SET_TRUE(jb, "wrong_thread");
431
432
102k
    if (f->flags & FLOW_ACTION_DROP) {
433
122
        JB_SET_STRING(jb, "action", "drop");
434
101k
    } else if (f->flags & FLOW_ACTION_PASS) {
435
303
        JB_SET_STRING(jb, "action", "pass");
436
303
    }
437
102k
    if (f->applied_exception_policy != 0 && ft->flowlog_ctx->log_exception_policies) {
438
0
        jb_open_array(jb, "exception_policy");
439
0
        EveExceptionPolicyLog(jb, f->applied_exception_policy);
440
0
        jb_close(jb); /* close array */
441
0
    }
442
443
    /* Close flow. */
444
102k
    jb_close(jb);
445
446
102k
    EveAddCommonOptions(&ft->output_ctx->ctx->cfg, NULL, f, jb, LOG_DIR_FLOW);
447
448
    /* TCP */
449
102k
    if (f->proto == IPPROTO_TCP) {
450
98.2k
        jb_open_object(jb, "tcp");
451
452
98.2k
        TcpSession *ssn = f->protoctx;
453
454
98.2k
        char hexflags[3];
455
98.2k
        snprintf(hexflags, sizeof(hexflags), "%02x",
456
98.2k
                ssn ? ssn->tcp_packet_flags : 0);
457
98.2k
        jb_set_string(jb, "tcp_flags", hexflags);
458
459
98.2k
        snprintf(hexflags, sizeof(hexflags), "%02x",
460
98.2k
                ssn ? ssn->client.tcp_flags : 0);
461
98.2k
        jb_set_string(jb, "tcp_flags_ts", hexflags);
462
463
98.2k
        snprintf(hexflags, sizeof(hexflags), "%02x",
464
98.2k
                ssn ? ssn->server.tcp_flags : 0);
465
98.2k
        jb_set_string(jb, "tcp_flags_tc", hexflags);
466
467
98.2k
        EveTcpFlags(ssn ? ssn->tcp_packet_flags : 0, jb);
468
469
98.2k
        if (ssn) {
470
95.0k
            const char *tcp_state = StreamTcpStateAsString(ssn->state);
471
95.0k
            if (tcp_state != NULL)
472
95.0k
                jb_set_string(jb, "state", tcp_state);
473
95.0k
            if (ssn->server.flags & STREAMTCP_STREAM_FLAG_HAS_GAP) {
474
15.5k
                JB_SET_TRUE(jb, "tc_gap");
475
15.5k
            }
476
95.0k
            if (ssn->client.flags & STREAMTCP_STREAM_FLAG_HAS_GAP) {
477
16.6k
                JB_SET_TRUE(jb, "ts_gap");
478
16.6k
            }
479
480
95.0k
            jb_set_uint(jb, "ts_max_regions", ssn->client.sb.max_regions);
481
95.0k
            jb_set_uint(jb, "tc_max_regions", ssn->server.sb.max_regions);
482
483
95.0k
            if (ssn->urg_offset_ts)
484
0
                jb_set_uint(jb, "ts_urgent_oob_data", ssn->urg_offset_ts);
485
95.0k
            if (ssn->urg_offset_tc)
486
0
                jb_set_uint(jb, "tc_urgent_oob_data", ssn->urg_offset_tc);
487
95.0k
        }
488
489
        /* Close tcp. */
490
98.2k
        jb_close(jb);
491
98.2k
    }
492
102k
}
493
494
static int JsonFlowLogger(ThreadVars *tv, void *thread_data, Flow *f)
495
206k
{
496
206k
    SCEnter();
497
206k
    LogFlowLogThread *thread = thread_data;
498
499
206k
    JsonBuilder *jb = CreateEveHeaderFromFlow(f);
500
206k
    if (unlikely(jb == NULL)) {
501
0
        SCReturnInt(TM_ECODE_OK);
502
0
    }
503
504
206k
    EveFlowLogJSON(thread, jb, f);
505
506
206k
    OutputJsonBuilderBuffer(jb, thread->output_ctx);
507
206k
    jb_free(jb);
508
509
206k
    SCReturnInt(TM_ECODE_OK);
510
206k
}
511
512
void JsonFlowLogRegister (void)
513
71
{
514
    /* register as child of eve-log */
515
71
    OutputRegisterFlowSubModule(LOGGER_JSON_FLOW, "eve-log", "JsonFlowLog", "eve-log.flow",
516
71
            OutputFlowLogInitSub, JsonFlowLogger, JsonFlowLogThreadInit, JsonFlowLogThreadDeInit,
517
            NULL);
518
71
}