The hash table merely associates data structures with conversations,
[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.7 2001/10/26 18:28:16 gram 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 "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, idx, hit_size;
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         unsigned long ip;
186
187         if(offset + size > tvb_length(tvb)) {
188                 proto_tree_add_item(tree,
189                         hf_gnutella_truncated,
190                         tvb,
191                         offset,
192                         size,
193                         FALSE);
194                 return;
195         }
196
197     hit_count = tvb_get_guint8(tvb, offset + GNUTELLA_QUERYHIT_COUNT_OFFSET);
198
199         proto_tree_add_uint(tree,
200                 hf_gnutella_queryhit_count,
201                 tvb,
202                 offset + GNUTELLA_QUERYHIT_COUNT_OFFSET,
203                 GNUTELLA_BYTE_LENGTH,
204                 hit_count);
205
206         proto_tree_add_item(tree,
207                 hf_gnutella_queryhit_port,
208                 tvb,
209                 offset + GNUTELLA_QUERYHIT_PORT_OFFSET,
210                 GNUTELLA_PORT_LENGTH,
211                 TRUE);
212
213         proto_tree_add_item(tree,
214                 hf_gnutella_queryhit_ip,
215                 tvb,
216                 offset + GNUTELLA_QUERYHIT_IP_OFFSET,
217                 GNUTELLA_IP_LENGTH,
218                 FALSE);
219
220         proto_tree_add_item(tree,
221                 hf_gnutella_queryhit_speed,
222                 tvb,
223                 offset + GNUTELLA_QUERYHIT_SPEED_OFFSET,
224                 GNUTELLA_LONG_LENGTH,
225                 TRUE);
226
227         hit_offset = offset + GNUTELLA_QUERYHIT_FIRST_HIT_OFFSET;
228
229         for(i = 0; i < hit_count; i++) {
230                 idx_at_offset  = hit_offset;
231                 size_at_offset = hit_offset + GNUTELLA_QUERYHIT_HIT_SIZE_OFFSET;
232
233                 hit_offset += (GNUTELLA_LONG_LENGTH * 2);
234
235                 name_length  = 0;
236                 extra_length = 0;
237
238                 name_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                         name_length++;
247                 }
248
249                 hit_offset++;
250
251                 extra_at_offset = hit_offset;
252
253                 while(hit_offset - offset < size) {
254                         cur_char = tvb_get_guint8(tvb, hit_offset);
255                         if(cur_char == '\0')
256                                 break;
257
258                         hit_offset++;
259                         extra_length++;
260                 }
261
262                 hit_offset++;
263
264                 qhi = proto_tree_add_item(tree,
265                         hf_gnutella_queryhit_hit,
266                         tvb,
267                         idx_at_offset,
268                         (GNUTELLA_LONG_LENGTH * 2) +
269                         name_length + extra_length +
270                         GNUTELLA_QUERYHIT_END_OF_STRING_LENGTH,
271                         FALSE);
272
273                 hit_tree = proto_item_add_subtree(qhi, ett_gnutella);
274
275                 proto_tree_add_item(hit_tree,
276                         hf_gnutella_queryhit_hit_index,
277                         tvb,
278                         idx_at_offset,
279                         GNUTELLA_LONG_LENGTH,
280                         TRUE);
281
282                 proto_tree_add_item(hit_tree,
283                         hf_gnutella_queryhit_hit_size,
284                         tvb,
285                         size_at_offset,
286                         GNUTELLA_LONG_LENGTH,
287                         TRUE);
288
289                 proto_tree_add_item(hit_tree,
290                         hf_gnutella_queryhit_hit_name,
291                         tvb,
292                         name_at_offset,
293                         name_length,
294                         FALSE);
295
296                 if(extra_length) {
297                         proto_tree_add_item(hit_tree,
298                                 hf_gnutella_queryhit_hit_extra,
299                                 tvb,
300                                 extra_at_offset,
301                                 extra_length,
302                                 FALSE);
303                 }
304         }
305
306         used = hit_offset - offset;
307         remaining = size - used;
308
309         if(remaining > GNUTELLA_SERVENT_ID_LENGTH) {
310                 servent_id_at_offset = hit_offset + remaining - GNUTELLA_SERVENT_ID_LENGTH;
311
312                 proto_tree_add_item(tree,
313                         hf_gnutella_queryhit_extra,
314                         tvb,
315                         hit_offset,
316                         servent_id_at_offset - hit_offset,
317                         FALSE);
318         }
319         else {
320                 servent_id_at_offset = hit_offset;
321         }
322
323         proto_tree_add_item(tree,
324                 hf_gnutella_queryhit_servent_id,
325                 tvb,
326                 servent_id_at_offset,
327                 GNUTELLA_SERVENT_ID_LENGTH,
328                 FALSE);
329
330 }
331
332 static void dissect_gnutella_push(tvbuff_t *tvb, guint offset, proto_tree *tree, guint size) {
333
334         if(offset + size > tvb_length(tvb)) {
335                 proto_tree_add_item(tree,
336                         hf_gnutella_truncated,
337                         tvb,
338                         offset,
339                         size,
340                         FALSE);
341                 return;
342         }
343
344         proto_tree_add_item(tree,
345                 hf_gnutella_push_servent_id,
346                 tvb,
347                 offset + GNUTELLA_PUSH_SERVENT_ID_OFFSET,
348                 GNUTELLA_SERVENT_ID_LENGTH,
349                 FALSE);
350
351         proto_tree_add_item(tree,
352                 hf_gnutella_push_index,
353                 tvb,
354                 offset + GNUTELLA_PUSH_INDEX_OFFSET,
355                 GNUTELLA_LONG_LENGTH,
356                 TRUE);
357
358         proto_tree_add_item(tree,
359                 hf_gnutella_push_ip,
360                 tvb,
361                 offset + GNUTELLA_PUSH_IP_OFFSET,
362                 GNUTELLA_IP_LENGTH,
363                 FALSE);
364
365         proto_tree_add_item(tree,
366                 hf_gnutella_push_port,
367                 tvb,
368                 offset + GNUTELLA_PUSH_PORT_OFFSET,
369                 GNUTELLA_PORT_LENGTH,
370                 TRUE);
371
372 }
373
374 static void dissect_gnutella(tvbuff_t *tvb, packet_info *pinfo, proto_tree *tree) {
375
376         proto_item *ti, *hi, *pi;
377         proto_tree *gnutella_tree, *gnutella_header_tree, *gnutella_pong_tree;
378         proto_tree *gnutella_queryhit_tree, *gnutella_push_tree;
379         proto_tree *gnutella_query_tree;
380         int snap_len, payload_descriptor, offset;
381         unsigned int size;
382         char *payload_descriptor_text;
383
384         if (check_col(pinfo->fd, COL_PROTOCOL)) 
385                 col_set_str(pinfo->fd, COL_PROTOCOL, "Gnutella");
386     
387         if (check_col(pinfo->fd, COL_INFO)) 
388                 col_set_str(pinfo->fd, COL_INFO, "Gnutella");
389
390         snap_len = tvb_length(tvb);
391
392         if(snap_len < GNUTELLA_HEADER_LENGTH) {
393                 if (check_col(pinfo->fd, COL_INFO)) 
394                         col_append_fstr(pinfo->fd, COL_INFO,
395                                         ", %i bytes [INCOMPLETE]", snap_len);
396                 return;
397         }
398         else {
399                 if (check_col(pinfo->fd, COL_INFO)) 
400                         col_append_fstr(pinfo->fd, COL_INFO,
401                                         ", %i bytes", snap_len);
402         }
403
404         if (tree) {
405                 ti = proto_tree_add_item(tree,
406                         proto_gnutella,
407                         tvb,
408                         0,
409                         tvb_length(tvb),
410                         FALSE);
411                 gnutella_tree = proto_item_add_subtree(ti, ett_gnutella);
412
413                 offset = 0;
414
415                 size = tvb_get_letohl(
416                         tvb,
417                         offset + GNUTELLA_HEADER_SIZE_OFFSET);
418                 if(size > GNUTELLA_MAX_SNAP_SIZE) {
419                         proto_tree_add_item(gnutella_tree,
420                                 hf_gnutella_stream,
421                                 tvb,
422                                 offset,
423                                 snap_len,
424                                 FALSE);
425                         return;
426                 }
427
428                 while(snap_len - offset >= GNUTELLA_HEADER_LENGTH) {
429                         payload_descriptor = tvb_get_guint8(
430                                 tvb,
431                                 offset +
432                                 GNUTELLA_HEADER_PAYLOAD_OFFSET);
433                         size = tvb_get_letohl(
434                                 tvb,
435                                 offset + GNUTELLA_HEADER_SIZE_OFFSET);
436
437                         switch(payload_descriptor) {
438                                 case GNUTELLA_PING:
439                                         payload_descriptor_text = GNUTELLA_PING_NAME;
440                                         break;
441                                 case GNUTELLA_PONG:
442                                         payload_descriptor_text = GNUTELLA_PONG_NAME;
443                                         break;
444                                 case GNUTELLA_PUSH:
445                                         payload_descriptor_text = GNUTELLA_PUSH_NAME;
446                                         break;
447                                 case GNUTELLA_QUERY:
448                                         payload_descriptor_text = GNUTELLA_QUERY_NAME;
449                                         break;
450                                 case GNUTELLA_QUERYHIT:
451                                         payload_descriptor_text = GNUTELLA_QUERYHIT_NAME;
452                                         break;
453                                 default:
454                                         payload_descriptor_text = GNUTELLA_UNKNOWN_NAME;
455                                         break;
456                         }
457
458                         hi = proto_tree_add_item(gnutella_tree,
459                                 hf_gnutella_header,
460                                 tvb,
461                                 offset,
462                                 GNUTELLA_HEADER_LENGTH,
463                                 FALSE);
464                         gnutella_header_tree = proto_item_add_subtree(hi, ett_gnutella);
465
466                         proto_tree_add_item(gnutella_header_tree,
467                                 hf_gnutella_header_id,
468                                 tvb,
469                                 offset + GNUTELLA_HEADER_ID_OFFSET,
470                                 GNUTELLA_SERVENT_ID_LENGTH,
471                                 FALSE);
472
473                         proto_tree_add_uint_format(gnutella_header_tree,
474                                 hf_gnutella_header_payload,
475                                 tvb,
476                                 offset + GNUTELLA_HEADER_PAYLOAD_OFFSET,
477                                 GNUTELLA_BYTE_LENGTH,
478                                 payload_descriptor,
479                                 "Payload: %i (%s)",
480                                 payload_descriptor,
481                                 payload_descriptor_text);
482
483                         proto_tree_add_item(gnutella_header_tree,
484                                 hf_gnutella_header_ttl,
485                                 tvb,
486                                 offset + GNUTELLA_HEADER_TTL_OFFSET,
487                                 GNUTELLA_BYTE_LENGTH,
488                                 FALSE);
489
490                         proto_tree_add_item(gnutella_header_tree,
491                                 hf_gnutella_header_hops,
492                                 tvb,
493                                 offset + GNUTELLA_HEADER_HOPS_OFFSET,
494                                 GNUTELLA_BYTE_LENGTH,
495                                 FALSE);
496
497                         proto_tree_add_uint(gnutella_header_tree,
498                                 hf_gnutella_header_size,
499                                 tvb,
500                                 offset + GNUTELLA_HEADER_SIZE_OFFSET,
501                                 GNUTELLA_LONG_LENGTH,
502                                 size);
503
504             if (size > 0) {
505
506                 switch(payload_descriptor) {
507                     case GNUTELLA_PONG:
508                         pi = proto_tree_add_item(
509                             gnutella_header_tree,
510                             hf_gnutella_pong_payload,
511                             tvb,
512                             offset + GNUTELLA_HEADER_LENGTH,
513                             size,
514                             FALSE);
515                         gnutella_pong_tree = proto_item_add_subtree(
516                             pi,
517                             ett_gnutella);
518                         dissect_gnutella_pong(
519                             tvb,
520                             offset + GNUTELLA_HEADER_LENGTH,
521                             gnutella_pong_tree,
522                             size);
523                         break;
524                     case GNUTELLA_PUSH:
525                         pi = proto_tree_add_item(
526                             gnutella_header_tree,
527                             hf_gnutella_push_payload,
528                             tvb,
529                             offset + GNUTELLA_HEADER_LENGTH,
530                             size,
531                             FALSE);
532                         gnutella_push_tree = proto_item_add_subtree(
533                             pi,
534                             ett_gnutella);
535                         dissect_gnutella_push(
536                             tvb,
537                             offset + GNUTELLA_HEADER_LENGTH,
538                             gnutella_push_tree,
539                             size);
540                         break;
541                     case GNUTELLA_QUERY:
542                         pi = proto_tree_add_item(
543                             gnutella_header_tree,
544                             hf_gnutella_query_payload,
545                             tvb,
546                             offset + GNUTELLA_HEADER_LENGTH,
547                             size,
548                             FALSE);
549                         gnutella_query_tree = proto_item_add_subtree(
550                             pi,
551                             ett_gnutella);
552                         dissect_gnutella_query(
553                             tvb,
554                             offset + GNUTELLA_HEADER_LENGTH,
555                             gnutella_query_tree,
556                             size);
557                         break;
558                     case GNUTELLA_QUERYHIT:
559                         pi = proto_tree_add_item(
560                             gnutella_header_tree,
561                             hf_gnutella_queryhit_payload,
562                             tvb,
563                             offset + GNUTELLA_HEADER_LENGTH,
564                             size,
565                             FALSE);
566                         gnutella_queryhit_tree = proto_item_add_subtree(
567                             pi,
568                             ett_gnutella);
569                         dissect_gnutella_queryhit(
570                             tvb,
571                             offset + GNUTELLA_HEADER_LENGTH,
572                             gnutella_queryhit_tree,
573                             size);
574                         break;
575                 }
576             }
577
578                         offset = offset + GNUTELLA_HEADER_LENGTH + size;
579                 }
580         }
581
582 }
583
584
585 void proto_register_gnutella(void) {                 
586
587         static hf_register_info hf[] = {
588                 { &hf_gnutella_header,
589                         { "Descriptor Header", "gnutella.header",
590                         FT_NONE, BASE_NONE, NULL, 0,          
591                         "Gnutella Descriptor Header", HFILL }
592                 },
593                 { &hf_gnutella_pong_payload,
594                         { "Pong", "gnutella.pong.payload",
595                         FT_NONE, BASE_NONE, NULL, 0,          
596                         "Gnutella Pong Payload", HFILL }
597                 },
598                 { &hf_gnutella_push_payload,
599                         { "Push", "gnutella.push.payload",
600                         FT_NONE, BASE_NONE, NULL, 0,          
601                         "Gnutella Push Payload", HFILL }
602                 },
603                 { &hf_gnutella_query_payload,
604                         { "Query", "gnutella.query.payload",
605                         FT_NONE, BASE_NONE, NULL, 0,          
606                         "Gnutella Query Payload", HFILL }
607                 },
608                 { &hf_gnutella_queryhit_payload,
609                         { "QueryHit", "gnutella.queryhit.payload",
610                         FT_NONE, BASE_NONE, NULL, 0,          
611                         "Gnutella QueryHit Payload", HFILL }
612                 },
613                 { &hf_gnutella_truncated,
614                         { "Truncated Frame", "gnutella.truncated",
615                         FT_NONE, BASE_NONE, NULL, 0,          
616                         "The Gnutella Frame Was Truncated", HFILL }
617                 },
618                 { &hf_gnutella_stream,
619                         { "Gnutella Upload / Download Stream", "gnutella.stream",
620                         FT_NONE, BASE_NONE, NULL, 0,          
621                         "Gnutella Upload / Download Stream", HFILL }
622                 },
623                 { &hf_gnutella_header_id,
624                         { "ID", "gnutella.header.id",
625                         FT_BYTES, BASE_HEX, NULL, 0,          
626                         "Gnutella Descriptor ID", HFILL }
627                 },
628                 { &hf_gnutella_header_payload,
629                         { "Payload", "gnutella.header.payload",
630                         FT_UINT8, BASE_DEC, NULL, 0,          
631                         "Gnutella Descriptor Payload", HFILL }
632                 },
633                 { &hf_gnutella_header_ttl,
634                         { "TTL", "gnutella.header.ttl",
635                         FT_UINT8, BASE_DEC, NULL, 0,          
636                         "Gnutella Descriptor Time To Live", HFILL }
637                 },
638                 { &hf_gnutella_header_hops,
639                         { "Hops", "gnutella.header.hops",
640                         FT_UINT8, BASE_DEC, NULL, 0,          
641                         "Gnutella Descriptor Hop Count", HFILL }
642                 },
643                 { &hf_gnutella_header_size,
644                         { "Length", "gnutella.header.size",
645                         FT_UINT8, BASE_DEC, NULL, 0,          
646                         "Gnutella Descriptor Payload Length", HFILL }
647                 },
648                 { &hf_gnutella_pong_port,
649                         { "Port", "gnutella.pong.port",
650                         FT_UINT16, BASE_DEC, NULL, 0,          
651                         "Gnutella Pong TCP Port", HFILL }
652                 },
653                 { &hf_gnutella_pong_ip,
654                         { "IP", "gnutella.pong.ip",
655                         FT_IPv4, BASE_DEC, NULL, 0,          
656                         "Gnutella Pong IP Address", HFILL }
657                 },
658                 { &hf_gnutella_pong_files,
659                         { "Files Shared", "gnutella.pong.files",
660                         FT_UINT32, BASE_DEC, NULL, 0,          
661                         "Gnutella Pong Files Shared", HFILL }
662                 },
663                 { &hf_gnutella_pong_kbytes,
664                         { "KBytes Shared", "gnutella.pong.kbytes",
665                         FT_UINT32, BASE_DEC, NULL, 0,          
666                         "Gnutella Pong KBytes Shared", HFILL }
667                 },
668                 { &hf_gnutella_query_min_speed,
669                         { "Min Speed", "gnutella.query.min_speed",
670                         FT_UINT32, BASE_DEC, NULL, 0,          
671                         "Gnutella Query Minimum Speed", HFILL }
672                 },
673                 { &hf_gnutella_query_search,
674                         { "Search", "gnutella.query.search",
675                         FT_STRINGZ, BASE_NONE, NULL, 0,          
676                         "Gnutella Query Search", HFILL }
677                 },
678                 { &hf_gnutella_queryhit_hit,
679                         { "Hit", "gnutella.queryhit.hit",
680                         FT_NONE, BASE_NONE, NULL, 0,          
681                         "Gnutella QueryHit", HFILL }
682                 },
683                 { &hf_gnutella_queryhit_hit_index,
684                         { "Index", "gnutella.queryhit.hit.index",
685                         FT_UINT32, BASE_DEC, NULL, 0,          
686                         "Gnutella QueryHit Index", HFILL }
687                 },
688                 { &hf_gnutella_queryhit_hit_size,
689                         { "Size", "gnutella.queryhit.hit.size",
690                         FT_UINT32, BASE_DEC, NULL, 0,          
691                         "Gnutella QueryHit Size", HFILL }
692                 },
693                 { &hf_gnutella_queryhit_hit_name,
694                         { "Name", "gnutella.queryhit.hit.name",
695                         FT_STRING, BASE_NONE, NULL, 0,          
696                         "Gnutella Query Name", HFILL }
697                 },
698                 { &hf_gnutella_queryhit_hit_extra,
699                         { "Extra", "gnutella.queryhit.hit.extra",
700                         FT_BYTES, BASE_HEX, NULL, 0,          
701                         "Gnutella Query Extra", HFILL }
702                 },
703                 { &hf_gnutella_queryhit_count,
704                         { "Count", "gnutella.queryhit.count",
705                         FT_UINT8, BASE_DEC, NULL, 0,          
706                         "Gnutella QueryHit Count", HFILL }
707                 },
708                 { &hf_gnutella_queryhit_port,
709                         { "Port", "gnutella.queryhit.port",
710                         FT_UINT16, BASE_DEC, NULL, 0,          
711                         "Gnutella QueryHit Port", HFILL }
712                 },
713                 { &hf_gnutella_queryhit_ip,
714                         { "IP", "gnutella.queryhit.ip",
715                         FT_IPv4, BASE_DEC, NULL, 0,          
716                         "Gnutella QueryHit IP Address", HFILL }
717                 },
718                 { &hf_gnutella_queryhit_speed,
719                         { "Speed", "gnutella.queryhit.speed",
720                         FT_UINT32, BASE_DEC, NULL, 0,          
721                         "Gnutella QueryHit Speed", HFILL }
722                 },
723                 { &hf_gnutella_queryhit_extra,
724                         { "Extra", "gnutella.queryhit.extra",
725                         FT_BYTES, BASE_HEX, NULL, 0,          
726                         "Gnutella QueryHit Extra", HFILL }
727                 },
728                 { &hf_gnutella_queryhit_servent_id,
729                         { "Servent ID", "gnutella.queryhit.servent_id",
730                         FT_BYTES, BASE_HEX, NULL, 0,          
731                         "Gnutella QueryHit Servent ID", HFILL }
732                 },
733                 { &hf_gnutella_push_servent_id,
734                         { "Servent ID", "gnutella.push.servent_id",
735                         FT_BYTES, BASE_HEX, NULL, 0,          
736                         "Gnutella Push Servent ID", HFILL }
737                 },
738                 { &hf_gnutella_push_ip,
739                         { "IP", "gnutella.push.ip",
740                         FT_IPv4, BASE_DEC, NULL, 0,          
741                         "Gnutella Push IP Address", HFILL }
742                 },
743                 { &hf_gnutella_push_index,
744                         { "Index", "gnutella.push.index",
745                         FT_UINT32, BASE_DEC, NULL, 0,          
746                         "Gnutella Push Index", HFILL }
747                 },
748                 { &hf_gnutella_push_port,
749                         { "Port", "gnutella.push.port",
750                         FT_UINT16, BASE_DEC, NULL, 0,          
751                         "Gnutella Push Port", HFILL }
752                 },
753         };
754
755         static gint *ett[] = {
756                 &ett_gnutella,
757         };
758
759         proto_gnutella = proto_register_protocol("Gnutella Protocol",
760                                                 "GNUTELLA",
761                                                 "gnutella");
762
763         proto_register_field_array(proto_gnutella, hf, array_length(hf));
764
765         proto_register_subtree_array(ett, array_length(ett));
766 }
767
768 void proto_reg_handoff_gnutella(void) {
769         dissector_add("tcp.port",
770                         GNUTELLA_TCP_PORT,
771                         dissect_gnutella,
772                         proto_gnutella);
773 }