#
-# Copyright (C) 2007-2014 Tobias Brunner
+# Copyright (C) 2007-2015 Tobias Brunner
# Copyright (C) 2006-2014 Andreas Steffen
# Copyright (C) 2006-2014 Martin Willi
# Hochschule fuer Technik Rapperswil
ARG_ENABL_SET([socket-dynamic], [enable dynamic socket implementation for charon])
ARG_ENABL_SET([socket-win], [enable Winsock2 based socket implementation for charon])
# configuration/control plugins
+ARG_ENABL_SET([connect], [simple plugin that allows to initiate/terminate existing connections.])
ARG_DISBL_SET([stroke], [disable charons stroke configuration backend.])
ARG_ENABL_SET([smp], [enable SMP configuration and control interface. Requires libxml.])
ARG_ENABL_SET([sql], [enable SQL database configuration backend.])
ADD_PLUGIN([socket-dynamic], [c charon cmd])
ADD_PLUGIN([socket-win], [c charon])
ADD_PLUGIN([farp], [c charon])
+ADD_PLUGIN([connect], [c charon])
ADD_PLUGIN([stroke], [c charon])
ADD_PLUGIN([vici], [c charon])
ADD_PLUGIN([smp], [c charon])
# charon plugins
# ----------------
+AM_CONDITIONAL(USE_CONNECT, test x$connect = xtrue)
AM_CONDITIONAL(USE_STROKE, test x$stroke = xtrue)
AM_CONDITIONAL(USE_VICI, test x$vici = xtrue)
AM_CONDITIONAL(USE_MEDSRV, test x$medsrv = xtrue)
src/libcharon/plugins/android_dns/Makefile
src/libcharon/plugins/android_log/Makefile
src/libcharon/plugins/maemo/Makefile
+ src/libcharon/plugins/connect/Makefile
src/libcharon/plugins/stroke/Makefile
src/libcharon/plugins/vici/Makefile
src/libcharon/plugins/vici/ruby/Makefile
endif
endif
+if USE_CONNECT
+ SUBDIRS += plugins/connect
+if MONOLITHIC
+ libcharon_la_LIBADD += plugins/connect/libstrongswan-connect.la
+endif
+endif
+
if USE_STROKE
SUBDIRS += plugins/stroke
if MONOLITHIC
--- /dev/null
+AM_CPPFLAGS = \
+ -I$(top_srcdir)/src/libstrongswan \
+ -I$(top_srcdir)/src/libhydra \
+ -I$(top_srcdir)/src/libcharon \
+ -DIPSEC_PIDDIR=\"${piddir}\"
+
+AM_CFLAGS = \
+ $(PLUGIN_CFLAGS)
+
+if MONOLITHIC
+noinst_LTLIBRARIES = libstrongswan-connect.la
+else
+plugin_LTLIBRARIES = libstrongswan-connect.la
+endif
+
+libstrongswan_connect_la_SOURCES = connect_plugin.h connect_plugin.c \
+ connect_socket.h connect_socket.c connect_msg.h
+
+libstrongswan_connect_la_LDFLAGS = -module -avoid-version
+
+ipsec_PROGRAMS = connect
+connect_SOURCES = connect.c
+connect_LDADD = $(top_builddir)/src/libstrongswan/libstrongswan.la
\ No newline at end of file
--- /dev/null
+/*
+ * Copyright (C) 2015 Tobias Brunner
+ * 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 "connect_msg.h"
+
+#include <arpa/inet.h>
+
+#include <library.h>
+
+/**
+ * Send a message
+ */
+static int send_msg(int type, char *name)
+{
+ connect_msg_t msg = {
+ .type = htonl(type),
+ };
+ stream_t *stream;
+ char *uri, buffer[512];
+ int count;
+
+ uri = lib->settings->get_str(lib->settings, "charon.plugins.connect.socket",
+ "unix://" CONNECT_SOCKET);
+ stream = lib->streams->connect(lib->streams, uri);
+ if (!stream)
+ {
+ fprintf(stderr, "failed to connect to socket '%s'\n", uri);
+ return 2;
+ }
+
+ snprintf(msg.name, sizeof(msg.name), "%s", name);
+ if (!stream->write_all(stream, &msg, sizeof(msg)))
+ {
+ fprintf(stderr, "sending message failed\n");
+ stream->destroy(stream);
+ return 2;
+ }
+
+ while ((count = stream->read(stream, buffer, sizeof(buffer)-1, TRUE)) > 0)
+ {
+ buffer[count] = '\0';
+ printf("%s", buffer);
+ }
+ if (count < 0)
+ {
+ fprintf(stderr, "reading response failed\n");
+ }
+ stream->destroy(stream);
+ return 0;
+}
+
+int main(int argc, char *argv[])
+{
+ library_init(NULL, "connect");
+ atexit(library_deinit);
+
+ if (argc == 3 && strcmp(argv[1], "up") == 0)
+ {
+ return send_msg(CONNECT_INITIATE, argv[2]);
+ }
+ if (argc == 3 && strcmp(argv[1], "down") == 0)
+ {
+ return send_msg(CONNECT_TERMINATE, argv[2]);
+ }
+ fprintf(stderr, "Usage:\n");
+ fprintf(stderr, " %s up <name>\n", argv[0]);
+ fprintf(stderr, " %s down <name>\n", argv[0]);
+ return 1;
+}
--- /dev/null
+/*
+ * Copyright (C) 2015 Tobias Brunner
+ * 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 connect_msg connect_msg
+ * @{ @ingroup connect
+ */
+
+#ifndef CONNECT_MSG_H_
+#define CONNECT_MSG_H_
+
+#define CONNECT_SOCKET IPSEC_PIDDIR "/charon.cnct"
+
+typedef struct connect_msg_t connect_msg_t;
+
+/**
+ * Message type
+ */
+enum {
+ /* initiate a connection */
+ CONNECT_INITIATE = 1,
+ /* terminate a connection */
+ CONNECT_TERMINATE = 2,
+};
+
+/**
+ * Message to exchange over socket
+ */
+struct connect_msg_t {
+ /** message type */
+ int type;
+ /** null terminated connection name */
+ char name[128];
+} __attribute__((packed));
+
+#endif /** CONNECT_MSG_H_ @}*/
--- /dev/null
+/*
+ * Copyright (C) 2015 Tobias Brunner
+ * 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 "connect_plugin.h"
+
+#include "connect_socket.h"
+
+#include <daemon.h>
+
+typedef struct private_connect_plugin_t private_connect_plugin_t;
+
+/**
+ * Private data of connect plugin
+ */
+struct private_connect_plugin_t {
+
+ /**
+ * Public interface
+ */
+ connect_plugin_t public;
+
+ /**
+ * Control socket
+ */
+ connect_socket_t *socket;
+};
+
+METHOD(plugin_t, get_name, char*,
+ private_connect_plugin_t *this)
+{
+ return "connect";
+}
+
+/**
+ * Register listener
+ */
+static bool plugin_cb(private_connect_plugin_t *this,
+ plugin_feature_t *feature, bool reg, void *cb_data)
+{
+ if (reg)
+ {
+ this->socket = connect_socket_create();
+ return this->socket != NULL;
+ }
+ else
+ {
+ DESTROY_IF(this->socket);
+ return TRUE;
+ }
+}
+
+METHOD(plugin_t, get_features, int,
+ private_connect_plugin_t *this, plugin_feature_t *features[])
+{
+ static plugin_feature_t f[] = {
+ PLUGIN_CALLBACK((plugin_feature_callback_t)plugin_cb, NULL),
+ PLUGIN_PROVIDE(CUSTOM, "connect"),
+ };
+ *features = f;
+ return countof(f);
+}
+
+METHOD(plugin_t, destroy, void,
+ private_connect_plugin_t *this)
+{
+ free(this);
+}
+
+/**
+ * Plugin constructor
+ */
+plugin_t *connect_plugin_create()
+{
+ private_connect_plugin_t *this;
+
+ INIT(this,
+ .public = {
+ .plugin = {
+ .get_name = _get_name,
+ .get_features = _get_features,
+ .destroy = _destroy,
+ },
+ },
+ );
+
+ return &this->public.plugin;
+}
--- /dev/null
+/*
+ * Copyright (C) 2015 Tobias Brunner
+ * 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 connect connect
+ * @ingroup cplugins
+ *
+ * @defgroup connect_plugin connect_plugin
+ * @{ @ingroup connect
+ */
+
+#ifndef CONNECT_PLUGIN_H_
+#define CONNECT_PLUGIN_H_
+
+#include <plugins/plugin.h>
+
+typedef struct connect_plugin_t connect_plugin_t;
+
+/**
+ * Simple plugin to initiate/termiante connections.
+ */
+struct connect_plugin_t {
+
+ /**
+ * Implements plugin interface
+ */
+ plugin_t plugin;
+};
+
+#endif /** CONNECT_PLUGIN_H_ @}*/
--- /dev/null
+/*
+ * Copyright (C) 2013-2015 Tobias Brunner
+ * Copyright (C) 2008 Martin Willi
+ * 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 "connect_socket.h"
+
+#include <daemon.h>
+#include <collections/array.h>
+
+#include "connect_msg.h"
+
+#define CONNECT_LOG_LEVEL 1
+
+typedef struct private_connect_socket_t private_connect_socket_t;
+
+/**
+ * Private data of a connect_socket_t object
+ */
+struct private_connect_socket_t {
+
+ /**
+ * Public interface
+ */
+ connect_socket_t public;
+
+ /**
+ * Connect stream service
+ */
+ stream_service_t *service;
+};
+
+/**
+ * Logging to the connect socket
+ */
+static bool connect_log(FILE *out, debug_t group, level_t level,
+ ike_sa_t *ike_sa, char *message)
+{
+ if (level <= CONNECT_LOG_LEVEL)
+ {
+ if (fprintf(out, "%s", message) < 0 ||
+ fprintf(out, "\n") < 0 ||
+ fflush(out) != 0)
+ {
+ return FALSE;
+ }
+ }
+ return TRUE;
+}
+
+/**
+ * Get the child_cfg with the same name as the peer cfg
+ */
+static child_cfg_t* get_child_from_peer(peer_cfg_t *peer_cfg, char *name)
+{
+ child_cfg_t *current, *found = NULL;
+ enumerator_t *enumerator;
+
+ enumerator = peer_cfg->create_child_cfg_enumerator(peer_cfg);
+ while (enumerator->enumerate(enumerator, ¤t))
+ {
+ if (streq(current->get_name(current), name))
+ {
+ found = current;
+ found->get_ref(found);
+ break;
+ }
+ }
+ enumerator->destroy(enumerator);
+ return found;
+}
+
+/**
+ * Initiate the connection with the given config
+ */
+static void perform_initiate(private_connect_socket_t *this, char *name,
+ peer_cfg_t *peer_cfg, child_cfg_t *child_cfg, FILE *out)
+{
+ status_t status;
+
+ status = charon->controller->initiate(charon->controller, peer_cfg,
+ child_cfg, (controller_cb_t)connect_log, out, 0);
+ switch (status)
+ {
+ case SUCCESS:
+ fprintf(out, "connection '%s' established successfully\n", name);
+ break;
+ default:
+ case FAILED:
+ fprintf(out, "establishing connection '%s' failed\n", name);
+ break;
+ }
+}
+
+/**
+ * Initiate the connection with the given name
+ */
+static void initiate(private_connect_socket_t *this, char *name, FILE *out)
+{
+ child_cfg_t *child_cfg = NULL;
+ peer_cfg_t *peer_cfg;
+ enumerator_t *enumerator;
+ bool empty = TRUE;
+
+ DBG1(DBG_CFG, "connect: initiate '%s'", name);
+
+ peer_cfg = charon->backends->get_peer_cfg_by_name(charon->backends, name);
+ if (peer_cfg)
+ {
+ child_cfg = get_child_from_peer(peer_cfg, name);
+ if (child_cfg == NULL)
+ {
+ enumerator = peer_cfg->create_child_cfg_enumerator(peer_cfg);
+ while (enumerator->enumerate(enumerator, &child_cfg))
+ {
+ empty = FALSE;
+ perform_initiate(this, name, peer_cfg->get_ref(peer_cfg),
+ child_cfg->get_ref(child_cfg), out);
+ }
+ enumerator->destroy(enumerator);
+
+ if (empty)
+ {
+ DBG1(DBG_CFG, "no child config named '%s'", name);
+ fprintf(out, "no child config named '%s'\n", name);
+ }
+ peer_cfg->destroy(peer_cfg);
+ return;
+ }
+ }
+ else
+ {
+ enumerator = charon->backends->create_peer_cfg_enumerator(
+ charon->backends, NULL, NULL, NULL, NULL, IKE_ANY);
+ while (enumerator->enumerate(enumerator, &peer_cfg))
+ {
+ child_cfg = get_child_from_peer(peer_cfg, name);
+ if (child_cfg)
+ {
+ peer_cfg->get_ref(peer_cfg);
+ break;
+ }
+ }
+ enumerator->destroy(enumerator);
+
+ if (child_cfg == NULL)
+ {
+ DBG1(DBG_CFG, "no config named '%s'", name);
+ fprintf(out, "no config named '%s'\n", name);
+ return;
+ }
+ }
+ perform_initiate(this, name, peer_cfg, child_cfg, out);
+}
+
+/**
+ * Terminate the connection with the given name
+ */
+static void terminate(private_connect_socket_t *this, char *name, FILE *out)
+{
+ ike_sa_t *ike_sa;
+ enumerator_t *enumerator;
+ array_t *ike_sas;
+ status_t status;
+ u_int32_t id, *current;
+
+ DBG1(DBG_CFG, "connect: terminate '%s'", name);
+
+ ike_sas = array_create(sizeof(u_int32_t), 1);
+ enumerator = charon->controller->create_ike_sa_enumerator(
+ charon->controller, TRUE);
+ while (enumerator->enumerate(enumerator, &ike_sa))
+ {
+ if (streq(name, ike_sa->get_name(ike_sa)))
+ {
+ id = ike_sa->get_unique_id(ike_sa);
+ array_insert(ike_sas, ARRAY_TAIL, &id);
+ }
+ }
+ enumerator->destroy(enumerator);
+
+ enumerator = array_create_enumerator(ike_sas);
+ while (enumerator->enumerate(enumerator, ¤t))
+ {
+ status = charon->controller->terminate_ike(charon->controller,
+ *current, (controller_cb_t)connect_log, out, 0);
+ switch (status)
+ {
+ case SUCCESS:
+ fprintf(out, "IKE_SA[%d] closed successfully\n", *current);
+ break;
+ default:
+ case FAILED:
+ fprintf(out, "closing IKE_SA[%d] failed\n", *current);
+ break;
+ }
+ }
+ enumerator->destroy(enumerator);
+
+ if (!array_count(ike_sas))
+ {
+ DBG1(DBG_CFG, "no IKE_SA named '%s'", name);
+ fprintf(out, "no IKE_SA named '%s'\n", name);
+ }
+ array_destroy(ike_sas);
+}
+
+/**
+ * Dispatch a received message
+ */
+static bool on_accept(private_connect_socket_t *this, stream_t *stream)
+{
+ connect_msg_t msg;
+ FILE *out;
+
+ if (stream->read_all(stream, &msg, sizeof(msg)))
+ {
+ msg.name[sizeof(msg.name) - 1] = '\0';
+ out = stream->get_file(stream);
+ if (!out)
+ {
+ DBG1(DBG_CFG, "creating connect output stream failed");
+ return FALSE;
+ }
+ switch (ntohl(msg.type))
+ {
+ case CONNECT_INITIATE:
+ initiate(this, msg.name, out);
+ break;
+ case CONNECT_TERMINATE:
+ terminate(this, msg.name, out);
+ break;
+ default:
+ DBG1(DBG_CFG, "received unknown connect command");
+ break;
+ }
+ fclose(out);
+ }
+ return FALSE;
+}
+
+METHOD(connect_socket_t, destroy, void,
+ private_connect_socket_t *this)
+{
+ this->service->destroy(this->service);
+ free(this);
+}
+
+/**
+ * See header
+ */
+connect_socket_t *connect_socket_create()
+{
+ private_connect_socket_t *this;
+ char *uri;
+
+ INIT(this,
+ .public = {
+ .destroy = _destroy,
+ },
+ );
+
+ uri = lib->settings->get_str(lib->settings,
+ "%s.plugins.connect.socket", "unix://" CONNECT_SOCKET,
+ lib->ns);
+ this->service = lib->streams->create_service(lib->streams, uri, 10);
+ if (!this->service)
+ {
+ DBG1(DBG_CFG, "creating connect socket failed");
+ free(this);
+ return NULL;
+ }
+
+ this->service->on_accept(this->service, (stream_service_cb_t)on_accept,
+ this, JOB_PRIO_CRITICAL, 0);
+
+ return &this->public;
+}
--- /dev/null
+/*
+ * Copyright (C) 2015 Tobias Brunner
+ * 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 connect_socket connect_socket
+ * @{ @ingroup connect
+ */
+
+#ifndef CONNECT_SOCKET_H_
+#define CONNECT_SOCKET_H_
+
+typedef struct connect_socket_t connect_socket_t;
+
+/**
+ * Control socket
+ */
+struct connect_socket_t {
+
+ /**
+ * Destroy a connect_socket_t
+ */
+ void (*destroy)(connect_socket_t *this);
+};
+
+/**
+ * Create a connect_socket instance
+ */
+connect_socket_t *connect_socket_create();
+
+#endif /** CONNECT_SOCKET_H_ @}*/