/* * TCPVIEW * * Author: Martin Hunt * Networks and Distributed Computing * Computing & Communications * University of Washington * Administration Building, AG-44 * Seattle, WA 98195 * Internet: martinh@cac.washington.edu * * * Copyright 1992 by the University of Washington * * Permission to use, copy, modify, and distribute this software and its * documentation for any purpose and without fee is hereby granted, provided * that the above copyright notice appears in all copies and that both the * above copyright notice and this permission notice appear in supporting * documentation, and that the name of the University of Washington not be * used in advertising or publicity pertaining to distribution of the software * without specific, written prior permission. This software is made * available "as is", and * THE UNIVERSITY OF WASHINGTON DISCLAIMS ALL WARRANTIES, EXPRESS OR IMPLIED, * WITH REGARD TO THIS SOFTWARE, INCLUDING WITHOUT LIMITATION ALL IMPLIED * WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE, AND IN * NO EVENT SHALL THE UNIVERSITY OF WASHINGTON BE LIABLE FOR ANY SPECIAL, * INDIRECT OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES WHATSOEVER RESULTING FROM * LOSS OF USE, DATA OR PROFITS, WHETHER IN AN ACTION OF CONTRACT, TORT * (INCLUDING NEGLIGENCE) OR STRICT LIABILITY, ARISING OUT OF OR IN CONNECTION * WITH THE USE OR PERFORMANCE OF THIS SOFTWARE. * */ #ifndef lint static char rcsid[] = "@(#) $Header: /usr/staff/martinh/tcpview/RCS/capture.c,v 1.2 1993/04/22 20:14:24 martinh Exp $ (UW)"; #endif #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include "net/bpf.h" #include "interface.h" #include "tcpview.h" #include "motif.h" #include "filter.h" #ifdef __STDC__ struct bpf_program *parse(char *, int, int, u_long); /* gencode.c */ void readfile(char *); char *malloc( int ); static void max_bytes_callback( Widget, caddr_t, caddr_t ); static void time_limit_callback( Widget, caddr_t, caddr_t ); static void num_frame_callback( Widget, caddr_t, caddr_t ); static void device_callback( Widget, caddr_t, caddr_t ); static void prom_callback( Widget, caddr_t, caddr_t ); static void done_callback( Widget, caddr_t, caddr_t ); static void cancel_callback( Widget, caddr_t, caddr_t ); static void dev_cancel( Widget, caddr_t, caddr_t ); #else struct bpf_program *parse(); /* gencode.c */ void readfile(); char *malloc(); static void max_bytes_callback(); static void time_limit_callback(); static void num_frame_callback(); static void device_callback(); static void prom_callback(); static void done_callback(); static void cancel_callback(); static void dev_cancel(); #endif /* __STDC__ */ static int if_fd; static char *strbuf; static Widget Work, bb_widget, mb_widget, tl_widget, nf_widget, dev_widget, pr_widget; static char *TempName; static XtIntervalId TimeoutID = 0; static char StderrName[64]; /* global configuration variables */ int MaxBytes; char *Device=0; static long TimeLimit = 0; static long NumberOfFrames = -1; static char *promstring[] = { "ON", "OFF" } ; static u_short mb_semaphore; static u_short tl_semaphore; static u_short nf_semaphore; static u_short dev_semaphore; char *ltos( num ) long num; { static char str[32]; sprintf(str,"%d",num); return( str ); } void cap_opt_callback( widget, name, call_data ) Widget widget; char *name; caddr_t call_data; { Widget ok, main_row, frame, rc, rd; int n; Arg args[5]; mb_semaphore = tl_semaphore = nf_semaphore = dev_semaphore = 0; n=0; XtSetArg( args[n], XmNautoUnmanage, False ); n++; XtSetArg( args[n], XmNdialogStyle, XmDIALOG_PRIMARY_APPLICATION_MODAL ); n++; bb_widget = XmCreateBulletinBoardDialog (widget,"capture_options",args,n); n = 0; XtSetArg( args[n], XmNorientation, XmVERTICAL ); n++; main_row = XmCreateRowColumn( bb_widget,"main",args,n); XtManageChild( main_row ); n=0; XtSetArg ( args[n], XmNshadowThickness, 4 ); n++; frame = XmCreateFrame (main_row,"frame",args,n); XtManageChild(frame); n = 0; XtSetArg( args[n], XmNorientation, XmVERTICAL ); n++; rc = XmCreateRowColumn( frame,"row",args,n); XtManageChild( rc ); n=0; CreateLabelWidget( rc, "interface_opts"," INTERFACE OPTIONS ", args, n ); XmCreateSeparator( rc, "sep", args, n ); n=0; XtSetArg( args[n], XmNorientation, XmHORIZONTAL ); n++; rd = XmCreateRowColumn( rc,"data",args,n); XtManageChild( rd ); CreateLabelWidget( rd, "device", "Device Name ", args, 0 ); if( Device == NULL ) { Device = lookup_device(); if( Device == NULL ) eprint("Can't find any interfaces"); } dev_widget = CreateSimpleButton( rd, Device, device_callback, (caddr_t)0 ); n=0; XtSetArg( args[n], XmNorientation, XmHORIZONTAL ); n++; rd = XmCreateRowColumn( rc,"rd",args,n); XtManageChild( rd ); CreateLabelWidget( rd, "prom_mode", "Promiscuous Mode ", args, 0 ); pr_widget = CreateSimpleButton( rd, promstring[pflag], prom_callback, NULL ); n=0; XtSetArg ( args[n], XmNshadowThickness, 4 ); n++; frame = XmCreateFrame (main_row,"frame",args,n); XtManageChild(frame); n = 0; XtSetArg( args[n], XmNorientation, XmVERTICAL ); n++; rc = XmCreateRowColumn( frame,"row2",args,n); XtManageChild( rc ); n=0; CreateLabelWidget( rc, "cap_opts"," CAPTURE OPTIONS ", args, n ); XmCreateSeparator( rc, "sep", args, n ); n=0; XtSetArg( args[n], XmNorientation, XmHORIZONTAL ); n++; rd = XmCreateRowColumn( rc,"data",args,n); XtManageChild( rd ); CreateLabelWidget( rd, "frame_num", "Number of Frames ", args, 0 ); if( NumberOfFrames > 0 ) nf_widget = CreateSimpleButton( rd, ltos(NumberOfFrames), num_frame_callback, (caddr_t)0 ); else nf_widget = CreateSimpleButton( rd, "infinite", num_frame_callback, (caddr_t)0 ); n=0; XtSetArg( args[n], XmNorientation, XmHORIZONTAL ); n++; rd = XmCreateRowColumn( rc,"data",args,n); XtManageChild( rd ); CreateLabelWidget( rd, "time", "Time Limit ", args, n ); if( TimeLimit > 0 ) tl_widget = CreateSimpleButton( rd, ltos(TimeLimit), time_limit_callback, (caddr_t)0 ); else tl_widget = CreateSimpleButton( rd, "infinite", time_limit_callback, (caddr_t)0 ); CreateLabelWidget( rd, "time_sec", " seconds", args, 0 ); n=0; XtSetArg( args[n], XmNorientation, XmHORIZONTAL ); n++; rd = XmCreateRowColumn( rc,"data",args,n); XtManageChild( rd ); CreateLabelWidget( rd, "bytes", "Max Bytes Per Frame ", args, 0 ); mb_widget = CreateSimpleButton( rd, ltos(MaxBytes), max_bytes_callback, (caddr_t)0 ); /* create 'OK' pushbutton */ n = 0; ok = CreatePushButton( main_row, "done", " DONE ", args, n, done_callback); /* Set OK button as default */ BulletinDefaultButton( bb_widget, ok ); XtManageChild( bb_widget ); } /* cap_opt_callback */ void get_long( parent, def, name, title, callback, semaphore ) Widget parent; long def; char *name, *title; void (*callback)(); u_short *semaphore; { Widget w; Arg args[2]; int n; XmString ms, ms2; ms = XmStringCreateSimple(title); ms2 = XmStringCreateSimple( ltos(def) ); n = 0; XtSetArg (args[n], XmNselectionLabelString, ms); n++; if( def > 0 ) { XtSetArg (args[n], XmNtextString, ms2); n++; } w = XmCreatePromptDialog( bb_widget, name ,args,n); XtAddCallback( w, XmNokCallback, (*callback), (caddr_t)0); XtAddCallback( w, XmNcancelCallback, cancel_callback, semaphore); XtAddCallback( w, XmNunmapCallback, cancel_callback, semaphore); XtManageChild( w ); XmStringFree( ms ); XmStringFree( ms2 ); } static void mb_result( widget, data, foo ) Widget widget; char *data; XmSelectionBoxCallbackStruct *foo; { char *string; XmStringGetLtoR( foo->value, XmSTRING_DEFAULT_CHARSET, &string); /* make sure MaxBytes is not too small or too large */ MaxBytes = max(DEFAULT_SNAPLEN, atoi(string)); MaxBytes = min(MaxBytes, MAX_SNAPLEN); SetLabel( mb_widget, ltos(MaxBytes) ); mb_semaphore = 0; } static void tl_result( widget, data, foo ) Widget widget; char *data; XmSelectionBoxCallbackStruct *foo; { char *string; XmStringGetLtoR( foo->value, XmSTRING_DEFAULT_CHARSET, &string); TimeLimit = atoi(string); if( TimeLimit <= 0 ) SetLabel( tl_widget, "infinite" ); else SetLabel( tl_widget, ltos(TimeLimit) ); tl_semaphore = 0; } static void nf_result( widget, data, foo ) Widget widget; char *data; XmSelectionBoxCallbackStruct *foo; { char *string; XmStringGetLtoR( foo->value, XmSTRING_DEFAULT_CHARSET, &string); NumberOfFrames = atoi(string); if( NumberOfFrames <= 0 ) { NumberOfFrames = -1; SetLabel( nf_widget, "infinite" ); } else SetLabel( nf_widget, ltos(NumberOfFrames) ); nf_semaphore = 0; } static void dev_result( widget, data, foo ) Widget widget; char *data; XmSelectionBoxCallbackStruct *foo; { char *string; static char buf[16]; XmStringGetLtoR( foo->value, XmSTRING_DEFAULT_CHARSET, &string); strcpy(buf, string); Device = buf; SetLabel( dev_widget, Device ); dev_semaphore = 0; } static void max_bytes_callback( widget, data, foo ) Widget widget; caddr_t data; caddr_t foo; { if( mb_semaphore ) return; mb_semaphore = 1; get_long( widget, MaxBytes, "max_bytes", "Maximum Number of Bytes to Capture Per Frame", mb_result, &mb_semaphore ); } static void time_limit_callback( widget, data, foo ) Widget widget; caddr_t data; caddr_t foo; { if( tl_semaphore ) return; tl_semaphore = 1; get_long( widget, TimeLimit, "time_limit", "Time Limit for Capture in Seconds", tl_result, &tl_semaphore ); } static void num_frame_callback( widget, data, foo ) Widget widget; caddr_t data; caddr_t foo; { if( nf_semaphore ) return; nf_semaphore = 1; get_long( widget, NumberOfFrames, "number_frames", "Number of Frames to Capture", nf_result, &nf_semaphore ); } static void prom_callback( widget, data, foo ) Widget widget; caddr_t data; caddr_t foo; { if( pflag ) pflag = 0; else pflag = 1; SetLabel( pr_widget, promstring[pflag]); } static void done_callback( widget, data, foo ) Widget widget; caddr_t data; caddr_t foo; { XtUnmanageChild( bb_widget ); } static void cancel_callback( widget, data, foo ) Widget widget; caddr_t data; caddr_t foo; { *data = 0; XtUnmanageChild(widget); } static void dev_cancel( widget, data, foo ) Widget widget; caddr_t data; caddr_t foo; { dev_semaphore = 0; XtUnmanageChild(widget); } static void device_callback( parent, data, foo ) Widget parent; caddr_t data; caddr_t foo; { Widget w; Arg args[2]; int n; XmString ms, ms2; if( dev_semaphore ) return; dev_semaphore = 1; ms = XmStringCreateSimple("Network Device Name"); if( Device ) ms2 = XmStringCreateSimple( Device ); else ms2 = XmStringCreateSimple(""); n = 0; XtSetArg (args[n], XmNselectionLabelString, ms); n++; XtSetArg (args[n], XmNtextString, ms2); n++; w = XmCreatePromptDialog( parent, "dev" ,args,n); XtAddCallback( w, XmNokCallback, dev_result, (caddr_t)0); XtAddCallback( w, XmNcancelCallback, dev_cancel, (caddr_t)0); XtManageChild( w ); XmStringFree( ms ); XmStringFree( ms2 ); } static void end_capture() { if( if_fd >= 0) wrapup(if_fd); *StrPtr = 0; sf_write_end(); exit(0); } u_short DoneWithCapture; static void child_end() { int status; FILE *fp; int num; char buf[512]; if( Work) XtUnrealizeWidget( Work ); DoneWithCapture = 1; signal( SIGCHLD, SIG_IGN); (void)wait(&status); /* fprintf(stderr,"child exited with status %d\n",WEXITSTATUS(status)); */ fp = fopen(StderrName,"r"); if( fp ) { num = fread( buf, 1, sizeof(buf), fp ); if( num ) { buf[num]='\0'; eprint( buf ); } unlink( StderrName ); fclose( fp ); } if( WEXITSTATUS(status) == 0 ) readfile( TempName ); unlink( TempName ); } /* semaphore */ static u_short Stopped=0; static void stop_capture_callback( widget, data, call_data ) Widget widget; caddr_t data; caddr_t call_data; { Stopped = 1; if( kill( (pid_t)data, SIGINT ) < 0 ) xperror("kill"); if( TimeoutID ) { XtRemoveTimeOut( TimeoutID ); TimeoutID = 0; } Stopped = 0; } static void timer_expired( data, id ) caddr_t data; XtIntervalId *id; { if( Stopped ) return; TimeoutID = 0; (void)kill( (pid_t)data, SIGINT ); } void capture_callback( widget, name, call_data ) Widget widget; char *name; caddr_t call_data; { u_long netmask, localnet; struct bpf_program *bpf; pid_t pid; extern long thiszone; extern int snaplen, Linktype, Precision; DoneWithCapture = 0; Work = NULL; { struct timeval now; struct timezone tz; if (gettimeofday(&now, &tz) < 0) { xperror("tcpdump: gettimeofday"); exit(1); } thiszone = tz.tz_minuteswest * -60; if (localtime((time_t *)&now.tv_sec)->tm_isdst) thiszone += 3600; } Precision = clock_sigfigs(); /* this should come from the capture options */ /* default and max should be based on DLC */ snaplen = MaxBytes; /* pick a temporary name for stderr */ strcpy(StderrName,tmpnam(NULL)); /* pick a temporary name to save frames to */ TempName = tmpnam(NULL); update_fstr(&Filter); (void)signal( SIGCHLD, child_end ); if( (pid = fork()) < 0 ) { eprint("Problem forking capture process"); return; } if( pid == 0 ) { /* send stderr to a temp file */ (void)freopen(StderrName,"w",stderr); if( Device == NULL ) { Device = lookup_device(); if( Device == NULL ) { eprint("Can't find device"); exit(1); } } if_fd = initdevice( Device, pflag, &Linktype ); lookup_net( Device, &localnet, &netmask ); bpf = parse( Fstr, 1, Linktype, netmask ); /* set up printf buffer */ StrPtr = strbuf = malloc(512); sf_write_init( TempName, Linktype, thiszone, snaplen, Precision ); (void)signal( SIGTERM, end_capture ); (void)signal( SIGINT, end_capture ); (void)signal( SIGHUP, end_capture ); readloop( NumberOfFrames, if_fd, bpf, sf_write ); end_capture(); } else { /* parent */ XmString ms, ms_stop; Arg args[2]; int n; if( TimeLimit > 0 ) TimeoutID = XtAddTimeOut( TimeLimit*1000, timer_expired, (caddr_t)pid ); /* now create a dialog with "Stop" button */ ms = XmStringCreateSimple( "Capturing"); ms_stop = XmStringCreateSimple( "STOP" ); n = 0; XtSetArg( args[n], XmNmessageString, ms ); n++; XtSetArg( args[n], XmNokLabelString, ms_stop ); n++; Work = XmCreateWorkingDialog( widget,"STOP",args,n ); RemoveDialButton( Work, XmDIALOG_HELP_BUTTON ); RemoveDialButton( Work, XmDIALOG_CANCEL_BUTTON ); XtAddCallback( Work, XmNokCallback,stop_capture_callback, (caddr_t)pid ); if( !DoneWithCapture ) XtManageChild( Work ); XmStringFree( ms ); XmStringFree( ms_stop ); } } /* capture_callback */