epan: Add more bookkeeping for layers

Packet info already contains the notion of layer depth for the
current protocol, among all the protocols in the frame. This
adds an extra layer number for the protocols that are the same
as the current one. Obviously this will only go above one if
the protocol is repeated in the stack, such as with IP tunneling.

Adds extra logic to track numbers for each protocol in the frame
and update them when calling a dissector.

The total layer number and protocol layer number are store in
the field info structure so they can be used after dissection,
namely by display filters.
This commit is contained in:
João Valverde 2022-04-09 16:32:21 +01:00 committed by A Wireshark GitLab Utility
parent b53d349583
commit d517feee74
4 changed files with 89 additions and 32 deletions

View File

@ -729,6 +729,67 @@ struct dissector_handle {
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
@ -788,10 +849,9 @@ 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;
@ -836,8 +896,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));
}
}
@ -857,16 +916,13 @@ call_dissector_work(dissector_handle_t handle, tvbuff_t *tvb, packet_info *pinfo
* 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
* 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.
*/
remove_last_layer(pinfo, len == 0);
}
}
pinfo->current_proto = saved_proto;
@ -2875,8 +2931,7 @@ 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;
@ -2890,16 +2945,13 @@ dissector_try_heuristic(heur_dissector_list_t sub_dissectors, tvbuff_t *tvb,
* 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
* 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.
*/
remove_last_layer(pinfo, len == 0);
}
}
if (len) {
@ -3368,8 +3420,7 @@ 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;
@ -3384,8 +3435,7 @@ void call_heur_dissector_direct(heur_dtbl_entry_t *heur_dtbl_entry, tvbuff_t *tv
* 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);
}
}

View File

@ -132,8 +132,10 @@ typedef struct _packet_info {
GHashTable *private_table; /**< a hash table passed from one dissector to another */
wmem_list_t *layers; /**< layers of each protocol */
guint8 curr_layer_num; /**< The current "depth" or layer number in the current frame */
wmem_list_t *layers; /**< layers of each protocol */
wmem_map_t *proto_layers; /** map of proto_id to curr_layer_num. */
guint8 curr_layer_num; /**< The current "depth" or layer number in the current frame */
guint8 curr_proto_layer_num; /**< The current "depth" or layer number for this dissector in the current frame */
guint16 link_number;
guint16 clnp_srcref; /**< clnp/cotp source reference (can't use srcport, this would confuse tpkt) */

View File

@ -6309,6 +6309,9 @@ new_field_info(proto_tree *tree, header_field_info *hfinfo, tvbuff_t *tvb,
fi->appendix_start = 0;
fi->appendix_length = 0;
fi->total_layer_num = tree->tree_data->pinfo->curr_layer_num;
fi->proto_layer_num = tree->tree_data->pinfo->curr_proto_layer_num;
return fi;
}

View File

@ -798,6 +798,8 @@ typedef struct field_info {
item_label_t *rep; /**< string for GUI tree */
tvbuff_t *ds_tvb; /**< data source tvbuff */
fvalue_t value;
int total_layer_num; /**< Hierarchical layer number, for all protocols in the tree. */
int proto_layer_num; /**< Protocol layer number, so 1st, 2nd, 3rd, ... for protocol X. */
} field_info;