package Guardian::Parser;
use strict;
use warnings;

use Exporter qw(import);

our @EXPORT_OK = qw(IsSupportedParser Parser);

# This hash contains all supported parsers and which function
# has to be called to parse messages in the right way.
my %logfile_parsers = (
	"snort" => \&message_parser_snort,
);

#
## The main parsing function.
#
## It is used to determine which sub-parser has to be used to
## parse the given message in the right way and to return if
## any action should be performed.
#
sub Parser ($$) {
        my ($parser, @message) = @_;

	# If no responsible message parser could be found, just return nothing.
	unless (exists($logfile_parsers{$parser})) {
		return;
	}

	# Call responsible message parser.
	my $action = $logfile_parsers{$parser}->(@message);

	# If the parser successfully parsed the message, an action
	# has been returned.
	if ($action) {
		# Return which action should be performed.
		return "count $action";
	}

	# If the parser was not able to parse the the given message
	# in the right way, return Nothing.
	return;
}

#
## IsSupportedParser function.
#
## This very tiny function checks if a given parser name is available and
## therefore a supported parser.
#
## To perform these check, the function is going to lookup if a key in the
## hash of supported parsers is available
#
sub IsSupportedParser ($) {
	my $parser = $_[0];

	# Check if a key for the given parser exists in the hash of logfile_parsers.
	if(exists($logfile_parsers{$parser})) {
		# Found a valid parser, so return nothing.
		return 1;
	}

	# Return "False" if we got here, and therefore no parser
	# is available.
	return;
}

#
## The Snort message parser.
#
## This subfunction is responsible for parsing sort alerts and determine if
## an action should be performed.
#
## XXX Currently the parser only supports IPv4. Add support for IPv6 at a
## later time.
#
sub message_parser_snort(@) {
	my @message = @_;

	# The name of the parser module.
	my $name = "SNORT";

	# Variable to store the grabbed IP-address.
	my $address;

	# Default returned message in case no one could be grabbed
	# from the snort alert.
	my $message = "An active snort rule has matched and gained an alert.";

	# A snort alert contains multiple lines, loop through all lines
	# to parse the complete alert.
	foreach my $line (@message) {
		# Check Priority Level and skip the alert if it is to low.
		#if ($line =~ /.*\[Priority: (\d+)\].*/) {
		#	return unless($1 < $priority);
		#}

		# Search for a line like xxx.xxx.xxx.xxx -> xxx.xxx.xxx.xxx
		if ($line =~ /(\d+\.\d+\.\d+\.\d+)+ -\> (\d+\.\d+\.\d+\.\d+)+/) {
			# Store the grabbed IP-address.
			$address = $1;
		}

		# Search for a line like xxx.xxx.xxx.xxx:xxx -> xxx.xxx.xxx.xxx:xxx
		elsif ($line =~ /(\d+\.\d+\.\d+\.\d+):\d+ -\> (\d+\.\d+\.\d+\.\d+):\d+/) {
			# Store the obtained IP-address.
			$address = $1;
		}

		# Obtain the reported reason.
		if ($line =~ /.*msg:\"(.*)\".*/) {
			# Store the extracted message.
			$message = $1;
		}
	}

	# Check if at least the IP-address information are obtained from the
	# provided alert.
	if ($address) {
		# Return the extracted values.
		return "$address $name $message";
	}

	# If we got here, the alert could not be parsed correctly, return nothing.
	return;
}

1;
