package Yaala::Parser;

use strict;
use warnings;
use vars qw#%DATAFIELDS#;

use Exporter;
use Yaala::Data::Persistent qw#init#;
use Yaala::Parser::WebserverTools qw#%MONTH_NUMBERS#;

@Yaala::Parser::EXPORT_OK = qw(parse extra %DATAFIELDS);
@Yaala::Parser::ISA = ('Exporter');

our $LASTDATE = init ('$LASTDATE', 'scalar');
                
if (!$$LASTDATE) { $$LASTDATE = 0; }

%DATAFIELDS =
(
	date		=> 'key:date',
	hour		=> 'key:hour',
	
	source_ip	=> 'key',
	dest_ip		=> 'key',
	
	incoming_dev	=> 'key',
	outgoing_dev	=> 'key',

	protocol	=> 'key',

	source_port	=> 'key:numeric',
	destination_port => 'key:numeric',

	icmp_type	=> 'key:numeric',

	mac_address	=> 'key',

	tos		=> 'key',
	prec		=> 'key',
	ttl		=> 'key:numeric',

	packets		=> 'agg',
	size		=> 'agg',
	payload		=> 'agg'
);


# This needs to be done at runtime, since Data uses Setup which relies on
# %DATAFIELDS to be defined  -octo
require Yaala::Data::Core;
import Yaala::Data::Core qw#store#;

my $VERSION = '$Id: Iptables.pm,v 1.4 2003/12/07 15:21:02 octo Exp octo $';
print STDERR $/, __FILE__, ": $VERSION" if ($::DEBUG);

return (1);

sub parse
{
	my $line = shift;

	if ($line =~ m/IN=(\S*) OUT=(\S*) /)
	{
		my $in  = $1 ? $1 : '*unknown*';
		my $out = $2 ? $2 : '*unknown*';
		my $rest = $';

		my $mac = '*unknown*';
		my $src, $dst;
		my $len, $tos, $prec, $ttl, $id;

		my $ip_flags = '';
		my $frag = 0;
		my $opt;
		my $proto_name;
		my $proto_type = 'N/A';

		my $dport = 'N/A';
		my $sport = 'N/A';
		
		if ($rest =~ m/^SRC=([\d\.]+) DST=([\d\.]+) LEN=(\d+) TOS=(0x\S\S) PREC=(0x\S\S) TTL=(\d+) ID=(\d+) /)
		{
			$src = $1;
			$dst = $2;
			$len = $3;
			$tos = unpack ("%02h", $4);
			$prec = $5;
			$ttl = $6;
			$id = $7;
			$rest = $';

			# PPPTTTTM
			#    ^^^^
			# 00011110
			#    1   E
			$tos &= 0x1E;
			if ($tos == 0x00)
			{
				$tos = 'Normal';
			}
			elsif ($tos == 0x10)
			{
				$tos = 'Minimize Delay';
			}
			elsif ($tos == 0x08)
			{
				$tos = 'Maximize Throughput';
			}
			elsif ($tos == 0x04)
			{
				$tos = 'Maximize Reliability';
			}
			else
			{
				$tos = sprintf ("Unknown (%02x)", $tos);
			}
		}
		else
		{
			return (0);
		}

		if ($rest =~ m/^((?:CE )?(?:DF )?(?:MF )?) (?:FRAG:(\d+) )?(?:OPT \(([0-9A-F]+)\) )?PROTO=(\S+) /)
		{
			$ip_flags = $1;
			$frag = defined ($2) ? $2 : 0;
			$opt  = defined ($3) ? $3 : 'none';
			$proto_name = $4;
			$rest = $';
		}
		else
		{
			return (0);
		}

		if (($proto eq 'TCP') or ($proto eq 'UDP'))
		{
			if ($rest =~ m/SPT=(\d+) DPT=(\d+) /)
			{
				$sport = $1;
				$dport = $2;
			}
		}
		
		if ($proto eq 'TCP')
		{
			if ($rest =~ m/RES=0x\S\S ((?:CWR )?(?:ECE )?(?:URG )?(?:ACK )?(?:PSH )?(?:RST )?(?:SYN )?(?:FIN )?)/)
			{
				my $temp = $1;
				$temp =~ s/ $//;
				$proto_type = $temp ? $temp : '*none*';
			}
		}
		elsif ($proto eq 'ICMP')
		{
			my $type = -1;
			
			if ($rest =~ m/TYPE=(\d+) /)
			{
				$type = $1;
			}

			if    ($type ==  0) { $proto_type = 'Echo Reply'; }
			elsif ($type ==  3) { $proto_type = 'Destination Unreachable'; }
			elsif ($type ==  4) { $proto_type = 'Source Quench'; }
			elsif ($type ==  5) { $proto_type = 'Redirect'; }
			elsif ($type ==  8) { $proto_type = 'Echo Request'; }
			elsif ($type == 11) { $proto_type = 'Time Exceeded'; }
			elsif ($type == 12) { $proto_type = 'Parameter Problem'; }
			elsif ($type == 13) { $proto_type = 'Timestamp Request'; }
			elsif ($type == 14) { $proto_type = 'Timestamp Reply'; }
			elsif ($type == 15) { $proto_type = 'Information Request'; }
			elsif ($type == 16) { $proto_type = 'Information Reply'; }
			elsif ($type == 17) { $proto_type = 'Address Mask Request'; }
			elsif ($type == 18) { $proto_type = 'Address Mask Reply'; }
			else { $proto_type = "Unknown type ($type)"; }
		}

			
			

		
		

	if ($line =~ m/IN=\S* OUT=/)
	{
		my ($month, $day, $hour, $minute, $second) = $line =~ m/^(\w{3}) (\d+) (\d\d):(\d\d):(\d\d)/;
		my $year = (localtime ())[5] + 1900;
		$month = $MONTH_NUMBERS{$month};

		{
			my $tmp = int (sprintf ("%04u%02u%02u%02u%02u%02u",
					$year, $month, $day, $hour, $minute, $second));

			if ($tmp < $$LASTDATE)
			{
				print STDERR $/, __FILE__, ": Skipping.. ($tmp < $$LASTDATE)" if ($::DEBUG & 0x0200);
				return (undef);
			}
			else { $$LASTDATE = $tmp; }
		}
		
		my $date = sprintf ("%04u-%02u-%02u", $year, $month, $day);

		my %packet = ();
		while ($line =~ m/([A-Z]+)=(\S+)/g)
		{
			my $key = lc ($1);
			my $val = $2;

			if ($key eq 'len')
			{
				if (defined ($packet{'size'}))
				{
					$packet{'payload'} = $val;
				}
				else
				{
					$packet{'size'} = $val;
				}
			}
			else
			{
				$packet{$key} = $val;
			}
		}

		my %data =
		(
			date		=> $date,
			hour		=> $hour,
			
			source_ip	=> 'n/a',
			dest_ip		=> 'n/a',
			
			incoming_dev	=> '*none*',
			outgoing_dev	=> '*none*',

			protocol	=> '*unknown*',

			source_port	=> 0,
			destination_port => 0,
			icmp_type	=> 0,

			mac_address	=> '*unknown*',

			tos		=> '0x00',
			prec		=> '0x00',
			ttl		=> 0,

			packets		=> 1,
			size		=> 0,
			payload		=> 0
		);

		$data{'source_ip'} = $packet{'src'} if (defined ($packet{'src'}));
		$data{'dest_ip'} = $packet{'dst'} if (defined ($packet{'dst'}));

		$data{'incoming_dev'} = $packet{'in'} if (defined ($packet{'in'}));
		$data{'outgoing_dev'} = $packet{'out'} if (defined ($packet{'out'}));

		$data{'protocol'} = $packet{'proto'} if (defined ($packet{'proto'}));

		$data{'source_port'} = $packet{'spt'} if (defined ($packet{'spt'}));
		$data{'destination_port'} = $packet{'dpt'} if (defined ($packet{'dpt'}));
		$data{'icmp_type'} = $packet{'type'} if (defined ($packet{'type'}));

		$data{'mac_address'} = $packet{'mac'} if (defined ($packet{'mac'}));

		$data{'tos'} = $packet{'tos'} if (defined ($packet{'tos'}));
		$data{'prec'} = $packet{'prec'} if (defined ($packet{'prec'}));
		$data{'ttl'} = $packet{'ttl'} if (defined ($packet{'ttl'}));

		$data{'size'} = $packet{'size'} if (defined ($packet{'size'}));
		$data{'payload'} = $packet{'payload'} if (defined ($packet{'payload'}));
		
		store (\%data);
	}
}

sub extra
{
}
