Add Cisco Unity client support for Split-Include and Local-LAN
authorMartin Willi <martin@revosec.ch>
Mon, 23 Jul 2012 15:14:47 +0000 (17:14 +0200)
committerMartin Willi <martin@revosec.ch>
Tue, 18 Sep 2012 15:17:47 +0000 (17:17 +0200)
configure.in
src/libcharon/Makefile.am
src/libcharon/plugins/unity/Makefile.am [new file with mode: 0644]
src/libcharon/plugins/unity/unity_handler.c [new file with mode: 0644]
src/libcharon/plugins/unity/unity_handler.h [new file with mode: 0644]
src/libcharon/plugins/unity/unity_narrow.c [new file with mode: 0644]
src/libcharon/plugins/unity/unity_narrow.h [new file with mode: 0644]
src/libcharon/plugins/unity/unity_plugin.c [new file with mode: 0644]
src/libcharon/plugins/unity/unity_plugin.h [new file with mode: 0644]

index 7a76efa..03dc5ac 100644 (file)
@@ -206,6 +206,7 @@ ARG_ENABL_SET([ctr],            [enables the Counter Mode wrapper crypto plugin.
 ARG_ENABL_SET([ccm],            [enables the CCM AEAD wrapper crypto plugin.])
 ARG_ENABL_SET([gcm],            [enables the GCM AEAD wrapper crypto plugin.])
 ARG_ENABL_SET([addrblock],      [enables RFC 3779 address block constraint support.])
+ARG_ENABL_SET([unity],          [enables Cisco Unity extension plugin.])
 ARG_ENABL_SET([uci],            [enable OpenWRT UCI configuration plugin.])
 ARG_ENABL_SET([android],        [enable Android specific plugin.])
 ARG_ENABL_SET([android-log],    [enable Android specific logger plugin.])
@@ -953,6 +954,7 @@ ADD_PLUGIN([radattr],              [c charon])
 ADD_PLUGIN([maemo],                [c charon])
 ADD_PLUGIN([uci],                  [c charon])
 ADD_PLUGIN([addrblock],            [c charon])
+ADD_PLUGIN([unity],                [c charon])
 ADD_PLUGIN([unit-tester],          [c charon])
 
 AC_SUBST(charon_plugins)
@@ -1078,6 +1080,7 @@ AM_CONDITIONAL(USE_SOCKET_DEFAULT, test x$socket_default = xtrue)
 AM_CONDITIONAL(USE_SOCKET_DYNAMIC, test x$socket_dynamic = xtrue)
 AM_CONDITIONAL(USE_FARP, test x$farp = xtrue)
 AM_CONDITIONAL(USE_ADDRBLOCK, test x$addrblock = xtrue)
+AM_CONDITIONAL(USE_UNITY, test x$unity = xtrue)
 
 dnl hydra plugins
 dnl =============
@@ -1257,6 +1260,7 @@ AC_OUTPUT(
        src/libcharon/plugins/medsrv/Makefile
        src/libcharon/plugins/medcli/Makefile
        src/libcharon/plugins/addrblock/Makefile
+       src/libcharon/plugins/unity/Makefile
        src/libcharon/plugins/uci/Makefile
        src/libcharon/plugins/ha/Makefile
        src/libcharon/plugins/whitelist/Makefile
index bc9a6f2..56192bf 100644 (file)
@@ -533,6 +533,13 @@ if MONOLITHIC
 endif
 endif
 
+if USE_UNITY
+  SUBDIRS += plugins/unity
+if MONOLITHIC
+  libcharon_la_LIBADD += plugins/unity/libstrongswan-unity.la
+endif
+endif
+
 if USE_UNIT_TESTS
   SUBDIRS += plugins/unit_tester
 if MONOLITHIC
diff --git a/src/libcharon/plugins/unity/Makefile.am b/src/libcharon/plugins/unity/Makefile.am
new file mode 100644 (file)
index 0000000..4c3cb88
--- /dev/null
@@ -0,0 +1,18 @@
+
+INCLUDES = -I$(top_srcdir)/src/libstrongswan -I$(top_srcdir)/src/libhydra \
+       -I$(top_srcdir)/src/libcharon
+
+AM_CFLAGS = -rdynamic
+
+if MONOLITHIC
+noinst_LTLIBRARIES = libstrongswan-unity.la
+else
+plugin_LTLIBRARIES = libstrongswan-unity.la
+endif
+
+libstrongswan_unity_la_SOURCES = \
+       unity_plugin.h unity_plugin.c \
+       unity_handler.h unity_handler.c \
+       unity_narrow.h unity_narrow.c
+
+libstrongswan_unity_la_LDFLAGS = -module -avoid-version
diff --git a/src/libcharon/plugins/unity/unity_handler.c b/src/libcharon/plugins/unity/unity_handler.c
new file mode 100644 (file)
index 0000000..afccaa5
--- /dev/null
@@ -0,0 +1,426 @@
+/*
+ * Copyright (C) 2012 Martin Willi
+ * Copyright (C) 2012 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 "unity_handler.h"
+
+#include <daemon.h>
+#include <threading/mutex.h>
+#include <utils/linked_list.h>
+#include <processing/jobs/callback_job.h>
+
+typedef struct private_unity_handler_t private_unity_handler_t;
+
+/**
+ * Private data of an unity_handler_t object.
+ */
+struct private_unity_handler_t {
+
+       /**
+        * Public unity_handler_t interface.
+        */
+       unity_handler_t public;
+
+       /**
+        * List of subnets to include, as entry_t
+        */
+       linked_list_t *include;
+
+       /**
+        * Mutex for concurrent access to lists
+        */
+       mutex_t *mutex;
+};
+
+/**
+ * Traffic selector entry for networks to include under a given IKE_SA
+ */
+typedef struct {
+       /** associated IKE_SA, unique ID */
+       u_int32_t sa;
+       /** traffic selector to include/exclude */
+       traffic_selector_t *ts;
+} entry_t;
+
+/**
+ * Clean up an entry
+ */
+static void entry_destroy(entry_t *this)
+{
+       this->ts->destroy(this->ts);
+       free(this);
+}
+
+/**
+ * Create a traffic selector from a unity subnet definition
+ */
+static traffic_selector_t *create_ts(chunk_t subnet)
+{
+       chunk_t net, mask;
+       int i;
+
+       if (subnet.len != 8)
+       {
+               return NULL;
+       }
+       net = chunk_create(subnet.ptr, 4);
+       mask = chunk_clonea(chunk_skip(subnet, 4));
+       for (i = 0; i < net.len; i++)
+       {
+               mask.ptr[i] = (mask.ptr[i] ^ 0xFF) | net.ptr[i];
+       }
+       return traffic_selector_create_from_bytes(0, TS_IPV4_ADDR_RANGE,
+                                                                                         net, 0, mask, 65535);
+}
+
+/**
+ * Store a subnet to include in tunnels under this IKE_SA
+ */
+static bool add_include(private_unity_handler_t *this, chunk_t subnet)
+{
+       traffic_selector_t *ts;
+       ike_sa_t *ike_sa;
+       entry_t *entry;
+
+       ike_sa = charon->bus->get_sa(charon->bus);
+       if (!ike_sa)
+       {
+               return FALSE;
+       }
+       ts = create_ts(subnet);
+       if (!ts)
+       {
+               return FALSE;
+       }
+       INIT(entry,
+               .sa = ike_sa->get_unique_id(ike_sa),
+               .ts = ts,
+       );
+
+       this->mutex->lock(this->mutex);
+       this->include->insert_last(this->include, entry);
+       this->mutex->unlock(this->mutex);
+       return TRUE;
+}
+
+/**
+ * Rempve a subnet from the inclusion list for this IKE_SA
+ */
+static bool remove_include(private_unity_handler_t *this, chunk_t subnet)
+{
+       enumerator_t *enumerator;
+       traffic_selector_t *ts;
+       ike_sa_t *ike_sa;
+       entry_t *entry;
+
+       ike_sa = charon->bus->get_sa(charon->bus);
+       if (!ike_sa)
+       {
+               return FALSE;
+       }
+       ts = create_ts(subnet);
+       if (!ts)
+       {
+               return FALSE;
+       }
+
+       this->mutex->lock(this->mutex);
+       enumerator = this->include->create_enumerator(this->include);
+       while (enumerator->enumerate(enumerator, &entry))
+       {
+               if (entry->sa == ike_sa->get_unique_id(ike_sa) &&
+                       ts->equals(ts, entry->ts))
+               {
+                       this->include->remove_at(this->include, enumerator);
+                       entry_destroy(entry);
+                       break;
+               }
+       }
+       enumerator->destroy(enumerator);
+       this->mutex->unlock(this->mutex);
+       ts->destroy(ts);
+       return TRUE;
+}
+
+/**
+ * Create a unique shunt name for a bypass policy
+ */
+static void create_shunt_name(ike_sa_t *ike_sa, traffic_selector_t *ts,
+                                                         char *buf, size_t len)
+{
+       snprintf(buf, len, "Unity (%s[%u]: %R)", ike_sa->get_name(ike_sa),
+                        ike_sa->get_unique_id(ike_sa), ts);
+}
+
+/**
+ * Install entry as a shunt policy
+ */
+static job_requeue_t add_exclude_async(entry_t *entry)
+{
+       enumerator_t *enumerator;
+       child_cfg_t *child_cfg;
+       lifetime_cfg_t lft = {};
+       ike_sa_t *ike_sa;
+       char name[128];
+       host_t *host;
+       bool has_vip = FALSE;
+
+       ike_sa = charon->ike_sa_manager->checkout_by_id(charon->ike_sa_manager,
+                                                                                                       entry->sa, FALSE);
+       if (ike_sa)
+       {
+               create_shunt_name(ike_sa, entry->ts, name, sizeof(name));
+
+               child_cfg = child_cfg_create(name, &lft, NULL, TRUE, MODE_PASS,
+                                                                        ACTION_NONE, ACTION_NONE, ACTION_NONE,
+                                                                        FALSE, 0, 0, NULL, NULL, FALSE);
+               child_cfg->add_traffic_selector(child_cfg, FALSE,
+                                                                               entry->ts->clone(entry->ts));
+               enumerator = ike_sa->create_virtual_ip_enumerator(ike_sa, TRUE);
+               while (enumerator->enumerate(enumerator, &host))
+               {
+                       has_vip = TRUE;
+                       child_cfg->add_traffic_selector(child_cfg, TRUE,
+                               traffic_selector_create_from_subnet(host->clone(host), 32, 0, 0));
+               }
+               enumerator->destroy(enumerator);
+
+               if (!has_vip)
+               {
+                       host = ike_sa->get_my_host(ike_sa);
+                       child_cfg->add_traffic_selector(child_cfg, TRUE,
+                               traffic_selector_create_from_subnet(host->clone(host), 32, 0, 0));
+               }
+               charon->ike_sa_manager->checkin(charon->ike_sa_manager, ike_sa);
+
+               charon->shunts->install(charon->shunts, child_cfg);
+               child_cfg->destroy(child_cfg);
+
+               DBG1(DBG_IKE, "installed %N bypass policy for %R",
+                        configuration_attribute_type_names, UNITY_LOCAL_LAN, entry->ts);
+       }
+       return JOB_REQUEUE_NONE;
+}
+
+/**
+ * Add a bypass policy for a given subnet
+ */
+static bool add_exclude(private_unity_handler_t *this, chunk_t subnet)
+{
+       traffic_selector_t *ts;
+       ike_sa_t *ike_sa;
+       entry_t *entry;
+
+       ike_sa = charon->bus->get_sa(charon->bus);
+       if (!ike_sa)
+       {
+               return FALSE;
+       }
+       ts = create_ts(subnet);
+       if (!ts)
+       {
+               return FALSE;
+       }
+       INIT(entry,
+               .sa = ike_sa->get_unique_id(ike_sa),
+               .ts = ts,
+       );
+
+       /* we can't install the shunt policy yet, as we don't know the virtual IP.
+        * Defer installation using an async callback. */
+       lib->processor->queue_job(lib->processor, (job_t*)
+                                               callback_job_create((void*)add_exclude_async, entry,
+                                                                                       (void*)entry_destroy, NULL));
+       return TRUE;
+}
+
+/**
+ * Remove a bypass policy for a given subnet
+ */
+static bool remove_exclude(private_unity_handler_t *this, chunk_t subnet)
+{
+       traffic_selector_t *ts;
+       ike_sa_t *ike_sa;
+       char name[128];
+
+       ike_sa = charon->bus->get_sa(charon->bus);
+       if (!ike_sa)
+       {
+               return FALSE;
+       }
+       ts = create_ts(subnet);
+       if (!ts)
+       {
+               return FALSE;
+       }
+       create_shunt_name(ike_sa, ts, name, sizeof(name));
+       DBG1(DBG_IKE, "uninstalling %N bypass policy for %R",
+                configuration_attribute_type_names, UNITY_LOCAL_LAN, ts);
+       ts->destroy(ts);
+       return charon->shunts->uninstall(charon->shunts, name);
+}
+
+METHOD(attribute_handler_t, handle, bool,
+       private_unity_handler_t *this, identification_t *id,
+       configuration_attribute_type_t type, chunk_t data)
+{
+       switch (type)
+       {
+               case UNITY_SPLIT_INCLUDE:
+                       return add_include(this, data);
+               case UNITY_LOCAL_LAN:
+                       return add_exclude(this, data);
+               default:
+                       return FALSE;
+       }
+}
+
+METHOD(attribute_handler_t, release, void,
+       private_unity_handler_t *this, identification_t *server,
+       configuration_attribute_type_t type, chunk_t data)
+{
+       switch (type)
+       {
+               case UNITY_SPLIT_INCLUDE:
+                       remove_include(this, data);
+                       break;
+               case UNITY_LOCAL_LAN:
+                       remove_exclude(this, data);
+                       break;
+               default:
+                       break;
+       }
+}
+
+/**
+ * Configuration attributes to request
+ */
+static configuration_attribute_type_t attributes[] = {
+       UNITY_SPLIT_INCLUDE,
+       UNITY_LOCAL_LAN,
+};
+
+/**
+ * Attribute enumerator implementation
+ */
+typedef struct {
+       /** implements enumerator_t */
+       enumerator_t public;
+       /** position in attributes[] */
+       int i;
+} attribute_enumerator_t;
+
+METHOD(enumerator_t, enumerate_attributes, bool,
+       attribute_enumerator_t *this, configuration_attribute_type_t *type,
+       chunk_t *data)
+{
+       if (this->i < countof(attributes))
+       {
+               *type = attributes[this->i++];
+               *data = chunk_empty;
+               return TRUE;
+       }
+       return FALSE;
+}
+
+METHOD(attribute_handler_t, create_attribute_enumerator, enumerator_t *,
+       unity_handler_t *this, identification_t *id, linked_list_t *vips)
+{
+       attribute_enumerator_t *enumerator;
+
+       INIT(enumerator,
+               .public = {
+                       .enumerate = (void*)_enumerate_attributes,
+                       .destroy = (void*)free,
+               },
+       );
+       return &enumerator->public;
+}
+
+typedef struct {
+       /** mutex to unlock */
+       mutex_t *mutex;
+       /** IKE_SA ID to filter for */
+       u_int32_t id;
+} include_filter_t;
+
+/**
+ * Include enumerator filter function
+ */
+static bool include_filter(include_filter_t *data,
+                                                  entry_t **entry, traffic_selector_t **ts)
+{
+       if ((*entry)->sa == data->id)
+       {
+               *ts = (*entry)->ts;
+               return TRUE;
+       }
+       return FALSE;
+}
+
+/**
+ * Destroy include filter data, unlock mutex
+ */
+static void destroy_filter(include_filter_t *data)
+{
+       data->mutex->unlock(data->mutex);
+       free(data);
+}
+
+METHOD(unity_handler_t, create_include_enumerator, enumerator_t*,
+       private_unity_handler_t *this, u_int32_t id)
+{
+       include_filter_t *data;
+
+       INIT(data,
+               .mutex = this->mutex,
+               .id = id,
+       );
+       data->mutex->lock(data->mutex);
+       return enumerator_create_filter(
+                                       this->include->create_enumerator(this->include),
+                                       (void*)include_filter, data, (void*)destroy_filter);
+}
+
+METHOD(unity_handler_t, destroy, void,
+       private_unity_handler_t *this)
+{
+       this->include->destroy(this->include);
+       this->mutex->destroy(this->mutex);
+       free(this);
+}
+
+/**
+ * See header
+ */
+unity_handler_t *unity_handler_create()
+{
+       private_unity_handler_t *this;
+
+       INIT(this,
+               .public = {
+                       .handler = {
+                               .handle = _handle,
+                               .release = _release,
+                               .create_attribute_enumerator = _create_attribute_enumerator,
+                       },
+                       .create_include_enumerator = _create_include_enumerator,
+                       .destroy = _destroy,
+               },
+               .include = linked_list_create(),
+               .mutex = mutex_create(MUTEX_TYPE_DEFAULT),
+       );
+
+       return &this->public;
+}
diff --git a/src/libcharon/plugins/unity/unity_handler.h b/src/libcharon/plugins/unity/unity_handler.h
new file mode 100644 (file)
index 0000000..8656fd3
--- /dev/null
@@ -0,0 +1,58 @@
+/*
+ * Copyright (C) 2012 Martin Willi
+ * Copyright (C) 2012 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 unity_handler unity_handler
+ * @{ @ingroup unity
+ */
+
+#ifndef UNITY_HANDLER_H_
+#define UNITY_HANDLER_H_
+
+#include <attributes/attribute_handler.h>
+
+typedef struct unity_handler_t unity_handler_t;
+
+/**
+ * Cisco Unity attribute handling.
+ */
+struct unity_handler_t {
+
+       /**
+        * Implements attribute_handler_t.
+        */
+       attribute_handler_t handler;
+
+       /**
+        * Create an enumerator over Split-Include attributes received for an IKE_SA.
+        *
+        * @param id                    IKE_SA unique ID to get Split-Includes for
+        * @return                              enumerator over traffic_selector_t*
+        */
+       enumerator_t* (*create_include_enumerator)(unity_handler_t *this,
+                                                                                          u_int32_t id);
+
+       /**
+        * Destroy a unity_handler_t.
+        */
+       void (*destroy)(unity_handler_t *this);
+};
+
+/**
+ * Create a unity_handler instance.
+ */
+unity_handler_t *unity_handler_create();
+
+#endif /** UNITY_HANDLER_H_ @}*/
diff --git a/src/libcharon/plugins/unity/unity_narrow.c b/src/libcharon/plugins/unity/unity_narrow.c
new file mode 100644 (file)
index 0000000..dada26d
--- /dev/null
@@ -0,0 +1,94 @@
+/*
+ * Copyright (C) 2012 Martin Willi
+ * Copyright (C) 2012 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 "unity_narrow.h"
+
+#include <daemon.h>
+
+typedef struct private_unity_narrow_t private_unity_narrow_t;
+
+/**
+ * Private data of an unity_narrow_t object.
+ */
+struct private_unity_narrow_t {
+
+       /**
+        * Public unity_narrow_t interface.
+        */
+       unity_narrow_t public;
+
+       /**
+        * Unity attribute handler
+        */
+       unity_handler_t *handler;
+};
+
+METHOD(listener_t, narrow, bool,
+       private_unity_narrow_t *this, ike_sa_t *ike_sa, child_sa_t *child_sa,
+       narrow_hook_t type, linked_list_t *local, linked_list_t *remote)
+{
+       traffic_selector_t *current, *orig = NULL;
+       enumerator_t *enumerator;
+
+       if (type == NARROW_INITIATOR_POST_AUTH &&
+               remote->get_count(remote) == 1)
+       {
+               enumerator = this->handler->create_include_enumerator(this->handler,
+                                                                                               ike_sa->get_unique_id(ike_sa));
+               while (enumerator->enumerate(enumerator, &current))
+               {
+                       if (orig == NULL)
+                       {       /* got one, replace original TS */
+                               remote->remove_first(remote, (void**)&orig);
+                       }
+                       remote->insert_last(remote, orig->get_subset(orig, current));
+               }
+               enumerator->destroy(enumerator);
+               if (orig)
+               {
+                       DBG1(DBG_CFG, "narrowed CHILD_SA to %N %#R",
+                                configuration_attribute_type_names,
+                                UNITY_SPLIT_INCLUDE, remote);
+                       orig->destroy(orig);
+               }
+       }
+       return TRUE;
+}
+
+METHOD(unity_narrow_t, destroy, void,
+       private_unity_narrow_t *this)
+{
+       free(this);
+}
+
+/**
+ * See header
+ */
+unity_narrow_t *unity_narrow_create(unity_handler_t *handler)
+{
+       private_unity_narrow_t *this;
+
+       INIT(this,
+               .public = {
+                       .listener = {
+                               .narrow = _narrow,
+                       },
+                       .destroy = _destroy,
+               },
+               .handler = handler,
+       );
+
+       return &this->public;
+}
diff --git a/src/libcharon/plugins/unity/unity_narrow.h b/src/libcharon/plugins/unity/unity_narrow.h
new file mode 100644 (file)
index 0000000..5e09685
--- /dev/null
@@ -0,0 +1,51 @@
+/*
+ * Copyright (C) 2012 Martin Willi
+ * Copyright (C) 2012 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 unity_narrow unity_narrow
+ * @{ @ingroup unity
+ */
+
+#ifndef UNITY_NARROW_H_
+#define UNITY_NARROW_H_
+
+#include <bus/listeners/listener.h>
+
+#include "unity_handler.h"
+
+typedef struct unity_narrow_t unity_narrow_t;
+
+/**
+ * Listener that narrows Quick Modes to the Unity Split-Include subnets.
+ */
+struct unity_narrow_t {
+
+       /**
+        * Implements listener_t.
+        */
+       listener_t listener;
+
+       /**
+        * Destroy a unity_narrow_t.
+        */
+       void (*destroy)(unity_narrow_t *this);
+};
+
+/**
+ * Create a unity_narrow instance.
+ */
+unity_narrow_t *unity_narrow_create(unity_handler_t *handler);
+
+#endif /** UNITY_NARROW_H_ @}*/
diff --git a/src/libcharon/plugins/unity/unity_plugin.c b/src/libcharon/plugins/unity/unity_plugin.c
new file mode 100644 (file)
index 0000000..092dfed
--- /dev/null
@@ -0,0 +1,85 @@
+/*
+ * Copyright (C) 2012 Martin Willi
+ * Copyright (C) 2012 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 "unity_plugin.h"
+#include "unity_handler.h"
+#include "unity_narrow.h"
+
+#include <daemon.h>
+#include <hydra.h>
+
+typedef struct private_unity_plugin_t private_unity_plugin_t;
+
+/**
+ * private data of unity_plugin
+ */
+struct private_unity_plugin_t {
+
+       /**
+        * public functions
+        */
+       unity_plugin_t public;
+
+       /**
+        * Handler for UNITY configuration attributes
+        */
+       unity_handler_t *handler;
+
+       /**
+        * Traffic selector narrower, for Unity Split-Includes
+        */
+       unity_narrow_t *narrower;
+};
+
+METHOD(plugin_t, get_name, char*,
+       private_unity_plugin_t *this)
+{
+       return "unity";
+}
+
+METHOD(plugin_t, destroy, void,
+       private_unity_plugin_t *this)
+{
+       charon->bus->remove_listener(charon->bus, &this->narrower->listener);
+       this->narrower->destroy(this->narrower);
+       hydra->attributes->remove_handler(hydra->attributes, &this->handler->handler);
+       this->handler->destroy(this->handler);
+       free(this);
+}
+
+/*
+ * see header file
+ */
+plugin_t *unity_plugin_create()
+{
+       private_unity_plugin_t *this;
+
+       INIT(this,
+               .public = {
+                       .plugin = {
+                               .get_name = _get_name,
+                               .reload = (void*)return_false,
+                               .destroy = _destroy,
+                       },
+               },
+               .handler = unity_handler_create(),
+       );
+       hydra->attributes->add_handler(hydra->attributes, &this->handler->handler);
+
+       this->narrower = unity_narrow_create(this->handler),
+       charon->bus->add_listener(charon->bus, &this->narrower->listener);
+
+       return &this->public.plugin;
+}
diff --git a/src/libcharon/plugins/unity/unity_plugin.h b/src/libcharon/plugins/unity/unity_plugin.h
new file mode 100644 (file)
index 0000000..0d407b5
--- /dev/null
@@ -0,0 +1,42 @@
+/*
+ * Copyright (C) 2012 Martin Willi
+ * Copyright (C) 2012 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 unity unity
+ * @ingroup cplugins
+ *
+ * @defgroup unity_plugin unity_plugin
+ * @{ @ingroup unity
+ */
+
+#ifndef UNITY_PLUGIN_H_
+#define UNITY_PLUGIN_H_
+
+#include <plugins/plugin.h>
+
+typedef struct unity_plugin_t unity_plugin_t;
+
+/**
+ * IKEv1 Cisco Unity extension support.
+ */
+struct unity_plugin_t {
+
+       /**
+        * Implements plugin_t. interface.
+        */
+       plugin_t plugin;
+};
+
+#endif /** UNITY_PLUGIN_H_ @}*/