1/* Do not modify this file. Changes will be overwritten */ 2/* Generated Automatically */ 3/* packet-skinny.c */ 4 5/* packet-skinny.c 6 * Dissector for the Skinny Client Control Protocol 7 * (The "D-Channel"-Protocol for Cisco Systems' IP-Phones) 8 * 9 * Author: Diederik de Groot <ddegroot@user.sf.net>, Copyright 2014 10 * Rewritten to support newer skinny protocolversions (V0-V22) 11 * Based on previous versions/contributions: 12 * - Joerg Mayer <jmayer@loplof.de>, Copyright 2001 13 * - Paul E. Erkkila (pee@erkkila.org) - fleshed out the decode 14 * skeleton to report values for most message/message fields. 15 * Much help from Guy Harris on figuring out the wireshark api. 16 * - packet-aim.c by Ralf Hoelzer <ralf@well.com>, Copyright 2000 17 * - Wireshark - Network traffic analyzer, 18 * By Gerald Combs <gerald@wireshark.org>, Copyright 1998 19 * 20 * SPDX-License-Identifier: GPL-2.0-or-later 21 */ 22 23/* [[[cog 24# 25# Using Cog.py Inplace Code Generator 26# 27# Dependencies: 28# - python2.x 29# - cog.py: (pip install cogapp / http://nedbatchelder.com/code/cog/) 30# - python.xml 31# - python.xml.sax 32# 33cog.out('/*\n') 34cog.out(' * Generated Automatically Using (from wireshark base directory):\n') 35cog.out(' * cog.py -D xmlfile=tools/SkinnyProtocolOptimized.xml -d -c -o epan/dissectors/packet-skinny.c epan/dissectors/packet-skinny.c.in\n') 36cog.out(' */\n') 37/*]]]*/ 38/*[[[end]]]*/ 39 40/* c-basic-offset: 2; tab-width: 8; indent-tabs-mode: nil 41 * vi: set shiftwidth=2 tabstop=8 expandtab: 42 * :indentSize=2:tabSize=8:noTabs=true: 43 */ 44 45 46#include "config.h" 47 48#include <epan/packet.h> 49#include <epan/prefs.h> 50#include <epan/conversation.h> 51#include <epan/wmem_scopes.h> 52#include <epan/to_str.h> 53#include <epan/reassemble.h> 54#include <epan/tap.h> 55#include <epan/ptvcursor.h> 56 57#include "packet-rtp.h" 58#include "packet-tcp.h" 59#include "packet-tls.h" 60#include "packet-skinny.h" 61 62/* un-comment the following as well as this line in conversation.c, to enable debug printing */ 63/* #define DEBUG_CONVERSATION */ 64#include "conversation_debug.h" 65 66void proto_register_skinny(void); 67void proto_reg_handoff_skinny(void); 68 69#define TCP_PORT_SKINNY 2000 /* Not IANA registered */ 70#define SSL_PORT_SKINNY 2443 /* IANA assigned to PowerClient Central Storage Facility */ 71 72#define BASIC_MSG_TYPE 0x00 73#define V10_MSG_TYPE 0x0A 74#define V11_MSG_TYPE 0x0B 75#define V15_MSG_TYPE 0x0F 76#define V16_MSG_TYPE 0x10 77#define V17_MSG_TYPE 0x11 78#define V18_MSG_TYPE 0x12 79#define V19_MSG_TYPE 0x13 80#define V20_MSG_TYPE 0x14 81#define V21_MSG_TYPE 0x15 82#define V22_MSG_TYPE 0x16 83 84static const value_string header_version[] = { 85 { BASIC_MSG_TYPE, "Basic" }, 86 { V10_MSG_TYPE, "V10" }, 87 { V11_MSG_TYPE, "V11" }, 88 { V15_MSG_TYPE, "V15" }, 89 { V16_MSG_TYPE, "V16" }, 90 { V17_MSG_TYPE, "V17" }, 91 { V18_MSG_TYPE, "V18" }, 92 { V19_MSG_TYPE, "V19" }, 93 { V20_MSG_TYPE, "V20" }, 94 { V21_MSG_TYPE, "V21" }, 95 { V22_MSG_TYPE, "V22" }, 96 { 0 , NULL } 97}; 98 99/* Declare MessageId */ 100/* [[[cog 101import sys 102sys.path.append('tools/') 103 104import parse_xml2skinny_dissector as xml2skinny 105global skinny 106global message_dissector_functions 107 108message_dissector_functions = '' 109skinny = xml2skinny.xml2obj(xmlfile) 110 111cog.out('static const value_string message_id[] = {\n') 112for message in skinny.message: 113 message_dissector_functions += '%s' %message.dissect() 114 cog.out(' { %s, "%s" },\n' %(message.opcode, message.name.replace('Message',''))) 115cog.out(' {0 , NULL}\n') 116cog.out('};\n') 117cog.out('static value_string_ext message_id_ext = VALUE_STRING_EXT_INIT(message_id);\n') 118/*]]]*/ 119/*[[[end]]]*/ 120 121/* Declare Enums and Defines */ 122/* [[[cog 123for enum in skinny.enum: 124 name = enum.name[0].upper() + enum.name[1:] 125 if enum.define == "yes": 126 for entries in enum.entries: 127 for entry in sorted(entries.entry, key=lambda x: int(x['value'],0)): 128 if entries.type is not None: 129 cog.out('#define {0:38} 0x{1:05x} /* {2} */\n' .format(entry.name.upper(), int(entry.value,0), entries.type)) 130 else: 131 cog.out('#define {0:38} 0x{1:05x}\n' .format(entry.name.upper(), int(entry.value,0))) 132 cog.out('\n') 133 cog.out('static const value_string %s[] = {\n' %(name)) 134 for entries in enum.entries: 135 for entry in sorted(entries.entry, key=lambda x: int(x['value'],0)): 136 if enum.define == "yes": 137 cog.out(' { %s, "%s" },\n' %(entry.name.upper(), entry.text)) 138 else: 139 cog.out(' { 0x%05x, "%s" },\n' %(int(entry.value,0), entry.text)) 140 cog.out(' { 0x00000, NULL }\n') 141 cog.out('};\n') 142 cog.out('static value_string_ext %s_ext = VALUE_STRING_EXT_INIT(%s);\n\n' %(name, name)) 143/*]]]*/ 144/*[[[end]]]*/ 145 146/* Staticly Declared Variables */ 147static int proto_skinny = -1; 148static int hf_skinny_messageId = -1; 149static int hf_skinny_data_length = -1; 150static int hf_skinny_hdr_version = -1; 151static int hf_skinny_xmlData = -1; 152static int hf_skinny_ipv4or6 = -1; 153static int hf_skinny_response_in = -1; 154static int hf_skinny_response_to = -1; 155static int hf_skinny_response_time = -1; 156 157/* [[[cog 158for key in sorted(xml2skinny.fieldsArray.keys()): 159 cog.out('static int hf_skinny_%s = -1;\n' %key) 160]]]*/ 161/*[[[end]]]*/ 162 163static dissector_handle_t xml_handle; 164 165/* Initialize the subtree pointers */ 166static gint ett_skinny = -1; 167static gint ett_skinny_tree = -1; 168 169/* preference globals */ 170static gboolean global_skinny_desegment = TRUE; 171 172/* tap register id */ 173static int skinny_tap = -1; 174 175/* skinny protocol tap info */ 176#define MAX_SKINNY_MESSAGES_IN_PACKET 10 177static skinny_info_t pi_arr[MAX_SKINNY_MESSAGES_IN_PACKET]; 178static int pi_current = 0; 179static skinny_info_t *si; 180 181dissector_handle_t skinny_handle; 182 183/* Get the length of a single SKINNY PDU */ 184static guint 185get_skinny_pdu_len(packet_info *pinfo _U_, tvbuff_t *tvb, int offset, void *data _U_) 186{ 187 guint32 hdr_data_length; 188 189 /* Get the length of the SKINNY packet. */ 190 hdr_data_length = tvb_get_letohl(tvb, offset); 191 192 /* That length doesn't include the length of the header itself. */ 193 return hdr_data_length + 8; 194} 195 196static void 197dissect_skinny_xml(ptvcursor_t *cursor, int hfindex, packet_info *pinfo, guint32 length, guint32 maxlength) 198{ 199 proto_item *item = NULL; 200 proto_tree *subtree = NULL; 201 proto_tree *tree = ptvcursor_tree(cursor); 202 guint32 offset = ptvcursor_current_offset(cursor); 203 tvbuff_t *tvb = ptvcursor_tvbuff(cursor); 204 tvbuff_t *next_tvb; 205 206 if (length == 0) { 207 length = tvb_strnlen(tvb, offset, -1); 208 } 209 if (length >= maxlength) { 210 length = maxlength; 211 } 212 213 ptvcursor_add_no_advance(cursor, hfindex, length, ENC_ASCII|ENC_NA); 214 215 item = proto_tree_add_item(tree, hf_skinny_xmlData, tvb, offset, length, ENC_ASCII|ENC_NA); 216 subtree = proto_item_add_subtree(item, 0); 217 next_tvb = tvb_new_subset_length_caplen(tvb, offset, length, -1); 218 if (xml_handle != NULL) { 219 call_dissector(xml_handle, next_tvb, pinfo, subtree); 220 } 221 ptvcursor_advance(cursor, maxlength); 222} 223 224static void 225dissect_skinny_ipv4or6(ptvcursor_t *cursor, int hfindex_ipv4, int hfindex_ipv6) 226{ 227 guint32 ipversion = 0; 228 guint32 offset = ptvcursor_current_offset(cursor); 229 tvbuff_t *tvb = ptvcursor_tvbuff(cursor); 230 guint32 hdr_version = tvb_get_letohl(tvb, 4); 231 232 /* ProtocolVersion > 18 include and extra field to declare IPv4 (0) / IPv6 (1) */ 233 if (hdr_version >= V17_MSG_TYPE) { 234 ipversion = tvb_get_letohl(tvb, offset); 235 ptvcursor_add(cursor, hf_skinny_ipv4or6, 4, ENC_LITTLE_ENDIAN); 236 } 237 if (ipversion == IPADDRTYPE_IPV4) { 238 ptvcursor_add(cursor, hfindex_ipv4, 4, ENC_BIG_ENDIAN); 239 if (hdr_version >= V17_MSG_TYPE) { 240 /* skip over the extra room for ipv6 addresses */ 241 ptvcursor_advance(cursor, 12); 242 } 243 } else if (ipversion == IPADDRTYPE_IPV6 || ipversion == IPADDRTYPE_IPV4_V6) { 244 ptvcursor_add(cursor, hfindex_ipv6, 16, ENC_NA); 245 } else { 246 /* Invalid : skip over ipv6 space completely */ 247 ptvcursor_advance(cursor, 16); 248 } 249} 250 251/* Reads address to provided variable */ 252static void 253read_skinny_ipv4or6(ptvcursor_t *cursor, address *media_addr) 254{ 255 guint32 ipversion = IPADDRTYPE_IPV4; 256 guint32 offset = ptvcursor_current_offset(cursor); 257 guint32 offset2 = 0; 258 tvbuff_t *tvb = ptvcursor_tvbuff(cursor); 259 guint32 hdr_version = tvb_get_letohl(tvb, 4); 260 261 /* ProtocolVersion > 18 include and extra field to declare IPv4 (0) / IPv6 (1) */ 262 if (hdr_version >= V17_MSG_TYPE) { 263 ipversion = tvb_get_letohl(tvb, offset); 264 offset2 = 4; 265 } 266 if (ipversion == IPADDRTYPE_IPV4) { 267 set_address_tvb(media_addr, AT_IPv4, 4, tvb, offset+offset2); 268 } else if (ipversion == IPADDRTYPE_IPV6 || ipversion == IPADDRTYPE_IPV4_V6) { 269 set_address_tvb(media_addr, AT_IPv6, 16, tvb, offset+offset2); 270 } else { 271 clear_address(media_addr); 272 } 273} 274 275/** 276 * Parse a displayLabel string and check if it is using any embedded labels, if so lookup the label and add a user readable translation to the item_tree 277 */ 278static void 279dissect_skinny_displayLabel(ptvcursor_t *cursor, packet_info *pinfo, int hfindex, gint length) 280{ 281 proto_item *item = NULL; 282 proto_tree *tree = ptvcursor_tree(cursor); 283 guint32 offset = ptvcursor_current_offset(cursor); 284 tvbuff_t *tvb = ptvcursor_tvbuff(cursor); 285 wmem_strbuf_t *wmem_new = NULL; 286 gchar *disp_string = NULL; 287 const gchar *replacestr = NULL; 288 gboolean show_replaced_str = FALSE; 289 gint x = 0; 290 291 if (length == 0) { 292 length = tvb_strnlen(tvb, offset, -1); 293 if (length == -1) { 294 /* did not find end of string */ 295 length = tvb_captured_length_remaining(tvb, offset); 296 } 297 } 298 299 item = proto_tree_add_item(tree, hfindex, tvb, offset, length, ENC_ASCII | ENC_NA); 300 301 wmem_new = wmem_strbuf_sized_new(pinfo->pool, length + 1, 0); 302 disp_string = (gchar*) wmem_alloc(pinfo->pool, length + 1); 303 disp_string[length] = '\0'; 304 tvb_memcpy(tvb, (void*)disp_string, offset, length); 305 306 for (x = 0; x < length && disp_string[x] != '\0'; x++) { 307 replacestr = NULL; 308 if (x + 1 < length) { 309 if (disp_string[x] == '\36') { 310 replacestr = try_val_to_str_ext(disp_string[x + 1], &DisplayLabels_36_ext); 311 } else if (disp_string[x] == '\200') { 312 replacestr = try_val_to_str_ext(disp_string[x + 1], &DisplayLabels_200_ext); 313 } 314 } 315 if (replacestr) { 316 x++; /* swallow replaced characters */ 317 wmem_strbuf_append(wmem_new, replacestr); 318 show_replaced_str = TRUE; 319 } else { 320 wmem_strbuf_append_c(wmem_new, disp_string[x]); 321 } 322 } 323 if (show_replaced_str) { 324 si->additionalInfo = g_strdup_printf("\"%s\"", wmem_strbuf_get_str(wmem_new)); 325 proto_item_append_text(item, " => \"%s\"" , wmem_strbuf_get_str(wmem_new)); 326 } 327 ptvcursor_advance(cursor, length); 328} 329 330/*** Request / Response helper functions */ 331static void skinny_reqrep_add_request(ptvcursor_t *cursor, packet_info * pinfo, skinny_conv_info_t * skinny_conv, const int request_key) 332{ 333 proto_tree *tree = ptvcursor_tree(cursor); 334 tvbuff_t *tvb = ptvcursor_tvbuff(cursor); 335 skinny_req_resp_t *req_resp = NULL; 336 337 if (!PINFO_FD_VISITED(pinfo)) { 338 req_resp = wmem_new0(wmem_file_scope(), skinny_req_resp_t); 339 req_resp->request_frame = pinfo->num; 340 req_resp->response_frame = 0; 341 req_resp->request_time = pinfo->abs_ts; 342 wmem_map_insert(skinny_conv->pending_req_resp, GINT_TO_POINTER(request_key), (void *)req_resp); 343 DPRINT(("SKINNY: setup_request: frame=%d add key=%d to map\n", pinfo->num, request_key)); 344 } 345 346 req_resp = (skinny_req_resp_t *) wmem_map_lookup(skinny_conv->requests, GUINT_TO_POINTER(pinfo->num)); 347 if (req_resp && req_resp->response_frame) { 348 DPRINT(("SKINNY: show request in tree: frame/key=%d\n", pinfo->num)); 349 proto_item *it; 350 it = proto_tree_add_uint(tree, hf_skinny_response_in, tvb, 0, 0, req_resp->response_frame); 351 proto_item_set_generated(it); 352 } else { 353 DPRINT(("SKINNY: no request found for frame/key=%d\n", pinfo->num)); 354 } 355} 356 357 358static void skinny_reqrep_add_response(ptvcursor_t *cursor, packet_info * pinfo, skinny_conv_info_t * skinny_conv, const int request_key) 359{ 360 proto_tree *tree = ptvcursor_tree(cursor); 361 tvbuff_t *tvb = ptvcursor_tvbuff(cursor); 362 skinny_req_resp_t *req_resp = NULL; 363 364 if (!PINFO_FD_VISITED(pinfo)) { 365 req_resp = (skinny_req_resp_t *) wmem_map_remove(skinny_conv->pending_req_resp, GINT_TO_POINTER(request_key)); 366 if (req_resp) { 367 DPRINT(("SKINNY: match request:%d with response:%d for key=%d\n", req_resp->request_frame, pinfo->num, request_key)); 368 req_resp->response_frame = pinfo->num; 369 wmem_map_insert(skinny_conv->requests, GUINT_TO_POINTER(req_resp->request_frame), (void *)req_resp); 370 wmem_map_insert(skinny_conv->responses, GUINT_TO_POINTER(pinfo->num), (void *)req_resp); 371 } else { 372 DPRINT(("SKINNY: no match found for response frame=%d and key=%d\n", pinfo->num, request_key)); 373 } 374 } 375 376 req_resp = (skinny_req_resp_t *) wmem_map_lookup(skinny_conv->responses, GUINT_TO_POINTER(pinfo->num)); 377 if (req_resp && req_resp->request_frame) { 378 DPRINT(("SKINNY: show response in tree: frame/key=%d\n", pinfo->num)); 379 proto_item *it; 380 nstime_t ns; 381 it = proto_tree_add_uint(tree, hf_skinny_response_to, tvb, 0, 0, req_resp->request_frame); 382 proto_item_set_generated(it); 383 384 nstime_delta(&ns, &pinfo->abs_ts, &req_resp->request_time); 385 it = proto_tree_add_time(tree, hf_skinny_response_time, tvb, 0, 0, &ns); 386 proto_item_set_generated(it); 387 } else { 388 DPRINT(("SKINNY: no response found for frame/key=%d\n", pinfo->num)); 389 } 390} 391 392/*** Messages Handlers ***/ 393/* [[[cog 394cog.out(message_dissector_functions) 395]]]*/ 396/*[[[end]]]*/ 397 398typedef void (*message_handler) (ptvcursor_t * cursor, packet_info *pinfo, skinny_conv_info_t * skinny_conv); 399 400typedef struct _skinny_opcode_map_t { 401 guint32 opcode; 402 message_handler handler; 403 skinny_message_type_t type; 404 const char *name; 405} skinny_opcode_map_t; 406 407/* Messages Handler Array */ 408/* [[[cog 409cog.out('static const skinny_opcode_map_t skinny_opcode_map[] = {\n') 410for message in skinny.message: 411 msg_type = "SKINNY_MSGTYPE_EVENT" 412 if message.msgtype == "request": 413 msg_type = "SKINNY_MSGTYPE_REQUEST" 414 if message.msgtype == "response" and message.request is not None: 415 msg_type = "SKINNY_MSGTYPE_RESPONSE" 416 cog.out(' {%-6s, %-47s, %-24s, "%s"},\n' %(message.opcode, message.gen_handler(), msg_type, message.name)) 417cog.out('};\n') 418]]]*/ 419/*[[[end]]]*/ 420 421/* Dissect a single SKINNY PDU */ 422static int dissect_skinny_pdu(tvbuff_t *tvb, packet_info *pinfo, proto_tree *tree, void* data _U_) 423{ 424 guint offset = 0; 425 /*gboolean is_video = FALSE;*/ /* FIX ME: need to indicate video or not */ 426 ptvcursor_t* cursor; 427 conversation_t *conversation; 428 skinny_conv_info_t *skinny_conv; 429 const skinny_opcode_map_t *opcode_entry = NULL; 430 431 /* Header fields */ 432 guint32 hdr_data_length; 433 guint32 hdr_version; 434 guint32 hdr_opcode; 435 guint16 i; 436 437 /* Set up structures we will need to add the protocol subtree and manage it */ 438 proto_tree *skinny_tree = NULL; 439 proto_item *ti = NULL; 440 441 /* Initialization */ 442 hdr_data_length = tvb_get_letohl(tvb, 0); 443 hdr_version = tvb_get_letohl(tvb, 4); 444 hdr_opcode = tvb_get_letohl(tvb, 8); 445 446 for (i = 0; i < sizeof(skinny_opcode_map)/sizeof(skinny_opcode_map_t) ; i++) { 447 if (skinny_opcode_map[i].opcode == hdr_opcode) { 448 opcode_entry = &skinny_opcode_map[i]; 449 } 450 } 451 452 conversation = find_or_create_conversation(pinfo); 453 skinny_conv = (skinny_conv_info_t *)conversation_get_proto_data(conversation, proto_skinny); 454 if (!skinny_conv) { 455 skinny_conv = wmem_new0(wmem_file_scope(), skinny_conv_info_t); 456 //skinny_conv->pending_req_resp = wmem_map_new(wmem_file_scope(), wmem_str_hash, g_str_equal); 457 skinny_conv->pending_req_resp = wmem_map_new(wmem_file_scope(), g_direct_hash, g_direct_equal); 458 skinny_conv->requests = wmem_map_new(wmem_file_scope(), g_direct_hash, g_direct_equal); 459 skinny_conv->responses = wmem_map_new(wmem_file_scope(), g_direct_hash, g_direct_equal); 460 skinny_conv->lineId = -1; 461 skinny_conv->mtype = SKINNY_MSGTYPE_EVENT; 462 conversation_add_proto_data(conversation, proto_skinny, skinny_conv); 463 } 464 465 /* Initialise stat info for passing to tap */ 466 /* WIP: will be (partially) replaced in favor of conversionation, dependents: ui/voip_calls.c */ 467 pi_current++; 468 if (pi_current == MAX_SKINNY_MESSAGES_IN_PACKET) 469 { 470 /* Overwrite info in first struct if run out of space... */ 471 pi_current = 0; 472 } 473 si = &pi_arr[pi_current]; 474 si->messId = hdr_opcode; 475 si->messageName = val_to_str_ext(hdr_opcode, &message_id_ext, "0x%08X (Unknown)"); 476 si->callId = 0; 477 si->lineId = 0; 478 si->passThroughPartyId = 0; 479 si->callState = 0; 480 g_free(si->callingParty); 481 si->callingParty = NULL; 482 g_free(si->calledParty); 483 si->calledParty = NULL; 484 si->mediaReceptionStatus = -1; 485 si->mediaTransmissionStatus = -1; 486 si->multimediaReceptionStatus = -1; 487 si->multimediaTransmissionStatus = -1; 488 si->multicastReceptionStatus = -1; 489 g_free(si->additionalInfo); 490 si->additionalInfo = NULL; 491 492 col_add_fstr(pinfo->cinfo, COL_INFO,"%s ", si->messageName); 493 col_set_fence(pinfo->cinfo, COL_INFO); 494 495 if (tree) { 496 ti = proto_tree_add_item(tree, proto_skinny, tvb, offset, hdr_data_length+8, ENC_NA); 497 skinny_tree = proto_item_add_subtree(ti, ett_skinny); 498 } 499 500 if (opcode_entry && opcode_entry->type != SKINNY_MSGTYPE_EVENT) { 501 skinny_conv->mtype = opcode_entry->type; 502 if (opcode_entry->type == SKINNY_MSGTYPE_REQUEST) { 503 col_set_str(pinfo->cinfo, COL_PROTOCOL, "SKINNY/REQ"); 504 } else { 505 col_set_str(pinfo->cinfo, COL_PROTOCOL, "SKINNY/RESP"); 506 } 507 } 508 509 if (skinny_tree) { 510 proto_tree_add_uint(skinny_tree, hf_skinny_data_length, tvb, offset , 4, hdr_data_length); 511 proto_tree_add_uint(skinny_tree, hf_skinny_hdr_version, tvb, offset+4, 4, hdr_version); 512 proto_tree_add_uint(skinny_tree, hf_skinny_messageId, tvb, offset+8, 4, hdr_opcode ); 513 } 514 offset += 12; 515 516 cursor = ptvcursor_new(pinfo->pool, skinny_tree, tvb, offset); 517 if (opcode_entry && opcode_entry->handler) { 518 opcode_entry->handler(cursor, pinfo, skinny_conv); 519 } 520 ptvcursor_free(cursor); 521 522 tap_queue_packet(skinny_tap, pinfo, si); 523 524 return tvb_captured_length(tvb); 525} 526 527/* Code to actually dissect the packets */ 528static int 529dissect_skinny(tvbuff_t *tvb, packet_info *pinfo, proto_tree *tree, void *data) 530{ 531 /* The general structure of a packet: {IP-Header|TCP-Header|n*SKINNY} 532 * SKINNY-Packet: {Header(Size, Reserved)|Data(MessageID, Message-Data)} 533 */ 534 /* Header fields */ 535 guint32 hdr_data_length; 536 guint32 hdr_version; 537 538 /* check, if this is really an SKINNY packet, they start with a length + 0 */ 539 540 if (tvb_captured_length(tvb) < 8) 541 { 542 return 0; 543 } 544 /* get relevant header information */ 545 hdr_data_length = tvb_get_letohl(tvb, 0); 546 hdr_version = tvb_get_letohl(tvb, 4); 547 548 /* data_size = MIN(8+hdr_data_length, tvb_length(tvb)) - 0xC; */ 549 550 if ( 551 (hdr_data_length < 4) || 552 ((hdr_version != BASIC_MSG_TYPE) && 553 (hdr_version != V10_MSG_TYPE) && 554 (hdr_version != V11_MSG_TYPE) && 555 (hdr_version != V15_MSG_TYPE) && 556 (hdr_version != V16_MSG_TYPE) && 557 (hdr_version != V17_MSG_TYPE) && 558 (hdr_version != V18_MSG_TYPE) && 559 (hdr_version != V19_MSG_TYPE) && 560 (hdr_version != V20_MSG_TYPE) && 561 (hdr_version != V21_MSG_TYPE) && 562 (hdr_version != V22_MSG_TYPE)) 563 ) 564 { 565 /* Not an SKINNY packet, just happened to use the same port */ 566 return 0; 567 } 568 569 /* Make entries in Protocol column and Info column on summary display */ 570 col_set_str(pinfo->cinfo, COL_PROTOCOL, "SKINNY"); 571 572 col_set_str(pinfo->cinfo, COL_INFO, "Skinny Client Control Protocol"); 573 574 tcp_dissect_pdus(tvb, pinfo, tree, global_skinny_desegment, 4, get_skinny_pdu_len, dissect_skinny_pdu, data); 575 576 return tvb_captured_length(tvb); 577} 578 579/* Register the protocol with Wireshark */ 580void 581proto_register_skinny(void) 582{ 583 /* Setup list of header fields */ 584 static hf_register_info hf[] = { 585 { &hf_skinny_data_length, 586 { 587 "Data length", "skinny.data_length", FT_UINT32, BASE_DEC, NULL, 0x0, 588 "Number of bytes in the data portion.", HFILL }}, 589 { &hf_skinny_hdr_version, 590 { 591 "Header version", "skinny.hdr_version", FT_UINT32, BASE_HEX, VALS(header_version), 0x0, 592 NULL, HFILL }}, 593 { &hf_skinny_messageId, 594 { 595 "Message ID", "skinny.messageId", FT_UINT32, BASE_DEC|BASE_EXT_STRING, &message_id_ext, 0x0, 596 NULL, HFILL }}, 597 { &hf_skinny_xmlData, 598 { 599 "XML data", "skinny.xmlData", FT_STRING, BASE_NONE, NULL, 0x0, 600 NULL, HFILL }}, 601 { &hf_skinny_ipv4or6, 602 { 603 "IPv4or6", "skinny.ipv4or6", FT_UINT32, BASE_DEC|BASE_EXT_STRING, &IpAddrType_ext, 0x0, 604 NULL, HFILL }}, 605 { &hf_skinny_response_in, 606 { 607 "Response In", "skinny.response_in", FT_FRAMENUM, BASE_NONE, FRAMENUM_TYPE(FT_FRAMENUM_RESPONSE), 0x0, 608 "The response to this SKINNY request is in this frame", HFILL }}, 609 { &hf_skinny_response_to, 610 { 611 "Request In", "skinny.response_to", FT_FRAMENUM, BASE_NONE, FRAMENUM_TYPE(FT_FRAMENUM_REQUEST), 0x0, 612 "This is a response to the SKINNY request in this frame", HFILL }}, 613 { &hf_skinny_response_time, 614 { 615 "Response Time", "skinny.response_time", FT_RELATIVE_TIME, BASE_NONE, NULL, 0x0, 616 "The time between the Call and the Reply", HFILL }}, 617 /* [[[cog 618 for valuestr in sorted(xml2skinny.fieldsArray.values()): 619 cog.out('%s' %valuestr) 620 ]]]*/ 621 /*[[[end]]]*/ 622 }; 623 624 /* Setup protocol subtree array */ 625 static gint *ett[] = { 626 &ett_skinny, 627 &ett_skinny_tree, 628 }; 629 630 module_t *skinny_module; 631 632 /* Register the protocol name and description */ 633 proto_skinny = proto_register_protocol("Skinny Client Control Protocol", 634 "SKINNY", "skinny"); 635 636 /* Required function calls to register the header fields and subtrees used */ 637 proto_register_field_array(proto_skinny, hf, array_length(hf)); 638 proto_register_subtree_array(ett, array_length(ett)); 639 640 skinny_module = prefs_register_protocol(proto_skinny, NULL); 641 prefs_register_bool_preference(skinny_module, "desegment", 642 "Reassemble SKINNY messages spanning multiple TCP segments", 643 "Whether the SKINNY dissector should reassemble messages spanning multiple TCP segments." 644 " To use this option, you must also enable" 645 " \"Allow subdissectors to reassemble TCP streams\" in the TCP protocol settings.", 646 &global_skinny_desegment); 647 648 skinny_handle = register_dissector("skinny", dissect_skinny, proto_skinny); 649 650 skinny_tap = register_tap("skinny"); 651} 652 653void 654proto_reg_handoff_skinny(void) 655{ 656 /* Skinny content type and internet media type used by other dissectors are the same */ 657 xml_handle = find_dissector_add_dependency("xml", proto_skinny); 658 dissector_add_uint_with_preference("tcp.port", TCP_PORT_SKINNY, skinny_handle); 659 ssl_dissector_add(SSL_PORT_SKINNY, skinny_handle); 660} 661 662/* 663 * Editor modelines - https://www.wireshark.org/tools/modelines.html 664 * 665 * Local variables: 666 * c-basic-offset: 2 667 * tab-width: 8 668 * indent-tabs-mode: nil 669 * End: 670 * 671 * vi: set shiftwidth=2 tabstop=8 expandtab: 672 * :indentSize=2:tabSize=8:noTabs=true: 673 */ 674