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
Qserverby callingsocatviaqvm-connect-tcpinQclient? This seems counterintuitive. - How does
EXEC:qrexec-client-vm...work exactly as the destination forsocatin the call toqvm-connect-tcpinQclient? - 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?