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.

Tailscale Architecture

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.

Tailscale Wireguard Mesh

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.

QNX Node shows up on tailscale admin console

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.

Tailscale SSH to QNX Raspberry Pi 5 using ts-forward

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

Share this project:

Updates

Submission history