# IPSEC using Linux Kernel 2.6

### Tom Eastep

Copyright © 2004, 2005, 2006 Thomas M. Eastep

Permission is granted to copy, distribute and/or modify this document under the terms of the GNU Free Documentation License, Version 1.2 or any later version published by the Free Software Foundation; with no Invariant Sections, with no Front-Cover, and with no Back-Cover Texts. A copy of the license is included in the section entitled “GNU Free Documentation License”.

2006-03-11

### Caution

This article applies to Shorewall 3.0 and later. If you are running a version of Shorewall earlier than Shorewall 3.0.0 then please see the documentation for that release.

### Important

The information in this article is only applicable if you plan to have IPSEC end-points on the same system where Shorewall is used.

### Warning

To use the features described in this article, your kernel but be 2.6.16 or later or your kernel and iptables must include the Netfilter+ipsec patches and policy match support. The Netfilter patches are available from Netfilter Patch-O-Matic-NG and are also included in some commercial distributions (most notably SUSE™ 9.1 through 10.0).

### Important

You must have BOTH the Netfilter+ipsec patches and the policy match patch. One without the other will not work.

Here's a combination of components that I know works:

1. Kernel 2.6.11 from kernel.org. Patched with:

   - The five patches in http://shorewall.net/pub/shorewall/contrib/IPSEC/2.6.11

   - The "policy match" extension from the Patch-o-matic-ng CVS snapshot from 2005-May-04 (be sure to NOT try to apply the ipsec-NN patches from patch-o-matic-ng).

2. iptables 1.3.1 patched with the "policy match" extension from the Patch-o-matic-ng CVS snapshot from 2005-May-04.

3. ipsec-tools 0.5.2 compiled from source. I've also had success with:

   - ipsec-tools 0.5.2 and racoon 0.5.2 from Debian Sarge/testing

   - The ipsec-tools 0.5 rpm from SUSE™ 9.3.

### Warning

As of this writing, the Netfilter+ipsec and policy match support are broken when used with a bridge device. The problem has been reported to the responsible Netfilter developer who has confirmed the problem.

## Shorewall 3.0 and Kernel 2.6 IPSEC

This is not a HOWTO for Kernel 2.6 IPSEC -- for that, please see http://www.ipsec-howto.org/.

The 2.6 Linux Kernel introduces new facilities for defining encrypted communication between hosts in a network. The network administrator defines a set of Security Policies which are stored in the kernel as a Security Policy Database (SPD). Security policies determine which traffic is subject to encryption. Security Associations are created between pairs of hosts in the network (one SA for traffic in each direction); these SAs define how traffic is to be encrypted. Outgoing traffic that is to be encrypted according to the contents of the SPD requires an appropriate SA to exist. SAs may be created manually using setkey(8) but most often, they are created by a cooperative process involving the ISAKMP protocol and daemons such as racoon or isakmpd. Incoming traffic is verified against the SPD to ensure that no unencrypted traffic is accepted in violation of the administrator's policies.

There are three ways in which IPSEC traffic can interact with Shorewall policies and rules:

1. Traffic that is encrypted on the firewall system. The traffic passes through Netfilter twice -- first as unencrypted then encrypted.

2. Traffic that is decrypted on the firewall system. The traffic passes through Netfilter twice -- first as encrypted then as unencrypted.

3. Encrypted traffic that is passed through the firewall system. The traffic passes through Netfilter once.

In cases 1 and 2, the encrypted traffic is handled by entries in `/etc/shorewall/tunnels` (don't be mislead by the name of the file -- transport mode encrypted traffic is also handled by entries in that file). The unencrypted traffic is handled by normal rules and policies.

Under the 2.4 Linux Kernel, the association of unencrypted traffic and zones was made easy by the presense of IPSEC pseudo-interfaces with names of the form `ipsecn` (e.g. `ipsec0`). Outgoing unencrypted traffic (case 1.) was send through an `ipsecn` device while incoming unencrypted traffic (case 2) arrived from an `ipsecn` device. The 2.6 kernel-based implementation does away with these pseudo-interfaces. Outgoing traffic that is going to be encrypted and incoming traffic that has been decrypted must be matched against policies in the SPD and/or the appropriate SA.

Shorewall provides support for policy matching in three ways:

1. In `/etc/shorewall/masq`, traffic that will later be encrypted is exempted from MASQUERADE/SNAT using existing entries. If you want to MASQUERADE/SNAT outgoing traffic that will later be encrypted, you must include the appropriate indication in the new IPSEC column in that file.

2. The`` `/etc/shorewall/zones` file allows you to associate zones with traffic that will be encrypted or that has been decrypted.

3. A new option (ipsec) has been provided for entries in `/etc/shorewall/hosts`. When an entry has this option specified, traffic to/from the hosts described in the entry is assumed to be encrypted.

In summary, Shorewall provides the facilities to replace the use of ipsec pseudo-interfaces in zone and MASQUERADE/SNAT definition.

There are two cases to consider:

1. Encrypted communication is used to/from all hosts in a zone.

   The value ipsec is placed in the TYPE column of the `/etc/shorewall/zones` entry for the zone.

2. By default, encrypted communication is not used to communicate with the hosts in a zone.

   The value ipv4 is placed in the TYPE column of the `/etc/shorewall/zones` entry for the zone and the new ipsec option is specified in `/etc/shorewall/hosts` for any hosts requiring secure communication.

### Note

For simple zones such as are shown in the following examples, the two techniques are equivalent and are used interchangably.

### Note

It is redundent to have ipsec in the TYPE column of the `/etc/shorewall/zones` entry for a zone and to also have the ipsec option in `/etc/shorewall/hosts` entries for that zone.

Finally, the OPTIONS, IN OPTIONS and OUT OPTIONS columns in /etc/shorewall/zones can be used to match the zone to a particular (set of) SA(s) used to encrypt and decrypt traffic to/from the zone and the security policies that select which traffic to encrypt/decrypt.

This article assumes the use of ipsec-tools (http://ipsec-tools.sourceforge.net). As of this writing, I recommend that you run at least version 0.5.2. Debian users, please note that there are separate Debian packages for ipsec-tools and racoon although the ipsec-tools project releases them as a single package.

For more information on IPSEC, Kernel 2.6 and Shorewall see my presentation on the subject given at LinuxFest NW 2005. Be warned though that the presentation is based on Shorewall 2.2 and there are some differences in the details of how IPSEC is configured.

## IPSec Gateway on the Firewall System

Suppose that we have the following sutuation:

We want systems in the 192.168.1.0/24 sub-network to be able to communicate with systems in the 10.0.0.0/8 network. We assume that on both systems A and B, eth0 is the internet interface.

To make this work, we need to do two things:

1. Open the firewall so that the IPSEC tunnel can be established (allow the ESP and AH protocols and UDP Port 500).

2. Allow traffic through the tunnel.

Opening the firewall for the IPSEC tunnel is accomplished by adding an entry to the `/etc/shorewall/tunnels` file.

In `/etc/shorewall/tunnels` on system A, we need the following

> `/etc/shorewall/tunnels` — System A:

>     #TYPE         ZONE        GATEWAY             GATEWAY ZONE
>     ipsec         net         134.28.54.2
>     #LAST LINE -- ADD YOUR ENTRIES ABOVE THIS LINE -- DO NOT REMOVE

> `/etc/shorewall/tunnels` — System B:

>     #TYPE         ZONE        GATEWAY             GATEWAY ZONE
>     ipsec         net         206.162.148.9
>     #LAST LINE -- ADD YOUR ENTRIES ABOVE THIS LINE -- DO NOT REMOVE

### Note

If either of the endpoints is behind a NAT gateway then the tunnels file entry on the other endpoint should specify a tunnel type of ipsecnat rather than ipsec and the GATEWAY address should specify the external address of the NAT gateway.

You need to define a zone for the remote subnet or include it in your local zone. In this example, we'll assume that you have created a zone called “vpn” to represent the remote subnet.

> `/etc/shorewall/zones` — Systems A and B:

>     #ZONE          TYPE             OPTIONS             IN           OUT
>     #                                                   OPTIONS      OPTIONS
>     vpn            ipv4
>     net            ipv4
>     #LAST LINE -- ADD YOUR ENTRIES ABOVE THIS LINE -- DO NOT REMOVE

Remember the assumption that both systems A and B have eth0 as their internet interface.

You must define the vpn zone using the `/etc/shorewall/hosts` file. The hosts file entries below assume that you want the remote gateway to be part of the vpn zone — If you don't wish the remote gateway included, simply omit it's IP address from the HOSTS column.

> /etc/shorewall/hosts — System A

>     #ZONE             HOSTS                                OPTIONS
>     vpn               eth0:10.0.0.0/8,134.28.54.2          ipsec
>     #LAST LINE -- ADD YOUR ENTRIES ABOVE THIS LINE -- DO NOT REMOVE

> /etc/shorewall/hosts — System B

>     #ZONE             HOSTS                                OPTIONS
>     vpn               eth0:192.168.1.0/24,206.162.148.9    ipsec
>     #LAST LINE -- ADD YOUR ENTRIES ABOVE THIS LINE -- DO NOT REMOVE

Assuming that you want to give each local network free access to the remote network and vice versa, you would need the following `/etc/shorewall/policy` entries on each system:

>     #SOURCE          DESTINATION            POLICY          LEVEL       BURST:LIMIT
>     loc              vpn                    ACCEPT
>     vpn              loc                    ACCEPT

Once you have these entries in place, restart Shorewall (type shorewall restart); you are now ready to configure IPSEC.

For full encrypted connectivity in this configuration (between the subnets, between each subnet and the opposite gateway, and between the gateways), you will need eight policies in `/etc/racoon/setkey.conf`. For example, on gateway A:

>     # First of all flush the SPD and SAD databases
>     spdflush;
>     flush;

>     # Add some SPD rules

>     spdadd 192.168.1.0/24   10.0.0.0/8       any -P out ipsec esp/tunnel/206.162.148.9-134.28.54.2/require;
>     spdadd 192.168.1.0/24   134.28.54.2/32   any -P out ipsec esp/tunnel/206.162.148.9-134.28.54.2/require;
>     spdadd 206.162.148.9/32 134.28.54.2/32   any -P out ipsec esp/tunnel/206.162.148.9-134.28.54.2/require;
>     spdadd 206.162.148.9/32 10.0.0.0/8       any -P out ipsec esp/tunnel/206.162.148.9-134.28.54.2/require;
>     spdadd 10.0.0.0/8       192.168.1.0/24   any -P in  ipsec esp/tunnel/134.28.54.2-206.162.148.9/require;
>     spdadd 10.0.0.0/8       206.162.148.9/32 any -P in  ipsec esp/tunnel/134.28.54.2-206.162.148.9/require;
>     spdadd 134.28.54.2/32   192.168.1.0/24   any -P in  ipsec esp/tunnel/134.28.54.2-206.162.148.9/require;
>     spdadd 134.28.54.2/32   206.162.148.9/32 any -P in  ipsec esp/tunnel/134.28.54.2-206.162.148.9/require;

The `setkey.conf` file on gateway B would be similar.

A sample `/etc/racoon/racoon.conf` file using X.509 certificates might look like:

>     path certificates "/etc/certs" ;

>     listen
>     {
>             isakmp 206.162.148.9;
>     }

>     remote 134.28.54.2
>     {
>             exchange_mode main ;
>             certificate_type x509 "GatewayA.pem" "GatewayA_key.pem" ;
>             verify_cert on;
>             my_identifier asn1dn ;
>             peers_identifier asn1dn ;
>             verify_identifier on ;
>             lifetime time 24 hour ;
>             proposal {
>                     encryption_algorithm blowfish;
>                     hash_algorithm sha1;
>                     authentication_method rsasig ;
>                     dh_group 2 ;
>             }
>     }

>     sainfo address 192.168.1.0/24 any address 10.0.0.0/8 any
>     {
>             pfs_group 2;
>             lifetime time 12 hour ;
>             encryption_algorithm blowfish ;
>             authentication_algorithm hmac_sha1, hmac_md5 ;
>             compression_algorithm deflate ;
>     }

>     sainfo address 206.162.148.9/32 any address 10.0.0.0/8 any
>     {
>             pfs_group 2;
>             lifetime time 12 hour ;
>             encryption_algorithm blowfish ;
>             authentication_algorithm hmac_sha1, hmac_md5 ;
>             compression_algorithm deflate ;
>     }

>     sainfo address 206.162.148.9/32 any address 134.28.54.2/32 any
>     {
>             pfs_group 2;
>             lifetime time 12 hour ;
>             encryption_algorithm blowfish ;
>             authentication_algorithm hmac_sha1, hmac_md5 ;
>             compression_algorithm deflate ;
>     }

>     sainfo address 192.168.1.0/24 any address 134.28.54.2/32 any
>     {
>             pfs_group 2;
>             lifetime time 12 hour ;
>             encryption_algorithm blowfish ;
>             authentication_algorithm hmac_sha1, hmac_md5 ;
>             compression_algorithm deflate ;
>     }

> ### Warning

> If you have hosts that access the internet through an IPSEC tunnel, then it is a good idea to set the MSS value for traffic from those hosts explicitly in the `/etc/shorewall/zones` file. For example, if hosts in the sec zone access the internet through an ESP tunnel then the following entry would be appropriate:

>     #ZONE   TYPE    OPTIONS                 IN                      OUT
>     #                                       OPTIONS                 OPTIONS
>     sec     ipsec   mode=tunnel             mss=1400

> Note that CLAMPMSS=Yes in `shorewall.conf` isn't effective with the 2.6 native IPSEC implementation because there is no separate ipsec device with a lower mtu as there was under the 2.4 and earlier kernels.

## Mobile System (Road Warrior)

Suppose that you have a laptop system (B) that you take with you when you travel and you want to be able to establish a secure connection back to your local network.

Example 1. Road Warrior VPN

You need to define a zone for the laptop or include it in your local zone. In this example, we'll assume that you have created a zone called “vpn” to represent the remote host.

> /etc/shorewall/zones — System A

>     #ZONE          TYPE             OPTIONS             IN           OUT
>     #                                                   OPTIONS      OPTIONS
>     vpn            ipsec
>     net            ipv4
>     loc            ipv4
>     #LAST LINE -- ADD YOUR ENTRIES ABOVE THIS LINE -- DO NOT REMOVE

In this instance, the mobile system (B) has IP address 134.28.54.2 but that cannot be determined in advance. In the `/etc/shorewall/tunnels` file on system A, the following entry should be made:

>     #TYPE         ZONE        GATEWAY             GATEWAY ZONE
>     ipsec         net         0.0.0.0/0           vpn
>     #LAST LINE -- ADD YOUR ENTRIES ABOVE THIS LINE -- DO NOT REMOVE

### Note

the GATEWAY ZONE column contains the name of the zone corresponding to peer subnetworks. This indicates that the gateway system itself comprises the peer subnetwork; in other words, the remote gateway is a standalone system.

The VPN zone is defined using the /etc/shorewall/hosts file:

> /etc/shorewall/hosts — System A:

>     #ZONE             HOSTS                  OPTIONS
>     vpn               eth0:0.0.0.0/0
>     #LAST LINE -- ADD YOUR ENTRIES ABOVE THIS LINE -- DO NOT REMOVE

You will need to configure your “through the tunnel” policy as shown under the first example above.

On the laptop:

> /etc/shorewall/zones - System B:

>     #ZONE          TYPE             OPTIONS             IN           OUT
>     #                                                   OPTIONS      OPTIONS
>     vpn            ipsec
>     net            ipv4
>     loc            ipv4
>     #LAST LINE -- ADD YOUR ENTRIES ABOVE THIS LINE -- DO NOT REMOVE

> /etc/shorewall/tunnels - System B:

>     #TYPE         ZONE        GATEWAY             GATEWAY ZONE
>     ipsec         net         206.162.148.9       vpn
>     #LAST LINE -- ADD YOUR ENTRIES ABOVE THIS LINE -- DO NOT REMOVE

> /etc/shorewall/hosts - System B:

>     #ZONE             HOSTS                  OPTIONS
>     vpn               eth0:0.0.0.0/0
>     #LAST LINE -- ADD YOUR ENTRIES ABOVE THIS LINE -- DO NOT REMOVE

On system A, here are the IPSEC files:

> /etc/racoon/racoon.conf - System A:

>     path certificate "/etc/certs" ;

>     listen
>     {
>             isakmp 206.162.148.9;
>     }

>     remote anonymous
>     {
>             exchange_mode main ;
>             generate_policy on ;
>             passive on ;
>             certificate_type x509 "GatewayA.pem" "GatewayA_key.pem" ;
>             verify_cert on;
>             my_identifier asn1dn ;
>             peers_identifier asn1dn ;
>             verify_identifier on ;
>             lifetime time 24 hour ;
>             proposal {
>                     encryption_algorithm blowfish ;
>                     hash_algorithm sha1;
>                     authentication_method rsasig ;
>                     dh_group 2 ;
>             }
>     }

>     sainfo anonymous
>     {
>             pfs_group 2;
>             lifetime time 12 hour ;
>             encryption_algorithm blowfish ;
>             authentication_algorithm hmac_sha1, hmac_md5 ;
>             compression_algorithm deflate ;
>     }

> /etc/racoon/setkey.conf - System A:

>     flush;
>     spdflush;

If system A is running kernel 2.6.10 or later then it must also be running ipsec-tools (racoon) 0.5rc1 or later.

On the mobile system (system B), it is not possible to create a static IPSEC configuration because the IP address of the laptop's internet connection isn't static. I have created an 'ipsecvpn' script and included in the tarball and in the RPM's documentation directory; this script can be used to start and stop the connection.

The ipsecvpn script has some variable assignments at the top -- in the above case, these would be as follows:

>     #
>     # External Interface
>     #
>     INTERFACE=eth0
>     #
>     # Remote IPSEC Gateway
>     #
>     GATEWAY=206.162.148.9
>     #
>     # Networks behind the remote gateway
>     #
>     NETWORKS="192.168.1.0/24"
>     #
>     # Directory where X.509 certificates are stored.
>     #
>     CERTS=/etc/certs
>     #
>     # Certificate to be used for this connection. The cert
>     # directory must contain:
>     #
>     #     ${CERT}.pem     - the certificate
>     #     ${CERT}_key.pem - the certificates's key
>     #
>     CERT=roadwarrior
>     #
>     #     The setkey binary
>     #
>     SETKEY=/usr/sbin/setkey
>     #
>     #     The racoon binary
>     #
>     RACOON=/usr/sbin/racoon

The ipsecvpn script can be installed in /etc/init.d/ but it is probably best installed in /usr/local/sbin and run manually:

> ipsecvpn start # Starts the tunnel

> ipsecvpn stop # Stops the tunnel

### Warning

Although the ipsecvpn script allows you to specify multiple remote NETWORKS as a space-separated list, SAs are created on the gateway only during ISAKMP negotiation. So in practice, only the first remote network accessed will be accessible from the roadwarrior.

## Transport Mode

In today's wireless world, it is often the case that individual hosts in a network need to establish secure connections with the other hosts in that network. In that case, IPSEC transport mode is an appropriate solution.

Here's an example using the ipsec-tools package. The files shown are from host 192.168.20.10; the configuration of the other nodes is similar.

> `/etc/racoon/racoon.conf`:

>     path pre_shared_key "/etc/racoon/psk.txt" ;

>     remote anonymous
>     {
>             exchange_mode main ;
>             my_identifier address ;
>             lifetime time 24 hour ;
>             proposal {
>                     encryption_algorithm blowfish ;
>                     hash_algorithm sha1;
>                     authentication_method pre_shared_key ;
>                     dh_group 2 ;
>             }
>     }

>     sainfo anonymous
>     {
>             pfs_group 2;
>             lifetime time 12 hour ;
>             encryption_algorithm blowfish ;
>             authentication_algorithm hmac_sha1, hmac_md5 ;
>             compression_algorithm deflate ;
>     }

> `/etc/racoon/setkey.conf`:

>     # First of all flush the SPD database
>     spdflush;

>     # Add some SPD rules

>     spdadd 192.168.20.10/32 192.168.20.20/32 any -P out ipsec esp/transport/192.168.20.10-192.168.20.20/require;
>     spdadd 192.168.20.20/32 192.168.20.10/32 any -P in  ipsec esp/transport/192.168.20.20-192.168.20.10/require;
>     spdadd 192.168.20.10/32 192.168.20.30/32 any -P out ipsec esp/transport/192.168.20.10-192.168.20.30/require;
>     spdadd 192.168.20.30/32 192.168.20.10/32 any -P in  ipsec esp/transport/192.168.20.30-192.168.20.10/require;
>     spdadd 192.168.20.10/32 192.168.20.40/32 any -P out ipsec esp/transport/192.168.20.10-192.168.20.40/require;
>     spdadd 192.168.20.40/32 192.168.20.10/32 any -P in  ipsec esp/transport/192.168.20.40-192.168.20.10/require;

> /etc/racoon/psk.txt:

>     192.168.20.20             <key for 192.168.20.10<->192.168.20.20>
>     192.168.20.30             <key for 192.168.20.10<->192.168.20.30>
>     192.168.20.40             <key for 192.168.20.10<->192.168.20.40>

> Note that the same keymust be used in both directions.

Shorewall configuration goes as follows:

> `/etc/shorewall/interfaces`:

>     #ZONE   INTERFACE       BROADCAST       OPTIONS
>     net     eth0            detect          routefilter,dhcp,tcpflags
>     #LAST LINE -- ADD YOUR ENTRIES BEFORE THIS ONE -- DO NOT REMOVE

> /etc/shorewall/tunnels:

>     #TYPE          ZONE             GATEWAY         GATEWAY
>     #                                               ZONE
>     ipsec:noah     net              192.168.20.0/24 loc

> /etc/shorewall/zones:

>     #ZONE          TYPE             OPTIONS             IN           OUT
>     #                                                   OPTIONS      OPTIONS
>     loc            ipsec            mode=transport
>     net            ipv4

> `/etc/shorewall/hosts`:

>     #ZONE           HOST(S)                         OPTIONS
>     loc             eth0:192.168.20.0/24
>     #LAST LINE -- ADD YOUR ENTRIES BEFORE THIS LINE -- DO NOT REMOVE

> It is worth noting that although loc is a sub-zone of net, because loc is an IPSEC-only zone it does not need to be defined before net in /etc/shorewall/zones.

> `/etc/shorewall/policy`:

>     #SOURCE         DEST            POLICY          LOG LEVEL       LIMIT:BURST
>     $FW             all             ACCEPT
>     loc             $FW             ACCEPT
>     net             loc             NONE
>     loc             net             NONE
>     net             all             DROP            info
>     # The FOLLOWING POLICY MUST BE LAST
>     all             all             REJECT          info
>     #LAST LINE -- ADD YOUR ENTRIES ABOVE THIS LINE -- DO NOT REMOVE

> Since there are no cases where net<->loc traffic should occur, NONE policies are used.

## IPSEC and Windows™ XP

I have successfully configured my work laptop to use IPSEC with X.509 certificates for wireless IP communication when it is undocked at home. I looked at dozens of sites and the one I found most helpful was http://ipsec.math.ucla.edu/services/ipsec-windows.html. The instructions on that site are directed to students at UCLA but they worked fine for me (once I followed them very carefully).

### Warning

The instructions found on the UCLA site are complex and do not include any information on the generation of X.509 certificates. There are lots of sites however that can tell you how to generate certificates, including http://www.ipsec-howto.org/.

One piece of information that may not be so easy to find is "How do I generate a PKCS#12 certificate to import into Windows?". Here's the openssl command that I used:

    openssl pkcs12 -export -in eastepnc6000.pem -inkey eastepnc6000_key.pem -out eastepnc6000.pfx -name "IPSEC Cert for Home Wireless"

I was prompted for a password to associate with the certificate. This password is entered on the Windows system during import.

In the above command:

- `eastepnc6000.pem` was the laptop's certificate in PEM format.

- `eastepnc6000_key.pem` was the laptop's private key (actually, it's the original signing request which includes the private key).

- `eastepnc6000.pfx` is the PKCS#12 output file.

- "IPSEC Cert for Home Wireless" is the friendly name for the certificate.

I started to write an article about how to do this, complete with graphics captured from my laptop. I gave up. I had captured 12 images and hadn't really started yet. The Windows interface for configuring IPSEC is the worst GUI that I have ever used. What can be displayed on one split Emacs screen (racoon.conf plus setkey.conf) takes 20+ different dialog boxes on Windows XP!!!

## Source of Additional Samples

Be sure to check out the `src/racoon/samples` subdirectory in the ipsec-tools source tree. It has a wide variety of sample racoon configuration files.