Prakhar Pandey

backend & protocol engineer


← writes

How Tor actually routes your traffic

May 31, 2026

This is the first post in a three-part series built around hop6, a peer-to-peer terminal messenger I wrote that speaks only over Tor.

  1. How Tor actually routes your traffic (this post)
  2. Onion services and the rendezvous protocol
  3. Building hop6

Before any of hop6 makes sense, you need a clear picture of what Tor does to a packet. So this post ignores hop6 entirely and builds onion routing up from ordinary networking.

What ordinary routing leaks

When you open a normal TCP connection, every packet carries a source IP and a destination IP in the clear. Routers along the path read those addresses to forward the packet. That is the whole point: the network has to know where a packet is going.

  you            ISP / backbone routers                    server
  1.2.3.4  ───▶  R1  ───▶  R2  ───▶  R3  ───▶  R4  ───▶  93.184.x.x
           src=1.2.3.4  dst=93.184.x.x  (visible to every hop)

Even with TLS, the contents are encrypted but the metadata is not. Your ISP sees which servers you talk to, when, and how much. The server sees your IP. Any router in between sees both endpoints. The link between “who you are” and “what you are doing” is sitting right there in every packet header.

Onion routing breaks that link.

The core idea: layered encryption

Instead of talking to the destination directly, a Tor client relays its traffic through a chain of three volunteer relays, and wraps the data in three layers of encryption, one per relay. Each relay can peel exactly one layer. That layer tells it only one thing: who to hand the packet to next.

  message wrapped in 3 layers (think of an onion):

      ┌─────────────────────────────────────────┐
      │ E_guard( E_middle( E_exit( data ) ) )    │
      └─────────────────────────────────────────┘

  guard  peels E_guard   → sees "send rest to middle"
  middle peels E_middle  → sees "send rest to exit"
  exit   peels E_exit    → sees the actual data + destination

No single relay holds the whole picture:

  relay     knows who sent to it   knows final destination   knows payload
  ──────    ────────────────────   ───────────────────────   ────────────
  guard     YES (your IP)          no                         no
  middle    no (only guard)        no                         no
  exit      no (only middle)       YES                        YES (if not TLS)

The guard knows your IP but not where you are going. The exit knows the destination but not who you are. The middle knows neither and exists precisely so the guard and exit never talk directly.

Building the circuit (telescoping)

The client cannot just send a triple-wrapped packet out of nowhere; it first has to agree on a separate encryption key with each relay, without the later relays learning the client’s identity. Tor does this by extending the circuit one hop at a time, a process called telescoping.

  step 1:  you ⇄ guard            (handshake, derive key K1)
  step 2:  you ⇄ guard ⇄ middle   (handshake through guard, derive K2)
  step 3:  you ⇄ guard ⇄ middle ⇄ exit  (handshake through middle, derive K3)

Each handshake is an authenticated Diffie-Hellman exchange (Tor’s “ntor” handshake, built on Curve25519). Two things matter about it:

Crucially, the middle and exit relays complete their handshakes through the existing partial circuit. They never see the client’s IP; they only ever see the hop before them.

Cells: everything is the same size

Tor does not send arbitrary-length packets between relays. It chops traffic into fixed-size cells (512 bytes in the classic design). Fixed-size units make it much harder for an observer to fingerprint traffic by packet size, and they keep the relay logic uniform.

  variable-length app data
        │  split + padded
        ▼
  [cell][cell][cell][cell] ...   all identical in size

Where the relay list comes from

A client cannot trust a random relay it found somewhere. Tor runs a small set of directory authorities: trusted servers that, once an hour, vote on and sign a consensus document listing every known relay, its keys, and its flags (is it a valid guard, an exit, how much bandwidth, and so on). Clients download this consensus and pick relays from it. The signatures are what stop an attacker from feeding you a list of relays they control.

Guards: why the first hop is sticky

If a client picked three fresh random relays for every circuit, then over enough circuits it would eventually pick an attacker-controlled relay as the first hop, and an attacker who controls your first and last hop can often de-anonymize you by correlating timing. To limit this exposure, Tor picks a small, stable set of entry guards and reuses them for a long time. You are either unlucky once and stuck with it, or (much more likely) fine for months. It trades a little unlinkability for a large reduction in the chance of full compromise.

What Tor does and does not protect

Onion routing hides the link between your identity and your destination from any single relay and from network observers. It does not magically encrypt the last hop to the destination: the exit relay sees whatever the client sends it, so if you speak plain HTTP, the exit can read it. Use TLS end to end and the exit sees only ciphertext and the hostname.

It is also not a defense against a global passive adversary who can watch both ends of a circuit at once; traffic-correlation attacks remain the hard, open problem of low-latency anonymity networks.

The piece this leaves out

Everything above describes reaching the ordinary internet through an exit relay. But hop6 has no servers and never touches the clearnet: two peers talk directly, each reachable at a .onion address, with no exit node anywhere in the path. That needs a different mechanism entirely, the one that makes the address itself a public key and lets two hidden parties meet without either learning the other’s location.

That is onion services and the rendezvous protocol, in part 2.