/* ethereal.c * * $Id: ethereal.c,v 1.11 1998/11/12 00:06:19 gram 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 "ethereal.h" #include "capture.h" #include "packet.h" #include "file.h" #include "menu.h" #include "etypes.h" #include "prefs.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; ts_type timestamp_type = RELATIVE; #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\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\n" "See http://ethereal.zing.org for more information", VERSION); } /* 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 = 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 (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 = 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 ); 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 ); 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); set_menu_sensitivity("
/File/Close", FALSE); set_menu_sensitivity("
/File/Reload", FALSE); } /* 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, 0, 0, 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\n", PACKAGE, VERSION); 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