[Thrift] Make it easier to make specific Thrift dissectors

Introduce functionallity simmilar to packet-ber.c

Change-Id: Ibb76e2db870c9a9dd8b26067b59a20044aafbd85
Reviewed-on: https://code.wireshark.org/review/25266
Petri-Dish: Anders Broman <a.broman58@gmail.com>
Tested-by: Petri Dish Buildbot
Reviewed-by: Anders Broman <a.broman58@gmail.com>
This commit is contained in:
AndersBroman 2018-01-11 13:47:08 +01:00 committed by Anders Broman
parent a106c762ef
commit ddf8d8704d
3 changed files with 389 additions and 19 deletions

View File

@ -1800,6 +1800,7 @@ DISSECTOR_INCLUDES = \
packet-tcp.h \
packet-tetra.h \
packet-tftp.h \
packet-thrift.h \
packet-tn3270.h \
packet-tn5250.h \
packet-tpkt.h \

View File

@ -18,8 +18,10 @@
#include "config.h"
#include <epan/packet.h>
#include <epan/expert.h>
#include "packet-ssl.h"
#include "packet-thrift.h"
void proto_register_thrift(void);
@ -27,10 +29,32 @@ void proto_reg_handoff_thrift(void);
#define THRIFT_VERSION_MASK 0xffff0000
#define THRIFT_VERSION_1 0x80010000
#define THRIFT_COMPACT 0x80020000
#define THRIFT_T_STOP 0
#define THRIFT_T_VOID 1
#define THRIFT_T_BOL 2
#define THRIFT_T_BYTE 3
#define THRIFT_T_DOUBLE 4
#define THRIFT_T_I16 6
#define THRIFT_T_I32 8
#define THRIFT_T_U64 9
#define THRIFT_T_I64 10
#define THRIFT_T_UTF7 11
#define THRIFT_T_STRUCT 12
#define THRIFT_T_MAP 13
#define THRIFT_T_SET 14
#define THRIFT_T_LIST 15
#define THRIFT_T_UTF8 16
#define THRIFT_T_UTF16 17
static dissector_handle_t thrift_handle;
static guint thrift_tls_port = 0;
static gboolean show_internal_thrift_fields = FALSE;
static dissector_table_t thrift_method_name_dissector_table;
static int proto_thrift = -1;
static int hf_thrift_version = -1;
static int hf_thrift_mtype = -1;
@ -52,6 +76,9 @@ static int hf_thrift_double = -1;
static int ett_thrift = -1;
static expert_field ei_thrift_wrong_type = EI_INIT;
static expert_field ei_thrift_struct_type_not_imp = EI_INIT;
static const value_string thrift_type_vals[] = {
{ 0, "T_STOP" },
{ 1, "T_VOID" },
@ -91,6 +118,184 @@ static const value_string thrift_bool_vals[] = {
static int dissect_thrift_type(tvbuff_t* tvb, packet_info* pinfo _U_, proto_tree* tree, int type, int offset, int length);
int
dissect_thrift_t_stop(tvbuff_t* tvb, packet_info* pinfo _U_, proto_tree* tree, int offset)
{
guint32 type;
proto_tree_add_item_ret_uint(tree, hf_thrift_type, tvb, offset, 1, ENC_BIG_ENDIAN, &type);
if (type != THRIFT_T_STOP) {
proto_tree_add_expert(tree, pinfo, &ei_thrift_wrong_type, tvb, offset, 1);
}
offset++;
return offset;
}
int
dissect_thrift_t_byte(tvbuff_t* tvb, packet_info* pinfo _U_, proto_tree* tree, int offset, int field_id _U_, gint hf_id)
{
guint8 type;
type = tvb_get_guint8(tvb, offset);
if (type != THRIFT_T_BYTE) {
proto_tree_add_expert(tree, pinfo, &ei_thrift_wrong_type, tvb, offset, 1);
}
if(show_internal_thrift_fields){
proto_tree_add_item(tree, hf_thrift_type, tvb, offset, 1, ENC_BIG_ENDIAN);
offset++;
proto_tree_add_item(tree, hf_thrift_fid, tvb, offset, 2, ENC_BIG_ENDIAN);
offset += 2;
} else {
offset += 3;
}
/*T_BYTE , T_I08*/
proto_tree_add_item(tree, hf_id, tvb, offset, 1, ENC_BIG_ENDIAN);
offset += 1;
return offset;
}
int
dissect_thrift_t_i32(tvbuff_t* tvb, packet_info* pinfo _U_, proto_tree* tree, int offset, int field_id _U_, gint hf_id)
{
guint8 type;
type = tvb_get_guint8(tvb, offset);
if (type != THRIFT_T_I32) {
proto_tree_add_expert(tree, pinfo, &ei_thrift_wrong_type, tvb, offset, 1);
}
if (show_internal_thrift_fields) {
proto_tree_add_item(tree, hf_thrift_type, tvb, offset, 1, ENC_BIG_ENDIAN);
offset++;
proto_tree_add_item(tree, hf_thrift_fid, tvb, offset, 2, ENC_BIG_ENDIAN);
offset += 2;
} else {
offset += 3;
}
proto_tree_add_item(tree, hf_id, tvb, offset, 4, ENC_BIG_ENDIAN);
offset += 4;
return offset;
}
int
dissect_thrift_t_utf7(tvbuff_t* tvb, packet_info* pinfo _U_, proto_tree* tree, int offset, int field_id _U_, gint hf_id)
{
guint32 str_len;
guint8 type;
type = tvb_get_guint8(tvb, offset);
if (type != THRIFT_T_UTF7) {
proto_tree_add_expert(tree, pinfo, &ei_thrift_wrong_type, tvb, offset, 1);
}
if (show_internal_thrift_fields) {
proto_tree_add_item(tree, hf_thrift_type, tvb, offset, 1, ENC_BIG_ENDIAN);
offset++;
proto_tree_add_item(tree, hf_thrift_fid, tvb, offset, 2, ENC_BIG_ENDIAN);
offset += 2;
proto_tree_add_item_ret_uint(tree, hf_thrift_str_len, tvb, offset, 4, ENC_BIG_ENDIAN, &str_len);
offset += 4;
} else {
offset += 3;
str_len = tvb_get_ntohl(tvb, offset);
offset += 4;
}
proto_tree_add_item(tree, hf_id, tvb, offset, str_len, ENC_ASCII | ENC_NA);
offset = offset + str_len;
return offset;
}
int
dissect_thrift_t_struct(tvbuff_t* tvb, packet_info* pinfo _U_, proto_tree* tree, int offset, const thrift_struct_t *seq, int field_id _U_, gint hf_id, gint ett_id)
{
proto_item *ti;
proto_tree *sub_tree;
guint8 type;
int start_offset = offset;
/* Add the struct to the tree*/
ti = proto_tree_add_item(tree, hf_id, tvb, offset, -1, ENC_BIG_ENDIAN);
sub_tree = proto_item_add_subtree(ti, ett_id);
type = tvb_get_guint8(tvb, offset);
if (type != THRIFT_T_STRUCT) {
proto_tree_add_expert(sub_tree, pinfo, &ei_thrift_wrong_type, tvb, offset, 1);
}
if (show_internal_thrift_fields) {
proto_tree_add_item(sub_tree, hf_thrift_type, tvb, offset, 1, ENC_BIG_ENDIAN);
offset++;
proto_tree_add_item(sub_tree, hf_thrift_fid, tvb, offset, 2, ENC_BIG_ENDIAN);
offset += 2;
}
else {
offset += 3;
}
while (seq->fid) {
switch (seq->type) {
case DE_THRIFT_T_STOP:
offset = dissect_thrift_t_stop(tvb, pinfo, sub_tree, offset);
break;
case DE_THRIFT_T_VOID:
case DE_THRIFT_T_BOL:
proto_tree_add_expert(sub_tree, pinfo, &ei_thrift_struct_type_not_imp, tvb, offset, 1);
break;
case DE_THRIFT_T_BYTE:
offset = dissect_thrift_t_byte(tvb, pinfo, sub_tree, offset, seq->fid, *seq->p_id);
break;
case DE_THRIFT_T_DOUBLE:
case DE_THRIFT_T_UNUSED_5:
case DE_THRIFT_T_I16:
case DE_THRIFT_T_UNUSED_7:
proto_tree_add_expert(sub_tree, pinfo, &ei_thrift_struct_type_not_imp, tvb, offset, 1);
break;
case DE_THRIFT_T_I32:
offset = dissect_thrift_t_i32(tvb, pinfo, sub_tree, offset, seq->fid, *seq->p_id);
break;
case DE_THRIFT_T_U64:
case DE_THRIFT_T_I64:
proto_tree_add_expert(sub_tree, pinfo, &ei_thrift_struct_type_not_imp, tvb, offset, 1);
break;
case DE_THRIFT_T_UTF7:
offset = dissect_thrift_t_utf7(tvb, pinfo, sub_tree, offset, seq->fid, *seq->p_id);
break;
case DE_THRIFT_T_STRUCT:
case DE_THRIFT_T_MAP:
case DE_THRIFT_T_SET:
case DE_THRIFT_T_LIST:
case DE_THRIFT_T_UTF8:
case DE_THRIFT_T_UTF16:
default:
proto_tree_add_expert(sub_tree, pinfo, &ei_thrift_struct_type_not_imp, tvb, offset, 1);
break;
}
seq++;
}
if (show_internal_thrift_fields) {
proto_tree_add_item(sub_tree, hf_thrift_type, tvb, offset, 1, ENC_BIG_ENDIAN);
}
offset++;
proto_item_set_len(ti, offset - start_offset);
return offset;
}
static int
dissect_thrift_utf7(tvbuff_t* tvb, packet_info* pinfo _U_, proto_tree* tree, int offset, int length _U_)
{
@ -261,13 +466,15 @@ dissect_thrift_common(tvbuff_t* tvb, packet_info* pinfo, proto_tree* tree, void
{
proto_tree *sub_tree;
int offset = 0;
guint32 str_len;
int str_len;
guint8 mtype;
guint16 version;
guint32 seq_id;
guint8 *method_str;
int length = tvb_reported_length(tvb);
guint8 type;
tvbuff_t *msg_tvb;
int len;
col_set_str(pinfo->cinfo, COL_PROTOCOL, "THRIFT");
col_clear(pinfo->cinfo, COL_INFO);
@ -275,6 +482,7 @@ dissect_thrift_common(tvbuff_t* tvb, packet_info* pinfo, proto_tree* tree, void
version = tvb_get_ntohs(tvb, 0);
mtype = tvb_get_guint8(tvb, 3);
str_len = tvb_get_ntohl(tvb, 4);
seq_id = tvb_get_ntohl(tvb, str_len + 8);
method_str = tvb_get_string_enc(wmem_packet_scope(), tvb, 8, str_len, ENC_UTF_8);
@ -307,23 +515,98 @@ dissect_thrift_common(tvbuff_t* tvb, packet_info* pinfo, proto_tree* tree, void
}
/* Call method dissector here using dissector_try_string()*/
sub_tree = proto_tree_add_subtree(tree, tvb, offset, -1, ett_thrift, NULL, "Data");
if (tree){
while (offset < length){
/*Read type and field id */
type = tvb_get_guint8(tvb, offset);
proto_tree_add_item(sub_tree, hf_thrift_type, tvb, offset, 1, ENC_BIG_ENDIAN);
if (type == 0){
return tvb_reported_length(tvb);
}
offset++;
proto_tree_add_item(sub_tree, hf_thrift_fid, tvb, offset, 2, ENC_BIG_ENDIAN);
offset += 2;
offset = dissect_thrift_type(tvb, pinfo, sub_tree, type, offset, length);
}
msg_tvb = tvb_new_subset_length(tvb, offset, length - offset);
len = dissector_try_string(thrift_method_name_dissector_table, method_str, msg_tvb, pinfo, tree, NULL);
if (len > 0) {
/* The sub dissector dissected the tvb*/
return tvb_reported_length(tvb);
} else if (len < 0) {
/* The subdissector requested more bytes ( len = -1 )*/
return len;
}
return tvb_reported_length(tvb);
/* len = 0, no subdissector */
sub_tree = proto_tree_add_subtree(tree, tvb, offset, -1, ett_thrift, NULL, "Data");
while (offset < length){
/*Read type and field id */
type = tvb_get_guint8(tvb, offset);
proto_tree_add_item(sub_tree, hf_thrift_type, tvb, offset, 1, ENC_BIG_ENDIAN);
if (type == 0){
return tvb_reported_length(tvb);
}
offset++;
proto_tree_add_item(sub_tree, hf_thrift_fid, tvb, offset, 2, ENC_BIG_ENDIAN);
offset += 2;
offset = dissect_thrift_type(tvb, pinfo, sub_tree, type, offset, length);
}
/* We did not encounter T_STOP*/
pinfo->desegment_offset = 0;
pinfo->desegment_len = DESEGMENT_ONE_MORE_SEGMENT;
return 0;
}
/*
Binary protocol Message, strict encoding, 12+ bytes:
+--------+--------+--------+--------+--------+--------+--------+--------+--------+...+--------+--------+--------+--------+--------+
|1vvvvvvv|vvvvvvvv|unused |00000mmm| name length | name | seq id |
+--------+--------+--------+--------+--------+--------+--------+--------+--------+...+--------+--------+--------+--------+--------+
'''
Where:
* 'vvvvvvvvvvvvvvv' is the version, an unsigned 15 bit number fixed to '1' (in binary: '000 0000 0000 0001').
The leading bit is '1'.
* 'unused' is an ignored byte.
* 'mmm' is the message type, an unsigned 3 bit integer. The 5 leading bits must be '0' as some clients (checked for
java in 0.9.1) take the whole byte.
* 'name length' is the byte length of the name field, a signed 32 bit integer encoded in network (big endian) order (must be >= 0).
* 'name' is the method name, a UTF-8 encoded string.
* 'seq id' is the sequence id, a signed 32 bit integer encoded in network (big endian) order.
Compact protocol Message (4+ bytes):
+--------+--------+--------+...+--------+--------+...+--------+--------+...+--------+
|pppppppp|mmmvvvvv| seq id | name length | name |
+--------+--------+--------+...+--------+--------+...+--------+--------+...+--------+
Where:
* 'pppppppp' is the protocol id, fixed to '1000 0010', 0x82.
3 * 'mmm' is the message type, an unsigned 3 bit integer.
* 'vvvvv' is the version, an unsigned 5 bit integer, fixed to '00001'.
* 'seq id' is the sequence id, a signed 32 bit integer encoded as a var int.
* 'name length' is the byte length of the name field, a signed 32 bit integer encoded as a var int (must be >= 0).
* 'name' is the method name to invoke, a UTF-8 encoded string.
Message types are encoded with the following values:
* _Call_: 1
* _Reply_: 2
* _Exception_: 3
* _Oneway_: 4
*/
static int
dissect_thrift_tcp(tvbuff_t* tvb, packet_info* pinfo, proto_tree* tree, void *data)
{
int str_len, length = tvb_reported_length(tvb);
/* Need at least 13 bytes for a thrift message */
if (length < 13) {
pinfo->desegment_offset = 0;
pinfo->desegment_len = DESEGMENT_ONE_MORE_SEGMENT;
return 0;
}
str_len = tvb_get_ntohl(tvb, 4);
/* Header 8 + string + seq_id + at least 4 bytes?*/
if (length < str_len + 8 + 4 + 4) {
pinfo->desegment_offset = 0;
pinfo->desegment_len = DESEGMENT_ONE_MORE_SEGMENT;
return 0;
}
return dissect_thrift_common(tvb, pinfo, tree, data);
}
static gboolean
@ -486,28 +769,42 @@ void proto_register_thrift(void) {
&ett_thrift,
};
static ei_register_info ei[] = {
{ &ei_thrift_wrong_type,{ "thrift.wrong_type", PI_PROTOCOL, PI_ERROR, "Type value not expected", EXPFILL } },
{ &ei_thrift_struct_type_not_imp,{ "thrift.struct_type_not_imp", PI_PROTOCOL, PI_ERROR, "Struct type handling not implemented in Wireshak yet", EXPFILL } },
};
module_t *thrift_module;
expert_module_t* expert_thrift;
/* Register protocol name and description */
proto_thrift = proto_register_protocol("Thrift Protocol", "Thrift", "thrift");
expert_thrift = expert_register_protocol(proto_thrift);
/* register field array */
proto_register_field_array(proto_thrift, hf, array_length(hf));
/* register subtree array */
proto_register_subtree_array(ett, array_length(ett));
expert_register_field_array(expert_thrift, ei, array_length(ei));
/* register dissector */
thrift_handle = register_dissector("thrift", dissect_thrift_common, proto_thrift);
thrift_handle = register_dissector("thrift", dissect_thrift_tcp, 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 Metod names",
proto_thrift, FT_STRING, BASE_NONE);
prefs_register_uint_preference(thrift_module, "tls.port",
"Thrift TLS Port",
"Thrift TLS Port",
10, &thrift_tls_port);
}
void proto_reg_handoff_thrift(void) {

View File

@ -0,0 +1,72 @@
/* packet-thrift.h
*
* Wireshark - Network traffic analyzer
* By Gerald Combs <gerald@wireshark.org>
* Copyright 1998 Gerald Combs
*
* SPDX-License-Identifier: GPL-2.0+
*
* Note used by proprietarry dissectors (too).
*/
#ifndef __PACKET_THRIFT_H__
#define __PACKET_THRIFT_H__
#include "ws_symbol_export.h"
typedef enum
{
DE_THRIFT_T_STOP = 0,
DE_THRIFT_T_VOID,
DE_THRIFT_T_BOL,
DE_THRIFT_T_BYTE,
DE_THRIFT_T_DOUBLE,
DE_THRIFT_T_UNUSED_5,
DE_THRIFT_T_I16,
DE_THRIFT_T_UNUSED_7,
DE_THRIFT_T_I32,
DE_THRIFT_T_U64,
DE_THRIFT_T_I64,
DE_THRIFT_T_UTF7,
DE_THRIFT_T_STRUCT,
DE_THRIFT_T_MAP,
DE_THRIFT_T_SET,
DE_THRIFT_T_LIST,
DE_THRIFT_T_UTF8,
DE_THRIFT_T_UTF16
} trift_type_enum_t;
typedef struct _thrift_struct_t {
const int *p_id; /* The hf field for the struct member*/
int fid; /* The Thrift field id of the stuct memeber*/
trift_type_enum_t type; /* The thrift type of the struct member */
} thrift_struct_t;
/*
These functions are to be used by dissectors dissecting Thrift based protocols sinilar to packet-ber.c
*/
WS_DLL_PUBLIC int dissect_thrift_t_stop(tvbuff_t* tvb, packet_info* pinfo _U_, proto_tree* tree, int offset);
WS_DLL_PUBLIC int dissect_thrift_t_byte(tvbuff_t* tvb, packet_info* pinfo _U_, proto_tree* tree, int offset, int field_id _U_, gint hf_id);
WS_DLL_PUBLIC int dissect_thrift_t_i32(tvbuff_t* tvb, packet_info* pinfo _U_, proto_tree* tree, int offset, int field_id _U_, gint hf_id);
WS_DLL_PUBLIC int dissect_thrift_t_utf7(tvbuff_t* tvb, packet_info* pinfo _U_, proto_tree* tree, int offset, int field_id _U_, gint hf_id);
/** Dissect a Thrift struct
* Dissect a Thrift struct by calling the struct member dissector in turn from the thrift_struct_t array
*
* @param[in] tvb tvb with the thrift data
* @param[in] pinfo The packet info struct
* @param[in] tree the packet tree
* @param[in] offset the offset where to start dissection in the given tvb
* @param[in] seq an array of thrift_struct_t's containing thrift type of the struct members the hf variable to use etc.
* @param[in] field_id the Thrift field id of the struct
* @param[in] hf_id a header field of FT_BYTES which will be the struct header field
* @param[in] ett_id an ett field used for the subtree created to list the struct members.
* @return The number of bytes dissected.
*/
WS_DLL_PUBLIC int dissect_thrift_t_struct(tvbuff_t* tvb, packet_info* pinfo, proto_tree* tree, int offset, const thrift_struct_t *seq,
int field_id _U_, gint hf_id, gint ett_id);
#endif /*__PACKET_THRIFT_H__ */