Port of: https://github.com/tailscale/tailscale-rs
Inspiration
Tailscale allows secure, gated communication and tunneling to devices even behind highly convoluted network structures like NATs (Network Address Translation) and other VPNs using wireguard + relay servers. Tailscale also brings multiple layers of authentication including 2FA, federated access, transient keys and organization membership to these devices allowing fleet-management and other production-critical features.
A QNX implementation of tailscale would allow greater telemetry and access to edge devices and automobiles along with more robust security features than simple Wireguard or traditional methods like port forwarding or DMZs.
Traditional tailscale is based on Go and would require the Go runtime to be ported to QNX, adding a garbage collector to an other tightly scheduled system where tailscale itself is unlikely to be a high priority process (over things like CAN busses or other real-time peripherals).
tailscale-rs is a recently developing Rust fork of tailscale that has many modular pieces allowing for embedded-specific scenarios such as no-std. It is provided as a library for other applications to bundle on a process-by-process basis rather than the device-wide VPN that tailscale installs. A simple program can pass the traffic from localhost to the outward tailnet (tailscale network) address for nearly the same effect as the VPN install without needing many of the kernel level modification that would be needed for a virtual network interface + VPN.
What it does
Lets a QNX device join a tailnet, advertise its interfaces and create TCP and UDP tunnels to peers on the network. Uses the existing library API of tailscale-rs.
An additional ts-loader program implements an application level port-forwarder (in lieu of tailscale's original tailscaled daemon) to allow ssh (and other) connections to the QNX device over the tailnet.
Challenges I ran into
While many of the changes are mainly compatibility modifications required for QNX 8.0, the tailscale-rs library currently does not have a platform-agnostic fallback for getting network interface information. This required a new crate to be added to tailscale-rs that polls the Unix interface list and reports updates. Since tailscale-rs doesn't permit community PRs without an issue being approved by an existing contributor, as of writing this the issue exists as a suggestion on the tailscale-rs repo.
Accomplishments
A fully-functional ssh terminal was achieved over completely different networks. The QNX device can freely communicate with peers on the tailnet.

Raspberry Pi 4 and 5 images with ts-forward were created to allow out-of-the-box tailscale support, allowing ssh on first boot, even without network-locality.

What I learned
Much of my existing knowledge about tailscale came from the Go client which allows direct syscalls through the Go runtime. tailscale-rs is somewhat different in principle in that its a library first. This means I had to think of parts of the program like the network monitor in terms of Rust libc calls.
What's next for Tailscale-rs QNX Port
Currently each of the patches to the existing crates exist within the port repo, those patches should be upstreamed to their respective crates to allow first-class support for QNX 8.0.
Tailscale-rs itself is pre-release and the API is not guraranteed to stay the same, however the library-based structure is very conducive to running as a RTOS process rather than being a system-level process that would be harder to interrupt.
Built With
- qnx
- raspberry-pi
- rust
- tailscale