Logo Search packages:      
Sourcecode: karpski version File versions  Download package

proto.c

/*

This module is a protocol workhorse:

It processes the protocol_parser.dat file
It identifies ethernet packets and fills the 
It tracks the used protocols

*/

#include <stdio.h>
#include <config.h>
#include <string.h>
#include <stdlib.h>
#include <ctype.h>
#include <unistd.h>
#include <sys/types.h>
#include <sys/stat.h>
#include <fcntl.h>
#include <netinet/in.h>
#include <pthread.h>
#include <gtk/gtk.h>
#ifdef TM_IN_SYS_TIME
 #include <sys/time.h>
#else
 #include <time.h>
#endif
#include "proto.h"
#include "connects.h"
#include "karpski.h"

ether_protocols *first_ether_protocol;
ether_protocols *cur_ether_protocol;
protolist *first_protolist;
int line_no;
int defaultfd = -1;
FILE *infile;

char scratchbuf[256];               /* Scratch, eh? */

/* ************************************************************** */
/* **************** START OF PARSING ROUTINES ******************* */
/* ************************************************************** */

 
/* Returns a POSITIVE integer - if it's negative, there was an error */

int getval(char *str)
{
   char *endptr;
   int value;
   
   value = strtol(str, &endptr, 0);
   if ((*endptr != '\0') && (*endptr != ' '))
   {
      fprintf(stderr,"Invalid char: %s - %c / %d\n", str, *endptr, *endptr); 
      return(-1);
   }
   else
      return(value);   
}

int gettok(char *buf, char *token, int tokno, int toeoln)
{
   int i, j, tok, inspaces;
   
   tok = i = j = inspaces = 0;
   
   /* First, remove \n's */
   
   for (i=0 ; i<strlen(buf) ; i++)
      if (buf[i] == '\n')
         buf[i] = '\0';
   
   /* Now look for the first character after whatever group of spaces */

   for (i = 0; (isspace(buf[i]) && (buf[i])); i++) ;
   while ((tok != tokno) && (buf[i]))
   {
      if ((inspaces) && (!isspace(buf[i])))
      {
         tok++;
         inspaces = 0;
      }
      else
      
      if ((!inspaces) && (isspace(buf[i])))
      {
         inspaces = 1;
      }
      else
      {
         i++;
      }
   }
   
   /* If we ran out of room, return -- that token does not exist */
   
   if ((!buf[i]) || (buf[i] == '\n'))
      return(0);
   
/* If we want to return to eoln, just copy from here on out... */
   
   if (toeoln)
      strcpy(token, &buf[i]);
   else
/* otherwise, just return the first word */   
   {
      for (j = i ; (!isspace(buf[j]) && (buf[j] != '\n') && (buf[j])); j++)
         token[j-i] = buf[j];
      token[j-i] = '\0';
   }
   return(1);
}

int getaddonval(packet_parse *packet_info, char *addonname)
{
   int i;
   
   if (!packet_info)
      return -1;
      
   for (i=0; ((i<packet_info->numaddons) && 
              (strcasecmp(addonname, packet_info->addons[i]))); i++)
              ;
   
   if (i == packet_info->numaddons)
      return -1;
   else
      return(packet_info->addonvals[i]);
}

char *print_addr(char s[], int places, char tick)
{
   int i;
   int j;
   int adv;
   unsigned char rval;

   j= 0;
   scratchbuf[j] = '\0';
   for (i=0 ; i<places; i++)
   {
       rval = s[i];
       if ((places == 6) || (places == 3))
       {
          sprintf(&scratchbuf[j], "%02X%n", rval, &adv);
          j+=adv;
       }
       else
       {
          sprintf(&scratchbuf[j], "%hd%n", rval, &adv);
          j+=adv;
       }
       if (i!=(places-1))
          scratchbuf[j++] = tick;
   }
   scratchbuf[j] = '\0';
   return(scratchbuf);
}

long getbyteval(char *byteptr, int len, u_char l_endian)
{
   int i;
   long placeval;
   long value = 0;
   
   if (!l_endian)
   {
      placeval = 1;
      for (i=0; i<len; i++)
      {
         value += (byteptr[i] & 0xff) * placeval;
         placeval *= 256;
      }
   }
   else
   {
      placeval = (len-1)*256;
      if (!placeval)
         placeval = 1;
      for (i=0; i<len; i++)
      {
         value += (byteptr[i] & 0xff) * placeval;
         placeval /= 256;
      }
   }
   return(value);
}

void evaluate_proto_addr(t_addr *addr, char *addstr, char *dptr)
{
   int i;
   int j;
   char strbuf[64];
   
   if (!addr)
      return;
   
   j=addr->offset;
   
   for (i=0 ; i<strlen(addr->mask); i++)
   {
      if (addr->mask[i] == 'd')
         sprintf(strbuf,"%d", dptr[j++] & 0xff);
      else
      if (addr->mask[i] == 'x')
         sprintf(strbuf,"%2X", dptr[j++] & 0xff);
      else
         sprintf(strbuf,"%c", addr->mask[i]);
         
      sprintf(addstr, "%s%s", addstr, strbuf);
   }
}

t_addr *get_proto_addr(char *buf)
{
   char tok1[64], tok2[64];
   t_addr *newaddr;

   if ((!gettok(buf,tok1, 1, 0)) || (!gettok(buf, tok2, 2, 1)))
   {
      fprintf(stderr,"Missing addr token in %s\n", buf);
      return(NULL);
   }
   
   newaddr = MALLOC(sizeof(t_addr), "Newaddr - proto.c");
   if (!newaddr)
   {
      perror("malloc newaddr");
      exit(1);
   }
   
   bzero(newaddr, sizeof(t_addr));
   
   newaddr->offset = getval(tok1);
   strcpy(newaddr->mask, tok2);
   return(newaddr);
}

long evaluate_proto_value(t_value *valptr, char *dptr)
{
   long tval;
   
   if (!valptr)
      return 0;
      
   if (valptr->direct_value)
      return(valptr->direct_value);
   
   tval = getbyteval(&dptr[valptr->offset], valptr->len, valptr->net_order);
   if (valptr->mask)
      tval &= valptr->mask;
   
   if (valptr->shift>0)
      tval = (tval >> valptr->shift);
      
   if (valptr->shift<0)
      tval = (tval << (valptr->shift * -1));
   
   return(tval);   
}


t_value *get_proto_value(char *buf)
{
   char tok1[64], tok2[64], tok3[64], tok4[64], tok5[64];
   t_value *newvalue;

   if (!gettok(buf,tok1, 1, 0))
   {
      fprintf(stderr,"Missing token in %s\n", buf);
      return(NULL);
   }
   
   newvalue = MALLOC(sizeof(t_value), "t_value - proto.c");
   if (!newvalue)
   {
      perror("MALLOC newvalue");
      exit(1);
   }
   
   bzero(newvalue, sizeof(t_value));
   
   if (!gettok(buf, tok2, 2, 0))          /* Absolue value */
   {
      newvalue->direct_value = getval(tok1);
      return(newvalue);
   }
   
   if  ( (!gettok(buf, tok3, 3, 0)) || (!gettok(buf, tok4, 4, 0)) || (!gettok(buf, tok5, 5, 0)))
   {
      fprintf(stderr,"Missing token in %s\n", buf);
      return(NULL);
   }

   newvalue->offset = getval(tok1);
   newvalue->len = getval(tok2);
   newvalue->mask = getval(tok3);
   newvalue->net_order = atoi(tok4);
   newvalue->shift = atoi(tok5);
   return(newvalue);
}

protocols *parse_protocols()
{
   char buffer[80];
   char tok1[80];
   char tok2[80];
   char tok3[80];
   char tok4[80];
   char tok6[80];
   int  tokval;
   protocols *first_protocol, *new_protocol, *t_pr;
   listitem *new_listitem;
   
   addons *new_addon = NULL;

   first_protocol = new_protocol = NULL;

   while (fgets(buffer, sizeof(buffer), infile))
   {
      line_no++;
      if (!gettok(buffer, tok1, 0, 0))
         continue;

      if (!strcasecmp(tok1, "/protocols"))
         break;
      
      if ((!gettok(buffer, tok2, 1, 0)))
      {
         fprintf(stderr,"%s is an invalid protocol item(1)\n", buffer);
         return(NULL);
      }
      
      if ((!strcasecmp(tok1, "listitem")) || (!strcasecmp(tok1, "bititem")))
      {
         if (!new_addon)
         {
            fprintf(stderr,"Error - use of listitem without a prior addon\n");
            return(NULL);
         }
         
         if (!gettok(buffer, tok3, 2, 1))
         {
            fprintf(stderr,"%s is an invalid list/bit item\n", buffer);
            return(NULL);
         }
         
         new_listitem = MALLOC(sizeof(listitem), "listitem - proto.c");
         if (!new_listitem)
         {
            perror("MALLOC new_listitem");
            return(NULL);
         }

         if (!strcasecmp(tok1, "listitem"))
            new_listitem->op = 0;
         if (!strcasecmp(tok1, "bititem"))
            new_listitem->op = 1;
         new_listitem->index = atoi(tok2);
         strcpy(new_listitem->list_desc, tok3);
         new_listitem->next = new_addon->first_listitem;
         new_addon->first_listitem = new_listitem;
      }

      if (!strcasecmp(tok1, "addon"))
      {
         if (!new_protocol)
         {
            fprintf(stderr,"Error - use of addon without a prior pdef\n");
            return(NULL);
         }

         if (!gettok(buffer, tok6, 6, 1))
         {
            fprintf(stderr,"%s is an invalid addon protocol item\n", buffer);
            return(NULL);
         }

         new_addon = (addons *)MALLOC(sizeof(addons), "addons - proto.c");

         if (!new_addon)
         {
            perror("MALLOC new_addon");
            return(NULL);
         }
         
         bzero(new_addon, sizeof(addons));
         new_addon->value = get_proto_value(buffer);
         strncpy(new_addon->addon_name, tok6, sizeof(new_addon->addon_name));
         new_addon->next = new_protocol->first_addon;
         new_protocol->first_addon = new_addon;
      }

      if (!strcasecmp(tok1, "prlen"))
      {
         if (!new_protocol)
         {
            fprintf(stderr,"Error - use of addon without a prior pdef\n");
            return(NULL);
         }
         
         new_protocol->protocol_data_len = get_proto_value(buffer);
      }
      
      if (!strcasecmp(tok1, "conntype"))
      {
         if (!new_protocol)
         {
            fprintf(stderr,"Error - use of conntype without a prior pdef\n");
            return(NULL);
         }
         
         new_protocol->conn_type = atoi(tok2);
      }
      
      if (!strcasecmp(tok1, "pdef"))
      {

         if ((!gettok(buffer, tok3, 2, 0)) || (!gettok(buffer, tok4, 3, 1)))
         {
            fprintf(stderr,"Missing token 4 in %s\n", buffer);
            return(NULL);
         }
         
         tokval = getval(tok2);
         if ((tokval < 0) || (tokval > 65535))
         {
            fprintf(stderr,"Invalid protocol number: %d\n", tokval);
            return(NULL);
         }
         new_protocol = (protocols *)MALLOC(sizeof(protocols), "protocols - proto.c");
         if (!new_protocol)
         {
            perror("Malloc of new_protocol");
            exit(1);
         }
         new_protocol->protocol_number = tokval;
         strncpy(new_protocol->protocol_short_name, tok3, sizeof(new_protocol->protocol_short_name));
         strncpy(new_protocol->protocol_description, tok4, sizeof(new_protocol->protocol_description));
         new_protocol->outfd = -1;
         new_protocol->first_addon = NULL;
         new_protocol->next = NULL;
         new_protocol->active = 1;
         if (!first_protocol)
            first_protocol = new_protocol;
         else
            for (t_pr = first_protocol; t_pr; t_pr=t_pr->next)
               if (!t_pr->next)
               {
                  t_pr->next = new_protocol;
                  break;
               }
      }
   }
   
   return(first_protocol);
}

int parse_ethertype()
{
   char buffer[80];
   char tok1[80];
   char tok2[80];
   char tok6[80];
   int tok2val;
   addons *new_addon;
   
   while (fgets(buffer, sizeof(buffer), infile))
   {
      line_no++;
      
      if (!gettok(buffer, tok1, 0, 0))
         continue;
      
      if (!strcasecmp(tok1, "transportlayer"))
      {
         cur_ether_protocol->transportlayer = 1;
         continue;
      }
      
      if (!strcasecmp(tok1, "protocols"))
      {
         if (!(cur_ether_protocol->first_protocol = parse_protocols()))
         {
            fprintf(stderr,"Error parsing protocols.\n");
            return(0);
         }
         continue;
      }

      if ((!strcasecmp(tok1, "/ethertype")))
         return(1);
      
      if (!gettok(buffer, tok2, 1, 0))
      {
         fprintf(stderr,"Error: keyword %s needs an argument!\n", buffer);
         return(0);
      }

      if (!strcasecmp(tok1, "addon"))
      {
         if (!gettok(buffer, tok6, 6, 1))
         {
            fprintf(stderr,"%s is an invalid protocol item(4)\n", buffer);
            return(0);
         }
         
         if (!cur_ether_protocol)
         {
            fprintf(stderr,"Error - no current ether block\n");
            return(0);
         }

         new_addon = (addons *)MALLOC(sizeof(addons), "addons2 - proto.c");

         if (!new_addon)
         {
            perror("MALLOC new_addon");
            exit(1);
         }
         
         bzero(new_addon, sizeof(addons));
         
         new_addon->value = get_proto_value(buffer);
         strncpy(new_addon->addon_name, tok6, sizeof(new_addon->addon_name));
         new_addon->next = cur_ether_protocol->first_addon;
         cur_ether_protocol->first_addon = new_addon;
         continue;
      }

      
      tok2val = getval(tok2);
      
      if (!strcasecmp(tok1, "type"))
      {
         cur_ether_protocol->ether_type = tok2val;
         continue;
      }

      if (!strcasecmp(tok1, "hlen"))
      {
         
         cur_ether_protocol->ether_hlen = get_proto_value(buffer);
         continue;
      }
      
      if (!strcasecmp(tok1, "tlen"))            /* Total length */
      {
         cur_ether_protocol->ether_tlen = get_proto_value(buffer);
         continue;
      }

      if (!strcasecmp(tok1, "saddr"))
      {
         cur_ether_protocol->ether_src_addr = get_proto_addr(buffer);
         continue;
      }
      if (!strcasecmp(tok1, "daddr"))
      {
         cur_ether_protocol->ether_dst_addr = get_proto_addr(buffer);
         continue;
      }

      if (!strcasecmp(tok1, "protocoloffset"))
      {
         cur_ether_protocol->ether_protocol_offset = tok2val;
         continue;
      }
      
      fprintf(stderr,"Unknown keyword: %s\n", tok1);
      return(0);
   }
   return(1);
}

/**********************************************************************

 parse_datafile()

 **********************************************************************/

int parse_datafile()
{
   ether_protocols *t_ep;
   
   char buffer[80];
   char tok1[80];
   char tok2[80];

   line_no = 0; 
   first_ether_protocol = cur_ether_protocol = NULL;
   
   while (fgets(buffer, sizeof(buffer), infile))
   {
      line_no++;
      if (strlen(buffer) == sizeof(buffer))
         return(0);
      
      if (buffer[0] == '#')
         continue;
         
      if (!gettok(buffer, tok1, 0, 0))
         continue;
         
      if (!gettok(buffer, tok2, 1, 1))
         continue;

      if (strcasecmp("ethertype", tok1))
      {
         fprintf(stderr,"Error - missing ethertype\n");
         return(0);
      }
      cur_ether_protocol = (ether_protocols *)MALLOC(sizeof(ether_protocols), "ether_protocols - proto.c");
      if (!cur_ether_protocol)
      {
         perror("MALLOC cur_ether_protocol");
         exit(1);
      }
      bzero(cur_ether_protocol, sizeof(ether_protocols));
      cur_ether_protocol->outfd = -1;
      cur_ether_protocol->active = 1;
      cur_ether_protocol->next = NULL;
      strncpy(cur_ether_protocol->ether_type_name, tok2, sizeof(cur_ether_protocol->ether_type_name));
      if (!(parse_ethertype(infile)))
      {
         fprintf(stderr,"Error parsing the ethertype\n");
         return(0);
      }
      if (first_ether_protocol)
      {
         for (t_ep=first_ether_protocol; t_ep; t_ep=t_ep->next)
            if (!t_ep->next)
            {
               t_ep->next = cur_ether_protocol;
               break;
            }
      }
      else
         first_ether_protocol = cur_ether_protocol;
   }
   return(1);
}

/* ************************************************************** */
/* ***************** END OF PARSING ROUTINES ******************** */
/* ************************************************************** */

/* 

Add a capture on a frame type.  This opens the file, fn, writes a header,
and returns the file descriptor.  If the opening of the file fails, or
if there is no associated frametype in the protocol defs file, -1 is
returned.

*/

int add_frame_capture(u_short frametype, char *fn)
{
   ether_protocols *t_ep;
   char str[64];
   time_t timeval;
   struct tm *tptr;
   
   for (t_ep = first_ether_protocol; ((t_ep) && (t_ep->ether_type != frametype)); t_ep=t_ep->next) ;

   if (!t_ep)
      return(-1);

   if ((t_ep->outfd = open(fn, O_WRONLY | O_CREAT | O_APPEND, S_IREAD | S_IWRITE))<0)
   {
      fprintf(stderr,"Error setting capture - frame type: %4X  output filename: %s\n", frametype, fn);
      perror("open frame output");
      exit(1);
   }
   
   time(&timeval);
   tptr = localtime(&timeval);
   
   sprintf(str,"Capture started at %02d:%02d:%02d %02d/%02d/%04d\n", tptr->tm_hour, tptr->tm_min, tptr->tm_sec, tptr->tm_mon, tptr->tm_mday, tptr->tm_year+1900);
   
   if (write(t_ep->outfd, str, strlen(str))!=strlen(str))
   {
      perror("Write header to capture file");
      exit(1);
   }   
   return(t_ep->outfd);
}  

/* 

Add a capture on a frame and protocol type.  This opens the file, fn, 
writes a header and returns the file descriptor.  If the opening of the 
file fails, or if there is no associated frametype/protocol combo in the 
protocol defs file, -1 is returned.

*/

int add_protocol_frame_capture(u_short frametype, char *pname, char *fn)
{
   ether_protocols *t_ep;
   protocols *t_pr;
   char str[64];
   time_t timeval;
   struct tm *tptr;
   
   for (t_ep = first_ether_protocol; ((t_ep) && (t_ep->ether_type != frametype)); t_ep=t_ep->next) ;

   if (!t_ep)
      return(-1);
      
   for (t_pr = t_ep->first_protocol; ((t_pr) && (strcasecmp(pname, t_pr->protocol_short_name))); t_pr = t_pr->next) ;

   if (!t_pr)
      return(-1);
      
   if ((t_pr->outfd = open(fn, O_WRONLY | O_CREAT | O_APPEND, S_IREAD | S_IWRITE))<0)
   {
      fprintf(stderr,"Error setting capture - frame type: %4X  output filename: %s\n", frametype, fn);
      perror("open frame output");
      exit(1);
   }
   
   time(&timeval);
   tptr = localtime(&timeval);
   
   sprintf(str,"Capture started at %02d:%02d:%02d %02d/%02d/%04d\n", tptr->tm_hour, tptr->tm_min, tptr->tm_sec, tptr->tm_mon, tptr->tm_mday, tptr->tm_year+1900);
   
   if (write(t_pr->outfd, str, strlen(str))!=strlen(str))
   {
      perror("Write header to capture file");
      exit(1);
   }   
   return(t_pr->outfd);
}  

/**************************************************************/

void setup_default_capture(char *fn)
{
   char str[64];
   time_t timeval;
   struct tm *tptr;

   if ((defaultfd = open(fn, O_WRONLY | O_CREAT | O_APPEND, S_IREAD | S_IWRITE))<0)
   {
      fprintf(stderr,"Error setting default capture - output filename: %s\n", fn);
      perror("open frame output");
      exit(1);
   }
   
   time(&timeval);
   tptr = localtime(&timeval);
   
   sprintf(str,"Capture started at %02d:%02d:%02d %02d/%02d/%04d\n", tptr->tm_hour, tptr->tm_min, tptr->tm_sec, tptr->tm_mon, tptr->tm_mday, tptr->tm_year+1900);
   
   if (write(defaultfd, str, strlen(str))!=strlen(str))
   {
      perror("Write header to capture file");
      exit(1);
   }   
   return;
}

/*

This writes the end timestamp to the fd outfd.

*/

void write_close_msg(int outfd)
{
   char str[64];
   time_t timeval;
   struct tm *tptr;
   
   time(&timeval);
   tptr = localtime(&timeval);
   
   sprintf(str,"Capture ended at %02d:%02d:%02d %02d/%02d/%04d\n", tptr->tm_hour, tptr->tm_min, tptr->tm_sec, tptr->tm_mon, tptr->tm_mday, tptr->tm_year+1900);
   
   if (write(outfd, str, strlen(str))!=strlen(str))
   {
      perror("Write closing to capture file");
      exit(1);
   }
   return;
}

/*

This function reads the file capture_filters.dat and sets up the
captures.

*/

void process_captures()
{
   FILE *infile;
   char fn[256];
   char line[256];
   char t1[80], t2[80], t3[80], t4[80];
   
   sprintf(fn, "%scapture_filters.dat", KARPSKI_DATA_DIR);
   
   if (!(infile = fopen(fn, "r")))
   {
      fprintf(stderr,"No capture filters file (%s)-- no capture filters will be applied.\n", fn);
      return;
   }
   
   while (fgets(line, sizeof(line), infile))
   {
      if ((line[0] == '#') || (line[0] == '\n') || (!line[0]))
         continue;
      if ( (!gettok(line, t1, 0, 0)) || (!gettok(line, t2, 1, 0)))
      {
         fprintf(stderr, "Error parsing line %s in %s.\n", line, fn);
         exit(1);
      }

      if (!strcasecmp(t1, "defcap"))
      {
         setup_default_capture(t2);
         continue;
      }
         
      if (!strcasecmp(t1, "protoframe"))
      {
         if  ((!gettok(line, t3, 2, 0)) || (!gettok(line, t4, 3, 0)))
         {
            fprintf(stderr,"Error: Missing argument to protoframe in %s.\n", fn);
            exit(1);
         }
         if ((add_protocol_frame_capture(getval(t2), t3, t4))<0)
         {
            fprintf(stderr, "Error setting frame protocol capture type %4X / %s to %s!\n", getval(t2), t3, t4);
            exit(1);
         }
         continue;
      }
      
      if (!strcasecmp(t1, "frame"))
      {
         if ( (!gettok(line, t3, 2, 0)) && ((add_frame_capture(getval(t2), t3))<0))
         {
            fprintf(stderr, "Error setting frame capture type %4X to %s!\n", getval(t2), t3);
            exit(1);
         }
         if (add_frame_capture(getval(t2), t3)<0)
         {
            fprintf(stderr, "Error setting frame capture %4X %s", getval(t2), t3);
            exit(1);
         }
         continue;
      }
      
      fprintf(stderr, "Illegal line in %s: %s\n", fn, line);
      exit(1);
      
   }
   
   fclose(infile);
}

void close_all_frame_captures()
{
   ether_protocols *t_ep;
   protocols *t_pr;
   
   for (t_ep = first_ether_protocol; (t_ep); t_ep=t_ep->next)
   {
      if (t_ep->outfd > 0)
      {
         write_close_msg(t_ep->outfd);
         close(t_ep->outfd);
      }
      for (t_pr = t_ep->first_protocol; t_pr; t_pr = t_pr->next)
         if (t_pr->outfd > 0)
         {
            write_close_msg(t_pr->outfd);
            close(t_pr->outfd);
         }
   }
   
   if (defaultfd > -1)
      close(defaultfd);
}  

int read_and_parse_protocols()
{
   char fn[256];
   
   sprintf(fn, "%sprotocol_parser.dat", KARPSKI_DATA_DIR);
   
   if (!(infile = fopen(fn,"r")))
   {
      perror("fopen");
      return(0);
   }
   
   if (!parse_datafile())
   {
      fclose(infile);
      return(0);
   }

   fclose(infile);
   
   process_captures();
   
   return(1);
}


ether_protocols *get_frame_enc_type(u_short ether_type)
{
   ether_protocols *cur_ep;
   
   for (cur_ep = first_ether_protocol; ((cur_ep) && (ether_type != cur_ep->ether_type)); cur_ep=cur_ep->next)
      ;
      
   if (cur_ep)
      return(cur_ep);
   else
      return(NULL);
}


void get_addons(char *payload, addons *first_addon, packet_parse *packet_info)
{
   addons *t_addon;
   listitem *t_listitem;
   int newbititem;
   long value;
   
   for (t_addon = first_addon; t_addon; t_addon = t_addon->next)
   {
      value = evaluate_proto_value(t_addon->value, payload);
      newbititem = 1;
      
      if (t_addon->first_listitem)
      {
         packet_info->addonvals[packet_info->numaddons] = value;
         for (t_listitem = t_addon->first_listitem ; t_listitem ; t_listitem = t_listitem->next)
         {
            if ((t_listitem->op==1) && (t_listitem->index & value))
            {
               if (newbititem)
               {
                  packet_info->addons[packet_info->numaddons] = t_addon->addon_name;
                  packet_info->addonstrs[packet_info->numaddons] = MALLOC(64, "New addonstrs");
                  strcpy(packet_info->addonstrs[packet_info->numaddons++], t_listitem->list_desc);
                  newbititem = 0;
               }
               else
               {
                  sprintf(packet_info->addonstrs[packet_info->numaddons-1], "%s, %s", packet_info->addonstrs[packet_info->numaddons-1], t_listitem->list_desc);
               }
            }
            if ((!t_listitem->op) && (t_listitem->index == value))
            {
               packet_info->addons[packet_info->numaddons] = t_addon->addon_name;
               packet_info->addonstrs[packet_info->numaddons++] = STRDUP(t_listitem->list_desc, "New addonstrs 2");
               break;
            }
         }
      }
      else
      {
         packet_info->addons[packet_info->numaddons] = t_addon->addon_name;
         packet_info->addonvals[packet_info->numaddons++] = value;
      }
   }
}

protocols *getproto(char *payload, ether_protocols *ep_ptr, int hlen, packet_parse *packet_info)
{
   int proto;
   protocols *t_proto;
   
   proto = getbyteval(&payload[ep_ptr->ether_protocol_offset], 1, 0);
   
   for (t_proto = ep_ptr->first_protocol; ((t_proto) && (proto!=t_proto->protocol_number)); t_proto=t_proto->next) ;
   
   if (!t_proto)
   {
      fprintf(stderr,"Unidentified protocol: %d\n", proto);
      return(NULL);
   }
   
   if (t_proto->first_addon)
      get_addons(&payload[hlen], t_proto->first_addon, packet_info);
   return(t_proto);
}

void get_packet_info(u_short ether_type, char *payload, packet_parse *packet_info)
{
   int hlen, phlen, packetlen;
   char *dptr;
   ether_protocols *ep_ptr;
   protocols *pr_ptr;
   char strbuf[256];
   
   phlen = 0;     /* force initial value... (didn't get one, below... */
   packet_info->display_proto = 0;        /* Don't unless we're asked */
   
   switch (packet_info->frame_enc_type)
   {
      case 1 : strcpy(strbuf, "802.3"); break;
      case 2 : strcpy(strbuf, "802.3/802.2"); break;
      case 3 : strcpy(strbuf, "Ether/SNAP"); break;
      case 4 : strcpy(strbuf, "Ether/II"); break;
      default : strcpy(strbuf, "???"); break;
   }
   
   if (!(ep_ptr = get_frame_enc_type(ether_type)))
   {
      sprintf(packet_info->frametype, "Unk. %s frame : %2X", strbuf, ether_type);
      packet_info->display_proto=1;       /* Can't filter unk. packets @@ */
      packet_info->phlen = 0;
      packet_info->hlen = 0;
      packet_info->dptr = payload;
      packet_info->outfd = defaultfd;
      return;
   }

   packet_info->display_proto= ep_ptr->active;
   
   strcpy(packet_info->frametype, ep_ptr->ether_type_name);

   packet_info->outfd = ep_ptr->outfd;

   if (ep_ptr->ether_src_addr)
      evaluate_proto_addr(ep_ptr->ether_src_addr, packet_info->src_address, payload);

   if (ep_ptr->ether_dst_addr)
      evaluate_proto_addr(ep_ptr->ether_dst_addr, packet_info->dst_address, payload);

   if (ep_ptr->first_addon)
   {
      get_addons(payload, ep_ptr->first_addon, packet_info);
   }
   
/* If we can extract the header length, do it, otherwise assume no header */   

   if (ep_ptr->ether_hlen) {
      hlen = evaluate_proto_value(ep_ptr->ether_hlen, payload);
   } else {
      hlen = 0;
   }

/* If we can extract the total length of the packet, do it ... otherwise assume the whole length */

   if (ep_ptr->ether_tlen) {
      packetlen = evaluate_proto_value(ep_ptr->ether_tlen, payload);
   } else {
      packetlen = packet_info->dlen; 
   }

/* If there is protocol info about this frame, see if it matches... */

   if (ep_ptr->first_protocol)
   {
      pr_ptr = packet_info->protocol_ptr = getproto(payload, ep_ptr, hlen, packet_info);
      
      if (pr_ptr)
      {
      
/* Only set display_proto if its ether frame type is active */
      
         if ((pr_ptr->active) && (packet_info->display_proto))
            packet_info->display_proto = 1;
         if (pr_ptr->outfd>-1) 
            packet_info->outfd = pr_ptr->outfd;
            
         dptr = payload + hlen;
            phlen = evaluate_proto_value(pr_ptr->protocol_data_len, dptr);
      }
      else
      {
         phlen = 0;
      }
   }
   else
   {
      phlen = 0;
   }
   
   packet_info->phlen = phlen;
   packet_info->hlen = hlen;
   packet_info->dptr = payload + hlen + phlen;
   packet_info->dlen = packetlen - hlen - phlen;
   if (hlen+phlen > packetlen)
   {
      fprintf(stderr, "Packet length mismatch! Pl = %d, hl = %d, ph = %d\n", packetlen, hlen, phlen);
   }
}

/*

This adds a frame type into the protocol statistics linked list.

*/

void add_protolist(char *proto, u_short frametype, int len)
{
   protolist *t_pl, *new_pl, *last_pl;
   
   for (t_pl = first_protolist; ((t_pl) && (strcmp(proto, t_pl->protoname))); t_pl = t_pl->next) ;
   
   if (!t_pl)           /* If this is a new frame */
   {
      new_pl = MALLOC(sizeof(protolist), "protolist new item - proto.c");
      if (!new_pl)
      {
         perror("MALLOC new_pl");
         exit(1);
      }
      strcpy(new_pl->protoname, proto);
      new_pl->frametype = frametype;
      new_pl->npackets=1;
      new_pl->nbytes=len;
      
      last_pl = NULL;
      for (t_pl = first_protolist; ((t_pl) && (t_pl->frametype != frametype)); t_pl=t_pl->next)
         last_pl = t_pl;

      if (t_pl)
      {
         new_pl->next = t_pl->next;
         t_pl->next = new_pl;
      }
      else
      {
         if (last_pl)
         {
            last_pl->next = new_pl;
            new_pl->next = NULL;
         }
         else
         {
            new_pl->next = NULL;
            first_protolist = new_pl;
         }
      }
   }
   else           /* Else it's a known protocol */
   {
      t_pl->npackets++;
      t_pl->nbytes+= len;
   }
   return;
}

void free_frame(packet_parse *packet_info)
{
   int i;
   
   for (i=0; i<packet_info->numaddons; i++)
   {
      if (packet_info->addonstrs[i])
         FREE(packet_info->addonstrs[i], "Free_frame");
   }
}

/*

**************************************************************************
*
* Function: decode_frame
* Desc:           This function is called right after a frame is received.
*           It determines which type of ethernet packet has been
*           received, then figures out with the frame type is, then
*           figures out if there are any known undlerlying protocols.
*           It fills in the structure packet_info along the way.  This
*           struct holds all of the information about the packet such
*           as a pointer to its payload, its data length, its header
*           len, etc.  Look in proto.h for more info.
* Input:    char *framepkt - a pointer to the raw packet
*           packet_parse * - a pointer to a pre-allocated packet_parse
*                        structure.
*           int packetlen  - The length of the entire ether frame.
* Output:   Fills in packet_info with the packet information
* Returns:  Nothing.
*
**************************************************************************

*/

void decode_frame(char *framepkt, packet_parse *packet_info, int packetlen)
{
   struct frame *frm;
   u_short frmtype;
   char *payload;
   
   frm = (struct frame *) framepkt;
   frmtype = htons(frm->type);

   bzero(packet_info, sizeof(packet_parse));
   strcpy(packet_info->saddr, print_addr(frm->saddr, 6, ':'));
   strcpy(packet_info->daddr, print_addr(frm->daddr, 6, ':'));
   packet_info->packetlen = packetlen;

   if (frmtype < 1501)
   {
      
/* Raw ether / Raw 802.3 */
      if ((frm->dsap == 0xff) && (frm->ssap == 0xff))
      {
         strcpy(packet_info->frametype, "Raw IPX");
         packet_info->dptr=(char *)framepkt+16;
         packet_info->dlen=frmtype;
         packet_info->frame_enc_type = 1;
         add_protolist(packet_info->frametype, frmtype ,packet_info->packetlen);
         strcpy(packet_info->protostr, packet_info->frametype);
         return;
      }
      

/* Ether SNAP */
      if ((frm->dsap == 0xaa) && (frm->ssap == 0xaa) && (frm->cntrl == 0x03))
      {
         packet_info->dlen=frmtype-8;
         frmtype = htons(frm->type2);
         sprintf(packet_info->frametype, "\nEther/SNAP type %4X\n", frmtype);
         packet_info->frame_enc_type = 3;
         payload = (char *) (framepkt + sizeof(struct frame));
      }
      else
      {
/* 802.3/802.2 */
         packet_info->dlen=frmtype;
         packet_info->dptr=framepkt + 17;
         packet_info->frame_enc_type = 2;
         switch (frm->dsap)
         {
            case 0: strcpy(packet_info->frametype, "XID (802.3/802.2)"); break;
            case 2: strcpy(packet_info->frametype, "ISM (802.3/802.2)"); break;
            case 3: strcpy(packet_info->frametype, "GSM (802.3/802.2)"); break;
            case 4 : case  8 : case 0x0c :strcpy(packet_info->frametype, "SNA (802.3/802.2)"); break; 
            case 0x06: strcpy(packet_info->frametype, "IP (802.3/802.2)"); break;
            case 0x0e: strcpy(packet_info->frametype, "(802.3/802.2)"); break;
            case 0x10: strcpy(packet_info->frametype, "Novell/SDLC (802.3/802.2)"); break;
            case 0x20 : case 0x34 : case 0xec : strcpy(packet_info->frametype, "CLNP ISO OSI (802.3/802.2)"); break;
            case 0x42: strcpy(packet_info->frametype, "BPDU (802.3/802.2)"); break;
            case 0x7e: strcpy(packet_info->frametype, "X.25 PLP (802.3/802.2)"); break;
            case 0x80: strcpy(packet_info->frametype, "XNS (802.3/802.2)"); break;
            case 0x86: strcpy(packet_info->frametype, "Nestar (802.3/802.2)"); break;
            case 0x8e: strcpy(packet_info->frametype, "Active station (802.3/802.2)"); break;
            case 0x98: strcpy(packet_info->frametype, "ARP (802.3/802.2)"); break;
            case 0xbc: strcpy(packet_info->frametype, "Vines (802.3/802.2)"); break;
            case 0xe0: strcpy(packet_info->frametype, "IPX (802.3/802.2)"); break;
            case 0xF0: strcpy(packet_info->frametype, "IBM Netbios (802.3/802.2)"); break;
            case 0xf4 : case 0xf5: strcpy(packet_info->frametype, "LAN Manager (802.3/802.2)"); break;
            case 0xf8 : strcpy(packet_info->frametype, "Rem. prog load (802.3/802.2)"); break;
            case 0xfa : strcpy(packet_info->frametype, "UB (802.3/802.2)"); break;
            case 0xfc : strcpy(packet_info->frametype, "IBM RPL (802.3/802.2)"); break;
            case 0xfe : strcpy(packet_info->frametype, "ISO Netlayer (802.3/802.2)"); break;
            case 0xff : strcpy(packet_info->frametype, "LLC broadcast (802.3/802.2)"); break;
            default : sprintf(packet_info->frametype, "Unknown DSAP (%2X)", frm->dsap); packet_info->outfd = defaultfd; break;
         }
         add_protolist(packet_info->frametype, frmtype, packet_info->packetlen);
         strcpy(packet_info->protostr, packet_info->frametype);
         return;
      }
   }
   
/* Ethernet II packet (standard ETHER) */
   else
   {
      packet_info->frame_enc_type = 4;
      packet_info->dlen = packetlen - 14;
      payload = (char *) (framepkt + 14);
   }

/* Here we should only have SNAP or ETHER2 packets */

   get_packet_info(frmtype, payload, packet_info);
   add_protolist(packet_info->frametype, frmtype, packet_info->packetlen);

   if (packet_info->protocol_ptr)
   {
      add_protolist(packet_info->protocol_ptr->protocol_short_name, frmtype, packet_info->packetlen);
      sprintf(packet_info->protostr, "%s/%s",packet_info->protocol_ptr->protocol_short_name, packet_info->frametype);
   }
   else
      strcpy(packet_info->protostr, packet_info->frametype);

   return;
}


Generated by  Doxygen 1.6.0   Back to index