Bug Summary

File:builds/wireshark/wireshark/epan/dissectors/packet-udx.c
Warning:line 1293, column 9
Value stored to 'offset' is never read

Annotated Source Code

Press '?' to see keyboard shortcuts

clang -cc1 -cc1 -triple x86_64-pc-linux-gnu -analyze -disable-free -clear-ast-before-backend -disable-llvm-verifier -discard-value-names -main-file-name packet-udx.c -analyzer-checker=core -analyzer-checker=apiModeling -analyzer-checker=unix -analyzer-checker=deadcode -analyzer-checker=security.insecureAPI.UncheckedReturn -analyzer-checker=security.insecureAPI.getpw -analyzer-checker=security.insecureAPI.gets -analyzer-checker=security.insecureAPI.mktemp -analyzer-checker=security.insecureAPI.mkstemp -analyzer-checker=security.insecureAPI.vfork -analyzer-checker=nullability.NullPassedToNonnull -analyzer-checker=nullability.NullReturnedFromNonnull -analyzer-output plist -w -setup-static-analyzer -mrelocation-model pic -pic-level 2 -fhalf-no-semantic-interposition -fno-delete-null-pointer-checks -mframe-pointer=all -relaxed-aliasing -fmath-errno -ffp-contract=on -fno-rounding-math -ffloat16-excess-precision=fast -fbfloat16-excess-precision=fast -mconstructor-aliases -funwind-tables=2 -target-cpu x86-64 -tune-cpu generic -debugger-tuning=gdb -fdebug-compilation-dir=/builds/wireshark/wireshark/build -fcoverage-compilation-dir=/builds/wireshark/wireshark/build -resource-dir /usr/lib/llvm-22/lib/clang/22 -isystem /usr/include/glib-2.0 -isystem /usr/lib/x86_64-linux-gnu/glib-2.0/include -isystem /builds/wireshark/wireshark/epan/dissectors -isystem /builds/wireshark/wireshark/build/epan/dissectors -isystem /usr/include/mit-krb5 -isystem /usr/include/libxml2 -isystem /builds/wireshark/wireshark/epan -D CARES_NO_DEPRECATED -D G_DISABLE_DEPRECATED -D G_DISABLE_SINGLE_INCLUDES -D WS_BUILD_DLL -D WS_DEBUG -D WS_DEBUG_UTF_8 -I /builds/wireshark/wireshark/build -I /builds/wireshark/wireshark -I /builds/wireshark/wireshark/include -D _GLIBCXX_ASSERTIONS -internal-isystem /usr/lib/llvm-22/lib/clang/22/include -internal-isystem /usr/local/include -internal-isystem /usr/lib/gcc/x86_64-linux-gnu/16/../../../../x86_64-linux-gnu/include -internal-externc-isystem /usr/include/x86_64-linux-gnu -internal-externc-isystem /include -internal-externc-isystem /usr/include -fmacro-prefix-map=/builds/wireshark/wireshark/= -fmacro-prefix-map=/builds/wireshark/wireshark/build/= -fmacro-prefix-map=../= -Wno-format-nonliteral -std=gnu17 -ferror-limit 19 -fvisibility=hidden -fwrapv -fwrapv-pointer -fstrict-flex-arrays=3 -stack-protector 2 -fstack-clash-protection -fcf-protection=full -fgnuc-version=4.2.1 -fskip-odr-check-in-gmf -fexceptions -fcolor-diagnostics -analyzer-output=html -faddrsig -fdwarf2-cfi-asm -o /builds/wireshark/wireshark/sbout/2026-08-21-100412-3660-1 -x c /builds/wireshark/wireshark/epan/dissectors/packet-udx.c
1/* packet-udx.c
2 * Routines for UDX dissection
3 * Copyright 2026, Frank <[email protected]>
4 *
5 * UDX is a reliable, multiplexed, UDP-based transport protocol used by the
6 * Holepunch peer-to-peer stack. Reference implementation:
7 * https://github.com/holepunchto/libudx
8 *
9 * Wireshark - Network traffic analyzer
10 * By Gerald Combs <[email protected]>
11 * Copyright 1998 Gerald Combs
12 *
13 * SPDX-License-Identifier: GPL-2.0-or-later
14 */
15
16#include "config.h"
17
18#include <math.h>
19
20#include <epan/packet.h>
21#include <epan/conversation.h>
22#include <epan/conversation_table.h>
23#include <epan/expert.h>
24#include <epan/prefs.h>
25#include <epan/proto_data.h>
26#include <epan/follow.h>
27#include <epan/addr_resolv.h>
28#include <epan/tap.h>
29#include "packet-udp.h"
30#include "packet-udx.h"
31#include <wsutil/wmem/wmem_map.h>
32#include <wsutil/wmem/wmem_tree.h>
33
34/*
35 * UDX wire format (all multi-byte fields little-endian):
36 *
37 * offset size field
38 * 0 1 magic (0xff)
39 * 1 1 version (1)
40 * 2 1 type flags
41 * 3 1 data offset: bytes between the fixed header and the payload,
42 * occupied by SACK blocks, or by padding on MTU probes
43 * 4 4 id - the *receiver's* stream id
44 * 8 4 window - sender's receive window in bytes
45 * 12 4 seq - per-PACKET sequence counter (not bytes)
46 * 16 4 ack - next seq expected from the peer
47 * 20 8*n SACK blocks: pairs of uint32 (start, end) seq ranges
48 * ... payload
49 */
50
51#define UDX_HEADER_SIZE20 20
52#define UDX_MAGIC_BYTE0xff 0xff
53#define UDX_VERSION1 1
54
55#define UDX_FLAG_DATA0x01 0x01
56#define UDX_FLAG_END0x02 0x02
57#define UDX_FLAG_SACK0x04 0x04
58#define UDX_FLAG_MESSAGE0x08 0x08
59#define UDX_FLAG_DESTROY0x10 0x10
60#define UDX_FLAG_HEARTBEAT0x20 0x20
61#define UDX_FLAG_MASK0x3f 0x3f
62
63/*
64 * Sequence numbers count packets and wrap at 2^32, so all comparisons are
65 * made in circular arithmetic.
66 */
67#define UDX_SEQ_LT(a, b)((int32_t)((a) - (b)) < 0) ((int32_t)((a) - (b)) < 0)
68#define UDX_SEQ_GT(a, b)((int32_t)((a) - (b)) > 0) ((int32_t)((a) - (b)) > 0)
69#define UDX_SEQ_GEQ(a, b)((int32_t)((a) - (b)) >= 0) ((int32_t)((a) - (b)) >= 0)
70
71/* Floor for the derived retransmission timeout, in seconds. Below this a
72 * repeat is attributed to loss recovery rather than to a timer firing. */
73#define UDX_MIN_RTO0.2 0.2
74
75/* A repeat arriving within this window of the original is a duplicate
76 * datagram rather than anything the sender chose to send again. */
77#define UDX_DUP_WINDOW0.0005 0.0005
78
79/* Shortest pause credited to a tail loss probe timer when no round-trip
80 * time has been measured yet. */
81#define UDX_MIN_PROBE_DELAY0.010 0.010
82
83void proto_register_udx(void);
84void proto_reg_handoff_udx(void);
85
86static dissector_handle_t udx_handle;
87
88static int proto_udx;
89
90static bool_Bool udx_analyze_sequence_numbers = true1;
91
92static int udx_follow_tap;
93static int udx_tap;
94
95/* Stream numbers are handed out across the whole capture so that a filter
96 * such as "udx.stream eq 3" identifies exactly one stream. */
97static uint32_t udx_stream_count;
98
99/* Queued for the follow taps: one packet's payload, where it belongs in the
100 * stream and which side sent it. */
101typedef struct udx_follow_tap_data {
102 tvbuff_t *tvb;
103 uint32_t stream;
104 uint32_t offset; /* position of this packet within its direction */
105 bool_Bool from_server;
106} udx_follow_tap_data_t;
107
108/* One transmitted packet, remembered so that a later acknowledgement can be
109 * linked back to it. */
110typedef struct udx_seg {
111 uint32_t frame;
112 nstime_t ts;
113 uint32_t len;
114 uint32_t acked_in_frame;
115 nstime_t ack_ts;
116 unsigned retrans;
117 bool_Bool sacked;
118} udx_seg_t;
119
120/* One direction of one stream: the packets one endpoint sends bearing the
121 * peer's stream id. */
122typedef struct udx_flow {
123 uint32_t id;
124 unsigned dir;
125 unsigned order; /* creation order within this direction */
126 nstime_t first_ts;
127 wmem_tree_t *segs; /* seq -> udx_seg_t */
128 uint32_t base_seq; /* first sequence number seen on this flow */
129 uint32_t low_seq; /* lowest sequence number seen on this flow */
130 uint32_t max_seq; /* highest sequence number sent */
131 bool_Bool have_seq;
132 uint32_t outstanding_bytes;
133 uint32_t outstanding_pkts;
134 uint32_t max_ack; /* highest acknowledgement this flow emitted */
135 bool_Bool have_ack;
136 uint32_t max_sacked; /* highest sequence the peer selectively acked */
137 bool_Bool have_sacked;
138 uint32_t last_rwnd;
139 bool_Bool rwnd_zero;
140 nstime_t last_tx_ts; /* when this flow last sent stream data */
141 bool_Bool have_tx;
142 double srtt;
143 double rttvar;
144 bool_Bool have_rtt;
145 uint32_t stream_num;
146 struct udx_flow *paired;
147 struct udx_flow *cand; /* pairing candidate under consideration */
148 unsigned cand_hits;
149} udx_flow_t;
150
151typedef struct udx_conv {
152 wmem_map_t *flows; /* (dir << 32 | id) -> udx_flow_t */
153 unsigned n_flows[2];
154 unsigned client_dir; /* the side that sent first is the client */
155 bool_Bool have_client_dir;
156} udx_conv_t;
157
158/* Verdicts reached on the first pass and replayed on every later visit. */
159#define UDX_A_RETRANS0x0001 0x0001
160#define UDX_A_FAST_RETRANS0x0002 0x0002
161#define UDX_A_RTO_RETRANS0x0004 0x0004
162#define UDX_A_TLP0x0008 0x0008
163#define UDX_A_SPURIOUS0x0010 0x0010
164#define UDX_A_OUT_OF_ORDER0x0020 0x0020
165#define UDX_A_LOST_SEGMENT0x0040 0x0040
166#define UDX_A_KEEPALIVE0x0080 0x0080
167#define UDX_A_ZERO_WIN_PROBE0x0100 0x0100
168#define UDX_A_ZERO_WIN0x0200 0x0200
169#define UDX_A_WINDOW_UPDATE0x0400 0x0400
170#define UDX_A_MTU_PROBE0x0800 0x0800
171#define UDX_A_END0x1000 0x1000
172#define UDX_A_DESTROY0x2000 0x2000
173#define UDX_A_DUPLICATE0x4000 0x4000
174
175typedef struct udx_ppd {
176 uint32_t flags;
177 uint32_t acks_frame; /* frame this packet acknowledges */
178 nstime_t ack_rtt;
179 bool_Bool have_ack_rtt;
180 uint32_t bytes_in_flight;
181 uint32_t packets_in_flight;
182 uint32_t seq; /* sender sequence, to find our own segment */
183 bool_Bool tracked; /* this packet consumed a sequence number */
184 uint32_t stream; /* stream number at analysis time */
185 uint32_t follow_offset; /* position within this direction */
186 bool_Bool from_server;
187 bool_Bool follow_ok; /* payload belongs in the reassembled stream */
188 udx_flow_t *flow;
189} udx_ppd_t;
190
191static int hf_udx_magic;
192static int hf_udx_version;
193static int hf_udx_flags;
194static int hf_udx_flags_data;
195static int hf_udx_flags_end;
196static int hf_udx_flags_sack;
197static int hf_udx_flags_message;
198static int hf_udx_flags_destroy;
199static int hf_udx_flags_heartbeat;
200static int hf_udx_data_offset;
201static int hf_udx_id;
202static int hf_udx_window;
203static int hf_udx_seq;
204static int hf_udx_ack;
205static int hf_udx_sacks;
206static int hf_udx_sack_block;
207static int hf_udx_sack_start;
208static int hf_udx_sack_end;
209static int hf_udx_padding;
210static int hf_udx_payload;
211static int hf_udx_payload_len;
212static int hf_udx_stream;
213static int hf_udx_analysis;
214static int hf_udx_analysis_acks_frame;
215static int hf_udx_analysis_acked_in;
216static int hf_udx_analysis_ack_rtt;
217static int hf_udx_analysis_bytes_in_flight;
218static int hf_udx_analysis_pkts_in_flight;
219static int hf_udx_analysis_no_reverse;
220
221static int ett_udx;
222static int ett_udx_flags;
223static int ett_udx_sacks;
224static int ett_udx_sack_block;
225static int ett_udx_analysis;
226
227static expert_field ei_udx_retrans;
228static expert_field ei_udx_fast_retrans;
229static expert_field ei_udx_rto_retrans;
230static expert_field ei_udx_tlp;
231static expert_field ei_udx_spurious_retrans;
232static expert_field ei_udx_duplicate;
233static expert_field ei_udx_out_of_order;
234static expert_field ei_udx_lost_segment;
235static expert_field ei_udx_keepalive;
236static expert_field ei_udx_zero_window_probe;
237static expert_field ei_udx_zero_window;
238static expert_field ei_udx_window_update;
239static expert_field ei_udx_mtu_probe;
240static expert_field ei_udx_end;
241static expert_field ei_udx_destroy;
242
243static int * const udx_flag_fields[] = {
244 &hf_udx_flags_data,
245 &hf_udx_flags_end,
246 &hf_udx_flags_sack,
247 &hf_udx_flags_message,
248 &hf_udx_flags_destroy,
249 &hf_udx_flags_heartbeat,
250 NULL((void*)0)
251};
252
253/* Build a "DATA,SACK"-style summary of the flags byte; bare 0 is an ACK. */
254static void
255udx_flags_to_str(uint8_t flags, char *buf, size_t buf_len)
256{
257 static const struct {
258 uint8_t bit;
259 const char *name;
260 } bits[] = {
261 { UDX_FLAG_DATA0x01, "DATA" },
262 { UDX_FLAG_END0x02, "END" },
263 { UDX_FLAG_SACK0x04, "SACK" },
264 { UDX_FLAG_MESSAGE0x08, "MESSAGE" },
265 { UDX_FLAG_DESTROY0x10, "DESTROY" },
266 { UDX_FLAG_HEARTBEAT0x20, "HEARTBEAT" },
267 };
268 size_t pos = 0;
269
270 if (flags == 0) {
271 (void) g_strlcpy(buf, "ACK", buf_len);
272 return;
273 }
274 buf[0] = '\0';
275 for (size_t i = 0; i < array_length(bits)(sizeof (bits) / sizeof (bits)[0]); i++) {
276 if (flags & bits[i].bit) {
277 if (pos > 0)
278 pos += g_strlcpy(buf + pos, ",", buf_len - pos);
279 pos += g_strlcpy(buf + pos, bits[i].name, buf_len - pos);
280 }
281 }
282}
283
284/*
285 * A stable label for the two endpoints of the enclosing UDP conversation.
286 * Which endpoint gets 0 does not matter; only that a given endpoint keeps
287 * the same label for the whole capture.
288 */
289static unsigned
290udx_direction(const packet_info *pinfo)
291{
292 int c = cmp_address(&pinfo->src, &pinfo->dst);
293
294 if (c != 0)
295 return (c < 0) ? 0 : 1;
296 return (pinfo->srcport < pinfo->destport) ? 0 : 1;
297}
298
299static udx_flow_t *
300udx_get_flow(udx_conv_t *conv, unsigned dir, uint32_t id, const nstime_t *ts)
301{
302 uint64_t key = ((uint64_t) dir << 32) | id;
303 udx_flow_t *flow = (udx_flow_t *) wmem_map_lookup(conv->flows, &key);
304 uint64_t *key_copy;
305
306 if (flow != NULL((void*)0))
307 return flow;
308
309 flow = wmem_new0(wmem_file_scope(), udx_flow_t)((udx_flow_t*)wmem_alloc0((wmem_file_scope()), sizeof(udx_flow_t
)))
;
310 flow->id = id;
311 flow->dir = dir;
312 flow->order = conv->n_flows[dir]++;
313 flow->first_ts = *ts;
314 flow->segs = wmem_tree_new(wmem_file_scope());
315 flow->stream_num = udx_stream_count++;
316
317 key_copy = wmem_new(wmem_file_scope(), uint64_t)((uint64_t*)wmem_alloc((wmem_file_scope()), sizeof(uint64_t))
)
;
318 *key_copy = key;
319 wmem_map_insert(conv->flows, key_copy, flow);
320
321 return flow;
322}
323
324/*
325 * Pairing a flow with its reverse.
326 *
327 * A UDX conversation is a six tuple, but a packet carries only the receiver's
328 * stream id: the ids are exchanged in an encrypted handshake that is not
329 * visible here. The reverse flow therefore has to be inferred.
330 *
331 * Candidates are the flows travelling the other way. Each is scored on
332 * - plausibility: the acknowledgement carried by this packet must fall
333 * within the sequence numbers the candidate has actually sent;
334 * - creation order: streams are set up in pairs, so the n'th flow in one
335 * direction usually answers the n'th flow in the other;
336 * - proximity: the two flows should have appeared at about the same time.
337 *
338 * A candidate is adopted once it has been the sole best choice twice, which
339 * keeps a single ambiguous packet from binding the wrong pair. Once bound,
340 * a pairing is never revised.
341 */
342typedef struct udx_pair_scan {
343 udx_flow_t *self;
344 uint32_t ack;
345 udx_flow_t *best;
346 int best_score;
347 bool_Bool tie;
348} udx_pair_scan_t;
349
350static void
351udx_score_candidate(void *key _U___attribute__((unused)), void *value, void *userdata)
352{
353 udx_flow_t *cand = (udx_flow_t *) value;
354 udx_pair_scan_t *scan = (udx_pair_scan_t *) userdata;
355 double dt;
356 int score = 0;
357
358 if (cand->dir == scan->self->dir || cand->paired != NULL((void*)0))
359 return;
360
361 /* The acknowledgement must not reach past what the candidate has sent. */
362 if (cand->have_seq) {
363 if (UDX_SEQ_GT(scan->ack, cand->max_seq + 1)((int32_t)((scan->ack) - (cand->max_seq + 1)) > 0))
364 return;
365 score += 4;
366 }
367
368 if (cand->order == scan->self->order)
369 score += 2;
370
371 dt = nstime_to_sec(&cand->first_ts) - nstime_to_sec(&scan->self->first_ts);
372 if (dt < 0)
373 dt = -dt;
374 if (dt < 0.050)
375 score += 1;
376
377 if (score > scan->best_score) {
378 scan->best_score = score;
379 scan->best = cand;
380 scan->tie = false0;
381 } else if (score == scan->best_score && scan->best != NULL((void*)0)) {
382 scan->tie = true1;
383 }
384}
385
386static void
387udx_try_pair(udx_conv_t *conv, udx_flow_t *flow, uint32_t ack)
388{
389 udx_pair_scan_t scan;
390
391 scan.self = flow;
392 scan.ack = ack;
393 scan.best = NULL((void*)0);
394 scan.best_score = 0;
395 scan.tie = false0;
396
397 wmem_map_foreach(conv->flows, udx_score_candidate, &scan);
398
399 if (scan.best == NULL((void*)0) || scan.tie) {
400 flow->cand = NULL((void*)0);
401 flow->cand_hits = 0;
402 return;
403 }
404
405 /*
406 * One unambiguous winner is adopted at once, so that a stream is paired
407 * from its first packet on. An ambiguous scan binds nothing and is
408 * retried on the next packet, by which time the acknowledgements have
409 * usually separated the candidates.
410 */
411 flow->cand = scan.best;
412 flow->cand_hits++;
413
414 flow->paired = scan.best;
415 scan.best->paired = flow;
416
417 /* Both halves report the lower of the two numbers. */
418 if (scan.best->stream_num < flow->stream_num)
419 flow->stream_num = scan.best->stream_num;
420 else
421 scan.best->stream_num = flow->stream_num;
422}
423
424/* RFC 6298 smoothing, fed only by segments that were never retransmitted. */
425static void
426udx_update_rtt(udx_flow_t *flow, double sample)
427{
428 if (!flow->have_rtt) {
429 flow->srtt = sample;
430 flow->rttvar = sample / 2;
431 flow->have_rtt = true1;
432 return;
433 }
434 flow->rttvar = 0.75 * flow->rttvar + 0.25 * fabs(flow->srtt - sample);
435 flow->srtt = 0.875 * flow->srtt + 0.125 * sample;
436}
437
438static double
439udx_rto(const udx_flow_t *flow)
440{
441 double rto;
442
443 if (!flow->have_rtt)
444 return UDX_MIN_RTO0.2;
445 rto = flow->srtt + 4 * flow->rttvar;
446 return (rto < UDX_MIN_RTO0.2) ? UDX_MIN_RTO0.2 : rto;
447}
448
449/*
450 * Retire one segment. A packet stops being in flight the moment it is
451 * acknowledged, whether cumulatively or selectively, so both paths come
452 * through here. Returns true only for the frame that first acknowledged it,
453 * which keeps a later cumulative acknowledgement of an already selectively
454 * acknowledged packet from counting it twice.
455 */
456static bool_Bool
457udx_retire_seg(packet_info *pinfo, udx_flow_t *flow, udx_seg_t *seg)
458{
459 if (seg->acked_in_frame != 0)
460 return false0;
461
462 seg->acked_in_frame = pinfo->num;
463 seg->ack_ts = pinfo->abs_ts;
464
465 if (flow->outstanding_pkts > 0) {
466 flow->outstanding_pkts--;
467 flow->outstanding_bytes -= seg->len;
468 }
469 return true1;
470}
471
472/*
473 * Retire every segment of the acknowledged flow below "ack", link the last
474 * of them to the acknowledging packet, and take an RTT sample from it.
475 */
476static void
477udx_process_ack(packet_info *pinfo, udx_flow_t *acked_flow,
478 uint32_t ack, uint32_t prev_ack, bool_Bool have_prev, udx_ppd_t *ppd)
479{
480 udx_seg_t *newest = NULL((void*)0);
481 uint32_t seq = ack - 1;
482 unsigned guard;
483
484 if (!acked_flow->have_seq)
485 return;
486
487 /*
488 * Walk back over the range this acknowledgement newly covers, which
489 * starts just above the previous cumulative acknowledgement. A segment
490 * already retired, by an earlier acknowledgement or by a selective one,
491 * is skipped rather than counted again, and the walk carries on past it
492 * so that anything older still outstanding is retired too. The counter
493 * only bounds pathological captures.
494 */
495 for (guard = 0; guard < 4096; guard++, seq--) {
496 udx_seg_t *seg;
497
498 if (have_prev && UDX_SEQ_LT(seq, prev_ack)((int32_t)((seq) - (prev_ack)) < 0))
499 break;
500 if (UDX_SEQ_LT(seq, acked_flow->low_seq)((int32_t)((seq) - (acked_flow->low_seq)) < 0))
501 break;
502
503 seg = (udx_seg_t *) wmem_tree_lookup32(acked_flow->segs, seq);
504 if (seg == NULL((void*)0))
505 continue;
506
507 if (udx_retire_seg(pinfo, acked_flow, seg) && newest == NULL((void*)0))
508 newest = seg;
509 }
510
511 if (newest != NULL((void*)0)) {
512 nstime_t rtt;
513
514 nstime_delta(&rtt, &pinfo->abs_ts, &newest->ts);
515 ppd->acks_frame = newest->frame;
516 ppd->ack_rtt = rtt;
517 ppd->have_ack_rtt = true1;
518
519 /*
520 * Karn's algorithm: a retransmitted segment yields no usable sample.
521 * The sample times a packet this flow sent, so it belongs to the flow
522 * that sent it and not to the one reporting the acknowledgement. The
523 * two are only ever the same on a stream carrying data both ways; on
524 * a one-way transfer the sending flow would otherwise never obtain a
525 * round trip time at all, and every timeout test would fall back on
526 * the floor.
527 */
528 if (newest->retrans == 0)
529 udx_update_rtt(acked_flow, nstime_to_sec(&rtt));
530 }
531}
532
533static void
534udx_analyze(packet_info *pinfo, udx_conv_t *conv, uint8_t flags, uint8_t data_offset,
535 uint32_t id, uint32_t window, uint32_t seq, uint32_t ack,
536 uint32_t payload_len, const uint32_t *sack_start, const uint32_t *sack_end,
537 unsigned n_sacks, udx_ppd_t *ppd)
538{
539 unsigned dir = udx_direction(pinfo);
540 udx_flow_t *flow = udx_get_flow(conv, dir, id, &pinfo->abs_ts);
541 udx_flow_t *rflow;
542 udx_seg_t *seg;
543 bool_Bool consumes_seq;
544
545 if (!conv->have_client_dir) {
546 conv->client_dir = dir;
547 conv->have_client_dir = true1;
548 }
549
550 ppd->flow = flow;
551 ppd->seq = seq;
552 ppd->from_server = (dir != conv->client_dir);
553
554 if (flow->paired == NULL((void*)0))
555 udx_try_pair(conv, flow, ack);
556 rflow = flow->paired;
557
558 /* DATA and END occupy a sequence number; MESSAGE is an unordered
559 * datagram outside the stream and a bare ACK only reports one. */
560 consumes_seq = (flags & (UDX_FLAG_DATA0x01 | UDX_FLAG_END0x02)) != 0;
561
562 if (consumes_seq) {
563 seg = (udx_seg_t *) wmem_tree_lookup32(flow->segs, seq);
564
565 if (seg == NULL((void*)0)) {
566 /*
567 * A tail loss probe does not have to repeat the tail: libudx can
568 * send the next new packet as the probe instead. Seen from here
569 * that is a fresh sequence number extending the flow after a
570 * probe-sized pause, while earlier data is still unacknowledged,
571 * which is the sender prodding for an acknowledgement rather than
572 * an application with more to say.
573 */
574 if (payload_len > 0 && flow->have_tx && flow->have_seq &&
575 flow->outstanding_pkts > 0 && seq == flow->max_seq + 1) {
576 double idle = nstime_to_sec(&pinfo->abs_ts) -
577 nstime_to_sec(&flow->last_tx_ts);
578
579 if (idle >= (flow->have_rtt ? 2 * flow->srtt : UDX_MIN_PROBE_DELAY0.010))
580 ppd->flags |= UDX_A_TLP0x0008;
581 }
582
583 if (flow->have_seq && UDX_SEQ_GT(seq, flow->max_seq + 1)((int32_t)((seq) - (flow->max_seq + 1)) > 0))
584 ppd->flags |= UDX_A_LOST_SEGMENT0x0040;
585 else if (flow->have_seq && UDX_SEQ_LT(seq, flow->max_seq)((int32_t)((seq) - (flow->max_seq)) < 0))
586 ppd->flags |= UDX_A_OUT_OF_ORDER0x0020;
587
588 seg = wmem_new0(wmem_file_scope(), udx_seg_t)((udx_seg_t*)wmem_alloc0((wmem_file_scope()), sizeof(udx_seg_t
)))
;
589 seg->frame = pinfo->num;
590 seg->ts = pinfo->abs_ts;
591 seg->len = payload_len;
592 wmem_tree_insert32(flow->segs, seq, seg);
593
594 if (!flow->have_seq) {
595 flow->base_seq = seq;
596 flow->low_seq = seq;
597 flow->max_seq = seq;
598 flow->have_seq = true1;
599 } else {
600 if (UDX_SEQ_GT(seq, flow->max_seq)((int32_t)((seq) - (flow->max_seq)) > 0))
601 flow->max_seq = seq;
602 /* The first packet on the wire need not be the oldest: if it
603 * was lost and resent, a lower sequence number turns up later
604 * and still has to be accounted for. */
605 if (UDX_SEQ_LT(seq, flow->low_seq)((int32_t)((seq) - (flow->low_seq)) < 0))
606 flow->low_seq = seq;
607 }
608 flow->outstanding_pkts++;
609 flow->outstanding_bytes += payload_len;
610 } else {
611 double dt = nstime_to_sec(&pinfo->abs_ts) - nstime_to_sec(&seg->ts);
612
613 seg->retrans++;
614 ppd->flags |= UDX_A_RETRANS0x0001;
615
616 if (seg->acked_in_frame != 0) {
617 ppd->flags |= UDX_A_SPURIOUS0x0010;
618 } else if (dt < UDX_DUP_WINDOW0.0005) {
619 /* Too soon to be any sender timer: the datagram was
620 * delivered, or captured, twice. */
621 ppd->flags |= UDX_A_DUPLICATE0x4000;
622 } else if (dt >= udx_rto(flow)) {
623 /* A whole retransmission timeout has passed. That is a timer
624 * firing, whatever the peer has selectively acknowledged in
625 * the meantime, so this test comes before the SACK one. */
626 ppd->flags |= UDX_A_RTO_RETRANS0x0004;
627 } else if (flow->have_sacked && UDX_SEQ_GT(flow->max_sacked, seq)((int32_t)((flow->max_sacked) - (seq)) > 0)) {
628 /* The peer has selectively acknowledged later packets, so
629 * this one was resent because it was reported missing rather
630 * than because a timer expired. */
631 ppd->flags |= UDX_A_FAST_RETRANS0x0002;
632 } else if (seq == flow->max_seq &&
633 dt >= (flow->have_rtt ? 2 * flow->srtt : UDX_MIN_PROBE_DELAY0.010)) {
634 /* A repeat of the tail after a probe-sized pause, with
635 * nothing newer sent, is how a tail loss probe looks here. */
636 ppd->flags |= UDX_A_TLP0x0008;
637 }
638 }
639
640 /* Used to spot the pause before a tail loss probe. */
641 flow->last_tx_ts = pinfo->abs_ts;
642 flow->have_tx = true1;
643
644 ppd->tracked = true1;
645 ppd->bytes_in_flight = flow->outstanding_bytes;
646 ppd->packets_in_flight = flow->outstanding_pkts;
647
648 /*
649 * Position within the stream, counted from the first packet seen on
650 * this flow. Anything before that point arrived out of order at the
651 * very start of the capture and cannot be placed.
652 */
653 if (payload_len > 0 && UDX_SEQ_GEQ(seq, flow->base_seq)((int32_t)((seq) - (flow->base_seq)) >= 0)) {
654 ppd->follow_offset = seq - flow->base_seq;
655 ppd->follow_ok = true1;
656 }
657 }
658
659 if (flags & UDX_FLAG_END0x02)
660 ppd->flags |= UDX_A_END0x1000;
661 if (flags & UDX_FLAG_DESTROY0x10)
662 ppd->flags |= UDX_A_DESTROY0x2000;
663
664 /* An MTU probe pads between the header and the payload; the same byte
665 * delimits SACK blocks when they are present. */
666 if (data_offset > 0 && !(flags & UDX_FLAG_SACK0x04))
667 ppd->flags |= UDX_A_MTU_PROBE0x0800;
668
669 /* Acknowledgement side: retire the peer's segments, then record the
670 * selective ranges so a later repeat can be recognised as recovery. */
671 if (rflow != NULL((void*)0)) {
672 udx_seg_t *newest_sack = NULL((void*)0);
673 uint32_t newest_sack_seq = 0;
674
675 if (!flow->have_ack || UDX_SEQ_GT(ack, flow->max_ack)((int32_t)((ack) - (flow->max_ack)) > 0))
676 udx_process_ack(pinfo, rflow, ack, flow->max_ack,
677 flow->have_ack, ppd);
678
679 for (unsigned i = 0; i < n_sacks; i++) {
680 uint32_t s;
681 unsigned guard = 0;
682
683 for (s = sack_start[i]; UDX_SEQ_LT(s, sack_end[i])((int32_t)((s) - (sack_end[i])) < 0) && guard < 1024;
684 s++, guard++) {
685 udx_seg_t *ss = (udx_seg_t *) wmem_tree_lookup32(rflow->segs, s);
686
687 if (ss == NULL((void*)0))
688 continue;
689
690 ss->sacked = true1;
691
692 /* A selective acknowledgement acknowledges the packet as
693 * surely as a cumulative one: it leaves the flight, and this
694 * is the frame that acknowledged it. */
695 if (udx_retire_seg(pinfo, rflow, ss) &&
696 (newest_sack == NULL((void*)0) || UDX_SEQ_GT(s, newest_sack_seq)((int32_t)((s) - (newest_sack_seq)) > 0))) {
697 newest_sack = ss;
698 newest_sack_seq = s;
699 }
700 }
701
702 /* Remember how far the selective acknowledgements reach: a
703 * retransmission below this point is loss recovery. */
704 if (!rflow->have_sacked || UDX_SEQ_GT(sack_end[i] - 1, rflow->max_sacked)((int32_t)((sack_end[i] - 1) - (rflow->max_sacked)) > 0
)
) {
705 rflow->max_sacked = sack_end[i] - 1;
706 rflow->have_sacked = true1;
707 }
708 }
709
710 /* Nothing was newly acknowledged cumulatively, but a selective range
711 * retired a packet, so report the link and the round trip from that. */
712 if (newest_sack != NULL((void*)0) && !ppd->have_ack_rtt) {
713 nstime_t rtt;
714
715 nstime_delta(&rtt, &pinfo->abs_ts, &newest_sack->ts);
716 ppd->acks_frame = newest_sack->frame;
717 ppd->ack_rtt = rtt;
718 ppd->have_ack_rtt = true1;
719
720 /* Karn's algorithm again: never sample a retransmitted packet.
721 * The round trip measured belongs to the flow that sent the data,
722 * which is where the retransmission timeout is later judged. */
723 if (newest_sack->retrans == 0)
724 udx_update_rtt(rflow, nstime_to_sec(&rtt));
725 }
726 }
727
728 if (!flow->have_ack || UDX_SEQ_GT(ack, flow->max_ack)((int32_t)((ack) - (flow->max_ack)) > 0)) {
729 flow->max_ack = ack;
730 flow->have_ack = true1;
731 }
732
733 /* Receive window transitions. */
734 if (window == 0) {
735 ppd->flags |= UDX_A_ZERO_WIN0x0200;
736 flow->rwnd_zero = true1;
737 } else if (flow->rwnd_zero) {
738 ppd->flags |= UDX_A_WINDOW_UPDATE0x0400;
739 flow->rwnd_zero = false0;
740 }
741 flow->last_rwnd = window;
742
743 /*
744 * Keepalives and zero-window probes are the same bytes on the wire: a
745 * bare heartbeat. Only the peer's advertised window tells them apart.
746 */
747 if ((flags & UDX_FLAG_HEARTBEAT0x20) && payload_len == 0) {
748 if (rflow != NULL((void*)0) && rflow->rwnd_zero)
749 ppd->flags |= UDX_A_ZERO_WIN_PROBE0x0100;
750 else
751 ppd->flags |= UDX_A_KEEPALIVE0x0080;
752 }
753
754 ppd->stream = (flow->paired != NULL((void*)0) && flow->paired->stream_num < flow->stream_num)
755 ? flow->paired->stream_num
756 : flow->stream_num;
757}
758
759/*
760 * Render the verdicts reached on the first pass. Nothing here computes: on a
761 * revisit the stored results are simply replayed, so what is shown never
762 * depends on how the packet was reached.
763 */
764static void
765udx_show_analysis(tvbuff_t *tvb, packet_info *pinfo, proto_tree *tree, udx_ppd_t *ppd)
766{
767 proto_item *ti;
768 proto_tree *an_tree;
769 udx_seg_t *seg;
770
771 if (ppd->flow == NULL((void*)0))
772 return;
773
774 ti = proto_tree_add_uint(tree, hf_udx_stream, tvb, 0, 0,
775 (ppd->flow->paired != NULL((void*)0) &&
776 ppd->flow->paired->stream_num < ppd->flow->stream_num)
777 ? ppd->flow->paired->stream_num
778 : ppd->flow->stream_num);
779 proto_item_set_generated(ti);
780
781 /* Nothing to report on a packet that neither carries data nor advances
782 * an acknowledgement, so leave the subtree out entirely rather than
783 * showing an empty one. */
784 if (ppd->flags == 0 && ppd->acks_frame == 0 && !ppd->tracked &&
785 ppd->flow->paired != NULL((void*)0))
786 return;
787
788 ti = proto_tree_add_item(tree, hf_udx_analysis, tvb, 0, 0, ENC_NA0x00000000);
789 proto_item_set_generated(ti);
790 an_tree = proto_item_add_subtree(ti, ett_udx_analysis);
791
792 if (ppd->flow->paired == NULL((void*)0)) {
793 proto_item *rev_ti = proto_tree_add_item(an_tree, hf_udx_analysis_no_reverse,
794 tvb, 0, 0, ENC_NA0x00000000);
795 proto_item_set_generated(rev_ti);
796 }
797
798 if (ppd->acks_frame != 0) {
799 ti = proto_tree_add_uint(an_tree, hf_udx_analysis_acks_frame, tvb, 0, 0,
800 ppd->acks_frame);
801 proto_item_set_generated(ti);
802
803 if (ppd->have_ack_rtt) {
804 ti = proto_tree_add_time(an_tree, hf_udx_analysis_ack_rtt, tvb, 0, 0,
805 &ppd->ack_rtt);
806 proto_item_set_generated(ti);
807 }
808 }
809
810 /* A packet that carried data learns only later which packet acked it. */
811 if (ppd->tracked) {
812 seg = (udx_seg_t *) wmem_tree_lookup32(ppd->flow->segs, ppd->seq);
813 if (seg != NULL((void*)0) && seg->frame == pinfo->num && seg->acked_in_frame != 0) {
814 nstime_t rtt;
815
816 ti = proto_tree_add_uint(an_tree, hf_udx_analysis_acked_in, tvb, 0, 0,
817 seg->acked_in_frame);
818 proto_item_set_generated(ti);
819
820 nstime_delta(&rtt, &seg->ack_ts, &seg->ts);
821 ti = proto_tree_add_time(an_tree, hf_udx_analysis_ack_rtt, tvb, 0, 0, &rtt);
822 proto_item_set_generated(ti);
823 }
824
825 ti = proto_tree_add_uint(an_tree, hf_udx_analysis_bytes_in_flight, tvb, 0, 0,
826 ppd->bytes_in_flight);
827 proto_item_set_generated(ti);
828 ti = proto_tree_add_uint(an_tree, hf_udx_analysis_pkts_in_flight, tvb, 0, 0,
829 ppd->packets_in_flight);
830 proto_item_set_generated(ti);
831 }
832
833 /* Expert notes, most specific classification first. */
834 if (ppd->flags & UDX_A_LOST_SEGMENT0x0040)
835 expert_add_info(pinfo, ti, &ei_udx_lost_segment);
836 if (ppd->flags & UDX_A_OUT_OF_ORDER0x0020)
837 expert_add_info(pinfo, ti, &ei_udx_out_of_order);
838
839 if (ppd->flags & UDX_A_SPURIOUS0x0010)
840 expert_add_info(pinfo, ti, &ei_udx_spurious_retrans);
841 else if (ppd->flags & UDX_A_FAST_RETRANS0x0002)
842 expert_add_info(pinfo, ti, &ei_udx_fast_retrans);
843 else if (ppd->flags & UDX_A_RTO_RETRANS0x0004)
844 expert_add_info(pinfo, ti, &ei_udx_rto_retrans);
845 else if (ppd->flags & UDX_A_TLP0x0008)
846 expert_add_info(pinfo, ti, &ei_udx_tlp);
847 else if (ppd->flags & UDX_A_DUPLICATE0x4000)
848 expert_add_info(pinfo, ti, &ei_udx_duplicate);
849 else if (ppd->flags & UDX_A_RETRANS0x0001)
850 expert_add_info(pinfo, ti, &ei_udx_retrans);
851
852 if (ppd->flags & UDX_A_ZERO_WIN_PROBE0x0100)
853 expert_add_info(pinfo, ti, &ei_udx_zero_window_probe);
854 else if (ppd->flags & UDX_A_KEEPALIVE0x0080)
855 expert_add_info(pinfo, ti, &ei_udx_keepalive);
856
857 if (ppd->flags & UDX_A_ZERO_WIN0x0200)
858 expert_add_info(pinfo, ti, &ei_udx_zero_window);
859 if (ppd->flags & UDX_A_WINDOW_UPDATE0x0400)
860 expert_add_info(pinfo, ti, &ei_udx_window_update);
861 if (ppd->flags & UDX_A_MTU_PROBE0x0800)
862 expert_add_info(pinfo, ti, &ei_udx_mtu_probe);
863 if (ppd->flags & UDX_A_END0x1000)
864 expert_add_info(pinfo, ti, &ei_udx_end);
865 if (ppd->flags & UDX_A_DESTROY0x2000)
866 expert_add_info(pinfo, ti, &ei_udx_destroy);
867}
868
869
870/*
871 * Conversations and endpoints.
872 *
873 * A UDX conversation is one stream, not one socket pair. Several streams can
874 * be multiplexed over a single UDP flow, so the enclosing UDP conversation
875 * counts them together and cannot say how much traffic any one of them
876 * carried. Keying on the stream index the dissector already assigns splits
877 * them apart.
878 */
879
880static const char *
881udx_conv_get_filter_type(conv_item_t *conv, conv_filter_type_e filter)
882{
883 if (filter == CONV_FT_SRC_PORT)
884 return "udp.srcport";
885
886 if (filter == CONV_FT_DST_PORT)
887 return "udp.dstport";
888
889 if (filter == CONV_FT_ANY_PORT)
890 return "udp.port";
891
892 if (conv == NULL((void*)0))
893 return CONV_FILTER_INVALID"INVALID";
894
895 if (filter == CONV_FT_SRC_ADDRESS) {
896 if (conv->src_address.type == AT_IPv4)
897 return "ip.src";
898 if (conv->src_address.type == AT_IPv6)
899 return "ipv6.src";
900 }
901
902 if (filter == CONV_FT_DST_ADDRESS) {
903 if (conv->dst_address.type == AT_IPv4)
904 return "ip.dst";
905 if (conv->dst_address.type == AT_IPv6)
906 return "ipv6.dst";
907 }
908
909 if (filter == CONV_FT_ANY_ADDRESS) {
910 if (conv->src_address.type == AT_IPv4)
911 return "ip.addr";
912 if (conv->src_address.type == AT_IPv6)
913 return "ipv6.addr";
914 }
915
916 return CONV_FILTER_INVALID"INVALID";
917}
918
919static ct_dissector_info_t udx_ct_dissector_info = { &udx_conv_get_filter_type };
920
921static tap_packet_status
922udx_conversation_packet(void *pct, packet_info *pinfo, epan_dissect_t *edt _U___attribute__((unused)),
923 const void *vip, tap_flags_t flags)
924{
925 conv_hash_t *hash = (conv_hash_t *) pct;
926 const udx_info_t *udxh = (const udx_info_t *) vip;
927
928 hash->flags = flags;
929
930 add_conversation_table_data_with_conv_id(hash, &udxh->ip_src, &udxh->ip_dst,
931 udxh->sport, udxh->dport,
932 (conv_id_t) udxh->stream, 1,
933 pinfo->fd->pkt_len,
934 &pinfo->rel_ts, &pinfo->abs_ts,
935 &udx_ct_dissector_info,
936 CONVERSATION_UDX);
937
938 return TAP_PACKET_REDRAW;
939}
940
941static const char *
942udx_endpoint_get_filter_type(endpoint_item_t *endpoint, conv_filter_type_e filter)
943{
944 if (filter == CONV_FT_SRC_PORT)
945 return "udp.srcport";
946
947 if (filter == CONV_FT_DST_PORT)
948 return "udp.dstport";
949
950 if (filter == CONV_FT_ANY_PORT)
951 return "udp.port";
952
953 if (endpoint == NULL((void*)0))
954 return CONV_FILTER_INVALID"INVALID";
955
956 if (filter == CONV_FT_SRC_ADDRESS) {
957 if (endpoint->myaddress.type == AT_IPv4)
958 return "ip.src";
959 if (endpoint->myaddress.type == AT_IPv6)
960 return "ipv6.src";
961 }
962
963 if (filter == CONV_FT_DST_ADDRESS) {
964 if (endpoint->myaddress.type == AT_IPv4)
965 return "ip.dst";
966 if (endpoint->myaddress.type == AT_IPv6)
967 return "ipv6.dst";
968 }
969
970 if (filter == CONV_FT_ANY_ADDRESS) {
971 if (endpoint->myaddress.type == AT_IPv4)
972 return "ip.addr";
973 if (endpoint->myaddress.type == AT_IPv6)
974 return "ipv6.addr";
975 }
976
977 return CONV_FILTER_INVALID"INVALID";
978}
979
980static et_dissector_info_t udx_endpoint_dissector_info = { &udx_endpoint_get_filter_type };
981
982static tap_packet_status
983udx_endpoint_packet(void *pit, packet_info *pinfo, epan_dissect_t *edt _U___attribute__((unused)),
984 const void *vip, tap_flags_t flags)
985{
986 conv_hash_t *hash = (conv_hash_t *) pit;
987 const udx_info_t *udxh = (const udx_info_t *) vip;
988
989 hash->flags = flags;
990
991 /* One pass per direction, so a datagram addressed to its own sender is
992 * still counted for both endpoints. */
993 add_endpoint_table_data(hash, &udxh->ip_src, udxh->sport, true1, 1,
994 pinfo->fd->pkt_len, &udx_endpoint_dissector_info,
995 ENDPOINT_UDXCONVERSATION_UDX);
996 add_endpoint_table_data(hash, &udxh->ip_dst, udxh->dport, false0, 1,
997 pinfo->fd->pkt_len, &udx_endpoint_dissector_info,
998 ENDPOINT_UDXCONVERSATION_UDX);
999
1000 return TAP_PACKET_REDRAW;
1001}
1002
1003
1004/*
1005 * Follow stream.
1006 *
1007 * Payload is delivered in sequence order per direction. A packet that
1008 * arrives early is held until the gap before it is filled, and a payload
1009 * already delivered - a retransmission - is dropped, so the reassembled
1010 * conversation reads the way the application saw it rather than the way the
1011 * network happened to deliver it.
1012 */
1013
1014/* Stream numbers restart with every capture file, as they do for TCP. */
1015static void
1016udx_init(void)
1017{
1018 udx_stream_count = 0;
1019}
1020
1021static char *
1022udx_follow_conv_filter(epan_dissect_t *edt _U___attribute__((unused)), packet_info *pinfo,
1023 unsigned *stream, unsigned *sub_stream _U___attribute__((unused)))
1024{
1025 udx_ppd_t *ppd = (udx_ppd_t *) p_get_proto_data(wmem_file_scope(), pinfo, proto_udx, 0);
1026
1027 if (ppd == NULL((void*)0) || ppd->flow == NULL((void*)0))
1028 return NULL((void*)0);
1029
1030 *stream = ppd->stream;
1031 return ws_strdup_printf("udx.stream eq %u", ppd->stream)wmem_strdup_printf(((void*)0), "udx.stream eq %u", ppd->stream
)
;
1032}
1033
1034static char *
1035udx_follow_index_filter(unsigned stream, unsigned sub_stream _U___attribute__((unused)))
1036{
1037 return ws_strdup_printf("udx.stream eq %u", stream)wmem_strdup_printf(((void*)0), "udx.stream eq %u", stream);
1038}
1039
1040static unsigned
1041udx_get_stream_count(void)
1042{
1043 return udx_stream_count;
1044}
1045
1046static void
1047udx_follow_append(follow_info_t *follow_info, follow_record_t *record)
1048{
1049 follow_info->payload = g_list_prepend(follow_info->payload, record);
1050 follow_info->bytes_written[record->is_server ? 1 : 0] += record->data->len;
1051}
1052
1053static int
1054udx_follow_seq_cmp(const void *a, const void *b)
1055{
1056 const follow_record_t *ra = (const follow_record_t *) a;
1057 const follow_record_t *rb = (const follow_record_t *) b;
1058
1059 if (ra->seq == rb->seq)
1060 return 0;
1061 return (ra->seq < rb->seq) ? -1 : 1;
1062}
1063
1064/*
1065 * Release held payload that now continues the stream. The pending list is
1066 * kept in sequence order, so this only ever walks its front.
1067 */
1068static void
1069udx_follow_drain(follow_info_t *follow_info, int dir)
1070{
1071 while (follow_info->fragments[dir] != NULL((void*)0)) {
1072 follow_record_t *held = (follow_record_t *) follow_info->fragments[dir]->data;
1073
1074 /*
1075 * A copy of this packet reached the delivery point ahead of the one
1076 * held here, which happens whenever a retransmission arrives while an
1077 * earlier gap is still open. The held copy has nothing left to give,
1078 * and leaving it at the head of the list would stop every packet
1079 * behind it from ever being released.
1080 */
1081 if (held->seq < follow_info->seq[dir]) {
1082 follow_info->fragments[dir] =
1083 g_list_delete_link(follow_info->fragments[dir],
1084 follow_info->fragments[dir]);
1085 g_byte_array_free(held->data, true1);
1086 g_free(held)(__builtin_object_size ((held), 0) != ((size_t) - 1)) ? g_free_sized
(held, __builtin_object_size ((held), 0)) : (g_free) (held)
;
1087 continue;
1088 }
1089
1090 if (held->seq != follow_info->seq[dir])
1091 break;
1092
1093 follow_info->seq[dir]++;
1094 follow_info->fragments[dir] = g_list_delete_link(follow_info->fragments[dir],
1095 follow_info->fragments[dir]);
1096 udx_follow_append(follow_info, held);
1097 }
1098}
1099
1100static tap_packet_status
1101udx_follow_tap_listener(void *tapdata, packet_info *pinfo, epan_dissect_t *edt _U___attribute__((unused)),
1102 const void *data, tap_flags_t flags _U___attribute__((unused)))
1103{
1104 follow_info_t *follow_info = (follow_info_t *) tapdata;
1105 const udx_follow_tap_data_t *follow_data = (const udx_follow_tap_data_t *) data;
1106 follow_record_t *record;
1107 unsigned length = tvb_captured_length(follow_data->tvb);
1108 int dir = follow_data->from_server ? 1 : 0;
1109
1110 if (follow_info->stream_id != follow_data->stream)
1111 return TAP_PACKET_DONT_REDRAW;
1112
1113 /* Already delivered: a retransmission or a duplicate. */
1114 if (follow_data->offset < follow_info->seq[dir])
1115 return TAP_PACKET_DONT_REDRAW;
1116
1117 record = g_new0(follow_record_t, 1)((follow_record_t *) g_malloc0_n ((1), sizeof (follow_record_t
)))
;
1118 record->is_server = follow_data->from_server;
1119 record->packet_num = pinfo->fd->num;
1120 record->abs_ts = pinfo->fd->abs_ts;
1121 record->seq = follow_data->offset;
1122 record->data = g_byte_array_sized_new(length);
1123 record->data = g_byte_array_append(record->data,
1124 tvb_get_ptr(follow_data->tvb, 0, length), length);
1125
1126 if (follow_data->from_server) {
1127 if (follow_info->server_port == 0) {
1128 follow_info->server_port = pinfo->srcport;
1129 copy_address(&follow_info->server_ip, &pinfo->src);
1130 follow_info->client_port = pinfo->destport;
1131 copy_address(&follow_info->client_ip, &pinfo->dst);
1132 }
1133 } else {
1134 if (follow_info->client_port == 0) {
1135 follow_info->client_port = pinfo->srcport;
1136 copy_address(&follow_info->client_ip, &pinfo->src);
1137 follow_info->server_port = pinfo->destport;
1138 copy_address(&follow_info->server_ip, &pinfo->dst);
1139 }
1140 }
1141
1142 if (follow_data->offset == follow_info->seq[dir]) {
1143 follow_info->seq[dir]++;
1144 udx_follow_append(follow_info, record);
1145 udx_follow_drain(follow_info, dir);
1146 } else {
1147 /* Arrived early: hold it, in order, until the gap ahead is filled.
1148 * The framework frees whatever is still pending when the stream is
1149 * reset, so an unfilled gap leaks nothing. */
1150 follow_info->fragments[dir] = g_list_insert_sorted(follow_info->fragments[dir],
1151 record, udx_follow_seq_cmp);
1152 }
1153
1154 return TAP_PACKET_DONT_REDRAW;
1155}
1156
1157static int
1158dissect_udx(tvbuff_t *tvb, packet_info *pinfo, proto_tree *tree, void *data _U___attribute__((unused)))
1159{
1160 proto_item *ti;
1161 proto_tree *udx_tree;
1162 uint8_t flags, data_offset;
1163 uint32_t id, window, seq, ack;
1164 int offset = 0;
1165 int sack_end_offset;
1166 unsigned payload_len;
1167 char flags_str[64];
1168 uint32_t sack_start[UDX_MAX_SACK_BLOCKS32];
1169 uint32_t sack_end[UDX_MAX_SACK_BLOCKS32];
1170 unsigned n_sacks = 0;
1171 udx_ppd_t *ppd = NULL((void*)0);
1172
1173 /*
1174 * Reached either from the heuristic, which has already validated the
1175 * header, or directly once a conversation has been claimed or through
1176 * "Decode As". The latter routes make this check load bearing.
1177 */
1178 if (tvb_reported_length(tvb) < UDX_HEADER_SIZE20)
1179 return 0;
1180
1181 col_set_str(pinfo->cinfo, COL_PROTOCOL, "UDX");
1182 col_clear(pinfo->cinfo, COL_INFO);
1183
1184 flags = tvb_get_uint8(tvb, 2);
1185 data_offset = tvb_get_uint8(tvb, 3);
1186 id = tvb_get_letohl(tvb, 4);
1187 window = tvb_get_letohl(tvb, 8);
1188 seq = tvb_get_letohl(tvb, 12);
1189 ack = tvb_get_letohl(tvb, 16);
1190
1191 udx_flags_to_str(flags, flags_str, sizeof(flags_str));
1192
1193 /* Collect the selective acknowledgement ranges before anything is added
1194 * to the tree: the analysis below needs them, and the display needs the
1195 * analysis. */
1196 if (flags & UDX_FLAG_SACK0x04) {
1197 /* Blocks fill the area delimited by data_offset; a packet with no
1198 * payload may leave that byte zero and run to the end instead. */
1199 sack_end_offset = (data_offset > 0)
1200 ? UDX_HEADER_SIZE20 + data_offset
1201 : (int) tvb_reported_length(tvb);
1202 } else {
1203 /* Anything reserved without SACK blocks is MTU probe padding. */
1204 sack_end_offset = UDX_HEADER_SIZE20 + data_offset;
1205 }
1206
1207 /* data_offset is not trustworthy on a packet this dissector did not
1208 * validate, so never let it point past the datagram. */
1209 sack_end_offset = MIN(sack_end_offset, (int) tvb_reported_length(tvb))(((sack_end_offset) < ((int) tvb_reported_length(tvb))) ? (
sack_end_offset) : ((int) tvb_reported_length(tvb)))
;
1210
1211 if (flags & UDX_FLAG_SACK0x04) {
1212 int pos = UDX_HEADER_SIZE20;
1213
1214 while (pos + 8 <= sack_end_offset && n_sacks < UDX_MAX_SACK_BLOCKS32) {
1215 sack_start[n_sacks] = tvb_get_letohl(tvb, pos);
1216 sack_end[n_sacks] = tvb_get_letohl(tvb, pos + 4);
1217 n_sacks++;
1218 pos += 8;
1219 }
1220 }
1221
1222 payload_len = (unsigned) MAX(0, (int) tvb_reported_length(tvb) - sack_end_offset)(((0) > ((int) tvb_reported_length(tvb) - sack_end_offset)
) ? (0) : ((int) tvb_reported_length(tvb) - sack_end_offset))
;
1223
1224 if (udx_analyze_sequence_numbers) {
1225 if (!PINFO_FD_VISITED(pinfo)((pinfo)->fd->visited)) {
1226 conversation_t *conversation = find_or_create_conversation(pinfo);
1227 udx_conv_t *conv;
1228
1229 conv = (udx_conv_t *) conversation_get_proto_data(conversation, proto_udx);
1230 if (conv == NULL((void*)0)) {
1231 conv = wmem_new0(wmem_file_scope(), udx_conv_t)((udx_conv_t*)wmem_alloc0((wmem_file_scope()), sizeof(udx_conv_t
)))
;
1232 conv->flows = wmem_map_new(wmem_file_scope(), g_int64_hash, g_int64_equal);
1233 conversation_add_proto_data(conversation, proto_udx, conv);
1234 }
1235
1236 ppd = wmem_new0(wmem_file_scope(), udx_ppd_t)((udx_ppd_t*)wmem_alloc0((wmem_file_scope()), sizeof(udx_ppd_t
)))
;
1237 udx_analyze(pinfo, conv, flags, data_offset, id, window, seq, ack,
1238 payload_len, sack_start, sack_end, n_sacks, ppd);
1239 p_add_proto_data(wmem_file_scope(), pinfo, proto_udx, 0, ppd);
1240 } else {
1241 ppd = (udx_ppd_t *) p_get_proto_data(wmem_file_scope(), pinfo, proto_udx, 0);
1242 }
1243 }
1244
1245 ti = proto_tree_add_item(tree, proto_udx, tvb, 0, -1, ENC_NA0x00000000);
1246 proto_item_append_text(ti, ", %s, Id: %u, Seq: %u, Ack: %u", flags_str, id, seq, ack);
1247 udx_tree = proto_item_add_subtree(ti, ett_udx);
1248
1249 proto_tree_add_item(udx_tree, hf_udx_magic, tvb, offset, 1, ENC_NA0x00000000);
1250 offset += 1;
1251 proto_tree_add_item(udx_tree, hf_udx_version, tvb, offset, 1, ENC_NA0x00000000);
1252 offset += 1;
1253 proto_tree_add_bitmask(udx_tree, tvb, offset, hf_udx_flags, ett_udx_flags,
1254 udx_flag_fields, ENC_NA0x00000000);
1255 offset += 1;
1256 proto_tree_add_item(udx_tree, hf_udx_data_offset, tvb, offset, 1, ENC_NA0x00000000);
1257 offset += 1;
1258 proto_tree_add_item(udx_tree, hf_udx_id, tvb, offset, 4, ENC_LITTLE_ENDIAN0x80000000);
1259 offset += 4;
1260 proto_tree_add_item(udx_tree, hf_udx_window, tvb, offset, 4, ENC_LITTLE_ENDIAN0x80000000);
1261 offset += 4;
1262 proto_tree_add_item(udx_tree, hf_udx_seq, tvb, offset, 4, ENC_LITTLE_ENDIAN0x80000000);
1263 offset += 4;
1264 proto_tree_add_item(udx_tree, hf_udx_ack, tvb, offset, 4, ENC_LITTLE_ENDIAN0x80000000);
1265 offset += 4;
1266
1267 if (n_sacks > 0) {
1268 proto_item *sacks_ti;
1269 proto_tree *sacks_tree, *block_tree;
1270
1271 sacks_ti = proto_tree_add_item(udx_tree, hf_udx_sacks, tvb, offset,
1272 sack_end_offset - offset, ENC_NA0x00000000);
1273 proto_item_append_text(sacks_ti, " (%u)", n_sacks);
1274 sacks_tree = proto_item_add_subtree(sacks_ti, ett_udx_sacks);
1275
1276 for (unsigned i = 0; i < n_sacks; i++) {
1277 block_tree = proto_tree_add_subtree_format(sacks_tree, tvb, offset, 8,
1278 ett_udx_sack_block, NULL((void*)0),
1279 "SACK: %u-%u",
1280 sack_start[i], sack_end[i]);
1281 proto_tree_add_item(block_tree, hf_udx_sack_start, tvb, offset, 4,
1282 ENC_LITTLE_ENDIAN0x80000000);
1283 proto_tree_add_item(block_tree, hf_udx_sack_end, tvb, offset + 4, 4,
1284 ENC_LITTLE_ENDIAN0x80000000);
1285 offset += 8;
1286 }
1287 } else if (!(flags & UDX_FLAG_SACK0x04) && data_offset > 0) {
1288 /*
1289 * Padding between header and payload with no SACK blocks: inserted by
1290 * mtu_probeify_packet() in libudx - this datagram is an MTU probe.
1291 */
1292 proto_tree_add_item(udx_tree, hf_udx_padding, tvb, offset, data_offset, ENC_NA0x00000000);
1293 offset += data_offset;
Value stored to 'offset' is never read
1294 }
1295
1296 if (payload_len > 0) {
1297 ti = proto_tree_add_uint(udx_tree, hf_udx_payload_len, tvb, 0, 0, payload_len);
1298 proto_item_set_generated(ti);
1299 proto_tree_add_item(udx_tree, hf_udx_payload, tvb, sack_end_offset,
1300 (int) payload_len, ENC_NA0x00000000);
1301 }
1302
1303 if (ppd != NULL((void*)0)) {
1304 udx_show_analysis(tvb, pinfo, udx_tree, ppd);
1305
1306 if (have_tap_listener(udx_tap)) {
1307 udx_info_t *udxh = wmem_new0(pinfo->pool, udx_info_t)((udx_info_t*)wmem_alloc0((pinfo->pool), sizeof(udx_info_t
)))
;
1308
1309 udxh->id = id;
1310 udxh->seq = seq;
1311 udxh->ack = ack;
1312 udxh->window = window;
1313 udxh->payload_len = payload_len;
1314 udxh->stream = ppd->stream;
1315 udxh->sport = pinfo->srcport;
1316 udxh->dport = pinfo->destport;
1317 udxh->flags = flags;
1318 udxh->data_offset = data_offset;
1319 copy_address_shallow(&udxh->ip_src, &pinfo->src);
1320 copy_address_shallow(&udxh->ip_dst, &pinfo->dst);
1321
1322 udxh->num_sack_blocks = n_sacks;
1323 for (unsigned i = 0; i < n_sacks; i++) {
1324 udxh->sack_start[i] = sack_start[i];
1325 udxh->sack_end[i] = sack_end[i];
1326 }
1327
1328 tap_queue_packet(udx_tap, pinfo, udxh);
1329 }
1330
1331 /* MESSAGE payloads travel outside the ordered stream, so they are
1332 * shown per packet but left out of the reassembled conversation. */
1333 if (ppd->follow_ok && !(flags & UDX_FLAG_MESSAGE0x08) &&
1334 have_tap_listener(udx_follow_tap)) {
1335 udx_follow_tap_data_t *follow_data = wmem_new0(pinfo->pool, udx_follow_tap_data_t)((udx_follow_tap_data_t*)wmem_alloc0((pinfo->pool), sizeof
(udx_follow_tap_data_t)))
;
1336
1337 follow_data->tvb = tvb_new_subset_length(tvb, sack_end_offset, (int) payload_len);
1338 follow_data->stream = ppd->stream;
1339 follow_data->offset = ppd->follow_offset;
1340 follow_data->from_server = ppd->from_server;
1341 tap_queue_packet(udx_follow_tap, pinfo, follow_data);
1342 }
1343 }
1344
1345 col_add_fstr(pinfo->cinfo, COL_INFO, "%s Id=%u Seq=%u Ack=%u Rwnd=%u",
1346 flags_str, id, seq, ack, window);
1347 if (payload_len > 0)
1348 col_append_fstr(pinfo->cinfo, COL_INFO, " Len=%u", payload_len);
1349 if (ppd != NULL((void*)0) && (ppd->flags & UDX_A_RETRANS0x0001))
1350 col_append_str(pinfo->cinfo, COL_INFO, " [retransmission]");
1351
1352 return tvb_reported_length(tvb);
1353}
1354
1355static bool_Bool
1356test_udx(tvbuff_t *tvb)
1357{
1358 uint8_t flags, data_offset;
1359
1360 if (tvb_captured_length(tvb) < UDX_HEADER_SIZE20)
1361 return false0;
1362 if (tvb_get_uint8(tvb, 0) != UDX_MAGIC_BYTE0xff)
1363 return false0;
1364 if (tvb_get_uint8(tvb, 1) != UDX_VERSION1)
1365 return false0;
1366
1367 flags = tvb_get_uint8(tvb, 2);
1368 if (flags & ~UDX_FLAG_MASK0x3f)
1369 return false0;
1370
1371 data_offset = tvb_get_uint8(tvb, 3);
1372 if (UDX_HEADER_SIZE20 + (unsigned) data_offset > tvb_reported_length(tvb))
1373 return false0;
1374 /* The area delimited by data_offset holds SACK blocks (uint32 pairs) when
1375 * the SACK flag is set - anything not a multiple of 8 is not UDX. */
1376 if ((flags & UDX_FLAG_SACK0x04) && data_offset > 0 && (data_offset % 8) != 0)
1377 return false0;
1378
1379 /*
1380 * Only DATA and MESSAGE packets carry a payload. Everything else is the
1381 * fixed header followed at most by selective acknowledgement blocks, so
1382 * its length is known exactly and anything else is not UDX.
1383 */
1384 if (!(flags & (UDX_FLAG_DATA0x01 | UDX_FLAG_MESSAGE0x08))) {
1385 unsigned trailing = tvb_reported_length(tvb) - UDX_HEADER_SIZE20;
1386
1387 if (flags & UDX_FLAG_SACK0x04) {
1388 if ((trailing % 8) != 0)
1389 return false0;
1390 } else if (trailing != 0) {
1391 return false0;
1392 }
1393 }
1394
1395 return true1;
1396}
1397
1398static bool_Bool
1399dissect_udx_heur(tvbuff_t *tvb, packet_info *pinfo, proto_tree *tree, void *data)
1400{
1401 conversation_t *conversation;
1402
1403 if (!test_udx(tvb))
1404 return false0;
1405
1406 /* Claim the whole UDP conversation so weaker frames (e.g. bare 20-byte
1407 * heartbeats) and future packets skip the heuristic. */
1408 conversation = find_or_create_conversation(pinfo);
1409 conversation_set_dissector(conversation, udx_handle);
1410
1411 dissect_udx(tvb, pinfo, tree, data);
1412 return true1;
1413}
1414
1415void
1416proto_register_udx(void)
1417{
1418 static hf_register_info hf[] = {
1419 { &hf_udx_magic,
1420 { "Magic Byte", "udx.magic_byte", FT_UINT8, BASE_HEX, NULL((void*)0), 0x0,
1421 "Always 0xff", HFILL-1, 0, HF_REF_TYPE_NONE, -1, ((void*)0) }
1422 },
1423 { &hf_udx_version,
1424 { "Version", "udx.version", FT_UINT8, BASE_DEC, NULL((void*)0), 0x0,
1425 NULL((void*)0), HFILL-1, 0, HF_REF_TYPE_NONE, -1, ((void*)0) }
1426 },
1427 { &hf_udx_flags,
1428 { "Type", "udx.type", FT_UINT8, BASE_HEX, NULL((void*)0), 0x0,
1429 "Packet type flags", HFILL-1, 0, HF_REF_TYPE_NONE, -1, ((void*)0) }
1430 },
1431 { &hf_udx_flags_data,
1432 { "Data", "udx.type.data", FT_BOOLEAN, 8, NULL((void*)0), UDX_FLAG_DATA0x01,
1433 "Carries stream payload", HFILL-1, 0, HF_REF_TYPE_NONE, -1, ((void*)0) }
1434 },
1435 { &hf_udx_flags_end,
1436 { "End", "udx.type.end", FT_BOOLEAN, 8, NULL((void*)0), UDX_FLAG_END0x02,
1437 "Graceful end of stream (consumes a sequence number)", HFILL-1, 0, HF_REF_TYPE_NONE, -1, ((void*)0) }
1438 },
1439 { &hf_udx_flags_sack,
1440 { "SACK", "udx.type.sack", FT_BOOLEAN, 8, NULL((void*)0), UDX_FLAG_SACK0x04,
1441 "Carries selective acknowledgement blocks", HFILL-1, 0, HF_REF_TYPE_NONE, -1, ((void*)0) }
1442 },
1443 { &hf_udx_flags_message,
1444 { "Message", "udx.type.message", FT_BOOLEAN, 8, NULL((void*)0), UDX_FLAG_MESSAGE0x08,
1445 "Unordered datagram outside the byte stream", HFILL-1, 0, HF_REF_TYPE_NONE, -1, ((void*)0) }
1446 },
1447 { &hf_udx_flags_destroy,
1448 { "Destroy", "udx.type.destroy", FT_BOOLEAN, 8, NULL((void*)0), UDX_FLAG_DESTROY0x10,
1449 "Abrupt stream termination", HFILL-1, 0, HF_REF_TYPE_NONE, -1, ((void*)0) }
1450 },
1451 { &hf_udx_flags_heartbeat,
1452 { "Heartbeat", "udx.type.heartbeat", FT_BOOLEAN, 8, NULL((void*)0), UDX_FLAG_HEARTBEAT0x20,
1453 "Keepalive or zero-window probe", HFILL-1, 0, HF_REF_TYPE_NONE, -1, ((void*)0) }
1454 },
1455 { &hf_udx_data_offset,
1456 { "Data Offset", "udx.data_offset", FT_UINT8, BASE_DEC, NULL((void*)0), 0x0,
1457 "Bytes between the fixed header and the payload", HFILL-1, 0, HF_REF_TYPE_NONE, -1, ((void*)0) }
1458 },
1459 { &hf_udx_id,
1460 { "Id", "udx.id", FT_UINT32, BASE_DEC, NULL((void*)0), 0x0,
1461 "Receiver's stream id", HFILL-1, 0, HF_REF_TYPE_NONE, -1, ((void*)0) }
1462 },
1463 { &hf_udx_window,
1464 { "Window", "udx.rwnd", FT_UINT32, BASE_DEC, NULL((void*)0), 0x0,
1465 "Sender's receive window in bytes", HFILL-1, 0, HF_REF_TYPE_NONE, -1, ((void*)0) }
1466 },
1467 { &hf_udx_seq,
1468 { "Seq", "udx.seq", FT_UINT32, BASE_DEC, NULL((void*)0), 0x0,
1469 "Packet sequence number (counts packets, not bytes)", HFILL-1, 0, HF_REF_TYPE_NONE, -1, ((void*)0) }
1470 },
1471 { &hf_udx_ack,
1472 { "Ack", "udx.ack", FT_UINT32, BASE_DEC, NULL((void*)0), 0x0,
1473 "Next sequence number expected from the peer", HFILL-1, 0, HF_REF_TYPE_NONE, -1, ((void*)0) }
1474 },
1475 { &hf_udx_sacks,
1476 { "SACK Blocks", "udx.sacks", FT_NONE, BASE_NONE, NULL((void*)0), 0x0,
1477 "Selective acknowledgement ranges", HFILL-1, 0, HF_REF_TYPE_NONE, -1, ((void*)0) }
1478 },
1479 { &hf_udx_sack_block,
1480 { "SACK Block", "udx.sack", FT_NONE, BASE_NONE, NULL((void*)0), 0x0,
1481 NULL((void*)0), HFILL-1, 0, HF_REF_TYPE_NONE, -1, ((void*)0) }
1482 },
1483 { &hf_udx_sack_start,
1484 { "Start", "udx.sack.start", FT_UINT32, BASE_DEC, NULL((void*)0), 0x0,
1485 "First sequence number in the acknowledged range", HFILL-1, 0, HF_REF_TYPE_NONE, -1, ((void*)0) }
1486 },
1487 { &hf_udx_sack_end,
1488 { "End", "udx.sack.end", FT_UINT32, BASE_DEC, NULL((void*)0), 0x0,
1489 "One past the last acknowledged sequence number", HFILL-1, 0, HF_REF_TYPE_NONE, -1, ((void*)0) }
1490 },
1491 { &hf_udx_padding,
1492 { "Padding", "udx.padding", FT_BYTES, BASE_NONE, NULL((void*)0), 0x0,
1493 "MTU probe padding", HFILL-1, 0, HF_REF_TYPE_NONE, -1, ((void*)0) }
1494 },
1495 { &hf_udx_payload,
1496 { "Payload", "udx.payload", FT_BYTES, BASE_NONE, NULL((void*)0), 0x0,
1497 NULL((void*)0), HFILL-1, 0, HF_REF_TYPE_NONE, -1, ((void*)0) }
1498 },
1499 { &hf_udx_payload_len,
1500 { "Payload Length", "udx.length", FT_UINT32, BASE_DEC, NULL((void*)0), 0x0,
1501 NULL((void*)0), HFILL-1, 0, HF_REF_TYPE_NONE, -1, ((void*)0) }
1502 },
1503 { &hf_udx_stream,
1504 { "Stream index", "udx.stream", FT_UINT32, BASE_DEC, NULL((void*)0), 0x0,
1505 "Index of the paired flows carrying this stream", HFILL-1, 0, HF_REF_TYPE_NONE, -1, ((void*)0) }
1506 },
1507 { &hf_udx_analysis,
1508 { "SEQ/ACK analysis", "udx.analysis", FT_NONE, BASE_NONE, NULL((void*)0), 0x0,
1509 "Results of the sequence number analysis", HFILL-1, 0, HF_REF_TYPE_NONE, -1, ((void*)0) }
1510 },
1511 { &hf_udx_analysis_acks_frame,
1512 { "This is an ACK to the packet in frame", "udx.analysis.acks_frame",
1513 FT_FRAMENUM, BASE_NONE, FRAMENUM_TYPE(FT_FRAMENUM_ACK)((gpointer) (glong) (FT_FRAMENUM_ACK)), 0x0,
1514 NULL((void*)0), HFILL-1, 0, HF_REF_TYPE_NONE, -1, ((void*)0) }
1515 },
1516 { &hf_udx_analysis_acked_in,
1517 { "ACKed in frame", "udx.analysis.acked_in", FT_FRAMENUM, BASE_NONE,
1518 FRAMENUM_TYPE(FT_FRAMENUM_NONE)((gpointer) (glong) (FT_FRAMENUM_NONE)), 0x0,
1519 "The frame that acknowledged this packet", HFILL-1, 0, HF_REF_TYPE_NONE, -1, ((void*)0) }
1520 },
1521 { &hf_udx_analysis_ack_rtt,
1522 { "Time to ACK", "udx.analysis.ack_rtt", FT_RELATIVE_TIME, BASE_NONE, NULL((void*)0), 0x0,
1523 "Time between the packet and its acknowledgement", HFILL-1, 0, HF_REF_TYPE_NONE, -1, ((void*)0) }
1524 },
1525 { &hf_udx_analysis_bytes_in_flight,
1526 { "Bytes in flight", "udx.analysis.bytes_in_flight", FT_UINT32, BASE_DEC,
1527 NULL((void*)0), 0x0, "Unacknowledged payload bytes on this flow", HFILL-1, 0, HF_REF_TYPE_NONE, -1, ((void*)0) }
1528 },
1529 { &hf_udx_analysis_pkts_in_flight,
1530 { "Packets in flight", "udx.analysis.packets_in_flight", FT_UINT32, BASE_DEC,
1531 NULL((void*)0), 0x0, "Unacknowledged packets on this flow", HFILL-1, 0, HF_REF_TYPE_NONE, -1, ((void*)0) }
1532 },
1533 { &hf_udx_analysis_no_reverse,
1534 { "Reverse flow not identified", "udx.analysis.no_reverse", FT_NONE, BASE_NONE,
1535 NULL((void*)0), 0x0, "The stream carrying the other direction has not been paired",
1536 HFILL-1, 0, HF_REF_TYPE_NONE, -1, ((void*)0) }
1537 },
1538 };
1539
1540 static int *ett[] = {
1541 &ett_udx,
1542 &ett_udx_flags,
1543 &ett_udx_sacks,
1544 &ett_udx_sack_block,
1545 &ett_udx_analysis,
1546 };
1547
1548 static ei_register_info ei[] = {
1549 { &ei_udx_retrans,
1550 { "udx.analysis.retransmission", PI_SEQUENCE0x02000000, PI_NOTE0x00400000,
1551 "This packet was retransmitted", EXPFILL0, ((void*)0), 0, ((void*)0), {0, {((void*)0), ((void*)0), FT_NONE
, BASE_NONE, ((void*)0), 0, ((void*)0), -1, 0, HF_REF_TYPE_NONE
, -1, ((void*)0)}}
}
1552 },
1553 { &ei_udx_fast_retrans,
1554 { "udx.analysis.fast_retransmission", PI_SEQUENCE0x02000000, PI_NOTE0x00400000,
1555 "Fast retransmission: resent while later packets were selectively"
1556 " acknowledged", EXPFILL0, ((void*)0), 0, ((void*)0), {0, {((void*)0), ((void*)0), FT_NONE
, BASE_NONE, ((void*)0), 0, ((void*)0), -1, 0, HF_REF_TYPE_NONE
, -1, ((void*)0)}}
}
1557 },
1558 { &ei_udx_rto_retrans,
1559 { "udx.analysis.rto_retransmission", PI_SEQUENCE0x02000000, PI_NOTE0x00400000,
1560 "Retransmission timeout: resent after more than the estimated RTO",
1561 EXPFILL0, ((void*)0), 0, ((void*)0), {0, {((void*)0), ((void*)0), FT_NONE
, BASE_NONE, ((void*)0), 0, ((void*)0), -1, 0, HF_REF_TYPE_NONE
, -1, ((void*)0)}}
}
1562 },
1563 { &ei_udx_tlp,
1564 { "udx.analysis.tail_loss_probe", PI_SEQUENCE0x02000000, PI_NOTE0x00400000,
1565 "Tail loss probe: sent after a pause to draw an acknowledgement"
1566 " out of the peer", EXPFILL0, ((void*)0), 0, ((void*)0), {0, {((void*)0), ((void*)0), FT_NONE
, BASE_NONE, ((void*)0), 0, ((void*)0), -1, 0, HF_REF_TYPE_NONE
, -1, ((void*)0)}}
}
1567 },
1568 { &ei_udx_spurious_retrans,
1569 { "udx.analysis.spurious_retransmission", PI_SEQUENCE0x02000000, PI_NOTE0x00400000,
1570 "Spurious retransmission: this packet was already acknowledged", EXPFILL0, ((void*)0), 0, ((void*)0), {0, {((void*)0), ((void*)0), FT_NONE
, BASE_NONE, ((void*)0), 0, ((void*)0), -1, 0, HF_REF_TYPE_NONE
, -1, ((void*)0)}}
}
1571 },
1572 { &ei_udx_duplicate,
1573 { "udx.analysis.duplicate", PI_SEQUENCE0x02000000, PI_NOTE0x00400000,
1574 "Duplicate packet: the same packet was seen twice in quick succession",
1575 EXPFILL0, ((void*)0), 0, ((void*)0), {0, {((void*)0), ((void*)0), FT_NONE
, BASE_NONE, ((void*)0), 0, ((void*)0), -1, 0, HF_REF_TYPE_NONE
, -1, ((void*)0)}}
}
1576 },
1577 { &ei_udx_out_of_order,
1578 { "udx.analysis.out_of_order", PI_SEQUENCE0x02000000, PI_NOTE0x00400000,
1579 "Out-of-order packet", EXPFILL0, ((void*)0), 0, ((void*)0), {0, {((void*)0), ((void*)0), FT_NONE
, BASE_NONE, ((void*)0), 0, ((void*)0), -1, 0, HF_REF_TYPE_NONE
, -1, ((void*)0)}}
}
1580 },
1581 { &ei_udx_lost_segment,
1582 { "udx.analysis.lost_segment", PI_SEQUENCE0x02000000, PI_WARN0x00600000,
1583 "Previous packet not captured: a sequence number was skipped", EXPFILL0, ((void*)0), 0, ((void*)0), {0, {((void*)0), ((void*)0), FT_NONE
, BASE_NONE, ((void*)0), 0, ((void*)0), -1, 0, HF_REF_TYPE_NONE
, -1, ((void*)0)}}
}
1584 },
1585 { &ei_udx_keepalive,
1586 { "udx.analysis.keepalive", PI_SEQUENCE0x02000000, PI_NOTE0x00400000,
1587 "Keepalive", EXPFILL0, ((void*)0), 0, ((void*)0), {0, {((void*)0), ((void*)0), FT_NONE
, BASE_NONE, ((void*)0), 0, ((void*)0), -1, 0, HF_REF_TYPE_NONE
, -1, ((void*)0)}}
}
1588 },
1589 { &ei_udx_zero_window_probe,
1590 { "udx.analysis.zero_window_probe", PI_SEQUENCE0x02000000, PI_NOTE0x00400000,
1591 "Zero window probe: sent while the peer advertised no receive window",
1592 EXPFILL0, ((void*)0), 0, ((void*)0), {0, {((void*)0), ((void*)0), FT_NONE
, BASE_NONE, ((void*)0), 0, ((void*)0), -1, 0, HF_REF_TYPE_NONE
, -1, ((void*)0)}}
}
1593 },
1594 { &ei_udx_zero_window,
1595 { "udx.analysis.zero_window", PI_SEQUENCE0x02000000, PI_WARN0x00600000,
1596 "Zero window: the sender cannot accept more data", EXPFILL0, ((void*)0), 0, ((void*)0), {0, {((void*)0), ((void*)0), FT_NONE
, BASE_NONE, ((void*)0), 0, ((void*)0), -1, 0, HF_REF_TYPE_NONE
, -1, ((void*)0)}}
}
1597 },
1598 { &ei_udx_window_update,
1599 { "udx.analysis.window_update", PI_SEQUENCE0x02000000, PI_CHAT0x00200000,
1600 "Window update: the receive window reopened", EXPFILL0, ((void*)0), 0, ((void*)0), {0, {((void*)0), ((void*)0), FT_NONE
, BASE_NONE, ((void*)0), 0, ((void*)0), -1, 0, HF_REF_TYPE_NONE
, -1, ((void*)0)}}
}
1601 },
1602 { &ei_udx_mtu_probe,
1603 { "udx.analysis.mtu_probe", PI_SEQUENCE0x02000000, PI_CHAT0x00200000,
1604 "MTU probe: padded to test a larger path MTU", EXPFILL0, ((void*)0), 0, ((void*)0), {0, {((void*)0), ((void*)0), FT_NONE
, BASE_NONE, ((void*)0), 0, ((void*)0), -1, 0, HF_REF_TYPE_NONE
, -1, ((void*)0)}}
}
1605 },
1606 { &ei_udx_end,
1607 { "udx.analysis.end", PI_SEQUENCE0x02000000, PI_CHAT0x00200000,
1608 "End of stream", EXPFILL0, ((void*)0), 0, ((void*)0), {0, {((void*)0), ((void*)0), FT_NONE
, BASE_NONE, ((void*)0), 0, ((void*)0), -1, 0, HF_REF_TYPE_NONE
, -1, ((void*)0)}}
}
1609 },
1610 { &ei_udx_destroy,
1611 { "udx.analysis.destroy", PI_SEQUENCE0x02000000, PI_WARN0x00600000,
1612 "Stream destroyed: abrupt termination", EXPFILL0, ((void*)0), 0, ((void*)0), {0, {((void*)0), ((void*)0), FT_NONE
, BASE_NONE, ((void*)0), 0, ((void*)0), -1, 0, HF_REF_TYPE_NONE
, -1, ((void*)0)}}
}
1613 },
1614 };
1615
1616 expert_module_t *expert_udx;
1617 module_t *udx_module;
1618
1619 proto_udx = proto_register_protocol("UDX Protocol", "UDX", "udx");
1620 proto_register_field_array(proto_udx, hf, array_length(hf)(sizeof (hf) / sizeof (hf)[0]));
1621 proto_register_subtree_array(ett, array_length(ett)(sizeof (ett) / sizeof (ett)[0]));
1622
1623 expert_udx = expert_register_protocol(proto_udx);
1624 expert_register_field_array(expert_udx, ei, array_length(ei)(sizeof (ei) / sizeof (ei)[0]));
1625
1626 udx_handle = register_dissector("udx", dissect_udx, proto_udx);
1627
1628 register_init_routine(udx_init);
1629
1630 udx_follow_tap = register_tap("udx_follow");
1631 register_follow_stream(proto_udx, "udx_follow",
1632 udx_follow_conv_filter, udx_follow_index_filter,
1633 udp_follow_address_filter, udp_port_to_display,
1634 udx_follow_tap_listener, udx_get_stream_count, NULL((void*)0));
1635
1636 /* The conversation and endpoint tables read this tap. It carries the
1637 * stream index, which only exists while sequence analysis is on, so the
1638 * tables follow the "analyze_sequence_numbers" preference. */
1639 udx_tap = register_tap("udx");
1640 register_conversation_table(proto_udx, false0,
1641 udx_conversation_packet, udx_endpoint_packet);
1642
1643 udx_module = prefs_register_protocol(proto_udx, NULL((void*)0));
1644 prefs_register_bool_preference(udx_module, "analyze_sequence_numbers",
1645 "Analyze UDX sequence numbers",
1646 "Track sequence and acknowledgement numbers to pair flows, measure "
1647 "round-trip times and flag retransmissions",
1648 &udx_analyze_sequence_numbers);
1649}
1650
1651void
1652proto_reg_handoff_udx(void)
1653{
1654 heur_dissector_add("udp", dissect_udx_heur, "UDX over UDP", "udx_udp",
1655 proto_udx, HEURISTIC_DISABLE);
1656 dissector_add_for_decode_as_with_preference("udp.port", udx_handle);
1657}
1658
1659/*
1660 * Editor modelines - https://www.wireshark.org/tools/modelines.html
1661 *
1662 * Local variables:
1663 * c-basic-offset: 4
1664 * tab-width: 8
1665 * indent-tabs-mode: nil
1666 * End:
1667 *
1668 * vi: set shiftwidth=4 tabstop=8 expandtab:
1669 * :indentSize=4:tabSize=8:noTabs=true:
1670 */