Revert "TODO epan/dissectors/asn1/kerberos/packet-kerberos-template.c new GSS flags"
[wireshark-sm.git] / epan / dissectors / packet-rtps-processed.c
blob9afe363f228c1e83b9170840cbd0dd0b3c650589
1 /* packet-rtps-processed.c
2 * Dissector for the Real-Time Publish-Subscribe (RTPS) Processed Protocol.
4 * (c) 2020 Copyright, Real-Time Innovations, Inc.
5 * Real-Time Innovations, Inc.
6 * 232 East Java Drive
7 * Sunnyvale, CA 94089
9 * Wireshark - Network traffic analyzer
10 * By Gerald Combs <gerald@wireshark.org>
11 * Copyright 1998 Gerald Combs
13 * SPDX-License-Identifier: GPL-2.0-or-later
15 * -----------------------------------------------------------------------------
16 * RTI Connext DDS can capture RTPS-related traffic by using the Network Capture
17 * Utility. The generated .pcap capture files will follow a format that
18 * defines how information must be saved, and then parsed.
20 * The format is divided into two layers/protocols: virtual transport
21 * (packet-rtps-virtual-transport.c) and processed (packet-rtps-processed.c).
22 * This file is about the processed dissector. For a general introduction and
23 * information about the virtual transport dissector, read the documentation at
24 * the beginning of packet-rtps-virtual-transport.c.
26 * The processed dissector is called by the transport dissector. It should never
27 * be called directly by Wireshark without going through the transport
28 * dissector first.
30 * The advanced information contains one parameter that it is really important
31 * (and compulsory). This parameter is the "main frame", i.e. the frame that
32 * would usually be captured over the wire. This frame is encrypted if security
33 * applies.
35 * Then we have two optional fields: advanced frame0 and frame1.
36 * - frame0: Contains the RTPS frame with submessage protection (but
37 * decrypted at the RTPS level).
38 * - frame1:
39 * - Inbound traffic: A list of decrypted RTPS submessages (the protected
40 * ones from frame0).
41 * - Outbound traffic: The RTPS message before any kind of protection.
42 * The contents encrypted at RTPS message level can be found in the main frame.
44 * We can see there is a difference between frame1 (the parameter containing the
45 * decrypted RTPS submessages): inbound traffic has a list of submessages (no
46 * RTPS header) but outbound traffic has a RTPS message. The reason behind
47 * this is related to how RTI Connext DDS handles protected inbound traffic.
49 * An alternative would be to build the RTPS message from frame0 and frame1 and
50 * then pass it to the RTPS dissector. This solution would be cleaner but would
51 * require to keep a buffer and information between parameters.
52 * The current solution is kept for the moment.
55 #include "config.h"
57 #include <epan/packet.h>
58 #include <epan/expert.h>
59 #include <epan/prefs.h>
60 #include <epan/addr_resolv.h>
61 #include <epan/wmem_scopes.h>
62 #include <epan/conversation.h>
63 #include "packet-tcp.h"
64 #include "packet-rtps.h"
67 #define PARAM_ID_ADVANCED_FRAME0 0x000C1
68 #define PARAM_ID_ADVANCED_FRAME1 0x000C2
70 void proto_reg_handoff_rtps_processed(void);
71 void proto_register_rtps_processed(void);
72 static int dissect_rtps_processed(
73 tvbuff_t *tvb,
74 packet_info *pinfo,
75 proto_tree *tree,
76 void *data);
77 static void get_new_colinfo_w_submessages(
78 wmem_strbuf_t *out,
79 wmem_strbuf_t *frame,
80 const char *submessages);
82 /* Subtree pointers */
83 static int rtpsproc_tree = -1;
84 static int ett_rtpsproc;
85 static int ett_rtpsproc_security;
86 static int ett_rtpsproc_advanced_frame0;
87 static int ett_rtpsproc_advanced_frame1;
89 /* Initialize the protocol and registered fields */
90 static header_field_info *rtpsproc_hf;
91 static int hf_rtpsproc_param_id;
92 static int hf_rtpsproc_param_length;
94 /* Used for caching a handle to the RTPS dissector */
95 static dissector_handle_t rtps_handle;
97 /* ========================================================================== */
98 /* Dissector */
99 /* ========================================================================== */
101 * Parameters must be in the right order or dissector will fail.
102 * This was done instead of looping for all parameters (like in
103 * packet-rtps-virtual-transport.c) because:
104 * - The number of parameters is small.
105 * - This way we can skip creating some headings if they are not needed (by
106 * using zeros instead).
108 static int dissect_rtps_processed(
109 tvbuff_t *tvb,
110 packet_info *pinfo,
111 proto_tree *tree,
112 void *data)
114 proto_tree *rtpsproc_tree_general = NULL;
115 proto_tree *rtpsproc_tree_security = NULL;
116 proto_item *rtpsproc_ti = NULL;
117 uint16_t param_id;
118 uint16_t param_length;
119 int offset = 0;
120 int offset_version = 4; /* 'R', 'T', 'P', 'S' */
121 tvbuff_t *rtps_payload = NULL;
122 tvbuff_t *message_payload = NULL;
123 struct rtpsvt_data *transport_data = (struct rtpsvt_data *) data;
124 const char *title_security;
125 uint16_t rtps_version = 0x0203;
126 uint16_t rtps_vendor_id = 0x0101;
127 endpoint_guid guid;
129 if (transport_data == NULL) {
130 /* Reject the packet if no transport information */
131 return 0;
133 param_length = transport_data->rtps_length;
134 title_security = transport_data->direction == 1
135 ? "RTPS Security decoding"
136 : "RTPS Security pre-encoding";
138 /* ***************************** MAIN ***********************************/
140 * The contents passed to the rtpsproc dissector must start with the RTPS
141 * frame.
143 rtps_version = tvb_get_uint16(
144 tvb,
145 offset + offset_version,
146 ENC_BIG_ENDIAN);
147 rtps_vendor_id = tvb_get_uint16(
148 tvb,
149 offset + offset_version + 2,
150 ENC_BIG_ENDIAN);
151 guid.host_id = tvb_get_ntohl(tvb, offset + offset_version + 4);
152 guid.app_id = tvb_get_ntohl(tvb, offset + offset_version + 8);
153 guid.instance_id = tvb_get_ntohl(tvb, offset + offset_version + 12);
154 guid.fields_present = GUID_HAS_HOST_ID | GUID_HAS_APP_ID | GUID_HAS_INSTANCE_ID;
155 rtps_payload = tvb_new_subset_length(tvb, offset, param_length);
156 if (rtps_handle != NULL) {
157 call_dissector(rtps_handle, rtps_payload, pinfo, tree);
159 offset += param_length;
161 /* *********** Add subtree used for the fields of our rtpsproc_tree *******/
162 rtpsproc_ti = proto_tree_add_item(
163 tree,
164 rtpsproc_tree,
165 tvb,
166 offset,
168 ENC_BIG_ENDIAN);
169 rtpsproc_tree_general = proto_item_add_subtree(rtpsproc_ti, ett_rtpsproc);
171 /* *************************** ADVANCED 0 *******************************/
172 param_id = tvb_get_uint16(tvb, offset, ENC_BIG_ENDIAN);
173 if (param_id == PARAM_ID_ADVANCED_FRAME0) {
174 proto_tree *rtpsproc_tree_frame0 = NULL;
175 param_length = tvb_get_uint16(tvb, offset + 2, ENC_BIG_ENDIAN);
177 rtpsproc_tree_security = proto_tree_add_subtree_format(
178 rtpsproc_tree_general,
179 tvb,
180 offset,
182 ett_rtpsproc_security,
183 NULL,
184 "%s",
185 title_security);
187 rtpsproc_tree_frame0 = proto_tree_add_subtree_format(
188 rtpsproc_tree_security,
189 tvb,
190 offset,
192 ett_rtpsproc_advanced_frame0,
193 NULL,
194 "%s",
195 "RTPS level");
197 proto_tree_add_uint(
198 rtpsproc_tree_frame0,
199 hf_rtpsproc_param_id,
200 tvb,
201 offset,
202 2, /* length */
203 param_id);
204 offset += 2;
206 proto_tree_add_uint(
207 rtpsproc_tree_frame0,
208 hf_rtpsproc_param_length,
209 tvb,
210 offset,
211 2, /* length */
212 param_length);
213 offset += 2;
215 message_payload = tvb_new_subset_length(tvb, offset, param_length);
216 if (rtps_handle != NULL) {
217 call_dissector(
218 rtps_handle,
219 message_payload,
220 pinfo,
221 rtpsproc_tree_frame0);
223 offset += param_length;
224 } else {
226 * If there is no security information, param_id is zeroed.
227 * In that case the length is also zero, so we move 4 Bytes in total.
229 offset += 4;
232 /* *************************** ADVANCED 1 *******************************/
233 param_id = tvb_get_uint16(tvb, offset, ENC_BIG_ENDIAN);
234 if (param_id == PARAM_ID_ADVANCED_FRAME1) {
235 proto_tree *rtpsproc_tree_frame1 = NULL;
236 const char *title = transport_data->direction
237 ? "Submessage level"
238 : "RTPS and Submessage level (no protection)";
239 param_length = tvb_get_uint16(tvb, offset + 2, ENC_BIG_ENDIAN);
241 if (rtpsproc_tree_security == NULL) {
242 rtpsproc_tree_security = proto_tree_add_subtree_format(
243 rtpsproc_tree_general,
244 tvb,
245 offset,
247 ett_rtpsproc_security,
248 NULL,
249 "%s",
250 title_security);
253 rtpsproc_tree_frame1 = proto_tree_add_subtree_format(
254 rtpsproc_tree_security,
255 tvb,
256 offset,
258 ett_rtpsproc_advanced_frame1,
259 NULL,
260 "%s",
261 title);
263 proto_tree_add_uint(
264 rtpsproc_tree_frame1,
265 hf_rtpsproc_param_id,
266 tvb,
267 offset,
268 2, /* length */
269 param_id);
270 offset += 2;
272 proto_tree_add_uint(
273 rtpsproc_tree_frame1,
274 hf_rtpsproc_param_length,
275 tvb,
276 offset,
277 2, /* length */
278 param_length);
279 offset += 2;
282 * Depending on the direction we have:
283 * - Inbound: List of decrypted submessages.
284 * - Outbound: The RTPS message before any kind of protection.
285 * So, we handle them differently.
287 if (transport_data->direction) {
288 tvbuff_t *rtps_submessages = NULL;
289 wmem_strbuf_t *info_w_encrypted = NULL; /* Current info */
290 wmem_strbuf_t *info_w_decrypted = NULL; /* New info */
293 * Get the current column info. This has the RTPS frames with the
294 * encrypted submessages. We are going to update the text so that
295 * it has the decrypted information, which is more useful to the
296 * user.
298 if (pinfo->cinfo) {
299 const char *colinfo = col_get_text(pinfo->cinfo, COL_INFO);
300 if (colinfo) {
301 info_w_encrypted = wmem_strbuf_new(
302 pinfo->pool,
303 colinfo);
304 col_clear(pinfo->cinfo, COL_INFO);
307 /* Dissect the submessages using the RTPS dissector */
308 rtps_submessages = tvb_new_subset_length(tvb, offset, param_length);
309 dissect_rtps_submessages(
310 rtps_submessages,
311 0, /* offset */
312 pinfo,
313 rtpsproc_tree_frame1,
314 rtps_version,
315 rtps_vendor_id,
316 &guid,
317 false /* dissect_rtps_submessages. */);
320 * Get the decrypted submessages and update the column information.
322 if (pinfo->cinfo) {
323 const char *colinfo = col_get_text(pinfo->cinfo, COL_INFO);
324 info_w_decrypted = wmem_strbuf_new(pinfo->pool, "");
325 if (colinfo) {
326 get_new_colinfo_w_submessages(
327 info_w_decrypted, /* out */
328 info_w_encrypted, /* in */
329 colinfo); /* in */
330 col_clear(pinfo->cinfo, COL_INFO);
331 col_set_str(
332 pinfo->cinfo,
333 COL_INFO,
334 wmem_strbuf_get_str(info_w_decrypted));
337 } else {
338 message_payload = tvb_new_subset_length(tvb, offset, param_length);
339 if (rtps_handle != NULL) {
340 call_dissector(
341 rtps_handle,
342 message_payload,
343 pinfo,
344 rtpsproc_tree_frame1);
348 return tvb_captured_length(tvb);
351 /* ========================================================================== */
352 /* Other */
353 /* ========================================================================== */
356 * This function is called at startup and caches the handle for the register.
357 * That way we don't have to find the dissector for each packet.
359 void proto_reg_handoff_rtps_processed(void)
361 rtps_handle = find_dissector("rtps");
364 static void get_new_colinfo_w_submessages(
365 wmem_strbuf_t *out,
366 wmem_strbuf_t *frame,
367 const char *submessages)
369 const char *pattern = "SEC_PREFIX, SEC_BODY, SEC_POSTFIX";
370 const char *frame_str = wmem_strbuf_get_str(frame);
371 size_t idx = 0; /* index for iterating frame_str */
372 char *submessages_dup = g_strdup(submessages);
373 /* First decrypted submessage in submessages list */
374 char *submessage_current = strtok(submessages_dup, ", ");
375 /* First encrypted submessage. Found by searching the RTPS colinfo */
376 char *encrypted_current = strstr(&frame_str[idx], pattern);
378 while (encrypted_current != NULL) {
379 /* Copy the RTPS frame up to the newly found encrypted submessage */
380 size_t length_to_copy = encrypted_current - &frame_str[idx];
381 wmem_strbuf_append_len(out, &frame_str[idx], length_to_copy);
383 /* Copy the decrypted contents that replace the encrypted submessage */
384 wmem_strbuf_append(out, submessage_current);
386 /* Advance the index and continue searching */
387 idx += length_to_copy + strlen(pattern);
388 encrypted_current = strstr(&frame_str[idx], pattern);
390 /* Copy the remaining from the RTPS frame */
391 wmem_strbuf_append(out, &frame_str[idx]);
394 /* ========================================================================== */
395 /* Protocol registration */
396 /* ========================================================================== */
397 void
398 proto_register_rtps_processed(void)
400 static hf_register_info hf[] = {
402 &hf_rtpsproc_param_id,
404 "Parameter Identifier", "rtpsproc.param.id",
405 FT_UINT16, BASE_DEC, NULL, 0, NULL, HFILL
409 &hf_rtpsproc_param_length,
411 "Parameter Length", "rtpsproc.param.length",
412 FT_UINT16, BASE_DEC, NULL, 0, NULL, HFILL
416 static int *ett[] = {
417 &ett_rtpsproc,
418 &ett_rtpsproc_security,
419 &ett_rtpsproc_advanced_frame0,
420 &ett_rtpsproc_advanced_frame1
423 /* Register the protocol name and description */
424 rtpsproc_tree = proto_register_protocol("Real-Time Publish-Subscribe Wire Protocol (processed)", "RTPS-PROC", "rtpsproc");
426 /* Required function calls to register the header fields and subtrees */
427 rtpsproc_hf = proto_registrar_get_nth(rtpsproc_tree);
428 proto_register_field_array(rtpsproc_tree, hf, array_length(hf));
429 proto_register_subtree_array(ett, array_length(ett));
431 register_dissector("rtpsproc", dissect_rtps_processed, rtpsproc_tree);
434 // /*
435 // * Editor modelines - https://www.wireshark.org/tools/modelines.html
436 // *
437 // * Local variables:
438 // * c-basic-offset: 4
439 // * tab-width: 8
440 // * indent-tabs-mode: nil
441 // * End:
442 // *
443 // * vi: set shiftwidth=4 tabstop=8 expandtab:
444 // * :indentSize=4:tabSize=8:noTabs=true:
445 // */