Paranoid Penguin - Linux VPNs with OpenVPN, Part V
In talking about the value of using VPN software when using untrusted networks like WLAN hot spots, I've described the benefits of using your home network's Web proxy rather than surfing the Web directly through the untrusted network. From a policy-enforcement standpoint, this allows you to enforce whatever URL or content filtering with which your home network's proxy is configured; from an endpoint-security standpoint, it makes phishing and man-in-the-middle attacks harder.
On the downside, it also results in a somewhat slower Web browsing experience, because each user's Web traffic must traverse a longer, slower path than without the VPN tunnel in place. Also, making remote users use your corporate Web proxy without also configuring them to use your corporate DNS servers may fail to prevent man-in-the-middle attacks (in which DNS redirection is a common technique), giving a false sense of security.
I return to the DNS problem shortly, but how do you use Web proxies with OpenVPN? It's quite simple. On the Web proxy itself, you simply need to make sure there's an Access Control List (ACL) allowing client connections from tunnel IPs. This is a moot question if your Squid server is running on a different box from the OpenVPN server, and the OpenVPN server is using Network Address Translation (NAT) to “hide” all tunnel-originated packets behind its own IP address (I discuss NAT shortly).
If, however, you are running the Web proxy on the OpenVPN server itself, you need an ACL. For Squid, you need to add something like this to /etc/squid/squid.conf:
acl openvpn_tunnels src 10.31.33.0/24 http_access allow openvpn_tunnels
The acl line defines an object named openvpn_tunnels, representing transactions whose source IP addresses fall between 10.31.33.1 and 10.31.33.254. The http_access line allows transactions initiating from this IP range. As with any other change you make to this file, you need to restart Squid for this ACL to take effect (sudo /etc/init.d/squid restart).
Your clients will, of course, need to be configured to use your Web proxy, but they target the same IP address regardless of whether they're connecting from afar via OpenVPN or connecting directly to your LAN. That is, if you're already having your users proxy all their Web traffic, no change to their Web browser settings should be necessary for them to use the same proxy through OpenVPN.
If you're requiring all remote users to route all their Internet traffic through the VPN tunnel, it isn't enough to force them to use the remote network's default gateway. You also need to force them to use the remote network's DNS servers. Otherwise, a man-in-the-middle attack that involves DNS spoofing on the client side of the tunnel will succeed. Once a remote user's browser has been handed a phishing site's IP address for a given URL, it doesn't matter whether it connects to that IP directly or through the VPN tunnel (unless, perhaps, the phishing site's IP address is on a blacklist enforced by your corporate Web proxy or firewall).
If your remote clients all run Windows, it's easy to enforce server-side DNS settings. Simply add the following line to your OpenVPN server's OpenVPN configuration file:
push "dhcp-option DNS 10.0.0.100" push "dhcp-option DNS 10.0.0.120"
Of course, you should replace 10.0.0.100 and 10.0.0.120 with the addresses of the DNS servers you want your clients to use.
Unfortunately, this won't work for non-Windows clients. For Linux and other UNIX clients, you'll need to edit those client systems' /etc/resolv.conf files either manually or dynamically. The server-side configuration parameter foreign_option_<I>n<I> lets you pass data to tunnel-initiation scripts (--up scripts); for example, the line foreign_option_1='dhcp-option DNS 10.0.0.100' sends the line dhcp-option DNS 10.0.0.100 to any defined “up” scripts, which can then act on that data.
The details of how all this works are out of the scope of this article. Suffice it to say that the OpenVPN man page describes how “up” scripts work, and the link to the update-resolv-conf script in the Resources for this article provides a script you can alter to rewrite /etc/resolv.conf to give precedence to your “home” network's DNS servers.
There's one more critical step necessary to allow remote users to route packets to the Internet through their VPN tunnels. You need to set up Network Address Translation (NAT) so that traffic entering your “home” network from VPN tunnels appears to originate from the OpenVPN server.
This is because the networks from which remote clients connect will have either different network IP addresses than your “home” network, in which case the odds are your “home” network infrastructure won't have a route to the remote clients, or they'll have the same network IP addresses, in which case it's quite possible that different hosts on opposite ends of the VPN tunnels will have the same host IP addresses!
Note that this problem plays out differently on “bridging” (Layer 2) VPN tunnels than on “routing” (Layer 3) VPN tunnels. Because all my examples so far have involved a routing VPN scenario, what I'm about to say regarding NAT applies to routed VPN tunnels.
So, the way to sidestep the problem of foreign IP addresses on remote clients' packets completely is simply to rewrite all packets entering the OpenVPN server's local network with the OpenVPN server's local IP address. To do so, add just one firewall rule, like this:
bash-$ sudo iptables -t nat -A POSTROUTING ↪-s 10.31.33.0/24 -o eth0 -j MASQUERADE
Note that as with any other time you execute the command iptables, this is not a persistent change. To make this rule persistent across reboots, you need to add an equivalent line to whatever configuration file or script controls firewalling on your OpenVPN server.
The OpenVPN man page has an entire section on firewalls (called “FIREWALLS”) that contains lots of good information about managing iptables firewall rules on your OpenVPN server. Remember, any VPN server is a security device. It's a good idea to run not just a single NAT rule, but a detailed set of filtering rules that restrict how people can connect to the server and to what systems your VPN clients may connect.
(Speaking of iptables, it's been a long time since I covered Linux's powerful firewall capabilities in this column. Look for an in-depth article on writing your own Linux firewall rules in a future column.)