[HOWTO] - SSH Tunneling for Mac Users

michaelsanford

Translator, Web Developer
There are a few great FAQs and HOW-TOs on this, but I figured we deserved our own.

What is SSH tunneling and what's it good for?
SSH (secure socket shell) is an encrypted connection between two computers that allows not only a secure remote terminal session but encrypted data transfer as well.

An SSH tunnel is simply one or more parallel data stream that get built when you connect to a remote host. Through this tunnel you can securely access any open service on the remote machine, from FTP to AFP to VNC to printing, and let's not forget X11!

How does it work?
Basically when you connect via `ssh` to a remote host, you specify some extra command line arguments that tell ssh something like "get the remote hosts's AFP port (548) to forward to my local port 10548 over the secure channel". This is called a direct port forward.

With this clever tool you can also forward any port on any machine that the remote machine is connected to, to your local machine over the secure channel, like "Tell the remote machine to connect to my router's web interface and forward that over the secure connection to my local port 10080".

The Syntax
Let's look at the following line:
ssh myhost.local -c blowfish -X -L 10548:127.0.0.1:548 -L 10080:192.168.0.0:88

The first part tells ssh to connect to myhost.local.

The red part tells ssh "Connect to 127.0.0.1 (localhost) at my port 10548, and route it to myhost.local's port 548". Then when you want to access myhost.local's AFP, you choose Connect To from the Finder and enter 127.0.0.1:10548 and voilà, up pops a connection dialogue for myhost.local.

The blue part tells ssh "Connect to 192.168.0.0 port 88 on the LAN to which myhost.local is connected, and forward that to my local port 10080". This is useful when you have a router with a web-based interface and don't want to open it up to the WAN, you can use this method to connect to it. You then enter http://127.0.0.1:10080 in Safari and voilà up pops the web interface for myhost.local's router.

If you want to enable X11 forwarding, you need to add the -X command-line flag, but you don't have to enter any host or port information, -X will automatically forward remote X11 sessions to your local machine. You must use an X11-based terminal program to create the tunnel however, or else the $DISPLAY variable won't be set and your local X11 won't know where the display is.

Tips for better operation
1. Use a 'shabbier' cypher. By default ssh will use 3des (triple-des) which is an encrypt-decrypt-encrypt triple algorythm with three different keys. As you can imagine for the text of a terminal session it makes little difference, but for AFP for VNC/X11 it will slow the connection immensely on a slow computer. Specify the blowfish algorythm using -c blowfish which is secure, and faster. If however you're extremely paranoid about security and have a very fast computer, des or 3des should work all right.

2. Once you connect to the remote machine renice the thread called AppleFileServer (AppleFileS) to something negative. If you have a slow system and have other apps running this may give you a tiny edge on file sharing.

3. Always, always end your tunneled sessions with ~& instead of logout or ^D. This is an escape character that tells ssh to background itself until all the secured channels are closed.

This means that you can exit the terminal and leave your AFP volumes mounted, then when you unmount them the SSH session closes completely. If, on the other hand, you choose ^D or logout, your drives won't be softly unmounted, they'll be ripped out :( and nobody wants that.

Note however that only persistent services (like AFP) will remain open after a background escape (~&) is issued, services like HTTP tunnels (like the router's web interface) will close as soon as the page is loaded (i.e., immediately if no page is loading).
 
So technically if I'm behind a firewall that doesn't allow me to use, for example, the right port for the Apache webhost, if I had access to another computer outside of the firewall, I could use that IP address and have it forward the appropriate ports to my computer, and thus set up a 'proxy' type thing?
 
@michael: Thank you for this great HOWTO.

@dlloyd: That's correct, as long as you can reach the system you specify in the -L expression from the system you ssh to.
 
For example, the e-mail server in the internal network is at 111.222.24.25. It is, however, not reachable via ssh because by purpose it doesn't have a default route. The firewall will only let ssh pass through to the 111.222.24.77 machine. If I want to access my company e-mail from home I would do:

ssh -C 111.222.24.77 -L143:111.222.24.25:143

After that I simply connect my IMAP e-mail client to localhost (port 143 is IMAP2) which goes through the ssh tunnel behind the scenes and connects to 111.222.24.25 on port 143. The -C option compresses all the traffic so the tunnel is even faster than plain IMAP :)
 
Perhaps you have a suggestion for this - I'm trying to do essentially the same as X11 forwarding, but in the opposite direction. The school firewalls allow no incoming connections, so I send out a ssh connection to my home computer, and forward telnet back along it to the school one, with
ssh -R 2323:127.0.0.1:23 scruffy@scruffys.comp
I get home, telnet localhost 2323, works like a charm.

What I can't seem to do is send X11 connections back to my home computer. I've tried adding
-L 6010:127.0.0.1:6000
Then I telnet back to the shool machine (with X11 running at home), set the display to ":10", but still can't launch any X11 apps.

I know, I could forward inbound ssh over the outbound ssh channel, and
ssh -p 2222 -X localhost
or whatever, but I'd like to avoid encrypting everything twice. The nice 2GHz P4 at school could handle it fine, but my poor 300 MHz G3 would be running pretty hot trying to double-encrypt all the X11 traffic...

Incidentally, you can also add the '-fN' flags, which will send ssh to the background immediately after authenticating, and the connection will be persistent. Actually not entirely persistent, it can still timeout - this was a problem for me, since the connection had to survive hours and hours of idle time till I wanted to telnet back. I had to download a patch for openSSH that adds a heartbeat - it sends a special ssh 'null' packet every so often to keep the connection going.
 
Oh, another tip for performance - if you have a slow connection, and the computers at either end are reasonably fast, you can add the -z flag to compress the traffic with gzip. That way if you're going to be using stuff that generates a lot of traffic, like X11 or file transfers, you can trade some of the connection load for extra CPU load.
 
Scruffy, it sounds like what you need is a 'reverse forward' which is implemented by the -R option (instead of -L), which does something akin to passive FTP...

However, it sounds like the problem isn't the channel but the $DISPLAY setting. I had that problem and it was a real bugger to deduce.

Try cat /etc/sshd_config | grep #X11 and you should see something like
#X11Forwarding yes (no)
#X11DisplayOffset 10
#X11UseLocalhost yes

The first (no) indicates the default setting. Firstly, you need to make sure that first line is set to yes and uncommented. Secondly, if the displayoffset is set to 10, then your remote display will be :11 not :10

Also make sure that /etc/ssh_config looks like
Host *
ForwardAgent yes
ForwardX11 yes

Just a warning to note that the first file is sshd_config and the second is ssh_config :p

Try 'er our and let us know.
 
Thanks Michael, but that's actually more or less the reverse of what I want to do. The ssh client is Linux box at school, and the server is my Mac at home. Problem with that - the school firewall lets nothing in. So, before I go home I would have to:
ssh -R 2222:127.0.0.1:22

Then when I get home, I can:
ssh -p 2222 -X localhost

which works, but it's dog slow, because I'm tunneling X11 over an ssh channel that's itself tunneled over an ssh channel the other direction - encrypting every mouse click twice.

Code:
   Linux                                      Mac
____________ ssh connection -> that way  ______________
|          |-----------------------------|            |
| 22 <----------------------------------------- 2222  |
|            ssh connection <- that way               |
|       -------------------------------------         |
| 6010 ---------------------------------------> 6000  |
|       -------------------------------------         |
|                                                     |
|          |-----------------------------|            |
|__________|                             |____________|

What I want to do is ssh from the Linux box at school to the Mac at home, pass telnet (not ssh, no need to encrypt twice) back form Mac to Linux, and pass X11 connections from Linux x clients to the Mac x server, all over the same ssh connection (or two parallel ones would be fine, just not one inside the other).
Code:
   Linux                                      Mac 
____________ ssh connection -> that way  ______________
|          |-----------------------------|            |
|    6010 --------------------------------> 6000      |
|      23 <-------------------------------- 2323      |
|          |-----------------------------|            |
|__________|                             |____________|

Then I can go home, sit at the Mac
telnet localhost 2323
and I've got a shell on the nice fast Linux box at school, and I can do my work, as long as it doesn't need a graphical application. But, I would like to set my DISPLAY on the Linux box such that it connects to port 6010 (hence :10) and it will be sent back to the X11 server on the Mac

As far as I know, the ForwardX11 only is for forwarding stuff from the ssh server to the ssh client, since that's the more typical arrangement. But I can't ssh into the school machine...
 
gee wiz...sounds like you guys are light years ahead of where I am at. I am having trouble with the creation of keys. Specifically, when I login I am told that the connection is not known and "are you sure you want to do this?" Also what am I supposed to do with the key? Copy it onto a usb drive and then take it to the cpu I want a secure connection with?

michael...you have done a nice job and added some great tweaks.

what about just using port 80 which seems to be wide open everywhere?
 
The keys live in ~/.ssh/known_hosts and known_hosts2. The first time you connect to a server from a particular client, it has never seen those host keys, so it asks you what to do. If you do connect that first time, then ssh will add the keys to one of the files.

Every time after that, when you connect to that server from that client, ssh will compare the keys the server sent this time, to the ones in the file from last time. If they match, it will just carry on; if they differ, then it may be a sign something fishy is up - you might be connecting to a bogus server.
 
bossa nova said:
michael...you have done a nice job and added some great tweaks.

what about just using port 80 which seems to be wide open everywhere?

Thanks :)

What exactly do you mean about port 80 though?

PS Scruffy has it totally right, but also of note is the fact that you will need to add a key for every different name you use to connect to the host. For example, I can connect to my other iMac, called homsar, buy either homsar.local, homsar, 192.168.0.22, or homsar.no-info.com, and all those names will prompt you to add a new key to your known_hosts since ssh doesn't know that they're all the same computer...
 
michaelsanford said:
Thanks :)

What exactly do you mean about port 80 though?

You're welcome...with regard to port 80, I was thinking that it would be open to incomming traffic but then I realized that most web servers (in a perfect world), would probably be in a DMZ or outside of the firewall. So I guess I just answered my own question. But this gets me thinking. If you want to use port 22, you would have to ensure that the port was open. Unless you punch a hole through from the other side right?
 
Actually in a perfect world we wouldn't need firewalls at all :p However, it's not considered good practice to put big servers in a DMZ and I'm not really sure why you'd need or want to.

As for using port 22, you need to make sure that the port is open for incoming traffic on the server's firewall.

The advantage to all of this is that port 22 is: (a) a privileged port, so you need to be root to run services on it (or any port below 1024) so at, in theory malicious, script-kiddies and hackers can't run arbitrary services on it to say, fake an ssh connection and get your username and password; (b) since the connection is encrypted it's secure; and lastly (c) that you can forward nearly any other insecure service through SSH at port 22 that you can close to the outside world.
 
michaelsanford said:
it's not considered good practice to put big servers in a DMZ and I'm not really sure why you'd need or want to.

Michael,

Ok I think maybe I misunderstood something along the way in my reading. I thought it was common practice to put a web server in what is called a DMZ, (De-Militarized Zone) so that it can be in a neutral zone when you need to offer services to the general populace but still protect more sensitive data by keeping that data on servers Not in the DMZ but behind a firewall. Did I misunderstand what I was reading?
 
I have the following problem:
- iMac A is connected to the web via cable ethernet
- iMac B is connected to iMac A via AirPort, with iMac A acting as a software base station
- I need a way for iMac B to be able to host AoE II internet games. AoE II uses TCP & UDP on port 23978
- I am setting this up from my iBook, which is not in the LAN

I first connect to iMac A via ssh over the web. Inside that ssh session, I type:

ssh 127.0.0.1 -c blowfish -X -L 23978:10.0.1.2:23978

Where 10.0.1.2 is the LAN IP of iMac B. Will that work, including for UDP? Do I need to keep my ssh session open, or is leaving it with ~& ok?

TIA,

Kinniken
 
bossa_nova, no, one should never ever leave a server open and in a DMZ. If you need to offer services, you put up a firewall and open only the ports necessary for the services you're offering.

Kinniken, let me think about that...
 
Ok Kinniken, you don't need to do all that tunneling at all in fact. If I understand you correctly you want to use B, which is connected to A over airport to hose AoK games to the internet?

Why don't you enable Internet Sharing on A and just share your internet connection to B, then you won't have any of these tunneling issues since B will be on the WAN.
 
Back
Top