Link two private networks using a VPN on Ubuntu Linux machines each behind NAT

http://blog.peter-b.org/2010/12/16/link-two-private-networks-using-a-vpn-on-ubuntu-linux-machines-each-behind-nat/

Link two private networks using a VPN on Ubuntu Linux machines each behind NAT

Might seem like a stretch, but clearly given the number of people asking the question out on the internet this is common enough. And I wanted to do it, so…..

The scenario. You have two private , home.local which is 192.168.0.0 netmask 255.255.255.0 and office.local numbered 192.168.1.0 netmask 255.255.255.0. They’re regular private connected to the internet via ADSL with routers of some description or other – could be the freebies that come from the service provider, or something you bought or built yourself. Either way it’s likely to be running NAT at the very least, possibly with some firewall as well, but for whatever reason, you can’t make these do the for you (if you can, you should – it’s by far the simplest route).

On each network there’s an machine that’s on all the time for whatever reason, and you figure you can use these to connect the two networks together somehow.

Good news, you can.

Please remember that connecting two networks like this has security issues. Unless you also run firewalls on the Ubuntu machines that run the VPN each network is only as secure as the other, so if one network was “more secure” than the other suddenly it will become less secure! Make sure that you own both networks, or if you don’t that you have the permission of whoever owns the remote network to do this and that you trust the remote network not to connect to your home Samba share and steal or delete all your music (but of course, you set up Samba so that can’t happen, right?).

Also note that if the two networks are not numbered differently – i.e. they’re both 192.168.0.0 netmask 255.255.255.0 – then you’re going to run into a whole mess of trouble. If this is the case, consider looking at a “Bridged VPN” that will make it seem like one big network (though if you do you’re going to run into a real whole mess of trouble as IP addresses must be unique across both networks!). Bridged VPNs are a whole other topic, and not covered here.

There are plenty of sites that will tell you how to set up the actual VPN, for example here and here to name just two. But they don’t really talk about anything other than the actual VPN itself and the basic between the two machines.

First things first, you need some way to look up the external IP of each network. This means registering with some kind of DNS service. If you’re lucky enough to have your own server out on the internet you can use a script to find out what your external IP is and use nsupdate to register this with your DNS server on the internet.

If not, there are plenty of “Dynamic DNS” services out there that can do this.

Ok, so you have your networks successfully registering with a DNS server somewhere out on the internet. Now you can create the actual VPN.

I like Sébastian Wains’ solution best as it doesn’t require configuration of the routers to open NAT ports etc. (but you might need to set some routes, more later).

So, the setup so far:

  • Private Network 192.168.0.0
  • Local DNS suffix is home.local
  • Ubuntu box is 192.168.0.23 and called ubuntubox.home.local
  • Registers with DynDNS as myhomenetwork.dyndns.org
  • Private Network 192.168.1.0
  • Local DNS is office.local
  • Ubuntu box is DHCP assigned IP (today it’s 192.168.1.57) and called myubuntu.office.local
  • Registers with a private dns service as office.mycompany.com

The private IP addresses of the machines don’t matter too much for the VPN configuration but it’s handy to know what they are for testing and diagnostic purposes and you will probably need them for routing purposes later.

The following assumes you have root access; use sudo/su as required.

First, you need to install openvpn by running the following on both computers:

apt-get install openvpn

Then you need a pre-shared key for securing the VPN. On ubuntubox.home.local run:

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

You need to copy this file from one machine to the other some way. They must be identical on both machines. Best not to use email! Cut and paste over an SSH link or copy using a USB key or something similar.

Once this is done you can create the actual VPN:

On computer ubuntubox.home.local in /etc/openvpn/office.mycompany.com.conf:

remote office.mycompany.com
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/static.key
route 192.168.1.0 255.255.255.0
chroot /var/empty
user nobody
group nogroup # Nobody on RedHat, but we're on Ubuntu, right?
log vpn.log
verb 1

On computer myubuntu.office.local in /etc/openvpn/myhomenetwork.dyndns.org.conf:

remote myhomenetwork.dyndns.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/static.key
route 192.168.0.0 255.255.255.0
chroot /var/empty
user nobody
group nogroup # Nobody on RedHat, but we're on Ubuntu, right?
log vpn.log
verb 1

You’ll need to create ‘/var/empty’ if it doesn’t already exist. Then restart the VPN on each machine:

/etc/init.d/openvpn restart

At this point you should be able to ping each machine from the other, for example:

ubuntubox# ping -c1 192.168.1.57
PING 192.168.1.57 (192.168.1.57) 56(84) bytes of data.
64 bytes from 192.168.1.57: icmp_seq=1 ttl=64 time=100 ms
--- 192.168.1.57 ping statistics ---
1 packets transmitted, 1 received, 0% packet loss, time 0ms
rtt min/avg/max/mdev = 100.456/100.456/100.456/0.000 ms

As you can see, all works great. If it doesn’t work, you should at least be able to ping both 10.0.0.1 and 10.0.0.2 from both machines. These are the addresses at the ends of the VPN tunnel. If that doesn’t work, then the tunnel doesn’t even exist. Check /etc/openvpn/vpn.log to find out why, often it’s because it can’t reach the remote host (lookup of office.mycompany.com for example).

If you can ping 10.0.0.1 and 10.0.0.2 but can’t ping the IP of the remote machine then it’s the routes that are broken. These are set up automatically thanks to the “route 192.168.0.0 255.255.255.0″ and “route 192.168.1.0 255.255.255.0″ lines in each of the configuration files. Check these first and restart the VPN if you need to make changes.

The routes should look something like:

ubuntubox# netstat -rn
Kernel IP routing table
Destination     Gateway         Genmask         Flags   MSS Window  irtt Iface
10.0.0.1        0.0.0.0         255.255.255.255 UH        0 0          0 tun0
192.168.1.0     10.0.0.1        255.255.255.0   UG        0 0          0 tun0
192.168.0.0     0.0.0.0         255.255.255.0   U         0 0          0 eth0
0.0.0.0         192.168.0.254   0.0.0.0         UG        0 0          0 eth0

This shows that anything destined for ip address 10.0.0.1 (the remote end of the VPN tunnel) will go down the tun0 interface, anything destined for network 192.168.1.0 (the office.local subnet) will be directed to 10.0.0.1 (therefore down the tunnel), anything for 192.168.0.0 (the home.local subnet, the one we’re actually connected to) will go out the local ethernet port, and that anything else (0.0.0.0) will go to whatever is connected to 192.168.0.254 – this ideally is the address of your ADSL router or similar device.

If you can ping both 10.0.0.x addresses but can’t ping the other machine’s IP address then check your /etc/openvpn config files that the “route” lines are correct, and check that there aren’t conflicting routes configured somewhere else on your machines.

So now that’s all working. But what about all the other machines on the network? You want everything on each side to reach everything else no?

Well, yes. So first off, you need to turn on IP forwarding on both machines. By default this is turned off, specifically to prevent information from one network “polluting” another.

To do this, on each machine type:

sysctl -w net.ipv4.ip_forward=1

To make this permanent across reboots you also need to edit /etc/sysctl.conf on both machines and make sure that there’s a line that looks like:

net.ipv4.ip_forward=1

Often this is simply commented out, though sometimes it says ‘=0′ rather than ‘=1′.

The last bit is tricky as a lot depends on your default routers. Remember that in ‘netstat -rn’ there’s a last route that looks like ’0.0.0.0′ (this is sometimes labelled ‘default’)? This is the IP address of the device that receives anything not destined for any of the other routes. Chances are that everything on your network sends anything not destined for the local private network to this IP address.

You have two choices at this point:

  1. You need to configure whatever device is using that IP address with two ‘static routes’ for the remote network and the tunnel address. Most routers will let you do this in their web interface.
  2. Configure everything on each network to use the local Ubuntu box as the default route – this is usually specified in the settings of your DHCP server as the “default gateway”, or possibly individually in the network configuration of every device on your network.

Option 1 is the simplest, assuming the router has the ability to let you do it. Option 2 may be easier but is not ideal, as everything will rely on your Ubuntu box for their internet connection and your Ubuntu box will be working a bit harder!

Remember, you need to do this on both networks, and you need to set routes for 192.168.x.0/255.255.255.0, 10.0.0.1 and 10.0.0.2. Why?

Assume all the routes are properly configured:

Let’s say machine 192.168.0.16 wants to ping 192.168.1.12. The default route on network 192.168.0.0 is for whatever is connected to 192.168.0.254 (and 192.168.1.0 it’s 192.168.1.254).

Assuming everything is set up correctly 192.168.0.16 will send a packet destined for 192.168.1.12 to 192.16.0.254 – the default route. This device knows that it must forward anything for 192.168.1.x to your Ubuntu box as you gave it a static route. So, it then forwards the packet for 192.168.1.12 on to 192.168.0.23 – your Ubuntu box ubuntubox.home.local.

Thanks to the VPN your Ubuntu box knows to send this packet down the tunnel to 10.0.0.1. The office Ubuntu box then forwards this on directly to 192.168.1.12, however at this point the originating IP address of the packet is no longer 192.168.0.16, it’s 10.0.0.2 – the IP address of the end of the tunnel on ubuntubox.home.local! So when 192.168.1.12 receives the packet and wants to send a reply, it’s going to send it to 10.0.0.2. This is why you need the extra static routes. Use ‘tcpdump’ to watch ping requests across the VPN and you’ll see what I mean.

In my case I chose option 1. So, I logged on to the routers 192.168.0.254 and set up a static route for 192.168.1.0 netmask 255.255.255.0 to point to 192.168.0.23 and for 10.0.0.1 netmask 255.255.255.255 to 192.168.0.23.

Then I logged on to the router at 192.168.1.254 and set up a static route for 192.168.0.0 netmask 255.255.255.0 to point to myubuntu.office.local and for 10.0.0.2 netmask 255.255.255.255 to myubuntu.office.local. I see you noticed the hostnames. Why the hostname and not the IP? Remember, myubuntu.office.local is configured using DHCP and so the IP address may change. If your router forces you to use the IP address make sure it’s a static IP address and not assigned via DHCP, as if the address changes for some reason your shiny VPN will break!

If what you’re configuring doesn’t like the host specific 10.0.0.x routes you can specify a route of 10.0.0.0 netmask 255.255.255.0 (yes I know this is bad behaviour, but it works) – this will obviously cause problems if you have anything that uses the 10.0.0.0 subnet! You can change these addresses and network numbers to suit your requirements though, just remember to change them in both config files and both default routers!

That’s it. You can now access any IP on either network from any IP on the other network.

Of course, you now have the issue of DNS. Set up a forwarding zone on the DNS server on each network using the IP address of the DNS server on the remote network in each case so that requests for the remote network are forwarded to the DNS server for the remote network. But that’s a whole other topic!

This entry was posted in Technical Tirades and tagged , , , by Peter. Bookmark the permalink.

3 thoughts on “Link two private networks using a VPN on Ubuntu Linux machines each behind NAT

  1. David Valentine on September 3, 2011 at 5:45 am said:

    I just tried out this guide today, and I was successful in connecting my two home networks together. Thanks for the well written advice!

    Two minor mistakes that I found were:
    – Left out .conf at the end of the line: “On computer myubuntu.office.local in /etc/openvpn/myhomenetwork.dyndns.org:” ie. it should read: “On computer myubuntu.office.local in /etc/openvpn/myhomenetwork.dyndns.org.conf:”
    – A config thing really, in the latest version of Ubuntu 11.04 there is no /var/empty directory. So you need to run the command “sudo mkdir /var/empty” on each server.

    Thanks again for the detailed guide. Now I can connect to my samba share and printers from either of my home networks!

    ~David

  2. Pingback: David and Claire’s Blog»Blog Archive » Link two private networks using a VPN on Ubuntu Linux machines each behind NAT

Also see: http://www.debian-administration.org/articles/35

YOUTUBE: http://www.youtube.com/watch?v=C_B9k0l6kEs


Tag Cloud