Remote sockets, recovery, and availability
On this page
- Authorization and connection preparation
- Remote allowlists
- Supply bridge binaries
- Sudo recovery
- Socket availability
- Failure reporting
- Source references
A browser supplies a socket destination. OuterSSH decides how to reach it and whether access is authorized. The browser does not need to classify its privilege mode or launch the socket bridge itself.
Authorization and connection preparation
For ordinary user socket paths, OuterSSH obtains authorization from a persistent remote socket service, then uses SSH direct-streamlocal forwarding. System-style paths first require the pool’s cached remote-user identity. If that user is root, they follow the direct authorization path; otherwise OuterSSH starts or reuses a sudo traffic bridge.
The current privilege decision uses path conventions (/run/ outside /run/user/, and /var/run/) plus the remote user. It is not a general remote ownership query performed for every path. A host may use its own heuristics to display a “root” label, but it should leave actual preparation to OuterSSH.
A packaged binary is application-supplied executable data. An installed executable is the uploaded remote file. A traffic bridge is a running outer-socket-bridge process serving connections to one socket. The socket service is a separate persistent outer-socket-bridge service process that handles authorization requests and watches for multiple paths. It does not carry the direct-streamlocal application’s traffic.
Successful direct-socket authorizations are cached for the pool’s lifetime, including socket-service restarts. Concurrent requests for one new path share an authorization query; failures are not cached. Removing an allowlist entry therefore does not revoke a previously cached direct authorization in an existing pool. Create a new pool to get a fresh authorization decision. Privileged traffic bridges check their allowlist on each stream open.
There is no special authorization exemption for Outer Shell. TCP forwarding does not use the Unix-socket allowlist; it remains subject to the SSH server’s forwarding permissions.
Remote allowlists
Allowlist files are on the SSH server, not the browser machine. They contain exact socket paths, one per line, with blank lines/comments allowed. They are not glob patterns. The helper supports %t for the user’s runtime directory, %T for the system runtime directory, %u for numeric UID, and %% for a literal percent sign.
| Remote OS | User allowlist | System allowlist |
|---|---|---|
| Linux | $XDG_CONFIG_HOME/outerssh/http-unix.allow, or $HOME/.config/outerssh/http-unix.allow |
/etc/outerssh/http-unix.allow |
| macOS | $HOME/Library/Application Support/org.outerssh/http-unix.allow |
/Library/Application Support/org.outerssh/http-unix.allow |
Hosts can opt into additional files with OuterSSHSessionPoolConfiguration.additional_socket_allowlists. Each entry specifies a path, its byte length, and whether it is system policy. User paths may begin with %h/ for the remote home or %c/ for the remote XDG configuration directory (default ~/.config). System paths must be absolute. Outer Loop uses this option for its former outerloop (Linux) and dev.outergroup.OuterLoop (macOS) locations; other consumers do not enable them by default. New entries belong in the standard locations above.
The helper checks file ownership and permissions: a regular file owned by the appropriate user (root for system policy), without group/other write permission. A missing or unsafe allowlist is an error. Socket classification and privilege checks also apply; having a path in an arbitrary allowlist is not sufficient.
For example, a user allowlist can contain:
%t/org.outershell.OuterShell
An error UI should name the decoded socket path, explain that access requires an entry in the appropriate remote allowlist, and preserve any more specific diagnostic. Do not suggest repeatedly reloading to resolve an authorization denial.
Supply bridge binaries
Unix-socket authorization and watches require the remote service even when traffic itself uses direct-streamlocal. Applications supporting sockets should therefore provide OuterSSHProxyBridgeBinaryLoader and package the binaries for the remote operating systems/architectures they support. A Windows client connecting to Linux supplies a Linux executable.
OuterSSH probes the remote platform, selects a resource name such as outer-socket-bridge-linux-aarch64-glibc, and invokes the loader on the control queue. The name is UTF-8 bytes with an explicit length and may not be NUL-terminated. The host maps it to a bundle resource, file, mapping, or embedded byte array.
Return OuterSSHSocketBridgePackagedBinary with bytes, byte count, and an optional release callback/context, or an error. The bytes and error text must survive until release. OuterSSH calls a supplied release exactly once, including on failure, on the control queue. Release may happen before installation finishes; its context must remain valid independently of the loader context. Static bytes can use a NULL release callback.
The loader is synchronous; keep resource lookup predictable. OuterSSH owns installation, reuse, bridge launch, and best-effort cleanup. It does not install Outer Shell or any other remote application.
Sudo recovery
Install the frontend’s sudo-recovery handler before exposing it to browser requests. The handler receives the selected pool, local proxy port, remote socket path, and a recovery completion/context. It runs on the control queue; schedule UI work without blocking that queue.
The host’s sequence is:
- Call
outerssh_session_pool_ensure_sudo_socket_bridge(pool, path, length, password, password_length, finished, context). NULL/zero password tries without supplying one. - If it reports
OuterSSHProxyErrorSudoPasswordRequired, prompt and retry with the supplied password, or cancel. - When preparation succeeds, invoke the original recovery completion with
true. On failure or cancellation, invoke it withfalse.
Call that recovery completion exactly once, even if the browser navigation disappeared or the frontend was stopped/destroyed while UI was open. The supplied pool and path are borrowed through that completion. After requesting pool destruction, do not submit another ensure operation; settle an outstanding recovery as cancelled instead.
The ensure API always requests a sudo bridge. Ordinary connection preparation has already handled the root-user/direct-access case. It can reuse a bridge or join setup in progress. Successful preparation alone does not resume the pending browser connection: the recovery completion does that. OuterSSH checks whether the pending connection still exists before continuing it.
Socket availability
Install outerssh_session_pool_set_socket_availability_handler before calling outerssh_session_pool_watch_socket. Each watch call has a one-shot completion for subscription success/failure. The separate availability handler reports an initial state and later changes as (path, length, available) on the control queue.
A path may be watched before its socket exists. Watching is independent of forwarding and works with direct-streamlocal traffic. Temporary observation/permission failures do not mean absence. After a present socket disappears, reporting absence is debounced; the current implementation uses three seconds. Established watches resume after service reconnection.
There is one handler per pool. Updates received without a handler are discarded; registering a handler later does not replay them. Repeating watch replaces that path’s subscription. Unwatch removes it, and pool destruction ends all watches. A watch’s completion is not itself an availability notification; use the handler for state.
OuterSSH still uses service heartbeats and remote polling; this is not an instantaneous kernel-event guarantee. A missing socket does not tell the library whether an application was uninstalled, crashed, or intentionally stopped. The browser decides what UI or install action follows.
Failure reporting
The HTTP and SOCKS frontend APIs expose set_connection_failure_handler. The handler identifies the pool, proxy port, requested host/port, decoded socket path, and an OuterSSHProxyError. It runs on the control queue and borrows its data until return. Copy the path/error before posting UI work.
This is a forwarding/preparation diagnostic, not a complete HTTP request log or a notification for every later stream failure. Some protocol rejections, such as malformed requests, can produce only a generic proxy failure. A web server’s HTTP 403 is an application response and does not invoke this callback merely because its status is an error.
A web engine may report a generic network error in addition to the richer forwarding diagnostic. Correlate by current server, endpoint, and navigation state; the callback does not carry a browser navigation ID. Multiple requests from one page may fail. Show one useful page-level error without automatically navigating back to the same failing endpoint in a loop.