The problem is that in some situations, the servers may well be sitting behind firewalls that only allow outgoing connections to selected ports (usually 80 and 443 for web browsing). One solution to this problem is to use SSH or a VPN server running on one of those ports, but these options have their own problems (key exchange, shell account access, etc)
r4326 implements a proof of concept proxy server (accessible via "
xpra proxy"): the user connects to this server and after authentication (if required - usually/probably should be) the packets are forwarded to the real server. The encryption and compression is only enabled between client and proxy, and not between proxy and server. (though we could quite easily add options to change this)
What is still needed to make this functional:
Other things this may be useful for:
We probably want to make this *the* default proxy for all sessions on a local system (in TCP mode - SSH has user auth already), and allow system level authentication (via PAM on Linux, per platform auth), it should support "xpra list" too.
So we need to specify the username, probably add a "
--username=NNNN" switch? (and/or support
Then there are threading issues, at the moment we start many threads per connection (2 for reading and 2 for writing), which is fine when you typically have just one connection active at a time, but this becomes a problem if we want to proxy for dozens of users. Even more so if the proxy handles picture encoding (one more thread..)
We also need to deal with session discoverability, and this is a good reason for moving the server sockets to
/tmp/. Backwards compatibility can be achieved by symlinking to the old location, checking both locations, (and maybe even adding some code to the
Then ideally we would want some sort of privilege separation between the code that needs root (socket binding, connecting to xpra sockets in /tmp/) and the code that runs once authenticated (IO and encoding).
Here's how I think this is going to work using the python multiprocessing module:
(and maybe this can be used for regular servers too?)
(maybe think about modules that can use a challenge rather than using a plain password)
real uid, real server URI(s), [xpra env options], [session options]
sendmsgand completely separate processes
splits authentication from server core, adds auth modules and keyfile so password file and encryption keyfile can be different
updated patch (broken multiprocessor support..)
Sigh. As explained here: Caution: python-multiprocessing, threads and glib don't mix
So the v5 patch does not run... as the idle_add calls never fire.
updated patch using timers and custom code instead of gobject from the subprocesses
The auth-v6.patch worksaround this by using custom code instead of gobject. Lots of new improvements too:
pamauth works and, setuid/setgid too
What does not work yet / not done yet:
adds attempts at signal handling and process cleanup + 1 important server fix
many fixes (except encryption drop outs)
Works ok as of r4399. We have a number of auth modules we can choose from:
sysis a virtual module which will choose win32 or pam
Once authenticated, the proxy server starts a new process as the user that successfully authenticated (with the uid and gid taken from the password database) and connects to the real server. We choose the real display to connect to using the "display" capability (TODO: let client specify it) or choose the only session we find (if only one exists), or we fail. The special case is with the file auth module, which allows us to specify authentication values which may not be valid system users (though a valid uid/gid pair is still required in that case) and a target display which may be a remote one (ie: "tcp:host:port")
Here's how you can use it with the file auth module (sys auth needs encryption to work as we refuse to send unencrypted system passwords over the sockets):
xpra proxy :100 --bind-tcp=0.0.0.0:20000 --auth=file --password-file=./xpra-auth
echo "antoine|thepassword|1000|1000|tcp:testhost:10|ENV=VALUE|compression=0" >> ./xpra-auth
echo "thepassword" >> password.txt xpra attach --username=myusername --password-file=./password.txt $PROXYHOST:20000
This should cause the proxy to forward the connection to the display specified in the auth file (in the example above:
If things don't work as expected, check that you haven't got an old daemon/zombie running.
Note: as of r4557, one can add session options to the auth file (only two are supported so far as a proof of concept
I have identified the problem with the encryption: it isn't a problem with the encryption per se, the encryption just makes it more obvious.
When using the proxy server, we *always* end up dropping the first packet that the client sends after the hello. Normally, that's a "
set_deflate" or one of two "
server-settings" (if applicable) or the first of the three "
So, when not using encryption, it's still wrong but we just don't notice because those packets aren't essential!
AES decryption relies on the strict presence and order of the data, and the missing packet causes a corrupted stream and disconnection.
That's because when we close the proxy-side connection, we may still have a read blocked in IO wait state via
socket.recv. When the next packet comes in, it gets to read it before closing down...
We either want to force exit the read loop early (not sure how), or get the data read and inject it into the subprocess (intrusive/ugly)... Or add a way to get the client to send a socket flush() (probably not enough to trigger a proxy read?) or to send a dummy unencrypted packet so we can close the connection? (also ugly but somewhat cleaner: everything exits with normal codepaths)
The socket race is fixed in r4614 and encryption now works in proxy mode too (still only between client and proxy - between proxy and proxied server would require more configuration options, and is not a priority at the moment)
Note: we use a socket timeout (defaults to 0.1s) to guarantee that the sockets are always in a consistent state when handing them over to the new subprocess. This does slow down the initial connection (on average by half that delay, so about 50ms). The current value seems like a good compromise between polling too frequently (wasting CPU) and waiting too long.
r4615 allows this timeout to be configured via the
XPRA_PROXY_SOCKET_TIMEOUT env var. (setting this value too high makes it much more noticeable and one can even set it so high that the connection will often timeout)
What is left for this release (the rest can go in an enhancement ticket for another release):
Most of the documentation found in this ticket has been added to the wiki:
As of r4735, the proxy server should be able to exit cleanly. "xpra stop" now works against the main proxy process (one must be authenticated as the same user that runs that process)
I think that's enough for this ticket, please test and close if it all works as expected. Please verify that the connection from the proxy to the real xpra server uses rencode and not bencode.
What we may want to add (in a new ticket):
This has been tested but not extensively. We are going to be testing this with 10+ clients and making sure there is nothing broken.
$ xpra list Found the following xpra sessions: LIVE session at :proxy-28752 LIVE session at :10 LIVE session at :20
Which gives us an easier way of interacting and collecting information from proxy instances. It supports: "info", "version" and "stop".
Is this normal when using the proxy.
]$ xpra list Found the following xpra sessions: LIVE session at :100 LIVE session at :17 LIVE session at :proxy-20954 ]$ xpra --username=username --password-file=./password.txt info :proxy-20954 server requested disconnect: this socket only handles 'hello', 'version' and 'stop' requests
Hmmm, the warning message was wrong (fixed in r5878), "info" is handled, that's one of the main purposes of the proxy socket.
It works fine here... (as usual)
Is there anything in the proxy log? All I see (since it works):
New proxy instance control connection received: SocketConnection(/home/antoine/.xpra/desktop-proxy-25522) Connection lost
Got it: don't use
--password-file. The proxy instance does not support any authentication at present (and I hope it never needs it), it is on a unix domain socket only, so regular unix permissions should be sufficient. Unless someone uses the proxy server and shared group sockets with
Tested this with 8 connections through the proxy with no issues.
Some improvements worth mentioning here:
Both could be backported, but no rush. See also: ticket:838#comment:12
this ticket has been moved to: https://github.com/Xpra-org/xpra/issues/426