X-Git-Url: http://git.ipfire.org/?p=ipfire-2.x.git;a=blobdiff_plain;f=html%2Fcgi-bin%2Fids.cgi;h=313714486553d5debd53ec67477eb91912370009;hp=0daf7903eef04db977e47c6e784a7c4a7099232e;hb=5fbd7b29829caf0bcadcccd6f56ead51e2fb812e;hpb=e2e7880dc73fc98aa7409b2de2384e5c9e436f29 diff --git a/html/cgi-bin/ids.cgi b/html/cgi-bin/ids.cgi index 0daf7903ee..3137144865 100644 --- a/html/cgi-bin/ids.cgi +++ b/html/cgi-bin/ids.cgi @@ -34,10 +34,12 @@ my %color = (); my %mainsettings = (); my %idsrules = (); my %idssettings=(); +my %rulessettings=(); my %rulesetsources = (); my %cgiparams=(); my %checked=(); my %selected=(); +my %ignored=(); # Read-in main settings, for language, theme and colors. &General::readhash("${General::swroot}/main/settings", \%mainsettings); @@ -47,19 +49,183 @@ my %selected=(); # the list of zones in an array. my @network_zones = &IDS::get_available_network_zones(); -# File where the used rulefiles are stored. -my $idsusedrulefilesfile = "$IDS::settingsdir/suricata-used-rulefiles.yaml"; +my $errormessage; -# File where the addresses of the homenet are stored. -my $idshomenetfile = "$IDS::settingsdir/suricata-homenet.yaml"; +# Create files if they does not exist yet. +&IDS::check_and_create_filelayout(); -my $errormessage; +# Hash which contains the colour code of a network zone. +my %colourhash = ( + 'red' => $Header::colourred, + 'green' => $Header::colourgreen, + 'blue' => $Header::colourblue, + 'orange' => $Header::colourorange +); &Header::showhttpheaders(); #Get GUI values &Header::getcgihash(\%cgiparams); +## Add/edit an entry to the ignore file. +# +if (($cgiparams{'WHITELIST'} eq $Lang::tr{'add'}) || ($cgiparams{'WHITELIST'} eq $Lang::tr{'update'})) { + + # Check if any input has been performed. + if ($cgiparams{'IGNORE_ENTRY_ADDRESS'} ne '') { + + # Check if the given input is no valid IP-address or IP-address with subnet, display an error message. + if ((!&General::validip($cgiparams{'IGNORE_ENTRY_ADDRESS'})) && (!&General::validipandmask($cgiparams{'IGNORE_ENTRY_ADDRESS'}))) { + $errormessage = "$Lang::tr{'guardian invalid address or subnet'}"; + } + } else { + $errormessage = "$Lang::tr{'guardian empty input'}"; + } + + # Go further if there was no error. + if ($errormessage eq '') { + my %ignored = (); + my $id; + my $status; + + # Assign hash values. + my $new_entry_address = $cgiparams{'IGNORE_ENTRY_ADDRESS'}; + my $new_entry_remark = $cgiparams{'IGNORE_ENTRY_REMARK'}; + + # Read-in ignoredfile. + &General::readhasharray($IDS::ignored_file, \%ignored); + + # Check if we should edit an existing entry and got an ID. + if (($cgiparams{'WHITELIST'} eq $Lang::tr{'update'}) && ($cgiparams{'ID'})) { + # Assin the provided id. + $id = $cgiparams{'ID'}; + + # Undef the given ID. + undef($cgiparams{'ID'}); + + # Grab the configured status of the corresponding entry. + $status = $ignored{$id}[2]; + } else { + # Each newly added entry automatically should be enabled. + $status = "enabled"; + + # Generate the ID for the new entry. + # + # Sort the keys by their ID and store them in an array. + my @keys = sort { $a <=> $b } keys %ignored; + + # Reverse the key array. + my @reversed = reverse(@keys); + + # Obtain the last used id. + my $last_id = @reversed[0]; + + # Increase the last id by one and use it as id for the new entry. + $id = ++$last_id; + } + + # Add/Modify the entry to/in the ignored hash. + $ignored{$id} = ["$new_entry_address", "$new_entry_remark", "$status"]; + + # Write the changed ignored hash to the ignored file. + &General::writehasharray($IDS::ignored_file, \%ignored); + + # Regenerate the ignore file. + &IDS::generate_ignore_file(); + } + + # Check if the IDS is running. + if(&IDS::ids_is_running()) { + # Call suricatactrl to perform a reload. + &IDS::call_suricatactrl("reload"); + } + +## Toggle Enabled/Disabled for an existing entry on the ignore list. +# + +} elsif ($cgiparams{'WHITELIST'} eq $Lang::tr{'toggle enable disable'}) { + my %ignored = (); + + # Only go further, if an ID has been passed. + if ($cgiparams{'ID'}) { + # Assign the given ID. + my $id = $cgiparams{'ID'}; + + # Undef the given ID. + undef($cgiparams{'ID'}); + + # Read-in ignoredfile. + &General::readhasharray($IDS::ignored_file, \%ignored); + + # Grab the configured status of the corresponding entry. + my $status = $ignored{$id}[2]; + + # Switch the status. + if ($status eq "disabled") { + $status = "enabled"; + } else { + $status = "disabled"; + } + + # Modify the status of the existing entry. + $ignored{$id} = ["$ignored{$id}[0]", "$ignored{$id}[1]", "$status"]; + + # Write the changed ignored hash to the ignored file. + &General::writehasharray($IDS::ignored_file, \%ignored); + + # Regenerate the ignore file. + &IDS::generate_ignore_file(); + + # Check if the IDS is running. + if(&IDS::ids_is_running()) { + # Call suricatactrl to perform a reload. + &IDS::call_suricatactrl("reload"); + } + } + +## Remove entry from ignore list. +# +} elsif ($cgiparams{'WHITELIST'} eq $Lang::tr{'remove'}) { + my %ignored = (); + + # Read-in ignoredfile. + &General::readhasharray($IDS::ignored_file, \%ignored); + + # Drop entry from the hash. + delete($ignored{$cgiparams{'ID'}}); + + # Undef the given ID. + undef($cgiparams{'ID'}); + + # Write the changed ignored hash to the ignored file. + &General::writehasharray($IDS::ignored_file, \%ignored); + + # Regenerate the ignore file. + &IDS::generate_ignore_file(); + + # Check if the IDS is running. + if(&IDS::ids_is_running()) { + # Call suricatactrl to perform a reload. + &IDS::call_suricatactrl("reload"); + } +} + +# Check if the page is locked, in this case, the ids_page_lock_file exists. +if (-e $IDS::ids_page_lock_file) { + # Lock the webpage and print notice about autoupgrade of the ruleset + # is in progess. + &working_notice("$Lang::tr{'ids ruleset autoupdate in progress'}"); + + # Loop and check if the file still exists. + while(-e $IDS::ids_page_lock_file) { + # Sleep for a second and re-check. + sleep 1; + } + + # Page has been unlocked, perform a reload. + &reload(); +} + # Check if any error has been stored. if (-e $IDS::storederrorfile) { # Open file to read in the stored error message. @@ -75,10 +241,9 @@ if (-e $IDS::storederrorfile) { unlink($IDS::storederrorfile); } - -## Grab all available snort rules and store them in the idsrules hash. +## Grab all available rules and store them in the idsrules hash. # -# Open snort rules directory and do a directory listing. +# Open rules directory and do a directory listing. opendir(DIR, $IDS::rulespath) or die $!; # Loop through the direcory. while (my $file = readdir(DIR)) { @@ -95,6 +260,9 @@ opendir(DIR, $IDS::rulespath) or die $!; # 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"); @@ -105,9 +273,9 @@ closedir(DIR); # Gather used rulefiles. # # Check if the file for activated rulefiles is not empty. -if(-f $idsusedrulefilesfile) { +if(-f $IDS::used_rulefiles_file) { # Open the file for used rulefile and read-in content. - open(FILE, $idsusedrulefilesfile) or die "Could not open $idsusedrulefilesfile. $!\n"; + open(FILE, $IDS::used_rulefiles_file) or die "Could not open $IDS::used_rulefiles_file. $!\n"; # Read-in content. my @lines = ; @@ -130,22 +298,111 @@ if(-f $idsusedrulefilesfile) { if ($line =~ /.*- (.*)/) { my $rulefile = $1; - # Add the rulefile to the %idsrules hash. - $idsrules{$rulefile}{'Rulefile'}{'State'} = "on"; + # 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"; + } } } } -# Save ruleset. -if ($cgiparams{'RULESET'} eq $Lang::tr{'update'}) { - my $enabled_sids_file = "$IDS::settingsdir/oinkmaster-enabled-sids.conf"; - my $disabled_sids_file = "$IDS::settingsdir/oinkmaster-disabled-sids.conf"; +# Save ruleset configuration. +if ($cgiparams{'RULESET'} eq $Lang::tr{'save'}) { + my %oldsettings; + my %rulesetsources; + + # Read-in current (old) IDS settings. + &General::readhash("$IDS::rules_settings_file", \%oldsettings); + + # Get all available ruleset locations. + &General::readhash("$IDS::rulesetsourcesfile", \%rulesetsources); - # Arrays to store sid which should be added to the corresponding files. - my @enabled_sids; - my @disabled_sids; + # Prevent form name from been stored in conf file. + delete $cgiparams{'RULESET'}; + + # Grab the URL based on the choosen vendor. + my $url = $rulesetsources{$cgiparams{'RULES'}}; + + # Check if the choosen vendor (URL) requires an subscription/oinkcode. + if ($url =~ /\/ ) { + # Check if an subscription/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'}; + } + } else { + # Print an error message, that an subsription/oinkcode is required for this + # vendor. + $errormessage = $Lang::tr{'ids oinkcode required'}; + } + } + + # 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'}); + } + + # Check if a ruleset is present - if not or the source has been changed download it. + if((! %idsrules) || ($oldsettings{'RULES'} ne $cgiparams{'RULES'})) { + # Check if the red device is active. + unless (-e "${General::swroot}/red/active") { + $errormessage = "$Lang::tr{'could not download latest updates'} - $Lang::tr{'system is offline'}"; + } + + # Check if enought free disk space is availabe. + if(&IDS::checkdiskspace()) { + $errormessage = "$Lang::tr{'not enough disk space'}"; + } + + # Check if any errors happend. + unless ($errormessage) { + # Lock the webpage and print notice about downloading + # a new ruleset. + &working_notice("$Lang::tr{'ids 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); + } else { + # Call subfunction to launch oinkmaster. + &IDS::oinkmaster(); + } + + # Check if the IDS is running. + if(&IDS::ids_is_running()) { + # Call suricatactrl to stop the IDS - because of the changed + # ruleset - the use has to configure it before suricata can be + # used again. + &IDS::call_suricatactrl("stop"); + } + + # Perform a reload of the page. + &reload(); + } + } + } + +# Save ruleset. +} elsif ($cgiparams{'RULESET'} eq $Lang::tr{'ids apply'}) { + # 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. @@ -158,6 +415,13 @@ if ($cgiparams{'RULESET'} eq $Lang::tr{'update'}) { } } + # 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. @@ -171,8 +435,8 @@ if ($cgiparams{'RULESET'} eq $Lang::tr{'update'}) { if ($idsrules{$rulefile}{$sid}{'State'} eq "off") { # Check if the state has been set to 'on'. if ($cgiparams{$sid} eq "on") { - # Add the sid to the enabled_sids array. - push(@enabled_sids, $sid); + # 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}; @@ -184,8 +448,8 @@ if ($cgiparams{'RULESET'} eq $Lang::tr{'update'}) { # 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 it to the disabled_sids array. - push(@disabled_sids, $sid); + # Add/Modify it to/in the enabled_disabled_sids hash. + $enabled_disabled_sids{$sid} = "disabled"; # Drop item from cgiparams hash. delete $cgiparams{$rulefile}{$sid}; @@ -195,68 +459,51 @@ if ($cgiparams{'RULESET'} eq $Lang::tr{'update'}) { } # Open enabled sid's file for writing. - open(FILE, ">$enabled_sids_file") or die "Could not write to $enabled_sids_file. $!\n"; - - # Write header to file. - print FILE "#Autogenerated file. Any custom changes will be overwritten!\n"; - - # Check if the enabled_sids array contains any sid's. - if (@enabled_sids) { - # Loop through the array of enabled sids and write them to the file. - foreach my $sid (@enabled_sids) { - print FILE "enablesid $sid\n"; - } - } - - # Close file after writing. - close(FILE); + 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(FILE, ">$disabled_sids_file") or die "Could not write to $disabled_sids_file. $!\n"; - - # Write header to file. - print FILE "#Autogenerated file. Any custom changes will be overwritten!\n"; - - # Check if the enabled_sids array contains any sid's. - if (@disabled_sids) { - # Loop through the array of disabled sids and write them to the file. - foreach my $sid (@disabled_sids) { - print FILE "disablesid $sid\n"; + 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 after writing. - close(FILE); - - # Open file for used rulefiles. - open (FILE, ">$idsusedrulefilesfile") or die "Could not write to $idsusedrulefilesfile. $!\n"; + # Close file for enabled_sids after writing. + close(ENABLED_FILE); - # 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"; - - # Check if the enabled_rulefiles array contains any entries. - if (@enabled_rulefiles) { - # Loop through the array of rulefiles which should be loaded and write the to the file. - foreach my $file (@enabled_rulefiles) { - print FILE " - $file\n"; - } - } + # Close file for disabled_sids after writing. + close(DISABLED_FILE); - # Close file after writing. - close(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'}"); + &working_notice("$Lang::tr{'ids apply ruleset changes'}"); # Call oinkmaster to alter the ruleset. &IDS::oinkmaster(); # Check if the IDS is running. - if(&IDS::is_ids_running()) { + if(&IDS::ids_is_running()) { # Call suricatactrl to perform a reload. &IDS::call_suricatactrl("reload"); } @@ -265,10 +512,10 @@ if ($cgiparams{'RULESET'} eq $Lang::tr{'update'}) { &reload(); # Download new ruleset. -} elsif ($cgiparams{'RULESET'} eq $Lang::tr{'download new ruleset'}) { +} elsif ($cgiparams{'RULESET'} eq $Lang::tr{'update ruleset'}) { # Check if the red device is active. unless (-e "${General::swroot}/red/active") { - $errormessage = $Lang::tr{'could not download latest updates'}; + $errormessage = "$Lang::tr{'could not download latest updates'} - $Lang::tr{'system is offline'}"; } # Check if enought free disk space is availabe. @@ -280,7 +527,7 @@ if ($cgiparams{'RULESET'} eq $Lang::tr{'update'}) { unless ($errormessage) { # Lock the webpage and print notice about downloading # a new ruleset. - &working_notice("$Lang::tr{'snort working'}"); + &working_notice("$Lang::tr{'ids download new ruleset'}"); # Call subfunction to download the ruleset. if(&IDS::downloadruleset()) { @@ -296,7 +543,7 @@ if ($cgiparams{'RULESET'} eq $Lang::tr{'update'}) { &IDS::oinkmaster(); # Check if the IDS is running. - if(&IDS::is_ids_running()) { + if(&IDS::ids_is_running()) { # Call suricatactrl to perform a reload. &IDS::call_suricatactrl("reload"); } @@ -305,27 +552,80 @@ if ($cgiparams{'RULESET'} eq $Lang::tr{'update'}) { &reload(); } } -# Save snort settings. +# Save IDS 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 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'}; + # 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::settingsdir/settings", \%cgiparams); + &General::writehash("$IDS::ids_settings_file", \%cgiparams); } # Generate file to store the home net. - &generate_home_net_file(); + &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{'ids 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()) { @@ -341,30 +641,83 @@ if ($cgiparams{'RULESET'} eq $Lang::tr{'update'}) { # 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(); + } } -# Read-in idssettings -&General::readhash("$IDS::settingsdir/settings", \%idssettings); +# Read-in idssettings and rulesetsettings +&General::readhash("$IDS::ids_settings_file", \%idssettings); +&General::readhash("$IDS::rules_settings_file", \%rulessettings); + +# If no autoupdate intervall has been configured yet, set default value. +unless(exists($rulessettings{'AUTOUPDATE_INTERVAL'})) { + # Set default to "weekly". + $rulessettings{'AUTOUPDATE_INTERVAL'} = 'weekly'; +} + +# Read-in ignored hosts. +&General::readhasharray("$IDS::settingsdir/ignored", \%ignored); $checked{'ENABLE_IDS'}{'off'} = ''; $checked{'ENABLE_IDS'}{'on'} = ''; $checked{'ENABLE_IDS'}{$idssettings{'ENABLE_IDS'}} = "checked='checked'"; +$checked{'MONITOR_TRAFFIC_ONLY'}{'off'} = ''; +$checked{'MONITOR_TRAFFIC_ONLY'}{'on'} = ''; +$checked{'MONITOR_TRAFFIC_ONLY'}{$idssettings{'MONITOR_TRAFFIC_ONLY'}} = "checked='checked'"; $selected{'RULES'}{'nothing'} = ''; $selected{'RULES'}{'community'} = ''; $selected{'RULES'}{'emerging'} = ''; $selected{'RULES'}{'registered'} = ''; $selected{'RULES'}{'subscripted'} = ''; -$selected{'RULES'}{$idssettings{'RULES'}} = "selected='selected'"; +$selected{'RULES'}{$rulessettings{'RULES'}} = "selected='selected'"; +$selected{'AUTOUPDATE_INTERVAL'}{'off'} = ''; +$selected{'AUTOUPDATE_INTERVAL'}{'daily'} = ''; +$selected{'AUTOUPDATE_INTERVAL'}{'weekly'} = ''; +$selected{'AUTOUPDATE_INTERVAL'}{$rulessettings{'AUTOUPDATE_INTERVAL'}} = "selected='selected'"; &Header::openpage($Lang::tr{'intrusion detection system'}, 1, ''); ### Java Script ### +print" END @@ -429,241 +782,399 @@ END END } -&Header::closebox(); -# Draw elements for IDS configuration. -&Header::openbox('100%', 'center', $Lang::tr{'settings'}); +# Only show this area, if a ruleset is present. +if (%idsrules) { -my $rulesdate; + print <

$Lang::tr{'settings'}

-print < - - - + +
- $Lang::tr{'ids activate'} $Lang::tr{'intrusion detection system'} -
+ + - - + - - + + + + + + - - + + + - - + END ; -# Loop through the array of available networks and print config options. -foreach my $zone (@network_zones) { - my $checked_input; - my $checked_forward; + # Loop through the array of available networks and print config options. + foreach my $zone (@network_zones) { + my $checked_input; + my $checked_forward; - # Convert current zone name to upper case. - my $zone_upper = uc($zone); + # Convert current zone name to upper case. + my $zone_upper = uc($zone); - # Grab checkbox status from settings hash. - if ($idssettings{"ENABLE_IDS_INPUT_$zone_upper"} eq "on") { - $checked_input = "checked = 'checked'"; - } + # Set zone name. + my $zone_name = $zone; - # Do the same for the forward setting. - if ($idssettings{"ENABLE_IDS_FORWARD_$zone_upper"} eq "on") { - $checked_forward = "checked = 'checked'"; + # Dirty hack to get the correct language string for the red zone. + if ($zone eq "red") { + $zone_name = "red1"; + } + + # Grab checkbox status from settings hash. + if ($idssettings{"ENABLE_IDS_$zone_upper"} eq "on") { + $checked_input = "checked = 'checked'"; + } + + print "\n"; } - print "\n"; - print "\n"; +print < +
+  $Lang::tr{'ids enable'} + -   + +  $Lang::tr{'ids monitor traffic only'}


-








- $Lang::tr{'ids analyze incomming traffic'} -
$Lang::tr{'ids monitored interfaces'}
- $Lang::tr{'ids analyze routing traffic'} -
\n"; + print "\n"; + print " $Lang::tr{'enabled on'} $Lang::tr{$zone_name}\n"; + print "
\n"; - print "$Lang::tr{'ids active on'} $Lang::tr{$zone}\n"; - print "
+ +

+ + + + + +
+ +END +; - print "\n"; - print "$Lang::tr{'ids active on'} $Lang::tr{$zone}\n"; - print "\n"; - print "\n"; } -print < +&Header::closebox(); - -

- +# Draw elements for ruleset configuration. +&Header::openbox('100%', 'center', $Lang::tr{'ids ruleset settings'}); +print < + - + + - - - - - + + + + + - + +
$Lang::tr{'ids rules update'}$Lang::tr{'ids rules update'}$Lang::tr{'ids automatic rules update'}
-
$Lang::tr{'ids rules license'} www.snort.org$Lang::tr{'ids rules license1'}
-
$Lang::tr{'ids rules license2'} Get an Oinkcode, $Lang::tr{'ids rules license3'}
+
+
Oinkcode: 


-  $Lang::tr{'updates installed'}: $rulesdate +
  +END +; + # Show the "Update Ruleset"-Button only if a ruleset has been downloaded yet and automatic updates are disabled. + if ((%idsrules) && ($rulessettings{'AUTOUPDATE_INTERVAL'} eq "off")) { + # Display button to update the ruleset. + print"\n"; + } +print <
+ +END +; + +&Header::closebox(); -

+# +# Whitelist / Ignorelist +# +&Header::openbox('100%', 'center', $Lang::tr{'guardian ignored hosts'}); +print < - + $Lang::tr{'ip address'} + $Lang::tr{'remark'} + - - END -; + # Check if some hosts have been added to be ignored. + if (keys (%ignored)) { + my $col = ""; + + # Loop through all entries of the hash. + while( (my $key) = each %ignored) { + # Assign data array positions to some nice variable names. + my $address = $ignored{$key}[0]; + my $remark = $ignored{$key}[1]; + my $status = $ignored{$key}[2]; + + # Check if the key (id) number is even or not. + if ($cgiparams{'ID'} eq $key) { + $col="bgcolor='${Header::colouryellow}'"; + } elsif ($key % 2) { + $col="bgcolor='$color{'color22'}'"; + } else { + $col="bgcolor='$color{'color20'}'"; + } -&Header::closebox(); + # Choose icon for the checkbox. + my $gif; + my $gdesc; -&Header::openbox('100%', 'LEFT', $Lang::tr{'intrusion detection system rules'}); - print"
\n"; + # Check if the status is enabled and select the correct image and description. + if ($status eq 'enabled' ) { + $gif = 'on.gif'; + $gdesc = $Lang::tr{'click to disable'}; + } else { + $gif = 'off.gif'; + $gdesc = $Lang::tr{'click to enable'}; + } - # Output display table for rule files - print "\n"; +print < + + + + + + + + + +END + } + } else { + # Print notice that currently no hosts are ignored. + print "\n"; + print "\n"; + print "\n"; + } + + print "
$address$remark + + + + + + +
+ + + +
+
+
+ + + +
+
$Lang::tr{'guardian no entries'}
\n"; + + # Section to add new elements or edit existing ones. +print < +
+
+ +
+ +END - # Local variable required for java script to show/hide - # rules of a rulefile. - my $rulesetcount = 1; + # Assign correct headline and button text. + my $buttontext; + my $entry_address; + my $entry_remark; - # Loop over each rule file - foreach my $rulefile (sort keys(%idsrules)) { - my $rulechecked = ''; + # Check if an ID (key) has been given, in this case an existing entry should be edited. + if ($cgiparams{'ID'} ne '') { + $buttontext = $Lang::tr{'update'}; + print "\n"; - # Check if rule file is enabled - if ($idsrules{$rulefile}{'Rulefile'}{'State'} eq 'on') { - $rulechecked = 'CHECKED'; + # Grab address and remark for the given key. + $entry_address = $ignored{$cgiparams{'ID'}}[0]; + $entry_remark = $ignored{$cgiparams{'ID'}}[1]; + } else { + $buttontext = $Lang::tr{'add'}; + print "\n"; } - # Table and rows for the rule files. - print"\n"; - print"\n"; - print"\n"; - print"\n"; - print"\n"; - - # Rows which will be hidden per default and will contain the single rules. - print"\n"; - print" + + + + + + + + +
$Lang::tr{'update'}
$Lang::tr{'dnsforward add a new entry'}
\n"; - print"\n"; - print"$rulefile\n"; - print"SHOW\n"; - print"
$Lang::tr{'ip address'}: $Lang::tr{'remark'}:
+
+END + +&Header::closebox(); + +# Only show the section for configuring the ruleset if one is present. +if (%idsrules) { + # Load neccessary perl modules for file stat and to format the timestamp. + use File::stat; + use POSIX qw( strftime ); + + # Call stat on the rulestarball. + my $stat = stat("$IDS::rulestarball"); + + # Get timestamp the file creation. + my $mtime = $stat->mtime; + + # Convert into human read-able format. + my $rulesdate = strftime('%Y-%m-%d %H:%M:%S', localtime($mtime)); + + &Header::openbox('100%', 'LEFT', "$Lang::tr{'intrusion detection system rules'} ($rulesdate)" ); + + print"
\n"; + + # Output display table for rule files print "\n"; - # Loop over rule file rules - foreach my $sid (sort {$a <=> $b} keys(%{$idsrules{$rulefile}})) { + # Loop over each rule file + foreach my $rulefile (sort keys(%idsrules)) { + my $rulechecked = ''; + + # Check if rule file is enabled + if ($idsrules{$rulefile}{'Rulefile'}{'State'} eq 'on') { + $rulechecked = 'CHECKED'; + } + + # Convert rulefile name into category name. + my $categoryname = &_rulefile_to_category($rulefile); + + # Table and rows for the rule files. + print"\n"; + print"\n"; + print"\n"; + print"\n"; + print"\n"; + + # Rows which will be hidden per default and will contain the single rules. + print"\n"; + print""; + # Increment rule count + $lines++; + } - # Finished whith the rule file, increase count. - $rulesetcount++; - } + # If do not have a second rule for row, create empty cell + if (($lines % 2) != 0) { + print ""; + } + + # Close display table + print "
\n"; + print"\n"; + print"$rulefile\n"; + print"$Lang::tr{'ids show'}\n"; + print"
"; + } - # Close display table - print ""; + # Close display table + print ""; print < - -   - + END ; -&Header::closebox(); + &Header::closebox(); +} + &Header::closebigbox(); &Header::closepage(); @@ -750,117 +1261,119 @@ sub readrulesfile ($) { } } } - } + } } # ## Function to get the used memory of a given process-id. # sub get_memory_usage($) { - my $pid = @_; + my ($pid) = @_; - my $memory=0; + my $memory = 0; - # Try to open statm file for the given process-id on the pseudo + # Try to open the status file for the given process-id on the pseudo # file system proc. - if (open(FILE, "/proc/$pid/statm")) { - # Read file content. - my $temp = ; - - # Splitt file content and store in an array. - my @memory = split(/ /,$temp); + if (open(FILE, "/proc/$pid/status")) { + # Loop through the entire file. + while () { + # Splitt current line content and store them into variables. + my ($key, $value) = split(":", $_, 2); + + # Check if the current key is the one which contains the memory usage. + # The wanted one is VmRSS which contains the Real-memory (resident set) + # of the entire process. + if ($key eq "VmRSS") { + # Found the memory usage add it to the memory variable. + $memory += $value; + + # Break the loop. + last; + } + } # Close file handle. - close(FILE); - - # Calculate memory usage. - $memory+=$memory[0]; + close(FILE); # Return memory usage. return $memory; - } + } # If the file could not be open, return nothing. return; } # -## Function to generate the file which contains the home net information. +## Function to read-in the given enabled or disables sids file. # -sub generate_home_net_file() { - my %netsettings; - - # Read-in network settings. - &General::readhash("${General::swroot}/ethernet/settings", \%netsettings); - - # Get available network zones. - my @network_zones = &IDS::get_available_network_zones(); - - # Temporary array to store network address and prefix of the configured - # networks. - my @networks; - - # Loop through the array of available network zones. - foreach my $zone (@network_zones) { - # Skip the red network - It never can be part to the home_net! - next if($zone eq "red"); - - # Convert current zone name into upper case. - $zone = uc($zone); +sub read_enabled_disabled_sids_file($) { + my ($file) = @_; - # Generate key to access the required data from the netsettings hash. - my $zone_netaddress = $zone . "_NETADDRESS"; - my $zone_netmask = $zone . "_NETMASK"; + # Temporary hash to store the sids and their state. It will be + # returned at the end of this function. + my %temphash; - # Obtain the settings from the netsettings hash. - my $netaddress = $netsettings{$zone_netaddress}; - my $netmask = $netsettings{$zone_netmask}; + # Open the given filename. + open(FILE, "$file") or die "Could not open $file. $!\n"; - # Convert the subnetmask into prefix notation. - my $prefix = &Network::convert_netmask2prefix($netmask); + # Loop through the file. + while() { + # Remove newlines. + chomp $_; - # Generate full network string. - my $network = join("/", $netaddress,$prefix); + # Skip blank lines. + next if ($_ =~ /^\s*$/); - # Check if the network is valid. - if(&Network::check_subnet($network)) { - # Add the generated network to the array of networks. - push(@networks, $network); - } - } + # Skip coments. + next if ($_ =~ /^\#/); - # Format home net declaration. - my $line = "\"\["; + # Splitt line into sid and state part. + my ($state, $sid) = split(" ", $_); - # Loop through the array of networks. - foreach my $network (@networks) { - # Add the network to the line. - $line = "$line" . "$network"; + # Skip line if the sid is not numeric. + next unless ($sid =~ /\d+/ ); - # Check if the current network was the last in the array. - if ($network eq $networks[-1]) { - # Close the line. - $line = "$line" . "\]\""; + # Check if the sid was enabled. + if ($state eq "enablesid") { + # Add the sid and its state as enabled to the temporary hash. + $temphash{$sid} = "enabled"; + # Check if the sid was disabled. + } elsif ($state eq "disablesid") { + # Add the sid and its state as disabled to the temporary hash. + $temphash{$sid} = "disabled"; + # Invalid state - skip the current sid and state. } else { - # Add "," for the next network. - $line = "$line" . "\,"; + next; } } - # Open file to store the addresses of the home net. - open(FILE, ">$idshomenetfile") or die "Could not open $idshomenetfile. $!\n"; + # Close filehandle. + close(FILE); - # Print yaml header. - print FILE "%YAML 1.1\n"; - print FILE "---\n\n"; + # Return the hash. + return %temphash; +} - # Print notice about autogenerated file. - print FILE "#Autogenerated file. Any custom changes will be overwritten!\n"; +# +## Private function to convert a given rulefile to a category name. +## ( No file extension anymore and if the name contained a dot, it +## would be replaced by a underline sign.) +# +sub _rulefile_to_category($) { + my ($filename) = @_; - # Print the generated and required HOME_NET declaration to the file. - print FILE "HOME_NET:\t$line\n"; + # Splitt the filename into single chunks and store them in a + # temorary array. + my @parts = split(/\./, $filename); - # Close file handle. - close(FILE); + # Return / Remove last element of the temporary array. + # This removes the file extension. + pop @parts; + + # Join together the single elements of the temporary array. + # If these are more than one, use a "underline" for joining. + my $category = join '_', @parts; + # Return the converted filename. + return $category; }