From: Tobias Brunner Date: Thu, 23 Apr 2015 09:50:31 +0000 (+0200) Subject: ikev2: Handle REDIRECT notifies during IKE_SA_INIT X-Git-Tag: 5.4.0dr8~12^2~26 X-Git-Url: http://git.ipfire.org/cgi-bin/gitweb.cgi?a=commitdiff_plain;h=c126ddd048ab41d8d71f9284c4ac5c75c53f9779;p=thirdparty%2Fstrongswan.git ikev2: Handle REDIRECT notifies during IKE_SA_INIT --- diff --git a/src/libcharon/sa/ike_sa.c b/src/libcharon/sa/ike_sa.c index 48a4b274a1..864e8c0557 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 3cefb4d998..384912d00c 100644 --- a/src/libcharon/sa/ike_sa.h +++ b/src/libcharon/sa/ike_sa.h @@ -847,6 +847,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. * diff --git a/src/libcharon/sa/ikev2/tasks/ike_init.c b/src/libcharon/sa/ikev2/tasks/ike_init.c index 87761ad59a..71bd82cf1d 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)