
/******************************************************************************
*
* gobview - A post-processor for the dump-file generated by gobbler
*           (net-sniffer)
*
* Author: Redproc (= Jacco in real life :)
*
* E-Mail: root@warns.et.tudelft.nl
*         redproc@warns.et.tudelft.nl
*
* I used rdunix.c (distributed with the gobbler package, available through
* anonymous ftp at ftp.et.tudelft.nl) written by Tirza van Rijn as a layer
* to build my routines on.
*
* This program may be freely distributed and modified.
*
* Please send bug reports or anything you would like to mention to above
* e-mail address
*
******************************************************************************/

#include <stdio.h>
#include <stdlib.h>
#include <ctype.h>
#include <string.h>
#include <fcntl.h>
#include <netdb.h>

#define	SIZE_ARRAY(x)	(sizeof(x)/sizeof(x[0]))


typedef struct IP_Lookup
{
	IP_Lookup	*Next;
	char		IP[16];			//	Max:   ???.???.???.??? + '\0'
	char		Name[16];
} IP_Lookup;


IP_Lookup	*IP_Lookup_Cache;


struct Name
{
	unsigned char	Hardware_Address[6];
	char			Name[16];
};

struct Name	Gateways[]=
{
	{ {0xaa, 0x00, 0x04, 0x00, 0x1f, 0x74}, "dutrci1"}
};

struct Protocol
{
	char	Name[8];
	int		Offset, Length;	
	char	ID[4];
	char	Base[8];			//	Base of protocol:
								//	e.g. IP is base of TCP.
	char	PreComment[32], PostComment[32];
	int		Data_PreOffset, Data_PostOffset;		//	e.g. [IP packet [TCP packet] end of IP packet]
													//					/\         /\
													//					||		   ||
													//		  0         100        150              200
													//
													//	PreOffset = 100, PostOffset = 200 - 150 = 50

	void	(*Function) (char *Variable);
};

void	LookUpIP (char *IP)
{
	char			Address[16] = "", Value[5], SystemName[32];
	char			Command[256];

	FILE			*Process_Out;

	int				Index, Return_Read;

	unsigned char	Byte;

	IP_Lookup		*Cache_Window;



	sprintf(Value, "%u.\0", (unsigned char)*IP);
	strcat(Address, Value);
	sprintf(Value, "%u.\0", (unsigned char)*(IP + 1));
	strcat(Address, Value);
	sprintf(Value, "%u.\0", (unsigned char)*(IP + 2));
	strcat(Address, Value);
	sprintf(Value, "%u\0", (unsigned char)*(IP + 3));
	strcat(Address, Value);

	Cache_Window = IP_Lookup_Cache;

	while (Cache_Window != NULL)
	{
		if (strcmp(Cache_Window->IP, Address) == 0)
		{
			/*	Cache hit!	*/

			printf(" (%s)", (char *)Cache_Window->Name);

			return;
		}

		Cache_Window = Cache_Window->Next;
	}


	sprintf(Command, "nslookup %s >/tmp/.process.out\0", (char *)Address);


	system(Command);


	Process_Out = fopen("/tmp/.process.out", "rb");


	Return_Read = 0;

	while (Return_Read < 3)
	{
		fread(&Byte, 1, 1, Process_Out);

		if (Byte == '\n')
		{
			Return_Read++;
		} 
	}

	fread (Value, 1, 1, Process_Out);
	fread (Value + 1, 1, 1, Process_Out);
	fread (Value + 2, 1, 1, Process_Out);
	fread (Value + 3, 1, 1, Process_Out);

	if (strncmp(Value, "Name", 4) == 0)
	{
		/*	Found it!	*/

		fread(&Byte, 1, 1, Process_Out);				//	Byte = ':'

		do
		{
			fread(&Byte, 1, 1, Process_Out);
		}
		while (Byte == ' ');


		Index = 0;

		while (Byte != 10)
		{
			SystemName[Index++] = Byte;

			if (fread(&Byte, 1, 1, Process_Out) != 1)
			{
				break;
			}
		}

		SystemName[Index] = '\0';

		printf(" (%s)", (char *)SystemName);


		/*	Now cache it. First create a new cache entry, and then	*/
		/*	prepend it.												*/

		#ifdef	DEBUG
			printf("Creating new cache entry...\n");
		#endif

		Cache_Window = new IP_Lookup;

		Cache_Window->Next = IP_Lookup_Cache;

		strcpy (Cache_Window->IP, Address);

		#ifdef	DEBUG
			printf("Cache_Window->IP = '%s'\n", Cache_Window->IP); 
		#endif

		strcpy (Cache_Window->Name, SystemName);

		#ifdef	DEBUG
			printf("Cache_Window->Name = '%s'\n", Cache_Window->Name); 
		#endif

		IP_Lookup_Cache = Cache_Window;
	}
	else
	{
		/*	nslookup failed.	*/

		printf( "(?)");
	}


	fclose (Process_Out);
}

void Get_UDP_Service (char *Port)
{
	struct servent	*ServiceEntry;


	ServiceEntry = getservbyport((int)(unsigned short *)*Port, "udp");

	printf("%s", ServiceEntry->s_name);
}

void Get_TCP_Service (char *Port)
{
	struct servent	*ServiceEntry;


	printf("Trying to find tcp service entry.\n");


	ServiceEntry = getservbyport((int)(unsigned short *)*Port, "tcp");

	printf("%s", ServiceEntry->s_name);
}

#define	HEX	0
#define	DEC	1
#define	IP	2
#define	BIN	3

struct Protocol	Protocols[] =
{
	{"IP", -2*8, 2*8, {0x08, 0x00}, "...", "\nFound ", " protocol:\n", 20, 0, NULL},
		{"...", 0, 4, {DEC}, "IP", "Version                 = ", "\n", 0, 0, NULL},
		{"...", 4, 4, {DEC}, "IP", "Header length           = ", "\n", 0, 0, NULL},
		{"...", 1*8, 1*8, {HEX}, "IP", "Sevice type             = ", "\n", 0, 0, NULL},
		{"...", 2*8, 2*8, {DEC}, "IP", "Total length            = ", " bytes \n", 0, 0, NULL},
		{"...", 4*8, 2*8, {HEX}, "IP", "ID                      = ", "\n", 0, 0, NULL},
		{"...", 6*8, 3, {BIN}, "IP", "Fragmentation flags     = ", "\n", 0, 0, NULL},
		{"...", 6*8, 12, {DEC}, "IP", "Fragmentation offset    = ", "\n", 0, 0, NULL},
		{"...", 8*8, 1*8, {DEC}, "IP", "TTL                     = ", "\n", 0, 0, NULL},
		{"...", 9*8, 1*8, {DEC}, "IP", "Protocol                = ", "\n", 0, 0, NULL},
		{"...", 10*8, 2*8, {HEX}, "IP", "Checksum                = ", "\n", 0, 0, NULL},
		{"...", 12*8, 4*8, {IP}, "IP", "Source IP address       = ", "\n", 0, 0, LookUpIP},
		{"...", 16*8, 4*8, {IP}, "IP", "Destination IP address  = ", "\n", 0, 0, LookUpIP},
//		{"...", , , {}, "IP", "", "\n", 0, 0, NULL},
		{"ICMP", 9*8, 1*8, {1}, "IP", "\nFound ", " protocol:\n", 4, 0, NULL},
			{"...", 0*8, 1*8, {DEC}, "ICMP", "Type     = ", "", 0, 0, NULL},
				{"???", 0*8, 1*8, {0}, "ICMP", " (Echo reply)", "\n", 4, 0, NULL},
				{"???", 0*8, 1*8, {3}, "ICMP", " (Destination unreachable)", "\n", 4, 0, NULL},
				{"???", 0*8, 1*8, {4}, "ICMP", " (Source quench)", "\n", 4, 0, NULL},
				{"???", 0*8, 1*8, {5}, "ICMP", " (Redirect)", "\n", 4, 0, NULL},
				{"???", 0*8, 1*8, {8}, "ICMP", " (Echo request)", "\n", 4, 0, NULL},
				{"???", 0*8, 1*8, {11}, "ICMP", " (Time exceeded)", "\n", 4, 0, NULL},
				{"???", 0*8, 1*8, {12}, "ICMP", " (Paramater problem)", "\n", 4, 0, NULL},
				{"???", 0*8, 1*8, {13}, "ICMP", " (Timestamp request)", "\n", 4, 0, NULL},
				{"???", 0*8, 1*8, {14}, "ICMP", " (Timestamp reply)", "\n", 4, 0, NULL},
				{"???", 0*8, 1*8, {15}, "ICMP", " (Info request (obsolete))", "\n", 4, 0, NULL},
				{"???", 0*8, 1*8, {16}, "ICMP", " (Info reply (obsolete))", "\n", 4, 0, NULL},
				{"???", 0*8, 1*8, {17}, "ICMP", " (Address mask request)", "\n", 4, 0, NULL},
				{"???", 0*8, 1*8, {18}, "ICMP", " (Address mask reply)", "\n", 4, 0, NULL},
			{"...", 1*8, 1*8, {DEC}, "ICMP", "Code     = ", " ", 0, 0, NULL},
				{"???", 0*8, 1*8, {0}, "ICMP", "", "\n", 0, 0, NULL},										// Echo reply
				{"???", 0*8, 2*8, {3,0}, "ICMP", "(Network unreachable)", "", 0, 0, NULL},					// Destination unreachable
					{"???", 0*8, 2*8, {3,1}, "ICMP", "(Host unreachable)", "", 0, 0, NULL},
					{"???", 0*8, 2*8, {3,2}, "ICMP", "(Protocol unreachable)", "", 0, 0, NULL},
					{"???", 0*8, 2*8, {3,3}, "ICMP", "(Port unreachable)", "", 0, 0, NULL},
					{"???", 0*8, 2*8, {3,4}, "ICMP", "(Fragmentation needed", " and DF set", 0, 0, NULL},
					{"???", 0*8, 2*8, {3,5}, "ICMP", "(Source route failed)", "", 0, 0, NULL},
					{"???", 0*8, 2*8, {3,6}, "ICMP", "(Destination network unknown)", "", 0, 0, NULL},
					{"???", 0*8, 2*8, {3,7}, "ICMP", "(Destination host unknown)", "", 0, 0, NULL},
					{"???", 0*8, 2*8, {3,8}, "ICMP", "(Source host isolated)", "", 0, 0, NULL},
					{"???", 0*8, 2*8, {3,9}, "ICMP", "(Communication destination", " network prohibited)", 0, 0, NULL},
					{"???", 0*8, 2*8, {3,10}, "ICMP", "(Communication destination", " host prohibited)", 0, 0, NULL},
					{"???", 0*8, 2*8, {3,11}, "ICMP", "(Network unreachable for ", "service)", 0, 0, NULL},
					{"???", 0*8, 2*8, {3,12}, "ICMP", "(Host unreachable for", " service)", 0, 0, NULL},
					{"???", 0, 8, {3}, "ICMP", "", "\n", 0, 0, NULL},			// Just a line feed
				{"???", 0*8, 1*8, {4}, "ICMP", "", "\n", 0, 0, NULL},											// Source quench
				{"???", 0*8, 2*8, {5,0}, "ICMP", "(Redirect for Net ", "(now obsolete))", 0, 0, NULL},			// Redirect
					{"???", 0*8, 2*8, {5,1}, "ICMP", "(Redirect for Host)", "", 0, 0, NULL},
					{"???", 0*8, 2*8, {5,2}, "ICMP", "(Redirect for service", " type and Net)", 0, 0, NULL},
					{"???", 0*8, 2*8, {5,3}, "ICMP", "(Redirect for service", " type and Host)", 0, 0, NULL},
					{"???", 0, 1, {5}, "ICMP", "", "\n", 0, 0, NULL},			// Just a line feed
				{"???", 0*8, 1*8, {8}, "ICMP", "", "\n", 0, 0, NULL},											// Echo request
				{"???", 0*8, 1*8, {11}, "ICMP", "", "\n", 0, 0, NULL},											// Time exceeded
				{"???", 0*8, 1*8, {12}, "ICMP", "", "\n", 0, 0, NULL},											// Paramater problem
				{"???", 0*8, 1*8, {13}, "ICMP", "", "\n", 0, 0, NULL},											// Timestamp request
				{"???", 0*8, 1*8, {14}, "ICMP", "", "\n", 0, 0, NULL},											// Timestamp reply
				{"???", 0*8, 1*8, {15}, "ICMP", "", "\n", 0, 0, NULL},											// Information request
				{"???", 0*8, 1*8, {16}, "ICMP", "", "\n", 0, 0, NULL},											// Information reply
				{"???", 0*8, 1*8, {17}, "ICMP", "", "\n", 0, 0, NULL},											// Address Mask Request
				{"???", 0*8, 1*8, {18}, "ICMP", "", "\n", 0, 0, NULL},											// Address Mask Reply
			{"...", 2*8, 2*8, {HEX}, "ICMP", "Checksum = ", "\n", 0, 0, NULL},
		{"GGP", 9*8, 1*8, {3}, "IP", "\nFound ", " protocol:\n", 0, 0, NULL},
		{"ST", 9*8, 1*8, {5}, "IP", "\nFound ", " protocol:\n", 0, 0, NULL},
		{"TCP", 9*8, 1*8, {6}, "IP", "\nFound ", " protocol:\n", 20, 0, NULL},
			{"...", 0*8, 2*8, {DEC}, "TCP", "Source port        = ", "\n", 0, 0, NULL},
			{"...", 2*8, 2*8, {DEC}, "TCP", "Destination port   = ", "\n", 0, 0, NULL},
			{"...", 4*8, 4*8, {DEC}, "TCP", "Sequence number    = ", "\n", 0, 0, NULL},
			{"...", 8*8, 4*8, {DEC}, "TCP", "Acknowledge number = ", "\n", 0, 0, NULL},
			{"...", 12*8, 1*8, {DEC}, "TCP", "Data offset        = ", "\n", 0, 0, NULL},
			{"...", 13*8, 1*8, {DEC}, "TCP", "Flags              = ", "\n", 0, 0, NULL},
			{"...", 14*8, 2*8, {DEC}, "TCP", "Window             = ", "\n", 0, 0, NULL},
			{"...", 16*8, 2*8, {HEX}, "TCP", "Checksum           = ", "\n", 0, 0, NULL},
			{"...", 18*8, 2*8, {HEX}, "TCP", "Urgent pointer     = ", "\n", 0, 0, NULL},
		{"UCL", 9*8, 1*8, {7}, "IP", "\nFound ", " protocol:\n", 0, 0, NULL},
		{"EGP", 9*8, 1*8, {8}, "IP", "\nFound ", " protocol:\n", 0, 0, NULL},
		{"IGP", 9*8, 1*8, {9}, "IP", "\nFound ", " protocol:\n", 0, 0, NULL},
		{"UDP", 9*8, 1*8, {17}, "IP", "\nFound ", " protocol:\n", 8, 0, NULL},
			{"...", 0*8, 2*8, {DEC}, "UDP", "Source port      = ", "\n", 0, 0, NULL},
			{"...", 2*8, 2*8, {DEC}, "UDP", "Destination port = ", "\n", 0, 0, NULL},
			{"...", 4*8, 2*8, {DEC}, "UDP", "Length           = ", "\n", 0, 0, NULL},
			{"...", 6*8, 2*8, {HEX}, "UDP", "Checksum         = ", "\n", 0, 0, NULL},
	{"ARP", -2*8, 2*8, {0x08, 0x06}, "...", "\nFound ", " frame:\n", 0, 0, NULL},
	{"RARP", -2*8, 2*8, {0x80, 0x35}, "...", "\nFound ", " frame:\n", 0, 0, NULL},
//	{"", , , {}, ""},
};


#define	NOTHING_FOUND	0
#define	PROTOCOL_FOUND	1
#define	VAR_FOUND		2


#define REC_FRAME       0xF8        /* Marks start of a frame */
#define BYTE            unsigned char

struct rec_hdr {
    unsigned char type;
    short len;
};

/* Compare DP.H _DPBUF for the first 6 items */
static struct frame {
    short Dev;                      /* Logic dev# [0..DPMAXDEV-1]  */
    unsigned long ClockMs;          /* Timestamp in micro seconds  */
    unsigned short Status;          /* Status bits - internal use  */
    unsigned short Size;            /* Packet length in bytes      */
    BYTE *pBuf;                     /* Pointer to packet's content */
    struct frame *pNext;            /* Pointer - internal use      */
    BYTE DestAddr [6];              /* Packet destination address  */
    BYTE SrcAddr [6];               /* Packet source address       */
    BYTE PacketType [2];            /* Protocol type               */
    BYTE Data[1600];                /* Packet data contents        */
};


int ReadByteFromFile (FILE *file, BYTE *b)
{
    return ((fread(b, 1, 1, file) == 1) ? 0 : EOF);
}

int ReadIntFromFile (FILE *file, short *i)
{
    BYTE t1, t2;

    if (ReadByteFromFile(file, &t1) == EOF)
        return (EOF);
    if (ReadByteFromFile(file, &t2) == EOF)
        return (EOF);
    *i = (t2 << 8) | t1;
    return (0);
}

int ReadLongFromFile (FILE *file, long *l)
{
    BYTE t1, t2, t3, t4;

    if (ReadByteFromFile(file, &t1) == EOF)
        return (EOF);
    if (ReadByteFromFile(file, &t2) == EOF)
        return (EOF);
    if (ReadByteFromFile(file, &t3) == EOF)
        return (EOF);
    if (ReadByteFromFile(file, &t4) == EOF)
        return (EOF);
    *l = (t4 << 24) | (t3 << 16) | (t2 << 8) | t1;
    return (0);
}

void hexdump (BYTE *Data, unsigned short Length, int Indent)
{
	int i, j;
	int c;
	int	Space;

	#ifdef	DEBUG
		printf("Hex dumping %u bytes at $%x\n", Length, Data);
	#endif


	for (Space = 0; Space < Indent; Space++)
	{
		printf(" ");
	}

    for (i=0;i<(int)Length;i++)
	{
		printf ("%02x ", Data[i]);
		if ((i & 15) == 15)
		{
			for (j=i-15;j<=i;j++)
			{
				c = (int) Data[j];
				if (c >= ' ' && c <= '~')
					putchar (c);
				else
					putchar ('.');
			}
            printf("\n");

			for (Space = 0; Space < Indent; Space++)
			{
				printf(" ");
			}
		}
    }
    for (i=(int)Length & 15;i<16;i++)
        fputs("   ", stdout);
    for (;j<(int)Length;j++)
    {
        c = (int) Data[j];
		if (c >= ' ' && c <= '~')
			putchar (c);
		else
			putchar ('.');
    }
    printf("\n");
}

void HandlePacket(unsigned int, unsigned int, char *, unsigned int);

struct frame buf;


int main(int argc, char *argv[])
{
    int t = 1;
    FILE *dumpfile;
    struct rec_hdr hdr;

	unsigned int	Indent, NameIndex, Index;


    if (argc == 2)
        dumpfile = fopen(argv[1], "r");
    else
        dumpfile = fopen("netcapt.dmp", "r");
    if (dumpfile != NULL)
    {

		/*	Try to read the config file 'process.conf' which contains the	*/
		/*	IP <-> Name table built so far. This is used as a cache for		*/
		/*	lookup using nslookup (which is slow). This way when a IP		*/
		/*	address is not in the cache, it's looked up once, and next		*/
		/*	time, it'll be a cache hit.										*/
		/*	Hmm, I tested a bit, and with the cache implemented the lookup	*/
		/*	is a LOT faster (surprise, surprise :). Building the cache		*/
		/*	everytime process is started is practically as fast as reading	*/
		/*	a cache file and writing it at the end, so I just build the		*/
		/*	cache dynamically: there's no file 'process.conf'.				*/


		IP_Lookup_Cache = NULL;


        while ((ReadByteFromFile(dumpfile, &hdr.type) == 0) &&
               (ReadIntFromFile(dumpfile, &hdr.len) == 0))
        {
            if (hdr.type == REC_FRAME)
            {
                if ((ReadIntFromFile (dumpfile, &buf.Dev) == 0) &&
                    (ReadLongFromFile (dumpfile, (long int *)&buf.ClockMs) == 0) &&
                    (ReadIntFromFile (dumpfile, (short int *)&buf.Status) == 0) &&
                    (ReadIntFromFile (dumpfile, (short int *)&buf.Size) == 0) &&
                    (fread(&buf.pBuf, sizeof(buf.pBuf), 1, dumpfile) == 1) &&
                    (fread(&buf.pNext, sizeof(buf.pNext), 1, dumpfile) == 1) &&
                    (fread(&buf.DestAddr, sizeof(BYTE), 6, dumpfile) == 6) &&
                    (fread(&buf.SrcAddr, sizeof(BYTE), 6, dumpfile) == 6) &&
                    (fread(&buf.PacketType, sizeof(BYTE), 2, dumpfile) == 2) &&
                    (fread(&buf.Data, sizeof(BYTE), (buf.Size-(6+6+2)), dumpfile) == (buf.Size-(6+6+2))))
                {
                    printf("ETHERNET FRAME #%d\n", t++);
                    printf("Frame length = %d\n", hdr.len);
//                    printf("Logic device # = %d\n", buf.Dev);
                    printf("Timestamp (in us): %d:%02d:%02d\n", (int)((buf.ClockMs / 1000000L) % 1000),
                            (int)((buf.ClockMs / 1000L) % 1000), (int)(buf.ClockMs % 1000));
//                    printf("Status %d\n", buf.Status);
                    printf("Packet length (in bytes) = %d\n", buf.Size);

                    printf("Destination address: %02x:%02x:%02x:%02x:%02x:%02x",
                            buf.DestAddr[0], buf.DestAddr[1],
                            buf.DestAddr[2], buf.DestAddr[3],
                            buf.DestAddr[4], buf.DestAddr[5]);
		
	
			for (Index = 0; Index < SIZE_ARRAY(Gateways); Index++)
			{
				#ifdef	DEBUG
					printf("Checking if hardware address is a gateway: ");
				#endif

				for (NameIndex = 0; NameIndex < 6; NameIndex++)
				{
					#ifdef	DEBUG
						printf("%u / %u\n", Gateways[Index].Hardware_Address[NameIndex], buf.DestAddr[NameIndex]);
					#endif

					if (Gateways[Index].Hardware_Address[NameIndex] != buf.DestAddr[NameIndex])
					{
						break;
					}
				}
			
				if (NameIndex > 5)
				{
					printf(" (Gateway %s)", (char *)Gateways[Index].Name);

					break;
				}
			}

			if (NameIndex < 6)
			{
				/*	Not a gateway.	*/

				LookUpIP((char *)(buf.Data + 16));
			}

			printf("\n");


                    printf("Source address: %02x:%02x:%02x:%02x:%02x:%02x",
                            buf.SrcAddr[0], buf.SrcAddr[1],
                            buf.SrcAddr[2], buf.SrcAddr[3],
                            buf.SrcAddr[4], buf.SrcAddr[5]);
	
			for (Index = 0; Index < SIZE_ARRAY(Gateways); Index++)
			{
				#ifdef	DEBUG
					printf("Checking if hardware address is a gateway: ");
				#endif

				for (NameIndex = 0; NameIndex < 6; NameIndex++)
				{
					#ifdef	DEBUG
						printf("%u / %u\n", Gateways[Index].Hardware_Address[NameIndex], buf.SrcAddr[NameIndex]);
					#endif

					if (Gateways[Index].Hardware_Address[NameIndex] != buf.SrcAddr[NameIndex])
					{
						break;
					}
				}
			
				if (NameIndex > 5)
				{
					printf(" (Gateway %s)", (char *)Gateways[Index].Name);

					break;
				}
			}

			if (NameIndex < 6)
			{
				/*	Not a gateway.	*/

				LookUpIP((char *)(buf.Data + 12));
			}

			printf("\n");

                    printf("Protocol type: %02x%02x\n", buf.PacketType[0], buf.PacketType[1]);
	
			for (Index = 0; Index < SIZE_ARRAY(Protocols); Index++)
			{
				if (strcmp(Protocols[Index].Base, "...") == 0)
				{
					if (strncmp(Protocols[Index].ID, (char *)(buf.Data + (Protocols[Index].Offset >> 3)),
								(Protocols[Index].Length >> 3)) == 0)
					{
						#ifdef	DEBUG
							printf("Main protocol!\n");
						#endif

						printf("%s%s%s",	Protocols[Index].PreComment, (char *)Protocols[Index].Name,
											Protocols[Index].PostComment);


						Indent = 4;

						HandlePacket(Index, Indent, (char *)buf.Data, buf.Size-(6+6+2));
					}
				}
			}


                   printf("\n\n\n");
                }
            }
            else
			{
				fread(&buf, sizeof(BYTE), (hdr.len-3), dumpfile);
			}
        }
    }
    else
	{
        printf("Can't open dumpfile\n");
	}


    fclose(dumpfile);

	return (0);
}


void HandlePacket (unsigned int BaseIndex, unsigned int Indent, char *Buffer, unsigned int BufferLength)
{
	unsigned int	Index, Space, HandledProtocol = NOTHING_FOUND;


	#ifdef	DEBUG
		printf("\nHandlePacket called with buffer at $%x, length %u\n", Buffer, BufferLength);
	#endif


	for (Index = 0; Index < SIZE_ARRAY(Protocols); Index++)
	{
		if (strcmp(Protocols[BaseIndex].Name, Protocols[Index].Base) == 0)
		{
			/*	Check if it's a variable (Protocol.Name == "...") or a protocol.	*/

			if (strcmp(Protocols[Index].Name, "...") == 0)
			{
				/*	It's a var.	*/

				HandledProtocol |= VAR_FOUND;

				#ifdef	DEBUG
					printf("Var found\n");
				#endif

				for (Space = 0; Space < Indent; Space++)
				{
					printf(" ");
				}

				printf("%s", Protocols[Index].PreComment);

				switch (Protocols[Index].ID[0])
				{
					case DEC:
							switch (Protocols[Index].Length)
							{
								case	1*8:
											printf("%u", (unsigned char)*(Buffer + (Protocols[Index].Offset >> 3)));

											break;
								case	2*8:
											printf("%u", ( (unsigned char)*(Buffer + (Protocols[Index].Offset >> 3))*256 +
															(unsigned char)*(Buffer + (Protocols[Index].Offset >> 3) + 1) ));

											break;

								default:
										unsigned long int	Dec = 0;
										int					Length, Offset;

										Length = Protocols[Index].Length;
										Offset = Protocols[Index].Offset;

										#ifdef	DEBUG
											printf("data = 0x%x\n", (unsigned char)Buffer[Offset >> 3]);
										#endif

										while (Length > 0)
										{
											#ifdef	DEBUG
												printf("Data at offset = %u, length = %u\n", Offset, Length);
											#endif


											if ( ( ((unsigned char)Buffer[Offset >> 3]) & (1 << (7 - (Offset & 0x07))) ) != 0)
											{
												#ifdef	DEBUG
													printf(" 1");
												#endif

												Dec += 1 << (Length - 1);
											}
											#ifdef	DEBUG
												else
												{
													printf(" 0");
												}
											#endif


											Offset++;
											Length--;
										}

										printf("%u", Dec);

										break;
							}

							break;
					case IP:
							printf("%u.", (unsigned char)*(Buffer + (Protocols[Index].Offset >> 3)));
							printf("%u.", (unsigned char)*(Buffer + (Protocols[Index].Offset >> 3) + 1));
							printf("%u.", (unsigned char)*(Buffer + (Protocols[Index].Offset >> 3) + 2));
							printf("%u", (unsigned char)*(Buffer + (Protocols[Index].Offset >> 3) + 3));

							break;

					case HEX:
/*							printf("0x");

							for (Space = 0; Space < (Protocols[Index].Length >> 3); Space++)
							{
								printf("%02x", (unsigned char)Buffer[(Protocols[Index].Offset >> 3) + Space]);
							}

							break;
*/
							unsigned long int	Hex = 0;
							int					Length, Offset;

							Length = Protocols[Index].Length;
							Offset = Protocols[Index].Offset;


							while (Length > 0)
							{

								if ( ( ((unsigned char)Buffer[Offset >> 3]) & (1 << (7 - (Offset & 0x07))) ) != 0)
								{

									Hex += 1 << (Length - 1);
								}

								Offset++;
								Length--;
							}

							printf("0x%x", Hex);

							break;

					case BIN:

							Length = Protocols[Index].Length;
							Offset = Protocols[Index].Offset;


							printf("%%");

							while (Length > 0)
							{

								if ( ( ((unsigned char)Buffer[Offset >> 3]) & (1 << (7 - (Offset & 0x07))) ) != 0)
								{

									printf("1");
								}
								else
								{
									printf("0");
								}

								Offset++;
								Length--;
							}

							break;
				}


				if (Protocols[Index].Function != NULL)
				{
					Protocols[Index].Function(Buffer + (Protocols[Index].Offset >> 3));
				}

				printf("%s", Protocols[Index].PostComment);
			}
			else
			{
				/*	It's a protocol.	*/

				#ifdef	DEBUG
					printf("Testing protocol %s...", Protocols[Index].Name);
				#endif

				if (strncmp(Protocols[Index].ID,
							(char *)(Buffer + ( Protocols[Index].Offset >> 3)),
							(Protocols[Index].Length >> 3)) == 0)
				{
					if (strncmp(Protocols[Index].Name, "???", 3) != 0)
					{
						HandledProtocol |= PROTOCOL_FOUND;

						#ifdef	DEBUG
							printf("and found it!\n");
						#endif

						for (Space = 0; Space < Indent; Space++)
						{
							printf(" ");
						}


						printf("%s%s%s",	Protocols[Index].PreComment, (char *)Protocols[Index].Name,
											Protocols[Index].PostComment);


						HandlePacket(	Index, Indent+4, Buffer + Protocols[BaseIndex].Data_PreOffset,
											BufferLength - Protocols[BaseIndex].Data_PostOffset - 
											Protocols[BaseIndex].Data_PreOffset);
					}
					else
					{
						/*	It's a '???' 'protocol'	*/

						HandledProtocol |= VAR_FOUND;

						printf("%s%s",	Protocols[Index].PreComment, Protocols[Index].PostComment);

					}
				}
			}
		}
	}


	#ifdef	DEBUG
		printf("HandledProtocol = %u\n", HandledProtocol);
	#endif

	if ((HandledProtocol & PROTOCOL_FOUND) != PROTOCOL_FOUND)
	{
		/*	Print data.	*/

		#ifdef	DEBUG
			printf("Printing data, no sub-protocol found:");
		#endif

		for (Space = 0; Space < Indent; Space++)
		{
			printf(" ");
		}

		printf("Encapsulated data:\n");

		hexdump((BYTE *)Buffer + Protocols[BaseIndex].Data_PreOffset,
				BufferLength - Protocols[BaseIndex].Data_PostOffset -
				Protocols[BaseIndex].Data_PreOffset, Indent + 1 + 4);
	}

	/*	Print data.	*/

	if (Protocols[Index].Data_PostOffset > 0)
	{
		#ifdef	DEBUG
			printf("Printing data:");
		#endif

		for (Space = 0; Space < Indent; Space++)
		{
			printf(" ");
		}

		printf("Data: \n");

		hexdump((BYTE *)Buffer + BufferLength - Protocols[Index].Data_PostOffset,
				Protocols[Index].Data_PostOffset, Indent + 1);
	}

	#ifdef	DEBUG
		printf("RETURN\n");
	#endif
}
