vpnc is an open source client for Cisco VPNs, which is pretty widely used. It’s intended as a user-driven interface: user decides to connect, user runs vpnc (or one of the many GUI wrappers around it) to connect, user uses remote resources, user disconnects. But for some users, manually connecting & disconnecting the VPN is a burden. I developed an auto-connecting VPNC setup for just such a customer scenario.
I started with OpenWRT (of course!) and vpnc. So far I’ve deployed this setup using OpenWRT Kamikaze, versions 8.09.1 and 8.09.2. I’ll describe how the process works first, and then show the details in my next post.
The first thing we need to do is intercept DNS queries for the secure network. (Most secure networks will have a private DNS server behind the firewall, with lots of information that’s not in the public version.) OpenWRT uses the dnsmasq name resolver, and happily dnsmasq provides for exactly this case. So, we configure dnsmasq to know that the servers for the VPN domain are on its private addresses, and not to use the public servers.
Some companies might have the name of the VPN gateway in the same domain as their private, through the VPN environment. This could be a problem: how do we find the IP address for the gateway, if we need the VPN to talk to the domain servers? The easy answer for now is to just hardcode it in /etc/hosts on the OpenWRT.
OK, so we dealt with DNS name resolution, but how do we get the IP packets to go through the VPN? Actually, once vpnc connects, it will set up routing on the OpenWRT for us. So the only tricky bit is starting up vpnc at just the right time.
One way to do this would be to start vpnc whenever the WRT boots. This works, pretty much, but might be considered hostile by the VPN administrators. Instead we want to start the vpn tunnel whenever a user tries to access a machine in the private environment. To do this, we need to capture IP packets being routed to private IP addresses. This sounds like a job for iptables!
iptables is part of the Linux kernel which lets you define rules for handling IP packets. It does all kinds of cool things – filtering, QOS, NAT – but all we need it to do is tell us when someone is trying to connect through the VPN, so that we can start up the VPN tunnel. To do this, I used the iptables “ULOG” target: ULOG writes a message to a userspace daemon called ulogd, which acts like a hub (kind of like syslogd) and routes the messages to other programs. I kept it simple and just wrote the message to a file.
To tie it all together, I wrote a script which monitors the ulog file. The script gets automatically started at boot time: if the VPN isn’t up yet, it just monitors the ulog file. When a packet trace appears in the ulog file, we know it’s time to start the VPN up. Once the VPN is connected, the script hangs out, waiting for it to get shut down — either manually or by an idle timer. If the VPN gets shut down, then the script goes back to watching the ulog file.
OK, so we have DNS requests going to the private servers, and IP traffic causes the VPN to autoconnect. We’re done, right? Well, almost. It turns out that sometimes vpnc shuts down messily. It can leave the OpenWRT without a default route, or it can leave the resolv.conf file pointing to behind-the-tunnel servers. Either one of these problems is enough to prevent reconnecting the VPN! So I added a cleanup step to my script, which makes sure that vpnc has cleaned up after itself.
Add some logging and a simple web interface, and we’re all set. Details in my next post.