2 ###############################################################################
4 # IPFire.org - A linux based firewall #
5 # Copyright (C) 2020 IPFire Development Team <info@ipfire.org> #
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. #
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. #
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/>. #
20 ###############################################################################
24 require '/var/ipfire/general-functions.pl';
25 require "${General::swroot}/ids-functions.pl";
26 require "${General::swroot}/network-functions.pl";
28 # Snort settings file, which contains the settings from the WUI.
29 my $snort_settings_file = "${General::swroot}/snort/settings";
31 # Main snort config file.
32 my $snort_config_file = "/etc/snort/snort.conf";
34 # Snort rules tarball.
35 my $snort_rules_tarball = "/var/tmp/snortrules.tar.gz";
38 ## Step 1: Convert snort user and group to suricata if exist.
41 # Check if the snort user exists.
42 if (getpwnam("snort")) {
46 '-l', 'suricata', 'snort'
49 system(@command) == 0 or die "Could not change username: @command failed: $?\n";
51 # Adjust home directory.
54 '-d', "/var/log/suricata",
58 system(@command) == 0 or die "Failed to adjust home directory: @command failed: $?\n";
61 # Check if the snort group exists.
62 if (getgrnam("snort")) {
66 '-n', 'suricata', 'snort'
69 system(@command) == 0 or die "Could not rename groupname: @command failed: $?\n";
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).
78 # Check if the settings directory exists.
79 unless (-d
$IDS::settingsdir
) {
80 # Create the directory.
81 mkdir($IDS::settingsdir
);
84 # Check if the rules directory exists.
85 unless (-d
$IDS::rulespath
) {
86 # Create the directory.
87 mkdir($IDS::rulespath
);
90 # Create file layout, if not exists yet.
91 &IDS
::check_and_create_filelayout
();
93 # Set correct ownership for settingsdir and rulespath.
94 &IDS
::set_ownership
("$IDS::settingsdir");
95 &IDS
::set_ownership
("$IDS::rulespath");
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";
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";
110 ## Step 3: Import snort settings and convert to the required format for the new IDS
114 # Hash which contains the "old" snort settings.
117 # Hash which contains the IDS (suricata) settings.
119 # Add default value for MONITOR_TRAFFIC_ONLY which will be "on"
120 # when migrating from snort to the new IDS.
122 "MONITOR_TRAFFIC_ONLY" => "on",
125 # Hash which contains the RULES settings.
127 # Set default value for UPDATE_INTERVAL to weekly.
128 my %rulessettings = (
129 "AUTOUPDATE_INTERVAL" => "weekly",
132 # Get all available network zones.
133 my @network_zones = &Network
::get_available_network_zones
();
135 # Read-in snort settings file.
136 &General
::readhash
("$snort_settings_file", \
%snortsettings);
138 # Loop through the array of network zones.
139 foreach my $zone (@network_zones) {
140 # Convert current zone into upper case.
141 my $zone_upper = uc($zone);
143 # Check if the current network zone is "red".
145 # Check if snort was enabled and enabled on red.
146 if ($snortsettings{"ENABLE_SNORT"} eq "on") {
148 $idssettings{"ENABLE_IDS"} = "on";
150 # Enable the IDS on RED.
151 $idssettings{"ENABLE_IDS_$zone_upper"} = "on";
154 # Check if snort was enabled on the current zone.
155 if ($snortsettings{"ENABLE_SNORT_$zone_upper"} eq "on") {
156 # Enable the IDS on this zone too.
157 $idssettings{"ENABLE_IDS_$zone_upper"} = "on";
162 # Grab the choosen ruleset from snort settings hash and store it in the rules
164 $rulessettings{"RULES"} = $snortsettings{"RULES"};
166 # Check if an oinkcode has been provided.
167 if($snortsettings{"OINKCODE"}) {
168 # Take the oinkcode from snort settings hash and store it in the rules
170 $rulessettings{"OINKCODE"} = $snortsettings{"OINKCODE"};
174 ## Step 4: Import guardian settings and whitelist if the addon is installed.
177 # Pakfire meta file for owncloud.
178 # (File exists when the addon is installed.)
179 my $guardian_meta = "/opt/pakfire/db/installed/meta-guardian";
181 # Check if the guardian addon is installed.
182 if (-f
$guardian_meta) {
183 # File which contains the taken setting for guardian.
184 my $guardian_settings_file = "${General::swroot}/guardian/settings";
186 # File which contains the white-listed hosts.
187 my $guardian_ignored_file = "${General::swroot}/guardian/ignored";
189 # Hash which will contain the settings of guardian.
190 my %guardiansettings;
192 # Check if the settings file of guardian is empty.
193 unless (-z
$guardian_settings_file) {
195 &General
::readhash
("$guardian_settings_file", \
%guardiansettings);
198 # Check if guardian is not configured to take actions on snort events.
199 if ($guardiansettings{"GUARDIAN_MONITOR_SNORT"} eq "on") {
200 # Change the IDS into MONITOR_TRAFFIC_ONLY mode.
201 $idssettings{"MONITOR_TRAFFIC_ONLY"} = "off";
204 # Check if guardian has any white-listed hosts configured.
205 unless (-z
$guardian_ignored_file) {
206 # Temporary hash to store the ignored hosts.
209 # Read-in white-listed hosts and store them in the hash.
210 &General
::readhasharray
($guardian_ignored_file, \
%ignored_hosts);
212 # Write-out the white-listed hosts for the IDS system.
213 &General
::writehasharray
($IDS::ignored_file
, \
%ignored_hosts);
215 # Call subfunction to generate the file for white-listing the hosts.
216 &IDS
::generate_ignored_file
();
222 ## Step 5: Save IDS and rules settings.
225 # Write IDS settings.
226 &General
::writehash
("$IDS::ids_settings_file", \
%idssettings);
228 # Write rules settings.
229 &General
::writehash
("$IDS::rules_settings_file", \
%rulessettings);
232 ## Step 6: Generate and write the file to modify the ruleset.
235 # Call subfunction and pass the desired IDS action.
236 &IDS
::write_modify_sids_file
();
238 # Set correct ownership.
239 &IDS
::set_ownership
("$IDS::modify_sids_file");
242 ## Step 7: Move rulestarball to its new location.
245 # Check if a rulestarball has been downloaded yet.
246 if (-f
$snort_rules_tarball) {
247 # Load perl module which contains the move command.
250 # Move the rulestarball to the new location.
251 move
($snort_rules_tarball, $IDS::rulestarball
);
253 # Set correct ownership.
254 &IDS
::set_ownership
("$IDS::rulestarball");
256 # In case no tarball is present, try to download the ruleset.
258 # Check if enought disk space is available.
259 if(&IDS
::checkdiskspace
()) {
260 # Print error message.
261 print "Could not download ruleset - Not enough free diskspace available.\n";
263 # Call the download function and grab the new ruleset.
264 &IDS
::downloadruleset
();
269 ## Step 8: Call oinkmaster to extract and setup the rules structures.
272 # Check if a rulestarball is present.
273 if (-f
$IDS::rulestarball
) {
274 # Launch oinkmaster by calling the subfunction.
277 # Set correct ownership for the rulesdir and files.
278 &IDS
::set_ownership
("$IDS::rulespath");
282 ## Step 9: Generate file for the HOME Net.
285 # Call subfunction to generate the file.
286 &IDS
::generate_home_net_file
();
288 # Set correct ownership for the homenet file.
289 &IDS
::set_ownership
("$IDS::homenet_file");
292 ## Step 10: Generate file for the DNS servers.
295 # Call subfunction to generate the file.
296 &IDS
::generate_dns_servers_file
();
298 # Set correct ownership for the dns_servers_file.
299 &IDS
::set_ownership
("$IDS::dns_servers_file");
302 ## Step 11: Generate file which contains the HTTP ports.
305 # Call subfunction to generate the file.
306 &IDS
::generate_http_ports_file
();
308 # Set correct ownership for the http_ports_file.
309 &IDS
::set_ownership
("$IDS::http_ports_file");
312 ## Step 12: Setup automatic ruleset updates.
315 # Check if a ruleset is configured.
316 if($rulessettings{"RULES"}) {
317 # Call suricatactrl and setup the periodic update mechanism.
318 &IDS
::call_suricatactrl
("cron", $rulessettings{'AUTOUPDATE_INTERVAL'});
322 ## Step 13: Grab used ruleset files from snort config file and convert
323 ## them into the new format.
326 # Check if the snort config file exists.
327 unless (-f
$snort_config_file) {
328 print "$snort_config_file does not exist - Nothing to do. Exiting!\n";
332 # Array to store the enabled rules files.
333 my @enabled_rule_files;
335 # Open snort config file.
336 open(SNORTCONF
, $snort_config_file) or die "Could not open $snort_config_file. $!\n";
338 # Loop through the file content.
339 while (my $line = <SNORTCONF
>) {
341 next if ($line =~ /\#/);
344 next if ($line =~ /^\s*$/);
349 # Check for a line with .rules
350 if ($line =~ /\.rules$/) {
351 # Parse out rule file name
352 my $rulefile = $line;
353 $rulefile =~ s/\$RULE_PATH\///i
;
354 $rulefile =~ s/ ?include ?//i;
356 # Add the enabled rulefile to the array of enabled rule files.
357 push(@enabled_rule_files, $rulefile);
364 # Pass the array of enabled rule files to the subfunction and write the file.
365 &IDS
::write_used_rulefiles_file
(@enabled_rule_files);
368 ## Step 14: Start the IDS if enabled.
371 # Check if the IDS should be started.
372 if($idssettings{"ENABLE_IDS"} eq "on") {
373 # Call suricatactrl and launch the IDS.
374 &IDS
::call_suricatactrl
("start");