Expand description

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 as an alternative to the HTTP tracker. The UDP tracker is more efficient than the HTTP tracker because it uses UDP instead of TCP.

Refer to the bit_torrent module for more information about the BitTorrent protocol.

Refer to BEP 15. UDP Tracker Protocol for BitTorrent and to BEP 41. UDP Tracker Protocol Extensions for more information about the UDP tracker protocol.

NOTICE: BEP-41 is not implemented yet.

NOTICE: we are using the aquatic_udp_protocol crate so requests and responses are handled by it.

NOTICE: all values are send in network byte order (big endian).

Table of Contents

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 crate and then handled by the Tracker struct. And then the response is also build using the aquatic_udp_protocol and converted to a UDP packet.

UDP packet -> Aquatic Struct Request -> [Torrust Struct Request] ->  Tracker -> Aquatic Struct Response -> UDP packet

For the Announce request there is a wrapper struct AnnounceWrapper. It was added to add an extra field with the internal 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.

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)

OffsetType/SizeNameDescriptionHexDecimal
0i64protocol_idMagic constant that will identify the protocol.0x00_00_04_17_27_10_19_804497486125440
8i32actionAction identifying the connect request.0x00_00_00_000
12i32transaction_idRandomly generated by the client.0x34_FA_A1_F9-888840697

Sample connect request (UDP packet)

UDP packet bytes:

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:

OffsetType/SizeNameBytes Dec (Big Endian)HexDecimal
0i64protocol_id[0, 0, 4, 23, 39, 16, 25, 128]0x00_00_04_17_27_10_19_804497486125440
4i32action[0, 0, 0, 0]0x00_00_00_000
8i32transaction_id[35, 63, 226, 1]0xCB_05_5E_07-888840697

Connect request (parsed struct)

After parsing the UDP packet, the ConnectRequest request struct will look like this:

FieldTypeExample
transaction_idTransactionId1950635409
Connect Response

Connect response (UDP packet)

OffsetType/SizeNameDescriptionHexDecimal
0i64actionAction identifying the connect request0x00_00_00_000
4i32transaction_idMust match the transaction_id sent from the client.0xCB_05_5E_07-888840697
8i32connection_idGenerated 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:

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:

OffsetType/SizeNameBytes (Big Endian)HexDecimal
0i64action[0, 0, 0, 0]0x00_00_00_000
4i64transaction_id[203, 5, 94, 7]0xCB_05_5E_07-888840697
8i64connection_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 struct will look like this:

FieldTypeExample
connection_idConnectionId-4226491872051668937
transaction_idTransactionId-888840697

Connect specification

Original specification in BEP 15. UDP Tracker Protocol for BitTorrent.

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)

OffsetType/SizeNameDescriptionHexDecimal
0i64connection_idThe connection id acquired from establishing the connection.0xC5_58_7C_09_08_48_D8_37-4226491872051668937
8i32actionAction for announce request.0x00_00_00_011
12i32transaction_idRandomly generated by the client.0xA2_F9_54_48-1560718264
1620-byteinfo_hashThe 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_3A20071130873666512363095721859061691407221705274
3620-bytepeer_idThe 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_44259430336069436570531165609119312093997849130564
56i64downloadedThe number of bytes the peer has downloaded so far.0x00_00_00_00_00_00_00_000
64i64leftThe number of bytes left to download by the peer.0x00_00_00_00_00_00_00_000
72i64uploadedThe number of bytes the peer has uploaded so far.0x00_00_00_00_00_00_00_000
80i32eventThe event the peer is reporting to the tracker.0x0, 0x1, 0x2, 0x30: none; 1: completed; 2: started; 3: stopped
84i32IP addressThe peer IP. Ignored by the tracker. It uses the Sender’s IP.0x00_00_00_000
88i32keyA unique key that is randomized by the client.0xEF_34_95_D6-281766442
92i32num_wantThe maximum number of peers the peer wants in the response.0x00_00_00_C8200
96i16portThe port the peer is listening on.0x44_8C17548

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).

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:

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:

OffsetType/SizeNameBytes Dec (Big Endian)HexDecimal
0i64connection_id[197,88,124,9,8,72,216,55]0xC5_58_7C_09_08_48_D8_37-4226491872051668937
8i32action[0,0,0,1]0x00_00_00_011
12i32transaction_id[162,249,84,72]0xA2_F9_54_48-1560718264
1620 bytesinfo_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_3A20071130873666512363095721859061691407221705274
3620 bytespeer_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_44259430336069436570531165609119312093997849130564
56i64downloaded[0,0,0,0,0,0,0,0]0x00_00_00_00_00_00_00_000
64i64left[0,0,0,0,0,0,0,0]0x00_00_00_00_00_00_00_000
72i64uploaded[0,0,0,0,0,0,0,0]0x00_00_00_00_00_00_00_000
80i32event[0,0,0,2]0x00_00_00_022 (Started)
84i32IP address[0,0,0,0]0x00_00_00_000
88i32key[239,52,149,214]0xEF_34_95_D6-281766442
92i32num_want[0,0,0,200]0x00_00_00_C8200
96i16port[8,140]0x44_8C17548
981 byteOption-Type[2]0x022
992 byteLength Byte[1,47]0x01_2F303
101N bytes

NOTICE: bytes after offset 98 are part of the BEP-41. UDP Tracker Protocol Extensions. 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 for more information.

Announce request (parsed struct)

After parsing the UDP packet, the AnnounceRequest struct will contain the following fields:

FieldTypeExample
connection_idConnectionId-4226491872051668937
transaction_idTransactionId-1560718264
info_hashInfoHash[3,132,5,72,100,58,242,167,182,58,159,92,188,163,72,188,113,80,202,58]
peer_idPeerId[45,113,66,52,52,49,48,45,41,83,100,126,100,101,52,120,77,112,54,68]
bytes_downloadedNumberOfBytes0
bytes_uploadedTransactionId0
eventAnnounceEventStarted
ip_addressIpv4AddrNone
peers_wantedNumberOfPeers200
portPort17548

NOTICE: the peers_wanted field is the num_want field in the UDP packet.

We are using a wrapper struct for the aquatic AnnounceRequest struct, because we have our internal InfoHash struct.

pub struct AnnounceWrapper {
    pub announce_request: AnnounceRequest, // aquatic
    pub info_hash: InfoHash, // our own
}
Announce Response

Announce response (UDP packet)

OffsetType/SizeNameDescriptionHexDecimal
0i32actionThe action this is a reply to.0x00_00_00_011: announce; 3: error
4i32transaction_idMust match the transaction_id sent in the announce request.0x00_00_00_000
8i32intervalThe number of seconds the peer should wait until re-announcing itself.0x00_00_00_000
12i32leechersThe number of peers in the swarm that has not finished downloading.0x00_00_00_000
16i32seedersThe number of peers in the swarm that has finished downloading and are seeding.0x00_00_00_000
20 + 6 * ni32IP addressThe IP of a peer in the swarm.0x69_69_69_691768515945
24 + 6 * ni16TCP portThe peer’s listen port.0x44_8C17548
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):

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):

OffsetType/SizeNameBytes (Big Endian)HexDecimal
0i32action[0, 0, 0, 0]0x00_00_00_011: announce; 3: error
4i32transaction_id[162,249,84,72]0xA2_F9_54_48-1560718264
8i32interval[0,0,0,120]0x00_00_00_78120
12i32leechers[0, 0, 0, 0]0x00_00_00_000
16i32seeders[0, 0, 0, 1]0x00_00_00_011

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):

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):

OffsetType/SizeNameBytes (Big Endian)HexDecimal
20 + 6*ni32IP address[105,105,105,105]0x69_69_69_691768515945
24 + 6*ni16TCP port[8,140]0x44_8C17548
20 + 6*N

UDP packet bytes (IPv6 peer list):

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):

OffsetType/SizeNameBytes (Big Endian)HexDecimal
20 + 18*ni128IP 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_69140116268732151132014330720707198675305
24 + 18*ni16TCP port[8,140]0x44_8C17548
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 struct will have the following fields:

FieldTypeExample
transaction_idTransactionId-1560718264
announce_intervalAnnounceInterval120
leechersNumberOfPeers0
seedersNumberOfPeers1
peersVector of ResponsePeer[]

Announce specification

Original specification in BEP 15. UDP Tracker Protocol for BitTorrent.

Scrape

The scrape request allows a peer to get swarm metadata for multiple torrents at the same time.

The response contains the swarm metadata for that torrent:

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. Refer to issue 262 for more information about this limitation.

Scrape Request

Scrape request (UDP packet)

OffsetType/SizeNameDescriptionHexDecimal
0i64connection_idThe connection_id retrieved from the establishing of the connection.0xC5_58_7C_09_08_48_D8_37-4226491872051668937
8i32actionAction identifying the scrape request0x00_00_00_022 (Scrape)
12i32transaction_idRandomly generated by the client.0xA2_F9_54_48-1560718264
16 + 20*n20 bytesinfo_hashThe 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_3A20071130873666512363095721859061691407221705274
16 + 20*N

The last field (info_hash) is repeated for each torrent being scraped.

Dynamic part of the UDP packet:

OffsetType/SizeNameDescriptionHexDecimal
16 + 20*n20 bytesinfo_hashThe 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_3A20071130873666512363095721859061691407221705274

Sample scrape request (UDP packet)

UDP packet bytes (fixed part):

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):

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:

OffsetType/SizeNameBytes Dec (Big Endian)HexDecimal
0i64connection_id[197,88,124,9,8,72,216,55]0xC5_58_7C_09_08_48_D8_37-4226491872051668937
4i32action[0, 0, 0, 2]0x00_00_00_022 (Scrape)
8i32transaction_id[162,249,84,72]0xA2_F9_54_48-1560718264
820 bytesinfo_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_3A20071130873666512363095721859061691407221705274

Scrape request (parsed struct)

After parsing the UDP packet, the ScrapeRequest struct will look like this:

FieldTypeExample
connection_idConnectionId-4226491872051668937
transaction_idTransactionId-1560718264
info_hashesVector of 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)

OffsetType/SizeName (BEP15 or libtorrent)DescriptionHexDecimal
0i32actionAction identifying the connect request0x00_00_00_002 (Scrape)
4i32transaction_idMust match the transaction_id sent from the client.0xA2_F9_54_48-1560718264
8 + 12*ni32seeders or completeThe current number of connected seeds.0x00_00_00_000
12 + 12*ni32completed or downloadedThe number of times this torrent has been downloaded.0x00_00_00_000
16 + 12*ni32leechers or incompleteThe current number of connected leechers.0x00_00_00_000
8 + 12*N

NOTICE: Hex column is a signed 2’s complement.

Dynamic part of the UDP packet:

OffsetType/SizeName (BEP15 or libtorrent)DescriptionHexDecimal
8 + 12*ni32seeders or completeThe current number of connected seeds.0x00_00_00_000
12 + 12*ni32completed or downloadedThe number of times this torrent has been downloaded.0x00_00_00_000
16 + 12*ni32leechers or incompleteThe current number of connected leechers.0x00_00_00_000
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:

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:

OffsetType/SizeNameBytes (Big Endian)HexDecimal
0i32action[0, 0, 0, 2]0x00_00_00_022 (Scrape)
4i32transaction_id[203, 5, 94, 7]0xA2_F9_54_48-1560718264
8i32seeders[0, 0, 0, 0]0x00_00_00_000
12i32completed[0, 0, 0, 0]0x00_00_00_000
16i32leechers[0, 0, 0, 0]0x00_00_00_000

NOTICE: Hex column is a signed 2’s complement.

Scrape response (struct)

Before building the UDP packet, the ScrapeResponse struct will look like this:

FieldTypeExample
transaction_idTransactionId-1560718264
torrent_statsVector of TorrentScrapeStatistics[]

Scrape specification

Original specification in BEP 15. UDP Tracker Protocol for BitTorrent.

Errors

Error Response

Error response (UDP packet)

OffsetType/SizeNameDescriptionHexDecimal
0i32actionAction identifying the error response.0x00_00_00_033
4i32transaction_idMust match the transaction_id sent from the client.0xCB_05_5E_07-888840697
8N Byteserror_stringError description.

Extensions

Extensions described in BEP 41. UDP Tracker Protocol Extensions are not supported yet.

Credits

Bittorrent UDP-tracker protocol extension documentation by Arvid Norberg was very supportive in the development of this documentation. Some descriptions were taken from the libtorrent.

Modules

  • Logic for generating and verifying connection IDs.
  • Error types for the UDP server.
  • Handlers for the UDP server.
  • Logic to extract the peer info from the announce request.
  • UDP request types.
  • Module to handle the UDP server instances.

Constants

  • The maximum number of bytes in a UDP packet.
  • A magic 64-bit integer constant defined in the protocol that is used to identify the protocol.

Type Aliases

  • Number of bytes.
  • The port the peer is listening on.
  • The transaction id. A random number generated byt the peer that is used to match requests and responses.