Running two reverse proxies (one in Windows, one in the WSL2 Linux VM), the Windows Tailscale daemon can be accessed via WSL2:
$ tailscale ip
100.101.102.102
$
$ tailscale status
100.101.102.102 suspicious-hawking dhermes@ windows -
100.101.102.103 pedantic-yonath dhermes@ linux -
On standard Linux, tailscaled
runs via systemd
and makes deep modifications
to network interfaces and routing to make sure Tailscale packets get handled
by Tailscale. However, on WSL2 there is no systemd
and the Linux VM doesn't
have "real" control of Windows host networking, so running tailscale
directly
in WSL2 isn't really an option.
However, Tailscale for Windows is a perfectly good choice and all of the host networking changes made by it are still visible to the WSL2 VM. This means things like Tailscale DNS and Tailscale routing "just work"
$ nslookup pedantic-yonath
Server: 100.100.100.100
Address: 100.100.100.100#53
Name: pedantic-yonath.dhermes.github.beta.tailscale.net
Address: 100.101.102.103
$
$ ssh dhermes@pedantic-yonath
dhermes@pedantic-yonath:~$
dhermes@pedantic-yonath:~$ tailscale ip -4
100.101.102.103
However, from the Linux side of WSL2, there is still no direct way to get information about the current device and other parts of the Tailnet:
$ tailscale ip -4
Failed to connect to local Tailscale daemon for /localapi/v0/status; not running?
Error: dial unix /var/run/tailscale/tailscaled.sock: connect: no such file or directory
This repository provides two reverse proxy binaries (one for Windows, one for Linux) that make it possible to directly reference the Windows-managed Tailscale daemon from inside the WSL2 VM.
On Linux, the tailscale
binary expects to communicate with tailscaled
via
a Unix Domain Socket (UDS) at /var/run/tailscale/tailscaled.sock
. However,
Windows (i.e. not Unix-y) doesn't have a UDS equivalent, so there isn't even
a host socket that the WSL2 VM could try to interact with. Due to this
Windows feature difference, the Tailscale daemon runs as a cleartext HTTP
service on localhost:41112
(as of Tailscale 1.18.1).
Unfortunately the local network interface on Windows is (intentionally) not exposed to the WSL2 VM. However, there is a virtual network interface that can be used to bridge the Windows host to the WSL2 VM:
PS C:\Users\dhermes> ipconfig
Windows IP Configuration
...
Ethernet adapter vEthernet (WSL):
Connection-specific DNS Suffix . :
Link-local IPv6 Address . . . . . : fe80::ed6d:71c5:2607:3ce6%22
IPv4 Address. . . . . . . . . . . : 172.27.64.1
Subnet Mask . . . . . . . . . . . : 255.255.240.0
Default Gateway . . . . . . . . . :
...
To expose the Tailscale daemon to the WSL2 VM, we bind a server to the
virtual network IP (e.g. here 172.27.64.1
) and run a reverse proxy
in Windows that will be available to the WSL2 VM:
PS C:\Users\dhermes\tailscale-wsl2> go install .\cmd\tailscale-wsl2-windows\
PS C:\Users\dhermes\tailscale-wsl2> tailscale-wsl2-windows.exe --vethernet-wsl-ip 172.27.64.1
Running a TCP reverse proxy is super easy with the super awesome
inet.af/tcpproxy
package. This package was of course created by the
lovely folks at Tailscale. They also made the inet.af/wf
package for
Windows Firewall operations, which turns out to be necessary to bind to
the virtual network IP. See Windows Firewall for more information about
which firewall rules are necessary.
But, this only solves half of the problem. The tailscale
CLI still assumes
it will have a UDS to talk to. To solve this problem, we run a second
reverse proxy, but on the Linux side of the house:
$ go install ./cmd/tailscale-wsl2-linux/
$ sudo tailscale-wsl2-linux --host-ip 172.27.64.1 --tailscale-socket /var/run/tailscale/tailscaled.sock
The default value of --tailscale-socket
is actually
/var/run/tailscale/wsl2-tailscaled.sock
to avoid colliding with the socket
that tailscaled
expects to be the owner of. If that default is used instead
then it needs to be explicitly provided to tailscale
$ tailscale --socket /var/run/tailscale/wsl2-tailscaled.sock ip -4
100.101.102.102
Having the client and server version mismatch is not great and actually causes the server to reject some requests:
$ tailscale ip -4
Warning: client version "1.18.1-t0a4334048-gb05dc05d4" != tailscaled server version "1.18.0-t22d969975-g7022e5a4c"
100.101.102.102
$ tailscale ping pedantic-yonath
Warning: client version "1.18.1-t0a4334048-gb05dc05d4" != tailscaled server version "1.18.0-t22d969975-g7022e5a4c"
2021/12/05 19:47:58 GotNotify: Version mismatch! frontend="1.18.1-t0a4334048-gb05dc05d4" backend="1.18.0-t22d969975-g7022e5a4c"
Notify.ErrMessage: GotNotify: Version mismatch! frontend="1.18.1-t0a4334048-gb05dc05d4" backend="1.18.0-t22d969975-g7022e5a4c"
Installing tailscale
from source is probably the best plan to ensure this
version mismatch doesn't occur, but at least for now the custom APT
package matches the Windows version:
$ tailscale version
1.18.1
tailscale commit: 0a43340482a86c3c227aa133c8f1ee9e36360b4b
other commit: b05dc05d46c4a3c7e634ef0695221985be99274d
go version: go1.17.2-ts7037d3ea51
$ [sudo] apt-get install tailscale=1.18.0
$ tailscale version
1.18.0
tailscale commit: 22d9699759fa34247153a542e9c4af5696c01fdf
other commit: 7022e5a4ccce1d12fbe4f679d641d816d81491a1
go version: go1.17.2-ts7037d3ea51
$
$ tailscale ip -4
100.101.102.102
$ tailscale ping pedantic-yonath
pong from pedantic-yonath (100.101.102.103) via 192.168.7.131:41641 in 5ms