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.
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 */
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" },
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
, "" },
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
, "" },
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" },
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" },
104 /* Info about a broadcaster */
105 typedef struct _ldss_broadcaster_t
{
108 } ldss_broadcaster_t
;
110 /* Info about a file */
111 typedef struct _ldss_file_t
{
116 /* Info about a broadcast packet */
117 typedef struct _ldss_broadcast_t
{
121 uint16_t message_detail
;
127 ldss_broadcaster_t
*broadcaster
;
130 /* Info about a file as seen in a file request */
131 typedef struct _ldss_file_req_t
{
138 } ldss_file_request_t
;
140 /* Info attached to a file transfer conversation */
141 typedef struct _ldss_transfer_info_t
{
144 /* Refers either to the file in the request (for pull)
145 * or the file in the broadcast (for push) */
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. */
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
249 dissect_ldss_broadcast(tvbuff_t
*tvb
, packet_info
*pinfo
, proto_tree
*tree
)
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
) {
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
;
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
;
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)",
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
,
332 ? " - shutdown (promises from this peer are no longer valid)"
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
,
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
,
352 (messageID
== MESSAGE_ID_WILLSEND
&&
355 ? " - file can be pulled at this TCP port"
356 : (messageID
== MESSAGE_ID_NEEDFILE
357 ? " - file can be pushed to this TCP port"
359 proto_tree_add_uint_format_value(ldss_tree
, hf_ldss_rate
,
363 ? (long)floor(exp(rate
* G_LN2
/ 2048))
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
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
;
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 */
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. */
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 */
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.
463 * md5:01234567890123...
467 * (remote end sends the file identified by the digest) */
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
)) {
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) {
503 transfer_info
->file
->digest_type
= DIGEST_TYPE_MD5
;
505 else if (strncmp(line
, "sha1:", 5)==0) {
507 transfer_info
->file
->digest_type
= DIGEST_TYPE_SHA1
;
509 else if (strncmp(line
, "sha256:", 7)==0) {
511 transfer_info
->file
->digest_type
= DIGEST_TYPE_SHA256
;
513 else if (strncmp(line
, "unknown:", 8)==0) {
515 transfer_info
->file
->digest_type
= DIGEST_TYPE_UNKNOWN
;
517 else if (strncmp(line
, "Size: ", 6)==0) {
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:
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
);
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();
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 */
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
;
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
;
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
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
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
));
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
,
679 proto_item_set_generated(ti
);
680 ti
= proto_tree_add_uint64(ldss_tree
, hf_ldss_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
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
);
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
);
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 */
760 proto_register_ldss (void) {
761 static hf_register_info hf
[] = {
762 { &hf_ldss_message_id
,
765 FT_UINT16
, BASE_DEC
, VALS(ldss_message_id_value
), 0x0,
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
,
779 FT_UINT8
, BASE_DEC
, VALS(ldss_digest_type_value
), 0x0,
783 { &hf_ldss_compression
,
784 { "Compressed Format",
786 FT_UINT8
, BASE_DEC
, VALS(ldss_compression_value
), 0x0,
793 FT_UINT32
, BASE_HEX
, NULL
, 0x0,
794 "Random value used for duplicate rejection", HFILL
800 FT_BYTES
, BASE_NONE
, NULL
, 0x0,
801 "Digest of file padded with 0x00", HFILL
807 FT_UINT64
, BASE_DEC
, NULL
, 0x0,
808 "Size of complete file", HFILL
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)",
821 FT_UINT32
, BASE_DEC
, NULL
, 0x0,
822 "Time until file will be needed/available", HFILL
825 { &hf_ldss_reserved_1
,
828 FT_UINT32
, BASE_HEX
, NULL
, 0x0,
829 "Unused field - should be 0x00000000", HFILL
835 FT_UINT16
, BASE_DEC
, NULL
, 0x0,
836 "TCP port for push (Need file) or pull (Will send)", HFILL
842 FT_UINT16
, BASE_DEC
, NULL
, 0x0,
843 "Estimated current download rate", HFILL
849 FT_UINT16
, BASE_DEC
, NULL
, 0x0,
853 { &hf_ldss_property_count
,
855 "ldss.property_count",
856 FT_UINT16
, BASE_DEC
, NULL
, 0x0,
860 { &hf_ldss_properties
,
863 FT_BYTES
, BASE_NONE
, NULL
, 0x0,
867 { &hf_ldss_file_data
,
870 FT_BYTES
, BASE_NONE
, NULL
, 0x0,
874 { &hf_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
,
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
,
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 */
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
938 * indent-tabs-mode: t
941 * vi: set shiftwidth=8 tabstop=8 noexpandtab:
942 * :indentSize=8:tabSize=8:noTabs=false: