Next Previous Contents

5. Encrypting Network Traffic

This section is in preparation. See the Release Notes for a planned roadmap. I included the CIPE documentation as a subsection, but the section layout is not complete, so this may change (Why doesn't linuxdoc provide a part commamd like LaTeX? :-(

Anyway, this section includes descriptions of Linux kernel add-ons that allow you to encrypt the flow of network traffic (at least IP traffic, don't know about IPX and such).

5.1 The Concept of IP Tunnels

All network encryption packages described in this document work on the same basis: A private network, which should be inaccessible to the outside world, is spread over many (physical) locations (read: company centres and/or roaming users) that are connected via the "evil" internet. This setup is commonly called VPN (virtual private network), because the private network shares its physical structure with the "real" internet.

The task is to route IP packets originating in the private network and destined for other hosts in the private network through the internet while preserving privacy.

This section describes problems and concepts common to all of the VPN packages to be described later on.

What are IP Tunnels?

The basic networking protocol nowadays is TCP/IP, mostly because it is the protocol the internet uses. But there were other network protocols and ever will be. When the internet began to grow, everyone was tempted to switch to the TCP/IP protocol, regardless of what he was using before. But many applications were not TCP/IP aware and it proved difficult to convert certain subnets to TCP/IP. However, one still wanted to benefit from the TCP/IP protocol and use it for communicating with the internet.

This was one major reason to invent tunnels. Just like TCP/IP packets are packed in Ethernet frames to send them over Ethernet or in PPP frames to send them over PPP links, one now wrappes TCP/IP packets with e.g. IPX frames to tunnel TCP/IP through IPX, or vice versa.

Thus, one was able to use TCP/IP in IPX or ATM---you name it---environments without fundamental changes to routers and so on.

The next picture shows an IP packet contained in an IPX frame:

 +------------++-----------+------------------+
 | IPX header || IP header |      payload     |
 +------------++-----------+------------------+
           <----- IP packet -------------->
 <----- IPX packet containing IP packet ------>

Of cource, no-one prevents you from tunneling IP packets in IP packets. While this does not seem very useful at first sight, there are indeed situations where this concept makes your network admin's life much easier.

One typical example of ordinary IP-in-IP tunneling is the connection of a roaming user to a LAN. The roaming user can plug his laptop into whatever network is available (provided it has a connection to the internet), establish a tunnel to a gateway in the home LAN and route everything through the tunnel. This means that the roaming user will always find the same configuration of networking services available once he gets the tunnel to the home LAN up and running. Another typical example is LAN-LAN coupling.

You can find out more about ordinary tunneling (as opposed to encrypted tunnels) in the NET-3-HOWTO. We will instead concentrate on tunnels that encrypt everything that is put into them.

Private vs. Carrier Networks

The main thing to keep in mind when discussing VPN setups is the existence of two logical networks sharing the same physical network hardware. It is important not to confuse those two.

On the one hand, one has the private network, consisting of possibly many sites and hosts, which have no (inherently) secure connection between each other. One has to provide for a secured, transparent connection between them in order to make the pieces a whole.

On the other hand, one has the carrier network (often the internet) that is used to connect the different sites the private network is physically located at.

Typically, the private network uses IP subnets that are reserved for use in closed networks with no connection to the internet. Those subnets include the class A 10.0.0.0/8, the class B 172.[16-31].0.0/16 and the class C 192.168.[0-255].0/8 subnets. Those IP addresses will not be routed by internet routers and thus can only be used for their intended use: private networks. (There are, however, examples where the carrier network uses these addresses and the "private" network uses ordinary, routable addresses, see Section Encrypt the Local Ethernet.)

All VPN packages establish an encrypted point-to-point connection on top of an existing network between two hosts. This connection belongs to the private network, while the existing network serves as the carrier of the encrypted datagrams.

Routing Issues

The toughest part in setting up a VPN seems to be the correct routing. But this is only so if one confuses the two distinct networks described above. Indeed, one has to maintain two disjoint routing tables:

One for routing the private traffic within the private network (usually through the tunnel interfaces) and one for routing the encrypted datagrams over the carrier network (usually through the physical interfaces like eth0, ppp0).

Be careful, though: Not all physical network interfaces belong to the carrier network! The internal Ethernet of a company may well belong to the private network.

The problem is now that Linux knows nothing of our ambition to create a VPN setup. Also, it does not know about private and carrier networks and their distinction. All Linux can do is, based on its routing table, send an IP packet destined to a particular IP address through an appropriate network interface.

Therefore, the logical distinction of the two networks has to be expressed in terms of routing rules. The best practice proves ever so often to be to consider the carrier network alone first. Once you have the routing table for the carrier network, you start creating the tunnels and add routing rules for the private network, independent of the carrier networks' rules.

Example: Encrypt the Local Ethernet

The simplest class of a VPN is where the private and the carrier network coincide. As an example, I picked the case where a company wants to encrypt all traffic in the local Ethernet. This can be useful, if the LAN carries sensible data and one wants to make the EM radiation of the ethernet cables unusable to possible spies.

In this setup one hits the limit of most current VPN packages: They only know of point-to-point connections. Only FreeS/WAN has/will eventually have the ability to connect two arbitrary hosts transparently.

So, the only way out is to either select a host as internal gateway, and route all packets through it or to set up point-to-point connections for every single combination of hosts on the network.

While the first method minimizes configuration overhead, it also minimizes performance, because each packet has to be sent from the originating host to the gateway and back to the destination host. So network performance is roughly halved, not even counting the additional de/encryption process on the gateway host.

The second method maximizes both network performance and configuration overhead, because each change in the network topology needs to be reflected in the local (w.r.t. each host) configuration files.

Assume that the company's LAN is a single Ethernet segment and an IP subnet with net address 200.0.0.0 and subnet mask 255.255.255.0, i.e. the class C network 200.0.0.0/24. It has a gateway to the internet (to exchange mail, etc) with IP address 200.0.0.1. Security is enforced by a firewall in front of the gateway, so our task is only to encrypt all traffic in the local part of the ethernet.

             ethernet
 - - - -----+----------+----------+ eth0
            |          |          |
  ...     host C     host B     host A (gateway)
        200.0.0.3  200.0.0.2  200.0.0.1
                                  |
                             eth1 +-----------| firewall |------> INTERNET

As the hosts behind the firewall have transparent access to the internet (within the rules of the firewall), it is necessary that the private network has IP addresses that are routable. The carrier network does not need to have routable IP addresses, so we choose to assign IP address 200.0.0.0/24 to the private network and IP address 10.0.0.0/24 to the carrier network.

In the configuration-friendly model where all traffic is routed via the gateway (200.0.0.1 in our setup), host A's routing table would look like this:

Routes for the carrier network and the connection to the firewall:

 Destination     Gateway         Genmask         Flags Metric Ref    Use Iface
 10.0.0.0        0.0.0.0         255.255.255.0   U     0      0        0 eth0
 firewall        0.0.0.0         255.255.255.255 UH    0      0        0 eth1
 127.0.0.0       0.0.0.0         255.0.0.0       U     0      0        0 lo
[200.0.0.0       0.0.0.0         255.255.255.0   U!    0      0        0 eth0]
 0.0.0.0         firewall        0.0.0.0         UG    0      0        0 eth1
The routing table entry in parenthesis is a reject route preventing that local traffic is sent unencryptedly via the default route if the point-to-point route for a particular host is not set or there is no host corresponding to a given IP address.

Routes for the private network:

 Destination     Gateway         Genmask         Flags Metric Ref    Use Iface
 200.0.0.2       0.0.0.0         255.255.255.255 UH    0      0        0 tunl0
 200.0.0.3       0.0.0.0         255.255.255.255 UH    0      0        0 tunl1
 200.0.0.4       0.0.0.0         255.255.255.255 UH    0      0        0 tunl2
   ...             ...                 ...       ...  ...    ...     ...  ... 
Here tunlx stands as a placeholder for the interface name of the particular software used (e.g. cipcbx for CIPE or ipsecx for FreeS/WAN).

The routing table on the other hosts (B, C, etc) would look simply thus:

 Destination     Gateway         Genmask         Flags Metric Ref    Use Iface
 127.0.0.0       0.0.0.0         255.0.0.0       U     0      0        0 lo
 10.0.0.1        0.0.0.0         255.255.255.255 UH    0      0        0 eth0
 200.0.0.1       0.0.0.0         255.255.255.255 UH    0      0        0 tunl0
 0.0.0.0         200.0.0.1       0.0.0.0         UG    0      0        0 tunl0
Here, 10.0.0.1 is the IP address of host A in the carrier network (this is all any given host needs to know for its routing job, but the first route can safely be changed to be a net route).

In the performance-friendly model, host A's routing table would look the same, but the other hosts would have a routing table like the following:

 Destination     Gateway         Genmask         Flags Metric Ref    Use Iface
 127.0.0.0       0.0.0.0         255.0.0.0       U     0      0        0 lo
 10.0.0.0        0.0.0.0         255.255.255.0   U     0      0        0 eth0
 200.0.0.1       0.0.0.0         255.255.255.255 UH    0      0        0 tunl0
 200.0.0.2       0.0.0.0         255.255.255.255 UH    0      0        0 tunl1
 200.0.0.3       0.0.0.0         255.255.255.255 UH    0      0        0 tunl2
   ...             ...                 ...       ...  ...    ...     ...  ... 
 0.0.0.0         200.0.0.1       0.0.0.0         UG    0      0        0 tunl0
Note that the point-to-point routes are usually set up automatically by the controlling daemon, so in the last routing table, you only need to set the default and net routes by yourself.

Example: Connect Two Private Ethernets

The classical class of VPNs is the situation where two or more physically separated offices are to be connected in a transparent and secure way via the internet.

We first look at the routing required to connect two offices:

OFFICE A      if0 +-------> INTERNET <--------+ if0    OFFICE B
         1.1.1.1 /                             \ 2.2.2.2         carrier
 -  -  -  -  -  /  -  -  -  -  -  -  -  -  -  - \ -  -  -  -  -  network  -
               /                                 \               private
   10.0.1.1   /  10.0.1.1               10.0.2.1  \   10.0.2.1
    +------ gw.a ------------------------------- gw.b ------+
    |   eth0     tunl0                    tunl0      eth0   |
    v                                                       v
  LAN A                                                   LAN B
10.0.1.0/24                                            10.0.2.0/24

We have two LANs A and B with private IP address spaces 10.0.1.0/24 and 10.0.2.0/24, respectively and we assume that one host in LAN A (called gw.a) is connected to the internet via the network interface if0 (this is a generic name, think of it as ppp0 for a PPP link or eth1 for a DSL or leased line, etc.) with IP 1.1.1.1. The same is true for a host gw.b in LAN B, connected to the internet via if0 with IP address 2.2.2.2. The eth0 IP address of the gateways is, as usual, 10.0.1.1 and 10.0.2.1, respectively.

We want to connect these two LANs with a tunnel, so that traffic can flow between them, although they use IP addresses that are not allowed to travel the internet.

The advantage of using private IP addresses is that these need not be reserved (and possibly paid for) and that they make it hard for external intruders to attack hosts, simply due to the fact that IP packets destined for these IP addresses are immediately dropped by every internet router.

We identify the internet, together with the if0 interfaces of each gateway, to be the carrier network, while the two LANs and the tunnel between the two gateways constitute the private network.

If we first consider the routing needed for the carrier network, we simply get the following tables:

gw.a's Kernel IP routing table
Destination     Gateway         Genmask         Flags Metric Ref    Use Iface
2.2.2.2         0.0.0.0         255.255.255.255 UH    0      0        0 if0
127.0.0.0       0.0.0.0         255.0.0.0       U     0      0        0 lo

gw.b's Kernel IP routing table
Destination     Gateway         Genmask         Flags Metric Ref    Use Iface
1.1.1.1         0.0.0.0         255.255.255.255 UH    0      0        0 if0
127.0.0.0       0.0.0.0         255.0.0.0       U     0      0        0 lo

On top of this, we construct the routing tables for the private network:

gw.a's Kernel IP routing table
Destination     Gateway         Genmask         Flags Metric Ref    Use Iface
10.0.2.1        0.0.0.0         255.255.255.255 UH    0      0        0 tunl0
10.0.1.0        0.0.0.0         255.255.255.0   U     0      0        0 eth0
10.0.2.0        10.0.2.1        255.255.255.0   UG    0      0        0 tunl0

gw.b's Kernel IP routing table
Destination     Gateway         Genmask         Flags Metric Ref    Use Iface
10.0.1.1        0.0.0.0         255.255.255.255 UH    0      0        0 tunl0
10.0.2.0        0.0.0.0         255.255.255.0   U     0      0        0 eth0
10.0.1.0        10.0.1.1        255.255.255.0   UG    0      0        0 tunl0

Example: Connect a Mobile Host to the Internal LAN

This class of VPNs is a special case of Example  Connect Two Private Ethernets, and the routing involved is in fact easier when considering the tables only.

What makes this example special and interesting from a configuration point of view, is the fact that the tunnels are dynamically created and destroyed possibly quite often (as opposed to created at boot time and destroyed at system shutdown) and that the IP address of the mobile host may change frequently, depending on what LAN or ISP the laptop is currently plugged into.

Often one part of the carrier network consists of a dynamically established PPP link, which adds even more configuration overhead and variables to consider.

This setup depends heavily on the VPN software used, so further discussion of this is postponed to the sections on specific VPN software below.

5.2 CIPE - Cryptographic IP Encapsulation

CIPE by Olaf Titz ( Olaf.Titz@inka.de) ships with the International Kernel Patch (see Section Obtaining and Installing the International Kernel Patch). The userspace tools needed are in the net/cipe subdirectoy of the patched kernel source. The package is also available from http: //sites.inka.de/~bigred/devel/cipe.html. I only document version 1.3.0 (Apr 1999) here, although there is a newer version out (1.4.2). It will not inter-operate with earlier versions due to a bug in the key handling or so in those earlier versions, but it finally supports Windows! See http://CIPE-Win32.sourceforge.net/. There is also a mailing list dedicated to CIPE. You can subscribe to it by sending a message with the single line subscribe cipe-l in its body to majordomo@inka.de.

Concepts and Features

CIPE is a very simple package in that it requires you to make some decisions at compile-time, which leads to specialized and simpler code, which in turn is supposedly less bug-loaden than a complicated protocol like IPSec. CIPE is only compatible to itself, but often enough that is no limitation.

These disadvantages turn out to be big wins when it comes to maintaining the package, as configuration is much easier done than e.g. the disk encryption in Section Disk Encryption.

CIPE intercepts the network stack just above the network layer by adding a new network interface (e.g. cipcb0). (IP-)Packets routed through it will be encrypted and put through a tunnel to a peer gateway, where they will be decrypted and delivered.

It employs symmetric ciphers (Blowfish and IDEA) and a shared secret (key) with dynamic re-keying, i.e. the shared secret is only used for authentication and exchanging the first dynamically generated, actual encryption key. Data is encrypted using these dynamic keys.

The package consists of a kernel module (cipcb for Blowfish and cipci for IDEA) and a user space deamon (ciped-cb resp. ciped-ci).

Compiling and Installing

The only thing you need to do in your kernel is to enable loadable module support (CONFIG_MODULES). Of course you need to have some kind of (carrier) network running, but I assume that this is in a working state. See the appropriate HOWTOs for how to configure that.

CIPE currently only works as modules and I do not see anything indicating a change to that. Also, the building of the CIPE modules is currently not included in the kernel build process, not even with the international kernel, although the entries in make config suggest otherwise. At least on my 2.2.17.6 CIPE modules were not build resp. installed by make modules modules_install.

So you have to do that yourself: Change into the CIPE directory. It is the net/cipe subfolder of the kernel source tree if you use CIPE from the international kernel patch or cipe-1.3.0 if you extracted it from the tar archive on inka.de.

If you have the source of the kernel under /usr/src/linux, then you can just enter ./configure to let CIPE figure out the details of your kernel. Otherwise you have to tell the configuration script where to find the kernel source with the --with-linux option, e.g.

root# ./configure --with-linux=/usr/src/linux-2.2.17
if your kernel source resides in /usr/src/linux-2.2.17. If you want to use the IDEA cipher instead of the default Blowfish, then call ./configure with the option --enable-idea. These are the compile-time options mentioned in the Concepts and Features Section. You can compile different versions of the CIPE modules and userspace tools one after the other to allow the use of both ciphers.

After the configure script has successfully finished, you will find a new folder named something like 2.2.17-i386-cb in the CIPE directory. This helps you with the compilation of multiple versions of the CIPE package (e.g. for using both ciphers). The first part of the folder name consists of the kernel version (like uname -r) for which the modules will be compiled, followed by the machine type (like uname -m) and by the CIPE features: The first character stands for the protocol version (only c=3 allowed) and the cipher used (b=Blowfish and i=IDEA).

To compile and install the modules and userspace tools, enter the newly created directory and type

root# make && make install
That was it! Have a look at the file cipe.info which accompanies the CIPE sources if you want to compile CIPE for special cases (e.g. if you do not have the kernel source, but only the includes installed).

Testing the Installation

First, you have to do a minimal configuration: Copy the samples directory to /etc/cipe and edit the file /etc/cipe/options to include only the parameter key. For a first test you can safely go with the value provided by the options file of the samples directory. Later, you have to change this key, of course.

It is important that the key is the same on both machines you want to connect with a CIPE tunnel. For first tests, I would recommend that you set up a CIPE connection between hosts on the local Ethernet segment, if possible. Things like CIPE over PPP are covered in more depth later on.

To be specific, assume that we are living on an ethernet that consists of two boxes and uses IP addresses from the private range 10.0.0.0/24. We want to use Blowfish encryption. The two boxes, called A and B, have IP addresses 10.0.0.1 and 10.0.0.2 respectively.

The first step after compiling and installing CIPE on both machines is to load the modules on both hosts:

root@A# modprobe cipcb
root@B# modprobe cipcb
Next, you start the CIPE-daemon on each machine:
root@A# ciped-cb me=10.0.0.1:6789 peer=10.0.0.2:6543 ipaddr=10.0.1.1 ptpaddr=10.0.1.2
root@B# ciped-cb peer=10.0.0.1:6789 me=10.0.0.2:6543 ptpaddr=10.0.1.1 ipaddr=10.0.1.2
As you can see, the configuration parameters have to be swapped, so to speak, as me's peer is peer's me. Also, we need to use additional IP addresses for the CIPE interface (called cibcb here), see next section.

If everything worked well, you can try to ping the peer to see if the tunnel has been successfully established:

user@A$ ping 10.0.1.2
user@B$ ping 10.0.1.1
A common mistake is to have a firewalling policy of DENY or REJECT and no ACCEPT rule corresponding to the UDP port numbers used. ping will report "sendto: write: operation not permitted" if this is the case. See the ipchains-HOWTO for how to add such rules. If you are using masquerading together with CIPE, you may want to look at the CIPE+Masquerading-miniHOWTO, too.

If you were able to ping the other host, you can now try to telnet or ssh the other host. If all works well, you have successfully completed the first tests.

Configuration Overview

In this subsection you will learn of the various parameters that influence CIPE's behaviour. You have seen the most important ones in the last section, here we discuss their meaning in detail:

key, nokey

For security reasons, the key parameter must be set via an options file, owned by root and unreadable for anyone else. It is followed by the 128-bit shared secret, i.e. the key that is used for authentication and generation of session keys. To generate a truly random key and add it directly to your options file, so no-one can sneak it, issue the following command:

root# echo key $(head -c 16 /dev/random | md5sum) >> /etc/cipe/options
It is your responsibility that you transfer the key from one machine to the other in a secure fashion. Do not use ftp or other unencrypted protocols to send the key! The recommended way is to learn the key by heart and type it into the other box by hand or to send it via PGP/GnuPG-encrypted E-Mail. But also transferring it via removable media or through a ssh session is acceptable. Make sure you are absolutely certain that the other end of the ssh connection is indeed the box you think it is. nokey leads to simple (and unauthenticated) IP-in-IP tunnelling, useful only for testing. key and nokey are mutually exclusive options.

me, peer

The IP address of my host, followed by the colon-separated port number the CIPE daemon should listen to (me) and the IP address of the other end of the CIPE tunnel, followed by the colon-separated port number to which we wish to connect to (peer). These are the IP addresses that hosts of the carrier network "see". Make sure that all firewalls between the two hosts let pass UDP packets destined for those ports. peer can be 0.0.0.0:0, in which case the IP address is taken as the one of the host connecting to us, provided it successfully authenticates itself. me needs not be specified. In this case CIPE will pick appropriate values and report them to the ip-up script.

ipaddr, ptpaddr

The IP address of the cipcb (resp. cipci) interface on my host (ipaddr) and the IP address of the cipcb (resp. cipci) interface of the peer (ptpaddr). The CIPE daemon uses this information to automatically set a point-to-point route between the two interfaces after a connection has been established (just like the PPP daemon does after successful dial-in). These are the IP addresses that hosts in the private network "see". ptpaddr can be 0.0.0.0, in which case the peer's IP address is determined when the other end tries to connect and successfully authenticates itself.

mtu, cttl, metric

These optional parameters specify the cipcb/i device MTU (maximum transfer unit), the UDP packets' TTL (time to live) value and the cipcb/i device metric. See the appropriate (networking) HOWTOs if you don't know what I am talking about.

tokxc, tokey, tokxts, ping, toping, maxerr

These optional parameters specify the key exchange timeout (10), the dynamic key lifetime (600), the key exchange timestamp window (0), the time between two successive keep-alive pings (0), the timeout for those pings (0) and the maximum number of network errors between two key exchanges (8). All these parameters take their values to be specified in seconds and a value of 0 (zero) means "disable this feature/no timeout". Default values are listed in parenthesis. maxerr is different, though: The value is just a number (no seconds) and a value of 0 (zero) means "accept no errors", while "accept any number of errors" corresponds to a value of -1 (minus one). You normally want to go with the default values, but sometimes adjusting the maxerr parameter is needed if your connection is not so reliable (e.g. PPP).

ipup, ipdown, arg

These optional parameters specify the name of the ip-ip and ip-down scripts to run resp. (default: /etc/cipe/ip-up resp. /etc/cipe/ip-down) and an optional argument to pass to the ip-up script. Useful if you intend to run more than one ciped.

There is also the socks parameter, which allows you to connect to a SOCKS5 server with CIPE. If you need it, you'll want to read the cipe.info file that comes with CIPE.

Two other parameters, device and debug, are only useful in testing, since CIPE 1.3.0 can automatically grab free cipcb/i interfaces as needed, and debug is useful for just that: debugging.

All these options can be specified in either of three ways:

  1. via the default options file /etc/cipe/options,
  2. via an options file specified as -o file on the command line,
  3. via the command line as parameter=value,
in order of processing (i.e. command line options override -o file options override /etc/cipe/options options).

5.3 Other Network Traffic Encryption Approaches

I will just give you the necessary links to find other documentation on the following packages:


Next Previous Contents