Skip to content

Releases: doedja/warren

v0.4.11

Choose a tag to compare

@github-actions github-actions released this 09 Jun 22:15

Security and robustness release from a full-codebase audit. Update nodes
(auto-update picks it up) and redeploy hubs.

Security

  • Node TLS pinning now verifies the handshake signature. The pinned-cert
    verifier accepted any CertificateVerify, and the hub's self-signed cert is
    public, so an active man-in-the-middle could present the real cert with its
    own key, complete the handshake, and read the tunnel (including the
    enrollment token in the node's Hello). Signature verification now runs
    through the real rustls crypto provider; pinning is unchanged otherwise.
  • Proxy auth fails closed: a store error (locked or broken database) used to
    disable authentication for that connection, briefly turning the pool into an
    open relay. Node-name uniqueness checks fail closed the same way.
  • The enrollment replay-guard map is pruned past the timestamp skew window; it
    previously grew without bound on attacker-minted keypairs.
  • Node identity and hub TLS key files are created with mode 0600 from the
    start (no world-readable window between write and chmod).
  • The unix self-update command and systemd unit now shell-quote the hub
    address, token, and fingerprint.
  • Release workflow actions are pinned to commit SHAs (the job holds a write
    token, so a hijacked action tag could have published attacker binaries with
    matching checksums). CI runs with a read-only token.
  • install.sh runs inside a function called on the last line, so a truncated
    curl | sh cannot execute a partial script; Termux boot-script arguments
    are single-quoted.
  • Geo/public-IP lookups (plaintext HTTP) cap the response at 64 KB.
  • The dashboard asks for confirmation before deleting the last proxy user
    (zero users disables proxy authentication entirely).

Fixed

  • Two nodes enrolling concurrently with the same name could both be approved
    and then permanently reject each other on reconnect; the name check and
    approval are now atomic.
  • Two SOCKS5 UDP clients behind one NAT IP no longer tear down each other's
    association on disconnect.
  • A failed auto-update no longer wedges updates until the process restarts;
    the debounce re-arms 10 minutes after launching the installer.
  • node install --join CODE --insecure keeps --insecure in the service
    command (the service used to crash-loop on a missing fingerprint).
  • Node dials time out after 10s instead of hanging in the OS SYN-retry path
    and holding up shutdown drains; the node's real dial-failure reason now
    shows in the dashboard instead of a generic "dial timed out".
  • Absolute-URI HTTP proxy requests handle bracketed IPv6 hosts and reject
    invalid ports instead of silently sending the request to port 80.
  • SOCKS5 replies 0x08 (address type not supported) to unknown address types
    instead of closing the connection without a reply.
  • Hub accept loops back off briefly on accept errors instead of hot-spinning
    at 100% CPU when out of file descriptors; the node-link TLS handshake is
    time-bounded; the sticky-session cap is enforced hard (oldest evicted).
  • Creating a proxy user with a reserved routing marker in the name returns
    400 instead of 500.

v0.4.10

Choose a tag to compare

@github-actions github-actions released this 08 Jun 15:59

Fixed

  • Windows uninstall now removes the node key created under the SYSTEM profile.
    The boot task runs as SYSTEM, so the identity lives at
    ...\System32\config\systemprofile\.warren\node.key, but uninstall runs as the
    elevated admin user and only cleared that user's profile. The stale key
    survived, so a reinstall reused the old identity and the hub kept the node on
    its previous approval (you had to revoke the key on the hub to re-enroll).
    Uninstall now clears the SYSTEM-profile key path explicitly.

v0.4.9

Choose a tag to compare

@github-actions github-actions released this 08 Jun 15:01

Security

  • Region routing can no longer be spoofed by a node. A connected node's
    self-reported IP, country, and city are now treated as display-only; the hub
    uses the control-connection peer address and its own geo lookup for all routing
    decisions, so a malicious node cannot claim another country to capture
    user-region-* traffic.
  • Revoking a node key in the dashboard now tears down that device's live link
    immediately. Previously the key was removed (blocking reconnect) but an
    already-connected device kept proxying until it disconnected on its own.
  • Enrollment is replay-protected. Each Hello must carry a timestamp strictly
    newer than the last one accepted for that key, so a captured Hello cannot be
    replayed inside the skew window to displace the live link.
  • State-changing admin routes (create/delete tokens, users, keys; approve/deny
    devices) now require an X-Warren-Admin request header in addition to the
    Basic-auth token. The dashboard sends it automatically; a cross-site page
    cannot, which blocks CSRF. Scripts driving these routes add
    -H "X-Warren-Admin: 1" (read-only GETs are unaffected).
  • DoS hardening on the public listeners: a per-IP cap on concurrent node links, a
    bounded proxy-handshake timeout, and a cap on the pending-enrollment table.
  • The TLS certificate and key files are written with 0600 permissions on Unix,
    matching node identity-key handling.

Fixed

  • HTTP CONNECT now parses bracketed IPv6 targets ([::1]:443) and bare hosts
    (defaulting to port 443) instead of rejecting them.
  • UDP node selection now applies the same recent-failure health window as TCP, so
    a recovered node is no longer wrongly excluded from UDP associations.
  • Sticky sessions over SOCKS5 UDP now pin to the session's device, matching TCP.
    Previously user-session-KEY silently spread datagrams across the whole pool.
  • A device may no longer enroll under a name already in use by a different key,
    which previously made user+name routing ambiguous.
  • SOCKS5 UDP replies for domain names longer than 255 bytes are dropped rather
    than truncated into a malformed datagram.
  • Empty proxy usernames and passwords are rejected server-side (was only checked
    in the dashboard).

Changed

  • Deleting an enrollment token in the dashboard now asks for confirmation.
  • A node connecting in plaintext to a TLS hub now fails with a pointed hint
    (use the join code or --tls) instead of an opaque handshake error.
  • launchd plist generation XML-escapes interpolated paths and arguments.
  • A client that connects but sends no bytes is logged at debug level.
  • README: minimum Rust is 1.88 (was 1.74); UDP egress targets may be IPv4 or
    IPv6 (was documented as IPv4-only).

v0.4.8

Choose a tag to compare

@github-actions github-actions released this 04 Jun 11:03

Fixed

  • Hub log no longer floods with rustls ... Illegal SNI extension warnings.
    Internet scanners probing the exposed node port present the host IP as the TLS
    SNI; rustls warned on every one. The warning was harmless (the SNI is ignored,
    node auth is the app-layer enroll token) but buried real warnings in the
    dashboard log card. That one rustls target is now filtered below WARN.
  • Dashboard no longer shows a healthy node as unhealthy next to a contradictory
    "100%" success rate. Two fixes: (1) the node Health counter now expires a run
    of failures after 60s with no new failure (a successful dial still resets it
    instantly), so a node that stopped failing or went idle recovers instead of
    sticking red until its next success, and transient dead-target timeouts no
    longer pin an otherwise-fine node. (2) the Success column floors to one decimal
    instead of rounding, so "100%" shows only when every dial succeeded. The
    expired health count also feeds routing order and the /metrics gauge.

Changed

  • Node auto-update is now staggered across the fleet. A hub redeploy announces
    the new version to every --auto-update node at once; previously they all
    re-ran the installer and restarted together, so the whole pool blinked out.
    Each node now waits a random delay (up to 5 min) before updating and keeps
    serving until it fires, so updates roll one node at a time (version tolerance
    keeps the not-yet-updated nodes routable). Debounced so a repeated announce
    does not stack timers. Single-node setups are unaffected (nothing to stagger).

Security

  • The admin//metrics Basic-auth token is now compared in constant time, so it
    cannot be recovered by timing how long a wrong token takes to reject.

v0.4.7

Choose a tag to compare

@github-actions github-actions released this 03 Jun 00:09

Fixed

  • Unix --auto-update could take a node down instead of upgrading it. The node
    launched install.sh as a child process, and the installer stops the
    warren-node service to swap the binary, which killed the still-running
    installer (its parent died) before the swap finished: service stopped, binary
    not replaced, node offline until a manual reinstall. The updater now runs
    detached from the service: a systemd transient unit on Linux (its own cgroup,
    independent of the warren-node unit's restart), or a new session via setsid
    elsewhere (so launchd's process-group teardown does not reach it). This mirrors
    the Windows detached-helper design added in 0.4.6. Node-side only; reinstall a
    node once to pick up the fixed updater.

v0.4.6

Choose a tag to compare

@github-actions github-actions released this 02 Jun 23:21

Fixed

  • A node that reconnected over a half-open link (the old TCP connection never
    sent a FIN, common on Windows) was silently dropped from the routable set even
    though its new connection was alive. The hub keyed a node only by its stable id
    and removed every entry with that id, so when the dead-peer timer reaped the
    stale duplicate connection (~75s after the node had already reconnected) it
    evicted the live reconnected entry too. The node stayed "ghost-connected" (TCP
    up, replying to pings) but invisible on the dashboard and carrying no traffic
    until a restart. Each connection now carries a unique sequence: a reconnect
    displaces the old entry on enroll, and the stale reap removes only its own
    connection, never the live one. Hub-only fix, no protocol change.

Added

  • Windows nodes support opt-in --auto-update. The running .exe is locked, so
    a detached PowerShell helper waits for the node process to exit, then re-runs
    install.ps1 to swap the binary and restart the service. Off by default, like
    the unix path; install.ps1 gained an -AutoUpdate switch and the dashboard
    auto-update toggle now applies to the Windows install command too.
  • CI gained an MSRV (Rust 1.74) build job and a cargo audit job, so the
    declared minimum toolchain and dependency advisories are both enforced.

v0.4.5

Choose a tag to compare

@github-actions github-actions released this 02 Jun 16:30

Fixed

  • Windows node install failed with "The task XML contains a value which is
    incorrectly formatted or out of range" (the restart Interval PT15S is below
    the Task Scheduler 1-minute minimum, and hand-written task XML is order-
    sensitive). The startup task is now built with PowerShell's ScheduledTask
    cmdlets, which generate valid XML: restart-on-failure every 1 minute, no
    execution time limit, run-on-batteries, SYSTEM at boot. If PowerShell is
    unavailable it falls back to the flat schtasks boot task, so install never
    hard-fails.

v0.4.4

Choose a tag to compare

@github-actions github-actions released this 02 Jun 16:16

Added

  • Node groups via enrollment tokens. The token's name is now a group label:
    every node that joins with a given token belongs to that group, and a client
    can route through the whole group with the proxy username user-group-NAME
    (case-insensitive, no fallback if the group is empty), alongside the existing
    +device, -region-, and -session- selectors. Pure hub-side routing, no
    protocol change, existing nodes unaffected.
  • Dashboard: each node shows its group as a badge next to its name; each
    enrollment token has a "rename" button (renaming relabels the group; connected
    nodes pick up the new label on their next reconnect) and a "copy group cmd"
    button that yields the ready user-group-NAME curl.

Changed

  • Enrollment-token names are now validated on create and rename (the name
    doubles as the user-group-NAME routing selector). Names are restricted to
    [A-Za-z0-9._-] and may not contain the reserved routing markers
    (-region-, -session-, -group-), so a name can no longer break the copied
    group curl or be silently swallowed by parse_route. The API rejects an
    invalid or empty name with 400.

v0.4.3

Choose a tag to compare

@github-actions github-actions released this 02 Jun 15:56

Fixed

  • macOS node install no longer requires (and must not use) sudo. A launchd
    LaunchAgent is per-user: when the installer ran it under sudo, the root
    launchctl load targeted the wrong domain, so the agent silently never
    started and the node never appeared on the hub. install.sh now installs the
    service as the user on macOS, and node install loads into the user's GUI
    domain (gui/<uid>).
  • macOS install run as root anyway (sudo sh install.sh, or a root shell) now
    resolves the real login user (SUDO_USER, else the console session owner),
    bootstraps into that user's domain, and chowns the plist back to them so no
    root-owned agent is left behind and later upgrades/uninstalls work without
    sudo.
  • macOS (re)install rides out the launchd bootout/bootstrap race
    (KeepAlive teardown settles asynchronously and an immediate bootstrap can fail
    with EIO): it retries, then falls back to the legacy load -w.

Changed

  • Windows startup task is now defined from a task XML so it carries
    restart-on-failure (parity with systemd Restart=always / launchd
    KeepAlive: a crashed node recovers instead of staying down until reboot), no
    execution time limit (the flat form inherited the 72h default), and
    run-on-batteries. install.ps1 checks for an elevated shell up front and
    fails with a clear message instead of a cryptic schtasks access error.
  • CI now also compiles (build + clippy) on macOS and Windows, so the
    platform-specific service-install paths are checked on their real targets.

v0.4.2

Choose a tag to compare

@github-actions github-actions released this 02 Jun 10:01

Added

  • Release assets now ship a sha256 checksum next to each archive, and both
    installers (install.sh, install.ps1) verify the download against it before
    extracting or running anything. Fails closed; WARREN_SKIP_VERIFY=1 bypasses.
    Because auto-update re-runs the installer, self-updates are verified too.

Changed

  • Dashboard is wider (max 1200px) so the Live nodes table fits all columns
    (including the new Version) without crowding on a normal desktop.

Fixed

  • Node auto-update is now actually reachable: --auto-update passed to the
    installer is baked into the boot service (it was previously dropped), and a
    self-update re-runs with the flag so it stays on across an upgrade. Still
    opt-in and off by default. Append --auto-update to the install line to
    enable it (Unix only).