]> git.ipfire.org Git - people/ms/strongswan.git/commitdiff
Merge branch 'vici-undo-on-unload'
authorMartin Willi <martin@strongswan.org>
Mon, 7 Dec 2015 09:29:57 +0000 (10:29 +0100)
committerMartin Willi <martin@strongswan.org>
Mon, 7 Dec 2015 09:29:57 +0000 (10:29 +0100)
Undo start actions when unloading connections, and add some misc fixes and
extensions to vici connection handling.

src/libcharon/plugins/vici/README.md
src/libcharon/plugins/vici/vici_config.c
src/libcharon/plugins/vici/vici_control.c
src/libstrongswan/collections/array.c
src/libstrongswan/collections/array.h
src/libstrongswan/tests/suites/test_array.c

index f5759870d8de594c1a3f6f09e38d422a4b5aabdb..b7e2a5e64c87ada0340b468d6f52ff8ae9c77985 100644 (file)
@@ -258,7 +258,8 @@ Initiates an SA while streaming _control-log_ events.
 
        {
                child = <CHILD_SA configuration name to initiate>
-               timeout = <timeout in seconds before returning>
+               ike = <optional IKE_SA configuraiton name to find child under>
+               timeout = <timeout in ms before returning>
                init-limits = <whether limits may prevent initiating the CHILD_SA>
                loglevel = <loglevel to issue "control-log" events for>
        } => {
@@ -266,6 +267,9 @@ Initiates an SA while streaming _control-log_ events.
                errmsg = <error string on failure or timeout>
        }
 
+The default timeout of 0 waits indefinitely for a result, and a timeout value
+of -1 returns a result immediately.
+
 ### terminate() ###
 
 Terminates an SA while streaming _control-log_ events.
@@ -275,19 +279,23 @@ Terminates an SA while streaming _control-log_ events.
                ike = <terminate an IKE_SA by configuration name>
                child_id = <terminate a CHILD_SA by its reqid>
                ike_id = <terminate an IKE_SA by its unique id>
-               timeout = <timeout in seconds before returning>
+               timeout = <timeout in ms before returning>
                loglevel = <loglevel to issue "control-log" events for>
        } => {
                success = <yes or no>
                errmsg = <error string on failure or timeout>
        }
 
+The default timeout of 0 waits indefinitely for a result, and a timeout value
+of -1 returns a result immediately.
+
 ### install() ###
 
 Install a trap, drop or bypass policy defined by a CHILD_SA config.
 
        {
                child = <CHILD_SA configuration name to install>
+               ike = <optional IKE_SA configuraiton name to find child under>
        } => {
                success = <yes or no>
                errmsg = <error string on failure>
index ea6d2958a0e96764eb11aad588d68cfb3b816647..7f7ce61a1567fddddf55135fec374aa43def83bd 100644 (file)
@@ -1613,14 +1613,14 @@ static void run_start_action(private_vici_config_t *this, peer_cfg_t *peer_cfg,
 /**
  * Undo start actions associated to a child config
  */
-static void clear_start_action(private_vici_config_t *this,
+static void clear_start_action(private_vici_config_t *this, char *peer_name,
                                                           child_cfg_t *child_cfg)
 {
        enumerator_t *enumerator, *children;
        child_sa_t *child_sa;
        ike_sa_t *ike_sa;
-       u_int32_t id = 0, *del;
-       array_t *ids = NULL;
+       u_int32_t id = 0, others;
+       array_t *ids = NULL, *ikeids = NULL;
        char *name;
 
        name = child_cfg->get_name(child_cfg);
@@ -1631,29 +1631,72 @@ static void clear_start_action(private_vici_config_t *this,
                                                                                                        charon->controller, TRUE);
                        while (enumerator->enumerate(enumerator, &ike_sa))
                        {
+                               if (!streq(ike_sa->get_name(ike_sa), peer_name))
+                               {
+                                       continue;
+                               }
+                               others = id = 0;
                                children = ike_sa->create_child_sa_enumerator(ike_sa);
                                while (children->enumerate(children, &child_sa))
                                {
-                                       if (streq(name, child_sa->get_name(child_sa)))
+                                       if (child_sa->get_state(child_sa) != CHILD_DELETING)
                                        {
-                                               id = child_sa->get_unique_id(child_sa);
-                                               array_insert_create(&ids, ARRAY_TAIL, &id);
+                                               if (streq(name, child_sa->get_name(child_sa)))
+                                               {
+                                                       id = child_sa->get_unique_id(child_sa);
+                                               }
+                                               else
+                                               {
+                                                       others++;
+                                               }
                                        }
                                }
                                children->destroy(children);
+
+                               if (id && !others)
+                               {
+                                       /* found matching children only, delete full IKE_SA */
+                                       id = ike_sa->get_unique_id(ike_sa);
+                                       array_insert_create_value(&ikeids, sizeof(id),
+                                                                                         ARRAY_TAIL, &id);
+                               }
+                               else
+                               {
+                                       children = ike_sa->create_child_sa_enumerator(ike_sa);
+                                       while (children->enumerate(children, &child_sa))
+                                       {
+                                               if (streq(name, child_sa->get_name(child_sa)))
+                                               {
+                                                       id = child_sa->get_unique_id(child_sa);
+                                                       array_insert_create_value(&ids, sizeof(id),
+                                                                                                         ARRAY_TAIL, &id);
+                                               }
+                                       }
+                                       children->destroy(children);
+                               }
                        }
                        enumerator->destroy(enumerator);
 
                        if (array_count(ids))
                        {
-                               while (array_remove(ids, ARRAY_HEAD, &del))
+                               while (array_remove(ids, ARRAY_HEAD, &id))
                                {
-                                       DBG1(DBG_CFG, "closing '%s' #%u", name, *del);
+                                       DBG1(DBG_CFG, "closing '%s' #%u", name, id);
                                        charon->controller->terminate_child(charon->controller,
-                                                                                                               *del, NULL, NULL, 0);
+                                                                                                               id, NULL, NULL, 0);
                                }
                                array_destroy(ids);
                        }
+                       if (array_count(ikeids))
+                       {
+                               while (array_remove(ikeids, ARRAY_HEAD, &id))
+                               {
+                                       DBG1(DBG_CFG, "closing IKE_SA #%u", id);
+                                       charon->controller->terminate_ike(charon->controller,
+                                                                                                         id, NULL, NULL, 0);
+                               }
+                               array_destroy(ikeids);
+                       }
                        break;
                case ACTION_ROUTE:
                        DBG1(DBG_CFG, "uninstalling '%s'", name);
@@ -1714,7 +1757,7 @@ static void clear_start_actions(private_vici_config_t *this,
        enumerator = peer_cfg->create_child_cfg_enumerator(peer_cfg);
        while (enumerator->enumerate(enumerator, &child_cfg))
        {
-               clear_start_action(this, child_cfg);
+               clear_start_action(this, peer_cfg->get_name(peer_cfg), child_cfg);
        }
        enumerator->destroy(enumerator);
 }
@@ -1732,7 +1775,7 @@ static void replace_children(private_vici_config_t *this,
        while (enumerator->enumerate(enumerator, &child))
        {
                to->remove_child_cfg(to, enumerator);
-               clear_start_action(this, child);
+               clear_start_action(this, to->get_name(to), child);
                child->destroy(child);
        }
        enumerator->destroy(enumerator);
@@ -1843,9 +1886,8 @@ CALLBACK(config_sn, bool,
 
        if (peer.local->get_count(peer.local) == 0)
        {
-               free_peer_data(&peer);
-               peer.request->reply = create_reply("missing local auth config");
-               return FALSE;
+               auth_cfg = auth_cfg_create();
+               peer.local->insert_last(peer.local, auth_cfg);
        }
        if (peer.remote->get_count(peer.remote) == 0)
        {
@@ -2005,6 +2047,7 @@ CALLBACK(unload_conn, vici_message_t*,
                if (streq(cfg->get_name(cfg), conn_name))
                {
                        this->conns->remove_at(this->conns, enumerator);
+                       clear_start_actions(this, cfg);
                        cfg->destroy(cfg);
                        found = TRUE;
                        break;
index 752007c242172080c564d395791830d2d92c0453..87794d24dda28ca464ab82523d2591fff4e11d39 100644 (file)
@@ -134,7 +134,7 @@ static child_cfg_t* get_child_from_peer(peer_cfg_t *peer_cfg, char *name)
 /**
  * Find a peer/child config from a child config name
  */
-static child_cfg_t* find_child_cfg(char *name, peer_cfg_t **out)
+static child_cfg_t* find_child_cfg(char *name, char *pname, peer_cfg_t **out)
 {
        enumerator_t *enumerator;
        peer_cfg_t *peer_cfg;
@@ -144,6 +144,10 @@ static child_cfg_t* find_child_cfg(char *name, peer_cfg_t **out)
                                                        charon->backends, NULL, NULL, NULL, NULL, IKE_ANY);
        while (enumerator->enumerate(enumerator, &peer_cfg))
        {
+               if (pname && !streq(pname, peer_cfg->get_name(peer_cfg)))
+               {
+                       continue;
+               }
                child_cfg = get_child_from_peer(peer_cfg, name);
                if (child_cfg)
                {
@@ -161,15 +165,17 @@ CALLBACK(initiate, vici_message_t*,
 {
        child_cfg_t *child_cfg = NULL;
        peer_cfg_t *peer_cfg;
-       char *child;
-       u_int timeout;
+       char *child, *ike;
+       int timeout;
        bool limits;
+       controller_cb_t log_cb = NULL;
        log_info_t log = {
                .dispatcher = this->dispatcher,
                .id = id,
        };
 
        child = request->get_str(request, NULL, "child");
+       ike = request->get_str(request, NULL, "ike");
        timeout = request->get_int(request, 0, "timeout");
        limits = request->get_bool(request, FALSE, "init-limits");
        log.level = request->get_int(request, 1, "loglevel");
@@ -178,16 +184,20 @@ CALLBACK(initiate, vici_message_t*,
        {
                return send_reply(this, "missing configuration name");
        }
+       if (timeout >= 0)
+       {
+               log_cb = (controller_cb_t)log_vici;
+       }
 
        DBG1(DBG_CFG, "vici initiate '%s'", child);
 
-       child_cfg = find_child_cfg(child, &peer_cfg);
+       child_cfg = find_child_cfg(child, ike, &peer_cfg);
        if (!child_cfg)
        {
                return send_reply(this, "CHILD_SA config '%s' not found", child);
        }
        switch (charon->controller->initiate(charon->controller, peer_cfg,
-                               child_cfg, (controller_cb_t)log_vici, &log, timeout, limits))
+                                                                       child_cfg, log_cb, &log, timeout, limits))
        {
                case SUCCESS:
                        return send_reply(this, NULL);
@@ -208,11 +218,13 @@ CALLBACK(terminate, vici_message_t*,
 {
        enumerator_t *enumerator, *isas, *csas;
        char *child, *ike, *errmsg = NULL;
-       u_int timeout, child_id, ike_id, current, *del, done = 0;
+       u_int child_id, ike_id, current, *del, done = 0;
+       int timeout;
        ike_sa_t *ike_sa;
        child_sa_t *child_sa;
        array_t *ids;
        vici_builder_t *builder;
+       controller_cb_t log_cb = NULL;
        log_info_t log = {
                .dispatcher = this->dispatcher,
                .id = id,
@@ -247,6 +259,11 @@ CALLBACK(terminate, vici_message_t*,
                DBG1(DBG_CFG, "vici terminate CHILD_SA '%s'", child);
        }
 
+       if (timeout >= 0)
+       {
+               log_cb = (controller_cb_t)log_vici;
+       }
+
        ids = array_create(sizeof(u_int), 0);
 
        isas = charon->controller->create_ike_sa_enumerator(charon->controller, TRUE);
@@ -296,7 +313,7 @@ CALLBACK(terminate, vici_message_t*,
                if (child || child_id)
                {
                        if (charon->controller->terminate_child(charon->controller, *del,
-                                               (controller_cb_t)log_vici, &log, timeout) == SUCCESS)
+                                                                                       log_cb, &log, timeout) == SUCCESS)
                        {
                                done++;
                        }
@@ -304,7 +321,7 @@ CALLBACK(terminate, vici_message_t*,
                else
                {
                        if (charon->controller->terminate_ike(charon->controller, *del,
-                                               (controller_cb_t)log_vici, &log, timeout) == SUCCESS)
+                                                                                       log_cb, &log, timeout) == SUCCESS)
                        {
                                done++;
                        }
@@ -379,10 +396,11 @@ CALLBACK(install, vici_message_t*,
 {
        child_cfg_t *child_cfg = NULL;
        peer_cfg_t *peer_cfg;
-       char *child;
+       char *child, *ike;
        bool ok;
 
        child = request->get_str(request, NULL, "child");
+       ike = request->get_str(request, NULL, "ike");
        if (!child)
        {
                return send_reply(this, "missing configuration name");
@@ -390,7 +408,7 @@ CALLBACK(install, vici_message_t*,
 
        DBG1(DBG_CFG, "vici install '%s'", child);
 
-       child_cfg = find_child_cfg(child, &peer_cfg);
+       child_cfg = find_child_cfg(child, ike, &peer_cfg);
        if (!child_cfg)
        {
                return send_reply(this, "configuration name not found");
index 61c696bc103311d697884b2af15146889e719976..a45a68aafeb3a35659e070bbd69dd5cee3b498ab 100644 (file)
@@ -277,6 +277,16 @@ void array_insert_create(array_t **array, int idx, void *ptr)
        array_insert(*array, idx, ptr);
 }
 
+void array_insert_create_value(array_t **array, u_int esize,
+                                                          int idx, void *val)
+{
+       if (*array == NULL)
+       {
+               *array = array_create(esize, 0);
+       }
+       array_insert(*array, idx, val);
+}
+
 void array_insert_enumerator(array_t *array, int idx, enumerator_t *enumerator)
 {
        void *ptr;
index 0659c70bddc66d114d6bf62cfacf0b5dab364ed6..c3be1a15d611176bc4e04aff02b617a2fd29a2c5 100644 (file)
@@ -138,6 +138,21 @@ void array_insert(array_t *array, int idx, void *data);
  */
 void array_insert_create(array_t **array, int idx, void *ptr);
 
+/**
+ * Create a value based array if it does not exist, insert value.
+ *
+ * This is a convenience function to insert a value and implicitly
+ * create a value based array if array is NULL. Array is set the the newly
+ * created array, if any.
+ *
+ * @param array                        pointer to array reference, potentially NULL
+ * @param esize                        element size of this array
+ * @param idx                  index to insert item at
+ * @param val                  pointer to value to insert
+ */
+void array_insert_create_value(array_t **array, u_int esize,
+                                                          int idx, void *val);
+
 /**
  * Insert all items from an enumerator to an array.
  *
index ba2aff4607b25ca6decca866a5db3a514c85e868..eda72e10a1c2c4d4c84e9176db2eca113f562b90 100644 (file)
@@ -491,6 +491,44 @@ START_TEST(test_invoke_offset)
 }
 END_TEST
 
+START_TEST(test_insert_create)
+{
+       array_t *array = NULL;
+       uintptr_t x;
+
+       array_insert_create(&array, ARRAY_TAIL, (void*)(uintptr_t)1);
+       array_insert_create(&array, ARRAY_TAIL, (void*)(uintptr_t)2);
+       ck_assert(array != NULL);
+
+       ck_assert(array_get(array, ARRAY_HEAD, &x));
+       ck_assert_int_eq(x, 1);
+       ck_assert(array_get(array, ARRAY_TAIL, &x));
+       ck_assert_int_eq(x, 2);
+
+       array_destroy(array);
+}
+END_TEST
+
+START_TEST(test_insert_create_value)
+{
+       array_t *array = NULL;
+       u_int16_t v;
+
+       v = 1;
+       array_insert_create_value(&array, sizeof(v), ARRAY_TAIL, &v);
+       v = 2;
+       array_insert_create_value(&array, sizeof(v), ARRAY_TAIL, &v);
+       ck_assert(array != NULL);
+
+       ck_assert(array_get(array, ARRAY_HEAD, &v));
+       ck_assert_int_eq(v, 1);
+       ck_assert(array_get(array, ARRAY_TAIL, &v));
+       ck_assert_int_eq(v, 2);
+
+       array_destroy(array);
+}
+END_TEST
+
 Suite *array_suite_create()
 {
        Suite *s;
@@ -528,5 +566,10 @@ Suite *array_suite_create()
        tcase_add_test(tc, test_invoke_offset);
        suite_add_tcase(s, tc);
 
+       tc = tcase_create("insert create");
+       tcase_add_test(tc, test_insert_create);
+       tcase_add_test(tc, test_insert_create_value);
+       suite_add_tcase(s, tc);
+
        return s;
 }