Moved all kernel plugins to libhydra.
authorTobias Brunner <tobias@strongswan.org>
Mon, 12 Jul 2010 16:10:16 +0000 (18:10 +0200)
committerTobias Brunner <tobias@strongswan.org>
Thu, 2 Sep 2010 17:01:26 +0000 (19:01 +0200)
55 files changed:
configure.in
src/libcharon/Android.mk
src/libcharon/Makefile.am
src/libcharon/plugins/kernel_klips/Makefile.am [deleted file]
src/libcharon/plugins/kernel_klips/kernel_klips_ipsec.c [deleted file]
src/libcharon/plugins/kernel_klips/kernel_klips_ipsec.h [deleted file]
src/libcharon/plugins/kernel_klips/kernel_klips_plugin.c [deleted file]
src/libcharon/plugins/kernel_klips/kernel_klips_plugin.h [deleted file]
src/libcharon/plugins/kernel_klips/pfkeyv2.h [deleted file]
src/libcharon/plugins/kernel_netlink/Makefile.am [deleted file]
src/libcharon/plugins/kernel_netlink/kernel_netlink_ipsec.c [deleted file]
src/libcharon/plugins/kernel_netlink/kernel_netlink_ipsec.h [deleted file]
src/libcharon/plugins/kernel_netlink/kernel_netlink_net.c [deleted file]
src/libcharon/plugins/kernel_netlink/kernel_netlink_net.h [deleted file]
src/libcharon/plugins/kernel_netlink/kernel_netlink_plugin.c [deleted file]
src/libcharon/plugins/kernel_netlink/kernel_netlink_plugin.h [deleted file]
src/libcharon/plugins/kernel_netlink/kernel_netlink_shared.c [deleted file]
src/libcharon/plugins/kernel_netlink/kernel_netlink_shared.h [deleted file]
src/libcharon/plugins/kernel_pfkey/Makefile.am [deleted file]
src/libcharon/plugins/kernel_pfkey/kernel_pfkey_ipsec.c [deleted file]
src/libcharon/plugins/kernel_pfkey/kernel_pfkey_ipsec.h [deleted file]
src/libcharon/plugins/kernel_pfkey/kernel_pfkey_plugin.c [deleted file]
src/libcharon/plugins/kernel_pfkey/kernel_pfkey_plugin.h [deleted file]
src/libcharon/plugins/kernel_pfroute/Makefile.am [deleted file]
src/libcharon/plugins/kernel_pfroute/kernel_pfroute_net.c [deleted file]
src/libcharon/plugins/kernel_pfroute/kernel_pfroute_net.h [deleted file]
src/libcharon/plugins/kernel_pfroute/kernel_pfroute_plugin.c [deleted file]
src/libcharon/plugins/kernel_pfroute/kernel_pfroute_plugin.h [deleted file]
src/libhydra/Android.mk
src/libhydra/Makefile.am
src/libhydra/plugins/kernel_klips/Makefile.am [new file with mode: 0644]
src/libhydra/plugins/kernel_klips/kernel_klips_ipsec.c [new file with mode: 0644]
src/libhydra/plugins/kernel_klips/kernel_klips_ipsec.h [new file with mode: 0644]
src/libhydra/plugins/kernel_klips/kernel_klips_plugin.c [new file with mode: 0644]
src/libhydra/plugins/kernel_klips/kernel_klips_plugin.h [new file with mode: 0644]
src/libhydra/plugins/kernel_klips/pfkeyv2.h [new file with mode: 0644]
src/libhydra/plugins/kernel_netlink/Makefile.am [new file with mode: 0644]
src/libhydra/plugins/kernel_netlink/kernel_netlink_ipsec.c [new file with mode: 0644]
src/libhydra/plugins/kernel_netlink/kernel_netlink_ipsec.h [new file with mode: 0644]
src/libhydra/plugins/kernel_netlink/kernel_netlink_net.c [new file with mode: 0644]
src/libhydra/plugins/kernel_netlink/kernel_netlink_net.h [new file with mode: 0644]
src/libhydra/plugins/kernel_netlink/kernel_netlink_plugin.c [new file with mode: 0644]
src/libhydra/plugins/kernel_netlink/kernel_netlink_plugin.h [new file with mode: 0644]
src/libhydra/plugins/kernel_netlink/kernel_netlink_shared.c [new file with mode: 0644]
src/libhydra/plugins/kernel_netlink/kernel_netlink_shared.h [new file with mode: 0644]
src/libhydra/plugins/kernel_pfkey/Makefile.am [new file with mode: 0644]
src/libhydra/plugins/kernel_pfkey/kernel_pfkey_ipsec.c [new file with mode: 0644]
src/libhydra/plugins/kernel_pfkey/kernel_pfkey_ipsec.h [new file with mode: 0644]
src/libhydra/plugins/kernel_pfkey/kernel_pfkey_plugin.c [new file with mode: 0644]
src/libhydra/plugins/kernel_pfkey/kernel_pfkey_plugin.h [new file with mode: 0644]
src/libhydra/plugins/kernel_pfroute/Makefile.am [new file with mode: 0644]
src/libhydra/plugins/kernel_pfroute/kernel_pfroute_net.c [new file with mode: 0644]
src/libhydra/plugins/kernel_pfroute/kernel_pfroute_net.h [new file with mode: 0644]
src/libhydra/plugins/kernel_pfroute/kernel_pfroute_plugin.c [new file with mode: 0644]
src/libhydra/plugins/kernel_pfroute/kernel_pfroute_plugin.h [new file with mode: 0644]

index 996b87f..ea49f1c 100644 (file)
@@ -724,12 +724,12 @@ ADD_PLUGIN([gcm],                  [s libcharon scripts])
 ADD_PLUGIN([xauth],                [p pluto])
 ADD_PLUGIN([attr],                 [h libcharon pluto])
 ADD_PLUGIN([attr-sql],             [h libcharon pluto])
+ADD_PLUGIN([kernel-pfkey],         [h libcharon pluto])
+ADD_PLUGIN([kernel-pfroute],       [h libcharon pluto])
+ADD_PLUGIN([kernel-klips],         [h libcharon pluto])
+ADD_PLUGIN([kernel-netlink],       [h libcharon pluto])
 ADD_PLUGIN([resolve],              [h libcharon pluto])
 ADD_PLUGIN([load-tester],          [c libcharon])
-ADD_PLUGIN([kernel-pfkey],         [c libcharon])
-ADD_PLUGIN([kernel-pfroute],       [c libcharon])
-ADD_PLUGIN([kernel-klips],         [c libcharon])
-ADD_PLUGIN([kernel-netlink],       [c libcharon])
 ADD_PLUGIN([socket-default],       [c libcharon])
 ADD_PLUGIN([socket-raw],           [c libcharon])
 ADD_PLUGIN([socket-dynamic],       [c libcharon])
@@ -847,10 +847,6 @@ AM_CONDITIONAL(USE_EAP_TLS, test x$eap_tls = xtrue)
 AM_CONDITIONAL(USE_EAP_TTLS, test x$eap_ttls = xtrue)
 AM_CONDITIONAL(USE_EAP_TNC, test x$eap_tnc = xtrue)
 AM_CONDITIONAL(USE_EAP_RADIUS, test x$eap_radius = xtrue)
-AM_CONDITIONAL(USE_KERNEL_NETLINK, test x$kernel_netlink = xtrue)
-AM_CONDITIONAL(USE_KERNEL_PFKEY, test x$kernel_pfkey = xtrue)
-AM_CONDITIONAL(USE_KERNEL_PFROUTE, test x$kernel_pfroute = xtrue)
-AM_CONDITIONAL(USE_KERNEL_KLIPS, test x$kernel_klips = xtrue)
 AM_CONDITIONAL(USE_SOCKET_DEFAULT, test x$socket_default = xtrue)
 AM_CONDITIONAL(USE_SOCKET_RAW, test x$socket_raw = xtrue)
 AM_CONDITIONAL(USE_SOCKET_DYNAMIC, test x$socket_dynamic = xtrue)
@@ -861,6 +857,10 @@ dnl hydra plugins
 dnl =============
 AM_CONDITIONAL(USE_ATTR, test x$attr = xtrue)
 AM_CONDITIONAL(USE_ATTR_SQL, test x$attr_sql = xtrue -o x$sql = xtrue)
+AM_CONDITIONAL(USE_KERNEL_KLIPS, test x$kernel_klips = xtrue)
+AM_CONDITIONAL(USE_KERNEL_NETLINK, test x$kernel_netlink = xtrue)
+AM_CONDITIONAL(USE_KERNEL_PFKEY, test x$kernel_pfkey = xtrue)
+AM_CONDITIONAL(USE_KERNEL_PFROUTE, test x$kernel_pfroute = xtrue)
 AM_CONDITIONAL(USE_RESOLVE, test x$resolve = xtrue)
 
 dnl pluto plugins
@@ -955,6 +955,10 @@ AC_OUTPUT(
        src/libhydra/Makefile
        src/libhydra/plugins/attr/Makefile
        src/libhydra/plugins/attr_sql/Makefile
+       src/libhydra/plugins/kernel_klips/Makefile
+       src/libhydra/plugins/kernel_netlink/Makefile
+       src/libhydra/plugins/kernel_pfkey/Makefile
+       src/libhydra/plugins/kernel_pfroute/Makefile
        src/libhydra/plugins/resolve/Makefile
        src/libfreeswan/Makefile
        src/libsimaka/Makefile
@@ -979,10 +983,6 @@ AC_OUTPUT(
        src/libcharon/plugins/eap_ttls/Makefile
        src/libcharon/plugins/eap_tnc/Makefile
        src/libcharon/plugins/eap_radius/Makefile
-       src/libcharon/plugins/kernel_netlink/Makefile
-       src/libcharon/plugins/kernel_pfkey/Makefile
-       src/libcharon/plugins/kernel_pfroute/Makefile
-       src/libcharon/plugins/kernel_klips/Makefile
        src/libcharon/plugins/socket_default/Makefile
        src/libcharon/plugins/socket_raw/Makefile
        src/libcharon/plugins/socket_dynamic/Makefile
index 2724b9b..e7de8e5 100644 (file)
@@ -135,10 +135,6 @@ LOCAL_SRC_FILES += $(addprefix ../libsimaka/, \
        )
 endif
 
-LOCAL_SRC_FILES += $(call add_plugin, kernel-netlink)
-
-LOCAL_SRC_FILES += $(call add_plugin, kernel-pfkey)
-
 LOCAL_SRC_FILES += $(call add_plugin, load-tester)
 
 LOCAL_SRC_FILES += $(call add_plugin, socket-default)
index ca2b8ff..ef5f9f4 100644 (file)
@@ -137,34 +137,6 @@ if MONOLITHIC
 endif
 endif
 
-if USE_KERNEL_PFKEY
-  SUBDIRS += plugins/kernel_pfkey
-if MONOLITHIC
-  libcharon_la_LIBADD += plugins/kernel_pfkey/libstrongswan-kernel-pfkey.la
-endif
-endif
-
-if USE_KERNEL_PFROUTE
-  SUBDIRS += plugins/kernel_pfroute
-if MONOLITHIC
-  libcharon_la_LIBADD += plugins/kernel_pfroute/libstrongswan-kernel-pfroute.la
-endif
-endif
-
-if USE_KERNEL_KLIPS
-  SUBDIRS += plugins/kernel_klips
-if MONOLITHIC
-  libcharon_la_LIBADD += plugins/kernel_klips/libstrongswan-kernel-klips.la
-endif
-endif
-
-if USE_KERNEL_NETLINK
-  SUBDIRS += plugins/kernel_netlink
-if MONOLITHIC
-  libcharon_la_LIBADD += plugins/kernel_netlink/libstrongswan-kernel-netlink.la
-endif
-endif
-
 if USE_SOCKET_DEFAULT
   SUBDIRS += plugins/socket_default
 if MONOLITHIC
diff --git a/src/libcharon/plugins/kernel_klips/Makefile.am b/src/libcharon/plugins/kernel_klips/Makefile.am
deleted file mode 100644 (file)
index 540bbe1..0000000
+++ /dev/null
@@ -1,17 +0,0 @@
-
-INCLUDES = -I$(top_srcdir)/src/libstrongswan -I$(top_srcdir)/src/libhydra \
-       -I$(top_srcdir)/src/libcharon
-
-AM_CFLAGS = -rdynamic
-
-if MONOLITHIC
-noinst_LTLIBRARIES = libstrongswan-kernel-klips.la
-else
-plugin_LTLIBRARIES = libstrongswan-kernel-klips.la
-endif
-
-libstrongswan_kernel_klips_la_SOURCES = \
-       kernel_klips_plugin.h kernel_klips_plugin.c \
-       kernel_klips_ipsec.h kernel_klips_ipsec.c pfkeyv2.h
-
-libstrongswan_kernel_klips_la_LDFLAGS = -module -avoid-version
diff --git a/src/libcharon/plugins/kernel_klips/kernel_klips_ipsec.c b/src/libcharon/plugins/kernel_klips/kernel_klips_ipsec.c
deleted file mode 100644 (file)
index 68cab17..0000000
+++ /dev/null
@@ -1,2644 +0,0 @@
-/*
- * Copyright (C) 2008 Tobias Brunner
- * Hochschule fuer Technik Rapperswil
- *
- * This program is free software; you can redistribute it and/or modify it
- * under the terms of the GNU General Public License as published by the
- * Free Software Foundation; either version 2 of the License, or (at your
- * option) any later version.  See <http://www.fsf.org/copyleft/gpl.txt>.
- *
- * This program is distributed in the hope that it will be useful, but
- * WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY
- * or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License
- * for more details.
- */
-
-#include <sys/types.h>
-#include <sys/socket.h>
-#include <sys/ioctl.h>
-#include <stdint.h>
-#include "pfkeyv2.h"
-#include <linux/udp.h>
-#include <net/if.h>
-#include <unistd.h>
-#include <stdio.h>
-#include <string.h>
-#include <time.h>
-#include <errno.h>
-
-#include "kernel_klips_ipsec.h"
-
-#include <hydra.h>
-#include <daemon.h>
-#include <threading/thread.h>
-#include <threading/mutex.h>
-#include <processing/jobs/callback_job.h>
-
-/** default timeout for generated SPIs (in seconds) */
-#define SPI_TIMEOUT 30
-
-/** buffer size for PF_KEY messages */
-#define PFKEY_BUFFER_SIZE 2048
-
-/** PF_KEY messages are 64 bit aligned */
-#define PFKEY_ALIGNMENT 8
-/** aligns len to 64 bits */
-#define PFKEY_ALIGN(len) (((len) + PFKEY_ALIGNMENT - 1) & ~(PFKEY_ALIGNMENT - 1))
-/** calculates the properly padded length in 64 bit chunks */
-#define PFKEY_LEN(len) ((PFKEY_ALIGN(len) / PFKEY_ALIGNMENT))
-/** calculates user mode length i.e. in bytes */
-#define PFKEY_USER_LEN(len) ((len) * PFKEY_ALIGNMENT)
-
-/** given a PF_KEY message header and an extension this updates the length in the header */
-#define PFKEY_EXT_ADD(msg, ext) ((msg)->sadb_msg_len += ((struct sadb_ext*)ext)->sadb_ext_len)
-/** given a PF_KEY message header this returns a pointer to the next extension */
-#define PFKEY_EXT_ADD_NEXT(msg) ((struct sadb_ext*)(((char*)(msg)) + PFKEY_USER_LEN((msg)->sadb_msg_len)))
-/** copy an extension and append it to a PF_KEY message */
-#define PFKEY_EXT_COPY(msg, ext) (PFKEY_EXT_ADD(msg, memcpy(PFKEY_EXT_ADD_NEXT(msg), ext, PFKEY_USER_LEN(((struct sadb_ext*)ext)->sadb_ext_len))))
-/** given a PF_KEY extension this returns a pointer to the next extension */
-#define PFKEY_EXT_NEXT(ext) ((struct sadb_ext*)(((char*)(ext)) + PFKEY_USER_LEN(((struct sadb_ext*)ext)->sadb_ext_len)))
-/** given a PF_KEY extension this returns a pointer to the next extension also updates len (len in 64 bit words) */
-#define PFKEY_EXT_NEXT_LEN(ext,len) ((len) -= (ext)->sadb_ext_len, PFKEY_EXT_NEXT(ext))
-/** true if ext has a valid length and len is large enough to contain ext (assuming len in 64 bit words) */
-#define PFKEY_EXT_OK(ext,len) ((len) >= PFKEY_LEN(sizeof(struct sadb_ext)) && \
-                               (ext)->sadb_ext_len >= PFKEY_LEN(sizeof(struct sadb_ext)) && \
-                               (ext)->sadb_ext_len <= (len))
-
-/** special SPI values used for policies in KLIPS */
-#define SPI_PASS 256
-#define SPI_DROP 257
-#define SPI_REJECT 258
-#define SPI_HOLD 259
-#define SPI_TRAP 260
-#define SPI_TRAPSUBNET 261
-
-/** the prefix of the name of KLIPS ipsec devices */
-#define IPSEC_DEV_PREFIX "ipsec"
-/** this is the default number of ipsec devices */
-#define DEFAULT_IPSEC_DEV_COUNT 4
-/** TRUE if the given name matches an ipsec device */
-#define IS_IPSEC_DEV(name) (strneq((name), IPSEC_DEV_PREFIX, sizeof(IPSEC_DEV_PREFIX) - 1))
-
-/** the following stuff is from ipsec_tunnel.h */
-struct ipsectunnelconf
-{
-       __u32   cf_cmd;
-       union
-       {
-               char    cfu_name[12];
-       } cf_u;
-#define cf_name cf_u.cfu_name
-};
-
-#define IPSEC_SET_DEV (SIOCDEVPRIVATE)
-#define IPSEC_DEL_DEV (SIOCDEVPRIVATE + 1)
-#define IPSEC_CLR_DEV (SIOCDEVPRIVATE + 2)
-
-typedef struct private_kernel_klips_ipsec_t private_kernel_klips_ipsec_t;
-
-/**
- * Private variables and functions of kernel_klips class.
- */
-struct private_kernel_klips_ipsec_t
-{
-       /**
-        * Public part of the kernel_klips_t object.
-        */
-       kernel_klips_ipsec_t public;
-
-       /**
-        * mutex to lock access to various lists
-        */
-       mutex_t *mutex;
-
-       /**
-        * List of installed policies (policy_entry_t)
-        */
-       linked_list_t *policies;
-
-       /**
-        * List of allocated SPIs without installed SA (sa_entry_t)
-        */
-       linked_list_t *allocated_spis;
-
-       /**
-        * List of installed SAs (sa_entry_t)
-        */
-       linked_list_t *installed_sas;
-
-       /**
-        * whether to install routes along policies
-        */
-       bool install_routes;
-
-       /**
-        * List of ipsec devices (ipsec_dev_t)
-        */
-       linked_list_t *ipsec_devices;
-
-       /**
-        * job receiving PF_KEY events
-        */
-       callback_job_t *job;
-
-       /**
-        * mutex to lock access to the PF_KEY socket
-        */
-       mutex_t *mutex_pfkey;
-
-       /**
-        * PF_KEY socket to communicate with the kernel
-        */
-       int socket;
-
-       /**
-        * PF_KEY socket to receive acquire and expire events
-        */
-       int socket_events;
-
-       /**
-        * sequence number for messages sent to the kernel
-        */
-       int seq;
-
-};
-
-
-typedef struct ipsec_dev_t ipsec_dev_t;
-
-/**
- * ipsec device
- */
-struct ipsec_dev_t {
-       /** name of the virtual ipsec interface */
-       char name[IFNAMSIZ];
-
-       /** name of the physical interface */
-       char phys_name[IFNAMSIZ];
-
-       /** by how many CHILD_SA's this ipsec device is used */
-       u_int refcount;
-};
-
-/**
- * compare the given name with the virtual device name
- */
-static inline bool ipsec_dev_match_byname(ipsec_dev_t *current, char *name)
-{
-       return name && streq(current->name, name);
-}
-
-/**
- * compare the given name with the physical device name
- */
-static inline bool ipsec_dev_match_byphys(ipsec_dev_t *current, char *name)
-{
-       return name && streq(current->phys_name, name);
-}
-
-/**
- * matches free ipsec devices
- */
-static inline bool ipsec_dev_match_free(ipsec_dev_t *current)
-{
-       return current->refcount == 0;
-}
-
-/**
- * tries to find an ipsec_dev_t object by name
- */
-static status_t find_ipsec_dev(private_kernel_klips_ipsec_t *this, char *name,
-                                                          ipsec_dev_t **dev)
-{
-       linked_list_match_t match = (linked_list_match_t)(IS_IPSEC_DEV(name) ?
-                                                               ipsec_dev_match_byname : ipsec_dev_match_byphys);
-       return this->ipsec_devices->find_first(this->ipsec_devices, match,
-                                                                                               (void**)dev, name);
-}
-
-/**
- * attach an ipsec device to a physical interface
- */
-static status_t attach_ipsec_dev(char* name, char *phys_name)
-{
-       int sock;
-       struct ifreq req;
-       struct ipsectunnelconf *itc = (struct ipsectunnelconf*)&req.ifr_data;
-       short phys_flags;
-       int mtu;
-
-       DBG2(DBG_KNL, "attaching virtual interface %s to %s", name, phys_name);
-
-       if ((sock = socket(AF_INET, SOCK_DGRAM, 0)) <= 0)
-       {
-               return FAILED;
-       }
-
-       strncpy(req.ifr_name, phys_name, IFNAMSIZ);
-       if (ioctl(sock, SIOCGIFFLAGS, &req) < 0)
-       {
-               close(sock);
-               return FAILED;
-       }
-       phys_flags = req.ifr_flags;
-
-       strncpy(req.ifr_name, name, IFNAMSIZ);
-       if (ioctl(sock, SIOCGIFFLAGS, &req) < 0)
-       {
-               close(sock);
-               return FAILED;
-       }
-
-       if (req.ifr_flags & IFF_UP)
-       {
-               /* if it's already up, it is already attached, detach it first */
-               ioctl(sock, IPSEC_DEL_DEV, &req);
-       }
-
-       /* attach it */
-       strncpy(req.ifr_name, name, IFNAMSIZ);
-       strncpy(itc->cf_name, phys_name, sizeof(itc->cf_name));
-       ioctl(sock, IPSEC_SET_DEV, &req);
-
-       /* copy address from physical to virtual */
-       strncpy(req.ifr_name, phys_name, IFNAMSIZ);
-       if (ioctl(sock, SIOCGIFADDR, &req) == 0)
-       {
-               strncpy(req.ifr_name, name, IFNAMSIZ);
-               ioctl(sock, SIOCSIFADDR, &req);
-       }
-
-       /* copy net mask from physical to virtual */
-       strncpy(req.ifr_name, phys_name, IFNAMSIZ);
-       if (ioctl(sock, SIOCGIFNETMASK, &req) == 0)
-       {
-               strncpy(req.ifr_name, name, IFNAMSIZ);
-               ioctl(sock, SIOCSIFNETMASK, &req);
-       }
-
-       /* copy other flags and addresses */
-       strncpy(req.ifr_name, name, IFNAMSIZ);
-       if (ioctl(sock, SIOCGIFFLAGS, &req) == 0)
-       {
-               if (phys_flags & IFF_POINTOPOINT)
-               {
-                       req.ifr_flags |= IFF_POINTOPOINT;
-                       req.ifr_flags &= ~IFF_BROADCAST;
-                       ioctl(sock, SIOCSIFFLAGS, &req);
-
-                       strncpy(req.ifr_name, phys_name, IFNAMSIZ);
-                       if (ioctl(sock, SIOCGIFDSTADDR, &req) == 0)
-                       {
-                               strncpy(req.ifr_name, name, IFNAMSIZ);
-                               ioctl(sock, SIOCSIFDSTADDR, &req);
-                       }
-               }
-               else if (phys_flags & IFF_BROADCAST)
-               {
-                       req.ifr_flags &= ~IFF_POINTOPOINT;
-                       req.ifr_flags |= IFF_BROADCAST;
-                       ioctl(sock, SIOCSIFFLAGS, &req);
-
-                       strncpy(req.ifr_name, phys_name, IFNAMSIZ);
-                       if (ioctl(sock, SIOCGIFBRDADDR, &req)==0)
-                       {
-                               strncpy(req.ifr_name, name, IFNAMSIZ);
-                               ioctl(sock, SIOCSIFBRDADDR, &req);
-                       }
-               }
-               else
-               {
-                       req.ifr_flags &= ~IFF_POINTOPOINT;
-                       req.ifr_flags &= ~IFF_BROADCAST;
-                       ioctl(sock, SIOCSIFFLAGS, &req);
-               }
-       }
-
-       mtu = lib->settings->get_int(lib->settings,
-                                               "charon.plugins.kernel-klips.ipsec_dev_mtu", 0);
-       if (mtu <= 0)
-       {
-               /* guess MTU as physical MTU - ESP overhead [- NAT-T overhead]
-                * ESP overhead      : 73 bytes
-                * NAT-T overhead    :  8 bytes ==> 81 bytes
-                *
-                * assuming tunnel mode with AES encryption and integrity
-                * outer IP header  : 20 bytes
-                * (NAT-T UDP header:  8 bytes)
-                * ESP header       :  8 bytes
-                * IV               : 16 bytes
-                * padding          : 15 bytes (worst-case)
-                * pad len / NH     :  2 bytes
-                * auth data        : 12 bytes
-                */
-               strncpy(req.ifr_name, phys_name, IFNAMSIZ);
-               ioctl(sock, SIOCGIFMTU, &req);
-               mtu = req.ifr_mtu - 81;
-       }
-
-       /* set MTU */
-       strncpy(req.ifr_name, name, IFNAMSIZ);
-       req.ifr_mtu = mtu;
-       ioctl(sock, SIOCSIFMTU, &req);
-
-       /* bring ipsec device UP */
-       if (ioctl(sock, SIOCGIFFLAGS, &req) == 0)
-       {
-               req.ifr_flags |= IFF_UP;
-               ioctl(sock, SIOCSIFFLAGS, &req);
-       }
-
-       close(sock);
-       return SUCCESS;
-}
-
-/**
- * detach an ipsec device from a physical interface
- */
-static status_t detach_ipsec_dev(char* name, char *phys_name)
-{
-       int sock;
-       struct ifreq req;
-
-       DBG2(DBG_KNL, "detaching virtual interface %s from %s", name,
-                       strlen(phys_name) ? phys_name : "any physical interface");
-
-       if ((sock = socket(AF_INET, SOCK_DGRAM, 0)) <= 0)
-       {
-               return FAILED;
-       }
-
-       strncpy(req.ifr_name, name, IFNAMSIZ);
-       if (ioctl(sock, SIOCGIFFLAGS, &req) < 0)
-       {
-               close(sock);
-               return FAILED;
-       }
-
-       /* shutting interface down */
-       if (req.ifr_flags & IFF_UP)
-       {
-               req.ifr_flags &= ~IFF_UP;
-               ioctl(sock, SIOCSIFFLAGS, &req);
-       }
-
-       /* unset address */
-       memset(&req.ifr_addr, 0, sizeof(req.ifr_addr));
-       req.ifr_addr.sa_family = AF_INET;
-       ioctl(sock, SIOCSIFADDR, &req);
-
-       /* detach interface */
-       ioctl(sock, IPSEC_DEL_DEV, &req);
-
-       close(sock);
-       return SUCCESS;
-}
-
-/**
- * destroy an ipsec_dev_t object
- */
-static void ipsec_dev_destroy(ipsec_dev_t *this)
-{
-       detach_ipsec_dev(this->name, this->phys_name);
-       free(this);
-}
-
-
-typedef struct route_entry_t route_entry_t;
-
-/**
- * installed routing entry
- */
-struct route_entry_t {
-       /** Name of the interface the route is bound to */
-       char *if_name;
-
-       /** Source ip of the route */
-       host_t *src_ip;
-
-       /** Gateway for this route */
-       host_t *gateway;
-
-       /** Destination net */
-       chunk_t dst_net;
-
-       /** Destination net prefixlen */
-       u_int8_t prefixlen;
-};
-
-/**
- * destroy an route_entry_t object
- */
-static void route_entry_destroy(route_entry_t *this)
-{
-       free(this->if_name);
-       this->src_ip->destroy(this->src_ip);
-       this->gateway->destroy(this->gateway);
-       chunk_free(&this->dst_net);
-       free(this);
-}
-
-typedef struct policy_entry_t policy_entry_t;
-
-/**
- * installed kernel policy.
- */
-struct policy_entry_t {
-
-       /** reqid of this policy, if setup as trap */
-       u_int32_t reqid;
-
-       /** direction of this policy: in, out, forward */
-       u_int8_t direction;
-
-       /** parameters of installed policy */
-       struct {
-               /** subnet and port */
-               host_t *net;
-               /** subnet mask */
-               u_int8_t mask;
-               /** protocol */
-               u_int8_t proto;
-       } src, dst;
-
-       /** associated route installed for this policy */
-       route_entry_t *route;
-
-       /** by how many CHILD_SA's this policy is actively used */
-       u_int activecount;
-
-       /** by how many CHILD_SA's this policy is trapped */
-       u_int trapcount;
-};
-
-/**
- * convert a numerical netmask to a host_t
- */
-static host_t *mask2host(int family, u_int8_t mask)
-{
-       static const u_char bitmask[] = { 0x00, 0x80, 0xc0, 0xe0, 0xf0, 0xf8, 0xfc, 0xfe };
-       chunk_t chunk = chunk_alloca(family == AF_INET ? 4 : 16);
-       int bytes = mask / 8, bits = mask % 8;
-       memset(chunk.ptr, 0xFF, bytes);
-       memset(chunk.ptr + bytes, 0, chunk.len - bytes);
-       if (bits)
-       {
-               chunk.ptr[bytes] =  bitmask[bits];
-       }
-       return host_create_from_chunk(family, chunk, 0);
-}
-
-/**
- * check if a host is in a subnet (host with netmask in bits)
- */
-static bool is_host_in_net(host_t *host, host_t *net, u_int8_t mask)
-{
-       static const u_char bitmask[] = { 0x00, 0x80, 0xc0, 0xe0, 0xf0, 0xf8, 0xfc, 0xfe };
-       chunk_t host_chunk, net_chunk;
-       int bytes = mask / 8, bits = mask % 8;
-
-       host_chunk = host->get_address(host);
-       net_chunk = net->get_address(net);
-
-       if (host_chunk.len != net_chunk.len)
-       {
-               return FALSE;
-       }
-
-       if (memeq(host_chunk.ptr, net_chunk.ptr, bytes))
-       {
-               return (bits == 0) ||
-                          (host_chunk.ptr[bytes] & bitmask[bits]) ==
-                                  (net_chunk.ptr[bytes] & bitmask[bits]);
-       }
-
-       return FALSE;
-}
-
-/**
- * create a policy_entry_t object
- */
-static policy_entry_t *create_policy_entry(traffic_selector_t *src_ts,
-               traffic_selector_t *dst_ts, policy_dir_t dir)
-{
-       policy_entry_t *policy = malloc_thing(policy_entry_t);
-       policy->reqid = 0;
-       policy->direction = dir;
-       policy->route = NULL;
-       policy->activecount = 0;
-       policy->trapcount = 0;
-
-       src_ts->to_subnet(src_ts, &policy->src.net, &policy->src.mask);
-       dst_ts->to_subnet(dst_ts, &policy->dst.net, &policy->dst.mask);
-
-       /* src or dest proto may be "any" (0), use more restrictive one */
-       policy->src.proto = max(src_ts->get_protocol(src_ts), dst_ts->get_protocol(dst_ts));
-       policy->src.proto = policy->src.proto ? policy->src.proto : 0;
-       policy->dst.proto = policy->src.proto;
-
-       return policy;
-}
-
-/**
- * destroy a policy_entry_t object
- */
-static void policy_entry_destroy(policy_entry_t *this)
-{
-       DESTROY_IF(this->src.net);
-       DESTROY_IF(this->dst.net);
-       if (this->route)
-       {
-               route_entry_destroy(this->route);
-       }
-       free(this);
-}
-
-/**
- * compares two policy_entry_t
- */
-static inline bool policy_entry_equals(policy_entry_t *current, policy_entry_t *policy)
-{
-       return current->direction == policy->direction &&
-                  current->src.proto == policy->src.proto &&
-                  current->dst.proto == policy->dst.proto &&
-                  current->src.mask == policy->src.mask &&
-                  current->dst.mask == policy->dst.mask &&
-                  current->src.net->equals(current->src.net, policy->src.net) &&
-                  current->dst.net->equals(current->dst.net, policy->dst.net);
-}
-
-static inline bool policy_entry_match_byaddrs(policy_entry_t *current, host_t *src,
-               host_t *dst)
-{
-       return is_host_in_net(src, current->src.net, current->src.mask) &&
-                       is_host_in_net(dst, current->dst.net, current->dst.mask);
-}
-
-typedef struct sa_entry_t sa_entry_t;
-
-/**
- * used for two things:
- * - allocated SPIs that have not yet resulted in an installed SA
- * - installed inbound SAs with enabled UDP encapsulation
- */
-struct sa_entry_t {
-
-       /** protocol of this SA */
-       u_int8_t protocol;
-
-       /** reqid of this SA */
-       u_int32_t reqid;
-
-       /** SPI of this SA */
-       u_int32_t spi;
-
-       /** src address of this SA */
-       host_t *src;
-
-       /** dst address of this SA */
-       host_t *dst;
-
-       /** TRUE if this SA uses UDP encapsulation */
-       bool encap;
-
-       /** TRUE if this SA is inbound */
-       bool inbound;
-};
-
-/**
- * create an sa_entry_t object
- */
-static sa_entry_t *create_sa_entry(u_int8_t protocol, u_int32_t spi,
-                                                                  u_int32_t reqid, host_t *src, host_t *dst,
-                                                                  bool encap, bool inbound)
-{
-       sa_entry_t *sa = malloc_thing(sa_entry_t);
-       sa->protocol = protocol;
-       sa->reqid = reqid;
-       sa->spi = spi;
-       sa->src = src ? src->clone(src) : NULL;
-       sa->dst = dst ? dst->clone(dst) : NULL;
-       sa->encap = encap;
-       sa->inbound = inbound;
-       return sa;
-}
-
-/**
- * destroy an sa_entry_t object
- */
-static void sa_entry_destroy(sa_entry_t *this)
-{
-       DESTROY_IF(this->src);
-       DESTROY_IF(this->dst);
-       free(this);
-}
-
-/**
- * match an sa_entry_t for an inbound SA that uses UDP encapsulation by spi and src (remote) address
- */
-static inline bool sa_entry_match_encapbysrc(sa_entry_t *current, u_int32_t *spi,
-               host_t *src)
-{
-       return current->encap && current->inbound &&
-                  current->spi == *spi && src->ip_equals(src, current->src);
-}
-
-/**
- * match an sa_entry_t by protocol, spi and dst address (as the kernel does it)
- */
-static inline bool sa_entry_match_bydst(sa_entry_t *current, u_int8_t *protocol,
-               u_int32_t *spi, host_t *dst)
-{
-       return current->protocol == *protocol && current->spi == *spi && dst->ip_equals(dst, current->dst);
-}
-
-/**
- * match an sa_entry_t by protocol, reqid and spi
- */
-static inline bool sa_entry_match_byid(sa_entry_t *current, u_int8_t *protocol,
-               u_int32_t *spi, u_int32_t *reqid)
-{
-       return current->protocol == *protocol && current->spi == *spi && current->reqid == *reqid;
-}
-
-typedef struct pfkey_msg_t pfkey_msg_t;
-
-struct pfkey_msg_t
-{
-       /**
-        * PF_KEY message base
-        */
-       struct sadb_msg *msg;
-
-
-       /**
-        * PF_KEY message extensions
-        */
-       union {
-               struct sadb_ext *ext[SADB_EXT_MAX + 1];
-               struct {
-                       struct sadb_ext *reserved;                              /* SADB_EXT_RESERVED */
-                       struct sadb_sa *sa;                                             /* SADB_EXT_SA */
-                       struct sadb_lifetime *lft_current;              /* SADB_EXT_LIFETIME_CURRENT */
-                       struct sadb_lifetime *lft_hard;                 /* SADB_EXT_LIFETIME_HARD */
-                       struct sadb_lifetime *lft_soft;                 /* SADB_EXT_LIFETIME_SOFT */
-                       struct sadb_address *src;                               /* SADB_EXT_ADDRESS_SRC */
-                       struct sadb_address *dst;                               /* SADB_EXT_ADDRESS_DST */
-                       struct sadb_address *proxy;                             /* SADB_EXT_ADDRESS_PROXY */
-                       struct sadb_key *key_auth;                              /* SADB_EXT_KEY_AUTH */
-                       struct sadb_key *key_encr;                              /* SADB_EXT_KEY_ENCRYPT */
-                       struct sadb_ident *id_src;                              /* SADB_EXT_IDENTITY_SRC */
-                       struct sadb_ident *id_dst;                              /* SADB_EXT_IDENTITY_DST */
-                       struct sadb_sens *sensitivity;                  /* SADB_EXT_SENSITIVITY */
-                       struct sadb_prop *proposal;                             /* SADB_EXT_PROPOSAL */
-                       struct sadb_supported *supported_auth;  /* SADB_EXT_SUPPORTED_AUTH */
-                       struct sadb_supported *supported_encr;  /* SADB_EXT_SUPPORTED_ENCRYPT */
-                       struct sadb_spirange *spirange;                 /* SADB_EXT_SPIRANGE */
-                       struct sadb_x_kmprivate *x_kmprivate;   /* SADB_X_EXT_KMPRIVATE */
-                       struct sadb_ext *x_policy;                              /* SADB_X_EXT_SATYPE2 */
-                       struct sadb_ext *x_sa2;                                 /* SADB_X_EXT_SA2 */
-                       struct sadb_address *x_dst2;                    /* SADB_X_EXT_ADDRESS_DST2 */
-                       struct sadb_address *x_src_flow;                /* SADB_X_EXT_ADDRESS_SRC_FLOW */
-                       struct sadb_address *x_dst_flow;                /* SADB_X_EXT_ADDRESS_DST_FLOW */
-                       struct sadb_address *x_src_mask;                /* SADB_X_EXT_ADDRESS_SRC_MASK */
-                       struct sadb_address *x_dst_mask;                /* SADB_X_EXT_ADDRESS_DST_MASK */
-                       struct sadb_x_debug *x_debug;                   /* SADB_X_EXT_DEBUG */
-                       struct sadb_protocol *x_protocol;               /* SADB_X_EXT_PROTOCOL */
-                       struct sadb_x_nat_t_type *x_natt_type;  /* SADB_X_EXT_NAT_T_TYPE */
-                       struct sadb_x_nat_t_port *x_natt_sport; /* SADB_X_EXT_NAT_T_SPORT */
-                       struct sadb_x_nat_t_port *x_natt_dport; /* SADB_X_EXT_NAT_T_DPORT */
-                       struct sadb_address *x_natt_oa;                 /* SADB_X_EXT_NAT_T_OA */
-               } __attribute__((__packed__));
-       };
-};
-
-/**
- * convert a protocol identifier to the PF_KEY sa type
- */
-static u_int8_t proto2satype(u_int8_t proto)
-{
-       switch (proto)
-       {
-               case IPPROTO_ESP:
-                       return SADB_SATYPE_ESP;
-               case IPPROTO_AH:
-                       return SADB_SATYPE_AH;
-               case IPPROTO_COMP:
-                       return SADB_X_SATYPE_COMP;
-               default:
-                       return proto;
-       }
-}
-
-/**
- * convert a PF_KEY sa type to a protocol identifier
- */
-static u_int8_t satype2proto(u_int8_t satype)
-{
-       switch (satype)
-       {
-               case SADB_SATYPE_ESP:
-                       return IPPROTO_ESP;
-               case SADB_SATYPE_AH:
-                       return IPPROTO_AH;
-               case SADB_X_SATYPE_COMP:
-                       return IPPROTO_COMP;
-               default:
-                       return satype;
-       }
-}
-
-typedef struct kernel_algorithm_t kernel_algorithm_t;
-
-/**
- * Mapping of IKEv2 algorithms to PF_KEY algorithms
- */
-struct kernel_algorithm_t {
-       /**
-        * Identifier specified in IKEv2
-        */
-       int ikev2;
-
-       /**
-        * Identifier as defined in pfkeyv2.h
-        */
-       int kernel;
-};
-
-#define END_OF_LIST -1
-
-/**
- * Algorithms for encryption
- */
-static kernel_algorithm_t encryption_algs[] = {
-/*     {ENCR_DES_IV64,                         0                                                       }, */
-       {ENCR_DES,                                      SADB_EALG_DESCBC                        },
-       {ENCR_3DES,                                     SADB_EALG_3DESCBC                       },
-/*     {ENCR_RC5,                                      0                                                       }, */
-/*     {ENCR_IDEA,                                     0                                                       }, */
-/*     {ENCR_CAST,                                     0                                                       }, */
-       {ENCR_BLOWFISH,                         SADB_EALG_BFCBC                         },
-/*     {ENCR_3IDEA,                            0                                                       }, */
-/*     {ENCR_DES_IV32,                         0                                                       }, */
-       {ENCR_NULL,                                     SADB_EALG_NULL                          },
-       {ENCR_AES_CBC,                          SADB_EALG_AESCBC                        },
-/*     {ENCR_AES_CTR,                          0                                                       }, */
-/*     {ENCR_AES_CCM_ICV8,                     0                                                       }, */
-/*     {ENCR_AES_CCM_ICV12,            0                                                       }, */
-/*     {ENCR_AES_CCM_ICV16,            0                                                       }, */
-/*     {ENCR_AES_GCM_ICV8,                     0                                                       }, */
-/*     {ENCR_AES_GCM_ICV12,            0                                                       }, */
-/*     {ENCR_AES_GCM_ICV16,            0                                                       }, */
-       {END_OF_LIST,                           0                                                       },
-};
-
-/**
- * Algorithms for integrity protection
- */
-static kernel_algorithm_t integrity_algs[] = {
-       {AUTH_HMAC_MD5_96,                      SADB_AALG_MD5HMAC                       },
-       {AUTH_HMAC_SHA1_96,                     SADB_AALG_SHA1HMAC                      },
-       {AUTH_HMAC_SHA2_256_128,        SADB_AALG_SHA256_HMAC           },
-       {AUTH_HMAC_SHA2_384_192,        SADB_AALG_SHA384_HMAC           },
-       {AUTH_HMAC_SHA2_512_256,        SADB_AALG_SHA512_HMAC           },
-/*     {AUTH_DES_MAC,                          0,                                                      }, */
-/*     {AUTH_KPDK_MD5,                         0,                                                      }, */
-/*     {AUTH_AES_XCBC_96,                      0,                                                      }, */
-       {END_OF_LIST,                           0,                                                      },
-};
-
-#if 0
-/**
- * Algorithms for IPComp, unused yet
- */
-static kernel_algorithm_t compression_algs[] = {
-/*     {IPCOMP_OUI,                            0                                                       }, */
-       {IPCOMP_DEFLATE,                        SADB_X_CALG_DEFLATE                     },
-       {IPCOMP_LZS,                            SADB_X_CALG_LZS                         },
-/*     {IPCOMP_LZJH,                           0                                                       }, */
-       {END_OF_LIST,                           0                                                       },
-};
-#endif
-
-/**
- * Look up a kernel algorithm ID and its key size
- */
-static int lookup_algorithm(kernel_algorithm_t *list, int ikev2)
-{
-       while (list->ikev2 != END_OF_LIST)
-       {
-               if (ikev2 == list->ikev2)
-               {
-                       return list->kernel;
-               }
-               list++;
-       }
-       return 0;
-}
-
-/**
- * add a host behind a sadb_address extension
- */
-static void host2ext(host_t *host, struct sadb_address *ext)
-{
-       sockaddr_t *host_addr = host->get_sockaddr(host);
-       socklen_t *len = host->get_sockaddr_len(host);
-       memcpy((char*)(ext + 1), host_addr, *len);
-       ext->sadb_address_len = PFKEY_LEN(sizeof(*ext) + *len);
-}
-
-/**
- * add a host to the given sadb_msg
- */
-static void add_addr_ext(struct sadb_msg *msg, host_t *host, u_int16_t type)
-{
-       struct sadb_address *addr = (struct sadb_address*)PFKEY_EXT_ADD_NEXT(msg);
-       addr->sadb_address_exttype = type;
-       host2ext(host, addr);
-       PFKEY_EXT_ADD(msg, addr);
-}
-
-/**
- * adds an empty address extension to the given sadb_msg
- */
-static void add_anyaddr_ext(struct sadb_msg *msg, int family, u_int8_t type)
-{
-       socklen_t len = (family == AF_INET) ? sizeof(struct sockaddr_in) :
-                                                                                 sizeof(struct sockaddr_in6);
-       struct sadb_address *addr = (struct sadb_address*)PFKEY_EXT_ADD_NEXT(msg);
-       addr->sadb_address_exttype = type;
-       sockaddr_t *saddr = (sockaddr_t*)(addr + 1);
-       saddr->sa_family = family;
-       addr->sadb_address_len = PFKEY_LEN(sizeof(*addr) + len);
-       PFKEY_EXT_ADD(msg, addr);
-}
-
-/**
- * add udp encap extensions to a sadb_msg
- */
-static void add_encap_ext(struct sadb_msg *msg, host_t *src, host_t *dst,
-                                                       bool ports_only)
-{
-       struct sadb_x_nat_t_type* nat_type;
-       struct sadb_x_nat_t_port* nat_port;
-
-       if (!ports_only)
-       {
-               nat_type = (struct sadb_x_nat_t_type*)PFKEY_EXT_ADD_NEXT(msg);
-               nat_type->sadb_x_nat_t_type_exttype = SADB_X_EXT_NAT_T_TYPE;
-               nat_type->sadb_x_nat_t_type_len = PFKEY_LEN(sizeof(struct sadb_x_nat_t_type));
-               nat_type->sadb_x_nat_t_type_type = UDP_ENCAP_ESPINUDP;
-               PFKEY_EXT_ADD(msg, nat_type);
-       }
-
-       nat_port = (struct sadb_x_nat_t_port*)PFKEY_EXT_ADD_NEXT(msg);
-       nat_port->sadb_x_nat_t_port_exttype = SADB_X_EXT_NAT_T_SPORT;
-       nat_port->sadb_x_nat_t_port_len = PFKEY_LEN(sizeof(struct sadb_x_nat_t_port));
-       nat_port->sadb_x_nat_t_port_port = src->get_port(src);
-       PFKEY_EXT_ADD(msg, nat_port);
-
-       nat_port = (struct sadb_x_nat_t_port*)PFKEY_EXT_ADD_NEXT(msg);
-       nat_port->sadb_x_nat_t_port_exttype = SADB_X_EXT_NAT_T_DPORT;
-       nat_port->sadb_x_nat_t_port_len = PFKEY_LEN(sizeof(struct sadb_x_nat_t_port));
-       nat_port->sadb_x_nat_t_port_port = dst->get_port(dst);
-       PFKEY_EXT_ADD(msg, nat_port);
-}
-
-/**
- * build an SADB_X_ADDFLOW msg
- */
-static void build_addflow(struct sadb_msg *msg, u_int8_t satype, u_int32_t spi,
-               host_t *src, host_t *dst, host_t *src_net, u_int8_t src_mask,
-               host_t *dst_net, u_int8_t dst_mask, u_int8_t protocol, bool replace)
-{
-       struct sadb_sa *sa;
-       struct sadb_protocol *proto;
-       host_t *host;
-
-       msg->sadb_msg_version = PF_KEY_V2;
-       msg->sadb_msg_type = SADB_X_ADDFLOW;
-       msg->sadb_msg_satype = satype;
-       msg->sadb_msg_len = PFKEY_LEN(sizeof(struct sadb_msg));
-
-       sa = (struct sadb_sa*)PFKEY_EXT_ADD_NEXT(msg);
-       sa->sadb_sa_exttype = SADB_EXT_SA;
-       sa->sadb_sa_spi = spi;
-       sa->sadb_sa_len = PFKEY_LEN(sizeof(struct sadb_sa));
-       sa->sadb_sa_flags = replace ? SADB_X_SAFLAGS_REPLACEFLOW : 0;
-       PFKEY_EXT_ADD(msg, sa);
-
-       if (!src)
-       {
-               add_anyaddr_ext(msg, src_net->get_family(src_net), SADB_EXT_ADDRESS_SRC);
-       }
-       else
-       {
-               add_addr_ext(msg, src, SADB_EXT_ADDRESS_SRC);
-       }
-
-       if (!dst)
-       {
-               add_anyaddr_ext(msg, dst_net->get_family(dst_net), SADB_EXT_ADDRESS_DST);
-       }
-       else
-       {
-               add_addr_ext(msg, dst, SADB_EXT_ADDRESS_DST);
-       }
-
-       add_addr_ext(msg, src_net, SADB_X_EXT_ADDRESS_SRC_FLOW);
-       add_addr_ext(msg, dst_net, SADB_X_EXT_ADDRESS_DST_FLOW);
-
-       host = mask2host(src_net->get_family(src_net), src_mask);
-       add_addr_ext(msg, host, SADB_X_EXT_ADDRESS_SRC_MASK);
-       host->destroy(host);
-
-       host = mask2host(dst_net->get_family(dst_net), dst_mask);
-       add_addr_ext(msg, host, SADB_X_EXT_ADDRESS_DST_MASK);
-       host->destroy(host);
-
-       proto = (struct sadb_protocol*)PFKEY_EXT_ADD_NEXT(msg);
-       proto->sadb_protocol_exttype = SADB_X_EXT_PROTOCOL;
-       proto->sadb_protocol_len = PFKEY_LEN(sizeof(struct sadb_protocol));
-       proto->sadb_protocol_proto = protocol;
-       PFKEY_EXT_ADD(msg, proto);
-}
-
-/**
- * build an SADB_X_DELFLOW msg
- */
-static void build_delflow(struct sadb_msg *msg, u_int8_t satype,
-               host_t *src_net, u_int8_t src_mask, host_t *dst_net, u_int8_t dst_mask,
-               u_int8_t protocol)
-{
-       struct sadb_protocol *proto;
-       host_t *host;
-
-       msg->sadb_msg_version = PF_KEY_V2;
-       msg->sadb_msg_type = SADB_X_DELFLOW;
-       msg->sadb_msg_satype = satype;
-       msg->sadb_msg_len = PFKEY_LEN(sizeof(struct sadb_msg));
-
-       add_addr_ext(msg, src_net, SADB_X_EXT_ADDRESS_SRC_FLOW);
-       add_addr_ext(msg, dst_net, SADB_X_EXT_ADDRESS_DST_FLOW);
-
-       host = mask2host(src_net->get_family(src_net),
-                                        src_mask);
-       add_addr_ext(msg, host, SADB_X_EXT_ADDRESS_SRC_MASK);
-       host->destroy(host);
-
-       host = mask2host(dst_net->get_family(dst_net),
-                                        dst_mask);
-       add_addr_ext(msg, host, SADB_X_EXT_ADDRESS_DST_MASK);
-       host->destroy(host);
-
-       proto = (struct sadb_protocol*)PFKEY_EXT_ADD_NEXT(msg);
-       proto->sadb_protocol_exttype = SADB_X_EXT_PROTOCOL;
-       proto->sadb_protocol_len = PFKEY_LEN(sizeof(struct sadb_protocol));
-       proto->sadb_protocol_proto = protocol;
-       PFKEY_EXT_ADD(msg, proto);
-}
-
-/**
- * Parses a pfkey message received from the kernel
- */
-static status_t parse_pfkey_message(struct sadb_msg *msg, pfkey_msg_t *out)
-{
-       struct sadb_ext* ext;
-       size_t len;
-
-       memset(out, 0, sizeof(pfkey_msg_t));
-       out->msg = msg;
-
-       len = msg->sadb_msg_len;
-       len -= PFKEY_LEN(sizeof(struct sadb_msg));
-
-       ext = (struct sadb_ext*)(((char*)msg) + sizeof(struct sadb_msg));
-
-       while (len >= PFKEY_LEN(sizeof(struct sadb_ext)))
-       {
-               if (ext->sadb_ext_len < PFKEY_LEN(sizeof(struct sadb_ext)) ||
-                       ext->sadb_ext_len > len)
-               {
-                       DBG1(DBG_KNL, "length of PF_KEY extension (%d) is invalid", ext->sadb_ext_type);
-                       break;
-               }
-
-               if ((ext->sadb_ext_type > SADB_EXT_MAX) || (!ext->sadb_ext_type))
-               {
-                       DBG1(DBG_KNL, "type of PF_KEY extension (%d) is invalid", ext->sadb_ext_type);
-                       break;
-               }
-
-               if (out->ext[ext->sadb_ext_type])
-               {
-                       DBG1(DBG_KNL, "duplicate PF_KEY extension of type (%d)", ext->sadb_ext_type);
-                       break;
-               }
-
-               out->ext[ext->sadb_ext_type] = ext;
-               ext = PFKEY_EXT_NEXT_LEN(ext, len);
-       }
-
-       if (len)
-       {
-               DBG1(DBG_KNL, "PF_KEY message length is invalid");
-               return FAILED;
-       }
-
-       return SUCCESS;
-}
-
-/**
- * Send a message to a specific PF_KEY socket and handle the response.
- */
-static status_t pfkey_send_socket(private_kernel_klips_ipsec_t *this, int socket,
-                                       struct sadb_msg *in, struct sadb_msg **out, size_t *out_len)
-{
-       unsigned char buf[PFKEY_BUFFER_SIZE];
-       struct sadb_msg *msg;
-       int in_len, len;
-
-       this->mutex_pfkey->lock(this->mutex_pfkey);
-
-       in->sadb_msg_seq = ++this->seq;
-       in->sadb_msg_pid = getpid();
-
-       in_len = PFKEY_USER_LEN(in->sadb_msg_len);
-
-       while (TRUE)
-       {
-               len = send(socket, in, in_len, 0);
-
-               if (len != in_len)
-               {
-                       switch (errno)
-                       {
-                               case EINTR:
-                                       /* interrupted, try again */
-                                       continue;
-                               case EINVAL:
-                               case EEXIST:
-                               case ESRCH:
-                                       /* we should also get a response for these from KLIPS */
-                                       break;
-                               default:
-                                       this->mutex_pfkey->unlock(this->mutex_pfkey);
-                                       DBG1(DBG_KNL, "error sending to PF_KEY socket: %s (%d)",
-                                                       strerror(errno), errno);
-                                       return FAILED;
-                       }
-               }
-               break;
-       }
-
-       while (TRUE)
-       {
-               msg = (struct sadb_msg*)buf;
-
-               len = recv(socket, buf, sizeof(buf), 0);
-
-               if (len < 0)
-               {
-                       if (errno == EINTR)
-                       {
-                               DBG1(DBG_KNL, "got interrupted");
-                               /* interrupted, try again */
-                               continue;
-                       }
-                       this->mutex_pfkey->unlock(this->mutex_pfkey);
-                       DBG1(DBG_KNL, "error reading from PF_KEY socket: %s", strerror(errno));
-                       return FAILED;
-               }
-               if (len < sizeof(struct sadb_msg) ||
-                       msg->sadb_msg_len < PFKEY_LEN(sizeof(struct sadb_msg)))
-               {
-                       this->mutex_pfkey->unlock(this->mutex_pfkey);
-                       DBG1(DBG_KNL, "received corrupted PF_KEY message");
-                       return FAILED;
-               }
-               if (msg->sadb_msg_len > len / PFKEY_ALIGNMENT)
-               {
-                       this->mutex_pfkey->unlock(this->mutex_pfkey);
-                       DBG1(DBG_KNL, "buffer was too small to receive the complete PF_KEY message");
-                       return FAILED;
-               }
-               if (msg->sadb_msg_pid != in->sadb_msg_pid)
-               {
-                       DBG2(DBG_KNL, "received PF_KEY message is not intended for us");
-                       continue;
-               }
-               if (msg->sadb_msg_seq != this->seq)
-               {
-                       DBG1(DBG_KNL, "received PF_KEY message with invalid sequence number,"
-                                       " was %d expected %d", msg->sadb_msg_seq, this->seq);
-                       if (msg->sadb_msg_seq < this->seq)
-                       {
-                               continue;
-                       }
-                       this->mutex_pfkey->unlock(this->mutex_pfkey);
-                       return FAILED;
-               }
-               if (msg->sadb_msg_type != in->sadb_msg_type)
-               {
-                       DBG2(DBG_KNL, "received PF_KEY message of wrong type,"
-                                       " was %d expected %d, ignoring",
-                                       msg->sadb_msg_type, in->sadb_msg_type);
-               }
-               break;
-       }
-
-       *out_len = len;
-       *out = (struct sadb_msg*)malloc(len);
-       memcpy(*out, buf, len);
-
-       this->mutex_pfkey->unlock(this->mutex_pfkey);
-
-       return SUCCESS;
-}
-
-/**
- * Send a message to the default PF_KEY socket.
- */
-static status_t pfkey_send(private_kernel_klips_ipsec_t *this,
-                                       struct sadb_msg *in, struct sadb_msg **out, size_t *out_len)
-{
-       return pfkey_send_socket(this, this->socket, in, out, out_len);
-}
-
-/**
- * Send a message to the default PF_KEY socket and handle the response.
- */
-static status_t pfkey_send_ack(private_kernel_klips_ipsec_t *this, struct sadb_msg *in)
-{
-       struct sadb_msg *out;
-       size_t len;
-
-       if (pfkey_send(this, in, &out, &len) != SUCCESS)
-       {
-               return FAILED;
-       }
-       else if (out->sadb_msg_errno)
-       {
-               DBG1(DBG_KNL, "PF_KEY error: %s (%d)",
-                                          strerror(out->sadb_msg_errno), out->sadb_msg_errno);
-               free(out);
-               return FAILED;
-       }
-       free(out);
-       return SUCCESS;
-}
-
-/**
- * Add an eroute to KLIPS
- */
-static status_t add_eroute(private_kernel_klips_ipsec_t *this, u_int8_t satype,
-               u_int32_t spi, host_t *src, host_t *dst, host_t *src_net, u_int8_t src_mask,
-               host_t *dst_net, u_int8_t dst_mask, u_int8_t protocol, bool replace)
-{
-       unsigned char request[PFKEY_BUFFER_SIZE];
-       struct sadb_msg *msg = (struct sadb_msg*)request;
-
-       memset(&request, 0, sizeof(request));
-
-       build_addflow(msg, satype, spi, src, dst, src_net, src_mask,
-                       dst_net, dst_mask, protocol, replace);
-
-       return pfkey_send_ack(this, msg);
-}
-
-/**
- * Delete an eroute fom KLIPS
- */
-static status_t del_eroute(private_kernel_klips_ipsec_t *this, u_int8_t satype,
-               host_t *src_net, u_int8_t src_mask, host_t *dst_net, u_int8_t dst_mask,
-               u_int8_t protocol)
-{
-       unsigned char request[PFKEY_BUFFER_SIZE];
-       struct sadb_msg *msg = (struct sadb_msg*)request;
-
-       memset(&request, 0, sizeof(request));
-
-       build_delflow(msg, satype, src_net, src_mask, dst_net, dst_mask, protocol);
-
-       return pfkey_send_ack(this, msg);
-}
-
-/**
- * Process a SADB_ACQUIRE message from the kernel
- */
-static void process_acquire(private_kernel_klips_ipsec_t *this, struct sadb_msg* msg)
-{
-       pfkey_msg_t response;
-       host_t *src, *dst;
-       u_int32_t reqid;
-       u_int8_t proto;
-       policy_entry_t *policy;
-
-       switch (msg->sadb_msg_satype)
-       {
-               case SADB_SATYPE_UNSPEC:
-               case SADB_SATYPE_ESP:
-               case SADB_SATYPE_AH:
-                       break;
-               default:
-                       /* acquire for AH/ESP only */
-                       return;
-       }
-
-       if (parse_pfkey_message(msg, &response) != SUCCESS)
-       {
-               DBG1(DBG_KNL, "parsing SADB_ACQUIRE from kernel failed");
-               return;
-       }
-
-       /* KLIPS provides us only with the source and destination address,
-        * and the transport protocol of the packet that triggered the policy.
-        * we use this information to find a matching policy in our cache.
-        * because KLIPS installs a narrow %hold eroute covering only this information,
-        * we replace both the %trap and this %hold eroutes with a broader %hold
-        * eroute covering the whole policy */
-       src = host_create_from_sockaddr((sockaddr_t*)(response.src + 1));
-       dst = host_create_from_sockaddr((sockaddr_t*)(response.dst + 1));
-       proto = response.src->sadb_address_proto;
-       if (!src || !dst || src->get_family(src) != dst->get_family(dst))
-       {
-               DBG1(DBG_KNL, "received an SADB_ACQUIRE with invalid hosts");
-               return;
-       }
-
-       DBG2(DBG_KNL, "received an SADB_ACQUIRE for %H == %H : %d", src, dst, proto);
-       this->mutex->lock(this->mutex);
-       if (this->policies->find_first(this->policies,
-                       (linked_list_match_t)policy_entry_match_byaddrs,
-                               (void**)&policy, src, dst) != SUCCESS)
-       {
-               this->mutex->unlock(this->mutex);
-               DBG1(DBG_KNL, "received an SADB_ACQUIRE, but found no matching policy");
-               return;
-       }
-       if ((reqid = policy->reqid) == 0)
-       {
-               this->mutex->unlock(this->mutex);
-               DBG1(DBG_KNL, "received an SADB_ACQUIRE, but policy is not routed anymore");
-               return;
-       }
-
-       /* add a broad %hold eroute that replaces the %trap eroute */
-       add_eroute(this, SADB_X_SATYPE_INT, htonl(SPI_HOLD), NULL, NULL,
-                       policy->src.net, policy->src.mask, policy->dst.net, policy->dst.mask,
-                       policy->src.proto, TRUE);
-
-       /* remove the narrow %hold eroute installed by KLIPS */
-       del_eroute(this, SADB_X_SATYPE_INT, src, 32, dst, 32, proto);
-
-       this->mutex->unlock(this->mutex);
-
-       hydra->kernel_interface->acquire(hydra->kernel_interface, reqid, NULL,
-                                                                        NULL);
-}
-
-/**
- * Process a SADB_X_NAT_T_NEW_MAPPING message from the kernel
- */
-static void process_mapping(private_kernel_klips_ipsec_t *this, struct sadb_msg* msg)
-{
-       pfkey_msg_t response;
-       u_int32_t spi, reqid;
-       host_t *old_src, *new_src;
-
-       DBG2(DBG_KNL, "received an SADB_X_NAT_T_NEW_MAPPING");
-
-       if (parse_pfkey_message(msg, &response) != SUCCESS)
-       {
-               DBG1(DBG_KNL, "parsing SADB_X_NAT_T_NEW_MAPPING from kernel failed");
-               return;
-       }
-
-       spi = response.sa->sadb_sa_spi;
-
-       if (satype2proto(msg->sadb_msg_satype) == IPPROTO_ESP)
-       {
-               sa_entry_t *sa;
-               sockaddr_t *addr = (sockaddr_t*)(response.src + 1);
-               old_src = host_create_from_sockaddr(addr);
-
-               this->mutex->lock(this->mutex);
-               if (!old_src || this->installed_sas->find_first(this->installed_sas,
-                               (linked_list_match_t)sa_entry_match_encapbysrc,
-                                       (void**)&sa, &spi, old_src) != SUCCESS)
-               {
-                       this->mutex->unlock(this->mutex);
-                       DBG1(DBG_KNL, "received an SADB_X_NAT_T_NEW_MAPPING, but found no matching SA");
-                       return;
-               }
-               reqid = sa->reqid;
-               this->mutex->unlock(this->mutex);
-
-               addr = (sockaddr_t*)(response.dst + 1);
-               switch (addr->sa_family)
-               {
-                       case AF_INET:
-                       {
-                               struct sockaddr_in *sin = (struct sockaddr_in*)addr;
-                               sin->sin_port = htons(response.x_natt_dport->sadb_x_nat_t_port_port);
-                       }
-                       case AF_INET6:
-                       {
-                               struct sockaddr_in6 *sin6 = (struct sockaddr_in6*)addr;
-                               sin6->sin6_port = htons(response.x_natt_dport->sadb_x_nat_t_port_port);
-                       }
-                       default:
-                               break;
-               }
-               new_src = host_create_from_sockaddr(addr);
-               if (new_src)
-               {
-                       hydra->kernel_interface->mapping(hydra->kernel_interface, reqid,
-                                                                                        spi, new_src);
-               }
-       }
-}
-
-/**
- * Receives events from kernel
- */
-static job_requeue_t receive_events(private_kernel_klips_ipsec_t *this)
-{
-       unsigned char buf[PFKEY_BUFFER_SIZE];
-       struct sadb_msg *msg = (struct sadb_msg*)buf;
-       int len;
-       bool oldstate;
-
-       oldstate = thread_cancelability(TRUE);
-       len = recv(this->socket_events, buf, sizeof(buf), 0);
-       thread_cancelability(oldstate);
-
-       if (len < 0)
-       {
-               switch (errno)
-               {
-                       case EINTR:
-                               /* interrupted, try again */
-                               return JOB_REQUEUE_DIRECT;
-                       case EAGAIN:
-                               /* no data ready, select again */
-                               return JOB_REQUEUE_DIRECT;
-                       default:
-                               DBG1(DBG_KNL, "unable to receive from PF_KEY event socket");
-                               sleep(1);
-                               return JOB_REQUEUE_FAIR;
-               }
-       }
-
-       if (len < sizeof(struct sadb_msg) ||
-               msg->sadb_msg_len < PFKEY_LEN(sizeof(struct sadb_msg)))
-       {
-               DBG2(DBG_KNL, "received corrupted PF_KEY message");
-               return JOB_REQUEUE_DIRECT;
-       }
-       if (msg->sadb_msg_pid != 0)
-       {       /* not from kernel. not interested, try another one */
-               return JOB_REQUEUE_DIRECT;
-       }
-       if (msg->sadb_msg_len > len / PFKEY_ALIGNMENT)
-       {
-               DBG1(DBG_KNL, "buffer was too small to receive the complete PF_KEY message");
-               return JOB_REQUEUE_DIRECT;
-       }
-
-       switch (msg->sadb_msg_type)
-       {
-               case SADB_ACQUIRE:
-                       process_acquire(this, msg);
-                       break;
-               case SADB_EXPIRE:
-                       /* SADB_EXPIRE events in KLIPS are only triggered by traffic (even
-                        * for the time based limits). So if there is no traffic for a
-                        * longer period than configured as hard limit, we wouldn't be able
-                        * to rekey the SA and just receive the hard expire and thus delete
-                        * the SA.
-                        * To avoid this behavior and to make charon behave as with the
-                        * other kernel plugins, we implement the expiration of SAs
-                        * ourselves. */
-                       break;
-               case SADB_X_NAT_T_NEW_MAPPING:
-                       process_mapping(this, msg);
-                       break;
-               default:
-                       break;
-       }
-
-       return JOB_REQUEUE_DIRECT;
-}
-
-typedef enum {
-       /** an SPI has expired */
-       EXPIRE_TYPE_SPI,
-       /** a CHILD_SA has to be rekeyed */
-       EXPIRE_TYPE_SOFT,
-       /** a CHILD_SA has to be deleted */
-       EXPIRE_TYPE_HARD
-} expire_type_t;
-
-typedef struct sa_expire_t sa_expire_t;
-
-struct sa_expire_t {
-       /** kernel interface */
-       private_kernel_klips_ipsec_t *this;
-       /** the SPI of the expiring SA */
-       u_int32_t spi;
-       /** the protocol of the expiring SA */
-       u_int8_t protocol;
-       /** the reqid of the expiring SA*/
-       u_int32_t reqid;
-       /** what type of expire this is */
-       expire_type_t type;
-};
-
-/**
- * Called when an SA expires
- */
-static job_requeue_t sa_expires(sa_expire_t *expire)
-{
-       private_kernel_klips_ipsec_t *this = expire->this;
-       u_int8_t protocol = expire->protocol;
-       u_int32_t spi = expire->spi, reqid = expire->reqid;
-       bool hard = expire->type != EXPIRE_TYPE_SOFT;
-       sa_entry_t *cached_sa;
-       linked_list_t *list;
-
-       /* for an expired SPI we first check whether the CHILD_SA got installed
-        * in the meantime, for expired SAs we check whether they are still installed */
-       list = expire->type == EXPIRE_TYPE_SPI ? this->allocated_spis : this->installed_sas;
-
-       this->mutex->lock(this->mutex);
-       if (list->find_first(list, (linked_list_match_t)sa_entry_match_byid,
-                       (void**)&cached_sa, &protocol, &spi, &reqid) != SUCCESS)
-       {
-               /* we found no entry:
-                * - for SPIs, a CHILD_SA has been installed
-                * - for SAs, the CHILD_SA has already been deleted */
-               this->mutex->unlock(this->mutex);
-               return JOB_REQUEUE_NONE;
-       }
-       else
-       {
-               list->remove(list, cached_sa, NULL);
-               sa_entry_destroy(cached_sa);
-       }
-       this->mutex->unlock(this->mutex);
-
-       DBG2(DBG_KNL, "%N CHILD_SA with SPI %.8x and reqid {%d} expired",
-                       protocol_id_names, protocol, ntohl(spi), reqid);
-
-       hydra->kernel_interface->expire(hydra->kernel_interface, reqid, protocol,
-                                                                       spi, hard);
-       return JOB_REQUEUE_NONE;
-}
-
-/**
- * Schedule an expire job for an SA. Time is in seconds.
- */
-static void schedule_expire(private_kernel_klips_ipsec_t *this,
-                                                       u_int8_t protocol, u_int32_t spi,
-                                                       u_int32_t reqid, expire_type_t type, u_int32_t time)
-{
-       callback_job_t *job;
-       sa_expire_t *expire = malloc_thing(sa_expire_t);
-       expire->this = this;
-       expire->protocol = protocol;
-       expire->spi = spi;
-       expire->reqid = reqid;
-       expire->type = type;
-       job = callback_job_create((callback_job_cb_t)sa_expires, expire, free, NULL);
-       hydra->scheduler->schedule_job(hydra->scheduler, (job_t*)job, time);
-}
-
-METHOD(kernel_ipsec_t, get_spi, status_t,
-       private_kernel_klips_ipsec_t *this, host_t *src, host_t *dst,
-       u_int8_t protocol, u_int32_t reqid, u_int32_t *spi)
-{
-       /* we cannot use SADB_GETSPI because KLIPS does not allow us to set the
-        * NAT-T type in an SADB_UPDATE which we would have to use to update the
-        * implicitly created SA.
-        */
-       rng_t *rng;
-       u_int32_t spi_gen;
-
-       rng = lib->crypto->create_rng(lib->crypto, RNG_WEAK);
-       if (!rng)
-       {
-               DBG1(DBG_KNL, "allocating SPI failed: no RNG");
-               return FAILED;
-       }
-       rng->get_bytes(rng, sizeof(spi_gen), (void*)&spi_gen);
-       rng->destroy(rng);
-
-       /* charon's SPIs lie within the range from 0xc0000000 to 0xcFFFFFFF */
-       spi_gen = 0xc0000000 | (spi_gen & 0x0FFFFFFF);
-
-       DBG2(DBG_KNL, "allocated SPI %.8x for %N SA between %#H..%#H",
-                       spi_gen, protocol_id_names, protocol, src, dst);
-
-       *spi = htonl(spi_gen);
-
-       this->mutex->lock(this->mutex);
-       this->allocated_spis->insert_last(this->allocated_spis,
-                       create_sa_entry(protocol, *spi, reqid, NULL, NULL, FALSE, TRUE));
-       this->mutex->unlock(this->mutex);
-       schedule_expire(this, protocol, *spi, reqid, EXPIRE_TYPE_SPI, SPI_TIMEOUT);
-
-       return SUCCESS;
-}
-
-METHOD(kernel_ipsec_t, get_cpi, status_t,
-       private_kernel_klips_ipsec_t *this, host_t *src, host_t *dst,
-       u_int32_t reqid, u_int16_t *cpi)
-{
-       return FAILED;
-}
-
-/**
- * Add a pseudo IPIP SA for tunnel mode with KLIPS.
- */
-static status_t add_ipip_sa(private_kernel_klips_ipsec_t *this,
-                                          host_t *src, host_t *dst, u_int32_t spi, u_int32_t reqid)
-{
-       unsigned char request[PFKEY_BUFFER_SIZE];
-       struct sadb_msg *msg, *out;
-       struct sadb_sa *sa;
-       size_t len;
-
-       memset(&request, 0, sizeof(request));
-
-       DBG2(DBG_KNL, "adding pseudo IPIP SA with SPI %.8x and reqid {%d}", ntohl(spi), reqid);
-
-       msg = (struct sadb_msg*)request;
-       msg->sadb_msg_version = PF_KEY_V2;
-       msg->sadb_msg_type = SADB_ADD;
-       msg->sadb_msg_satype = SADB_X_SATYPE_IPIP;
-       msg->sadb_msg_len = PFKEY_LEN(sizeof(struct sadb_msg));
-
-       sa = (struct sadb_sa*)PFKEY_EXT_ADD_NEXT(msg);
-       sa->sadb_sa_exttype = SADB_EXT_SA;
-       sa->sadb_sa_len = PFKEY_LEN(sizeof(struct sadb_sa));
-       sa->sadb_sa_spi = spi;
-       sa->sadb_sa_state = SADB_SASTATE_MATURE;
-       PFKEY_EXT_ADD(msg, sa);
-
-       add_addr_ext(msg, src, SADB_EXT_ADDRESS_SRC);
-       add_addr_ext(msg, dst, SADB_EXT_ADDRESS_DST);
-
-       if (pfkey_send(this, msg, &out, &len) != SUCCESS)
-       {
-               DBG1(DBG_KNL, "unable to add pseudo IPIP SA with SPI %.8x", ntohl(spi));
-               return FAILED;
-       }
-       else if (out->sadb_msg_errno)
-       {
-               DBG1(DBG_KNL, "unable to add pseudo IPIP SA with SPI %.8x: %s (%d)",
-                               ntohl(spi), strerror(out->sadb_msg_errno), out->sadb_msg_errno);
-               free(out);
-               return FAILED;
-       }
-
-       free(out);
-       return SUCCESS;
-}
-
-/**
- * group the IPIP SA required for tunnel mode with the outer SA
- */
-static status_t group_ipip_sa(private_kernel_klips_ipsec_t *this,
-                                          host_t *src, host_t *dst, u_int32_t spi,
-                                          u_int8_t protocol, u_int32_t reqid)
-{
-       unsigned char request[PFKEY_BUFFER_SIZE];
-       struct sadb_msg *msg, *out;
-       struct sadb_sa *sa;
-       struct sadb_x_satype *satype;
-       size_t len;
-
-       memset(&request, 0, sizeof(request));
-
-       DBG2(DBG_KNL, "grouping SAs with SPI %.8x and reqid {%d}", ntohl(spi), reqid);
-
-       msg = (struct sadb_msg*)request;
-       msg->sadb_msg_version = PF_KEY_V2;
-       msg->sadb_msg_type = SADB_X_GRPSA;
-       msg->sadb_msg_satype = SADB_X_SATYPE_IPIP;
-       msg->sadb_msg_len = PFKEY_LEN(sizeof(struct sadb_msg));
-
-       sa = (struct sadb_sa*)PFKEY_EXT_ADD_NEXT(msg);
-       sa->sadb_sa_exttype = SADB_EXT_SA;
-       sa->sadb_sa_len = PFKEY_LEN(sizeof(struct sadb_sa));
-       sa->sadb_sa_spi = spi;
-       sa->sadb_sa_state = SADB_SASTATE_MATURE;
-       PFKEY_EXT_ADD(msg, sa);
-
-       add_addr_ext(msg, dst, SADB_EXT_ADDRESS_DST);
-
-       satype = (struct sadb_x_satype*)PFKEY_EXT_ADD_NEXT(msg);
-       satype->sadb_x_satype_exttype = SADB_X_EXT_SATYPE2;
-       satype->sadb_x_satype_len = PFKEY_LEN(sizeof(struct sadb_x_satype));
-       satype->sadb_x_satype_satype = proto2satype(protocol);
-       PFKEY_EXT_ADD(msg, satype);
-
-       sa = (struct sadb_sa*)PFKEY_EXT_ADD_NEXT(msg);
-       sa->sadb_sa_exttype = SADB_X_EXT_SA2;
-       sa->sadb_sa_len = PFKEY_LEN(sizeof(struct sadb_sa));
-       sa->sadb_sa_spi = spi;
-       sa->sadb_sa_state = SADB_SASTATE_MATURE;
-       PFKEY_EXT_ADD(msg, sa);
-
-       add_addr_ext(msg, dst, SADB_X_EXT_ADDRESS_DST2);
-
-       if (pfkey_send(this, msg, &out, &len) != SUCCESS)
-       {
-               DBG1(DBG_KNL, "unable to group SAs with SPI %.8x", ntohl(spi));
-               return FAILED;
-       }
-       else if (out->sadb_msg_errno)
-       {
-               DBG1(DBG_KNL, "unable to group SAs with SPI %.8x: %s (%d)",
-                               ntohl(spi), strerror(out->sadb_msg_errno), out->sadb_msg_errno);
-               free(out);
-               return FAILED;
-       }
-
-       free(out);
-       return SUCCESS;
-}
-
-METHOD(kernel_ipsec_t, add_sa, status_t,
-       private_kernel_klips_ipsec_t *this, host_t *src, host_t *dst, u_int32_t spi,
-       u_int8_t protocol, u_int32_t reqid, mark_t mark,
-       lifetime_cfg_t *lifetime, u_int16_t enc_alg, chunk_t enc_key,
-       u_int16_t int_alg, chunk_t int_key, ipsec_mode_t mode,
-       u_int16_t ipcomp, u_int16_t cpi, bool encap, bool inbound,
-       traffic_selector_t *src_ts, traffic_selector_t *dst_ts)
-{
-       unsigned char request[PFKEY_BUFFER_SIZE];
-       struct sadb_msg *msg, *out;
-       struct sadb_sa *sa;
-       struct sadb_key *key;
-       size_t len;
-
-       if (inbound)
-       {
-               /* for inbound SAs we allocated an SPI via get_spi, so we first check
-                * whether that SPI has already expired (race condition) */
-               sa_entry_t *alloc_spi;
-               this->mutex->lock(this->mutex);
-               if (this->allocated_spis->find_first(this->allocated_spis,
-                               (linked_list_match_t)sa_entry_match_byid, (void**)&alloc_spi,
-                                       &protocol, &spi, &reqid) != SUCCESS)
-               {
-                       this->mutex->unlock(this->mutex);
-                       DBG1(DBG_KNL, "allocated SPI %.8x has already expired", ntohl(spi));
-                       return FAILED;
-               }
-               else
-               {
-                       this->allocated_spis->remove(this->allocated_spis, alloc_spi, NULL);
-                       sa_entry_destroy(alloc_spi);
-               }
-               this->mutex->unlock(this->mutex);
-       }
-
-       memset(&request, 0, sizeof(request));
-
-       DBG2(DBG_KNL, "adding SAD entry with SPI %.8x and reqid {%d}", ntohl(spi), reqid);
-
-       msg = (struct sadb_msg*)request;
-       msg->sadb_msg_version = PF_KEY_V2;
-       msg->sadb_msg_type = SADB_ADD;
-       msg->sadb_msg_satype = proto2satype(protocol);
-       msg->sadb_msg_len = PFKEY_LEN(sizeof(struct sadb_msg));
-
-       sa = (struct sadb_sa*)PFKEY_EXT_ADD_NEXT(msg);
-       sa->sadb_sa_exttype = SADB_EXT_SA;
-       sa->sadb_sa_len = PFKEY_LEN(sizeof(struct sadb_sa));
-       sa->sadb_sa_spi = spi;
-       sa->sadb_sa_state = SADB_SASTATE_MATURE;
-       sa->sadb_sa_replay = (protocol == IPPROTO_COMP) ? 0 : 32;
-       sa->sadb_sa_auth = lookup_algorithm(integrity_algs, int_alg);
-       sa->sadb_sa_encrypt = lookup_algorithm(encryption_algs, enc_alg);
-       PFKEY_EXT_ADD(msg, sa);
-
-       add_addr_ext(msg, src, SADB_EXT_ADDRESS_SRC);
-       add_addr_ext(msg, dst, SADB_EXT_ADDRESS_DST);
-
-       if (enc_alg != ENCR_UNDEFINED)
-       {
-               if (!sa->sadb_sa_encrypt)
-               {
-                       DBG1(DBG_KNL, "algorithm %N not supported by kernel!",
-                                encryption_algorithm_names, enc_alg);
-                       return FAILED;
-               }
-               DBG2(DBG_KNL, "  using encryption algorithm %N with key size %d",
-                        encryption_algorithm_names, enc_alg, enc_key.len * 8);
-
-               key = (struct sadb_key*)PFKEY_EXT_ADD_NEXT(msg);
-               key->sadb_key_exttype = SADB_EXT_KEY_ENCRYPT;
-               key->sadb_key_bits = enc_key.len * 8;
-               key->sadb_key_len = PFKEY_LEN(sizeof(struct sadb_key) + enc_key.len);
-               memcpy(key + 1, enc_key.ptr, enc_key.len);
-
-               PFKEY_EXT_ADD(msg, key);
-       }
-
-       if (int_alg != AUTH_UNDEFINED)
-       {
-               if (!sa->sadb_sa_auth)
-               {
-                       DBG1(DBG_KNL, "algorithm %N not supported by kernel!",
-                                        integrity_algorithm_names, int_alg);
-                       return FAILED;
-               }
-               DBG2(DBG_KNL, "  using integrity algorithm %N with key size %d",
-                        integrity_algorithm_names, int_alg, int_key.len * 8);
-
-               key = (struct sadb_key*)PFKEY_EXT_ADD_NEXT(msg);
-               key->sadb_key_exttype = SADB_EXT_KEY_AUTH;
-               key->sadb_key_bits = int_key.len * 8;
-               key->sadb_key_len = PFKEY_LEN(sizeof(struct sadb_key) + int_key.len);
-               memcpy(key + 1, int_key.ptr, int_key.len);
-
-               PFKEY_EXT_ADD(msg, key);
-       }
-
-       if (ipcomp != IPCOMP_NONE)
-       {
-               /*TODO*/
-       }
-
-       if (encap)
-       {
-               add_encap_ext(msg, src, dst, FALSE);
-       }
-
-       if (pfkey_send(this, msg, &out, &len) != SUCCESS)
-       {
-               DBG1(DBG_KNL, "unable to add SAD entry with SPI %.8x", ntohl(spi));
-               return FAILED;
-       }
-       else if (out->sadb_msg_errno)
-       {
-               DBG1(DBG_KNL, "unable to add SAD entry with SPI %.8x: %s (%d)",
-                               ntohl(spi), strerror(out->sadb_msg_errno), out->sadb_msg_errno);
-               free(out);
-               return FAILED;
-       }
-       free(out);
-
-       /* for tunnel mode SAs we have to install an additional IPIP SA and
-        * group the two SAs together */
-       if (mode == MODE_TUNNEL)
-       {
-               if (add_ipip_sa(this, src, dst, spi, reqid) != SUCCESS ||
-                       group_ipip_sa(this, src, dst, spi, protocol, reqid) != SUCCESS)
-               {
-                       DBG1(DBG_KNL, "unable to add SAD entry with SPI %.8x", ntohl(spi));
-                       return FAILED;
-               }
-       }
-
-       this->mutex->lock(this->mutex);
-       /* we cache this SA for two reasons:
-        * - in case an SADB_X_NAT_T_MAPPING_NEW event occurs (we need to find the reqid then)
-        * - to decide if an expired SA is still installed */
-       this->installed_sas->insert_last(this->installed_sas,
-                               create_sa_entry(protocol, spi, reqid, src, dst, encap, inbound));
-       this->mutex->unlock(this->mutex);
-
-       /* Although KLIPS supports SADB_EXT_LIFETIME_SOFT/HARD, we handle the lifetime
-        * of SAs manually in the plugin. Refer to the comments in receive_events()
-        * for details. */
-       if (lifetime->time.rekey)
-       {
-               schedule_expire(this, protocol, spi, reqid, EXPIRE_TYPE_SOFT, lifetime->time.rekey);
-       }
-
-       if (lifetime->time.life)
-       {
-               schedule_expire(this, protocol, spi, reqid, EXPIRE_TYPE_HARD, lifetime->time.life);
-       }
-
-       return SUCCESS;
-}
-
-METHOD(kernel_ipsec_t, update_sa, status_t,
-       private_kernel_klips_ipsec_t *this, u_int32_t spi, u_int8_t protocol,
-       u_int16_t cpi, host_t *src, host_t *dst, host_t *new_src, host_t *new_dst,
-       bool encap, bool new_encap, mark_t mark)
-{
-       unsigned char request[PFKEY_BUFFER_SIZE];
-       struct sadb_msg *msg, *out;
-       struct sadb_sa *sa;
-       size_t len;
-
-       /* we can't update the SA if any of the ip addresses have changed.
-        * that's because we can't use SADB_UPDATE and by deleting and readding the
-        * SA the sequence numbers would get lost */
-       if (!src->ip_equals(src, new_src) ||
-               !dst->ip_equals(dst, new_dst))
-       {
-               DBG1(DBG_KNL, "unable to update SAD entry with SPI %.8x: address changes"
-                               " are not supported", ntohl(spi));
-               return NOT_SUPPORTED;
-       }
-
-       /* because KLIPS does not allow us to change the NAT-T type in an SADB_UPDATE,
-        * we can't update the SA if the encap flag has changed since installing it */
-       if (encap != new_encap)
-       {
-               DBG1(DBG_KNL, "unable to update SAD entry with SPI %.8x: change of UDP"
-                               " encapsulation is not supported", ntohl(spi));
-               return NOT_SUPPORTED;
-       }
-
-       DBG2(DBG_KNL, "updating SAD entry with SPI %.8x from %#H..%#H to %#H..%#H",
-                ntohl(spi), src, dst, new_src, new_dst);
-
-       memset(&request, 0, sizeof(request));
-
-       msg = (struct sadb_msg*)request;
-       msg->sadb_msg_version = PF_KEY_V2;
-       msg->sadb_msg_type = SADB_UPDATE;
-       msg->sadb_msg_satype = proto2satype(protocol);
-       msg->sadb_msg_len = PFKEY_LEN(sizeof(struct sadb_msg));
-
-       sa = (struct sadb_sa*)PFKEY_EXT_ADD_NEXT(msg);
-       sa->sadb_sa_exttype = SADB_EXT_SA;
-       sa->sadb_sa_len = PFKEY_LEN(sizeof(struct sadb_sa));
-       sa->sadb_sa_spi = spi;
-       sa->sadb_sa_encrypt = SADB_EALG_AESCBC; /* ignored */
-       sa->sadb_sa_auth = SADB_AALG_SHA1HMAC; /* ignored */
-       sa->sadb_sa_state = SADB_SASTATE_MATURE;
-       PFKEY_EXT_ADD(msg, sa);
-
-       add_addr_ext(msg, src, SADB_EXT_ADDRESS_SRC);
-       add_addr_ext(msg, dst, SADB_EXT_ADDRESS_DST);
-
-       add_encap_ext(msg, new_src, new_dst, TRUE);
-
-       if (pfkey_send(this, msg, &out, &len) != SUCCESS)
-       {
-               DBG1(DBG_KNL, "unable to update SAD entry with SPI %.8x", ntohl(spi));
-               return FAILED;
-       }
-       else if (out->sadb_msg_errno)
-       {
-               DBG1(DBG_KNL, "unable to update SAD entry with SPI %.8x: %s (%d)",
-                               ntohl(spi), strerror(out->sadb_msg_errno), out->sadb_msg_errno);
-               free(out);
-               return FAILED;
-       }
-       free(out);
-
-       return SUCCESS;
-}
-
-METHOD(kernel_ipsec_t, query_sa, status_t,
-       private_kernel_klips_ipsec_t *this, host_t *src, host_t *dst,
-       u_int32_t spi, u_int8_t protocol, mark_t mark, u_int64_t *bytes)
-{
-       return NOT_SUPPORTED;  /* TODO */
-}
-
-METHOD(kernel_ipsec_t, del_sa, status_t,
-       private_kernel_klips_ipsec_t *this, host_t *src, host_t *dst,
-       u_int32_t spi, u_int8_t protocol, u_int16_t cpi, mark_t mark)
-{
-       unsigned char request[PFKEY_BUFFER_SIZE];
-       struct sadb_msg *msg, *out;
-       struct sadb_sa *sa;
-       sa_entry_t *cached_sa;
-       size_t len;
-
-       memset(&request, 0, sizeof(request));
-
-       /* all grouped SAs are automatically deleted by KLIPS as soon as
-        * one of them is deleted, therefore we delete only the main one */
-       DBG2(DBG_KNL, "deleting SAD entry with SPI %.8x", ntohl(spi));
-
-       this->mutex->lock(this->mutex);
-       /* this should not fail, but we don't care if it does, let the kernel decide
-        * whether this SA exists or not */
-       if (this->installed_sas->find_first(this->installed_sas,
-                       (linked_list_match_t)sa_entry_match_bydst, (void**)&cached_sa,
-                       &protocol, &spi, dst) == SUCCESS)
-       {
-               this->installed_sas->remove(this->installed_sas, cached_sa, NULL);
-               sa_entry_destroy(cached_sa);
-       }
-       this->mutex->unlock(this->mutex);
-
-       msg = (struct sadb_msg*)request;
-       msg->sadb_msg_version = PF_KEY_V2;
-       msg->sadb_msg_type = SADB_DELETE;
-       msg->sadb_msg_satype = proto2satype(protocol);
-       msg->sadb_msg_len = PFKEY_LEN(sizeof(struct sadb_msg));
-
-       sa = (struct sadb_sa*)PFKEY_EXT_ADD_NEXT(msg);
-       sa->sadb_sa_exttype = SADB_EXT_SA;
-       sa->sadb_sa_len = PFKEY_LEN(sizeof(struct sadb_sa));
-       sa->sadb_sa_spi = spi;
-       PFKEY_EXT_ADD(msg, sa);
-
-       /* the kernel wants an SADB_EXT_ADDRESS_SRC to be present even though
-        * it is not used for anything. */
-       add_anyaddr_ext(msg, dst->get_family(dst), SADB_EXT_ADDRESS_SRC);
-       add_addr_ext(msg, dst, SADB_EXT_ADDRESS_DST);
-
-       if (pfkey_send(this, msg, &out, &len) != SUCCESS)
-       {
-               DBG1(DBG_KNL, "unable to delete SAD entry with SPI %.8x", ntohl(spi));
-               return FAILED;
-       }
-       else if (out->sadb_msg_errno)
-       {
-               DBG1(DBG_KNL, "unable to delete SAD entry with SPI %.8x: %s (%d)",
-                               ntohl(spi), strerror(out->sadb_msg_errno), out->sadb_msg_errno);
-               free(out);
-               return FAILED;
-       }
-
-       DBG2(DBG_KNL, "deleted SAD entry with SPI %.8x", ntohl(spi));
-       free(out);
-       return SUCCESS;
-}
-
-METHOD(kernel_ipsec_t, add_policy, status_t,
-       private_kernel_klips_ipsec_t *this, host_t *src, host_t *dst,
-       traffic_selector_t *src_ts, traffic_selector_t *dst_ts,
-       policy_dir_t direction, u_int32_t spi, u_int8_t protocol,
-       u_int32_t reqid, mark_t mark, ipsec_mode_t mode, u_int16_t ipcomp,
-       u_int16_t cpi, bool routed)
-{
-       unsigned char request[PFKEY_BUFFER_SIZE];
-       struct sadb_msg *msg, *out;
-       policy_entry_t *policy, *found = NULL;
-       u_int8_t satype;
-       size_t len;
-
-       if (direction == POLICY_FWD)
-       {
-               /* no forward policies for KLIPS */
-               return SUCCESS;
-       }
-
-       /* tunnel mode policies direct the packets into the pseudo IPIP SA */
-       satype = (mode == MODE_TUNNEL) ? SADB_X_SATYPE_IPIP :
-                                                                        proto2satype(protocol);
-
-       /* create a policy */
-       policy = create_policy_entry(src_ts, dst_ts, direction);
-
-       /* find a matching policy */
-       this->mutex->lock(this->mutex);
-       if (this->policies->find_first(this->policies,
-                       (linked_list_match_t)policy_entry_equals, (void**)&found, policy) == SUCCESS)
-       {
-               /* use existing policy */
-               DBG2(DBG_KNL, "policy %R === %R %N already exists, increasing"
-                                         " refcount", src_ts, dst_ts,
-                                          policy_dir_names, direction);
-               policy_entry_destroy(policy);
-               policy = found;
-       }
-       else
-       {
-               /* apply the new one, if we have no such policy */
-               this->policies->insert_last(this->policies, policy);
-       }
-
-       if (routed)
-       {
-               /* we install this as a %trap eroute in the kernel, later to be
-                * triggered by packets matching the policy (-> ACQUIRE). */
-               spi = htonl(SPI_TRAP);
-               satype = SADB_X_SATYPE_INT;
-
-               /* the reqid is always set to the latest child SA that trapped this
-                * policy. we will need this reqid upon receiving an acquire. */
-               policy->reqid = reqid;
-
-               /* increase the trap counter */
-               policy->trapcount++;
-
-               if (policy->activecount)
-               {
-                       /* we do not replace the current policy in the kernel while a
-                        * policy is actively used */
-                       this->mutex->unlock(this->mutex);
-                       return SUCCESS;
-               }
-       }
-       else
-       {
-               /* increase the reference counter */
-               policy->activecount++;
-       }
-
-       DBG2(DBG_KNL, "adding policy %R === %R %N", src_ts, dst_ts,
-                                  policy_dir_names, direction);
-
-       memset(&request, 0, sizeof(request));
-
-       msg = (struct sadb_msg*)request;
-
-       /* FIXME: SADB_X_SAFLAGS_INFLOW may be required, if we add an inbound policy for an IPIP SA */
-       build_addflow(msg, satype, spi, routed ? NULL : src, routed ? NULL : dst,
-                       policy->src.net, policy->src.mask, policy->dst.net, policy->dst.mask,
-                       policy->src.proto, found != NULL);
-
-       this->mutex->unlock(this->mutex);
-
-       if (pfkey_send(this, msg, &out, &len) != SUCCESS)
-       {
-               DBG1(DBG_KNL, "unable to add policy %R === %R %N", src_ts, dst_ts,
-                                          policy_dir_names, direction);
-               return FAILED;
-       }
-       else if (out->sadb_msg_errno)
-       {
-               DBG1(DBG_KNL, "unable to add policy %R === %R %N: %s (%d)", src_ts, dst_ts,
-                                          policy_dir_names, direction,
-                                          strerror(out->sadb_msg_errno), out->sadb_msg_errno);
-               free(out);
-               return FAILED;
-       }
-       free(out);
-
-       this->mutex->lock(this->mutex);
-
-       /* we try to find the policy again and install the route if needed */
-       if (this->policies->find_last(this->policies, NULL, (void**)&policy) != SUCCESS)
-       {
-               this->mutex->unlock(this->mutex);
-               DBG2(DBG_KNL, "the policy %R === %R %N is already gone, ignoring",
-                               src_ts, dst_ts, policy_dir_names, direction);
-               return SUCCESS;
-       }
-
-       /* KLIPS requires a special route that directs traffic that matches this
-        * policy to one of the virtual ipsec interfaces. The virtual interface
-        * has to be attached to the physical one the traffic runs over.
-        * This is a special case of the source route we install in other kernel
-        * interfaces.
-        * In the following cases we do NOT install a source route (but just a
-        * regular route):
-        * - we are not in tunnel mode
-        * - we are using IPv6 (does not work correctly yet!)
-        * - routing is disabled via strongswan.conf
-        */
-       if (policy->route == NULL && direction == POLICY_OUT)
-       {
-               char *iface;
-               ipsec_dev_t *dev;
-               route_entry_t *route = malloc_thing(route_entry_t);
-               route->src_ip = NULL;
-
-               if (mode != MODE_TRANSPORT && src->get_family(src) != AF_INET6 &&
-                       this->install_routes)
-               {
-                       hydra->kernel_interface->get_address_by_ts(hydra->kernel_interface,
-                                                                                                          src_ts, &route->src_ip);
-               }
-
-               if (!route->src_ip)
-               {
-                       route->src_ip = host_create_any(src->get_family(src));
-               }
-
-               /* find the virtual interface */
-               iface = hydra->kernel_interface->get_interface(hydra->kernel_interface,
-                                                                                                          src);
-               if (find_ipsec_dev(this, iface, &dev) == SUCCESS)
-               {
-                       /* above, we got either the name of a virtual or a physical
-                        * interface. for both cases it means we already have the devices
-                        * properly attached (assuming that we are exclusively attaching
-                        * ipsec devices). */
-                       dev->refcount++;
-               }
-               else
-               {
-                       /* there is no record of a mapping with the returned interface.
-                        * thus, we attach the first free virtual interface we find to
-                        * it. As above we assume we are the only client fiddling with
-                        * ipsec devices. */
-                       if (this->ipsec_devices->find_first(this->ipsec_devices,
-                                       (linked_list_match_t)ipsec_dev_match_free,
-                                               (void**)&dev) == SUCCESS)
-                       {
-                               if (attach_ipsec_dev(dev->name, iface) == SUCCESS)
-                               {
-                                       strncpy(dev->phys_name, iface, IFNAMSIZ);
-                                       dev->refcount = 1;
-                               }
-                               else
-                               {
-                                       DBG1(DBG_KNL, "failed to attach virtual interface %s"
-                                                       " to %s", dev->name, iface);
-                                       this->mutex->unlock(this->mutex);
-                                       free(iface);
-                                       return FAILED;
-                               }
-                       }
-                       else
-                       {
-                               this->mutex->unlock(this->mutex);
-                               DBG1(DBG_KNL, "failed to attach a virtual interface to %s: no"
-                                               " virtual interfaces left", iface);
-                               free(iface);
-                               return FAILED;
-                       }
-               }
-               free(iface);
-               route->if_name = strdup(dev->name);
-
-               /* get the nexthop to dst */
-               route->gateway = hydra->kernel_interface->get_nexthop(
-                                                                                               hydra->kernel_interface, dst);
-               route->dst_net = chunk_clone(policy->dst.net->get_address(policy->dst.net));
-               route->prefixlen = policy->dst.mask;
-
-               switch (hydra->kernel_interface->add_route(hydra->kernel_interface,
-                               route->dst_net, route->prefixlen, route->gateway,
-                               route->src_ip, route->if_name))
-               {
-                       default:
-                               DBG1(DBG_KNL, "unable to install route for policy %R === %R",
-                                        src_ts, dst_ts);
-                               /* FALL */
-                       case ALREADY_DONE:
-                               /* route exists, do not uninstall */
-                               route_entry_destroy(route);
-                               break;
-                       case SUCCESS:
-                               /* cache the installed route */
-                               policy->route = route;
-                               break;
-               }
-       }
-
-       this->mutex->unlock(this->mutex);
-
-       return SUCCESS;
-}
-
-METHOD(kernel_ipsec_t, query_policy, status_t,
-       private_kernel_klips_ipsec_t *this, traffic_selector_t *src_ts,
-       traffic_selector_t *dst_ts, policy_dir_t direction, mark_t mark,
-       u_int32_t *use_time)
-{
-       #define IDLE_PREFIX "idle="
-       static const char *path_eroute = "/proc/net/ipsec_eroute";
-       static const char *path_spi = "/proc/net/ipsec_spi";
-       FILE *file;
-       char line[1024], src[INET6_ADDRSTRLEN + 9], dst[INET6_ADDRSTRLEN + 9];
-       char *said = NULL, *pos;
-       policy_entry_t *policy, *found = NULL;
-       status_t status = FAILED;
-
-       if (direction == POLICY_FWD)
-       {
-               /* we do not install forward policies */
-               return FAILED;
-       }
-
-       DBG2(DBG_KNL, "querying policy %R === %R %N", src_ts, dst_ts,
-                                  policy_dir_names, direction);
-
-       /* create a policy */
-       policy = create_policy_entry(src_ts, dst_ts, direction);
-
-       /* find a matching policy */
-       this->mutex->lock(this->mutex);
-       if (this->policies->find_first(this->policies,
-                       (linked_list_match_t)policy_entry_equals, (void**)&found, policy) != SUCCESS)
-       {
-               this->mutex->unlock(this->mutex);
-               DBG1(DBG_KNL, "querying policy %R === %R %N failed, not found", src_ts,
-                                          dst_ts, policy_dir_names, direction);
-               policy_entry_destroy(policy);
-               return NOT_FOUND;
-       }
-       policy_entry_destroy(policy);
-       policy = found;
-
-       /* src and dst selectors in KLIPS are of the form NET_ADDR/NETBITS:PROTO */
-       snprintf(src, sizeof(src), "%H/%d:%d", policy->src.net, policy->src.mask,
-                       policy->src.proto);
-       src[sizeof(src) - 1] = '\0';
-       snprintf(dst, sizeof(dst), "%H/%d:%d", policy->dst.net, policy->dst.mask,
-                       policy->dst.proto);
-       dst[sizeof(dst) - 1] = '\0';
-
-       this->mutex->unlock(this->mutex);
-
-       /* we try to find the matching eroute first */
-       file = fopen(path_eroute, "r");
-       if (file == NULL)
-       {
-               DBG1(DBG_KNL, "unable to query policy %R === %R %N: %s (%d)", src_ts,
-                               dst_ts, policy_dir_names, direction, strerror(errno), errno);
-               return FAILED;
-       }
-
-       /* read line by line where each line looks like:
-        * packets  src  ->  dst  =>  said */
-       while (fgets(line, sizeof(line), file))
-       {
-               enumerator_t *enumerator;
-               char *token;
-               int i = 0;
-
-               enumerator = enumerator_create_token(line, " \t", " \t\n");
-               while (enumerator->enumerate(enumerator, &token))
-               {
-                       switch (i++)
-                       {
-                               case 0: /* packets */
-                                       continue;
-                               case 1: /* src */
-                                       if (streq(token, src))
-                                       {
-                                               continue;
-                                       }
-                                       break;
-                               case 2: /* -> */
-                                       continue;
-                               case 3: /* dst */
-                                       if (streq(token, dst))
-                                       {
-                                               continue;
-                                       }
-                                       break;
-                               case 4: /* => */
-                                       continue;
-                               case 5: /* said */
-                                       said = strdup(token);
-                                       break;
-                       }
-                       break;
-               }
-               enumerator->destroy(enumerator);
-
-               if (i == 5)
-               {
-                       /* eroute matched */
-                       break;
-               }
-       }
-       fclose(file);
-
-       if (said == NULL)
-       {
-               DBG1(DBG_KNL, "unable to query policy %R === %R %N: found no matching"
-                               " eroute", src_ts, dst_ts, policy_dir_names, direction);
-               return FAILED;
-       }
-
-       /* compared with the one in the spi entry the SA ID from the eroute entry
-        * has an additional ":PROTO" appended, which we need to cut off */
-       pos = strrchr(said, ':');
-       *pos = '\0';
-
-       /* now we try to find the matching spi entry */
-       file = fopen(path_spi, "r");
-       if (file == NULL)
-       {
-               DBG1(DBG_KNL, "unable to query policy %R === %R %N: %s (%d)", src_ts,
-                               dst_ts, policy_dir_names, direction, strerror(errno), errno);
-               return FAILED;
-       }
-
-       while (fgets(line, sizeof(line), file))
-       {
-               if (strneq(line, said, strlen(said)))
-               {
-                       /* fine we found the correct line, now find the idle time */
-                       u_int32_t idle_time;
-                       pos = strstr(line, IDLE_PREFIX);
-                       if (pos == NULL)
-                       {
-                               /* no idle time, i.e. this SA has not been used yet */
-                               break;
-                       }
-                       if (sscanf(pos, IDLE_PREFIX"%u", &idle_time) <= 0)
-                       {
-                               /* idle time not valid */
-                               break;
-                       }
-
-                       *use_time = time_monotonic(NULL) - idle_time;
-                       status = SUCCESS;
-                       break;
-               }
-       }
-       fclose(file);
-       free(said);
-
-       return status;
-}
-
-METHOD(kernel_ipsec_t, del_policy, status_t,
-       private_kernel_klips_ipsec_t *this, traffic_selector_t *src_ts,
-       traffic_selector_t *dst_ts, policy_dir_t direction, mark_t mark,
-       bool unrouted)
-{
-       unsigned char request[PFKEY_BUFFER_SIZE];
-       struct sadb_msg *msg = (struct sadb_msg*)request, *out;
-       policy_entry_t *policy, *found = NULL;
-       route_entry_t *route;
-       size_t len;
-
-       if (direction == POLICY_FWD)
-       {
-               /* no forward policies for KLIPS */
-               return SUCCESS;
-       }
-
-       DBG2(DBG_KNL, "deleting policy %R === %R %N", src_ts, dst_ts,
-                                  policy_dir_names, direction);
-
-       /* create a policy */
-       policy = create_policy_entry(src_ts, dst_ts, direction);
-
-       /* find a matching policy */
-       this->mutex->lock(this->mutex);
-       if (this->policies->find_first(this->policies,
-                       (linked_list_match_t)policy_entry_equals, (void**)&found, policy) != SUCCESS)
-       {
-               this->mutex->unlock(this->mutex);
-               DBG1(DBG_KNL, "deleting policy %R === %R %N failed, not found", src_ts,
-                                          dst_ts, policy_dir_names, direction);
-               policy_entry_destroy(policy);
-               return NOT_FOUND;
-       }
-       policy_entry_destroy(policy);
-
-       /* decrease appropriate counter */
-       unrouted ? found->trapcount-- : found->activecount--;
-
-       if (found->trapcount == 0)
-       {
-               /* if this policy is finally unrouted, we reset the reqid because it
-                * may still be actively used and there might be a pending acquire for
-                * this policy. */
-               found->reqid = 0;
-       }
-
-       if (found->activecount > 0)
-       {
-               /* is still used by SAs, keep in kernel */
-               this->mutex->unlock(this->mutex);
-               DBG2(DBG_KNL, "policy still used by another CHILD_SA, not removed");
-               return SUCCESS;
-       }
-       else if (found->activecount == 0 && found->trapcount > 0)
-       {
-               /* for a policy that is not used actively anymore, but is still trapped
-                * by another child SA we replace the current eroute with a %trap eroute */
-               DBG2(DBG_KNL, "policy still routed by another CHILD_SA, not removed");
-               memset(&request, 0, sizeof(request));
-               build_addflow(msg, SADB_X_SATYPE_INT, htonl(SPI_TRAP), NULL, NULL,
-                               found->src.net, found->src.mask, found->dst.net,
-                               found->dst.mask, found->src.proto, TRUE);
-               this->mutex->unlock(this->mutex);
-               return pfkey_send_ack(this, msg);
-       }
-
-       /* remove if last reference */
-       this->policies->remove(this->policies, found, NULL);
-       policy = found;
-
-       this->mutex->unlock(this->mutex);
-
-       memset(&request, 0, sizeof(request));
-
-       build_delflow(msg, 0, policy->src.net, policy->src.mask, policy->dst.net,
-                       policy->dst.mask, policy->src.proto);
-
-       route = policy->route;
-       policy->route = NULL;
-       policy_entry_destroy(policy);
-
-       if (pfkey_send(this, msg, &out, &len) != SUCCESS)
-       {
-               DBG1(DBG_KNL, "unable to delete policy %R === %R %N", src_ts, dst_ts,
-                                          policy_dir_names, direction);
-               return FAILED;
-       }
-       else if (out->sadb_msg_errno)
-       {
-               DBG1(DBG_KNL, "unable to delete policy %R === %R %N: %s (%d)", src_ts,
-                                          dst_ts, policy_dir_names, direction,
-                                          strerror(out->sadb_msg_errno), out->sadb_msg_errno);
-               free(out);
-               return FAILED;
-       }
-       free(out);
-
-       if (route)
-       {
-               ipsec_dev_t *dev;
-
-               if (hydra->kernel_interface->del_route(hydra->kernel_interface,
-                               route->dst_net, route->prefixlen, route->gateway,
-                               route->src_ip, route->if_name) != SUCCESS)
-               {
-                       DBG1(DBG_KNL, "error uninstalling route installed with"
-                                                 " policy %R === %R %N", src_ts, dst_ts,
-                                                  policy_dir_names, direction);
-               }
-
-               /* we have to detach the ipsec interface from the physical one over which
-                * this SA ran (if it is not used by any other) */
-               this->mutex->lock(this->mutex);
-
-               if (find_ipsec_dev(this, route->if_name, &dev) == SUCCESS)
-               {
-                       /* fine, we found a matching device object, let's check if we have
-                        * to detach it. */
-                       if (--dev->refcount == 0)
-                       {
-                               if (detach_ipsec_dev(dev->name, dev->phys_name) != SUCCESS)
-                               {
-                                       DBG1(DBG_KNL, "failed to detach virtual interface %s"
-                                                       " from %s", dev->name, dev->phys_name);
-                               }
-                               dev->phys_name[0] = '\0';
-                       }
-               }
-
-               this->mutex->unlock(this->mutex);
-
-               route_entry_destroy(route);
-       }
-
-       return SUCCESS;
-}
-
-/**
- * Initialize the list of ipsec devices
- */
-static void init_ipsec_devices(private_kernel_klips_ipsec_t *this)
-{
-       int i, count = lib->settings->get_int(lib->settings,
-                                               "charon.plugins.kernel-klips.ipsec_dev_count",
-                                               DEFAULT_IPSEC_DEV_COUNT);
-
-       for (i = 0; i < count; ++i)
-       {
-               ipsec_dev_t *dev = malloc_thing(ipsec_dev_t);
-               snprintf(dev->name, IFNAMSIZ, IPSEC_DEV_PREFIX"%d", i);
-               dev->name[IFNAMSIZ - 1] = '\0';
-               dev->phys_name[0] = '\0';
-               dev->refcount = 0;
-               this->ipsec_devices->insert_last(this->ipsec_devices, dev);
-
-               /* detach any previously attached ipsec device */
-               detach_ipsec_dev(dev->name, dev->phys_name);
-       }
-}
-
-/**
- * Register a socket for AQUIRE/EXPIRE messages
- */
-static status_t register_pfkey_socket(private_kernel_klips_ipsec_t *this, u_int8_t satype)
-{
-       unsigned char request[PFKEY_BUFFER_SIZE];
-       struct sadb_msg *msg, *out;
-       size_t len;
-
-       memset(&request, 0, sizeof(request));
-
-       msg = (struct sadb_msg*)request;
-       msg->sadb_msg_version = PF_KEY_V2;
-       msg->sadb_msg_type = SADB_REGISTER;
-       msg->sadb_msg_satype = satype;
-       msg->sadb_msg_len = PFKEY_LEN(sizeof(struct sadb_msg));
-
-       if (pfkey_send_socket(this, this->socket_events, msg, &out, &len) != SUCCESS)
-       {
-               DBG1(DBG_KNL, "unable to register PF_KEY socket");
-               return FAILED;
-       }
-       else if (out->sadb_msg_errno)
-       {
-               DBG1(DBG_KNL, "unable to register PF_KEY socket: %s (%d)",
-                                          strerror(out->sadb_msg_errno), out->sadb_msg_errno);
-               free(out);
-               return FAILED;
-       }
-       free(out);
-       return SUCCESS;
-}
-
-METHOD(kernel_ipsec_t, bypass_socket, bool,
-       private_kernel_klips_ipsec_t *this, int fd, int family)
-{
-       /* KLIPS does not need a bypass policy for IKE */
-       return TRUE;
-}
-
-METHOD(kernel_ipsec_t, destroy, void,
-       private_kernel_klips_ipsec_t *this)
-{
-       if (this->job)
-       {
-               this->job->cancel(this->job);
-       }
-       if (this->socket > 0)
-       {
-               close(this->socket);
-       }
-       if (this->socket_events > 0)
-       {
-               close(this->socket_events);
-       }
-       this->mutex_pfkey->destroy(this->mutex_pfkey);
-       this->mutex->destroy(this->mutex);
-       this->ipsec_devices->destroy_function(this->ipsec_devices, (void*)ipsec_dev_destroy);
-       this->installed_sas->destroy_function(this->installed_sas, (void*)sa_entry_destroy);
-       this->allocated_spis->destroy_function(this->allocated_spis, (void*)sa_entry_destroy);
-       this->policies->destroy_function(this->policies, (void*)policy_entry_destroy);
-       free(this);
-}
-
-/*
- * Described in header.
- */
-kernel_klips_ipsec_t *kernel_klips_ipsec_create()
-{
-       private_kernel_klips_ipsec_t *this;
-
-       INIT(this,
-               .public = {
-                       .interface = {
-                               .get_spi = _get_spi,
-                               .get_cpi = _get_cpi,
-                               .add_sa  = _add_sa,
-                               .update_sa = _update_sa,
-                               .query_sa = _query_sa,
-                               .del_sa = _del_sa,
-                               .add_policy = _add_policy,
-                               .query_policy = _query_policy,
-                               .del_policy = _del_policy,
-                               .bypass_socket = _bypass_socket,
-                               .destroy = _destroy,
-                       },
-               },
-               .policies = linked_list_create(),
-               .allocated_spis = linked_list_create(),
-               .installed_sas = linked_list_create(),
-               .ipsec_devices = linked_list_create(),
-               .mutex = mutex_create(MUTEX_TYPE_DEFAULT),
-               .mutex_pfkey = mutex_create(MUTEX_TYPE_DEFAULT),
-               .install_routes = lib->settings->get_bool(lib->settings,
-                                                                                               "charon.install_routes", TRUE),
-       );
-
-       /* initialize ipsec devices */
-       init_ipsec_devices(this);
-
-       /* create a PF_KEY socket to communicate with the kernel */
-       this->socket = socket(PF_KEY, SOCK_RAW, PF_KEY_V2);
-       if (this->socket <= 0)
-       {
-               DBG1(DBG_KNL, "unable to create PF_KEY socket");
-               destroy(this);
-               return NULL;
-       }
-
-       /* create a PF_KEY socket for ACQUIRE & EXPIRE */
-       this->socket_events = socket(PF_KEY, SOCK_RAW, PF_KEY_V2);
-       if (this->socket_events <= 0)
-       {
-               DBG1(DBG_KNL, "unable to create PF_KEY event socket");
-               destroy(this);
-               return NULL;
-       }
-
-       /* register the event socket */
-       if (register_pfkey_socket(this, SADB_SATYPE_ESP) != SUCCESS ||
-               register_pfkey_socket(this, SADB_SATYPE_AH) != SUCCESS)
-       {
-               DBG1(DBG_KNL, "unable to register PF_KEY event socket");
-               destroy(this);
-               return NULL;
-       }
-
-       this->job = callback_job_create((callback_job_cb_t)receive_events,
-                                                                       this, NULL, NULL);
-       hydra->processor->queue_job(hydra->processor, (job_t*)this->job);
-
-       return &this->public;
-}
-
diff --git a/src/libcharon/plugins/kernel_klips/kernel_klips_ipsec.h b/src/libcharon/plugins/kernel_klips/kernel_klips_ipsec.h
deleted file mode 100644 (file)
index 306ec0a..0000000
+++ /dev/null
@@ -1,46 +0,0 @@
-/*
- * Copyright (C) 2008 Tobias Brunner
- * Hochschule fuer Technik Rapperswil
- *
- * This program is free software; you can redistribute it and/or modify it
- * under the terms of the GNU General Public License as published by the
- * Free Software Foundation; either version 2 of the License, or (at your
- * option) any later version.  See <http://www.fsf.org/copyleft/gpl.txt>.
- *
- * This program is distributed in the hope that it will be useful, but
- * WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY
- * or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License
- * for more details.
- */
-
-/**
- * @defgroup kernel_klips_ipsec_i kernel_klips_ipsec
- * @{ @ingroup kernel_klips
- */
-
-#ifndef KERNEL_KLIPS_IPSEC_H_
-#define KERNEL_KLIPS_IPSEC_H_
-
-#include <kernel/kernel_ipsec.h>
-
-typedef struct kernel_klips_ipsec_t kernel_klips_ipsec_t;
-
-/**
- * Implementation of the kernel ipsec interface using PF_KEY.
- */
-struct kernel_klips_ipsec_t {
-
-       /**
-        * Implements kernel_ipsec_t interface
-        */
-       kernel_ipsec_t interface;
-};
-
-/**
- * Create a PF_KEY kernel ipsec interface instance.
- *
- * @return                     kernel_klips_ipsec_t instance
- */
-kernel_klips_ipsec_t *kernel_klips_ipsec_create();
-
-#endif /** KERNEL_KLIPS_IPSEC_H_ @}*/
diff --git a/src/libcharon/plugins/kernel_klips/kernel_klips_plugin.c b/src/libcharon/plugins/kernel_klips/kernel_klips_plugin.c
deleted file mode 100644 (file)
index 1a22835..0000000
+++ /dev/null
@@ -1,58 +0,0 @@
-/*
- * Copyright (C) 2008 Tobias Brunner
- * Hochschule fuer Technik Rapperswil
- *
- * This program is free software; you can redistribute it and/or modify it
- * under the terms of the GNU General Public License as published by the
- * Free Software Foundation; either version 2 of the License, or (at your
- * option) any later version.  See <http://www.fsf.org/copyleft/gpl.txt>.
- *
- * This program is distributed in the hope that it will be useful, but
- * WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY
- * or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License
- * for more details.
- */
-
-
-#include "kernel_klips_plugin.h"
-
-#include "kernel_klips_ipsec.h"
-
-#include <hydra.h>
-
-typedef struct private_kernel_klips_plugin_t private_kernel_klips_plugin_t;
-
-/**
- * private data of kernel PF_KEY plugin
- */
-struct private_kernel_klips_plugin_t {
-       /**
-        * implements plugin interface
-        */
-       kernel_klips_plugin_t public;
-};
-
-/**
- * Implementation of plugin_t.destroy
- */
-static void destroy(private_kernel_klips_plugin_t *this)
-{
-       hydra->kernel_interface->remove_ipsec_interface(hydra->kernel_interface,
-                                               (kernel_ipsec_constructor_t)kernel_klips_ipsec_create);
-       free(this);
-}
-
-/*
- * see header file
- */
-plugin_t *kernel_klips_plugin_create()
-{
-       private_kernel_klips_plugin_t *this = malloc_thing(private_kernel_klips_plugin_t);
-
-       this->public.plugin.destroy = (void(*)(plugin_t*))destroy;
-
-       hydra->kernel_interface->add_ipsec_interface(hydra->kernel_interface,
-                                               (kernel_ipsec_constructor_t)kernel_klips_ipsec_create);
-
-       return &this->public.plugin;
-}
diff --git a/src/libcharon/plugins/kernel_klips/kernel_klips_plugin.h b/src/libcharon/plugins/kernel_klips/kernel_klips_plugin.h
deleted file mode 100644 (file)
index 6086217..0000000
+++ /dev/null
@@ -1,42 +0,0 @@
-/*
- * Copyright (C) 2008 Tobias Brunner
- * Hochschule fuer Technik Rapperswil
- *
- * This program is free software; you can redistribute it and/or modify it
- * under the terms of the GNU General Public License as published by the
- * Free Software Foundation; either version 2 of the License, or (at your
- * option) any later version.  See <http://www.fsf.org/copyleft/gpl.txt>.
- *
- * This program is distributed in the hope that it will be useful, but
- * WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY
- * or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License
- * for more details.
- */
-
-/**
- * @defgroup kernel_klips kernel_klips
- * @ingroup cplugins
- *
- * @defgroup kernel_klips_plugin kernel_klips_plugin
- * @{ @ingroup kernel_klips
- */
-
-#ifndef KERNEL_KLIPS_PLUGIN_H_
-#define KERNEL_KLIPS_PLUGIN_H_
-
-#include <plugins/plugin.h>
-
-typedef struct kernel_klips_plugin_t kernel_klips_plugin_t;
-
-/**
- * PF_KEY kernel interface plugin
- */
-struct kernel_klips_plugin_t {
-
-       /**
-        * implements plugin interface
-        */
-       plugin_t plugin;
-};
-
-#endif /** KERNEL_KLIPS_PLUGIN_H_ @}*/
diff --git a/src/libcharon/plugins/kernel_klips/pfkeyv2.h b/src/libcharon/plugins/kernel_klips/pfkeyv2.h
deleted file mode 100644 (file)
index 20d1c29..0000000
+++ /dev/null
@@ -1,322 +0,0 @@
-/*
-RFC 2367               PF_KEY Key Management API               July 1998
-
-
-Appendix D: Sample Header File
-
-This file defines structures and symbols for the PF_KEY Version 2
-key management interface. It was written at the U.S. Naval Research
-Laboratory. This file is in the public domain. The authors ask that
-you leave this credit intact on any copies of this file.
-*/
-#ifndef __PFKEY_V2_H
-#define __PFKEY_V2_H 1
-
-#define PF_KEY_V2 2
-#define PFKEYV2_REVISION        199806L
-
-#define SADB_RESERVED    0
-#define SADB_GETSPI      1
-#define SADB_UPDATE      2
-#define SADB_ADD         3
-#define SADB_DELETE      4
-#define SADB_GET         5
-#define SADB_ACQUIRE     6
-#define SADB_REGISTER    7
-#define SADB_EXPIRE      8
-#define SADB_FLUSH       9
-#define SADB_DUMP       10
-#define SADB_X_PROMISC  11
-#define SADB_X_PCHANGE  12
-#define SADB_X_GRPSA    13
-#define SADB_X_ADDFLOW 14
-#define SADB_X_DELFLOW 15
-#define SADB_X_DEBUG   16
-#define SADB_X_NAT_T_NEW_MAPPING  17
-#define SADB_MAX                  17
-
-struct sadb_msg {
-  uint8_t sadb_msg_version;
-  uint8_t sadb_msg_type;
-  uint8_t sadb_msg_errno;
-  uint8_t sadb_msg_satype;
-  uint16_t sadb_msg_len;
-  uint16_t sadb_msg_reserved;
-  uint32_t sadb_msg_seq;
-  uint32_t sadb_msg_pid;
-};
-
-struct sadb_ext {
-  uint16_t sadb_ext_len;
-  uint16_t sadb_ext_type;
-};
-
-struct sadb_sa {
-  uint16_t sadb_sa_len;
-  uint16_t sadb_sa_exttype;
-  uint32_t sadb_sa_spi;
-  uint8_t sadb_sa_replay;
-  uint8_t sadb_sa_state;
-  uint8_t sadb_sa_auth;
-  uint8_t sadb_sa_encrypt;
-  uint32_t sadb_sa_flags;
-};
-
-struct sadb_lifetime {
-  uint16_t sadb_lifetime_len;
-  uint16_t sadb_lifetime_exttype;
-  uint32_t sadb_lifetime_allocations;
-  uint64_t sadb_lifetime_bytes;
-  uint64_t sadb_lifetime_addtime;
-  uint64_t sadb_lifetime_usetime;
-  uint32_t sadb_x_lifetime_packets;
-  uint32_t sadb_x_lifetime_reserved;
-};
-
-struct sadb_address {
-  uint16_t sadb_address_len;
-  uint16_t sadb_address_exttype;
-  uint8_t sadb_address_proto;
-  uint8_t sadb_address_prefixlen;
-  uint16_t sadb_address_reserved;
-};
-
-struct sadb_key {
-  uint16_t sadb_key_len;
-  uint16_t sadb_key_exttype;
-  uint16_t sadb_key_bits;
-  uint16_t sadb_key_reserved;
-};
-
-struct sadb_ident {
-  uint16_t sadb_ident_len;
-  uint16_t sadb_ident_exttype;
-  uint16_t sadb_ident_type;
-  uint16_t sadb_ident_reserved;
-  uint64_t sadb_ident_id;
-};
-
-struct sadb_sens {
-  uint16_t sadb_sens_len;
-  uint16_t sadb_sens_exttype;
-  uint32_t sadb_sens_dpd;
-  uint8_t sadb_sens_sens_level;
-  uint8_t sadb_sens_sens_len;
-  uint8_t sadb_sens_integ_level;
-  uint8_t sadb_sens_integ_len;
-  uint32_t sadb_sens_reserved;
-};
-
-struct sadb_prop {
-  uint16_t sadb_prop_len;
-  uint16_t sadb_prop_exttype;
-  uint8_t sadb_prop_replay;
-  uint8_t sadb_prop_reserved[3];
-};
-
-struct sadb_comb {
-  uint8_t sadb_comb_auth;
-  uint8_t sadb_comb_encrypt;
-  uint16_t sadb_comb_flags;
-  uint16_t sadb_comb_auth_minbits;
-  uint16_t sadb_comb_auth_maxbits;
-  uint16_t sadb_comb_encrypt_minbits;
-  uint16_t sadb_comb_encrypt_maxbits;
-  uint32_t sadb_comb_reserved;
-  uint32_t sadb_comb_soft_allocations;
-  uint32_t sadb_comb_hard_allocations;
-  uint64_t sadb_comb_soft_bytes;
-  uint64_t sadb_comb_hard_bytes;
-  uint64_t sadb_comb_soft_addtime;
-  uint64_t sadb_comb_hard_addtime;
-  uint64_t sadb_comb_soft_usetime;
-  uint64_t sadb_comb_hard_usetime;
-  uint32_t sadb_x_comb_soft_packets;
-  uint32_t sadb_x_comb_hard_packets;
-};
-
-struct sadb_supported {
-  uint16_t sadb_supported_len;
-  uint16_t sadb_supported_exttype;
-  uint32_t sadb_supported_reserved;
-};
-
-struct sadb_alg {
-  uint8_t sadb_alg_id;
-  uint8_t sadb_alg_ivlen;
-  uint16_t sadb_alg_minbits;
-  uint16_t sadb_alg_maxbits;
-  uint16_t sadb_alg_reserved;
-};
-
-struct sadb_spirange {
-  uint16_t sadb_spirange_len;
-  uint16_t sadb_spirange_exttype;
-  uint32_t sadb_spirange_min;
-  uint32_t sadb_spirange_max;
-  uint32_t sadb_spirange_reserved;
-};
-
-struct sadb_x_kmprivate {
-  uint16_t sadb_x_kmprivate_len;
-  uint16_t sadb_x_kmprivate_exttype;
-  uint32_t sadb_x_kmprivate_reserved;
-};
-
-struct sadb_x_satype {
-  uint16_t sadb_x_satype_len;
-  uint16_t sadb_x_satype_exttype;
-  uint8_t sadb_x_satype_satype;
-  uint8_t sadb_x_satype_reserved[3];
-};
-
-struct sadb_x_debug {
-  uint16_t sadb_x_debug_len;
-  uint16_t sadb_x_debug_exttype;
-  uint32_t sadb_x_debug_tunnel;
-  uint32_t sadb_x_debug_netlink;
-  uint32_t sadb_x_debug_xform;
-  uint32_t sadb_x_debug_eroute;
-  uint32_t sadb_x_debug_spi;
-  uint32_t sadb_x_debug_radij;
-  uint32_t sadb_x_debug_esp;
-  uint32_t sadb_x_debug_ah;
-  uint32_t sadb_x_debug_rcv;
-  uint32_t sadb_x_debug_pfkey;
-  uint32_t sadb_x_debug_ipcomp;
-  uint32_t sadb_x_debug_verbose;
-  uint8_t sadb_x_debug_reserved[4];
-};
-
-struct sadb_x_nat_t_type {
-  uint16_t sadb_x_nat_t_type_len;
-  uint16_t sadb_x_nat_t_type_exttype;
-  uint8_t sadb_x_nat_t_type_type;
-  uint8_t sadb_x_nat_t_type_reserved[3];
-};
-struct sadb_x_nat_t_port {
-  uint16_t sadb_x_nat_t_port_len;
-  uint16_t sadb_x_nat_t_port_exttype;
-  uint16_t sadb_x_nat_t_port_port;
-  uint16_t sadb_x_nat_t_port_reserved;
-};
-
-/*
- * A protocol structure for passing through the transport level
- * protocol.  It contains more fields than are actually used/needed
- * but it is this way to be compatible with the structure used in
- * OpenBSD (http://www.openbsd.org/cgi-bin/cvsweb/src/sys/net/pfkeyv2.h)
- */
-struct sadb_protocol {
-  uint16_t sadb_protocol_len;
-  uint16_t sadb_protocol_exttype;
-  uint8_t  sadb_protocol_proto;
-  uint8_t  sadb_protocol_direction;
-  uint8_t  sadb_protocol_flags;
-  uint8_t  sadb_protocol_reserved2;
-};
-
-#define SADB_EXT_RESERVED             0
-#define SADB_EXT_SA                   1
-#define SADB_EXT_LIFETIME_CURRENT     2
-#define SADB_EXT_LIFETIME_HARD        3
-#define SADB_EXT_LIFETIME_SOFT        4
-#define SADB_EXT_ADDRESS_SRC          5
-#define SADB_EXT_ADDRESS_DST          6
-#define SADB_EXT_ADDRESS_PROXY        7
-#define SADB_EXT_KEY_AUTH             8
-#define SADB_EXT_KEY_ENCRYPT          9
-#define SADB_EXT_IDENTITY_SRC         10
-#define SADB_EXT_IDENTITY_DST         11
-#define SADB_EXT_SENSITIVITY          12
-#define SADB_EXT_PROPOSAL             13
-#define SADB_EXT_SUPPORTED_AUTH       14
-#define SADB_EXT_SUPPORTED_ENCRYPT    15
-#define SADB_EXT_SPIRANGE             16
-#define SADB_X_EXT_KMPRIVATE          17
-#define SADB_X_EXT_SATYPE2            18
-#define SADB_X_EXT_SA2                19
-#define SADB_X_EXT_ADDRESS_DST2       20
-#define SADB_X_EXT_ADDRESS_SRC_FLOW   21
-#define SADB_X_EXT_ADDRESS_DST_FLOW   22
-#define SADB_X_EXT_ADDRESS_SRC_MASK   23
-#define SADB_X_EXT_ADDRESS_DST_MASK   24
-#define SADB_X_EXT_DEBUG              25
-#define SADB_X_EXT_PROTOCOL           26
-#define SADB_X_EXT_NAT_T_TYPE         27
-#define SADB_X_EXT_NAT_T_SPORT        28
-#define SADB_X_EXT_NAT_T_DPORT        29
-#define SADB_X_EXT_NAT_T_OA           30
-#define SADB_EXT_MAX                  30
-
-/* SADB_X_DELFLOW required over and above SADB_X_SAFLAGS_CLEARFLOW */
-#define SADB_X_EXT_ADDRESS_DELFLOW \
-       ( (1<<SADB_X_EXT_ADDRESS_SRC_FLOW) \
-       | (1<<SADB_X_EXT_ADDRESS_DST_FLOW) \
-       | (1<<SADB_X_EXT_ADDRESS_SRC_MASK) \
-       | (1<<SADB_X_EXT_ADDRESS_DST_MASK))
-
-#define SADB_SATYPE_UNSPEC    0
-#define SADB_SATYPE_AH        2
-#define SADB_SATYPE_ESP       3
-#define SADB_SATYPE_RSVP      5
-#define SADB_SATYPE_OSPFV2    6
-#define SADB_SATYPE_RIPV2     7
-#define SADB_SATYPE_MIP       8
-#define SADB_X_SATYPE_IPIP    9
-#define SADB_X_SATYPE_COMP    10
-#define SADB_X_SATYPE_INT     11
-#define SADB_SATYPE_MAX       11
-
-#define SADB_SASTATE_LARVAL   0
-#define SADB_SASTATE_MATURE   1
-#define SADB_SASTATE_DYING    2
-#define SADB_SASTATE_DEAD     3
-#define SADB_SASTATE_MAX      3
-
-#define SADB_SAFLAGS_PFS               1
-#define SADB_X_SAFLAGS_REPLACEFLOW     2
-#define SADB_X_SAFLAGS_CLEARFLOW       4
-#define SADB_X_SAFLAGS_INFLOW          8
-
-#define SADB_AALG_NONE        0
-#define SADB_AALG_MD5HMAC     2
-#define SADB_AALG_SHA1HMAC    3
-#define        SADB_AALG_SHA256_HMAC    5
-#define        SADB_AALG_SHA384_HMAC    6
-#define        SADB_AALG_SHA512_HMAC    7
-#define        SADB_AALG_RIPEMD160HMAC      8
-#define        SADB_AALG_MAX         15
-
-#define SADB_EALG_NONE        0
-#define SADB_EALG_DESCBC      2
-#define SADB_EALG_3DESCBC     3
-#define SADB_EALG_BFCBC              7
-#define SADB_EALG_NULL        11
-#define SADB_EALG_AESCBC      12
-#define SADB_EALG_MAX         255
-
-#define SADB_X_CALG_NONE          0
-#define SADB_X_CALG_OUI           1
-#define SADB_X_CALG_DEFLATE       2
-#define SADB_X_CALG_LZS           3
-#define SADB_X_CALG_V42BIS        4
-#define SADB_X_CALG_MAX           4
-
-#define SADB_X_TALG_NONE          0
-#define SADB_X_TALG_IPv4_in_IPv4  1
-#define SADB_X_TALG_IPv6_in_IPv4  2
-#define SADB_X_TALG_IPv4_in_IPv6  3
-#define SADB_X_TALG_IPv6_in_IPv6  4
-#define SADB_X_TALG_MAX           4
-
-
-#define SADB_IDENTTYPE_RESERVED   0
-#define SADB_IDENTTYPE_PREFIX     1
-#define SADB_IDENTTYPE_FQDN       2
-#define SADB_IDENTTYPE_USERFQDN   3
-#define SADB_X_IDENTTYPE_CONNECTION 4
-#define SADB_IDENTTYPE_MAX        4
-
-#define SADB_KEY_FLAGS_MAX     0
-#endif /* __PFKEY_V2_H */
diff --git a/src/libcharon/plugins/kernel_netlink/Makefile.am b/src/libcharon/plugins/kernel_netlink/Makefile.am
deleted file mode 100644 (file)
index 2bb00ec..0000000
+++ /dev/null
@@ -1,20 +0,0 @@
-
-INCLUDES = -I${linux_headers} -I$(top_srcdir)/src/libstrongswan \
-       -I$(top_srcdir)/src/libhydra -I$(top_srcdir)/src/libcharon
-
-AM_CFLAGS = -rdynamic \
--DROUTING_TABLE=${routing_table} \
--DROUTING_TABLE_PRIO=${routing_table_prio}
-
-if MONOLITHIC
-noinst_LTLIBRARIES = libstrongswan-kernel-netlink.la
-else
-plugin_LTLIBRARIES = libstrongswan-kernel-netlink.la
-endif
-
-libstrongswan_kernel_netlink_la_SOURCES = \
-       kernel_netlink_plugin.h kernel_netlink_plugin.c \
-       kernel_netlink_ipsec.h kernel_netlink_ipsec.c kernel_netlink_net.h kernel_netlink_net.c \
-       kernel_netlink_shared.h kernel_netlink_shared.c
-
-libstrongswan_kernel_netlink_la_LDFLAGS = -module -avoid-version
diff --git a/src/libcharon/plugins/kernel_netlink/kernel_netlink_ipsec.c b/src/libcharon/plugins/kernel_netlink/kernel_netlink_ipsec.c
deleted file mode 100644 (file)
index 7de60b0..0000000
+++ /dev/null
@@ -1,2208 +0,0 @@
-/*
- * Copyright (C) 2006-2010 Tobias Brunner
- * Copyright (C) 2005-2009 Martin Willi
- * Copyright (C) 2008 Andreas Steffen
- * Copyright (C) 2006-2007 Fabian Hartmann, Noah Heusser
- * Copyright (C) 2006 Daniel Roethlisberger
- * Copyright (C) 2005 Jan Hutter
- * Hochschule fuer Technik Rapperswil
- *
- * This program is free software; you can redistribute it and/or modify it
- * under the terms of the GNU General Public License as published by the
- * Free Software Foundation; either version 2 of the License, or (at your
- * option) any later version.  See <http://www.fsf.org/copyleft/gpl.txt>.
- *
- * This program is distributed in the hope that it will be useful, but
- * WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY
- * or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License
- * for more details.
- */
-
-#include <sys/types.h>
-#include <sys/socket.h>
-#include <stdint.h>
-#include <linux/ipsec.h>
-#include <linux/netlink.h>
-#include <linux/rtnetlink.h>
-#include <linux/xfrm.h>
-#include <linux/udp.h>
-#include <unistd.h>
-#include <time.h>
-#include <errno.h>
-#include <string.h>
-#include <fcntl.h>
-
-#include "kernel_netlink_ipsec.h"
-#include "kernel_netlink_shared.h"
-
-#include <hydra.h>
-#include <daemon.h>
-#include <threading/thread.h>
-#include <threading/mutex.h>
-#include <utils/hashtable.h>
-#include <processing/jobs/callback_job.h>
-
-/** required for Linux 2.6.26 kernel and later */
-#ifndef XFRM_STATE_AF_UNSPEC
-#define XFRM_STATE_AF_UNSPEC   32
-#endif
-
-/** from linux/in.h */
-#ifndef IP_XFRM_POLICY
-#define IP_XFRM_POLICY 17
-#endif
-
-/* missing on uclibc */
-#ifndef IPV6_XFRM_POLICY
-#define IPV6_XFRM_POLICY 34
-#endif /*IPV6_XFRM_POLICY*/
-
-/** default priority of installed policies */
-#define PRIO_LOW 3000
-#define PRIO_HIGH 2000
-
-/**
- * map the limit for bytes and packets to XFRM_INF per default
- */
-#define XFRM_LIMIT(x) ((x) == 0 ? XFRM_INF : (x))
-
-/**
- * Create ORable bitfield of XFRM NL groups
- */
-#define XFRMNLGRP(x) (1<<(XFRMNLGRP_##x-1))
-
-/**
- * returns a pointer to the first rtattr following the nlmsghdr *nlh and the
- * 'usual' netlink data x like 'struct xfrm_usersa_info'
- */
-#define XFRM_RTA(nlh, x) ((struct rtattr*)(NLMSG_DATA(nlh) + NLMSG_ALIGN(sizeof(x))))
-/**
- * returns a pointer to the next rtattr following rta.
- * !!! do not use this to parse messages. use RTA_NEXT and RTA_OK instead !!!
- */
-#define XFRM_RTA_NEXT(rta) ((struct rtattr*)(((char*)(rta)) + RTA_ALIGN((rta)->rta_len)))
-/**
- * returns the total size of attached rta data
- * (after 'usual' netlink data x like 'struct xfrm_usersa_info')
- */
-#define XFRM_PAYLOAD(nlh, x) NLMSG_PAYLOAD(nlh, sizeof(x))
-
-typedef struct kernel_algorithm_t kernel_algorithm_t;
-
-/**
- * Mapping of IKEv2 kernel identifier to linux crypto API names
- */
-struct kernel_algorithm_t {
-       /**
-        * Identifier specified in IKEv2
-        */
-       int ikev2;
-
-       /**
-        * Name of the algorithm in linux crypto API
-        */
-       char *name;
-};
-
-ENUM(xfrm_msg_names, XFRM_MSG_NEWSA, XFRM_MSG_MAPPING,
-       "XFRM_MSG_NEWSA",
-       "XFRM_MSG_DELSA",
-       "XFRM_MSG_GETSA",
-       "XFRM_MSG_NEWPOLICY",
-       "XFRM_MSG_DELPOLICY",
-       "XFRM_MSG_GETPOLICY",
-       "XFRM_MSG_ALLOCSPI",
-       "XFRM_MSG_ACQUIRE",
-       "XFRM_MSG_EXPIRE",
-       "XFRM_MSG_UPDPOLICY",
-       "XFRM_MSG_UPDSA",
-       "XFRM_MSG_POLEXPIRE",
-       "XFRM_MSG_FLUSHSA",
-       "XFRM_MSG_FLUSHPOLICY",
-       "XFRM_MSG_NEWAE",
-       "XFRM_MSG_GETAE",
-       "XFRM_MSG_REPORT",
-       "XFRM_MSG_MIGRATE",
-       "XFRM_MSG_NEWSADINFO",
-       "XFRM_MSG_GETSADINFO",
-       "XFRM_MSG_NEWSPDINFO",
-       "XFRM_MSG_GETSPDINFO",
-       "XFRM_MSG_MAPPING"
-);
-
-ENUM(xfrm_attr_type_names, XFRMA_UNSPEC, XFRMA_KMADDRESS,
-       "XFRMA_UNSPEC",
-       "XFRMA_ALG_AUTH",
-       "XFRMA_ALG_CRYPT",
-       "XFRMA_ALG_COMP",
-       "XFRMA_ENCAP",
-       "XFRMA_TMPL",
-       "XFRMA_SA",
-       "XFRMA_POLICY",
-       "XFRMA_SEC_CTX",
-       "XFRMA_LTIME_VAL",
-       "XFRMA_REPLAY_VAL",
-       "XFRMA_REPLAY_THRESH",
-       "XFRMA_ETIMER_THRESH",
-       "XFRMA_SRCADDR",
-       "XFRMA_COADDR",
-       "XFRMA_LASTUSED",
-       "XFRMA_POLICY_TYPE",
-       "XFRMA_MIGRATE",
-       "XFRMA_ALG_AEAD",
-       "XFRMA_KMADDRESS"
-);
-
-#define END_OF_LIST -1
-
-/**
- * Algorithms for encryption
- */
-static kernel_algorithm_t encryption_algs[] = {
-/*     {ENCR_DES_IV64,                         "***"                           }, */
-       {ENCR_DES,                                      "des"                           },
-       {ENCR_3DES,                                     "des3_ede"                      },
-/*     {ENCR_RC5,                                      "***"                           }, */
-/*     {ENCR_IDEA,                                     "***"                           }, */
-       {ENCR_CAST,                                     "cast128"                       },
-       {ENCR_BLOWFISH,                         "blowfish"                      },
-/*     {ENCR_3IDEA,                            "***"                           }, */
-/*     {ENCR_DES_IV32,                         "***"                           }, */
-       {ENCR_NULL,                                     "cipher_null"           },
-       {ENCR_AES_CBC,                          "aes"                           },
-       {ENCR_AES_CTR,                          "rfc3686(ctr(aes))"     },
-       {ENCR_AES_CCM_ICV8,                     "rfc4309(ccm(aes))"     },
-       {ENCR_AES_CCM_ICV12,            "rfc4309(ccm(aes))"     },
-       {ENCR_AES_CCM_ICV16,            "rfc4309(ccm(aes))"     },
-       {ENCR_AES_GCM_ICV8,                     "rfc4106(gcm(aes))"     },
-       {ENCR_AES_GCM_ICV12,            "rfc4106(gcm(aes))"     },
-       {ENCR_AES_GCM_ICV16,            "rfc4106(gcm(aes))"     },
-       {ENCR_NULL_AUTH_AES_GMAC,       "rfc4543(gcm(aes))"     },
-       {ENCR_CAMELLIA_CBC,                     "cbc(camellia)"         },
-/*     {ENCR_CAMELLIA_CTR,                     "***"                           }, */
-/*     {ENCR_CAMELLIA_CCM_ICV8,        "***"                           }, */
-/*     {ENCR_CAMELLIA_CCM_ICV12,       "***"                           }, */
-/*     {ENCR_CAMELLIA_CCM_ICV16,       "***"                           }, */
-       {END_OF_LIST,                           NULL                            }
-};
-
-/**
- * Algorithms for integrity protection
- */
-static kernel_algorithm_t integrity_algs[] = {
-       {AUTH_HMAC_MD5_96,                      "md5"                           },
-       {AUTH_HMAC_SHA1_96,                     "sha1"                          },
-       {AUTH_HMAC_SHA2_256_96,         "sha256"                        },
-       {AUTH_HMAC_SHA2_256_128,        "hmac(sha256)"          },
-       {AUTH_HMAC_SHA2_384_192,        "hmac(sha384)"          },
-       {AUTH_HMAC_SHA2_512_256,        "hmac(sha512)"          },
-/*     {AUTH_DES_MAC,                          "***"                           }, */
-/*     {AUTH_KPDK_MD5,                         "***"                           }, */
-       {AUTH_AES_XCBC_96,                      "xcbc(aes)"                     },
-       {END_OF_LIST,                           NULL                            }
-};
-
-/**
- * Algorithms for IPComp
- */
-static kernel_algorithm_t compression_algs[] = {
-/*     {IPCOMP_OUI,                            "***"                           }, */
-       {IPCOMP_DEFLATE,                        "deflate"                       },
-       {IPCOMP_LZS,                            "lzs"                           },
-       {IPCOMP_LZJH,                           "lzjh"                          },
-       {END_OF_LIST,                           NULL                            }
-};
-
-/**
- * Look up a kernel algorithm name and its key size
- */
-static char* lookup_algorithm(kernel_algorithm_t *list, int ikev2)
-{
-       while (list->ikev2 != END_OF_LIST)
-       {
-               if (list->ikev2 == ikev2)
-               {
-                       return list->name;
-               }
-               list++;
-       }
-       return NULL;
-}
-
-typedef struct route_entry_t route_entry_t;
-
-/**
- * installed routing entry
- */
-struct route_entry_t {
-       /** Name of the interface the route is bound to */
-       char *if_name;
-
-       /** Source ip of the route */
-       host_t *src_ip;
-
-       /** gateway for this route */
-       host_t *gateway;
-
-       /** Destination net */
-       chunk_t dst_net;
-
-       /** Destination net prefixlen */
-       u_int8_t prefixlen;
-};
-
-/**
- * destroy an route_entry_t object
- */
-static void route_entry_destroy(route_entry_t *this)
-{
-       free(this->if_name);
-       this->src_ip->destroy(this->src_ip);
-       DESTROY_IF(this->gateway);
-       chunk_free(&this->dst_net);
-       free(this);
-}
-
-typedef struct policy_entry_t policy_entry_t;
-
-/**
- * installed kernel policy.
- */
-struct policy_entry_t {
-
-       /** direction of this policy: in, out, forward */
-       u_int8_t direction;
-
-       /** parameters of installed policy */
-       struct xfrm_selector sel;
-
-       /** optional mark */
-       u_int32_t mark;
-
-       /** associated route installed for this policy */
-       route_entry_t *route;
-
-       /** by how many CHILD_SA's this policy is used */
-       u_int refcount;
-};
-
-/**
- * Hash function for policy_entry_t objects
- */
-static u_int policy_hash(policy_entry_t *key)
-{
-       chunk_t chunk = chunk_create((void*)&key->sel,
-                                                       sizeof(struct xfrm_selector) + sizeof(u_int32_t));
-       return chunk_hash(chunk);
-}
-
-/**
- * Equality function for policy_entry_t objects
- */
-static bool policy_equals(policy_entry_t *key, policy_entry_t *other_key)
-{
-       return memeq(&key->sel, &other_key->sel,
-                                sizeof(struct xfrm_selector) + sizeof(u_int32_t)) &&
-                  key->direction == other_key->direction;
-}
-
-typedef struct private_kernel_netlink_ipsec_t private_kernel_netlink_ipsec_t;
-
-/**
- * Private variables and functions of kernel_netlink class.
- */
-struct private_kernel_netlink_ipsec_t {
-       /**
-        * Public part of the kernel_netlink_t object.
-        */
-       kernel_netlink_ipsec_t public;
-
-       /**
-        * mutex to lock access to various lists
-        */
-       mutex_t *mutex;
-
-       /**
-        * Hash table of installed policies (policy_entry_t)
-        */
-       hashtable_t *policies;
-
-       /**
-        * job receiving netlink events
-        */
-       callback_job_t *job;
-
-       /**
-        * Netlink xfrm socket (IPsec)
-        */
-       netlink_socket_t *socket_xfrm;
-
-       /**
-        * netlink xfrm socket to receive acquire and expire events
-        */
-       int socket_xfrm_events;
-
-       /**
-        * whether to install routes along policies
-        */
-       bool install_routes;
-};
-
-/**
- * convert the general ipsec mode to the one defined in xfrm.h
- */
-static u_int8_t mode2kernel(ipsec_mode_t mode)
-{
-       switch (mode)
-       {
-               case MODE_TRANSPORT:
-                       return XFRM_MODE_TRANSPORT;
-               case MODE_TUNNEL:
-                       return XFRM_MODE_TUNNEL;
-               case MODE_BEET:
-                       return XFRM_MODE_BEET;
-               default:
-                       return mode;
-       }
-}
-
-/**
- * convert a host_t to a struct xfrm_address
- */
-static void host2xfrm(host_t *host, xfrm_address_t *xfrm)
-{
-       chunk_t chunk = host->get_address(host);
-       memcpy(xfrm, chunk.ptr, min(chunk.len, sizeof(xfrm_address_t)));
-}
-
-/**
- * convert a struct xfrm_address to a host_t
- */
-static host_t* xfrm2host(int family, xfrm_address_t *xfrm, u_int16_t port)
-{
-       chunk_t chunk;
-
-       switch (family)
-       {
-               case AF_INET:
-                       chunk = chunk_create((u_char*)&xfrm->a4, sizeof(xfrm->a4));
-                       break;
-               case AF_INET6:
-                       chunk = chunk_create((u_char*)&xfrm->a6, sizeof(xfrm->a6));
-                       break;
-               default:
-                       return NULL;
-       }
-       return host_create_from_chunk(family, chunk, ntohs(port));
-}
-
-/**
- * convert a traffic selector address range to subnet and its mask.
- */
-static void ts2subnet(traffic_selector_t* ts,
-                                         xfrm_address_t *net, u_int8_t *mask)
-{
-       host_t *net_host;
-       chunk_t net_chunk;
-
-       ts->to_subnet(ts, &net_host, mask);
-       net_chunk = net_host->get_address(net_host);
-       memcpy(net, net_chunk.ptr, net_chunk.len);
-       net_host->destroy(net_host);
-}
-
-/**
- * convert a traffic selector port range to port/portmask
- */
-static void ts2ports(traffic_selector_t* ts,
-                                        u_int16_t *port, u_int16_t *mask)
-{
-       /* linux does not seem to accept complex portmasks. Only
-        * any or a specific port is allowed. We set to any, if we have
-        * a port range, or to a specific, if we have one port only.
-        */
-       u_int16_t from, to;
-
-       from = ts->get_from_port(ts);
-       to = ts->get_to_port(ts);
-
-       if (from == to)
-       {
-               *port = htons(from);
-               *mask = ~0;
-       }
-       else
-       {
-               *port = 0;
-               *mask = 0;
-       }
-}
-
-/**
- * convert a pair of traffic_selectors to a xfrm_selector
- */
-static struct xfrm_selector ts2selector(traffic_selector_t *src,
-                                                                               traffic_selector_t *dst)
-{
-       struct xfrm_selector sel;
-
-       memset(&sel, 0, sizeof(sel));
-       sel.family = (src->get_type(src) == TS_IPV4_ADDR_RANGE) ? AF_INET : AF_INET6;
-       /* src or dest proto may be "any" (0), use more restrictive one */
-       sel.proto = max(src->get_protocol(src), dst->get_protocol(dst));
-       ts2subnet(dst, &sel.daddr, &sel.prefixlen_d);
-       ts2subnet(src, &sel.saddr, &sel.prefixlen_s);
-       ts2ports(dst, &sel.dport, &sel.dport_mask);
-       ts2ports(src, &sel.sport, &sel.sport_mask);
-       sel.ifindex = 0;
-       sel.user = 0;
-
-       return sel;
-}
-
-/**
- * convert a xfrm_selector to a src|dst traffic_selector
- */
-static traffic_selector_t* selector2ts(struct xfrm_selector *sel, bool src)
-{
-       u_char *addr;
-       u_int8_t prefixlen;
-       u_int16_t port = 0;
-       host_t *host = NULL;
-
-       if (src)
-       {
-               addr = (u_char*)&sel->saddr;
-               prefixlen = sel->prefixlen_s;
-               if (sel->sport_mask)
-               {
-                       port = htons(sel->sport);
-               }
-       }
-       else
-       {
-               addr = (u_char*)&sel->daddr;
-               prefixlen = sel->prefixlen_d;
-               if (sel->dport_mask)
-               {
-                       port = htons(sel->dport);
-               }
-       }
-
-       /* The Linux 2.6 kernel does not set the selector's family field,
-        * so as a kludge we additionally test the prefix length.
-        */
-       if (sel->family == AF_INET || sel->prefixlen_s == 32)
-       {
-               host = host_create_from_chunk(AF_INET, chunk_create(addr, 4), 0);
-       }
-       else if (sel->family == AF_INET6 || sel->prefixlen_s == 128)
-       {
-               host = host_create_from_chunk(AF_INET6, chunk_create(addr, 16), 0);
-       }
-
-       if (host)
-       {
-               return traffic_selector_create_from_subnet(host, prefixlen,
-                                                                                                  sel->proto, port);
-       }
-       return NULL;
-}
-
-/**
- * process a XFRM_MSG_ACQUIRE from kernel
- */
-static void process_acquire(private_kernel_netlink_ipsec_t *this, struct nlmsghdr *hdr)
-{
-       u_int32_t reqid = 0;
-       int proto = 0;
-       traffic_selector_t *src_ts, *dst_ts;
-       struct xfrm_user_acquire *acquire;
-       struct rtattr *rta;
-       size_t rtasize;
-
-       acquire = (struct xfrm_user_acquire*)NLMSG_DATA(hdr);
-       rta = XFRM_RTA(hdr, struct xfrm_user_acquire);
-       rtasize = XFRM_PAYLOAD(hdr, struct xfrm_user_acquire);
-
-       DBG2(DBG_KNL, "received a XFRM_MSG_ACQUIRE");
-
-       while (RTA_OK(rta, rtasize))
-       {
-               DBG2(DBG_KNL, "  %N", xfrm_attr_type_names, rta->rta_type);
-
-               if (rta->rta_type == XFRMA_TMPL)
-               {
-                       struct xfrm_user_tmpl* tmpl;
-
-                       tmpl = (struct xfrm_user_tmpl*)RTA_DATA(rta);
-                       reqid = tmpl->reqid;
-                       proto = tmpl->id.proto;
-               }
-               rta = RTA_NEXT(rta, rtasize);
-       }
-       switch (proto)
-       {
-               case 0:
-               case IPPROTO_ESP:
-               case IPPROTO_AH:
-                       break;
-               default:
-                       /* acquire for AH/ESP only, not for IPCOMP */
-                       return;
-       }
-       src_ts = selector2ts(&acquire->sel, TRUE);
-       dst_ts = selector2ts(&acquire->sel, FALSE);
-
-       hydra->kernel_interface->acquire(hydra->kernel_interface, reqid, src_ts,
-                                                                        dst_ts);
-}
-
-/**
- * process a XFRM_MSG_EXPIRE from kernel
- */
-static void process_expire(private_kernel_netlink_ipsec_t *this, struct nlmsghdr *hdr)
-{
-       u_int8_t protocol;
-       u_int32_t spi, reqid;
-       struct xfrm_user_expire *expire;
-
-       expire = (struct xfrm_user_expire*)NLMSG_DATA(hdr);
-       protocol = expire->state.id.proto;
-       spi = expire->state.id.spi;
-       reqid = expire->state.reqid;
-
-       DBG2(DBG_KNL, "received a XFRM_MSG_EXPIRE");
-
-       if (protocol != IPPROTO_ESP && protocol != IPPROTO_AH)
-       {
-               DBG2(DBG_KNL, "ignoring XFRM_MSG_EXPIRE for SA with SPI %.8x and "
-                                         "reqid {%u} which is not a CHILD_SA", ntohl(spi), reqid);
-               return;
-       }
-
-       hydra->kernel_interface->expire(hydra->kernel_interface, reqid, protocol,
-                                                                       spi, expire->hard != 0);
-}
-
-/**
- * process a XFRM_MSG_MIGRATE from kernel
- */
-static void process_migrate(private_kernel_netlink_ipsec_t *this, struct nlmsghdr *hdr)
-{
-       traffic_selector_t *src_ts, *dst_ts;
-       host_t *local = NULL, *remote = NULL;
-       host_t *old_src = NULL, *old_dst = NULL;
-       host_t *new_src = NULL, *new_dst = NULL;
-       struct xfrm_userpolicy_id *policy_id;
-       struct rtattr *rta;
-       size_t rtasize;
-       u_int32_t reqid = 0;
-       policy_dir_t dir;
-
-       policy_id = (struct xfrm_userpolicy_id*)NLMSG_DATA(hdr);
-       rta     = XFRM_RTA(hdr, struct xfrm_userpolicy_id);
-       rtasize = XFRM_PAYLOAD(hdr, struct xfrm_userpolicy_id);
-
-       DBG2(DBG_KNL, "received a XFRM_MSG_MIGRATE");
-
-       src_ts = selector2ts(&policy_id->sel, TRUE);
-       dst_ts = selector2ts(&policy_id->sel, FALSE);
-       dir = (policy_dir_t)policy_id->dir;
-
-       DBG2(DBG_KNL, "  policy: %R === %R %N", src_ts, dst_ts, policy_dir_names);
-
-       while (RTA_OK(rta, rtasize))
-       {
-               DBG2(DBG_KNL, "  %N", xfrm_attr_type_names, rta->rta_type);
-               if (rta->rta_type == XFRMA_KMADDRESS)
-               {
-                       struct xfrm_user_kmaddress *kmaddress;
-
-                       kmaddress = (struct xfrm_user_kmaddress*)RTA_DATA(rta);
-                       local  = xfrm2host(kmaddress->family, &kmaddress->local, 0);
-                       remote = xfrm2host(kmaddress->family, &kmaddress->remote, 0);
-                       DBG2(DBG_KNL, "  kmaddress: %H...%H", local, remote);
-               }
-               else if (rta->rta_type == XFRMA_MIGRATE)
-               {
-                       struct xfrm_user_migrate *migrate;
-
-                       migrate = (struct xfrm_user_migrate*)RTA_DATA(rta);
-                       old_src = xfrm2host(migrate->old_family, &migrate->old_saddr, 0);
-                       old_dst = xfrm2host(migrate->old_family, &migrate->old_daddr, 0);
-                       new_src = xfrm2host(migrate->new_family, &migrate->new_saddr, 0);
-                       new_dst = xfrm2host(migrate->new_family, &migrate->new_daddr, 0);
-                       reqid = migrate->reqid;
-                       DBG2(DBG_KNL, "  migrate %H...%H to %H...%H, reqid {%u}",
-                                                 old_src, old_dst, new_src, new_dst, reqid);
-                       DESTROY_IF(old_src);
-                       DESTROY_IF(old_dst);
-                       DESTROY_IF(new_src);
-                       DESTROY_IF(new_dst);
-               }
-               rta = RTA_NEXT(rta, rtasize);
-       }
-
-       if (src_ts && dst_ts && local && remote)
-       {
-               hydra->kernel_interface->migrate(hydra->kernel_interface, reqid,
-                                                                                src_ts, dst_ts, dir, local, remote);
-       }
-       else
-       {
-               DESTROY_IF(src_ts);
-               DESTROY_IF(dst_ts);
-               DESTROY_IF(local);
-               DESTROY_IF(remote);
-       }
-}
-
-/**
- * process a XFRM_MSG_MAPPING from kernel
- */
-static void process_mapping(private_kernel_netlink_ipsec_t *this,
-                                                       struct nlmsghdr *hdr)
-{
-       u_int32_t spi, reqid;
-       struct xfrm_user_mapping *mapping;
-       host_t *host;
-
-       mapping = (struct xfrm_user_mapping*)NLMSG_DATA(hdr);
-       spi = mapping->id.spi;
-       reqid = mapping->reqid;
-
-       DBG2(DBG_KNL, "received a XFRM_MSG_MAPPING");
-
-       if (mapping->id.proto == IPPROTO_ESP)
-       {
-               host = xfrm2host(mapping->id.family, &mapping->new_saddr,
-                                                mapping->new_sport);
-               if (host)
-               {
-                       hydra->kernel_interface->mapping(hydra->kernel_interface, reqid,
-                                                                                        spi, host);
-               }
-       }
-}
-
-/**
- * Receives events from kernel
- */
-static job_requeue_t receive_events(private_kernel_netlink_ipsec_t *this)
-{
-       char response[1024];
-       struct nlmsghdr *hdr = (struct nlmsghdr*)response;
-       struct sockaddr_nl addr;
-       socklen_t addr_len = sizeof(addr);
-       int len;
-       bool oldstate;
-
-       oldstate = thread_cancelability(TRUE);
-       len = recvfrom(this->socket_xfrm_events, response, sizeof(response), 0,
-                                  (struct sockaddr*)&addr, &addr_len);
-       thread_cancelability(oldstate);
-
-       if (len < 0)
-       {
-               switch (errno)
-               {
-                       case EINTR:
-                               /* interrupted, try again */
-                               return JOB_REQUEUE_DIRECT;
-                       case EAGAIN:
-                               /* no data ready, select again */
-                               return JOB_REQUEUE_DIRECT;
-                       default:
-                               DBG1(DBG_KNL, "unable to receive from xfrm event socket");
-                               sleep(1);
-                               return JOB_REQUEUE_FAIR;
-               }
-       }
-
-       if (addr.nl_pid != 0)
-       {       /* not from kernel. not interested, try another one */
-               return JOB_REQUEUE_DIRECT;
-       }
-
-       while (NLMSG_OK(hdr, len))
-       {
-               switch (hdr->nlmsg_type)
-               {
-                       case XFRM_MSG_ACQUIRE:
-                               process_acquire(this, hdr);
-                               break;
-                       case XFRM_MSG_EXPIRE:
-                               process_expire(this, hdr);
-                               break;
-                       case XFRM_MSG_MIGRATE:
-                               process_migrate(this, hdr);
-                               break;
-                       case XFRM_MSG_MAPPING:
-                               process_mapping(this, hdr);
-                               break;
-                       default:
-                               DBG1(DBG_KNL, "received unknown event from xfrm event socket: %d", hdr->nlmsg_type);
-                               break;
-               }
-               hdr = NLMSG_NEXT(hdr, len);
-       }
-       return JOB_REQUEUE_DIRECT;
-}
-
-/**
- * Get an SPI for a specific protocol from the kernel.
- */
-static status_t get_spi_internal(private_kernel_netlink_ipsec_t *this,
-               host_t *src, host_t *dst, u_int8_t proto, u_int32_t min, u_int32_t max,
-               u_int32_t reqid, u_int32_t *spi)
-{
-       netlink_buf_t request;
-       struct nlmsghdr *hdr, *out;
-       struct xfrm_userspi_info *userspi;
-       u_int32_t received_spi = 0;
-       size_t len;
-
-       memset(&request, 0, sizeof(request));
-
-       hdr = (struct nlmsghdr*)request;
-       hdr->nlmsg_flags = NLM_F_REQUEST;
-       hdr->nlmsg_type = XFRM_MSG_ALLOCSPI;
-       hdr->nlmsg_len = NLMSG_LENGTH(sizeof(struct xfrm_userspi_info));
-
-       userspi = (struct xfrm_userspi_info*)NLMSG_DATA(hdr);
-       host2xfrm(src, &userspi->info.saddr);
-       host2xfrm(dst, &userspi->info.id.daddr);
-       userspi->info.id.proto = proto;
-       userspi->info.mode = XFRM_MODE_TUNNEL;
-       userspi->info.reqid = reqid;
-       userspi->info.family = src->get_family(src);
-       userspi->min = min;
-       userspi->max = max;
-
-       if (this->socket_xfrm->send(this->socket_xfrm, hdr, &out, &len) == SUCCESS)
-       {
-               hdr = out;
-               while (NLMSG_OK(hdr, len))
-               {
-                       switch (hdr->nlmsg_type)
-                       {
-                               case XFRM_MSG_NEWSA:
-                               {
-                                       struct xfrm_usersa_info* usersa = NLMSG_DATA(hdr);
-                                       received_spi = usersa->id.spi;
-                                       break;
-                               }
-                               case NLMSG_ERROR:
-                               {
-                                       struct nlmsgerr *err = NLMSG_DATA(hdr);
-
-                                       DBG1(DBG_KNL, "allocating SPI failed: %s (%d)",
-                                                strerror(-err->error), -err->error);
-                                       break;
-                               }
-                               default:
-                                       hdr = NLMSG_NEXT(hdr, len);
-                                       continue;
-                               case NLMSG_DONE:
-                                       break;
-                       }
-                       break;
-               }
-               free(out);
-       }
-
-       if (received_spi == 0)
-       {
-               return FAILED;
-       }
-
-       *spi = received_spi;
-       return SUCCESS;
-}
-
-METHOD(kernel_ipsec_t, get_spi, status_t,
-       private_kernel_netlink_ipsec_t *this, host_t *src, host_t *dst,
-       u_int8_t protocol, u_int32_t reqid, u_int32_t *spi)
-{
-       DBG2(DBG_KNL, "getting SPI for reqid {%u}", reqid);
-
-       if (get_spi_internal(this, src, dst, protocol,
-                       0xc0000000, 0xcFFFFFFF, reqid, spi) != SUCCESS)
-       {
-               DBG1(DBG_KNL, "unable to get SPI for reqid {%u}", reqid);
-               return FAILED;
-       }
-
-       DBG2(DBG_KNL, "got SPI %.8x for reqid {%u}", ntohl(*spi), reqid);
-
-       return SUCCESS;
-}
-
-METHOD(kernel_ipsec_t, get_cpi, status_t,
-       private_kernel_netlink_ipsec_t *this, host_t *src, host_t *dst,
-       u_int32_t reqid, u_int16_t *cpi)
-{
-       u_int32_t received_spi = 0;
-
-       DBG2(DBG_KNL, "getting CPI for reqid {%u}", reqid);
-
-       if (get_spi_internal(this, src, dst,
-                       IPPROTO_COMP, 0x100, 0xEFFF, reqid, &received_spi) != SUCCESS)
-       {
-               DBG1(DBG_KNL, "unable to get CPI for reqid {%u}", reqid);
-               return FAILED;
-       }
-
-       *cpi = htons((u_int16_t)ntohl(received_spi));
-
-       DBG2(DBG_KNL, "got CPI %.4x for reqid {%u}", ntohs(*cpi), reqid);
-
-       return SUCCESS;
-}
-
-METHOD(kernel_ipsec_t, add_sa, status_t,
-       private_kernel_netlink_ipsec_t *this, host_t *src, host_t *dst,
-       u_int32_t spi, u_int8_t protocol, u_int32_t reqid, mark_t mark,
-       lifetime_cfg_t *lifetime, u_int16_t enc_alg, chunk_t enc_key,
-       u_int16_t int_alg, chunk_t int_key,     ipsec_mode_t mode, u_int16_t ipcomp,
-       u_int16_t cpi, bool encap, bool inbound,
-       traffic_selector_t* src_ts, traffic_selector_t* dst_ts)
-{
-       netlink_buf_t request;
-       char *alg_name;
-       struct nlmsghdr *hdr;
-       struct xfrm_usersa_info *sa;
-       u_int16_t icv_size = 64;
-
-       /* if IPComp is used, we install an additional IPComp SA. if the cpi is 0
-        * we are in the recursive call below */
-       if (ipcomp != IPCOMP_NONE && cpi != 0)
-       {
-               lifetime_cfg_t lft = {{0,0,0},{0,0,0},{0,0,0}};
-               add_sa(this, src, dst, htonl(ntohs(cpi)), IPPROTO_COMP, reqid, mark,
-                          &lft, ENCR_UNDEFINED, chunk_empty, AUTH_UNDEFINED, chunk_empty,
-                          mode, ipcomp, 0, FALSE, inbound, NULL, NULL);
-               ipcomp = IPCOMP_NONE;
-               /* use transport mode ESP SA, IPComp uses tunnel mode */
-               mode = MODE_TRANSPORT;
-       }
-
-       memset(&request, 0, sizeof(request));
-
-       if (mark.value)
-       {
-               DBG2(DBG_KNL, "adding SAD entry with SPI %.8x and reqid {%u}  "
-                                         "(mark %u/0x%8x)", ntohl(spi), reqid, mark.value, mark.mask);
-       }
-       else
-       {
-               DBG2(DBG_KNL, "adding SAD entry with SPI %.8x and reqid {%u}",
-                                          ntohl(spi), reqid);
-       }
-       hdr = (struct nlmsghdr*)request;
-       hdr->nlmsg_flags = NLM_F_REQUEST | NLM_F_ACK;
-       hdr->nlmsg_type = inbound ? XFRM_MSG_UPDSA : XFRM_MSG_NEWSA;
-       hdr->nlmsg_len = NLMSG_LENGTH(sizeof(struct xfrm_usersa_info));
-
-       sa = (struct xfrm_usersa_info*)NLMSG_DATA(hdr);
-       host2xfrm(src, &sa->saddr);
-       host2xfrm(dst, &sa->id.daddr);
-       sa->id.spi = spi;
-       sa->id.proto = protocol;
-       sa->family = src->get_family(src);
-       sa->mode = mode2kernel(mode);
-       switch (mode)
-       {
-               case MODE_TUNNEL:
-                       sa->flags |= XFRM_STATE_AF_UNSPEC;
-                       break;
-               case MODE_BEET:
-                       if(src_ts && dst_ts)
-                       {
-                               sa->sel = ts2selector(src_ts, dst_ts);
-                       }
-                       break;
-               default:
-                       break;
-       }
-
-       sa->replay_window = (protocol == IPPROTO_COMP) ? 0 : 32;
-       sa->reqid = reqid;
-       sa->lft.soft_byte_limit = XFRM_LIMIT(lifetime->bytes.rekey);
-       sa->lft.hard_byte_limit = XFRM_LIMIT(lifetime->bytes.life);
-       sa->lft.soft_packet_limit = XFRM_LIMIT(lifetime->packets.rekey);
-       sa->lft.hard_packet_limit = XFRM_LIMIT(lifetime->packets.life);
-       /* we use lifetimes since added, not since used */
-       sa->lft.soft_add_expires_seconds = lifetime->time.rekey;
-       sa->lft.hard_add_expires_seconds = lifetime->time.life;
-       sa->lft.soft_use_expires_seconds = 0;
-       sa->lft.hard_use_expires_seconds = 0;
-
-       struct rtattr *rthdr = XFRM_RTA(hdr, struct xfrm_usersa_info);
-
-       switch (enc_alg)
-       {
-               case ENCR_UNDEFINED:
-                       /* no encryption */
-                       break;
-               case ENCR_AES_CCM_ICV16:
-               case ENCR_AES_GCM_ICV16:
-               case ENCR_NULL_AUTH_AES_GMAC:
-               case ENCR_CAMELLIA_CCM_ICV16:
-                       icv_size += 32;
-                       /* FALL */
-               case ENCR_AES_CCM_ICV12:
-               case ENCR_AES_GCM_ICV12:
-               case ENCR_CAMELLIA_CCM_ICV12:
-                       icv_size += 32;
-                       /* FALL */
-               case ENCR_AES_CCM_ICV8:
-               case ENCR_AES_GCM_ICV8:
-               case ENCR_CAMELLIA_CCM_ICV8:
-               {
-                       struct xfrm_algo_aead *algo;
-
-                       alg_name = lookup_algorithm(encryption_algs, enc_alg);
-                       if (alg_name == NULL)
-                       {
-                               DBG1(DBG_KNL, "algorithm %N not supported by kernel!",
-                                        encryption_algorithm_names, enc_alg);
-                               return FAILED;
-                       }
-                       DBG2(DBG_KNL, "  using encryption algorithm %N with key size %d",
-                                encryption_algorithm_names, enc_alg, enc_key.len * 8);
-
-                       rthdr->rta_type = XFRMA_ALG_AEAD;
-                       rthdr->rta_len = RTA_LENGTH(sizeof(struct xfrm_algo_aead) + enc_key.len);
-                       hdr->nlmsg_len += rthdr->rta_len;
-                       if (hdr->nlmsg_len > sizeof(request))
-                       {
-                               return FAILED;
-                       }
-
-                       algo = (struct xfrm_algo_aead*)RTA_DATA(rthdr);
-                       algo->alg_key_len = enc_key.len * 8;
-                       algo->alg_icv_len = icv_size;
-                       strcpy(algo->alg_name, alg_name);
-                       memcpy(algo->alg_key, enc_key.ptr, enc_key.len);
-
-                       rthdr = XFRM_RTA_NEXT(rthdr);
-                       break;
-               }
-               default:
-               {
-                       struct xfrm_algo *algo;
-
-                       alg_name = lookup_algorithm(encryption_algs, enc_alg);
-                       if (alg_name == NULL)
-                       {
-                               DBG1(DBG_KNL, "algorithm %N not supported by kernel!",
-                                        encryption_algorithm_names, enc_alg);
-                               return FAILED;
-                       }
-                       DBG2(DBG_KNL, "  using encryption algorithm %N with key size %d",
-                                encryption_algorithm_names, enc_alg, enc_key.len * 8);
-
-                       rthdr->rta_type = XFRMA_ALG_CRYPT;
-                       rthdr->rta_len = RTA_LENGTH(sizeof(struct xfrm_algo) + enc_key.len);
-                       hdr->nlmsg_len += rthdr->rta_len;
-                       if (hdr->nlmsg_len > sizeof(request))
-                       {
-                               return FAILED;
-                       }
-
-                       algo = (struct xfrm_algo*)RTA_DATA(rthdr);
-                       algo->alg_key_len = enc_key.len * 8;
-                       strcpy(algo->alg_name, alg_name);
-                       memcpy(algo->alg_key, enc_key.ptr, enc_key.len);
-
-                       rthdr = XFRM_RTA_NEXT(rthdr);
-               }
-       }
-
-       if (int_alg  != AUTH_UNDEFINED)
-       {
-               alg_name = lookup_algorithm(integrity_algs, int_alg);
-               if (alg_name == NULL)
-               {
-                       DBG1(DBG_KNL, "algorithm %N not supported by kernel!",
-                                integrity_algorithm_names, int_alg);
-                       return FAILED;
-               }
-               DBG2(DBG_KNL, "  using integrity algorithm %N with key size %d",
-                        integrity_algorithm_names, int_alg, int_key.len * 8);
-
-               if (int_alg == AUTH_HMAC_SHA2_256_128)
-               {
-                       struct xfrm_algo_auth* algo;
-
-                       /* the kernel uses SHA256 with 96 bit truncation by default,
-                        * use specified truncation size supported by newer kernels */
-                       rthdr->rta_type = XFRMA_ALG_AUTH_TRUNC;
-                       rthdr->rta_len = RTA_LENGTH(sizeof(struct xfrm_algo_auth) + int_key.len);
-
-                       hdr->nlmsg_len += rthdr->rta_len;
-                       if (hdr->nlmsg_len > sizeof(request))
-                       {
-                               return FAILED;
-                       }
-
-                       algo = (struct xfrm_algo_auth*)RTA_DATA(rthdr);
-                       algo->alg_key_len = int_key.len * 8;
-                       algo->alg_trunc_len = 128;
-                       strcpy(algo->alg_name, alg_name);
-                       memcpy(algo->alg_key, int_key.ptr, int_key.len);
-               }
-               else
-               {
-                       struct xfrm_algo* algo;
-
-                       rthdr->rta_type = XFRMA_ALG_AUTH;
-                       rthdr->rta_len = RTA_LENGTH(sizeof(struct xfrm_algo) + int_key.len);
-
-                       hdr->nlmsg_len += rthdr->rta_len;
-                       if (hdr->nlmsg_len > sizeof(request))
-                       {
-                               return FAILED;
-                       }
-
-                       algo = (struct xfrm_algo*)RTA_DATA(rthdr);
-                       algo->alg_key_len = int_key.len * 8;
-                       strcpy(algo->alg_name, alg_name);
-                       memcpy(algo->alg_key, int_key.ptr, int_key.len);
-               }
-               rthdr = XFRM_RTA_NEXT(rthdr);
-       }
-
-       if (ipcomp != IPCOMP_NONE)
-       {
-               rthdr->rta_type = XFRMA_ALG_COMP;
-               alg_name = lookup_algorithm(compression_algs, ipcomp);
-               if (alg_name == NULL)
-               {
-                       DBG1(DBG_KNL, "algorithm %N not supported by kernel!",
-                                ipcomp_transform_names, ipcomp);
-                       return FAILED;
-               }
-               DBG2(DBG_KNL, "  using compression algorithm %N",
-                        ipcomp_transform_names, ipcomp);
-
-               rthdr->rta_len = RTA_LENGTH(sizeof(struct xfrm_algo));
-               hdr->nlmsg_len += rthdr->rta_len;
-               if (hdr->nlmsg_len > sizeof(request))
-               {
-                       return FAILED;
-               }
-
-               struct xfrm_algo* algo = (struct xfrm_algo*)RTA_DATA(rthdr);
-               algo->alg_key_len = 0;
-               strcpy(algo->alg_name, alg_name);
-
-               rthdr = XFRM_RTA_NEXT(rthdr);
-       }
-
-       if (encap)
-       {
-               struct xfrm_encap_tmpl *tmpl;
-
-               rthdr->rta_type = XFRMA_ENCAP;
-               rthdr->rta_len = RTA_LENGTH(sizeof(struct xfrm_encap_tmpl));
-
-               hdr->nlmsg_len += rthdr->rta_len;
-               if (hdr->nlmsg_len > sizeof(request))
-               {
-                       return FAILED;
-               }
-
-               tmpl = (struct xfrm_encap_tmpl*)RTA_DATA(rthdr);
-               tmpl->encap_type = UDP_ENCAP_ESPINUDP;
-               tmpl->encap_sport = htons(src->get_port(src));
-               tmpl->encap_dport = htons(dst->get_port(dst));
-               memset(&tmpl->encap_oa, 0, sizeof (xfrm_address_t));
-               /* encap_oa could probably be derived from the
-                * traffic selectors [rfc4306, p39]. In the netlink kernel implementation
-                * pluto does the same as we do here but it uses encap_oa in the
-                * pfkey implementation. BUT as /usr/src/linux/net/key/af_key.c indicates
-                * the kernel ignores it anyway
-                *   -> does that mean that NAT-T encap doesn't work in transport mode?
-                * No. The reason the kernel ignores NAT-OA is that it recomputes
-                * (or, rather, just ignores) the checksum. If packets pass
-                * the IPsec checks it marks them "checksum ok" so OA isn't needed. */
-               rthdr = XFRM_RTA_NEXT(rthdr);
-       }
-
-       if (mark.value)
-       {
-               struct xfrm_mark *mrk;
-
-               rthdr->rta_type = XFRMA_MARK;
-               rthdr->rta_len = RTA_LENGTH(sizeof(struct xfrm_mark));
-
-               hdr->nlmsg_len += rthdr->rta_len;
-               if (hdr->nlmsg_len > sizeof(request))
-               {
-                       return FAILED;
-               }
-
-               mrk = (struct xfrm_mark*)RTA_DATA(rthdr);
-               mrk->v = mark.value;
-               mrk->m = mark.mask;
-               rthdr = XFRM_RTA_NEXT(rthdr);
-       }
-
-       if (this->socket_xfrm->send_ack(this->socket_xfrm, hdr) != SUCCESS)
-       {
-               if (mark.value)
-               {
-                       DBG1(DBG_KNL, "unable to add SAD entry with SPI %.8x  "
-                                                 "(mark %u/0x%8x)", ntohl(spi), mark.value, mark.mask);
-               }
-               else
-               {
-                       DBG1(DBG_KNL, "unable to add SAD entry with SPI %.8x", ntohl(spi));
-               }
-               return FAILED;
-       }
-       return SUCCESS;
-}
-
-/**
- * Get the replay state (i.e. sequence numbers) of an SA.
- */
-static status_t get_replay_state(private_kernel_netlink_ipsec_t *this,
-                                                 u_int32_t spi, u_int8_t protocol, host_t *dst,
-                                                 struct xfrm_replay_state *replay)
-{
-       netlink_buf_t request;
-       struct nlmsghdr *hdr, *out = NULL;
-       struct xfrm_aevent_id *out_aevent = NULL, *aevent_id;
-       size_t len;
-       struct rtattr *rta;
-       size_t rtasize;
-
-       memset(&request, 0, sizeof(request));
-
-       DBG2(DBG_KNL, "querying replay state from SAD entry with SPI %.8x", ntohl(spi));
-
-       hdr = (struct nlmsghdr*)request;
-       hdr->nlmsg_flags = NLM_F_REQUEST;
-       hdr->nlmsg_type = XFRM_MSG_GETAE;
-       hdr->nlmsg_len = NLMSG_LENGTH(sizeof(struct xfrm_aevent_id));
-
-       aevent_id = (struct xfrm_aevent_id*)NLMSG_DATA(hdr);
-       aevent_id->flags = XFRM_AE_RVAL;
-
-       host2xfrm(dst, &aevent_id->sa_id.daddr);
-       aevent_id->sa_id.spi = spi;
-       aevent_id->sa_id.proto = protocol;
-       aevent_id->sa_id.family = dst->get_family(dst);
-
-       if (this->socket_xfrm->send(this->socket_xfrm, hdr, &out, &len) == SUCCESS)
-       {
-               hdr = out;
-               while (NLMSG_OK(hdr, len))
-               {
-                       switch (hdr->nlmsg_type)
-                       {
-                               case XFRM_MSG_NEWAE:
-                               {
-                                       out_aevent = NLMSG_DATA(hdr);
-                                       break;
-                               }
-                               case NLMSG_ERROR:
-                               {
-                                       struct nlmsgerr *err = NLMSG_DATA(hdr);
-                                       DBG1(DBG_KNL, "querying replay state from SAD entry failed: %s (%d)",
-                                                strerror(-err->error), -err->error);
-                                       break;
-                               }
-                               default:
-                                       hdr = NLMSG_NEXT(hdr, len);
-                                       continue;
-                               case NLMSG_DONE:
-                                       break;
-                       }
-                       break;
-               }
-       }
-
-       if (out_aevent == NULL)
-       {
-               DBG1(DBG_KNL, "unable to query replay state from SAD entry with SPI %.8x",
-                                         ntohl(spi));
-               free(out);
-               return FAILED;
-       }
-
-       rta = XFRM_RTA(out, struct xfrm_aevent_id);
-       rtasize = XFRM_PAYLOAD(out, struct xfrm_aevent_id);
-       while(RTA_OK(rta, rtasize))
-       {
-               if (rta->rta_type == XFRMA_REPLAY_VAL &&
-                       RTA_PAYLOAD(rta) == sizeof(struct xfrm_replay_state))
-               {
-                       memcpy(replay, RTA_DATA(rta), RTA_PAYLOAD(rta));
-                       free(out);
-                       return SUCCESS;
-               }
-               rta = RTA_NEXT(rta, rtasize);
-       }
-
-       DBG1(DBG_KNL, "unable to query replay state from SAD entry with SPI %.8x",
-                                 ntohl(spi));
-       free(out);
-       return FAILED;
-}
-
-METHOD(kernel_ipsec_t, query_sa, status_t,
-       private_kernel_netlink_ipsec_t *this, host_t *src, host_t *dst,
-       u_int32_t spi, u_int8_t protocol, mark_t mark, u_int64_t *bytes)
-{
-       netlink_buf_t request;
-       struct nlmsghdr *out = NULL, *hdr;
-       struct xfrm_usersa_id *sa_id;
-       struct xfrm_usersa_info *sa = NULL;
-       size_t len;
-
-       memset(&request, 0, sizeof(request));
-
-       if (mark.value)
-       {
-               DBG2(DBG_KNL, "querying SAD entry with SPI %.8x  (mark %u/0x%8x)",
-                                          ntohl(spi), mark.value, mark.mask);
-       }
-       else
-       {
-               DBG2(DBG_KNL, "querying SAD entry with SPI %.8x", ntohl(spi));
-       }
-       hdr = (struct nlmsghdr*)request;
-       hdr->nlmsg_flags = NLM_F_REQUEST;
-       hdr->nlmsg_type = XFRM_MSG_GETSA;
-       hdr->nlmsg_len = NLMSG_LENGTH(sizeof(struct xfrm_usersa_id));
-
-       sa_id = (struct xfrm_usersa_id*)NLMSG_DATA(hdr);
-       host2xfrm(dst, &sa_id->daddr);
-       sa_id->spi = spi;
-       sa_id->proto = protocol;
-       sa_id->family = dst->get_family(dst);
-
-       if (mark.value)
-       {
-               struct xfrm_mark *mrk;
-               struct rtattr *rthdr = XFRM_RTA(hdr, struct xfrm_usersa_id);
-
-               rthdr->rta_type = XFRMA_MARK;
-               rthdr->rta_len = RTA_LENGTH(sizeof(struct xfrm_mark));
-               hdr->nlmsg_len += rthdr->rta_len;
-               if (hdr->nlmsg_len > sizeof(request))
-               {
-                       return FAILED;
-               }
-
-               mrk = (struct xfrm_mark*)RTA_DATA(rthdr);
-               mrk->v = mark.value;
-               mrk->m = mark.mask;
-       }
-
-       if (this->socket_xfrm->send(this->socket_xfrm, hdr, &out, &len) == SUCCESS)
-       {
-               hdr = out;
-               while (NLMSG_OK(hdr, len))
-               {
-                       switch (hdr->nlmsg_type)
-                       {
-                               case XFRM_MSG_NEWSA:
-                               {
-                                       sa = (struct xfrm_usersa_info*)NLMSG_DATA(hdr);
-                                       break;
-                               }
-                               case NLMSG_ERROR:
-                               {
-                                       struct nlmsgerr *err = NLMSG_DATA(hdr);
-
-                                       if (mark.value)
-                                       {
-                                               DBG1(DBG_KNL, "querying SAD entry with SPI %.8x  "
-                                                                         "(mark %u/0x%8x) failed: %s (%d)",
-                                                                          ntohl(spi), mark.value, mark.mask,
-                                                                          strerror(-err->error), -err->error);
-                                       }
-                                       else
-                                       {
-                                               DBG1(DBG_KNL, "querying SAD entry with SPI %.8x "
-                                                                         "failed: %s (%d)", ntohl(spi),
-                                                                          strerror(-err->error), -err->error);
-                                       }
-                                       break;
-                               }
-                               default:
-                                       hdr = NLMSG_NEXT(hdr, len);
-                                       continue;
-                               case NLMSG_DONE:
-                                       break;
-                       }
-                       break;
-               }
-       }
-
-       if (sa == NULL)
-       {
-               DBG2(DBG_KNL, "unable to query SAD entry with SPI %.8x", ntohl(spi));
-               free(out);
-               return FAILED;
-       }
-       *bytes = sa->curlft.bytes;
-
-       free(out);
-       return SUCCESS;
-}
-
-METHOD(kernel_ipsec_t, del_sa, status_t,
-       private_kernel_netlink_ipsec_t *this, host_t *src, host_t *dst,
-       u_int32_t spi, u_int8_t protocol, u_int16_t cpi, mark_t mark)
-{
-       netlink_buf_t request;
-       struct nlmsghdr *hdr;
-       struct xfrm_usersa_id *sa_id;
-
-       /* if IPComp was used, we first delete the additional IPComp SA */
-       if (cpi)
-       {
-               del_sa(this, src, dst, htonl(ntohs(cpi)), IPPROTO_COMP, 0, mark);
-       }
-
-       memset(&request, 0, sizeof(request));
-
-       if (mark.value)
-       {
-               DBG2(DBG_KNL, "deleting SAD entry with SPI %.8x  (mark %u/0x%8x)",
-                                          ntohl(spi), mark.value, mark.mask);
-       }
-       else
-       {
-               DBG2(DBG_KNL, "deleting SAD entry with SPI %.8x", ntohl(spi));
-       }
-       hdr = (struct nlmsghdr*)request;
-       hdr->nlmsg_flags = NLM_F_REQUEST | NLM_F_ACK;
-       hdr->nlmsg_type = XFRM_MSG_DELSA;
-       hdr->nlmsg_len = NLMSG_LENGTH(sizeof(struct xfrm_usersa_id));
-
-       sa_id = (struct xfrm_usersa_id*)NLMSG_DATA(hdr);
-       host2xfrm(dst, &sa_id->daddr);
-       sa_id->spi = spi;
-       sa_id->proto = protocol;
-       sa_id->family = dst->get_family(dst);
-
-       if (mark.value)
-       {
-               struct xfrm_mark *mrk;
-               struct rtattr *rthdr = XFRM_RTA(hdr, struct xfrm_usersa_id);
-
-               rthdr->rta_type = XFRMA_MARK;
-               rthdr->rta_len = RTA_LENGTH(sizeof(struct xfrm_mark));
-               hdr->nlmsg_len += rthdr->rta_len;
-               if (hdr->nlmsg_len > sizeof(request))
-               {
-                       return FAILED;
-               }
-
-               mrk = (struct xfrm_mark*)RTA_DATA(rthdr);
-               mrk->v = mark.value;
-               mrk->m = mark.mask;
-       }
-
-       if (this->socket_xfrm->send_ack(this->socket_xfrm, hdr) != SUCCESS)
-       {
-               if (mark.value)
-               {
-                       DBG1(DBG_KNL, "unable to delete SAD entry with SPI %.8x  "
-                                                 "(mark %u/0x%8x)", ntohl(spi), mark.value, mark.mask);
-               }
-               else
-               {
-                       DBG1(DBG_KNL, "unable to delete SAD entry with SPI %.8x", ntohl(spi));
-               }
-               return FAILED;
-       }
-       if (mark.value)
-       {
-               DBG2(DBG_KNL, "deleted SAD entry with SPI %.8x  (mark %u/0x%8x)",
-                                          ntohl(spi), mark.value, mark.mask);
-       }
-       else
-       {
-               DBG2(DBG_KNL, "deleted SAD entry with SPI %.8x", ntohl(spi));
-       }
-       return SUCCESS;
-}
-
-METHOD(kernel_ipsec_t, update_sa, status_t,
-       private_kernel_netlink_ipsec_t *this, u_int32_t spi, u_int8_t protocol,
-       u_int16_t cpi, host_t *src, host_t *dst, host_t *new_src, host_t *new_dst,
-       bool old_encap, bool new_encap, mark_t mark)
-{
-       netlink_buf_t request;
-       u_char *pos;
-       struct nlmsghdr *hdr, *out = NULL;
-       struct xfrm_usersa_id *sa_id;
-       struct xfrm_usersa_info *out_sa = NULL, *sa;
-       size_t len;
-       struct rtattr *rta;
-       size_t rtasize;
-       struct xfrm_encap_tmpl* tmpl = NULL;
-       bool got_replay_state = FALSE;
-       struct xfrm_replay_state replay;
-
-       /* if IPComp is used, we first update the IPComp SA */
-       if (cpi)
-       {
-               update_sa(this, htonl(ntohs(cpi)), IPPROTO_COMP, 0,
-                                 src, dst, new_src, new_dst, FALSE, FALSE, mark);
-       }
-
-       memset(&request, 0, sizeof(request));
-
-       DBG2(DBG_KNL, "querying SAD entry with SPI %.8x for update", ntohl(spi));
-
-       /* query the existing SA first */
-       hdr = (struct nlmsghdr*)request;
-       hdr->nlmsg_flags = NLM_F_REQUEST;
-       hdr->nlmsg_type = XFRM_MSG_GETSA;
-       hdr->nlmsg_len = NLMSG_LENGTH(sizeof(struct xfrm_usersa_id));
-
-       sa_id = (struct xfrm_usersa_id*)NLMSG_DATA(hdr);
-       host2xfrm(dst, &sa_id->daddr);
-       sa_id->spi = spi;
-       sa_id->proto = protocol;
-       sa_id->family = dst->get_family(dst);
-
-       if (this->socket_xfrm->send(this->socket_xfrm, hdr, &out, &len) == SUCCESS)
-       {
-               hdr = out;
-               while (NLMSG_OK(hdr, len))
-               {
-                       switch (hdr->nlmsg_type)
-                       {
-                               case XFRM_MSG_NEWSA:
-                               {
-                                       out_sa = NLMSG_DATA(hdr);
-                                       break;
-                               }
-                               case NLMSG_ERROR:
-                               {
-                                       struct nlmsgerr *err = NLMSG_DATA(hdr);
-                                       DBG1(DBG_KNL, "querying SAD entry failed: %s (%d)",
-                                                strerror(-err->error), -err->error);
-                                       break;
-                               }
-                               default:
-                                       hdr = NLMSG_NEXT(hdr, len);
-                                       continue;
-                               case NLMSG_DONE:
-                                       break;
-                       }
-                       break;
-               }
-       }
-       if (out_sa == NULL)
-       {
-               DBG1(DBG_KNL, "unable to update SAD entry with SPI %.8x", ntohl(spi));
-               free(out);
-               return FAILED;
-       }
-
-       /* try to get the replay state */
-       if (get_replay_state(this, spi, protocol, dst, &replay) == SUCCESS)
-       {
-               got_replay_state = TRUE;
-       }
-
-       /* delete the old SA (without affecting the IPComp SA) */
-       if (del_sa(this, src, dst, spi, protocol, 0, mark) != SUCCESS)
-       {
-               DBG1(DBG_KNL, "unable to delete old SAD entry with SPI %.8x", ntohl(spi));
-               free(out);
-               return FAILED;
-       }
-
-       DBG2(DBG_KNL, "updating SAD entry with SPI %.8x from %#H..%#H to %#H..%#H",
-                ntohl(spi), src, dst, new_src, new_dst);
-       /* copy over the SA from out to request */
-       hdr = (struct nlmsghdr*)request;
-       memcpy(hdr, out, min(out->nlmsg_len, sizeof(request)));
-       hdr->nlmsg_flags = NLM_F_REQUEST | NLM_F_ACK;
-       hdr->nlmsg_type = XFRM_MSG_NEWSA;
-       hdr->nlmsg_len = NLMSG_LENGTH(sizeof(struct xfrm_usersa_info));
-       sa = NLMSG_DATA(hdr);
-       sa->family = new_dst->get_family(new_dst);
-
-       if (!src->ip_equals(src, new_src))
-       {
-               host2xfrm(new_src, &sa->saddr);
-       }
-       if (!dst->ip_equals(dst, new_dst))
-       {
-               host2xfrm(new_dst, &sa->id.daddr);
-       }
-
-       rta = XFRM_RTA(out, struct xfrm_usersa_info);
-       rtasize = XFRM_PAYLOAD(out, struct xfrm_usersa_info);
-       pos = (u_char*)XFRM_RTA(hdr, struct xfrm_usersa_info);
-       while(RTA_OK(rta, rtasize))
-       {
-               /* copy all attributes, but not XFRMA_ENCAP if we are disabling it */
-               if (rta->rta_type != XFRMA_ENCAP || new_encap)
-               {
-                       if (rta->rta_type == XFRMA_ENCAP)
-                       {       /* update encap tmpl */
-                               tmpl = (struct xfrm_encap_tmpl*)RTA_DATA(rta);
-                               tmpl->encap_sport = ntohs(new_src->get_port(new_src));
-                               tmpl->encap_dport = ntohs(new_dst->get_port(new_dst));
-                       }
-                       memcpy(pos, rta, rta->rta_len);
-                       pos += RTA_ALIGN(rta->rta_len);
-                       hdr->nlmsg_len += RTA_ALIGN(rta->rta_len);
-               }
-               rta = RTA_NEXT(rta, rtasize);
-       }
-
-       rta = (struct rtattr*)pos;
-       if (tmpl == NULL && new_encap)
-       {       /* add tmpl if we are enabling it */
-               rta->rta_type = XFRMA_ENCAP;
-               rta->rta_len = RTA_LENGTH(sizeof(struct xfrm_encap_tmpl));
-
-               hdr->nlmsg_len += rta->rta_len;
-               if (hdr->nlmsg_len > sizeof(request))
-               {
-                       return FAILED;
-               }
-
-               tmpl = (struct xfrm_encap_tmpl*)RTA_DATA(rta);
-               tmpl->encap_type = UDP_ENCAP_ESPINUDP;
-               tmpl->encap_sport = ntohs(new_src->get_port(new_src));
-               tmpl->encap_dport = ntohs(new_dst->get_port(new_dst));
-               memset(&tmpl->encap_oa, 0, sizeof (xfrm_address_t));
-
-               rta = XFRM_RTA_NEXT(rta);
-       }
-
-       if (got_replay_state)
-       {       /* copy the replay data if available */
-               rta->rta_type = XFRMA_REPLAY_VAL;
-               rta->rta_len = RTA_LENGTH(sizeof(struct xfrm_replay_state));
-
-               hdr->nlmsg_len += rta->rta_len;
-               if (hdr->nlmsg_len > sizeof(request))
-               {
-                       return FAILED;
-               }
-               memcpy(RTA_DATA(rta), &replay, sizeof(replay));
-
-               rta = XFRM_RTA_NEXT(rta);
-       }
-
-       if (this->socket_xfrm->send_ack(this->socket_xfrm, hdr) != SUCCESS)
-       {
-               DBG1(DBG_KNL, "unable to update SAD entry with SPI %.8x", ntohl(spi));
-               free(out);
-               return FAILED;
-       }
-       free(out);
-
-       return SUCCESS;
-}
-
-METHOD(kernel_ipsec_t, add_policy, status_t,
-       private_kernel_netlink_ipsec_t *this, host_t *src, host_t *dst,
-       traffic_selector_t *src_ts, traffic_selector_t *dst_ts,
-       policy_dir_t direction, u_int32_t spi, u_int8_t protocol,
-       u_int32_t reqid, mark_t mark, ipsec_mode_t mode, u_int16_t ipcomp,
-       u_int16_t cpi, bool routed)
-{
-       policy_entry_t *current, *policy;
-       bool found = FALSE;
-       netlink_buf_t request;
-       struct xfrm_userpolicy_info *policy_info;
-       struct nlmsghdr *hdr;
-
-       /* create a policy */
-       policy = malloc_thing(policy_entry_t);
-       memset(policy, 0, sizeof(policy_entry_t));
-       policy->sel = ts2selector(src_ts, dst_ts);
-       policy->mark = mark.value & mark.mask;
-       policy->direction = direction;
-
-       /* find the policy, which matches EXACTLY */
-       this->mutex->lock(this->mutex);
-       current = this->policies->get(this->policies, policy);
-       if (current)
-       {
-               /* use existing policy */
-               current->refcount++;
-               if (mark.value)
-               {
-                       DBG2(DBG_KNL, "policy %R === %R %N  (mark %u/0x%8x) "
-                                                 "already exists, increasing refcount",
-                                                  src_ts, dst_ts, policy_dir_names, direction,
-                                                  mark.value, mark.mask);
-               }
-               else
-               {
-                       DBG2(DBG_KNL, "policy %R === %R %N "
-                                                 "already exists, increasing refcount",
-                                                  src_ts, dst_ts, policy_dir_names, direction);
-               }
-               free(policy);
-               policy = current;
-               found = TRUE;
-       }
-       else
-       {       /* apply the new one, if we have no such policy */
-               this->policies->put(this->policies, policy, policy);
-               policy->refcount = 1;
-       }
-
-       if (mark.value)
-       {
-               DBG2(DBG_KNL, "adding policy %R === %R %N  (mark %u/0x%8x)",
-                                          src_ts, dst_ts, policy_dir_names, direction,
-                                          mark.value, mark.mask);
-       }
-       else
-       {
-               DBG2(DBG_KNL, "adding policy %R === %R %N",
-                                          src_ts, dst_ts, policy_dir_names, direction);
-       }
-
-       memset(&request, 0, sizeof(request));
-       hdr = (struct nlmsghdr*)request;
-       hdr->nlmsg_flags = NLM_F_REQUEST | NLM_F_ACK;
-       hdr->nlmsg_type = found ? XFRM_MSG_UPDPOLICY : XFRM_MSG_NEWPOLICY;
-       hdr->nlmsg_len = NLMSG_LENGTH(sizeof(struct xfrm_userpolicy_info));
-
-       policy_info = (struct xfrm_userpolicy_info*)NLMSG_DATA(hdr);
-       policy_info->sel = policy->sel;
-       policy_info->dir = policy->direction;
-       /* calculate priority based on source selector size, small size = high prio */
-       policy_info->priority = routed ? PRIO_LOW : PRIO_HIGH;
-       policy_info->priority -= policy->sel.prefixlen_s * 10;
-       policy_info->priority -= policy->sel.proto ? 2 : 0;
-       policy_info->priority -= policy->sel.sport_mask ? 1 : 0;
-       policy_info->action = XFRM_POLICY_ALLOW;
-       policy_info->share = XFRM_SHARE_ANY;
-       this->mutex->unlock(this->mutex);
-
-       /* policies don't expire */
-       policy_info->lft.soft_byte_limit = XFRM_INF;
-       policy_info->lft.soft_packet_limit = XFRM_INF;
-       policy_info->lft.hard_byte_limit = XFRM_INF;
-       policy_info->lft.hard_packet_limit = XFRM_INF;
-       policy_info->lft.soft_add_expires_seconds = 0;
-       policy_info->lft.hard_add_expires_seconds = 0;
-       policy_info->lft.soft_use_expires_seconds = 0;
-       policy_info->lft.hard_use_expires_seconds = 0;
-
-       struct rtattr *rthdr = XFRM_RTA(hdr, struct xfrm_userpolicy_info);
-       rthdr->rta_type = XFRMA_TMPL;
-       rthdr->rta_len = RTA_LENGTH(sizeof(struct xfrm_user_tmpl));
-
-       hdr->nlmsg_len += rthdr->rta_len;
-       if (hdr->nlmsg_len > sizeof(request))
-       {
-               return FAILED;
-       }
-
-       struct xfrm_user_tmpl *tmpl = (struct xfrm_user_tmpl*)RTA_DATA(rthdr);
-
-       if (ipcomp != IPCOMP_NONE)
-       {
-               tmpl->reqid = reqid;
-               tmpl->id.proto = IPPROTO_COMP;
-               tmpl->aalgos = tmpl->ealgos = tmpl->calgos = ~0;
-               tmpl->mode = mode2kernel(mode);
-               tmpl->optional = direction != POLICY_OUT;
-               tmpl->family = src->get_family(src);
-
-               host2xfrm(src, &tmpl->saddr);
-               host2xfrm(dst, &tmpl->id.daddr);
-
-               /* add an additional xfrm_user_tmpl */
-               rthdr->rta_len += RTA_LENGTH(sizeof(struct xfrm_user_tmpl));
-               hdr->nlmsg_len += RTA_LENGTH(sizeof(struct xfrm_user_tmpl));
-               if (hdr->nlmsg_len > sizeof(request))
-               {
-                       return FAILED;
-               }
-
-               tmpl++;
-
-               /* use transport mode for ESP if we have a tunnel mode IPcomp SA */
-               mode = MODE_TRANSPORT;
-       }
-       else
-       {
-               /* when using IPcomp, only the IPcomp SA uses tmp src/dst addresses */
-               host2xfrm(src, &tmpl->saddr);
-               host2xfrm(dst, &tmpl->id.daddr);
-       }
-
-       tmpl->reqid = reqid;
-       tmpl->id.proto = protocol;
-       tmpl->aalgos = tmpl->ealgos = tmpl->calgos = ~0;
-       tmpl->mode = mode2kernel(mode);
-       tmpl->family = src->get_family(src);
-       rthdr = XFRM_RTA_NEXT(rthdr);
-
-       if (mark.value)
-       {
-               struct xfrm_mark *mrk;
-
-               rthdr->rta_type = XFRMA_MARK;
-               rthdr->rta_len = RTA_LENGTH(sizeof(struct xfrm_mark));
-
-               hdr->nlmsg_len += rthdr->rta_len;
-               if (hdr->nlmsg_len > sizeof(request))
-               {
-                       return FAILED;
-               }
-
-               mrk = (struct xfrm_mark*)RTA_DATA(rthdr);
-               mrk->v = mark.value;
-               mrk->m = mark.mask;
-       }
-
-       if (this->socket_xfrm->send_ack(this->socket_xfrm, hdr) != SUCCESS)
-       {
-               DBG1(DBG_KNL, "unable to add policy %R === %R %N", src_ts, dst_ts,
-                                          policy_dir_names, direction);
-               return FAILED;
-       }
-
-       /* install a route, if:
-        * - we are NOT updating a policy
-        * - this is a forward policy (to just get one for each child)
-        * - we are in tunnel/BEET mode
-        * - routing is not disabled via strongswan.conf
-        */
-       if (policy->route == NULL && direction == POLICY_FWD &&
-               mode != MODE_TRANSPORT && this->install_routes)
-       {
-               route_entry_t *route = malloc_thing(route_entry_t);
-
-               if (hydra->kernel_interface->get_address_by_ts(hydra->kernel_interface,
-                               dst_ts, &route->src_ip) == SUCCESS)
-               {
-                       /* get the nexthop to src (src as we are in POLICY_FWD).*/
-                       route->gateway = hydra->kernel_interface->get_nexthop(
-                                                                                               hydra->kernel_interface, src);
-                       /* install route via outgoing interface */
-                       route->if_name = hydra->kernel_interface->get_interface(
-                                                                                               hydra->kernel_interface, dst);
-                       route->dst_net = chunk_alloc(policy->sel.family == AF_INET ? 4 : 16);
-                       memcpy(route->dst_net.ptr, &policy->sel.saddr, route->dst_net.len);
-                       route->prefixlen = policy->sel.prefixlen_s;
-
-                       if (route->if_name)
-                       {
-                               switch (hydra->kernel_interface->add_route(
-                                                                       hydra->kernel_interface, route->dst_net,
-                                                                       route->prefixlen, route->gateway,
-                                                                       route->src_ip, route->if_name))
-                               {
-                                       default:
-                                               DBG1(DBG_KNL, "unable to install source route for %H",
-                                                        route->src_ip);
-                                               /* FALL */
-                                       case ALREADY_DONE:
-                                               /* route exists, do not uninstall */
-                                               route_entry_destroy(route);
-                                               break;
-                                       case SUCCESS:
-                                               /* cache the installed route */
-                                               policy->route = route;
-                                               break;
-                               }
-                       }
-                       else
-                       {
-                               route_entry_destroy(route);
-                       }
-               }
-               else
-               {
-                       free(route);
-               }
-       }
-       return SUCCESS;
-}
-
-METHOD(kernel_ipsec_t, query_policy, status_t,
-       private_kernel_netlink_ipsec_t *this, traffic_selector_t *src_ts,
-       traffic_selector_t *dst_ts, policy_dir_t direction, mark_t mark,
-       u_int32_t *use_time)
-{
-       netlink_buf_t request;
-       struct nlmsghdr *out = NULL, *hdr;
-       struct xfrm_userpolicy_id *policy_id;
-       struct xfrm_userpolicy_info *policy = NULL;
-       size_t len;
-
-       memset(&request, 0, sizeof(request));
-
-       if (mark.value)
-       {
-               DBG2(DBG_KNL, "querying policy %R === %R %N  (mark %u/0x%8x)",
-                                          src_ts, dst_ts, policy_dir_names, direction,
-                                          mark.value, mark.mask);
-       }
-       else
-       {
-               DBG2(DBG_KNL, "querying policy %R === %R %N", src_ts, dst_ts,
-                                          policy_dir_names, direction);
-       }
-       hdr = (struct nlmsghdr*)request;
-       hdr->nlmsg_flags = NLM_F_REQUEST;
-       hdr->nlmsg_type = XFRM_MSG_GETPOLICY;
-       hdr->nlmsg_len = NLMSG_LENGTH(sizeof(struct xfrm_userpolicy_id));
-
-       policy_id = (struct xfrm_userpolicy_id*)NLMSG_DATA(hdr);
-       policy_id->sel = ts2selector(src_ts, dst_ts);
-       policy_id->dir = direction;
-
-       if (mark.value)
-       {
-               struct xfrm_mark *mrk;
-               struct rtattr *rthdr = XFRM_RTA(hdr, struct xfrm_userpolicy_id);
-
-               rthdr->rta_type = XFRMA_MARK;
-               rthdr->rta_len = RTA_LENGTH(sizeof(struct xfrm_mark));
-
-               hdr->nlmsg_len += rthdr->rta_len;
-               if (hdr->nlmsg_len > sizeof(request))
-               {
-                       return FAILED;
-               }
-
-               mrk = (struct xfrm_mark*)RTA_DATA(rthdr);
-               mrk->v = mark.value;
-               mrk->m = mark.mask;
-       }
-
-       if (this->socket_xfrm->send(this->socket_xfrm, hdr, &out, &len) == SUCCESS)
-       {
-               hdr = out;
-               while (NLMSG_OK(hdr, len))
-               {
-                       switch (hdr->nlmsg_type)
-                       {
-                               case XFRM_MSG_NEWPOLICY:
-                               {
-                                       policy = (struct xfrm_userpolicy_info*)NLMSG_DATA(hdr);
-                                       break;
-                               }
-                               case NLMSG_ERROR:
-                               {
-                                       struct nlmsgerr *err = NLMSG_DATA(hdr);
-                                       DBG1(DBG_KNL, "querying policy failed: %s (%d)",
-                                                strerror(-err->error), -err->error);
-                                       break;
-                               }
-                               default:
-                                       hdr = NLMSG_NEXT(hdr, len);
-                                       continue;
-                               case NLMSG_DONE:
-                                       break;
-                       }
-                       break;
-               }
-       }
-
-       if (policy == NULL)
-       {
-               DBG2(DBG_KNL, "unable to query policy %R === %R %N", src_ts, dst_ts,
-                                          policy_dir_names, direction);
-               free(out);
-               return FAILED;
-       }
-
-       if (policy->curlft.use_time)
-       {
-               /* we need the monotonic time, but the kernel returns system time. */
-               *use_time = time_monotonic(NULL) - (time(NULL) - policy->curlft.use_time);
-       }
-       else
-       {
-               *use_time = 0;
-       }
-
-       free(out);
-       return SUCCESS;
-}
-
-METHOD(kernel_ipsec_t, del_policy, status_t,
-       private_kernel_netlink_ipsec_t *this, traffic_selector_t *src_ts,
-       traffic_selector_t *dst_ts, policy_dir_t direction,     mark_t mark,
-       bool unrouted)
-{
-       policy_entry_t *current, policy, *to_delete = NULL;
-       route_entry_t *route;
-       netlink_buf_t request;
-       struct nlmsghdr *hdr;
-       struct xfrm_userpolicy_id *policy_id;
-
-       if (mark.value)
-       {
-               DBG2(DBG_KNL, "deleting policy %R === %R %N  (mark %u/0x%8x)",
-                                          src_ts, dst_ts, policy_dir_names, direction,
-                                          mark.value, mark.mask);
-       }
-       else
-       {
-               DBG2(DBG_KNL, "deleting policy %R === %R %N",
-                                          src_ts, dst_ts, policy_dir_names, direction);
-       }
-
-       /* create a policy */
-       memset(&policy, 0, sizeof(policy_entry_t));
-       policy.sel = ts2selector(src_ts, dst_ts);
-       policy.mark = mark.value & mark.mask;
-       policy.direction = direction;
-
-       /* find the policy */
-       this->mutex->lock(this->mutex);
-       current = this->policies->get(this->policies, &policy);
-       if (current)
-       {
-               to_delete = current;
-               if (--to_delete->refcount > 0)
-               {
-                       /* is used by more SAs, keep in kernel */
-                       DBG2(DBG_KNL, "policy still used by another CHILD_SA, not removed");
-                       this->mutex->unlock(this->mutex);
-                       return SUCCESS;
-               }
-               /* remove if last reference */
-               this->policies->remove(this->policies, to_delete);
-       }
-       this->mutex->unlock(this->mutex);
-       if (!to_delete)
-       {
-               if (mark.value)
-               {
-                       DBG1(DBG_KNL, "deleting policy %R === %R %N  (mark %u/0x%8x) "
-                                                 "failed, not found", src_ts, dst_ts, policy_dir_names,
-                                                  direction, mark.value, mark.mask);
-               }
-               else
-               {
-                       DBG1(DBG_KNL, "deleting policy %R === %R %N failed, not found",
-                                                  src_ts, dst_ts, policy_dir_names, direction);
-               }
-               return NOT_FOUND;
-       }
-
-       memset(&request, 0, sizeof(request));
-
-       hdr = (struct nlmsghdr*)request;
-       hdr->nlmsg_flags = NLM_F_REQUEST | NLM_F_ACK;
-       hdr->nlmsg_type = XFRM_MSG_DELPOLICY;
-       hdr->nlmsg_len = NLMSG_LENGTH(sizeof(struct xfrm_userpolicy_id));
-
-       policy_id = (struct xfrm_userpolicy_id*)NLMSG_DATA(hdr);
-       policy_id->sel = to_delete->sel;
-       policy_id->dir = direction;
-
-       if (mark.value)
-       {
-               struct xfrm_mark *mrk;
-               struct rtattr *rthdr = XFRM_RTA(hdr, struct xfrm_userpolicy_id);
-
-               rthdr->rta_type = XFRMA_MARK;
-               rthdr->rta_len = RTA_LENGTH(sizeof(struct xfrm_mark));
-               hdr->nlmsg_len += rthdr->rta_len;
-               if (hdr->nlmsg_len > sizeof(request))
-               {
-                       return FAILED;
-               }
-
-               mrk = (struct xfrm_mark*)RTA_DATA(rthdr);
-               mrk->v = mark.value;
-               mrk->m = mark.mask;
-       }
-
-       route = to_delete->route;
-       free(to_delete);
-
-       if (this->socket_xfrm->send_ack(this->socket_xfrm, hdr) != SUCCESS)
-       {
-               if (mark.value)
-               {
-                       DBG1(DBG_KNL, "unable to delete policy %R === %R %N  "
-                          "(mark %u/0x%8x)", src_ts, dst_ts, policy_dir_names,
-                                                  direction, mark.value, mark.mask);
-               }
-               else
-               {
-                       DBG1(DBG_KNL, "unable to delete policy %R === %R %N",
-                                                  src_ts, dst_ts, policy_dir_names, direction);
-               }
-               return FAILED;
-       }
-
-       if (route)
-       {
-               if (hydra->kernel_interface->del_route(hydra->kernel_interface,
-                               route->dst_net, route->prefixlen, route->gateway,
-                               route->src_ip, route->if_name) != SUCCESS)
-               {
-                       DBG1(DBG_KNL, "error uninstalling route installed with "
-                                                 "policy %R === %R %N", src_ts, dst_ts,
-                                                  policy_dir_names, direction);
-               }
-               route_entry_destroy(route);
-       }
-       return SUCCESS;
-}
-
-METHOD(kernel_ipsec_t, bypass_socket, bool,
-       private_kernel_netlink_ipsec_t *this, int fd, int family)
-{
-       struct xfrm_userpolicy_info policy;
-       u_int sol, ipsec_policy;
-
-       switch (family)
-       {
-               case AF_INET:
-                       sol = SOL_IP;
-                       ipsec_policy = IP_XFRM_POLICY;
-                       break;
-               case AF_INET6:
-                       sol = SOL_IPV6;
-                       ipsec_policy = IPV6_XFRM_POLICY;
-                       break;
-               default:
-                       return FALSE;
-       }
-
-       memset(&policy, 0, sizeof(policy));
-       policy.action = XFRM_POLICY_ALLOW;
-       policy.sel.family = family;
-
-       policy.dir = XFRM_POLICY_OUT;
-       if (setsockopt(fd, sol, ipsec_policy, &policy, sizeof(policy)) < 0)
-       {
-               DBG1(DBG_KNL, "unable to set IPSEC_POLICY on socket: %s",
-                        strerror(errno));
-               return FALSE;
-       }
-       policy.dir = XFRM_POLICY_IN;
-       if (setsockopt(fd, sol, ipsec_policy, &policy, sizeof(policy)) < 0)
-       {
-               DBG1(DBG_KNL, "unable to set IPSEC_POLICY on socket: %s",
-                        strerror(errno));
-               return FALSE;
-       }
-       return TRUE;
-}
-
-METHOD(kernel_ipsec_t, destroy, void,
-       private_kernel_netlink_ipsec_t *this)
-{
-       enumerator_t *enumerator;
-       policy_entry_t *policy;
-
-       if (this->job)
-       {
-               this->job->cancel(this->job);
-       }
-       if (this->socket_xfrm_events > 0)
-       {
-               close(this->socket_xfrm_events);
-       }
-       DESTROY_IF(this->socket_xfrm);
-       enumerator = this->policies->create_enumerator(this->policies);
-       while (enumerator->enumerate(enumerator, &policy, &policy))
-       {
-               free(policy);
-       }
-       enumerator->destroy(enumerator);
-       this->policies->destroy(this->policies);
-       this->mutex->destroy(this->mutex);
-       free(this);
-}
-
-/*
- * Described in header.
- */
-kernel_netlink_ipsec_t *kernel_netlink_ipsec_create()
-{
-       private_kernel_netlink_ipsec_t *this;
-       struct sockaddr_nl addr;
-       int fd;
-
-       INIT(this,
-               .public = {
-                       .interface = {
-                               .get_spi = _get_spi,
-                               .get_cpi = _get_cpi,
-                               .add_sa  = _add_sa,
-                               .update_sa = _update_sa,
-                               .query_sa = _query_sa,
-                               .del_sa = _del_sa,
-                               .add_policy = _add_policy,
-                               .query_policy = _query_policy,
-                               .del_policy = _del_policy,
-                               .bypass_socket = _bypass_socket,
-                               .destroy = _destroy,
-                       },
-               },
-               .policies = hashtable_create((hashtable_hash_t)policy_hash,
-                                                                        (hashtable_equals_t)policy_equals, 32),
-               .mutex = mutex_create(MUTEX_TYPE_DEFAULT),
-               .install_routes = lib->settings->get_bool(lib->settings,
-                                                                                               "charon.install_routes", TRUE),
-       );
-
-       /* disable lifetimes for allocated SPIs in kernel */
-       fd = open("/proc/sys/net/core/xfrm_acq_expires", O_WRONLY);
-       if (fd)
-       {
-               ignore_result(write(fd, "165", 3));
-               close(fd);
-       }
-
-       this->socket_xfrm = netlink_socket_create(NETLINK_XFRM);
-       if (!this->socket_xfrm)
-       {
-               destroy(this);
-               return NULL;
-       }
-
-       memset(&addr, 0, sizeof(addr));
-       addr.nl_family = AF_NETLINK;
-
-       /* create and bind XFRM socket for ACQUIRE, EXPIRE, MIGRATE & MAPPING */
-       this->socket_xfrm_events = socket(AF_NETLINK, SOCK_RAW, NETLINK_XFRM);
-       if (this->socket_xfrm_events <= 0)
-       {
-               DBG1(DBG_KNL, "unable to create XFRM event socket");
-               destroy(this);
-               return NULL;
-       }
-       addr.nl_groups = XFRMNLGRP(ACQUIRE) | XFRMNLGRP(EXPIRE) |
-                                        XFRMNLGRP(MIGRATE) | XFRMNLGRP(MAPPING);
-       if (bind(this->socket_xfrm_events, (struct sockaddr*)&addr, sizeof(addr)))
-       {
-               DBG1(DBG_KNL, "unable to bind XFRM event socket");
-               destroy(this);
-               return NULL;
-       }
-       this->job = callback_job_create((callback_job_cb_t)receive_events,
-                                                                       this, NULL, NULL);
-       hydra->processor->queue_job(hydra->processor, (job_t*)this->job);
-
-       return &this->public;
-}
-
diff --git a/src/libcharon/plugins/kernel_netlink/kernel_netlink_ipsec.h b/src/libcharon/plugins/kernel_netlink/kernel_netlink_ipsec.h
deleted file mode 100644 (file)
index 3a45cce..0000000
+++ /dev/null
@@ -1,46 +0,0 @@
-/*
- * Copyright (C) 2008 Tobias Brunner
- * Hochschule fuer Technik Rapperswil
- *
- * This program is free software; you can redistribute it and/or modify it
- * under the terms of the GNU General Public License as published by the
- * Free Software Foundation; either version 2 of the License, or (at your
- * option) any later version.  See <http://www.fsf.org/copyleft/gpl.txt>.
- *
- * This program is distributed in the hope that it will be useful, but
- * WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY
- * or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License
- * for more details.
- */
-
-/**
- * @defgroup kernel_netlink_ipsec_i kernel_netlink_ipsec
- * @{ @ingroup kernel_netlink
- */
-
-#ifndef KERNEL_NETLINK_IPSEC_H_
-#define KERNEL_NETLINK_IPSEC_H_
-
-#include <kernel/kernel_ipsec.h>
-
-typedef struct kernel_netlink_ipsec_t kernel_netlink_ipsec_t;
-
-/**
- * Implementation of the kernel ipsec interface using Netlink.
- */
-struct kernel_netlink_ipsec_t {
-
-       /**
-        * Implements kernel_ipsec_t interface
-        */
-       kernel_ipsec_t interface;
-};
-
-/**
- * Create a netlink kernel ipsec interface instance.
- *
- * @return                     kernel_netlink_ipsec_t instance
- */
-kernel_netlink_ipsec_t *kernel_netlink_ipsec_create();
-
-#endif /** KERNEL_NETLINK_IPSEC_H_ @}*/
diff --git a/src/libcharon/plugins/kernel_netlink/kernel_netlink_net.c b/src/libcharon/plugins/kernel_netlink/kernel_netlink_net.c
deleted file mode 100644 (file)
index 0beb32d..0000000
+++ /dev/null
@@ -1,1519 +0,0 @@
-/*
- * Copyright (C) 2008 Tobias Brunner
- * Copyright (C) 2005-2008 Martin Willi
- * Hochschule fuer Technik Rapperswil
- *
- * This program is free software; you can redistribute it and/or modify it
- * under the terms of the GNU General Public License as published by the
- * Free Software Foundation; either version 2 of the License, or (at your
- * option) any later version.  See <http://www.fsf.org/copyleft/gpl.txt>.
- *
- * This program is distributed in the hope that it will be useful, but
- * WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY
- * or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License
- * for more details.
- */
-
-/*
- * Copyright (C) 2010 secunet Security Networks AG
- * Copyright (C) 2010 Thomas Egerer
- *
- * Permission is hereby granted, free of charge, to any person obtaining a copy
- * of this software and associated documentation files (the "Software"), to deal
- * in the Software without restriction, including without limitation the rights
- * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
- * copies of the Software, and to permit persons to whom the Software is
- * furnished to do so, subject to the following conditions:
- *
- * The above copyright notice and this permission notice shall be included in
- * all copies or substantial portions of the Software.
- *
- * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
- * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
- * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
- * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
- * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
- * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
- * THE SOFTWARE.
- */
-
-#include <sys/socket.h>
-#include <linux/netlink.h>
-#include <linux/rtnetlink.h>
-#include <unistd.h>
-#include <errno.h>
-#include <net/if.h>
-
-#include "kernel_netlink_net.h"
-#include "kernel_netlink_shared.h"
-
-#include <hydra.h>
-#include <daemon.h>
-#include <threading/thread.h>
-#include <threading/condvar.h>
-#include <threading/mutex.h>
-#include <utils/linked_list.h>
-#include <processing/jobs/callback_job.h>
-
-/** delay before firing roam events (ms) */
-#define ROAM_DELAY 100
-
-typedef struct addr_entry_t addr_entry_t;
-
-/**
- * IP address in an inface_entry_t
- */
-struct addr_entry_t {
-
-       /** The ip address */
-       host_t *ip;
-
-       /** virtual IP managed by us */
-       bool virtual;
-
-       /** scope of the address */
-       u_char scope;
-
-       /** Number of times this IP is used, if virtual */
-       u_int refcount;
-};
-
-/**
- * destroy a addr_entry_t object
- */
-static void addr_entry_destroy(addr_entry_t *this)
-{
-       this->ip->destroy(this->ip);
-       free(this);
-}
-
-typedef struct iface_entry_t iface_entry_t;
-
-/**
- * A network interface on this system, containing addr_entry_t's
- */
-struct iface_entry_t {
-
-       /** interface index */
-       int ifindex;
-
-       /** name of the interface */
-       char ifname[IFNAMSIZ];
-
-       /** interface flags, as in netdevice(7) SIOCGIFFLAGS */
-       u_int flags;
-
-       /** list of addresses as host_t */
-       linked_list_t *addrs;
-};
-
-/**
- * destroy an interface entry
- */
-static void iface_entry_destroy(iface_entry_t *this)
-{
-       this->addrs->destroy_function(this->addrs, (void*)addr_entry_destroy);
-       free(this);
-}
-
-typedef struct private_kernel_netlink_net_t private_kernel_netlink_net_t;
-
-/**
- * Private variables and functions of kernel_netlink_net class.
- */
-struct private_kernel_netlink_net_t {
-       /**
-        * Public part of the kernel_netlink_net_t object.
-        */
-       kernel_netlink_net_t public;
-
-       /**
-        * mutex to lock access to various lists
-        */
-       mutex_t *mutex;
-
-       /**
-        * condition variable to signal virtual IP add/removal
-        */
-       condvar_t *condvar;
-
-       /**
-        * Cached list of interfaces and its addresses (iface_entry_t)
-        */
-       linked_list_t *ifaces;
-
-       /**
-        * job receiving netlink events
-        */
-       callback_job_t *job;
-
-       /**
-        * netlink rt socket (routing)
-        */
-       netlink_socket_t *socket;
-
-       /**
-        * Netlink rt socket to receive address change events
-        */
-       int socket_events;
-
-       /**
-        * time of the last roam event
-        */
-       timeval_t last_roam;
-
-       /**
-        * routing table to install routes
-        */
-       int routing_table;
-
-       /**
-        * priority of used routing table
-        */
-       int routing_table_prio;
-
-       /**
-        * whether to react to RTM_NEWROUTE or RTM_DELROUTE events
-        */
-       bool process_route;
-
-       /**
-        * whether to actually install virtual IPs
-        */
-       bool install_virtual_ip;
-
-       /**
-        * list with routing tables to be excluded from route lookup
-        */
-       linked_list_t *rt_exclude;
-};
-
-/**
- * get the refcount of a virtual ip
- */
-static int get_vip_refcount(private_kernel_netlink_net_t *this, host_t* ip)
-{
-       iterator_t *ifaces, *addrs;
-       iface_entry_t *iface;
-       addr_entry_t *addr;
-       int refcount = 0;
-
-       ifaces = this->ifaces->create_iterator(this->ifaces, TRUE);
-       while (ifaces->iterate(ifaces, (void**)&iface))
-       {
-               addrs = iface->addrs->create_iterator(iface->addrs, TRUE);
-               while (addrs->iterate(addrs, (void**)&addr))
-               {
-                       if (addr->virtual && (iface->flags & IFF_UP) &&
-                               ip->ip_equals(ip, addr->ip))
-                       {
-                               refcount = addr->refcount;
-                               break;
-                       }
-               }
-               addrs->destroy(addrs);
-               if (refcount)
-               {
-                       break;
-               }
-       }
-       ifaces->destroy(ifaces);
-
-       return refcount;
-}
-
-/**
- * callback function that raises the delayed roam event
- */
-static job_requeue_t roam_event(uintptr_t address)
-{
-       hydra->kernel_interface->roam(hydra->kernel_interface, address != 0);
-       return JOB_REQUEUE_NONE;
-}
-
-/**
- * fire a roaming event. we delay it for a bit and fire only one event
- * for multiple calls. otherwise we would create too many events.
- */
-static void fire_roam_event(private_kernel_netlink_net_t *this, bool address)
-{
-       timeval_t now;
-       job_t *job;
-
-       time_monotonic(&now);
-       if (timercmp(&now, &this->last_roam, >))
-       {
-               now.tv_usec += ROAM_DELAY * 1000;
-               while (now.tv_usec > 1000000)
-               {
-                       now.tv_sec++;
-                       now.tv_usec -= 1000000;
-               }
-               this->last_roam = now;
-
-               job = (job_t*)callback_job_create((callback_job_cb_t)roam_event,
-                                                                                 (void*)(uintptr_t)(address ? 1 : 0),
-                                                                                 NULL, NULL);
-               hydra->scheduler->schedule_job_ms(hydra->scheduler, job, ROAM_DELAY);
-       }
-}
-
-/**
- * process RTM_NEWLINK/RTM_DELLINK from kernel
- */
-static void process_link(private_kernel_netlink_net_t *this,
-                                                struct nlmsghdr *hdr, bool event)
-{
-       struct ifinfomsg* msg = (struct ifinfomsg*)(NLMSG_DATA(hdr));
-       struct rtattr *rta = IFLA_RTA(msg);
-       size_t rtasize = IFLA_PAYLOAD (hdr);
-       enumerator_t *enumerator;
-       iface_entry_t *current, *entry = NULL;
-       char *name = NULL;
-       bool update = FALSE;
-
-       while(RTA_OK(rta, rtasize))
-       {
-               switch (rta->rta_type)
-               {
-                       case IFLA_IFNAME:
-                               name = RTA_DATA(rta);
-                               break;
-               }
-               rta = RTA_NEXT(rta, rtasize);
-       }
-       if (!name)
-       {
-               name = "(unknown)";
-       }
-
-       this->mutex->lock(this->mutex);
-       switch (hdr->nlmsg_type)
-       {
-               case RTM_NEWLINK:
-               {
-                       if (msg->ifi_flags & IFF_LOOPBACK)
-                       {       /* ignore loopback interfaces */
-                               break;
-                       }
-                       enumerator = this->ifaces->create_enumerator(this->ifaces);
-                       while (enumerator->enumerate(enumerator, &current))
-                       {
-                               if (current->ifindex == msg->ifi_index)
-                               {
-                                       entry = current;
-                                       break;
-                               }
-                       }
-                       enumerator->destroy(enumerator);
-                       if (!entry)
-                       {
-                               entry = malloc_thing(iface_entry_t);
-                               entry->ifindex = msg->ifi_index;
-                               entry->flags = 0;
-                               entry->addrs = linked_list_create();
-                               this->ifaces->insert_last(this->ifaces, entry);
-                       }
-                       memcpy(entry->ifname, name, IFNAMSIZ);
-                       entry->ifname[IFNAMSIZ-1] = '\0';
-                       if (event)
-                       {
-                               if (!(entry->flags & IFF_UP) && (msg->ifi_flags & IFF_UP))
-                               {
-                                       update = TRUE;
-                                       DBG1(DBG_KNL, "interface %s activated", name);
-                               }
-                               if ((entry->flags & IFF_UP) && !(msg->ifi_flags & IFF_UP))
-                               {
-                                       update = TRUE;
-                                       DBG1(DBG_KNL, "interface %s deactivated", name);
-                               }
-                       }
-                       entry->flags = msg->ifi_flags;
-                       break;
-               }
-               case RTM_DELLINK:
-               {
-                       enumerator = this->ifaces->create_enumerator(this->ifaces);
-                       while (enumerator->enumerate(enumerator, &current))
-                       {
-                               if (current->ifindex == msg->ifi_index)
-                               {
-                                       /* we do not remove it, as an address may be added to a
-                                        * "down" interface and we wan't to know that. */
-                                       current->flags = msg->ifi_flags;
-                                       break;
-                               }
-                       }
-                       enumerator->destroy(enumerator);
-                       break;
-               }
-       }
-       this->mutex->unlock(this->mutex);
-
-       /* send an update to all IKE_SAs */
-       if (update && event)
-       {
-               fire_roam_event(this, TRUE);
-       }
-}
-
-/**
- * process RTM_NEWADDR/RTM_DELADDR from kernel
- */
-static void process_addr(private_kernel_netlink_net_t *this,
-                                                struct nlmsghdr *hdr, bool event)
-{
-       struct ifaddrmsg* msg = (struct ifaddrmsg*)(NLMSG_DATA(hdr));
-       struct rtattr *rta = IFA_RTA(msg);
-       size_t rtasize = IFA_PAYLOAD (hdr);
-       host_t *host = NULL;
-       enumerator_t *ifaces, *addrs;
-       iface_entry_t *iface;
-       addr_entry_t *addr;
-       chunk_t local = chunk_empty, address = chunk_empty;
-       bool update = FALSE, found = FALSE, changed = FALSE;
-
-       while(RTA_OK(rta, rtasize))
-       {
-               switch (rta->rta_type)
-               {
-                       case IFA_LOCAL:
-                               local.ptr = RTA_DATA(rta);
-                               local.len = RTA_PAYLOAD(rta);
-                               break;
-                       case IFA_ADDRESS:
-                               address.ptr = RTA_DATA(rta);
-                               address.len = RTA_PAYLOAD(rta);
-                               break;
-               }
-               rta = RTA_NEXT(rta, rtasize);
-       }
-
-       /* For PPP interfaces, we need the IFA_LOCAL address,
-        * IFA_ADDRESS is the peers address. But IFA_LOCAL is
-        * not included in all cases (IPv6?), so fallback to IFA_ADDRESS. */
-       if (local.ptr)
-       {
-               host = host_create_from_chunk(msg->ifa_family, local, 0);
-       }
-       else if (address.ptr)
-       {
-               host = host_create_from_chunk(msg->ifa_family, address, 0);
-       }
-
-       if (host == NULL)
-       {       /* bad family? */
-               return;
-       }
-
-       this->mutex->lock(this->mutex);
-       ifaces = this->ifaces->create_enumerator(this->ifaces);
-       while (ifaces->enumerate(ifaces, &iface))
-       {
-               if (iface->ifindex == msg->ifa_index)
-               {
-                       addrs = iface->addrs->create_enumerator(iface->addrs);
-                       while (addrs->enumerate(addrs, &addr))
-                       {
-                               if (host->ip_equals(host, addr->ip))
-                               {
-                                       found = TRUE;
-                                       if (hdr->nlmsg_type == RTM_DELADDR)
-                                       {
-                                               iface->addrs->remove_at(iface->addrs, addrs);
-                                               if (!addr->virtual)
-                                               {
-                                                       changed = TRUE;
-                                                       DBG1(DBG_KNL, "%H disappeared from %s",
-                                                                host, iface->ifname);
-                                               }
-                                               addr_entry_destroy(addr);
-                                       }
-                                       else if (hdr->nlmsg_type == RTM_NEWADDR && addr->virtual)
-                                       {
-                                               addr->refcount = 1;
-                                       }
-                               }
-                       }
-                       addrs->destroy(addrs);
-
-                       if (hdr->nlmsg_type == RTM_NEWADDR)
-                       {
-                               if (!found)
-                               {
-                                       found = TRUE;
-                                       changed = TRUE;
-                                       addr = malloc_thing(addr_entry_t);
-                                       addr->ip = host->clone(host);
-                                       addr->virtual = FALSE;
-                                       addr->refcount = 1;
-                                       addr->scope = msg->ifa_scope;
-
-                                       iface->addrs->insert_last(iface->addrs, addr);
-                                       if (event)
-                                       {
-                                               DBG1(DBG_KNL, "%H appeared on %s", host, iface->ifname);
-                                       }
-                               }
-                       }
-                       if (found && (iface->flags & IFF_UP))
-                       {
-                               update = TRUE;
-                       }
-                       break;
-               }
-       }
-       ifaces->destroy(ifaces);
-       this->mutex->unlock(this->mutex);
-       host->destroy(host);
-
-       /* send an update to all IKE_SAs */
-       if (update && event && changed)
-       {
-               fire_roam_event(this, TRUE);
-       }
-}
-
-/**
- * process RTM_NEWROUTE and RTM_DELROUTE from kernel
- */
-static void process_route(private_kernel_netlink_net_t *this, struct nlmsghdr *hdr)
-{
-       struct rtmsg* msg = (struct rtmsg*)(NLMSG_DATA(hdr));
-       struct rtattr *rta = RTM_RTA(msg);
-       size_t rtasize = RTM_PAYLOAD(hdr);
-       host_t *host = NULL;
-
-       /* ignore routes added by us */
-       if (msg->rtm_table && msg->rtm_table == this->routing_table)
-       {
-               return;
-       }
-
-       while (RTA_OK(rta, rtasize))
-       {
-               switch (rta->rta_type)
-               {
-                       case RTA_PREFSRC:
-                               host = host_create_from_chunk(msg->rtm_family,
-                                                       chunk_create(RTA_DATA(rta), RTA_PAYLOAD(rta)), 0);
-                               break;
-               }
-               rta = RTA_NEXT(rta, rtasize);
-       }
-       if (host)
-       {
-               this->mutex->lock(this->mutex);
-               if (!get_vip_refcount(this, host))
-               {       /* ignore routes added for virtual IPs */
-                       fire_roam_event(this, FALSE);
-               }
-               this->mutex->unlock(this->mutex);
-               host->destroy(host);
-       }
-}
-
-/**
- * Receives events from kernel
- */
-static job_requeue_t receive_events(private_kernel_netlink_net_t *this)
-{
-       char response[1024];
-       struct nlmsghdr *hdr = (struct nlmsghdr*)response;
-       struct sockaddr_nl addr;
-       socklen_t addr_len = sizeof(addr);
-       int len;
-       bool oldstate;
-
-       oldstate = thread_cancelability(TRUE);
-       len = recvfrom(this->socket_events, response, sizeof(response), 0,
-                                  (struct sockaddr*)&addr, &addr_len);
-       thread_cancelability(oldstate);
-
-       if (len < 0)
-       {
-               switch (errno)
-               {
-                       case EINTR:
-                               /* interrupted, try again */
-                               return JOB_REQUEUE_DIRECT;
-                       case EAGAIN:
-                               /* no data ready, select again */
-                               return JOB_REQUEUE_DIRECT;
-                       default:
-                               DBG1(DBG_KNL, "unable to receive from rt event socket");
-                               sleep(1);
-                               return JOB_REQUEUE_FAIR;
-               }
-       }
-
-       if (addr.nl_pid != 0)
-       {       /* not from kernel. not interested, try another one */
-               return JOB_REQUEUE_DIRECT;
-       }
-
-       while (NLMSG_OK(hdr, len))
-       {
-               /* looks good so far, dispatch netlink message */
-               switch (hdr->nlmsg_type)
-               {
-                       case RTM_NEWADDR:
-                       case RTM_DELADDR:
-                               process_addr(this, hdr, TRUE);
-                               this->condvar->broadcast(this->condvar);
-                               break;
-                       case RTM_NEWLINK:
-                       case RTM_DELLINK:
-                               process_link(this, hdr, TRUE);
-                               this->condvar->broadcast(this->condvar);
-                               break;
-                       case RTM_NEWROUTE:
-                       case RTM_DELROUTE:
-                               if (this->process_route)
-                               {
-                                       process_route(this, hdr);
-                               }
-                               break;
-                       default:
-                               break;
-               }
-               hdr = NLMSG_NEXT(hdr, len);
-       }
-       return JOB_REQUEUE_DIRECT;
-}
-
-/** enumerator over addresses */
-typedef struct {
-       private_kernel_netlink_net_t* this;
-       /** whether to enumerate down interfaces */
-       bool include_down_ifaces;
-       /** whether to enumerate virtual ip addresses */
-       bool include_virtual_ips;
-} address_enumerator_t;
-
-/**
- * cleanup function for address enumerator
- */
-static void address_enumerator_destroy(address_enumerator_t *data)
-{
-       data->this->mutex->unlock(data->this->mutex);
-       free(data);
-}
-
-/**
- * filter for addresses
- */
-static bool filter_addresses(address_enumerator_t *data, addr_entry_t** in, host_t** out)
-{
-       if (!data->include_virtual_ips && (*in)->virtual)
-       {       /* skip virtual interfaces added by us */
-               return FALSE;
-       }
-       if ((*in)->scope >= RT_SCOPE_LINK)
-       {       /* skip addresses with a unusable scope */
-               return FALSE;
-       }
-       *out = (*in)->ip;
-       return TRUE;
-}
-
-/**
- * enumerator constructor for interfaces
- */
-static enumerator_t *create_iface_enumerator(iface_entry_t *iface, address_enumerator_t *data)
-{
-       return enumerator_create_filter(iface->addrs->create_enumerator(iface->addrs),
-                               (void*)filter_addresses, data, NULL);
-}
-
-/**
- * filter for interfaces
- */
-static bool filter_interfaces(address_enumerator_t *data, iface_entry_t** in, iface_entry_t** out)
-{
-       if (!data->include_down_ifaces && !((*in)->flags & IFF_UP))
-       {       /* skip interfaces not up */
-               return FALSE;
-       }
-       *out = *in;
-       return TRUE;
-}
-
-/**
- * implementation of kernel_net_t.create_address_enumerator
- */
-static enumerator_t *create_address_enumerator(private_kernel_netlink_net_t *this,
-               bool include_down_ifaces, bool include_virtual_ips)
-{
-       address_enumerator_t *data = malloc_thing(address_enumerator_t);
-       data->this = this;
-       data->include_down_ifaces = include_down_ifaces;
-       data->include_virtual_ips = include_virtual_ips;
-
-       this->mutex->lock(this->mutex);
-       return enumerator_create_nested(
-                               enumerator_create_filter(this->ifaces->create_enumerator(this->ifaces),
-                                                       (void*)filter_interfaces, data, NULL),
-                               (void*)create_iface_enumerator, data, (void*)address_enumerator_destroy);
-}
-
-/**
- * implementation of kernel_net_t.get_interface_name
- */
-static char *get_interface_name(private_kernel_netlink_net_t *this, host_t* ip)
-{
-       enumerator_t *ifaces, *addrs;
-       iface_entry_t *iface;
-       addr_entry_t *addr;
-       char *name = NULL;
-
-       DBG2(DBG_KNL, "getting interface name for %H", ip);
-
-       this->mutex->lock(this->mutex);
-       ifaces = this->ifaces->create_enumerator(this->ifaces);
-       while (ifaces->enumerate(ifaces, &iface))
-       {
-               addrs = iface->addrs->create_enumerator(iface->addrs);
-               while (addrs->enumerate(addrs, &addr))
-               {
-                       if (ip->ip_equals(ip, addr->ip))
-                       {
-                               name = strdup(iface->ifname);
-                               break;
-                       }
-               }
-               addrs->destroy(addrs);
-               if (name)
-               {
-                       break;
-               }
-       }
-       ifaces->destroy(ifaces);
-       this->mutex->unlock(this->mutex);
-
-       if (name)
-       {
-               DBG2(DBG_KNL, "%H is on interface %s", ip, name);
-       }
-       else
-       {
-               DBG2(DBG_KNL, "%H is not a local address", ip);
-       }
-       return name;
-}
-
-/**
- * get the index of an interface by name
- */
-static int get_interface_index(private_kernel_netlink_net_t *this, char* name)
-{
-       enumerator_t *ifaces;
-       iface_entry_t *iface;
-       int ifindex = 0;
-
-       DBG2(DBG_KNL, "getting iface index for %s", name);
-
-       this->mutex->lock(this->mutex);
-       ifaces = this->ifaces->create_enumerator(this->ifaces);
-       while (ifaces->enumerate(ifaces, &iface))
-       {
-               if (streq(name, iface->ifname))
-               {
-                       ifindex = iface->ifindex;
-                       break;
-               }
-       }
-       ifaces->destroy(ifaces);
-       this->mutex->unlock(this->mutex);
-
-       if (ifindex == 0)
-       {
-               DBG1(DBG_KNL, "unable to get interface index for %s", name);
-       }
-       return ifindex;
-}
-
-/**
- * Check if an interface with a given index is up
- */
-static bool is_interface_up(private_kernel_netlink_net_t *this, int index)
-{
-       enumerator_t *ifaces;
-       iface_entry_t *iface;
-       /* default to TRUE for interface we do not monitor (e.g. lo) */
-       bool up = TRUE;
-
-       ifaces = this->ifaces->create_enumerator(this->ifaces);
-       while (ifaces->enumerate(ifaces, &iface))
-       {
-               if (iface->ifindex == index)
-               {
-                       up = iface->flags & IFF_UP;
-                       break;
-               }
-       }
-       ifaces->destroy(ifaces);
-       return up;
-}
-
-/**
- * check if an address (chunk) addr is in subnet (net with net_len net bits)
- */
-static bool addr_in_subnet(chunk_t addr, chunk_t net, int net_len)
-{
-       static const u_char mask[] = { 0x00, 0x80, 0xc0, 0xe0, 0xf0, 0xf8, 0xfc, 0xfe };
-       int byte = 0;
-
-       if (net_len == 0)
-       {       /* any address matches a /0 network */
-               return TRUE;
-       }
-       if (addr.len != net.len || net_len > 8 * net.len )
-       {
-               return FALSE;
-       }
-       /* scan through all bytes in network order */
-       while (net_len > 0)
-       {
-               if (net_len < 8)
-               {
-                       return (mask[net_len] & addr.ptr[byte]) == (mask[net_len] & net.ptr[byte]);
-               }
-               else
-               {
-                       if (addr.ptr[byte] != net.ptr[byte])
-                       {
-                               return FALSE;
-                       }
-                       byte++;
-                       net_len -= 8;
-               }
-       }
-       return TRUE;
-}
-
-/**
- * Get a route: If "nexthop", the nexthop is returned. source addr otherwise.
- */
-static host_t *get_route(private_kernel_netlink_net_t *this, host_t *dest,
-                                                bool nexthop, host_t *candidate)
-{
-       netlink_buf_t request;
-       struct nlmsghdr *hdr, *out, *current;
-       struct rtmsg *msg;
-       chunk_t chunk;
-       size_t len;
-       int best = -1;
-       enumerator_t *enumerator;
-       host_t *src = NULL, *gtw = NULL;
-
-       DBG2(DBG_KNL, "getting address to reach %H", dest);
-
-       memset(&request, 0, sizeof(request));
-
-       hdr = (struct nlmsghdr*)request;
-       hdr->nlmsg_flags = NLM_F_REQUEST;
-       if (dest->get_family(dest) == AF_INET)
-       {
-               /* We dump all addresses for IPv4, as we want to ignore IPsec specific
-                * routes installed by us. But the kernel does not return source
-                * addresses in a IPv6 dump, so fall back to get() for v6 routes. */
-               hdr->nlmsg_flags |= NLM_F_ROOT | NLM_F_DUMP;
-       }
-       hdr->nlmsg_type = RTM_GETROUTE;
-       hdr->nlmsg_len = NLMSG_LENGTH(sizeof(struct rtmsg));
-
-       msg = (struct rtmsg*)NLMSG_DATA(hdr);
-       msg->rtm_family = dest->get_family(dest);
-       if (candidate)
-       {
-               chunk = candidate->get_address(candidate);
-               netlink_add_attribute(hdr, RTA_PREFSRC, chunk, sizeof(request));
-       }
-       chunk = dest->get_address(dest);
-       netlink_add_attribute(hdr, RTA_DST, chunk, sizeof(request));
-
-       if (this->socket->send(this->socket, hdr, &out, &len) != SUCCESS)
-       {
-               DBG1(DBG_KNL, "getting address to %H failed", dest);
-               return NULL;
-       }
-       this->mutex->lock(this->mutex);
-
-       for (current = out; NLMSG_OK(current, len);
-                current = NLMSG_NEXT(current, len))
-       {
-               switch (current->nlmsg_type)
-               {
-                       case NLMSG_DONE:
-                               break;
-                       case RTM_NEWROUTE:
-                       {
-                               struct rtattr *rta;
-                               size_t rtasize;
-                               chunk_t rta_gtw, rta_src, rta_dst;
-                               u_int32_t rta_oif = 0;
-                               host_t *new_src, *new_gtw;
-                               bool cont = FALSE;
-                               uintptr_t table;
-
-                               rta_gtw = rta_src = rta_dst = chunk_empty;
-                               msg = (struct rtmsg*)(NLMSG_DATA(current));
-                               rta = RTM_RTA(msg);
-                               rtasize = RTM_PAYLOAD(current);
-                               while (RTA_OK(rta, rtasize))
-                               {
-                                       switch (rta->rta_type)
-                                       {
-                                               case RTA_PREFSRC:
-                                                       rta_src = chunk_create(RTA_DATA(rta), RTA_PAYLOAD(rta));
-                                                       break;
-                                               case RTA_GATEWAY:
-                                                       rta_gtw = chunk_create(RTA_DATA(rta), RTA_PAYLOAD(rta));
-                                                       break;
-                                               case RTA_DST:
-                                                       rta_dst = chunk_create(RTA_DATA(rta), RTA_PAYLOAD(rta));
-                                                       break;
-                                               case RTA_OIF:
-                                                       if (RTA_PAYLOAD(rta) == sizeof(rta_oif))
-                                                       {
-                                                               rta_oif = *(u_int32_t*)RTA_DATA(rta);
-                                                       }
-                                                       break;
-                                       }
-                                       rta = RTA_NEXT(rta, rtasize);
-                               }
-                               if (msg->rtm_dst_len <= best)
-                               {       /* not better than a previous one */
-                                       continue;
-                               }
-                               enumerator = this->rt_exclude->create_enumerator(this->rt_exclude);
-                               while (enumerator->enumerate(enumerator, &table))
-                               {
-                                       if (table == msg->rtm_table)
-                                       {
-                                               cont = TRUE;
-                                               break;
-                                       }
-                               }
-                               enumerator->destroy(enumerator);
-                               if (cont)
-                               {
-                                       continue;
-                               }
-                               if (this->routing_table != 0 &&
-                                       msg->rtm_table == this->routing_table)
-                               {       /* route is from our own ipsec routing table */
-                                       continue;
-                               }
-                               if (rta_oif && !is_interface_up(this, rta_oif))
-                               {       /* interface is down */
-                                       continue;
-                               }
-                               if (!addr_in_subnet(chunk, rta_dst, msg->rtm_dst_len))
-                               {       /* route destination does not contain dest */
-                                       continue;
-                               }
-
-                               if (nexthop)
-                               {
-                                       /* nexthop lookup, return gateway if any */
-                                       DESTROY_IF(gtw);
-                                       gtw = host_create_from_chunk(msg->rtm_family, rta_gtw, 0);
-                                       best = msg->rtm_dst_len;
-                                       continue;
-                               }
-                               if (rta_src.ptr)
-                               {
-                                       /* got a source address */
-                                       new_src = host_create_from_chunk(msg->rtm_family, rta_src, 0);
-                                       if (new_src)
-                                       {
-                                               if (get_vip_refcount(this, new_src))
-                                               {       /* skip source address if it is installed by us */
-                                                       new_src->destroy(new_src);
-                                               }
-                                               else
-                                               {
-                                                       DESTROY_IF(src);
-                                                       src = new_src;
-                                                       best = msg->rtm_dst_len;
-                                               }
-                                       }
-                                       continue;
-                               }
-                               if (rta_gtw.ptr)
-                               {       /* no source, but a gateway. Lookup source to reach gtw. */
-                                       new_gtw = host_create_from_chunk(msg->rtm_family, rta_gtw, 0);
-                                       new_src = get_route(this, new_gtw, FALSE, candidate);
-                                       new_gtw->destroy(new_gtw);
-                                       if (new_src)
-                                       {
-                                               DESTROY_IF(src);
-                                               src = new_src;
-                                               best = msg->rtm_dst_len;
-                                       }
-                                       continue;
-                               }
-                               continue;
-                       }
-                       default:
-                               continue;
-               }
-               break;
-       }
-       free(out);
-       this->mutex->unlock(this->mutex);
-
-       if (nexthop)
-       {
-               if (gtw)
-               {
-                       return gtw;
-               }
-               return dest->clone(dest);
-       }
-       return src;
-}
-
-/**
- * Implementation of kernel_net_t.get_source_addr.
- */
-static host_t* get_source_addr(private_kernel_netlink_net_t *this,
-                                                          host_t *dest, host_t *src)
-{
-       return get_route(this, dest, FALSE, src);
-}
-
-/**
- * Implementation of kernel_net_t.get_nexthop.
- */
-static host_t* get_nexthop(private_kernel_netlink_net_t *this, host_t *dest)
-{
-       return get_route(this, dest, TRUE, NULL);
-}
-
-/**
- * Manages the creation and deletion of ip addresses on an interface.
- * By setting the appropriate nlmsg_type, the ip will be set or unset.
- */
-static status_t manage_ipaddr(private_kernel_netlink_net_t *this, int nlmsg_type,
-                                                         int flags, int if_index, host_t *ip)
-{
-       netlink_buf_t request;
-       struct nlmsghdr *hdr;
-       struct ifaddrmsg *msg;
-       chunk_t chunk;
-
-       memset(&request, 0, sizeof(request));
-
-       chunk = ip->get_address(ip);
-
-       hdr = (struct nlmsghdr*)request;
-       hdr->nlmsg_flags = NLM_F_REQUEST | NLM_F_ACK | flags;
-       hdr->nlmsg_type = nlmsg_type;
-       hdr->nlmsg_len = NLMSG_LENGTH(sizeof(struct ifaddrmsg));
-
-       msg = (struct ifaddrmsg*)NLMSG_DATA(hdr);
-       msg->ifa_family = ip->get_family(ip);
-       msg->ifa_flags = 0;
-       msg->ifa_prefixlen = 8 * chunk.len;
-       msg->ifa_scope = RT_SCOPE_UNIVERSE;
-       msg->ifa_index = if_index;
-
-       netlink_add_attribute(hdr, IFA_LOCAL, chunk, sizeof(request));
-
-       return this->socket->send_ack(this->socket, hdr);
-}
-
-/**
- * Implementation of kernel_net_t.add_ip.
- */
-static status_t add_ip(private_kernel_netlink_net_t *this,
-                                               host_t *virtual_ip, host_t *iface_ip)
-{
-       iface_entry_t *iface;
-       addr_entry_t *addr;
-       enumerator_t *addrs, *ifaces;
-       int ifindex;
-
-       if (!this->install_virtual_ip)
-       {       /* disabled by config */
-               return SUCCESS;
-       }
-
-       DBG2(DBG_KNL, "adding virtual IP %H", virtual_ip);
-
-       this->mutex->lock(this->mutex);
-       ifaces = this->ifaces->create_enumerator(this->ifaces);
-       while (ifaces->enumerate(ifaces, &iface))
-       {
-               bool iface_found = FALSE;
-
-               addrs = iface->addrs->create_enumerator(iface->addrs);
-               while (addrs->enumerate(addrs, &addr))
-               {
-                       if (iface_ip->ip_equals(iface_ip, addr->ip))
-                       {
-                               iface_found = TRUE;
-                       }
-                       else if (virtual_ip->ip_equals(virtual_ip, addr->ip))
-                       {
-                               addr->refcount++;
-                               DBG2(DBG_KNL, "virtual IP %H already installed on %s",
-                                        virtual_ip, iface->ifname);
-                               addrs->destroy(addrs);
-                               ifaces->destroy(ifaces);
-                               this->mutex->unlock(this->mutex);
-                               return SUCCESS;
-                       }
-               }
-               addrs->destroy(addrs);
-
-               if (iface_found)
-               {
-                       ifindex = iface->ifindex;
-                       addr = malloc_thing(addr_entry_t);
-                       addr->ip = virtual_ip->clone(virtual_ip);
-                       addr->refcount = 0;
-                       addr->virtual = TRUE;
-                       addr->scope = RT_SCOPE_UNIVERSE;
-                       iface->addrs->insert_last(iface->addrs, addr);
-
-                       if (manage_ipaddr(this, RTM_NEWADDR, NLM_F_CREATE | NLM_F_EXCL,
-                                                         ifindex, virtual_ip) == SUCCESS)
-                       {
-                               while (get_vip_refcount(this, virtual_ip) == 0)
-                               {       /* wait until address appears */
-                                       this->condvar->wait(this->condvar, this->mutex);
-                               }
-                               ifaces->destroy(ifaces);
-                               this->mutex->unlock(this->mutex);
-                               return SUCCESS;
-                       }
-                       ifaces->destroy(ifaces);
-                       this->mutex->unlock(this->mutex);
-                       DBG1(DBG_KNL, "adding virtual IP %H failed", virtual_ip);
-                       return FAILED;
-               }
-       }
-       ifaces->destroy(ifaces);
-       this->mutex->unlock(this->mutex);
-
-       DBG1(DBG_KNL, "interface address %H not found, unable to install"
-                "virtual IP %H", iface_ip, virtual_ip);
-       return FAILED;
-}
-
-/**
- * Implementation of kernel_net_t.del_ip.
- */
-static status_t del_ip(private_kernel_netlink_net_t *this, host_t *virtual_ip)
-{
-       iface_entry_t *iface;
-       addr_entry_t *addr;
-       enumerator_t *addrs, *ifaces;
-       status_t status;
-       int ifindex;
-
-       if (!this->install_virtual_ip)
-       {       /* disabled by config */
-               return SUCCESS;
-       }
-
-       DBG2(DBG_KNL, "deleting virtual IP %H", virtual_ip);
-
-       this->mutex->lock(this->mutex);
-       ifaces = this->ifaces->create_enumerator(this->ifaces);
-       while (ifaces->enumerate(ifaces, &iface))
-       {
-               addrs = iface->addrs->create_enumerator(iface->addrs);
-               while (addrs->enumerate(addrs, &addr))
-               {
-                       if (virtual_ip->ip_equals(virtual_ip, addr->ip))
-                       {
-                               ifindex = iface->ifindex;
-                               if (addr->refcount == 1)
-                               {
-                                       status = manage_ipaddr(this, RTM_DELADDR, 0,
-                                                                                  ifindex, virtual_ip);
-                                       if (status == SUCCESS)
-                                       {       /* wait until the address is really gone */
-                                               while (get_vip_refcount(this, virtual_ip) > 0)
-                                               {
-                                                       this->condvar->wait(this->condvar, this->mutex);
-                                               }
-                                       }
-                                       addrs->destroy(addrs);
-                                       ifaces->destroy(ifaces);
-                                       this->mutex->unlock(this->mutex);
-                                       return status;
-                               }
-                               else
-                               {
-                                       addr->refcount--;
-                               }
-                               DBG2(DBG_KNL, "virtual IP %H used by other SAs, not deleting",
-                                        virtual_ip);
-                               addrs->destroy(addrs);
-                               ifaces->destroy(ifaces);
-                               this->mutex->unlock(this->mutex);
-                               return SUCCESS;
-                       }
-               }
-               addrs->destroy(addrs);
-       }
-       ifaces->destroy(ifaces);
-       this->mutex->unlock(this->mutex);
-
-       DBG2(DBG_KNL, "virtual IP %H not cached, unable to delete", virtual_ip);
-       return FAILED;
-}
-
-/**
- * Manages source routes in the routing table.
- * By setting the appropriate nlmsg_type, the route gets added or removed.
- */
-static status_t manage_srcroute(private_kernel_netlink_net_t *this, int nlmsg_type,
-                                                               int flags, chunk_t dst_net, u_int8_t prefixlen,
-                                                               host_t *gateway, host_t *src_ip, char *if_name)
-{
-       netlink_buf_t request;
-       struct nlmsghdr *hdr;
-       struct rtmsg *msg;
-       int ifindex;
-       chunk_t chunk;
-
-       /* if route is 0.0.0.0/0, we can't install it, as it would
-        * overwrite the default route. Instead, we add two routes:
-        * 0.0.0.0/1 and 128.0.0.0/1 */
-       if (this->routing_table == 0 && prefixlen == 0)
-       {
-               chunk_t half_net;
-               u_int8_t half_prefixlen;
-               status_t status;
-
-               half_net = chunk_alloca(dst_net.len);
-               memset(half_net.ptr, 0, half_net.len);
-               half_prefixlen = 1;
-
-               status = manage_srcroute(this, nlmsg_type, flags, half_net, half_prefixlen,
-                                       gateway, src_ip, if_name);
-               half_net.ptr[0] |= 0x80;
-               status = manage_srcroute(this, nlmsg_type, flags, half_net, half_prefixlen,
-                                       gateway, src_ip, if_name);
-               return status;
-       }
-
-       memset(&request, 0, sizeof(request));
-
-       hdr = (struct nlmsghdr*)request;
-       hdr->nlmsg_flags = NLM_F_REQUEST | NLM_F_ACK | flags;
-       hdr->nlmsg_type = nlmsg_type;
-       hdr->nlmsg_len = NLMSG_LENGTH(sizeof(struct rtmsg));
-
-       msg = (struct rtmsg*)NLMSG_DATA(hdr);
-       msg->rtm_family = src_ip->get_family(src_ip);
-       msg->rtm_dst_len = prefixlen;
-       msg->rtm_table = this->routing_table;
-       msg->rtm_protocol = RTPROT_STATIC;
-       msg->rtm_type = RTN_UNICAST;
-       msg->rtm_scope = RT_SCOPE_UNIVERSE;
-
-       netlink_add_attribute(hdr, RTA_DST, dst_net, sizeof(request));
-       chunk = src_ip->get_address(src_ip);
-       netlink_add_attribute(hdr, RTA_PREFSRC, chunk, sizeof(request));
-       if (gateway && gateway->get_family(gateway) == src_ip->get_family(src_ip))
-       {
-               chunk = gateway->get_address(gateway);
-               netlink_add_attribute(hdr, RTA_GATEWAY, chunk, sizeof(request));
-       }
-       ifindex = get_interface_index(this, if_name);
-       chunk.ptr = (char*)&ifindex;
-       chunk.len = sizeof(ifindex);
-       netlink_add_attribute(hdr, RTA_OIF, chunk, sizeof(request));
-
-       return this->socket->send_ack(this->socket, hdr);
-}
-
-/**
- * Implementation of kernel_net_t.add_route.
- */
-static status_t add_route(private_kernel_netlink_net_t *this, chunk_t dst_net,
-               u_int8_t prefixlen, host_t *gateway, host_t *src_ip, char *if_name)
-{
-       return manage_srcroute(this, RTM_NEWROUTE, NLM_F_CREATE | NLM_F_EXCL,
-                               dst_net, prefixlen, gateway, src_ip, if_name);
-}
-
-/**
- * Implementation of kernel_net_t.del_route.
- */
-static status_t del_route(private_kernel_netlink_net_t *this, chunk_t dst_net,
-               u_int8_t prefixlen, host_t *gateway, host_t *src_ip, char *if_name)
-{
-       return manage_srcroute(this, RTM_DELROUTE, 0, dst_net, prefixlen,
-                               gateway, src_ip, if_name);
-}
-
-/**
- * Initialize a list of local addresses.
- */
-static status_t init_address_list(private_kernel_netlink_net_t *this)
-{
-       netlink_buf_t request;
-       struct nlmsghdr *out, *current, *in;
-       struct rtgenmsg *msg;
-       size_t len;
-       enumerator_t *ifaces, *addrs;
-       iface_entry_t *iface;
-       addr_entry_t *addr;
-
-       DBG1(DBG_KNL, "listening on interfaces:");
-
-       memset(&request, 0, sizeof(request));
-
-       in = (struct nlmsghdr*)&request;
-       in->nlmsg_len = NLMSG_LENGTH(sizeof(struct rtgenmsg));
-       in->nlmsg_flags = NLM_F_REQUEST | NLM_F_MATCH | NLM_F_ROOT;
-       msg = (struct rtgenmsg*)NLMSG_DATA(in);
-       msg->rtgen_family = AF_UNSPEC;
-
-       /* get all links */
-       in->nlmsg_type = RTM_GETLINK;
-       if (this->socket->send(this->socket, in, &out, &len) != SUCCESS)
-       {
-               return FAILED;
-       }
-       current = out;
-       while (NLMSG_OK(current, len))
-       {
-               switch (current->nlmsg_type)
-               {
-                       case NLMSG_DONE:
-                               break;
-                       case RTM_NEWLINK:
-                               process_link(this, current, FALSE);
-                               /* fall through */
-                       default:
-                               current = NLMSG_NEXT(current, len);
-                               continue;
-               }
-               break;
-       }
-       free(out);
-
-       /* get all interface addresses */
-       in->nlmsg_type = RTM_GETADDR;
-       if (this->socket->send(this->socket, in, &out, &len) != SUCCESS)
-       {
-               return FAILED;
-       }
-       current = out;
-       while (NLMSG_OK(current, len))
-       {
-               switch (current->nlmsg_type)
-               {
-                       case NLMSG_DONE:
-                               break;
-                       case RTM_NEWADDR:
-                               process_addr(this, current, FALSE);
-                               /* fall through */
-                       default:
-                               current = NLMSG_NEXT(current, len);
-                               continue;
-               }
-               break;
-       }
-       free(out);
-
-       this->mutex->lock(this->mutex);
-       ifaces = this->ifaces->create_enumerator(this->ifaces);
-       while (ifaces->enumerate(ifaces, &iface))
-       {
-               if (iface->flags & IFF_UP)
-               {
-                       DBG1(DBG_KNL, "  %s", iface->ifname);
-                       addrs = iface->addrs->create_enumerator(iface->addrs);
-                       while (addrs->enumerate(addrs, (void**)&addr))
-                       {
-                               DBG1(DBG_KNL, "    %H", addr->ip);
-                       }
-                       addrs->destroy(addrs);
-               }
-       }
-       ifaces->destroy(ifaces);
-       this->mutex->unlock(this->mutex);
-       return SUCCESS;
-}
-
-/**
- * create or delete a rule to use our routing table
- */
-static status_t manage_rule(private_kernel_netlink_net_t *this, int nlmsg_type,
-                                                       int family, u_int32_t table, u_int32_t prio)
-{
-       netlink_buf_t request;
-       struct nlmsghdr *hdr;
-       struct rtmsg *msg;
-       chunk_t chunk;
-
-       memset(&request, 0, sizeof(request));
-       hdr = (struct nlmsghdr*)request;
-       hdr->nlmsg_flags = NLM_F_REQUEST | NLM_F_ACK;
-       hdr->nlmsg_type = nlmsg_type;
-       if (nlmsg_type == RTM_NEWRULE)
-       {
-               hdr->nlmsg_flags |= NLM_F_CREATE | NLM_F_EXCL;
-       }
-       hdr->nlmsg_len = NLMSG_LENGTH(sizeof(struct rtmsg));
-
-       msg = (struct rtmsg*)NLMSG_DATA(hdr);
-       msg->rtm_table = table;
-       msg->rtm_family = family;
-       msg->rtm_protocol = RTPROT_BOOT;
-       msg->rtm_scope = RT_SCOPE_UNIVERSE;
-       msg->rtm_type = RTN_UNICAST;
-
-       chunk = chunk_from_thing(prio);
-       netlink_add_attribute(hdr, RTA_PRIORITY, chunk, sizeof(request));
-
-       return this->socket->send_ack(this->socket, hdr);
-}
-
-/**
- * Implementation of kernel_netlink_net_t.destroy.
- */
-static void destroy(private_kernel_netlink_net_t *this)
-{
-       if (this->routing_table)
-       {
-               manage_rule(this, RTM_DELRULE, AF_INET, this->routing_table,
-                                       this->routing_table_prio);
-               manage_rule(this, RTM_DELRULE, AF_INET6, this->routing_table,
-                                       this->routing_table_prio);
-       }
-       if (this->job)
-       {
-               this->job->cancel(this->job);
-       }
-       if (this->socket_events > 0)
-       {
-               close(this->socket_events);
-       }
-       DESTROY_IF(this->socket);
-       this->ifaces->destroy_function(this->ifaces, (void*)iface_entry_destroy);
-       this->rt_exclude->destroy(this->rt_exclude);
-       this->condvar->destroy(this->condvar);
-       this->mutex->destroy(this->mutex);
-       free(this);
-}
-
-/*
- * Described in header.
- */
-kernel_netlink_net_t *kernel_netlink_net_create()
-{
-       private_kernel_netlink_net_t *this = malloc_thing(private_kernel_netlink_net_t);
-       struct sockaddr_nl addr;
-       enumerator_t *enumerator;
-       char *exclude;
-
-       /* public functions */
-       this->public.interface.get_interface = (char*(*)(kernel_net_t*,host_t*))get_interface_name;
-       this->public.interface.create_address_enumerator = (enumerator_t*(*)(kernel_net_t*,bool,bool))create_address_enumerator;
-       this->public.interface.get_source_addr = (host_t*(*)(kernel_net_t*, host_t *dest, host_t *src))get_source_addr;
-       this->public.interface.get_nexthop = (host_t*(*)(kernel_net_t*, host_t *dest))get_nexthop;
-       this->public.interface.add_ip = (status_t(*)(kernel_net_t*,host_t*,host_t*)) add_ip;
-       this->public.interface.del_ip = (status_t(*)(kernel_net_t*,host_t*)) del_ip;
-       this->public.interface.add_route = (status_t(*)(kernel_net_t*,chunk_t,u_int8_t,host_t*,host_t*,char*)) add_route;
-       this->public.interface.del_route = (status_t(*)(kernel_net_t*,chunk_t,u_int8_t,host_t*,host_t*,char*)) del_route;
-       this->public.interface.destroy = (void(*)(kernel_net_t*)) destroy;
-
-       /* private members */
-       this->ifaces = linked_list_create();
-       this->mutex = mutex_create(MUTEX_TYPE_RECURSIVE);
-       this->condvar = condvar_create(CONDVAR_TYPE_DEFAULT);
-       timerclear(&this->last_roam);
-       this->routing_table = lib->settings->get_int(lib->settings,
-                                       "charon.routing_table", ROUTING_TABLE);
-       this->routing_table_prio = lib->settings->get_int(lib->settings,
-                                       "charon.routing_table_prio", ROUTING_TABLE_PRIO);
-       this->process_route = lib->settings->get_bool(lib->settings,
-                                       "charon.process_route", TRUE);
-       this->install_virtual_ip = lib->settings->get_bool(lib->settings,
-                                       "charon.install_virtual_ip", TRUE);
-
-       this->rt_exclude = linked_list_create();
-       exclude = lib->settings->get_str(lib->settings,
-                                       "charon.ignore_routing_tables", NULL);
-       if (exclude)
-       {
-               char *token;
-               uintptr_t table;
-
-               enumerator = enumerator_create_token(exclude, " ", " ");
-               while (enumerator->enumerate(enumerator, &token))
-               {
-                       errno = 0;
-                       table = strtoul(token, NULL, 10);
-
-                       if (errno == 0)
-                       {
-                               this->rt_exclude->insert_last(this->rt_exclude, (void*)table);
-                       }
-               }
-               enumerator->destroy(enumerator);
-       }
-
-       this->socket = netlink_socket_create(NETLINK_ROUTE);
-       this->job = NULL;
-
-       memset(&addr, 0, sizeof(addr));
-       addr.nl_family = AF_NETLINK;
-
-       /* create and bind RT socket for events (address/interface/route changes) */
-       this->socket_events = socket(AF_NETLINK, SOCK_RAW, NETLINK_ROUTE);
-       if (this->socket_events < 0)
-       {
-               DBG1(DBG_KNL, "unable to create RT event socket");
-               destroy(this);
-               return NULL;
-       }
-       addr.nl_groups = RTMGRP_IPV4_IFADDR | RTMGRP_IPV6_IFADDR |
-                                        RTMGRP_IPV4_ROUTE | RTMGRP_IPV4_ROUTE | RTMGRP_LINK;
-       if (bind(this->socket_events, (struct sockaddr*)&addr, sizeof(addr)))
-       {
-               DBG1(DBG_KNL, "unable to bind RT event socket");
-               destroy(this);
-               return NULL;
-       }
-
-       this->job = callback_job_create((callback_job_cb_t)receive_events,
-                                                                       this, NULL, NULL);
-       hydra->processor->queue_job(hydra->processor, (job_t*)this->job);
-
-       if (init_address_list(this) != SUCCESS)
-       {
-               DBG1(DBG_KNL, "unable to get interface list");
-               destroy(this);
-               return NULL;
-       }
-
-       if (this->routing_table)
-       {
-               if (manage_rule(this, RTM_NEWRULE, AF_INET, this->routing_table,
-                                               this->routing_table_prio) != SUCCESS)
-               {
-                       DBG1(DBG_KNL, "unable to create IPv4 routing table rule");
-               }
-               if (manage_rule(this, RTM_NEWRULE, AF_INET6, this->routing_table,
-                                               this->routing_table_prio) != SUCCESS)
-               {
-                       DBG1(DBG_KNL, "unable to create IPv6 routing table rule");
-               }
-       }
-
-       return &this->public;
-}
diff --git a/src/libcharon/plugins/kernel_netlink/kernel_netlink_net.h b/src/libcharon/plugins/kernel_netlink/kernel_netlink_net.h
deleted file mode 100644 (file)
index ff9831d..0000000
+++ /dev/null
@@ -1,46 +0,0 @@
-/*
- * Copyright (C) 2008 Tobias Brunner
- * Hochschule fuer Technik Rapperswil
- *
- * This program is free software; you can redistribute it and/or modify it
- * under the terms of the GNU General Public License as published by the
- * Free Software Foundation; either version 2 of the License, or (at your
- * option) any later version.  See <http://www.fsf.org/copyleft/gpl.txt>.
- *
- * This program is distributed in the hope that it will be useful, but
- * WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY
- * or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License
- * for more details.
- */
-
-/**
- * @defgroup kernel_netlink_net_i kernel_netlink_net
- * @{ @ingroup kernel_netlink
- */
-
-#ifndef KERNEL_NETLINK_NET_H_
-#define KERNEL_NETLINK_NET_H_
-
-#include <kernel/kernel_net.h>
-
-typedef struct kernel_netlink_net_t kernel_netlink_net_t;
-
-/**
- * Implementation of the kernel network interface using Netlink.
- */
-struct kernel_netlink_net_t {
-
-       /**
-        * Implements kernel_net_t interface
-        */
-       kernel_net_t interface;
-};
-
-/**
- * Create a netlink kernel network interface instance.
- *
- * @return                     kernel_netlink_net_t instance
- */
-kernel_netlink_net_t *kernel_netlink_net_create();
-
-#endif /** KERNEL_NETLINK_NET_H_ @}*/
diff --git a/src/libcharon/plugins/kernel_netlink/kernel_netlink_plugin.c b/src/libcharon/plugins/kernel_netlink/kernel_netlink_plugin.c
deleted file mode 100644 (file)
index 212675d..0000000
+++ /dev/null
@@ -1,63 +0,0 @@
-/*
- * Copyright (C) 2008 Tobias Brunner
- * Hochschule fuer Technik Rapperswil
- *
- * This program is free software; you can redistribute it and/or modify it
- * under the terms of the GNU General Public License as published by the
- * Free Software Foundation; either version 2 of the License, or (at your
- * option) any later version.  See <http://www.fsf.org/copyleft/gpl.txt>.
- *
- * This program is distributed in the hope that it will be useful, but
- * WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY
- * or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License
- * for more details.
- */
-
-
-#include "kernel_netlink_plugin.h"
-
-#include "kernel_netlink_ipsec.h"
-#include "kernel_netlink_net.h"
-
-#include <hydra.h>
-
-typedef struct private_kernel_netlink_plugin_t private_kernel_netlink_plugin_t;
-
-/**
- * private data of kernel netlink plugin
- */
-struct private_kernel_netlink_plugin_t {
-       /**
-        * implements plugin interface
-        */
-       kernel_netlink_plugin_t public;
-};
-
-/**
- * Implementation of plugin_t.destroy
- */
-static void destroy(private_kernel_netlink_plugin_t *this)
-{
-       hydra->kernel_interface->remove_ipsec_interface(hydra->kernel_interface,
-                                       (kernel_ipsec_constructor_t)kernel_netlink_ipsec_create);
-       hydra->kernel_interface->remove_net_interface(hydra->kernel_interface,
-                                       (kernel_net_constructor_t)kernel_netlink_net_create);
-       free(this);
-}
-
-/*
- * see header file
- */
-plugin_t *kernel_netlink_plugin_create()
-{
-       private_kernel_netlink_plugin_t *this = malloc_thing(private_kernel_netlink_plugin_t);
-
-       this->public.plugin.destroy = (void(*)(plugin_t*))destroy;
-
-       hydra->kernel_interface->add_ipsec_interface(hydra->kernel_interface,
-                                       (kernel_ipsec_constructor_t)kernel_netlink_ipsec_create);
-       hydra->kernel_interface->add_net_interface(hydra->kernel_interface,
-                                       (kernel_net_constructor_t)kernel_netlink_net_create);
-
-       return &this->public.plugin;
-}
diff --git a/src/libcharon/plugins/kernel_netlink/kernel_netlink_plugin.h b/src/libcharon/plugins/kernel_netlink/kernel_netlink_plugin.h
deleted file mode 100644 (file)
index 74c9ae2..0000000
+++ /dev/null
@@ -1,42 +0,0 @@
-/*
- * Copyright (C) 2008 Tobias Brunner
- * Hochschule fuer Technik Rapperswil
- *
- * This program is free software; you can redistribute it and/or modify it
- * under the terms of the GNU General Public License as published by the
- * Free Software Foundation; either version 2 of the License, or (at your
- * option) any later version.  See <http://www.fsf.org/copyleft/gpl.txt>.
- *
- * This program is distributed in the hope that it will be useful, but
- * WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY
- * or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License
- * for more details.
- */
-
-/**
- * @defgroup kernel_netlink kernel_netlink
- * @ingroup cplugins
- *
- * @defgroup kernel_netlink_plugin kernel_netlink_plugin
- * @{ @ingroup kernel_netlink
- */
-
-#ifndef KERNEL_NETLINK_PLUGIN_H_
-#define KERNEL_NETLINK_PLUGIN_H_
-
-#include <plugins/plugin.h>
-
-typedef struct kernel_netlink_plugin_t kernel_netlink_plugin_t;
-
-/**
- * netlink kernel interface plugin
- */
-struct kernel_netlink_plugin_t {
-
-       /**
-        * implements plugin interface
-        */
-       plugin_t plugin;
-};
-
-#endif /** KERNEL_NETLINK_PLUGIN_H_ @}*/
diff --git a/src/libcharon/plugins/kernel_netlink/kernel_netlink_shared.c b/src/libcharon/plugins/kernel_netlink/kernel_netlink_shared.c
deleted file mode 100644 (file)
index 5ed5681..0000000
+++ /dev/null
@@ -1,306 +0,0 @@
-/*
- * Copyright (C) 2008 Tobias Brunner
- * Hochschule fuer Technik Rapperswil
- *
- * This program is free software; you can redistribute it and/or modify it
- * under the terms of the GNU General Public License as published by the
- * Free Software Foundation; either version 2 of the License, or (at your
- * option) any later version.  See <http://www.fsf.org/copyleft/gpl.txt>.
- *
- * This program is distributed in the hope that it will be useful, but
- * WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY
- * or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License
- * for more details.
- */
-
-#include <sys/socket.h>
-#include <linux/netlink.h>
-#include <linux/rtnetlink.h>
-#include <errno.h>
-#include <unistd.h>
-
-#include "kernel_netlink_shared.h"
-
-#include <daemon.h>
-#include <threading/mutex.h>
-
-typedef struct private_netlink_socket_t private_netlink_socket_t;
-
-/**
- * Private variables and functions of netlink_socket_t class.
- */
-struct private_netlink_socket_t {
-       /**
-        * public part of the netlink_socket_t object.
-        */
-       netlink_socket_t public;
-
-       /**
-        * mutex to lock access to netlink socket
-        */
-       mutex_t *mutex;
-
-       /**
-        * current sequence number for netlink request
-        */
-       int seq;
-
-       /**
-        * netlink socket protocol
-        */
-       int protocol;
-
-       /**
-        * netlink socket
-        */
-       int socket;
-};
-
-/**
- * Imported from kernel_netlink_ipsec.c
- */
-extern enum_name_t *xfrm_msg_names;
-
-/**
- * Implementation of netlink_socket_t.send
- */
-static status_t netlink_send(private_netlink_socket_t *this, struct nlmsghdr *in,
-                         struct nlmsghdr **out, size_t *out_len)
-{
-       int len, addr_len;
-       struct sockaddr_nl addr;
-       chunk_t result = chunk_empty, tmp;
-       struct nlmsghdr *msg, peek;
-
-       this->mutex->lock(this->mutex);
-
-       in->nlmsg_seq = ++this->seq;
-       in->nlmsg_pid = getpid();
-
-       memset(&addr, 0, sizeof(addr));
-       addr.nl_family = AF_NETLINK;
-       addr.nl_pid = 0;
-       addr.nl_groups = 0;
-
-       if (this->protocol == NETLINK_XFRM)
-       {
-               chunk_t in_chunk = { (u_char*)in, in->nlmsg_len };
-
-               DBG3(DBG_KNL, "sending %N: %B", xfrm_msg_names, in->nlmsg_type, &in_chunk);
-       }
-
-       while (TRUE)
-       {
-               len = sendto(this->socket, in, in->nlmsg_len, 0,
-                                        (struct sockaddr*)&addr, sizeof(addr));
-
-               if (len != in->nlmsg_len)
-               {
-                       if (errno == EINTR)
-                       {
-                               /* interrupted, try again */
-                               continue;
-                       }
-                       this->mutex->unlock(this->mutex);
-                       DBG1(DBG_KNL, "error sending to netlink socket: %s", strerror(errno));
-                       return FAILED;
-               }
-               break;
-       }
-
-       while (TRUE)
-       {
-               char buf[4096];
-               tmp.len = sizeof(buf);
-               tmp.ptr = buf;
-               msg = (struct nlmsghdr*)tmp.ptr;
-
-               memset(&addr, 0, sizeof(addr));
-               addr.nl_family = AF_NETLINK;
-               addr.nl_pid = getpid();
-               addr.nl_groups = 0;
-               addr_len = sizeof(addr);
-
-               len = recvfrom(this->socket, tmp.ptr, tmp.len, 0,
-                                          (struct sockaddr*)&addr, &addr_len);
-
-               if (len < 0)
-               {
-                       if (errno == EINTR)
-                       {
-                               DBG1(DBG_KNL, "got interrupted");
-                               /* interrupted, try again */
-                               continue;
-                       }
-                       DBG1(DBG_KNL, "error reading from netlink socket: %s", strerror(errno));
-                       this->mutex->unlock(this->mutex);
-                       free(result.ptr);
-                       return FAILED;
-               }
-               if (!NLMSG_OK(msg, len))
-               {
-                       DBG1(DBG_KNL, "received corrupted netlink message");
-                       this->mutex->unlock(this->mutex);
-                       free(result.ptr);
-                       return FAILED;
-               }
-               if (msg->nlmsg_seq != this->seq)
-               {
-                       DBG1(DBG_KNL, "received invalid netlink sequence number");
-                       if (msg->nlmsg_seq < this->seq)
-                       {
-                               continue;
-                       }
-                       this->mutex->unlock(this->mutex);
-                       free(result.ptr);
-                       return FAILED;
-               }
-
-               tmp.len = len;
-               result.ptr = realloc(result.ptr, result.len + tmp.len);
-               memcpy(result.ptr + result.len, tmp.ptr, tmp.len);
-               result.len += tmp.len;
-
-               /* NLM_F_MULTI flag does not seem to be set correctly, we use sequence
-                * numbers to detect multi header messages */
-               len = recvfrom(this->socket, &peek, sizeof(peek), MSG_PEEK | MSG_DONTWAIT,
-                                          (struct sockaddr*)&addr, &addr_len);
-
-               if (len == sizeof(peek) && peek.nlmsg_seq == this->seq)
-               {
-                       /* seems to be multipart */
-                       continue;
-               }
-               break;
-       }
-
-       *out_len = result.len;
-       *out = (struct nlmsghdr*)result.ptr;
-
-       this->mutex->unlock(this->mutex);
-
-       return SUCCESS;
-}
-
-/**
- * Implementation of netlink_socket_t.send_ack.
- */
-static status_t netlink_send_ack(private_netlink_socket_t *this, struct nlmsghdr *in)
-{
-       struct nlmsghdr *out, *hdr;
-       size_t len;
-
-       if (netlink_send(this, in, &out, &len) != SUCCESS)
-       {
-               return FAILED;
-       }
-       hdr = out;
-       while (NLMSG_OK(hdr, len))
-       {
-               switch (hdr->nlmsg_type)
-               {
-                       case NLMSG_ERROR:
-                       {
-                               struct nlmsgerr* err = (struct nlmsgerr*)NLMSG_DATA(hdr);
-
-                               if (err->error)
-                               {
-                                       if (-err->error == EEXIST)
-                                       {       /* do not report existing routes */
-                                               free(out);
-                                               return ALREADY_DONE;
-                                       }
-                                       DBG1(DBG_KNL, "received netlink error: %s (%d)",
-                                                strerror(-err->error), -err->error);
-                                       free(out);
-                                       return FAILED;
-                               }
-                               free(out);
-                               return SUCCESS;
-                       }
-                       default:
-                               hdr = NLMSG_NEXT(hdr, len);
-                               continue;
-                       case NLMSG_DONE:
-                               break;
-               }
-               break;
-       }
-       DBG1(DBG_KNL, "netlink request not acknowledged");
-       free(out);
-       return FAILED;
-}
-
-/**
- * Implementation of netlink_socket_t.destroy.
- */
-static void destroy(private_netlink_socket_t *this)
-{
-       if (this->socket > 0)
-       {
-               close(this->socket);
-       }
-       this->mutex->destroy(this->mutex);
-       free(this);
-}
-
-/**
- * Described in header.
- */
-netlink_socket_t *netlink_socket_create(int protocol)
-{
-       private_netlink_socket_t *this = malloc_thing(private_netlink_socket_t);
-       struct sockaddr_nl addr;
-
-       /* public functions */
-       this->public.send = (status_t(*)(netlink_socket_t*,struct nlmsghdr*, struct nlmsghdr**, size_t*))netlink_send;
-       this->public.send_ack = (status_t(*)(netlink_socket_t*,struct nlmsghdr*))netlink_send_ack;
-       this->public.destroy = (void(*)(netlink_socket_t*))destroy;
-
-       /* private members */
-       this->seq = 200;
-       this->mutex = mutex_create(MUTEX_TYPE_DEFAULT);
-
-       memset(&addr, 0, sizeof(addr));
-       addr.nl_family = AF_NETLINK;
-
-       this->protocol = protocol;
-       this->socket = socket(AF_NETLINK, SOCK_RAW, protocol);
-       if (this->socket < 0)
-       {
-               DBG1(DBG_KNL, "unable to create netlink socket");
-               destroy(this);
-               return NULL;
-       }
-
-       addr.nl_groups = 0;
-       if (bind(this->socket, (struct sockaddr*)&addr, sizeof(addr)))
-       {
-               DBG1(DBG_KNL, "unable to bind netlink socket");
-               destroy(this);
-               return NULL;
-       }
-
-       return &this->public;
-}
-
-/**
- * Described in header.
- */
-void netlink_add_attribute(struct nlmsghdr *hdr, int rta_type, chunk_t data,
-                                                 size_t buflen)
-{
-       struct rtattr *rta;
-
-       if (NLMSG_ALIGN(hdr->nlmsg_len) + RTA_ALIGN(data.len) > buflen)
-       {
-               DBG1(DBG_KNL, "unable to add attribute, buffer too small");
-               return;
-       }
-
-       rta = (struct rtattr*)(((char*)hdr) + NLMSG_ALIGN(hdr->nlmsg_len));
-       rta->rta_type = rta_type;
-       rta->rta_len = RTA_LENGTH(data.len);
-       memcpy(RTA_DATA(rta), data.ptr, data.len);
-       hdr->nlmsg_len = NLMSG_ALIGN(hdr->nlmsg_len) + rta->rta_len;
-}
diff --git a/src/libcharon/plugins/kernel_netlink/kernel_netlink_shared.h b/src/libcharon/plugins/kernel_netlink/kernel_netlink_shared.h
deleted file mode 100644 (file)
index dfd27a2..0000000
+++ /dev/null
@@ -1,77 +0,0 @@
-/*
- * Copyright (C) 2