From 5ff012f717893f632465bc667f563d63df32b655 Mon Sep 17 00:00:00 2001 From: Martin Willi Date: Mon, 23 Jul 2012 17:14:47 +0200 Subject: [PATCH] Add Cisco Unity client support for Split-Include and Local-LAN --- configure.in | 4 + src/libcharon/Makefile.am | 7 + src/libcharon/plugins/unity/Makefile.am | 18 + src/libcharon/plugins/unity/unity_handler.c | 426 ++++++++++++++++++++ src/libcharon/plugins/unity/unity_handler.h | 58 +++ src/libcharon/plugins/unity/unity_narrow.c | 94 +++++ src/libcharon/plugins/unity/unity_narrow.h | 51 +++ src/libcharon/plugins/unity/unity_plugin.c | 85 ++++ src/libcharon/plugins/unity/unity_plugin.h | 42 ++ 9 files changed, 785 insertions(+) create mode 100644 src/libcharon/plugins/unity/Makefile.am create mode 100644 src/libcharon/plugins/unity/unity_handler.c create mode 100644 src/libcharon/plugins/unity/unity_handler.h create mode 100644 src/libcharon/plugins/unity/unity_narrow.c create mode 100644 src/libcharon/plugins/unity/unity_narrow.h create mode 100644 src/libcharon/plugins/unity/unity_plugin.c create mode 100644 src/libcharon/plugins/unity/unity_plugin.h diff --git a/configure.in b/configure.in index 7a76efa9c..03dc5ac65 100644 --- a/configure.in +++ b/configure.in @@ -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 diff --git a/src/libcharon/Makefile.am b/src/libcharon/Makefile.am index bc9a6f28c..56192bf0e 100644 --- a/src/libcharon/Makefile.am +++ b/src/libcharon/Makefile.am @@ -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 index 000000000..4c3cb887e --- /dev/null +++ b/src/libcharon/plugins/unity/Makefile.am @@ -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 index 000000000..afccaa529 --- /dev/null +++ b/src/libcharon/plugins/unity/unity_handler.c @@ -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 . + * + * 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 +#include +#include +#include + +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 index 000000000..8656fd372 --- /dev/null +++ b/src/libcharon/plugins/unity/unity_handler.h @@ -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 . + * + * 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 + +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 index 000000000..dada26dc6 --- /dev/null +++ b/src/libcharon/plugins/unity/unity_narrow.c @@ -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 . + * + * 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 + +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, ¤t)) + { + 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 index 000000000..5e0968518 --- /dev/null +++ b/src/libcharon/plugins/unity/unity_narrow.h @@ -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 . + * + * 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 + +#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 index 000000000..092dfed88 --- /dev/null +++ b/src/libcharon/plugins/unity/unity_plugin.c @@ -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 . + * + * 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 +#include + +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 index 000000000..0d407b561 --- /dev/null +++ b/src/libcharon/plugins/unity/unity_plugin.h @@ -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 . + * + * 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 + +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_ @}*/