Dirty NAT tricks to get a VPN to work with clients also numbered in the private address space


Nick Martin

The Problem

You have a corporate LAN. You want to set up a VPN (in this case OpenVPN) into the LAN for your road-warriors. However, your LAN is numbered with one of the very common private subnets, such as 192.168/16. Your road-warriors often get addresses in the same private subnet from their coffee-shops, and this breaks things horribly. This is illustrated in the diagram below.

I'm going to use specific IP addresses and interface names on this page, since too often I find when people try to describe the general solution it actually makes it less clear and harder to apply to your own network.

The standard VPN solution will simply number the client node on to the corporate LAN (somewhere in 192.168/16). Now the client will be confused, since it will have a route for both 192.168.0/24 and 192.168/16. What will likely happen is the client will simply not be able to access anything in the corporate LAN's 192.168.0/24 range.

This page assumes you are able to set up a bare VPN connection between the clients and the server (just two connected virtual Ethernet devices, as shown in the diagram), but are just not sure how to number it such that the client can actually talk to all the nodes in the LAN.

Discarded Solution #1: Renumber the LAN

The OpenVPN HOWTO suggests renumbering the corporate LAN. For many people, this is simply not an option. A typical dialog might go something like this:
- Hello, friendly sysadmin!
+ What do you want?
- I'd like to set up a VPN so I can work from the road.
+ Seems reasonable. What do you need from me.
- Oh, just permission and uhh... renumbering the whole corporate LAN
+ What!?!?
- We need to renumber the network.
+ I WILL DESTROY YOU!

Discarded Solution #2: Client side static routing

Another solution people on various mailing lists have proposed is to number the client into the corporate LAN as normal, but alter the routing table on the client such that it has a static route to its gateway. The routing table on the client would look something like this:
192.168.0.1/32 dev eth0
192.168.0.0/16 dev tap0
default via 192.168.0.1 dev eth0

There are several problems with this approach. First, it requires manual intervention on the client side, and a client OS that supports such intervention. If you want to support Windows clients, this may not be the best approach.

The more major problem with this approach is that two IPs on the private LAN will be "shadowed" on the client: both the address of the gateway (192.168.0.1) and the IP of the client itself (192.168.0.42). If there is an important server on 192.168.0.42 on the private LAN, the client will not be able to access it.

Solution: Dirty NAT tricks

The solution I settled on was to create a one-to-one NAT to remap all of corporate LAN to a different private netblock (10.22/16), and put the client into that range. To the hosts in the corporate network, the VPN client appears to be in 192.168/16 and to the client the corporate network seems to be 10.22/16. (The OpenVPN FAQ mentions this approach, but does not give detail as to how to set it up.) A diagram of the configuration is provided below.

Configuring OpenVPN

First, you should pick a subnet of the corporate LAN to put VPN clients on. I chose 192.168.8/24, which will be mapped to 10.22.8/24. OpenVPN should be configured to hand out addresses in the mapped range, and set the VPN host as the router to the rest of the mapped range. We have the following lines in the OpenVPN configuration:
server-bridge 10.22.8.1 255.255.255.0 10.22.8.10 10.22.8.120
push "route 10.22.0.0 255.255.0.0 10.22.8.1"
Once the OpenVPN link is configured, configure the TAP interface:
ip addr add 10.22.8.1/24 dev tap0
ip link set tap0 up

Now you should be able to bring an OpenVPN client up (say 10.22.8.10). You should be able to ping the server (as 10.22.8.1) from the client and vice versa.

Setting up the NAT

Next, set up the one-to-one NAT mapping the two private networks together:

iptables -v -t nat -A PREROUTING -d 192.168.8.0/24 -j NETMAP --to 10.22.8.0/24
iptables -v -t nat -A PREROUTING -i tap0 -d 10.22.0.0/16 -j NETMAP --to 192.168.0.0/16
iptables -v -t nat -A POSTROUTING -o tap0 -s 192.168.0.0/16 -j NETMAP --to 10.22.0.0/16
iptables -v -t nat -A POSTROUTING -o eth0 -s 10.22.0.0/16 -j NETMAP --to 192.168.0.0/16
echo 1 > /proc/sys/net/ipv4/ip_forward

More documentation on iptables and netfilter can be found here. Netfilter is a very complicated beast, but is well worth spending some time getting acquainted with.

At this stage, you should be able to send pings out from the VPN client to hosts on the private LAN (at the remapped address, of course), but the LAN machines won't know how to reply to the ping since ARP is not set up yet.

You can test this by logging in to another server (say 192.168.1.12) on the LAN and watching tcpdump. Ping the remapped address (10.22.1.12) from the client. You should see the ping requests come in to the server, followed by ARP packets asking who-has 192.168.8.10.

Setting up Proxy ARP

In order for the system to work correctly, the VPN server should respond to all ARP requests for 192.168.8/24 on eth0. However, in Linux version 2.2, the ability to instruct the kernel to reply to any ARP packet for addresses in a given subnet was removed, and replaced by automatic proxy ARP. For the automatic proxy ARP to work, the VPN server must think it has a different route to the virtual client subnet. The following should enable proxy ARP in the configuration required.

ip addr add 192.168.8.1/24 dev tap0
echo 1 > /proc/sys/net/ipv4/conf/tap0/proxy_arp
echo 1 > /proc/sys/net/ipv4/conf/eth0/proxy_arp

Once this is set up, you should be able to get full communication between VPN clients and servers on the corporate LAN. Test this by pinging the remapped address of a machine on the LAN (from 10.22.8.10 to 10.22.1.12) from the client and the non-remapped client address from said machine (from 192.168.1.12 to 192.168.8.10).

Other details

As with any NAT, some things will break over this connection. Anything with IP addresses hard coded will not quite work right due to the remapping.

Also, you can not use the same DNS entries for things in the private LAN. DNS must return remapped addresses to VPN clients on remapped networks. The simplest solution is to run a DNS server on the VPN server that has edited copies of the zone files from the master DNS for the subnet. Ideally, there would be a simple proxy DNS server that did the remapping, but I have been unable to find such a thing.


Copyright 2005 Nick Martin. All rights reserved.
Last modified: Sun May 1 19:26:55 EDT 2005