From Kovarththanan Rajaratnam via bug 3548:
[obnox/wireshark/wip.git] / epan / dissectors / packet-bittorrent.c
1 /* packet-bittorrent.c
2  * Routines for bittorrent packet dissection
3  * Copyright (C) 2004 Jelmer Vernooij <jelmer@samba.org>
4  *
5  * $Id$
6  *
7  * Wireshark - Network traffic analyzer
8  * By Gerald Combs <gerald@wireshark.org>
9  * Copyright 1998 Gerald Combs
10  *
11  * Copied from packet-pop.c
12  *
13  * This program is free software; you can redistribute it and/or
14  * modify it under the terms of the GNU General Public License
15  * as published by the Free Software Foundation; either version 2
16  * of the License, or (at your option) any later version.
17  *
18  * This program is distributed in the hope that it will be useful,
19  * but WITHOUT ANY WARRANTY; without even the implied warranty of
20  * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
21  * GNU General Public License for more details.
22  *
23  * You should have received a copy of the GNU General Public License
24  * along with this program; if not, write to the Free Software
25  * Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA  02111-1307, USA.
26  */
27
28 #ifdef HAVE_CONFIG_H
29 # include "config.h"
30 #endif
31
32 #include <stdio.h>
33
34 #include <string.h>
35 #include <glib.h>
36 #include <epan/prefs.h>
37 #include <epan/conversation.h>
38 #include <epan/packet.h>
39 #include <epan/strutil.h>
40
41 #include "packet-tcp.h"
42
43 /*
44  * See
45  *
46  * http://bittorrent.com/protocol.html
47  * http://wiki.theory.org/BitTorrentSpecification
48  * http://bitconjurer.org/BitTorrent/protocol.html
49  */
50
51 #define BITTORRENT_MESSAGE_CHOKE          0
52 #define BITTORRENT_MESSAGE_UNCHOKE        1
53 #define BITTORRENT_MESSAGE_INTERESTED     2
54 #define BITTORRENT_MESSAGE_NOT_INTERESTED 3
55 #define BITTORRENT_MESSAGE_HAVE           4
56 #define BITTORRENT_MESSAGE_BITFIELD       5
57 #define BITTORRENT_MESSAGE_REQUEST        6
58 #define BITTORRENT_MESSAGE_PIECE          7
59 #define BITTORRENT_MESSAGE_CANCEL         8
60
61 #define BITTORRENT_HEADER_LENGTH          4
62
63 /*
64  * Azureus messages are specified by name so these are made up numbers
65  * for internal identification only.
66  *
67  * Standard BT message types are a single byte, so these won't clash
68  */
69 #define AZUREUS_MESSAGE_HANDSHAKE         256
70 #define AZUREUS_MESSAGE_KEEP_ALIVE        257
71 #define AZUREUS_MESSAGE_BT_HANDSHAKE      258
72 #define AZUREUS_MESSAGE_PEER_EXCHANGE     259
73 #define AZUREUS_MESSAGE_JPC_HELLO         260
74 #define AZUREUS_MESSAGE_JPC_REPLY         261
75
76
77 static const value_string bittorrent_messages[] = {
78    { BITTORRENT_MESSAGE_CHOKE, "Choke" },
79    { BITTORRENT_MESSAGE_UNCHOKE, "Unchoke" },
80    { BITTORRENT_MESSAGE_INTERESTED, "Interested" },
81    { BITTORRENT_MESSAGE_NOT_INTERESTED, "Not Interested" },
82    { BITTORRENT_MESSAGE_HAVE, "Have" },
83    { BITTORRENT_MESSAGE_BITFIELD, "Bitfield" },
84    { BITTORRENT_MESSAGE_REQUEST, "Request" },
85    { BITTORRENT_MESSAGE_PIECE, "Piece" },
86    { BITTORRENT_MESSAGE_CANCEL, "Cancel" },
87    { AZUREUS_MESSAGE_KEEP_ALIVE, "Keepalive" },
88    { AZUREUS_MESSAGE_HANDSHAKE, "Azureus Handshake" },
89    { AZUREUS_MESSAGE_BT_HANDSHAKE, "Azureus BitTorrent Handshake" },
90    { AZUREUS_MESSAGE_PEER_EXCHANGE, "Azureus Peer Exchange" },
91    { AZUREUS_MESSAGE_JPC_HELLO, "Azureus PeerCache Hello" },
92    { AZUREUS_MESSAGE_JPC_REPLY, "Azureus PeerCache Reply" },
93    { 0, NULL }
94 };
95
96 static const value_string azureus_priorities[] = {
97   { 0, "Low" },
98   { 1, "Normal" },
99   { 2, "High" },
100   { 0, NULL }
101 };
102
103
104 struct amp_message {
105   const char *name;
106   guint32 value;
107 };
108
109 static const struct amp_message amp_messages[] = {
110   { "BT_KEEP_ALIVE", AZUREUS_MESSAGE_KEEP_ALIVE },
111   { "BT_CHOKE", BITTORRENT_MESSAGE_CHOKE },
112   { "BT_UNCHOKE", BITTORRENT_MESSAGE_UNCHOKE },
113   { "BT_INTERESTED", BITTORRENT_MESSAGE_INTERESTED },
114   { "BT_UNINTERESTED", BITTORRENT_MESSAGE_NOT_INTERESTED },
115   { "BT_HAVE", BITTORRENT_MESSAGE_HAVE },
116   { "BT_BITFIELD", BITTORRENT_MESSAGE_BITFIELD },
117   { "BT_REQUEST", BITTORRENT_MESSAGE_REQUEST },
118   { "BT_PIECE", BITTORRENT_MESSAGE_PIECE },
119   { "BT_CANCEL", BITTORRENT_MESSAGE_CANCEL },
120   { "AZ_HANDSHAKE", AZUREUS_MESSAGE_HANDSHAKE },
121   { "BT_HANDSHAKE", AZUREUS_MESSAGE_BT_HANDSHAKE },
122   { "AZ_PEER_EXCHANGE", AZUREUS_MESSAGE_PEER_EXCHANGE },
123   { "JPC_HELLO", AZUREUS_MESSAGE_JPC_HELLO },
124   { "JPC_REPLY", AZUREUS_MESSAGE_JPC_REPLY },
125   { NULL, 0 }
126 };
127
128 static dissector_handle_t dissector_handle;
129 static int proto_bittorrent = -1;
130
131 static gint hf_bittorrent_field_length  = -1;
132 static gint hf_bittorrent_prot_name_len = -1;
133 static gint hf_bittorrent_prot_name     = -1;
134 static gint hf_bittorrent_reserved      = -1;
135 static gint hf_bittorrent_sha1_hash     = -1;
136 static gint hf_bittorrent_peer_id       = -1;
137 static gint hf_bittorrent_msg           = -1;
138 static gint hf_bittorrent_msg_len       = -1;
139 static gint hf_bittorrent_msg_type      = -1;
140 static gint hf_azureus_msg              = -1;
141 static gint hf_azureus_msg_type_len     = -1;
142 static gint hf_azureus_msg_type         = -1;
143 static gint hf_azureus_msg_prio         = -1;
144 static gint hf_bittorrent_bitfield_data = -1;
145 static gint hf_bittorrent_piece_index   = -1;
146 static gint hf_bittorrent_piece_begin   = -1;
147 static gint hf_bittorrent_piece_length  = -1;
148 static gint hf_bittorrent_piece_data    = -1;
149 static gint hf_bittorrent_bstr_length   = -1;
150 static gint hf_bittorrent_bstr          = -1;
151 static gint hf_bittorrent_bint          = -1;
152 static gint hf_bittorrent_bdict         = -1;
153 static gint hf_bittorrent_bdict_entry   = -1;
154 static gint hf_bittorrent_blist         = -1;
155 static gint hf_azureus_jpc_addrlen      = -1;
156 static gint hf_azureus_jpc_addr         = -1;
157 static gint hf_azureus_jpc_port         = -1;
158 static gint hf_azureus_jpc_session      = -1;
159
160 static gint ett_bittorrent = -1;
161 static gint ett_bittorrent_msg = -1;
162 static gint ett_peer_id = -1;
163 static gint ett_bittorrent_bdict = -1;
164 static gint ett_bittorrent_bdict_entry = -1;
165 static gint ett_bittorrent_blist = -1;
166
167 static gboolean bittorrent_desegment = TRUE;
168 static gboolean decode_client_information = FALSE;
169
170 struct client_information {
171    char id[4];
172    const char *name;
173 };
174
175 static struct client_information peer_id[] = {
176    {"-AZ", "Azureus"},
177    {"-BB", "BitBuddy"},
178    {"-CT", "CTorrent"},
179    {"-MT", "MoonlightTorrent"},
180    {"-LT", "libtorrent"},
181    {"-BX", "Bittorrent X"},
182    {"-TS", "Torrentstorm"},
183    {"-TN", "TorrentDotNET"},
184    {"-SS", "SwarmScope"},
185    {"-XT", "XanTorrent"},
186    {"-BS", "BTSlave"},
187    {"-ZT", "ZipTorrent"},
188    {"S",   "Shadow's client"},
189    {"U",   "UPnP NAT Bit Torrent"},
190    {"T",   "BitTornado"},
191    {"A",   "ABC"},
192    {"",    NULL}
193 };
194
195 static guint get_bittorrent_pdu_length(packet_info *pinfo _U_, tvbuff_t *tvb, int offset)
196 {
197    guint8 type;
198    guint32 length;
199
200    if (tvb_get_guint8(tvb, offset) == 19 &&
201        tvb_memeql(tvb, offset + 1, "BitTorrent protocol", 19) == 0) {
202       /* Return the length of a Handshake message */
203       return 1 + /* pstrlen */
204          19 +    /* pstr */
205          8 +     /* reserved */
206          20 +    /* SHA1 hash of the info key */
207          20;     /* peer id */
208    } else {
209       /* Try to validate the length of the message indicated by the header. */
210       length = tvb_get_ntohl(tvb, offset);
211       if(length == 0) {
212         /* keep-alive - no message ID */
213         return BITTORRENT_HEADER_LENGTH;
214       }
215       /* Do some sanity checking of the message, if we have the ID byte */
216       if(tvb_offset_exists(tvb, offset + BITTORRENT_HEADER_LENGTH)) {
217          type = tvb_get_guint8(tvb, offset + BITTORRENT_HEADER_LENGTH);
218          if(type <= BITTORRENT_MESSAGE_CANCEL && length<0x1000000) {
219             /* This seems to be a valid BitTorrent header with a known
220                type identifier */
221             return BITTORRENT_HEADER_LENGTH + length;
222          } else {
223             /* The type is not known, so this message cannot be decoded
224                properly by this dissector.  We assume it's continuation
225                data from the middle of a message, and just return the
226                remaining length in the tvbuff so the rest of the tvbuff
227                is displayed as continuation data. */
228             return tvb_length_remaining(tvb, offset);
229          }
230       } else {
231          /* We don't have the type field, so we can't determine
232             whether this is a valid message.  For now, we assume
233             it's continuation data from the middle of a message,
234             and just return the remaining length in the tvbuff so
235             the rest of the tvbuff is displayed as continuation
236             data. */
237          return tvb_length_remaining(tvb, offset);
238       }
239    }
240 }
241
242 static int dissect_bencoding_str(tvbuff_t *tvb, packet_info *pinfo _U_,
243                                  int offset, int length, proto_tree *tree, proto_item *ti, int treeadd)
244 {
245   guint8 ch;
246   int stringlen = 0, nextstringlen;
247   int used;
248   int izero = 0;
249
250   if (length<2) {
251     if (tree) {
252       proto_tree_add_text(tree, tvb, offset, length, "Decode Aborted: Invalid String");
253     }
254     return -1;
255   }
256
257   used = 0;
258
259   while (length>=1) {
260     ch = tvb_get_guint8(tvb, offset+used);
261     length--;
262     used++;
263
264     if (ch==':' && used>1) {
265       if (stringlen>length || stringlen<0) {
266         if (tree) {
267           proto_tree_add_text(tree, tvb, offset, length, "Decode Aborted: Invalid String Length");
268         }
269         return -1;
270       }
271       if (tree) {
272         proto_tree_add_uint(tree, hf_bittorrent_bstr_length, tvb, offset, used, stringlen);
273         proto_tree_add_item(tree, hf_bittorrent_bstr, tvb, offset+used, stringlen, FALSE);
274
275         if (treeadd==1) {
276           proto_item_append_text(ti, " Key: %s", format_text(ep_tvb_memdup(tvb, offset+used, stringlen), stringlen));
277         }
278         if (treeadd==2) {
279           proto_item_append_text(ti, "  Value: %s", format_text(ep_tvb_memdup(tvb, offset+used, stringlen), stringlen));
280         }
281       }
282       return used+stringlen;
283     }
284
285     if (!izero && ch>='0' && ch<='9') {
286       if (ch=='0' && used==1) {
287         izero = 1;
288       }
289
290       nextstringlen = (stringlen * 10) + (ch - '0');
291       if (nextstringlen>=stringlen) {
292         stringlen = nextstringlen;
293         continue;
294       }
295     }
296
297     if (tree) {
298       proto_tree_add_text(tree, tvb, offset, length, "Decode Aborted: Invalid String");
299     }
300     return -1;
301   }
302
303   if (tree) {
304     proto_tree_add_text(tree, tvb, offset, length, "Truncated Data");
305   }
306   return -1;
307 }
308
309 static int dissect_bencoding_int(tvbuff_t *tvb, packet_info *pinfo _U_,
310                                  int offset, int length, proto_tree *tree, proto_item *ti, int treeadd)
311 {
312   gint32 ival=0;
313   int neg = 0;
314   int izero = 0;
315   int used;
316   guint8 ch;
317
318   if (length<3) {
319     if (tree) {
320       proto_tree_add_text(tree, tvb, offset, length, "Decode Aborted: Invalid Integer");
321     }
322     return -1;
323   }
324
325   length--;
326   used = 1;
327
328   while (length>=1) {
329     ch = tvb_get_guint8(tvb, offset+used);
330     length--;
331     used++;
332
333     switch (ch) {
334     case 'e':
335       if (tree) {
336         if (neg) ival = -ival;
337         proto_tree_add_int(tree, hf_bittorrent_bint, tvb, offset, used, ival);
338         if (treeadd==2) {
339           proto_item_append_text(ti, "  Value: %d", ival);
340         }
341       }
342       return used;
343
344     case '-':
345       if (used==2) {
346         neg = 1;
347         break;
348       }
349       /* Fall through */
350
351     default:
352       if (!(ch=='0' && used==3 && neg)) { /* -0 is invalid */
353         if (ch=='0' && used==2) { /* as is 0[0-9]+ */
354           izero = 1;
355           break;
356         }
357         if (!izero && ch>='0' && ch<='9') {
358           ival = (ival * 10) + (ch - '0');
359           break;
360         }
361       }
362
363       if (tree) {
364         proto_tree_add_text(tree, tvb, offset, length, "Decode Aborted: Invalid Integer");
365       }
366       return -1;
367     }
368   }
369
370   if (tree) {
371     proto_tree_add_text(tree, tvb, offset, length, "Truncated Data");
372   }
373   return -1;
374 }
375
376 static int dissect_bencoding_rec(tvbuff_t *tvb, packet_info *pinfo _U_,
377                                  int offset, int length, proto_tree *tree, int level, proto_item *treei, int treeadd)
378 {
379   guint8 op;
380   int oplen = 0, op1len, op2len;
381   int used;
382
383   proto_item *ti = NULL, *td = NULL;
384   proto_tree *itree = NULL, *dtree = NULL;
385
386   if (level>10) {
387     proto_tree_add_text(tree, tvb, offset, -1, "Decode Aborted: Nested Too Deep");
388     return -1;
389   }
390   if (length<1) {
391     proto_tree_add_text(tree, tvb, offset, -1, "Truncated Data");
392     return length;
393   }
394
395   op = tvb_get_guint8(tvb, offset);
396   if (tree) {
397     oplen = dissect_bencoding_rec(tvb, pinfo, offset, length, NULL, level, NULL, 0);
398     if (oplen<0) oplen = length;
399   }
400
401   switch (op) {
402   case 'd':
403     if (tree) {
404       td = proto_tree_add_item(tree, hf_bittorrent_bdict, tvb, offset, oplen, FALSE);
405       dtree = proto_item_add_subtree(td, ett_bittorrent_bdict);
406     }
407
408     used = 1;
409     length--;
410
411     while (length>=1) {
412       op = tvb_get_guint8(tvb, offset+used);
413
414       if (op=='e') {
415         return used+1;
416       }
417
418       op1len = dissect_bencoding_str(tvb, pinfo, offset+used, length, NULL, NULL, 0);
419       if (op1len<0) {
420         if (dtree) {
421           proto_tree_add_text(dtree, tvb, offset+used, -1, "Decode Aborted: Invalid Dictionary Key");
422         }
423         return op1len;
424       }
425
426       op2len = -1;
427       if (length-op1len>2)
428         op2len = dissect_bencoding_rec(tvb, pinfo, offset+used+op1len, length-op1len, NULL, level+1, NULL, 0);
429       if (op2len<0) {
430         if (dtree) {
431           proto_tree_add_text(dtree, tvb, offset+used+op1len, -1, "Decode Aborted: Invalid Dictionary Value");
432         }
433         return op2len;
434       }
435
436       if (dtree) {
437         ti = proto_tree_add_item(dtree, hf_bittorrent_bdict_entry, tvb, offset+used, op1len+op2len, FALSE);
438         itree = proto_item_add_subtree(ti, ett_bittorrent_bdict_entry);
439
440         dissect_bencoding_str(tvb, pinfo, offset+used, length, itree, ti, 1);
441         dissect_bencoding_rec(tvb, pinfo, offset+used+op1len, length-op1len, itree, level+1, ti, 2);
442       }
443
444       used += op1len+op2len;
445       length -= op1len+op2len;
446     }
447     if (dtree) {
448       proto_tree_add_text(dtree, tvb, offset+used, -1, "Truncated Data");
449     }
450     return -1;
451
452   case 'l':
453     if (tree) {
454       ti = proto_tree_add_item(tree, hf_bittorrent_blist, tvb, offset, oplen, FALSE);
455       itree = proto_item_add_subtree(ti, ett_bittorrent_blist);
456     }
457
458     used = 1;
459     length--;
460
461     while (length>=1) {
462       op = tvb_get_guint8(tvb, offset+used);
463
464       if (op=='e') {
465         return used+1;
466       }
467
468       oplen = dissect_bencoding_rec(tvb, pinfo, offset+used, length, itree, level+1, ti, 0);
469       if (oplen<1) return oplen;
470
471       used += oplen;
472       length -= oplen;
473     }
474     if (itree) {
475       proto_tree_add_text(itree, tvb, offset+used, -1, "Truncated Data");
476     }
477     return -1;
478
479   case 'i':
480     return dissect_bencoding_int(tvb, pinfo, offset, length, tree, treei, treeadd);
481
482   default:
483     if (op>='1' && op<='9') {
484       return dissect_bencoding_str(tvb, pinfo, offset, length, tree, treei, treeadd);
485     }
486
487     if (tree) {
488       proto_tree_add_text(tree, tvb, offset, -1, "Decode Aborted: Invalid Bencoding");
489     }
490   }
491
492   return -1;
493 }
494
495 static void dissect_bencoding(tvbuff_t *tvb, packet_info *pinfo _U_,
496                              int offset, int length, proto_tree *tree)
497 {
498   dissect_bencoding_rec(tvb, pinfo, offset, length, tree, 0, NULL, 0);
499 }
500
501 static void dissect_bittorrent_message (tvbuff_t *tvb, packet_info *pinfo, proto_tree *tree)
502 {
503    int offset = 0;
504    int i;
505    int doffset = BITTORRENT_HEADER_LENGTH;
506    int isamp = 0;
507    proto_tree *mtree;
508    guint16 type = 0;
509    guint32 typelen = 0;
510    guint8 prio = 0;
511    guint32 length;
512    const char *msgtype = NULL;
513    proto_item *ti;
514    guint32 piece_index, piece_begin, piece_length;
515    guint32 stringlen;
516
517    if (tvb_bytes_exist(tvb, offset + BITTORRENT_HEADER_LENGTH, 1)) {
518       /* Check for data from the middle of a message. */
519       length = tvb_get_ntohl(tvb, offset);
520       type = tvb_get_guint8(tvb, offset + BITTORRENT_HEADER_LENGTH);
521
522       if (type==BITTORRENT_MESSAGE_CHOKE && length>4) {
523         /*
524          * Choke messages have no payload, so this is likely an Azureus
525          * Messaging Protocol packet
526          */
527         if (!tvb_bytes_exist(tvb, offset + BITTORRENT_HEADER_LENGTH, 4))
528           return;
529
530         typelen = tvb_get_ntohl(tvb, offset + BITTORRENT_HEADER_LENGTH);
531         if (4+typelen+1<=length) {
532           if (!tvb_bytes_exist(tvb, offset + BITTORRENT_HEADER_LENGTH + 4, typelen+1))
533             return;
534
535           for ( i=0 ; amp_messages[i].name ; i++ ) {
536             if (strlen(amp_messages[i].name)==typelen &&
537                 tvb_memeql(tvb, offset + BITTORRENT_HEADER_LENGTH + 4,
538                            amp_messages[i].name, (int)strlen(amp_messages[i].name))==0) {
539
540               prio = tvb_get_guint8(tvb, offset + BITTORRENT_HEADER_LENGTH + 4 + typelen);
541               if (prio==0 || prio==1 || prio==2) {
542                 type = amp_messages[i].value;
543                 doffset = BITTORRENT_HEADER_LENGTH + 4 + typelen + 1;
544                 isamp = 1;
545               }
546               break;
547             }
548           }
549         }
550       }
551
552       msgtype = match_strval(type, bittorrent_messages);
553       /*      if (msgtype == NULL && isamp) {
554         msgtype = match_strval(type, azureus_messages);
555         } */
556       if (msgtype == NULL) {
557          proto_tree_add_text(tree, tvb, offset, -1, "Continuation data");
558          if (check_col(pinfo->cinfo, COL_INFO)) {
559             col_set_str(pinfo->cinfo, COL_INFO, "Continuation data");
560          }
561          return;
562       }
563    } else {
564           /* not enough bytes of the header, stop here */
565           return;
566    }
567
568    if (isamp) {
569      ti = proto_tree_add_item(tree, hf_azureus_msg, tvb, offset, length + BITTORRENT_HEADER_LENGTH, FALSE);
570    } else {
571      ti = proto_tree_add_item(tree, hf_bittorrent_msg, tvb, offset, length + BITTORRENT_HEADER_LENGTH, FALSE);
572    }
573    mtree = proto_item_add_subtree(ti, ett_bittorrent_msg);
574
575    /* Keepalive message */
576    if (length == 0) {
577       proto_tree_add_item(mtree, hf_bittorrent_msg_len, tvb, offset, BITTORRENT_HEADER_LENGTH, FALSE);
578       if (check_col(pinfo->cinfo, COL_INFO)) {
579          col_set_str(pinfo->cinfo, COL_INFO, "KeepAlive");
580       }
581       return;
582    }
583
584    proto_tree_add_item(mtree, hf_bittorrent_msg_len, tvb, offset, BITTORRENT_HEADER_LENGTH, FALSE);
585    offset += BITTORRENT_HEADER_LENGTH;
586
587    /* If the tvb_bytes_exist() call above returned FALSE, this will
588       throw an exception, so we won't use msgtype or type. */
589    if (isamp) {
590      proto_tree_add_item(mtree, hf_azureus_msg_type_len, tvb, offset, 4, FALSE);
591      proto_tree_add_item(mtree, hf_azureus_msg_type, tvb, offset+4, typelen, FALSE);
592      proto_item_append_text(ti, ": Len %u, %s", length, msgtype);
593      proto_tree_add_item(mtree, hf_azureus_msg_prio, tvb, offset+4+typelen, 1, FALSE);
594      offset += 4+typelen+1;
595      length -= 4+typelen+1;
596    } else {
597      proto_tree_add_item(mtree, hf_bittorrent_msg_type, tvb, offset, 1, FALSE);
598      proto_item_append_text(ti, ": Len:%u, %s", length, msgtype);
599      offset += 1;
600      length -= 1;
601    }
602    if (check_col(pinfo->cinfo, COL_INFO)) {
603       col_set_str(pinfo->cinfo, COL_INFO, msgtype);
604    }
605
606    switch (type) {
607    case BITTORRENT_MESSAGE_CHOKE:
608    case BITTORRENT_MESSAGE_UNCHOKE:
609    case BITTORRENT_MESSAGE_INTERESTED:
610    case BITTORRENT_MESSAGE_NOT_INTERESTED:
611       /* No payload */
612       break;
613
614    case BITTORRENT_MESSAGE_REQUEST:
615    case BITTORRENT_MESSAGE_CANCEL:
616           piece_index = tvb_get_ntohl(tvb, offset);
617       proto_tree_add_uint(mtree, hf_bittorrent_piece_index, tvb, offset, 4, piece_index); offset += 4;
618           piece_begin = tvb_get_ntohl(tvb, offset);
619       proto_tree_add_uint(mtree, hf_bittorrent_piece_begin, tvb, offset, 4, piece_begin); offset += 4;
620           piece_length = tvb_get_ntohl(tvb, offset);
621       proto_tree_add_uint(mtree, hf_bittorrent_piece_length, tvb, offset, 4, piece_length);
622       proto_item_append_text(ti, ", Piece (Idx:0x%x,Begin:0x%x,Len:0x%x)", piece_index, piece_begin, piece_length);
623       if (check_col(pinfo->cinfo, COL_INFO)) {
624          col_append_fstr(pinfo->cinfo, COL_INFO, ", Piece (Idx:0x%x,Begin:0x%x,Len:0x%x)", piece_index, piece_begin, piece_length);
625           }
626       break;
627
628    case BITTORRENT_MESSAGE_HAVE:
629           piece_index = tvb_get_ntohl(tvb, offset);
630       proto_tree_add_item(mtree, hf_bittorrent_piece_index, tvb, offset, 4, FALSE);
631       proto_item_append_text(ti, ", Piece (Idx:0x%x)", piece_index);
632       if (check_col(pinfo->cinfo, COL_INFO)) {
633          col_append_fstr(pinfo->cinfo, COL_INFO, ", Piece (Idx:0x%x)", piece_index);
634           }
635       break;
636
637    case BITTORRENT_MESSAGE_BITFIELD:
638       proto_tree_add_item(mtree, hf_bittorrent_bitfield_data, tvb, offset, length, FALSE);
639       proto_item_append_text(ti, ", Len:0x%x", length);
640       if (check_col(pinfo->cinfo, COL_INFO)) {
641          col_append_fstr(pinfo->cinfo, COL_INFO, ", Len:0x%x", length);
642           }
643       break;
644
645    case BITTORRENT_MESSAGE_PIECE:
646           piece_index = tvb_get_ntohl(tvb, offset);
647       proto_tree_add_uint(mtree, hf_bittorrent_piece_index, tvb, offset, 4, piece_index);
648       offset += 4;
649       length -= 4;
650           piece_begin = tvb_get_ntohl(tvb, offset);
651       proto_tree_add_item(mtree, hf_bittorrent_piece_begin, tvb, offset, 4, piece_begin);
652       offset += 4;
653       length -= 4;
654       proto_tree_add_item(mtree, hf_bittorrent_piece_data, tvb, offset, length, FALSE);
655       proto_item_append_text(ti, ", Idx:0x%x,Begin:0x%x,Len:0x%x", piece_index, piece_begin, length);
656       if (check_col(pinfo->cinfo, COL_INFO)) {
657          col_append_fstr(pinfo->cinfo, COL_INFO, ", Idx:0x%x,Begin:0x%x,Len:0x%x", piece_index, piece_begin, length);
658           }
659       break;
660
661    case AZUREUS_MESSAGE_HANDSHAKE:
662    case AZUREUS_MESSAGE_PEER_EXCHANGE:
663      dissect_bencoding(tvb, pinfo, offset, length, mtree);
664      break;
665
666    case AZUREUS_MESSAGE_JPC_HELLO:
667      stringlen = tvb_get_ntohl(tvb, offset);
668      proto_tree_add_item(mtree, hf_azureus_jpc_addrlen, tvb, offset, 4, FALSE);
669      proto_tree_add_item(mtree, hf_azureus_jpc_addr, tvb, offset+4, stringlen, FALSE);
670      proto_tree_add_item(mtree, hf_azureus_jpc_port, tvb, offset+4+stringlen, 4, FALSE);
671      proto_tree_add_item(mtree, hf_azureus_jpc_session, tvb, offset+4+stringlen+4, 4, FALSE);
672      break;
673
674    case AZUREUS_MESSAGE_JPC_REPLY:
675      proto_tree_add_item(mtree, hf_azureus_jpc_session, tvb, offset, 4, FALSE);
676      break;
677
678    default:
679       break;
680    }
681 }
682
683 static void dissect_bittorrent_welcome (tvbuff_t *tvb, packet_info *pinfo _U_, proto_tree *tree)
684 {
685    int offset = 0;
686    int i;
687    char *version;
688
689    if (check_col(pinfo->cinfo, COL_INFO)) {
690       col_set_str(pinfo->cinfo, COL_INFO, "Handshake");
691    }
692
693    proto_tree_add_item(tree, hf_bittorrent_prot_name_len, tvb, offset, 1, FALSE); offset+=1;
694    proto_tree_add_item(tree, hf_bittorrent_prot_name, tvb, offset, 19, FALSE); offset += 19;
695    proto_tree_add_item(tree, hf_bittorrent_reserved, tvb, offset, 8, FALSE); offset += 8;
696
697    proto_tree_add_item(tree, hf_bittorrent_sha1_hash, tvb, offset, 20, FALSE);
698    offset += 20;
699
700    proto_tree_add_item(tree, hf_bittorrent_peer_id, tvb, offset, 20, FALSE);
701    if(decode_client_information) {
702       for(i = 0; peer_id[i].id[0] != '\0'; ++i)
703       {
704          if(tvb_memeql(tvb, offset, peer_id[i].id, (int)strlen(peer_id[i].id)) == 0) {
705             /* The version number is 4 numeric characters for the
706                client ids beginning with '-' and 3 characters for the
707                rest. */
708             version = tvb_get_ephemeral_string(tvb, offset + (int)strlen(peer_id[i].id),
709                (peer_id[i].id[0] == '-') ? 4 : 3);
710             proto_tree_add_text(tree, tvb, offset, 20, "Client is %s v%s",
711                peer_id[i].name,
712                format_text((guchar*)version, (peer_id[i].id[0] == '-') ? 4 : 3));
713             break;
714          }
715       }
716    }
717    offset += 20;
718 }
719
720 static void dissect_bittorrent_tcp_pdu (tvbuff_t *tvb, packet_info *pinfo, proto_tree *tree)
721 {
722    proto_item *ti;
723
724    if (check_col(pinfo->cinfo, COL_PROTOCOL)) {
725       col_set_str(pinfo->cinfo, COL_PROTOCOL, "BitTorrent");
726    }
727
728    if (check_col(pinfo->cinfo, COL_INFO)) {
729       col_set_str(pinfo->cinfo, COL_INFO, "BitTorrent ");
730    }
731
732    ti = proto_tree_add_item (tree, proto_bittorrent, tvb, 0, -1, FALSE);
733    tree = proto_item_add_subtree(ti, ett_bittorrent);
734
735    if (tvb_get_guint8(tvb, 0) == 19 &&
736        tvb_memeql(tvb, 1, "BitTorrent protocol", 19) == 0) {
737       dissect_bittorrent_welcome(tvb, pinfo, tree);
738    } else {
739       dissect_bittorrent_message(tvb, pinfo, tree);
740    }
741
742    if (check_col(pinfo->cinfo, COL_INFO)) {
743       col_append_str(pinfo->cinfo, COL_INFO, "  ");
744       col_set_fence(pinfo->cinfo, COL_INFO);
745    }
746 }
747
748 static void dissect_bittorrent (tvbuff_t *tvb, packet_info *pinfo, proto_tree *tree)
749 {
750    tcp_dissect_pdus(tvb, pinfo, tree, bittorrent_desegment, BITTORRENT_HEADER_LENGTH,
751                     get_bittorrent_pdu_length, dissect_bittorrent_tcp_pdu);
752 }
753
754 static gboolean test_bittorrent_packet (tvbuff_t *tvb, packet_info *pinfo,
755                                         proto_tree *tree)
756 {
757    conversation_t *conversation;
758
759    if (tvb_length(tvb) >= 20 &&
760        tvb_get_guint8(tvb, 0) == 19 &&
761        tvb_memeql(tvb, 1, "BitTorrent protocol", 19) == 0) {
762       /* XXXX why new ? */
763       conversation = conversation_new (pinfo->fd->num, &pinfo->src, &pinfo->dst, pinfo->ptype, pinfo->srcport, pinfo->destport, 0);
764
765       conversation_set_dissector(conversation, dissector_handle);
766
767       dissect_bittorrent(tvb, pinfo, tree);
768
769       return TRUE;
770    }
771
772    return FALSE;
773 }
774
775 void
776 proto_register_bittorrent(void)
777 {
778    static hf_register_info hf[] = {
779       { &hf_bittorrent_field_length,
780       { "Field Length", "bittorrent.length", FT_UINT32, BASE_DEC, NULL, 0x0, NULL, HFILL }
781       },
782       { &hf_bittorrent_prot_name_len,
783       { "Protocol Name Length", "bittorrent.protocol.name.length", FT_UINT8, BASE_DEC, NULL, 0x0, NULL, HFILL }
784       },
785       { &hf_bittorrent_prot_name,
786       { "Protocol Name", "bittorrent.protocol.name", FT_STRING, BASE_NONE, NULL, 0x0, NULL, HFILL }
787       },
788       { &hf_bittorrent_reserved,
789       { "Reserved Extension Bytes", "bittorrent.reserved", FT_BYTES, BASE_NONE, NULL, 0x0, NULL, HFILL }
790       },
791       { &hf_bittorrent_sha1_hash,
792       { "SHA1 Hash of info dictionary", "bittorrent.info_hash", FT_BYTES, BASE_NONE, NULL, 0x0, NULL, HFILL }
793       },
794       { &hf_bittorrent_peer_id,
795       { "Peer ID", "bittorrent.peer_id", FT_BYTES, BASE_NONE, NULL, 0x0, NULL, HFILL }
796       },
797       { &hf_bittorrent_msg,
798       { "Message", "bittorrent.msg", FT_NONE, BASE_NONE, NULL, 0x0, NULL, HFILL }
799       },
800       { &hf_bittorrent_msg_len,
801       { "Message Length", "bittorrent.msg.length", FT_UINT32, BASE_DEC, NULL, 0x0, NULL, HFILL }
802       },
803       { &hf_bittorrent_msg_type,
804       { "Message Type", "bittorrent.msg.type", FT_UINT8, BASE_DEC, VALS(bittorrent_messages), 0x0, NULL, HFILL }
805       },
806       { &hf_azureus_msg,
807       { "Azureus Message", "bittorrent.azureus_msg", FT_NONE, BASE_NONE, NULL, 0x0, NULL, HFILL }
808       },
809       { &hf_azureus_msg_type_len,
810       { "Message Type Length", "bittorrent.msg.typelen", FT_UINT32, BASE_DEC, NULL, 0x0, NULL, HFILL }
811       },
812       { &hf_azureus_msg_type,
813       { "Message Type", "bittorrent.msg.aztype", FT_STRING, BASE_NONE, NULL, 0x0, NULL, HFILL }
814       },
815       { &hf_azureus_msg_prio,
816       { "Message Priority", "bittorrent.msg.prio", FT_UINT8, BASE_DEC, VALS(azureus_priorities), 0x0, NULL, HFILL }
817       },
818       { &hf_bittorrent_bitfield_data,
819      { "Bitfield data", "bittorrent.msg.bitfield", FT_BYTES, BASE_NONE, NULL, 0x0, NULL, HFILL }
820       },
821       { &hf_bittorrent_piece_index,
822       { "Piece index", "bittorrent.piece.index", FT_UINT32, BASE_HEX, NULL, 0x0, NULL, HFILL }
823       },
824       { &hf_bittorrent_piece_begin,
825       { "Begin offset of piece", "bittorrent.piece.begin", FT_UINT32, BASE_HEX, NULL, 0x0, NULL, HFILL }
826       },
827       { &hf_bittorrent_piece_data,
828       { "Data in a piece", "bittorrent.piece.data", FT_BYTES, BASE_NONE, NULL, 0x0, NULL, HFILL }
829       },
830       { &hf_bittorrent_piece_length,
831          { "Piece Length", "bittorrent.piece.length", FT_UINT32, BASE_HEX, NULL, 0x0, NULL, HFILL }
832       },
833       { &hf_bittorrent_bstr_length,
834         { "String Length", "bittorrent.bstr.length", FT_UINT32, BASE_DEC, NULL, 0x0, NULL, HFILL }
835       },
836       { &hf_bittorrent_bstr,
837         { "String", "bittorrent.bstr", FT_STRING, BASE_NONE, NULL, 0x0, NULL, HFILL }
838       },
839       { &hf_bittorrent_bint,
840         { "Integer", "bittorrent.bint", FT_INT32, BASE_DEC, NULL, 0x0, NULL, HFILL }
841       },
842       { &hf_bittorrent_bdict,
843         { "Dictionary", "bittorrent.bdict", FT_NONE, BASE_NONE, NULL, 0x0, NULL, HFILL }
844       },
845       { &hf_bittorrent_bdict_entry,
846         { "Entry", "bittorrent.bdict.entry", FT_NONE, BASE_NONE, NULL, 0x0, NULL, HFILL }
847       },
848       { &hf_bittorrent_blist,
849         { "List", "bittorrent.blist", FT_NONE, BASE_NONE, NULL, 0x0, NULL, HFILL }
850       },
851       { &hf_azureus_jpc_addrlen,
852         { "Cache Address Length", "bittorrent.jpc.addr.length", FT_UINT32, BASE_DEC, NULL, 0x0, NULL, HFILL }
853       },
854       { &hf_azureus_jpc_addr,
855         { "Cache Address", "bittorrent.jpc.addr", FT_STRING, BASE_NONE, NULL, 0x0, NULL, HFILL }
856       },
857       { &hf_azureus_jpc_port,
858         { "Port", "bittorrent.jpc.port", FT_UINT32, BASE_DEC, NULL, 0x0, NULL, HFILL }
859       },
860       { &hf_azureus_jpc_session,
861         { "Session ID", "bittorrent.jpc.session", FT_UINT32, BASE_HEX, NULL, 0x0, NULL, HFILL }
862       }
863   };
864
865   static gint *ett[] = {
866     &ett_bittorrent,
867     &ett_bittorrent_msg,
868     &ett_peer_id,
869     &ett_bittorrent_bdict,
870     &ett_bittorrent_bdict_entry,
871     &ett_bittorrent_blist
872   };
873
874   module_t *bittorrent_module;
875
876   proto_bittorrent = proto_register_protocol("BitTorrent", "BitTorrent", "bittorrent");
877   proto_register_field_array(proto_bittorrent, hf, array_length(hf));
878   proto_register_subtree_array(ett, array_length(ett));
879
880   register_dissector("bittorrent.tcp", dissect_bittorrent, proto_bittorrent);
881
882   bittorrent_module = prefs_register_protocol(proto_bittorrent, NULL);
883   prefs_register_bool_preference(bittorrent_module, "desegment",
884     "Reassemble BitTorrent messages spanning multiple TCP segments",
885     "Whether the BitTorrent dissector should reassemble messages spanning multiple TCP segments."
886     " To use this option, you must also enable \"Allow subdissectors to reassemble TCP streams\" in the TCP protocol settings.",
887     &bittorrent_desegment);
888   prefs_register_bool_preference(bittorrent_module, "decode_client",
889      "Decode the peer_id of the handshake messages",
890      "Enabling this will tell which BitTorrent client that produced the handshake message",
891      &decode_client_information);
892 }
893
894
895 void
896 proto_reg_handoff_bittorrent(void)
897 {
898 /*   dissector_handle = create_dissector_handle(dissect_bittorrent, proto_bittorrent); */
899    dissector_handle = find_dissector("bittorrent.tcp");
900 #if 0
901    dissector_add("tcp.port", 6881, dissector_handle);
902    dissector_add("tcp.port", 6882, dissector_handle);
903    dissector_add("tcp.port", 6883, dissector_handle);
904    dissector_add("tcp.port", 6884, dissector_handle);
905    dissector_add("tcp.port", 6885, dissector_handle);
906    dissector_add("tcp.port", 6886, dissector_handle);
907    dissector_add("tcp.port", 6887, dissector_handle);
908    dissector_add("tcp.port", 6888, dissector_handle);
909    dissector_add("tcp.port", 6889, dissector_handle);
910 #endif
911    heur_dissector_add("tcp", test_bittorrent_packet, proto_bittorrent);
912 }