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, ×tamp)) {
679 ti = proto_tree_add_time(pbf_tree, *hf_id_ptr, tvb, offset, length, ×tamp);
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