Skip to content

How It Works ​

One Access is a thin iOS shell around a small Go kernel. The kernel is a trimmed reimplementation of the client half of cloudflared access tcp, built to run inside an iOS Network Extension.

The pieces ​

  • accesskit — dials an Access-fronted hostname over a WebSocket, authenticates with an Access JWT or a service token, and exposes the tunnel as a plain net.Conn. It also carries the bidirectional byte pump used to pipe a local flow to the origin.
  • nettun — a userspace TCP/IP tunnel on a gVisor netstack. It turns the IP packets from the iOS utun into TCP flows, dials each one through accesskit, and pipes bytes both ways. It also answers DNS for configured .internal names with their distinct virtual IPs. Unknown names return NXDOMAIN; AAAA queries for known names return no IPv6 address.
  • login — Cloudflare Access interactive login: the NaCl-box token-transfer flow that yields an app JWT.
  • mobile — the gomobile-bound facade the Swift side calls.

The data path ​

  1. Your SSH client connects to myhost.internal. iOS routes that DNS query and the resulting TCP traffic into the packet tunnel.
  2. The destination IP selects one host from the routing table. Only then does accesskit dial the Access edge with that host's cached token (if any). An authentication rejection notifies the user to sign in to that host and retry. Starting the VPN itself does not probe or authenticate hosts.
  3. Bytes are pumped in both directions between the local flow and the edge connection. The edge routes them to the origin service behind your tunnel.

Because the WebSocket dial to Cloudflare's edge uses the phone's real interface (a protected socket), the edge connection escapes the very tunnel it's carrying — no loop.

Why a userspace netstack ​

An iOS Network Extension can't open arbitrary kernel sockets for the traffic it carries, and it runs under a tight memory budget. A gVisor netstack lets the kernel turn raw IP packets into ordinary Go net.Conn flows entirely in userspace, so the same accesskit code runs unchanged on desktop and on iOS.

Attribution ​

The kernel is derived from cloudflared (Apache-2.0): the WebSocket handshake, the net.Conn adapter, and the Access token-transfer flow, trimmed for mobile.