#include <stdio.h>
#include <dos.h>

#define MAXETHB 1522
#define MINETHB 59

#define CONNTAB 20

typedef struct {

   unsigned long sip;
   unsigned int sp;
   unsigned long dip;
   unsigned int dp;
   unsigned long expack;
   int state;
   int lru;

   } tcp_connection;

typedef struct {

   unsigned char etha[6];
   unsigned char enam[18];

   } ethtrans;

typedef struct {

   unsigned int port;
   char *name;

   } portmap;

portmap tcpports[] = {
#include "c:/c/tcpport.h"

portmap udpports[] = {
#include "C:/c/udpport.h"

portmap protocols[] = {
#include "C:/c/protocol.h"

portmap ipprotocols[] = {
#include "c:/c/ipprot.h"

int tcpcount, udpcount, procount, ipprocount;
int tcpstart, udpstart, prostart, ipprostart;

ethtrans far *ethtab;

int ethtabs, ethstart;

tcp_connection conn[CONNTAB];

void inittab(tab, length, count, start)

portmap tab[];
int length;
int *count;
int *start;

{

*count = length/sizeof(portmap);
*start = 1;

while ((*start << 1) <= (*count - 1)) *start = *start << 1;

}

char *findtab(val, tab, length, start)

unsigned int val;
portmap tab[];
int length;
int start;

{

int i, up, down, l, v;

i = start;
l = length;
v = val;

up = i >> 1;
down = i | up;

loop:

if(i >= l) goto godown;

if(tab[i].port == v) return tab[i].name;

if(tab[i].port < v) {

   if(up == 0) goto notfound;

   i ^= up;

   down >>= 1;
   up >>= 1;

   goto loop;

   }

godown:

if(down == 0) goto notfound;

i ^= down;

down >>= 1;
up >>= 1;

goto loop;

notfound:

return NULL;

}


void initethtab(file)

FILE *file;

{

int ic, iv, linecnt, charcnt;
unsigned int segp;
ethtrans far *nexteth, far *competh;

linecnt = 0;
charcnt = 0;

loop1:

ic = fgetc(file);

switch (ic) {

   case '\n': linecnt++;
              charcnt = 0;
              goto loop1;

   case EOF : if(charcnt > 0) linecnt++;
              break;

   default:   charcnt++;
              goto loop1;

   }

fseek(file, (long) 0, SEEK_SET);

if((long) linecnt* (long)24 > (long) 65536) {
   puts("Cannot accomodate that many address translations");
   linecnt = (long) 65536/(long) 24;
   }

if(allocmem((linecnt * 24 + 15)/16, &segp) != -1) {
   puts("Error allocating Address Translation Table");
   ethtabs=0;
   return;
   }

ethtab = (ethtrans far *) MK_FP(segp, 0);
nexteth = ethtab;
ethtabs = 0;

loop2:

charcnt = 0;
iv = -1;

loop3:

ic = fgetc(file);

if (ic == EOF) goto sort1;

if ((ic >= '0') && (ic <= '9')) {

   if(iv < 0) {

      iv = ic - '0';

      }

   else {

      iv = (iv << 4) + ic - '0';

      goto putadd;

      }

   }

if ((ic >= 'A') && (ic <= 'F')) {

   if(iv < 0) {

      iv = ic - 'A' + 10;

      }

   else {

      iv = (iv << 4) + ic - 'A' + 10;

      goto putadd;

      }

   }

if ((ic >= 'a') && (ic <= 'f')) {

   if(iv < 0) {

      iv = ic - 'a' + 10;

      }

   else {

      iv = (iv << 4) + ic - 'a' + 10;

      goto putadd;

      }

   }

goto loop3;

skip2:

if( ic == '\n') goto loop2;

ic = fgetc(file);

if(ic == EOF) goto sort1;

goto skip2;

putadd:

nexteth->etha[charcnt] = iv;
charcnt++;
iv = -1;
if (charcnt < 6) goto loop3;

charcnt = 0;

ic = fgetc(file);

if(ic != ' ') goto skip2;

loop4:

ic = fgetc(file);

if (ic == EOF) goto done;

if (ic == '\n') goto fill;

if (charcnt < 17) {

   nexteth->enam[charcnt] = ic;
   charcnt++;
   goto loop4;

   }

nexteth->enam[17] = 0;
nexteth++;
ethtabs++;

if(ethtabs >= linecnt) goto sort1;

skip3:

ic = fgetc(file);

if(ic == EOF) goto sort1;

if(ic == '\n') goto loop2;

goto skip3;

fill:

for(iv = charcnt; iv < 17; iv++) nexteth->enam[iv] = ' ';

nexteth->enam[17] = 0;
nexteth++;
ethtabs++;

if(ethtabs >= linecnt) goto sort1;

goto loop2;

done:

if(charcnt == 0) goto sort1;

for(iv = charcnt; iv < 17; iv++) nexteth->enam[iv] = ' ';

nexteth->enam[17] = 0;
nexteth++;
ethtabs++;

sort1:

if(ethtabs < 2) {
   ethstart = 0;
   return;
   }

linecnt = ethtabs - 1;

sort2:

linecnt--;

if(linecnt < 0) goto sortdone;

charcnt = 0;
nexteth = ethtab;
competh = ethtab;
competh++;

sort3:

for(iv = 0; iv < 6; iv++) {

   if(nexteth->etha[iv] < competh->etha[iv]) goto checknext;
   if(nexteth->etha[iv] > competh->etha[iv]) goto swap;

   }

puts("Duplicate Ethernet Address removed");

nexteth = ethtab + (ethtabs - 1);

for(iv = 0; iv < 6; iv++) competh->etha[iv] = nexteth->etha[iv];

for(iv = 0; iv < 17; iv++) competh->enam[iv] = nexteth->enam[iv];

ethtabs--;

goto sort1;

swap:

for(iv = 0; iv < 6; iv++) {

   ic = competh->etha[iv];
   competh->etha[iv] = nexteth->etha[iv];
   nexteth->etha[iv] = ic;

   }

for(iv = 0; iv < 17; iv++) {

   ic = competh->enam[iv];
   competh->enam[iv] = nexteth->enam[iv];
   nexteth->enam[iv] = ic;

   }

checknext:

if(charcnt >= linecnt) goto sort2;

nexteth++;
competh++;
charcnt++;

goto sort3;

sortdone:

ethstart = 1;

while(ethtabs > (ethstart << 1)) ethstart <<= 1;

}

void printethaddr(addr)

unsigned char *addr;

{

unsigned char *work;

ethtrans far *competh;

int start, comphigh, complow, i;

if(ethtabs < 1) goto printhex;

start = ethstart;
comphigh = (start >> 1) & 0x7fff;
complow = start | comphigh;

testloop:

if(start >= ethtabs) goto scanlower;

competh = ethtab + start;

work = addr;

for(i = 0; i < 6; i++) {

   if(*work < competh->etha[i]) goto scanlower;
   if(*work > competh->etha[i]) goto scanhigher;

   work++;

   }

printf("%17Fs",&competh->enam[0]);

return;

scanlower:

if(complow == 0) goto printhex;

start ^= complow;

scannext:

complow = (complow >> 1) & 0x7fff;
comphigh = (comphigh >> 1) & 0x7fff;

goto testloop;

scanhigher:

if(comphigh == 0) goto printhex;

start ^= comphigh;

goto scannext;

printhex:

work = addr;

printf("%2.2x:%2.2x:%2.2x:%2.2x:%2.2x:%2.2x", *work, *(work+1),
        *(work+2), *(work+3), *(work+4), *(work+5));

}


void printtcpport(port)

unsigned int port;

{

char *res;

if((res = findtab(port, tcpports, tcpcount, tcpstart)) == NULL) return;

printf(" (%s) ", res);

}

int findtcpconn(source, sourceport, dest, destport)

unsigned char source[4];
unsigned int sourceport;
unsigned char dest[4];
unsigned int destport;

{

int i, j;

unsigned long ips, ipd;

ips = (((unsigned long) source[0]) << 24) |
      (((unsigned long) source[1]) << 16) |
      (((unsigned long) source[2]) << 8) |
        (unsigned long) source[3];

ipd = (((unsigned long) dest[0]) << 24) |
      (((unsigned long) dest[1]) << 16) |
      (((unsigned long) dest[2]) << 8) |
        (unsigned long) dest[3];

for(i = 0; i < CONNTAB; i++) {

   if(ips == conn[i].sip && sourceport == conn[i].sp &&
      ipd == conn[i].dip && destport == conn[i].dp) {

      for(j = 0; j < CONNTAB; j++) {

         if(conn[j].lru < conn[i].lru) conn[j].lru++;

         }

      conn[i].lru = 0;

      return i;

      }

   }

return (-1);

}



void checktcpack(source, sourceport, dest, destport, ack)

unsigned char source[4];
unsigned int sourceport;
unsigned char dest[4];
unsigned int destport;
unsigned long ack;

{

int tcpconn;

if((tcpconn = findtcpconn(source, sourceport, dest, destport)) >= 0) {

   if(conn[tcpconn].expack != ack) {

      printf("TCP: **** Acknowledge Mismatch, Expected = %lx ****\n",
             conn[tcpconn].expack);

      }

   }

}


int maketcpconn(source, sourceport, dest, destport)

unsigned char source[4];
unsigned int sourceport;
unsigned char dest[4];
unsigned int destport;

{

int i, j, maxlru;

unsigned long ips, ipd;

ips = (((unsigned long) source[0]) << 24) |
      (((unsigned long) source[1]) << 16) |
      (((unsigned long) source[2]) << 8) |
        (unsigned long) source[3];

ipd = (((unsigned long) dest[0]) << 24) |
      (((unsigned long) dest[1]) << 16) |
      (((unsigned long) dest[2]) << 8) |
        (unsigned long) dest[3];

j = 0;
maxlru = 0;

for(i  = 0; i < CONNTAB; i++) {

   if(conn[i].lru > maxlru) {

      maxlru = conn[i].lru;
      j = i;

      }

   conn[i].lru++;

   }

conn[j].sip = ips;
conn[j].sp = sourceport;
conn[j].dip = ipd;
conn[j].dp = destport;
conn[j].expack = 0;
conn[j].lru = 0;

return j;

}




void analyzetcp(data, source, dest, len)

unsigned char *data;
unsigned char source[4];
unsigned char dest[4];
unsigned int len;

{

union {

unsigned char form4[4];
unsigned long form1;

   } ipform;

unsigned int sourceport, destport;
unsigned long sequence, ack;
int tcphl, flagurg, flagack, flagpsh, flagrst, flagsyn, flagfin;
unsigned int window;
int chksum;
unsigned int urgpnt;

unsigned char *work;

int i, optl;

work = data;

sourceport = (((unsigned int) *work) << 8) | *(work + 1);
destport = (((unsigned int) *(work + 2)) << 8) | *(work + 3);
sequence = (((unsigned long) *(work + 4)) << 24) |
           (((unsigned long) *(work + 5)) << 16) |
           (((unsigned long) *(work + 6)) << 8) | *(work + 7);
ack = (((unsigned long) *(work + 8)) << 24) |
      (((unsigned long) *(work + 9)) << 16) |
      (((unsigned long) *(work + 10)) << 8) | *(work + 11);
tcphl = *(work + 12) >> 4;
flagurg = (*(work + 13) >> 5) & 1;
flagack = (*(work + 13) >> 4) & 1;
flagpsh = (*(work + 13) >> 3) & 1;
flagrst = (*(work + 13) >> 2) & 1;
flagsyn = (*(work + 13) >> 1) & 1;
flagfin = *(work + 13) & 1;
window = (((unsigned int) *(work + 14)) << 8) | *(work + 15);
chksum = ((((int) *(work + 16)) << 8) & 0xff00) | *(work + 17);
urgpnt = (((unsigned int) *(work + 18)) << 8) | *(work + 19);

printf("TCP:   Source Port: %d ", sourceport);

printtcpport(sourceport);

printf("  Destination Port: %d ", destport);

printtcpport(destport);

printf("\n");

printf("TCP:   Sequence : %lx  Acknowledge : %lx\n", sequence, ack);

if(flagack) checktcpack(dest, destport, source, sourceport, ack);

if((i = findtcpconn(source, sourceport, dest, destport)) >= 0) {

   if(conn[i].expack != sequence) {

      printf("TCP: **** Unexpected Sequence, Expected: %lx ****\n",
             conn[i].expack);

      }

   }

else {

   i = maketcpconn(source, sourceport, dest, destport);

   }

conn[i].expack = sequence + (flagsyn | flagfin) + (len - 4*tcphl);

printf("TCP:   Header Length: %i  Window: %u ", tcphl, window);

if(flagurg || flagack || flagpsh || flagrst || flagsyn || flagfin) {

   printf(" Flags: ");

   if(flagurg) printf(" Urgent Valid ");
   if(flagack) printf(" ACK ");
   if(flagpsh) printf(" Push ");
   if(flagrst) printf(" Reset ");
   if(flagsyn) printf(" Synch ");
   if(flagfin) printf(" Finish ");

   }

printf("\n");

printf("TCP:   Checksum: %x ", chksum);

if(flagurg) printf(" Urgent Data up to Byte %u ", urgpnt);

printf("\n");

if(tcphl > 5) {

   work = data + 5*4;
   optl = (tcphl - 5)*4;
   i = 0;

   while (i < optl) {

      switch (*work) {

         case 0: return;

         case 1: work++;
                 i++;
                 break;

         case 2: printf("TCP:   Maximum Segment Size Option: ");
                 if(*(work + 1) == 4) {

                    printf("%u\n", (((unsigned int) *(work + 2)) << 8) |
                                     (unsigned int) *(work + 3));

                    }

                 else {

                    printf("Illegal Option Length\n");

                    }

                 i += *(work + 1);
                 work += *(work + 1);

                 break;

         default: printf("TCP:   Unknown Option: %d\n", *work);

                  return;

         }

      }

   }

}


void printipprot(port)

unsigned int port;

{

char *res;

if((res = findtab(port, ipprotocols, ipprocount, ipprostart)) == NULL) return;

printf(" (%s) ", res);

}

void printudpport(port)

unsigned int port;

{

char *res;

if((res = findtab(port, udpports, udpcount, udpstart)) == NULL) return;

printf(" (%s) ", res);

}


void analyzeudp(data, source, dest, len)

unsigned char *data;
unsigned char source[4];
unsigned char dest[4];
unsigned int len;

{

union {

unsigned char form4[4];
unsigned long form1;

   } ipform;

unsigned int sourceport, destport;
int chksum;
unsigned int udplen;

unsigned char *work;

work = data;

sourceport = (((unsigned int) *work) << 8) | *(work + 1);
destport = (((unsigned int) *(work + 2)) << 8) | *(work + 3);
udplen = (((unsigned int) *(work + 4)) << 8) | *(work + 5);
chksum = (((int) *(work + 6)) << 8) | *(work + 7);

printf("UDP:   Source Port: %d ", sourceport);

printudpport(sourceport);

printf("  Destination Port: %d ", destport);

printudpport(destport);

printf("\n");

printf("UDP:   Length: %u    Checksum: %4.4x\n", udplen, chksum);

}



void analyzeip(data, etype, len)

unsigned char *data;
unsigned int etype;
int len;

{

unsigned char *work;

int vers, ihl, ttl, protocol, checks, offset;
int precedence, delay, throughput, reliability;
int mayfragment, lastfragment;
int optl;

int i, k;

int source[4], dest[4];

unsigned int totlen, ident;

work = data;

vers = (*work >> 4) & 0xff;
ihl = *work & 0xf;
precedence = (*(work + 1) >> 5) & 7;
delay = (*(work + 1) >> 4) & 1;
throughput = (*(work + 1) >> 3) & 1;
reliability = (*(work + 1) >> 2) & 1;
totlen = (*(work + 2) << 8) | *(work + 3);
ident = (*(work + 4) << 8) | *(work + 5);
mayfragment = (*(work + 6) >> 6) & 1;
lastfragment = (*(work + 6) >> 5) & 1;
offset = ((*(work + 6) & 0x1f) << 8) | *(work + 7);
ttl = *(work + 8);
protocol = *(work + 9);
checks = (*(work + 10) << 8) | *(work + 11);

for(i = 0; i < 4; i++) {

   source[i] = *(work + 12 + i);
   dest[i] = *(work + 16 + i);

   }

printf("IP:   From : %d.%d.%d.%d  To : %d.%d.%d.%d  Length : %u\n",
        source[0], source[1], source[2], source[3],
        dest[0], dest[1], dest[2], dest[3], totlen);

printf("IP:   Ident: %4.4x  TTL: %d  Protocol: %d ", ident, ttl, protocol);

printipprot(protocol);

printf("\n");

printf("IP:   Precedence: ");

switch (precedence) {

   case 0: printf("Routine ");
           break;

   case 1: printf("Priority ");
           break;

   case 2: printf("Immediate ");
           break;

   case 3: printf("Flash ");
           break;

   case 4: printf("Flash Override ");
           break;

   case 5: printf("CRITIC/ECP ");
           break;

   case 6: printf("Internetwork Control ");
           break;

   case 7: printf("Network Control ");
           break;

   }

if(delay) printf(" Low Delay ");

if(throughput) printf(" High Throughput ");

if(reliability) printf(" High Reliability ");

printf("\n");

printf("IP:   Fragment Offset: %d ", offset);

if(mayfragment) printf(" May Fragment ");

if(lastfragment) printf(" Last Fragment ");

printf("\n");

if(ihl > 5) {

   work = data + 5 * 4;
   optl = (ihl - 5) * 4;

   i = 0;

   while (i < optl) {


     switch ((*work) & 0x7f) {

        case 0 : goto optdone;

        case 1 : i++;
                 work++;
                 break;

        case 2 : printf("IP:   Security Option: ");
                 if (*(work + 1) != 11) {

                    printf(" Wrong Length ");

                    i += *(work + 1);
                    work += *(work + 1);

                    break;

                    }

                 printf(" %2.2x%2.2x %2.2x%2.2x %c%c %c%c%c\n",
                        *(work+2), *(work+3), *(work+4), *(work+5),
                        *(work+6), *(work+7),
                        *(work+8), *(work+9), *(work+10));

                 i +=11;
                 work +=11;

                 break;

        case 3 : printf("IP:   Loose Source and Record Route Option ");
                 goto routeopt;

        case 9 : printf("IP:   Strict Source and Record Route Option ");
                 goto routeopt;

        case 7 : printf("IP:   Record Route Option ");

routeopt:
                 printf(" Length: %d  Pointer: %d\n",
                        (*(work + 1) - 3)/4, *(work + 2)/4);

                 for (k = 0; k < ((*(work + 1) - 3)/4); k++) {

                    printf("IP:       Route: %u.%u.%u.%u\n",
                           *(work + 3 + k*4), *(work + 4 + k*4),
                           *(work + 5 + k*4), *(work + 6 + k*4));

                    }

                 i += *(work + 1);
                 work += *(work + 1);

                 break;

        case 8 : printf("IP:   Stream ID Option: ");

                 if(*(work + 1) != 4) {

                    printf(" Wrong Length\n");

                    i += *(work + 1);
                    work += *(work + 1);

                    break;

                    }

                 printf(" %2.2x%2.2x\n",
                        *(work + 2), *(work + 3));

                 i += 4;
                 work += 4;

                 break;

        case 68: printf("IP:   Timestamp Option  Length: %d  Pointer %d\n",
                        (*(work + 1) - 4)/4, (*(work + 2) - 5)/4);

                 printf("IP:       Overflow: %d ",
                        (*(work + 3) >> 4) & 0xf);

                 if(*(work + 3) & 1) printf(" IP Addresses");

                 if(*(work + 3) & 2) printf(" prespecified");

                 printf("\n");

                 if(*(work + 3) & 1) {

                    for (k = 0; k < (*(work + 1) - 4)/4; k += 2) {

                       printf("IP:      IP-Address: %u.%u.%u.%u  Time: %l\n",
                               *(work + 4 + 4*k), *(work + 5 + 4*k),
                               *(work + 6 + 4*k), *(work + 7 + 4*k),
                               ((long) *(work + 8 + 4*k) << 24) |
                               ((long) *(work + 9 + 4*k) << 16) |
                               ((long) *(work + 10 + 4*k) << 8) |
                               (long) *(work + 11 + 4*k));

                       }

                    }

                 else {

                    for (k = 0; k < (*(work + 1) - 4)/4; k++) {

                       printf("IP:      Time: %l\n",
                               ((long) *(work + 4 + 4*k) << 24) |
                               ((long) *(work + 5 + 4*k) << 16) |
                               ((long) *(work + 6 + 4*k) << 8) |
                               (long) *(work + 7 + 4*k));

                       }

                    }

                 i += *(work + 1);
                 work += *(work + 1);

                 break;

        default: printf("IP     Unknown Option\n");

                 goto optdone;


        }

      }

   }

optdone:


if(offset == 0) {

   switch (protocol) {

      case 6 : analyzetcp(data + ihl*4, &source[0], &dest[0], totlen - 4*ihl);
               break;

      case 17: analyzeudp(data + ihl*4, &source[0], &dest[0], totlen - 4*ihl);
               break;

      }

   }

}


void analyze(data, etype, len)

unsigned char *data;
unsigned int etype;
int len;

{

char *res;

switch (etype) {

   case 0x0800 : analyzeip(data, etype, len);
                 break;

   default : if((res = findtab(etype, protocols, procount, prostart)) == NULL) {

                printf("*** Protocol Type Unknown ***\n");

                }

             else {

                printf("** Protocol %s not further analyzed **\n", res);

                }

   }

}




FILE *capture;
FILE *ethname;

main (argc, argv)

int argc;
char *argv[];

{

int lenr, hours, testlen, lostflag, minutes, secs;
unsigned int ticks;
float seconds;
int i, j, k, m;
unsigned char skipch;
unsigned char ethblock[MAXETHB];
unsigned int ethtype;

for (i = 0; i < CONNTAB; i++) conn[i].lru = i + CONNTAB + 1;

lostflag = 0;

if (argc > 1) {

   if((capture = fopen(argv[1], "rb")) == NULL) {

      puts("Cannot open capture file");
      exit(1);

      }

   }

if (argc > 2) {

   if((ethname = fopen(argv[2], "r")) == NULL) {

      puts("Cannot open Ethernet Address file");
      exit(1);

      }

initethtab(ethname);

   }

inittab(protocols, sizeof(protocols), &procount, &prostart);
inittab(tcpports, sizeof(tcpports), &tcpcount, &tcpstart);
inittab(udpports, sizeof(udpports), &udpcount, &udpstart);
inittab(ipprotocols, sizeof(ipprotocols), &ipprocount, &ipprostart);

readnext:

if(fread(&lenr, 2, 1, capture) < 1) goto done;

if(fread(&ticks, 2, 1, capture) < 1) goto done;

if(fread(&hours, 2, 1, capture) < 1) goto done;

if(lenr > MAXETHB) {

   puts("*** Long block ***");

   if(fread(&ethblock[0], 1, MAXETHB, capture) < MAXETHB) goto done;

   for (i = MAXETHB; i < lenr; i++) {

      if(fread(&skipch, 1, 1, capture) < 1) goto done;

      }

   }

if(lenr < MINETHB) {

   puts("*** Short block ***");

   }

if(lenr <= MAXETHB) {

   if(fread(&ethblock[0], 1, lenr, capture) < lenr) goto done;

   }

if(fread(&testlen, 2, 1, capture) < 1) goto done;

if(testlen != lenr) {

   puts("*** Lost position ***");

   lostflag = 1;

   }

seconds = (float) ticks / 65536.0 * 3600.0;
minutes = seconds / 60.0;
seconds = seconds - (float) minutes * 60.0;
secs = seconds / 10.0;
seconds = seconds - (float) secs * 10.0;

printf("\n Time %2d:%2.2d:%1.1d%4.2f  Length %4d\n",
       hours, minutes, secs, seconds, lenr);

printf(" From ");

printethaddr(&ethblock[6]);

printf("  To ");

printethaddr(&ethblock[0]);

printf("  Type/Length 0x%2.2x%2.2x\n", ethblock[12], ethblock[13]);

ethtype = (ethblock[12] << 8) | ethblock[13];

if (ethtype > MAXETHB) {

   analyze(&ethblock[14], ethtype, lenr - 14);

   }

for (i = 14; i < lenr; i += 16) {

   printf(" %4i   ", i);

   m = (i + 16 > lenr) ? lenr : i + 16;

   for (j = i; j < m; j++) printf("%2.2x ", ethblock[j]);

   if (m < i + 16) for (j = m; j < i + 16; j++) printf("   ");

   printf("  ");

   for (j = i; j < m; j++) {

      k = ethblock[j];

      if ((k < (int) ' ') || (k > 0x7e)) k = ' ';

      printf("%c", k);

      }

   printf("\n");

   }

if (!lostflag) goto readnext;

done:

fclose(capture);

}

