diff options
author | Daniel Baumann <daniel.baumann@progress-linux.org> | 2024-04-10 20:34:10 +0000 |
---|---|---|
committer | Daniel Baumann <daniel.baumann@progress-linux.org> | 2024-04-10 20:34:10 +0000 |
commit | e4ba6dbc3f1e76890b22773807ea37fe8fa2b1bc (patch) | |
tree | 68cb5ef9081156392f1dd62a00c6ccc1451b93df /plugins/epan/transum | |
parent | Initial commit. (diff) | |
download | wireshark-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/AUTHORS | 2 | ||||
-rw-r--r-- | plugins/epan/transum/CMakeLists.txt | 72 | ||||
-rw-r--r-- | plugins/epan/transum/README | 6 | ||||
-rw-r--r-- | plugins/epan/transum/decoders.c | 335 | ||||
-rw-r--r-- | plugins/epan/transum/decoders.h | 31 | ||||
-rw-r--r-- | plugins/epan/transum/extractors.c | 165 | ||||
-rw-r--r-- | plugins/epan/transum/extractors.h | 21 | ||||
-rw-r--r-- | plugins/epan/transum/packet-transum.c | 1366 | ||||
-rw-r--r-- | plugins/epan/transum/packet-transum.h | 189 | ||||
-rw-r--r-- | plugins/epan/transum/preferences.h | 41 |
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; |