Added an advanced duplicate checking plugin with liveness check of old SA
authorMartin Willi <martin@revosec.ch>
Wed, 9 Feb 2011 14:04:21 +0000 (15:04 +0100)
committerMartin Willi <martin@revosec.ch>
Mon, 28 Feb 2011 15:37:18 +0000 (15:37 +0000)
configure.in
src/libcharon/Makefile.am
src/libcharon/plugins/duplicheck/Makefile.am [new file with mode: 0644]
src/libcharon/plugins/duplicheck/duplicheck_listener.c [new file with mode: 0644]
src/libcharon/plugins/duplicheck/duplicheck_listener.h [new file with mode: 0644]
src/libcharon/plugins/duplicheck/duplicheck_plugin.c [new file with mode: 0644]
src/libcharon/plugins/duplicheck/duplicheck_plugin.h [new file with mode: 0644]

index 3948362..938afb0 100644 (file)
@@ -168,6 +168,7 @@ ARG_ENABL_SET([nm],             [enable NetworkManager plugin.])
 ARG_ENABL_SET([ha],             [enable high availability cluster plugin.])
 ARG_ENABL_SET([whitelist],      [enable peer identity whitelisting plugin.])
 ARG_ENABL_SET([led],            [enable plugin to control LEDs on IKEv2 activity using the Linux kernel LED subsystem.])
+ARG_ENABL_SET([duplicheck],     [advanced duplicate checking plugin using liveness checks.])
 ARG_ENABL_SET([vstr],           [enforce using the Vstr string library to replace glibc-like printf hooks.])
 ARG_ENABL_SET([monolithic],     [build monolithic version of libstrongswan that includes all enabled plugins. Similarly, the plugins of charon are assembled in libcharon.])
 
@@ -777,6 +778,7 @@ ADD_PLUGIN([android],              [c libcharon])
 ADD_PLUGIN([ha],                   [c libcharon])
 ADD_PLUGIN([whitelist],            [c libcharon])
 ADD_PLUGIN([led],                  [c libcharon])
+ADD_PLUGIN([duplicheck],           [c libcharon])
 ADD_PLUGIN([maemo],                [c libcharon])
 ADD_PLUGIN([uci],                  [c libcharon])
 ADD_PLUGIN([addrblock],            [c libcharon])
@@ -857,6 +859,7 @@ AM_CONDITIONAL(USE_LOAD_TESTER, test x$load_tester = xtrue)
 AM_CONDITIONAL(USE_HA, test x$ha = xtrue)
 AM_CONDITIONAL(USE_WHITELIST, test x$whitelist = xtrue)
 AM_CONDITIONAL(USE_LED, test x$led = xtrue)
+AM_CONDITIONAL(USE_DUPLICHECK, test x$duplicheck = xtrue)
 AM_CONDITIONAL(USE_EAP_SIM, test x$eap_sim = xtrue)
 AM_CONDITIONAL(USE_EAP_SIM_FILE, test x$eap_sim_file = xtrue)
 AM_CONDITIONAL(USE_EAP_SIMAKA_SQL, test x$eap_simaka_sql = xtrue)
@@ -1039,6 +1042,7 @@ AC_OUTPUT(
        src/libcharon/plugins/ha/Makefile
        src/libcharon/plugins/whitelist/Makefile
        src/libcharon/plugins/led/Makefile
+       src/libcharon/plugins/duplicheck/Makefile
        src/libcharon/plugins/android/Makefile
        src/libcharon/plugins/maemo/Makefile
        src/libcharon/plugins/stroke/Makefile
index 7ae04f7..8a4f891 100644 (file)
@@ -417,6 +417,13 @@ if MONOLITHIC
 endif
 endif
 
+if USE_DUPLICHECK
+  SUBDIRS += plugins/duplicheck
+if MONOLITHIC
+  libcharon_la_LIBADD += plugins/duplicheck/libstrongswan-duplicheck.la
+endif
+endif
+
 if USE_UCI
   SUBDIRS += plugins/uci
 if MONOLITHIC
diff --git a/src/libcharon/plugins/duplicheck/Makefile.am b/src/libcharon/plugins/duplicheck/Makefile.am
new file mode 100644 (file)
index 0000000..1e2ea7f
--- /dev/null
@@ -0,0 +1,16 @@
+
+INCLUDES = -I$(top_srcdir)/src/libstrongswan -I$(top_srcdir)/src/libhydra \
+       -I$(top_srcdir)/src/libcharon
+
+AM_CFLAGS = -rdynamic
+
+if MONOLITHIC
+noinst_LTLIBRARIES = libstrongswan-duplicheck.la
+else
+plugin_LTLIBRARIES = libstrongswan-duplicheck.la
+endif
+
+libstrongswan_duplicheck_la_SOURCES = duplicheck_plugin.h duplicheck_plugin.c \
+       duplicheck_listener.h duplicheck_listener.c
+
+libstrongswan_duplicheck_la_LDFLAGS = -module -avoid-version
diff --git a/src/libcharon/plugins/duplicheck/duplicheck_listener.c b/src/libcharon/plugins/duplicheck/duplicheck_listener.c
new file mode 100644 (file)
index 0000000..6e23daa
--- /dev/null
@@ -0,0 +1,235 @@
+/*
+ * Copyright (C) 2011 Martin Willi
+ * Copyright (C) 2011 revosec AG
+ *
+ * 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 "duplicheck_listener.h"
+
+#include <daemon.h>
+#include <threading/mutex.h>
+#include <utils/hashtable.h>
+#include <encoding/payloads/delete_payload.h>
+#include <processing/jobs/delete_ike_sa_job.h>
+
+typedef struct private_duplicheck_listener_t private_duplicheck_listener_t;
+
+/**
+ * Private data of an duplicheck_listener_t object.
+ */
+struct private_duplicheck_listener_t {
+
+       /**
+        * Public duplicheck_listener_t interface.
+        */
+       duplicheck_listener_t public;
+
+       /**
+        * Mutex to lock hashtables
+        */
+       mutex_t *mutex;
+
+       /**
+        * Hashtable of active IKE_SAs, identification_t => entry_t
+        */
+       hashtable_t *active;
+
+       /**
+        * Hashtable with active liveness checks, identification_t => entry_t
+        */
+       hashtable_t *checking;
+};
+
+/**
+ * Entry for hashtables
+ */
+typedef struct {
+       /** peer identity */
+       identification_t *id;
+       /** IKE_SA identifier */
+       ike_sa_id_t *sa;
+} entry_t;
+
+/**
+ * Destroy a hashtable entry
+ */
+static void entry_destroy(entry_t *this)
+{
+       this->id->destroy(this->id);
+       this->sa->destroy(this->sa);
+       free(this);
+}
+
+/**
+ * Hashtable hash function
+ */
+static u_int hash(identification_t *key)
+{
+       return chunk_hash(key->get_encoding(key));
+}
+
+/**
+ * Hashtable equals function
+ */
+static bool equals(identification_t *a, identification_t *b)
+{
+       return a->equals(a, b);
+}
+
+METHOD(listener_t, ike_rekey, bool,
+       private_duplicheck_listener_t *this, ike_sa_t *new, ike_sa_t *old)
+{
+       this->mutex->lock(this->mutex);
+       /* TODO update entires */
+       this->mutex->unlock(this->mutex);
+       return TRUE;
+}
+
+METHOD(listener_t, ike_updown, bool,
+       private_duplicheck_listener_t *this, ike_sa_t *ike_sa, bool up)
+{
+       identification_t *id;
+       ike_sa_id_t *sa;
+       entry_t *entry;
+       job_t *job;
+
+       sa = ike_sa->get_id(ike_sa);
+       id = ike_sa->get_other_id(ike_sa);
+
+       if (up)
+       {
+               INIT(entry,
+                       .id = id->clone(id),
+                       .sa = sa->clone(sa),
+               );
+               this->mutex->lock(this->mutex);
+               entry = this->active->put(this->active, entry->id, entry);
+               this->mutex->unlock(this->mutex);
+               if (entry)
+               {
+                       DBG1(DBG_CFG, "detected duplicate IKE_SA for '%Y', "
+                                "triggering delete for old IKE_SA", id);
+                       job = (job_t*)delete_ike_sa_job_create(entry->sa, TRUE);
+                       this->mutex->lock(this->mutex);
+                       entry = this->checking->put(this->checking, entry->id, entry);
+                       this->mutex->unlock(this->mutex);
+                       lib->processor->queue_job(lib->processor, job);
+                       if (entry)
+                       {
+                               entry_destroy(entry);
+                       }
+               }
+       }
+       else
+       {
+               this->mutex->lock(this->mutex);
+               entry = this->active->remove(this->active, id);
+               if (entry)
+               {
+                       entry_destroy(entry);
+               }
+               entry = this->checking->remove(this->checking, id);
+               this->mutex->unlock(this->mutex);
+               if (entry)
+               {
+                       DBG1(DBG_CFG, "delete for duplicate IKE_SA '%Y' timed out, "
+                                "keeping new IKE_SA", id);
+                       entry_destroy(entry);
+               }
+       }
+       return TRUE;
+}
+
+METHOD(listener_t, message_hook, bool,
+       private_duplicheck_listener_t *this, ike_sa_t *ike_sa,
+       message_t *message, bool incoming)
+{
+       if (incoming && !message->get_request(message))
+       {
+               identification_t *id;
+               entry_t *entry;
+
+               id = ike_sa->get_other_id(ike_sa);
+               this->mutex->lock(this->mutex);
+               entry = this->checking->remove(this->checking, id);
+               this->mutex->unlock(this->mutex);
+               if (entry)
+               {
+                       DBG1(DBG_CFG, "got a response on a duplicate IKE_SA for '%Y', "
+                                "deleting new IKE_SA", id);
+                       entry_destroy(entry);
+                       this->mutex->lock(this->mutex);
+                       entry = this->active->remove(this->active, id);
+                       this->mutex->unlock(this->mutex);
+                       if (entry)
+                       {
+                               lib->processor->queue_job(lib->processor,
+                                               (job_t*)delete_ike_sa_job_create(entry->sa, TRUE));
+                               entry_destroy(entry);
+                       }
+               }
+       }
+       return TRUE;
+}
+
+METHOD(duplicheck_listener_t, destroy, void,
+       private_duplicheck_listener_t *this)
+{
+       enumerator_t *enumerator;
+       identification_t *key;
+       entry_t *value;
+
+       enumerator = this->active->create_enumerator(this->active);
+       while (enumerator->enumerate(enumerator, &key, &value))
+       {
+               entry_destroy(value);
+       }
+       enumerator->destroy(enumerator);
+
+       enumerator = this->checking->create_enumerator(this->checking);
+       while (enumerator->enumerate(enumerator, &key, &value))
+       {
+               entry_destroy(value);
+       }
+       enumerator->destroy(enumerator);
+
+       this->active->destroy(this->active);
+       this->checking->destroy(this->checking);
+       this->mutex->destroy(this->mutex);
+       free(this);
+}
+
+/**
+ * See header
+ */
+duplicheck_listener_t *duplicheck_listener_create()
+{
+       private_duplicheck_listener_t *this;
+
+       INIT(this,
+               .public = {
+                       .listener = {
+                               .ike_rekey = _ike_rekey,
+                               .ike_updown = _ike_updown,
+                               .message = _message_hook,
+                       },
+                       .destroy = _destroy,
+               },
+               .mutex = mutex_create(MUTEX_TYPE_DEFAULT),
+               .active = hashtable_create((hashtable_hash_t)hash,
+                                                                  (hashtable_equals_t)equals, 32),
+               .checking = hashtable_create((hashtable_hash_t)hash,
+                                                                        (hashtable_equals_t)equals, 2),
+       );
+
+       return &this->public;
+}
diff --git a/src/libcharon/plugins/duplicheck/duplicheck_listener.h b/src/libcharon/plugins/duplicheck/duplicheck_listener.h
new file mode 100644 (file)
index 0000000..8f1a27e
--- /dev/null
@@ -0,0 +1,49 @@
+/*
+ * Copyright (C) 2011 Martin Willi
+ * Copyright (C) 2011 revosec AG
+ *
+ * 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 duplicheck_listener duplicheck_listener
+ * @{ @ingroup duplicheck
+ */
+
+#ifndef DUPLICHECK_LISTENER_H_
+#define DUPLICHECK_LISTENER_H_
+
+#include <bus/listeners/listener.h>
+
+typedef struct duplicheck_listener_t duplicheck_listener_t;
+
+/**
+ * Listener checking for duplicates.
+ */
+struct duplicheck_listener_t {
+
+       /**
+        * Implements listener_t interface.
+        */
+       listener_t listener;
+
+       /**
+        * Destroy a duplicheck_listener_t.
+        */
+       void (*destroy)(duplicheck_listener_t *this);
+};
+
+/**
+ * Create a duplicheck_listener instance.
+ */
+duplicheck_listener_t *duplicheck_listener_create();
+
+#endif /** DUPLICHECK_LISTENER_H_ @}*/
diff --git a/src/libcharon/plugins/duplicheck/duplicheck_plugin.c b/src/libcharon/plugins/duplicheck/duplicheck_plugin.c
new file mode 100644 (file)
index 0000000..cbb575a
--- /dev/null
@@ -0,0 +1,67 @@
+/*
+ * Copyright (C) 2011 Martin Willi
+ * Copyright (C) 2011 revosec AG
+ *
+ * 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 "duplicheck_plugin.h"
+
+#include "duplicheck_listener.h"
+
+#include <daemon.h>
+
+typedef struct private_duplicheck_plugin_t private_duplicheck_plugin_t;
+
+/**
+ * Private data of duplicheck plugin
+ */
+struct private_duplicheck_plugin_t {
+
+       /**
+        * Implements plugin interface
+        */
+       duplicheck_plugin_t public;
+
+       /**
+        * Listener doing duplicate checks
+        */
+       duplicheck_listener_t *listener;
+};
+
+METHOD(plugin_t, destroy, void,
+       private_duplicheck_plugin_t *this)
+{
+       charon->bus->remove_listener(charon->bus, &this->listener->listener);
+       this->listener->destroy(this->listener);
+       free(this);
+}
+
+/**
+ * Plugin constructor
+ */
+plugin_t *duplicheck_plugin_create()
+{
+       private_duplicheck_plugin_t *this;
+
+       INIT(this,
+               .public = {
+                       .plugin = {
+                               .destroy = _destroy,
+                       },
+               },
+               .listener = duplicheck_listener_create(),
+       );
+
+       charon->bus->add_listener(charon->bus, &this->listener->listener);
+
+       return &this->public.plugin;
+}
diff --git a/src/libcharon/plugins/duplicheck/duplicheck_plugin.h b/src/libcharon/plugins/duplicheck/duplicheck_plugin.h
new file mode 100644 (file)
index 0000000..3dddf14
--- /dev/null
@@ -0,0 +1,42 @@
+/*
+ * Copyright (C) 2011 Martin Willi
+ * Copyright (C) 2011 revosec AG
+ *
+ * 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 duplicheck duplicheck
+ * @ingroup cplugins
+ *
+ * @defgroup duplicheck_plugin duplicheck_plugin
+ * @{ @ingroup duplicheck
+ */
+
+#ifndef DUPLICHECK_PLUGIN_H_
+#define DUPLICHECK_PLUGIN_H_
+
+#include <plugins/plugin.h>
+
+typedef struct duplicheck_plugin_t duplicheck_plugin_t;
+
+/**
+ * Advanced duplicate checking using liveness checks.
+ */
+struct duplicheck_plugin_t {
+
+       /**
+        * Implements plugin interface
+        */
+       plugin_t plugin;
+};
+
+#endif /** DUPLICHECK_PLUGIN_H_ @}*/