Posted in Networking Security VPN

Routed OpenVPN between two subnets behind NAT gateways

June 7, 2008 - 15 comments

Edit : between two or MORE subnets. Check out the exchange between Michael Antal and me in the comments. He’s been able to interconnect 3 subnets using this method and some slight tweaks in routes.

The following is the configuration needed to create a routed OpenVPN network between two remote subnets, both behind NAT gateways. On each side, the gateways will act as the VPN gateways.

Network subnets on both side must be different. In this example, we connect 192.168.1.0/24 to 192.168.200.0/24.

With this setup, we don’t even need to open ports at the NAT level on either side of the VPN.

Network configuration

Network A :

Subnet : 192.168.1.0/24

Gateway for Network A
VPN interface (tun0) : 10.0.0.1
Eth0 : 192.168.1.254
Eth1 / Public IP : 212.x.x.x (machineA.example.org)

Network B :

Subnet : 192.168.200.0/24

Gateway for Network B
VPN interface (tun0) : 10.0.0.2
Eth0 / Public IP : 66.x.x.x (machineB.example.org)
Eth1 : 192.168.200.254

If we imagine forwarding is rejected at the firewall level on machine B, we would need to allow traffic between the tun device created by OpenVPN and the LAN interface, as root you would then type :
iptables -I FORWARD -i tun0 -o eth1 -j ACCEPT
iptables -I FORWARD -i eth1 -o tun0 -j ACCEPT

Make sure the rules remain applied across reboots (using iptables-save or storing the rules in /etc/rc.local or else)

Enabling IP routing :

We need to enable routing on both VPN gateways..

echo “1″ > /proc/sys/net/ipv4/ip_forward

Using this method, routing is not persistent across reboots, check the following link :
http://www.wains.be/index.php/2006/06/06/enable-ip-forward-under-rhelcentos/ (which works for Debian as well)

Static key generation :

We will use simple static key for our example…

openvpn --genkey --secret /etc/openvpn/vpn.key

Share the key between the VPN gateways over a secure channel (scp, etc.).

If you want to use certificates instead (which I recommend), check out : http://www.wains.be/index.php/2008/07/15/a-vpn-for-remote-users-with-openvpn/

OpenVPN configuration :

machine A : /etc/openvpn/vpn.conf

remote machineB.example.org
float
port 8000
dev tun
ifconfig 10.0.0.1 10.0.0.2
persist-tun
persist-local-ip
persist-remote-ip
comp-lzo
ping 15
secret /etc/openvpn/vpn.key
route 192.168.200.0 255.255.255.0
chroot /var/empty
user nobody
group nogroup
# If using RedHat replace with
# group nobody
log vpn.log
verb 1

machine B : /etc/openvpn/vpn.conf

remote machineA.example.org
float
port 8000
dev tun
ifconfig 10.0.0.2 10.0.0.1
persist-tun
persist-local-ip
persist-remote-ip
comp-lzo
ping 15
secret /etc/openvpn/vpn.key
route 192.168.1.0 255.255.255.0
chroot /var/empty
user nobody
group nogroup
# If using RedHat replace with
# group nobody
log vpn.log
verb 1

Establishing the connection :

On machine A type :

openvpn --config /etc/openvpn/vpn.conf

Machine A will try to establish the connection. Type the same command on machine B to initialize the connection.

As soon as the connection is up, hosts on network A should be able to ping hosts on network B and vice-versa. If you can’t ping from one side to the other, it’s probably a routing issue.

We can use traceroute from a machine on network A to see the path taken to reach a host on network B :

$ traceroute 192.168.200.30
traceroute to 192.168.200.30 (192.168.200.30), 30 hops max, 40 byte packets
1 192.168.1.254 (192.168.1.254) 2.128 ms 2.378 ms 2.781 ms
2 10.0.0.2 (10.0.0.2) 132.761 ms 137.342 ms 141.130 ms
3 192.168.200.30 (192.168.200.30) 136.752 ms 133.869 ms 135.960 ms

We can see the traffic is going through the 10.0.0.2 interface.

We also can check the routing table on the VPN gateway on network A :

# route -n
Kernel IP routing table
Destination Gateway Genmask Flags Metric Ref Use Iface
10.0.0.2 0.0.0.0 255.255.255.255 UH 0 0 0 tun0
192.168.1.0 0.0.0.0 255.255.255.0 U 0 0 0 eth0
192.168.200.0 10.0.0.2 255.255.255.0 UG 0 0 0 tun0
0.0.0.0 212.x.x.x 0.0.0.0 UG 0 0 0 eth1

We see any traffic directed to 192.168.200.0/255.255.255.0 must go through interface 10.0.0.2 on device tun0.

Making sure the VPN connection is established at boot (Debian way) :

Edit /etc/defaults/openvpn and specify which VPN network must be started.

Make OpenVPN starts at boot with this command :

update-rc.d openvpn defaults

OpenVPN will start any VPN configuration named *.conf found in /etc/openvpn/
So don’t store copies of config like test.conf test-backup.conf as OpenVPN will try to start them at boot.

Comments

Serge van Ginderachter

June 7, 2008 - 16:28

Another fine howto. Thanks!

Sébastien Wains » Tunneling UDP through SSH

July 26, 2008 - 2:16

[...] Say you need to forward UDP packets between two remote networks securely. E.g : dns queries from your home machine to your dns servers at work. You should use a VPN between the networks in order to do so (see : http://www.wains.be/index.php/2008/06/07/routed-openvpn-between-two-subnets-behind-nat-gateways/ [...]

Michael Antal

January 17, 2009 - 0:34

Hi there Sébastien!

Any thoughts on how this method could be extrapolated to three or even more subnets? Btw: I connected two subnets with this method flawlessly! Thank you for the great howto!

Best of luck,
Michael

Sébastien Wains

January 17, 2009 - 0:55

Hey Michael,

Thanks :-)

If you want to interconnect 3 or more remote sites.. just make one site the central “hub” that would store the routes to every remote sites. Let’s call that hub site “A”.

Site A : 192.168.0.0/24
Site B : 192.168.1.0/24
Site C : 192.168.2.0/24

VPN 1 : A (on tun0) to B (on tun0) with 10.0.0.0/24
VPN 2 : A (on tun1) to C (on tun0) with 10.0.1.0/24

If B wants to connect to C, just set the route on the gateway at site B to point to the tunnel to site A. Like this :

192.168.2.0 10.0.0.2 255.255.255.0 UG 0 0 0 tun0

Gateway A would receive the packets and redirect them through the VPN tunnel to site C, since it has the following route :

192.168.2.0 10.0.1.2 255.255.255.0 UG 0 0 0 tun1

Of course, gateway C must know how to send packets back to site B with the following route :

192.168.1.0 10.0.1.5 255.255.255.0 UG 0 0 0 tun0

Michael Antal

January 17, 2009 - 1:39

Thanks for the quick answer Sébastien!

I’ve set up the way you said:

There is two communication between (A central hub with 2 vpn interfaces)
A B
A C

But I cannot get B -> C nor C -> B connections going.

The routing tables look fine I guess :
A(192.168.0.1):
192.168.4.0 10.0.1.2 255.255.255.0 UG 0 0 0 tun0
192.168.1.0 10.0.0.2 255.255.255.0 UG 0 0 0 tun1

B(192.168.4.1):
192.168.1.0 10.0.1.1 255.255.255.0 UG 0 0 0 tun0
192.168.0.0 10.0.1.1 255.255.255.0 UG 0 0 0 tun0

C(192.168.1.1):
192.168.4.0 10.0.0.1 255.255.255.0 UG 0 0 0 tun0
192.168.0.0 10.0.0.1 255.255.255.0 UG 0 0 0 tun0

Thank you again for your time,
Michael

Michael Antal

January 17, 2009 - 1:40

Correction for the last comment:

There is two-WAY communication between (A central hub with 2 vpn interfaces):
A B
A C

Sébastien Wains

January 17, 2009 - 2:05

Have you tried running tcpdump on the “hub” while trying to ping from B to C or reverse ?

Please try and see what happens.

Michael Antal

January 17, 2009 - 11:39

Yes I’ve tried it. And thank you for the tip because that solved the problem. It turns out that I had to include another route in B and C’s routing table that is: I had to route the OTHER VPN subnet through the local VPN interface as well:
On B (192.168.4.1, VPN tun0 inet addr:10.0.1.2 P-t-P:10.0.1.1)
The extra routing is:
10.0.0.0 10.0.1.1 255.255.255.0 UG 0 0 0 tun1

Where 10.0.0.0/24 is the VPN subnet of the A – C channel,

Did the opposite on C and now I have perfect connection between
any given subnet!

Thanks again!
Michael

Sébastien Wains

January 17, 2009 - 13:11

Great, thanks for the feedback. I made up all the config without actually trying it. Of course source addresses appear to come from 10.0.x.0/24 and not 192.168… it makes sense :-)

David Piedra

June 17, 2009 - 20:20

Hello, this works great for me, i did ti and it’s working great. There’s just one thing that is not working at all. There’s an internal email that’s not working between sites, the server is in site A but none of the site B computers can neither receive nor send emails to the server. With the iptables rules you put, all the traffic from one network to the other, suppose to be passed through the tunnel, but all packages from the email seems to be lost and never get to the tunnel. I configure the email clients to use the IP of the server not the name, but still not working.

Any ideas, thanks!!

Sébastien Wains

June 17, 2009 - 21:51

I don’t want to talk you down but have you configured your SMTP server to accept send/receive emails from the range at site B ?

David Piedra

June 19, 2009 - 18:25

Yes, I did. I think is a firewall problem, because I can’t even connect from a computer on site B to the mail server on site A, using telnet to port 110 or 25; I get conection refused and put a sniffer to get all packages from tun interface on site B and there isn’t packages going through the tunnel when telnet is trying.

Thanks for your quick answer.

Sébastien Wains

June 19, 2009 - 18:48

Please sniff on each end. Try to telnet into SMTP and send me the output. Also provide me with your range info (LAN + VPN).

David Piedra

June 19, 2009 - 19:34

thanks for all your help!!!
The firewall on both sides are allowing everything pass though!!

Lan config
Site A 130.0.0.0/24
Site B 130.0.1.0/24

VPN
Site A 10.0.0.0
Site B 10.0.1.0

Mail Server 130.0.0.252

Telnet from 130.0.1.17

$ telnet 130.0.0.252 25
Trying 130.0.0.252…
telnet: Unable to connect to remote host: Connection refused

Sniff Site A
:/ home/computo# tshark -i tun0
Running as user “root” and group “root”. This could be dangerous.
Capturing on tun0
tshark: arptype 65534 not supported by libpcap – falling back to cooked socket.

Sniff Site B
:~# tshark -i tun0
Running as user “root” and group “root”. This could be dangerous.
Capturing on tun0
tshark: arptype 65534 not supported by libpcap – falling back to cooked socket.

Leave Comment

Please consider visiting the partners below if you enjoyed this article :

If this post saved you time and money, please consider checking my Amazon wishlist.

Before submitting, some rules :
- Is your comment related to the article ?
- You're having a problem ? Have you checked Google, other howtos, docs, manpages ?
- You're still having the problem ? Have you raised log verbosity, checked traces, ran tcpdump ?
- Have you checked your configuratoin for typo ?
Unless your comment is providing additional info or respect the rules above, DON'T comment.
If you don't understand what you are doing, I urge you to read the documentation, I'm not your free Level 1 helpdesk guy.