Skip to main content

Gateways and port mapping

FREEHOP / NETWORK MODELDesktop gateway
◈Browser
◇Desktop gateway
◈Desktop player

The participant offers a bounded TURN gateway through its router.

A desktop participant offers a gateway through a router port mapping.

A gateway is a small TURN server that runs on a desktop participant's own machine, made reachable from the internet through the participant's router. It is not a third-party relay: it is the participant's own front door, and only the people in that participant's session get a key.

Why a front door helps​

Take Ben, on a phone hotspot behind a carrier NAT that picks a new random port for every destination, and Dani, who uses the desktop app at home. Ben's NAT makes his address unpredictable, and Dani's home router drops packets it was not expecting. A direct route between them usually fails.

Dani's router can do something about that: it supports UPnP. So Dani's app asks the router to forward a port to her machine, and runs a TURN server behind it. Now Ben has an address that accepts his packets. His browser connects to Dani's gateway, the gateway hands the packets to Dani, and the path is reported as gateway. In the home-lab network tests this was scenario two-peer-desktop-host, three passes out of three, with 37 to 66 KB of gate traffic per run.

The same front door works for Omar, whose office blocks all UDP: his browser reaches Dani's gateway with TURN over TCP (scenario udpblock-gateway).

How the gateway becomes reachable​

When the desktop app first asks for its gateway, Freehop:

  1. asks the router for listener port mappings, trying PCP (RFC 6887), then NAT-PMP (RFC 6886), then UPnP IGD v1 and v2;
  2. starts a TURN server on the machine's LAN address, listening on UDP and TCP port 3478 by default;
  3. maps each relayed port on demand (49160 to 49359 by default), requesting the same external port as the internal one, and releases that mapping when its allocation ends.

A machine with a public address skips the mapping step. If the router reports a private or carrier-grade NAT address as its external address, the gateway is not offered at all, because nobody outside could reach it. If you forward ports by hand, pass externalAddress and portMapping: false.

Not every router can do this

Routers without PCP, NAT-PMP or UPnP cannot map a port, and participants behind carrier-grade NAT have no public address to map. Their desktop app then joins as an ordinary peer, and the other steps of the ladder (host node, forwarding) remain available. Port mapping passed the home-lab test against miniupnpd and unit tests against simulated routers; physical routers are not yet verified.

Keys for one room and one person​

A gateway never hands out a general password. Dani's privileged gateway process mints a credential for each peer, for this room only, following the TURN REST convention:

username = "<unix expiry>:<first 8 characters of the room tag>:<recipient peer id>"
credential = base64( HMAC-SHA1( gateway secret, username ) )
  • The credential travels to Ben inside a sealed caps envelope, so the gate never sees it.
  • Credentials go only to authenticated room members, never to a peer that a gate merely announced.
  • They expire after 2 hours by default and are renewed at half-life. credentialTtlSeconds can be set from 1 to 86400 seconds; the server rejects credentials extending beyond its configured lifetime.
  • The gateway accepts only rooms its owner told it to serve. On a ticket rotation, the entire old room epoch is revoked and all its allocations are torn down, including unreported aliases. Update every remaining client and host.
  • The gateway's signing key stays in its privileged process. Dani's page requests bounded credentials through a broker.

What a gateway refuses​

A TURN server on someone's home machine must not become a proxy into their home. Freehop's gateway:

  • refuses loopback, link-local, multicast, private and selected IPv6 transition destinations (6to4, Teredo and local-use NAT64) by default;
  • keeps services on the host itself unreachable (the machine's own addresses only work relay to relay);
  • bounds unauthenticated UDP errors and Binding answers per source and globally to limit reflection;
  • accepts at most 16 TCP connections per source address, with a 10-second deadline to authenticate;
  • caps usage at 6 allocations per username, 32 allocations per room and 64 in total; bandwidth caps are 4 Mbit/s per allocation, 20 Mbit/s per room and 40 Mbit/s in total, separately per direction.

Media stays DTLS-SRTP encrypted end to end, so the gateway relays ciphertext it cannot read. The TURN realm is peerlane, Freehop's codename, which is why that name appears on the wire.

A front door for the whole session​

A gateway can also help two other people. Ben and Kai are both behind random-port NATs, so they cannot reach each other, but both can reach Dani's gateway. When their own pair runs out of options, the session phase adds Dani's gateway to their ICE servers. Each of them allocates a relay on it, and the gateway delivers traffic between its own allocations internally, without depending on the router's hairpinning. Their path is reported as relay via Dani (home-lab test scenario hard-pair-gateway).

That traffic uses Dani's upload. It stays inside the session, and the quotas above bound it.

Using it in your app​

The Electron helper runs the gateway in the main process and exposes it to your page. connect() finds it automatically, allows the room on it and offers it to the room's peers with per-peer credentials. In other Node.js programs, startGateway() from freehop/relay gives you the same gateway directly.

Electron 28 and newer can alternatively pin WebRTC's UDP port range (webContents.setWebRTCUDPPortRange) and map that range directly. Freehop's gateway approach needs no cooperation from Chromium.

Next​

Host nodes bring the same front door to sessions where no participant runs the desktop app.