19

I have a computer with CentOS (computer A) that configured as has an private ip 10.150.5.141 (with restricted firewall), can access internet and my ArchLinux VPS (computer B) with real ip w.x.y.z

How can I make another pc (computer C) that could access computer B to connect to computer A, but computer C cannot connect to computer A directly (because it's on A's own private network)?

I know that a tunnel can open local ports to another computer:port, but how to do the opposite?

I want to access computer A using ssh through computer B but computer B cannot access computer A, because the network on computer A is restrictive (can go out, but can't go in, because I have no access to their router)

I want something like this:

ssh -connect-to w.x.y.z:22 -open-port vvv -forward-to 10.150.5.141 -port 22

so that when I ssh w.x.y.z:vvv from computer C it will forwarded to private network 10.150.5.141:22.

Kokizzu
  • 9,699

3 Answers3

14

What you're looking for is called a reverse tunnel. ssh provides it through the -R switch:

-R [bind_address:]port:host:hostport
       Specifies that the given port on the remote (server) host is to 
       be forwarded to the given host and port on the local side.  This 
       works by allocating a socket to listen to port on the remote side, 
       and whenever a connection is made to this port, the connection is
       forwarded over the secure channel, and a connection is made to host 
       port hostport from the local machine.

As the OP discovered with their answer the syntax is as follows:

$ ssh -f -N -R vvv:localhost:22 w.x.y.z

Example

I have 2 computers on the network, lappy and remotey. So I run the following command on lappy:

$ ssh -f -N -R 12345:localhost:22 remotey

I can confirm that it's working:

$ ps -eaf|grep "[l]ocalhost:22"
saml     27685     1  0 11:10 ?        00:00:00 ssh -f -N -R 12345:localhost:22 remotey

Now if I ssh separately over to the remote system, remotey and run this command I can see that it's now accepting connections on port 12345 on the remote system's local interface:

$ netstat -an|grep :12345
tcp        0      0 127.0.0.1:12345             0.0.0.0:*                   LISTEN      
tcp        0      0 ::1:12345                   :::*                        LISTEN      

Testing the connection

You can see that the reverse ssh tunnel is working as follows.

  1. login to remotey

    [user@lappy ~]$ ssh remotey
    
  2. test out reverse tunnel port

    [user@remotey ~]$ ssh -p 12345 localhost
    
  3. should now be back on lappy

    user@localhost's password: 
    Last login: Thu Aug  1 17:53:54 2013
    /usr/bin/xauth:  creating new authority file /home/user/.Xauthority
    [user@lappy ~]$ 
    

Ports on interfaces other than localhost (lo)?

You might be left scratching your head if you try a command like this and it doesn't appear to work, or it always binds to a port on the localhost (lo) interface.

For example:

lappy$ ssh -f -N -R remotey:12345:lappy:22 remotey

NOTE: This command says to open up port 12345@remotey and tunnel any connections to port 22@lappy.

Then on remotey:

remotey$ netstat -an|grep 12345
tcp        0      0 127.0.0.1:12345              0.0.0.0:*                   LISTEN   

What's going on is sshd's configurations aren't allowing you to do this. In fact without this feature enabled (GatewayPorts) you won't be able to bind any ssh tunnel ports to anything except localhost.

Enabling GatewayPorts

remotey$ grep GatewayPorts /etc/ssh/sshd_config
#GatewayPorts no

To enable it, edit this file /etc/ssh/sshd_config:

GatewayPorts clientspecified

And restart sshd:

remotey$ sudo service sshd restart

Now try it again and we should see the effect we're after:

lappy$ ssh -f -N -R remotey:12345:lappy:22 remotey

And double check it this time on remotey:

remotey$ netstat -anp | grep 12345
tcp        0      0 192.168.1.3:12345           0.0.0.0:*                   LISTEN      9333/sshd

NOTE: In the above we can see that the sshd process now is listening on the interface which has IP address 192.168.1.3, for connections on port 12345.

Testing the connection (part deux)

Now with our altered setup when we test it this time. The primary difference is that we no longer have to connect to localhost!

  1. login to remotey

    [user@lappy ~]$ ssh remotey
    
  2. test out reverse connection

    [user@remotey ~]$ ssh -p 12345 remotey
    
  3. should now be back on lappy

    root@remotey's password: 
    Last login: Wed Aug 21 01:49:10 2013 from remotey
    [user@lappy ~]$ 
    

References

slm
  • 369,824
  • is there a way to make tunnel from 0.0.0.0:12346 to 127.0.0.1:12345 on the same machine? – Kokizzu Aug 20 '13 at 15:47
  • 1
    @Kokizzu - I tried setting this up and I'm getting wrapped around the axel on what you're asking for. I found this which sounds like what you want, http://www.anattatechnologies.com/q/2012/08/chaining-ssh-tunnels/. I'll try and work it out later tonight, feel free to play with it and let me know if you make any progress with it. – slm Aug 20 '13 at 18:16
  • that's not what i meant, i want it to bind to w.x.y.z:vvv2 instead of 127.0.0.1 (on computer B), so other people can use it also.. – Kokizzu Aug 21 '13 at 01:13
  • 1
    @Kokizzu - see updates. – slm Aug 21 '13 at 06:38
2

Since computer B cannot access computer A, you will need to open a remote tunnel from computer A first.

ssh user@computerB -R vvv:localhost:22
  • thanks, but is there a way to open a port on eth0's IP that forwarded to a service that listened to localhost? – Kokizzu Aug 20 '13 at 11:41
1

nevermind, i found the answer:

ssh -f -N -R vvv:localhost:22 w.x.y.z

from computer A

EDIT: TL;DR, correct solution:

ssh -f -N -R w.x.y.z:vvv:localhost:22 w.x.y.z
Kokizzu
  • 9,699