added support for transport mode and (experimental!) BEET mode
[strongswan.git] / src / charon / sa / transactions / ike_auth.c
index ae155ec..3ab4d8a 100644 (file)
@@ -128,6 +128,11 @@ struct private_ike_auth_t {
         * reqid to use for CHILD_SA setup
         */
        u_int32_t reqid;
         * reqid to use for CHILD_SA setup
         */
        u_int32_t reqid;
+       
+       /**
+        * mode the CHILD_SA uses: tranport, tunnel, BEET
+        */
+       mode_t mode;
 };
 
 /**
 };
 
 /**
@@ -183,6 +188,30 @@ static void set_init_messages(private_ike_auth_t *this, chunk_t init_request, ch
 }
 
 /**
 }
 
 /**
+ * Build a notify message.
+ */
+static void build_notify(notify_type_t type, message_t *message, bool flush_message)
+{
+       notify_payload_t *notify;
+       
+       if (flush_message)
+       {
+               payload_t *payload;
+               iterator_t *iterator = message->get_payload_iterator(message);
+               while (iterator->iterate(iterator, (void**)&payload))
+               {
+                       payload->destroy(payload);
+                       iterator->remove(iterator);
+               }
+               iterator->destroy(iterator);
+       }
+       
+       notify = notify_payload_create();
+       notify->set_notify_type(notify, type);
+       message->add_payload(message, (payload_t*)notify);
+}
+
+/**
  * Implementation of transaction_t.get_request.
  */
 static status_t get_request(private_ike_auth_t *this, message_t **result)
  * Implementation of transaction_t.get_request.
  */
 static status_t get_request(private_ike_auth_t *this, message_t **result)
@@ -319,6 +348,28 @@ static status_t get_request(private_ike_auth_t *this, message_t **result)
                request->add_payload(request, (payload_t*)sa_payload);
        }
        
                request->add_payload(request, (payload_t*)sa_payload);
        }
        
+       /* notify for transport/BEET mode, we propose it 
+        * independent of the traffic selectors */
+       switch (this->policy->get_mode(this->policy))
+       {
+               case MODE_TUNNEL:
+                       /* is the default */
+                       break;
+               case MODE_TRANSPORT:
+                       if (this->ike_sa->is_natt_enabled(this->ike_sa))
+                       {
+                               DBG1(DBG_IKE, "not using tranport mode, as connection NATed");
+                       }
+                       else
+                       {
+                               build_notify(USE_TRANSPORT_MODE, request, FALSE);
+                       }
+                       break;
+               case MODE_BEET:
+                       build_notify(USE_BEET_MODE, request, FALSE);
+                       break;
+       }
+       
        {       /* build TSi payload */
                linked_list_t *ts_list;
                ts_payload_t *ts_payload;
        {       /* build TSi payload */
                linked_list_t *ts_list;
                ts_payload_t *ts_payload;
@@ -376,6 +427,16 @@ static status_t process_notifies(private_ike_auth_t *this, notify_payload_t *not
                        this->build_child = FALSE;
                        return SUCCESS;
                }
                        this->build_child = FALSE;
                        return SUCCESS;
                }
+               case USE_TRANSPORT_MODE:
+               {
+                       this->mode = MODE_TRANSPORT;
+                       return SUCCESS;
+               }
+               case USE_BEET_MODE:
+               {
+                       this->mode = MODE_BEET;
+                       return SUCCESS;
+               }
                default:
                {
                        if (notify_type < 16383)
                default:
                {
                        if (notify_type < 16383)
@@ -395,30 +456,6 @@ static status_t process_notifies(private_ike_auth_t *this, notify_payload_t *not
 }
 
 /**
 }
 
 /**
- * Build a notify message.
- */
-static void build_notify(notify_type_t type, message_t *message, bool flush_message)
-{
-       notify_payload_t *notify;
-       
-       if (flush_message)
-       {
-               payload_t *payload;
-               iterator_t *iterator = message->get_payload_iterator(message);
-               while (iterator->iterate(iterator, (void**)&payload))
-               {
-                       payload->destroy(payload);
-                       iterator->remove(iterator);
-               }
-               iterator->destroy(iterator);
-       }
-       
-       notify = notify_payload_create();
-       notify->set_notify_type(notify, type);
-       message->add_payload(message, (payload_t*)notify);
-}
-
-/**
  * Import certificate requests from a certreq payload
  */
 static void add_certificate_request(certreq_payload_t *certreq_payload,
  * Import certificate requests from a certreq payload
  */
 static void add_certificate_request(certreq_payload_t *certreq_payload,
@@ -502,6 +539,23 @@ static void import_certificate(cert_payload_t *cert_payload)
 }
 
 /**
 }
 
 /**
+ * Check a list of traffic selectors if any selector belongs to host
+ */
+static bool ts_list_is_host(linked_list_t *list, host_t *host)
+{
+       traffic_selector_t *ts;
+       bool is_host = TRUE;
+       iterator_t *iterator = list->create_iterator(list, TRUE);
+       
+       while (is_host && iterator->iterate(iterator, (void**)&ts))
+       {
+               is_host = is_host && ts->is_host(ts, host);
+       }
+       iterator->destroy(iterator);
+       return is_host;
+}
+
+/**
  * Install a CHILD_SA for usage
  */
 static status_t install_child_sa(private_ike_auth_t *this, bool initiator)
  * Install a CHILD_SA for usage
  */
 static status_t install_child_sa(private_ike_auth_t *this, bool initiator)
@@ -518,11 +572,13 @@ static status_t install_child_sa(private_ike_auth_t *this, bool initiator)
        
        if (initiator)
        {
        
        if (initiator)
        {
-               status = this->child_sa->update(this->child_sa, this->proposal, prf_plus);
+               status = this->child_sa->update(this->child_sa, this->proposal, 
+                                                                               this->mode, prf_plus);
        }
        else
        {
        }
        else
        {
-               status = this->child_sa->add(this->child_sa, this->proposal, prf_plus);
+               status = this->child_sa->add(this->child_sa, this->proposal, 
+                                                                        this->mode, prf_plus);
        }
        prf_plus->destroy(prf_plus);
        if (status != SUCCESS)
        }
        prf_plus->destroy(prf_plus);
        if (status != SUCCESS)
@@ -531,11 +587,13 @@ static status_t install_child_sa(private_ike_auth_t *this, bool initiator)
        }
        if (initiator)
        {
        }
        if (initiator)
        {
-               status = this->child_sa->add_policies(this->child_sa, this->tsi, this->tsr);
+               status = this->child_sa->add_policies(this->child_sa, this->tsi,
+                                                                                         this->tsr, this->mode);
        }
        else
        {
        }
        else
        {
-               status = this->child_sa->add_policies(this->child_sa, this->tsr, this->tsi);
+               status = this->child_sa->add_policies(this->child_sa, this->tsr,
+                                                                                         this->tsi, this->mode);
        }
        if (status != SUCCESS)
        {
        }
        if (status != SUCCESS)
        {
@@ -850,6 +908,44 @@ static status_t get_response(private_ike_auth_t *this, message_t *request,
                                                                                         this->policy->get_hostaccess(this->policy),
                                                                                         use_natt);
                        this->child_sa->set_name(this->child_sa, this->policy->get_name(this->policy));
                                                                                         this->policy->get_hostaccess(this->policy),
                                                                                         use_natt);
                        this->child_sa->set_name(this->child_sa, this->policy->get_name(this->policy));
+                       
+                       /* check mode, and include notify into reply */
+                       switch (this->mode)
+                       {
+                               case MODE_TUNNEL:
+                                       /* is the default */
+                                       break;
+                               case MODE_TRANSPORT:
+                                       if (!ts_list_is_host(this->tsi, other) ||
+                                               !ts_list_is_host(this->tsr, me))
+                                       {
+                                               this->mode = MODE_TUNNEL;
+                                               DBG1(DBG_IKE, "not using tranport mode, not host-to-host");
+                                       }
+                                       else if (this->ike_sa->is_natt_enabled(this->ike_sa))
+                                       {
+                                               this->mode = MODE_TUNNEL;
+                                               DBG1(DBG_IKE, "not using tranport mode, as connection NATed");
+                                       }
+                                       else 
+                                       {
+                                               build_notify(USE_TRANSPORT_MODE, response, FALSE);
+                                       }
+                                       break;
+                               case MODE_BEET:
+                                       if (!ts_list_is_host(this->tsi, NULL) ||
+                                               !ts_list_is_host(this->tsr, NULL))
+                                       {
+                                               this->mode = MODE_TUNNEL;
+                                               DBG1(DBG_IKE, "not using BEET mode, not host-to-host");
+                                       }
+                                       else
+                                       {
+                                               build_notify(USE_BEET_MODE, response, FALSE);
+                                       }
+                                       break;
+                       }
+                       
                        if (install_child_sa(this, FALSE) != SUCCESS)
                        {
                                SIG(CHILD_UP_FAILED, "installing CHILD_SA failed, no CHILD_SA created");
                        if (install_child_sa(this, FALSE) != SUCCESS)
                        {
                                SIG(CHILD_UP_FAILED, "installing CHILD_SA failed, no CHILD_SA created");
@@ -1048,6 +1144,37 @@ static status_t conclude(private_ike_auth_t *this, message_t *response,
                }
                else
                {
                }
                else
                {
+                       /* check mode if it is acceptable */
+                       switch (this->mode)
+                       {
+                               case MODE_TUNNEL:
+                                       /* is the default */
+                                       break;
+                               case MODE_TRANSPORT:
+                                       /* TODO: we should close the CHILD_SA if negotiated
+                                        * mode is not acceptable for us */
+                                       if (!ts_list_is_host(this->tsi, me) ||
+                                               !ts_list_is_host(this->tsr, other))
+                                       {
+                                               this->mode = MODE_TUNNEL;
+                                               DBG1(DBG_IKE, "not using tranport mode, not host-to-host");
+                                       }
+                                       else if (this->ike_sa->is_natt_enabled(this->ike_sa))
+                                       {
+                                               this->mode = MODE_TUNNEL;
+                                               DBG1(DBG_IKE, "not using tranport mode, as connection NATed");
+                                       }
+                                       break;
+                               case MODE_BEET:
+                                       if (!ts_list_is_host(this->tsi, NULL) ||
+                                               !ts_list_is_host(this->tsr, NULL))
+                                       {
+                                               this->mode = MODE_TUNNEL;
+                                               DBG1(DBG_IKE, "not using BEET mode, not host-to-host");
+                                       }
+                                       break;
+                       }
+               
                        if (install_child_sa(this, TRUE) != SUCCESS)
                        {
                                SIG(CHILD_UP_FAILED, "installing CHILD_SA failed, no CHILD_SA built");
                        if (install_child_sa(this, TRUE) != SUCCESS)
                        {
                                SIG(CHILD_UP_FAILED, "installing CHILD_SA failed, no CHILD_SA built");
@@ -1126,6 +1253,7 @@ ike_auth_t *ike_auth_create(ike_sa_t *ike_sa)
        this->tsr = NULL;
        this->build_child = TRUE;
        this->reqid = 0;
        this->tsr = NULL;
        this->build_child = TRUE;
        this->reqid = 0;
+       this->mode = MODE_TUNNEL;
        
        return &this->public;
 }
        
        return &this->public;
 }