Protobuf: add dissecting protobuf fields as wireshark fields preferences, etc.

Two enhancements and one fixed bug:

1. Add dissecting protobuf fields as wireshark (header) fields preferences. User
can input the full names of protobuf fields or messages in Filter toolbar for
searching.

2. Add 'protobuf_field' dissector table. Dissector based on protobuf can register
itself to 'protobuf_field' keyed with the full names of fields of BYETS or STRING
types.

3. A bug about search MESSAGE or ENUM type in context is fixed.

4. Another small enhancement is adding prefs_set_preference_effect_fields() which
can mark a preference that affects fields change (triggering FieldsChanged event).

See the linked bug for sample capture file and .proto files.

Ping-Bug: 16209
Change-Id: Ibc3c45a6d596a8bb983b0d847dd6a22801af7e04
Reviewed-on: https://code.wireshark.org/review/35111
Petri-Dish: Alexis La Goutte <alexis.lagoutte@gmail.com>
Tested-by: Petri Dish Buildbot
Reviewed-by: Peter Wu <peter@lekensteyn.nl>
Reviewed-by: Anders Broman <a.broman58@gmail.com>
This commit is contained in:
Huang Qiangxiong 2019-11-17 20:25:15 +08:00 committed by Anders Broman
parent 5d342b01e3
commit 623b347d1e
13 changed files with 519 additions and 38 deletions

View File

@ -1077,6 +1077,7 @@ libwireshark.so.0 libwireshark0 #MINVER#
prefs_set_gui_theme_is_dark@Base 2.5.0
prefs_set_module_effect_flags@Base 2.5.0
prefs_set_pref@Base 1.9.1
prefs_set_preference_effect_fields@Base 3.3.0
prefs_set_range_value@Base 2.1.0
prefs_set_range_value_work@Base 2.3.0
prefs_set_stashed_range_value@Base 2.3.0

4
docbook/release-notes.adoc Normal file → Executable file
View File

@ -35,6 +35,10 @@ since version 3.2.0:
* Windows executables and installers are now https://support.microsoft.com/en-us/help/4472027/2019-sha-2-code-signing-support-requirement-for-windows-and-wsus[signed using SHA-2 only].
* Save RTP stream to .au supports any codec with 8000 Hz rate supported by Wireshark (shown in RTP player). If save of audio is not possible (unsupported codec or rate), silence of same length is saved and warning is shown.
* C-ares is now a required dependency.
* Protobuf fields can be dissected as wireshark (header) fields that allows user input
the full names of Protobuf fields or messages in Filter toolbar for searching.
* Dissector based on Protobuf can register itself to a new 'protobuf_field' dissector table,
which is keyed with the full names of fields, for further parsing fields of BYETS or STRING type.
// === Removed Features and Support

View File

@ -145,7 +145,20 @@ static int ett_protobuf_packed_repeated = -1;
static gboolean try_dissect_as_string = FALSE;
static gboolean show_all_possible_field_types = FALSE;
static gboolean dissect_bytes_as_string = FALSE;
static gboolean old_dissect_bytes_as_string = FALSE;
static gboolean show_details = FALSE;
static gboolean pbf_as_hf = FALSE; /* dissect protobuf fields as header fields of wireshark */
/* dynamic wireshark header fields for protobuf fields */
static hf_register_info *dynamic_hf = NULL;
static guint dynamic_hf_size = 0;
/* the key is full name of protobuf fields, the value is header field id */
static GHashTable *pbf_hf_hash = NULL;
/* Protobuf field value subdissector table list.
* Only valid for the value of PROTOBUF_TYPE_BYTES or PROTOBUF_TYPE_STRING fields.
*/
static dissector_table_t protobuf_field_subdissector_table;
static dissector_handle_t protobuf_handle;
@ -400,10 +413,27 @@ protobuf_dissect_field_value(proto_tree *value_tree, tvbuff_t *tvb, guint offset
gint32 int32_value;
char* buf;
gboolean add_datatype = TRUE;
proto_item* ti;
proto_item* ti = NULL;
proto_tree* subtree = NULL;
const char* enum_value_name = NULL;
const PbwDescriptor* sub_message_desc = NULL;
const PbwEnumDescriptor* enum_desc = NULL;
int* hf_id_ptr = NULL;
const gchar* field_full_name = field_desc ? pbw_FieldDescriptor_full_name(field_desc) : NULL;
proto_tree* field_tree = proto_item_get_subtree(ti_field);
proto_tree* field_parent_tree = proto_tree_get_parent_tree(field_tree);
proto_tree* pbf_tree = field_tree;
if (pbf_as_hf && field_full_name) {
hf_id_ptr = (int*)g_hash_table_lookup(pbf_hf_hash, field_full_name);
DISSECTOR_ASSERT_HINT(hf_id_ptr && (*hf_id_ptr) > 0, "hf must have been initialized properly");
}
if (pbf_as_hf && hf_id_ptr && !show_details) {
/* set ti_field (Field(x)) item hidden if there is header_field */
proto_item_set_hidden(ti_field);
pbf_tree = field_parent_tree;
}
if (prepend_text == NULL) {
prepend_text = "";
@ -418,6 +448,9 @@ protobuf_dissect_field_value(proto_tree *value_tree, tvbuff_t *tvb, guint offset
if (is_top_level) {
col_append_fstr(pinfo->cinfo, COL_INFO, "=%lf", double_value);
}
if (hf_id_ptr) {
proto_tree_add_double(pbf_tree, *hf_id_ptr, tvb, offset, length, double_value);
}
break;
case PROTOBUF_TYPE_FLOAT:
@ -427,6 +460,9 @@ protobuf_dissect_field_value(proto_tree *value_tree, tvbuff_t *tvb, guint offset
if (is_top_level) {
col_append_fstr(pinfo->cinfo, COL_INFO, "=%f", float_value);
}
if (hf_id_ptr) {
proto_tree_add_float(pbf_tree, *hf_id_ptr, tvb, offset, length, float_value);
}
break;
case PROTOBUF_TYPE_INT64:
@ -437,6 +473,9 @@ protobuf_dissect_field_value(proto_tree *value_tree, tvbuff_t *tvb, guint offset
if (is_top_level) {
col_append_fstr(pinfo->cinfo, COL_INFO, "=%" G_GINT64_MODIFIER "d", int64_value);
}
if (hf_id_ptr) {
proto_tree_add_int64(pbf_tree, *hf_id_ptr, tvb, offset, length, int64_value);
}
break;
case PROTOBUF_TYPE_UINT64:
@ -446,6 +485,9 @@ protobuf_dissect_field_value(proto_tree *value_tree, tvbuff_t *tvb, guint offset
if (is_top_level) {
col_append_fstr(pinfo->cinfo, COL_INFO, "=%" G_GINT64_MODIFIER "u", value);
}
if (hf_id_ptr) {
proto_tree_add_uint64(pbf_tree, *hf_id_ptr, tvb, offset, length, value);
}
break;
case PROTOBUF_TYPE_INT32:
@ -456,7 +498,9 @@ protobuf_dissect_field_value(proto_tree *value_tree, tvbuff_t *tvb, guint offset
if (is_top_level) {
col_append_fstr(pinfo->cinfo, COL_INFO, "=%d", int32_value);
}
if (hf_id_ptr) {
proto_tree_add_int(pbf_tree, *hf_id_ptr, tvb, offset, length, int32_value);
}
break;
case PROTOBUF_TYPE_ENUM:
@ -485,6 +529,9 @@ protobuf_dissect_field_value(proto_tree *value_tree, tvbuff_t *tvb, guint offset
}
}
if (hf_id_ptr) {
proto_tree_add_int(pbf_tree, *hf_id_ptr, tvb, offset, length, int32_value);
}
break;
case PROTOBUF_TYPE_BOOL:
@ -494,29 +541,43 @@ protobuf_dissect_field_value(proto_tree *value_tree, tvbuff_t *tvb, guint offset
if (is_top_level) {
col_append_fstr(pinfo->cinfo, COL_INFO, "=%s", value ? "true" : "false");
}
if (hf_id_ptr) {
proto_tree_add_boolean(pbf_tree, *hf_id_ptr, tvb, offset, length, (guint32)value);
}
break;
case PROTOBUF_TYPE_BYTES:
if (!dissect_bytes_as_string) {
if (hf_id_ptr) {
ti = proto_tree_add_bytes_format_value(pbf_tree, *hf_id_ptr, tvb, offset, length, NULL, "(%u bytes)", length);
}
break;
}
/* or continue dissect BYTES as STRING */
/* FALLTHROUGH */
case PROTOBUF_TYPE_STRING:
proto_tree_add_item_ret_display_string(value_tree, hf_protobuf_value_string, tvb, offset, length, ENC_UTF_8|ENC_NA, wmem_packet_scope(), &buf);
ti = proto_tree_add_item_ret_display_string(value_tree, hf_protobuf_value_string, tvb, offset, length, ENC_UTF_8|ENC_NA, wmem_packet_scope(), &buf);
proto_item_append_text(ti_field, "%s %s", prepend_text, buf);
if (is_top_level) {
col_append_fstr(pinfo->cinfo, COL_INFO, "=%s", buf);
}
if (hf_id_ptr) {
ti = proto_tree_add_item_ret_display_string(pbf_tree, *hf_id_ptr, tvb, offset, length, ENC_UTF_8|ENC_NA, wmem_packet_scope(), &buf);
}
break;
case PROTOBUF_TYPE_GROUP: /* This feature is deprecated. GROUP is identical to Nested MESSAGE. */
case PROTOBUF_TYPE_MESSAGE:
subtree = field_tree;
if (hf_id_ptr) {
ti = proto_tree_add_bytes_format_value(pbf_tree, *hf_id_ptr, tvb, offset, length, NULL, "(%u bytes)", length);
subtree = proto_item_add_subtree(ti, ett_protobuf_message);
}
if (field_desc) {
sub_message_desc = pbw_FieldDescriptor_message_type(field_desc);
if (sub_message_desc) {
dissect_protobuf_message(tvb, offset, length, pinfo,
proto_item_get_subtree(ti_field), sub_message_desc, FALSE);
subtree, sub_message_desc, FALSE);
} else {
expert_add_info(pinfo, ti_field, &et_protobuf_message_type_not_found);
}
@ -532,6 +593,9 @@ protobuf_dissect_field_value(proto_tree *value_tree, tvbuff_t *tvb, guint offset
if (is_top_level) {
col_append_fstr(pinfo->cinfo, COL_INFO, "=%u", (guint32)value);
}
if (hf_id_ptr) {
proto_tree_add_uint(pbf_tree, *hf_id_ptr, tvb, offset, length, (guint32)value);
}
break;
case PROTOBUF_TYPE_SINT32:
@ -541,6 +605,9 @@ protobuf_dissect_field_value(proto_tree *value_tree, tvbuff_t *tvb, guint offset
if (is_top_level) {
col_append_fstr(pinfo->cinfo, COL_INFO, "=%d", int32_value);
}
if (hf_id_ptr) {
proto_tree_add_int(pbf_tree, *hf_id_ptr, tvb, offset, length, int32_value);
}
break;
case PROTOBUF_TYPE_SINT64:
@ -550,6 +617,9 @@ protobuf_dissect_field_value(proto_tree *value_tree, tvbuff_t *tvb, guint offset
if (is_top_level) {
col_append_fstr(pinfo->cinfo, COL_INFO, "=%" G_GINT64_MODIFIER "d", int64_value);
}
if (hf_id_ptr) {
proto_tree_add_int64(pbf_tree, *hf_id_ptr, tvb, offset, length, int64_value);
}
break;
default:
@ -558,6 +628,21 @@ protobuf_dissect_field_value(proto_tree *value_tree, tvbuff_t *tvb, guint offset
break;
}
/* try dissect field value according to protobuf_field dissector table */
if (field_full_name && (field_type == PROTOBUF_TYPE_BYTES || field_type == PROTOBUF_TYPE_STRING)) {
/* determine the tree passing to the subdissector */
subtree = value_tree;
if (ti) {
subtree = proto_item_get_subtree(ti);
if (!subtree) {
subtree = proto_item_add_subtree(ti, ett_protobuf_value);
}
}
dissector_try_string(protobuf_field_subdissector_table, field_full_name,
tvb_new_subset_length(tvb, offset, length), pinfo, subtree, NULL);
}
if (add_datatype)
proto_item_append_text(ti_field, " (%s)", val_to_str(field_type, protobuf_field_type, "Unknown type (%d)"));
@ -664,6 +749,10 @@ dissect_one_protobuf_field(tvbuff_t *tvb, guint* offset, guint maxlen, packet_in
}
}
/* move ti_field_number and ti_wire after ti_field_type (or field_type) for good look */
proto_tree_move_item(field_tree, (ti_field_type ? ti_field_type : ti_field_name), ti_wire);
proto_tree_move_item(field_tree, (ti_field_type ? ti_field_type : ti_field_name), ti_field_number);
/* determine value_length, uint of numeric value and maybe value_length_size according to wire_type */
switch (wire_type)
{
@ -769,11 +858,33 @@ dissect_protobuf_message(tvbuff_t *tvb, guint offset, guint length, packet_info
const gchar* message_name = "<UNKNOWN> Message Type";
guint max_offset = offset + length;
message_tree = proto_tree_add_subtree(protobuf_tree, tvb, offset, length, ett_protobuf_message, &ti_message, "Message");
if (message_desc) {
message_name = pbw_Descriptor_full_name(message_desc);
}
if (pbf_as_hf && message_desc) {
/* support filtering with message name as wireshark field name */
int *hf_id_ptr = (int*)g_hash_table_lookup(pbf_hf_hash, message_name);
DISSECTOR_ASSERT_HINT(hf_id_ptr && (*hf_id_ptr) > 0, "hf of message should initialized properly");
ti_message = proto_tree_add_item(protobuf_tree, *hf_id_ptr, tvb, offset, length, ENC_NA);
proto_item_set_text(ti_message, "Message: %s", message_name);
if (show_details) {
/* show "Message" item and add its fields under this item */
message_tree = proto_item_add_subtree(ti_message, ett_protobuf_message);
} else {
/* hidden "Message" item (but still can be filtered by wireshark field name with "pbm.xxx" prefix),
* and add its fields under the parent (field or protobuf protocol) item directly */
proto_item_set_hidden(ti_message);
message_tree = protobuf_tree;
ti_message = proto_tree_get_parent(message_tree);
proto_item_append_text(ti_message, " (Message: %s)", message_name);
}
} else {
message_tree = proto_tree_add_subtree_format(protobuf_tree, tvb, offset, length, ett_protobuf_message,
&ti_message, "Message: %s", message_name);
}
if (is_top_level) {
col_clear(pinfo->cinfo, COL_PROTOCOL);
col_append_fstr(pinfo->cinfo, COL_PROTOCOL, "PB(%s)", message_name);
@ -781,7 +892,6 @@ dissect_protobuf_message(tvbuff_t *tvb, guint offset, guint length, packet_info
col_clear(pinfo->cinfo, COL_INFO);
}
proto_item_append_text(ti_message, ": %s", message_name);
/* support filtering with message name */
ti = proto_tree_add_string(message_tree, hf_protobuf_message_name, tvb, offset, length, message_name);
proto_item_set_generated(ti);
@ -999,6 +1109,197 @@ update_protobuf_udp_message_types(void)
protobuf_reinit(PREFS_UPDATE_PROTOBUF_UDP_MESSAGE_TYPES);
}
static void
deregister_header_fields(void)
{
if (dynamic_hf) {
/* Deregister all fields */
for (guint i = 0; i < dynamic_hf_size; i++) {
proto_deregister_field(proto_protobuf, *(dynamic_hf[i].p_id));
g_free(dynamic_hf[i].p_id);
/* dynamic_hf[i].name and .abbrev will be freed by proto_add_deregistered_data */
}
proto_add_deregistered_data(dynamic_hf);
dynamic_hf = NULL;
dynamic_hf_size = 0;
}
if (pbf_hf_hash) {
g_hash_table_destroy(pbf_hf_hash);
pbf_hf_hash = NULL;
}
}
/* convert the names of the enum's values to value_string array */
static value_string*
enum_to_value_string(const PbwEnumDescriptor* enum_desc)
{
value_string* vals;
int i, value_count;
if (enum_desc == NULL || (value_count = pbw_EnumDescriptor_value_count(enum_desc)) == 0) {
return NULL;
}
vals = g_new0(value_string, value_count + 1);
for (i = 0; i < value_count; i++) {
const PbwEnumValueDescriptor* enum_value_desc = pbw_EnumDescriptor_value(enum_desc, i);
vals[i].value = pbw_EnumValueDescriptor_number(enum_value_desc);
vals[i].strptr = g_strdup(pbw_EnumValueDescriptor_name(enum_value_desc));
}
/* the strptr of last element of vals must be NULL */
return vals;
}
/* create wireshark header fields according to each message's fields
* and add them into pbf_as_hf hash table */
static void
collect_fields(const PbwDescriptor* message, void* userdata)
{
wmem_list_t* hf_list = (wmem_list_t*) userdata;
hf_register_info* hf;
const PbwFieldDescriptor* field_desc;
const PbwEnumDescriptor* enum_desc;
int i, field_type, total_num = pbw_Descriptor_field_count(message);
/* add message as field */
hf = g_new0(hf_register_info, 1);
hf->p_id = g_new(gint, 1);
*(hf->p_id) = -1;
hf->hfinfo.name = g_strdup(pbw_Descriptor_name(message));
hf->hfinfo.abbrev = g_strdup_printf("pbm.%s", pbw_Descriptor_full_name(message));
hf->hfinfo.type = FT_BYTES;
hf->hfinfo.display = BASE_NONE;
wmem_list_append(hf_list, hf);
g_hash_table_insert(pbf_hf_hash, g_strdup(pbw_Descriptor_full_name(message)), hf->p_id);
/* add fields of this message as fields */
for (i = 0; i < total_num; i++) {
field_desc = pbw_Descriptor_field(message, i);
field_type = pbw_FieldDescriptor_type(field_desc);
if (field_type <= PROTOBUF_TYPE_NONE ||field_type > PROTOBUF_MAX_FIELD_TYPE) {
/* not a valid field type */
continue;
}
hf = g_new0(hf_register_info, 1);
hf->p_id = g_new(gint, 1);
*(hf->p_id) = -1;
hf->hfinfo.name = g_strdup(pbw_FieldDescriptor_name(field_desc));
hf->hfinfo.abbrev = g_strdup_printf("pbf.%s", pbw_FieldDescriptor_full_name(field_desc));
switch (field_type) {
case PROTOBUF_TYPE_DOUBLE:
hf->hfinfo.type = FT_DOUBLE;
hf->hfinfo.display = BASE_NONE;
break;
case PROTOBUF_TYPE_FLOAT:
hf->hfinfo.type = FT_FLOAT;
hf->hfinfo.display = BASE_NONE;
break;
case PROTOBUF_TYPE_INT64:
case PROTOBUF_TYPE_SFIXED64:
case PROTOBUF_TYPE_SINT64:
hf->hfinfo.type = FT_INT64;
hf->hfinfo.display = BASE_DEC;
break;
case PROTOBUF_TYPE_UINT64:
case PROTOBUF_TYPE_FIXED64:
hf->hfinfo.type = FT_UINT64;
hf->hfinfo.display = BASE_DEC;
break;
case PROTOBUF_TYPE_INT32:
case PROTOBUF_TYPE_SFIXED32:
case PROTOBUF_TYPE_SINT32:
hf->hfinfo.type = FT_INT32;
hf->hfinfo.display = BASE_DEC;
break;
case PROTOBUF_TYPE_UINT32:
case PROTOBUF_TYPE_FIXED32:
hf->hfinfo.type = FT_UINT32;
hf->hfinfo.display = BASE_DEC;
break;
case PROTOBUF_TYPE_ENUM:
hf->hfinfo.type = FT_INT32;
hf->hfinfo.display = BASE_DEC;
enum_desc = pbw_FieldDescriptor_enum_type(field_desc);
if (enum_desc) {
hf->hfinfo.strings = enum_to_value_string(enum_desc);
}
break;
case PROTOBUF_TYPE_BOOL:
hf->hfinfo.type = FT_BOOLEAN;
hf->hfinfo.display = BASE_NONE;
break;
case PROTOBUF_TYPE_BYTES:
hf->hfinfo.type = dissect_bytes_as_string ? FT_STRING : FT_BYTES;
hf->hfinfo.display = BASE_NONE;
break;
case PROTOBUF_TYPE_STRING:
hf->hfinfo.type = FT_STRING;
hf->hfinfo.display = BASE_NONE;
break;
case PROTOBUF_TYPE_GROUP:
case PROTOBUF_TYPE_MESSAGE:
hf->hfinfo.type = FT_BYTES;
hf->hfinfo.display = BASE_NONE;
break;
default:
/* should not happen */
break;
}
wmem_list_append(hf_list, hf);
g_hash_table_insert(pbf_hf_hash, g_strdup(pbw_FieldDescriptor_full_name(field_desc)), hf->p_id);
}
}
static void
update_header_fields(gboolean force_reload)
{
if (!force_reload && pbf_as_hf && dynamic_hf) {
/* If initialized, do nothing. */
return;
}
deregister_header_fields();
if (pbf_as_hf) {
int i;
wmem_list_frame_t *it;
wmem_list_t* hf_list = wmem_list_new(NULL);
pbf_hf_hash = g_hash_table_new_full(g_str_hash, g_str_equal, g_free, NULL);
DISSECTOR_ASSERT(pbw_pool);
pbw_foreach_message(pbw_pool, collect_fields, hf_list);
dynamic_hf_size = wmem_list_count(hf_list);
if (dynamic_hf_size == 0) {
deregister_header_fields();
return;
}
dynamic_hf = g_new0(hf_register_info, dynamic_hf_size);
for (it = wmem_list_head(hf_list), i = 0; it; it = wmem_list_frame_next(it), i++) {
hf_register_info* hf = (hf_register_info*) wmem_list_frame_data(it);
/* copy hf_register_info structure */
dynamic_hf[i] = *hf;
g_free(hf);
HFILL_INIT(dynamic_hf[i]);
}
wmem_destroy_list(hf_list);
proto_register_field_array(proto_protobuf, dynamic_hf, dynamic_hf_size);
}
}
static void
protobuf_reinit(int target)
{
@ -1061,6 +1362,7 @@ protobuf_reinit(int target)
}
g_free(source_paths);
update_header_fields(TRUE);
}
/* check if the message types of UDP port exist */
@ -1224,7 +1526,7 @@ proto_register_protobuf(void)
proto_register_field_array(proto_protobuf, hf, array_length(hf));
proto_register_subtree_array(ett, array_length(ett));
protobuf_module = prefs_register_protocol(proto_protobuf, NULL);
protobuf_module = prefs_register_protocol(proto_protobuf, proto_reg_handoff_protobuf);
protobuf_search_paths_uat = uat_new("Protobuf Search Paths",
sizeof(protobuf_search_path_t),
@ -1246,6 +1548,16 @@ proto_register_protobuf(void)
"Specify the directories where .proto files are recursively loaded from, or in which to search for imports.",
protobuf_search_paths_uat);
prefs_register_bool_preference(protobuf_module, "pbf_as_hf",
"Dissect Protobuf fields as Wireshark fields.",
"If Protobuf messages and fields are defined in loaded .proto files,"
" they will be dissected as wireshark fields if this option is turnned on."
" The names of all these wireshark fields will be prefixed with \"pbf.\" (for fields)"
" or \"pbm.\" (for messages) followed by their full names in the .proto files.",
&pbf_as_hf);
prefs_set_preference_effect_fields(protobuf_module, "pbf_as_hf");
prefs_register_bool_preference(protobuf_module, "show_details",
"Show details of message, fields and enums.",
"Show the names of message, field, enum and enum_value."
@ -1291,6 +1603,15 @@ proto_register_protobuf(void)
"Try to show all possible field types for each undefined field according to wire type.",
&show_all_possible_field_types);
prefs_register_static_text_preference(protobuf_module, "field_dissector_table_note",
"Subdissector can register itself in \"protobuf_field\" dissector table for parsing"
" the value of the field of bytes or string type.",
"The key of \"protobuf_field\" table is the full name of field.");
protobuf_field_subdissector_table =
register_dissector_table("protobuf_field", "Protobuf field subdissector table",
proto_protobuf, FT_STRING, BASE_NONE);
expert_protobuf = expert_register_protocol(proto_protobuf);
expert_register_field_array(expert_protobuf, ei, array_length(ei));
@ -1300,6 +1621,12 @@ proto_register_protobuf(void)
void
proto_reg_handoff_protobuf(void)
{
if (protobuf_dissector_called) {
update_header_fields( /* if bytes_as_string preferences changed, we force reload header fields */
(old_dissect_bytes_as_string && !dissect_bytes_as_string) || (!old_dissect_bytes_as_string && dissect_bytes_as_string)
);
}
old_dissect_bytes_as_string = dissect_bytes_as_string;
dissector_add_string("grpc_message_type", "application/grpc", protobuf_handle);
dissector_add_string("grpc_message_type", "application/grpc+proto", protobuf_handle);
}

View File

@ -142,6 +142,7 @@ WS_DLL_PUBLIC guint32 prefs_get_max_value(pref_t *pref);
#define PREF_EFFECT_GUI (1u << 2)
#define PREF_EFFECT_FONT (1u << 3)
#define PREF_EFFECT_GUI_LAYOUT (1u << 4)
#define PREF_EFFECT_FIELDS (1u << 5)
#define PREF_EFFECT_CUSTOM (1u << 31)
/** Fetch flags that show the effect of the preference

View File

@ -1964,6 +1964,15 @@ prefs_register_obsolete_preference(module_t *module, const char *name)
register_preference(module, name, NULL, NULL, PREF_OBSOLETE);
}
void
prefs_set_preference_effect_fields(module_t *module, const char *name)
{
pref_t * pref = prefs_find_preference(module, name);
if (pref) {
prefs_set_effect_flags(pref, prefs_get_effect_flags(pref) | PREF_EFFECT_FIELDS);
}
}
/*
* Check to see if a preference is obsolete.
*/

View File

@ -513,6 +513,14 @@ void prefs_register_decode_as_preference(module_t *module, const char *name,
WS_DLL_PUBLIC void prefs_register_obsolete_preference(module_t *module,
const char *name);
/*
* Mark a preference that affects fields change. This works for bool, enum,
* int, string (containing filename), range preferences. UAT is not included,
* because you can specified UAT_AFFECTS_FIELDS at uat_new().
*/
WS_DLL_PUBLIC void prefs_set_preference_effect_fields(module_t *module,
const char *name);
typedef guint (*pref_cb)(pref_t *pref, gpointer user_data);

View File

@ -183,6 +183,18 @@ pbw_EnumDescriptor_full_name(const PbwEnumDescriptor* anEnum) {
return pbl_enum_descriptor_full_name((const pbl_enum_descriptor_t*) anEnum);
}
/* like EnumDescriptor::value_count() */
int
pbw_EnumDescriptor_value_count(const PbwEnumDescriptor* anEnum) {
return pbl_enum_descriptor_value_count((const pbl_enum_descriptor_t*) anEnum);
}
/* like EnumDescriptor::value() */
const PbwEnumValueDescriptor*
pbw_EnumDescriptor_value(const PbwEnumDescriptor* anEnum, int value_index) {
return (const PbwEnumValueDescriptor*) pbl_enum_descriptor_value((const pbl_enum_descriptor_t*) anEnum, value_index);
}
/* like EnumDescriptor::FindValueByNumber() */
const PbwEnumValueDescriptor*
pbw_EnumDescriptor_FindValueByNumber(const PbwEnumDescriptor* anEnum, int number) {
@ -198,7 +210,20 @@ pbw_EnumValueDescriptor_name(const PbwEnumValueDescriptor* enumValue) {
/* like EnumValueDescriptor::full_name() */
const char*
pbw_EnumValueDescriptor_full_name(const PbwEnumValueDescriptor* enumValue) {
return pbl_enum_value_descriptor_full_name((const pbl_enum_value_descriptor_t*) enumValue);
return pbl_enum_value_descriptor_full_name((const pbl_enum_value_descriptor_t*) enumValue);
}
/* like EnumValueDescriptor::number() */
int
pbw_EnumValueDescriptor_number(const PbwEnumValueDescriptor* enumValue) {
return pbl_enum_value_descriptor_number((const pbl_enum_value_descriptor_t*) enumValue);
}
/* visit all messages of this pool */
void
pbw_foreach_message(const PbwDescriptorPool* pool, void (*cb)(const PbwDescriptor* message, void* userdata), void* userdata)
{
pbl_foreach_message((const pbl_descriptor_pool_t*) pool, (void (*)(const pbl_message_descriptor_t*, void*)) cb, userdata);
}
/*

View File

@ -177,6 +177,14 @@ pbw_EnumDescriptor_name(const PbwEnumDescriptor* anEnum);
const char*
pbw_EnumDescriptor_full_name(const PbwEnumDescriptor* anEnum);
/* like EnumDescriptor::value_count() */
int
pbw_EnumDescriptor_value_count(const PbwEnumDescriptor* anEnum);
/* like EnumDescriptor::value() */
const PbwEnumValueDescriptor*
pbw_EnumDescriptor_value(const PbwEnumDescriptor* anEnum, int value_index);
/* like EnumDescriptor::FindValueByNumber() */
const PbwEnumValueDescriptor*
pbw_EnumDescriptor_FindValueByNumber(const PbwEnumDescriptor* anEnum, int number);
@ -189,6 +197,14 @@ pbw_EnumValueDescriptor_name(const PbwEnumValueDescriptor* enumValue);
const char*
pbw_EnumValueDescriptor_full_name(const PbwEnumValueDescriptor* enumValue);
/* like EnumValueDescriptor::number() */
int
pbw_EnumValueDescriptor_number(const PbwEnumValueDescriptor* enumValue);
/* visit all messages of this pool */
void
pbw_foreach_message(const PbwDescriptorPool* pool, void (*cb)(const PbwDescriptor* message, void* userdata), void* userdata);
#ifdef __cplusplus
}
#endif /* __cplusplus */

View File

@ -248,14 +248,13 @@ pbl_get_node_full_name(pbl_node_t* node)
return node->full_name;
}
/* try to find node globally or in the package of given context */
/* try to find node globally or in the context or parents (message or package) of the context */
static const pbl_node_t*
pbl_find_node_in_context(const pbl_node_t* context, const char* name, pbl_node_type_t nodetype)
{
pbl_node_t* package = NULL;
const pbl_node_t* node = NULL;
pbl_descriptor_pool_t* pool = NULL;
const char* pack_name;
char* parent_name;
char* full_name;
if (context == NULL || name == NULL) {
@ -271,39 +270,36 @@ pbl_find_node_in_context(const pbl_node_t* context, const char* name, pbl_node_t
}
}
/* try find node in context first */
if (context->children_by_name) {
node = (pbl_node_t*) g_hash_table_lookup(context->children_by_name, name);
if (node && node->nodetype == nodetype) {
return node;
}
}
/* find package node */
for (node = context; node; node = node->parent) {
if (node->nodetype == PBL_PACKAGE) {
package = (pbl_node_t*)node;
break;
}
}
/* find pool */
if (context->file) {
pool = context->file->pool;
}
/* try find node in package */
if (package && pool) {
pack_name = pbl_get_node_full_name(package);
full_name = (pack_name[0] == 0) ? g_strdup(name) : g_strconcat(pack_name, ".", name, NULL);
node = pbl_find_node_in_pool(pool, full_name, nodetype);
g_free(full_name);
if (node) {
return node;
}
}
/* try find node in pool directly */
/* try find node in the context or parents (message or package) of the context */
if (pool) {
int remaining;
parent_name = g_strdup(pbl_get_node_full_name((pbl_node_t*) context));
remaining = (int)strlen(parent_name);
while (remaining > 0) {
full_name = g_strconcat(parent_name, ".", name, NULL);
node = pbl_find_node_in_pool(pool, full_name, nodetype);
g_free(full_name);
if (node) {
g_free(parent_name);
return node;
}
/* scan from end to begin, and replace first '.' to '\0' */
for (remaining--; remaining > 0; remaining--) {
if (parent_name[remaining] == '.') {
/* found a potential parent node name */
parent_name[remaining] = '\0';
break; /* break from the 'for' loop, continue 'while' loop */
}
}
}
g_free(parent_name);
/* try find node in pool directly */
return pbl_find_node_in_pool(pool, name, nodetype);
}
@ -538,6 +534,20 @@ pbl_enum_descriptor_full_name(const pbl_enum_descriptor_t* anEnum)
return pbl_get_node_full_name((pbl_node_t*)anEnum);
}
/* like EnumDescriptor::value_count() */
int
pbl_enum_descriptor_value_count(const pbl_enum_descriptor_t* anEnum)
{
return (anEnum && anEnum->values) ? g_slist_length(anEnum->values) : 0;
}
/* like EnumDescriptor::value() */
const pbl_enum_value_descriptor_t*
pbl_enum_descriptor_value(const pbl_enum_descriptor_t* anEnum, int value_index)
{
return (anEnum && anEnum->values) ? (pbl_enum_value_descriptor_t*) g_slist_nth_data(anEnum->values, value_index) : NULL;
}
/* like EnumDescriptor::FindValueByNumber() */
const pbl_enum_value_descriptor_t*
pbl_enum_descriptor_FindValueByNumber(const pbl_enum_descriptor_t* anEnum, int number)
@ -563,6 +573,45 @@ pbl_enum_value_descriptor_full_name(const pbl_enum_value_descriptor_t* enumValue
return pbl_get_node_full_name((pbl_node_t*)enumValue);
}
/* like EnumValueDescriptor::number() */
int
pbl_enum_value_descriptor_number(const pbl_enum_value_descriptor_t* enumValue)
{
return GPOINTER_TO_INT(enumValue->number);
}
static void
pbl_traverse_sub_tree(const pbl_node_t* node, void (*cb)(const pbl_message_descriptor_t*, void*), void* userdata)
{
GSList* it;
if (node == NULL) {
return;
}
if (node->nodetype == PBL_MESSAGE) {
(*cb)((const pbl_message_descriptor_t*) node, userdata);
}
if (node->children) {
for (it = node->children; it; it = it->next) {
pbl_traverse_sub_tree((const pbl_node_t*) it->data, cb, userdata);
}
}
}
/* visit all message in this pool */
void
pbl_foreach_message(const pbl_descriptor_pool_t* pool, void (*cb)(const pbl_message_descriptor_t*, void*), void* userdata)
{
GHashTableIter it;
gpointer key, value;
g_hash_table_iter_init (&it, pool->packages);
while (g_hash_table_iter_next (&it, &key, &value)) {
pbl_traverse_sub_tree((const pbl_node_t*)value, cb, userdata);
}
}
/*
* Following are tree building functions that should only be invoked by protobuf_lang parser.
*/
@ -746,6 +795,7 @@ pbl_add_child(pbl_node_t* parent, pbl_node_t* child)
}
} else if (parent->nodetype == PBL_ENUM && child->nodetype == PBL_ENUM_VALUE) {
pbl_enum_descriptor_t* anEnum = (pbl_enum_descriptor_t*) parent;
anEnum->values = g_slist_append(anEnum->values, child);
/* add child to values_by_number table */
if (anEnum->values_by_number == NULL) {
anEnum->values_by_number = g_hash_table_new_full(g_direct_hash, g_direct_equal, NULL, NULL);
@ -793,6 +843,10 @@ pbl_merge_children(pbl_node_t* to, pbl_node_t* from)
}
} else if (from->nodetype == PBL_ENUM) {
pbl_enum_descriptor_t* anEnum = (pbl_enum_descriptor_t*) from;
if (anEnum->values) {
g_slist_free(anEnum->values);
anEnum->values = NULL;
}
if (anEnum->values_by_number) {
g_hash_table_destroy(anEnum->values_by_number);
anEnum->values_by_number = NULL;
@ -841,6 +895,9 @@ pbl_free_node(gpointer anode)
break;
case PBL_ENUM:
enum_node = (pbl_enum_descriptor_t*) node;
if (enum_node->values) {
g_slist_free(enum_node->values);
}
if (enum_node->values_by_number) {
g_hash_table_destroy(enum_node->values_by_number);
}

View File

@ -101,6 +101,7 @@ typedef struct {
/* like google::protobuf::EnumDescriptor of protobuf cpp library */
typedef struct {
pbl_node_t basic_info;
GSList* values;
GHashTable* values_by_number;
} pbl_enum_descriptor_t;
@ -256,6 +257,14 @@ pbl_enum_descriptor_name(const pbl_enum_descriptor_t* anEnum);
const char*
pbl_enum_descriptor_full_name(const pbl_enum_descriptor_t* anEnum);
/* like EnumDescriptor::value_count() */
int
pbl_enum_descriptor_value_count(const pbl_enum_descriptor_t* anEnum);
/* like EnumDescriptor::value() */
const pbl_enum_value_descriptor_t*
pbl_enum_descriptor_value(const pbl_enum_descriptor_t* anEnum, int value_index);
/* like EnumDescriptor::FindValueByNumber() */
const pbl_enum_value_descriptor_t*
pbl_enum_descriptor_FindValueByNumber(const pbl_enum_descriptor_t* anEnum, int number);
@ -268,6 +277,14 @@ pbl_enum_value_descriptor_name(const pbl_enum_value_descriptor_t* enumValue);
const char*
pbl_enum_value_descriptor_full_name(const pbl_enum_value_descriptor_t* enumValue);
/* like EnumValueDescriptor::number() */
int
pbl_enum_value_descriptor_number(const pbl_enum_value_descriptor_t* enumValue);
/* visit all message in this pool */
void
pbl_foreach_message(const pbl_descriptor_pool_t* pool, void (*cb)(const pbl_message_descriptor_t*, void*), void* userdata);
/*
* Following are tree building functions.
*/

View File

@ -181,6 +181,7 @@ void PreferenceEditorFrame::on_preferenceLineEdit_returnPressed()
void PreferenceEditorFrame::on_buttonBox_accepted()
{
unsigned int changed_flags = 0;
unsigned int apply = 0;
switch(prefs_get_type(pref_)) {
case PREF_UINT:
@ -199,6 +200,7 @@ void PreferenceEditorFrame::on_buttonBox_accepted()
}
if (apply && module_) {
changed_flags = module_->prefs_changed_flags;
pref_unstash_data_t unstashed_data;
unstashed_data.module = module_;
@ -218,6 +220,9 @@ void PreferenceEditorFrame::on_buttonBox_accepted()
on_buttonBox_rejected();
// Emit signals once UI is hidden
if (apply) {
if (changed_flags & PREF_EFFECT_FIELDS) {
wsApp->emitAppSignal(WiresharkApplication::FieldsChanged);
}
wsApp->emitAppSignal(WiresharkApplication::PacketDissectionChanged);
wsApp->emitAppSignal(WiresharkApplication::PreferencesChanged);
}

View File

@ -264,6 +264,10 @@ void PreferencesDialog::on_buttonBox_accepted()
wsApp->setMonospaceFont(prefs.gui_qt_font_name);
if (redissect_flags & PREF_EFFECT_FIELDS) {
wsApp->queueAppSignal(WiresharkApplication::FieldsChanged);
}
if (redissect_flags & PREF_EFFECT_DISSECTION) {
/* Redissect all the packets, and re-evaluate the display filter. */
wsApp->queueAppSignal(WiresharkApplication::PacketDissectionChanged);

View File

@ -274,10 +274,14 @@ void ProtocolPreferencesMenu::boolPreferenceTriggered()
if (!bpa) return;
module_->prefs_changed_flags |= bpa->setBoolValue();
unsigned int changed_flags = module_->prefs_changed_flags;
prefs_apply(module_);
prefs_main_write();
if (changed_flags & PREF_EFFECT_FIELDS) {
wsApp->emitAppSignal(WiresharkApplication::FieldsChanged);
}
/* Protocol preference changes almost always affect dissection,
so don't bother checking flags */
wsApp->emitAppSignal(WiresharkApplication::PacketDissectionChanged);
@ -294,6 +298,9 @@ void ProtocolPreferencesMenu::enumPreferenceTriggered()
prefs_apply(module_);
prefs_main_write();
if (changed_flags & PREF_EFFECT_FIELDS) {
wsApp->emitAppSignal(WiresharkApplication::FieldsChanged);
}
/* Protocol preference changes almost always affect dissection,
so don't bother checking flags */
wsApp->emitAppSignal(WiresharkApplication::PacketDissectionChanged);