Setting up a permanent ssh tunnel on Mac OS X

tunnel

At my work for security reasons we access some of internal services (eg. irc chat server) via ssh tunnel. Generally, setting up an ssh tunnel (a.k.a. secure port forward) on any UNIX type system having openssh client takes one simple command:

$ ssh -L 6667:localhost:6667 user@server

and entering a system password.

However, I like to close my MacBooks’ lid occasionally or reboot the Book and I really hate (and forget) to reconnect the tunnel every time connection breaks or Book is restarted so encouraged by a colleague, I decided to do something about it. The result is – few simple steps and the tunnel is available permanently. The steps are:

1. Key based ssh authentication. This was actually set long time ago but I’ll mention it here as it’s necessary to have key-based authentication – tunnel is created in the background. I won’t cover the details, simply on your Mac terminal, run ssh-keygen – this will generate your private/public rsa key pairs. Then copy your ~/.ssh/id_rsa.pub to remote server ~/.ssh directory and name it authorized_keys. Make sure file is only writable by owner. For starters, $ chmod 644 ~/.ssh/authorized_keys should be enough.

2. Two simple shell scripts. One – to initialize the permanent ssh tunnel script on user login and, of course – the tunnel creation (and recreation on failure) script.

a) The first one will be invoked by Mac OS Login Hook. I placed it as ~/devel/login-hook.sh. Here’s scripts’ content (replace <user> with your short username):


#! /bin/bash
 
if [ "$(ps ax | grep tunnel-start.sh | grep -vc grep)" -lt 1 ]; then
 sudo -u <user> /Users/<user>/devel/tunnel-start.sh &
fi

The statement checks whether an instance of the script is not running yet (this could happen if you log out and then log back in again), and if not, starts tunnel script with your username rights (sudo is used because Login Hooks are run with root privileges)

b) The tunnel script which is placed in ~/devel/tunnel-start.sh in my case:


#! /bin/bash
 
while [ 1 ]; do
 ssh -N -L 6667:127.0.0.1:6667 user@server
 sleep 5
done

Generally – it’s a simple loop which tries to create a tunnel infinitely with short 5 second breaks. If tunnel is established, the script becomes idle.

3. We have to enable the login hook. As a simple user issue in terminal:

$ sudo defaults write com.apple.loginwindow \
    LoginHook /Users/<user>/devel/login-hook.sh

That’s it! Log out, Log in or reboot to test. Any questions?

7 comments ↓

#1 andreas on 02.17.08 at 10:50

Thanks!

I was searching high and low for some application that would do this, but your script is a simple solution that looks very effective.

I am currently using ssh keychain, but after sleep it can’t handle reestablishing the tunnel.

Must not forget my unix skills

Cheers

#2 andreas on 02.27.08 at 21:34

Now I even tried it. It works well, but especially after I added

-o ServerAliveInterval=3

to the ssh command. Without this the ssh process would hang after a sleep in some cases. Now the process is terminated when the connection is lost.

Cheers

#3 Aurimas on 02.27.08 at 21:52

Ah, so did not find some tool ready for that out of the box? Regarding ServerAliveInterval – makes sense, I’ll have to add that as well.

#4 thai on 03.05.08 at 08:48

Great tutorial! Exactly what I was looking for.

Question: is it normal for the tunnel-start.sh script to continually try to tunnel through?

ps-efl|grep ssh shows multiple ssh tunnel attempts.

If I run the login-hook.sh script manually (instead of the loginhook way), I can see errors about trying to use 10548 (my local side port to AFP) again.

Thanks again for posting this how-to.

T

#5 G.J. van de Streek on 03.17.08 at 14:28

@thai: did you change the script in any way? You might see this when using the -f option.

#6 Justin on 06.19.08 at 18:33

I’ve developed a Mac application called Meerkat which helps manage tunnels and keep them up over sleep/wake, network changes, etc. It might be handier than building scripts for each tunnel that you need. I had started scripting lots of things like you did initially, but after a while, it got unmanageable.

http://codesorcery.net/meerkat

#7 Aurimas on 08.03.10 at 10:31

I see there’s one more project doing the thing:

http://code.google.com/p/cocoa-sshtunnel/

Leave a Comment