How to bridge networks with OpenVPN

5352

For this setup I’ll assume that you have two networks, A and B, in different locations, both connected to the Internet with broadband. At each location you will need a Linux system acting as a router/firewall to serve as the VPN end point. I’m using two Asus WL-500G Deluxe routers running OpenWRT RC5 — a Linux distribution for embedded routers — but you’re free to use the hardware and distribution of your choice. You can use one of the BSDs, Mac OS X, or even Windows; check the documentation on OpenVPN’s homepage for a list of supported operating systems. If your use OpenBSD, have a look at the article Creating secure wireless access points with OpenBSD and OpenVPN.

The networks on both locations must use the same subnet — for instace, 192.168.0.0/24 — and in order to avoid conflicts, each computer at any location should have its own private IP address. A good practice is to use, for example, IP addresses 192.168.0.1 through 192.168.0.100 for computers on network A and 192.168.0.101 through 192.168.0.200 for network B. Reserve the range 192.168.0.201 through 192.168.0.254 for the routers and other network devices. In this example, the router on network A (routerA) will have the IP address 192.168.0.253 and will be the server for the VPN, while the router on network B (routerB) will have the IP address 192.168.0.254 and will be the client.

This setup runs OpenVPN in bridging mode, so you need to bridge the local network interface with the virtual interface tap0 used by OpenVPN on both routers. Issue openvpn --mktun --dev tap0 to create the tap0 interface, then run brctl addbr br0 to create the bridge and brctl addif br0 eth0; brctl addif br0 tap0; ifconfig tap0 0.0.0.0 promisc up to add the local network interface eth0 (replace with your interface) and tap0 to the bridge and bring tap0 up. Each distribution has its own way of configuring network bridges; see the article Create a secure Linux-based wireless access point for bridging on Debian.

Now you need to create SSL certificates. It’s good security practice to use a separate computer for this purpose, and preferably one not connected to the Internet. OpenVPN provides scripts (called easy-rsa) to facilitate the procedure, so it’s just a matter of answering a few simple questions. The creation of certificates is described in the PKI part of OpenVPN’s How-To, so I’ll just provide a list of the steps necessary for creating the required certificates:

cd /usr/share/doc/openvpn/easy-rsa (might be different on your distribution)
. ./vars
./clean-all
./build-ca
./build-key-server routerA
./build-key routerB
./build-dh
openvpn --genkey --secret keys/ta.key

On routerA, create the directory /etc/openvpn/keys by issuing mkdir -p /etc/openvpn/keys and copy the files ca.crt, dh1024.pem, routerA.crt, routerA.key, and ta.key that you created earlier to that directory. Do the same thing on routerB, copying instead the files ca.crt, routerB.crt, routerB.key, and ta.key. Also create the directories /etc/openvpn/chroot/ccd on routerA and /etc/openvpn/chroot on routerB. Paste the following lines into the file /etc/openvpn/server.conf on routerA:

mode server
proto udp
port 1194
dev tap0
keepalive 10 120
daemon
writepid /var/run/openvpn.pid
comp-lzo
max-clients 10
user nobody
group nogroup
persist-key
persist-tun
verb 3
mute 20
client-to-client
duplicate-cn
cd /etc/openvpn
tls-server
tls-auth keys/ta.key 0
cipher BF-CBC
ca keys/ca.crt
cert keys/routerA.crt
key keys/routerA.key
dh keys/dh1024.pem
chroot chroot
client-config-dir ccd

Paste the following lines into /etc/openvpn/client.conf on routerB, replacing 1.2.3.4 with routerA’s public IP address. If you don’t use an Internet connection with static IP addresses, you can use a dynamic DNS service, such as DynDNS, instead.

client
proto udp
dev tap0
remote 1.2.3.4 1194
resolv-retry infinite
nobind
persist-key
persist-tun
ns-cert-type server
comp-lzo
daemon
writepid /var/run/openvpn.pid
verb 3
mute 20
user nobody
group nogroup
cd /etc/openvpn
ca keys/ca.crt
cert keys/routerB.crt
key keys/routerB.key
tls-auth keys/ta.key 1
chroot chroot

OpenVPN will drop its privileges to user nobody and group nogroup and will chroot to the directory /etc/openvpn/chroot as soon as it initializes, for better security. Since the VPN will run over the Internet, it’s a good idea to use LZO compression to save some bandwidth, so unless you have really fast Internet connections you should leave the comp-lzo parameter as it is. You can find explanations about the other options used in the configuration files on the openvpn man page.

Make sure that routerA accepts UDP connections from the Internet on port 1194; if you use iptables, run iptables -A INPUT -i WAN -p udp --dport 1194 -j ACCEPT, replacing WAN with your router’s interface that’s connected to the Internet. Start the OpenVPN daemon on routerA with openvpn --config /etc/openvpn/server.conf and on routerB with openvpn --config /etc/openvpn/client.conf. Now you should be able to connect to hosts on network B from hosts on network A and vice versa. If you have any problems, set the verbosity level, verb, to 9 in your configuration files and check the system logs.

To have OpenVPN start automatically on boot you can use your distribution’s init scripts or just add the commands you issued before to initialize the bridge and run the openvpn daemon to your rc.local file. If you use OpenWRT, create /etc/init.d/S70openvpn on both routers and paste the following into the file:

#!/bin/sh

case "$1" in
  stop)
    kill `cat /var/run/openvpn.pid`
    ;;
  *)
    if ! brctl show | grep -q tap0; then
      openvpn --mktun --dev tap0
      brctl addif br0 tap0
      ifconfig tap0 0.0.0.0 promisc up
    fi
    openvpn --config /etc/openvpn/server.conf (replace with client.conf in routerB)
    ;;
esac

Make that file executable, with chmod 755 /etc/init.d/S70openvpn.

Recently I installed a system like this for a small company that wanted to connect its branch office to its headquarters. The company’s owner is more than happy with OpenVPN’s performance and security, but he’s happier because he could upgrade their IT infrastructure to meet their needs without spending a fortune on proprietary VPN systems.