Coverage Report

Created: 2026-06-16 07:08

next uncovered line (L), next uncovered region (R), next uncovered branch (B)
/src/ndpi/src/lib/protocols/bittorrent.c
Line
Count
Source
1
/*
2
 * bittorrent.c
3
 *
4
 * Copyright (C) 2009-11 - ipoque GmbH
5
 * Copyright (C) 2011-26 - ntop.org
6
 *
7
 * This file is part of nDPI, an open source deep packet inspection
8
 * library based on the OpenDPI and PACE technology by ipoque GmbH
9
 *
10
 * nDPI is free software: you can redistribute it and/or modify
11
 * it under the terms of the GNU Lesser General Public License as published by
12
 * the Free Software Foundation, either version 3 of the License, or
13
 * (at your option) any later version.
14
 *
15
 * nDPI is distributed in the hope that it will be useful,
16
 * but WITHOUT ANY WARRANTY; without even the implied warranty of
17
 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
18
 * GNU Lesser General Public License for more details.
19
 *
20
 * You should have received a copy of the GNU Lesser General Public License
21
 * along with nDPI.  If not, see <http://www.gnu.org/licenses/>.
22
 *
23
 */
24
25
26
#include "ndpi_protocol_ids.h"
27
28
#define NDPI_CURRENT_PROTO NDPI_PROTOCOL_BITTORRENT
29
30
#include "ndpi_api.h"
31
#include "ndpi_private.h"
32
33
2.54M
#define BITTORRENT_PROTO_STRING          "BitTorrent protocol"
34
35
// #define BITTORRENT_CACHE_DEBUG 1
36
37
PACK_ON
38
struct ndpi_utp_hdr {
39
#if defined(__BIG_ENDIAN__)
40
  u_int8_t h_type:4, h_version:4;
41
#elif defined(__LITTLE_ENDIAN__)
42
  u_int8_t h_version:4, h_type:4;
43
#else
44
#error "Missing endian macro definitions."
45
#endif
46
  u_int8_t next_extension;
47
  u_int16_t connection_id;
48
  u_int32_t ts_usec, tdiff_usec, window_size;
49
  u_int16_t sequence_nr, ack_nr;
50
} PACK_OFF;
51
52
53
/* Forward declaration */
54
static void ndpi_search_bittorrent(struct ndpi_detection_module_struct *ndpi_struct,
55
           struct ndpi_flow_struct *flow);
56
static void ndpi_search_bittorrent_hash(struct ndpi_detection_module_struct *ndpi_struct,
57
          struct ndpi_flow_struct *flow, int bt_offset);
58
59
/* *********************************************** */
60
61
static int search_bittorrent_again(struct ndpi_detection_module_struct *ndpi_struct,
62
90.5k
           struct ndpi_flow_struct *flow) {
63
90.5k
  ndpi_search_bittorrent_hash(ndpi_struct, flow, -1);
64
  
65
  /* Possibly more processing */
66
90.5k
  return flow->extra_packets_func != NULL;
67
90.5k
}
68
69
/* *********************************************** */
70
71
static int get_utpv1_length(const u_int8_t *payload, u_int payload_len)
72
1.11M
{
73
1.11M
  struct ndpi_utp_hdr *h = (struct ndpi_utp_hdr*)payload;
74
1.11M
  unsigned int off, num_ext = 0;
75
1.11M
  u_int8_t ext_type = h->next_extension;
76
77
1.11M
  off = sizeof(struct ndpi_utp_hdr);
78
1.41M
  while(ext_type != 0 && off + 1 < payload_len) {
79
937k
    ext_type = payload[off];
80
937k
    if(ext_type > 2)
81
632k
      return -1;
82
    /* BEP-29 doesn't have any limits on the number of extensions
83
       but putting an hard limit makes sense (there are only 3 ext types) */
84
304k
    if(++num_ext > 4)
85
969
      return -1;
86
303k
    off += 2 + payload[off + 1];
87
303k
  }
88
478k
  if(ext_type == 0)
89
459k
    return off;
90
19.2k
  return -1;
91
478k
}
92
93
/* *********************************************** */
94
95
1.11M
static u_int8_t is_utpv1_pkt(const u_int8_t *payload, u_int payload_len) {
96
1.11M
  struct ndpi_utp_hdr *h = (struct ndpi_utp_hdr*)payload;
97
1.11M
  int h_length;
98
99
1.11M
  if(payload_len < sizeof(struct ndpi_utp_hdr)) return(0);
100
1.11M
  h_length = get_utpv1_length(payload, payload_len);
101
1.11M
  if(h_length == -1)                return(0);
102
459k
  if(h->h_version != 1)             return(0);
103
35.7k
  if(h->h_type > 4)                 return(0);
104
25.5k
  if(h->next_extension > 2)         return(0);
105
16.9k
  if(h->h_type == 4 /* SYN */ && (h->tdiff_usec != 0 ||
106
1.21k
     payload_len != (u_int)h_length)) return(0);
107
15.7k
  if(h->h_type == 2 /* STATE */ &&
108
1.33k
     payload_len != (u_int)h_length) return(0);
109
14.8k
  if(h->h_type == 0 /* DATA */ &&
110
13.3k
     payload_len == (u_int)h_length) return(0);
111
14.2k
  if(h->connection_id == 0) return(0);
112
9.58k
  if(h->ts_usec == 0) return(0);
113
114
8.94k
  if((h->window_size == 0) && (payload_len != (u_int)h_length))
115
940
    return(0);
116
117
8.00k
  if(h->h_type == 0)
118
7.39k
    return (2); /* DATA */
119
603
  return(1);
120
8.00k
}
121
122
/* *********************************************** */
123
124
static void ndpi_search_bittorrent_hash(struct ndpi_detection_module_struct *ndpi_struct,
125
99.2k
          struct ndpi_flow_struct *flow, int bt_offset) {
126
99.2k
  const char *bt_hash = NULL; /* 20 bytes long */
127
99.2k
  struct ndpi_packet_struct *packet = &ndpi_struct->packet;
128
  
129
99.2k
  if(bt_offset == -1) {
130
96.6k
    const char *bt_magic = ndpi_strnstr((const char *)packet->payload,
131
96.6k
          BITTORRENT_PROTO_STRING, packet->payload_packet_len);
132
    
133
96.6k
    if(bt_magic) {
134
685
      if(bt_magic == (const char*)&packet->payload[1])
135
304
  bt_hash = (const char*)&packet->payload[28];
136
381
      else
137
381
  bt_hash = &bt_magic[19];
138
685
    }
139
96.6k
  } else
140
2.59k
    bt_hash = (const char*)&packet->payload[28];
141
  
142
99.2k
  if(bt_hash && (packet->payload_packet_len >= (20 + (bt_hash-(const char*)packet->payload))))
143
2.81k
    memcpy(flow->protos.bittorrent.hash, bt_hash, 20);
144
99.2k
}
145
146
/* *********************************************** */
147
148
9.48M
u_int64_t make_bittorrent_host_key(struct ndpi_flow_struct *flow, int client, int offset) {
149
9.48M
  u_int64_t key;
150
151
  /* network byte order */
152
9.48M
  if(flow->is_ipv6) {
153
276k
    if(client)
154
141k
      key = (ndpi_quick_hash64((const char *)flow->c_address.v6, 16) << 16) | htons(ntohs(flow->c_port) + offset);
155
134k
    else
156
134k
      key = (ndpi_quick_hash64((const char *)flow->s_address.v6, 16) << 16) | flow->s_port;
157
9.20M
  } else {
158
9.20M
    if(client)
159
4.68M
      key = ((u_int64_t)flow->c_address.v4 << 32) | htons(ntohs(flow->c_port) + offset);
160
4.51M
    else
161
4.51M
      key = ((u_int64_t)flow->s_address.v4 << 32) | flow->s_port;
162
9.20M
  }
163
164
9.48M
  return key;
165
9.48M
}
166
167
/* *********************************************** */
168
169
4.65M
u_int64_t make_bittorrent_peers_key(struct ndpi_flow_struct *flow) {
170
4.65M
  u_int64_t key;
171
172
  /* network byte order */
173
4.65M
  if(flow->is_ipv6)
174
134k
    key = (ndpi_quick_hash64((const char *)flow->c_address.v6, 16) << 32) | (ndpi_quick_hash64((const char *)flow->s_address.v6, 16) & 0xFFFFFFFF);
175
4.51M
  else
176
4.51M
    key = ((u_int64_t)flow->c_address.v4 << 32) | flow->s_address.v4;
177
178
4.65M
  return key;
179
4.65M
}
180
181
/* *********************************************** */
182
183
static void ndpi_add_connection_as_bittorrent(struct ndpi_detection_module_struct *ndpi_struct,
184
                struct ndpi_flow_struct *flow,
185
                int bt_offset, int check_hash,
186
87.2k
                ndpi_confidence_t confidence) {
187
87.2k
  if(ndpi_struct->cfg.bittorrent_hash_enabled &&
188
77.1k
     check_hash)
189
8.72k
    ndpi_search_bittorrent_hash(ndpi_struct, flow, bt_offset);
190
191
87.2k
  ndpi_set_detected_protocol_keeping_master(ndpi_struct, flow, NDPI_PROTOCOL_BITTORRENT,
192
87.2k
              confidence);
193
  
194
87.2k
  if(ndpi_struct->cfg.bittorrent_hash_enabled &&
195
77.1k
     flow->protos.bittorrent.hash[0] == '\0') {
196
    /* Don't use just 1 as in TCP DNS more packets could be returned (e.g. ACK). */
197
74.6k
    flow->max_extra_packets_to_check = 3;
198
74.6k
    flow->extra_packets_func = search_bittorrent_again;
199
74.6k
  }
200
  
201
87.2k
  if(ndpi_struct->bittorrent_cache) {
202
86.9k
    u_int64_t key, key1, key2, i;
203
204
86.9k
    key = make_bittorrent_peers_key(flow);
205
86.9k
    key1 = make_bittorrent_host_key(flow, 1, 0), key2 = make_bittorrent_host_key(flow, 0, 0);
206
207
86.9k
    ndpi_lru_add_to_cache(ndpi_struct->bittorrent_cache, key1, NDPI_PROTOCOL_BITTORRENT, ndpi_get_current_time(flow));
208
86.9k
    ndpi_lru_add_to_cache(ndpi_struct->bittorrent_cache, key2, NDPI_PROTOCOL_BITTORRENT, ndpi_get_current_time(flow));
209
210
    /* Now add hosts as twins */
211
86.9k
    ndpi_lru_add_to_cache(ndpi_struct->bittorrent_cache,
212
86.9k
        key,
213
86.9k
        NDPI_PROTOCOL_BITTORRENT,
214
86.9k
        ndpi_get_current_time(flow));
215
216
    /* Also add +2 ports of the sender in order to catch additional sockets open by the same client */
217
260k
    for(i=0; i<2; i++) {
218
173k
      key1 = make_bittorrent_host_key(flow, 1, 1 + i);
219
220
173k
      ndpi_lru_add_to_cache(ndpi_struct->bittorrent_cache, key1, NDPI_PROTOCOL_BITTORRENT, ndpi_get_current_time(flow));
221
173k
    }
222
    
223
#ifdef BITTORRENT_CACHE_DEBUG
224
    printf("[BitTorrent] [%s] *** ADDED ports %u / %u [0x%llx][0x%llx]\n",
225
     flow->l4_proto == IPPROTO_TCP ? "TCP" : "UDP",
226
     ntohs(flow->c_port), ntohs(flow->s_port),
227
     (long long unsigned int)key1, (long long unsigned int)key2);
228
#endif
229
86.9k
  }
230
87.2k
}
231
232
/* ************************************* */
233
234
static u_int8_t ndpi_int_search_bittorrent_tcp_zero(struct ndpi_detection_module_struct
235
                *ndpi_struct, struct ndpi_flow_struct *flow)
236
5.91M
{
237
5.91M
  struct ndpi_packet_struct *packet = &ndpi_struct->packet;
238
5.91M
  u_int16_t a = 0;
239
240
5.91M
  if(packet->payload_packet_len == 1 && packet->payload[0] == 0x13) {
241
1.38k
    return 0;
242
1.38k
  }
243
244
5.90M
  if(flow->packet_counter == 2 && packet->payload_packet_len > 20) {
245
551k
    if(memcmp(&packet->payload[0], BITTORRENT_PROTO_STRING, 19) == 0) {
246
84
      NDPI_LOG_INFO(ndpi_struct, "found BT: plain\n");
247
84
      ndpi_add_connection_as_bittorrent(ndpi_struct, flow, 19, 1, NDPI_CONFIDENCE_DPI);
248
84
      return 1;
249
84
    }
250
551k
  }
251
252
5.90M
  if(packet->payload_packet_len > 20) {
253
    /* test for match 0x13+BITTORRENT_PROTO_STRING */
254
3.80M
    if(packet->payload[0] == 0x13) {
255
9.69k
      if(memcmp(&packet->payload[1], BITTORRENT_PROTO_STRING, 19) == 0) {
256
2.58k
  NDPI_LOG_INFO(ndpi_struct, "found BT: plain\n");
257
2.58k
  ndpi_add_connection_as_bittorrent(ndpi_struct, flow, 20, 1, NDPI_CONFIDENCE_DPI);
258
2.58k
  return 1;
259
2.58k
      }
260
9.69k
    }
261
3.80M
  }
262
263
5.90M
  if(packet->payload_packet_len > 23 && memcmp(packet->payload, "GET /webseed?info_hash=", 23) == 0) {
264
565
    NDPI_LOG_INFO(ndpi_struct, "found BT: plain webseed\n");
265
565
    ndpi_add_connection_as_bittorrent(ndpi_struct, flow, -1, 1, NDPI_CONFIDENCE_DPI);
266
565
    return 1;
267
565
  }
268
  /* seen Azureus as server for webseed, possibly other servers existing, to implement */
269
  /* is Server: hypertracker Bittorrent? */
270
  /* no asymmetric detection possible for answer of pattern "GET /data?fid=". */
271
5.90M
  if(packet->payload_packet_len > 60
272
2.98M
     && memcmp(packet->payload, "GET /data?fid=", 14) == 0 && memcmp(&packet->payload[54], "&size=", 6) == 0) {
273
86
    NDPI_LOG_INFO(ndpi_struct, "found BT: plain Bitcomet persistent seed\n");
274
86
    ndpi_add_connection_as_bittorrent(ndpi_struct, flow, -1, 1, NDPI_CONFIDENCE_DPI);
275
86
    return 1;
276
86
  }
277
278
279
5.90M
  if(packet->payload_packet_len > 90 && (memcmp(packet->payload, "GET ", 4) == 0
280
1.85M
           || memcmp(packet->payload, "POST ", 5) == 0)) {
281
664k
    const u_int8_t *ptr = &packet->payload[4];
282
664k
    u_int16_t len = packet->payload_packet_len - 4;
283
284
    /* parse complete get packet here into line structure elements */
285
664k
    ndpi_parse_packet_line_info(ndpi_struct, flow);
286
    /* answer to this pattern is HTTP....Server: hypertracker */
287
664k
    if(packet->user_agent_line.ptr != NULL
288
411k
       && ((packet->user_agent_line.len > 8 && memcmp(packet->user_agent_line.ptr, "Azureus ", 8) == 0)
289
410k
     || (packet->user_agent_line.len >= 10 && memcmp(packet->user_agent_line.ptr, "BitTorrent", 10) == 0)
290
409k
     || (packet->user_agent_line.len >= 11 && memcmp(packet->user_agent_line.ptr, "BTWebClient", 11) == 0))) {
291
1.54k
      NDPI_LOG_INFO(ndpi_struct, "found BT: Azureus /Bittorrent user agent\n");
292
1.54k
      ndpi_add_connection_as_bittorrent(ndpi_struct, flow, -1, 1, NDPI_CONFIDENCE_DPI);
293
1.54k
      return 1;
294
1.54k
    }
295
296
662k
    if(packet->user_agent_line.ptr != NULL
297
409k
       && (packet->user_agent_line.len >= 9 && memcmp(packet->user_agent_line.ptr, "Shareaza ", 9) == 0)
298
1.04k
       && (packet->parsed_lines > 8 && packet->line[8].ptr != 0
299
758
     && packet->line[8].len >= 9 && memcmp(packet->line[8].ptr, "X-Queue: ", 9) == 0)) {
300
71
      NDPI_LOG_INFO(ndpi_struct, "found BT: Shareaza detected\n");
301
71
      ndpi_add_connection_as_bittorrent(ndpi_struct, flow, -1, 1, NDPI_CONFIDENCE_DPI);
302
71
      return 1;
303
71
    }
304
305
    /* this is a self built client, not possible to catch asymmetrically */
306
662k
    if((packet->parsed_lines == 10 || (packet->parsed_lines == 11 && packet->line[10].len == 0))
307
31.6k
       && packet->user_agent_line.ptr != NULL
308
26.2k
       && packet->user_agent_line.len > 12
309
25.4k
       && memcmp(packet->user_agent_line.ptr, "Mozilla/4.0 ",
310
25.4k
     12) == 0
311
2.17k
       && packet->host_line.ptr != NULL
312
1.83k
       && packet->host_line.len >= 7
313
1.68k
       && packet->line[2].ptr != NULL
314
1.68k
       && packet->line[2].len > 14
315
1.48k
       && memcmp(packet->line[2].ptr, "Keep-Alive: 300", 15) == 0
316
1.03k
       && packet->line[3].ptr != NULL
317
1.03k
       && packet->line[3].len > 21
318
883
       && memcmp(packet->line[3].ptr, "Connection: Keep-alive", 22) == 0
319
755
       && packet->line[4].ptr != NULL
320
755
       && packet->line[4].len > 10
321
678
       && (memcmp(packet->line[4].ptr, "Accpet: */*", 11) == 0
322
262
     || memcmp(packet->line[4].ptr, "Accept: */*", 11) == 0)
323
324
542
       && packet->line[5].ptr != NULL
325
542
       && packet->line[5].len > 12
326
462
       && memcmp(packet->line[5].ptr, "Range: bytes=", 13) == 0
327
299
       && packet->line[7].ptr != NULL
328
299
       && packet->line[7].len > 15
329
238
       && memcmp(packet->line[7].ptr, "Pragma: no-cache", 16) == 0
330
112
       && packet->line[8].ptr != NULL
331
112
       && packet->line[8].len > 22 && memcmp(packet->line[8].ptr, "Cache-Control: no-cache", 23) == 0) {
332
333
16
      NDPI_LOG_INFO(ndpi_struct, "found BT: Bitcomet LTS\n");
334
16
      ndpi_add_connection_as_bittorrent(ndpi_struct, flow, -1, 1, NDPI_CONFIDENCE_DPI);
335
16
      return 1;
336
16
    }
337
338
    /* FlashGet pattern */
339
662k
    if(packet->parsed_lines == 8
340
30.6k
       && packet->user_agent_line.ptr != NULL
341
22.3k
       && packet->user_agent_line.len > (sizeof("Mozilla/4.0 (compatible; MSIE 6.0;") - 1)
342
19.6k
       && memcmp(packet->user_agent_line.ptr, "Mozilla/4.0 (compatible; MSIE 6.0;",
343
19.6k
     sizeof("Mozilla/4.0 (compatible; MSIE 6.0;") - 1) == 0
344
1.64k
       && packet->host_line.ptr != NULL
345
1.44k
       && packet->host_line.len >= 7
346
1.29k
       && packet->line[2].ptr != NULL
347
1.29k
       && packet->line[2].len == 11
348
1.05k
       && memcmp(packet->line[2].ptr, "Accept: */*", 11) == 0
349
924
       && packet->line[3].ptr != NULL && packet->line[3].len >= (sizeof("Referer: ") - 1)
350
800
       && memcmp(packet->line[3].ptr, "Referer: ", sizeof("Referer: ") - 1) == 0
351
656
       && packet->line[5].ptr != NULL
352
656
       && packet->line[5].len > 13
353
524
       && memcmp(packet->line[5].ptr, "Range: bytes=", 13) == 0
354
362
       && packet->line[6].ptr != NULL
355
362
       && packet->line[6].len > 21 && memcmp(packet->line[6].ptr, "Connection: Keep-Alive", 22) == 0) {
356
357
98
      NDPI_LOG_INFO(ndpi_struct, "found BT: FlashGet\n");
358
98
      ndpi_add_connection_as_bittorrent(ndpi_struct, flow, -1, 1, NDPI_CONFIDENCE_DPI);
359
98
      return 1;
360
98
    }
361
362
662k
    if(packet->parsed_lines == 7
363
57.5k
       && packet->user_agent_line.ptr != NULL
364
42.2k
       && packet->user_agent_line.len > (sizeof("Mozilla/4.0 (compatible; MSIE 6.0;") - 1)
365
37.4k
       && memcmp(packet->user_agent_line.ptr, "Mozilla/4.0 (compatible; MSIE 6.0;",
366
37.4k
     sizeof("Mozilla/4.0 (compatible; MSIE 6.0;") - 1) == 0
367
1.70k
       && packet->host_line.ptr != NULL
368
1.47k
       && packet->host_line.len >= 7
369
1.29k
       && packet->line[2].ptr != NULL
370
1.29k
       && packet->line[2].len == 11
371
1.00k
       && memcmp(packet->line[2].ptr, "Accept: */*", 11) == 0
372
803
       && packet->line[3].ptr != NULL && packet->line[3].len >= (sizeof("Referer: ") - 1)
373
680
       && memcmp(packet->line[3].ptr, "Referer: ", sizeof("Referer: ") - 1) == 0
374
488
       && packet->line[5].ptr != NULL
375
488
       && packet->line[5].len > 21 && memcmp(packet->line[5].ptr, "Connection: Keep-Alive", 22) == 0) {
376
377
91
      NDPI_LOG_INFO(ndpi_struct, "found BT: FlashGet\n");
378
91
      ndpi_add_connection_as_bittorrent(ndpi_struct, flow, -1, 1, NDPI_CONFIDENCE_DPI);
379
91
      return 1;
380
91
    }
381
382
    /* answer to this pattern is not possible to implement asymmetrically */
383
53.9M
    while (1) {
384
53.9M
      if(len < 50 || ptr[0] == 0x0d) {
385
654k
  goto ndpi_end_bt_tracker_check;
386
654k
      }
387
53.2M
      if(memcmp(ptr, "info_hash=", 10) == 0) {
388
7.98k
  break;
389
7.98k
      }
390
53.2M
      len--;
391
53.2M
      ptr++;
392
53.2M
    }
393
394
7.98k
    NDPI_LOG_DBG2(ndpi_struct, " BT stat: tracker info hash found\n");
395
396
    /* len is > 50, so save operation here */
397
7.98k
    len -= 10;
398
7.98k
    ptr += 10;
399
400
    /* parse bt hash */
401
99.8k
    for (a = 0; a < 20; a++) {
402
96.8k
      if(len < 3) {
403
78
  goto ndpi_end_bt_tracker_check;
404
78
      }
405
96.7k
      if(*ptr == '%') {
406
18.8k
  u_int8_t x1 = 0xFF;
407
18.8k
  u_int8_t x2 = 0xFF;
408
409
410
18.8k
  if(ptr[1] >= '0' && ptr[1] <= '9') {
411
7.63k
    x1 = ptr[1] - '0';
412
7.63k
  }
413
18.8k
  if(ptr[1] >= 'a' && ptr[1] <= 'f') {
414
9.06k
    x1 = 10 + ptr[1] - 'a';
415
9.06k
  }
416
18.8k
  if(ptr[1] >= 'A' && ptr[1] <= 'F') {
417
1.23k
    x1 = 10 + ptr[1] - 'A';
418
1.23k
  }
419
420
18.8k
  if(ptr[2] >= '0' && ptr[2] <= '9') {
421
8.59k
    x2 = ptr[2] - '0';
422
8.59k
  }
423
18.8k
  if(ptr[2] >= 'a' && ptr[2] <= 'f') {
424
8.11k
    x2 = 10 + ptr[2] - 'a';
425
8.11k
  }
426
18.8k
  if(ptr[2] >= 'A' && ptr[2] <= 'F') {
427
959
    x2 = 10 + ptr[2] - 'A';
428
959
  }
429
430
18.8k
  if(x1 == 0xFF || x2 == 0xFF) {
431
1.50k
    goto ndpi_end_bt_tracker_check;
432
1.50k
  }
433
17.3k
  ptr += 3;
434
17.3k
  len -= 3;
435
77.9k
      } else if(*ptr >= 32 && *ptr < 127) {
436
74.5k
  ptr++;
437
74.5k
  len--;
438
74.5k
      } else {
439
3.40k
  goto ndpi_end_bt_tracker_check;
440
3.40k
      }
441
96.7k
    }
442
443
2.99k
    NDPI_LOG_INFO(ndpi_struct, "found BT: tracker info hash parsed\n");
444
2.99k
    ndpi_add_connection_as_bittorrent(ndpi_struct, flow, -1, 1, NDPI_CONFIDENCE_DPI);
445
2.99k
    return 1;
446
7.98k
  }
447
448
5.90M
 ndpi_end_bt_tracker_check:
449
450
5.90M
  if(packet->payload_packet_len == 80) {
451
    /* Warez 80 Bytes Packet
452
     * +----------------+---------------+-----------------+-----------------+
453
     * |20 BytesPattern | 32 Bytes Value| 12 BytesPattern | 16 Bytes Data   |
454
     * +----------------+---------------+-----------------+-----------------+
455
     * 20 BytesPattern : 4c 00 00 00 ff ff ff ff 57 00 00 00 00 00 00 00 20 00 00 00
456
     * 12 BytesPattern : 28 23 00 00 01 00 00 00 10 00 00 00
457
     * */
458
16.7k
    static const u_char pattern_20_bytes[20] = { 0x4c, 0x00, 0x00, 0x00, 0xff,
459
16.7k
                 0xff, 0xff, 0xff, 0x57, 0x00,
460
16.7k
                 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x20, 0x00, 0x00, 0x00
461
16.7k
    };
462
16.7k
    static const u_char pattern_12_bytes[12] = { 0x28, 0x23, 0x00, 0x00, 0x01,
463
16.7k
                 0x00, 0x00, 0x00, 0x10, 0x00,
464
16.7k
                 0x00, 0x00
465
16.7k
    };
466
467
    /* did not see this pattern anywhere */
468
16.7k
    if((memcmp(&packet->payload[0], pattern_20_bytes, 20) == 0)
469
335
       && (memcmp(&packet->payload[52], pattern_12_bytes, 12) == 0)) {
470
27
      NDPI_LOG_INFO(ndpi_struct, "found BT: Warez - Plain\n");
471
27
      ndpi_add_connection_as_bittorrent(ndpi_struct, flow, -1, 1, NDPI_CONFIDENCE_DPI);
472
27
      return 1;
473
27
    }
474
16.7k
  }
475
476
5.88M
  else if(packet->payload_packet_len > 50) {
477
3.12M
    if(memcmp(packet->payload, "GET", 3) == 0) {
478
479
672k
      ndpi_parse_packet_line_info(ndpi_struct, flow);
480
      /* haven't fount this pattern anywhere */
481
672k
      if(packet->host_line.ptr != NULL
482
484k
   && packet->host_line.len >= 9 && memcmp(packet->host_line.ptr, "ip2p.com:", 9) == 0) {
483
878
  NDPI_LOG_INFO(ndpi_struct, "found BT: Warez - Plain Host: ip2p.com: pattern\n");
484
878
  ndpi_add_connection_as_bittorrent(ndpi_struct, flow, -1, 1, NDPI_CONFIDENCE_DPI);
485
878
  return 1;
486
878
      }
487
672k
    }
488
3.12M
  }
489
5.90M
  return 0;
490
5.90M
}
491
492
/* ************************************* */
493
494
/* Search for BitTorrent commands */
495
static void ndpi_int_search_bittorrent_tcp(struct ndpi_detection_module_struct *ndpi_struct, struct ndpi_flow_struct *flow)
496
5.91M
{
497
5.91M
  struct ndpi_packet_struct *packet = &ndpi_struct->packet;
498
499
5.91M
  if(packet->payload_packet_len == 0) {
500
0
    return;
501
0
  }
502
503
5.91M
  ndpi_int_search_bittorrent_tcp_zero(ndpi_struct, flow);
504
5.91M
}
505
506
/* ************************************* */
507
508
4.50M
static u_int8_t is_port(u_int16_t a, u_int16_t b, u_int16_t what) {
509
4.50M
  return(((what == a) || (what == b)) ? 1 : 0);
510
4.50M
}
511
512
/* ************************************* */
513
514
static void ndpi_skip_bittorrent(struct ndpi_detection_module_struct *ndpi_struct,
515
358k
         struct ndpi_flow_struct *flow) {
516
358k
  if(flow->detected_protocol_stack[0] == NDPI_PROTOCOL_BITTORRENT)
517
223
    return;
518
358k
  if(search_into_bittorrent_cache(ndpi_struct, flow))
519
74.3k
    ndpi_add_connection_as_bittorrent(ndpi_struct, flow, -1, 0, NDPI_CONFIDENCE_DPI_CACHE);
520
284k
  else
521
284k
    NDPI_EXCLUDE_DISSECTOR(ndpi_struct, flow);
522
358k
}
523
524
/* ************************************* */
525
526
static void ndpi_search_bittorrent(struct ndpi_detection_module_struct *ndpi_struct,
527
7.51M
           struct ndpi_flow_struct *flow) {
528
7.51M
  struct ndpi_packet_struct *packet = &ndpi_struct->packet;
529
7.51M
  char *bt_proto = NULL;
530
531
7.51M
  NDPI_LOG_DBG(ndpi_struct, "Search bittorrent\n");
532
533
  /* This is broadcast */
534
7.51M
  if(packet->iph) {
535
7.29M
    if((packet->iph->saddr == 0xFFFFFFFF) || (packet->iph->daddr == 0xFFFFFFFF))
536
17.8k
      goto exclude_bt;
537
538
7.27M
    if(packet->udp) {
539
1.50M
      u_int16_t sport = ntohs(packet->udp->source), dport = ntohs(packet->udp->dest);
540
541
1.50M
      if(is_port(sport, dport, 3544) /* teredo */
542
1.50M
   || is_port(sport, dport, 5246) || is_port(sport, dport, 5247) /* CAPWAP */) {
543
23.9k
      exclude_bt:
544
23.9k
  NDPI_EXCLUDE_DISSECTOR(ndpi_struct, flow);
545
23.9k
  return;
546
6.18k
      }
547
1.50M
    }
548
7.27M
  }
549
550
7.49M
  if(flow->detected_protocol_stack[0] != NDPI_PROTOCOL_BITTORRENT) {
551
7.49M
    if(packet->tcp != NULL) {
552
5.91M
      ndpi_int_search_bittorrent_tcp(ndpi_struct, flow);
553
5.91M
    } else if(packet->udp != NULL) {
554
      /* UDP */
555
1.58M
      const char *bt_search  = "BT-SEARCH * HTTP/1.1\r\n";
556
1.58M
      const char *bt_search1 = "d1:ad2:id20:";
557
558
1.58M
      if((ntohs(packet->udp->source) < 1024)
559
1.47M
   || (ntohs(packet->udp->dest) < 1024) /* High ports only */) {
560
204k
  ndpi_skip_bittorrent(ndpi_struct, flow);
561
204k
  return;
562
204k
      }
563
564
      /*
565
  Check for uTP http://www.bittorrent.org/beps/bep_0029.html
566
567
  wireshark/epan/dissectors/packet-bt-utp.c
568
      */
569
570
1.38M
  if(
571
1.38M
     (packet->payload_packet_len > 22 && strncmp((const char*)packet->payload, bt_search, strlen(bt_search)) == 0) ||
572
1.38M
     (packet->payload_packet_len > 12 && strncmp((const char*)packet->payload, bt_search1, strlen(bt_search1)) == 0)
573
1.38M
     ) {
574
295
    ndpi_add_connection_as_bittorrent(ndpi_struct, flow, -1, 1, NDPI_CONFIDENCE_DPI);
575
295
    return;
576
1.38M
  } else if(packet->payload_packet_len >= 20) {
577
    /* Check if this is protocol v0 */
578
1.11M
    u_int8_t v0_extension = packet->payload[17];
579
1.11M
    u_int8_t v0_flags     = packet->payload[18];
580
1.11M
    int rc;
581
582
1.11M
    if((rc = is_utpv1_pkt(packet->payload, packet->payload_packet_len)) > 0) {
583
8.00k
      bt_proto = ndpi_strnstr((const char *)&packet->payload[20], BITTORRENT_PROTO_STRING, packet->payload_packet_len-20);
584
      /* DATA check is quite weak so in that case wait for multiple packets/confirmations */
585
8.00k
      if(rc == 1 || bt_proto != NULL || (rc == 2 && flow->packet_counter > 2)) {
586
1.84k
        goto bittorrent_found;
587
6.15k
      } else {
588
6.15k
        return;
589
6.15k
      }
590
1.10M
    } else if((packet->payload[0]== 0x60)
591
4.77k
        && (packet->payload[1]== 0x0)
592
1.36k
        && (packet->payload[2]== 0x0)
593
915
        && (packet->payload[3]== 0x0)
594
532
        && (packet->payload[4]== 0x0)) {
595
      /* Heuristic */
596
217
      bt_proto = ndpi_strnstr((const char *)&packet->payload[20], BITTORRENT_PROTO_STRING, packet->payload_packet_len-20);
597
217
      goto bittorrent_found;
598
      /* CSGO/DOTA conflict */
599
1.10M
    } else if((v0_flags < 6 /* ST_NUM_STATES */) && (v0_extension < 3 /* EXT_NUM_EXT */)) {
600
280k
      u_int32_t ts = ntohl(*((u_int32_t*)&(packet->payload[4])));
601
280k
      u_int32_t now;
602
603
280k
      now = (u_int32_t)(packet->current_time_ms / 1000);
604
605
280k
      if((ts < (now+86400)) && (ts > (now-86400))) {
606
42
        bt_proto = ndpi_strnstr((const char *)&packet->payload[20], BITTORRENT_PROTO_STRING, packet->payload_packet_len-20);
607
42
        goto bittorrent_found;
608
42
      }
609
823k
    } else if(ndpi_strnstr((const char *)&packet->payload[20], BITTORRENT_PROTO_STRING, packet->payload_packet_len-20)
610
823k
        ) {
611
223
      goto bittorrent_found;
612
223
    }
613
614
1.11M
  }
615
616
1.37M
      flow->bittorrent_stage++;
617
618
1.37M
      if(flow->bittorrent_stage < 5) {
619
  /* We have detected bittorrent but we need to wait until we get a hash */
620
621
1.30M
  if(packet->payload_packet_len > 19 /* min size */) {
622
1.05M
    if(ndpi_strnstr((const char *)packet->payload, ":target20:", packet->payload_packet_len)
623
1.05M
       || ndpi_strnstr((const char *)packet->payload, ":find_node1:", packet->payload_packet_len)
624
1.05M
       || ndpi_strnstr((const char *)packet->payload, "d1:ad2:id20:", packet->payload_packet_len)
625
1.05M
       || ndpi_strnstr((const char *)packet->payload, ":info_hash20:", packet->payload_packet_len)
626
1.05M
       || ndpi_strnstr((const char *)packet->payload, ":filter64", packet->payload_packet_len)
627
1.05M
       || ndpi_strnstr((const char *)packet->payload, "d1:rd2:id20:", packet->payload_packet_len)
628
1.05M
       || (bt_proto = ndpi_strnstr((const char *)packet->payload, BITTORRENT_PROTO_STRING, packet->payload_packet_len))
629
1.05M
       ) {
630
3.58k
    bittorrent_found:
631
3.58k
      if(bt_proto != NULL && ((u_int8_t *)&bt_proto[27] - packet->payload +
632
341
            sizeof(flow->protos.bittorrent.hash)) < packet->payload_packet_len) {
633
139
        memcpy(flow->protos.bittorrent.hash, &bt_proto[27], sizeof(flow->protos.bittorrent.hash));
634
139
        flow->extra_packets_func = NULL; /* Nothing else to do */
635
139
      }
636
637
3.58k
      NDPI_LOG_INFO(ndpi_struct, "found BT: plain\n");
638
3.58k
      ndpi_add_connection_as_bittorrent(ndpi_struct, flow, -1, 0, NDPI_CONFIDENCE_DPI);
639
3.58k
      return;
640
1.25k
    }
641
1.05M
  }
642
643
1.30M
  return;
644
1.30M
      }
645
646
64.2k
      ndpi_skip_bittorrent(ndpi_struct, flow);
647
64.2k
    }
648
7.49M
  }
649
650
5.97M
  if(flow->packet_counter > 5)
651
90.1k
    ndpi_skip_bittorrent(ndpi_struct, flow);  
652
5.97M
}
653
654
/* ************************************* */
655
656
void init_bittorrent_dissector(struct ndpi_detection_module_struct *ndpi_struct)
657
20.4k
{
658
20.4k
  ndpi_register_dissector("BitTorrent", ndpi_struct,
659
20.4k
                     ndpi_search_bittorrent,
660
20.4k
                     NDPI_SELECTION_BITMASK_PROTOCOL_V4_V6_TCP_OR_UDP_WITH_PAYLOAD_WITHOUT_RETRANSMISSION,
661
20.4k
                     1, NDPI_PROTOCOL_BITTORRENT);
662
20.4k
}