The view from here
12 May
For a long time, I have used SSH port forwarding to access a lot of my home files and services, but I’ve found myself hitting the limits of usefulness. So I decided to try and create a VPN. This isn’t a true VPN – it’s NAT over SSH with tun. Good enough for me.
Much of the heavy lifting for this post was done by daleroberts at his wiki site. My only real contribution here is around the last steps of getting the routing working.
So, here’s what you’ll need:
Even though OS X has a tun manpage, it appears to not actually have tun installed. The easiest way to get the tun/tap drivers is to download tunnelblick. You will need it both on the client and server machines. Once you have it, mount the disk image, and copy the application somewhere (for illustrative purposes, I put it on my Desktop).
At the command line, execute the following (assuming you are in your home dir):
sudo cp -rp Desktop/Tunnelblick.app/Contents/Resources/*kext /System/Library/Extensions/
cd /System/Library/Extensions
sudo chown -R root:wheel tun.kext
sudo chmod -R go-w tun.kext
sudo chown -R root:wheel tap.kext
sudo chmod -R go-w tap.kext
sudo kextload /System/Library/Extensions/tun.kext
Repeat the above on the server
Edit /private/etc/sshd_config on the server as root to permit tunnelling. Make sure the following lines are uncommented (in a default OS X install, they should be there, but will be commented out with a ‘#’ sign – you just need to delete the ‘#’)
PermitRootLogin yes
PermitTunnel yes
Then, from the client, execute:
sudo ssh -w 0:0 root@home while true \; do echo . \&\& sleep 60 \; done
Replace “home” with the internet available hostname of the server. The output should be a “period”, with a new “period” every 60 seconds.
If this worked correctly, you should be able to open a new command prompt on the client and execute the following:
ifconfig tun0
which should return
tun0: flags=8851
open (pid ABCDE)
where ABCDE isn’t really relevant. If you execute the same ‘ifconfig tun0′ on the server, you should see something similar.
Execute the following on the client:
sudo ifconfig tun0 172.16.0.1 172.16.0.2
ssh root@home ifconfig tun0 172.16.0.2 172.16.0.1 \&\& sysctl -w net.inet.ip.forwarding=1
Again, replacing “home” with the internet available hostname of the server.
To test this, add the route on your client
sudo route add -net 172.16.0 -interface tun0
You should now be able to access your server from your client via the IP address 172.16.0.2. Congrats, you now have a basic VPN
So, what if you have more machines on your home network than just your server? You’ll need to set up NAT and some routing rules
First, a route to push traffic to 172.16.0.* via the tun0 interface:
sudo route add -net 172.16.0 -interface tun0
Second, a route to push traffic headed to the home network via the 172.16.0.2 gateway
sudo route add 192.168.0 172.16.0.2
Finally, you need to set up NAT on the server:
sudo /usr/sbin/natd -interface en0 -l -s -m
sudo ipfw add 00002 allow ip from any to any via tun0
sudo ipfw add 00003 divert 8668 ip from any to 192.168.0/24 via en0
sudo ipfw add 00004 allow ip from any to 172.16.0.1
You should now be able to access any of the machines on the home network by IP address!
I have setup some aliases and scripts so I don’t have to remember the exact commands to execute. This is probably not the most efficient way to do this, but it’s better than nothing.
That’s it. I’m sure some people will comment on how this could be made better, but it’s meant to be quick and dirty but work.
Leave a reply