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>
8 * Wireshark - Network traffic analyzer
9 * By Gerald Combs <gerald@wireshark.org>
10 * Copyright 1998 Gerald Combs
12 * This program is free software; you can redistribute it and/or
13 * modify it under the terms of the GNU General Public License
14 * as published by the Free Software Foundation; either version 2
15 * of the License, or (at your option) any later version.
17 * This program is distributed in the hope that it will be useful,
18 * but WITHOUT ANY WARRANTY; without even the implied warranty of
19 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
20 * GNU General Public License for more details.
22 * You should have received a copy of the GNU General Public License
23 * along with this program; if not, write to the Free Software
24 * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA.
27 /* LDSS is a protocol for peers on a LAN to co-operatively download
28 * files from a WAN. The peers ask each other about files and can
29 * send files to each other, thus WAN use is minimized. However
30 * if no peer possesses a file, a peer can download it via the WAN.
31 * Usually the download uses HTTP, but WAN downloads are beyond
32 * the scope of this dissector. To avoid saturating the WAN link,
33 * peers also tell each other what they are fetching and how fast
34 * they're downloading. Files are identified only by digests.
35 * Broadcasts are sent via UDP and files transferred via TCP. Both
36 * UDP and TCP portions of the protocol are handled in this dissector.
47 #include <epan/packet.h>
48 #include <epan/conversation.h>
49 #include <epan/addr_resolv.h>
50 #include <epan/ipproto.h>
51 #include <epan/prefs.h>
52 #include <epan/strutil.h>
53 #include <epan/wmem/wmem.h>
54 #include <epan/dissectors/packet-tcp.h>
56 /* The digest is up to 32 bytes long */
59 #define MESSAGE_ID_NEEDFILE 0
60 #define MESSAGE_ID_WILLSEND 1
63 static const value_string ldss_message_id_value
[] = {
64 { MESSAGE_ID_NEEDFILE
, "Need file" },
65 { MESSAGE_ID_WILLSEND
, "Will send" },
69 /* Message detail is inferred from various contents in the packet */
70 #define INFERRED_PEERSHUTDOWN 0
71 #define INFERRED_SEARCH 1
72 #define INFERRED_OFFER 2
73 #define INFERRED_PROMISE 3
74 #define INFERRED_WANDOWNLOAD 4
75 #define INFERRED_NONE 5
77 /* Displayed in the info column */
78 static const value_string ldss_inferred_info
[] = {
79 { INFERRED_PEERSHUTDOWN
, " - peer shutting down" },
80 { INFERRED_SEARCH
, " - search" },
81 { INFERRED_OFFER
, " - offer" },
82 { INFERRED_PROMISE
, " - promise" },
83 { INFERRED_WANDOWNLOAD
, " - WAN download start" },
84 { INFERRED_NONE
, "" },
88 /* Displayed in the tree as a generated item */
89 static const value_string ldss_inferred_value
[] = {
90 { INFERRED_PEERSHUTDOWN
, "Peer shutdown" },
91 { INFERRED_SEARCH
, "File search" },
92 { INFERRED_OFFER
, "File offer" },
93 { INFERRED_PROMISE
, "Promise (download in progress)" },
94 { INFERRED_WANDOWNLOAD
, "WAN download start" },
95 { INFERRED_NONE
, "" },
100 #define DIGEST_TYPE_UNKNOWN 0
101 #define DIGEST_TYPE_MD5 1
102 #define DIGEST_TYPE_SHA1 2
103 #define DIGEST_TYPE_SHA256 3
106 static const value_string ldss_digest_type_value
[] = {
107 { DIGEST_TYPE_UNKNOWN
, "Unknown" },
108 { DIGEST_TYPE_MD5
, "MD5" },
109 { DIGEST_TYPE_SHA1
, "SHA1" },
110 { DIGEST_TYPE_SHA256
, "SHA256" },
115 #define COMPRESSION_NONE 0
116 #define COMPRESSION_GZIP 1
119 static const value_string ldss_compression_value
[] = {
120 { COMPRESSION_NONE
, "None" },
121 { COMPRESSION_GZIP
, "gzip" },
125 /* Info about a broadcaster */
126 typedef struct _ldss_broadcaster_t
{
129 } ldss_broadcaster_t
;
131 /* Info about a file */
132 typedef struct _ldss_file_t
{
137 /* Info about a broadcast packet */
138 typedef struct _ldss_broadcast_t
{
142 guint16 message_detail
;
148 ldss_broadcaster_t
*broadcaster
;
151 /* Info about a file as seen in a file request */
152 typedef struct _ldss_file_req_t
{
159 } ldss_file_request_t
;
161 /* Info attached to a file transfer conversation */
162 typedef struct _ldss_transfer_info_t
{
165 /* Refers either to the file in the request (for pull)
166 * or the file in the broadcast (for push) */
168 ldss_file_request_t
*req
;
169 ldss_broadcast_t
*broadcast
;
170 } ldss_transfer_info_t
;
172 /* Define udp_port for LDSS (IANA assigned) */
173 #define UDP_PORT_LDSS 6087
175 void proto_register_ldss(void);
176 void proto_reg_handoff_ldss(void);
178 /* Define the ldss proto */
179 static int proto_ldss
= -1;
181 /* Define headers for ldss */
182 static int hf_ldss_message_id
= -1;
183 static int hf_ldss_message_detail
= -1;
184 static int hf_ldss_digest_type
= -1;
185 static int hf_ldss_compression
= -1;
186 static int hf_ldss_cookie
= -1;
187 static int hf_ldss_digest
= -1;
188 static int hf_ldss_size
= -1;
189 static int hf_ldss_offset
= -1;
190 static int hf_ldss_target_time
= -1;
191 static int hf_ldss_reserved_1
= -1;
192 static int hf_ldss_port
= -1;
193 static int hf_ldss_rate
= -1;
194 static int hf_ldss_priority
= -1;
195 static int hf_ldss_property_count
= -1;
196 static int hf_ldss_properties
= -1;
197 static int hf_ldss_file_data
= -1;
198 static int hf_ldss_response_in
= -1;
199 static int hf_ldss_response_to
= -1;
200 static int hf_ldss_initiated_by
= -1;
201 static int hf_ldss_transfer_response_time
= -1;
202 static int hf_ldss_transfer_completed_in
= -1;
204 /* Define the tree for ldss */
205 static int ett_ldss_broadcast
= -1;
206 static int ett_ldss_transfer
= -1;
207 static int ett_ldss_transfer_req
= -1;
209 static dissector_handle_t ldss_udp_handle
;
210 static dissector_handle_t ldss_tcp_handle
;
212 /* Global variables associated with the preferences for ldss */
213 static guint global_udp_port_ldss
= UDP_PORT_LDSS
;
215 /* Avoid creating conversations and data twice */
216 static unsigned int highest_num_seen
= 0;
218 /* When seeing a broadcast talking about an open TCP port on a host, create
219 * a conversation to dissect anything sent/received at that address. Setup
220 * protocol data so the TCP dissection knows what broadcast triggered it. */
222 prepare_ldss_transfer_conv(ldss_broadcast_t
*broadcast
)
224 conversation_t
*transfer_conv
;
225 ldss_transfer_info_t
*transfer_info
;
227 transfer_info
= wmem_new0(wmem_file_scope(), ldss_transfer_info_t
);
228 transfer_info
->broadcast
= broadcast
;
230 /* Preparation for later push/pull dissection */
231 transfer_conv
= conversation_new (broadcast
->num
, &broadcast
->broadcaster
->addr
, &broadcast
->broadcaster
->addr
,
232 PT_TCP
, broadcast
->broadcaster
->port
, broadcast
->broadcaster
->port
, NO_ADDR2
|NO_PORT2
);
233 conversation_add_proto_data(transfer_conv
, proto_ldss
, transfer_info
);
234 conversation_set_dissector(transfer_conv
, ldss_tcp_handle
);
237 /* Broadcasts are searches, offers or promises.
239 * Searches are sent by
240 * a peer when it needs a file (ie. while applying its policy, when it needs
241 * files such as installers to install software.)
243 * Each broadcast relates to one file and each file is identified only by its
244 * checksum - no file names are ever used. A search times out after 10 seconds
245 * (configurable) and the peer will then attempt to act on any offers by
246 * downloading (via push or pull - see dissect_ldss_transfer) from those peers.
248 * If no offers are received, the search fails and the peer fetches the file
249 * from a remote server, generally a HTTP server on the other side of a WAN.
250 * The protocol exists to minimize the number of WAN downloads needed.
252 * While downloading from WAN the peer sends promises to inform other peers
253 * when it will be available for them to download. This prevents multiple peers
254 * simultaneously downloading the same file. Promises also inform other peers
255 * how much download bandwidth is being used by their download. Other peers use
256 * this information and the configured knowledge of the WAN bandwidth to avoid
257 * saturating the WAN link, as file downloads are a non-time-critical and
258 * non-business-critical network function. LDSS is intended for networks of
259 * 5-20 machines connected by slow WAN link. The current implementation of the
260 * protocol allows administrator to configure "time windows" when WAN usage is
261 * throttled/unthrottled, though this isn't visible in LDSS.
263 * Once a WAN download or a LAN transfer (see below above dissect_ldss_transfer)
264 * has complete the peer will offer the file to other peers on the LAN so they
265 * don't need to download it themselves.
267 * Peers also notify when they shut down in case any other peer is waiting for
270 dissect_ldss_broadcast(tvbuff_t
*tvb
, packet_info
*pinfo
, proto_tree
*tree
)
282 guint16 messageDetail
= INFERRED_NONE
;
284 proto_tree
*ti
, *ldss_tree
;
286 const gchar
*packet_type
, *packet_detail
;
288 messageID
= tvb_get_ntohs (tvb
, 0);
289 digest_type
= tvb_get_guint8 (tvb
, 2);
290 compression
= tvb_get_guint8 (tvb
, 3);
291 cookie
= tvb_get_ntohl (tvb
, 4);
292 digest
= (guint8
*)tvb_memdup (NULL
, tvb
, 8, DIGEST_LEN
);
293 size
= tvb_get_ntoh64 (tvb
, 40);
294 offset
= tvb_get_ntoh64 (tvb
, 48);
295 targetTime
= tvb_get_ntohl (tvb
, 56);
296 port
= tvb_get_ntohs (tvb
, 64);
297 rate
= tvb_get_ntohs (tvb
, 66);
299 packet_type
= val_to_str_const(messageID
, ldss_message_id_value
, "unknown");
301 if (messageID
== MESSAGE_ID_WILLSEND
) {
303 /* Shutdown: Dishonor promises from this peer. Current
304 * implementation abuses WillSend for this. */
305 messageDetail
= INFERRED_PEERSHUTDOWN
;
307 else if (size
== 0 && offset
== 0) {
308 /* NeedFile search failed - going to WAN */
309 messageDetail
= INFERRED_WANDOWNLOAD
;
312 /* Size is known (not always the case) */
313 if (size
== offset
) {
314 /* File is available for pull on this peer's TCP port */
315 messageDetail
= INFERRED_OFFER
;
318 /* WAN download progress announcement from this peer */
319 messageDetail
= INFERRED_PROMISE
;
323 else if (messageID
== MESSAGE_ID_NEEDFILE
) {
324 messageDetail
= INFERRED_SEARCH
;
326 packet_detail
= val_to_str_const(messageDetail
, ldss_inferred_info
, "unknown");
328 /* Set the info column */
329 col_add_fstr(pinfo
->cinfo
, COL_INFO
, "LDSS Broadcast (%s%s)",
333 /* If we have a non-null tree (ie we are building the proto_tree
334 * instead of just filling out the columns), then give more detail. */
336 ti
= proto_tree_add_item(tree
, proto_ldss
,
337 tvb
, 0, (tvb_length(tvb
) > 72) ? tvb_length(tvb
) : 72, ENC_NA
);
338 ldss_tree
= proto_item_add_subtree(ti
, ett_ldss_broadcast
);
340 proto_tree_add_item(ldss_tree
, hf_ldss_message_id
,
341 tvb
, 0, 2, ENC_BIG_ENDIAN
);
342 ti
= proto_tree_add_uint(ldss_tree
, hf_ldss_message_detail
,
343 tvb
, 0, 0, messageDetail
);
344 PROTO_ITEM_SET_GENERATED(ti
);
345 proto_tree_add_item(ldss_tree
, hf_ldss_digest_type
,
346 tvb
, 2, 1, ENC_BIG_ENDIAN
);
347 proto_tree_add_item(ldss_tree
, hf_ldss_compression
,
348 tvb
, 3, 1, ENC_BIG_ENDIAN
);
349 proto_tree_add_uint_format_value(ldss_tree
, hf_ldss_cookie
,
354 ? " - shutdown (promises from this peer are no longer valid)"
356 proto_tree_add_item(ldss_tree
, hf_ldss_digest
,
357 tvb
, 8, DIGEST_LEN
, ENC_NA
);
358 proto_tree_add_item(ldss_tree
, hf_ldss_size
,
359 tvb
, 40, 8, ENC_BIG_ENDIAN
);
360 proto_tree_add_item(ldss_tree
, hf_ldss_offset
,
361 tvb
, 48, 8, ENC_BIG_ENDIAN
);
362 proto_tree_add_uint_format_value(ldss_tree
, hf_ldss_target_time
,
365 (int)(targetTime
/ 3600),
366 (int)((targetTime
/ 60) % 60),
367 (int)(targetTime
% 60));
368 proto_tree_add_item(ldss_tree
, hf_ldss_reserved_1
,
369 tvb
, 60, 4, ENC_BIG_ENDIAN
);
370 proto_tree_add_uint_format_value(ldss_tree
, hf_ldss_port
,
374 (messageID
== MESSAGE_ID_WILLSEND
&&
377 ? " - file can be pulled at this TCP port"
378 : (messageID
== MESSAGE_ID_NEEDFILE
379 ? " - file can be pushed to this TCP port"
381 proto_tree_add_uint_format_value(ldss_tree
, hf_ldss_rate
,
385 ? (long)floor(exp(rate
* G_LN2
/ 2048))
387 proto_tree_add_item(ldss_tree
, hf_ldss_priority
,
388 tvb
, 68, 2, ENC_BIG_ENDIAN
);
389 proto_tree_add_item(ldss_tree
, hf_ldss_property_count
,
390 tvb
, 70, 2, ENC_BIG_ENDIAN
);
391 if (tvb_length(tvb
) > 72) {
392 proto_tree_add_item(ldss_tree
, hf_ldss_properties
,
393 tvb
, 72, tvb_length(tvb
) - 72, ENC_NA
);
397 /* Finally, store the broadcast and register ourselves to dissect
398 * any pushes or pulls that result from this broadcast. All data
399 * is pushed/pulled over TCP using the port from the broadcast
400 * packet's port field.
401 * Track each by a TCP conversation with the remote end wildcarded.
402 * The TCP conv tracks back to a broadcast conv to determine what it
405 * These steps only need to be done once per packet, so a variable
406 * tracks the highest frame number seen. Handles the case of first frame
407 * being frame zero. */
408 if (messageDetail
!= INFERRED_PEERSHUTDOWN
&&
409 (highest_num_seen
== 0 ||
410 highest_num_seen
< pinfo
->fd
->num
)) {
412 ldss_broadcast_t
*data
;
414 /* Populate data from the broadcast */
415 data
= wmem_new0(wmem_file_scope(), ldss_broadcast_t
);
416 data
->num
= pinfo
->fd
->num
;
417 data
->ts
= pinfo
->fd
->abs_ts
;
418 data
->message_id
= messageID
;
419 data
->message_detail
= messageDetail
;
422 data
->offset
= offset
;
423 data
->compression
= compression
;
425 data
->file
= wmem_new0(wmem_file_scope(), ldss_file_t
);
426 data
->file
->digest
= digest
;
427 data
->file
->digest_type
= digest_type
;
429 data
->broadcaster
= wmem_new0(wmem_file_scope(), ldss_broadcaster_t
);
430 COPY_ADDRESS(&data
->broadcaster
->addr
, &pinfo
->src
);
431 data
->broadcaster
->port
= port
;
433 /* Dissect any future pushes/pulls */
435 prepare_ldss_transfer_conv(data
);
438 /* Record that the frame was processed */
439 highest_num_seen
= pinfo
->fd
->num
;
442 return tvb_length(tvb
);
445 /* Transfers happen in response to broadcasts, they are always TCP and are
446 * used to send the file to the port mentioned in the broadcast. There are
447 * 2 types of transfers: Pushes, which are direct responses to searches,
448 * in which the peer that has the file connects to the peer that doesnt and
449 * sends it, then disconnects. The other type of transfer is a pull, where
450 * the peer that doesn't have the file connects to the peer that does and
451 * requests it be sent.
453 * Pulls have a file request which identifies the desired file,
454 * while pushes simply send the file. In practice this works because every
455 * file the implementation sends searches for is on a different TCP port
456 * on the searcher's machine. */
458 dissect_ldss_transfer (tvbuff_t
*tvb
, packet_info
*pinfo
, proto_tree
*tree
, void* data
)
460 conversation_t
*transfer_conv
;
461 ldss_transfer_info_t
*transfer_info
;
462 struct tcpinfo
*transfer_tcpinfo
= (struct tcpinfo
*)data
;
464 proto_tree
*ti
, *line_tree
= NULL
, *ldss_tree
= NULL
;
466 nstime_t broadcast_response_time
;
468 col_set_str(pinfo
->cinfo
, COL_PROTOCOL
, "LDSS");
470 /* Look for the transfer conversation; this was created during
471 * earlier broadcast dissection (see prepate_ldss_transfer_conv) */
472 transfer_conv
= find_conversation (pinfo
->fd
->num
, &pinfo
->src
, &pinfo
->dst
,
473 PT_TCP
, pinfo
->srcport
, pinfo
->destport
, 0);
474 transfer_info
= (ldss_transfer_info_t
*)conversation_get_proto_data(transfer_conv
, proto_ldss
);
476 /* For a pull, the first packet in the TCP connection is the file request.
477 * First packet is identified by relative seq/ack numbers of 1.
478 * File request only appears on a pull (triggered by an offer - see above
479 * about broadcasts) */
480 if (transfer_tcpinfo
->seq
== 1 &&
481 transfer_tcpinfo
->lastackseq
== 1 &&
482 transfer_info
->broadcast
->message_id
== MESSAGE_ID_WILLSEND
) {
483 /* LDSS pull transfers look a lot like HTTP.
485 * md5:01234567890123...
489 * (remote end sends the file identified by the digest) */
491 gboolean already_dissected
= TRUE
;
493 col_set_str(pinfo
->cinfo
, COL_INFO
, "LDSS File Transfer (Requesting file - pull)");
495 if (highest_num_seen
== 0 ||
496 highest_num_seen
< pinfo
->fd
->num
) {
498 already_dissected
= FALSE
;
499 transfer_info
->req
= wmem_new0(wmem_file_scope(), ldss_file_request_t
);
500 transfer_info
->req
->file
= wmem_new0(wmem_file_scope(), ldss_file_t
);
501 highest_num_seen
= pinfo
->fd
->num
;
505 ti
= proto_tree_add_item(tree
, proto_ldss
,
506 tvb
, 0, tvb_reported_length(tvb
), ENC_NA
);
507 ldss_tree
= proto_item_add_subtree(ti
, ett_ldss_transfer
);
510 /* Populate digest data into the file struct in the request */
511 transfer_info
->file
= transfer_info
->req
->file
;
513 /* Grab each line from the packet, there should be 4 but lets
514 * not walk off the end looking for more. */
515 while (offset
< tvb_reported_length(tvb
)) {
519 gboolean is_digest_line
;
520 guint digest_type_len
;
522 linelen
= tvb_find_line_end(tvb
, offset
,
523 tvb_ensure_length_remaining(tvb
, offset
), &next_offset
,
526 /* Include new-line in line */
527 line
= (guint8
*)tvb_memdup(NULL
, tvb
, offset
, linelen
+1); /* XXX - memory leak? */
530 ti
= proto_tree_add_text(ldss_tree
, tvb
, offset
, linelen
,
532 tvb_format_text(tvb
, offset
, next_offset
-offset
));
533 line_tree
= proto_item_add_subtree(ti
, ett_ldss_transfer_req
);
536 /* Reduce code duplication processing digest lines.
537 * There are too many locals to pass to a function - the signature
538 * looked pretty ugly when I tried! */
539 is_digest_line
= FALSE
;
541 if (strncmp(line
,"md5:",4)==0) {
542 is_digest_line
= TRUE
;
544 transfer_info
->file
->digest_type
= DIGEST_TYPE_MD5
;
546 else if (strncmp(line
, "sha1:", 5)==0) {
547 is_digest_line
= TRUE
;
549 transfer_info
->file
->digest_type
= DIGEST_TYPE_SHA1
;
551 else if (strncmp(line
, "sha256:", 7)==0) {
552 is_digest_line
= TRUE
;
554 transfer_info
->file
->digest_type
= DIGEST_TYPE_SHA256
;
556 else if (strncmp(line
, "unknown:", 8)==0) {
557 is_digest_line
= TRUE
;
559 transfer_info
->file
->digest_type
= DIGEST_TYPE_UNKNOWN
;
561 else if (strncmp(line
, "Size: ", 6)==0) {
564 transfer_info
->req
->size
= g_ascii_strtoull(line
+6, NULL
, 10);
566 ti
= proto_tree_add_uint64(line_tree
, hf_ldss_size
,
567 tvb
, offset
+6, linelen
-6, transfer_info
->req
->size
);
568 PROTO_ITEM_SET_GENERATED(ti
);
571 else if (strncmp(line
, "Start: ", 7)==0) {
572 /* Sample offset line:
574 transfer_info
->req
->offset
= g_ascii_strtoull(line
+7, NULL
, 10);
576 ti
= proto_tree_add_uint64(line_tree
, hf_ldss_offset
,
577 tvb
, offset
+7, linelen
-7, transfer_info
->req
->offset
);
578 PROTO_ITEM_SET_GENERATED(ti
);
581 else if (strncmp(line
, "Compression: ", 13)==0) {
582 /* Sample compression line:
583 * Compression: 0\n */
584 transfer_info
->req
->compression
= (gint8
)strtol(line
+13, NULL
, 10); /* XXX - bad cast */
586 ti
= proto_tree_add_uint(line_tree
, hf_ldss_compression
,
587 tvb
, offset
+13, linelen
-13, transfer_info
->req
->compression
);
588 PROTO_ITEM_SET_GENERATED(ti
);
593 ti
= proto_tree_add_text(line_tree
, tvb
, offset
, linelen
,
594 "Unrecognized line ignored");
595 PROTO_ITEM_SET_GENERATED(ti
);
599 if (is_digest_line
) {
600 /* Sample digest-type/digest line:
601 * md5:0123456789ABCDEF\n */
602 if (!already_dissected
) {
603 GByteArray
*digest_bytes
;
605 digest_bytes
= g_byte_array_new();
607 tvb_get_ptr(tvb
, offset
+digest_type_len
, linelen
-digest_type_len
),
608 digest_bytes
, FALSE
);
610 if(digest_bytes
->len
>= DIGEST_LEN
)
611 digest_bytes
->len
= (DIGEST_LEN
-1);
612 /* Ensure the digest is zero-padded */
613 transfer_info
->file
->digest
= (guint8
*)wmem_alloc0(wmem_file_scope(), DIGEST_LEN
);
614 memcpy(transfer_info
->file
->digest
, digest_bytes
->data
, digest_bytes
->len
);
616 g_byte_array_free(digest_bytes
, TRUE
);
619 proto_item
*tii
= NULL
;
621 tii
= proto_tree_add_uint(line_tree
, hf_ldss_digest_type
,
622 tvb
, offset
, digest_type_len
, transfer_info
->file
->digest_type
);
623 PROTO_ITEM_SET_GENERATED(tii
);
624 tii
= proto_tree_add_bytes(line_tree
, hf_ldss_digest
,
625 tvb
, offset
+digest_type_len
, linelen
-digest_type_len
,
626 transfer_info
->file
->digest
);
627 PROTO_ITEM_SET_GENERATED(tii
);
631 offset
= next_offset
;
634 /* Link forwards to the response for this pull. */
635 if (tree
&& transfer_info
->resp_num
!= 0) {
636 ti
= proto_tree_add_uint(ldss_tree
, hf_ldss_response_in
,
637 tvb
, 0, 0, transfer_info
->resp_num
);
638 PROTO_ITEM_SET_GENERATED(ti
);
641 transfer_info
->req
->num
= pinfo
->fd
->num
;
642 transfer_info
->req
->ts
= pinfo
->fd
->abs_ts
;
644 /* Remaining packets are the file response */
650 /* size, digest, compression come from the file request for a pull but
651 * they come from the broadcast for a push. Pushes don't bother
652 * with a file request - they just send the data. We have to get file
653 * info from the offer broadcast which triggered this transfer.
654 * If we cannot find the file request, default to the broadcast. */
655 if (transfer_info
->broadcast
->message_id
== MESSAGE_ID_WILLSEND
&&
656 transfer_info
->req
!= NULL
) {
657 transfer_info
->file
= transfer_info
->req
->file
;
658 size
= transfer_info
->req
->size
;
659 offset
= transfer_info
->req
->offset
;
660 compression
= transfer_info
->req
->compression
;
663 transfer_info
->file
= transfer_info
->broadcast
->file
;
664 size
= transfer_info
->broadcast
->size
;
665 offset
= transfer_info
->broadcast
->offset
;
666 compression
= transfer_info
->broadcast
->compression
;
669 /* Remaining data in this TCP connection is all file data.
670 * Always desegment if the size is 0 (ie. unknown)
672 if (pinfo
->can_desegment
) {
673 if (size
== 0 || tvb_length(tvb
) < size
) {
674 pinfo
->desegment_offset
= 0;
675 pinfo
->desegment_len
= DESEGMENT_UNTIL_FIN
;
680 /* OK. Now we have the whole file that was transferred. */
681 transfer_info
->resp_num
= pinfo
->fd
->num
;
682 transfer_info
->resp_ts
= pinfo
->fd
->abs_ts
;
684 col_add_fstr(pinfo
->cinfo
, COL_INFO
, "LDSS File Transfer (Sending file - %s)",
685 transfer_info
->broadcast
->message_id
== MESSAGE_ID_WILLSEND
690 ti
= proto_tree_add_item(tree
, proto_ldss
,
691 tvb
, 0, tvb_reported_length(tvb
), ENC_NA
);
692 ldss_tree
= proto_item_add_subtree(ti
, ett_ldss_transfer
);
693 proto_tree_add_bytes_format(ldss_tree
, hf_ldss_file_data
,
694 tvb
, 0, tvb_length(tvb
), NULL
,
695 compression
== COMPRESSION_GZIP
696 ? "Gzip compressed data: %d bytes"
697 : "File data: %d bytes",
700 /* Be nice and uncompress the file data. */
701 if (compression
== COMPRESSION_GZIP
) {
702 tvbuff_t
*uncomp_tvb
;
703 uncomp_tvb
= tvb_child_uncompress(tvb
, tvb
, 0, tvb_length(tvb
));
704 if (uncomp_tvb
!= NULL
) {
705 /* XXX: Maybe not a good idea to add a data_source for
706 what may very well be a large buffer since then
707 the full uncompressed buffer will be shown in a tab
708 in the hex bytes pane ?
709 However, if we don't, bytes in an unrelated tab will
712 add_new_data_source(pinfo
, uncomp_tvb
, "Uncompressed Data");
713 proto_tree_add_bytes_format_value(ldss_tree
, hf_ldss_file_data
,
714 uncomp_tvb
, 0, tvb_length(uncomp_tvb
),
715 NULL
, "Uncompressed data: %d bytes",
716 tvb_length(uncomp_tvb
));
720 ti
= proto_tree_add_uint(ldss_tree
, hf_ldss_digest_type
,
721 tvb
, 0, 0, transfer_info
->file
->digest_type
);
722 PROTO_ITEM_SET_GENERATED(ti
);
723 if (transfer_info
->file
->digest
!= NULL
) {
724 /* This is ugly. You can't add bytes of nonzero length and have
725 * filtering work correctly unless you give a valid location in
726 * the packet. This hack pretends the first 32 bytes of the packet
727 * are the digest, which they aren't: they're actually the first 32
728 * bytes of the file that was sent. */
729 ti
= proto_tree_add_bytes(ldss_tree
, hf_ldss_digest
,
730 tvb
, 0, DIGEST_LEN
, transfer_info
->file
->digest
);
732 PROTO_ITEM_SET_GENERATED(ti
);
733 ti
= proto_tree_add_uint64(ldss_tree
, hf_ldss_size
,
735 PROTO_ITEM_SET_GENERATED(ti
);
736 ti
= proto_tree_add_uint64(ldss_tree
, hf_ldss_offset
,
738 PROTO_ITEM_SET_GENERATED(ti
);
739 ti
= proto_tree_add_uint(ldss_tree
, hf_ldss_compression
,
740 tvb
, 0, 0, compression
);
741 PROTO_ITEM_SET_GENERATED(ti
);
742 /* Link to the request for a pull. */
743 if (transfer_info
->broadcast
->message_id
== MESSAGE_ID_WILLSEND
&&
744 transfer_info
->req
!= NULL
&&
745 transfer_info
->req
->num
!= 0) {
746 ti
= proto_tree_add_uint(ldss_tree
, hf_ldss_response_to
,
747 tvb
, 0, 0, transfer_info
->req
->num
);
748 PROTO_ITEM_SET_GENERATED(ti
);
753 /* Print the pull response time */
754 if (transfer_info
->broadcast
->message_id
== MESSAGE_ID_WILLSEND
&&
755 transfer_info
->req
!= NULL
&&
756 transfer_info
->resp_num
!= 0) {
757 nstime_t pull_response_time
;
758 nstime_delta(&pull_response_time
, &transfer_info
->resp_ts
,
759 &transfer_info
->req
->ts
);
760 ti
= proto_tree_add_time(ldss_tree
, hf_ldss_transfer_response_time
,
761 tvb
, 0, 0, &pull_response_time
);
762 PROTO_ITEM_SET_GENERATED(ti
);
765 /* Link the transfer back to the initiating broadcast. Response time is
766 * calculated as the time from broadcast to completed transfer. */
767 ti
= proto_tree_add_uint(ldss_tree
, hf_ldss_initiated_by
,
768 tvb
, 0, 0, transfer_info
->broadcast
->num
);
769 PROTO_ITEM_SET_GENERATED(ti
);
771 if (transfer_info
->resp_num
!= 0) {
772 nstime_delta(&broadcast_response_time
, &transfer_info
->resp_ts
,
773 &transfer_info
->broadcast
->ts
);
774 ti
= proto_tree_add_time(ldss_tree
, hf_ldss_transfer_completed_in
,
775 tvb
, 0, 0, &broadcast_response_time
);
776 PROTO_ITEM_SET_GENERATED(ti
);
779 /* This conv got its addr2/port2 set by the TCP dissector because a TCP
780 * connection was established. Make a new one to handle future connections
781 * to the addr/port mentioned in the broadcast, because that socket is
783 if (transfer_tcpinfo
->seq
== 1 &&
784 transfer_tcpinfo
->lastackseq
== 1) {
786 prepare_ldss_transfer_conv(transfer_info
->broadcast
);
789 return tvb_length(tvb
);
793 is_broadcast(address
* addr
)
795 static address broadcast_addr
;
796 static const guint8 broadcast_addr_bytes
[6] = {
797 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF
800 SET_ADDRESS(&broadcast_addr
, AT_ETHER
, 6, broadcast_addr_bytes
);
801 return ADDRESSES_EQUAL(addr
, &broadcast_addr
);
805 dissect_ldss (tvbuff_t
*tvb
, packet_info
*pinfo
, proto_tree
*tree
, void *data _U_
)
807 if (is_broadcast(&pinfo
->dl_dst
)) {
809 col_set_str(pinfo
->cinfo
, COL_PROTOCOL
, "LDSS");
810 return dissect_ldss_broadcast(tvb
, pinfo
, tree
);
813 /* Definitely not LDSS */
817 /* Initialize the highest num seen each time a
818 * new file is loaded or re-loaded in wireshark */
820 ldss_init_protocol(void)
822 /* We haven't dissected anything yet. */
823 highest_num_seen
= 0;
827 proto_register_ldss (void) {
828 static hf_register_info hf
[] = {
829 { &hf_ldss_message_id
,
832 FT_UINT16
, BASE_DEC
, ldss_message_id_value
, 0x0,
836 { &hf_ldss_message_detail
,
837 { "Inferred meaning",
838 "ldss.inferred_meaning",
839 FT_UINT16
, BASE_DEC
, ldss_inferred_value
, 0x0,
840 "Inferred meaning of the packet", HFILL
843 { &hf_ldss_digest_type
,
846 FT_UINT8
, BASE_DEC
, ldss_digest_type_value
, 0x0,
850 { &hf_ldss_compression
,
851 { "Compressed Format",
853 FT_UINT8
, BASE_DEC
, ldss_compression_value
, 0x0,
860 FT_UINT32
, BASE_HEX
, NULL
, 0x0,
861 "Random value used for duplicate rejection", HFILL
867 FT_BYTES
, BASE_NONE
, NULL
, 0x0,
868 "Digest of file padded with 0x00", HFILL
874 FT_UINT64
, BASE_DEC
, NULL
, 0x0,
875 "Size of complete file", HFILL
881 FT_UINT64
, BASE_DEC
, NULL
, 0x0,
882 "Size of currently available portion of file", HFILL
885 { &hf_ldss_target_time
,
886 { "Target time (relative)",
888 FT_UINT32
, BASE_DEC
, NULL
, 0x0,
889 "Time until file will be needed/available", HFILL
892 { &hf_ldss_reserved_1
,
895 FT_UINT32
, BASE_HEX
, NULL
, 0x0,
896 "Unused field - should be 0x00000000", HFILL
902 FT_UINT16
, BASE_DEC
, NULL
, 0x0,
903 "TCP port for push (Need file) or pull (Will send)", HFILL
909 FT_UINT16
, BASE_DEC
, NULL
, 0x0,
910 "Estimated current download rate", HFILL
916 FT_UINT16
, BASE_DEC
, NULL
, 0x0,
920 { &hf_ldss_property_count
,
922 "ldss.property_count",
923 FT_UINT16
, BASE_DEC
, NULL
, 0x0,
927 { &hf_ldss_properties
,
930 FT_BYTES
, BASE_NONE
, NULL
, 0x0,
934 { &hf_ldss_file_data
,
937 FT_BYTES
, BASE_NONE
, NULL
, 0x0,
941 { &hf_ldss_response_in
,
944 FT_FRAMENUM
, BASE_NONE
, NULL
, 0x0,
945 "The response to this file pull request is in this frame", HFILL
}
947 { &hf_ldss_response_to
,
950 FT_FRAMENUM
, BASE_NONE
, NULL
, 0x0,
951 "This is a response to the file pull request in this frame", HFILL
}
953 { &hf_ldss_initiated_by
,
956 FT_FRAMENUM
, BASE_NONE
, NULL
, 0x0,
957 "The broadcast that initiated this file transfer", HFILL
}
959 { &hf_ldss_transfer_response_time
,
960 { "Transfer response time",
961 "ldss.transfer_response_time",
962 FT_RELATIVE_TIME
, BASE_NONE
, NULL
, 0x0,
963 "The time between the request and the response for a pull transfer", HFILL
}
965 { &hf_ldss_transfer_completed_in
,
966 { "Transfer completed in",
967 "ldss.transfer_completed_in",
968 FT_RELATIVE_TIME
, BASE_NONE
, NULL
, 0x0,
969 "The time between requesting the file and completion of the file transfer", HFILL
}
973 static gint
*ett
[] = { &ett_ldss_broadcast
, &ett_ldss_transfer
, &ett_ldss_transfer_req
};
975 module_t
*ldss_module
;
977 proto_ldss
= proto_register_protocol("Local Download Sharing Service", "LDSS", "ldss");
978 proto_register_field_array(proto_ldss
, hf
, array_length(hf
));
979 proto_register_subtree_array(ett
, array_length(ett
));
981 ldss_module
= prefs_register_protocol( proto_ldss
, proto_reg_handoff_ldss
);
982 prefs_register_uint_preference( ldss_module
, "udp_port",
984 "The UDP port on which "
985 "Local Download Sharing Service "
986 "broadcasts will be sent",
987 10, &global_udp_port_ldss
);
989 register_init_routine(&ldss_init_protocol
);
993 /* The registration hand-off routine */
995 proto_reg_handoff_ldss (void)
997 static guint saved_udp_port_ldss
;
998 static gboolean ldss_initialized
= FALSE
;
1000 if (!ldss_initialized
) {
1001 ldss_udp_handle
= new_create_dissector_handle(dissect_ldss
, proto_ldss
);
1002 ldss_tcp_handle
= new_create_dissector_handle(dissect_ldss_transfer
, proto_ldss
);
1003 ldss_initialized
= TRUE
;
1006 dissector_delete_uint("udp.port", saved_udp_port_ldss
, ldss_udp_handle
);
1008 dissector_add_uint("udp.port", global_udp_port_ldss
, ldss_udp_handle
);
1009 saved_udp_port_ldss
= global_udp_port_ldss
;