summaryrefslogtreecommitdiffstats
path: root/epan/dissectors/packet-protobuf.c
diff options
context:
space:
mode:
Diffstat (limited to '')
-rw-r--r--epan/dissectors/packet-protobuf.c756
1 files changed, 470 insertions, 286 deletions
diff --git a/epan/dissectors/packet-protobuf.c b/epan/dissectors/packet-protobuf.c
index e6f892e6..b1f3b993 100644
--- a/epan/dissectors/packet-protobuf.c
+++ b/epan/dissectors/packet-protobuf.c
@@ -21,7 +21,7 @@
* For example:
* application/grpc,/helloworld.Greeter/SayHello,request
* In this format, we will try to get real protobuf message type by method (service-name.method-name)
- * and in/out type (request / reponse).
+ * and in/out type (request / response).
* For other dissectors can specifies message type directly, like:
* "message," message_type_name
* For example:
@@ -45,19 +45,20 @@
#include "protobuf-helper.h"
#include "packet-protobuf.h"
+#include "epan/dissectors/packet-http.h"
/* converting */
-static inline gdouble
-protobuf_uint64_to_double(guint64 value) {
- union { gdouble f; guint64 i; } double_uint64_union;
+static inline double
+protobuf_uint64_to_double(uint64_t value) {
+ union { double f; uint64_t i; } double_uint64_union;
double_uint64_union.i = value;
return double_uint64_union.f;
}
-static inline gfloat
-protobuf_uint32_to_float(guint32 value) {
- union { gfloat f; guint32 i; } float_uint32_union;
+static inline float
+protobuf_uint32_to_float(uint32_t value) {
+ union { float f; uint32_t i; } float_uint32_union;
float_uint32_union.i = value;
return float_uint32_union.f;
@@ -96,68 +97,71 @@ void proto_reg_handoff_protobuf(void);
#define PREFS_UPDATE_PROTOBUF_SEARCH_PATHS 1
#define PREFS_UPDATE_PROTOBUF_UDP_MESSAGE_TYPES 2
-#define PREFS_UPDATE_ALL (PREFS_UPDATE_PROTOBUF_SEARCH_PATHS | PREFS_UPDATE_PROTOBUF_UDP_MESSAGE_TYPES)
+#define PREFS_UPDATE_PROTOBUF_URI_MESSAGE_TYPES 3
+#define PREFS_UPDATE_ALL (PREFS_UPDATE_PROTOBUF_SEARCH_PATHS | PREFS_UPDATE_PROTOBUF_UDP_MESSAGE_TYPES | PREFS_UPDATE_PROTOBUF_URI_MESSAGE_TYPES)
static void protobuf_reinit(int target);
-static int proto_protobuf = -1;
-static int proto_protobuf_json_mapping = -1;
+static int proto_protobuf;
+static int proto_protobuf_json_mapping;
-static gboolean protobuf_dissector_called = FALSE;
+static bool protobuf_dissector_called;
/* information get from *.proto files */
-static int hf_protobuf_message_name = -1;
-static int hf_protobuf_field_name = -1;
-static int hf_protobuf_field_type = -1;
+static int hf_protobuf_message_name;
+static int hf_protobuf_field_name;
+static int hf_protobuf_field_type;
/* field tag */
-static int hf_protobuf_field_number = -1;
-static int hf_protobuf_wire_type = -1;
+static int hf_protobuf_field_number;
+static int hf_protobuf_wire_type;
/* field value */
-static int hf_protobuf_value_length = -1; /* only Length-delimited field has */
-static int hf_protobuf_value_data = -1;
-static int hf_protobuf_value_double = -1;
-static int hf_protobuf_value_float = -1;
-static int hf_protobuf_value_int64 = -1;
-static int hf_protobuf_value_uint64 = -1;
-static int hf_protobuf_value_int32 = -1;
-static int hf_protobuf_value_uint32 = -1;
-static int hf_protobuf_value_bool = -1;
-static int hf_protobuf_value_string = -1;
-static int hf_protobuf_value_repeated = -1;
-static int hf_json_mapping_line = -1;
+static int hf_protobuf_value_length; /* only Length-delimited field has */
+static int hf_protobuf_value_data;
+static int hf_protobuf_value_double;
+static int hf_protobuf_value_float;
+static int hf_protobuf_value_int64;
+static int hf_protobuf_value_uint64;
+static int hf_protobuf_value_int32;
+static int hf_protobuf_value_uint32;
+static int hf_protobuf_value_bool;
+static int hf_protobuf_value_string;
+static int hf_protobuf_value_repeated;
+static int hf_json_mapping_line;
/* expert */
-static expert_field ei_protobuf_failed_parse_tag = EI_INIT;
-static expert_field ei_protobuf_failed_parse_length_delimited_field = EI_INIT;
-static expert_field ei_protobuf_failed_parse_field = EI_INIT;
-static expert_field ei_protobuf_wire_type_invalid = EI_INIT;
-static expert_field et_protobuf_message_type_not_found = EI_INIT;
-static expert_field et_protobuf_wire_type_not_support_packed_repeated = EI_INIT;
-static expert_field et_protobuf_failed_parse_packed_repeated_field = EI_INIT;
-static expert_field et_protobuf_missing_required_field = EI_INIT;
-static expert_field et_protobuf_default_value_error = EI_INIT;
+static expert_field ei_protobuf_failed_parse_tag;
+static expert_field ei_protobuf_failed_parse_length_delimited_field;
+static expert_field ei_protobuf_failed_parse_field;
+static expert_field ei_protobuf_wire_type_invalid;
+static expert_field ei_protobuf_message_type_not_found;
+static expert_field ei_protobuf_wire_type_not_support_packed_repeated;
+static expert_field ei_protobuf_failed_parse_packed_repeated_field;
+static expert_field ei_protobuf_missing_required_field;
+static expert_field ei_protobuf_default_value_error;
/* trees */
-static int ett_protobuf = -1;
-static int ett_protobuf_message = -1;
-static int ett_protobuf_field = -1;
-static int ett_protobuf_value = -1;
-static int ett_protobuf_packed_repeated = -1;
-static int ett_protobuf_json = -1;
+static int ett_protobuf;
+static int ett_protobuf_message;
+static int ett_protobuf_field;
+static int ett_protobuf_value;
+static int ett_protobuf_packed_repeated;
+static int ett_protobuf_json;
/* preferences */
-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 */
-static gboolean preload_protos = FALSE;
+static bool try_dissect_as_string;
+static bool show_all_possible_field_types;
+static bool dissect_bytes_as_string;
+static bool old_dissect_bytes_as_string;
+static bool show_details;
+static bool pbf_as_hf; /* dissect protobuf fields as header fields of wireshark */
+static bool preload_protos;
/* Show protobuf as JSON similar to https://developers.google.com/protocol-buffers/docs/proto3#json */
-static gboolean display_json_mapping = FALSE;
-static gboolean use_utc_fmt = FALSE;
+static bool display_json_mapping;
+static bool use_utc_fmt;
+static const char* default_message_type = "";
+
#define add_default_value_policy_vals_ENUM_VAL_T_LIST(XXX) \
XXX(ADD_DEFAULT_VALUE_NONE, 0, "none", "None") \
@@ -167,13 +171,13 @@ static gboolean use_utc_fmt = FALSE;
typedef ENUM_VAL_T_ENUM(add_default_value_policy_vals) add_default_value_policy_t;
-static gint add_default_value = (gint) ADD_DEFAULT_VALUE_NONE;
+static int add_default_value = (int) ADD_DEFAULT_VALUE_NONE;
/* dynamic wireshark header fields for protobuf fields */
-static hf_register_info *dynamic_hf = NULL;
-static guint dynamic_hf_size = 0;
+static hf_register_info *dynamic_hf;
+static unsigned dynamic_hf_size;
/* the key is full name of protobuf fields, the value is header field id */
-static GHashTable *pbf_hf_hash = NULL;
+static GHashTable *pbf_hf_hash;
/* Protobuf field value subdissector table list.
* Only valid for the value of PROTOBUF_TYPE_BYTES or PROTOBUF_TYPE_STRING fields.
@@ -184,21 +188,23 @@ static dissector_handle_t protobuf_handle;
/* store varint tvb info */
typedef struct {
- guint offset;
- guint length;
- guint64 value;
+ unsigned offset;
+ unsigned length;
+ uint64_t value;
} protobuf_varint_tvb_info_t;
-static PbwDescriptorPool* pbw_pool = NULL;
+static PbwDescriptorPool* pbw_pool;
/* protobuf source files search paths */
typedef struct {
char* path; /* protobuf source files searching directory path */
- gboolean load_all; /* load all *.proto files in this directory and its sub directories */
+ bool load_all; /* load all *.proto files in this directory and its sub directories */
} protobuf_search_path_t;
-static protobuf_search_path_t* protobuf_search_paths = NULL;
-static guint num_protobuf_search_paths = 0;
+static protobuf_search_path_t* protobuf_search_paths;
+static unsigned num_protobuf_search_paths;
+
+int proto_http;
static void *
protobuf_search_paths_copy_cb(void* n, const void* o, size_t siz _U_)
@@ -206,7 +212,7 @@ protobuf_search_paths_copy_cb(void* n, const void* o, size_t siz _U_)
protobuf_search_path_t* new_rec = (protobuf_search_path_t*)n;
const protobuf_search_path_t* old_rec = (const protobuf_search_path_t*)o;
- /* copy interval values like gint */
+ /* copy interval values like int */
memcpy(new_rec, old_rec, sizeof(protobuf_search_path_t));
if (old_rec->path)
@@ -226,14 +232,16 @@ protobuf_search_paths_free_cb(void*r)
UAT_DIRECTORYNAME_CB_DEF(protobuf_search_paths, path, protobuf_search_path_t)
UAT_BOOL_CB_DEF(protobuf_search_paths, load_all, protobuf_search_path_t)
-/* the protobuf message type of the data on certain udp ports */
+
+
+/* The protobuf message type of the data on certain udp ports */
typedef struct {
range_t *udp_port_range; /* dissect data on these udp ports as protobuf */
- gchar *message_type; /* protobuf message type of data on these udp ports */
+ char *message_type; /* protobuf message type of data on these udp ports */
} protobuf_udp_message_type_t;
-static protobuf_udp_message_type_t* protobuf_udp_message_types = NULL;
-static guint num_protobuf_udp_message_types = 0;
+static protobuf_udp_message_type_t* protobuf_udp_message_types;
+static unsigned num_protobuf_udp_message_types;
static void *
protobuf_udp_message_types_copy_cb(void* n, const void* o, size_t siz _U_)
@@ -241,7 +249,7 @@ protobuf_udp_message_types_copy_cb(void* n, const void* o, size_t siz _U_)
protobuf_udp_message_type_t* new_rec = (protobuf_udp_message_type_t*)n;
const protobuf_udp_message_type_t* old_rec = (const protobuf_udp_message_type_t*)o;
- /* copy interval values like gint */
+ /* copy interval values like int */
memcpy(new_rec, old_rec, sizeof(protobuf_udp_message_type_t));
if (old_rec->udp_port_range)
@@ -262,11 +270,11 @@ protobuf_udp_message_types_update_cb(void *r, char **err)
if (ranges_are_equal(rec->udp_port_range, empty)) {
*err = g_strdup("Must specify UDP port(s) (like 8000 or 8000,8008-8088)");
wmem_free(NULL, empty);
- return FALSE;
+ return false;
}
wmem_free(NULL, empty);
- return TRUE;
+ return true;
}
static void
@@ -281,7 +289,46 @@ protobuf_udp_message_types_free_cb(void*r)
UAT_RANGE_CB_DEF(protobuf_udp_message_types, udp_port_range, protobuf_udp_message_type_t)
UAT_CSTRING_CB_DEF(protobuf_udp_message_types, message_type, protobuf_udp_message_type_t)
-static GSList* old_udp_port_ranges = NULL;
+static GSList* old_udp_port_ranges;
+
+
+
+/* The protobuf message type associated with a request URI */
+typedef struct {
+ char *uri; /* URI appearing in HTTP message */
+ char *message_type; /* associated protobuf message type */
+} protobuf_uri_mapping_t;
+
+static protobuf_uri_mapping_t* protobuf_uri_message_types;
+static unsigned num_protobuf_uri_message_types;
+
+static void *
+protobuf_uri_message_type_copy_cb(void* n, const void* o, size_t siz _U_)
+{
+ protobuf_uri_mapping_t* new_rec = (protobuf_uri_mapping_t*)n;
+ const protobuf_uri_mapping_t* old_rec = (const protobuf_uri_mapping_t*)o;
+
+ if (old_rec->uri)
+ new_rec->uri = g_strdup(old_rec->uri);
+ if (old_rec->message_type)
+ new_rec->message_type = g_strdup(old_rec->message_type);
+
+ return new_rec;
+}
+
+static void
+protobuf_uri_message_type_free_cb(void*r)
+{
+ protobuf_uri_mapping_t* rec = (protobuf_uri_mapping_t*)r;
+
+ g_free(rec->uri);
+ g_free(rec->message_type);
+}
+
+UAT_CSTRING_CB_DEF(protobuf_uri_message_type, uri, protobuf_uri_mapping_t)
+UAT_CSTRING_CB_DEF(protobuf_uri_message_type, message_type, protobuf_uri_mapping_t)
+
+
/* If you use int32 or int64 as the type for a negative number, the resulting varint is always
* ten bytes long - it is, effectively, treated like a very large unsigned integer. If you use
@@ -290,27 +337,27 @@ static GSList* old_udp_port_ranges = NULL;
* value (for instance, -1) have a small varint encoded value too. (refers to protobuf spec)
* sint32 encoded using (n << 1) ^ (n >> 31)
*/
-static gint32
-sint32_decode(guint32 sint32) {
- return (sint32 >> 1) ^ ((gint32)sint32 << 31 >> 31);
+static int32_t
+sint32_decode(uint32_t sint32) {
+ return (sint32 >> 1) ^ ((int32_t)sint32 << 31 >> 31);
}
/* sint64 encoded using (n << 1) ^ (n >> 63) */
-static gint64
-sint64_decode(guint64 sint64) {
- return (sint64 >> 1) ^ ((gint64)sint64 << 63 >> 63);
+static int64_t
+sint64_decode(uint64_t sint64) {
+ return (sint64 >> 1) ^ ((int64_t)sint64 << 63 >> 63);
}
/* Try to get a protobuf field which has a varint value from the tvb.
* The field number, wire type and uint64 value will be output.
* @return the length of this field. Zero if failed.
*/
-static guint
-tvb_get_protobuf_field_uint(tvbuff_t* tvb, guint offset, guint maxlen,
- guint64* field_number, guint32* wire_type, guint64* value)
+static unsigned
+tvb_get_protobuf_field_uint(tvbuff_t* tvb, unsigned offset, unsigned maxlen,
+ uint64_t* field_number, uint32_t* wire_type, uint64_t* value)
{
- guint tag_length, value_length;
- guint64 tag_value;
+ unsigned tag_length, value_length;
+ uint64_t tag_value;
/* parsing the tag of the field */
tag_length = tvb_get_varint(tvb, offset, maxlen, &tag_value, ENC_VARINT_PROTOBUF);
@@ -331,14 +378,14 @@ tvb_get_protobuf_field_uint(tvbuff_t* tvb, guint offset, guint maxlen,
/* Get Protobuf timestamp from the tvb according to the format of google.protobuf.Timestamp.
* return the length parsed.
*/
-static guint
-tvb_get_protobuf_time(tvbuff_t* tvb, guint offset, guint maxlen, nstime_t* timestamp)
+static unsigned
+tvb_get_protobuf_time(tvbuff_t* tvb, unsigned offset, unsigned maxlen, nstime_t* timestamp)
{
- guint field_length;
- guint64 field_number, value;
- guint32 wire_type;
- guint off = offset;
- guint len = maxlen; /* remain bytes */
+ unsigned field_length;
+ uint64_t field_number, value;
+ uint32_t wire_type;
+ unsigned off = offset;
+ unsigned len = maxlen; /* remain bytes */
/* Get the seconds and nanos fields from google.protobuf.Timestamp message which defined:
*
@@ -347,8 +394,7 @@ tvb_get_protobuf_time(tvbuff_t* tvb, guint offset, guint maxlen, nstime_t* times
* int32 nanos = 2;
* }
*/
- timestamp->secs = 0;
- timestamp->nsecs = 0;
+ nstime_set_zero(timestamp);
while (len > 0) {
field_length = tvb_get_protobuf_field_uint(tvb, off, len, &field_number, &wire_type, &value);
@@ -357,28 +403,32 @@ tvb_get_protobuf_time(tvbuff_t* tvb, guint offset, guint maxlen, nstime_t* times
}
if (field_number == 1) {
- timestamp->secs = (gint64)value;
+ timestamp->secs = (time_t)value;
} else if (field_number == 2) {
- timestamp->nsecs = (gint32)value;
+ timestamp->nsecs = (int)value;
}
off += field_length;
len -= field_length;
}
+ if (timestamp->nsecs < 0 || timestamp->nsecs > 999999999) {
+ nstime_set_unset(timestamp);
+ }
+
return maxlen - len;
}
/* declare first because it will be called by dissect_packed_repeated_field_values */
static void
-protobuf_dissect_field_value(proto_tree *value_tree, tvbuff_t *tvb, guint offset, guint length, packet_info *pinfo,
- proto_item *ti_field, int field_type, const guint64 value, const gchar* prepend_text, const PbwFieldDescriptor* field_desc,
- gboolean is_top_level, json_dumper *dumper);
+protobuf_dissect_field_value(proto_tree *value_tree, tvbuff_t *tvb, unsigned offset, unsigned length, packet_info *pinfo,
+ proto_item *ti_field, int field_type, const uint64_t value, const char* prepend_text, const PbwFieldDescriptor* field_desc,
+ bool is_top_level, json_dumper *dumper);
static void
-dissect_protobuf_message(tvbuff_t *tvb, guint offset, guint length, packet_info *pinfo, proto_tree *protobuf_tree,
- const PbwDescriptor* message_desc, int hf_msg, gboolean is_top_level, json_dumper *dumper, wmem_allocator_t* scope, char** retval);
+dissect_protobuf_message(tvbuff_t *tvb, unsigned offset, unsigned length, packet_info *pinfo, proto_tree *protobuf_tree,
+ const PbwDescriptor* message_desc, int hf_msg, bool is_top_level, json_dumper *dumper, wmem_allocator_t* scope, char** retval);
/* Only repeated fields of primitive numeric types (types which use the varint, 32-bit, or 64-bit wire types) can
* be declared "packed".
@@ -386,17 +436,17 @@ dissect_protobuf_message(tvbuff_t *tvb, guint offset, guint length, packet_info
* or likes: tag + fixed64 + fixed64 + fixed64 ...
* Return consumed bytes
*/
-static guint
+static unsigned
// NOLINTNEXTLINE(misc-no-recursion)
-dissect_packed_repeated_field_values(tvbuff_t *tvb, guint start, guint length, packet_info *pinfo,
- proto_item *ti_field, int field_type, const gchar* prepend_text, const PbwFieldDescriptor* field_desc,
+dissect_packed_repeated_field_values(tvbuff_t *tvb, unsigned start, unsigned length, packet_info *pinfo,
+ proto_item *ti_field, int field_type, const char* prepend_text, const PbwFieldDescriptor* field_desc,
json_dumper *dumper)
{
- guint64 sub_value;
- guint sub_value_length;
- guint offset = start;
+ uint64_t sub_value;
+ unsigned sub_value_length;
+ unsigned offset = start;
protobuf_varint_tvb_info_t *info;
- guint max_offset = offset + length;
+ unsigned max_offset = offset + length;
wmem_list_frame_t *lframe;
wmem_list_t* varint_list;
int value_size = 0;
@@ -449,7 +499,7 @@ dissect_packed_repeated_field_values(tvbuff_t *tvb, guint start, guint length, p
for (lframe = wmem_list_head(varint_list); lframe != NULL; lframe = wmem_list_frame_next(lframe)) {
info = (protobuf_varint_tvb_info_t*)wmem_list_frame_data(lframe);
protobuf_dissect_field_value(subtree, tvb, info->offset, info->length, pinfo,
- ti_field, field_type, info->value, prepend_text, field_desc, FALSE, dumper);
+ ti_field, field_type, info->value, prepend_text, field_desc, false, dumper);
prepend_text = ",";
}
@@ -471,15 +521,15 @@ dissect_packed_repeated_field_values(tvbuff_t *tvb, guint start, guint length, p
}
if (length % value_size != 0) {
- expert_add_info(pinfo, ti_field, &et_protobuf_failed_parse_packed_repeated_field);
+ expert_add_info(pinfo, ti_field, &ei_protobuf_failed_parse_packed_repeated_field);
return 0;
}
for (offset = start; offset < max_offset; offset += value_size) {
protobuf_dissect_field_value(subtree, tvb, offset, value_size, pinfo, ti_field, field_type,
- (value_size == 4 ? tvb_get_guint32(tvb, offset, ENC_LITTLE_ENDIAN)
- : tvb_get_guint64(tvb, offset, ENC_LITTLE_ENDIAN)),
- prepend_text, field_desc, FALSE, dumper);
+ (value_size == 4 ? tvb_get_uint32(tvb, offset, ENC_LITTLE_ENDIAN)
+ : tvb_get_uint64(tvb, offset, ENC_LITTLE_ENDIAN)),
+ prepend_text, field_desc, false, dumper);
prepend_text = ",";
}
@@ -487,7 +537,7 @@ dissect_packed_repeated_field_values(tvbuff_t *tvb, guint start, guint length, p
break;
default:
- expert_add_info(pinfo, ti_field, &et_protobuf_wire_type_not_support_packed_repeated);
+ expert_add_info(pinfo, ti_field, &ei_protobuf_wire_type_not_support_packed_repeated);
return 0; /* prevent dead loop */
}
@@ -504,6 +554,7 @@ abs_time_to_rfc3339(wmem_allocator_t *scope, const nstime_t *nstime, bool use_ut
struct tm *tm;
char datetime_format[128];
int nsecs;
+ int width;
char nsecs_buf[32];
if (use_utc) {
@@ -524,10 +575,12 @@ abs_time_to_rfc3339(wmem_allocator_t *scope, const nstime_t *nstime, bool use_ut
return wmem_strdup_printf(scope, datetime_format, "");
nsecs = nstime->nsecs;
- while (nsecs > 0 && (nsecs % 10) == 0) {
- nsecs /= 10;
+ width = 9;
+ while (width > 0 && (nsecs % 1000) == 0) {
+ nsecs /= 1000;
+ width -= 3;
}
- snprintf(nsecs_buf, sizeof(nsecs_buf), ".%d", nsecs);
+ snprintf(nsecs_buf, sizeof(nsecs_buf), ".%0*d", width, nsecs);
return wmem_strdup_printf(scope, datetime_format, nsecs_buf);
}
@@ -535,23 +588,23 @@ abs_time_to_rfc3339(wmem_allocator_t *scope, const nstime_t *nstime, bool use_ut
/* Dissect field value based on a specific type. */
static void
// NOLINTNEXTLINE(misc-no-recursion)
-protobuf_dissect_field_value(proto_tree *value_tree, tvbuff_t *tvb, guint offset, guint length, packet_info *pinfo,
- proto_item *ti_field, int field_type, const guint64 value, const gchar* prepend_text, const PbwFieldDescriptor* field_desc,
- gboolean is_top_level, json_dumper *dumper)
+protobuf_dissect_field_value(proto_tree *value_tree, tvbuff_t *tvb, unsigned offset, unsigned length, packet_info *pinfo,
+ proto_item *ti_field, int field_type, const uint64_t value, const char* prepend_text, const PbwFieldDescriptor* field_desc,
+ bool is_top_level, json_dumper *dumper)
{
- gdouble double_value;
- gfloat float_value;
- gint64 int64_value;
- gint32 int32_value;
+ double double_value;
+ float float_value;
+ int64_t int64_value;
+ int32_t int32_value;
char* buf;
- gboolean add_datatype = TRUE;
+ bool add_datatype = true;
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;
+ const char* 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;
@@ -590,7 +643,7 @@ protobuf_dissect_field_value(proto_tree *value_tree, tvbuff_t *tvb, guint offset
break;
case PROTOBUF_TYPE_FLOAT:
- float_value = protobuf_uint32_to_float((guint32) value);
+ float_value = protobuf_uint32_to_float((uint32_t) value);
proto_tree_add_float(value_tree, hf_protobuf_value_float, tvb, offset, length, float_value);
proto_item_append_text(ti_field, "%s %f", prepend_text, float_value);
if (is_top_level) {
@@ -606,7 +659,7 @@ protobuf_dissect_field_value(proto_tree *value_tree, tvbuff_t *tvb, guint offset
case PROTOBUF_TYPE_INT64:
case PROTOBUF_TYPE_SFIXED64:
- int64_value = (gint64) value;
+ int64_value = (int64_t) value;
proto_tree_add_int64(value_tree, hf_protobuf_value_int64, tvb, offset, length, int64_value);
proto_item_append_text(ti_field, "%s %" PRId64, prepend_text, int64_value);
if (is_top_level) {
@@ -637,7 +690,7 @@ protobuf_dissect_field_value(proto_tree *value_tree, tvbuff_t *tvb, guint offset
case PROTOBUF_TYPE_INT32:
case PROTOBUF_TYPE_SFIXED32:
- int32_value = (gint32)value;
+ int32_value = (int32_t)value;
proto_tree_add_int(value_tree, hf_protobuf_value_int32, tvb, offset, length, int32_value);
proto_item_append_text(ti_field, "%s %d", prepend_text, int32_value);
if (is_top_level) {
@@ -652,7 +705,7 @@ protobuf_dissect_field_value(proto_tree *value_tree, tvbuff_t *tvb, guint offset
break;
case PROTOBUF_TYPE_ENUM:
- int32_value = (gint32) value;
+ int32_value = (int32_t) value;
/* get the name of enum value */
if (field_desc) {
enum_desc = pbw_FieldDescriptor_enum_type(field_desc);
@@ -687,13 +740,13 @@ protobuf_dissect_field_value(proto_tree *value_tree, tvbuff_t *tvb, guint offset
case PROTOBUF_TYPE_BOOL:
if (length > 1) break; /* boolean should not use more than one bytes */
- proto_tree_add_boolean(value_tree, hf_protobuf_value_bool, tvb, offset, length, (guint32)value);
+ proto_tree_add_boolean(value_tree, hf_protobuf_value_bool, tvb, offset, length, value);
proto_item_append_text(ti_field, "%s %s", prepend_text, value ? "true" : "false");
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);
+ proto_tree_add_boolean(pbf_tree, *hf_id_ptr, tvb, offset, length, value);
}
if (field_desc && dumper) {
json_dumper_value_anyf(dumper, value ? "true" : "false");
@@ -753,12 +806,16 @@ protobuf_dissect_field_value(proto_tree *value_tree, tvbuff_t *tvb, guint offset
if (field_desc) {
sub_message_desc = pbw_FieldDescriptor_message_type(field_desc);
if (sub_message_desc == NULL) {
- expert_add_info(pinfo, ti_field, &et_protobuf_message_type_not_found);
+ expert_add_info(pinfo, ti_field, &ei_protobuf_message_type_not_found);
}
}
if (sub_message_desc) {
dissect_protobuf_message(tvb, offset, length, pinfo, pbf_as_hf ? pbf_tree : subtree, sub_message_desc,
- hf_id_ptr ? *hf_id_ptr : -1, FALSE, dumper, wmem_packet_scope(), &buf);
+ hf_id_ptr ? *hf_id_ptr : -1,
+ false, // not top level
+ dumper,
+ pinfo->pool,
+ &buf);
if (buf) { /* append the value in string format to ti_field node */
proto_item_append_text(ti_field, "= %s", buf);
@@ -772,21 +829,21 @@ protobuf_dissect_field_value(proto_tree *value_tree, tvbuff_t *tvb, guint offset
case PROTOBUF_TYPE_UINT32:
case PROTOBUF_TYPE_FIXED32: /* same as UINT32 */
- proto_tree_add_uint(value_tree, hf_protobuf_value_uint32, tvb, offset, length, (guint32)value);
- proto_item_append_text(ti_field, "%s %u", prepend_text, (guint32)value);
+ proto_tree_add_uint(value_tree, hf_protobuf_value_uint32, tvb, offset, length, (uint32_t)value);
+ proto_item_append_text(ti_field, "%s %u", prepend_text, (uint32_t)value);
if (is_top_level) {
- col_append_fstr(pinfo->cinfo, COL_INFO, "=%u", (guint32)value);
+ col_append_fstr(pinfo->cinfo, COL_INFO, "=%u", (uint32_t)value);
}
if (hf_id_ptr) {
- proto_tree_add_uint(pbf_tree, *hf_id_ptr, tvb, offset, length, (guint32)value);
+ proto_tree_add_uint(pbf_tree, *hf_id_ptr, tvb, offset, length, (uint32_t)value);
}
if (field_desc && dumper) {
- json_dumper_value_anyf(dumper, "%u", (guint32)value);
+ json_dumper_value_anyf(dumper, "%u", (uint32_t)value);
}
break;
case PROTOBUF_TYPE_SINT32:
- int32_value = sint32_decode((guint32)value);
+ int32_value = sint32_decode((uint32_t)value);
proto_tree_add_int(value_tree, hf_protobuf_value_int32, tvb, offset, length, int32_value);
proto_item_append_text(ti_field, "%s %d", prepend_text, int32_value);
if (is_top_level) {
@@ -817,7 +874,7 @@ protobuf_dissect_field_value(proto_tree *value_tree, tvbuff_t *tvb, guint offset
default:
/* ignore unknown field type */
- add_datatype = FALSE;
+ add_datatype = false;
break;
}
@@ -843,8 +900,8 @@ protobuf_dissect_field_value(proto_tree *value_tree, tvbuff_t *tvb, guint offset
/* add all possible values according to field types. */
static void
// NOLINTNEXTLINE(misc-no-recursion)
-protobuf_try_dissect_field_value_on_multi_types(proto_tree *value_tree, tvbuff_t *tvb, guint offset, guint length,
- packet_info *pinfo, proto_item *ti_field, int* field_types, const guint64 value, const gchar* prepend_text,
+protobuf_try_dissect_field_value_on_multi_types(proto_tree *value_tree, tvbuff_t *tvb, unsigned offset, unsigned length,
+ packet_info *pinfo, proto_item *ti_field, int* field_types, const uint64_t value, const char* prepend_text,
json_dumper *dumper)
{
int i;
@@ -854,34 +911,34 @@ protobuf_try_dissect_field_value_on_multi_types(proto_tree *value_tree, tvbuff_t
}
for (i = 0; field_types[i] != PROTOBUF_TYPE_NONE; ++i) {
- protobuf_dissect_field_value(value_tree, tvb, offset, length, pinfo, ti_field, field_types[i], value, prepend_text, NULL, FALSE, dumper);
+ protobuf_dissect_field_value(value_tree, tvb, offset, length, pinfo, ti_field, field_types[i], value, prepend_text, NULL, false, dumper);
prepend_text = ",";
}
}
-static gboolean
+static bool
// NOLINTNEXTLINE(misc-no-recursion)
-dissect_one_protobuf_field(tvbuff_t *tvb, guint* offset, guint maxlen, packet_info *pinfo, proto_tree *protobuf_tree,
- const PbwDescriptor* message_desc, gboolean is_top_level, const PbwFieldDescriptor** field_desc_ptr,
+dissect_one_protobuf_field(tvbuff_t *tvb, unsigned* offset, unsigned maxlen, packet_info *pinfo, proto_tree *protobuf_tree,
+ const PbwDescriptor* message_desc, bool is_top_level, const PbwFieldDescriptor** field_desc_ptr,
const PbwFieldDescriptor* prev_field_desc, json_dumper *dumper)
{
- guint64 tag_value; /* tag value = (field_number << 3) | wire_type */
- guint tag_length; /* how many bytes this tag has */
- guint64 field_number;
- guint32 wire_type;
- guint64 value_uint64; /* uint64 value of numeric field (type of varint, 64-bit, 32-bit */
- guint value_length;
- guint value_length_size = 0; /* only Length-delimited field has it */
+ uint64_t tag_value; /* tag value = (field_number << 3) | wire_type */
+ unsigned tag_length; /* how many bytes this tag has */
+ uint64_t field_number;
+ uint32_t wire_type;
+ uint64_t value_uint64; /* uint64 value of numeric field (type of varint, 64-bit, 32-bit */
+ unsigned value_length;
+ unsigned value_length_size = 0; /* only Length-delimited field has it */
proto_item *ti_field, *ti_field_number, *ti_wire, *ti_value_length = NULL;
proto_item *ti_value, *ti_field_name, *ti_field_type = NULL;
proto_tree *field_tree;
proto_tree *value_tree;
- const gchar* field_name = NULL;
+ const char* field_name = NULL;
int field_type = -1;
- gboolean is_packed = FALSE;
- gboolean is_repeated = FALSE;
+ bool is_packed = false;
+ bool is_repeated = false;
const PbwFieldDescriptor* field_desc = NULL;
- guint start_offset = *offset;
+ unsigned start_offset = *offset;
/* A protocol buffer message is a series of key-value pairs. The binary version of a message just uses
* the field's number as the key. a wire type that provides just enough information to find the length of
@@ -905,7 +962,7 @@ dissect_one_protobuf_field(tvbuff_t *tvb, guint* offset, guint maxlen, packet_in
if (tag_length == 0) { /* not found a valid varint */
expert_add_info(pinfo, ti_field, &ei_protobuf_failed_parse_tag);
- return FALSE;
+ return false;
}
ti_field_number = proto_tree_add_item_ret_uint64(field_tree, hf_protobuf_field_number, tvb, *offset, tag_length, ENC_LITTLE_ENDIAN|ENC_VARINT_PROTOBUF, &field_number);
@@ -959,7 +1016,7 @@ dissect_one_protobuf_field(tvbuff_t *tvb, guint* offset, guint maxlen, packet_in
value_length = tvb_get_varint(tvb, *offset, maxlen - tag_length, &value_uint64, ENC_VARINT_PROTOBUF);
if (value_length == 0) {
expert_add_info(pinfo, ti_wire, &ei_protobuf_failed_parse_field);
- return FALSE;
+ return false;
}
break;
@@ -979,19 +1036,19 @@ dissect_one_protobuf_field(tvbuff_t *tvb, guint* offset, guint maxlen, packet_in
value_length_size = tvb_get_varint(tvb, *offset, maxlen - tag_length, &value_uint64, ENC_VARINT_PROTOBUF);
if (value_length_size == 0) {
expert_add_info(pinfo, ti_field, &ei_protobuf_failed_parse_length_delimited_field);
- return FALSE;
+ return false;
}
ti_value_length = proto_tree_add_uint64(field_tree, hf_protobuf_value_length, tvb, *offset, value_length_size, value_uint64);
(*offset) += value_length_size;
- /* we believe the length of following value will not be bigger than guint */
- value_length = (guint) value_uint64;
+ /* we believe the length of following value will not be bigger than unsigned */
+ value_length = (unsigned) value_uint64;
break;
default:
expert_add_info(pinfo, ti_wire, &ei_protobuf_wire_type_invalid);
- return FALSE;
+ return false;
}
proto_item_set_len(ti_field, tag_length + value_length_size + value_length);
@@ -1062,7 +1119,7 @@ dissect_one_protobuf_field(tvbuff_t *tvb, guint* offset, guint maxlen, packet_in
}
(*offset) += value_length;
- return TRUE;
+ return true;
}
/* Make Protobuf fields that are not serialized on the wire (missing in capture files) to be displayed
@@ -1086,34 +1143,34 @@ dissect_one_protobuf_field(tvbuff_t *tvb, guint* offset, guint maxlen, packet_in
* - ADD_DEFAULT_VALUE_ALL -- missing fields of all situations (1, 2, 3, and 4) will be displayed.
*/
static void
-add_missing_fields_with_default_values(tvbuff_t* tvb, guint offset, packet_info* pinfo, proto_tree* message_tree,
- const PbwDescriptor* message_desc, int* parsed_fields, int parsed_fields_count, json_dumper *dumper)
+add_missing_fields_with_default_values(tvbuff_t* tvb, unsigned offset, packet_info* pinfo, proto_tree* message_tree,
+ const PbwDescriptor* message_desc, wmem_map_t* parsed_fields, json_dumper *dumper)
{
const PbwFieldDescriptor* field_desc;
- const gchar* field_name, * field_full_name, * enum_value_name, * string_value;
+ const char* field_name, * field_full_name, * enum_value_name, * string_value;
int field_count = pbw_Descriptor_field_count(message_desc);
- int field_type, i, j;
- guint64 field_number;
- gboolean is_required;
- gboolean is_repeated;
- gboolean has_default_value; /* explicitly-declared default value */
+ int field_type, i;
+ uint64_t field_number;
+ bool is_required;
+ bool is_repeated;
+ bool has_default_value; /* explicitly-declared default value */
proto_item* ti_message = proto_tree_get_parent(message_tree);
proto_item* ti_field, * ti_field_number, * ti_field_name, * ti_field_type, * ti_value, * ti_pbf;
proto_tree* field_tree, * pbf_tree;
int* hf_id_ptr;
- gdouble double_value;
- gfloat float_value;
- gint64 int64_value;
- gint32 int32_value;
- guint64 uint64_value;
- guint32 uint32_value;
- gboolean bool_value;
- gint size;
+ double double_value;
+ float float_value;
+ int64_t int64_value;
+ int32_t int32_value;
+ uint64_t uint64_value;
+ uint32_t uint32_value;
+ bool bool_value;
+ int size;
const PbwEnumValueDescriptor* enum_value_desc;
for (i = 0; i < field_count; i++) {
field_desc = pbw_Descriptor_field(message_desc, i);
- field_number = (guint64) pbw_FieldDescriptor_number(field_desc);
+ field_number = (uint64_t) pbw_FieldDescriptor_number(field_desc);
field_type = pbw_FieldDescriptor_type(field_desc);
is_required = pbw_FieldDescriptor_is_required(field_desc);
is_repeated = pbw_FieldDescriptor_is_repeated(field_desc);
@@ -1143,22 +1200,15 @@ add_missing_fields_with_default_values(tvbuff_t* tvb, guint offset, packet_info*
}
/* check if it is parsed */
- if (parsed_fields && parsed_fields_count > 0) {
- for (j = 0; j < parsed_fields_count; j++) {
- if ((guint64) parsed_fields[j] == field_number) {
- break;
- }
- }
- if (j < parsed_fields_count) {
- continue; /* this field is parsed */
- }
+ if (wmem_map_lookup(parsed_fields, GINT_TO_POINTER(field_number))) {
+ continue; /* this field is parsed */
}
field_name = pbw_FieldDescriptor_name(field_desc);
/* this field is not found in message payload */
if (is_required) {
- expert_add_info_format(pinfo, ti_message, &et_protobuf_missing_required_field, "missing required field '%s'", field_name);
+ expert_add_info_format(pinfo, ti_message, &ei_protobuf_missing_required_field, "missing required field '%s'", field_name);
continue;
}
@@ -1295,15 +1345,15 @@ add_missing_fields_with_default_values(tvbuff_t* tvb, guint offset, packet_info*
DISSECTOR_ASSERT_HINT(has_default_value && string_value, "Bytes field must have default value!");
if (dumper) {
json_dumper_begin_base64(dumper);
- json_dumper_write_base64(dumper, (const guchar *)string_value, size);
+ json_dumper_write_base64(dumper, (const unsigned char *)string_value, size);
json_dumper_end_base64(dumper);
}
if (!dissect_bytes_as_string) {
- ti_value = proto_tree_add_bytes_with_length(field_tree, hf_protobuf_value_data, tvb, offset, 0, (const guint8*) string_value, size);
+ ti_value = proto_tree_add_bytes_with_length(field_tree, hf_protobuf_value_data, tvb, offset, 0, (const uint8_t*) string_value, size);
proto_item_append_text(ti_field, " (%d bytes)", size);
/* the type of *hf_id_ptr MUST be FT_BYTES now */
if (hf_id_ptr) {
- ti_pbf = proto_tree_add_bytes_with_length(pbf_tree, *hf_id_ptr, tvb, offset, 0, (const guint8*)string_value, size);
+ ti_pbf = proto_tree_add_bytes_with_length(pbf_tree, *hf_id_ptr, tvb, offset, 0, (const uint8_t*)string_value, size);
}
break;
}
@@ -1345,7 +1395,7 @@ add_missing_fields_with_default_values(tvbuff_t* tvb, guint offset, packet_info*
}
break;
} else {
- expert_add_info_format(pinfo, ti_message, &et_protobuf_default_value_error, "enum value of field '%s' not found in *.proto!", field_name);
+ expert_add_info_format(pinfo, ti_message, &ei_protobuf_default_value_error, "enum value of field '%s' not found in *.proto!", field_name);
}
break;
@@ -1376,43 +1426,43 @@ add_missing_fields_with_default_values(tvbuff_t* tvb, guint offset, packet_info*
static void
// NOLINTNEXTLINE(misc-no-recursion)
-dissect_protobuf_message(tvbuff_t *tvb, guint offset, guint length, packet_info *pinfo, proto_tree *protobuf_tree,
- const PbwDescriptor* message_desc, int hf_msg, gboolean is_top_level, json_dumper *dumper, wmem_allocator_t* scope, char** retval)
+dissect_protobuf_message(tvbuff_t *tvb, unsigned offset, unsigned length, packet_info *pinfo, proto_tree *protobuf_tree,
+ const PbwDescriptor* message_desc, int hf_msg, bool is_top_level, json_dumper *dumper, wmem_allocator_t* scope, char** retval)
{
proto_tree *message_tree;
proto_item *ti_message, *ti;
- const gchar* message_name = "<UNKNOWN> Message Type";
- guint max_offset = offset + length;
+ const char* message_name = "<UNKNOWN>";
+ unsigned max_offset = offset + length;
const PbwFieldDescriptor* field_desc;
const PbwFieldDescriptor* prev_field_desc = NULL;
- int* parsed_fields = NULL; /* store parsed field numbers. end with NULL */
- int parsed_fields_count = 0;
- int field_count = 0;
+ wmem_map_t* parsed_fields = NULL; /* store parsed field numbers. */
nstime_t timestamp = { 0 };
- gchar* value_label = NULL; /* The label representing the value of some wellknown message, such as google.protobuf.Timestamp */
+ char* value_label = NULL; /* The label representing the value of some wellknown message, such as google.protobuf.Timestamp */
if (message_desc) {
message_name = pbw_Descriptor_full_name(message_desc);
- /* N.B. extra entries are needed because of possibly repeated items within message.
- TODO: use dynamic wmem_array_t? Don't fancy void* interface... */
- field_count = pbw_Descriptor_field_count(message_desc) + 256;
- if (add_default_value && field_count > 0) {
- parsed_fields = wmem_alloc0_array(pinfo->pool, int, field_count);
+
+ if (add_default_value) {
+ parsed_fields = wmem_map_new(pinfo->pool, g_direct_hash, g_direct_equal);
}
if (strcmp(message_name, "google.protobuf.Timestamp") == 0) {
/* parse this message as timestamp */
tvb_get_protobuf_time(tvb, offset, length, &timestamp);
- value_label = abs_time_to_rfc3339(scope ? scope : pinfo->pool, &timestamp, use_utc_fmt);
- if (hf_msg != -1) {
- ti = proto_tree_add_time_format_value(protobuf_tree, hf_msg, tvb, offset, length, &timestamp, "%s", value_label);
- protobuf_tree = proto_item_add_subtree(ti, ett_protobuf_message);
- }
- if (dumper) {
- json_dumper_value_string(dumper, value_label);
- dumper = NULL; /* this message will not dump as JSON object */
+ if (!nstime_is_unset(&timestamp)) {
+ value_label = abs_time_to_rfc3339(scope ? scope : pinfo->pool, &timestamp, use_utc_fmt);
+ if (hf_msg > 0) {
+ ti = proto_tree_add_time_format_value(protobuf_tree, hf_msg, tvb, offset, length, &timestamp, "%s", value_label);
+ protobuf_tree = proto_item_add_subtree(ti, ett_protobuf_message);
+ }
+ if (dumper) {
+ json_dumper_value_string(dumper, value_label);
+ dumper = NULL; /* this message will not dump as JSON object */
+ }
+ } else {
+ expert_add_info(pinfo, proto_tree_get_parent(protobuf_tree), &ei_protobuf_failed_parse_field);
}
- } else if (hf_msg != -1) {
+ } else if (hf_msg > 0) {
ti = proto_tree_add_bytes_format_value(protobuf_tree, hf_msg, tvb, offset, length, NULL, "(%u bytes)", length);
protobuf_tree = proto_item_add_subtree(ti, ett_protobuf_message);
}
@@ -1442,10 +1492,14 @@ dissect_protobuf_message(tvbuff_t *tvb, guint offset, guint length, packet_info
}
if (is_top_level) {
- col_clear(pinfo->cinfo, COL_PROTOCOL);
+ if (col_get_text(pinfo->cinfo, COL_PROTOCOL) && strlen(col_get_text(pinfo->cinfo, COL_PROTOCOL))) {
+ col_append_str(pinfo->cinfo, COL_PROTOCOL, "/");
+ }
+ else {
+ col_clear(pinfo->cinfo, COL_PROTOCOL);
+ col_clear(pinfo->cinfo, COL_INFO);
+ }
col_append_fstr(pinfo->cinfo, COL_PROTOCOL, "PB(%s)", message_name);
- /* Top-level info will get written into Info column. */
- col_clear(pinfo->cinfo, COL_INFO);
}
/* support filtering with message name */
@@ -1471,12 +1525,7 @@ dissect_protobuf_message(tvbuff_t *tvb, guint offset, guint length, packet_info
}
if (parsed_fields && field_desc) {
- if (parsed_fields_count < field_count) {
- parsed_fields[parsed_fields_count++] = pbw_FieldDescriptor_number(field_desc);
- }
- else {
- /* TODO: error? Means default values may not be set/shown.. */
- }
+ wmem_map_insert(parsed_fields, GINT_TO_POINTER(pbw_FieldDescriptor_number(field_desc)), GINT_TO_POINTER(1));
}
prev_field_desc = field_desc;
@@ -1489,18 +1538,14 @@ dissect_protobuf_message(tvbuff_t *tvb, guint offset, guint length, packet_info
}
/* add default values for missing fields */
- if (add_default_value && field_count > 0) {
- add_missing_fields_with_default_values(tvb, offset, pinfo, message_tree, message_desc, parsed_fields, parsed_fields_count, dumper);
+ if (add_default_value && parsed_fields) {
+ add_missing_fields_with_default_values(tvb, offset, pinfo, message_tree, message_desc, parsed_fields, dumper);
}
if (message_desc && dumper) {
json_dumper_end_object(dumper);
}
- if (parsed_fields) {
- wmem_free(pinfo->pool, parsed_fields);
- }
-
if (value_label) {
ti = proto_tree_add_item(message_tree, hf_text_only, tvb, offset, length, ENC_NA);
proto_item_set_text(ti, "[Message Value: %s]", value_label);
@@ -1516,8 +1561,8 @@ static const PbwDescriptor*
find_message_type_by_udp_port(packet_info *pinfo)
{
range_t* udp_port_range;
- const gchar* message_type;
- guint i;
+ const char* message_type;
+ unsigned i;
for (i = 0; i < num_protobuf_udp_message_types; ++i) {
udp_port_range = protobuf_udp_message_types[i].udp_port_range;
if (value_is_in_range(udp_port_range, pinfo->srcport)
@@ -1532,20 +1577,78 @@ find_message_type_by_udp_port(packet_info *pinfo)
return NULL;
}
+static bool
+// NOLINTNEXTLINE(misc-no-recursion)
+uri_matches_pattern(const char *request_uri, const char *uri_pattern, int depth)
+{
+ /* Arbitrary recursion depth limit.. */
+ if (depth > 32) {
+ return false;
+ }
+
+ /* Exact match */
+ if (strcmp(request_uri, uri_pattern)==0) {
+ return true;
+ }
+
+ /* Match if both strings now empty */
+ if (strlen(uri_pattern)==0 && strlen(request_uri)==0) {
+ return true;
+ }
+
+ /* Fail if remaining, unmatched pattern but reached end of uri */
+ if (strlen(uri_pattern)>0 && strlen(request_uri)==0) {
+ return false;
+ }
+
+ /* If remainder of pattern is just '*', it matches */
+ if (strlen(uri_pattern)==1 && uri_pattern[0] == '*') {
+ return true;
+ }
+
+ /* If next uri_pattern char is not '*', needs to match exactly */
+ if (strlen(uri_pattern) && uri_pattern[0] != '*') {
+
+ /* Skip identical characters */
+ int n;
+ for (n=0; strlen(request_uri+n) && strlen(request_uri+n) && uri_pattern[n] != '*'; n++) {
+ if (request_uri[n] == uri_pattern[n]) {
+ continue;
+ }
+ else {
+ /* Fail if non-wildcarded comparison fails */
+ return false;
+ }
+ }
+
+ /* Recursively call n characters along */
+ return uri_matches_pattern(request_uri+n, uri_pattern+n, depth+1);
+ }
+
+ if (strlen(uri_pattern) && uri_pattern[0] == '*') {
+ /* We are at a '*'. Test with/without moving past it now */
+ return (uri_matches_pattern(request_uri+1, uri_pattern, depth+1) ||
+ uri_matches_pattern(request_uri+1, uri_pattern+1, depth+1));
+ }
+
+ return false;
+}
+
+
static int
dissect_protobuf(tvbuff_t *tvb, packet_info *pinfo, proto_tree *tree, void *data)
{
proto_item *ti;
proto_tree *protobuf_tree, *protobuf_json_tree;
- guint offset = 0;
- guint i;
+ unsigned offset = 0;
+ unsigned i;
const PbwDescriptor* message_desc = NULL;
- const gchar* data_str = NULL;
- gchar *json_str, *p, *q;
+ const char* data_str = NULL;
+ char *json_str, *p;
/* initialize only the first time the protobuf dissector is called */
if (!protobuf_dissector_called) {
- protobuf_dissector_called = TRUE;
+ protobuf_dissector_called = true;
protobuf_reinit(PREFS_UPDATE_ALL);
}
@@ -1559,27 +1662,27 @@ dissect_protobuf(tvbuff_t *tvb, packet_info *pinfo, proto_tree *tree, void *data
parameter when calling protobuf dissector. But they can tell Protobuf dissector
the message type by the value of pinfo->private_table["pb_msg_type"]. */
if (data) {
- data_str = (const gchar*)data;
+ data_str = (const char*)data;
} else if (pinfo->private_table) {
- data_str = (const gchar*)g_hash_table_lookup(pinfo->private_table, "pb_msg_type");
+ data_str = (const char*)g_hash_table_lookup(pinfo->private_table, "pb_msg_type");
}
if (data_str) {
/* The data_str has two formats:
* (1) Come from GRPC dissector like:
* http2_content_type "," http2_path "," ("request" / "response")
- * Acording to grpc wire format guide, it will be:
+ * According to grpc wire format guide, it will be:
* "application/grpc" ["+proto"] "," "/" service-name "/" method-name "," ("request" / "response")
* For example:
* application/grpc,/helloworld.Greeter/SayHello,request
* In this format, we will try to get real protobuf message type by method (service-name.method-name)
- * and in/out type (request / reponse).
+ * and in/out type (request / response).
* (2) Come from other dissector which specifies message type directly, like:
* "message," message_type_name
* For example:
* message,helloworld.HelloRequest (helloworld is package, HelloRequest is message type)
*/
- const gchar* message_info = strchr(data_str, ',');
+ const char* message_info = strchr(data_str, ',');
if (message_info) {
message_info++; /* ignore ',' */
@@ -1594,9 +1697,9 @@ dissect_protobuf(tvbuff_t *tvb, packet_info *pinfo, proto_tree *tree, void *data
message_info++; /* ignore first '/' */
}
- gchar** tmp_names = wmem_strsplit(pinfo->pool, message_info, ",", 2);
- gchar* method_name = (tmp_names[0]) ? tmp_names[0] : NULL;
- gchar* direction_type = (method_name && tmp_names[1]) ? tmp_names[1] : NULL;
+ char** tmp_names = wmem_strsplit(pinfo->pool, message_info, ",", 2);
+ char* method_name = (tmp_names[0]) ? tmp_names[0] : NULL;
+ char* direction_type = (method_name && tmp_names[1]) ? tmp_names[1] : NULL;
/* replace all '/' to '.', so helloworld.Greeter/SayHello converted to helloworld.Greeter.SayHello */
if (method_name) {
@@ -1630,6 +1733,33 @@ dissect_protobuf(tvbuff_t *tvb, packet_info *pinfo, proto_tree *tree, void *data
message_desc = find_message_type_by_udp_port(pinfo);
}
+ if (!message_desc) {
+ /* If this was inside an HTTP request, do we have a message type assigned to this URI? */
+ http_req_res_t *curr = (http_req_res_t *)p_get_proto_data(wmem_file_scope(), pinfo,
+ proto_http, HTTP_PROTO_DATA_REQRES);
+ if (curr) {
+ if (curr->request_uri) {
+ for (unsigned n=0; n < num_protobuf_uri_message_types; n++) {
+ if (uri_matches_pattern(curr->request_uri, protobuf_uri_message_types[n].uri, 1 /* depth */)) {
+ if (strlen(protobuf_uri_message_types[n].message_type)) {
+ /* Lookup message type for matching URI */
+ message_desc = pbw_DescriptorPool_FindMessageTypeByName(pbw_pool,
+ protobuf_uri_message_types[n].message_type);
+ }
+ /* Found a matched URI, so stop looking */
+ break;
+ }
+ }
+ }
+ }
+ }
+
+ /* If *still* have no schema and a default is configured, try to use that */
+ if (!message_desc && strlen(default_message_type)) {
+ message_desc = pbw_DescriptorPool_FindMessageTypeByName(pbw_pool,
+ default_message_type);
+ }
+
if (display_json_mapping && message_desc) {
json_dumper dumper = {
.output_string = g_string_new(NULL),
@@ -1640,49 +1770,57 @@ dissect_protobuf(tvbuff_t *tvb, packet_info *pinfo, proto_tree *tree, void *data
* should be used to free the GString to avoid a leak.
*/
dissect_protobuf_message(tvb, offset, tvb_reported_length_remaining(tvb, offset), pinfo,
- protobuf_tree, message_desc, -1, pinfo->ptype == PT_UDP, &dumper, NULL, NULL);
+ protobuf_tree, message_desc,
+ -1, // no hf item
+ pinfo->ptype == PT_UDP, // is_top_level
+ &dumper,
+ NULL, // scope
+ NULL); // retval
DISSECTOR_ASSERT_HINT(json_dumper_finish(&dumper), "Bad json_dumper state");
ti = proto_tree_add_item(tree, proto_protobuf_json_mapping, tvb, 0, -1, ENC_NA);
protobuf_json_tree = proto_item_add_subtree(ti, ett_protobuf_json);
- json_str = g_string_free(dumper.output_string, FALSE);
+ json_str = g_string_free(dumper.output_string, false);
if (json_str != NULL) {
p = json_str;
- q = NULL;
/* add each line of json to the protobuf_json_tree */
do {
- q = strchr(p, '\n');
+ char *q = strchr(p, '\n');
if (q != NULL) {
*(q++) = '\0'; /* replace the '\n' to '\0' */
} /* else (q == NULL) means this is the last line of the JSON */
proto_tree_add_string_format(protobuf_json_tree, hf_json_mapping_line, tvb, 0, -1, p, "%s", p);
p = q;
- q = NULL;
} while (p);
g_free(json_str);
}
} else {
dissect_protobuf_message(tvb, offset, tvb_reported_length_remaining(tvb, offset), pinfo,
- protobuf_tree, message_desc, -1, pinfo->ptype == PT_UDP, NULL, NULL, NULL);
+ protobuf_tree, message_desc,
+ -1, // no hf item
+ true, // is_top_level
+ NULL, // dumper
+ NULL, // scope
+ NULL); // retval
}
return tvb_captured_length(tvb);
}
-static gboolean
+static bool
// NOLINTNEXTLINE(misc-no-recursion)
-load_all_files_in_dir(PbwDescriptorPool* pool, const gchar* dir_path, unsigned depth)
+load_all_files_in_dir(PbwDescriptorPool* pool, const char* dir_path, unsigned depth)
{
WS_DIR *dir; /* scanned directory */
WS_DIRENT *file; /* current file */
- const gchar *dot;
- const gchar *name; /* current file or dir name (without parent dir path) */
- gchar *path; /* sub file or dir path of dir_path */
+ const char *dot;
+ const char *name; /* current file or dir name (without parent dir path) */
+ char *path; /* sub file or dir path of dir_path */
if (depth > prefs.gui_max_tree_depth) {
- return FALSE;
+ return false;
}
if (g_file_test(dir_path, G_FILE_TEST_IS_DIR)) {
@@ -1697,13 +1835,13 @@ load_all_files_in_dir(PbwDescriptorPool* pool, const gchar* dir_path, unsigned d
if (pbw_load_proto_file(pool, path) != 0) {
g_free(path);
ws_dir_close(dir);
- return FALSE;
+ return false;
}
} else {
if (!load_all_files_in_dir(pool, path, depth + 1)) {
g_free(path);
ws_dir_close(dir);
- return FALSE;
+ return false;
}
}
g_free(path);
@@ -1711,17 +1849,17 @@ load_all_files_in_dir(PbwDescriptorPool* pool, const gchar* dir_path, unsigned d
ws_dir_close(dir);
}
}
- return TRUE;
+ return true;
}
/* There might be a lot of errors to be found during parsing .proto files.
We buffer the errors first, and print them in one list finally. */
-static wmem_strbuf_t* err_msg_buf = NULL;
+static wmem_strbuf_t* err_msg_buf;
#define MIN_ERR_STR_BUF_SIZE 512
#define MAX_ERR_STR_BUF_SIZE 1024
static void
-buffer_error(const gchar *fmt, ...)
+buffer_error(const char *fmt, ...)
{
va_list ap;
va_start(ap, fmt);
@@ -1759,11 +1897,18 @@ update_protobuf_udp_message_types(void)
}
static void
+update_protobuf_uri_message_types(void)
+{
+ protobuf_reinit(PREFS_UPDATE_PROTOBUF_URI_MESSAGE_TYPES);
+}
+
+
+static void
deregister_header_fields(void)
{
if (dynamic_hf) {
/* Deregister all fields */
- for (guint i = 0; i < dynamic_hf_size; i++) {
+ for (unsigned 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 */
@@ -1814,7 +1959,7 @@ collect_fields(const PbwDescriptor* message, void* userdata)
/* add message as field */
hf = g_new0(hf_register_info, 1);
- hf->p_id = g_new(gint, 1);
+ hf->p_id = g_new(int, 1);
*(hf->p_id) = -1;
hf->hfinfo.name = g_strdup(pbw_Descriptor_name(message));
hf->hfinfo.abbrev = ws_strdup_printf("pbm.%s", pbw_Descriptor_full_name(message));
@@ -1832,7 +1977,7 @@ collect_fields(const PbwDescriptor* message, void* userdata)
continue;
}
hf = g_new0(hf_register_info, 1);
- hf->p_id = g_new(gint, 1);
+ hf->p_id = g_new(int, 1);
*(hf->p_id) = -1;
hf->hfinfo.name = g_strdup(pbw_FieldDescriptor_name(field_desc));
@@ -1921,7 +2066,7 @@ collect_fields(const PbwDescriptor* message, void* userdata)
}
static void
-update_header_fields(gboolean force_reload)
+update_header_fields(bool force_reload)
{
if (!force_reload && pbf_as_hf && dynamic_hf) {
/* If initialized, do nothing. */
@@ -1959,12 +2104,12 @@ update_header_fields(gboolean force_reload)
static void
protobuf_reinit(int target)
{
- guint i;
+ unsigned i;
char **source_paths;
GSList* it;
range_t* udp_port_range;
- const gchar* message_type;
- gboolean loading_completed = TRUE;
+ const char* message_type;
+ bool loading_completed = true;
size_t num_proto_paths;
if (target & PREFS_UPDATE_PROTOBUF_UDP_MESSAGE_TYPES) {
@@ -2004,7 +2149,7 @@ protobuf_reinit(int target)
/* Load the files in the global and personal config dirs */
source_paths[0] = get_datafile_path("protobuf");
- source_paths[1] = get_persconffile_path("protobuf", TRUE);
+ source_paths[1] = get_persconffile_path("protobuf", true);
for (i = 0; i < num_protobuf_search_paths; ++i) {
source_paths[i + 2] = protobuf_search_paths[i].path;
@@ -2018,7 +2163,7 @@ protobuf_reinit(int target)
if ((i < 2) || protobuf_search_paths[i - 2].load_all) {
if (!load_all_files_in_dir(pbw_pool, source_paths[i], 0)) {
buffer_error("Protobuf: Loading .proto files action stopped!\n");
- loading_completed = FALSE;
+ loading_completed = false;
break; /* stop loading when error occurs */
}
}
@@ -2027,7 +2172,7 @@ protobuf_reinit(int target)
g_free(source_paths[0]);
g_free(source_paths[1]);
g_free(source_paths);
- update_header_fields(TRUE);
+ update_header_fields(true);
}
/* check if the message types of UDP port exist */
@@ -2064,7 +2209,7 @@ proto_register_protobuf(void)
},
{ &hf_protobuf_field_number,
{ "Field Number", "protobuf.field.number",
- FT_UINT64, BASE_DEC, NULL, G_GUINT64_CONSTANT(0xFFFFFFFFFFFFFFF8),
+ FT_UINT64, BASE_DEC, NULL, UINT64_C(0xFFFFFFFFFFFFFFF8),
"Field number encoded in varint", HFILL }
},
{ &hf_protobuf_wire_type,
@@ -2114,7 +2259,7 @@ proto_register_protobuf(void)
},
{ &hf_protobuf_value_bool,
{ "Bool", "protobuf.field.value.bool",
- FT_BOOLEAN, BASE_DEC, NULL, 0x0,
+ FT_BOOLEAN, BASE_NONE, NULL, 0x0,
"Dissect value as bool", HFILL }
},
{ &hf_protobuf_value_string,
@@ -2137,7 +2282,7 @@ proto_register_protobuf(void)
}
};
- static gint *ett[] = {
+ static int *ett[] = {
&ett_protobuf,
&ett_protobuf_message,
&ett_protobuf_field,
@@ -2145,7 +2290,7 @@ proto_register_protobuf(void)
&ett_protobuf_packed_repeated
};
- static gint *ett_json[] = {
+ static int *ett_json[] = {
&ett_protobuf_json
};
@@ -2167,23 +2312,23 @@ proto_register_protobuf(void)
{ "protobuf.field.failed_parse_field", PI_MALFORMED, PI_ERROR,
"Failed to parse value field", EXPFILL }
},
- { &et_protobuf_message_type_not_found,
+ { &ei_protobuf_message_type_not_found,
{ "protobuf.field.message_type_not_found", PI_PROTOCOL, PI_WARN,
"Failed to find message type of a field", EXPFILL }
},
- { &et_protobuf_wire_type_not_support_packed_repeated,
+ { &ei_protobuf_wire_type_not_support_packed_repeated,
{ "protobuf.field.wire_type_not_support_packed_repeated", PI_MALFORMED, PI_ERROR,
"The wire type does not support protobuf packed repeated field", EXPFILL }
},
- { &et_protobuf_failed_parse_packed_repeated_field,
+ { &ei_protobuf_failed_parse_packed_repeated_field,
{ "protobuf.field.failed_parse_packed_repeated_field", PI_MALFORMED, PI_ERROR,
"Failed to parse packed repeated field", EXPFILL }
},
- { &et_protobuf_missing_required_field,
+ { &ei_protobuf_missing_required_field,
{ "protobuf.message.missing_required_field", PI_PROTOCOL, PI_WARN,
"The required field is not found in message payload", EXPFILL }
},
- { &et_protobuf_default_value_error,
+ { &ei_protobuf_default_value_error,
{ "protobuf.message.default_value_error", PI_PROTOCOL, PI_WARN,
"Parsing default value of a field error", EXPFILL }
},
@@ -2208,6 +2353,14 @@ proto_register_protobuf(void)
};
uat_t* protobuf_udp_message_types_uat;
+ static uat_field_t protobuf_uri_message_types_table_columns[] = {
+ UAT_FLD_CSTRING(protobuf_uri_message_type, uri, "HTTP URI", "URI for HTTP request carrying protobuf contents"),
+ UAT_FLD_CSTRING(protobuf_uri_message_type, message_type, "Message Type", "Protobuf message type of data on these URIs"),
+ UAT_END_FIELDS
+ };
+ uat_t* protobuf_uri_message_types_uat;
+
+
proto_protobuf = proto_register_protocol("Protocol Buffers", "ProtoBuf", "protobuf");
proto_protobuf_json_mapping = proto_register_protocol("Protocol Buffers (as JSON Mapping View)", "ProtoBuf_JSON", "protobuf_json");
@@ -2228,7 +2381,7 @@ proto_register_protobuf(void)
protobuf_search_paths_uat = uat_new("Protobuf Search Paths",
sizeof(protobuf_search_path_t),
"protobuf_search_paths",
- TRUE,
+ true,
&protobuf_search_paths,
&num_protobuf_search_paths,
UAT_AFFECTS_DISSECTION | UAT_AFFECTS_FIELDS,
@@ -2277,12 +2430,12 @@ proto_register_protobuf(void)
" 4) Zero for numeric types.\n"
"There are no default values for fields 'repeated' or 'bytes' and 'string' without default value declared.\n"
"If the missing field is 'required' in a 'proto2' file, a warning item will be added to the tree.",
- &add_default_value, add_default_value_policy_vals, FALSE);
+ &add_default_value, add_default_value_policy_vals, false);
protobuf_udp_message_types_uat = uat_new("Protobuf UDP Message Types",
sizeof(protobuf_udp_message_type_t),
"protobuf_udp_message_types",
- TRUE,
+ true,
&protobuf_udp_message_types,
&num_protobuf_udp_message_types,
UAT_AFFECTS_DISSECTION | UAT_AFFECTS_FIELDS,
@@ -2299,6 +2452,28 @@ proto_register_protobuf(void)
"Specify the Protobuf message type of data on certain UDP ports.",
protobuf_udp_message_types_uat);
+
+ protobuf_uri_message_types_uat = uat_new("Protobuf URI Message Types",
+ sizeof(protobuf_uri_mapping_t),
+ "protobuf_uri_message_types",
+ true,
+ &protobuf_uri_message_types,
+ &num_protobuf_uri_message_types,
+ UAT_AFFECTS_DISSECTION | UAT_AFFECTS_FIELDS,
+ NULL, //"ChProtobufURIMessageTypes",
+ protobuf_uri_message_type_copy_cb,
+ NULL,
+ protobuf_uri_message_type_free_cb,
+ update_protobuf_uri_message_types,
+ NULL,
+ protobuf_uri_message_types_table_columns
+ );
+
+ prefs_register_uat_preference(protobuf_module, "uri_message_types", "Protobuf URI message types",
+ "Specify the Protobuf message type of data on certain URIs. N.B., URI may contain '*'",
+ protobuf_uri_message_types_uat);
+
+
prefs_register_bool_preference(protobuf_module, "display_json_mapping",
"Display JSON mapping for Protobuf message",
"Specifies that the JSON text of the "
@@ -2324,6 +2499,11 @@ 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_string_preference(protobuf_module, "default_type",
+ "Message type to use if none set",
+ "Can be useful e.g. if dissector called through media type",
+ &default_message_type);
+
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.",
@@ -2347,7 +2527,7 @@ proto_reg_handoff_protobuf(void)
(old_dissect_bytes_as_string && !dissect_bytes_as_string) || (!old_dissect_bytes_as_string && dissect_bytes_as_string)
);
} else if (preload_protos) {
- protobuf_dissector_called = TRUE;
+ protobuf_dissector_called = true;
protobuf_reinit(PREFS_UPDATE_ALL);
}
old_dissect_bytes_as_string = dissect_bytes_as_string;
@@ -2357,6 +2537,10 @@ proto_reg_handoff_protobuf(void)
dissector_add_string("grpc_message_type", "application/grpc-web+proto", protobuf_handle);
dissector_add_string("grpc_message_type", "application/grpc-web-text", protobuf_handle);
dissector_add_string("grpc_message_type", "application/grpc-web-text+proto", protobuf_handle);
+
+ dissector_add_string("media_type", "application/x-protobuf", protobuf_handle);
+
+ proto_http = proto_get_id_by_filter_name("http");
}
/*