From 89c96d2772528b7a5e532438b5721f33ce440df5 Mon Sep 17 00:00:00 2001 From: Michael Mann Date: Wed, 15 Oct 2014 23:39:23 -0400 Subject: [PATCH] Add GUID dissector table support. It seems like DCE/RPC could benefit from a GUID dissector table, where a dissector can register it's GUID with a dissector handle. So here is a basic start. Change-Id: Id407117687a1a648d87f6f99c2ecbf858d8c0911 Reviewed-on: https://code.wireshark.org/review/4718 Reviewed-by: Michael Mann --- epan/packet.c | 143 +++++++++++++++++++++++++++++++++++++++++++++++++- epan/packet.h | 35 +++++++++++- 2 files changed, 176 insertions(+), 2 deletions(-) diff --git a/epan/packet.c b/epan/packet.c index 60e7dc73b3..0ed943876a 100644 --- a/epan/packet.c +++ b/epan/packet.c @@ -1555,6 +1555,124 @@ dissector_handle_t dissector_get_custom_table_handle(dissector_table_t sub_disse return NULL; } +/* Add an entry to a guid dissector table. */ +void dissector_add_guid(const char *name, guid_key* guid_val, dissector_handle_t handle) +{ + dissector_table_t sub_dissectors; + dtbl_entry_t *dtbl_entry; + + sub_dissectors = find_dissector_table(name); + + /* + * Make sure the dissector table exists. + */ + if (sub_dissectors == NULL) { + fprintf(stderr, "OOPS: dissector table \"%s\" doesn't exist\n", + name); + fprintf(stderr, "Protocol being registered is \"%s\"\n", + proto_get_protocol_long_name(handle->protocol)); + if (getenv("WIRESHARK_ABORT_ON_DISSECTOR_BUG") != NULL) + abort(); + return; + } + + /* sanity checks */ + g_assert(handle!=NULL); + if (sub_dissectors->type != FT_GUID) { + g_assert_not_reached(); + } + + dtbl_entry = (dtbl_entry_t *)g_malloc(sizeof (dtbl_entry_t)); + dtbl_entry->current = handle; + dtbl_entry->initial = dtbl_entry->current; + + /* do the table insertion */ + g_hash_table_insert( sub_dissectors->hash_table, + guid_val, (gpointer)dtbl_entry); + + /* + * Now add it to the list of handles that could be used with this + * table, because it *is* being used with this table. + */ + dissector_add_handle(name, handle); + +} + +/* Look for a given value in a given guid dissector table and, if found, + call the dissector with the arguments supplied, and return TRUE, + otherwise return FALSE. */ +int dissector_try_guid_new(dissector_table_t sub_dissectors, + guid_key* guid_val, tvbuff_t *tvb, packet_info *pinfo, proto_tree *tree, const gboolean add_proto_name, void *data) +{ + dtbl_entry_t *dtbl_entry; + struct dissector_handle *handle; + int len; + + dtbl_entry = (dtbl_entry_t *)g_hash_table_lookup(sub_dissectors->hash_table, guid_val); + if (dtbl_entry != NULL) { + /* + * Is there currently a dissector handle for this entry? + */ + handle = dtbl_entry->current; + if (handle == NULL) { + /* + * No - pretend this dissector didn't exist, + * so that other dissectors might have a chance + * to dissect this packet. + */ + return 0; + } + + /* + * Save the current value of "pinfo->match_uint", + * set it to the uint_val that matched, call the + * dissector, and restore "pinfo->match_uint". + */ + len = call_dissector_work(handle, tvb, pinfo, tree, add_proto_name, data); + + /* + * If a new-style dissector returned 0, it means that + * it didn't think this tvbuff represented a packet for + * its protocol, and didn't dissect anything. + * + * Old-style dissectors can't reject the packet. + * + * 0 is also returned if the protocol wasn't enabled. + * + * If the packet was rejected, we return 0, so that + * other dissectors might have a chance to dissect this + * packet, otherwise we return the dissected length. + */ + return len; + } + return 0; +} + +int dissector_try_guid(dissector_table_t sub_dissectors, + guid_key* guid_val, tvbuff_t *tvb, packet_info *pinfo, proto_tree *tree) +{ + return dissector_try_guid_new(sub_dissectors, guid_val, tvb, pinfo, tree, TRUE, NULL); +} + +/** Look for a given value in a given guid dissector table and, if found, + * return the current dissector handle for that value. + * + * @param[in] sub_dissectors Dissector table to search. + * @param[in] uint_val Value to match, e.g. the port number for the TCP dissector. + * @return The matching dissector handle on success, NULL if no match is found. + */ +dissector_handle_t dissector_get_guid_handle( + dissector_table_t const sub_dissectors, guid_key* guid_val) +{ + dtbl_entry_t *dtbl_entry; + + dtbl_entry = (dtbl_entry_t *)g_hash_table_lookup(sub_dissectors->hash_table, guid_val); + if (dtbl_entry != NULL) + return dtbl_entry->current; + else + return NULL; +} + dissector_handle_t dtbl_entry_get_handle (dtbl_entry_t *dtbl_entry) @@ -1637,6 +1755,24 @@ dissector_table_get_type(dissector_table_t dissector_table) { return dissector_table->type; } +static gint +uuid_equal(gconstpointer k1, gconstpointer k2) +{ + const guid_key *key1 = (const guid_key *)k1; + const guid_key *key2 = (const guid_key *)k2; + return ((memcmp(&key1->guid, &key2->guid, sizeof (e_guid_t)) == 0) + && (key1->ver == key2->ver)); +} + +static guint +uuid_hash(gconstpointer k) +{ + const guid_key *key = (const guid_key *)k; + /* This isn't perfect, but the Data1 part of these is almost always + unique. */ + return key->guid.data1; +} + /**************************************************/ /* */ /* Routines to walk dissector tables */ @@ -1915,7 +2051,12 @@ register_dissector_table(const char *name, const char *ui_name, const ftenum_t t &g_free, &g_free ); break; - + case FT_GUID: + sub_dissectors->hash_table = g_hash_table_new_full( uuid_hash, + uuid_equal, + NULL, + &g_free ); + break; default: g_assert_not_reached(); } diff --git a/epan/packet.h b/epan/packet.h index 31789dcda9..27606d85a6 100644 --- a/epan/packet.h +++ b/epan/packet.h @@ -29,6 +29,7 @@ #include "frame_data.h" #include "packet_info.h" #include "column-utils.h" +#include "guid-utils.h" #include "tfs.h" #include "ws_symbol_export.h" @@ -235,7 +236,7 @@ WS_DLL_PUBLIC int get_dissector_table_param(const char *name); WS_DLL_PUBLIC void dissector_dump_dissector_tables(void); /* Add an entry to a uint dissector table. */ -WS_DLL_PUBLIC void dissector_add_uint(const char *abbrev, const guint32 pattern, +WS_DLL_PUBLIC void dissector_add_uint(const char *name, const guint32 pattern, dissector_handle_t handle); /* Add an range of entries to a uint dissector table. */ @@ -350,7 +351,39 @@ WS_DLL_PUBLIC void dissector_add_custom_table_handle(const char *name, void *pat */ WS_DLL_PUBLIC dissector_handle_t dissector_get_custom_table_handle( dissector_table_t sub_dissectors, void *key); +/* Key for GUID dissector tables. This is based off of DCE/RPC needs + so some dissector tables may not need the ver portion of the hash + */ +typedef struct _guid_key { + e_guid_t guid; + guint16 ver; +} guid_key; +/* Add an entry to a guid dissector table. */ +WS_DLL_PUBLIC void dissector_add_guid(const char *name, guid_key* guid_val, + dissector_handle_t handle); + +/* Look for a given value in a given guid dissector table and, if found, + call the dissector with the arguments supplied, and return TRUE, + otherwise return FALSE. */ +WS_DLL_PUBLIC int dissector_try_guid(dissector_table_t sub_dissectors, + guid_key* guid_val, tvbuff_t *tvb, packet_info *pinfo, proto_tree *tree); + +/* Look for a given value in a given guid dissector table and, if found, + call the dissector with the arguments supplied, and return TRUE, + otherwise return FALSE. */ +WS_DLL_PUBLIC int dissector_try_guid_new(dissector_table_t sub_dissectors, + guid_key* guid_val, tvbuff_t *tvb, packet_info *pinfo, proto_tree *tree, const gboolean add_proto_name, void *data); + +/** Look for a given value in a given guid dissector table and, if found, + * return the current dissector handle for that value. + * + * @param[in] sub_dissectors Dissector table to search. + * @param[in] uint_val Value to match, e.g. the port number for the TCP dissector. + * @return The matching dissector handle on success, NULL if no match is found. + */ +WS_DLL_PUBLIC dissector_handle_t dissector_get_guid_handle( + dissector_table_t const sub_dissectors, guid_key* guid_val); /* Add a handle to the list of handles that *could* be used with this table. That list is used by the "Decode As"/"-d" code in the UI. */