diff options
Diffstat (limited to 'src/libcharon/plugins/updown')
-rw-r--r-- | src/libcharon/plugins/updown/Makefile.am | 1 | ||||
-rw-r--r-- | src/libcharon/plugins/updown/Makefile.in | 18 | ||||
-rw-r--r-- | src/libcharon/plugins/updown/updown_handler.c | 243 | ||||
-rw-r--r-- | src/libcharon/plugins/updown/updown_handler.h | 57 | ||||
-rw-r--r-- | src/libcharon/plugins/updown/updown_listener.c | 117 | ||||
-rw-r--r-- | src/libcharon/plugins/updown/updown_listener.h | 4 | ||||
-rw-r--r-- | src/libcharon/plugins/updown/updown_plugin.c | 22 |
7 files changed, 434 insertions, 28 deletions
diff --git a/src/libcharon/plugins/updown/Makefile.am b/src/libcharon/plugins/updown/Makefile.am index 312c8d7e8..30683d83e 100644 --- a/src/libcharon/plugins/updown/Makefile.am +++ b/src/libcharon/plugins/updown/Makefile.am @@ -12,6 +12,7 @@ endif libstrongswan_updown_la_SOURCES = \ updown_plugin.h updown_plugin.c \ + updown_handler.h updown_handler.c \ updown_listener.h updown_listener.c libstrongswan_updown_la_LDFLAGS = -module -avoid-version diff --git a/src/libcharon/plugins/updown/Makefile.in b/src/libcharon/plugins/updown/Makefile.in index fb7b38f65..0f3463704 100644 --- a/src/libcharon/plugins/updown/Makefile.in +++ b/src/libcharon/plugins/updown/Makefile.in @@ -49,6 +49,7 @@ am__aclocal_m4_deps = $(top_srcdir)/m4/config/libtool.m4 \ am__configure_deps = $(am__aclocal_m4_deps) $(CONFIGURE_DEPENDENCIES) \ $(ACLOCAL_M4) mkinstalldirs = $(install_sh) -d +CONFIG_HEADER = $(top_builddir)/config.h CONFIG_CLEAN_FILES = CONFIG_CLEAN_VPATH_FILES = am__vpath_adj_setup = srcdirstrip=`echo "$(srcdir)" | sed 's|.|.|g'`; @@ -76,7 +77,7 @@ am__installdirs = "$(DESTDIR)$(plugindir)" LTLIBRARIES = $(noinst_LTLIBRARIES) $(plugin_LTLIBRARIES) libstrongswan_updown_la_LIBADD = am_libstrongswan_updown_la_OBJECTS = updown_plugin.lo \ - updown_listener.lo + updown_handler.lo updown_listener.lo libstrongswan_updown_la_OBJECTS = \ $(am_libstrongswan_updown_la_OBJECTS) libstrongswan_updown_la_LINK = $(LIBTOOL) --tag=CC $(AM_LIBTOOLFLAGS) \ @@ -85,7 +86,7 @@ libstrongswan_updown_la_LINK = $(LIBTOOL) --tag=CC $(AM_LIBTOOLFLAGS) \ @MONOLITHIC_FALSE@am_libstrongswan_updown_la_rpath = -rpath \ @MONOLITHIC_FALSE@ $(plugindir) @MONOLITHIC_TRUE@am_libstrongswan_updown_la_rpath = -DEFAULT_INCLUDES = -I.@am__isrc@ +DEFAULT_INCLUDES = -I.@am__isrc@ -I$(top_builddir) depcomp = $(SHELL) $(top_srcdir)/depcomp am__depfiles_maybe = depfiles am__mv = mv -f @@ -111,6 +112,7 @@ AUTOCONF = @AUTOCONF@ AUTOHEADER = @AUTOHEADER@ AUTOMAKE = @AUTOMAKE@ AWK = @AWK@ +BFDLIB = @BFDLIB@ BTLIB = @BTLIB@ CC = @CC@ CCDEPMODE = @CCDEPMODE@ @@ -205,11 +207,14 @@ build_os = @build_os@ build_vendor = @build_vendor@ builddir = @builddir@ c_plugins = @c_plugins@ +charon_natt_port = @charon_natt_port@ +charon_plugins = @charon_plugins@ +charon_udp_port = @charon_udp_port@ clearsilver_LIBS = @clearsilver_LIBS@ datadir = @datadir@ datarootdir = @datarootdir@ dbusservicedir = @dbusservicedir@ -default_pkcs11 = @default_pkcs11@ +dev_headers = @dev_headers@ docdir = @docdir@ dvidir = @dvidir@ exec_prefix = @exec_prefix@ @@ -226,11 +231,12 @@ imcvdir = @imcvdir@ includedir = @includedir@ infodir = @infodir@ install_sh = @install_sh@ +ipsec_script = @ipsec_script@ +ipsec_script_upper = @ipsec_script_upper@ ipsecdir = @ipsecdir@ ipsecgroup = @ipsecgroup@ ipseclibdir = @ipseclibdir@ ipsecuser = @ipsecuser@ -libcharon_plugins = @libcharon_plugins@ libdir = @libdir@ libexecdir = @libexecdir@ linux_headers = @linux_headers@ @@ -246,6 +252,7 @@ mkdir_p = @mkdir_p@ nm_CFLAGS = @nm_CFLAGS@ nm_LIBS = @nm_LIBS@ nm_ca_dir = @nm_ca_dir@ +nm_plugins = @nm_plugins@ oldincludedir = @oldincludedir@ openac_plugins = @openac_plugins@ p_plugins = @p_plugins@ @@ -255,7 +262,6 @@ pdfdir = @pdfdir@ piddir = @piddir@ pki_plugins = @pki_plugins@ plugindir = @plugindir@ -pluto_plugins = @pluto_plugins@ pool_plugins = @pool_plugins@ prefix = @prefix@ program_transform_name = @program_transform_name@ @@ -291,6 +297,7 @@ AM_CFLAGS = -rdynamic @MONOLITHIC_FALSE@plugin_LTLIBRARIES = libstrongswan-updown.la libstrongswan_updown_la_SOURCES = \ updown_plugin.h updown_plugin.c \ + updown_handler.h updown_handler.c \ updown_listener.h updown_listener.c libstrongswan_updown_la_LDFLAGS = -module -avoid-version @@ -377,6 +384,7 @@ mostlyclean-compile: distclean-compile: -rm -f *.tab.c +@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/updown_handler.Plo@am__quote@ @AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/updown_listener.Plo@am__quote@ @AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/updown_plugin.Plo@am__quote@ diff --git a/src/libcharon/plugins/updown/updown_handler.c b/src/libcharon/plugins/updown/updown_handler.c new file mode 100644 index 000000000..b2ac02e85 --- /dev/null +++ b/src/libcharon/plugins/updown/updown_handler.c @@ -0,0 +1,243 @@ +/* + * 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 "updown_handler.h" + +#include <daemon.h> +#include <utils/linked_list.h> +#include <threading/rwlock.h> + +typedef struct private_updown_handler_t private_updown_handler_t; + +/** + * Private data of an updown_handler_t object. + */ +struct private_updown_handler_t { + + /** + * Public updown_handler_t interface. + */ + updown_handler_t public; + + /** + * List of connection specific attributes, as attributes_t + */ + linked_list_t *attrs; + + /** + * rwlock to lock access to pools + */ + rwlock_t *lock; +}; + +/** + * Attributes assigned to an IKE_SA + */ +typedef struct { + /** unique IKE_SA identifier */ + u_int id; + /** list of DNS attributes, as host_t */ + linked_list_t *dns; +} attributes_t; + +/** + * Destroy an attributes_t entry + */ +static void attributes_destroy(attributes_t *this) +{ + this->dns->destroy_offset(this->dns, offsetof(host_t, destroy)); + free(this); +} + +METHOD(attribute_handler_t, handle, bool, + private_updown_handler_t *this, identification_t *server, + configuration_attribute_type_t type, chunk_t data) +{ + attributes_t *current, *attr = NULL; + enumerator_t *enumerator; + ike_sa_t *ike_sa; + host_t *host; + + ike_sa = charon->bus->get_sa(charon->bus); + if (!ike_sa) + { + return FALSE; + } + switch (type) + { + case INTERNAL_IP4_DNS: + host = host_create_from_chunk(AF_INET, data, 0); + break; + case INTERNAL_IP6_DNS: + host = host_create_from_chunk(AF_INET6, data, 0); + break; + default: + return FALSE; + } + if (!host) + { + return FALSE; + } + + this->lock->write_lock(this->lock); + enumerator = this->attrs->create_enumerator(this->attrs); + while (enumerator->enumerate(enumerator, ¤t)) + { + if (current->id == ike_sa->get_unique_id(ike_sa)) + { + attr = current; + } + } + enumerator->destroy(enumerator); + + if (!attr) + { + INIT(attr, + .id = ike_sa->get_unique_id(ike_sa), + .dns = linked_list_create(), + ); + this->attrs->insert_last(this->attrs, attr); + } + attr->dns->insert_last(attr->dns, host); + this->lock->unlock(this->lock); + + return TRUE; +} + +METHOD(attribute_handler_t, release, void, + private_updown_handler_t *this, identification_t *server, + configuration_attribute_type_t type, chunk_t data) +{ + attributes_t *attr; + enumerator_t *enumerator, *servers; + ike_sa_t *ike_sa; + host_t *host; + bool found = FALSE; + int family; + + switch (type) + { + case INTERNAL_IP4_DNS: + family = AF_INET; + break; + case INTERNAL_IP6_DNS: + family = AF_INET6; + break; + default: + return; + } + + ike_sa = charon->bus->get_sa(charon->bus); + if (ike_sa) + { + this->lock->write_lock(this->lock); + enumerator = this->attrs->create_enumerator(this->attrs); + while (enumerator->enumerate(enumerator, &attr)) + { + if (attr->id == ike_sa->get_unique_id(ike_sa)) + { + servers = attr->dns->create_enumerator(attr->dns); + while (servers->enumerate(servers, &host)) + { + if (host->get_family(host) == family && + chunk_equals(data, host->get_address(host))) + { + attr->dns->remove_at(attr->dns, servers); + host->destroy(host); + found = TRUE; + break; + } + } + servers->destroy(servers); + if (attr->dns->get_count(attr->dns) == 0) + { + this->attrs->remove_at(this->attrs, enumerator); + attributes_destroy(attr); + break; + } + } + if (found) + { + break; + } + } + enumerator->destroy(enumerator); + this->lock->unlock(this->lock); + } +} + +METHOD(updown_handler_t, create_dns_enumerator, enumerator_t*, + private_updown_handler_t *this, u_int id) +{ + attributes_t *attr; + enumerator_t *enumerator; + ike_sa_t *ike_sa; + + ike_sa = charon->bus->get_sa(charon->bus); + if (!ike_sa) + { + return FALSE; + } + + this->lock->read_lock(this->lock); + enumerator = this->attrs->create_enumerator(this->attrs); + while (enumerator->enumerate(enumerator, &attr)) + { + if (attr->id == ike_sa->get_unique_id(ike_sa)) + { + enumerator->destroy(enumerator); + return enumerator_create_cleaner( + attr->dns->create_enumerator(attr->dns), + (void*)this->lock->unlock, this->lock); + } + } + enumerator->destroy(enumerator); + this->lock->unlock(this->lock); + + return enumerator_create_empty(); +} + + +METHOD(updown_handler_t, destroy, void, + private_updown_handler_t *this) +{ + this->lock->destroy(this->lock); + this->attrs->destroy_function(this->attrs, (void*)attributes_destroy); + free(this); +} + +/** + * See header + */ +updown_handler_t *updown_handler_create() +{ + private_updown_handler_t *this; + + INIT(this, + .public = { + .handler = { + .handle = _handle, + .release = _release, + .create_attribute_enumerator = enumerator_create_empty, + }, + .create_dns_enumerator = _create_dns_enumerator, + .destroy = _destroy, + }, + .attrs = linked_list_create(), + .lock = rwlock_create(RWLOCK_TYPE_DEFAULT), + ); + + return &this->public; +} diff --git a/src/libcharon/plugins/updown/updown_handler.h b/src/libcharon/plugins/updown/updown_handler.h new file mode 100644 index 000000000..d4de880b8 --- /dev/null +++ b/src/libcharon/plugins/updown/updown_handler.h @@ -0,0 +1,57 @@ +/* + * 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 updown_handler updown_handler + * @{ @ingroup updown + */ + +#ifndef UPDOWN_HANDLER_H_ +#define UPDOWN_HANDLER_H_ + +#include <attributes/attribute_handler.h> + +typedef struct updown_handler_t updown_handler_t; + +/** + * Handler storing configuration attributes to pass to updown script. + */ +struct updown_handler_t { + + /** + * Implements the attribute_handler_t interface + */ + attribute_handler_t handler; + + /** + * Create an enumerator over received DNS servers. + * + * @param id unique IKE_SA identifier to get attributes for + * @return enumerator over host_t* + */ + enumerator_t* (*create_dns_enumerator)(updown_handler_t *this, u_int id); + + /** + * Destroy a updown_handler_t. + */ + void (*destroy)(updown_handler_t *this); +}; + +/** + * Create a updown_handler instance. + */ +updown_handler_t *updown_handler_create(); + +#endif /** UPDOWN_HANDLER_H_ @}*/ diff --git a/src/libcharon/plugins/updown/updown_listener.c b/src/libcharon/plugins/updown/updown_listener.c index 2bd757ec7..8b2af05b6 100644 --- a/src/libcharon/plugins/updown/updown_listener.c +++ b/src/libcharon/plugins/updown/updown_listener.c @@ -38,6 +38,11 @@ struct private_updown_listener_t { * List of cached interface names */ linked_list_t *iface_cache; + + /** + * DNS attribute handler + */ + updown_handler_t *handler; }; typedef struct cache_entry_t cache_entry_t; @@ -90,6 +95,85 @@ static char* uncache_iface(private_updown_listener_t *this, u_int32_t reqid) return iface; } +/** + * Create variables for handled DNS attributes + */ +static char *make_dns_vars(private_updown_listener_t *this, ike_sa_t *ike_sa) +{ + enumerator_t *enumerator; + host_t *host; + int v4 = 0, v6 = 0; + char total[512] = "", current[64]; + + if (!this->handler) + { + return strdup(""); + } + + enumerator = this->handler->create_dns_enumerator(this->handler, + ike_sa->get_unique_id(ike_sa)); + while (enumerator->enumerate(enumerator, &host)) + { + switch (host->get_family(host)) + { + case AF_INET: + snprintf(current, sizeof(current), + "PLUTO_DNS4_%d='%H' ", ++v4, host); + break; + case AF_INET6: + snprintf(current, sizeof(current), + "PLUTO_DNS6_%d='%H' ", ++v6, host); + break; + default: + continue; + } + strncat(total, current, sizeof(total) - strlen(total) - 1); + } + enumerator->destroy(enumerator); + + return strdup(total); +} + +/** + * Create variables for local virtual IPs + */ +static char *make_vip_vars(private_updown_listener_t *this, ike_sa_t *ike_sa) +{ + enumerator_t *enumerator; + host_t *host; + int v4 = 0, v6 = 0; + char total[512] = "", current[64]; + bool first = TRUE; + + enumerator = ike_sa->create_virtual_ip_enumerator(ike_sa, TRUE); + while (enumerator->enumerate(enumerator, &host)) + { + if (first) + { /* legacy variable for first VIP */ + snprintf(current, sizeof(current), + "PLUTO_MY_SOURCEIP='%H' ", host); + strncat(total, current, sizeof(total) - strlen(total) - 1); + } + switch (host->get_family(host)) + { + case AF_INET: + snprintf(current, sizeof(current), + "PLUTO_MY_SOURCEIP4_%d='%H' ", ++v4, host); + break; + case AF_INET6: + snprintf(current, sizeof(current), + "PLUTO_MY_SOURCEIP6_%d='%H' ", ++v6, host); + break; + default: + continue; + } + strncat(total, current, sizeof(total) - strlen(total) - 1); + } + enumerator->destroy(enumerator); + + return strdup(total); +} + METHOD(listener_t, child_updown, bool, private_updown_listener_t *this, ike_sa_t *ike_sa, child_sa_t *child_sa, bool up) @@ -97,11 +181,10 @@ METHOD(listener_t, child_updown, bool, traffic_selector_t *my_ts, *other_ts; enumerator_t *enumerator; child_cfg_t *config; - host_t *vip, *me, *other; + host_t *me, *other; char *script; config = child_sa->get_config(child_sa); - vip = ike_sa->get_virtual_ip(ike_sa, TRUE); script = config->get_updown(config); me = ike_sa->get_my_host(ike_sa); other = ike_sa->get_other_host(ike_sa); @@ -117,7 +200,7 @@ METHOD(listener_t, child_updown, bool, char command[1024]; host_t *my_client, *other_client; u_int8_t my_client_mask, other_client_mask; - char *virtual_ip, *iface, *mark_in, *mark_out, *udp_enc; + char *virtual_ip, *iface, *mark_in, *mark_out, *udp_enc, *dns; mark_t mark; bool is_host, is_ipv6; FILE *shell; @@ -125,20 +208,7 @@ METHOD(listener_t, child_updown, bool, my_ts->to_subnet(my_ts, &my_client, &my_client_mask); other_ts->to_subnet(other_ts, &other_client, &other_client_mask); - if (vip) - { - if (asprintf(&virtual_ip, "PLUTO_MY_SOURCEIP='%H' ", vip) < 0) - { - virtual_ip = NULL; - } - } - else - { - if (asprintf(&virtual_ip, "") < 0) - { - virtual_ip = NULL; - } - } + virtual_ip = make_vip_vars(this, ike_sa); /* check for the presence of an inbound mark */ mark = config->get_mark(config, TRUE); @@ -197,9 +267,8 @@ METHOD(listener_t, child_updown, bool, if (up) { - iface = hydra->kernel_interface->get_interface( - hydra->kernel_interface, me); - if (iface) + if (hydra->kernel_interface->get_interface(hydra->kernel_interface, + me, &iface)) { cache_iface(this, child_sa->get_reqid(child_sa), iface); } @@ -209,6 +278,8 @@ METHOD(listener_t, child_updown, bool, iface = uncache_iface(this, child_sa->get_reqid(child_sa)); } + dns = make_dns_vars(this, ike_sa); + /* determine IPv4/IPv6 and client/host situation */ is_host = my_ts->is_host(my_ts, me); is_ipv6 = is_host ? (me->get_family(me) == AF_INET6) : @@ -239,6 +310,7 @@ METHOD(listener_t, child_updown, bool, "%s" "%s" "%s" + "%s" "%s", up ? "up" : "down", is_host ? "-host" : "-client", @@ -259,6 +331,7 @@ METHOD(listener_t, child_updown, bool, mark_out, udp_enc, config->get_hostaccess(config) ? "PLUTO_HOST_ACCESS='1' " : "", + dns, script); my_client->destroy(my_client); other_client->destroy(other_client); @@ -266,6 +339,7 @@ METHOD(listener_t, child_updown, bool, free(mark_in); free(mark_out); free(udp_enc); + free(dns); free(iface); DBG3(DBG_CHD, "running updown script: %s", command); @@ -315,7 +389,7 @@ METHOD(updown_listener_t, destroy, void, /** * See header */ -updown_listener_t *updown_listener_create() +updown_listener_t *updown_listener_create(updown_handler_t *handler) { private_updown_listener_t *this; @@ -327,6 +401,7 @@ updown_listener_t *updown_listener_create() .destroy = _destroy, }, .iface_cache = linked_list_create(), + .handler = handler, ); return &this->public; diff --git a/src/libcharon/plugins/updown/updown_listener.h b/src/libcharon/plugins/updown/updown_listener.h index 5b866c4e5..2d9b56ade 100644 --- a/src/libcharon/plugins/updown/updown_listener.h +++ b/src/libcharon/plugins/updown/updown_listener.h @@ -23,6 +23,8 @@ #include <bus/bus.h> +#include "updown_handler.h" + typedef struct updown_listener_t updown_listener_t; /** @@ -44,6 +46,6 @@ struct updown_listener_t { /** * Create a updown_listener instance. */ -updown_listener_t *updown_listener_create(); +updown_listener_t *updown_listener_create(updown_handler_t *handler); #endif /** UPDOWN_LISTENER_H_ @}*/ diff --git a/src/libcharon/plugins/updown/updown_plugin.c b/src/libcharon/plugins/updown/updown_plugin.c index 2ce2d3257..e1f0d1380 100644 --- a/src/libcharon/plugins/updown/updown_plugin.c +++ b/src/libcharon/plugins/updown/updown_plugin.c @@ -15,8 +15,10 @@ #include "updown_plugin.h" #include "updown_listener.h" +#include "updown_handler.h" #include <daemon.h> +#include <hydra.h> typedef struct private_updown_plugin_t private_updown_plugin_t; @@ -34,6 +36,11 @@ struct private_updown_plugin_t { * Listener interface, listens to CHILD_SA state changes */ updown_listener_t *listener; + + /** + * Attribute handler, to pass DNS servers to updown + */ + updown_handler_t *handler; }; METHOD(plugin_t, get_name, char*, @@ -47,6 +54,12 @@ METHOD(plugin_t, destroy, void, { charon->bus->remove_listener(charon->bus, &this->listener->listener); this->listener->destroy(this->listener); + if (this->handler) + { + hydra->attributes->remove_handler(hydra->attributes, + &this->handler->handler); + this->handler->destroy(this->handler); + } free(this); } @@ -65,9 +78,16 @@ plugin_t *updown_plugin_create() .destroy = _destroy, }, }, - .listener = updown_listener_create(), ); + if (lib->settings->get_bool(lib->settings, + "charon.plugins.updown.dns_handler", FALSE)) + { + this->handler = updown_handler_create(); + hydra->attributes->add_handler(hydra->attributes, + &this->handler->handler); + } + this->listener = updown_listener_create(this->handler); charon->bus->add_listener(charon->bus, &this->listener->listener); return &this->public.plugin; |