Teamviewer alternative: How to get a Remote Desktop VNC connection via SSH over an intermediate server, avoiding firewalls

What to do when Teamviewer suddenly doesn’t connect or you can’t or don’t want to use it for other reasons? What if a friend needs urgent assistance and you need to see his screen to help out? Standard Open Source tools to the rescue! If you know how to use SSH from the command line and have access to an user account on a remote server running SSHD, then this article will save you!

Teamviewer-like products are so popular because they solve a real problem: To connect from one household computer to another is not straightforward because we all use regular modems/routers to connect to the internet. They are usually not set up for Port Forwarding. In laymans terms this means: You can initiate a connection to the internet, but the internet never can initiate a connection to you. This quandary has only one solution: an intermediary is needed. Teamviewer-like products all offer such intermediary servers. Data is never directly sent from one computer to the other. Data is passed through a server (which allows for all kinds of spying by the way, if the encryption is not good enough!)

There are tons of (unfortunately for me) half-working instructions in the web about how the commands must look like. I took me several hours to wrap my mind around the problem. For this article, I’ve decided to make an image gallery so that you can see easier what is going on behind the scenes. Running just 4 commands will do the trick!

The following list and image shows the starting point of our situation:

We are sitting in front of the computer called “sittinghere”.

We want to see the screen of the computer called “overthere”.

There is a server called “hopper” which runs an ssh daemon (sshd) listening on the standard port 22. Our data will ‘hop’ though there, hence the name “hopper”.

The initial situation: Regular firewalls are constrict “sittinghere” and “overthere”. “hopper” has a firewall with only port 22 open.

We instruct our friend, sitting in front of the computer “overthere”, to start any kind of VNC server. There are many products for Windows, Mac OS, and Linux available. I’m using Linux and decided for x11vnc because it allows access to the screen of the currently logged in user instead of starting a new user session. The command is:

1

x11vnc-nap-noxdamage-passwd PASSWORD-display:0-forever-bg

After this command, our situation has changed. See the following image. The VNC server has started listening on port 5900 (see lower right corner):

A VNC server is started “overthere”. It listens on port 5900.

Now we have to instruct our friend, sitting on “overthere”, to run a ssh command to connect to “hopper”. You can make a little batch script for this to make it more convenient, but this is not the focus of this article. The command is:

1

ssh-R7001:localhost:5900hop@hopper.com

With this command, sshd on “hopper” is instructed to create a socket on port 7001. And when someone connects to this port, it will be as if the same connection had been made on “overthere” port 5900. In the code above, “localhost” refers to the computer “overthere” because the command is executed on this computer.

Let’s see how our situation now looks like:

An ssh client is started “overthere” with Remote Port Forwarding options. A connection is made to sshd, running on “hopper”. sshd opens a port on localhost:7001 and listens for incoming connections.

Now that “overthere” has done its connection to “hopper”, it is time for “sittinghere” to connect to “hopper” too. Here is the command:

1

ssh-L7002:localhost:7001hop@hopper.com

This means: A socket on port 7002 will be created on localhost (“sittinghere”). If someone connects to this port, it will be as if the same connection had been made on port 7001 on “hopper”. Here’s the new situation:

“sittinghere” starts ssh with Local Port Forwarding options. It connects to sshd running on port 22 of “hopper”. It also creates port 7002 on localhost and listens for incoming connections.

Now, remember that a connection to port 7001 on “hopper” will have the same effect as if the same connection had been made on “overthere”. This means we will have a kind of ripple-through effect: As soon as we connect to port 7002 on “sittinghere”, the connection will ripple through until it connects to port 5900 of “overthere”. And this endpoint is our VNC server.

Now let’s connect with a VNC client from “sittinghere” to “overthere”. You will find lots of good VNC clients in the internet. Just connect to

1

localhost:7002

which is equivalent to

1

127.0.0.1:7002

This will start our connection cascade, and the final situation looks like this:

On “sittinghere”, a VNC viewer is started and told to connect to localhost port 7002. This connection is detected by ssh which makes sshd running on “hopper” connect to port 7001, which causes ssh running on “overthere” to connect to port 5900. Now the route is complete and we can see the remote screen!

Congratulations, we’re now all connected through! If you have set a password (we’ve set it to “PASSWORD” in the above example), you now will see the remote screen. Note that we didn’t even have to execute a command on “hopper”, nor even reconfigure any firewall! My experience is that the quality and speed of the transmitted remote image is much better with this method than with commercial products. Of course, this is because commercial products have to divide and share bandwidth across all users.

The SSH connections will stay alive until you terminate them. So, just type “exit” in the ssh terminals opened at “sittinghere” and “overthere” that we have been opened previously (to “hopper”).

4 Responses to Teamviewer alternative: How to get a Remote Desktop VNC connection via SSH over an intermediate server, avoiding firewalls

Hello,
I really love this article. And if you don’t mind I have one thing to add (if it is not mentioned somewhere else).

In most cases you won’t like the guy sitting “overthere” to have full shell access. Moreover, you probably want him to have no access at all. But here comes the problem. How am I going to give him SSH access without SSH access :).

It is just a suggestion so don’t hesitate to correct me if you find some mistakes here.

I made this using SSH ChrootDirectory on my FreeBSD server. I created user for such special use called remoteaccess. I made him whole environment needed to run shell and open the socket, but nothing more. I have done it like follows:

I created directory /remoteaccess where I copied /bin/bash and all libs it needed:
# mkdir -p /remoteaccess/{dev, home, lib, libexec, usr}
# mkdir /remoteaccess/home/remoteaccess
# mkdir -p /remoteaccess/usr/local/bin
# cp -p /usr/local/bin/bash /remoteaccess/usr/local/bin
And put those lines into sshd_config:
Match User remoteaccess
ChrootDirectory /remoteaccess
After that try to login to your remoteaccess user. There should be some errors about libs that are missing. So you have to copy them to “chrooted root file system”.
After that the user remoteaccess is not able to run any of bash commands (although I gave him the possibility) and sees /remoteaccess folder as its root filesystem.

I hope this helps.

@Michael: Do you mind if I translate your article to Polish, add some comments and post it on my blog (blog.tstrojny.pl)? Mentioning your blog of course.

[…] An established SSH connection has a number of security implications. As I have argued in a previous blog post “Unprivileged Unix Users vs. Untrusted Unix Users”, having access to a shell on a server is problematic if the user is untrusted (as is always the case when the user originates from an untrusted machine), even if he is unprivileged on the server. In my blog post I presented a method to confine a SSH user into a jail directory (via a PAM module using the Linux kernel’s chroot system call) to prevent reading of all world-readable files on the server. However, such a jail directory still doesn’t prevent SSH port forwarding (which I illustrated in this blog post). […]