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