#!/usr/bin/perl ############################################################################### # # # IPFire.org - A linux based firewall # # Copyright (C) 2020 IPFire Development Team # # # # This program is free software: you can redistribute it and/or modify # # it under the terms of the GNU General Public License as published by # # the Free Software Foundation, either version 3 of the License, or # # (at your option) any later version. # # # # This program is distributed in the hope that it will be useful, # # but WITHOUT ANY WARRANTY; without even the implied warranty of # # MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the # # GNU General Public License for more details. # # # # You should have received a copy of the GNU General Public License # # along with this program. If not, see . # # # ############################################################################### use strict; require '/var/ipfire/general-functions.pl'; require "${General::swroot}/ids-functions.pl"; require "${General::swroot}/network-functions.pl"; # Snort settings file, which contains the settings from the WUI. my $snort_settings_file = "${General::swroot}/snort/settings"; # Main snort config file. my $snort_config_file = "/etc/snort/snort.conf"; # Snort rules tarball. my $snort_rules_tarball = "/var/tmp/snortrules.tar.gz"; # ## Step 1: Convert snort user and group to suricata if exist. # # Check if the snort user exists. if (getpwnam("snort")) { # Change username. my @command = ( '/usr/sbin/usermod', '-l', 'suricata', 'snort' ); system(@command) == 0 or die "Could not change username: @command failed: $?\n"; # Adjust home directory. @command = ( '/usr/sbin/usermod', '-d', "/var/log/suricata", 'suricata' ); system(@command) == 0 or die "Failed to adjust home directory: @command failed: $?\n"; } # Check if the snort group exists. if (getgrnam("snort")) { # Change groupname my @command = ( '/usr/sbin/groupmod', '-n', 'suricata', 'snort' ); system(@command) == 0 or die "Could not rename groupname: @command failed: $?\n"; } # ## Step 2: Setup directory and file layout, if not present and set correct ## ownership. The converter runs as a privileged user, but the files ## needs to be full access-able by the WUI user and group (nobody:nobody). # # Check if the settings directory exists. unless (-d $IDS::settingsdir) { # Create the directory. mkdir($IDS::settingsdir); } # Check if the rules directory exists. unless (-d $IDS::rulespath) { # Create the directory. mkdir($IDS::rulespath); } # Create file layout, if not exists yet. &IDS::check_and_create_filelayout(); # Set correct ownership for settingsdir and rulespath. &IDS::set_ownership("$IDS::settingsdir"); &IDS::set_ownership("$IDS::rulespath"); # Check if a snort settings file exists. unless( -f "$snort_settings_file") { print "$snort_settings_file not found - Nothing to do. Exiting!\n"; exit(0); } # Check if the snort settings file is empty. if (-z "$snort_settings_file") { print "$snort_settings_file is empty - Nothing to do. Exiting!\n"; exit(0); } # ## Step 3: Import snort settings and convert to the required format for the new IDS ## (suricata). # # Hash which contains the "old" snort settings. my %snortsettings; # Hash which contains the IDS (suricata) settings. # # Add default value for MONITOR_TRAFFIC_ONLY which will be "on" # when migrating from snort to the new IDS. # # Set default value for UPDATE_INTERVAL to weekly. my %idssettings = ( "MONITOR_TRAFFIC_ONLY" => "on", "AUTOUPDATE_INTERVAL" => "weekly", ); # Get all available network zones. my @network_zones = &Network::get_available_network_zones(); # Read-in snort settings file. &General::readhash("$snort_settings_file", \%snortsettings); # Loop through the array of network zones. foreach my $zone (@network_zones) { # Convert current zone into upper case. my $zone_upper = uc($zone); # Check if the current network zone is "red". if($zone eq "red") { # Check if snort was enabled and enabled on red. if ($snortsettings{"ENABLE_SNORT"} eq "on") { # Enable the IDS. $idssettings{"ENABLE_IDS"} = "on"; # Enable the IDS on RED. $idssettings{"ENABLE_IDS_$zone_upper"} = "on"; } } else { # Check if snort was enabled on the current zone. if ($snortsettings{"ENABLE_SNORT_$zone_upper"} eq "on") { # Enable the IDS on this zone too. $idssettings{"ENABLE_IDS_$zone_upper"} = "on"; } } } # Hash to store the provider settings. my %providersettings = (); # Default ID. $id = "1"; # Grab the choosen ruleset from snort settings hash. my $provider = $snortsettings{"RULES"}; my $subscription_code; # Check if an oinkcode has been provided. if($snortsettings{"OINKCODE"}) { # Take the oinkcode from snort settings hash. $subscription_code = $snortsettings{"OINKCODE"}; } # Generate providers config line and add it to the provider settings hash. # # Enabled automatic ruleste updates and the usage of the provider. $providersettings{$id} = [ "$provider", "$subscription_code", "enabled", "enabled" ]; # ## Step 4: Import guardian settings and whitelist if the addon is installed. # # Pakfire meta file for owncloud. # (File exists when the addon is installed.) my $guardian_meta = "/opt/pakfire/db/installed/meta-guardian"; # Check if the guardian addon is installed. if (-f $guardian_meta) { # File which contains the taken setting for guardian. my $guardian_settings_file = "${General::swroot}/guardian/settings"; # File which contains the white-listed hosts. my $guardian_ignored_file = "${General::swroot}/guardian/ignored"; # Hash which will contain the settings of guardian. my %guardiansettings; # Check if the settings file of guardian is empty. unless (-z $guardian_settings_file) { # Read-in settings. &General::readhash("$guardian_settings_file", \%guardiansettings); } # Check if guardian is not configured to take actions on snort events. if ($guardiansettings{"GUARDIAN_MONITOR_SNORT"} eq "on") { # Change the IDS into MONITOR_TRAFFIC_ONLY mode. $idssettings{"MONITOR_TRAFFIC_ONLY"} = "off"; } # Check if guardian has any white-listed hosts configured. unless (-z $guardian_ignored_file) { # Temporary hash to store the ignored hosts. my %ignored_hosts; # Read-in white-listed hosts and store them in the hash. &General::readhasharray($guardian_ignored_file, \%ignored_hosts); # Write-out the white-listed hosts for the IDS system. &General::writehasharray($IDS::ignored_file, \%ignored_hosts); # Call subfunction to generate the file for white-listing the hosts. &IDS::generate_ignored_file(); } } # ## Step 5: Save IDS and rules settings. # # Write IDS settings. &General::writehash("$IDS::ids_settings_file", \%idssettings); # Write provider settings. &General::writehash("$IDS::providers_settings_file", \%providersettings); # ## Step 6: Generate and write the file to modify the ruleset. # # Call subfunction and pass the desired IDS action. &IDS::write_modify_sids_file(); # Set correct ownership. &IDS::set_ownership("$IDS::modify_sids_file"); # ## Step 7: Move rulestarball to its new location. # # Grab file and path to store the provider rules tarball. my $rulestarball = &IDS::_get_dl_rulesfile($provider); # Check if a rulestarball has been downloaded yet. if (-f $snort_rules_tarball) { # Load perl module which contains the move command. use File::Copy; # Move the rulestarball to the new location. move($snort_rules_tarball, $rulestarball); # Set correct ownership. &IDS::set_ownership("$rulestarball"); # In case no tarball is present, try to download the ruleset. } else { # Check if enought disk space is available. if(&IDS::checkdiskspace()) { # Print error message. print "Could not download ruleset - Not enough free diskspace available.\n"; } else { # Call the download function and grab the new ruleset. &IDS::downloadruleset(); } } # ## Step 8: Call oinkmaster to extract and setup the rules structures. # # Check if a rulestarball is present. if (-f $rulestarball) { # Launch oinkmaster by calling the subfunction. &IDS::oinkmaster(); # Set correct ownership for the rulesdir and files. &IDS::set_ownership("$IDS::rulespath"); } # ## Step 9: Generate file for the HOME Net. # # Call subfunction to generate the file. &IDS::generate_home_net_file(); # Set correct ownership for the homenet file. &IDS::set_ownership("$IDS::homenet_file"); # ## Step 10: Generate file for the DNS servers. # # Call subfunction to generate the file. &IDS::generate_dns_servers_file(); # Set correct ownership for the dns_servers_file. &IDS::set_ownership("$IDS::dns_servers_file"); # ## Step 11: Generate file which contains the HTTP ports. # # Call subfunction to generate the file. &IDS::generate_http_ports_file(); # Set correct ownership for the http_ports_file. &IDS::set_ownership("$IDS::http_ports_file"); # ## Step 12: Setup automatic ruleset updates. # # Check if a provider is configured. if(%providersettings) { # Call suricatactrl and setup the periodic update mechanism. &IDS::call_suricatactrl("cron", $idssettings{'AUTOUPDATE_INTERVAL'}); } # ## Step 13: Grab used ruleset files from snort config file and convert ## them into the new format. # # Check if the snort config file exists. unless (-f $snort_config_file) { print "$snort_config_file does not exist - Nothing to do. Exiting!\n"; exit(0); } # Array to store the enabled rules files. my @enabled_rule_files; # Open snort config file. open(SNORTCONF, $snort_config_file) or die "Could not open $snort_config_file. $!\n"; # Loop through the file content. while (my $line = ) { # Skip comments. next if ($line =~ /\#/); # Skip blank lines. next if ($line =~ /^\s*$/); # Remove newlines. chomp($line); # Check for a line with .rules if ($line =~ /\.rules$/) { # Parse out rule file name my $rulefile = $line; $rulefile =~ s/\$RULE_PATH\///i; $rulefile =~ s/ ?include ?//i; # Add the enabled rulefile to the array of enabled rule files. push(@enabled_rule_files, $rulefile); } } # Close filehandle. close(SNORTCONF); # Pass the array of enabled rule files to the subfunction and write the file. &IDS::write_used_provider_rulefiles_file("$provider", @enabled_rule_files); &IDS::write_main_used_rulefiles_file("$provider"); # Grab the used provider rulesfile file path and name. my $used_provider_rulesfile_file = &IDS::get_used_provider_rulesfile_file("$provider"); # Set correct ownership for new files. &IDS::set_ownership("$suricata_used_providers_file"); &IDS::set_ownership("$suricata_static_rulefiles_file"); &IDS::set_ownership("$used_provider_rulesfile_file"); # ## Step 14: Start the IDS if enabled. # # Check if the IDS should be started. if($idssettings{"ENABLE_IDS"} eq "on") { # Call suricatactrl and launch the IDS. &IDS::call_suricatactrl("start"); }