ACM@UIUC has a bunch of machines behind NAT, which are all in the non-publicly-served domain internal.acm.uiuc.edu, and as I started to need these machines more for my research, I got annoyed at having to do a nested ssh every time I wanted to access them.
The obvious solution was a VPN. I set up OpenVPN on our OpenBSD router box. I’ve done enough OpenVPN evangelism here, so I won’t do more than say it’s worth checking out.
Next came the client side. OpenVPN, at least on Unix platforms, doesn’t automatically modify your nameserver configuration (it used to not modify your routing table either), so I wrote a Python script which automatically edits resolv.conf to add the appropriate nameserver address for internal.acm when you connect, and remove it when you disconnect.
This worked wonderfully until I upgraded to Tiger. OS X 10.4, except for a few tools like host, no longer directly reads /etc/resolv.conf to determine nameservers and search domains. Instead, Tiger has a much more flexible (but rather poorly documented) DNS interface as part of the System Configuration framework. Not to worry, it does keep resolv.conf up to date with the current state of things, but if you change that file, don’t expect Safari, Mail, or even ssh or ping to recognize your changes.
After some poking around and help from a mailing list, I developed a solution. Try running scutil --dns, where you’ll see multiple resolvers, each resolver with its own set of (search) domains and nameservers—it’s like a routing table for DNS. This architecture solves my problem much more elegantly than editing resolv.conf. You can even be connected to multiple VPNs simultaneously, with a private nameserver and associated domains for each VPN, and everything just works.
I rewrote the script to use this new mechanism, and had been using it a month or so without problems, when I found this article posted at macosxhints.com, which proposes a much more primitive method of altering the nameserver configuration. So I posted a comment saying anyone could email me and I’d send them my script—a sure-fire procrastination tactic, since I was sure nobody would email me immediately, and I planned on cleaning the script up for more general use, just not then because I had several deadlines.
I’ve now had a chance to clean up the script so it is more generically useful. Here is the script with its associated OpenVPN config file.
In order to get the script to work, you’ll need to install PyObjC (has an installer), then the SystemConfiguration wrapper.
If you’re not familiar with using Python’s distutils, to install the wrapper, cd into the SystemConfiguration-0.3 directory, then run python setup.py install. If you get permissions errors (which you shouldn’t on a default OS X install, but…) you might need to sudo python setup.py install instead.
When the VPN is up, OS X Tiger will use the OpenVPN DHCP option-provided nameserver(s) for the corresponding search domains, but will use your existing nameserver(s) for everything else. Use scutil --dns to see one or more resolvers appear after you’re connected, and disappear when you disconnect.
Version 3.0a2 of Tunnelblick, an OS X OpenVPN GUI, now seems to work with this script, as long as you change the cd command in the OpenVPN config file to use an absolute path. It’d be great if it or similar software could adopt this approach automatically, so I didn’t have to write a script at all.