Debian IPsec Micro-Howto

This information is now outdated due to the release of Debian 3.1!

So in a moment of weakness I promised I'd write a simple how-to for setting up IPsec in Debian. That ought to be easy; I've set up two separate computer systems (that's systems, with many computers in each system) each using IPsec extensively, I've used both FreeS/WAN and IPsec-tools, by themselves and interoperating, and I've used both PSKs and X.509 certificates. Well, we'll see.

Why Another Howto?

So what's wrong with other howtos about how to setup IPsec? Well, they usually don't cover Debian specifically, but that's not my chief problem. The main thing which makes other IPsec texts unsuitable for me is that they all assume I'm using IPsec to do a VPN. Well, I'm not, I'm using it to get IP security for otherwise completely insecure thing like NIS and NFS. And once you've got it running you can enable things like FTP and even telnet, and you can then run X over the network like it was meant to be run and not inside some ugly SSH tunnel.

Well, enough ranting.

Authentication Methods

Another thing which put me off other texts about IPsec was that they all used PSKs in their examples and then, maybe, covered X.509 certificates at the end, and only as a list of things to do differently. This annoyed me because of course I was using real X.509 certificates signed by a CA (home-made, but anyway), and didn't want to be forced to learn how to set up IPsec into a configuration I wasn't going to use in order to only then learn how to do what I really wanted to do. So here I'm going to assume that you have your certificates ready, all signed by specific CA which you will trust. How to do all that CA signing and stuff have, thankfully, been covered elsewhere, so I'm not going to. If you don't want to deal with that, there's always PSKs.

What Implementation?

Debian contains two main implementations of IPsec, FreeS/WAN and IPsec-tools. For reasons outlined here I've decided to go with IPsec-tools for the future. The IPsec-tools packages are called "racoon" and "ipsec-tools". You'll have to recompile them yourself for Woody; I'll show you how below.

If you're a really ardent "woody" user, then feel free to use the "freeswan" and "kernel-patch-freeswan" packages. However, I am not satisfied with Linux 2.4.18, which is what those packages require to patch cleanly. So, since we are not using official Debian woody packages, the following is going to be a bit messy.

I occasionally see a weird bug with IPsec-tools; when I'm using screen(1) and repainting a screenful (80×48) of text it sometimes seemingly drops a packet and loses track of the TCP connection and I have to kill my ssh (or telnet) session and relogin and reconnect to my screen(1). However, I believe this is caused by this bug, which you may want to patch if you're using kernel-source-2.4.26 from Debian Woody. And if you're patching, you might as well do this one too. But other than the screen(1) thing I don't have any other problems with it; I can run NIS, NFS, telnet and X (untunneled) just fine.

Anyway, on to the installation.

Installation

If you are a sane person with other things to do (or to purposely not do) than maintaining computers, then you run Debian Woody since it's stable and supported with security updates. However, racoon and ipsec-tools does not exist in Woody, nor do the backports site have them, for some reason.

So it's compile-your-own-debian-package time. Here we go. First, download the packages. Since the packages does not exist in Woody, we can't just apt-get source them; so we employ some clever use of wget:

$ wget --recursive --level=1 --no-host-directories --accept \
.gz --span-hosts --domains=ftp.debian.org --cut-dirs=5 \
'http://packages.debian.org/testing/source/ipsec-tools'
--17:03:18--  http://packages.debian.org/testing/source/ipsec-tools
           => `ipsec-tools'
Resolving packages.debian.org... done.
Connecting to packages.debian.org[192.25.206.10]:80... connected.
HTTP request sent, awaiting response... 200 OK
Length: 8,782 [text/html]

100%[====================================>] 8,782         23.50K/s    ETA 00:00

17:03:19 (23.50 KB/s) - `ipsec-tools' saved [8782/8782]

Loading robots.txt; please ignore errors.
--17:03:19--  http://ftp.debian.org/robots.txt
           => `robots.txt'
Connecting to ftp.debian.org[208.185.25.35]:80... connected.
HTTP request sent, awaiting response... 404 Not Found
17:03:19 ERROR 404: Not Found.

Removing ipsec-tools since it should be rejected.
--17:03:19--  http://ftp.debian.org/debian/pool/main/i/ipsec-tools/ipsec-tools_0.3.3.orig.tar.gz
           => `ipsec-tools_0.3.3.orig.tar.gz'
Connecting to ftp.debian.org[208.185.25.35]:80... connected.
HTTP request sent, awaiting response... 200 OK
Length: 864,122 [application/x-tar]

100%[====================================>] 864,122      234.15K/s    ETA 00:00

17:03:23 (234.15 KB/s) - `ipsec-tools_0.3.3.orig.tar.gz' saved [864122/864122]

--17:03:23--  http://ftp.debian.org/debian/pool/main/i/ipsec-tools/ipsec-tools_0.3.3-1.diff.gz
           => `ipsec-tools_0.3.3-1.diff.gz'
Reusing connection to ftp.debian.org:80.
HTTP request sent, awaiting response... 200 OK
Length: 188,784 [text/plain]

100%[====================================>] 188,784      181.81K/s    ETA 00:00

17:03:24 (181.81 KB/s) - `ipsec-tools_0.3.3-1.diff.gz' saved [188784/188784]


FINISHED --17:03:24--
Downloaded: 1,061,688 bytes in 3 files
$

Since we didn't use apt-get source, we need to unpack and patch manually:

$ tar --gzip --extract --file ipsec-tools_*.orig.tar.gz
$ zcat ipsec-tools_*.diff.gz | patch --strip=0 --silent

Now we need to reconfigure the package to compile in Woody, after which we start the compilation.

$ cd ipsec-tools-*/
$ perl -pi -e 's/^dist := sid/dist := woody/' debian/rules
$ cp -a debian/control.woody debian/control
$ debuild -us -uc -b

If it complains about missing build-dependencies, just install the packages listed by "grep Build-Depends debian/control". Also, the "debuild" command is in the "devscripts" package in case you didn't have it installed. And make sure /usr/src/linux/include really contains your kernel header files; you may have to link /usr/src/kernel-headers-2.4.whatever to /usr/src/linux.

Compiling should have gone smoothly. Time to install the packages.

$ su
Password: ********
# dpkg -i ../ipsec-tools_*.deb ../racoon_*.deb

The startup init scripts

The default for the racoon package is to be started rather late in the boot process, like it was some kind of VPN daemon and not an essential network component. I use IPsec to the NIS server, to the NFS server, and other things, so I need to change the startup order:

# update-rc.d -f racoon remove
update-rc.d: /etc/init.d/racoon exists during rc.d purge (continuing)
 Removing any system startup links for /etc/init.d/racoon ...
   /etc/rc0.d/K20racoon
   /etc/rc1.d/K20racoon
   /etc/rc2.d/S20racoon
   /etc/rc3.d/S20racoon
   /etc/rc4.d/S20racoon
   /etc/rc5.d/S20racoon
   /etc/rc6.d/K20racoon
# update-rc.d racoon start 43 S . start 34 0 6 .
 Adding system startup for /etc/init.d/racoon ...
   /etc/rc0.d/S34racoon -> ../init.d/racoon
   /etc/rc6.d/S34racoon -> ../init.d/racoon
   /etc/rcS.d/S43racoon -> ../init.d/racoon
# 

Now, this change necessitates yet another patch; since we now start racoon before bootmisc.sh, the latter will now cheerfully delete the newly-created racoon runtime files. This is no good, and will bite us mightily when we try to stop racoon at system reboot or shutdown. So another patch, please, maestro:

# patch --strip=0 <<EOF
+++ /etc/init.d/bootmisc.sh	Fri May 14 12:01:31 2004
@@ -52,6 +52,7 @@
 [ "$VERBOSE" != no ] && echo -n "/var/run"
 ( cd /var/run && \
 	find . ! -type d ! -name utmp ! -name innd.pid \
+	! -name "pluto.*" ! -name "racoon.pid" \
 	! -newer /etc/mtab -exec rm -f -- {} \; )
 : > /var/run/utmp
 if grep -q ^utmp: /etc/group
EOF
patching file /etc/init.d/bootmisc.sh
# 

I have noticed that when using this setup, mounting network filesystems from an NFS server over an IPsec connection immediately after starting Racoon will fail (rather than simply be deferred until the IPsec SA is established as was the case with FreeS/WAN). I'm not sure why this is, but we can fix it by pinging the NFS servers before mounting.

We do this with a new script, /etc/init.d/ipsecfix, which is inserted after racoon and before mountnfs.sh:

# cat > /etc/init.d/ipsecfix <<EOF
#!/bin/bash -e
echo -n "Pausing..."
sleep 3
echo -n "done.  "

echo "Now pinging all NFS servers:"
awk '/^[^#]/&&$3=="nfs"{ sub(/:.*/, "", $1); print $1 }' /etc/fstab \
    | sort -u | xargs --no-run-if-empty --max-args=1 ping -q -c1
EOF
# chmod 755 /etc/init.d/ipsecfix
# update-rc.d ipsecfix start 44 S .
 Adding system startup for /etc/init.d/ipsecfix ...
   /etc/rcS.d/S44ipsecfix -> ../init.d/ipsecfix
# 

Now we can safely start and stop racoon. But it won't do anything without configuration.

Configuration files

I previously used FreeS/WAN, and its configuration was really flexible and powerful (if incomprehensible). So when I saw the racoon.conf file, I was disappointed. Well, in Debian our good friend the package maintainer has implemented a macro preprocessor for us in the form of "racoon-tool", which reads its own configuration file "/etc/racoon/racoon-tool.conf". It purports to imitate FreeS/WAN's configuration features, and does so after a fashion even if some features are still missing. In any case it's better than using racoon.conf directly.

Anyway, the configuration files. First, put your CA public cert and host key and certificate (all unencrypted and in PEM format) in /etc/racoon/certs/ as ca.crt, host.key, and host.crt, respectively. Then run, as root:

# cd /etc/racoon/certs
# ln -s ca.crt `openssl x509 -noout -hash -in ca.crt`.0
# chmod go-rwx host.key

That last command is just to make sure we didn't do something stupid.

I've put it off long enough, so here it is, the racoon-tool.conf file. I'm assuming a host name of "host.example.org" with IP address 333.333.333.333 and an IPsec connection to another host named "guest.example.org" with IP address 444.444.444.444. The file will have some default settings at the top and lots of commented-out examples. Keep those and add the following at the end.

peer(%default):
	certificate_type: x509 host.crt host.key
	my_identifier: fqdn host.example.org
	verify_identifier: on
	authentication_method[0]: rsasig
connection(%default):
	src_ip: 333.333.333.333

# Guest
peer(444.444.444.444):
	peers_identifier: fqdn guest.example.org
connection(guest):
	dst_ip: 444.444.444.444
	admin_status: enabled
#

With this configuration, we will no longer accept any non-IPsec packets from guest.example.org, and will also send only IPsec packets to that host. Now that's what I call real network security.

You then repeat that last section (the one enclosed by #'es) for all hosts you want to communicate securely with.

Pre-Shared Keys

Delete "authentication_method[0]", "certificate_type", and "my_identifier" to use the default values which use PSKs. Change "peers_identifier" to be set to "address" (and only the string "address") on each host section. Edit /etc/racoon/psk.txt to contain the keys for each hosts (which obviously must be different, for security). The format is like the /etc/hosts file, but the second field is the key, not a host name. Keys can be either a free-form string or hexadecimal, starting with "0x". Beware, there seems to be a limit of about 1022 characters or so per line.

This work is dedicated to the Public Domain.