8e33f9e5d29ed5311e5bba3f6289c010b8690b86
[feed/packages.git] / net / snort3 / files / main.uc
1 {%
2 //------------------------------------------------------------------------------
3 // Copyright (c) 2023-2024 Eric Fahlgren <eric.fahlgren@gmail.com>
4 // SPDX-License-Identifier: GPL-2.0
5 //
6 // The tables defined using 'config_item' are the source of record for the
7 // configuration file, '/etc/config/snort'. If you wish to add new items,
8 // do that only in the tables and propagate that use into the templates.
9 //
10 //------------------------------------------------------------------------------
11
12 QUIET; // Reference globals passed from CLI, so we get errors when missing.
13 TYPE;
14
15 import { cursor } from 'uci';
16 let uci = cursor();
17
18 function wrn(fmt, ...args) {
19 if (QUIET)
20 exit(1);
21
22 let msg = "ERROR: " + sprintf(fmt, ...args);
23
24 if (getenv("TTY"))
25 warn(`\033[33m${msg}\033[m\n`);
26 else
27 warn(`[!] ${msg}\n`);
28 exit(1);
29 }
30
31 function rpad(str, fill, len)
32 {
33 str = rtrim(str) + ' ';
34 while (length(str) < len) {
35 str += fill;
36 }
37 return str;
38 }
39
40 //------------------------------------------------------------------------------
41
42 const ConfigItem = {
43 contains: function(value) {
44 // Check if the value is contained in the listed values,
45 // depending on the item type.
46 switch (this.type) {
47 case "enum":
48 return value in this.values;
49 case "range":
50 return value >= this.values[0] && value <= this.values[1];
51 default:
52 return true;
53 }
54 },
55
56 allowed: function() {
57 // Show a pretty version of the possible values, for error messages.
58 switch (this.type) {
59 case "enum":
60 return "one of [" + join(", ", this.values) + "]";
61 case "range":
62 return `${this.values[0]} <= x <= ${this.values[1]}`;
63 case "path":
64 return "a path string";
65 case "str":
66 return "a string";
67 default:
68 return "???";
69 }
70 },
71 };
72
73 function config_item(type, values, def) {
74 // If no default value is provided explicity, then values[0] is used as default.
75 if (! type in [ "enum", "range", "path", "str" ]) {
76 wrn(`Invalid item type '${type}', must be one of "enum", "range", "path" or "str".`);
77 return;
78 }
79 if (type == "range" && (length(values) != 2 || values[0] > values[1])) {
80 wrn(`A 'range' type item must have exactly 2 values in ascending order.`);
81 return;
82 }
83 // Maybe check 'path' values for existence???
84
85 return proto({
86 type: type,
87 values: values,
88 default: def ?? values[0],
89 }, ConfigItem);
90 };
91
92 const snort_config = {
93 enabled: config_item("enum", [ 0, 1 ], 0), // Defaults to off, so that user must configure before first start.
94 manual: config_item("enum", [ 0, 1 ], 1), // Allow user to manually configure, legacy behavior when enabled.
95 oinkcode: config_item("str", [ "" ]), // User subscription oinkcode. Much more in 'snort-rules' script.
96 home_net: config_item("str", [ "" ], "192.168.1.0/24"),
97 external_net: config_item("str", [ "" ], "any"),
98
99 config_dir: config_item("path", [ "/etc/snort" ]), // Location of the base snort configuration files.
100 temp_dir: config_item("path", [ "/var/snort.d" ]), // Location of all transient snort config, including downloaded rules.
101 log_dir: config_item("path", [ "/var/log" ]), // Location of the generated logs, and oh-by-the-way the snort PID file (why?).
102 logging: config_item("enum", [ 0, 1 ], 1),
103 openappid: config_item("enum", [ 0, 1 ], 0),
104
105 mode: config_item("enum", [ "ids", "ips" ]),
106 method: config_item("enum", [ "pcap", "afpacket", "nfq" ]),
107 action: config_item("enum", [ "default", "alert", "block", "drop", "reject" ]),
108 interface: config_item("str", [ uci.get("network", "wan", "device") ]),
109 snaplen: config_item("range", [ 1518, 65535 ]), // int daq.snaplen = 1518: set snap length (same as -s) { 0:65535 }
110
111 include: config_item("path", [ "" ]), // User-defined snort configuration, applied at end of snort.lua.
112 };
113
114 const nfq_config = {
115 queue_count: config_item("range", [ 1, 16 ], 4), // Count of queues to allocate in nft chain when method=nfq, usually 2-8.
116 queue_start: config_item("range", [ 1, 32768], 4), // Start of queue numbers in nftables.
117 queue_maxlen: config_item("range", [ 1024, 65536 ], 1024), // --daq-var queue_maxlen=int
118 fanout_type: config_item("enum", [ "hash", "lb", "cpu", "rollover", "rnd", "qm"], "hash"), // See below.
119 thread_count: config_item("range", [ 0, 32 ], 0), // 0 = use cpu count
120 chain_type: config_item("enum", [ "prerouting", "input", "forward", "output", "postrouting" ], "input"),
121 chain_priority: config_item("enum", [ "raw", "filter", "300"], "filter"),
122 include: config_item("path", [ "" ]), // User-defined rules to include inside queue chain.
123 };
124
125
126 let _snort_config_doc =
127 "
128 This is not an exhaustive list of configuration items, just those that
129 require more explanation than is given in the tables that define them, below.
130
131 https://openwrt.org/docs/guide-user/services/snort
132
133 snort
134 manual - When set to 1, use manual configuration for legacy behavior.
135 When disabled, then use this config.
136 interface - Default should usually be 'uci get network.wan.device',
137 something like 'eth0'
138 home_net - IP range/ranges to protect. May be 'any', but more likely it's
139 your lan range, default is '192.168.1.0/24'
140 external_net - IP range external to home. Usually 'any', but if you only
141 care about true external hosts (trusting all lan devices),
142 then '!$HOME_NET' or some specific range
143 mode - 'ids' or 'ips', for detection-only or prevention, respectively
144 oinkcode - https://www.snort.org/oinkcodes
145 config_dir - Location of the base snort configuration files. Default /etc/snort
146 temp_dir - Location of all transient snort config, including downloaded rules
147 Default /var/snort.d
148 logging - Enable external logging of events thus enabling 'snort-mgr report',
149 otherwise events only go to system log (i.e., 'logread -e snort:')
150 log_dir - Location of the generated logs, and oh-by-the-way the snort
151 PID file (why?). Default /var/log
152 openappid - Enabled inspection using the 'openappid' package
153 See 'opkg info openappid'
154 action - Override the specified action of your rules. One of 'default',
155 'alert', 'block', 'reject' or 'drop', where 'default' means use
156 the rule as defined and don't override.
157 method - 'pcap', 'afpacket' or 'nfq'
158 snaplen - int daq.snaplen = 1518: set snap length (same as -s) { 0:65535 }
159 include - User-defined snort configuration, applied at end of generated snort.lua
160
161 nfq - https://github.com/snort3/libdaq/blob/master/modules/nfq/README.nfq.md
162 queue_maxlen - nfq's '--daq-var queue_maxlen=int'
163 queue_count - Count of queues to use when method=nfq, usually 2-8
164 fanout_type - Sets kernel load balancing algorithm*, one of hash, lb, cpu,
165 rollover, rnd, qm.
166 thread_count - int snort.-z: <count> maximum number of packet threads
167 (same as --max-packet-threads); 0 gets the number of
168 CPU cores reported by the system; default is 1 { 0:max32 }
169 chain_type - Chain type when generating nft output
170 chain_priority - Chain priority when generating nft output
171 include - Full path to user-defined extra rules to include inside queue chain
172
173 * - for details on fanout_type, see these pages:
174 https://github.com/florincoras/daq/blob/master/README
175 https://www.kernel.org/doc/Documentation/networking/packet_mmap.txt
176 ";
177
178 function snort_config_doc(comment) {
179 if (comment == null) comment = "";
180 if (comment != "") comment += " ";
181 for (let line in split(_snort_config_doc, "\n")) {
182 let msg = rtrim(sprintf("%s%s", comment, line));
183 print(msg, "\n");
184 }
185 }
186
187 //------------------------------------------------------------------------------
188
189 function load(section, config) {
190 let self = {
191 ".name": section,
192 ".config": config,
193 };
194
195 // Set the defaults from definitions in table.
196 for (let item in config) {
197 self[item] = config[item].default;
198 }
199
200 // Overwrite them with any uci config settings.
201 let cfg = uci.get_all("snort", section);
202 for (let item in cfg) {
203 // If you need to rename, delete or change the meaning of a
204 // config item, just intercept it and do the work here.
205
206 if (exists(config, item)) {
207 let val = cfg[item];
208 if (config[item].contains(val))
209 self[item] = val;
210 else {
211 wrn(`In option ${item}='${val}', must be ${config[item].allowed()}`);
212 // ??? self[item] = config[item][0]; ???
213 }
214 }
215 }
216
217 return self;
218 }
219
220 let snort = null;
221 let nfq = null;
222 function load_all() {
223 snort = load("snort", snort_config);
224 nfq = load("nfq", nfq_config);
225 }
226
227 function dump_config(settings) {
228 let section = settings[".name"];
229 let config = settings[".config"];
230 printf("config %s '%s'\n", section, section);
231 for (let item in config) {
232 printf("\toption %-15s %-17s# %s\n", item, `'${settings[item]}'`, config[item].allowed());
233 }
234 print("\n");
235 }
236
237 function render_snort() {
238 include("templates/snort.uc", { snort, nfq, rpad });
239 }
240
241 function render_nftables() {
242 include("templates/nftables.uc", { snort, nfq, rpad });
243 }
244
245 function render_config() {
246 snort_config_doc("#");
247 dump_config(snort);
248 dump_config(nfq);
249 }
250
251 function render_help() {
252 snort_config_doc();
253 }
254
255 //------------------------------------------------------------------------------
256
257 load_all();
258
259 let table_type = TYPE; // Supply on cli with '-D TYPE=snort'...
260 switch (table_type) {
261 case "snort":
262 render_snort();
263 return;
264
265 case "nftables":
266 render_nftables();
267 return;
268
269 case "config":
270 render_config();
271 return;
272
273 case "help":
274 render_help();
275 return;
276
277 default:
278 print(`Invalid table type '${table_type}', should be one of snort, nftables, config, help.\n`);
279 return;
280 }
281
282 //------------------------------------------------------------------------------
283 -%}