PPTP over SSH
Tunneling PPP over SSH
While PPTP is a very common solution for creating a VPN on the Internet, server solutions for Mac OS X are limited at this point. There is a PPTP VPN daemon available, shipping with Mac OS X Server, but unfortunately it is not listed as an open source component on Apple's site. This greatly hampers the ability to get two Mac OS X clients together in a VPN. However, there is another solution: using PPP and SSH together to form a VPN link.
This method works by creating a PPP link between two systems over an SSH connection. The master machine initiates an SSH connection to the slave. Once it has authenticated the connection, the slave machine launches pppd, with output going to the inbound SSH session. On the master machine, pppd is launched to respond to the slave's pppd. The two daemons sync up and begin passing packets, which are in turn encrypted by SSH. While it isn't terribly optimized (read "fast"), it does work, and is a great placeholder while we're waiting for more PPTP daemons to be ported to Mac OS X.
The slave machine is the machine that is connected to the main network. This is the same box that would run the actual VPN server, but in this situation it is the slave of the PPP link. This is the easiest method, because it allows the remote machine to build and tear down the VPN connection. The slave machine in my examples will be "utopia.lifehertz.com."
The first thing we'll need to do is create an account on the slave machine for our master machine to log into. This should be a brand-new account and will not be used beyond the VPN. We're going to modify some settings on the account that may break a normal user.
To create the user account, open the Accounts tab of the System Preferences pane. Click New User, and enter "VPN User" for the Name and "vpn" for the Short Name. Set an easy-to-remember password for now; we're going to disable it later. Once you've filled out these fields, click the OK button.
Creating the VPN user.
The next step is to setup the vpn account with the ability to launch the PPP daemon. To do this, we're going to edit the sudoers file. Open up the Terminal and issue the command sudo pico /etc/sudoers to open the file in pico. You'll want to add the VPN Cmnd_Alias and VPN user privileges to make your sudoers file look similar to the one below:
# Cmnd alias specification Cmnd_Alias VPN=/usr/sbin/pppd, /sbin/route # Defaults specification # User privilege specification root ALL=(ALL) ALL %admin ALL=(ALL) ALL vpn ALL=NOPASSWD: VPN
The master machine is the machine you are using remotely. This machine will initialize the SSH connection and then respond to the PPP daemon launching on the slave. In my example, the master machine is "nomad.lifehertz.com." In order to easily log in to the slave machine to launch pppd, we'll be using SSH key authentication. To do this, we first need to generate the key, then copy the public portion of the key to the vpn account's home directory on the slave machine. You don't need to use a password on the key. The commands below should help you do this:
$ sudo ssh-keygen -t rsa Generating public/private rsa key pair. Enter passphrase (empty for no passphrase): Enter same passphrase again: Your identification has been saved in /var/root/.ssh/id_rsa. Your public key has been saved in /var/root/.ssh/id_rsa.pub. The key fingerprint is: a3:46:24:8b:b7:a9:d6:91:d7:25:9a:e2:82:ce:16:82 musouka@nomad $ sudo scp /var/root/.ssh/id_rsa.pub firstname.lastname@example.org:~ The authenticity of host 'utopia (220.127.116.11)' can't be established. RSA key fingerprint is 00:41:24:66:bf:d4:38:d4:cb:2a:e2:75:93:74:d2:9e. Are you sure you want to continue connecting (yes/no)? yes Warning: Permanently added 'utopia,18.104.22.168' (RSA) to the list of known hosts. vpn@utopia's password: id_rsa.pub 100% |**********************************************************************| 123
Once you've copied the public key to the slave system, you'll want to connect to it and finish setting up the vpn account. First ssh into the slave machine and then attempt to connect back to the master machine from the slave to exchange host keys. You'll want to confirm adding the master to your slave's known hosts and then just Ctrl-C to cancel the actual connection. Verify that there is a file in the vpn account's ~/.ssh folder called known_hosts. Next, move the generated public key to the a file called authorized_keys in the ~/.ssh folder. Finally, configure the PPP daemon to launch passively upon login. The commands below should get you there:
$ ssh email@example.com vpn@utopia's password: $ ssh nomad The authenticity of host 'nomad (22.214.171.124)' can't be established. RSA key fingerprint is 71:7d:6d:03:87:86:28:94:ee:16:2f:e2:01:dd:e9:38. Are you sure you want to continue connecting (yes/no)? yes vpn@nomad's password: ^C $ mv ~/utopia.pub ~/.ssh/authorized_keys $ echo "sudo /usr/sbin/pppd passive; logout" > ~/.login $ logout
To verify that your slave machine is set up properly, from the master machine, attempt the command sudo ssh firstname.lastname@example.org. Your master machine should connect to the slave machine, be authenticated via the SSH key, and then begin to see the garbled output of the PPP daemon. If this is all working properly, then your slave machine is ready to go.
To finish up configuring the master machine, you'll need to make use of a little tool called pty-redir (http://www.macdevcenter.com/mac/2002/12/20/examples/pty-redir-0.1.tar.gz). This program will execute a passed command on a separate TTY. As you saw above, when you SSH to the slave machine, the PPP daemon will launch and start filling your screen with garbage. In order to get the two machines to connect, you need to have the PPP daemon on the master machine launch to respond to the slave's PPP daemon. The problem is that you can't launch pppd very well if you're busy looking at the slave machine's output. pty-redir helps you get around this quite easily. To download and install pty-redir, follow the code below:
$ curl -O http://www.macdevcenter.com/mac/2002/12/20/examples/pty-redir-0.1.tar.gz $ tar zxvf pty-redir-0.1.tar.gz $ cd pty-redir-0.1 $ make $ sudo mkdir /usr/local/bin $ sudo cp pty-redir /usr/local/bin
These commands will put the pty-redir binary in your /usr/local/bin directory. To test it out, execute the command sudo /usr/local/bin/pty-redir /usr/bin/ssh email@example.com. You should just see a result along the lines of /dev/ttyp4. This output tells you which TTY was allocated for your command and to where its output is going. In this case, the slave machine's PPP daemon is sending its connection information to the redirected TTY. All you need to do to finish the link is launch pppd on the master machine and have it use the redirected port. You do this with the command sudo /usr/sbin/pppd /dev/ttyp4 local noauth proxyarp persist 192.168.10.1:192.168.10.2. This will tell the master machine's PPP daemon to use the redirected TTY and use the IP address of 192.168.10.1 for its end of the PPP link. The slave machine's IP would be 192.168.10.2. If everything is working up to this point, you should be able to ping 192.168.10.2 and get a response from the slave machine. This means your connection is up and running!
Code Fragments only Now that you have the tunnel up, you can use a static route to point to the slave machine's network. You will then be able to pass traffic to other hosts on the slave's network through the encrypted PPP tunnel securely. If the network you are trying to access is 192.168.3.0/24, you would use the command sudo /sbin/route add -net 192.168.3.0/24 192.168.10.2. Make sure that the gateway for the route is the slave machine's end of the PPP link. Depending on the slave machine's routing setup, you might be able to have the master machine pass all Internet traffic through the slave machine. This is a good way to help secure traffic if you're using a wireless access point in a public place. You can bring up the VPN connection and then change your default route with the command sudo /sbin/route add -net 0.0.0.0 192.168.10.2. This will route all of your Internet traffic through the VPN link, securing your wireless traffic. The main thing to consider with changing the gateway is that you are going to take a hit in performance. You must take into account that your traffic will be encrypted, passed through the tunnel, decrypted, passed out of the slave machine, and then out onto the Internet. This can definitely slow things down.
So you've been connected into your slave machine for a while, and have decided that it's time to disconnect. The process is pretty simple. Use ps ax | grep pppd to search for the PPP daemon's process ID. Then use the sudo kill command to kill the daemon. The master machine's PPP daemon will bring down the link. This allows the slave machine's PPP daemon to quit. Upon quitting, the slave machine will log out the vpn user. At this point, the PPP connection will have stopped, both daemons will have quit, and your SSH connection should be down as well.
For finishing touches, I've included a script here that can help build and tear down the VPN connection with just a few keystrokes. It's also a good idea to disable the vpn user's password, making it less susceptible to break-in attempts. To do this, just issue the command sudo niutil -createprop . /users/vpn passwd *.