ssh into a server without a public IP from a server without a public IP that is hidden behind a server with public IP

I have the following setup: I would like to access machine A from machine C, but neither of those have a public IP address. Machine C is, though, in the same network as machine B, which has a public IP access, hence I can access machine C from anywhere by first ssh'ing into machine B and from there ssh into machine C. I don't have root access on machine B, while at both A and C I do. See the following diagram for clarification:

machine A          machine B      machine C
no public IP       public IP      no public IP
root access        no root access root access     
how to access?    '---------------------------'
                           same network
                       hence both accessible

A dumb solution would be to have machine A regularly sniff a file in machine C (by the 2-step ssh access described above) and whenever a command appears in that file, execute it and write the outputs over ssh somewhere at machine C. I, though, wonder, can ssh somehow "reverse" the connection, so that machine A connects in 2 steps to machine C, and then the connection gets "reversed" so that machine C actually has the remote shell of machine A? And if yes, how do I do it?


Solution 1:

You can have machineA to open an SSH tunnel to machineB, with a remote forward option, which would allow you to SSH into machineA from machineB.

If you have root access on machineB, then set the GatewayPorts configuration option to yes in /etc/ssh/sshd_config, then issue this command on machineA:

ssh -N -R 0.0.0.0:2222:127.0.0.1:22 the_public_ip_of_machine_B

This will open the port 2222 on machineB, and forward any traffic on that port to itself, to port 22. Note that this will listen on all interfaces, the public one included, so you may want to firewall port number 2222 (but probably you have a firewall on machineB anyway). While this tunnel is active, you can SSH to machineB on port 2222, and this will take you to machineA. Since machineB and machineC are on the same subnet, you can loginto machineA from machineC in one step.

If you don't have root access on machineB, then the process is the same, with the exception of the listening address. If GatewayPorts is set to no (which is the default), then the first argument (0.0.0.0) will simply be ignored, and the listening address will be bound to 127.0.0.1. In this case, you can still use the command from above, and the forwarding will work the same, but the opened port will not be available from anywhere but from machineB. So you must SSH into machineB, then SSH to localhost, port 2222, which will take you to machineA.

However, you might want to consider using something more robust, like a VPN.