3 * Routines for UDT packet dissection
4 * http://udt.sourceforge.net
7 * Copyright 2013 (c) chas williams <chas@cmf.nrl.navy.mil>
9 * Wireshark - Network traffic analyzer
10 * By Gerald Combs <gerald@wireshark.org>
11 * Copyright 1998 Gerald Combs
13 * Copied from packet-tftp.c
15 * SPDX-License-Identifier: GPL-2.0-or-later
20 #include <epan/packet.h>
21 #include <epan/conversation.h>
22 #include <epan/expert.h>
23 #include <epan/wmem_scopes.h>
26 * Per-conversation information
28 typedef struct _udt_conversation
{
34 * based on https://tools.ietf.org/html/draft-gg-udt-03
37 #define UDT_TYPE_DATA 0
38 #define UDT_TYPE_CONTROL 1
40 #define UDT_PACKET_TYPE_HANDSHAKE 0x0000
41 #define UDT_PACKET_TYPE_KEEPALIVE 0x0001
42 #define UDT_PACKET_TYPE_ACK 0x0002
43 #define UDT_PACKET_TYPE_NAK 0x0003
44 #define UDT_PACKET_TYPE_SHUTDOWN 0x0005
45 #define UDT_PACKET_TYPE_ACK2 0x0006
47 #define UDT_HANDSHAKE_TYPE_STREAM 1
48 #define UDT_HANDSHAKE_TYPE_DGRAM 2
50 #define UDT_CONTROL_OFFSET 16 /* Offset of control information field */
51 #define UDT_MAX_NAK_ENTRIES 8 /* max number of NAK entries displayed in summary */
52 #define UDT_MAX_NAK_LENGTH (UDT_CONTROL_OFFSET + UDT_MAX_NAK_ENTRIES*4)
54 void proto_register_udt(void);
55 void proto_reg_handoff_udt(void);
57 static const value_string udt_packet_types
[] = {
58 {UDT_PACKET_TYPE_HANDSHAKE
, "handshake"},
59 {UDT_PACKET_TYPE_KEEPALIVE
, "keepalive"},
60 {UDT_PACKET_TYPE_ACK
, "ack"},
61 {UDT_PACKET_TYPE_NAK
, "nak"},
62 {UDT_PACKET_TYPE_SHUTDOWN
, "shutdown"},
63 {UDT_PACKET_TYPE_ACK2
, "ack2"},
67 static const value_string udt_handshake_types
[] = {
68 {UDT_HANDSHAKE_TYPE_STREAM
, "STREAM"},
69 {UDT_HANDSHAKE_TYPE_DGRAM
, "DGRAM"},
73 static const value_string udt_types
[] = {
74 {UDT_TYPE_DATA
, "DATA"},
75 {UDT_TYPE_CONTROL
, "CONTROL"},
80 static int hf_udt_iscontrol
;
81 static int hf_udt_type
;
82 static int hf_udt_seqno
;
83 static int hf_udt_ack_seqno
;
84 static int hf_udt_ackno
;
85 static int hf_udt_msgno
;
86 static int hf_udt_msgno_first
;
87 static int hf_udt_msgno_last
;
88 static int hf_udt_msgno_inorder
;
89 static int hf_udt_timestamp
;
91 static int hf_udt_addinfo
;
92 static int hf_udt_rtt
;
93 static int hf_udt_rttvar
;
94 static int hf_udt_bufavail
;
95 static int hf_udt_rate
;
96 static int hf_udt_linkcap
;
97 static int hf_udt_handshake_version
;
98 static int hf_udt_handshake_type
;
99 static int hf_udt_handshake_isn
;
100 static int hf_udt_handshake_mtu
;
101 static int hf_udt_handshake_flow_window
;
102 static int hf_udt_handshake_reqtype
;
103 static int hf_udt_handshake_id
;
104 static int hf_udt_handshake_cookie
;
105 static int hf_udt_handshake_peerip
;
109 static expert_field ei_udt_nak_seqno
;
111 static dissector_handle_t udt_handle
;
113 static heur_dissector_list_t heur_subdissector_list
;
115 static int get_sqn(udt_conversation
*udt_conv
, uint32_t sqn
)
118 sqn
-= udt_conv
->isn
;
124 dissect_udt(tvbuff_t
*tvb
, packet_info
* pinfo
, proto_tree
*parent_tree
,
128 proto_item
*udt_item
;
129 int is_control
, type
;
131 conversation_t
*conv
;
132 udt_conversation
*udt_conv
;
133 heur_dtbl_entry_t
*hdtbl_entry
;
135 conv
= find_or_create_conversation(pinfo
);
136 udt_conv
= (udt_conversation
*)conversation_get_proto_data(conv
, proto_udt
);
138 col_set_str(pinfo
->cinfo
, COL_PROTOCOL
, "UDT");
139 col_clear(pinfo
->cinfo
, COL_INFO
);
141 is_control
= tvb_get_ntohl(tvb
, 0) & 0x80000000;
142 type
= (tvb_get_ntohl(tvb
, 0) >> 16) & 0x7fff;
145 const char *typestr
= val_to_str(type
, udt_packet_types
,
146 "Unknown Control Type (%x)");
148 case UDT_PACKET_TYPE_ACK
:
149 col_add_fstr(pinfo
->cinfo
, COL_INFO
, "UDT type: ack seqno: %u",
150 get_sqn(udt_conv
, tvb_get_ntohl(tvb
, 16)));
152 case UDT_PACKET_TYPE_ACK2
:
153 col_set_str(pinfo
->cinfo
, COL_INFO
, "UDT type: ack2");
155 case UDT_PACKET_TYPE_NAK
: {
156 wmem_strbuf_t
*nakstr
= wmem_strbuf_new(pinfo
->pool
, "");
157 unsigned max
= tvb_reported_length(tvb
);
158 if (max
> UDT_MAX_NAK_LENGTH
)
159 max
= UDT_MAX_NAK_LENGTH
;
161 for (i
= UDT_CONTROL_OFFSET
; i
<= (max
-4) ; i
= i
+ 4) {
162 uint32_t start
, finish
;
165 is_range
= tvb_get_ntohl(tvb
, i
) & 0x80000000;
166 start
= get_sqn(udt_conv
, tvb_get_ntohl(tvb
, i
) & 0x7fffffff);
170 // Message is truncated
173 finish
= get_sqn(udt_conv
, tvb_get_ntohl(tvb
, i
+ 4) & 0x7fffffff);
174 wmem_strbuf_append_printf(nakstr
, "%s%u-%u",
175 i
== UDT_CONTROL_OFFSET
? "":",",
179 wmem_strbuf_append_printf(nakstr
, "%s%u",
180 i
== UDT_CONTROL_OFFSET
? "":",",
185 // Add ellipsis if the list was too long
186 if (max
!= tvb_reported_length(tvb
))
187 wmem_strbuf_append(nakstr
, "...");
189 col_add_fstr(pinfo
->cinfo
, COL_INFO
, "UDT type: %s missing:%s",
190 typestr
, wmem_strbuf_get_str(nakstr
));
194 col_add_fstr(pinfo
->cinfo
, COL_INFO
, "UDT type: %s", typestr
);
198 col_add_fstr(pinfo
->cinfo
, COL_INFO
,
199 "UDT type: data seqno: %u msgno: %u",
200 get_sqn(udt_conv
, tvb_get_ntohl(tvb
, 0) & 0x7fffffff),
201 tvb_get_ntohl(tvb
, 4) & 0x1fffffff);
204 udt_item
= proto_tree_add_item(parent_tree
, proto_udt
, tvb
,
206 tree
= proto_item_add_subtree(udt_item
, ett_udt
);
208 proto_tree_add_item(tree
, hf_udt_iscontrol
, tvb
, 0, 4, ENC_BIG_ENDIAN
);
211 proto_tree_add_item(tree
, hf_udt_type
, tvb
, 0, 4,
214 case UDT_PACKET_TYPE_ACK
:
215 proto_tree_add_item(tree
, hf_udt_ackno
, tvb
, 4, 4,
218 case UDT_PACKET_TYPE_ACK2
:
219 proto_tree_add_item(tree
, hf_udt_ackno
, tvb
, 4, 4,
223 proto_tree_add_item(tree
, hf_udt_addinfo
, tvb
, 4, 4,
226 proto_tree_add_item(tree
, hf_udt_timestamp
, tvb
, 8, 4,
228 proto_tree_add_item(tree
, hf_udt_id
, tvb
, 12, 4,
233 case UDT_PACKET_TYPE_HANDSHAKE
:
235 proto_tree_add_item(tree
, hf_udt_handshake_version
, tvb
,
236 16, 4, ENC_BIG_ENDIAN
);
237 proto_tree_add_item(tree
, hf_udt_handshake_type
, tvb
,
238 20, 4, ENC_BIG_ENDIAN
);
239 proto_tree_add_item(tree
, hf_udt_handshake_isn
, tvb
,
240 24, 4, ENC_BIG_ENDIAN
);
241 proto_tree_add_item(tree
, hf_udt_handshake_mtu
, tvb
,
242 28, 4, ENC_BIG_ENDIAN
);
243 proto_tree_add_item(tree
, hf_udt_handshake_flow_window
, tvb
,
244 32, 4, ENC_BIG_ENDIAN
);
245 proto_tree_add_item(tree
, hf_udt_handshake_reqtype
, tvb
,
246 36, 4, ENC_BIG_ENDIAN
);
247 proto_tree_add_item(tree
, hf_udt_handshake_id
, tvb
,
248 40, 4, ENC_BIG_ENDIAN
);
249 proto_tree_add_item(tree
, hf_udt_handshake_cookie
, tvb
,
250 44, 4, ENC_BIG_ENDIAN
);
251 proto_tree_add_item(tree
, hf_udt_handshake_peerip
, tvb
,
253 proto_item_set_len(udt_item
, 64);
256 case UDT_PACKET_TYPE_ACK
:
258 int len
= tvb_reported_length(tvb
);
259 uint32_t real_sqn
= tvb_get_ntohl(tvb
, 16);
260 uint32_t sqn
= get_sqn(udt_conv
, real_sqn
);
262 proto_tree_add_uint_format_value(tree
, hf_udt_ack_seqno
, tvb
, 16, 4, real_sqn
,
263 "%d (relative) [%d]", sqn
, real_sqn
);
265 proto_tree_add_uint(tree
, hf_udt_ack_seqno
, tvb
, 16, 4, real_sqn
);
267 /* if not a light ack, decode the extended fields */
269 proto_item_set_len(udt_item
, 20);
271 proto_tree_add_item(tree
, hf_udt_rtt
, tvb
, 20, 4,
273 proto_tree_add_item(tree
, hf_udt_rttvar
, tvb
, 24, 4,
275 proto_tree_add_item(tree
, hf_udt_bufavail
, tvb
, 28, 4,
278 proto_tree_add_item(tree
, hf_udt_rate
, tvb
,
279 32, 4, ENC_BIG_ENDIAN
);
280 proto_tree_add_item(tree
, hf_udt_linkcap
, tvb
,
281 36, 4, ENC_BIG_ENDIAN
);
282 proto_item_set_len(udt_item
, 40);
284 proto_item_set_len(udt_item
, 32);
289 case UDT_PACKET_TYPE_NAK
:
290 for (i
= 16; i
<= (tvb_reported_length(tvb
)-4); i
= i
+ 4) {
291 uint32_t real_start
, real_finish
;
292 uint32_t start
, finish
;
295 is_range
= tvb_get_ntohl(tvb
, i
) & 0x80000000;
296 real_start
= tvb_get_ntohl(tvb
, i
) & 0x7fffffff;
297 start
= get_sqn(udt_conv
, real_start
);
300 if (i
> (tvb_reported_length(tvb
)-8)) {
301 // Message is truncated - bail
305 real_finish
= tvb_get_ntohl(tvb
, i
+ 4) & 0x7fffffff;
306 finish
= get_sqn(udt_conv
, real_finish
);
308 if (start
!= real_start
)
309 proto_tree_add_expert_format(tree
, pinfo
, &ei_udt_nak_seqno
,
311 "Missing Sequence Numbers: "
312 "%u-%u (relative) [%u-%u]",
313 start
, finish
, real_start
, real_finish
);
315 proto_tree_add_expert_format(tree
, pinfo
, &ei_udt_nak_seqno
,
317 "Missing Sequence Numbers: %u-%u",
318 real_start
, real_finish
);
321 if (start
!= real_start
)
322 proto_tree_add_expert_format(tree
, pinfo
, &ei_udt_nak_seqno
,
324 "Missing Sequence Number : %u (relative) [%u]",
327 proto_tree_add_expert_format(tree
, pinfo
, &ei_udt_nak_seqno
,
329 "Missing Sequence Number : %u", real_start
);
333 proto_item_set_len(udt_item
, tvb_reported_length(tvb
));
337 /* otherwise, a data packet */
341 uint32_t real_seqno
= tvb_get_ntohl(tvb
, 0);
342 uint32_t seqno
= get_sqn(udt_conv
, real_seqno
);
343 if (seqno
!= real_seqno
)
344 proto_tree_add_uint_format_value(tree
, hf_udt_seqno
, tvb
, 0, 4, real_seqno
,
345 "%u (relative) [%u]", seqno
, real_seqno
);
347 proto_tree_add_uint(tree
, hf_udt_seqno
, tvb
, 0, 4, real_seqno
);
348 proto_tree_add_item(tree
, hf_udt_msgno_first
, tvb
, 4, 4,
350 proto_tree_add_item(tree
, hf_udt_msgno_last
, tvb
, 4, 4,
352 proto_tree_add_item(tree
, hf_udt_msgno_inorder
, tvb
, 4, 4,
354 proto_tree_add_item(tree
, hf_udt_msgno
, tvb
, 4, 4,
356 proto_tree_add_item(tree
, hf_udt_timestamp
, tvb
, 8, 4,
358 proto_tree_add_item(tree
, hf_udt_id
, tvb
, 12, 4,
363 next_tvb
= tvb_new_subset_remaining(tvb
, 16);
365 // Try heuristic dissectors first...
366 if (!dissector_try_heuristic(heur_subdissector_list
, next_tvb
, pinfo
, parent_tree
, &hdtbl_entry
, NULL
))
367 call_data_dissector(next_tvb
, pinfo
, parent_tree
);
370 return tvb_reported_length(tvb
);
374 dissect_udt_heur(tvbuff_t
*tvb
, packet_info
*pinfo
, proto_tree
*tree
, void *data
, bool is_dtls
)
376 conversation_t
*conv
;
377 udt_conversation
*udt_conv
;
379 conv
= find_or_create_conversation(pinfo
);
380 udt_conv
= (udt_conversation
*)conversation_get_proto_data(conv
, proto_udt
);
383 // Already identified conversation as UDT - BUT we might have been called from
384 // the other dissector.
385 if (is_dtls
!= udt_conv
->is_dtls
)
387 dissect_udt(tvb
, pinfo
, tree
, data
);
389 // Check if this is UDT...
391 /* Must have at least 24 captured bytes for heuristic check */
392 if (tvb_captured_length(tvb
) < 24)
395 /* detect handshake control packet */
396 if (tvb_get_ntohl(tvb
, 0) != (0x80000000 | UDT_PACKET_TYPE_HANDSHAKE
))
399 /* must be version 4 */
400 if ((tvb_get_ntohl(tvb
, 16) != 4))
403 /* must be datagram or stream */
404 if ((tvb_get_ntohl(tvb
, 20) != UDT_HANDSHAKE_TYPE_DGRAM
)
405 && (tvb_get_ntohl(tvb
, 20) != UDT_HANDSHAKE_TYPE_STREAM
))
408 /* This looks like UDT! */
409 udt_conv
= wmem_new0(wmem_file_scope(), udt_conversation
);
410 udt_conv
->is_dtls
= is_dtls
;
411 /* Save initial sequence number if sufficient bytes were captured */
412 if (tvb_captured_length(tvb
) >= 28)
413 udt_conv
->isn
= tvb_get_ntohl(tvb
, 24);
414 conversation_add_proto_data(conv
, proto_udt
, udt_conv
);
415 // DTLS should remain the dissector of record for encrypted conversations
417 conversation_set_dissector(conv
, udt_handle
);
419 dissect_udt(tvb
, pinfo
, tree
, data
);
425 dissect_udt_heur_udp(tvbuff_t
*tvb
, packet_info
*pinfo
, proto_tree
*tree
, void *data
)
427 return dissect_udt_heur(tvb
, pinfo
, tree
, data
, false /* Not DTLS */);
431 dissect_udt_heur_dtls(tvbuff_t
*tvb
, packet_info
*pinfo
, proto_tree
*tree
, void *data
)
433 return dissect_udt_heur(tvb
, pinfo
, tree
, data
, true /* Is DTLS */);
436 void proto_register_udt(void)
438 expert_module_t
*expert_udt
;
440 static hf_register_info hf
[] = {
441 {&hf_udt_iscontrol
, {
442 "Type", "udt.iscontrol",
444 VALS(udt_types
), 0x80000000, NULL
, HFILL
}},
449 VALS(udt_packet_types
), 0x7fff0000, NULL
, HFILL
}},
452 "Sequence Number", "udt.seqno",
454 NULL
, 0x7fffffff, NULL
, HFILL
}},
457 "Additional Info", "udt.addinfo",
459 NULL
, 0, NULL
, HFILL
}},
462 "Message Number", "udt.msgno",
464 NULL
, 0x1fffffff, NULL
, HFILL
}},
466 {&hf_udt_msgno_first
, {
467 "First Indicator", "udt.msg.first",
469 NULL
, 0x80000000, NULL
, HFILL
}},
471 {&hf_udt_msgno_last
, {
472 "Last Indicator", "udt.msg.last",
474 NULL
, 0x40000000, NULL
, HFILL
}},
476 {&hf_udt_msgno_inorder
, {
477 "In-Order Indicator", "udt.msg.order",
479 NULL
, 0x20000000, NULL
, HFILL
}},
481 {&hf_udt_timestamp
, {
482 "Timestamp", "udt.timestamp",
484 NULL
, 0, NULL
, HFILL
}},
489 NULL
, 0, NULL
, HFILL
}},
491 {&hf_udt_ack_seqno
, {
492 "Ack Sequence Number", "udt.ack_seqno",
494 NULL
, 0, NULL
, HFILL
}},
497 "Ack Number", "udt.ackno",
499 NULL
, 0, NULL
, HFILL
}},
502 "RTT (microseconds)", "udt.rtt",
504 NULL
, 0, NULL
, HFILL
}},
507 "RTT Variance (microseconds)", "udt.rttvar",
509 NULL
, 0, NULL
, HFILL
}},
512 "Buffer Available (packets)", "udt.buf",
514 NULL
, 0, NULL
, HFILL
}},
517 "Rate (packets/second)", "udt.rate",
519 NULL
, 0, NULL
, HFILL
}},
522 "Link Capacity (packets/second)", "udt.linkcap",
524 NULL
, 0, NULL
, HFILL
}},
526 {&hf_udt_handshake_version
, {
527 "Version", "udt.hs.version",
529 NULL
, 0, NULL
, HFILL
}},
531 {&hf_udt_handshake_type
, {
532 "Type", "udt.hs.type",
534 VALS(udt_handshake_types
), 0, NULL
,
537 {&hf_udt_handshake_isn
, {
538 "Initial Sequence Number", "udt.hs.isn",
540 NULL
, 0, NULL
, HFILL
}},
542 {&hf_udt_handshake_mtu
, {
545 NULL
, 0, NULL
, HFILL
}},
547 {&hf_udt_handshake_flow_window
, {
548 "Flow Window", "udt.hs.flow_window",
550 NULL
, 0, NULL
, HFILL
}},
552 {&hf_udt_handshake_reqtype
, {
553 "Requested Type", "udt.hs.reqtype",
555 NULL
, 0, NULL
, HFILL
}},
557 {&hf_udt_handshake_id
, {
560 NULL
, 0, NULL
, HFILL
}},
562 {&hf_udt_handshake_cookie
, {
563 "SYN Cookie", "udt.hs.cookie",
565 NULL
, 0, NULL
, HFILL
}},
567 {&hf_udt_handshake_peerip
, {
568 "Peer IP Address", "udt.hs.peerip",
570 NULL
, 0, NULL
, HFILL
}},
573 static int *ett
[] = {
577 static ei_register_info ei
[] = {
579 { "udt.nak_seqno", PI_SEQUENCE
, PI_NOTE
,
580 "Missing Sequence Number(s)", EXPFILL
}},
583 proto_udt
= proto_register_protocol("UDT Protocol", "UDT", "udt");
584 proto_register_field_array(proto_udt
, hf
, array_length(hf
));
585 proto_register_subtree_array(ett
, array_length(ett
));
587 expert_udt
= expert_register_protocol(proto_udt
);
588 expert_register_field_array(expert_udt
, ei
, array_length(ei
));
590 udt_handle
= register_dissector("udt", dissect_udt
, proto_udt
);
592 heur_subdissector_list
= register_heur_dissector_list_with_description("udt", "UDT data", proto_udt
);
595 void proto_reg_handoff_udt(void)
597 heur_dissector_add("udp", dissect_udt_heur_udp
, "UDT over UDP", "udt_udp", proto_udt
, HEURISTIC_ENABLE
);
598 heur_dissector_add("dtls", dissect_udt_heur_dtls
, "UDT over DTLS", "udt_dtls", proto_udt
, HEURISTIC_ENABLE
);
599 dissector_add_for_decode_as_with_preference("udp.port", udt_handle
);
604 * Editor modelines - https://www.wireshark.org/tools/modelines.html
609 * indent-tabs-mode: t
612 * vi: set shiftwidth=8 tabstop=8 noexpandtab:
613 * :indentSize=8:tabSize=8:noTabs=false: