User Tools

Site Tools


encryption:ipsec

IPSec

The following describes nwl's site IPSec setup. It's rather complex, as it has to fulfil a number of requirements:

  • be of the roadwarrior type (clients with changing IPs)
  • provide an official IPv6 address for clients
  • do not imply the need of a subnet behind the server or client to tunnel into

also there is a single limitation (for now), no IPv4 support (i.e. no support for NAT and other PITAs).

Two Stage Setup Approach

The following sections describe a setup in two stages which is quite obscure and not used anymore. It's documentation is left mainly for reference.

Server Setup

This is the raccon.conf for the server:

path certificate "/etc/ssl/ipsec";

remote anonymous {
        exchange_mode main;
        generate_policy on;
        certificate_type x509 "certs/orbit.nwl.cc.crt" "private/orbit.nwl.cc.key";
        verify_cert on;
        my_identifier asn1dn;
        peers_identifier asn1dn;
        passive on;
        proposal {
                encryption_algorithm aes;
                hash_algorithm md5;
                authentication_method rsasig;
                dh_group modp1024;
        }
}

sainfo anonymous {
        pfs_group modp768;
        encryption_algorithm aes;
        authentication_algorithm hmac_md5;
        compression_algorithm deflate;
}

nothing else is necessary, as generate_policy on will generate the necessary policies after completing phase 1.

Client Setup

Client side setup is obviously the more complex one. What makes it especially difficult is the fact, that the source address is potentially unknown and tunnel mode has to be used.

To prevent having to manually specifying a policy for all potential source addresses, a dummy policy is being used which just triggers some transport mode connection, and the phase1_up script does then set the real policies for later use with the information in it's environment (specifically the current source IP, which must be reachable by the server).

#!/usr/sbin/setkey -f

spdadd ::/0 2001:41d0:1:ea5f::1 any -P out ipsec
	esp/transport//require
	ah/transport//require;

spdadd 2001:41d0:1:ea5f::1 ::/0 any -P in ipsec
	esp/transport//require
	ah/transport//require;

The following racoon.conf is being used. Important fact here is that the single remote definition is used for both IPSec sessions.

path certificate "/etc/racoon/nuty";
path script "/etc/racoon";

remote 2001:41d0:1:ea5f::1 {
	exchange_mode main;
	certificate_type x509 "nuty.nwl.cc.crt" "nuty.nwl.cc.key";
	verify_cert on;
	my_identifier asn1dn;
	peers_identifier asn1dn;
	script "phase1.sh" phase1_up;
	script "phase1.sh" phase1_down;
	proposal {
		encryption_algorithm aes;
		hash_algorithm md5;
		authentication_method rsasig;
		dh_group modp1024;
	}
}

sainfo anonymous {
	pfs_group modp768;
	encryption_algorithm aes;
	authentication_algorithm hmac_md5;
	compression_algorithm deflate;
}

The following script does the magic: it creates the tunnel policies and assigns the public IP to the interface with the default route. The tunnel IPs are still hardcoded, maybe they could be passed as parameters from within racoon.conf.

Note here that the remote tunnel IP is the same as the one of the remote endpoint. So on the server side this setup behaves just like a transport mode connection, but for a previously non-existent ip (which must be reachable, of course).

#!/bin/bash

TUNLOC_IP="2001:41d0:1:ea5f::40"
TUNREM_IP="2001:41d0:1:ea5f::1"
TUNPFX="64"

OPT="-6"
[[ "${LOCAL_ADDR}" = *.*.*.* ]] && OPT="-4"
GW_IFACE="`ip ${OPT} route show | awk '/^default/{print $5}'`"

case $1 in

phase1_up)
logger -t "phase1.sh" "setting up"
/usr/sbin/setkey -c << EOF
spdadd ${TUNLOC_IP} ${TUNREM_IP} any -P out ipsec
	esp/tunnel/${LOCAL_ADDR}-${REMOTE_ADDR}/require
	ah/tunnel/${LOCAL_ADDR}-${REMOTE_ADDR}/require;
spdadd ${TUNREM_IP} ${TUNLOC_IP} any -P in ipsec
	esp/tunnel/${REMOTE_ADDR}-${LOCAL_ADDR}/require
	ah/tunnel/${REMOTE_ADDR}-${LOCAL_ADDR}/require;
EOF
/sbin/ip addr add ${TUNLOC_IP}/${TUNPFX} dev ${GW_IFACE}
;;

phase1_down)
logger -t "phase1.sh" "shutting down"
/sbin/ip addr del ${TUNLOC_IP}/${TUNPFX} dev ${GW_IFACE}
/usr/sbin/setkey -c << EOF
spddelete ${TUNLOC_IP} ${TUNREM_IP} any -P out;
spddelete ${TUNREM_IP} ${TUNLOC_IP} any -P in;
EOF
;;

esac

exit 0

Bugs

When using racoon in an IPv6 environment, IP address passing to phase1 scripts is broken. The following patch fixes this (see Bug #300):

Index: src/racoon/isakmp.c
===================================================================
RCS file: /cvsroot/src/crypto/dist/ipsec-tools/src/racoon/isakmp.c,v
retrieving revision 1.49
diff -r1.49 isakmp.c
3126d3125
< 	struct sockaddr_in *sin;
3139,3141c3138,3140
< 	sin = (struct sockaddr_in *)iph1->local;
< 	inet_ntop(sin->sin_family, &sin->sin_addr, addrstr, IP_MAX);
< 	snprintf(portstr, PORT_MAX, "%d", ntohs(sin->sin_port));
---
> 	getnameinfo(iph1->local, sizeof(struct sockaddr_storage),
> 	            addrstr, IP_MAX, portstr, PORT_MAX,
> 	            NI_NUMERICHOST | NI_NUMERICSERV);
3155,3157c3154,3156
< 		sin = (struct sockaddr_in *)iph1->remote;
< 		inet_ntop(sin->sin_family, &sin->sin_addr, addrstr, IP_MAX);
< 		snprintf(portstr, PORT_MAX, "%d", ntohs(sin->sin_port));
---
> 		getnameinfo(iph1->remote, sizeof(struct sockaddr_storage),
> 		            addrstr, IP_MAX, portstr, PORT_MAX,
> 		            NI_NUMERICHOST | NI_NUMERICSERV);

Site IPsec, Second Approach

… to be continued …

encryption/ipsec.txt · Last modified: 2009/10/18 22:17 (external edit)