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