• Home
  • Features
  • Pricing
  • Docs
  • Announcements
  • Sign In

jasonish / suricata / 23105300094

15 Mar 2026 06:48AM UTC coverage: 75.784% (-0.7%) from 76.495%
23105300094

push

github

jasonish
github-ci: ubuntu minimal build fixups

- Don't run on the GitHub provided VM, it contains a newer Rust than
  stock Ubuntu does.

252836 of 333628 relevant lines covered (75.78%)

1978514.46 hits per line

Source File
Press 'n' to go to next uncovered line, 'b' for previous

73.13
/src/runmodes.c
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
/** \file
19
 *
20
 *  \author Victor Julien <victor@inliniac.net>
21
 *
22
 *  Pre-cooked threading runmodes.
23
 */
24

25
#include "suricata-common.h"
26
#include "detect-engine.h"
27
#include "app-layer-parser.h"
28
#include "util-debug.h"
29
#include "util-affinity.h"
30
#include "conf.h"
31
#include "log-flush.h"
32
#include "runmodes.h"
33
#include "runmode-af-packet.h"
34
#include "runmode-af-xdp.h"
35
#include "runmode-dpdk.h"
36
#include "runmode-erf-dag.h"
37
#include "runmode-erf-file.h"
38
#include "runmode-ipfw.h"
39
#include "runmode-lib.h"
40
#include "runmode-netmap.h"
41
#include "runmode-nflog.h"
42
#include "runmode-nfq.h"
43
#include "runmode-pcap.h"
44
#include "runmode-pcap-file.h"
45
#include "runmode-unix-socket.h"
46
#include "runmode-windivert.h"
47
#include "util-unittest.h"
48
#include "util-misc.h"
49
#include "util-plugin.h"
50

51
#include "output.h"
52

53
#include "tmqh-flow.h"
54
#include "flow-manager.h"
55
#include "flow-bypass.h"
56
#include "counters.h"
57

58
#include "suricata-plugin.h"
59
#include "util-device-private.h"
60

61
int debuglog_enabled = 0;
62
bool threading_set_cpu_affinity = false;
63
uint64_t threading_set_stack_size = 0;
64

65
/* Runmode Global Thread Names */
66
const char *thread_name_autofp = "RX";
67
const char *thread_name_single = "W";
68
const char *thread_name_workers = "W";
69
const char *thread_name_verdict = "TX";
70
const char *thread_name_flow_mgr = "FM";
71
const char *thread_name_flow_rec = "FR";
72
const char *thread_name_flow_bypass = "FB";
73
const char *thread_name_unix_socket = "US";
74
const char *thread_name_detect_loader = "DL";
75
const char *thread_name_counter_stats = "CS";
76
const char *thread_name_counter_wakeup = "CW";
77
const char *thread_name_heartbeat = "HB";
78

79
/**
80
 * \brief Holds description for a runmode.
81
 */
82
typedef struct RunMode_ {
83
    /* the runmode type */
84
    enum SCRunModes runmode;
85
    const char *name;
86
    const char *description;
87
    /* runmode function */
88
    int (*RunModeFunc)(void);
89
    int (*RunModeIsIPSEnabled)(void);
90
} RunMode;
91

92
typedef struct RunModes_ {
93
    int cnt;
94
    RunMode *runmodes;
95
} RunModes;
96

97
static RunModes runmodes[RUNMODE_USER_MAX];
98

99
static char *active_runmode;
100

101
/* free list for our outputs */
102
typedef struct OutputFreeList_ {
103
    OutputModule *output_module;
104
    OutputCtx *output_ctx;
105

106
    TAILQ_ENTRY(OutputFreeList_) entries;
107
} OutputFreeList;
108
static TAILQ_HEAD(, OutputFreeList_) output_free_list =
109
    TAILQ_HEAD_INITIALIZER(output_free_list);
110

111
/**
112
 * \internal
113
 * \brief Translate a runmode mode to a printable string.
114
 *
115
 * \param runmode Runmode to be converted into a printable string.
116
 *
117
 * \retval string Printable string.
118
 */
119
static const char *RunModeTranslateModeToName(int runmode)
120
{
14✔
121
    switch (runmode) {
14✔
122
        case RUNMODE_PCAP_DEV:
1✔
123
            return "PCAP_DEV";
1✔
124
        case RUNMODE_PCAP_FILE:
1✔
125
            return "PCAP_FILE";
1✔
126
        case RUNMODE_PLUGIN:
×
127
            return "PLUGIN";
×
128
        case RUNMODE_NFQ:
1✔
129
            return "NFQ";
1✔
130
        case RUNMODE_NFLOG:
1✔
131
            return "NFLOG";
1✔
132
        case RUNMODE_IPFW:
1✔
133
            return "IPFW";
1✔
134
        case RUNMODE_ERF_FILE:
1✔
135
            return "ERF_FILE";
1✔
136
        case RUNMODE_DAG:
1✔
137
            return "ERF_DAG";
1✔
138
        case RUNMODE_UNITTEST:
1✔
139
            return "UNITTEST";
1✔
140
        case RUNMODE_AFP_DEV:
1✔
141
            return "AF_PACKET_DEV";
1✔
142
        case RUNMODE_AFXDP_DEV:
1✔
143
            return "AF_XDP_DEV";
1✔
144
        case RUNMODE_NETMAP:
1✔
145
#ifdef HAVE_NETMAP
146
            return "NETMAP";
147
#else
148
            return "NETMAP(DISABLED)";
1✔
149
#endif
×
150
        case RUNMODE_UNIX_SOCKET:
1✔
151
            return "UNIX_SOCKET";
1✔
152
        case RUNMODE_WINDIVERT:
1✔
153
#ifdef WINDIVERT
154
            return "WINDIVERT";
155
#else
156
            return "WINDIVERT(DISABLED)";
1✔
157
#endif
×
158
        case RUNMODE_DPDK:
1✔
159
#ifdef HAVE_DPDK
160
            return "DPDK";
161
#else
162
            return "DPDK(DISABLED)";
1✔
163
#endif
×
164
        case RUNMODE_LIB:
×
165
            return "LIB";
×
166

167
        default:
×
168
            FatalError("Unknown runtime mode. Aborting");
×
169
    }
14✔
170
}
14✔
171

172
/**
173
 * \internal
174
 * \brief Dispatcher function for runmodes.  Calls the required runmode function
175
 *        based on runmode + runmode_custom_id.
176
 *
177
 * \param runmode           The runmode type.
178
 * \param runmode_custom_id The runmode custom id.
179
 */
180
static RunMode *RunModeGetCustomMode(enum SCRunModes runmode, const char *custom_mode)
181
{
67,993✔
182
    if (runmode < RUNMODE_USER_MAX) {
67,993✔
183
        for (int i = 0; i < runmodes[runmode].cnt; i++) {
118,267✔
184
            if (strcmp(runmodes[runmode].runmodes[i].name, custom_mode) == 0)
54,342✔
185
                return &runmodes[runmode].runmodes[i];
4,068✔
186
        }
54,342✔
187
    }
67,993✔
188
    return NULL;
63,925✔
189
}
67,993✔
190

191

192
/**
193
 * Return the running mode
194
 *
195
 * The returned string must not be freed.
196
 *
197
 * \return a string containing the current running mode
198
 */
199
char *RunmodeGetActive(void)
200
{
12✔
201
    return active_runmode;
12✔
202
}
12✔
203

204
bool RunmodeIsWorkers(void)
205
{
×
206
    return RunmodeGetActive() && (strcmp(RunmodeGetActive(), "workers") == 0);
×
207
}
×
208

209
bool RunmodeIsAutofp(void)
210
{
×
211
    return RunmodeGetActive() && (strcmp(RunmodeGetActive(), "autofp") == 0);
×
212
}
×
213

214
/**
215
 * Return the running mode
216
 *
217
 * The returned string must not be freed.
218
 *
219
 * \return a string containing the current running mode
220
 */
221
const char *RunModeGetMainMode(void)
222
{
×
223
    int mainmode = SCRunmodeGet();
×
224

225
    return RunModeTranslateModeToName(mainmode);
×
226
}
×
227

228
/**
229
 * \brief Register all runmodes in the engine.
230
 */
231
void RunModeRegisterRunModes(void)
232
{
2,204✔
233
    memset(runmodes, 0, sizeof(runmodes));
2,204✔
234

235
    RunModeIdsPcapRegister();
2,204✔
236
    RunModeFilePcapRegister();
2,204✔
237
    RunModeIpsNFQRegister();
2,204✔
238
    RunModeIpsIPFWRegister();
2,204✔
239
    RunModeErfFileRegister();
2,204✔
240
    RunModeErfDagRegister();
2,204✔
241
    RunModeIdsAFPRegister();
2,204✔
242
    RunModeIdsAFXDPRegister();
2,204✔
243
    RunModeIdsNetmapRegister();
2,204✔
244
    RunModeIdsNflogRegister();
2,204✔
245
    RunModeUnixSocketRegister();
2,204✔
246
    RunModeIpsWinDivertRegister();
2,204✔
247
    RunModeDpdkRegister();
2,204✔
248
#ifdef UNITTESTS
9✔
249
    UtRunModeRegister();
9✔
250
#endif
9✔
251
}
2,204✔
252

253
/**
254
 * \brief Lists all registered runmodes.
255
 */
256
void RunModeListRunmodes(void)
257
{
1✔
258
    printf("------------------------------------- Runmodes -------------------"
1✔
259
           "-----------------------\n");
1✔
260

261
    printf("| %-17s | %-17s | %-10s \n",
1✔
262
           "RunMode Type", "Custom Mode ", "Description");
1✔
263
    printf("|-----------------------------------------------------------------"
1✔
264
           "-----------------------\n");
1✔
265
    int i = RUNMODE_UNKNOWN + 1;
1✔
266
    int j = 0;
1✔
267
    for ( ; i < RUNMODE_USER_MAX; i++) {
17✔
268
        int mode_displayed = 0;
16✔
269
        for (j = 0; j < runmodes[i].cnt; j++) {
46✔
270
            if (mode_displayed == 1) {
30✔
271
                printf("|                   ----------------------------------------------"
16✔
272
                       "-----------------------\n");
16✔
273
                RunMode *runmode = &runmodes[i].runmodes[j];
16✔
274
                printf("| %-17s | %-17s | %-27s \n",
16✔
275
                       "",
16✔
276
                       runmode->name,
16✔
277
                       runmode->description);
16✔
278
            } else {
16✔
279
                RunMode *runmode = &runmodes[i].runmodes[j];
14✔
280
                printf("| %-17s | %-17s | %-27s \n",
14✔
281
                       RunModeTranslateModeToName(runmode->runmode),
14✔
282
                       runmode->name,
14✔
283
                       runmode->description);
14✔
284
            }
14✔
285
            if (mode_displayed == 0)
30✔
286
                mode_displayed = 1;
14✔
287
        }
30✔
288
        if (mode_displayed == 1) {
16✔
289
            printf("|-----------------------------------------------------------------"
14✔
290
                   "-----------------------\n");
14✔
291
        }
14✔
292
    }
16✔
293
}
1✔
294

295
static const char *RunModeGetConfOrDefault(int capture_mode, const char *capture_plugin_name)
296
{
4,114✔
297
    const char *custom_mode = NULL;
4,114✔
298
    const char *val = NULL;
4,114✔
299
    if (SCConfGet("runmode", &val) != 1) {
4,114✔
300
        custom_mode = NULL;
4,112✔
301
    } else {
4,112✔
302
        custom_mode = val;
2✔
303
    }
2✔
304

305
    if ((custom_mode == NULL) || (strcmp(custom_mode, "auto") == 0)) {
4,114✔
306
        switch (capture_mode) {
4,112✔
307
            case RUNMODE_PCAP_DEV:
×
308
                custom_mode = RunModeIdsGetDefaultMode();
×
309
                break;
×
310
            case RUNMODE_PCAP_FILE:
3,976✔
311
                custom_mode = RunModeFilePcapGetDefaultMode();
3,976✔
312
                break;
3,976✔
313
            case RUNMODE_PLUGIN: {
×
314
#ifdef HAVE_PLUGINS
×
315
                SCCapturePlugin *plugin = SCPluginFindCaptureByName(capture_plugin_name);
×
316
                if (plugin == NULL) {
×
317
                    FatalError("No capture plugin found with name %s", capture_plugin_name);
×
318
                }
×
319
                custom_mode = (const char *)plugin->GetDefaultMode();
×
320
#endif
×
321
                break;
×
322
            }
×
323
            case RUNMODE_NFQ:
×
324
                custom_mode = RunModeIpsNFQGetDefaultMode();
×
325
                break;
×
326
            case RUNMODE_IPFW:
×
327
                custom_mode = RunModeIpsIPFWGetDefaultMode();
×
328
                break;
×
329
            case RUNMODE_ERF_FILE:
×
330
                custom_mode = RunModeErfFileGetDefaultMode();
×
331
                break;
×
332
            case RUNMODE_DAG:
×
333
                custom_mode = RunModeErfDagGetDefaultMode();
×
334
                break;
×
335
            case RUNMODE_AFP_DEV:
×
336
                custom_mode = RunModeAFPGetDefaultMode();
×
337
                break;
×
338
            case RUNMODE_AFXDP_DEV:
×
339
                custom_mode = RunModeAFXDPGetDefaultMode();
×
340
                break;
×
341
            case RUNMODE_NETMAP:
×
342
                custom_mode = RunModeNetmapGetDefaultMode();
×
343
                break;
×
344
            case RUNMODE_UNIX_SOCKET:
2✔
345
                custom_mode = RunModeUnixSocketGetDefaultMode();
2✔
346
                break;
2✔
347
            case RUNMODE_NFLOG:
×
348
                custom_mode = RunModeIdsNflogGetDefaultMode();
×
349
                break;
×
350
#ifdef WINDIVERT
351
            case RUNMODE_WINDIVERT:
352
                custom_mode = RunModeIpsWinDivertGetDefaultMode();
353
                break;
354
#endif
355
#ifdef HAVE_DPDK
356
            case RUNMODE_DPDK:
357
                custom_mode = RunModeDpdkGetDefaultMode();
358
                break;
359
#endif
360
            default:
134✔
361
                return NULL;
134✔
362
        }
4,112✔
363
    } else {
4,112✔
364
        /* Add compatibility with old 'worker' name */
365
        if (!strcmp("worker", custom_mode)) {
2✔
366
            SCLogWarning("'worker' mode have been renamed "
×
367
                         "to 'workers', please modify your setup.");
×
368
            custom_mode = "workers";
×
369
        }
×
370
    }
2✔
371

372
    return custom_mode;
3,980✔
373
}
4,114✔
374

375
int RunModeEngineIsIPS(int capture_mode, const char *runmode, const char *capture_plugin_name)
376
{
2,190✔
377
    if (runmode == NULL) {
2,190✔
378
        runmode = RunModeGetConfOrDefault(capture_mode, capture_plugin_name);
2,146✔
379
        if (runmode == NULL) // non-standard runmode
2,146✔
380
            return 0;
134✔
381
    }
2,146✔
382

383
    RunMode *mode = RunModeGetCustomMode(capture_mode, runmode);
2,056✔
384
    if (mode == NULL) {
2,056✔
385
        return 0;
×
386
    }
×
387

388
    int ips_enabled = 0;
2,056✔
389
    if (mode->RunModeIsIPSEnabled != NULL) {
2,056✔
390
        ips_enabled = mode->RunModeIsIPSEnabled();
4✔
391
        if (ips_enabled == 1) {
4✔
392
            extern uint16_t g_livedev_mask;
4✔
393
            if (g_livedev_mask != 0 && LiveGetDeviceCount() > 0) {
4✔
394
                SCLogWarning("disabling livedev.use-for-tracking with IPS mode. See ticket #6726.");
4✔
395
                g_livedev_mask = 0;
4✔
396
            }
4✔
397
        }
4✔
398
    }
4✔
399

400
    return ips_enabled;
2,056✔
401
}
2,056✔
402

403
/**
404
 */
405
void RunModeDispatch(int runmode, const char *custom_mode, const char *capture_plugin_name,
406
        const char *capture_plugin_args)
407
{
2,012✔
408
    char *local_custom_mode = NULL;
2,012✔
409

410
    if (custom_mode == NULL) {
2,012✔
411
        custom_mode = RunModeGetConfOrDefault(runmode, capture_plugin_name);
1,968✔
412
        if (custom_mode == NULL)
1,968✔
413
            FatalError("Unknown runtime mode. Aborting");
×
414
    }
1,968✔
415

416
    RunMode *mode = RunModeGetCustomMode(runmode, custom_mode);
2,012✔
417
    if (mode == NULL) {
2,012✔
418
        SCLogError("The custom type \"%s\" doesn't exist "
×
419
                   "for this runmode type \"%s\".  Please use --list-runmodes to "
×
420
                   "see available custom types for this runmode",
×
421
                custom_mode, RunModeTranslateModeToName(runmode));
×
422
        exit(EXIT_FAILURE);
×
423
    }
×
424

425
    /* Export the custom mode */
426
    if (active_runmode) {
2,012✔
427
        SCFree(active_runmode);
×
428
    }
×
429
    active_runmode = SCStrdup(custom_mode);
2,012✔
430
    if (unlikely(active_runmode == NULL)) {
2,012✔
431
        FatalError("Unable to dup active mode");
×
432
    }
×
433

434
    if (strcasecmp(active_runmode, "autofp") == 0) {
2,012✔
435
        TmqhFlowPrintAutofpHandler();
1,969✔
436
    }
1,969✔
437

438
    mode->RunModeFunc();
2,012✔
439

440
    if (local_custom_mode != NULL)
2,012✔
441
        SCFree(local_custom_mode);
×
442

443
    /* Check if the alloted queues have at least 1 reader and writer */
444
    TmValidateQueueState();
2,012✔
445

446
    if (runmode != RUNMODE_UNIX_SOCKET) {
2,012✔
447
        /* spawn management threads */
448
        FlowManagerThreadSpawn();
2,011✔
449
        FlowRecyclerThreadSpawn();
2,011✔
450
        if (RunModeNeedsBypassManager()) {
2,011✔
451
            BypassedFlowManagerThreadSpawn();
×
452
        }
×
453
        StatsSpawnThreads();
2,011✔
454
        LogFlushThreads();
2,011✔
455
        TmThreadsSealThreads();
2,011✔
456
    }
2,011✔
457
}
2,012✔
458

459
static int g_runmode_needs_bypass = 0;
460

461
void RunModeEnablesBypassManager(void)
462
{
×
463
    g_runmode_needs_bypass = 1;
×
464
}
×
465

466
int RunModeNeedsBypassManager(void)
467
{
2,011✔
468
    return g_runmode_needs_bypass;
2,011✔
469
}
2,011✔
470

471

472

473
/**
474
 * \brief Registers a new runmode.
475
 *
476
 * \param runmode     Runmode type.
477
 * \param name        Custom mode for this specific runmode type.  Within each
478
 *                    runmode type, each custom name is a primary key.
479
 * \param description Description for this runmode.
480
 * \param RunModeFunc The function to be run for this runmode.
481
 */
482
void RunModeRegisterNewRunMode(enum SCRunModes runmode, const char *name, const char *description,
483
        int (*RunModeFunc)(void), int (*RunModeIsIPSEnabled)(void))
484
{
63,925✔
485
    if (RunModeGetCustomMode(runmode, name) != NULL) {
63,925✔
486
        FatalError("runmode '%s' has already "
×
487
                   "been registered. Please use an unique name.",
×
488
                name);
×
489
    }
×
490

491
    void *ptmp = SCRealloc(runmodes[runmode].runmodes,
63,925✔
492
                     (runmodes[runmode].cnt + 1) * sizeof(RunMode));
63,925✔
493
    if (ptmp == NULL) {
63,925✔
494
        SCFree(runmodes[runmode].runmodes);
×
495
        runmodes[runmode].runmodes = NULL;
×
496
        exit(EXIT_FAILURE);
×
497
    }
×
498
    runmodes[runmode].runmodes = ptmp;
63,925✔
499

500
    RunMode *mode = &runmodes[runmode].runmodes[runmodes[runmode].cnt];
63,925✔
501
    runmodes[runmode].cnt++;
63,925✔
502
    memset(mode, 0x00, sizeof(*mode));
63,925✔
503

504
    mode->runmode = runmode;
63,925✔
505
    mode->name = SCStrdup(name);
63,925✔
506
    if (unlikely(mode->name == NULL)) {
63,925✔
507
        FatalError("Failed to allocate string");
×
508
    }
×
509
    mode->description = SCStrdup(description);
63,925✔
510
    if (unlikely(mode->description == NULL)) {
63,925✔
511
        FatalError("Failed to allocate string");
×
512
    }
×
513
    mode->RunModeFunc = RunModeFunc;
63,925✔
514
    mode->RunModeIsIPSEnabled = RunModeIsIPSEnabled;
63,925✔
515
}
63,925✔
516

517
/**
518
 * Setup the outputs for this run mode.
519
 *
520
 * \param tv The ThreadVars for the thread the outputs will be
521
 * appended to.
522
 */
523
static void RunOutputFreeList(void)
524
{
2,011✔
525
    OutputFreeList *output;
2,011✔
526
    while ((output = TAILQ_FIRST(&output_free_list))) {
54,088✔
527
        TAILQ_REMOVE(&output_free_list, output, entries);
52,077✔
528

529
        SCLogDebug("output %s %p %p", output->output_module->name, output, output->output_ctx);
52,077✔
530
        if (output->output_ctx != NULL && output->output_ctx->DeInit != NULL)
52,077✔
531
            output->output_ctx->DeInit(output->output_ctx);
52,077✔
532
        SCFree(output);
52,077✔
533
    }
52,077✔
534
}
2,011✔
535

536
static int file_logger_count = 0;
537
static int filedata_logger_count = 0;
538

539
int RunModeOutputFiledataEnabled(void)
540
{
45✔
541
    return filedata_logger_count > 0;
45✔
542
}
45✔
543

544
bool IsRunModeSystem(enum SCRunModes run_mode_to_check)
545
{
2,201✔
546
    switch (run_mode_to_check) {
2,201✔
547
        case RUNMODE_PCAP_FILE:
2,049✔
548
        case RUNMODE_ERF_FILE:
2,049✔
549
        case RUNMODE_ENGINE_ANALYSIS:
2,159✔
550
            return false;
2,159✔
551
            break;
×
552
        default:
42✔
553
            return true;
42✔
554
    }
2,201✔
555
}
2,201✔
556

557
bool IsRunModeOffline(enum SCRunModes run_mode_to_check)
558
{
3,553✔
559
    switch(run_mode_to_check) {
3,553✔
560
        case RUNMODE_CONF_TEST:
43✔
561
        case RUNMODE_PCAP_FILE:
3,347✔
562
        case RUNMODE_ERF_FILE:
3,347✔
563
        case RUNMODE_ENGINE_ANALYSIS:
3,529✔
564
        case RUNMODE_UNIX_SOCKET:
3,530✔
565
            return true;
3,530✔
566
            break;
×
567
        default:
23✔
568
            return false;
23✔
569
    }
3,553✔
570
}
3,553✔
571

572
/**
573
 * Cleanup the run mode.
574
 */
575
void RunModeShutDown(void)
576
{
2,011✔
577
    RunOutputFreeList();
2,011✔
578

579
    OutputPacketShutdown();
2,011✔
580
    OutputTxShutdown();
2,011✔
581
    OutputFileShutdown();
2,011✔
582
    OutputFiledataShutdown();
2,011✔
583
    OutputStreamingShutdown();
2,011✔
584
    OutputStatsShutdown();
2,011✔
585
    OutputFlowShutdown();
2,011✔
586

587
    OutputClearActiveLoggers();
2,011✔
588

589
    /* Reset logger counts. */
590
    file_logger_count = 0;
2,011✔
591
    filedata_logger_count = 0;
2,011✔
592
}
2,011✔
593

594
/** \internal
595
 *  \brief add Sub RunModeOutput to list for Submodule so we can free
596
 *         the output ctx at shutdown and unix socket reload */
597
static void AddOutputToFreeList(OutputModule *module, OutputCtx *output_ctx)
598
{
55,971✔
599
    OutputFreeList *fl_output = SCCalloc(1, sizeof(OutputFreeList));
55,971✔
600
    if (unlikely(fl_output == NULL))
55,971✔
601
        return;
×
602
    fl_output->output_module = module;
55,971✔
603
    fl_output->output_ctx = output_ctx;
55,971✔
604
    TAILQ_INSERT_TAIL(&output_free_list, fl_output, entries);
55,971✔
605
}
55,971✔
606

607
/** \brief Turn output into thread module */
608
static void SetupOutput(
609
        const char *name, OutputModule *module, OutputCtx *output_ctx, LoggerId *logger_bits)
610
{
53,884✔
611
    /* flow logger doesn't run in the packet path */
612
    if (module->FlowLogFunc) {
53,884✔
613
        SCOutputRegisterFlowLogger(module->name, module->FlowLogFunc, output_ctx,
1,752✔
614
                module->ThreadInit, module->ThreadDeinit);
1,752✔
615
        return;
1,752✔
616
    }
1,752✔
617
    /* stats logger doesn't run in the packet path */
618
    if (module->StatsLogFunc) {
52,132✔
619
        OutputRegisterStatsLogger(module->name, module->StatsLogFunc, output_ctx,
3,131✔
620
                module->ThreadInit, module->ThreadDeinit);
3,131✔
621
        return;
3,131✔
622
    }
3,131✔
623

624
    if (module->logger_id == LOGGER_ALERT_DEBUG) {
49,001✔
625
        debuglog_enabled = 1;
2✔
626
    }
2✔
627

628
    if (module->PacketLogFunc) {
49,001✔
629
        SCLogDebug("%s is a packet logger", module->name);
5,184✔
630
        SCOutputRegisterPacketLogger(module->logger_id, module->name, module->PacketLogFunc,
5,184✔
631
                module->PacketConditionFunc, output_ctx, module->ThreadInit, module->ThreadDeinit);
5,184✔
632
    } else if (module->TxLogFunc) {
43,817✔
633
        SCLogDebug("%s is a tx logger", module->name);
42,187✔
634
        SCOutputRegisterTxLogger(module->logger_id, module->name, module->alproto,
42,187✔
635
                module->TxLogFunc, output_ctx, module->tc_log_progress, module->ts_log_progress,
42,187✔
636
                module->TxLogCondition, module->ThreadInit, module->ThreadDeinit);
42,187✔
637
        /* Not used with wild card loggers */
638
        if (module->alproto != ALPROTO_UNKNOWN) {
42,187✔
639
            logger_bits[module->alproto] |= BIT_U32(module->logger_id);
40,593✔
640
        }
40,593✔
641
    } else if (module->FiledataLogFunc) {
42,187✔
642
        SCLogDebug("%s is a filedata logger", module->name);
45✔
643
        SCOutputRegisterFiledataLogger(module->logger_id, module->name, module->FiledataLogFunc,
45✔
644
                output_ctx, module->ThreadInit, module->ThreadDeinit);
45✔
645
        filedata_logger_count++;
45✔
646
    } else if (module->FileLogFunc) {
1,585✔
647
        SCLogDebug("%s is a file logger", module->name);
1,581✔
648
        SCOutputRegisterFileLogger(module->logger_id, module->name, module->FileLogFunc, output_ctx,
1,581✔
649
                module->ThreadInit, module->ThreadDeinit);
1,581✔
650
        file_logger_count++;
1,581✔
651
    } else if (module->StreamingLogFunc) {
1,581✔
652
        SCLogDebug("%s is a streaming logger", module->name);
4✔
653
        SCOutputRegisterStreamingLogger(module->logger_id, module->name, module->StreamingLogFunc,
4✔
654
                output_ctx, module->stream_type, module->ThreadInit, module->ThreadDeinit);
4✔
655
    } else {
4✔
656
        SCLogError("Unknown logger type: name=%s", module->name);
×
657
    }
×
658
}
49,001✔
659

660
static void RunModeInitializeEveOutput(
661
        SCConfNode *conf, OutputCtx *parent_ctx, LoggerId *logger_bits)
662
{
2,072✔
663
    SCConfNode *types = SCConfNodeLookupChild(conf, "types");
2,072✔
664
    SCLogDebug("types %p", types);
2,072✔
665
    if (types == NULL) {
2,072✔
666
        return;
2✔
667
    }
2✔
668
    if (!SCConfNodeIsSequence(types)) {
2,070✔
669
        FatalError("output types should be a sequence");
×
670
    }
×
671

672
    SCConfNode *type = NULL;
2,070✔
673
    TAILQ_FOREACH(type, &types->head, next) {
52,180✔
674
        int sub_count = 0;
52,180✔
675
        char subname[256];
52,180✔
676

677
        if (strcmp(type->val, "ikev2") == 0) {
52,180✔
678
            SCLogWarning("eve module 'ikev2' has been replaced by 'ike'");
×
679
            strlcpy(subname, "eve-log.ike", sizeof(subname));
×
680
        } else {
52,180✔
681
            snprintf(subname, sizeof(subname), "eve-log.%s", type->val);
52,180✔
682
        }
52,180✔
683

684
        SCLogConfig("enabling 'eve-log' module '%s'", type->val);
52,180✔
685

686
        SCConfNode *sub_output_config = SCConfNodeLookupChild(type, type->val);
52,180✔
687
        if (sub_output_config != NULL) {
52,180✔
688
            const char *enabled = SCConfNodeLookupChildValue(sub_output_config, "enabled");
22,995✔
689
            if (enabled != NULL && !SCConfValIsTrue(enabled)) {
22,995✔
690
                continue;
4,445✔
691
            }
4,445✔
692
        }
22,995✔
693

694
        /* Now setup all registers logger of this name. */
695
        OutputModule *sub_module;
47,735✔
696
        TAILQ_FOREACH(sub_module, &output_modules, entries) {
2,812,241✔
697
            if (strcmp(subname, sub_module->conf_name) == 0) {
2,812,241✔
698
                sub_count++;
50,815✔
699

700
                if (sub_module->parent_name == NULL ||
50,815✔
701
                        strcmp(sub_module->parent_name, "eve-log") != 0) {
50,815✔
702
                    FatalError("bad parent for %s", subname);
×
703
                }
×
704
                if (sub_module->InitSubFunc == NULL) {
50,815✔
705
                    FatalError("bad sub-module for %s", subname);
×
706
                }
×
707

708
                /* pass on parent output_ctx */
709
                OutputInitResult result =
50,815✔
710
                    sub_module->InitSubFunc(sub_output_config, parent_ctx);
50,815✔
711
                if (!result.ok || result.ctx == NULL) {
50,815✔
712
                    FatalError("unable to initialize sub-module %s", subname);
1✔
713
                }
1✔
714

715
                AddOutputToFreeList(sub_module, result.ctx);
50,814✔
716
                SetupOutput(sub_module->name, sub_module, result.ctx, logger_bits);
50,814✔
717
            }
50,814✔
718
        }
2,812,241✔
719

720
        /* Error is no registered loggers with this name
721
         * were found .*/
722
        if (!sub_count) {
47,734✔
723
            FatalErrorOnInit("No output module named %s", subname);
×
724
            continue;
×
725
        }
×
726
    }
47,734✔
727
}
2,070✔
728

729
static void RunModeInitializeLuaOutput(
730
        SCConfNode *conf, OutputCtx *parent_ctx, LoggerId *logger_bits)
731
{
18✔
732
    OutputModule *lua_module = OutputGetModuleByConfName("lua");
18✔
733
    BUG_ON(lua_module == NULL);
18✔
734

735
    SCConfNode *scripts = SCConfNodeLookupChild(conf, "scripts");
18✔
736
    BUG_ON(scripts == NULL); //TODO
18✔
737

738
    OutputModule *m;
18✔
739
    TAILQ_FOREACH(m, &parent_ctx->submodules, entries) {
19✔
740
        SCLogDebug("m %p %s:%s", m, m->name, m->conf_name);
19✔
741

742
        SCConfNode *script = NULL;
19✔
743
        TAILQ_FOREACH(script, &scripts->head, next) {
20✔
744
            SCLogDebug("script %s", script->val);
20✔
745
            if (strcmp(script->val, m->conf_name) == 0) {
20✔
746
                break;
19✔
747
            }
19✔
748
        }
20✔
749
        BUG_ON(script == NULL);
19✔
750

751
        /* pass on parent output_ctx */
752
        OutputInitResult result = m->InitSubFunc(script, parent_ctx);
19✔
753
        if (!result.ok || result.ctx == NULL) {
19✔
754
            continue;
×
755
        }
×
756

757
        AddOutputToFreeList(m, result.ctx);
19✔
758
        SetupOutput(m->name, m, result.ctx, logger_bits);
19✔
759
    }
19✔
760
}
18✔
761

762
extern bool g_file_logger_enabled;
763
extern bool g_filedata_logger_enabled;
764

765
/**
766
 * Initialize the output modules.
767
 */
768
void RunModeInitializeOutputs(void)
769
{
2,174✔
770
    SCConfNode *outputs = SCConfGetNode("outputs");
2,174✔
771
    if (outputs == NULL) {
2,174✔
772
        /* No "outputs" section in the configuration. */
773
        return;
76✔
774
    }
76✔
775

776
    SCConfNode *output, *output_config;
2,098✔
777
    const char *enabled;
2,098✔
778
    char tls_log_enabled = 0;
2,098✔
779
    char tls_store_present = 0;
2,098✔
780

781
    // g_alproto_max is set to its final value
782
    LoggerId logger_bits[g_alproto_max];
2,098✔
783
    memset(logger_bits, 0, g_alproto_max * sizeof(LoggerId));
2,098✔
784
    TAILQ_FOREACH(output, &outputs->head, next) {
15,522✔
785

786
        output_config = SCConfNodeLookupChild(output, output->val);
15,522✔
787
        if (output_config == NULL) {
15,522✔
788
            /* Shouldn't happen. */
789
            FatalError("Failed to lookup configuration child node: %s", output->val);
×
790
        }
×
791

792
        if (strcmp(output->val, "tls-store") == 0) {
15,522✔
793
            tls_store_present = 1;
1,480✔
794
        }
1,480✔
795

796
        enabled = SCConfNodeLookupChildValue(output_config, "enabled");
15,522✔
797
        if (enabled == NULL || !SCConfValIsTrue(enabled)) {
15,522✔
798
            continue;
10,376✔
799
        }
10,376✔
800

801
        if (strcmp(output->val, "file-log") == 0) {
5,146✔
802
            SCLogWarning("file-log is no longer supported,"
×
803
                         " use eve.files instead "
×
804
                         "(see ticket #2376"
×
805
                         " for an explanation)");
×
806
            continue;
×
807
        } else if (strncmp(output->val, "unified-", sizeof("unified-") - 1) == 0) {
5,146✔
808
            SCLogWarning("Unified1 is no longer supported,"
×
809
                         " use Unified2 instead "
×
810
                         "(see ticket #353"
×
811
                         " for an explanation)");
×
812
            continue;
×
813
        } else if (strncmp(output->val, "unified2-", sizeof("unified2-") - 1) == 0) {
5,146✔
814
            SCLogWarning("Unified2 is no longer supported.");
4✔
815
            continue;
4✔
816
        } else if (strcmp(output->val, "dns-log") == 0) {
5,142✔
817
            SCLogWarning("dns-log is not longer available as of Suricata 5.0");
×
818
            continue;
×
819
        } else if (strcmp(output->val, "tls-log") == 0) {
5,142✔
820
            tls_log_enabled = 1;
×
821
        }
×
822

823
        OutputModule *module;
5,142✔
824
        int count = 0;
5,142✔
825
        TAILQ_FOREACH(module, &output_modules, entries) {
301,768✔
826
            if (strcmp(module->conf_name, output->val) != 0) {
301,768✔
827
                continue;
296,624✔
828
            }
296,624✔
829

830
            count++;
5,144✔
831

832
            OutputCtx *output_ctx = NULL;
5,144✔
833
            if (module->InitFunc != NULL) {
5,144✔
834
                OutputInitResult r = module->InitFunc(output_config);
5,144✔
835
                if (!r.ok) {
5,144✔
836
                    FatalErrorOnInit("output module \"%s\": setup failed", output->val);
1✔
837
                    continue;
×
838
                } else if (r.ctx == NULL) {
5,143✔
839
                    continue;
×
840
                }
×
841
                output_ctx = r.ctx;
5,143✔
842
            } else if (module->InitSubFunc != NULL) {
5,143✔
843
                SCLogInfo("skipping submodule");
×
844
                continue;
×
845
            }
×
846

847
            // TODO if module == parent, find it's children
848
            if (strcmp(output->val, "eve-log") == 0) {
5,143✔
849
                RunModeInitializeEveOutput(output_config, output_ctx, logger_bits);
2,072✔
850

851
                /* add 'eve-log' to free list as it's the owner of the
852
                 * main output ctx from which the sub-modules share the
853
                 * LogFileCtx */
854
                AddOutputToFreeList(module, output_ctx);
2,072✔
855
            } else if (strcmp(output->val, "lua") == 0) {
3,077✔
856
                SCLogDebug("handle lua");
18✔
857
                if (output_ctx == NULL)
18✔
858
                    continue;
×
859
                RunModeInitializeLuaOutput(output_config, output_ctx, logger_bits);
18✔
860
                AddOutputToFreeList(module, output_ctx);
18✔
861
            } else {
3,053✔
862
                AddOutputToFreeList(module, output_ctx);
3,053✔
863
                SetupOutput(module->name, module, output_ctx, logger_bits);
3,053✔
864
            }
3,053✔
865
        }
5,143✔
866
        if (count == 0) {
5,141✔
867
            FatalErrorOnInit("No output module named %s", output->val);
×
868
            continue;
×
869
        }
×
870
    }
5,141✔
871

872
    /* Backward compatibility code */
873
    if (!tls_store_present && tls_log_enabled) {
2,097✔
874
        /* old YAML with no "tls-store" in outputs. "tls-log" value needs
875
         * to be started using 'tls-log' config as own config */
876
        SCLogWarning("Please use 'tls-store' in YAML to configure TLS storage");
×
877

878
        TAILQ_FOREACH(output, &outputs->head, next) {
×
879
            output_config = SCConfNodeLookupChild(output, output->val);
×
880

881
            if (strcmp(output->val, "tls-log") == 0) {
×
882

883
                OutputModule *module = OutputGetModuleByConfName("tls-store");
×
884
                if (module == NULL) {
×
885
                    SCLogWarning("No output module named %s, ignoring", "tls-store");
×
886
                    continue;
×
887
                }
×
888

889
                OutputCtx *output_ctx = NULL;
×
890
                if (module->InitFunc != NULL) {
×
891
                    OutputInitResult r = module->InitFunc(output_config);
×
892
                    if (!r.ok) {
×
893
                        FatalErrorOnInit("output module setup failed");
×
894
                        continue;
×
895
                    } else if (r.ctx == NULL) {
×
896
                        continue;
×
897
                    }
×
898
                    output_ctx = r.ctx;
×
899
                }
×
900

901
                AddOutputToFreeList(module, output_ctx);
×
902
                SetupOutput(module->name, module, output_ctx, logger_bits);
×
903
            }
×
904
        }
×
905
    }
×
906

907
    /* register the logger bits to the app-layer */
908
    AppProto a;
2,097✔
909
    for (a = 0; a < g_alproto_max; a++) {
85,856✔
910
        if (AppLayerParserSupportsFiles(IPPROTO_TCP, a)) {
83,759✔
911
            if (g_file_logger_enabled)
16,736✔
912
                logger_bits[a] |= BIT_U32(LOGGER_FILE);
12,628✔
913
            if (g_filedata_logger_enabled)
16,736✔
914
                logger_bits[a] |= BIT_U32(LOGGER_FILEDATA);
352✔
915
            SCLogDebug("IPPROTO_TCP::%s: g_file_logger_enabled %d g_filedata_logger_enabled %d -> "
16,736✔
916
                       "%08x",
16,736✔
917
                    AppProtoToString(a), g_file_logger_enabled, g_filedata_logger_enabled,
16,736✔
918
                    logger_bits[a]);
16,736✔
919
        }
16,736✔
920
        if (AppLayerParserSupportsFiles(IPPROTO_UDP, a)) {
83,759✔
921
            if (g_file_logger_enabled)
2,083✔
922
                logger_bits[a] |= BIT_U32(LOGGER_FILE);
1,573✔
923
            if (g_filedata_logger_enabled)
2,083✔
924
                logger_bits[a] |= BIT_U32(LOGGER_FILEDATA);
44✔
925
        }
2,083✔
926

927
        if (logger_bits[a] == 0)
83,759✔
928
            continue;
40,980✔
929

930
        const int tcp = AppLayerParserProtocolHasLogger(IPPROTO_TCP, a) | (g_file_logger_enabled) |
42,779✔
931
                        (g_filedata_logger_enabled);
42,779✔
932
        const int udp = AppLayerParserProtocolHasLogger(IPPROTO_UDP, a) | (g_file_logger_enabled) |
42,779✔
933
                        (g_filedata_logger_enabled);
42,779✔
934
        SCLogDebug("tcp %d udp %d", tcp, udp);
42,779✔
935

936
        SCLogDebug("logger for %s: %s %s", AppProtoToString(a),
42,779✔
937
                tcp ? "true" : "false", udp ? "true" : "false");
42,779✔
938

939
        SCLogDebug("logger bits for %s: %08x", AppProtoToString(a), logger_bits[a]);
42,779✔
940
        if (tcp)
42,779✔
941
            AppLayerParserRegisterLoggerBits(IPPROTO_TCP, a, logger_bits[a]);
42,769✔
942
        if (udp)
42,779✔
943
            AppLayerParserRegisterLoggerBits(IPPROTO_UDP, a, logger_bits[a]);
42,471✔
944
    }
42,779✔
945
    OutputSetupActiveLoggers();
2,097✔
946
}
2,097✔
947

948
float threading_detect_ratio = 1;
949

950
/**
951
 * Initialize multithreading settings.
952
 */
953
void RunModeInitializeThreadSettings(void)
954
{
2,190✔
955
    int affinity = 0;
2,190✔
956
    if ((SCConfGetBool("threading.set-cpu-affinity", &affinity)) == 0) {
2,190✔
957
        threading_set_cpu_affinity = false;
682✔
958
    } else {
1,514✔
959
        threading_set_cpu_affinity = affinity == 1;
1,508✔
960
    }
1,508✔
961

962
    /* try to get custom cpu mask value if needed */
963
    if (threading_set_cpu_affinity) {
2,190✔
964
        AffinitySetupLoadFromConfig();
×
965
    }
×
966
    if ((SCConfGetFloat("threading.detect-thread-ratio", &threading_detect_ratio)) != 1) {
2,190✔
967
        if (SCConfGetNode("threading.detect-thread-ratio") != NULL)
682✔
968
            WarnInvalidConfEntry("threading.detect-thread-ratio", "%s", "1");
×
969
        threading_detect_ratio = 1;
682✔
970
    }
682✔
971

972
    SCLogDebug("threading.detect-thread-ratio %f", threading_detect_ratio);
2,190✔
973

974
    /*
975
     * Check if there's a configuration setting for the per-thread stack size
976
     * in case the default per-thread stack size is to be adjusted
977
     */
978
    const char *ss = NULL;
2,190✔
979
    if ((SCConfGet("threading.stack-size", &ss)) == 1) {
2,190✔
980
        if (ss != NULL) {
×
981
            if (ParseSizeStringU64(ss, &threading_set_stack_size) < 0) {
×
982
                FatalError("Failed to initialize thread_stack_size output, invalid limit: %s", ss);
×
983
            }
×
984
        }
×
985
    } else {
2,190✔
986
        pthread_attr_t attr;
2,190✔
987
        pthread_attr_init(&attr);
2,190✔
988
        size_t size;
2,190✔
989
        if (pthread_attr_getstacksize(&attr, &size) == 0 && size < 512 * 1024) {
2,190✔
990
            threading_set_stack_size = 512 * 1024;
×
991
            SCLogNotice("thread stack size of %" PRIuMAX " too small: setting to 512k",
×
992
                    (uintmax_t)size);
×
993
        }
×
994
    }
2,190✔
995

996
    SCLogDebug("threading.stack-size %" PRIu64, threading_set_stack_size);
2,190✔
997
}
2,190✔
STATUS · Troubleshooting · Open an Issue · Sales · Support · CAREERS · ENTERPRISE · START FREE · SCHEDULE DEMO
ANNOUNCEMENTS · TWITTER · TOS & SLA · Supported CI Services · What's a CI service? · Automated Testing

© 2026 Coveralls, Inc