com.harryaskham.weartailnet · Kotlin · Go · Wear OS
Wear Tailnet
A Wear OS app that joins a Tailscale network as its own node, with Tailscale's tsnet library built into the app rather than a VPN. Machines on the tailnet can reach services on the watch, and other watch apps can reach the tailnet through it, while the rest of the watch's traffic is untouched.
One app on the tailnet
The Go side is a small bridge around tsnet, compiled with gomobile into an Android library for 32- and 64-bit ARM watches and the x86_64 emulator. It supports two kinds of mapping: a tailnet port that forwards to a service on the watch's loopback address, and a loopback port on the watch that forwards to a tailnet peer. Proxy targets other than loopback are rejected.
The first start prints a Tailscale login link and QR code to open on any device with a browser. A one-off pre-approved auth key also works; it goes straight to the bridge and is never stored.
Configured from a phone
Editing routes on a watch is slow, so Configure from phone shows a QR code for a temporary page served by the watch over the tailnet. The phone's browser edits routes and app access there, Save to watch stores them, and the session ends after ten minutes or when you end it.
Tunnels for other watch apps
Apps signed with the same key bind the broker with a signature permission; other installed apps only if you allow them all explicitly. Each tunnel is a local port that accepts one connection, guarded by a random bearer that is never logged. NOD Term's watch app opens its SSH connections this way. A watch-face complication and a Tile show whether the node is online, waiting for login or offline, and how many tunnels are open.
What has been tested
- Built and run on a Wear OS 5 emulator (API 34, x86_64): the native library loads, and the node correctly reports that it needs login, with a real login link.
- The bridge library is about 44 MB for three ABIs; the release APK about 24 MB.
- The service survived 30 seconds with the screen off at about 57 MB of memory while waiting for login.
Not yet shown: an emulator cannot prove authenticated reachability over LTE, behaviour under a watch maker's power saving, carrier NAT or heat, so those wait for a real LTE watch.
The service starts when you start it. Android 15 does not let it start itself after a reboot or a force-stop, and the Tile opens the app rather than trying to.