1 /*
2  * TCPVIEW
3  *
4  * Author:	Martin Hunt
5  *		Networks and Distributed Computing
6  *		Computing & Communications
7  *		University of Washington
8  *		Administration Building, AG-44
9  *		Seattle, WA  98195
10  *		Internet: martinh@cac.washington.edu
11  *
12  *
13  * Copyright 1992 by the University of Washington
14  *
15  * Permission to use, copy, modify, and distribute this software and its
16  * documentation for any purpose and without fee is hereby granted, provided
17  * that the above copyright notice appears in all copies and that both the
18  * above copyright notice and this permission notice appear in supporting
19  * documentation, and that the name of the University of Washington not be
20  * used in advertising or publicity pertaining to distribution of the software
21  * without specific, written prior permission.  This software is made
22  * available "as is", and
23  * THE UNIVERSITY OF WASHINGTON DISCLAIMS ALL WARRANTIES, EXPRESS OR IMPLIED,
24  * WITH REGARD TO THIS SOFTWARE, INCLUDING WITHOUT LIMITATION ALL IMPLIED
25  * WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE, AND IN
26  * NO EVENT SHALL THE UNIVERSITY OF WASHINGTON BE LIABLE FOR ANY SPECIAL,
27  * INDIRECT OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES WHATSOEVER RESULTING FROM
28  * LOSS OF USE, DATA OR PROFITS, WHETHER IN AN ACTION OF CONTRACT, TORT
29  * (INCLUDING NEGLIGENCE) OR STRICT LIABILITY, ARISING OUT OF OR IN CONNECTION
30  * WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
31  *
32  */
33 
34 #ifndef lint
35 static char rcsid[] =
36     "@(#) $Header: /usr/staff/martinh/tcpview/RCS/sniffer_file.c,v 1.3 1993/04/22 20:35:19 martinh Exp $ (UW)";
37 #endif
38 
39 /*
40  * routines to write and playback a Network General "Sniffer" compatible file
41  * through tcpdump.  Most of the information about Sniffer files came from the
42  * Sniffer documentation.  Some was gained by squinting at hex dumps.
43  *
44  * This code is brought to you by Corey Satten, corey@cac.wasnington.edu
45  * and Martin Hunt, martinh@cac.washington.edu.  The ifdefs are optional
46  * and for speed, of course.
47  */
48 
49 #include <stdio.h>
50 #include <sys/types.h>
51 #include <sys/time.h>
52 #include <math.h>
53 #include <string.h>
54 #include <net/bpf.h>
55 #include "version.h"
56 #include "savefile.h"
57 
58 #define MAXPKT 1600				/* >= any ether pkt */
59 
60 static short byte_order = 0x100;
61 static int low_offset;				/* where is low byte in short */
62 static int high_offset;				/* where is hi byte in short */
63 
64 /*
65  * The following moves byte-order determination from runtime to compile-time
66  * if known.  Don't worry, if you don't know, it will still work.
67  */
68 #if defined(vax)||defined(mips)||defined(i386)
69 # define LOW_OFFSET 0
70 # define HIGH_OFFSET 1
71 #endif
72 #if defined(mc68000)||defined(sparc)
73 # define LOW_OFFSET 1
74 # define HIGH_OFFSET 0
75 #endif
76 #if !defined(HIGH_OFFSET)||!defined(LOW_OFFSET)
77 # define LOW_OFFSET low_offset
78 # define HIGH_OFFSET high_offset
79 #endif
80 
81 /*
82  * x should be of static storage class.  If HIGH/LOW_OFFSET is constant,
83  * these should result in compile-time access to the proper byte.
84  */
85 #define low(x) (*(((char *)&(x))+LOW_OFFSET))
86 #define high(x) (*(((char *)&(x))+HIGH_OFFSET))
87 #define putbs(x,f) putc(low(x),f); putc(high(x),f)
88 #define getbs(x,f) low(x)=getc(f); high(x)=getc(f)
89 
90 static void hdr_load(), hdr_print(), dh_print(), ver_print(), dh_load();
91 
92 static FILE *sfd;		/* sniffer output file descriptor */
93 static FILE *rfd;		/* sniffer input file descriptor  */
94 
95 static int TimeZoneOffset;	/* number of seconds from GMT */
96 
97 static int frame_count = 0;	/* number of records written to sniffer file */
98 static long last_offset = 0;	/* position of start of last complete record */
99 
100 static char s_magic[] = {	/* magic header */
101 'T', 'R', 'S', 'N', 'I', 'F', 'F', ' ', 'd', 'a', 't', 'a', ' ', ' ', ' ', ' ',
102 0x1a };
103 
104 /*
105  * putting the two structures all in one big structure allows us to
106  * fwrite the entire structure at once for a substantial speedup on
107  * little-endian machines (vax, etc)
108  */
109 static struct s {
110   struct s_hdr {			/* data record header */
111     short type;
112     short len;
113     short rsvd;
114   } s_hdr;
115 
116   struct s_dh {			/* record data header */
117     ushort time_low;
118     ushort time_med;
119     ushort time_high;
120     short  size;
121     char   fs;
122     char   flags;
123     short  truesize;
124     short  rsvd;
125   } s_dh;
126 
127 } s = { {4, 0, 0}, {0, 0, 0, 0, 0, 0x1c, 0, 0} };
128 
129 static struct v {
130   short maj_vers;     /* major version number */
131   short min_vers;     /* minor version number */
132   short time;
133   short date;
134   char type;
135   char network;       /* network type */
136   char format;
137   char timeunit;      /* timestamp units */
138   short rsvd[3];      /* reserved */
139 } V;
140 
141 /* values for V.timeunit */
142 double Usec[] = { 15.0, 0.838096, 15.0, 0.5, 2.0 };
143 double Timeunit;
144 
145 /* initializes reading.
146 ** returns SFERR_BADF if incorrect file type, -1 on open failure, 0 otherwise
147 */
148 int
sniff_rinit(name,linktypep,thiszonep,snaplenp,precisionp)149 sniff_rinit(name, linktypep, thiszonep, snaplenp, precisionp)
150 char *name;
151 int *linktypep, *thiszonep, *snaplenp, *precisionp;
152 {
153   char buf[128];
154 
155   void print2hexwindow();
156 
157   /* Sniffer saves times in local format */
158   *thiszonep = 0;
159 
160   low_offset = *(((char *)&(byte_order))+0);
161   high_offset = *(((char *)&(byte_order))+1);
162 
163   /* the Sniffer file format doesn't give the max frame size */
164   /* Each frame has a true size and a stored size, so we */
165   /* have to set 'snaplen' to the max possible size */
166   *snaplenp = MAXPKT;
167 
168   if (name[0]=='-' && name[1]=='\0')
169     rfd = stdin;
170   else if ( !(rfd=fopen(name, "r")) ) {
171     fprintf(stderr,"tcpdump: fopen: ");
172     perror(name);
173     return(1);
174   }
175 
176   /* read in magic header */
177   fread(buf,sizeof(s_magic),1,rfd);
178   if(strncmp(buf,s_magic,sizeof(s_magic)))
179     return SFERR_BADF;  /* no magic header found */
180 
181   hdr_load();
182   if (s.s_hdr.type != 1 )       /* version record should be next */
183     return SFERR_BADF;
184   getbs(V.maj_vers, rfd);
185   getbs(V.min_vers, rfd);
186   getbs(V.time, rfd);
187   getbs(V.date, rfd);
188   V.type = getc(rfd);
189   V.network = getc(rfd);
190   V.format = getc(rfd);
191   V.timeunit = getc(rfd);
192   getbs(V.rsvd[0], rfd);
193   getbs(V.rsvd[1], rfd);
194   getbs(V.rsvd[2], rfd);
195 
196   sprintf(buf,"Sniffer save file\nCreated by Version %d.%d on %d-%d-%d at %d:%d:%d",
197 	 V.maj_vers,V.min_vers,
198 	 ((V.date&0x1e0)>>5),(V.date&0x1f),
199 	 ((V.date&0xfe00)>>9)+1980,
200 	 (V.time&0xfc00)>>11,
201 	 (V.time&0x7e0)>>5,
202 	 (V.time&0x1f)<<1);
203 #ifdef TCPVIEW
204   print2hexwindow(buf);
205 #else
206   fputs(buf,stderr);
207 #endif
208 
209   if(V.timeunit==2)
210     *precisionp = 5;
211   else
212     *precisionp = 6;
213 
214   Timeunit = Usec[V.timeunit];
215 
216   if (linktypep) {
217     switch (V.network) {
218     case 1:
219       *linktypep = DLT_EN10MB;
220       break;
221     case 2:
222       *linktypep = DLT_ARCNET;
223       break;
224     case 7:
225       *linktypep = DLT_PPP;
226       break;
227     case 8:
228       *linktypep = DLT_SLIP;
229       break;
230     default:
231       *linktypep = 0;
232     }
233   }
234   return 0;
235 }
236 
sniff_winit(name,linktype,thiszone,snaplen,precision)237 int sniff_winit(name, linktype, thiszone, snaplen, precision)
238 char *name;
239 int linktype, thiszone, snaplen, precision;
240 {
241   time_t tt;
242   struct tm *t;
243 
244   TimeZoneOffset = thiszone;
245 
246   low_offset = *(((char *)&(byte_order))+0);
247   high_offset = *(((char *)&(byte_order))+1);
248 
249   frame_count = 0;
250 
251   if (name[0]=='-' && name[1]=='\0')
252     sfd = stdout;
253   else if ( !(sfd=fopen(name ? name : "snif.enc", "w")) ) {
254     fprintf(stderr,"tcpdump: fopen: ");
255     perror(name);
256 #ifdef TCPVIEW
257     return(1);
258 #else
259     exit(1);
260 #endif
261   }
262 
263   /* write the magic header */
264   fwrite(s_magic, sizeof(s_magic), 1, sfd);
265 
266   /* write a version header */
267   s.s_hdr.type = 1;
268   s.s_hdr.len = 18;
269   hdr_print();
270 
271   /* write the version record */
272   V.maj_vers = 3;
273   V.min_vers = 9;
274   (void)time( &tt );
275   t = localtime( &tt );
276   V.time = t->tm_sec>>1 | t->tm_min<<5 | t->tm_hour<<11;
277   V.date = t->tm_mday | (t->tm_mon+1)<<5 | (t->tm_year-80)<<9;
278   V.type = (char)4;
279 
280   switch ( linktype ) {
281   case DLT_EN10MB:
282     V.network = (char)1;
283     break;
284   case DLT_ARCNET:
285     V.network = (char)2;
286     break;
287   case DLT_SLIP:
288     V.network = (char)7;
289     break;
290   case DLT_PPP:
291     V.network = (char)8;
292     break;
293   default:
294     V.network = (char)9;
295     break;
296   }
297   V.format = (char)1;
298   if( precision > 5)
299     V.timeunit = (char)4;
300   else
301     V.timeunit = (char)2;
302   Timeunit = Usec[V.timeunit];
303   ver_print();
304 
305   /* write fake type 6 record */
306   /*    fwrite(s_sixrec, sizeof(s_sixrec), 1, sfd);
307   last_offset = sizeof(s_magic) + sizeof(s_sixrec) + sizeof(struct v) + 6; */
308 
309   last_offset = sizeof(s_magic) + sizeof(struct v) + 6;
310   s.s_hdr.type = 4;
311   return 0;
312 }
313 
sniff_end(mode)314 void sniff_end(mode)
315 char *mode;
316 {
317   if (*mode == 'w') {	/* end writing sniffer file */
318     s.s_hdr.type = 3;	/* EOF */
319     s.s_hdr.len = 0;
320     fseek(sfd, last_offset, 0);	/* undo any partial records */
321     hdr_print();
322     fclose(sfd);
323     fprintf(stderr,"wrote %d sniffer frames\n", frame_count);
324   }
325   if (*mode == 'r') {	/* end re-reading a sniffer file */
326     fclose(rfd);
327   }
328 }
329 
330 void
sniff_write(sp,tvp,length,caplen)331 sniff_write(sp, tvp, length, caplen)
332      u_char *sp;
333      struct timeval *tvp;
334      int length;
335      int caplen;
336 {
337   double t, x;
338   int days;
339   extern int Wflag;
340 
341   tvp->tv_sec += TimeZoneOffset;
342   x = 4.0*(double)(1<<30);
343 
344   t = (double)(tvp->tv_sec)*1.0e6 + (double)(tvp->tv_usec);
345   days = t/8.64e10;
346   t -= days*8.64e10;
347 
348   t /= Timeunit;
349   s.s_dh.time_high = (u_short)(t/x);
350   t -= (double)(s.s_dh.time_high)*x;
351   s.s_dh.time_med = (u_short)(t/(double)(1<<16));
352   s.s_dh.time_low = (u_short)(t - (double)(s.s_dh.time_med)*(double)(1<<16));
353   s.s_hdr.len = (s.s_dh.size = caplen) + 14;
354   s.s_dh.truesize = s.s_dh.size < length ? length : 0;
355 
356   if (HIGH_OFFSET)
357     fwrite(&s, sizeof(s), 1, sfd);
358   else
359     hdr_print(), dh_print();
360   fwrite(sp, s.s_dh.size, 1, sfd);
361   last_offset += sizeof(s.s_dh) + sizeof(s.s_hdr) + s.s_dh.size;
362   ++frame_count;
363 
364 #ifndef TCPVIEW
365   switch (Wflag) {
366   case 2:                         /* a dot to stderr */
367     write(2,".",1);
368     break;
369   case 3:                         /* the normal print too */
370     ether_if_print(sp, tvp, length, caplen);
371     break;
372   }
373 #endif
374 
375   return;
376 }
377 
378 #ifndef TCPVIEW
379 
sniff_read(filtp,cnt,snaplen,printit)380 int sniff_read(filtp, cnt, snaplen, printit)
381 struct bpf_program *filtp;
382 int cnt, snaplen;
383 void (*printit)();
384 {
385   struct packet_header h;
386   u_char *buf;
387   struct bpf_insn *fcode = filtp->bf_insns;
388 
389   buf = (u_char *)malloc(snaplen);
390   if (buf==NULL)
391     return 1;
392 
393   while(sniff_next_packet(&h, buf) == 0) {
394     if (bpf_filter(fcode,buf,h.len,h.caplen)) {
395       if (cnt >= 0 && --cnt < 0 )
396 	break;
397       (*printit)(buf, &h.ts, h.len, h.caplen);
398     }
399   }
400   free((char *)buf);
401   return 0;
402 }
403 #endif	/* not TCPVIEW */
404 
405 int
sniff_next_packet(hdr,buf,buflen)406 sniff_next_packet(hdr, buf, buflen)
407 struct packet_header *hdr;
408 u_char *buf;
409 int buflen;
410 {
411   double t,x;
412 
413   hdr_load();
414 
415   if (s.s_hdr.type == 3 || s.s_hdr.type == EOF )
416     return 1;
417 
418   if (s.s_hdr.type == 6 ) {      /* infamous type 6 header detected */
419     if(fread(buf,s.s_hdr.len,1,rfd)==0)
420       return 1;
421     return (sniff_next_packet(hdr,buf));
422   }
423 
424   dh_load();
425 
426   if(fread(buf, s.s_dh.size, 1, rfd)==0)
427     return 1;
428 
429   x = 4.0*(double)(1<<30);
430   t = (double)s.s_dh.time_low+(double)(s.s_dh.time_med)*65536.0 +
431     (double)s.s_dh.time_high*x;
432   t = t/1000000.0*Timeunit; /* set t equal to number of secs */
433 
434   hdr->ts.tv_sec = (long)t;
435   hdr->ts.tv_usec = (u_long)((t-(double)(hdr->ts.tv_sec))*1.0e6);
436 
437   hdr->len = s.s_dh.truesize ? s.s_dh.truesize : s.s_dh.size;
438   hdr->caplen = s.s_dh.size;
439 
440   return 0;
441 }
442 
443 static void
hdr_print()444 hdr_print() {
445 	register FILE *f = sfd;
446 
447 	putbs(s.s_hdr.type, f);
448 	putbs(s.s_hdr.len, f);
449 	putbs(s.s_hdr.rsvd, f);
450 }
451 
452 static void
hdr_load()453 hdr_load() {
454 	register FILE *f = rfd;
455 
456 	getbs(s.s_hdr.type, f);
457 	getbs(s.s_hdr.len, f);
458 	getbs(s.s_hdr.rsvd, f);
459 }
460 
461 static void
dh_print()462 dh_print() {
463 	register FILE *f = sfd;
464 
465 	putbs(s.s_dh.time_low, f);
466 	putbs(s.s_dh.time_med, f);
467 	putbs(s.s_dh.time_high, f);
468 	putbs(s.s_dh.size, f);
469 	putc(s.s_dh.fs, f);
470 	putc(s.s_dh.flags, f);
471 	putbs(s.s_dh.truesize, f);
472 	putbs(s.s_dh.rsvd, f);
473 }
474 
475 static void
ver_print()476 ver_print() {
477 	register FILE *f = sfd;
478 
479 	putbs(V.maj_vers, f);
480 	putbs(V.min_vers, f);
481 	putbs(V.time, f);
482 	putbs(V.date, f);
483 	putc(V.type, f);
484 	putc(V.network, f);
485 	putc(V.format, f);
486 	putc(V.timeunit, f);
487 	putbs(V.rsvd[1], f);
488 	putbs(V.rsvd[2], f);
489 	putbs(V.rsvd[3], f);
490 }
491 
492 static void
dh_load()493 dh_load() {
494 	register FILE *f = rfd;
495 
496 	getbs(s.s_dh.time_low, f);
497 	getbs(s.s_dh.time_med, f);
498 	getbs(s.s_dh.time_high, f);
499 	getbs(s.s_dh.size, f);
500 	s.s_dh.fs = getc(f);
501 	s.s_dh.flags = getc(f);
502 	getbs(s.s_dh.truesize, f);
503 	getbs(s.s_dh.rsvd, f);
504 }
505 
506 
507