Search:  
Gentoo Wiki

HOWTO_IPSEC

This article is part of the HOWTO series.
Installation Kernel & Hardware Networks Portage Software System X Server Gaming Non-x86 Emulators Misc

Document Status: DRAFT

Wikipedia has an article on:
IPsec

Contents

Preface

Motivation

IPSec was developed for IPv6. Its intention is to secure network communications at the IP layer, instead of at the presentation or application layer. The lower in the OSI model you secure your communications, the more transparent that security becomes. If security is not transparent to the user, there is a chance the user may choose not to use it. By using a lower layer security protocol to make encryption and authenticaiton transparent to the user, we can more easily guarantee that the security measures will be utilized by the user.

Aside from encryption, IPSec can also guarantee the identity of the computer you are communicating with. This can prevent man-in-the-middle attacks, IP spoofing attacks, ARP poisoining attacks, etc. If used widely across the entire Internet, it could even prevent fraudulent Internet transanctions, spoofed websites used in Phishing, etc. This level of deployment, however, would require a concertated effort by the entire Internet community. As IPv6 becomes more widely deployed, this may eventually become a reality.

This HOWTO intends to make it easy to setup IPSec secured connections using your Gentoo box. Good luck!

Prerequisites

Kernel Configuration

Compile a 2.6.x kernel with the following options enabled:

Linux Kernel Configuration: for IPSec
Networking  --->
  [*] Networking support
     Networking options  --->
       <M> IPsec user configuration interface
       <M> PF_KEY sockets
       <M> IP: AH transformation
       <M> IP: ESP transformation
       <M> IP: IPComp transformation

Note: In later kernels IPsec user configuration interface was renamed to Transformation user configuration interface

You also MUST activate encryption and hash algorithms within the Crypto section of the kernel. Enabling them as modules is fine though.

Packages to install

emerge -v ipsec-tools
emerge -v iptables
emerge -v iproute2

Please note, do not start the provided init script yet.

The Manual Way

Prepare Your Firewall

You must be able to send/receive packets from certain UDP ports (and other protocols?).

What we need

using iptables

You must accept all traffic regarding the ports/protocols mentioned above:

iptables -A INPUT -p udp --dport 500 -m state --state NEW -j ACCEPT
iptables -A OUTPUT -p udp --dport 500 -m state --state NEW -j ACCEPT

iptables -A INPUT -p esp -j ACCEPT
iptables -A OUTPUT -p esp -j ACCEPT

iptables -A INPUT -p ah -j ACCEPT
iptables -A OUTPUT -p ah -j ACCEPT

Statically Securing Host-to-Host Communication

This is usually the easiest way to configure IPsec for two hosts.

Host Network Configuration

Here I'm using faked IP addresses and subnet. You may guess why ;)

Configuring Host A (111.222.333.444)

File: /etc/conf.d/racoon
RACOON_OPTS="-4 -l /var/log/racoon.log"
RACOON_CONF="/etc/racoon/racoon.conf"
RACOON_PSK_FILE="/etc/racoon/psk.txt"
SETKEY_CONF="/etc/ipsec.conf"
RACOON_RESET_TABLES="true"
File: /etc/ipsec.conf
#!/usr/sbin/setkey -f

# Flush the SAD and SPD
flush;
spdflush;

# Attention: Use these keys for testing purposes only!
# Generate your own keys!

# AH SAs using 128 bit long keys
add 111.222.333.444 555.666.777.888 ah 0x200 -A hmac-md5
0x88dfd37ce0d4b0641f3c14fa9197301c;
add 555.666.777.888 111.222.333.444 ah 0x300 -A hmac-md5
0x91bc25a6e4c1e8e592bd9d2cbd09ff0b;

# ESP SAs using 192 bit long keys
add 111.222.333.444 555.666.777.888 esp 0x201 -E rijndael-cbc
0x61272157401bf304177fa8ac0c38de4095992d06c0499cf7;
add 555.666.777.888 111.222.333.444 esp 0x301 -E rijndael-cbc
0x49fce5b82ff7acc4d6aded691a0f5f9a65e18861ad4b66bf;

spdadd 111.222.333.444 555.666.777.888 any -P out ipsec
       esp/transport//require
       ah/transport//require;

spdadd 555.666.777.888 111.222.333.444 any -P in ipsec
       esp/transport//require
       ah/transport//require;

Configuring Host B (555.666.777.888)

For here, the configuration looks quite the same.

File: /etc/conf.d/racoon
RACOON_OPTS="-4 -l /var/log/racoon.log"
RACOON_CONF="/etc/racoon/racoon.conf"
RACOON_PSK_FILE="/etc/racoon/psk.txt"
SETKEY_CONF="/etc/ipsec.conf"
RACOON_RESET_TABLES="true"

However, please note, that the only thing within the configuration files that differ from host A and B is the in/out order of the spdadd lines.

File: /etc/ipsec.conf
#!/usr/sbin/setkey -f

# Flush the SAD and SPD
flush;
spdflush;

# Attention: Use these keys for testing purposes only!
# Generate your own keys!

# AH SAs using 128 bit long keys
add 111.222.333.444 555.666.777.888 ah 0x200 -A hmac-md5
0x88dfd37ce0d4b0641f3c14fa9197301c;
add 555.666.777.888 111.222.333.444 ah 0x300 -A hmac-md5
0x91bc25a6e4c1e8e592bd9d2cbd09ff0b;

# ESP SAs using 192 bit long keys
add 111.222.333.444 555.666.777.888 esp 0x201 -E rijndael-cbc
0x61272157401bf304177fa8ac0c38de4095992d06c0499cf7;
add 555.666.777.888 111.222.333.444 esp 0x301 -E rijndael-cbc
0x49fce5b82ff7acc4d6aded691a0f5f9a65e18861ad4b66bf;

spdadd 111.222.333.444 555.666.777.888 any -P in ipsec
      esp/transport//require
      ah/transport//require;

spdadd 555.666.777.888 111.222.333.444 any -P out ipsec
      esp/transport//require
      ah/transport//require;

Loading the Configuration

On both hosts, load the configuration by starting the ipsec-tools racoon init script like below:

/etc/init.d/racoon start

Testing

Host-a will ping host-b:

Code: ping -c4 host-b
 PING host-b (555.666.777.888) 56(84) bytes of data.
 64 bytes from host-b (555.666.777.888): icmp_seq=1 ttl=59 time=54.5 ms
 64 bytes from host-b (555.666.777.888): icmp_seq=2 ttl=59 time=55.1 ms
 64 bytes from host-b (555.666.777.888): icmp_seq=3 ttl=59 time=54.8 ms
 64 bytes from host-b (555.666.777.888): icmp_seq=4 ttl=59 time=55.1 ms
 
 --- host-b ping statistics ---
 4 packets transmitted, 4 received, 0% packet loss, time 3002ms
 rtt min/avg/max/mdev = 54.548/54.919/55.130/0.232 ms

While doing some traffic from host-A to host-B we can (on host A) sniff the traffic using tcpdump (or alike). You should see the following output (from tcpdump):

Code: tcpdump
[...]
19:30:16.661723 IP host-A > host-B: AH(spi=0x069623f6,seq=0x4a): ESP(spi=0x0b691cf7,seq=0x4a)
19:30:16.716527 IP host-B > host-A: AH(spi=0x05137270,seq=0x48): ESP(spi=0x0dd7604e,seq=0x48)

19:30:17.662021 IP host-A > host-B: AH(spi=0x069623f6,seq=0x4b): ESP(spi=0x0b691cf7,seq=0x4b)
19:30:17.717120 IP host-B > host-A: AH(spi=0x05137270,seq=0x49): ESP(spi=0x0dd7604e,seq=0x49)
[...]

When you though see lots of AH and ESP traffic, then you have succeeded. Have a look at tcpdump when sniffing for plaintext ICMP ping requests/responses to compare.

So, when you're done with this, not only is the ping traffic secured, all traffic is secured.

Creating your own random keys

You can easily create your own random keys for manual keying:

$ # 128 bit keys
$ dd if=/dev/random count=16 bs=1| xxd -ps -
16+0 records in
16+0 records out
66cae55a472213e942da2275af5896d3

$ # 192 bit keys
$ dd if=/dev/random count=24 bs=1| xxd -ps -
24+0 records in
24+0 records out
bd94fe3cadd714e07a8ea8c4dc4ce1282c1b6a6ae79979cd

xxd is part of the vim-core package. An emerge vim-core will allow you to use it. Now, you can edit the file: /etc/racoon/psk.txt:

  111.222.333.444  shared_key
  555.666.777.888  shared_key

NOTE: The two shared keys have the same value.

IPsec tunnels

FIXME

Algorithms presentation

Include a presentation/discussion of the available algorithms so people can choose wisely between them.

Automated IPSec Tunnels / Transports / Firewalling

Introduction

Creating IPSec tunnels and transport connections between a single host by hand takes fairly little time and effort -- especially if you use pre-shared keys. However, if you need to configure multiple tunnels between multiple hosts, manual configuration of IPSec tunnels and transport connections becomes extremely tedious. Things get worse when you are trying to make a connection to your home network from on the road. In this case, you probably won't know in advance what IP address you will be connecting from.

To combat these issues, I will present a more automated way of configuring IPSec tunnels and transport connections. I will also present how to configure Windows XP with Service Pack 2 to connect to your Gentoo system using IPSec.

For this new method of IPSec, we will use X.509 digital certificates for authentication.

Creating a Certificate Authority

If you do not already have OpenSSL installed, you will need to install it now:

emerge openssl

After OpenSSL is fully installed, we need to create a folder for storing our certificates. I use /etc/certs:

bash ~ # mkdir /etc/certs && chmod 700 /etc/certs && cd /etc/certs

Once inside the folder, we need to create a Certificate Authority. But, before we do so, we need to ensure we generate the CA certificate with the correct parameters. Edit /etc/ssl/openssl.cnf to ensure the following settings:

bash certs # vim /etc/ssl/openssl.cnf
File: /etc/ssl/openssl.cnf
[ CA_default ]

...<snip>...

x509_extensions = v3_ca     # The extentions to add to the cert

...<snip>...

[ req ]

...<snip>...

x509_extensions = v3_req    # The extentions to add to the self signed cert

...<big snip>...

[ v3_req ]

# Extensions to add to a certificate request

basicConstraints = CA:FALSE
keyUsage = nonRepudiation, digitalSignature, keyEncipherment

[ v3_ca ]

...<snip>...

basicConstraints = CA:true

...<snip>...

keyUsage = cRLSign, keyCertSign

These settings basically tell OpenSSL to generate the CA certificate as a CA (basicConstraints=CA:true) and that the certificate is used for signing. They also tell OpenSSL to generate certificate requests as a non-CA certificate (basicConstraints=CA:FALSE), and to set the flags on the requested certificates for nonRepudiation, digitalSignature, and keyEncipherment. All of these settings are required for the IPSec tunnel to establish.

OpenSSL provides a script to generate a new Certificate Authority. From inside /etc/certs, issue the following command to create the CA:

bash certs # /etc/ssl/misc/CA.sh -newca

After you have created your Certificate Authority, you need to issue a certificate for your Gentoo box. To issue and manage certificates, we will use three scripts. Place these inside /etc/certs (or wherever you chose to store your certificates):

File: /etc/certs/issue
#!/bin/bash
#
# Author: Eliot Gable <e gable AT@AT gmail .DOT. com>
# Copyright (c) 4/22/2006
# Distributed under the terms of the GNU General Public License v2

NAME=$1

/etc/ssl/misc/CA.sh -newreq
/etc/ssl/misc/CA.sh -sign
mv newcert.pem ${NAME}_cert.pem
rm newreq.pem
mv newkey.pem ${NAME}_key.pem
openssl rsa -in ${NAME}_key.pem -out ${NAME}_key.pem
chmod 600 ${NAME}*.pem
File: /etc/certs/revoke
#!/bin/bash
#
# Author: Eliot Gable <e gable AT@AT gmail .DOT. com>
# Copyright (c) 4/22/2006
# Distributed under the terms of the GNU General Public License v2

openssl ca -revoke $1
File: /etc/certs/create_pfx
#!/bin/bash
#
# Author: Eliot Gable <e gable AT@AT gmail .DOT. com>
# Copyright (c) 4/22/2006
# Distributed under the terms of the GNU General Public License v2

openssl pkcs12 -export -in ${1}_cert.pem -inkey ${1}_key.pem -out ${1}.pfx -name "IPSEC Cert for Home"
chmod 600 ${1}.pfx

Set these three scripts so they are executable:

bash certs # chmod 700 issue
bash certs # chmod 700 revoke
bash certs # chmod 700 create_pfx

Now, before you start issuing certificates, we need to edit /etc/ssl/openssl.cnf again. Specifically, you should modify these lines accordingly:

File: /etc/ssl/openssl.cnf

[ CA_default ]

...<snip>...

x509_extensions = v3_req        # The extentions to add to the cert

...<snip>...

[ req_distinguished_name ]
countryName                     = Country Name (2 letter code)
countryName_default             = US
countryName_min                 = 2
countryName_max                 = 2

stateOrProvinceName             = State or Province Name (full name)
stateOrProvinceName_default     = MyState

localityName                    = Locality Name (eg, city)
localityName_default            = MyCity

0.organizationName              = Organization Name (eg, company)
0.organizationName_default      = MyCompany

# we can do this but it is not needed normally :-)
#1.organizationName             = Second Organization Name (eg, company)
#1.organizationName_default     = World Wide Web Pty Ltd

organizationalUnitName          = Organizational Unit Name (eg, section)
organizationalUnitName_default  = MyUnitName

It is imperative that you change the x509_extensions line in the CA_default section back to v3_req before you issue certificates for your Gentoo box or for your client devices, otherwise they will be issued with the signing keyUsage settings used on the CA certificate. After you have set your defaults appropriately, it is time to issue your first certificate:

bash certs # ./issue myhost.mydomain.com

You will need to enter a password for the new certificate when prompted. Then, fill out the rest of the information as requested. For the common name, you can either enter something descriptive (like "VPN Cert"), or you can enter the host + domain name for the machine, like you would for a webserver certificate. After entering all of the requested information, you will have a chance to sign the certificate with your CA, where you will be prompted for your Certificate Authority password which you chose when setting up your CA.

After successfully signing the new certificate, you will be prompted for your new certificate's password. This step is required in order to generate a non-password protected key file. Racoon (the daemon that does the IPSec stuff) does not support password encrypted key files. When this process is complete, you will see two new files in /etc/certs: myhost.mydomain.com_cert.pem and myhost.mydomain.com_key.pem. These are your certificate and certificate key files, respectively.

After completing your first certificate, you will need to generate another one for your client machine. Go ahead and do that now, using the same 'issue' command and a different name for the client certificate. If your client machine will be a Windows machine, you will need to create a PFX file for importing the certificate and key into Windows. You can do that like so:

bash certs # ./create_pfx myclient.mydomain.com

It will prompt you for an export password which you will need in order to import the certificate and key into Windows. Make sure you do not forget this password, or you will not be able to import the certificate and key into Windows.

Do not do anything else with the client certificate yet (do not copy it to your Windows machine or anywhere else -- just leave it sit right there). We will cover the client setup later, including how to securely copy the certificate to your Windows machine.

Finally, we need to create a link to the CA certificate that Racoon can use to validate the client certificates:

bash certs # ln -s MyCA/cacert.pem `openssl x509 -noout -hash < MyCA/cacert.pem`.0

If you maintain a certificate revocation list, you need to do this for the CRL, too:

bash certs # ln -s MyCA/cacrl.pem `openssl crl -noout -hash < MyCA/cacrl.pem`.r0

Init Script and Config File

To automate the setup of IPSec tunnels, I have created an easy-to-use configuration file (/etc/conf.d/ipsec) and a corresponding init script which does all the heavy lifting. You will need to create these files on your Gentoo system since Gentoo does not come with them by default:

File: /etc/conf.d/ipsec
# IPSec/ISAKMP Configuration File
#
# Author: Eliot Gable <e gable AT@AT gmail .DOT. com>
# Copyright (c) 4/22/2006
# Distributed under the terms of the GNU General Public License v2


debug_ipsec="off"
certificate_path="/etc/certs"
psk_path="/etc/racoon/psk.txt"

# If the 'listen' variable is configured, the array of values
# are dumped directly into the 'listen { }' section of
# racoon.conf as entered here. To find out what you can specify
# and the format required, man racoon.conf.
listen=(
        "isakmp 111.111.111.111 [500]"
        "isakmp_natt 111.111.111.111 [4500]"
        "isakmp 192.168.0.1 [500]"
        "isakmp_natt 192.168.0.1 [4500]"
)

# For any IPSec connection, you can specify:
#   ul_proto <any/ip6/ip4/Upper layer protocol to apply IPSec to>
#   protocol <ah/esp/ipcomp> level <use/require>
#   encryption_algorithm <rijndael/3des/etc>
#   hash_algorithm <md5/sha1/sha256/sha384/sha512/etc>
#   compression_algorithm <none/deflate>
#   authentication_algorithm <hmac_sha1/hmac_md5/etc>
#   authentication <psk/X.509>
#     If authentication==psk:
#       psk <your pre-shared key>     ** NOTE: pre-shared key support is not yet completed
#     If authentication==X.509:
#       certificate <certificate name relative to certificate_path>
#       certificate_key <cert key relative to certificate_path>

# For details on which algorithms and key lengths can be used, man setkey

# Here, we define a tunnel to a work location
# For tunnels, we can specify:
#   src_net           - Source network block/IP
#   dst_net           - Destination network block/IP
#   src_port          - Source port
#   dst_port          - Destination port
#   src_gw_ip         - Source gateway IP
#   dst_gw_ip         - Destination gateway IP
tunnel_hometowork=(
        "src_net 192.168.0.0/24"
        "dst_net 192.168.1.0/24"
        "src_gw_ip 111.111.111.111"
        "dst_gw_ip 222.222.222.222"
        "ul_proto any"
        "protocol esp level require"
        "encryption_algorithm aes"
        "compression_algorithm deflate"
        "hash_algorithm md5"
        "authentication X.509"
        "certificate myhost.mydomain.com_cert.pem"
        "certificate_key myhost.mydomain.com_key.pem"
)
iptables_hometowork=(
        "INPUT -s 192.168.1.0/24 -j ACCEPT"
        "OUTPUT -d 192.168.1.0/24 -j ACCEPT"
        "FORWARD -s 192.168.1.0/24 -j ACCEPT"
        "FORWARD -d 192.168.1.0/24 -j ACCEPT"
        "INPUT -s 222.222.222.222 -j ACCEPT"
        "OUTPUT -d 222.222.222.222 -j ACCEPT"
)

transport_work2=(
        "src_ip 111.111.111.111"
        "dst_ip 333.333.333.333"
        "ul_proto any"
        "protocol esp level require"
        "protocol ah level require"
        "encryption_algorithm aes"
        "hash_algorithm sha1"
        "authentication X.509"
        "compression_algorithm deflate"
        "certificate myhost.mydomain.com.pem"
        "certificate_key myhost.mydomain.com.pem"
)
iptables_work2=(
        "INPUT -s 333.333.333.333 -j ACCEPT"
        "OUTPUT -d 333.333.333.333 -j ACCEPT"
)

# This enables connections while traveling on the road when you do not know your
# IP address information.
roadwarrior=(
        "status enable"
        "authentication X.509"
        "certificate myhost.mydomain.com_cert.pem"
        "certificate_key myhost.mydomain.com_key.pem"
        "encryption_algorithm 3des"
        "hash_algorithm sha1"
        "authentication_algorithm hmac_sha1"
        "compression_algorithm deflate"
)

After you have created your configuration file, you will need to create the init script (which should not be modified unless you really know what you are doing):

File: /etc/init.d/ipsec
#!/sbin/runscript
#
# Author: Eliot Gable <e gable AT@AT gmail .DOT. com>
# Copyright (c) 4/22/2006
# Update: 5/2/2006
#    Fixed 2 bugs that crop up on newer version of setkey
# Distributed under the terms of the GNU General Public License v2


depend() {
        need net
}

start() {
        create_policies || return 1
        create_firewall_rules || return 1
        create_racoon_conf || return 1
}

stop() {
        if [ -x /var/lib/ipsec/remove_firewall ]; then
                /var/lib/ipsec/remove_firewall
        fi
        if [ -x /var/lib/ipsec/remove_routes ]; then
                /var/lib/ipsec/remove_routes
        fi
        # This is a slightly overblown way of killing racoon if it is running
        if [ -e /service/racoon ]; then
                ebegin "Bringing down racoon using daemontools"
                svc -d /service/racoon   &>/tmp/error
                ewend $? $(cat /tmp/error 2>/dev/null && rm -f /tmp/error 2>/dev/null)
                # At the moment, we are going to trust that daemontools really killed racoon.
                # We really should check up on it, though, like we do below.
        else
                if [ -x /etc/init.d/racoon ] && [ -e /var/lib/init.d/started/racoon ]; then
                        /etc/init.d/racoon stop
                else
                        if [ -r /var/run/racoon.pid ] && [ "$(ps ax | grep racoon | grep -v grep)" ]; then
                                PID=$(cat /var/run/racoon.pid)
                                ebegin "Terminating racoon PID ${PID}"
                                kill -SIGTERM ${PID}   &>/dev/null
                                LOOP1=1
                                while [ "$(ps ax | grep ${PID} | grep -v grep)" ] && (( $LOOP1 < 3 )); do
                                        LOOP2=1
                                        while [ "$(ps ax | grep ${PID} | grep -v grep)" ] && (( $LOOP2 < 5 )); do
                                                printf "."
                                                sleep 1
                                                LOOP2=$((LOOP+1))
                                        done
                                        if [ "$(ps ax | grep ${PID} | grep -v grep)" ]; then
                                                kill -SIGKILL ${PID}  &>/dev/null
                                                printf "K"
                                        fi
                                done
                                if [ "$(ps ax | grep ${PID} | grep -v grep)" ]; then
                                        ewend 1 "Could not kill the racoon! Something is wrong."
                                        return 1
                                else
                                        ewend 0 ""
                                fi
                        else
                                einfo "Racoon PID file not found."
                                if [ "$(ps ax | grep racoon | grep -v grep)" ]; then
                                        ebegin "Terminating racoon's life"
                                        killall -SIGTERM racoon
                                        LOOP1=1
                                        while [ "$(ps ax | grep racoon | grep -v grep)" ] && (( $LOOP1 < 3 )); do
                                                LOOP2=1
                                                while [ "$(ps ax | grep racoon | grep -v grep)" ] && (( $LOOP2 < 5 )); do
                                                        printf "."
                                                        sleep 1
                                                        LOOP2=$((LOOP+1))
                                                done
                                                if [ "$(ps ax | grep racoon | grep -v grep)" ]; then
                                                        killall -SIGKILL racoon
                                                        printf "K"
                                                fi
                                        done
                                        if [ "$(ps ax | grep racoon | grep -v grep)" ]; then
                                                ewend 1 "Could not kill the racoon! Something is wrong."
                                                return 1
                                        else
                                                ewend 0 ""
                                        fi
                                else
                                        einfo "Racoon not running (maybe it's sleeping)."
                                fi
                        fi
                        rm -f /var/run/racoon.pid
                fi
        fi

        # The racoon should now be thuroughly dead
        # Flush the SAD and SPD
        ebegin "Flushing IPSec policies"
        setkey -P -F  &>/tmp/error
        ewend $? $(cat /tmp/error 2>/dev/null && rm -f /tmp/error 2>/dev/null)
        rm -f /var/lib/ipsec/remove_routes
}

restart() {
        svc_stop
        svc_start
}

create_policies() {
        # First, clear out any old policies
        ebegin "Flushing old policies"
        setkey -P -F  &>/tmp/error
        ewend $? $(cat /tmp/error 2>/dev/null && rm -f /tmp/error 2>/dev/null)

        # Start a new script for removing any routes we add
        mkdir -p /var/lib/ipsec
        printf "#!/bin/bash\n\nsource /sbin/functions.sh\n\n" > /var/lib/ipsec/remove_routes
        chmod 750 /var/lib/ipsec/remove_routes

        # Loop through the IPSec tunnels/transports and create appropriate policies
        for tun in ${!tunnel*}; do
                unset src_net dst_net src_gw_ip dst_gw_ip src_ip dst_ip src_port dst_port ul_proto esp_level ah_level ipcomp_level
                unset esp_proto_sd esp_proto_ds ah_proto_sd ah_proto_ds ipcomp_proto_sd ipcomp_proto_ds
                unset policy1 policy2 policy3 policy4 policy5 policy6 policy7 policy8
                TUN="tunnel=(\"\${${tun}[@]}\")"
                eval $TUN
                # Extract all of the options for the tunnel
                for i in ${!tunnel[*]}; do
                        if [[ "src_net" == ${tunnel[${i}]:0:7} ]]; then
                                local src_net=${tunnel[${i}]##src_net }
                        fi
                        if [[ "dst_net" == ${tunnel[${i}]:0:7} ]]; then
                                local dst_net=${tunnel[${i}]##dst_net }
                        fi
                        if [[ "src_port" == ${tunnel[${i}]:0:8} ]]; then
                                local src_port="[${tunnel[${i}]##src_port }]"
                        fi
                        if [[ "dst_port" == ${tunnel[${i}]:0:8} ]]; then
                                local dst_port="[${tunnel[${i}]##dst_port }]"
                        fi
                        if [[ "src_gw_ip" == ${tunnel[${i}]:0:9} ]]; then
                                local src_gw_ip=${tunnel[${i}]##src_gw_ip }
                        fi
                        if [[ "dst_gw_ip" == ${tunnel[${i}]:0:9} ]]; then
                                local dst_gw_ip=${tunnel[${i}]##dst_gw_ip }
                        fi
                        if [[ "ul_proto" == ${tunnel[${i}]:0:8} ]]; then
                                local ul_proto=${tunnel[${i}]##ul_proto }
                        fi
                        if [[ "protocol esp level" == ${tunnel[${i}]:0:18} ]]; then
                                local esp_level=${tunnel[${i}]##protocol esp level }
                        fi
                        if [[ "protocol ah level" == ${tunnel[${i}]:0:17} ]]; then
                                local ah_level=${tunnel[${i}]##protocol ah level }
                        fi
                        if [[ "protocol ipcomp level" == ${tunnel[${i}]:0:21} ]]; then
                                local ipcomp_level=${tunnel[${i}]##protocol ipcomp level }
                        fi
                done

                # Decide whether to include ah/esp/ipcomp
                if [[ "$esp_level" ]]; then
                        local esp_proto_sd=$(printf "\n\tesp/tunnel/${src_gw_ip}-${dst_gw_ip}/${esp_level}")
                        local esp_proto_ds=$(printf "\n\tesp/tunnel/${dst_gw_ip}-${src_gw_ip}/${esp_level}")
                fi
                if [[ "${ah_level}" ]]; then
                        local ah_proto_sd=$(printf "\n\tah/tunnel/${src_gw_ip}-${dst_gw_ip}/${ah_level}")
                        local ah_proto_ds=$(printf "\n\tah/tunnel/${dst_gw_ip}-${src_gw_ip}/${ah_level}")
                fi
                if [[ "${ipcomp_level}" ]]; then
                        local ipcomp_proto_sd=$(printf "\n\tipcomp/tunnel/${src_gw_ip}-${dst_gw_ip}/${ipcomp_level}")
                        local ipcomp_proto_ds=$(printf "\n\tipcomp/tunnel/${dst_gw_ip}-${src_gw_ip}/${ipcomp_level}")
                fi

                # Build our 8 policies for fully encrypted communications
                local policy1=$(printf "spdadd ${src_net}${src_port} ${dst_net}${dst_port} ${ul_proto} -P out ipsec ${esp_proto_sd} ${ah_proto_sd} ${ipcomp_proto_sd} ;")
                local policy2=$(printf "\nspdadd ${src_net}${src_port} ${dst_gw_ip}${dst_port} ${ul_proto} -P out ipsec ${esp_proto_sd} ${ah_proto_sd} ${ipcomp_proto_sd} ;")
                local policy3=$(printf "\nspdadd ${src_gw_ip} ${dst_gw_ip} ${ul_proto} -P out ipsec ${esp_proto_sd} ${ah_proto_sd} ${ipcomp_proto_sd} ;")
                local policy4=$(printf "\nspdadd ${src_gw_ip}${src_port} ${dst_net}${dst_port} ${ul_proto} -P out ipsec ${esp_proto_sd} ${ah_proto_sd} ${ipcomp_proto_sd} ;")
                local policy5=$(printf "\nspdadd ${dst_net}${dst_port} ${src_net}${src_port} ${ul_proto} -P in ipsec ${esp_proto_ds} ${ah_proto_ds} ${ipcomp_proto_ds} ;")
                local policy6=$(printf "\nspdadd ${dst_net}${dst_port} ${src_gw_ip}${src_port} ${ul_proto} -P in ipsec ${esp_proto_ds} ${ah_proto_ds} ${ipcomp_proto_ds} ;")
                local policy7=$(printf "\nspdadd ${dst_gw_ip} ${src_gw_ip} ${ul_proto} -P in ipsec ${esp_proto_ds} ${ah_proto_ds} ${ipcomp_proto_ds} ;")
                local policy8=$(printf "\nspdadd ${dst_gw_ip}${dst_port} ${src_net}${src_port} ${ul_proto} -P in ipsec ${esp_proto_ds} ${ah_proto_ds} ${ipcomp_proto_ds} ;")

                # Now we are ready to insert policies
                printf "${policy1} ${policy2} ${policy3} ${policy4} ${policy5} ${policy6} ${policy7} ${policy8}\n" > /tmp/polfile
                ebegin "Checking generated policy"
                setkey -n -f /tmp/polfile &>/tmp/error
                RET=$?
                ERR=$(cat /tmp/error 2>/dev/null && rm -f /tmp/error 2>/dev/null)
                if [[ "$ERR" ]]; then
                        ewend 1 $ERR
                        cat /tmp/polfile && rm -f /tmp/polfile
                        return 1
                else
                        ewend 0
                fi
                ebegin "Instating policy for ${tun}"
                setkey -f /tmp/polfile &>/tmp/error
                ewend $? $(cat /tmp/error 2>/dev/null && rm -f /tmp/error 2>/dev/null)
                if [[ "${debug_ipsec}" == "on" ]]; then
                        einfo "The following policy was generated for ${tun}:"
                        cat /tmp/polfile
                fi
                rm -f /tmp/polfile &>/dev/null
                ebegin "Routing traffic for ${dst_net} to ${src_gw_ip}"
                ip route add ${dst_net} via ${src_gw_ip}   &>/tmp/error
                ewend $? $(cat /tmp/error 2>/dev/null && rm -f /tmp/error 2>/dev/null)

                # Make an entry in the remove_routes script to remove this route we just added
                printf "ebegin \"Removing route for ${dst_net} via ${src_gw_ip}\"\n" >> /var/lib/ipsec/remove_routes
                printf "ip route del ${dst_net} via ${src_gw_ip}   &>/tmp/error\n" >> /var/lib/ipsec/remove_routes
                printf "ewend \$? \$(cat /tmp/error 2>/dev/null && rm -f /tmp/error 2>/dev/null)\n" >> /var/lib/ipsec/remove_routes
        done
        for tran in ${!transport*}; do
                unset src_net dst_net src_gw_ip dst_gw_ip src_ip dst_ip src_port dst_port ul_proto esp_level ah_level ipcomp_level
                unset esp_proto_sd esp_proto_ds ah_proto_sd ah_proto_ds ipcomp_proto_sd ipcomp_proto_ds
                unset policy1 policy2 policy3 policy4 policy5 policy6 policy7 policy8
                TRAN="transport=(\"\${${tran}[@]}\")"
                eval $TRAN
                # Extract all of the options for the tunnel
                for i in ${!transport[*]}; do
                        if [[ "src_ip" == ${transport[${i}]:0:6} ]]; then
                                local src_ip=${transport[${i}]##src_ip }
                        fi
                        if [[ "dst_ip" == ${transport[${i}]:0:6} ]]; then
                                local dst_ip=${transport[${i}]##dst_ip }
                        fi
                        if [[ "src_port" == ${transport[${i}]:0:8} ]]; then
                                local src_port="[${transport[${i}]##src_port }]"
                        fi
                        if [[ "dst_port" == ${transport[${i}]:0:8} ]]; then
                                local dst_port="[${transport[${i}]##dst_port }]"
                        fi
                        if [[ "ul_proto" == ${transport[${i}]:0:8} ]]; then
                                local ul_proto=${transport[${i}]##ul_proto }
                        fi
                        if [[ "protocol esp level" == ${transport[${i}]:0:18} ]]; then
                                local esp_level=${transport[${i}]##protocol esp level }
                        fi
                        if [[ "protocol ah level" == ${transport[${i}]:0:17} ]]; then
                                local ah_level=${transport[${i}]##protocol ah level }
                        fi
                        if [[ "protocol ipcomp level" == ${transport[${i}]:0:21} ]]; then
                                local ipcomp_level=${transport[${i}]##protocol ipcomp level }
                        fi
                done

                # Decide whether to include ah/esp/ipcomp
                if [[ "$esp_level" ]]; then
                        local esp_proto_sd=$(printf "\n\tesp/transport/${src_ip}-${dst_ip}/${esp_level}")
                        local esp_proto_ds=$(printf "\n\tesp/transport/${dst_ip}-${src_ip}/${esp_level}")
                fi
                if [[ "${ah_level}" ]]; then
                        local ah_proto_sd=$(printf "\n\tah/transport/${src_ip}-${dst_ip}/${ah_level}")
                        local ah_proto_ds=$(printf "\n\tah/transport/${dst_ip}-${src_ip}/${ah_level}")
                fi
                if [[ "${ipcomp_level}" ]]; then
                        local ipcomp_proto_sd=$(printf "\n\tipcomp/transport/${src_ip}-${dst_ip}/${ipcomp_level}")
                        local ipcomp_proto_ds=$(printf "\n\tipcomp/transport/${dst_ip}-${src_ip}/${ipcomp_level}")
                fi

                local policy1=$(printf "spdadd ${src_ip}${src_port} ${dst_ip}${dst_port} ${ul_proto} -P out ipsec ${esp_proto_sd} ${ah_proto_sd} ${ipcomp_proto_sd} ;")
                local policy2=$(printf "\nspdadd ${dst_ip}${dst_port} ${src_ip}${src_port} ${ul_proto} -P in ipsec ${esp_proto_ds} ${ah_proto_ds} ${ipcomp_proto_ds} ;")

                # Now we are ready to insert policies
                printf "${policy1} ${policy2}\n" > /tmp/polfile
                ebegin "Checking generated policy"
                setkey -n -f /tmp/polfile &>/tmp/error
                RET=$?
                ERR=$(cat /tmp/error 2>/dev/null && rm -f /tmp/error 2>/dev/null)
                if [[ "$ERR" ]]; then
                        ewend 1 $ERR
                        cat /tmp/polfile && rm -f /tmp/polfile
                        return 1
                else
                        ewend 0
                fi
                ebegin "Instating policy for ${tran}"
                setkey -f /tmp/polfile &>/tmp/error
                ewend $? $(cat /tmp/error 2>/dev/null && rm -f /tmp/error 2>/dev/null)
                if [[ "${debug_ipsec}" == "on" ]]; then
                        einfo "The following policy was generated for ${tran}:"
                        cat /tmp/polfile
                fi
                rm -f /tmp/polfile &>/dev/null
        done
        unset tunnel transport
}

create_firewall_rules() {
        r_fw="/var/lib/ipsec/remove_firewall"

        mkdir -p /var/lib/ipsec
        printf "#!/bin/bash\n\nsource /sbin/functions.sh\n\n" > $r_fw
        chmod 750 $r_fw

        for rules in ${!iptables*}; do
                RULES="rules2=(\"\${${rules}[@]}\")"
                eval $RULES
                # Extract all of the rules for the tunnels/transports
                einfo "Instating firewall rules for ${rules} ..."
                printf "ebegin \"Removing firewall rules for ${rules}\"\n" >> $r_fw
                for i in ${!rules2[*]}; do
                        rule_add="iptables -I ${rules2[${i}]}"
                        rule_del="iptables -D ${rules2[${i}]}"
                        ebegin " - ${rule_add}"
                        $rule_add &>/tmp/error
                        ewend $? $(cat /tmp/error 2>/dev/null && rm -f /tmp/error 2>/dev/null)

                        printf "ebegin \" - ${rule_del}\"\n" >> $r_fw
                        printf "${rule_del}   &>/tmp/error\n" >> $r_fw
                        printf "ewend \$? \$(cat /tmp/error 2>/dev/null && rm -f /tmp/error 2>/dev/null)\n" >> $r_fw
                done
        done
}

create_racoon_conf() {
        mkdir -p /var/lib/ipsec
        conf=/var/lib/ipsec/racoon.conf
        printf "# File: /var/lib/ipsec/racoon.conf\n#\n" > $conf
        printf "# This file is automatically generated by /etc/init.d/ipsec. All changes will be overwritten.\n\n" >> $conf
        printf "path certificate \"$certificate_path\";\n" >> $conf
        printf "path pre_shared_key \"$psk_path\";\n\n" >> $conf
        if [[ "${listen[@]}" ]]; then
                printf "listen {\n" >> $conf
                for listn in "${listen[@]}"; do
                        printf "\t$listn;\n" >> $conf
                done
                printf "}\n\n" >> $conf
        fi
        for tun in ${!tunnel*}; do
                unset encryption_algorithm encryption_keylen authentication_algorithm authentication_keylen
                unset authentication certificate certificate_key pre_shared_key compression_algorithm exchange_mode
                unset src_net dst_net src_port dst_port src_gw_ip dst_gw_ip ul_proto block
                ebegin "Building security associations for ${tun}"
                TUN="tunnel=(\"\${${tun}[@]}\")"
                eval $TUN
                # Extract all of the options for the tunnel
                for i in ${!tunnel[*]}; do
                        if [[ "src_net" == ${tunnel[${i}]:0:7} ]]; then
                                local src_net=${tunnel[${i}]##src_net }
                        fi
                        if [[ "dst_net" == ${tunnel[${i}]:0:7} ]]; then
                                local dst_net=${tunnel[${i}]##dst_net }
                        fi
                        if [[ "src_port" == ${tunnel[${i}]:0:8} ]]; then
                                local src_port="[${tunnel[${i}]##src_port }]"
                        fi
                        if [[ "dst_port" == ${tunnel[${i}]:0:8} ]]; then
                                local dst_port="[${tunnel[${i}]##dst_port }]"
                        fi
                        if [[ "src_gw_ip" == ${tunnel[${i}]:0:9} ]]; then
                                local src_gw_ip=${tunnel[${i}]##src_gw_ip }
                        fi
                        if [[ "dst_gw_ip" == ${tunnel[${i}]:0:9} ]]; then
                                local dst_gw_ip=${tunnel[${i}]##dst_gw_ip }
                        fi
                        if [[ "ul_proto" == ${tunnel[${i}]:0:8} ]]; then
                                local ul_proto=${tunnel[${i}]##ul_proto }
                        fi
                        if [[ "exchange_mode " == ${tunnel[${i}]:0:14} ]]; then
                                local exchange_mode=${tunnel[${i}]##exchange_mode }
                        fi
                        if [[ "encryption_algorithm " == ${tunnel[${i}]:0:21} ]]; then
                                local encryption_algorithm=${tunnel[${i}]##encryption_algorithm }
                        fi
                        if [[ "encryption_keylen " == ${tunnel[${i}]:0:18} ]]; then
                                local encryption_keylen=${tunnel[${i}]##encryption_keylen }
                        fi
                        if [[ "hash_algorithm " == ${tunnel[${i}]:0:15} ]]; then
                                local hash_algorithm=${tunnel[${i}]##hash_algorithm }
                        fi
                        if [[ "compression_algorithm " == ${tunnel[${i}]:0:22} ]]; then
                                local compression_algorithm=${tunnel[${i}]##compression_algorithm }
                        fi
                        if [[ "authentication_algorithm " == ${tunnel[${i}]:0:25} ]]; then
                                local authentication_algorithm="[${tunnel[${i}]##authentication_algorithm }]"
                        fi
                        if [[ "authentication_keylen " == ${tunnel[${i}]:0:22} ]]; then
                                local authentication_keylen="[${tunnel[${i}]##authentication_keylen }]"
                        fi
                        if [[ "authentication " == ${tunnel[${i}]:0:15} ]]; then
                                local authentication=${tunnel[${i}]##authentication }
                        fi
                        if [[ "certificate " == ${tunnel[${i}]:0:12} ]]; then
                                local certificate=${tunnel[${i}]##certificate }
                        fi
                        if [[ "certificate_key " == ${tunnel[${i}]:0:16} ]]; then
                                local certificate_key=${tunnel[${i}]##certificate_key }
                        fi
                        if [[ "pre_shared_key " == ${tunnel[${i}]:0:15} ]]; then
                                local pre_shared_key=${tunnel[${i}]##pre_shared_key }
                        fi
                done

                # Set some defaults
                local exchange_mode=${exchange_mode:-main}
                local encryption_algorithm=${encryption_algorithm:-aes}
                local encryption_keylen=${encryption_keylen:-256}
                local hash_algorithm=${hash_algorithm:-md5}
                local compression_algorithm=${compression_algorithm:-deflate}
                local authentication_algorithm=${authentication_algorithm:-hmac_sha1}
                local authentication_keylen=${authentication_keylen:-160}
                local authentication=${authentication:-pre_shared_key}

                # We have now extracted all of the settings for the tunnel
                printf "remote ${dst_gw_ip} {\n" >> $conf
                printf "\texchange_mode ${exchange_mode};\n" >> $conf
                if [[ "${authentication}" == "X.509" ]]; then
                        printf "\tcertificate_type x509 \"${certificate}\" \"${certificate_key}\";\n" >> $conf
                        printf "\tverify_cert on;\n" >> $conf
                        printf "\tmy_identifier asn1dn;\n" >> $conf
                        printf "\tpeers_identifier asn1dn;\n" >> $conf
                fi
                printf "\tproposal {\n" >> $conf
                printf "\t\tencryption_algorithm ${encryption_algorithm};\n" >> $conf
                printf "\t\thash_algorithm ${hash_algorithm};\n" >> $conf
                if [[ "${authentication}" == "X.509" ]]; then
                        printf "\t\tauthentication_method rsasig;\n" >> $conf
                fi
                if [[ "${authentication}" == "psk" ]]; then
                        printf "\t\tauthentication_method pre_shared_key;\n" >> $conf
                fi
                printf "\t\tdh_group modp1024;\n" >> $conf
                printf "\t}\n" >> $conf
                printf "}\n" >> $conf
                local block=$(printf "\tpfs_group modp768;\n\tencryption_algorithm ${encryption_algorithm};\n\tauthentication_algorithm ${authentication_algorithm};\n\tcompression_algorithm ${compression_algorithm};")
                printf "sainfo address ${src_gw_ip} ${ul_proto} address ${dst_gw_ip} ${ul_proto} {\n$block\n}\n" >> $conf
                printf "sainfo address ${src_gw_ip} ${ul_proto} address ${dst_net} ${dst_port} ${ul_proto} {\n$block\n}\n" >> $conf
                printf "sainfo address ${src_net} ${src_port} ${ul_proto} address ${dst_net} ${dst_port} ${ul_proto} {\n$block\n}\n" >> $conf
                printf "sainfo address ${src_net} ${src_port} ${ul_proto} address ${dst_gw_ip} ${ul_proto} {\n$block\n}\n" >> $conf
                printf "\n" >> $conf
                ewend 0
        done
        for tran in ${!transport*}; do
                unset encryption_algorithm encryption_keylen authentication_algorithm authentication_keylen
                unset authentication certificate certificate_key pre_shared_key compression_algorithm exchange_mode
                unset src_ip dst_ip src_port dst_port ul_proto block
                ebegin "Building security associations for ${tran}"
                TRAN="transport=(\"\${${tran}[@]}\")"
                eval $TRAN
                # Extract all of the options for the transport
                for i in ${!transport[*]}; do
                        if [[ "src_ip" == ${transport[${i}]:0:6} ]]; then
                                local src_ip=${transport[${i}]##src_ip }
                        fi
                        if [[ "dst_ip" == ${transport[${i}]:0:6} ]]; then
                                local dst_ip=${transport[${i}]##dst_ip }
                        fi
                        if [[ "src_port" == ${transport[${i}]:0:8} ]]; then
                                local src_port="[${transport[${i}]##src_port }]"
                        fi
                        if [[ "dst_port" == ${transport[${i}]:0:8} ]]; then
                                local dst_port="[${transport[${i}]##dst_port }]"
                        fi
                        if [[ "ul_proto" == ${transport[${i}]:0:8} ]]; then
                                local ul_proto=${transport[${i}]##ul_proto }
                        fi
                        if [[ "exchange_mode " == ${transport[${i}]:0:14} ]]; then
                                local exchange_mode=${transport[${i}]##exchange_mode }
                        fi
                        if [[ "encryption_algorithm " == ${transport[${i}]:0:21} ]]; then
                                local encryption_algorithm=${transport[${i}]##encryption_algorithm }
                        fi
                        if [[ "encryption_keylen " == ${transport[${i}]:0:18} ]]; then
                                local encryption_keylen=${transport[${i}]##encryption_keylen }
                        fi
                        if [[ "hash_algorithm " == ${transport[${i}]:0:15} ]]; then
                                local hash_algorithm=${transport[${i}]##hash_algorithm }
                        fi
                        if [[ "compression_algorithm " == ${transport[${i}]:0:22} ]]; then
                                local compression_algorithm=${transport[${i}]##compression_algorithm }
                        fi
                        if [[ "authentication_algorithm " == ${transport[${i}]:0:25} ]]; then
                                local authentication_algorithm="[${transport[${i}]##authentication_algorithm }]"
                        fi
                        if [[ "authentication_keylen " == ${transport[${i}]:0:22} ]]; then
                                local authentication_keylen="[${transport[${i}]##authentication_keylen }]"
                        fi
                        if [[ "authentication " == ${transport[${i}]:0:15} ]]; then
                                local authentication=${transport[${i}]##authentication }
                        fi
                        if [[ "certificate " == ${transport[${i}]:0:12} ]]; then
                                local certificate=${transport[${i}]##certificate }
                        fi
                        if [[ "certificate_key " == ${transport[${i}]:0:16} ]]; then
                                local certificate_key=${transport[${i}]##certificate_key }
                        fi
                        if [[ "pre_shared_key " == ${transport[${i}]:0:15} ]]; then
                                local pre_shared_key=${transport[${i}]##pre_shared_key }
                        fi
                done

                # Set some defaults
                local exchange_mode=${exchange_mode:-main}
                local encryption_algorithm=${encryption_algorithm:-aes}
                local encryption_keylen=${encryption_keylen:-256}
                local hash_algorithm=${hash_algorithm:-md5}
                local compression_algorithm=${compression_algorithm:-deflate}
                local authentication_algorithm=${authentication_algorithm:-hmac_sha1}
                local authentication_keylen=${authentication_keylen:-160}
                local authentication=${authentication:-pre_shared_key}

                # We have now extracted all of the settings for the tunnel
                printf "remote ${dst_ip} {\n" >> $conf
                printf "\texchange_mode ${exchange_mode};\n" >> $conf
                if [[ "${authentication}" == "X.509" ]]; then
                        printf "\tcertificate_type x509 \"${certificate}\" \"${certificate_key}\";\n" >> $conf
                        printf "\tverify_cert on;\n" >> $conf
                        printf "\tmy_identifier asn1dn;\n" >> $conf
                        printf "\tpeers_identifier asn1dn;\n" >> $conf
                fi
                printf "\tproposal {\n" >> $conf
                printf "\t\tencryption_algorithm ${encryption_algorithm};\n" >> $conf
                printf "\t\thash_algorithm ${hash_algorithm};\n" >> $conf
                if [[ "${authentication}" == "X.509" ]]; then
                        printf "\t\tauthentication_method rsasig;\n" >> $conf
                fi
                if [[ "${authentication}" == "psk" ]]; then
                        printf "\t\tauthentication_method pre_shared_key;\n" >> $conf
                fi
                printf "\t\tdh_group modp1024;\n" >> $conf
                printf "\t}\n" >> $conf
                printf "}\n" >> $conf
                local block=$(printf "\tpfs_group modp768;\n\tencryption_algorithm ${encryption_algorithm};\n\tauthentication_algorithm ${authentication_algorithm};\n\tcompression_algorithm ${compression_algorithm};")
                printf "sainfo address ${src_ip} ${ul_proto} address ${dst_ip} ${ul_proto} {\n$block\n}\n" >> $conf
                ewend 0
        done
        if [[ "${!roadwarrior[*]}" ]]; then
                unset encryption_algorithm encryption_keylen authentication_algorithm authentication_keylen
                unset authentication certificate certificate_key pre_shared_key compression_algorithm exchange_mode
                unset src_ip dst_ip src_port dst_port ul_proto block
                for i in ${!roadwarrior[*]}; do
                        if [[ "exchange_mode " == ${roadwarrior[${i}]:0:14} ]]; then
                                local exchange_mode=${roadwarrior[${i}]##exchange_mode }
                        fi
                        if [[ "encryption_algorithm " == ${roadwarrior[${i}]:0:21} ]]; then
                                local encryption_algorithm=${roadwarrior[${i}]##encryption_algorithm }
                        fi
                        if [[ "encryption_keylen " == ${roadwarrior[${i}]:0:18} ]]; then
                                local encryption_keylen=${roadwarrior[${i}]##encryption_keylen }
                        fi
                        if [[ "hash_algorithm " == ${roadwarrior[${i}]:0:15} ]]; then
                                local hash_algorithm=${roadwarrior[${i}]##hash_algorithm }
                        fi
                        if [[ "compression_algorithm " == ${roadwarrior[${i}]:0:22} ]]; then
                                local compression_algorithm=${roadwarrior[${i}]##compression_algorithm }
                        fi
                        if [[ "authentication_algorithm " == ${roadwarrior[${i}]:0:25} ]]; then
                                local authentication_algorithm="[${roadwarrior[${i}]##authentication_algorithm }]"
                        fi
                        if [[ "authentication_keylen " == ${roadwarrior[${i}]:0:22} ]]; then
                                local authentication_keylen="[${roadwarrior[${i}]##authentication_keylen }]"
                        fi
                        if [[ "authentication " == ${roadwarrior[${i}]:0:15} ]]; then
                                local authentication=${roadwarrior[${i}]##authentication }
                        fi
                        if [[ "certificate " == ${roadwarrior[${i}]:0:12} ]]; then
                                local certificate=${roadwarrior[${i}]##certificate }
                        fi
                        if [[ "certificate_key " == ${roadwarrior[${i}]:0:16} ]]; then
                                local certificate_key=${roadwarrior[${i}]##certificate_key }
                        fi
                        if [[ "pre_shared_key " == ${roadwarrior[${i}]:0:15} ]]; then
                                local pre_shared_key=${roadwarrior[${i}]##pre_shared_key }
                        fi
                done

                # Set some defaults
                local exchange_mode=${exchange_mode:-main}
                local encryption_algorithm=${encryption_algorithm:-3des}
                local encryption_keylen=${encryption_keylen:-256}
                local hash_algorithm=${hash_algorithm:-sha1}
                local compression_algorithm=${compression_algorithm:-deflate}
                local authentication_algorithm=${authentication_algorithm:-hmac_sha1}
                local authentication_keylen=${authentication_keylen:-160}
                local authentication=${authentication:-pre_shared_key}

                # We have now extracted all of the settings for the tunnel
                printf "remote anonymous {\n" >> $conf
                printf "\texchange_mode ${exchange_mode};\n" >> $conf
                if [[ "${authentication}" == "X.509" ]]; then
                        printf "\tcertificate_type x509 \"${certificate}\" \"${certificate_key}\";\n" >> $conf
                        printf "\tverify_cert on;\n" >> $conf
                        printf "\tmy_identifier asn1dn;\n" >> $conf
                        printf "\tpeers_identifier asn1dn;\n" >> $conf
                fi
                printf "\tnat_traversal on;\n" >> $conf
                printf "\tgenerate_policy on;\n" >> $conf
                printf "\tproposal {\n" >> $conf
                printf "\t\tencryption_algorithm ${encryption_algorithm};\n" >> $conf
                printf "\t\thash_algorithm ${hash_algorithm};\n" >> $conf
                if [[ "${authentication}" == "X.509" ]]; then
                        printf "\t\tauthentication_method rsasig;\n" >> $conf
                fi
                if [[ "${authentication}" == "psk" ]]; then
                        printf "\t\tauthentication_method pre_shared_key;\n" >> $conf
                fi
                printf "\t\tdh_group modp1024;\n" >> $conf
                printf "\t}\n" >> $conf
                printf "}\n" >> $conf
                local block=$(printf "\tencryption_algorithm ${encryption_algorithm};\n\tauthentication_algorithm ${authentication_algorithm};\n\tcompression_algorithm ${compression_algorithm};")
                printf "sainfo anonymous {\n$block\n}\n" >> $conf
                ewend 0
        fi
        ebegin "Starting racoon"
        racoon -f $conf    &>/tmp/error
        RET=$?
        ERR=$(cat /tmp/error 2>/dev/null)
        CONFERR=$(cat /tmp/error 2>/dev/null | grep "failed to parse configuration")
        ewend $RET $ERR
        if [[ -z $RET ]]; then
                svc_stop
                if [[ "${CONFERR}" ]]; then
                        ewarn "There was a problem with your configuration. I am about to dump the config."
                        sleep 5
                        less $conf
                fi
        fi
        if [[ "${debug_ipsec}" == "on" ]]; then
                einfo "The following policy was generated for ${tran}:"
                cat $conf
        fi
}

docmd() {
        if [[ "$debug_ipsec" == "on" ]]; then
                ebegin "  - ${CMD}"
        fi
        ${CMD} &>/tmp/error
        if [[ "$debug_ipsec" == "on" ]]; then
                ewend $? $(cat /tmp/error)
        fi
        rm -f /tmp/error
}

if [ -r /etc/conf.d/ipsec ]; then
        source /etc/conf.d/ipsec
fi
   

Don't forget to make the script executable and add it to your default runlevel:

bash init.d # chmod 755 /etc/init.d/ipsec
bash init.d # rc-update add ipsec default

Creating the IPSec Connection

IPSec Between Two Gentoo Boxes

If you are creating a tunnel between two Gentoo boxes, go ahead and install the /etc/conf.d/ipsec and /etc/init.d/ipsec files on your second Gentoo box. You can literally copy the configuration of your first box to your second box and swap the source and destination IP addresses and then change the name of the certificate on your second box accordingly. Don't forget to change the IP addresses to listen to in the listen section at the top. Aside from changing IP addresses and your certificate files, everything else stays the same.

Next, you need to copy your certificate from your first machine to your second machine. On your second machine, issue the following commands:

bash ~ # mkdir /etc/certs && chmod 700 /etc/certs && cd /etc/certs
bash certs # scp 111.111.111.111:/etc/certs/mysecondhost.mydomain.com* .

The scp utility allows you to securely copy files between two hosts running SSH. For more information on how scp operates, man scp.

You will also need to copy over the CA certificate and the CA certificate revocation list. The names of the CA certificate and CA CRL will vary. They will look something like '0a9b467afd.0' and '65ad8d7ee6.r0' inside the /etc/certs directory on the server where you set up the CA. Copy both files to this host:

bash certs # scp 111.111.111.111:/etc/certs/*.0 .
bash certs # scp 111.111.111.111:/etc/certs/*.r0 .

If you maintain a CRL, you will need to set up some method for automating the transfer of the CRL to each of your clients on a regular basis.

Now, on both Gentoo boxes, issue this command:

bash ~ # /etc/init.d/ipsec start

That's it! You should have a fully operational IPSec connection between your two Gentoo boxes. Try a ping:

bash ~ # ping -c 5 222.222.222.222
connect: Resource temporarily unavailable
bash ~ # ping -c 5 222.222.222.222
PING 222.222.222.222 (222.222.222.222) 56(84) bytes of data.
64 bytes from 222.222.222.222: icmp_seq=1 ttl=64 time=30.2 ms
64 bytes from 222.222.222.222: icmp_seq=2 ttl=64 time=31.1 ms
64 bytes from 222.222.222.222: icmp_seq=3 ttl=64 time=31.2 ms
64 bytes from 222.222.222.222: icmp_seq=4 ttl=64 time=32.0 ms
64 bytes from 222.222.222.222: icmp_seq=5 ttl=64 time=32.4 ms

--- 222.222.222.222 ping statistics ---
5 packets transmitted, 5 received, 0% packet loss, time 4002ms
rtt min/avg/max/mdev = 30.284/31.420/32.474/0.791 ms
bash ~ #

If you run a tcpdump simultaneously with the ping, you should see something like this:

bash ~ # tcpdump -n -i eth0 host 222.222.222.222
tcpdump: verbose output suppressed, use -v or -vv for full protocol decode
listening on eth0, link-type EN10MB (Ethernet), capture size 68 bytes 
18:59:45.761406 IP 111.111.111.111.500 > 222.222.222.222.500: [|isakmp]
18:59:45.767691 IP 222.222.222.222.500 > 111.111.111.111.500: [|isakmp]
18:59:45.903988 IP 111.111.111.111.500 > 222.222.222.222.500: [|isakmp]
18:59:45.920815 IP 222.222.222.222.500 > 111.111.111.111.500: [|isakmp]
18:59:46.121085 IP 111.111.111.111.500 > 222.222.222.222.500: [|isakmp]
18:59:46.133957 IP 222.222.222.222.500 > 111.111.111.111.500: [|isakmp]
18:59:46.202756 IP 111.111.111.111.500 > 222.222.222.222.500: [|isakmp]
18:59:47.275971 IP 111.111.111.111.500 > 222.222.222.222.500: [|isakmp]
18:59:47.284567 IP 222.222.222.222.500 > 111.111.111.111.500: [|isakmp]
18:59:47.321799 IP 111.111.111.111.500 > 222.222.222.222.500: [|isakmp]
18:59:52.614406 IP 111.111.111.111 > 222.222.222.222: ESP(spi=0x0d23c49b,seq=0x1), length 132
18:59:52.614562 IP 222.222.222.222 > 111.111.111.111: ESP(spi=0x05167468,seq=0x1), length 132
18:59:53.616321 IP 111.111.111.111 > 222.222.222.222: ESP(spi=0x0d23c49b,seq=0x2), length 132
18:59:53.616437 IP 222.222.222.222 > 111.111.111.111: ESP(spi=0x05167468,seq=0x2), length 132
18:59:54.616211 IP 111.111.111.111 > 222.222.222.222: ESP(spi=0x0d23c49b,seq=0x3), length 132
18:59:54.616330 IP 222.222.222.222 > 111.111.111.111: ESP(spi=0x05167468,seq=0x3), length 132
18:59:55.617116 IP 111.111.111.111 > 222.222.222.222: ESP(spi=0x0d23c49b,seq=0x4), length 132
18:59:55.617231 IP 222.222.222.222 > 111.111.111.111: ESP(spi=0x05167468,seq=0x4), length 132
18:59:56.618996 IP 111.111.111.111 > 222.222.222.222: ESP(spi=0x0d23c49b,seq=0x5), length 132
18:59:56.619113 IP 222.222.222.222 > 111.111.111.111: ESP(spi=0x05167468,seq=0x5), length 132

Configuring Windows XP w/Service Pack 2 For IPSec

First, we need to securely copy the XP certificate (the .pfx file) and CA certificate (.pem file) to the Windows client. To do this, go download WinSCP. It is a secure copy program which uses SSH to transfer files. Use WinSCP to transfer both files to your Desktop. When you are finished, close WinSCP and follow these steps:

1. Click on Start->Run and type 'mmc'.
Run dialog box
Run dialog box
2. Click Ok. The Windows Management Console should appear.
3. Click File->Add/Remove Snap In...
Windows Management Console
Windows Management Console
4. Click IP Security Policy Management.
5. Click Add.
Add IP Security Policy Management
Add IP Security Policy Management
6. Make sure the dot is in Local computer.
Select Local Computer
Select Local Computer
7. Click Ok.
8. Click IP Security Monitor.
Add IP Security Monitor
Add IP Security Monitor
9. Click Add.
10. Click Event Viewer.
Add Event Viewer
Add Event Viewer
11. Click Add.
12. Make sure the dot is in Local computer.
Select Local Computer
Select Local Computer
13. Click Ok.
14. Click Certificates.
Add Certificates
Add Certificates
15. Click Add.
16. Put the dot in Computer Account.
Select Computer Account
Select Computer Account
17. Click Next.
18. Make sure the dot is in Local computer.
Select Local Computer
Select Local Computer
19. Click Finish.
20. Click Close.
Click Close
Click Close
21. Click Ok.
Click Ok
Click Ok
22. Expand Certificates.
Import CA Certificate
Import CA Certificate
23. Click Trusted Root Certification Authority.
24. Click Action->All Tasks->Import
25. Click Next.
Certificate Import Wizard
Certificate Import Wizard
26. Browse to the location where you saved your CA certificate (.pem file).
Choose CA Certificate
Choose CA Certificate
27. Click Next.
28. Make sure the dot is in Place all certificates in the following store.
Certificate Store Selection
Certificate Store Selection
29. Make sure the Trusted Root Certification Authorities store is selected.
30. Click Next.
31. Click Finish.
Finish Certificate Import Wizard
Finish Certificate Import Wizard
32. Click on the Personal certificate store.
Import Client Certificate
Import Client Certificate
33. Click Action->All Tasks->Import.
34. Browse to the location where you saved your client certificate (.pfx file).
Choose Client Certificate
Choose Client Certificate
35. Click Next.
36. Enter the password you chose when you created your PFX certificate.
Enter Client Certificate Password
Enter Client Certificate Password
37. Click Next.
38. Make sure the dot is in Place all certificates in the following store.
Certificate Store Selection
Certificate Store Selection
39. Make sure the Personal certificate store is selected.
40. Click Next.
41. Click Finish.
Finish Certificate Import Wizard
Finish Certificate Import Wizard
42. Click IP Security Policies on Local Computer.
Create IP Security Policy
Create IP Security Policy
43. Right-click on the white-space on the right-hand side.
44. Left-click on Create IP Security Policy.
45. Click Next.
IP Security Policy Wizard
IP Security Policy Wizard
46. Type a name for your security policy.
Name IP Security Policy
Name IP Security Policy
47. Type a description for your security policy.
48. Click Next.
49. Uncheck Activate the default response rule.
Uncheck Default Response Rule
Uncheck Default Response Rule
50. Click Next.
51. Make sure Edit properties is checked.
Finish IP Security policy Wizard
Finish IP Security policy Wizard
52. Click Finish.
53. Uncheck Use Add Wizard.
IP Security Policy Properties
IP Security Policy Properties
54. Click Add to create a new rule.
55. Click Add to create a new IP filter list.
New Rule Properties
New Rule Properties
56. Name the IP filter list 'Me to Gentoo'.
New IP Filter List
New IP Filter List
57. In the description, type 'Me to Gentoo'.
58. Uncheck Use Add Wizard.
59. Click Add to create a new IP filter.
60. For the source address, select My IP Address.
IP Filter Properties
IP Filter Properties
61. For the destination address, select A specific IP Address.
62. In the IP Address box, enter the IP address of your Gentoo Linux IPSec server.
63. Uncheck Mirrored.
64. Click Ok to close the IP Filter Properties.
65. Click Ok to close the IP Filter List Properties.
IP Filter List Properties
IP Filter List Properties
66. Click Add to create a new IP filter list.
New Rule Properties
New Rule Properties
67. Name the IP filter list 'Gentoo to Me'.
New IP Filter List
New IP Filter List
68. In the description, type 'Gentoo to Me'.
69. Use Add Wizard should still be unchecked.
70. Click Add to create a new IP filter.
71. For the source address, select A specific IP Address.
IP Filter Properties
IP Filter Properties
72. In the IP Address box, enter the IP address of your Gentoo Linux IPSec server.
73. For the destination address, select My IP Address.
74. Uncheck Mirrored.
75. Click Ok to close the IP Filter Properties.
76. Click Ok to close the IP Filter List Properties.
IP Filter List Properties
IP Filter List Properties
77. Put a dot in Me to Gentoo.
Select Me to Gentoo
Select Me to Gentoo
78. Click the Filter Action tab.
79. Uncheck Use Add Wizard.
Filter Action Tab
Filter Action Tab
80. Click Add to create a new Filter Action.
81. Make sure the dot is in Negotiate Security.
New Filter Action Properties
New Filter Action Properties
82. Click Add to define a new security method.
83. Put the dot in Custom.
New Security Method
New Security Method
84. Click Settings.
85. Make sure there is a check in Data integrity and encryption (ESP).
Custom Security Method Settings
Custom Security Method Settings
86. For Integrity algorithm, make sure SHA1 is selected.
87. For Encryption algorithm, if you have an option to choose AES, choose it; otherwise, choose 3DES.
88. Put a check in the left Generate a new key every.
89. Put a check in the right Generate a new key every.
90. Click Ok.
91. Put a check in Use session key perfect forward security (PFS).
Check Perfect Forward Security
Check Perfect Forward Security
92. Click the General tab.
93. In the name field, type 'Secure Two-Way Communication'.
General Tab
General Tab
94. In the description field, type 'This option requires both parties to communicate over a secure channel.
95. Click Ok.
96. Put a dot in Secure Two-Way Communication.
Choose Secure Two-Way Communication
Choose Secure Two-Way Communication
97. Click the Authentication Methods tab.
98. Click Edit.
Authentication Methods Tab
Authentication Methods Tab
99. Put a dot in Use a certificate from this certificate authority (CA).
Edit Authentication Method Properties
Edit Authentication Method Properties
100. Click Browse.
101. Select the CA certificate you imported in steps 22 through 31.
102. Click Ok to select the certificate.
103. Click Ok to close the Authentication Method Properties dialog.
104. Click Close to close the New Rule Properties dialog.
Close New Rule Properties
Close New Rule Properties
105. Click Add to create a new rule.
IP Security Policy Properties
IP Security Policy Properties
106. Put a dot in Gentoo to Me.
Choose Gentoo to Me
Choose Gentoo to Me
107. Click on the Filter Action tab.
108. Put a dot in Secure Two-Way Communication.
Choose Secure Two-Way Communication
Choose Secure Two-Way Communication
109. Click on the Authentication Methods tab.
110. Click Edit.
Authentication Methods Tab
Authentication Methods Tab
111. Put a dot in Use a certificate from this certificate authority (CA).
Edit Authentication Method Properties
Edit Authentication Method Properties
112. Click Browse.
113. Select the CA certificate you imported in steps 22 through 31.
114. Click Ok to select the certificate.
115. Click Ok to close the Authentication Method Properties dialog.
116. Click Close to close the New Rule Properties dialog.
Close New Rule Properties
Close New Rule Properties
117. Click Ok to close the IP Security Policy Properties dialog.
IP Security Policy Properties
IP Security Policy Properties
118. Right-click the new security policy you created.
Assign New Security Policy
Assign New Security Policy
119. Left-click Assign to use the new security policy.
120. Ensure the policy is assigned.
Assigned Policy
Assigned Policy

If you are still with us at this point, you should now have an IPSec transport connection between your Windows XP SP2 computer and your Gentoo IPSec server. When you issue a ping to your Gentoo server, you should see a couple of messages saying "Negotiating IP Security". After 1-4 of these messages, your pings should start going through. If you continue to receive these messages, it is most likely that you either did not import your certificates correctly, you did not enter the correct IP address in one of the fields of the IP filters, or you did not select the correct options for the filter actions. It is also possible that you messed something up on your Gentoo side. To troubleshoot the connection, turn on Logon/Logoff auditing (Control Panel->Administrative Tools->Local Security Policy->Local Policies->Audit Policy) and use the Security Log in the Event Viewer.

IPsec Troubleshooting Guide

IPsec in general works fine, but particular TCP protocols do not

When you can PING through your IPsec path, you can (most probably) be sure that it works. However, when you're using protocols that sometimes require some huge IP packets (e.g. HTTP, IMAP, ...) then you may run into trouble. AH and ESP are making your IP packets bigger than usual, and Linux usually marks all IP packets with the DF-flag (DF = don't fragment).

So, you've to decrease the MTU value of your interface (wich usually is 1500)

To decrease the MTU value down to 1000 of interface eth0 with IP 111.222.333.444, use a command like below:

Code: iproute2 version (requires iproute2 package)
ip link set eth0 mtu 1000


Code: ifconfig version
ifconfig eth0 111.222.333.444 mtu 1000

Now, test again. Big IP packets shall now pass through your IPsec path.

Another approach is to limit the MSS only for specific routes to other IPsec endpoints. The advantage of this approach is that you need not clamp the MSS/MTU for all traffic leaving the local interface.

Code: using routes to limit MSS
route add -host 123.123.123.123 gw 234.234.234.234 mss 1200

The host IP is the address of the host or router at the other end of the IPsec link; the gateway IP is the address of your default gateway. This setup will clamp the MSS for the IPsec link, but not for any other traffic that gets forwarded through your default gateway route. You will, however, have to add route entries for each IPsec endpoint, which limits its utility to static links.

Definitions

References

Toubleshooting References:

Retrieved from "http://www.gentoo-wiki.info/HOWTO_IPSEC"

Last modified: Wed, 14 May 2008 04:03:00 +0000 Hits: 37,553