/* * 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 */