From: Tobias Brunner Date: Tue, 3 Sep 2024 14:15:02 +0000 (+0200) Subject: vici-config: Consider queued tasks when terminating IKE/CHILD_SAs X-Git-Tag: 6.0.0rc1~47^2 X-Git-Url: http://git.ipfire.org/cgi-bin/gitweb.cgi?a=commitdiff_plain;h=a4a3dcf6c2e97067248a34946bedd3e958a0c3b3;p=thirdparty%2Fstrongswan.git vici-config: Consider queued tasks when terminating IKE/CHILD_SAs This is particularly important for IKE_SAs that are not yet established, which would get terminated as they have no established CHILD_SAs yet. Fixes: 72f9a21b22e9 ("Merge branch 'vici-reload-actions'") --- diff --git a/src/libcharon/plugins/vici/vici_config.c b/src/libcharon/plugins/vici/vici_config.c index 2d548ab3a6..1bb925417f 100644 --- a/src/libcharon/plugins/vici/vici_config.c +++ b/src/libcharon/plugins/vici/vici_config.c @@ -49,6 +49,8 @@ #include #include #include +#include +#include #include @@ -2294,6 +2296,102 @@ typedef struct { char *name; } child_name_id_t; +/** + * Get the child config of the given task depending on its type. + */ +static child_cfg_t *get_task_config(task_t *task, task_type_t type) +{ + child_create_t *child_create = (child_create_t*)task; + + if (type == TASK_QUICK_MODE) + { + quick_mode_t *quick_mode = (quick_mode_t*)task; + return quick_mode->get_config(quick_mode); + } + return child_create->get_config(child_create); +} + +/** + * Abort the given child-creating task depending on its type. + */ +static void abort_child_task(task_t *task, task_type_t type) +{ + child_create_t *child_create = (child_create_t*)task; + + if (type == TASK_QUICK_MODE) + { + quick_mode_t *quick_mode = (quick_mode_t*)task; + return quick_mode->abort(quick_mode); + } + return child_create->abort(child_create); +} + +/** + * Check if there are child-creating tasks queued that should be aborted, as + * well as if there are any others that should prevent the deletion of the + * IKE_SA. + */ +static void check_queued_tasks(ike_sa_t *ike_sa, hashtable_t *to_terminate, + bool *others) +{ + enumerator_t *enumerator; + child_cfg_t *cfg; + task_t *task; + task_type_t type = TASK_CHILD_CREATE; + + if (ike_sa->get_version(ike_sa) == IKEV1) + { + type = TASK_QUICK_MODE; + } + + /* if we find an active task, we can't remove it as there is no way to + * abort an exchange (i.e. the peer will have created the SA even if we + * don't process the response). so we instruct the task to immediately + * delete the CHILD_SA once it's created */ + enumerator = ike_sa->create_task_enumerator(ike_sa, TASK_QUEUE_ACTIVE); + while (enumerator->enumerate(enumerator, &task)) + { + if (task->get_type(task) == type) + { + cfg = get_task_config(task, type); + if (to_terminate->get(to_terminate, cfg->get_name(cfg))) + { + DBG1(DBG_CFG, "vici aborting %N task for CHILD_SA '%s'", + task_type_names, type, cfg->get_name(cfg)); + abort_child_task(task, type); + } + else + { + *others = TRUE; + } + } + } + enumerator->destroy(enumerator); + + /* for the queued tasks, we just remove any that use a config that is to + * be terminated, but also note if there are others */ + enumerator = ike_sa->create_task_enumerator(ike_sa, TASK_QUEUE_QUEUED); + while (enumerator->enumerate(enumerator, &task)) + { + if (task->get_type(task) == type) + { + cfg = get_task_config(task, type); + if (to_terminate->get(to_terminate, cfg->get_name(cfg))) + { + DBG1(DBG_CFG, "vici removing %N task for CHILD_SA '%s'", + task_type_names, type, cfg->get_name(cfg)); + ike_sa->remove_task(ike_sa, enumerator); + task->destroy(task); + } + else + { + *others = TRUE; + } + } + } + enumerator->destroy(enumerator); +} + /** * Terminate given CHILD_SAs and optionally terminate any IKE_SA without other * children. @@ -2332,9 +2430,11 @@ static void terminate_for_action(private_vici_config_t *this, char *peer_name, } children->destroy(children); - if (delete_ike && (!others || !ike_sa->get_child_count(ike_sa))) + check_queued_tasks(ike_sa, to_terminate, &others); + + if (delete_ike && !others) { - /* found no children or only matching, delete IKE_SA */ + /* found no children/tasks or only matching, delete IKE_SA */ id = ike_sa->get_unique_id(ike_sa); array_insert_create_value(&ikeids, sizeof(id), ARRAY_TAIL, &id);