diff options
-rw-r--r-- | configure.ac | 4 | ||||
-rw-r--r-- | src/libcharon/Makefile.am | 7 | ||||
-rw-r--r-- | src/libcharon/plugins/bypass_lan/Makefile.am | 18 | ||||
-rw-r--r-- | src/libcharon/plugins/bypass_lan/bypass_lan_listener.c | 216 | ||||
-rw-r--r-- | src/libcharon/plugins/bypass_lan/bypass_lan_listener.h | 49 | ||||
-rw-r--r-- | src/libcharon/plugins/bypass_lan/bypass_lan_plugin.c | 101 | ||||
-rw-r--r-- | src/libcharon/plugins/bypass_lan/bypass_lan_plugin.h | 42 |
7 files changed, 437 insertions, 0 deletions
diff --git a/configure.ac b/configure.ac index 86562bc70..ddedad184 100644 --- a/configure.ac +++ b/configure.ac @@ -254,6 +254,7 @@ ARG_ENABL_SET([tnccs-20], [enable TNCCS 2.0 protocol module.]) ARG_ENABL_SET([tnccs-dynamic], [enable dynamic TNCCS protocol discovery module.]) # misc plugins ARG_ENABL_SET([android-log], [enable Android specific logger plugin.]) +ARG_ENABL_SET([bypass-lan], [enable plugin to install bypass policies for local subnets.]) ARG_ENABL_SET([certexpire], [enable CSV export of expiration dates of used certificates.]) ARG_ENABL_SET([connmark], [enable connmark plugin using conntrack based marks to select return path SA.]) ARG_ENABL_SET([forecast], [enable forecast plugin forwarding broadcast/multicast messages.]) @@ -1395,6 +1396,7 @@ ADD_PLUGIN([resolve], [c charon cmd]) ADD_PLUGIN([socket-default], [c charon nm cmd]) ADD_PLUGIN([socket-dynamic], [c charon cmd]) ADD_PLUGIN([socket-win], [c charon]) +ADD_PLUGIN([bypass-lan], [c charon nm cmd]) ADD_PLUGIN([connmark], [c charon]) ADD_PLUGIN([forecast], [c charon]) ADD_PLUGIN([farp], [c charon]) @@ -1616,6 +1618,7 @@ AM_CONDITIONAL(USE_IMV_HCD, test x$imv_hcd = xtrue) AM_CONDITIONAL(USE_SOCKET_DEFAULT, test x$socket_default = xtrue) AM_CONDITIONAL(USE_SOCKET_DYNAMIC, test x$socket_dynamic = xtrue) AM_CONDITIONAL(USE_SOCKET_WIN, test x$socket_win = xtrue) +AM_CONDITIONAL(USE_BYPASS_LAN, test x$bypass_lan = xtrue) AM_CONDITIONAL(USE_CONNMARK, test x$connmark = xtrue) AM_CONDITIONAL(USE_FORECAST, test x$forecast = xtrue) AM_CONDITIONAL(USE_FARP, test x$farp = xtrue) @@ -1864,6 +1867,7 @@ AC_CONFIG_FILES([ src/libcharon/plugins/socket_default/Makefile src/libcharon/plugins/socket_dynamic/Makefile src/libcharon/plugins/socket_win/Makefile + src/libcharon/plugins/bypass_lan/Makefile src/libcharon/plugins/connmark/Makefile src/libcharon/plugins/forecast/Makefile src/libcharon/plugins/farp/Makefile diff --git a/src/libcharon/Makefile.am b/src/libcharon/Makefile.am index 6fa995a30..18f2dee10 100644 --- a/src/libcharon/Makefile.am +++ b/src/libcharon/Makefile.am @@ -227,6 +227,13 @@ if MONOLITHIC endif endif +if USE_BYPASS_LAN + SUBDIRS += plugins/bypass_lan +if MONOLITHIC + libcharon_la_LIBADD += plugins/bypass_lan/libstrongswan-bypass-lan.la +endif +endif + if USE_FORECAST SUBDIRS += plugins/forecast if MONOLITHIC diff --git a/src/libcharon/plugins/bypass_lan/Makefile.am b/src/libcharon/plugins/bypass_lan/Makefile.am new file mode 100644 index 000000000..c1313f6ba --- /dev/null +++ b/src/libcharon/plugins/bypass_lan/Makefile.am @@ -0,0 +1,18 @@ +AM_CPPFLAGS = \ + -I$(top_srcdir)/src/libstrongswan \ + -I$(top_srcdir)/src/libcharon + +AM_CFLAGS = \ + $(PLUGIN_CFLAGS) + +if MONOLITHIC +noinst_LTLIBRARIES = libstrongswan-bypass-lan.la +else +plugin_LTLIBRARIES = libstrongswan-bypass-lan.la +endif + +libstrongswan_bypass_lan_la_SOURCES = \ + bypass_lan_plugin.h bypass_lan_plugin.c \ + bypass_lan_listener.h bypass_lan_listener.c + +libstrongswan_bypass_lan_la_LDFLAGS = -module -avoid-version diff --git a/src/libcharon/plugins/bypass_lan/bypass_lan_listener.c b/src/libcharon/plugins/bypass_lan/bypass_lan_listener.c new file mode 100644 index 000000000..7963677bf --- /dev/null +++ b/src/libcharon/plugins/bypass_lan/bypass_lan_listener.c @@ -0,0 +1,216 @@ +/* + * Copyright (C) 2016 Tobias Brunner + * HSR 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 "bypass_lan_listener.h" + +#include <collections/hashtable.h> +#include <threading/mutex.h> +#include <processing/jobs/callback_job.h> + +#include <daemon.h> + +typedef struct private_bypass_lan_listener_t private_bypass_lan_listener_t; + +/** + * Private data + */ +struct private_bypass_lan_listener_t { + + /** + * Public interface. + */ + bypass_lan_listener_t public; + + /** + * Currently installed bypass policies, bypass_policy_t* + */ + hashtable_t *policies; + + /** + * Mutex to access list of policies + */ + mutex_t *mutex; +}; + +/** + * Data for bypass policies + */ +typedef struct { + private_bypass_lan_listener_t *listener; + host_t *net; + uint8_t mask; + child_cfg_t *cfg; +} bypass_policy_t; + +/** + * Destroy a bypass policy + */ +static void bypass_policy_destroy(bypass_policy_t *this) +{ + traffic_selector_t *ts; + + if (this->cfg) + { + ts = traffic_selector_create_from_subnet(this->net->clone(this->net), + this->mask, 0, 0, 65535); + DBG1(DBG_IKE, "uninstalling bypass policy for %R", ts); + charon->shunts->uninstall(charon->shunts, + this->cfg->get_name(this->cfg)); + this->cfg->destroy(this->cfg); + ts->destroy(ts); + } + this->net->destroy(this->net); + free(this); +} + +/** + * Hash a bypass policy + */ +static u_int policy_hash(bypass_policy_t *policy) +{ + return chunk_hash_inc(policy->net->get_address(policy->net), + chunk_hash(chunk_from_thing(policy->mask))); +} + +/** + * Compare bypass policy + */ +static bool policy_equals(bypass_policy_t *a, bypass_policy_t *b) +{ + return a->mask == b->mask && a->net->equals(a->net, b->net); +} + +/** + * Job updating bypass policies + */ +static job_requeue_t update_bypass(private_bypass_lan_listener_t *this) +{ + enumerator_t *enumerator; + hashtable_t *seen; + bypass_policy_t *found, *lookup; + host_t *net; + uint8_t mask; + + seen = hashtable_create((hashtable_hash_t)policy_hash, + (hashtable_equals_t)policy_equals, 4); + + this->mutex->lock(this->mutex); + + enumerator = charon->kernel->create_local_subnet_enumerator(charon->kernel); + while (enumerator->enumerate(enumerator, &net, &mask)) + { + INIT(lookup, + .net = net->clone(net), + .mask = mask, + ); + seen->put(seen, lookup, lookup); + + found = this->policies->get(this->policies, lookup); + if (!found) + { + child_cfg_create_t child = { + .mode = MODE_PASS, + }; + child_cfg_t *cfg; + traffic_selector_t *ts; + char name[128]; + + ts = traffic_selector_create_from_subnet(net->clone(net), mask, + 0, 0, 65535); + snprintf(name, sizeof(name), "Bypass LAN %R", ts); + + cfg = child_cfg_create(name, &child); + cfg->add_traffic_selector(cfg, FALSE, ts->clone(ts)); + cfg->add_traffic_selector(cfg, TRUE, ts); + charon->shunts->install(charon->shunts, cfg); + DBG1(DBG_IKE, "installed bypass policy for %R", ts); + + INIT(found, + .net = net->clone(net), + .mask = mask, + .cfg = cfg, + ); + this->policies->put(this->policies, found, found); + } + } + enumerator->destroy(enumerator); + + enumerator = this->policies->create_enumerator(this->policies); + while (enumerator->enumerate(enumerator, NULL, &lookup)) + { + if (!seen->get(seen, lookup)) + { + this->policies->remove_at(this->policies, enumerator); + bypass_policy_destroy(lookup); + } + } + enumerator->destroy(enumerator); + this->mutex->unlock(this->mutex); + + seen->destroy_function(seen, (void*)bypass_policy_destroy); + return JOB_REQUEUE_NONE; +} + +METHOD(kernel_listener_t, roam, bool, + private_bypass_lan_listener_t *this, bool address) +{ + lib->processor->queue_job(lib->processor, + (job_t*)callback_job_create((callback_job_cb_t)update_bypass, this, + NULL, (callback_job_cancel_t)return_false)); + return TRUE; +} + +METHOD(bypass_lan_listener_t, destroy, void, + private_bypass_lan_listener_t *this) +{ + enumerator_t *enumerator; + bypass_policy_t *policy; + + enumerator = this->policies->create_enumerator(this->policies); + while (enumerator->enumerate(enumerator, NULL, &policy)) + { + bypass_policy_destroy(policy); + } + enumerator->destroy(enumerator); + this->policies->destroy(this->policies); + this->mutex->destroy(this->mutex); + free(this); +} + +/* + * See header + */ +bypass_lan_listener_t *bypass_lan_listener_create() +{ + private_bypass_lan_listener_t *this; + + INIT(this, + .public = { + .listener = { + .roam = _roam, + }, + .destroy = _destroy, + }, + .policies = hashtable_create((hashtable_hash_t)policy_hash, + (hashtable_equals_t)policy_equals, 4), + .mutex = mutex_create(MUTEX_TYPE_DEFAULT), + ); + + /* FIXME: schedule this? */ + lib->processor->queue_job(lib->processor, + (job_t*)callback_job_create((callback_job_cb_t)update_bypass, this, + NULL, (callback_job_cancel_t)return_false)); + return &this->public; +} diff --git a/src/libcharon/plugins/bypass_lan/bypass_lan_listener.h b/src/libcharon/plugins/bypass_lan/bypass_lan_listener.h new file mode 100644 index 000000000..5d4b73245 --- /dev/null +++ b/src/libcharon/plugins/bypass_lan/bypass_lan_listener.h @@ -0,0 +1,49 @@ +/* + * Copyright (C) 2016 Tobias Brunner + * HSR 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 bypass_lan_listener bypass_lan_listener + * @{ @ingroup bypass_lan + */ + +#ifndef BYPASS_LAN_LISTENER_H_ +#define BYPASS_LAN_LISTENER_H_ + +#include <bus/listeners/listener.h> + +typedef struct bypass_lan_listener_t bypass_lan_listener_t; + +/** + * Listener to install bypass policies + */ +struct bypass_lan_listener_t { + + /** + * Implements kernel_listener_t interface. + */ + kernel_listener_t listener; + + /** + * Destroy a bypass_lan_listener_t. + */ + void (*destroy)(bypass_lan_listener_t *this); +}; + +/** + * Create a bypass_lan_listener instance. + */ +bypass_lan_listener_t *bypass_lan_listener_create(); + +#endif /** BYPASS_LAN_LISTENER_H_ @}*/ diff --git a/src/libcharon/plugins/bypass_lan/bypass_lan_plugin.c b/src/libcharon/plugins/bypass_lan/bypass_lan_plugin.c new file mode 100644 index 000000000..aea7ece7e --- /dev/null +++ b/src/libcharon/plugins/bypass_lan/bypass_lan_plugin.c @@ -0,0 +1,101 @@ +/* + * Copyright (C) 2016 Tobias Brunner + * HSR 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 "bypass_lan_plugin.h" +#include "bypass_lan_listener.h" + +#include <daemon.h> + +typedef struct private_bypass_lan_plugin_t private_bypass_lan_plugin_t; + +/** + * Private data + */ +struct private_bypass_lan_plugin_t { + + /** + * Public interface + */ + bypass_lan_plugin_t public; + + /** + * Listener installing bypass policies + */ + bypass_lan_listener_t *listener; +}; + +METHOD(plugin_t, get_name, char*, + private_bypass_lan_plugin_t *this) +{ + return "bypass-lan"; +} + +/** + * Register listener + */ +static bool plugin_cb(private_bypass_lan_plugin_t *this, + plugin_feature_t *feature, bool reg, void *cb_data) +{ + if (reg) + { + charon->kernel->add_listener(charon->kernel, + &this->listener->listener); + } + else + { + charon->kernel->remove_listener(charon->kernel, + &this->listener->listener); + } + return TRUE; +} + +METHOD(plugin_t, get_features, int, + private_bypass_lan_plugin_t *this, plugin_feature_t *features[]) +{ + static plugin_feature_t f[] = { + PLUGIN_CALLBACK((plugin_feature_callback_t)plugin_cb, NULL), + PLUGIN_PROVIDE(CUSTOM, "bypass-lan"), + }; + *features = f; + return countof(f); +} + +METHOD(plugin_t, destroy, void, + private_bypass_lan_plugin_t *this) +{ + this->listener->destroy(this->listener); + free(this); +} + +/** + * Plugin constructor + */ +plugin_t *bypass_lan_plugin_create() +{ + private_bypass_lan_plugin_t *this; + + INIT(this, + .public = { + .plugin = { + .get_name = _get_name, + .get_features = _get_features, + .destroy = _destroy, + }, + }, + .listener = bypass_lan_listener_create(), + ); + + return &this->public.plugin; +} diff --git a/src/libcharon/plugins/bypass_lan/bypass_lan_plugin.h b/src/libcharon/plugins/bypass_lan/bypass_lan_plugin.h new file mode 100644 index 000000000..934bf0cf5 --- /dev/null +++ b/src/libcharon/plugins/bypass_lan/bypass_lan_plugin.h @@ -0,0 +1,42 @@ +/* + * Copyright (C) 2016 Tobias Brunner + * HSR 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 bypass_lan bypass_lan + * @ingroup cplugins + * + * @defgroup bypass_lan_plugin bypass_lan_plugin + * @{ @ingroup bypass_lan + */ + +#ifndef BYPASS_LAN_PLUGIN_H_ +#define BYPASS_LAN_PLUGIN_H_ + +#include <plugins/plugin.h> + +typedef struct bypass_lan_plugin_t bypass_lan_plugin_t; + +/** + * Plugin installing bypass policies for locally attached subnets. + */ +struct bypass_lan_plugin_t { + + /** + * Implements plugin interface + */ + plugin_t plugin; +}; + +#endif /** BYPASS_LAN_PLUGIN_H_ @}*/ |