From f3b2d4a9d85e8bf44425012cb792e3311c11b3c5 Mon Sep 17 00:00:00 2001 From: Martin Willi Date: Wed, 4 Nov 2015 13:25:07 +0100 Subject: vici: Undo start actions when unloading configs --- src/libcharon/plugins/vici/vici_config.c | 1 + 1 file changed, 1 insertion(+) (limited to 'src') diff --git a/src/libcharon/plugins/vici/vici_config.c b/src/libcharon/plugins/vici/vici_config.c index ea6d2958a..c1dbbc2ab 100644 --- a/src/libcharon/plugins/vici/vici_config.c +++ b/src/libcharon/plugins/vici/vici_config.c @@ -2005,6 +2005,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; -- cgit v1.2.3 From 01caed533b8df3c96fc039a863c8d5f0c64e134d Mon Sep 17 00:00:00 2001 From: Martin Willi Date: Fri, 4 Dec 2015 09:02:28 +0100 Subject: array: Add an insert/create function for value based arrays --- src/libstrongswan/collections/array.c | 10 +++++++ src/libstrongswan/collections/array.h | 15 ++++++++++ src/libstrongswan/tests/suites/test_array.c | 43 +++++++++++++++++++++++++++++ 3 files changed, 68 insertions(+) (limited to 'src') diff --git a/src/libstrongswan/collections/array.c b/src/libstrongswan/collections/array.c index 61c696bc1..a45a68aaf 100644 --- a/src/libstrongswan/collections/array.c +++ b/src/libstrongswan/collections/array.c @@ -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; diff --git a/src/libstrongswan/collections/array.h b/src/libstrongswan/collections/array.h index 0659c70bd..c3be1a15d 100644 --- a/src/libstrongswan/collections/array.h +++ b/src/libstrongswan/collections/array.h @@ -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. * diff --git a/src/libstrongswan/tests/suites/test_array.c b/src/libstrongswan/tests/suites/test_array.c index ba2aff460..eda72e10a 100644 --- a/src/libstrongswan/tests/suites/test_array.c +++ b/src/libstrongswan/tests/suites/test_array.c @@ -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; } -- cgit v1.2.3 From 2facf18833fdc55ad72d1828ed62d8856d24430d Mon Sep 17 00:00:00 2001 From: Martin Willi Date: Fri, 4 Dec 2015 09:05:31 +0100 Subject: vici: Use value based array to store CHILD_SA ids during restart The previous approach stored a pointer to a volatile stack variable, which works for a single ID, but not for multiple. --- src/libcharon/plugins/vici/vici_config.c | 11 ++++++----- 1 file changed, 6 insertions(+), 5 deletions(-) (limited to 'src') diff --git a/src/libcharon/plugins/vici/vici_config.c b/src/libcharon/plugins/vici/vici_config.c index c1dbbc2ab..69bcd4c7a 100644 --- a/src/libcharon/plugins/vici/vici_config.c +++ b/src/libcharon/plugins/vici/vici_config.c @@ -1619,7 +1619,7 @@ static void clear_start_action(private_vici_config_t *this, enumerator_t *enumerator, *children; child_sa_t *child_sa; ike_sa_t *ike_sa; - u_int32_t id = 0, *del; + u_int32_t id = 0; array_t *ids = NULL; char *name; @@ -1637,7 +1637,8 @@ static void clear_start_action(private_vici_config_t *this, if (streq(name, child_sa->get_name(child_sa))) { id = child_sa->get_unique_id(child_sa); - array_insert_create(&ids, ARRAY_TAIL, &id); + array_insert_create_value(&ids, sizeof(id), + ARRAY_TAIL, &id); } } children->destroy(children); @@ -1646,11 +1647,11 @@ static void clear_start_action(private_vici_config_t *this, 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); } -- cgit v1.2.3 From 23b1f7137241ebbb54bbdc78d3b985c86c85ff1b Mon Sep 17 00:00:00 2001 From: Martin Willi Date: Wed, 4 Nov 2015 13:25:51 +0100 Subject: vici: Close empty IKE_SAs after undoing CHILD_SA start actions --- src/libcharon/plugins/vici/vici_config.c | 50 ++++++++++++++++++++++++++++---- 1 file changed, 44 insertions(+), 6 deletions(-) (limited to 'src') diff --git a/src/libcharon/plugins/vici/vici_config.c b/src/libcharon/plugins/vici/vici_config.c index 69bcd4c7a..9a36136b9 100644 --- a/src/libcharon/plugins/vici/vici_config.c +++ b/src/libcharon/plugins/vici/vici_config.c @@ -1619,8 +1619,8 @@ static void clear_start_action(private_vici_config_t *this, enumerator_t *enumerator, *children; child_sa_t *child_sa; ike_sa_t *ike_sa; - u_int32_t id = 0; - 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,17 +1631,45 @@ static void clear_start_action(private_vici_config_t *this, charon->controller, TRUE); while (enumerator->enumerate(enumerator, &ike_sa)) { + 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_value(&ids, sizeof(id), - 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); @@ -1655,6 +1683,16 @@ static void clear_start_action(private_vici_config_t *this, } 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); -- cgit v1.2.3 From b26ba1b4a477dd75af30f416b445e1b1fd18a1a0 Mon Sep 17 00:00:00 2001 From: Martin Willi Date: Wed, 4 Nov 2015 16:03:14 +0100 Subject: vici: Limit start action undoing to IKE_SAs using the base peer config name If two peer configs use the same child config names, potentailly delete the wrong CHILD_SA. Check the peer config name as well to avoid that. --- src/libcharon/plugins/vici/vici_config.c | 10 +++++++--- 1 file changed, 7 insertions(+), 3 deletions(-) (limited to 'src') diff --git a/src/libcharon/plugins/vici/vici_config.c b/src/libcharon/plugins/vici/vici_config.c index 9a36136b9..2a652e014 100644 --- a/src/libcharon/plugins/vici/vici_config.c +++ b/src/libcharon/plugins/vici/vici_config.c @@ -1613,7 +1613,7 @@ 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; @@ -1631,6 +1631,10 @@ 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)) @@ -1753,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); } @@ -1771,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); -- cgit v1.2.3 From 1db918c4f89fa97ecf04ec29b07960e7cf91fa5c Mon Sep 17 00:00:00 2001 From: Martin Willi Date: Wed, 4 Nov 2015 17:04:11 +0100 Subject: vici: Use an empty local auth round if none given While it hardly makes sense to use none for negotiated SAs, it actually does when installing shunt policies. --- src/libcharon/plugins/vici/vici_config.c | 5 ++--- 1 file changed, 2 insertions(+), 3 deletions(-) (limited to 'src') diff --git a/src/libcharon/plugins/vici/vici_config.c b/src/libcharon/plugins/vici/vici_config.c index 2a652e014..7f7ce61a1 100644 --- a/src/libcharon/plugins/vici/vici_config.c +++ b/src/libcharon/plugins/vici/vici_config.c @@ -1886,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) { -- cgit v1.2.3 From 5e79ae2d65e16e17bf3daee79756559d2c6e0eed Mon Sep 17 00:00:00 2001 From: Martin Willi Date: Thu, 5 Nov 2015 10:04:35 +0100 Subject: vici: Support completely asynchronous initiating and termination In some situations the vici client is not interested in waiting for a timeout at all, so don't register a logging callback if the timeout argument is negative. --- src/libcharon/plugins/vici/README.md | 6 ++++++ src/libcharon/plugins/vici/vici_control.c | 22 +++++++++++++++++----- 2 files changed, 23 insertions(+), 5 deletions(-) (limited to 'src') diff --git a/src/libcharon/plugins/vici/README.md b/src/libcharon/plugins/vici/README.md index f5759870d..736626d92 100644 --- a/src/libcharon/plugins/vici/README.md +++ b/src/libcharon/plugins/vici/README.md @@ -266,6 +266,9 @@ Initiates an SA while streaming _control-log_ events. errmsg = } +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. @@ -282,6 +285,9 @@ Terminates an SA while streaming _control-log_ events. errmsg = } +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. diff --git a/src/libcharon/plugins/vici/vici_control.c b/src/libcharon/plugins/vici/vici_control.c index 752007c24..0756d53e6 100644 --- a/src/libcharon/plugins/vici/vici_control.c +++ b/src/libcharon/plugins/vici/vici_control.c @@ -162,8 +162,9 @@ CALLBACK(initiate, vici_message_t*, child_cfg_t *child_cfg = NULL; peer_cfg_t *peer_cfg; char *child; - u_int timeout; + int timeout; bool limits; + controller_cb_t log_cb = NULL; log_info_t log = { .dispatcher = this->dispatcher, .id = id, @@ -178,6 +179,10 @@ 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); @@ -187,7 +192,7 @@ CALLBACK(initiate, vici_message_t*, 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 +213,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 +254,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 +308,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 +316,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++; } -- cgit v1.2.3 From eaca77d03e84520d577948f944126d0ff2d3ca69 Mon Sep 17 00:00:00 2001 From: Martin Willi Date: Thu, 5 Nov 2015 10:09:00 +0100 Subject: vici: Honor an optionally passed IKE configuration name in initiate/install If two IKE configurations have CHILD configurations with the same name, we have no control about the CHILD_SA that actually gets controlled. The new "ike" parameter specifies the peer config name to find the "child" config under. --- src/libcharon/plugins/vici/README.md | 2 ++ src/libcharon/plugins/vici/vici_control.c | 16 +++++++++++----- 2 files changed, 13 insertions(+), 5 deletions(-) (limited to 'src') diff --git a/src/libcharon/plugins/vici/README.md b/src/libcharon/plugins/vici/README.md index 736626d92..7be247300 100644 --- a/src/libcharon/plugins/vici/README.md +++ b/src/libcharon/plugins/vici/README.md @@ -258,6 +258,7 @@ Initiates an SA while streaming _control-log_ events. { child = + ike = timeout = init-limits = loglevel = @@ -294,6 +295,7 @@ Install a trap, drop or bypass policy defined by a CHILD_SA config. { child = + ike = } => { success = errmsg = diff --git a/src/libcharon/plugins/vici/vici_control.c b/src/libcharon/plugins/vici/vici_control.c index 0756d53e6..87794d24d 100644 --- a/src/libcharon/plugins/vici/vici_control.c +++ b/src/libcharon/plugins/vici/vici_control.c @@ -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,7 +165,7 @@ CALLBACK(initiate, vici_message_t*, { child_cfg_t *child_cfg = NULL; peer_cfg_t *peer_cfg; - char *child; + char *child, *ike; int timeout; bool limits; controller_cb_t log_cb = NULL; @@ -171,6 +175,7 @@ CALLBACK(initiate, vici_message_t*, }; 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"); @@ -186,7 +191,7 @@ CALLBACK(initiate, vici_message_t*, 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); @@ -391,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"); @@ -402,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"); -- cgit v1.2.3 From 1a8a420c1c1be781c5c5aa2d7d95599d2fbd35e8 Mon Sep 17 00:00:00 2001 From: Martin Willi Date: Tue, 1 Dec 2015 09:26:40 +0100 Subject: vici: Fix documentation about the initiate/terminate timeout --- src/libcharon/plugins/vici/README.md | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) (limited to 'src') diff --git a/src/libcharon/plugins/vici/README.md b/src/libcharon/plugins/vici/README.md index 7be247300..b7e2a5e64 100644 --- a/src/libcharon/plugins/vici/README.md +++ b/src/libcharon/plugins/vici/README.md @@ -259,7 +259,7 @@ Initiates an SA while streaming _control-log_ events. { child = ike = - timeout = + timeout = init-limits = loglevel = } => { @@ -279,7 +279,7 @@ Terminates an SA while streaming _control-log_ events. ike = child_id = ike_id = - timeout = + timeout = loglevel = } => { success = -- cgit v1.2.3