diff options
author | Tobias Brunner <tobias@strongswan.org> | 2015-08-21 18:21:24 +0200 |
---|---|---|
committer | Tobias Brunner <tobias@strongswan.org> | 2015-08-21 18:21:24 +0200 |
commit | d88cec920c9def7ed2d9906858f4b88a4b46a730 (patch) | |
tree | cc5798460efe4618077e8b17694ed6340071b6d4 /src | |
parent | ffa20bad6356732e840aaffc6f9ef8fd1e6eb88e (diff) | |
parent | 256e666d2235718a3711cf7ad9634354c10f7a7e (diff) | |
download | strongswan-d88cec920c9def7ed2d9906858f4b88a4b46a730.tar.bz2 strongswan-d88cec920c9def7ed2d9906858f4b88a4b46a730.tar.xz |
Merge branch 'init-limits'
IKE_SAs that are initiated are now counted towards the half-open IKE_SAs
limit. Optionally it is possible to enforce limits towards the number of
half-open IKE_SAs and the job load also when initiating SAs. This is
currently only possible via VICI.
Diffstat (limited to 'src')
20 files changed, 171 insertions, 21 deletions
diff --git a/src/charon-cmd/cmd/cmd_connection.c b/src/charon-cmd/cmd/cmd_connection.c index 2c0b7b9d5..0c6a504e9 100644 --- a/src/charon-cmd/cmd/cmd_connection.c +++ b/src/charon-cmd/cmd/cmd_connection.c @@ -434,7 +434,7 @@ static job_requeue_t initiate(private_cmd_connection_t *this) child_cfg = create_child_cfg(this, peer_cfg); if (charon->controller->initiate(charon->controller, peer_cfg, child_cfg, - controller_cb_empty, NULL, 0) != SUCCESS) + controller_cb_empty, NULL, 0, FALSE) != SUCCESS) { terminate(pid); } diff --git a/src/conftest/actions.c b/src/conftest/actions.c index 474672ca1..256b63d1b 100644 --- a/src/conftest/actions.c +++ b/src/conftest/actions.c @@ -65,7 +65,7 @@ static job_requeue_t initiate(char *config) { DBG1(DBG_CFG, "initiating IKE_SA for CHILD_SA config '%s'", config); charon->controller->initiate(charon->controller, peer_cfg, child_cfg, - NULL, NULL, 0); + NULL, NULL, 0, FALSE); } else { diff --git a/src/frontends/osx/charon-xpc/xpc_dispatch.c b/src/frontends/osx/charon-xpc/xpc_dispatch.c index 04aad8735..4b4c67cc4 100644 --- a/src/frontends/osx/charon-xpc/xpc_dispatch.c +++ b/src/frontends/osx/charon-xpc/xpc_dispatch.c @@ -196,7 +196,7 @@ void start_connection(private_xpc_dispatch_t *this, peer_cfg->add_child_cfg(peer_cfg, child_cfg->get_ref(child_cfg)); if (charon->controller->initiate(charon->controller, peer_cfg, child_cfg, - (controller_cb_t)initiate_cb, &ike_sa, 0) == NEED_MORE) + (controller_cb_t)initiate_cb, &ike_sa, 0, FALSE) == NEED_MORE) { this->channels->add(this->channels, channel, ike_sa); success = TRUE; diff --git a/src/libcharon/control/controller.c b/src/libcharon/control/controller.c index fd8349e2f..097f5ac2e 100644 --- a/src/libcharon/control/controller.c +++ b/src/libcharon/control/controller.c @@ -1,5 +1,5 @@ /* - * Copyright (C) 2011-2012 Tobias Brunner + * Copyright (C) 2011-2015 Tobias Brunner * Copyright (C) 2007-2011 Martin Willi * Copyright (C) 2011 revosec AG * Hochschule fuer Technik Rapperswil @@ -116,6 +116,11 @@ struct interface_listener_t { * spinlock to update the IKE_SA handle properly */ spinlock_t *lock; + + /** + * whether to check limits + */ + bool limits; }; @@ -358,7 +363,6 @@ METHOD(job_t, initiate_execute, job_requeue_t, listener->child_cfg->destroy(listener->child_cfg); peer_cfg->destroy(peer_cfg); listener->status = FAILED; - /* release listener */ listener_done(listener); return JOB_REQUEUE_NONE; } @@ -372,6 +376,49 @@ METHOD(job_t, initiate_execute, job_requeue_t, } peer_cfg->destroy(peer_cfg); + if (listener->limits && ike_sa->get_state(ike_sa) == IKE_CREATED) + { /* only check if we are not reusing an IKE_SA */ + u_int half_open, limit_half_open, limit_job_load; + + half_open = charon->ike_sa_manager->get_half_open_count( + charon->ike_sa_manager, NULL); + limit_half_open = lib->settings->get_int(lib->settings, + "%s.init_limit_half_open", 0, lib->ns); + limit_job_load = lib->settings->get_int(lib->settings, + "%s.init_limit_job_load", 0, lib->ns); + if (limit_half_open && half_open >= limit_half_open) + { + DBG1(DBG_IKE, "abort IKE_SA initiation, half open IKE_SA count of " + "%d exceeds limit of %d", half_open, limit_half_open); + charon->ike_sa_manager->checkin_and_destroy(charon->ike_sa_manager, + ike_sa); + listener->child_cfg->destroy(listener->child_cfg); + listener->status = INVALID_STATE; + listener_done(listener); + return JOB_REQUEUE_NONE; + } + if (limit_job_load) + { + u_int jobs = 0, i; + + for (i = 0; i < JOB_PRIO_MAX; i++) + { + jobs += lib->processor->get_job_load(lib->processor, i); + } + if (jobs > limit_job_load) + { + DBG1(DBG_IKE, "abort IKE_SA initiation, job load of %d exceeds " + "limit of %d", jobs, limit_job_load); + charon->ike_sa_manager->checkin_and_destroy( + charon->ike_sa_manager, ike_sa); + listener->child_cfg->destroy(listener->child_cfg); + listener->status = INVALID_STATE; + listener_done(listener); + return JOB_REQUEUE_NONE; + } + } + } + if (ike_sa->initiate(ike_sa, listener->child_cfg, 0, NULL, NULL) == SUCCESS) { if (!listener->logger.callback) @@ -391,7 +438,7 @@ METHOD(job_t, initiate_execute, job_requeue_t, METHOD(controller_t, initiate, status_t, private_controller_t *this, peer_cfg_t *peer_cfg, child_cfg_t *child_cfg, - controller_cb_t callback, void *param, u_int timeout) + controller_cb_t callback, void *param, u_int timeout, bool limits) { interface_job_t *job; status_t status; @@ -414,6 +461,7 @@ METHOD(controller_t, initiate, status_t, .child_cfg = child_cfg, .peer_cfg = peer_cfg, .lock = spinlock_create(), + .limits = limits, }, .public = { .execute = _initiate_execute, diff --git a/src/libcharon/control/controller.h b/src/libcharon/control/controller.h index 02f4ebb2b..5ffeac522 100644 --- a/src/libcharon/control/controller.h +++ b/src/libcharon/control/controller.h @@ -82,15 +82,18 @@ struct controller_t { * @param cb logging callback * @param param parameter to include in each call of cb * @param timeout timeout in ms to wait for callbacks, 0 to disable + * @param limits whether to check limits regarding IKE_SA initiation * @return * - SUCCESS, if CHILD_SA established * - FAILED, if setup failed * - NEED_MORE, if callback returned FALSE * - OUT_OF_RES if timed out + * - INVALID_STATE if limits prevented initiation */ status_t (*initiate)(controller_t *this, peer_cfg_t *peer_cfg, child_cfg_t *child_cfg, - controller_cb_t callback, void *param, u_int timeout); + controller_cb_t callback, void *param, u_int timeout, + bool limits); /** * Terminate an IKE_SA and all of its CHILD_SAs. diff --git a/src/libcharon/plugins/load_tester/load_tester_control.c b/src/libcharon/plugins/load_tester/load_tester_control.c index 5f089f5db..24076d443 100644 --- a/src/libcharon/plugins/load_tester/load_tester_control.c +++ b/src/libcharon/plugins/load_tester/load_tester_control.c @@ -239,7 +239,7 @@ static bool on_accept(private_load_tester_control_t *this, stream_t *io) switch (charon->controller->initiate(charon->controller, peer_cfg, child_cfg->get_ref(child_cfg), - (void*)initiate_cb, listener, 0)) + (void*)initiate_cb, listener, 0, FALSE)) { case NEED_MORE: /* Callback returns FALSE once it got track of this IKE_SA. diff --git a/src/libcharon/plugins/load_tester/load_tester_plugin.c b/src/libcharon/plugins/load_tester/load_tester_plugin.c index e684f22ce..c7380b974 100644 --- a/src/libcharon/plugins/load_tester/load_tester_plugin.c +++ b/src/libcharon/plugins/load_tester/load_tester_plugin.c @@ -152,7 +152,7 @@ static job_requeue_t do_load_test(private_load_tester_plugin_t *this) charon->controller->initiate(charon->controller, peer_cfg, child_cfg->get_ref(child_cfg), - NULL, NULL, 0); + NULL, NULL, 0, FALSE); if (s) { sleep(s); diff --git a/src/libcharon/plugins/medcli/medcli_config.c b/src/libcharon/plugins/medcli/medcli_config.c index 1fb57b928..25b138387 100644 --- a/src/libcharon/plugins/medcli/medcli_config.c +++ b/src/libcharon/plugins/medcli/medcli_config.c @@ -314,7 +314,7 @@ static job_requeue_t initiate_config(peer_cfg_t *peer_cfg) peer_cfg->get_ref(peer_cfg); enumerator->destroy(enumerator); charon->controller->initiate(charon->controller, - peer_cfg, child_cfg, NULL, NULL, 0); + peer_cfg, child_cfg, NULL, NULL, 0, FALSE); } else { diff --git a/src/libcharon/plugins/smp/smp.c b/src/libcharon/plugins/smp/smp.c index 04bf382ed..2aa061fd2 100644 --- a/src/libcharon/plugins/smp/smp.c +++ b/src/libcharon/plugins/smp/smp.c @@ -488,7 +488,7 @@ static void request_control_initiate(xmlTextReaderPtr reader, { status = charon->controller->initiate(charon->controller, peer, child, (controller_cb_t)xml_callback, - writer, 0); + writer, 0, FALSE); } else { diff --git a/src/libcharon/plugins/stroke/stroke_control.c b/src/libcharon/plugins/stroke/stroke_control.c index 0084fbf93..0125d17c6 100644 --- a/src/libcharon/plugins/stroke/stroke_control.c +++ b/src/libcharon/plugins/stroke/stroke_control.c @@ -109,7 +109,7 @@ static void charon_initiate(private_stroke_control_t *this, peer_cfg_t *peer_cfg if (msg->output_verbosity < 0) { charon->controller->initiate(charon->controller, peer_cfg, child_cfg, - NULL, NULL, 0); + NULL, NULL, 0, FALSE); } else { @@ -118,7 +118,7 @@ static void charon_initiate(private_stroke_control_t *this, peer_cfg_t *peer_cfg status = charon->controller->initiate(charon->controller, peer_cfg, child_cfg, (controller_cb_t)stroke_log, - &info, this->timeout); + &info, this->timeout, FALSE); switch (status) { case SUCCESS: diff --git a/src/libcharon/plugins/uci/uci_control.c b/src/libcharon/plugins/uci/uci_control.c index cebc389e7..a7d26e67d 100644 --- a/src/libcharon/plugins/uci/uci_control.c +++ b/src/libcharon/plugins/uci/uci_control.c @@ -147,7 +147,7 @@ static void initiate(private_uci_control_t *this, char *name) if (enumerator->enumerate(enumerator, &child_cfg) && charon->controller->initiate(charon->controller, peer_cfg, child_cfg->get_ref(child_cfg), - controller_cb_empty, NULL, 0) == SUCCESS) + controller_cb_empty, NULL, 0, FALSE) == SUCCESS) { write_fifo(this, "connection '%s' established\n", name); } diff --git a/src/libcharon/plugins/vici/README.md b/src/libcharon/plugins/vici/README.md index 1273bb8fc..e20e8ab26 100644 --- a/src/libcharon/plugins/vici/README.md +++ b/src/libcharon/plugins/vici/README.md @@ -259,6 +259,7 @@ Initiates an SA while streaming _control-log_ events. { child = <CHILD_SA configuration name to initiate> timeout = <timeout in seconds before returning> + init-limits = <whether limits may prevent initiating the CHILD_SA> loglevel = <loglevel to issue "control-log" events for> } => { success = <yes or no> diff --git a/src/libcharon/plugins/vici/suites/test_message.c b/src/libcharon/plugins/vici/suites/test_message.c index e76d27332..045e34fff 100644 --- a/src/libcharon/plugins/vici/suites/test_message.c +++ b/src/libcharon/plugins/vici/suites/test_message.c @@ -1,4 +1,7 @@ /* + * Copyright (C) 2015 Tobias Brunner + * Hochschule fuer Technik Rapperswil + * * Copyright (C) 2014 Martin Willi * Copyright (C) 2014 revosec AG * @@ -355,6 +358,33 @@ START_TEST(test_get_int) } END_TEST +START_TEST(test_get_bool) +{ + vici_message_t *m; + + m = build_getter_msg(); + + ck_assert(m->get_bool(m, TRUE, "key1")); + ck_assert(m->get_bool(m, FALSE, "key1")); + + ck_assert(m->get_bool(m, TRUE, "section1.key2")); + ck_assert(m->get_bool(m, TRUE, "section1.section2.key3")); + ck_assert(m->get_bool(m, TRUE, "section1.key4")); + ck_assert(m->get_bool(m, TRUE, "key5")); + ck_assert(m->get_bool(m, TRUE, "nonexistent")); + ck_assert(m->get_bool(m, TRUE, "n.o.n.e.x.i.s.t.e.n.t")); + + ck_assert(!m->get_bool(m, FALSE, "section1.key2")); + ck_assert(!m->get_bool(m, FALSE, "section1.section2.key3")); + ck_assert(!m->get_bool(m, FALSE, "section1.key4")); + ck_assert(!m->get_bool(m, FALSE, "key5")); + ck_assert(!m->get_bool(m, FALSE, "nonexistent")); + ck_assert(!m->get_bool(m, FALSE, "n.o.n.e.x.i.s.t.e.n.t")); + + m->destroy(m); +} +END_TEST + START_TEST(test_get_value) { vici_message_t *m; @@ -400,6 +430,7 @@ Suite *message_suite_create() tc = tcase_create("convenience getters"); tcase_add_test(tc, test_get_str); tcase_add_test(tc, test_get_int); + tcase_add_test(tc, test_get_bool); tcase_add_test(tc, test_get_value); suite_add_tcase(s, tc); diff --git a/src/libcharon/plugins/vici/vici_config.c b/src/libcharon/plugins/vici/vici_config.c index d442bd69e..ea6d2958a 100644 --- a/src/libcharon/plugins/vici/vici_config.c +++ b/src/libcharon/plugins/vici/vici_config.c @@ -1589,7 +1589,7 @@ static void run_start_action(private_vici_config_t *this, peer_cfg_t *peer_cfg, DBG1(DBG_CFG, "initiating '%s'", child_cfg->get_name(child_cfg)); charon->controller->initiate(charon->controller, peer_cfg->get_ref(peer_cfg), child_cfg->get_ref(child_cfg), - NULL, NULL, 0); + NULL, NULL, 0, FALSE); break; case ACTION_ROUTE: DBG1(DBG_CFG, "installing '%s'", child_cfg->get_name(child_cfg)); diff --git a/src/libcharon/plugins/vici/vici_control.c b/src/libcharon/plugins/vici/vici_control.c index 408d29985..752007c24 100644 --- a/src/libcharon/plugins/vici/vici_control.c +++ b/src/libcharon/plugins/vici/vici_control.c @@ -163,6 +163,7 @@ CALLBACK(initiate, vici_message_t*, peer_cfg_t *peer_cfg; char *child; u_int timeout; + bool limits; log_info_t log = { .dispatcher = this->dispatcher, .id = id, @@ -170,6 +171,7 @@ CALLBACK(initiate, vici_message_t*, child = request->get_str(request, NULL, "child"); timeout = request->get_int(request, 0, "timeout"); + limits = request->get_bool(request, FALSE, "init-limits"); log.level = request->get_int(request, 1, "loglevel"); if (!child) @@ -184,14 +186,17 @@ 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)) + switch (charon->controller->initiate(charon->controller, peer_cfg, + child_cfg, (controller_cb_t)log_vici, &log, timeout, limits)) { case SUCCESS: return send_reply(this, NULL); case OUT_OF_RES: return send_reply(this, "CHILD_SA '%s' not established after %dms", child, timeout); + case INVALID_STATE: + return send_reply(this, "establishing CHILD_SA '%s' not possible " + "at the moment due to limits", child); case FAILED: default: return send_reply(this, "establishing CHILD_SA '%s' failed", child); diff --git a/src/libcharon/plugins/vici/vici_message.c b/src/libcharon/plugins/vici/vici_message.c index e79fbc8d3..fb6e8a1ab 100644 --- a/src/libcharon/plugins/vici/vici_message.c +++ b/src/libcharon/plugins/vici/vici_message.c @@ -1,4 +1,7 @@ /* + * Copyright (C) 2015 Tobias Brunner + * Hochschule fuer Technik Rapperswil + * * Copyright (C) 2014 Martin Willi * Copyright (C) 2014 revosec AG * @@ -385,6 +388,41 @@ METHOD(vici_message_t, get_int, int, return val; } +METHOD(vici_message_t, vget_bool, bool, + private_vici_message_t *this, bool def, char *fmt, va_list args) +{ + chunk_t value; + bool found; + char buf[16]; + + found = find_value(this, &value, fmt, args); + if (found) + { + if (value.len == 0) + { + return def; + } + if (chunk_printable(value, NULL, 0)) + { + snprintf(buf, sizeof(buf), "%.*s", (int)value.len, value.ptr); + return settings_value_as_bool(buf, def); + } + } + return def; +} + +METHOD(vici_message_t, get_bool, bool, + private_vici_message_t *this, bool def, char *fmt, ...) +{ + va_list args; + bool val; + + va_start(args, fmt); + val = vget_bool(this, def, fmt, args); + va_end(args); + return val; +} + METHOD(vici_message_t, vget_value, chunk_t, private_vici_message_t *this, chunk_t def, char *fmt, va_list args) { @@ -633,6 +671,8 @@ vici_message_t *vici_message_create_from_data(chunk_t data, bool cleanup) .vget_str = _vget_str, .get_int = _get_int, .vget_int = _vget_int, + .get_bool = _get_bool, + .vget_bool = _vget_bool, .get_value = _get_value, .vget_value = _vget_value, .get_encoding = _get_encoding, diff --git a/src/libcharon/plugins/vici/vici_message.h b/src/libcharon/plugins/vici/vici_message.h index 1a89cf829..7f357b8ec 100644 --- a/src/libcharon/plugins/vici/vici_message.h +++ b/src/libcharon/plugins/vici/vici_message.h @@ -1,4 +1,7 @@ /* + * Copyright (C) 2015 Tobias Brunner + * Hochschule fuer Technik Rapperswil + * * Copyright (C) 2014 Martin Willi * Copyright (C) 2014 revosec AG * @@ -138,6 +141,26 @@ struct vici_message_t { int (*vget_int)(vici_message_t *this, int def, char *fmt, va_list args); /** + * Get the value of a key/value pair as boolean. + * + * @param def default value if not found + * @param fmt printf style format string for key, with sections + * @param ... arguments to fmt string + * @return value + */ + bool (*get_bool)(vici_message_t *this, bool def, char *fmt, ...); + + /** + * Get the value of a key/value pair as boolean, va_list variant + * + * @param def default value if not found + * @param fmt printf style format string for key, with sections + * @param args arguments to fmt string + * @return value + */ + bool (*vget_bool)(vici_message_t *this, bool def, char *fmt, va_list args); + + /** * Get the raw value of a key/value pair. * * @param def default value if not found diff --git a/src/libcharon/processing/jobs/initiate_mediation_job.c b/src/libcharon/processing/jobs/initiate_mediation_job.c index 17ab83053..5b5fb9d98 100644 --- a/src/libcharon/processing/jobs/initiate_mediation_job.c +++ b/src/libcharon/processing/jobs/initiate_mediation_job.c @@ -119,8 +119,8 @@ METHOD(job_t, initiate, job_requeue_t, /* we need an additional reference because initiate consumes one */ mediation_cfg->get_ref(mediation_cfg); - if (charon->controller->initiate(charon->controller, mediation_cfg, - NULL, (controller_cb_t)initiate_callback, this, 0) != SUCCESS) + if (charon->controller->initiate(charon->controller, mediation_cfg, NULL, + (controller_cb_t)initiate_callback, this, 0, FALSE) != SUCCESS) { mediation_cfg->destroy(mediation_cfg); mediated_cfg->destroy(mediated_cfg); diff --git a/src/libcharon/processing/jobs/start_action_job.c b/src/libcharon/processing/jobs/start_action_job.c index 981473b5c..5e88ac230 100644 --- a/src/libcharon/processing/jobs/start_action_job.c +++ b/src/libcharon/processing/jobs/start_action_job.c @@ -61,7 +61,7 @@ METHOD(job_t, execute, job_requeue_t, charon->controller->initiate(charon->controller, peer_cfg->get_ref(peer_cfg), child_cfg->get_ref(child_cfg), - NULL, NULL, 0); + NULL, NULL, 0, FALSE); break; case ACTION_ROUTE: DBG1(DBG_JOB, "start action: route '%s'", name); diff --git a/src/libcharon/sa/ike_sa_manager.c b/src/libcharon/sa/ike_sa_manager.c index 3e6496da5..137920a96 100644 --- a/src/libcharon/sa/ike_sa_manager.c +++ b/src/libcharon/sa/ike_sa_manager.c @@ -1572,7 +1572,6 @@ METHOD(ike_sa_manager_t, checkin, void, put_half_open(this, entry); } else if (!entry->half_open && - !entry->ike_sa_id->is_initiator(entry->ike_sa_id) && ike_sa->get_state(ike_sa) == IKE_CONNECTING) { /* this is a new half-open SA */ |