I want to connect several LANs located on remote buildings.
The "central" site have a Linux computer running OpenVPN. Each remote site also run OpenVPN.

  1. the central site has a LAN numbered
  2. several remote sites are also numbered
  3. I can't/won't/don't want to/whatever modify LAN numbering
  4. I don't have control on most remote OpenVPNs

I then need to :
1. define virtual LANs
2. configure a 1:1 NAT for each site
3. the 1:1 NAT has to be configured on the central router

LAN map .
So each site is seen to have a 10.10.x.0/24 LAN.
When a computer want to reach, say, on site 12, it just have to send a paquet to

Operating a VPN is not a problem for me. I currently connect 60+ sites. But I don't find a simple way to do this 1:1 NAT.

Here is an example of a packet sent from the central site to a remote site, and its response packet :

enter image description here

I did some tests with iptables NETMAP but I can't manage to make it work because I don't find a way to modify source+destination after routing decision.
I prefer to avoid the new --client-nat OpenVPN's feature.
Maybe I have to force routing with ip route ? Or to loop twice into the network stack with veth ?

Note : I don't want to use masquerade. Only 1/1 NAT.

It's not possible with a regular openVPN setup. Because a packet from a remote site is indistinguishable from a packet from another site : both have similar source and destination addresses, and both come from the same tun (or tap) interface. So it's not possible to source-NAT it.

Solution 1 : do the NAT on the remote sites. Not possible in my case. I have to do it only on the central site.

Solution 2 : setup one VPN for each remote site. So I'll have one tun for each. I think this can be ok. Not very memory efficient but ok.

Solution 3 : setup a (unencrypted) tunnel inside the VPN for each site. This will give one interface for each. Simple tunnels are are not cross-platform (to my knoledge). For example GRE or ipip or sit are ok for Linux, but some distant sites are running only one Windows computer, so openVPN is installed on it. So impossible to setup a simple tunnel. Other option is to use a more complicated tunnel (wich ?) but the overhead on the system and on the sysadmin may be bigger than having multiple VPNs

Solution 4 : compile the latest openVPN, because its include a 1:1 NAT feature. I test this this week.

  • 1
    For solution 4 you don't have to compile. Most major Linux distributions have compiled packages on the official openVPN website. But this won't work for you because the --client-nat feature is a pushable option. So your clients have to also use the latest RC version (and you say you don't have control over remote sites). Dec 5, 2012 at 21:13
  • 1
    Well, I'm wrong : the --client-nat feature is 100% inside OpenVPN (I thought it was using ipfilter). I just tested : it works on Windows too. See my solution below. Dec 8, 2012 at 21:02
  • 1
    I would like to know if you ever got this working and what you did. Jun 25, 2015 at 0:14

2 Answers 2


A very basic solution is :
1. use OpenVPN 2.3 or more (currently, the latest is 2.3-alpha) for server + clients
2. use the OpenVPN configuration option below
3. don't use anything else (no ipfilter, no tricks)

On the server side, you need to manually distribute VPN addresses (so no server option, you have to use ifconfig or ifconfig-push) :

# /etc/openvpn/server.conf
push "route"
push "client-nat dnat"
push "client-nat dnat"
push "client-nat dnat"

The route and push route and client-nat lines are required if you want to communicate directly between routers (ping from a distant site throught the VPN). Else you can discard them.



Now you have to choose a virtual network address. I kept the same you used in your example :
You allow routing for this :

# /etc/openvpn/server.conf
push "route"



You have now to instruct the client to use the 1:1 NAT :

# /etc/openvpn/ccd/client_11
push "client-nat snat"
push "client-nat snat"
push "client-nat dnat"

The first line set the remote router address. Beware about Windows driver requiring special addresses.
The second and last lines allow the distant router to communicate from its 10.99.99.x interface.
Third and fourth lines do the source and destination 1:1 NAT
The fifth line tells OpenVPN what to do with the corresponding packets.

This method allow to connect sites with identical (or not) LAN addresses, without any shadowed host.

  • 2
    Simple, brilliant. Dec 8, 2012 at 23:34
  • 1
    I tried this but could not get it to work. I am using Linux on both sides. Somethings are odd or I don't understand some thing fully. Your ifconfig-push in the client_11 file (first line), shouldn't that be a netmask for the second argument instead of Second, why are you using this third network It seems you are trying to use the 111 network for communication between sites, can't the 10.10 network be used for that directly? Lastly, no matter what I try, I don't see (in tcpdump) the snat and dnat affecting packets on the client. Jun 25, 2015 at 10:04
  • Not really simple but still brilliant. Oct 2, 2016 at 21:38
  • Not working. Same problem of Micheal Grant. Somebody has working solutions?
    – Kaiser69
    Jul 22, 2021 at 14:12
  • Working on openvpn 2.5.5.
    – YCN-
    May 17, 2023 at 7:20

I've done something similar with real interfaces, but I can't see why it wouldn't work with VPN interfaces.

The idea is that, as you have the same subnet available at different interfaces on that router, it complicates the routing. Basically, when a packet for enters the router, it is DNATed before routing to, so you have to be able to tell routing that it was intended for the on the interface VPN13.

That can be done by using firewall marks and routing rules that use those marks. SNAT and DNAT are to be done with the NETMAP firewall target. For SNAT, it's the same problem, in POSTROUTING, you've lost the information that the packet came from this or that interface and they've all got source address 192.168.0.x. So you need a mark as well to carry that information from mangle-PREROUTING to nat-POSTROUTING. You can use the same mark, but then that would mean those packets would use that alternate routing table, so you'd need to duplicate the global routing table on all.

For each network, you'd do:

if10=eth0 if11=tun0 if12=tun1 if13=tun2

for site in 10 11 12 13; do
  n=$(($n + 1))
  eval "interface=\$if$site"
  inmark=$(($n * 2)) outmark=$(($n * 2 + 1))

  iptables -t nat -A PREROUTING -d "$net" -j NETMAP --to "$lnet"
  iptables -t nat -A POSTROUTING -s -m mark --mark "$inmark"/0xf -j NETMAP --to "$net"
  iptables -t mangle -A PREROUTING -i "$interface" -j MARK --set-mark "$inmark"/0xf
  iptables -t mangle -A PREROUTING -d "$net" -j MARK --set-mark "$outmark"/0xf
  ip rule add fwmark "$outmark"/0xf table "$table"
  ip route add "$lnet" dev "$interface" table "$table"

Above, we're using the first 4 bits of the mark, to allow up to 7 networks to be routed that way.

  • 1
    Thanks for your answer. I tested it but it doesn't work. I tested with only one LAN, no more result. I use tcpdump to monitor the packets, and when I send a packet from remote to centrale site, I don't even see anything (?! how is it possible ?). With your directions, I try to construct my step by step answer. Not sure I will succeed. Dec 3, 2012 at 22:50
  • 2
    My answer only covers what to do on the central site. I assume you configure routing correctly on the other sites. For instance, you probably need to add a route to via the VPN tunnel on the remote sites. You may also need to tell openvpn to let those packets through. In anycase, using tcpdump to see what packets get where and how is the right approach. the iptables LOG target is also your friend. Dec 3, 2012 at 22:55
  • 2
    If you see no packets, you have to look into your openvpn log. You probably will find dropped packets. If this is the case, use a "iroute" for each client into your client-config-dir Dec 4, 2012 at 12:03

You must log in to answer this question.

Not the answer you're looking for? Browse other questions tagged .