#!/bin/sh
#
# Copyright 2003 Sun Microsystems, Inc.  All rights reserved.
# Use is subject to license terms.
#
# Script to summarise the statetable output from SunScreen
#
# This script is not a supported part of SunScreen. Its
# made available to help support personnel diagnose problems
# caused by large statetables without actually having to see
# the output from the statetables command.
#
# Usage:
#
# This command can be run in 2 ways:
# 
# statetable_summary <filename>
#
# Where <filename> contains the output of one of the following:
#
# ssadm lib/statetables
# ssadm lib/nattables
# ssadm lib/screeninfo
#
# Alternatively run without the <filename> argument and the script
# will get state/NAT information from the running system.
#
# Note: For  configurations with large numbers state/NAT tables
# the command may take some time to run, depending on the amount of
# CPU time available to run the script. This could impact performance of
# a production firewall, if in doubt run the statetables or nattables
# commands on the firewall, redirect the output to a file and transfer
# the files to another system and run the script there.
#
# This script does not need the SunScreen software installed to work
# (Unless you want to use the script to gather statistics from the
# running system!)
#
VERSION='statetable_summary 3.1 03/09/16'
SUNSCREENDIR=/usr/lib/sunscreen/
SSADM=$SUNSCREENDIR/lib/ssadm
NATTABLES=$SUNSCREENDIR/lib/nattables
SAVE_STATS=YES
BIGBUCKET=10
VBIGBUCKET=50
TOPLINES=10
DATE=`date '+%a_%d_%m_%T'`
REPORT_DIR=/tmp/SunScreen_statetable_reports/$DATE

EFSTCPSTATETABLE=$REPORT_DIR/efs_tcp_statetable.$$
EFSUDPSTATETABLE=$REPORT_DIR/efs_udp_statetable.$$
EFSIPSTATETABLE=$REPORT_DIR/efs_ip_statetable.$$
SPFTCPSTATETABLE=$REPORT_DIR/spf_tcp_statetable.$$
SPFUDPSTATETABLE=$REPORT_DIR/spf_udp_statetable.$$
SPFIPSTATETABLE=$REPORT_DIR/spf_ip_statetable.$$
NATSTATETABLE=$REPORT_DIR/nat_statetable.$$
TMP15=$REPORT_DIR/NAT_state_table_summary.$$
TMP1=$REPORT_DIR/source_file.$$
SUMMARY_FILE=state_table_summary.$$

# scratch files

define_variables(){

TMP2=$REPORT_DIR/$INST/tmpfiles/tmp2.$$
TMP20=$REPORT_DIR/$INST/tmpfiles/tcp_hasbucket_ksh_script.$$
TMP21=$REPORT_DIR/$INST/tmpfiles/tcp_hashbuckets_interim.$$
TMP22=$REPORT_DIR/$INST/tmpfiles/tcp_number_of_entries_per_bucket.$$
TMP23=$REPORT_DIR/$INST/tmpfiles/tcp_number_of_buckets_larger_than_$BIGBUCKET.$$
TMP231=$REPORT_DIR/$INST/tmpfiles/tcp_number_of_buckets_larger_than_$VBIGBUCKET.$$
TMP24=$REPORT_DIR/$INST/tcp_hashbuckets_sizes_$BIGBUCKET.$$
TMP241=$REPORT_DIR/$INST/tcp_hashbuckets_sizes_$VBIGBUCKET.$$
TMP25=$REPORT_DIR/$INST/tcp_hashbuckets_summary_$BIGBUCKET.$$
TMP251=$REPORT_DIR/$INST/tcp_hashbuckets_summary_$VBIGBUCKET.$$
TMP30=$REPORT_DIR/$INST/tmpfiles/udp_hasbucket_ksh_script.$$
TMP31=$REPORT_DIR/$INST/tmpfiles/udp_hashbuckets_interim.$$
TMP32=$REPORT_DIR/$INST/tmpfiles/udp_number_of_entries_per_bucket.$$
TMP33=$REPORT_DIR/$INST/tmpfiles/udp_number_of_buckets_larger_than_$BIGBUCKET.$$
TMP331=$REPORT_DIR/$INST/tmpfiles/udp_number_of_buckets_larger_than_$VBIGBUCKET.$$
TMP34=$REPORT_DIR/$INST/udp_hashbuckets_sizes_$BIGBUCKET.$$
TMP341=$REPORT_DIR/$INST/udp_hashbuckets_sizes_$VBIGBUCKET.$$
TMP35=$REPORT_DIR/$INST/udp_hashbuckets_summary_$BIGBUCKET.$$
TMP351=$REPORT_DIR/$INST/udp_hashbuckets_summary_$VBIGBUCKET.$$
TMP40=$REPORT_DIR/$INST/tmpfiles/ip_hasbucket_ksh_script.$$
TMP41=$REPORT_DIR/$INST/tmpfiles/ip_hashbuckets_interim.$$
TMP42=$REPORT_DIR/$INST/tmpfiles/ip_number_of_entries_per_bucket.$$
TMP43=$REPORT_DIR/$INST/tmpfiles/ip_number_of_buckets_larger_than_$BIGBUCKET.$$
TMP431=$REPORT_DIR/$INST/tmpfiles/ip_number_of_buckets_larger_than_$VBIGBUCKET.$$
TMP44=$REPORT_DIR/$INST/ip_hashbuckets_sizes_$BIGBUCKET.$$
TMP441=$REPORT_DIR/$INST/ip_hashbuckets_sizes_$VBIGBUCKET.$$
TMP45=$REPORT_DIR/$INST/ip_hashbuckets_summary_$BIGBUCKET.$$
TMP451=$REPORT_DIR/$INST/ip_hashbuckets_summary_$VBIGBUCKET.$$
TMP3=$REPORT_DIR/$INST/tmpfiles/state_tcp_src_addr_port.$$
TMP4=$REPORT_DIR/$INST/tmpfiles/state_tcp_dst_addr_port.$$
TMP5=$REPORT_DIR/$INST/tmpfiles/state_udp_src_addr_port.$$
TMP6=$REPORT_DIR/$INST/tmpfiles/state_udp_dst_addr_port.$$
TMP7=$REPORT_DIR/$INST/tmpfiles/state_ip_src_addr.$$
TMP8=$REPORT_DIR/$INST/tmpfiles/state_ip_dst_addr.$$
TMP9=$REPORT_DIR/$INST/ip_statetable.$$
TMP10=$REPORT_DIR/$INST/tcp_hash_file.$$
TMP11=$REPORT_DIR/$INST/udp_hash_file.$$
TMP12=$REPORT_DIR/$INST/duplicate_tcp_state.$$
TMP13=$REPORT_DIR/$INST/duplicate_udp_state.$$
REPORT=$REPORT_DIR/$INST/$SUMMARY_FILE
TMP16=$REPORT_DIR/$INST/tmpfiles/state_tcp_dest_port.$$
TMP17=$REPORT_DIR/$INST/tmpfiles/state_udp_dest_port.$$
TMP18=$REPORT_DIR/$INST/tmpfiles/tcp_source_addresses_for_badports.$$
TMP19=$REPORT_DIR/$INST/tmpfiles/udp_source_addresses_for_badports.$$


cat /dev/null > $TMP2
cat /dev/null > $TMP20
cat /dev/null > $TMP21
cat /dev/null > $TMP22
cat /dev/null > $TMP23
cat /dev/null > $TMP231
cat /dev/null > $TMP24
cat /dev/null > $TMP241
cat /dev/null > $TMP25
cat /dev/null > $TMP251
cat /dev/null > $TMP30
cat /dev/null > $TMP31
cat /dev/null > $TMP32
cat /dev/null > $TMP33
cat /dev/null > $TMP331
cat /dev/null > $TMP34
cat /dev/null > $TMP341
cat /dev/null > $TMP35
cat /dev/null > $TMP351
cat /dev/null > $TMP40
cat /dev/null > $TMP41
cat /dev/null > $TMP42
cat /dev/null > $TMP43
cat /dev/null > $TMP431
cat /dev/null > $TMP44
cat /dev/null > $TMP441
cat /dev/null > $TMP45
cat /dev/null > $TMP451
cat /dev/null > $TMP3
cat /dev/null > $TMP4
cat /dev/null > $TMP5
cat /dev/null > $TMP6
cat /dev/null > $TMP7
cat /dev/null > $TMP8
cat /dev/null > $TMP9
cat /dev/null > $TMP10
cat /dev/null > $TMP11
cat /dev/null > $TMP12
cat /dev/null > $TMP13
cat /dev/null > $REPORT
cat /dev/null > $TMP15
cat /dev/null > $TMP16
cat /dev/null > $TMP17
cat /dev/null > $TMP18
cat /dev/null > $TMP19

}

tidy_up(){

if [ "$SAVE_STATS" != "YES" ]
	then echo "Removing $REPORT_DIR"
	rm -rf $REPORT_DIR
fi


}

create_empty_files(){

# create empty files

cat /dev/null > $EFSTCPSTATETABLE
cat /dev/null > $EFSUDPSTATETABLE
cat /dev/null > $EFSIPSTATETABLE
cat /dev/null > $SPFTCPSTATETABLE
cat /dev/null > $SPFUDPSTATETABLE
cat /dev/null > $SPFIPSTATETABLE
cat /dev/null > $NATSTATETABLE
cat /dev/null > $TMP15

}

long_line_tip(){

echo "You may have just got an error that looks like this:

Parsing out IP state entries (ROUTING instance)
nawk: input record \`        translations...' too long
 input record number 81826
 source line number 1

This is caused by very long lines in the source file, these lines
are too long for nawk to process. Typically the source file was
a screeninfo file, in certain configurations screeninfo can
create very long lines, but these lines are nothing to do with
the state or NAT information this script is trying to process.

Suggested fix:

Delete offending lines from source file and try again!

EG:

cat source_file | sed '/translations.../d' >source_file.fixed

or

cat source_file | sed '81826d' >source_file.fixed

You may have to perform this operation several times.



"

}

check_process(){

# No point reporting if the statetable
# does not exist

process='NO'
if [ -s $TCPSTATETABLE ]
	then process='yes'
fi
if [ -s $UDPSTATETABLE ]
	then process='yes'
fi
if [ -s $IPSTATETABLE ]
	then process='yes'
fi

}

#
# parse_screeninfo()
#
# This function pulls the TCP / UDP / IP and NAT statetables
# from a screeninfo output and puts each one in a separate file
#

parse_screeninfo(){

nawk '

BEGIN{ spf=0; efs=0; tcpefs=0; tcpspf=0; udpspf=0; ipspf=0; udpefs=0; ipefs=0; nat=0;}

function printentry(line) {
	firstchar=(substr(line,1,1))
	if( 0 <= firstchar && firstchar <= 9)
		return 1
	else
		return 0

}

{

	if($1 == "EFS/ADMIN" && (substr($2,1,8) == "instance")) {
		efs = 1
		spf = 0
		nat = 0
	}
	if($1 == "SPF" && (substr($2,1,8) == "instance")) {
		efs = 0
		spf = 1
		nat = 0
	}
	if($1 == "NAT" && (substr($2,1,5) == "STATE")) {
		efs = 0
		spf = 0
		nat = 1
		print "Parsing out NAT state entries"
	}
	if(substr($1,1,3) == "***") {
		efs = 0
		spf = 0
		nat = 0
	}
	if(efs) {
		if($1 == "TCP" && (substr($2,1,5) == "STATE")) {
			udpefs = 0
			ipefs = 0
			tcpspf = 0
			udpspf = 0
			ipspf = 0
			nat = 0
			tcpefs = 1
			print "Parsing out TCP state entries (ROUTING instance)"
		}
		if($1 == "UDP" && (substr($2,1,5) == "STATE")) {
			tcpefs = 0
			ipefs = 0
			tcpspf = 0
			udpspf = 0
			ipspf = 0
			nat = 0
			udpefs = 1
			print "Parsing out UDP state entries (ROUTING instance)"
		}
		if($1 == "IP" && (substr($2,1,5) == "STATE")) {
			tcpefs = 0
			udpefs = 0
			tcpspf = 0
			udpspf = 0
			ipspf = 0
			nat = 0
			ipefs = 1
			print "Parsing out IP state entries (ROUTING instance)" 
		}
		if(tcpefs) 
			if(printentry($0))
				print $0 >>"'"$EFSTCPSTATETABLE"'"
		if(udpefs)
			if(printentry($0))
				print $0 >>"'"$EFSUDPSTATETABLE"'"
		if(ipefs)
			if(printentry($0))
				print $0 >>"'"$EFSIPSTATETABLE"'"
	}
	if(spf) {
		if($1 == "TCP" && (substr($2,1,5) == "STATE")) {
			tcpefs = 0
			udpefs = 0
			ipefs = 0
			udpspf = 0
			ipspf = 0
			nat = 0
			tcpspf = 1
			print "Parsing out TCP state entries (STEALTH instance)"
		}
		if($1 == "UDP" && (substr($2,1,5) == "STATE")) {
			tcpefs = 0
			udpefs = 0
			ipefs = 0
			tcpspf = 0
			ipspf = 0
			nat = 0
			udpspf = 1
			print "Parsing out UDP state entries (STEALTH instance)"
		}
		if($1 == "IP" && (substr($2,1,5) == "STATE")) {
			tcpefs = 0
			udpefs = 0
			tcpspf = 0
			udpspf = 0
			ipspf = 0
			nat = 0
			ipspf = 1
			print "Parsing out IP state entries (STEALTH instance)"
		}
		if(tcpspf) 
			if(printentry($0))
				print $0 >>"'"$SPFTCPSTATETABLE"'"
		if(udpspf)
			if(printentry($0))
				print $0 >>"'"$SPFUDPSTATETABLE"'"
		if(ipspf)
			if(printentry($0))
				print $0 >>"'"$SPFIPSTATETABLE"'"
	}
	if(nat) 
		if(printentry($0))
			print $0 >>"'"$NATSTATETABLE"'"

}


' <$1

if [ "$?" != "0" ]
	then echo "Parsing of $1 failed!"
	echo "Exiting."
	long_line_tip
	exit 2
fi
}

#
# Next 3 functions for nice formatting of log files
#

underline(){
        echo
        echo $1 | nawk '{for( num=$1 ; num > 0 ; num--)printf("=")}'
        echo "\n\n"
}

header(){
        echo "\n\n$1\c"
        length=`echo $1 | wc -c`
        underline $length

}

subheader(){

	echo "$1" | awk '{printf("%s\t\t%s\t\t%s\t\t%s\n\n", $1,$2,$3,$4)}'
}

#
# If the user does not specify a file with the screeninfo in
# then get it from the live system
#

get_statetable(){

# Check SunScreen installed !

if [ ! -f $SSADM ]
	then echo "Unable to find $SSADM"
	echo "SunScreen does not appear to be installed on this system."
	exit 1
fi
$SSADM lib/statetables >$TMP1
echo "\n****************************\n" >>$TMP1

if [ ! -f $NATTABLES ]
	then echo "Unable to find $NATTABLES"
	echo "Can't collect NAT state table"
else
	$NATTABLES >>$TMP1
fi

}

check_root(){

/usr/bin/id | grep root >/dev/null
if [ "$?" != "0" ]
	then echo "Must be root"
	exit 1
fi
}

top(){

cat - | sort | uniq -c | sort -n |tail -$TOPLINES | awk '{printf("%s\t\t%s\t\t%s\t\t%s\n", $1, $2,$3,$4)}'

}

topa(){

cat - |tail -$TOPLINES | awk '{printf("%s\t\t%s\t\t%s\t\t%s\n", $1, $2,$3,$4)}'

}


process_nat(){


header "$DATE SunScreen NAT statetable summary" >>$TMP15

number_entries=`grep "_____Translated" $NATSTATETABLE |wc -l| nawk '{print $1}'`
echo "Total NAT entries: $number_entries" >>$TMP15
number_entries=`grep "TCP" $NATSTATETABLE | wc -l | nawk '{print $1}'`
echo "TCP NAT entries: $number_entries" >>$TMP15
number_entries=`grep "UDP" $NATSTATETABLE | wc -l | nawk '{print $1}'`
echo "UDP NAT entries: $number_entries" >>$TMP15
number_entries=`grep "ICMP" $NATSTATETABLE | wc -l | nawk '{print $1}'`
echo "ICMP NAT entries: $number_entries" >>$TMP15

nawk '
BEGIN {
	tcp_old=0;
	tcp_vold=0
	tcp_neg=0;
	icmp_old=0;
	icmp_vold=0;
	icmp_neg=0;
	udp_old=0;
	udp_vold=0;
	udp_neg=0;
	sport_80=0;
	dport_80=0;
	sport_53=0;
	dport_53=0;
}
# main loop
{

	if ($1 == "TCP") {
		tcp=1
		udp=0
		icmp=0
		trans=0
	}
	if ($1 == "UDP") {
		tcp=0
		udp=1
		icmp=0
		trans=0
	}
	if ($1 == "ICMP") {
		tcp=0
		udp=0
		icmp=1
		trans=0
	}
	if ($1 == "_____Translated") {
		trans=1
	}
	
	if (trans) {
		age = ($6 - $5)
		if (tcp) {
			if (age < 0) {
				tcp_neg++
			}
			else if (age  > 600) {
				tcp_vold++
			}
			else if (age > 20) {
				tcp_old++
			}
			tcp=0
		}
		if (udp) {
			if (age < 0) {
				udp_neg++
			}
			else if (age > 600) {
				udp_vold++
			}
			else if (age > 20) {
				udp_old++
			}
			udp=0
		}
		if (icmp) {
			if (age < 0) {
				icmp_neg++
			}
			else if (age > 60) {
				icmp_vold++
			}
			else if (age > 20) {
			icmp_old++
			}
			icmp=0
		}
	split($2,sport,":")
	if ( sport[2] == "53" )
		sport_53++
	else if (sport[2] == "80")
		sport_80++
	split($4,dport,":")
	if (dport[2] == "53")
		dport_53++
	else if  (dport[2] == "80")
		dport_80++
	trans=0
	}
}
END {
	printf("\n")
	printf("TCP entries older than 10 minues: %d\n", tcp_vold)
	printf("UDP entries older than 10 minues: %d\n", udp_vold)
	printf("ICMP entries older than 60 seconds: %d\n", icmp_vold)
	printf("\n")
	printf("TCP entries older than 60 seconds: %d\n", tcp_old)
	printf("UDP entries older than 60 seconds: %d\n", udp_old)
	printf("ICMP entries older than 20 seconds: %d\n", icmp_old)
	printf("\n")
	printf("TCP entries newer than MAX TTL: %d\n", tcp_neg)
	printf("UDP entries newer than MAX TTL: %d\n", udp_neg)
	printf("ICMP entries newer than MAX TTL: %d\n", icmp_neg)
	printf("\n") 
	printf("%d entries with source port = 53\n", sport_53)
	printf("%d entries with source port = 80\n", sport_80)
	printf("%d entries with destination port = 53\n", dport_53)
	printf("%d entries with destination port = 80\n", dport_80)

}
' <$NATSTATETABLE >>$TMP15


}

do_nat_report(){

header "Top $TOPLINES original source addresses" >>"$TMP15"
subheader "Count SRC_address" >>"$TMP15"

cat $NATSTATETABLE | nawk '{if ($2 == "Original") {
	split($3,src_ip,":")
	printf("%s\n", src_ip[1])
}
}' | top >>"$TMP15"

header "Top $TOPLINES original destination addresses" >>"$TMP15"
subheader "Count DST_address" >>"$TMP15"

cat $NATSTATETABLE | nawk '{if ($2 == "Original") {
	split($5, dst_ip, ":")
	printf("%s\n", dst_ip[1])
}
}' | top >>"$TMP15"

header "Top $TOPLINES translated source addresses" >>"$TMP15"
subheader "Count TRANSLATED_ADDRESS" >>"$TMP15"

cat $NATSTATETABLE | nawk '{if ($1 == "_____Translated") {
	split($2, src_ip, ":")
	printf("%s\n", src_ip[1])
}
}' | top >>"$TMP15"

header "Top $TOPLINES translated destination addresses" >>"$TMP15"
subheader "Count TRANSLATED_ADDRESS" >>"$TMP15"

cat $NATSTATETABLE | nawk '{if ($1 == "_____Translated") {
	split($4, dst_ip, ":")
	printf("%s\n", dst_ip[1])
}
}' | top >>"$TMP15"

}

#
# process_state()
#
# This function gets the statistics from the various
# statetables.
#

process_state(){

header "SunScreen statetable summary ($INST)" >>$REPORT

#
# First the TCP state table
#

awk '
BEGIN	{ tcp_est =0 ;
	tcp_closing = 0;
	tcp_connect = 0;
	tcp_connectack = 0;
	tcp_closed = 0;
	tcp_old = 0;
	tcp_old80 = 0;
	tcp_unknown = 0;
	udp_est =0 ;
	udp_close =0;
	ip_est = 0;
	tcp = 0;
	udp = 0;
	ip = 0;
	dst_port_80_est = 0;
	dst_port_80_close = 0;
	dst_port_53 = 0;
	src_port_53 = 0;
}

{
	print $1 >>"'"$TMP3"'"
	print $2  >>"'"$TMP4"'"
	if($3 == "ESTABLISHED") {
		tcp_est++
		split($2,dstport,":")
		printf("%d\t\t\tESTABLISHED\n", dstport[2]) >>"'"$TMP16"'"
		if (dstport[2] == "80") {
			dst_port_80_est++
			if (($5 - $4) >  600) {
				tcp_old80++
			}
		}
		else
		{
			if (($5 - $4) >  600)
				tcp_old++
		}
	}
	else if ($3 == "CLOSING") {
		tcp_closing++
		split($2, dstport, ":")
		printf("%d\t\t\tCLOSING\n",  dstport[2]) >>"'"$TMP16"'"
		if (dstport[2] == "80")
			dst_port_80_close++
	}
       else if ($3 == "CLOSED")
		tcp_closed++
       else if ($3 == "CONNECTING") {
		split($2, dstport, ":")
		printf("%d\t\t\tCONNECTING\n", dstport[2]) >>"'"$TMP16"'"
		tcp_connect++
	}
       else if ($3 == "CONNECTINGACK") {
		split($2, dstport, ":")
		printf("%d\t\t\tCONNECTINGACK\n", dstport[2]) >>"'"$TMP16"'"
		tcp_connectack++
	}

}

END	{
	printf("TCP sessions: ESTABLISHED %d , CLOSING %d\n", tcp_est , tcp_closing) >>"'"$REPORT"'"
	printf("TCP sessions: CONNECTING %d, CONNECTINGACK %d\n", tcp_connect, tcp_connectack) >>"'"$REPORT"'"
	printf("Number of ESTABLISHED connections to port 80 - %d\n", dst_port_80_est) >>"'"$REPORT"'"
	printf("Number of ESTABLISHED connections idle more than 10 mins (port 80) - %d\n", tcp_old80) >>"'"$REPORT"'"
	printf("Number of ESTABLISHED connections idle more than 10 mins (other ports) - %d\n", tcp_old) >>"'"$REPORT"'"
	printf("Number of CLOSING connections to port 80 - %d\n\n", dst_port_80_close) >>"'"$REPORT"'"
}
' <$TCPSTATETABLE

#
# Now the UDP state table
#

awk '
BEGIN	{ tcp_est =0 ;
	tcp_closing = 0;
	tcp_connect = 0;
	tcp_connectack = 0;
	tcp_closed = 0;
	tcp_old = 0;
	tcp_old80 = 0;
	tcp_unknown = 0;
	udp_est =0 ;
	udp_close =0;
	ip_est = 0;
	tcp = 0;
	udp = 0;
	ip = 0;
	dst_port_80_est = 0;
	dst_port_80_close = 0;
	dst_port_53 = 0;
	src_port_53 = 0;
}

{
	print $1 >>"'"$TMP5"'"
	print $2  >>"'"$TMP6"'"
	udp_est++
	split($1, sport, ":")
	if (sport[2] == "53")
		src_port_53++
	split($2, dport, ":")
	printf("%d\n", dport[2]) >>"'"$TMP17"'"
	if (dport[2] == "53")
		dst_port_53++
}

END	{
	printf("UDP sessions: %d \n", udp_est ) >>"'"$REPORT"'"
	printf("Number of UDP src port 53 - %d\n", src_port_53) >>"'"$REPORT"'"
	printf("Number of UDP dst port 53 - %d\n\n", dst_port_53) >>"'"$REPORT"'"
}
' <$UDPSTATETABLE

#
# Finnaly IP state table
#

awk '
BEGIN	{ tcp_est =0 ;
	tcp_closing = 0;
	tcp_connect = 0;
	tcp_connectack = 0;
	tcp_closed = 0;
	tcp_old = 0;
	tcp_old80 = 0;
	tcp_unknown = 0;
	udp_est =0 ;
	udp_close =0;
	ip_est = 0;
	tcp = 0;
	udp = 0;
	ip = 0;
	dst_port_80_est = 0;
	dst_port_80_close = 0;
	dst_port_53 = 0;
	src_port_53 = 0;
}

{
	print $1 >>"'"$TMP7"'"
	print $2 >>"'"$TMP8"'"
	x = int(substr($0,1,1))
	if(x != "0")	
		ip_est++
}

END	{
	printf("IP sessions:  %d\n\n" , ip_est ) >>"'"$REPORT"'"
}
' <$IPSTATETABLE

}

#
# process_state2()
#
# This function goes through state tables again
# looking for the source IP addresses  that
# created large numbers of state entries to a single
# destiantion port number
# 

process_state2(){

# TCP

for badtcpport in `cat $TMP16 | top | awk '{print $2}'`
	do
awk '

{
	split($2, dstport, ":")
	if (dstport[2] == badport) {
		split($1, srcaddr, ":")
		printf("%s\t\t%s\n", badport, srcaddr[1]) >>"'"$TMP18"'"
	}
}
' badport="$badtcpport" <$TCPSTATETABLE

done

# UDP

for badudpport in `cat $TMP17 | top | awk '{print $2}'`
	do
awk '

{
	split($2, dstport, ":")
	if (dstport[2] == badport) {
		split($1, srcaddr, ":")
		printf("%s\t\t%s\n", badport, srcaddr[1]) >>"'"$TMP19"'"
	}
}
' badport="$badudpport" <$UDPSTATETABLE

done
}

do_report(){

header "Report finished at: `date` " 
echo
echo "For full details see files in $REPORT_DIR"
echo

echo
header "Statetable summary (ROUTING)"
echo
if [ -s $EFSSUMMARY ]
	then cat $EFSSUMMARY
fi
echo
echo
header "Statetable summary (STEALTH)"
echo
if [ -s $SPFSUMMARY ]
	then cat $SPFSUMMARY
fi
echo

header "Statetable summary (NAT)"
echo
if [ -s $TMP15 ]
	then cat $TMP15
fi
echo

}

do_state_report(){

echo "Number of unique source IP addresses (TCP state):      \c" >>"$REPORT"

nawk  -F':' '

{

	print $1
}' <$TMP3 | sort | uniq | wc -l >>"$REPORT"

echo "Number of unique destination IP addresses (TCP state): \c" >>"$REPORT"

nawk -F':' '

{
	print $1 
} ' <$TMP4 | sort | uniq | wc -l >>"$REPORT"

echo "Number of unique source port numbers (TCP state):      \c" >>"$REPORT"

nawk -F':' '
{
	print $2
}'< $TMP3 | sort | uniq | wc -l >>"$REPORT"

echo "Number of unique destination ports (TCP state):        \c" >>"$REPORT"

nawk -F":" '

{
	print $2 
}' <$TMP4 | sort | uniq | wc -l >>"$REPORT"

# UDP

echo "Number of unique source IP addresses (UDP state):      \c" >>"$REPORT"

nawk  -F':' '

{

	print $1
}' <$TMP5 | sort | uniq | wc -l >>"$REPORT"

echo "Number of unique destination IP addresses (UDP state): \c" >>"$REPORT"

nawk -F':' '

{
	print $1 
} ' <$TMP6 | sort | uniq | wc -l >>"$REPORT"

echo "Number of unique source port numbers (UDP state):      \c" >>"$REPORT"

nawk -F':' '
{
	print $2
}'< $TMP5 | sort | uniq | wc -l >>"$REPORT"

echo "Number of unique destination ports (UDP state):        \c" >>"$REPORT"

nawk -F":" '

{
	print $2 
}' <$TMP6 | sort | uniq | wc -l >>"$REPORT"


#IP

echo "Number of unique source addresses (IP state):          \c" >>"$REPORT"

nawk  -F':' '

{
	print $1
}' <$TMP7 | sort | uniq | wc -l >>"$REPORT"

echo "Number of unique destination addresses (IP state):     \c" >>"$REPORT"

nawk  -F':' '

{
	print $1
}' <$TMP8 | sort | uniq | wc -l >>"$REPORT"

# duplicate state table entries

awk '
{
	print $1,$2 
}
' <$TCPSTATETABLE | sort | uniq -c | sort -k1 >$TMP12

#UDP

awk '
{
	print $1,$2
}
' <$UDPSTATETABLE | sort | uniq -c | sort -k1 >$TMP13


header "Top $TOPLINES SRC address / ports (TCP)" >>"$REPORT"
subheader "Count Address/Port" >>"$REPORT"
cat $TMP3 | top >>"$REPORT"

header "Top $TOPLINES DST address / ports (TCP)" >>"$REPORT"
subheader "Count Address/Port" >>"$REPORT"
cat $TMP4 | top >>"$REPORT"

header "Top $TOPLINES DST port numbers (TCP)" >>"$REPORT"
subheader "Count Port State" >>"$REPORT"
cat $TMP16 | top >>"$REPORT"

header "Top $TOPLINES SRC addresses connecting to Top $TOPLINES DST ports (TCP)" >>"$REPORT"
subheader "Count Port IP_address" >>"$REPORT"
cat $TMP18 | top >>"$REPORT"

header "Top $TOPLINES SRC address / ports (UDP)" >>"$REPORT"
subheader "Count Address/Port" >>"$REPORT"
cat $TMP5 | top >>"$REPORT"

header "Top $TOPLINES DST address / ports (UDP)" >>"$REPORT"
subheader "Count Address/Port" >>"$REPORT"
cat $TMP6 | top >>"$REPORT"

header "Top $TOPLINES DST port numbers (UDP)" >>"$REPORT"
subheader "Count Port" >>"$REPORT"
cat $TMP17 | top >>"$REPORT"

header "Top $TOPLINES SRC addresses connecting to Top $TOPLINES DST ports (UDP)" >>"$REPORT"
subheader "Count Port IP_address" >>"$REPORT"
cat $TMP19 | top >>"$REPORT"

header "Top $TOPLINES SRC addresses  (IP)" >>"$REPORT"
subheader "Count Address" >>"$REPORT"
cat $TMP7 | top >>"$REPORT"

header "Top $TOPLINES DST addresses  (IP)" >>"$REPORT"
subheader "Count Address" >>"$REPORT"
cat $TMP8 | top >>"$REPORT"

header "Top $TOPLINES duplicate state entries (TCP)" >>"$REPORT"
subheader "Count Address/Port Address/Port " >>"$REPORT"
cat $TMP12 | topa >>"$REPORT"

header "Top $TOPLINES duplicate state entries (UDP)" >>"$REPORT"
subheader "Count Address/Port Address/Port " >>"$REPORT"
cat $TMP13 | topa >>"$REPORT"

header "HASH Bucket summary" >>"$REPORT"

echo "Number of TCP hash buckets with more than $BIGBUCKET entries\c" >>"$REPORT"
cat $TMP25 | wc -l >>"$REPORT"

echo "Number of TCP hash buckets with more than $VBIGBUCKET entries\c" >>"$REPORT"
cat $TMP251 | wc -l >>"$REPORT"

echo "Number of UDP hash buckets with more than $BIGBUCKET entries\c" >>"$REPORT"
cat $TMP35 | wc -l >>"$REPORT"

echo "Number of UDP hash buckets with more than $VBIGBUCKET entries\c" >>"$REPORT"
cat $TMP351 | wc -l >>"$REPORT"

echo "Number of IP  hash buckets with more than $BIGBUCKET entries\c" >>"$REPORT"
cat $TMP45 | wc -l >>"$REPORT"

echo "Number of IP  hash buckets with more than $VBIGBUCKET entries\c" >>"$REPORT"
cat $TMP451 | wc -l >>"$REPORT"

}

calculate_hash_collisions_tcp(){

# This uses the TCP statetable and generates the hash bucket
# based on the same algorithm used by SunScreen.
# This bit of nawk writes to a file that is run by ksh
# to generate the hashes as I don't know how to do Xor in nawk!

cat $TCPSTATETABLE | sed 's/:/ /g'  | sed 's/\./ /g'| nawk '

{
	printf("let hash=\047(((((%d * 16777216)+(%d * 65536)+(%d * 256) + %d) ^ ((%d * 16777216)+(%d * 65536)+(%d * 256) + %d)) ^ %d ^ %d) & %d)\047\n", $1, $2,$3,$4,$6,$7,$8,$9,$5,$10,16383) >>"'"$TMP20"'"
	printf("print $hash %d.%d.%d.%d:%d %d.%d.%d.%d:%d\n", $1, $2,$3,$4,$5,$6,$7,$8,$9,$10) >>"'"$TMP20"'"
}'

ksh $TMP20 > $TMP21
cat $TMP21 | sort >$TMP21.sorted
cat $TMP21.sorted | nawk '{print $1}' | uniq -c >$TMP22
cat $TMP22 |nawk '{if($1 > bigbucket){print $0}}' bigbucket="$BIGBUCKET" >$TMP23
cat $TMP22 |nawk '{if($1 > bigbucket){print $0}}' bigbucket="$VBIGBUCKET" >$TMP231
for hash in `cat $TMP23 | nawk '{print $2}'`
	do echo "\nEntries for bucket number $hash\n\n" >>$TMP24
	grep "^$hash " $TMP21.sorted >>$TMP24
	echo "\nTotal for bucket number $hash: \c" >>$TMP24
	grep "^$hash " $TMP21.sorted | wc -l >>$TMP24
done

grep "Total" $TMP24 > $TMP25

for hash in `cat $TMP231 | nawk '{print $2}'`
	do echo "\nEntries for bucket number $hash\n\n" >>$TMP241
	grep "^$hash " $TMP21.sorted >>$TMP241
	echo "\nTotal for bucket number $hash: \c" >>$TMP241
	grep "^$hash " $TMP21.sorted | wc -l >>$TMP241
done

grep "Total" $TMP241 > $TMP251

}

calculate_hash_collisions_udp(){

# This uses the UDP statetable and generates the hash bucket
# based on the same algorithm used by SunScreen.
# This bit of nawk writes to a file that is run by ksh
# to generate the hashes as I don't know how to do Xor in nawk!

cat $UDPSTATETABLE | sed 's/:/ /g'  | sed 's/\./ /g'| nawk '

{
	printf("let hash=\047(((((%d * 16777216)+(%d * 65536)+(%d * 256) + %d) ^ ((%d * 16777216)+(%d * 65536)+(%d * 256) + %d)) ^ %d ^ %d) & %d)\047\n", $1, $2,$3,$4,$6,$7,$8,$9,$5,$10,16383) >>"'"$TMP30"'"
	#printf("let hash=\047(((((%d * 256 * 256 * 256)+(%d * 256 * 256)+(%d * 256) + %d) ^ %d ^ ((%d * 256 * 256 * 256)+(%d * 256 * 256)+(%d * 256) + %d)) ^ %d) & %d)\047\n", $1, $2,$3,$4,$5,$6,$7,$8,$9,$10,16383) >>"'"$TMP30"'"
	printf("print $hash %d.%d.%d.%d:%d %d.%d.%d.%d:%d\n", $1, $2,$3,$4,$5,$6,$7,$8,$9,$10) >>"'"$TMP30"'"
}'

ksh $TMP30 > $TMP31
cat $TMP31 | sort >$TMP31.sorted
cat $TMP31.sorted | nawk '{print $1}' | uniq -c >$TMP32
cat $TMP32 |nawk '{if($1 > bigbucket){print $0}}' bigbucket="$BIGBUCKET" >$TMP33
cat $TMP32 |nawk '{if($1 > bigbucket){print $0}}' bigbucket="$VBIGBUCKET" >$TMP331
for hash in `cat $TMP33 | nawk '{print $2}'`
	do echo "\nEntries for bucket number $hash\n\n" >>$TMP34
	grep "^$hash " $TMP31.sorted >>$TMP34
	echo "\nTotal for bucket number $hash: \c" >>$TMP34
	grep "^$hash " $TMP31.sorted | wc -l >>$TMP34
done

grep "Total" $TMP34 > $TMP35

for hash in `cat $TMP331 | nawk '{print $2}'`
	do echo "\nEntries for bucket number $hash\n\n" >>$TMP341
	grep "^$hash " $TMP31.sorted >>$TMP341
	echo "\nTotal for bucket number $hash: \c" >>$TMP341
	grep "^$hash " $TMP31.sorted | wc -l >>$TMP341
done

grep "Total" $TMP341 > $TMP351

}

calculate_hash_collisions_ip(){

# This uses the IP statetable and generates the hash bucket
# based on the same algorithm used by SunScreen.
# This bit of nawk writes to a file that is run by ksh
# to generate the hashes as I don't know how to do Xor in nawk!

cat $IPSTATETABLE | sed 's/\// /g'  | sed 's/\./ /g'| nawk '

{
	printf("let hash=\047(((((%d * 16777216)+(%d * 65536)+(%d * 256) + %d) ^ ((%d * 16777216)+(%d * 65536)+(%d * 256) + %d)) ^ %d) & %d)\047\n", $1, $2,$3,$4,$6,$7,$8,$9,$5,16383) >>"'"$TMP40"'"
	printf("print $hash %d.%d.%d.%d / %d %d.%d.%d.%d\n", $1, $2,$3,$4,$5,$6,$7,$8,$9) >>"'"$TMP40"'"
}'

ksh $TMP40 > $TMP41
cat $TMP41 | sort >$TMP41.sorted
cat $TMP41.sorted | nawk '{print $1}' | uniq -c >$TMP42
cat $TMP42 |nawk '{if($1 > bigbucket){print $0}}' bigbucket="$BIGBUCKET" >$TMP43
cat $TMP42 |nawk '{if($1 > bigbucket){print $0}}' bigbucket="$VBIGBUCKET" >$TMP431
for hash in `cat $TMP43 | nawk '{print $2}'`
	do echo "\nEntries for bucket number $hash\n\n" >>$TMP44
	grep "^$hash " $TMP41.sorted >>$TMP44
	echo "\nTotal for bucket number $hash: \c" >>$TMP44
	grep "^$hash " $TMP41.sorted | wc -l >>$TMP44
done

grep "Total" $TMP44 > $TMP45

for hash in `cat $TMP431 | nawk '{print $2}'`
	do echo "\nEntries for bucket number $hash\n\n" >>$TMP441
	grep "^$hash " $TMP41.sorted >>$TMP441
	echo "\nTotal for bucket number $hash: \c" >>$TMP441
	grep "^$hash " $TMP41.sorted | wc -l >>$TMP441
done

grep "Total" $TMP441 > $TMP451

}

intro(){

echo "Output written to $REPORT_DIR"
echo "$0 - Version $VERSION"
echo "Script started at: `date`"

mkdir -p $REPORT_DIR
header "Report Started: `date`" >$REPORT
create_empty_files

}

# main
# Everything else above is a function !
#

if [ "$1" != "" ]
	then if [ -f $1 ]
		then intro
		cp $1 $TMP1
	else
		echo "Can't open $1"
		exit 1
	fi
	
else
	echo "Getting live information from system"
	check_root
	intro
	get_statetable
fi

parse_screeninfo $TMP1
echo "Processing ROUTING state table ...."
INST='ROUTING'
EFSSUMMARY=$REPORT_DIR/$INST/$SUMMARY_FILE
mkdir -p $REPORT_DIR/$INST
mkdir -p $REPORT_DIR/$INST/tmpfiles
define_variables
TCPSTATETABLE=$EFSTCPSTATETABLE
UDPSTATETABLE=$EFSUDPSTATETABLE
IPSTATETABLE=$EFSIPSTATETABLE
check_process
if [ "$process" = "yes" ]
	then process_state
	process_state2
	calculate_hash_collisions_udp
	calculate_hash_collisions_ip
	calculate_hash_collisions_tcp
	do_state_report
fi
echo "Processing STEALTH state table ...."
INST='STEALTH'
SPFSUMMARY=$REPORT_DIR/$INST/$SUMMARY_FILE
mkdir -p $REPORT_DIR/$INST
mkdir -p $REPORT_DIR/$INST/tmpfiles
define_variables
TCPSTATETABLE=$SPFTCPSTATETABLE
UDPSTATETABLE=$SPFUDPSTATETABLE
IPSTATETABLE=$SPFIPSTATETABLE
check_process
if [ "$process" = "yes" ]
	then process_state
	process_state2
	calculate_hash_collisions_udp
	calculate_hash_collisions_ip
	calculate_hash_collisions_tcp
	do_state_report
fi
if [ -s $NATSTATETABLE ]
	then echo "Processing NAT state table ...."
	process_nat
	do_nat_report
fi

do_report
tidy_up

