[skinny]: Added conversation and request_response handling

Improvements:
 - added conversation
 - added request/response handling

Change-Id: Ia670eb23c0671b195108876a30ff3ff5eb4a152c
Reviewed-on: https://code.wireshark.org/review/20094
Reviewed-by: Alexis La Goutte <alexis.lagoutte@gmail.com>
Petri-Dish: Alexis La Goutte <alexis.lagoutte@gmail.com>
Tested-by: Petri Dish Buildbot <buildbot-no-reply@wireshark.org>
Reviewed-by: Anders Broman <a.broman58@gmail.com>
This commit is contained in:
Diederik de Groot 2017-02-13 17:50:53 +01:00 committed by Anders Broman
parent e6c51e7bad
commit 9a22102d35
6 changed files with 1438 additions and 759 deletions

File diff suppressed because it is too large Load Diff

View File

@ -59,6 +59,9 @@ cog.out(' */\n')
#include <epan/packet.h>
#include <epan/prefs.h>
#include <epan/conversation.h>
#include <epan/wmem/wmem.h>
#include <epan/to_str.h>
#include <epan/reassemble.h>
#include <epan/tap.h>
#include <epan/ptvcursor.h>
@ -68,6 +71,10 @@ cog.out(' */\n')
#include "packet-ssl.h"
#include "packet-skinny.h"
/* un-comment the following as well as this line in conversation.c, to enable debug printing */
/* #define DEBUG_CONVERSATION */
#include "conversation_debug.h"
void proto_register_skinny(void);
void proto_reg_handoff_skinny(void);
@ -113,7 +120,7 @@ global message_dissector_functions
message_dissector_functions = ''
skinny = xml2skinny.xml2obj(xmlfile)
cog.out('static const value_string message_id[] = {\n')
cog.out('static const value_string message_id[] = {\n')
for message in skinny.message:
message_dissector_functions += '%s' %message.dissect()
cog.out(' { %s, "%s" },\n' %(message.opcode, message.name.replace('Message','')))
@ -123,7 +130,6 @@ cog.out('static value_string_ext message_id_ext = VALUE_STRING_EXT_INIT(message_
]]]*/
/*[[[end]]]*/
/* Declare Enums and Defines */
/* [[[cog
for enum in skinny.enum:
@ -156,6 +162,9 @@ static int hf_skinny_data_length = -1;
static int hf_skinny_hdr_version = -1;
static int hf_skinny_xmlData = -1;
static int hf_skinny_ipv4or6 = -1;
static int hf_skinny_response_in = -1;
static int hf_skinny_response_to = -1;
static int hf_skinny_response_time = -1;
/* [[[cog
for key in sorted(xml2skinny.fieldsArray.keys()):
@ -305,23 +314,93 @@ dissect_skinny_displayLabel(ptvcursor_t *cursor, int hfindex, gint length)
ptvcursor_advance(cursor, length);
}
/*** Messages Handlers ***/
/*** Request / Response helper functions */
static void skinny_reqrep_add_request(ptvcursor_t *cursor, packet_info * pinfo, skinny_conv_info_t * skinny_conv, const int request_key)
{
proto_tree *tree = ptvcursor_tree(cursor);
tvbuff_t *tvb = ptvcursor_tvbuff(cursor);
skinny_req_resp_t *req_resp = NULL;
if (!PINFO_FD_VISITED(pinfo)) {
req_resp = wmem_new0(wmem_file_scope(), skinny_req_resp_t);
req_resp->request_frame = pinfo->num;
req_resp->response_frame = 0;
req_resp->request_time = pinfo->fd->abs_ts;
wmem_map_insert(skinny_conv->pending_req_resp, GINT_TO_POINTER(request_key), (void *)req_resp);
DPRINT(("SKINNY: setup_request: frame=%d add key=%d to map\n", pinfo->num, request_key));
}
req_resp = (skinny_req_resp_t *) wmem_map_lookup(skinny_conv->requests, GUINT_TO_POINTER(pinfo->num));
if (req_resp && req_resp->response_frame) {
DPRINT(("SKINNY: show request in tree: frame/key=%d\n", pinfo->num));
proto_item *it;
it = proto_tree_add_uint(tree, hf_skinny_response_in, tvb, 0, 0, req_resp->response_frame);
PROTO_ITEM_SET_GENERATED(it);
} else {
DPRINT(("SKINNY: no request found for frame/key=%d\n", pinfo->num));
}
}
static void skinny_reqrep_add_response(ptvcursor_t *cursor, packet_info * pinfo, skinny_conv_info_t * skinny_conv, const int request_key)
{
proto_tree *tree = ptvcursor_tree(cursor);
tvbuff_t *tvb = ptvcursor_tvbuff(cursor);
skinny_req_resp_t *req_resp = NULL;
if (!PINFO_FD_VISITED(pinfo)) {
req_resp = (skinny_req_resp_t *) wmem_map_remove(skinny_conv->pending_req_resp, GINT_TO_POINTER(request_key));
if (req_resp) {
DPRINT(("SKINNY: match request:%d with response:%d for key=%d\n", req_resp->request_frame, pinfo->num, request_key));
req_resp->response_frame = pinfo->num;
wmem_map_insert(skinny_conv->requests, GUINT_TO_POINTER(req_resp->request_frame), (void *)req_resp);
wmem_map_insert(skinny_conv->responses, GUINT_TO_POINTER(pinfo->num), (void *)req_resp);
} else {
DPRINT(("SKINNY: no match found for reponse frame=%d and key=%d\n", pinfo->num, request_key));
}
}
req_resp = (skinny_req_resp_t *) wmem_map_lookup(skinny_conv->responses, GUINT_TO_POINTER(pinfo->num));
if (req_resp && req_resp->request_frame) {
DPRINT(("SKINNY: show response in tree: frame/key=%d\n", pinfo->num));
proto_item *it;
nstime_t ns;
it = proto_tree_add_uint(tree, hf_skinny_response_to, tvb, 0, 0, req_resp->request_frame);
PROTO_ITEM_SET_GENERATED(it);
nstime_delta(&ns, &pinfo->fd->abs_ts, &req_resp->request_time);
it = proto_tree_add_time(tree, hf_skinny_response_time, tvb, 0, 0, &ns);
PROTO_ITEM_SET_GENERATED(it);
} else {
DPRINT(("SKINNY: no response found for frame/key=%d\n", pinfo->num));
}
}
/*** Messages Handlers ***/
/* [[[cog
cog.out(message_dissector_functions)
]]]*/
/*[[[end]]]*/
typedef void (*message_handler) (ptvcursor_t * cursor, packet_info *pinfo, skinny_conv_info_t * skinny_conv);
typedef struct _skinny_opcode_map_t {
guint32 opcode;
message_handler handler;
skinny_message_type_t type;
const char *name;
} skinny_opcode_map_t;
/* Messages Handler Array */
/* [[[cog
cog.out('typedef void (*message_handler) (ptvcursor_t * cursor, packet_info *pinfo);\n')
cog.out('static const struct opcode2handler {\n')
cog.out(' guint16 opcode;\n');
cog.out(' message_handler handler;\n');
cog.out(' const char *name;\n');
cog.out('} skinny_opcode2handler[] = {\n')
cog.out('static const skinny_opcode_map_t skinny_opcode_map[] = {\n')
for message in skinny.message:
cog.out(' {%-6s, %-47s, "%s"},\n' %(message.opcode, message.gen_handler(), message.name))
msg_type = "SKINNY_MSGTYPE_EVENT"
if message.msgtype == "request":
msg_type = "SKINNY_MSGTYPE_REQUEST"
if message.msgtype == "response" and message.request is not None:
msg_type = "SKINNY_MSGTYPE_RESPONSE"
cog.out(' {%-6s, %-47s, %-24s, "%s"},\n' %(message.opcode, message.gen_handler(), msg_type, message.name))
cog.out('};\n')
]]]*/
/*[[[end]]]*/
@ -332,11 +411,14 @@ static int dissect_skinny_pdu(tvbuff_t *tvb, packet_info *pinfo, proto_tree *tre
guint offset = 0;
/*gboolean is_video = FALSE;*/ /* FIX ME: need to indicate video or not */
ptvcursor_t* cursor;
conversation_t *conversation;
skinny_conv_info_t *skinny_conv;
const skinny_opcode_map_t *opcode_entry = NULL;
/* Header fields */
guint32 hdr_data_length;
guint32 hdr_version;
guint32 data_messageid;
guint32 hdr_opcode;
guint16 i;
/* Set up structures we will need to add the protocol subtree and manage it */
@ -346,9 +428,29 @@ static int dissect_skinny_pdu(tvbuff_t *tvb, packet_info *pinfo, proto_tree *tre
/* Initialization */
hdr_data_length = tvb_get_letohl(tvb, 0);
hdr_version = tvb_get_letohl(tvb, 4);
data_messageid = tvb_get_letohl(tvb, 8);
hdr_opcode = tvb_get_letohl(tvb, 8);
for (i = 0; i < sizeof(skinny_opcode_map)/sizeof(skinny_opcode_map_t) ; i++) {
if (skinny_opcode_map[i].opcode == hdr_opcode) {
opcode_entry = &skinny_opcode_map[i];
}
}
conversation = find_or_create_conversation(pinfo);
skinny_conv = (skinny_conv_info_t *)conversation_get_proto_data(conversation, proto_skinny);
if (!skinny_conv) {
skinny_conv = wmem_new0(wmem_file_scope(), skinny_conv_info_t);
//skinny_conv->pending_req_resp = wmem_map_new(wmem_file_scope(), wmem_str_hash, g_str_equal);
skinny_conv->pending_req_resp = wmem_map_new(wmem_file_scope(), g_direct_hash, g_direct_equal);
skinny_conv->requests = wmem_map_new(wmem_file_scope(), g_direct_hash, g_direct_equal);
skinny_conv->responses = wmem_map_new(wmem_file_scope(), g_direct_hash, g_direct_equal);
skinny_conv->lineId = -1;
skinny_conv->mtype = SKINNY_MSGTYPE_EVENT;
conversation_add_proto_data(conversation, proto_skinny, skinny_conv);
}
/* Initialise stat info for passing to tap */
/* WIP: will be (partially) replaced in favor of conversionation, dependents: ui/voip_calls.c */
pi_current++;
if (pi_current == MAX_SKINNY_MESSAGES_IN_PACKET)
{
@ -356,13 +458,12 @@ static int dissect_skinny_pdu(tvbuff_t *tvb, packet_info *pinfo, proto_tree *tre
pi_current = 0;
}
si = &pi_arr[pi_current];
si->messId = data_messageid;
si->messageName = val_to_str_ext(data_messageid, &message_id_ext, "0x%08X (Unknown)");
si->messId = hdr_opcode;
si->messageName = val_to_str_ext(hdr_opcode, &message_id_ext, "0x%08X (Unknown)");
si->callId = 0;
si->lineId = -1;
si->lineId = 0;
si->passThruId = 0;
si->callState = 0;
si->hasCallInfo = FALSE;
g_free(si->callingParty);
si->callingParty = NULL;
g_free(si->calledParty);
@ -373,27 +474,33 @@ static int dissect_skinny_pdu(tvbuff_t *tvb, packet_info *pinfo, proto_tree *tre
si->multimediaTransmissionStatus = -1;
si->multicastReceptionStatus = -1;
/* In the interest of speed, if "tree" is NULL, don't do any work not
* necessary to generate protocol tree items.
*/
if (tree) {
ti = proto_tree_add_item(tree, proto_skinny, tvb, offset, hdr_data_length+8, ENC_NA);
skinny_tree = proto_item_add_subtree(ti, ett_skinny);
proto_tree_add_uint(skinny_tree, hf_skinny_data_length, tvb, offset, 4, hdr_data_length);
proto_tree_add_uint(skinny_tree, hf_skinny_hdr_version, tvb, offset+4, 4, hdr_version);
}
col_add_fstr(pinfo->cinfo, COL_INFO,"%s ", si->messageName);
col_set_fence(pinfo->cinfo, COL_INFO);
proto_tree_add_uint(skinny_tree, hf_skinny_messageId, tvb,offset+8, 4, data_messageid );
if (tree) {
ti = proto_tree_add_item(tree, proto_skinny, tvb, offset, hdr_data_length+8, ENC_NA);
skinny_tree = proto_item_add_subtree(ti, ett_skinny);
}
if (opcode_entry && opcode_entry->type != SKINNY_MSGTYPE_EVENT) {
skinny_conv->mtype = opcode_entry->type;
if (opcode_entry->type == SKINNY_MSGTYPE_REQUEST) {
col_set_str(pinfo->cinfo, COL_PROTOCOL, "SKINNY/REQ");
} else {
col_set_str(pinfo->cinfo, COL_PROTOCOL, "SKINNY/RESP");
}
}
if (skinny_tree) {
proto_tree_add_uint(skinny_tree, hf_skinny_data_length, tvb, offset , 4, hdr_data_length);
proto_tree_add_uint(skinny_tree, hf_skinny_hdr_version, tvb, offset+4, 4, hdr_version);
proto_tree_add_uint(skinny_tree, hf_skinny_messageId, tvb, offset+8, 4, hdr_opcode );
}
offset += 12;
cursor = ptvcursor_new(skinny_tree, tvb, offset);
for (i = 0; i < sizeof(skinny_opcode2handler)/sizeof(struct opcode2handler) ; i++) {
if (skinny_opcode2handler[i].opcode == data_messageid && skinny_opcode2handler[i].handler) {
skinny_opcode2handler[i].handler(cursor, pinfo);
}
if (opcode_entry && opcode_entry->handler) {
opcode_entry->handler(cursor, pinfo, skinny_conv);
}
ptvcursor_free(cursor);
@ -480,6 +587,18 @@ proto_register_skinny(void)
{
"IPv4or6", "skinny.ipv4or6", FT_UINT32, BASE_DEC|BASE_EXT_STRING, &IpAddrType_ext, 0x0,
NULL, HFILL }},
{ &hf_skinny_response_in,
{
"Response In", "skinny.response_in", FT_FRAMENUM, BASE_NONE, FRAMENUM_TYPE(FT_FRAMENUM_RESPONSE), 0x0,
"The response to this SKINNY request is in this frame", HFILL }},
{ &hf_skinny_response_to,
{
"Request In", "skinny.response_to", FT_FRAMENUM, BASE_NONE, FRAMENUM_TYPE(FT_FRAMENUM_REQUEST), 0x0,
"This is a response to the SKINNY request in this frame", HFILL }},
{ &hf_skinny_response_time,
{
"Response Time", "skinny.response_time", FT_RELATIVE_TIME, BASE_NONE, NULL, 0x0,
"The time between the Call and the Reply", HFILL }},
/* [[[cog
for valuestr in sorted(xml2skinny.fieldsArray.values()):
cog.out('%s' %valuestr)

View File

@ -37,24 +37,55 @@
* cog.py -D xmlfile=tools/SkinnyProtocolOptimized.xml -d -c -o epan/dissectors/packet-skinny.c epan/dissectors/packet-skinny.c.in
*/
/* Container for tapping relevant data */
#include <epan/wmem/wmem.h>
/* request response tracking */
typedef struct _skinny_req_resp_t {
guint32 request_frame;
guint32 response_frame;
nstime_t request_time;
} skinny_req_resp_t;
/* begin conversaton info*/
typedef enum _skinny_message_type_t {
SKINNY_MSGTYPE_EVENT = 0,
SKINNY_MSGTYPE_REQUEST = 1,
SKINNY_MSGTYPE_RESPONSE = 2,
} skinny_message_type_t;
typedef struct _skinny_conv_info_t {
skinny_message_type_t mtype;
wmem_map_t * pending_req_resp;
wmem_map_t * requests;
wmem_map_t * responses;
gint32 lineId;
//guint32 callId;
//guint32 passThruId;
//guint32 transactionId;
//guint32 callState;
} skinny_conv_info_t;
/* end conversation info */
/* Containers for tapping relevant data */
/* WIP: will be (partially) replaced in favor of conversionation, dependents: ui/voip_calls.c */
typedef struct _skinny_info_t
{
guint32 messId;
guint32 maxProtocolVersion;
gint32 lineId;
guint32 callId;
guint32 passThruId;
const gchar * messageName;
guint32 callState;
gboolean hasCallInfo;
gchar * callingParty;
gchar * calledParty;
gint32 mediaReceptionStatus;
gint32 mediaTransmissionStatus;
gint32 multimediaReceptionStatus;
gint32 multimediaTransmissionStatus;
gint32 multicastReceptionStatus;
guint32 messId;
guint32 maxProtocolVersion;
gint32 lineId;
guint32 callId;
guint32 passThruId;
const gchar * messageName;
guint32 callState;
gboolean hasCallInfo;
gchar * callingParty;
gchar * calledParty;
gint32 mediaReceptionStatus;
gint32 mediaTransmissionStatus;
gint32 multimediaReceptionStatus;
gint32 multimediaTransmissionStatus;
gint32 multicastReceptionStatus;
//skinny_conv_info_t * skinny_conv;
} skinny_info_t;
/*

View File

@ -49,24 +49,55 @@ cog.out(' */\n')
/*]]]*/
/*[[[end]]]*/
/* Container for tapping relevant data */
#include <epan/wmem/wmem.h>
/* request response tracking */
typedef struct _skinny_req_resp_t {
guint32 request_frame;
guint32 response_frame;
nstime_t request_time;
} skinny_req_resp_t;
/* begin conversaton info*/
typedef enum _skinny_message_type_t {
SKINNY_MSGTYPE_EVENT = 0,
SKINNY_MSGTYPE_REQUEST = 1,
SKINNY_MSGTYPE_RESPONSE = 2,
} skinny_message_type_t;
typedef struct _skinny_conv_info_t {
skinny_message_type_t mtype;
wmem_map_t * pending_req_resp;
wmem_map_t * requests;
wmem_map_t * responses;
gint32 lineId;
//guint32 callId;
//guint32 passThruId;
//guint32 transactionId;
//guint32 callState;
} skinny_conv_info_t;
/* end conversation info */
/* Containers for tapping relevant data */
/* WIP: will be (partially) replaced in favor of conversionation, dependents: ui/voip_calls.c */
typedef struct _skinny_info_t
{
guint32 messId;
guint32 maxProtocolVersion;
gint32 lineId;
guint32 callId;
guint32 passThruId;
const gchar * messageName;
guint32 callState;
gboolean hasCallInfo;
gchar * callingParty;
gchar * calledParty;
gint32 mediaReceptionStatus;
gint32 mediaTransmissionStatus;
gint32 multimediaReceptionStatus;
gint32 multimediaTransmissionStatus;
gint32 multicastReceptionStatus;
guint32 messId;
guint32 maxProtocolVersion;
gint32 lineId;
guint32 callId;
guint32 passThruId;
const gchar * messageName;
guint32 callState;
gboolean hasCallInfo;
gchar * callingParty;
gchar * calledParty;
gint32 mediaReceptionStatus;
gint32 mediaTransmissionStatus;
gint32 multimediaReceptionStatus;
gint32 multimediaTransmissionStatus;
gint32 multicastReceptionStatus;
//skinny_conv_info_t * skinny_conv;
} skinny_info_t;
/*

File diff suppressed because it is too large Load Diff

View File

@ -128,6 +128,14 @@ def xml2obj(src):
def getfieldnames(self):
return ''
def get_req_resp_keys(self, req_resp_keys):
return []
def get_req_resp_key(self):
if self.req_resp_key == "1":
return self.name
return None
def declaration(self):
global fieldsArray
if self.name not in fieldsArray:
@ -177,16 +185,18 @@ def xml2obj(src):
ret += self.indent_out("/*\n")
ret += self.indent_out(" * Message: %s\n" %self.name)
ret += self.indent_out(" * Opcode: %s\n" %self.opcode)
ret += self.indent_out(" * Type: %s\n" %self.type)
ret += self.indent_out(" * Type: %s\n" %self.type)
ret += self.indent_out(" * Direction: %s\n" %self.direction)
ret += self.indent_out(" * VarLength: %s\n" %self.dynamic)
ret += self.indent_out(" * MsgType: %s\n" %self.msgtype)
if self.comment:
ret += self.indent_out(" * Comment: %s\n" %self.comment)
ret += self.indent_out(" */\n")
ret += self.indent_out("static void\n")
ret += self.indent_out("handle_%s(ptvcursor_t *cursor, packet_info * pinfo _U_)\n" %self.name)
ret += self.indent_out("handle_%s(ptvcursor_t *cursor, packet_info * pinfo _U_, skinny_conv_info_t * skinny_conv _U_)\n" %self.name)
ret += self.indent_out("{\n")
self.incr_indent()
for fields in self.fields:
if fields.size_lt or fields.size_gt:
if self.basemessage.declared is None or "hdr_data_length" not in self.basemessage.declared:
@ -202,7 +212,10 @@ def xml2obj(src):
ret += self.indent_out("guint32 hdr_version = tvb_get_letohl(ptvcursor_tvbuff(cursor), 4);\n")
self.basemessage.declared.append("hdr_version")
declarations += 1
req_resp_keys = []
for fields in self.fields:
fields.get_req_resp_keys(req_resp_keys)
ret += '%s' %fields.declaration()
declarations += 1
@ -213,6 +226,19 @@ def xml2obj(src):
for fields in self.fields:
ret += '%s' %fields.dissect()
# setup request/response
if self.msgtype == "request":
if req_resp_keys and req_resp_keys[0] != '':
ret += self.indent_out('skinny_reqrep_add_request(cursor, pinfo, skinny_conv, %s ^ %s);\n' %(self.opcode, req_resp_keys[0]))
else:
ret += self.indent_out('skinny_reqrep_add_request(cursor, pinfo, skinny_conv, %s);\n' %(self.opcode))
if self.msgtype == "response":
if req_resp_keys and req_resp_keys[0] != '':
ret += self.indent_out('skinny_reqrep_add_response(cursor, pinfo, skinny_conv, %s ^ %s);\n' %(self.request, req_resp_keys[0]))
else:
ret += self.indent_out('skinny_reqrep_add_response(cursor, pinfo, skinny_conv, %s);\n' %(self.request))
self.decr_indent()
ret += "}\n\n"
@ -222,6 +248,12 @@ def xml2obj(src):
''' Fields '''
size_fieldnames= []
def get_req_resp_keys(self, req_resp):
for field in self._children:
key = field.get_req_resp_key()
if not key is None and not key in req_resp:
req_resp.append(key)
def declaration(self):
ret = ''
@ -474,6 +506,11 @@ def xml2obj(src):
def __str__(self):
return '%s:%s' %(self.__class__,self.name)
def get_req_resp_key(self):
if self.req_resp_key == "1":
return 'wmem_str_hash(%s)' %self.name
return None
def declaration(self):
ret = ''
self.intsize = 0
@ -494,10 +531,10 @@ def xml2obj(src):
self.basemessage.declared.append("hdr_version")
ret += self.indent_out('guint32 VariableDirnumSize = (hdr_version >= V18_MSG_TYPE) ? 25 : 24;\n')
self.basemessage.declared.append("VariableDirnumSize")
else:
if self.basemessage.declared is None or self.name not in self.basemessage.declared:
ret += self.indent_out('guint32 %s = 0;\n' %self.name)
self.basemessage.declared.append(self.name)
#else:
# if self.basemessage.declared is None or self.name not in self.basemessage.declared:
# ret += self.indent_out('gchar *%s = NULL;\n' %self.name)
# self.basemessage.declared.append(self.name)
if self.basemessage.dynamic == "yes" and not self.subtype == "DisplayLabel":
if self.basemessage.declared is None or self.name + '_len' not in self.basemessage.declared:
@ -513,7 +550,7 @@ def xml2obj(src):
ret = ''
if self.declare == "yes" and self.size != "VariableDirnumSize":
ret += self.indent_out('%s = tvb_get_letohl(ptvcursor_tvbuff(cursor), 4);\n' %self.name)
ret += self.indent_out('const gchar * %s = g_strdup(tvb_format_stringzpad(ptvcursor_tvbuff(cursor), ptvcursor_current_offset(cursor), %s));\n' %(self.name, self.size))
if self.subtype == "DisplayLabel":
if self.basemessage.dynamic == "yes":