From: Stefan Schantl Date: Mon, 21 Jan 2019 12:04:13 +0000 (+0100) Subject: Merge branch 'next' of ssh://git.ipfire.org/pub/git/ipfire-2.x into next-suricata X-Git-Tag: v2.23-core131~117^2~109 X-Git-Url: http://git.ipfire.org/?p=ipfire-2.x.git;a=commitdiff_plain;h=c1a34012352f9eee339f78c00130807e275b05c2 Merge branch 'next' of ssh://git.ipfire.org/pub/git/ipfire-2.x into next-suricata --- c1a34012352f9eee339f78c00130807e275b05c2 diff --cc config/rootfiles/common/aarch64/initscripts index cab453420d,367a0a725b..07216d285e --- a/config/rootfiles/common/aarch64/initscripts +++ b/config/rootfiles/common/aarch64/initscripts @@@ -103,7 -104,8 +104,8 @@@ etc/rc.d/rc0.d/K45rando etc/rc.d/rc0.d/K47setclock etc/rc.d/rc0.d/K49cyrus-sasl etc/rc.d/rc0.d/K51vnstat + etc/rc.d/rc0.d/K77conntrackd -etc/rc.d/rc0.d/K78snort +etc/rc.d/rc0.d/K78suricata etc/rc.d/rc0.d/K79leds etc/rc.d/rc0.d/K79unbound etc/rc.d/rc0.d/K80network @@@ -154,7 -157,8 +157,8 @@@ etc/rc.d/rc6.d/K45rando etc/rc.d/rc6.d/K47setclock etc/rc.d/rc6.d/K49cyrus-sasl etc/rc.d/rc6.d/K51vnstat + etc/rc.d/rc6.d/K77conntrackd -etc/rc.d/rc6.d/K78snort +etc/rc.d/rc6.d/K78suricata etc/rc.d/rc6.d/K79leds etc/rc.d/rc6.d/K79unbound etc/rc.d/rc6.d/K80network diff --cc config/rootfiles/common/armv5tel/initscripts index cab453420d,367a0a725b..07216d285e --- a/config/rootfiles/common/armv5tel/initscripts +++ b/config/rootfiles/common/armv5tel/initscripts @@@ -103,7 -104,8 +104,8 @@@ etc/rc.d/rc0.d/K45rando etc/rc.d/rc0.d/K47setclock etc/rc.d/rc0.d/K49cyrus-sasl etc/rc.d/rc0.d/K51vnstat + etc/rc.d/rc0.d/K77conntrackd -etc/rc.d/rc0.d/K78snort +etc/rc.d/rc0.d/K78suricata etc/rc.d/rc0.d/K79leds etc/rc.d/rc0.d/K79unbound etc/rc.d/rc0.d/K80network @@@ -154,7 -157,8 +157,8 @@@ etc/rc.d/rc6.d/K45rando etc/rc.d/rc6.d/K47setclock etc/rc.d/rc6.d/K49cyrus-sasl etc/rc.d/rc6.d/K51vnstat + etc/rc.d/rc6.d/K77conntrackd -etc/rc.d/rc6.d/K78snort +etc/rc.d/rc6.d/K78suricata etc/rc.d/rc6.d/K79leds etc/rc.d/rc6.d/K79unbound etc/rc.d/rc6.d/K80network diff --cc config/rootfiles/common/i586/initscripts index 5f10acd586,6f9868ec3e..7037030f96 --- a/config/rootfiles/common/i586/initscripts +++ b/config/rootfiles/common/i586/initscripts @@@ -102,7 -103,8 +103,8 @@@ etc/rc.d/rc0.d/K45rando etc/rc.d/rc0.d/K47setclock etc/rc.d/rc0.d/K49cyrus-sasl etc/rc.d/rc0.d/K51vnstat + etc/rc.d/rc0.d/K77conntrackd -etc/rc.d/rc0.d/K78snort +etc/rc.d/rc0.d/K78suricata etc/rc.d/rc0.d/K79leds etc/rc.d/rc0.d/K79unbound etc/rc.d/rc0.d/K80network @@@ -153,7 -156,8 +156,8 @@@ etc/rc.d/rc6.d/K45rando etc/rc.d/rc6.d/K47setclock etc/rc.d/rc6.d/K49cyrus-sasl etc/rc.d/rc6.d/K51vnstat + etc/rc.d/rc6.d/K77conntrackd -etc/rc.d/rc6.d/K78snort +etc/rc.d/rc6.d/K78suricata etc/rc.d/rc6.d/K79leds etc/rc.d/rc6.d/K79unbound etc/rc.d/rc6.d/K80network diff --cc config/rootfiles/common/x86_64/initscripts index 5f10acd586,6f9868ec3e..7037030f96 --- a/config/rootfiles/common/x86_64/initscripts +++ b/config/rootfiles/common/x86_64/initscripts @@@ -102,7 -103,8 +103,8 @@@ etc/rc.d/rc0.d/K45rando etc/rc.d/rc0.d/K47setclock etc/rc.d/rc0.d/K49cyrus-sasl etc/rc.d/rc0.d/K51vnstat + etc/rc.d/rc0.d/K77conntrackd -etc/rc.d/rc0.d/K78snort +etc/rc.d/rc0.d/K78suricata etc/rc.d/rc0.d/K79leds etc/rc.d/rc0.d/K79unbound etc/rc.d/rc0.d/K80network @@@ -153,7 -156,8 +156,8 @@@ etc/rc.d/rc6.d/K45rando etc/rc.d/rc6.d/K47setclock etc/rc.d/rc6.d/K49cyrus-sasl etc/rc.d/rc6.d/K51vnstat + etc/rc.d/rc6.d/K77conntrackd -etc/rc.d/rc6.d/K78snort +etc/rc.d/rc6.d/K78suricata etc/rc.d/rc6.d/K79leds etc/rc.d/rc6.d/K79unbound etc/rc.d/rc6.d/K80network diff --cc html/cgi-bin/ids.cgi index c5fa93ce7b,5a3f4c3143..0c3664547e --- a/html/cgi-bin/ids.cgi +++ b/html/cgi-bin/ids.cgi @@@ -210,371 -251,98 +210,370 @@@ if (($cgiparams{'WHITELIST'} eq $Lang:: } } -####################### End added for snort rules control ################################# +# Check if any error has been stored. +if (-e $IDS::storederrorfile) { + # Open file to read in the stored error message. + open(FILE, "<$IDS::storederrorfile") or die "Could not open $IDS::storederrorfile. $!\n"; + + # Read the stored error message. + $errormessage = ; -if ($snortsettings{'OINKCODE'} ne "") { - $errormessage = $Lang::tr{'invalid input for oink code'} unless ($snortsettings{'OINKCODE'} =~ /^[a-z0-9]+$/); + # Close file. + close (FILE); + + # Delete the file, which is now not longer required. + unlink($IDS::storederrorfile); } - -if (!$errormessage) { - if ($snortsettings{'RULES'} eq 'subscripted') { - $url=" https://www.snort.org/rules/snortrules-snapshot-29120.tar.gz?oinkcode=$snortsettings{'OINKCODE'}"; - } elsif ($snortsettings{'RULES'} eq 'registered') { - $url=" https://www.snort.org/rules/snortrules-snapshot-29120.tar.gz?oinkcode=$snortsettings{'OINKCODE'}"; - } elsif ($snortsettings{'RULES'} eq 'community') { - $url=" https://www.snort.org/rules/community"; - } else { - $url="https://rules.emergingthreats.net/open/snort-2.9.0/emerging.rules.tar.gz"; +## Grab all available snort rules and store them in the idsrules hash. +# +# Open snort rules directory and do a directory listing. +opendir(DIR, $IDS::rulespath) or die $!; + # Loop through the direcory. + while (my $file = readdir(DIR)) { + + # We only want files. + next unless (-f "$IDS::rulespath/$file"); + + # Ignore empty files. + next if (-z "$IDS::rulespath/$file"); + + # Use a regular expression to find files ending in .rules + next unless ($file =~ m/\.rules$/); + + # Ignore files which are not read-able. + next unless (-R "$IDS::rulespath/$file"); + + # Skip whitelist rules file. + next if( $file eq "whitelist.rules"); + + # Call subfunction to read-in rulefile and add rules to + # the idsrules hash. + &readrulesfile("$file"); } - if ($snortsettings{'ACTION'} eq $Lang::tr{'save'} && $snortsettings{'ACTION2'} eq "snort" ) { - &General::writehash("${General::swroot}/snort/settings", \%snortsettings); - if ($snortsettings{'ENABLE_SNORT'} eq 'on') - { - system ('/usr/bin/touch', "${General::swroot}/snort/enable"); - } else { - unlink "${General::swroot}/snort/enable"; +closedir(DIR); + +# Gather used rulefiles. +# +# Check if the file for activated rulefiles is not empty. +if(-f $IDS::used_rulefiles_file) { + # Open the file for used rulefile and read-in content. + open(FILE, $IDS::used_rulefiles_file) or die "Could not open $IDS::used_rulefiles_file. $!\n"; + + # Read-in content. + my @lines = ; + + # Close file. + close(FILE); + + # Loop through the array. + foreach my $line (@lines) { + # Remove newlines. + chomp($line); + + # Skip comments. + next if ($line =~ /\#/); + + # Skip blank lines. + next if ($line =~ /^\s*$/); + + # Gather rule sid and message from the ruleline. + if ($line =~ /.*- (.*)/) { + my $rulefile = $1; + + # Check if the current rulefile exists in the %idsrules hash. + # If not, the file probably does not exist anymore or contains + # no rules. + if($idsrules{$rulefile}) { + # Add the rulefile state to the %idsrules hash. + $idsrules{$rulefile}{'Rulefile'}{'State'} = "on"; + } } - if ($snortsettings{'ENABLE_SNORT_GREEN'} eq 'on') - { - system ('/usr/bin/touch', "${General::swroot}/snort/enable_green"); - } else { - unlink "${General::swroot}/snort/enable_green"; + } +} + +# Save ruleset configuration. +if ($cgiparams{'RULESET'} eq $Lang::tr{'save'}) { + my %oldsettings; + + # Read-in current (old) IDS settings. + &General::readhash("$IDS::rules_settings_file", \%oldsettings); + + # Prevent form name from been stored in conf file. + delete $cgiparams{'RULESET'}; + + # Check if an oinkcode has been provided. + if ($cgiparams{'OINKCODE'}) { + # Check if the oinkcode contains unallowed chars. + unless ($cgiparams{'OINKCODE'} =~ /^[a-z0-9]+$/) { + $errormessage = $Lang::tr{'invalid input for oink code'}; } - if ($snortsettings{'ENABLE_SNORT_BLUE'} eq 'on') - { - system ('/usr/bin/touch', "${General::swroot}/snort/enable_blue"); - } else { - unlink "${General::swroot}/snort/enable_blue"; + } + + # Go on if there are no error messages. + if (!$errormessage) { + # Store settings into settings file. + &General::writehash("$IDS::rules_settings_file", \%cgiparams); + } + + # Check if the the automatic rule update hass been touched. + if($cgiparams{'AUTOUPDATE_INTERVAL'} ne $oldsettings{'AUTOUPDATE_INTERVAL'}) { + # Call suricatactrl to set the new interval. + &IDS::call_suricatactrl("cron", $cgiparams{'AUTOUPDATE_INTERVAL'}); + } + +# Save ruleset. +} elsif ($cgiparams{'RULESET'} eq $Lang::tr{'update'}) { + # Arrays to store which rulefiles have been enabled and will be used. + my @enabled_rulefiles; + + # Hash to store the user-enabled and disabled sids. + my %enabled_disabled_sids; + + # Loop through the hash of idsrules. + foreach my $rulefile(keys %idsrules) { + # Check if the rulefile is enabled. + if ($cgiparams{$rulefile} eq "on") { + # Add rulefile to the array of enabled rulefiles. + push(@enabled_rulefiles, $rulefile); + + # Drop item from cgiparams hash. + delete $cgiparams{$rulefile}; } - if ($snortsettings{'ENABLE_SNORT_ORANGE'} eq 'on') - { - system ('/usr/bin/touch', "${General::swroot}/snort/enable_orange"); - } else { - unlink "${General::swroot}/snort/enable_orange"; + } + + # Read-in the files for enabled/disabled sids. + # This will be done by calling the read_enabled_disabled_sids_file function two times + # and merge the returned hashes together into the enabled_disabled_sids hash. + %enabled_disabled_sids = ( + &read_enabled_disabled_sids_file($IDS::disabled_sids_file), + &read_enabled_disabled_sids_file($IDS::enabled_sids_file)); + + # Loop through the hash of idsrules. + foreach my $rulefile (keys %idsrules) { + # Loop through the single rules of the rulefile. + foreach my $sid (keys %{$idsrules{$rulefile}}) { + # Skip the current sid if it is not numeric. + next unless ($sid =~ /\d+/ ); + + # Check if there exists a key in the cgiparams hash for this sid. + if (exists($cgiparams{$sid})) { + # Look if the rule is disabled. + if ($idsrules{$rulefile}{$sid}{'State'} eq "off") { + # Check if the state has been set to 'on'. + if ($cgiparams{$sid} eq "on") { + # Add/Modify the sid to/in the enabled_disabled_sids hash. + $enabled_disabled_sids{$sid} = "enabled"; + + # Drop item from cgiparams hash. + delete $cgiparams{$rulefile}{$sid}; + } + } + } else { + # Look if the rule is enabled. + if ($idsrules{$rulefile}{$sid}{'State'} eq "on") { + # Check if the state is 'on' and should be disabled. + # In this case there is no entry + # for the sid in the cgiparams hash. + # Add/Modify it to/in the enabled_disabled_sids hash. + $enabled_disabled_sids{$sid} = "disabled"; + + # Drop item from cgiparams hash. + delete $cgiparams{$rulefile}{$sid}; + } + } } - if ($snortsettings{'ENABLE_PREPROCESSOR_HTTP_INSPECT'} eq 'on') - { - system ('/usr/bin/touch', "${General::swroot}/snort/enable_preprocessor_http_inspect"); - } else { - unlink "${General::swroot}/snort/enable_preprocessor_http_inspect"; + } + + # Open enabled sid's file for writing. + open(ENABLED_FILE, ">$IDS::enabled_sids_file") or die "Could not write to $IDS::enabled_sids_file. $!\n"; + + # Open disabled sid's file for writing. + open(DISABLED_FILE, ">$IDS::disabled_sids_file") or die "Could not write to $IDS::disabled_sids_file. $!\n"; + + # Write header to the files. + print ENABLED_FILE "#Autogenerated file. Any custom changes will be overwritten!\n"; + print DISABLED_FILE "#Autogenerated file. Any custom changes will be overwritten!\n"; + + # Check if the hash for enabled/disabled files contains any entries. + if (%enabled_disabled_sids) { + # Loop through the hash. + foreach my $sid (keys %enabled_disabled_sids) { + # Check if the sid is enabled. + if ($enabled_disabled_sids{$sid} eq "enabled") { + # Print the sid to the enabled_sids file. + print ENABLED_FILE "enablesid $sid\n"; + # Check if the sid is disabled. + } elsif ($enabled_disabled_sids{$sid} eq "disabled") { + # Print the sid to the disabled_sids file. + print DISABLED_FILE "disablesid $sid\n"; + # Something strange happende - skip the current sid. + } else { + next; + } } + } + + # Close file for enabled_sids after writing. + close(ENABLED_FILE); + + # Close file for disabled_sids after writing. + close(DISABLED_FILE); + + # Call function to generate and write the used rulefiles file. + &IDS::write_used_rulefiles_file(@enabled_rulefiles); + + # Lock the webpage and print message. + &working_notice("$Lang::tr{'snort working'}"); - system('/usr/local/bin/snortctrl restart >/dev/null'); + # Call oinkmaster to alter the ruleset. + &IDS::oinkmaster(); + + # Check if the IDS is running. + if(&IDS::ids_is_running()) { + # Call suricatactrl to perform a reload. + &IDS::call_suricatactrl("reload"); } - # INSTALLMD5 is not in the form, so not retrieved by getcgihash - &General::readhash("${General::swroot}/snort/settings", \%snortsettings); + # Reload page. + &reload(); - if ($snortsettings{'ACTION'} eq $Lang::tr{'download new ruleset'} || $snortsettings{'ACTION'} eq $Lang::tr{'upload new ruleset'}) { - my @df = `/bin/df -B M /var`; - foreach my $line (@df) { - next if $line =~ m/^Filesystem/; - my $return; +# Download new ruleset. +} elsif ($cgiparams{'RULESET'} eq $Lang::tr{'download new ruleset'}) { + # Check if the red device is active. + unless (-e "${General::swroot}/red/active") { + $errormessage = $Lang::tr{'could not download latest updates'}; + } - if ($line =~ m/dev/ ) { - $line =~ m/^.* (\d+)M.*$/; - my @temp = split(/ +/,$line); - if ($1<300) { - $errormessage = "$Lang::tr{'not enough disk space'} < 300MB, /var $1MB"; - } else { - if ( $snortsettings{'ACTION'} eq $Lang::tr{'download new ruleset'}) { - &downloadrulesfile(); - sleep(3); - $return = `cat /var/tmp/log 2>/dev/null`; - - } elsif ( $snortsettings{'ACTION'} eq $Lang::tr{'upload new ruleset'}) { - my $upload = $a->param("UPLOAD"); - open UPLOADFILE, ">/var/tmp/snortrules.tar.gz"; - binmode $upload; - while ( <$upload> ) { - print UPLOADFILE; - } - close UPLOADFILE; - } + # Check if enought free disk space is availabe. + if(&IDS::checkdiskspace()) { + $errormessage = "$Lang::tr{'not enough disk space'}"; + } - if ($return =~ "ERROR") { - $errormessage = "
".$return."
"; - } else { - system("/usr/local/bin/oinkmaster.pl -v -s -u file:///var/tmp/snortrules.tar.gz -C /var/ipfire/snort/oinkmaster.conf -o /etc/snort/rules >>/var/tmp/log 2>&1 &"); - sleep(2); - } - } + # Check if any errors happend. + unless ($errormessage) { + # Lock the webpage and print notice about downloading + # a new ruleset. + &working_notice("$Lang::tr{'snort working'}"); + + # Call subfunction to download the ruleset. + if(&IDS::downloadruleset()) { + $errormessage = $Lang::tr{'could not download latest updates'}; + + # Call function to store the errormessage. + &IDS::_store_error_message($errormessage); + + # Preform a reload of the page. + &reload(); + } else { + # Call subfunction to launch oinkmaster. + &IDS::oinkmaster(); + + # Check if the IDS is running. + if(&IDS::ids_is_running()) { + # Call suricatactrl to perform a reload. + &IDS::call_suricatactrl("reload"); + } + + # Perform a reload of the page. + &reload(); + } + } +# Save snort settings. +} elsif ($cgiparams{'IDS'} eq $Lang::tr{'save'}) { + my %oldidssettings; + my $reload_page; + my $monitored_zones = 0; + + # Read-in current (old) IDS settings. + &General::readhash("$IDS::ids_settings_file", \%oldidssettings); + + # Prevent form name from been stored in conf file. + delete $cgiparams{'IDS'}; + + # Check if the IDS should be enabled. + if ($cgiparams{'ENABLE_IDS'} eq "on") { + # Check if any ruleset is available. Otherwise abort and display an error. + unless(%idsrules) { + $errormessage = $Lang::tr{'ids no ruleset available'}; + } + + # Loop through the array of available interfaces. + foreach my $zone (@network_zones) { + # Convert interface name into upper case. + my $zone_upper = uc($zone); + + # Check if the IDS is enabled for this interaces. + if ($cgiparams{"ENABLE_IDS_$zone_upper"}) { + # Increase count. + $monitored_zones++; } } + + # Check if at least one zone should be monitored, or show an error. + unless ($monitored_zones >= 1) { + $errormessage = $Lang::tr{'ids no network zone'}; + } + } + + # Go on if there are no error messages. + if (!$errormessage) { + # Store settings into settings file. + &General::writehash("$IDS::ids_settings_file", \%cgiparams); + } + + # Generate file to store the home net. + &IDS::generate_home_net_file(); + + # Temporary variable to set the ruleaction. + # Default is "drop" to use suricata as IPS. + my $ruleaction="drop"; + + # Check if the traffic only should be monitored. + if($cgiparams{'MONITOR_TRAFFIC_ONLY'} eq 'on') { + # Switch the ruleaction to "alert". + # Suricata acts as an IDS only. + $ruleaction="alert"; + } + + # Write the modify sid's file and pass the taken ruleaction. + &IDS::write_modify_sids_file($ruleaction); + + # Check if "MONITOR_TRAFFIC_ONLY" has been changed. + if($cgiparams{'MONITOR_TRAFFIC_ONLY'} ne $oldidssettings{'MONITOR_TRAFFIC_ONLY'}) { + # Check if a ruleset exists. + if (%idsrules) { + # Lock the webpage and print message. + &working_notice("$Lang::tr{'snort working'}"); + + # Call oinkmaster to alter the ruleset. + &IDS::oinkmaster(); + + # Set reload_page to "True". + $reload_page="True"; + } + } + + # Check if the IDS currently is running. + if(&IDS::ids_is_running()) { + # Check if ENABLE_IDS is set to on. + if($cgiparams{'ENABLE_IDS'} eq "on") { + # Call suricatactrl to perform a reload of suricata. + &IDS::call_suricatactrl("reload"); + } else { + # Call suricatactrl to stop suricata. + &IDS::call_suricatactrl("stop"); + } + } else { + # Call suricatactrl to start suricata. + &IDS::call_suricatactrl("start"); + } + + # Check if the page should be reloaded. + if ($reload_page) { + # Perform a reload of the page. + &reload(); } }