]> git.ipfire.org Git - people/stevee/ipfire-2.x.git/blob - config/suricata/convert-snort
ids-functions.pl: Dynamically generate file of default suricata rules.
[people/stevee/ipfire-2.x.git] / config / suricata / convert-snort
1 #!/usr/bin/perl
2 ###############################################################################
3 # #
4 # IPFire.org - A linux based firewall #
5 # Copyright (C) 2020 IPFire Development Team <info@ipfire.org> #
6 # #
7 # This program is free software: you can redistribute it and/or modify #
8 # it under the terms of the GNU General Public License as published by #
9 # the Free Software Foundation, either version 3 of the License, or #
10 # (at your option) any later version. #
11 # #
12 # This program is distributed in the hope that it will be useful, #
13 # but WITHOUT ANY WARRANTY; without even the implied warranty of #
14 # MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the #
15 # GNU General Public License for more details. #
16 # #
17 # You should have received a copy of the GNU General Public License #
18 # along with this program. If not, see <http://www.gnu.org/licenses/>. #
19 # #
20 ###############################################################################
21
22 use strict;
23
24 require '/var/ipfire/general-functions.pl';
25 require "${General::swroot}/ids-functions.pl";
26 require "${General::swroot}/network-functions.pl";
27
28 # Snort settings file, which contains the settings from the WUI.
29 my $snort_settings_file = "${General::swroot}/snort/settings";
30
31 # Main snort config file.
32 my $snort_config_file = "/etc/snort/snort.conf";
33
34 # Snort rules tarball.
35 my $snort_rules_tarball = "/var/tmp/snortrules.tar.gz";
36
37 #
38 ## Step 1: Convert snort user and group to suricata if exist.
39 #
40
41 # Check if the snort user exists.
42 if (getpwnam("snort")) {
43 # Change username.
44 my @command = (
45 '/usr/sbin/usermod',
46 '-l', 'suricata', 'snort'
47 );
48
49 system(@command) == 0 or die "Could not change username: @command failed: $?\n";
50
51 # Adjust home directory.
52 @command = (
53 '/usr/sbin/usermod',
54 '-d', "/var/log/suricata",
55 'suricata'
56 );
57
58 system(@command) == 0 or die "Failed to adjust home directory: @command failed: $?\n";
59 }
60
61 # Check if the snort group exists.
62 if (getgrnam("snort")) {
63 # Change groupname
64 my @command = (
65 '/usr/sbin/groupmod',
66 '-n', 'suricata', 'snort'
67 );
68
69 system(@command) == 0 or die "Could not rename groupname: @command failed: $?\n";
70 }
71
72 #
73 ## Step 2: Setup directory and file layout, if not present and set correct
74 ## ownership. The converter runs as a privileged user, but the files
75 ## needs to be full access-able by the WUI user and group (nobody:nobody).
76 #
77
78 # Check if the settings directory exists.
79 unless (-d $IDS::settingsdir) {
80 # Create the directory.
81 mkdir($IDS::settingsdir);
82 }
83
84 # Check if the rules directory exists.
85 unless (-d $IDS::rulespath) {
86 # Create the directory.
87 mkdir($IDS::rulespath);
88 }
89
90 # Create file layout, if not exists yet.
91 &IDS::check_and_create_filelayout();
92
93 # Set correct ownership for settingsdir and rulespath.
94 &IDS::set_ownership("$IDS::settingsdir");
95 &IDS::set_ownership("$IDS::rulespath");
96
97 # Check if a snort settings file exists.
98 unless( -f "$snort_settings_file") {
99 print "$snort_settings_file not found - Nothing to do. Exiting!\n";
100 exit(0);
101 }
102
103 # Check if the snort settings file is empty.
104 if (-z "$snort_settings_file") {
105 print "$snort_settings_file is empty - Nothing to do. Exiting!\n";
106 exit(0);
107 }
108
109 #
110 ## Step 3: Import snort settings and convert to the required format for the new IDS
111 ## (suricata).
112 #
113
114 # Hash which contains the "old" snort settings.
115 my %snortsettings;
116
117 # Hash which contains the IDS (suricata) settings.
118 #
119 # Add default value for MONITOR_TRAFFIC_ONLY which will be "on"
120 # when migrating from snort to the new IDS.
121 #
122 # Set default value for UPDATE_INTERVAL to weekly.
123 my %idssettings = (
124 "MONITOR_TRAFFIC_ONLY" => "on",
125 "AUTOUPDATE_INTERVAL" => "weekly",
126 );
127
128 # Get all available network zones.
129 my @network_zones = &Network::get_available_network_zones();
130
131 # Read-in snort settings file.
132 &General::readhash("$snort_settings_file", \%snortsettings);
133
134 # Loop through the array of network zones.
135 foreach my $zone (@network_zones) {
136 # Convert current zone into upper case.
137 my $zone_upper = uc($zone);
138
139 # Check if the current network zone is "red".
140 if($zone eq "red") {
141 # Check if snort was enabled and enabled on red.
142 if ($snortsettings{"ENABLE_SNORT"} eq "on") {
143 # Enable the IDS.
144 $idssettings{"ENABLE_IDS"} = "on";
145
146 # Enable the IDS on RED.
147 $idssettings{"ENABLE_IDS_$zone_upper"} = "on";
148 }
149 } else {
150 # Check if snort was enabled on the current zone.
151 if ($snortsettings{"ENABLE_SNORT_$zone_upper"} eq "on") {
152 # Enable the IDS on this zone too.
153 $idssettings{"ENABLE_IDS_$zone_upper"} = "on";
154 }
155 }
156 }
157
158 # Hash to store the provider settings.
159 my %providersettings = ();
160
161 # Default ID.
162 $id = "1";
163
164 # Grab the choosen ruleset from snort settings hash.
165 my $provider = $snortsettings{"RULES"};
166 my $subscription_code;
167
168 # Check if an oinkcode has been provided.
169 if($snortsettings{"OINKCODE"}) {
170 # Take the oinkcode from snort settings hash.
171 $subscription_code = $snortsettings{"OINKCODE"};
172 }
173
174 # Generate providers config line and add it to the provider settings hash.
175 #
176 # Enabled automatic ruleste updates and the usage of the provider.
177 $providersettings{$id} = [ "$provider", "$subscription_code", "enabled", "enabled" ];
178
179 #
180 ## Step 4: Import guardian settings and whitelist if the addon is installed.
181 #
182
183 # Pakfire meta file for owncloud.
184 # (File exists when the addon is installed.)
185 my $guardian_meta = "/opt/pakfire/db/installed/meta-guardian";
186
187 # Check if the guardian addon is installed.
188 if (-f $guardian_meta) {
189 # File which contains the taken setting for guardian.
190 my $guardian_settings_file = "${General::swroot}/guardian/settings";
191
192 # File which contains the white-listed hosts.
193 my $guardian_ignored_file = "${General::swroot}/guardian/ignored";
194
195 # Hash which will contain the settings of guardian.
196 my %guardiansettings;
197
198 # Check if the settings file of guardian is empty.
199 unless (-z $guardian_settings_file) {
200 # Read-in settings.
201 &General::readhash("$guardian_settings_file", \%guardiansettings);
202 }
203
204 # Check if guardian is not configured to take actions on snort events.
205 if ($guardiansettings{"GUARDIAN_MONITOR_SNORT"} eq "on") {
206 # Change the IDS into MONITOR_TRAFFIC_ONLY mode.
207 $idssettings{"MONITOR_TRAFFIC_ONLY"} = "off";
208 }
209
210 # Check if guardian has any white-listed hosts configured.
211 unless (-z $guardian_ignored_file) {
212 # Temporary hash to store the ignored hosts.
213 my %ignored_hosts;
214
215 # Read-in white-listed hosts and store them in the hash.
216 &General::readhasharray($guardian_ignored_file, \%ignored_hosts);
217
218 # Write-out the white-listed hosts for the IDS system.
219 &General::writehasharray($IDS::ignored_file, \%ignored_hosts);
220
221 # Call subfunction to generate the file for white-listing the hosts.
222 &IDS::generate_ignored_file();
223 }
224
225 }
226
227 #
228 ## Step 5: Save IDS and rules settings.
229 #
230
231 # Write IDS settings.
232 &General::writehash("$IDS::ids_settings_file", \%idssettings);
233
234 # Write provider settings.
235 &General::writehash("$IDS::providers_settings_file", \%providersettings);
236
237 #
238 ## Step 6: Generate and write the file to modify the ruleset.
239 #
240
241 # Call subfunction and pass the desired IDS action.
242 &IDS::write_modify_sids_file();
243
244 # Set correct ownership.
245 &IDS::set_ownership("$IDS::modify_sids_file");
246
247 #
248 ## Step 7: Move rulestarball to its new location.
249 #
250
251 # Grab file and path to store the provider rules tarball.
252 my $rulestarball = &IDS::_get_dl_rulesfile($provider);
253
254 # Check if a rulestarball has been downloaded yet.
255 if (-f $snort_rules_tarball) {
256 # Load perl module which contains the move command.
257 use File::Copy;
258
259 # Move the rulestarball to the new location.
260 move($snort_rules_tarball, $rulestarball);
261
262 # Set correct ownership.
263 &IDS::set_ownership("$rulestarball");
264
265 # In case no tarball is present, try to download the ruleset.
266 } else {
267 # Check if enought disk space is available.
268 if(&IDS::checkdiskspace()) {
269 # Print error message.
270 print "Could not download ruleset - Not enough free diskspace available.\n";
271 } else {
272 # Call the download function and grab the new ruleset.
273 &IDS::downloadruleset();
274 }
275 }
276
277 #
278 ## Step 8: Call oinkmaster to extract and setup the rules structures.
279 #
280
281 # Check if a rulestarball is present.
282 if (-f $rulestarball) {
283 # Launch oinkmaster by calling the subfunction.
284 &IDS::oinkmaster();
285
286 # Set correct ownership for the rulesdir and files.
287 &IDS::set_ownership("$IDS::rulespath");
288 }
289
290 #
291 ## Step 9: Generate file for the HOME Net.
292 #
293
294 # Call subfunction to generate the file.
295 &IDS::generate_home_net_file();
296
297 # Set correct ownership for the homenet file.
298 &IDS::set_ownership("$IDS::homenet_file");
299
300 #
301 ## Step 10: Generate file for the DNS servers.
302 #
303
304 # Call subfunction to generate the file.
305 &IDS::generate_dns_servers_file();
306
307 # Set correct ownership for the dns_servers_file.
308 &IDS::set_ownership("$IDS::dns_servers_file");
309
310 #
311 ## Step 11: Generate file which contains the HTTP ports.
312 #
313
314 # Call subfunction to generate the file.
315 &IDS::generate_http_ports_file();
316
317 # Set correct ownership for the http_ports_file.
318 &IDS::set_ownership("$IDS::http_ports_file");
319
320 #
321 ## Step 12: Setup automatic ruleset updates.
322 #
323
324 # Check if a provider is configured.
325 if(%providersettings) {
326 # Call suricatactrl and setup the periodic update mechanism.
327 &IDS::call_suricatactrl("cron", $idssettings{'AUTOUPDATE_INTERVAL'});
328 }
329
330 #
331 ## Step 13: Grab used ruleset files from snort config file and convert
332 ## them into the new format.
333 #
334
335 # Check if the snort config file exists.
336 unless (-f $snort_config_file) {
337 print "$snort_config_file does not exist - Nothing to do. Exiting!\n";
338 exit(0);
339 }
340
341 # Array to store the enabled rules files.
342 my @enabled_rule_files;
343
344 # Open snort config file.
345 open(SNORTCONF, $snort_config_file) or die "Could not open $snort_config_file. $!\n";
346
347 # Loop through the file content.
348 while (my $line = <SNORTCONF>) {
349 # Skip comments.
350 next if ($line =~ /\#/);
351
352 # Skip blank lines.
353 next if ($line =~ /^\s*$/);
354
355 # Remove newlines.
356 chomp($line);
357
358 # Check for a line with .rules
359 if ($line =~ /\.rules$/) {
360 # Parse out rule file name
361 my $rulefile = $line;
362 $rulefile =~ s/\$RULE_PATH\///i;
363 $rulefile =~ s/ ?include ?//i;
364
365 # Add the enabled rulefile to the array of enabled rule files.
366 push(@enabled_rule_files, $rulefile);
367 }
368 }
369
370 # Close filehandle.
371 close(SNORTCONF);
372
373 # Pass the array of enabled rule files to the subfunction and write the file.
374 &IDS::write_used_provider_rulefiles_file("$provider", @enabled_rule_files);
375 &IDS::write_main_used_rulefiles_file("$provider");
376
377 # Grab the used provider rulesfile file path and name.
378 my $used_provider_rulesfile_file = &IDS::get_used_provider_rulesfile_file("$provider");
379
380 # Set correct ownership for new files.
381 &IDS::set_ownership("$suricata_used_providers_file");
382 &IDS::set_ownership("$suricata_static_rulefiles_file");
383 &IDS::set_ownership("$used_provider_rulesfile_file");
384
385 #
386 ## Step 14: Start the IDS if enabled.
387 #
388
389 # Check if the IDS should be started.
390 if($idssettings{"ENABLE_IDS"} eq "on") {
391 # Call suricatactrl and launch the IDS.
392 &IDS::call_suricatactrl("start");
393 }