2 * Routines for gnutella dissection
3 * Copyright 2001, B. Johannessen <bob@havoq.com>
7 * Wireshark - Network traffic analyzer
8 * By Gerald Combs <gerald@wireshark.org>
9 * Copyright 1998 Gerald Combs
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.
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.
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., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA.
30 #include <epan/packet.h>
31 #include "packet-gnutella.h"
32 #include "packet-tcp.h"
37 * http://rfc-gnutella.sourceforge.net/developer/index.html
40 static int proto_gnutella
= -1;
42 static int hf_gnutella_stream
= -1;
44 static int hf_gnutella_header
= -1;
45 static int hf_gnutella_header_id
= -1;
46 static int hf_gnutella_header_payload
= -1;
47 static int hf_gnutella_header_ttl
= -1;
48 static int hf_gnutella_header_hops
= -1;
49 static int hf_gnutella_header_size
= -1;
51 static int hf_gnutella_pong_payload
= -1;
52 static int hf_gnutella_pong_port
= -1;
53 static int hf_gnutella_pong_ip
= -1;
54 static int hf_gnutella_pong_files
= -1;
55 static int hf_gnutella_pong_kbytes
= -1;
57 static int hf_gnutella_query_payload
= -1;
58 static int hf_gnutella_query_min_speed
= -1;
59 static int hf_gnutella_query_search
= -1;
61 static int hf_gnutella_queryhit_payload
= -1;
62 static int hf_gnutella_queryhit_count
= -1;
63 static int hf_gnutella_queryhit_port
= -1;
64 static int hf_gnutella_queryhit_ip
= -1;
65 static int hf_gnutella_queryhit_speed
= -1;
66 static int hf_gnutella_queryhit_extra
= -1;
67 static int hf_gnutella_queryhit_servent_id
= -1;
69 static int hf_gnutella_queryhit_hit
= -1;
70 static int hf_gnutella_queryhit_hit_index
= -1;
71 static int hf_gnutella_queryhit_hit_size
= -1;
72 static int hf_gnutella_queryhit_hit_name
= -1;
73 static int hf_gnutella_queryhit_hit_extra
= -1;
75 static int hf_gnutella_push_payload
= -1;
76 static int hf_gnutella_push_servent_id
= -1;
77 static int hf_gnutella_push_index
= -1;
78 static int hf_gnutella_push_ip
= -1;
79 static int hf_gnutella_push_port
= -1;
81 static gint ett_gnutella
= -1;
83 static void dissect_gnutella_pong(tvbuff_t
*tvb
, guint offset
, proto_tree
*tree
) {
85 proto_tree_add_item(tree
,
86 hf_gnutella_pong_port
,
88 offset
+ GNUTELLA_PONG_PORT_OFFSET
,
92 proto_tree_add_item(tree
,
95 offset
+ GNUTELLA_PONG_IP_OFFSET
,
99 proto_tree_add_item(tree
,
100 hf_gnutella_pong_files
,
102 offset
+ GNUTELLA_PONG_FILES_OFFSET
,
103 GNUTELLA_LONG_LENGTH
,
106 proto_tree_add_item(tree
,
107 hf_gnutella_pong_kbytes
,
109 offset
+ GNUTELLA_PONG_KBYTES_OFFSET
,
110 GNUTELLA_LONG_LENGTH
,
115 static void dissect_gnutella_query(tvbuff_t
*tvb
, guint offset
, proto_tree
*tree
, guint size
) {
117 proto_tree_add_item(tree
,
118 hf_gnutella_query_min_speed
,
120 offset
+ GNUTELLA_QUERY_SPEED_OFFSET
,
121 GNUTELLA_SHORT_LENGTH
,
124 if (size
> GNUTELLA_SHORT_LENGTH
) {
125 proto_tree_add_item(tree
,
126 hf_gnutella_query_search
,
128 offset
+ GNUTELLA_QUERY_SEARCH_OFFSET
,
129 size
- GNUTELLA_SHORT_LENGTH
,
133 proto_tree_add_text(tree
,
135 offset
+ GNUTELLA_QUERY_SEARCH_OFFSET
,
137 "Missing data for Query Search.");
141 static void dissect_gnutella_queryhit(tvbuff_t
*tvb
, guint offset
, proto_tree
*tree
, guint size
) {
143 proto_tree
*qhi
, *hit_tree
;
146 int name_length
, extra_length
;
147 int idx_at_offset
, size_at_offset
;
148 int servent_id_at_offset
;
149 int name_at_offset
, extra_at_offset
;
150 int cur_char
, remaining
, used
;
152 hit_count
= tvb_get_guint8(tvb
, offset
+ GNUTELLA_QUERYHIT_COUNT_OFFSET
);
154 proto_tree_add_uint(tree
,
155 hf_gnutella_queryhit_count
,
157 offset
+ GNUTELLA_QUERYHIT_COUNT_OFFSET
,
158 GNUTELLA_BYTE_LENGTH
,
161 proto_tree_add_item(tree
,
162 hf_gnutella_queryhit_port
,
164 offset
+ GNUTELLA_QUERYHIT_PORT_OFFSET
,
165 GNUTELLA_PORT_LENGTH
,
168 proto_tree_add_item(tree
,
169 hf_gnutella_queryhit_ip
,
171 offset
+ GNUTELLA_QUERYHIT_IP_OFFSET
,
175 proto_tree_add_item(tree
,
176 hf_gnutella_queryhit_speed
,
178 offset
+ GNUTELLA_QUERYHIT_SPEED_OFFSET
,
179 GNUTELLA_LONG_LENGTH
,
182 hit_offset
= offset
+ GNUTELLA_QUERYHIT_FIRST_HIT_OFFSET
;
184 for(i
= 0; i
< hit_count
; i
++) {
185 idx_at_offset
= hit_offset
;
186 size_at_offset
= hit_offset
+ GNUTELLA_QUERYHIT_HIT_SIZE_OFFSET
;
188 hit_offset
+= (GNUTELLA_LONG_LENGTH
* 2);
193 name_at_offset
= hit_offset
;
195 while(hit_offset
- offset
< size
) {
196 cur_char
= tvb_get_guint8(tvb
, hit_offset
);
206 extra_at_offset
= hit_offset
;
208 while(hit_offset
- offset
< size
) {
209 cur_char
= tvb_get_guint8(tvb
, hit_offset
);
219 qhi
= proto_tree_add_item(tree
,
220 hf_gnutella_queryhit_hit
,
223 (GNUTELLA_LONG_LENGTH
* 2) +
224 name_length
+ extra_length
+
225 GNUTELLA_QUERYHIT_END_OF_STRING_LENGTH
,
228 hit_tree
= proto_item_add_subtree(qhi
, ett_gnutella
);
230 proto_tree_add_item(hit_tree
,
231 hf_gnutella_queryhit_hit_index
,
234 GNUTELLA_LONG_LENGTH
,
237 proto_tree_add_item(hit_tree
,
238 hf_gnutella_queryhit_hit_size
,
241 GNUTELLA_LONG_LENGTH
,
244 proto_tree_add_item(hit_tree
,
245 hf_gnutella_queryhit_hit_name
,
252 proto_tree_add_item(hit_tree
,
253 hf_gnutella_queryhit_hit_extra
,
261 used
= hit_offset
- offset
;
262 remaining
= size
- used
;
264 if(remaining
> GNUTELLA_SERVENT_ID_LENGTH
) {
265 servent_id_at_offset
= hit_offset
+ remaining
- GNUTELLA_SERVENT_ID_LENGTH
;
267 proto_tree_add_item(tree
,
268 hf_gnutella_queryhit_extra
,
271 servent_id_at_offset
- hit_offset
,
275 servent_id_at_offset
= hit_offset
;
278 proto_tree_add_item(tree
,
279 hf_gnutella_queryhit_servent_id
,
281 servent_id_at_offset
,
282 GNUTELLA_SERVENT_ID_LENGTH
,
287 static void dissect_gnutella_push(tvbuff_t
*tvb
, guint offset
, proto_tree
*tree
) {
289 proto_tree_add_item(tree
,
290 hf_gnutella_push_servent_id
,
292 offset
+ GNUTELLA_PUSH_SERVENT_ID_OFFSET
,
293 GNUTELLA_SERVENT_ID_LENGTH
,
296 proto_tree_add_item(tree
,
297 hf_gnutella_push_index
,
299 offset
+ GNUTELLA_PUSH_INDEX_OFFSET
,
300 GNUTELLA_LONG_LENGTH
,
303 proto_tree_add_item(tree
,
306 offset
+ GNUTELLA_PUSH_IP_OFFSET
,
310 proto_tree_add_item(tree
,
311 hf_gnutella_push_port
,
313 offset
+ GNUTELLA_PUSH_PORT_OFFSET
,
314 GNUTELLA_PORT_LENGTH
,
320 get_gnutella_pdu_len(packet_info
*pinfo _U_
, tvbuff_t
*tvb
, int offset
) {
323 size
= tvb_get_letohl(
325 offset
+ GNUTELLA_HEADER_SIZE_OFFSET
);
326 if (size
> GNUTELLA_MAX_SNAP_SIZE
) {
328 * XXX - arbitrary limit, preventing overflows and
329 * attempts to reassemble 4GB of data.
331 size
= GNUTELLA_MAX_SNAP_SIZE
;
334 /* The size doesn't include the header */
335 return GNUTELLA_HEADER_LENGTH
+ size
;
338 static int dissect_gnutella_pdu(tvbuff_t
*tvb
, packet_info
*pinfo
, proto_tree
*tree
, void* data _U_
) {
340 proto_item
*ti
, *hi
, *pi
;
341 proto_tree
*gnutella_tree
= NULL
;
342 proto_tree
*gnutella_header_tree
, *gnutella_pong_tree
;
343 proto_tree
*gnutella_queryhit_tree
, *gnutella_push_tree
;
344 proto_tree
*gnutella_query_tree
;
345 guint8 payload_descriptor
;
347 const char *payload_descriptor_text
;
350 ti
= proto_tree_add_item(tree
,
356 gnutella_tree
= proto_item_add_subtree(ti
, ett_gnutella
);
358 size
= tvb_get_letohl(
360 GNUTELLA_HEADER_SIZE_OFFSET
);
363 payload_descriptor
= tvb_get_guint8(
365 GNUTELLA_HEADER_PAYLOAD_OFFSET
);
367 switch(payload_descriptor
) {
369 payload_descriptor_text
= GNUTELLA_PING_NAME
;
372 payload_descriptor_text
= GNUTELLA_PONG_NAME
;
375 payload_descriptor_text
= GNUTELLA_PUSH_NAME
;
378 payload_descriptor_text
= GNUTELLA_QUERY_NAME
;
380 case GNUTELLA_QUERYHIT
:
381 payload_descriptor_text
= GNUTELLA_QUERYHIT_NAME
;
384 payload_descriptor_text
= GNUTELLA_UNKNOWN_NAME
;
388 col_append_sep_fstr(pinfo
->cinfo
, COL_INFO
, NULL
, "%s",
389 payload_descriptor_text
);
392 hi
= proto_tree_add_item(gnutella_tree
,
396 GNUTELLA_HEADER_LENGTH
,
398 gnutella_header_tree
= proto_item_add_subtree(hi
, ett_gnutella
);
400 proto_tree_add_item(gnutella_header_tree
,
401 hf_gnutella_header_id
,
403 GNUTELLA_HEADER_ID_OFFSET
,
404 GNUTELLA_SERVENT_ID_LENGTH
,
407 proto_tree_add_uint_format_value(gnutella_header_tree
,
408 hf_gnutella_header_payload
,
410 GNUTELLA_HEADER_PAYLOAD_OFFSET
,
411 GNUTELLA_BYTE_LENGTH
,
415 payload_descriptor_text
);
417 proto_tree_add_item(gnutella_header_tree
,
418 hf_gnutella_header_ttl
,
420 GNUTELLA_HEADER_TTL_OFFSET
,
421 GNUTELLA_BYTE_LENGTH
,
424 proto_tree_add_item(gnutella_header_tree
,
425 hf_gnutella_header_hops
,
427 GNUTELLA_HEADER_HOPS_OFFSET
,
428 GNUTELLA_BYTE_LENGTH
,
431 proto_tree_add_uint(gnutella_header_tree
,
432 hf_gnutella_header_size
,
434 GNUTELLA_HEADER_SIZE_OFFSET
,
435 GNUTELLA_LONG_LENGTH
,
439 switch(payload_descriptor
) {
441 pi
= proto_tree_add_item(
442 gnutella_header_tree
,
443 hf_gnutella_pong_payload
,
445 GNUTELLA_HEADER_LENGTH
,
448 gnutella_pong_tree
= proto_item_add_subtree(
451 dissect_gnutella_pong(
453 GNUTELLA_HEADER_LENGTH
,
457 pi
= proto_tree_add_item(
458 gnutella_header_tree
,
459 hf_gnutella_push_payload
,
461 GNUTELLA_HEADER_LENGTH
,
464 gnutella_push_tree
= proto_item_add_subtree(
467 dissect_gnutella_push(
469 GNUTELLA_HEADER_LENGTH
,
473 pi
= proto_tree_add_item(
474 gnutella_header_tree
,
475 hf_gnutella_query_payload
,
477 GNUTELLA_HEADER_LENGTH
,
480 gnutella_query_tree
= proto_item_add_subtree(
483 dissect_gnutella_query(
485 GNUTELLA_HEADER_LENGTH
,
489 case GNUTELLA_QUERYHIT
:
490 pi
= proto_tree_add_item(
491 gnutella_header_tree
,
492 hf_gnutella_queryhit_payload
,
494 GNUTELLA_HEADER_LENGTH
,
497 gnutella_queryhit_tree
= proto_item_add_subtree(
500 dissect_gnutella_queryhit(
502 GNUTELLA_HEADER_LENGTH
,
503 gnutella_queryhit_tree
,
510 return tvb_length(tvb
);
514 static int dissect_gnutella(tvbuff_t
*tvb
, packet_info
*pinfo
, proto_tree
*tree
, void* data
) {
517 proto_tree
*gnutella_tree
= NULL
;
520 col_set_str(pinfo
->cinfo
, COL_PROTOCOL
, "Gnutella");
522 col_clear(pinfo
->cinfo
, COL_INFO
);
525 * OK, do we have enough data to determine whether this
526 * is Gnutella messages or just a transfer stream?
528 if (tvb_bytes_exist(tvb
, GNUTELLA_HEADER_SIZE_OFFSET
, 4)) {
530 * Yes - fetch the length and see if it's bigger
531 * than GNUTELLA_MAX_SNAP_SIZE; if it is, we assume
532 * it's a transfer stream.
534 * Should we also check the payload descriptor?
536 size
= tvb_get_letohl(
538 GNUTELLA_HEADER_SIZE_OFFSET
);
539 if (size
> GNUTELLA_MAX_SNAP_SIZE
) {
541 ti
= proto_tree_add_item(tree
,
547 gnutella_tree
= proto_item_add_subtree(ti
,
550 proto_tree_add_item(gnutella_tree
,
557 return tvb_length(tvb
);
561 tcp_dissect_pdus(tvb
, pinfo
, tree
, TRUE
, GNUTELLA_HEADER_SIZE_OFFSET
+4,
562 get_gnutella_pdu_len
, dissect_gnutella_pdu
, data
);
563 return tvb_length(tvb
);
566 void proto_register_gnutella(void) {
568 static hf_register_info hf
[] = {
569 { &hf_gnutella_header
,
570 { "Descriptor Header", "gnutella.header",
571 FT_NONE
, BASE_NONE
, NULL
, 0,
572 "Gnutella Descriptor Header", HFILL
}
574 { &hf_gnutella_pong_payload
,
575 { "Pong", "gnutella.pong.payload",
576 FT_NONE
, BASE_NONE
, NULL
, 0,
577 "Gnutella Pong Payload", HFILL
}
579 { &hf_gnutella_push_payload
,
580 { "Push", "gnutella.push.payload",
581 FT_NONE
, BASE_NONE
, NULL
, 0,
582 "Gnutella Push Payload", HFILL
}
584 { &hf_gnutella_query_payload
,
585 { "Query", "gnutella.query.payload",
586 FT_NONE
, BASE_NONE
, NULL
, 0,
587 "Gnutella Query Payload", HFILL
}
589 { &hf_gnutella_queryhit_payload
,
590 { "QueryHit", "gnutella.queryhit.payload",
591 FT_NONE
, BASE_NONE
, NULL
, 0,
592 "Gnutella QueryHit Payload", HFILL
}
594 { &hf_gnutella_stream
,
595 { "Gnutella Upload / Download Stream", "gnutella.stream",
596 FT_NONE
, BASE_NONE
, NULL
, 0,
599 { &hf_gnutella_header_id
,
600 { "ID", "gnutella.header.id",
601 FT_BYTES
, BASE_NONE
, NULL
, 0,
602 "Gnutella Descriptor ID", HFILL
}
604 { &hf_gnutella_header_payload
,
605 { "Payload", "gnutella.header.payload",
606 FT_UINT8
, BASE_DEC
, NULL
, 0,
607 "Gnutella Descriptor Payload", HFILL
}
609 { &hf_gnutella_header_ttl
,
610 { "TTL", "gnutella.header.ttl",
611 FT_UINT8
, BASE_DEC
, NULL
, 0,
612 "Gnutella Descriptor Time To Live", HFILL
}
614 { &hf_gnutella_header_hops
,
615 { "Hops", "gnutella.header.hops",
616 FT_UINT8
, BASE_DEC
, NULL
, 0,
617 "Gnutella Descriptor Hop Count", HFILL
}
619 { &hf_gnutella_header_size
,
620 { "Length", "gnutella.header.size",
621 FT_UINT8
, BASE_DEC
, NULL
, 0,
622 "Gnutella Descriptor Payload Length", HFILL
}
624 { &hf_gnutella_pong_port
,
625 { "Port", "gnutella.pong.port",
626 FT_UINT16
, BASE_DEC
, NULL
, 0,
627 "Gnutella Pong TCP Port", HFILL
}
629 { &hf_gnutella_pong_ip
,
630 { "IP", "gnutella.pong.ip",
631 FT_IPv4
, BASE_NONE
, NULL
, 0,
632 "Gnutella Pong IP Address", HFILL
}
634 { &hf_gnutella_pong_files
,
635 { "Files Shared", "gnutella.pong.files",
636 FT_UINT32
, BASE_DEC
, NULL
, 0,
637 "Gnutella Pong Files Shared", HFILL
}
639 { &hf_gnutella_pong_kbytes
,
640 { "KBytes Shared", "gnutella.pong.kbytes",
641 FT_UINT32
, BASE_DEC
, NULL
, 0,
642 "Gnutella Pong KBytes Shared", HFILL
}
644 { &hf_gnutella_query_min_speed
,
645 { "Min Speed", "gnutella.query.min_speed",
646 FT_UINT32
, BASE_DEC
, NULL
, 0,
647 "Gnutella Query Minimum Speed", HFILL
}
649 { &hf_gnutella_query_search
,
650 { "Search", "gnutella.query.search",
651 FT_STRINGZ
, BASE_NONE
, NULL
, 0,
652 "Gnutella Query Search", HFILL
}
654 { &hf_gnutella_queryhit_hit
,
655 { "Hit", "gnutella.queryhit.hit",
656 FT_NONE
, BASE_NONE
, NULL
, 0,
657 "Gnutella QueryHit", HFILL
}
659 { &hf_gnutella_queryhit_hit_index
,
660 { "Index", "gnutella.queryhit.hit.index",
661 FT_UINT32
, BASE_DEC
, NULL
, 0,
662 "Gnutella QueryHit Index", HFILL
}
664 { &hf_gnutella_queryhit_hit_size
,
665 { "Size", "gnutella.queryhit.hit.size",
666 FT_UINT32
, BASE_DEC
, NULL
, 0,
667 "Gnutella QueryHit Size", HFILL
}
669 { &hf_gnutella_queryhit_hit_name
,
670 { "Name", "gnutella.queryhit.hit.name",
671 FT_STRING
, BASE_NONE
, NULL
, 0,
672 "Gnutella Query Name", HFILL
}
674 { &hf_gnutella_queryhit_hit_extra
,
675 { "Extra", "gnutella.queryhit.hit.extra",
676 FT_BYTES
, BASE_NONE
, NULL
, 0,
677 "Gnutella Query Extra", HFILL
}
679 { &hf_gnutella_queryhit_count
,
680 { "Count", "gnutella.queryhit.count",
681 FT_UINT8
, BASE_DEC
, NULL
, 0,
682 "Gnutella QueryHit Count", HFILL
}
684 { &hf_gnutella_queryhit_port
,
685 { "Port", "gnutella.queryhit.port",
686 FT_UINT16
, BASE_DEC
, NULL
, 0,
687 "Gnutella QueryHit Port", HFILL
}
689 { &hf_gnutella_queryhit_ip
,
690 { "IP", "gnutella.queryhit.ip",
691 FT_IPv4
, BASE_NONE
, NULL
, 0,
692 "Gnutella QueryHit IP Address", HFILL
}
694 { &hf_gnutella_queryhit_speed
,
695 { "Speed", "gnutella.queryhit.speed",
696 FT_UINT32
, BASE_DEC
, NULL
, 0,
697 "Gnutella QueryHit Speed", HFILL
}
699 { &hf_gnutella_queryhit_extra
,
700 { "Extra", "gnutella.queryhit.extra",
701 FT_BYTES
, BASE_NONE
, NULL
, 0,
702 "Gnutella QueryHit Extra", HFILL
}
704 { &hf_gnutella_queryhit_servent_id
,
705 { "Servent ID", "gnutella.queryhit.servent_id",
706 FT_BYTES
, BASE_NONE
, NULL
, 0,
707 "Gnutella QueryHit Servent ID", HFILL
}
709 { &hf_gnutella_push_servent_id
,
710 { "Servent ID", "gnutella.push.servent_id",
711 FT_BYTES
, BASE_NONE
, NULL
, 0,
712 "Gnutella Push Servent ID", HFILL
}
714 { &hf_gnutella_push_ip
,
715 { "IP", "gnutella.push.ip",
716 FT_IPv4
, BASE_NONE
, NULL
, 0,
717 "Gnutella Push IP Address", HFILL
}
719 { &hf_gnutella_push_index
,
720 { "Index", "gnutella.push.index",
721 FT_UINT32
, BASE_DEC
, NULL
, 0,
722 "Gnutella Push Index", HFILL
}
724 { &hf_gnutella_push_port
,
725 { "Port", "gnutella.push.port",
726 FT_UINT16
, BASE_DEC
, NULL
, 0,
727 "Gnutella Push Port", HFILL
}
731 static gint
*ett
[] = {
735 proto_gnutella
= proto_register_protocol("Gnutella Protocol",
739 proto_register_field_array(proto_gnutella
, hf
, array_length(hf
));
741 proto_register_subtree_array(ett
, array_length(ett
));
744 void proto_reg_handoff_gnutella(void) {
745 dissector_handle_t gnutella_handle
;
747 gnutella_handle
= new_create_dissector_handle(dissect_gnutella
,
749 dissector_add_uint("tcp.port", GNUTELLA_TCP_PORT
, gnutella_handle
);