Read actions from test config, delayed execution
authorMartin Willi <martin@revosec.ch>
Fri, 29 Oct 2010 13:45:58 +0000 (15:45 +0200)
committerMartin Willi <martin@revosec.ch>
Wed, 5 Jan 2011 15:45:41 +0000 (16:45 +0100)
src/conftest/Makefile.am
src/conftest/actions.c [new file with mode: 0644]
src/conftest/actions.h [new file with mode: 0644]
src/conftest/conftest.c
src/conftest/conftest.h

index ce009e4..a841201 100644 (file)
@@ -2,7 +2,8 @@ ipsec_PROGRAMS = conftest
 
 AM_CFLAGS = -rdynamic
 
-conftest_SOURCES = conftest.c conftest.h config.c config.h hooks/hook.h
+conftest_SOURCES = conftest.c conftest.h config.c config.h hooks/hook.h \
+       actions.c actions.h
 
 INCLUDES = \
        -I$(top_srcdir)/src/libstrongswan \
diff --git a/src/conftest/actions.c b/src/conftest/actions.c
new file mode 100644 (file)
index 0000000..92b523f
--- /dev/null
@@ -0,0 +1,339 @@
+/*
+ * Copyright (C) 2010 Martin Willi
+ * Copyright (C) 2010 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 "actions.h"
+#include "conftest.h"
+
+#include <daemon.h>
+#include <processing/jobs/callback_job.h>
+#include <processing/jobs/rekey_ike_sa_job.h>
+#include <processing/jobs/rekey_child_sa_job.h>
+#include <processing/jobs/send_dpd_job.h>
+
+typedef struct private_actions_t private_actions_t;
+
+/**
+ * Private data of an actions_t object.
+ */
+struct private_actions_t {
+
+       /**
+        * Public actions_t interface.
+        */
+       actions_t public;
+};
+
+/**
+ * Initiate a CHILD_SA
+ */
+static job_requeue_t initiate(char *config)
+{
+       peer_cfg_t *peer_cfg;
+       child_cfg_t *child_cfg = NULL, *current;
+       enumerator_t *enumerator;
+
+       peer_cfg = charon->backends->get_peer_cfg_by_name(charon->backends, config);
+       if (!peer_cfg)
+       {
+               DBG1(DBG_CFG, "initiating '%s' failed, config not found");
+               return JOB_REQUEUE_NONE;
+       }
+       enumerator = peer_cfg->create_child_cfg_enumerator(peer_cfg);
+       while (enumerator->enumerate(enumerator, &current))
+       {
+               if (streq(current->get_name(current), config))
+               {
+                       child_cfg = current;
+                       child_cfg->get_ref(child_cfg);
+                       break;
+               }
+       }
+       enumerator->destroy(enumerator);
+       if (child_cfg)
+       {
+               DBG1(DBG_CFG, "initiating IKE_SA for CHILD_SA config '%s'", config);
+               charon->controller->initiate(charon->controller, peer_cfg, child_cfg,
+                                                                        NULL, NULL);
+       }
+       else
+       {
+               DBG1(DBG_CFG, "initiating '%s' failed, CHILD_SA config not found",
+                        config);
+       }
+
+       return JOB_REQUEUE_NONE;
+}
+
+/**
+ * Rekey an IKE_SA
+ */
+static job_requeue_t rekey_ike(char *config)
+{
+       enumerator_t *enumerator;
+       job_t *job = NULL;
+       ike_sa_t *ike_sa;
+
+       enumerator = charon->controller->create_ike_sa_enumerator(charon->controller);
+       while (enumerator->enumerate(enumerator, &ike_sa))
+       {
+               if (strcaseeq(config, ike_sa->get_name(ike_sa)))
+               {
+                       job = (job_t*)rekey_ike_sa_job_create(ike_sa->get_id(ike_sa), FALSE);
+                       break;
+               }
+       }
+       enumerator->destroy(enumerator);
+
+       if (job)
+       {
+               DBG1(DBG_CFG, "starting rekey of IKE_SA '%s'", config);
+               lib->processor->queue_job(lib->processor, job);
+       }
+       else
+       {
+               DBG1(DBG_CFG, "rekeying '%s' failed, IKE_SA not found", config);
+       }
+       return JOB_REQUEUE_NONE;
+}
+
+/**
+ * Rekey an CHILD_SA
+ */
+static job_requeue_t rekey_child(char *config)
+{
+       enumerator_t *enumerator;
+       iterator_t *children;
+       ike_sa_t *ike_sa;
+       child_sa_t *child_sa;
+       u_int32_t reqid = 0, spi = 0;
+       protocol_id_t proto = PROTO_ESP;
+
+       enumerator = charon->controller->create_ike_sa_enumerator(charon->controller);
+       while (enumerator->enumerate(enumerator, &ike_sa))
+       {
+               children = ike_sa->create_child_sa_iterator(ike_sa);
+               while (children->iterate(children, (void**)&child_sa))
+               {
+                       if (streq(config, child_sa->get_name(child_sa)))
+                       {
+                               reqid = child_sa->get_reqid(child_sa);
+                               proto = child_sa->get_protocol(child_sa);
+                               spi = child_sa->get_spi(child_sa, TRUE);
+                               break;
+                       }
+               }
+               children->destroy(children);
+       }
+       enumerator->destroy(enumerator);
+       if (reqid)
+       {
+               DBG1(DBG_CFG, "starting rekey of CHILD_SA '%s'", config);
+               lib->processor->queue_job(lib->processor,
+                                               (job_t*)rekey_child_sa_job_create(reqid, proto, spi));
+       }
+       else
+       {
+               DBG1(DBG_CFG, "rekeying '%s' failed, CHILD_SA not found", config);
+       }
+       return JOB_REQUEUE_NONE;
+}
+
+/**
+ * Do a liveness check
+ */
+static job_requeue_t liveness(char *config)
+{
+       enumerator_t *enumerator;
+       job_t *job = NULL;
+       ike_sa_t *ike_sa;
+
+       enumerator = charon->controller->create_ike_sa_enumerator(charon->controller);
+       while (enumerator->enumerate(enumerator, &ike_sa))
+       {
+               if (strcaseeq(config, ike_sa->get_name(ike_sa)))
+               {
+                       job = (job_t*)send_dpd_job_create(ike_sa->get_id(ike_sa));
+                       break;
+               }
+       }
+       enumerator->destroy(enumerator);
+
+       if (job)
+       {
+               DBG1(DBG_CFG, "starting liveness check of IKE_SA '%s'", config);
+               lib->processor->queue_job(lib->processor, job);
+       }
+       else
+       {
+               DBG1(DBG_CFG, "liveness check for '%s' failed, IKE_SA not found", config);
+       }
+       return JOB_REQUEUE_NONE;
+}
+
+/**
+ * Close an IKE_SA with all CHILD_SAs
+ */
+static job_requeue_t close_ike(char *config)
+{
+       enumerator_t *enumerator;
+       ike_sa_t *ike_sa;
+       int id = 0;
+
+       enumerator = charon->controller->create_ike_sa_enumerator(charon->controller);
+       while (enumerator->enumerate(enumerator, &ike_sa))
+       {
+               if (strcaseeq(config, ike_sa->get_name(ike_sa)))
+               {
+                       id = ike_sa->get_unique_id(ike_sa);
+                       break;
+               }
+       }
+       enumerator->destroy(enumerator);
+       if (id)
+       {
+               DBG1(DBG_CFG, "closing IKE_SA '%s'", config);
+               charon->controller->terminate_ike(charon->controller, id, NULL, NULL);
+       }
+       else
+       {
+               DBG1(DBG_CFG, "unable to close IKE_SA '%s', not found", config);
+       }
+       return JOB_REQUEUE_NONE;
+}
+
+/**
+ * Close a CHILD_SAs
+ */
+static job_requeue_t close_child(char *config)
+{
+       enumerator_t *enumerator;
+       iterator_t *children;
+       ike_sa_t *ike_sa;
+       child_sa_t *child_sa;
+       int id = 0;
+
+       enumerator = charon->controller->create_ike_sa_enumerator(charon->controller);
+       while (enumerator->enumerate(enumerator, &ike_sa))
+       {
+
+               children = ike_sa->create_child_sa_iterator(ike_sa);
+               while (children->iterate(children, (void**)&child_sa))
+               {
+                       if (streq(config, child_sa->get_name(child_sa)))
+                       {
+                               id = child_sa->get_reqid(child_sa);
+                               break;
+                       }
+               }
+               children->destroy(children);
+       }
+       enumerator->destroy(enumerator);
+       if (id)
+       {
+               DBG1(DBG_CFG, "closing CHILD_SA '%s'", config);
+               charon->controller->terminate_child(charon->controller, id, NULL, NULL);
+       }
+       else
+       {
+               DBG1(DBG_CFG, "unable to close CHILD_SA '%s', not found", config);
+       }
+       return JOB_REQUEUE_NONE;
+}
+
+/**
+ * Load a single action
+ */
+static void load_action(settings_t *settings, char *action)
+{
+       static struct {
+               char *name;
+               callback_job_cb_t cb;
+       } actions[] = {
+               {"initiate",            (void*)initiate},
+               {"rekey_ike",           (void*)rekey_ike},
+               {"rekey_child",         (void*)rekey_child},
+               {"liveness",            (void*)liveness},
+               {"close_ike",           (void*)close_ike},
+               {"close_child",         (void*)close_child},
+       };
+       bool found = FALSE;
+       int i;
+
+       for (i = 0; i < countof(actions); i++)
+       {
+               if (strcaseeq(actions[i].name, action))
+               {
+                       int delay;
+                       char *config;
+
+                       found = TRUE;
+                       delay = settings->get_int(settings, "actions.%s.delay", 0, action);
+                       config = settings->get_str(settings, "actions.%s.config",
+                                                                          NULL, action);
+                       if (!config)
+                       {
+                               DBG1(DBG_CFG, "no config defined for action '%s'", action);
+                               break;
+                       }
+                       lib->scheduler->schedule_job(lib->scheduler,
+                               (job_t*)callback_job_create(actions[i].cb, config, NULL, NULL),
+                               delay);
+               }
+       }
+       if (!found)
+       {
+               DBG1(DBG_CFG, "unknown action '%s', skipped", action);
+       }
+}
+
+/**
+ * Load configured actions
+ */
+static void load_actions(settings_t *settings)
+{
+       enumerator_t *enumerator;
+       char *action;
+
+       enumerator = settings->create_section_enumerator(settings, "actions");
+       while (enumerator->enumerate(enumerator, &action))
+       {
+               load_action(settings, action);
+       }
+       enumerator->destroy(enumerator);
+}
+
+METHOD(actions_t, destroy, void,
+       private_actions_t *this)
+{
+       free(this);
+}
+
+/**
+ * See header
+ */
+actions_t *actions_create()
+{
+       private_actions_t *this;
+
+       INIT(this,
+               .public = {
+                       .destroy = _destroy,
+               },
+       );
+
+       load_actions(conftest->test);
+
+       return &this->public;
+}
diff --git a/src/conftest/actions.h b/src/conftest/actions.h
new file mode 100644 (file)
index 0000000..2e1cbba
--- /dev/null
@@ -0,0 +1,42 @@
+/*
+ * Copyright (C) 2010 Martin Willi
+ * Copyright (C) 2010 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 actions actions
+ * @{ @ingroup conftest
+ */
+
+#ifndef ACTIONS_H_
+#define ACTIONS_H_
+
+typedef struct actions_t actions_t;
+
+/**
+ * actionss to trigger based on configuration.
+ */
+struct actions_t {
+
+       /**
+        * Destroy a actions_t.
+        */
+       void (*destroy)(actions_t *this);
+};
+
+/**
+ * Create a actions instance.
+ */
+actions_t *actions_create();
+
+#endif /** ACTIONS_H_ @}*/
index 6efd063..604fe26 100644 (file)
@@ -255,6 +255,7 @@ static void cleanup()
        DESTROY_IF(conftest->test);
        lib->credmgr->remove_set(lib->credmgr, &conftest->creds->set);
        conftest->creds->destroy(conftest->creds);
+       DESTROY_IF(conftest->actions);
        while (conftest->hooks->remove_last(conftest->hooks,
                                                                                (void**)&hook) == SUCCESS)
        {
@@ -378,6 +379,7 @@ int main(int argc, char *argv[])
        charon->backends->add_backend(charon->backends, &conftest->config->backend);
        conftest->config->load(conftest->config, conftest->suite);
        conftest->config->load(conftest->config, conftest->test);
+       conftest->actions = actions_create();
 
        /* set up thread specific handlers */
        action.sa_handler = segv_handler;
index 5fa2e37..2d32e6c 100644 (file)
@@ -26,6 +26,7 @@
 #include <credentials/sets/mem_cred.h>
 
 #include "config.h"
+#include "actions.h"
 
 typedef struct conftest_t conftest_t;
 
@@ -68,6 +69,11 @@ struct conftest_t {
         * Loaded hooks
         */
        linked_list_t *hooks;
+
+       /**
+        * Action handling
+        */
+       actions_t *actions;
 };
 
 /**