Take the 2-minute tour ×
Unix & Linux Stack Exchange is a question and answer site for users of Linux, FreeBSD and other Un*x-like operating systems.. It's 100% free, no registration required.

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 192.168.0.0/24
  2. several remote sites are also numbered 192.168.0.0/24
  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, 192.168.0.44 on site 12, it just have to send a paquet to 10.10.12.44

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.

EDIT :
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.

share|improve this question
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). –  Gregory MOUSSAT Dec 5 '12 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. –  Gregory MOUSSAT Dec 8 '12 at 21:02
add comment

2 Answers

up vote 1 down vote accepted

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
ifconfig 10.99.99.1 10.99.99.2
route 10.99.99.0 255.255.255.0
push "route 10.99.99.0 255.255.255.0"
push "client-nat dnat 10.99.99.11 255.255.255.255 10.10.111.11"
push "client-nat dnat 10.99.99.12 255.255.255.255 10.10.112.12"
push "client-nat dnat 10.99.99.13 255.255.255.255 10.10.113.13"

The route and push route and client-nat lines are required if you want to communicate directly between routers (ping 10.99.99.1 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 : 10.10.0.0/16
You allow routing for this :

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

.

.

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

# /etc/openvpn/ccd/client_11
ifconfig-push 10.99.99.11 10.99.99.1
push "client-nat snat 10.99.99.11 255.255.255.255 10.10.111.11"
push "client-nat snat 192.168.0.0 255.255.255.0 10.10.11.0"
push "client-nat dnat 10.10.10.0 255.255.255.0 192.168.0.0"
iroute 10.10.11.0 255.255.255.0
iroute 10.10.111.0 255.255.255.0

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.

share|improve this answer
1  
Simple, brilliant. –  Bertrand SCHITS Dec 8 '12 at 23:34
add comment

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 10.10.13.123 enters the router, it is DNATed before routing to 192.168.0.123, so you have to be able to tell routing that it was intended for the 192.168.0.123 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:

lnet=192.168.0.0/24
if10=eth0 if11=tun0 if12=tun1 if13=tun2

n=0
for site in 10 11 12 13; do
  table=$site
  net=10.10.$site.0/24
  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 192.168.0.0/24 -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"
done

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

share|improve this answer
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. –  Bertrand SCHITS Dec 3 '12 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 10.10.0.0/16 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. –  Stephane Chazelas Dec 3 '12 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 192.168.0.0 255.255.255.0" for each client into your client-config-dir –  Gregory MOUSSAT Dec 4 '12 at 12:03
add comment

Your Answer

 
discard

By posting your answer, you agree to the privacy policy and terms of service.

Not the answer you're looking for? Browse other questions tagged or ask your own question.