Google Site SearchFN Site Search FN Blog Login FN Blog Login
Site Navigation:
 
 

Implementing OpenVPN

by Florin Andrei on Mar 26, 2004

1. The many ways of VPN

Essentially, there are three ways to implement a VPN:

  1. A proprietary solution, using an appliance-like VPN server, such as Cisco VPN, based on IPSec
  2. An Open Source implementation of IPSec, such as FreeS/WAN
  3. A non-IPSec VPN, like OpenVPN

The proprietary solutions, such as Cisco, are scalable, you usually get good support and are pretty well documented. On the other side, they can be extremely expensive (unless you choose to cheat and combine the VPN function into an existing firewall or similar device, which is pretty bad from several points of view); also, proprietary solutions tend to lock you into whatever features the vendor provides - if you want to (or have to) deviate even a little bit from the One True Way, you can easily be left in the dust.

The Open Source implementations of the IPSec protocol are nice because they are able to interoperate with pretty much any other IPSec-based VPN; being Open Source, they are also cheap. On the other side, if you try to implement such a solution, like FreeS/WAN for example, you will face significant issues:

  • there is no good and free IPSec VPN client for Windows; if you don't use a commercial VPN client, you'll have to go through an extremely convoluted procedure to setup a Windows client
  • IPSec is not exactly a firewall-friendly protocol, especially in NAT environments; often, your customers will fail to connect to the VPN server just because some firewall in between decided it doesn't like your connection :-)

Enter OpenVPN - http://openvpn.sourceforge.net/:

  • it is an Open Source VPN software, hence it's free
  • it works on Linux as well as on Windows, but also on Solaris, BSD, etc.
  • installing a client, especially on Windows, is very simple
  • it is trivial to automate the client, hence it works very well when the client is not a workstation controlled by a human, but it's an isolated appliance (or kiosk) in a remote place
  • it is not only firewall-friendly, but it is able to actually circumvent firewalls when clients are in restrictive environments (by using HTTP proxies to tunnel the VPN connection)
  • has sophisticated and intelligent compression algorithms that can save bandwidth on your VPN connections
  • can perform traffic-shaping to limit the bandwidth usage on a given tunnel
  • does not have problems if clients are on DHCP networks and change their address while being connected
  • has a rich and flexible palette of encryption schemes that include popular strong-crypto algorithms, based on the OpenSSL library (it's using the SSL API to perform the encryption)

There is usually one thing that people get wrong when they hear about OpenVPN: even though it's based on SSL, it is not a browser-based pseudo-VPN; instead, it is a full-blown VPN solution, that can tunnel any arbitrary protocol. You can even ping through it, and a browser is not required at all. Functionally, it is a perfect equivalent to Cisco VPN or FreeS/WAN, except the fact that the encryption is not based on IPSec, but instead it encapsulates the IP packets in a tunnel encrypted with SSL. Let's say it's a "free form" implementation of SSL that happens to be able to tunnel arbitrary IP traffic.

2. The problem

Let's consider a practical situation that requires a VPN solution. The diagram below illustrates a typical small-company network. There's a Linux firewall in the middle that creates an intranet on the private address space 192.168.1.0/24 (painted red) and a DMZ on the public address space 222.111.222.0/24 (painted blue). The firewall's outside interface has the address x.y.z.k. The intranet has workstations and such, the DMZ has the webservers, a few mail servers, etc.

At some point, the management desires to connect several remote systems (painted green) to the internal network, using VPN. There are several ways to accomplish that; we will show you how to accomplish that by adding VPN functionality to the Linux firewall, using OpenVPN.

3. The solution

We will assume that the Linux firewall is running Fedora Core 1, although other Linux distributions should be similar. Of the many encryption schemes offered by OpenVPN, we will use the one based on preshared static keys; while the method based on RSA certificates has a slight advantage on the crypto side, static keys are much more simple to deploy and are not measurably weaker under normal circumstances.

Download the LZO libraries from freshrpms.net. The website offers both binary RPM packages (install them directly) and src.rpm packages (which you can rebuild). Install the binary LZO packages (both the main package and the devel-).

Download the latest OpenVPN software and generate the binary RPM package. It is generally o.k. to use "pre" or "beta" versions of OpenVPN, the software seems remarkably stable even when in beta stage.

rpmbuild -tb openvpn-1.6_rc3.tar.gz

Install the binary RPM once it's done.

There are two types of tunnels that can be established with OpenVPN: Routed IP Tunnels, and Bridged Ethernet Tunnels.

The Routed IP Tunnels mode is more efficient and easier to setup. However, it cannot provide the VPN clients with addresses in the same network as the IP range used on the intranet, but it must use a different range for them.

The Bridged Ethernet Tunnels mode is more difficult to setup and is less efficient, however it is able to assign to the VPN clients addresses in the same range as the intranet; this is good for simple Windows networks that do not use WINS, because it allows the Windows machines to "see" each other, even if they reside on the opposite ends of a VPN tunnel (the VPN clients can "see" Windows shares on the internal network, and viceversa).

The first method is covered in the OpenVPN HOWTO. We will describe here the second one: Bridged Ethernet Tunnels.

We will assume that the internal interface of the firewall (the one facing the Intranet) is eth1. You will have to configure that interface so that it does not have an IP address; instead, you will configure a bridge interface br0 on it that has the same address. On top of that, you'll create several TAP interfaces, one for each VPN client.

I made a script that does all that for you. You don't have to modify the settings for eth1, the script will read the settings and perform all configuration bits. The script assumes there will be no more than 16 VPN clients connected to the firewall (you can change that with the maxtap variable).

#!/bin/bash
#
# Replace eth1 with TAP/bridge interfaces
#
# chkconfig: 2345 11 89
# description: Create TAP/bridge interfaces
                                                                                                                                                                       
. /etc/rc.d/init.d/functions
                                                                                                                                                                       
start() {
maxtap=15
. /etc/sysconfig/network-scripts/ifcfg-eth1
                                                                                                                                                                       
echo "Create TAP/bridge interfaces:"
modprobe tun
modprobe bridge
                                                                                                                                                                       
ifconfig eth1 down
for i in `seq 0 ${maxtap}`; do
    openvpn --mktun --dev tap${i}
done
sleep 1
brctl addbr br0
brctl addif br0 eth1
sleep 1
for i in `seq 0 ${maxtap}`; do
    brctl addif br0 tap${i}
done
sleep 1
for i in `seq 0 ${maxtap}`; do
    ifconfig tap${i} 0.0.0.0 promisc up
done
sleep 1
ifconfig eth1 0.0.0.0 promisc up
sleep 1
ifconfig br0 ${IPADDR} netmask ${NETMASK} broadcast ${BROADCAST} && success || failure
RETVAL=$?
sleep 1
echo
}
 
stop() {
    echo "TAP/bridge fake shutdown (we never stop)"
    RETVAL=$?
    success
}
 
case "$1" in
        start)
                start
                ;;
        stop)
                stop
                ;;
        restart)
                stop
                start
                ;;
        *)
                echo $"Usage: $0 {start|stop|restart}"
                RETVAL=1
esac
exit $RETVAL

Name the script eth1-replace and put it in /etc/init.d then make it active:

chkconfig --add eth1-replace

At every reboot, the script will reconfigure eth1 to be in IP-less mode, will create the bridge and TAP interfaces, will load appropriate kernel modules, etc., all that transparently and in a fashion that's compatible with Fedora network configuration files.

Create a group openvpn and a user named openvpn that belongs to that group. Create a directory /var/log/openvpn then change its ownership to openvpn:openvpn.

Make sure to configure your iptables firewall so that it is compatible with OpenVPN, according to the OpenVPN HOWTO.

At this moment, the machine is ready for you to start creating VPN accounts on it.

4. Server-side configuration

Create the server-side configurations required to connect the user John Doe to the VPN server.

One current limitation of OpenVPN is that it needs one UDP port on the server for each client that's registered with the server; there's also one openvpn daemon for each registered client. This effectively limits the number of clients you can register with one OpenVPN server to approx. 1000 or something like that. Future versions of OpenVPN will remove this limitation, for the moment you have to deal with it (the limit is actually pretty high, so most users don't have to worry about that).

Choose a username for this new user/client:

export user=johndoe

Go to the /etc/openvpn directory; from now on all operations will be performed in that directory:

cd /etc/openvpn

Create the shared key for the user:

openvpn --genkey --secret $user.key

Before creating the configuration for a new client, you have to choose the UDP port that the client will connect to. Don't forget to assign a unique port for each new client. Suppose the port number for this user is 5000. Then create a file named $user.conf (different names for different users, and the extension .conf is critical) with a content similar to this:

# Linux VPN server config file
# These settings are different for each user
port 5000
dev tap0
secret johndoe.key
log-append /var/log/openvpn/johndoe.log
# These settings are the same for all users
local x.y.z.k
fragment 1400
mssfix
ping 10
ping-restart 35
ping-timer-rem
persist-tun
persist-key
persist-local-ip
comp-lzo
comp-noadapt
user openvpn
group openvpn
verb 4

The first 4 parameters (port, dev, secret and log-append) will be different for each user/client. "dev tap0" uses the first TAP interface created by /etc/init.d/eth1-replace; next user/client will use the next one (tap1) and so on.

The next parameters are the same for all users. x.y.z.k is the external IP address of the firewall. Delete comp-noadapt if you want smart, adaptive compression on the VPN tunnels.

5. Client-side configuration

I'm assuming that the clients are all Windows machines. If the clients are Linux machines, the configuration should not be very different from the server, although probably much simpler, so i won't describe it here.

On each client, download and install the Windows version of OpenVPN. Get the $user.key file from the server and put it in C:\Program Files\OpenVPN\config. In the same directory, create a file named $user.ovpn (the extension .ovpn is important) with the following content:

# Windows VPN client config file
# These settings are different for each user
port 5000
secret johndoe.key
ifconfig 192.168.1.252 255.255.255.0
# These settings are the same for all users
remote x.y.z.k
route 222.111.222.0 255.255.255.0 192.168.1.254
route-delay 10
dev tap
tap-sleep 1
fragment 1400
mssfix
ifconfig-nowarn
ip-win32 dynamic
ping 10
comp-lzo
comp-noadapt
verb 4

The port should be the same with the setting on the server. ifconfig assigns the client an IP address in the address space of the intranet. remote is the outside IP address of the firewall. The route statement assigns a static route to the DMZ through the VPN tunnel; 192.168.1.254 is the internal address of the firewall, which is a gateway for this route. Don't use the route statement if your network doesn't have a DMZ or you don't want to provide access to the DMZ for this particular system.

On Windows, OpenVPN is a service, so you can control it from Administrative Tools / Services. Or you could create a VPN-Start.bat file containing the "net start openvpnservice" command, and a VPN-Stop.bat file containing the "net stop openvpnservice" command and put them on the Desktop and click on them when you want to start/stop the VPN tunnel.

6. Conclusion

Read the OpenVPN HOWTO and the rest of the documentation on the OpenVPN site. The mailing list is helpful, but make sure you searched the docs before asking a question on the list.

OpenVPN is rock solid under typical conditions. The tunnels stay up indefinitely, there are no unexpected glitches, and the software seems to scale pretty well - it will saturate your Internet connection long before you run out of CPU cycles on the VPN server, even when using non-adaptive compression.

When compared to FreeS/WAN or other IPSec-based VPNs, it's easier to setup, it's a lot less sensitive to interactions with firewalls and NAT, it uses the well-known and widely tested OpenSSL library, and has many other useful features. It is highly recommended, both for private usage and commercial applications.