/src/wireshark/epan/dissectors/packet-gnutella.c
Line | Count | Source |
1 | | /* packet-gnutella.c |
2 | | * Routines for gnutella dissection |
3 | | * Copyright 2001, B. Johannessen <bob@havoq.com> |
4 | | * |
5 | | * Wireshark - Network traffic analyzer |
6 | | * By Gerald Combs <gerald@wireshark.org> |
7 | | * Copyright 1998 Gerald Combs |
8 | | * |
9 | | * SPDX-License-Identifier: GPL-2.0-or-later |
10 | | */ |
11 | | |
12 | | #include "config.h" |
13 | | |
14 | | #include <epan/packet.h> |
15 | | #include "packet-tcp.h" |
16 | | |
17 | | void proto_register_gnutella(void); |
18 | | void proto_reg_handoff_gnutella(void); |
19 | | |
20 | | static dissector_handle_t gnutella_handle; |
21 | | |
22 | | /* |
23 | | * See |
24 | | * |
25 | | * http://rfc-gnutella.sourceforge.net/developer/index.html |
26 | | */ |
27 | | |
28 | | static int proto_gnutella; |
29 | | |
30 | | static int hf_gnutella_stream; |
31 | | |
32 | | static int hf_gnutella_header; |
33 | | static int hf_gnutella_header_id; |
34 | | static int hf_gnutella_header_payload; |
35 | | static int hf_gnutella_header_ttl; |
36 | | static int hf_gnutella_header_hops; |
37 | | static int hf_gnutella_header_size; |
38 | | |
39 | | static int hf_gnutella_pong_payload; |
40 | | static int hf_gnutella_pong_port; |
41 | | static int hf_gnutella_pong_ip; |
42 | | static int hf_gnutella_pong_files; |
43 | | static int hf_gnutella_pong_kbytes; |
44 | | |
45 | | static int hf_gnutella_query_payload; |
46 | | static int hf_gnutella_query_min_speed; |
47 | | static int hf_gnutella_query_search; |
48 | | |
49 | | static int hf_gnutella_queryhit_payload; |
50 | | static int hf_gnutella_queryhit_count; |
51 | | static int hf_gnutella_queryhit_port; |
52 | | static int hf_gnutella_queryhit_ip; |
53 | | static int hf_gnutella_queryhit_speed; |
54 | | static int hf_gnutella_queryhit_extra; |
55 | | static int hf_gnutella_queryhit_servent_id; |
56 | | |
57 | | static int hf_gnutella_queryhit_hit; |
58 | | static int hf_gnutella_queryhit_hit_index; |
59 | | static int hf_gnutella_queryhit_hit_size; |
60 | | static int hf_gnutella_queryhit_hit_name; |
61 | | static int hf_gnutella_queryhit_hit_extra; |
62 | | |
63 | | static int hf_gnutella_push_payload; |
64 | | static int hf_gnutella_push_servent_id; |
65 | | static int hf_gnutella_push_index; |
66 | | static int hf_gnutella_push_ip; |
67 | | static int hf_gnutella_push_port; |
68 | | |
69 | | static int ett_gnutella; |
70 | | |
71 | 15 | #define GNUTELLA_TCP_PORT 6346 |
72 | | |
73 | | /* |
74 | | * Used to determine whether a chunk of data looks like a Gnutella packet |
75 | | * or not - it might be a transfer stream, or it might be part of a |
76 | | * Gnutella packet that starts in an earlier missing TCP segment. |
77 | | * |
78 | | * One Gnutella spec says packets SHOULD be no bigger than 4K, although |
79 | | * that's SHOULD, not MUST. |
80 | | */ |
81 | 151 | #define GNUTELLA_MAX_SNAP_SIZE 4096 |
82 | | |
83 | 11 | #define GNUTELLA_UNKNOWN_NAME "Unknown" |
84 | 53 | #define GNUTELLA_PING 0x00 |
85 | 53 | #define GNUTELLA_PING_NAME "Ping" |
86 | 2 | #define GNUTELLA_PONG 0x01 |
87 | 1 | #define GNUTELLA_PONG_NAME "Pong" |
88 | 0 | #define GNUTELLA_PUSH 0x40 |
89 | 0 | #define GNUTELLA_PUSH_NAME "Push" |
90 | 0 | #define GNUTELLA_QUERY 0x80 |
91 | 0 | #define GNUTELLA_QUERY_NAME "Query" |
92 | 46 | #define GNUTELLA_QUERYHIT 0x81 |
93 | 24 | #define GNUTELLA_QUERYHIT_NAME "QueryHit" |
94 | | |
95 | 225 | #define GNUTELLA_HEADER_LENGTH 23 |
96 | 137 | #define GNUTELLA_SERVENT_ID_LENGTH 16 |
97 | 23 | #define GNUTELLA_PORT_LENGTH 2 |
98 | 23 | #define GNUTELLA_IP_LENGTH 4 |
99 | 1.17k | #define GNUTELLA_LONG_LENGTH 4 |
100 | 0 | #define GNUTELLA_SHORT_LENGTH 2 |
101 | 289 | #define GNUTELLA_BYTE_LENGTH 1 |
102 | | |
103 | | #define GNUTELLA_PONG_LENGTH 14 |
104 | 1 | #define GNUTELLA_PONG_PORT_OFFSET 0 |
105 | 1 | #define GNUTELLA_PONG_IP_OFFSET 2 |
106 | 1 | #define GNUTELLA_PONG_FILES_OFFSET 6 |
107 | 1 | #define GNUTELLA_PONG_KBYTES_OFFSET 10 |
108 | | |
109 | 0 | #define GNUTELLA_QUERY_SPEED_OFFSET 0 |
110 | 0 | #define GNUTELLA_QUERY_SEARCH_OFFSET 2 |
111 | | |
112 | | #define GNUTELLA_QUERYHIT_HEADER_LENGTH 11 |
113 | 44 | #define GNUTELLA_QUERYHIT_COUNT_OFFSET 0 |
114 | 22 | #define GNUTELLA_QUERYHIT_PORT_OFFSET 1 |
115 | 22 | #define GNUTELLA_QUERYHIT_IP_OFFSET 3 |
116 | 22 | #define GNUTELLA_QUERYHIT_SPEED_OFFSET 7 |
117 | 22 | #define GNUTELLA_QUERYHIT_FIRST_HIT_OFFSET 11 |
118 | | #define GNUTELLA_QUERYHIT_HIT_INDEX_OFFSET 0 |
119 | 265 | #define GNUTELLA_QUERYHIT_HIT_SIZE_OFFSET 4 |
120 | 265 | #define GNUTELLA_QUERYHIT_END_OF_STRING_LENGTH 2 |
121 | | |
122 | 0 | #define GNUTELLA_PUSH_SERVENT_ID_OFFSET 0 |
123 | 0 | #define GNUTELLA_PUSH_INDEX_OFFSET 16 |
124 | 0 | #define GNUTELLA_PUSH_IP_OFFSET 20 |
125 | 0 | #define GNUTELLA_PUSH_PORT_OFFSET 24 |
126 | | |
127 | 89 | #define GNUTELLA_HEADER_ID_OFFSET 0 |
128 | 178 | #define GNUTELLA_HEADER_PAYLOAD_OFFSET 16 |
129 | 89 | #define GNUTELLA_HEADER_TTL_OFFSET 17 |
130 | 89 | #define GNUTELLA_HEADER_HOPS_OFFSET 18 |
131 | 365 | #define GNUTELLA_HEADER_SIZE_OFFSET 19 |
132 | | |
133 | 1 | static void dissect_gnutella_pong(tvbuff_t *tvb, unsigned offset, proto_tree *tree) { |
134 | | |
135 | 1 | proto_tree_add_item(tree, |
136 | 1 | hf_gnutella_pong_port, |
137 | 1 | tvb, |
138 | 1 | offset + GNUTELLA_PONG_PORT_OFFSET, |
139 | 1 | GNUTELLA_PORT_LENGTH, |
140 | 1 | ENC_LITTLE_ENDIAN); |
141 | | |
142 | 1 | proto_tree_add_item(tree, |
143 | 1 | hf_gnutella_pong_ip, |
144 | 1 | tvb, |
145 | 1 | offset + GNUTELLA_PONG_IP_OFFSET, |
146 | 1 | GNUTELLA_IP_LENGTH, |
147 | 1 | ENC_BIG_ENDIAN); |
148 | | |
149 | 1 | proto_tree_add_item(tree, |
150 | 1 | hf_gnutella_pong_files, |
151 | 1 | tvb, |
152 | 1 | offset + GNUTELLA_PONG_FILES_OFFSET, |
153 | 1 | GNUTELLA_LONG_LENGTH, |
154 | 1 | ENC_LITTLE_ENDIAN); |
155 | | |
156 | 1 | proto_tree_add_item(tree, |
157 | 1 | hf_gnutella_pong_kbytes, |
158 | 1 | tvb, |
159 | 1 | offset + GNUTELLA_PONG_KBYTES_OFFSET, |
160 | 1 | GNUTELLA_LONG_LENGTH, |
161 | 1 | ENC_LITTLE_ENDIAN); |
162 | | |
163 | 1 | } |
164 | | |
165 | 0 | static void dissect_gnutella_query(tvbuff_t *tvb, unsigned offset, proto_tree *tree, unsigned size) { |
166 | |
|
167 | 0 | proto_tree_add_item(tree, |
168 | 0 | hf_gnutella_query_min_speed, |
169 | 0 | tvb, |
170 | 0 | offset + GNUTELLA_QUERY_SPEED_OFFSET, |
171 | 0 | GNUTELLA_SHORT_LENGTH, |
172 | 0 | ENC_LITTLE_ENDIAN); |
173 | |
|
174 | 0 | if (size > GNUTELLA_SHORT_LENGTH) { |
175 | | /* |
176 | | * XXX - the 0.4 spec says, of this field: |
177 | | * |
178 | | * It SHOULD use an ASCII-compatible encoding and |
179 | | * charset. In this version of the protocol, no |
180 | | * encoding was specified, but most servents use |
181 | | * the ISO-8859-1 character set, but other encodings |
182 | | * such as UTF-8 MAY also be used (possibly in |
183 | | * conjunction with Query Data), as well as other |
184 | | * international character sets (ISO-8859-*, KOI-8, |
185 | | * S-JIS, Big5, ...). |
186 | | * |
187 | | * No obvious mechanism is provided to indicate what |
188 | | * encoding is being used; perhaps this should be |
189 | | * made a preference, defaulting to ISO 8859-1. |
190 | | */ |
191 | 0 | proto_tree_add_item(tree, |
192 | 0 | hf_gnutella_query_search, |
193 | 0 | tvb, |
194 | 0 | offset + GNUTELLA_QUERY_SEARCH_OFFSET, |
195 | 0 | size - GNUTELLA_SHORT_LENGTH, |
196 | 0 | ENC_ASCII); |
197 | 0 | } |
198 | 0 | else { |
199 | 0 | proto_tree_add_string_format(tree, |
200 | 0 | hf_gnutella_query_search, tvb, |
201 | 0 | offset + GNUTELLA_QUERY_SEARCH_OFFSET, |
202 | 0 | 0, "", "Missing data for Query Search."); |
203 | 0 | } |
204 | 0 | } |
205 | | |
206 | 22 | static void dissect_gnutella_queryhit(tvbuff_t *tvb, unsigned offset, proto_tree *tree, unsigned size) { |
207 | | |
208 | 22 | proto_tree *qhi, *hit_tree; |
209 | 22 | int hit_count, i; |
210 | 22 | int hit_offset; |
211 | 22 | int name_length, extra_length; |
212 | 22 | int idx_at_offset, size_at_offset; |
213 | 22 | int servent_id_at_offset; |
214 | 22 | int name_at_offset, extra_at_offset; |
215 | 22 | int cur_char, remaining, used; |
216 | | |
217 | 22 | hit_count = tvb_get_uint8(tvb, offset + GNUTELLA_QUERYHIT_COUNT_OFFSET); |
218 | | |
219 | 22 | proto_tree_add_uint(tree, |
220 | 22 | hf_gnutella_queryhit_count, |
221 | 22 | tvb, |
222 | 22 | offset + GNUTELLA_QUERYHIT_COUNT_OFFSET, |
223 | 22 | GNUTELLA_BYTE_LENGTH, |
224 | 22 | hit_count); |
225 | | |
226 | 22 | proto_tree_add_item(tree, |
227 | 22 | hf_gnutella_queryhit_port, |
228 | 22 | tvb, |
229 | 22 | offset + GNUTELLA_QUERYHIT_PORT_OFFSET, |
230 | 22 | GNUTELLA_PORT_LENGTH, |
231 | 22 | ENC_LITTLE_ENDIAN); |
232 | | |
233 | 22 | proto_tree_add_item(tree, |
234 | 22 | hf_gnutella_queryhit_ip, |
235 | 22 | tvb, |
236 | 22 | offset + GNUTELLA_QUERYHIT_IP_OFFSET, |
237 | 22 | GNUTELLA_IP_LENGTH, |
238 | 22 | ENC_BIG_ENDIAN); |
239 | | |
240 | 22 | proto_tree_add_item(tree, |
241 | 22 | hf_gnutella_queryhit_speed, |
242 | 22 | tvb, |
243 | 22 | offset + GNUTELLA_QUERYHIT_SPEED_OFFSET, |
244 | 22 | GNUTELLA_LONG_LENGTH, |
245 | 22 | ENC_LITTLE_ENDIAN); |
246 | | |
247 | 22 | hit_offset = offset + GNUTELLA_QUERYHIT_FIRST_HIT_OFFSET; |
248 | | |
249 | 287 | for(i = 0; i < hit_count; i++) { |
250 | 265 | idx_at_offset = hit_offset; |
251 | 265 | size_at_offset = hit_offset + GNUTELLA_QUERYHIT_HIT_SIZE_OFFSET; |
252 | | |
253 | 265 | hit_offset += (GNUTELLA_LONG_LENGTH * 2); |
254 | | |
255 | 265 | name_length = 0; |
256 | 265 | extra_length = 0; |
257 | | |
258 | 265 | name_at_offset = hit_offset; |
259 | | |
260 | 1.74k | while(hit_offset - offset < size) { |
261 | 1.73k | cur_char = tvb_get_uint8(tvb, hit_offset); |
262 | 1.73k | if(cur_char == '\0') |
263 | 257 | break; |
264 | | |
265 | 1.47k | hit_offset++; |
266 | 1.47k | name_length++; |
267 | 1.47k | } |
268 | | |
269 | 265 | hit_offset++; |
270 | | |
271 | 265 | extra_at_offset = hit_offset; |
272 | | |
273 | 600 | while(hit_offset - offset < size) { |
274 | 583 | cur_char = tvb_get_uint8(tvb, hit_offset); |
275 | 583 | if(cur_char == '\0') |
276 | 248 | break; |
277 | | |
278 | 335 | hit_offset++; |
279 | 335 | extra_length++; |
280 | 335 | } |
281 | | |
282 | 265 | hit_offset++; |
283 | | |
284 | 265 | qhi = proto_tree_add_item(tree, |
285 | 265 | hf_gnutella_queryhit_hit, |
286 | 265 | tvb, |
287 | 265 | idx_at_offset, |
288 | 265 | (GNUTELLA_LONG_LENGTH * 2) + |
289 | 265 | name_length + extra_length + |
290 | 265 | GNUTELLA_QUERYHIT_END_OF_STRING_LENGTH, |
291 | 265 | ENC_NA); |
292 | | |
293 | 265 | hit_tree = proto_item_add_subtree(qhi, ett_gnutella); |
294 | | |
295 | 265 | proto_tree_add_item(hit_tree, |
296 | 265 | hf_gnutella_queryhit_hit_index, |
297 | 265 | tvb, |
298 | 265 | idx_at_offset, |
299 | 265 | GNUTELLA_LONG_LENGTH, |
300 | 265 | ENC_LITTLE_ENDIAN); |
301 | | |
302 | 265 | proto_tree_add_item(hit_tree, |
303 | 265 | hf_gnutella_queryhit_hit_size, |
304 | 265 | tvb, |
305 | 265 | size_at_offset, |
306 | 265 | GNUTELLA_LONG_LENGTH, |
307 | 265 | ENC_LITTLE_ENDIAN); |
308 | | |
309 | 265 | proto_tree_add_item(hit_tree, |
310 | 265 | hf_gnutella_queryhit_hit_name, |
311 | 265 | tvb, |
312 | 265 | name_at_offset, |
313 | 265 | name_length, |
314 | 265 | ENC_ASCII); |
315 | | |
316 | 265 | if(extra_length) { |
317 | 61 | proto_tree_add_item(hit_tree, |
318 | 61 | hf_gnutella_queryhit_hit_extra, |
319 | 61 | tvb, |
320 | 61 | extra_at_offset, |
321 | 61 | extra_length, |
322 | 61 | ENC_NA); |
323 | 61 | } |
324 | 265 | } |
325 | | |
326 | 22 | used = hit_offset - offset; |
327 | 22 | remaining = size - used; |
328 | | |
329 | 22 | if(remaining > GNUTELLA_SERVENT_ID_LENGTH) { |
330 | 4 | servent_id_at_offset = hit_offset + remaining - GNUTELLA_SERVENT_ID_LENGTH; |
331 | | |
332 | 4 | proto_tree_add_item(tree, |
333 | 4 | hf_gnutella_queryhit_extra, |
334 | 4 | tvb, |
335 | 4 | hit_offset, |
336 | 4 | servent_id_at_offset - hit_offset, |
337 | 4 | ENC_NA); |
338 | 4 | } |
339 | 18 | else { |
340 | 18 | servent_id_at_offset = hit_offset; |
341 | 18 | } |
342 | | |
343 | 22 | proto_tree_add_item(tree, |
344 | 22 | hf_gnutella_queryhit_servent_id, |
345 | 22 | tvb, |
346 | 22 | servent_id_at_offset, |
347 | 22 | GNUTELLA_SERVENT_ID_LENGTH, |
348 | 22 | ENC_NA); |
349 | | |
350 | 22 | } |
351 | | |
352 | 0 | static void dissect_gnutella_push(tvbuff_t *tvb, unsigned offset, proto_tree *tree) { |
353 | |
|
354 | 0 | proto_tree_add_item(tree, |
355 | 0 | hf_gnutella_push_servent_id, |
356 | 0 | tvb, |
357 | 0 | offset + GNUTELLA_PUSH_SERVENT_ID_OFFSET, |
358 | 0 | GNUTELLA_SERVENT_ID_LENGTH, |
359 | 0 | ENC_NA); |
360 | |
|
361 | 0 | proto_tree_add_item(tree, |
362 | 0 | hf_gnutella_push_index, |
363 | 0 | tvb, |
364 | 0 | offset + GNUTELLA_PUSH_INDEX_OFFSET, |
365 | 0 | GNUTELLA_LONG_LENGTH, |
366 | 0 | ENC_LITTLE_ENDIAN); |
367 | |
|
368 | 0 | proto_tree_add_item(tree, |
369 | 0 | hf_gnutella_push_ip, |
370 | 0 | tvb, |
371 | 0 | offset + GNUTELLA_PUSH_IP_OFFSET, |
372 | 0 | GNUTELLA_IP_LENGTH, |
373 | 0 | ENC_BIG_ENDIAN); |
374 | |
|
375 | 0 | proto_tree_add_item(tree, |
376 | 0 | hf_gnutella_push_port, |
377 | 0 | tvb, |
378 | 0 | offset + GNUTELLA_PUSH_PORT_OFFSET, |
379 | 0 | GNUTELLA_PORT_LENGTH, |
380 | 0 | ENC_LITTLE_ENDIAN); |
381 | |
|
382 | 0 | } |
383 | | |
384 | | static unsigned |
385 | | get_gnutella_pdu_len(packet_info *pinfo _U_, tvbuff_t *tvb, |
386 | | int offset, void *data _U_) |
387 | 90 | { |
388 | 90 | uint32_t size; |
389 | | |
390 | 90 | size = tvb_get_letohl( |
391 | 90 | tvb, |
392 | 90 | offset + GNUTELLA_HEADER_SIZE_OFFSET); |
393 | 90 | if (size > GNUTELLA_MAX_SNAP_SIZE) { |
394 | | /* |
395 | | * XXX - arbitrary limit, preventing overflows and |
396 | | * attempts to reassemble 4GB of data. |
397 | | */ |
398 | 28 | size = GNUTELLA_MAX_SNAP_SIZE; |
399 | 28 | } |
400 | | |
401 | | /* The size doesn't include the header */ |
402 | 90 | return GNUTELLA_HEADER_LENGTH + size; |
403 | 90 | } |
404 | | |
405 | 89 | static int dissect_gnutella_pdu(tvbuff_t *tvb, packet_info *pinfo, proto_tree *tree, void* data _U_) { |
406 | | |
407 | 89 | proto_item *ti, *hi, *pi; |
408 | 89 | proto_tree *gnutella_tree = NULL; |
409 | 89 | proto_tree *gnutella_header_tree, *gnutella_pong_tree; |
410 | 89 | proto_tree *gnutella_queryhit_tree, *gnutella_push_tree; |
411 | 89 | proto_tree *gnutella_query_tree; |
412 | 89 | uint8_t payload_descriptor; |
413 | 89 | uint32_t size = 0; |
414 | 89 | const char *payload_descriptor_text; |
415 | | |
416 | 89 | if (tree) { |
417 | 89 | ti = proto_tree_add_item(tree, |
418 | 89 | proto_gnutella, |
419 | 89 | tvb, |
420 | 89 | 0, |
421 | 89 | -1, |
422 | 89 | ENC_NA); |
423 | 89 | gnutella_tree = proto_item_add_subtree(ti, ett_gnutella); |
424 | | |
425 | 89 | size = tvb_get_letohl( |
426 | 89 | tvb, |
427 | 89 | GNUTELLA_HEADER_SIZE_OFFSET); |
428 | 89 | } |
429 | | |
430 | 89 | payload_descriptor = tvb_get_uint8( |
431 | 89 | tvb, |
432 | 89 | GNUTELLA_HEADER_PAYLOAD_OFFSET); |
433 | | |
434 | 89 | switch(payload_descriptor) { |
435 | 53 | case GNUTELLA_PING: |
436 | 53 | payload_descriptor_text = GNUTELLA_PING_NAME; |
437 | 53 | break; |
438 | 1 | case GNUTELLA_PONG: |
439 | 1 | payload_descriptor_text = GNUTELLA_PONG_NAME; |
440 | 1 | break; |
441 | 0 | case GNUTELLA_PUSH: |
442 | 0 | payload_descriptor_text = GNUTELLA_PUSH_NAME; |
443 | 0 | break; |
444 | 0 | case GNUTELLA_QUERY: |
445 | 0 | payload_descriptor_text = GNUTELLA_QUERY_NAME; |
446 | 0 | break; |
447 | 24 | case GNUTELLA_QUERYHIT: |
448 | 24 | payload_descriptor_text = GNUTELLA_QUERYHIT_NAME; |
449 | 24 | break; |
450 | 11 | default: |
451 | 11 | payload_descriptor_text = GNUTELLA_UNKNOWN_NAME; |
452 | 11 | break; |
453 | 89 | } |
454 | | |
455 | 89 | col_append_sep_str(pinfo->cinfo, COL_INFO, NULL, |
456 | 89 | payload_descriptor_text); |
457 | | |
458 | 89 | if (tree) { |
459 | 89 | hi = proto_tree_add_item(gnutella_tree, |
460 | 89 | hf_gnutella_header, |
461 | 89 | tvb, |
462 | 89 | 0, |
463 | 89 | GNUTELLA_HEADER_LENGTH, |
464 | 89 | ENC_NA); |
465 | 89 | gnutella_header_tree = proto_item_add_subtree(hi, ett_gnutella); |
466 | | |
467 | 89 | proto_tree_add_item(gnutella_header_tree, |
468 | 89 | hf_gnutella_header_id, |
469 | 89 | tvb, |
470 | 89 | GNUTELLA_HEADER_ID_OFFSET, |
471 | 89 | GNUTELLA_SERVENT_ID_LENGTH, |
472 | 89 | ENC_NA); |
473 | | |
474 | 89 | proto_tree_add_uint_format_value(gnutella_header_tree, |
475 | 89 | hf_gnutella_header_payload, |
476 | 89 | tvb, |
477 | 89 | GNUTELLA_HEADER_PAYLOAD_OFFSET, |
478 | 89 | GNUTELLA_BYTE_LENGTH, |
479 | 89 | payload_descriptor, |
480 | 89 | "%i (%s)", |
481 | 89 | payload_descriptor, |
482 | 89 | payload_descriptor_text); |
483 | | |
484 | 89 | proto_tree_add_item(gnutella_header_tree, |
485 | 89 | hf_gnutella_header_ttl, |
486 | 89 | tvb, |
487 | 89 | GNUTELLA_HEADER_TTL_OFFSET, |
488 | 89 | GNUTELLA_BYTE_LENGTH, |
489 | 89 | ENC_BIG_ENDIAN); |
490 | | |
491 | 89 | proto_tree_add_item(gnutella_header_tree, |
492 | 89 | hf_gnutella_header_hops, |
493 | 89 | tvb, |
494 | 89 | GNUTELLA_HEADER_HOPS_OFFSET, |
495 | 89 | GNUTELLA_BYTE_LENGTH, |
496 | 89 | ENC_BIG_ENDIAN); |
497 | | |
498 | 89 | proto_tree_add_uint(gnutella_header_tree, |
499 | 89 | hf_gnutella_header_size, |
500 | 89 | tvb, |
501 | 89 | GNUTELLA_HEADER_SIZE_OFFSET, |
502 | 89 | GNUTELLA_LONG_LENGTH, |
503 | 89 | size); |
504 | | |
505 | 89 | if (size > 0) { |
506 | 33 | switch(payload_descriptor) { |
507 | 1 | case GNUTELLA_PONG: |
508 | 1 | pi = proto_tree_add_item( |
509 | 1 | gnutella_header_tree, |
510 | 1 | hf_gnutella_pong_payload, |
511 | 1 | tvb, |
512 | 1 | GNUTELLA_HEADER_LENGTH, |
513 | 1 | size, |
514 | 1 | ENC_NA); |
515 | 1 | gnutella_pong_tree = proto_item_add_subtree( |
516 | 1 | pi, |
517 | 1 | ett_gnutella); |
518 | 1 | dissect_gnutella_pong( |
519 | 1 | tvb, |
520 | 1 | GNUTELLA_HEADER_LENGTH, |
521 | 1 | gnutella_pong_tree); |
522 | 1 | break; |
523 | 0 | case GNUTELLA_PUSH: |
524 | 0 | pi = proto_tree_add_item( |
525 | 0 | gnutella_header_tree, |
526 | 0 | hf_gnutella_push_payload, |
527 | 0 | tvb, |
528 | 0 | GNUTELLA_HEADER_LENGTH, |
529 | 0 | size, |
530 | 0 | ENC_NA); |
531 | 0 | gnutella_push_tree = proto_item_add_subtree( |
532 | 0 | pi, |
533 | 0 | ett_gnutella); |
534 | 0 | dissect_gnutella_push( |
535 | 0 | tvb, |
536 | 0 | GNUTELLA_HEADER_LENGTH, |
537 | 0 | gnutella_push_tree); |
538 | 0 | break; |
539 | 0 | case GNUTELLA_QUERY: |
540 | 0 | pi = proto_tree_add_item( |
541 | 0 | gnutella_header_tree, |
542 | 0 | hf_gnutella_query_payload, |
543 | 0 | tvb, |
544 | 0 | GNUTELLA_HEADER_LENGTH, |
545 | 0 | size, |
546 | 0 | ENC_NA); |
547 | 0 | gnutella_query_tree = proto_item_add_subtree( |
548 | 0 | pi, |
549 | 0 | ett_gnutella); |
550 | 0 | dissect_gnutella_query( |
551 | 0 | tvb, |
552 | 0 | GNUTELLA_HEADER_LENGTH, |
553 | 0 | gnutella_query_tree, |
554 | 0 | size); |
555 | 0 | break; |
556 | 22 | case GNUTELLA_QUERYHIT: |
557 | 22 | pi = proto_tree_add_item( |
558 | 22 | gnutella_header_tree, |
559 | 22 | hf_gnutella_queryhit_payload, |
560 | 22 | tvb, |
561 | 22 | GNUTELLA_HEADER_LENGTH, |
562 | 22 | size, |
563 | 22 | ENC_NA); |
564 | 22 | gnutella_queryhit_tree = proto_item_add_subtree( |
565 | 22 | pi, |
566 | 22 | ett_gnutella); |
567 | 22 | dissect_gnutella_queryhit( |
568 | 22 | tvb, |
569 | 22 | GNUTELLA_HEADER_LENGTH, |
570 | 22 | gnutella_queryhit_tree, |
571 | 22 | size); |
572 | 22 | break; |
573 | 33 | } |
574 | 33 | } |
575 | 89 | } |
576 | | |
577 | 69 | return tvb_captured_length(tvb); |
578 | 89 | } |
579 | | |
580 | | |
581 | 33 | static int dissect_gnutella(tvbuff_t *tvb, packet_info *pinfo, proto_tree *tree, void* data) { |
582 | | |
583 | 33 | proto_item *ti; |
584 | 33 | proto_tree *gnutella_tree = NULL; |
585 | 33 | uint32_t size; |
586 | | |
587 | 33 | col_set_str(pinfo->cinfo, COL_PROTOCOL, "Gnutella"); |
588 | | |
589 | 33 | col_clear(pinfo->cinfo, COL_INFO); |
590 | | |
591 | | /* |
592 | | * OK, do we have enough data to determine whether this |
593 | | * is Gnutella messages or just a transfer stream? |
594 | | */ |
595 | 33 | if (tvb_bytes_exist(tvb, GNUTELLA_HEADER_SIZE_OFFSET, 4)) { |
596 | | /* |
597 | | * Yes - fetch the length and see if it's bigger |
598 | | * than GNUTELLA_MAX_SNAP_SIZE; if it is, we assume |
599 | | * it's a transfer stream. |
600 | | * |
601 | | * Should we also check the payload descriptor? |
602 | | */ |
603 | 33 | size = tvb_get_letohl( |
604 | 33 | tvb, |
605 | 33 | GNUTELLA_HEADER_SIZE_OFFSET); |
606 | 33 | if (size > GNUTELLA_MAX_SNAP_SIZE) { |
607 | 2 | if (tree) { |
608 | 2 | ti = proto_tree_add_item(tree, |
609 | 2 | proto_gnutella, |
610 | 2 | tvb, |
611 | 2 | 0, |
612 | 2 | -1, |
613 | 2 | ENC_NA); |
614 | 2 | gnutella_tree = proto_item_add_subtree(ti, |
615 | 2 | ett_gnutella); |
616 | | |
617 | 2 | proto_tree_add_item(gnutella_tree, |
618 | 2 | hf_gnutella_stream, |
619 | 2 | tvb, |
620 | 2 | 0, |
621 | 2 | -1, |
622 | 2 | ENC_NA); |
623 | 2 | } |
624 | 2 | return tvb_captured_length(tvb); |
625 | 2 | } |
626 | 33 | } |
627 | | |
628 | 31 | tcp_dissect_pdus(tvb, pinfo, tree, true, GNUTELLA_HEADER_SIZE_OFFSET+4, |
629 | 31 | get_gnutella_pdu_len, dissect_gnutella_pdu, data); |
630 | 31 | return tvb_captured_length(tvb); |
631 | 33 | } |
632 | | |
633 | 15 | void proto_register_gnutella(void) { |
634 | | |
635 | 15 | static hf_register_info hf[] = { |
636 | 15 | { &hf_gnutella_header, |
637 | 15 | { "Descriptor Header", "gnutella.header", |
638 | 15 | FT_NONE, BASE_NONE, NULL, 0, |
639 | 15 | "Gnutella Descriptor Header", HFILL } |
640 | 15 | }, |
641 | 15 | { &hf_gnutella_pong_payload, |
642 | 15 | { "Pong", "gnutella.pong.payload", |
643 | 15 | FT_NONE, BASE_NONE, NULL, 0, |
644 | 15 | "Gnutella Pong Payload", HFILL } |
645 | 15 | }, |
646 | 15 | { &hf_gnutella_push_payload, |
647 | 15 | { "Push", "gnutella.push.payload", |
648 | 15 | FT_NONE, BASE_NONE, NULL, 0, |
649 | 15 | "Gnutella Push Payload", HFILL } |
650 | 15 | }, |
651 | 15 | { &hf_gnutella_query_payload, |
652 | 15 | { "Query", "gnutella.query.payload", |
653 | 15 | FT_NONE, BASE_NONE, NULL, 0, |
654 | 15 | "Gnutella Query Payload", HFILL } |
655 | 15 | }, |
656 | 15 | { &hf_gnutella_queryhit_payload, |
657 | 15 | { "QueryHit", "gnutella.queryhit.payload", |
658 | 15 | FT_NONE, BASE_NONE, NULL, 0, |
659 | 15 | "Gnutella QueryHit Payload", HFILL } |
660 | 15 | }, |
661 | 15 | { &hf_gnutella_stream, |
662 | 15 | { "Gnutella Upload / Download Stream", "gnutella.stream", |
663 | 15 | FT_NONE, BASE_NONE, NULL, 0, |
664 | 15 | NULL, HFILL } |
665 | 15 | }, |
666 | 15 | { &hf_gnutella_header_id, |
667 | 15 | { "ID", "gnutella.header.id", |
668 | 15 | FT_BYTES, BASE_NONE, NULL, 0, |
669 | 15 | "Gnutella Descriptor ID", HFILL } |
670 | 15 | }, |
671 | 15 | { &hf_gnutella_header_payload, |
672 | 15 | { "Payload", "gnutella.header.payload", |
673 | 15 | FT_UINT8, BASE_DEC, NULL, 0, |
674 | 15 | "Gnutella Descriptor Payload", HFILL } |
675 | 15 | }, |
676 | 15 | { &hf_gnutella_header_ttl, |
677 | 15 | { "TTL", "gnutella.header.ttl", |
678 | 15 | FT_UINT8, BASE_DEC, NULL, 0, |
679 | 15 | "Gnutella Descriptor Time To Live", HFILL } |
680 | 15 | }, |
681 | 15 | { &hf_gnutella_header_hops, |
682 | 15 | { "Hops", "gnutella.header.hops", |
683 | 15 | FT_UINT8, BASE_DEC, NULL, 0, |
684 | 15 | "Gnutella Descriptor Hop Count", HFILL } |
685 | 15 | }, |
686 | 15 | { &hf_gnutella_header_size, |
687 | 15 | { "Length", "gnutella.header.size", |
688 | 15 | FT_UINT8, BASE_DEC, NULL, 0, |
689 | 15 | "Gnutella Descriptor Payload Length", HFILL } |
690 | 15 | }, |
691 | 15 | { &hf_gnutella_pong_port, |
692 | 15 | { "Port", "gnutella.pong.port", |
693 | 15 | FT_UINT16, BASE_PT_TCP, NULL, 0, |
694 | 15 | "Gnutella Pong TCP Port", HFILL } |
695 | 15 | }, |
696 | 15 | { &hf_gnutella_pong_ip, |
697 | 15 | { "IP", "gnutella.pong.ip", |
698 | 15 | FT_IPv4, BASE_NONE, NULL, 0, |
699 | 15 | "Gnutella Pong IP Address", HFILL } |
700 | 15 | }, |
701 | 15 | { &hf_gnutella_pong_files, |
702 | 15 | { "Files Shared", "gnutella.pong.files", |
703 | 15 | FT_UINT32, BASE_DEC, NULL, 0, |
704 | 15 | "Gnutella Pong Files Shared", HFILL } |
705 | 15 | }, |
706 | 15 | { &hf_gnutella_pong_kbytes, |
707 | 15 | { "KBytes Shared", "gnutella.pong.kbytes", |
708 | 15 | FT_UINT32, BASE_DEC, NULL, 0, |
709 | 15 | "Gnutella Pong KBytes Shared", HFILL } |
710 | 15 | }, |
711 | 15 | { &hf_gnutella_query_min_speed, |
712 | 15 | { "Min Speed", "gnutella.query.min_speed", |
713 | 15 | FT_UINT32, BASE_DEC, NULL, 0, |
714 | 15 | "Gnutella Query Minimum Speed", HFILL } |
715 | 15 | }, |
716 | 15 | { &hf_gnutella_query_search, |
717 | 15 | { "Search", "gnutella.query.search", |
718 | 15 | FT_STRINGZ, BASE_NONE, NULL, 0, |
719 | 15 | "Gnutella Query Search", HFILL } |
720 | 15 | }, |
721 | 15 | { &hf_gnutella_queryhit_hit, |
722 | 15 | { "Hit", "gnutella.queryhit.hit", |
723 | 15 | FT_NONE, BASE_NONE, NULL, 0, |
724 | 15 | "Gnutella QueryHit", HFILL } |
725 | 15 | }, |
726 | 15 | { &hf_gnutella_queryhit_hit_index, |
727 | 15 | { "Index", "gnutella.queryhit.hit.index", |
728 | 15 | FT_UINT32, BASE_DEC, NULL, 0, |
729 | 15 | "Gnutella QueryHit Index", HFILL } |
730 | 15 | }, |
731 | 15 | { &hf_gnutella_queryhit_hit_size, |
732 | 15 | { "Size", "gnutella.queryhit.hit.size", |
733 | 15 | FT_UINT32, BASE_DEC, NULL, 0, |
734 | 15 | "Gnutella QueryHit Size", HFILL } |
735 | 15 | }, |
736 | 15 | { &hf_gnutella_queryhit_hit_name, |
737 | 15 | { "Name", "gnutella.queryhit.hit.name", |
738 | 15 | FT_STRING, BASE_NONE, NULL, 0, |
739 | 15 | "Gnutella Query Name", HFILL } |
740 | 15 | }, |
741 | 15 | { &hf_gnutella_queryhit_hit_extra, |
742 | 15 | { "Extra", "gnutella.queryhit.hit.extra", |
743 | 15 | FT_BYTES, BASE_NONE, NULL, 0, |
744 | 15 | "Gnutella Query Extra", HFILL } |
745 | 15 | }, |
746 | 15 | { &hf_gnutella_queryhit_count, |
747 | 15 | { "Count", "gnutella.queryhit.count", |
748 | 15 | FT_UINT8, BASE_DEC, NULL, 0, |
749 | 15 | "Gnutella QueryHit Count", HFILL } |
750 | 15 | }, |
751 | 15 | { &hf_gnutella_queryhit_port, |
752 | 15 | { "Port", "gnutella.queryhit.port", |
753 | 15 | FT_UINT16, BASE_PT_TCP, NULL, 0, |
754 | 15 | "Gnutella QueryHit Port", HFILL } |
755 | 15 | }, |
756 | 15 | { &hf_gnutella_queryhit_ip, |
757 | 15 | { "IP", "gnutella.queryhit.ip", |
758 | 15 | FT_IPv4, BASE_NONE, NULL, 0, |
759 | 15 | "Gnutella QueryHit IP Address", HFILL } |
760 | 15 | }, |
761 | 15 | { &hf_gnutella_queryhit_speed, |
762 | 15 | { "Speed", "gnutella.queryhit.speed", |
763 | 15 | FT_UINT32, BASE_DEC, NULL, 0, |
764 | 15 | "Gnutella QueryHit Speed", HFILL } |
765 | 15 | }, |
766 | 15 | { &hf_gnutella_queryhit_extra, |
767 | 15 | { "Extra", "gnutella.queryhit.extra", |
768 | 15 | FT_BYTES, BASE_NONE, NULL, 0, |
769 | 15 | "Gnutella QueryHit Extra", HFILL } |
770 | 15 | }, |
771 | 15 | { &hf_gnutella_queryhit_servent_id, |
772 | 15 | { "Servent ID", "gnutella.queryhit.servent_id", |
773 | 15 | FT_BYTES, BASE_NONE, NULL, 0, |
774 | 15 | "Gnutella QueryHit Servent ID", HFILL } |
775 | 15 | }, |
776 | 15 | { &hf_gnutella_push_servent_id, |
777 | 15 | { "Servent ID", "gnutella.push.servent_id", |
778 | 15 | FT_BYTES, BASE_NONE, NULL, 0, |
779 | 15 | "Gnutella Push Servent ID", HFILL } |
780 | 15 | }, |
781 | 15 | { &hf_gnutella_push_ip, |
782 | 15 | { "IP", "gnutella.push.ip", |
783 | 15 | FT_IPv4, BASE_NONE, NULL, 0, |
784 | 15 | "Gnutella Push IP Address", HFILL } |
785 | 15 | }, |
786 | 15 | { &hf_gnutella_push_index, |
787 | 15 | { "Index", "gnutella.push.index", |
788 | 15 | FT_UINT32, BASE_DEC, NULL, 0, |
789 | 15 | "Gnutella Push Index", HFILL } |
790 | 15 | }, |
791 | 15 | { &hf_gnutella_push_port, |
792 | 15 | { "Port", "gnutella.push.port", |
793 | 15 | FT_UINT16, BASE_DEC, NULL, 0, |
794 | 15 | "Gnutella Push Port", HFILL } |
795 | 15 | }, |
796 | 15 | }; |
797 | | |
798 | 15 | static int *ett[] = { |
799 | 15 | &ett_gnutella, |
800 | 15 | }; |
801 | | |
802 | 15 | proto_gnutella = proto_register_protocol("Gnutella Protocol", "GNUTELLA", "gnutella"); |
803 | | |
804 | 15 | proto_register_field_array(proto_gnutella, hf, array_length(hf)); |
805 | | |
806 | 15 | proto_register_subtree_array(ett, array_length(ett)); |
807 | | |
808 | 15 | gnutella_handle = register_dissector("gnutella", dissect_gnutella, proto_gnutella); |
809 | 15 | } |
810 | | |
811 | 15 | void proto_reg_handoff_gnutella(void) { |
812 | 15 | dissector_add_uint_with_preference("tcp.port", GNUTELLA_TCP_PORT, gnutella_handle); |
813 | 15 | } |
814 | | |
815 | | /* |
816 | | * Editor modelines - https://www.wireshark.org/tools/modelines.html |
817 | | * |
818 | | * Local variables: |
819 | | * c-basic-offset: 8 |
820 | | * tab-width: 8 |
821 | | * indent-tabs-mode: t |
822 | | * End: |
823 | | * |
824 | | * vi: set shiftwidth=8 tabstop=8 noexpandtab: |
825 | | * :indentSize=8:tabSize=8:noTabs=false: |
826 | | */ |