Coverage Report

Created: 2026-07-12 07:10

next uncovered line (L), next uncovered region (R), next uncovered branch (B)
/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
 */