/*
* 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 */
syntax highlighted by Code2HTML, v. 0.9.1