Coverage Report

Created: 2026-01-16 07:00

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