#!/usr/bin/perl -w

# $Id: parse_tcpshow.pl,v 1.8 2006/09/29 11:37:23 mtsouk Exp $
#
# Please note that this code is
# provided without and guarantees.
#
# Programmer: Mihalis Tsoukalos
# Date: Thursday 10 August 2006
#
# Summary: This Perl script parses tcpshow data.
#
#

use strict;
use Tie::IxHash;

# The input filename
my $input = "";
# A record structure that holds the data
my @record = ();
# The line that we read from the input file
my $line = "";

#
# The following variables hold the useful data
# They are used in function parse_record().
#
my %PACKET_TIME = ();
tie %PACKET_TIME, "Tie::IxHash";
my %TCP_PACKET_TIME = ();
tie %TCP_PACKET_TIME, "Tie::IxHash";
my %SOURCE_PORT_COUNT = ();
tie %SOURCE_PORT_COUNT, "Tie::IxHash";
my %DEST_PORT_COUNT = ();
tie %DEST_PORT_COUNT, "Tie::IxHash";
my %PACKET_TYPE_COUNT = ();
tie %PACKET_TYPE_COUNT, "Tie::IxHash";
my %SOURCE_PORT_TIME = ();
tie %SOURCE_PORT_TIME, "Tie::IxHash";
my %DEST_PORT_TIME = ();
tie %DEST_PORT_TIME, "Tie::IxHash";

die <<Thanatos unless @ARGV;
ussage:
	$0 filename
Thanatos

if ( @ARGV != 1 )
{
	die <<Thanatos
		ussage info:
			Please use exactly 1 argument!
Thanatos
}

# Get the input filename
$input = shift @ARGV;

# Open file for reading
open( INPUT, "< $input" )
 or die "Cannot open file $input: $!\n";

my $i=0;
my $j=0;

while ( defined ($line = <INPUT>) )
{
	chomp $line;

	# Skip lines with -
	if ( $line =~ /^(-)*$/ )
	{
		$j++;
		next;
	}
		
	#
	# A new packet denotes the end of the previous one!
	#
	if ( $line =~ /^Packet/ )
	{
		# Process the packet that has just ended.
		parse_record(@record);
		$i++;
		# Initialize the @record variable.
		@record = ();
	}
	else
	{
		# Add line to @record variable
		push(@record, $line);
	}
}

#
# Also parse the last package!
#
parse_record(@record);

# Close the file
close( INPUT )
 or die "Cannot close file INPUT: $!\n";

my $key = "";


# Open file for reading
open( OUTPUT, "> SOURCE_PORT_COUNT.data" )
 or die "Cannot open file $input: $!\n";
#
# Print the SOURCE_PORT_COUNT structure
#
print "* * * SOURCE_PORT_COUNT data\n";
foreach $key (sort keys %SOURCE_PORT_COUNT)
{
	print OUTPUT $key."\t".$SOURCE_PORT_COUNT{$key}."\n";
}
# Close the file
close( OUTPUT )
 or die "Cannot close file OUTPUT: $!\n";

# Open file for reading
open( OUTPUT, "> DEST_PORT_COUNT.data" )
 or die "Cannot open file $input: $!\n";
#
# Print the DEST_PORT_COUNT structure
#
print "* * * DEST_PORT_COUNT data\n";
foreach $key (sort keys %DEST_PORT_COUNT)
{
	print OUTPUT $key."\t".$DEST_PORT_COUNT{$key}."\n";
}
# Close the file
close( OUTPUT )
 or die "Cannot close file OUTPUT: $!\n";

# Open file for reading
open( OUTPUT, "> PACKET_TYPE_COUNT.data" )
 or die "Cannot open file $input: $!\n";
#
# Print the PACKET_TYPE_COUNT structure
#
print "* * * PACKET_TYPE_COUNT data\n";
foreach $key (sort keys %PACKET_TYPE_COUNT)
{
	print OUTPUT $key."\t".$PACKET_TYPE_COUNT{$key}."\n";
}
# Close the file
close( OUTPUT )
 or die "Cannot close file OUTPUT: $!\n";


# Open file for reading
open( OUTPUT, "> PACKET_TIME.data" )
 or die "Cannot open file $input: $!\n";
#
# Print the PACKET_TIME structure
#
print "* * * PACKET_TIME\n";
foreach $key (keys %PACKET_TIME)
{
	print OUTPUT $key."\t".$PACKET_TIME{$key}."\n";
}
# Close the file
close( OUTPUT )
 or die "Cannot close file OUTPUT: $!\n";


# Open file for reading
open( OUTPUT, "> TCP_PACKET_TIME.data" )
 or die "Cannot open file $input: $!\n";
#
# Print the TCP_PACKET_TIME structure
#
print "* * * TCP_PACKET_TIME\n";
foreach $key (keys %TCP_PACKET_TIME)
{
	print OUTPUT $key."\t".$TCP_PACKET_TIME{$key}."\n";
}
# Close the file
close( OUTPUT )
 or die "Cannot close file OUTPUT: $!\n";

# Open file for reading
open( OUTPUT, "> SOURCE_PORT_TIME.data" )
 or die "Cannot open file $input: $!\n";
#
# Print the SOURCE_PORT_TIME structure
#
print "* * * SOURCE_PORT_TIME\n";
print OUTPUT "Time\tSourcePort\n";
foreach $key (keys %SOURCE_PORT_TIME)
{
	print OUTPUT $PACKET_TIME{$key}."\t".$SOURCE_PORT_TIME{$key}."\n";
}
# Close the file
close( OUTPUT )
 or die "Cannot close file OUTPUT: $!\n";

# Open file for reading
open( OUTPUT, "> DEST_PORT_TIME.data" )
 or die "Cannot open file $input: $!\n";
#
# Print the DEST_PORT_TIME structure
#
print "* * * DEST_PORT_TIME\n";
print OUTPUT "Time\tDestPort\n";
foreach $key (keys %DEST_PORT_TIME)
{
	print OUTPUT $PACKET_TIME{$key}."\t".$DEST_PORT_TIME{$key}."\n";
}
# Close the file
close( OUTPUT )
 or die "Cannot close file OUTPUT: $!\n";

# Open file for reading
open( OUTPUT, "> SOURCE_DEST_PORT.data" )
 or die "Cannot open file $input: $!\n";
#
# Print from SOURCE_PORT_TIME and DEST_PORT_TIME structures
#
print "* * * SOURCE_DEST_PORT\n";
foreach $key (keys %SOURCE_PORT_TIME)
{
	print OUTPUT $SOURCE_PORT_TIME{$key}."\t".$DEST_PORT_TIME{$key}."\n";
}
# Close the file
close( OUTPUT )
 or die "Cannot close file OUTPUT: $!\n";


# Open file for reading
open( OUTPUT, "> SOURCE_DEST_TIME.data" )
 or die "Cannot open file $input: $!\n";
#
# Print from SOURCE_PORT_TIME, DEST_PORT_TIME and
# PACKET_TIME structure
#
print "* * * SOURCE_DEST_TIME\n";
print OUTPUT "Time\tSourcePort\tDestPort\n";
foreach $key (keys %SOURCE_PORT_TIME)
{
	print OUTPUT $PACKET_TIME{$key}."\t";
	print OUTPUT $SOURCE_PORT_TIME{$key}."\t";
	print OUTPUT $DEST_PORT_TIME{$key}."\n";
}
# Close the file
close( OUTPUT )
 or die "Cannot close file OUTPUT: $!\n";


print "Beggining of Record: $i"."\n";
print "Records processed: $j"."\n";

exit 0;

# Parse the input file
#
# # # #
# # # # Sample tcpshow data
# # # #
#
# ---------------------------------------------------------------------------
# Packet 1
# TIME:	14:59:01.547498
# LINK:	08:00:09:61:AA:C9 -> 08:00:09:61:AA:C9 type=0028
#	<*** No decode support for encapsulated protocol ***>
# ---------------------------------------------------------------------------
# Packet 2
# TIME:	14:59:02.108822 (0.561324)
# LINK:	00:C0:4F:A3:58:23 -> 00:00:0C:04:41:BC type=IP
#  IP:	192.168.1.10 -> AS-20144-has-not-REGISTERED-the-use-of-this-prefix
#   hlen=20 TOS=00 dgramlen=51 id=012E
#	MF/DF=0/0 frag=0 TTL=64 proto=UDP cksum=B1AD
# UDP:	port domain -> domain hdr=8 data=23
# DATA:	.*...........aesop.....
# ---------------------------------------------------------------------------
# Packet 169
# TIME:   15:00:15.366830 (0.000364)
# LINK:   00:00:0C:04:41:BC -> 00:60:97:DE:54:36 type=IP
#   IP:   172.16.x.y -> 207.46.x.z hlen=20 TOS=00 dgramlen=40 id=007D
#         MF/DF=0/1 frag=0 TTL=63 proto=TCP cksum=C854
# TCP:    port 1024 -> http seq=3183900830 ack=1274940435
#         hlen=20 (data=0) UAPRSF=010000 wnd=32120 cksum=2C97 urg=0
# DATA:   <No data>
# ---------------------------------------------------------------------------
#
# This function parses each record
# and prints out the useful data
# according to our wills.
#
# Notes: Each record is a netword packet
#        Not all records have the same amount
#        and kind of data
#
sub parse_record
{
	my $LINE = "";
	my $sourcePort = "";
	my $destinationPort = "";
	my $time = "";
	
	foreach $LINE (@record)
	{
		if ( $LINE =~ /^TIME/ )
		{
			my @time = split(/:/, $LINE);
			# Remove spaces
			$time[1] =~ s/ //g;
			# Only get hours and minutes from time.
			$time = $time[1].":".$time[2];
			#
			# Convert time to minutes
			#
			$time = $time[1]*60 + $time[2];
			$PACKET_TIME{$i} = $time;
		}
		elsif ( $LINE =~ /^\s+IP/ )
		{
			#
			#
			# This code is not used in this article
			# but is provided here in case you
			# want to use it elsewhere.
			#
			#
			# Find source and destination IPs
			# if ( $LINE =~ /(\d+\.\d+.\d+\.\d+) -> (\d+\.\d+.\d+\.\d+)/ )
			# {
			#	print $1."\t".$2."\n";
			# }
		}
		elsif ( $LINE =~ /^\s+UDP/ )
		{
			# count an UDP packet.
			if ( defined $PACKET_TYPE_COUNT{'UDP'} )
			{
				$PACKET_TYPE_COUNT{'UDP'} = $PACKET_TYPE_COUNT{'UDP'} + 1;
			}
			else
			{
				$PACKET_TYPE_COUNT{'UDP'} = 1;
			}
		}
		elsif ( $LINE =~ /^ICMP/ )
		{
			# count an ICMP packet.
			if ( defined $PACKET_TYPE_COUNT{'ICMP'} )
			{
				$PACKET_TYPE_COUNT{'ICMP'} = $PACKET_TYPE_COUNT{'ICMP'} + 1;
			}
			else
			{
				$PACKET_TYPE_COUNT{'ICMP'} = 1;
			}

		}
		elsif ( $LINE =~ /^ARP/ )
		{
			# count and ARP packet.
			if ( defined $PACKET_TYPE_COUNT{'ARP'} )
			{
				$PACKET_TYPE_COUNT{'ARP'} = $PACKET_TYPE_COUNT{'ARP'} + 1;
			}
			else
			{
				$PACKET_TYPE_COUNT{'ARP'} = 1;
			}
		}
		elsif ( $LINE =~ /^\s+TCP/ )
		{
			# count a TCP packet.
			if ( defined $PACKET_TYPE_COUNT{'TCP'} )
			{
				$PACKET_TYPE_COUNT{'TCP'} = $PACKET_TYPE_COUNT{'TCP'} + 1;
			}
			else
			{
				$PACKET_TYPE_COUNT{'TCP'} = 1;
			}
			
			#
			# Add an entry to TCP_PACKET_TIME
			#
			$TCP_PACKET_TIME{$i} = $time;
			
			# Find the source and destination ports data.
			if ( $LINE =~ /port/ )
			{
				my @words = split(/\s/,$LINE);
				$sourcePort = $words[6];
				$destinationPort = $words[8];
				
				$SOURCE_PORT_TIME{$i} = $sourcePort;
				$DEST_PORT_TIME{$i} = $destinationPort;

				if ( defined $SOURCE_PORT_COUNT{$sourcePort} )
				{
					$SOURCE_PORT_COUNT{$sourcePort} =
						$SOURCE_PORT_COUNT{$sourcePort} + 1;
				}
				else
				{
					$SOURCE_PORT_COUNT{$sourcePort} = 1;				
				}
				
				if ( defined $DEST_PORT_COUNT{$destinationPort} )
				{
					$DEST_PORT_COUNT{$destinationPort} =
						$DEST_PORT_COUNT{$destinationPort} + 1;
				}
				else
				{
					$DEST_PORT_COUNT{$destinationPort} = 1;				
				}
			}
		}
	}
}