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