Relay WSL unix sockets through windows named pipes by using a relay proxy native windows program's stdin and stdout.
Think of it as the inverse of npiperelay.exe
- Although
AF_UNIX
support exists in Windows, as of30.09.2024
, native programs cannot use unix sockets from WSL 2, see microsoft/WSL#5961. They are supported in WSL 1 though. - Spawning TCP listeners on
localhost
would be easy, but it is not secure as any users logged-in to the machine can listen to them. In some environments, this might not be acceptable. - Personal note - I wish this utility wouldn't exist and WSL 2 sockets can be used by native windows programs, just as WSL 1.
Flow of communication when using socat relay
sequenceDiagram
Windows-->>Windows: Spawn native windows container-desktop-relay.exe
Windows-->>NamedPipe: Spawn named pipe server
Windows-->>WSL: Launch WSL linux program - Listen to STDIO
WSL-->>UnixSocket: Listen to UNIX socket - Write STDIN data to socket
UnixSocket-->>WSL: Write socket data to STDOUT
NamedPipe-->>WSL: Write data to WSL process STDIN
WSL-->>NamedPipe: Read data from WSL process STDOUT
NamedPipe<<-->>UnixSocket: Bidirectional communication (unix socket <=> named pipe)
Flow of communication when using sshd relay
sequenceDiagram
Windows-->>Windows: Spawn native windows container-desktop-relay.exe
Windows-->>NamedPipe: Spawn named pipe server
Windows-->>WSL: Launch WSL linux sshd server - Listen to TCP
WSL-->>UnixSocket: Dial UNIX socket - Write SSH data to unix socket
UnixSocket-->>WSL: Read UNIX socket data - Write socket data to SSH socket
NamedPipe-->>WSL: Write named pipe data to WSL SSH socket
WSL-->>NamedPipe: Read data from WSL SSH socket - Write to named pipe
NamedPipe<<-->>UnixSocket: Bidirectional communication (unix socket <=> named pipe)
- NodeJS installed in windows and exposed to
%PATH%
(needed to test the relay named pipe connection) - WSL with default distribution(Ubuntu)
- Build dependencies
In the default WSL distribution(Ubuntu), where the repo is cloned and where tests are made, golang and windows cross-compilation and optimization tools are needed.
sudo apt-get install build-essential gcc-mingw-w64 musl-tools golang upx-ucl
- Static binaries are generated to make the relay available on as many linux distributions as possible, besides the default WSL distribution(Ubuntu)
- UPX is used to reduce the size of the binaries, that are usually embedded into other programs
./relay-build.sh
- Inside the cloned directory, execute the next script from
wsl.exe
terminal console - IMPORTANT - Not windows powershell or cmd! - Must use
node.exe
becauserelay-test.js
will need to connect to a named pipe, only Windows has named pipes, hencenode.exe
, notnode
!
./relay-build.sh
./relay-start.sh
From a powershell console
npm install
node.exe relay-test.js
- AllowEveryone =
"S:(ML;;NW;;;LW)D:(A;;0x12019f;;;WD)"
- AllowEveryone - to be avoided, allows any users running on current machine. - AllowCurrentUser =
"D:P(A;;GA;;;$SID)"
- AllowCurrentUser grants full access permissions for the current user. The variable$SID
is interpolated at runtime. - AllowServiceSystemAdmin =
"D:(A;ID;FA;;;SY)(A;ID;FA;;;BA)(A;ID;FA;;;LA)(A;ID;FA;;;LS)"
- AllowServiceSystemAdmin grants full access permissions for Service, System, Administrator group and account. - If the permission don't match the strings above, any ACL expression can be used.
Example with SSH relay - from a WSL terminal bash console
RELAY_SOCKET=$(docker context inspect --format json | jq -e ".[0].Endpoints.docker.Host | sub(\"unix://\"; \"\")" | tr -d '"')
RELAY_PIPE="\\\\.\\pipe\\container-desktop-test"
RELAY_PROGRAM="$PROJECT_HOME/bin/container-desktop-ssh-relay-sshd"
./bin/container-desktop-ssh-relay.exe \
--named-pipe \
"npipe:////./pipe/container-desktop-test" \
--ssh-connection \
"ssh://istoica@localhost:50508/var/run/docker.sock" \
--ssh-timeout \
15 \
--identity-path \
"./temp/id_rsa" \
--distribution \
"Ubuntu-24.04" \
--relay-program-path \
"./bin/container-desktop-ssh-relay-sshd" \
--watch-process-termination \
"--generate-key-pair" \
--host \
"localhost" \
--port \
"50508"
Test using a NodeJS child_process
started by the Windows native node.exe
interpreter. This can be executed from any shell.
node.exe relay-test.js
container-desktop-wsl-relay.exe --help
-buffer-size int
I/O buffer size in bytes (default 512)
-distribution string
WSL Distribution name of the parent process
-named-pipe string
Named pipe to relay through (default "\\\\.\\pipe\\container-desktop")
-parent-pid int
Parent WSL Distribution process ID (default -1)
-permissions string
Named pipe permissions specifier - see https://learn.microsoft.com/en-us/windows/win32/ipc/named-pipe-security-and-access-rights
Available are:
AllowServiceSystemAdmin=D:(A;ID;FA;;;SY)(A;ID;FA;;;BA)(A;ID;FA;;;LA)(A;ID;FA;;;LS)
AllowCurrentUser=D:P(A;;GA;;;$SID)
AllowEveryone=S:(ML;;NW;;;LW)D:(A;;0x12019f;;;WD)
(default "AllowCurrentUser")
-pid-file string
PID file path - The native Windows path where the native Windows PID is to be written
-poll-interval int
Parent process polling interval in seconds - default is 2 seconds (default 2)
-relay-program-options string
The options to pass to the WSL relay program(socat UNIX-CONNECT options) (default "retry,forever")
-relay-program-path string
The path to the WSL relay program (default "./socat-static")
-unix-socket string
The Unix socket to relay through (default "/var/run/docker.sock")
- The spawned Windows native
container-desktop-wsl-relay.exe
is checking every2
seconds if the parent process that spawned it has died, in such case it exits. - Why is the custom
socat
build static binary renamed - to be easily identifiable fromps -aux
- Why the need for custom
socat
build - because users ignore it, because it is hard to ensure on all distributions supported by WSL, because I don't know how to write an equivalent myself.