Files
RemSound/server
EdnunpandClaude Fable 5 6c53fe54d1 v5.6 batch: signed releases + stronger passwords enforced + relay address-proof
The everyone-must-update release. Four coordinated changes, each from the security
discussion Ed approved 2026-07-27, plus the remembered-apps polish:

1. SIGNED RELEASES. build-release.ps1 now signs the release zip (ECDSA P-256 /
   SHA-256, --sign-update verb) with a private key that lives ONLY at Ed's chosen
   location outside the repo; the matching public key is embedded (UpdateSignature)
   and the updater REFUSES any release whose .sig asset is missing or does not
   verify - a compromised GitHub account can no longer ship code to users. The
   signing verb self-checks against the embedded key so a key/embed mismatch fails
   the pipeline, and the gate proves the on-disk key matches the embed when present.

2. STRONGER PASSWORDS, ENFORCED (BREAKING). PBKDF2 raised 100k -> 600k (both peers
   must derive the same key, so 5.6 cannot stream with pre-5.6 AT ALL - release
   notes lead with it). New PasswordStrength rule (>= 8 chars, not an infamous
   password) enforced at EVERY door: both password dialogs block weak NEW entries
   with concrete plain-English advice; the streaming gate walks an existing weak
   password through strengthening; and ForPlainPassword - the single derivation
   choke-point shared with the service - refuses weak outright, so no path streams
   on a guessable password. Headless service logs the why. Per Ed: painful once,
   and this coordinated-update release is the cheapest moment it will ever have.

3. RELAY ADDRESS-PROOF (watch-only). The relay sends every new client address a
   random cookie and marks it verified when echoed - a forged source address can
   never echo, killing the reflection attack. 5.6 clients echo automatically
   (AddrCheck type 10, verbatim, self-limiting); the relay ships watch-only
   (logs would-blocks) until the fleet updates, then one flag (--require-addr-check)
   enforces. Per-IP entry cap (4) enforced immediately. Relay changes are committed
   but NOT deployed to the Pi - they ride the v5.6 release moment.

4. Remembered-apps empty state teaches its lifecycle + manual sentence; About/
   release notes written; version bumped to 5.6.

New gate steps: signing round-trip/tamper/wrong-key/embed-match; password rules incl.
the exact "Games" case; AddrCheck verbatim echo. Gate 69/69.

Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
2026-07-27 08:19:20 +01:00
..

RemSound UDP Relay — server-v2.0

A small UDP reflector that lets RemSound peers reach each other across the internet without Tailscale in the audio path. Two modes in one binary:

  • v1 (pairwise) — the original two-slot reflector. First two endpoints to send a valid RemSound v1 packet claim the slots; their traffic gets mirrored to each other. Used by RemSound clients up to v1.x.
  • v2 (lobby) — a multi-peer lobby (default cap: 10) keyed on a per-instance CLIENT_ID. Used by RemSound clients that emit v2 packets. Periodic LobbyRoster packets keep clients informed of who's in.

A single relay instance handles both protocols concurrently on the same UDP port. v1 clients keep working unchanged; v2 clients get the lobby model. (A v1 client and a v2 client cannot hear each other in the same session; that's a deliberate scope cut for this release.)

What's in this bundle

File Purpose
remsound-relay.py the relay itself (dual-protocol)
remsound-relay.service systemd unit for the relay
remsound-relay-update.sh auto-updater. Polls GitHub Releases hourly for newer server-* tags and installs them in place
remsound-relay-update.service systemd one-shot unit fired by the timer
remsound-relay-update.timer the schedule (boot + every hour, with random jitter)
install.sh sets up the relay AND the auto-updater
uninstall.sh removes everything this bundle installed
smoke-test.sh post-install sanity check (v1 + v2 paths + updater scaffolding)
VERSION the tag this bundle represents (server-v2.0)
README.md this file

Installing on a fresh host

Tested on Raspberry Pi OS Bookworm and Debian / Ubuntu. Requires python3 and curl (both usually preinstalled).

# 1. Download and extract the latest server tarball.
curl -L -o /tmp/remsound-server.tar.gz \
  https://github.com/Ednunp/RemSound/releases/download/server-v2.0/remsound-server-v2.0.tar.gz
tar xzf /tmp/remsound-server.tar.gz -C /tmp
cd /tmp/remsound-server-v2.0

# 2. Install — sets up the relay AND auto-updates.
sudo ./install.sh

# 3. Open UDP 47830 in the firewall and / or router port-forward.
#    On UFW: sudo ufw allow 47830/udp
#    On UDM / pfSense / etc.: WAN UDP 47830 -> this host's LAN IP.

# 4. Confirm it's alive.
sudo ./smoke-test.sh

After install, the auto-updater is enabled. Future releases roll out automatically — no manual SCP, no manual edit. To pin to the current version:

sudo systemctl disable --now remsound-relay-update.timer

To check for updates manually:

sudo systemctl start remsound-relay-update.service

To uninstall everything cleanly:

cd /tmp/remsound-server-v2.0   # or wherever the bundle is
sudo ./uninstall.sh

Files on disk after install

Path Purpose
/usr/local/sbin/remsound-relay.py the relay
/usr/local/sbin/remsound-relay-update.sh the auto-updater
/etc/systemd/system/remsound-relay.service relay unit
/etc/systemd/system/remsound-relay-update.service updater unit
/etc/systemd/system/remsound-relay-update.timer updater schedule
/etc/remsound-relay/version currently installed tag
/etc/remsound-relay/backup/ snapshot for the updater's rollback
/var/log/remsound-relay.log relay event log (event=... per line)
/var/log/remsound-relay-update.log update-check history

Networking

  • Listens on UDP 47830 (chosen to avoid clashes with RemSound's own defaults — 47820/47821/47822 — plus NetFlow 2055 and NUT 3493).
  • Bound to 0.0.0.0, so the kernel routes via the default interface. Tailscale must NOT carry this traffic — the whole point of the relay is to remove Tailscale's hops from the audio path.
  • The relay process itself never decodes audio. It validates the RemSound header (magic RMND, version 1 or 2) and forwards or drops.

Log format

Structured key=value lines. Notable events:

event=startup version_supported=v1,v2 listen=0.0.0.0:47830 max_clients=10

# v1 (pairwise)
event=peer_joined addr=1.2.3.4:5555 slots_filled=1
event=peer_paired a=1.2.3.4:5555 b=5.6.7.8:9999
event=peer_dropped reason=idle addr=1.2.3.4:5555 remaining=1
event=peer_replaced old=1.2.3.4:5555 new=9.8.7.6:4444

# v2 (lobby)
event=client_joined client_id=<uuid> addr=1.2.3.4:5555 count=2
event=client_endpoint_update client_id=<uuid> old=1.2.3.4:5555 new=1.2.3.4:6666
event=client_named client_id=<uuid> name=Andre
event=client_left client_id=<uuid> addr=... reason=bye
event=client_idle_expired client_id=<uuid> addr=...
event=lobby_full attempted_client_id=<uuid> addr=... count=10 max=10

# once a minute
event=stats forwarded=N dropped_unpaired=N dropped_lobby_full=N
            rejected_bad_header=N pair_changes=N lobby_changes=N
            client_count=N v1_peers=[...] v2_clients=[...]

Never logs CLIENT_ID payload bytes beyond the UUID itself. Never logs audio payload.

Tunables

Setting How to override
Listen port (47830) ExecStart= --port=N in the service unit
Listen address ExecStart= --host=X in the service unit
Lobby capacity (10) --max-clients=N or env var REMSOUND_MAX_CLIENTS=N in the service unit
Idle timeout (60 s) edit IDLE_TIMEOUT_SECONDS in remsound-relay.py
Stats interval (60 s) edit STATS_INTERVAL_SECONDS in remsound-relay.py
Update check (hourly) edit remsound-relay-update.timer
Update repo (Ednunp/RemSound) env var REMSOUND_UPDATE_REPO in the updater service unit

Why an auto-updater

The relay is small and (after this release) doesn't change often, but when it does we'd rather not chase every operator to re-SCP. The updater polls GitHub Releases for tags starting with server-, finds the highest version, downloads it, swaps the files, restarts the service, and falls back to the prior version if startup fails. Logs everything to /var/log/remsound-relay-update.log.

It only triggers on server-* tags, so RemSound client releases (v1.x, v2.x without the server- prefix) don't affect the relay.

Disabling auto-updates

Either disable the timer:

sudo systemctl disable --now remsound-relay-update.timer

…or run uninstall.sh (removes the updater scaffolding entirely along with the relay).