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 // snort_module.cc author Russ Combs <rucombs@cisco.com>
20 
21 #ifdef HAVE_CONFIG_H
22 #include "config.h"
23 #endif
24 
25 #include "snort_module.h"
26 
27 #include <string>
28 
29 #include "detection/detect.h"
30 #include "detection/fp_detect.h"
31 #include "framework/module.h"
32 #include "framework/parameter.h"
33 #include "log/messages.h"
34 #include "main.h"
35 #include "main/snort_debug.h"
36 #include "managers/codec_manager.h"
37 #include "packet_io/sfdaq_config.h"
38 #include "packet_io/trough.h"
39 #include "parser/config_file.h"
40 #include "parser/parser.h"
41 #include "parser/parse_utils.h"
42 #include "parser/vars.h"
43 #include "trace/trace_config.h"
44 
45 #if defined(UNIT_TEST) || defined(BENCHMARK_TEST)
46 #include "catch/unit_test.h"
47 #endif
48 
49 #include "analyzer.h"
50 #include "help.h"
51 #include "shell.h"
52 #include "snort_config.h"
53 #include "thread_config.h"
54 
55 using namespace snort;
56 using namespace std;
57 
58 //-------------------------------------------------------------------------
59 // commands
60 //-------------------------------------------------------------------------
61 
62 #ifdef SHELL
63 static const Parameter s_reload[] =
64 {
65     { "filename", Parameter::PT_STRING, nullptr, nullptr,
66       "name of file to load" },
67 
68     { nullptr, Parameter::PT_MAX, nullptr, nullptr, nullptr }
69 };
70 
71 static const Parameter s_reload_w_path[] =
72 {
73     { "filename", Parameter::PT_STRING, "(optional)", nullptr,
74       "[<plugin path>] name of file to load" },
75 
76     { nullptr, Parameter::PT_MAX, nullptr, nullptr, nullptr }
77 };
78 
79 static const Parameter s_delete[] =
80 {
81     { "inspector", Parameter::PT_STRING, nullptr, nullptr,
82       "name of inspector to delete" },
83 
84     { nullptr, Parameter::PT_MAX, nullptr, nullptr, nullptr }
85 };
86 
87 static const Parameter s_module[] =
88 {
89     { "module", Parameter::PT_STRING, nullptr, nullptr,
90       "name of the module to reload" },
91 
92     { nullptr, Parameter::PT_MAX, nullptr, nullptr, nullptr }
93 };
94 
95 static const Parameter s_pktnum[] =
96 {
97     { "pkt_num", Parameter::PT_INT, "1:max53", nullptr,
98       "resume and pause after pkt_num packets" },
99 
100     { nullptr, Parameter::PT_MAX, nullptr, nullptr, nullptr }
101 };
102 
103 static const Command snort_cmds[] =
104 {
105     { "show_plugins", main_dump_plugins, nullptr, "show available plugins" },
106 
107     { "delete_inspector", main_delete_inspector, s_delete,
108       "delete an inspector from the default policy" },
109 
110     { "dump_stats", main_dump_stats, nullptr, "show summary statistics" },
111     { "reset_stats", main_reset_stats, nullptr, "clear summary statistics" },
112     { "rotate_stats", main_rotate_stats, nullptr, "roll perfmonitor log files" },
113     { "reload_config", main_reload_config, s_reload_w_path, "load new configuration" },
114     { "reload_policy", main_reload_policy, s_reload, "reload part or all of the default policy" },
115     { "reload_module", main_reload_module, s_module, "reload module" },
116     { "reload_daq", main_reload_daq, nullptr, "reload daq module" },
117     { "reload_hosts", main_reload_hosts, s_reload, "load a new hosts table" },
118 
119     // FIXIT-M rewrite trough to permit updates on the fly
120     //{ "process", main_process, nullptr, "process given pcap" },
121 
122     { "pause", main_pause, nullptr, "suspend packet processing" },
123 
124     { "resume", main_resume, s_pktnum, "continue packet processing. "
125       "If number of packets is specified, will resume for n packets and pause" },
126 
127     { "detach", main_detach, nullptr, "detach from control shell (without shutting down)" },
128     { "quit", main_quit, nullptr, "shutdown and dump-stats" },
129     { "help", main_help, nullptr, "this output" },
130 
131     { nullptr, nullptr, nullptr, nullptr }
132 };
133 #endif
134 
135 //-------------------------------------------------------------------------
136 // hex conversion helper funcs
137 //-------------------------------------------------------------------------
138 
c2x(const char * s)139 [[noreturn]] static void c2x(const char* s)
140 {
141     printf("'%c' = 0x%2.2X (%d)\n", s[0], s[0], s[0]);
142     exit(0);
143 }
144 
x2c(uint8_t x)145 [[noreturn]] static void x2c(uint8_t x)
146 {
147     printf("0x%2.2X (%u) = '%c'\n", x, x, static_cast<char>(x));
148     exit(0);
149 }
150 
x2s(const char * s)151 [[noreturn]] static void x2s(const char* s)
152 {
153     bool inv;
154     string out, in = "\"";
155     in += s;
156     in += "\"";
157 
158     if ( parse_byte_code(in.c_str(), inv, out) )
159         printf("%s = '%s'\n", s, out.c_str());
160 
161     else
162         printf("%s = '%s'\n", s, "error");
163 
164     exit(0);
165 }
166 
167 //-------------------------------------------------------------------------
168 // parameters
169 //
170 // users aren't used to seeing the standard help format for command line
171 // args so the few cases where there is a default, we include it in the
172 // help as well.
173 //
174 // command line options can be specified in Lua instead by doing e.g.
175 //
176 //     snort = { }; snort["-z"] = 2
177 //
178 // so a default value can't be provided for args that kick off optional
179 // run modes such as --rule-to-text because the program will do strange
180 // things like waiting on stdin for input that won't be coming.  in these
181 // cases the default must only be indicated in the help.
182 //-------------------------------------------------------------------------
183 
184 static const TraceOption snort_trace_options[] =
185 {
186     { "inspector_manager", TRACE_INSPECTOR_MANAGER, "enable inspector manager trace logging" },
187 #ifdef DEBUG_MSGS
188     { "main", TRACE_MAIN, "enable main trace logging" },
189 #endif
190 
191     { nullptr, 0, nullptr }
192 };
193 
194 static const Parameter s_params[] =
195 {
196     { "-?", Parameter::PT_STRING, "(optional)", nullptr,
197       "<option prefix> output matching command line option quick help (same as --help-options)" },
198 
199     // FIXIT-M should use PluginManager::get_available_plugins(PT_LOGGER)
200     // but plugins not yet loaded upon set
201     { "-A", Parameter::PT_STRING, nullptr, nullptr,
202       "<mode> set alert mode: none, cmg, or alert_*" },
203 
204     { "-B", Parameter::PT_ADDR, nullptr, "255.255.255.255/32",
205       "<mask> obfuscated IP addresses in alerts and packet dumps using CIDR mask" },
206 
207     { "-C", Parameter::PT_IMPLIED, nullptr, nullptr,
208       "print out payloads with character data only (no hex)" },
209 
210     { "-c", Parameter::PT_STRING, nullptr, nullptr,
211       "<conf> use this configuration" },
212 
213     { "-D", Parameter::PT_IMPLIED, nullptr, nullptr,
214       "run Snort in background (daemon) mode" },
215 
216     { "-d", Parameter::PT_IMPLIED, nullptr, nullptr,
217       "dump the Application Layer" },
218 
219     { "-e", Parameter::PT_IMPLIED, nullptr, nullptr,
220       "display the second layer header info" },
221 
222     { "-f", Parameter::PT_IMPLIED, nullptr, nullptr,
223       "turn off fflush() calls after binary log writes" },
224 
225     { "-G", Parameter::PT_INT, "0:65535", nullptr,
226       "<0xid> (same as --logid)" },
227 
228     { "-g", Parameter::PT_STRING, nullptr, nullptr,
229       "<gname> run snort gid as <gname> group (or gid) after initialization" },
230 
231     { "-H", Parameter::PT_IMPLIED, nullptr, nullptr,
232       "make hash tables deterministic" },
233 
234     { "-h", Parameter::PT_IMPLIED, nullptr, nullptr,
235       "show help overview (same as --help)" },
236 
237     { "-i", Parameter::PT_STRING, nullptr, nullptr,
238       "<iface>... list of interfaces" },
239 
240 #ifdef SHELL
241     { "-j", Parameter::PT_PORT, nullptr, nullptr,
242       "<port> to listen for Telnet connections" },
243 #endif
244 
245     { "-k", Parameter::PT_ENUM, "all|noip|notcp|noudp|noicmp|none", "all",
246       "<mode> checksum mode; default is all" },
247 
248     { "-L", Parameter::PT_STRING, nullptr, nullptr,
249       "<mode> logging mode (none, dump, pcap, or log_*)" },
250 
251     { "-l", Parameter::PT_STRING, nullptr, nullptr,
252       "<logdir> log to this directory instead of current directory" },
253 
254     { "-M", Parameter::PT_IMPLIED, nullptr, nullptr,
255       "log messages to syslog (not alerts)" },
256 
257     { "-m", Parameter::PT_INT, "0x000:0x1FF", nullptr,
258       "<umask> set the process file mode creation mask" },
259 
260     { "-n", Parameter::PT_INT, "0:max53", nullptr,
261       "<count> stop after count packets" },
262 
263     { "-O", Parameter::PT_IMPLIED, nullptr, nullptr,
264       "obfuscate the logged IP addresses" },
265 
266     { "-Q", Parameter::PT_IMPLIED, nullptr, nullptr,
267       "enable inline mode operation" },
268 
269     { "-q", Parameter::PT_IMPLIED, nullptr, nullptr,
270       "quiet mode - suppress normal logging on stdout" },
271 
272     { "-R", Parameter::PT_STRING, nullptr, nullptr,
273       "<rules> include this rules file in the default policy" },
274 
275     { "-r", Parameter::PT_STRING, nullptr, nullptr,
276       "<pcap>... (same as --pcap-list)" },
277 
278     { "-s", Parameter::PT_INT, "68:65535", "1518",
279       "<snap> (same as --snaplen); default is 1518" },
280 
281     { "-T", Parameter::PT_IMPLIED, nullptr, nullptr,
282       "test and report on the current Snort configuration" },
283 
284     { "-t", Parameter::PT_STRING, nullptr, nullptr,
285       "<dir> chroots process to <dir> after initialization" },
286 
287     { "-U", Parameter::PT_IMPLIED, nullptr, nullptr,
288       "use UTC for timestamps" },
289 
290     { "-u", Parameter::PT_STRING, nullptr, nullptr,
291       "<uname> run snort as <uname> or <uid> after initialization" },
292 
293     { "-V", Parameter::PT_IMPLIED, nullptr, nullptr,
294       "(same as --version)" },
295 
296     { "-v", Parameter::PT_IMPLIED, nullptr, nullptr,
297       "be verbose" },
298 
299     { "-X", Parameter::PT_IMPLIED, nullptr, nullptr,
300       "dump the raw packet data starting at the link layer" },
301 
302     { "-x", Parameter::PT_IMPLIED, nullptr, nullptr,
303       "same as --pedantic" },
304 
305     { "-y", Parameter::PT_IMPLIED, nullptr, nullptr,
306       "include year in timestamp in the alert and log files" },
307 
308     // do not provide parameter default as it will cause the value to change
309     // after allocations in SnortConfig if snort = { } is set in Lua
310     { "-z", Parameter::PT_INT, "0:max32", nullptr,
311       "<count> maximum number of packet threads (same as --max-packet-threads); "
312       "0 gets the number of CPU cores reported by the system; default is 1" },
313 
314     { "--alert-before-pass", Parameter::PT_IMPLIED, nullptr, nullptr,
315       "evaluate alert rules before pass rules; default is pass rules first" },
316 
317     { "--bpf", Parameter::PT_STRING, nullptr, nullptr,
318       "<filter options> are standard BPF options, as seen in TCPDump" },
319 
320     { "--c2x", Parameter::PT_STRING, nullptr, nullptr,
321       "output hex for given char (see also --x2c)" },
322 
323 #ifdef SHELL
324     { "--control-socket", Parameter::PT_STRING, nullptr, nullptr,
325       "<file> to create unix socket" },
326 #endif
327 
328     { "--create-pidfile", Parameter::PT_IMPLIED, nullptr, nullptr,
329       "create PID file, even when not in Daemon mode" },
330 
331     { "--daq", Parameter::PT_STRING, nullptr, nullptr,
332       "<type> select packet acquisition module (default is pcap)" },
333 
334     { "--daq-batch-size", Parameter::PT_INT, "1:", "64",
335       "<size> set the DAQ receive batch size", },
336 
337     { "--daq-dir", Parameter::PT_STRING, nullptr, nullptr,
338       "<dir> tell snort where to find desired DAQ" },
339 
340     { "--daq-list", Parameter::PT_IMPLIED, nullptr, nullptr,
341       "list packet acquisition modules available in optional dir, default is static modules only" },
342 
343     { "--daq-mode", Parameter::PT_ENUM, "passive | inline | read-file", nullptr,
344       "<mode> select DAQ module operating mode (overrides automatic selection)" },
345 
346     { "--daq-var", Parameter::PT_STRING, nullptr, nullptr,
347       "<name=value> specify extra DAQ configuration variable" },
348 
349     { "--dirty-pig", Parameter::PT_IMPLIED, nullptr, nullptr,
350       "don't flush packets on shutdown" },
351 
352     { "--dump-builtin-options", Parameter::PT_STRING, nullptr, nullptr,
353       "additional options to include with --dump-builtin-rules stubs" },
354 
355     { "--dump-builtin-rules", Parameter::PT_STRING, "(optional)", nullptr,
356       "[<module prefix>] output stub rules for selected modules" },
357 
358     { "--dump-config", Parameter::PT_SELECT, "all | top", nullptr,
359       "dump config in json format" },
360 
361     { "--dump-config-text", Parameter::PT_IMPLIED, nullptr, nullptr,
362       "dump config in text format" },
363 
364     // FIXIT-L add --list-dynamic-rules like --list-builtin-rules
365     { "--dump-dynamic-rules", Parameter::PT_IMPLIED, nullptr, nullptr,
366       "output stub rules for all loaded rules libraries" },
367 
368     { "--dump-defaults", Parameter::PT_STRING, "(optional)", nullptr,
369       "[<module prefix>] output module defaults in Lua format" },
370 
371     { "--dump-rule-databases", Parameter::PT_STRING, nullptr, nullptr,
372       "dump rule databases to given directory (hyperscan only)" },
373 
374     { "--dump-rule-deps", Parameter::PT_IMPLIED, nullptr, nullptr,
375       "dump rule dependencies in json format for use by other tools" },
376 
377     { "--dump-rule-meta", Parameter::PT_IMPLIED, nullptr, nullptr,
378       "dump configured rule info in json format for use by other tools" },
379 
380     { "--dump-rule-state", Parameter::PT_IMPLIED, nullptr, nullptr,
381       "dump configured rule state in json format for use by other tools" },
382 
383     { "--dump-version", Parameter::PT_IMPLIED, nullptr, nullptr,
384       "output the version, the whole version, and only the version" },
385 
386     { "--enable-inline-test", Parameter::PT_IMPLIED, nullptr, nullptr,
387       "enable Inline-Test Mode Operation" },
388 
389     { "--enable-test-features", Parameter::PT_IMPLIED, nullptr, nullptr,
390       "enable features used in testing" },
391 
392     { "--gen-msg-map", Parameter::PT_IMPLIED, nullptr, nullptr,
393       "dump configured rules in gen-msg.map format for use by other tools" },
394 
395     { "--help", Parameter::PT_IMPLIED, nullptr, nullptr,
396       "show help overview" },
397 
398     { "--help-commands", Parameter::PT_STRING, "(optional)", nullptr,
399       "[<module prefix>] output matching commands" },
400 
401     { "--help-config", Parameter::PT_STRING, "(optional)", nullptr,
402       "[<module prefix>] output matching config options" },
403 
404     { "--help-counts", Parameter::PT_STRING, "(optional)", nullptr,
405       "[<module prefix>] output matching peg counts" },
406 
407     { "--help-limits", Parameter::PT_IMPLIED, nullptr, nullptr,
408       "print the int upper bounds denoted by max*" },
409 
410     { "--help-module", Parameter::PT_STRING, nullptr, nullptr,
411       "<module> output description of given module" },
412 
413     { "--help-modules", Parameter::PT_IMPLIED, nullptr, nullptr,
414       "list all available modules with brief help" },
415 
416     { "--help-modules-json", Parameter::PT_IMPLIED, nullptr, nullptr,
417       "dump description of all available modules in JSON format" },
418 
419     { "--help-options", Parameter::PT_STRING, "(optional)", nullptr,
420       "[<option prefix>] output matching command line option quick help (same as -?)" },
421 
422     { "--help-plugins", Parameter::PT_IMPLIED, nullptr, nullptr,
423       "list all available plugins with brief help" },
424 
425     { "--help-signals", Parameter::PT_IMPLIED, nullptr, nullptr,
426       "dump available control signals" },
427 
428     { "--id-offset", Parameter::PT_INT, "0:65535", "0",
429       "offset to add to instance IDs when logging to files" },
430 
431     { "--id-subdir", Parameter::PT_IMPLIED, nullptr, nullptr,
432       "create/use instance subdirectories in logdir instead of instance filename prefix" },
433 
434     { "--id-zero", Parameter::PT_IMPLIED, nullptr, nullptr,
435       "use id prefix / subdirectory even with one packet thread" },
436 
437     { "--include-path", Parameter::PT_STRING, nullptr, nullptr,
438       "<path> where to find Lua and rule included files; "
439       "searched before current or config directories" },
440 
441     { "--list-buffers", Parameter::PT_IMPLIED, nullptr, nullptr,
442       "output available inspection buffers" },
443 
444     { "--list-builtin", Parameter::PT_STRING, "(optional)", nullptr,
445       "[<module prefix>] output matching builtin rules" },
446 
447     { "--list-gids", Parameter::PT_STRING, "(optional)", nullptr,
448       "[<module prefix>] output matching generators" },
449 
450     { "--list-modules", Parameter::PT_STRING, "(optional)", nullptr,
451       "[<module type>] list all known modules of given type" },
452 
453     { "--list-plugins", Parameter::PT_IMPLIED, nullptr, nullptr,
454       "list all known plugins" },
455 
456     { "--lua", Parameter::PT_STRING, nullptr, nullptr,
457       "<chunk> extend/override conf with chunk; may be repeated" },
458 
459     { "--lua-sandbox", Parameter::PT_STRING, nullptr, nullptr,
460       "<file> file that contains the lua sandbox environment in which config will be loaded" },
461 
462     { "--logid", Parameter::PT_INT, "0:65535", nullptr,
463       "<0xid> log Identifier to uniquely id events for multiple snorts (same as -G)" },
464 
465     { "--markup", Parameter::PT_IMPLIED, nullptr, nullptr,
466       "output help in asciidoc compatible format" },
467 
468     { "--max-packet-threads", Parameter::PT_INT, "0:max32", nullptr,
469       "<count> configure maximum number of packet threads (same as -z)" },
470 
471     { "--mem-check", Parameter::PT_IMPLIED, nullptr, nullptr,
472       "like -T but also compile search engines" },
473 
474     { "--metadata-filter", Parameter::PT_STRING, nullptr, nullptr,
475       "<filter> load only rules containing filter string in metadata if set" },
476 
477     { "--nostamps", Parameter::PT_IMPLIED, nullptr, nullptr,
478       "don't include timestamps in log file names" },
479 
480     { "--nolock-pidfile", Parameter::PT_IMPLIED, nullptr, nullptr,
481       "do not try to lock Snort PID file" },
482 
483     { "--no-warn-flowbits", Parameter::PT_IMPLIED, nullptr, nullptr,
484       "ignore warnings about flowbits that are checked but not set and vice-versa" },
485 
486     { "--no-warn-rules", Parameter::PT_IMPLIED, nullptr, nullptr,
487       "ignore warnings about duplicate rules and rule parsing issues" },
488 
489     { "--pause", Parameter::PT_IMPLIED, nullptr, nullptr,
490       "wait for resume/quit command before processing packets/terminating", },
491 
492 #ifdef REG_TEST
493     { "--pause-after-n", Parameter::PT_INT, "1:max53", nullptr,
494       "<count> pause after count packets", },
495 #endif
496 
497     { "--pcap-file", Parameter::PT_STRING, nullptr, nullptr,
498       "<file> file that contains a list of pcaps to read - read mode is implied" },
499 
500     { "--pcap-list", Parameter::PT_STRING, nullptr, nullptr,
501       "<list> a space separated list of pcaps to read - read mode is implied" },
502 
503     { "--pcap-dir", Parameter::PT_STRING, nullptr, nullptr,
504       "<dir> a directory to recurse to look for pcaps - read mode is implied" },
505 
506     { "--pcap-filter", Parameter::PT_STRING, nullptr, "*.*cap*",
507       "<filter> filter to apply when getting pcaps from file or directory" },
508 
509     { "--pcap-loop", Parameter::PT_INT, "0:max32", nullptr,
510       "<count> read all pcaps <count> times;  0 will read until Snort is terminated" },
511 
512     { "--pcap-no-filter", Parameter::PT_IMPLIED, nullptr, nullptr,
513       "reset to use no filter when getting pcaps from file or directory" },
514 
515     { "--pcap-show", Parameter::PT_IMPLIED, nullptr, nullptr,
516       "print a line saying what pcap is currently being read" },
517 
518     { "--pedantic", Parameter::PT_IMPLIED, nullptr, nullptr,
519       "warnings are fatal" },
520 
521 #ifdef PIGLET
522     { "--piglet", Parameter::PT_IMPLIED, nullptr, nullptr,
523       "enable piglet test harness mode" },
524 #endif
525 
526     { "--plugin-path", Parameter::PT_STRING, nullptr, nullptr,
527       "<path> a colon separated list of directories or plugin libraries" },
528 
529     { "--process-all-events", Parameter::PT_IMPLIED, nullptr, nullptr,
530       "process all action groups" },
531 
532     { "--rule", Parameter::PT_STRING, nullptr, nullptr,
533       "<rules> to be added to configuration; may be repeated" },
534 
535     { "--rule-path", Parameter::PT_STRING, nullptr, nullptr,
536       "<path> where to find rules files" },
537 
538     { "--rule-to-hex", Parameter::PT_IMPLIED, nullptr, nullptr,
539       "output so rule header to stdout for text rule on stdin" },
540 
541     { "--rule-to-text", Parameter::PT_STRING, "16", nullptr,
542       "output plain so rule header to stdout for text rule on stdin "
543       "(specify delimiter or [Snort_SO_Rule] will be used)" },
544 
545     { "--run-prefix", Parameter::PT_STRING, nullptr, nullptr,
546       "<pfx> prepend this to each output file" },
547 
548     { "--script-path", Parameter::PT_STRING, nullptr, nullptr,
549       "<path> to a luajit script or directory containing luajit scripts" },
550 
551 #ifdef SHELL
552     { "--shell", Parameter::PT_IMPLIED, nullptr, nullptr,
553       "enable the interactive command line", },
554 #endif
555 
556     { "--show-file-codes", Parameter::PT_IMPLIED, nullptr, nullptr,
557       "indicate how files are located: A=absolute and W, F, C which are relative "
558       "to the working directory, including file, and config file respectively" },
559 
560     { "--show-plugins", Parameter::PT_IMPLIED, nullptr, nullptr,
561       "list module and plugin versions", },
562 
563     { "--skip", Parameter::PT_INT, "0:max53", nullptr,
564       "<n> skip 1st n packets", },
565 
566     { "--snaplen", Parameter::PT_INT, "68:65535", "1518",
567       "<snap> set snaplen of packet (same as -s)", },
568 
569     { "--stdin-rules", Parameter::PT_IMPLIED, nullptr, nullptr,
570       "read rules from stdin until EOF or a line starting with END is read", },
571 
572     { "--talos", Parameter::PT_IMPLIED, nullptr, nullptr,
573       "enable Talos tweak (same as --tweaks talos)", },
574 
575     { "--tweaks", Parameter::PT_STRING, nullptr, nullptr,
576       "tune configuration" },
577 
578 #if defined(UNIT_TEST) || defined(BENCHMARK_TEST)
579     { "--catch-test", Parameter::PT_STRING, nullptr, nullptr,
580       "comma separated list of Catch test tags or 'all'" },
581 #endif
582     { "--version", Parameter::PT_IMPLIED, nullptr, nullptr,
583       "show version number (same as -V)" },
584 
585     { "--warn-all", Parameter::PT_IMPLIED, nullptr, nullptr,
586       "enable all warnings" },
587 
588     { "--warn-conf", Parameter::PT_IMPLIED, nullptr, nullptr,
589       "warn about configuration issues" },
590 
591     { "--warn-conf-strict", Parameter::PT_IMPLIED, nullptr, nullptr,
592       "warn about unrecognized elements in configuration files" },
593 
594     { "--warn-daq", Parameter::PT_IMPLIED, nullptr, nullptr,
595       "warn about DAQ issues, usually related to mode" },
596 
597     { "--warn-flowbits", Parameter::PT_IMPLIED, nullptr, nullptr,
598       "warn about flowbits that are checked but not set and vice-versa" },
599 
600     { "--warn-hosts", Parameter::PT_IMPLIED, nullptr, nullptr,
601       "warn about host table issues" },
602 
603     { "--warn-plugins", Parameter::PT_IMPLIED, nullptr, nullptr,
604       "warn about issues that prevent plugins from loading" },
605 
606     { "--warn-rules", Parameter::PT_IMPLIED, nullptr, nullptr,
607       "warn about duplicate rules and rule parsing issues" },
608 
609     { "--warn-scripts", Parameter::PT_IMPLIED, nullptr, nullptr,
610       "warn about issues discovered while processing Lua scripts" },
611 
612     { "--warn-symbols", Parameter::PT_IMPLIED, nullptr, nullptr,
613       "warn about unknown symbols in your Lua config" },
614 
615     { "--warn-vars", Parameter::PT_IMPLIED, nullptr, nullptr,
616       "warn about variable definition and usage issues" },
617 
618     { "--x2c", Parameter::PT_INT, "0x00:0xFF", nullptr,
619       "output ASCII char for given hex (see also --c2x)" },
620 
621     { "--x2s", Parameter::PT_STRING, nullptr, nullptr,
622       "output ASCII string for given byte code (see also --x2c)" },
623 
624     { nullptr, Parameter::PT_MAX, nullptr, nullptr, nullptr }
625 };
626 
627 //-------------------------------------------------------------------------
628 // module
629 //-------------------------------------------------------------------------
630 
631 #define s_name "snort"
632 
633 #ifdef SHELL
634 #define s_help \
635     "command line configuration and shell commands"
636 #else
637 #define s_help \
638     "command line configuration"
639 #endif
640 
641 THREAD_LOCAL const Trace* snort_trace = nullptr;
642 
643 class SnortModule : public Module
644 {
645 public:
SnortModule()646     SnortModule() : Module(s_name, s_help, s_params)
647     { }
648 
649 #ifdef SHELL
get_commands() const650     const Command* get_commands() const override
651     { return snort_cmds; }
652 #endif
653 
654     bool begin(const char*, int, SnortConfig*) override;
655     bool set(const char*, Value&, SnortConfig*) override;
656     bool end(const char*, int, SnortConfig*) override;
657 
get_pegs() const658     const PegInfo* get_pegs() const override
659     { return proc_names; }
660 
get_counts() const661     PegCount* get_counts() const override
662     { return (PegCount*)&proc_stats; }
663 
global_stats() const664     bool global_stats() const override
665     { return true; }
666 
sum_stats(bool)667     void sum_stats(bool) override
668     { }  // accumulate externally
669 
670     ProfileStats* get_profile(unsigned, const char*&, const char*&) const override;
671 
get_usage() const672     Usage get_usage() const override
673     { return GLOBAL; }
674 
675     void set_trace(const Trace*) const override;
676     const TraceOption* get_trace_options() const override;
677 
678 private:
679     SFDAQModuleConfig* module_config;
680     bool no_warn_flowbits = false;
681     bool no_warn_rules = false;
682     std::string stub_opts;
683 };
684 
set_trace(const Trace * trace) const685 void SnortModule::set_trace(const Trace* trace) const
686 { snort_trace = trace; }
687 
get_trace_options() const688 const TraceOption* SnortModule::get_trace_options() const
689 {
690     return snort_trace_options;
691 }
692 
begin(const char * fqn,int,SnortConfig *)693 bool SnortModule::begin(const char* fqn, int, SnortConfig*)
694 {
695     if (!strcmp(fqn, "snort"))
696         module_config = nullptr;
697     return true;
698 }
699 
set(const char *,Value & v,SnortConfig * sc)700 bool SnortModule::set(const char*, Value& v, SnortConfig* sc)
701 {
702     if ( v.is("-?") )
703         help_options(sc, v.get_string());
704 
705     else if ( v.is("-A") )
706         sc->set_alert_mode(v.get_string());
707 
708     else if ( v.is("-B") )
709         sc->set_obfuscation_mask(v.get_string());
710 
711     else if ( v.is("-C") )
712         sc->set_dump_chars_only(true);
713 
714     else if ( v.is("-c") )
715         config_conf(v.get_string());
716 
717     else if ( v.is("-D") )
718         sc->set_daemon(true);
719 
720     else if ( v.is("-d") )
721         sc->set_dump_payload(true);
722 
723     else if ( v.is("-e") )
724         sc->set_decode_data_link(true);
725 
726     else if ( v.is("-f") )
727         sc->output_flags |= OUTPUT_FLAG__LINE_BUFFER;
728 
729     else if ( v.is("-G") || v.is("--logid") )
730         sc->event_log_id = v.get_uint16();
731 
732     else if ( v.is("-g") )
733         sc->set_gid(v.get_string());
734 
735     else if ( v.is("-H") )
736         sc->run_flags |= RUN_FLAG__STATIC_HASH;
737 
738     else if ( v.is("-h") )
739         help_basic(sc, v.get_string());
740 
741     else if ( v.is("-i") )
742         sc->daq_config->add_input(v.get_string());
743 
744 #ifdef SHELL
745     else if ( v.is("-j") )
746     {
747         sc->remote_control_port = v.get_uint16();
748         sc->remote_control_socket.clear();
749     }
750 #endif
751 
752     else if ( v.is("-k") )
753         ConfigChecksumMode(v.get_string());
754 
755     else if ( v.is("-L") )
756         sc->set_log_mode(v.get_string());
757 
758     else if ( v.is("-l") )
759         sc->set_log_dir(v.get_string());
760 
761     else if ( v.is("-M") )
762         sc->enable_syslog();
763 
764     else if ( v.is("-m") )
765         sc->set_umask(v.get_uint32());
766 
767     else if ( v.is("-n") )
768         sc->pkt_cnt = v.get_uint64();
769 
770     else if ( v.is("-O") )
771         sc->set_obfuscate(true);
772 
773     else if ( v.is("-Q") )
774         sc->run_flags |= RUN_FLAG__INLINE;
775 
776     else if ( v.is("-q") )
777         SnortConfig::set_log_quiet(true);
778 
779     else if ( v.is("-R") )
780     {
781         string s = "include ";
782         s += v.get_string();
783         parser_append_rules(s.c_str());
784     }
785     else if ( v.is("-r") || v.is("--pcap-list") )
786     {
787         sc->run_flags |= RUN_FLAG__READ;
788         Trough::add_source(Trough::SOURCE_LIST, v.get_string());
789     }
790 
791     else if ( v.is("-s") or v.is("--snaplen") )
792         sc->daq_config->set_mru_size(v.get_uint16());
793 
794     else if ( v.is("-T") )
795         sc->run_flags |= RUN_FLAG__TEST;
796 
797     else if ( v.is("-t") )
798         sc->set_chroot_dir(v.get_string());
799 
800     else if ( v.is("-U") )
801         sc->set_utc(true);
802 
803     else if ( v.is("-u") )
804         sc->set_uid(v.get_string());
805 
806     else if ( v.is("-V") )
807         help_version(sc);
808 
809     else if ( v.is("-v") )
810         SnortConfig::enable_log_verbose();
811 
812     else if ( v.is("-X") )
813         sc->set_dump_payload_verbose(true);
814 
815     else if ( v.is("-x") || v.is("--pedantic") )
816         sc->run_flags |= RUN_FLAG__CONF_ERROR_OUT;
817 
818     else if ( v.is("-y") )
819         sc->set_show_year(true);
820 
821     else if ( v.is("-z") || v.is("--max-packet-threads") )
822         ThreadConfig::set_instance_max(v.get_uint32());
823 
824     else if ( v.is("--alert-before-pass") )
825         sc->set_alert_before_pass(true);
826 
827     else if ( v.is("--bpf") )
828         sc->bpf_filter = v.get_string();
829 
830     else if ( v.is("--c2x") )
831         c2x(v.get_string());
832 
833 #ifdef SHELL
834     else if ( v.is("--control-socket") )
835     {
836         sc->remote_control_socket = v.get_string();
837         sc->remote_control_port = 0;
838     }
839 #endif
840 
841     else if ( v.is("--create-pidfile") )
842         sc->set_create_pid_file(true);
843 
844     else if ( v.is("--daq") )
845         module_config = sc->daq_config->add_module_config(v.get_string());
846 
847     else if ( v.is("--daq-batch-size") )
848         sc->daq_config->set_batch_size(v.get_uint32());
849 
850     else if ( v.is("--daq-dir") )
851     {
852         stringstream ss { v.get_string() };
853         string path;
854 
855         while ( getline(ss, path, ':') )
856             sc->daq_config->add_module_dir(path.c_str());
857     }
858     else if ( v.is("--daq-mode") )
859     {
860         if (!module_config)
861             return false;
862         switch ( v.get_uint8() )
863         {
864             case 0:
865                 module_config->mode = SFDAQModuleConfig::SFDAQ_MODE_PASSIVE;
866                 break;
867             case 1:
868                 module_config->mode = SFDAQModuleConfig::SFDAQ_MODE_INLINE;
869                 break;
870             case 2:
871                 module_config->mode = SFDAQModuleConfig::SFDAQ_MODE_READ_FILE;
872                 break;
873         }
874     }
875     else if ( v.is("--daq-list") )
876         list_daqs(sc);
877 
878     else if ( v.is("--daq-var") )
879     {
880         if (!module_config)
881             return false;
882         module_config->set_variable(v.get_string());
883     }
884     else if ( v.is("--dirty-pig") )
885         sc->set_dirty_pig(true);
886 
887     else if ( v.is("--dump-builtin-options") )
888         stub_opts = v.get_string();
889 
890     else if ( v.is("--dump-builtin-rules") )
891         dump_builtin_rules(sc, v.get_string(), stub_opts.c_str());
892 
893     else if ( v.is("--dump-config") )
894     {
895         SnortConfig::set_log_quiet(true);
896         sc->run_flags |= RUN_FLAG__TEST;
897         if ( v.get_as_string() == "all" )
898             sc->dump_config_type = DUMP_CONFIG_JSON_ALL;
899         else if ( v.get_as_string() == "top" )
900             sc->dump_config_type = DUMP_CONFIG_JSON_TOP;
901     }
902 
903     else if ( v.is("--dump-config-text") )
904     {
905         SnortConfig::set_log_quiet(true);
906         sc->run_flags |= RUN_FLAG__TEST;
907         sc->dump_config_type = DUMP_CONFIG_TEXT;
908     }
909 
910     else if ( v.is("--dump-dynamic-rules") )
911         dump_dynamic_rules(sc, v.get_string());
912 
913     else if ( v.is("--dump-defaults") )
914         dump_defaults(sc, v.get_string());
915 
916     else if ( v.is("--dump-rule-databases") )
917     {
918         sc->set_rule_db_dir(v.get_string());
919         sc->run_flags |= (RUN_FLAG__TEST | RUN_FLAG__MEM_CHECK);
920     }
921     else if ( v.is("--dump-rule-deps") )
922     {
923         sc->run_flags |= (RUN_FLAG__DUMP_RULE_DEPS | RUN_FLAG__TEST);
924         SnortConfig::set_log_quiet(true);
925     }
926     else if ( v.is("--dump-rule-meta") )
927     {
928         sc->run_flags |= (RUN_FLAG__DUMP_RULE_META | RUN_FLAG__TEST);
929         sc->output_flags |= OUTPUT_FLAG__ALERT_REFS;
930         SnortConfig::set_log_quiet(true);
931     }
932     else if ( v.is("--dump-rule-state") )
933     {
934         sc->run_flags |= (RUN_FLAG__DUMP_RULE_STATE | RUN_FLAG__TEST);
935         SnortConfig::set_log_quiet(true);
936     }
937     else if ( v.is("--dump-version") )
938         dump_version(sc);
939 
940     else if ( v.is("--enable-inline-test") )
941         sc->run_flags |= RUN_FLAG__INLINE_TEST;
942 
943     else if ( v.is("--enable-test-features") )
944     {
945         sc->run_flags |= RUN_FLAG__TEST_FEATURES;
946         SfIp::test_features = true;
947     }
948 
949     else if ( v.is("--gen-msg-map") )
950     {
951         sc->run_flags |= (RUN_FLAG__DUMP_MSG_MAP | RUN_FLAG__TEST);
952         sc->output_flags |= OUTPUT_FLAG__ALERT_REFS;
953         SnortConfig::set_log_quiet(true);
954     }
955     else if ( v.is("--help") )
956         help_basic(sc, v.get_string());
957 
958     else if ( v.is("--help-commands") )
959         help_commands(sc, v.get_string());
960 
961     else if ( v.is("--help-config") )
962         help_config(sc, v.get_string());
963 
964     else if ( v.is("--help-counts") )
965         help_counts(sc, v.get_string());
966 
967     else if ( v.is("--help-limits") )
968         help_limits(sc, v.get_string());
969 
970     else if ( v.is("--help-module") )
971         help_module(sc, v.get_string());
972 
973     else if ( v.is("--help-modules") )
974         help_modules(sc, v.get_string());
975 
976     else if ( v.is("--help-modules-json") )
977         help_modules_json(sc, v.get_string());
978 
979     else if ( v.is("--help-options") )
980         help_options(sc, v.get_string());
981 
982     else if ( v.is("--help-plugins") )
983         help_plugins(sc, v.get_string());
984 
985     else if ( v.is("--help-signals") )
986         help_signals(sc, v.get_string());
987 
988     else if ( v.is("--id-offset") )
989         sc->id_offset = v.get_uint16();
990 
991     else if ( v.is("--id-subdir") )
992         sc->id_subdir = true;
993 
994     else if ( v.is("--id-zero") )
995         sc->id_zero = true;
996 
997     else if ( v.is("--include-path") )
998         sc->set_include_path(v.get_string());
999 
1000     else if ( v.is("--list-buffers") )
1001         help_buffers(sc, v.get_string());
1002 
1003     else if ( v.is("--list-builtin") )
1004         help_builtin(sc, v.get_string());
1005 
1006     else if ( v.is("--list-gids") )
1007         help_gids(sc, v.get_string());
1008 
1009     else if ( v.is("--list-modules") )
1010         list_modules(sc, v.get_string());
1011 
1012     else if ( v.is("--list-plugins") )
1013         list_plugins(sc, v.get_string());
1014 
1015     else if ( v.is("--lua") )
1016         sc->policy_map->get_shell()->set_overrides(v.get_string());
1017 
1018     else if ( v.is("--lua-sandbox") )
1019         Shell::set_lua_sandbox(v.get_string());
1020 
1021     else if ( v.is("--markup") )
1022         config_markup(sc, v.get_string());
1023 
1024     else if ( v.is("--mem-check") )
1025         sc->run_flags |= (RUN_FLAG__TEST | RUN_FLAG__MEM_CHECK);
1026 
1027     else if ( v.is("--metadata-filter") )
1028         sc->metadata_filter = v.get_string();
1029 
1030     else if ( v.is("--nostamps") )
1031         sc->set_no_logging_timestamps(true);
1032 
1033     else if ( v.is("--nolock-pidfile") )
1034         sc->run_flags |= RUN_FLAG__NO_LOCK_PID_FILE;
1035 
1036     else if ( v.is("--no-warn-flowbits") )
1037         no_warn_flowbits = true;
1038 
1039     else if ( v.is("--no-warn-rules") )
1040         no_warn_rules = true;
1041 
1042     else if ( v.is("--pause") )
1043         sc->run_flags |= RUN_FLAG__PAUSE;
1044 
1045 #ifdef REG_TEST
1046     else if ( v.is("--pause-after-n") )
1047         sc->pkt_pause_cnt = v.get_uint64();
1048 #endif
1049 
1050     else if ( v.is("--pcap-file") )
1051     {
1052         sc->run_flags |= RUN_FLAG__READ;
1053         Trough::add_source(Trough::SOURCE_FILE_LIST, v.get_string());
1054     }
1055     else if ( v.is("--pcap-dir") )
1056     {
1057         sc->run_flags |= RUN_FLAG__READ;
1058         Trough::add_source(Trough::SOURCE_DIR, v.get_string());
1059     }
1060     else if ( v.is("--pcap-filter") )
1061         Trough::set_filter(v.get_string());
1062 
1063     else if ( v.is("--pcap-loop") )
1064         Trough::set_loop_count(v.get_uint32());
1065 
1066     else if ( v.is("--pcap-no-filter") )
1067         Trough::set_filter(nullptr);
1068 
1069     else if ( v.is("--pcap-show") )
1070         sc->run_flags |= RUN_FLAG__PCAP_SHOW;
1071 
1072 #ifdef PIGLET
1073     else if ( v.is("--piglet") )
1074         sc->run_flags |= RUN_FLAG__PIGLET;
1075 #endif
1076 
1077     else if ( v.is("--plugin-path") )
1078         sc->add_plugin_path(v.get_string());
1079 
1080     else if ( v.is("--process-all-events") )
1081         sc->set_process_all_events(true);
1082 
1083     else if ( v.is("--rule") )
1084         parser_append_rules(v.get_string());
1085 
1086     else if ( v.is("--rule-path") )
1087         parser_append_includes(v.get_string());
1088 
1089     else if ( v.is("--rule-to-hex") )
1090         dump_rule_hex(sc, v.get_string());
1091 
1092     else if ( v.is("--rule-to-text") )
1093         dump_rule_text(sc, v.get_string());
1094 
1095     else if ( v.is("--run-prefix") )
1096         sc->run_prefix = v.get_string();
1097 
1098     else if ( v.is("--script-path") )
1099         sc->add_script_path(v.get_string());
1100 
1101 #ifdef SHELL
1102     else if ( v.is("--shell") )
1103         sc->run_flags |= RUN_FLAG__SHELL;
1104 #endif
1105 
1106     else if ( v.is("--show-file-codes") )
1107         sc->run_flags |= RUN_FLAG__SHOW_FILE_CODES;
1108 
1109     else if ( v.is("--show-plugins") )
1110         SnortConfig::enable_log_show_plugins();
1111 
1112     else if ( v.is("--skip") )
1113         sc->pkt_skip = v.get_uint64();
1114 
1115     else if ( v.is("--stdin-rules") )
1116         sc->stdin_rules = true;
1117 
1118     else if ( v.is("--talos") )
1119         sc->set_tweaks("talos");
1120 
1121     else if ( v.is("--tweaks") )
1122         sc->set_tweaks(v.get_string());
1123 
1124 #if defined(UNIT_TEST) || defined(BENCHMARK_TEST)
1125     else if ( v.is("--catch-test") )
1126         catch_set_filter(v.get_string());
1127 #endif
1128     else if ( v.is("--version") )
1129         help_version(sc);
1130 
1131     else if ( v.is("--warn-all") )
1132         sc->warning_flags = 0xFFFFFFFF;
1133 
1134     else if ( v.is("--warn-conf") )
1135         sc->warning_flags |= (1 << WARN_CONF);
1136 
1137     else if ( v.is("--warn-conf-strict") )
1138         sc->warning_flags |= (1 << WARN_CONF_STRICT);
1139 
1140     else if ( v.is("--warn-daq") )
1141         sc->warning_flags |= (1 << WARN_DAQ);
1142 
1143     else if ( v.is("--warn-flowbits") )
1144         sc->warning_flags |= (1 << WARN_FLOWBITS);
1145 
1146     else if ( v.is("--warn-hosts") )
1147         sc->warning_flags |= (1 << WARN_HOSTS);
1148 
1149     else if ( v.is("--warn-plugins") )
1150         sc->warning_flags |= (1 << WARN_PLUGINS);
1151 
1152     else if ( v.is("--warn-rules") )
1153         sc->warning_flags |= (1 << WARN_RULES);
1154 
1155     else if ( v.is("--warn-scripts") )
1156         sc->warning_flags |= (1 << WARN_SCRIPTS);
1157 
1158     else if ( v.is("--warn-symbols") )
1159         sc->warning_flags |= (1 << WARN_SYMBOLS);
1160 
1161     else if ( v.is("--warn-vars") )
1162         sc->warning_flags |= (1 << WARN_VARS);
1163 
1164     else if ( v.is("--x2c") )
1165         x2c(v.get_uint8());
1166 
1167     else if ( v.is("--x2s") )
1168         x2s(v.get_string());
1169 
1170     return true;
1171 }
1172 
end(const char *,int,SnortConfig * sc)1173 bool SnortModule::end(const char*, int, SnortConfig* sc)
1174 {
1175     if ( sc->offload_threads and ThreadConfig::get_instance_max() != 1 )
1176         ParseError("You can not enable experimental offload with more than one packet thread.");
1177 
1178     if ( no_warn_flowbits )
1179     {
1180         sc->warning_flags &= ~(1 << WARN_FLOWBITS);
1181         no_warn_flowbits = false;
1182     }
1183 
1184     if ( no_warn_rules )
1185     {
1186         sc->warning_flags &= ~(1 << WARN_RULES);
1187         no_warn_rules = false;
1188     }
1189 
1190     return true;
1191 }
1192 
get_profile(unsigned index,const char * & name,const char * & parent) const1193 ProfileStats* SnortModule::get_profile(
1194     unsigned index, const char*& name, const char*& parent) const
1195 {
1196     switch ( index )
1197     {
1198     case 0:
1199         name = "daq";
1200         parent = nullptr;
1201         return &daqPerfStats;
1202 
1203     case 1:
1204         name = "decode";
1205         parent = nullptr;
1206         return &decodePerfStats;
1207 
1208     case 2:
1209         name = "mpse";
1210         parent = nullptr;
1211         return &mpsePerfStats;
1212 
1213     case 3:
1214         name = "rule_eval";
1215         parent = nullptr;
1216         return &rulePerfStats;
1217 
1218     case 4:
1219         name = "eventq";
1220         parent = nullptr;
1221         return &eventqPerfStats;
1222     }
1223     return nullptr;
1224 }
1225 
1226 //-------------------------------------------------------------------------
1227 // singleton
1228 //-------------------------------------------------------------------------
1229 
1230 static SnortModule* snort_module = nullptr;
1231 
get_snort_module()1232 Module* get_snort_module()
1233 {
1234     if ( !snort_module )
1235         snort_module = new SnortModule;
1236 
1237     return snort_module;
1238 }
1239 
1240