Revert "TODO epan/dissectors/asn1/kerberos/packet-kerberos-template.c new GSS flags"
[wireshark-sm.git] / epan / dissectors / packet-ldss.c
blob889c8449d0d45cbbe0df83e02f4ab4f7894cd75d
1 /* packet-ldss.c
2 * Routines for Local Download Sharing Service dissection
3 * Copyright 2009, Vasantha Crabb <vcrabb@managesoft.com.au>
4 * and Chris Adams <cadams@managesoft.com.au>
6 * Wireshark - Network traffic analyzer
7 * By Gerald Combs <gerald@wireshark.org>
8 * Copyright 1998 Gerald Combs
10 * SPDX-License-Identifier: GPL-2.0-or-later
13 /* LDSS is a protocol for peers on a LAN to cooperatively download
14 * files from a WAN. The peers ask each other about files and can
15 * send files to each other, thus WAN use is minimized. However
16 * if no peer possesses a file, a peer can download it via the WAN.
17 * Usually the download uses HTTP, but WAN downloads are beyond
18 * the scope of this dissector. To avoid saturating the WAN link,
19 * peers also tell each other what they are fetching and how fast
20 * they're downloading. Files are identified only by digests.
21 * Broadcasts are sent via UDP and files transferred via TCP. Both
22 * UDP and TCP portions of the protocol are handled in this dissector.
25 #include "config.h"
27 #include <stdlib.h>
28 #include <math.h>
30 #include <epan/packet.h>
31 #include <epan/expert.h>
32 #include <epan/strutil.h>
33 #include "packet-tcp.h"
35 /* The digest is up to 32 bytes long */
36 #define DIGEST_LEN 32
38 #define MESSAGE_ID_NEEDFILE 0
39 #define MESSAGE_ID_WILLSEND 1
42 static const value_string ldss_message_id_value[] = {
43 { MESSAGE_ID_NEEDFILE, "Need file" },
44 { MESSAGE_ID_WILLSEND, "Will send" },
45 { 0, NULL }
48 /* Message detail is inferred from various contents in the packet */
49 #define INFERRED_PEERSHUTDOWN 0
50 #define INFERRED_SEARCH 1
51 #define INFERRED_OFFER 2
52 #define INFERRED_PROMISE 3
53 #define INFERRED_WANDOWNLOAD 4
54 #define INFERRED_NONE 5
56 /* Displayed in the info column */
57 static const value_string ldss_inferred_info[] = {
58 { INFERRED_PEERSHUTDOWN, " - peer shutting down" },
59 { INFERRED_SEARCH, " - search" },
60 { INFERRED_OFFER, " - offer" },
61 { INFERRED_PROMISE, " - promise" },
62 { INFERRED_WANDOWNLOAD, " - WAN download start" },
63 { INFERRED_NONE, "" },
64 { 0, NULL }
67 /* Displayed in the tree as a generated item */
68 static const value_string ldss_inferred_value[] = {
69 { INFERRED_PEERSHUTDOWN, "Peer shutdown" },
70 { INFERRED_SEARCH, "File search" },
71 { INFERRED_OFFER, "File offer" },
72 { INFERRED_PROMISE, "Promise (download in progress)" },
73 { INFERRED_WANDOWNLOAD, "WAN download start" },
74 { INFERRED_NONE, "" },
75 { 0, NULL }
79 #define DIGEST_TYPE_UNKNOWN 0
80 #define DIGEST_TYPE_MD5 1
81 #define DIGEST_TYPE_SHA1 2
82 #define DIGEST_TYPE_SHA256 3
85 static const value_string ldss_digest_type_value[] = {
86 { DIGEST_TYPE_UNKNOWN, "Unknown" },
87 { DIGEST_TYPE_MD5, "MD5" },
88 { DIGEST_TYPE_SHA1, "SHA1" },
89 { DIGEST_TYPE_SHA256, "SHA256" },
90 { 0, NULL }
94 #define COMPRESSION_NONE 0
95 #define COMPRESSION_GZIP 1
98 static const value_string ldss_compression_value[] = {
99 { COMPRESSION_NONE, "None" },
100 { COMPRESSION_GZIP, "gzip" },
101 { 0, NULL }
104 /* Info about a broadcaster */
105 typedef struct _ldss_broadcaster_t {
106 address addr;
107 uint16_t port;
108 } ldss_broadcaster_t;
110 /* Info about a file */
111 typedef struct _ldss_file_t {
112 uint8_t *digest;
113 uint8_t digest_type;
114 } ldss_file_t;
116 /* Info about a broadcast packet */
117 typedef struct _ldss_broadcast_t {
118 uint32_t num;
119 nstime_t ts;
120 uint16_t message_id;
121 uint16_t message_detail;
122 uint16_t port;
123 uint64_t size;
124 uint64_t offset;
125 uint8_t compression;
126 ldss_file_t *file;
127 ldss_broadcaster_t *broadcaster;
128 } ldss_broadcast_t;
130 /* Info about a file as seen in a file request */
131 typedef struct _ldss_file_req_t {
132 uint32_t num;
133 nstime_t ts;
134 uint64_t size;
135 uint64_t offset;
136 uint8_t compression;
137 ldss_file_t *file;
138 } ldss_file_request_t;
140 /* Info attached to a file transfer conversation */
141 typedef struct _ldss_transfer_info_t {
142 uint32_t resp_num;
143 nstime_t resp_ts;
144 /* Refers either to the file in the request (for pull)
145 * or the file in the broadcast (for push) */
146 ldss_file_t *file;
147 ldss_file_request_t *req;
148 ldss_broadcast_t *broadcast;
149 } ldss_transfer_info_t;
151 /* Define udp_port for LDSS (IANA assigned) */
152 #define UDP_PORT_LDSS 6087
154 void proto_register_ldss(void);
155 void proto_reg_handoff_ldss(void);
157 /* Define the ldss proto */
158 static int proto_ldss;
160 /* Define headers for ldss */
161 static int hf_ldss_message_id;
162 static int hf_ldss_message_detail;
163 static int hf_ldss_digest_type;
164 static int hf_ldss_compression;
165 static int hf_ldss_cookie;
166 static int hf_ldss_digest;
167 static int hf_ldss_size;
168 static int hf_ldss_offset;
169 static int hf_ldss_target_time;
170 static int hf_ldss_reserved_1;
171 static int hf_ldss_port;
172 static int hf_ldss_rate;
173 static int hf_ldss_priority;
174 static int hf_ldss_property_count;
175 static int hf_ldss_properties;
176 static int hf_ldss_file_data;
177 static int hf_ldss_response_in;
178 static int hf_ldss_response_to;
179 static int hf_ldss_initiated_by;
180 static int hf_ldss_transfer_response_time;
181 static int hf_ldss_transfer_completed_in;
183 /* Define the tree for ldss */
184 static int ett_ldss_broadcast;
185 static int ett_ldss_transfer;
186 static int ett_ldss_transfer_req;
188 static expert_field ei_ldss_unrecognized_line;
191 static dissector_handle_t ldss_udp_handle;
192 static dissector_handle_t ldss_tcp_handle;
194 /* When seeing a broadcast talking about an open TCP port on a host, create
195 * a conversation to dissect anything sent/received at that address. Setup
196 * protocol data so the TCP dissection knows what broadcast triggered it. */
197 static void
198 prepare_ldss_transfer_conv(ldss_broadcast_t *broadcast)
200 if (!find_conversation(broadcast->num, &broadcast->broadcaster->addr, &broadcast->broadcaster->addr,
201 CONVERSATION_TCP, broadcast->broadcaster->port, broadcast->broadcaster->port, NO_ADDR_B|NO_PORT_B)) {
202 conversation_t *transfer_conv;
203 ldss_transfer_info_t *transfer_info;
205 transfer_info = wmem_new0(wmem_file_scope(), ldss_transfer_info_t);
206 transfer_info->broadcast = broadcast;
208 /* Preparation for later push/pull dissection */
209 transfer_conv = conversation_new (broadcast->num, &broadcast->broadcaster->addr, &broadcast->broadcaster->addr,
210 CONVERSATION_TCP, broadcast->broadcaster->port, broadcast->broadcaster->port, NO_ADDR2|NO_PORT2);
211 conversation_add_proto_data(transfer_conv, proto_ldss, transfer_info);
212 conversation_set_dissector(transfer_conv, ldss_tcp_handle);
216 /* Broadcasts are searches, offers or promises.
218 * Searches are sent by
219 * a peer when it needs a file (ie. while applying its policy, when it needs
220 * files such as installers to install software.)
222 * Each broadcast relates to one file and each file is identified only by its
223 * checksum - no file names are ever used. A search times out after 10 seconds
224 * (configurable) and the peer will then attempt to act on any offers by
225 * downloading (via push or pull - see dissect_ldss_transfer) from those peers.
227 * If no offers are received, the search fails and the peer fetches the file
228 * from a remote server, generally a HTTP server on the other side of a WAN.
229 * The protocol exists to minimize the number of WAN downloads needed.
231 * While downloading from WAN the peer sends promises to inform other peers
232 * when it will be available for them to download. This prevents multiple peers
233 * simultaneously downloading the same file. Promises also inform other peers
234 * how much download bandwidth is being used by their download. Other peers use
235 * this information and the configured knowledge of the WAN bandwidth to avoid
236 * saturating the WAN link, as file downloads are a non-time-critical and
237 * non-business-critical network function. LDSS is intended for networks of
238 * 5-20 machines connected by slow WAN link. The current implementation of the
239 * protocol allows administrator to configure "time windows" when WAN usage is
240 * throttled/unthrottled, though this isn't visible in LDSS.
242 * Once a WAN download or a LAN transfer (see below above dissect_ldss_transfer)
243 * has complete the peer will offer the file to other peers on the LAN so they
244 * don't need to download it themselves.
246 * Peers also notify when they shut down in case any other peer is waiting for
247 * a file. */
248 static int
249 dissect_ldss_broadcast(tvbuff_t *tvb, packet_info *pinfo, proto_tree *tree)
251 uint16_t messageID;
252 uint8_t digest_type;
253 uint8_t compression;
254 uint32_t cookie;
255 uint8_t *digest;
256 uint64_t size;
257 uint64_t offset;
258 uint32_t targetTime;
259 uint16_t port;
260 uint16_t rate;
261 uint16_t messageDetail = INFERRED_NONE;
263 proto_tree *ti, *ldss_tree;
265 const char *packet_type, *packet_detail;
267 messageID = tvb_get_ntohs (tvb, 0);
268 digest_type = tvb_get_uint8 (tvb, 2);
269 compression = tvb_get_uint8 (tvb, 3);
270 cookie = tvb_get_ntohl (tvb, 4);
271 digest = (uint8_t *)tvb_memdup (wmem_file_scope(), tvb, 8, DIGEST_LEN);
272 size = tvb_get_ntoh64 (tvb, 40);
273 offset = tvb_get_ntoh64 (tvb, 48);
274 targetTime = tvb_get_ntohl (tvb, 56);
275 port = tvb_get_ntohs (tvb, 64);
276 rate = tvb_get_ntohs (tvb, 66);
278 packet_type = val_to_str_const(messageID, ldss_message_id_value, "unknown");
280 if (messageID == MESSAGE_ID_WILLSEND) {
281 if (cookie == 0) {
282 /* Shutdown: Dishonor promises from this peer. Current
283 * implementation abuses WillSend for this. */
284 messageDetail = INFERRED_PEERSHUTDOWN;
286 else if (size == 0 && offset == 0) {
287 /* NeedFile search failed - going to WAN */
288 messageDetail = INFERRED_WANDOWNLOAD;
290 else if (size > 0) {
291 /* Size is known (not always the case) */
292 if (size == offset) {
293 /* File is available for pull on this peer's TCP port */
294 messageDetail = INFERRED_OFFER;
296 else {
297 /* WAN download progress announcement from this peer */
298 messageDetail = INFERRED_PROMISE;
302 else if (messageID == MESSAGE_ID_NEEDFILE) {
303 messageDetail = INFERRED_SEARCH;
305 packet_detail = val_to_str_const(messageDetail, ldss_inferred_info, "unknown");
307 /* Set the info column */
308 col_add_fstr(pinfo->cinfo, COL_INFO, "LDSS Broadcast (%s%s)",
309 packet_type,
310 packet_detail);
312 /* If we have a non-null tree (ie we are building the proto_tree
313 * instead of just filling out the columns), then give more detail. */
314 ti = proto_tree_add_item(tree, proto_ldss,
315 tvb, 0, (tvb_captured_length(tvb) > 72) ? tvb_captured_length(tvb) : 72, ENC_NA);
316 ldss_tree = proto_item_add_subtree(ti, ett_ldss_broadcast);
318 proto_tree_add_item(ldss_tree, hf_ldss_message_id,
319 tvb, 0, 2, ENC_BIG_ENDIAN);
320 ti = proto_tree_add_uint(ldss_tree, hf_ldss_message_detail,
321 tvb, 0, 0, messageDetail);
322 proto_item_set_generated(ti);
323 proto_tree_add_item(ldss_tree, hf_ldss_digest_type,
324 tvb, 2, 1, ENC_BIG_ENDIAN);
325 proto_tree_add_item(ldss_tree, hf_ldss_compression,
326 tvb, 3, 1, ENC_BIG_ENDIAN);
327 proto_tree_add_uint_format_value(ldss_tree, hf_ldss_cookie,
328 tvb, 4, 4, false,
329 "0x%x%s",
330 cookie,
331 (cookie == 0)
332 ? " - shutdown (promises from this peer are no longer valid)"
333 : "");
334 proto_tree_add_item(ldss_tree, hf_ldss_digest,
335 tvb, 8, DIGEST_LEN, ENC_NA);
336 proto_tree_add_item(ldss_tree, hf_ldss_size,
337 tvb, 40, 8, ENC_BIG_ENDIAN);
338 proto_tree_add_item(ldss_tree, hf_ldss_offset,
339 tvb, 48, 8, ENC_BIG_ENDIAN);
340 proto_tree_add_uint_format_value(ldss_tree, hf_ldss_target_time,
341 tvb, 56, 4, false,
342 "%d:%02d:%02d",
343 (int)(targetTime / 3600),
344 (int)((targetTime / 60) % 60),
345 (int)(targetTime % 60));
346 proto_tree_add_item(ldss_tree, hf_ldss_reserved_1,
347 tvb, 60, 4, ENC_BIG_ENDIAN);
348 proto_tree_add_uint_format_value(ldss_tree, hf_ldss_port,
349 tvb, 64, 2, false,
350 "%d%s",
351 port,
352 (messageID == MESSAGE_ID_WILLSEND &&
353 size > 0 &&
354 size == offset)
355 ? " - file can be pulled at this TCP port"
356 : (messageID == MESSAGE_ID_NEEDFILE
357 ? " - file can be pushed to this TCP port"
358 : ""));
359 proto_tree_add_uint_format_value(ldss_tree, hf_ldss_rate,
360 tvb, 66, 2, false,
361 "%ld",
362 (rate > 0)
363 ? (long)floor(exp(rate * G_LN2 / 2048))
364 : 0);
365 proto_tree_add_item(ldss_tree, hf_ldss_priority,
366 tvb, 68, 2, ENC_BIG_ENDIAN);
367 proto_tree_add_item(ldss_tree, hf_ldss_property_count,
368 tvb, 70, 2, ENC_BIG_ENDIAN);
369 if (tvb_reported_length(tvb) > 72) {
370 proto_tree_add_item(ldss_tree, hf_ldss_properties,
371 tvb, 72, tvb_captured_length(tvb) - 72, ENC_NA);
374 /* Finally, store the broadcast and register ourselves to dissect
375 * any pushes or pulls that result from this broadcast. All data
376 * is pushed/pulled over TCP using the port from the broadcast
377 * packet's port field.
378 * Track each by a TCP conversation with the remote end wildcarded.
379 * The TCP conv tracks back to a broadcast conv to determine what it
380 * is in response to.
382 * These steps only need to be done once per packet, so a variable
383 * tracks the highest frame number seen. Handles the case of first frame
384 * being frame zero. */
385 if ((messageDetail != INFERRED_PEERSHUTDOWN) &&
386 !PINFO_FD_VISITED(pinfo)) {
388 ldss_broadcast_t *data;
390 /* Populate data from the broadcast */
391 data = wmem_new0(wmem_file_scope(), ldss_broadcast_t);
392 data->num = pinfo->num;
393 data->ts = pinfo->abs_ts;
394 data->message_id = messageID;
395 data->message_detail = messageDetail;
396 data->port = port;
397 data->size = size;
398 data->offset = offset;
399 data->compression = compression;
401 data->file = wmem_new0(wmem_file_scope(), ldss_file_t);
402 data->file->digest = digest;
403 data->file->digest_type = digest_type;
405 data->broadcaster = wmem_new0(wmem_file_scope(), ldss_broadcaster_t);
406 copy_address_wmem(wmem_file_scope(), &data->broadcaster->addr, &pinfo->src);
407 data->broadcaster->port = port;
409 /* Dissect any future pushes/pulls */
410 if (port > 0) {
411 prepare_ldss_transfer_conv(data);
415 return tvb_captured_length(tvb);
418 /* Transfers happen in response to broadcasts, they are always TCP and are
419 * used to send the file to the port mentioned in the broadcast. There are
420 * 2 types of transfers: Pushes, which are direct responses to searches,
421 * in which the peer that has the file connects to the peer that doesn't and
422 * sends it, then disconnects. The other type of transfer is a pull, where
423 * the peer that doesn't have the file connects to the peer that does and
424 * requests it be sent.
426 * Pulls have a file request which identifies the desired file,
427 * while pushes simply send the file. In practice this works because every
428 * file the implementation sends searches for is on a different TCP port
429 * on the searcher's machine. */
430 static int
431 dissect_ldss_transfer (tvbuff_t *tvb, packet_info *pinfo, proto_tree *tree, void* data)
433 conversation_t *transfer_conv;
434 ldss_transfer_info_t *transfer_info;
435 struct tcpinfo *transfer_tcpinfo;
436 proto_tree *ti, *line_tree = NULL, *ldss_tree = NULL;
437 nstime_t broadcast_response_time;
439 /* Reject the packet if data is NULL */
440 if (data == NULL)
441 return 0;
442 transfer_tcpinfo = (struct tcpinfo *)data;
444 col_set_str(pinfo->cinfo, COL_PROTOCOL, "LDSS");
446 /* Look for the transfer conversation; this was created during
447 * earlier broadcast dissection (see prepare_ldss_transfer_conv) */
448 transfer_conv = find_conversation (pinfo->num, &pinfo->src, &pinfo->dst,
449 CONVERSATION_TCP, pinfo->srcport, pinfo->destport, 0);
450 DISSECTOR_ASSERT(transfer_conv);
451 transfer_info = (ldss_transfer_info_t *)conversation_get_proto_data(transfer_conv, proto_ldss);
452 DISSECTOR_ASSERT(transfer_info);
454 /* For a pull, the first packet in the TCP connection is the file request.
455 * First packet is identified by relative seq/ack numbers of 1.
456 * File request only appears on a pull (triggered by an offer - see above
457 * about broadcasts) */
458 if (transfer_tcpinfo->seq == 1 &&
459 transfer_tcpinfo->lastackseq == 1 &&
460 transfer_info->broadcast->message_id == MESSAGE_ID_WILLSEND) {
461 /* LDSS pull transfers look a lot like HTTP.
462 * Sample request:
463 * md5:01234567890123...
464 * Size: 2550
465 * Start: 0
466 * Compression: 0
467 * (remote end sends the file identified by the digest) */
468 unsigned offset = 0;
470 col_set_str(pinfo->cinfo, COL_INFO, "LDSS File Transfer (Requesting file - pull)");
472 if (transfer_info->req == NULL) {
473 transfer_info->req = wmem_new0(wmem_file_scope(), ldss_file_request_t);
474 transfer_info->req->file = wmem_new0(wmem_file_scope(), ldss_file_t);
477 ti = proto_tree_add_item(tree, proto_ldss,
478 tvb, 0, tvb_reported_length(tvb), ENC_NA);
479 ldss_tree = proto_item_add_subtree(ti, ett_ldss_transfer);
481 /* Populate digest data into the file struct in the request */
482 transfer_info->file = transfer_info->req->file;
484 /* Grab each line from the packet, there should be 4 but lets
485 * not walk off the end looking for more. */
486 while (tvb_offset_exists(tvb, offset)) {
487 int next_offset;
488 const uint8_t *line;
489 int linelen;
490 unsigned digest_type_len = 0;
492 linelen = tvb_find_line_end(tvb, offset, -1, &next_offset, false);
494 /* Include new-line in line */
495 line = tvb_get_string_enc(pinfo->pool, tvb, offset, linelen, ENC_ASCII);
497 line_tree = proto_tree_add_subtree(ldss_tree, tvb, offset, linelen,
498 ett_ldss_transfer_req, NULL,
499 tvb_format_text(pinfo->pool, tvb, offset, next_offset-offset));
501 if (strncmp(line,"md5:",4)==0) {
502 digest_type_len = 4;
503 transfer_info->file->digest_type = DIGEST_TYPE_MD5;
505 else if (strncmp(line, "sha1:", 5)==0) {
506 digest_type_len = 5;
507 transfer_info->file->digest_type = DIGEST_TYPE_SHA1;
509 else if (strncmp(line, "sha256:", 7)==0) {
510 digest_type_len = 7;
511 transfer_info->file->digest_type = DIGEST_TYPE_SHA256;
513 else if (strncmp(line, "unknown:", 8)==0) {
514 digest_type_len = 8;
515 transfer_info->file->digest_type = DIGEST_TYPE_UNKNOWN;
517 else if (strncmp(line, "Size: ", 6)==0) {
518 /* Sample size line:
519 * Size: 2550\n */
520 transfer_info->req->size = g_ascii_strtoull(line+6, NULL, 10);
521 ti = proto_tree_add_uint64(line_tree, hf_ldss_size,
522 tvb, offset+6, linelen-6, transfer_info->req->size);
523 proto_item_set_generated(ti);
525 else if (strncmp(line, "Start: ", 7)==0) {
526 /* Sample offset line:
527 * Start: 0\n */
528 transfer_info->req->offset = g_ascii_strtoull(line+7, NULL, 10);
529 ti = proto_tree_add_uint64(line_tree, hf_ldss_offset,
530 tvb, offset+7, linelen-7, transfer_info->req->offset);
531 proto_item_set_generated(ti);
533 else if (strncmp(line, "Compression: ", 13)==0) {
534 /* Sample compression line:
535 * Compression: 0\n */
536 transfer_info->req->compression = (int8_t)strtol(line+13, NULL, 10); /* XXX - bad cast */
537 ti = proto_tree_add_uint(line_tree, hf_ldss_compression,
538 tvb, offset+13, linelen-13, transfer_info->req->compression);
539 proto_item_set_generated(ti);
541 else {
542 proto_tree_add_expert(line_tree, pinfo, &ei_ldss_unrecognized_line, tvb, offset, linelen);
545 if (digest_type_len > 0) {
546 proto_item *tii = NULL;
548 /* Sample digest-type/digest line:
549 * md5:0123456789ABCDEF\n */
550 if (!transfer_info->file->digest) {
551 GByteArray *digest_bytes;
553 digest_bytes = g_byte_array_new();
554 hex_str_to_bytes(
555 tvb_get_ptr(tvb, offset+digest_type_len, linelen-digest_type_len),
556 digest_bytes, false);
558 if(digest_bytes->len >= DIGEST_LEN)
559 digest_bytes->len = (DIGEST_LEN-1);
560 /* Ensure the digest is zero-padded */
561 transfer_info->file->digest = (uint8_t *)wmem_alloc0(wmem_file_scope(), DIGEST_LEN);
562 memcpy(transfer_info->file->digest, digest_bytes->data, digest_bytes->len);
564 g_byte_array_free(digest_bytes, true);
567 tii = proto_tree_add_uint(line_tree, hf_ldss_digest_type,
568 tvb, offset, digest_type_len, transfer_info->file->digest_type);
569 proto_item_set_generated(tii);
570 tii = proto_tree_add_bytes(line_tree, hf_ldss_digest,
571 tvb, offset+digest_type_len, MIN(linelen-digest_type_len, DIGEST_LEN),
572 transfer_info->file->digest);
573 proto_item_set_generated(tii);
576 offset = next_offset;
579 /* Link forwards to the response for this pull. */
580 if (transfer_info->resp_num != 0) {
581 ti = proto_tree_add_uint(ldss_tree, hf_ldss_response_in,
582 tvb, 0, 0, transfer_info->resp_num);
583 proto_item_set_generated(ti);
586 transfer_info->req->num = pinfo->num;
587 transfer_info->req->ts = pinfo->abs_ts;
589 /* Remaining packets are the file response */
590 else {
591 uint64_t size;
592 uint64_t offset;
593 uint8_t compression;
595 /* size, digest, compression come from the file request for a pull but
596 * they come from the broadcast for a push. Pushes don't bother
597 * with a file request - they just send the data. We have to get file
598 * info from the offer broadcast which triggered this transfer.
599 * If we cannot find the file request, default to the broadcast. */
600 if (transfer_info->broadcast->message_id == MESSAGE_ID_WILLSEND &&
601 transfer_info->req != NULL) {
602 transfer_info->file = transfer_info->req->file;
603 size = transfer_info->req->size;
604 offset = transfer_info->req->offset;
605 compression = transfer_info->req->compression;
607 else {
608 transfer_info->file = transfer_info->broadcast->file;
609 size = transfer_info->broadcast->size;
610 offset = transfer_info->broadcast->offset;
611 compression = transfer_info->broadcast->compression;
614 /* Remaining data in this TCP connection is all file data.
615 * Always desegment if the size is 0 (ie. unknown)
617 if (pinfo->can_desegment) {
618 if (size == 0 || tvb_captured_length(tvb) < size) {
619 pinfo->desegment_offset = 0;
620 pinfo->desegment_len = DESEGMENT_UNTIL_FIN;
621 return -1;
625 /* OK. Now we have the whole file that was transferred. */
626 transfer_info->resp_num = pinfo->num;
627 transfer_info->resp_ts = pinfo->abs_ts;
629 col_add_fstr(pinfo->cinfo, COL_INFO, "LDSS File Transfer (Sending file - %s)",
630 transfer_info->broadcast->message_id == MESSAGE_ID_WILLSEND
631 ? "pull"
632 : "push");
634 ti = proto_tree_add_item(tree, proto_ldss,
635 tvb, 0, tvb_reported_length(tvb), ENC_NA);
636 ldss_tree = proto_item_add_subtree(ti, ett_ldss_transfer);
637 proto_tree_add_bytes_format(ldss_tree, hf_ldss_file_data,
638 tvb, 0, tvb_captured_length(tvb), NULL,
639 compression == COMPRESSION_GZIP
640 ? "Gzip compressed data: %d bytes"
641 : "File data: %d bytes",
642 tvb_captured_length(tvb));
643 #if defined (HAVE_ZLIB) || defined (HAVE_ZLIBNG)
644 /* Be nice and uncompress the file data. */
645 if (compression == COMPRESSION_GZIP) {
646 tvbuff_t *uncomp_tvb;
647 uncomp_tvb = tvb_child_uncompress_zlib(tvb, tvb, 0, tvb_captured_length(tvb));
648 if (uncomp_tvb != NULL) {
649 /* XXX: Maybe not a good idea to add a data_source for
650 what may very well be a large buffer since then
651 the full uncompressed buffer will be shown in a tab
652 in the hex bytes pane ?
653 However, if we don't, bytes in an unrelated tab will
654 be highlighted.
656 add_new_data_source(pinfo, uncomp_tvb, "Uncompressed Data");
657 proto_tree_add_bytes_format_value(ldss_tree, hf_ldss_file_data,
658 uncomp_tvb, 0, tvb_captured_length(uncomp_tvb),
659 NULL, "Uncompressed data: %d bytes",
660 tvb_captured_length(uncomp_tvb));
663 #endif
664 ti = proto_tree_add_uint(ldss_tree, hf_ldss_digest_type,
665 tvb, 0, 0, transfer_info->file->digest_type);
666 proto_item_set_generated(ti);
667 if (transfer_info->file->digest != NULL) {
668 /* This is ugly. You can't add bytes of nonzero length and have
669 * filtering work correctly unless you give a valid location in
670 * the packet. This hack pretends the first 32 bytes of the packet
671 * are the digest, which they aren't: they're actually the first 32
672 * bytes of the file that was sent. */
673 ti = proto_tree_add_bytes(ldss_tree, hf_ldss_digest,
674 tvb, 0, DIGEST_LEN, transfer_info->file->digest);
676 proto_item_set_generated(ti);
677 ti = proto_tree_add_uint64(ldss_tree, hf_ldss_size,
678 tvb, 0, 0, size);
679 proto_item_set_generated(ti);
680 ti = proto_tree_add_uint64(ldss_tree, hf_ldss_offset,
681 tvb, 0, 0, offset);
682 proto_item_set_generated(ti);
683 ti = proto_tree_add_uint(ldss_tree, hf_ldss_compression,
684 tvb, 0, 0, compression);
685 proto_item_set_generated(ti);
686 /* Link to the request for a pull. */
687 if (transfer_info->broadcast->message_id == MESSAGE_ID_WILLSEND &&
688 transfer_info->req != NULL &&
689 transfer_info->req->num != 0) {
690 ti = proto_tree_add_uint(ldss_tree, hf_ldss_response_to,
691 tvb, 0, 0, transfer_info->req->num);
692 proto_item_set_generated(ti);
696 /* Print the pull response time */
697 if (transfer_info->broadcast->message_id == MESSAGE_ID_WILLSEND &&
698 transfer_info->req != NULL &&
699 transfer_info->resp_num != 0) {
700 nstime_t pull_response_time;
701 nstime_delta(&pull_response_time, &transfer_info->resp_ts,
702 &transfer_info->req->ts);
703 ti = proto_tree_add_time(ldss_tree, hf_ldss_transfer_response_time,
704 tvb, 0, 0, &pull_response_time);
705 proto_item_set_generated(ti);
708 /* Link the transfer back to the initiating broadcast. Response time is
709 * calculated as the time from broadcast to completed transfer. */
710 ti = proto_tree_add_uint(ldss_tree, hf_ldss_initiated_by,
711 tvb, 0, 0, transfer_info->broadcast->num);
712 proto_item_set_generated(ti);
714 if (transfer_info->resp_num != 0) {
715 nstime_delta(&broadcast_response_time, &transfer_info->resp_ts,
716 &transfer_info->broadcast->ts);
717 ti = proto_tree_add_time(ldss_tree, hf_ldss_transfer_completed_in,
718 tvb, 0, 0, &broadcast_response_time);
719 proto_item_set_generated(ti);
722 /* This conv got its addr2/port2 set by the TCP dissector because a TCP
723 * connection was established. Make a new one to handle future connections
724 * to the addr/port mentioned in the broadcast, because that socket is
725 * still open. */
726 if (transfer_tcpinfo->seq == 1 &&
727 transfer_tcpinfo->lastackseq == 1) {
729 prepare_ldss_transfer_conv(transfer_info->broadcast);
732 return tvb_captured_length(tvb);
735 static bool
736 is_broadcast(address* addr)
738 static const uint8_t broadcast_addr_bytes[6] = {
739 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF
741 static const address broadcast_addr = ADDRESS_INIT(AT_ETHER, 6, broadcast_addr_bytes);
743 return addresses_equal(addr, &broadcast_addr);
746 static int
747 dissect_ldss (tvbuff_t *tvb, packet_info *pinfo, proto_tree *tree, void *data _U_)
749 if (is_broadcast(&pinfo->dl_dst)) {
751 col_set_str(pinfo->cinfo, COL_PROTOCOL, "LDSS");
752 return dissect_ldss_broadcast(tvb, pinfo, tree);
755 /* Definitely not LDSS */
756 return 0;
759 void
760 proto_register_ldss (void) {
761 static hf_register_info hf[] = {
762 { &hf_ldss_message_id,
763 { "LDSS Message ID",
764 "ldss.message_id",
765 FT_UINT16, BASE_DEC, VALS(ldss_message_id_value), 0x0,
766 NULL, HFILL
769 { &hf_ldss_message_detail,
770 { "Inferred meaning",
771 "ldss.inferred_meaning",
772 FT_UINT16, BASE_DEC, VALS(ldss_inferred_value), 0x0,
773 "Inferred meaning of the packet", HFILL
776 { &hf_ldss_digest_type,
777 { "Digest Type",
778 "ldss.digest_type",
779 FT_UINT8, BASE_DEC, VALS(ldss_digest_type_value), 0x0,
780 NULL, HFILL
783 { &hf_ldss_compression,
784 { "Compressed Format",
785 "ldss.compression",
786 FT_UINT8, BASE_DEC, VALS(ldss_compression_value), 0x0,
787 NULL, HFILL
790 { &hf_ldss_cookie,
791 { "Cookie",
792 "ldss.cookie",
793 FT_UINT32, BASE_HEX, NULL, 0x0,
794 "Random value used for duplicate rejection", HFILL
797 { &hf_ldss_digest,
798 { "Digest",
799 "ldss.digest",
800 FT_BYTES, BASE_NONE, NULL, 0x0,
801 "Digest of file padded with 0x00", HFILL
804 { &hf_ldss_size,
805 { "Size",
806 "ldss.size",
807 FT_UINT64, BASE_DEC, NULL, 0x0,
808 "Size of complete file", HFILL
811 { &hf_ldss_offset,
812 { "Offset",
813 "ldss.offset",
814 FT_UINT64, BASE_DEC, NULL, 0x0,
815 "Size of currently available portion of file", HFILL
818 { &hf_ldss_target_time,
819 { "Target time (relative)",
820 "ldss.target_time",
821 FT_UINT32, BASE_DEC, NULL, 0x0,
822 "Time until file will be needed/available", HFILL
825 { &hf_ldss_reserved_1,
826 { "Reserved",
827 "ldss.reserved_1",
828 FT_UINT32, BASE_HEX, NULL, 0x0,
829 "Unused field - should be 0x00000000", HFILL
832 { &hf_ldss_port,
833 { "Port",
834 "ldss.port",
835 FT_UINT16, BASE_DEC, NULL, 0x0,
836 "TCP port for push (Need file) or pull (Will send)", HFILL
839 { &hf_ldss_rate,
840 { "Rate (B/s)",
841 "ldss.rate",
842 FT_UINT16, BASE_DEC, NULL, 0x0,
843 "Estimated current download rate", HFILL
846 { &hf_ldss_priority,
847 { "Priority",
848 "ldss.priority",
849 FT_UINT16, BASE_DEC, NULL, 0x0,
850 NULL, HFILL
853 { &hf_ldss_property_count,
854 { "Property Count",
855 "ldss.property_count",
856 FT_UINT16, BASE_DEC, NULL, 0x0,
857 NULL, HFILL
860 { &hf_ldss_properties,
861 { "Properties",
862 "ldss.properties",
863 FT_BYTES, BASE_NONE, NULL, 0x0,
864 NULL, HFILL
867 { &hf_ldss_file_data,
868 { "File data",
869 "ldss.file_data",
870 FT_BYTES, BASE_NONE, NULL, 0x0,
871 NULL, HFILL
874 { &hf_ldss_response_in,
875 { "Response In",
876 "ldss.response_in",
877 FT_FRAMENUM, BASE_NONE, FRAMENUM_TYPE(FT_FRAMENUM_RESPONSE), 0x0,
878 "The response to this file pull request is in this frame", HFILL }
880 { &hf_ldss_response_to,
881 { "Request In",
882 "ldss.response_to",
883 FT_FRAMENUM, BASE_NONE, FRAMENUM_TYPE(FT_FRAMENUM_REQUEST), 0x0,
884 "This is a response to the file pull request in this frame", HFILL }
886 { &hf_ldss_initiated_by,
887 { "Initiated by",
888 "ldss.initiated_by",
889 FT_FRAMENUM, BASE_NONE, NULL, 0x0,
890 "The broadcast that initiated this file transfer", HFILL }
892 { &hf_ldss_transfer_response_time,
893 { "Transfer response time",
894 "ldss.transfer_response_time",
895 FT_RELATIVE_TIME, BASE_NONE, NULL, 0x0,
896 "The time between the request and the response for a pull transfer", HFILL }
898 { &hf_ldss_transfer_completed_in,
899 { "Transfer completed in",
900 "ldss.transfer_completed_in",
901 FT_RELATIVE_TIME, BASE_NONE, NULL, 0x0,
902 "The time between requesting the file and completion of the file transfer", HFILL }
906 static int *ett[] = { &ett_ldss_broadcast, &ett_ldss_transfer, &ett_ldss_transfer_req };
908 static ei_register_info ei[] = {
909 { &ei_ldss_unrecognized_line, { "ldss.unrecognized_line", PI_PROTOCOL, PI_WARN, "Unrecognized line ignored", EXPFILL }},
912 expert_module_t* expert_ldss;
914 proto_ldss = proto_register_protocol("Local Download Sharing Service", "LDSS", "ldss");
915 proto_register_field_array(proto_ldss, hf, array_length(hf));
916 proto_register_subtree_array(ett, array_length(ett));
917 expert_ldss = expert_register_protocol(proto_ldss);
918 expert_register_field_array(expert_ldss, ei, array_length(ei));
920 ldss_udp_handle = register_dissector("ldss", dissect_ldss, proto_ldss);
921 ldss_tcp_handle = register_dissector("ldss_transfer", dissect_ldss_transfer, proto_ldss);
925 /* The registration hand-off routine */
926 void
927 proto_reg_handoff_ldss (void)
929 dissector_add_uint_with_preference("udp.port", UDP_PORT_LDSS, ldss_udp_handle);
933 * Editor modelines - https://www.wireshark.org/tools/modelines.html
935 * Local variables:
936 * c-basic-offset: 8
937 * tab-width: 8
938 * indent-tabs-mode: t
939 * End:
941 * vi: set shiftwidth=8 tabstop=8 noexpandtab:
942 * :indentSize=8:tabSize=8:noTabs=false: