Minggu, 12 Juni 2011

How do I do port-forwarding with ssh?

If you can ssh out from a firewalled machine, you can ask ssh to set up a tunnel back to that machine, so that it can be reached from the outside world. Here's how.
For the purposes of this explanation, the "inside" machine is the machine inside the firewall -- the one you want to be able to reach. The "outside" machine is the one that will be forwarding connections to the inside one.
Also note that when I say "ssh", I mean ssh version 1. There is an ssh version 2, but it's commercial and nobody uses it (and it's incompatible with version 1) -- so to avoid confusing yourself, don't even look at it. Use ssh version 1.

1. Create a key
The first thing you need to do is create an ssh "identity" key that doesn't have a password set -- it just uses RSA keys to authenticate. (You need this because you're going to be running ssh in the background and you don't want it asking you for a password when you're not around.)
On the inside machine, go into your .ssh/ directory (the one inside your home directory -- if you don't have one, go ahead and create it) and type:
ssh-keygen -f tunnel -C "tunnel key"
It will do a little song and dance, and ask you for a password. Just hit enter here -- you don't want a password set on this key. When you're done, you'll have a file tunnel (this is your private key -- protect it!) and a file tunnel.pub (the public key).

2. Add the key to the outside machine
You need to let the outside machine know this new public key, so it'll let you login without a password (using this key). On the outside machine, go into your .ssh/ directory and edit the fileauthorized_keys. (If this file doesn't exist, it's okay to create it.)
This is somewhat annoying, but what you want to do is copy the contents of tunnel.pub (from the inside machine) into one line of your authorized_keys file. It's important that the line be identical, and that it be one line. (Sometimes cut-and-paste will insert linefeeds -- be careful and check it.)
It should work now. But to be safe, you ought to also limit the places this key can be used from. Since you're only going to use this key to set up an automatic tunnel from the inside machine, you can set this key so that it will only work for connections coming from there. To do that, add a from= section to the beginning of the line in authorized_keys. For example, if your inside box is 10.23.128.4, the line in authorized_keys should look like this:
from="10.23.128.4" 1024 37 1283091749021[...]923492
In other words, you want from="inside IP", followed by a space, to be at the front of the line. This is optional, but highly recommended.

3. Checkpoint
If you've done everything right up till now, you should be able to use this command on the inside machine:
ssh -i ~/.ssh/tunnel username@outside.machine.top
and ssh should connect you to the outside machine and login as you, without asking you for a password. If that isn't what happened, something got messed up along the way -- start over. If that is what happened, you're halfway there.

4. Backwards port redirect
This is the interesting part. Ssh has the ability to, after connecting to a machine, listen to a TCP port on that machine, and redirect traffic over the ssh connection back to the ssh client's machine. It's done with the -R option:
-R far-port:local-address:local-port
If the inside machine is named "squirtle", and the outside machine is named "house.example.com", you can type this command:
ssh -i ~/.ssh/tunnel -R 3939:squirtle:23 me@house.example.com
It will connect you to house.example.com, as before, but this time it also starts listening on port 3939 on house.example.com, and forwarding traffic to squirtle's port 23 (the telnet port). So, anyone who telnets to house.example.com port 3939, is effectively telnet'ing to squirtle's login prompt. Hopefully this makes you nervous. You should be really careful about this, because now anyone that finds this port can try to login to squirtle. And it's not exactly hard to find the port.
Leigh Klotz emailed me and pointed out that it would be even better if you used port 22 (the ssh port) instead of port 23 (the telnet port) since most systems have sshd running now. That's definitely more secure.

5. Automating it
One thing you can do, if you don't give a crap about the security of squirtle (the inside machine), is to just leave the connection up 24/7. I know at least one (unnamed) company where this is happening. To do that, just run a script like this one the inside machine:

#!/bin/sh
while `true`; do
ssh -i ~/.ssh/tunnel -R 3939:squirtle:23 me@house.example.com sleep 32000
sleep 1
done
Adding the sleep 32000 to the ssh command makes it execute that command (on the remote machine -- i.e. the outside machine) instead of giving you a login shell. This is what you want for scripts.
Another thing you could do is set up a "time window" that the tunnel will be open. Set it up as a cron job that goes off at, say, every 2-3 hours and leaves the connection up for 15 minutes (just change the sleep time on the ssh command line to 900).
If you're really perverse like me, you could run a bot on the inside machine, and run some Tcl scripts on a botnet so that anyone on the botnet could do a command that causes the bot on the inside machine to open up the tunnel. If that sounds cool to you, go write it yourself -- don't ask me for help. :)

0 komentar:

Posting Komentar

VISITORS

Flag Counter