Cover V12, I03

Article
Figure 1
Figure 2
Figure 3

mar2003.tar

Easy-to-Use VPN Connections with vpnd

Bill Davidsen

Because I frequently work over network connections and have helped various groups set up VPN installations over the open net, I have been painfully aware that many examples of VPN are complex to install and require patching the kernel to provide functionality. I was therefore interested in the vpnd program that is included with recent Red Hat releases and available in source for any UNIX distribution. It runs in user mode without kernel patches and is trivial to set up. In practice, it has proven reliable, even when used by non-technical users.

Overview of vpnd

A VPN (Virtual Private Network) is a substitute for a dedicated link between systems. If those connected nodes do routing, then full seamless connectivity is available. vpnd provides this by sending network packets in compressed and encrypted form over a socket. Because it runs in user space without special kernel support, it is inherently portable. Although I first used it as a Linux solution, FreeBSD is also supported, and I think Solaris would support this application as well.

How It Works

A vpnd process is started as a daemon on the server node. This will listen for connections, by default on port 379. The client node starts a vpnd process configured as a client, and the two processes with matching configuration files will be able to connect.

The client and server daemon processes establish an SL/IP link between the nodes. This link is used to communicate between the nodes, transparently passing encrypted packets. With suitable routing support, this can be used as a full connection between the local networks of each vpnd node, allowing access as if the two local networks were physically connected through a router.

Configuration Process

Configuration is easy -- only a few lines in a heavily commented config file need be defined, and most of those have usable optional values. The client and server configuration are almost identical, and for each server a key must be generated once on the server and installed on both the server and client machine(s). For the simple case of one client connecting to one server, all the files may be left in their default locations, and most of the default values will work without change.

Server Configuration

For this example server, which is used in several ways, I changed only nine values in the config file, and for some of those the default value would have worked. The full list of changes, shown as a diff file between the sample and what I actually run, is shown in Figure 1. Following is the list of things I changed on the server and a discussion of each change. For quick reference, just the list of parameters defined appears in Figure 2, showing how little configuration is actually needed with this software.

This is what I changed:

+ pidfile /var/run/vpnds1.pid -- The pidfile is a file containing the PID of the process running vpnd. If you don't define this value, no file will be created. However, I wanted to be able to track the daemon easily, so I specified a file in /var/run. This file is deleted when the daemon terminates.

+ randomdev /dev/urandom -- This is the name of the device that provides random numbers to the encryption. The default value of /dev/random will work, but on a lightly used system may be very slow, because it generates data based on system events. There is a discussion of security and devices in both the documentation README file and the config file comments (this software is very well documented).

+ keepalive 20 and + noanswer 6 -- These parameters control how often the daemon sends a keepalive ping to the client and how many pings must go unanswered before the connection is declared dead. The client is expected to reestablish the connection when (or if) it dies, and there is a discussion of this process in the documentation as well. The default values may be appropriate for a dialed connection between modems, but I felt they were overly paranoid and might reset when network congestion introduced a temporary problem.

The keepalive is the time in seconds between pings, and the noanswer value is the number of unanswered pings that cause a connection reset. This server has a dedicated connection and rarely goes away, so I didn't want to dedicate much bandwidth to pings. When a failure occurs, it's usually caused by broken lines or cars trying to climb utility poles. In those cases, the outage will be hours rather than seconds, so a speedy retry is unlikely to be beneficial.

+ mode server -- The mode setting must be either client or server. This controls which branch of the setup code is used.

+ client 0.0.0.0 0 -- This setting is required, as is the IP and port number of the client. If they are set to zero, any connection is accepted. This setting allows the server to accept connections from a single static IP address -- better than nothing if no firewall is being used, and useful if a server is to be dedicated to a single client. By setting the IP zero and the port to a known value, a small degree of additional security is available even when the client is using an unknown IP, such as DHCP-assigned connections.

+ server 0.0.0.0 24741 -- In this case, I have my server listening on any IP address, on port 24741. The default port is 379, and in most cases is satisfactory; the port chosen is an example only. It might be used to run the daemon as a non-privileged user; I have not tested doing that, but it appears to be possible.

Note that if an IP is given, it is possible to listen on a single address rather than on all configured IP addresses. This may be useful if several servers are configured against IP addresses provided by aliases on a single physical network device, or if there are addresses on several subnets, each on a separate network interface.

+ keyfile /etc/vpnd/vpnd.conf-server1 -- The keyfile holds the key used to start the connection. There is a default location, and it is perfectly satisfactory for most applications. The server I used for this article actually supports several vpnd configurations, so all config files were moved to /etc/vpnd and given more descriptive names.

+ local 192.168.202.2 -- This is the address of the local end of the SL/IP link. It should be chosen to avoid conflict with any other IP addresses in use at either end. If the connection is made over a network connection, it should not be the IP configured on an NIC at either end.

+ remote 192.168.202.1 -- This is the IP of the "other end" of the SL/IP link. The local and remote IP addresses are swapped between the client and server, since the client "local" is the server "remote" and vice versa.

Routing on Startup

If the VPN connection is only to be used as a link between two systems, the route to the remote system will be created by the kernel (Linux 2.2 or later, or FreeBSD). If additional routing is needed, up to nine additional routes may be specified in the configuration file created when the link is established. Note that adding routes requires root privilege; if you want to try running this as a normal user, this feature will not be available. Also see the section on startup scripts in the client configuration.

The format of a route directive is:

# route1 <destination-ip> <netmask-in-dot-notation> <gateway-ip>
where route1 to route9 commands may be included in the config file. This can be used for individual hosts, or more commonly for a subnet. In the case of the server used, for example:

route1 192.168.203.0 255.255.192.0 192.168.202.1
This says I routed through the VPN to 192.168.203.0 through 192.168.203.63, a 6-bit subnet. If I want to route an entire class C (old nomenclature) network, it might look like:

route2 192.168.202.0 255.255.255.0 192.168.202.1
Hosts with individual routes, such as the ends of the SL/IP link, would still be routed individually.

Client Configuration

The client configuration can be almost identical to the server, other than setting the mode to client and interchanging the values of the local and remote IP address definitions. The values defined for the example client configuration are shown in Figure 3.

There are two differences between these client settings and the server settings previously discussed, besides the required changes already noted. The first change is that I now provide the IP of the server to which I need to connect, instead of providing zeros. The server IP value on the server itself is the IP on which the server listens, with zeros meaning "any". On the client, however, it is the IP to which the daemon connects. Note that the IP shown has been munged to avoid accidental use of the example server.

The second change is the use of the linkup directive to identify a script that needs to be run when the link starts. In this case, the script contains a complex routing setup, which can't be handled by the simple route statements I described earlier.

The linkup script can perform any initialization required, not just routing. In the case of a "moving target", such as a laptop going to various locations, the startup might involve fetching any mail waiting and sending any mail queued for the home office. It could also include some backup of critical files, updates of shared calendars, or anything else needed. There is a corresponding linkdown parameter used when the link is terminated.

Other Features

There are some advanced features that I should mention, which make vpnd even more versatile. These are useful for applications where the VPN cannot be established over an available network connection and a dialed connection must be used, or where there are some other special problems or data content on the link.

Use Between Dial-Up Sites

While connection via dialed circuit is growing less common, vpnd does support dial or direct connected serial cable use. In the case where a serial connection is used, with or without a modem, the IP address in the client and server specifications is replaced with a device name, which is the device name of the serial port.

These are most of the features needed for establishing a dialed connection.

+ slipup <name> and + slipdown <name> -- These are the names of scripts to be run when the connection is established or terminated.

+ speed <serial bitrate> -- This sets the speed of the serial line, which defaults to 115200. Clearly this isn't magic, the hardware and driver must support the speeds selected.

+ localline and + nortscts -- These disable modem control hardware signaling, and RTS/CTS flow control, respectively. Use nortscts with care on a direct connect; data loss is possible, particularly at speeds higher than 115200.

+ xfilter -- This escapes flow control characters XON and XOFF. It's used primarily when a modem or other part of the communication link responds to this as flow control.

+ modemchat <script> -- This defines a chat file to be used to establish modem state. There is a well-commented example file in the package, which should be adequate to provide connectivity with many modems using the AT command set.

Tuning the Connection

There are a few parameters that allow tuning the connections to optimize the behavior for various types of traffic. These are a few of the parameters that are generally useful.

+ ipopts <type-of-service-and-precedence-flags> -- An optional specification. This is described in the comments as a combination (sum of values used) of the following values:

1 high reliability type of service

2 high throughput type of service

4 low delay type of service

8 priority precedence

The comments also contain this warning: Please keep in mind that nearly all routers do ignore these settings so except for very special environments you won't gain anything.

+ sendbuf <size> -- The send buffer is used for data compression. Making this buffer larger, perhaps 4K, will help throughput if the connection is slow, such as a modem link. It is unlikely to help if you are moving a lot of compressed data, because it won't compress further in most cases. If you are running an X session over a slow link, this may make a great improvement.

Security

All data is encrypted in the VPN. The common key is used only to establish a session key, which is then used for the actual traffic. The length of the key may be set by user option, and the encryption is done using the blowfish algorithm.

By default, the shared key is stored unencrypted in a file readable only by root. The author of the package notes that when someone has root privileges, they can grab the unencrypted packets as well, but there is an optional method that stores the key encrypted and uses strong authentication between the client and server to establish mutual trust. The drawback is that a transaction number is part of the key, and it is possible for the client and server to have different ideas of this value after a disconnect. Additionally, it requires a separate server for each client, rather than allowing multiple clients to connect to a single server.

Like everything else in this package, the theory of the encrypted key method is described in detail a cryptographer could love. There are also some options to drop the connection if certain delays are noted and to control how often a new random key is generated. These features, used with the encrypted shared key, appear to provide protection against all but the most serious attacks.

Because interactive connections using ssh work through the VPN, and other secure bulk transfers can be used, such as scp or encrypting data before transmission, the security of the data in transit also appears to be adequate for commercial use.

Experience and Warnings

I tried this setup because I was tired of patching things into Linux kernels, and because I only needed to connect Linux machines and didn't need to use some standard protocol to talk to Windows, Cisco routers, or any of the other nodes that want a standard protocol like PPPoE. In meeting those goals, this system has worked extremely well. It has produced no unexpected behavior, even in the face of very bad dialed connections. The transfer rate is acceptable, it hasn't complained when moving compressed data, and it has no interaction with ssh, which also encrypts its connection. I was able to run PPPoE through such a connection, but only as a proof of concept, so I can't speak to the throughput.

Setup has been easy. I have talked people through it over the phone, which I would rather not do but occasionally must, and the setup files are human readable. I recommend it for connections between UNIX systems as a reliable and easy-to-install VPN solution.

Bill Davidsen has been doing systems programming and administration since 1968, and was one of the founders of TMR Associates in 1979. In addition to being "part-time CTO" at TMR, he works as a project leader with a national ISP and writes an Internet column.