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