Coverage Report

Created: 2026-11-12 06:59

next uncovered line (L), next uncovered region (R), next uncovered branch (B)
/src/suricata8/src/runmodes.c
Line
Count
Source
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
0
{
121
0
    switch (runmode) {
122
0
        case RUNMODE_PCAP_DEV:
123
0
            return "PCAP_DEV";
124
0
        case RUNMODE_PCAP_FILE:
125
0
            return "PCAP_FILE";
126
0
        case RUNMODE_PLUGIN:
127
0
            return "PLUGIN";
128
0
        case RUNMODE_NFQ:
129
0
            return "NFQ";
130
0
        case RUNMODE_NFLOG:
131
0
            return "NFLOG";
132
0
        case RUNMODE_IPFW:
133
0
            return "IPFW";
134
0
        case RUNMODE_ERF_FILE:
135
0
            return "ERF_FILE";
136
0
        case RUNMODE_DAG:
137
0
            return "ERF_DAG";
138
0
        case RUNMODE_UNITTEST:
139
0
            return "UNITTEST";
140
0
        case RUNMODE_AFP_DEV:
141
0
            return "AF_PACKET_DEV";
142
0
        case RUNMODE_AFXDP_DEV:
143
0
            return "AF_XDP_DEV";
144
0
        case RUNMODE_NETMAP:
145
#ifdef HAVE_NETMAP
146
            return "NETMAP";
147
#else
148
0
            return "NETMAP(DISABLED)";
149
0
#endif
150
0
        case RUNMODE_UNIX_SOCKET:
151
0
            return "UNIX_SOCKET";
152
0
        case RUNMODE_WINDIVERT:
153
#ifdef WINDIVERT
154
            return "WINDIVERT";
155
#else
156
0
            return "WINDIVERT(DISABLED)";
157
0
#endif
158
0
        case RUNMODE_DPDK:
159
#ifdef HAVE_DPDK
160
            return "DPDK";
161
#else
162
0
            return "DPDK(DISABLED)";
163
0
#endif
164
0
        case RUNMODE_LIB:
165
0
            return "LIB";
166
167
0
        default:
168
0
            FatalError("Unknown runtime mode. Aborting");
169
0
    }
170
0
}
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
607
{
182
607
    if (runmode < RUNMODE_USER_MAX) {
183
1.04k
        for (int i = 0; i < runmodes[runmode].cnt; i++) {
184
447
            if (strcmp(runmodes[runmode].runmodes[i].name, custom_mode) == 0)
185
9
                return &runmodes[runmode].runmodes[i];
186
447
        }
187
607
    }
188
598
    return NULL;
189
607
}
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
0
{
201
0
    return active_runmode;
202
0
}
203
204
bool RunmodeIsWorkers(void)
205
0
{
206
0
    return RunmodeGetActive() && (strcmp(RunmodeGetActive(), "workers") == 0);
207
0
}
208
209
bool RunmodeIsAutofp(void)
210
0
{
211
0
    return RunmodeGetActive() && (strcmp(RunmodeGetActive(), "autofp") == 0);
212
0
}
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
0
{
223
0
    int mainmode = SCRunmodeGet();
224
225
0
    return RunModeTranslateModeToName(mainmode);
226
0
}
227
228
/**
229
 * \brief Register all runmodes in the engine.
230
 */
231
void RunModeRegisterRunModes(void)
232
20
{
233
20
    memset(runmodes, 0, sizeof(runmodes));
234
235
20
    RunModeIdsPcapRegister();
236
20
    RunModeFilePcapRegister();
237
20
    RunModeIpsNFQRegister();
238
20
    RunModeIpsIPFWRegister();
239
20
    RunModeErfFileRegister();
240
20
    RunModeErfDagRegister();
241
20
    RunModeIdsAFPRegister();
242
20
    RunModeIdsAFXDPRegister();
243
20
    RunModeIdsNetmapRegister();
244
20
    RunModeIdsNflogRegister();
245
20
    RunModeUnixSocketRegister();
246
20
    RunModeIpsWinDivertRegister();
247
20
    RunModeDpdkRegister();
248
20
    SCRunModeLibIdsRegister();
249
#ifdef UNITTESTS
250
    UtRunModeRegister();
251
#endif
252
20
}
253
254
/**
255
 * \brief Lists all registered runmodes.
256
 */
257
void RunModeListRunmodes(void)
258
0
{
259
0
    printf("------------------------------------- Runmodes -------------------"
260
0
           "-----------------------\n");
261
262
0
    printf("| %-17s | %-17s | %-10s \n",
263
0
           "RunMode Type", "Custom Mode ", "Description");
264
0
    printf("|-----------------------------------------------------------------"
265
0
           "-----------------------\n");
266
0
    int i = RUNMODE_UNKNOWN + 1;
267
0
    int j = 0;
268
0
    for ( ; i < RUNMODE_USER_MAX; i++) {
269
0
        int mode_displayed = 0;
270
0
        for (j = 0; j < runmodes[i].cnt; j++) {
271
0
            if (mode_displayed == 1) {
272
0
                printf("|                   ----------------------------------------------"
273
0
                       "-----------------------\n");
274
0
                RunMode *runmode = &runmodes[i].runmodes[j];
275
0
                printf("| %-17s | %-17s | %-27s \n",
276
0
                       "",
277
0
                       runmode->name,
278
0
                       runmode->description);
279
0
            } else {
280
0
                RunMode *runmode = &runmodes[i].runmodes[j];
281
0
                printf("| %-17s | %-17s | %-27s \n",
282
0
                       RunModeTranslateModeToName(runmode->runmode),
283
0
                       runmode->name,
284
0
                       runmode->description);
285
0
            }
286
0
            if (mode_displayed == 0)
287
0
                mode_displayed = 1;
288
0
        }
289
0
        if (mode_displayed == 1) {
290
0
            printf("|-----------------------------------------------------------------"
291
0
                   "-----------------------\n");
292
0
        }
293
0
    }
294
0
}
295
296
static const char *RunModeGetConfOrDefault(int capture_mode, const char *capture_plugin_name)
297
4
{
298
4
    const char *custom_mode = NULL;
299
4
    const char *val = NULL;
300
4
    if (SCConfGet("runmode", &val) != 1) {
301
4
        custom_mode = NULL;
302
4
    } else {
303
0
        custom_mode = val;
304
0
    }
305
306
4
    if ((custom_mode == NULL) || (strcmp(custom_mode, "auto") == 0)) {
307
4
        switch (capture_mode) {
308
0
            case RUNMODE_PCAP_DEV:
309
0
                custom_mode = RunModeIdsGetDefaultMode();
310
0
                break;
311
4
            case RUNMODE_PCAP_FILE:
312
4
                custom_mode = RunModeFilePcapGetDefaultMode();
313
4
                break;
314
0
            case RUNMODE_PLUGIN: {
315
0
#ifdef HAVE_PLUGINS
316
0
                SCCapturePlugin *plugin = SCPluginFindCaptureByName(capture_plugin_name);
317
0
                if (plugin == NULL) {
318
0
                    FatalError("No capture plugin found with name %s", capture_plugin_name);
319
0
                }
320
0
                custom_mode = (const char *)plugin->GetDefaultMode();
321
0
#endif
322
0
                break;
323
0
            }
324
0
            case RUNMODE_NFQ:
325
0
                custom_mode = RunModeIpsNFQGetDefaultMode();
326
0
                break;
327
0
            case RUNMODE_IPFW:
328
0
                custom_mode = RunModeIpsIPFWGetDefaultMode();
329
0
                break;
330
0
            case RUNMODE_ERF_FILE:
331
0
                custom_mode = RunModeErfFileGetDefaultMode();
332
0
                break;
333
0
            case RUNMODE_DAG:
334
0
                custom_mode = RunModeErfDagGetDefaultMode();
335
0
                break;
336
0
            case RUNMODE_AFP_DEV:
337
0
                custom_mode = RunModeAFPGetDefaultMode();
338
0
                break;
339
0
            case RUNMODE_AFXDP_DEV:
340
0
                custom_mode = RunModeAFXDPGetDefaultMode();
341
0
                break;
342
0
            case RUNMODE_NETMAP:
343
0
                custom_mode = RunModeNetmapGetDefaultMode();
344
0
                break;
345
0
            case RUNMODE_UNIX_SOCKET:
346
0
                custom_mode = RunModeUnixSocketGetDefaultMode();
347
0
                break;
348
0
            case RUNMODE_NFLOG:
349
0
                custom_mode = RunModeIdsNflogGetDefaultMode();
350
0
                break;
351
#ifdef WINDIVERT
352
            case RUNMODE_WINDIVERT:
353
                custom_mode = RunModeIpsWinDivertGetDefaultMode();
354
                break;
355
#endif
356
#ifdef HAVE_DPDK
357
            case RUNMODE_DPDK:
358
                custom_mode = RunModeDpdkGetDefaultMode();
359
                break;
360
#endif
361
0
            case RUNMODE_LIB:
362
0
                custom_mode = SCRunModeLibGetDefaultMode();
363
0
                break;
364
0
            default:
365
0
                return NULL;
366
4
        }
367
4
    } else {
368
        /* Add compatibility with old 'worker' name */
369
0
        if (!strcmp("worker", custom_mode)) {
370
0
            SCLogWarning("'worker' mode have been renamed "
371
0
                         "to 'workers', please modify your setup.");
372
0
            custom_mode = "workers";
373
0
        }
374
0
    }
375
376
4
    return custom_mode;
377
4
}
378
379
int RunModeEngineIsIPS(int capture_mode, const char *runmode, const char *capture_plugin_name)
380
11
{
381
11
    if (runmode == NULL) {
382
11
        runmode = RunModeGetConfOrDefault(capture_mode, capture_plugin_name);
383
11
        if (runmode == NULL) // non-standard runmode
384
2
            return 0;
385
11
    }
386
387
9
    RunMode *mode = RunModeGetCustomMode(capture_mode, runmode);
388
9
    if (mode == NULL) {
389
0
        return 0;
390
0
    }
391
392
9
    int ips_enabled = 0;
393
9
    if (mode->RunModeIsIPSEnabled != NULL) {
394
0
        ips_enabled = mode->RunModeIsIPSEnabled();
395
0
        if (ips_enabled == 1) {
396
0
            extern uint16_t g_livedev_mask;
397
0
            if (g_livedev_mask != 0 && LiveGetDeviceCount() > 0) {
398
0
                SCLogWarning("disabling livedev.use-for-tracking with IPS mode. See ticket #6726.");
399
0
                g_livedev_mask = 0;
400
0
            }
401
0
        }
402
0
    }
403
404
9
    return ips_enabled;
405
9
}
406
407
/**
408
 */
409
void RunModeDispatch(int runmode, const char *custom_mode, const char *capture_plugin_name,
410
        const char *capture_plugin_args)
411
0
{
412
0
    char *local_custom_mode = NULL;
413
414
0
    if (custom_mode == NULL) {
415
0
        custom_mode = RunModeGetConfOrDefault(runmode, capture_plugin_name);
416
0
        if (custom_mode == NULL)
417
0
            FatalError("Unknown runtime mode. Aborting");
418
0
    }
419
420
0
    RunMode *mode = RunModeGetCustomMode(runmode, custom_mode);
421
0
    if (mode == NULL) {
422
0
        SCLogError("The custom type \"%s\" doesn't exist "
423
0
                   "for this runmode type \"%s\".  Please use --list-runmodes to "
424
0
                   "see available custom types for this runmode",
425
0
                custom_mode, RunModeTranslateModeToName(runmode));
426
0
        exit(EXIT_FAILURE);
427
0
    }
428
429
    /* Export the custom mode */
430
0
    if (active_runmode) {
431
0
        SCFree(active_runmode);
432
0
    }
433
0
    active_runmode = SCStrdup(custom_mode);
434
0
    if (unlikely(active_runmode == NULL)) {
435
0
        FatalError("Unable to dup active mode");
436
0
    }
437
438
0
    if (strcasecmp(active_runmode, "autofp") == 0) {
439
0
        TmqhFlowPrintAutofpHandler();
440
0
    }
441
442
0
    mode->RunModeFunc();
443
444
0
    if (local_custom_mode != NULL)
445
0
        SCFree(local_custom_mode);
446
447
    /* Check if the alloted queues have at least 1 reader and writer */
448
0
    TmValidateQueueState();
449
450
0
    if (runmode != RUNMODE_UNIX_SOCKET) {
451
        /* spawn management threads */
452
0
        FlowManagerThreadSpawn();
453
0
        FlowRecyclerThreadSpawn();
454
0
        if (RunModeNeedsBypassManager()) {
455
0
            BypassedFlowManagerThreadSpawn();
456
0
        }
457
0
        StatsSpawnThreads();
458
0
        LogFlushThreads();
459
0
        TmThreadsSealThreads();
460
0
    }
461
0
}
462
463
static int g_runmode_needs_bypass = 0;
464
465
void RunModeEnablesBypassManager(void)
466
0
{
467
0
    g_runmode_needs_bypass = 1;
468
0
}
469
470
int RunModeNeedsBypassManager(void)
471
0
{
472
0
    return g_runmode_needs_bypass;
473
0
}
474
475
476
477
/**
478
 * \brief Registers a new runmode.
479
 *
480
 * \param runmode     Runmode type.
481
 * \param name        Custom mode for this specific runmode type.  Within each
482
 *                    runmode type, each custom name is a primary key.
483
 * \param description Description for this runmode.
484
 * \param RunModeFunc The function to be run for this runmode.
485
 */
486
void RunModeRegisterNewRunMode(enum SCRunModes runmode, const char *name, const char *description,
487
        int (*RunModeFunc)(void), int (*RunModeIsIPSEnabled)(void))
488
279
{
489
279
    if (RunModeGetCustomMode(runmode, name) != NULL) {
490
0
        FatalError("runmode '%s' has already "
491
0
                   "been registered. Please use an unique name.",
492
0
                name);
493
0
    }
494
495
279
    void *ptmp = SCRealloc(runmodes[runmode].runmodes,
496
279
                     (runmodes[runmode].cnt + 1) * sizeof(RunMode));
497
279
    if (ptmp == NULL) {
498
0
        SCFree(runmodes[runmode].runmodes);
499
0
        runmodes[runmode].runmodes = NULL;
500
0
        exit(EXIT_FAILURE);
501
0
    }
502
279
    runmodes[runmode].runmodes = ptmp;
503
504
279
    RunMode *mode = &runmodes[runmode].runmodes[runmodes[runmode].cnt];
505
279
    runmodes[runmode].cnt++;
506
279
    memset(mode, 0x00, sizeof(*mode));
507
508
279
    mode->runmode = runmode;
509
279
    mode->name = SCStrdup(name);
510
279
    if (unlikely(mode->name == NULL)) {
511
0
        FatalError("Failed to allocate string");
512
0
    }
513
279
    mode->description = SCStrdup(description);
514
279
    if (unlikely(mode->description == NULL)) {
515
0
        FatalError("Failed to allocate string");
516
0
    }
517
279
    mode->RunModeFunc = RunModeFunc;
518
279
    mode->RunModeIsIPSEnabled = RunModeIsIPSEnabled;
519
279
}
520
521
/**
522
 * Setup the outputs for this run mode.
523
 *
524
 * \param tv The ThreadVars for the thread the outputs will be
525
 * appended to.
526
 */
527
static void RunOutputFreeList(void)
528
0
{
529
0
    OutputFreeList *output;
530
0
    while ((output = TAILQ_FIRST(&output_free_list))) {
531
0
        TAILQ_REMOVE(&output_free_list, output, entries);
532
533
0
        SCLogDebug("output %s %p %p", output->output_module->name, output, output->output_ctx);
534
0
        if (output->output_ctx != NULL && output->output_ctx->DeInit != NULL)
535
0
            output->output_ctx->DeInit(output->output_ctx);
536
0
        SCFree(output);
537
0
    }
538
0
}
539
540
static int file_logger_count = 0;
541
static int filedata_logger_count = 0;
542
543
int RunModeOutputFiledataEnabled(void)
544
4
{
545
4
    return filedata_logger_count > 0;
546
4
}
547
548
bool IsRunModeSystem(enum SCRunModes run_mode_to_check)
549
0
{
550
0
    switch (run_mode_to_check) {
551
0
        case RUNMODE_PCAP_FILE:
552
0
        case RUNMODE_ERF_FILE:
553
0
        case RUNMODE_ENGINE_ANALYSIS:
554
0
            return false;
555
0
            break;
556
0
        default:
557
0
            return true;
558
0
    }
559
0
}
560
561
bool IsRunModeOffline(enum SCRunModes run_mode_to_check)
562
0
{
563
0
    switch(run_mode_to_check) {
564
0
        case RUNMODE_CONF_TEST:
565
0
        case RUNMODE_PCAP_FILE:
566
0
        case RUNMODE_ERF_FILE:
567
0
        case RUNMODE_ENGINE_ANALYSIS:
568
0
        case RUNMODE_UNIX_SOCKET:
569
0
            return true;
570
0
            break;
571
0
        default:
572
0
            return false;
573
0
    }
574
0
}
575
576
/**
577
 * Cleanup the run mode.
578
 */
579
void RunModeShutDown(void)
580
0
{
581
0
    RunOutputFreeList();
582
583
0
    OutputPacketShutdown();
584
0
    OutputTxShutdown();
585
0
    OutputFileShutdown();
586
0
    OutputFiledataShutdown();
587
0
    OutputStreamingShutdown();
588
0
    OutputStatsShutdown();
589
0
    OutputFlowShutdown();
590
591
0
    OutputClearActiveLoggers();
592
593
    /* Reset logger counts. */
594
0
    file_logger_count = 0;
595
0
    filedata_logger_count = 0;
596
0
}
597
598
/** \internal
599
 *  \brief add Sub RunModeOutput to list for Submodule so we can free
600
 *         the output ctx at shutdown and unix socket reload */
601
static void AddOutputToFreeList(OutputModule *module, OutputCtx *output_ctx)
602
124
{
603
124
    OutputFreeList *fl_output = SCCalloc(1, sizeof(OutputFreeList));
604
124
    if (unlikely(fl_output == NULL))
605
0
        return;
606
124
    fl_output->output_module = module;
607
124
    fl_output->output_ctx = output_ctx;
608
124
    TAILQ_INSERT_TAIL(&output_free_list, fl_output, entries);
609
124
}
610
611
/** \brief Turn output into thread module */
612
static void SetupOutput(
613
        const char *name, OutputModule *module, OutputCtx *output_ctx, LoggerId *logger_bits)
614
62
{
615
    /* flow logger doesn't run in the packet path */
616
62
    if (module->FlowLogFunc) {
617
4
        SCOutputRegisterFlowLogger(module->name, module->FlowLogFunc, output_ctx,
618
4
                module->ThreadInit, module->ThreadDeinit);
619
4
        return;
620
4
    }
621
    /* stats logger doesn't run in the packet path */
622
58
    if (module->StatsLogFunc) {
623
0
        OutputRegisterStatsLogger(module->name, module->StatsLogFunc, output_ctx,
624
0
                module->ThreadInit, module->ThreadDeinit);
625
0
        return;
626
0
    }
627
628
58
    if (module->logger_id == LOGGER_ALERT_DEBUG) {
629
0
        debuglog_enabled = 1;
630
0
    }
631
632
58
    if (module->PacketLogFunc) {
633
8
        SCLogDebug("%s is a packet logger", module->name);
634
8
        SCOutputRegisterPacketLogger(module->logger_id, module->name, module->PacketLogFunc,
635
8
                module->PacketConditionFunc, output_ctx, module->ThreadInit, module->ThreadDeinit);
636
50
    } else if (module->TxLogFunc) {
637
46
        SCLogDebug("%s is a tx logger", module->name);
638
46
        SCOutputRegisterTxLogger(module->logger_id, module->name, module->alproto,
639
46
                module->TxLogFunc, output_ctx, module->tc_log_progress, module->ts_log_progress,
640
46
                module->TxLogCondition, module->ThreadInit, module->ThreadDeinit);
641
        /* Not used with wild card loggers */
642
46
        if (module->alproto != ALPROTO_UNKNOWN) {
643
44
            logger_bits[module->alproto] |= BIT_U32(module->logger_id);
644
44
        }
645
46
    } else if (module->FiledataLogFunc) {
646
2
        SCLogDebug("%s is a filedata logger", module->name);
647
2
        SCOutputRegisterFiledataLogger(module->logger_id, module->name, module->FiledataLogFunc,
648
2
                output_ctx, module->ThreadInit, module->ThreadDeinit);
649
2
        filedata_logger_count++;
650
2
    } else if (module->FileLogFunc) {
651
2
        SCLogDebug("%s is a file logger", module->name);
652
2
        SCOutputRegisterFileLogger(module->logger_id, module->name, module->FileLogFunc, output_ctx,
653
2
                module->ThreadInit, module->ThreadDeinit);
654
2
        file_logger_count++;
655
2
    } else if (module->StreamingLogFunc) {
656
0
        SCLogDebug("%s is a streaming logger", module->name);
657
0
        SCOutputRegisterStreamingLogger(module->logger_id, module->name, module->StreamingLogFunc,
658
0
                output_ctx, module->stream_type, module->ThreadInit, module->ThreadDeinit);
659
0
    } else {
660
0
        SCLogError("Unknown logger type: name=%s", module->name);
661
0
    }
662
58
}
663
664
static void RunModeInitializeEveOutput(
665
        SCConfNode *conf, OutputCtx *parent_ctx, LoggerId *logger_bits)
666
4
{
667
4
    SCConfNode *types = SCConfNodeLookupChild(conf, "types");
668
4
    SCLogDebug("types %p", types);
669
4
    if (types == NULL) {
670
0
        return;
671
0
    }
672
4
    if (!SCConfNodeIsSequence(types)) {
673
0
        FatalError("output types should be a sequence");
674
0
    }
675
676
4
    SCConfNode *type = NULL;
677
96
    TAILQ_FOREACH(type, &types->head, next) {
678
96
        int sub_count = 0;
679
96
        char subname[256];
680
681
96
        if (strcmp(type->val, "ikev2") == 0) {
682
0
            SCLogWarning("eve module 'ikev2' has been replaced by 'ike'");
683
0
            strlcpy(subname, "eve-log.ike", sizeof(subname));
684
96
        } else {
685
96
            snprintf(subname, sizeof(subname), "eve-log.%s", type->val);
686
96
        }
687
688
96
        SCLogConfig("enabling 'eve-log' module '%s'", type->val);
689
690
96
        SCConfNode *sub_output_config = SCConfNodeLookupChild(type, type->val);
691
96
        if (sub_output_config != NULL) {
692
24
            const char *enabled = SCConfNodeLookupChildValue(sub_output_config, "enabled");
693
24
            if (enabled != NULL && !SCConfValIsTrue(enabled)) {
694
0
                continue;
695
0
            }
696
24
        }
697
698
        /* Now setup all registers logger of this name. */
699
96
        OutputModule *sub_module;
700
5.80k
        TAILQ_FOREACH(sub_module, &output_modules, entries) {
701
5.80k
            if (strcmp(subname, sub_module->conf_name) == 0) {
702
104
                sub_count++;
703
704
104
                if (sub_module->parent_name == NULL ||
705
104
                        strcmp(sub_module->parent_name, "eve-log") != 0) {
706
0
                    FatalError("bad parent for %s", subname);
707
0
                }
708
104
                if (sub_module->InitSubFunc == NULL) {
709
0
                    FatalError("bad sub-module for %s", subname);
710
0
                }
711
712
                /* pass on parent output_ctx */
713
104
                OutputInitResult result =
714
104
                    sub_module->InitSubFunc(sub_output_config, parent_ctx);
715
104
                if (!result.ok || result.ctx == NULL) {
716
0
                    FatalError("unable to initialize sub-module %s", subname);
717
0
                }
718
719
104
                AddOutputToFreeList(sub_module, result.ctx);
720
104
                SetupOutput(sub_module->name, sub_module, result.ctx, logger_bits);
721
104
            }
722
5.80k
        }
723
724
        /* Error is no registered loggers with this name
725
         * were found .*/
726
96
        if (!sub_count) {
727
0
            FatalErrorOnInit("No output module named %s", subname);
728
0
            continue;
729
0
        }
730
96
    }
731
4
}
732
733
static void RunModeInitializeLuaOutput(
734
        SCConfNode *conf, OutputCtx *parent_ctx, LoggerId *logger_bits)
735
0
{
736
0
    OutputModule *lua_module = OutputGetModuleByConfName("lua");
737
0
    BUG_ON(lua_module == NULL);
738
739
0
    SCConfNode *scripts = SCConfNodeLookupChild(conf, "scripts");
740
0
    BUG_ON(scripts == NULL); //TODO
741
742
0
    OutputModule *m;
743
0
    TAILQ_FOREACH(m, &parent_ctx->submodules, entries) {
744
0
        SCLogDebug("m %p %s:%s", m, m->name, m->conf_name);
745
746
0
        SCConfNode *script = NULL;
747
0
        TAILQ_FOREACH(script, &scripts->head, next) {
748
0
            SCLogDebug("script %s", script->val);
749
0
            if (strcmp(script->val, m->conf_name) == 0) {
750
0
                break;
751
0
            }
752
0
        }
753
0
        BUG_ON(script == NULL);
754
755
        /* pass on parent output_ctx */
756
0
        OutputInitResult result = m->InitSubFunc(script, parent_ctx);
757
0
        if (!result.ok || result.ctx == NULL) {
758
0
            continue;
759
0
        }
760
761
0
        AddOutputToFreeList(m, result.ctx);
762
0
        SetupOutput(m->name, m, result.ctx, logger_bits);
763
0
    }
764
0
}
765
766
extern bool g_file_logger_enabled;
767
extern bool g_filedata_logger_enabled;
768
769
/**
770
 * Initialize the output modules.
771
 */
772
void RunModeInitializeOutputs(void)
773
6
{
774
6
    SCConfNode *outputs = SCConfGetNode("outputs");
775
6
    if (outputs == NULL) {
776
        /* No "outputs" section in the configuration. */
777
2
        return;
778
2
    }
779
780
4
    SCConfNode *output, *output_config;
781
4
    const char *enabled;
782
4
    char tls_log_enabled = 0;
783
4
    char tls_store_present = 0;
784
785
    // g_alproto_max is set to its final value
786
4
    LoggerId logger_bits[g_alproto_max];
787
4
    memset(logger_bits, 0, g_alproto_max * sizeof(LoggerId));
788
18
    TAILQ_FOREACH(output, &outputs->head, next) {
789
790
18
        output_config = SCConfNodeLookupChild(output, output->val);
791
18
        if (output_config == NULL) {
792
            /* Shouldn't happen. */
793
0
            FatalError("Failed to lookup configuration child node: %s", output->val);
794
0
        }
795
796
18
        if (strcmp(output->val, "tls-store") == 0) {
797
0
            tls_store_present = 1;
798
0
        }
799
800
18
        enabled = SCConfNodeLookupChildValue(output_config, "enabled");
801
18
        if (enabled == NULL || !SCConfValIsTrue(enabled)) {
802
0
            continue;
803
0
        }
804
805
18
        if (strcmp(output->val, "file-log") == 0) {
806
0
            SCLogWarning("file-log is no longer supported,"
807
0
                         " use eve.files instead "
808
0
                         "(see ticket #2376"
809
0
                         " for an explanation)");
810
0
            continue;
811
18
        } else if (strncmp(output->val, "unified-", sizeof("unified-") - 1) == 0) {
812
0
            SCLogWarning("Unified1 is no longer supported,"
813
0
                         " use Unified2 instead "
814
0
                         "(see ticket #353"
815
0
                         " for an explanation)");
816
0
            continue;
817
18
        } else if (strncmp(output->val, "unified2-", sizeof("unified2-") - 1) == 0) {
818
0
            SCLogWarning("Unified2 is no longer supported.");
819
0
            continue;
820
18
        } else if (strcmp(output->val, "dns-log") == 0) {
821
0
            SCLogWarning("dns-log is not longer available as of Suricata 5.0");
822
0
            continue;
823
18
        } else if (strcmp(output->val, "tls-log") == 0) {
824
4
            tls_log_enabled = 1;
825
4
        }
826
827
18
        OutputModule *module;
828
18
        int count = 0;
829
1.08k
        TAILQ_FOREACH(module, &output_modules, entries) {
830
1.08k
            if (strcmp(module->conf_name, output->val) != 0) {
831
1.07k
                continue;
832
1.07k
            }
833
834
16
            count++;
835
836
16
            OutputCtx *output_ctx = NULL;
837
16
            if (module->InitFunc != NULL) {
838
16
                OutputInitResult r = module->InitFunc(output_config);
839
16
                if (!r.ok) {
840
0
                    FatalErrorOnInit("output module \"%s\": setup failed", output->val);
841
0
                    continue;
842
16
                } else if (r.ctx == NULL) {
843
0
                    continue;
844
0
                }
845
16
                output_ctx = r.ctx;
846
16
            } else if (module->InitSubFunc != NULL) {
847
0
                SCLogInfo("skipping submodule");
848
0
                continue;
849
0
            }
850
851
            // TODO if module == parent, find it's children
852
16
            if (strcmp(output->val, "eve-log") == 0) {
853
4
                RunModeInitializeEveOutput(output_config, output_ctx, logger_bits);
854
855
                /* add 'eve-log' to free list as it's the owner of the
856
                 * main output ctx from which the sub-modules share the
857
                 * LogFileCtx */
858
4
                AddOutputToFreeList(module, output_ctx);
859
12
            } else if (strcmp(output->val, "lua") == 0) {
860
0
                SCLogDebug("handle lua");
861
0
                if (output_ctx == NULL)
862
0
                    continue;
863
0
                RunModeInitializeLuaOutput(output_config, output_ctx, logger_bits);
864
0
                AddOutputToFreeList(module, output_ctx);
865
12
            } else {
866
12
                AddOutputToFreeList(module, output_ctx);
867
12
                SetupOutput(module->name, module, output_ctx, logger_bits);
868
12
            }
869
16
        }
870
18
        if (count == 0) {
871
2
            FatalErrorOnInit("No output module named %s", output->val);
872
2
            continue;
873
2
        }
874
18
    }
875
876
    /* Backward compatibility code */
877
4
    if (!tls_store_present && tls_log_enabled) {
878
        /* old YAML with no "tls-store" in outputs. "tls-log" value needs
879
         * to be started using 'tls-log' config as own config */
880
4
        SCLogWarning("Please use 'tls-store' in YAML to configure TLS storage");
881
882
18
        TAILQ_FOREACH(output, &outputs->head, next) {
883
18
            output_config = SCConfNodeLookupChild(output, output->val);
884
885
18
            if (strcmp(output->val, "tls-log") == 0) {
886
887
4
                OutputModule *module = OutputGetModuleByConfName("tls-store");
888
4
                if (module == NULL) {
889
0
                    SCLogWarning("No output module named %s, ignoring", "tls-store");
890
0
                    continue;
891
0
                }
892
893
4
                OutputCtx *output_ctx = NULL;
894
4
                if (module->InitFunc != NULL) {
895
4
                    OutputInitResult r = module->InitFunc(output_config);
896
4
                    if (!r.ok) {
897
0
                        FatalErrorOnInit("output module setup failed");
898
0
                        continue;
899
4
                    } else if (r.ctx == NULL) {
900
0
                        continue;
901
0
                    }
902
4
                    output_ctx = r.ctx;
903
4
                }
904
905
4
                AddOutputToFreeList(module, output_ctx);
906
4
                SetupOutput(module->name, module, output_ctx, logger_bits);
907
4
            }
908
18
        }
909
4
    }
910
911
    /* register the logger bits to the app-layer */
912
4
    AppProto a;
913
166
    for (a = 0; a < g_alproto_max; a++) {
914
162
        if (AppLayerParserSupportsFiles(IPPROTO_TCP, a)) {
915
32
            if (g_file_logger_enabled)
916
32
                logger_bits[a] |= BIT_U32(LOGGER_FILE);
917
32
            if (g_filedata_logger_enabled)
918
32
                logger_bits[a] |= BIT_U32(LOGGER_FILEDATA);
919
32
            SCLogDebug("IPPROTO_TCP::%s: g_file_logger_enabled %d g_filedata_logger_enabled %d -> "
920
32
                       "%08x",
921
32
                    AppProtoToString(a), g_file_logger_enabled, g_filedata_logger_enabled,
922
32
                    logger_bits[a]);
923
32
        }
924
162
        if (AppLayerParserSupportsFiles(IPPROTO_UDP, a)) {
925
4
            if (g_file_logger_enabled)
926
4
                logger_bits[a] |= BIT_U32(LOGGER_FILE);
927
4
            if (g_filedata_logger_enabled)
928
4
                logger_bits[a] |= BIT_U32(LOGGER_FILEDATA);
929
4
        }
930
931
162
        if (logger_bits[a] == 0)
932
74
            continue;
933
934
88
        const int tcp = AppLayerParserProtocolHasLogger(IPPROTO_TCP, a) | (g_file_logger_enabled) |
935
88
                        (g_filedata_logger_enabled);
936
88
        const int udp = AppLayerParserProtocolHasLogger(IPPROTO_UDP, a) | (g_file_logger_enabled) |
937
88
                        (g_filedata_logger_enabled);
938
88
        SCLogDebug("tcp %d udp %d", tcp, udp);
939
940
88
        SCLogDebug("logger for %s: %s %s", AppProtoToString(a),
941
88
                tcp ? "true" : "false", udp ? "true" : "false");
942
943
88
        SCLogDebug("logger bits for %s: %08x", AppProtoToString(a), logger_bits[a]);
944
88
        if (tcp)
945
88
            AppLayerParserRegisterLoggerBits(IPPROTO_TCP, a, logger_bits[a]);
946
88
        if (udp)
947
88
            AppLayerParserRegisterLoggerBits(IPPROTO_UDP, a, logger_bits[a]);
948
88
    }
949
4
    OutputSetupActiveLoggers();
950
4
}
951
952
float threading_detect_ratio = 1;
953
954
/**
955
 * Initialize multithreading settings.
956
 */
957
void RunModeInitializeThreadSettings(void)
958
2
{
959
2
    int affinity = 0;
960
2
    if ((SCConfGetBool("threading.set-cpu-affinity", &affinity)) == 0) {
961
2
        threading_set_cpu_affinity = false;
962
2
    } else {
963
0
        threading_set_cpu_affinity = affinity == 1;
964
0
    }
965
966
    /* try to get custom cpu mask value if needed */
967
2
    if (threading_set_cpu_affinity) {
968
0
        AffinitySetupLoadFromConfig();
969
0
    }
970
2
    if ((SCConfGetFloat("threading.detect-thread-ratio", &threading_detect_ratio)) != 1) {
971
2
        if (SCConfGetNode("threading.detect-thread-ratio") != NULL)
972
0
            WarnInvalidConfEntry("threading.detect-thread-ratio", "%s", "1");
973
2
        threading_detect_ratio = 1;
974
2
    }
975
976
2
    SCLogDebug("threading.detect-thread-ratio %f", threading_detect_ratio);
977
978
    /*
979
     * Check if there's a configuration setting for the per-thread stack size
980
     * in case the default per-thread stack size is to be adjusted
981
     */
982
2
    const char *ss = NULL;
983
2
    if ((SCConfGet("threading.stack-size", &ss)) == 1) {
984
0
        if (ss != NULL) {
985
0
            if (ParseSizeStringU64(ss, &threading_set_stack_size) < 0) {
986
0
                FatalError("Failed to initialize thread_stack_size output, invalid limit: %s", ss);
987
0
            }
988
0
        }
989
2
    } else {
990
2
        pthread_attr_t attr;
991
2
        pthread_attr_init(&attr);
992
2
        size_t size;
993
2
        if (pthread_attr_getstacksize(&attr, &size) == 0 && size < 512 * 1024) {
994
0
            threading_set_stack_size = 512 * 1024;
995
0
            SCLogNotice("thread stack size of %" PRIuMAX " too small: setting to 512k",
996
0
                    (uintmax_t)size);
997
0
        }
998
2
    }
999
1000
2
    SCLogDebug("threading.stack-size %" PRIu64, threading_set_stack_size);
1001
2
}