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

OISF / suricata / 23374838686

21 Mar 2026 07:29AM UTC coverage: 59.341% (-20.0%) from 79.315%
23374838686

Pull #15075

github

web-flow
Merge 90b4e834f into 6587e363a
Pull Request #15075: Stack 8001 v16.4

38 of 70 new or added lines in 10 files covered. (54.29%)

34165 existing lines in 563 files now uncovered.

119621 of 201584 relevant lines covered (59.34%)

650666.92 hits per line

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

42.54
/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)
UNCOV
120
{
×
UNCOV
121
    switch (runmode) {
×
UNCOV
122
        case RUNMODE_PCAP_DEV:
×
UNCOV
123
            return "PCAP_DEV";
×
UNCOV
124
        case RUNMODE_PCAP_FILE:
×
UNCOV
125
            return "PCAP_FILE";
×
126
        case RUNMODE_PLUGIN:
×
127
            return "PLUGIN";
×
UNCOV
128
        case RUNMODE_NFQ:
×
UNCOV
129
            return "NFQ";
×
UNCOV
130
        case RUNMODE_NFLOG:
×
UNCOV
131
            return "NFLOG";
×
UNCOV
132
        case RUNMODE_IPFW:
×
UNCOV
133
            return "IPFW";
×
UNCOV
134
        case RUNMODE_ERF_FILE:
×
UNCOV
135
            return "ERF_FILE";
×
UNCOV
136
        case RUNMODE_DAG:
×
UNCOV
137
            return "ERF_DAG";
×
UNCOV
138
        case RUNMODE_UNITTEST:
×
UNCOV
139
            return "UNITTEST";
×
UNCOV
140
        case RUNMODE_AFP_DEV:
×
UNCOV
141
            return "AF_PACKET_DEV";
×
UNCOV
142
        case RUNMODE_AFXDP_DEV:
×
UNCOV
143
            return "AF_XDP_DEV";
×
UNCOV
144
        case RUNMODE_NETMAP:
×
145
#ifdef HAVE_NETMAP
146
            return "NETMAP";
147
#else
UNCOV
148
            return "NETMAP(DISABLED)";
×
149
#endif
×
UNCOV
150
        case RUNMODE_UNIX_SOCKET:
×
UNCOV
151
            return "UNIX_SOCKET";
×
UNCOV
152
        case RUNMODE_WINDIVERT:
×
153
#ifdef WINDIVERT
154
            return "WINDIVERT";
155
#else
UNCOV
156
            return "WINDIVERT(DISABLED)";
×
157
#endif
×
UNCOV
158
        case RUNMODE_DPDK:
×
159
#ifdef HAVE_DPDK
160
            return "DPDK";
161
#else
UNCOV
162
            return "DPDK(DISABLED)";
×
UNCOV
163
#endif
×
164
        case RUNMODE_LIB:
×
165
            return "LIB";
×
166

167
        default:
×
168
            FatalError("Unknown runtime mode. Aborting");
×
UNCOV
169
    }
×
UNCOV
170
}
×
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
{
205✔
182
    if (runmode < RUNMODE_USER_MAX) {
205✔
183
        for (int i = 0; i < runmodes[runmode].cnt; i++) {
354✔
184
            if (strcmp(runmodes[runmode].runmodes[i].name, custom_mode) == 0)
151✔
185
                return &runmodes[runmode].runmodes[i];
2✔
186
        }
151✔
187
    }
205✔
188
    return NULL;
203✔
189
}
205✔
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)
UNCOV
200
{
×
UNCOV
201
    return active_runmode;
×
UNCOV
202
}
×
203

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

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

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

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

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

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

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

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

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

372
    return custom_mode;
2✔
373
}
2✔
374

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

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

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

400
    return ips_enabled;
2✔
401
}
2✔
402

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

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

UNCOV
416
    RunMode *mode = RunModeGetCustomMode(runmode, custom_mode);
×
UNCOV
417
    if (mode == NULL) {
×
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 */
UNCOV
426
    if (active_runmode) {
×
UNCOV
427
        SCFree(active_runmode);
×
UNCOV
428
    }
×
UNCOV
429
    active_runmode = SCStrdup(custom_mode);
×
UNCOV
430
    if (unlikely(active_runmode == NULL)) {
×
431
        FatalError("Unable to dup active mode");
×
432
    }
×
433

UNCOV
434
    if (strcasecmp(active_runmode, "autofp") == 0) {
×
UNCOV
435
        TmqhFlowPrintAutofpHandler();
×
UNCOV
436
    }
×
437

UNCOV
438
    mode->RunModeFunc();
×
439

UNCOV
440
    if (local_custom_mode != NULL)
×
441
        SCFree(local_custom_mode);
×
442

443
    /* Check if the alloted queues have at least 1 reader and writer */
UNCOV
444
    TmValidateQueueState();
×
445

UNCOV
446
    if (runmode != RUNMODE_UNIX_SOCKET) {
×
447
        /* spawn management threads */
UNCOV
448
        FlowManagerThreadSpawn();
×
UNCOV
449
        FlowRecyclerThreadSpawn();
×
UNCOV
450
        if (RunModeNeedsBypassManager()) {
×
451
            BypassedFlowManagerThreadSpawn();
×
452
        }
×
UNCOV
453
        StatsSpawnThreads();
×
UNCOV
454
        LogFlushThreads();
×
UNCOV
455
        TmThreadsSealThreads();
×
UNCOV
456
    }
×
UNCOV
457
}
×
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)
UNCOV
467
{
×
UNCOV
468
    return g_runmode_needs_bypass;
×
UNCOV
469
}
×
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
{
203✔
485
    if (RunModeGetCustomMode(runmode, name) != NULL) {
203✔
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,
203✔
492
                     (runmodes[runmode].cnt + 1) * sizeof(RunMode));
203✔
493
    if (ptmp == NULL) {
203✔
494
        SCFree(runmodes[runmode].runmodes);
×
495
        runmodes[runmode].runmodes = NULL;
×
496
        exit(EXIT_FAILURE);
×
497
    }
×
498
    runmodes[runmode].runmodes = ptmp;
203✔
499

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

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

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

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

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

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

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

572
/**
573
 * Cleanup the run mode.
574
 */
575
void RunModeShutDown(void)
UNCOV
576
{
×
UNCOV
577
    RunOutputFreeList();
×
578

UNCOV
579
    OutputPacketShutdown();
×
UNCOV
580
    OutputTxShutdown();
×
UNCOV
581
    OutputFileShutdown();
×
UNCOV
582
    OutputFiledataShutdown();
×
UNCOV
583
    OutputStreamingShutdown();
×
UNCOV
584
    OutputStatsShutdown();
×
UNCOV
585
    OutputFlowShutdown();
×
586

UNCOV
587
    OutputClearActiveLoggers();
×
588

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

624
    if (module->logger_id == LOGGER_ALERT_DEBUG) {
28✔
UNCOV
625
        debuglog_enabled = 1;
×
UNCOV
626
    }
×
627

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

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

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

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

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

686
        SCConfNode *sub_output_config = SCConfNodeLookupChild(type, type->val);
24✔
687
        if (sub_output_config != NULL) {
24✔
688
            const char *enabled = SCConfNodeLookupChildValue(sub_output_config, "enabled");
6✔
689
            if (enabled != NULL && !SCConfValIsTrue(enabled)) {
6✔
UNCOV
690
                continue;
×
UNCOV
691
            }
×
692
        }
6✔
693

694
        /* Now setup all registers logger of this name. */
695
        OutputModule *sub_module;
24✔
696
        TAILQ_FOREACH(sub_module, &output_modules, entries) {
1,392✔
697
            if (strcmp(subname, sub_module->conf_name) == 0) {
1,392✔
698
                sub_count++;
26✔
699

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

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

715
                AddOutputToFreeList(sub_module, result.ctx);
26✔
716
                SetupOutput(sub_module->name, sub_module, result.ctx, logger_bits);
26✔
717
            }
26✔
718
        }
1,392✔
719

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

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

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

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

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

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

UNCOV
757
        AddOutputToFreeList(m, result.ctx);
×
UNCOV
758
        SetupOutput(m->name, m, result.ctx, logger_bits);
×
UNCOV
759
    }
×
UNCOV
760
}
×
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
{
1✔
770
    SCConfNode *outputs = SCConfGetNode("outputs");
1✔
771
    if (outputs == NULL) {
1✔
772
        /* No "outputs" section in the configuration. */
UNCOV
773
        return;
×
UNCOV
774
    }
×
775

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

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

786
        output_config = SCConfNodeLookupChild(output, output->val);
5✔
787
        if (output_config == NULL) {
5✔
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) {
5✔
UNCOV
793
            tls_store_present = 1;
×
UNCOV
794
        }
×
795

796
        enabled = SCConfNodeLookupChildValue(output_config, "enabled");
5✔
797
        if (enabled == NULL || !SCConfValIsTrue(enabled)) {
5✔
UNCOV
798
            continue;
×
UNCOV
799
        }
×
800

801
        if (strcmp(output->val, "file-log") == 0) {
5✔
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✔
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✔
UNCOV
814
            SCLogWarning("Unified2 is no longer supported.");
×
UNCOV
815
            continue;
×
816
        } else if (strcmp(output->val, "dns-log") == 0) {
5✔
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✔
820
            tls_log_enabled = 1;
1✔
821
        }
1✔
822

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

830
            count++;
4✔
831

832
            OutputCtx *output_ctx = NULL;
4✔
833
            if (module->InitFunc != NULL) {
4✔
834
                OutputInitResult r = module->InitFunc(output_config);
4✔
835
                if (!r.ok) {
4✔
UNCOV
836
                    FatalErrorOnInit("output module \"%s\": setup failed", output->val);
×
837
                    continue;
×
838
                } else if (r.ctx == NULL) {
4✔
839
                    continue;
×
840
                }
×
841
                output_ctx = r.ctx;
4✔
842
            } else if (module->InitSubFunc != NULL) {
4✔
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) {
4✔
849
                RunModeInitializeEveOutput(output_config, output_ctx, logger_bits);
1✔
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);
1✔
855
            } else if (strcmp(output->val, "lua") == 0) {
3✔
UNCOV
856
                SCLogDebug("handle lua");
×
UNCOV
857
                if (output_ctx == NULL)
×
858
                    continue;
×
UNCOV
859
                RunModeInitializeLuaOutput(output_config, output_ctx, logger_bits);
×
UNCOV
860
                AddOutputToFreeList(module, output_ctx);
×
861
            } else {
3✔
862
                AddOutputToFreeList(module, output_ctx);
3✔
863
                SetupOutput(module->name, module, output_ctx, logger_bits);
3✔
864
            }
3✔
865
        }
4✔
866
        if (count == 0) {
5✔
867
            FatalErrorOnInit("No output module named %s", output->val);
1✔
868
            continue;
1✔
869
        }
1✔
870
    }
5✔
871

872
    /* Backward compatibility code */
873
    if (!tls_store_present && tls_log_enabled) {
1✔
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✔
885
                    SCLogWarning("No output module named %s, ignoring", "tls-store");
×
886
                    continue;
×
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✔
893
                        FatalErrorOnInit("output module setup failed");
×
894
                        continue;
×
895
                    } else if (r.ctx == NULL) {
1✔
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;
1✔
909
    for (a = 0; a < g_alproto_max; a++) {
41✔
910
        if (AppLayerParserSupportsFiles(IPPROTO_TCP, a)) {
40✔
911
            if (g_file_logger_enabled)
8✔
912
                logger_bits[a] |= BIT_U32(LOGGER_FILE);
8✔
913
            if (g_filedata_logger_enabled)
8✔
914
                logger_bits[a] |= BIT_U32(LOGGER_FILEDATA);
8✔
915
            SCLogDebug("IPPROTO_TCP::%s: g_file_logger_enabled %d g_filedata_logger_enabled %d -> "
8✔
916
                       "%08x",
8✔
917
                    AppProtoToString(a), g_file_logger_enabled, g_filedata_logger_enabled,
8✔
918
                    logger_bits[a]);
8✔
919
        }
8✔
920
        if (AppLayerParserSupportsFiles(IPPROTO_UDP, a)) {
40✔
921
            if (g_file_logger_enabled)
1✔
922
                logger_bits[a] |= BIT_U32(LOGGER_FILE);
1✔
923
            if (g_filedata_logger_enabled)
1✔
924
                logger_bits[a] |= BIT_U32(LOGGER_FILEDATA);
1✔
925
        }
1✔
926

927
        if (logger_bits[a] == 0)
40✔
928
            continue;
18✔
929

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

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

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

948
float threading_detect_ratio = 1;
949

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

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

972
    SCLogDebug("threading.detect-thread-ratio %f", threading_detect_ratio);
1✔
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;
1✔
979
    if ((SCConfGet("threading.stack-size", &ss)) == 1) {
1✔
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 {
1✔
986
        pthread_attr_t attr;
1✔
987
        pthread_attr_init(&attr);
1✔
988
        size_t size;
1✔
989
        if (pthread_attr_getstacksize(&attr, &size) == 0 && size < 512 * 1024) {
1✔
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
    }
1✔
995

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