1 /* packet-transum.c
2 * Routines for the TRANSUM response time analyzer post-dissector
3 * By Paul Offord <paul.offord@advance7.com>
4 * Copyright 2016 Advance Seven Limited
5 *
6 * Wireshark - Network traffic analyzer
7 * By Gerald Combs <gerald@wireshark.org>
8 * Copyright 1998 Gerald Combs
9 *
10 * SPDX-License-Identifier: GPL-2.0-or-later
11 */
12
13 /* ToDo: Test handling of multiple SMB2 messages within a packet */
14 /* ToDo: Rework the Summarizer code (future release) */
15
16 #include "config.h"
17 #define WS_LOG_DOMAIN "transum"
18
19 #include <epan/proto.h>
20 #include <epan/packet.h>
21 #include <epan/prefs.h>
22 #include <epan/ws_printf.h>
23 #include "packet-transum.h"
24 #include "preferences.h"
25 #include "extractors.h"
26 #include "decoders.h"
27 #include <wsutil/wslog.h>
28
29 void proto_register_transum(void);
30 void proto_reg_handoff_transum(void);
31
32 static dissector_handle_t transum_handle;
33
34 #define CAPTURE_CLIENT 0
35 #define CAPTURE_INTERMEDIATE 1
36 #define CAPTURE_SERVICE 2
37
38 #define RTE_TIME_SEC 1
39 #define RTE_TIME_MSEC 1000
40 #define RTE_TIME_USEC 1000000
41
42 /* The following are the field ids for the protocol values used by TRANSUM.
43 Make sure they line up with ehf_of_interest order */
44 HF_OF_INTEREST_INFO hf_of_interest[HF_INTEREST_END_OF_LIST] = {
45 { -1, "ip.proto" },
46 { -1, "ipv6.nxt" },
47
48 { -1, "tcp.analysis.retransmission" },
49 { -1, "tcp.analysis.keep_alive" },
50 { -1, "tcp.flags.syn" },
51 { -1, "tcp.flags.ack" },
52 { -1, "tcp.flags.reset" },
53 { -1, "tcp.flags.urg" },
54 { -1, "tcp.seq" },
55 { -1, "tcp.srcport" },
56 { -1, "tcp.dstport" },
57 { -1, "tcp.stream" },
58 { -1, "tcp.len" },
59
60 { -1, "udp.srcport" },
61 { -1, "udp.dstport" },
62 { -1, "udp.stream" },
63 { -1, "udp.length" },
64
65 { -1, "tls.record.content_type" },
66
67 { -1, "tds.type" },
68 { -1, "tds.length" },
69
70 { -1, "smb.mid" },
71
72 { -1, "smb2.sesid" },
73 { -1, "smb2.msg_id" },
74 { -1, "smb2.cmd" },
75
76 { -1, "dcerpc.ver" },
77 { -1, "dcerpc.pkt_type" },
78 { -1, "dcerpc.cn_call_id" },
79 { -1, "dcerpc.cn_ctx_id" },
80
81 { -1, "dns.id"},
82 };
83
84
85 static range_t *tcp_svc_port_range_values;
86
87 static range_t *udp_svc_port_range_values;
88
89 TSUM_PREFERENCES preferences;
90
91
92 static wmem_map_t *detected_tcp_svc; /* this array is used to track services detected during the syn/syn-ack process */
93
94 static wmem_map_t *dcerpc_req_pkt_type; /* used to indicate if a DCE-RPC pkt_type is a request */
95
96 static wmem_map_t *dcerpc_streams = NULL; /* used to record TCP stream numbers that are carrying DCE-RPC data */
97
98 /*
99 This array contains calls and returns that have no TRUE context_id
100 This is needed to overcome an apparent bug in Wireshark where
101 the field name of context id in parameters is the same as context id
102 in a message header
103 */
104 static wmem_map_t *dcerpc_context_zero;
105
106 /*
107 The rrpd_list holds information about all of the APDU Request-Response Pairs seen in the trace.
108 */
109 static wmem_list_t *rrpd_list = NULL;
110
111 /*
112 output_rrpd is a hash of pointers to RRPDs on the rrpd_list. The index is the frame number. This hash is
113 used during Wireshark's second scan. As each packet is processed, TRANSUM uses the packet's frame number to index into
114 this hash to determine if we have RTE data for this particular packet, and if so the write_rte function is called.
115 */
116 static wmem_map_t *output_rrpd;
117
118 /*
119 The temp_rsp_rrpd_list holds RRPDs for APDUs where we have not yet seen the header information and so we can't
120 fully qualify the identification of the RRPD (the identification being ip_proto:stream_no:session_id:msg_id).
121 This only occurs when a) we are using one of the decode_based calculations (such as SMB2), and b) when we have
122 TCP Reassembly enabled. Once we receive a header packet for an APDU we migrate the entry from this array to the
123 main rrpd_list.
124 */
125 static wmem_list_t *temp_rsp_rrpd_list = NULL; /* Reuse these for speed and efficient memory use - issue a warning if we run out */
126
127 /* Optimisation data - the following is used for various optimisation measures */
128 static int highest_tcp_stream_no;
129 static int highest_udp_stream_no;
130 wmem_map_t *tcp_stream_exceptions;
131
132
133 static gint ett_transum = -1;
134 static gint ett_transum_header = -1;
135 static gint ett_transum_data = -1;
136
137 static int proto_transum = -1;
138
139 static int hf_tsum_status = -1;
140 //static int hf_tsum_time_units = -1;
141 static int hf_tsum_req_first_seg = -1;
142 static int hf_tsum_req_last_seg = -1;
143 static int hf_tsum_rsp_first_seg = -1;
144 static int hf_tsum_rsp_last_seg = -1;
145 static int hf_tsum_apdu_rsp_time = -1;
146 static int hf_tsum_service_time = -1;
147 static int hf_tsum_req_spread = -1;
148 static int hf_tsum_rsp_spread = -1;
149 static int hf_tsum_clip_filter = -1;
150 static int hf_tsum_calculation = -1;
151 static int hf_tsum_summary = -1;
152 static int hf_tsum_req_search = -1;
153 static int hf_tsum_rsp_search = -1;
154
155 static const enum_val_t capture_position_vals[] = {
156 { "TRACE_CAP_CLIENT", "Client", TRACE_CAP_CLIENT },
157 { "TRACE_CAP_INTERMEDIATE", "Intermediate", TRACE_CAP_INTERMEDIATE },
158 { "TRACE_CAP_SERVICE", "Service", TRACE_CAP_SERVICE },
159 { NULL, NULL, 0}
160 };
161
162 static const value_string rrdp_calculation_vals[] = {
163 { RTE_CALC_GTCP, "Generic TCP" },
164 { RTE_CALC_SYN, "SYN and SYN/ACK" },
165 { RTE_CALC_DCERPC, "DCE-RPC" },
166 { RTE_CALC_SMB2, "SMB2" },
167 { RTE_CALC_GUDP, "Generic UDP" },
168 { RTE_CALC_DNS, "DNS" },
169
170 { 0, NULL }
171 };
172
173 /*static const enum_val_t time_multiplier_vals[] = {
174 { "RTE_TIME_SEC", "seconds", RTE_TIME_SEC },
175 { "RTE_TIME_MSEC", "milliseconds", RTE_TIME_MSEC },
176 { "RTE_TIME_USEC", "microseconds", RTE_TIME_USEC },
177 { NULL, NULL, 0}
178 };*/
179
add_detected_tcp_svc(guint16 port)180 void add_detected_tcp_svc(guint16 port)
181 {
182 wmem_map_insert(detected_tcp_svc, GUINT_TO_POINTER(port), GUINT_TO_POINTER(port));
183 }
184
185
init_dcerpc_data(void)186 static void init_dcerpc_data(void)
187 {
188 wmem_map_insert(dcerpc_req_pkt_type, GUINT_TO_POINTER(0), GUINT_TO_POINTER(1));
189 wmem_map_insert(dcerpc_req_pkt_type, GUINT_TO_POINTER(11), GUINT_TO_POINTER(1));
190 wmem_map_insert(dcerpc_req_pkt_type, GUINT_TO_POINTER(14), GUINT_TO_POINTER(1));
191
192 wmem_map_insert(dcerpc_context_zero, GUINT_TO_POINTER(11), GUINT_TO_POINTER(11));
193 wmem_map_insert(dcerpc_context_zero, GUINT_TO_POINTER(12), GUINT_TO_POINTER(12));
194 wmem_map_insert(dcerpc_context_zero, GUINT_TO_POINTER(14), GUINT_TO_POINTER(14));
195 wmem_map_insert(dcerpc_context_zero, GUINT_TO_POINTER(15), GUINT_TO_POINTER(15));
196 }
197
register_dcerpc_stream(guint32 stream_no)198 static void register_dcerpc_stream(guint32 stream_no)
199 {
200 wmem_map_insert(dcerpc_streams, GUINT_TO_POINTER(stream_no), GUINT_TO_POINTER(1));
201 }
202
203 /* This function should be called before any change to RTE data. */
null_output_rrpd_entries(RRPD * in_rrpd)204 static void null_output_rrpd_entries(RRPD *in_rrpd)
205 {
206 wmem_map_remove(output_rrpd, GUINT_TO_POINTER(in_rrpd->req_first_frame));
207 wmem_map_remove(output_rrpd, GUINT_TO_POINTER(in_rrpd->req_last_frame));
208 wmem_map_remove(output_rrpd, GUINT_TO_POINTER(in_rrpd->rsp_first_frame));
209 wmem_map_remove(output_rrpd, GUINT_TO_POINTER(in_rrpd->rsp_last_frame));
210 }
211
212 /* This function should be called after any change to RTE data. */
update_output_rrpd(RRPD * in_rrpd)213 static void update_output_rrpd(RRPD *in_rrpd)
214 {
215 if (preferences.rte_on_first_req)
216 wmem_map_insert(output_rrpd, GUINT_TO_POINTER(in_rrpd->req_first_frame), in_rrpd);
217
218 if (preferences.rte_on_last_req)
219 wmem_map_insert(output_rrpd, GUINT_TO_POINTER(in_rrpd->req_last_frame), in_rrpd);
220
221 if (preferences.rte_on_first_rsp)
222 wmem_map_insert(output_rrpd, GUINT_TO_POINTER(in_rrpd->rsp_first_frame), in_rrpd);
223
224 if (preferences.rte_on_last_rsp)
225 wmem_map_insert(output_rrpd, GUINT_TO_POINTER(in_rrpd->rsp_last_frame), in_rrpd);
226 }
227
228 /* Return the index of the RRPD that has been appended */
append_to_rrpd_list(RRPD * in_rrpd)229 static RRPD* append_to_rrpd_list(RRPD *in_rrpd)
230 {
231 RRPD *next_rrpd = (RRPD*)wmem_memdup(wmem_file_scope(), in_rrpd, sizeof(RRPD));
232
233 update_output_rrpd(next_rrpd);
234
235 wmem_list_append(rrpd_list, next_rrpd);
236
237 return next_rrpd;
238 }
239
find_latest_rrpd_dcerpc(RRPD * in_rrpd)240 static RRPD *find_latest_rrpd_dcerpc(RRPD *in_rrpd)
241 {
242 RRPD *rrpd;
243 wmem_list_frame_t* i;
244
245 for (i = wmem_list_tail(rrpd_list); i != NULL; i = wmem_list_frame_prev(i))
246 {
247 rrpd = (RRPD*)wmem_list_frame_data(i);
248
249 if (rrpd->calculation != RTE_CALC_DCERPC && rrpd->calculation != RTE_CALC_SYN)
250 continue;
251
252 /* if the input 5-tuple doesn't match the rrpd_list_entry 5-tuple -> go find the next list entry */
253 if (rrpd->ip_proto == in_rrpd->ip_proto && rrpd->stream_no == in_rrpd->stream_no)
254 {
255 /* if we can match on session_id and msg_id must be a retransmission of the last request packet or the response */
256 /* this logic works whether or not we are using reassembly */
257 if (rrpd->session_id == in_rrpd->session_id && rrpd->msg_id == in_rrpd->msg_id)
258 return rrpd;
259
260 /* If this is a retransmission, we assume it relates to this rrpd_list entry.
261 This is a bit of a kludge and not ideal but a compromise.*/
262 /* ToDo: look at using TCP sequence number to allocate a retransmission to the correct APDU */
263 if (in_rrpd->is_retrans)
264 return rrpd;
265
266 if (preferences.reassembly)
267 {
268 if (in_rrpd->c2s)
269 {
270 /* if the input rrpd is for c2s and the one we have found already has response information, then the
271 in_rrpd represents a new RR Pair. */
272 if (rrpd->rsp_first_frame)
273 return NULL;
274
275 /* 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. */
276 if (!rrpd->msg_id)
277 return rrpd;
278 }
279 else /* The in_rrpd relates to a packet going s2c */
280 {
281 /* When reassembly is enabled, multi-packet response information is actually migrated from the temp_rsp_rrpd_list
282 to the rrpd_list and so we won't come through here. */
283 ;
284 }
285 }
286 else /* we are not using reassembly */
287 {
288 if (in_rrpd->c2s)
289 {
290 if (in_rrpd->msg_id)
291 /* if we have a message id this is a new Request APDU */
292 return NULL;
293 else /* No msg_id */
294 {
295 return rrpd; /* add this packet to the matching stream */
296 }
297 }
298 else /* this packet is going s2c */
299 {
300 if (!in_rrpd->msg_id && rrpd->rsp_first_frame)
301 /* we need to add this frame to the response APDU of the most recent rrpd_list entry that has already had response packets */
302 return rrpd;
303 }
304 }
305 } /* this is the end of the 5-tuple check */
306
307 if (in_rrpd->c2s)
308 in_rrpd->req_search_total++;
309 else
310 in_rrpd->rsp_search_total++;
311 } /* end of the for loop */
312
313 return NULL;
314 }
315
find_latest_rrpd_dns(RRPD * in_rrpd)316 static RRPD *find_latest_rrpd_dns(RRPD *in_rrpd)
317 {
318 RRPD *rrpd;
319 wmem_list_frame_t* i;
320
321 for (i = wmem_list_tail(rrpd_list); i != NULL; i = wmem_list_frame_prev(i))
322 {
323 rrpd = (RRPD*)wmem_list_frame_data(i);
324
325 if (rrpd->calculation != RTE_CALC_DNS)
326 continue;
327
328 /* if the input 5-tuple doesn't match the rrpd_list_entry 5-tuple -> go find the next list entry */
329 if (rrpd->ip_proto == in_rrpd->ip_proto && rrpd->stream_no == in_rrpd->stream_no)
330 {
331 if (rrpd->session_id == in_rrpd->session_id && rrpd->msg_id == in_rrpd->msg_id)
332 {
333 if (in_rrpd->c2s && rrpd->rsp_first_frame)
334 return NULL; /* this is new */
335 else
336 return rrpd;
337 }
338 } /* this is the end of the 5-tuple check */
339
340 if (in_rrpd->c2s)
341 in_rrpd->req_search_total++;
342 else
343 in_rrpd->rsp_search_total++;
344 } /* this is the end of the for loop */
345
346 return NULL;
347 }
348
find_latest_rrpd_gtcp(RRPD * in_rrpd)349 static RRPD *find_latest_rrpd_gtcp(RRPD *in_rrpd)
350 {
351 RRPD *rrpd;
352 wmem_list_frame_t* i;
353
354 for (i = wmem_list_tail(rrpd_list); i != NULL; i = wmem_list_frame_prev(i))
355 {
356 rrpd = (RRPD*)wmem_list_frame_data(i);
357
358 if (rrpd->calculation != RTE_CALC_GTCP && rrpd->calculation != RTE_CALC_SYN)
359 continue;
360
361 /* if the input 5-tuple doesn't match the rrpd_list_entry 5-tuple -> go find the next list entry */
362 if (rrpd->ip_proto == in_rrpd->ip_proto && rrpd->stream_no == in_rrpd->stream_no)
363 {
364 if (in_rrpd->c2s && rrpd->rsp_first_frame)
365 return NULL; /* this is new */
366 else
367 return rrpd;
368 } /* this is the end of the 5-tuple check */
369
370 if (in_rrpd->c2s)
371 in_rrpd->req_search_total++;
372 else
373 in_rrpd->rsp_search_total++;
374 } /* this is the end of the for loop */
375
376 return NULL;
377 }
378
find_latest_rrpd_gudp(RRPD * in_rrpd)379 static RRPD *find_latest_rrpd_gudp(RRPD *in_rrpd)
380 {
381 RRPD *rrpd;
382 wmem_list_frame_t* i;
383
384 for (i = wmem_list_tail(rrpd_list); i != NULL; i = wmem_list_frame_prev(i))
385 {
386 rrpd = (RRPD*)wmem_list_frame_data(i);
387
388 if (rrpd->calculation != RTE_CALC_GUDP)
389 continue;
390
391 /* if the input 5-tuple doesn't match the rrpd_list_entry 5-tuple -> go find the next list entry */
392 if (rrpd->ip_proto == in_rrpd->ip_proto && rrpd->stream_no == in_rrpd->stream_no)
393 {
394 if (in_rrpd->c2s && rrpd->rsp_first_frame)
395 return NULL; /* this is new */
396 else
397 return rrpd;
398 } /* this is the end of the 5-tuple check */
399
400 if (in_rrpd->c2s)
401 in_rrpd->req_search_total++;
402 else
403 in_rrpd->rsp_search_total++;
404 } /* this is the end of the for loop */
405
406 return NULL;
407 }
408
find_latest_rrpd_smb2(RRPD * in_rrpd)409 static RRPD *find_latest_rrpd_smb2(RRPD *in_rrpd)
410 {
411 RRPD *rrpd;
412 wmem_list_frame_t* i;
413
414 for (i = wmem_list_tail(rrpd_list); i != NULL; i = wmem_list_frame_prev(i))
415 {
416 rrpd = (RRPD*)wmem_list_frame_data(i);
417
418 if (rrpd->calculation != RTE_CALC_SMB2 && rrpd->calculation != RTE_CALC_SYN)
419 continue;
420
421 /* if the input 5-tuple doesn't match the rrpd_list_entry 5-tuple -> go find the next list entry */
422 if (rrpd->ip_proto == in_rrpd->ip_proto && rrpd->stream_no == in_rrpd->stream_no)
423 {
424 /* if we can match on session_id and msg_id must be a retransmission of the last request packet or the response */
425 /* this logic works whether or not we are using reassembly */
426 if (rrpd->session_id == in_rrpd->session_id && rrpd->msg_id == in_rrpd->msg_id)
427 return rrpd;
428
429 /* If this is a retransmission, we assume it relates to this rrpd_list entry.
430 This is a bit of a kludge and not ideal but a compromise.*/
431 /* ToDo: look at using TCP sequence number to allocate a retransmission to the correct APDU */
432 if (in_rrpd->is_retrans)
433 return rrpd;
434
435 if (preferences.reassembly)
436 {
437 if (in_rrpd->c2s)
438 {
439 /* if the input rrpd is for c2s and the one we have found already has response information, then the
440 in_rrpd represents a new RR Pair. */
441 if (rrpd->rsp_first_frame)
442 return NULL;
443
444 /* 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. */
445 if (!rrpd->msg_id)
446 return rrpd;
447 }
448 else /* The in_rrpd relates to a packet going s2c */
449 {
450 /* When reassembly is enabled, multi-packet response information is actually migrated from the temp_rsp_rrpd_list
451 to the rrpd_list and so we won't come through here. */
452 ;
453 }
454 }
455 else /* we are not using reassembly */
456 {
457 if (in_rrpd->c2s)
458 {
459 if (in_rrpd->msg_id)
460 /* if we have a message id this is a new Request APDU */
461 return NULL;
462 else /* No msg_id */
463 {
464 return rrpd; /* add this packet to the matching stream */
465 }
466 }
467 else /* this packet is going s2c */
468 {
469 if (!in_rrpd->msg_id && rrpd->rsp_first_frame)
470 /* we need to add this frame to the response APDU of the most recent rrpd_list entry that has already had response packets */
471 return rrpd;
472 }
473 }
474 } /* this is the end of the 5-tuple check */
475
476 if (in_rrpd->c2s)
477 in_rrpd->req_search_total++;
478 else
479 in_rrpd->rsp_search_total++;
480 } /* end of the for loop */
481
482 return NULL;
483 }
484
find_latest_rrpd_syn(RRPD * in_rrpd)485 static RRPD *find_latest_rrpd_syn(RRPD *in_rrpd)
486 {
487 RRPD *rrpd;
488 wmem_list_frame_t* i;
489
490 for (i = wmem_list_tail(rrpd_list); i != NULL; i = wmem_list_frame_prev(i))
491 {
492 rrpd = (RRPD*)wmem_list_frame_data(i);
493
494 if (rrpd->calculation != RTE_CALC_SYN)
495 continue;
496
497 /* if the input 5-tuple doesn't match the rrpd_list_entry 5-tuple -> go find the next list entry */
498 if (rrpd->ip_proto == in_rrpd->ip_proto && rrpd->stream_no == in_rrpd->stream_no)
499 {
500 return rrpd;
501 } /* this is the end of the 5-tuple check */
502
503 if (in_rrpd->c2s)
504 in_rrpd->req_search_total++;
505 else
506 in_rrpd->rsp_search_total++;
507 } /* this is the end of the for loop */
508
509 return NULL;
510 }
511
find_latest_rrpd(RRPD * in_rrpd)512 static RRPD *find_latest_rrpd(RRPD *in_rrpd)
513 {
514 /* Optimisation Code */
515 if (in_rrpd->ip_proto == IP_PROTO_TCP && (int)in_rrpd->stream_no > highest_tcp_stream_no)
516 {
517 highest_tcp_stream_no = in_rrpd->stream_no;
518 return NULL;
519 }
520 else if (in_rrpd->ip_proto == IP_PROTO_UDP && (int)in_rrpd->stream_no > highest_udp_stream_no)
521 {
522 highest_udp_stream_no = in_rrpd->stream_no;
523 return NULL;
524 }
525 /* End of Optimisation Code */
526
527 switch (in_rrpd->calculation)
528 {
529 case RTE_CALC_DCERPC:
530 return find_latest_rrpd_dcerpc(in_rrpd);
531 break;
532
533 case RTE_CALC_DNS:
534 return find_latest_rrpd_dns(in_rrpd);
535 break;
536
537 case RTE_CALC_GTCP:
538 return find_latest_rrpd_gtcp(in_rrpd);
539 break;
540
541 case RTE_CALC_GUDP:
542 return find_latest_rrpd_gudp(in_rrpd);
543 break;
544
545 case RTE_CALC_SMB2:
546 return find_latest_rrpd_smb2(in_rrpd);
547 break;
548
549 case RTE_CALC_SYN:
550 return find_latest_rrpd_syn(in_rrpd);
551 break;
552 }
553
554 return NULL;
555 }
556
update_rrpd_list_entry(RRPD * match,RRPD * in_rrpd)557 static void update_rrpd_list_entry(RRPD *match, RRPD *in_rrpd)
558 {
559 null_output_rrpd_entries(match);
560
561 if (preferences.debug_enabled)
562 {
563 match->req_search_total += in_rrpd->req_search_total;
564 match->rsp_search_total += in_rrpd->rsp_search_total;
565 }
566
567 if (in_rrpd->c2s)
568 {
569 match->req_last_frame = in_rrpd->req_last_frame;
570 match->req_last_rtime = in_rrpd->req_last_rtime;
571 if (in_rrpd->msg_id)
572 {
573 match->session_id = in_rrpd->session_id;
574 match->msg_id = in_rrpd->msg_id;
575 }
576 }
577 else
578 {
579 if (!match->rsp_first_frame)
580 {
581 match->rsp_first_frame = in_rrpd->rsp_first_frame;
582 match->rsp_first_rtime = in_rrpd->rsp_first_rtime;
583 }
584 match->rsp_last_frame = in_rrpd->rsp_last_frame;
585 match->rsp_last_rtime = in_rrpd->rsp_last_rtime;
586 }
587
588 update_output_rrpd(match);
589 }
590
591 /*
592 This function processes a sub-packet that is going from client-to-service.
593 */
update_rrpd_list_entry_req(RRPD * in_rrpd)594 static void update_rrpd_list_entry_req(RRPD *in_rrpd)
595 {
596 RRPD *match;
597
598 match = find_latest_rrpd(in_rrpd);
599
600 if (match != NULL)
601 update_rrpd_list_entry(match, in_rrpd);
602 else
603 append_to_rrpd_list(in_rrpd);
604 }
605
606 /*
607 This function inserts an RRPD into the temp_rsp_rrpd_list. If this is
608 successful return a pointer to the entry, else return NULL.
609 */
insert_into_temp_rsp_rrpd_list(RRPD * in_rrpd)610 static RRPD* insert_into_temp_rsp_rrpd_list(RRPD *in_rrpd)
611 {
612 RRPD *rrpd = (RRPD*)wmem_memdup(wmem_file_scope(), in_rrpd, sizeof(RRPD));
613
614 wmem_list_append(temp_rsp_rrpd_list, rrpd);
615
616 return rrpd;
617 }
618
find_temp_rsp_rrpd(RRPD * in_rrpd)619 static RRPD* find_temp_rsp_rrpd(RRPD *in_rrpd)
620 {
621 wmem_list_frame_t *i;
622 RRPD* rrpd;
623
624 for (i = wmem_list_head(temp_rsp_rrpd_list); i; i = wmem_list_frame_next(i))
625 {
626 rrpd = (RRPD*)wmem_list_frame_data(i);
627 if (rrpd->ip_proto == in_rrpd->ip_proto && rrpd->stream_no == in_rrpd->stream_no)
628 return rrpd;
629 }
630
631 return NULL;
632 }
633
update_temp_rsp_rrpd(RRPD * temp_list,RRPD * in_rrpd)634 static void update_temp_rsp_rrpd(RRPD *temp_list, RRPD *in_rrpd)
635 {
636 temp_list->rsp_last_frame = in_rrpd->rsp_last_frame;
637 temp_list->rsp_last_rtime = in_rrpd->rsp_last_rtime;
638 }
639
640 /* This function migrates an entry from the temp_rsp_rrpd_list to the main rrpd_list. */
migrate_temp_rsp_rrpd(RRPD * main_list,RRPD * temp_list)641 static void migrate_temp_rsp_rrpd(RRPD *main_list, RRPD *temp_list)
642 {
643 update_rrpd_list_entry(main_list, temp_list);
644
645 wmem_list_remove(temp_rsp_rrpd_list, temp_list);
646 }
647
update_rrpd_list_entry_rsp(RRPD * in_rrpd)648 static void update_rrpd_list_entry_rsp(RRPD *in_rrpd)
649 {
650 RRPD *match, *temp_list;
651
652 if (in_rrpd->decode_based)
653 {
654 if (preferences.reassembly)
655 {
656 if (in_rrpd->msg_id)
657 {
658 /* If we have a msg_id in the input RRPD we must have header information. */
659 temp_list = find_temp_rsp_rrpd(in_rrpd);
660
661 if (temp_list != NULL)
662 {
663 update_temp_rsp_rrpd(temp_list, in_rrpd);
664
665 /* Migrate the temp_rsp_rrpd_list entry to the main rrpd_list */
666 match = find_latest_rrpd(in_rrpd);
667 if (match != NULL)
668 migrate_temp_rsp_rrpd(match, temp_list);
669 }
670 else
671 {
672 match = find_latest_rrpd(in_rrpd);
673 /* There isn't an entry in the temp_rsp_rrpd_list so update the master rrpd_list entry */
674 if (match != NULL)
675 update_rrpd_list_entry(match, in_rrpd);
676 }
677 }
678 else
679 {
680 /* Update an existing entry to the temp_rsp_rrpd_list or add a new one. */
681 temp_list = find_temp_rsp_rrpd(in_rrpd);
682
683 if (temp_list != NULL)
684 update_temp_rsp_rrpd(temp_list, in_rrpd);
685 else
686 {
687 /* If this is a retransmission we need to add it to the last completed rrpd_list entry for this stream */
688 if (in_rrpd->is_retrans)
689 {
690 match = find_latest_rrpd(in_rrpd);
691
692 if (match != NULL)
693 update_rrpd_list_entry(match, in_rrpd);
694 else
695 insert_into_temp_rsp_rrpd_list(in_rrpd);
696 }
697 else
698 /* As it's not a retransmission, just create a new entry on the temp list */
699 insert_into_temp_rsp_rrpd_list(in_rrpd);
700 }
701 }
702 }
703 else
704 {
705 /* Reassembly isn't set and so just go ahead and use the list function */
706 match = find_latest_rrpd(in_rrpd);
707 if (match != NULL)
708 update_rrpd_list_entry(match, in_rrpd);
709 }
710 }
711 else
712 {
713 /* if this isn't decode_based then just go ahead and update the RTE data */
714 match = find_latest_rrpd(in_rrpd);
715 if (match != NULL)
716 update_rrpd_list_entry(match, in_rrpd);
717 }
718
719 return;
720 }
721
722
723 /*
724 This function updates the RTE data of an RRPD on the rrpd_list. The
725 frame_no values in the input RRPD double up as a mask. If the frame_no
726 is > 0 then the frame_no value and rtime values are updated. If the
727 frame_no is 0 then that particular frame_no and rtime value is not updated.
728 */
update_rrpd_rte_data(RRPD * in_rrpd)729 static void update_rrpd_rte_data(RRPD *in_rrpd)
730 {
731 if (in_rrpd->c2s)
732 update_rrpd_list_entry_req(in_rrpd);
733 else
734 update_rrpd_list_entry_rsp(in_rrpd);
735 }
736
is_dcerpc_context_zero(guint32 pkt_type)737 gboolean is_dcerpc_context_zero(guint32 pkt_type)
738 {
739 return (wmem_map_lookup(dcerpc_context_zero, GUINT_TO_POINTER(pkt_type)) != NULL);
740 }
741
is_dcerpc_req_pkt_type(guint32 pkt_type)742 gboolean is_dcerpc_req_pkt_type(guint32 pkt_type)
743 {
744 return (wmem_map_lookup(dcerpc_req_pkt_type, GUINT_TO_POINTER(pkt_type)) != NULL);
745 }
746
is_dcerpc_stream(guint32 stream_no)747 static gboolean is_dcerpc_stream(guint32 stream_no)
748 {
749 return (wmem_map_lookup(dcerpc_streams, GUINT_TO_POINTER(stream_no)) != NULL);
750 }
751
752 /*
753 This function initialises the global variables and populates the
754 [tcp|udp]_svc_ports tables with information from the preference settings
755 */
init_globals(void)756 static void init_globals(void)
757 {
758 if (!proto_is_protocol_enabled(find_protocol_by_id(proto_transum)))
759 return;
760
761 highest_tcp_stream_no = -1;
762 highest_udp_stream_no = -1;
763
764 /* Create and initialise some dynamic memory areas */
765 tcp_stream_exceptions = wmem_map_new(wmem_file_scope(), g_direct_hash, g_direct_equal);
766 detected_tcp_svc = wmem_map_new(wmem_file_scope(), g_direct_hash, g_direct_equal);
767 rrpd_list = wmem_list_new(wmem_file_scope());
768 temp_rsp_rrpd_list = wmem_list_new(wmem_file_scope());
769
770 /* Indicate what fields we're interested in. */
771 GArray *wanted_fields = g_array_sized_new(FALSE, FALSE, (guint)sizeof(int), HF_INTEREST_END_OF_LIST);
772 for (int i = 0; i < HF_INTEREST_END_OF_LIST; i++)
773 {
774 if (hf_of_interest[i].hf != -1)
775 g_array_append_val(wanted_fields, hf_of_interest[i].hf);
776 else
777 ws_warning("TRANSUM: unknown field %s", hf_of_interest[i].proto_name);
778 }
779 set_postdissector_wanted_hfids(transum_handle, wanted_fields);
780
781 preferences.tcp_svc_ports = wmem_map_new(wmem_file_scope(), g_direct_hash, g_direct_equal);
782 preferences.udp_svc_ports = wmem_map_new(wmem_file_scope(), g_direct_hash, g_direct_equal);
783
784 /* use the range values to populate the tcp_svc_ports list*/
785 for (guint i = 0; i < tcp_svc_port_range_values->nranges; i++)
786 {
787 for (guint32 j = tcp_svc_port_range_values->ranges[i].low; j <= tcp_svc_port_range_values->ranges[i].high; j++)
788 {
789 wmem_map_insert(preferences.tcp_svc_ports, GUINT_TO_POINTER(j), GUINT_TO_POINTER(RTE_CALC_GTCP));
790 }
791 }
792
793 /* use the range values to populate the udp_svc_ports list*/
794 for (guint i = 0; i < udp_svc_port_range_values->nranges; i++)
795 {
796 for (guint32 j = udp_svc_port_range_values->ranges[i].low; j <= udp_svc_port_range_values->ranges[i].high; j++)
797 {
798 wmem_map_insert(preferences.udp_svc_ports, GUINT_TO_POINTER(j), GUINT_TO_POINTER(RTE_CALC_GUDP));
799 }
800 }
801
802 /* create arrays to hold some DCE-RPC values */
803 dcerpc_context_zero = wmem_map_new(wmem_file_scope(), g_direct_hash, g_direct_equal);
804 dcerpc_req_pkt_type = wmem_map_new(wmem_file_scope(), g_direct_hash, g_direct_equal);
805 dcerpc_streams = wmem_map_new(wmem_file_scope(), g_direct_hash, g_direct_equal);
806 init_dcerpc_data();
807
808 wmem_map_insert(preferences.tcp_svc_ports, GUINT_TO_POINTER(445), GUINT_TO_POINTER(RTE_CALC_SMB2));
809 wmem_map_insert(preferences.udp_svc_ports, GUINT_TO_POINTER(53), GUINT_TO_POINTER(RTE_CALC_DNS));
810 }
811
812 /* Undo capture file-specific initializations. */
cleanup_globals(void)813 static void cleanup_globals(void)
814 {
815 /* Clear the list of wanted fields as it will be reinitialized. */
816 set_postdissector_wanted_hfids(transum_handle, NULL);
817 }
818
819 /* This function adds the RTE data to the tree. The summary ptr is currently
820 not used but will be used for summariser information once this feature has
821 been ported from the LUA code. */
write_rte(RRPD * in_rrpd,tvbuff_t * tvb,packet_info * pinfo,proto_tree * tree,char * summary)822 static void write_rte(RRPD *in_rrpd, tvbuff_t *tvb, packet_info *pinfo, proto_tree *tree, char *summary)
823 {
824 nstime_t rte_art;
825 nstime_t rte_st;
826 nstime_t rte_reqspread;
827 nstime_t rte_rspspread;
828 proto_tree *rte_tree;
829 proto_item *pi;
830 wmem_strbuf_t *temp_string = wmem_strbuf_new(pinfo->pool, "");
831
832 if (in_rrpd->req_first_frame)
833 {
834 pi = proto_tree_add_item(tree, proto_transum, tvb, 0, -1, ENC_NA);
835 rte_tree = proto_item_add_subtree(pi, ett_transum);
836
837 nstime_delta(&rte_reqspread, &(in_rrpd->req_last_rtime), &(in_rrpd->req_first_rtime));
838 if (in_rrpd->rsp_first_frame)
839 {
840 /* calculate the RTE times */
841 nstime_delta(&rte_art, &(in_rrpd->rsp_last_rtime), &(in_rrpd->req_first_rtime));
842 nstime_delta(&rte_st, &(in_rrpd->rsp_first_rtime), &(in_rrpd->req_last_rtime));
843 nstime_delta(&rte_rspspread, &(in_rrpd->rsp_last_rtime), &(in_rrpd->rsp_first_rtime));
844
845 pi = proto_tree_add_string(rte_tree, hf_tsum_status, tvb, 0, 0, "OK");
846 }
847 else
848 {
849 pi = proto_tree_add_string(rte_tree, hf_tsum_status, tvb, 0, 0, "Response missing");
850 }
851 proto_item_set_generated(pi);
852
853
854 pi = proto_tree_add_uint(rte_tree, hf_tsum_req_first_seg, tvb, 0, 0, in_rrpd->req_first_frame);
855 proto_item_set_generated(pi);
856 pi = proto_tree_add_uint(rte_tree, hf_tsum_req_last_seg, tvb, 0, 0, in_rrpd->req_last_frame);
857 proto_item_set_generated(pi);
858
859 if (in_rrpd->rsp_first_frame)
860 {
861 pi = proto_tree_add_uint(rte_tree, hf_tsum_rsp_first_seg, tvb, 0, 0, in_rrpd->rsp_first_frame);
862 proto_item_set_generated(pi);
863 pi = proto_tree_add_uint(rte_tree, hf_tsum_rsp_last_seg, tvb, 0, 0, in_rrpd->rsp_last_frame);
864 proto_item_set_generated(pi);
865
866 pi = proto_tree_add_time(rte_tree, hf_tsum_apdu_rsp_time, tvb, 0, 0, &rte_art);
867 proto_item_set_generated(pi);
868 pi = proto_tree_add_time(rte_tree, hf_tsum_service_time, tvb, 0, 0, &rte_st);
869 proto_item_set_generated(pi);
870 }
871
872 pi = proto_tree_add_time(rte_tree, hf_tsum_req_spread, tvb, 0, 0, &rte_reqspread);
873 proto_item_set_generated(pi);
874
875 if (in_rrpd->rsp_first_frame)
876 {
877 pi = proto_tree_add_time(rte_tree, hf_tsum_rsp_spread, tvb, 0, 0, &rte_rspspread);
878 proto_item_set_generated(pi);
879 }
880
881 if (in_rrpd->ip_proto == IP_PROTO_TCP)
882 wmem_strbuf_append_printf(temp_string, "tcp.stream==%d", in_rrpd->stream_no);
883 else if (in_rrpd->ip_proto == IP_PROTO_UDP)
884 wmem_strbuf_append_printf(temp_string, "udp.stream==%d", in_rrpd->stream_no);
885
886 if (in_rrpd->rsp_first_frame)
887 wmem_strbuf_append_printf(temp_string, " && frame.number>=%d && frame.number<=%d", in_rrpd->req_first_frame, in_rrpd->rsp_last_frame);
888 else
889 wmem_strbuf_append_printf(temp_string, " && frame.number>=%d && frame.number<=%d", in_rrpd->req_first_frame, in_rrpd->req_last_frame);
890
891 if (in_rrpd->calculation == RTE_CALC_GTCP)
892 wmem_strbuf_append_printf(temp_string, " && tcp.len>0");
893
894 pi = proto_tree_add_string(rte_tree, hf_tsum_clip_filter, tvb, 0, 0, wmem_strbuf_get_str(temp_string));
895 proto_item_set_generated(pi);
896
897 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"));
898 proto_item_set_generated(pi);
899
900 if (in_rrpd->rsp_first_frame)
901 {
902 if (preferences.summarisers_enabled)
903 {
904 if (summary)
905 {
906 pi = proto_tree_add_string(tree, hf_tsum_summary, tvb, 0, 0, summary);
907 proto_item_set_generated(pi);
908 }
909 }
910 }
911
912 if (preferences.debug_enabled)
913 {
914 pi = proto_tree_add_uint(rte_tree, hf_tsum_req_search, tvb, 0, 0, in_rrpd->req_search_total);
915 proto_item_set_generated(pi);
916 pi = proto_tree_add_uint(rte_tree, hf_tsum_rsp_search, tvb, 0, 0, in_rrpd->rsp_search_total);
917 proto_item_set_generated(pi);
918 }
919 }
920 }
921
922 /*
923 This function sets initial values in the current_pkt structure and checks
924 the xxx_svc_port arrays to see if they contain a match for the source or
925 destination port. This function also adds tcp_svc_ports entries when it
926 discovers DCE-RPC traffic.
927
928 Returns the number of sub-packets to be processed.
929 */
set_proto_values(packet_info * pinfo,proto_tree * tree,PKT_INFO * pkt_info,PKT_INFO * subpackets)930 static void set_proto_values(packet_info *pinfo, proto_tree *tree, PKT_INFO* pkt_info, PKT_INFO* subpackets)
931 {
932 guint32 field_uint[MAX_RETURNED_ELEMENTS]; /* An extracted field array for unsigned integers */
933 size_t field_value_count; /* How many entries are there in the extracted field array */
934
935 pkt_info->frame_number = pinfo->fd->num; /* easy access to frame number */
936 pkt_info->relative_time = pinfo->rel_ts;
937
938 int number_sub_pkts_of_interest = 0; /* default */
939
940 if (pinfo->ptype == PT_TCP)
941 pkt_info->rrpd.ip_proto = IP_PROTO_TCP;
942 else if (pinfo->ptype == PT_UDP)
943 pkt_info->rrpd.ip_proto = IP_PROTO_UDP;
944
945 if (pkt_info->rrpd.ip_proto == IP_PROTO_TCP)
946 {
947 number_sub_pkts_of_interest = decode_gtcp(pinfo, tree, pkt_info);
948 /* decode_gtcp may return 0 but we need to keep processing because we
949 calculate RTE figures for all SYNs and also we may detect DCE-RPC later
950 (even though we don't currently have an entry in the tcp_svc_ports list). */
951
952 /* Optimisation code */
953 if (pkt_info->len || pkt_info->tcp_flags_syn)
954 {
955 if (pkt_info->ssl_content_type == 21) /* this is an SSL Alert */
956 {
957 pkt_info->pkt_of_interest = FALSE;
958 return;
959 }
960
961 if ((int)pkt_info->rrpd.stream_no > highest_tcp_stream_no && !pkt_info->rrpd.c2s)
962 {
963 /* first packet on the stream is s2c and so add to exception list */
964 if (wmem_map_lookup(tcp_stream_exceptions, GUINT_TO_POINTER(pkt_info->rrpd.stream_no)) == NULL)
965 wmem_map_insert(tcp_stream_exceptions, GUINT_TO_POINTER(pkt_info->rrpd.stream_no), GUINT_TO_POINTER(1));
966 }
967
968 if (wmem_map_lookup(tcp_stream_exceptions, GUINT_TO_POINTER(pkt_info->rrpd.stream_no)) != NULL)
969 {
970 if (pkt_info->rrpd.c2s)
971 wmem_map_remove(tcp_stream_exceptions, GUINT_TO_POINTER(pkt_info->rrpd.stream_no));
972 else
973 pkt_info->pkt_of_interest = FALSE;
974 }
975 }
976 /* End of Optimisation Code */
977
978 if (pkt_info->tcp_retran)
979 {
980 /* we may not want to continue with this packet if it's a retransmission */
981
982 /* If this is a server-side trace we need to ignore client-to-service TCP retransmissions
983 the rationale being that if we saw the original in the trace the service process saw it too */
984 if (pkt_info->rrpd.c2s && preferences.capture_position == CAPTURE_SERVICE)
985 {
986 pkt_info->pkt_of_interest = FALSE;
987 return;
988 }
989
990 /* If this is a client-side trace we need to ignore service-to-client TCP retransmissions
991 the rationale being that if we saw the original in the trace the client process saw it too */
992 else if (!pkt_info->rrpd.c2s && preferences.capture_position == CAPTURE_CLIENT)
993 {
994 pkt_info->pkt_of_interest = FALSE;
995 return;
996 }
997 }
998
999 /* We are not interested in TCP Keep-Alive */
1000 if (pkt_info->tcp_keep_alive)
1001 {
1002 pkt_info->pkt_of_interest = FALSE;
1003 return;
1004 }
1005
1006 if (pkt_info->len == 1)
1007 {
1008 if (preferences.orphan_ka_discard && pkt_info->tcp_flags_ack && pkt_info->rrpd.c2s)
1009 {
1010 pkt_info->pkt_of_interest = FALSE;
1011 return; /* It's a KEEP-ALIVE -> stop processing this packet */
1012 }
1013 }
1014
1015 /* check if SYN */
1016 if (pkt_info->tcp_flags_syn)
1017 number_sub_pkts_of_interest = decode_syn(pinfo, tree, pkt_info);
1018
1019 if (pkt_info->len > 0)
1020 {
1021 /* check if SMB2 */
1022 if (pkt_info->dstport == 445 || pkt_info->srcport == 445)
1023 number_sub_pkts_of_interest = decode_smb(pinfo, tree, pkt_info, subpackets);
1024
1025 else
1026 {
1027 /* check if DCE-RPC */
1028 /* We need to set RTE_CALC_DCERPC even when we don't have header info. */
1029 if (is_dcerpc_stream(pkt_info->rrpd.stream_no))
1030 {
1031 pkt_info->rrpd.calculation = RTE_CALC_DCERPC;
1032 pkt_info->rrpd.decode_based = TRUE;
1033 pkt_info->pkt_of_interest = TRUE;
1034 }
1035
1036 if (!extract_uint(tree, hf_of_interest[HF_INTEREST_DCERPC_VER].hf, field_uint, &field_value_count))
1037 {
1038 if (field_value_count)
1039 {
1040 if (pkt_info->rrpd.calculation != RTE_CALC_DCERPC)
1041 register_dcerpc_stream(pkt_info->rrpd.stream_no);
1042
1043 number_sub_pkts_of_interest = decode_dcerpc(pinfo, tree, pkt_info);
1044 }
1045 }
1046 }
1047 }
1048
1049 }
1050 else if (pkt_info->rrpd.ip_proto == IP_PROTO_UDP)
1051 {
1052 /* It's UDP */
1053 number_sub_pkts_of_interest = decode_gudp(pinfo, tree, pkt_info);
1054
1055 if (pkt_info->srcport == 53 || pkt_info->dstport == 53)
1056 number_sub_pkts_of_interest = decode_dns(pinfo, tree, pkt_info);
1057 }
1058
1059 /* Set appropriate RTE values in the sub-packets */
1060 for (int i = 0; (i < number_sub_pkts_of_interest) && (i < MAX_SUBPKTS_PER_PACKET); i++)
1061 {
1062 if (pkt_info->rrpd.c2s)
1063 {
1064 subpackets[i].rrpd.req_first_frame = pkt_info->frame_number;
1065 subpackets[i].rrpd.req_first_rtime = pkt_info->relative_time;
1066 subpackets[i].rrpd.req_last_frame = pkt_info->frame_number;
1067 subpackets[i].rrpd.req_last_rtime = pkt_info->relative_time;
1068
1069 subpackets[i].frame_number = pkt_info->frame_number; /* this acts as a switch later */
1070 }
1071 else
1072 {
1073 subpackets[i].rrpd.rsp_first_frame = pkt_info->frame_number;
1074 subpackets[i].rrpd.rsp_first_rtime = pkt_info->relative_time;
1075 subpackets[i].rrpd.rsp_last_frame = pkt_info->frame_number;
1076 subpackets[i].rrpd.rsp_last_rtime = pkt_info->relative_time;
1077
1078 subpackets[i].frame_number = pkt_info->frame_number; /* this acts as a switch later */
1079 }
1080 }
1081 }
1082
1083
1084 /*
1085 * This function is called for each packet
1086 * Wireshark scans all the packets once and then once again as they are displayed
1087 * The pinfo.visited boolean is set to FALSE; on the first scan
1088 */
dissect_transum(tvbuff_t * buffer,packet_info * pinfo,proto_tree * tree,void * data _U_)1089 static int dissect_transum(tvbuff_t *buffer, packet_info *pinfo, proto_tree *tree, void *data _U_)
1090 {
1091 /* if (there is RTE info associated with this packet we need to output it */
1092 if (PINFO_FD_VISITED(pinfo))
1093 {
1094 RRPD *rrpd = (RRPD*)wmem_map_lookup(output_rrpd, GUINT_TO_POINTER(pinfo->num));
1095
1096 if (rrpd)
1097 {
1098 if (tree)
1099 {
1100 /* Add the RTE data to the protocol decode tree if we output_flag is set */
1101 write_rte(rrpd, buffer, pinfo, tree, NULL);
1102 }
1103 }
1104 }
1105 else
1106 {
1107 PKT_INFO *sub_packet = wmem_alloc0_array(pinfo->pool, PKT_INFO, MAX_SUBPKTS_PER_PACKET);
1108
1109 set_proto_values(pinfo, tree, &sub_packet[0], sub_packet);
1110
1111 if (sub_packet[0].pkt_of_interest)
1112 {
1113 /* Loop to process each sub_packet and update the related RTE data */
1114 for (int i = 0; i < MAX_SUBPKTS_PER_PACKET; i++)
1115 {
1116 if (!sub_packet[i].frame_number)
1117 break;
1118
1119 update_rrpd_rte_data(&(sub_packet[i].rrpd));
1120 }
1121 }
1122 }
1123
1124 return 0;
1125 }
1126
1127 void
proto_register_transum(void)1128 proto_register_transum(void)
1129 {
1130 module_t *transum_module;
1131
1132 static hf_register_info hf[] = {
1133 { &hf_tsum_status,
1134 { "RTE Status", "transum.status",
1135 FT_STRING, BASE_NONE, NULL, 0x0,
1136 "Indication of completeness of the RTE information", HFILL } },
1137 #if 0
1138 { &hf_tsum_time_units,
1139 { "RTE Time Units", "transum.time_units",
1140 FT_STRING, BASE_NONE, NULL, 0x0,
1141 "Time units used (s, ms or us) for the RTE values", HFILL }
1142 },
1143 #endif
1144 { &hf_tsum_req_first_seg,
1145 { "Req First Seg", "transum.firstreq",
1146 FT_FRAMENUM, BASE_NONE, NULL, 0x0,
1147 "First Segment of an APDU Request", HFILL }
1148 },
1149
1150 { &hf_tsum_req_last_seg,
1151 { "Req Last Seg", "transum.lastreq",
1152 FT_FRAMENUM, BASE_NONE, NULL, 0x0,
1153 "Last Segment of an APDU Request", HFILL }
1154 },
1155
1156 { &hf_tsum_rsp_first_seg,
1157 { "Rsp First Seg", "transum.firstrsp",
1158 FT_FRAMENUM, BASE_NONE, NULL, 0x0,
1159 "First Segment of an APDU Response", HFILL }
1160 },
1161
1162 { &hf_tsum_rsp_last_seg,
1163 { "Rsp Last Seg", "transum.lastrsp",
1164 FT_FRAMENUM, BASE_NONE, NULL, 0x0,
1165 "Last Segment of an APDU Response", HFILL }
1166 },
1167
1168 { &hf_tsum_apdu_rsp_time,
1169 { "APDU Rsp Time", "transum.art",
1170 FT_RELATIVE_TIME, BASE_NONE, NULL, 0x0,
1171 "RTE APDU Response Time", HFILL }
1172 },
1173
1174 { &hf_tsum_service_time,
1175 { "Service Time", "transum.st",
1176 FT_RELATIVE_TIME, BASE_NONE, NULL, 0x0,
1177 "RTE Service Time", HFILL }
1178 },
1179
1180 { &hf_tsum_req_spread,
1181 { "Req Spread", "transum.reqspread",
1182 FT_RELATIVE_TIME, BASE_NONE, NULL, 0x0,
1183 "RTE Request Spread", HFILL }
1184 },
1185
1186 { &hf_tsum_rsp_spread,
1187 { "Rsp Spread", "transum.rspspread",
1188 FT_RELATIVE_TIME, BASE_NONE, NULL, 0x0,
1189 "RTE Response Spread", HFILL }
1190 },
1191
1192 { &hf_tsum_clip_filter,
1193 { "Trace clip filter", "transum.clip_filter",
1194 FT_STRING, BASE_NONE, NULL, 0x0,
1195 "Filter expression to select the APDU Request-Response pair", HFILL }
1196 },
1197
1198 { &hf_tsum_calculation,
1199 { "Calculation", "transum.calculation",
1200 FT_STRING, BASE_NONE, NULL, 0x0,
1201 "Basis of the RTE calculation", HFILL }
1202 },
1203
1204 { &hf_tsum_summary,
1205 { "Summary", "transum.summary",
1206 FT_STRING, BASE_NONE, NULL, 0x0,
1207 "Summarizer information", HFILL }
1208 },
1209
1210 { &hf_tsum_req_search,
1211 { "Req Search Count", "transum.req_search",
1212 FT_UINT32, BASE_DEC, NULL, 0x0,
1213 "rrpd_list search total for the request packets", HFILL }
1214 },
1215
1216 { &hf_tsum_rsp_search,
1217 { "Rsp Search Counts", "transum.rsp_search",
1218 FT_UINT32, BASE_DEC, NULL, 0x0,
1219 "rrpd_list search total for the response packets", HFILL }
1220 }
1221
1222 };
1223
1224 /* Setup protocol subtree array */
1225 static gint *ett[] = {
1226 &ett_transum,
1227 &ett_transum_header,
1228 &ett_transum_data
1229 };
1230
1231 proto_transum = proto_register_protocol("TRANSUM RTE Data", "TRANSUM", "transum");
1232
1233 /* Due to performance concerns of the dissector, it's disabled by default */
1234 proto_disable_by_default(proto_transum);
1235
1236
1237 /* Set User Preferences defaults */
1238 preferences.capture_position = TRACE_CAP_CLIENT;
1239 preferences.reassembly = TRUE;
1240
1241 range_convert_str(wmem_epan_scope(), &tcp_svc_port_range_values, "25, 80, 443, 1433", MAX_TCP_PORT);
1242 range_convert_str(wmem_epan_scope(), &udp_svc_port_range_values, "137-139", MAX_UDP_PORT);
1243
1244 preferences.orphan_ka_discard = FALSE;
1245 preferences.time_multiplier = RTE_TIME_SEC;
1246 preferences.rte_on_first_req = FALSE;
1247 preferences.rte_on_last_req = TRUE;
1248 preferences.rte_on_first_rsp = FALSE;
1249 preferences.rte_on_last_rsp = FALSE;
1250
1251 preferences.debug_enabled = FALSE;
1252
1253 /* no start registering stuff */
1254 proto_register_field_array(proto_transum, hf, array_length(hf));
1255 proto_register_subtree_array(ett, array_length(ett));
1256
1257 transum_module = prefs_register_protocol(proto_transum, NULL); /* ToDo: We need to rethink the NULL pointer so that a preference change causes a rescan */
1258
1259 /* Register the preferences */
1260 prefs_register_obsolete_preference(transum_module, "tsumenabled");
1261
1262 prefs_register_enum_preference(transum_module,
1263 "capture_position",
1264 "Capture position",
1265 "Position of the capture unit that produced this trace. This setting affects the way TRANSUM handles TCP Retransmissions. See the manual for details.",
1266 &preferences.capture_position,
1267 capture_position_vals,
1268 FALSE);
1269
1270 prefs_register_bool_preference(transum_module,
1271 "reassembly",
1272 "Subdissector reassembly enabled",
1273 "Set this to match to the TCP subdissector reassembly setting",
1274 &preferences.reassembly);
1275
1276 prefs_register_range_preference(transum_module,
1277 "tcp_port_ranges",
1278 "Output RTE data for these TCP service ports",
1279 "Add and remove ports numbers separated by commas\nRanges are supported e.g. 25,80,2000-3000,5432",
1280 &tcp_svc_port_range_values,
1281 65536);
1282
1283 prefs_register_range_preference(transum_module,
1284 "udp_port_ranges",
1285 "Output RTE data for these UDP service ports",
1286 "Add and remove ports numbers separated by commas\nRanges are supported e.g. 123,137-139,520-521,2049",
1287 &udp_svc_port_range_values,
1288 65536);
1289
1290 prefs_register_bool_preference(transum_module,
1291 "orphan_ka_discard",
1292 "Discard orphaned TCP Keep-Alives",
1293 "Set this to discard any packet in the direction client to service,\nwith a 1-byte payload of 0x00 and the ACK flag set",
1294 &preferences.orphan_ka_discard);
1295
1296 /* removed from this release
1297 prefs_register_enum_preference(transum_module,
1298 "time_multiplier",
1299 "Time units for RTE values",
1300 "Unit of time used for APDU Response Time, Service Time and Spread Time values.",
1301 &preferences.time_multiplier,
1302 time_multiplier_vals,
1303 FALSE);
1304 */
1305
1306 prefs_register_bool_preference(transum_module,
1307 "rte_on_first_req",
1308 "Add RTE data to the first request segment",
1309 "RTE data will be added to the first request packet",
1310 &preferences.rte_on_first_req);
1311
1312 prefs_register_bool_preference(transum_module,
1313 "rte_on_last_req",
1314 "Add RTE data to the last request segment",
1315 "RTE data will be added to the last request packet",
1316 &preferences.rte_on_last_req);
1317
1318 prefs_register_bool_preference(transum_module,
1319 "rte_on_first_rsp",
1320 "Add RTE data to the first response segment",
1321 "RTE data will be added to the first response packet",
1322 &preferences.rte_on_first_rsp);
1323
1324 prefs_register_bool_preference(transum_module,
1325 "rte_on_last_rsp",
1326 "Add RTE data to the last response segment",
1327 "RTE data will be added to the last response packet",
1328 &preferences.rte_on_last_rsp);
1329
1330 prefs_register_bool_preference(transum_module,
1331 "debug_enabled",
1332 "Enable debug info",
1333 "Set this only to troubleshoot problems",
1334 &preferences.debug_enabled);
1335
1336 transum_handle = register_dissector("transum", dissect_transum, proto_transum);
1337
1338 register_init_routine(init_globals);
1339 register_cleanup_routine(cleanup_globals);
1340
1341 register_postdissector(transum_handle);
1342
1343 output_rrpd = wmem_map_new_autoreset(wmem_epan_scope(), wmem_file_scope(), g_direct_hash, g_direct_equal);
1344 }
1345
proto_reg_handoff_transum(void)1346 void proto_reg_handoff_transum(void)
1347 {
1348 /* Get the field id for each field we will need */
1349 for (int i = 0; i < HF_INTEREST_END_OF_LIST; i++)
1350 {
1351 hf_of_interest[i].hf = proto_registrar_get_id_byname(hf_of_interest[i].proto_name);
1352 }
1353 }
1354
1355 /*
1356 * Editor modelines - https://www.wireshark.org/tools/modelines.html
1357 *
1358 * Local variables:
1359 * c-basic-offset: 4
1360 * tab-width: 8
1361 * indent-tabs-mode: nil
1362 * End:
1363 *
1364 * vi: set shiftwidth=4 tabstop=8 expandtab:
1365 * :indentSize=4:tabSize=8:noTabs=true:
1366 */
1367