/* ethereal.c * * $Id: ethereal.c,v 1.20 1999/01/04 07:39:14 guy Exp $ * * Ethereal - Network traffic analyzer * By Gerald Combs * Copyright 1998 Gerald Combs * * * This program 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. * * This program 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 this program; if not, write to the Free Software * Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. * * * To do: * - Live browser/capture display * - Graphs * - Get AIX to work * - Check for end of packet in dissect_* routines. * - Playback window * - Multiple window support * - Add cut/copy/paste * - Handle snoop files * - Fix progress/status bar glitches? (GTK+ bug?) * - Create header parsing routines * - Check fopens, freads, fwrites * - Make byte view scrollbars automatic? * - Make byte view selections more fancy? * */ #ifdef HAVE_CONFIG_H # include "config.h" #endif #include #include /* needed for capture.h */ #include #include #include #include #include #include #include #include #ifdef NEED_SNPRINTF_H # ifdef HAVE_STDARG_H # include # else # include # endif # include "snprintf.h" #endif #include "ethereal.h" #include "capture.h" #include "packet.h" #include "file.h" #include "menu.h" #include "etypes.h" #include "prefs.h" #include "column.h" #include "print.h" #include "resolv.h" #include "follow.h" #include "util.h" FILE *data_out_file = NULL; packet_info pi; capture_file cf; GtkWidget *file_sel, *packet_list, *tree_view, *byte_view, *prog_bar, *info_bar; GdkFont *m_r_font, *m_b_font; guint main_ctx, file_ctx; frame_data *fd; gint start_capture = 0; gchar comp_info_str[256]; ts_type timestamp_type = RELATIVE; GtkStyle *item_style; #define E_DFILTER_TE_KEY "display_filter_te" /* About Ethereal window */ void about_ethereal( GtkWidget *w, gpointer data ) { simple_dialog(ESD_TYPE_INFO, NULL, "GNU Ethereal - network protocol analyzer\n" "Version %s (C) 1998 Gerald Combs \n" "Compiled with %s\n\n" "Contributors:\n" "Gilbert Ramirez Jr. \n" "Hannes R. Boehm \n" "Mike Hall \n" "Bobo Rajec \n" "Laurent Deniel \n" "Don Lafontaine \n" "Guy Harris \n" "Simon Wilkinson \n" "Joerg Mayer \n\n" "See http://ethereal.zing.org for more information", VERSION, comp_info_str); } /* Things to do when the OK button is pressed */ void file_sel_ok_cb(GtkWidget *w, GtkFileSelection *fs) { gchar *cf_name; int err; GtkWidget *filter_te = NULL; /* Gilbert --- I added this if statement. Is this right? */ if (w) filter_te = gtk_object_get_data(GTK_OBJECT(w), E_DFILTER_TE_KEY); cf_name = g_strdup(gtk_file_selection_get_filename(GTK_FILE_SELECTION (fs))); gtk_widget_hide(GTK_WIDGET (fs)); gtk_widget_destroy(GTK_WIDGET (fs)); if (w && cf.dfilter) { g_free(cf.dfilter); cf.dfilter = g_strdup(gtk_entry_get_text(GTK_ENTRY(filter_te))); } if ((err = load_cap_file(cf_name, &cf)) == 0) chdir(cf_name); g_free(cf_name); } /* Update the progress bar */ gint file_progress_cb(gpointer p) { gtk_progress_bar_update(GTK_PROGRESS_BAR(prog_bar), (gfloat) ftell(cf.fh) / (gfloat) cf.f_len); return TRUE; } /* Follow a TCP stream */ void follow_stream_cb( GtkWidget *w, gpointer data ) { char filename1[128]; GtkWidget *streamwindow, *box, *text, *vscrollbar, *table; GtkWidget *filter_te = NULL; if (w) filter_te = gtk_object_get_data(GTK_OBJECT(w), E_DFILTER_TE_KEY); if( pi.ipproto == 6 ) { /* we got tcp so we can follow */ /* check to see if we are using a filter */ if( cf.dfilter != NULL ) { /* get rid of this one */ g_free( cf.dfilter ); cf.dfilter = NULL; } /* create a new one and set the display filter entry accordingly */ cf.dfilter = build_follow_filter( &pi ); if (filter_te) gtk_entry_set_text(GTK_ENTRY(filter_te), cf.dfilter); /* reload so it goes in effect. Also we set data_out_file which tells the tcp code to output the data */ close_cap_file( &cf, info_bar, file_ctx); strcpy( filename1, tmpnam(NULL) ); data_out_file = fopen( filename1, "a" ); if( data_out_file == NULL ) { fprintf( stderr, "Could not open tmp file %s\n", filename1 ); } reset_tcp_reassembly(); load_cap_file( cf.filename, &cf ); /* the data_out_file should now be full of the streams information */ fclose( data_out_file ); /* the filename1 file now has all the text that was in the session */ streamwindow = gtk_window_new( GTK_WINDOW_TOPLEVEL); gtk_widget_set_name( streamwindow, "TCP stream window" ); gtk_signal_connect( GTK_OBJECT(streamwindow), "delete_event", NULL, "WM destroy" ); gtk_signal_connect( GTK_OBJECT(streamwindow), "destroy", NULL, "WM destroy" ); gtk_window_set_title( GTK_WINDOW(streamwindow), "Contents of TCP stream" ); gtk_widget_set_usize( GTK_WIDGET(streamwindow), DEF_WIDTH, DEF_HEIGHT ); gtk_container_border_width( GTK_CONTAINER(streamwindow), 2 ); /* setup the container */ box = gtk_vbox_new( FALSE, 0 ); gtk_container_add( GTK_CONTAINER(streamwindow), box ); gtk_widget_show( box ); /* set up the table we attach to */ table = gtk_table_new( 1, 2, FALSE ); gtk_table_set_col_spacing( GTK_TABLE(table), 0, 2); gtk_box_pack_start( GTK_BOX(box), table, TRUE, TRUE, 0 ); gtk_widget_show( table ); /* create a text box */ text = gtk_text_new( NULL, NULL ); gtk_text_set_editable( GTK_TEXT(text), FALSE); gtk_table_attach( GTK_TABLE(table), text, 0, 1, 0, 1, GTK_EXPAND | GTK_SHRINK | GTK_FILL, GTK_EXPAND | GTK_SHRINK | GTK_FILL, 0, 0 ); gtk_widget_show(text); /* create the scrollbar */ vscrollbar = gtk_vscrollbar_new( GTK_TEXT(text)->vadj ); gtk_table_attach( GTK_TABLE(table), vscrollbar, 1, 2, 0, 1, GTK_FILL, GTK_EXPAND | GTK_SHRINK | GTK_FILL, 0, 0 ); gtk_widget_show( vscrollbar ); gtk_widget_realize( text ); /* stop the updates while we fill the text box */ gtk_text_freeze( GTK_TEXT(text) ); data_out_file = NULL; data_out_file = fopen( filename1, "r" ); if( data_out_file ) { char buffer[1024]; int nchars; while( 1 ) { nchars = fread( buffer, 1, 1024, data_out_file ); gtk_text_insert( GTK_TEXT(text), m_r_font, NULL, NULL, buffer, nchars ); if( nchars < 1024 ) { break; } } fclose( data_out_file ); unlink( filename1 ); } gtk_text_thaw( GTK_TEXT(text) ); data_out_file = NULL; gtk_widget_show( streamwindow ); if( cf.dfilter != NULL ) { g_free( cf.dfilter ); cf.dfilter = NULL; } } else { simple_dialog(ESD_TYPE_WARN, NULL, "Error following stream. Please make\n" "sure you have a TCP packet selected."); } } /* Open a file */ void file_open_cmd_cb(GtkWidget *w, gpointer data) { file_sel = gtk_file_selection_new ("Ethereal: Open Capture File"); /* Connect the ok_button to file_ok_sel_cb function and pass along the pointer to the filter entry */ gtk_signal_connect (GTK_OBJECT (GTK_FILE_SELECTION (file_sel)->ok_button), "clicked", (GtkSignalFunc) file_sel_ok_cb, file_sel ); /* Gilbert --- I added this if statement. Is this right? */ if (w) gtk_object_set_data(GTK_OBJECT(GTK_FILE_SELECTION(file_sel)->ok_button), E_DFILTER_TE_KEY, gtk_object_get_data(GTK_OBJECT(w), E_DFILTER_TE_KEY)); /* Connect the cancel_button to destroy the widget */ gtk_signal_connect_object(GTK_OBJECT (GTK_FILE_SELECTION (file_sel)->cancel_button), "clicked", (GtkSignalFunc) gtk_widget_destroy, GTK_OBJECT (file_sel)); gtk_file_selection_set_filename(GTK_FILE_SELECTION(file_sel), ""); gtk_widget_show(file_sel); } /* Close a file */ void file_close_cmd_cb(GtkWidget *widget, gpointer data) { close_cap_file(&cf, info_bar, file_ctx); #ifdef USE_ITEM set_menu_sensitivity("/File/Close", FALSE); set_menu_sensitivity("/File/Reload", FALSE); #else set_menu_sensitivity("
/File/Close", FALSE); set_menu_sensitivity("
/File/Reload", FALSE); #endif } /* Reload a file using the current display filter */ void file_reload_cmd_cb(GtkWidget *w, gpointer data) { GtkWidget *filter_te = gtk_object_get_data(GTK_OBJECT(w), E_DFILTER_TE_KEY); if (cf.dfilter) g_free(cf.dfilter); cf.dfilter = g_strdup(gtk_entry_get_text(GTK_ENTRY(filter_te))); load_cap_file(cf.filename, &cf); } /* Print a packet */ void file_print_cmd_cb(GtkWidget *widget, gpointer data) { print_tree(cf.pd, fd, GTK_TREE(tree_view)); } /* What to do when a list item is selected/unselected */ void packet_list_select_cb(GtkWidget *w, gint row, gint col, gpointer evt) { GList *l; #ifdef WITH_WIRETAP if (cf.wth) return; #else if (cf.pfh) return; #endif blank_packetinfo(); gtk_text_freeze(GTK_TEXT(byte_view)); gtk_text_set_point(GTK_TEXT(byte_view), 0); gtk_text_forward_delete(GTK_TEXT(byte_view), gtk_text_get_length(GTK_TEXT(byte_view))); l = g_list_nth(cf.plist, row); if (l) { fd = (frame_data *) l->data; fseek(cf.fh, fd->file_off, SEEK_SET); fread(cf.pd, sizeof(guint8), fd->cap_len, cf.fh); dissect_packet(cf.pd, fd, GTK_TREE(tree_view)); packet_hex_print(GTK_TEXT(byte_view), cf.pd, fd->cap_len, -1, -1); } gtk_text_thaw(GTK_TEXT(byte_view)); } void packet_list_unselect_cb(GtkWidget *w, gint row, gint col, gpointer evt) { gtk_text_freeze(GTK_TEXT(byte_view)); gtk_text_set_point(GTK_TEXT(byte_view), 0); gtk_text_forward_delete(GTK_TEXT(byte_view), gtk_text_get_length(GTK_TEXT(byte_view))); gtk_text_thaw(GTK_TEXT(byte_view)); gtk_tree_clear_items(GTK_TREE(tree_view), 0, g_list_length(GTK_TREE(tree_view)->children)); } void tree_view_cb(GtkWidget *w) { gint start = -1, len = -1; if (GTK_TREE(w)->selection) { start = (gint) gtk_object_get_data(GTK_OBJECT(GTK_TREE(w)->selection->data), E_TREEINFO_START_KEY); len = (gint) gtk_object_get_data(GTK_OBJECT(GTK_TREE(w)->selection->data), E_TREEINFO_LEN_KEY); } gtk_text_freeze(GTK_TEXT(byte_view)); gtk_text_set_point(GTK_TEXT(byte_view), 0); gtk_text_forward_delete(GTK_TEXT(byte_view), gtk_text_get_length(GTK_TEXT(byte_view))); packet_hex_print(GTK_TEXT(byte_view), cf.pd, fd->cap_len, start, len); gtk_text_thaw(GTK_TEXT(byte_view)); } void file_quit_cmd_cb (GtkWidget *widget, gpointer data) { gtk_exit(0); } void blank_packetinfo() { pi.srcip = 0; pi.destip = 0; pi.ipproto = 0; pi.srcport = 0; pi.destport = 0; } /* Things to do when the OK button is pressed */ void main_realize_cb(GtkWidget *w, gpointer data) { gchar *cf_name = (gchar *) data; int err; if (cf_name) { err = load_cap_file(cf_name, &cf); cf_name[0] = '\0'; } if (start_capture) { if (cf.save_file) capture(1); else capture(0); start_capture = 0; } } void print_usage(void) { fprintf(stderr, "This is GNU %s %s, compiled with %s\n", PACKAGE, VERSION, comp_info_str); fprintf(stderr, "%s [-v] [-b bold font] [-B byte view height] [-c count] [-h]\n", PACKAGE); fprintf(stderr, " [-i interface] [-m medium font] [-n] [-P packet list height]\n"); fprintf(stderr, " [-r infile] [-s snaplen] [-t