Skip to content
UDP Tracker Protocol
step 1/5

Reading — step 1 of 5

Read

~3 min readTracker Communication

UDP Tracker Protocol

Do the arithmetic on HTTP announces. Each one costs a TCP handshake, HTTP request headers, response headers, and a teardown — several hundred bytes and two round-trips of latency for what is logically "here I am, who else is here?". Now multiply by a public tracker's load: millions of peers, each re-announcing every 30 minutes, across thousands of torrents. BEP 15 replaces the whole exchange with two UDP datagrams each way and a fixed binary layout.

Why there is a connect step at all

UDP has no handshake, and that is a security problem, not just a convenience: the source address of a datagram is trivially forged. A naive UDP tracker could be tricked into announcing victims into swarms, or used as a DDoS amplifier (small spoofed request in, large peer list out, aimed at the victim). The fix is a cheap proof of address ownership:

Step 1 — connect. You send a request containing a magic constant and a random transaction_id; the tracker replies with a connection_id. Only someone who can receive at the source address ever learns that value.

Step 2 — announce. You present the connection_id. No valid id, no service — spoofed announces die at step 1.

Connect, byte by byte

Request — exactly 16 bytes, every integer big-endian:

OffsetSizeFieldValue
08protocol_id0x41727101980 (magic)
84action0 = connect
124transaction_idrandom, chosen by you

Response — 16 bytes:

OffsetSizeField
04action (0, echoed)
44transaction_id (echoed — MUST match yours)
88connection_id

Check the echoed transaction_id before believing anything — a mismatched reply is stale or forged, so drop it. UDP also loses packets silently; BEP 15 prescribes retransmission with exponential backoff (15 × 2^n seconds).

The connection_id is short-lived by design: a client may keep using it for about a minute, and trackers honor it for at most two — after that you reconnect. Within that window one connect can front many requests (announces for every torrent you manage, scrapes), which is where the savings multiply. The routine 30-minute re-announce does need a fresh connect first — still just two tiny packets instead of a whole TCP + HTTP exchange.

Announce (step 2), for context

The announce packet is a fixed 98 bytes: connection_id(8) action=1(4) transaction_id(4) info_hash(20) peer_id(20) downloaded(8) left(8) uploaded(8) event(4) ip(4) key(4) num_want(4) port(2). The reply is action(4) transaction_id(4) interval(4) leechers(4) seeders(4) followed by 6-byte compact peer entries — the same 4-byte-IP + 2-byte-port format the HTTP tracker uses.

Your exercise

Build CONNECT-REQ and parse CONNECT-RESP, both as hex. Mistakes the grader catches:

  1. The magic constant is only 6 non-zero bytes. 0x41727101980 fits in 04 17 27 10 19 80; the field is 8 bytes, so left-pad with zeros: CONNECT-REQ 12345678 must print exactly 00000417271019800000000012345678 (32 hex chars). Emit a 6-byte protocol_id and you produce 28 chars and fail every BUILD test.
  2. Dropping leading zeros on output. The hidden test expects transaction_id=00000001 — fixed-width, zero-padded hex (8 chars for the id, 16 for connection_id), never 1.
  3. Parsing the response with the request layout. The response is action(4) + transaction_id(4) + connection_id(8) — there is no protocol_id. Skip 8 bytes first and you will report garbage instead of action=0.

Discussion

Ask a question, share an insight, or help someone who’s stuck.

Sign in to post a comment or reply.

Loading…