Commit Graph

5 Commits

Author SHA1 Message Date
Alexander 62db1e2a9e feat(torad): bring up a WireGuard tunnel in user space from a config file
`--wireguard-config` is now the only thing an operator supplies. torad
re-executes itself inside a private user+network namespace, brings up a
userspace WireGuard datapath, and binds every torrent socket to it. No
root, no wg-quick, no pre-created interface, no kernel module, no one-time
host setup.

The mechanism differs from what was planned, because the plan's
assumptions did not survive being checked against the actual binaries:

- pasta already creates an unprivileged user+net namespace with full
  capabilities and a configured tap interface, so the hand-rolled
  unshare(CLONE_NEWUSER|CLONE_NEWNET) with uid_map, gid_map and
  setgroups=deny is gone. torad re-execs itself under pasta instead.

- WG_SOCKET_DIRECTORY does not exist; wireguard-go's socket directory is
  a build-time linker variable. WG_UAPI_FD does not avoid it either,
  because UAPIListen inotify-watches that path even when handed a
  pre-bound socket. Since /var/run is a symlink to /run, a tmpfs over
  /var inside a private mount namespace makes /var/run/wireguard
  writable while leaving the real /run visible -- which matters, because
  torad's gRPC socket lives under /run/user and the aggregator connects
  to it from the host.

- The peer endpoint needs a host route via pasta's gateway before the
  default route moves to wg0, or WireGuard's own handshake is routed
  into the tunnel it is trying to establish.

The device is configured by speaking WireGuard's UAPI protocol over its
unix socket, so wireguard-tools is not a dependency either.

If the datapath exits, torad shuts down instead of routing around it: a
live torad with a dead tunnel is the failure mode that leaks.

pasta also creates a PID namespace, so the pid file is written on the
host before the re-exec and not again inside -- otherwise it would
record PID 1, which names init when read from the host.

Co-Authored-By: Claude Opus 5 <noreply@anthropic.com>
2026-08-17 23:01:33 +02:00
Alexander dd41f1961f feat(torad): upgrade librqbit to 9.0.0-rc.0 and add --bind-device
Pinned exactly (=9.0.0-rc.0) — no v9 stable exists yet, so a caret range
would silently drift onto a future prerelease.

Two source changes were needed for the upgrade:

- `torrent_from_bytes_ext` moved to `librqbit_core::torrent_metainfo::
  torrent_from_bytes` and no longer wraps the result in a `meta` field.
- `peer_stats.live` / `.not_needed` are now `u32`, so the casts are
  redundant.

v9 also adds `SessionOptions::bind_device_name`, which is the reason for
the upgrade: it applies SO_BINDTODEVICE to every librqbit socket — peer
connections, trackers, DHT and LSD. Binding those to a VPN interface
means that when the interface goes away the sockets error out instead of
falling back to the host route, giving a kernel-enforced kill switch.
Exposed as --bind-device / TORAD_BIND_DEVICE; unset reproduces today's
behaviour exactly.

Note that `listen` stays at its default of None, so there is no listener
and no uTP socket in either direction — torad is TCP-only and leech-only.
That is unchanged from v8 but now written down, since incoming
connections need NAT-PMP port forwarding that we have not built.

Also drops torad's `nix` pin from 0.29 to 0.31.3 to match the sibling
tora crate; the workspace was carrying three copies.

Verified end-to-end against a real swarm rather than by compiling alone:
a 755 MiB torrent added via HTTP .torrent URL, driven through
pending -> downloading -> finished, with pause/resume on an active
torrent, remove, and the notification stream all exercised. Evidence in
.omo/evidence/task-5-torad-vpn-namespace.txt.

Co-Authored-By: Claude Opus 5 <noreply@anthropic.com>
2026-08-15 00:17:09 +02:00
Alexander 6309b87323 Hanlde jacket torrent url 2026-07-19 17:39:19 +02:00
Alexander 0036b19612 Add pause/resume, enchance tora-cli 2026-07-03 19:10:26 +02:00
Alexander 80ebf1cb63 Simple mini clone of torrra 2026-07-02 17:02:49 +02:00