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/capture.c,v 1.2 1993/04/22 20:14:24 martinh Exp $ (UW)";
37 #endif
38
39 #include <stdio.h>
40 #include <sys/types.h>
41 #include <sys/time.h>
42 #include <sys/wait.h>
43 #include <signal.h>
44
45 #include <X11/IntrinsicP.h>
46 #include <X11/StringDefs.h>
47 #include <X11/CoreP.h>
48 #include <Xm/Xm.h>
49 #include <Xm/Frame.h>
50 #include <Xm/MessageB.h>
51 #include <Xm/RowColumn.h>
52 #include <Xm/Separator.h>
53 #include <Xm/ToggleB.h>
54 #include <Xm/BulletinB.h>
55 #include <Xm/SelectioB.h>
56 #include <Xm/TextF.h>
57 #include <Xm/Form.h>
58
59 #include "net/bpf.h"
60 #include "interface.h"
61 #include "tcpview.h"
62 #include "motif.h"
63 #include "filter.h"
64
65 #ifdef __STDC__
66 struct bpf_program *parse(char *, int, int, u_long); /* gencode.c */
67 void readfile(char *);
68 static void max_bytes_callback( Widget, caddr_t, caddr_t );
69 static void time_limit_callback( Widget, caddr_t, caddr_t );
70 static void num_frame_callback( Widget, caddr_t, caddr_t );
71 static void device_callback( Widget, caddr_t, caddr_t );
72 static void prom_callback( Widget, caddr_t, caddr_t );
73 static void done_callback( Widget, caddr_t, caddr_t );
74 static void cancel_callback( Widget, caddr_t, caddr_t );
75 static void dev_cancel( Widget, caddr_t, caddr_t );
76 #else
77 struct bpf_program *parse(); /* gencode.c */
78 void readfile();
79 static void max_bytes_callback();
80 static void time_limit_callback();
81 static void num_frame_callback();
82 static void device_callback();
83 static void prom_callback();
84 static void done_callback();
85 static void cancel_callback();
86 static void dev_cancel();
87 #endif /* __STDC__ */
88
89 static int if_fd;
90 static char *strbuf;
91 static Widget Work, bb_widget, mb_widget, tl_widget, nf_widget, dev_widget, pr_widget;
92 static char *TempName;
93 static XtIntervalId TimeoutID = 0;
94 static char StderrName[64];
95
96 /* global configuration variables */
97 int MaxBytes;
98 char *Device=0;
99
100 static long TimeLimit = 0;
101 static long NumberOfFrames = -1;
102 static char *promstring[] = { "ON", "OFF" } ;
103 static u_short mb_semaphore;
104 static u_short tl_semaphore;
105 static u_short nf_semaphore;
106 static u_short dev_semaphore;
107
ltos(num)108 char *ltos( num )
109 long num;
110 {
111 static char str[32];
112 sprintf(str,"%d",num);
113 return( str );
114 }
115
cap_opt_callback(widget,name,call_data)116 void cap_opt_callback( widget, name, call_data )
117 Widget widget;
118 char *name;
119 caddr_t call_data;
120 {
121 Widget ok, main_row, frame, rc, rd;
122 int n;
123 Arg args[5];
124
125 mb_semaphore = tl_semaphore = nf_semaphore = dev_semaphore = 0;
126
127 n=0;
128 XtSetArg( args[n], XmNautoUnmanage, False ); n++;
129 XtSetArg( args[n], XmNdialogStyle, XmDIALOG_PRIMARY_APPLICATION_MODAL ); n++;
130 bb_widget = XmCreateBulletinBoardDialog (widget,"capture_options",args,n);
131
132 n = 0;
133 XtSetArg( args[n], XmNorientation, XmVERTICAL ); n++;
134 main_row = XmCreateRowColumn( bb_widget,"main",args,n);
135 XtManageChild( main_row );
136
137 n=0;
138 XtSetArg ( args[n], XmNshadowThickness, 4 ); n++;
139 frame = XmCreateFrame (main_row,"frame",args,n);
140 XtManageChild(frame);
141
142 n = 0;
143 XtSetArg( args[n], XmNorientation, XmVERTICAL ); n++;
144 rc = XmCreateRowColumn( frame,"row",args,n);
145 XtManageChild( rc );
146
147 n=0;
148 CreateLabelWidget( rc, "interface_opts"," INTERFACE OPTIONS ", args, n );
149 XmCreateSeparator( rc, "sep", args, n );
150
151 n=0;
152 XtSetArg( args[n], XmNorientation, XmHORIZONTAL ); n++;
153 rd = XmCreateRowColumn( rc,"data",args,n);
154 XtManageChild( rd );
155 CreateLabelWidget( rd, "device", "Device Name ", args, 0 );
156 if( Device == NULL ) {
157 Device = lookup_device();
158 if( Device == NULL )
159 eprint("Can't find any interfaces");
160 }
161 dev_widget = CreateSimpleButton( rd, Device, device_callback, (caddr_t)0 );
162
163 n=0;
164 XtSetArg( args[n], XmNorientation, XmHORIZONTAL ); n++;
165 rd = XmCreateRowColumn( rc,"rd",args,n);
166 XtManageChild( rd );
167 CreateLabelWidget( rd, "prom_mode", "Promiscuous Mode ", args, 0 );
168 pr_widget = CreateSimpleButton( rd, promstring[pflag], prom_callback, NULL );
169
170 n=0;
171 XtSetArg ( args[n], XmNshadowThickness, 4 ); n++;
172 frame = XmCreateFrame (main_row,"frame",args,n);
173 XtManageChild(frame);
174
175 n = 0;
176 XtSetArg( args[n], XmNorientation, XmVERTICAL ); n++;
177 rc = XmCreateRowColumn( frame,"row2",args,n);
178 XtManageChild( rc );
179
180 n=0;
181 CreateLabelWidget( rc, "cap_opts"," CAPTURE OPTIONS ", args, n );
182 XmCreateSeparator( rc, "sep", args, n );
183
184 n=0;
185 XtSetArg( args[n], XmNorientation, XmHORIZONTAL ); n++;
186 rd = XmCreateRowColumn( rc,"data",args,n);
187 XtManageChild( rd );
188 CreateLabelWidget( rd, "frame_num", "Number of Frames ", args, 0 );
189 if( NumberOfFrames > 0 )
190 nf_widget = CreateSimpleButton( rd, ltos(NumberOfFrames), num_frame_callback, (caddr_t)0 );
191 else
192 nf_widget = CreateSimpleButton( rd, "infinite", num_frame_callback, (caddr_t)0 );
193
194 n=0;
195 XtSetArg( args[n], XmNorientation, XmHORIZONTAL ); n++;
196 rd = XmCreateRowColumn( rc,"data",args,n);
197 XtManageChild( rd );
198 CreateLabelWidget( rd, "time", "Time Limit ", args, n );
199 if( TimeLimit > 0 )
200 tl_widget = CreateSimpleButton( rd, ltos(TimeLimit), time_limit_callback, (caddr_t)0 );
201 else
202 tl_widget = CreateSimpleButton( rd, "infinite", time_limit_callback, (caddr_t)0 );
203 CreateLabelWidget( rd, "time_sec", " seconds", args, 0 );
204
205 n=0;
206 XtSetArg( args[n], XmNorientation, XmHORIZONTAL ); n++;
207 rd = XmCreateRowColumn( rc,"data",args,n);
208 XtManageChild( rd );
209 CreateLabelWidget( rd, "bytes", "Max Bytes Per Frame ", args, 0 );
210 mb_widget = CreateSimpleButton( rd, ltos(MaxBytes), max_bytes_callback, (caddr_t)0 );
211
212 /* create 'OK' pushbutton */
213 n = 0;
214 ok = CreatePushButton( main_row, "done", " DONE ", args, n, done_callback);
215
216 /* Set OK button as default */
217 BulletinDefaultButton( bb_widget, ok );
218
219 XtManageChild( bb_widget );
220 } /* cap_opt_callback */
221
get_long(parent,def,name,title,callback,semaphore)222 void get_long( parent, def, name, title, callback, semaphore )
223 Widget parent;
224 long def;
225 char *name, *title;
226 void (*callback)();
227 u_short *semaphore;
228 {
229 Widget w;
230 Arg args[2];
231 int n;
232 XmString ms, ms2;
233
234 ms = XmStringCreateSimple(title);
235 ms2 = XmStringCreateSimple( ltos(def) );
236 n = 0;
237 XtSetArg (args[n], XmNselectionLabelString, ms); n++;
238 if( def > 0 ) {
239 XtSetArg (args[n], XmNtextString, ms2); n++;
240 }
241 w = XmCreatePromptDialog( bb_widget, name ,args,n);
242 XtAddCallback( w, XmNokCallback, (*callback), (caddr_t)0);
243 XtAddCallback( w, XmNcancelCallback, cancel_callback, semaphore);
244 XtAddCallback( w, XmNunmapCallback, cancel_callback, semaphore);
245 XtManageChild( w );
246 XmStringFree( ms );
247 XmStringFree( ms2 );
248 }
249
250
251
mb_result(widget,data,foo)252 static void mb_result( widget, data, foo )
253 Widget widget;
254 char *data;
255 XmSelectionBoxCallbackStruct *foo;
256 {
257 char *string;
258 XmStringGetLtoR( foo->value, XmSTRING_DEFAULT_CHARSET, &string);
259
260 /* make sure MaxBytes is not too small or too large */
261 MaxBytes = max(DEFAULT_SNAPLEN, atoi(string));
262 MaxBytes = min(MaxBytes, MAX_SNAPLEN);
263
264 SetLabel( mb_widget, ltos(MaxBytes) );
265 mb_semaphore = 0;
266 }
267
268
tl_result(widget,data,foo)269 static void tl_result( widget, data, foo )
270 Widget widget;
271 char *data;
272 XmSelectionBoxCallbackStruct *foo;
273 {
274 char *string;
275 XmStringGetLtoR( foo->value, XmSTRING_DEFAULT_CHARSET, &string);
276 TimeLimit = atoi(string);
277 if( TimeLimit <= 0 )
278 SetLabel( tl_widget, "infinite" );
279 else
280 SetLabel( tl_widget, ltos(TimeLimit) );
281 tl_semaphore = 0;
282 }
283
nf_result(widget,data,foo)284 static void nf_result( widget, data, foo )
285 Widget widget;
286 char *data;
287 XmSelectionBoxCallbackStruct *foo;
288 {
289 char *string;
290 XmStringGetLtoR( foo->value, XmSTRING_DEFAULT_CHARSET, &string);
291 NumberOfFrames = atoi(string);
292 if( NumberOfFrames <= 0 ) {
293 NumberOfFrames = -1;
294 SetLabel( nf_widget, "infinite" );
295 } else
296 SetLabel( nf_widget, ltos(NumberOfFrames) );
297 nf_semaphore = 0;
298 }
299
300
dev_result(widget,data,foo)301 static void dev_result( widget, data, foo )
302 Widget widget;
303 char *data;
304 XmSelectionBoxCallbackStruct *foo;
305 {
306 char *string;
307 static char buf[16];
308
309 XmStringGetLtoR( foo->value, XmSTRING_DEFAULT_CHARSET, &string);
310 strcpy(buf, string);
311 Device = buf;
312 SetLabel( dev_widget, Device );
313 dev_semaphore = 0;
314 }
315
316
max_bytes_callback(widget,data,foo)317 static void max_bytes_callback( widget, data, foo )
318 Widget widget;
319 caddr_t data;
320 caddr_t foo;
321 {
322 if( mb_semaphore )
323 return;
324 mb_semaphore = 1;
325 get_long( widget, MaxBytes,
326 "max_bytes",
327 "Maximum Number of Bytes to Capture Per Frame",
328 mb_result, &mb_semaphore );
329 }
330
time_limit_callback(widget,data,foo)331 static void time_limit_callback( widget, data, foo )
332 Widget widget;
333 caddr_t data;
334 caddr_t foo;
335 {
336 if( tl_semaphore )
337 return;
338 tl_semaphore = 1;
339 get_long( widget, TimeLimit,
340 "time_limit",
341 "Time Limit for Capture in Seconds",
342 tl_result, &tl_semaphore );
343 }
344
num_frame_callback(widget,data,foo)345 static void num_frame_callback( widget, data, foo )
346 Widget widget;
347 caddr_t data;
348 caddr_t foo;
349 {
350 if( nf_semaphore )
351 return;
352 nf_semaphore = 1;
353 get_long( widget, NumberOfFrames,
354 "number_frames",
355 "Number of Frames to Capture",
356 nf_result, &nf_semaphore );
357 }
358
359
prom_callback(widget,data,foo)360 static void prom_callback( widget, data, foo )
361 Widget widget;
362 caddr_t data;
363 caddr_t foo;
364 {
365 if( pflag )
366 pflag = 0;
367 else
368 pflag = 1;
369 SetLabel( pr_widget, promstring[pflag]);
370 }
371
done_callback(widget,data,foo)372 static void done_callback( widget, data, foo )
373 Widget widget;
374 caddr_t data;
375 caddr_t foo;
376 {
377 XtUnmanageChild( bb_widget );
378 }
379
cancel_callback(widget,data,foo)380 static void cancel_callback( widget, data, foo )
381 Widget widget;
382 caddr_t data;
383 caddr_t foo;
384 {
385 *data = 0;
386 XtUnmanageChild(widget);
387 }
388
dev_cancel(widget,data,foo)389 static void dev_cancel( widget, data, foo )
390 Widget widget;
391 caddr_t data;
392 caddr_t foo;
393 {
394 dev_semaphore = 0;
395 XtUnmanageChild(widget);
396 }
397
device_callback(parent,data,foo)398 static void device_callback( parent, data, foo )
399 Widget parent;
400 caddr_t data;
401 caddr_t foo;
402 {
403 Widget w;
404 Arg args[2];
405 int n;
406 XmString ms, ms2;
407
408 if( dev_semaphore )
409 return;
410 dev_semaphore = 1;
411
412 ms = XmStringCreateSimple("Network Device Name");
413 if( Device )
414 ms2 = XmStringCreateSimple( Device );
415 else
416 ms2 = XmStringCreateSimple("");
417 n = 0;
418 XtSetArg (args[n], XmNselectionLabelString, ms); n++;
419 XtSetArg (args[n], XmNtextString, ms2); n++;
420 w = XmCreatePromptDialog( parent, "dev" ,args,n);
421 XtAddCallback( w, XmNokCallback, dev_result, (caddr_t)0);
422 XtAddCallback( w, XmNcancelCallback, dev_cancel, (caddr_t)0);
423 XtManageChild( w );
424 XmStringFree( ms );
425 XmStringFree( ms2 );
426 }
427
428
end_capture()429 static void end_capture()
430 {
431 if( if_fd >= 0)
432 wrapup(if_fd);
433 *StrPtr = 0;
434 sf_write_end();
435 exit(0);
436 }
437
438 u_short DoneWithCapture;
439
child_end()440 static void child_end()
441 {
442 int status;
443 FILE *fp;
444 int num;
445 char buf[512];
446
447 if( Work) XtUnrealizeWidget( Work );
448 DoneWithCapture = 1;
449 signal( SIGCHLD, SIG_IGN);
450 (void)wait(&status);
451 /* fprintf(stderr,"child exited with status %d\n",WEXITSTATUS(status)); */
452
453 fp = fopen(StderrName,"r");
454 if( fp ) {
455 num = fread( buf, 1, sizeof(buf), fp );
456 if( num ) {
457 buf[num]='\0';
458 eprint( buf );
459 }
460 unlink( StderrName );
461 fclose( fp );
462 }
463 if( WEXITSTATUS(status) == 0 )
464 readfile( TempName );
465 unlink( TempName );
466 }
467
468 /* semaphore */
469 static u_short Stopped=0;
470
stop_capture_callback(widget,data,call_data)471 static void stop_capture_callback( widget, data, call_data )
472 Widget widget;
473 caddr_t data;
474 caddr_t call_data;
475 {
476 Stopped = 1;
477 if( kill( (pid_t)data, SIGINT ) < 0 )
478 xperror("kill");
479 if( TimeoutID ) {
480 XtRemoveTimeOut( TimeoutID );
481 TimeoutID = 0;
482 }
483 Stopped = 0;
484 }
485
timer_expired(data,id)486 static void timer_expired( data, id )
487 caddr_t data;
488 XtIntervalId *id;
489 {
490 if( Stopped )
491 return;
492 TimeoutID = 0;
493 (void)kill( (pid_t)data, SIGINT );
494 }
495
capture_callback(widget,name,call_data)496 void capture_callback( widget, name, call_data )
497 Widget widget;
498 char *name;
499 caddr_t call_data;
500 {
501 u_long netmask, localnet;
502 struct bpf_program *bpf;
503 pid_t pid;
504 extern long thiszone;
505 extern int snaplen, Linktype, Precision;
506
507 DoneWithCapture = 0;
508 Work = NULL;
509
510 {
511 struct timeval now;
512 struct timezone tz;
513
514 if (gettimeofday(&now, &tz) < 0) {
515 xperror("tcpdump: gettimeofday");
516 exit(1);
517 }
518 thiszone = tz.tz_minuteswest * -60;
519 if (localtime((time_t *)&now.tv_sec)->tm_isdst)
520 thiszone += 3600;
521 }
522 Precision = clock_sigfigs();
523
524 /* this should come from the capture options */
525 /* default and max should be based on DLC */
526 snaplen = MaxBytes;
527
528 /* pick a temporary name for stderr */
529 strcpy(StderrName,tmpnam(NULL));
530
531 /* pick a temporary name to save frames to */
532 TempName = tmpnam(NULL);
533
534 update_fstr(&Filter);
535
536 (void)signal( SIGCHLD, child_end );
537
538 if( (pid = fork()) < 0 ) {
539 eprint("Problem forking capture process");
540 return;
541 }
542 if( pid == 0 ) {
543
544 /* send stderr to a temp file */
545 (void)freopen(StderrName,"w",stderr);
546
547 if( Device == NULL ) {
548 Device = lookup_device();
549 if( Device == NULL ) {
550 eprint("Can't find device");
551 exit(1);
552 }
553 }
554 if_fd = initdevice( Device, pflag, &Linktype );
555 lookup_net( Device, &localnet, &netmask );
556 bpf = parse( Fstr, 1, Linktype, netmask );
557
558 /* set up printf buffer */
559 StrPtr = strbuf = malloc(512);
560
561 sf_write_init( TempName, Linktype, thiszone, snaplen, Precision );
562 (void)signal( SIGTERM, end_capture );
563 (void)signal( SIGINT, end_capture );
564 (void)signal( SIGHUP, end_capture );
565 readloop( NumberOfFrames, if_fd, bpf, sf_write );
566 end_capture();
567 } else { /* parent */
568 XmString ms, ms_stop;
569 Arg args[2];
570 int n;
571
572 if( TimeLimit > 0 )
573 TimeoutID = XtAddTimeOut( TimeLimit*1000, timer_expired, (caddr_t)pid );
574
575 /* now create a dialog with "Stop" button */
576 ms = XmStringCreateSimple( "Capturing");
577 ms_stop = XmStringCreateSimple( "STOP" );
578 n = 0;
579 XtSetArg( args[n], XmNmessageString, ms ); n++;
580 XtSetArg( args[n], XmNokLabelString, ms_stop ); n++;
581 Work = XmCreateWorkingDialog( widget,"STOP",args,n );
582 RemoveDialButton( Work, XmDIALOG_HELP_BUTTON );
583 RemoveDialButton( Work, XmDIALOG_CANCEL_BUTTON );
584 XtAddCallback( Work, XmNokCallback,stop_capture_callback, (caddr_t)pid );
585
586 if( !DoneWithCapture )
587 XtManageChild( Work );
588
589 XmStringFree( ms );
590 XmStringFree( ms_stop );
591 }
592 } /* capture_callback */
593
594
595