#!/usr/bin/perl
#
# decode 'debug atm packet interface ATM1/0.1' (Cisco 3600, Version 12.1(5)T7) 
# 
# jwa@jammed.com  17 July 2001  
# http://www.jammed.com/~jwa/hacks/security/cisco/
#
# $Id: catm-clean.pl,v 1.2 2001/08/07 05:10:51 jwa Exp $
#

while ($arg = shift @ARGV)
{
	$dumppacket = 1 if ($arg eq "--dump");
	$timestamp = 1 if ($arg eq "-t");
}	


while ($line = <STDIN>)
{
#	$line =~ tr/\b/V/;
#	$line =~ s/\ --More--\ //g;	# 'terminal length 0' fixes this

	$line =~ s/\r|\n//g;
	$line =~ s/^.*.\dw\dd/0w0d/g;	# takes care of --More-- ...crap

	# debug
	#if ($line !~ /^\dw\dd/) { print "skip [$line]\n"; }	

	next if ($line !~ /^\dw\dd/);

	@pairs = split(" ", $line);
	while ($pair = shift @pairs)
	{
		#print "Pair: $pair - ";
		if (length($pair) == 4) 
		{
			if ($pair =~ /[A-F]|[0-9]/)
			{
				$b1 = substr($pair, 0, 1) . substr($pair, 1, 1);
				$b2 = substr($pair, 2, 1) . substr($pair, 3, 1);

				$d1 = chr (hex($b1));
				$d2 = chr (hex($b2));

				push (@bytes, $d1);
				push (@bytes, $d2);

				#print "$b1 $b1 ";
			}
		}
		elsif (length($pair) == 2)
		{
			if ($pair =~ /[A-F]|[0-9]/)
			{
				$b1 = substr($pair, 0, 1) . substr($pair, 1, 1);
				$d1 = chr (hex($b1));
				push (@bytes, $d1);
			 	#print "$b1 - ";
			}
		}
		else
		{
			#print "reject";
			#if (!$printrej{$pair})
			#{
				#print STDERR "REJECTED $pair [$line]\n" ;
		#		$printrej{$pair} = 1;
		#	}
		}
		#print "\n";
	}
	#print "\n--\nbytes now:\n";
	#@b = @bytes;
	#while ($byte = shift @b) { printf "%.2x ", ord($byte); }; print "\n--\n";
	if ($line =~ /^\dw\dd: ATM1/)
	{
		#print "Packet:\n";
		while (@bytes)
		{
			$byte = shift @bytes;
			#printf "%.2x ", ord($byte);
			push(@data, $byte);
		}
		#print "\n--\n";
		decode(@data);
		undef @data;
	}
#	print STDERR ".";
}


# linger

while (@bytes)
{
	$byte = shift @bytes;
	#printf "%.2x ", ord($byte);
	push(@data, $byte);
}
decode(@data);
exit(0);


sub decode
{
	my (@data) = @_;
	my ($pos) = 0;
	my ($output);

	#print "decode " . scalar(@data) . " bytes\n";
	#printf "%5d %.2x\n", $pos, ord($data[$pos]);

	$output = time . " " if ($timestamp);



	if (ord($data[0]) != 0x45)
	{
		printf "Unknown type: %.2x%.2x\n", ord($data[0]), ord($data[1]);
		$buf = join("", @data);
		$output .= "\n" . hexdump($buf);
		print "\n";
		return;
	}	

	#print "Match at $pos - ";
	#printf "Bytes: %.2x%.2x %.2x%.2x\n", ord($data[$pos]), ord($data[$pos+1]), ord($data[$pos+2]), ord($data[$pos+3]),

	#print "pos: $pos\n";
	$len = unpack("n", $data[$pos+2] . $data[$pos+3]);

	$ttl = ord($data[$pos+8]);
	$proto = ord($data[$pos+9]);

	$a = $data[$pos+12];
	$b = $data[$pos+13];
	$c = $data[$pos+14];
	$d = $data[$pos+15];

	$srcip = ord($a) . "." . ord($b) . "." . ord($c) . "." . ord($d);
	$a = $data[$pos+16];
	$b = $data[$pos+17];
	$c = $data[$pos+18];
	$d = $data[$pos+19];

	$dstip = ord($a) . "." . ord($b) . "." . ord($c) . "." . ord($d);

	$output .= sprintf "L:%-3d P:%-3d T:%-3d  ",
		$len, $proto, $ttl;

		

	if (($proto == 6) || ($proto == 17) || ($proto == 1))
	{
		if ($proto == 1)
		{
			# icmp
			$srcport = ord($data[$pos+20]);
			$dstport = ord($data[$pos+21]);
		}
		else
		{
			# dump udp/tcp port #
			$srcport = unpack("n", $data[$pos+20] . $data[$pos+21]);
			$dstport = unpack("n", $data[$pos+22] . $data[$pos+23]);
		}	
		$output .= sprintf "%s:%d -> %s:%d", $srcip, $srcport, $dstip, $dstport;
	}

	# filter me
       	#return if ($output =~ /216\.99\.218\.161/);

	if ($proto == 6)
	{
		undef $flags;
		$tcp_flags = ord($data[$pos+33]);
		$flags .= "F" if ($tcp_flags & 1);	# umm seems right
		$flags .= "S" if ($tcp_flags & 2);
		$flags .= "R" if ($tcp_flags & 4);
		$flags .= "P" if ($tcp_flags & 8);
		$flags .= "A" if ($tcp_flags & 16);
		$flags .= "U" if ($tcp_flags & 32);
		$output .= " $flags";
	}
	# dump rest of packet, starting at data portion (offset 20)

	if ($dumppacket)
	{	
		my ($buf);
		# make something grepable
		$len = 5000;
		$output .= " ";
		for ($i=0;$i<$len;$i++)
		{
			$x = $data[$pos+$i+20];
			$output .= $x if ((ord($x) > 31) && (ord($x) < 127));
		}

		# do it right
		$buf = join("", @data);
		$output .= "\n" . hexdump($buf);
	}	
			
	# move ptr to end of packet
	# not any more
	#$pos += $i + 20;

	select (STDOUT);$!=1;
	print "$output\n" ;
}


sub hexdump
{
        my ($buf) = @_;
        my ($p, $c, $pc, $str);
        my ($i);
	my ($out);

        for ($i=0;$i<length($buf);$i++)
        {
                $p = substr($buf, $i, 1);
                $c = ord ($p);
                $out .= sprintf "%.2x ", $c;
                $pc++;
                if (($c > 31) && ($c < 127))
                {
                        $str .= $p;
                }
                else
                {
                        $str .= ".";
                }       
                if ($pc == 16)
                {
                        $out .= " $str\n";
                        undef $str;
                        $pc = 0;
                }       
        }
        $out .= "   " x (16 - $pc);
	if ($str ne "")
	{
		$out .= " $str";
		return "$out\n";	# needs \n
	}
	else
	{
		return $out;		# has \n
	}	
}

