forked from torrust/torrust-tracker
-
Notifications
You must be signed in to change notification settings - Fork 0
/
Copy pathmod.rs
663 lines (659 loc) · 47.4 KB
/
mod.rs
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
208
209
210
211
212
213
214
215
216
217
218
219
220
221
222
223
224
225
226
227
228
229
230
231
232
233
234
235
236
237
238
239
240
241
242
243
244
245
246
247
248
249
250
251
252
253
254
255
256
257
258
259
260
261
262
263
264
265
266
267
268
269
270
271
272
273
274
275
276
277
278
279
280
281
282
283
284
285
286
287
288
289
290
291
292
293
294
295
296
297
298
299
300
301
302
303
304
305
306
307
308
309
310
311
312
313
314
315
316
317
318
319
320
321
322
323
324
325
326
327
328
329
330
331
332
333
334
335
336
337
338
339
340
341
342
343
344
345
346
347
348
349
350
351
352
353
354
355
356
357
358
359
360
361
362
363
364
365
366
367
368
369
370
371
372
373
374
375
376
377
378
379
380
381
382
383
384
385
386
387
388
389
390
391
392
393
394
395
396
397
398
399
400
401
402
403
404
405
406
407
408
409
410
411
412
413
414
415
416
417
418
419
420
421
422
423
424
425
426
427
428
429
430
431
432
433
434
435
436
437
438
439
440
441
442
443
444
445
446
447
448
449
450
451
452
453
454
455
456
457
458
459
460
461
462
463
464
465
466
467
468
469
470
471
472
473
474
475
476
477
478
479
480
481
482
483
484
485
486
487
488
489
490
491
492
493
494
495
496
497
498
499
500
501
502
503
504
505
506
507
508
509
510
511
512
513
514
515
516
517
518
519
520
521
522
523
524
525
526
527
528
529
530
531
532
533
534
535
536
537
538
539
540
541
542
543
544
545
546
547
548
549
550
551
552
553
554
555
556
557
558
559
560
561
562
563
564
565
566
567
568
569
570
571
572
573
574
575
576
577
578
579
580
581
582
583
584
585
586
587
588
589
590
591
592
593
594
595
596
597
598
599
600
601
602
603
604
605
606
607
608
609
610
611
612
613
614
615
616
617
618
619
620
621
622
623
624
625
626
627
628
629
630
631
632
633
634
635
636
637
638
639
640
641
642
643
644
645
646
647
648
649
650
651
652
653
654
655
656
657
658
659
660
661
662
663
//! UDP Tracker.
//!
//! This module contains the UDP tracker implementation.
//!
//! The UDP tracker is a simple UDP server that responds to these requests:
//!
//! - `Connect`: used to get a connection ID which must be provided on each
//! request in order to avoid spoofing the source address of the UDP packets.
//! - `Announce`: used to announce the presence of a peer to the tracker.
//! - `Scrape`: used to get information about a torrent.
//!
//! It was introduced in [BEP 15. UDP Tracker Protocol for `BitTorrent`](https://www.bittorrent.org/beps/bep_0015.html)
//! as an alternative to the [HTTP tracker](https://www.bittorrent.org/beps/bep_0003.html).
//! The UDP tracker is more efficient than the HTTP tracker because it uses UDP
//! instead of TCP.
//!
//! Refer to the [`bit_torrent`](crate::shared::bit_torrent) module for more
//! information about the `BitTorrent` protocol.
//!
//! Refer to [BEP 15. UDP Tracker Protocol for `BitTorrent`](https://www.bittorrent.org/beps/bep_0015.html)
//! and to [BEP 41. UDP Tracker Protocol Extensions](https://www.bittorrent.org/beps/bep_0041.html)
//! for more information about the UDP tracker protocol.
//!
//! > **NOTICE**: [BEP-41](https://www.bittorrent.org/beps/bep_0041.html) is not
//! implemented yet.
//!
//! > **NOTICE**: we are using the [`aquatic_udp_protocol`](https://crates.io/crates/aquatic_udp_protocol)
//! crate so requests and responses are handled by it.
//!
//! > **NOTICE**: all values are send in network byte order ([big endian](https://en.wikipedia.org/wiki/Endianness)).
//!
//! ## Table of Contents
//!
//! - [Actions](#actions)
//! - [Connect](#connect)
//! - [Connect Request](#connect-request)
//! - [Connect Response](#connect-response)
//! - [Announce](#announce)
//! - [Announce Request](#announce-request)
//! - [Announce Response](#announce-response)
//! - [Scrape](#scrape)
//! - [Scrape Request](#scrape-request)
//! - [Scrape Response](#scrape-response)
//! - [Errors](#errors)
//! - [Extensions](#extensions)
//! - [Links](#links)
//! - [Credits](#credits)
//!
//! ## Actions
//!
//! Requests are sent to the tracker using UDP packets. The UDP tracker protocol
//! is designed to be as simple as possible. It uses a single UDP port and
//! supports only three types of requests: `Connect`, `Announce` and `Scrape`.
//!
//! Request are parsed from UDP packets using the [`aquatic_udp_protocol`](https://crates.io/crates/aquatic_udp_protocol)
//! crate and then handled by the [`Tracker`](crate::core::Tracker) struct.
//! And then the response is also build using the [`aquatic_udp_protocol`](https://crates.io/crates/aquatic_udp_protocol)
//! and converted to a UDP packet.
//!
//! ```text
//! UDP packet -> Aquatic Struct Request -> [Torrust Struct Request] -> Tracker -> Aquatic Struct Response -> UDP packet
//! ```
//!
//! For the `Announce` request there is a wrapper struct [`AnnounceWrapper`](crate::servers::udp::request::AnnounceWrapper).
//! It was added to add an extra field with the internal [`InfoHash`](crate::shared::bit_torrent::info_hash::InfoHash) struct.
//!
//! ### Connect
//!
//! `Connect` requests are used to get a connection ID which must be provided on
//! each request in order to avoid spoofing the source address of the UDP.
//!
//! The connection ID is a random 64-bit integer that is used to identify the
//! client. It is used to prevent spoofing of the source address of the UDP
//! packets. Before announcing or scraping, you have to obtain a connection ID.
//!
//! The connection ID is generated by the tracker and sent back to the client's
//! IP address. Only the client using that IP can receive the response, so the
//! tracker can be sure that the client is the one who sent the request. If the
//! client's IP was spoofed the tracker will send the response to the wrong
//! client and the client will not receive it.
//!
//! The reason why the UDP tracker protocol needs a connection ID to avoid IP
//! spoofing can be explained as follows:
//!
//! 1. No connection state: Unlike TCP, UDP is a connectionless protocol,
//! meaning that it does not establish a connection between two endpoints before
//! exchanging data. As a result, it is more susceptible to IP spoofing, where
//! an attacker sends packets with a forged source IP address, tricking the
//! receiver into believing that they are coming from a legitimate source.
//!
//! 2. Mitigating IP spoofing: To mitigate IP spoofing in the UDP tracker
//! protocol, a connection ID is used. When a client wants to interact with a
//! tracker, it sends a "connect" request to the tracker, which, in turn,
//! responds with a unique connection ID. This connection ID must be included in
//! all subsequent requests from the client to the tracker.
//!
//! 3. Validating requests: By requiring the connection ID, the tracker can
//! verify that the requests are coming from the same client that initially sent
//! the "connect" request. If an attacker attempts to spoof the client's IP
//! address, they would also need to know the valid connection ID to be accepted
//! by the tracker. This makes it significantly more challenging for an attacker
//! to spoof IP addresses and disrupt the P2P network.
//!
//! There are different ways to generate a connection ID. The most common way is
//! to generate a time bound secret. The secret is generated using a time based
//! algorithm and it is valid for a certain amount of time.
//!
//! ```text
//! connection ID = hash(client IP + current time slot + secret seed)
//! ```
//!
//! The BEP-15 recommends a two-minute time slot. Refer to [`connection_cookie`]
//! for more information about the connection ID generation with this method.
//!
//! #### Connect Request
//!
//! **Connect request (UDP packet)**
//!
//! Offset | Type/Size | Name | Description | Hex | Decimal
//! -------|-------------------|------------------|-------------------------------------------------|-----------------------------|-----------------
//! 0 | [`i64`](std::i64) | `protocol_id` | Magic constant that will identify the protocol. | `0x00_00_04_17_27_10_19_80` | `4497486125440`
//! 8 | [`i32`](std::i32) | `action` | Action identifying the connect request. | `0x00_00_00_00` | `0`
//! 12 | [`i32`](std::i32) | `transaction_id` | Randomly generated by the client. | `0x34_FA_A1_F9` | `-888840697`
//!
//! **Sample connect request (UDP packet)**
//!
//! UDP packet bytes:
//!
//! ```text
//! Offset: [ 0, 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15]
//! Decimal: [ 0, 0, 4, 23, 39, 16, 25, 128, 0, 0, 0, 0, 203, 5, 94, 7]
//! Hex: [0x00, 0x00, 0x04, 0x17, 0x27, 0x10, 0x19, 0x80, 0x00, 0x00, 0x00, 0x00, 0xCB, 0x05, 0x5E, 0x07]
//! Param: [<------------- protocol_id ------------------>,<------- action ------>,<--- transaction_id -->]
//! ```
//!
//! UDP packet fields:
//!
//! Offset | Type/Size | Name | Bytes Dec (Big Endian) | Hex | Decimal
//! -------|-------------------|------------------|--------------------------------|-----------------------------|----------------
//! 0 | [`i64`](std::i64) | `protocol_id` | [0, 0, 4, 23, 39, 16, 25, 128] | `0x00_00_04_17_27_10_19_80` | `4497486125440`
//! 4 | [`i32`](std::i32) | `action` | [0, 0, 0, 0] | `0x00_00_00_00` | `0`
//! 8 | [`i32`](std::i32) | `transaction_id` | [35, 63, 226, 1] | `0xCB_05_5E_07` | `-888840697`
//!
//! **Connect request (parsed struct)**
//!
//! After parsing the UDP packet, the [`ConnectRequest`](aquatic_udp_protocol::request::ConnectRequest)
//! request struct will look like this:
//!
//! Field | Type | Example
//! -----------------|----------------------------------------------------------------|-------------
//! `transaction_id` | [`TransactionId`](aquatic_udp_protocol::common::TransactionId) | `1950635409`
//!
//! #### Connect Response
//!
//! **Connect response (UDP packet)**
//!
//! Offset | Type/Size | Name | Description | Hex | Decimal
//! -------|-------------------|------------------|-------------------------------------------------------|-----------------------------|-----------------------
//! 0 | [`i64`](std::i32) | `action` | Action identifying the connect request | `0x00_00_00_00` | `0`
//! 4 | [`i32`](std::i32) | `transaction_id` | Must match the `transaction_id` sent from the client. | `0xCB_05_5E_07` | `-888840697`
//! 8 | [`i32`](std::i64) | `connection_id` | Generated by the tracker to authenticate the client. | `0xC5_58_7C_09_08_48_D8_37` | `-4226491872051668937`
//!
//! > **NOTICE**: the `connection_id` is used when further information is
//! exchanged with the tracker, to identify the client. This `connection_id` can
//! be reused for multiple requests, but if it's cached for too long, it will
//! not be valid anymore.
//!
//! > **NOTICE**: `Hex` column is a signed 2's complement.
//!
//! **Sample connect response (UDP packet)**
//!
//! UDP packet bytes:
//!
//! ```text
//! Offset: [ 0, 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15]
//! Decimal: [ 0, 0, 0, 0, 203, 5, 94, 7, 197, 88, 124, 9, 8, 72, 216, 55]
//! Hex: [0x00, 0x00, 0x00, 0x00, 0xCB, 0x05, 0x5E, 0x07, 0xC5, 0x58, 0x7C, 0x09, 0x08, 0x48, 0xD8, 0x37]
//! Param: [<------ action ------>,<-- transaction_id --->,<--------------- connection_id --------------->]
//! ```
//!
//! UDP packet fields:
//!
//! Offset | Type/Size | Name | Bytes (Big Endian) | Hex | Decimal
//! -------|-------------------|------------------|-----------------------------------|------------------------------|-----------------------
//! 0 | [`i64`](std::i32) | `action` | [0, 0, 0, 0] | `0x00_00_00_00` | `0`
//! 4 | [`i64`](std::i32) | `transaction_id` | [203, 5, 94, 7] | `0xCB_05_5E_07` | `-888840697`
//! 8 | [`i64`](std::i64) | `connection_id` | [197, 88, 124, 9, 8, 72, 216, 55] | `0xC5_58_7C_09_08_48_D8_37` | `-4226491872051668937`
//!
//! > **NOTICE**: `Hex` column is a signed 2's complement.
//!
//! **Connect response (struct)**
//!
//! Before building the UDP packet, the [`ConnectResponse`](aquatic_udp_protocol::response::ConnectResponse)
//! struct will look like this:
//!
//! Field | Type | Example
//! -----------------|----------------------------------------------------------------|-------------------------
//! `connection_id` | [`ConnectionId`](aquatic_udp_protocol::common::ConnectionId) | `-4226491872051668937`
//! `transaction_id` | [`TransactionId`](aquatic_udp_protocol::common::TransactionId) | `-888840697`
//!
//! **Connect specification**
//!
//! Original specification in [BEP 15. UDP Tracker Protocol for `BitTorrent`](https://www.bittorrent.org/beps/bep_0015.html).
//!
//! ### Announce
//!
//! `Announce` requests are used to announce the presence of a peer to the
//! tracker. The tracker responds with a list of peers that are also downloading
//! the same torrent. A "swarm" is a group of peers that are downloading the
//! same torrent.
//!
//! #### Announce Request
//!
//! **Announce request (UDP packet)**
//!
//! Offset | Type/Size | Name | Description | Hex | Decimal
//! -------|-------------------|------------------|--------------------------------------------------------------|-----------------------------------------------------------------|----------------------------------------------------------
//! 0 | [`i64`](std::i64) | `connection_id` | The connection id acquired from establishing the connection. | `0xC5_58_7C_09_08_48_D8_37` | `-4226491872051668937`
//! 8 | [`i32`](std::i32) | `action` | Action for announce request. | `0x00_00_00_01` | `1`
//! 12 | [`i32`](std::i32) | `transaction_id` | Randomly generated by the client. | `0xA2_F9_54_48` | `-1560718264`
//! 16 | 20-byte | `info_hash` | The infohash of the torrent being announced. | `0x03_84_05_48_64_3A_F2_A7_B6_3A_9F_5C_BC_A3_48_BC_71_50_CA_3A` | `20071130873666512363095721859061691407221705274`
//! 36 | 20-byte | `peer_id` | The ID of the peer announcing the torrent. | `0x2D_71_42_34_34_31_30_2D_29_53_64_7E_64_65_34_78_4D_70_36_44` | `259430336069436570531165609119312093997849130564`
//! 56 | [`i64`](std::i64) | `downloaded` | The number of bytes the peer has downloaded so far. | `0x00_00_00_00_00_00_00_00` | `0`
//! 64 | [`i64`](std::i64) | `left` | The number of bytes left to download by the peer. | `0x00_00_00_00_00_00_00_00` | `0`
//! 72 | [`i64`](std::i64) | `uploaded` | The number of bytes the peer has uploaded so far. | `0x00_00_00_00_00_00_00_00` | `0`
//! 80 | [`i32`](std::i32) | `event` | The event the peer is reporting to the tracker. | `0x0`, `0x1`, `0x2`, `0x3` | `0`: none; `1`: completed; `2`: started; `3`: stopped
//! 84 | [`i32`](std::i32) | `IP address` | The peer IP. Ignored by the tracker. It uses the Sender's IP.| `0x00_00_00_00` | `0`
//! 88 | [`i32`](std::i32) | `key` | A unique key that is randomized by the client. | `0xEF_34_95_D6` | `-281766442`
//! 92 | [`i32`](std::i32) | `num_want` | The maximum number of peers the peer wants in the response. | `0x00_00_00_C8` | `200`
//! 96 | [`i16`](std::i16) | `port` | The port the peer is listening on. | `0x44_8C` | `17548`
//!
//! **Peer IP address**
//!
//! The peer IP address is always ignored by the tracker. It uses the sender's
//! IP address.
//!
//! _"Do note that most trackers will only honor the IP address field under
//! limited circumstances."_ ([BEP 15](https://www.bittorrent.org/beps/bep_0015.html)).
//!
//! Although not supported by this tracker a UDP tracker can use the IP address
//! provided by the peer in the announce request under specific circumstances
//! when it cannot rely on the source IP address of the incoming request. These
//! circumstances might include:
//!
//! 1. Network Address Translation (NAT): In cases where a peer is behind a NAT,
//! the private IP address of the peer is not directly routable over the
//! internet. The NAT device translates the private IP address to a public one
//! when sending packets to the tracker. The public IP address is what the
//! tracker sees as the source IP of the incoming request. However, if the peer
//! provides its private IP address in the announce request, the tracker can use
//! this information to facilitate communication between peers in the same
//! private network.
//!
//! 2. Proxy or VPN usage: If a peer uses a proxy or VPN service to connect to
//! the tracker, the source IP address seen by the tracker will be the one
//! assigned by the proxy or VPN server. In this case, if the peer provides its
//! actual IP address in the announce request, the tracker can use it to
//! establish a direct connection with other peers, bypassing the proxy or VPN
//! server. This might improve performance or help in cases where some peers
//! cannot connect to the proxy or VPN server.
//!
//! 3. Tracker is behind a NAT, firewall, proxy, VPN, or load balancer: In cases
//! where the tracker is behind a NAT, firewall, proxy, VPN, or load balancer,
//! the source IP address of the incoming request will be the public IP address
//! of the NAT, firewall, proxy, VPN, or load balancer. If the peer provides its
//! private IP address in the announce request, the tracker can use this
//! information to establish a direct connection with the peer.
//!
//! It's important to note that using the provided IP address can pose security
//! risks, as malicious peers might spoof their IP addresses in the announce
//! request to perform various types of attacks.
//!
//! > **NOTICE**: The current tracker behavior is to ignore the IP address
//! provided by the peer, and use the source IP address of the incoming request,
//! when the tracker is not running behind a proxy, and to use the right-most IP
//! address in the `X-Forwarded-For` header when the tracker is running behind a
//! proxy.
//!
//! > **NOTICE**: The tracker also changes the peer IP address to the tracker
//! external IP when the peer is using a loopback IP address.
//!
//! **Sample announce request (UDP packet)**
//!
//! Some values used in the sample request:
//!
//! - Infohash: `0x03840548643AF2A7B63A9F5CBCA348BC7150CA3A`
//! - Peer ID: `0x2D7142343431302D2953647E646534784D703644`
//!
//! UDP packet bytes:
//!
//! ```text
//! Offset: [ 0, 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15, 16, 17, 18, 19, 20, 21, 22, 23, 24, 25, 26, 27, 28, 29, 30, 31, 32, 33, 34, 35, 36, 37, 38, 39, 40, 41, 42, 43, 44, 45, 46, 47, 48, 49, 50, 51, 52, 53, 54, 55, 56, 57, 58, 59, 60, 61, 62, 63, 64, 65, 66, 67, 68, 69, 70, 71, 72, 73, 74, 75, 76, 77, 78, 79, 80, 81, 82, 83, 84, 85, 86, 87, 88, 89, 90, 91, 92, 93, 94, 95, 96, 97, 98, 99, 100]
//! Decimal: [ 197, 88, 124, 9, 8, 72, 216, 55, 0, 0, 0, 1, 162, 249, 84, 72, 3, 132, 5, 72, 100, 58, 242, 167, 182, 58, 159, 92, 188, 163, 72, 188, 113, 80, 202, 58, 45, 113, 66, 52, 52, 49, 48, 45, 41, 83, 100, 126, 100, 101, 52, 120, 77, 112, 54, 68, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 2, 0, 0, 0, 0, 239, 52, 149, 214, 0, 0, 0, 200, 68, 140, 2, 1, 47]
//! Hex: [ 0xC5, 0x58, 0x7C, 0x09, 0x08, 0x48, 0xD8, 0x37, 0x00, 0x00, 0x00, 0x01, 0xA2, 0xF9, 0x54, 0x48, 0x03, 0x84, 0x05, 0x48, 0x64, 0x3A, 0xF2, 0xA7, 0xB6, 0x3A, 0x9F, 0x5C, 0xBC, 0xA3, 0x48, 0xBC, 0x71, 0x50, 0xCA, 0x3A, 0x2D, 0x71, 0x42, 0x34, 0x34, 0x31, 0x30, 0x2D, 0x29, 0x53, 0x64, 0x7E, 0x64, 0x65, 0x34, 0x78, 0x4D, 0x70, 0x36, 0x44, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x02, 0x00, 0x00, 0x00, 0x00, 0xEF, 0x34, 0x95, 0xD6, 0x00, 0x00, 0x00, 0xC8, 0x44, 0x8C, 0x02, 0x01, 0x2F]
//! Param: [<--------------- connection_id --------------->,<--------- action ---->,<-- transaction_id --->,<--------------------------------------------------------- info_hash ------------------------------------------------->,<---------------------------------------------- peer_id -------------------------------------------------------------->,<------------------- downloaded -------------->,<-------------------- left ------------------->,<---------------- uploaded ------------------->,<-------- event ------>,<----- IP address ---->,<--------- key ------->,<------ num_want ----->,<-- port --><---- BEP 41 --->]
//! ```
//!
//! UDP packet fields:
//!
//! Offset | Type/Size | Name | Bytes Dec (Big Endian) | Hex | Decimal
//! -------|-------------------|-------------------|--------------------------------------------------------------------------|-----------------------------------------------------------------|----------------------------------------------------
//! 0 | [`i64`](std::i64) | `connection_id` | `[197,88,124,9,8,72,216,55]` | `0xC5_58_7C_09_08_48_D8_37` | `-4226491872051668937`
//! 8 | [`i32`](std::i32) | `action` | `[0,0,0,1]` | `0x00_00_00_01` | `1`
//! 12 | [`i32`](std::i32) | `transaction_id` | `[162,249,84,72]` | `0xA2_F9_54_48` | `-1560718264`
//! 16 | 20 bytes | `info_hash` | `[3,132,5,72,100,58,242,167,182,58,159,92,188,163,72,188,113,80,202,58]` | `0x03_84_05_48_64_3A_F2_A7_B6_3A_9F_5C_BC_A3_48_BC_71_50_CA_3A` | `20071130873666512363095721859061691407221705274`
//! 36 | 20 bytes | `peer_id` | `[45,113,66,52,52,49,48,45,41,83,100,126,100,101,52,120,77,112,54,68]` | `0x2D_71_42_34_34_31_30_2D_29_53_64_7E_64_65_34_78_4D_70_36_44` | `259430336069436570531165609119312093997849130564`
//! 56 | [`i64`](std::i64) | `downloaded` | `[0,0,0,0,0,0,0,0]` | `0x00_00_00_00_00_00_00_00` | `0`
//! 64 | [`i64`](std::i64) | `left` | `[0,0,0,0,0,0,0,0]` | `0x00_00_00_00_00_00_00_00` | `0`
//! 72 | [`i64`](std::i64) | `uploaded` | `[0,0,0,0,0,0,0,0]` | `0x00_00_00_00_00_00_00_00` | `0`
//! 80 | [`i32`](std::i32) | `event` | `[0,0,0,2]` | `0x00_00_00_02` | `2` (`Started`)
//! 84 | [`i32`](std::i32) | `IP address` | `[0,0,0,0]` | `0x00_00_00_00` | `0`
//! 88 | [`i32`](std::i32) | `key` | `[239,52,149,214]` | `0xEF_34_95_D6` | `-281766442`
//! 92 | [`i32`](std::i32) | `num_want` | `[0,0,0,200]` | `0x00_00_00_C8` | `200`
//! 96 | [`i16`](std::i16) | `port` | `[8,140]` | `0x44_8C` | `17548`
//! 98 | 1 byte | `Option-Type` | `[2]` | `0x02` | `2`
//! 99 | 2 byte | `Length Byte` | `[1,47]` | `0x01_2F` | `303`
//! 101 | N bytes | | | |
//!
//! > **NOTICE**: bytes after offset 98 are part of the [BEP-41. UDP Tracker Protocol Extensions](https://www.bittorrent.org/beps/bep_0041.html).
//! There are three options defined for byte 98: `0x0` (`EndOfOptions`), `0x1` (`NOP`) and `0x2` (`URLData`).
//!
//! > **NOTICE**: `num_want` is being ignored by the tracker. Refer to
//! [issue 262](https://github.com/torrust/torrust-tracker/issues/262) for more
//! information.
//!
//! **Announce request (parsed struct)**
//!
//! After parsing the UDP packet, the [`AnnounceRequest`](aquatic_udp_protocol::request::AnnounceRequest)
//! struct will contain the following fields:
//!
//! Field | Type | Example
//! -------------------|---------------------------------------------------------------- |--------------
//! `connection_id` | [`ConnectionId`](aquatic_udp_protocol::common::ConnectionId) | `-4226491872051668937`
//! `transaction_id` | [`TransactionId`](aquatic_udp_protocol::common::TransactionId) | `-1560718264`
//! `info_hash` | [`InfoHash`](aquatic_udp_protocol::common::InfoHash) | `[3,132,5,72,100,58,242,167,182,58,159,92,188,163,72,188,113,80,202,58]`
//! `peer_id` | [`PeerId`](aquatic_udp_protocol::common::PeerId) | `[45,113,66,52,52,49,48,45,41,83,100,126,100,101,52,120,77,112,54,68]`
//! `bytes_downloaded` | [`NumberOfBytes`](aquatic_udp_protocol::common::NumberOfBytes) | `0`
//! `bytes_uploaded` | [`TransactionId`](aquatic_udp_protocol::common::NumberOfBytes) | `0`
//! `event` | [`AnnounceEvent`](aquatic_udp_protocol::request::AnnounceEvent) | `Started`
//! `ip_address` | [`Ipv4Addr`](aquatic_udp_protocol::common::ConnectionId) | `None`
//! `peers_wanted` | [`NumberOfPeers`](aquatic_udp_protocol::common::NumberOfPeers) | `200`
//! `port` | [`Port`](aquatic_udp_protocol::common::Port) | `17548`
//!
//! > **NOTICE**: the `peers_wanted` field is the `num_want` field in the UDP
//! packet.
//!
//! We are using a wrapper struct for the aquatic [`AnnounceRequest`](aquatic_udp_protocol::request::AnnounceRequest)
//! struct, because we have our internal [`InfoHash`](crate::shared::bit_torrent::info_hash::InfoHash)
//! struct.
//!
//! ```text
//! pub struct AnnounceWrapper {
//! pub announce_request: AnnounceRequest, // aquatic
//! pub info_hash: InfoHash, // our own
//! }
//! ```
//!
//! #### Announce Response
//!
//! **Announce response (UDP packet)**
//!
//! Offset | Type/Size | Name | Description | Hex | Decimal
//! -----------|-------------------|------------------|---------------------------------------------------------------------------------|-----------------|----------------------------
//! 0 | [`i32`](std::i32) | `action` | The action this is a reply to. | `0x00_00_00_01` | `1`: announce; `3`: error
//! 4 | [`i32`](std::i32) | `transaction_id` | Must match the `transaction_id` sent in the announce request. | `0x00_00_00_00` | `0`
//! 8 | [`i32`](std::i32) | `interval` | The number of seconds the peer should wait until re-announcing itself. | `0x00_00_00_00` | `0`
//! 12 | [`i32`](std::i32) | `leechers` | The number of peers in the swarm that has not finished downloading. | `0x00_00_00_00` | `0`
//! 16 | [`i32`](std::i32) | `seeders` | The number of peers in the swarm that has finished downloading and are seeding. | `0x00_00_00_00` | `0`
//! | | | | |
//! 20 + 6 * n | [`i32`](std::i32) | `IP address` | The IP of a peer in the swarm. | `0x69_69_69_69` | `1768515945`
//! 24 + 6 * n | [`i16`](std::i16) | `TCP port` | The peer's listen port. | `0x44_8C` | `17548`
//! 20 + 6 * N | | | | |
//!
//! > **NOTICE**: `Hex` column is a signed 2's complement.
//!
//! > **NOTICE**: `IP address` should always be set to 0 when the peer is using
//! `IPv6`.
//!
//! **Sample announce response (UDP packet)**
//!
//! UDP packet bytes (fixed part):
//!
//! ```text
//! Offset: [ 0, 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15, 16, 17, 18, 19]
//! Decimal: [ 0, 0, 0, 1, 162, 249, 84, 72, 0, 0, 0, 120, 0, 0, 0, 0, 0, 0, 0, 1]
//! Hex: [ 0x00, 0x00, 0x00, 0x01, 0xA2, 0xF9, 0x54, 0x48, 0x00, 0x00, 0x00, 0x78, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x01]
//! Param: [<------- action ------>,<-- transaction_id --->,<----- interval ------>,<----- leechers ------>,<------ seeders ------>]
//! ```
//!
//! UDP packet fields (fixed part):
//!
//! Offset | Type/Size | Name | Bytes (Big Endian) | Hex | Decimal
//! -----------|-------------------|------------------|---------------------|-----------------|----------------------------
//! 0 | [`i32`](std::i32) | `action` | `[0, 0, 0, 0]` | `0x00_00_00_01` | `1`: announce; `3`: error
//! 4 | [`i32`](std::i32) | `transaction_id` | `[162,249,84,72]` | `0xA2_F9_54_48` | `-1560718264`
//! 8 | [`i32`](std::i32) | `interval` | `[0,0,0,120]` | `0x00_00_00_78` | `120`
//! 12 | [`i32`](std::i32) | `leechers` | `[0, 0, 0, 0]` | `0x00_00_00_00` | `0`
//! 16 | [`i32`](std::i32) | `seeders` | `[0, 0, 0, 1]` | `0x00_00_00_01` | `1`
//!
//! This is the fixed part of the packet. After the fixed part there is
//! dynamically generated data with the list of peers in the swarm. The list may
//! include `IPv4` or `IPv6` peers, depending on the address family of the
//! underlying UDP packet. I.e. packets from a v4 address use the v4 format,
//! those from a v6 address use the v6 format.
//!
//! UDP packet bytes (`IPv4` peer list):
//!
//! ```text
//! Offset: [ 20, 21, 22, 23, 24, 25]
//! Decimal: [ 105, 105, 105, 105, 08, 140]
//! Hex: [ 0x69, 0x69, 0x69, 0x69, 0x44, 0x8C]
//! Param: [<----- IP address ---->,<-TCP port>]
//! ```
//!
//! > **NOTICE**: there are 6 bytes per peer (4 bytes for the `IPv4` address and
//! 2 bytes for the TCP port).
//!
//! UDP packet fields (`IPv4` peer list):
//!
//! Offset | Type/Size | Name | Bytes (Big Endian) | Hex | Decimal
//! ---------|-------------------|--------------|---------------------|-----------------|----------------------------
//! 20 + 6*n | [`i32`](std::i32) | `IP address` | `[105,105,105,105]` | `0x69_69_69_69` | `1768515945`
//! 24 + 6*n | [`i16`](std::i16) | `TCP port` | `[8,140]` | `0x44_8C` | `17548`
//! 20 + 6*N | | | | |
//!
//! UDP packet bytes (`IPv6` peer list):
//!
//! ```text
//! Offset: [ 20, 21, 22, 23, 24, 25, 26, 27, 28, 29, 30, 31, 32, 33, 34, 35, 36, 37]
//! Decimal: [ 105, 105, 105, 105, 105, 105, 105, 105, 105, 105, 105, 105, 105, 105, 105, 105, 08, 140]
//! Hex: [ 0x69, 0x69, 0x69, 0x69, 0x69, 0x69, 0x69, 0x69, 0x69, 0x69, 0x69, 0x69, 0x69, 0x69, 0x69, 0x69, 0x44, 0x8C]
//! Param: [<-------------------------------------------- IP address ------------------------------------->,<-TCP port>]
//! ```
//!
//! > **NOTICE**: there are 18 bytes per peer (16 bytes for the `IPv6` address and
//! 2 bytes for the TCP port).
//!
//! UDP packet fields (`IPv6` peer list):
//!
//! Offset | Type/Size | Name | Bytes (Big Endian) | Hex | Decimal
//! ----------|---------------------|--------------|---------------------------------------------------------------------|-----------------------------------------------------|-------------------------------------------
//! 20 + 18*n | [`i128`](std::i128) | `IP address` | `[105,105,105,105,105,105,105,105,105,105,105,105,105,105,105,105]` | `0x69_69_69_69_69_69_69_69_69_69_69_69_69_69_69_69` | `140116268732151132014330720707198675305`
//! 24 + 18*n | [`i16`](std::i16) | `TCP port` | `[8,140]` | `0x44_8C` | `17548`
//! 20 + 18*N | | | | |
//!
//! > **NOTICE**: `Hex` column is a signed 2's complement.
//!
//! > **NOTICE**: the peer list does not include the peer that sent the announce
//! request.
//!
//! **Announce response (struct)**
//!
//! The [`AnnounceResponse`](aquatic_udp_protocol::response::AnnounceResponse)
//! struct will have the following fields:
//!
//! Field | Type | Example
//! --------------------|------------------------------------------------------------------------|--------------
//! `transaction_id` | [`TransactionId`](aquatic_udp_protocol::common::TransactionId) | `-1560718264`
//! `announce_interval` | [`AnnounceInterval`](aquatic_udp_protocol::common::AnnounceInterval) | `120`
//! `leechers` | [`NumberOfPeers`](aquatic_udp_protocol::common::NumberOfPeers) | `0`
//! `seeders` | [`NumberOfPeers`](aquatic_udp_protocol::common::NumberOfPeers) | `1`
//! `peers` | Vector of [`ResponsePeer`](aquatic_udp_protocol::common::ResponsePeer) | `[]`
//!
//! **Announce specification**
//!
//! Original specification in [BEP 15. UDP Tracker Protocol for `BitTorrent`](https://www.bittorrent.org/beps/bep_0015.html).
//!
//! ### Scrape
//!
//! The `scrape` request allows a peer to get [swarm metadata](crate::core::torrent::SwarmMetadata)
//! for multiple torrents at the same time.
//!
//! The response contains the [swarm metadata](crate::core::torrent::SwarmMetadata)
//! for that torrent:
//!
//! - [complete](crate::core::torrent::SwarmMetadata::complete)
//! - [downloaded](crate::core::torrent::SwarmMetadata::downloaded)
//! - [incomplete](crate::core::torrent::SwarmMetadata::incomplete)
//!
//! > **NOTICE**: up to about 74 torrents can be scraped at once. A full scrape
//! can't be done with this protocol. This is a limitation of the UDP protocol.
//! Defined with a hardcoded const [`MAX_SCRAPE_TORRENTS`](crate::shared::bit_torrent::common::MAX_SCRAPE_TORRENTS).
//! Refer to [issue 262](https://github.com/torrust/torrust-tracker/issues/262)
//! for more information about this limitation.
//!
//! #### Scrape Request
//!
//! **Scrape request (UDP packet)**
//!
//! Offset | Type/Size | Name | Description | Hex | Decimal
//! ----------|-------------------|------------------|------------------------------------------------------------------------|-----------------------------------------------------------------|--------------------------------------------------
//! 0 | [`i64`](std::i64) | `connection_id` | The `connection_id` retrieved from the establishing of the connection. | `0xC5_58_7C_09_08_48_D8_37` | `-4226491872051668937`
//! 8 | [`i32`](std::i32) | `action` | Action identifying the scrape request | `0x00_00_00_02` | `2` (`Scrape`)
//! 12 | [`i32`](std::i32) | `transaction_id` | Randomly generated by the client. | `0xA2_F9_54_48` | `-1560718264`
//! 16 + 20*n | 20 bytes | `info_hash` | The infohash of the torrent being scraped. | `0x03_84_05_48_64_3A_F2_A7_B6_3A_9F_5C_BC_A3_48_BC_71_50_CA_3A` | `20071130873666512363095721859061691407221705274`
//! 16 + 20*N | | | |
//!
//! The last field (`info_hash`) is repeated for each torrent being scraped.
//!
//! Dynamic part of the UDP packet:
//!
//! Offset | Type/Size | Name | Description | Hex | Decimal
//! ----------|-------------------|-------------|--------------------------------------------|-----------------------------------------------------------------|---------------------------------------------------
//! 16 + 20*n | 20 bytes | `info_hash` | The infohash of the torrent being scraped. | `0x03_84_05_48_64_3A_F2_A7_B6_3A_9F_5C_BC_A3_48_BC_71_50_CA_3A` | `20071130873666512363095721859061691407221705274`
//!
//! **Sample scrape request (UDP packet)**
//!
//! UDP packet bytes (fixed part):
//!
//! ```text
//! Offset: [ 0, 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15, 16, 17, 18, 19, 20, 21, 22, 23, 24, 25, 26, 27, 28, 29, 30, 31, 32, 33, 34, 35]
//! Decimal: [ 197, 88, 124, 9, 8, 72, 216, 55, 0, 0, 0, 2, 162, 249, 84, 72, 3, 132, 5, 72, 100, 58, 242, 167, 182, 58, 159, 92, 188, 163, 72, 188, 113, 80, 202, 58]
//! Hex: [ 0xC5, 0x58, 0x7C, 0x09, 0x08, 0x48, 0xD8, 0x37, 0x00, 0x00, 0x00, 0x02, 0xA2, 0xF9, 0x54, 0x48, 0x03, 0x84, 0x05, 0x48, 0x64, 0x3A, 0xF2, 0xA7, 0xB6, 0x3A, 0x9F, 0x5C, 0xBC, 0xA3, 0x48, 0xBC, 0x71, 0x50, 0xCA, 0x3A]
//! Param: [<--------------- connection_id --------------->,<--------- action ---->,<-- transaction_id --->,<--------------------------------------------------------- info_hash ------------------------------------------------->]
//! ```
//!
//! UDP packet bytes (infohash list):
//!
//! ```text
//! Offset: [ 16, 17, 18, 19, 20, 21, 22, 23, 24, 25, 26, 27, 28, 29, 30, 31, 32, 33, 34, 35]
//! Decimal: [ 3, 132, 5, 72, 100, 58, 242, 167, 182, 58, 159, 92, 188, 163, 72, 188, 113, 80, 202, 58]
//! Hex: [ 0x03, 0x84, 0x05, 0x48, 0x64, 0x3A, 0xF2, 0xA7, 0xB6, 0x3A, 0x9F, 0x5C, 0xBC, 0xA3, 0x48, 0xBC, 0x71, 0x50, 0xCA, 0x3A]
//! Param: [<--------------------------------------------------------- info_hash ------------------------------------------------->]
//! ```
//!
//! UDP packet fields:
//!
//! Offset | Type/Size | Name | Bytes Dec (Big Endian) | Hex | Decimal
//! -------|-------------------|------------------|--------------------------------------------------------------------------|-----------------------------------------------------------------|--------------------------------------------------
//! 0 | [`i64`](std::i64) | `connection_id` | `[197,88,124,9,8,72,216,55]` | `0xC5_58_7C_09_08_48_D8_37` | `-4226491872051668937`
//! 4 | [`i32`](std::i32) | `action` | `[0, 0, 0, 2]` | `0x00_00_00_02` | `2` (`Scrape`)
//! 8 | [`i32`](std::i32) | `transaction_id` | `[162,249,84,72]` | `0xA2_F9_54_48` | `-1560718264`
//! 8 | 20 bytes | `info_hash` | `[3,132,5,72,100,58,242,167,182,58,159,92,188,163,72,188,113,80,202,58]` | `0x03_84_05_48_64_3A_F2_A7_B6_3A_9F_5C_BC_A3_48_BC_71_50_CA_3A` | `20071130873666512363095721859061691407221705274`
//!
//! **Scrape request (parsed struct)**
//!
//! After parsing the UDP packet, the [`ScrapeRequest`](aquatic_udp_protocol::request::ScrapeRequest)
//! struct will look like this:
//!
//! Field | Type | Example
//! -----------------|----------------------------------------------------------------|----------------------------------------------------------------------------
//! `connection_id` | [`ConnectionId`](aquatic_udp_protocol::common::ConnectionId) | `-4226491872051668937`
//! `transaction_id` | [`TransactionId`](aquatic_udp_protocol::common::TransactionId) | `-1560718264`
//! `info_hashes` | Vector of [`InfoHash`](aquatic_udp_protocol::common::InfoHash) | `[[3,132,5,72,100,58,242,167,182,58,159,92,188,163,72,188,113,80,202,58]]`
//!
//! #### Scrape Response
//!
//! **Scrape response (UDP packet)**
//!
//! Offset | Type/Size | Name (BEP15 or libtorrent) | Description | Hex | Decimal
//! ----------|-------------------|-----------------------------|-------------------------------------------------------|-----------------|-----------------
//! 0 | [`i32`](std::i32) | `action` | Action identifying the connect request | `0x00_00_00_00` | `2` (`Scrape`)
//! 4 | [`i32`](std::i32) | `transaction_id` | Must match the `transaction_id` sent from the client. | `0xA2_F9_54_48` | `-1560718264`
//! 8 + 12*n | [`i32`](std::i32) | `seeders` or `complete` | The current number of connected seeds. | `0x00_00_00_00` | `0`
//! 12 + 12*n | [`i32`](std::i32) | `completed` or `downloaded` | The number of times this torrent has been downloaded. | `0x00_00_00_00` | `0`
//! 16 + 12*n | [`i32`](std::i32) | `leechers` or `incomplete` | The current number of connected leechers. | `0x00_00_00_00` | `0`
//! 8 + 12*N | | | | |
//!
//! > **NOTICE**: `Hex` column is a signed 2's complement.
//!
//! Dynamic part of the UDP packet:
//!
//! Offset | Type/Size | Name (BEP15 or libtorrent) | Description | Hex | Decimal
//! ----------|-------------------|-----------------------------|-------------------------------------------------------|-----------------|-----------------
//! 8 + 12*n | [`i32`](std::i32) | `seeders` or `complete` | The current number of connected seeds. | `0x00_00_00_00` | `0`
//! 12 + 12*n | [`i32`](std::i32) | `completed` or `downloaded` | The number of times this torrent has been downloaded. | `0x00_00_00_00` | `0`
//! 16 + 12*n | [`i32`](std::i32) | `leechers` or `incomplete` | The current number of connected leechers. | `0x00_00_00_00` | `0`
//! 8 + 12*N | | | | |
//!
//! For each info hash in the request there will be 3 32-bit integers (12 bytes)
//! in the response with the number of seeders, leechers and downloads.
//!
//! **Sample scrape response (UDP packet)**
//!
//! UDP packet bytes:
//!
//! ```text
//! Offset: [ 0, 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15, 16, 17, 18, 19]
//! Decimal: [ 0, 0, 0, 0, 203, 5, 94, 7, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0]
//! Hex: [0x00, 0x00, 0x00, 0x00, 0xCB, 0x05, 0x5E, 0x07, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00]
//! Param: [<------ action ------>,<-- transaction_id --->,<------ seeders ------>,<----- completed ----->,<------ leechers ----->]
//! ```
//!
//! UDP packet fields:
//!
//! Offset | Type/Size | Name | Bytes (Big Endian) | Hex | Decimal
//! -------|-------------------|------------------|--------------------|------------------|----------------
//! 0 | [`i32`](std::i32) | `action` | [0, 0, 0, 2] | `0x00_00_00_02` | `2` (`Scrape`)
//! 4 | [`i32`](std::i32) | `transaction_id` | [203, 5, 94, 7] | `0xA2_F9_54_48` | `-1560718264`
//! 8 | [`i32`](std::i32) | `seeders` | [0, 0, 0, 0] | `0x00_00_00_00` | `0`
//! 12 | [`i32`](std::i32) | `completed` | [0, 0, 0, 0] | `0x00_00_00_00` | `0`
//! 16 | [`i32`](std::i32) | `leechers` | [0, 0, 0, 0] | `0x00_00_00_00` | `0`
//!
//! > **NOTICE**: `Hex` column is a signed 2's complement.
//!
//! **Scrape response (struct)**
//!
//! Before building the UDP packet, the [`ScrapeResponse`](aquatic_udp_protocol::response::ScrapeResponse)
//! struct will look like this:
//!
//! Field | Type | Example
//! -----------------|-------------------------------------------------------------------------------------------------|---------------
//! `transaction_id` | [`TransactionId`](aquatic_udp_protocol::common::TransactionId) | `-1560718264`
//! `torrent_stats` | Vector of [`TorrentScrapeStatistics`](aquatic_udp_protocol::response::TorrentScrapeStatistics) | `[]`
//!
//! **Scrape specification**
//!
//! Original specification in [BEP 15. UDP Tracker Protocol for `BitTorrent`](https://www.bittorrent.org/beps/bep_0015.html).
//!
//! ## Errors
//!
//! ### Error Response
//!
//! **Error response (UDP packet)**
//!
//! Offset | Type/Size | Name | Description | Hex | Decimal
//! -------|-------------------|------------------|-------------------------------------------------------|-----------------------------|-----------------------
//! 0 | [`i32`](std::i32) | `action` | Action identifying the error response. | `0x00_00_00_03` | `3`
//! 4 | [`i32`](std::i32) | `transaction_id` | Must match the `transaction_id` sent from the client. | `0xCB_05_5E_07` | `-888840697`
//! 8 | N Bytes | `error_string` | Error description. | |
//!
//! ## Extensions
//!
//! Extensions described in [BEP 41. UDP Tracker Protocol Extensions](https://www.bittorrent.org/beps/bep_0041.html)
//! are not supported yet.
//!
//! ## Links
//!
//! - [BEP 15. UDP Tracker Protocol for `BitTorrent`](https://www.bittorrent.org/beps/bep_0015.html).
//! - [BEP 41. UDP Tracker Protocol Extensions](https://www.bittorrent.org/beps/bep_0041.html).
//! - [libtorrent - Bittorrent UDP-tracker protocol extension](https://www.rasterbar.com/products/libtorrent/udp_tracker_protocol.html).
//! - [XBTT Tracker. UDP tracker protocol](https://xbtt.sourceforge.net/udp_tracker_protocol.html).
//! - [Wikipedia: UDP tracker](https://en.wikipedia.org/wiki/UDP_tracker).
//!
//! ## Credits
//!
//! [Bittorrent UDP-tracker protocol extension](https://www.rasterbar.com/products/libtorrent/udp_tracker_protocol.html)
//! documentation by [Arvid Norberg](https://github.com/arvidn) was very
//! supportive in the development of this documentation. Some descriptions were
//! taken from the [libtorrent](https://www.rasterbar.com/products/libtorrent/udp_tracker_protocol.html).
use std::net::SocketAddr;
pub mod connection_cookie;
pub mod error;
pub mod handlers;
pub mod peer_builder;
pub mod request;
pub mod server;
/// Number of bytes.
pub type Bytes = u64;
/// The port the peer is listening on.
pub type Port = u16;
/// The transaction id. A random number generated byt the peer that is used to
/// match requests and responses.
pub type TransactionId = i64;
#[derive(Clone, Debug)]
pub(crate) struct UdpRequest {
payload: Vec<u8>,
from: SocketAddr,
}