qvm-connect-tcp
plays an important role in Qubes, so I’m trying to understand it more fully. In particular, I’m confused about how it works to expose a service with a simple port binding. Any insight into the following would be appreciated and hopefully of value to the forum at large.
In general, exposing a service with socat
in a server-client setup would look something like
user@server$ socat TCP-LISTEN:55555,reuseaddr,fork,bind=server TCP:localhost:55555
enabling user@client
to call on the service at port 5555.
In Qubes, qvm-connect-tcp
employs socat
under the hood, but it’s not clear to me exactly how it works.
Specifically, if we want to expose a service in a qube, call it Qserver
, we would call qvm-connect-tcp ::55555
from another qube, Qclient
, which would invoke socat
as follows:
Qclient$ socat TCP-LISTEN:55555,reuseaddr,fork EXEC:"qrexec-client-vm '' qubes.ConnectTCP+55555"
so the Qclient
qube would listen on port 55555, as the source, and would call qubes.ConnectTCP
acting on the Qserver
qube via qrexec-client-vm
as the destination. (At least this is how I understand it in my admittedly confused state…)
So with a RPC policy of
qubes.ConnectTCP +55555 Qclient @default allow target=Qserver
qvm-connect-tcp ::5555
should create a socat
process in Qserver
which communicates any input from Qclient
to the service listening on port 55555 according to qubes.ConnectTCP+55555
which invokes:
Qserver$ socat STDIO TCP:localhost:55555
However, when I check pstree -ap | grep 55555
in each of these qubes I find the following:
├─socat,632 TCP-LISTEN:55555,reuseaddr,fork EXEC:qrexec-client-vm \\'\\' qubes.ConnectTCP+55555
│ └─socat,728 TCP-LISTEN:55555,reuseaddr,fork ...
│ └─qrexec-client-v,729 qubes.ConnectTCP+55555
in the Qclient
qube and nothing in the Qserver
qube. Leading me to question my understanding of how this all works.
Nevertheless, when I check netstat -talnp
in each qube I find that they are each listening on port 55555 (the service in Qserver
and socat
in Qclient
) and there are established connections in both directions at 127.0.0.1:5555
, as expected.
So I’m left with a few quetions:
- At which points above am I misunderstanding something basic?
- Why does the Qubes documentation expose a service in
Qserver
by callingsocat
viaqvm-connect-tcp
inQclient
? This seems counterintuitive. - How does
EXEC:qrexec-client-vm...
work exactly as the destination forsocat
in the call toqvm-connect-tcp
inQclient
? - How would I replicate this setup outside of Qubes? Would it be as simple as
socat TCP-LISTEN:55555,reuseaddr,fork TCP:localhost:55555
on the server, even though Qubes essentially implements this from the client side?