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

OISF / suricata / 22752045889

05 Mar 2026 09:21PM UTC coverage: 79.291% (+0.008%) from 79.283%
22752045889

push

github

victorjulien
hs: address coverity warning in a reference string

Move the locking mechanism outside of the getter function and hold the
lock until the reference string is no longer reused.

** CID 1682023:       Concurrent data access violations  (MISSING_LOCK)
/src/util-mpm-hs-cache.c: 139           in HSGetReferenceDbInfo()

0 of 6 new or added lines in 1 file covered. (0.0%)

166 existing lines in 20 files now uncovered.

265804 of 335224 relevant lines covered (79.29%)

4553782.75 hits per line

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

79.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
{
20✔
121
    switch (runmode) {
20✔
122
        case RUNMODE_PCAP_DEV:
3✔
123
            return "PCAP_DEV";
3✔
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:
5✔
141
            return "AF_PACKET_DEV";
5✔
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
UNCOV
164
        case RUNMODE_LIB:
×
UNCOV
165
            return "LIB";
×
166

167
        default:
×
168
            FatalError("Unknown runtime mode. Aborting");
×
169
    }
20✔
170
}
20✔
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
{
70,030✔
182
    if (runmode < RUNMODE_USER_MAX) {
70,030✔
183
        for (int i = 0; i < runmodes[runmode].cnt; i++) {
122,135✔
184
            if (strcmp(runmodes[runmode].runmodes[i].name, custom_mode) == 0)
57,601✔
185
                return &runmodes[runmode].runmodes[i];
5,496✔
186
        }
57,601✔
187
    }
70,030✔
188
    return NULL;
64,534✔
189
}
70,030✔
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
{
423✔
201
    return active_runmode;
423✔
202
}
423✔
203

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

209
bool RunmodeIsAutofp(void)
210
{
104✔
211
    return RunmodeGetActive() && (strcmp(RunmodeGetActive(), "autofp") == 0);
104✔
212
}
104✔
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
{
6✔
223
    int mainmode = SCRunmodeGet();
6✔
224

225
    return RunModeTranslateModeToName(mainmode);
6✔
226
}
6✔
227

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

235
    RunModeIdsPcapRegister();
2,225✔
236
    RunModeFilePcapRegister();
2,225✔
237
    RunModeIpsNFQRegister();
2,225✔
238
    RunModeIpsIPFWRegister();
2,225✔
239
    RunModeErfFileRegister();
2,225✔
240
    RunModeErfDagRegister();
2,225✔
241
    RunModeIdsAFPRegister();
2,225✔
242
    RunModeIdsAFXDPRegister();
2,225✔
243
    RunModeIdsNetmapRegister();
2,225✔
244
    RunModeIdsNflogRegister();
2,225✔
245
    RunModeUnixSocketRegister();
2,225✔
246
    RunModeIpsWinDivertRegister();
2,225✔
247
    RunModeDpdkRegister();
2,225✔
248
#ifdef UNITTESTS
9✔
249
    UtRunModeRegister();
9✔
250
#endif
9✔
251
}
2,225✔
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
{
5,526✔
297
    const char *custom_mode = NULL;
5,526✔
298
    const char *val = NULL;
5,526✔
299
    if (SCConfGet("runmode", &val) != 1) {
5,526✔
300
        custom_mode = NULL;
5,524✔
301
    } else {
5,524✔
302
        custom_mode = val;
2✔
303
    }
2✔
304

305
    if ((custom_mode == NULL) || (strcmp(custom_mode, "auto") == 0)) {
5,526✔
306
        switch (capture_mode) {
5,524✔
UNCOV
307
            case RUNMODE_PCAP_DEV:
×
308
                custom_mode = RunModeIdsGetDefaultMode();
×
309
                break;
×
310
            case RUNMODE_PCAP_FILE:
5,348✔
311
                custom_mode = RunModeFilePcapGetDefaultMode();
5,348✔
312
                break;
5,348✔
UNCOV
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:
4✔
345
                custom_mode = RunModeUnixSocketGetDefaultMode();
4✔
346
                break;
4✔
UNCOV
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:
40✔
357
                custom_mode = RunModeDpdkGetDefaultMode();
40✔
358
                break;
40✔
359
#endif
360
            default:
132✔
361
                return NULL;
132✔
362
        }
5,524✔
363
    } else {
5,524✔
364
        /* Add compatibility with old 'worker' name */
365
        if (!strcmp("worker", custom_mode)) {
2✔
UNCOV
366
            SCLogWarning("'worker' mode have been renamed "
×
UNCOV
367
                         "to 'workers', please modify your setup.");
×
UNCOV
368
            custom_mode = "workers";
×
UNCOV
369
        }
×
370
    }
2✔
371

372
    return custom_mode;
5,394✔
373
}
5,526✔
374

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

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

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

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

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

410
    if (custom_mode == NULL) {
3,422✔
411
        custom_mode = RunModeGetConfOrDefault(runmode, capture_plugin_name);
3,371✔
412
        if (custom_mode == NULL)
3,371✔
UNCOV
413
            FatalError("Unknown runtime mode. Aborting");
×
414
    }
3,371✔
415

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

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

434
    if (strcasecmp(active_runmode, "autofp") == 0) {
3,422✔
435
        TmqhFlowPrintAutofpHandler();
3,356✔
436
    }
3,356✔
437

438
    mode->RunModeFunc();
3,422✔
439

440
    if (local_custom_mode != NULL)
3,422✔
UNCOV
441
        SCFree(local_custom_mode);
×
442

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

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

459
static int g_runmode_needs_bypass = 0;
460

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

466
int RunModeNeedsBypassManager(void)
467
{
3,415✔
468
    return g_runmode_needs_bypass;
3,415✔
469
}
3,415✔
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
{
64,534✔
485
    if (RunModeGetCustomMode(runmode, name) != NULL) {
64,534✔
UNCOV
486
        FatalError("runmode '%s' has already "
×
UNCOV
487
                   "been registered. Please use an unique name.",
×
UNCOV
488
                name);
×
UNCOV
489
    }
×
490

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

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

504
    mode->runmode = runmode;
64,534✔
505
    mode->name = SCStrdup(name);
64,534✔
506
    if (unlikely(mode->name == NULL)) {
64,534✔
UNCOV
507
        FatalError("Failed to allocate string");
×
UNCOV
508
    }
×
509
    mode->description = SCStrdup(description);
64,534✔
510
    if (unlikely(mode->description == NULL)) {
64,534✔
511
        FatalError("Failed to allocate string");
×
512
    }
×
513
    mode->RunModeFunc = RunModeFunc;
64,534✔
514
    mode->RunModeIsIPSEnabled = RunModeIsIPSEnabled;
64,534✔
515
}
64,534✔
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
{
3,415✔
525
    OutputFreeList *output;
3,415✔
526
    while ((output = TAILQ_FIRST(&output_free_list))) {
105,526✔
527
        TAILQ_REMOVE(&output_free_list, output, entries);
102,111✔
528

529
        SCLogDebug("output %s %p %p", output->output_module->name, output, output->output_ctx);
102,111✔
530
        if (output->output_ctx != NULL && output->output_ctx->DeInit != NULL)
102,111✔
531
            output->output_ctx->DeInit(output->output_ctx);
102,111✔
532
        SCFree(output);
102,111✔
533
    }
102,111✔
534
}
3,415✔
535

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

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

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

557
bool IsRunModeOffline(enum SCRunModes run_mode_to_check)
558
{
3,581✔
559
    switch(run_mode_to_check) {
3,581✔
560
        case RUNMODE_CONF_TEST:
43✔
561
        case RUNMODE_PCAP_FILE:
3,324✔
562
        case RUNMODE_ERF_FILE:
3,324✔
563
        case RUNMODE_ENGINE_ANALYSIS:
3,502✔
564
        case RUNMODE_UNIX_SOCKET:
3,504✔
565
            return true;
3,504✔
UNCOV
566
            break;
×
567
        default:
77✔
568
            return false;
77✔
569
    }
3,581✔
570
}
3,581✔
571

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

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

587
    OutputClearActiveLoggers();
3,415✔
588

589
    /* Reset logger counts. */
590
    file_logger_count = 0;
3,415✔
591
    filedata_logger_count = 0;
3,415✔
592
}
3,415✔
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
{
105,938✔
599
    OutputFreeList *fl_output = SCCalloc(1, sizeof(OutputFreeList));
105,938✔
600
    if (unlikely(fl_output == NULL))
105,938✔
UNCOV
601
        return;
×
602
    fl_output->output_module = module;
105,938✔
603
    fl_output->output_ctx = output_ctx;
105,938✔
604
    TAILQ_INSERT_TAIL(&output_free_list, fl_output, entries);
105,938✔
605
}
105,938✔
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
{
102,444✔
611
    /* flow logger doesn't run in the packet path */
612
    if (module->FlowLogFunc) {
102,444✔
613
        SCOutputRegisterFlowLogger(module->name, module->FlowLogFunc, output_ctx,
3,140✔
614
                module->ThreadInit, module->ThreadDeinit);
3,140✔
615
        return;
3,140✔
616
    }
3,140✔
617
    /* stats logger doesn't run in the packet path */
618
    if (module->StatsLogFunc) {
99,304✔
619
        OutputRegisterStatsLogger(module->name, module->StatsLogFunc, output_ctx,
5,923✔
620
                module->ThreadInit, module->ThreadDeinit);
5,923✔
621
        return;
5,923✔
622
    }
5,923✔
623

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

628
    if (module->PacketLogFunc) {
93,381✔
629
        SCLogDebug("%s is a packet logger", module->name);
9,346✔
630
        SCOutputRegisterPacketLogger(module->logger_id, module->name, module->PacketLogFunc,
9,346✔
631
                module->PacketConditionFunc, output_ctx, module->ThreadInit, module->ThreadDeinit);
9,346✔
632
    } else if (module->TxLogFunc) {
84,035✔
633
        SCLogDebug("%s is a tx logger", module->name);
81,017✔
634
        SCOutputRegisterTxLogger(module->logger_id, module->name, module->alproto,
81,017✔
635
                module->TxLogFunc, output_ctx, module->tc_log_progress, module->ts_log_progress,
81,017✔
636
                module->TxLogCondition, module->ThreadInit, module->ThreadDeinit);
81,017✔
637
        /* Not used with wild card loggers */
638
        if (module->alproto != ALPROTO_UNKNOWN) {
81,017✔
639
            logger_bits[module->alproto] |= BIT_U32(module->logger_id);
78,036✔
640
        }
78,036✔
641
    } else if (module->FiledataLogFunc) {
81,017✔
642
        SCLogDebug("%s is a filedata logger", module->name);
46✔
643
        SCOutputRegisterFiledataLogger(module->logger_id, module->name, module->FiledataLogFunc,
46✔
644
                output_ctx, module->ThreadInit, module->ThreadDeinit);
46✔
645
        filedata_logger_count++;
46✔
646
    } else if (module->FileLogFunc) {
2,972✔
647
        SCLogDebug("%s is a file logger", module->name);
2,968✔
648
        SCOutputRegisterFileLogger(module->logger_id, module->name, module->FileLogFunc, output_ctx,
2,968✔
649
                module->ThreadInit, module->ThreadDeinit);
2,968✔
650
        file_logger_count++;
2,968✔
651
    } else if (module->StreamingLogFunc) {
2,968✔
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✔
UNCOV
656
        SCLogError("Unknown logger type: name=%s", module->name);
×
UNCOV
657
    }
×
658
}
93,381✔
659

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

672
    SCConfNode *type = NULL;
3,477✔
673
    TAILQ_FOREACH(type, &types->head, next) {
99,348✔
674
        int sub_count = 0;
99,348✔
675
        char subname[256];
99,348✔
676

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

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

686
        SCConfNode *sub_output_config = SCConfNodeLookupChild(type, type->val);
99,348✔
687
        if (sub_output_config != NULL) {
99,348✔
688
            const char *enabled = SCConfNodeLookupChildValue(sub_output_config, "enabled");
43,811✔
689
            if (enabled != NULL && !SCConfValIsTrue(enabled)) {
43,811✔
690
                continue;
8,603✔
691
            }
8,603✔
692
        }
43,811✔
693

694
        /* Now setup all registers logger of this name. */
695
        OutputModule *sub_module;
90,745✔
696
        TAILQ_FOREACH(sub_module, &output_modules, entries) {
5,349,767✔
697
            if (strcmp(subname, sub_module->conf_name) == 0) {
5,349,767✔
698
                sub_count++;
96,599✔
699

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

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

715
                AddOutputToFreeList(sub_module, result.ctx);
96,598✔
716
                SetupOutput(sub_module->name, sub_module, result.ctx, logger_bits);
96,598✔
717
            }
96,598✔
718
        }
5,349,767✔
719

720
        /* Error is no registered loggers with this name
721
         * were found .*/
722
        if (!sub_count) {
90,744✔
UNCOV
723
            FatalErrorOnInit("No output module named %s", subname);
×
UNCOV
724
            continue;
×
UNCOV
725
        }
×
726
    }
90,744✔
727
}
3,477✔
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✔
UNCOV
754
            continue;
×
UNCOV
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
{
3,581✔
770
    SCConfNode *outputs = SCConfGetNode("outputs");
3,581✔
771
    if (outputs == NULL) {
3,581✔
772
        /* No "outputs" section in the configuration. */
773
        return;
76✔
774
    }
76✔
775

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

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

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

792
        if (strcmp(output->val, "tls-store") == 0) {
29,407✔
793
            tls_store_present = 1;
2,866✔
794
        }
2,866✔
795

796
        enabled = SCConfNodeLookupChildValue(output_config, "enabled");
29,407✔
797
        if (enabled == NULL || !SCConfValIsTrue(enabled)) {
29,407✔
798
            continue;
20,078✔
799
        }
20,078✔
800

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

823
        OutputModule *module;
9,325✔
824
        int count = 0;
9,325✔
825
        TAILQ_FOREACH(module, &output_modules, entries) {
548,520✔
826
            if (strcmp(module->conf_name, output->val) != 0) {
548,520✔
827
                continue;
539,194✔
828
            }
539,194✔
829

830
            count++;
9,326✔
831

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

847
            // TODO if module == parent, find it's children
848
            if (strcmp(output->val, "eve-log") == 0) {
9,325✔
849
                RunModeInitializeEveOutput(output_config, output_ctx, logger_bits);
3,479✔
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);
3,479✔
855
            } else if (strcmp(output->val, "lua") == 0) {
5,865✔
856
                SCLogDebug("handle lua");
18✔
857
                if (output_ctx == NULL)
18✔
UNCOV
858
                    continue;
×
859
                RunModeInitializeLuaOutput(output_config, output_ctx, logger_bits);
18✔
860
                AddOutputToFreeList(module, output_ctx);
18✔
861
            } else {
5,828✔
862
                AddOutputToFreeList(module, output_ctx);
5,828✔
863
                SetupOutput(module->name, module, output_ctx, logger_bits);
5,828✔
864
            }
5,828✔
865
        }
9,325✔
866
        if (count == 0) {
9,324✔
867
            FatalErrorOnInit("No output module named %s", output->val);
1✔
868
            continue;
1✔
869
        }
1✔
870
    }
9,324✔
871

872
    /* Backward compatibility code */
873
    if (!tls_store_present && tls_log_enabled) {
3,504✔
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");
1✔
877

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

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

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

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

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

907
    /* register the logger bits to the app-layer */
908
    AppProto a;
3,504✔
909
    for (a = 0; a < g_alproto_max; a++) {
143,543✔
910
        if (AppLayerParserSupportsFiles(IPPROTO_TCP, a)) {
140,039✔
911
            if (g_file_logger_enabled)
27,992✔
912
                logger_bits[a] |= BIT_U32(LOGGER_FILE);
23,724✔
913
            if (g_filedata_logger_enabled)
27,992✔
914
                logger_bits[a] |= BIT_U32(LOGGER_FILEDATA);
360✔
915
            SCLogDebug("IPPROTO_TCP::%s: g_file_logger_enabled %d g_filedata_logger_enabled %d -> "
27,992✔
916
                       "%08x",
27,992✔
917
                    AppProtoToString(a), g_file_logger_enabled, g_filedata_logger_enabled,
27,992✔
918
                    logger_bits[a]);
27,992✔
919
        }
27,992✔
920
        if (AppLayerParserSupportsFiles(IPPROTO_UDP, a)) {
140,039✔
921
            if (g_file_logger_enabled)
3,490✔
922
                logger_bits[a] |= BIT_U32(LOGGER_FILE);
2,960✔
923
            if (g_filedata_logger_enabled)
3,490✔
924
                logger_bits[a] |= BIT_U32(LOGGER_FILEDATA);
45✔
925
        }
3,490✔
926

927
        if (logger_bits[a] == 0)
140,039✔
928
            continue;
58,430✔
929

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

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

939
        SCLogDebug("logger bits for %s: %08x", AppProtoToString(a), logger_bits[a]);
81,609✔
940
        if (tcp)
81,609✔
941
            AppLayerParserRegisterLoggerBits(IPPROTO_TCP, a, logger_bits[a]);
81,599✔
942
        if (udp)
81,609✔
943
            AppLayerParserRegisterLoggerBits(IPPROTO_UDP, a, logger_bits[a]);
81,301✔
944
    }
81,609✔
945
    OutputSetupActiveLoggers();
3,504✔
946
}
3,504✔
947

948
float threading_detect_ratio = 1;
949

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

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

972
    SCLogDebug("threading.detect-thread-ratio %f", threading_detect_ratio);
2,205✔
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,205✔
979
    if ((SCConfGet("threading.stack-size", &ss)) == 1) {
2,205✔
UNCOV
980
        if (ss != NULL) {
×
UNCOV
981
            if (ParseSizeStringU64(ss, &threading_set_stack_size) < 0) {
×
UNCOV
982
                FatalError("Failed to initialize thread_stack_size output, invalid limit: %s", ss);
×
UNCOV
983
            }
×
984
        }
×
985
    } else {
2,205✔
986
        pthread_attr_t attr;
2,205✔
987
        pthread_attr_init(&attr);
2,205✔
988
        size_t size;
2,205✔
989
        if (pthread_attr_getstacksize(&attr, &size) == 0 && size < 512 * 1024) {
2,205✔
UNCOV
990
            threading_set_stack_size = 512 * 1024;
×
UNCOV
991
            SCLogNotice("thread stack size of %" PRIuMAX " too small: setting to 512k",
×
UNCOV
992
                    (uintmax_t)size);
×
UNCOV
993
        }
×
994
    }
2,205✔
995

996
    SCLogDebug("threading.stack-size %" PRIu64, threading_set_stack_size);
2,205✔
997
}
2,205✔
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