1 //--------------------------------------------------------------------------
2 // Copyright (C) 2014-2021 Cisco and/or its affiliates. All rights reserved.
3 //
4 // This program is free software; you can redistribute it and/or modify it
5 // under the terms of the GNU General Public License Version 2 as published
6 // by the Free Software Foundation.  You may not use, modify or distribute
7 // this program under any other version of the GNU General Public License.
8 //
9 // This program is distributed in the hope that it will be useful, but
10 // WITHOUT ANY WARRANTY; without even the implied warranty of
11 // MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
12 // General Public License for more details.
13 //
14 // You should have received a copy of the GNU General Public License along
15 // with this program; if not, write to the Free Software Foundation, Inc.,
16 // 51 Franklin Street, Fifth Floor, Boston, MA  02110-1301, USA.
17 //--------------------------------------------------------------------------
18 
19 // modules.cc author Russ Combs <rucombs@cisco.com>
20 
21 #ifdef HAVE_CONFIG_H
22 #include "config.h"
23 #endif
24 
25 #include "modules.h"
26 
27 #include <sys/resource.h>
28 
29 #include "codecs/codec_module.h"
30 #include "detection/detection_module.h"
31 #include "detection/fp_config.h"
32 #include "detection/rules.h"
33 #include "detection/tag.h"
34 #include "filters/detection_filter.h"
35 #include "filters/rate_filter.h"
36 #include "filters/sfrf.h"
37 #include "filters/sfthd.h"
38 #include "filters/sfthreshold.h"
39 #include "flow/ha_module.h"
40 #include "framework/module.h"
41 #include "host_tracker/host_tracker_module.h"
42 #include "host_tracker/host_cache_module.h"
43 #include "latency/latency_module.h"
44 #include "log/messages.h"
45 #include "managers/module_manager.h"
46 #include "managers/plugin_manager.h"
47 #include "memory/memory_module.h"
48 #include "packet_io/active.h"
49 #include "packet_io/sfdaq_module.h"
50 #include "packet_tracer/packet_tracer_module.h"
51 #include "parser/config_file.h"
52 #include "parser/parse_conf.h"
53 #include "parser/parse_ip.h"
54 #include "parser/parser.h"
55 #include "parser/vars.h"
56 #include "payload_injector/payload_injector_module.h"
57 #include "profiler/profiler.h"
58 #include "search_engines/pat_stats.h"
59 #include "side_channel/side_channel_module.h"
60 #include "sfip/sf_ipvar.h"
61 #include "stream/stream.h"
62 #include "target_based/host_attributes.h"
63 #include "target_based/snort_protocols.h"
64 #include "trace/trace_module.h"
65 
66 #include "snort_config.h"
67 #include "snort_module.h"
68 #include "thread_config.h"
69 
70 using namespace snort;
71 using namespace std;
72 
73 //-------------------------------------------------------------------------
74 // event queue module
75 //-------------------------------------------------------------------------
76 
77 static const Parameter event_queue_params[] =
78 {
79     { "max_queue", Parameter::PT_INT, "1:max32", "8",
80       "maximum events to queue" },
81 
82     { "log", Parameter::PT_INT, "1:max32", "3",
83       "maximum events to log" },
84 
85     { "order_events", Parameter::PT_ENUM,
86       "priority|content_length", "content_length",
87       "criteria for ordering incoming events" },
88 
89     { "process_all_events", Parameter::PT_BOOL, nullptr, "false",
90       "process just first action group or all action groups" },
91 
92     { nullptr, Parameter::PT_MAX, nullptr, nullptr, nullptr }
93 };
94 
95 #define event_queue_help \
96     "configure event queue parameters"
97 
98 class EventQueueModule : public Module
99 {
100 public:
EventQueueModule()101     EventQueueModule() : Module("event_queue", event_queue_help, event_queue_params) { }
102     bool set(const char*, Value&, SnortConfig*) override;
103     bool end(const char*, int, SnortConfig*) override;
104 
get_usage() const105     Usage get_usage() const override
106     { return CONTEXT; }
107 };
108 
set(const char *,Value & v,SnortConfig * sc)109 bool EventQueueModule::set(const char*, Value& v, SnortConfig* sc)
110 {
111     EventQueueConfig* eq = sc->event_queue_config;
112 
113     if ( v.is("max_queue") )
114         eq->max_events = v.get_uint32();
115 
116     else if ( v.is("log") )
117         eq->log_events = v.get_uint32();
118 
119     else if ( v.is("order_events") )
120     {
121         if ( v.get_uint8() )
122             eq->order = SNORT_EVENTQ_CONTENT_LEN;
123         else
124             eq->order = SNORT_EVENTQ_PRIORITY;
125     }
126     else if ( v.is("process_all_events") )
127         eq->process_all_events = v.get_bool();
128 
129     return true;
130 }
131 
end(const char *,int,SnortConfig * sc)132 bool EventQueueModule::end(const char*, int, SnortConfig* sc)
133 {
134     EventQueueConfig* eq = sc->event_queue_config;
135 
136     if ( eq->max_events < eq->log_events )
137         eq->max_events = eq->log_events;
138 
139     return true;
140 }
141 
142 //-------------------------------------------------------------------------
143 // search engine module
144 //-------------------------------------------------------------------------
145 
146 function<const char*()> get_search_methods = []()
__anonb3a7072e0102() 147 { return PluginManager::get_available_plugins(PT_SEARCH_ENGINE); };
148 
149 static const Parameter search_engine_params[] =
150 {
151     { "bleedover_port_limit", Parameter::PT_INT, "1:max32", "1024",
152       "maximum ports in rule before demotion to any-any port group" },
153 
154     { "bleedover_warnings_enabled", Parameter::PT_BOOL, nullptr, "false",
155       "print warning if a rule is demoted to any-any port group" },
156 
157     { "enable_single_rule_group", Parameter::PT_BOOL, nullptr, "false",
158       "put all rules into one group" },
159 
160     { "debug", Parameter::PT_BOOL, nullptr, "false",
161       "print verbose fast pattern info" },
162 
163     { "debug_print_nocontent_rule_tests", Parameter::PT_BOOL, nullptr, "false",
164       "print rule group info during packet evaluation" },
165 
166     { "debug_print_rule_group_build_details", Parameter::PT_BOOL, nullptr, "false",
167       "print rule group info during compilation" },
168 
169     { "debug_print_rule_groups_uncompiled", Parameter::PT_BOOL, nullptr, "false",
170       "prints uncompiled rule group information" },
171 
172     { "debug_print_rule_groups_compiled", Parameter::PT_BOOL, nullptr, "false",
173       "prints compiled rule group information" },
174 
175     { "max_pattern_len", Parameter::PT_INT, "0:max32", "0",
176       "truncate patterns when compiling into state machine (0 means no maximum)" },
177 
178     { "max_queue_events", Parameter::PT_INT, "2:100", "5",  // upper bound is MAX_EVENT_MATCH
179       "maximum number of matching fast pattern states to queue per packet" },
180 
181     { "detect_raw_tcp", Parameter::PT_BOOL, nullptr, "false",
182       "detect on TCP payload before reassembly" },
183 
184     { "search_method", Parameter::PT_DYNAMIC, (void*)&get_search_methods, "ac_bnfa",
185       "set fast pattern algorithm - choose available search engine" },
186 
187     { "offload_search_method", Parameter::PT_DYNAMIC, (void*)&get_search_methods, nullptr,
188       "set fast pattern offload algorithm - choose available search engine" },
189 
190     { "rule_db_dir", Parameter::PT_STRING, nullptr, nullptr,
191       "deserialize rule databases from given directory" },
192 
193     { "search_optimize", Parameter::PT_BOOL, nullptr, "true",
194       "tweak state machine construction for better performance" },
195 
196     { "show_fast_patterns", Parameter::PT_BOOL, nullptr, "false",
197       "print fast pattern info for each rule" },
198 
199     { "split_any_any", Parameter::PT_BOOL, nullptr, "true",
200       "evaluate any-any rules separately to save memory" },
201 
202     { "queue_limit", Parameter::PT_INT, "0:max32", "0",
203       "maximum number of fast pattern matches to queue per packet (0 is unlimited)" },
204 
205     { nullptr, Parameter::PT_MAX, nullptr, nullptr, nullptr }
206 };
207 
208 #define search_engine_help \
209     "configure fast pattern matcher"
210 
211 namespace snort
212 {
213 THREAD_LOCAL PatMatQStat pmqs;
214 }
215 
216 const PegInfo mpse_pegs[] =
217 {
218     { CountType::MAX, "max_queued", "maximum fast pattern matches queued for further evaluation" },
219     { CountType::SUM, "total_flushed", "total fast pattern matches processed" },
220     { CountType::SUM, "total_inserts", "total fast pattern hits" },
221     { CountType::SUM, "total_overruns", "fast pattern matches discarded due to overflow" },
222     { CountType::SUM, "total_unique", "total unique fast pattern hits" },
223     { CountType::SUM, "non_qualified_events", "total non-qualified events" },
224     { CountType::SUM, "qualified_events", "total qualified events" },
225     { CountType::SUM, "searched_bytes", "total bytes searched" },
226     { CountType::END, nullptr, nullptr }
227 };
228 
229 class SearchEngineModule : public Module
230 {
231 public:
SearchEngineModule()232     SearchEngineModule() : Module("search_engine", search_engine_help, search_engine_params) { }
233     bool set(const char*, Value&, SnortConfig*) override;
234 
get_pegs() const235     const PegInfo* get_pegs() const override
236     { return mpse_pegs; }
237 
get_counts() const238     PegCount* get_counts() const override
239     { return (PegCount*)&pmqs; }
240 
get_usage() const241     Usage get_usage() const override
242     { return GLOBAL; }
243 };
244 
set(const char *,Value & v,SnortConfig * sc)245 bool SearchEngineModule::set(const char*, Value& v, SnortConfig* sc)
246 {
247     FastPatternConfig* fp = sc->fast_pattern_config;
248 
249     if ( v.is("bleedover_port_limit") )
250         fp->set_bleed_over_port_limit(v.get_uint32());
251 
252     else if ( v.is("bleedover_warnings_enabled") )
253     {
254         if ( v.get_bool() )
255             fp->set_bleed_over_warnings();  // FIXIT-L these should take arg
256     }
257     else if ( v.is("enable_single_rule_group") )
258     {
259         if ( v.get_bool() )
260             fp->set_single_rule_group();
261     }
262     else if ( v.is("debug") )
263     {
264         if ( v.get_bool() )
265             fp->set_debug_mode();
266     }
267     else if ( v.is("debug_print_nocontent_rule_tests") )
268     {
269         if ( v.get_bool() )
270             fp->set_debug_print_nc_rules();
271     }
272     else if ( v.is("debug_print_rule_group_build_details") )
273     {
274         if ( v.get_bool() )
275             fp->set_debug_print_rule_group_build_details();
276     }
277     else if ( v.is("debug_print_rule_groups_uncompiled") )
278     {
279         if ( v.get_bool() )
280             fp->set_debug_print_rule_groups_uncompiled();
281     }
282     else if ( v.is("debug_print_rule_groups_compiled") )
283     {
284         if ( v.get_bool() )
285             fp->set_debug_print_rule_groups_compiled();
286     }
287     else if ( v.is("max_pattern_len") )
288         fp->set_max_pattern_len(v.get_uint32());
289 
290     else if ( v.is("max_queue_events") )
291         fp->set_max_queue_events(v.get_uint8());
292 
293     else if ( v.is("detect_raw_tcp") )
294         fp->set_stream_insert(v.get_bool());
295 
296     else if ( v.is("rule_db_dir") )
297         fp->set_rule_db_dir(v.get_string());
298 
299     else if ( v.is("search_method") )
300     {
301         if ( !fp->set_search_method(v.get_string()) )
302             return false;
303     }
304     else if ( v.is("offload_search_method") )
305     {
306         if ( !fp->set_offload_search_method(v.get_string()) )
307             return false;
308     }
309     else if ( v.is("search_optimize") )
310         fp->set_search_opt(v.get_bool());
311 
312     else if ( v.is("show_fast_patterns") )
313         fp->set_debug_print_fast_patterns(v.get_bool());
314 
315     else if ( v.is("split_any_any") )
316         fp->set_split_any_any(v.get_bool());
317 
318     else if ( v.is("queue_limit") )
319         fp->set_queue_limit(v.get_uint32());
320 
321     return true;
322 }
323 
324 // -----------------------------------------------------------------------------
325 // profiler module
326 // -----------------------------------------------------------------------------
327 
328 static const Parameter profiler_time_params[] =
329 {
330     { "show", Parameter::PT_BOOL, nullptr, "true",
331       "show module time profile stats" },
332 
333     { "count", Parameter::PT_INT, "0:max32", "0",
334       "limit results to count items per level (0 = no limit)" },
335 
336     { "sort", Parameter::PT_ENUM,
337       "none | checks | avg_check | total_time ",
338       "total_time", "sort by given field" },
339 
340     { "max_depth", Parameter::PT_INT, "-1:255", "-1",
341       "limit depth to max_depth (-1 = no limit)" },
342 
343     { nullptr, Parameter::PT_MAX, nullptr, nullptr, nullptr }
344 };
345 
346 static const Parameter profiler_memory_params[] =
347 {
348     { "show", Parameter::PT_BOOL, nullptr, "true",
349       "show module memory profile stats" },
350 
351     { "count", Parameter::PT_INT, "0:max32", "0",
352       "limit results to count items per level (0 = no limit)" },
353 
354     { "sort", Parameter::PT_ENUM,
355       "none | allocations | total_used | avg_allocation ",
356       "total_used", "sort by given field" },
357 
358     { "max_depth", Parameter::PT_INT, "-1:255", "-1",
359       "limit depth to max_depth (-1 = no limit)" },
360 
361     { nullptr, Parameter::PT_MAX, nullptr, nullptr, nullptr }
362 };
363 
364 static const Parameter profiler_rule_params[] =
365 {
366     { "show", Parameter::PT_BOOL, nullptr, "true",
367       "show rule time profile stats" },
368 
369     { "count", Parameter::PT_INT, "0:max32", "0",
370       "print results to given level (0 = all)" },
371 
372     { "sort", Parameter::PT_ENUM,
373       "none | checks | avg_check | total_time | matches | no_matches | "
374       "avg_match | avg_no_match",
375       "total_time", "sort by given field" },
376 
377     { nullptr, Parameter::PT_MAX, nullptr, nullptr, nullptr }
378 };
379 
380 static const Parameter profiler_params[] =
381 {
382     { "modules", Parameter::PT_TABLE, profiler_time_params, nullptr,
383       "module time profiling" },
384 
385     { "memory", Parameter::PT_TABLE, profiler_memory_params, nullptr,
386       "module memory profiling" },
387 
388     { "rules", Parameter::PT_TABLE, profiler_rule_params, nullptr,
389       "rule time profiling" },
390 
391     { nullptr, Parameter::PT_MAX, nullptr, nullptr, nullptr }
392 };
393 
394 #define profiler_help \
395     "configure profiling of rules and/or modules"
396 
397 template<typename T>
s_profiler_module_set_max_depth(T & config,Value & v)398 static bool s_profiler_module_set_max_depth(T& config, Value& v)
399 { config.max_depth = v.get_uint8(); return true; }
400 
s_profiler_module_set_max_depth(RuleProfilerConfig &,Value &)401 static bool s_profiler_module_set_max_depth(RuleProfilerConfig&, Value&)
402 { return false; }
403 
404 template<typename T>
s_profiler_module_set(T & config,Value & v)405 static bool s_profiler_module_set(T& config, Value& v)
406 {
407     if ( v.is("count") )
408         config.count = v.get_uint32();
409 
410     else if ( v.is("show") )
411         config.show = v.get_bool();
412 
413     else if ( v.is("sort") )
414         config.sort = static_cast<typename T::Sort>(v.get_uint8());
415 
416     else if ( v.is("max_depth") )
417         return s_profiler_module_set_max_depth(config, v);
418 
419     else
420         return false;
421 
422     return true;
423 }
424 
425 class ProfilerModule : public Module
426 {
427 public:
ProfilerModule()428     ProfilerModule() : Module("profiler", profiler_help, profiler_params) { }
429 
430     bool set(const char*, Value&, SnortConfig*) override;
431     bool end(const char*, int, SnortConfig*) override;
432 
433     ProfileStats* get_profile(unsigned, const char*&, const char*&) const override;
434 
get_usage() const435     Usage get_usage() const override
436     { return GLOBAL; }
437 };
438 
set(const char * fqn,Value & v,SnortConfig * sc)439 bool ProfilerModule::set(const char* fqn, Value& v, SnortConfig* sc)
440 {
441     const char* spt = "profiler.modules";
442     const char* spm = "profiler.memory";
443     const char* spr = "profiler.rules";
444 
445     if ( !strncmp(fqn, spt, strlen(spt)) )
446         return s_profiler_module_set(sc->profiler->time, v);
447 
448     else if ( !strncmp(fqn, spm, strlen(spm)) )
449         return s_profiler_module_set(sc->profiler->memory, v);
450 
451     else if ( !strncmp(fqn, spr, strlen(spr)) )
452         return s_profiler_module_set(sc->profiler->rule, v);
453 
454     return false;
455 }
456 
end(const char *,int,SnortConfig * sc)457 bool ProfilerModule::end(const char*, int, SnortConfig* sc)
458 {
459     TimeProfilerStats::set_enabled(sc->profiler->time.show);
460     RuleContext::set_enabled(sc->profiler->rule.show);
461     return true;
462 }
463 
get_profile(unsigned index,const char * & name,const char * & parent) const464 ProfileStats* ProfilerModule::get_profile(
465     unsigned index, const char*& name, const char*& parent) const
466 {
467     switch ( index )
468     {
469     case 0:
470         name = "total";
471         parent = nullptr;
472         return &totalPerfStats;
473 
474     case 1:
475         name = "other";
476         parent = nullptr;
477         return &otherPerfStats;
478     }
479     return nullptr;
480 }
481 
482 //-------------------------------------------------------------------------
483 // classification module
484 //-------------------------------------------------------------------------
485 // FIXIT-L signature.{h,cc} has type and name confused
486 // the keys here make more sense
487 
488 #define classifications_help \
489     "define rule categories with priority"
490 
491 static const Parameter classification_params[] =
492 {
493     { "name", Parameter::PT_STRING, nullptr, nullptr,
494       "name used with classtype rule option" },
495 
496     { "priority", Parameter::PT_INT, "0:max32", "1",
497       "default priority for class" },
498 
499     { "text", Parameter::PT_STRING, nullptr, nullptr,
500       "description of class" },
501 
502     { nullptr, Parameter::PT_MAX, nullptr, nullptr, nullptr }
503 };
504 
505 class ClassificationsModule : public Module
506 {
507 public:
ClassificationsModule()508     ClassificationsModule() :
509         Module("classifications", classifications_help, classification_params, true) { }
510 
511     bool set(const char*, Value&, SnortConfig*) override;
512     bool begin(const char*, int, SnortConfig*) override;
513     bool end(const char*, int, SnortConfig*) override;
514 
get_usage() const515     Usage get_usage() const override
516     { return GLOBAL; }
517 
518 private:
519     string name;
520     string text;
521     unsigned priority;
522 };
523 
begin(const char *,int,SnortConfig *)524 bool ClassificationsModule::begin(const char*, int, SnortConfig*)
525 {
526     name.erase();
527     text.erase();
528     priority = 1;
529     return true;
530 }
531 
end(const char *,int idx,SnortConfig * sc)532 bool ClassificationsModule::end(const char*, int idx, SnortConfig* sc)
533 {
534     if ( idx )
535         add_classification(sc, name.c_str(), text.c_str(), priority);
536     return true;
537 }
538 
set(const char *,Value & v,SnortConfig *)539 bool ClassificationsModule::set(const char*, Value& v, SnortConfig*)
540 {
541     if ( v.is("name") )
542         name = v.get_string();
543 
544     else if ( v.is("priority") )
545         priority = v.get_uint32();
546 
547     else if ( v.is("text") )
548         text = v.get_string();
549 
550     return true;
551 }
552 
553 //-------------------------------------------------------------------------
554 // reference module
555 //-------------------------------------------------------------------------
556 
557 #define reference_help \
558     "define reference systems used in rules"
559 
560 static const Parameter reference_params[] =
561 {
562     { "name", Parameter::PT_STRING, nullptr, nullptr,
563       "name used with reference rule option" },
564 
565     { "url", Parameter::PT_STRING, nullptr, nullptr,
566       "where this reference is defined" },
567 
568     { nullptr, Parameter::PT_MAX, nullptr, nullptr, nullptr }
569 };
570 
571 class ReferencesModule : public Module
572 {
573 public:
ReferencesModule()574     ReferencesModule() :
575         Module("references", reference_help, reference_params, true) { }
576 
577     bool set(const char*, Value&, SnortConfig*) override;
578     bool begin(const char*, int, SnortConfig*) override;
579     bool end(const char*, int, SnortConfig*) override;
580 
get_usage() const581     Usage get_usage() const override
582     { return GLOBAL; }
583 
584 private:
585     string name;
586     string url;
587 };
588 
begin(const char *,int,SnortConfig *)589 bool ReferencesModule::begin(const char*, int, SnortConfig*)
590 {
591     name.erase();
592     url.erase();
593     return true;
594 }
595 
end(const char *,int idx,SnortConfig * sc)596 bool ReferencesModule::end(const char*, int idx, SnortConfig* sc)
597 {
598     if ( idx )
599         reference_system_add(sc, name, url.c_str());
600     return true;
601 }
602 
set(const char *,Value & v,SnortConfig *)603 bool ReferencesModule::set(const char*, Value& v, SnortConfig*)
604 {
605     if ( v.is("name") )
606         name = v.get_string();
607 
608     else if ( v.is("url") )
609         url = v.get_string();
610 
611     return true;
612 }
613 
614 //-------------------------------------------------------------------------
615 // alerts module
616 //-------------------------------------------------------------------------
617 static const Parameter alerts_params[] =
618 {
619     { "alert_with_interface_name", Parameter::PT_BOOL, nullptr, "false",
620       "include interface in alert info (fast, full, or syslog only)" },
621 
622     { "detection_filter_memcap", Parameter::PT_INT, "0:max32", "1048576",
623       "set available MB of memory for detection_filters" },
624 
625     { "event_filter_memcap", Parameter::PT_INT, "0:max32", "1048576",
626       "set available MB of memory for event_filters" },
627 
628     { "log_references", Parameter::PT_BOOL, nullptr, "false",
629       "include rule references in alert info (full only)" },
630 
631     { "order", Parameter::PT_STRING, nullptr, nullptr,
632       "change the order of rule action application" },
633 
634     { "rate_filter_memcap", Parameter::PT_INT, "0:max32", "1048576",
635       "set available MB of memory for rate_filters" },
636 
637     { "reference_net", Parameter::PT_STRING, nullptr, nullptr,
638       "set the CIDR for homenet "
639       "(for use with -l or -B, does NOT change $HOME_NET in IDS mode)" },
640 
641     { "stateful", Parameter::PT_BOOL, nullptr, "false",
642       "don't alert w/o established session (note: rule action still taken)" },
643 
644     { "tunnel_verdicts", Parameter::PT_STRING, nullptr, nullptr,
645       "let DAQ handle non-allow verdicts for gtp|teredo|6in4|4in6|4in4|6in6|gre|mpls|vxlan traffic" },
646 
647     { nullptr, Parameter::PT_MAX, nullptr, nullptr, nullptr }
648 };
649 
650 #define alerts_help \
651     "configure alerts"
652 
653 class AlertsModule : public Module
654 {
655 public:
AlertsModule()656     AlertsModule() : Module("alerts", alerts_help, alerts_params) { }
657     bool set(const char*, Value&, SnortConfig*) override;
658 
get_usage() const659     Usage get_usage() const override
660     { return GLOBAL; }
661 };
662 
set(const char *,Value & v,SnortConfig * sc)663 bool AlertsModule::set(const char*, Value& v, SnortConfig* sc)
664 {
665     if ( v.is("alert_with_interface_name") )
666         v.update_mask(sc->output_flags, OUTPUT_FLAG__ALERT_IFACE);
667 
668     else if ( v.is("detection_filter_memcap") )
669         sc->detection_filter_config->memcap = v.get_uint32();
670 
671     else if ( v.is("event_filter_memcap") )
672         sc->threshold_config->memcap = v.get_uint32();
673 
674     else if ( v.is("log_references") )
675         v.update_mask(sc->output_flags, OUTPUT_FLAG__ALERT_REFS);
676 
677     else if ( v.is("order") )
678         sc->rule_order = v.get_string();
679 
680     else if ( v.is("rate_filter_memcap") )
681         sc->rate_filter_config->memcap = v.get_uint32();
682 
683     else if ( v.is("reference_net") )
684         return ( sc->homenet.set(v.get_string()) == SFIP_SUCCESS );
685 
686     else if ( v.is("stateful") )
687         v.update_mask(sc->run_flags, RUN_FLAG__ASSURE_EST);
688 
689     else if ( v.is("tunnel_verdicts") )
690         sc->set_tunnel_verdicts(v.get_string());
691 
692     return true;
693 }
694 
695 //-------------------------------------------------------------------------
696 // output module
697 //-------------------------------------------------------------------------
698 
699 static const Parameter output_event_trace_params[] =
700 {
701     { "max_data", Parameter::PT_INT, "0:65535", "0",
702       "maximum amount of packet data to capture" },
703 
704     { nullptr, Parameter::PT_MAX, nullptr, nullptr, nullptr }
705 };
706 
707 static const Parameter output_params[] =
708 {
709     { "dump_chars_only", Parameter::PT_BOOL, nullptr, "false",
710       "turns on character dumps (same as -C)" },
711 
712     { "dump_payload", Parameter::PT_BOOL, nullptr, "false",
713       "dumps application layer (same as -d)" },
714 
715     { "dump_payload_verbose", Parameter::PT_BOOL, nullptr, "false",
716       "dumps raw packet starting at link layer (same as -X)" },
717 
718     { "event_trace", Parameter::PT_TABLE, output_event_trace_params, nullptr,
719       "" },
720 
721     { "quiet", Parameter::PT_BOOL, nullptr, "false",
722       "suppress normal logging on stdout (same as -q)" },
723 
724     { "logdir", Parameter::PT_STRING, nullptr, ".",
725       "where to put log files (same as -l)" },
726 
727     { "show_year", Parameter::PT_BOOL, nullptr, "false",
728       "include year in timestamp in the alert and log files (same as -y)" },
729 
730     { "tagged_packet_limit", Parameter::PT_INT, "0:max32", "256",
731       "maximum number of packets tagged for non-packet metrics" },
732 
733     { "verbose", Parameter::PT_BOOL, nullptr, "false",
734       "be verbose (same as -v)" },
735 
736     { "obfuscate", Parameter::PT_BOOL, nullptr, "false",
737       "obfuscate the logged IP addresses (same as -O)" },
738 
739 #ifdef REG_TEST
740     { "wide_hex_dump", Parameter::PT_BOOL, nullptr, "true",
741 #else
742     { "wide_hex_dump", Parameter::PT_BOOL, nullptr, "false",
743 #endif
744       "output 20 bytes per lines instead of 16 when dumping buffers" },
745 
746     { nullptr, Parameter::PT_MAX, nullptr, nullptr, nullptr }
747 };
748 
749 #define output_help \
750     "configure general output parameters"
751 
752 static const RuleMap output_rules[] =
753 {
754     { TAG_LOG_PKT, "tagged packet" },
755     { 0, nullptr }
756 };
757 
758 class OutputModule : public Module
759 {
760 public:
OutputModule()761     OutputModule() : Module("output", output_help, output_params) { }
762     bool set(const char*, Value&, SnortConfig*) override;
763 
get_usage() const764     Usage get_usage() const override
765     { return GLOBAL; }
766 
get_gid() const767     unsigned get_gid() const override
768     { return GID_TAG; }
769 
get_rules() const770     const RuleMap* get_rules() const override
771     { return output_rules; }
772 };
773 
set(const char *,Value & v,SnortConfig * sc)774 bool OutputModule::set(const char*, Value& v, SnortConfig* sc)
775 {
776     if ( v.is("dump_chars_only") )
777         v.update_mask(sc->output_flags, OUTPUT_FLAG__CHAR_DATA);
778 
779     else if ( v.is("dump_payload") )
780         v.update_mask(sc->output_flags, OUTPUT_FLAG__APP_DATA);
781 
782     else if ( v.is("dump_payload_verbose") )
783         v.update_mask(sc->output_flags, OUTPUT_FLAG__VERBOSE_DUMP);
784 
785     else if ( v.is("quiet") )
786     {
787         if ( v.get_bool() )
788             SnortConfig::set_log_quiet(true);
789     }
790 
791     else if ( v.is("logdir") )
792         sc->log_dir = v.get_string();
793 
794     else if ( v.is("max_data") )
795         sc->event_trace_max = v.get_uint16();
796 
797     else if ( v.is("show_year") )
798         v.update_mask(sc->output_flags, OUTPUT_FLAG__INCLUDE_YEAR);
799 
800     else if ( v.is("tagged_packet_limit") )
801         sc->tagged_packet_limit = v.get_uint32();
802 
803     else if ( v.is("verbose") )
804     {
805         if ( v.get_bool() )
806             SnortConfig::enable_log_verbose();
807     }
808     else if ( v.is("wide_hex_dump") )
809         v.update_mask(sc->output_flags, OUTPUT_FLAG__WIDE_HEX);
810 
811     else if ( v.is("obfuscate") )
812         v.update_mask(sc->output_flags, OUTPUT_FLAG__OBFUSCATE);
813 
814     return true;
815 }
816 
817 //-------------------------------------------------------------------------
818 // active module
819 //-------------------------------------------------------------------------
820 
821 static const Parameter active_params[] =
822 {
823     { "attempts", Parameter::PT_INT, "0:255", "0",
824       "number of TCP packets sent per response (with varying sequence numbers)" },
825 
826     { "device", Parameter::PT_STRING, nullptr, nullptr,
827       "use 'ip' for network layer responses or 'eth0' etc for link layer" },
828 
829     { "dst_mac", Parameter::PT_STRING, nullptr, nullptr,
830       "use format '01:23:45:67:89:ab'" },
831 
832     { "max_responses", Parameter::PT_INT, "0:255", "0",
833       "maximum number of responses" },
834 
835     { "min_interval", Parameter::PT_INT, "1:255", "255",
836       "minimum number of seconds between responses" },
837 
838     { nullptr, Parameter::PT_MAX, nullptr, nullptr, nullptr }
839 };
840 
841 #define active_help \
842     "configure responses"
843 
844 static PegInfo active_pegs[]
845 {
846     { CountType::SUM, "injects", "total crafted packets encoded and injected" },
847     { CountType::SUM, "failed_injects", "total crafted packet encode + injects that failed" },
848     { CountType::SUM, "direct_injects", "total crafted packets directly injected" },
849     { CountType::SUM, "failed_direct_injects", "total crafted packet direct injects that failed" },
850     { CountType::SUM, "holds_denied", "total number of packet hold requests denied" },
851     { CountType::SUM, "holds_canceled", "total number of packet hold requests canceled" },
852     { CountType::SUM, "holds_allowed", "total number of packet hold requests allowed" },
853     { CountType::END, nullptr, nullptr }
854 };
855 
856 class ActiveModule : public Module
857 {
858 public:
ActiveModule()859     ActiveModule() : Module("active", active_help, active_params) { }
860     bool set(const char*, Value&, SnortConfig*) override;
861 
get_pegs() const862     const PegInfo* get_pegs() const override
863     { return active_pegs; }
864 
get_counts() const865     PegCount* get_counts() const override
866     { return (PegCount*) &active_counts; }
867 
get_usage() const868     Usage get_usage() const override
869     { return GLOBAL; }
870 };
871 
set(const char *,Value & v,SnortConfig * sc)872 bool ActiveModule::set(const char*, Value& v, SnortConfig* sc)
873 {
874     if ( v.is("attempts") )
875         sc->respond_attempts = v.get_uint8();
876 
877     else if ( v.is("device") )
878         sc->respond_device = v.get_string();
879 
880     else if ( v.is("dst_mac") )
881         sc->set_dst_mac(v.get_string());
882 
883     else if ( v.is("max_responses") )
884         sc->max_responses = v.get_uint8();
885 
886     else if ( v.is("min_interval") )
887         sc->min_interval = v.get_uint8();
888 
889     return true;
890 }
891 
892 //-------------------------------------------------------------------------
893 // packets module
894 //-------------------------------------------------------------------------
895 
896 static const Parameter packets_params[] =
897 {
898     { "address_space_agnostic", Parameter::PT_BOOL, nullptr, "false",
899       "determines whether DAQ address space info is used to track fragments and connections" },
900 
901     { "bpf_file", Parameter::PT_STRING, nullptr, nullptr,
902       "file with BPF to select traffic for Snort" },
903 
904     { "limit", Parameter::PT_INT, "0:max53", "0",
905       "maximum number of packets to process before stopping (0 is unlimited)" },
906 
907     { "skip", Parameter::PT_INT, "0:max53", "0",
908       "number of packets to skip before before processing" },
909 
910     { "mpls_agnostic", Parameter::PT_BOOL, nullptr, "true",
911       "determines whether MPLS labels are used to track fragments and connections" },
912 
913     { "vlan_agnostic", Parameter::PT_BOOL, nullptr, "false",
914       "determines whether VLAN tags are used to track fragments and connections" },
915 
916     { nullptr, Parameter::PT_MAX, nullptr, nullptr, nullptr }
917 };
918 
919 #define packets_help \
920     "configure basic packet handling"
921 
922 class PacketsModule : public Module
923 {
924 public:
PacketsModule()925     PacketsModule() : Module("packets", packets_help, packets_params) { }
926     bool set(const char*, Value&, SnortConfig*) override;
927 
get_usage() const928     Usage get_usage() const override
929     { return GLOBAL; }
930 };
931 
set(const char *,Value & v,SnortConfig * sc)932 bool PacketsModule::set(const char*, Value& v, SnortConfig* sc)
933 {
934     if ( v.is("address_space_agnostic") )
935         sc->asid_agnostic = v.get_bool();
936 
937     else if ( v.is("bpf_file") )
938         sc->bpf_file = v.get_string();
939 
940     else if ( v.is("limit") )
941         sc->pkt_cnt = v.get_uint64();
942 
943     else if ( v.is("mpls_agnostic") )
944         sc->mpls_agnostic = v.get_bool();
945 
946     else if ( v.is("skip") )
947         sc->pkt_skip = v.get_uint64();
948 
949     else if ( v.is("vlan_agnostic") )
950         sc->vlan_agnostic = v.get_bool();
951 
952     return true;
953 }
954 
955 
956 //-------------------------------------------------------------------------
957 // attribute_table module
958 //-------------------------------------------------------------------------
959 
960 static const Parameter attribute_table_params[] =
961 {
962     { "hosts_file", Parameter::PT_STRING, nullptr, nullptr,
963       "filename to load attribute host table from" },
964 
965     { "max_hosts", Parameter::PT_INT, "32:max53", "1024",
966       "maximum number of hosts in attribute table" },
967 
968     { "max_services_per_host", Parameter::PT_INT, "1:65535", "8",
969       "maximum number of services per host entry in attribute table" },
970 
971     { "max_metadata_services", Parameter::PT_INT, "1:255", "9",
972       "maximum number of services in rule" },
973 
974     { nullptr, Parameter::PT_MAX, nullptr, nullptr, nullptr }
975 };
976 
977 const char* attribute_table_help =
978     "configure hosts loading";
979 
980 class AttributeTableModule : public Module
981 {
982 public:
AttributeTableModule()983     AttributeTableModule() :
984         Module("attribute_table", attribute_table_help, attribute_table_params) { }
985     bool set(const char*, Value&, SnortConfig*) override;
986 
get_usage() const987     Usage get_usage() const override
988     { return GLOBAL; }
989 };
990 
set(const char *,Value & v,SnortConfig * sc)991 bool AttributeTableModule::set(const char*, Value& v, SnortConfig* sc)
992 {
993     if ( v.is("hosts_file") )
994         sc->attribute_hosts_file = std::string(v.get_string());
995 
996     else if ( v.is("max_hosts") )
997         sc->max_attribute_hosts = v.get_uint32();
998 
999     else if ( v.is("max_services_per_host") )
1000         sc->max_attribute_services_per_host = v.get_uint16();
1001 
1002     else if ( v.is("max_metadata_services") )
1003         sc->max_metadata_services = v.get_uint8();
1004 
1005     return true;
1006 }
1007 
1008 //-------------------------------------------------------------------------
1009 // network module
1010 //-------------------------------------------------------------------------
1011 
1012 static const Parameter network_params[] =
1013 {
1014     { "checksum_drop", Parameter::PT_MULTI,
1015       "all | ip | noip | tcp | notcp | udp | noudp | icmp | noicmp | none", "none",
1016       "drop if checksum is bad" },
1017 
1018     { "checksum_eval", Parameter::PT_MULTI,
1019       "all | ip | noip | tcp | notcp | udp | noudp | icmp | noicmp | none", "all",
1020       "checksums to verify" },
1021 
1022     { "id", Parameter::PT_INT, "0:65535", "0",
1023       "correlate unified2 events with configuration" },
1024 
1025     { "min_ttl", Parameter::PT_INT, "1:255", "1",
1026       "alert / normalize packets with lower TTL / hop limit "
1027       "(you must enable rules and / or normalization also)" },
1028 
1029     { "new_ttl", Parameter::PT_INT, "1:255", "1",
1030       "use this value for responses and when normalizing" },
1031 
1032     { "layers", Parameter::PT_INT, "3:255", "40",
1033       "the maximum number of protocols that Snort can correctly decode" },
1034 
1035     { "max_ip6_extensions", Parameter::PT_INT, "0:255", "0",
1036       "the maximum number of IP6 options Snort will process for a given IPv6 layer "
1037       "before raising 116:456 (0 = unlimited)" },
1038 
1039     { "max_ip_layers", Parameter::PT_INT, "0:255", "0",
1040       "the maximum number of IP layers Snort will process for a given packet "
1041       "before raising 116:293 (0 = unlimited)" },
1042 
1043     { nullptr, Parameter::PT_MAX, nullptr, nullptr, nullptr }
1044 };
1045 
1046 #define network_help \
1047     "configure basic network parameters"
1048 
1049 class NetworkModule : public Module
1050 {
1051 public:
NetworkModule()1052     NetworkModule() : Module("network", network_help, network_params) { }
1053     bool set(const char*, Value&, SnortConfig*) override;
1054 
get_usage() const1055     Usage get_usage() const override
1056     { return CONTEXT; }
1057 };
1058 
set(const char *,Value & v,SnortConfig * sc)1059 bool NetworkModule::set(const char*, Value& v, SnortConfig* sc)
1060 {
1061     NetworkPolicy* p = get_network_policy();
1062 
1063     if ( v.is("checksum_drop") )
1064         ConfigChecksumDrop(v.get_string());
1065 
1066     else if ( v.is("checksum_eval") )
1067         ConfigChecksumMode(v.get_string());
1068 
1069     else if ( v.is("id") )
1070     {
1071         p->user_policy_id = v.get_uint16();
1072         sc->policy_map->set_user_network(p);
1073     }
1074 
1075     else if ( v.is("min_ttl") )
1076         p->min_ttl = v.get_uint8();
1077 
1078     else if ( v.is("new_ttl") )
1079         p->new_ttl = v.get_uint8();
1080 
1081     else if (v.is("layers"))
1082         sc->num_layers = v.get_uint8();
1083 
1084     else if (v.is("max_ip6_extensions"))
1085         sc->max_ip6_extensions = v.get_uint8();
1086 
1087     else if (v.is("max_ip_layers"))
1088         sc->max_ip_layers = v.get_uint8();
1089 
1090     return true;
1091 }
1092 
1093 //-------------------------------------------------------------------------
1094 // inspection policy module
1095 //-------------------------------------------------------------------------
1096 
1097 static const Parameter inspection_params[] =
1098 {
1099     { "id", Parameter::PT_INT, "0:65535", "0",
1100       "correlate policy and events with other items in configuration" },
1101 
1102 #ifdef HAVE_UUID
1103     { "uuid", Parameter::PT_STRING, nullptr, nullptr,
1104       "correlate events by uuid" },
1105 #endif
1106 
1107     { "mode", Parameter::PT_ENUM, "inline | inline-test", "inline-test",
1108       "set policy mode" },
1109 
1110     { "max_aux_ip", Parameter::PT_INT, "-1:127", "16",
1111       "maximum number of auxiliary IPs per flow to detect and save "
1112       "(-1 = disable, 0 = detect but don't save, 1+ = save in FIFO manner)" },
1113 
1114     { nullptr, Parameter::PT_MAX, nullptr, nullptr, nullptr }
1115 };
1116 
1117 #define inspection_help \
1118     "configure basic inspection policy parameters"
1119 
1120 class InspectionModule : public Module
1121 {
1122 public:
InspectionModule()1123     InspectionModule() : Module("inspection", inspection_help, inspection_params) { }
1124     bool set(const char*, Value&, SnortConfig*) override;
1125 
get_usage() const1126     Usage get_usage() const override
1127     { return INSPECT; }
1128 };
1129 
set(const char *,Value & v,SnortConfig * sc)1130 bool InspectionModule::set(const char*, Value& v, SnortConfig* sc)
1131 {
1132     InspectionPolicy* p = get_inspection_policy();
1133 
1134     if ( v.is("id") )
1135     {
1136         p->user_policy_id = v.get_uint16();
1137         sc->policy_map->set_user_inspection(p);
1138     }
1139 
1140 #ifdef HAVE_UUID
1141     else if ( v.is("uuid") )
1142     {
1143         if(uuid_parse(v.get_string(), p->uuid) != 0)
1144         {
1145             ParseError("Invalid Inspection UUID: %s", v.get_string());
1146             uuid_clear(p->uuid);
1147         }
1148     }
1149 #endif
1150 
1151     else if ( v.is("mode") )
1152     {
1153         switch ( v.get_uint8() )
1154         {
1155             case 0:
1156                 p->policy_mode = POLICY_MODE__INLINE;
1157                 break;
1158             case 1:
1159                 p->policy_mode = POLICY_MODE__INLINE_TEST;
1160                 break;
1161             default:
1162                 break;
1163         }
1164     }
1165 
1166     else if ( v.is("max_aux_ip") )
1167     {
1168         sc->max_aux_ip = v.get_int16();
1169         return true;
1170     }
1171 
1172     return true;
1173 }
1174 //-------------------------------------------------------------------------
1175 // Ips policy module
1176 //-------------------------------------------------------------------------
1177 
get_var_name(const char * fqn)1178 static const char* get_var_name(const char* fqn)
1179 {
1180     const char* ptr = strrchr(fqn, '.');
1181     assert(ptr);
1182     return ptr + 1;
1183 }
1184 
1185 static const Parameter var_params[] =
1186 {
1187     { "$var" , Parameter::PT_STRING, nullptr, nullptr,
1188       "IPS policy variable" },
1189 
1190     { nullptr, Parameter::PT_MAX, nullptr, nullptr, nullptr }
1191 };
1192 
1193 static const Parameter variable_params[] =
1194 {
1195     { "nets" , Parameter::PT_TABLE, var_params, nullptr,
1196       "net variables" },
1197 
1198     { "paths" , Parameter::PT_TABLE, var_params, nullptr,
1199       "path variables" },
1200 
1201     { "ports" , Parameter::PT_TABLE, var_params, nullptr,
1202       "port variables" },
1203 
1204     { nullptr, Parameter::PT_MAX, nullptr, nullptr, nullptr }
1205 };
1206 
1207 static const Parameter action_map_params[] =
1208 {
1209     { "replace" , Parameter::PT_STRING, nullptr, nullptr,
1210       "action you want to change" },
1211 
1212     { "with" , Parameter::PT_STRING, nullptr, nullptr,
1213       "action you want to use instead" },
1214 
1215     { nullptr, Parameter::PT_MAX, nullptr, nullptr, nullptr }
1216 };
1217 
1218 static const Parameter ips_params[] =
1219 {
1220     { "action_map", Parameter::PT_LIST, action_map_params, nullptr,
1221       "change actions like block to alert (applied after action_override)" },
1222 
1223     { "action_override", Parameter::PT_STRING, nullptr, nullptr,
1224       "use this action for all rules (applied before action_map)" },
1225 
1226     { "default_rule_state", Parameter::PT_ENUM, "no | yes | inherit", "inherit",
1227       "enable or disable ips rules" },
1228 
1229     { "enable_builtin_rules", Parameter::PT_BOOL, nullptr, "false",
1230       "enable events from builtin rules w/o stubs" },
1231 
1232     { "id", Parameter::PT_INT, "0:65535", "0",
1233       "correlate unified2 events with configuration" },
1234 
1235     { "include", Parameter::PT_STRING, nullptr, nullptr,
1236       "snort rules and includes" },
1237 
1238     { "includer", Parameter::PT_STRING, "(optional)", nullptr,
1239       "for internal use; where includes are included from" },
1240 
1241     // FIXIT-L no default; it breaks initialization by -Q
1242     { "mode", Parameter::PT_ENUM, "tap | inline | inline-test", nullptr,
1243       "set policy mode" },
1244 
1245     { "obfuscate_pii", Parameter::PT_BOOL, nullptr, "false",
1246       "mask all but the last 4 characters of credit card and social security numbers" },
1247 
1248     { "rules", Parameter::PT_STRING, nullptr, nullptr,
1249       "snort rules and includes (may contain states too)" },
1250 
1251     { "states", Parameter::PT_STRING, nullptr, nullptr,
1252       "snort rule states and includes (may contain rules too)" },
1253 
1254 #ifdef HAVE_UUID
1255     { "uuid", Parameter::PT_STRING, nullptr, "00000000-0000-0000-0000-000000000000",
1256       "IPS policy uuid" },
1257 #endif
1258 
1259     { "variables", Parameter::PT_TABLE, variable_params, nullptr,
1260       "defines IPS policy variables" },
1261 
1262     { nullptr, Parameter::PT_MAX, nullptr, nullptr, nullptr }
1263 };
1264 
1265 #define ips_help \
1266     "configure IPS rule processing"
1267 
1268 class IpsModule : public Module
1269 {
1270 public:
IpsModule()1271     IpsModule() : Module("ips", ips_help, ips_params) { }
1272     bool set(const char*, Value&, SnortConfig*) override;
1273     bool end(const char*, int, SnortConfig*) override;
1274     bool matches(const char*, std::string&) override;
1275 
get_usage() const1276     Usage get_usage() const override
1277     { return DETECT; }
1278 
1279 private:
1280     std::string replace;
1281     std::string with;
1282 };
1283 
matches(const char *,std::string &)1284 bool IpsModule::matches(const char*, std::string&)
1285 { return true; }
1286 
set(const char * fqn,Value & v,SnortConfig * sc)1287 bool IpsModule::set(const char* fqn, Value& v, SnortConfig* sc)
1288 {
1289     IpsPolicy* p = get_ips_policy();
1290 
1291     if ( v.is("action_override") )
1292         p->action_override = v.get_string();
1293 
1294     else if ( v.is("default_rule_state") )
1295         p->default_rule_state = (IpsPolicy::Enable)v.get_uint8();
1296 
1297     else if ( v.is("enable_builtin_rules") )
1298         p->enable_builtin_rules = v.get_bool();
1299 
1300     else if ( v.is("id") )
1301     {
1302         p->user_policy_id = v.get_uint16();
1303         sc->policy_map->set_user_ips(p);
1304     }
1305 
1306     else if ( v.is("include") )
1307         p->include = v.get_string();
1308 
1309     else if ( v.is("includer") )
1310         p->includer = v.get_string();
1311 
1312     else if ( v.is("mode") )
1313         p->policy_mode = (PolicyMode)v.get_uint8();
1314 
1315     else if ( v.is("obfuscate_pii") )
1316         p->obfuscate_pii = v.get_bool();
1317 
1318     else if ( v.is("replace") )
1319         replace = v.get_string();
1320 
1321     else if ( v.is("rules") )
1322         p->rules += v.get_string();
1323 
1324     else if ( v.is("states") )
1325         p->states += v.get_string();
1326 
1327 #ifdef HAVE_UUID
1328     else if ( v.is("uuid") )
1329     {
1330         if(uuid_parse(v.get_string(), p->uuid) != 0)
1331         {
1332             ParseError("Invalid IPS UUID: %s", v.get_string());
1333             uuid_clear(p->uuid);
1334         }
1335     }
1336 #endif
1337 
1338     // FIXIT-M should only need one table with dynamically typed vars
1339     else if ( strstr(fqn, "variables.nets.") )
1340         ParseIpVar(get_var_name(fqn), v.get_string());
1341 
1342     else if ( strstr(fqn, "variables.paths.") )
1343         ParsePathVar(get_var_name(fqn), v.get_string());
1344 
1345     else if ( strstr(fqn, "variables.ports.") )
1346         ParsePortVar(get_var_name(fqn), v.get_string());
1347 
1348     else if ( v.is("with") )
1349         with = v.get_string();
1350 
1351     return true;
1352 }
1353 
end(const char * fqn,int idx,SnortConfig *)1354 bool IpsModule::end(const char* fqn, int idx, SnortConfig*)
1355 {
1356     if ( idx and !strcmp(fqn, "ips.action_map") )
1357     {
1358         if ( replace.empty() or with.empty() )
1359         {
1360             ParseError("%s - must set both replace and with", fqn);
1361             return false;
1362         }
1363 
1364         IpsPolicy* p = get_ips_policy();
1365         p->action_map[replace] = with;
1366 
1367         replace.clear();
1368         with.clear();
1369     }
1370     return true;
1371 }
1372 
1373 //-------------------------------------------------------------------------
1374 // process module
1375 //-------------------------------------------------------------------------
1376 
1377 static const Parameter thread_pinning_params[] =
1378 {
1379     { "cpuset", Parameter::PT_STRING, nullptr, nullptr,
1380       "pin the associated thread to this cpuset" },
1381 
1382     { "thread", Parameter::PT_INT, "0:65535", nullptr,
1383       "set cpu affinity for the <cur_thread_num> thread that runs" },
1384 
1385     { "type", Parameter::PT_ENUM, "other|packet|main", nullptr,
1386       "define which threads will have specified affinity, by their type" },
1387 
1388     { "name", Parameter::PT_STRING, nullptr, nullptr,
1389       "define which threads will have specified affinity, by thread name" },
1390 
1391     { nullptr, Parameter::PT_MAX, nullptr, nullptr, nullptr }
1392 };
1393 
1394 static const Parameter process_params[] =
1395 {
1396     { "chroot", Parameter::PT_STRING, nullptr, nullptr,
1397       "set chroot directory (same as -t)" },
1398 
1399     { "threads", Parameter::PT_LIST, thread_pinning_params, nullptr,
1400       "thread pinning parameters" },
1401 
1402     { "daemon", Parameter::PT_BOOL, nullptr, "false",
1403       "fork as a daemon (same as -D)" },
1404 
1405     { "dirty_pig", Parameter::PT_BOOL, nullptr, "false",
1406       "shutdown without internal cleanup" },
1407 
1408     { "set_gid", Parameter::PT_STRING, nullptr, nullptr,
1409       "set group ID (same as -g)" },
1410 
1411     { "set_uid", Parameter::PT_STRING, nullptr, nullptr,
1412       "set user ID (same as -u)" },
1413 
1414     { "umask", Parameter::PT_INT, "0x000:0x1FF", nullptr,
1415       "set process umask (same as -m)" },
1416 
1417     { "utc", Parameter::PT_BOOL, nullptr, "false",
1418       "use UTC instead of local time for timestamps" },
1419 
1420     { nullptr, Parameter::PT_MAX, nullptr, nullptr, nullptr }
1421 };
1422 
1423 #define process_help \
1424     "configure basic process setup"
1425 
1426 class ProcessModule : public Module
1427 {
1428 public:
ProcessModule()1429     ProcessModule() : Module("process", process_help, process_params) { }
1430     bool set(const char*, Value&, SnortConfig*) override;
1431     bool begin(const char*, int, SnortConfig*) override;
1432     bool end(const char*, int, SnortConfig*) override;
1433 
get_usage() const1434     Usage get_usage() const override
1435     { return GLOBAL; }
1436 
1437 private:
1438     int thread;
1439     CpuSet* cpuset;
1440     string type;
1441     string name;
1442 };
1443 
set(const char *,Value & v,SnortConfig * sc)1444 bool ProcessModule::set(const char*, Value& v, SnortConfig* sc)
1445 {
1446     if ( v.is("daemon") )
1447     {
1448         if ( v.get_bool() )  // FIXIT-M fix cmd line vs conf conflicts
1449             sc->set_daemon(true);
1450     }
1451     else if ( v.is("chroot") )
1452         sc->set_chroot_dir(v.get_string());
1453 
1454     else if ( v.is("dirty_pig") )
1455         sc->set_dirty_pig(v.get_bool());
1456 
1457     else if ( v.is("set_gid") )
1458         sc->set_gid(v.get_string());
1459 
1460     else if ( v.is("set_uid") )
1461         sc->set_uid(v.get_string());
1462 
1463     else if ( v.is("umask") )
1464         sc->set_umask(v.get_uint32());
1465 
1466     else if ( v.is("utc") )
1467         sc->set_utc(v.get_bool());
1468 
1469     else if (v.is("cpuset"))
1470     {
1471         if (!(cpuset = ThreadConfig::validate_cpuset_string(v.get_string())))
1472             return false;
1473     }
1474 
1475     else if (v.is("thread"))
1476         thread = v.get_uint16();
1477 
1478     else if (v.is("type"))
1479         type = v.get_string();
1480 
1481     else if (v.is("name"))
1482         name = v.get_string();
1483 
1484     return true;
1485 }
1486 
begin(const char *,int,SnortConfig *)1487 bool ProcessModule::begin(const char*, int, SnortConfig*)
1488 {
1489     thread = -1;
1490     cpuset = nullptr;
1491     type.clear();
1492     name.clear();
1493     return true;
1494 }
1495 
end(const char * fqn,int idx,SnortConfig * sc)1496 bool ProcessModule::end(const char* fqn, int idx, SnortConfig* sc)
1497 {
1498     if ( !idx )
1499         return true;
1500 
1501     if (!strcmp(fqn, "process.threads"))
1502     {
1503         if (!cpuset)
1504         {
1505             ParseError("%s - no cpuset specified", fqn);
1506             return false;
1507         }
1508 
1509         if (thread >= 0)
1510         {
1511             // Packet thread affinity.
1512             if ( !(name.empty() && (type.empty() || type == "packet")) )
1513             {
1514                 ParseError("%s - type or name specified for thread %d", fqn, thread);
1515                 ThreadConfig::destroy_cpuset(cpuset);
1516                 return false;
1517             }
1518 
1519             // Thread type is implicitly "packet".
1520             sc->thread_config->set_thread_affinity(STHREAD_TYPE_PACKET, thread, cpuset);
1521         }
1522 
1523         else if (!type.empty() && name.empty())
1524         {
1525             // Type-based affinity: main, or other.
1526             thread = ThreadConfig::DEFAULT_THREAD_ID;
1527             if (type == "main")
1528                 sc->thread_config->set_thread_affinity(STHREAD_TYPE_MAIN, thread, cpuset);
1529             else if (type == "other")
1530                 sc->thread_config->set_thread_affinity(STHREAD_TYPE_OTHER, thread, cpuset);
1531             else
1532             {
1533                 ParseError("%s - bad thread type %s", fqn, type.c_str());
1534                 ThreadConfig::destroy_cpuset(cpuset);
1535                 return false;
1536             }
1537         }
1538 
1539         else if (type.empty() && !name.empty())
1540         {
1541             // name-based affinity
1542             sc->thread_config->set_named_thread_affinity(name, cpuset);
1543         }
1544 
1545         else if (!type.empty() && !name.empty())
1546         {
1547             ParseError("%s - can't specify both type and name", fqn);
1548             ThreadConfig::destroy_cpuset(cpuset);
1549             return false;
1550         }
1551 
1552         else
1553         {
1554             ParseError("%s - none of thread, type or name specified", fqn);
1555             ThreadConfig::destroy_cpuset(cpuset);
1556             return false;
1557         }
1558     }
1559 
1560     return true;
1561 }
1562 
1563 //-------------------------------------------------------------------------
1564 // suppress module
1565 //-------------------------------------------------------------------------
1566 
1567 static const Parameter suppress_params[] =
1568 {
1569     { "gid", Parameter::PT_INT, "0:max32", "0",
1570       "rule generator ID" },
1571 
1572     { "sid", Parameter::PT_INT, "0:max32", "0",
1573       "rule signature ID" },
1574 
1575     { "track", Parameter::PT_ENUM, "by_src | by_dst", nullptr,
1576       "suppress only matching source or destination addresses" },
1577 
1578     { "ip", Parameter::PT_STRING, nullptr, nullptr,
1579       "restrict suppression to these addresses according to track" },
1580 
1581     { nullptr, Parameter::PT_MAX, nullptr, nullptr, nullptr }
1582 };
1583 
1584 #define suppress_help \
1585     "configure event suppressions"
1586 
1587 class SuppressModule : public Module
1588 {
1589 public:
SuppressModule()1590     SuppressModule() : Module("suppress", suppress_help, suppress_params, true) { }
1591     bool set(const char*, Value&, SnortConfig*) override;
1592     bool begin(const char*, int, SnortConfig*) override;
1593     bool end(const char*, int, SnortConfig*) override;
1594 
get_usage() const1595     Usage get_usage() const override
1596     { return CONTEXT; }
1597 
1598 private:
1599     THDX_STRUCT thdx;
1600 };
1601 
set(const char *,Value & v,SnortConfig *)1602 bool SuppressModule::set(const char*, Value& v, SnortConfig*)
1603 {
1604     if ( v.is("gid") )
1605         thdx.gen_id = v.get_uint32();
1606 
1607     else if ( v.is("sid") )
1608         thdx.sig_id = v.get_uint32();
1609 
1610     else if ( v.is("track") )
1611         thdx.tracking = v.get_uint8() + 1;
1612 
1613     else if ( v.is("ip") )
1614         thdx.ip_address = sfip_var_from_string(v.get_string(), "suppress");
1615 
1616     return true;
1617 }
1618 
begin(const char *,int,SnortConfig *)1619 bool SuppressModule::begin(const char*, int, SnortConfig*)
1620 {
1621     memset(&thdx, 0, sizeof(thdx));
1622     thdx.type = THD_TYPE_SUPPRESS;
1623     thdx.priority = THD_PRIORITY_SUPPRESS;
1624     thdx.tracking = THD_TRK_NONE;
1625     return true;
1626 }
1627 
end(const char *,int idx,SnortConfig * sc)1628 bool SuppressModule::end(const char*, int idx, SnortConfig* sc)
1629 {
1630     if ( idx && sfthreshold_create(sc, sc->threshold_config, &thdx, get_network_policy()->policy_id) )
1631     {
1632         ParseError("bad suppress configuration [%d]", idx);
1633         return false;
1634     }
1635     return true;
1636 }
1637 
1638 //-------------------------------------------------------------------------
1639 // event_filter module
1640 //-------------------------------------------------------------------------
1641 
1642 static const Parameter event_filter_params[] =
1643 {
1644     { "gid", Parameter::PT_INT, "0:max32", "1",
1645       "rule generator ID" },
1646 
1647     { "sid", Parameter::PT_INT, "0:max32", "1",
1648       "rule signature ID" },
1649 
1650     { "type", Parameter::PT_ENUM, "limit | threshold | both", nullptr,
1651       "1st count events | every count events | once after count events" },
1652 
1653     { "track", Parameter::PT_ENUM, "by_src | by_dst", nullptr,
1654       "filter only matching source or destination addresses" },
1655 
1656     { "count", Parameter::PT_INT, "-1:max31", "0",
1657       "number of events in interval before tripping; -1 to disable" },
1658 
1659     { "seconds", Parameter::PT_INT, "0:max32", "0",
1660       "count interval" },
1661 
1662     { "ip", Parameter::PT_STRING, nullptr, nullptr,
1663       "restrict filter to these addresses according to track" },
1664 
1665     { nullptr, Parameter::PT_MAX, nullptr, nullptr, nullptr }
1666 };
1667 
1668 #define event_filter_help \
1669     "configure thresholding of events"
1670 
1671 extern THREAD_LOCAL EventFilterStats event_filter_stats; // in sfthd.cc
1672 const PegInfo event_filter_peg_names[] =
1673 {
1674     { CountType::SUM, "no_memory_local", "number of times event filter ran out of local memory" },
1675     { CountType::SUM, "no_memory_global", "number of times event filter ran out of global memory" },
1676     { CountType::END, nullptr, nullptr }
1677 };
1678 
1679 class EventFilterModule : public Module
1680 {
1681 public:
EventFilterModule()1682     EventFilterModule() :
1683         Module("event_filter", event_filter_help, event_filter_params, true) { }
1684     bool set(const char*, Value&, SnortConfig*) override;
1685     bool begin(const char*, int, SnortConfig*) override;
1686     bool end(const char*, int, SnortConfig*) override;
1687 
get_pegs() const1688     const PegInfo* get_pegs() const override
1689     {
1690         return event_filter_peg_names;
1691     }
1692 
get_counts() const1693     PegCount* get_counts() const override
1694     {
1695         return (PegCount*)&event_filter_stats;
1696     }
1697 
get_usage() const1698     Usage get_usage() const override
1699     { return CONTEXT; }
1700 
1701 private:
1702     THDX_STRUCT thdx;
1703 };
1704 
set(const char *,Value & v,SnortConfig *)1705 bool EventFilterModule::set(const char*, Value& v, SnortConfig*)
1706 {
1707     if ( v.is("gid") )
1708         thdx.gen_id = v.get_uint32();
1709 
1710     else if ( v.is("sid") )
1711         thdx.sig_id = v.get_uint32();
1712 
1713     else if ( v.is("track") )
1714         thdx.tracking = v.get_uint8() + 1;
1715 
1716     else if ( v.is("ip") )
1717         thdx.ip_address = sfip_var_from_string(v.get_string(), "event_filter");
1718 
1719     else if ( v.is("count") )
1720         thdx.count = v.get_int32();
1721 
1722     else if ( v.is("seconds") )
1723         thdx.seconds = v.get_uint32();
1724 
1725     else if ( v.is("type") )
1726         thdx.type = v.get_uint8();
1727 
1728     return true;
1729 }
1730 
begin(const char *,int,SnortConfig *)1731 bool EventFilterModule::begin(const char*, int, SnortConfig*)
1732 {
1733     memset(&thdx, 0, sizeof(thdx));
1734     thdx.priority = THD_PRIORITY_SUPPRESS;
1735     thdx.tracking = THD_TRK_NONE;
1736     return true;
1737 }
1738 
end(const char *,int idx,SnortConfig * sc)1739 bool EventFilterModule::end(const char*, int idx, SnortConfig* sc)
1740 {
1741     if ( idx && sfthreshold_create(sc, sc->threshold_config, &thdx, get_network_policy()->policy_id) )
1742     {
1743         ParseError("bad event_filter configuration [%d]", idx);
1744         return false;
1745     }
1746     return true;
1747 }
1748 
1749 //-------------------------------------------------------------------------
1750 // rate_filter module
1751 //-------------------------------------------------------------------------
1752 
1753 function<const char*()> get_action_types = []()
__anonb3a7072e0202() 1754 { return PluginManager::get_available_plugins(PT_IPS_ACTION); };
1755 
1756 static const Parameter rate_filter_params[] =
1757 {
1758     { "gid", Parameter::PT_INT, "0:max32", "1",
1759       "rule generator ID" },
1760 
1761     { "sid", Parameter::PT_INT, "0:max32", "1",
1762       "rule signature ID" },
1763 
1764     { "track", Parameter::PT_ENUM, "by_src | by_dst | by_rule", "by_src",
1765       "filter only matching source or destination addresses" },
1766 
1767     { "count", Parameter::PT_INT, "0:max32", "1",
1768       "number of events in interval before tripping" },
1769 
1770     { "seconds", Parameter::PT_INT, "0:max32", "1",
1771       "count interval" },
1772 
1773     { "new_action", Parameter::PT_DYNAMIC, (void*)&get_action_types, "alert",
1774       "take this action on future hits until timeout" },
1775 
1776     { "timeout", Parameter::PT_INT, "0:max32", "1",
1777       "count interval" },
1778 
1779     { "apply_to", Parameter::PT_STRING, nullptr, nullptr,
1780       "restrict filter to these addresses according to track" },
1781 
1782     { nullptr, Parameter::PT_MAX, nullptr, nullptr, nullptr }
1783 };
1784 
1785 #define rate_filter_help \
1786     "configure rate filters (which change rule actions)"
1787 
1788 extern THREAD_LOCAL RateFilterStats rate_filter_stats;
1789 const PegInfo rate_filter_peg_names[] =
1790 {
1791     { CountType::SUM, "no_memory", "number of times rate filter ran out of memory" },
1792     { CountType::END, nullptr, nullptr }
1793 };
1794 
1795 
1796 class RateFilterModule : public Module
1797 {
1798 public:
RateFilterModule()1799     RateFilterModule() : Module("rate_filter", rate_filter_help, rate_filter_params, true)
1800     { thdx.applyTo = nullptr; }
1801     ~RateFilterModule() override;
1802     bool set(const char*, Value&, SnortConfig*) override;
1803     bool begin(const char*, int, SnortConfig*) override;
1804     bool end(const char*, int, SnortConfig*) override;
1805 
get_pegs() const1806     const PegInfo* get_pegs() const override
1807     {
1808         return rate_filter_peg_names;
1809     }
1810 
get_counts() const1811     PegCount* get_counts() const override
1812     {
1813         return (PegCount*)&rate_filter_stats;
1814     }
1815 
get_usage() const1816     Usage get_usage() const override
1817     { return CONTEXT; }
1818 
1819 private:
1820     tSFRFConfigNode thdx;
1821 };
1822 
~RateFilterModule()1823 RateFilterModule::~RateFilterModule()
1824 {
1825     if ( thdx.applyTo )
1826         sfvar_free(thdx.applyTo);
1827 }
1828 
set(const char *,Value & v,SnortConfig *)1829 bool RateFilterModule::set(const char*, Value& v, SnortConfig*)
1830 {
1831     if ( v.is("gid") )
1832         thdx.gid = v.get_uint32();
1833 
1834     else if ( v.is("sid") )
1835         thdx.sid = v.get_uint32();
1836 
1837     else if ( v.is("track") )
1838         thdx.tracking = (SFRF_TRACK)(v.get_uint8() + 1);
1839 
1840     else if ( v.is("count") )
1841         thdx.count = v.get_uint32();
1842 
1843     else if ( v.is("seconds") )
1844         thdx.seconds = v.get_uint32();
1845 
1846     else if ( v.is("timeout") )
1847         thdx.timeout = v.get_uint32();
1848 
1849     else if ( v.is("apply_to") )
1850         thdx.applyTo = sfip_var_from_string(v.get_string(), "rate_filter");
1851 
1852     else if ( v.is("new_action") )
1853     {
1854         thdx.newAction = Actions::get_type(v.get_string());
1855 
1856         if ( !Actions::is_valid_action(thdx.newAction) )
1857             ParseError("unknown new_action type rate_filter configuration %s",
1858                     v.get_string());
1859     }
1860 
1861     return true;
1862 }
1863 
begin(const char *,int,SnortConfig *)1864 bool RateFilterModule::begin(const char*, int, SnortConfig*)
1865 {
1866     memset(&thdx, 0, sizeof(thdx));
1867     return true;
1868 }
1869 
end(const char *,int idx,SnortConfig * sc)1870 bool RateFilterModule::end(const char*, int idx, SnortConfig* sc)
1871 {
1872     if ( idx && RateFilter_Create(sc, sc->rate_filter_config,  &thdx) )
1873         ParseError("bad rate_filter configuration [%d]", idx);
1874 
1875     thdx.applyTo = nullptr;
1876     return true;
1877 }
1878 
1879 //-------------------------------------------------------------------------
1880 // hosts module
1881 //-------------------------------------------------------------------------
1882 
1883 static const Parameter service_params[] =
1884 {
1885     { "name", Parameter::PT_STRING, nullptr, nullptr,
1886       "service identifier" },
1887 
1888     { "proto", Parameter::PT_ENUM, "tcp | udp", "tcp",
1889       "IP protocol" },
1890 
1891     { "port", Parameter::PT_PORT, nullptr, nullptr,
1892       "port number" },
1893 
1894     { nullptr, Parameter::PT_MAX, nullptr, nullptr, nullptr }
1895 };
1896 
1897 static const Parameter hosts_params[] =
1898 {
1899     { "ip", Parameter::PT_ADDR, nullptr, "0.0.0.0/32",
1900       "hosts address / CIDR" },
1901 
1902     { "frag_policy", Parameter::PT_ENUM, IP_POLICIES, nullptr,
1903       "defragmentation policy" },
1904 
1905     { "tcp_policy", Parameter::PT_ENUM, TCP_POLICIES, nullptr,
1906       "TCP reassembly policy" },
1907 
1908     { "services", Parameter::PT_LIST, service_params, nullptr,
1909       "list of service parameters" },
1910 
1911     { nullptr, Parameter::PT_MAX, nullptr, nullptr, nullptr }
1912 };
1913 
1914 #define hosts_help \
1915     "configure hosts"
1916 
1917 class HostsModule : public Module
1918 {
1919 public:
HostsModule()1920     HostsModule() : Module("hosts", hosts_help, hosts_params, true)
1921     { host = nullptr; }
1922 
~HostsModule()1923     ~HostsModule() override
1924     { assert(!host); }
1925 
1926     bool set(const char*, Value&, SnortConfig*) override;
1927     bool begin(const char*, int, SnortConfig*) override;
1928     bool end(const char*, int, SnortConfig*) override;
1929 
get_pegs() const1930     const PegInfo* get_pegs() const override
1931     { return HostAttributesManager::get_pegs(); }
1932 
get_counts() const1933     PegCount* get_counts() const override
1934     { return HostAttributesManager::get_peg_counts(); }
1935 
get_usage() const1936     Usage get_usage() const override
1937     { return GLOBAL; }
1938 
1939 private:
1940     HostServiceDescriptor service;
1941     HostAttributesEntry host;
1942 };
1943 
set(const char *,Value & v,SnortConfig * sc)1944 bool HostsModule::set(const char*, Value& v, SnortConfig* sc)
1945 {
1946     if ( host and v.is("ip") )
1947     {
1948         SfIp addr;
1949         v.get_addr(addr);
1950         host->set_ip_addr(addr);
1951     }
1952 
1953     else if ( host and v.is("frag_policy") )
1954         host->set_frag_policy(v.get_uint8() + 1);
1955 
1956     else if ( host and v.is("tcp_policy") )
1957         host->set_stream_policy(v.get_uint8());
1958 
1959     else if ( v.is("name") )
1960         service.snort_protocol_id = sc->proto_ref->add(v.get_string());
1961 
1962     else if ( v.is("proto") )
1963         service.ipproto = sc->proto_ref->add(v.get_string());
1964 
1965     else if ( v.is("port") )
1966         service.port = v.get_uint16();
1967 
1968     return true;
1969 }
1970 
begin(const char * fqn,int idx,SnortConfig *)1971 bool HostsModule::begin(const char* fqn, int idx, SnortConfig*)
1972 {
1973     if ( idx && !strcmp(fqn, "hosts.services") )
1974         service.reset();
1975     else if ( idx && !strcmp(fqn, "hosts") )
1976         host.reset(new HostAttributesDescriptor);
1977 
1978     return true;
1979 }
1980 
end(const char * fqn,int idx,SnortConfig * sc)1981 bool HostsModule::end(const char* fqn, int idx, SnortConfig* sc)
1982 {
1983     if ( idx && !strcmp(fqn, "hosts.services") )
1984     {
1985         bool updated = false;
1986         host->update_service(service.port, service.ipproto, service.snort_protocol_id, updated);
1987         service.reset();
1988     }
1989     else if ( idx && !strcmp(fqn, "hosts") )
1990     {
1991         if ( !HostAttributesManager::add_host(host, sc) )
1992             host.reset();
1993         host = nullptr;
1994     }
1995 
1996     return true;
1997 }
1998 
1999 //-------------------------------------------------------------------------
2000 // module manager stuff - move to framework/module_manager.cc
2001 //-------------------------------------------------------------------------
2002 
module_init()2003 void module_init()
2004 {
2005     // parameters must be settable regardless of sequence
2006     // since Lua calls this by table hash key traversal
2007     // (which is effectively random)
2008     // so module interdependencies must come after this phase
2009     ModuleManager::add_module(get_snort_module());
2010 
2011     // these modules are not policy specific
2012     ModuleManager::add_module(new ClassificationsModule);
2013     ModuleManager::add_module(new CodecModule);
2014     ModuleManager::add_module(new DetectionModule);
2015     ModuleManager::add_module(new MemoryModule);
2016     ModuleManager::add_module(new PacketTracerModule);
2017     ModuleManager::add_module(new PacketsModule);
2018     ModuleManager::add_module(new ProcessModule);
2019     ModuleManager::add_module(new ProfilerModule);
2020     ModuleManager::add_module(new ReferencesModule);
2021     ModuleManager::add_module(new SearchEngineModule);
2022     ModuleManager::add_module(new SFDAQModule);
2023     ModuleManager::add_module(new PayloadInjectorModule);
2024 
2025     // these could but probably shouldn't be policy specific
2026     // or should be broken into policy and non-policy parts
2027     ModuleManager::add_module(new AlertsModule);
2028     ModuleManager::add_module(new EventQueueModule);
2029     ModuleManager::add_module(new OutputModule);
2030 
2031     // these modules could be in traffic policy
2032     ModuleManager::add_module(new ActiveModule);
2033 
2034     ModuleManager::add_module(new LatencyModule);
2035 
2036     ModuleManager::add_module(new SideChannelModule);
2037     ModuleManager::add_module(new HighAvailabilityModule);
2038 
2039     // these modules should be in ips policy
2040     ModuleManager::add_module(new EventFilterModule);
2041     ModuleManager::add_module(new RateFilterModule);
2042     ModuleManager::add_module(new SuppressModule);
2043 
2044     // these are preliminary policies
2045     ModuleManager::add_module(new NetworkModule);
2046     ModuleManager::add_module(new InspectionModule);
2047     ModuleManager::add_module(new IpsModule);
2048 
2049     // these modules replace config and hosts.xml
2050     ModuleManager::add_module(new AttributeTableModule);
2051     ModuleManager::add_module(new HostsModule);
2052     ModuleManager::add_module(new HostTrackerModule);
2053     ModuleManager::add_module(new HostCacheModule);
2054     // The TraceModule must be added last so that it can properly generate its Parameter table
2055     ModuleManager::add_module(new TraceModule);
2056 }
2057