From 3cdbbcdfb93ecd8df79f3ac76e4b00c0e743cc77 Mon Sep 17 00:00:00 2001 From: Luis Colmenero Date: Wed, 7 Oct 2020 22:30:16 +0200 Subject: [PATCH] RTPS-VT: New dissector to enhance the RTPS protocol Added dissectors for RTPS Virtual Transport and RTPS Processed Protocols RTI Connext DDS can capture RTPS-related traffic by using the Network Capture Utility. The generated .pcap capture files will follow these protocols, establishing a format for how information must be saved, and then parsed. This will improve debuggability by including additional information obtained from within Connext DDS. RTPS-VT parses the information related to the transport. It then, calls the RTPS-PROC dissector, which handles the rest: calling the RTPS dissector when needed, and parsing additional information such as the one related to security. --- epan/dissectors/CMakeLists.txt | 2 + epan/dissectors/packet-rtps-processed.c | 450 ++++++ .../packet-rtps-virtual-transport.c | 1207 +++++++++++++++++ epan/dissectors/packet-rtps.c | 63 +- epan/dissectors/packet-rtps.h | 70 + 5 files changed, 1760 insertions(+), 32 deletions(-) create mode 100644 epan/dissectors/packet-rtps-processed.c create mode 100644 epan/dissectors/packet-rtps-virtual-transport.c create mode 100644 epan/dissectors/packet-rtps.h diff --git a/epan/dissectors/CMakeLists.txt b/epan/dissectors/CMakeLists.txt index a942ea63a1..2726b2bb40 100644 --- a/epan/dissectors/CMakeLists.txt +++ b/epan/dissectors/CMakeLists.txt @@ -1693,6 +1693,8 @@ set(DISSECTOR_SRC ${CMAKE_CURRENT_SOURCE_DIR}/packet-rtp-ed137.c ${CMAKE_CURRENT_SOURCE_DIR}/packet-rtpproxy.c ${CMAKE_CURRENT_SOURCE_DIR}/packet-rtps.c + ${CMAKE_CURRENT_SOURCE_DIR}/packet-rtps-virtual-transport.c + ${CMAKE_CURRENT_SOURCE_DIR}/packet-rtps-processed.c ${CMAKE_CURRENT_SOURCE_DIR}/packet-rtsp.c ${CMAKE_CURRENT_SOURCE_DIR}/packet-rudp.c ${CMAKE_CURRENT_SOURCE_DIR}/packet-rwall.c diff --git a/epan/dissectors/packet-rtps-processed.c b/epan/dissectors/packet-rtps-processed.c new file mode 100644 index 0000000000..1fb6fa25b3 --- /dev/null +++ b/epan/dissectors/packet-rtps-processed.c @@ -0,0 +1,450 @@ +/* packet-rtps-processed.c + * Dissector for the Real-Time Publish-Subscribe (RTPS) Processed Protocol. + * + * (c) 2020 Copyright, Real-Time Innovations, Inc. + * Real-Time Innovations, Inc. + * 232 East Java Drive + * Sunnyvale, CA 94089 + * + * Wireshark - Network traffic analyzer + * By Gerald Combs + * Copyright 1998 Gerald Combs + * + * SPDX-License-Identifier: GPL-2.0-or-later + * + * ----------------------------------------------------------------------------- + * RTI Connext DDS can capture RTPS-related traffic by using the Network Capture + * Utility. The generated .pcap capture files will follow a format that + * defines how information must be saved, and then parsed. + * + * The format is divided into two layers/protocols: virtual transport + * (packet-rtps-virtual-transport.c) and processed (packet-rtps-processed.c). + * This file is about the processed dissector. For a general introduction and + * information about the virtual transport dissector, read the documentation at + * the beginning of packet-rtps-virtual-transport.c. + * + * The processed dissector is called by the transport dissector. It should never + * be called directly by Wireshark without going through the transport + * dissector first. + * + * The advanced information contains one parameter that it is really important + * (and compulsory). This parameter is the "main frame", i.e. the frame that + * would usually be captured over the wire. This frame is encrypted if security + * applies. + * + * Then we have two optional fields: advanced frame0 and frame1. + * - frame0: Contains the RTPS frame with submessage protection (but + * decrypted at the RTPS level). + * - frame1: + * - Inbound traffic: A list of decrypted RTPS submessages (the protected + * ones from frame0). + * - Outbound traffic: The RTPS message before any kind of protection. + * The contents encrypted at RTPS message level can be found in the main frame. + * + * We can see there is a difference between frame1 (the parameter containing the + * decrypted RTPS submessages): inbound traffic has a list of submessages (no + * RTPS header) but outbound traffic has a RTPS message. The reason behind + * this is related to how RTI Connext DDS handles protected inbound traffic. + * + * An alternative would be to build the RTPS message from frame0 and frame1 and + * then pass it to the RTPS dissector. This solution would be cleaner but would + * require to keep a buffer and information between parameters. + * The current solution is kept for the moment. + */ + +#include "config.h" +#include + +#include +#include +#include +#include +#include +#include +#include +#include +#include + +#include + +#define PARAM_ID_ADVANCED_FRAME0 0x000C1 +#define PARAM_ID_ADVANCED_FRAME1 0x000C2 + +void proto_reg_handoff_rtps_processed(void); +void proto_register_rtps_processed(void); +static gint dissect_rtps_processed( + tvbuff_t *tvb, + packet_info *pinfo, + proto_tree *tree, + void *data); +void get_new_colinfo_w_submessages( + wmem_strbuf_t *out, + wmem_strbuf_t *frame, + const gchar *submessages); + +/* Subtree pointers */ +static gint rtpsproc_tree = -1; +static gint rtpsproc_ett = -1; +static gint rtpsproc_ett_security = -1; +static gint rtpsproc_ett_advanced_frame0 = -1; +static gint rtpsproc_ett_advanced_frame1 = -1; + +/* Initialize the protocol and registered fields */ +static header_field_info *rtpsproc_hf = NULL; +static gint rtpsproc_hf_param_id = -1; +static gint rtpsproc_hf_param_length = -1; + +/* Used for caching a handle to the RTPS dissector */ +static dissector_handle_t rtps_handle = NULL; + +/* ========================================================================== */ +/* Dissector */ +/* ========================================================================== */ +/* + * Parameters must be in the right order or dissector will fail. + * This was done instead of looping for all parameters (like in + * packet-rtps-virtual-transport.c) because: + * - The number of parameters is small. + * - This way we can skip creating some headings if they are not needed (by + * using zeros instead). + */ +static gint dissect_rtps_processed( + tvbuff_t *tvb, + packet_info *pinfo, + proto_tree *tree, + void *data) +{ + proto_tree *rtpsproc_tree_general = NULL; + proto_tree *rtpsproc_tree_security = NULL; + proto_item *rtpsproc_ti = NULL; + guint16 param_id; + guint16 param_length; + gint offset = 0; + gint offset_version = 4; /* 'R', 'T', 'P', 'S' */ + tvbuff_t *rtps_payload = NULL; + tvbuff_t *message_payload = NULL; + struct rtpsvt_data *transport_data = (struct rtpsvt_data *) data; + const gchar *title_security = transport_data->direction == 1 + ? "RTPS Security decoding" + : "RTPS Security pre-encoding"; + guint16 rtps_version = 0x0203; + guint16 rtps_vendor_id = 0x0101; + + if (transport_data == NULL) { + /* Reject the packet if no transport information */ + return 0; + } + param_length = transport_data->rtps_length; + + /* ***************************** MAIN ***********************************/ + /* + * The contents passed to the rtpsproc dissector must start with the RTPS + * frame. + */ + rtps_version = tvb_get_guint16( + tvb, + offset + offset_version, + ENC_BIG_ENDIAN); + rtps_vendor_id = tvb_get_guint16( + tvb, + offset + offset_version + 2, + ENC_BIG_ENDIAN); + + rtps_payload = tvb_new_subset_length(tvb, offset, param_length); + if (rtps_handle != NULL) { + call_dissector(rtps_handle, rtps_payload, pinfo, tree); + } + offset += param_length; + + /* *********** Add subtree used for the fields of our rtpsproc_tree *******/ + rtpsproc_ti = proto_tree_add_item( + tree, + rtpsproc_tree, + tvb, + offset, + -1, + ENC_BIG_ENDIAN); + rtpsproc_tree_general = proto_item_add_subtree(rtpsproc_ti, rtpsproc_ett); + + /* *************************** ADVANCED 0 *******************************/ + param_id = tvb_get_guint16(tvb, offset, ENC_BIG_ENDIAN); + if (param_id == PARAM_ID_ADVANCED_FRAME0) { + proto_tree *rtpsproc_tree_frame0 = NULL; + param_length = tvb_get_guint16(tvb, offset + 2, ENC_BIG_ENDIAN); + + rtpsproc_tree_security = proto_tree_add_subtree_format( + rtpsproc_tree_general, + tvb, + offset, + 0, + rtpsproc_ett_security, + NULL, + "%s", + title_security); + + rtpsproc_tree_frame0 = proto_tree_add_subtree_format( + rtpsproc_tree_security, + tvb, + offset, + 0, + rtpsproc_ett_advanced_frame0, + NULL, + "%s", + "RTPS level"); + + proto_tree_add_uint( + rtpsproc_tree_frame0, + rtpsproc_hf_param_id, + tvb, + offset, + 2, /* length */ + param_id); + offset += 2; + + proto_tree_add_uint( + rtpsproc_tree_frame0, + rtpsproc_hf_param_length, + tvb, + offset, + 2, /* length */ + param_length); + offset += 2; + + message_payload = tvb_new_subset_length(tvb, offset, param_length); + if (rtps_handle != NULL) { + call_dissector( + rtps_handle, + message_payload, + pinfo, + rtpsproc_tree_frame0); + } + offset += param_length; + } else { + /* + * If there is no security information, param_id is zeroed. + * In that case the length is also zero, so we move 4 Bytes in total. + */ + offset += 4; + } + + /* *************************** ADVANCED 1 *******************************/ + param_id = tvb_get_guint16(tvb, offset, ENC_BIG_ENDIAN); + if (param_id == PARAM_ID_ADVANCED_FRAME1) { + proto_tree *rtpsproc_tree_frame1 = NULL; + const gchar *title = transport_data->direction + ? "Submessage level" + : "RTPS and Submessage level (no protection)"; + param_length = tvb_get_guint16(tvb, offset + 2, ENC_BIG_ENDIAN); + + if (rtpsproc_tree_security == NULL) { + rtpsproc_tree_security = proto_tree_add_subtree_format( + rtpsproc_tree_general, + tvb, + offset, + 0, + rtpsproc_ett_security, + NULL, + "%s", + title_security); + } + + rtpsproc_tree_frame1 = proto_tree_add_subtree_format( + rtpsproc_tree_security, + tvb, + offset, + 0, + rtpsproc_ett_advanced_frame1, + NULL, + "%s", + title); + + proto_tree_add_uint( + rtpsproc_tree_frame1, + rtpsproc_hf_param_id, + tvb, + offset, + 2, /* length */ + param_id); + offset += 2; + + proto_tree_add_uint( + rtpsproc_tree_frame1, + rtpsproc_hf_param_length, + tvb, + offset, + 2, /* length */ + param_length); + offset += 2; + + /* + * Depending on the direction we have: + * - Inbound: List of decrypted submessages. + * - Outbound: The RTPS message before any kind of protection. + * So, we handle them differently. + */ + if (transport_data->direction) { + tvbuff_t *rtps_submessages = NULL; + wmem_strbuf_t *info_w_encrypted = NULL; /* Current info */ + wmem_strbuf_t *info_w_decrypted = NULL; /* New info */ + /* + * Get the current column info. This has the RTPS frames with the + * encrypted submessages. We are going to update the text so that + * it has the decrypted information, which is more useful to the + * user. + */ + if (pinfo->cinfo) { + const gchar *colinfo = col_get_text(pinfo->cinfo, COL_INFO); + if (colinfo) { + info_w_encrypted = wmem_strbuf_new( + wmem_packet_scope(), + colinfo); + col_clear(pinfo->cinfo, COL_INFO); + } + } + /* Dissect the submessages using the RTPS dissector */ + rtps_submessages = tvb_new_subset_length(tvb, offset, param_length); + dissect_rtps_submessages( + rtps_submessages, + 0, /* offset */ + pinfo, + rtpsproc_tree_frame1, + rtps_version, + rtps_vendor_id); + offset += param_length; + /* + * Get the decrypted submessages and update the column information. + */ + if (pinfo->cinfo) { + const gchar *colinfo = col_get_text(pinfo->cinfo, COL_INFO); + info_w_decrypted = wmem_strbuf_new(wmem_packet_scope(), ""); + if (colinfo) { + get_new_colinfo_w_submessages( + info_w_decrypted, /* out */ + info_w_encrypted, /* in */ + colinfo); /* in */ + col_clear(pinfo->cinfo, COL_INFO); + col_set_str( + pinfo->cinfo, + COL_INFO, + wmem_strbuf_get_str(info_w_decrypted)); + } + } + } else { + message_payload = tvb_new_subset_length(tvb, offset, param_length); + if (rtps_handle != NULL) { + call_dissector( + rtps_handle, + message_payload, + pinfo, + rtpsproc_tree_frame1); + } + offset += param_length; + } + } else { + /* + * If there is no security information, param_id is zeroed. + * In that case the length is also zero, so we move 4 Bytes in total. + */ + offset += 4; + } + return tvb_captured_length(tvb); +} + +/* ========================================================================== */ +/* Other */ +/* ========================================================================== */ + +/* + * This function is called at startup and caches the handle for the register. + * That way we don't have to find the dissector for each packet. + */ +void proto_reg_handoff_rtps_processed(void) +{ + rtps_handle = find_dissector("rtps"); +} + +void get_new_colinfo_w_submessages( + wmem_strbuf_t *out, + wmem_strbuf_t *frame, + const gchar *submessages) +{ + const gchar *pattern = "SEC_PREFIX, SEC_BODY, SEC_POSTFIX"; + const gchar *frame_str = wmem_strbuf_get_str(frame); + gsize idx = 0; /* index for iterating frame_str */ + gchar *submessages_dup = g_strdup(submessages); + /* First decrypted submessage in submessages list */ + gchar *submessage_current = strtok(submessages_dup, ", "); + /* First encrypted submessage. Found by searching the RTPS colinfo */ + gchar *encrypted_current = strstr(&frame_str[idx], pattern); + + while (encrypted_current != NULL) { + /* Copy the RTPS frame up to the newly found encrypted submessage */ + gsize length_to_copy = encrypted_current - &frame_str[idx]; + wmem_strbuf_append_len(out, &frame_str[idx], length_to_copy); + + /* Copy the decrypted contents that replace the encrypted submessage */ + wmem_strbuf_append(out, submessage_current); + + /* Advance the index and continue searching */ + idx += length_to_copy + strlen(pattern); + encrypted_current = strstr(&frame_str[idx], pattern); + } + /* Copy the remaining from the RTPS frame */ + wmem_strbuf_append(out, &frame_str[idx]); +} + +/* ========================================================================== */ +/* Protocol egistration */ +/* ========================================================================== */ +void +proto_register_rtps_processed(void) +{ + static hf_register_info hf[] = { + { + &rtpsproc_hf_param_id, + { + "Parameter Identifier", "rtpsproc.param.id", + FT_UINT16, BASE_DEC, NULL, 0, 0, HFILL + }, + }, + { + &rtpsproc_hf_param_length, + { + "Parameter Length", "rtpsproc.param.length", + FT_UINT16, BASE_DEC, NULL, 0, 0, HFILL + } + }, + }; + static gint *ett[] = { + &rtpsproc_ett, + &rtpsproc_ett_security, + &rtpsproc_ett_advanced_frame0, + &rtpsproc_ett_advanced_frame1 + }; + + /* Register the protocol name and description */ + rtpsproc_tree = proto_register_protocol( + "Real-Time Publish-Subscribe Wire Protocol (processed)", + "RTPS-PROC", + "rtpsproc"); + + /* Required function calls to register the header fields and subtrees */ + rtpsproc_hf = proto_registrar_get_nth(rtpsproc_tree); + proto_register_field_array(rtpsproc_tree, hf, array_length(hf)); + proto_register_subtree_array(ett, array_length(ett)); + + register_dissector("rtpsproc", dissect_rtps_processed, rtpsproc_tree); +} + +// /* +// * 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/epan/dissectors/packet-rtps-virtual-transport.c b/epan/dissectors/packet-rtps-virtual-transport.c new file mode 100644 index 0000000000..e4785fb473 --- /dev/null +++ b/epan/dissectors/packet-rtps-virtual-transport.c @@ -0,0 +1,1207 @@ +/* packet-rtps-virtual-transport.c + * Dissector for the Real-Time Publish-Subscribe (RTPS) Virtual Transport + * Protocol. + * + * (c) 2020 Copyright, Real-Time Innovations, Inc. + * Real-Time Innovations, Inc. + * 232 East Java Drive + * Sunnyvale, CA 94089 + * + * Wireshark - Network traffic analyzer + * By Gerald Combs + * Copyright 1998 Gerald Combs + * + * SPDX-License-Identifier: GPL-2.0-or-later + * + * ----------------------------------------------------------------------------- + * RTI Connext DDS can capture RTPS-related traffic by using the Network Capture + * Utility. The generated .pcap capture files will follow the RTPS-VT protocol, + * which establishes a format for how information must be saved, and then + * parsed. + * + * The protocol is divided into two layers: transport + * (packet-rtps-virtual-transport.c) and advanced (packet-rtps-processed.c). + * This file is about the transport dissector. For more information about the + * advanced dissector, read the documentation at the beginning of + * packet-rtps-processed.c. + * + * Every packet saved in the capture file follows the PCAP file format. + * As a consequence, there are two headers: a global one (unique per file) and + * a per-packet header. These headers have the typical content described in the + * PCAP format: a magic number, version number, some timestamps, information + * describing the length of the packet and the data link layer (0x000000fc, i.e. + * custom protocol), etc. Then, we have a header that indicates Wireshark the + * name of the protocol: "rtpsvt". The transport dissector is called when + * Wireshark finds "rtpsvt" as the protocol name. + * + * After the RTPS-VT header, we have the frame type. The frame type determines + * what kind of information has the dumped packet. RTPS-VT data comes as a + * series of [parameter identifier, content length, content]. Depending on the + * type of frame (RTPS or lossInfo), the dissector will expect some parameters + * or others. + * + * If the frame type is RTPS, we will continue parsing transport-layer data. + * The transport layer contains all information about the source and destination + * of a packet. This corresponds to data typically found on Network or Transport + * protocols. However, because RTI Connext DDS generates the capture file + * directly at application-level, this information is added at the moment of + * writing the capture file. + * After the transport-layer information, we will call the advanced dissector. + * + * If the frame type is lossInfo, the dissector will generate a packet + * indicating that there were missing frames (and the range of sequence + * numbers). + */ +#include "config.h" +#include + +#include +#include +#include +#include +#include +#include +#include +#include +#include + +#include + +#define CONTENT_KIND_RTPS 0x01 +#define CONTENT_KIND_LOSS_INFO 0x02 + +#define PARAM_ID_TRANSPORT_CLASS 0x0001 +#define PARAM_ID_MONITORING_GUID 0x0002 +#define PARAM_ID_MONITORING_SN 0x0003 +#define PARAM_ID_SOURCE_IP_ADDRESS 0x0004 +#define PARAM_ID_SOURCE_PORT 0x0005 +#define PARAM_ID_DESTINATION_IP_ADDRESS 0x0006 +#define PARAM_ID_DESTINATION_RTPS_PORT 0x0007 +#define PARAM_ID_DESTINATION_PORT 0x0008 +#define PARAM_ID_DIRECTION 0x0009 +#define FIRST_PARAM_ID_RTPS PARAM_ID_TRANSPORT_CLASS +#define LAST_PARAM_ID_RTPS PARAM_ID_DIRECTION + +/* First parameter Identifier that the "rtpsproc" protocol accepts */ +#define PARAM_ID_MAIN_FRAME 0x00C0 + +#define PARAM_ID_LOST_MESSAGES 0x0001 + +void proto_register_rtps_virtual_transport(void); +static gint dissect_rtps_virtual_transport( + tvbuff_t *tvb, + packet_info *pinfo, + proto_tree *tree, + void *data _U_); +static gint dissect_rtps_virtual_transport_rtps_type( + tvbuff_t *tvb, + packet_info *pinfo, + proto_tree *tree, + proto_tree *tree_transport, + gint offset, + struct rtpsvt_data *transport_data); +static gint dissect_parameter_transport_rtps_type( + tvbuff_t *tvb, + proto_tree *rtpsvt_tree_general, + proto_tree *rtpsvt_tree_identifier, + proto_tree *rtpsvt_tree_information, + gint offset, + packet_info *pinfo, + struct rtpsvt_data *transport_data); +static gint dissect_rtps_virtual_transport_loss_info_type( + tvbuff_t *tvb, + packet_info *pinfo, + proto_tree *tree_transport, + gint offset); + +/* Subtree pointers */ +static gint proto_rtpsvt = -1; +static gint rtpsvt_ett = -1; +static gint rtpsvt_ett_version = -1; +static gint rtpsvt_ett_identifier = -1; +static gint rtpsvt_ett_information = -1; +static gint rtpsvt_ett_information_class = -1; +static gint rtpsvt_ett_information_src_port = -1; +static gint rtpsvt_ett_information_dst_port = -1; +static gint rtpsvt_ett_information_src_addr = -1; +static gint rtpsvt_ett_information_dst_addr = -1; +static gint rtpsvt_ett_information_direction = -1; +static gint rtpsvt_ett_monitoring_sn = -1; +static gint rtpsvt_ett_frame = -1; + +/* Initialize the protocol and registered fields */ +static header_field_info *rtpsvt_hf = NULL; +static gint rtpsvt_hf_version = -1; +static gint rtpsvt_hf_version_major = -1; +static gint rtpsvt_hf_version_minor = -1; +static gint rtpsvt_hf_content_kind = -1; +static gint rtpsvt_hf_param_id = -1; +static gint rtpsvt_hf_param_length = -1; +static gint rtpsvt_hf_packet_identifier = -1; +static gint rtpsvt_hf_monitoring_guid = -1; +static gint rtpsvt_hf_monitoring_seqNr = -1; +static gint rtpsvt_hf_information = -1; +static gint rtpsvt_hf_class = -1; +static gint rtpsvt_hf_source_port = -1; +static gint rtpsvt_hf_source_address = -1; +static gint rtpsvt_hf_source_pid = -1; +static gint rtpsvt_hf_destination_port = -1; +static gint rtpsvt_hf_destination_rtps_port = -1; +static gint rtpsvt_hf_destination_address = -1; +static gint rtpsvt_hf_direction = -1; +static gint rtpsvt_hf_destination_pid = -1; +static gint rtpsvt_hf_missing_messages = -1; + +/* expert info fields */ +static expert_field ei_missing_msg = EI_INIT; + +/* Vendor specific: RTI */ +static const value_string ndds_transport_class_id_vals[] = { + { NDDS_TRANSPORT_CLASSID_ANY, "ANY" }, + { NDDS_TRANSPORT_CLASSID_UDPv4, "UDPv4" }, + { NDDS_TRANSPORT_CLASSID_UDPv4_WAN, "UDPv4_WAN"}, + { NDDS_TRANSPORT_CLASSID_SHMEM, "SHMEM" }, + { NDDS_TRANSPORT_CLASSID_INTRA, "INTRA" }, + { NDDS_TRANSPORT_CLASSID_UDPv6, "UDPv6" }, + { NDDS_TRANSPORT_CLASSID_DTLS, "DTLS" }, + { NDDS_TRANSPORT_CLASSID_WAN, "WAN" }, + { NDDS_TRANSPORT_CLASSID_TCPV4_LAN, "TCPv4_LAN" }, + { NDDS_TRANSPORT_CLASSID_TCPV4_WAN, "TCPv4_WAN" }, + { NDDS_TRANSPORT_CLASSID_TLSV4_LAN, "TLSv4_LAN" }, + { NDDS_TRANSPORT_CLASSID_TLSV4_WAN, "TLSv4_WAN" }, + { NDDS_TRANSPORT_CLASSID_PCIE, "PCIE" }, + { NDDS_TRANSPORT_CLASSID_ITP, "ITP" }, + { 0, NULL } +}; + +static gint dissect_rtps_virtual_transport( + tvbuff_t *tvb, + packet_info *pinfo, + proto_tree *tree, + void *data _U_) +{ + proto_tree *rtpsvt_tree_transport; + proto_item *rtpsvt_ti_transport; + proto_item *rtpsvt_ti_version; + proto_tree *rtpsvt_tree_version; + proto_item *rtpsvt_ti_content_kind; + struct rtpsvt_data transport_data; + guint16 version; + guint8 content_type; + const gchar *content_type_label; + gint offset = 0; + gint output = 0; + + /* Add transport tree, used for the fields of our proto_rtpsvt */ + rtpsvt_ti_transport = proto_tree_add_item( + tree, + proto_rtpsvt, + tvb, + offset, + -1, + ENC_BIG_ENDIAN); + rtpsvt_tree_transport = proto_item_add_subtree(rtpsvt_ti_transport, rtpsvt_ett); + + /* Add the version to the transport protocol */ + version = tvb_get_ntohs(tvb, offset); + transport_data.version_major = version >> 8; + transport_data.version_minor = version & 0xff; + rtpsvt_ti_version = proto_tree_add_uint_format( + rtpsvt_tree_transport, + rtpsvt_hf_version, + tvb, + offset, + sizeof(guint16), + version, + "Version: %d.%d", + transport_data.version_major, + transport_data.version_minor); + rtpsvt_tree_version = proto_item_add_subtree( + rtpsvt_ti_version, + rtpsvt_ett_version); + + proto_tree_add_item( + rtpsvt_tree_version, + rtpsvt_hf_version_major, + tvb, + offset, + sizeof(guint8), + ENC_NA); + proto_tree_add_item( + rtpsvt_tree_version, + rtpsvt_hf_version_minor, + tvb, + offset + 1, + sizeof(guint8), + ENC_NA); + offset += 2; + + /* Add the content kind. */ + content_type = tvb_get_guint8(tvb, offset); + rtpsvt_ti_content_kind = proto_tree_add_item( + rtpsvt_ti_transport, + rtpsvt_hf_content_kind, + tvb, + offset, + sizeof(guint8), + ENC_NA); + if (content_type == CONTENT_KIND_RTPS) { + content_type_label = "RTPS"; + } else { + content_type_label = "LOST_INFO"; + } + proto_item_append_text(rtpsvt_ti_content_kind, " (%s)", content_type_label); + offset += 1; + + switch(content_type) { + case CONTENT_KIND_RTPS: + output = dissect_rtps_virtual_transport_rtps_type( + tvb, + pinfo, + tree, + rtpsvt_tree_transport, + offset, + &transport_data); + break; + + case CONTENT_KIND_LOSS_INFO: + output = dissect_rtps_virtual_transport_loss_info_type( + tvb, + pinfo, + rtpsvt_tree_transport, + offset); + break; + } + return output; +} + +static gint dissect_rtps_virtual_transport_rtps_type( + tvbuff_t *tvb, + packet_info *pinfo, + proto_tree *tree, + proto_tree *tree_transport, + gint offset, + struct rtpsvt_data *transport_data) +{ + proto_item *rtpsvt_ti_identifier; + proto_tree *rtpsvt_tree_identifier; + proto_item *rtpsvt_ti_information; + proto_tree *rtpsvt_tree_information; + tvbuff_t *advanced_payload; + static dissector_handle_t advanced_handle = NULL; + unsigned int idx = FIRST_PARAM_ID_RTPS; + guint16 param_id; + guint16 param_length; + + /* + * Add the tree for the packet identifier, which will be populated in + * dissect_parameter_transport_rtps_type. + */ + rtpsvt_ti_identifier = proto_tree_add_item( + tree_transport, + rtpsvt_hf_packet_identifier, + tvb, + offset, + -1, + ENC_NA); + rtpsvt_tree_identifier = proto_item_add_subtree( + rtpsvt_ti_identifier, + rtpsvt_ett_identifier); + + /* + * Add the tree for the transport information, which will be populated in + * dissect_parameter_transport_rtps_type. + */ + rtpsvt_ti_information = proto_tree_add_item( + tree_transport, + rtpsvt_hf_information, + tvb, + offset, + -1, + ENC_NA); + rtpsvt_tree_information = proto_item_add_subtree( + rtpsvt_ti_information, + rtpsvt_ett_information); + + /* + * Each parameter has an id, a length and a value. + */ + for (idx = FIRST_PARAM_ID_RTPS; idx <= LAST_PARAM_ID_RTPS; idx++) { + offset = dissect_parameter_transport_rtps_type( + tvb, + tree_transport, + rtpsvt_tree_identifier, + rtpsvt_tree_information, + offset, + pinfo, + transport_data); + } + + /* + * In the future we may have more transport parameters. + * These parameters will have an identifier less than PARAM_ID_MAIN_FRAME + * (which is parsed by the rtpsproc dissector). + * If we open a "future" capture file with this dissector, we will skip all + * of those parameters and parse only the ones we know about. + */ + do { + param_id = tvb_get_guint16(tvb, offset, ENC_BIG_ENDIAN); + offset += sizeof(guint16); + param_length = tvb_get_guint16(tvb, offset, ENC_BIG_ENDIAN); + offset += sizeof(guint16); + if (param_id == PARAM_ID_MAIN_FRAME) { + proto_tree *rtpsvt_tree_frame; + transport_data->rtps_length = param_length; + rtpsvt_tree_frame = proto_tree_add_subtree_format( + tree_transport, + tvb, + offset, + 0, + rtpsvt_ett_frame, + NULL, + "Real-Time Publish-Subscribe Wire Protocol (content)"); + + proto_tree_add_uint( + rtpsvt_tree_frame, + rtpsvt_hf_param_id, + tvb, + offset, + sizeof(guint16), + param_id); + proto_tree_add_uint( + rtpsvt_tree_frame, + rtpsvt_hf_param_length, + tvb, + offset + sizeof(guint16), + sizeof(guint16), + param_length); + break; + } + offset += param_length; + } while (tvb_reported_length_remaining(tvb, offset) > 0); + + if (param_id != PARAM_ID_MAIN_FRAME || param_length <= 0) { + /* + * Reject the packet if we don't have an RTPS frame. + * The rtpsproc dissector assumes that the contents start with the + * RTPS frame (parameter value; the length is obtained from + * transport_data). + */ + return 0; + } + + advanced_payload = tvb_new_subset_length(tvb, offset, -1); + advanced_handle = find_dissector("rtpsproc"); + call_dissector_with_data( + advanced_handle, + advanced_payload, + pinfo, + tree, + (void *) transport_data); + + return tvb_captured_length(tvb); +} + +static gint dissect_parameter_transport_rtps_type( + tvbuff_t *tvb, + proto_tree *rtpsvt_tree_general, + proto_tree *rtpsvt_tree_identifier, + proto_tree *rtpsvt_tree_information, + gint offset, + packet_info *pinfo, + struct rtpsvt_data *transport_data) +{ + /* + * We will add the parameter id and length later, as part of a subtree + * dependent of the parameter. + * That is why value of the parameter is now at offset + 4 + * (i.e. offset + sizeof(param_id) + sizeof(param_length)) + */ + guint16 param_id = tvb_get_guint16(tvb, offset, ENC_BIG_ENDIAN); + guint16 param_length = tvb_get_guint16(tvb, offset + 2, ENC_BIG_ENDIAN); + const gint OFFSET_TO_VAL = offset + 2 * sizeof(guint16); + if (param_length <=0) { + /* Length not valid: skip parameter (id + length) */ + return OFFSET_TO_VAL; + } + + switch(param_id) { + case PARAM_ID_TRANSPORT_CLASS: + { + proto_tree *rtpsvt_tree_information_class; + gint32 classId = tvb_get_gint32(tvb, OFFSET_TO_VAL, ENC_BIG_ENDIAN); + const gchar *className = val_to_str( + classId, + ndds_transport_class_id_vals, + "%d"); + + rtpsvt_tree_information_class = proto_tree_add_subtree_format( + rtpsvt_tree_information, + tvb, + offset, + 0, + rtpsvt_ett_information_class, + NULL, + "Class: %s", + className); + + /* Add parameter identifier and length */ + proto_tree_add_uint( + rtpsvt_tree_information_class, + rtpsvt_hf_param_id, + tvb, + offset, + sizeof(guint16), /* length: 2B */ + param_id); + offset += sizeof(guint16); + proto_tree_add_uint( + rtpsvt_tree_information_class, + rtpsvt_hf_param_length, + tvb, + offset, + sizeof(guint16), /* length: 2B */ + param_length); + offset += sizeof(guint16); + + /* + * Add transport class as item to the tree. + * This is useful to apply as column or filter. + */ + proto_tree_add_string( + rtpsvt_tree_information_class, + rtpsvt_hf_class, + tvb, + offset, + param_length, + className); + offset += param_length; + + /* Add summary to protocol header */ + proto_item_append_text(rtpsvt_tree_general, ", %s", className); + + /* Add summary to the transport information header */ + proto_item_append_text( + rtpsvt_tree_information, + ", %s", + className); + } + break; + + case PARAM_ID_MONITORING_GUID: + { + proto_tree *rtpsvt_tree_monitoring_guid; + const guint8 *guid_bytes = tvb_get_ptr( + tvb, + OFFSET_TO_VAL, + param_length); + const gchar *guid_string = bytestring_to_str( + wmem_packet_scope(), + guid_bytes, + MIN(param_length, 12), + 0); + + rtpsvt_tree_monitoring_guid = proto_tree_add_subtree_format( + rtpsvt_tree_identifier, + tvb, + offset, + 0, + rtpsvt_ett_information_src_addr, + NULL, + "Monitoring GUID Prefix: %s", + guid_string); + + /* Add parameter identifier and length */ + proto_tree_add_uint( + rtpsvt_tree_monitoring_guid, + rtpsvt_hf_param_id, + tvb, + offset, + sizeof(guint16), + param_id); + offset += sizeof(guint16); + proto_tree_add_uint( + rtpsvt_tree_monitoring_guid, + rtpsvt_hf_param_length, + tvb, + offset, + sizeof(guint16), + param_length); + offset += sizeof(guint16); + + proto_tree_add_item( + rtpsvt_tree_monitoring_guid, + rtpsvt_hf_monitoring_guid, + tvb, + offset, + param_length, + ENC_NA); + offset += param_length; + + /* Add summary to packet identifier header */ + proto_item_append_text( + rtpsvt_tree_identifier, + ", GUID: %s", + guid_string); + } + break; + case PARAM_ID_MONITORING_SN: + { + proto_tree *rtpsvt_tree_seqNr; + guint64 seqNr = tvb_get_guint64(tvb, OFFSET_TO_VAL, ENC_BIG_ENDIAN); + + rtpsvt_tree_seqNr = proto_tree_add_subtree_format( + rtpsvt_tree_identifier, + tvb, + offset, + 0, + rtpsvt_ett_monitoring_sn, + NULL, + "Monitoring Sequence Number: %lu", + seqNr); + + /* Add parameter identifier and length */ + proto_tree_add_uint( + rtpsvt_tree_seqNr, + rtpsvt_hf_param_id, + tvb, + offset, + sizeof(guint16), + param_id); + offset += sizeof(guint16); + proto_tree_add_uint( + rtpsvt_tree_seqNr, + rtpsvt_hf_param_length, + tvb, + offset, + sizeof(guint16), + param_length); + offset += sizeof(guint16); + + proto_tree_add_uint64( + rtpsvt_tree_seqNr, + rtpsvt_hf_monitoring_seqNr, + tvb, + offset, + param_length, + seqNr); + offset += param_length; + + /* Add summary to packet identifier header */ + proto_item_append_text( + rtpsvt_tree_identifier, + ", SeqNum: %lu", + seqNr); + } + break; + case PARAM_ID_SOURCE_IP_ADDRESS: + { + proto_tree *rtpsvt_tree_information_address; + gint temporary_hf = rtpsvt_hf_source_address; + const gchar *prefix = "shmem_prefix"; + const gchar *title_tree = "Source address"; + gchar addr[COL_MAX_LEN]; + ws_in6_addr addr_raw; + const guint8 bytes_zeroed[12] = {0}; + tvb_get_ipv6(tvb, OFFSET_TO_VAL, &addr_raw); + + /* shared memory pid or address? */ + if (memcmp(&addr_raw.bytes, prefix, strlen(prefix)) == 0) { + temporary_hf = rtpsvt_hf_source_pid; + title_tree = "Source process ID"; + guint32 pid = tvb_get_guint32( + tvb, + OFFSET_TO_VAL + (gint) (strlen(prefix)), + ENC_BIG_ENDIAN); + g_snprintf(addr, sizeof(addr), "%u", pid); + } else if (memcmp( + &addr_raw.bytes, + bytes_zeroed, + sizeof(bytes_zeroed)) == 0){ + g_snprintf( + addr, + sizeof(addr), + "%s", + tvb_ip_to_str(tvb, OFFSET_TO_VAL + sizeof(bytes_zeroed))); + } else { + g_snprintf( + addr, + sizeof(addr), + "%s", + tvb_ip6_to_str(tvb, OFFSET_TO_VAL)); + } + + /* Add source to destination column field */ + if (pinfo->cinfo) { + col_append_str(pinfo->cinfo, COL_DEF_SRC, addr); + } + + rtpsvt_tree_information_address = proto_tree_add_subtree_format( + rtpsvt_tree_information, + tvb, + offset, + 0, + rtpsvt_ett_information_src_addr, + NULL, + "%s: %s", + title_tree, + addr); + + /* Add parameter identifier and length */ + proto_tree_add_uint( + rtpsvt_tree_information_address, + rtpsvt_hf_param_id, + tvb, + offset, + sizeof(guint16), + param_id); + offset += sizeof(guint16); + proto_tree_add_uint( + rtpsvt_tree_information_address, + rtpsvt_hf_param_length, + tvb, + offset, + sizeof(guint16), + param_length); + offset += sizeof(guint16); + + /* Add source to the transport information tree */ + proto_tree_add_string( + rtpsvt_tree_information_address, + temporary_hf, + tvb, + offset, + param_length, + addr); + offset += param_length; + + /* Add summary to protocol header */ + proto_item_append_text(rtpsvt_tree_general, ", Src: (%s", addr); + + /* Add summary to transport information header */ + proto_item_append_text( + rtpsvt_tree_information, + ", Src: (%s", + addr); + } + break; + case PARAM_ID_SOURCE_PORT: + { + proto_tree *rtpsvt_tree_information_port; + guint32 port = tvb_get_guint32( + tvb, + OFFSET_TO_VAL, + ENC_BIG_ENDIAN); + + rtpsvt_tree_information_port = proto_tree_add_subtree_format( + rtpsvt_tree_information, + tvb, + offset, + 0, + rtpsvt_ett_information_src_port, + NULL, + "Source port: %d", + port); + + /* Add parameter identifier and length */ + proto_tree_add_uint( + rtpsvt_tree_information_port, + rtpsvt_hf_param_id, + tvb, + offset, + sizeof(guint16), + param_id); + offset += sizeof(guint16); + proto_tree_add_uint( + rtpsvt_tree_information_port, + rtpsvt_hf_param_length, + tvb, + offset, + sizeof(guint16), + param_length); + offset += sizeof(guint16); + + proto_tree_add_uint( + rtpsvt_tree_information_port, + rtpsvt_hf_source_port, + tvb, + offset, + param_length, + port); + offset += param_length; + + /* Add summary to protocol header */ + proto_item_append_text(rtpsvt_tree_general, ":%d)", port); + + /* Add summary to transport information header */ + proto_item_append_text( + rtpsvt_tree_information, + ":%d)", + port); + + /* + * Add the source port to pinfo. + * This is used by the RTPS dissector to get the domainId and + * participantIdx information displayed in discovery packets. + */ + pinfo->srcport = port; + } + break; + case PARAM_ID_DESTINATION_IP_ADDRESS: + { + proto_tree *rtpsvt_tree_information_address; + gint temporary_hf= rtpsvt_hf_destination_address; + const gchar *prefix = "shmem_prefix"; + const gchar *title_tree = "Destination address"; + gchar addr[COL_MAX_LEN]; + ws_in6_addr addr_raw; + const guint8 bytes_zeroed[12] = {0}; + tvb_get_ipv6(tvb, OFFSET_TO_VAL, &addr_raw); + + /* shared memory pid or address? */ + if (memcmp(&addr_raw.bytes, prefix, strlen(prefix)) == 0) { + temporary_hf = rtpsvt_hf_destination_pid; + title_tree = "Destination process ID"; + guint32 pid = tvb_get_guint32( + tvb, + OFFSET_TO_VAL + (gint) (strlen(prefix)), + ENC_BIG_ENDIAN); + g_snprintf(addr, sizeof(addr), "%u", pid); + } else if (memcmp( + &addr_raw.bytes, + bytes_zeroed, + sizeof(bytes_zeroed)) == 0){ + g_snprintf( + addr, + sizeof(addr), + "%s", + tvb_ip_to_str(tvb, OFFSET_TO_VAL + sizeof(bytes_zeroed))); + } else { + g_snprintf( + addr, + sizeof(addr), + "%s", + tvb_ip6_to_str(tvb, OFFSET_TO_VAL)); + } + + /* Add address to destination column field */ + if (pinfo->cinfo) { + col_append_str(pinfo->cinfo, COL_DEF_DST, addr); + } + + rtpsvt_tree_information_address = proto_tree_add_subtree_format( + rtpsvt_tree_information, + tvb, + offset, + 0, + rtpsvt_ett_information_dst_addr, + NULL, + "%s: %s", + title_tree, + addr); + + /* Add parameter identifier and length */ + proto_tree_add_uint( + rtpsvt_tree_information_address, + rtpsvt_hf_param_id, + tvb, + offset, + sizeof(guint16), + param_id); + offset += sizeof(guint16); + proto_tree_add_uint( + rtpsvt_tree_information_address, + rtpsvt_hf_param_length, + tvb, + offset, + sizeof(guint16), + param_length); + offset += sizeof(guint16); + + /* Add destination to the transport information tree */ + proto_tree_add_string( + rtpsvt_tree_information_address, + temporary_hf, + tvb, + offset, + param_length, + addr); + offset += param_length; + + /* Add summary to protocol header */ + proto_item_append_text(rtpsvt_tree_general, ", Dst: (%s", addr); + + /* Add summary to transport information header */ + proto_item_append_text( + rtpsvt_tree_information, + ", Dst: (%s", + addr); + } + break; + case PARAM_ID_DESTINATION_RTPS_PORT: + { + guint32 port = tvb_get_guint32(tvb, OFFSET_TO_VAL, ENC_BIG_ENDIAN); + + proto_tree_add_uint( + rtpsvt_tree_information, + rtpsvt_hf_destination_rtps_port, + tvb, + OFFSET_TO_VAL, + param_length, + port); + + offset = OFFSET_TO_VAL + param_length; + } + break; + case PARAM_ID_DESTINATION_PORT: + { + proto_tree *rtpsvt_tree_information_port; + guint32 port = tvb_get_guint32(tvb, OFFSET_TO_VAL, ENC_BIG_ENDIAN); + + rtpsvt_tree_information_port = proto_tree_add_subtree_format( + rtpsvt_tree_information, + tvb, + offset, + 0, + rtpsvt_ett_information_dst_port, + NULL, + "Destination port: %d", + port); + + /* Add parameter identifier and length */ + proto_tree_add_uint( + rtpsvt_tree_information_port, + rtpsvt_hf_param_id, + tvb, + offset, + sizeof(guint16), + param_id); + offset += sizeof(guint16); + proto_tree_add_uint( + rtpsvt_tree_information_port, + rtpsvt_hf_param_length, + tvb, + offset, + sizeof(guint16), + param_length); + offset += sizeof(guint16); + + proto_tree_add_uint( + rtpsvt_tree_information_port, + rtpsvt_hf_destination_port, + tvb, + offset, + param_length, + port); + offset += param_length; + + /* Add summary to protocol header */ + proto_item_append_text(rtpsvt_tree_general, ":%d)", port); + + /* Add summary to transport information header */ + proto_item_append_text( + rtpsvt_tree_information, + ":%d)", + port); + + /* + * Add the destination port to pinfo. + * This is used by the RTPS dissector to get the domainId and + * participantIdx information displayed in discovery packets. + */ + pinfo->destport = port; + } + break; + case PARAM_ID_DIRECTION: + { + proto_tree *rtpsvt_tree_direction; + guint8 value = tvb_get_guint8(tvb, OFFSET_TO_VAL); + const gchar *direction = value ? "INBOUND" : "OUTBOUND"; + + rtpsvt_tree_direction = proto_tree_add_subtree_format( + rtpsvt_tree_general, + tvb, + offset, + 0, + rtpsvt_ett_information_src_addr, + NULL, + "Traffic Direction: %s", + direction); + + /* Add parameter identifier and length */ + proto_tree_add_uint( + rtpsvt_tree_direction, + rtpsvt_hf_param_id, + tvb, + offset, + sizeof(guint16), + param_id); + offset += sizeof(guint16); + proto_tree_add_uint( + rtpsvt_tree_direction, + rtpsvt_hf_param_length, + tvb, + offset, + sizeof(guint16), + param_length); + offset += sizeof(guint16); + + proto_tree_add_string( + rtpsvt_tree_direction, + rtpsvt_hf_direction, + tvb, + OFFSET_TO_VAL, + param_length, + direction); + offset = OFFSET_TO_VAL + param_length; + + /* Save transport direction for the RTPS-PROC protocol */ + transport_data->direction = value; + } + break; + } + return offset; +} + +static gint dissect_rtps_virtual_transport_loss_info_type( + tvbuff_t *tvb, + packet_info *pinfo, + proto_tree *tree_transport, + gint offset) +{ + + guint16 param_id; + guint16 param_length; + + param_id = tvb_get_guint16(tvb, offset, ENC_BIG_ENDIAN); + offset += sizeof(guint16); + param_length = tvb_get_guint16(tvb, offset, ENC_BIG_ENDIAN); + offset += sizeof(guint16); + if (param_id == PARAM_ID_LOST_MESSAGES) { + guint64 first_lost = tvb_get_guint64(tvb, offset, ENC_BIG_ENDIAN); + guint64 last_lost = tvb_get_guint64(tvb, offset+8, ENC_BIG_ENDIAN); + + if (pinfo->cinfo) { + char info[COL_MAX_INFO_LEN] = {'\0'}; + g_snprintf( + info, + sizeof(info), + "Missing RTPS messages [%ld-%ld]", + first_lost, + last_lost); + col_append_str(pinfo->cinfo, COL_INFO, info); + } + expert_add_info(NULL, tree_transport, &ei_missing_msg); + } + offset += param_length; + + return tvb_captured_length(tvb); +} + +/* Register the protocol with Wireshark */ +void +proto_register_rtps_virtual_transport(void) +{ + expert_module_t* expert_info; + + static hf_register_info hf[] = { + { + &rtpsvt_hf_version, + { + "Version", "rtpsvt.version", + FT_UINT16, BASE_HEX, NULL, 0, 0, HFILL + } + }, + { + &rtpsvt_hf_version_major, + { + "Major", "rtpsvt.version.major", + FT_INT8, BASE_DEC, NULL, 0, 0, HFILL + } + }, + { + &rtpsvt_hf_version_minor, + { + "Minor", "rtpsvt.version.minor", + FT_INT8, BASE_DEC, NULL, 0, 0, HFILL + } + }, + { + &rtpsvt_hf_content_kind, + { + "Content kind", "rtpsvt.content.kind", + FT_INT8, BASE_DEC, NULL, 0, 0, HFILL + } + }, + { + &rtpsvt_hf_param_id, + { + "Parameter Identifier", "rtpsvt.param.id", + FT_UINT16, BASE_DEC, NULL, 0, 0, HFILL + }, + }, + { + &rtpsvt_hf_param_length, + { + "Parameter Length", "rtpsvt.param.length", + FT_UINT16, BASE_DEC, NULL, 0, 0, HFILL + } + }, + { + &rtpsvt_hf_direction, + { + "Traffic Direction", "rtpsvt.direction", + FT_STRING, BASE_NONE, NULL, 0x0, 0, HFILL + } + }, + { + &rtpsvt_hf_packet_identifier, + { + "Packet identifier", "rtpsvt.identifier", + FT_NONE, BASE_NONE, NULL, 0, 0, HFILL + } + }, + { + &rtpsvt_hf_monitoring_guid, + { + "GUID", "rtpsvt.monitoring_guid", + FT_BYTES, BASE_NONE, NULL, 0, 0, HFILL + } + }, + { + &rtpsvt_hf_monitoring_seqNr, + { + "SeqNum", "rtpsvt.seqNr", + FT_UINT64, BASE_DEC, NULL, 0x0, 0, HFILL + } + }, + { + &rtpsvt_hf_information, + { + "Transport Information", "rtpsvt.information", + FT_NONE, BASE_NONE, NULL, 0x0, 0, HFILL + } + }, + { + &rtpsvt_hf_source_port, + { + "Source Port", "rtpsvt.source_port", + FT_UINT32, BASE_DEC, NULL, 0x0, 0, HFILL + } + }, + { + &rtpsvt_hf_source_address, + { + "Source address", "rtpsvt.source_address", + FT_STRING, BASE_NONE, NULL, 0, 0, HFILL + } + }, + { + &rtpsvt_hf_source_pid, + { + "Source process ID", "rtpsvt.source_pid", + FT_STRING, BASE_NONE, NULL, 0, 0, HFILL + } + }, + { + &rtpsvt_hf_destination_port, + { + "Destination Port", "rtpsvt.port", + FT_UINT32, BASE_DEC, NULL, 0x0, 0, HFILL + } + }, + { + &rtpsvt_hf_destination_rtps_port, + { + "Destination RTPS Port", "rtpsvt.rtps_port", + FT_UINT32, BASE_DEC, NULL, 0x0, 0, HFILL + } + }, + { + &rtpsvt_hf_destination_address, + { + "Destination address", "rtpsvt.destination_address", + FT_STRING, BASE_NONE, NULL, 0, 0, HFILL + } + }, + { + &rtpsvt_hf_destination_pid, + { + "Destination process ID", "rtpsvt.destination_pid", + FT_STRING, BASE_NONE, NULL, 0, 0, HFILL + } + }, + { + &rtpsvt_hf_class, + { + "Transport class", "rtpsvt.class", + FT_STRING, BASE_NONE, NULL, 0, 0, HFILL + } + }, + { + /* Information related to the 'lost' content type */ + &rtpsvt_hf_missing_messages, + { + "Packets lost", "rtpsvt.missing_messages", + FT_UINT64, BASE_DEC, NULL, 0x0, 0, HFILL + } + } + }; + + static gint *ett[] = { + &rtpsvt_ett, + &rtpsvt_ett_version, + &rtpsvt_ett_identifier, + &rtpsvt_ett_information, + &rtpsvt_ett_information_class, + &rtpsvt_ett_information_src_port, + &rtpsvt_ett_information_dst_port, + &rtpsvt_ett_information_src_addr, + &rtpsvt_ett_information_dst_addr, + &rtpsvt_ett_information_direction, + &rtpsvt_ett_monitoring_sn, + &rtpsvt_ett_frame + }; + + static ei_register_info ei[] = { + { + &ei_missing_msg, + { + "rtpsvt.expert.missing_messages", + PI_PROTOCOL, + PI_NOTE, + "Missing RTPS Messages because of full buffer pool", + EXPFILL + } + }, + }; + + /* Register the protocol name and description */ + proto_rtpsvt = proto_register_protocol( + "Real-Time Publish-Subscribe Virtual Transport", + "RTPS-VT", + "rtpsvt"); + + /* Required function calls to register the header fields and subtrees */ + rtpsvt_hf = proto_registrar_get_nth(proto_rtpsvt); + proto_register_field_array(proto_rtpsvt, hf, array_length(hf)); + proto_register_subtree_array(ett, array_length(ett)); + + /* Register expert information */ + expert_info = expert_register_protocol(proto_rtpsvt); + expert_register_field_array(expert_info, ei, array_length(ei)); + + register_dissector("rtpsvt", dissect_rtps_virtual_transport, proto_rtpsvt); +} + +/* + * 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/epan/dissectors/packet-rtps.c b/epan/dissectors/packet-rtps.c index cc5886772e..94d3341948 100644 --- a/epan/dissectors/packet-rtps.c +++ b/epan/dissectors/packet-rtps.c @@ -47,6 +47,7 @@ #include #include #include +#include "packet-rtps.h" #include #include #include "zlib.h" @@ -699,22 +700,6 @@ static dissector_table_t rtps_type_name_table; #define CRYPTO_TRANSFORMATION_KIND_AES256_GMAC (3) #define CRYPTO_TRANSFORMATION_KIND_AES256_GCM (4) -/* Vendor specific - rti */ -#define NDDS_TRANSPORT_CLASSID_ANY (0) -#define NDDS_TRANSPORT_CLASSID_UDPv4 (1) -#define NDDS_TRANSPORT_CLASSID_UDPv6 (2) -#define NDDS_TRANSPORT_CLASSID_INTRA (3) -#define NDDS_TRANSPORT_CLASSID_DTLS (6) -#define NDDS_TRANSPORT_CLASSID_WAN (7) -#define NDDS_TRANSPORT_CLASSID_TCPV4_LAN (8) -#define NDDS_TRANSPORT_CLASSID_TCPV4_WAN (9) -#define NDDS_TRANSPORT_CLASSID_TLSV4_LAN (10) -#define NDDS_TRANSPORT_CLASSID_TLSV4_WAN (11) -#define NDDS_TRANSPORT_CLASSID_PCIE (12) -#define NDDS_TRANSPORT_CLASSID_ITP (13) -#define NDDS_TRANSPORT_CLASSID_SHMEM (0x01000000) -#define NDDS_TRANSPORT_CLASSID_UDPv4_WAN (0x01000001) - #define TOPIC_INFO_ADD_GUID (0x01) #define TOPIC_INFO_ADD_TYPE_NAME (0x02) #define TOPIC_INFO_ADD_TOPIC_NAME (0x04) @@ -11863,16 +11848,11 @@ static gboolean dissect_rtps_submessage_v1(tvbuff_t *tvb, packet_info *pinfo, gi static gboolean dissect_rtps(tvbuff_t *tvb, packet_info *pinfo, proto_tree *tree, gint offset) { proto_item *ti; - proto_tree *rtps_tree, *rtps_submessage_tree; - guint8 submessageId, flags, majorRev; + proto_tree *rtps_tree; + guint8 majorRev; guint16 version, vendor_id; gboolean is_ping; - guint encoding; - gint next_submsg, octets_to_next_header; - int sub_hf; - const value_string *sub_vals; endpoint_guid guid; - endpoint_guid dst_guid; guint32 magic_number; gchar domain_id_str[RTPS_UNKNOWN_DOMAIN_ID_STR_LEN] = RTPS_UNKNOWN_DOMAIN_ID_STR; /* Check 'RTPS' signature: @@ -11891,9 +11871,8 @@ static gboolean dissect_rtps(tvbuff_t *tvb, packet_info *pinfo, proto_tree *tree if ((majorRev != 1) && (majorRev != 2)) return FALSE; - /* No fields have been set in either GUID yet. */ + /* No fields have been set in GUID yet. */ guid.fields_present = 0; - dst_guid.fields_present = 0; col_set_str(pinfo->cinfo, COL_PROTOCOL, "RTPS"); col_clear(pinfo->cinfo, COL_INFO); @@ -12044,6 +12023,30 @@ static gboolean dissect_rtps(tvbuff_t *tvb, packet_info *pinfo, proto_tree *tree /* offset behind RTPS's Header (need to be set in case tree=NULL)*/ offset += ((version < 0x0200) ? 16 : 20); + dissect_rtps_submessages(tvb, offset, pinfo, rtps_tree, version, vendor_id); + + /* If TCP there's an extra OOB byte at the end of the message */ + /* TODO: What to do with it? */ + return TRUE; + +} /* dissect_rtps(...) */ + +void dissect_rtps_submessages( + tvbuff_t *tvb, int offset, packet_info *pinfo, proto_tree *rtps_tree, + guint16 version, guint16 vendor_id) +{ + guint8 submessageId, flags; + int sub_hf; + const value_string *sub_vals; + proto_item *ti; + proto_tree *rtps_submessage_tree; + guint encoding; + gint next_submsg, octets_to_next_header; + endpoint_guid guid; + endpoint_guid dst_guid; + + /* No fields have been set in GUID yet. */ + dst_guid.fields_present = 0; while (tvb_reported_length_remaining(tvb, offset) > 0) { submessageId = tvb_get_guint8(tvb, offset); @@ -12085,7 +12088,8 @@ static gboolean dissect_rtps(tvbuff_t *tvb, packet_info *pinfo, proto_tree *tree /* Octets-to-next-header */ octets_to_next_header = tvb_get_guint16(tvb, offset + 2, encoding); - if ((octets_to_next_header == 0) && (version >= 0x0200) && (submessageId != SUBMESSAGE_PAD) && (submessageId != SUBMESSAGE_INFO_TS)) { + if ((octets_to_next_header == 0) && (version >= 0x0200) + && (submessageId != SUBMESSAGE_PAD) && (submessageId != SUBMESSAGE_INFO_TS)) { octets_to_next_header = tvb_reported_length_remaining(tvb, offset + 4); } next_submsg = offset + octets_to_next_header + 4; @@ -12116,12 +12120,7 @@ static gboolean dissect_rtps(tvbuff_t *tvb, packet_info *pinfo, proto_tree *tree /* next submessage's offset */ offset = next_submsg; } - - /* If TCP there's an extra OOB byte at the end of the message */ - /* TODO: What to do with it? */ - return TRUE; - -} /* dissect_rtps(...) */ +} static gboolean dissect_rtps_udp(tvbuff_t *tvb, packet_info *pinfo, proto_tree *tree, void *data _U_) { diff --git a/epan/dissectors/packet-rtps.h b/epan/dissectors/packet-rtps.h new file mode 100644 index 0000000000..b264a94488 --- /dev/null +++ b/epan/dissectors/packet-rtps.h @@ -0,0 +1,70 @@ +/* packet-rtps.h + * Header file for the Real-Time Publish-Subscribe (RTPS) and related (RTPS + * Virtual Transport and Processed) protocols. + * + * (c) 2020 Copyright, Real-Time Innovations, Inc. + * Real-Time Innovations, Inc. + * 232 East Java Drive + * Sunnyvale, CA 94089 + * + * Wireshark - Network traffic analyzer + * By Gerald Combs + * Copyright 1998 Gerald Combs + * + * SPDX-License-Identifier: GPL-2.0-or-later + */ + +#ifndef _TYPEDEFS_DEFINES_RTPS_H +#define _TYPEDEFS_DEFINES_RTPS_H + +#ifdef __cplusplus +extern "C" { +#endif + +/* Vendor specific - rti */ +#define NDDS_TRANSPORT_CLASSID_ANY (0) +#define NDDS_TRANSPORT_CLASSID_UDPv4 (1) +#define NDDS_TRANSPORT_CLASSID_UDPv6 (2) +#define NDDS_TRANSPORT_CLASSID_INTRA (3) +#define NDDS_TRANSPORT_CLASSID_DTLS (6) +#define NDDS_TRANSPORT_CLASSID_WAN (7) +#define NDDS_TRANSPORT_CLASSID_TCPV4_LAN (8) +#define NDDS_TRANSPORT_CLASSID_TCPV4_WAN (9) +#define NDDS_TRANSPORT_CLASSID_TLSV4_LAN (10) +#define NDDS_TRANSPORT_CLASSID_TLSV4_WAN (11) +#define NDDS_TRANSPORT_CLASSID_PCIE (12) +#define NDDS_TRANSPORT_CLASSID_ITP (13) +#define NDDS_TRANSPORT_CLASSID_SHMEM (0x01000000) +#define NDDS_TRANSPORT_CLASSID_UDPv4_WAN (0x01000001) + +/* Process a submessage: used in packet-rtps-processed.c */ +extern void dissect_rtps_submessages( + tvbuff_t *tvb, int offset, packet_info *pinfo, proto_tree *rtps_tree, + guint16 version, guint16 vendor_id); + +/* Information that the RTPS-VT protocol passes to RTPS-PROC */ +struct rtpsvt_data { + guint8 version_major; + guint8 version_minor; + guint8 direction; + guint16 rtps_length; +}; + +#ifdef __cplusplus +} /* extern "C"*/ +#endif + +#endif /* _TYPEDEFS_DEFINES_RTPS_H */ + +/* + * Editor modelines + * + * Local Variables: + * c-basic-offset: 2 + * tab-width: 8 + * indent-tabs-mode: nil + * End: + * + * ex: set shiftwidth=2 tabstop=8 expandtab: + * :indentSize=2:tabSize=8:noTabs=true: + */