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
- The main network :
- Subnet : 192.168.1.0/24
- Inetrnet gateway : rhum, 192.168.1.254, a small NetBSD box
- Machines : FreeBSD, NetBSD, Linux and Windows servers, mostly Windows clients
- Telephony : IP phones, PABX
- Software : isc-dhcpd, openldap, bind, samba, racoon
- Internet access : professionnal ADSL, with fixed IP
- The satellite offices :
- Subnets : 192.168.2.0/24 and 192.168.3.0/24
- Internet gateways : pineau, 192.168.2.1 and armagnac, 192.168.3.1, two other NetBSD boxes
- Machines : Windows clients exclusively
- Telephony : one IP phone at each site
- Software : the same, mirrored where possible (slave bind, replicated openldap, samba BDC, etc)
- Internet access : normal ADSL lines, dynamic IPs, different ISPs
- The other users :
- Subnets : all and everything, often NATted towards the internet
- Machines : single Windows clients
- Software : Cisco VPN client
- Internet access : normal ADSL lines
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
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
{
maximum_length 20;
randomize off;
strict_check off;
exclusive_tail off;
}
listen
{
adminsock "/var/racoon/racoon.sock";
}
timer
{
counter 5;
interval 20 sec;
persend 1;
phase1 30 sec;
phase2 15 sec;
}
Server configuration
Here's one of the biggest pieces.
rhum:/etc/raccon/local.conf
remote anonymous
{
exchange_mode main,aggressive;
nonce_size 16;
lifetime time 1440 min;
initial_contact on;
proposal_check obey;
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;
proposal {
encryption_algorithm 3des;
hash_algorithm md5;
authentication_method rsasig;
dh_group modp1024;
}
proposal {
encryption_algorithm 3des;
hash_algorithm sha1;
authentication_method hybrid_rsa_server;
dh_group modp1024;
}
}
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;
}
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;
}
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 :
- exchange_mode main,aggressive : Cisco VPN client works in aggressive mode, while I prefer to use main mode for the other clients.
- my_identifier asn1dn and certificate_type x509 "rhum.crt" "rhum.pem" : both the rsasig and hybrid rsa modes need a certificate for the server ; here is it. I'll say a word about certificates generation further below in this document.
- The two script statements : they aren't essential to this setup, but I use them nonetheless they are described below too.
- generate_policy on and passive on : on the contrary, those two are essential ; it says basically that all policies will be generated on the fly.
- The two proposal blocks : Those are, of course, essential too ; the different authentication_method serve for each kind of clients ; the roadwarriors' block works perfectly well with recent Cisco VPN clients.
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
remote 10.1.2.3
{
exchange_mode main;
nonce_size 16;
lifetime time 1440 min;
initial_contact on;
proposal_check obey;
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;
}
}
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 :
- No anonymous directive : the server is known, and we're not here to answer to anybody over the web.
- No passive on : one side has to start the dance...
- my_identifier asn1dn, peers_identifier asn1dn : here, we make sure both sides will use certificates.
- Two other scripts : I like to keep my script names different depending on the side they're on ; although simple, those scripts are critical to the whole setup.
- The proposals and sainfo blocks : they must be compatible with the other side ; since I control everything here, it's evidently easier to keep it as simple as possible, so they are exactly identical (except for the inversed subnets of the sainfo).
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
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
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
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
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
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
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 :
- In the certificates menu, choose import, select the path of the CA certificate (it will not be visible in the list unless you check the option to show the CA certificates in the same menu).
- Crate a new VPN entry, give it a name, and enter the hostname of the VPN server.
- Select the 'Mutual Group Authentication' option (it's the term used by Cisco to designate hybrid authentication).
- In the name field and password fields, you can enter about anything in fact, this setup relies entierly on the XAuth exchange (as described above) to authenticate the client (the server is authenticated by the certificates exchange, though).
- The other options should be left alone.
- Save.
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
/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
/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.