How to make any tunnel via any proxy

by Martin Monperrus
(tagged as )

1. Problem

In this document, we present the different solutions to a classical problem. How to connect to a target machine on a given port, via another machine ?


2. Motivations

Why is it needed ? Because in a lot of networks :

  • One does not have direct access to the target (firewall, etc.) machine;

  • One has direct access to the target machine but not to the wanted port;

  • Non-democratic networks : one does not want that the target machine knows that it is accessed from the source machine (masquerade).


3. Scheme of resolution

The scheme we will follow is always the same. First we set up a tunnel chain from source:localport to target:targetport. Then, we open connections to source:localport and actually we are connected to target:target port. Example : accessing to mail via IMAP

  1. set up the tunnel from localhost:2143 to imap.toto.com:143

  2. configure yout favorite mail client to access to localhost:2143


4. Tools used

Configuration of all these tools is not detailed. Documentation web pages, man pages and --help are your friends if needed ! A lot of other tools are equivalent. The goal of this document is neither to list nor to compare them (netcat ~= ucspi-tcpclient for example). Note that ucspi-tcpserver is preferred to netcat in listening mode because it allows multiple connections.

NB : In this HOWTO :

  • we do not adress the issue of the encryption of the tunnel (except for obvious SSH tunnels !)

  • others solutions include the ability of some SSH servers of acting as a SOCKS server or the GNU netcat tool.


5. Parameters

The solutions will depend on :

proxy type ssh/telnet/socks/http (proxy web such as squid)
open ports on proxy, is the target port is allowed by the proxy? yes/no
assistant telnet/ssh
root access on assistant (for privileged ports <1024) yes/no
Thus, there are potentially 4*2*2*2 = 32 different cases. Actually, there are less cases described in this document since some are redundant. Note that we are able to use any protocol via an http proxy thanks to the connect method of protocol http.

6. Solutions

All command line are prefixed by {source/proxy/assistant/target}$ to define where the command must be launched. We assume that you know how to launch a command line on a given machine.


6.1. Assistantless

Proxy Command line
ssh (easy and well known)
[user@source]$ ssh -L localport:target:port user@proxy
telnet
[user@source]$ tcpserver localhost localport netcat proxy tmpport&
#connecting to proxy
[user@source]$ telnet proxy
[user@proxy]$ tcpserver localhost tmpport netcat target port
socks
[user@source]$ tcpserver localhost localport connect -4 -S proxy:socksport target port
http
[user@source]$ tcpserver localhost localport connect -H proxy:proxywebport target port
In a lot of cases, these solutions are not sufficient :
  1. ssh : tunnels are disabled

  2. ssh/telnet : proxy machine do not have access to wanted port

  3. socks : wanted port is forbidden

  4. http : wanted port is forbidden (usually, http proxy allow connect only on ports 443 and 563)


6.2. With assistant

If you can not access to wanted target:targetport one needs an assistant machine. An assistant is a machine on the other side of the proxy, where you have an account (ideally where you are root), and from where you have access to target:port.


6.2.1. SSH access on assistant (you do not need to be root)

The easiest with-assistant case: SSH port (22) is allowed by the proxy and you have an account on assistant. Then you access to your assistant via the above methods, and set up a tunnel.

Proxy Command line
ssh
[user@source]$ ssh -L sshlocalport:assistant:22 user@proxy
#on another terminal
[user@source]$ ssh -L targetlocalport:target:targetport -p sshlocalport user@localhost
telnet
[user@source]$ tcpserver localhost sshlocalport netcat proxy tmpport&
#connecting to proxy
[user@source]$ telnet proxy
[user@proxy]$ tcpserver localhost tmpport netcat assistant 22
[user@source]$ ssh -L targetlocalport:target:targetport -p sshlocalport user@localhost
socks
[user@source]$ tcpserver localhost sshlocalport connect -4 -S proxy:socksport assistant 22
[user@source]$ ssh -L targetlocalport:target:targetport -p sshlocalport user@localhost
http
[user@source]$ tcpserver localhost sshlocalport connect -H proxy:proxywebport assistant 22
[user@source]$ ssh -L targetlocalport:target:targetport -p sshlocalport user@localhost

6.2.2. Root access on assistant

But sometimes SSH port 22 is not allowed by the proxy. Then, the best thing to do is to launch a SSH server which listen on an accessible port from the proxy (for example port 443 via a HTTP proxy). In short, you should modify one line of sshd.conf or of the (x)inetd configuration file. Then it is exactly the same methods as previous section, but usual SSH port (22) is replaced by the allowed port.

Proxy Command line
ssh
[user@source]$ ssh -L sshlocalport:assistant:allowedport user@proxy
#on another terminal
[user@source]$ ssh -L targetlocalport:target:targetport -p sshlocalport user@localhost
telnet
[user@source]$ tcpserver localhost sshlocalport netcat proxy tmpport&
#connecting to proxy
[user@source]$ telnet proxy
[user@proxy]$ tcpserver localhost tmpport netcat assistant allowedport
[user@source]$ ssh -L targetlocalport:target:targetport -p sshlocalport user@localhost
socks
[user@source]$ tcpserver localhost sshlocalport connect -4 -S proxy:socksport assistant allowedport
[user@source]$ ssh -L targetlocalport:target:targetport -p sshlocalport user@localhost
http
[user@source]$ tcpserver localhost sshlocalport connect -H proxy:proxywebport assistant allowedport
[user@source]$ ssh -L targetlocalport:target:targetport -p sshlocalport user@localhost

6.2.3. telnet access on assistant (on which you are not root)

Those cases will not be expanded for the four proxy types, but just for socks ! Port > 1024 are likely to be opened, such as CVS port (2041).


6.2.3.1. Telnet port is allowed by the proxy, and another one > 1024

For this case, you need to have at least two allowed port by the proxy (telnetport - 23 and allowedport). One for the setting the tunnel via telnet, the other for the tunnel (unlike SSH tunnels which are encapsulated onto the same port).

Proxy Command line
socks
# telnet connection to source
[user@source]$ tcpserver localhost localtelnetport connect -4 -S proxy:socksport assistant telnetport&
# telnet assistant via tunnelsource
[user@source]$ telnet localhost localtelnetportassistant
[user@assistant]$ tcpserver localhost allowedport netcat target targetport
# in another terminal, setting up the final tunnel
[user@source]$ tcpserver localhost localport connect -4 -S proxy:socksport assistant allowedport
# it's done, you just have to access to localhost:localport and in fact you are on target:targetport

6.2.3.2. Only one port > 1024 is allowed by the proxy

Previous tunneling techniques let us to set up the tunnel entirely from the source. For this last case, you need to launch a command being "outside". From outside:

[user@assistant]$ tcpserver localhost allowedport netcat target targetport&
Proxy Command line
socks
[user@source]$ tcpserver localhost localport connect -4 -S proxy:socksport assistant allowedport

7. Conclusion

As a conclusion, there is almost always a solution to access to a given port on a target machine. The only cases where it is impossible are:

  • No port > 1024 is allowed by the proxy and you are not root on assistant

  • HTTP proxy does not accept the CONNECT command, hence does not accept HTTPS. This is unlikely to appear !

With the concepts and commands presented in this paper, you should be able to set up a tunnel chain of any length!