summaryrefslogtreecommitdiffstats
path: root/plugins/epan/transum
diff options
context:
space:
mode:
authorDaniel Baumann <daniel.baumann@progress-linux.org>2024-04-10 20:34:10 +0000
committerDaniel Baumann <daniel.baumann@progress-linux.org>2024-04-10 20:34:10 +0000
commite4ba6dbc3f1e76890b22773807ea37fe8fa2b1bc (patch)
tree68cb5ef9081156392f1dd62a00c6ccc1451b93df /plugins/epan/transum
parentInitial commit. (diff)
downloadwireshark-e4ba6dbc3f1e76890b22773807ea37fe8fa2b1bc.tar.xz
wireshark-e4ba6dbc3f1e76890b22773807ea37fe8fa2b1bc.zip
Adding upstream version 4.2.2.upstream/4.2.2
Signed-off-by: Daniel Baumann <daniel.baumann@progress-linux.org>
Diffstat (limited to 'plugins/epan/transum')
-rw-r--r--plugins/epan/transum/AUTHORS2
-rw-r--r--plugins/epan/transum/CMakeLists.txt72
-rw-r--r--plugins/epan/transum/README6
-rw-r--r--plugins/epan/transum/decoders.c335
-rw-r--r--plugins/epan/transum/decoders.h31
-rw-r--r--plugins/epan/transum/extractors.c165
-rw-r--r--plugins/epan/transum/extractors.h21
-rw-r--r--plugins/epan/transum/packet-transum.c1366
-rw-r--r--plugins/epan/transum/packet-transum.h189
-rw-r--r--plugins/epan/transum/preferences.h41
10 files changed, 2228 insertions, 0 deletions
diff --git a/plugins/epan/transum/AUTHORS b/plugins/epan/transum/AUTHORS
new file mode 100644
index 00000000..109c3fcd
--- /dev/null
+++ b/plugins/epan/transum/AUTHORS
@@ -0,0 +1,2 @@
+Author :
+Paul Offord <paul.offord@advance7.com>
diff --git a/plugins/epan/transum/CMakeLists.txt b/plugins/epan/transum/CMakeLists.txt
new file mode 100644
index 00000000..d26d4e46
--- /dev/null
+++ b/plugins/epan/transum/CMakeLists.txt
@@ -0,0 +1,72 @@
+# CMakeLists.txt
+#
+# Wireshark - Network traffic analyzer
+# By Gerald Combs <gerald@wireshark.org>
+# Copyright 1998 Gerald Combs
+#
+# SPDX-License-Identifier: GPL-2.0-or-later
+#
+
+include(WiresharkPlugin)
+
+# Plugin name and version info (major minor micro extra)
+set_module_info(transum 2 0 4 0)
+
+set(DISSECTOR_SRC
+ packet-transum.c
+)
+
+set(DISSECTOR_SUPPORT_SRC
+ decoders.c
+ extractors.c
+)
+
+set(PLUGIN_FILES
+ plugin.c
+ ${DISSECTOR_SRC}
+ ${DISSECTOR_SUPPORT_SRC}
+)
+
+set_source_files_properties(
+ ${PLUGIN_FILES}
+ PROPERTIES
+ COMPILE_FLAGS "${WERROR_COMMON_FLAGS}"
+)
+
+register_plugin_files(plugin.c
+ plugin
+ ${DISSECTOR_SRC}
+ ${DISSECTOR_SUPPORT_SRC}
+)
+
+add_wireshark_plugin_library(transum epan)
+
+target_link_libraries(transum epan)
+
+install_plugin(transum epan)
+
+file(GLOB DISSECTOR_HEADERS RELATIVE "${CMAKE_CURRENT_SOURCE_DIR}" "*.h")
+CHECKAPI(
+ NAME
+ transum
+ SWITCHES
+ --group dissectors-prohibited
+ --group dissectors-restricted
+ SOURCES
+ ${DISSECTOR_SRC}
+ ${DISSECTOR_SUPPORT_SRC}
+ ${DISSECTOR_HEADERS}
+)
+
+#
+# Editor modelines - https://www.wireshark.org/tools/modelines.html
+#
+# Local variables:
+# c-basic-offset: 8
+# tab-width: 8
+# indent-tabs-mode: t
+# End:
+#
+# vi: set shiftwidth=8 tabstop=8 noexpandtab:
+# :indentSize=8:tabSize=8:noTabs=false:
+#
diff --git a/plugins/epan/transum/README b/plugins/epan/transum/README
new file mode 100644
index 00000000..876f3f70
--- /dev/null
+++ b/plugins/epan/transum/README
@@ -0,0 +1,6 @@
+Advance7 has released under GPL this plugin
+for Wireshark. It produces detailed response
+time information based on the RTE model.
+
+Advance7 can be found at https://www.advance7.com
+The author is Paul Offord <paul.offord@advance7.com>
diff --git a/plugins/epan/transum/decoders.c b/plugins/epan/transum/decoders.c
new file mode 100644
index 00000000..c430f588
--- /dev/null
+++ b/plugins/epan/transum/decoders.c
@@ -0,0 +1,335 @@
+/* decoders.c
+ * Routines for the TRANSUM response time analyzer post-dissector
+ * By Paul Offord <paul.offord@advance7.com>
+ * Copyright 2016 Advance Seven Limited
+ *
+ * Wireshark - Network traffic analyzer
+ * By Gerald Combs <gerald@wireshark.org>
+ * Copyright 1998 Gerald Combs
+ *
+ * SPDX-License-Identifier: GPL-2.0-or-later
+ */
+
+#include "config.h"
+
+#include <stdio.h>
+#include <epan/packet.h>
+#include <epan/prefs.h>
+#include <epan/dissectors/packet-tcp.h>
+#include "packet-transum.h"
+#include "preferences.h"
+#include "extractors.h"
+#include "decoders.h"
+
+extern TSUM_PREFERENCES preferences;
+
+
+/* Returns the number of sub-packets of interest */
+int decode_syn(packet_info *pinfo _U_, proto_tree *tree _U_, PKT_INFO* pkt_info)
+{
+ if (pkt_info->tcp_flags_ack)
+ pkt_info->rrpd.c2s = FALSE;
+ else
+ {
+ pkt_info->rrpd.c2s = TRUE;
+ add_detected_tcp_svc(pkt_info->dstport);
+ }
+
+ pkt_info->rrpd.session_id = 1; /* Fake session ID */
+ pkt_info->rrpd.msg_id = 1; /* Fake message ID */
+ pkt_info->rrpd.decode_based = TRUE;
+ pkt_info->rrpd.calculation = RTE_CALC_SYN;
+ pkt_info->pkt_of_interest = TRUE;
+
+ return 1;
+}
+
+/*
+ This function sets basic information in the sub_packet entry.
+ Because we don't expect multiple DCE-RPC messages in a single packet
+ we only use single PKT_INFO
+
+ Returns the number of sub-packets of interest, which in this case is always 1.
+ */
+int decode_dcerpc(packet_info *pinfo _U_, proto_tree *tree, PKT_INFO* pkt_info)
+{
+ guint32 field_uint[MAX_RETURNED_ELEMENTS]; /* An extracted field array for unsigned integers */
+ size_t field_value_count; /* How many entries are there in the extracted field array */
+ guint32 dcerpc_cn_ctx_id = 0;
+
+ if (!extract_uint(tree, hf_of_interest[HF_INTEREST_DCERPC_VER].hf, field_uint, &field_value_count))
+ {
+ if (field_value_count)
+ pkt_info->dcerpc_ver = field_uint[0];
+ }
+
+ if (!extract_uint(tree, hf_of_interest[HF_INTEREST_DCERPC_PKT_TYPE].hf, field_uint, &field_value_count))
+ {
+ if (field_value_count)
+ pkt_info->dcerpc_pkt_type = field_uint[0];
+ }
+
+ if (field_value_count)
+ {
+ if (!extract_uint(tree, hf_of_interest[HF_INTEREST_DCERPC_CN_CTX_ID].hf, field_uint, &field_value_count))
+ {
+ if (field_value_count)
+ dcerpc_cn_ctx_id = field_uint[0];
+ }
+
+ if (is_dcerpc_context_zero(pkt_info->dcerpc_pkt_type))
+ { /* This is needed to overcome an apparent Wireshark bug
+ found in the Lua code - is this still true in C? */
+ pkt_info->rrpd.session_id = 1;
+ }
+ else
+ {
+ if (dcerpc_cn_ctx_id)
+ pkt_info->rrpd.session_id = dcerpc_cn_ctx_id;
+ else
+ pkt_info->rrpd.session_id = 1;
+ }
+ if (!extract_uint(tree, hf_of_interest[HF_INTEREST_DCERPC_CN_CALL_ID].hf, field_uint, &field_value_count))
+ {
+ if (field_value_count)
+ pkt_info->rrpd.msg_id = field_uint[0];
+ }
+ }
+ else
+ {
+ /*
+ we don't have header information and so by setting the session_id and msg_id to zero
+ the rrpd functions will either create a new rrpd_list (or temp_rsp_rrpd_list) entry
+ or update the last entry for this ip_proto:stream_no.
+ */
+ pkt_info->rrpd.session_id = 0;
+ pkt_info->rrpd.msg_id = 0;
+ }
+
+
+ if (is_dcerpc_req_pkt_type(pkt_info->dcerpc_pkt_type))
+ {
+ pkt_info->rrpd.c2s = TRUE;
+ wmem_map_insert(preferences.tcp_svc_ports, GUINT_TO_POINTER(pkt_info->dstport), GUINT_TO_POINTER(RTE_CALC_DCERPC)); /* make sure we have this DCE-RPC service port set */
+ }
+ else
+ {
+ pkt_info->rrpd.c2s = FALSE;
+ wmem_map_insert(preferences.tcp_svc_ports, GUINT_TO_POINTER(pkt_info->srcport), GUINT_TO_POINTER(RTE_CALC_DCERPC)); /* make sure we have this DCE-RPC service port set */
+ }
+
+ pkt_info->rrpd.decode_based = TRUE;
+ pkt_info->rrpd.calculation = RTE_CALC_DCERPC;
+ pkt_info->pkt_of_interest = TRUE;
+
+ return 1;
+}
+
+/* Returns the number of sub-packets of interest */
+int decode_smb(packet_info *pinfo _U_, proto_tree *tree, PKT_INFO* pkt_info, PKT_INFO* subpackets)
+{
+ guint32 field_uint[MAX_RETURNED_ELEMENTS]; /* An extracted field array for unsigned integers */
+ size_t field_value_count; /* How many entries are there in the extracted field array */
+
+ guint64 ses_id[MAX_RETURNED_ELEMENTS];
+ size_t ses_id_count;
+ guint64 msg_id[MAX_RETURNED_ELEMENTS];
+ size_t msg_id_count;
+
+ /* set the direction information */
+ if (pkt_info->dstport == 445)
+ pkt_info->rrpd.c2s = TRUE;
+ else
+ pkt_info->rrpd.c2s = FALSE;
+
+ if (!extract_uint(tree, hf_of_interest[HF_INTEREST_SMB_MID].hf, field_uint, &field_value_count))
+ {
+ if (field_value_count)
+ {
+ pkt_info->rrpd.calculation = RTE_CALC_SMB1;
+ pkt_info->pkt_of_interest = FALSE; /* can't process SMB1 at the moment */
+ return 0;
+ }
+ }
+ /* Default in case we don't have header information */
+ pkt_info->rrpd.session_id = 0;
+ pkt_info->rrpd.msg_id = 0;
+ pkt_info->rrpd.decode_based = TRUE;
+ pkt_info->rrpd.calculation = RTE_CALC_SMB2;
+ pkt_info->pkt_of_interest = TRUE;
+
+ extract_ui64(tree, hf_of_interest[HF_INTEREST_SMB2_MSG_ID].hf, msg_id, &msg_id_count);
+ if (msg_id_count) /* test for header information */
+ {
+ extract_ui64(tree, hf_of_interest[HF_INTEREST_SMB2_SES_ID].hf, ses_id, &ses_id_count);
+
+ for (size_t i = 0; (i < msg_id_count) && (i < MAX_SUBPKTS_PER_PACKET); i++)
+ {
+ subpackets[i].rrpd.c2s = pkt_info->rrpd.c2s;
+ subpackets[i].rrpd.ip_proto = pkt_info->rrpd.ip_proto;
+ subpackets[i].rrpd.stream_no = pkt_info->rrpd.stream_no;
+
+ subpackets[i].rrpd.session_id = ses_id[i];
+ subpackets[i].rrpd.msg_id = msg_id[i];
+
+ subpackets[i].rrpd.decode_based = TRUE;
+ subpackets[i].rrpd.calculation = RTE_CALC_SMB2;
+ subpackets[i].pkt_of_interest = TRUE;
+ }
+ return (int)msg_id_count;
+ }
+
+ return 1;
+}
+
+/* Returns the number of sub-packets of interest */
+int decode_gtcp(packet_info *pinfo, proto_tree *tree, PKT_INFO* pkt_info)
+{
+ guint32 field_uint[MAX_RETURNED_ELEMENTS]; /* An extracted field array for unsigned integers */
+ gboolean field_bool[MAX_RETURNED_ELEMENTS]; /* An extracted field array for unsigned integers */
+ size_t field_value_count; /* How many entries are there in the extracted field array */
+
+ if (!extract_uint(tree, hf_of_interest[HF_INTEREST_TCP_STREAM].hf, field_uint, &field_value_count)) {
+ if (field_value_count)
+ pkt_info->rrpd.stream_no = field_uint[0];
+ }
+
+ pkt_info->srcport = pinfo->srcport;
+ pkt_info->dstport = pinfo->destport;
+
+ if (!extract_uint(tree, hf_of_interest[HF_INTEREST_TCP_LEN].hf, field_uint, &field_value_count)) {
+ if (field_value_count)
+ pkt_info->len = field_uint[0];
+ }
+
+ if (!extract_bool(tree, hf_of_interest[HF_INTEREST_TCP_FLAGS_SYN].hf, field_bool, &field_value_count)) {
+ if (field_value_count)
+ pkt_info->tcp_flags_syn = field_bool[0];
+ }
+
+ if (!extract_bool(tree, hf_of_interest[HF_INTEREST_TCP_FLAGS_ACK].hf, field_bool, &field_value_count)) {
+ if (field_value_count)
+ pkt_info->tcp_flags_ack = field_bool[0];
+ }
+
+ if (!extract_bool(tree, hf_of_interest[HF_INTEREST_TCP_FLAGS_RESET].hf, field_bool, &field_value_count)) {
+ if (field_value_count)
+ pkt_info->tcp_flags_reset = field_bool[0];
+ }
+
+ /*
+ * This is an expert info, not a field with a value, so it's either
+ * present or not; if present, it's a retransmission.
+ */
+ if (!extract_instance_count(tree, hf_of_interest[HF_INTEREST_TCP_RETRAN].hf, &field_value_count)) {
+ if (field_value_count)
+ pkt_info->tcp_retran = TRUE;
+ else
+ pkt_info->tcp_retran = FALSE;
+ }
+
+ /*
+ * Another expert info.
+ */
+ if (!extract_instance_count(tree, hf_of_interest[HF_INTEREST_TCP_KEEP_ALIVE].hf, &field_value_count)) {
+ if (field_value_count)
+ pkt_info->tcp_retran = TRUE;
+ else
+ pkt_info->tcp_retran = FALSE;
+ }
+
+ /* we use the SSL Content Type to detect SSL Alerts */
+ if (!extract_uint(tree, hf_of_interest[HF_INTEREST_SSL_CONTENT_TYPE].hf, field_uint, &field_value_count))
+ {
+ if (field_value_count)
+ pkt_info->ssl_content_type = field_uint[0];
+ else
+ pkt_info->ssl_content_type = 0;
+ }
+
+ if (wmem_map_lookup(preferences.tcp_svc_ports, GUINT_TO_POINTER(pkt_info->dstport)) != NULL ||
+ wmem_map_lookup(preferences.tcp_svc_ports, GUINT_TO_POINTER(pkt_info->srcport)) != NULL)
+ {
+ if (wmem_map_lookup(preferences.tcp_svc_ports, GUINT_TO_POINTER(pkt_info->dstport)) != NULL)
+ pkt_info->rrpd.c2s = TRUE;
+
+ pkt_info->rrpd.is_retrans = pkt_info->tcp_retran;
+ pkt_info->rrpd.session_id = 0;
+ pkt_info->rrpd.msg_id = 0;
+ pkt_info->rrpd.calculation = RTE_CALC_GTCP;
+ pkt_info->rrpd.decode_based = FALSE;
+ if (pkt_info->len > 0)
+ pkt_info->pkt_of_interest = TRUE;
+
+ return 1;
+ }
+
+ return 0;
+}
+
+/* Returns the number of sub-packets of interest */
+int decode_dns(packet_info *pinfo _U_, proto_tree *tree, PKT_INFO* pkt_info)
+{
+ guint32 field_uint[MAX_RETURNED_ELEMENTS]; /* An extracted field array for unsigned integers */
+ size_t field_value_count; /* How many entries are there in the extracted field array */
+
+ if (!extract_uint(tree, hf_of_interest[HF_INTEREST_DNS_ID].hf, field_uint, &field_value_count)) {
+ if (field_value_count)
+ pkt_info->rrpd.msg_id = field_uint[0];
+ }
+
+ pkt_info->rrpd.session_id = 1;
+ pkt_info->rrpd.decode_based = TRUE;
+ pkt_info->rrpd.calculation = RTE_CALC_DNS;
+ pkt_info->pkt_of_interest = TRUE;
+
+ return 1;
+}
+
+/* Returns the number of sub-packets of interest */
+int decode_gudp(packet_info *pinfo, proto_tree *tree, PKT_INFO* pkt_info)
+{
+ guint32 field_uint[MAX_RETURNED_ELEMENTS]; /* An extracted field array for unsigned integers */
+ size_t field_value_count; /* How many entries are there in the extracted field array */
+
+ pkt_info->srcport = pinfo->srcport;
+ pkt_info->dstport = pinfo->destport;
+
+ if (!extract_uint(tree, hf_of_interest[HF_INTEREST_UDP_STREAM].hf, field_uint, &field_value_count)) {
+ if (field_value_count)
+ pkt_info->rrpd.stream_no = field_uint[0];
+ }
+
+ if (!extract_uint(tree, hf_of_interest[HF_INTEREST_UDP_LENGTH].hf, field_uint, &field_value_count)) {
+ if (field_value_count)
+ pkt_info->len = field_uint[0];
+ }
+
+ if ((wmem_map_lookup(preferences.udp_svc_ports, GUINT_TO_POINTER(pkt_info->dstport)) != NULL) ||
+ (wmem_map_lookup(preferences.udp_svc_ports, GUINT_TO_POINTER(pkt_info->srcport)) != NULL))
+ {
+ if (wmem_map_lookup(preferences.udp_svc_ports, GUINT_TO_POINTER(pkt_info->dstport)) != NULL)
+ pkt_info->rrpd.c2s = TRUE;
+
+ pkt_info->rrpd.session_id = 0;
+ pkt_info->rrpd.msg_id = 0;
+ pkt_info->rrpd.decode_based = FALSE;
+ pkt_info->rrpd.calculation = RTE_CALC_GUDP;
+ pkt_info->pkt_of_interest = TRUE;
+ }
+
+ return 1;
+}
+
+/*
+ * Editor modelines - https://www.wireshark.org/tools/modelines.html
+ *
+ * Local variables:
+ * c-basic-offset: 4
+ * tab-width: 8
+ * indent-tabs-mode: nil
+ * End:
+ *
+ * vi: set shiftwidth=4 tabstop=8 expandtab:
+ * :indentSize=4:tabSize=8:noTabs=true:
+ */
diff --git a/plugins/epan/transum/decoders.h b/plugins/epan/transum/decoders.h
new file mode 100644
index 00000000..6d95d207
--- /dev/null
+++ b/plugins/epan/transum/decoders.h
@@ -0,0 +1,31 @@
+/* decoders.h
+ * Header file for the TRANSUM response time analyzer post-dissector
+ * By Paul Offord <paul.offord@advance7.com>
+ * Copyright 2016 Advance Seven Limited
+ *
+ * Wireshark - Network traffic analyzer
+ * By Gerald Combs <gerald@wireshark.org>
+ * Copyright 1998 Gerald Combs
+ *
+ * SPDX-License-Identifier: GPL-2.0-or-later
+ */
+
+int decode_syn(packet_info *pinfo, proto_tree *tree, PKT_INFO* pkt_info);
+int decode_dcerpc(packet_info *pinfo, proto_tree *tree, PKT_INFO* pkt_info);
+int decode_smb(packet_info *pinfo, proto_tree *tree, PKT_INFO* pkt_info, PKT_INFO* subpackets);
+int decode_gtcp(packet_info *pinfo, proto_tree *tree, PKT_INFO* pkt_info);
+int decode_dns(packet_info *pinfo, proto_tree *tree, PKT_INFO* pkt_info);
+int decode_gudp(packet_info *pinfo, proto_tree *tree, PKT_INFO* pkt_info);
+
+/*
+ * Editor modelines - https://www.wireshark.org/tools/modelines.html
+ *
+ * Local variables:
+ * c-basic-offset: 4
+ * tab-width: 8
+ * indent-tabs-mode: nil
+ * End:
+ *
+ * vi: set shiftwidth=4 tabstop=8 expandtab:
+ * :indentSize=4:tabSize=8:noTabs=true:
+ */
diff --git a/plugins/epan/transum/extractors.c b/plugins/epan/transum/extractors.c
new file mode 100644
index 00000000..80475ae3
--- /dev/null
+++ b/plugins/epan/transum/extractors.c
@@ -0,0 +1,165 @@
+/* extractors.c
+ * Routines for the TRANSUM response time analyzer post-dissector
+ * By Paul Offord <paul.offord@advance7.com>
+ * Copyright 2016 Advance Seven Limited
+ *
+ * Wireshark - Network traffic analyzer
+ * By Gerald Combs <gerald@wireshark.org>
+ * Copyright 1998 Gerald Combs
+ *
+ * SPDX-License-Identifier: GPL-2.0-or-later
+ */
+#include "config.h"
+#include <epan/prefs.h>
+#include <epan/packet.h>
+#include "extractors.h"
+
+/*
+ This function extracts a field value (e.g. tcp.len) from a tree. Because a packet may contain
+ multiple values for the field, the extracted values are returned in a result_array. The
+ number of array entries is returned in element_count.
+
+ Return is 0 if all went well. If this function return -1 it is probably because the tree did not
+ include the field defined by the field_id.
+ */
+int extract_uint(proto_tree *tree, int field_id, guint32 *result_array, size_t *element_count)
+{
+ GPtrArray *finfo_array;
+
+ *element_count = 0;
+ if (tree == NULL) {
+ return -1;
+ }
+
+ finfo_array = proto_get_finfo_ptr_array(tree, field_id);
+
+ if (finfo_array == NULL) {
+ return -1;
+ }
+
+ *element_count = g_ptr_array_len(finfo_array);
+
+ for (size_t i = 0; i < *element_count && i < MAX_RETURNED_ELEMENTS; i++)
+ {
+ result_array[i] = fvalue_get_uinteger(((field_info*)finfo_array->pdata[i])->value);
+ }
+
+ return 0;
+}
+
+int extract_ui64(proto_tree *tree, int field_id, guint64 *result_array, size_t *element_count)
+{
+ GPtrArray *finfo_array;
+
+ *element_count = 0;
+ if (tree == NULL) {
+ return -1;
+ }
+
+ finfo_array = proto_get_finfo_ptr_array(tree, field_id);
+
+ if (finfo_array == NULL) {
+ return -1;
+ }
+
+ *element_count = g_ptr_array_len(finfo_array);
+
+ for (size_t i = 0; i < *element_count && i < MAX_RETURNED_ELEMENTS; i++)
+ {
+ result_array[i] = fvalue_get_uinteger64(((field_info*)finfo_array->pdata[i])->value);
+ }
+
+ return 0;
+}
+
+int extract_si64(proto_tree *tree, int field_id, guint64 *result_array, size_t *element_count)
+{
+ GPtrArray *finfo_array;
+
+ *element_count = 0;
+ if (tree == NULL) {
+ return -1;
+ }
+
+ finfo_array = proto_get_finfo_ptr_array(tree, field_id);
+
+ if (finfo_array == NULL) {
+ return -1;
+ }
+
+ *element_count = g_ptr_array_len(finfo_array);
+
+ for (size_t i = 0; i < *element_count && i < MAX_RETURNED_ELEMENTS; i++)
+ {
+ result_array[i] = fvalue_get_sinteger64(((field_info*)finfo_array->pdata[i])->value);
+ }
+
+ return 0;
+}
+
+int extract_bool(proto_tree *tree, int field_id, gboolean *result_array, size_t *element_count)
+{
+ GPtrArray *finfo_array;
+
+ *element_count = 0;
+ if (tree == NULL) {
+ return -1;
+ }
+
+ finfo_array = proto_get_finfo_ptr_array(tree, field_id);
+
+ if (finfo_array == NULL) {
+ return -1;
+ }
+
+ *element_count = g_ptr_array_len(finfo_array);
+
+ for (size_t i = 0; i < *element_count && i < MAX_RETURNED_ELEMENTS; i++)
+ {
+ fvalue_t *fv = ((field_info*)finfo_array->pdata[i])->value;
+
+ ws_assert(fvalue_type_ftenum(fv) == FT_BOOLEAN);
+ if (fvalue_get_uinteger64(fv))
+ result_array[i] = TRUE;
+ else
+ result_array[i] = FALSE;
+ }
+
+ return 0;
+}
+
+/*
+ * Extract a count of the number of instances of a given field.
+ */
+int extract_instance_count(proto_tree *tree, int field_id, size_t *element_count)
+{
+ GPtrArray *finfo_array;
+
+ *element_count = 0;
+ if (tree == NULL) {
+ return -1;
+ }
+
+ finfo_array = proto_get_finfo_ptr_array(tree, field_id);
+
+ if (finfo_array == NULL) {
+ return -1;
+ }
+
+ *element_count = g_ptr_array_len(finfo_array);
+
+ return 0;
+}
+
+/*
+ * Editor modelines - https://www.wireshark.org/tools/modelines.html
+ *
+ * Local variables:
+ * c-basic-offset: 4
+ * tab-width: 8
+ * indent-tabs-mode: nil
+ * End:
+ *
+ * vi: set shiftwidth=4 tabstop=8 expandtab:
+ * :indentSize=4:tabSize=8:noTabs=true:
+ */
diff --git a/plugins/epan/transum/extractors.h b/plugins/epan/transum/extractors.h
new file mode 100644
index 00000000..d56134a6
--- /dev/null
+++ b/plugins/epan/transum/extractors.h
@@ -0,0 +1,21 @@
+/* extractors.h
+ * Header file for the TRANSUM response time analyzer post-dissector
+ * By Paul Offord <paul.offord@advance7.com>
+ * Copyright 2016 Advance Seven Limited
+ *
+ * Wireshark - Network traffic analyzer
+ * By Gerald Combs <gerald@wireshark.org>
+ * Copyright 1998 Gerald Combs
+ *
+ * SPDX-License-Identifier: GPL-2.0-or-later
+ */
+#include <epan/prefs.h>
+#include <epan/packet.h>
+
+#define MAX_RETURNED_ELEMENTS 16
+
+int extract_uint(proto_tree *tree, int field_id, guint32 *result_array, size_t *element_count);
+int extract_ui64(proto_tree *tree, int field_id, guint64 *result_array, size_t *element_count);
+int extract_si64(proto_tree *tree, int field_id, guint64 *result_array, size_t *element_count);
+int extract_bool(proto_tree *tree, int field_id, gboolean *result_array, size_t *element_count);
+int extract_instance_count(proto_tree *tree, int field_id, size_t *element_count);
diff --git a/plugins/epan/transum/packet-transum.c b/plugins/epan/transum/packet-transum.c
new file mode 100644
index 00000000..1022423a
--- /dev/null
+++ b/plugins/epan/transum/packet-transum.c
@@ -0,0 +1,1366 @@
+/* packet-transum.c
+ * Routines for the TRANSUM response time analyzer post-dissector
+ * By Paul Offord <paul.offord@advance7.com>
+ * Copyright 2016 Advance Seven Limited
+ *
+ * Wireshark - Network traffic analyzer
+ * By Gerald Combs <gerald@wireshark.org>
+ * Copyright 1998 Gerald Combs
+ *
+ * SPDX-License-Identifier: GPL-2.0-or-later
+ */
+
+/* ToDo: Test handling of multiple SMB2 messages within a packet */
+/* ToDo: Rework the Summarizer code (future release) */
+
+#include "config.h"
+#define WS_LOG_DOMAIN "transum"
+
+#include <epan/proto.h>
+#include <epan/packet.h>
+#include <epan/prefs.h>
+#include <epan/ws_printf.h>
+#include "packet-transum.h"
+#include "preferences.h"
+#include "extractors.h"
+#include "decoders.h"
+#include <wsutil/wslog.h>
+
+void proto_register_transum(void);
+void proto_reg_handoff_transum(void);
+
+static dissector_handle_t transum_handle;
+
+#define CAPTURE_CLIENT 0
+#define CAPTURE_INTERMEDIATE 1
+#define CAPTURE_SERVICE 2
+
+#define RTE_TIME_SEC 1
+#define RTE_TIME_MSEC 1000
+#define RTE_TIME_USEC 1000000
+
+/* The following are the field ids for the protocol values used by TRANSUM.
+ Make sure they line up with ehf_of_interest order */
+HF_OF_INTEREST_INFO hf_of_interest[HF_INTEREST_END_OF_LIST] = {
+ { -1, "ip.proto" },
+ { -1, "ipv6.nxt" },
+
+ { -1, "tcp.analysis.retransmission" },
+ { -1, "tcp.analysis.keep_alive" },
+ { -1, "tcp.flags.syn" },
+ { -1, "tcp.flags.ack" },
+ { -1, "tcp.flags.reset" },
+ { -1, "tcp.flags.urg" },
+ { -1, "tcp.seq" },
+ { -1, "tcp.srcport" },
+ { -1, "tcp.dstport" },
+ { -1, "tcp.stream" },
+ { -1, "tcp.len" },
+
+ { -1, "udp.srcport" },
+ { -1, "udp.dstport" },
+ { -1, "udp.stream" },
+ { -1, "udp.length" },
+
+ { -1, "tls.record.content_type" },
+
+ { -1, "tds.type" },
+ { -1, "tds.length" },
+
+ { -1, "smb.mid" },
+
+ { -1, "smb2.sesid" },
+ { -1, "smb2.msg_id" },
+ { -1, "smb2.cmd" },
+
+ { -1, "dcerpc.ver" },
+ { -1, "dcerpc.pkt_type" },
+ { -1, "dcerpc.cn_call_id" },
+ { -1, "dcerpc.cn_ctx_id" },
+
+ { -1, "dns.id"},
+};
+
+
+static range_t *tcp_svc_port_range_values;
+
+static range_t *udp_svc_port_range_values;
+
+TSUM_PREFERENCES preferences;
+
+
+static wmem_map_t *detected_tcp_svc; /* this array is used to track services detected during the syn/syn-ack process */
+
+static wmem_map_t *dcerpc_req_pkt_type; /* used to indicate if a DCE-RPC pkt_type is a request */
+
+static wmem_map_t *dcerpc_streams = NULL; /* used to record TCP stream numbers that are carrying DCE-RPC data */
+
+/*
+This array contains calls and returns that have no TRUE context_id
+This is needed to overcome an apparent bug in Wireshark where
+the field name of context id in parameters is the same as context id
+in a message header
+*/
+static wmem_map_t *dcerpc_context_zero;
+
+/*
+ The rrpd_list holds information about all of the APDU Request-Response Pairs seen in the trace.
+ */
+static wmem_list_t *rrpd_list = NULL;
+
+/*
+ output_rrpd is a hash of pointers to RRPDs on the rrpd_list. The index is the frame number. This hash is
+ used during Wireshark's second scan. As each packet is processed, TRANSUM uses the packet's frame number to index into
+ this hash to determine if we have RTE data for this particular packet, and if so the write_rte function is called.
+ */
+static wmem_map_t *output_rrpd;
+
+/*
+ The temp_rsp_rrpd_list holds RRPDs for APDUs where we have not yet seen the header information and so we can't
+ fully qualify the identification of the RRPD (the identification being ip_proto:stream_no:session_id:msg_id).
+ This only occurs when a) we are using one of the decode_based calculations (such as SMB2), and b) when we have
+ TCP Reassembly enabled. Once we receive a header packet for an APDU we migrate the entry from this array to the
+ main rrpd_list.
+ */
+static wmem_list_t *temp_rsp_rrpd_list = NULL; /* Reuse these for speed and efficient memory use - issue a warning if we run out */
+
+/* Optimisation data - the following is used for various optimisation measures */
+static int highest_tcp_stream_no;
+static int highest_udp_stream_no;
+wmem_map_t *tcp_stream_exceptions;
+
+
+static gint ett_transum = -1;
+static gint ett_transum_header = -1;
+static gint ett_transum_data = -1;
+
+static int proto_transum = -1;
+
+static int hf_tsum_status = -1;
+//static int hf_tsum_time_units = -1;
+static int hf_tsum_req_first_seg = -1;
+static int hf_tsum_req_last_seg = -1;
+static int hf_tsum_rsp_first_seg = -1;
+static int hf_tsum_rsp_last_seg = -1;
+static int hf_tsum_apdu_rsp_time = -1;
+static int hf_tsum_service_time = -1;
+static int hf_tsum_req_spread = -1;
+static int hf_tsum_rsp_spread = -1;
+static int hf_tsum_clip_filter = -1;
+static int hf_tsum_calculation = -1;
+static int hf_tsum_summary = -1;
+static int hf_tsum_req_search = -1;
+static int hf_tsum_rsp_search = -1;
+
+static const enum_val_t capture_position_vals[] = {
+ { "TRACE_CAP_CLIENT", "Client", TRACE_CAP_CLIENT },
+ { "TRACE_CAP_INTERMEDIATE", "Intermediate", TRACE_CAP_INTERMEDIATE },
+ { "TRACE_CAP_SERVICE", "Service", TRACE_CAP_SERVICE },
+ { NULL, NULL, 0}
+};
+
+static const value_string rrdp_calculation_vals[] = {
+ { RTE_CALC_GTCP, "Generic TCP" },
+ { RTE_CALC_SYN, "SYN and SYN/ACK" },
+ { RTE_CALC_DCERPC, "DCE-RPC" },
+ { RTE_CALC_SMB2, "SMB2" },
+ { RTE_CALC_GUDP, "Generic UDP" },
+ { RTE_CALC_DNS, "DNS" },
+
+ { 0, NULL }
+};
+
+/*static const enum_val_t time_multiplier_vals[] = {
+ { "RTE_TIME_SEC", "seconds", RTE_TIME_SEC },
+ { "RTE_TIME_MSEC", "milliseconds", RTE_TIME_MSEC },
+ { "RTE_TIME_USEC", "microseconds", RTE_TIME_USEC },
+ { NULL, NULL, 0}
+};*/
+
+void add_detected_tcp_svc(guint16 port)
+{
+ wmem_map_insert(detected_tcp_svc, GUINT_TO_POINTER(port), GUINT_TO_POINTER(port));
+}
+
+
+static void init_dcerpc_data(void)
+{
+ wmem_map_insert(dcerpc_req_pkt_type, GUINT_TO_POINTER(0), GUINT_TO_POINTER(1));
+ wmem_map_insert(dcerpc_req_pkt_type, GUINT_TO_POINTER(11), GUINT_TO_POINTER(1));
+ wmem_map_insert(dcerpc_req_pkt_type, GUINT_TO_POINTER(14), GUINT_TO_POINTER(1));
+
+ wmem_map_insert(dcerpc_context_zero, GUINT_TO_POINTER(11), GUINT_TO_POINTER(11));
+ wmem_map_insert(dcerpc_context_zero, GUINT_TO_POINTER(12), GUINT_TO_POINTER(12));
+ wmem_map_insert(dcerpc_context_zero, GUINT_TO_POINTER(14), GUINT_TO_POINTER(14));
+ wmem_map_insert(dcerpc_context_zero, GUINT_TO_POINTER(15), GUINT_TO_POINTER(15));
+}
+
+static void register_dcerpc_stream(guint32 stream_no)
+{
+ wmem_map_insert(dcerpc_streams, GUINT_TO_POINTER(stream_no), GUINT_TO_POINTER(1));
+}
+
+/* This function should be called before any change to RTE data. */
+static void null_output_rrpd_entries(RRPD *in_rrpd)
+{
+ wmem_map_remove(output_rrpd, GUINT_TO_POINTER(in_rrpd->req_first_frame));
+ wmem_map_remove(output_rrpd, GUINT_TO_POINTER(in_rrpd->req_last_frame));
+ wmem_map_remove(output_rrpd, GUINT_TO_POINTER(in_rrpd->rsp_first_frame));
+ wmem_map_remove(output_rrpd, GUINT_TO_POINTER(in_rrpd->rsp_last_frame));
+}
+
+/* This function should be called after any change to RTE data. */
+static void update_output_rrpd(RRPD *in_rrpd)
+{
+ if (preferences.rte_on_first_req)
+ wmem_map_insert(output_rrpd, GUINT_TO_POINTER(in_rrpd->req_first_frame), in_rrpd);
+
+ if (preferences.rte_on_last_req)
+ wmem_map_insert(output_rrpd, GUINT_TO_POINTER(in_rrpd->req_last_frame), in_rrpd);
+
+ if (preferences.rte_on_first_rsp)
+ wmem_map_insert(output_rrpd, GUINT_TO_POINTER(in_rrpd->rsp_first_frame), in_rrpd);
+
+ if (preferences.rte_on_last_rsp)
+ wmem_map_insert(output_rrpd, GUINT_TO_POINTER(in_rrpd->rsp_last_frame), in_rrpd);
+}
+
+/* Return the index of the RRPD that has been appended */
+static RRPD* append_to_rrpd_list(RRPD *in_rrpd)
+{
+ RRPD *next_rrpd = (RRPD*)wmem_memdup(wmem_file_scope(), in_rrpd, sizeof(RRPD));
+
+ update_output_rrpd(next_rrpd);
+
+ wmem_list_append(rrpd_list, next_rrpd);
+
+ return next_rrpd;
+}
+
+static RRPD *find_latest_rrpd_dcerpc(RRPD *in_rrpd)
+{
+ RRPD *rrpd;
+ wmem_list_frame_t* i;
+
+ for (i = wmem_list_tail(rrpd_list); i != NULL; i = wmem_list_frame_prev(i))
+ {
+ rrpd = (RRPD*)wmem_list_frame_data(i);
+
+ if (rrpd->calculation != RTE_CALC_DCERPC && rrpd->calculation != RTE_CALC_SYN)
+ continue;
+
+ /* if the input 5-tuple doesn't match the rrpd_list_entry 5-tuple -> go find the next list entry */
+ if (rrpd->ip_proto == in_rrpd->ip_proto && rrpd->stream_no == in_rrpd->stream_no)
+ {
+ /* if we can match on session_id and msg_id must be a retransmission of the last request packet or the response */
+ /* this logic works whether or not we are using reassembly */
+ if (rrpd->session_id == in_rrpd->session_id && rrpd->msg_id == in_rrpd->msg_id)
+ return rrpd;
+
+ /* If this is a retransmission, we assume it relates to this rrpd_list entry.
+ This is a bit of a kludge and not ideal but a compromise.*/
+ /* ToDo: look at using TCP sequence number to allocate a retransmission to the correct APDU */
+ if (in_rrpd->is_retrans)
+ return rrpd;
+
+ if (preferences.reassembly)
+ {
+ if (in_rrpd->c2s)
+ {
+ /* if the input rrpd is for c2s and the one we have found already has response information, then the
+ in_rrpd represents a new RR Pair. */
+ if (rrpd->rsp_first_frame)
+ return NULL;
+
+ /* If the current rrpd_list entry doesn't have a msg_id then we assume we are mid Request APDU and so we have a match. */
+ if (!rrpd->msg_id)
+ return rrpd;
+ }
+ else /* The in_rrpd relates to a packet going s2c */
+ {
+ /* When reassembly is enabled, multi-packet response information is actually migrated from the temp_rsp_rrpd_list
+ to the rrpd_list and so we won't come through here. */
+ ;
+ }
+ }
+ else /* we are not using reassembly */
+ {
+ if (in_rrpd->c2s)
+ {
+ if (in_rrpd->msg_id)
+ /* if we have a message id this is a new Request APDU */
+ return NULL;
+ else /* No msg_id */
+ {
+ return rrpd; /* add this packet to the matching stream */
+ }
+ }
+ else /* this packet is going s2c */
+ {
+ if (!in_rrpd->msg_id && rrpd->rsp_first_frame)
+ /* we need to add this frame to the response APDU of the most recent rrpd_list entry that has already had response packets */
+ return rrpd;
+ }
+ }
+ } /* this is the end of the 5-tuple check */
+
+ if (in_rrpd->c2s)
+ in_rrpd->req_search_total++;
+ else
+ in_rrpd->rsp_search_total++;
+ } /* end of the for loop */
+
+ return NULL;
+}
+
+static RRPD *find_latest_rrpd_dns(RRPD *in_rrpd)
+{
+ RRPD *rrpd;
+ wmem_list_frame_t* i;
+
+ for (i = wmem_list_tail(rrpd_list); i != NULL; i = wmem_list_frame_prev(i))
+ {
+ rrpd = (RRPD*)wmem_list_frame_data(i);
+
+ if (rrpd->calculation != RTE_CALC_DNS)
+ continue;
+
+ /* if the input 5-tuple doesn't match the rrpd_list_entry 5-tuple -> go find the next list entry */
+ if (rrpd->ip_proto == in_rrpd->ip_proto && rrpd->stream_no == in_rrpd->stream_no)
+ {
+ if (rrpd->session_id == in_rrpd->session_id && rrpd->msg_id == in_rrpd->msg_id)
+ {
+ if (in_rrpd->c2s && rrpd->rsp_first_frame)
+ return NULL; /* this is new */
+ else
+ return rrpd;
+ }
+ } /* this is the end of the 5-tuple check */
+
+ if (in_rrpd->c2s)
+ in_rrpd->req_search_total++;
+ else
+ in_rrpd->rsp_search_total++;
+ } /* this is the end of the for loop */
+
+ return NULL;
+}
+
+static RRPD *find_latest_rrpd_gtcp(RRPD *in_rrpd)
+{
+ RRPD *rrpd;
+ wmem_list_frame_t* i;
+
+ for (i = wmem_list_tail(rrpd_list); i != NULL; i = wmem_list_frame_prev(i))
+ {
+ rrpd = (RRPD*)wmem_list_frame_data(i);
+
+ if (rrpd->calculation != RTE_CALC_GTCP && rrpd->calculation != RTE_CALC_SYN)
+ continue;
+
+ /* if the input 5-tuple doesn't match the rrpd_list_entry 5-tuple -> go find the next list entry */
+ if (rrpd->ip_proto == in_rrpd->ip_proto && rrpd->stream_no == in_rrpd->stream_no)
+ {
+ if (in_rrpd->c2s && rrpd->rsp_first_frame)
+ return NULL; /* this is new */
+ else
+ return rrpd;
+ } /* this is the end of the 5-tuple check */
+
+ if (in_rrpd->c2s)
+ in_rrpd->req_search_total++;
+ else
+ in_rrpd->rsp_search_total++;
+ } /* this is the end of the for loop */
+
+ return NULL;
+}
+
+static RRPD *find_latest_rrpd_gudp(RRPD *in_rrpd)
+{
+ RRPD *rrpd;
+ wmem_list_frame_t* i;
+
+ for (i = wmem_list_tail(rrpd_list); i != NULL; i = wmem_list_frame_prev(i))
+ {
+ rrpd = (RRPD*)wmem_list_frame_data(i);
+
+ if (rrpd->calculation != RTE_CALC_GUDP)
+ continue;
+
+ /* if the input 5-tuple doesn't match the rrpd_list_entry 5-tuple -> go find the next list entry */
+ if (rrpd->ip_proto == in_rrpd->ip_proto && rrpd->stream_no == in_rrpd->stream_no)
+ {
+ if (in_rrpd->c2s && rrpd->rsp_first_frame)
+ return NULL; /* this is new */
+ else
+ return rrpd;
+ } /* this is the end of the 5-tuple check */
+
+ if (in_rrpd->c2s)
+ in_rrpd->req_search_total++;
+ else
+ in_rrpd->rsp_search_total++;
+ } /* this is the end of the for loop */
+
+ return NULL;
+}
+
+static RRPD *find_latest_rrpd_smb2(RRPD *in_rrpd)
+{
+ RRPD *rrpd;
+ wmem_list_frame_t* i;
+
+ for (i = wmem_list_tail(rrpd_list); i != NULL; i = wmem_list_frame_prev(i))
+ {
+ rrpd = (RRPD*)wmem_list_frame_data(i);
+
+ if (rrpd->calculation != RTE_CALC_SMB2 && rrpd->calculation != RTE_CALC_SYN)
+ continue;
+
+ /* if the input 5-tuple doesn't match the rrpd_list_entry 5-tuple -> go find the next list entry */
+ if (rrpd->ip_proto == in_rrpd->ip_proto && rrpd->stream_no == in_rrpd->stream_no)
+ {
+ /* if we can match on session_id and msg_id must be a retransmission of the last request packet or the response */
+ /* this logic works whether or not we are using reassembly */
+ if (rrpd->session_id == in_rrpd->session_id && rrpd->msg_id == in_rrpd->msg_id)
+ return rrpd;
+
+ /* If this is a retransmission, we assume it relates to this rrpd_list entry.
+ This is a bit of a kludge and not ideal but a compromise.*/
+ /* ToDo: look at using TCP sequence number to allocate a retransmission to the correct APDU */
+ if (in_rrpd->is_retrans)
+ return rrpd;
+
+ if (preferences.reassembly)
+ {
+ if (in_rrpd->c2s)
+ {
+ /* if the input rrpd is for c2s and the one we have found already has response information, then the
+ in_rrpd represents a new RR Pair. */
+ if (rrpd->rsp_first_frame)
+ return NULL;
+
+ /* If the current rrpd_list entry doesn't have a msg_id then we assume we are mid Request APDU and so we have a match. */
+ if (!rrpd->msg_id)
+ return rrpd;
+ }
+ else /* The in_rrpd relates to a packet going s2c */
+ {
+ /* When reassembly is enabled, multi-packet response information is actually migrated from the temp_rsp_rrpd_list
+ to the rrpd_list and so we won't come through here. */
+ ;
+ }
+ }
+ else /* we are not using reassembly */
+ {
+ if (in_rrpd->c2s)
+ {
+ if (in_rrpd->msg_id)
+ /* if we have a message id this is a new Request APDU */
+ return NULL;
+ else /* No msg_id */
+ {
+ return rrpd; /* add this packet to the matching stream */
+ }
+ }
+ else /* this packet is going s2c */
+ {
+ if (!in_rrpd->msg_id && rrpd->rsp_first_frame)
+ /* we need to add this frame to the response APDU of the most recent rrpd_list entry that has already had response packets */
+ return rrpd;
+ }
+ }
+ } /* this is the end of the 5-tuple check */
+
+ if (in_rrpd->c2s)
+ in_rrpd->req_search_total++;
+ else
+ in_rrpd->rsp_search_total++;
+ } /* end of the for loop */
+
+ return NULL;
+}
+
+static RRPD *find_latest_rrpd_syn(RRPD *in_rrpd)
+{
+ RRPD *rrpd;
+ wmem_list_frame_t* i;
+
+ for (i = wmem_list_tail(rrpd_list); i != NULL; i = wmem_list_frame_prev(i))
+ {
+ rrpd = (RRPD*)wmem_list_frame_data(i);
+
+ if (rrpd->calculation != RTE_CALC_SYN)
+ continue;
+
+ /* if the input 5-tuple doesn't match the rrpd_list_entry 5-tuple -> go find the next list entry */
+ if (rrpd->ip_proto == in_rrpd->ip_proto && rrpd->stream_no == in_rrpd->stream_no)
+ {
+ return rrpd;
+ } /* this is the end of the 5-tuple check */
+
+ if (in_rrpd->c2s)
+ in_rrpd->req_search_total++;
+ else
+ in_rrpd->rsp_search_total++;
+ } /* this is the end of the for loop */
+
+ return NULL;
+}
+
+static RRPD *find_latest_rrpd(RRPD *in_rrpd)
+{
+ /* Optimisation Code */
+ if (in_rrpd->ip_proto == IP_PROTO_TCP && (int)in_rrpd->stream_no > highest_tcp_stream_no)
+ {
+ highest_tcp_stream_no = in_rrpd->stream_no;
+ return NULL;
+ }
+ else if (in_rrpd->ip_proto == IP_PROTO_UDP && (int)in_rrpd->stream_no > highest_udp_stream_no)
+ {
+ highest_udp_stream_no = in_rrpd->stream_no;
+ return NULL;
+ }
+ /* End of Optimisation Code */
+
+ switch (in_rrpd->calculation)
+ {
+ case RTE_CALC_DCERPC:
+ return find_latest_rrpd_dcerpc(in_rrpd);
+ break;
+
+ case RTE_CALC_DNS:
+ return find_latest_rrpd_dns(in_rrpd);
+ break;
+
+ case RTE_CALC_GTCP:
+ return find_latest_rrpd_gtcp(in_rrpd);
+ break;
+
+ case RTE_CALC_GUDP:
+ return find_latest_rrpd_gudp(in_rrpd);
+ break;
+
+ case RTE_CALC_SMB2:
+ return find_latest_rrpd_smb2(in_rrpd);
+ break;
+
+ case RTE_CALC_SYN:
+ return find_latest_rrpd_syn(in_rrpd);
+ break;
+ }
+
+ return NULL;
+}
+
+static void update_rrpd_list_entry(RRPD *match, RRPD *in_rrpd)
+{
+ null_output_rrpd_entries(match);
+
+ if (preferences.debug_enabled)
+ {
+ match->req_search_total += in_rrpd->req_search_total;
+ match->rsp_search_total += in_rrpd->rsp_search_total;
+ }
+
+ if (in_rrpd->c2s)
+ {
+ match->req_last_frame = in_rrpd->req_last_frame;
+ match->req_last_rtime = in_rrpd->req_last_rtime;
+ if (in_rrpd->msg_id)
+ {
+ match->session_id = in_rrpd->session_id;
+ match->msg_id = in_rrpd->msg_id;
+ }
+ }
+ else
+ {
+ if (!match->rsp_first_frame)
+ {
+ match->rsp_first_frame = in_rrpd->rsp_first_frame;
+ match->rsp_first_rtime = in_rrpd->rsp_first_rtime;
+ }
+ match->rsp_last_frame = in_rrpd->rsp_last_frame;
+ match->rsp_last_rtime = in_rrpd->rsp_last_rtime;
+ }
+
+ update_output_rrpd(match);
+}
+
+/*
+ This function processes a sub-packet that is going from client-to-service.
+ */
+static void update_rrpd_list_entry_req(RRPD *in_rrpd)
+{
+ RRPD *match;
+
+ match = find_latest_rrpd(in_rrpd);
+
+ if (match != NULL)
+ update_rrpd_list_entry(match, in_rrpd);
+ else
+ append_to_rrpd_list(in_rrpd);
+}
+
+/*
+ This function inserts an RRPD into the temp_rsp_rrpd_list. If this is
+ successful return a pointer to the entry, else return NULL.
+ */
+static RRPD* insert_into_temp_rsp_rrpd_list(RRPD *in_rrpd)
+{
+ RRPD *rrpd = (RRPD*)wmem_memdup(wmem_file_scope(), in_rrpd, sizeof(RRPD));
+
+ wmem_list_append(temp_rsp_rrpd_list, rrpd);
+
+ return rrpd;
+}
+
+static RRPD* find_temp_rsp_rrpd(RRPD *in_rrpd)
+{
+ wmem_list_frame_t *i;
+ RRPD* rrpd;
+
+ for (i = wmem_list_head(temp_rsp_rrpd_list); i; i = wmem_list_frame_next(i))
+ {
+ rrpd = (RRPD*)wmem_list_frame_data(i);
+ if (rrpd->ip_proto == in_rrpd->ip_proto && rrpd->stream_no == in_rrpd->stream_no)
+ return rrpd;
+ }
+
+ return NULL;
+}
+
+static void update_temp_rsp_rrpd(RRPD *temp_list, RRPD *in_rrpd)
+{
+ temp_list->rsp_last_frame = in_rrpd->rsp_last_frame;
+ temp_list->rsp_last_rtime = in_rrpd->rsp_last_rtime;
+}
+
+/* This function migrates an entry from the temp_rsp_rrpd_list to the main rrpd_list. */
+static void migrate_temp_rsp_rrpd(RRPD *main_list, RRPD *temp_list)
+{
+ update_rrpd_list_entry(main_list, temp_list);
+
+ wmem_list_remove(temp_rsp_rrpd_list, temp_list);
+}
+
+static void update_rrpd_list_entry_rsp(RRPD *in_rrpd)
+{
+ RRPD *match, *temp_list;
+
+ if (in_rrpd->decode_based)
+ {
+ if (preferences.reassembly)
+ {
+ if (in_rrpd->msg_id)
+ {
+ /* If we have a msg_id in the input RRPD we must have header information. */
+ temp_list = find_temp_rsp_rrpd(in_rrpd);
+
+ if (temp_list != NULL)
+ {
+ update_temp_rsp_rrpd(temp_list, in_rrpd);
+
+ /* Migrate the temp_rsp_rrpd_list entry to the main rrpd_list */
+ match = find_latest_rrpd(in_rrpd);
+ if (match != NULL)
+ migrate_temp_rsp_rrpd(match, temp_list);
+ }
+ else
+ {
+ match = find_latest_rrpd(in_rrpd);
+ /* There isn't an entry in the temp_rsp_rrpd_list so update the master rrpd_list entry */
+ if (match != NULL)
+ update_rrpd_list_entry(match, in_rrpd);
+ }
+ }
+ else
+ {
+ /* Update an existing entry to the temp_rsp_rrpd_list or add a new one. */
+ temp_list = find_temp_rsp_rrpd(in_rrpd);
+
+ if (temp_list != NULL)
+ update_temp_rsp_rrpd(temp_list, in_rrpd);
+ else
+ {
+ /* If this is a retransmission we need to add it to the last completed rrpd_list entry for this stream */
+ if (in_rrpd->is_retrans)
+ {
+ match = find_latest_rrpd(in_rrpd);
+
+ if (match != NULL)
+ update_rrpd_list_entry(match, in_rrpd);
+ else
+ insert_into_temp_rsp_rrpd_list(in_rrpd);
+ }
+ else
+ /* As it's not a retransmission, just create a new entry on the temp list */
+ insert_into_temp_rsp_rrpd_list(in_rrpd);
+ }
+ }
+ }
+ else
+ {
+ /* Reassembly isn't set and so just go ahead and use the list function */
+ match = find_latest_rrpd(in_rrpd);
+ if (match != NULL)
+ update_rrpd_list_entry(match, in_rrpd);
+ }
+ }
+ else
+ {
+ /* if this isn't decode_based then just go ahead and update the RTE data */
+ match = find_latest_rrpd(in_rrpd);
+ if (match != NULL)
+ update_rrpd_list_entry(match, in_rrpd);
+ }
+
+ return;
+}
+
+
+/*
+ This function updates the RTE data of an RRPD on the rrpd_list. The
+ frame_no values in the input RRPD double up as a mask. If the frame_no
+ is > 0 then the frame_no value and rtime values are updated. If the
+ frame_no is 0 then that particular frame_no and rtime value is not updated.
+ */
+static void update_rrpd_rte_data(RRPD *in_rrpd)
+{
+ if (in_rrpd->c2s)
+ update_rrpd_list_entry_req(in_rrpd);
+ else
+ update_rrpd_list_entry_rsp(in_rrpd);
+}
+
+gboolean is_dcerpc_context_zero(guint32 pkt_type)
+{
+ return (wmem_map_lookup(dcerpc_context_zero, GUINT_TO_POINTER(pkt_type)) != NULL);
+}
+
+gboolean is_dcerpc_req_pkt_type(guint32 pkt_type)
+{
+ return (wmem_map_lookup(dcerpc_req_pkt_type, GUINT_TO_POINTER(pkt_type)) != NULL);
+}
+
+static gboolean is_dcerpc_stream(guint32 stream_no)
+{
+ return (wmem_map_lookup(dcerpc_streams, GUINT_TO_POINTER(stream_no)) != NULL);
+}
+
+/*
+ This function initialises the global variables and populates the
+ [tcp|udp]_svc_ports tables with information from the preference settings
+ */
+static void init_globals(void)
+{
+ if (!proto_is_protocol_enabled(find_protocol_by_id(proto_transum)))
+ return;
+
+ highest_tcp_stream_no = -1;
+ highest_udp_stream_no = -1;
+
+ /* Create and initialise some dynamic memory areas */
+ tcp_stream_exceptions = wmem_map_new(wmem_file_scope(), g_direct_hash, g_direct_equal);
+ detected_tcp_svc = wmem_map_new(wmem_file_scope(), g_direct_hash, g_direct_equal);
+ rrpd_list = wmem_list_new(wmem_file_scope());
+ temp_rsp_rrpd_list = wmem_list_new(wmem_file_scope());
+
+ /* Indicate what fields we're interested in. */
+ GArray *wanted_fields = g_array_sized_new(FALSE, FALSE, (guint)sizeof(int), HF_INTEREST_END_OF_LIST);
+ for (int i = 0; i < HF_INTEREST_END_OF_LIST; i++)
+ {
+ if (hf_of_interest[i].hf != -1)
+ g_array_append_val(wanted_fields, hf_of_interest[i].hf);
+ else
+ ws_warning("TRANSUM: unknown field %s", hf_of_interest[i].proto_name);
+ }
+ set_postdissector_wanted_hfids(transum_handle, wanted_fields);
+
+ preferences.tcp_svc_ports = wmem_map_new(wmem_file_scope(), g_direct_hash, g_direct_equal);
+ preferences.udp_svc_ports = wmem_map_new(wmem_file_scope(), g_direct_hash, g_direct_equal);
+
+ /* use the range values to populate the tcp_svc_ports list*/
+ for (guint i = 0; i < tcp_svc_port_range_values->nranges; i++)
+ {
+ for (guint32 j = tcp_svc_port_range_values->ranges[i].low; j <= tcp_svc_port_range_values->ranges[i].high; j++)
+ {
+ wmem_map_insert(preferences.tcp_svc_ports, GUINT_TO_POINTER(j), GUINT_TO_POINTER(RTE_CALC_GTCP));
+ }
+ }
+
+ /* use the range values to populate the udp_svc_ports list*/
+ for (guint i = 0; i < udp_svc_port_range_values->nranges; i++)
+ {
+ for (guint32 j = udp_svc_port_range_values->ranges[i].low; j <= udp_svc_port_range_values->ranges[i].high; j++)
+ {
+ wmem_map_insert(preferences.udp_svc_ports, GUINT_TO_POINTER(j), GUINT_TO_POINTER(RTE_CALC_GUDP));
+ }
+ }
+
+ /* create arrays to hold some DCE-RPC values */
+ dcerpc_context_zero = wmem_map_new(wmem_file_scope(), g_direct_hash, g_direct_equal);
+ dcerpc_req_pkt_type = wmem_map_new(wmem_file_scope(), g_direct_hash, g_direct_equal);
+ dcerpc_streams = wmem_map_new(wmem_file_scope(), g_direct_hash, g_direct_equal);
+ init_dcerpc_data();
+
+ wmem_map_insert(preferences.tcp_svc_ports, GUINT_TO_POINTER(445), GUINT_TO_POINTER(RTE_CALC_SMB2));
+ wmem_map_insert(preferences.udp_svc_ports, GUINT_TO_POINTER(53), GUINT_TO_POINTER(RTE_CALC_DNS));
+}
+
+/* Undo capture file-specific initializations. */
+static void cleanup_globals(void)
+{
+ /* Clear the list of wanted fields as it will be reinitialized. */
+ set_postdissector_wanted_hfids(transum_handle, NULL);
+}
+
+/* This function adds the RTE data to the tree. The summary ptr is currently
+ not used but will be used for summariser information once this feature has
+ been ported from the Lua code. */
+static void write_rte(RRPD *in_rrpd, tvbuff_t *tvb, packet_info *pinfo, proto_tree *tree, char *summary)
+{
+ nstime_t rte_art;
+ nstime_t rte_st;
+ nstime_t rte_reqspread;
+ nstime_t rte_rspspread;
+ proto_tree *rte_tree;
+ proto_item *pi;
+ wmem_strbuf_t *temp_string = wmem_strbuf_new(pinfo->pool, "");
+
+ if (in_rrpd->req_first_frame)
+ {
+ pi = proto_tree_add_item(tree, proto_transum, tvb, 0, 0, ENC_NA);
+ rte_tree = proto_item_add_subtree(pi, ett_transum);
+
+ nstime_delta(&rte_reqspread, &(in_rrpd->req_last_rtime), &(in_rrpd->req_first_rtime));
+ if (in_rrpd->rsp_first_frame)
+ {
+ /* calculate the RTE times */
+ nstime_delta(&rte_art, &(in_rrpd->rsp_last_rtime), &(in_rrpd->req_first_rtime));
+ nstime_delta(&rte_st, &(in_rrpd->rsp_first_rtime), &(in_rrpd->req_last_rtime));
+ nstime_delta(&rte_rspspread, &(in_rrpd->rsp_last_rtime), &(in_rrpd->rsp_first_rtime));
+
+ pi = proto_tree_add_string(rte_tree, hf_tsum_status, tvb, 0, 0, "OK");
+ }
+ else
+ {
+ pi = proto_tree_add_string(rte_tree, hf_tsum_status, tvb, 0, 0, "Response missing");
+ }
+ proto_item_set_generated(pi);
+
+
+ pi = proto_tree_add_uint(rte_tree, hf_tsum_req_first_seg, tvb, 0, 0, in_rrpd->req_first_frame);
+ proto_item_set_generated(pi);
+ pi = proto_tree_add_uint(rte_tree, hf_tsum_req_last_seg, tvb, 0, 0, in_rrpd->req_last_frame);
+ proto_item_set_generated(pi);
+
+ if (in_rrpd->rsp_first_frame)
+ {
+ pi = proto_tree_add_uint(rte_tree, hf_tsum_rsp_first_seg, tvb, 0, 0, in_rrpd->rsp_first_frame);
+ proto_item_set_generated(pi);
+ pi = proto_tree_add_uint(rte_tree, hf_tsum_rsp_last_seg, tvb, 0, 0, in_rrpd->rsp_last_frame);
+ proto_item_set_generated(pi);
+
+ pi = proto_tree_add_time(rte_tree, hf_tsum_apdu_rsp_time, tvb, 0, 0, &rte_art);
+ proto_item_set_generated(pi);
+ pi = proto_tree_add_time(rte_tree, hf_tsum_service_time, tvb, 0, 0, &rte_st);
+ proto_item_set_generated(pi);
+ }
+
+ pi = proto_tree_add_time(rte_tree, hf_tsum_req_spread, tvb, 0, 0, &rte_reqspread);
+ proto_item_set_generated(pi);
+
+ if (in_rrpd->rsp_first_frame)
+ {
+ pi = proto_tree_add_time(rte_tree, hf_tsum_rsp_spread, tvb, 0, 0, &rte_rspspread);
+ proto_item_set_generated(pi);
+ }
+
+ if (in_rrpd->ip_proto == IP_PROTO_TCP)
+ wmem_strbuf_append_printf(temp_string, "tcp.stream==%d", in_rrpd->stream_no);
+ else if (in_rrpd->ip_proto == IP_PROTO_UDP)
+ wmem_strbuf_append_printf(temp_string, "udp.stream==%d", in_rrpd->stream_no);
+
+ if (in_rrpd->rsp_first_frame)
+ wmem_strbuf_append_printf(temp_string, " && frame.number>=%d && frame.number<=%d", in_rrpd->req_first_frame, in_rrpd->rsp_last_frame);
+ else
+ wmem_strbuf_append_printf(temp_string, " && frame.number>=%d && frame.number<=%d", in_rrpd->req_first_frame, in_rrpd->req_last_frame);
+
+ if (in_rrpd->calculation == RTE_CALC_GTCP)
+ wmem_strbuf_append_printf(temp_string, " && tcp.len>0");
+
+ pi = proto_tree_add_string(rte_tree, hf_tsum_clip_filter, tvb, 0, 0, wmem_strbuf_get_str(temp_string));
+ proto_item_set_generated(pi);
+
+ pi = proto_tree_add_string(rte_tree, hf_tsum_calculation, tvb, 0, 0, val_to_str(in_rrpd->calculation, rrdp_calculation_vals, "Unknown calculation type: %d"));
+ proto_item_set_generated(pi);
+
+ if (in_rrpd->rsp_first_frame)
+ {
+ if (preferences.summarisers_enabled)
+ {
+ if (summary)
+ {
+ pi = proto_tree_add_string(tree, hf_tsum_summary, tvb, 0, 0, summary);
+ proto_item_set_generated(pi);
+ }
+ }
+ }
+
+ if (preferences.debug_enabled)
+ {
+ pi = proto_tree_add_uint(rte_tree, hf_tsum_req_search, tvb, 0, 0, in_rrpd->req_search_total);
+ proto_item_set_generated(pi);
+ pi = proto_tree_add_uint(rte_tree, hf_tsum_rsp_search, tvb, 0, 0, in_rrpd->rsp_search_total);
+ proto_item_set_generated(pi);
+ }
+ }
+}
+
+/*
+ This function sets initial values in the current_pkt structure and checks
+ the xxx_svc_port arrays to see if they contain a match for the source or
+ destination port. This function also adds tcp_svc_ports entries when it
+ discovers DCE-RPC traffic.
+
+ Returns the number of sub-packets to be processed.
+*/
+static void set_proto_values(packet_info *pinfo, proto_tree *tree, PKT_INFO* pkt_info, PKT_INFO* subpackets)
+{
+ guint32 field_uint[MAX_RETURNED_ELEMENTS]; /* An extracted field array for unsigned integers */
+ size_t field_value_count; /* How many entries are there in the extracted field array */
+
+ pkt_info->frame_number = pinfo->fd->num; /* easy access to frame number */
+ pkt_info->relative_time = pinfo->rel_ts;
+
+ int number_sub_pkts_of_interest = 0; /* default */
+
+ if (pinfo->ptype == PT_TCP)
+ pkt_info->rrpd.ip_proto = IP_PROTO_TCP;
+ else if (pinfo->ptype == PT_UDP)
+ pkt_info->rrpd.ip_proto = IP_PROTO_UDP;
+
+ if (pkt_info->rrpd.ip_proto == IP_PROTO_TCP)
+ {
+ number_sub_pkts_of_interest = decode_gtcp(pinfo, tree, pkt_info);
+ /* decode_gtcp may return 0 but we need to keep processing because we
+ calculate RTE figures for all SYNs and also we may detect DCE-RPC later
+ (even though we don't currently have an entry in the tcp_svc_ports list). */
+
+ /* Optimisation code */
+ if (pkt_info->len || pkt_info->tcp_flags_syn)
+ {
+ if (pkt_info->ssl_content_type == 21) /* this is an SSL Alert */
+ {
+ pkt_info->pkt_of_interest = FALSE;
+ return;
+ }
+
+ if ((int)pkt_info->rrpd.stream_no > highest_tcp_stream_no && !pkt_info->rrpd.c2s)
+ {
+ /* first packet on the stream is s2c and so add to exception list */
+ if (wmem_map_lookup(tcp_stream_exceptions, GUINT_TO_POINTER(pkt_info->rrpd.stream_no)) == NULL)
+ wmem_map_insert(tcp_stream_exceptions, GUINT_TO_POINTER(pkt_info->rrpd.stream_no), GUINT_TO_POINTER(1));
+ }
+
+ if (wmem_map_lookup(tcp_stream_exceptions, GUINT_TO_POINTER(pkt_info->rrpd.stream_no)) != NULL)
+ {
+ if (pkt_info->rrpd.c2s)
+ wmem_map_remove(tcp_stream_exceptions, GUINT_TO_POINTER(pkt_info->rrpd.stream_no));
+ else
+ pkt_info->pkt_of_interest = FALSE;
+ }
+ }
+ /* End of Optimisation Code */
+
+ if (pkt_info->tcp_retran)
+ {
+ /* we may not want to continue with this packet if it's a retransmission */
+
+ /* If this is a server-side trace we need to ignore client-to-service TCP retransmissions
+ the rationale being that if we saw the original in the trace the service process saw it too */
+ if (pkt_info->rrpd.c2s && preferences.capture_position == CAPTURE_SERVICE)
+ {
+ pkt_info->pkt_of_interest = FALSE;
+ return;
+ }
+
+ /* If this is a client-side trace we need to ignore service-to-client TCP retransmissions
+ the rationale being that if we saw the original in the trace the client process saw it too */
+ else if (!pkt_info->rrpd.c2s && preferences.capture_position == CAPTURE_CLIENT)
+ {
+ pkt_info->pkt_of_interest = FALSE;
+ return;
+ }
+ }
+
+ /* We are not interested in TCP Keep-Alive */
+ if (pkt_info->tcp_keep_alive)
+ {
+ pkt_info->pkt_of_interest = FALSE;
+ return;
+ }
+
+ if (pkt_info->len == 1)
+ {
+ if (preferences.orphan_ka_discard && pkt_info->tcp_flags_ack && pkt_info->rrpd.c2s)
+ {
+ pkt_info->pkt_of_interest = FALSE;
+ return; /* It's a KEEP-ALIVE -> stop processing this packet */
+ }
+ }
+
+ /* check if SYN */
+ if (pkt_info->tcp_flags_syn)
+ number_sub_pkts_of_interest = decode_syn(pinfo, tree, pkt_info);
+
+ if (pkt_info->len > 0)
+ {
+ /* check if SMB2 */
+ if (pkt_info->dstport == 445 || pkt_info->srcport == 445)
+ number_sub_pkts_of_interest = decode_smb(pinfo, tree, pkt_info, subpackets);
+
+ else
+ {
+ /* check if DCE-RPC */
+ /* We need to set RTE_CALC_DCERPC even when we don't have header info. */
+ if (is_dcerpc_stream(pkt_info->rrpd.stream_no))
+ {
+ pkt_info->rrpd.calculation = RTE_CALC_DCERPC;
+ pkt_info->rrpd.decode_based = TRUE;
+ pkt_info->pkt_of_interest = TRUE;
+ }
+
+ if (!extract_uint(tree, hf_of_interest[HF_INTEREST_DCERPC_VER].hf, field_uint, &field_value_count))
+ {
+ if (field_value_count)
+ {
+ if (pkt_info->rrpd.calculation != RTE_CALC_DCERPC)
+ register_dcerpc_stream(pkt_info->rrpd.stream_no);
+
+ number_sub_pkts_of_interest = decode_dcerpc(pinfo, tree, pkt_info);
+ }
+ }
+ }
+ }
+
+ }
+ else if (pkt_info->rrpd.ip_proto == IP_PROTO_UDP)
+ {
+ /* It's UDP */
+ number_sub_pkts_of_interest = decode_gudp(pinfo, tree, pkt_info);
+
+ if (pkt_info->srcport == 53 || pkt_info->dstport == 53)
+ number_sub_pkts_of_interest = decode_dns(pinfo, tree, pkt_info);
+ }
+
+ /* Set appropriate RTE values in the sub-packets */
+ for (int i = 0; (i < number_sub_pkts_of_interest) && (i < MAX_SUBPKTS_PER_PACKET); i++)
+ {
+ if (pkt_info->rrpd.c2s)
+ {
+ subpackets[i].rrpd.req_first_frame = pkt_info->frame_number;
+ subpackets[i].rrpd.req_first_rtime = pkt_info->relative_time;
+ subpackets[i].rrpd.req_last_frame = pkt_info->frame_number;
+ subpackets[i].rrpd.req_last_rtime = pkt_info->relative_time;
+
+ subpackets[i].frame_number = pkt_info->frame_number; /* this acts as a switch later */
+ }
+ else
+ {
+ subpackets[i].rrpd.rsp_first_frame = pkt_info->frame_number;
+ subpackets[i].rrpd.rsp_first_rtime = pkt_info->relative_time;
+ subpackets[i].rrpd.rsp_last_frame = pkt_info->frame_number;
+ subpackets[i].rrpd.rsp_last_rtime = pkt_info->relative_time;
+
+ subpackets[i].frame_number = pkt_info->frame_number; /* this acts as a switch later */
+ }
+ }
+}
+
+
+/*
+ * This function is called for each packet
+ * Wireshark scans all the packets once and then once again as they are displayed
+ * The pinfo.visited boolean is set to FALSE; on the first scan
+*/
+static int dissect_transum(tvbuff_t *buffer, packet_info *pinfo, proto_tree *tree, void *data _U_)
+{
+ /* if (there is RTE info associated with this packet we need to output it */
+ if (PINFO_FD_VISITED(pinfo))
+ {
+ RRPD *rrpd = (RRPD*)wmem_map_lookup(output_rrpd, GUINT_TO_POINTER(pinfo->num));
+
+ if (rrpd)
+ {
+ if (tree)
+ {
+ /* Add the RTE data to the protocol decode tree if we output_flag is set */
+ write_rte(rrpd, buffer, pinfo, tree, NULL);
+ }
+ }
+ }
+ else
+ {
+ PKT_INFO *sub_packet = wmem_alloc0_array(pinfo->pool, PKT_INFO, MAX_SUBPKTS_PER_PACKET);
+
+ set_proto_values(pinfo, tree, &sub_packet[0], sub_packet);
+
+ if (sub_packet[0].pkt_of_interest)
+ {
+ /* Loop to process each sub_packet and update the related RTE data */
+ for (int i = 0; i < MAX_SUBPKTS_PER_PACKET; i++)
+ {
+ if (!sub_packet[i].frame_number)
+ break;
+
+ update_rrpd_rte_data(&(sub_packet[i].rrpd));
+ }
+ }
+ }
+
+ return 0;
+}
+
+void
+proto_register_transum(void)
+{
+ module_t *transum_module;
+
+ static hf_register_info hf[] = {
+ { &hf_tsum_status,
+ { "RTE Status", "transum.status",
+ FT_STRING, BASE_NONE, NULL, 0x0,
+ "Indication of completeness of the RTE information", HFILL } },
+#if 0
+ { &hf_tsum_time_units,
+ { "RTE Time Units", "transum.time_units",
+ FT_STRING, BASE_NONE, NULL, 0x0,
+ "Time units used (s, ms or us) for the RTE values", HFILL }
+ },
+#endif
+ { &hf_tsum_req_first_seg,
+ { "Req First Seg", "transum.firstreq",
+ FT_FRAMENUM, BASE_NONE, NULL, 0x0,
+ "First Segment of an APDU Request", HFILL }
+ },
+
+ { &hf_tsum_req_last_seg,
+ { "Req Last Seg", "transum.lastreq",
+ FT_FRAMENUM, BASE_NONE, NULL, 0x0,
+ "Last Segment of an APDU Request", HFILL }
+ },
+
+ { &hf_tsum_rsp_first_seg,
+ { "Rsp First Seg", "transum.firstrsp",
+ FT_FRAMENUM, BASE_NONE, NULL, 0x0,
+ "First Segment of an APDU Response", HFILL }
+ },
+
+ { &hf_tsum_rsp_last_seg,
+ { "Rsp Last Seg", "transum.lastrsp",
+ FT_FRAMENUM, BASE_NONE, NULL, 0x0,
+ "Last Segment of an APDU Response", HFILL }
+ },
+
+ { &hf_tsum_apdu_rsp_time,
+ { "APDU Rsp Time", "transum.art",
+ FT_RELATIVE_TIME, BASE_NONE, NULL, 0x0,
+ "RTE APDU Response Time", HFILL }
+ },
+
+ { &hf_tsum_service_time,
+ { "Service Time", "transum.st",
+ FT_RELATIVE_TIME, BASE_NONE, NULL, 0x0,
+ "RTE Service Time", HFILL }
+ },
+
+ { &hf_tsum_req_spread,
+ { "Req Spread", "transum.reqspread",
+ FT_RELATIVE_TIME, BASE_NONE, NULL, 0x0,
+ "RTE Request Spread", HFILL }
+ },
+
+ { &hf_tsum_rsp_spread,
+ { "Rsp Spread", "transum.rspspread",
+ FT_RELATIVE_TIME, BASE_NONE, NULL, 0x0,
+ "RTE Response Spread", HFILL }
+ },
+
+ { &hf_tsum_clip_filter,
+ { "Trace clip filter", "transum.clip_filter",
+ FT_STRING, BASE_NONE, NULL, 0x0,
+ "Filter expression to select the APDU Request-Response pair", HFILL }
+ },
+
+ { &hf_tsum_calculation,
+ { "Calculation", "transum.calculation",
+ FT_STRING, BASE_NONE, NULL, 0x0,
+ "Basis of the RTE calculation", HFILL }
+ },
+
+ { &hf_tsum_summary,
+ { "Summary", "transum.summary",
+ FT_STRING, BASE_NONE, NULL, 0x0,
+ "Summarizer information", HFILL }
+ },
+
+ { &hf_tsum_req_search,
+ { "Req Search Count", "transum.req_search",
+ FT_UINT32, BASE_DEC, NULL, 0x0,
+ "rrpd_list search total for the request packets", HFILL }
+ },
+
+ { &hf_tsum_rsp_search,
+ { "Rsp Search Counts", "transum.rsp_search",
+ FT_UINT32, BASE_DEC, NULL, 0x0,
+ "rrpd_list search total for the response packets", HFILL }
+ }
+
+ };
+
+ /* Setup protocol subtree array */
+ static gint *ett[] = {
+ &ett_transum,
+ &ett_transum_header,
+ &ett_transum_data
+ };
+
+ proto_transum = proto_register_protocol("TRANSUM RTE Data", "TRANSUM", "transum");
+
+ /* Due to performance concerns of the dissector, it's disabled by default */
+ proto_disable_by_default(proto_transum);
+
+
+ /* Set User Preferences defaults */
+ preferences.capture_position = TRACE_CAP_CLIENT;
+ preferences.reassembly = TRUE;
+
+ range_convert_str(wmem_epan_scope(), &tcp_svc_port_range_values, "25, 80, 443, 1433", MAX_TCP_PORT);
+ range_convert_str(wmem_epan_scope(), &udp_svc_port_range_values, "137-139", MAX_UDP_PORT);
+
+ preferences.orphan_ka_discard = FALSE;
+ preferences.time_multiplier = RTE_TIME_SEC;
+ preferences.rte_on_first_req = FALSE;
+ preferences.rte_on_last_req = TRUE;
+ preferences.rte_on_first_rsp = FALSE;
+ preferences.rte_on_last_rsp = FALSE;
+
+ preferences.debug_enabled = FALSE;
+
+ /* no start registering stuff */
+ proto_register_field_array(proto_transum, hf, array_length(hf));
+ proto_register_subtree_array(ett, array_length(ett));
+
+ transum_module = prefs_register_protocol(proto_transum, NULL); /* ToDo: We need to rethink the NULL pointer so that a preference change causes a rescan */
+
+ /* Register the preferences */
+ prefs_register_obsolete_preference(transum_module, "tsumenabled");
+
+ prefs_register_enum_preference(transum_module,
+ "capture_position",
+ "Capture position",
+ "Position of the capture unit that produced this trace. This setting affects the way TRANSUM handles TCP Retransmissions. See the manual for details.",
+ &preferences.capture_position,
+ capture_position_vals,
+ FALSE);
+
+ prefs_register_bool_preference(transum_module,
+ "reassembly",
+ "Subdissector reassembly enabled",
+ "Set this to match to the TCP subdissector reassembly setting",
+ &preferences.reassembly);
+
+ prefs_register_range_preference(transum_module,
+ "tcp_port_ranges",
+ "Output RTE data for these TCP service ports",
+ "Add and remove ports numbers separated by commas\nRanges are supported e.g. 25,80,2000-3000,5432",
+ &tcp_svc_port_range_values,
+ 65536);
+
+ prefs_register_range_preference(transum_module,
+ "udp_port_ranges",
+ "Output RTE data for these UDP service ports",
+ "Add and remove ports numbers separated by commas\nRanges are supported e.g. 123,137-139,520-521,2049",
+ &udp_svc_port_range_values,
+ 65536);
+
+ prefs_register_bool_preference(transum_module,
+ "orphan_ka_discard",
+ "Discard orphaned TCP Keep-Alives",
+ "Set this to discard any packet in the direction client to service,\nwith a 1-byte payload of 0x00 and the ACK flag set",
+ &preferences.orphan_ka_discard);
+
+ /* removed from this release
+ prefs_register_enum_preference(transum_module,
+ "time_multiplier",
+ "Time units for RTE values",
+ "Unit of time used for APDU Response Time, Service Time and Spread Time values.",
+ &preferences.time_multiplier,
+ time_multiplier_vals,
+ FALSE);
+ */
+
+ prefs_register_bool_preference(transum_module,
+ "rte_on_first_req",
+ "Add RTE data to the first request segment",
+ "RTE data will be added to the first request packet",
+ &preferences.rte_on_first_req);
+
+ prefs_register_bool_preference(transum_module,
+ "rte_on_last_req",
+ "Add RTE data to the last request segment",
+ "RTE data will be added to the last request packet",
+ &preferences.rte_on_last_req);
+
+ prefs_register_bool_preference(transum_module,
+ "rte_on_first_rsp",
+ "Add RTE data to the first response segment",
+ "RTE data will be added to the first response packet",
+ &preferences.rte_on_first_rsp);
+
+ prefs_register_bool_preference(transum_module,
+ "rte_on_last_rsp",
+ "Add RTE data to the last response segment",
+ "RTE data will be added to the last response packet",
+ &preferences.rte_on_last_rsp);
+
+ prefs_register_bool_preference(transum_module,
+ "debug_enabled",
+ "Enable debug info",
+ "Set this only to troubleshoot problems",
+ &preferences.debug_enabled);
+
+ transum_handle = register_dissector("transum", dissect_transum, proto_transum);
+
+ register_init_routine(init_globals);
+ register_cleanup_routine(cleanup_globals);
+
+ register_postdissector(transum_handle);
+
+ output_rrpd = wmem_map_new_autoreset(wmem_epan_scope(), wmem_file_scope(), g_direct_hash, g_direct_equal);
+}
+
+void proto_reg_handoff_transum(void)
+{
+ /* Get the field id for each field we will need */
+ for (int i = 0; i < HF_INTEREST_END_OF_LIST; i++)
+ {
+ hf_of_interest[i].hf = proto_registrar_get_id_byname(hf_of_interest[i].proto_name);
+ }
+}
+
+/*
+ * Editor modelines - https://www.wireshark.org/tools/modelines.html
+ *
+ * Local variables:
+ * c-basic-offset: 4
+ * tab-width: 8
+ * indent-tabs-mode: nil
+ * End:
+ *
+ * vi: set shiftwidth=4 tabstop=8 expandtab:
+ * :indentSize=4:tabSize=8:noTabs=true:
+ */
diff --git a/plugins/epan/transum/packet-transum.h b/plugins/epan/transum/packet-transum.h
new file mode 100644
index 00000000..c8915e14
--- /dev/null
+++ b/plugins/epan/transum/packet-transum.h
@@ -0,0 +1,189 @@
+/* packet-transum.h
+ * Header file for the TRANSUM response time analyzer post-dissector
+ * By Paul Offord <paul.offord@advance7.com>
+ * Copyright 2016 Advance Seven Limited
+ *
+ * Wireshark - Network traffic analyzer
+ * By Gerald Combs <gerald@wireshark.org>
+ * Copyright 1998 Gerald Combs
+ *
+ * SPDX-License-Identifier: GPL-2.0-or-later
+ */
+
+#define ETH_TYPE_IPV4 0x0800
+#define ETH_TYPE_IPV6 0x86dd
+
+#define IP_PROTO_TCP 6
+#define IP_PROTO_UDP 17
+
+#define RTE_CALC_SYN 1
+#define RTE_CALC_GTCP 2
+#define RTE_CALC_GUDP 3
+#define RTE_CALC_SMB1 4
+#define RTE_CALC_SMB2 5
+#define RTE_CALC_DCERPC 6
+#define RTE_CALC_DNS 7
+
+#define MAX_SUBPKTS_PER_PACKET 16
+
+/*
+ An RR pair is identified by a Fully Qualified Message ID (RRPD)
+*/
+
+typedef struct _RRPD
+{
+ /*
+ When a c2s is set TRUE it means that the associated packet is going from
+ client-to-service. If this value is false the associated packet is going
+ from service-to-client.
+
+ This value is only valid for RRPDs imbedded in subpacket structures.
+ */
+ gboolean c2s;
+
+ guint8 ip_proto;
+ guint32 stream_no;
+ guint64 session_id;
+ guint64 msg_id;
+
+ /*
+ Some request-response pairs are demarked simple by a change in direction on a
+ TCP or UDP stream from s2c to c2s. This is true for the GTCP and GUDP
+ calculations. Other calculations (such as DCERPC) use application protocol
+ values to detect the start and end of APDUs. In this latter case decode_based
+ is set to true.
+ */
+ gboolean decode_based;
+
+ gboolean is_retrans;
+
+ guint32 req_first_frame;
+ nstime_t req_first_rtime;
+ guint32 req_last_frame;
+ nstime_t req_last_rtime;
+
+ guint32 rsp_first_frame;
+ nstime_t rsp_first_rtime;
+ guint32 rsp_last_frame;
+ nstime_t rsp_last_rtime;
+
+ guint calculation;
+
+ /* The following numbers are for tuning purposes */
+ guint32 req_search_total; /* The total number of steps back through the rrpd_list when matching requests to this entry */
+ guint32 rsp_search_total; /* The total number of steps back through the rrpd_list when matching responses to this entry */
+} RRPD;
+
+typedef struct _PKT_INFO
+{
+ int frame_number;
+ nstime_t relative_time;
+
+ gboolean tcp_retran; /* tcp.analysis.retransmission */
+ gboolean tcp_keep_alive; /* tcp.analysis.keep_alive */
+ gboolean tcp_flags_syn; /* tcp.flags.syn */
+ gboolean tcp_flags_ack; /* tcp.flags.ack */
+ gboolean tcp_flags_reset; /* tcp.flags.reset */
+ guint32 tcp_flags_urg; /* tcp.urgent_pointer */
+ guint32 tcp_seq; /* tcp.seq */
+
+ /* Generic transport values */
+ guint16 srcport; /* tcp.srcport or udp.srcport*/
+ guint16 dstport; /* tcp.dstport or udp.dstport*/
+ guint16 len; /* tcp.len or udp.len */
+
+ guint8 ssl_content_type; /*tls.record.content_type */
+
+ guint8 tds_type; /*tds.type */
+ guint16 tds_length; /* tds.length */
+
+ guint16 smb_mid; /* smb.mid */
+
+ guint64 smb2_sesid; /* smb2.sesid */
+ guint64 smb2_msg_id; /* smb2.msg_id */
+ guint16 smb2_cmd; /* smb2.cmd */
+
+ guint8 dcerpc_ver; /* dcerpc.ver */
+ guint8 dcerpc_pkt_type; /* dcerpc.pkt_type */
+ guint32 dcerpc_cn_call_id; /* dcerpc.cn_call_id */
+ guint16 dcerpc_cn_ctx_id; /* dcerpc.cn_ctx_id */
+
+ guint16 dns_id; /* dns.id */
+
+ /* The following values are calculated */
+ gboolean pkt_of_interest;
+
+ /* RRPD data for this packet */
+ /* Complete this based on the detected protocol */
+ RRPD rrpd;
+
+} PKT_INFO;
+
+typedef enum {
+ HF_INTEREST_IP_PROTO = 0,
+ HF_INTEREST_IPV6_NXT,
+
+ HF_INTEREST_TCP_RETRAN,
+ HF_INTEREST_TCP_KEEP_ALIVE,
+ HF_INTEREST_TCP_FLAGS_SYN,
+ HF_INTEREST_TCP_FLAGS_ACK,
+ HF_INTEREST_TCP_FLAGS_RESET,
+ HF_INTEREST_TCP_FLAGS_URG,
+ HF_INTEREST_TCP_SEQ,
+ HF_INTEREST_TCP_SRCPORT,
+ HF_INTEREST_TCP_DSTPORT,
+ HF_INTEREST_TCP_STREAM,
+ HF_INTEREST_TCP_LEN,
+
+ HF_INTEREST_UDP_SRCPORT,
+ HF_INTEREST_UDP_DSTPORT,
+ HF_INTEREST_UDP_STREAM,
+ HF_INTEREST_UDP_LENGTH,
+
+ HF_INTEREST_SSL_CONTENT_TYPE,
+
+ HF_INTEREST_TDS_TYPE,
+ HF_INTEREST_TDS_LENGTH,
+
+ HF_INTEREST_SMB_MID,
+
+ HF_INTEREST_SMB2_SES_ID,
+ HF_INTEREST_SMB2_MSG_ID,
+ HF_INTEREST_SMB2_CMD,
+
+ HF_INTEREST_DCERPC_VER,
+ HF_INTEREST_DCERPC_PKT_TYPE,
+ HF_INTEREST_DCERPC_CN_CALL_ID,
+ HF_INTEREST_DCERPC_CN_CTX_ID,
+
+ HF_INTEREST_DNS_ID,
+
+ HF_INTEREST_END_OF_LIST
+} ehf_of_interest;
+
+typedef struct _HF_OF_INTEREST_INFO
+{
+ int hf;
+ const char* proto_name;
+
+} HF_OF_INTEREST_INFO;
+
+extern HF_OF_INTEREST_INFO hf_of_interest[HF_INTEREST_END_OF_LIST];
+
+void add_detected_tcp_svc(guint16 port);
+extern gboolean is_dcerpc_context_zero(guint32 pkt_type);
+extern gboolean is_dcerpc_req_pkt_type(guint32 pkt_type);
+
+
+/*
+ * Editor modelines - https://www.wireshark.org/tools/modelines.html
+ *
+ * Local variables:
+ * c-basic-offset: 4
+ * tab-width: 8
+ * indent-tabs-mode: nil
+ * End:
+ *
+ * vi: set shiftwidth=4 tabstop=8 expandtab:
+ * :indentSize=4:tabSize=8:noTabs=true:
+ */
diff --git a/plugins/epan/transum/preferences.h b/plugins/epan/transum/preferences.h
new file mode 100644
index 00000000..96eea06a
--- /dev/null
+++ b/plugins/epan/transum/preferences.h
@@ -0,0 +1,41 @@
+/* preferences.h
+ * Header file for the TRANSUM response time analyzer post-dissector
+ * By Paul Offord <paul.offord@advance7.com>
+ * Copyright 2016 Advance Seven Limited
+ *
+ * Wireshark - Network traffic analyzer
+ * By Gerald Combs <gerald@wireshark.org>
+ * Copyright 1998 Gerald Combs
+ *
+ * SPDX-License-Identifier: GPL-2.0-or-later
+ */
+#include <epan/packet.h>
+#include <epan/prefs.h>
+
+#define RTE_TIME_SEC 1
+#define RTE_TIME_MSEC 1000
+#define RTE_TIME_USEC 1000000
+
+#define TRACE_CAP_CLIENT 1
+#define TRACE_CAP_INTERMEDIATE 2
+#define TRACE_CAP_SERVICE 3
+
+/* Add entries to the service port table for packets to be treated as services
+* This is populated with preferences "service ports" data */
+typedef struct _TSUM_PREFERENCES
+{
+ int capture_position;
+ gboolean reassembly;
+ wmem_map_t *tcp_svc_ports;
+ wmem_map_t *udp_svc_ports;
+ gboolean orphan_ka_discard;
+ int time_multiplier;
+ gboolean rte_on_first_req;
+ gboolean rte_on_last_req;
+ gboolean rte_on_first_rsp;
+ gboolean rte_on_last_rsp;
+ gboolean summarisers_enabled;
+ gboolean summarise_tds;
+ gboolean summarisers_escape_quotes;
+ gboolean debug_enabled;
+} TSUM_PREFERENCES;