Ethereal-dev: [Ethereal-dev] New feature for ethereal
Note: This archive is from the project's previous web site, ethereal.com. This list is no longer active.
From: David Hampton <dhampton@xxxxxxx>
Date: Thu, 04 Jan 2001 20:17:34 -0800
I've modified Ethereal so that dissectors can be assigned to TCP and UDP ports on the fly. This isn't of any use for well known port numbers, but can be incredibly handy for looking at traces where the hosts are communicating on dynamically assigned port numbers. I needed this to study Microsoft's Universal Plug and Play protocols, which mainly consist of HTTP and SSDP on random ports. Hard coding port numbers wouldn't help as the port numbers are continually changing. This is my first attempt at programming in GTK, so I'd welcome any comments. I'm not particularly pleased with the need for a new function to connect protocol names and their dissectors, but I couldn't find any other way to get this information to put into the dialog box. I did this as a variant of the proto_register_protocol routine in hopes that developers of new protocol dissectors would be more likely to use it. The other choice would have been a second function that dissector writers would have to remember to call. I've attached diffs for my changes (including two new files in the gtk directory) and a trace from a uPnP session. If you look at this trace, it first appears to be indecipherable TCP and UDP streams. Right click on one of the packets and select the "Decode As" menu item. In the dialog box that is displayed, set both source and destination ports to be decoded as HTTP and click OK. Parts of the trace will now display as comprehensible HTTP text. The same can be done for the UDP packets. I'd appreciate any comments, queries, pointers. etc. David P.S. I added doc++ style comments to the code.
? Diffs ? ID ? gtk/html cvs server: Diffing . Index: packet-http.c =================================================================== RCS file: /cvsroot/ethereal/packet-http.c,v retrieving revision 1.32 diff -u -r1.32 packet-http.c --- packet-http.c 2001/01/03 06:55:28 1.32 +++ packet-http.c 2001/01/05 04:05:42 @@ -386,8 +386,8 @@ &ett_http, }; - proto_http = proto_register_protocol("Hypertext Transfer Protocol", - "HTTP", "http"); + proto_http = proto_register_tcpudp_protocol( + "Hypertext Transfer Protocol", "HTTP", "http", dissect_http); proto_register_field_array(proto_http, hf, array_length(hf)); proto_register_subtree_array(ett, array_length(ett)); } Index: packet-ntp.c =================================================================== RCS file: /cvsroot/ethereal/packet-ntp.c,v retrieving revision 1.21 diff -u -r1.21 packet-ntp.c --- packet-ntp.c 2001/01/03 06:55:30 1.21 +++ packet-ntp.c 2001/01/05 04:05:42 @@ -437,7 +437,8 @@ &ett_ntp_flags, }; - proto_ntp = proto_register_protocol("Network Time Protocol", "NTP", "ntp"); + proto_ntp = proto_register_tcpudp_protocol("Network Time Protocol", "NTP", + "ntp", dissect_ntp); proto_register_field_array(proto_ntp, hf, array_length(hf)); proto_register_subtree_array(ett, array_length(ett)); } cvs server: Diffing debian cvs server: Diffing doc cvs server: Diffing epan Index: epan/packet.c =================================================================== RCS file: /cvsroot/ethereal/epan/packet.c,v retrieving revision 1.11 diff -u -r1.11 packet.c --- packet.c 2000/12/04 06:37:46 1.11 +++ packet.c 2001/01/05 04:05:44 @@ -1170,6 +1170,26 @@ return g_hash_table_lookup( dissector_tables, name ); } +/* Finds a dissector by its associated pattern */ +dissector_t +find_dissector_by_pattern(const char *name, guint32 pattern) +{ + dissector_table_t sub_dissectors = find_dissector_table( name); + dtbl_entry_t *dtbl_entry; + +/* sanity check */ + g_assert( sub_dissectors); + + /* + * See if the entry already exists. If so, reuse it. + */ + dtbl_entry = g_hash_table_lookup(sub_dissectors, + GUINT_TO_POINTER(pattern)); + if (dtbl_entry != NULL) + return(dtbl_entry->dissector.new); + return(NULL); +} + /* add an entry, lookup the dissector table for the specified field name, */ /* if a valid table found, add the subdissector */ void @@ -1181,6 +1201,17 @@ /* sanity check */ g_assert( sub_dissectors); + /* + * See if the entry already exists. If so, reuse it. + */ + dtbl_entry = g_hash_table_lookup(sub_dissectors, + GUINT_TO_POINTER(pattern)); + if (dtbl_entry != NULL) { + dtbl_entry->is_old_dissector = TRUE; + dtbl_entry->dissector.old = dissector; + return; + } + dtbl_entry = g_malloc(sizeof (dtbl_entry_t)); dtbl_entry->is_old_dissector = TRUE; dtbl_entry->dissector.old = dissector; @@ -1198,6 +1229,17 @@ /* sanity check */ g_assert( sub_dissectors); + + /* + * See if the entry already exists. If so, reuse it. + */ + dtbl_entry = g_hash_table_lookup(sub_dissectors, + GUINT_TO_POINTER(pattern)); + if (dtbl_entry != NULL) { + dtbl_entry->is_old_dissector = FALSE; + dtbl_entry->dissector.new = dissector; + return; + } dtbl_entry = g_malloc(sizeof (dtbl_entry_t)); dtbl_entry->is_old_dissector = FALSE; Index: epan/packet.h =================================================================== RCS file: /cvsroot/ethereal/epan/packet.h,v retrieving revision 1.15 diff -u -r1.15 packet.h --- packet.h 2000/12/13 02:24:23 1.15 +++ packet.h 2001/01/05 04:05:44 @@ -209,6 +209,9 @@ /* a protocol uses the function to register a sub-dissector table */ dissector_table_t register_dissector_table(const char *name); +/* Finds a dissector by its associated pattern */ +dissector_t find_dissector_by_pattern(const char *name, guint32 pattern); + /* Add a sub-dissector to a dissector table. Called by the protocol routine */ /* that wants to register a sub-dissector. */ void old_dissector_add(const char *abbrev, guint32 pattern, old_dissector_t dissector); Index: epan/plugins.c =================================================================== RCS file: /cvsroot/ethereal/epan/plugins.c,v retrieving revision 1.15 diff -u -r1.15 plugins.c --- plugins.c 2001/01/03 07:53:46 1.15 +++ plugins.c 2001/01/05 04:05:45 @@ -94,8 +94,8 @@ static gchar std_plug_dir[] = "c:/program files/ethereal/plugins/0.8.14.1"; static gchar local_plug_dir[] = "c:/ethereal/plugins/0.8.14.1"; #else -static gchar std_plug_dir[] = "/usr/lib/ethereal/plugins/0.8.14"; -static gchar local_plug_dir[] = "/usr/local/lib/ethereal/plugins/0.8.14"; +static gchar std_plug_dir[] = "/tmp"; +static gchar local_plug_dir[] = "/tmp"; #endif static gchar *user_plug_dir = NULL; static gchar *plugin_status_file = NULL; Index: epan/proto.c =================================================================== RCS file: /cvsroot/ethereal/epan/proto.c,v retrieving revision 1.4 diff -u -r1.4 proto.c --- proto.c 2001/01/03 06:55:58 1.4 +++ proto.c 2001/01/05 04:05:46 @@ -125,6 +125,7 @@ GList *last_field; /* pointer to end of list of fields */ gboolean is_enabled; /* TRUE if protocol is enabled */ gboolean can_disable; /* TRUE if protocol can be disabled */ + gpointer dissector; } protocol_t; /* List of all protocols */ @@ -1506,6 +1507,7 @@ protocol->fields = NULL; protocol->is_enabled = TRUE; /* protocol is enabled by default */ protocol->can_disable = TRUE; + protocol->dissector = NULL; protocols = g_list_insert_sorted(protocols, protocol, proto_compare_name); @@ -1525,6 +1527,17 @@ return proto_id; } +int +proto_register_tcpudp_protocol(char *name, char *short_name, char *filter_name, + gpointer dissector) +{ + gint proto_id; + + proto_id = proto_register_protocol(name, short_name, filter_name); + proto_set_protocol_dissector(proto_id, dissector); + return proto_id; +} + /* * Routines to use to iterate over the protocols. * The argument passed to the iterator routines is an opaque cookie to @@ -1643,6 +1656,27 @@ protocol = find_protocol_by_id(proto_id); protocol->can_disable = FALSE; +} + +gpointer +proto_get_protocol_dissector(int proto_id) +{ + protocol_t *protocol; + + protocol = find_protocol_by_id(proto_id); + if (protocol == NULL) + return(NULL); + return protocol->dissector; +} + +void +proto_set_protocol_dissector(int proto_id, gpointer dissector) +{ + protocol_t *protocol; + + protocol = find_protocol_by_id(proto_id); + if (protocol != NULL) + protocol->dissector = dissector; } /* for use with static arrays only, since we don't allocate our own copies Index: epan/proto.h =================================================================== RCS file: /cvsroot/ethereal/epan/proto.h,v retrieving revision 1.3 diff -u -r1.3 proto.h --- proto.h 2001/01/03 06:55:59 1.3 +++ proto.h 2001/01/05 04:05:47 @@ -193,6 +193,9 @@ int proto_register_protocol(char *name, char *short_name, char *filter_name); +int +proto_register_tcpudp_protocol(char *name, char *short_name, char *filter_name, + gpointer dissector); void proto_register_field_array(int parent, hf_register_info *hf, int num_records); @@ -524,6 +527,9 @@ /* Disable disabling of protocol */ void proto_set_cant_disable(int proto_id); + +gpointer proto_get_protocol_dissector(int proto_id); +void proto_set_protocol_dissector(int proto_id, gpointer dissector); /* Get length of registered field according to field type. * 0 means undeterminable at registration time. cvs server: Diffing gtk Index: gtk/Makefile.am =================================================================== RCS file: /cvsroot/ethereal/gtk/Makefile.am,v retrieving revision 1.32 diff -u -r1.32 Makefile.am --- Makefile.am 2001/01/02 01:32:21 1.32 +++ Makefile.am 2001/01/05 04:05:47 @@ -39,6 +39,8 @@ color_utils.h \ column_prefs.c \ column_prefs.h \ + decode_as_dlg.c \ + decode_as_dlg.h \ dfilter_expr_dlg.c \ dfilter_expr_dlg.h \ display_opts.c \ Index: gtk/decode_as_dlg.c =================================================================== RCS file: decode_as_dlg.c diff -N decode_as_dlg.c --- /dev/null Sat Oct 7 15:19:25 2000 +++ decode_as_dlg.c Thu Jan 4 22:05:48 2001 @@ -0,0 +1,1011 @@ +/* decode_as_dlg.c + * + * $Id: $ + * + * Ethereal - Network traffic analyzer + * By Gerald Combs <gerald@xxxxxxxx> + * Copyright 2000 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. + * + */ + +#ifdef HAVE_CONFIG_H +# include "config.h" +#endif + +#include <gtk/gtk.h> + +#include <stdlib.h> +#include <stdio.h> +#include <string.h> + +#include <errno.h> + +#ifdef HAVE_SYS_TYPES_H +#include <sys/types.h> +#endif + +#include "decode_as_dlg.h" +#include "dlg_utils.h" +#include "globals.h" +#include "simple_dialog.h" +#include "packet.h" +#include "packet-ip.h" +#include "ui_util.h" + + +/**************************************************/ +/* Typedefs & Enums */ +/**************************************************/ + +/* + * Enum used to track which radio button is currently selected in the + * dialog. These buttons are labeled "Decode" and "Do not decode". + */ +enum action_type { + /* The "Decode" button is currently selected. */ + E_DECODE_YES, + + /* The "Do not decode" button is currently selected. */ + E_DECODE_NO +}; + +/* + * Enum used to track which transport layer protocol menu item is + * currently selected in the dialog. These items are labeled "TCP", + * "UDP", and "TCP/UDP". + */ +enum tcpudp_type { + /* The "TCP" menu item is currently selected. */ + E_DECODE_TCP, + + /* The "TCP" menu item is currently selected. */ + E_DECODE_UDP, + + /* The "TCP/UDP" menu item is currently selected. */ + E_DECODE_TCPUDP +}; + +/* + * Enum used to track which transport layer port menu item is + * currently selected in the dialog. These items are labeled "source", + * "destination", and "source/destination". + */ +enum srcdst_type { + /* The "source port" menu item is currently selected. */ + E_DECODE_SPORT, + /* The "destination port" menu item is currently selected. */ + E_DECODE_DPORT, + /* The "source/destination port" menu item is currently selected. */ + E_DECODE_BPORT +}; + + +/* + * Data structure for tracking the original dissector used for any + * given port on any given protocol. Dissectors are only tracked when + * they are modified, so this table does not keep a full list of + * dissectors (which would be a waste of space since the same + * information is tracked in packet.c). + */ +struct decode_saved_orig_port { + /* Which transport layer protocol (TCP/UDP) */ + gint saved_transport; + /* Which port number */ + gint saved_port; + /* The original dissector for this protocol. If NULL, this port + is not decoded by default. */ + dissector_t orig_dissector; +}; +/* + * A typedef for the data structure to track the original dissector + * used for any given port on any given protocol. + */ +typedef struct decode_saved_orig_port decode_saved_orig_port_t; + + +/**************************************************/ +/* File Global Variables */ +/**************************************************/ + +/* + * Keep a static pointer to the current "Decode As" window, if any, so that + * if somebody tries to do "Tools:Decode As" while there's already a + * "Decode As" window up, we just pop up the existing one, rather than + * creating a new one. + */ +static GtkWidget *decode_w = NULL; + +/* + * A list to the dialog items that only have meaning when the user has + * selected the "Decode" radio button. When the "Do not decode" + * button is selected these items should be dimmed. + */ +static GSList *decode_enable_list = NULL; + +/* + * Remember the "action" radio button that is currently selected in + * the dialog. This value is initialized when the dialog is created, + * modified in a callback routine, and read in the routine that + * handles a click in the "OK" button for the dialog. + */ +static enum action_type requested_action = -1; + +/* + * Remember the "transport layer" menu item that is currently selected + * in the dialog. This value is initialized when the dialog is + * created, modified in a callback routine, and read in the routine + * that handles a click in the "OK" button for the dialog. + */ +static enum tcpudp_type requested_tcpudp = -1; + +/* + * Remember the "direction" menu item that is currently selected + * in the dialog. This value is initialized when the dialog is + * created, modified in a callback routine, and read in the routine + * that handles a click in the "OK" button for the dialog. + */ +static enum srcdst_type requested_srcdst = -1; + +/* + * Remember the "protocol" menu item that is currently selected + * in the dialog. This value is initialized when the dialog is + * created, modified in a callback routine, and read in the routine + * that handles a click in the "OK" button for the dialog. + * + * Legal values for this variable are -1 for "default", and a positive + * value for a protocol that has been registered by a call to + * proto_register_protocol(). + */ +static gint requested_proto = -1; + +/**************************************************/ +/* Maintain a list of original */ +/* protocol/port/dissector combinations */ +/**************************************************/ + +static GSList *decode_orig_data_list; + +/* + * Scan the list of saved transport/port/dissector values to find a given entry. + * + * @param transport The transport layer protocol + * @param port The transport layer port number + * @return GSList * A pointer to the list entry for this triplet. + */ +static GSList * +decode_find_orig_port (gint transport, gint port) +{ + GSList *tmp; + decode_saved_orig_port_t *entry; + + tmp = decode_orig_data_list; + while (tmp != NULL) { + entry = tmp->data; + if ((entry->saved_transport == transport) && + (entry->saved_port == port)) { + return(tmp); + } + tmp = g_slist_next(tmp); + } + return(NULL); +} + +/* + * Scan the list of saved transport/port/dissector values to find a given entry. + * + * @param transport The transport layer protocol + * @param port The transport layer port number + * @return decode_saved_orig_port_t * A pointer to the data structure for this triplet. + */ +static decode_saved_orig_port_t * +decode_find_orig_port_entry (gint transport, gint port) +{ + GSList *tmp; + + tmp = decode_find_orig_port(transport, port); + if (tmp != NULL) + return(tmp->data); + return(NULL); +} + +static void +decode_list_orig_port(gchar *string) +{ + GSList *tmp; + decode_saved_orig_port_t *entry; + + printf("%s\n", string); + + tmp = decode_orig_data_list; + while (tmp != NULL) { + entry = tmp->data; + printf("Head %p, entry %p, transport %d, proto %d, dissector %p\n", + tmp, entry, entry->saved_transport, entry->saved_port, + entry->orig_dissector); + tmp = g_slist_next(tmp); + } + + printf("\n"); +} + +/* + * Add an entry to the list of saved transport/port/dissector values. + * If an entry for this transport/port combination is already present, + * this routines modifies the existing entry instead of adding a new + * entry. This makes it the callers responsibility to track whether + * or not a dissector should be added to the list. + * + * @param transport The transport layer protocol + * @param port The transport layer port number + * @param dissector The current dissector for this transport/port combination. + * @return void + */ +static void +decode_add_orig_port (gint transport, gint port, dissector_t dissector) +{ + GSList *tmp; + decode_saved_orig_port_t *entry; + + tmp = decode_find_orig_port(transport, port); + if (tmp != NULL) { + entry = tmp->data; + entry->orig_dissector = dissector; + return; + } + + entry = g_malloc(sizeof(decode_saved_orig_port_t)); + printf("g_malloc %p\n", entry); + g_assert(entry != NULL); + + entry->saved_transport = transport; + entry->saved_port = port; + entry->orig_dissector = dissector; + decode_orig_data_list = g_slist_prepend(decode_orig_data_list, entry); + decode_list_orig_port("Add success"); +} + +/* + * Delete an entry to the list of saved transport/port/dissector + * values. If an entry for this transport/port combination is not + * present, this routines does nothing. + * + * @param transport The transport layer protocol + * @param port The transport layer port number + * @return void + */ +static void +decode_delete_orig_port (gint transport, gint port) +{ + decode_saved_orig_port_t *entry; + + entry = decode_find_orig_port_entry(transport, port); + if (entry != NULL) { + decode_orig_data_list = g_slist_remove(decode_orig_data_list, entry); + printf("g_free %p\n", entry); + g_free(entry); + decode_list_orig_port("Delete success"); + return; + } + decode_list_orig_port("Delete failed"); +} + + +/**************************************************/ +/* Modify the dissector routines */ +/**************************************************/ + +/* + * Modify a single dissector. This routine first takes care of + * updating the internal table of original protocol/port/dissector + * combinations by adding a new entry (or removing an existing entry + * if the value is being set back to its default). This routine then + * performs the actual modification to the packet dissector tables. + * + * @param s Pointer to a string buffer. This buffer is used to build + * up a message indicating which ports have had their dissector + * changed. This output will be displayed all at once after all + * dissectors have been modified. + * + * @param proto An enum value indication which transport layer + * protocol's ports are to be changed. + * + * @param port An enum value indication whether the source port, + * destination port, or both ports are to be changed. + * + * @param abbrev The protocol abbreviation for the new dissector to be + * installed. + * + * @param dissector The new dissector to be installed. + * + * @return gchar * Pointer to the next free location in the string + * buffer. + */ +static gchar * +decode_set_one_dissector (gchar *s, gint proto, gint port, + gchar *abbrev, dissector_t dissector) +{ + gchar *proto_name, *table; + GSList *tmp; + decode_saved_orig_port_t *entry; + dissector_t old_dissector; + + /* Get constants */ + if (proto == E_DECODE_TCP) { + proto_name = "TCP"; + table = "tcp.port"; + } else { + proto_name = "UDP"; + table = "udp.port"; + } + + /* Track the default dissectors for each proto/port */ + tmp = decode_find_orig_port(proto, port); + if (tmp != NULL) { + /* An entry exists, so this dissector has been changed at least once */ + entry = tmp->data; + if (entry->orig_dissector == dissector) { + /* setting back to the default value so we can delete this entry */ + decode_delete_orig_port(proto, port); + } else { + /* + * Do nothing. The data structure should track the original + * dissector, not the previous dissector. + */ + } + } else { + /* + * First time this has been changed. Make a record. + */ + old_dissector = find_dissector_by_pattern(table, port); + if (dissector != old_dissector) + decode_add_orig_port(proto, port, old_dissector); + } + + /* Now make the change to the packet dissector tables. */ + if (dissector != NULL) { + dissector_add(table, port, dissector); + s += sprintf(s, "Decoding %s port %5d as %s.\n", + proto_name, port, abbrev); + } else { + dissector_delete(table, port, NULL /* unused */); + s += sprintf(s, "Not decoding %s port %5d.\n", proto_name, port); + } + return(s); +} + + +/* + * Modify a dissector or set of dissectors. + * + * The user has asked us to set the packet dissector values back to + * their original values. This cannot be done with a blanket install + * of a single dissector, but must be done by looking up each + * combination of transport layer protocol and port to find its + * original value. (E.G. TCP port 21 is FTP, but UDP port 21 is not.) + * Once the original values are determined, then can be set as the + * current dissector value. This function uses the + * decode_set_one_dissector() routine to perform the actual work. + * + * Note: The negative tests catch multiple cases. For example, if the + * user didn't select UDP, then they either selected TCP or TCP/UDP. + * Either way they DID select TCP. + * + * @param s Pointer to a string buffer. This buffer is used to build + * up a message indicating which ports have had their dissector + * changed. This output will be displayed all at once after all + * dissectors have been modified. + * + * @return void + */ +static void +decode_set_default_dissectors (gchar *s) +{ + decode_saved_orig_port_t *entry; + + if (requested_tcpudp != E_DECODE_UDP) { + if (requested_srcdst != E_DECODE_DPORT) { + entry = decode_find_orig_port_entry(E_DECODE_TCP, pi.srcport); + s = decode_set_one_dissector(s, E_DECODE_TCP, pi.srcport, "default", + entry ? entry->orig_dissector : NULL); + } + if (requested_srcdst != E_DECODE_SPORT) { + entry = decode_find_orig_port_entry(E_DECODE_TCP, pi.destport); + s = decode_set_one_dissector(s, E_DECODE_TCP, pi.destport, "default", + entry ? entry->orig_dissector : NULL); + } + } + if (requested_tcpudp != E_DECODE_TCP) { + if (requested_srcdst != E_DECODE_DPORT) { + entry = decode_find_orig_port_entry(E_DECODE_UDP, pi.srcport); + s = decode_set_one_dissector(s, E_DECODE_UDP, pi.srcport, "default", + entry ? entry->orig_dissector : NULL); + } + if (requested_srcdst != E_DECODE_SPORT) { + entry = decode_find_orig_port_entry(E_DECODE_UDP, pi.destport); + s = decode_set_one_dissector(s, E_DECODE_UDP, pi.destport, "default", + entry ? entry->orig_dissector : NULL); + } + } +} + + +/* + * Modify a dissector or set of dissectors. + * + * The user has asked us to set the packet dissector values to a new + * value, provided as an argument. This requires no thought. + * + * Note: The negative tests catch multiple cases. For example, if the + * user didn't select UDP, then they either selected TCP or TCP/UDP. + * Either way they DID select TCP. + * + * @param s Pointer to a string buffer. This buffer is used to build + * up a message indicating which ports have had their dissector + * changed. This output will be displayed all at once after all + * dissectors have been modified. + * + * @param abbrev The protocol abbreviation for the new dissector to be + * installed. + * + * @param dissector The new dissector to be installed. + * + * @return void + */ +static void +decode_set_new_dissectors (gchar *s, gchar *abbrev, dissector_t dissector) +{ + if (requested_tcpudp != E_DECODE_UDP) { + if (requested_srcdst != E_DECODE_DPORT) + s = decode_set_one_dissector(s, E_DECODE_TCP, pi.srcport, + abbrev, dissector); + if (requested_srcdst != E_DECODE_SPORT) + s = decode_set_one_dissector(s, E_DECODE_TCP, pi.destport, + abbrev, dissector); + } + if (requested_tcpudp != E_DECODE_TCP) { + if (requested_srcdst != E_DECODE_DPORT) + s = decode_set_one_dissector(s, E_DECODE_UDP, pi.srcport, + abbrev, dissector); + if (requested_srcdst != E_DECODE_SPORT) + s = decode_set_one_dissector(s, E_DECODE_UDP, pi.destport, + abbrev, dissector); + } +} + + +/**************************************************/ +/* Simple action callbacks from the dialog */ +/**************************************************/ + +/* + * Update the requested action field of the dialog. This routine is + * called by GTK when either of the two radio buttons in the dialog is + * clicked. + * + * @param GtkWidget * The radio button that was clicked. + * + * @param data The enum value assigned to this radio button. This + * will be either E_DECODE_YES or E_DECODE_NO + * + * @return void + */ +static void +decode_update_action (GtkWidget *w, gpointer data) +{ + GSList *tmp; + gboolean enable; + + requested_action = (gint)data; + enable = (requested_action == E_DECODE_YES); + for (tmp = decode_enable_list; tmp; tmp = g_slist_next(tmp)) { + gtk_widget_set_sensitive(tmp->data, enable); + } +} + + +/* + * Update the requested transport layer protocol field of the dialog. + * This routine is called by GTK when the transport layer menu + * selection is changed. + * + * @param GtkWidget * The new menu item that was selected. + * + * @param data The enum value assigned to this menu item. This + * will be either E_DECODE_TCP, E_DECODE_UDP, or E_DECODE_TCPUDP + * + * @return void + */ +static void +decode_update_tcpudp (GtkWidget *w, gpointer data) +{ + requested_tcpudp = (gint)gtk_object_get_user_data(GTK_OBJECT(w)); +} + + +/* + * Update the requested "direction" field of the dialog. This routine + * is called by GTK when the Source/destination menu selection is + * changed. + * + * @param GtkWidget * The new menu item that was selected. + * + * @param data The enum value assigned to this menu item. This + * will be either E_DECODE_SPORT, E_DECODE_DPORT, E_DECODE_BPORT + * + * @return void + */ +static void +decode_update_srcdst (GtkWidget *w, gpointer data) +{ + requested_srcdst = (gint)gtk_object_get_user_data(GTK_OBJECT(w)); +} + + +/* + * Update the requested protocol dissector field of the dialog. This routine + * is called by GTK when the protocol dissector menu selection is + * changed. + * + * @param GtkWidget * The new menu item that was selected. + * + * @param data The enum value assigned to this menu item. This will + * be either -1 for default, or a positive value for a protocol that + * has been registered by a call to proto_register_protocol(). + * + * @return void + */ +static void +decode_update_proto (GtkWidget *w, gpointer data) +{ + requested_proto = (gint)gtk_object_get_user_data(GTK_OBJECT(w)); +} + + +/**************************************************/ +/* Action routines for the dialog */ +/**************************************************/ + +/* + * This routine is called when the user clicks the "OK" button in the + * "Decode As..." dialog window. This routine calls various helper + * routines to set/clear dissector values as requested by the user. + * These routines accumulate information on what actions they have + * taken, and this summary information is printed by this routine. + * This routine then destroys the dialog box and performs other + * housekeeping functions. + * + * @param GtkWidget * A pointer to the "OK" button. + * + * @param gpointer A pointer to the dialog window. + * + * @return void + */ +static void +decode_ok_cb (GtkWidget *ok_bt, gpointer parent_w) +{ + dissector_t dissector; + gchar *s, *string, *abbrev; + + string = s = g_malloc(1024); + if (requested_action == E_DECODE_YES) { + if (requested_proto != -1) { + dissector = proto_get_protocol_dissector(requested_proto); + if (dissector == NULL) { + simple_dialog(ESD_TYPE_CRIT, NULL, + "Protocol dissector structure disappeared"); + gtk_widget_destroy(GTK_WIDGET(parent_w)); + return; + } + + /* Now go set all the dissector vectors */ + abbrev = proto_get_protocol_short_name(requested_proto); + decode_set_new_dissectors(s, abbrev, dissector); + } else { + decode_set_default_dissectors(s); + } + } else { + decode_set_new_dissectors(s, "(NULL)", NULL); + } + simple_dialog(ESD_TYPE_INFO, NULL, string); + g_free(string); + + /* Now destroy the "Decode As" dialog. */ + gtk_widget_destroy(GTK_WIDGET(parent_w)); + g_slist_free(decode_enable_list); + decode_enable_list = NULL; + + redissect_packets(&cfile); +} + + +/* + * This routine is called when the user clicks the "Cancel" button in + * the "Decode As..." dialog window. This routine then destroys the + * dialog box and performs other housekeeping functions. + * + * @param GtkWidget * A pointer to the "OK" button. + * + * @param gpointer A pointer to the dialog window. + * + * @return void + */ +static void +decode_cancel_cb (GtkWidget *cancel_bt, gpointer parent_w) +{ + gtk_widget_destroy(GTK_WIDGET(parent_w)); + g_slist_free(decode_enable_list); + decode_enable_list = NULL; +} + + +/* + * This routine is called when the user clicks the "Close" button in + * the "Decode As..." dialog window. This routine simply calls the + * cancel routine as if the user had clicked the cancel button instead + * of the close button. + * + * @param GtkWidget * A pointer to the dialog box. + * + * @param gpointer Unknown + * + * @return void + */ +static gboolean +decode_delete_cb (GtkWidget *decode_w, gpointer dummy) +{ + decode_cancel_cb(NULL, decode_w); + return FALSE; +} + + +/* + * This routine is called at the destruction of the "Decode As..." + * dialog box. It clears the pointer maintained by this file, so that + * the next time the user selects the "Decode As..." menu item a new + * dialog box will be created. + * + * @param GtkWidget * A pointer to the dialog box. + * + * @param gpointer Unknown + * + * @return void + */ +static void +decode_destroy_cb (GtkWidget *win, gpointer user_data) +{ + /* Note that we no longer have a "Decode As" dialog box. */ + decode_w = NULL; +} + + +/**************************************************/ +/* Dialog setup - menus */ +/**************************************************/ + +/* + * This routine is called to add the transport protocol selection menu + * to the dialog box. This is a three choice menu: TCP, UDP, and + * TCP/UDP. The default choice for the menu is set to the transport + * layer protocol of the currently selected packet. + * + * @return GtkWidget * A pointer to the newly created option menu. + */ +static GtkWidget * +decode_add_tcpudp_menu (void) +{ + GtkWidget *optmenu, *menu, *menuitem; + + optmenu = gtk_option_menu_new(); + g_assert(optmenu); + + menu = gtk_menu_new(); + g_assert(menu); + + menuitem = gtk_menu_item_new_with_label("TCP"); + gtk_object_set_user_data (GTK_OBJECT(menuitem), (gpointer)E_DECODE_TCP); + gtk_signal_connect(GTK_OBJECT(menuitem), "activate", + GTK_SIGNAL_FUNC(decode_update_tcpudp), NULL); + gtk_menu_append (GTK_MENU(menu), menuitem); + gtk_widget_show(menuitem); /* gtk_widget_show_all() doesn't show this */ + + menuitem = gtk_menu_item_new_with_label("UDP"); + gtk_object_set_user_data (GTK_OBJECT(menuitem), (gpointer)E_DECODE_UDP); + gtk_signal_connect(GTK_OBJECT(menuitem), "activate", + GTK_SIGNAL_FUNC(decode_update_tcpudp), NULL); + gtk_menu_append (GTK_MENU(menu), menuitem); + gtk_widget_show(menuitem); /* gtk_widget_show_all() doesn't show this */ + + menuitem = gtk_menu_item_new_with_label("TCP/UDP"); + gtk_object_set_user_data (GTK_OBJECT(menuitem), (gpointer)E_DECODE_TCPUDP); + gtk_signal_connect(GTK_OBJECT(menuitem), "activate", + GTK_SIGNAL_FUNC(decode_update_tcpudp), NULL); + gtk_menu_append (GTK_MENU(menu), menuitem); + gtk_widget_show(menuitem); /* gtk_widget_show_all() doesn't show this */ + + requested_tcpudp = (pi.ipproto == IP_PROTO_TCP) ? E_DECODE_TCP : E_DECODE_UDP; + gtk_menu_set_active(GTK_MENU(menu), requested_tcpudp == E_DECODE_UDP); + gtk_option_menu_set_menu(GTK_OPTION_MENU(optmenu), menu); + + return(optmenu); +} + + +/* + * This routine is called to add the transport port selection menu to + * the dialog box. This is a three choice menu: source, destination + * and both. The default choice for the menu is set to the source + * port number of the currently selected packet. + * + * @return GtkWidget * A pointer to the newly created option menu. + */ +static GtkWidget * +decode_add_srcdst_menu (void) +{ + GtkWidget *optmenu, *menu, *menuitem; + gchar tmp[100]; + + optmenu = gtk_option_menu_new(); + g_assert(optmenu); + + menu = gtk_menu_new(); + g_assert(menu); + + sprintf(tmp, "source (%d)", pi.srcport); + menuitem = gtk_menu_item_new_with_label(tmp); + gtk_object_set_user_data (GTK_OBJECT(menuitem), (gpointer)E_DECODE_SPORT); + gtk_signal_connect(GTK_OBJECT(menuitem), "activate", + GTK_SIGNAL_FUNC(decode_update_srcdst), NULL); + gtk_menu_append (GTK_MENU(menu), menuitem); + gtk_widget_show(menuitem); /* gtk_widget_show_all() doesn't show this */ + + sprintf(tmp, "destination (%d)", pi.destport); + menuitem = gtk_menu_item_new_with_label(tmp); + gtk_object_set_user_data (GTK_OBJECT(menuitem), (gpointer)E_DECODE_DPORT); + gtk_signal_connect(GTK_OBJECT(menuitem), "activate", + GTK_SIGNAL_FUNC(decode_update_srcdst), NULL); + gtk_menu_append (GTK_MENU(menu), menuitem); + gtk_widget_show(menuitem); /* gtk_widget_show_all() doesn't show this */ + + menuitem = gtk_menu_item_new_with_label("both"); + gtk_object_set_user_data (GTK_OBJECT(menuitem), (gpointer)E_DECODE_BPORT); + gtk_signal_connect(GTK_OBJECT(menuitem), "activate", + GTK_SIGNAL_FUNC(decode_update_srcdst), NULL); + gtk_menu_append (GTK_MENU(menu), menuitem); + gtk_widget_show(menuitem); /* gtk_widget_show_all() doesn't show this */ + + requested_srcdst = E_DECODE_SPORT; + gtk_option_menu_set_menu(GTK_OPTION_MENU(optmenu), menu); + + return(optmenu); +} + + +/* + * This routine is called to add the dissector selection menu to the + * dialog box. This menu contains an entry labeled "default", and an + * entry for each protocol that has had a dissector registered. The + * default choice for the menu is set to the "default" choice, which + * will return the protocol/port selections to their original + * dissector(s). + * + * @return GtkWidget * A pointer to the newly created option menu. + */ +static GtkWidget * +decode_add_proto_menu (void) +{ + GtkWidget *optmenu, *menu, *menuitem; + int i, len; + + optmenu = gtk_option_menu_new(); + g_assert(optmenu); + + menu = gtk_menu_new(); + g_assert(menu); + + menuitem = gtk_menu_item_new_with_label("default"); + gtk_object_set_user_data (GTK_OBJECT(menuitem), (gpointer)-1); + gtk_signal_connect(GTK_OBJECT(menuitem), "activate", + GTK_SIGNAL_FUNC(decode_update_proto), NULL); + gtk_menu_append (GTK_MENU(menu), menuitem); + gtk_widget_show(menuitem); /* gtk_widget_show_all() doesn't show this */ + + len = proto_registrar_n(); + for (i = 0; i < len ; i++) { + if (proto_get_protocol_dissector(i) == NULL) + continue; + + menuitem = gtk_menu_item_new_with_label(proto_get_protocol_short_name(i)); + gtk_object_set_user_data (GTK_OBJECT(menuitem), (gpointer)i); + gtk_signal_connect(GTK_OBJECT(menuitem), "activate", + GTK_SIGNAL_FUNC(decode_update_proto), NULL); + gtk_menu_append (GTK_MENU(menu), menuitem); + gtk_widget_show(menuitem); /* gtk_widget_show_all() doesn't show this */ + } + + requested_proto = -1; + gtk_option_menu_set_menu(GTK_OPTION_MENU(optmenu), menu); + + return(optmenu); +} + +/**************************************************/ +/* Dialog setup */ +/**************************************************/ + +/* + * This routine creates the bulk of the "Decode As" dialog box. All + * items created by this routine are packed into a single horizontal + * box. First is a two radio button vbox allowing the user to select + * whether or not do decode packets. Second is a menu allowing the + * user to select the TCP or UDP transport layer protocol. Third is a + * menu allowing the user to select whether the source port, + * destination port, or both ports will have dissectors added for + * them. Last is a (conditionally enabled) popup menu listing all + * possible dissectors that can be used to decode the packets, and the + * choice or returning to the default dissector for these ports. + * + * The defaults for these items are "Decode", the transport layer + * protocol of the currently selected packet, the source port of the + * currently selected packet, and the "default dissector". + * + * @param GtkWidget * A pointer to the main vertical box of the dialog. + */ +static void +decode_add_selection_row (GtkWidget * main_vb) +{ + GtkWidget *format_hb, *format_vb; + GtkWidget *radio_button, *label, *optmenu, *separator; + GSList *format_grp; + + format_hb = gtk_hbox_new(FALSE, 5); + gtk_box_pack_start(GTK_BOX(main_vb), format_hb, FALSE, FALSE, 10); + + /* + * First the radio buttons. Make a vbox for them + */ + format_vb = gtk_vbox_new(FALSE, 2); + gtk_box_pack_start(GTK_BOX(format_hb), format_vb, FALSE, FALSE, 10); + + radio_button = gtk_radio_button_new_with_label(NULL, "Decode"); + format_grp = gtk_radio_button_group(GTK_RADIO_BUTTON(radio_button)); + gtk_toggle_button_set_active(GTK_TOGGLE_BUTTON(radio_button), TRUE); + gtk_signal_connect(GTK_OBJECT(radio_button), "clicked", + GTK_SIGNAL_FUNC(decode_update_action), + (gpointer)E_DECODE_YES); + gtk_box_pack_start(GTK_BOX(format_vb), radio_button, FALSE, FALSE, 0); + + radio_button = gtk_radio_button_new_with_label(format_grp, "No not decode"); + format_grp = gtk_radio_button_group(GTK_RADIO_BUTTON(radio_button)); + gtk_signal_connect(GTK_OBJECT(radio_button), "clicked", + GTK_SIGNAL_FUNC(decode_update_action), + (gpointer)E_DECODE_NO); + gtk_box_pack_start(GTK_BOX(format_vb), radio_button, FALSE, FALSE, 0); + + separator = gtk_vseparator_new(); + gtk_box_pack_start(GTK_BOX(format_hb), separator, FALSE, FALSE, 0); + + /* + * Now the popup menus + */ + optmenu = decode_add_tcpudp_menu(); + gtk_box_pack_start(GTK_BOX(format_hb), optmenu, FALSE, FALSE, 0); + + optmenu = decode_add_srcdst_menu(); + gtk_box_pack_start(GTK_BOX(format_hb), optmenu, FALSE, FALSE, 0); + + label = gtk_label_new("port(s)"); + gtk_box_pack_start(GTK_BOX(format_hb), label, FALSE, FALSE, 0); + + /* + * Now the parts that are enabled only when decoding packets + */ + label = gtk_label_new("as"); + gtk_box_pack_start(GTK_BOX(format_hb), label, FALSE, FALSE, 0); + decode_enable_list = g_slist_prepend(decode_enable_list, label); + + optmenu = decode_add_proto_menu(); + gtk_box_pack_start(GTK_BOX(format_hb), optmenu, FALSE, FALSE, 0); + decode_enable_list = g_slist_prepend(decode_enable_list, optmenu); +} + + +/* + * This routine creates the "Decode As" dialog box. This dialog box + * asks the user which protocol to use for decoding the currently + * selected packet. This will affect 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). + * + * This routine uses an auxiliary function to create the bulk of the + * dialog box, and then hand crafts the button box at the bottom of + * the dialog. + * + * @param w Unknown + * @param data Unknown + * @return void + */ +void +decode_as_cb (GtkWidget * w, gpointer data) +{ + GtkWidget *main_vb, *bbox, *ok_bt, *cancel_bt; + + if (decode_w != NULL) { + /* There's already a "Decode As" dialog box; reactivate it. */ + reactivate_window(decode_w); + return; + } + + if ((pi.ipproto != IP_PROTO_TCP) && (pi.ipproto != IP_PROTO_UDP)) { + simple_dialog(ESD_TYPE_CRIT, NULL, + "Error getting port numbers. Please make\n" + "sure you have a TCP or UDP packet selected."); + return; + } + + requested_action = E_DECODE_YES; + decode_w = dlg_window_new("Ethereal: Decode As"); + gtk_signal_connect(GTK_OBJECT(decode_w), "delete_event", + GTK_SIGNAL_FUNC(decode_delete_cb), NULL); + gtk_signal_connect(GTK_OBJECT(decode_w), "destroy", + GTK_SIGNAL_FUNC(decode_destroy_cb), NULL); + + /* Container for each row of widgets */ + main_vb = gtk_vbox_new(TRUE, 5); + gtk_container_border_width(GTK_CONTAINER(main_vb), 5); + gtk_container_add(GTK_CONTAINER(decode_w), main_vb); + + /* Add selection row */ + decode_add_selection_row(main_vb); + + /* Button row: OK and cancel buttons */ + bbox = gtk_hbutton_box_new(); + gtk_button_box_set_layout (GTK_BUTTON_BOX (bbox), GTK_BUTTONBOX_END); + gtk_button_box_set_spacing(GTK_BUTTON_BOX(bbox), 5); + gtk_container_add(GTK_CONTAINER(main_vb), bbox); + + ok_bt = gtk_button_new_with_label("OK"); + gtk_signal_connect(GTK_OBJECT(ok_bt), "clicked", + GTK_SIGNAL_FUNC(decode_ok_cb), + GTK_OBJECT(decode_w)); + GTK_WIDGET_SET_FLAGS(ok_bt, GTK_CAN_DEFAULT); + gtk_box_pack_start(GTK_BOX (bbox), ok_bt, TRUE, TRUE, 0); + gtk_widget_grab_default(ok_bt); + + cancel_bt = gtk_button_new_with_label("Cancel"); + gtk_signal_connect(GTK_OBJECT(cancel_bt), "clicked", + GTK_SIGNAL_FUNC(decode_cancel_cb), + GTK_OBJECT(decode_w)); + GTK_WIDGET_SET_FLAGS(cancel_bt, GTK_CAN_DEFAULT); + gtk_box_pack_start(GTK_BOX (bbox), cancel_bt, TRUE, TRUE, 0); + + /* + * Catch the "key_press_event" signal in the window, so that + * we can catch the ESC key being pressed and act as if the + * "Cancel" button had been selected. + */ + dlg_set_cancel(decode_w, cancel_bt); + + gtk_widget_show_all(decode_w); +} + + +/* + * Local Variables: + * mode:c + * c-basic-offset: 4 + * End: + */ Index: gtk/decode_as_dlg.h =================================================================== RCS file: decode_as_dlg.h diff -N decode_as_dlg.h --- /dev/null Sat Oct 7 15:19:25 2000 +++ decode_as_dlg.h Thu Jan 4 22:05:48 2001 @@ -0,0 +1,30 @@ +/* decode_as_dlg.c + * + * $Id: $ + * + * Ethereal - Network traffic analyzer + * By Gerald Combs <gerald@xxxxxxxx> + * Copyright 2000 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. + * + */ + +#ifndef __DECODE_AS_DLG_H__ +#define __DECODE_AS_DLG_H__ + +void decode_as_cb( GtkWidget *, gpointer); + +#endif Index: gtk/menu.c =================================================================== RCS file: /cvsroot/ethereal/gtk/menu.c,v retrieving revision 1.46 diff -u -r1.46 menu.c --- menu.c 2000/10/19 22:59:24 1.46 +++ menu.c 2001/01/05 04:05:48 @@ -55,6 +55,7 @@ #include "packet_win.h" #include "print.h" #include "follow_dlg.h" +#include "decode_as_dlg.h" #include "help_dlg.h" #include "proto_dlg.h" #include "keys.h" @@ -144,6 +145,7 @@ {"/Tools/_Plugins...", NULL, GTK_MENU_FUNC(tools_plugins_cmd_cb), 0, NULL}, #endif {"/Tools/_Follow TCP Stream", NULL, GTK_MENU_FUNC(follow_stream_cb), 0, NULL}, + {"/Tools/_Decode As", NULL, GTK_MENU_FUNC(decode_as_cb), 0, NULL}, /* {"/Tools/Graph", NULL, NULL, 0, NULL}, future use */ {"/Tools/_Summary", NULL, GTK_MENU_FUNC(summary_open_cb), 0, NULL}, {"/_Help", NULL, NULL, 0, "<LastBranch>" }, @@ -159,6 +161,7 @@ static GtkItemFactoryEntry packet_list_menu_items[] = { {"/Follow TCP Stream", NULL, GTK_MENU_FUNC(follow_stream_cb), 0, NULL}, + {"/Decode As", NULL, GTK_MENU_FUNC(decode_as_cb), 0, NULL}, {"/Filters...", NULL, GTK_MENU_FUNC(filter_dialog_cb), 0, NULL}, {"/<separator>", NULL, NULL, 0, "<Separator>"}, {"/Colorize Display...", NULL, GTK_MENU_FUNC(color_display_cb), 0, NULL}, @@ -170,6 +173,7 @@ static GtkItemFactoryEntry tree_view_menu_items[] = { {"/Follow TCP Stream", NULL, GTK_MENU_FUNC(follow_stream_cb), 0, NULL}, + {"/Decode As", NULL, GTK_MENU_FUNC(decode_as_cb), 0, NULL}, {"/Filters...", NULL, GTK_MENU_FUNC(filter_dialog_cb), 0, NULL}, {"/<separator>", NULL, NULL, 0, "<Separator>"}, {"/Resolve Name", NULL, GTK_MENU_FUNC(resolve_name_cb), 0, NULL}, @@ -183,6 +187,7 @@ static GtkItemFactoryEntry hexdump_menu_items[] = { {"/Follow TCP Stream", NULL, GTK_MENU_FUNC(follow_stream_cb), 0, NULL}, + {"/Decode As", NULL, GTK_MENU_FUNC(decode_as_cb), 0, NULL}, {"/Filters...", NULL, GTK_MENU_FUNC(filter_dialog_cb), 0, NULL} }; @@ -387,6 +392,8 @@ set_menu_sensitivity("/Display/Show Packet In New Window", have_selected_packet); set_menu_sensitivity("/Tools/Follow TCP Stream", have_selected_packet ? (pi.ipproto == 6) : FALSE); + set_menu_sensitivity("/Tools/Decode As", + have_selected_packet ? ((pi.ipproto == 6) || (pi.ipproto == 17)) : FALSE); set_menu_sensitivity("/Resolve Name", have_selected_packet && !g_resolving_actif); } cvs server: Diffing image cvs server: Diffing libltdl cvs server: Diffing packaging cvs server: Diffing packaging/rpm cvs server: Diffing packaging/solaris cvs server: Diffing packaging/svr4 cvs server: Diffing plugins cvs server: Diffing plugins/gryphon cvs server: Diffing plugins/mgcp cvs server: Diffing wiretap
Attachment:
AA_Test_Trace
Description: Binary data
- Follow-Ups:
- Re: [Ethereal-dev] New feature for ethereal
- From: Guy Harris
- Re: [Ethereal-dev] New feature for ethereal
- Prev by Date: [Ethereal-dev] Re: [Ethereal-users] Segfault in 0.8.12 / 0.8.14
- Next by Date: [Ethereal-dev] Re: [Ethereal-users] Segfault in 0.8.12 / 0.8.14
- Previous by thread: Re: [Ethereal-dev] Re: [Ethereal-users] Segfault in 0.8.12 / 0.8.14
- Next by thread: Re: [Ethereal-dev] New feature for ethereal
- Index(es):