1 /* packet-protobuf.c
2  * Routines for Google Protocol Buffers dissection
3  * Copyright 2017, Huang Qiangxiong <qiangxiong.huang@qq.com>
4  *
5  * Wireshark - Network traffic analyzer
6  * By Gerald Combs <gerald@wireshark.org>
7  * Copyright 1998 Gerald Combs
8  *
9  * SPDX-License-Identifier: GPL-2.0-or-later
10  */
11 
12 /*
13  * The information used comes from:
14  * https://developers.google.com/protocol-buffers/docs/encoding
15  *
16  * This protobuf dissector may be invoked by GRPC dissector or other dissectors.
17  * Other dissectors can give protobuf message type info by the data argument or private_table["pb_msg_type"]
18  * before call protobuf dissector.
19  * For GRPC dissector the data argument format is:
20  *    "application/grpc" ["+proto"] "," "/" service-name "/" method-name "," ("request" / "response")
21  * For example:
22  *    application/grpc,/helloworld.Greeter/SayHello,request
23  * In this format, we will try to get real protobuf message type by method (service-name.method-name)
24  * and in/out type (request / reponse).
25  * For other dissectors can specifies message type directly, like:
26  *    "message," message_type_name
27  * For example:
28  *    message,helloworld.HelloRequest      (helloworld is package, HelloRequest is message type)
29  */
30 
31 #include "config.h"
32 
33 #include <epan/packet.h>
34 #include <epan/expert.h>
35 #include <epan/prefs.h>
36 #include <epan/uat.h>
37 #include <epan/strutil.h>
38 #include <epan/proto_data.h>
39 #include <wsutil/filesystem.h>
40 #include <wsutil/file_util.h>
41 #include <wsutil/pint.h>
42 #include <epan/ws_printf.h>
43 #include <wsutil/report_message.h>
44 
45 #include "protobuf-helper.h"
46 #include "packet-protobuf.h"
47 
48 /* converting */
49 static inline gdouble
protobuf_uint64_to_double(guint64 value)50 protobuf_uint64_to_double(guint64 value) {
51     union { gdouble f; guint64 i; } double_uint64_union;
52 
53     double_uint64_union.i = value;
54     return double_uint64_union.f;
55 }
56 
57 static inline gfloat
protobuf_uint32_to_float(guint32 value)58 protobuf_uint32_to_float(guint32 value) {
59     union { gfloat f; guint32 i; } float_uint32_union;
60 
61     float_uint32_union.i = value;
62     return float_uint32_union.f;
63 }
64 
65 VALUE_STRING_ARRAY_GLOBAL_DEF(protobuf_wire_type);
66 
67 /* which field type of each wire type could be */
68 static int protobuf_wire_to_field_type[6][9] = {
69     /* PROTOBUF_WIRETYPE_VARINT, 0, "varint") */
70     { PROTOBUF_TYPE_INT32, PROTOBUF_TYPE_INT64, PROTOBUF_TYPE_UINT32, PROTOBUF_TYPE_UINT64,
71       PROTOBUF_TYPE_SINT32, PROTOBUF_TYPE_SINT64, PROTOBUF_TYPE_BOOL, PROTOBUF_TYPE_ENUM,
72       PROTOBUF_TYPE_NONE },
73 
74     /* PROTOBUF_WIRETYPE_FIXED64, 1, "64-bit")   */
75     { PROTOBUF_TYPE_FIXED64, PROTOBUF_TYPE_SFIXED64, PROTOBUF_TYPE_DOUBLE,
76       PROTOBUF_TYPE_NONE },
77 
78     /* PROTOBUF_WIRETYPE_LENGTH_DELIMITED, 2, "Length-delimited") */
79     { PROTOBUF_TYPE_STRING, PROTOBUF_TYPE_BYTES, PROTOBUF_TYPE_MESSAGE, PROTOBUF_TYPE_GROUP,
80       PROTOBUF_TYPE_NONE },
81 
82     /* PROTOBUF_WIRETYPE_START_GROUP, 3, "Start group (deprecated)") */
83     { PROTOBUF_TYPE_NONE },
84 
85     /* PROTOBUF_WIRETYPE_END_GROUP, 4, "End group (deprecated)") */
86     { PROTOBUF_TYPE_NONE },
87 
88     /* PROTOBUF_WIRETYPE_FIXED32, 5, "32-bit") */
89     { PROTOBUF_TYPE_FIXED32, PROTOBUF_TYPE_SINT32, PROTOBUF_TYPE_FLOAT,
90       PROTOBUF_TYPE_NONE }
91 };
92 
93 void proto_register_protobuf(void);
94 void proto_reg_handoff_protobuf(void);
95 
96 #define PREFS_UPDATE_PROTOBUF_SEARCH_PATHS            1
97 #define PREFS_UPDATE_PROTOBUF_UDP_MESSAGE_TYPES       2
98 #define PREFS_UPDATE_ALL   (PREFS_UPDATE_PROTOBUF_SEARCH_PATHS | PREFS_UPDATE_PROTOBUF_UDP_MESSAGE_TYPES)
99 
100 static void protobuf_reinit(int target);
101 
102 static int proto_protobuf = -1;
103 
104 static gboolean protobuf_dissector_called = FALSE;
105 
106 /* information get from *.proto files */
107 static int hf_protobuf_message_name = -1;
108 static int hf_protobuf_field_name = -1;
109 static int hf_protobuf_field_type = -1;
110 
111 /* field tag */
112 static int hf_protobuf_field_number = -1;
113 static int hf_protobuf_wire_type = -1;
114 
115 /* field value */
116 static int hf_protobuf_value_length = -1; /* only Length-delimited field has */
117 static int hf_protobuf_value_data = -1;
118 static int hf_protobuf_value_double = -1;
119 static int hf_protobuf_value_float = -1;
120 static int hf_protobuf_value_int64 = -1;
121 static int hf_protobuf_value_uint64 = -1;
122 static int hf_protobuf_value_int32 = -1;
123 static int hf_protobuf_value_uint32 = -1;
124 static int hf_protobuf_value_bool = -1;
125 static int hf_protobuf_value_string = -1;
126 static int hf_protobuf_value_repeated = -1;
127 
128 /* expert */
129 static expert_field ei_protobuf_failed_parse_tag = EI_INIT;
130 static expert_field ei_protobuf_failed_parse_length_delimited_field = EI_INIT;
131 static expert_field ei_protobuf_failed_parse_field = EI_INIT;
132 static expert_field ei_protobuf_wire_type_invalid = EI_INIT;
133 static expert_field et_protobuf_message_type_not_found = EI_INIT;
134 static expert_field et_protobuf_wire_type_not_support_packed_repeated = EI_INIT;
135 static expert_field et_protobuf_failed_parse_packed_repeated_field = EI_INIT;
136 static expert_field et_protobuf_missing_required_field = EI_INIT;
137 static expert_field et_protobuf_default_value_error = EI_INIT;
138 
139 /* trees */
140 static int ett_protobuf = -1;
141 static int ett_protobuf_message = -1;
142 static int ett_protobuf_field = -1;
143 static int ett_protobuf_value = -1;
144 static int ett_protobuf_packed_repeated = -1;
145 
146 /* preferences */
147 static gboolean try_dissect_as_string = FALSE;
148 static gboolean show_all_possible_field_types = FALSE;
149 static gboolean dissect_bytes_as_string = FALSE;
150 static gboolean old_dissect_bytes_as_string = FALSE;
151 static gboolean show_details = FALSE;
152 static gboolean pbf_as_hf = FALSE; /* dissect protobuf fields as header fields of wireshark */
153 static gboolean preload_protos = FALSE;
154 
155 enum add_default_value_policy_t {
156     ADD_DEFAULT_VALUE_NONE,
157     ADD_DEFAULT_VALUE_DECLARED,
158     ADD_DEFAULT_VALUE_ENUM_BOOL,
159     ADD_DEFAULT_VALUE_ALL,
160 };
161 
162 static gint add_default_value = (gint) ADD_DEFAULT_VALUE_NONE;
163 
164 /* dynamic wireshark header fields for protobuf fields */
165 static hf_register_info *dynamic_hf = NULL;
166 static guint dynamic_hf_size = 0;
167 /* the key is full name of protobuf fields, the value is header field id */
168 static GHashTable *pbf_hf_hash = NULL;
169 
170 /* Protobuf field value subdissector table list.
171  * Only valid for the value of PROTOBUF_TYPE_BYTES or PROTOBUF_TYPE_STRING fields.
172  */
173 static dissector_table_t protobuf_field_subdissector_table;
174 
175 static dissector_handle_t protobuf_handle;
176 
177 /* store varint tvb info */
178 typedef struct {
179     guint offset;
180     guint length;
181     guint64 value;
182 } protobuf_varint_tvb_info_t;
183 
184 static PbwDescriptorPool* pbw_pool = NULL;
185 
186 /* protobuf source files search paths */
187 typedef struct {
188     char* path; /* protobuf source files searching directory path */
189     gboolean load_all; /* load all *.proto files in this directory and its sub directories */
190 } protobuf_search_path_t;
191 
192 static protobuf_search_path_t* protobuf_search_paths = NULL;
193 static guint num_protobuf_search_paths = 0;
194 
195 static void *
protobuf_search_paths_copy_cb(void * n,const void * o,size_t siz _U_)196 protobuf_search_paths_copy_cb(void* n, const void* o, size_t siz _U_)
197 {
198     protobuf_search_path_t* new_rec = (protobuf_search_path_t*)n;
199     const protobuf_search_path_t* old_rec = (const protobuf_search_path_t*)o;
200 
201     /* copy interval values like gint */
202     memcpy(new_rec, old_rec, sizeof(protobuf_search_path_t));
203 
204     if (old_rec->path)
205         new_rec->path = g_strdup(old_rec->path);
206 
207     return new_rec;
208 }
209 
210 static void
protobuf_search_paths_free_cb(void * r)211 protobuf_search_paths_free_cb(void*r)
212 {
213     protobuf_search_path_t* rec = (protobuf_search_path_t*)r;
214 
215     g_free(rec->path);
216 }
217 
218 UAT_DIRECTORYNAME_CB_DEF(protobuf_search_paths, path, protobuf_search_path_t)
219 UAT_BOOL_CB_DEF(protobuf_search_paths, load_all, protobuf_search_path_t)
220 
221 /* the protobuf message type of the data on certain udp ports */
222 typedef struct {
223     range_t  *udp_port_range; /* dissect data on these udp ports as protobuf */
224     gchar    *message_type; /* protobuf message type of data on these udp ports */
225 } protobuf_udp_message_type_t;
226 
227 static protobuf_udp_message_type_t* protobuf_udp_message_types = NULL;
228 static guint num_protobuf_udp_message_types = 0;
229 
230 static void *
protobuf_udp_message_types_copy_cb(void * n,const void * o,size_t siz _U_)231 protobuf_udp_message_types_copy_cb(void* n, const void* o, size_t siz _U_)
232 {
233     protobuf_udp_message_type_t* new_rec = (protobuf_udp_message_type_t*)n;
234     const protobuf_udp_message_type_t* old_rec = (const protobuf_udp_message_type_t*)o;
235 
236     /* copy interval values like gint */
237     memcpy(new_rec, old_rec, sizeof(protobuf_udp_message_type_t));
238 
239     if (old_rec->udp_port_range)
240         new_rec->udp_port_range = range_copy(NULL, old_rec->udp_port_range);
241     if (old_rec->message_type)
242         new_rec->message_type = g_strdup(old_rec->message_type);
243 
244     return new_rec;
245 }
246 
247 static gboolean
protobuf_udp_message_types_update_cb(void * r,char ** err)248 protobuf_udp_message_types_update_cb(void *r, char **err)
249 {
250     protobuf_udp_message_type_t* rec = (protobuf_udp_message_type_t*)r;
251     static range_t *empty;
252 
253     empty = range_empty(NULL);
254     if (ranges_are_equal(rec->udp_port_range, empty)) {
255         *err = g_strdup("Must specify UDP port(s) (like 8000 or 8000,8008-8088)");
256         wmem_free(NULL, empty);
257         return FALSE;
258     }
259 
260     wmem_free(NULL, empty);
261     return TRUE;
262 }
263 
264 static void
protobuf_udp_message_types_free_cb(void * r)265 protobuf_udp_message_types_free_cb(void*r)
266 {
267     protobuf_udp_message_type_t* rec = (protobuf_udp_message_type_t*)r;
268 
269     wmem_free(NULL, rec->udp_port_range);
270     g_free(rec->message_type);
271 }
272 
273 UAT_RANGE_CB_DEF(protobuf_udp_message_types, udp_port_range, protobuf_udp_message_type_t)
274 UAT_CSTRING_CB_DEF(protobuf_udp_message_types, message_type, protobuf_udp_message_type_t)
275 
276 static GSList* old_udp_port_ranges = NULL;
277 
278 /* If you use int32 or int64 as the type for a negative number, the resulting varint is always
279  * ten bytes long - it is, effectively, treated like a very large unsigned integer. If you use
280  * one of the signed types, the resulting varint uses ZigZag encoding, which is much more efficient.
281  * ZigZag encoding maps signed integers to unsigned integers so that numbers with a small absolute
282  * value (for instance, -1) have a small varint encoded value too. (refers to protobuf spec)
283  *      sint32 encoded using   (n << 1) ^ (n >> 31)
284  */
285 static gint32
sint32_decode(guint32 sint32)286 sint32_decode(guint32 sint32) {
287     return (sint32 >> 1) ^ ((gint32)sint32 << 31 >> 31);
288 }
289 
290 /* sint64 encoded using   (n << 1) ^ (n >> 63) */
291 static gint64
sint64_decode(guint64 sint64)292 sint64_decode(guint64 sint64) {
293     return (sint64 >> 1) ^ ((gint64)sint64 << 63 >> 63);
294 }
295 
296 /* Try to get a protobuf field which has a varint value from the tvb.
297  * The field number, wire type and uint64 value will be output.
298  * @return the length of this field. Zero if failed.
299  */
300 static guint
tvb_get_protobuf_field_uint(tvbuff_t * tvb,guint offset,guint maxlen,guint64 * field_number,guint32 * wire_type,guint64 * value)301 tvb_get_protobuf_field_uint(tvbuff_t* tvb, guint offset, guint maxlen,
302     guint64* field_number, guint32* wire_type, guint64* value)
303 {
304     guint tag_length, value_length;
305     guint64 tag_value;
306 
307     /* parsing the tag of the field */
308     tag_length = tvb_get_varint(tvb, offset, maxlen, &tag_value, ENC_VARINT_PROTOBUF);
309     if (tag_length == 0 || tag_length >= maxlen) {
310         return 0;
311     }
312     *field_number = tag_value >> 3;
313     *wire_type = tag_value & 0x07;
314 
315     if (*wire_type != PROTOBUF_WIRETYPE_VARINT) {
316         return 0;
317     }
318     /* parsing the value of the field */
319     value_length = tvb_get_varint(tvb, offset + tag_length, maxlen - tag_length, value, ENC_VARINT_PROTOBUF);
320     return (value_length == 0) ? 0 : (tag_length + value_length);
321 }
322 
323 /* Get Protobuf timestamp from the tvb according to the format of google.protobuf.Timestamp.
324  * return the length parsed.
325  */
326 static guint
tvb_get_protobuf_time(tvbuff_t * tvb,guint offset,guint maxlen,nstime_t * timestamp)327 tvb_get_protobuf_time(tvbuff_t* tvb, guint offset, guint maxlen, nstime_t* timestamp)
328 {
329     guint field_length;
330     guint64 field_number, value;
331     guint32 wire_type;
332     guint off = offset;
333     guint len = maxlen; /* remain bytes */
334 
335     /* Get the seconds and nanos fields from google.protobuf.Timestamp message which defined:
336      *
337      * message Timestamp {
338      *    int64 seconds = 1;
339      *    int32 nanos = 2;
340      * }
341      */
342     timestamp->secs = 0;
343     timestamp->nsecs = 0;
344 
345     while (len > 0) {
346         field_length = tvb_get_protobuf_field_uint(tvb, off, len, &field_number, &wire_type, &value);
347         if (field_length == 0) {
348             break;
349         }
350 
351         if (field_number == 1) {
352             timestamp->secs = (gint64)value;
353         } else if (field_number == 2) {
354             timestamp->nsecs = (gint32)value;
355         }
356 
357         off += field_length;
358         len -= field_length;
359     }
360 
361     return maxlen - len;
362 }
363 
364 
365 /* declare first because it will be called by dissect_packed_repeated_field_values */
366 static void
367 protobuf_dissect_field_value(proto_tree *value_tree, tvbuff_t *tvb, guint offset, guint length, packet_info *pinfo,
368     proto_item *ti_field, int field_type, const guint64 value, const gchar* prepend_text, const PbwFieldDescriptor* field_desc, gboolean is_top_level);
369 
370 static void
371 dissect_protobuf_message(tvbuff_t *tvb, guint offset, guint length, packet_info *pinfo, proto_tree *protobuf_tree, const PbwDescriptor* message_desc, gboolean is_top_level);
372 
373 /* Only repeated fields of primitive numeric types (types which use the varint, 32-bit, or 64-bit wire types) can
374  * be declared "packed".
375  * The format of a packed_repeated field likes: tag + varint + varint + varint ...
376  * or likes: tag + fixed64 + fixed64 + fixed64 ...
377  * Return consumed bytes
378  */
379 static guint
dissect_packed_repeated_field_values(tvbuff_t * tvb,guint start,guint length,packet_info * pinfo,proto_item * ti_field,int wire_type,int field_type,const gchar * prepend_text,const PbwFieldDescriptor * field_desc)380 dissect_packed_repeated_field_values(tvbuff_t *tvb, guint start, guint length, packet_info *pinfo,
381     proto_item *ti_field, int wire_type, int field_type, const gchar* prepend_text, const PbwFieldDescriptor* field_desc)
382 {
383     guint64 sub_value;
384     guint sub_value_length;
385     guint offset = start;
386     protobuf_varint_tvb_info_t *info;
387     guint max_offset = offset + length;
388     wmem_list_frame_t *lframe;
389     wmem_list_t* varint_list;
390     int value_size = 0;
391 
392     if (prepend_text == NULL) {
393         prepend_text = "";
394     }
395 
396     /* prepare subtree */
397     proto_item_append_text(ti_field, "%s [", prepend_text);
398     proto_item *ti = proto_tree_add_item(proto_item_get_subtree(ti_field), hf_protobuf_value_repeated, tvb, start, length, ENC_NA);
399     proto_tree *subtree = proto_item_add_subtree(ti, ett_protobuf_packed_repeated);
400 
401     prepend_text = "";
402 
403     switch (field_type)
404     {
405     /* packed for Varint encoded types (int32, int64, uint32, uint64, sint32, sint64, bool, enum) */
406     /* format: tag + varint + varint + varint ... */
407     case PROTOBUF_TYPE_INT32:
408     case PROTOBUF_TYPE_INT64:
409     case PROTOBUF_TYPE_UINT32:
410     case PROTOBUF_TYPE_UINT64:
411     case PROTOBUF_TYPE_SINT32:
412     case PROTOBUF_TYPE_SINT64:
413     case PROTOBUF_TYPE_BOOL:
414     case PROTOBUF_TYPE_ENUM:
415         varint_list = wmem_list_new(pinfo->pool);
416 
417         /* try to test all can parsed as varint */
418         while (offset < max_offset) {
419             sub_value_length = tvb_get_varint(tvb, offset, max_offset - offset, &sub_value, ENC_VARINT_PROTOBUF);
420             if (sub_value_length == 0) {
421                 /* not a valid packed repeated field */
422                 wmem_destroy_list(varint_list);
423                 return 0;
424             }
425 
426             /* temporarily store varint info in the list */
427             info = wmem_new(pinfo->pool, protobuf_varint_tvb_info_t);
428             info->offset = offset;
429             info->length = sub_value_length;
430             info->value = sub_value;
431             wmem_list_append(varint_list, info);
432 
433             offset += sub_value_length;
434         }
435 
436         /* all parsed, we add varints into the packed-repeated subtree */
437         for (lframe = wmem_list_head(varint_list); lframe != NULL; lframe = wmem_list_frame_next(lframe)) {
438             info = (protobuf_varint_tvb_info_t*)wmem_list_frame_data(lframe);
439             protobuf_dissect_field_value(subtree, tvb, info->offset, info->length, pinfo,
440                 ti_field, field_type, info->value, prepend_text, field_desc,  FALSE);
441             prepend_text = ",";
442         }
443 
444         wmem_destroy_list(varint_list);
445         break;
446 
447     /* packed for 64-bit encoded types (fixed64, sfixed64, double) and 32-bit encoded types (fixed32, sfixed32, float) */
448     /* format like: tag + sint32 + sint32 + sint32 ... */
449     case PROTOBUF_TYPE_FIXED64:
450     case PROTOBUF_TYPE_SFIXED64:
451     case PROTOBUF_TYPE_DOUBLE:
452         value_size = 8; /* 64-bit */
453         /* FALLTHROUGH */
454     case PROTOBUF_TYPE_FIXED32:
455     case PROTOBUF_TYPE_SFIXED32:
456     case PROTOBUF_TYPE_FLOAT:
457         if (value_size == 0) {
458             value_size = 4; /* 32-bit */
459         }
460 
461         if (length % value_size != 0) {
462             expert_add_info(pinfo, ti_field, &et_protobuf_failed_parse_packed_repeated_field);
463             return 0;
464         }
465 
466         for (offset = start; offset < max_offset; offset += value_size) {
467             protobuf_dissect_field_value(subtree, tvb, offset, value_size, pinfo, ti_field, field_type,
468                 (wire_type == PROTOBUF_WIRETYPE_FIXED32 ? tvb_get_guint32(tvb, offset, ENC_LITTLE_ENDIAN)
469                     : tvb_get_guint64(tvb, offset, ENC_LITTLE_ENDIAN)),
470                 prepend_text, field_desc, FALSE);
471             prepend_text = ",";
472         }
473 
474         break;
475 
476     default:
477         expert_add_info(pinfo, ti_field, &et_protobuf_wire_type_not_support_packed_repeated);
478         return 0; /* prevent dead loop */
479     }
480 
481     proto_item_append_text(ti_field, "]");
482     return length;
483 }
484 
485 /* Dissect field value based on a specific type. */
486 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)487 protobuf_dissect_field_value(proto_tree *value_tree, tvbuff_t *tvb, guint offset, guint length, packet_info *pinfo,
488     proto_item *ti_field, int field_type, const guint64 value, const gchar* prepend_text, const PbwFieldDescriptor* field_desc, gboolean is_top_level)
489 {
490     gdouble double_value;
491     gfloat float_value;
492     gint64 int64_value;
493     gint32 int32_value;
494     char* buf;
495     gboolean add_datatype = TRUE;
496     proto_item* ti = NULL;
497     proto_tree* subtree = NULL;
498     const char* enum_value_name = NULL;
499     const PbwDescriptor* sub_message_desc = NULL;
500     const PbwEnumDescriptor* enum_desc = NULL;
501     int* hf_id_ptr = NULL;
502     const gchar* field_full_name = field_desc ? pbw_FieldDescriptor_full_name(field_desc) : NULL;
503     proto_tree* field_tree = proto_item_get_subtree(ti_field);
504     proto_tree* field_parent_tree = proto_tree_get_parent_tree(field_tree);
505     proto_tree* pbf_tree = field_tree;
506     nstime_t timestamp = { 0 };
507     dissector_handle_t field_dissector = field_full_name ? dissector_get_string_handle(protobuf_field_subdissector_table, field_full_name) : NULL;
508 
509     if (pbf_as_hf && field_full_name) {
510         hf_id_ptr = (int*)g_hash_table_lookup(pbf_hf_hash, field_full_name);
511         DISSECTOR_ASSERT_HINT(hf_id_ptr && (*hf_id_ptr) > 0, "hf must have been initialized properly");
512     }
513 
514     if (pbf_as_hf && hf_id_ptr && !show_details) {
515         /* set ti_field (Field(x)) item hidden if there is header_field */
516         proto_item_set_hidden(ti_field);
517         pbf_tree = field_parent_tree;
518     }
519 
520     if (prepend_text == NULL) {
521         prepend_text = "";
522     }
523 
524     switch (field_type)
525     {
526     case PROTOBUF_TYPE_DOUBLE:
527         double_value = protobuf_uint64_to_double(value);
528         proto_tree_add_double(value_tree, hf_protobuf_value_double, tvb, offset, length, double_value);
529         proto_item_append_text(ti_field, "%s %lf", prepend_text, double_value);
530         if (is_top_level) {
531             col_append_fstr(pinfo->cinfo, COL_INFO, "=%lf", double_value);
532         }
533         if (hf_id_ptr) {
534             proto_tree_add_double(pbf_tree, *hf_id_ptr, tvb, offset, length, double_value);
535         }
536         break;
537 
538     case PROTOBUF_TYPE_FLOAT:
539         float_value = protobuf_uint32_to_float((guint32) value);
540         proto_tree_add_float(value_tree, hf_protobuf_value_float, tvb, offset, length, float_value);
541         proto_item_append_text(ti_field, "%s %f", prepend_text, float_value);
542         if (is_top_level) {
543             col_append_fstr(pinfo->cinfo, COL_INFO, "=%f", float_value);
544         }
545         if (hf_id_ptr) {
546             proto_tree_add_float(pbf_tree, *hf_id_ptr, tvb, offset, length, float_value);
547         }
548         break;
549 
550     case PROTOBUF_TYPE_INT64:
551     case PROTOBUF_TYPE_SFIXED64:
552         int64_value = (gint64) value;
553         proto_tree_add_int64(value_tree, hf_protobuf_value_int64, tvb, offset, length, int64_value);
554         proto_item_append_text(ti_field, "%s %" G_GINT64_MODIFIER "d", prepend_text, int64_value);
555         if (is_top_level) {
556             col_append_fstr(pinfo->cinfo, COL_INFO, "=%" G_GINT64_MODIFIER "d", int64_value);
557         }
558         if (hf_id_ptr) {
559             proto_tree_add_int64(pbf_tree, *hf_id_ptr, tvb, offset, length, int64_value);
560         }
561         break;
562 
563     case PROTOBUF_TYPE_UINT64:
564     case PROTOBUF_TYPE_FIXED64: /* same as UINT64 */
565         proto_tree_add_uint64(value_tree, hf_protobuf_value_uint64, tvb, offset, length, value);
566         proto_item_append_text(ti_field, "%s %" G_GINT64_MODIFIER "u", prepend_text, value);
567         if (is_top_level) {
568             col_append_fstr(pinfo->cinfo, COL_INFO, "=%" G_GINT64_MODIFIER "u", value);
569         }
570         if (hf_id_ptr) {
571             proto_tree_add_uint64(pbf_tree, *hf_id_ptr, tvb, offset, length, value);
572         }
573         break;
574 
575     case PROTOBUF_TYPE_INT32:
576     case PROTOBUF_TYPE_SFIXED32:
577         int32_value = (gint32)value;
578         proto_tree_add_int(value_tree, hf_protobuf_value_int32, tvb, offset, length, int32_value);
579         proto_item_append_text(ti_field, "%s %d", prepend_text, int32_value);
580         if (is_top_level) {
581             col_append_fstr(pinfo->cinfo, COL_INFO, "=%d", int32_value);
582         }
583         if (hf_id_ptr) {
584             proto_tree_add_int(pbf_tree, *hf_id_ptr, tvb, offset, length, int32_value);
585         }
586         break;
587 
588     case PROTOBUF_TYPE_ENUM:
589         int32_value = (gint32) value;
590         /* get the name of enum value */
591         if (field_desc) {
592             enum_desc = pbw_FieldDescriptor_enum_type(field_desc);
593             if (enum_desc) {
594                 const PbwEnumValueDescriptor* enum_value_desc = pbw_EnumDescriptor_FindValueByNumber(enum_desc, int32_value);
595                 if (enum_value_desc) {
596                     enum_value_name = pbw_EnumValueDescriptor_name(enum_value_desc);
597                 }
598             }
599         }
600         ti = proto_tree_add_int(value_tree, hf_protobuf_value_int32, tvb, offset, length, int32_value);
601         if (enum_value_name) { /* show enum value name */
602             proto_item_append_text(ti_field, "%s %s(%d)", prepend_text, enum_value_name, int32_value);
603             proto_item_append_text(ti, " (%s)", enum_value_name);
604             if (is_top_level) {
605                 col_append_fstr(pinfo->cinfo, COL_INFO, "=%s", enum_value_name);
606             }
607         } else {
608             proto_item_append_text(ti_field, "%s %d", prepend_text, int32_value);
609             if (is_top_level) {
610                 col_append_fstr(pinfo->cinfo, COL_INFO, "=%d", int32_value);
611             }
612 
613         }
614         if (hf_id_ptr) {
615             proto_tree_add_int(pbf_tree, *hf_id_ptr, tvb, offset, length, int32_value);
616         }
617         break;
618 
619     case PROTOBUF_TYPE_BOOL:
620         if (length > 1) break; /* boolean should not use more than one bytes */
621         proto_tree_add_boolean(value_tree, hf_protobuf_value_bool, tvb, offset, length, (guint32)value);
622         proto_item_append_text(ti_field, "%s %s", prepend_text, value ? "true" : "false");
623         if (is_top_level) {
624             col_append_fstr(pinfo->cinfo, COL_INFO, "=%s", value ? "true" : "false");
625         }
626         if (hf_id_ptr) {
627             proto_tree_add_boolean(pbf_tree, *hf_id_ptr, tvb, offset, length, (guint32)value);
628         }
629         break;
630 
631     case PROTOBUF_TYPE_BYTES:
632         if (field_dissector) {
633             if (!show_details) { /* don't show Value node if there is a subdissector for this field */
634                 proto_item_set_hidden(proto_tree_get_parent(value_tree));
635             }
636             if (dissect_bytes_as_string) { /* the type of *hf_id_ptr MUST be FT_STRING now */
637                 if (hf_id_ptr) {
638                     ti = proto_tree_add_string_format_value(pbf_tree, *hf_id_ptr, tvb, offset, length, "", "(%u bytes)", length);
639                 }
640                 /* don't try to dissect bytes as string if there is a subdissector for this field */
641                 break;
642             }
643         }
644         if (!dissect_bytes_as_string) {
645             /* the type of *hf_id_ptr MUST be FT_BYTES now */
646             if (hf_id_ptr) {
647                 ti = proto_tree_add_bytes_format_value(pbf_tree, *hf_id_ptr, tvb, offset, length, NULL, "(%u bytes)", length);
648             }
649             break;
650         }
651         /* or continue dissect BYTES as STRING */
652         proto_item_append_text(ti_field, " =");
653         /* FALLTHROUGH */
654     case PROTOBUF_TYPE_STRING:
655         proto_tree_add_item_ret_display_string(value_tree, hf_protobuf_value_string, tvb, offset, length, ENC_UTF_8|ENC_NA, pinfo->pool, &buf);
656         proto_item_append_text(ti_field, "%s %s", prepend_text, buf);
657         if (is_top_level) {
658             col_append_fstr(pinfo->cinfo, COL_INFO, "=%s", buf);
659         }
660         if (hf_id_ptr) {
661             ti = proto_tree_add_item_ret_display_string(pbf_tree, *hf_id_ptr, tvb, offset, length, ENC_UTF_8|ENC_NA, pinfo->pool, &buf);
662         }
663         break;
664 
665     case PROTOBUF_TYPE_GROUP: /* This feature is deprecated. GROUP is identical to Nested MESSAGE. */
666     case PROTOBUF_TYPE_MESSAGE:
667         subtree = field_tree;
668         if (field_desc) {
669             sub_message_desc = pbw_FieldDescriptor_message_type(field_desc);
670             if (sub_message_desc == NULL) {
671                 expert_add_info(pinfo, ti_field, &et_protobuf_message_type_not_found);
672             }
673         }
674         if (hf_id_ptr) {
675             if (sub_message_desc
676                 && strcmp(pbw_Descriptor_full_name(sub_message_desc), "google.protobuf.Timestamp") == 0)
677             {   /* parse this field directly as timestamp */
678                 if (tvb_get_protobuf_time(tvb, offset, length, &timestamp)) {
679                     ti = proto_tree_add_time(pbf_tree, *hf_id_ptr, tvb, offset, length, &timestamp);
680                     subtree = proto_item_add_subtree(ti, ett_protobuf_message);
681                 } else {
682                     expert_add_info(pinfo, ti_field, &ei_protobuf_failed_parse_field);
683                 }
684             } else {
685                 ti = proto_tree_add_bytes_format_value(pbf_tree, *hf_id_ptr, tvb, offset, length, NULL, "(%u bytes)", length);
686                 subtree = proto_item_add_subtree(ti, ett_protobuf_message);
687             }
688         }
689         if (sub_message_desc) {
690             dissect_protobuf_message(tvb, offset, length, pinfo, subtree, sub_message_desc, FALSE);
691         }
692         break;
693 
694     case PROTOBUF_TYPE_UINT32:
695     case PROTOBUF_TYPE_FIXED32: /* same as UINT32 */
696         proto_tree_add_uint(value_tree, hf_protobuf_value_uint32, tvb, offset, length, (guint32)value);
697         proto_item_append_text(ti_field, "%s %u", prepend_text, (guint32)value);
698         if (is_top_level) {
699             col_append_fstr(pinfo->cinfo, COL_INFO, "=%u", (guint32)value);
700         }
701         if (hf_id_ptr) {
702             proto_tree_add_uint(pbf_tree, *hf_id_ptr, tvb, offset, length, (guint32)value);
703         }
704         break;
705 
706     case PROTOBUF_TYPE_SINT32:
707         int32_value = sint32_decode((guint32)value);
708         proto_tree_add_int(value_tree, hf_protobuf_value_int32, tvb, offset, length, int32_value);
709         proto_item_append_text(ti_field, "%s %d", prepend_text, int32_value);
710         if (is_top_level) {
711             col_append_fstr(pinfo->cinfo, COL_INFO, "=%d", int32_value);
712         }
713         if (hf_id_ptr) {
714             proto_tree_add_int(pbf_tree, *hf_id_ptr, tvb, offset, length, int32_value);
715         }
716         break;
717 
718     case PROTOBUF_TYPE_SINT64:
719         int64_value = sint64_decode(value);
720         proto_tree_add_int64(value_tree, hf_protobuf_value_int64, tvb, offset, length, int64_value);
721         proto_item_append_text(ti_field, "%s %" G_GINT64_MODIFIER "d", prepend_text, int64_value);
722         if (is_top_level) {
723             col_append_fstr(pinfo->cinfo, COL_INFO, "=%" G_GINT64_MODIFIER "d", int64_value);
724         }
725         if (hf_id_ptr) {
726             proto_tree_add_int64(pbf_tree, *hf_id_ptr, tvb, offset, length, int64_value);
727         }
728         break;
729 
730     default:
731         /* ignore unknown field type */
732         add_datatype = FALSE;
733         break;
734     }
735 
736     /* try dissect field value according to protobuf_field dissector table */
737     if (field_dissector) {
738         /* determine the tree passing to the subdissector */
739         subtree = field_tree;
740         if (ti) {
741             subtree = proto_item_get_subtree(ti);
742             if (!subtree) {
743                 subtree = proto_item_add_subtree(ti, ett_protobuf_value);
744             }
745         }
746 
747         call_dissector(field_dissector, tvb_new_subset_length(tvb, offset, length), pinfo, subtree);
748     }
749 
750     if (add_datatype)
751         proto_item_append_text(ti_field, " (%s)", val_to_str(field_type, protobuf_field_type, "Unknown type (%d)"));
752 
753 }
754 
755 /* add all possible values according to field types. */
756 static void
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)757 protobuf_try_dissect_field_value_on_multi_types(proto_tree *value_tree, tvbuff_t *tvb, guint offset, guint length,
758     packet_info *pinfo, proto_item *ti_field, int* field_types, const guint64 value, const gchar* prepend_text)
759 {
760     int i;
761 
762     if (prepend_text == NULL) {
763         prepend_text = "";
764     }
765 
766     for (i = 0; field_types[i] != PROTOBUF_TYPE_NONE; ++i) {
767         protobuf_dissect_field_value(value_tree, tvb, offset, length, pinfo, ti_field, field_types[i], value, prepend_text, NULL, FALSE);
768         prepend_text = ",";
769     }
770 }
771 
772 static guint
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)773 dissect_one_protobuf_field(tvbuff_t *tvb, guint* offset, guint maxlen, packet_info *pinfo, proto_tree *protobuf_tree,
774     const PbwDescriptor* message_desc, gboolean is_top_level, const PbwFieldDescriptor** field_desc_ptr)
775 {
776     guint64 tag_value; /* tag value = (field_number << 3) | wire_type */
777     guint tag_length; /* how many bytes this tag has */
778     guint64 field_number;
779     guint32 wire_type;
780     guint64 value_uint64; /* uint64 value of numeric field (type of varint, 64-bit, 32-bit */
781     guint value_length;
782     guint value_length_size = 0; /* only Length-delimited field has it */
783     proto_item *ti_field, *ti_field_number, *ti_wire, *ti_value_length = NULL;
784     proto_item *ti_value, *ti_field_name, *ti_field_type = NULL;
785     proto_tree *field_tree;
786     proto_tree *value_tree;
787     const gchar* field_name = NULL;
788     int field_type = -1;
789     gboolean is_packed_repeated = FALSE;
790     const PbwFieldDescriptor* field_desc = NULL;
791 
792     /* A protocol buffer message is a series of key-value pairs. The binary version of a message just uses
793      * the field's number as the key. a wire type that provides just enough information to find the length of
794      * the following value.
795      * Format of protobuf is:
796      *       protobuf field -> tag value
797      *       tag -> (field_number << 3) | wire_type  (the last three bits of the number store the wire type)
798      *       value -> according to wiret_type, value may be
799      *                 - varint (int32, int64, uint32, uint64, sint32, sint64, bool, enum),
800      *                 - 64-bit number (fixed64, sfixed64, double)
801      *                 - Length-delimited (string, bytes, embedded messages, packed repeated fields)
802      *                 - deprecated 'Start group' or 'End group' (we stop dissecting when encountered them)
803      *                 - 32-bit (fixed32, sfixed32, float)
804      * All numbers in protobuf are stored in little-endian byte order.
805      */
806 
807     field_tree = proto_tree_add_subtree(protobuf_tree, tvb, *offset, 0, ett_protobuf_field, &ti_field, "Field");
808 
809     /* parsing Tag */
810     tag_length = tvb_get_varint(tvb, *offset, maxlen, &tag_value, ENC_VARINT_PROTOBUF);
811 
812     if (tag_length == 0) { /* not found a valid varint */
813         expert_add_info(pinfo, ti_field, &ei_protobuf_failed_parse_tag);
814         return FALSE;
815     }
816 
817     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);
818     ti_wire = proto_tree_add_item_ret_uint(field_tree, hf_protobuf_wire_type, tvb, *offset, 1, ENC_LITTLE_ENDIAN|ENC_VARINT_PROTOBUF, &wire_type);
819     (*offset) += tag_length;
820 
821     /* try to find field_info first */
822     if (message_desc) {
823         /* find field descriptor according to field number from message descriptor */
824         field_desc = pbw_Descriptor_FindFieldByNumber(message_desc, (int) field_number);
825         if (field_desc) {
826             *field_desc_ptr = field_desc;
827             field_name = pbw_FieldDescriptor_name(field_desc);
828             field_type = pbw_FieldDescriptor_type(field_desc);
829             is_packed_repeated = pbw_FieldDescriptor_is_packed(field_desc)
830                 && pbw_FieldDescriptor_is_repeated(field_desc);
831         }
832     }
833 
834     proto_item_append_text(ti_field, "(%" G_GINT64_MODIFIER "u):", field_number);
835 
836     /* support filtering with field name */
837     ti_field_name = proto_tree_add_string(field_tree, hf_protobuf_field_name, tvb, *offset, 1,
838         (field_name ? field_name : "<UNKNOWN>"));
839     proto_item_set_generated(ti_field_name);
840     if (field_name) {
841         proto_item_append_text(ti_field, " %s %s", field_name,
842             (field_type == PROTOBUF_TYPE_MESSAGE || field_type == PROTOBUF_TYPE_GROUP
843                 || field_type == PROTOBUF_TYPE_BYTES)
844             ? "" : "="
845         );
846         if (field_type > 0) {
847             ti_field_type = proto_tree_add_int(field_tree, hf_protobuf_field_type, tvb, *offset, 1, field_type);
848             proto_item_set_generated(ti_field_type);
849         }
850 
851         if (is_top_level) {
852             /* Show field name in Info column */
853             col_append_fstr(pinfo->cinfo, COL_INFO, " %s", field_name);
854         }
855     }
856 
857     /* move ti_field_number and ti_wire after ti_field_type (or field_type) for good look */
858     proto_tree_move_item(field_tree, (ti_field_type ? ti_field_type : ti_field_name), ti_wire);
859     proto_tree_move_item(field_tree, (ti_field_type ? ti_field_type : ti_field_name), ti_field_number);
860 
861     /* determine value_length, uint of numeric value and maybe value_length_size according to wire_type */
862     switch (wire_type)
863     {
864     case PROTOBUF_WIRETYPE_VARINT: /* varint, format: tag + varint */
865         /* get value length and real value */
866         value_length = tvb_get_varint(tvb, *offset, maxlen - tag_length, &value_uint64, ENC_VARINT_PROTOBUF);
867         if (value_length == 0) {
868             expert_add_info(pinfo, ti_wire, &ei_protobuf_failed_parse_field);
869             return FALSE;
870         }
871         break;
872 
873     case PROTOBUF_WIRETYPE_FIXED64: /* fixed 64-bit type, format: tag + 64-bit-value */
874         /* get value length and real value */
875         value_length = 8;
876         value_uint64 = tvb_get_letoh64(tvb, *offset);
877         break;
878 
879     case PROTOBUF_WIRETYPE_FIXED32: /* fixed 32-bit type, format: tag + 32-bit-value */
880         value_length = 4;
881         value_uint64 = tvb_get_letohl(tvb, *offset);
882         break;
883 
884     case PROTOBUF_WIRETYPE_LENGTH_DELIMITED: /* Length-delimited, format: tag + length(varint) + bytes_value */
885         /* this time value_uint64 is the length of following value bytes */
886         value_length_size = tvb_get_varint(tvb, *offset, maxlen - tag_length, &value_uint64, ENC_VARINT_PROTOBUF);
887         if (value_length_size == 0) {
888             expert_add_info(pinfo, ti_field, &ei_protobuf_failed_parse_length_delimited_field);
889             return FALSE;
890         }
891 
892         ti_value_length = proto_tree_add_uint64(field_tree, hf_protobuf_value_length, tvb, *offset, value_length_size, value_uint64);
893         (*offset) += value_length_size;
894 
895         /* we believe the length of following value will not be bigger than guint */
896         value_length = (guint) value_uint64;
897         break;
898 
899     default:
900         expert_add_info(pinfo, ti_wire, &ei_protobuf_wire_type_invalid);
901         return FALSE;
902     }
903 
904     proto_item_set_len(ti_field, tag_length + value_length_size + value_length);
905     proto_item_set_len(ti_field_name, tag_length + value_length_size + value_length);
906     if (ti_field_type) {
907         proto_item_set_len(ti_field_type, tag_length + value_length_size + value_length);
908     }
909 
910     /* add value as bytes first */
911     ti_value = proto_tree_add_item(field_tree, hf_protobuf_value_data, tvb, *offset, value_length, ENC_NA);
912 
913     /* add value subtree. we add uint value for numeric field or string for length-delimited at least. */
914     value_tree = proto_item_add_subtree(ti_value, ett_protobuf_value);
915 
916     if (field_desc) {
917         if (is_packed_repeated) {
918             dissect_packed_repeated_field_values(tvb, *offset, value_length, pinfo, ti_field,
919                 wire_type, field_type, "", field_desc);
920         } else {
921             protobuf_dissect_field_value(value_tree, tvb, *offset, value_length, pinfo, ti_field, field_type, value_uint64, "", field_desc,
922                                          is_top_level);
923         }
924     } else {
925         if (show_all_possible_field_types) {
926             /* try dissect every possible field type */
927             protobuf_try_dissect_field_value_on_multi_types(value_tree, tvb, *offset, value_length, pinfo,
928                 ti_field, protobuf_wire_to_field_type[wire_type], value_uint64, "");
929         } else {
930             field_type = (wire_type == PROTOBUF_WIRETYPE_LENGTH_DELIMITED)
931                 /* print string at least for length-delimited */
932                 ? (try_dissect_as_string ? PROTOBUF_TYPE_STRING : PROTOBUF_TYPE_NONE)
933                 /* use uint32 or uint64 */
934                 : (value_uint64 <= 0xFFFFFFFF ? PROTOBUF_TYPE_UINT32 : PROTOBUF_TYPE_UINT64);
935             int field_types[] = { field_type, PROTOBUF_TYPE_NONE };
936 
937             protobuf_try_dissect_field_value_on_multi_types(value_tree, tvb, *offset, value_length, pinfo,
938                 ti_field, field_types, value_uint64, "");
939         }
940     }
941 
942     if (field_desc && !show_details) {
943         proto_item_set_hidden(ti_field_number);
944         proto_item_set_hidden(ti_wire);
945         proto_item_set_hidden(ti_value_length);
946         proto_item_set_hidden(ti_field_name);
947         proto_item_set_hidden(ti_field_type);
948         if (field_type != PROTOBUF_TYPE_BYTES && field_type != PROTOBUF_TYPE_GROUP) {
949             proto_item_set_hidden(ti_value);
950         }
951     }
952 
953     (*offset) += value_length;
954     return TRUE;
955 }
956 
957 /* Make Protobuf fields that are not serialized on the wire (missing in capture files) to be displayed
958  * with default values. In 'proto2', default values can be explicitly declared. In 'proto3', if a
959  * field is set to its default, the value will *not* be serialized on the wire.
960  *
961  * The default value will be displayed according to following situations:
962  *  1. Explicitly-declared default values in 'proto2', for example:
963  *             optional int32 result_per_page = 3 [default = 10]; // default value is 10
964  *  2. For bools, the default value is false.
965  *  3. For enums, the default value is the first defined enum value, which must be 0 in 'proto3' (but
966  *     allowed to be other in 'proto2').
967  *  4. For numeric types, the default value is zero.
968  * There are no default values for fields 'repeated' or 'bytes' and 'string' without default value declared.
969  * If the missing field is 'required' in a 'proto2' file, an expert warning item will be added to the tree.
970  *
971  * Which fields will be displayed is controlled by 'add_default_value' option:
972  *  - ADD_DEFAULT_VALUE_NONE      -- do not display any missing fields.
973  *  - ADD_DEFAULT_VALUE_DECLARED  -- only missing fields of situation (1) will be displayed.
974  *  - ADD_DEFAULT_VALUE_ENUM_BOOL -- missing fields of situantions (1, 2 and 3) will be displayed.
975  *  - ADD_DEFAULT_VALUE_ALL       -- missing fields of all situations (1, 2, 3, and 4) will be displayed.
976  */
977 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)978 add_missing_fields_with_default_values(tvbuff_t* tvb, guint offset, packet_info* pinfo, proto_tree* message_tree,
979     const PbwDescriptor* message_desc, int* parsed_fields, int parsed_fields_count)
980 {
981     const PbwFieldDescriptor* field_desc;
982     const gchar* field_name, * field_full_name, * enum_value_name, * string_value;
983     int field_count = pbw_Descriptor_field_count(message_desc);
984     int field_type, i, j;
985     guint64 field_number;
986     gboolean is_required;
987     gboolean is_repeated;
988     gboolean has_default_value; /* explicitly-declared default value */
989     proto_item* ti_message = proto_tree_get_parent(message_tree);
990     proto_item* ti_field, * ti_field_number, * ti_field_name, * ti_field_type, * ti_value, * ti_pbf;
991     proto_tree* field_tree, * pbf_tree;
992     int* hf_id_ptr;
993     gdouble double_value;
994     gfloat float_value;
995     gint64 int64_value;
996     gint32 int32_value;
997     guint64 uint64_value;
998     guint32 uint32_value;
999     gboolean bool_value;
1000     gint size;
1001     const PbwEnumValueDescriptor* enum_value_desc;
1002 
1003     for (i = 0; i < field_count; i++) {
1004         field_desc = pbw_Descriptor_field(message_desc, i);
1005         field_number = (guint64) pbw_FieldDescriptor_number(field_desc);
1006         field_type = pbw_FieldDescriptor_type(field_desc);
1007         is_required = pbw_FieldDescriptor_is_required(field_desc);
1008         is_repeated = pbw_FieldDescriptor_is_repeated(field_desc);
1009         has_default_value = pbw_FieldDescriptor_has_default_value(field_desc);
1010 
1011         if (!is_required && add_default_value == ADD_DEFAULT_VALUE_DECLARED && !has_default_value) {
1012             /* ignore this field if default value is not explicitly-declared */
1013             continue;
1014         }
1015 
1016         if (!is_required && add_default_value == ADD_DEFAULT_VALUE_ENUM_BOOL && !has_default_value
1017             && field_type != PROTOBUF_TYPE_ENUM && field_type != PROTOBUF_TYPE_BOOL) {
1018             /* ignore this field if default value is not explicitly-declared, or it is not enum or bool */
1019             continue;
1020         }
1021 
1022         /* ignore repeated fields, or optional fields of message/group,
1023          * or string/bytes fields without explicitly-declared default value.
1024          */
1025         if (is_repeated || (!is_required && (field_type == PROTOBUF_TYPE_NONE
1026             || field_type == PROTOBUF_TYPE_MESSAGE
1027             || field_type == PROTOBUF_TYPE_GROUP
1028             || (field_type == PROTOBUF_TYPE_BYTES && !has_default_value)
1029             || (field_type == PROTOBUF_TYPE_STRING && !has_default_value)
1030             ))) {
1031             continue;
1032         }
1033 
1034         /* check if it is parsed */
1035         if (parsed_fields && parsed_fields_count > 0) {
1036             for (j = 0; j < parsed_fields_count; j++) {
1037                 if ((guint64) parsed_fields[j] == field_number) {
1038                     break;
1039                 }
1040             }
1041             if (j < parsed_fields_count) {
1042                 continue; /* this field is parsed */
1043             }
1044         }
1045 
1046         field_name = pbw_FieldDescriptor_name(field_desc);
1047 
1048         /* this field is not found in message payload */
1049         if (is_required) {
1050             expert_add_info_format(pinfo, ti_message, &et_protobuf_missing_required_field, "missing required field '%s'", field_name);
1051             continue;
1052         }
1053 
1054         field_full_name = pbw_FieldDescriptor_full_name(field_desc);
1055 
1056         /* add common tree item for this field */
1057         field_tree = proto_tree_add_subtree_format(message_tree, tvb, offset, 0, ett_protobuf_field, &ti_field,
1058             "Field(%" G_GUINT64_FORMAT "): %s %s", field_number, field_name, "=");
1059         proto_item_set_generated(ti_field);
1060 
1061         /* support filtering with the name, type or number of the field  */
1062         ti_field_name = proto_tree_add_string(field_tree, hf_protobuf_field_name, tvb, offset, 0, field_name);
1063         proto_item_set_generated(ti_field_name);
1064         ti_field_type = proto_tree_add_int(field_tree, hf_protobuf_field_type, tvb, offset, 0, field_type);
1065         proto_item_set_generated(ti_field_type);
1066         ti_field_number = proto_tree_add_uint64_format(field_tree, hf_protobuf_field_number, tvb, offset, 0, field_number << 3, "Field Number: %" G_GUINT64_FORMAT, field_number);
1067         proto_item_set_generated(ti_field_number);
1068 
1069         hf_id_ptr = NULL;
1070         if (pbf_as_hf && field_full_name) {
1071             hf_id_ptr = (int*)g_hash_table_lookup(pbf_hf_hash, field_full_name);
1072             DISSECTOR_ASSERT_HINT(hf_id_ptr && (*hf_id_ptr) > 0, "hf must have been initialized properly");
1073         }
1074 
1075         pbf_tree = field_tree;
1076         if (pbf_as_hf && hf_id_ptr && !show_details) {
1077             /* set ti_field (Field(x)) item hidden if there is header_field */
1078             proto_item_set_hidden(ti_field);
1079             pbf_tree = message_tree;
1080         }
1081 
1082         ti_value = ti_pbf = NULL;
1083         string_value = NULL;
1084         size = 0;
1085 
1086         switch (field_type)
1087         {
1088         case PROTOBUF_TYPE_INT32:
1089         case PROTOBUF_TYPE_SINT32:
1090         case PROTOBUF_TYPE_SFIXED32:
1091             int32_value = pbw_FieldDescriptor_default_value_int32(field_desc);
1092             ti_value = proto_tree_add_int(field_tree, hf_protobuf_value_int32, tvb, offset, 0, int32_value);
1093             proto_item_append_text(ti_field, " %d", int32_value);
1094             if (hf_id_ptr) {
1095                 ti_pbf = proto_tree_add_int(pbf_tree, *hf_id_ptr, tvb, offset, 0, int32_value);
1096             }
1097             break;
1098 
1099         case PROTOBUF_TYPE_INT64:
1100         case PROTOBUF_TYPE_SINT64:
1101         case PROTOBUF_TYPE_SFIXED64:
1102             int64_value = pbw_FieldDescriptor_default_value_int64(field_desc);
1103             ti_value = proto_tree_add_int64(field_tree, hf_protobuf_value_int64, tvb, offset, 0, int64_value);
1104             proto_item_append_text(ti_field, " %" G_GINT64_MODIFIER "d", int64_value);
1105             if (hf_id_ptr) {
1106                 ti_pbf = proto_tree_add_int64(pbf_tree, *hf_id_ptr, tvb, offset, 0, int64_value);
1107             }
1108             break;
1109 
1110         case PROTOBUF_TYPE_UINT32:
1111         case PROTOBUF_TYPE_FIXED32:
1112             uint32_value = pbw_FieldDescriptor_default_value_uint32(field_desc);
1113             ti_value = proto_tree_add_uint(field_tree, hf_protobuf_value_uint32, tvb, offset, 0, uint32_value);
1114             proto_item_append_text(ti_field, " %u", uint32_value);
1115             if (hf_id_ptr) {
1116                 ti_pbf = proto_tree_add_uint(pbf_tree, *hf_id_ptr, tvb, offset, 0, uint32_value);
1117             }
1118             break;
1119 
1120         case PROTOBUF_TYPE_UINT64:
1121         case PROTOBUF_TYPE_FIXED64:
1122             uint64_value = pbw_FieldDescriptor_default_value_uint64(field_desc);
1123             ti_value = proto_tree_add_uint64(field_tree, hf_protobuf_value_uint64, tvb, offset, 0, uint64_value);
1124             proto_item_append_text(ti_field, " %" G_GINT64_MODIFIER "u", uint64_value);
1125             if (hf_id_ptr) {
1126                 ti_pbf = proto_tree_add_uint64(pbf_tree, *hf_id_ptr, tvb, offset, 0, uint64_value);
1127             }
1128             break;
1129 
1130         case PROTOBUF_TYPE_BOOL:
1131             bool_value = pbw_FieldDescriptor_default_value_bool(field_desc);
1132             ti_value = proto_tree_add_boolean(field_tree, hf_protobuf_value_bool, tvb, offset, 0, bool_value);
1133             proto_item_append_text(ti_field, " %s", bool_value ? "true" : "false");
1134             if (hf_id_ptr) {
1135                 ti_pbf = proto_tree_add_boolean(pbf_tree, *hf_id_ptr, tvb, offset, 0, bool_value);
1136             }
1137             break;
1138 
1139         case PROTOBUF_TYPE_DOUBLE:
1140             double_value = pbw_FieldDescriptor_default_value_double(field_desc);
1141             ti_value = proto_tree_add_double(field_tree, hf_protobuf_value_double, tvb, offset, 0, double_value);
1142             proto_item_append_text(ti_field, " %lf", double_value);
1143             if (hf_id_ptr) {
1144                 ti_pbf = proto_tree_add_double(pbf_tree, *hf_id_ptr, tvb, offset, 0, double_value);
1145             }
1146             break;
1147 
1148         case PROTOBUF_TYPE_FLOAT:
1149             float_value = pbw_FieldDescriptor_default_value_float(field_desc);
1150             ti_value = proto_tree_add_float(field_tree, hf_protobuf_value_float, tvb, offset, 0, float_value);
1151             proto_item_append_text(ti_field, " %f", float_value);
1152             if (hf_id_ptr) {
1153                 ti_pbf = proto_tree_add_float(pbf_tree, *hf_id_ptr, tvb, offset, 0, float_value);
1154             }
1155             break;
1156 
1157         case PROTOBUF_TYPE_BYTES:
1158             string_value = pbw_FieldDescriptor_default_value_string(field_desc, &size);
1159             DISSECTOR_ASSERT_HINT(has_default_value && string_value, "Bytes field must have default value!");
1160             if (!dissect_bytes_as_string) {
1161                 ti_value = proto_tree_add_bytes_with_length(field_tree, hf_protobuf_value_data, tvb, offset, 0, (const guint8*) string_value, size);
1162                 proto_item_append_text(ti_field, " (%d bytes)", size);
1163                 /* the type of *hf_id_ptr MUST be FT_BYTES now */
1164                 if (hf_id_ptr) {
1165                     ti_pbf = proto_tree_add_bytes_with_length(pbf_tree, *hf_id_ptr, tvb, offset, 0, (const guint8*)string_value, size);
1166                 }
1167                 break;
1168             }
1169             /* or continue dissect BYTES as STRING */
1170             /* FALLTHROUGH */
1171         case PROTOBUF_TYPE_STRING:
1172             if (string_value == NULL) {
1173                 string_value = pbw_FieldDescriptor_default_value_string(field_desc, &size);
1174             }
1175             DISSECTOR_ASSERT_HINT(has_default_value && string_value, "String field must have default value!");
1176             ti_value = proto_tree_add_string(field_tree, hf_protobuf_value_string, tvb, offset, 0, string_value);
1177             proto_item_append_text(ti_field, " %s", string_value);
1178             if (hf_id_ptr) {
1179                 ti_pbf = proto_tree_add_string(pbf_tree, *hf_id_ptr, tvb, offset, 0, string_value);
1180             }
1181             break;
1182 
1183         case PROTOBUF_TYPE_ENUM:
1184             enum_value_desc = pbw_FieldDescriptor_default_value_enum(field_desc);
1185             if (enum_value_desc) {
1186                 int32_value = pbw_EnumValueDescriptor_number(enum_value_desc);
1187                 enum_value_name = pbw_EnumValueDescriptor_name(enum_value_desc);
1188                 ti_value = proto_tree_add_int(field_tree, hf_protobuf_value_int32, tvb, offset, 0, int32_value);
1189                 if (enum_value_name) { /* show enum value name */
1190                     proto_item_append_text(ti_field, " %s(%d)", enum_value_name, int32_value);
1191                     proto_item_append_text(ti_value, " (%s)", enum_value_name);
1192                 } else {
1193                     proto_item_append_text(ti_field, " %d", int32_value);
1194                 }
1195                 if (hf_id_ptr) {
1196                     ti_pbf = proto_tree_add_int(pbf_tree, *hf_id_ptr, tvb, offset, 0, int32_value);
1197                 }
1198                 break;
1199             } else {
1200                 expert_add_info_format(pinfo, ti_message, &et_protobuf_default_value_error, "enum value of field '%s' not found in *.proto!", field_name);
1201             }
1202             break;
1203 
1204         default:
1205             /* should not get here */
1206             break;
1207         }
1208 
1209         proto_item_append_text(ti_field, " (%s)", val_to_str(field_type, protobuf_field_type, "Unknown type (%d)"));
1210 
1211         if (ti_value) {
1212             proto_item_set_generated(ti_value);
1213         }
1214         if (ti_pbf) {
1215             proto_item_set_generated(ti_pbf);
1216         }
1217 
1218         if (!show_details) {
1219             proto_item_set_hidden(ti_field_name);
1220             proto_item_set_hidden(ti_field_type);
1221             proto_item_set_hidden(ti_field_number);
1222             if (ti_value && (field_type != PROTOBUF_TYPE_BYTES || dissect_bytes_as_string)) {
1223                 proto_item_set_hidden(ti_value);
1224             }
1225         }
1226     }
1227 }
1228 
1229 static void
dissect_protobuf_message(tvbuff_t * tvb,guint offset,guint length,packet_info * pinfo,proto_tree * protobuf_tree,const PbwDescriptor * message_desc,gboolean is_top_level)1230 dissect_protobuf_message(tvbuff_t *tvb, guint offset, guint length, packet_info *pinfo, proto_tree *protobuf_tree,
1231     const PbwDescriptor* message_desc, gboolean is_top_level)
1232 {
1233     proto_tree *message_tree;
1234     proto_item *ti_message, *ti;
1235     const gchar* message_name = "<UNKNOWN> Message Type";
1236     guint max_offset = offset + length;
1237     const PbwFieldDescriptor* field_desc;
1238     int* parsed_fields = NULL; /* store parsed field numbers. end with NULL */
1239     int parsed_fields_count = 0;
1240     int field_count = 0;
1241 
1242     if (message_desc) {
1243         message_name = pbw_Descriptor_full_name(message_desc);
1244         field_count = pbw_Descriptor_field_count(message_desc);
1245         if (add_default_value && field_count > 0) {
1246             parsed_fields = wmem_alloc0_array(pinfo->pool, int, field_count);
1247         }
1248     }
1249 
1250     if (pbf_as_hf && message_desc) {
1251         /* support filtering with message name as wireshark field name */
1252         int *hf_id_ptr = (int*)g_hash_table_lookup(pbf_hf_hash, message_name);
1253         DISSECTOR_ASSERT_HINT(hf_id_ptr && (*hf_id_ptr) > 0, "hf of message should initialized properly");
1254         ti_message = proto_tree_add_item(protobuf_tree, *hf_id_ptr, tvb, offset, length, ENC_NA);
1255         proto_item_set_text(ti_message, "Message: %s", message_name);
1256 
1257         if (show_details) {
1258             /* show "Message" item and add its fields under this item */
1259             message_tree = proto_item_add_subtree(ti_message, ett_protobuf_message);
1260         } else {
1261             /* hidden "Message" item (but still can be filtered by wireshark field name with "pbm.xxx" prefix),
1262              * and add its fields under the parent (field or protobuf protocol) item directly */
1263             proto_item_set_hidden(ti_message);
1264             message_tree = protobuf_tree;
1265             ti_message = proto_tree_get_parent(message_tree);
1266             proto_item_append_text(ti_message, " (Message: %s)", message_name);
1267         }
1268     } else {
1269         message_tree = proto_tree_add_subtree_format(protobuf_tree, tvb, offset, length, ett_protobuf_message,
1270             &ti_message, "Message: %s", message_name);
1271     }
1272 
1273     if (is_top_level) {
1274         col_clear(pinfo->cinfo, COL_PROTOCOL);
1275         col_append_fstr(pinfo->cinfo, COL_PROTOCOL, "PB(%s)", message_name);
1276         /* Top-level info will get written into Info column. */
1277         col_clear(pinfo->cinfo, COL_INFO);
1278     }
1279 
1280     /* support filtering with message name */
1281     ti = proto_tree_add_string(message_tree, hf_protobuf_message_name, tvb, offset, length, message_name);
1282     proto_item_set_generated(ti);
1283     if (!show_details) {
1284         proto_item_set_hidden(ti);
1285     }
1286 
1287     /* each time we dissect one protobuf field. */
1288     while (offset < max_offset)
1289     {
1290         field_desc = NULL;
1291         if (!dissect_one_protobuf_field(tvb, &offset, max_offset - offset, pinfo, message_tree, message_desc, is_top_level, &field_desc))
1292             break;
1293 
1294         if (parsed_fields && field_desc) {
1295             parsed_fields[parsed_fields_count++] = pbw_FieldDescriptor_number(field_desc);
1296         }
1297     }
1298 
1299     /* add default values for missing fields */
1300     if (add_default_value && field_count > 0) {
1301         add_missing_fields_with_default_values(tvb, offset, pinfo, message_tree, message_desc, parsed_fields, parsed_fields_count);
1302     }
1303 
1304     if (parsed_fields) {
1305         wmem_free(pinfo->pool, parsed_fields);
1306     }
1307 }
1308 
1309 /* try to find message type by UDP port */
1310 static const PbwDescriptor*
find_message_type_by_udp_port(packet_info * pinfo)1311 find_message_type_by_udp_port(packet_info *pinfo)
1312 {
1313     range_t* udp_port_range;
1314     const gchar* message_type;
1315     guint i;
1316     for (i = 0; i < num_protobuf_udp_message_types; ++i) {
1317         udp_port_range = protobuf_udp_message_types[i].udp_port_range;
1318         if (value_is_in_range(udp_port_range, pinfo->srcport)
1319             || value_is_in_range(udp_port_range, pinfo->destport))
1320         {
1321             message_type = protobuf_udp_message_types[i].message_type;
1322             if (message_type && strlen(message_type) > 0) {
1323                 return pbw_DescriptorPool_FindMessageTypeByName(pbw_pool, message_type);
1324             }
1325         }
1326     }
1327     return NULL;
1328 }
1329 
1330 static int
dissect_protobuf(tvbuff_t * tvb,packet_info * pinfo,proto_tree * tree,void * data)1331 dissect_protobuf(tvbuff_t *tvb, packet_info *pinfo, proto_tree *tree, void *data)
1332 {
1333     proto_item *ti;
1334     proto_tree *protobuf_tree;
1335     guint offset = 0;
1336     guint i;
1337     const PbwDescriptor* message_desc = NULL;
1338     const gchar* data_str = NULL;
1339 
1340     /* initialize only the first time the protobuf dissector is called */
1341     if (!protobuf_dissector_called) {
1342         protobuf_dissector_called = TRUE;
1343         protobuf_reinit(PREFS_UPDATE_ALL);
1344     }
1345 
1346     /* may set col_set_str(pinfo->cinfo, COL_PROTOCOL, "PROTOBUF"); */
1347     col_append_str(pinfo->cinfo, COL_INFO, " (PROTOBUF)");
1348 
1349     ti = proto_tree_add_item(tree, proto_protobuf, tvb, 0, -1, ENC_NA);
1350     protobuf_tree = proto_item_add_subtree(ti, ett_protobuf);
1351 
1352     /* The dissectors written in Lua are not able to specify the message type by data
1353        parameter when calling protobuf dissector. But they can tell Protobuf dissector
1354        the message type by the value of pinfo->private_table["pb_msg_type"]. */
1355     if (data) {
1356         data_str = (const gchar*)data;
1357     } else if (pinfo->private_table) {
1358         data_str = (const gchar*)g_hash_table_lookup(pinfo->private_table, "pb_msg_type");
1359     }
1360 
1361     if (data_str) {
1362         /* The data_str has two formats:
1363         * (1) Come from GRPC dissector like:
1364         *    http2_content_type "," http2_path "," ("request" / "response")
1365         * Acording to grpc wire format guide, it will be:
1366         *    "application/grpc" ["+proto"] "," "/" service-name "/" method-name "," ("request" / "response")
1367         * For example:
1368         *    application/grpc,/helloworld.Greeter/SayHello,request
1369         * In this format, we will try to get real protobuf message type by method (service-name.method-name)
1370         * and in/out type (request / reponse).
1371         * (2) Come from other dissector which specifies message type directly, like:
1372         *    "message," message_type_name
1373         * For example:
1374         *    message,helloworld.HelloRequest      (helloworld is package, HelloRequest is message type)
1375         */
1376         const gchar* message_info = strchr(data_str, ',');
1377 
1378         if (message_info) {
1379             message_info++; /* ignore ',' */
1380             proto_item_append_text(ti, ": %s", message_info);  /* append to proto item */
1381 
1382             if (g_str_has_prefix(data_str, "message,")) {
1383                 /* find message type by name directly */
1384                 message_desc = pbw_DescriptorPool_FindMessageTypeByName(pbw_pool, message_info);
1385             } else /* if (g_str_has_prefix(data_str, "application/grpc,") */ {
1386                 /* get long method-name like: helloworld.Greeter.SayHello */
1387                 if (message_info[0] == '/') {
1388                     message_info++; /* ignore first '/' */
1389                 }
1390 
1391                 gchar** tmp_names = wmem_strsplit(pinfo->pool, message_info, ",", 2);
1392                 gchar* method_name = (tmp_names[0]) ? tmp_names[0] : NULL;
1393                 gchar* direction_type = (method_name && tmp_names[1]) ? tmp_names[1] : NULL;
1394 
1395                 /* replace all '/' to '.', so helloworld.Greeter/SayHello converted to helloworld.Greeter.SayHello */
1396                 if (method_name) {
1397                     for (i = 0; method_name[i] != 0; i++) {
1398                         if (method_name[i] == '/') {
1399                             method_name[i] = '.';
1400                         }
1401                     }
1402                 }
1403 
1404                 /* find message type according to method descriptor */
1405                 if (direction_type) {
1406                     const PbwMethodDescriptor* method_desc = pbw_DescriptorPool_FindMethodByName(pbw_pool, method_name);
1407                     if (method_desc) {
1408                         message_desc = strcmp(direction_type, "request") == 0
1409                             ? pbw_MethodDescriptor_input_type(method_desc)
1410                             : pbw_MethodDescriptor_output_type(method_desc);
1411                     }
1412                 }
1413             }
1414 
1415             if (message_desc) {
1416                 const char* message_full_name = pbw_Descriptor_full_name(message_desc);
1417                 if (message_full_name) {
1418                     col_append_fstr(pinfo->cinfo, COL_INFO, " %s", message_full_name);
1419                 }
1420             }
1421         }
1422 
1423     } else if (pinfo->ptype == PT_UDP) {
1424         message_desc = find_message_type_by_udp_port(pinfo);
1425     }
1426 
1427     dissect_protobuf_message(tvb, offset, tvb_reported_length_remaining(tvb, offset), pinfo,
1428         protobuf_tree, message_desc, pinfo->ptype == PT_UDP);
1429 
1430     return tvb_captured_length(tvb);
1431 }
1432 
1433 static gboolean
load_all_files_in_dir(PbwDescriptorPool * pool,const gchar * dir_path)1434 load_all_files_in_dir(PbwDescriptorPool* pool, const gchar* dir_path)
1435 {
1436     WS_DIR        *dir;             /* scanned directory */
1437     WS_DIRENT     *file;            /* current file */
1438     const gchar   *dot;
1439     const gchar   *name;            /* current file or dir name (without parent dir path) */
1440     gchar         *path;            /* sub file or dir path of dir_path */
1441 
1442     if (g_file_test(dir_path, G_FILE_TEST_IS_DIR)) {
1443         if ((dir = ws_dir_open(dir_path, 0, NULL)) != NULL) {
1444             while ((file = ws_dir_read_name(dir)) != NULL) {
1445                 /* load all files with '.proto' suffix */
1446                 name = ws_dir_get_name(file);
1447                 path = g_build_filename(dir_path, name, NULL);
1448                 dot = strrchr(name, '.');
1449                 if (dot && g_ascii_strcasecmp(dot + 1, "proto") == 0) {
1450                     /* Note: pbw_load_proto_file support absolute or relative (to one of search paths) path */
1451                     if (pbw_load_proto_file(pool, path) != 0) {
1452                         g_free(path);
1453                         ws_dir_close(dir);
1454                         return FALSE;
1455                     }
1456                 } else {
1457                     if (!load_all_files_in_dir(pool, path)) {
1458                         g_free(path);
1459                         ws_dir_close(dir);
1460                         return FALSE;
1461                     }
1462                 }
1463                 g_free(path);
1464             }
1465             ws_dir_close(dir);
1466         }
1467     }
1468     return TRUE;
1469 }
1470 
1471 /* There might be a lot of errors to be found during parsing .proto files.
1472    We buffer the errors first, and print them in one list finally. */
1473 static wmem_strbuf_t* err_msg_buf = NULL;
1474 #define MIN_ERR_STR_BUF_SIZE 512
1475 #define MAX_ERR_STR_BUF_SIZE 1024
1476 
1477 static void
buffer_error(const gchar * fmt,...)1478 buffer_error(const gchar *fmt, ...)
1479 {
1480     va_list ap;
1481     va_start(ap, fmt);
1482 
1483     if (err_msg_buf == NULL)
1484         err_msg_buf = wmem_strbuf_sized_new(wmem_epan_scope(), MIN_ERR_STR_BUF_SIZE, MAX_ERR_STR_BUF_SIZE);
1485 
1486     wmem_strbuf_append_vprintf(err_msg_buf, fmt, ap);
1487 
1488     va_end(ap);
1489 }
1490 
1491 static void
flush_and_report_error(void)1492 flush_and_report_error(void)
1493 {
1494     char* str;
1495     if (err_msg_buf) {
1496         str = wmem_strbuf_finalize(err_msg_buf);
1497         err_msg_buf = NULL;
1498         report_failure("Protobuf: Error(s):\n%s", str);
1499         wmem_free(wmem_epan_scope(), str);
1500     }
1501 }
1502 
1503 static void
update_protobuf_search_paths(void)1504 update_protobuf_search_paths(void)
1505 {
1506     protobuf_reinit(PREFS_UPDATE_PROTOBUF_SEARCH_PATHS);
1507 }
1508 
1509 static void
update_protobuf_udp_message_types(void)1510 update_protobuf_udp_message_types(void)
1511 {
1512     protobuf_reinit(PREFS_UPDATE_PROTOBUF_UDP_MESSAGE_TYPES);
1513 }
1514 
1515 static void
deregister_header_fields(void)1516 deregister_header_fields(void)
1517 {
1518     if (dynamic_hf) {
1519         /* Deregister all fields */
1520         for (guint i = 0; i < dynamic_hf_size; i++) {
1521             proto_deregister_field(proto_protobuf, *(dynamic_hf[i].p_id));
1522             g_free(dynamic_hf[i].p_id);
1523             /* dynamic_hf[i].name and .abbrev will be freed by proto_add_deregistered_data */
1524         }
1525 
1526         proto_add_deregistered_data(dynamic_hf);
1527         dynamic_hf = NULL;
1528         dynamic_hf_size = 0;
1529     }
1530 
1531     if (pbf_hf_hash) {
1532         g_hash_table_destroy(pbf_hf_hash);
1533         pbf_hf_hash = NULL;
1534     }
1535 }
1536 
1537 /* convert the names of the enum's values to value_string array */
1538 static value_string*
enum_to_value_string(const PbwEnumDescriptor * enum_desc)1539 enum_to_value_string(const PbwEnumDescriptor* enum_desc)
1540 {
1541     value_string* vals;
1542     int i, value_count;
1543     if (enum_desc == NULL || (value_count = pbw_EnumDescriptor_value_count(enum_desc)) == 0) {
1544         return NULL;
1545     }
1546 
1547     vals = g_new0(value_string, value_count + 1);
1548     for (i = 0; i < value_count; i++) {
1549         const PbwEnumValueDescriptor* enum_value_desc = pbw_EnumDescriptor_value(enum_desc, i);
1550         vals[i].value = pbw_EnumValueDescriptor_number(enum_value_desc);
1551         vals[i].strptr = g_strdup(pbw_EnumValueDescriptor_name(enum_value_desc));
1552     }
1553     /* the strptr of last element of vals must be NULL */
1554     return vals;
1555 }
1556 
1557 /* create wireshark header fields according to each message's fields
1558  * and add them into pbf_as_hf hash table */
1559 static void
collect_fields(const PbwDescriptor * message,void * userdata)1560 collect_fields(const PbwDescriptor* message, void* userdata)
1561 {
1562     wmem_list_t* hf_list = (wmem_list_t*) userdata;
1563     hf_register_info* hf;
1564     const PbwFieldDescriptor* field_desc;
1565     const PbwEnumDescriptor* enum_desc;
1566     const PbwDescriptor* sub_msg_desc;
1567     int i, field_type, total_num = pbw_Descriptor_field_count(message);
1568 
1569     /* add message as field */
1570     hf = g_new0(hf_register_info, 1);
1571     hf->p_id = g_new(gint, 1);
1572     *(hf->p_id) = -1;
1573     hf->hfinfo.name = g_strdup(pbw_Descriptor_name(message));
1574     hf->hfinfo.abbrev = g_strdup_printf("pbm.%s", pbw_Descriptor_full_name(message));
1575     hf->hfinfo.type = FT_BYTES;
1576     hf->hfinfo.display = BASE_NONE;
1577     wmem_list_append(hf_list, hf);
1578     g_hash_table_insert(pbf_hf_hash, g_strdup(pbw_Descriptor_full_name(message)), hf->p_id);
1579 
1580     /* add fields of this message as fields */
1581     for (i = 0; i < total_num; i++) {
1582         field_desc = pbw_Descriptor_field(message, i);
1583         field_type = pbw_FieldDescriptor_type(field_desc);
1584         if (field_type <= PROTOBUF_TYPE_NONE ||field_type > PROTOBUF_MAX_FIELD_TYPE) {
1585             /* not a valid field type */
1586             continue;
1587         }
1588         hf = g_new0(hf_register_info, 1);
1589         hf->p_id = g_new(gint, 1);
1590         *(hf->p_id) = -1;
1591 
1592         hf->hfinfo.name = g_strdup(pbw_FieldDescriptor_name(field_desc));
1593         hf->hfinfo.abbrev = g_strdup_printf("pbf.%s", pbw_FieldDescriptor_full_name(field_desc));
1594         switch (field_type) {
1595         case PROTOBUF_TYPE_DOUBLE:
1596             hf->hfinfo.type = FT_DOUBLE;
1597             hf->hfinfo.display = BASE_NONE;
1598             break;
1599 
1600         case PROTOBUF_TYPE_FLOAT:
1601             hf->hfinfo.type = FT_FLOAT;
1602             hf->hfinfo.display = BASE_NONE;
1603             break;
1604 
1605         case PROTOBUF_TYPE_INT64:
1606         case PROTOBUF_TYPE_SFIXED64:
1607         case PROTOBUF_TYPE_SINT64:
1608             hf->hfinfo.type = FT_INT64;
1609             hf->hfinfo.display = BASE_DEC;
1610             break;
1611 
1612         case PROTOBUF_TYPE_UINT64:
1613         case PROTOBUF_TYPE_FIXED64:
1614             hf->hfinfo.type = FT_UINT64;
1615             hf->hfinfo.display = BASE_DEC;
1616             break;
1617 
1618         case PROTOBUF_TYPE_INT32:
1619         case PROTOBUF_TYPE_SFIXED32:
1620         case PROTOBUF_TYPE_SINT32:
1621             hf->hfinfo.type = FT_INT32;
1622             hf->hfinfo.display = BASE_DEC;
1623             break;
1624 
1625         case PROTOBUF_TYPE_UINT32:
1626         case PROTOBUF_TYPE_FIXED32:
1627             hf->hfinfo.type = FT_UINT32;
1628             hf->hfinfo.display = BASE_DEC;
1629             break;
1630 
1631         case PROTOBUF_TYPE_ENUM:
1632             hf->hfinfo.type = FT_INT32;
1633             hf->hfinfo.display = BASE_DEC;
1634             enum_desc = pbw_FieldDescriptor_enum_type(field_desc);
1635             if (enum_desc) {
1636                 hf->hfinfo.strings = enum_to_value_string(enum_desc);
1637             }
1638             break;
1639 
1640         case PROTOBUF_TYPE_BOOL:
1641             hf->hfinfo.type = FT_BOOLEAN;
1642             hf->hfinfo.display = BASE_NONE;
1643             break;
1644 
1645         case PROTOBUF_TYPE_BYTES:
1646             hf->hfinfo.type = dissect_bytes_as_string ? FT_STRING : FT_BYTES;
1647             hf->hfinfo.display = BASE_NONE;
1648             break;
1649 
1650         case PROTOBUF_TYPE_STRING:
1651             hf->hfinfo.type = FT_STRING;
1652             hf->hfinfo.display = BASE_NONE;
1653             break;
1654 
1655         case PROTOBUF_TYPE_GROUP:
1656         case PROTOBUF_TYPE_MESSAGE:
1657             sub_msg_desc = pbw_FieldDescriptor_message_type(field_desc);
1658             if (sub_msg_desc && strcmp(pbw_Descriptor_full_name(sub_msg_desc), "google.protobuf.Timestamp") == 0) {
1659                 hf->hfinfo.type = FT_ABSOLUTE_TIME;
1660                 hf->hfinfo.display = ABSOLUTE_TIME_LOCAL;
1661             } else {
1662                 hf->hfinfo.type = FT_BYTES;
1663                 hf->hfinfo.display = BASE_NONE;
1664             }
1665             break;
1666 
1667         default:
1668             /* should not happen */
1669             break;
1670         }
1671 
1672         wmem_list_append(hf_list, hf);
1673         g_hash_table_insert(pbf_hf_hash, g_strdup(pbw_FieldDescriptor_full_name(field_desc)), hf->p_id);
1674     }
1675 }
1676 
1677 static void
update_header_fields(gboolean force_reload)1678 update_header_fields(gboolean force_reload)
1679 {
1680     if (!force_reload && pbf_as_hf && dynamic_hf) {
1681         /* If initialized, do nothing. */
1682         return;
1683     }
1684     deregister_header_fields();
1685 
1686     if (pbf_as_hf) {
1687         int i;
1688         wmem_list_frame_t *it;
1689         wmem_list_t* hf_list = wmem_list_new(NULL);
1690         pbf_hf_hash = g_hash_table_new_full(g_str_hash, g_str_equal, g_free, NULL);
1691         DISSECTOR_ASSERT(pbw_pool);
1692         pbw_foreach_message(pbw_pool, collect_fields, hf_list);
1693         dynamic_hf_size = wmem_list_count(hf_list);
1694         if (dynamic_hf_size == 0) {
1695             deregister_header_fields();
1696             return;
1697         }
1698         dynamic_hf = g_new0(hf_register_info, dynamic_hf_size);
1699 
1700         for (it = wmem_list_head(hf_list), i = 0; it; it = wmem_list_frame_next(it), i++) {
1701             hf_register_info* hf = (hf_register_info*) wmem_list_frame_data(it);
1702             /* copy hf_register_info structure */
1703             dynamic_hf[i] = *hf;
1704             g_free(hf);
1705             HFILL_INIT(dynamic_hf[i]);
1706         }
1707 
1708         wmem_destroy_list(hf_list);
1709         proto_register_field_array(proto_protobuf, dynamic_hf, dynamic_hf_size);
1710     }
1711 }
1712 
1713 static void
protobuf_reinit(int target)1714 protobuf_reinit(int target)
1715 {
1716     guint i;
1717     char **source_paths;
1718     GSList* it;
1719     range_t* udp_port_range;
1720     const gchar* message_type;
1721     gboolean loading_completed = TRUE;
1722     size_t num_proto_paths;
1723 
1724     if (target & PREFS_UPDATE_PROTOBUF_UDP_MESSAGE_TYPES) {
1725         /* delete protobuf dissector from old udp ports */
1726         for (it = old_udp_port_ranges; it; it = it->next) {
1727             udp_port_range = (range_t*) it->data;
1728             dissector_delete_uint_range("udp.port", udp_port_range, protobuf_handle);
1729             wmem_free(NULL, udp_port_range);
1730         }
1731 
1732         if (old_udp_port_ranges) {
1733             g_slist_free(old_udp_port_ranges);
1734             old_udp_port_ranges = NULL;
1735         }
1736 
1737         /* add protobuf dissector to new udp ports */
1738         for (i = 0; i < num_protobuf_udp_message_types; ++i) {
1739             udp_port_range = protobuf_udp_message_types[i].udp_port_range;
1740             if (udp_port_range) {
1741                 udp_port_range = range_copy(NULL, udp_port_range);
1742                 old_udp_port_ranges = g_slist_append(old_udp_port_ranges, udp_port_range);
1743                 dissector_add_uint_range("udp.port", udp_port_range, protobuf_handle);
1744             }
1745         }
1746     }
1747 
1748     /* loading .proto files and checking message types of UDP port will be done only after dissector is called */
1749     if (!protobuf_dissector_called) {
1750         return;
1751     }
1752 
1753     if (target & PREFS_UPDATE_PROTOBUF_SEARCH_PATHS) {
1754         /* convert protobuf_search_path_t array to char* array. should release by g_free().
1755            Add the global and profile protobuf dirs to the search list, add 1 for the terminating null entry */
1756         num_proto_paths = (size_t)num_protobuf_search_paths + 2;
1757         source_paths = g_new0(char *, num_proto_paths + 1);
1758 
1759         /* Load the files in the global and personal config dirs */
1760         source_paths[0] = get_datafile_path("protobuf");
1761         source_paths[1] = get_persconffile_path("protobuf", TRUE);
1762 
1763         for (i = 0; i < num_protobuf_search_paths; ++i) {
1764             source_paths[i + 2] = protobuf_search_paths[i].path;
1765         }
1766 
1767         /* init DescriptorPool of protobuf */
1768         pbw_reinit_DescriptorPool(&pbw_pool, (const char **)source_paths, buffer_error);
1769 
1770         /* load all .proto files in the marked search paths, we can invoke FindMethodByName etc later. */
1771         for (i = 0; i < num_proto_paths; ++i) {
1772             if ((i < 2) || protobuf_search_paths[i - 2].load_all) {
1773                 if (!load_all_files_in_dir(pbw_pool, source_paths[i])) {
1774                     buffer_error("Protobuf: Loading .proto files action stopped!\n");
1775                     loading_completed = FALSE;
1776                     break; /* stop loading when error occurs */
1777                 }
1778             }
1779         }
1780 
1781         g_free(source_paths[0]);
1782         g_free(source_paths[1]);
1783         g_free(source_paths);
1784         update_header_fields(TRUE);
1785     }
1786 
1787     /* check if the message types of UDP port exist */
1788     for (i = 0; i < num_protobuf_udp_message_types; ++i) {
1789         message_type = protobuf_udp_message_types[i].message_type;
1790         if (loading_completed && message_type && strlen(message_type) > 0
1791             && pbw_DescriptorPool_FindMessageTypeByName(pbw_pool, message_type) == NULL) {
1792             buffer_error("Protobuf: the message type \"%s\" of UDP Message Type preferences does not exist!\n", message_type);
1793         }
1794     }
1795 
1796     /* report error if encountered */
1797     flush_and_report_error();
1798 }
1799 
1800 void
proto_register_protobuf(void)1801 proto_register_protobuf(void)
1802 {
1803     static hf_register_info hf[] = {
1804         { &hf_protobuf_message_name,
1805             { "Message Name", "protobuf.message.name",
1806                FT_STRING, BASE_NONE, NULL, 0x0,
1807               "The name of the protobuf message", HFILL }
1808         },
1809         { &hf_protobuf_field_name,
1810             { "Field Name", "protobuf.field.name",
1811                FT_STRING, BASE_NONE, NULL, 0x0,
1812               "The name of the field", HFILL }
1813         },
1814         { &hf_protobuf_field_type,
1815             { "Field Type", "protobuf.field.type",
1816                FT_INT32, BASE_DEC, VALS(protobuf_field_type), 0x0,
1817               "The type of the field", HFILL }
1818         },
1819         { &hf_protobuf_field_number,
1820             { "Field Number", "protobuf.field.number",
1821                FT_UINT64, BASE_DEC, NULL, G_GUINT64_CONSTANT(0xFFFFFFFFFFFFFFF8),
1822               "Field number encoded in varint", HFILL }
1823         },
1824         { &hf_protobuf_wire_type,
1825             { "Wire Type", "protobuf.field.wiretype",
1826                FT_UINT8, BASE_DEC, VALS(protobuf_wire_type), 0x07,
1827               "The Wire Type of the field.", HFILL }
1828         },
1829         { &hf_protobuf_value_length,
1830             { "Value Length", "protobuf.field.value.length",
1831                FT_UINT64, BASE_DEC, NULL, 0x0,
1832               "The length of length-delimited field value.", HFILL }
1833         },
1834         { &hf_protobuf_value_data,
1835             { "Value", "protobuf.field.value",
1836                FT_BYTES, BASE_NONE, NULL, 0x0,
1837               "The wire type determines value format", HFILL }
1838         },
1839         { &hf_protobuf_value_double,
1840             { "Double", "protobuf.field.value.double",
1841                FT_DOUBLE, BASE_NONE, NULL, 0x0,
1842               "Dissect value as double", HFILL }
1843         },
1844         { &hf_protobuf_value_float,
1845             { "Float", "protobuf.field.value.float",
1846                FT_FLOAT, BASE_NONE, NULL, 0x0,
1847               "Dissect value as float", HFILL }
1848         },
1849         { &hf_protobuf_value_int64,
1850             { "Int64", "protobuf.field.value.int64",
1851                FT_INT64, BASE_DEC, NULL, 0x0,
1852               "Dissect value as int64", HFILL }
1853         },
1854         { &hf_protobuf_value_uint64,
1855             { "Uint64", "protobuf.field.value.uint64",
1856                FT_UINT64, BASE_DEC, NULL, 0x0,
1857               "Dissect value as uint64", HFILL }
1858         },
1859         { &hf_protobuf_value_int32,
1860             { "Int32", "protobuf.field.value.int32",
1861                FT_INT32, BASE_DEC, NULL, 0x0,
1862               "Dissect value as int32", HFILL }
1863         },
1864         { &hf_protobuf_value_uint32,
1865             { "Uint32", "protobuf.field.value.uint32",
1866                FT_UINT32, BASE_DEC, NULL, 0x0,
1867               "Dissect value as uint32", HFILL }
1868         },
1869         { &hf_protobuf_value_bool,
1870             { "Bool", "protobuf.field.value.bool",
1871                FT_BOOLEAN, BASE_DEC, NULL, 0x0,
1872               "Dissect value as bool", HFILL }
1873         },
1874         { &hf_protobuf_value_string,
1875             { "String", "protobuf.field.value.string",
1876                FT_STRING, BASE_NONE, NULL, 0x0,
1877               "Dissect value as string", HFILL }
1878         },
1879         { &hf_protobuf_value_repeated,
1880             { "Repeated", "protobuf.field.value.repeated",
1881                FT_BYTES, BASE_NONE, NULL, 0x0,
1882               "Dissect value as repeated", HFILL }
1883         }
1884     };
1885 
1886     static gint *ett[] = {
1887         &ett_protobuf,
1888         &ett_protobuf_message,
1889         &ett_protobuf_field,
1890         &ett_protobuf_value,
1891         &ett_protobuf_packed_repeated
1892     };
1893 
1894     /* Setup protocol expert items */
1895     static ei_register_info ei[] = {
1896         { &ei_protobuf_failed_parse_tag,
1897           { "protobuf.failed_parse_tag", PI_MALFORMED, PI_ERROR,
1898             "Failed to parse tag field", EXPFILL }
1899         },
1900         { &ei_protobuf_wire_type_invalid,
1901           { "protobuf.field.wiretype.invalid", PI_PROTOCOL, PI_WARN,
1902             "Unknown or unsupported wiretype", EXPFILL }
1903         },
1904         { &ei_protobuf_failed_parse_length_delimited_field,
1905           { "protobuf.field.failed_parse_length_delimited_field", PI_MALFORMED, PI_ERROR,
1906             "Failed to parse length delimited field", EXPFILL }
1907         },
1908         { &ei_protobuf_failed_parse_field,
1909           { "protobuf.field.failed_parse_field", PI_MALFORMED, PI_ERROR,
1910             "Failed to parse value field", EXPFILL }
1911         },
1912         { &et_protobuf_message_type_not_found,
1913           { "protobuf.field.message_type_not_found", PI_PROTOCOL, PI_WARN,
1914             "Failed to find message type of a field", EXPFILL }
1915         },
1916         { &et_protobuf_wire_type_not_support_packed_repeated,
1917           { "protobuf.field.wire_type_not_support_packed_repeated", PI_MALFORMED, PI_ERROR,
1918             "The wire type does not support protobuf packed repeated field", EXPFILL }
1919         },
1920         { &et_protobuf_failed_parse_packed_repeated_field,
1921           { "protobuf.field.failed_parse_packed_repeated_field", PI_MALFORMED, PI_ERROR,
1922             "Failed to parse packed repeated field", EXPFILL }
1923         },
1924         { &et_protobuf_missing_required_field,
1925           { "protobuf.message.missing_required_field", PI_PROTOCOL, PI_WARN,
1926             "The required field is not found in message payload", EXPFILL }
1927         },
1928         { &et_protobuf_default_value_error,
1929           { "protobuf.message.default_value_error", PI_PROTOCOL, PI_WARN,
1930             "Parsing default value of a field error", EXPFILL }
1931         },
1932     };
1933 
1934     static const enum_val_t add_default_value_policy_vals[] = {
1935         {"none", "None", ADD_DEFAULT_VALUE_NONE},
1936         {"decl", "Only Explicitly-Declared (proto2)", ADD_DEFAULT_VALUE_DECLARED},
1937         {"enbl", "Explicitly-Declared, ENUM and BOOL", ADD_DEFAULT_VALUE_ENUM_BOOL},
1938         {"all",  "All", ADD_DEFAULT_VALUE_ALL},
1939         {NULL, NULL, -1}
1940     };
1941 
1942     module_t *protobuf_module;
1943     expert_module_t *expert_protobuf;
1944 
1945     static uat_field_t protobuf_search_paths_table_columns[] = {
1946         UAT_FLD_DIRECTORYNAME(protobuf_search_paths, path, "Protobuf source directory", "Directory of the root of protobuf source files"),
1947         UAT_FLD_BOOL(protobuf_search_paths, load_all, "Load all files", "Load all .proto files from this directory and its subdirectories"),
1948         UAT_END_FIELDS
1949     };
1950     uat_t* protobuf_search_paths_uat;
1951 
1952     static uat_field_t protobuf_udp_message_types_table_columns[] = {
1953         UAT_FLD_RANGE(protobuf_udp_message_types, udp_port_range, "UDP Ports", 0xFFFF, "UDP ports on which data will be dissected as protobuf"),
1954         UAT_FLD_CSTRING(protobuf_udp_message_types, message_type, "Message Type", "Protobuf message type of data on these udp ports"),
1955         UAT_END_FIELDS
1956     };
1957     uat_t* protobuf_udp_message_types_uat;
1958 
1959     proto_protobuf = proto_register_protocol("Protocol Buffers", "ProtoBuf", "protobuf");
1960 
1961     proto_register_field_array(proto_protobuf, hf, array_length(hf));
1962     proto_register_subtree_array(ett, array_length(ett));
1963 
1964     protobuf_module = prefs_register_protocol(proto_protobuf, proto_reg_handoff_protobuf);
1965 
1966     prefs_register_bool_preference(protobuf_module, "preload_protos",
1967         "Load .proto files on startup.",
1968         "Load .proto files when Wireshark starts. By default, the .proto files are loaded only"
1969         " when the Protobuf dissector is called for the first time.",
1970         &preload_protos);
1971 
1972     protobuf_search_paths_uat = uat_new("Protobuf Search Paths",
1973         sizeof(protobuf_search_path_t),
1974         "protobuf_search_paths",
1975         TRUE,
1976         &protobuf_search_paths,
1977         &num_protobuf_search_paths,
1978         UAT_AFFECTS_DISSECTION | UAT_AFFECTS_FIELDS,
1979         "ChProtobufSearchPaths",
1980         protobuf_search_paths_copy_cb,
1981         NULL,
1982         protobuf_search_paths_free_cb,
1983         update_protobuf_search_paths,
1984         NULL,
1985         protobuf_search_paths_table_columns
1986     );
1987 
1988     prefs_register_uat_preference(protobuf_module, "search_paths", "Protobuf search paths",
1989         "Specify the directories where .proto files are recursively loaded from, or in which to search for imports.",
1990         protobuf_search_paths_uat);
1991 
1992     prefs_register_bool_preference(protobuf_module, "pbf_as_hf",
1993         "Dissect Protobuf fields as Wireshark fields.",
1994         "If Protobuf messages and fields are defined in loaded .proto files,"
1995         " they will be dissected as wireshark fields if this option is turned on."
1996         " The names of all these wireshark fields will be prefixed with \"pbf.\" (for fields)"
1997         " or \"pbm.\" (for messages) followed by their full names in the .proto files.",
1998         &pbf_as_hf);
1999 
2000     prefs_set_preference_effect_fields(protobuf_module, "pbf_as_hf");
2001 
2002     prefs_register_bool_preference(protobuf_module, "show_details",
2003         "Show details of message, fields and enums.",
2004         "Show the names of message, field, enum and enum_value."
2005         " Show the wire type and field number format of field."
2006         " Show value nodes of field and enum_value.",
2007         &show_details);
2008 
2009     prefs_register_bool_preference(protobuf_module, "bytes_as_string",
2010         "Show all fields of bytes type as string.",
2011         "Show all fields of bytes type as string. For example ETCD string",
2012         &dissect_bytes_as_string);
2013 
2014     prefs_register_enum_preference(protobuf_module, "add_default_value",
2015         "Add missing fields with default values.",
2016         "Make Protobuf fields that are not serialized on the wire to be displayed with default values.\n"
2017         "The default value will be one of the following: \n"
2018         "  1) The value of the 'default' option of an optional field defined in 'proto2' file. (explicitly-declared)\n"
2019         "  2) False for bools.\n"
2020         "  3) First defined enum value for enums.\n"
2021         "  4) Zero for numeric types.\n"
2022         "There are no default values for fields 'repeated' or 'bytes' and 'string' without default value declared.\n"
2023         "If the missing field is 'required' in a 'proto2' file, a warning item will be added to the tree.",
2024         &add_default_value, add_default_value_policy_vals, FALSE);
2025 
2026     protobuf_udp_message_types_uat = uat_new("Protobuf UDP Message Types",
2027         sizeof(protobuf_udp_message_type_t),
2028         "protobuf_udp_message_types",
2029         TRUE,
2030         &protobuf_udp_message_types,
2031         &num_protobuf_udp_message_types,
2032         UAT_AFFECTS_DISSECTION | UAT_AFFECTS_FIELDS,
2033         "ChProtobufUDPMessageTypes",
2034         protobuf_udp_message_types_copy_cb,
2035         protobuf_udp_message_types_update_cb,
2036         protobuf_udp_message_types_free_cb,
2037         update_protobuf_udp_message_types,
2038         NULL,
2039         protobuf_udp_message_types_table_columns
2040     );
2041 
2042     prefs_register_uat_preference(protobuf_module, "udp_message_types", "Protobuf UDP message types",
2043         "Specify the Protobuf message type of data on certain UDP ports.",
2044         protobuf_udp_message_types_uat);
2045 
2046     /* Following preferences are for undefined fields, that happened while message type is not specified
2047        when calling dissect_protobuf(), or message type or field information is not found in search paths
2048     */
2049     prefs_register_bool_preference(protobuf_module, "try_dissect_as_string",
2050         "Try to dissect all undefined length-delimited fields as string.",
2051         "Try to dissect all undefined length-delimited fields as string.",
2052         &try_dissect_as_string);
2053 
2054     prefs_register_bool_preference(protobuf_module, "show_all_types",
2055         "Try to show all possible field types for each undefined field.",
2056         "Try to show all possible field types for each undefined field according to wire type.",
2057         &show_all_possible_field_types);
2058 
2059     prefs_register_static_text_preference(protobuf_module, "field_dissector_table_note",
2060         "Subdissector can register itself in \"protobuf_field\" dissector table for parsing"
2061         " the value of the field.",
2062         "The key of \"protobuf_field\" table is the full name of field.");
2063 
2064     protobuf_field_subdissector_table =
2065         register_dissector_table("protobuf_field", "Protobuf field subdissector table",
2066             proto_protobuf, FT_STRING, BASE_NONE);
2067 
2068     expert_protobuf = expert_register_protocol(proto_protobuf);
2069     expert_register_field_array(expert_protobuf, ei, array_length(ei));
2070 
2071     protobuf_handle = register_dissector("protobuf", dissect_protobuf, proto_protobuf);
2072 }
2073 
2074 void
proto_reg_handoff_protobuf(void)2075 proto_reg_handoff_protobuf(void)
2076 {
2077     if (protobuf_dissector_called) {
2078         update_header_fields( /* if bytes_as_string preferences changed, we force reload header fields */
2079             (old_dissect_bytes_as_string && !dissect_bytes_as_string) || (!old_dissect_bytes_as_string && dissect_bytes_as_string)
2080         );
2081     } else if (preload_protos) {
2082         protobuf_dissector_called = TRUE;
2083         protobuf_reinit(PREFS_UPDATE_ALL);
2084     }
2085     old_dissect_bytes_as_string = dissect_bytes_as_string;
2086     dissector_add_string("grpc_message_type", "application/grpc", protobuf_handle);
2087     dissector_add_string("grpc_message_type", "application/grpc+proto", protobuf_handle);
2088 }
2089 
2090 /*
2091  * Editor modelines  -  https://www.wireshark.org/tools/modelines.html
2092  *
2093  * Local variables:
2094  * c-basic-offset: 4
2095  * tab-width: 8
2096  * indent-tabs-mode: nil
2097  * End:
2098  *
2099  * vi: set shiftwidth=4 tabstop=8 expandtab:
2100  * :indentSize=4:tabSize=8:noTabs=true:
2101  */
2102