A while ago, I have configured a small OpenVPN for personal use (mostly for security when using public wireless networks) with OpenVPN. The setup is pretty easy, thanks to a very helpful tutorial (in German) and the sensible default settings of OpenVPN itself. (Setting up the certificate infrastructure was a bit annoying, though – I would really prefer an SSH-like approach where the users can create a private key for themselves, and the VPN server has a list of the key/user mappings, but that's another story.)
Configuring the server to push a default route to the clients is as simple as setting the
push redirect-gateway def1 option in the server configuration, and mostly, that works as expected.
However, there is a huge caveat for IPv4-only clients. Since I don't have an IPv6 subnet big enough to provide IPv6 tunneling on my server as well (OpenVPN, or at least the version included in Ubuntu 12.04, seems to require a /64 subnet for now, but my provider only provides a tiny /112), I just didn't configure IPv6 and expected IPv6 connectivity to be broken. But that's not what's happening:
When connecting to the VPN from a client that has both IPv4 and IPv6 connectivity, only the IPv4 traffic will be routed over the VPN gateway, but the IPv6 traffic will be routed locally – and since the world IPv6 launch, there are quite a lot of hosts that are reachable over IPv6 and serve AAAA records to all users. Except for TLS protected connections, traffic to them will be unencrypted, and even then, the connection metadata (IP addresses etc.) will be plainly visible to anybody on the public network.
After thinking about that for a while, it kind of makes sense: At no point did I instruct OpenVPN to break my existing IPv6 connectivity, and since I didn't provide any IPv6 tunneling settings, my routes for that were just left alone. It can also be fixed easily enough – just configure a script that tears down IPv6 connectivity before connecting to the VPN, and restores it immediately after that. Maybe there is even a way to do that from the server via
push instructions, but I've had no success with that so far.
Curious about the issue, I decided to check how other VPN solutions and clients handle that situation, with pretty much the same results:
Cisco's AnyConnect, when used with OpenConnect, behaves exactly like OpenVPN. The Android client, however, seems to specifically work around that problem – IPv6 connectivity breaks while connected to an IPv4-only VPN. I haven't been able to find out how that works, but I suspect that either some additional routes are pushed to the client, and the IPv6 traffic is discarded locally or at the gateway, or something is going on at the DNS level (since I get
NAME_NOT_RESOLVED errors when visiting what-is-my-IPv6–like sites from the VPN).
OpenVPN for Android behaves just like the Linux client. Unfortunately, unlike Linux, Android provides no way for the user or the VPN application developer to disable IPv6, which makes a workaround pretty much impossible. I've reported that as a bug to the developer, even though it is a problem with android, not OpenVPN – maybe he'll figure out a solution. (I've also reported it as an Android bug, but I'm really not sure if there's anybody from Google watching that bug tracker...)
I'm not really sure what would be the best solution to the problem: Should VPN clients just break IPv6 connectivity by default, to protect the data of users who will most likely be using a VPN under the assumption that it will be doing just that? Or should it leave IPv6 alone by default, just providing an option to automatically disable their IPv6 connectivity when needed? I'm in favor of the first approach, but as it is, even the second one would be a big step forward – on Android, users have no way of disabling IPv6 traffic circumventing their VPN connection, and most will not even know that it's happening.