http:// www.jms1.net / osx-case-sensitive-fs.shtml

Routing specific IP blocks over a VPN under Mac OS X

My office has several machines which I use on a daily basis, which are behind a firewall or which use iptables to limit the IP addresses from which they can be accessed. My job requires me to be able to access those servers from anywhere, so I use a VPN (running the PPTP protocol) to connect to an internal machine, and route my traffic through that to work on the other servers.

When I connect to the VPN from a Linux machine, I route the office's public IP ranges through the VPN, but I don't use the VPN as my default route, because (1) it can be a burden to the network at the office, and (2) I don't need (or usually want) the office firewall proxying my web traffic.

The Problem

The VPN client built into Mac OS 10.5 has a single checkbox saying "Send all traffic over VPN connection". If you turn this on, the VPN becomes the default route. If you turn this off, the only IP block which gets routed through the VPN is the one IP block in which the VPN server resides. Since the office has multiple IP blocks, neither option is suitable for my needs.

The Solution

My VPN uses a program called "pppd" to handle connecting to the server and negotiating the IP addresses of the VPN link. This is the same pppd used on other systems, so the various configuration options and scripts work the same way. The Mac OS X GUI tools simply run the program with command line options rather than using a configuration file.

When a ppp connection is made, the pppd program looks for a script called "/etc/ppp/ip-up", and if it exists and is executable, runs it. By default, Mac OS X doesn't have this file, so it's up to us to create one.

When pppd executes this script, it passes several pieces of information on the command line. The one parameter we are interested in is $5, which contains the IP address of the remote end of the link. If the office VPN server has IP address 192.168.7.10/24, and the office has other IP blocks 192.168.8.0/24 and 192.168.9.0/24 which the client should route through the VPN, the script will look like this:

#!/bin/sh

if [ "${5:-}" = "192.168.7.10" ]
then
    /sbin/route add 192.168.8.0/24 $5
    /sbin/route add 192.168.9.0/24 $5
fi

The file should be owned by root with permissions 0755.

With this file in place, and the "Send all traffic over VPN connection" option turned off, when I connect the VPN it automatically routes all of the office's IP space through the VPN. When the VPN link drops, those routes are automatically removed.

Note that the IP block containing the remote end of the VPN link (in this case 192.168.7.0/24) will automatically be routed through the VPN. You don't need to manually add the route in your script.