ikev2: Handle REDIRECT notifies during IKE_SA_INIT
authorTobias Brunner <tobias@strongswan.org>
Thu, 23 Apr 2015 09:50:31 +0000 (11:50 +0200)
committerTobias Brunner <tobias@strongswan.org>
Fri, 4 Mar 2016 15:02:58 +0000 (16:02 +0100)
src/libcharon/sa/ike_sa.c
src/libcharon/sa/ike_sa.h
src/libcharon/sa/ikev2/tasks/ike_init.c

index 48a4b27..864e8c0 100644 (file)
@@ -1951,6 +1951,37 @@ METHOD(ike_sa_t, reestablish, status_t,
        return status;
 }
 
        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)
 {
 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,
                        .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,
                        .get_keymat = _get_keymat,
                        .add_child_sa = _add_child_sa,
                        .get_child_sa = _get_child_sa,
index 3cefb4d..384912d 100644 (file)
@@ -848,6 +848,16 @@ struct ike_sa_t {
        void (*send_keepalive) (ike_sa_t *this, bool scheduled);
 
        /**
        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
         * Get the keying material of this IKE_SA.
         *
         * @return                              per IKE_SA keymat instance
index 87761ad..71bd82c 100644 (file)
@@ -704,6 +704,28 @@ METHOD(task_t, process_i, status_t,
                                        this->retry++;
                                        return NEED_MORE;
                                }
                                        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)
                                default:
                                {
                                        if (type <= 16383)