aboutsummaryrefslogtreecommitdiffstats
path: root/epan/dissectors/packet-thrift.c
diff options
context:
space:
mode:
Diffstat (limited to 'epan/dissectors/packet-thrift.c')
-rw-r--r--epan/dissectors/packet-thrift.c818
1 files changed, 660 insertions, 158 deletions
diff --git a/epan/dissectors/packet-thrift.c b/epan/dissectors/packet-thrift.c
index f3667dc3f8..5205f18e7c 100644
--- a/epan/dissectors/packet-thrift.c
+++ b/epan/dissectors/packet-thrift.c
@@ -7,7 +7,7 @@
*
* Copyright 2015, Anders Broman <anders.broman[at]ericsson.com>
* Copyright 2021, Richard van der Hoff <richard[at]matrix.org>
- * Copyright 2019-2021, Triton Circonflexe <triton[at]kumal.info>
+ * Copyright 2019-2024, Triton Circonflexe <triton[at]kumal.info>
*
* Wireshark - Network traffic analyzer
* By Gerald Combs <gerald@wireshark.org>
@@ -26,8 +26,8 @@
#include <stdint.h>
#include <epan/packet.h>
-#include <epan/expert.h>
#include <epan/prefs.h>
+#include <epan/proto_data.h>
#include "packet-tcp.h"
#include "packet-tls.h"
@@ -70,11 +70,13 @@ void proto_reg_handoff_thrift(void);
} } while (0)
static dissector_handle_t thrift_handle;
+static dissector_handle_t thrift_http_handle;
static gboolean framed_desegment = TRUE;
static guint thrift_tls_port = 0;
static gboolean show_internal_thrift_fields = FALSE;
static gboolean try_generic_if_sub_dissector_fails = FALSE;
+static guint nested_type_depth = 25;
static dissector_table_t thrift_method_name_dissector_table;
@@ -87,6 +89,7 @@ static const int TBP_THRIFT_DOUBLE_LEN = 8;
static const int TBP_THRIFT_I16_LEN = 2;
static const int TBP_THRIFT_I32_LEN = 4;
static const int TBP_THRIFT_I64_LEN = 8;
+static const int TBP_THRIFT_UUID_LEN = 16;
static const int TBP_THRIFT_MTYPE_OFFSET = 3;
static const int TBP_THRIFT_MTYPE_LEN = 1;
static const int TBP_THRIFT_VERSION_LEN = 4; /* (Version + method type) is explicitly passed as an int32 in libthrift */
@@ -126,68 +129,72 @@ static const guint32 TCP_THRIFT_NIBBLE_MASK = 0xf;
static const int OCTETS_TO_BITS_SHIFT = 3; /* 8 bits per octets = 3 shifts left. */
static const int DISABLE_SUBTREE = -1;
-static int proto_thrift = -1;
-static int hf_thrift_frame_length = -1;
-static int hf_thrift_protocol_id = -1;
-static int hf_thrift_version = -1;
-static int hf_thrift_mtype = -1;
-static int hf_thrift_str_len = -1;
-static int hf_thrift_method = -1;
-static int hf_thrift_seq_id = -1;
-static int hf_thrift_type = -1;
-static int hf_thrift_key_type = -1;
-static int hf_thrift_value_type = -1;
-static int hf_thrift_compact_struct_type = -1;
-static int hf_thrift_fid = -1;
-static int hf_thrift_fid_delta = -1;
-static int hf_thrift_bool = -1;
-static int hf_thrift_i8 = -1;
-static int hf_thrift_i16 = -1;
-static int hf_thrift_i32 = -1;
-static int hf_thrift_i64 = -1;
-static int hf_thrift_binary = -1;
-static int hf_thrift_string = -1;
-static int hf_thrift_struct = -1;
-static int hf_thrift_list = -1;
-static int hf_thrift_set = -1;
-static int hf_thrift_map = -1;
-static int hf_thrift_num_list_item = -1;
-static int hf_thrift_num_set_item = -1;
-static int hf_thrift_num_map_item = -1;
-static int hf_thrift_large_container = -1;
-static int hf_thrift_double = -1;
-static int hf_thrift_exception = -1;
-static int hf_thrift_exception_message = -1;
-static int hf_thrift_exception_type = -1;
-
-static int ett_thrift = -1;
-static int ett_thrift_header = -1;
-static int ett_thrift_params = -1;
-static int ett_thrift_field = -1;
-static int ett_thrift_struct = -1;
-static int ett_thrift_list = -1;
-static int ett_thrift_set = -1;
-static int ett_thrift_map = -1;
-static int ett_thrift_error = -1; /* ME_THRIFT_T_REPLY with field id != 0 */
-static int ett_thrift_exception = -1; /* ME_THRIFT_T_EXCEPTION */
-
-static expert_field ei_thrift_wrong_type = EI_INIT;
-static expert_field ei_thrift_wrong_field_id = EI_INIT;
-static expert_field ei_thrift_negative_length = EI_INIT;
-static expert_field ei_thrift_wrong_proto_version = EI_INIT;
-static expert_field ei_thrift_struct_fid_not_in_seq = EI_INIT;
-static expert_field ei_thrift_frame_too_short = EI_INIT;
-static expert_field ei_thrift_not_enough_data = EI_INIT;
-static expert_field ei_thrift_frame_too_long = EI_INIT;
-static expert_field ei_thrift_varint_too_large = EI_INIT;
-static expert_field ei_thrift_undefined_field_id = EI_INIT;
-static expert_field ei_thrift_negative_field_id = EI_INIT;
-static expert_field ei_thrift_unordered_field_id = EI_INIT;
-static expert_field ei_thrift_application_exception = EI_INIT;
-static expert_field ei_thrift_protocol_exception = EI_INIT;
+static int proto_thrift;
+static int hf_thrift_frame_length;
+static int hf_thrift_protocol_id;
+static int hf_thrift_version;
+static int hf_thrift_mtype;
+static int hf_thrift_str_len;
+static int hf_thrift_method;
+static int hf_thrift_seq_id;
+static int hf_thrift_type;
+static int hf_thrift_key_type;
+static int hf_thrift_value_type;
+static int hf_thrift_compact_struct_type;
+static int hf_thrift_fid;
+static int hf_thrift_fid_delta;
+static int hf_thrift_bool;
+static int hf_thrift_i8;
+static int hf_thrift_i16;
+static int hf_thrift_i32;
+static int hf_thrift_i64;
+static int hf_thrift_uuid;
+static int hf_thrift_binary;
+static int hf_thrift_string;
+static int hf_thrift_struct;
+static int hf_thrift_list;
+static int hf_thrift_set;
+static int hf_thrift_map;
+static int hf_thrift_num_list_item;
+static int hf_thrift_num_list_pos;
+static int hf_thrift_num_set_item;
+static int hf_thrift_num_set_pos;
+static int hf_thrift_num_map_item;
+static int hf_thrift_large_container;
+static int hf_thrift_double;
+static int hf_thrift_exception;
+static int hf_thrift_exception_message;
+static int hf_thrift_exception_type;
+
+static int ett_thrift;
+static int ett_thrift_header;
+static int ett_thrift_params;
+static int ett_thrift_field;
+static int ett_thrift_struct;
+static int ett_thrift_list;
+static int ett_thrift_set;
+static int ett_thrift_map;
+static int ett_thrift_error; /* Error while reading the header. */
+static int ett_thrift_exception; /* ME_THRIFT_T_EXCEPTION */
+
+static expert_field ei_thrift_wrong_type;
+static expert_field ei_thrift_wrong_field_id;
+static expert_field ei_thrift_negative_length;
+static expert_field ei_thrift_wrong_proto_version;
+static expert_field ei_thrift_struct_fid_not_in_seq;
+static expert_field ei_thrift_frame_too_short;
+static expert_field ei_thrift_not_enough_data;
+static expert_field ei_thrift_frame_too_long;
+static expert_field ei_thrift_varint_too_large;
+static expert_field ei_thrift_undefined_field_id;
+static expert_field ei_thrift_negative_field_id;
+static expert_field ei_thrift_unordered_field_id;
+static expert_field ei_thrift_application_exception;
+static expert_field ei_thrift_protocol_exception;
+static expert_field ei_thrift_too_many_subtypes;
static const thrift_member_t thrift_exception[] = {
- { &hf_thrift_exception_message, 1, TRUE, DE_THRIFT_T_BINARY, NULL, { .encoding = ENC_UTF_8|ENC_NA } },
+ { &hf_thrift_exception_message, 1, TRUE, DE_THRIFT_T_BINARY, NULL, { .encoding = ENC_UTF_8 }, NULL },
{ &hf_thrift_exception_type, 2, FALSE, DE_THRIFT_T_I32, TMFILL },
{ NULL, 0, FALSE, DE_THRIFT_T_STOP, TMFILL }
};
@@ -206,6 +213,7 @@ typedef enum {
DE_THRIFT_C_SET,
DE_THRIFT_C_MAP,
DE_THRIFT_C_STRUCT,
+ DE_THRIFT_C_UUID,
} thrift_compact_type_enum_t;
typedef struct _thrift_field_header_t {
@@ -236,6 +244,7 @@ static const value_string thrift_type_vals[] = {
{ DE_THRIFT_T_MAP, "T_MAP" },
{ DE_THRIFT_T_SET, "T_SET" },
{ DE_THRIFT_T_LIST, "T_LIST" },
+ { DE_THRIFT_T_UUID, "T_UUID" },
{ 0, NULL }
};
@@ -253,6 +262,7 @@ static const value_string thrift_compact_type_vals[] = {
{ DE_THRIFT_C_SET, "T_SET" },
{ DE_THRIFT_C_MAP, "T_MAP" },
{ DE_THRIFT_C_STRUCT, "T_STRUCT" },
+ { DE_THRIFT_C_UUID, "T_UUID" },
{ 0, NULL }
};
@@ -311,7 +321,7 @@ static const enum_val_t binary_display_options[] = {
static int dissect_thrift_binary_type(tvbuff_t *tvb, packet_info *pinfo, proto_tree *tree, int *offset, thrift_option_data_t *thrift_opt, proto_tree *header_tree, int type, proto_item *type_pi);
static int dissect_thrift_compact_type(tvbuff_t *tvb, packet_info *pinfo, proto_tree *tree, int *offset, thrift_option_data_t *thrift_opt, proto_tree *header_tree, int type, proto_item *type_pi);
-
+static int dissect_thrift_t_struct_expert(tvbuff_t *tvb, packet_info *pinfo, proto_tree *tree, int offset, thrift_option_data_t *thrift_opt, gboolean is_field, int field_id, gint hf_id, gint ett_id, const thrift_member_t *seq, expert_field* ei);
/*=====BEGIN GENERIC HELPERS=====*/
/* Check that the 4-byte value match a Thrift Strict TBinaryProtocol version
@@ -487,6 +497,12 @@ thrift_get_varint_enc(tvbuff_t *tvb, packet_info *pinfo, proto_tree *tree, int o
return length;
}
+static gboolean
+is_thrift_compact_bool_type(thrift_compact_type_enum_t type)
+{
+ return type == DE_THRIFT_C_BOOL_TRUE || type == DE_THRIFT_C_BOOL_FALSE;
+}
+
/* Function that reads the field header and return all associated data.
*
* @param[in] tvb: Pointer to the tvbuff_t holding the captured data.
@@ -497,10 +513,12 @@ thrift_get_varint_enc(tvbuff_t *tvb, packet_info *pinfo, proto_tree *tree, int o
* and by dissect_thrift_common to differentiate between successful and exception T_REPLY.
* @param[in] offset: Offset from the beginning of the tvbuff_t where the Thrift field is. Function will dissect type, id, & data.
* @param[in] thrift_opt: Options from the Thrift dissector that will be necessary for sub-dissection (binary vs. compact, ...)
+ * @param[in] gen_bool: Generate item when one of the boolean types is encountered.
*
+ * @return See "GENERIC DISSECTION PARAMETERS DOCUMENTATION".
*/
static int
-dissect_thrift_field_header(tvbuff_t *tvb, packet_info *pinfo, proto_tree *tree, int *offset, thrift_option_data_t *thrift_opt, thrift_field_header_t *header)
+dissect_thrift_field_header(tvbuff_t *tvb, packet_info *pinfo, proto_tree *tree, int *offset, thrift_option_data_t *thrift_opt, thrift_field_header_t *header, gboolean gen_bool)
{
/*
* Binary protocol field header (3 bytes):
@@ -587,14 +605,28 @@ dissect_thrift_field_header(tvbuff_t *tvb, packet_info *pinfo, proto_tree *tree,
/* Create the field header sub-tree if requested only. */
if (tree != NULL) {
+ guint nested_count = p_get_proto_depth(pinfo, proto_thrift);
+ if (nested_count >= thrift_opt->nested_type_depth) {
+ expert_add_info(pinfo, proto_tree_get_parent(tree), &ei_thrift_too_many_subtypes);
+ return THRIFT_REQUEST_REASSEMBLY;
+ }
+
header->fh_tree = proto_tree_add_subtree_format(tree, tvb, header->type_offset, *offset - header->type_offset, ett_thrift_field, NULL,
- "Field Header #%" G_GINT64_MODIFIER "d", header->field_id);
+ "Field Header #%" PRId64, header->field_id);
if (thrift_opt->tprotocol & PROTO_THRIFT_COMPACT) {
header->type_pi = proto_tree_add_bits_item(header->fh_tree, hf_thrift_compact_struct_type, tvb, (header->type_offset << OCTETS_TO_BITS_SHIFT) + TCP_THRIFT_NIBBLE_SHIFT, TCP_THRIFT_NIBBLE_SHIFT, ENC_BIG_ENDIAN);
header->fid_pi = proto_tree_add_bits_item(header->fh_tree, hf_thrift_fid_delta, tvb, header->type_offset << OCTETS_TO_BITS_SHIFT, TCP_THRIFT_NIBBLE_SHIFT, ENC_BIG_ENDIAN);
if (delta == TCP_THRIFT_DELTA_NOT_SET) {
proto_item_append_text(header->fid_pi, " (Not Set)");
}
+ if (gen_bool && is_thrift_compact_bool_type(header->type.compact)) {
+ proto_item *bool_item = proto_tree_add_boolean(tree, hf_thrift_bool, tvb, header->type_offset, TBP_THRIFT_TYPE_LEN, 2 - header->type.compact);
+ proto_item_set_generated(bool_item);
+ }
+ if (gen_bool && is_thrift_compact_bool_type(header->type.compact)) {
+ proto_item *bool_item = proto_tree_add_boolean(tree, hf_thrift_bool, tvb, header->type_offset, TBP_THRIFT_TYPE_LEN, 2 - header->type.compact);
+ proto_item_set_generated(bool_item);
+ }
} else {
header->type_pi = proto_tree_add_item(header->fh_tree, hf_thrift_type, tvb, header->type_offset, TBP_THRIFT_TYPE_LEN, ENC_BIG_ENDIAN);
}
@@ -629,10 +661,27 @@ dissect_thrift_field_header(tvbuff_t *tvb, packet_info *pinfo, proto_tree *tree,
expert_add_info(pinfo, header->fid_pi, &ei_thrift_unordered_field_id);
}
}
- } else if (header->fid_length <= 0) {
- /* Varint for field id was too long to decode, handle the error without the sub-tree. */
- proto_tree_add_expert(tree, pinfo, &ei_thrift_varint_too_large, tvb, header->fid_offset, TCP_THRIFT_MAX_I16_LEN);
- return THRIFT_REQUEST_REASSEMBLY;
+ } else {
+ /* The fid_pi value (proto_item for field_id) is required for sub-dissectors.
+ * Create it even in the absence of tree. */
+ if (delta == TCP_THRIFT_DELTA_NOT_SET) {
+ if (header->fid_length > 0) {
+ header->fid_pi = proto_tree_add_item(header->fh_tree, hf_thrift_fid, tvb, header->fid_offset, header->fid_length, ENC_BIG_ENDIAN);
+ } else {
+ /* Varint for field id was too long to decode, handle the error without the sub-tree. */
+ proto_tree_add_expert(tree, pinfo, &ei_thrift_varint_too_large, tvb, header->fid_offset, TCP_THRIFT_MAX_I16_LEN);
+ return THRIFT_REQUEST_REASSEMBLY;
+ }
+ } else {
+ if ((gint64)INT16_MIN > header->field_id || header->field_id > (gint64)INT16_MAX) {
+ header->fid_pi = proto_tree_add_int64(header->fh_tree, hf_thrift_i64, tvb, header->fid_offset, header->fid_length, header->field_id);
+ expert_add_info(pinfo, header->fid_pi, &ei_thrift_varint_too_large);
+ /* We continue anyway as the field id was displayed successfully. */
+ } else {
+ header->fid_pi = proto_tree_add_int(header->fh_tree, hf_thrift_fid, tvb, header->fid_offset, header->fid_length, (gint16)header->field_id);
+ }
+ proto_item_set_generated(header->fid_pi);
+ }
}
return *offset;
@@ -654,11 +703,12 @@ dissect_thrift_field_header(tvbuff_t *tvb, packet_info *pinfo, proto_tree *tree,
* @param[in] hf_id: The hf_id that needs to be used for the display.
* If the found integer is larger that the expected integer size (driven by max_length parameter),
* the integer will always be displayed as a generic T_I64 and an expert info will be added.
+ * @param[in] raw_dissector Dissector for raw integer (we need to create a tvbuff_t with the flatten integer.
*
* @return See "GENERIC DISSECTION PARAMETERS DOCUMENTATION".
*/
static int
-dissect_thrift_varint(tvbuff_t *tvb, packet_info *pinfo, proto_tree *tree, int *offset, thrift_option_data_t *thrift_opt, int max_length, int hf_id)
+dissect_thrift_varint(tvbuff_t *tvb, packet_info *pinfo, proto_tree *tree, int *offset, thrift_option_data_t *thrift_opt, int max_length, int hf_id, dissector_t raw_dissector)
{
gint64 varint;
proto_item *pi;
@@ -679,7 +729,17 @@ dissect_thrift_varint(tvbuff_t *tvb, packet_info *pinfo, proto_tree *tree, int *
expert_add_info(pinfo, pi, &ei_thrift_varint_too_large);
/* We continue anyway as the varint was indeed decoded. */
} else {
- proto_tree_add_int(tree, hf_id, tvb, *offset, length, (gint16)varint);
+ if (raw_dissector != NULL) {
+ guint8 *data = wmem_alloc(wmem_packet_scope(), TBP_THRIFT_I16_LEN);
+ data[0] = (varint >> 8) & 0xFF;
+ data[1] = varint & 0xFF;
+ tvbuff_t* sub_tvb = tvb_new_child_real_data(tvb, data, TBP_THRIFT_I16_LEN, TBP_THRIFT_I16_LEN);
+ thrift_opt->use_std_dissector = FALSE;
+ raw_dissector(sub_tvb, pinfo, tree, thrift_opt);
+ }
+ if (thrift_opt->use_std_dissector) {
+ proto_tree_add_int(tree, hf_id, tvb, *offset, length, (gint16)varint);
+ }
}
break;
case TCP_THRIFT_MAX_I32_LEN:
@@ -688,12 +748,40 @@ dissect_thrift_varint(tvbuff_t *tvb, packet_info *pinfo, proto_tree *tree, int *
expert_add_info(pinfo, pi, &ei_thrift_varint_too_large);
/* We continue anyway as the varint was indeed decoded. */
} else {
- proto_tree_add_int(tree, hf_id, tvb, *offset, length, (gint32)varint);
+ if (raw_dissector != NULL) {
+ guint8 *data = wmem_alloc(wmem_packet_scope(), TBP_THRIFT_I32_LEN);
+ data[0] = (varint >> 24) & 0xFF;
+ data[1] = (varint >> 16) & 0xFF;
+ data[2] = (varint >> 8) & 0xFF;
+ data[3] = varint & 0xFF;
+ tvbuff_t* sub_tvb = tvb_new_child_real_data(tvb, data, TBP_THRIFT_I32_LEN, TBP_THRIFT_I32_LEN);
+ thrift_opt->use_std_dissector = FALSE;
+ raw_dissector(sub_tvb, pinfo, tree, thrift_opt);
+ }
+ if (thrift_opt->use_std_dissector) {
+ proto_tree_add_int(tree, hf_id, tvb, *offset, length, (gint32)varint);
+ }
}
break;
case TCP_THRIFT_MAX_I64_LEN:
default:
- proto_tree_add_int64(tree, hf_id, tvb, *offset, length, varint);
+ if (raw_dissector != NULL) {
+ guint8 *data = wmem_alloc(wmem_packet_scope(), TBP_THRIFT_I64_LEN);
+ data[0] = (varint >> 56) & 0xFF;
+ data[1] = (varint >> 48) & 0xFF;
+ data[2] = (varint >> 40) & 0xFF;
+ data[3] = (varint >> 32) & 0xFF;
+ data[4] = (varint >> 24) & 0xFF;
+ data[5] = (varint >> 16) & 0xFF;
+ data[6] = (varint >> 8) & 0xFF;
+ data[7] = varint & 0xFF;
+ tvbuff_t* sub_tvb = tvb_new_child_real_data(tvb, data, TBP_THRIFT_I64_LEN, TBP_THRIFT_I64_LEN);
+ thrift_opt->use_std_dissector = FALSE;
+ raw_dissector(sub_tvb, pinfo, tree, thrift_opt);
+ }
+ if (thrift_opt->use_std_dissector) {
+ proto_tree_add_int64(tree, hf_id, tvb, *offset, length, varint);
+ }
break;
}
*offset += length;
@@ -726,10 +814,10 @@ dissect_thrift_string_as_preferred(tvbuff_t *tvb, packet_info *pinfo, proto_tree
proto_tree_add_item(tree, hf_thrift_string, tvb, *offset, str_len, ENC_UTF_16 | ENC_BIG_ENDIAN);
break;
case DECODE_BINARY_AS_UTF8:
- proto_tree_add_item(tree, hf_thrift_string, tvb, *offset, str_len, ENC_UTF_8|ENC_NA);
+ proto_tree_add_item(tree, hf_thrift_string, tvb, *offset, str_len, ENC_UTF_8);
break;
case DECODE_BINARY_AS_ASCII:
- proto_tree_add_item(tree, hf_thrift_string, tvb, *offset, str_len, ENC_ASCII|ENC_NA);
+ proto_tree_add_item(tree, hf_thrift_string, tvb, *offset, str_len, ENC_ASCII);
break;
case DECODE_BINARY_AS_AUTO_UTF8:
/* When there is no data at all, consider it a string
@@ -737,7 +825,7 @@ dissect_thrift_string_as_preferred(tvbuff_t *tvb, packet_info *pinfo, proto_tree
* If not entirely captured, consider it as a binary. */
if (tvb_captured_length_remaining(tvb, *offset) >= str_len &&
(str_len == 0 || thrift_binary_utf8_isprint(tvb, *offset, str_len, TRUE) > 0)) {
- proto_tree_add_item(tree, hf_thrift_string, tvb, *offset, str_len, ENC_UTF_8|ENC_NA);
+ proto_tree_add_item(tree, hf_thrift_string, tvb, *offset, str_len, ENC_UTF_8);
break;
}
/* otherwise, continue with type BINARY */
@@ -784,6 +872,8 @@ compact_struct_type_to_generic_type(thrift_compact_type_enum_t compact)
return DE_THRIFT_T_MAP;
case DE_THRIFT_C_STRUCT:
return DE_THRIFT_T_STRUCT;
+ case DE_THRIFT_C_UUID:
+ return DE_THRIFT_T_UUID;
default:
return DE_THRIFT_T_VOID;
}
@@ -863,7 +953,7 @@ dissect_thrift_t_field_header(tvbuff_t *tvb, packet_info *pinfo, proto_tree *tre
internal_tree = tree;
}
/* Read the entire field header using the dedicated function. */
- if (dissect_thrift_field_header(tvb, pinfo, internal_tree, &offset, thrift_opt, &field_header) == THRIFT_REQUEST_REASSEMBLY) {
+ if (dissect_thrift_field_header(tvb, pinfo, internal_tree, &offset, thrift_opt, &field_header, FALSE) == THRIFT_REQUEST_REASSEMBLY) {
if (offset == THRIFT_REQUEST_REASSEMBLY) {
return THRIFT_REQUEST_REASSEMBLY;
} else {
@@ -888,7 +978,7 @@ dissect_thrift_t_field_header(tvbuff_t *tvb, packet_info *pinfo, proto_tree *tre
/* Once we know it's the expected type (which is /not/ T_STOP), we can read the field id. */
if (field_header.field_id != (gint64)field_id) {
expert_add_info_format(pinfo, field_header.fid_pi, &ei_thrift_wrong_field_id,
- "Sub-dissector expects field id = %d, found %" G_GINT64_MODIFIER "d instead.", field_id, field_header.field_id);
+ "Sub-dissector expects field id = %d, found %" PRId64 " instead.", field_id, field_header.field_id);
}
/* Expose the field header sub-tree if requested. */
@@ -899,17 +989,17 @@ dissect_thrift_t_field_header(tvbuff_t *tvb, packet_info *pinfo, proto_tree *tre
return offset;
}
-int
-dissect_thrift_t_bool(tvbuff_t *tvb, packet_info *pinfo, proto_tree *tree, int offset, thrift_option_data_t *thrift_opt, gboolean is_field, int field_id, gint hf_id)
+static int
+dissect_thrift_raw_bool(tvbuff_t *tvb, packet_info *pinfo, proto_tree *tree, int offset, thrift_option_data_t *thrift_opt, gboolean is_field, int field_id, gint hf_id, dissector_t raw_dissector)
{
int dt_offset = offset;
gboolean bool_val = FALSE;
- proto_item *pi;
/* Get the current state of dissection. */
DISSECTOR_ASSERT(thrift_opt);
DISSECTOR_ASSERT(thrift_opt->canary == THRIFT_OPTION_DATA_CANARY);
ABORT_SUBDISSECTION_ON_ISSUE(offset);
+ thrift_opt->use_std_dissector = TRUE;
if (is_field) {
/* In case of Compact protocol struct field (or command parameter / return value),
* the boolean type also indicates the boolean value. */
@@ -927,9 +1017,17 @@ dissect_thrift_t_bool(tvbuff_t *tvb, packet_info *pinfo, proto_tree *tree, int o
offset = dissect_thrift_t_field_header(tvb, pinfo, tree, offset, thrift_opt, DE_THRIFT_T_BOOL, field_id, NULL);
ABORT_SUBDISSECTION_ON_ISSUE(offset);
if (thrift_opt->tprotocol & PROTO_THRIFT_COMPACT) {
- /* The value must be in the top-level tree, /after/ the field header tree. */
- pi = proto_tree_add_boolean(tree, hf_id, tvb, dt_offset, TBP_THRIFT_TYPE_LEN, bool_val);
- proto_item_set_generated(pi);
+ /* It is the responsibility of the sub-dissector to only use the least significant bit. */
+ if (raw_dissector != NULL) {
+ tvbuff_t* sub_tvb = tvb_new_subset_length(tvb, offset, TBP_THRIFT_BOOL_LEN);
+ thrift_opt->use_std_dissector = FALSE;
+ raw_dissector(sub_tvb, pinfo, tree, thrift_opt);
+ }
+ if (thrift_opt->use_std_dissector) {
+ /* The value must be in the top-level tree, /after/ the field header tree. */
+ proto_item *pi = proto_tree_add_boolean(tree, hf_id, tvb, dt_offset, TBP_THRIFT_TYPE_LEN, bool_val);
+ proto_item_set_generated(pi);
+ }
return offset;
}
}
@@ -938,14 +1036,32 @@ dissect_thrift_t_bool(tvbuff_t *tvb, packet_info *pinfo, proto_tree *tree, int o
}
/* Either in a list/set/map or in a Binary protocol encoding. */
- proto_tree_add_item(tree, hf_id, tvb, offset, TBP_THRIFT_BOOL_LEN, ENC_BIG_ENDIAN);
+ if (raw_dissector != NULL) {
+ tvbuff_t* sub_tvb = tvb_new_subset_length(tvb, offset, TBP_THRIFT_BOOL_LEN);
+ thrift_opt->use_std_dissector = FALSE;
+ raw_dissector(sub_tvb, pinfo, tree, thrift_opt);
+ }
+ if (thrift_opt->use_std_dissector) {
+ proto_tree_add_item(tree, hf_id, tvb, offset, TBP_THRIFT_BOOL_LEN, ENC_BIG_ENDIAN);
+ }
offset += TBP_THRIFT_BOOL_LEN;
+ if (is_field) {
+ thrift_opt->previous_field_id = field_id;
+ }
return offset;
}
int
-dissect_thrift_t_i8(tvbuff_t *tvb, packet_info *pinfo, proto_tree *tree, int offset, thrift_option_data_t *thrift_opt, gboolean is_field, int field_id, gint hf_id)
+dissect_thrift_t_bool(tvbuff_t *tvb, packet_info *pinfo, proto_tree *tree, int offset, thrift_option_data_t *thrift_opt, gboolean is_field, int field_id, gint hf_id)
+{
+ DISSECTOR_ASSERT(thrift_opt);
+ DISSECTOR_ASSERT(thrift_opt->canary == THRIFT_OPTION_DATA_CANARY);
+ return dissect_thrift_raw_bool(tvb, pinfo, tree, offset, thrift_opt, is_field, field_id, hf_id, NULL);
+}
+
+static int
+dissect_thrift_raw_i8(tvbuff_t *tvb, packet_info *pinfo, proto_tree *tree, int offset, thrift_option_data_t *thrift_opt, gboolean is_field, int field_id, gint hf_id, dissector_t raw_dissector)
{
/* Get the current state of dissection. */
DISSECTOR_ASSERT(thrift_opt);
@@ -959,15 +1075,34 @@ dissect_thrift_t_i8(tvbuff_t *tvb, packet_info *pinfo, proto_tree *tree, int off
return THRIFT_REQUEST_REASSEMBLY;
}
+ thrift_opt->use_std_dissector = TRUE;
/* Compact protocol does not use varint for T_I8 as it would be counter-productive. */
- proto_tree_add_item(tree, hf_id, tvb, offset, TBP_THRIFT_I8_LEN, ENC_BIG_ENDIAN);
+ if (raw_dissector != NULL) {
+ tvbuff_t* sub_tvb = tvb_new_subset_length(tvb, offset, TBP_THRIFT_I8_LEN);
+ thrift_opt->use_std_dissector = FALSE;
+ raw_dissector(sub_tvb, pinfo, tree, thrift_opt);
+ }
+ if (thrift_opt->use_std_dissector) {
+ proto_tree_add_item(tree, hf_id, tvb, offset, TBP_THRIFT_I8_LEN, ENC_BIG_ENDIAN);
+ }
offset += TBP_THRIFT_I8_LEN;
+ if (is_field) {
+ thrift_opt->previous_field_id = field_id;
+ }
return offset;
}
int
-dissect_thrift_t_i16(tvbuff_t *tvb, packet_info *pinfo, proto_tree *tree, int offset, thrift_option_data_t *thrift_opt, gboolean is_field, int field_id, gint hf_id)
+dissect_thrift_t_i8(tvbuff_t *tvb, packet_info *pinfo, proto_tree *tree, int offset, thrift_option_data_t *thrift_opt, gboolean is_field, int field_id, gint hf_id)
+{
+ DISSECTOR_ASSERT(thrift_opt);
+ DISSECTOR_ASSERT(thrift_opt->canary == THRIFT_OPTION_DATA_CANARY);
+ return dissect_thrift_raw_i8(tvb, pinfo, tree, offset, thrift_opt, is_field, field_id, hf_id, NULL);
+}
+
+static int
+dissect_thrift_raw_i16(tvbuff_t *tvb, packet_info *pinfo, proto_tree *tree, int offset, thrift_option_data_t *thrift_opt, gboolean is_field, int field_id, gint hf_id, dissector_t raw_dissector)
{
/* Get the current state of dissection. */
DISSECTOR_ASSERT(thrift_opt);
@@ -977,8 +1112,9 @@ dissect_thrift_t_i16(tvbuff_t *tvb, packet_info *pinfo, proto_tree *tree, int of
offset = dissect_thrift_t_field_header(tvb, pinfo, tree, offset, thrift_opt, DE_THRIFT_T_I16, field_id, NULL);
}
ABORT_SUBDISSECTION_ON_ISSUE(offset);
+ thrift_opt->use_std_dissector = TRUE;
if (thrift_opt->tprotocol & PROTO_THRIFT_COMPACT) {
- int result = dissect_thrift_varint(tvb, pinfo, tree, &offset, thrift_opt, TCP_THRIFT_MAX_I16_LEN, hf_id);
+ int result = dissect_thrift_varint(tvb, pinfo, tree, &offset, thrift_opt, TCP_THRIFT_MAX_I16_LEN, hf_id, raw_dissector);
if (result == THRIFT_REQUEST_REASSEMBLY) {
if (offset == THRIFT_REQUEST_REASSEMBLY) {
return THRIFT_REQUEST_REASSEMBLY;
@@ -989,15 +1125,33 @@ dissect_thrift_t_i16(tvbuff_t *tvb, packet_info *pinfo, proto_tree *tree, int of
} else if (tvb_reported_length_remaining(tvb, offset) < TBP_THRIFT_I16_LEN) {
return THRIFT_REQUEST_REASSEMBLY;
} else {
- proto_tree_add_item(tree, hf_id, tvb, offset, TBP_THRIFT_I16_LEN, ENC_BIG_ENDIAN);
- offset += TBP_THRIFT_FID_LEN;
+ if (raw_dissector != NULL) {
+ tvbuff_t* sub_tvb = tvb_new_subset_length(tvb, offset, TBP_THRIFT_I16_LEN);
+ thrift_opt->use_std_dissector = FALSE;
+ raw_dissector(sub_tvb, pinfo, tree, thrift_opt);
+ }
+ if (thrift_opt->use_std_dissector) {
+ proto_tree_add_item(tree, hf_id, tvb, offset, TBP_THRIFT_I16_LEN, ENC_BIG_ENDIAN);
+ }
+ offset += TBP_THRIFT_I16_LEN;
}
+ if (is_field) {
+ thrift_opt->previous_field_id = field_id;
+ }
return offset;
}
int
-dissect_thrift_t_i32(tvbuff_t *tvb, packet_info *pinfo, proto_tree *tree, int offset, thrift_option_data_t *thrift_opt, gboolean is_field, int field_id, gint hf_id)
+dissect_thrift_t_i16(tvbuff_t *tvb, packet_info *pinfo, proto_tree *tree, int offset, thrift_option_data_t *thrift_opt, gboolean is_field, int field_id, gint hf_id)
+{
+ DISSECTOR_ASSERT(thrift_opt);
+ DISSECTOR_ASSERT(thrift_opt->canary == THRIFT_OPTION_DATA_CANARY);
+ return dissect_thrift_raw_i16(tvb, pinfo, tree, offset, thrift_opt, is_field, field_id, hf_id, NULL);
+}
+
+static int
+dissect_thrift_raw_i32(tvbuff_t *tvb, packet_info *pinfo, proto_tree *tree, int offset, thrift_option_data_t *thrift_opt, gboolean is_field, int field_id, gint hf_id, dissector_t raw_dissector)
{
/* Get the current state of dissection. */
DISSECTOR_ASSERT(thrift_opt);
@@ -1007,8 +1161,9 @@ dissect_thrift_t_i32(tvbuff_t *tvb, packet_info *pinfo, proto_tree *tree, int of
offset = dissect_thrift_t_field_header(tvb, pinfo, tree, offset, thrift_opt, DE_THRIFT_T_I32, field_id, NULL);
}
ABORT_SUBDISSECTION_ON_ISSUE(offset);
+ thrift_opt->use_std_dissector = TRUE;
if (thrift_opt->tprotocol & PROTO_THRIFT_COMPACT) {
- int result = dissect_thrift_varint(tvb, pinfo, tree, &offset, thrift_opt, TCP_THRIFT_MAX_I32_LEN, hf_id);
+ int result = dissect_thrift_varint(tvb, pinfo, tree, &offset, thrift_opt, TCP_THRIFT_MAX_I32_LEN, hf_id, raw_dissector);
if (result == THRIFT_REQUEST_REASSEMBLY) {
if (offset == THRIFT_REQUEST_REASSEMBLY) {
return THRIFT_REQUEST_REASSEMBLY;
@@ -1019,15 +1174,33 @@ dissect_thrift_t_i32(tvbuff_t *tvb, packet_info *pinfo, proto_tree *tree, int of
} else if (tvb_reported_length_remaining(tvb, offset) < TBP_THRIFT_I32_LEN) {
return THRIFT_REQUEST_REASSEMBLY;
} else {
- proto_tree_add_item(tree, hf_id, tvb, offset, TBP_THRIFT_I32_LEN, ENC_BIG_ENDIAN);
+ if (raw_dissector != NULL) {
+ tvbuff_t* sub_tvb = tvb_new_subset_length(tvb, offset, TBP_THRIFT_I32_LEN);
+ thrift_opt->use_std_dissector = FALSE;
+ raw_dissector(sub_tvb, pinfo, tree, thrift_opt);
+ }
+ if (thrift_opt->use_std_dissector) {
+ proto_tree_add_item(tree, hf_id, tvb, offset, TBP_THRIFT_I32_LEN, ENC_BIG_ENDIAN);
+ }
offset += TBP_THRIFT_I32_LEN;
}
+ if (is_field) {
+ thrift_opt->previous_field_id = field_id;
+ }
return offset;
}
int
-dissect_thrift_t_i64(tvbuff_t *tvb, packet_info *pinfo, proto_tree *tree, int offset, thrift_option_data_t *thrift_opt, gboolean is_field, int field_id, gint hf_id)
+dissect_thrift_t_i32(tvbuff_t *tvb, packet_info *pinfo, proto_tree *tree, int offset, thrift_option_data_t *thrift_opt, gboolean is_field, int field_id, gint hf_id)
+{
+ DISSECTOR_ASSERT(thrift_opt);
+ DISSECTOR_ASSERT(thrift_opt->canary == THRIFT_OPTION_DATA_CANARY);
+ return dissect_thrift_raw_i32(tvb, pinfo, tree, offset, thrift_opt, is_field, field_id, hf_id, NULL);
+}
+
+static int
+dissect_thrift_raw_i64(tvbuff_t *tvb, packet_info *pinfo, proto_tree *tree, int offset, thrift_option_data_t *thrift_opt, gboolean is_field, int field_id, gint hf_id, dissector_t raw_dissector)
{
/* Get the current state of dissection. */
DISSECTOR_ASSERT(thrift_opt);
@@ -1037,8 +1210,9 @@ dissect_thrift_t_i64(tvbuff_t *tvb, packet_info *pinfo, proto_tree *tree, int of
offset = dissect_thrift_t_field_header(tvb, pinfo, tree, offset, thrift_opt, DE_THRIFT_T_I64, field_id, NULL);
}
ABORT_SUBDISSECTION_ON_ISSUE(offset);
+ thrift_opt->use_std_dissector = TRUE;
if (thrift_opt->tprotocol & PROTO_THRIFT_COMPACT) {
- int result = dissect_thrift_varint(tvb, pinfo, tree, &offset, thrift_opt, TCP_THRIFT_MAX_I64_LEN, hf_id);
+ int result = dissect_thrift_varint(tvb, pinfo, tree, &offset, thrift_opt, TCP_THRIFT_MAX_I64_LEN, hf_id, raw_dissector);
if (result == THRIFT_REQUEST_REASSEMBLY) {
if (offset == THRIFT_REQUEST_REASSEMBLY) {
return THRIFT_REQUEST_REASSEMBLY;
@@ -1049,15 +1223,33 @@ dissect_thrift_t_i64(tvbuff_t *tvb, packet_info *pinfo, proto_tree *tree, int of
} else if (tvb_reported_length_remaining(tvb, offset) < TBP_THRIFT_I64_LEN) {
return THRIFT_REQUEST_REASSEMBLY;
} else {
- proto_tree_add_item(tree, hf_id, tvb, offset, TBP_THRIFT_I64_LEN, ENC_BIG_ENDIAN);
+ if (raw_dissector != NULL) {
+ tvbuff_t* sub_tvb = tvb_new_subset_length(tvb, offset, TBP_THRIFT_I64_LEN);
+ thrift_opt->use_std_dissector = FALSE;
+ raw_dissector(sub_tvb, pinfo, tree, thrift_opt);
+ }
+ if (thrift_opt->use_std_dissector) {
+ proto_tree_add_item(tree, hf_id, tvb, offset, TBP_THRIFT_I64_LEN, ENC_BIG_ENDIAN);
+ }
offset += TBP_THRIFT_I64_LEN;
}
+ if (is_field) {
+ thrift_opt->previous_field_id = field_id;
+ }
return offset;
}
int
-dissect_thrift_t_double(tvbuff_t *tvb, packet_info *pinfo, proto_tree *tree, int offset, thrift_option_data_t *thrift_opt, gboolean is_field, int field_id, gint hf_id)
+dissect_thrift_t_i64(tvbuff_t *tvb, packet_info *pinfo, proto_tree *tree, int offset, thrift_option_data_t *thrift_opt, gboolean is_field, int field_id, gint hf_id)
+{
+ DISSECTOR_ASSERT(thrift_opt);
+ DISSECTOR_ASSERT(thrift_opt->canary == THRIFT_OPTION_DATA_CANARY);
+ return dissect_thrift_raw_i64(tvb, pinfo, tree, offset, thrift_opt, is_field, field_id, hf_id, NULL);
+}
+
+static int
+dissect_thrift_raw_double(tvbuff_t *tvb, packet_info *pinfo, proto_tree *tree, int offset, thrift_option_data_t *thrift_opt, gboolean is_field, int field_id, gint hf_id, dissector_t raw_dissector)
{
/* Get the current state of dissection. */
DISSECTOR_ASSERT(thrift_opt);
@@ -1071,30 +1263,94 @@ dissect_thrift_t_double(tvbuff_t *tvb, packet_info *pinfo, proto_tree *tree, int
return THRIFT_REQUEST_REASSEMBLY;
}
- if (thrift_opt->tprotocol & PROTO_THRIFT_COMPACT) {
- proto_tree_add_item(tree, hf_id, tvb, offset, TBP_THRIFT_DOUBLE_LEN, ENC_LITTLE_ENDIAN);
- } else {
- proto_tree_add_item(tree, hf_id, tvb, offset, TBP_THRIFT_DOUBLE_LEN, ENC_BIG_ENDIAN);
+ thrift_opt->use_std_dissector = TRUE;
+ if (raw_dissector != NULL) {
+ tvbuff_t* sub_tvb;
+ if (thrift_opt->tprotocol & PROTO_THRIFT_COMPACT) {
+ /* Create a sub-tvbuff_t in big endian format as documented. */
+ guint8 *data = wmem_alloc(wmem_packet_scope(), TBP_THRIFT_DOUBLE_LEN);
+ data[0] = tvb_get_guint8(tvb, offset + 7);
+ data[1] = tvb_get_guint8(tvb, offset + 6);
+ data[2] = tvb_get_guint8(tvb, offset + 5);
+ data[3] = tvb_get_guint8(tvb, offset + 4);
+ data[4] = tvb_get_guint8(tvb, offset + 3);
+ data[5] = tvb_get_guint8(tvb, offset + 2);
+ data[6] = tvb_get_guint8(tvb, offset + 1);
+ data[7] = tvb_get_guint8(tvb, offset);
+ sub_tvb = tvb_new_child_real_data(tvb, data, TBP_THRIFT_DOUBLE_LEN, TBP_THRIFT_DOUBLE_LEN);
+ } else {
+ sub_tvb = tvb_new_subset_length(tvb, offset, TBP_THRIFT_DOUBLE_LEN);
+ }
+ thrift_opt->use_std_dissector = FALSE;
+ raw_dissector(sub_tvb, pinfo, tree, thrift_opt);
+ }
+ if (thrift_opt->use_std_dissector) {
+ if (thrift_opt->tprotocol & PROTO_THRIFT_COMPACT) {
+ proto_tree_add_item(tree, hf_id, tvb, offset, TBP_THRIFT_DOUBLE_LEN, ENC_LITTLE_ENDIAN);
+ } else {
+ proto_tree_add_item(tree, hf_id, tvb, offset, TBP_THRIFT_DOUBLE_LEN, ENC_BIG_ENDIAN);
+ }
}
offset += TBP_THRIFT_DOUBLE_LEN;
+ if (is_field) {
+ thrift_opt->previous_field_id = field_id;
+ }
return offset;
}
int
-dissect_thrift_t_binary(tvbuff_t *tvb, packet_info *pinfo, proto_tree *tree, int offset, thrift_option_data_t *thrift_opt, gboolean is_field, int field_id, gint hf_id)
+dissect_thrift_t_double(tvbuff_t *tvb, packet_info *pinfo, proto_tree *tree, int offset, thrift_option_data_t *thrift_opt, gboolean is_field, int field_id, gint hf_id)
{
- return dissect_thrift_t_string_enc(tvb, pinfo, tree, offset, thrift_opt, is_field, field_id, hf_id, ENC_NA);
+ DISSECTOR_ASSERT(thrift_opt);
+ DISSECTOR_ASSERT(thrift_opt->canary == THRIFT_OPTION_DATA_CANARY);
+ return dissect_thrift_raw_double(tvb, pinfo, tree, offset, thrift_opt, is_field, field_id, hf_id, NULL);
}
-int
-dissect_thrift_t_string(tvbuff_t *tvb, packet_info *pinfo, proto_tree *tree, int offset, thrift_option_data_t *thrift_opt, gboolean is_field, int field_id, gint hf_id)
+static int
+dissect_thrift_raw_uuid(tvbuff_t *tvb, packet_info *pinfo, proto_tree *tree, int offset, thrift_option_data_t *thrift_opt, gboolean is_field, int field_id, gint hf_id, dissector_t raw_dissector)
{
- return dissect_thrift_t_string_enc(tvb, pinfo, tree, offset, thrift_opt, is_field, field_id, hf_id, ENC_UTF_8|ENC_NA);
+ /* Get the current state of dissection. */
+ DISSECTOR_ASSERT(thrift_opt);
+ DISSECTOR_ASSERT(thrift_opt->canary == THRIFT_OPTION_DATA_CANARY);
+
+ /* Dissect field header if necessary. */
+ if (is_field) {
+ offset = dissect_thrift_t_field_header(tvb, pinfo, tree, offset, thrift_opt, DE_THRIFT_T_UUID, field_id, NULL);
+ }
+ ABORT_SUBDISSECTION_ON_ISSUE(offset);
+
+ if (tvb_reported_length_remaining(tvb, offset) < TBP_THRIFT_UUID_LEN) {
+ return THRIFT_REQUEST_REASSEMBLY;
+ }
+
+ thrift_opt->use_std_dissector = TRUE;
+ if (raw_dissector != NULL) {
+ tvbuff_t* sub_tvb = tvb_new_subset_length(tvb, offset, TBP_THRIFT_UUID_LEN);
+ thrift_opt->use_std_dissector = FALSE;
+ raw_dissector(sub_tvb, pinfo, tree, thrift_opt);
+ }
+ if (thrift_opt->use_std_dissector) {
+ proto_tree_add_item(tree, hf_id, tvb, offset, TBP_THRIFT_UUID_LEN, ENC_BIG_ENDIAN);
+ }
+ offset += TBP_THRIFT_UUID_LEN;
+
+ if (is_field) {
+ thrift_opt->previous_field_id = field_id;
+ }
+ return offset;
}
int
-dissect_thrift_t_string_enc(tvbuff_t *tvb, packet_info *pinfo, proto_tree *tree, int offset, thrift_option_data_t *thrift_opt, gboolean is_field, int field_id, gint hf_id, guint encoding)
+dissect_thrift_t_uuid(tvbuff_t *tvb, packet_info *pinfo, proto_tree *tree, int offset, thrift_option_data_t *thrift_opt, gboolean is_field, int field_id, gint hf_id)
+{
+ DISSECTOR_ASSERT(thrift_opt);
+ DISSECTOR_ASSERT(thrift_opt->canary == THRIFT_OPTION_DATA_CANARY);
+ return dissect_thrift_raw_uuid(tvb, pinfo, tree, offset, thrift_opt, is_field, field_id, hf_id, NULL);
+}
+
+static int
+dissect_thrift_raw_binary(tvbuff_t *tvb, packet_info *pinfo, proto_tree *tree, int offset, thrift_option_data_t *thrift_opt, gboolean is_field, int field_id, gint hf_id, guint encoding, dissector_t raw_dissector)
{
/* Get the current state of dissection. */
DISSECTOR_ASSERT(thrift_opt);
@@ -1159,14 +1415,89 @@ dissect_thrift_t_string_enc(tvbuff_t *tvb, packet_info *pinfo, proto_tree *tree,
return THRIFT_REQUEST_REASSEMBLY;
}
- proto_tree_add_item(tree, hf_id, tvb, offset, str_len, encoding);
+ thrift_opt->use_std_dissector = TRUE;
+ if (raw_dissector != NULL) {
+ tvbuff_t* sub_tvb = tvb_new_subset_length(tvb, offset, str_len);
+ thrift_opt->use_std_dissector = FALSE;
+ raw_dissector(sub_tvb, pinfo, tree, thrift_opt);
+ }
+ if (thrift_opt->use_std_dissector) {
+ proto_tree_add_item(tree, hf_id, tvb, offset, str_len, encoding);
+ }
offset = offset + str_len;
+ if (is_field) {
+ thrift_opt->previous_field_id = field_id;
+ }
+ return offset;
+}
+
+int
+dissect_thrift_t_binary(tvbuff_t *tvb, packet_info *pinfo, proto_tree *tree, int offset, thrift_option_data_t *thrift_opt, gboolean is_field, int field_id, gint hf_id)
+{
+ DISSECTOR_ASSERT(thrift_opt);
+ DISSECTOR_ASSERT(thrift_opt->canary == THRIFT_OPTION_DATA_CANARY);
+ return dissect_thrift_raw_binary(tvb, pinfo, tree, offset, thrift_opt, is_field, field_id, hf_id, ENC_NA, NULL);
+}
+
+int
+dissect_thrift_t_string(tvbuff_t *tvb, packet_info *pinfo, proto_tree *tree, int offset, thrift_option_data_t *thrift_opt, gboolean is_field, int field_id, gint hf_id)
+{
+ DISSECTOR_ASSERT(thrift_opt);
+ DISSECTOR_ASSERT(thrift_opt->canary == THRIFT_OPTION_DATA_CANARY);
+ return dissect_thrift_raw_binary(tvb, pinfo, tree, offset, thrift_opt, is_field, field_id, hf_id, ENC_UTF_8, NULL);
+}
+
+int
+dissect_thrift_t_string_enc(tvbuff_t *tvb, packet_info *pinfo, proto_tree *tree, int offset, thrift_option_data_t *thrift_opt, gboolean is_field, int field_id, gint hf_id, guint encoding)
+{
+ DISSECTOR_ASSERT(thrift_opt);
+ DISSECTOR_ASSERT(thrift_opt->canary == THRIFT_OPTION_DATA_CANARY);
+ return dissect_thrift_raw_binary(tvb, pinfo, tree, offset, thrift_opt, is_field, field_id, hf_id, encoding, NULL);
+}
+
+int
+dissect_thrift_t_raw_data(tvbuff_t* tvb, packet_info* pinfo, proto_tree* tree, int offset, thrift_option_data_t* thrift_opt, gboolean is_field, int field_id, gint hf_id, thrift_type_enum_t type, dissector_t raw_dissector)
+{
+ /* Get the current state of dissection. */
+ DISSECTOR_ASSERT(thrift_opt);
+ DISSECTOR_ASSERT(thrift_opt->canary == THRIFT_OPTION_DATA_CANARY);
+
+ switch (type) {
+ case DE_THRIFT_T_BOOL:
+ offset = dissect_thrift_raw_bool(tvb, pinfo, tree, offset, thrift_opt, is_field, field_id, hf_id, raw_dissector);
+ break;
+ case DE_THRIFT_T_I8:
+ offset = dissect_thrift_raw_i8(tvb, pinfo, tree, offset, thrift_opt, is_field, field_id, hf_id, raw_dissector);
+ break;
+ case DE_THRIFT_T_I16:
+ offset = dissect_thrift_raw_i16(tvb, pinfo, tree, offset, thrift_opt, is_field, field_id, hf_id, raw_dissector);
+ break;
+ case DE_THRIFT_T_I32:
+ offset = dissect_thrift_raw_i32(tvb, pinfo, tree, offset, thrift_opt, is_field, field_id, hf_id, raw_dissector);
+ break;
+ case DE_THRIFT_T_I64:
+ offset = dissect_thrift_raw_i64(tvb, pinfo, tree, offset, thrift_opt, is_field, field_id, hf_id, raw_dissector);
+ break;
+ case DE_THRIFT_T_DOUBLE:
+ offset = dissect_thrift_raw_double(tvb, pinfo, tree, offset, thrift_opt, is_field, field_id, hf_id, raw_dissector);
+ break;
+ case DE_THRIFT_T_BINARY:
+ offset = dissect_thrift_raw_binary(tvb, pinfo, tree, offset, thrift_opt, is_field, field_id, hf_id, ENC_NA, raw_dissector);
+ break;
+ case DE_THRIFT_T_UUID:
+ offset = dissect_thrift_raw_uuid(tvb, pinfo, tree, offset, thrift_opt, is_field, field_id, hf_id, raw_dissector);
+ break;
+ default:
+ REPORT_DISSECTOR_BUG("Only simple data types support raw dissection.");
+ break;
+ }
return offset;
}
/* Simple dispatch function for lists, sets, maps, and structs internal elements to avoid code duplication. */
static int
+// NOLINTNEXTLINE(misc-no-recursion)
dissect_thrift_t_member(tvbuff_t *tvb, packet_info *pinfo, proto_tree *tree, int offset, thrift_option_data_t *thrift_opt, gboolean is_field, const thrift_member_t *elt)
{
switch (elt->type) {
@@ -1174,25 +1505,25 @@ dissect_thrift_t_member(tvbuff_t *tvb, packet_info *pinfo, proto_tree *tree, int
offset = dissect_thrift_t_stop(tvb, pinfo, tree, offset);
break;
case DE_THRIFT_T_BOOL:
- offset = dissect_thrift_t_bool(tvb, pinfo, tree, offset, thrift_opt, is_field, elt->fid, *elt->p_hf_id);
+ offset = dissect_thrift_raw_bool(tvb, pinfo, tree, offset, thrift_opt, is_field, elt->fid, *elt->p_hf_id, elt->raw_dissector);
break;
case DE_THRIFT_T_I8:
- offset = dissect_thrift_t_i8(tvb, pinfo, tree, offset, thrift_opt, is_field, elt->fid, *elt->p_hf_id);
+ offset = dissect_thrift_raw_i8(tvb, pinfo, tree, offset, thrift_opt, is_field, elt->fid, *elt->p_hf_id, elt->raw_dissector);
break;
case DE_THRIFT_T_I16:
- offset = dissect_thrift_t_i16(tvb, pinfo, tree, offset, thrift_opt, is_field, elt->fid, *elt->p_hf_id);
+ offset = dissect_thrift_raw_i16(tvb, pinfo, tree, offset, thrift_opt, is_field, elt->fid, *elt->p_hf_id, elt->raw_dissector);
break;
case DE_THRIFT_T_I32:
- offset = dissect_thrift_t_i32(tvb, pinfo, tree, offset, thrift_opt, is_field, elt->fid, *elt->p_hf_id);
+ offset = dissect_thrift_raw_i32(tvb, pinfo, tree, offset, thrift_opt, is_field, elt->fid, *elt->p_hf_id, elt->raw_dissector);
break;
case DE_THRIFT_T_I64:
- offset = dissect_thrift_t_i64(tvb, pinfo, tree, offset, thrift_opt, is_field, elt->fid, *elt->p_hf_id);
+ offset = dissect_thrift_raw_i64(tvb, pinfo, tree, offset, thrift_opt, is_field, elt->fid, *elt->p_hf_id, elt->raw_dissector);
break;
case DE_THRIFT_T_DOUBLE:
- offset = dissect_thrift_t_double(tvb, pinfo, tree, offset, thrift_opt, is_field, elt->fid, *elt->p_hf_id);
+ offset = dissect_thrift_raw_double(tvb, pinfo, tree, offset, thrift_opt, is_field, elt->fid, *elt->p_hf_id, elt->raw_dissector);
break;
case DE_THRIFT_T_BINARY:
- offset = dissect_thrift_t_string(tvb, pinfo, tree, offset, thrift_opt, is_field, elt->fid, *elt->p_hf_id);
+ offset = dissect_thrift_raw_binary(tvb, pinfo, tree, offset, thrift_opt, is_field, elt->fid, *elt->p_hf_id, elt->u.encoding, elt->raw_dissector);
break;
case DE_THRIFT_T_LIST:
offset = dissect_thrift_t_list(tvb, pinfo, tree, offset, thrift_opt, is_field, elt->fid, *elt->p_hf_id, *elt->p_ett_id, elt->u.element);
@@ -1204,7 +1535,10 @@ dissect_thrift_t_member(tvbuff_t *tvb, packet_info *pinfo, proto_tree *tree, int
offset = dissect_thrift_t_map(tvb, pinfo, tree, offset, thrift_opt, is_field, elt->fid, *elt->p_hf_id, *elt->p_ett_id, elt->u.m.key, elt->u.m.value);
break;
case DE_THRIFT_T_STRUCT:
- offset = dissect_thrift_t_struct(tvb, pinfo, tree, offset, thrift_opt, is_field, elt->fid, *elt->p_hf_id, *elt->p_ett_id, elt->u.members);
+ offset = dissect_thrift_t_struct_expert(tvb, pinfo, tree, offset, thrift_opt, is_field, elt->fid, *elt->p_hf_id, *elt->p_ett_id, elt->u.s.members, elt->u.s.expert_info);
+ break;
+ case DE_THRIFT_T_UUID:
+ offset = dissect_thrift_raw_uuid(tvb, pinfo, tree, offset, thrift_opt, is_field, elt->fid, *elt->p_hf_id, elt->raw_dissector);
break;
default:
REPORT_DISSECTOR_BUG("Unexpected Thrift type dissection requested.");
@@ -1220,6 +1554,7 @@ dissect_thrift_t_member(tvbuff_t *tvb, packet_info *pinfo, proto_tree *tree, int
* so it's easy to use the same code and handle the additional elements only when necessary.
*/
static int
+// NOLINTNEXTLINE(misc-no-recursion)
dissect_thrift_b_linear(tvbuff_t *tvb, packet_info *pinfo, proto_tree *tree, int offset, thrift_option_data_t *thrift_opt, gboolean is_field, int field_id, gint hf_id, gint ett_id, const thrift_member_t *key, const thrift_member_t *val, thrift_type_enum_t expected)
{
proto_item *container_pi = NULL;
@@ -1227,6 +1562,7 @@ dissect_thrift_b_linear(tvbuff_t *tvb, packet_info *pinfo, proto_tree *tree, int
proto_tree *sub_tree;
gint32 key_type, val_type;
gint32 length;
+ guint nested_count = p_get_proto_depth(pinfo, proto_thrift);
/* Get the current state of dissection. */
DISSECTOR_ASSERT(thrift_opt);
@@ -1239,6 +1575,11 @@ dissect_thrift_b_linear(tvbuff_t *tvb, packet_info *pinfo, proto_tree *tree, int
}
/* Create the sub-tree. */
+ if (nested_count >= thrift_opt->nested_type_depth) {
+ expert_add_info(pinfo, proto_tree_get_parent(tree), &ei_thrift_too_many_subtypes);
+ return THRIFT_REQUEST_REASSEMBLY;
+ }
+ p_set_proto_depth(pinfo, proto_thrift, nested_count + 1);
container_pi = proto_tree_add_item(tree, hf_id, tvb, offset, -1, ENC_BIG_ENDIAN);
sub_tree = proto_item_add_subtree(container_pi, ett_id);
ABORT_SUBDISSECTION_ON_ISSUE(offset);
@@ -1313,6 +1654,7 @@ dissect_thrift_b_linear(tvbuff_t *tvb, packet_info *pinfo, proto_tree *tree, int
if (container_pi && offset > 0) {
proto_item_set_end(container_pi, tvb, offset);
}
+ p_set_proto_depth(pinfo, proto_thrift, nested_count);
return offset;
}
@@ -1321,6 +1663,7 @@ dissect_thrift_b_linear(tvbuff_t *tvb, packet_info *pinfo, proto_tree *tree, int
* this prevents code duplication.
*/
static int
+// NOLINTNEXTLINE(misc-no-recursion)
dissect_thrift_c_list_set(tvbuff_t *tvb, packet_info *pinfo, proto_tree *tree, int offset, thrift_option_data_t *thrift_opt, gboolean is_field, int field_id, gint hf_id, gint ett_id, const thrift_member_t *elt, gboolean is_list)
{
proto_item *container_pi;
@@ -1333,10 +1676,13 @@ dissect_thrift_c_list_set(tvbuff_t *tvb, packet_info *pinfo, proto_tree *tree, i
guint64 varint;
int lt_offset;
int hf_num_item = hf_thrift_num_set_item;
+ int hf_pos_item = hf_thrift_num_set_pos;
thrift_type_enum_t expected = DE_THRIFT_T_SET;
+ guint nested_count = p_get_proto_depth(pinfo, proto_thrift);
if (is_list) {
hf_num_item = hf_thrift_num_list_item;
+ hf_pos_item = hf_thrift_num_list_pos;
expected = DE_THRIFT_T_LIST;
}
@@ -1355,6 +1701,11 @@ dissect_thrift_c_list_set(tvbuff_t *tvb, packet_info *pinfo, proto_tree *tree, i
}
/* Create the sub-tree. */
+ if (nested_count >= thrift_opt->nested_type_depth) {
+ expert_add_info(pinfo, proto_tree_get_parent(tree), &ei_thrift_too_many_subtypes);
+ return THRIFT_REQUEST_REASSEMBLY;
+ }
+ p_set_proto_depth(pinfo, proto_thrift, nested_count + 1);
container_pi = proto_tree_add_item(tree, hf_id, tvb, offset, -1, ENC_BIG_ENDIAN);
sub_tree = proto_item_add_subtree(container_pi, ett_id);
@@ -1403,7 +1754,7 @@ dissect_thrift_c_list_set(tvbuff_t *tvb, packet_info *pinfo, proto_tree *tree, i
break;
}
} else if (show_internal_thrift_fields) {
- proto_tree_add_bits_item(sub_tree, hf_num_item, tvb, (lt_offset << OCTETS_TO_BITS_SHIFT), TCP_THRIFT_NIBBLE_SHIFT, ENC_BIG_ENDIAN);
+ proto_tree_add_bits_item(sub_tree, hf_pos_item, tvb, (lt_offset << OCTETS_TO_BITS_SHIFT), TCP_THRIFT_NIBBLE_SHIFT, ENC_BIG_ENDIAN);
}
/* Read the content of the container. */
@@ -1415,47 +1766,65 @@ dissect_thrift_c_list_set(tvbuff_t *tvb, packet_info *pinfo, proto_tree *tree, i
if (container_pi && offset > 0) {
proto_item_set_end(container_pi, tvb, offset);
}
+ p_set_proto_depth(pinfo, proto_thrift, nested_count);
return offset;
}
int
+// NOLINTNEXTLINE(misc-no-recursion)
dissect_thrift_t_list(tvbuff_t *tvb, packet_info *pinfo, proto_tree *tree, int offset, thrift_option_data_t *thrift_opt, gboolean is_field, int field_id, gint hf_id, gint ett_id, const thrift_member_t *elt)
{
+ int result;
if (thrift_opt->tprotocol & PROTO_THRIFT_COMPACT) {
- return dissect_thrift_c_list_set(tvb, pinfo, tree, offset, thrift_opt, is_field, field_id, hf_id, ett_id, elt, TRUE);
+ result = dissect_thrift_c_list_set(tvb, pinfo, tree, offset, thrift_opt, is_field, field_id, hf_id, ett_id, elt, TRUE);
} else {
- return dissect_thrift_b_linear(tvb, pinfo, tree, offset, thrift_opt, is_field, field_id, hf_id, ett_id, NULL, elt, DE_THRIFT_T_LIST);
+ result = dissect_thrift_b_linear(tvb, pinfo, tree, offset, thrift_opt, is_field, field_id, hf_id, ett_id, NULL, elt, DE_THRIFT_T_LIST);
}
+
+ if (is_field) {
+ thrift_opt->previous_field_id = field_id;
+ }
+ return result;
}
int
+// NOLINTNEXTLINE(misc-no-recursion)
dissect_thrift_t_set(tvbuff_t *tvb, packet_info *pinfo, proto_tree *tree, int offset, thrift_option_data_t *thrift_opt, gboolean is_field, int field_id, gint hf_id, gint ett_id, const thrift_member_t *elt)
{
+ int result;
if (thrift_opt->tprotocol & PROTO_THRIFT_COMPACT) {
- return dissect_thrift_c_list_set(tvb, pinfo, tree, offset, thrift_opt, is_field, field_id, hf_id, ett_id, elt, FALSE);
+ result = dissect_thrift_c_list_set(tvb, pinfo, tree, offset, thrift_opt, is_field, field_id, hf_id, ett_id, elt, FALSE);
} else {
- return dissect_thrift_b_linear(tvb, pinfo, tree, offset, thrift_opt, is_field, field_id, hf_id, ett_id, NULL, elt, DE_THRIFT_T_SET);
+ result = dissect_thrift_b_linear(tvb, pinfo, tree, offset, thrift_opt, is_field, field_id, hf_id, ett_id, NULL, elt, DE_THRIFT_T_SET);
+ }
+
+ if (is_field) {
+ thrift_opt->previous_field_id = field_id;
}
+ return result;
}
int
+// NOLINTNEXTLINE(misc-no-recursion)
dissect_thrift_t_map(tvbuff_t *tvb, packet_info *pinfo, proto_tree *tree, int offset, thrift_option_data_t *thrift_opt, gboolean is_field, int field_id, gint hf_id, gint ett_id, const thrift_member_t *key, const thrift_member_t *value)
{
+ int result;
/* Get the current state of dissection. */
DISSECTOR_ASSERT(thrift_opt);
DISSECTOR_ASSERT(thrift_opt->canary == THRIFT_OPTION_DATA_CANARY);
if ((thrift_opt->tprotocol & PROTO_THRIFT_COMPACT) == 0) {
- return dissect_thrift_b_linear(tvb, pinfo, tree, offset, thrift_opt, is_field, field_id, hf_id, ett_id, key, value, DE_THRIFT_T_MAP);
+ result = dissect_thrift_b_linear(tvb, pinfo, tree, offset, thrift_opt, is_field, field_id, hf_id, ett_id, key, value, DE_THRIFT_T_MAP);
} else {
proto_tree *sub_tree = NULL;
- proto_item *container_pi, *len_pi;
+ proto_item *container_pi;
proto_item *ktype_pi = NULL;
proto_item *vtype_pi = NULL;
gint32 container_len, len_len, i, types;
gint32 len_offset = offset;
thrift_compact_type_enum_t ktype, vtype;
guint64 varint;
+ guint nested_count = p_get_proto_depth(pinfo, proto_thrift);
/* Dissect field header if necessary. */
if (is_field) {
@@ -1478,7 +1847,7 @@ dissect_thrift_t_map(tvbuff_t *tvb, packet_info *pinfo, proto_tree *tree, int of
return THRIFT_SUBDISSECTOR_ERROR;
default:
if (varint > (guint64)INT32_MAX) {
- len_pi = proto_tree_add_int64(sub_tree, hf_thrift_i64, tvb, offset, len_len, varint);
+ proto_item *len_pi = proto_tree_add_int64(sub_tree, hf_thrift_i64, tvb, offset, len_len, varint);
expert_add_info(pinfo, len_pi, &ei_thrift_varint_too_large);
return THRIFT_SUBDISSECTOR_ERROR;
}
@@ -1488,12 +1857,18 @@ dissect_thrift_t_map(tvbuff_t *tvb, packet_info *pinfo, proto_tree *tree, int of
}
/* Create the sub-tree. */
+ if (nested_count >= thrift_opt->nested_type_depth) {
+ expert_add_info(pinfo, proto_tree_get_parent(tree), &ei_thrift_too_many_subtypes);
+ return THRIFT_REQUEST_REASSEMBLY;
+ }
+ p_set_proto_depth(pinfo, proto_thrift, nested_count + 1);
container_pi = proto_tree_add_item(tree, hf_id, tvb, len_offset, -1, ENC_BIG_ENDIAN);
sub_tree = proto_item_add_subtree(container_pi, ett_id);
if (container_len == 0) {
proto_item_set_end(container_pi, tvb, offset);
proto_item_append_text(container_pi, " (Empty)");
+ p_set_proto_depth(pinfo, proto_thrift, nested_count);
return offset;
}
@@ -1539,18 +1914,32 @@ dissect_thrift_t_map(tvbuff_t *tvb, packet_info *pinfo, proto_tree *tree, int of
if (container_pi && offset > 0) {
proto_item_set_end(container_pi, tvb, offset);
}
- return offset;
+ result = offset;
+ p_set_proto_depth(pinfo, proto_thrift, nested_count);
}
+
+ if (is_field) {
+ thrift_opt->previous_field_id = field_id;
+ }
+ return result;
}
int
dissect_thrift_t_struct(tvbuff_t *tvb, packet_info *pinfo, proto_tree *tree, int offset, thrift_option_data_t *thrift_opt, gboolean is_field, int field_id, gint hf_id, gint ett_id, const thrift_member_t *seq)
{
+ return dissect_thrift_t_struct_expert(tvb, pinfo, tree, offset, thrift_opt, is_field, field_id, hf_id, ett_id, seq, NULL);
+}
+
+static int
+// NOLINTNEXTLINE(misc-no-recursion)
+dissect_thrift_t_struct_expert(tvbuff_t *tvb, packet_info *pinfo, proto_tree *tree, int offset, thrift_option_data_t *thrift_opt, gboolean is_field, int field_id, gint hf_id, gint ett_id, const thrift_member_t *seq, expert_field* ei)
+{
thrift_field_header_t field_header;
proto_tree *sub_tree = NULL;
proto_item *type_pi = NULL;
gboolean enable_subtree = (ett_id != DISABLE_SUBTREE) || (hf_id != DISABLE_SUBTREE);
+ guint nested_count = p_get_proto_depth(pinfo, proto_thrift);
/* Get the current state of dissection. */
DISSECTOR_ASSERT(thrift_opt);
@@ -1571,6 +1960,11 @@ dissect_thrift_t_struct(tvbuff_t *tvb, packet_info *pinfo, proto_tree *tree, int
/* Create the sub-tree, if not explicitly refused. */
if (enable_subtree) {
/* Add the struct to the tree. */
+ if (nested_count >= thrift_opt->nested_type_depth) {
+ expert_add_info(pinfo, proto_tree_get_parent(tree), &ei_thrift_too_many_subtypes);
+ return THRIFT_REQUEST_REASSEMBLY;
+ }
+ p_set_proto_depth(pinfo, proto_thrift, nested_count--);
type_pi = proto_tree_add_item(tree, hf_id, tvb, offset, -1, ENC_BIG_ENDIAN);
sub_tree = proto_item_add_subtree(type_pi, ett_id);
} else {
@@ -1587,7 +1981,7 @@ dissect_thrift_t_struct(tvbuff_t *tvb, packet_info *pinfo, proto_tree *tree, int
* Never create the field header sub-tree here as it will be handled by the field's own dissector.
* We only want to get the type & field id information to compare them against what we expect.
*/
- if (dissect_thrift_field_header(tvb, pinfo, NULL, &local_offset, thrift_opt, &field_header) == THRIFT_REQUEST_REASSEMBLY) {
+ if (dissect_thrift_field_header(tvb, pinfo, NULL, &local_offset, thrift_opt, &field_header, FALSE) == THRIFT_REQUEST_REASSEMBLY) {
if (local_offset == THRIFT_REQUEST_REASSEMBLY) {
return THRIFT_REQUEST_REASSEMBLY;
} else {
@@ -1625,15 +2019,16 @@ dissect_thrift_t_struct(tvbuff_t *tvb, packet_info *pinfo, proto_tree *tree, int
/* The field is not defined in the struct, switch back to generic dissection.
* Re-read the header ensuring it is displayed (no need to check result,
* we already dissected it but without the header tree creation. */
- dissect_thrift_field_header(tvb, pinfo, sub_tree, &offset, thrift_opt, &field_header);
+ dissect_thrift_field_header(tvb, pinfo, sub_tree, &offset, thrift_opt, &field_header, FALSE);
expert_add_info(pinfo, field_header.fid_pi, &ei_thrift_undefined_field_id);
// Then dissect just this field.
if (thrift_opt->tprotocol & PROTO_THRIFT_COMPACT) {
- if (dissect_thrift_compact_type(tvb, pinfo, sub_tree, &offset, thrift_opt, field_header.fh_tree, field_header.type.compact, field_header.type_pi) == THRIFT_REQUEST_REASSEMBLY) {
+ if (!is_thrift_compact_bool_type(field_header.type.compact) &&
+ dissect_thrift_compact_type(tvb, pinfo, sub_tree, &offset, thrift_opt, field_header.fh_tree, field_header.type.compact, field_header.type_pi) == THRIFT_REQUEST_REASSEMBLY) {
return THRIFT_REQUEST_REASSEMBLY;
}
} else {
- if (dissect_thrift_binary_type(tvb, pinfo, sub_tree, &offset, thrift_opt, field_header.fh_tree, field_header.type.compact, field_header.type_pi) == THRIFT_REQUEST_REASSEMBLY) {
+ if (dissect_thrift_binary_type(tvb, pinfo, sub_tree, &offset, thrift_opt, field_header.fh_tree, field_header.type.binary, field_header.type_pi) == THRIFT_REQUEST_REASSEMBLY) {
return THRIFT_REQUEST_REASSEMBLY;
}
}
@@ -1651,10 +2046,19 @@ dissect_thrift_t_struct(tvbuff_t *tvb, packet_info *pinfo, proto_tree *tree, int
/* The loop exits before dissecting the T_STOP. */
offset = dissect_thrift_t_stop(tvb, pinfo, sub_tree, offset);
+ /* Set expert info if required. */
+ if (ei != NULL) {
+ expert_add_info(pinfo, type_pi, ei);
+ }
+
if (enable_subtree && offset > 0) {
proto_item_set_end(type_pi, tvb, offset);
}
+ if (is_field) {
+ thrift_opt->previous_field_id = field_id;
+ }
+ p_set_proto_depth(pinfo, proto_thrift, nested_count);
return offset;
}
/*=====END SUB-DISSECTION=====*/
@@ -1733,6 +2137,7 @@ dissect_thrift_binary_binary(tvbuff_t *tvb, packet_info *pinfo, proto_tree *tree
}
static int
+// NOLINTNEXTLINE(misc-no-recursion)
dissect_thrift_binary_linear(tvbuff_t *tvb, packet_info *pinfo, proto_tree *tree, int *offset, thrift_option_data_t *thrift_opt, thrift_type_enum_t expected)
{
/* Binary protocol list and set (5 bytes + elements):
@@ -1760,6 +2165,7 @@ dissect_thrift_binary_linear(tvbuff_t *tvb, packet_info *pinfo, proto_tree *tree
int hf_num_item = -1;
int hf_vtype = hf_thrift_type;
int min_len = TBP_THRIFT_LINEAR_LEN;
+ guint nested_count = p_get_proto_depth(pinfo, proto_thrift);
/* Set the different hf_id & ett depending on effective type. */
switch (expected) {
@@ -1787,6 +2193,11 @@ dissect_thrift_binary_linear(tvbuff_t *tvb, packet_info *pinfo, proto_tree *tree
ABORT_ON_INCOMPLETE_PDU(min_len);
/* Create the sub-tree. */
+ if (nested_count >= thrift_opt->nested_type_depth) {
+ expert_add_info(pinfo, proto_tree_get_parent(tree), &ei_thrift_too_many_subtypes);
+ return THRIFT_REQUEST_REASSEMBLY;
+ }
+ p_set_proto_depth(pinfo, proto_thrift, nested_count + 1);
container_pi = proto_tree_add_item(tree, hf_container, tvb, *offset, -1, ENC_NA);
sub_tree = proto_item_add_subtree(container_pi, ett);
@@ -1817,28 +2228,33 @@ dissect_thrift_binary_linear(tvbuff_t *tvb, packet_info *pinfo, proto_tree *tree
}
proto_item_set_end(container_pi, tvb, *offset);
+ p_set_proto_depth(pinfo, proto_thrift, nested_count);
return *offset;
}
static int
+// NOLINTNEXTLINE(misc-no-recursion)
dissect_thrift_binary_list(tvbuff_t *tvb, packet_info *pinfo, proto_tree *tree, int *offset, thrift_option_data_t *thrift_opt)
{
return dissect_thrift_binary_linear(tvb, pinfo, tree, offset, thrift_opt, DE_THRIFT_T_LIST);
}
static int
+// NOLINTNEXTLINE(misc-no-recursion)
dissect_thrift_binary_set(tvbuff_t *tvb, packet_info *pinfo, proto_tree *tree, int *offset, thrift_option_data_t *thrift_opt)
{
return dissect_thrift_binary_linear(tvb, pinfo, tree, offset, thrift_opt, DE_THRIFT_T_SET);
}
static int
+// NOLINTNEXTLINE(misc-no-recursion)
dissect_thrift_binary_map(tvbuff_t *tvb, packet_info *pinfo, proto_tree *tree, int *offset, thrift_option_data_t *thrift_opt)
{
return dissect_thrift_binary_linear(tvb, pinfo, tree, offset, thrift_opt, DE_THRIFT_T_MAP);
}
static int
+// NOLINTNEXTLINE(misc-no-recursion)
dissect_thrift_binary_fields(tvbuff_t *tvb, packet_info *pinfo, proto_tree *tree, int *offset, thrift_option_data_t *thrift_opt)
{
/*
@@ -1863,11 +2279,13 @@ dissect_thrift_binary_fields(tvbuff_t *tvb, packet_info *pinfo, proto_tree *tree
* - either dissect_thrift_common which creates the "Data" sub-tree,
* - or dissect_thrift_binary_struct which creates the "Struct" sub-tree.
*/
- thrift_field_header_t field_header;
+ thrift_field_header_t field_header = {
+ .type.binary = DE_THRIFT_T_STOP, // Overwritten by dissect_thrift_field_header() but undetected by Clang.
+ };
thrift_opt->previous_field_id = 0;
while (TRUE) {
- if (dissect_thrift_field_header(tvb, pinfo, tree, offset, thrift_opt, &field_header) == THRIFT_REQUEST_REASSEMBLY) {
+ if (dissect_thrift_field_header(tvb, pinfo, tree, offset, thrift_opt, &field_header, TRUE) == THRIFT_REQUEST_REASSEMBLY) {
return THRIFT_REQUEST_REASSEMBLY;
}
if (field_header.type.binary == DE_THRIFT_T_STOP) {
@@ -1882,6 +2300,7 @@ dissect_thrift_binary_fields(tvbuff_t *tvb, packet_info *pinfo, proto_tree *tree
}
static int
+// NOLINTNEXTLINE(misc-no-recursion)
dissect_thrift_binary_struct(tvbuff_t *tvb, packet_info *pinfo, proto_tree *tree, int *offset, thrift_option_data_t *thrift_opt)
{
/* This function only creates the "Struct" sub-tree
@@ -1889,8 +2308,14 @@ dissect_thrift_binary_struct(tvbuff_t *tvb, packet_info *pinfo, proto_tree *tree
*/
proto_tree *sub_tree;
proto_item *pi;
+ guint nested_count = p_get_proto_depth(pinfo, proto_thrift);
ABORT_ON_INCOMPLETE_PDU(TBP_THRIFT_STRUCT_LEN);
+ if (nested_count >= thrift_opt->nested_type_depth) {
+ expert_add_info(pinfo, proto_tree_get_parent(tree), &ei_thrift_too_many_subtypes);
+ return THRIFT_REQUEST_REASSEMBLY;
+ }
+ p_set_proto_depth(pinfo, proto_thrift, nested_count + 1);
pi = proto_tree_add_item(tree, hf_thrift_struct, tvb, *offset, -1, ENC_NA);
sub_tree = proto_item_add_subtree(pi, ett_thrift_struct);
@@ -1899,10 +2324,12 @@ dissect_thrift_binary_struct(tvbuff_t *tvb, packet_info *pinfo, proto_tree *tree
} else {
proto_item_set_end(pi, tvb, *offset);
}
+ p_set_proto_depth(pinfo, proto_thrift, nested_count);
return *offset;
}
static int
+// NOLINTNEXTLINE(misc-no-recursion)
dissect_thrift_binary_type(tvbuff_t *tvb, packet_info *pinfo, proto_tree *tree, int *offset, thrift_option_data_t *thrift_opt, proto_tree *header_tree, int type, proto_item *type_pi)
{
switch (type) {
@@ -1936,6 +2363,11 @@ dissect_thrift_binary_type(tvbuff_t *tvb, packet_info *pinfo, proto_tree *tree,
proto_tree_add_item(tree, hf_thrift_double, tvb, *offset, TBP_THRIFT_DOUBLE_LEN, ENC_BIG_ENDIAN);
*offset += TBP_THRIFT_DOUBLE_LEN;
break;
+ case DE_THRIFT_T_UUID:
+ ABORT_ON_INCOMPLETE_PDU(TBP_THRIFT_UUID_LEN);
+ proto_tree_add_item(tree, hf_thrift_uuid, tvb, *offset, TBP_THRIFT_UUID_LEN, ENC_BIG_ENDIAN);
+ *offset += TBP_THRIFT_UUID_LEN;
+ break;
case DE_THRIFT_T_BINARY:
if (dissect_thrift_binary_binary(tvb, pinfo, tree, offset, thrift_opt, header_tree) == THRIFT_REQUEST_REASSEMBLY) {
return THRIFT_REQUEST_REASSEMBLY;
@@ -2033,6 +2465,7 @@ dissect_thrift_compact_binary(tvbuff_t *tvb, packet_info *pinfo, proto_tree *tre
}
static int
+// NOLINTNEXTLINE(misc-no-recursion)
dissect_thrift_compact_list_set(tvbuff_t *tvb, packet_info *pinfo, proto_tree *tree, int *offset, thrift_option_data_t *thrift_opt, gboolean is_list)
{
/* Compact protocol list/set (short form, 1 byte):
@@ -2059,6 +2492,8 @@ dissect_thrift_compact_list_set(tvbuff_t *tvb, packet_info *pinfo, proto_tree *t
int ett = ett_thrift_set;
int hf_container = hf_thrift_set;
int hf_num_item = hf_thrift_num_set_item;
+ int hf_pos_item = hf_thrift_num_set_pos;
+ guint nested_count = p_get_proto_depth(pinfo, proto_thrift);
ABORT_ON_INCOMPLETE_PDU(TBP_THRIFT_TYPE_LEN);
/* Set the different hf_id & ett depending on effective type. */
@@ -2066,9 +2501,15 @@ dissect_thrift_compact_list_set(tvbuff_t *tvb, packet_info *pinfo, proto_tree *t
ett = ett_thrift_list;
hf_container = hf_thrift_list;
hf_num_item = hf_thrift_num_list_item;
+ hf_pos_item = hf_thrift_num_list_pos;
}
/* Create the sub-tree. */
+ if (nested_count >= thrift_opt->nested_type_depth) {
+ expert_add_info(pinfo, proto_tree_get_parent(tree), &ei_thrift_too_many_subtypes);
+ return THRIFT_REQUEST_REASSEMBLY;
+ }
+ p_set_proto_depth(pinfo, proto_thrift, nested_count + 1);
container_pi = proto_tree_add_item(tree, hf_container, tvb, *offset, -1, ENC_NA);
sub_tree = proto_item_add_subtree(container_pi, ett);
@@ -2104,7 +2545,7 @@ dissect_thrift_compact_list_set(tvbuff_t *tvb, packet_info *pinfo, proto_tree *t
break;
}
} else {
- len_pi = proto_tree_add_bits_item(sub_tree, hf_num_item, tvb, (lt_offset << OCTETS_TO_BITS_SHIFT), TCP_THRIFT_NIBBLE_SHIFT, ENC_BIG_ENDIAN);
+ len_pi = proto_tree_add_bits_item(sub_tree, hf_pos_item, tvb, (lt_offset << OCTETS_TO_BITS_SHIFT), TCP_THRIFT_NIBBLE_SHIFT, ENC_BIG_ENDIAN);
}
if (container_len < 0) {
expert_add_info(pinfo, len_pi, &ei_thrift_negative_length);
@@ -2119,22 +2560,26 @@ dissect_thrift_compact_list_set(tvbuff_t *tvb, packet_info *pinfo, proto_tree *t
}
proto_item_set_end(container_pi, tvb, *offset);
+ p_set_proto_depth(pinfo, proto_thrift, nested_count);
return *offset;
}
static int
+// NOLINTNEXTLINE(misc-no-recursion)
dissect_thrift_compact_list(tvbuff_t *tvb, packet_info *pinfo, proto_tree *tree, int *offset, thrift_option_data_t *thrift_opt)
{
return dissect_thrift_compact_list_set(tvb, pinfo, tree, offset, thrift_opt, TRUE);
}
static int
+// NOLINTNEXTLINE(misc-no-recursion)
dissect_thrift_compact_set(tvbuff_t *tvb, packet_info *pinfo, proto_tree *tree, int *offset, thrift_option_data_t *thrift_opt)
{
return dissect_thrift_compact_list_set(tvb, pinfo, tree, offset, thrift_opt, FALSE);
}
static int
+// NOLINTNEXTLINE(misc-no-recursion)
dissect_thrift_compact_map(tvbuff_t *tvb, packet_info *pinfo, proto_tree *tree, int *offset, thrift_option_data_t *thrift_opt)
{
/* Compact protocol map header (1 byte, empty map):
@@ -2159,9 +2604,15 @@ dissect_thrift_compact_map(tvbuff_t *tvb, packet_info *pinfo, proto_tree *tree,
guint32 types, ktype, vtype;
gint32 container_len, len_len, i;
guint64 varint;
+ guint nested_count = p_get_proto_depth(pinfo, proto_thrift);
ABORT_ON_INCOMPLETE_PDU(TCP_THRIFT_MIN_VARINT_LEN);
/* Create the sub-tree. */
+ if (nested_count >= thrift_opt->nested_type_depth) {
+ expert_add_info(pinfo, proto_tree_get_parent(tree), &ei_thrift_too_many_subtypes);
+ return THRIFT_REQUEST_REASSEMBLY;
+ }
+ p_set_proto_depth(pinfo, proto_thrift, nested_count + 1);
container_pi = proto_tree_add_item(tree, hf_thrift_map, tvb, *offset, -1, ENC_NA);
sub_tree = proto_item_add_subtree(container_pi, ett_thrift_map);
@@ -2213,10 +2664,12 @@ dissect_thrift_compact_map(tvbuff_t *tvb, packet_info *pinfo, proto_tree *tree,
}
proto_item_set_end(container_pi, tvb, *offset);
+ p_set_proto_depth(pinfo, proto_thrift, nested_count);
return *offset;
}
static int
+// NOLINTNEXTLINE(misc-no-recursion)
dissect_thrift_compact_fields(tvbuff_t *tvb, packet_info *pinfo, proto_tree *tree, int *offset, thrift_option_data_t *thrift_opt)
{
/*
@@ -2247,17 +2700,20 @@ dissect_thrift_compact_fields(tvbuff_t *tvb, packet_info *pinfo, proto_tree *tre
* - either dissect_thrift_common which creates the "Data" sub-tree,
* - or dissect_thrift_compact_struct which creates the "Struct" sub-tree.
*/
- thrift_field_header_t field_header;
+ thrift_field_header_t field_header = {
+ .type.compact = DE_THRIFT_C_STOP, // Overwritten by dissect_thrift_field_header() but undetected by Clang.
+ };
thrift_opt->previous_field_id = 0;
while (TRUE) {
- if (dissect_thrift_field_header(tvb, pinfo, tree, offset, thrift_opt, &field_header) == THRIFT_REQUEST_REASSEMBLY) {
+ if (dissect_thrift_field_header(tvb, pinfo, tree, offset, thrift_opt, &field_header, TRUE) == THRIFT_REQUEST_REASSEMBLY) {
return THRIFT_REQUEST_REASSEMBLY;
}
if (field_header.type.compact == DE_THRIFT_C_STOP) {
break; /* Need to break out of the loop, cannot do that in the switch. */
}
- if (dissect_thrift_compact_type(tvb, pinfo, tree, offset, thrift_opt, field_header.fh_tree, field_header.type.compact, field_header.type_pi) == THRIFT_REQUEST_REASSEMBLY) {
+ if (!is_thrift_compact_bool_type(field_header.type.compact) &&
+ dissect_thrift_compact_type(tvb, pinfo, tree, offset, thrift_opt, field_header.fh_tree, field_header.type.compact, field_header.type_pi) == THRIFT_REQUEST_REASSEMBLY) {
return THRIFT_REQUEST_REASSEMBLY;
}
thrift_opt->previous_field_id = field_header.field_id;
@@ -2267,6 +2723,7 @@ dissect_thrift_compact_fields(tvbuff_t *tvb, packet_info *pinfo, proto_tree *tre
}
static int
+// NOLINTNEXTLINE(misc-no-recursion)
dissect_thrift_compact_struct(tvbuff_t *tvb, packet_info *pinfo, proto_tree *tree, int *offset, thrift_option_data_t *thrift_opt)
{
/* This function only creates the "Struct" sub-tree
@@ -2274,8 +2731,14 @@ dissect_thrift_compact_struct(tvbuff_t *tvb, packet_info *pinfo, proto_tree *tre
*/
proto_tree *sub_tree;
proto_item *pi;
+ guint nested_count = p_get_proto_depth(pinfo, proto_thrift);
ABORT_ON_INCOMPLETE_PDU(TCP_THRIFT_STRUCT_LEN);
+ if (nested_count >= thrift_opt->nested_type_depth) {
+ expert_add_info(pinfo, proto_tree_get_parent(tree), &ei_thrift_too_many_subtypes);
+ return THRIFT_REQUEST_REASSEMBLY;
+ }
+ p_set_proto_depth(pinfo, proto_thrift, nested_count + 1);
pi = proto_tree_add_item(tree, hf_thrift_struct, tvb, *offset, -1, ENC_NA);
sub_tree = proto_item_add_subtree(pi, ett_thrift_struct);
@@ -2284,19 +2747,21 @@ dissect_thrift_compact_struct(tvbuff_t *tvb, packet_info *pinfo, proto_tree *tre
} else {
proto_item_set_end(pi, tvb, *offset);
}
+ p_set_proto_depth(pinfo, proto_thrift, nested_count);
return *offset;
}
/* Dissect a compact thrift field of a given type.
*
* This function is used only for linear containers (list, set, map).
- * It uses the same type identifiers as TBinaryProtocol.
+ * It uses the same type identifiers as TCompactProtocol, except for
+ * the bool type which is encoded in the same way as BOOL_FALSE (2).
*/
static int
+// NOLINTNEXTLINE(misc-no-recursion)
dissect_thrift_compact_type(tvbuff_t *tvb, packet_info *pinfo, proto_tree *tree, int *offset, thrift_option_data_t *thrift_opt, proto_tree *header_tree, int type, proto_item *type_pi)
{
switch (type) {
- case DE_THRIFT_C_BOOL_TRUE:
case DE_THRIFT_C_BOOL_FALSE:
ABORT_ON_INCOMPLETE_PDU(TBP_THRIFT_BOOL_LEN);
proto_tree_add_item(tree, hf_thrift_bool, tvb, *offset, TBP_THRIFT_BOOL_LEN, ENC_BIG_ENDIAN);
@@ -2308,17 +2773,17 @@ dissect_thrift_compact_type(tvbuff_t *tvb, packet_info *pinfo, proto_tree *tree,
*offset += TBP_THRIFT_I8_LEN;
break;
case DE_THRIFT_C_I16:
- if (dissect_thrift_varint(tvb, pinfo, tree, offset, thrift_opt, TCP_THRIFT_MAX_I16_LEN, hf_thrift_i16) == THRIFT_REQUEST_REASSEMBLY) {
+ if (dissect_thrift_varint(tvb, pinfo, tree, offset, thrift_opt, TCP_THRIFT_MAX_I16_LEN, hf_thrift_i16, NULL) == THRIFT_REQUEST_REASSEMBLY) {
return THRIFT_REQUEST_REASSEMBLY;
}
break;
case DE_THRIFT_C_I32:
- if (dissect_thrift_varint(tvb, pinfo, tree, offset, thrift_opt, TCP_THRIFT_MAX_I32_LEN, hf_thrift_i32) == THRIFT_REQUEST_REASSEMBLY) {
+ if (dissect_thrift_varint(tvb, pinfo, tree, offset, thrift_opt, TCP_THRIFT_MAX_I32_LEN, hf_thrift_i32, NULL) == THRIFT_REQUEST_REASSEMBLY) {
return THRIFT_REQUEST_REASSEMBLY;
}
break;
case DE_THRIFT_C_I64:
- if (dissect_thrift_varint(tvb, pinfo, tree, offset, thrift_opt, TCP_THRIFT_MAX_I64_LEN, hf_thrift_i64) == THRIFT_REQUEST_REASSEMBLY) {
+ if (dissect_thrift_varint(tvb, pinfo, tree, offset, thrift_opt, TCP_THRIFT_MAX_I64_LEN, hf_thrift_i64, NULL) == THRIFT_REQUEST_REASSEMBLY) {
return THRIFT_REQUEST_REASSEMBLY;
}
break;
@@ -2333,6 +2798,11 @@ dissect_thrift_compact_type(tvbuff_t *tvb, packet_info *pinfo, proto_tree *tree,
proto_tree_add_item(tree, hf_thrift_double, tvb, *offset, TBP_THRIFT_DOUBLE_LEN, ENC_LITTLE_ENDIAN);
*offset += TBP_THRIFT_DOUBLE_LEN;
break;
+ case DE_THRIFT_C_UUID:
+ ABORT_ON_INCOMPLETE_PDU(TBP_THRIFT_UUID_LEN);
+ proto_tree_add_item(tree, hf_thrift_uuid, tvb, *offset, TBP_THRIFT_UUID_LEN, ENC_BIG_ENDIAN);
+ *offset += TBP_THRIFT_UUID_LEN;
+ break;
case DE_THRIFT_C_BINARY:
if (dissect_thrift_compact_binary(tvb, pinfo, tree, offset, thrift_opt, header_tree) == THRIFT_REQUEST_REASSEMBLY) {
return THRIFT_REQUEST_REASSEMBLY;
@@ -2555,7 +3025,7 @@ dissect_thrift_common(tvbuff_t *tvb, packet_info *pinfo, proto_tree *tree, int o
if (tvb_reported_length_remaining(tvb, offset) < str_len) {
goto add_expert_and_reassemble;
}
- method_str = tvb_get_string_enc(pinfo->pool, tvb, offset, str_len, ENC_UTF_8|ENC_NA);
+ method_str = tvb_get_string_enc(pinfo->pool, tvb, offset, str_len, ENC_UTF_8);
offset += str_len;
} else if (thrift_opt->tprotocol & PROTO_THRIFT_STRICT) {
if (remaining < TBP_THRIFT_STRICT_MIN_MESSAGE_LEN) {
@@ -2572,7 +3042,7 @@ dissect_thrift_common(tvbuff_t *tvb, packet_info *pinfo, proto_tree *tree, int o
goto add_expert_and_reassemble;
}
offset += TBP_THRIFT_VERSION_LEN + TBP_THRIFT_LENGTH_LEN;
- method_str = tvb_get_string_enc(pinfo->pool, tvb, offset, str_len, ENC_UTF_8|ENC_NA);
+ method_str = tvb_get_string_enc(pinfo->pool, tvb, offset, str_len, ENC_UTF_8);
offset += str_len;
seq_id = tvb_get_ntohil(tvb, offset);
@@ -2591,7 +3061,7 @@ dissect_thrift_common(tvbuff_t *tvb, packet_info *pinfo, proto_tree *tree, int o
goto add_expert_and_reassemble;
}
offset += TBP_THRIFT_LENGTH_LEN;
- method_str = tvb_get_string_enc(pinfo->pool, tvb, offset, str_len, ENC_UTF_8|ENC_NA);
+ method_str = tvb_get_string_enc(pinfo->pool, tvb, offset, str_len, ENC_UTF_8);
offset += str_len;
mtype = tvb_get_guint8(tvb, offset + TBP_THRIFT_LENGTH_LEN + str_len) & THRIFT_BINARY_MESSAGE_MASK;
offset += TBP_THRIFT_TYPE_LEN;
@@ -2634,7 +3104,7 @@ dissect_thrift_common(tvbuff_t *tvb, packet_info *pinfo, proto_tree *tree, int o
offset += seqid_len;
proto_tree_add_int(sub_tree, hf_thrift_str_len, tvb, offset, str_len_len, str_len);
offset += str_len_len;
- proto_tree_add_item(sub_tree, hf_thrift_method, tvb, offset, str_len, ENC_UTF_8|ENC_NA);
+ proto_tree_add_item(sub_tree, hf_thrift_method, tvb, offset, str_len, ENC_UTF_8);
offset = offset + str_len;
} else if (thrift_opt->tprotocol & PROTO_THRIFT_STRICT) {
/* Strict: proto_id|version|mtype|length|name|seqid */
@@ -2645,7 +3115,7 @@ dissect_thrift_common(tvbuff_t *tvb, packet_info *pinfo, proto_tree *tree, int o
offset += TBP_THRIFT_MTYPE_LEN;
proto_tree_add_item(sub_tree, hf_thrift_str_len, tvb, offset, TBP_THRIFT_LENGTH_LEN, ENC_BIG_ENDIAN);
offset += TBP_THRIFT_LENGTH_LEN;
- proto_tree_add_item(sub_tree, hf_thrift_method, tvb, offset, str_len, ENC_UTF_8|ENC_NA);
+ proto_tree_add_item(sub_tree, hf_thrift_method, tvb, offset, str_len, ENC_UTF_8);
offset = offset + str_len;
proto_tree_add_item(sub_tree, hf_thrift_seq_id, tvb, offset, TBP_THRIFT_SEQ_ID_LEN, ENC_BIG_ENDIAN);
offset += TBP_THRIFT_SEQ_ID_LEN;
@@ -2653,7 +3123,7 @@ dissect_thrift_common(tvbuff_t *tvb, packet_info *pinfo, proto_tree *tree, int o
/* Old: length|name|mtype|seqid */
proto_tree_add_item(sub_tree, hf_thrift_str_len, tvb, offset, TBP_THRIFT_LENGTH_LEN, ENC_BIG_ENDIAN);
offset += TBP_THRIFT_LENGTH_LEN;
- proto_tree_add_item(sub_tree, hf_thrift_method, tvb, offset, str_len, ENC_UTF_8|ENC_NA);
+ proto_tree_add_item(sub_tree, hf_thrift_method, tvb, offset, str_len, ENC_UTF_8);
offset = offset + str_len;
mtype_pi = proto_tree_add_bits_item(sub_tree, hf_thrift_mtype, tvb, (offset << OCTETS_TO_BITS_SHIFT) + 5, 3, ENC_BIG_ENDIAN);
offset += TBP_THRIFT_MTYPE_LEN;
@@ -2676,7 +3146,9 @@ dissect_thrift_common(tvbuff_t *tvb, packet_info *pinfo, proto_tree *tree, int o
thrift_opt->previous_field_id = 0;
msg_tvb = tvb_new_subset_remaining(tvb, data_offset);
if (thrift_opt->mtype == ME_THRIFT_T_REPLY) {
- thrift_field_header_t header;
+ thrift_field_header_t header = {
+ .field_id = 0, // Overwritten by dissect_thrift_field_header() but undetected by Clang.
+ };
/* For REPLY, in order to separate successful answers from errors (exceptions),
* Thrift generates a struct with as much fields (all optional) as there are exceptions possible + 1.
* At most 1 field will be filled for any reply
@@ -2687,7 +3159,7 @@ dissect_thrift_common(tvbuff_t *tvb, packet_info *pinfo, proto_tree *tree, int o
* We read this before checking for sub-dissectors as the information might be useful to them.
*/
int result = data_offset;
- result = dissect_thrift_field_header(tvb, pinfo, NULL, &result, thrift_opt, &header);
+ result = dissect_thrift_field_header(tvb, pinfo, NULL, &result, thrift_opt, &header, FALSE);
switch (result) {
case THRIFT_REQUEST_REASSEMBLY:
goto add_expert_and_reassemble;
@@ -2704,6 +3176,7 @@ dissect_thrift_common(tvbuff_t *tvb, packet_info *pinfo, proto_tree *tree, int o
len = dissector_try_string(thrift_method_name_dissector_table, method_str, msg_tvb, pinfo, tree, thrift_opt);
if (pinfo->can_desegment > 0) pinfo->can_desegment--;
} else {
+ /* Attach the expert_info to the method type as it is a protocol-level exception. */
expert_add_info(pinfo, mtype_pi, &ei_thrift_protocol_exception);
/* Leverage the sub-dissector capabilities to dissect Thrift exceptions. */
len = dissect_thrift_t_struct(msg_tvb, pinfo, thrift_tree, 0, thrift_opt, FALSE, 0, hf_thrift_exception, ett_thrift_exception, thrift_exception);
@@ -2732,7 +3205,7 @@ dissect_thrift_common(tvbuff_t *tvb, packet_info *pinfo, proto_tree *tree, int o
thrift_opt->reassembly_length = TBP_THRIFT_TYPE_LEN;
if (thrift_opt->reply_field_id != 0) {
expert_add_info(pinfo, fid_pi, &ei_thrift_application_exception);
- proto_item_set_text(data_pi, "Exception: %" G_GINT64_MODIFIER "d", thrift_opt->reply_field_id);
+ proto_item_set_text(data_pi, "Exception: %" PRId64, thrift_opt->reply_field_id);
}
if (is_compact) {
@@ -2854,7 +3327,9 @@ dissect_thrift_framed(tvbuff_t *tvb, packet_info *pinfo, proto_tree *tree, void
DISSECTOR_ASSERT(thrift_opt->canary == THRIFT_OPTION_DATA_CANARY);
DISSECTOR_ASSERT(thrift_opt->tprotocol & PROTO_THRIFT_FRAMED);
frame_len = tvb_get_ntohil(tvb, offset);
- DISSECTOR_ASSERT((frame_len + TBP_THRIFT_LENGTH_LEN) == reported);
+ // Note: The framed dissector can be called even if the entire packet is bigger than the frame.
+ // This can happen when the frame was initially rejected because it was too short.
+ DISSECTOR_ASSERT((frame_len + TBP_THRIFT_LENGTH_LEN) <= reported);
offset = dissect_thrift_common(tvb, pinfo, tree, offset, thrift_opt);
if (offset == THRIFT_REQUEST_REASSEMBLY) {
@@ -2877,6 +3352,7 @@ dissect_thrift_transport(tvbuff_t *tvb, packet_info *pinfo, proto_tree *tree, vo
gint32 str_len, length = tvb_reported_length(tvb);
thrift_option_data_t thrift_opt;
memset(&thrift_opt, 0, sizeof(thrift_option_data_t));
+ thrift_opt.nested_type_depth = nested_type_depth;
/* Starting without even the version / frame length / name length probably means a Keep-Alive at the beginning of the capture. */
if (length < TBP_THRIFT_VERSION_LEN) {
@@ -3143,7 +3619,11 @@ test_thrift_compact(tvbuff_t *tvb, packet_info *pinfo _U_, proto_tree *tree _U_,
/* 4. Get method name length and check against what we have. */
if ((guint)offset >= length) return FALSE;
- str_len = tvb_get_gint8(tvb, offset);
+ str_len = tvb_get_guint8(tvb, offset);
+ // MSb = 1 means the method length is greater than 127 bytes long.
+ if ((str_len & 0x80) != 0) {
+ return FALSE; // Reject it to avoid too many false positive.
+ }
++offset;
if ((tframe_length > 0) && (TBP_THRIFT_LENGTH_LEN + tframe_length < offset + str_len)) {
/* The frame cannot even contain an empty Thrift message (no data, only T_STOP after the sequence id). */
@@ -3175,6 +3655,7 @@ dissect_thrift_heur(tvbuff_t *tvb, packet_info *pinfo, proto_tree *tree, void *d
{
thrift_option_data_t thrift_opt;
memset(&thrift_opt, 0, sizeof(thrift_option_data_t));
+ thrift_opt.nested_type_depth = nested_type_depth;
if (!test_thrift_strict(tvb, pinfo, tree, &thrift_opt) && !test_thrift_compact(tvb, pinfo, tree, &thrift_opt)) {
return FALSE;
@@ -3314,7 +3795,7 @@ proto_register_thrift(void)
NULL, HFILL }
},
{ &hf_thrift_string,
- { "String", "thrift.binary",
+ { "String", "thrift.string",
FT_STRING, BASE_NONE, NULL, 0x0,
"Binary field interpreted as a string.", HFILL }
},
@@ -3343,11 +3824,21 @@ proto_register_thrift(void)
FT_INT32, BASE_DEC, NULL, 0x0,
NULL, HFILL }
},
+ { &hf_thrift_num_set_pos,
+ { "Number of Set Items", "thrift.num_set_pos",
+ FT_UINT32, BASE_DEC, NULL, 0x0,
+ NULL, HFILL }
+ },
{ &hf_thrift_num_list_item,
{ "Number of List Items", "thrift.num_list_item",
FT_INT32, BASE_DEC, NULL, 0x0,
NULL, HFILL }
},
+ { &hf_thrift_num_list_pos,
+ { "Number of List Items", "thrift.num_list_pos",
+ FT_UINT32, BASE_DEC, NULL, 0x0,
+ NULL, HFILL }
+ },
{ &hf_thrift_num_map_item,
{ "Number of Map Items", "thrift.num_map_item",
FT_INT32, BASE_DEC, NULL, 0x0,
@@ -3358,6 +3849,11 @@ proto_register_thrift(void)
FT_UINT8, BASE_HEX, NULL, 0x0,
NULL, HFILL }
},
+ { &hf_thrift_uuid,
+ { "UUID", "thrift.uuid",
+ FT_GUID, BASE_NONE, NULL, 0x0,
+ NULL, HFILL }
+ },
};
@@ -3387,9 +3883,10 @@ proto_register_thrift(void)
{ &ei_thrift_varint_too_large, { "thrift.varint_too_large", PI_PROTOCOL, PI_ERROR, "Thrift varint value too large for target integer type.", EXPFILL } },
{ &ei_thrift_undefined_field_id, { "thrift.undefined_field_id", PI_PROTOCOL, PI_NOTE, "Field id not defined by sub-dissector, using generic Thrift dissector.", EXPFILL } },
{ &ei_thrift_negative_field_id, { "thrift.negative_field_id", PI_PROTOCOL, PI_NOTE, "Encountered unexpected negative field id, possibly an old application.", EXPFILL } },
- { &ei_thrift_unordered_field_id, { "thrift.unordered_field_id", PI_PROTOCOL, PI_WARN, "Field id not defined by sub-dissector, using generic Thrift dissector.", EXPFILL } },
+ { &ei_thrift_unordered_field_id, { "thrift.unordered_field_id", PI_PROTOCOL, PI_WARN, "Field id not in strictly increasing order.", EXPFILL } },
{ &ei_thrift_application_exception, { "thrift.application_exception", PI_PROTOCOL, PI_NOTE, "The application recognized the method but rejected the content.", EXPFILL } },
{ &ei_thrift_protocol_exception, { "thrift.protocol_exception", PI_PROTOCOL, PI_WARN, "The application was not able to handle the request.", EXPFILL } },
+ { &ei_thrift_too_many_subtypes, { "thrift.too_many_subtypes", PI_PROTOCOL, PI_ERROR, "Too many level of sub-types nesting.", EXPFILL } },
};
@@ -3412,11 +3909,12 @@ proto_register_thrift(void)
/* register dissector */
thrift_handle = register_dissector("thrift", dissect_thrift_transport, proto_thrift);
+ thrift_http_handle = register_dissector("thrift.http", dissect_thrift_heur, proto_thrift);
thrift_module = prefs_register_protocol(proto_thrift, proto_reg_handoff_thrift);
thrift_method_name_dissector_table = register_dissector_table("thrift.method_names", "Thrift Method names",
- proto_thrift, FT_STRING, FALSE); /* FALSE because Thrift is case-sensitive */
+ proto_thrift, FT_STRING, STRING_CASE_SENSITIVE); /* Thrift is case-sensitive. */
prefs_register_enum_preference(thrift_module, "decode_binary",
"Display binary as bytes or strings",
@@ -3439,6 +3937,13 @@ proto_register_thrift(void)
" This option can be useful if the data is well-formed but the sub-dissector is expecting different type/content.",
&try_generic_if_sub_dissector_fails);
+ prefs_register_uint_preference(thrift_module, "nested_type_depth",
+ "Thrift nested types depth",
+ "Maximum expected depth of nested types in the Thrift structures and containers."
+ " A Thrift-based protocol using no parameter and void return types only uses a depth of 0."
+ " A Thrift-based protocol using only simple types as parameters or return values uses a depth of 1.",
+ 10, &nested_type_depth);
+
prefs_register_bool_preference(thrift_module, "desegment_framed",
"Reassemble Framed Thrift messages spanning multiple TCP segments",
"Whether the Thrift dissector should reassemble framed messages spanning multiple TCP segments."
@@ -3450,11 +3955,8 @@ void
proto_reg_handoff_thrift(void)
{
static guint saved_thrift_tls_port;
- static dissector_handle_t thrift_http_handle;
static gboolean thrift_initialized = FALSE;
- thrift_http_handle = create_dissector_handle(dissect_thrift_heur, proto_thrift);
-
if (!thrift_initialized) {
thrift_initialized = TRUE;
heur_dissector_add("tcp", dissect_thrift_heur, "Thrift over TCP", "thrift_tcp", proto_thrift, HEURISTIC_ENABLE);