From 7b7290977411661cd0fe591d933f610aca6d36f9 Mon Sep 17 00:00:00 2001 From: Tobias Brunner Date: Fri, 27 Apr 2018 18:01:54 +0200 Subject: [PATCH] controller: Add option to force destruction of an IKE_SA It's optionally possible to wait for a timeout to destroy the SA. --- src/charon-nm/nm/nm_service.c | 2 +- src/conftest/actions.c | 3 +- .../backend/android_service.c | 2 +- src/frontends/osx/charon-xpc/xpc_channels.c | 2 +- src/libcharon/control/controller.c | 36 ++++++++++++++----- src/libcharon/control/controller.h | 7 +++- src/libcharon/plugins/smp/smp.c | 2 +- src/libcharon/plugins/stroke/stroke_control.c | 5 +-- src/libcharon/plugins/uci/uci_control.c | 2 +- src/libcharon/plugins/vici/vici_config.c | 2 +- src/libcharon/plugins/vici/vici_control.c | 2 +- 11 files changed, 45 insertions(+), 20 deletions(-) diff --git a/src/charon-nm/nm/nm_service.c b/src/charon-nm/nm/nm_service.c index 82e126ace9..0e7035ae9e 100644 --- a/src/charon-nm/nm/nm_service.c +++ b/src/charon-nm/nm/nm_service.c @@ -741,7 +741,7 @@ static gboolean do_disconnect(gpointer plugin) { id = ike_sa->get_unique_id(ike_sa); enumerator->destroy(enumerator); - charon->controller->terminate_ike(charon->controller, id, + charon->controller->terminate_ike(charon->controller, id, FALSE, controller_cb_empty, NULL, 0); return FALSE; } diff --git a/src/conftest/actions.c b/src/conftest/actions.c index 36c3c8e74b..66e41f7433 100644 --- a/src/conftest/actions.c +++ b/src/conftest/actions.c @@ -209,7 +209,8 @@ static job_requeue_t close_ike(char *config) if (id) { DBG1(DBG_CFG, "closing IKE_SA '%s'", config); - charon->controller->terminate_ike(charon->controller, id, NULL, NULL, 0); + charon->controller->terminate_ike(charon->controller, id, FALSE, NULL, + NULL, 0); } else { diff --git a/src/frontends/android/app/src/main/jni/libandroidbridge/backend/android_service.c b/src/frontends/android/app/src/main/jni/libandroidbridge/backend/android_service.c index 806375c2f7..b1a095bcdf 100644 --- a/src/frontends/android/app/src/main/jni/libandroidbridge/backend/android_service.c +++ b/src/frontends/android/app/src/main/jni/libandroidbridge/backend/android_service.c @@ -401,7 +401,7 @@ static void close_tun_device(private_android_service_t *this) CALLBACK(terminate, job_requeue_t, uint32_t *id) { - charon->controller->terminate_ike(charon->controller, *id, + charon->controller->terminate_ike(charon->controller, *id, FALSE, controller_cb_empty, NULL, 0); return JOB_REQUEUE_NONE; } diff --git a/src/frontends/osx/charon-xpc/xpc_channels.c b/src/frontends/osx/charon-xpc/xpc_channels.c index 6724841d95..d013e752b6 100644 --- a/src/frontends/osx/charon-xpc/xpc_channels.c +++ b/src/frontends/osx/charon-xpc/xpc_channels.c @@ -131,7 +131,7 @@ static void stop_connection(private_xpc_channels_t *this, uint32_t ike_sa, { status_t status; - status = charon->controller->terminate_ike(charon->controller, ike_sa, + status = charon->controller->terminate_ike(charon->controller, ike_sa, FALSE, NULL, NULL, 0); xpc_dictionary_set_bool(reply, "success", status != NOT_FOUND); } diff --git a/src/libcharon/control/controller.c b/src/libcharon/control/controller.c index 6a37fff455..3ff1c4b800 100644 --- a/src/libcharon/control/controller.c +++ b/src/libcharon/control/controller.c @@ -117,10 +117,17 @@ struct interface_listener_t { */ spinlock_t *lock; - /** - * whether to check limits - */ - bool limits; + union { + /** + * whether to check limits during initiation + */ + bool limits; + + /** + * whether to force termination + */ + bool force; + } options; }; @@ -423,7 +430,7 @@ METHOD(job_t, initiate_execute, job_requeue_t, } peer_cfg->destroy(peer_cfg); - if (listener->limits && ike_sa->get_state(ike_sa) == IKE_CREATED) + if (listener->options.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; @@ -508,7 +515,7 @@ METHOD(controller_t, initiate, status_t, .child_cfg = child_cfg, .peer_cfg = peer_cfg, .lock = spinlock_create(), - .limits = limits, + .options.limits = limits, }, .public = { .execute = _initiate_execute, @@ -557,8 +564,8 @@ METHOD(job_t, terminate_ike_execute, job_requeue_t, listener->ike_sa = ike_sa; listener->lock->unlock(listener->lock); - if (ike_sa->delete(ike_sa, FALSE) != DESTROY_ME) - { /* delete failed */ + if (ike_sa->delete(ike_sa, listener->options.force) != DESTROY_ME) + { /* delete queued */ listener->status = FAILED; charon->ike_sa_manager->checkin(charon->ike_sa_manager, ike_sa); } @@ -575,7 +582,7 @@ METHOD(job_t, terminate_ike_execute, job_requeue_t, } METHOD(controller_t, terminate_ike, status_t, - controller_t *this, uint32_t unique_id, + controller_t *this, uint32_t unique_id, bool force, controller_cb_t callback, void *param, u_int timeout) { interface_job_t *job; @@ -610,13 +617,24 @@ METHOD(controller_t, terminate_ike, status_t, if (callback == NULL) { + job->listener.options.force = force; terminate_ike_execute(job); } else { + if (!timeout) + { + job->listener.options.force = force; + } if (wait_for_listener(job, timeout)) { job->listener.status = OUT_OF_RES; + + if (force) + { /* force termination once timeout is reached */ + job->listener.options.force = TRUE; + terminate_ike_execute(job); + } } } status = job->listener.status; diff --git a/src/libcharon/control/controller.h b/src/libcharon/control/controller.h index 9524f53b97..7ba7218602 100644 --- a/src/libcharon/control/controller.h +++ b/src/libcharon/control/controller.h @@ -102,6 +102,11 @@ struct controller_t { * until the IKE_SA is properly deleted, or the call timed out. * * @param unique_id unique id of the IKE_SA to terminate. + * @param force whether to immediately destroy the IKE_SA without + * waiting for a response or retransmitting the delete, + * if a callback is provided and timeout is > 0 the + * IKE_SA is destroyed once the timeout is reached but + * retransmits are sent until then * @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 @@ -112,7 +117,7 @@ struct controller_t { * - OUT_OF_RES if timed out */ status_t (*terminate_ike)(controller_t *this, uint32_t unique_id, - controller_cb_t callback, void *param, + bool force, controller_cb_t callback, void *param, u_int timeout); /** diff --git a/src/libcharon/plugins/smp/smp.c b/src/libcharon/plugins/smp/smp.c index 56891b2636..d4b01f42cc 100644 --- a/src/libcharon/plugins/smp/smp.c +++ b/src/libcharon/plugins/smp/smp.c @@ -415,7 +415,7 @@ static void request_control_terminate(xmlTextReaderPtr reader, if (ike) { status = charon->controller->terminate_ike( - charon->controller, id, + charon->controller, id, FALSE, (controller_cb_t)xml_callback, writer, 0); } else diff --git a/src/libcharon/plugins/stroke/stroke_control.c b/src/libcharon/plugins/stroke/stroke_control.c index d3c279131f..016f0e71bb 100644 --- a/src/libcharon/plugins/stroke/stroke_control.c +++ b/src/libcharon/plugins/stroke/stroke_control.c @@ -316,7 +316,8 @@ static void charon_terminate(private_stroke_control_t *this, uint32_t id, else { status = charon->controller->terminate_ike(charon->controller, id, - (controller_cb_t)stroke_log, &info, this->timeout); + FALSE, (controller_cb_t)stroke_log, &info, + this->timeout); } report_terminate_status(this, status, out, id, child); } @@ -327,7 +328,7 @@ static void charon_terminate(private_stroke_control_t *this, uint32_t id, } else { - charon->controller->terminate_ike(charon->controller, id, + charon->controller->terminate_ike(charon->controller, id, FALSE, NULL, NULL, 0); } } diff --git a/src/libcharon/plugins/uci/uci_control.c b/src/libcharon/plugins/uci/uci_control.c index a7d26e67d8..22fd3c27da 100644 --- a/src/libcharon/plugins/uci/uci_control.c +++ b/src/libcharon/plugins/uci/uci_control.c @@ -180,7 +180,7 @@ static void terminate(private_uci_control_t *this, char *name) { id = ike_sa->get_unique_id(ike_sa); enumerator->destroy(enumerator); - charon->controller->terminate_ike(charon->controller, id, + charon->controller->terminate_ike(charon->controller, id, FALSE, controller_cb_empty, NULL, 0); write_fifo(this, "connection '%s' terminated\n", name); return; diff --git a/src/libcharon/plugins/vici/vici_config.c b/src/libcharon/plugins/vici/vici_config.c index 2faa66e91f..c851615506 100644 --- a/src/libcharon/plugins/vici/vici_config.c +++ b/src/libcharon/plugins/vici/vici_config.c @@ -2083,7 +2083,7 @@ static void clear_start_action(private_vici_config_t *this, char *peer_name, while (array_remove(ikeids, ARRAY_HEAD, &id)) { DBG1(DBG_CFG, "closing IKE_SA #%u", id); - charon->controller->terminate_ike(charon->controller, + charon->controller->terminate_ike(charon->controller, FALSE, id, NULL, NULL, 0); } array_destroy(ikeids); diff --git a/src/libcharon/plugins/vici/vici_control.c b/src/libcharon/plugins/vici/vici_control.c index f9c7d8f19a..6824079213 100644 --- a/src/libcharon/plugins/vici/vici_control.c +++ b/src/libcharon/plugins/vici/vici_control.c @@ -326,7 +326,7 @@ CALLBACK(terminate, vici_message_t*, } else { - if (charon->controller->terminate_ike(charon->controller, *del, + if (charon->controller->terminate_ike(charon->controller, *del, FALSE, log_cb, &log, timeout) == SUCCESS) { done++; -- 2.47.3