377 lines
11 KiB
C
377 lines
11 KiB
C
/* packet-msrcp.c
|
|
* Routines for decoding Microsoft Cluster Route Control Protocol (MSRCP)
|
|
* Copyright 2022, Will Aftring <william.aftring@outlook.com>
|
|
*
|
|
* SPDX-License-Identifier: MIT
|
|
*
|
|
* Wireshark - Network traffic analyzer
|
|
* By Gerald Combs <gerald@wireshark.org>
|
|
* Copyright 1998 Gerald Combs
|
|
*
|
|
*/
|
|
|
|
|
|
#include "config.h"
|
|
#include <epan/packet.h>
|
|
#include <epan/expert.h>
|
|
#include <epan/conversation.h>
|
|
|
|
void proto_register_msrcp(void);
|
|
void proto_reg_handoff_msrcp(void);
|
|
|
|
#define MSRCP_PORT 3343
|
|
#define MSRCP_REQUEST 0
|
|
#define MSRCP_RESPONSE 1
|
|
#define MSRCP_OFFSET_TYPE 6
|
|
#define MSRCP_OFFSET_SEQ 12
|
|
|
|
|
|
static const value_string packettypenames[] = {
|
|
{0, "REQUEST" },
|
|
{1, "RESPONSE" },
|
|
{0, NULL}
|
|
};
|
|
|
|
static const value_string headertypenames[] = {
|
|
{0, "MSRCP EXTENSION NONE",},
|
|
{1, "MSRCP IPv4 Pair"},
|
|
{2, "MSRCP IPv6 Pair"},
|
|
{3, "MSRCP Signature"},
|
|
{4, "MSRCP Maximum"},
|
|
{0, NULL}
|
|
};
|
|
|
|
typedef struct _msrcp_conv_info_t {
|
|
wmem_tree_t* pdus;
|
|
} msrcp_conv_info_t;
|
|
|
|
typedef struct _msrcp_transaction_t {
|
|
guint32 req_frame;
|
|
guint32 rep_frame;
|
|
nstime_t req_time;
|
|
guint32 seq;
|
|
gboolean matched;
|
|
} msrcp_transaction_t;
|
|
|
|
static int proto_msrcp = -1;
|
|
static int hf_msrcp_id = -1;
|
|
static int hf_msrcp_type = -1;
|
|
static int hf_msrcp_vers = -1;
|
|
static int hf_msrcp_reserved = -1;
|
|
static int hf_msrcp_next_header = -1;
|
|
static int hf_msrcp_len = -1;
|
|
static int hf_msrcp_seq = -1;
|
|
static int hf_msrcp_response_in = -1;
|
|
static int hf_msrcp_response_to = -1;
|
|
static int hf_msrcp_ext_header = -1;
|
|
static int hf_msrcp_ext_next_header = -1;
|
|
static int hf_msrcp_ext_len = -1;
|
|
static int hf_msrcp_ext_res = -1;
|
|
|
|
static gint ett_msrcp = -1;
|
|
static gint ett_msrcp_nxt = -1;
|
|
|
|
static expert_field ei_msrcp_no_resp = EI_INIT;
|
|
|
|
// Handles for subparsing
|
|
static dissector_handle_t eth_handle;
|
|
|
|
static int
|
|
dissect_msrcp(tvbuff_t* tvb, packet_info* pinfo, proto_tree* tree, void* data _U_)
|
|
{
|
|
|
|
/*
|
|
Rough Packet layout:
|
|
Identifier: 4 bytes
|
|
Version: 1 byte
|
|
Reserved: 1 byte
|
|
Type: 2 bytes
|
|
NextHeader: 2 bytes
|
|
Total Length: 2 bytes
|
|
SeqNum: 4 bytes
|
|
ExtHeader: 40 bytes
|
|
NextHeader: 2 bytes
|
|
Length: 2 bytes
|
|
Reserved: 4 bytes
|
|
SrcAddr: 16 bytes
|
|
DstAddr: 16 bytes
|
|
*/
|
|
guint tree_offset = 0;
|
|
|
|
proto_tree* msrcp_tree, * nxt_tree;
|
|
proto_item* ti, * nxt_ti;
|
|
tvbuff_t* next_tvb;
|
|
guint32 seq;
|
|
guint16 type;
|
|
|
|
// variables for our expert analysis
|
|
conversation_t* conv = NULL;
|
|
msrcp_conv_info_t* msrcp_info = NULL;
|
|
msrcp_transaction_t* msrcp_trans = NULL;
|
|
wmem_tree_key_t key[3];
|
|
|
|
type = tvb_get_guint8(tvb, MSRCP_OFFSET_TYPE);
|
|
seq = tvb_get_guint32(tvb, MSRCP_OFFSET_SEQ, ENC_LITTLE_ENDIAN);
|
|
|
|
conv = find_or_create_conversation(pinfo);
|
|
msrcp_info = (msrcp_conv_info_t*)conversation_get_proto_data(conv, proto_msrcp);
|
|
if (!msrcp_info)
|
|
{
|
|
msrcp_info = wmem_new(wmem_file_scope(), msrcp_conv_info_t);
|
|
msrcp_info->pdus = wmem_tree_new(wmem_file_scope());
|
|
conversation_add_proto_data(conv, proto_msrcp, msrcp_info);
|
|
}
|
|
|
|
key[0].length = 1;
|
|
key[0].key = &seq;
|
|
key[1].length = 1;
|
|
key[1].key = &pinfo->num;
|
|
key[2].length = 0;
|
|
key[2].key = NULL;
|
|
if ((type == MSRCP_REQUEST) || (type == MSRCP_RESPONSE))
|
|
{
|
|
if (!pinfo->fd->visited)
|
|
{
|
|
if (type == MSRCP_REQUEST)
|
|
{
|
|
msrcp_trans = wmem_new(wmem_file_scope(), msrcp_transaction_t);
|
|
msrcp_trans->req_frame = pinfo->num;
|
|
msrcp_trans->rep_frame = 0;
|
|
msrcp_trans->req_time = pinfo->abs_ts;
|
|
msrcp_trans->seq = seq;
|
|
msrcp_trans->matched = FALSE;
|
|
wmem_tree_insert32_array(msrcp_info->pdus, key, (void*)msrcp_trans);
|
|
}
|
|
else
|
|
{
|
|
msrcp_trans = (msrcp_transaction_t*)wmem_tree_lookup32_array_le(msrcp_info->pdus, key);
|
|
if (msrcp_trans)
|
|
{
|
|
if (msrcp_trans->seq != seq)
|
|
{
|
|
msrcp_trans = NULL;
|
|
}
|
|
else if (msrcp_trans->rep_frame == 0)
|
|
{
|
|
msrcp_trans->rep_frame = pinfo->num;
|
|
msrcp_trans->matched = TRUE;
|
|
}
|
|
}
|
|
}
|
|
}
|
|
else
|
|
{
|
|
msrcp_trans = (msrcp_transaction_t*)wmem_tree_lookup32_array_le(msrcp_info->pdus, key);
|
|
if (msrcp_trans)
|
|
{
|
|
if (msrcp_trans->seq != seq)
|
|
{
|
|
msrcp_trans = NULL;
|
|
}
|
|
else if ((!(type == MSRCP_RESPONSE)) && (msrcp_trans->req_frame != pinfo->num))
|
|
{
|
|
msrcp_transaction_t* retrans_msrcp = wmem_new(pinfo->pool, msrcp_transaction_t);
|
|
retrans_msrcp->req_frame = msrcp_trans->req_frame;
|
|
retrans_msrcp->rep_frame = 0;
|
|
retrans_msrcp->req_time = pinfo->abs_ts;
|
|
msrcp_trans = retrans_msrcp;
|
|
}
|
|
}
|
|
}
|
|
if (!msrcp_trans)
|
|
{
|
|
msrcp_trans = wmem_new(pinfo->pool, msrcp_transaction_t);
|
|
msrcp_trans->req_frame = 0;
|
|
msrcp_trans->rep_frame = 0;
|
|
msrcp_trans->req_time = pinfo->abs_ts;
|
|
msrcp_trans->matched = FALSE;
|
|
}
|
|
}
|
|
|
|
|
|
col_set_str(pinfo->cinfo, COL_PROTOCOL, "MSRCP");
|
|
col_clear(pinfo->cinfo, COL_INFO);
|
|
col_add_fstr(pinfo->cinfo, COL_INFO, "%s ID %d (0x%X)",
|
|
val_to_str(type, packettypenames, "MSRCP"), seq, seq);
|
|
|
|
|
|
ti = proto_tree_add_item(tree, proto_msrcp, tvb, 0, -1, ENC_BIG_ENDIAN);
|
|
proto_item_append_text(ti, "Type %s",
|
|
val_to_str(type, packettypenames, "MSRCP"));
|
|
msrcp_tree = proto_item_add_subtree(ti, ett_msrcp);
|
|
|
|
if (type == MSRCP_REQUEST || type == MSRCP_RESPONSE)
|
|
{
|
|
proto_item* it;
|
|
proto_tree_add_item(msrcp_tree, hf_msrcp_id, tvb, 0, 4, ENC_BIG_ENDIAN);
|
|
tree_offset += 4;
|
|
proto_tree_add_item(msrcp_tree, hf_msrcp_vers, tvb, tree_offset, 1, ENC_LITTLE_ENDIAN);
|
|
tree_offset += 1;
|
|
proto_tree_add_item(msrcp_tree, hf_msrcp_reserved, tvb, tree_offset, 1, ENC_LITTLE_ENDIAN);
|
|
tree_offset += 1;
|
|
proto_tree_add_item(msrcp_tree, hf_msrcp_type, tvb, tree_offset, 2, ENC_LITTLE_ENDIAN);
|
|
tree_offset += 2;
|
|
proto_tree_add_item(msrcp_tree, hf_msrcp_next_header, tvb, tree_offset, 2, ENC_LITTLE_ENDIAN);
|
|
tree_offset += 2;
|
|
proto_tree_add_item(msrcp_tree, hf_msrcp_len, tvb, tree_offset, 2, ENC_LITTLE_ENDIAN);
|
|
tree_offset += 2;
|
|
it = proto_tree_add_item(msrcp_tree, hf_msrcp_seq, tvb, tree_offset, 4, ENC_LITTLE_ENDIAN);
|
|
tree_offset += 4;
|
|
|
|
if (msrcp_trans->matched)
|
|
{
|
|
if ((msrcp_trans->req_frame) && (type == MSRCP_RESPONSE))
|
|
{
|
|
it = proto_tree_add_uint(msrcp_tree, hf_msrcp_response_to, tvb, 0, 0, msrcp_trans->req_frame);
|
|
proto_item_set_generated(it);
|
|
|
|
}
|
|
else if ((msrcp_trans->rep_frame) && (type == MSRCP_REQUEST))
|
|
{
|
|
it = proto_tree_add_uint(msrcp_tree, hf_msrcp_response_in, tvb, 0, 0, msrcp_trans->rep_frame);
|
|
proto_item_set_generated(it);
|
|
}
|
|
}
|
|
else
|
|
{
|
|
expert_add_info(pinfo, it, &ei_msrcp_no_resp);
|
|
col_prepend_fence_fstr(pinfo->cinfo, COL_INFO, "[Missing MSRCP Response]");
|
|
}
|
|
|
|
nxt_ti = proto_tree_add_item(msrcp_tree, hf_msrcp_ext_header, tvb, 0, 0, ENC_ASCII);
|
|
nxt_tree = proto_item_add_subtree(nxt_ti, ett_msrcp_nxt);
|
|
proto_tree_add_item(nxt_tree, hf_msrcp_ext_next_header, tvb, tree_offset, 2, ENC_LITTLE_ENDIAN);
|
|
tree_offset += 2;
|
|
proto_tree_add_item(nxt_tree, hf_msrcp_ext_len, tvb, tree_offset, 2, ENC_LITTLE_ENDIAN);
|
|
tree_offset += 2;
|
|
proto_tree_add_item(nxt_tree, hf_msrcp_ext_res, tvb, tree_offset, 4, ENC_LITTLE_ENDIAN);
|
|
|
|
}
|
|
else
|
|
{
|
|
next_tvb = tvb_new_subset_remaining(tvb, 0);
|
|
call_dissector(eth_handle, next_tvb, pinfo, msrcp_tree);
|
|
}
|
|
|
|
return tvb_captured_length(tvb);
|
|
}
|
|
|
|
|
|
void
|
|
proto_register_msrcp(void)
|
|
{
|
|
expert_module_t* expert_msrcp;
|
|
|
|
static hf_register_info hf[] = {
|
|
{ &hf_msrcp_id,
|
|
{ "MSRCP ID", "msrcp.id",
|
|
FT_UINT32, BASE_DEC_HEX,
|
|
NULL, 0x0,
|
|
NULL, HFILL},
|
|
},
|
|
{ &hf_msrcp_vers,
|
|
{ "Version", "msrcp.vers",
|
|
FT_UINT8, BASE_DEC,
|
|
NULL, 0x0,
|
|
NULL, HFILL}
|
|
},
|
|
{ &hf_msrcp_reserved,
|
|
{ "Reserved", "msrcp.reserved",
|
|
FT_UINT8, BASE_DEC,
|
|
NULL, 0x0,
|
|
NULL, HFILL}
|
|
},
|
|
{ &hf_msrcp_type,
|
|
{ "MSRCP Type", "msrcp.type",
|
|
FT_UINT16, BASE_DEC,
|
|
VALS(packettypenames), 0x0,
|
|
NULL, HFILL}
|
|
},
|
|
{ &hf_msrcp_next_header,
|
|
{ "Next Header", "msrcp.nxt_header",
|
|
FT_UINT16, BASE_DEC,
|
|
VALS(headertypenames), 0x0,
|
|
NULL, HFILL}
|
|
},
|
|
{ &hf_msrcp_len,
|
|
{ "Total Length", "msrcp.len",
|
|
FT_UINT16, BASE_DEC,
|
|
NULL, 0x0,
|
|
NULL, HFILL}
|
|
},
|
|
{ &hf_msrcp_seq,
|
|
{ "Sequence Number", "msrcp.seq",
|
|
FT_UINT32, BASE_DEC_HEX,
|
|
NULL, 0x0,
|
|
NULL, HFILL}
|
|
},
|
|
{ &hf_msrcp_response_in,
|
|
{ "Response In", "msrcp.response_in",
|
|
FT_FRAMENUM, BASE_NONE, FRAMENUM_TYPE(FT_FRAMENUM_RESPONSE), 0x0,
|
|
"The response to this MSRCP request is in frame", HFILL}
|
|
},
|
|
{ &hf_msrcp_response_to,
|
|
{ "Request In", "msrcp.response_to",
|
|
FT_FRAMENUM,BASE_NONE, FRAMENUM_TYPE(FT_FRAMENUM_REQUEST), 0x0,
|
|
"This is a response to an MSRCP request in frame", HFILL}
|
|
},
|
|
{ &hf_msrcp_ext_header,
|
|
{ "Extension Header", "msrcp.ext",
|
|
FT_NONE, BASE_NONE,
|
|
NULL, 0x0,
|
|
NULL, HFILL}
|
|
},
|
|
{ &hf_msrcp_ext_next_header,
|
|
{ "Next Header", "msrcp.ext_nxt_header",
|
|
FT_UINT16, BASE_DEC,
|
|
VALS(headertypenames), 0x0, NULL, HFILL}
|
|
},
|
|
{ &hf_msrcp_ext_len,
|
|
{ "Length", "msrcp.ext_len",
|
|
FT_UINT16, BASE_DEC,
|
|
NULL, 0x0, NULL, HFILL}
|
|
},
|
|
{ &hf_msrcp_ext_res,
|
|
{ "Reserved", "msrcp.nxt_res",
|
|
FT_UINT32, BASE_HEX,
|
|
NULL, 0x0,
|
|
NULL, HFILL}
|
|
},
|
|
};
|
|
|
|
static gint* ett[] = {
|
|
&ett_msrcp,
|
|
&ett_msrcp_nxt
|
|
};
|
|
|
|
static ei_register_info ei[] = {
|
|
{
|
|
&ei_msrcp_no_resp,
|
|
{ "msrcp.no_resp", PI_SEQUENCE, PI_WARN,
|
|
"MSRCP Response not found", EXPFILL }
|
|
}
|
|
};
|
|
|
|
proto_msrcp = proto_register_protocol(
|
|
"MSRCP Protocol",
|
|
"MSRCP",
|
|
"msrcp"
|
|
);
|
|
|
|
|
|
proto_register_field_array(proto_msrcp, hf, array_length(hf));
|
|
proto_register_subtree_array(ett, array_length(ett));
|
|
expert_msrcp = expert_register_protocol(proto_msrcp);
|
|
expert_register_field_array(expert_msrcp, ei, array_length(ei));
|
|
}
|
|
|
|
void
|
|
proto_reg_handoff_msrcp(void)
|
|
{
|
|
static dissector_handle_t msrcp_handle;
|
|
|
|
eth_handle = find_dissector_add_dependency("eth_withoutfcs", proto_msrcp);
|
|
msrcp_handle = create_dissector_handle(dissect_msrcp, proto_msrcp);
|
|
dissector_add_uint("udp.port", MSRCP_PORT, msrcp_handle);
|
|
}
|