ike: Move fragmentation to ike_sa_t
authorTobias Brunner <tobias@strongswan.org>
Thu, 12 Jun 2014 14:28:27 +0000 (16:28 +0200)
committerTobias Brunner <tobias@strongswan.org>
Fri, 10 Oct 2014 07:30:26 +0000 (09:30 +0200)
The message() hook on bus_t is now called exactly once before (plain) and
once after fragmenting (!plain), not twice for the complete message and again
for each individual fragment, as was the case in earlier iterations.

For inbound messages the hook is called once for each fragment (!plain)
and twice for the reassembled message.

src/libcharon/sa/ike_sa.c
src/libcharon/sa/ike_sa.h
src/libcharon/sa/ikev1/task_manager_v1.c

index 516b243..6f4ffb8 100644 (file)
@@ -1,5 +1,5 @@
 /*
- * Copyright (C) 2006-2013 Tobias Brunner
+ * Copyright (C) 2006-2014 Tobias Brunner
  * Copyright (C) 2006 Daniel Roethlisberger
  * Copyright (C) 2005-2009 Martin Willi
  * Copyright (C) 2005 Jan Hutter
@@ -251,6 +251,11 @@ struct private_ike_sa_t {
         * Flush auth configs once established?
         */
        bool flush_auth_cfg;
+
+       /**
+        * Maximum length of a single fragment, 0 for address-specific defaults
+        */
+       size_t fragment_size;
 };
 
 /**
@@ -994,6 +999,61 @@ METHOD(ike_sa_t, generate_message, status_t,
        return status;
 }
 
+static bool filter_fragments(private_ike_sa_t *this, packet_t **fragment,
+                                                        packet_t **packet)
+{
+       *packet = (*fragment)->clone(*fragment);
+       set_dscp(this, *packet);
+       return TRUE;
+}
+
+METHOD(ike_sa_t, generate_message_fragmented, status_t,
+       private_ike_sa_t *this, message_t *message, enumerator_t **packets)
+{
+       enumerator_t *fragments;
+       packet_t *packet;
+       status_t status;
+       bool use_frags = FALSE;
+
+       if (this->ike_cfg && this->version == IKEV1)
+       {
+               switch (this->ike_cfg->fragmentation(this->ike_cfg))
+               {
+                       case FRAGMENTATION_FORCE:
+                               use_frags = TRUE;
+                               break;
+                       case FRAGMENTATION_YES:
+                               use_frags = supports_extension(this, EXT_IKE_FRAGMENTATION);
+                               break;
+                       default:
+                               break;
+               }
+       }
+       if (!use_frags)
+       {
+               status = generate_message(this, message, &packet);
+               if (status != SUCCESS)
+               {
+                       return status;
+               }
+               *packets = enumerator_create_single(packet, NULL);
+               return SUCCESS;
+       }
+
+       this->stats[STAT_OUTBOUND] = time_monotonic(NULL);
+       message->set_ike_sa_id(message, this->ike_sa_id);
+       charon->bus->message(charon->bus, message, FALSE, TRUE);
+       status = message->fragment(message, this->keymat, this->fragment_size,
+                                                          &fragments);
+       if (status == SUCCESS)
+       {
+               charon->bus->message(charon->bus, message, FALSE, FALSE);
+               *packets = enumerator_create_filter(fragments, (void*)filter_fragments,
+                                                                                       this, NULL);
+       }
+       return status;
+}
+
 METHOD(ike_sa_t, set_kmaddress, void,
        private_ike_sa_t *this, host_t *local, host_t *remote)
 {
@@ -2362,6 +2422,7 @@ ike_sa_t * ike_sa_create(ike_sa_id_t *ike_sa_id, bool initiator,
                        .inherit_pre = _inherit_pre,
                        .inherit_post = _inherit_post,
                        .generate_message = _generate_message,
+                       .generate_message_fragmented = _generate_message_fragmented,
                        .reset = _reset,
                        .get_unique_id = _get_unique_id,
                        .add_virtual_ip = _add_virtual_ip,
@@ -2407,6 +2468,8 @@ ike_sa_t * ike_sa_create(ike_sa_id_t *ike_sa_id, bool initiator,
                                                                "%s.retry_initiate_interval", 0, lib->ns),
                .flush_auth_cfg = lib->settings->get_bool(lib->settings,
                                                                "%s.flush_auth_cfg", FALSE, lib->ns),
+               .fragment_size = lib->settings->get_int(lib->settings,
+                                                               "%s.fragment_size", 0, lib->ns),
        );
 
        if (version == IKEV2)
index 15fb474..7926301 100644 (file)
@@ -1,5 +1,5 @@
 /*
- * Copyright (C) 2006-2012 Tobias Brunner
+ * Copyright (C) 2006-2014 Tobias Brunner
  * Copyright (C) 2006 Daniel Roethlisberger
  * Copyright (C) 2005-2009 Martin Willi
  * Copyright (C) 2005 Jan Hutter
@@ -756,7 +756,7 @@ struct ike_sa_t {
        status_t (*roam)(ike_sa_t *this, bool address);
 
        /**
-        * Processes a incoming IKEv2-Message.
+        * Processes an incoming IKE message.
         *
         * Message processing may fail. If a critical failure occurs,
         * process_message() return DESTROY_ME. Then the caller must
@@ -768,10 +768,10 @@ struct ike_sa_t {
         *                                              - FAILED
         *                                              - DESTROY_ME if this IKE_SA MUST be deleted
         */
-       status_t (*process_message) (ike_sa_t *this, message_t *message);
+       status_t (*process_message)(ike_sa_t *this, message_t *message);
 
        /**
-        * Generate a IKE message to send it to the peer.
+        * Generate an IKE message to send it to the peer.
         *
         * This method generates all payloads in the message and encrypts/signs
         * the packet.
@@ -783,8 +783,26 @@ struct ike_sa_t {
         *                                              - FAILED
         *                                              - DESTROY_ME if this IKE_SA MUST be deleted
         */
-       status_t (*generate_message) (ike_sa_t *this, message_t *message,
-                                                                 packet_t **packet);
+       status_t (*generate_message)(ike_sa_t *this, message_t *message,
+                                                                packet_t **packet);
+
+       /**
+        * Generate an IKE message to send it to the peer. If enabled and supported
+        * it will be fragmented.
+        *
+        * This method generates all payloads in the message and encrypts/signs
+        * the packet/fragments.
+        *
+        * @param message               message to generate
+        * @param packets               enumerator of generated packet_t* (are not destroyed
+        *                                              with the enumerator)
+        * @return
+        *                                              - SUCCESS
+        *                                              - FAILED
+        *                                              - DESTROY_ME if this IKE_SA MUST be deleted
+        */
+       status_t (*generate_message_fragmented)(ike_sa_t *this, message_t *message,
+                                                                                       enumerator_t **packets);
 
        /**
         * Retransmits a request.
index 4e35118..498d6c4 100644 (file)
@@ -208,18 +208,6 @@ struct private_task_manager_t {
                 */
                size_t max_packet;
 
-               /**
-                * Maximum length of a single fragment (when sending)
-                */
-               size_t size;
-
-               /**
-                * The exchange type we use for fragments. Always the initial type even
-                * for fragmented quick mode or transaction messages (i.e. either
-                * ID_PROT or AGGRESSIVE)
-                */
-               exchange_type_t exchange;
-
        } frag;
 
        /**
@@ -398,52 +386,20 @@ static void send_packets(private_task_manager_t *this, array_t *packets)
 static bool generate_message(private_task_manager_t *this, message_t *message,
                                                         array_t **packets)
 {
-       bool use_frags = FALSE, result = TRUE;
-       ike_cfg_t *ike_cfg;
        enumerator_t *fragments;
-       packet_t *packet;
-       status_t status;
+       packet_t *fragment;
 
-       ike_cfg = this->ike_sa->get_ike_cfg(this->ike_sa);
-       if (ike_cfg)
-       {
-               switch (ike_cfg->fragmentation(ike_cfg))
-               {
-                       case FRAGMENTATION_FORCE:
-                               use_frags = TRUE;
-                               break;
-                       case FRAGMENTATION_YES:
-                               use_frags = this->ike_sa->supports_extension(this->ike_sa,
-                                                                                                       EXT_IKE_FRAGMENTATION);
-                               break;
-                       default:
-                               break;
-               }
-       }
-
-       if (!use_frags)
-       {
-               if (this->ike_sa->generate_message(this->ike_sa, message,
-                                                                                  &packet) != SUCCESS)
-               {
-                       return FALSE;
-               }
-               array_insert_create(packets, ARRAY_TAIL, packet);
-               return TRUE;
-       }
-       message->set_ike_sa_id(message, this->ike_sa->get_id(this->ike_sa));
-       status = message->fragment(message, this->ike_sa->get_keymat(this->ike_sa),
-                                                          this->frag.size, &fragments);
-       if (status != SUCCESS)
+       if (this->ike_sa->generate_message_fragmented(this->ike_sa, message,
+                                                                                                 &fragments) != SUCCESS)
        {
                return FALSE;
        }
-       while (fragments->enumerate(fragments, &packet))
+       while (fragments->enumerate(fragments, &fragment))
        {
-               array_insert_create(packets, ARRAY_TAIL, packet->clone(packet));
+               array_insert_create(packets, ARRAY_TAIL, fragment);
        }
        fragments->destroy(fragments);
-       return result;
+       return TRUE;
 }
 
 /**
@@ -1046,7 +1002,6 @@ static status_t process_request(private_task_manager_t *this,
                                this->passive_tasks->insert_last(this->passive_tasks, task);
                                task = (task_t *)isakmp_natd_create(this->ike_sa, FALSE);
                                this->passive_tasks->insert_last(this->passive_tasks, task);
-                               this->frag.exchange = AGGRESSIVE;
                                break;
                        case QUICK_MODE:
                                if (this->ike_sa->get_state(this->ike_sa) != IKE_ESTABLISHED)
@@ -1623,7 +1578,6 @@ METHOD(task_manager_t, queue_ike, void,
                {
                        queue_task(this, (task_t*)aggressive_mode_create(this->ike_sa, TRUE));
                }
-               this->frag.exchange = AGGRESSIVE;
        }
        else
        {
@@ -2061,11 +2015,8 @@ task_manager_v1_t *task_manager_v1_create(ike_sa_t *ike_sa)
                        .seqnr = RESPONDING_SEQ,
                },
                .frag = {
-                       .exchange = ID_PROT,
                        .max_packet = lib->settings->get_int(lib->settings,
                                                "%s.max_packet", MAX_PACKET, lib->ns),
-                       .size = lib->settings->get_int(lib->settings,
-                                               "%s.fragment_size", 0, lib->ns),
                },
                .ike_sa = ike_sa,
                .rng = lib->crypto->create_rng(lib->crypto, RNG_WEAK),