Ah, the beauty of open source software. This is a long post that started with a simple problem. At work, we live behind the Great Olin Firewall (GOF). I checked out some code from an internal Subversion repository over HTTP. Now, I’m outside the GOF and I want to commit some important changes. We have an SSH gateway, and SSH has a built-in SOCKS5 proxy. Cool, that should work, right? Nope. While you can use tsocks or proxychains, or some other transparent proxy service to get most of the way there, it isn’t the whole thing. I learned a lot from this page, but proxychains doesn’t compile well on OS X. Ugh. And tsocks doesn’t tunnel DNS requests on OS X.
Now, the GOF is a Nortel piece that uses a custom hash function for the username running and standards-based IPSec VPN. Boo. That means it won’t work with any third-party VPN client. You have to use the Contivity piece of garbage. Bonus that this piece of garbage is written by Apani, and is now no longer actively supported. Double ugh. So here is what I need:
- VPN access to the work network
- Tunneled through SSH
- Ability to redirect DNS lookups through the VPN
- Free, as in speech
What you’ll need to do this:
- Root on a linux server inside the firewall
- Mac on the outside
There, not so hard? Thankfully, the Intarwebs and a little hacking last night delivered the goods. In short, I used OpenVPN, a few scripts, and a little luck. Here’s how.
- I used Ubuntu Dapper inside a Xen virtual machine. Worked great.
- apt-get install openvpn openssl bridge-utils
- cp -R /usr/share/doc/openvpn/examples/easy-rsa /etc/openvpn
- Follow the directions for generating keys at the OpenVPN HOWTO
- Copy the keys to the right places, as from the above HOWTO. I put my keys in /etc/openvpn/keys
- Use the following configuration file for your server. This assumes an ethernet bridge will be built (later) and that you have a DHCP server somewhere on the LAN to give out IP addresses to VPN clients
keepalive 10 120
- Create the ethernet bridge Debian-style by adding the following lines to your /etc/network/interfaces:
iface br0 inet dhcp
pre-up openvpn --mktun --dev tap0
bridge_ports eth0 tap0
- Restart network with
- Now you should still have internet connectivity, and eth0 and a br0 bridge
- Get and install OpenVPN 2.x. I used Macports, so I just fired up ports like:
sudo port install openvpn2
- Grab and install the tun/tap driver for Mac OS X
- Reboot, or force install the kernel extensions
- Make sure you have the client encryption keys from above, and use the following client configuration:
- Grab the openvpn-tap-up-down.sh script from the bottom half of this mailing list posting, or download it right here: tap-up-down.sh
- Install that tap-up-down.sh in /opt/local/etc/openvpn and chmod +x it so it can be executed
Fire it up
Now we’re ready to start this thing up, over an SSH tunnel, kind of like describe in this post.
- Fire up your ssh, tunneling the OpenVPN port like
ssh -L 1194:vpn.your.domain.com:1194 ssh-gateway.your.company.com
- Where ssh-gateway.your.company.com is your ssh gateway, and vpn.your.domain.com specifies the tunnel endpoint at the VPN server you have just set up.
- Turn on OpenVPN on the server like
openvpn --conf /etc/openvpn/bridge.conf
- Turn on OpenVPN on the client like
sudo openvpn2 --config /opt/local/etc/openvpn/client.conf
- You should see, on both sides, OpenVPN authenticating and then starting up.
Now, you should be able to ping any machine on the remote subnet. I wanted to be able to get to anything on the internal network through the VPN, so I manually added a route to all of the internal network (10.0.0.0/8) through the VPN server’s default gateway. Like this:
route add 10.0.0.0/8 10.49.27.1
Of course, substitue the IP of the VPN server’s gateway to the rest of the network for 10.49.27.1. That, combined with the handy script from Ben Low, allows all DNS lookups for the internal network to go to the internal DNS servers, routed through the VPN.
- On the server side, everything is pretty much normal. I can’t seem to use the “push redirect-gateway” through this system, as a) either the OS X port of OpenVPN doesn’t support it (unlikely), or b) the gateway information is a little borked as it is going over an SSH tunnel. Either way, I just manually add the route to the default gateway.
- For some reason, the tap0 driver does not go into DHCP mode by default. You have to force it using the ipconfig program, which is done for you in the tap-up-down.sh script.
- On the client side, Mac OS X has a very complex name resolution service. Very cool if you get under the hood, as seen in these two threads on the Apple developer mailing list. The end result is that when you get the DHCP lease from the internal LAN DHCP server, the
tap0device gets some service keys that record the DNS servers pushed from the LAN DHCP server. After the
tap0driver comes up through OpenVPN, you can see this by running
scutilfrom the command line, and executing
- Now, OS X needs to have a
SupplmentalMatchDomainskey associated with these DNS entries before it will actually consult them as part of the name resolution service. The script does that for you. You can see its effects after the VPN starts up by running
There you go. Now poke holes in your own Great Corporate Firewall!