/* main.c * * $Id: main.c,v 1.21 1999/10/12 05:01:07 guy Exp $ * * Ethereal - Network traffic analyzer * By Gerald Combs * Copyright 1998 Gerald Combs * * Richard Sharpe, 13-Feb-1999, added support for initializing structures * needed by dissect routines * * 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: * - Graphs * - Get AIX to work * - Check for end of packet in dissect_* routines. * - Playback window * - Multiple window support * - Add cut/copy/paste * - Create header parsing routines * - Make byte view scrollbars automatic? * - Make byte view selections more fancy? * */ #ifdef HAVE_CONFIG_H # include "config.h" #endif #include #include #include #include #ifdef HAVE_UNISTD_H #include #endif #include #include #include #ifdef HAVE_DIRECT_H #include #endif #ifdef HAVE_NETINET_IN_H #include #endif #include #ifdef NEED_SNPRINTF_H # ifdef HAVE_STDARG_H # include # else # include # endif # include "snprintf.h" #endif #ifdef NEED_STRERROR_H #include "strerror.h" #endif #include "main.h" #include "timestamp.h" #include "packet.h" #include "capture.h" #include "summary.h" #include "file.h" #include "menu.h" #include "prefs_dlg.h" #include "column.h" #include "print.h" #include "resolv.h" #include "follow.h" #include "util.h" #include "proto_draw.h" #include "dfilter.h" #include "keys.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; gchar comp_info_str[256]; gchar *ethereal_path = NULL; gchar *medium_font = MONO_MEDIUM_FONT; gchar *bold_font = MONO_BOLD_FONT; gchar *last_open_dir = NULL; ts_type timestamp_type = RELATIVE; GtkStyle *item_style; /* Specifies byte offsets for object selected in tree */ static gint tree_selected_start=-1, tree_selected_len=-1; /* 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 \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" "Martin Maciaszek \n" "Didier Jorand \n" "Jun-ichiro itojun Hagino \n" "Richard Sharpe \n" "John McDermott \n" "Jeff Jahr \n" "Brad Robel-Forrest \n" "Ashok Narayanan \n" "Aaron Hillegass \n" "Jason Lango \n" "Johan Feyaerts \n" "Olivier Abad \n" "Thierry Andry \n" "Jeff Foster \n" "Peter Torvals \n" "Christophe Tronche \n" "\nSee http://ethereal.zing.org for more information", VERSION, comp_info_str); } /* Follow the TCP stream, if any, to which the last packet that we called a dissection routine on belongs (this might be the most recently selected packet, or it might be the last packet in the file). */ void follow_stream_cb( GtkWidget *w, gpointer data ) { char filename1[128+1]; GtkWidget *streamwindow, *box, *text, *vscrollbar, *table; int tmp_fd; gchar *follow_filter; if( pi.ipproto == 6 ) { /* we got tcp so we can follow */ /* Create a temporary file into which to dump the reassembled data from the TCP stream, and set "data_out_file" to refer to it, so that the TCP code will write to it. XXX - it might be nicer to just have the TCP code directly append stuff to the text widget for the TCP stream window, if we can arrange that said window not pop up until we're done. */ tmp_fd = create_tempfile( filename1, sizeof filename1, "follow"); if (tmp_fd == -1) { simple_dialog(ESD_TYPE_WARN, NULL, "Could not create temporary file %s: %s", filename1, strerror(errno)); return; } data_out_file = fdopen( tmp_fd, "w" ); if( data_out_file == NULL ) { simple_dialog(ESD_TYPE_WARN, NULL, "Could not create temporary file %s: %s", filename1, strerror(errno)); close(tmp_fd); unlink(filename1); return; } /* Create a new filter that matches all packets in the TCP stream, and set the display filter entry accordingly */ reset_tcp_reassembly(); follow_filter = build_follow_filter( &pi ); /* Run the display filter so it goes in effect. */ filter_packets(&cf, follow_filter); /* 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" ); if( incomplete_tcp_stream ) { gtk_window_set_title( GTK_WINDOW(streamwindow), "Contents of TCP stream (incomplete)" ); } else { 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 = 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; } } if( ferror( data_out_file ) ) { simple_dialog(ESD_TYPE_WARN, NULL, "Error reading temporary file %s: %s", filename1, strerror(errno)); } fclose( data_out_file ); } else { simple_dialog(ESD_TYPE_WARN, NULL, "Could not open temporary file %s: %s", filename1, strerror(errno)); } gtk_text_thaw( GTK_TEXT(text) ); unlink( filename1 ); data_out_file = NULL; gtk_widget_show( streamwindow ); } else { simple_dialog(ESD_TYPE_WARN, NULL, "Error following stream. Please make\n" "sure you have a TCP packet selected."); } } /* Match selected byte pattern */ void match_selected_cb(GtkWidget *w, gpointer data) { char *buf; GtkWidget *filter_te = NULL; char *ptr; int i; guint8 *c; filter_te = gtk_object_get_data(GTK_OBJECT(w), E_DFILTER_TE_KEY); if (tree_selected_start<0) { simple_dialog(ESD_TYPE_WARN, NULL, "Error determining selected bytes. Please make\n" "sure you have selected a field within the tree\n" "view to be matched."); return; } c = cf.pd + tree_selected_start; buf = g_malloc(32 + tree_selected_len * 3); ptr = buf; sprintf(ptr, "frame[%d : %d] == ", tree_selected_start, tree_selected_len); ptr = buf+strlen(buf); if (tree_selected_len == 1) { sprintf(ptr, "0x%02x", *c++); } else { for (i=0;iselection) { tree_selected_start = (gint) gtk_object_get_data(GTK_OBJECT(GTK_TREE(w)->selection->data), E_TREEINFO_START_KEY); tree_selected_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, cf.fd->cap_len, tree_selected_start, tree_selected_len); gtk_text_thaw(GTK_TEXT(byte_view)); } void collapse_all_cb(GtkWidget *widget, gpointer data) { if (cf.protocol_tree) collapse_all_tree(cf.protocol_tree, tree_view); } void expand_all_cb(GtkWidget *widget, gpointer data) { if (cf.protocol_tree) expand_all_tree(cf.protocol_tree, tree_view); } void file_quit_cmd_cb (GtkWidget *widget, gpointer data) { if (cf.save_file && !cf.user_saved) { unlink(cf.save_file); } gtk_exit(0); } void blank_packetinfo() { pi.ip_src = 0; pi.ip_dst = 0; pi.ipproto = 0; pi.srcport = 0; pi.destport = 0; } /* call initialization routines at program startup time */ static void ethereal_proto_init(void) { proto_init(); init_dissect_udp(); dfilter_init(); } static void ethereal_proto_cleanup(void) { proto_cleanup(); dfilter_cleanup(); } static void print_usage(void) { fprintf(stderr, "This is GNU %s %s, compiled with %s\n", PACKAGE, VERSION, comp_info_str); fprintf(stderr, "%s [-vh] [-kQS] [-b ] [-B ] [-c count]\n", PACKAGE); fprintf(stderr, " [-f ] [-i interface] [-m ] [-n]\n"); fprintf(stderr, " [-P ] [-r infile] [-s snaplen]\n"); fprintf(stderr, " [-t