From 4f80148e5c4955f15faa6e7b0bdb76d02829df0d Mon Sep 17 00:00:00 2001 From: Stefan Schantl Date: Thu, 1 Apr 2021 11:39:57 +0200 Subject: [PATCH] IDS: Redesign backend for used provider rulesfiles. The selected rulesfiles of a provider now will be written to an own provider exclusive yaml file, which will be included dynamically when the provider is enabled or not. This allows very easy handling to enable or disable a provider, in this case the file which keeps the enabled providers rulesets only needs to be included in the main file or even not. Signed-off-by: Stefan Schantl --- config/cfgroot/ids-functions.pl | 85 +++++++++++++++++++++++++++------ config/suricata/suricata.yaml | 2 +- html/cgi-bin/ids.cgi | 76 ++++++++++++++++++++++++----- 3 files changed, 136 insertions(+), 27 deletions(-) diff --git a/config/cfgroot/ids-functions.pl b/config/cfgroot/ids-functions.pl index ed9bb203ba..245a267bf2 100644 --- a/config/cfgroot/ids-functions.pl +++ b/config/cfgroot/ids-functions.pl @@ -27,12 +27,15 @@ package IDS; require '/var/ipfire/general-functions.pl'; require "${General::swroot}/network-functions.pl"; -require "${General::swroot}/suricata/ruleset-sources"; +require "${General::swroot}/suricata/ruleset-sources-new"; # Location where all config and settings files are stored. our $settingsdir = "${General::swroot}/suricata"; -# File where the used rulefiles are stored. +# File where the main file for providers ruleset inclusion exists. +our $suricata_used_providers_file = "$settingsdir/suricata-used-providers.yaml"; + +# DEPRECATED - File where the used rulefiles are stored. our $used_rulefiles_file = "$settingsdir/suricata-used-rulefiles.yaml"; # File where the addresses of the homenet are stored. @@ -138,7 +141,7 @@ sub check_and_create_filelayout() { unless (-f "$enabled_sids_file") { &create_empty_file($enabled_sids_file); } unless (-f "$disabled_sids_file") { &create_empty_file($disabled_sids_file); } unless (-f "$modify_sids_file") { &create_empty_file($modify_sids_file); } - unless (-f "$used_rulefiles_file") { &create_empty_file($used_rulefiles_file); } + unless (-f "$suricata_used_providers_file") { &create_empty_file($suricata_used_providers_file); } unless (-f "$ids_settings_file") { &create_empty_file($ids_settings_file); } unless (-f "$providers_settings_file") { &create_empty_file($providers_settings_file); } unless (-f "$ignored_file") { &create_empty_file($ignored_file); } @@ -1226,13 +1229,18 @@ sub generate_http_ports_file() { } # -## Function to generate and write the file for used rulefiles. +## Function to generate and write the file for used rulefiles file for a given provider. +## +## The function requires as first argument a provider handle, and as second an array with files. # -sub write_used_rulefiles_file(@) { - my @files = @_; +sub write_used_provider_rulefiles_file($@) { + my ($provider, @files) = @_; + + # Get the path and file for the provider specific used rulefiles file. + my $used_provider_rulesfile_file = &get_used_provider_rulesfile_file($provider); # Open file for used rulefiles. - open (FILE, ">$used_rulefiles_file") or die "Could not write to $used_rulefiles_file. $!\n"; + open (FILE, ">$used_provider_rulesfile_file") or die "Could not write to $used_provider_rulesfile_file. $!\n"; # Write yaml header to the file. print FILE "%YAML 1.1\n"; @@ -1241,9 +1249,6 @@ sub write_used_rulefiles_file(@) { # Write header to file. print FILE "#Autogenerated file. Any custom changes will be overwritten!\n"; - # Allways use the whitelist. - print FILE " - whitelist.rules\n"; - # Loop through the array of given files. foreach my $file (@files) { # Check if the given filename exists and write it to the file of used rulefiles. @@ -1256,6 +1261,53 @@ sub write_used_rulefiles_file(@) { close(FILE); } +# +## Function to write the main file for provider rulesfiles inclusions. +## +## This function requires an array of provider handles. +# +sub write_main_used_rulefiles_file (@) { + my (@providers) = @_; + + # Open file for used rulefils inclusion. + open (FILE, ">", "$suricata_used_providers_file") or die "Could not write to $suricata_used_providers_file. $!\n"; + + # Write yaml header to the file. + print FILE "%YAML 1.1\n"; + print FILE "---\n\n"; + + # Write header to file. + print FILE "#Autogenerated file. Any custom changes will be overwritten!\n"; + + # Loop through the list of given providers. + foreach my $provider (@providers) { + # Call function to get the providers used rulefiles file. + my $filename = &get_used_provider_rulesfile_file($provider); + + # Print the provider to the file. + print FILE "include\: $filename\n"; + } + + # XXX - whitelist.rules is not allowed directly, needs to be in a yaml file which has to be included. + # Always use the whitelist file. + #print FILE "\n - whitelist.rules\n"; + + # Close the filehandle after writing. + close(FILE); +} + +# +## Tiny function to generate the full path and name for the used_provider_rulesfile file of a given provider. +# +sub get_used_provider_rulesfile_file ($) { + my ($provider) = @_; + + my $filename = "$settingsdir/suricata\-$provider\-used\-rulefiles.yaml"; + + # Return the gernerated file. + return $filename; +} + # ## Function to generate and write the file for modify the ruleset. # @@ -1509,16 +1561,21 @@ sub get_red_address() { } # -## Function to get all used rulesfiles files. +## Function to get the used rules files of a given provider. # -sub get_used_rulesfiles() { +sub read_used_provider_rulesfiles($) { + my ($provider) = @_; + # Array to store the used rulefiles. my @used_rulesfiles = (); + # Get the used rulesefile file for the provider. + my $rulesfile_file = &get_used_provider_rulesfile_file($provider); + # Check if the used rulesfile is empty. - unless (-z $used_rulefiles_file) { + unless (-z $rulesfile_file) { # Open the file or used rulefiles and read-in content. - open(FILE, $used_rulefiles_file) or die "Could not open $used_rulefiles_file. $!\n"; + open(FILE, $rulesfile_file) or die "Could not open $rulesfile_file. $!\n"; while () { # Assign the current line to a nice variable. diff --git a/config/suricata/suricata.yaml b/config/suricata/suricata.yaml index 4e9e399675..cc9e23642b 100644 --- a/config/suricata/suricata.yaml +++ b/config/suricata/suricata.yaml @@ -47,7 +47,7 @@ vars: default-rule-path: /var/lib/suricata rule-files: # Include enabled ruleset files from external file. - include: /var/ipfire/suricata/suricata-used-rulefiles.yaml + include: /var/ipfire/suricata/suricata-used-providers.yaml classification-file: /var/lib/suricata/classification.config reference-config-file: /var/lib/suricata/reference.config diff --git a/html/cgi-bin/ids.cgi b/html/cgi-bin/ids.cgi index 043faad2ef..fc3234474c 100644 --- a/html/cgi-bin/ids.cgi +++ b/html/cgi-bin/ids.cgi @@ -254,6 +254,10 @@ if (-e $IDS::storederrorfile) { if ($cgiparams{'RULESET'}) { ## Grab all available rules and store them in the idsrules hash. # + + # Get enabled providers. + my @enabled_providers = &IDS::get_enabled_providers(); + # Open rules directory and do a directory listing. opendir(DIR, $IDS::rulespath) or die $!; # Loop through the direcory. @@ -274,6 +278,15 @@ if ($cgiparams{'RULESET'}) { # Skip whitelist rules file. next if( $file eq "whitelist.rules"); + # Splitt vendor from filename. + my @filename_parts = split(/-/, $file); + + # Assign vendor name for easy processing. + my $vendor = @filename_parts[0]; + + # Skip rulefile if the provider is disabled. + next unless ($vendor ~~ @enabled_providers); + # Call subfunction to read-in rulefile and add rules to # the idsrules hash. &readrulesfile("$file"); @@ -281,17 +294,20 @@ if ($cgiparams{'RULESET'}) { closedir(DIR); - # Gather used rulefiles. - my @used_rulesfiles = &IDS::get_used_rulesfiles(); - - # Loop through the array of used rulesfiles. - foreach my $rulesfile (@used_rulesfiles) { - # 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"; + # Loop through the array of used providers. + foreach my $provider (@enabled_providers) { + # Gather used rulefiles. + my @used_rulesfiles = &IDS::read_used_provider_rulesfiles($provider); + + # Loop through the array of used rulesfiles. + foreach my $rulefile (@used_rulesfiles) { + # 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"; + } } } } @@ -479,8 +495,40 @@ if ($cgiparams{'RULESET'} eq $Lang::tr{'save'}) { # Close file for disabled_sids after writing. close(DISABLED_FILE); + # Handle enabled / disabled rulefiles. + # + # Get enabled providers. + my @enabled_providers = &IDS::get_enabled_providers(); + + # Loop through the array of enabled providers. + foreach my $provider(@enabled_providers) { + # Array to store the rulefiles which belong to the current processed provider. + my @provider_rulefiles = (); + + # Loop through the array of enabled rulefiles. + foreach my $rulesfile (@enabled_rulefiles) { + # Split the rulefile name. + my @filename_parts = split(/-/, "$rulesfile"); + + # Assign vendor name for easy processings. + my $vendor = @filename_parts[0]; + + # Check if the rulesvendor is our current processed enabled provider. + if ("$vendor" eq "$provider") { + # Add the rulesfile to the array of provider rulesfiles. + push(@provider_rulefiles, $rulesfile); + } + + # Check if any rulesfiles have been found for this provider. + if (@provider_rulefiles) { + # Call function and write the providers used rulesfile file. + &IDS::write_used_provider_rulefiles_file($provider, @provider_rulefiles); + } + } + } + # Call function to generate and write the used rulefiles file. - &IDS::write_used_rulefiles_file(@enabled_rulefiles); + &IDS::write_main_used_rulefiles_file(@enabled_providers); # Lock the webpage and print message. &working_notice("$Lang::tr{'ids apply ruleset changes'}"); @@ -779,6 +827,10 @@ if ($cgiparams{'RULESET'} eq $Lang::tr{'save'}) { # Cleanup temporary directory. &IDS::cleanup_tmp_directory(); + # Create new empty file for used rulefiles + # for this provider. + &IDS::write_used_provider_rulefiles_file($provider); + # Perform a reload of the page. &reload(); } -- 2.39.5