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