Skip to content

feat: dumbpipe daemon#101

Draft
Frando wants to merge 7 commits into
mainfrom
feat-daemon
Draft

feat: dumbpipe daemon#101
Frando wants to merge 7 commits into
mainfrom
feat-daemon

Conversation

@Frando

@Frando Frando commented Jun 23, 2026

Copy link
Copy Markdown
Member

not sure if this is too much for this repo. can also move it into a new repo/crate. also not yet fully reviewed (initial version was vibecoded).
but: i wanted to have this for quite a while and it turned out to be really straightforward

dumbpipe daemon starts a daemon that runs multiple dumbpipe TCP proxies, defined in a config file.
each stream opens with a hello with a name to map it to the target and an optional token to secure it.
config file is reloaded on changes, so you can add connections with dumbpipe daemon accept and dumbpipe daemon connect.

Workflow.

  1. Build the config with subcommands (no hand-edited TOML needed):
    • dumbpipe daemon accept <name> <addr> [--secure] adds an inbound tunnel
      and can mint a token.
    • dumbpipe daemon connect <remote>:<name> <local-addr> [--token <t>] adds an
      outbound tunnel.
    • dumbpipe daemon show prints what is configured.
  2. Run it:
    • dumbpipe daemon run runs in the foreground and prints the endpoint id and
      a ticket to share.
    • dumbpipe daemon install, then start / status / stop / uninstall
      manage it as a user-level service.
  3. Change it live. With reload = true (the default) the daemon watches its
    config file: added or removed tunnels take effect without a restart, so the
    accept and connect subcommands reconfigure a running daemon on the fly.

Two daemons pair up by matching names: a connect tunnel forwards a local port
to a remote's accept tunnel of the same name, over a single reused, encrypted
iroh connection.

Frando added 6 commits June 22, 2026 10:42
Add a `dumbpipe daemon` subcommand that runs any number of incoming and
outgoing tunnels over a single iroh endpoint, driven by a TOML config.

- `[[connect]]` entries expose a local TCP port that forwards to a remote
  endpoint under a name; `[[accept]]` entries forward incoming named
  streams to a local TCP backend selected by name.
- A "named" handshake (prefix, u32 length, name) routes streams, so one
  endpoint can multiplex several tunnels.
- `remote` accepts a bare endpoint id or a full ticket; ticket address
  hints are seeded via a static address lookup alongside discovery.
- The connect side reuses one pooled iroh connection per remote across
  TCP streams and retries a failed connect once.
- The secret key is read from IROH_SECRET, else a hex key file under the
  data dir, else generated and persisted.

Config and secret default to <data_dir>/dumbpipe/daemon/. Documented in
docs/daemon.md and linked from the README.
Build out the daemon into a configurable, long-running service.

- New daemon ALPN, distinct from the single-tunnel dumbpipe protocol.
- Per-stream header is now postcard-encoded { name, token }.
- Optional per-tunnel token: an accept entry with a token only forwards
  streams whose connect side presents the same token.
- Subcommands (start is the default): `accept` and `connect` append
  entries to the config file, `show` prints the configured tunnels, and
  `start` runs the daemon. `accept --secure` generates a random token.
- `start` creates an empty config file when none exists.
- `reload` (default on) watches the config with notify and applies
  changes live: accept routes swap atomically, connect tunnels are
  reconciled by local addr, new remotes' hints are registered.
- Connection reuse via iroh-util ConnectionPool with one retry on
  connect failure, plus a static address lookup so ticket-form remotes'
  relay and address hints are honored.
- Logging: connect/disconnect events inside incoming{remote}:tcp{name,
  target} and outgoing{remote}:tcp{name, target} spans; the daemon
  defaults to dumbpipe=info,iroh=info when RUST_LOG is unset.

Documented in docs/daemon.md and linked from the README.
Add service subcommands backed by the service-manager crate, and make a
subcommand required so bare `dumbpipe daemon` prints help.

- `install` / `uninstall` / `start` / `stop` manage a user-level service
  (systemd user units, launchd, etc.). `install` runs `daemon run` with
  an absolute config path and enables start at login.
- `run` runs the daemon in the foreground (formerly the default `start`).
- The systemd unit is named `dumbpipe.service`.
- Default log filter `dumbpipe=info,iroh=info` now applies to `daemon
  run` specifically.

Documented in docs/daemon.md and the README.
Add `dumbpipe daemon status`, which reports the service status via
service-manager: not installed, running, or stopped.
@n0bot n0bot Bot added this to iroh Jun 23, 2026
@github-project-automation github-project-automation Bot moved this to 🚑 Needs Triage in iroh Jun 23, 2026
service-manager loads the launchd agent with `launchctl load`, which
targets the GUI login session and aborts over SSH. Fall back to managing
the agent in the per-user (Background) launchd domain that an SSH session
has, so install/start/stop/status/uninstall work over SSH without
elevated permissions. status also checks the per-user domain, since
service-manager queries the GUI domain and would report not installed.
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

Status: 🚑 Needs Triage

Development

Successfully merging this pull request may close these issues.

1 participant