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