Skip to content

GeiserX/tailscaled-rs

tailscaled-rs

tailscaled-rs

CI License: BSD-3-Clause Rust edition 2024 Status: experimental

An independent, from-scratch Rust system daemon that joins a WireGuard-based mesh overlay network by speaking the Tailscale control protocol — the long-running, IPC-controlled daemon layer (a tailscaled-shaped process) built on top of the embeddable tailscale-rs engine library.

Where tailscale-rs is an embeddable library (you link it into your own program, the way Go's tsnet works), tailscaled-rs is the daemon: a persistent background service with a reconcilable state machine, persisted preferences, and a local control socket that a thin CLI (tnet) talks to. That daemon layer is exactly what an embeddable library leaves out, and it is what this project adds.

Warning

Experimental. Not for production. This is early-days software. The underlying engine contains unaudited cryptography and carries no stability or compatibility guarantees, and the daemon layer here is a young MVP. Do not rely on it for data privacy yet.

What works today (MVP)

  • Joins a real tailnet non-interactively with a pre-auth key, obtains a tailnet IP, and reaches Running over DERP-relayed connectivity.
  • IPN-style state machineNoState → NeedsLogin → Starting → Running → Stopped, with the reported state derived from live engine/netmap reality (never stored, so it can't drift).
  • Persisted preferences — the node's intent (up/down, hostname, accept-routes) survives a restart.
  • LocalAPI over a Unix domain socket — the daemon (tailnetd) serves a local control surface; the CLI (tnet up / down / status) is a thin client over it.

Not yet (the road to a full daemon)

TUN-mode by default and per-OS routing/DNS programming, interactive (browser) login, netmon-driven endpoint re-binding on network change, service installation (systemd/launchd/Windows), MagicDNS OS integration, exit-node/subnet-router operation, Tailscale SSH / Serve / Funnel, and Tailnet Lock enforcement. The MVP runs in userspace-networking mode (no TUN, no OS routing/DNS changes) — applications reach the tailnet via the daemon rather than the kernel. See docs/DESIGN.md for the full architecture and phased plan.

Quick start

# Build
cargo build --release

# The engine requires an explicit acknowledgement that it is experimental:
export TS_RS_EXPERIMENT=this_is_unstable_software

# Run the daemon (foreground)
./target/release/tailnetd

# In another shell: join a tailnet with a pre-auth key, then check status
./target/release/tnet up --authkey tskey-auth-XXXX --hostname my-node
./target/release/tnet status
./target/release/tnet down

State (node keys + prefs) lives in $XDG_STATE_HOME/tailnetd (override with TAILNETD_STATE_DIR); the control socket is <state-dir>/tailnetd.sock (override with TAILNETD_SOCKET).

Architecture

flowchart LR
    CLI["tnet (CLI)"] -->|"up / down / status<br/>over Unix socket"| D
    subgraph D["tailnetd (daemon)"]
        IPN["IPN state machine<br/>+ persisted Prefs"]
        API["LocalAPI server"]
        API --> IPN
        IPN -->|"build Config,<br/>bring up / tear down"| ENG
        ENG["tailscale-rs engine<br/>(control · magicsock · DERP · WireGuard · netstack)"]
    end
    ENG <-->|"Noise control protocol"| CTRL["Control server"]
    ENG <-->|"WireGuard / DERP"| PEERS["Tailnet peers"]
Loading

The daemon owns the lifecycle and intent; the engine owns the cryptography and data plane. See docs/DESIGN.md for the component graph, the state machine, and what each layer is responsible for.

Developing against a local engine

tailscaled-rs depends on a pinned revision of tailscale-rs (see Cargo.toml), and Cargo.lock is committed so every build is reproducible. If you are co-developing the engine, point Cargo at a local checkout with a gitignored .cargo/config.toml:

# .cargo/config.toml  (gitignored — never committed)
paths = ["/path/to/your/tailscale-rs"]

Cargo transparently substitutes the local source when its version matches the pinned one — edit the engine, rebuild the daemon, no manifest change. To bump the pinned engine deliberately, update the rev in Cargo.toml and run cargo update -p tailscale-rs.

Relationship to Tailscale and WireGuard

This is an independent, unofficial project. It is not affiliated with, endorsed by, or sponsored by Tailscale Inc. "Tailscale" is a trademark of Tailscale Inc.; this project uses the name only nominatively, to describe the protocol it is compatible with. "WireGuard" is a registered trademark of Jason A. Donenfeld; this project implements/speaks the WireGuard protocol and is not an official WireGuard project.

The bulk of Tailscale's own client is open source (BSD-3-Clause), and this project is offered in the same spirit: a permissively-licensed, community contribution that anyone — including upstream — is free to use, study, and build on.

License

BSD-3-Clause. Portions derived from or interoperating with tailscale-rs retain the original Tailscale Inc. copyright notice, as required.

About

An independent, from-scratch Rust system daemon (tailnetd) for joining a WireGuard-based mesh overlay via the Tailscale control protocol — the daemon layer atop the tailscale-rs engine. Unofficial; not affiliated with Tailscale Inc.

Topics

Resources

License

Contributing

Security policy

Stars

Watchers

Forks

Releases

No releases published

Packages

 
 
 

Contributors