HACK: pinfo->private_data points to smb_info again
[wireshark-wip.git] / epan / dissectors / packet-ldss.c
blobab412f6f90d323d18bac094ecae9e159f700b0b1
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 * $Id$
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.
39 #include "config.h"
41 #include <stdlib.h>
42 #include <string.h>
43 #include <math.h>
45 #include <glib.h>
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 */
57 #define DIGEST_LEN 32
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" },
66 { 0, NULL }
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, "" },
85 { 0, NULL }
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, "" },
96 { 0, NULL }
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" },
111 { 0, NULL }
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" },
122 { 0, NULL }
125 /* Info about a broadcaster */
126 typedef struct _ldss_broadcaster_t {
127 address addr;
128 guint16 port;
129 } ldss_broadcaster_t;
131 /* Info about a file */
132 typedef struct _ldss_file_t {
133 guint8 *digest;
134 guint8 digest_type;
135 } ldss_file_t;
137 /* Info about a broadcast packet */
138 typedef struct _ldss_broadcast_t {
139 guint32 num;
140 nstime_t ts;
141 guint16 message_id;
142 guint16 message_detail;
143 guint16 port;
144 guint64 size;
145 guint64 offset;
146 guint8 compression;
147 ldss_file_t *file;
148 ldss_broadcaster_t *broadcaster;
149 } ldss_broadcast_t;
151 /* Info about a file as seen in a file request */
152 typedef struct _ldss_file_req_t {
153 guint32 num;
154 nstime_t ts;
155 guint64 size;
156 guint64 offset;
157 guint8 compression;
158 ldss_file_t *file;
159 } ldss_file_request_t;
161 /* Info attached to a file transfer conversation */
162 typedef struct _ldss_transfer_info_t {
163 guint32 resp_num;
164 nstime_t resp_ts;
165 /* Refers either to the file in the request (for pull)
166 * or the file in the broadcast (for push) */
167 ldss_file_t *file;
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. */
221 static void
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
268 * a file. */
269 static int
270 dissect_ldss_broadcast(tvbuff_t *tvb, packet_info *pinfo, proto_tree *tree)
272 guint16 messageID;
273 guint8 digest_type;
274 guint8 compression;
275 guint32 cookie;
276 guint8 *digest;
277 guint64 size;
278 guint64 offset;
279 guint32 targetTime;
280 guint16 port;
281 guint16 rate;
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) {
302 if (cookie == 0) {
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;
311 else if (size > 0) {
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;
317 else {
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)",
330 packet_type,
331 packet_detail);
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. */
335 if (tree) {
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,
350 tvb, 4, 4, FALSE,
351 "0x%x%s",
352 cookie,
353 (cookie == 0)
354 ? " - shutdown (promises from this peer are no longer valid)"
355 : "");
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,
363 tvb, 56, 4, FALSE,
364 "%d:%02d:%02d",
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,
371 tvb, 64, 2, FALSE,
372 "%d%s",
373 port,
374 (messageID == MESSAGE_ID_WILLSEND &&
375 size > 0 &&
376 size == offset)
377 ? " - file can be pulled at this TCP port"
378 : (messageID == MESSAGE_ID_NEEDFILE
379 ? " - file can be pushed to this TCP port"
380 : ""));
381 proto_tree_add_uint_format_value(ldss_tree, hf_ldss_rate,
382 tvb, 66, 2, FALSE,
383 "%ld",
384 (rate > 0)
385 ? (long)floor(exp(rate * G_LN2 / 2048))
386 : 0);
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
403 * is in response to.
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;
420 data->port = port;
421 data->size = size;
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 */
434 if (port > 0) {
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. */
457 static int
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.
484 * Sample request:
485 * md5:01234567890123...
486 * Size: 2550
487 * Start: 0
488 * Compression: 0
489 * (remote end sends the file identified by the digest) */
490 guint offset = 0;
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;
504 if (tree) {
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)) {
516 gint next_offset;
517 const guint8 *line;
518 int linelen;
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,
524 FALSE);
526 /* Include new-line in line */
527 line = (guint8 *)tvb_memdup(NULL, tvb, offset, linelen+1); /* XXX - memory leak? */
529 if (tree) {
530 ti = proto_tree_add_text(ldss_tree, tvb, offset, linelen,
531 "%s",
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;
543 digest_type_len = 4;
544 transfer_info->file->digest_type = DIGEST_TYPE_MD5;
546 else if (strncmp(line, "sha1:", 5)==0) {
547 is_digest_line = TRUE;
548 digest_type_len = 5;
549 transfer_info->file->digest_type = DIGEST_TYPE_SHA1;
551 else if (strncmp(line, "sha256:", 7)==0) {
552 is_digest_line = TRUE;
553 digest_type_len = 7;
554 transfer_info->file->digest_type = DIGEST_TYPE_SHA256;
556 else if (strncmp(line, "unknown:", 8)==0) {
557 is_digest_line = TRUE;
558 digest_type_len = 8;
559 transfer_info->file->digest_type = DIGEST_TYPE_UNKNOWN;
561 else if (strncmp(line, "Size: ", 6)==0) {
562 /* Sample size line:
563 * Size: 2550\n */
564 transfer_info->req->size = g_ascii_strtoull(line+6, NULL, 10);
565 if (tree) {
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:
573 * Start: 0\n */
574 transfer_info->req->offset = g_ascii_strtoull(line+7, NULL, 10);
575 if (tree) {
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 */
585 if (tree) {
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);
591 else {
592 if (tree) {
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();
606 hex_str_to_bytes(
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);
618 if (tree) {
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 */
645 else {
646 guint64 size;
647 guint64 offset;
648 guint8 compression;
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;
662 else {
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;
676 return 0;
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
686 ? "pull"
687 : "push");
689 if (tree) {
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",
698 tvb_length(tvb));
699 #ifdef HAVE_LIBZ
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
710 be highlighted.
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));
719 #endif
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,
734 tvb, 0, 0, size);
735 PROTO_ITEM_SET_GENERATED(ti);
736 ti = proto_tree_add_uint64(ldss_tree, hf_ldss_offset,
737 tvb, 0, 0, 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
782 * still open. */
783 if (transfer_tcpinfo->seq == 1 &&
784 transfer_tcpinfo->lastackseq == 1) {
786 prepare_ldss_transfer_conv(transfer_info->broadcast);
789 return tvb_length(tvb);
792 static gboolean
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);
804 static int
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 */
814 return 0;
817 /* Initialize the highest num seen each time a
818 * new file is loaded or re-loaded in wireshark */
819 static void
820 ldss_init_protocol(void)
822 /* We haven't dissected anything yet. */
823 highest_num_seen = 0;
826 void
827 proto_register_ldss (void) {
828 static hf_register_info hf[] = {
829 { &hf_ldss_message_id,
830 { "LDSS Message ID",
831 "ldss.message_id",
832 FT_UINT16, BASE_DEC, ldss_message_id_value, 0x0,
833 NULL, HFILL
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,
844 { "Digest Type",
845 "ldss.digest_type",
846 FT_UINT8, BASE_DEC, ldss_digest_type_value, 0x0,
847 NULL, HFILL
850 { &hf_ldss_compression,
851 { "Compressed Format",
852 "ldss.compression",
853 FT_UINT8, BASE_DEC, ldss_compression_value, 0x0,
854 NULL, HFILL
857 { &hf_ldss_cookie,
858 { "Cookie",
859 "ldss.cookie",
860 FT_UINT32, BASE_HEX, NULL, 0x0,
861 "Random value used for duplicate rejection", HFILL
864 { &hf_ldss_digest,
865 { "Digest",
866 "ldss.digest",
867 FT_BYTES, BASE_NONE, NULL, 0x0,
868 "Digest of file padded with 0x00", HFILL
871 { &hf_ldss_size,
872 { "Size",
873 "ldss.size",
874 FT_UINT64, BASE_DEC, NULL, 0x0,
875 "Size of complete file", HFILL
878 { &hf_ldss_offset,
879 { "Offset",
880 "ldss.offset",
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)",
887 "ldss.target_time",
888 FT_UINT32, BASE_DEC, NULL, 0x0,
889 "Time until file will be needed/available", HFILL
892 { &hf_ldss_reserved_1,
893 { "Reserved",
894 "ldss.reserved_1",
895 FT_UINT32, BASE_HEX, NULL, 0x0,
896 "Unused field - should be 0x00000000", HFILL
899 { &hf_ldss_port,
900 { "Port",
901 "ldss.port",
902 FT_UINT16, BASE_DEC, NULL, 0x0,
903 "TCP port for push (Need file) or pull (Will send)", HFILL
906 { &hf_ldss_rate,
907 { "Rate (B/s)",
908 "ldss.rate",
909 FT_UINT16, BASE_DEC, NULL, 0x0,
910 "Estimated current download rate", HFILL
913 { &hf_ldss_priority,
914 { "Priority",
915 "ldss.priority",
916 FT_UINT16, BASE_DEC, NULL, 0x0,
917 NULL, HFILL
920 { &hf_ldss_property_count,
921 { "Property Count",
922 "ldss.property_count",
923 FT_UINT16, BASE_DEC, NULL, 0x0,
924 NULL, HFILL
927 { &hf_ldss_properties,
928 { "Properties",
929 "ldss.properties",
930 FT_BYTES, BASE_NONE, NULL, 0x0,
931 NULL, HFILL
934 { &hf_ldss_file_data,
935 { "File data",
936 "ldss.file_data",
937 FT_BYTES, BASE_NONE, NULL, 0x0,
938 NULL, HFILL
941 { &hf_ldss_response_in,
942 { "Response In",
943 "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,
948 { "Request In",
949 "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,
954 { "Initiated by",
955 "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",
983 "LDSS 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 */
994 void
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;
1005 else {
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;