From c126ddd048ab41d8d71f9284c4ac5c75c53f9779 Mon Sep 17 00:00:00 2001 From: Tobias Brunner Date: Thu, 23 Apr 2015 11:50:31 +0200 Subject: [PATCH] ikev2: Handle REDIRECT notifies during IKE_SA_INIT --- src/libcharon/sa/ike_sa.c | 32 ++++++++++++++++++++++++++++++++ src/libcharon/sa/ike_sa.h | 10 ++++++++++ src/libcharon/sa/ikev2/tasks/ike_init.c | 22 ++++++++++++++++++++++ 3 files changed, 64 insertions(+) diff --git a/src/libcharon/sa/ike_sa.c b/src/libcharon/sa/ike_sa.c index 48a4b27..864e8c0 100644 --- a/src/libcharon/sa/ike_sa.c +++ b/src/libcharon/sa/ike_sa.c @@ -1951,6 +1951,37 @@ METHOD(ike_sa_t, reestablish, status_t, return status; } +METHOD(ike_sa_t, handle_redirect, bool, + private_ike_sa_t *this, identification_t *gateway) +{ + char gw[BUF_LEN]; + host_t *other; + + DBG1(DBG_IKE, "redirected to %Y", gateway); + + snprintf(gw, sizeof(gw), "%Y", gateway); + gw[sizeof(gw)-1] = '\0'; + other = host_create_from_dns(gw, AF_UNSPEC, IKEV2_UDP_PORT); + if (!other) + { + DBG1(DBG_IKE, "unable to resolve gateway ID '%Y', redirect failed", + gateway); + return FALSE; + } + switch (this->state) + { + case IKE_CONNECTING: + reset(this); + set_other_host(this, other); + return TRUE; + default: + DBG1(DBG_IKE, "unable to handle redirect for IKE_SA in state %N", + ike_sa_state_names, this->state); + other->destroy(other); + return FALSE; + } +} + METHOD(ike_sa_t, retransmit, status_t, private_ike_sa_t *this, u_int32_t message_id) { @@ -2543,6 +2574,7 @@ ike_sa_t * ike_sa_create(ike_sa_id_t *ike_sa_id, bool initiator, .destroy = _destroy, .send_dpd = _send_dpd, .send_keepalive = _send_keepalive, + .handle_redirect = _handle_redirect, .get_keymat = _get_keymat, .add_child_sa = _add_child_sa, .get_child_sa = _get_child_sa, diff --git a/src/libcharon/sa/ike_sa.h b/src/libcharon/sa/ike_sa.h index 3cefb4d..384912d 100644 --- a/src/libcharon/sa/ike_sa.h +++ b/src/libcharon/sa/ike_sa.h @@ -848,6 +848,16 @@ struct ike_sa_t { void (*send_keepalive) (ike_sa_t *this, bool scheduled); /** + * Handle a redirect request. + * + * The behavior is different depending on the state of the IKE_SA. + * + * @param gateway gateway ID (IP or FQDN) of the target + * @return FALSE if redirect not possible, TRUE otherwise + */ + bool (*handle_redirect)(ike_sa_t *this, identification_t *gateway); + + /** * Get the keying material of this IKE_SA. * * @return per IKE_SA keymat instance diff --git a/src/libcharon/sa/ikev2/tasks/ike_init.c b/src/libcharon/sa/ikev2/tasks/ike_init.c index 87761ad..71bd82c 100644 --- a/src/libcharon/sa/ikev2/tasks/ike_init.c +++ b/src/libcharon/sa/ikev2/tasks/ike_init.c @@ -704,6 +704,28 @@ METHOD(task_t, process_i, status_t, this->retry++; return NEED_MORE; } + case REDIRECT: + { + identification_t *gateway; + chunk_t data, nonce = chunk_empty; + status_t status = FAILED; + + data = notify->get_notification_data(notify); + gateway = redirect_data_parse(data, &nonce); + enumerator->destroy(enumerator); + if (!gateway || !chunk_equals(nonce, this->my_nonce)) + { + DBG1(DBG_IKE, "received invalid REDIRECT notify"); + } + else if (this->ike_sa->handle_redirect(this->ike_sa, + gateway)) + { + status = NEED_MORE; + } + DESTROY_IF(gateway); + chunk_free(&nonce); + return status; + } default: { if (type <= 16383) -- 2.7.4