[ Prev ] [ Index ] [ Next ]

SSH Port-forwarding and tunnels

Created Sunday 1/2/2004

Todo: Needs textile formatting

1. Portforwarding using ssh

Note: CVS examples for accessing port 2401 from behing a firewall in cvs.

It's possible to forward ports on the local machine to ports on a remote server using ssh(1). The -L command of ssh allows for a target port on the remote server to be mapped to a different port on that same server.

This has obvious implications for client pc's that have ssh access to a particular server that run's services that are of interest. Examples of these include accessing a Perforce repository, running X11 applications and accessing database serices.

2. Perforce

It is possib;e to access a perforce server running on a remote machine called perforce.com, by making an ssh tunnel from the client PC and requesting that the ssh daemon at the other end perform port fowarding of a given port to the perforce port.

If the server is listening for perforce requests on the standard port 1666, then we might ask that server to forward 4000 to 1666 on the localhost, by executing the command:

ssh -L 4000:localhost:1666 user@perforce.com

Any other ssh options such the userid and any special ports required to access the ssh daemon must also be given. After the ssh connection is established, the client simply sets the perforce server and port to localhost:4000.

Any request send to the localhost's port 4000 is picked up by ssh and dispatched off to the ssh daemon listening at the other end's port 4000, who then redirects these requests onto the normal perforce port 1666.

For neatness, it's possible to get the ssh client to not actually login and create a shell by asking it to perform some arbitraryily long command like sleep(1). This can be done with:

ssh -L 4000:localhost:1666 user@perforce.com -c "sleep 9999999&"

3. X11 XFree86/Xorg

Another interesting part of ssh forwarding is the use of the -X switch, which tells ssh to foward all X11 requests back to the client. If the client is running an X-server, then it's possible to run an application under X on the remote machine and have it display on the client.

By default, X11 forwarding is done via port 6000 on the X display server (the client PC). The ssh client then connects to the remote machine and sets up the port forwarding there. The same process also sets the DISPLAY variable to point back to the forwarded port on the remote machine. To do this, use ssh's -X option, such as:

ssh -X foo@server.com

After login, the DISPLAY variable will be something like DISPLAY=localhost:14. X11 requests received on the localhost (which is the remote machine) will be forwarded back to the X display server (the client pc) on port 6000 by default. The client PC must be running an instance of X (via xinit or gdm or other).

3.B Cygwin XFree86

Cygwin's X server works fine in this way too. Simply start a cygwin shell, run X via xinit (by executing "startx"), start another shell and login to the remote server with X11 forwarding, using the -X option and bob is your uncle.

4. SCP

It's possible to setup an ssh tunnel to avoid the hassle of having to go through a restricted ssh port on a machine that allows connections only from a specific host (assumeing of course access is available from the ssh client machine to this specific host). E.g., assume host transmission only allows ssh connections over port 2222 from host bund. In this case, a client 'gillian can access transmission'' directly by setting up the following tunnels:

5. Port Forwarding CVS

Note: This section assumes access to port 22 is available.

The cvs remote repository normally works over port 2401. If this is blocked, but 22 is open on the localhost and you have ssh access to a machine that has 2401 open, then the cvs remote commands and work via hopping over the blocked ports using the ssh tunnels, like this:

For example, the cvs repository for enlightenment is hosted on 2401 at cvs.sourceforge.net. To access this repository from blockedhost, do the following:

blockedhost $ ssh -L 2401:localhost:2401 user@openhost
openhost $ ssh -L 2401:cvs.sourceforge.net:2401 user@localhost

Then operations on the cvs repository on "blockedhost" are directed at localhost, thus:

blockedhost $ cvs -d:pserver:anonymous@localhost:/cvsroot/enlightenment login
blockedhost $ cvs -z3 -d:pserver:anonymous@localhost:/cvsroot/enlightenment co module

This should checkout the files in module from cvs.sourceforge.net using the several ssh portforwarded tunnels.

6. MSN (Gaim/aMSN) behind a firewall

Many of the p2p chat programs use http tunnels to establish the communication socket on which to talk. However, some programs don't and go directly over the msn chat port (1863). If this port is blocked, or the http tunnel method of amsn doesn't work, then port forward the msn port 1863 to a host that does allow access over the msn port. The hostname to link the final phase of the redirect is 207.46.107.113 (which is baym-cs313.msgr.hotmail.com) and not messenger.hotmail.com. E.g.,:

on blockedhost:
bash $ ssh -L 1863:localhost:1863 user@openhost

on openhost:
bash $ ssh -L 1863:207.46.107.113:1863 user@localhost

or:
bash $ ssh -L 1863:baym-cs313.msgr.hotmail.com:1863 user@localhost

Then in GAIM/AMSN configuration: set the connection method to direct so that it uses port 1863 (this option is available in amsn on the tools->preferences->connection tab. I think GAIM uses this port by default and so probably doesn't require an explicit configuation setting). Then specify the connect server as localhost:1863 (within AMSN, this is on the tools->preferences->advanced tab)

7. Gnutella (Mutella) behind a firewall, with blocked ports

Assumption: port 22 and 80 outbound are open on the blockedhost and we can ssh to a host that has the public port range open. In the following steps blockehost refers to the host with only 22 and 80 open and openhost refers to the host with the public port range open.

Todo: Add sub-sections for the A,B,C sections and textile markup and to general cleanup

The gnutella network uses port 6346 by default, but the Gwebcaches open redirect to many other ports (7504, 4191, 6350, etc.). The easiest way to get arround the situation where outbound ports are blocked is to do the following:

▨ Note: The output in the following sections uses > for the mutella prompt and $ for the shell prompt. The shell prompt is prefixed by an example name where required.

7.A. Port forward 6346

Set up an ssh tunnel over the gnutella port 6346 on the blockedhost     the same port on the openhost    . In ssh terms, this requires forwarding the port from the host behind the firewall (the blockedhost) to the host outside the firewall (the openhost) using the unblocked ssh port 22. E.g.,

blockedhost $ ssh -L 6346:localhost:6346 user@openhost

7.B. Determine high efficiency openhost

▨ Note: This step requires mutella, download from mutella.sourceforge.net

In selecting a gnutella host, it is best to choose one with a high efficency. The best way to determine this is to use mutella on the host outside the firewall (i.e., on openhost). The mutella command info conn will list the active connections, displaying data about the connected hosts. From the displayed list, locate an entry that has a high efficiency and has a non-zero I/O Rate and a reasonable Horizon.

> info conn
gnutella network connections:
-----------------------------
no.|     address:port | rate i:o | horizon | eff. | uptime
1)  81.241.61.34:7504   1.25K:5    2/128M   100%    2h25m 
2)  68.13.81.226:6346    0:0         0/0K      0%     11s

From this, we see that the first (#1) entry is a good candidate. we remember this host ip and port

7.C. Setup the ssh tunnel

After selecting a host with high efficiency host, an ssh tunnel must be established by using the ssh port forwarding option. The tunnel will connect the the openhost to the IP and port selected in step #7.B, previously.

openhost $ ssh -L 6346:81.241.61.34:7504 user@localhost

7.D. Add the port fowarded entry to mutella

On blockedhost, edit the hosts.save file, located in the $HOME/.mutella directory. Add the single entry localhost:6346

▨ Todo: Describe why this is necessary

7.E. Edit the webcache

The Web Cache entries on the blockedhost must be edited so that XXXX. This is done by editing the Gwebcache entries in the xx on blockedhost. These entries are in the $HOME/.mutella/webcaches.save file. Remove all entries that do not use the standard http port 80. E.g., an entry like http://goeg.dk/Gnutella/gcache.php is ok as it uses the default http port (80), but entries such as http://cache.kicks-ass.net:8000 (where the specified port is anything other than 80) should be removed.

7.F. Start mutella

Start the mutella app on blockedhost by running whatever startup script is appropriate. Typically this is done by simply running the command:

blockedhost $ mutella

7.G. Force a connection to localhost

A connection to localhost must be created. This is done using mutella's open command, which assumes port 6346 by default. Again, the > is the mutella prompt.

> open localhost

7.H. List connections

We have now forwarded port to 6346 on the blockedhost to the same port on openhost. The openhost port 6346 is then itself forwarded to (e.g.,) port 7504 on the host with IP address 81.241.61.34 (this is the host we determined as having high efficency in step #7B). This now means that we should see an active connection to a host in the gnutella network. We can determine if this is the case by excuting a connection information request by issuing info conn within mutella on the blockedhost. The list should contain one active entry that matches the stats of the gnutella host we selected in step #7C. The list will also contain a bunch of dead entries, which correspond to standard gnutella discovery (pointing to hosts and ports that we cannot reach as we did not forward to them):

> info conn
gnutella network connections:
-----------------------------

no. |   address:port     | rate i:o | horizon | eff. | uptime
1)       127.0.0.1:6346     389:1      51/3.19G  100%    2h43m
2)     68.90.79.91:6349       0:0          0/0K    0%       6s 
3)   213.46.199.20:6346       0:0          0/0K    0%       6s
etc.

7.I. Test connection to gnutella network

After completing the preceeding steps, it should now be possible to access hosts on the gnutella network on a blockedhost, a host beind a firewall which has the gnutella ports (6436, 7504 etc.) blocked. As a test, perform a find on the gnutella network. For example,

> find 2pac
> list
   Searches in progress, matching your criteria
1) `2pac'
    no size filter            HITS:256
    count: 2

8. Port fowarding UDP ports to TCP

It's possible to forward udp ports over tcp using netcat, nc(1), Here's an example excerpt from from nc(1):

▨ Todo: Need citation as for why for tunnelling UDP over TCP is not good

Tunneling UDP over TCP is generally considered a bad idea netcat may be of use here? Something like this may work (warning: not tried and certainly not tested):

outside-firewall$ nc -l 2345 | nc -u localhost 1234
inside-firewall$ nc -l 1234 -u | nc outside 2345

Which should (in theory) connect UDP port 1234 on inside to UDP port 1234 on the outside, tunneling via TCP on port 2345. So instead of connecting directly to outside:1234 you can connect to localhost:1234.

9. CU to localhost with ssh tunnels

Assumption #1: The localhost has IP address 83.31.205.217

Services on hosts in the CU Polksa DMZ such as bumerang can be accessed by setting up several ssh tunnels. If the host that the tunnels are being created from is in the same geographic region (i.e, in Poland), then accessing services such as Perforce over these ssh tunnels is actually much faster than using the vpn the end-points of the service tunnel are connecting hosts that are a few hops away from each other. For the vpn, traffic must travel from poland to melbournce then up to poland then back again.

To setup the ssh tunnel, use the ssh(1) port forward (-L) and reverse forwarding options (-R). The script ssh-portfw(1U) does the port forwarding so long as reverse tunnel as been previously setup. The ssh-portfw uses the port specified in the variable ssh_tunnel_port as the port where the reverse tunnel has been created. The following interaction shows how to hop over specific ports on a firewall. The configuration in this example is typical of many commerical environments, where a user is allowed to login to a host, but is typically restricted to port 80 (http) and similar (imap and a few others).

Assumption #2: All ports a blocked inbound including ssh 22 inbound. The user is already on blockedhost (i.e., on the internal network).

In this sequence, an ssh connection to bumerang, a host in the CUP DMZ is established. This is done by connecting to the Fluency GW, which is only possible if the connection is comming from one of a few well-known hosts, such as bund.com.au, from the Fluency GW, a connection to the CUP DMZ is possible via the Fluency-CUP VPN. The DMZ is located behind a CUP Firewall which is pretty much all inbound ports blocked but allows ssh outbound over port 22. We make use of ssh outbound over port 22 to create a reverse tunnel over port 2225, which is then used as the connect-to (inbound) port for setting up port forwarding for ports like Perforce (1666), Bugzero (8080), Oracle (1521) and etc. The forwarded ports are setup using the ssh-portfw script, which requires the existence of a reverse ssh tunnel. The ssh-portfw script uses the variable ssh_tunnel_port as the reverse tunnelling port, which has a default value of 2225. Be sure to specify a different value for this variable if the reverse tunnel is created on a different port.

somehost $ ssh foo@bund.com.au
bund $ ssh -p 2222 foo@mel-gw.fluencyfinancial.com
mel-gw $ ssh foo@bumerang
bumerang $ ssh -R 2225:localhost:22 foo@83.31.205.217
somehost $ ssh_tunnel_port=2225 ssh-portfw

10. See also

Other foonix™ documentation relating to port forwarding:

Stuart Moorfoot © 1 Feb 2004 foo@bund.com.au


Backlinks: Home