diff options
Diffstat (limited to 'epan/packet.c')
-rw-r--r-- | epan/packet.c | 668 |
1 files changed, 505 insertions, 163 deletions
diff --git a/epan/packet.c b/epan/packet.c index c087659657..322b4f491d 100644 --- a/epan/packet.c +++ b/epan/packet.c @@ -32,6 +32,7 @@ #include <epan/wmem_scopes.h> +#include <epan/column-info.h> #include <epan/exceptions.h> #include <epan/reassemble.h> #include <epan/stream.h> @@ -43,7 +44,7 @@ #include <wsutil/wslog.h> #include <wsutil/ws_assert.h> -static gint proto_malformed = -1; +static gint proto_malformed; static dissector_handle_t frame_handle = NULL; static dissector_handle_t file_handle = NULL; static dissector_handle_t data_handle = NULL; @@ -157,6 +158,7 @@ destroy_depend_dissector_list(void *data) * A heuristics dissector list. */ struct heur_dissector_list { + const char *ui_name; protocol_t *protocol; GSList *dissectors; }; @@ -235,8 +237,32 @@ packet_cache_proto_handles(void) /* List of routines that are called before we make a pass through a capture file * and dissect all its packets. See register_init_routine, register_cleanup_routine * and register_shutdown_routine in packet.h */ +/** + * List of "init" routines, which are called before we make a pass through + * a capture file and dissect all its packets (e.g., when we read in a + * new capture file, or run a "filter packets" or "colorize packets" + * pass over the current capture file or when the preferences are changed). + * + * See register_init_routine(). + */ static GSList *init_routines = NULL; + +/** + * List of "cleanup" routines, which are called after closing a capture + * file (or when preferences are changed; in that case these routines + * are called before the init routines are executed). They can be used + * to release resources that are allocated in an "init" routine. + * + * See register_cleanup_routine(). + */ static GSList *cleanup_routines = NULL; + +/* + * List of "shutdown" routines, which are called once, just before + * program exit. + * + * See register_shutdown_routine(). + */ static GSList *shutdown_routines = NULL; typedef void (*void_func_t)(void); @@ -316,7 +342,7 @@ init_dissection(void) { /* * Reinitialize resolution information. Don't leak host entries from - * one file to another (e.g. embarassing-host-name.example.com from + * one file to another (e.g. embarrassing-host-name.example.com from * file1.pcapng into a name resolution block in file2.pcapng). */ host_name_lookup_reset(); @@ -422,7 +448,7 @@ get_data_source_tvb_by_name(packet_info *pinfo, const char *name) { GSList *source; for (source = pinfo->data_src; source; source = source->next) { - struct data_source *this_source = (struct data_source *)source; + struct data_source *this_source = (struct data_source *)source->data; if (this_source->name && strcmp(this_source->name, name) == 0) { return this_source->tvb; } @@ -444,11 +470,17 @@ free_data_sources(packet_info *pinfo) } void -mark_frame_as_depended_upon(packet_info *pinfo, guint32 frame_num) +mark_frame_as_depended_upon(frame_data *fd, guint32 frame_num) { /* Don't mark a frame as dependent on itself */ - if (frame_num != pinfo->num) { - pinfo->dependent_frames = g_slist_prepend(pinfo->dependent_frames, GUINT_TO_POINTER(frame_num)); + if (frame_num != fd->num) { + /* ws_assert(frame_num < fd->num) - we assume in several other + * places in the code that frames don't depend on future + * frames. */ + if (fd->dependent_frames == NULL) { + fd->dependent_frames = g_hash_table_new(g_direct_hash, g_direct_equal); + } + g_hash_table_add(fd->dependent_frames, GUINT_TO_POINTER(frame_num)); } } @@ -589,15 +621,23 @@ dissect_record(epan_dissect_t *edt, int file_type_subtype, clear_address(&edt->pi.dst); edt->pi.noreassembly_reason = ""; edt->pi.ptype = PT_NONE; - edt->pi.use_endpoint = FALSE; - edt->pi.conv_endpoint = NULL; + edt->pi.use_conv_addr_port_endpoints = FALSE; + edt->pi.conv_addr_port_endpoints = NULL; + edt->pi.conv_elements = NULL; edt->pi.p2p_dir = P2P_DIR_UNKNOWN; edt->pi.link_dir = LINK_DIR_UNKNOWN; + edt->pi.src_win_scale = -1; /* unknown Rcv.Wind.Shift */ + edt->pi.dst_win_scale = -1; /* unknown Rcv.Wind.Shift */ edt->pi.layers = wmem_list_new(edt->pi.pool); edt->tvb = tvb; frame_delta_abs_time(edt->session, fd, fd->frame_ref_num, &edt->pi.rel_ts); + if (rec->ts_rel_cap_valid) { + nstime_copy(&edt->pi.rel_cap_ts, &rec->ts_rel_cap); + edt->pi.rel_cap_ts_present = true; + } + /* * If the block has been modified, use the modified block, * otherwise use the block from the file. @@ -660,8 +700,9 @@ dissect_file(epan_dissect_t *edt, wtap_rec *rec, clear_address(&edt->pi.dst); edt->pi.noreassembly_reason = ""; edt->pi.ptype = PT_NONE; - edt->pi.use_endpoint = FALSE; - edt->pi.conv_endpoint = NULL; + edt->pi.use_conv_addr_port_endpoints = FALSE; + edt->pi.conv_addr_port_endpoints = NULL; + edt->pi.conv_elements = NULL; edt->pi.p2p_dir = P2P_DIR_UNKNOWN; edt->pi.link_dir = LINK_DIR_UNKNOWN; edt->pi.layers = wmem_list_new(edt->pi.pool); @@ -721,12 +762,74 @@ enum dissector_e { */ struct dissector_handle { const char *name; /* dissector name */ + const char *description; /* dissector description */ enum dissector_e dissector_type; void *dissector_func; void *dissector_data; protocol_t *protocol; }; +static void +add_layer(packet_info *pinfo, int proto_id) +{ + int *proto_layer_num_ptr; + + pinfo->curr_layer_num++; + wmem_list_append(pinfo->layers, GINT_TO_POINTER(proto_id)); + + /* Increment layer number for this proto id. */ + if (pinfo->proto_layers == NULL) { + pinfo->proto_layers = wmem_map_new(pinfo->pool, g_direct_hash, g_direct_equal); + } + + proto_layer_num_ptr = wmem_map_lookup(pinfo->proto_layers, GINT_TO_POINTER(proto_id)); + if (proto_layer_num_ptr == NULL) { + /* Insert new layer */ + proto_layer_num_ptr = wmem_new(pinfo->pool, int); + *proto_layer_num_ptr = 1; + wmem_map_insert(pinfo->proto_layers, GINT_TO_POINTER(proto_id), proto_layer_num_ptr); + } + else { + /* Increment layer number */ + (*proto_layer_num_ptr)++; + } + pinfo->curr_proto_layer_num = *proto_layer_num_ptr; +} + +static void +remove_last_layer(packet_info *pinfo, gboolean reduce_count) +{ + int *proto_layer_num_ptr; + wmem_list_frame_t *frame; + int proto_id; + + if (reduce_count) { + pinfo->curr_layer_num--; + } + + frame = wmem_list_tail(pinfo->layers); + proto_id = GPOINTER_TO_INT(wmem_list_frame_data(frame)); + wmem_list_remove_frame(pinfo->layers, frame); + + if (reduce_count) { + /* Reduce count for removed protocol layer. */ + proto_layer_num_ptr = wmem_map_lookup(pinfo->proto_layers, GINT_TO_POINTER(proto_id)); + if (proto_layer_num_ptr && *proto_layer_num_ptr > 0) { + (*proto_layer_num_ptr)--; + } + } + + /* Restore count for new last (protocol) layer. */ + frame = wmem_list_tail(pinfo->layers); + if (frame) { + proto_id = GPOINTER_TO_INT(wmem_list_frame_data(frame)); + proto_layer_num_ptr = wmem_map_lookup(pinfo->proto_layers, GINT_TO_POINTER(proto_id)); + ws_assert(proto_layer_num_ptr); + pinfo->curr_proto_layer_num = *proto_layer_num_ptr; + } +} + + /* This function will return * old style dissector : * length of the payload or 1 of the payload is empty @@ -786,15 +889,16 @@ call_dissector_work_error(dissector_handle_t handle, tvbuff_t *tvb, #define PINFO_LAYER_MAX_RECURSION_DEPTH 500 static int -call_dissector_work(dissector_handle_t handle, tvbuff_t *tvb, packet_info *pinfo_arg, +call_dissector_work(dissector_handle_t handle, tvbuff_t *tvb, packet_info *pinfo, proto_tree *tree, gboolean add_proto_name, void *data) { - packet_info *pinfo = pinfo_arg; const char *saved_proto; guint16 saved_can_desegment; int len; guint saved_layers_len = 0; guint saved_tree_count = tree ? tree->tree_data->count : 0; + unsigned saved_desegment_len = pinfo->desegment_len; + bool consumed_none; if (handle->protocol != NULL && !proto_is_protocol_enabled(handle->protocol)) { @@ -812,7 +916,7 @@ call_dissector_work(dissector_handle_t handle, tvbuff_t *tvb, packet_info *pinfo /* * can_desegment is set to 2 by anyone which offers the * desegmentation api/service. - * Then everytime a subdissector is called it is decremented + * Then every time a subdissector is called it is decremented * by one. * Thus only the subdissector immediately on top of whoever * offers this service can use it. @@ -834,8 +938,7 @@ call_dissector_work(dissector_handle_t handle, tvbuff_t *tvb, packet_info *pinfo */ /* XXX Should we check for a duplicate layer here? */ if (add_proto_name) { - pinfo->curr_layer_num++; - wmem_list_append(pinfo->layers, GINT_TO_POINTER(proto_get_id(handle->protocol))); + add_layer(pinfo, proto_get_id(handle->protocol)); } } @@ -847,24 +950,35 @@ call_dissector_work(dissector_handle_t handle, tvbuff_t *tvb, packet_info *pinfo */ len = call_dissector_through_handle(handle, tvb, pinfo, tree, data); } + consumed_none = len == 0 || (pinfo->desegment_len != saved_desegment_len && pinfo->desegment_offset == 0); + /* If len == 0, then the dissector didn't accept the packet. + * In the latter case, the dissector accepted the packet, but didn't + * consume any bytes because they all belong in a later segment. + * In the latter case, we probably won't call a dissector here again + * on the next pass, so removing the layer keeps any *further* layers + * past this one the same on subsequent passes. + * + * XXX: DISSECTOR_ASSERT that the tree count didn't change? If the + * dissector didn't consume any bytes but added items to the tree, + * that's improper behavior and needs a rethink. We could also move the + * test that the packet didn't change desegment_offset and desegment_len + * while rejecting the packet from packet-tcp.c decode_tcp_ports to here. + */ if (handle->protocol != NULL && !proto_is_pino(handle->protocol) && add_proto_name && - (len == 0 || (tree && saved_tree_count == tree->tree_data->count))) { + (consumed_none || (tree && saved_tree_count == tree->tree_data->count))) { /* * We've added a layer and either the dissector didn't - * accept the packet or we didn't add any items to the + * consume any data or we didn't add any items to the * tree. Remove it. */ while (wmem_list_count(pinfo->layers) > saved_layers_len) { - if (len == 0) { - /* - * Only reduce the layer number if the dissector - * rejected the data. Since tree can be NULL on - * the first pass, we cannot check it or it will - * break dissectors that rely on a stable value. - */ - pinfo->curr_layer_num--; - } - wmem_list_remove_frame(pinfo->layers, wmem_list_tail(pinfo->layers)); + /* + * Only reduce the layer number if the dissector didn't + * consume any data. Since tree can be NULL on + * the first pass, we cannot check it or it will + * break dissectors that rely on a stable value. + */ + remove_last_layer(pinfo, consumed_none); } } pinfo->current_proto = saved_proto; @@ -1155,43 +1269,8 @@ void dissector_add_uint_range(const char *name, range_t *range, } } -static void -dissector_add_preference(const char *name, dissector_handle_t handle, guint init_value) -{ - guint* uint_var; - module_t *module; - gchar *description, *title; - dissector_table_t pref_dissector_table = find_dissector_table(name); - int proto_id = proto_get_id(handle->protocol); - - uint_var = wmem_new(wmem_epan_scope(), guint); - *uint_var = init_value; - - /* If the dissector already has a preference module, use it */ - module = prefs_find_module(proto_get_protocol_filter_name(proto_id)); - if (module == NULL) - { - /* Otherwise create a new one */ - module = prefs_register_protocol(proto_id, NULL); - } - - description = wmem_strdup_printf(wmem_epan_scope(), "Set the %s for %s (if other than the default of %u)", - pref_dissector_table->ui_name, proto_get_protocol_short_name(handle->protocol), *uint_var); - title = wmem_strdup_printf(wmem_epan_scope(), "%s %s", proto_get_protocol_short_name(handle->protocol), - pref_dissector_table->ui_name); - - prefs_register_decode_as_preference(module, name, title, description, uint_var); -} - -void dissector_add_uint_with_preference(const char *name, const guint32 pattern, - dissector_handle_t handle) -{ - dissector_add_preference(name, handle, pattern); - dissector_add_uint(name, pattern, handle); -} - -void dissector_add_uint_range_with_preference(const char *name, const char* range_str, - dissector_handle_t handle) +static range_t* +dissector_add_range_preference(const char *name, dissector_handle_t handle, const char* range_str) { range_t** range; module_t *module; @@ -1216,8 +1295,13 @@ void dissector_add_uint_range_with_preference(const char *name, const char* rang routine to apply preferences, which could duplicate the registration of a preference. Check for that here */ if (prefs_find_preference(module, name) == NULL) { - description = wmem_strdup_printf(wmem_epan_scope(), "%s %s(s)", + if (g_strcmp0(range_str, "") > 0) { + description = wmem_strdup_printf(wmem_epan_scope(), "%s %s(s) (default: %s)", + proto_get_protocol_short_name(handle->protocol), pref_dissector_table->ui_name, range_str); + } else { + description = wmem_strdup_printf(wmem_epan_scope(), "%s %s(s)", proto_get_protocol_short_name(handle->protocol), pref_dissector_table->ui_name); + } title = wmem_strdup_printf(wmem_epan_scope(), "%s(s)", pref_dissector_table->ui_name); /* Max value is based on datatype of dissector table */ @@ -1245,14 +1329,34 @@ void dissector_add_uint_range_with_preference(const char *name, const char* rang prefs_register_decode_as_range_preference(module, name, title, description, range, max_value); } - dissector_add_uint_range(name, *range, handle); + return *range; +} + +void dissector_add_uint_with_preference(const char *name, const guint32 pattern, + dissector_handle_t handle) +{ + char* range_str; + + range_str = wmem_strdup_printf(NULL, "%d", pattern); + dissector_add_range_preference(name, handle, range_str); + wmem_free(NULL, range_str); + dissector_add_uint(name, pattern, handle); +} + +void dissector_add_uint_range_with_preference(const char *name, const char* range_str, + dissector_handle_t handle) +{ + range_t* range; + + range = dissector_add_range_preference(name, handle, range_str); + dissector_add_uint_range(name, range, handle); } /* Delete the entry for a dissector in a uint dissector table with a particular pattern. */ /* NOTE: this doesn't use the dissector call variable. It is included to */ -/* be consistant with the dissector_add_uint and more importantly to be used */ +/* be consistent with the dissector_add_uint and more importantly to be used */ /* if the technique of adding a temporary dissector is implemented. */ /* If temporary dissectors are deleted, then the original dissector must */ /* be available. */ @@ -1294,6 +1398,36 @@ void dissector_delete_uint_range(const char *name, range_t *range, } } +/* Remove an entry from a guid dissector table. */ +void dissector_delete_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); + + /* sanity check */ + ws_assert(sub_dissectors); + + /* Find the table entry */ + dtbl_entry = (dtbl_entry_t *)g_hash_table_lookup(sub_dissectors->hash_table, guid_val); + + if (dtbl_entry == NULL) { + fprintf(stderr, "OOPS: guid not found in dissector table \"%s\"\n", name); + return; + } + + /* Make sure the handles match */ + if (dtbl_entry->current != handle) { + fprintf(stderr, "OOPS: handle does not match for guid in dissector table \"%s\"\n", name); + return; + } + + /* Remove the table entry */ + g_hash_table_remove(sub_dissectors->hash_table, guid_val); +} + + static gboolean dissector_delete_all_check (gpointer key _U_, gpointer value, gpointer user_data) { @@ -1403,6 +1537,22 @@ dissector_reset_uint(const char *name, const guint32 pattern) } } +/* Return TRUE if an entry in a uint dissector table is found and has been + * changed (i.e. dissector_change_uint() has been called, such as from + * Decode As, prefs registered via dissector_add_uint_[range_]with_preference), + * etc.), otherwise return FALSE. + */ +gboolean +dissector_is_uint_changed(dissector_table_t const sub_dissectors, const guint32 uint_val) +{ + if (sub_dissectors != NULL) { + dtbl_entry_t *dtbl_entry = find_uint_dtbl_entry(sub_dissectors, uint_val); + if (dtbl_entry != NULL) + return (dtbl_entry->current != dtbl_entry->initial); + } + return FALSE; +} + /* Look for a given value in a given uint dissector table and, if found, call the dissector with the arguments supplied, and return the number of bytes consumed by the dissector, otherwise return 0. */ @@ -1525,7 +1675,7 @@ find_string_dtbl_entry(dissector_table_t const sub_dissectors, const gchar *patt ws_assert_not_reached(); } - if (sub_dissectors->param == TRUE) { + if (sub_dissectors->param == STRING_CASE_INSENSITIVE) { key = g_ascii_strdown(pattern, -1); } else { key = g_strdup(pattern); @@ -1593,7 +1743,7 @@ dissector_add_string(const char *name, const gchar *pattern, dtbl_entry->current = handle; dtbl_entry->initial = dtbl_entry->current; - if (sub_dissectors->param == TRUE) { + if (sub_dissectors->param == STRING_CASE_INSENSITIVE) { key = g_ascii_strdown(pattern, -1); } else { key = g_strdup(pattern); @@ -1616,7 +1766,7 @@ dissector_add_string(const char *name, const gchar *pattern, with a particular pattern. */ /* NOTE: this doesn't use the dissector call variable. It is included to */ -/* be consistant with the dissector_add_string and more importantly to */ +/* be consistent with the dissector_add_string and more importantly to */ /* be used if the technique of adding a temporary dissector is */ /* implemented. */ /* If temporary dissectors are deleted, then the original dissector must */ @@ -1710,6 +1860,22 @@ dissector_reset_string(const char *name, const gchar *pattern) } } +/* Return TRUE if an entry in a uint dissector table is found and has been + * changed (i.e. dissector_change_uint() has been called, such as from + * Decode As, prefs registered via dissector_add_uint_[range_]with_preference), + * etc.), otherwise return FALSE. + */ +gboolean +dissector_is_string_changed(dissector_table_t const sub_dissectors, const gchar *string) +{ + if (sub_dissectors != NULL) { + dtbl_entry_t *dtbl_entry = find_string_dtbl_entry(sub_dissectors, string); + if (dtbl_entry != NULL) + return (dtbl_entry->current != dtbl_entry->initial); + } + return FALSE; +} + /* Look for a given string in a given dissector table and, if found, call the dissector with the arguments supplied, and return length of dissected data, otherwise return 0. */ @@ -1963,7 +2129,7 @@ int dissector_try_guid_new(dissector_table_t sub_dissectors, 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); + 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, @@ -2108,8 +2274,10 @@ dissector_add_for_decode_as(const char *name, dissector_handle_t handle) return; } - /* Ensure the protocol is unique. This prevents confusion when - using Decode As with duplicative entries. + /* Ensure the dissector's description is unique. This prevents + confusion when using Decode As; duplicate descriptions would + make it impossible to distinguish between the dissectors + with the same descriptions. FT_STRING can at least show the string value in the dialog, so we don't do the check for them. */ @@ -2118,7 +2286,8 @@ dissector_add_for_decode_as(const char *name, dissector_handle_t handle) for (entry = sub_dissectors->dissector_handles; entry != NULL; entry = g_slist_next(entry)) { dup_handle = (dissector_handle_t)entry->data; - if (dup_handle->protocol == handle->protocol) + if (dup_handle->description != NULL && + strcmp(dup_handle->description, handle->description) == 0) { const char *dissector_name, *dup_dissector_name; @@ -2128,10 +2297,9 @@ dissector_add_for_decode_as(const char *name, dissector_handle_t handle) dup_dissector_name = dissector_handle_get_dissector_name(dup_handle); if (dup_dissector_name == NULL) dup_dissector_name = "(anonymous)"; - fprintf(stderr, "Duplicate dissectors %s and %s for protocol %s in dissector table %s\n", + fprintf(stderr, "Dissectors %s and %s in dissector table %s have same dissector name %s\n", dissector_name, dup_dissector_name, - proto_get_protocol_short_name(handle->protocol), - name); + name, handle->description); if (wireshark_abort_on_dissector_bug) abort(); } @@ -2150,7 +2318,7 @@ void dissector_add_for_decode_as_with_preference(const char *name, table value would default to 0. Set up a preference value with that information */ - dissector_add_preference(name, handle, 0); + dissector_add_range_preference(name, handle, ""); dissector_add_for_decode_as(name, handle); } @@ -2173,7 +2341,7 @@ dissector_table_get_dissector_handles(dissector_table_t dissector_table) { * Data structure used as user data when iterating dissector handles */ typedef struct lookup_entry { - const gchar* dissector_short_name; + const gchar* dissector_description; dissector_handle_t handle; } lookup_entry_t; @@ -2186,17 +2354,17 @@ find_dissector_in_table(gpointer item, gpointer user_data) { dissector_handle_t handle = (dissector_handle_t)item; lookup_entry_t * lookup = (lookup_entry_t *)user_data; - const gchar *proto_short_name = dissector_handle_get_short_name(handle); - if (proto_short_name && strcmp(lookup->dissector_short_name, proto_short_name) == 0) { + const gchar *description = dissector_handle_get_description(handle); + if (description && strcmp(lookup->dissector_description, description) == 0) { lookup->handle = handle; } } -dissector_handle_t dissector_table_get_dissector_handle(dissector_table_t dissector_table, const gchar* short_name) +dissector_handle_t dissector_table_get_dissector_handle(dissector_table_t dissector_table, const gchar* description) { lookup_entry_t lookup; - lookup.dissector_short_name = short_name; + lookup.dissector_description = description; lookup.handle = NULL; g_slist_foreach(dissector_table->dissector_handles, find_dissector_in_table, &lookup); @@ -2215,22 +2383,27 @@ dissector_table_allow_decode_as(dissector_table_t dissector_table) dissector_table->supports_decode_as = TRUE; } +gboolean +dissector_table_supports_decode_as(dissector_table_t dissector_table) +{ + return dissector_table->supports_decode_as; +} + 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)); + 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; + 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; } /**************************************************/ @@ -2345,7 +2518,7 @@ dissector_table_foreach_handle(const char *table_name, for (tmp = sub_dissectors->dissector_handles; tmp != NULL; tmp = g_slist_next(tmp)) - func(table_name, tmp->data, user_data); + func(table_name, tmp->data, user_data); } /* @@ -2538,14 +2711,15 @@ register_dissector_table(const char *name, const char *ui_name, const int proto, sub_dissectors->ui_name = ui_name; sub_dissectors->type = type; sub_dissectors->param = param; - sub_dissectors->protocol = find_protocol_by_id(proto); + sub_dissectors->protocol = (proto == -1) ? NULL : find_protocol_by_id(proto); sub_dissectors->supports_decode_as = FALSE; g_hash_table_insert(dissector_tables, (gpointer)name, (gpointer) sub_dissectors); return sub_dissectors; } dissector_table_t register_custom_dissector_table(const char *name, - const char *ui_name, const int proto, GHashFunc hash_func, GEqualFunc key_equal_func) + const char *ui_name, const int proto, GHashFunc hash_func, GEqualFunc key_equal_func, + GDestroyNotify key_destroy_func) { dissector_table_t sub_dissectors; @@ -2560,14 +2734,14 @@ dissector_table_t register_custom_dissector_table(const char *name, sub_dissectors->hash_func = hash_func; sub_dissectors->hash_table = g_hash_table_new_full(hash_func, key_equal_func, - &g_free, + key_destroy_func, &g_free); sub_dissectors->dissector_handles = NULL; sub_dissectors->ui_name = ui_name; sub_dissectors->type = FT_BYTES; /* Consider key a "blob" of data, no need to really create new type */ sub_dissectors->param = BASE_NONE; - sub_dissectors->protocol = find_protocol_by_id(proto); + sub_dissectors->protocol = (proto == -1) ? NULL : find_protocol_by_id(proto); sub_dissectors->supports_decode_as = FALSE; g_hash_table_insert(dissector_tables, (gpointer)name, (gpointer) sub_dissectors); return sub_dissectors; @@ -2639,19 +2813,7 @@ get_dissector_table_param(const char *name) static void check_valid_heur_name_or_fail(const char *heur_name) { - gboolean found_invalid = proto_check_field_name(heur_name); - - /* Additionally forbid upper case characters. */ - if (!found_invalid) { - for (guint i = 0; heur_name[i]; i++) { - if (g_ascii_isupper(heur_name[i])) { - found_invalid = TRUE; - break; - } - } - } - - if (found_invalid) { + if (proto_check_field_name_lower(heur_name)) { ws_error("Heuristic Protocol internal name \"%s\" has one or more invalid characters." " Allowed are lowercase, digits, '-', '_' and non-repeating '.'." " This might be caused by an inappropriate plugin or a development error.", heur_name); @@ -2736,6 +2898,7 @@ heur_dissector_add(const char *name, heur_dissector_t dissector, const char *dis hdtbl_entry->short_name = g_strdup(internal_name); hdtbl_entry->list_name = g_strdup(name); hdtbl_entry->enabled = (enable == HEURISTIC_ENABLE); + hdtbl_entry->enabled_by_default = (enable == HEURISTIC_ENABLE); /* do the table insertion */ g_hash_table_insert(heuristic_short_names, (gpointer)hdtbl_entry->short_name, hdtbl_entry); @@ -2804,10 +2967,12 @@ dissector_try_heuristic(heur_dissector_list_t sub_dissectors, tvbuff_t *tvb, heur_dtbl_entry_t *hdtbl_entry; int proto_id; int len; + bool consumed_none; + unsigned saved_desegment_len; guint saved_tree_count = tree ? tree->tree_data->count : 0; /* can_desegment is set to 2 by anyone which offers this api/service. - then everytime a subdissector is called it is decremented by one. + then every time a subdissector is called it is decremented by one. thus only the subdissector immediately ontop of whoever offers this service can use it. We save the current value of "can_desegment" for the @@ -2853,34 +3018,36 @@ dissector_try_heuristic(heur_dissector_list_t sub_dissectors, tvbuff_t *tvb, * Add the protocol name to the layers; we'll remove it * if the dissector fails. */ - pinfo->curr_layer_num++; - wmem_list_append(pinfo->layers, GINT_TO_POINTER(proto_id)); + add_layer(pinfo, proto_id); } pinfo->heur_list_name = hdtbl_entry->list_name; + saved_desegment_len = pinfo->desegment_len; len = (hdtbl_entry->dissector)(tvb, pinfo, tree, data); + consumed_none = len == 0 || (pinfo->desegment_len != saved_desegment_len && pinfo->desegment_offset == 0); if (hdtbl_entry->protocol != NULL && - (len == 0 || (tree && saved_tree_count == tree->tree_data->count))) { + (consumed_none || (tree && saved_tree_count == tree->tree_data->count))) { /* * We added a protocol layer above. The dissector - * didn't accept the packet or it didn't add any + * didn't consume any data or it didn't add any * items to the tree so remove it from the list. */ while (wmem_list_count(pinfo->layers) > saved_layers_len) { - if (len == 0) { - /* - * Only reduce the layer number if the dissector - * rejected the data. Since tree can be NULL on - * the first pass, we cannot check it or it will - * break dissectors that rely on a stable value. - */ - pinfo->curr_layer_num--; - } - wmem_list_remove_frame(pinfo->layers, wmem_list_tail(pinfo->layers)); + /* + * Only reduce the layer number if the dissector + * didn't consume data. Since tree can be NULL on + * the first pass, we cannot check it or it will + * break dissectors that rely on a stable value. + */ + remove_last_layer(pinfo, consumed_none); } } if (len) { + if (ws_log_msg_is_active(WS_LOG_DOMAIN, LOG_LEVEL_DEBUG)) { + ws_debug("Frame: %d | Layers: %s | Dissector: %s\n", pinfo->num, proto_list_layers(pinfo), hdtbl_entry->short_name); + } + *heur_dtbl_entry = hdtbl_entry; /* Bubble the matched entry to the top for faster search next time. */ @@ -2960,7 +3127,7 @@ dissector_all_heur_tables_foreach_table_func (gpointer key, gpointer value, gpoi heur_dissector_foreach_table_info_t *info; info = (heur_dissector_foreach_table_info_t *)user_data; - (*info->caller_func)((gchar *)key, (struct heur_dissector_list *)value, info->caller_data); + (*info->caller_func)((gchar *)key, (struct heur_dissector_list *)value, info->caller_data); } /* @@ -2970,10 +3137,10 @@ dissector_all_heur_tables_foreach_table_func (gpointer key, gpointer value, gpoi static void dissector_all_heur_tables_foreach_list_func (gpointer key, gpointer user_data) { - struct heur_dissector_list *list; + struct heur_dissector_list *list; heur_dissector_foreach_table_info_t *info; - list = (struct heur_dissector_list *)g_hash_table_lookup(heur_dissector_lists, key); + list = (struct heur_dissector_list *)g_hash_table_lookup(heur_dissector_lists, key); info = (heur_dissector_foreach_table_info_t *)user_data; (*info->caller_func)((gchar*)key, list, info->caller_data); } @@ -3010,10 +3177,13 @@ display_heur_dissector_table_entries(const char *table_name, heur_dtbl_entry_t *hdtbl_entry, gpointer user_data _U_) { if (hdtbl_entry->protocol != NULL) { - printf("%s\t%s\t%c\n", + printf("%s\t%s\t%c\t%c\t%s\t%s\n", table_name, proto_get_protocol_filter_name(proto_get_id(hdtbl_entry->protocol)), - (proto_is_protocol_enabled(hdtbl_entry->protocol) && hdtbl_entry->enabled) ? 'T' : 'F'); + (proto_is_protocol_enabled(hdtbl_entry->protocol) && hdtbl_entry->enabled) ? 'T' : 'F', + (proto_is_protocol_enabled_by_default(hdtbl_entry->protocol) && hdtbl_entry->enabled_by_default) ? 'T' : 'F', + hdtbl_entry->short_name, + hdtbl_entry->display_name); } } @@ -3034,7 +3204,7 @@ dissector_dump_heur_decodes(void) heur_dissector_list_t -register_heur_dissector_list(const char *name, const int proto) +register_heur_dissector_list_with_description(const char *name, const char *ui_name, const int proto) { heur_dissector_list_t sub_dissectors; @@ -3046,13 +3216,26 @@ register_heur_dissector_list(const char *name, const int proto) /* Create and register the dissector table for this name; returns */ /* a pointer to the dissector table. */ sub_dissectors = g_slice_new(struct heur_dissector_list); - sub_dissectors->protocol = find_protocol_by_id(proto); + sub_dissectors->protocol = (proto == -1) ? NULL : find_protocol_by_id(proto); + sub_dissectors->ui_name = ui_name; sub_dissectors->dissectors = NULL; /* initially empty */ g_hash_table_insert(heur_dissector_lists, (gpointer)name, (gpointer) sub_dissectors); return sub_dissectors; } +heur_dissector_list_t +register_heur_dissector_list(const char *name, const int proto) +{ + return register_heur_dissector_list_with_description(name, NULL, proto); +} + +const char * +heur_dissector_list_get_description(heur_dissector_list_t list) +{ + return list ? list->ui_name : NULL; +} + /* * Register dissectors by name; used if one dissector always calls a * particular dissector, or if it bases the decision of which dissector @@ -3063,7 +3246,7 @@ register_heur_dissector_list(const char *name, const int proto) /* Get the long name of the protocol for a dissector handle, if it has a protocol. */ const char * -dissector_handle_get_long_name(const dissector_handle_t handle) +dissector_handle_get_protocol_long_name(const dissector_handle_t handle) { if (handle == NULL || handle->protocol == NULL) { return NULL; @@ -3074,20 +3257,29 @@ dissector_handle_get_long_name(const dissector_handle_t handle) /* Get the short name of the protocol for a dissector handle, if it has a protocol. */ const char * -dissector_handle_get_short_name(const dissector_handle_t handle) +dissector_handle_get_protocol_short_name(const dissector_handle_t handle) { - if (handle->protocol == NULL) { - /* - * No protocol (see, for example, the handle for - * dissecting the set of protocols where the first - * octet of the payload is an OSI network layer protocol - * ID). - */ + if (handle == NULL || handle->protocol == NULL) { return NULL; } return proto_get_protocol_short_name(handle->protocol); } +/* For backwards source and binary compatibility */ +const char * +dissector_handle_get_short_name(const dissector_handle_t handle) +{ + return dissector_handle_get_protocol_short_name(handle); +} + +/* Get the description for what the dissector in the dissector handle + dissects, if it has one. */ +const char * +dissector_handle_get_description(const dissector_handle_t handle) +{ + return handle->description; +} + /* Get the index of the protocol for a dissector handle, if it has a protocol. */ int @@ -3111,6 +3303,10 @@ dissector_handle_get_protocol_index(const dissector_handle_t handle) GList* get_dissector_names(void) { + if (!registered_dissectors) { + return NULL; + } + return g_hash_table_get_keys(registered_dissectors); } @@ -3121,13 +3317,13 @@ find_dissector(const char *name) return (dissector_handle_t)g_hash_table_lookup(registered_dissectors, name); } -/** Find a dissector by name and add parent protocol as a depedency*/ +/** Find a dissector by name and add parent protocol as a dependency*/ dissector_handle_t find_dissector_add_dependency(const char *name, const int parent_proto) { dissector_handle_t handle = (dissector_handle_t)g_hash_table_lookup(registered_dissectors, name); if ((handle != NULL) && (parent_proto > 0)) { - register_depend_dissector(proto_get_protocol_short_name(find_protocol_by_id(parent_proto)), dissector_handle_get_short_name(handle)); + register_depend_dissector(proto_get_protocol_short_name(find_protocol_by_id(parent_proto)), dissector_handle_get_protocol_short_name(handle)); } return handle; @@ -3144,16 +3340,32 @@ dissector_handle_get_dissector_name(const dissector_handle_t handle) } static dissector_handle_t -new_dissector_handle(enum dissector_e type, void *dissector, const int proto, const char *name, void *cb_data) +new_dissector_handle(enum dissector_e type, void *dissector, const int proto, const char *name, const char *description, void *cb_data) { struct dissector_handle *handle; handle = wmem_new(wmem_epan_scope(), struct dissector_handle); handle->name = name; + handle->description = description; handle->dissector_type = type; handle->dissector_func = dissector; handle->dissector_data = cb_data; handle->protocol = find_protocol_by_id(proto); + + if (handle->description == NULL) { + /* + * No description for what this dissector dissects + * was supplied; use the short name for the protocol, + * if we have the protocol. + * + * (We may have no protocol; see, for example, the handle + * for dissecting the set of protocols where the first + * octet of the payload is an OSI network layer protocol + * ID.) + */ + if (handle->protocol != NULL) + handle->description = proto_get_protocol_short_name(handle->protocol); + } return handle; } @@ -3161,14 +3373,29 @@ new_dissector_handle(enum dissector_e type, void *dissector, const int proto, co dissector_handle_t create_dissector_handle(dissector_t dissector, const int proto) { - return new_dissector_handle(DISSECTOR_TYPE_SIMPLE, dissector, proto, NULL, NULL); + return new_dissector_handle(DISSECTOR_TYPE_SIMPLE, dissector, proto, NULL, NULL, NULL); } dissector_handle_t create_dissector_handle_with_name(dissector_t dissector, const int proto, const char* name) { - return new_dissector_handle(DISSECTOR_TYPE_SIMPLE, dissector, proto, name, NULL); + return new_dissector_handle(DISSECTOR_TYPE_SIMPLE, dissector, proto, name, NULL, NULL); +} + +dissector_handle_t +create_dissector_handle_with_name_and_description(dissector_t dissector, + const int proto, + const char* name, + const char* description) +{ + return new_dissector_handle(DISSECTOR_TYPE_SIMPLE, dissector, proto, name, description, NULL); +} + +dissector_handle_t +create_dissector_handle_with_data(dissector_cb_t dissector, const int proto, void* cb_data) +{ + return new_dissector_handle(DISSECTOR_TYPE_CALLBACK, dissector, proto, NULL, NULL, cb_data); } /* Destroy an anonymous handle for a dissector. */ @@ -3182,13 +3409,30 @@ destroy_dissector_handle(dissector_handle_t handle) wmem_free(wmem_epan_scope(), handle); } +static void +check_valid_dissector_name_or_fail(const char *name) +{ + if (proto_check_field_name(name)) { + ws_error("Dissector name \"%s\" has one or more invalid characters." + " Allowed are letters, digits, '-', '_' and non-repeating '.'." + " This might be caused by an inappropriate plugin or a development error.", name); + } +} + static dissector_handle_t register_dissector_handle(const char *name, dissector_handle_t handle) { - /* Make sure the registration is unique */ - ws_assert(g_hash_table_lookup(registered_dissectors, name) == NULL); + gboolean new_entry; + + /* Make sure name is "parsing friendly" - descriptions should be + * used for complicated phrases. */ + check_valid_dissector_name_or_fail(name); - g_hash_table_insert(registered_dissectors, (gpointer)name, handle); + new_entry = g_hash_table_insert(registered_dissectors, (gpointer)name, handle); + if (!new_entry) { + /* Make sure the registration is unique */ + ws_error("dissector handle name \"%s\" is already registered", name); + } return handle; } @@ -3199,7 +3443,17 @@ register_dissector(const char *name, dissector_t dissector, const int proto) { struct dissector_handle *handle; - handle = new_dissector_handle(DISSECTOR_TYPE_SIMPLE, dissector, proto, name, NULL); + handle = new_dissector_handle(DISSECTOR_TYPE_SIMPLE, dissector, proto, name, NULL, NULL); + + return register_dissector_handle(name, handle); +} + +dissector_handle_t +register_dissector_with_description(const char *name, const char *description, dissector_t dissector, const int proto) +{ + struct dissector_handle *handle; + + handle = new_dissector_handle(DISSECTOR_TYPE_SIMPLE, dissector, proto, name, description, NULL); return register_dissector_handle(name, handle); } @@ -3209,7 +3463,7 @@ register_dissector_with_data(const char *name, dissector_cb_t dissector, const i { struct dissector_handle *handle; - handle = new_dissector_handle(DISSECTOR_TYPE_CALLBACK, dissector, proto, name, cb_data); + handle = new_dissector_handle(DISSECTOR_TYPE_CALLBACK, dissector, proto, name, NULL, cb_data); return register_dissector_handle(name, handle); } @@ -3318,7 +3572,7 @@ void call_heur_dissector_direct(heur_dtbl_entry_t *heur_dtbl_entry, tvbuff_t *tv DISSECTOR_ASSERT(heur_dtbl_entry); /* can_desegment is set to 2 by anyone which offers this api/service. - then everytime a subdissector is called it is decremented by one. + then every time a subdissector is called it is decremented by one. thus only the subdissector immediately ontop of whoever offers this service can use it. We save the current value of "can_desegment" for the @@ -3346,27 +3600,30 @@ void call_heur_dissector_direct(heur_dtbl_entry_t *heur_dtbl_entry, tvbuff_t *tv /* do NOT change this behavior - wslua uses the protocol short name set here in order to determine which Lua-based heuristic dissector to call */ pinfo->current_proto = proto_get_protocol_short_name(heur_dtbl_entry->protocol); - pinfo->curr_layer_num++; - wmem_list_append(pinfo->layers, GINT_TO_POINTER(proto_get_id(heur_dtbl_entry->protocol))); + add_layer(pinfo, proto_get_id(heur_dtbl_entry->protocol)); } pinfo->heur_list_name = heur_dtbl_entry->list_name; /* call the dissector, in case of failure call data handle (might happen with exported PDUs) */ if (!(*heur_dtbl_entry->dissector)(tvb, pinfo, tree, data)) { - call_dissector_work(data_handle, tvb, pinfo, tree, TRUE, NULL); - /* * We added a protocol layer above. The dissector * didn't accept the packet or it didn't add any * items to the tree so remove it from the list. */ while (wmem_list_count(pinfo->layers) > saved_layers_len) { - pinfo->curr_layer_num--; - wmem_list_remove_frame(pinfo->layers, wmem_list_tail(pinfo->layers)); + remove_last_layer(pinfo, TRUE); } + + call_dissector_work(data_handle, tvb, pinfo, tree, TRUE, NULL); } + /* XXX: Remove layers if it was accepted but didn't actually consume + * data due to desegmentation? (Currently the only callers of this + * are UDP and exported PDUs, so not yet necessary.) + */ + /* Restore info from caller */ pinfo->can_desegment = saved_can_desegment; pinfo->current_proto = saved_curr_proto; @@ -3484,17 +3741,22 @@ dissector_dump_decodes(void) } /* - * Dumps the "layer type"/"decode as" associations to stdout, similar - * to the proto_registrar_dump_*() routines. + * Dumps information about dissector tables to stdout. * * There is one record per line. The fields are tab-delimited. * - * Field 1 = layer type, e.g. "tcp.port" - * Field 2 = selector in decimal - * Field 3 = "decode as" name, e.g. "http" + * Field 1 = dissector table name, e.g. "tcp.port" + * Field 2 = name used for the dissector table in the GUI + * Field 3 = type (textual representation of the ftenum type) + * Field 4 = base for display (for integer types) + * Field 5 = protocol name + * Field 6 = "decode as" support + * + * This does not dump the *individual entries* in the dissector tables, + * i.e. it doesn't show what dissector handles what particular value + * of the key in the dissector table. */ - static void dissector_dump_dissector_tables_display (gpointer key, gpointer user_data _U_) { @@ -3550,6 +3812,30 @@ dissector_dump_dissector_tables_display (gpointer key, gpointer user_data _U_) printf("\n"); } +/** The output format of this function is meant to parallel + * that of dissector_dump_dissector_tables_display(). + * Field 3 is shown as "heuristic". + * Field 4 is omitted, as it is for FT_STRING dissector tables above. + * Field 6 is omitted since "Decode As" doesn't apply. + */ + +static void +dissector_dump_heur_dissector_tables_display (gpointer key, gpointer user_data _U_) +{ + const char *list_name = (const char *)key; + heur_dissector_list_t list; + + list = (heur_dissector_list_t)g_hash_table_lookup(heur_dissector_lists, key); + printf("%s\t%s\theuristic", list_name, list->ui_name ? list->ui_name : list_name); + + if (list->protocol != NULL) { + printf("\t%s", + proto_get_protocol_short_name(list->protocol)); + } else + printf("\t(no protocol)"); + printf("\n"); +} + static gint compare_dissector_key_name(gconstpointer dissector_a, gconstpointer dissector_b) { @@ -3565,6 +3851,62 @@ dissector_dump_dissector_tables(void) list = g_list_sort(list, compare_dissector_key_name); g_list_foreach(list, dissector_dump_dissector_tables_display, NULL); g_list_free(list); + + list = g_hash_table_get_keys(heur_dissector_lists); + list = g_list_sort(list, compare_dissector_key_name); + g_list_foreach(list, dissector_dump_heur_dissector_tables_display, NULL); + g_list_free(list); +} + +/* + * Dumps the entries in the table of registered dissectors. + * + * There is one record per line. The fields are tab-delimited. + * + * Field 1 = dissector name + * Field 2 = dissector description + */ + +struct dissector_info { + const char *name; + const char *description; +}; + +static int +compare_dissector_info_names(const void *arg1, const void *arg2) +{ + const struct dissector_info *info1 = (const struct dissector_info *) arg1; + const struct dissector_info *info2 = (const struct dissector_info *) arg2; + + return strcmp(info1->name, info2->name); +} + +void +dissector_dump_dissectors(void) +{ + GHashTableIter iter; + struct dissector_info *dissectors_info; + guint num_protocols; + gpointer key, value; + guint proto_index; + + g_hash_table_iter_init(&iter, registered_dissectors); + num_protocols = g_hash_table_size(registered_dissectors); + dissectors_info = g_new(struct dissector_info, num_protocols); + proto_index = 0; + while (g_hash_table_iter_next(&iter, &key, &value)) { + dissectors_info[proto_index].name = (const char *)key; + dissectors_info[proto_index].description = + ((dissector_handle_t) value)->description; + proto_index++; + } + qsort(dissectors_info, num_protocols, sizeof(struct dissector_info), + compare_dissector_info_names); + for (proto_index = 0; proto_index < num_protocols; proto_index++) { + printf("%s\t%s\n", dissectors_info[proto_index].name, + dissectors_info[proto_index].description); + } + g_free(dissectors_info); } void |