regen pidl all: rm epan/dissectors/pidl/*-stamp; pushd epan/dissectors/pidl/ && make...
[wireshark-sm.git] / plugins / epan / transum / packet-transum.c
blob496e5f56c0cb0daa232072dbd36aa0b4a18c2b99
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
6 * Wireshark - Network traffic analyzer
7 * By Gerald Combs <gerald@wireshark.org>
8 * Copyright 1998 Gerald Combs
10 * SPDX-License-Identifier: GPL-2.0-or-later
13 /* ToDo: Test handling of multiple SMB2 messages within a packet */
14 /* ToDo: Rework the Summarizer code (future release) */
16 #include "config.h"
17 #define WS_LOG_DOMAIN "transum"
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>
29 void proto_register_transum(void);
30 void proto_reg_handoff_transum(void);
32 static dissector_handle_t transum_handle;
34 #define CAPTURE_CLIENT 0
35 #define CAPTURE_INTERMEDIATE 1
36 #define CAPTURE_SERVICE 2
38 #define RTE_TIME_SEC 1
39 #define RTE_TIME_MSEC 1000
40 #define RTE_TIME_USEC 1000000
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" },
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" },
60 { -1, "udp.srcport" },
61 { -1, "udp.dstport" },
62 { -1, "udp.stream" },
63 { -1, "udp.length" },
65 { -1, "tls.record.content_type" },
67 { -1, "tds.type" },
68 { -1, "tds.length" },
70 { -1, "smb.mid" },
72 { -1, "smb2.sesid" },
73 { -1, "smb2.msg_id" },
74 { -1, "smb2.cmd" },
76 { -1, "dcerpc.ver" },
77 { -1, "dcerpc.pkt_type" },
78 { -1, "dcerpc.cn_call_id" },
79 { -1, "dcerpc.cn_ctx_id" },
81 { -1, "dns.id"},
85 static range_t *tcp_svc_port_range_values;
87 static range_t *udp_svc_port_range_values;
89 TSUM_PREFERENCES preferences;
92 static wmem_map_t *detected_tcp_svc; /* this array is used to track services detected during the syn/syn-ack process */
94 static wmem_map_t *dcerpc_req_pkt_type; /* used to indicate if a DCE-RPC pkt_type is a request */
96 static wmem_map_t *dcerpc_streams; /* used to record TCP stream numbers that are carrying DCE-RPC data */
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
104 static wmem_map_t *dcerpc_context_zero;
107 The rrpd_list holds information about all of the APDU Request-Response Pairs seen in the trace.
109 static wmem_list_t *rrpd_list;
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.
116 static wmem_map_t *output_rrpd;
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.
125 static wmem_list_t *temp_rsp_rrpd_list; /* Reuse these for speed and efficient memory use - issue a warning if we run out */
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;
133 static int ett_transum;
134 static int ett_transum_header;
135 static int ett_transum_data;
137 static int proto_transum;
139 static int hf_tsum_status;
140 //static int hf_tsum_time_units;
141 static int hf_tsum_req_first_seg;
142 static int hf_tsum_req_last_seg;
143 static int hf_tsum_rsp_first_seg;
144 static int hf_tsum_rsp_last_seg;
145 static int hf_tsum_apdu_rsp_time;
146 static int hf_tsum_service_time;
147 static int hf_tsum_req_spread;
148 static int hf_tsum_rsp_spread;
149 static int hf_tsum_clip_filter;
150 static int hf_tsum_calculation;
151 static int hf_tsum_summary;
152 static int hf_tsum_req_search;
153 static int hf_tsum_rsp_search;
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}
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" },
170 { 0, NULL }
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 };*/
180 void add_detected_tcp_svc(uint16_t port)
182 wmem_map_insert(detected_tcp_svc, GUINT_TO_POINTER(port), GUINT_TO_POINTER(port));
186 static void init_dcerpc_data(void)
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));
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));
198 static void register_dcerpc_stream(uint32_t stream_no)
200 wmem_map_insert(dcerpc_streams, GUINT_TO_POINTER(stream_no), GUINT_TO_POINTER(1));
203 /* This function should be called before any change to RTE data. */
204 static void null_output_rrpd_entries(RRPD *in_rrpd)
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));
212 /* This function should be called after any change to RTE data. */
213 static void update_output_rrpd(RRPD *in_rrpd)
215 if (preferences.rte_on_first_req)
216 wmem_map_insert(output_rrpd, GUINT_TO_POINTER(in_rrpd->req_first_frame), in_rrpd);
218 if (preferences.rte_on_last_req)
219 wmem_map_insert(output_rrpd, GUINT_TO_POINTER(in_rrpd->req_last_frame), in_rrpd);
221 if (preferences.rte_on_first_rsp)
222 wmem_map_insert(output_rrpd, GUINT_TO_POINTER(in_rrpd->rsp_first_frame), in_rrpd);
224 if (preferences.rte_on_last_rsp)
225 wmem_map_insert(output_rrpd, GUINT_TO_POINTER(in_rrpd->rsp_last_frame), in_rrpd);
228 /* Return the index of the RRPD that has been appended */
229 static RRPD* append_to_rrpd_list(RRPD *in_rrpd)
231 RRPD *next_rrpd = (RRPD*)wmem_memdup(wmem_file_scope(), in_rrpd, sizeof(RRPD));
233 update_output_rrpd(next_rrpd);
235 wmem_list_append(rrpd_list, next_rrpd);
237 return next_rrpd;
240 static RRPD *find_latest_rrpd_dcerpc(RRPD *in_rrpd)
242 RRPD *rrpd;
243 wmem_list_frame_t* i;
245 for (i = wmem_list_tail(rrpd_list); i != NULL; i = wmem_list_frame_prev(i))
247 rrpd = (RRPD*)wmem_list_frame_data(i);
249 if (rrpd->calculation != RTE_CALC_DCERPC && rrpd->calculation != RTE_CALC_SYN)
250 continue;
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)
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;
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;
266 if (preferences.reassembly)
268 if (in_rrpd->c2s)
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;
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;
279 else /* The in_rrpd relates to a packet going s2c */
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. */
286 else /* we are not using reassembly */
288 if (in_rrpd->c2s)
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 */
295 return rrpd; /* add this packet to the matching stream */
298 else /* this packet is going s2c */
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;
305 } /* this is the end of the 5-tuple check */
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 */
313 return NULL;
316 static RRPD *find_latest_rrpd_dns(RRPD *in_rrpd)
318 RRPD *rrpd;
319 wmem_list_frame_t* i;
321 for (i = wmem_list_tail(rrpd_list); i != NULL; i = wmem_list_frame_prev(i))
323 rrpd = (RRPD*)wmem_list_frame_data(i);
325 if (rrpd->calculation != RTE_CALC_DNS)
326 continue;
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)
331 if (rrpd->session_id == in_rrpd->session_id && rrpd->msg_id == in_rrpd->msg_id)
333 if (in_rrpd->c2s && rrpd->rsp_first_frame)
334 return NULL; /* this is new */
335 else
336 return rrpd;
338 } /* this is the end of the 5-tuple check */
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 */
346 return NULL;
349 static RRPD *find_latest_rrpd_gtcp(RRPD *in_rrpd)
351 RRPD *rrpd;
352 wmem_list_frame_t* i;
354 for (i = wmem_list_tail(rrpd_list); i != NULL; i = wmem_list_frame_prev(i))
356 rrpd = (RRPD*)wmem_list_frame_data(i);
358 if (rrpd->calculation != RTE_CALC_GTCP && rrpd->calculation != RTE_CALC_SYN)
359 continue;
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)
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 */
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 */
376 return NULL;
379 static RRPD *find_latest_rrpd_gudp(RRPD *in_rrpd)
381 RRPD *rrpd;
382 wmem_list_frame_t* i;
384 for (i = wmem_list_tail(rrpd_list); i != NULL; i = wmem_list_frame_prev(i))
386 rrpd = (RRPD*)wmem_list_frame_data(i);
388 if (rrpd->calculation != RTE_CALC_GUDP)
389 continue;
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)
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 */
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 */
406 return NULL;
409 static RRPD *find_latest_rrpd_smb2(RRPD *in_rrpd)
411 RRPD *rrpd;
412 wmem_list_frame_t* i;
414 for (i = wmem_list_tail(rrpd_list); i != NULL; i = wmem_list_frame_prev(i))
416 rrpd = (RRPD*)wmem_list_frame_data(i);
418 if (rrpd->calculation != RTE_CALC_SMB2 && rrpd->calculation != RTE_CALC_SYN)
419 continue;
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)
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;
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;
435 if (preferences.reassembly)
437 if (in_rrpd->c2s)
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;
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;
448 else /* The in_rrpd relates to a packet going s2c */
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. */
455 else /* we are not using reassembly */
457 if (in_rrpd->c2s)
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 */
464 return rrpd; /* add this packet to the matching stream */
467 else /* this packet is going s2c */
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;
474 } /* this is the end of the 5-tuple check */
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 */
482 return NULL;
485 static RRPD *find_latest_rrpd_syn(RRPD *in_rrpd)
487 RRPD *rrpd;
488 wmem_list_frame_t* i;
490 for (i = wmem_list_tail(rrpd_list); i != NULL; i = wmem_list_frame_prev(i))
492 rrpd = (RRPD*)wmem_list_frame_data(i);
494 if (rrpd->calculation != RTE_CALC_SYN)
495 continue;
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)
500 return rrpd;
501 } /* this is the end of the 5-tuple check */
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 */
509 return NULL;
512 static RRPD *find_latest_rrpd(RRPD *in_rrpd)
514 /* Optimisation Code */
515 if (in_rrpd->ip_proto == IP_PROTO_TCP && (int)in_rrpd->stream_no > highest_tcp_stream_no)
517 highest_tcp_stream_no = in_rrpd->stream_no;
518 return NULL;
520 else if (in_rrpd->ip_proto == IP_PROTO_UDP && (int)in_rrpd->stream_no > highest_udp_stream_no)
522 highest_udp_stream_no = in_rrpd->stream_no;
523 return NULL;
525 /* End of Optimisation Code */
527 switch (in_rrpd->calculation)
529 case RTE_CALC_DCERPC:
530 return find_latest_rrpd_dcerpc(in_rrpd);
532 case RTE_CALC_DNS:
533 return find_latest_rrpd_dns(in_rrpd);
535 case RTE_CALC_GTCP:
536 return find_latest_rrpd_gtcp(in_rrpd);
538 case RTE_CALC_GUDP:
539 return find_latest_rrpd_gudp(in_rrpd);
541 case RTE_CALC_SMB2:
542 return find_latest_rrpd_smb2(in_rrpd);
544 case RTE_CALC_SYN:
545 return find_latest_rrpd_syn(in_rrpd);
548 return NULL;
551 static void update_rrpd_list_entry(RRPD *match, RRPD *in_rrpd)
553 null_output_rrpd_entries(match);
555 if (preferences.debug_enabled)
557 match->req_search_total += in_rrpd->req_search_total;
558 match->rsp_search_total += in_rrpd->rsp_search_total;
561 if (in_rrpd->c2s)
563 match->req_last_frame = in_rrpd->req_last_frame;
564 match->req_last_rtime = in_rrpd->req_last_rtime;
565 if (in_rrpd->msg_id)
567 match->session_id = in_rrpd->session_id;
568 match->msg_id = in_rrpd->msg_id;
571 else
573 if (!match->rsp_first_frame)
575 match->rsp_first_frame = in_rrpd->rsp_first_frame;
576 match->rsp_first_rtime = in_rrpd->rsp_first_rtime;
578 match->rsp_last_frame = in_rrpd->rsp_last_frame;
579 match->rsp_last_rtime = in_rrpd->rsp_last_rtime;
582 update_output_rrpd(match);
586 This function processes a sub-packet that is going from client-to-service.
588 static void update_rrpd_list_entry_req(RRPD *in_rrpd)
590 RRPD *match;
592 match = find_latest_rrpd(in_rrpd);
594 if (match != NULL)
595 update_rrpd_list_entry(match, in_rrpd);
596 else
597 append_to_rrpd_list(in_rrpd);
601 This function inserts an RRPD into the temp_rsp_rrpd_list. If this is
602 successful return a pointer to the entry, else return NULL.
604 static RRPD* insert_into_temp_rsp_rrpd_list(RRPD *in_rrpd)
606 RRPD *rrpd = (RRPD*)wmem_memdup(wmem_file_scope(), in_rrpd, sizeof(RRPD));
608 wmem_list_append(temp_rsp_rrpd_list, rrpd);
610 return rrpd;
613 static RRPD* find_temp_rsp_rrpd(RRPD *in_rrpd)
615 wmem_list_frame_t *i;
616 RRPD* rrpd;
618 for (i = wmem_list_head(temp_rsp_rrpd_list); i; i = wmem_list_frame_next(i))
620 rrpd = (RRPD*)wmem_list_frame_data(i);
621 if (rrpd->ip_proto == in_rrpd->ip_proto && rrpd->stream_no == in_rrpd->stream_no)
622 return rrpd;
625 return NULL;
628 static void update_temp_rsp_rrpd(RRPD *temp_list, RRPD *in_rrpd)
630 temp_list->rsp_last_frame = in_rrpd->rsp_last_frame;
631 temp_list->rsp_last_rtime = in_rrpd->rsp_last_rtime;
634 /* This function migrates an entry from the temp_rsp_rrpd_list to the main rrpd_list. */
635 static void migrate_temp_rsp_rrpd(RRPD *main_list, RRPD *temp_list)
637 update_rrpd_list_entry(main_list, temp_list);
639 wmem_list_remove(temp_rsp_rrpd_list, temp_list);
642 static void update_rrpd_list_entry_rsp(RRPD *in_rrpd)
644 RRPD *match, *temp_list;
646 if (in_rrpd->decode_based)
648 if (preferences.reassembly)
650 if (in_rrpd->msg_id)
652 /* If we have a msg_id in the input RRPD we must have header information. */
653 temp_list = find_temp_rsp_rrpd(in_rrpd);
655 if (temp_list != NULL)
657 update_temp_rsp_rrpd(temp_list, in_rrpd);
659 /* Migrate the temp_rsp_rrpd_list entry to the main rrpd_list */
660 match = find_latest_rrpd(in_rrpd);
661 if (match != NULL)
662 migrate_temp_rsp_rrpd(match, temp_list);
664 else
666 match = find_latest_rrpd(in_rrpd);
667 /* There isn't an entry in the temp_rsp_rrpd_list so update the master rrpd_list entry */
668 if (match != NULL)
669 update_rrpd_list_entry(match, in_rrpd);
672 else
674 /* Update an existing entry to the temp_rsp_rrpd_list or add a new one. */
675 temp_list = find_temp_rsp_rrpd(in_rrpd);
677 if (temp_list != NULL)
678 update_temp_rsp_rrpd(temp_list, in_rrpd);
679 else
681 /* If this is a retransmission we need to add it to the last completed rrpd_list entry for this stream */
682 if (in_rrpd->is_retrans)
684 match = find_latest_rrpd(in_rrpd);
686 if (match != NULL)
687 update_rrpd_list_entry(match, in_rrpd);
688 else
689 insert_into_temp_rsp_rrpd_list(in_rrpd);
691 else
692 /* As it's not a retransmission, just create a new entry on the temp list */
693 insert_into_temp_rsp_rrpd_list(in_rrpd);
697 else
699 /* Reassembly isn't set and so just go ahead and use the list function */
700 match = find_latest_rrpd(in_rrpd);
701 if (match != NULL)
702 update_rrpd_list_entry(match, in_rrpd);
705 else
707 /* if this isn't decode_based then just go ahead and update the RTE data */
708 match = find_latest_rrpd(in_rrpd);
709 if (match != NULL)
710 update_rrpd_list_entry(match, in_rrpd);
713 return;
718 This function updates the RTE data of an RRPD on the rrpd_list. The
719 frame_no values in the input RRPD double up as a mask. If the frame_no
720 is > 0 then the frame_no value and rtime values are updated. If the
721 frame_no is 0 then that particular frame_no and rtime value is not updated.
723 static void update_rrpd_rte_data(RRPD *in_rrpd)
725 if (in_rrpd->c2s)
726 update_rrpd_list_entry_req(in_rrpd);
727 else
728 update_rrpd_list_entry_rsp(in_rrpd);
731 bool is_dcerpc_context_zero(uint32_t pkt_type)
733 return (wmem_map_lookup(dcerpc_context_zero, GUINT_TO_POINTER(pkt_type)) != NULL);
736 bool is_dcerpc_req_pkt_type(uint32_t pkt_type)
738 return (wmem_map_lookup(dcerpc_req_pkt_type, GUINT_TO_POINTER(pkt_type)) != NULL);
741 static bool is_dcerpc_stream(uint32_t stream_no)
743 return (wmem_map_lookup(dcerpc_streams, GUINT_TO_POINTER(stream_no)) != NULL);
747 This function initialises the global variables and populates the
748 [tcp|udp]_svc_ports tables with information from the preference settings
750 static void init_globals(void)
752 if (!proto_is_protocol_enabled(find_protocol_by_id(proto_transum)))
753 return;
755 highest_tcp_stream_no = -1;
756 highest_udp_stream_no = -1;
758 /* Create and initialise some dynamic memory areas */
759 tcp_stream_exceptions = wmem_map_new(wmem_file_scope(), g_direct_hash, g_direct_equal);
760 detected_tcp_svc = wmem_map_new(wmem_file_scope(), g_direct_hash, g_direct_equal);
761 rrpd_list = wmem_list_new(wmem_file_scope());
762 temp_rsp_rrpd_list = wmem_list_new(wmem_file_scope());
764 /* Indicate what fields we're interested in. */
765 GArray *wanted_fields = g_array_sized_new(false, false, (unsigned)sizeof(int), HF_INTEREST_END_OF_LIST);
766 for (int i = 0; i < HF_INTEREST_END_OF_LIST; i++)
768 if (hf_of_interest[i].hf != -1)
769 g_array_append_val(wanted_fields, hf_of_interest[i].hf);
770 else
771 ws_warning("TRANSUM: unknown field %s", hf_of_interest[i].proto_name);
773 set_postdissector_wanted_hfids(transum_handle, wanted_fields);
775 preferences.tcp_svc_ports = wmem_map_new(wmem_file_scope(), g_direct_hash, g_direct_equal);
776 preferences.udp_svc_ports = wmem_map_new(wmem_file_scope(), g_direct_hash, g_direct_equal);
778 /* use the range values to populate the tcp_svc_ports list*/
779 for (unsigned i = 0; i < tcp_svc_port_range_values->nranges; i++)
781 for (uint32_t j = tcp_svc_port_range_values->ranges[i].low; j <= tcp_svc_port_range_values->ranges[i].high; j++)
783 wmem_map_insert(preferences.tcp_svc_ports, GUINT_TO_POINTER(j), GUINT_TO_POINTER(RTE_CALC_GTCP));
787 /* use the range values to populate the udp_svc_ports list*/
788 for (unsigned i = 0; i < udp_svc_port_range_values->nranges; i++)
790 for (uint32_t j = udp_svc_port_range_values->ranges[i].low; j <= udp_svc_port_range_values->ranges[i].high; j++)
792 wmem_map_insert(preferences.udp_svc_ports, GUINT_TO_POINTER(j), GUINT_TO_POINTER(RTE_CALC_GUDP));
796 /* create arrays to hold some DCE-RPC values */
797 dcerpc_context_zero = wmem_map_new(wmem_file_scope(), g_direct_hash, g_direct_equal);
798 dcerpc_req_pkt_type = wmem_map_new(wmem_file_scope(), g_direct_hash, g_direct_equal);
799 dcerpc_streams = wmem_map_new(wmem_file_scope(), g_direct_hash, g_direct_equal);
800 init_dcerpc_data();
802 wmem_map_insert(preferences.tcp_svc_ports, GUINT_TO_POINTER(445), GUINT_TO_POINTER(RTE_CALC_SMB2));
803 wmem_map_insert(preferences.udp_svc_ports, GUINT_TO_POINTER(53), GUINT_TO_POINTER(RTE_CALC_DNS));
806 /* Undo capture file-specific initializations. */
807 static void cleanup_globals(void)
809 /* Clear the list of wanted fields as it will be reinitialized. */
810 set_postdissector_wanted_hfids(transum_handle, NULL);
813 /* This function adds the RTE data to the tree. The summary ptr is currently
814 not used but will be used for summariser information once this feature has
815 been ported from the Lua code. */
816 static void write_rte(RRPD *in_rrpd, tvbuff_t *tvb, packet_info *pinfo, proto_tree *tree, char *summary)
818 nstime_t rte_art;
819 nstime_t rte_st;
820 nstime_t rte_reqspread;
821 nstime_t rte_rspspread;
822 proto_tree *rte_tree;
823 proto_item *pi;
824 wmem_strbuf_t *temp_string = wmem_strbuf_new(pinfo->pool, "");
826 if (in_rrpd->req_first_frame)
828 pi = proto_tree_add_item(tree, proto_transum, tvb, 0, 0, ENC_NA);
829 rte_tree = proto_item_add_subtree(pi, ett_transum);
831 nstime_delta(&rte_reqspread, &(in_rrpd->req_last_rtime), &(in_rrpd->req_first_rtime));
832 if (in_rrpd->rsp_first_frame)
834 /* calculate the RTE times */
835 nstime_delta(&rte_art, &(in_rrpd->rsp_last_rtime), &(in_rrpd->req_first_rtime));
836 nstime_delta(&rte_st, &(in_rrpd->rsp_first_rtime), &(in_rrpd->req_last_rtime));
837 nstime_delta(&rte_rspspread, &(in_rrpd->rsp_last_rtime), &(in_rrpd->rsp_first_rtime));
839 pi = proto_tree_add_string(rte_tree, hf_tsum_status, tvb, 0, 0, "OK");
841 else
843 pi = proto_tree_add_string(rte_tree, hf_tsum_status, tvb, 0, 0, "Response missing");
845 proto_item_set_generated(pi);
848 pi = proto_tree_add_uint(rte_tree, hf_tsum_req_first_seg, tvb, 0, 0, in_rrpd->req_first_frame);
849 proto_item_set_generated(pi);
850 pi = proto_tree_add_uint(rte_tree, hf_tsum_req_last_seg, tvb, 0, 0, in_rrpd->req_last_frame);
851 proto_item_set_generated(pi);
853 if (in_rrpd->rsp_first_frame)
855 pi = proto_tree_add_uint(rte_tree, hf_tsum_rsp_first_seg, tvb, 0, 0, in_rrpd->rsp_first_frame);
856 proto_item_set_generated(pi);
857 pi = proto_tree_add_uint(rte_tree, hf_tsum_rsp_last_seg, tvb, 0, 0, in_rrpd->rsp_last_frame);
858 proto_item_set_generated(pi);
860 pi = proto_tree_add_time(rte_tree, hf_tsum_apdu_rsp_time, tvb, 0, 0, &rte_art);
861 proto_item_set_generated(pi);
862 pi = proto_tree_add_time(rte_tree, hf_tsum_service_time, tvb, 0, 0, &rte_st);
863 proto_item_set_generated(pi);
866 pi = proto_tree_add_time(rte_tree, hf_tsum_req_spread, tvb, 0, 0, &rte_reqspread);
867 proto_item_set_generated(pi);
869 if (in_rrpd->rsp_first_frame)
871 pi = proto_tree_add_time(rte_tree, hf_tsum_rsp_spread, tvb, 0, 0, &rte_rspspread);
872 proto_item_set_generated(pi);
875 if (in_rrpd->ip_proto == IP_PROTO_TCP)
876 wmem_strbuf_append_printf(temp_string, "tcp.stream==%d", in_rrpd->stream_no);
877 else if (in_rrpd->ip_proto == IP_PROTO_UDP)
878 wmem_strbuf_append_printf(temp_string, "udp.stream==%d", in_rrpd->stream_no);
880 if (in_rrpd->rsp_first_frame)
881 wmem_strbuf_append_printf(temp_string, " && frame.number>=%d && frame.number<=%d", in_rrpd->req_first_frame, in_rrpd->rsp_last_frame);
882 else
883 wmem_strbuf_append_printf(temp_string, " && frame.number>=%d && frame.number<=%d", in_rrpd->req_first_frame, in_rrpd->req_last_frame);
885 if (in_rrpd->calculation == RTE_CALC_GTCP)
886 wmem_strbuf_append_printf(temp_string, " && tcp.len>0");
888 pi = proto_tree_add_string(rte_tree, hf_tsum_clip_filter, tvb, 0, 0, wmem_strbuf_get_str(temp_string));
889 proto_item_set_generated(pi);
891 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"));
892 proto_item_set_generated(pi);
894 if (in_rrpd->rsp_first_frame)
896 if (preferences.summarisers_enabled)
898 if (summary)
900 pi = proto_tree_add_string(tree, hf_tsum_summary, tvb, 0, 0, summary);
901 proto_item_set_generated(pi);
906 if (preferences.debug_enabled)
908 pi = proto_tree_add_uint(rte_tree, hf_tsum_req_search, tvb, 0, 0, in_rrpd->req_search_total);
909 proto_item_set_generated(pi);
910 pi = proto_tree_add_uint(rte_tree, hf_tsum_rsp_search, tvb, 0, 0, in_rrpd->rsp_search_total);
911 proto_item_set_generated(pi);
917 This function sets initial values in the current_pkt structure and checks
918 the xxx_svc_port arrays to see if they contain a match for the source or
919 destination port. This function also adds tcp_svc_ports entries when it
920 discovers DCE-RPC traffic.
922 Returns the number of sub-packets to be processed.
924 static void set_proto_values(packet_info *pinfo, proto_tree *tree, PKT_INFO* pkt_info, PKT_INFO* subpackets)
926 uint32_t field_uint[MAX_RETURNED_ELEMENTS]; /* An extracted field array for unsigned integers */
927 size_t field_value_count; /* How many entries are there in the extracted field array */
929 pkt_info->frame_number = pinfo->fd->num; /* easy access to frame number */
930 pkt_info->relative_time = pinfo->rel_ts;
932 int number_sub_pkts_of_interest = 0; /* default */
934 if (pinfo->ptype == PT_TCP)
935 pkt_info->rrpd.ip_proto = IP_PROTO_TCP;
936 else if (pinfo->ptype == PT_UDP)
937 pkt_info->rrpd.ip_proto = IP_PROTO_UDP;
939 if (pkt_info->rrpd.ip_proto == IP_PROTO_TCP)
941 number_sub_pkts_of_interest = decode_gtcp(pinfo, tree, pkt_info);
942 /* decode_gtcp may return 0 but we need to keep processing because we
943 calculate RTE figures for all SYNs and also we may detect DCE-RPC later
944 (even though we don't currently have an entry in the tcp_svc_ports list). */
946 /* Optimisation code */
947 if (pkt_info->len || pkt_info->tcp_flags_syn)
949 if (pkt_info->ssl_content_type == 21) /* this is an SSL Alert */
951 pkt_info->pkt_of_interest = false;
952 return;
955 if ((int)pkt_info->rrpd.stream_no > highest_tcp_stream_no && !pkt_info->rrpd.c2s)
957 /* first packet on the stream is s2c and so add to exception list */
958 if (wmem_map_lookup(tcp_stream_exceptions, GUINT_TO_POINTER(pkt_info->rrpd.stream_no)) == NULL)
959 wmem_map_insert(tcp_stream_exceptions, GUINT_TO_POINTER(pkt_info->rrpd.stream_no), GUINT_TO_POINTER(1));
962 if (wmem_map_lookup(tcp_stream_exceptions, GUINT_TO_POINTER(pkt_info->rrpd.stream_no)) != NULL)
964 if (pkt_info->rrpd.c2s)
965 wmem_map_remove(tcp_stream_exceptions, GUINT_TO_POINTER(pkt_info->rrpd.stream_no));
966 else
967 pkt_info->pkt_of_interest = false;
970 /* End of Optimisation Code */
972 if (pkt_info->tcp_retran)
974 /* we may not want to continue with this packet if it's a retransmission */
976 /* If this is a server-side trace we need to ignore client-to-service TCP retransmissions
977 the rationale being that if we saw the original in the trace the service process saw it too */
978 if (pkt_info->rrpd.c2s && preferences.capture_position == CAPTURE_SERVICE)
980 pkt_info->pkt_of_interest = false;
981 return;
984 /* If this is a client-side trace we need to ignore service-to-client TCP retransmissions
985 the rationale being that if we saw the original in the trace the client process saw it too */
986 else if (!pkt_info->rrpd.c2s && preferences.capture_position == CAPTURE_CLIENT)
988 pkt_info->pkt_of_interest = false;
989 return;
993 /* We are not interested in TCP Keep-Alive */
994 if (pkt_info->tcp_keep_alive)
996 pkt_info->pkt_of_interest = false;
997 return;
1000 if (pkt_info->len == 1)
1002 if (preferences.orphan_ka_discard && pkt_info->tcp_flags_ack && pkt_info->rrpd.c2s)
1004 pkt_info->pkt_of_interest = false;
1005 return; /* It's a KEEP-ALIVE -> stop processing this packet */
1009 /* check if SYN */
1010 if (pkt_info->tcp_flags_syn)
1011 number_sub_pkts_of_interest = decode_syn(pinfo, tree, pkt_info);
1013 if (pkt_info->len > 0)
1015 /* check if SMB2 */
1016 if (pkt_info->dstport == 445 || pkt_info->srcport == 445)
1017 number_sub_pkts_of_interest = decode_smb(pinfo, tree, pkt_info, subpackets);
1019 else
1021 /* check if DCE-RPC */
1022 /* We need to set RTE_CALC_DCERPC even when we don't have header info. */
1023 if (is_dcerpc_stream(pkt_info->rrpd.stream_no))
1025 pkt_info->rrpd.calculation = RTE_CALC_DCERPC;
1026 pkt_info->rrpd.decode_based = true;
1027 pkt_info->pkt_of_interest = true;
1030 if (!extract_uint(tree, hf_of_interest[HF_INTEREST_DCERPC_VER].hf, field_uint, &field_value_count))
1032 if (field_value_count)
1034 if (pkt_info->rrpd.calculation != RTE_CALC_DCERPC)
1035 register_dcerpc_stream(pkt_info->rrpd.stream_no);
1037 number_sub_pkts_of_interest = decode_dcerpc(pinfo, tree, pkt_info);
1044 else if (pkt_info->rrpd.ip_proto == IP_PROTO_UDP)
1046 /* It's UDP */
1047 number_sub_pkts_of_interest = decode_gudp(pinfo, tree, pkt_info);
1049 if (pkt_info->srcport == 53 || pkt_info->dstport == 53)
1050 number_sub_pkts_of_interest = decode_dns(pinfo, tree, pkt_info);
1053 /* Set appropriate RTE values in the sub-packets */
1054 for (int i = 0; (i < number_sub_pkts_of_interest) && (i < MAX_SUBPKTS_PER_PACKET); i++)
1056 if (pkt_info->rrpd.c2s)
1058 subpackets[i].rrpd.req_first_frame = pkt_info->frame_number;
1059 subpackets[i].rrpd.req_first_rtime = pkt_info->relative_time;
1060 subpackets[i].rrpd.req_last_frame = pkt_info->frame_number;
1061 subpackets[i].rrpd.req_last_rtime = pkt_info->relative_time;
1063 subpackets[i].frame_number = pkt_info->frame_number; /* this acts as a switch later */
1065 else
1067 subpackets[i].rrpd.rsp_first_frame = pkt_info->frame_number;
1068 subpackets[i].rrpd.rsp_first_rtime = pkt_info->relative_time;
1069 subpackets[i].rrpd.rsp_last_frame = pkt_info->frame_number;
1070 subpackets[i].rrpd.rsp_last_rtime = pkt_info->relative_time;
1072 subpackets[i].frame_number = pkt_info->frame_number; /* this acts as a switch later */
1079 * This function is called for each packet
1080 * Wireshark scans all the packets once and then once again as they are displayed
1081 * The pinfo.visited boolean is set to false; on the first scan
1083 static int dissect_transum(tvbuff_t *buffer, packet_info *pinfo, proto_tree *tree, void *data _U_)
1085 /* if (there is RTE info associated with this packet we need to output it */
1086 if (PINFO_FD_VISITED(pinfo))
1088 RRPD *rrpd = (RRPD*)wmem_map_lookup(output_rrpd, GUINT_TO_POINTER(pinfo->num));
1090 if (rrpd)
1092 if (tree)
1094 /* Add the RTE data to the protocol decode tree if we output_flag is set */
1095 write_rte(rrpd, buffer, pinfo, tree, NULL);
1099 else
1101 PKT_INFO *sub_packet = wmem_alloc0_array(pinfo->pool, PKT_INFO, MAX_SUBPKTS_PER_PACKET);
1103 set_proto_values(pinfo, tree, &sub_packet[0], sub_packet);
1105 if (sub_packet[0].pkt_of_interest)
1107 /* Loop to process each sub_packet and update the related RTE data */
1108 for (int i = 0; i < MAX_SUBPKTS_PER_PACKET; i++)
1110 if (!sub_packet[i].frame_number)
1111 break;
1113 update_rrpd_rte_data(&(sub_packet[i].rrpd));
1118 return 0;
1121 void
1122 proto_register_transum(void)
1124 module_t *transum_module;
1126 static hf_register_info hf[] = {
1127 { &hf_tsum_status,
1128 { "RTE Status", "transum.status",
1129 FT_STRING, BASE_NONE, NULL, 0x0,
1130 "Indication of completeness of the RTE information", HFILL } },
1131 #if 0
1132 { &hf_tsum_time_units,
1133 { "RTE Time Units", "transum.time_units",
1134 FT_STRING, BASE_NONE, NULL, 0x0,
1135 "Time units used (s, ms or us) for the RTE values", HFILL }
1137 #endif
1138 { &hf_tsum_req_first_seg,
1139 { "Req First Seg", "transum.firstreq",
1140 FT_FRAMENUM, BASE_NONE, NULL, 0x0,
1141 "First Segment of an APDU Request", HFILL }
1144 { &hf_tsum_req_last_seg,
1145 { "Req Last Seg", "transum.lastreq",
1146 FT_FRAMENUM, BASE_NONE, NULL, 0x0,
1147 "Last Segment of an APDU Request", HFILL }
1150 { &hf_tsum_rsp_first_seg,
1151 { "Rsp First Seg", "transum.firstrsp",
1152 FT_FRAMENUM, BASE_NONE, NULL, 0x0,
1153 "First Segment of an APDU Response", HFILL }
1156 { &hf_tsum_rsp_last_seg,
1157 { "Rsp Last Seg", "transum.lastrsp",
1158 FT_FRAMENUM, BASE_NONE, NULL, 0x0,
1159 "Last Segment of an APDU Response", HFILL }
1162 { &hf_tsum_apdu_rsp_time,
1163 { "APDU Rsp Time", "transum.art",
1164 FT_RELATIVE_TIME, BASE_NONE, NULL, 0x0,
1165 "RTE APDU Response Time", HFILL }
1168 { &hf_tsum_service_time,
1169 { "Service Time", "transum.st",
1170 FT_RELATIVE_TIME, BASE_NONE, NULL, 0x0,
1171 "RTE Service Time", HFILL }
1174 { &hf_tsum_req_spread,
1175 { "Req Spread", "transum.reqspread",
1176 FT_RELATIVE_TIME, BASE_NONE, NULL, 0x0,
1177 "RTE Request Spread", HFILL }
1180 { &hf_tsum_rsp_spread,
1181 { "Rsp Spread", "transum.rspspread",
1182 FT_RELATIVE_TIME, BASE_NONE, NULL, 0x0,
1183 "RTE Response Spread", HFILL }
1186 { &hf_tsum_clip_filter,
1187 { "Trace clip filter", "transum.clip_filter",
1188 FT_STRING, BASE_NONE, NULL, 0x0,
1189 "Filter expression to select the APDU Request-Response pair", HFILL }
1192 { &hf_tsum_calculation,
1193 { "Calculation", "transum.calculation",
1194 FT_STRING, BASE_NONE, NULL, 0x0,
1195 "Basis of the RTE calculation", HFILL }
1198 { &hf_tsum_summary,
1199 { "Summary", "transum.summary",
1200 FT_STRING, BASE_NONE, NULL, 0x0,
1201 "Summarizer information", HFILL }
1204 { &hf_tsum_req_search,
1205 { "Req Search Count", "transum.req_search",
1206 FT_UINT32, BASE_DEC, NULL, 0x0,
1207 "rrpd_list search total for the request packets", HFILL }
1210 { &hf_tsum_rsp_search,
1211 { "Rsp Search Counts", "transum.rsp_search",
1212 FT_UINT32, BASE_DEC, NULL, 0x0,
1213 "rrpd_list search total for the response packets", HFILL }
1218 /* Setup protocol subtree array */
1219 static int *ett[] = {
1220 &ett_transum,
1221 &ett_transum_header,
1222 &ett_transum_data
1225 proto_transum = proto_register_protocol("TRANSUM RTE Data", "TRANSUM", "transum");
1227 /* Due to performance concerns of the dissector, it's disabled by default */
1228 proto_disable_by_default(proto_transum);
1231 /* Set User Preferences defaults */
1232 preferences.capture_position = TRACE_CAP_CLIENT;
1233 preferences.reassembly = true;
1235 range_convert_str(wmem_epan_scope(), &tcp_svc_port_range_values, "25, 80, 443, 1433", MAX_TCP_PORT);
1236 range_convert_str(wmem_epan_scope(), &udp_svc_port_range_values, "137-139", MAX_UDP_PORT);
1238 preferences.orphan_ka_discard = false;
1239 preferences.time_multiplier = RTE_TIME_SEC;
1240 preferences.rte_on_first_req = false;
1241 preferences.rte_on_last_req = true;
1242 preferences.rte_on_first_rsp = false;
1243 preferences.rte_on_last_rsp = false;
1245 preferences.debug_enabled = false;
1247 /* no start registering stuff */
1248 proto_register_field_array(proto_transum, hf, array_length(hf));
1249 proto_register_subtree_array(ett, array_length(ett));
1251 transum_module = prefs_register_protocol(proto_transum, NULL); /* ToDo: We need to rethink the NULL pointer so that a preference change causes a rescan */
1253 /* Register the preferences */
1254 prefs_register_obsolete_preference(transum_module, "tsumenabled");
1256 prefs_register_enum_preference(transum_module,
1257 "capture_position",
1258 "Capture position",
1259 "Position of the capture unit that produced this trace. This setting affects the way TRANSUM handles TCP Retransmissions. See the manual for details.",
1260 &preferences.capture_position,
1261 capture_position_vals,
1262 false);
1264 prefs_register_bool_preference(transum_module,
1265 "reassembly",
1266 "Subdissector reassembly enabled",
1267 "Set this to match to the TCP subdissector reassembly setting",
1268 &preferences.reassembly);
1270 prefs_register_range_preference(transum_module,
1271 "tcp_port_ranges",
1272 "Output RTE data for these TCP service ports",
1273 "Add and remove ports numbers separated by commas\nRanges are supported e.g. 25,80,2000-3000,5432",
1274 &tcp_svc_port_range_values,
1275 65536);
1277 prefs_register_range_preference(transum_module,
1278 "udp_port_ranges",
1279 "Output RTE data for these UDP service ports",
1280 "Add and remove ports numbers separated by commas\nRanges are supported e.g. 123,137-139,520-521,2049",
1281 &udp_svc_port_range_values,
1282 65536);
1284 prefs_register_bool_preference(transum_module,
1285 "orphan_ka_discard",
1286 "Discard orphaned TCP Keep-Alives",
1287 "Set this to discard any packet in the direction client to service,\nwith a 1-byte payload of 0x00 and the ACK flag set",
1288 &preferences.orphan_ka_discard);
1290 /* removed from this release
1291 prefs_register_enum_preference(transum_module,
1292 "time_multiplier",
1293 "Time units for RTE values",
1294 "Unit of time used for APDU Response Time, Service Time and Spread Time values.",
1295 &preferences.time_multiplier,
1296 time_multiplier_vals,
1297 false);
1300 prefs_register_bool_preference(transum_module,
1301 "rte_on_first_req",
1302 "Add RTE data to the first request segment",
1303 "RTE data will be added to the first request packet",
1304 &preferences.rte_on_first_req);
1306 prefs_register_bool_preference(transum_module,
1307 "rte_on_last_req",
1308 "Add RTE data to the last request segment",
1309 "RTE data will be added to the last request packet",
1310 &preferences.rte_on_last_req);
1312 prefs_register_bool_preference(transum_module,
1313 "rte_on_first_rsp",
1314 "Add RTE data to the first response segment",
1315 "RTE data will be added to the first response packet",
1316 &preferences.rte_on_first_rsp);
1318 prefs_register_bool_preference(transum_module,
1319 "rte_on_last_rsp",
1320 "Add RTE data to the last response segment",
1321 "RTE data will be added to the last response packet",
1322 &preferences.rte_on_last_rsp);
1324 prefs_register_bool_preference(transum_module,
1325 "debug_enabled",
1326 "Enable debug info",
1327 "Set this only to troubleshoot problems",
1328 &preferences.debug_enabled);
1330 transum_handle = register_dissector("transum", dissect_transum, proto_transum);
1332 register_init_routine(init_globals);
1333 register_cleanup_routine(cleanup_globals);
1335 register_postdissector(transum_handle);
1337 output_rrpd = wmem_map_new_autoreset(wmem_epan_scope(), wmem_file_scope(), g_direct_hash, g_direct_equal);
1340 void proto_reg_handoff_transum(void)
1342 /* Get the field id for each field we will need */
1343 for (int i = 0; i < HF_INTEREST_END_OF_LIST; i++)
1345 hf_of_interest[i].hf = proto_registrar_get_id_byname(hf_of_interest[i].proto_name);
1350 * Editor modelines - https://www.wireshark.org/tools/modelines.html
1352 * Local variables:
1353 * c-basic-offset: 4
1354 * tab-width: 8
1355 * indent-tabs-mode: nil
1356 * End:
1358 * vi: set shiftwidth=4 tabstop=8 expandtab:
1359 * :indentSize=4:tabSize=8:noTabs=true: