Introduction

The story

I'm working for a small IT company that is growing quite well.  The direct result of this is that we recenlty left our old offices to find someplace bigger.  On the other hand, since the building we left is situated in a very nice neighborhood, and quite well equipped, a small part of the activity stayed behind.

Add to this one of the owners, who is very frequently working from home with his spouse (also working with us), some developpers who can't leave their code overnight, and you have a somewhat complex situation.

The situation

  1. The main network :
  2. The satellite offices :
  3. The other users :

The goals

To enable everybody to interact as transparently with the network as possible, with their everyday tools (Windows shares, etc), to allow the distant offices to use their IP phones on our network (thus greatly diminishing our phone bill).

To secure the inter-office communications, while still allowing each site to use it's internet access for browsing the web, using the mail, etc.

What I won't explain

The whole setup is greatly aided by the LDAP + DHCP + DNS + samba combination, but all that configuration process is way out of scope of this little page.  I'll just say when and how it interacts with everything else when it's useful.

I won't neither bore you to death about the compiling, installation of the different OSses and packages implied.

Configuring the racoon daemon

Overview

The idea is such : since all clients use dynamic IP addresses, as much the satellite offices as the roadwarriors (nomad users), the main server's config files will have to deal with anonymous blocks for IPSEC's phase 1.  The only way to distinguish between roadwarriors and whole subnets will be the authentication algorithms : the first will use hybrid authentication, the latter will use RSA certificates.

No policies will be setup on the server prior the connections, it will use the generate_policy directive to dynamically spawn whatever is needed on the fly.

Client-side, scripts will build the policies, as long as the tunnel is kicked into action at some point.

For the roadwarriors, the server will use a mode_cfg block to configure them, and the Cisco client will take care of the rest.

Building

All you need to know about it's installation is that it needs to be compiled with --enable-hybrid, --enable-natt, --enable-adminport and finally --with-libpam options.  In my setup, it's residing along the base system, with bits under /sbin and /usr/sbin ; it's configuration sits in /etc/raccon.

Common configuration

I find it easier to maintain a common core config file with the usual directives, and then to include a different file on each site.  Here's the common file :

rhum:/etc/raccon/racoon.conf
armagnac:/etc/racoon/racoon.conf

# Common configuration file path include "/etc/racoon" ; path pre_shared_key "/etc/racoon/psk.txt" ; path certificate "/etc/racoon/cert" ; path script "/etc/racoon" ; include "local.conf"; log notify; # "padding" defines some parameter of padding. You should not touch these. padding { maximum_length 20; # maximum padding length. randomize off; # enable randomize length. strict_check off; # enable strict check. exclusive_tail off; # extract last one octet. } # if no listen directive is specified, racoon will listen to all # available interface addresses. listen { adminsock "/var/racoon/racoon.sock"; } # Specification of default various timer. timer { # These value can be changed per remote node. counter 5; # maximum trying count to send. interval 20 sec; # maximum interval to resend. persend 1; # the number of packets per a send. # timer for waiting to complete each phase. phase1 30 sec; phase2 15 sec; }

Server configuration

Here's one of the biggest pieces.

rhum:/etc/raccon/local.conf

#### #### One remote block to rule them all... #### remote anonymous { exchange_mode main,aggressive; nonce_size 16; lifetime time 1440 min; # sec,min,hour initial_contact on; proposal_check obey; # obey, strict or claim my_identifier asn1dn; certificate_type x509 "rhum.crt" "rhum.pem"; verify_identifier on; support_proxy on; ike_frag on; weak_phase1_check on; script "phase1_up.sh" phase1_up; script "phase1_down.sh" phase1_down; generate_policy on; passive on; #### Permanent VPNs proposal { encryption_algorithm 3des; hash_algorithm md5; authentication_method rsasig; dh_group modp1024; } #### Roadwarriors proposal { encryption_algorithm 3des; hash_algorithm sha1; authentication_method hybrid_rsa_server; dh_group modp1024; } } #### #### Pineau #### sainfo address 192.168.0.0/16 any address 192.168.2.0/24 any { pfs_group modp1024; lifetime time 3 min; encryption_algorithm 3des; authentication_algorithm hmac_md5; compression_algorithm deflate; } #### #### Armagnac #### sainfo address 192.168.0.0/16 any address 192.168.3.0/24 any { pfs_group modp1024; lifetime time 3 min; encryption_algorithm 3des; authentication_algorithm hmac_md5; compression_algorithm deflate; } #### #### Roadwarriors #### sainfo anonymous { lifetime time 8 hour; encryption_algorithm 3des; authentication_algorithm hmac_md5; compression_algorithm deflate; } mode_cfg { auth_source pam; conf_source local; pool_size 180; network4 192.168.201.20; netmask4 255.255.255.255; dns4 192.168.1.1,192.168.1.2; wins4 192.168.1.1; split_network include 192.168.1.0/24,192.168.2.0/24,192.168.3.0/24; default_domain "local"; }

First, you see the anonymous remote block.  In that block, the really interesting bits are :

Next, you have two boring sainfo blocks.  The only thing worth of note is the asymetric shape of the subnets : that way, I force a star topology, with the main server at the center, but everyone has a VPN to everyone else.  The short lifetimes come in handy when the machines are disconnected and get a new IP.

The last sainfo anonymous block is used for the roadwarriors.  Again, it's directly understandable to the Cisco clients.

The mode_cfg block gives an IP range to use, and some useful information about my network topology to the clients.  I use PAM for the authentication, I'll detail that somewhat later.

Satellite office configuration

This file is somewhat easier, having to manage only one kind of connection, towards a fixed IP even.

armagnac:/etc/raccon/local.conf

#### #### Rhum #### remote 10.1.2.3 { exchange_mode main; nonce_size 16; lifetime time 1440 min; # sec,min,hour initial_contact on; proposal_check obey; # obey, strict or claim my_identifier asn1dn; certificate_type x509 "armagnac.crt" "armagnac.pem"; peers_identifier asn1dn; verify_identifier on; support_proxy on; ike_frag on; weak_phase1_check on; script "phase1_up_cli.sh" phase1_up; script "phase1_down_cli.sh" phase1_down; proposal { encryption_algorithm 3des; hash_algorithm md5; authentication_method rsasig; dh_group modp1024; } } #### #### SA #### sainfo address 192.168.3.0/24 any address 192.168.0.0/16 any { pfs_group modp1024; lifetime time 3 min; encryption_algorithm 3des; authentication_algorithm hmac_md5; compression_algorithm deflate; }

Of course, there are many common points with the preceding file.  The important stuff :

Scripts on the far side

Since those are the most important, I'll begin with the satellite offices.

armagnac:/etc/raccon/phase1_up_cli.sh

#!/bin/sh echo " spdadd 192.168.3.0/24[any] 192.168.3.0/24[any] any -P in none; spdadd 192.168.3.0/24[any] 192.168.3.0/24[any] any -P out none; spdadd 192.168.0.0/16[any] 192.168.3.0/24[any] any -P in ipsec esp/tunnel/${REMOTE_ADDR}-${LOCAL_ADDR}/require; spdadd 192.168.3.0/24[any] 192.168.0.0/16[any] any -P out ipsec esp/tunnel/${LOCAL_ADDR}-${REMOTE_ADDR}/require; " | /sbin/setkey -c /sbin/ping -c5 192.168.1.1 >/dev/null 2>&1

At the stablishment of the connection, I setup two pairs of SPD policies, using the addresses gathered through the phase1.  The first one tells the system it shouldn't try to encrypt the communications on the local network.  It's needed because the second one uses a subnet which englobes the local subnet.  Without that, no machine on the local net can reach the server directly, which is quite annoying.

The last part simply serves to bring the phase2 up immediately ; 192.168.1.1 is another server on the main network.

armagnac:/etc/raccon/phase1_down_cli.sh

#!/bin/sh echo " deleteall ${REMOTE_ADDR} ${LOCAL_ADDR} esp; deleteall ${LOCAL_ADDR} ${REMOTE_ADDR} esp; spddelete 192.168.3.0/24[any] 192.168.0.0/16[any] any -P out ipsec esp/tunnel/${LOCAL_ADDR}-${REMOTE_ADDR}/require; spddelete 192.168.0.0/16[any] 192.168.3.0/24[any] any -P in ipsec esp/tunnel/${REMOTE_ADDR}-${LOCAL_ADDR}/require; " | /sbin/setkey -c

This script simply destroys the entries added by previously.  I keep my safeguarding none entries, just in case.

Scripts on the main network

Those two scripts serve no real value to the ISAKMP side of the setup, but give some comfort to the users.

rhum:/etc/raccon/phase1_up.sh

#!/bin/sh IPFW=/sbin/ipfw if [ ! -z ${XAUTH_USER} ] ; then echo "update delete ${XAUTH_USER}-vpn.local " | /usr/bin/nsupdate echo "update add ${XAUTH_USER}-vpn.local 86400 A ${INTERNAL_ADDR4} " | /usr/bin/nsupdate #GID=`/usr/bin/id -G ${XAUTH_USER}` fi

Here, I simply use the username sent during the XAuth exchange (if any) to inscribe the roadwarrior into the local DNS (I should inscribe it's revers DNS too).  The steps needed to setup this on the DNS server side are left as en exercise to the reader.

Note that, since I use LDAP + PAM + NSS, I can query a group id (id -G) for the logged on user ; initialy, I meant to use it to setup firewall rules to keep some groups of users from accessing some sensitive parts of the network.  It has still to be done.

rhum:/etc/raccon/phase1_down.sh

#!/bin/sh if [ ! -z ${XAUTH_USER} ] ; then echo "update delete ${XAUTH_USER}-vpn.local A " | /usr/bin/nsupdate fi

Again, the exact contrary : once the user logs off, I delete his DNS entry, and I could flush the firewall rules I'd have added previously.

Routing

The setup isn't be complete until you add some routes.  Most of the route commands are OS specific, but the principle is that you need to add a route for the remote network using the internal address of your tunnel as a gateway.  On my NetBSD machines, it went like this on the server :

rhum

/sbin/route add -net 192.168.0.0/16 192.168.1.254 -ifp ex0

And on the other side :

armagnac

/sbin/route add -net 192.168.0.0/16 192.168.3.1 -ifp rtk0

Other points of interest

Certificates

I have generated a root CA certificate and keys for my use here.  I've then used the CA to sign a key per fixed node in this setup.  The CA certificate and the host certificates for both local and remote nodes are required to be installed on each machine, in the /etc/racoon/cert/ directory.  The private key of each machine should be copied into that directory too.  Finally, a "magic" symbolic link (or copy of the file, actually) must be made to the root CA certificate.

The magic command to type in this case is : ln -s ca_cert.pem `openssl x509 -noout -hash -in ca_cert.pem`.0.

In fewer words, here's how it looks like on the main server :

rhum:/etc/racoon/cert/*

total 11 lrwxr-xr-x 1 root wheel 11 Sep 10 18:10 35775e56.0 -> CA_mims.crt -rw------- 1 root wheel 1241 Feb 10 2005 CA_mims.crt -rw------- 1 root wheel 1326 Sep 19 15:16 armagnac.crt -rw------- 1 root wheel 1322 Feb 10 2005 pineau.crt -rw------- 1 root wheel 1322 Mar 21 2005 rhum.crt -rw------- 1 root wheel 887 Mar 21 2005 rhum.pem -rw------- 1 root wheel 1322 Feb 10 2005 vodka.crt

And on the other node :

armagnac:/etc/racoon/cert/*

total 8 lrwxr-xr-x 1 root wheel 11 Sep 10 18:01 35775e56.0 -> CA_mims.crt -rw------- 1 root wheel 1241 Feb 10 2005 CA_mims.crt -rw------- 1 root wheel 1326 Sep 19 15:16 armagnac.crt -rw------- 1 root wheel 887 Sep 19 15:14 armagnac.pem -rw------- 1 root wheel 1322 Sep 10 18:16 rhum.crt

I will not give a detailed tutorial on how to generate the CA and the certificates, because it's out of scope in this document, and, too, because I'm pretty unable to do it.  On the other hand, I found a wonderful little opensource software, xca, that can handle all of this for me...

Roadwarrior authentication

As I said before, I use PAM for this.  The config file is boring :

rhum:/etc/pam.d/raccon

# PAM configuration for the "racoon" service auth required pam_nologin.so no_warn auth include system account include system session include system password include system

This means that any user that can log on locally on a machine can use a VPN.  Paranoid admins will probably configure more restrictions.

By the way, my PAM system uses pam_ldap.so, the nsswitch.conf is configured to also use nss_ldap.so, as well as samba and quite a few daemons (directly or via PAM) ; this allows me to centralize users for all the aspects of the system in one repository - with all the benefits and the risks this entails.

Cisco client configuration

I'm using Cisco's VPN client (versions 4.6 and 4.8).  The configuration is quite straightforward :

NetBSD specifics

The startup scripts

Finally, I will add a few words about the startup.

Indeed, the weakest point of all this is that all the configuration above will do everthing you need but one thing : start automatically the VPN if it ever goes down, or wen the machine boots.

To solve that precise problem, there's no universal way.  Since I use NetBSD on my gateways, I'll show you how it's done with it, but Linux or FreeBSD users will probably have to think about it themselves.

The NetBSD OS offers a nice tool on top of it's ppp(oe) implementation : ifwatchd.  The handbook instructs you to add ifwatchd=YES in your /etc/rc.conf file and to use two scripts, /etc/ppp/ip-up and /etc/ppp/ip-down for the permanent ADSL connections.

While those scripts are necessary to setup default routes; the can also be used to kick a VPN into action.  Here's my current version of the up script (on the far office) :

armagnac:/etc/ppp/ip-up

#!/bin/sh /sbin/route add default $5 /etc/rc.d/ipnat forcestart /etc/rc.d/ntpd stop /etc/rc.d/ntpdate start /etc/rc.d/ntpd start /etc/rc.d/ipsec forcestop /etc/rc.d/racoon forcestart ! /bin/sleep 5 ! /usr/sbin/racoonctl 10.1.2.3 &

And the down one :

armagnac:/etc/ppp/ip-down

#!/bin/sh /sbin/route delete default $5 /etc/rc.d/ipnat forcestop /etc/rc.d/racoon forcestop /etc/rc.d/ipsec forcestop

Those are somewhat messy, and I'm not entirely sure of their efficiency.  Time will tell.

I should note too that I had to set the sysctl net.inet.ip.redirect to 0 to stop the machine from sending icmp redirects for each packet that went through.

Thanks

To Emmanuel Dreyfus, who has brought me screaming and kicking into the wonderful world of IPSEC...

To Aidas Kasparas, who put me on the right track about this setup, with much precision and patience.

To my boss, who allowed me to code on this during working hours...

Back - contact me

Page last updated the 27/10/2005 - XHTML 1.1 strict and CSS 2.0.