summaryrefslogtreecommitdiff
path: root/src/libcharon/sa/ikev2/task_manager_v2.c
diff options
context:
space:
mode:
Diffstat (limited to 'src/libcharon/sa/ikev2/task_manager_v2.c')
-rw-r--r--src/libcharon/sa/ikev2/task_manager_v2.c113
1 files changed, 98 insertions, 15 deletions
diff --git a/src/libcharon/sa/ikev2/task_manager_v2.c b/src/libcharon/sa/ikev2/task_manager_v2.c
index eb7df3516..298167703 100644
--- a/src/libcharon/sa/ikev2/task_manager_v2.c
+++ b/src/libcharon/sa/ikev2/task_manager_v2.c
@@ -29,6 +29,7 @@
#include <sa/ikev2/tasks/ike_cert_post.h>
#include <sa/ikev2/tasks/ike_rekey.h>
#include <sa/ikev2/tasks/ike_reauth.h>
+#include <sa/ikev2/tasks/ike_reauth_complete.h>
#include <sa/ikev2/tasks/ike_delete.h>
#include <sa/ikev2/tasks/ike_config.h>
#include <sa/ikev2/tasks/ike_dpd.h>
@@ -171,6 +172,11 @@ struct private_task_manager_t {
* Base to calculate retransmission timeout
*/
double retransmit_base;
+
+ /**
+ * Use make-before-break instead of break-before-make reauth?
+ */
+ bool make_before_break;
};
/**
@@ -510,6 +516,11 @@ METHOD(task_manager_t, initiate, status_t,
break;
}
#endif /* ME */
+ if (activate_task(this, TASK_IKE_REAUTH_COMPLETE))
+ {
+ exchange = INFORMATIONAL;
+ break;
+ }
case IKE_REKEYING:
if (activate_task(this, TASK_IKE_DELETE))
{
@@ -604,6 +615,11 @@ METHOD(task_manager_t, initiate, status_t,
/* update exchange type if a task changed it */
this->initiating.type = message->get_exchange_type(message);
+ if (this->initiating.type == EXCHANGE_TYPE_UNDEFINED)
+ {
+ message->destroy(message);
+ return SUCCESS;
+ }
if (!generate_message(this, message, &this->initiating.packets))
{
@@ -1170,7 +1186,7 @@ static status_t parse_message(private_task_manager_t *this, message_t *msg)
{
unknown = (unknown_payload_t*)payload;
type = payload->get_type(payload);
- if (!payload_is_known(type) &&
+ if (!payload_is_known(type, msg->get_major_version(msg)) &&
unknown->is_critical(unknown))
{
DBG1(DBG_ENC, "payload type %N is not supported, "
@@ -1288,17 +1304,16 @@ METHOD(task_manager_t, process_message, status_t,
{
if (mid == this->responding.mid)
{
- /* reject initial messages once established */
- if (msg->get_exchange_type(msg) == IKE_SA_INIT ||
- msg->get_exchange_type(msg) == IKE_AUTH)
+ /* reject initial messages if not received in specific states */
+ if ((msg->get_exchange_type(msg) == IKE_SA_INIT &&
+ this->ike_sa->get_state(this->ike_sa) != IKE_CREATED) ||
+ (msg->get_exchange_type(msg) == IKE_AUTH &&
+ this->ike_sa->get_state(this->ike_sa) != IKE_CONNECTING))
{
- if (this->ike_sa->get_state(this->ike_sa) != IKE_CREATED &&
- this->ike_sa->get_state(this->ike_sa) != IKE_CONNECTING)
- {
- DBG1(DBG_IKE, "ignoring %N in established IKE_SA state",
- exchange_type_names, msg->get_exchange_type(msg));
- return FAILED;
- }
+ DBG1(DBG_IKE, "ignoring %N in IKE_SA state %N",
+ exchange_type_names, msg->get_exchange_type(msg),
+ ike_sa_state_names, this->ike_sa->get_state(this->ike_sa));
+ return FAILED;
}
if (!this->ike_sa->supports_extension(this->ike_sa, EXT_MOBIKE))
{ /* with MOBIKE, we do no implicit updates */
@@ -1339,10 +1354,6 @@ METHOD(task_manager_t, process_message, status_t,
{
DBG1(DBG_IKE, "received message ID %d, expected %d. Ignored",
mid, this->responding.mid);
- if (msg->get_exchange_type(msg) == IKE_SA_INIT)
- { /* clean up IKE_SA state if IKE_SA_INIT has invalid msg ID */
- return DESTROY_ME;
- }
}
}
else
@@ -1505,9 +1516,79 @@ METHOD(task_manager_t, queue_ike_rekey, void,
queue_task(this, (task_t*)ike_rekey_create(this->ike_sa, TRUE));
}
+/**
+ * Start reauthentication using make-before-break
+ */
+static void trigger_mbb_reauth(private_task_manager_t *this)
+{
+ enumerator_t *enumerator;
+ child_sa_t *child_sa;
+ child_cfg_t *cfg;
+ ike_sa_t *new;
+ host_t *host;
+ task_t *task;
+
+ new = charon->ike_sa_manager->checkout_new(charon->ike_sa_manager,
+ this->ike_sa->get_version(this->ike_sa), TRUE);
+ if (!new)
+ { /* shouldn't happen */
+ return;
+ }
+
+ new->set_peer_cfg(new, this->ike_sa->get_peer_cfg(this->ike_sa));
+ host = this->ike_sa->get_other_host(this->ike_sa);
+ new->set_other_host(new, host->clone(host));
+ host = this->ike_sa->get_my_host(this->ike_sa);
+ new->set_my_host(new, host->clone(host));
+ enumerator = this->ike_sa->create_virtual_ip_enumerator(this->ike_sa, TRUE);
+ while (enumerator->enumerate(enumerator, &host))
+ {
+ new->add_virtual_ip(new, TRUE, host);
+ }
+ enumerator->destroy(enumerator);
+
+ enumerator = this->ike_sa->create_child_sa_enumerator(this->ike_sa);
+ while (enumerator->enumerate(enumerator, &child_sa))
+ {
+ cfg = child_sa->get_config(child_sa);
+ new->queue_task(new, &child_create_create(new, cfg->get_ref(cfg),
+ FALSE, NULL, NULL)->task);
+ }
+ enumerator->destroy(enumerator);
+
+ enumerator = array_create_enumerator(this->queued_tasks);
+ while (enumerator->enumerate(enumerator, &task))
+ {
+ if (task->get_type(task) == TASK_CHILD_CREATE)
+ {
+ task->migrate(task, new);
+ new->queue_task(new, task);
+ array_remove_at(this->queued_tasks, enumerator);
+ }
+ }
+ enumerator->destroy(enumerator);
+
+ if (new->initiate(new, NULL, 0, NULL, NULL) != DESTROY_ME)
+ {
+ new->queue_task(new, (task_t*)ike_reauth_complete_create(new,
+ this->ike_sa->get_id(this->ike_sa)));
+ charon->ike_sa_manager->checkin(charon->ike_sa_manager, new);
+ }
+ else
+ {
+ charon->ike_sa_manager->checkin_and_destroy(charon->ike_sa_manager, new);
+ DBG1(DBG_IKE, "reauthenticating IKE_SA failed");
+ }
+ charon->bus->set_sa(charon->bus, this->ike_sa);
+}
+
METHOD(task_manager_t, queue_ike_reauth, void,
private_task_manager_t *this)
{
+ if (this->make_before_break)
+ {
+ return trigger_mbb_reauth(this);
+ }
queue_task(this, (task_t*)ike_reauth_create(this->ike_sa));
}
@@ -1773,6 +1854,8 @@ task_manager_v2_t *task_manager_v2_create(ike_sa_t *ike_sa)
"%s.retransmit_timeout", RETRANSMIT_TIMEOUT, lib->ns),
.retransmit_base = lib->settings->get_double(lib->settings,
"%s.retransmit_base", RETRANSMIT_BASE, lib->ns),
+ .make_before_break = lib->settings->get_bool(lib->settings,
+ "%s.make_before_break", FALSE, lib->ns),
);
return &this->public;