X-Git-Url: http://git.ipfire.org/?p=people%2Fstevee%2Fguardian.git;a=blobdiff_plain;f=modules%2FEvents.pm;h=376438fb25681119ac6df1537e046d8994f01a1d;hp=2f4b561a15d5bfd914620ddb8dcdcf63b015f868;hb=ab7c10eb2c226795115499b3ab2f88cd4f958c0b;hpb=e9c558fec0c7abed46ea56d712686af37b735b12 diff --git a/modules/Events.pm b/modules/Events.pm index 2f4b561..376438f 100644 --- a/modules/Events.pm +++ b/modules/Events.pm @@ -4,7 +4,7 @@ use warnings; use Exporter qw(import); -our @EXPORT_OK = qw(Init CheckAction Update); +our @EXPORT_OK = qw(Init CheckAction GenerateIgnoreList Update); # Hash which stores all supported commands from the queue. my %commands = ( @@ -12,6 +12,8 @@ my %commands = ( 'block' => \&CallBlock, 'unblock' => \&CallUnblock, 'flush' => \&CallFlush, + 'reload' => \&main::Reload, + 'reload-ignore-list' => \&main::ReloadIgnoreList, ); # Hash to store addresses and their current count. @@ -21,6 +23,15 @@ my %counthash = (); # when the block for this address can be released. my %blockhash = (); +# Hash to store user-defined IP addresses and/or subnets which should be +# ignored in case any events should be repored for them. +my %ignorehash = (); + +# Array to store localhost related IP addresses. +# They are always white-listed to prevent guardian from blocking +# any local traffic. +my @localhost_addresses = ("127.0.0.1", "::1"); + # This object will contain the reference to the logger object after calling Init. my $logger; @@ -55,6 +66,15 @@ sub Init (%) { my $module_name = "Guardian::" . $self->{FirewallEngine}; eval "use $module_name; 1" or die "Could not load a module for firewall engine: $self->{FirewallEngine}!"; + # Check if an IgnoreFile has been configured. + if (exists($self->{IgnoreFile})) { + # Call function to handle the ignore mechanism. + &GenerateIgnoreList($self->{IgnoreFile}); + } else { + # Whitelist local addresses. + %ignorehash = &_whitelist_localhost(); + } + # Return the class object. return $self; } @@ -77,8 +97,24 @@ sub CheckAction ($$) { return; } - # XXX - # Check if the given address is valid. + # Check if the given event contains an address. + if ($address) { + # Convert and validate the given address. + my $bin_address = &Guardian::Base::IPOrNet2Int($address); + + # Abort if the given address could not be converted because it is not valid. + unless ($bin_address) { + $logger->Log("err", "Invalid IP address: $address"); + return; + } + + # Check if address should be ignored. + if(&_IsOnIgnoreList($bin_address)) { + # Log message. + $logger->Log("info", "Ignoring event for $address, because it is part of the ignore list."); + return; + } + } # Call required handler. my $error = $commands{$command}->($self, $address, $module, $message); @@ -259,4 +295,220 @@ sub CallUnblock ($) { return undef; } +# +## GenerateIgnoreList function. +# +## This function is responsible for generating/updating the +## IgnoreHash which contains all ignored IP addresses and +## networks. +# +sub GenerateIgnoreList($) { + my $file = shift; + my @include_files; + + # Reset current ignore hash and add + # localhost related IP addresses. + %ignorehash = &_whitelist_localhost(); + + # Check if the given IgnoreFile could be opened. + unless(-e $file) { + $logger->Log("err", "The configured IgnoreFile \($file\) could not be opened. Skipped!"); + return; + } + + # Open the given IgnoreFile. + open (IGNORE, $file); + + # Read-in the file line by line. + while () { + # Skip comments. + next if (/\#/); + + # Skip blank lines. + next if (/^\s*$/); + + # Remove any newlines. + chomp; + + # Check for an include instruction. + if ($_ =~ /^Include_File = (.*)/) { + my $include_file = $1; + + # Check if the parsed include file exists and is read-able. + if (-e $include_file) { + # Add file to the array of files wich will be included. + push(@include_files, $include_file); + + # Write out log message. + $logger->Log("debug", "Addresses from $include_file will be included..."); + } else { + # Log missing file. + $logger->Log("err", "$include_file will not be included. File does not exist!"); + } + } else { + # Check if the line contains a valid single address or network and + # convert it into binary format. Store the result/start and + # end values in a temporary array. + my @values = &Guardian::Base::IPOrNet2Int($_); + + # If the function returned any values, the line contained a valid + # single address or network which successfully has been converted into + # binary format. + if (@values) { + # Assign the array as value to the ignorehash. + $ignorehash{$_} = [@values]; + } else { + # Log invalid entry. + $logger->Log("err", "IgnoreFile contains an invalid address/network: $_"); + + # Skip line. + next; + } + } + } + + # Close filehandle for the IgnoreFile. + close (IGNORE); + + # Check if any files should be included. + if (@include_files) { + # Loop through the array of files which should be included. + foreach my $file (@include_files) { + # Open the file. + open(INCLUDE, $file); + + # Read-in file line by line. + while() { + # Skip any comments. + next if (/\#/); + + # Skip any blank lines. + next if (/^\s*$/); + + # Chomp any newlines. + chomp; + + # Check if the line contains a valid single address or network and + # convert it into binary format. Store the result/start and + # end values in a temporary array. + my @values = &Guardian::Base::IPOrNet2Int($_); + + # If the function returned any values, the line contained a valid + # single address or network which successfully has been converted into + # binary format. + if (@values) { + # Assign the array as value to the ignorehash. + $ignorehash{$_} = [@values]; + } else { + # Log invalid entry. + $logger->Log("err", "$file contains an invalid address/network: $_"); + + # Skip line. + next; + } + } + + # Close filehandle. + close(INCLUDE); + } + } + + # Get amount of current elements in hash. + my $amount = scalar(keys(%ignorehash)); + + # Write out log message. + $logger->Log("debug", "Ignore list currently contains $amount entries."); +} + +# +## Private function to check if an address is part of the Ignore Hash. +# +## This function checks if a passed IP address in binary format (!), +## directly or as part of an ignored network is stored in the ignore hash. +# +sub _IsOnIgnoreList ($) { + my $bin_address = shift; + + # Loop through the ignore hash and grab the stored values. + foreach my $key ( keys %ignorehash ) { + # Dereference values array. + my @values = @{$ignorehash{$key}}; + + # Obtain amount of items for the current value array. + my $items = scalar @values; + + # Whether the amount equals one, the given binary address just + # needs to be compared against a single address. + if ($items eq "1") { + my ($ignored_address) = @values; + + # Simple check if the stored and the given binary address + # are the same. + if ($bin_address eq $ignored_address) { + # The given address is part of the ignore list. + $logger->Log("debug", "Address $key found on the ignore list."); + + # Return "1" (True). + return 1; + } + } + + # If the amount equals two, for passed binary address needs to + # be checked if it is part of the ignored network range. + elsif ($items eq "2") { + my ($first_address, $last_address) = @values; + + # Check if the passed binary address is bigger than + # the first address and smaler than the last address + # (between) the stored network range. + if (($bin_address >= $first_address) && ($bin_address <= $last_address)) { + # The address is part of an ignored network. + $logger->Log("debug", "Address is found inside the ignored network $key."); + + # Return "1" (True). + return 1; + } + + # If the amount is not eighter one or two, the current entry of the ignorehash seems + # to be corrupted. Skip and log it. + } else { + # Write log message about this corruped item in the ignore hash. + $logger->Log("err", "Invalid item in the Ignore Hash: $key - @values"); + + # Skip this element of the ignore hash. + next; + } + } + + # If we got here, the given address is not part of the ignore hash. + # Return nothing (False). + return; +} + +# +## The _whitelist_localhost function. +# +## This tiny private function simple generates and returns a hash which contains +## the clear and binary converted addresses for all array-stored +## (@localhost_addresses) in an ignorelist compatible format. +# +sub _whitelist_localhost () { + my %temphash; + + # Loop through the array of localhost related addresses. + foreach my $address (@localhost_addresses) { + # Validate and convert the addresss into binary format. + my @values = &Guardian::Base::IPOrNet2Int($address); + + # Check if any values are returned. + if (@values) { + # Store the converted binary values in the temporary hash. + $temphash{$address} = [@values]; + } + } + + # Return the temporary hash. + return %temphash; +} + 1;