added some options and enhancements to the print output:
[obnox/wireshark/wip.git] / packet-gnutella.c
1 /* packet-gnutella.c
2  * Routines for gnutella dissection
3  * Copyright 2001, B. Johannessen <bob@havoq.com>
4  *
5  * $Id: packet-gnutella.c,v 1.15 2002/08/28 21:00:13 jmayer Exp $
6  *
7  * Ethereal - Network traffic analyzer
8  * By Gerald Combs <gerald@ethereal.com>
9  * Copyright 1998 Gerald Combs
10  *
11  * This program is free software; you can redistribute it and/or
12  * modify it under the terms of the GNU General Public License
13  * as published by the Free Software Foundation; either version 2
14  * of the License, or (at your option) any later version.
15  *
16  * This program is distributed in the hope that it will be useful,
17  * but WITHOUT ANY WARRANTY; without even the implied warranty of
18  * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
19  * GNU General Public License for more details.
20  *
21  * You should have received a copy of the GNU General Public License
22  * along with this program; if not, write to the Free Software
23  * Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA.
24  */
25
26 #ifdef HAVE_CONFIG_H
27 #include "config.h"
28 #endif
29
30 #include <stdio.h>
31 #include <stdlib.h>
32 #include <string.h>
33
34 #include <glib.h>
35
36
37 #include <epan/packet.h>
38 #include "packet-gnutella.h"
39
40 static int proto_gnutella = -1;
41
42 static int hf_gnutella_stream = -1;
43
44 static int hf_gnutella_truncated = -1;
45
46 static int hf_gnutella_header = -1;
47 static int hf_gnutella_header_id = -1;
48 static int hf_gnutella_header_payload = -1;
49 static int hf_gnutella_header_ttl = -1;
50 static int hf_gnutella_header_hops = -1;
51 static int hf_gnutella_header_size = -1;
52
53 static int hf_gnutella_pong_payload = -1;
54 static int hf_gnutella_pong_port = -1;
55 static int hf_gnutella_pong_ip = -1;
56 static int hf_gnutella_pong_files = -1;
57 static int hf_gnutella_pong_kbytes = -1;
58
59 static int hf_gnutella_query_payload = -1;
60 static int hf_gnutella_query_min_speed = -1;
61 static int hf_gnutella_query_search = -1;
62
63 static int hf_gnutella_queryhit_payload = -1;
64 static int hf_gnutella_queryhit_count = -1;
65 static int hf_gnutella_queryhit_port = -1;
66 static int hf_gnutella_queryhit_ip = -1;
67 static int hf_gnutella_queryhit_speed = -1;
68 static int hf_gnutella_queryhit_extra = -1;
69 static int hf_gnutella_queryhit_servent_id = -1;
70
71 static int hf_gnutella_queryhit_hit = -1;
72 static int hf_gnutella_queryhit_hit_index = -1;
73 static int hf_gnutella_queryhit_hit_size = -1;
74 static int hf_gnutella_queryhit_hit_name = -1;
75 static int hf_gnutella_queryhit_hit_extra = -1;
76
77 static int hf_gnutella_push_payload = -1;
78 static int hf_gnutella_push_servent_id = -1;
79 static int hf_gnutella_push_index = -1;
80 static int hf_gnutella_push_ip = -1;
81 static int hf_gnutella_push_port = -1;
82
83 static gint ett_gnutella = -1;
84
85 static void dissect_gnutella_pong(tvbuff_t *tvb, guint offset, proto_tree *tree, guint size) {
86
87         if(offset + size > tvb_length(tvb)) {
88                 proto_tree_add_item(tree,
89                         hf_gnutella_truncated,
90                         tvb,
91                         offset,
92                         size,
93                         FALSE);
94                 return;
95         }
96
97         proto_tree_add_item(tree,
98                 hf_gnutella_pong_port,
99                 tvb,
100                 offset + GNUTELLA_PONG_PORT_OFFSET,
101                 GNUTELLA_PORT_LENGTH,
102                 TRUE);
103
104         proto_tree_add_item(tree,
105                 hf_gnutella_pong_ip,
106                 tvb,
107                 offset + GNUTELLA_PONG_IP_OFFSET,
108                 GNUTELLA_IP_LENGTH,
109         FALSE);
110
111         proto_tree_add_item(tree,
112                 hf_gnutella_pong_files,
113                 tvb,
114                 offset + GNUTELLA_PONG_FILES_OFFSET,
115                 GNUTELLA_LONG_LENGTH,
116                 TRUE);
117
118         proto_tree_add_item(tree,
119                 hf_gnutella_pong_kbytes,
120                 tvb,
121                 offset + GNUTELLA_PONG_KBYTES_OFFSET,
122                 GNUTELLA_LONG_LENGTH,
123                 TRUE);
124
125 }
126
127 static void dissect_gnutella_query(tvbuff_t *tvb, guint offset, proto_tree *tree, guint size) {
128
129         if(offset + size > tvb_length(tvb)) {
130                 proto_tree_add_item(tree,
131                         hf_gnutella_truncated,
132                         tvb,
133                         offset,
134                         size,
135                         FALSE);
136                 return;
137         }
138
139         proto_tree_add_item(tree,
140                 hf_gnutella_query_min_speed,
141                 tvb,
142                 offset + GNUTELLA_QUERY_SPEED_OFFSET,
143                 GNUTELLA_SHORT_LENGTH,
144         TRUE);
145
146     if (size > GNUTELLA_SHORT_LENGTH) {
147         proto_tree_add_item(tree,
148             hf_gnutella_query_search,
149             tvb,
150             offset + GNUTELLA_QUERY_SEARCH_OFFSET,
151             size - GNUTELLA_SHORT_LENGTH,
152             FALSE);
153     }
154     else {
155         proto_tree_add_text(tree,
156             tvb,
157             offset + GNUTELLA_QUERY_SEARCH_OFFSET,
158             0,
159             "Missing data for Query Search.");
160     }
161 }
162
163 static void dissect_gnutella_queryhit(tvbuff_t *tvb, guint offset, proto_tree *tree, guint size) {
164
165         proto_tree *qhi, *hit_tree;
166         int hit_count, i;
167         int hit_offset;
168         int name_length, extra_length;
169         int idx_at_offset, size_at_offset;
170         int servent_id_at_offset;
171         int name_at_offset, extra_at_offset;
172         int cur_char, remaining, used;
173
174         if(offset + size > tvb_length(tvb)) {
175                 proto_tree_add_item(tree,
176                         hf_gnutella_truncated,
177                         tvb,
178                         offset,
179                         size,
180                         FALSE);
181                 return;
182         }
183
184         hit_count = tvb_get_guint8(tvb, offset + GNUTELLA_QUERYHIT_COUNT_OFFSET);
185
186         proto_tree_add_uint(tree,
187                 hf_gnutella_queryhit_count,
188                 tvb,
189                 offset + GNUTELLA_QUERYHIT_COUNT_OFFSET,
190                 GNUTELLA_BYTE_LENGTH,
191                 hit_count);
192
193         proto_tree_add_item(tree,
194                 hf_gnutella_queryhit_port,
195                 tvb,
196                 offset + GNUTELLA_QUERYHIT_PORT_OFFSET,
197                 GNUTELLA_PORT_LENGTH,
198                 TRUE);
199
200         proto_tree_add_item(tree,
201                 hf_gnutella_queryhit_ip,
202                 tvb,
203                 offset + GNUTELLA_QUERYHIT_IP_OFFSET,
204                 GNUTELLA_IP_LENGTH,
205                 FALSE);
206
207         proto_tree_add_item(tree,
208                 hf_gnutella_queryhit_speed,
209                 tvb,
210                 offset + GNUTELLA_QUERYHIT_SPEED_OFFSET,
211                 GNUTELLA_LONG_LENGTH,
212                 TRUE);
213
214         hit_offset = offset + GNUTELLA_QUERYHIT_FIRST_HIT_OFFSET;
215
216         for(i = 0; i < hit_count; i++) {
217                 idx_at_offset  = hit_offset;
218                 size_at_offset = hit_offset + GNUTELLA_QUERYHIT_HIT_SIZE_OFFSET;
219
220                 hit_offset += (GNUTELLA_LONG_LENGTH * 2);
221
222                 name_length  = 0;
223                 extra_length = 0;
224
225                 name_at_offset = hit_offset;
226
227                 while(hit_offset - offset < size) {
228                         cur_char = tvb_get_guint8(tvb, hit_offset);
229                         if(cur_char == '\0')
230                                 break;
231
232                         hit_offset++;
233                         name_length++;
234                 }
235
236                 hit_offset++;
237
238                 extra_at_offset = hit_offset;
239
240                 while(hit_offset - offset < size) {
241                         cur_char = tvb_get_guint8(tvb, hit_offset);
242                         if(cur_char == '\0')
243                                 break;
244
245                         hit_offset++;
246                         extra_length++;
247                 }
248
249                 hit_offset++;
250
251                 qhi = proto_tree_add_item(tree,
252                         hf_gnutella_queryhit_hit,
253                         tvb,
254                         idx_at_offset,
255                         (GNUTELLA_LONG_LENGTH * 2) +
256                         name_length + extra_length +
257                         GNUTELLA_QUERYHIT_END_OF_STRING_LENGTH,
258                         FALSE);
259
260                 hit_tree = proto_item_add_subtree(qhi, ett_gnutella);
261
262                 proto_tree_add_item(hit_tree,
263                         hf_gnutella_queryhit_hit_index,
264                         tvb,
265                         idx_at_offset,
266                         GNUTELLA_LONG_LENGTH,
267                         TRUE);
268
269                 proto_tree_add_item(hit_tree,
270                         hf_gnutella_queryhit_hit_size,
271                         tvb,
272                         size_at_offset,
273                         GNUTELLA_LONG_LENGTH,
274                         TRUE);
275
276                 proto_tree_add_item(hit_tree,
277                         hf_gnutella_queryhit_hit_name,
278                         tvb,
279                         name_at_offset,
280                         name_length,
281                         FALSE);
282
283                 if(extra_length) {
284                         proto_tree_add_item(hit_tree,
285                                 hf_gnutella_queryhit_hit_extra,
286                                 tvb,
287                                 extra_at_offset,
288                                 extra_length,
289                                 FALSE);
290                 }
291         }
292
293         used = hit_offset - offset;
294         remaining = size - used;
295
296         if(remaining > GNUTELLA_SERVENT_ID_LENGTH) {
297                 servent_id_at_offset = hit_offset + remaining - GNUTELLA_SERVENT_ID_LENGTH;
298
299                 proto_tree_add_item(tree,
300                         hf_gnutella_queryhit_extra,
301                         tvb,
302                         hit_offset,
303                         servent_id_at_offset - hit_offset,
304                         FALSE);
305         }
306         else {
307                 servent_id_at_offset = hit_offset;
308         }
309
310         proto_tree_add_item(tree,
311                 hf_gnutella_queryhit_servent_id,
312                 tvb,
313                 servent_id_at_offset,
314                 GNUTELLA_SERVENT_ID_LENGTH,
315                 FALSE);
316
317 }
318
319 static void dissect_gnutella_push(tvbuff_t *tvb, guint offset, proto_tree *tree, guint size) {
320
321         if(offset + size > tvb_length(tvb)) {
322                 proto_tree_add_item(tree,
323                         hf_gnutella_truncated,
324                         tvb,
325                         offset,
326                         size,
327                         FALSE);
328                 return;
329         }
330
331         proto_tree_add_item(tree,
332                 hf_gnutella_push_servent_id,
333                 tvb,
334                 offset + GNUTELLA_PUSH_SERVENT_ID_OFFSET,
335                 GNUTELLA_SERVENT_ID_LENGTH,
336                 FALSE);
337
338         proto_tree_add_item(tree,
339                 hf_gnutella_push_index,
340                 tvb,
341                 offset + GNUTELLA_PUSH_INDEX_OFFSET,
342                 GNUTELLA_LONG_LENGTH,
343                 TRUE);
344
345         proto_tree_add_item(tree,
346                 hf_gnutella_push_ip,
347                 tvb,
348                 offset + GNUTELLA_PUSH_IP_OFFSET,
349                 GNUTELLA_IP_LENGTH,
350                 FALSE);
351
352         proto_tree_add_item(tree,
353                 hf_gnutella_push_port,
354                 tvb,
355                 offset + GNUTELLA_PUSH_PORT_OFFSET,
356                 GNUTELLA_PORT_LENGTH,
357                 TRUE);
358
359 }
360
361 static void dissect_gnutella(tvbuff_t *tvb, packet_info *pinfo, proto_tree *tree) {
362
363         proto_item *ti, *hi, *pi;
364         proto_tree *gnutella_tree, *gnutella_header_tree, *gnutella_pong_tree;
365         proto_tree *gnutella_queryhit_tree, *gnutella_push_tree;
366         proto_tree *gnutella_query_tree;
367         int snap_len, payload_descriptor, offset;
368         unsigned int size;
369         char *payload_descriptor_text;
370
371         if (check_col(pinfo->cinfo, COL_PROTOCOL))
372                 col_set_str(pinfo->cinfo, COL_PROTOCOL, "Gnutella");
373
374         if (check_col(pinfo->cinfo, COL_INFO))
375                 col_set_str(pinfo->cinfo, COL_INFO, "Gnutella");
376
377         snap_len = tvb_length(tvb);
378
379         if(snap_len < GNUTELLA_HEADER_LENGTH) {
380                 if (check_col(pinfo->cinfo, COL_INFO))
381                         col_append_fstr(pinfo->cinfo, COL_INFO,
382                                         ", %i bytes [INCOMPLETE]", snap_len);
383                 return;
384         }
385         else {
386                 if (check_col(pinfo->cinfo, COL_INFO))
387                         col_append_fstr(pinfo->cinfo, COL_INFO,
388                                         ", %i bytes", snap_len);
389         }
390
391         if (tree) {
392                 ti = proto_tree_add_item(tree,
393                         proto_gnutella,
394                         tvb,
395                         0,
396                         -1,
397                         FALSE);
398                 gnutella_tree = proto_item_add_subtree(ti, ett_gnutella);
399
400                 offset = 0;
401
402                 size = tvb_get_letohl(
403                         tvb,
404                         offset + GNUTELLA_HEADER_SIZE_OFFSET);
405                 if(size > GNUTELLA_MAX_SNAP_SIZE) {
406                         proto_tree_add_item(gnutella_tree,
407                                 hf_gnutella_stream,
408                                 tvb,
409                                 offset,
410                                 snap_len,
411                                 FALSE);
412                         return;
413                 }
414
415                 while(snap_len - offset >= GNUTELLA_HEADER_LENGTH) {
416                         payload_descriptor = tvb_get_guint8(
417                                 tvb,
418                                 offset +
419                                 GNUTELLA_HEADER_PAYLOAD_OFFSET);
420                         size = tvb_get_letohl(
421                                 tvb,
422                                 offset + GNUTELLA_HEADER_SIZE_OFFSET);
423
424                         switch(payload_descriptor) {
425                                 case GNUTELLA_PING:
426                                         payload_descriptor_text = GNUTELLA_PING_NAME;
427                                         break;
428                                 case GNUTELLA_PONG:
429                                         payload_descriptor_text = GNUTELLA_PONG_NAME;
430                                         break;
431                                 case GNUTELLA_PUSH:
432                                         payload_descriptor_text = GNUTELLA_PUSH_NAME;
433                                         break;
434                                 case GNUTELLA_QUERY:
435                                         payload_descriptor_text = GNUTELLA_QUERY_NAME;
436                                         break;
437                                 case GNUTELLA_QUERYHIT:
438                                         payload_descriptor_text = GNUTELLA_QUERYHIT_NAME;
439                                         break;
440                                 default:
441                                         payload_descriptor_text = GNUTELLA_UNKNOWN_NAME;
442                                         break;
443                         }
444
445                         hi = proto_tree_add_item(gnutella_tree,
446                                 hf_gnutella_header,
447                                 tvb,
448                                 offset,
449                                 GNUTELLA_HEADER_LENGTH,
450                                 FALSE);
451                         gnutella_header_tree = proto_item_add_subtree(hi, ett_gnutella);
452
453                         proto_tree_add_item(gnutella_header_tree,
454                                 hf_gnutella_header_id,
455                                 tvb,
456                                 offset + GNUTELLA_HEADER_ID_OFFSET,
457                                 GNUTELLA_SERVENT_ID_LENGTH,
458                                 FALSE);
459
460                         proto_tree_add_uint_format(gnutella_header_tree,
461                                 hf_gnutella_header_payload,
462                                 tvb,
463                                 offset + GNUTELLA_HEADER_PAYLOAD_OFFSET,
464                                 GNUTELLA_BYTE_LENGTH,
465                                 payload_descriptor,
466                                 "Payload: %i (%s)",
467                                 payload_descriptor,
468                                 payload_descriptor_text);
469
470                         proto_tree_add_item(gnutella_header_tree,
471                                 hf_gnutella_header_ttl,
472                                 tvb,
473                                 offset + GNUTELLA_HEADER_TTL_OFFSET,
474                                 GNUTELLA_BYTE_LENGTH,
475                                 FALSE);
476
477                         proto_tree_add_item(gnutella_header_tree,
478                                 hf_gnutella_header_hops,
479                                 tvb,
480                                 offset + GNUTELLA_HEADER_HOPS_OFFSET,
481                                 GNUTELLA_BYTE_LENGTH,
482                                 FALSE);
483
484                         proto_tree_add_uint(gnutella_header_tree,
485                                 hf_gnutella_header_size,
486                                 tvb,
487                                 offset + GNUTELLA_HEADER_SIZE_OFFSET,
488                                 GNUTELLA_LONG_LENGTH,
489                                 size);
490
491             if (size > 0) {
492
493                 switch(payload_descriptor) {
494                     case GNUTELLA_PONG:
495                         pi = proto_tree_add_item(
496                             gnutella_header_tree,
497                             hf_gnutella_pong_payload,
498                             tvb,
499                             offset + GNUTELLA_HEADER_LENGTH,
500                             size,
501                             FALSE);
502                         gnutella_pong_tree = proto_item_add_subtree(
503                             pi,
504                             ett_gnutella);
505                         dissect_gnutella_pong(
506                             tvb,
507                             offset + GNUTELLA_HEADER_LENGTH,
508                             gnutella_pong_tree,
509                             size);
510                         break;
511                     case GNUTELLA_PUSH:
512                         pi = proto_tree_add_item(
513                             gnutella_header_tree,
514                             hf_gnutella_push_payload,
515                             tvb,
516                             offset + GNUTELLA_HEADER_LENGTH,
517                             size,
518                             FALSE);
519                         gnutella_push_tree = proto_item_add_subtree(
520                             pi,
521                             ett_gnutella);
522                         dissect_gnutella_push(
523                             tvb,
524                             offset + GNUTELLA_HEADER_LENGTH,
525                             gnutella_push_tree,
526                             size);
527                         break;
528                     case GNUTELLA_QUERY:
529                         pi = proto_tree_add_item(
530                             gnutella_header_tree,
531                             hf_gnutella_query_payload,
532                             tvb,
533                             offset + GNUTELLA_HEADER_LENGTH,
534                             size,
535                             FALSE);
536                         gnutella_query_tree = proto_item_add_subtree(
537                             pi,
538                             ett_gnutella);
539                         dissect_gnutella_query(
540                             tvb,
541                             offset + GNUTELLA_HEADER_LENGTH,
542                             gnutella_query_tree,
543                             size);
544                         break;
545                     case GNUTELLA_QUERYHIT:
546                         pi = proto_tree_add_item(
547                             gnutella_header_tree,
548                             hf_gnutella_queryhit_payload,
549                             tvb,
550                             offset + GNUTELLA_HEADER_LENGTH,
551                             size,
552                             FALSE);
553                         gnutella_queryhit_tree = proto_item_add_subtree(
554                             pi,
555                             ett_gnutella);
556                         dissect_gnutella_queryhit(
557                             tvb,
558                             offset + GNUTELLA_HEADER_LENGTH,
559                             gnutella_queryhit_tree,
560                             size);
561                         break;
562                 }
563             }
564
565                         offset = offset + GNUTELLA_HEADER_LENGTH + size;
566                 }
567         }
568
569 }
570
571
572 void proto_register_gnutella(void) {
573
574         static hf_register_info hf[] = {
575                 { &hf_gnutella_header,
576                         { "Descriptor Header", "gnutella.header",
577                         FT_NONE, BASE_NONE, NULL, 0,
578                         "Gnutella Descriptor Header", HFILL }
579                 },
580                 { &hf_gnutella_pong_payload,
581                         { "Pong", "gnutella.pong.payload",
582                         FT_NONE, BASE_NONE, NULL, 0,
583                         "Gnutella Pong Payload", HFILL }
584                 },
585                 { &hf_gnutella_push_payload,
586                         { "Push", "gnutella.push.payload",
587                         FT_NONE, BASE_NONE, NULL, 0,
588                         "Gnutella Push Payload", HFILL }
589                 },
590                 { &hf_gnutella_query_payload,
591                         { "Query", "gnutella.query.payload",
592                         FT_NONE, BASE_NONE, NULL, 0,
593                         "Gnutella Query Payload", HFILL }
594                 },
595                 { &hf_gnutella_queryhit_payload,
596                         { "QueryHit", "gnutella.queryhit.payload",
597                         FT_NONE, BASE_NONE, NULL, 0,
598                         "Gnutella QueryHit Payload", HFILL }
599                 },
600                 { &hf_gnutella_truncated,
601                         { "Truncated Frame", "gnutella.truncated",
602                         FT_NONE, BASE_NONE, NULL, 0,
603                         "The Gnutella Frame Was Truncated", HFILL }
604                 },
605                 { &hf_gnutella_stream,
606                         { "Gnutella Upload / Download Stream", "gnutella.stream",
607                         FT_NONE, BASE_NONE, NULL, 0,
608                         "Gnutella Upload / Download Stream", HFILL }
609                 },
610                 { &hf_gnutella_header_id,
611                         { "ID", "gnutella.header.id",
612                         FT_BYTES, BASE_HEX, NULL, 0,
613                         "Gnutella Descriptor ID", HFILL }
614                 },
615                 { &hf_gnutella_header_payload,
616                         { "Payload", "gnutella.header.payload",
617                         FT_UINT8, BASE_DEC, NULL, 0,
618                         "Gnutella Descriptor Payload", HFILL }
619                 },
620                 { &hf_gnutella_header_ttl,
621                         { "TTL", "gnutella.header.ttl",
622                         FT_UINT8, BASE_DEC, NULL, 0,
623                         "Gnutella Descriptor Time To Live", HFILL }
624                 },
625                 { &hf_gnutella_header_hops,
626                         { "Hops", "gnutella.header.hops",
627                         FT_UINT8, BASE_DEC, NULL, 0,
628                         "Gnutella Descriptor Hop Count", HFILL }
629                 },
630                 { &hf_gnutella_header_size,
631                         { "Length", "gnutella.header.size",
632                         FT_UINT8, BASE_DEC, NULL, 0,
633                         "Gnutella Descriptor Payload Length", HFILL }
634                 },
635                 { &hf_gnutella_pong_port,
636                         { "Port", "gnutella.pong.port",
637                         FT_UINT16, BASE_DEC, NULL, 0,
638                         "Gnutella Pong TCP Port", HFILL }
639                 },
640                 { &hf_gnutella_pong_ip,
641                         { "IP", "gnutella.pong.ip",
642                         FT_IPv4, BASE_DEC, NULL, 0,
643                         "Gnutella Pong IP Address", HFILL }
644                 },
645                 { &hf_gnutella_pong_files,
646                         { "Files Shared", "gnutella.pong.files",
647                         FT_UINT32, BASE_DEC, NULL, 0,
648                         "Gnutella Pong Files Shared", HFILL }
649                 },
650                 { &hf_gnutella_pong_kbytes,
651                         { "KBytes Shared", "gnutella.pong.kbytes",
652                         FT_UINT32, BASE_DEC, NULL, 0,
653                         "Gnutella Pong KBytes Shared", HFILL }
654                 },
655                 { &hf_gnutella_query_min_speed,
656                         { "Min Speed", "gnutella.query.min_speed",
657                         FT_UINT32, BASE_DEC, NULL, 0,
658                         "Gnutella Query Minimum Speed", HFILL }
659                 },
660                 { &hf_gnutella_query_search,
661                         { "Search", "gnutella.query.search",
662                         FT_STRINGZ, BASE_NONE, NULL, 0,
663                         "Gnutella Query Search", HFILL }
664                 },
665                 { &hf_gnutella_queryhit_hit,
666                         { "Hit", "gnutella.queryhit.hit",
667                         FT_NONE, BASE_NONE, NULL, 0,
668                         "Gnutella QueryHit", HFILL }
669                 },
670                 { &hf_gnutella_queryhit_hit_index,
671                         { "Index", "gnutella.queryhit.hit.index",
672                         FT_UINT32, BASE_DEC, NULL, 0,
673                         "Gnutella QueryHit Index", HFILL }
674                 },
675                 { &hf_gnutella_queryhit_hit_size,
676                         { "Size", "gnutella.queryhit.hit.size",
677                         FT_UINT32, BASE_DEC, NULL, 0,
678                         "Gnutella QueryHit Size", HFILL }
679                 },
680                 { &hf_gnutella_queryhit_hit_name,
681                         { "Name", "gnutella.queryhit.hit.name",
682                         FT_STRING, BASE_NONE, NULL, 0,
683                         "Gnutella Query Name", HFILL }
684                 },
685                 { &hf_gnutella_queryhit_hit_extra,
686                         { "Extra", "gnutella.queryhit.hit.extra",
687                         FT_BYTES, BASE_HEX, NULL, 0,
688                         "Gnutella Query Extra", HFILL }
689                 },
690                 { &hf_gnutella_queryhit_count,
691                         { "Count", "gnutella.queryhit.count",
692                         FT_UINT8, BASE_DEC, NULL, 0,
693                         "Gnutella QueryHit Count", HFILL }
694                 },
695                 { &hf_gnutella_queryhit_port,
696                         { "Port", "gnutella.queryhit.port",
697                         FT_UINT16, BASE_DEC, NULL, 0,
698                         "Gnutella QueryHit Port", HFILL }
699                 },
700                 { &hf_gnutella_queryhit_ip,
701                         { "IP", "gnutella.queryhit.ip",
702                         FT_IPv4, BASE_DEC, NULL, 0,
703                         "Gnutella QueryHit IP Address", HFILL }
704                 },
705                 { &hf_gnutella_queryhit_speed,
706                         { "Speed", "gnutella.queryhit.speed",
707                         FT_UINT32, BASE_DEC, NULL, 0,
708                         "Gnutella QueryHit Speed", HFILL }
709                 },
710                 { &hf_gnutella_queryhit_extra,
711                         { "Extra", "gnutella.queryhit.extra",
712                         FT_BYTES, BASE_HEX, NULL, 0,
713                         "Gnutella QueryHit Extra", HFILL }
714                 },
715                 { &hf_gnutella_queryhit_servent_id,
716                         { "Servent ID", "gnutella.queryhit.servent_id",
717                         FT_BYTES, BASE_HEX, NULL, 0,
718                         "Gnutella QueryHit Servent ID", HFILL }
719                 },
720                 { &hf_gnutella_push_servent_id,
721                         { "Servent ID", "gnutella.push.servent_id",
722                         FT_BYTES, BASE_HEX, NULL, 0,
723                         "Gnutella Push Servent ID", HFILL }
724                 },
725                 { &hf_gnutella_push_ip,
726                         { "IP", "gnutella.push.ip",
727                         FT_IPv4, BASE_DEC, NULL, 0,
728                         "Gnutella Push IP Address", HFILL }
729                 },
730                 { &hf_gnutella_push_index,
731                         { "Index", "gnutella.push.index",
732                         FT_UINT32, BASE_DEC, NULL, 0,
733                         "Gnutella Push Index", HFILL }
734                 },
735                 { &hf_gnutella_push_port,
736                         { "Port", "gnutella.push.port",
737                         FT_UINT16, BASE_DEC, NULL, 0,
738                         "Gnutella Push Port", HFILL }
739                 },
740         };
741
742         static gint *ett[] = {
743                 &ett_gnutella,
744         };
745
746         proto_gnutella = proto_register_protocol("Gnutella Protocol",
747                                                 "GNUTELLA",
748                                                 "gnutella");
749
750         proto_register_field_array(proto_gnutella, hf, array_length(hf));
751
752         proto_register_subtree_array(ett, array_length(ett));
753 }
754
755 void proto_reg_handoff_gnutella(void) {
756         dissector_handle_t gnutella_handle;
757
758         gnutella_handle = create_dissector_handle(dissect_gnutella,
759                         proto_gnutella);
760         dissector_add("tcp.port", GNUTELLA_TCP_PORT, gnutella_handle);
761 }