/src/wireshark/epan/dissectors/packet-bt-utp.c
Line | Count | Source |
1 | | /* packet-bt-utp.c |
2 | | * Routines for BT-UTP dissection |
3 | | * Copyright 2011, Xiao Xiangquan <xiaoxiangquan@gmail.com> |
4 | | * Copyright 2021, John Thacker <johnthacker@gmail.com> |
5 | | * |
6 | | * Wireshark - Network traffic analyzer |
7 | | * By Gerald Combs <gerald@wireshark.org> |
8 | | * Copyright 1999 Gerald Combs |
9 | | * |
10 | | * SPDX-License-Identifier: GPL-2.0-or-later |
11 | | */ |
12 | | |
13 | | #include "config.h" |
14 | | |
15 | | #include <epan/packet.h> |
16 | | #include <epan/conversation.h> |
17 | | #include <epan/exceptions.h> |
18 | | #include <epan/show_exception.h> |
19 | | #include <epan/expert.h> |
20 | | #include <epan/prefs.h> |
21 | | #include <epan/proto_data.h> |
22 | | #include <epan/unit_strings.h> |
23 | | |
24 | | #include "packet-bt-utp.h" |
25 | | |
26 | | void proto_register_bt_utp(void); |
27 | | void proto_reg_handoff_bt_utp(void); |
28 | | |
29 | | enum { |
30 | | ST_DATA = 0, |
31 | | ST_FIN = 1, |
32 | | ST_STATE = 2, |
33 | | ST_RESET = 3, |
34 | | ST_SYN = 4, |
35 | | ST_NUM_STATES |
36 | | }; |
37 | | |
38 | | /* V0 hdr: "flags"; V1 hdr: "type" */ |
39 | | static const value_string bt_utp_type_vals[] = { |
40 | | { ST_DATA, "Data" }, |
41 | | { ST_FIN, "Fin" }, |
42 | | { ST_STATE, "State" }, |
43 | | { ST_RESET, "Reset" }, |
44 | | { ST_SYN, "Syn" }, |
45 | | { 0, NULL } |
46 | | }; |
47 | | |
48 | | enum { |
49 | | EXT_NO_EXTENSION = 0, |
50 | | EXT_SELECTIVE_ACKS = 1, |
51 | | EXT_EXTENSION_BITS = 2, |
52 | | EXT_CLOSE_REASON = 3, |
53 | | EXT_NUM_EXT |
54 | | }; |
55 | | |
56 | | static const value_string bt_utp_extension_type_vals[] = { |
57 | | { EXT_NO_EXTENSION, "No Extension" }, |
58 | | { EXT_SELECTIVE_ACKS, "Selective ACKs" }, |
59 | | { EXT_EXTENSION_BITS, "Extension bits" }, |
60 | | { EXT_CLOSE_REASON, "Close reason" }, |
61 | | { 0, NULL } |
62 | | }; |
63 | | |
64 | | /* https://github.com/arvidn/libtorrent/blob/master/include/libtorrent/close_reason.hpp */ |
65 | | static const value_string bt_utp_close_reason_vals[] = { |
66 | | { 0, "None" }, |
67 | | { 1, "Duplicate peer ID" }, |
68 | | { 2, "Torrent removed" }, |
69 | | { 3, "Memory allocation failed" }, |
70 | | { 4, "Port blocked" }, |
71 | | { 5, "Address blocked" }, |
72 | | { 6, "Upload to upload" }, |
73 | | { 7, "Not interested upload only" }, |
74 | | { 8, "Timeout" }, |
75 | | { 9, "Timeout: interest" }, |
76 | | { 10, "Timeout: activity" }, |
77 | | { 11, "Timeout: handshake" }, |
78 | | { 12, "Timeout: request" }, |
79 | | { 13, "Protocol blocked" }, |
80 | | { 14, "Peer churn" }, |
81 | | { 15, "Too many connections" }, |
82 | | { 16, "Too many files" }, |
83 | | /* Reasons caused by the peer sending unexpected data are 256 and up */ |
84 | | {256, "Encryption error" }, |
85 | | {257, "Invalid info hash" }, |
86 | | {258, "Self connection" }, |
87 | | {259, "Invalid metadata" }, |
88 | | {260, "Metadata too big" }, |
89 | | {261, "Message too big" }, |
90 | | {262, "Invalid message id" }, |
91 | | {263, "Invalid message" }, |
92 | | {264, "Invalid piece message" }, |
93 | | {265, "Invalid have message" }, |
94 | | {266, "Invalid bitfield message" }, |
95 | | {267, "Invalid choke message" }, |
96 | | {268, "Invalid unchoke message" }, |
97 | | {269, "Invalid interested message" }, |
98 | | {270, "Invalid not interested message" }, |
99 | | {271, "Invalid request message" }, |
100 | | {272, "Invalid reject message" }, |
101 | | {273, "Invalid allow fast message" }, |
102 | | {274, "Invalid extended message" }, |
103 | | {275, "Invalid cancel message" }, |
104 | | {276, "Invalid DHT port message" }, |
105 | | {277, "Invalid suggest message" }, |
106 | | {278, "Invalid have all message" }, |
107 | | {279, "Invalid don't have message" }, |
108 | | {280, "Invalid PEX message" }, |
109 | | {281, "Invalid metadata request message" }, |
110 | | {282, "Invalid metadata message" }, |
111 | | {283, "Invalid metadata offset" }, |
112 | | {284, "Request when choked" }, |
113 | | {285, "Corrupt pieces" }, |
114 | | {286, "PEX message too big" }, |
115 | | {287, "PEX too frequent" }, |
116 | | { 0, NULL } |
117 | | }; |
118 | | |
119 | | static int proto_bt_utp; |
120 | | |
121 | | /* --- "Original" uTP Header ("version 0" ?) -------------- |
122 | | |
123 | | See utp.cpp source code @ https://github.com/bittorrent/libutp |
124 | | |
125 | | -- Fixed Header -- |
126 | | 0 4 8 16 24 32 |
127 | | +-------+-------+---------------+---------------+---------------+ |
128 | | | connection_id | |
129 | | +-------+-------+---------------+---------------+---------------+ |
130 | | | timestamp_seconds | |
131 | | +---------------+---------------+---------------+---------------+ |
132 | | | timestamp_microseconds | |
133 | | +---------------+---------------+---------------+---------------+ |
134 | | | timestamp_difference_microseconds | |
135 | | +---------------+---------------+---------------+---------------+ |
136 | | | wnd_size | ext | flags | seq_nr [ho] | |
137 | | +---------------+---------------+---------------+---------------+ |
138 | | | seq_nr [lo] | ack_nr | |
139 | | +---------------+---------------+---------------+ |
140 | | |
141 | | -- Extension Field(s) -- |
142 | | 0 8 16 |
143 | | +---------------+---------------+---------------+---------------+ |
144 | | | extension | len | bitmask |
145 | | +---------------+---------------+---------------+---------------+ |
146 | | | |
147 | | +---------------+---------------+.... |
148 | | |
149 | | */ |
150 | | |
151 | | /* --- Version 1 Header ---------------- |
152 | | |
153 | | Specifications: BEP-0029 |
154 | | http://www.bittorrent.org/beps/bep_0029.html |
155 | | |
156 | | -- Fixed Header -- |
157 | | Fields Types |
158 | | 0 4 8 16 24 32 |
159 | | +-------+-------+---------------+---------------+---------------+ |
160 | | | type | ver | extension | connection_id | |
161 | | +-------+-------+---------------+---------------+---------------+ |
162 | | | timestamp_microseconds | |
163 | | +---------------+---------------+---------------+---------------+ |
164 | | | timestamp_difference_microseconds | |
165 | | +---------------+---------------+---------------+---------------+ |
166 | | | wnd_size | |
167 | | +---------------+---------------+---------------+---------------+ |
168 | | | seq_nr | ack_nr | |
169 | | +---------------+---------------+---------------+---------------+ |
170 | | |
171 | | -- Extension Field(s) -- |
172 | | 0 8 16 |
173 | | +---------------+---------------+---------------+---------------+ |
174 | | | extension | len | bitmask |
175 | | +---------------+---------------+---------------+---------------+ |
176 | | | |
177 | | +---------------+---------------+.... |
178 | | */ |
179 | | |
180 | 0 | #define V0_FIXED_HDR_SIZE 23 |
181 | 0 | #define V1_FIXED_HDR_SIZE 20 |
182 | | |
183 | | /* Very early versions of libutp (still used by Transmission) set the max |
184 | | * recv window size to 0x00380000, versions from 2013 and later set it to |
185 | | * 0x00100000, and some other clients use 0x00040000. This is one of the |
186 | | * few possible sources of heuristics. |
187 | | */ |
188 | | |
189 | | #define V1_MAX_WINDOW_SIZE 0x380000U |
190 | | |
191 | | static dissector_handle_t bt_utp_handle; |
192 | | static dissector_handle_t bittorrent_handle; |
193 | | |
194 | | static int hf_bt_utp_ver; |
195 | | static int hf_bt_utp_type; |
196 | | static int hf_bt_utp_flags; |
197 | | static int hf_bt_utp_extension; |
198 | | static int hf_bt_utp_next_extension_type; |
199 | | static int hf_bt_utp_extension_len; |
200 | | static int hf_bt_utp_extension_bitmask; |
201 | | static int hf_bt_utp_extension_close_reason; |
202 | | static int hf_bt_utp_extension_unknown; |
203 | | static int hf_bt_utp_connection_id_v0; |
204 | | static int hf_bt_utp_connection_id_v1; |
205 | | static int hf_bt_utp_stream; |
206 | | static int hf_bt_utp_timestamp_sec; |
207 | | static int hf_bt_utp_timestamp_us; |
208 | | static int hf_bt_utp_timestamp_diff_us; |
209 | | static int hf_bt_utp_wnd_size_v0; |
210 | | static int hf_bt_utp_wnd_size_v1; |
211 | | static int hf_bt_utp_seq_nr; |
212 | | static int hf_bt_utp_ack_nr; |
213 | | static int hf_bt_utp_len; |
214 | | static int hf_bt_utp_data; |
215 | | static int hf_bt_utp_pdu_size; |
216 | | static int hf_bt_utp_continuation_to; |
217 | | |
218 | | static expert_field ei_extension_len_invalid; |
219 | | |
220 | | static int ett_bt_utp; |
221 | | static int ett_bt_utp_extension; |
222 | | |
223 | | static bool enable_version0; |
224 | | static unsigned max_window_size = V1_MAX_WINDOW_SIZE; |
225 | | /* XXX: Desegmentation and OOO-reassembly are not supported yet */ |
226 | | static bool utp_desegment; |
227 | | /*static bool utp_reassemble_out_of_order = false;*/ |
228 | | static bool utp_analyze_seq = true; |
229 | | |
230 | | static uint32_t bt_utp_stream_count; |
231 | | |
232 | | typedef struct _utp_multisegment_pdu { |
233 | | |
234 | | uint16_t first_seq; |
235 | | uint16_t last_seq; |
236 | | unsigned first_seq_start_offset; |
237 | | unsigned last_seq_end_offset; |
238 | | /*int length; |
239 | | uint32_t reassembly_id;*/ |
240 | | uint32_t first_frame; |
241 | | |
242 | | } utp_multisegment_pdu; |
243 | | |
244 | | typedef struct _utp_flow_t { |
245 | | #if 0 |
246 | | /* XXX: Some other things to add in later. */ |
247 | | bool base_seq_set; |
248 | | uint16_t base_seq; |
249 | | uint32_t fin; |
250 | | uint32_t window; |
251 | | uint32_t maxnextseq; |
252 | | #endif |
253 | | |
254 | | wmem_tree_t *multisegment_pdus; |
255 | | } utp_flow_t; |
256 | | |
257 | | typedef struct { |
258 | | uint32_t stream; |
259 | | |
260 | | utp_flow_t flow[2]; |
261 | | utp_flow_t *fwd; |
262 | | utp_flow_t *rev; |
263 | | #if 0 |
264 | | /* XXX: Some other things to add in later. */ |
265 | | nstime_t ts_first; |
266 | | nstime_t ts_prev; |
267 | | uint8_t conversation_completeness; |
268 | | #endif |
269 | | } utp_stream_info_t; |
270 | | |
271 | | /* Per-packet header information. */ |
272 | | typedef struct { |
273 | | uint8_t type; |
274 | | bool v0; |
275 | | uint32_t connection; /* The prelease "V0" version is 32 bit */ |
276 | | uint32_t stream; |
277 | | uint16_t seq; |
278 | | uint16_t ack; |
279 | | uint32_t seglen; /* reported length remaining */ |
280 | | bool have_seglen; |
281 | | |
282 | | proto_tree *tree; /* For the bittorrent subdissector to access */ |
283 | | } utp_info_t; |
284 | | |
285 | | static utp_stream_info_t* |
286 | | get_utp_stream_info(packet_info *pinfo, utp_info_t *utp_info) |
287 | 0 | { |
288 | 0 | conversation_t* conv; |
289 | 0 | utp_stream_info_t *stream_info; |
290 | 0 | uint32_t id_up, id_down; |
291 | 0 | int direction; |
292 | | |
293 | | /* Handle connection ID wrapping correctly. (Mainline libutp source |
294 | | * does not appear to do this, probably fails to connect if the random |
295 | | * connection ID is GMAX_UINT16 and tries again.) |
296 | | */ |
297 | 0 | if (utp_info->v0) { |
298 | 0 | id_up = utp_info->connection+1; |
299 | 0 | id_down = utp_info->connection-1; |
300 | 0 | } else { |
301 | 0 | id_up = (uint16_t)(utp_info->connection+1); |
302 | 0 | id_down = (uint16_t)(utp_info->connection-1); |
303 | 0 | } |
304 | |
|
305 | 0 | if (utp_info->type == ST_SYN) { |
306 | | /* SYN packets are special, they have the connection ID for the other |
307 | | * side, and allow us to know both. |
308 | | */ |
309 | 0 | conv = find_conversation(pinfo->num, &pinfo->src, &pinfo->dst, CONVERSATION_BT_UTP, |
310 | 0 | id_up, utp_info->connection, 0); |
311 | 0 | if (!conv) { |
312 | | /* XXX: A SYN for between the same pair of hosts with a duplicate |
313 | | * connection ID in the same direction is almost surely a retransmission |
314 | | * (unless there's a client that doesn't actually generate random IDs.) |
315 | | * We could check to see if we've gotten a FIN or RST on that same |
316 | | * connection, and also could do like TCP and see if the initial sequence |
317 | | * number matches. (The latter still doesn't help if the client also |
318 | | * doesn't start with random sequence numbers.) |
319 | | */ |
320 | 0 | conv = conversation_new(pinfo->num, &pinfo->src, &pinfo->dst, CONVERSATION_BT_UTP, id_up, utp_info->connection, 0); |
321 | 0 | } |
322 | 0 | } else { |
323 | | /* For non-SYN packets, we know our connection ID, but we don't know if |
324 | | * the other side has our ID+1 (src initiated the connection) or our ID-1 |
325 | | * (dst initiated). We also don't want find_conversation() to accidentally |
326 | | * call conversation_set_port2() with the wrong ID. So first we see if |
327 | | * we have a wildcarded conversation around (if we've seen previous |
328 | | * non-SYN packets from our current direction but none in the other.) |
329 | | */ |
330 | 0 | conv = find_conversation(pinfo->num, &pinfo->src, &pinfo->dst, CONVERSATION_BT_UTP, utp_info->connection, 0, NO_PORT_B); |
331 | 0 | if (!conv) { |
332 | | /* Do we have a complete conversation originated by our src, or |
333 | | * possibly a wildcarded conversation originated in this direction |
334 | | * (but we saw a non-SYN for the non-initiating side first)? */ |
335 | 0 | conv = find_conversation(pinfo->num, &pinfo->src, &pinfo->dst, CONVERSATION_BT_UTP, utp_info->connection, id_up, 0); |
336 | 0 | if (!conv) { |
337 | | /* As above, but dst initiated? */ |
338 | 0 | conv = find_conversation(pinfo->num, &pinfo->src, &pinfo->dst, CONVERSATION_BT_UTP, utp_info->connection, id_down, 0); |
339 | 0 | if (!conv) { |
340 | | /* Didn't find it, so create a new wildcarded conversation. When we |
341 | | * get a packet for the other direction, find_conversation() above |
342 | | * will set port2 with the other connection ID. |
343 | | */ |
344 | 0 | conv = conversation_new(pinfo->num, &pinfo->src, &pinfo->dst, CONVERSATION_BT_UTP, utp_info->connection, 0, NO_PORT2); |
345 | 0 | } |
346 | 0 | } |
347 | 0 | } |
348 | 0 | } |
349 | |
|
350 | 0 | stream_info = (utp_stream_info_t *)conversation_get_proto_data(conv, proto_bt_utp); |
351 | 0 | if (!stream_info) { |
352 | 0 | stream_info = wmem_new0(wmem_file_scope(), utp_stream_info_t); |
353 | 0 | stream_info->stream = bt_utp_stream_count++; |
354 | 0 | stream_info->flow[0].multisegment_pdus=wmem_tree_new(wmem_file_scope()); |
355 | 0 | stream_info->flow[1].multisegment_pdus=wmem_tree_new(wmem_file_scope()); |
356 | 0 | conversation_add_proto_data(conv, proto_bt_utp, stream_info); |
357 | 0 | } |
358 | | |
359 | | /* check direction */ |
360 | 0 | direction=cmp_address(&pinfo->src, &pinfo->dst); |
361 | | /* if the addresses are equal, match the ports instead. Use |
362 | | * the UDP ports instead of the uTP connection IDs because |
363 | | * we don't know which ID is smaller if we don't have both. */ |
364 | 0 | if(direction==0) { |
365 | 0 | direction= (pinfo->srcport > pinfo->destport) ? 1 : -1; |
366 | 0 | } |
367 | 0 | if(direction>=0) { |
368 | 0 | stream_info->fwd=&(stream_info->flow[0]); |
369 | 0 | stream_info->rev=&(stream_info->flow[1]); |
370 | 0 | } else { |
371 | 0 | stream_info->fwd=&(stream_info->flow[1]); |
372 | 0 | stream_info->rev=&(stream_info->flow[0]); |
373 | 0 | } |
374 | |
|
375 | 0 | return stream_info; |
376 | 0 | } |
377 | | |
378 | | static void |
379 | | print_pdu_tracking_data(packet_info *pinfo, tvbuff_t *tvb, proto_tree *utp_tree, utp_multisegment_pdu *msp) |
380 | 0 | { |
381 | 0 | proto_item *item; |
382 | |
|
383 | 0 | col_prepend_fence_fstr(pinfo->cinfo, COL_INFO, "[Continuation to #%u] ", msp->first_frame); |
384 | 0 | item=proto_tree_add_uint(utp_tree, hf_bt_utp_continuation_to, |
385 | 0 | tvb, 0, 0, msp->first_frame); |
386 | 0 | proto_item_set_generated(item); |
387 | 0 | } |
388 | | |
389 | | static int |
390 | | scan_for_next_pdu(tvbuff_t *tvb, proto_tree *utp_tree, packet_info *pinfo, wmem_tree_t *multisegment_pdus) |
391 | 0 | { |
392 | 0 | utp_multisegment_pdu *msp; |
393 | 0 | utp_info_t *p_utp_info; |
394 | 0 | uint16_t seq, prev_seq; |
395 | |
|
396 | 0 | p_utp_info = (utp_info_t *)p_get_proto_data(pinfo->pool, pinfo, proto_bt_utp, pinfo->curr_layer_num); |
397 | | |
398 | | /* XXX: Wraparound is possible, as is cycling through all 16 bit |
399 | | * sequence numbers in a connection. We only do this path if |
400 | | * "seq analysis" is on; that ought to do something (relative |
401 | | * sequence numbers definitely, maybe extend the width?) to help, |
402 | | * but doesn't yet. |
403 | | */ |
404 | 0 | seq = p_utp_info->seq; |
405 | 0 | prev_seq = seq - 1; |
406 | 0 | msp = (utp_multisegment_pdu *)wmem_tree_lookup32_le(multisegment_pdus, prev_seq); |
407 | 0 | if (msp) { |
408 | |
|
409 | 0 | if(seq>msp->first_seq && seq<=msp->last_seq) { |
410 | 0 | print_pdu_tracking_data(pinfo, tvb, utp_tree, msp); |
411 | 0 | } |
412 | | |
413 | | /* If this segment is completely within a previous PDU |
414 | | * then we just skip this packet |
415 | | */ |
416 | 0 | if(seq>msp->first_seq && seq<msp->last_seq) { |
417 | 0 | return -1; |
418 | 0 | } |
419 | | |
420 | 0 | if(seq>msp->first_seq && seq==msp->last_seq) { |
421 | 0 | if (!PINFO_FD_VISITED(pinfo) && p_utp_info->have_seglen) { |
422 | | /* Unlike TCP, the sequence numbers don't measure bytes, so |
423 | | * we can only really update the end of the MSP when the packets |
424 | | * are in order, and if we have the real segment length (so not |
425 | | * an unreassembled IP fragment). |
426 | | */ |
427 | 0 | if (p_utp_info->seglen >= msp->last_seq_end_offset) { |
428 | 0 | return msp->last_seq_end_offset; |
429 | 0 | } else { |
430 | 0 | msp->last_seq++; |
431 | 0 | msp->last_seq_end_offset -= p_utp_info->seglen; |
432 | 0 | return -1; |
433 | 0 | } |
434 | 0 | } else { |
435 | | /* We can still provide a hint to the offset start in some |
436 | | * cases even when we can't update the MSP. |
437 | | */ |
438 | 0 | if (msp->last_seq_end_offset < tvb_reported_length(tvb)) { |
439 | 0 | return msp->last_seq_end_offset; |
440 | 0 | } else { |
441 | 0 | return -1; |
442 | 0 | } |
443 | 0 | } |
444 | 0 | } |
445 | 0 | } |
446 | | |
447 | 0 | return 0; |
448 | 0 | } |
449 | | |
450 | | static utp_multisegment_pdu * |
451 | | pdu_store_sequencenumber_of_next_pdu(packet_info *pinfo, uint16_t seq, int offset, uint32_t bytes_until_next_pdu, wmem_tree_t *multisegment_pdus) |
452 | 0 | { |
453 | 0 | utp_multisegment_pdu *msp; |
454 | |
|
455 | 0 | msp = wmem_new(wmem_file_scope(), utp_multisegment_pdu); |
456 | 0 | msp->first_seq = seq; |
457 | 0 | msp->first_seq_start_offset = offset; |
458 | 0 | msp->last_seq = seq+1; |
459 | 0 | msp->last_seq_end_offset = bytes_until_next_pdu; |
460 | 0 | msp->first_frame = pinfo->num; |
461 | 0 | wmem_tree_insert32(multisegment_pdus, seq, (void *)msp); |
462 | |
|
463 | 0 | return msp; |
464 | 0 | } |
465 | | |
466 | | #if 0 |
467 | | static void |
468 | | desegment_utp(tvbuff_t *tvb, packet_info *pinfo, int offset, |
469 | | uint32_t seq, uint32_t nxtseq, |
470 | | proto_tree *tree, proto_tree *utp_tree, |
471 | | utp_stream_info_t *stream_info) |
472 | | { |
473 | | |
474 | | } |
475 | | #endif |
476 | | |
477 | | void |
478 | | utp_dissect_pdus(tvbuff_t *tvb, packet_info *pinfo, proto_tree *tree, |
479 | | bool proto_desegment, unsigned fixed_len, |
480 | | unsigned (*get_pdu_len)(packet_info *, tvbuff_t *, int, void*), |
481 | | dissector_t dissect_pdu, void* dissector_data) |
482 | 0 | { |
483 | 0 | volatile int offset = 0; |
484 | 0 | int offset_before; |
485 | 0 | unsigned captured_length_remaining; |
486 | 0 | volatile unsigned plen; |
487 | 0 | tvbuff_t *next_tvb; |
488 | 0 | proto_item *item=NULL; |
489 | 0 | const char *saved_proto; |
490 | 0 | uint8_t curr_layer_num; |
491 | 0 | wmem_list_frame_t *frame; |
492 | |
|
493 | 0 | while (tvb_reported_length_remaining(tvb, offset) > 0) { |
494 | | /* |
495 | | * We use "tvb_ensure_captured_length_remaining()" to make |
496 | | * sure there actually *is* data remaining. The protocol |
497 | | * we're handling could conceivably consists of a sequence of |
498 | | * fixed-length PDUs, and therefore the "get_pdu_len" routine |
499 | | * might not actually fetch anything from the tvbuff, and thus |
500 | | * might not cause an exception to be thrown if we've run past |
501 | | * the end of the tvbuff. |
502 | | * |
503 | | * This means we're guaranteed that "captured_length_remaining" is positive. |
504 | | */ |
505 | 0 | captured_length_remaining = tvb_ensure_captured_length_remaining(tvb, offset); |
506 | | |
507 | | /* |
508 | | * Can we do reassembly? |
509 | | */ |
510 | 0 | if (proto_desegment && pinfo->can_desegment) { |
511 | | /* |
512 | | * Yes - is the fixed-length part of the PDU split across segment |
513 | | * boundaries? |
514 | | */ |
515 | 0 | if (captured_length_remaining < fixed_len) { |
516 | | /* |
517 | | * Yes. Tell the uTP dissector where the data for this message |
518 | | * starts in the data it handed us and that we need "some more |
519 | | * data." Don't tell it exactly how many bytes we need because |
520 | | * if/when we ask for even more (after the header) that will |
521 | | * break reassembly. |
522 | | */ |
523 | 0 | pinfo->desegment_offset = offset; |
524 | 0 | pinfo->desegment_len = DESEGMENT_ONE_MORE_SEGMENT; |
525 | 0 | return; |
526 | 0 | } |
527 | 0 | } |
528 | | |
529 | | /* |
530 | | * Get the length of the PDU. |
531 | | */ |
532 | 0 | plen = (*get_pdu_len)(pinfo, tvb, offset, dissector_data); |
533 | 0 | if (plen == 0) { |
534 | | /* |
535 | | * Support protocols which have a variable length which cannot |
536 | | * always be determined within the given fixed_len. |
537 | | */ |
538 | | /* |
539 | | * If another segment was requested but we can't do reassembly, |
540 | | * abort and warn about the unreassembled packet. |
541 | | */ |
542 | 0 | THROW_ON(!(proto_desegment && pinfo->can_desegment), FragmentBoundsError); |
543 | 0 | pinfo->desegment_offset = offset; |
544 | 0 | pinfo->desegment_len = DESEGMENT_ONE_MORE_SEGMENT; |
545 | 0 | return; |
546 | 0 | } |
547 | 0 | if (plen < fixed_len) { |
548 | | /* |
549 | | * Either: |
550 | | * |
551 | | * 1) the length value extracted from the fixed-length portion |
552 | | * doesn't include the fixed-length portion's length, and |
553 | | * was so large that, when the fixed-length portion's |
554 | | * length was added to it, the total length overflowed; |
555 | | * |
556 | | * 2) the length value extracted from the fixed-length portion |
557 | | * includes the fixed-length portion's length, and the value |
558 | | * was less than the fixed-length portion's length, i.e. it |
559 | | * was bogus. |
560 | | * |
561 | | * Report this as a bounds error. |
562 | | */ |
563 | 0 | show_reported_bounds_error(tvb, pinfo, tree); |
564 | 0 | return; |
565 | 0 | } |
566 | | |
567 | | /* give a hint to uTP where the next PDU starts |
568 | | * so that it can attempt to find it in case it starts |
569 | | * somewhere in the middle of a segment. |
570 | | */ |
571 | 0 | if(!pinfo->fd->visited && utp_analyze_seq) { |
572 | 0 | unsigned remaining_bytes; |
573 | 0 | remaining_bytes = tvb_reported_length_remaining(tvb, offset); |
574 | 0 | if(plen>remaining_bytes) { |
575 | 0 | pinfo->want_pdu_tracking=2; |
576 | 0 | pinfo->bytes_until_next_pdu=plen-remaining_bytes; |
577 | 0 | } |
578 | 0 | } |
579 | | |
580 | | /* |
581 | | * Can we do reassembly? |
582 | | */ |
583 | 0 | if (proto_desegment && pinfo->can_desegment) { |
584 | | /* |
585 | | * Yes - is the PDU split across segment boundaries? |
586 | | */ |
587 | 0 | if (captured_length_remaining < plen) { |
588 | | /* |
589 | | * Yes. Tell the TCP dissector where the data for this message |
590 | | * starts in the data it handed us, and how many more bytes we |
591 | | * need, and return. |
592 | | */ |
593 | 0 | pinfo->desegment_offset = offset; |
594 | 0 | pinfo->desegment_len = plen - captured_length_remaining; |
595 | 0 | return; |
596 | 0 | } |
597 | 0 | } |
598 | | |
599 | 0 | curr_layer_num = pinfo->curr_layer_num-1; |
600 | 0 | frame = wmem_list_frame_prev(wmem_list_tail(pinfo->layers)); |
601 | 0 | while (frame && (proto_bt_utp != (int) GPOINTER_TO_UINT(wmem_list_frame_data(frame)))) { |
602 | 0 | frame = wmem_list_frame_prev(frame); |
603 | 0 | curr_layer_num--; |
604 | 0 | } |
605 | | #if 0 |
606 | | if (captured_length_remaining >= plen || there are more packets) |
607 | | { |
608 | | #endif |
609 | | /* |
610 | | * Display the PDU length as a field |
611 | | */ |
612 | 0 | item=proto_tree_add_uint(((utp_info_t *)p_get_proto_data(pinfo->pool, pinfo, proto_bt_utp, curr_layer_num))->tree, |
613 | 0 | hf_bt_utp_pdu_size, |
614 | 0 | tvb, offset, plen, plen); |
615 | 0 | proto_item_set_generated(item); |
616 | | #if 0 |
617 | | } else { |
618 | | item = proto_tree_add_expert_format((proto_tree *)p_get_proto_data(pinfo->pool, pinfo, proto_bt_utp, curr_layer_num), |
619 | | tvb, offset, -1, |
620 | | "PDU Size: %u cut short at %u",plen,captured_length_remaining); |
621 | | proto_item_set_generated(item); |
622 | | } |
623 | | #endif |
624 | | |
625 | | /* |
626 | | * Construct a tvbuff containing the amount of the payload we have |
627 | | * available. Make its reported length the amount of data in the PDU. |
628 | | */ |
629 | 0 | next_tvb = tvb_new_subset_length(tvb, offset, plen); |
630 | 0 | if (!(proto_desegment && pinfo->can_desegment)) { |
631 | | /* If we can't do reassembly, give a hint that bounds errors |
632 | | * are probably fragment errors. */ |
633 | 0 | tvb_set_fragment(next_tvb); |
634 | 0 | } |
635 | | |
636 | | /* |
637 | | * Dissect the PDU. |
638 | | * |
639 | | * If it gets an error that means there's no point in |
640 | | * dissecting any more PDUs, rethrow the exception in |
641 | | * question. |
642 | | * |
643 | | * If it gets any other error, report it and continue, as that |
644 | | * means that PDU got an error, but that doesn't mean we should |
645 | | * stop dissecting PDUs within this frame or chunk of reassembled |
646 | | * data. |
647 | | */ |
648 | 0 | saved_proto = pinfo->current_proto; |
649 | 0 | TRY { |
650 | 0 | (*dissect_pdu)(next_tvb, pinfo, tree, dissector_data); |
651 | 0 | } |
652 | 0 | CATCH_NONFATAL_ERRORS { |
653 | 0 | show_exception(tvb, pinfo, tree, EXCEPT_CODE, GET_MESSAGE); |
654 | | /* |
655 | | * Restore the saved protocol as well; we do this after |
656 | | * show_exception(), so that the "Malformed packet" indication |
657 | | * shows the protocol for which dissection failed. |
658 | | */ |
659 | 0 | pinfo->current_proto = saved_proto; |
660 | 0 | } |
661 | 0 | ENDTRY; |
662 | | |
663 | | /* |
664 | | * Step to the next PDU. |
665 | | * Make sure we don't overflow. |
666 | | */ |
667 | 0 | offset_before = offset; |
668 | 0 | offset += plen; |
669 | 0 | if (offset <= offset_before) |
670 | 0 | break; |
671 | 0 | } |
672 | 0 | } |
673 | | |
674 | | static int |
675 | 0 | get_utp_version(tvbuff_t *tvb) { |
676 | 0 | uint8_t v0_flags; |
677 | 0 | uint8_t v1_ver_type, ext, ext_len; |
678 | 0 | uint32_t window; |
679 | 0 | unsigned len, offset = 0; |
680 | 0 | int ver = -1; |
681 | | |
682 | | /* Simple heuristics inspired by code from utp.cpp */ |
683 | |
|
684 | 0 | len = tvb_captured_length(tvb); |
685 | | |
686 | | /* Version 1? */ |
687 | 0 | if (len < V1_FIXED_HDR_SIZE) { |
688 | 0 | return -1; |
689 | 0 | } |
690 | | |
691 | 0 | v1_ver_type = tvb_get_uint8(tvb, 0); |
692 | 0 | ext = tvb_get_uint8(tvb, 1); |
693 | 0 | if (((v1_ver_type & 0x0f) == 1) && ((v1_ver_type>>4) < ST_NUM_STATES) && |
694 | 0 | (ext < EXT_NUM_EXT)) { |
695 | 0 | window = tvb_get_uint32(tvb, 12, ENC_BIG_ENDIAN); |
696 | 0 | if (window > max_window_size) { |
697 | 0 | return -1; |
698 | 0 | } |
699 | 0 | ver = 1; |
700 | 0 | offset = V1_FIXED_HDR_SIZE; |
701 | 0 | } else if (enable_version0) { |
702 | | /* Version 0? */ |
703 | 0 | if (len < V0_FIXED_HDR_SIZE) { |
704 | 0 | return -1; |
705 | 0 | } |
706 | 0 | v0_flags = tvb_get_uint8(tvb, 18); |
707 | 0 | ext = tvb_get_uint8(tvb, 17); |
708 | 0 | if ((v0_flags < ST_NUM_STATES) && (ext < EXT_NUM_EXT)) { |
709 | 0 | ver = 0; |
710 | 0 | offset = V0_FIXED_HDR_SIZE; |
711 | 0 | } |
712 | 0 | } |
713 | | |
714 | 0 | if (ver < 0) { |
715 | 0 | return ver; |
716 | 0 | } |
717 | | |
718 | | /* In V0 we could use the microseconds value as a heuristic, because |
719 | | * it was tv_usec, but in the modern V1 we cannot, because it is |
720 | | * computed by converting a time_t into a 64 bit quantity of microseconds |
721 | | * and then taking the lower 32 bits, so all possible values are likely. |
722 | | */ |
723 | | /* If we have an extension, then check the next two bytes, |
724 | | * the first of which is another extension type (likely NO_EXTENSION) |
725 | | * and the second of which is a length, which must be at least 4. |
726 | | */ |
727 | 0 | if (ext != EXT_NO_EXTENSION) { |
728 | 0 | if (len < offset + 2) { |
729 | 0 | return -1; |
730 | 0 | } |
731 | 0 | ext = tvb_get_uint8(tvb, offset); |
732 | 0 | ext_len = tvb_get_uint8(tvb, offset+1); |
733 | 0 | if (ext >= EXT_NUM_EXT || ext_len < 4) { |
734 | 0 | return -1; |
735 | 0 | } |
736 | 0 | } |
737 | | |
738 | 0 | return ver; |
739 | 0 | } |
740 | | |
741 | | static int |
742 | | dissect_utp_header_v0(tvbuff_t *tvb, packet_info *pinfo, proto_tree *tree, int offset, uint8_t *extension_type) |
743 | 0 | { |
744 | | /* "Original" (V0) */ |
745 | 0 | utp_info_t *p_utp_info = NULL; |
746 | 0 | utp_stream_info_t *stream_info = NULL; |
747 | |
|
748 | 0 | proto_item *ti; |
749 | 0 | uint32_t type, connection, win, seq, ack; |
750 | |
|
751 | 0 | p_utp_info = wmem_new(pinfo->pool, utp_info_t); |
752 | 0 | p_utp_info->v0 = true; |
753 | 0 | p_add_proto_data(pinfo->pool, pinfo, proto_bt_utp, pinfo->curr_layer_num, p_utp_info); |
754 | |
|
755 | 0 | proto_tree_add_item_ret_uint(tree, hf_bt_utp_connection_id_v0, tvb, offset, 4, ENC_BIG_ENDIAN, &connection); |
756 | 0 | offset += 4; |
757 | 0 | proto_tree_add_item(tree, hf_bt_utp_timestamp_sec, tvb, offset, 4, ENC_BIG_ENDIAN); |
758 | 0 | offset += 4; |
759 | 0 | proto_tree_add_item(tree, hf_bt_utp_timestamp_us, tvb, offset, 4, ENC_BIG_ENDIAN); |
760 | 0 | offset += 4; |
761 | 0 | proto_tree_add_item(tree, hf_bt_utp_timestamp_diff_us, tvb, offset, 4, ENC_BIG_ENDIAN); |
762 | 0 | offset += 4; |
763 | 0 | proto_tree_add_item_ret_uint(tree, hf_bt_utp_wnd_size_v0, tvb, offset, 1, ENC_BIG_ENDIAN, &win); |
764 | 0 | offset += 1; |
765 | 0 | proto_tree_add_item(tree, hf_bt_utp_next_extension_type, tvb, offset, 1, ENC_BIG_ENDIAN); |
766 | 0 | *extension_type = tvb_get_uint8(tvb, offset); |
767 | 0 | offset += 1; |
768 | 0 | proto_tree_add_item_ret_uint(tree, hf_bt_utp_flags, tvb, offset, 1, ENC_BIG_ENDIAN, &type); |
769 | 0 | offset += 1; |
770 | |
|
771 | 0 | col_append_fstr(pinfo->cinfo, COL_INFO, "Connection ID:%d [%s]", connection, val_to_str(pinfo->pool, type, bt_utp_type_vals, "Unknown %d")); |
772 | 0 | p_utp_info->type = type; |
773 | 0 | p_utp_info->connection = connection; |
774 | |
|
775 | 0 | proto_tree_add_item(tree, hf_bt_utp_seq_nr, tvb, offset, 2, ENC_BIG_ENDIAN); |
776 | 0 | offset += 2; |
777 | 0 | proto_tree_add_item(tree, hf_bt_utp_ack_nr, tvb, offset, 2, ENC_BIG_ENDIAN); |
778 | 0 | offset += 2; |
779 | |
|
780 | 0 | proto_tree_add_item_ret_uint(tree, hf_bt_utp_seq_nr, tvb, offset, 2, ENC_BIG_ENDIAN, &seq); |
781 | 0 | col_append_str_uint(pinfo->cinfo, COL_INFO, "Seq", seq, " "); |
782 | 0 | p_utp_info->seq = seq; |
783 | 0 | offset += 2; |
784 | 0 | proto_tree_add_item_ret_uint(tree, hf_bt_utp_ack_nr, tvb, offset, 2, ENC_BIG_ENDIAN, &ack); |
785 | 0 | col_append_str_uint(pinfo->cinfo, COL_INFO, "Ack", ack, " "); |
786 | 0 | p_utp_info->ack = ack; |
787 | 0 | offset += 2; |
788 | 0 | col_append_str_uint(pinfo->cinfo, COL_INFO, "Win", win, " "); |
789 | |
|
790 | 0 | stream_info = get_utp_stream_info(pinfo, p_utp_info); |
791 | 0 | ti = proto_tree_add_uint(tree, hf_bt_utp_stream, tvb, offset, 0, stream_info->stream); |
792 | 0 | p_utp_info->stream = stream_info->stream; |
793 | 0 | proto_item_set_generated(ti); |
794 | |
|
795 | 0 | return offset; |
796 | 0 | } |
797 | | |
798 | | static int |
799 | | dissect_utp_header_v1(tvbuff_t *tvb, packet_info *pinfo, proto_tree *tree, int offset, uint8_t *extension_type) |
800 | 0 | { |
801 | | /* V1 */ |
802 | 0 | utp_info_t *p_utp_info = NULL; |
803 | 0 | utp_stream_info_t *stream_info = NULL; |
804 | |
|
805 | 0 | proto_item *ti; |
806 | |
|
807 | 0 | uint32_t type, connection, win, seq, ack; |
808 | |
|
809 | 0 | p_utp_info = wmem_new(pinfo->pool, utp_info_t); |
810 | 0 | p_utp_info->v0 = false; |
811 | 0 | p_add_proto_data(pinfo->pool, pinfo, proto_bt_utp, pinfo->curr_layer_num, p_utp_info); |
812 | |
|
813 | 0 | proto_tree_add_item(tree, hf_bt_utp_ver, tvb, offset, 1, ENC_BIG_ENDIAN); |
814 | 0 | proto_tree_add_item_ret_uint(tree, hf_bt_utp_type, tvb, offset, 1, ENC_BIG_ENDIAN, &type); |
815 | 0 | offset += 1; |
816 | 0 | proto_tree_add_item(tree, hf_bt_utp_next_extension_type, tvb, offset, 1, ENC_BIG_ENDIAN); |
817 | 0 | *extension_type = tvb_get_uint8(tvb, offset); |
818 | 0 | offset += 1; |
819 | 0 | proto_tree_add_item_ret_uint(tree, hf_bt_utp_connection_id_v1, tvb, offset, 2, ENC_BIG_ENDIAN, &connection); |
820 | 0 | offset += 2; |
821 | |
|
822 | 0 | col_append_fstr(pinfo->cinfo, COL_INFO, "Connection ID:%d [%s]", connection, val_to_str(pinfo->pool, type, bt_utp_type_vals, "Unknown %d")); |
823 | 0 | p_utp_info->type = type; |
824 | 0 | p_utp_info->connection = connection; |
825 | |
|
826 | 0 | proto_tree_add_item(tree, hf_bt_utp_timestamp_us, tvb, offset, 4, ENC_BIG_ENDIAN); |
827 | 0 | offset += 4; |
828 | 0 | proto_tree_add_item(tree, hf_bt_utp_timestamp_diff_us, tvb, offset, 4, ENC_BIG_ENDIAN); |
829 | 0 | offset += 4; |
830 | 0 | proto_tree_add_item_ret_uint(tree, hf_bt_utp_wnd_size_v1, tvb, offset, 4, ENC_BIG_ENDIAN, &win); |
831 | 0 | offset += 4; |
832 | 0 | proto_tree_add_item_ret_uint(tree, hf_bt_utp_seq_nr, tvb, offset, 2, ENC_BIG_ENDIAN, &seq); |
833 | 0 | col_append_str_uint(pinfo->cinfo, COL_INFO, "Seq", seq, " "); |
834 | 0 | p_utp_info->seq = seq; |
835 | 0 | offset += 2; |
836 | 0 | proto_tree_add_item_ret_uint(tree, hf_bt_utp_ack_nr, tvb, offset, 2, ENC_BIG_ENDIAN, &ack); |
837 | 0 | col_append_str_uint(pinfo->cinfo, COL_INFO, "Ack", ack, " "); |
838 | 0 | p_utp_info->ack = ack; |
839 | 0 | offset += 2; |
840 | 0 | col_append_str_uint(pinfo->cinfo, COL_INFO, "Win", win, " "); |
841 | |
|
842 | 0 | stream_info = get_utp_stream_info(pinfo, p_utp_info); |
843 | 0 | ti = proto_tree_add_uint(tree, hf_bt_utp_stream, tvb, offset, 0, stream_info->stream); |
844 | 0 | p_utp_info->stream = stream_info->stream; |
845 | 0 | proto_item_set_generated(ti); |
846 | | |
847 | | /* XXX: Multisegment PDUs are the top priority to add, but a number of |
848 | | * other features in the TCP dissector would be useful- relative sequence |
849 | | * numbers, conversation completeness, maybe even tracking SACKs. |
850 | | */ |
851 | 0 | return offset; |
852 | 0 | } |
853 | | |
854 | | static int |
855 | | dissect_utp_extension(tvbuff_t *tvb, packet_info _U_*pinfo, proto_tree *tree, int offset, uint8_t *extension_type) |
856 | 0 | { |
857 | 0 | proto_item *ti; |
858 | 0 | proto_tree *ext_tree; |
859 | 0 | uint32_t next_extension, extension_length; |
860 | | /* display the extension tree */ |
861 | |
|
862 | 0 | while(*extension_type != EXT_NO_EXTENSION && offset < (int)tvb_reported_length(tvb)) |
863 | 0 | { |
864 | 0 | ti = proto_tree_add_none_format(tree, hf_bt_utp_extension, tvb, offset, -1, "Extension: %s", val_to_str_const(*extension_type, bt_utp_extension_type_vals, "Unknown")); |
865 | 0 | ext_tree = proto_item_add_subtree(ti, ett_bt_utp_extension); |
866 | |
|
867 | 0 | proto_tree_add_item_ret_uint(ext_tree, hf_bt_utp_next_extension_type, tvb, offset, 1, ENC_BIG_ENDIAN, &next_extension); |
868 | 0 | offset += 1; |
869 | |
|
870 | 0 | proto_tree_add_item_ret_uint(ext_tree, hf_bt_utp_extension_len, tvb, offset, 1, ENC_BIG_ENDIAN, &extension_length); |
871 | 0 | proto_item_append_text(ti, ", Len=%d", extension_length); |
872 | 0 | offset += 1; |
873 | |
|
874 | 0 | switch(*extension_type){ |
875 | 0 | case EXT_SELECTIVE_ACKS: /* 1 */ |
876 | 0 | { |
877 | 0 | proto_tree_add_item(ext_tree, hf_bt_utp_extension_bitmask, tvb, offset, extension_length, ENC_NA); |
878 | 0 | break; |
879 | 0 | } |
880 | 0 | case EXT_EXTENSION_BITS: /* 2 */ |
881 | 0 | { |
882 | 0 | proto_tree_add_item(ext_tree, hf_bt_utp_extension_bitmask, tvb, offset, extension_length, ENC_NA); |
883 | 0 | break; |
884 | 0 | } |
885 | 0 | case EXT_CLOSE_REASON: /* 3 */ |
886 | 0 | { |
887 | 0 | if (extension_length != 4) { |
888 | 0 | expert_add_info(pinfo, ti, &ei_extension_len_invalid); |
889 | 0 | } |
890 | 0 | proto_tree_add_item(ext_tree, hf_bt_utp_extension_close_reason, tvb, offset, 4, ENC_BIG_ENDIAN); |
891 | 0 | break; |
892 | 0 | } |
893 | 0 | default: |
894 | 0 | proto_tree_add_item(ext_tree, hf_bt_utp_extension_unknown, tvb, offset, extension_length, ENC_NA); |
895 | 0 | break; |
896 | 0 | } |
897 | 0 | offset += extension_length; |
898 | 0 | proto_item_set_len(ti, 1 + 1 + extension_length); |
899 | 0 | *extension_type = next_extension; |
900 | 0 | } |
901 | | |
902 | 0 | return offset; |
903 | 0 | } |
904 | | |
905 | | static bool |
906 | | decode_utp(tvbuff_t *tvb, int offset, packet_info *pinfo, |
907 | | proto_tree *tree) |
908 | 0 | { |
909 | 0 | proto_tree *parent_tree; |
910 | 0 | tvbuff_t *next_tvb; |
911 | 0 | int save_desegment_offset; |
912 | 0 | uint32_t save_desegment_len; |
913 | | |
914 | | /* XXX: Check for retransmission? */ |
915 | |
|
916 | 0 | next_tvb = tvb_new_subset_remaining(tvb, offset); |
917 | |
|
918 | 0 | save_desegment_offset = pinfo->desegment_offset; |
919 | 0 | save_desegment_len = pinfo->desegment_len; |
920 | | |
921 | | /* The only possible payload is bittorrent */ |
922 | |
|
923 | 0 | parent_tree = proto_tree_get_parent_tree(tree); |
924 | 0 | if (call_dissector_with_data(bittorrent_handle, next_tvb, pinfo, parent_tree, NULL)) { |
925 | 0 | pinfo->want_pdu_tracking -= !!(pinfo->want_pdu_tracking); |
926 | 0 | return true; |
927 | 0 | } |
928 | | |
929 | 0 | DISSECTOR_ASSERT(save_desegment_offset == pinfo->desegment_offset && |
930 | 0 | save_desegment_len == pinfo->desegment_len); |
931 | |
|
932 | 0 | call_data_dissector(tvb, pinfo, parent_tree); |
933 | 0 | pinfo->want_pdu_tracking -= !!(pinfo->want_pdu_tracking); |
934 | |
|
935 | 0 | return false; |
936 | 0 | } |
937 | | |
938 | | static void |
939 | | process_utp_payload(tvbuff_t *tvb, packet_info *pinfo, |
940 | | proto_tree *tree, uint16_t seq, bool is_utp_segment, |
941 | | utp_stream_info_t *stream_info) |
942 | 0 | { |
943 | 0 | volatile int offset = 0; |
944 | 0 | pinfo->want_pdu_tracking = 0; |
945 | |
|
946 | 0 | TRY { |
947 | 0 | if (is_utp_segment) { |
948 | | /* See if an unaligned PDU */ |
949 | 0 | if (stream_info && utp_analyze_seq && (!utp_desegment)) { |
950 | 0 | offset = scan_for_next_pdu(tvb, tree, pinfo, |
951 | 0 | stream_info->fwd->multisegment_pdus); |
952 | 0 | } |
953 | 0 | } |
954 | |
|
955 | 0 | if ((offset != -1) && decode_utp(tvb, offset, pinfo, tree)) { |
956 | | /* |
957 | | * We succeeded in handing off to bittorrent. |
958 | | * |
959 | | * Is this a segment (so we're not desegmenting for whatever |
960 | | * reason)? Then at least do rudimentary PDU tracking. |
961 | | */ |
962 | 0 | if(is_utp_segment) { |
963 | | /* if !visited, check want_pdu_tracking and |
964 | | store it in table */ |
965 | 0 | if(stream_info && (!pinfo->fd->visited) && |
966 | 0 | utp_analyze_seq && pinfo->want_pdu_tracking) { |
967 | 0 | pdu_store_sequencenumber_of_next_pdu( |
968 | 0 | pinfo, |
969 | 0 | seq, |
970 | 0 | offset, |
971 | 0 | pinfo->bytes_until_next_pdu, |
972 | 0 | stream_info->fwd->multisegment_pdus); |
973 | 0 | } |
974 | 0 | } |
975 | 0 | } |
976 | 0 | } |
977 | 0 | CATCH_ALL { |
978 | | /* We got an exception. Before dissection is aborted and execution |
979 | | * is transferred back to (probably) the frame dissector, do PDU |
980 | | * tracking if we need to because this is a segment. |
981 | | */ |
982 | 0 | if (is_utp_segment) { |
983 | 0 | if(stream_info && (!pinfo->fd->visited) && |
984 | 0 | utp_analyze_seq && pinfo->want_pdu_tracking) { |
985 | 0 | pdu_store_sequencenumber_of_next_pdu( |
986 | 0 | pinfo, |
987 | 0 | seq, |
988 | 0 | offset, |
989 | 0 | pinfo->bytes_until_next_pdu, |
990 | 0 | stream_info->fwd->multisegment_pdus); |
991 | 0 | } |
992 | 0 | } |
993 | 0 | RETHROW; |
994 | 0 | } |
995 | 0 | ENDTRY; |
996 | 0 | } |
997 | | |
998 | | static unsigned |
999 | | dissect_utp_payload(tvbuff_t *tvb, packet_info *pinfo, proto_tree *tree) |
1000 | 0 | { |
1001 | 0 | proto_item *ti; |
1002 | |
|
1003 | 0 | utp_info_t *p_utp_info; |
1004 | 0 | unsigned len_tvb; |
1005 | 0 | bool save_fragmented; |
1006 | |
|
1007 | 0 | p_utp_info = (utp_info_t *)p_get_proto_data(pinfo->pool, pinfo, proto_bt_utp, pinfo->curr_layer_num); |
1008 | |
|
1009 | 0 | p_utp_info->tree = tree; |
1010 | |
|
1011 | 0 | utp_stream_info_t *stream_info; |
1012 | 0 | stream_info = get_utp_stream_info(pinfo, p_utp_info); |
1013 | |
|
1014 | 0 | len_tvb = tvb_reported_length(tvb); |
1015 | | |
1016 | | /* As with TCP, if we've been handed an IP fragment, we don't really |
1017 | | * know how big the segment is, and we don't really want to do anything |
1018 | | * if this is an error packet from ICMP or similar. |
1019 | | * |
1020 | | * XXX: We don't want to desegment if the UDP checksum is bad either. |
1021 | | * Need to add that to the per-packet info that UDP stores and access |
1022 | | * it. |
1023 | | */ |
1024 | 0 | pinfo->can_desegment = 0; |
1025 | 0 | if (!pinfo->fragmented && !pinfo->flags.in_error_pkt) { |
1026 | 0 | p_utp_info->seglen = len_tvb; |
1027 | 0 | p_utp_info->have_seglen = true; |
1028 | |
|
1029 | 0 | ti = proto_tree_add_uint(tree, hf_bt_utp_len, tvb, 0, 0, len_tvb); |
1030 | 0 | proto_item_set_generated(ti); |
1031 | 0 | col_append_str_uint(pinfo->cinfo, COL_INFO, "Len", len_tvb, " "); |
1032 | |
|
1033 | 0 | if (utp_desegment && tvb_bytes_exist(tvb, 0, len_tvb)) { |
1034 | | /* If we actually have the bytes too then we can desegment. */ |
1035 | 0 | pinfo->can_desegment = 2; |
1036 | 0 | } |
1037 | 0 | } else { |
1038 | 0 | p_utp_info->have_seglen = false; |
1039 | 0 | } |
1040 | |
|
1041 | 0 | if(tvb_captured_length(tvb)) { |
1042 | 0 | proto_tree_add_item(tree, hf_bt_utp_data, tvb, 0, len_tvb, ENC_NA); |
1043 | 0 | if (pinfo->can_desegment) { |
1044 | | /* XXX: desegment_utp() is not implemented, but we can't get |
1045 | | * into this code path yet because utp_desegment is false. */ |
1046 | 0 | } else { |
1047 | 0 | save_fragmented = pinfo->fragmented; |
1048 | 0 | pinfo->fragmented = true; |
1049 | 0 | process_utp_payload(tvb, pinfo, tree, p_utp_info->seq, true, stream_info); |
1050 | 0 | pinfo->fragmented = save_fragmented; |
1051 | 0 | } |
1052 | 0 | } |
1053 | |
|
1054 | 0 | return len_tvb; |
1055 | 0 | } |
1056 | | |
1057 | | static int |
1058 | | dissect_bt_utp(tvbuff_t *tvb, packet_info *pinfo, proto_tree *tree, void *data _U_) |
1059 | 0 | { |
1060 | 0 | int version; |
1061 | 0 | version = get_utp_version(tvb); |
1062 | | |
1063 | | /* try dissecting */ |
1064 | 0 | if (version >= 0) |
1065 | 0 | { |
1066 | 0 | proto_tree *sub_tree = NULL; |
1067 | 0 | proto_item *ti; |
1068 | 0 | int offset = 0; |
1069 | 0 | uint8_t extension_type; |
1070 | | |
1071 | | /* set the protocol column */ |
1072 | 0 | col_set_str(pinfo->cinfo, COL_PROTOCOL, "BT-uTP"); |
1073 | 0 | col_clear(pinfo->cinfo, COL_INFO); |
1074 | | |
1075 | | /* Determine header version */ |
1076 | |
|
1077 | 0 | if (version == 0) { |
1078 | 0 | ti = proto_tree_add_protocol_format(tree, proto_bt_utp, tvb, 0, -1, |
1079 | 0 | "uTorrent Transport Protocol V0"); |
1080 | 0 | sub_tree = proto_item_add_subtree(ti, ett_bt_utp); |
1081 | 0 | offset = dissect_utp_header_v0(tvb, pinfo, sub_tree, offset, &extension_type); |
1082 | 0 | } else { |
1083 | 0 | ti = proto_tree_add_item(tree, proto_bt_utp, tvb, 0, -1, ENC_NA); |
1084 | 0 | sub_tree = proto_item_add_subtree(ti, ett_bt_utp); |
1085 | 0 | offset = dissect_utp_header_v1(tvb, pinfo, sub_tree, offset, &extension_type); |
1086 | 0 | } |
1087 | |
|
1088 | 0 | offset = dissect_utp_extension(tvb, pinfo, sub_tree, offset, &extension_type); |
1089 | |
|
1090 | 0 | offset += dissect_utp_payload(tvb_new_subset_remaining(tvb, offset), pinfo, sub_tree); |
1091 | |
|
1092 | 0 | return offset; |
1093 | 0 | } |
1094 | 0 | return 0; |
1095 | 0 | } |
1096 | | |
1097 | | static bool |
1098 | | dissect_bt_utp_heur(tvbuff_t *tvb, packet_info *pinfo, proto_tree *tree, void *data) |
1099 | 0 | { |
1100 | 0 | int version; |
1101 | 0 | version = get_utp_version(tvb); |
1102 | |
|
1103 | 0 | if (version >= 0) |
1104 | 0 | { |
1105 | 0 | conversation_t *conversation; |
1106 | |
|
1107 | 0 | conversation = find_or_create_conversation(pinfo); |
1108 | 0 | conversation_set_dissector_from_frame_number(conversation, pinfo->num, bt_utp_handle); |
1109 | |
|
1110 | 0 | dissect_bt_utp(tvb, pinfo, tree, data); |
1111 | 0 | return true; |
1112 | 0 | } |
1113 | | |
1114 | 0 | return false; |
1115 | 0 | } |
1116 | | |
1117 | | static void |
1118 | | utp_init(void) |
1119 | 14 | { |
1120 | 14 | bt_utp_stream_count = 0; |
1121 | 14 | } |
1122 | | |
1123 | | void |
1124 | | proto_register_bt_utp(void) |
1125 | 14 | { |
1126 | 14 | static hf_register_info hf[] = { |
1127 | 14 | { &hf_bt_utp_ver, |
1128 | 14 | { "Version", "bt-utp.ver", |
1129 | 14 | FT_UINT8, BASE_DEC, NULL, 0x0F, |
1130 | 14 | NULL, HFILL } |
1131 | 14 | }, |
1132 | 14 | { &hf_bt_utp_flags, |
1133 | 14 | { "Flags", "bt-utp.flags", |
1134 | 14 | FT_UINT8, BASE_DEC, VALS(bt_utp_type_vals), 0x0, |
1135 | 14 | NULL, HFILL } |
1136 | 14 | }, |
1137 | 14 | { &hf_bt_utp_type, |
1138 | 14 | { "Type", "bt-utp.type", |
1139 | 14 | FT_UINT8, BASE_DEC, VALS(bt_utp_type_vals), 0xF0, |
1140 | 14 | NULL, HFILL } |
1141 | 14 | }, |
1142 | 14 | { &hf_bt_utp_extension, |
1143 | 14 | { "Extension", "bt-utp.extension", |
1144 | 14 | FT_NONE, BASE_NONE, NULL, 0x0, |
1145 | 14 | NULL, HFILL } |
1146 | 14 | }, |
1147 | 14 | { &hf_bt_utp_next_extension_type, |
1148 | 14 | { "Next Extension Type", "bt-utp.next_extension_type", |
1149 | 14 | FT_UINT8, BASE_DEC, VALS(bt_utp_extension_type_vals), 0x0, |
1150 | 14 | NULL, HFILL } |
1151 | 14 | }, |
1152 | 14 | { &hf_bt_utp_extension_len, |
1153 | 14 | { "Extension Length", "bt-utp.extension_len", |
1154 | 14 | FT_UINT8, BASE_DEC|BASE_UNIT_STRING, UNS(&units_byte_bytes), 0x0, |
1155 | 14 | NULL, HFILL } |
1156 | 14 | }, |
1157 | 14 | { &hf_bt_utp_extension_bitmask, |
1158 | 14 | { "Extension Bitmask", "bt-utp.extension_bitmask", |
1159 | 14 | FT_BYTES, BASE_NONE, NULL, 0x0, |
1160 | 14 | NULL, HFILL } |
1161 | 14 | }, |
1162 | 14 | { &hf_bt_utp_extension_close_reason, |
1163 | 14 | { "Close Reason", "bt-utp.extension_close_reason", |
1164 | 14 | FT_UINT32, BASE_DEC, VALS(bt_utp_close_reason_vals), 0x0, |
1165 | 14 | NULL, HFILL } |
1166 | 14 | }, |
1167 | 14 | { &hf_bt_utp_extension_unknown, |
1168 | 14 | { "Extension Unknown", "bt-utp.extension_unknown", |
1169 | 14 | FT_BYTES, BASE_NONE, NULL, 0x0, |
1170 | 14 | NULL, HFILL } |
1171 | 14 | }, |
1172 | 14 | { &hf_bt_utp_connection_id_v0, |
1173 | 14 | { "Connection ID", "bt-utp.connection_id", |
1174 | 14 | FT_UINT32, BASE_DEC, NULL, 0x0, |
1175 | 14 | NULL, HFILL } |
1176 | 14 | }, |
1177 | 14 | { &hf_bt_utp_connection_id_v1, |
1178 | 14 | { "Connection ID", "bt-utp.connection_id", |
1179 | 14 | FT_UINT16, BASE_DEC, NULL, 0x0, |
1180 | 14 | NULL, HFILL } |
1181 | 14 | }, |
1182 | 14 | { &hf_bt_utp_stream, |
1183 | 14 | { "Stream index", "bt-utp.stream", |
1184 | 14 | FT_UINT32, BASE_DEC, NULL, 0x0, |
1185 | 14 | NULL, HFILL } |
1186 | 14 | }, |
1187 | 14 | { &hf_bt_utp_timestamp_sec, |
1188 | 14 | { "Timestamp seconds", "bt-utp.timestamp_sec", |
1189 | 14 | FT_UINT32, BASE_DEC, NULL, 0x0, |
1190 | 14 | NULL, HFILL } |
1191 | 14 | }, |
1192 | 14 | { &hf_bt_utp_timestamp_us, |
1193 | 14 | { "Timestamp Microseconds", "bt-utp.timestamp_us", |
1194 | 14 | FT_UINT32, BASE_DEC, NULL, 0x0, |
1195 | 14 | NULL, HFILL } |
1196 | 14 | }, |
1197 | 14 | { &hf_bt_utp_timestamp_diff_us, |
1198 | 14 | { "Timestamp Difference Microseconds", "bt-utp.timestamp_diff_us", |
1199 | 14 | FT_UINT32, BASE_DEC, NULL, 0x0, |
1200 | 14 | NULL, HFILL } |
1201 | 14 | }, |
1202 | 14 | { &hf_bt_utp_wnd_size_v0, |
1203 | 14 | { "Window Size", "bt-utp.wnd_size", |
1204 | 14 | FT_UINT8, BASE_DEC, NULL, 0x0, |
1205 | 14 | "V0 receive window size, in multiples of 350 bytes", HFILL } |
1206 | 14 | }, |
1207 | 14 | { &hf_bt_utp_wnd_size_v1, |
1208 | 14 | { "Window Size", "bt-utp.wnd_size", |
1209 | 14 | FT_UINT32, BASE_DEC|BASE_UNIT_STRING, UNS(&units_byte_bytes), 0x0, |
1210 | 14 | NULL, HFILL } |
1211 | 14 | }, |
1212 | 14 | { &hf_bt_utp_seq_nr, |
1213 | 14 | { "Sequence number", "bt-utp.seq_nr", |
1214 | 14 | FT_UINT16, BASE_DEC, NULL, 0x0, |
1215 | 14 | NULL, HFILL } |
1216 | 14 | }, |
1217 | 14 | { &hf_bt_utp_ack_nr, |
1218 | 14 | { "ACK number", "bt-utp.ack_nr", |
1219 | 14 | FT_UINT16, BASE_DEC, NULL, 0x0, |
1220 | 14 | NULL, HFILL } |
1221 | 14 | }, |
1222 | 14 | { &hf_bt_utp_len, |
1223 | 14 | { "uTP Segment Len", "bt-utp.len", |
1224 | 14 | FT_UINT32, BASE_DEC, NULL, 0x0, |
1225 | 14 | NULL, HFILL } |
1226 | 14 | }, |
1227 | 14 | { &hf_bt_utp_data, |
1228 | 14 | { "Data", "bt-utp.data", |
1229 | 14 | FT_BYTES, BASE_NONE, NULL, 0x0, |
1230 | 14 | NULL, HFILL } |
1231 | 14 | }, |
1232 | 14 | { &hf_bt_utp_pdu_size, |
1233 | 14 | { "PDU Size", "bt-utp.pdu.size", |
1234 | 14 | FT_UINT32, BASE_DEC, NULL, 0x0, |
1235 | 14 | "The size of this PDU", HFILL } |
1236 | 14 | }, |
1237 | 14 | { &hf_bt_utp_continuation_to, |
1238 | 14 | { "This is a continuation to the PDU in frame", |
1239 | 14 | "bt-utp.continuation_to", FT_FRAMENUM, BASE_NONE, |
1240 | 14 | NULL, 0x0, "This is a continuation to the PDU in frame #", HFILL } |
1241 | 14 | }, |
1242 | 14 | }; |
1243 | | |
1244 | 14 | static ei_register_info ei[] = { |
1245 | 14 | { &ei_extension_len_invalid, |
1246 | 14 | { "bt-utp.extension_len.invalid", PI_PROTOCOL, PI_WARN, |
1247 | 14 | "The extension is an unexpected length", EXPFILL } |
1248 | 14 | }, |
1249 | 14 | }; |
1250 | | |
1251 | | /* Setup protocol subtree array */ |
1252 | 14 | static int *ett[] = { &ett_bt_utp, &ett_bt_utp_extension }; |
1253 | | |
1254 | 14 | module_t *bt_utp_module; |
1255 | 14 | expert_module_t *expert_bt_utp; |
1256 | | |
1257 | | /* Register protocol */ |
1258 | 14 | proto_bt_utp = proto_register_protocol ("uTorrent Transport Protocol", "BT-uTP", "bt-utp"); |
1259 | | |
1260 | 14 | bt_utp_module = prefs_register_protocol(proto_bt_utp, NULL); |
1261 | 14 | prefs_register_obsolete_preference(bt_utp_module, "enable"); |
1262 | 14 | prefs_register_bool_preference(bt_utp_module, |
1263 | 14 | "analyze_sequence_numbers", |
1264 | 14 | "Analyze uTP sequence numbers", |
1265 | 14 | "Make the uTP dissector analyze uTP sequence numbers. Currently this " |
1266 | 14 | "just means that it tries to find the correct start offset of a PDU " |
1267 | 14 | "if it detected that previous in-order packets spanned multiple " |
1268 | 14 | "frames.", |
1269 | 14 | &utp_analyze_seq); |
1270 | 14 | prefs_register_bool_preference(bt_utp_module, |
1271 | 14 | "enable_version0", |
1272 | 14 | "Dissect prerelease (version 0) packets", |
1273 | 14 | "Whether the dissector should attempt to dissect packets with the " |
1274 | 14 | "obsolete format (version 0) that predates BEP 29 (22-Jun-2009)", |
1275 | 14 | &enable_version0); |
1276 | 14 | prefs_register_uint_preference(bt_utp_module, |
1277 | 14 | "max_window_size", |
1278 | 14 | "Maximum window size (in hex)", |
1279 | 14 | "Maximum receive window size allowed by the dissector. Early clients " |
1280 | 14 | "(and a few modern ones) set this value to 0x380000 (the default), " |
1281 | 14 | "later ones use smaller values like 0x100000 and 0x40000. A higher " |
1282 | 14 | "value can detect nonstandard packets, but at the cost of false " |
1283 | 14 | "positives.", |
1284 | 14 | 16, &max_window_size); |
1285 | | |
1286 | 14 | proto_register_field_array(proto_bt_utp, hf, array_length(hf)); |
1287 | 14 | proto_register_subtree_array(ett, array_length(ett)); |
1288 | | |
1289 | 14 | expert_bt_utp = expert_register_protocol(proto_bt_utp); |
1290 | 14 | expert_register_field_array(expert_bt_utp, ei, array_length(ei)); |
1291 | | |
1292 | 14 | register_init_routine(utp_init); |
1293 | | |
1294 | 14 | bt_utp_handle = register_dissector("bt-utp", dissect_bt_utp, proto_bt_utp); |
1295 | 14 | } |
1296 | | |
1297 | | void |
1298 | | proto_reg_handoff_bt_utp(void) |
1299 | 14 | { |
1300 | | /* disabled by default since heuristic is weak */ |
1301 | | /* XXX: The heuristic is stronger now, but might still get false positives |
1302 | | * on packets with lots of zero bytes. Needs more testing before enabling |
1303 | | * by default. |
1304 | | */ |
1305 | 14 | heur_dissector_add("udp", dissect_bt_utp_heur, "BitTorrent UTP over UDP", "bt_utp_udp", proto_bt_utp, HEURISTIC_DISABLE); |
1306 | | |
1307 | 14 | dissector_add_for_decode_as_with_preference("udp.port", bt_utp_handle); |
1308 | | |
1309 | 14 | bittorrent_handle = find_dissector_add_dependency("bittorrent.utp", proto_bt_utp); |
1310 | 14 | } |
1311 | | |
1312 | | /* |
1313 | | * Editor modelines |
1314 | | * |
1315 | | * Local Variables: |
1316 | | * c-basic-offset: 2 |
1317 | | * tab-width: 8 |
1318 | | * indent-tabs-mode: nil |
1319 | | * End: |
1320 | | * |
1321 | | * ex: set shiftwidth=2 tabstop=8 expandtab: |
1322 | | * :indentSize=2:tabSize=8:noTabs=true: |
1323 | | */ |
1324 | | |