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

etherpeek.c

/*
 * Copyright (c) 1994, 1995, 1996, 1997, 1998, 1999, 2000, 2001,
 *               2002, 2003, 2004
 *    Ohio University.
 *
 * ---
 * 
 * Starting with the release of tcptrace version 6 in 2001, tcptrace
 * is licensed under the GNU General Public License (GPL).  We believe
 * that, among the available licenses, the GPL will do the best job of
 * allowing tcptrace to continue to be a valuable, freely-available
 * and well-maintained tool for the networking community.
 *
 * Previous versions of tcptrace were released under a license that
 * was much less restrictive with respect to how tcptrace could be
 * used in commercial products.  Because of this, I am willing to
 * consider alternate license arrangements as allowed in Section 10 of
 * the GNU GPL.  Before I would consider licensing tcptrace under an
 * alternate agreement with a particular individual or company,
 * however, I would have to be convinced that such an alternative
 * would be to the greater benefit of the networking community.
 * 
 * ---
 *
 * This file is part of Tcptrace.
 *
 * Tcptrace was originally written and continues to be maintained by
 * Shawn Ostermann with the help of a group of devoted students and
 * users (see the file 'THANKS').  The work on tcptrace has been made
 * possible over the years through the generous support of NASA GRC,
 * the National Science Foundation, and Sun Microsystems.
 *
 * Tcptrace is free software; you can redistribute it and/or modify it
 * under the terms of the GNU General Public License as published by
 * the Free Software Foundation; either version 2 of the License, or
 * (at your option) any later version.
 *
 * Tcptrace is distributed in the hope that it will be useful, but
 * WITHOUT ANY WARRANTY; without even the implied warranty of
 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
 * General Public License for more details.
 *
 * You should have received a copy of the GNU General Public License
 * along with Tcptrace (in the file 'COPYING'); if not, write to the
 * Free Software Foundation, Inc., 59 Temple Place, Suite 330, Boston,
 * MA 02111-1307 USA
 * 
 * Author:  Shawn Ostermann
 *          School of Electrical Engineering and Computer Science
 *          Ohio University
 *          Athens, OH
 *          ostermann@cs.ohiou.edu
 *          http://www.tcptrace.org/
 */
#include "tcptrace.h"
static char const GCC_UNUSED copyright[] =
    "@(#)Copyright (c) 2004 -- Ohio University.\n";
static char const GCC_UNUSED rcsid[] =
    "@(#)$Header: /usr/local/cvs/tcptrace/etherpeek.c,v 5.8 2003/11/19 14:38:02 sdo Exp $";


/****************************************
**  This is the Ether Peek reading stuff.
**  Author: Brian Wilson
**          Ohio University
**          Computer Science
**  Date:   Mon, July   ,1995
****************************************/
  



#ifdef GROK_ETHERPEEK

/* Defining SYS_STDIN which is fp for Windows and stdin for all other systems */
#ifdef __WIN32
static FILE *fp;
#define SYS_STDIN fp
#else
#define SYS_STDIN stdin
#endif /* __WIN32 */

/* NOTE:  This is for version 5 of the file.  Other file formats may not work
 correctly.*/

static struct EPFileHeader {
    char version;       /* file version (must be 5, 6, or 7)*/
    char status;        /* filler to fill to even boundary*/
} file_header;

static struct EPFileHeader2 {
    tt_uint32 length;         /* length of file*/
    tt_uint32 numPackets;           /* number of packets contained in the file*/
    tt_uint32 timeDate;       /* time and date stamp of the file (MAC format)*/
    tt_uint32 timeStart;            /* time of the first packet in the file*/
    tt_uint32 timeStop;       /* time of the last packet in the file*/
    tt_uint32 futureUse[7];   /*reserved for future use and irrelevent to us!*/
} file_header2;



struct EPFilePacket_v5_6 {
    tt_uint16 packetlength;   /* total packet length */
    tt_uint16 slicelength;    /* sliced length of packet*/
};

struct EPFilePacket2_v5_6 {
    u_char flags;       /* crc, frame, runt, ...*/
    u_char status;            /* slice, trunc, ...*/
};

struct EPFilePacket3_v5_6 { 
    tt_uint32  timestamp;           /* timestamp in milliseconds*/
    tt_uint16 destNum;        /* str corresponding to ether address*/
    tt_uint16 srcNum;         /* dnum is entry in table*/
    tt_uint16 protoNum;       /* table number for the protocol*/
    char protoStr[8];         /* protocol identity string (NOT null terminated!)*/
    tt_uint16 filterNum;            /* index to filter table*/
};


/* what we need for version 7 */
typedef struct PeekPacket_v7 {
    tt_uint16     protospec;  /* ProtoSpec ID. */
    tt_uint16     packetlength;     /* Total length of packet. */
    tt_uint16     slicelength;      /* Sliced length of packet. */
    u_char  flags;            /* CRC, frame, runt, ... */
    u_char  status;           /* Slicing, ... */
    tt_uint32     timestamphi;      /* 64-bit timestamp in microseconds. */
    tt_uint32     timestamplo;
} PeekPacket_v7;

/* byte swapping */
/* Mac's are in network byte order.  If this machine is NOT, then */
/* we'll need to do conversion */

  
static u_long mactime;

#define Real_Size_FH 2
#define Real_Size_FH2 48 
#define Real_Size_FP 4
#define Real_Size_FP2 2
#define Real_Size_FP3 20 

#define Mac2unix 2082844800u  /* difference between Unix and Mac timestamp */

#define VERSION_7 7    /* Version 7 */
#define VERSION_6 6    /* Version 6 */
#define VERSION_5 5    /* Version 5 */ 
static char thisfile_ep_version;
#define EP_V5 (thisfile_ep_version == VERSION_5)
#define EP_V6 (thisfile_ep_version == VERSION_6)
#define EP_V7 (thisfile_ep_version == VERSION_7)



/* static buffers for reading */
static struct ether_header *pep;
static int *pip_buf;


/* currently only works for ETHERNET */
static int
pread_EP(
    struct timeval      *ptime,
    int                 *plen,
    int                 *ptlen,
    void          **pphys,
    int                 *pphystype,
    struct ip           **ppip,
    void          **pplast)
{
    u_int packlen;
    u_int rlen;
    u_int len;

    /* read the EP packet header */
    while(1){
      if (EP_V5 || EP_V6) {
          struct EPFilePacket_v5_6 hdr;
          struct EPFilePacket2_v5_6 hdr2;
          struct EPFilePacket3_v5_6 hdr3;

          if ((rlen=fread(&hdr,1,Real_Size_FP,SYS_STDIN)) != Real_Size_FP) {
            if (rlen != 0)
                fprintf(stderr,"Bad EP header\n");
            return(0);
          }
          hdr.packetlength = ntohs(hdr.packetlength);
          hdr.slicelength = ntohs(hdr.slicelength);

          if (debug>1) {
            printf("EP_read: next packet: original length: %d, saved length: %d\n",
                   hdr.packetlength, hdr.slicelength);
          }
          
      
          if ((rlen=fread(&hdr2,1,Real_Size_FP2,SYS_STDIN)) !=Real_Size_FP2) {
            if (rlen != 0)
                fprintf(stderr,"Bad EP header\n");
            return(0);
          }

          if ((rlen=fread(&hdr3,1,Real_Size_FP3,SYS_STDIN)) != Real_Size_FP3) {
            if (rlen != 0)
                fprintf(stderr,"Bad EP header\n");
            return(0);
          }

          if (hdr.slicelength)
            packlen = hdr.slicelength; 
          else
            packlen = hdr.packetlength;

          hdr3.timestamp = ntohl(hdr3.timestamp);
     
          ptime->tv_sec  = mactime + (hdr3.timestamp / 1000); /*milliseconds div 1000*/
          ptime->tv_usec = 1000 * (hdr3.timestamp % 1000);

          *plen          = hdr.packetlength;
          /* hmmm... I guess 0 bytes means that they grabbed the whole */
          /* packet.  Seems to work that way... sdo - Thu Feb 13, 1997 */
          if (hdr.slicelength)
            *ptlen = hdr.slicelength;
          else
            *ptlen = hdr.packetlength;
      } else { /* version 7 */
          struct PeekPacket_v7 hdrv7;

          if ((rlen=fread(&hdrv7,sizeof(hdrv7),1,SYS_STDIN)) != 1) {
            if (rlen != 0)
                fprintf(stderr,"Bad EP V7 header (rlen is %d)\n", rlen);
            return(0);
          }

          hdrv7.packetlength = ntohs(hdrv7.packetlength);
          hdrv7.slicelength = ntohs(hdrv7.slicelength);

          if (hdrv7.slicelength)
            packlen = hdrv7.slicelength; 
          else
            packlen = hdrv7.packetlength;

          /* file save version 7 time is NOT an offset, it's a 64 bit counter in microseconds */
#ifdef HAVE_LONG_LONG
          {  /* not everybody has LONG LONG now */
            unsigned long long int usecs;

            /* avoid ugly alignment problems */
            usecs = ntohl(hdrv7.timestamphi);
            usecs <<= 32;
            usecs |= ntohl(hdrv7.timestamplo);

            ptime->tv_sec  = usecs / 1000000 - Mac2unix;
            ptime->tv_usec = usecs % 1000000;
          }
#else /* HAVE_LONG_LONG */
          {
            double usecs;

            /* secs is hard because I don't want to depend on "long long" */
            /* which isn't universal yet.  "float" probably isn't enough */
            /* signigicant figures to make this work, so I'll do it in */
            /* (slow) double precision :-(  */
            usecs = (double)hdrv7.timestamphi * (65536.0 * 65536.0);
            usecs += (double)hdrv7.timestamplo;
            usecs -= (double)Mac2unix*1000000.0;
            ptime->tv_sec  = usecs/1000000.0;

            /* usecs is easier, the part we want is all in the lower word */
            ptime->tv_usec = usecs - (double)ptime->tv_sec * 1000000.0;
          }
#endif /* HAVE_LONG_LONG */


          *plen          = hdrv7.packetlength;
          /* hmmm... I guess 0 bytes means that they grabbed the whole */
          /* packet.  Seems to work that way... sdo - Thu Feb 13, 1997 */
          if (hdrv7.slicelength)
            *ptlen = hdrv7.slicelength;
          else
            *ptlen = hdrv7.packetlength;

          if (debug>1) {
            printf("File position: %ld\n", ftell(SYS_STDIN));
            printf("pread_EP (v7) next packet:\n");
            printf("  packetlength: %d\n", hdrv7.packetlength);
            printf("  slicelength:  %d\n", hdrv7.slicelength);
            printf("  packlen:      %d\n", packlen);
            printf("  time:         %s\n", ts2ascii_date(ptime));
          }
      }


      len= packlen;

      /* read the ethernet header */
      rlen=fread(pep,1,sizeof(struct ether_header),SYS_STDIN);
      if (rlen != sizeof(struct ether_header)) {
          fprintf(stderr,"Couldn't read ether header\n");
          return(0);
      }


      if (debug > 3) {
          PrintRawDataHex("EP_READ: Ethernet Dump", pep, (char *)(pep+1)-1);
      }

      /* read the rest of the packet */
      len -= sizeof(struct ether_header);
      if (len >= IP_MAXPACKET) {
          /* sanity check */
          fprintf(stderr,
                "pread_EP: invalid next packet, IP len is %d, return EOF\n", len);
          return(0);
      }
      if ((rlen=fread(pip_buf,1,len,SYS_STDIN)) != len) {
          if (rlen != 0)
            if (debug)
                fprintf(stderr,
                      "Couldn't read %d more bytes, skipping last packet\n",
                      len);
          return(0);
      }

      if (debug > 3)
          PrintRawDataHex("EP_READ: IP Dump", pip_buf, (char *)pip_buf+len-1);

      /* round to 2 bytes for V7 */
      if (EP_V7) {
          if (len%2 != 0) {
            /* can't SEEK, because this might be a pipe!! */
            (void) fgetc(SYS_STDIN);
          }
      }

      *ppip  = (struct ip *) pip_buf;
      *pplast = (char *)pip_buf+len-1; /* last byte in the IP packet */
      *pphys  = pep;
      *pphystype = PHYS_ETHER;

      /* if it's not IP, then skip it */
      if ((ntohs(pep->ether_type) != ETHERTYPE_IP) &&
          (ntohs(pep->ether_type) != ETHERTYPE_IPV6)) {
          if (debug > 2)
            fprintf(stderr,"pread_EP: not an IP packet\n");
          continue;
      }

      return(1);
    }
}



/* is the input file a Ether Peek format file?? */
pread_f *is_EP(char *filename)
{
    int rlen;

#ifdef __WIN32
    if((fp = fopen(filename, "r")) == NULL) {
       perror(filename);
       exit(-1);
    }
#endif /* __WIN32 */   

    /* read the EP file header */
    if ((rlen=fread(&file_header,1,Real_Size_FH,SYS_STDIN)) != Real_Size_FH) {
      rewind(SYS_STDIN);
      return(NULL);
    }
    /*rewind(SYS_STDIN);  I might need this*/
    if ((rlen=fread(&file_header2,1,Real_Size_FH2,SYS_STDIN)) != Real_Size_FH2) {
      rewind(SYS_STDIN);
      return(NULL);
    }

    /* byte swapping */
    file_header2.length = ntohl(file_header2.length);
    file_header2.numPackets = ntohl(file_header2.numPackets);
    file_header2.timeDate = ntohl(file_header2.timeDate);
    file_header2.timeStart = ntohl(file_header2.timeStart);
    file_header2.timeStop = ntohl(file_header2.timeStop);
    
    mactime=file_header2.timeDate - Mac2unix;  /*get time plus offset to unix time */
    /********** File header info ********************************/
    if (debug>1) {
      int i;
      
      fprintf(stderr, "IS_EP says version number %d \n",file_header.version);
      fprintf(stderr, "IS_EP says status number %d\n",file_header.status);
      fprintf(stderr, "IS_EP says length number %ld\n",file_header2.length);
      fprintf(stderr, "IS_EP says num packets number %ld \n",file_header2.numPackets);
      fprintf(stderr, "IS_EP says time date in mac format %lu \n", (tt_uint32)file_header2.timeDate);
      fprintf(stderr, "IS_EP says time start  %lu \n",file_header2.timeStart);
      fprintf(stderr, "IS_EP says time stop %lu \n",file_header2.timeStop);
      fprintf(stderr, "future is: ");
      for(i=0;i<7;i++)
          fprintf(stderr, " %ld ",file_header2.futureUse[i]);
      fprintf(stderr, "\n");
      fprintf(stderr, "RLEN is %d \n",rlen);
    }


    /* check for EP file format */
    /* Note, there's no "magic number" here, so this is just a heuristic :-( */
    if ((file_header.version == VERSION_7 ||
       file_header.version == VERSION_6 ||
       file_header.version == VERSION_5) &&
      (file_header.status == 0) &&
      (memcmp(file_header2.futureUse,"\000\000\000\000\000\000\000",7) == 0)) {
      if (debug)
          fprintf(stderr, "Valid Etherpeek format file (file version: %d)\n",
               file_header.version);
      thisfile_ep_version = file_header.version;

    } else {
      if (debug)
          fprintf(stderr,"I don't think this is version 5, 6, or 7 Ether Peek File\n");

      return(NULL);
    } 

    /* OK, it's mine.  Init some stuff */
    pep = MallocZ(sizeof(struct ether_header));
    pip_buf = MallocZ(IP_MAXPACKET);
    

    return(pread_EP);
}

#endif /* GROK_ETHERPEEK */

Generated by  Doxygen 1.6.0   Back to index