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