Decisions

Why tunnels work the way they do. What they do is the feature page; what they protect is Security.

Why does the tunnel only dial out?

lnk tunnel open opens one WebSocket to the relay, and every public request comes back over it, many at once, with responses streamed to the visitor as they're produced. The user's machine never opens an inbound port, so it works behind any router and nothing on it listens for the internet.

Who owns a name under the relay's domain?

The user a token belongs to. <you> in <app>.<you>.local.link comes from the login, never from the request, so nobody else can claim a name under it, and a reconnecting lnk gets the same URL back.

Who can sign up?

GitHub accounts on the relay's invite list (LINK_GITHUB_ALLOW), logging in through the relay's own GitHub OAuth app. * opens it to any GitHub account, with the extra checks in open signups, because open relays attract abuse.

Why does a tunnel have to say who can reach it?

lnk tunnel open refuses to start without --public, --github or --auth. An unusual URL isn't a secret: tunnel hostnames show up in public Certificate Transparency logs, so going public is a choice the user makes out loud.

How do you let in only some people?

With a GitHub sign-in per visitor, checked at the relay (--github). With one shared password, anyone who has it gets in, and many addresses guessing can use up its wrong-password allowance. A sign-in per person has neither problem, and most of the people a developer shares with have a GitHub account. The relay's own OAuth app does it, so a tunnel needs no setup.

How does a sign-in reach the tunnel?

GitHub sends the browser back to the bare domain, which hands a one-time code to the tunnel's host, where the relay sets a host-only cookie. The OAuth app has one callback URL, and a cookie set on the bare domain would reach every tunnel, since local.link isn't on the Public Suffix List. A nonce cookie from the tunnel's host ties the code to the browser that started the sign-in.

Why does the relay check passwords and sign-ins?

So nothing reaches the user's machine until a visitor is let in, and the app never sees the password or the sign-in cookie: the relay strips both before forwarding. lnk refuses to serve a protected tunnel unless the relay confirms it enforces the protection.

Why does a password not skip the visitor warning?

A browser takes a password written into a link (https://user:password@host/) and answers the relay's request for one with it, so a phisher can publish the password with the link. On an open-signup user's tunnel the relay asks for the password first, then shows the warning. A GitHub sign-in skips it: each visitor signs in as themselves, and only the accounts the tunnel lists get in.

Why does lnk hold each connection to the local app itself?

A local app that stops reading leaves what its HTTP client took waiting in that client's buffers. A shared client's connections run on their own and wait to flush them before closing, so a cancelled request could keep its body, and its socket, for good. The port service instead holds each connection for as long as its request, closes it when the request ends unfinished or is cancelled, and keeps up to 8 finished ones for the next requests. What it hands a connection stays counted against lnk's 64 MiB until it has been written.

Why does lnk send its token before Hello?

The relay holds a few slots for connections that haven't said Hello, capped per address and network, and anyone can take them. A few dozen IPv4 addresses could keep them all full, so agents got 503. With the token in the upgrade request, the relay knows an agent before its socket opens, and gives it a slot of its user's own: only strangers wait. Hello still carries the token, so an old lnk and an old relay keep working with each other and with new ones.