243 lines
7.7 KiB
Markdown
243 lines
7.7 KiB
Markdown
# dosh - Dormant Shell
|
|
|
|
dosh is a low-latency remote terminal designed around fast attach and fast reconnect.
|
|
It is mosh-shaped, but not a mosh clone: the server is a resident daemon, terminal
|
|
sessions stay hot, and repeat connects try encrypted UDP before starting SSH.
|
|
|
|
The core target is simple:
|
|
|
|
- First secure trust establishment uses SSH.
|
|
- Existing sessions attach in one encrypted UDP exchange whenever cached credentials allow it.
|
|
- Reconnect after sleep, roaming, or network change resumes in one encrypted UDP exchange.
|
|
- Cold SSH fallback stays competitive with plain `ssh` by doing less after auth.
|
|
|
|
## Why not just mosh?
|
|
|
|
mosh is excellent at roaming and high-latency interactivity. Its startup path still
|
|
has work dosh can avoid:
|
|
|
|
1. SSH connects to the host.
|
|
2. SSH starts `mosh-server`.
|
|
3. The client receives connection material over SSH.
|
|
4. SSH exits and the mosh UDP session begins.
|
|
|
|
dosh keeps `dosh-server` running before the client arrives. Named PTY sessions can
|
|
also be prewarmed, so attaching to `default` does not need to spawn a daemon, create
|
|
a PTY, or start a shell on the user's critical path.
|
|
|
|
This is not an encryption argument against mosh. dosh also encrypts its UDP data
|
|
channel; the speed difference comes from keeping the server and session hot.
|
|
|
|
## Fast Path Order
|
|
|
|
The client always tries the cheapest valid path first:
|
|
|
|
1. **UDP resume:** existing `ClientId` and session key. No SSH. One encrypted UDP
|
|
request, one encrypted UDP reply.
|
|
2. **UDP attach ticket:** cached server-issued attach ticket for the same
|
|
host/user/session/mode. No SSH. One encrypted UDP request, one encrypted UDP
|
|
reply.
|
|
3. **SSH bootstrap:** `ssh -T user@host ~/.local/bin/dosh-auth ...`, then one encrypted UDP
|
|
attach.
|
|
4. **New session:** same as attach, but the server must create the PTY/shell unless
|
|
the session was prewarmed.
|
|
|
|
The fastest path is not a custom SSH replacement. SSH remains the first trust root;
|
|
dosh removes SSH from repeat attaches when the server has already issued valid
|
|
credentials.
|
|
|
|
Attach tickets are implemented because they are the way a fresh client process can
|
|
skip SSH after a recent successful bootstrap.
|
|
|
|
## Connection Speed Contract
|
|
|
|
dosh is measured by terminal-ready time: elapsed time from running `dosh host` to the
|
|
first usable terminal screen.
|
|
|
|
- UDP resume: <= one measured UDP RTT + local render time.
|
|
- UDP attach ticket: <= one measured UDP RTT + local render time.
|
|
- Warm attach with ControlMaster: <= `ssh host true` over the existing master + one
|
|
measured UDP RTT.
|
|
- Cold attach without ControlMaster: <= cold `ssh host` terminal-ready time + one
|
|
measured UDP RTT.
|
|
- New session: measured separately because it may need PTY and shell creation.
|
|
|
|
The client emits timing spans for credential lookup, SSH bootstrap, UDP resume,
|
|
UDP ticket attach, and terminal-ready time.
|
|
|
|
## Architecture
|
|
|
|
```text
|
|
dosh-server
|
|
UDP socket on one configurable port
|
|
session table keyed by name
|
|
one PTY per named session
|
|
optional prewarmed sessions, default ["default"]
|
|
terminal parser/screen state per session
|
|
client table per session
|
|
encrypted UDP protocol
|
|
tiny SSH-invoked dosh-auth helper mode
|
|
|
|
dosh-client
|
|
terminal raw mode
|
|
local credential cache
|
|
UDP resume/attach first
|
|
SSH bootstrap fallback
|
|
PTY input/output forwarding
|
|
reconnect and roaming state machine
|
|
```
|
|
|
|
## Install
|
|
|
|
Default UDP port: `50000`. This is intentionally inside the common forwarded range
|
|
`50000-52000/udp`.
|
|
|
|
Install on each Linux server you want to attach to:
|
|
|
|
```bash
|
|
curl -fsSL https://git.palav.dev/Palav/dosh/raw/branch/main/install.sh \
|
|
| DOSH_REPO=https://git.palav.dev/Palav/dosh.git DOSH_PORT=50000 sh -s -- server
|
|
```
|
|
|
|
Install the client on macOS:
|
|
|
|
```bash
|
|
curl -fsSL https://git.palav.dev/Palav/dosh/raw/branch/main/install.sh \
|
|
| DOSH_REPO=https://git.palav.dev/Palav/dosh.git DOSH_SERVER=palav DOSH_HOST=git.palav.dev DOSH_PORT=50000 sh -s -- client
|
|
```
|
|
|
|
Update an installed client later:
|
|
|
|
```bash
|
|
dosh update
|
|
```
|
|
|
|
Install the client on Windows PowerShell:
|
|
|
|
```powershell
|
|
$env:DOSH_REPO="https://git.palav.dev/Palav/dosh.git"; $env:DOSH_SERVER="palav"; $env:DOSH_HOST="git.palav.dev"; $env:DOSH_PORT="50000"; irm https://git.palav.dev/Palav/dosh/raw/branch/main/install.ps1 | iex
|
|
```
|
|
|
|
Attach:
|
|
|
|
```bash
|
|
dosh palav
|
|
```
|
|
|
|
Plain `dosh palav` opens a fresh terminal session. Use named sessions when you want
|
|
to reattach to the same persistent terminal from multiple clients:
|
|
|
|
```bash
|
|
dosh --session work palav
|
|
dosh --session logs palav
|
|
```
|
|
|
|
Press `Ctrl-]` to detach the current client while leaving the server session alive.
|
|
Typing `exit` in the remote shell closes that Dosh session and returns the client.
|
|
If UDP packets stop arriving, Dosh shows a blue status bar at the top of the
|
|
terminal with the disconnected duration and sends keepalive pings until traffic
|
|
returns.
|
|
|
|
If SSH and UDP use different public names, specify the UDP address:
|
|
|
|
```bash
|
|
dosh-client --dosh-host public.example.com --dosh-port 50000 user@host
|
|
```
|
|
|
|
## Develop
|
|
|
|
Build:
|
|
|
|
```bash
|
|
cargo build
|
|
```
|
|
|
|
Attach locally, using local bootstrap instead of SSH:
|
|
|
|
```bash
|
|
target/debug/dosh-client --local-auth --no-cache local
|
|
```
|
|
|
|
Benchmark local attach:
|
|
|
|
```bash
|
|
target/debug/dosh-bench --local-auth --server local --iterations 5
|
|
```
|
|
|
|
Benchmark a remote host over SSH bootstrap:
|
|
|
|
```bash
|
|
target/release/dosh-bench --server user@host --ssh-port 22 --iterations 3
|
|
```
|
|
|
|
Benchmark the ControlMaster-backed SSH bootstrap path:
|
|
|
|
```bash
|
|
target/release/dosh-bench --server user@host --controlmaster --iterations 3
|
|
```
|
|
|
|
Run the Docker OpenSSH benchmark gate used by CI. It checks both cold SSH bootstrap
|
|
and ControlMaster-backed SSH bootstrap against a containerized `sshd` plus resident
|
|
`dosh-server`:
|
|
|
|
```bash
|
|
make bench-docker-ssh
|
|
```
|
|
|
|
The CI workflow includes an optional remote benchmark job. It runs when
|
|
`DOSH_BENCH_HOST`, `DOSH_BENCH_USER`, and `DOSH_BENCH_SSH_KEY` repository secrets are
|
|
configured.
|
|
|
|
Install release binaries and the user systemd service:
|
|
|
|
```bash
|
|
make install
|
|
```
|
|
|
|
## Performance Rules
|
|
|
|
The stack is performance-driven, not fixed by taste. Rust is the default because the
|
|
likely bottlenecks are network RTT, SSH startup/auth, PTY/shell creation, packet
|
|
size, and terminal rendering. Change language or runtime only if measurements show
|
|
they are the bottleneck.
|
|
|
|
Hot-path rules:
|
|
|
|
- Custom UDP protocol with AEAD for v0; no QUIC handshake on attach.
|
|
- Fixed binary packet headers for terminal traffic; no JSON on the protocol path.
|
|
- Preallocated buffers; avoid per-packet heap churn.
|
|
- Single-thread event loop is preferred for the hot path.
|
|
- No PTY allocation, shell spawn, shell rc files, or MOTD on attach to an existing
|
|
session.
|
|
- Initial snapshot should be sent in the first UDP reply when it fits under the
|
|
packet budget.
|
|
|
|
## Goals
|
|
|
|
- Connection speed as specified above.
|
|
- UDP roaming and reconnect.
|
|
- Encrypted terminal data.
|
|
- Reuse SSH pubkeys for first trust establishment.
|
|
- Named persistent sessions.
|
|
- Multiple clients attached to one session.
|
|
- Optional view-only clients.
|
|
- Single server port, not one port per session.
|
|
- Static server and client binaries where practical.
|
|
|
|
## Non-Goals
|
|
|
|
- Replacing SSH as the first public-key trust mechanism.
|
|
- Multi-user access control.
|
|
- Windows support in v0.
|
|
- Full mosh compatibility.
|
|
- Perfect predictive local echo in the first MVP.
|
|
|
|
## Status
|
|
|
|
Rust implementation is present in this repository. It contains `dosh-server`,
|
|
`dosh-client`, `dosh-auth`, `dosh-bench`, shared auth/crypto/protocol modules, a
|
|
resident PTY server, encrypted UDP bootstrap attach, UDP resume, sealed UDP attach
|
|
tickets, client ACKs, server retransmit bookkeeping, sliding replay protection,
|
|
server-side `vt100` screen snapshots/diffs, a hardened user systemd unit, an install
|
|
script, Docker SSH benchmark gates, CI, and protocol/integration tests.
|