Added support for IKEv1 IPComp proposals in SA payload.
authorTobias Brunner <tobias@strongswan.org>
Thu, 24 May 2012 11:31:53 +0000 (13:31 +0200)
committerTobias Brunner <tobias@strongswan.org>
Thu, 24 May 2012 13:32:28 +0000 (15:32 +0200)
src/libcharon/encoding/payloads/sa_payload.c
src/libcharon/encoding/payloads/sa_payload.h
src/libcharon/sa/ikev1/tasks/aggressive_mode.c
src/libcharon/sa/ikev1/tasks/main_mode.c
src/libcharon/sa/ikev1/tasks/quick_mode.c

index 18b1dc7..4fb1bc6 100644 (file)
@@ -336,6 +336,60 @@ METHOD(sa_payload_t, get_proposals, linked_list_t*,
        return list;
 }
 
+METHOD(sa_payload_t, get_ipcomp_proposals, linked_list_t*,
+       private_sa_payload_t *this, u_int16_t *cpi)
+{
+       int current_proposal = -1, unsupported_proposal = -1;
+       enumerator_t *enumerator;
+       proposal_substructure_t *substruct, *esp = NULL, *ipcomp = NULL;
+       linked_list_t *list;
+
+       /* we currently only support the combination ESP+IPComp, find the first */
+       enumerator = this->proposals->create_enumerator(this->proposals);
+       while (enumerator->enumerate(enumerator, &substruct))
+       {
+               u_int8_t proposal_number = substruct->get_proposal_number(substruct);
+               u_int8_t protocol_id = substruct->get_protocol_id(substruct);
+
+               if (proposal_number == unsupported_proposal)
+               {
+                       continue;
+               }
+               if (protocol_id != PROTO_ESP && protocol_id != PROTO_IPCOMP)
+               {       /* unsupported combination */
+                       esp = ipcomp = NULL;
+                       unsupported_proposal = current_proposal;
+                       continue;
+               }
+               if (proposal_number != current_proposal)
+               {       /* start of a new proposal */
+                       if (esp && ipcomp)
+                       {       /* previous proposal is valid */
+                               break;
+                       }
+                       esp = ipcomp = NULL;
+                       current_proposal = proposal_number;
+               }
+               switch (protocol_id)
+               {
+                       case PROTO_ESP:
+                               esp = substruct;
+                               break;
+                       case PROTO_IPCOMP:
+                               ipcomp = substruct;
+                               break;
+               }
+       }
+       enumerator->destroy(enumerator);
+
+       list = linked_list_create();
+       if (esp && ipcomp && ipcomp->get_cpi(ipcomp, cpi))
+       {
+               esp->get_proposals(esp, list);
+       }
+       return list;
+}
+
 METHOD(sa_payload_t, create_substructure_enumerator, enumerator_t*,
        private_sa_payload_t *this)
 {
@@ -438,6 +492,7 @@ sa_payload_t *sa_payload_create(payload_type_t type)
                                .destroy = _destroy,
                        },
                        .get_proposals = _get_proposals,
+                       .get_ipcomp_proposals = _get_ipcomp_proposals,
                        .create_substructure_enumerator = _create_substructure_enumerator,
                        .get_lifetime = _get_lifetime,
                        .get_lifebytes = _get_lifebytes,
@@ -497,7 +552,8 @@ sa_payload_t *sa_payload_create_from_proposal_v2(proposal_t *proposal)
  */
 sa_payload_t *sa_payload_create_from_proposals_v1(linked_list_t *proposals,
                                                                u_int32_t lifetime, u_int64_t lifebytes,
-                                                               auth_method_t auth, ipsec_mode_t mode, bool udp)
+                                                               auth_method_t auth, ipsec_mode_t mode, bool udp,
+                                                               u_int16_t cpi)
 {
        proposal_substructure_t *substruct;
        private_sa_payload_t *this;
@@ -505,11 +561,18 @@ sa_payload_t *sa_payload_create_from_proposals_v1(linked_list_t *proposals,
        this = (private_sa_payload_t*)sa_payload_create(SECURITY_ASSOCIATION_V1);
 
        /* IKEv1 encodes multiple proposals in a single substructure
-        * TODO-IKEv1: Encode ESP+AH proposals in two different substructs */
+        * TODO-IKEv1: Encode ESP+AH proposals in two substructs with same num */
        substruct = proposal_substructure_create_from_proposals_v1(proposals,
                                                                                lifetime, lifebytes, auth, mode, udp);
-       substruct->set_is_last_proposal(substruct, TRUE);
        this->proposals->insert_last(this->proposals, substruct);
+       substruct->set_is_last_proposal(substruct, FALSE);
+       if (cpi)
+       {
+               substruct = proposal_substructure_create_for_ipcomp_v1(lifetime,
+                                       lifebytes, cpi, substruct->get_proposal_number(substruct));
+               this->proposals->insert_last(this->proposals, substruct);
+       }
+       substruct->set_is_last_proposal(substruct, TRUE);
        compute_length(this);
 
        return &this->public;
@@ -520,7 +583,8 @@ sa_payload_t *sa_payload_create_from_proposals_v1(linked_list_t *proposals,
  */
 sa_payload_t *sa_payload_create_from_proposal_v1(proposal_t *proposal,
                                                                u_int32_t lifetime, u_int64_t lifebytes,
-                                                               auth_method_t auth, ipsec_mode_t mode, bool udp)
+                                                               auth_method_t auth, ipsec_mode_t mode, bool udp,
+                                                               u_int16_t cpi)
 {
        proposal_substructure_t *substruct;
        private_sa_payload_t *this;
@@ -529,8 +593,15 @@ sa_payload_t *sa_payload_create_from_proposal_v1(proposal_t *proposal,
 
        substruct = proposal_substructure_create_from_proposal_v1(proposal,
                                                                                lifetime, lifebytes, auth, mode, udp);
-       substruct->set_is_last_proposal(substruct, TRUE);
        this->proposals->insert_last(this->proposals, substruct);
+       substruct->set_is_last_proposal(substruct, FALSE);
+       if (cpi)
+       {
+               substruct = proposal_substructure_create_for_ipcomp_v1(lifetime,
+                                       lifebytes, cpi, substruct->get_proposal_number(substruct));
+               this->proposals->insert_last(this->proposals, substruct);
+       }
+       substruct->set_is_last_proposal(substruct, TRUE);
        compute_length(this);
 
        return &this->public;
index 6dfbd51..9a88ccc 100644 (file)
@@ -46,11 +46,20 @@ struct sa_payload_t {
        /**
         * Gets the proposals in this payload as a list.
         *
-        * @return                                      a list containing proposal_t s
+        * @return                              a list containing proposal_ts
         */
        linked_list_t *(*get_proposals) (sa_payload_t *this);
 
        /**
+        * Gets the proposals from the first proposal in this payload with IPComp
+        * enabled (IKEv1 only).
+        *
+        * @param cpi                   the CPI of the first IPComp (sub)proposal
+        * @return                              a list containing proposal_ts
+        */
+       linked_list_t *(*get_ipcomp_proposals) (sa_payload_t *this, u_int16_t *cpi);
+
+       /**
         * Get the (shortest) lifetime of a proposal (IKEv1 only).
         *
         * @return                                      lifetime, in seconds
@@ -125,11 +134,13 @@ sa_payload_t *sa_payload_create_from_proposal_v2(proposal_t *proposal);
  * @param auth                         authentication method to use, or AUTH_NONE
  * @param mode                         IPsec encapsulation mode, TRANSPORT or TUNNEL
  * @param udp                          TRUE to use UDP encapsulation
+ * @param cpi                          CPI in case IPComp should be used
  * @return                                     sa_payload_t object
  */
 sa_payload_t *sa_payload_create_from_proposals_v1(linked_list_t *proposals,
                                                        u_int32_t lifetime, u_int64_t lifebytes,
-                                                       auth_method_t auth, ipsec_mode_t mode, bool udp);
+                                                       auth_method_t auth, ipsec_mode_t mode, bool udp,
+                                                       u_int16_t cpi);
 
 /**
  * Creates an IKEv1 sa_payload_t object from a single proposal.
@@ -140,10 +151,12 @@ sa_payload_t *sa_payload_create_from_proposals_v1(linked_list_t *proposals,
  * @param auth                         authentication method to use, or AUTH_NONE
  * @param mode                         IPsec encapsulation mode, TRANSPORT or TUNNEL
  * @param udp                          TRUE to use UDP encapsulation
+ * @param cpi                          CPI in case IPComp should be used
  * @return                                     sa_payload_t object
  */
 sa_payload_t *sa_payload_create_from_proposal_v1(proposal_t *proposal,
                                                        u_int32_t lifetime, u_int64_t lifebytes,
-                                                       auth_method_t auth, ipsec_mode_t mode, bool udp);
+                                                       auth_method_t auth, ipsec_mode_t mode, bool udp,
+                                                       u_int16_t cpi);
 
 #endif /** SA_PAYLOAD_H_ @}*/
index 664fce9..db27ae1 100644 (file)
@@ -235,7 +235,7 @@ METHOD(task_t, build_i, status_t,
                        this->lifetime += this->peer_cfg->get_over_time(this->peer_cfg);
                        proposals = this->ike_cfg->get_proposals(this->ike_cfg);
                        sa_payload = sa_payload_create_from_proposals_v1(proposals,
-                                               this->lifetime, 0, this->method, MODE_NONE, FALSE);
+                                               this->lifetime, 0, this->method, MODE_NONE, FALSE, 0);
                        proposals->destroy_offset(proposals, offsetof(proposal_t, destroy));
 
                        message->add_payload(message, &sa_payload->payload_interface);
@@ -480,7 +480,7 @@ METHOD(task_t, build_r, status_t,
                identification_t *id;
 
                sa_payload = sa_payload_create_from_proposal_v1(this->proposal,
-                                                       this->lifetime, 0, this->method, MODE_NONE, FALSE);
+                                               this->lifetime, 0, this->method, MODE_NONE, FALSE, 0);
                message->add_payload(message, &sa_payload->payload_interface);
 
                if (!this->ph1->add_nonce_ke(this->ph1, message))
index ce047df..23c90ba 100644 (file)
@@ -241,7 +241,7 @@ METHOD(task_t, build_i, status_t,
                        this->lifetime += this->peer_cfg->get_over_time(this->peer_cfg);
                        proposals = this->ike_cfg->get_proposals(this->ike_cfg);
                        sa_payload = sa_payload_create_from_proposals_v1(proposals,
-                                                       this->lifetime, 0, this->method, MODE_NONE, FALSE);
+                                               this->lifetime, 0, this->method, MODE_NONE, FALSE, 0);
                        proposals->destroy_offset(proposals, offsetof(proposal_t, destroy));
 
                        message->add_payload(message, &sa_payload->payload_interface);
@@ -455,7 +455,7 @@ METHOD(task_t, build_r, status_t,
                        sa_payload_t *sa_payload;
 
                        sa_payload = sa_payload_create_from_proposal_v1(this->proposal,
-                                                       this->lifetime, 0, this->method, MODE_NONE, FALSE);
+                                               this->lifetime, 0, this->method, MODE_NONE, FALSE, 0);
                        message->add_payload(message, &sa_payload->payload_interface);
 
                        return NEED_MORE;
index cc3ac67..6fa0752 100644 (file)
@@ -654,7 +654,7 @@ METHOD(task_t, build_i, status_t,
                        get_lifetimes(this);
                        sa_payload = sa_payload_create_from_proposals_v1(list,
                                                                this->lifetime, this->lifebytes, AUTH_NONE,
-                                                               this->mode, this->udp);
+                                                               this->mode, this->udp, 0);
                        list->destroy_offset(list, offsetof(proposal_t, destroy));
                        message->add_payload(message, &sa_payload->payload_interface);
 
@@ -933,7 +933,7 @@ METHOD(task_t, build_r, status_t,
 
                        sa_payload = sa_payload_create_from_proposal_v1(this->proposal,
                                                                this->lifetime, this->lifebytes, AUTH_NONE,
-                                                               this->mode, this->udp);
+                                                               this->mode, this->udp, 0);
                        message->add_payload(message, &sa_payload->payload_interface);
 
                        if (!add_nonce(this, &this->nonce_r, message))