add priority management for kernel policy
authorMartin Willi <martin@strongswan.org>
Fri, 8 Sep 2006 13:10:52 +0000 (13:10 -0000)
committerMartin Willi <martin@strongswan.org>
Fri, 8 Sep 2006 13:10:52 +0000 (13:10 -0000)
let ROUTED policies installed, until manuall removed
introduced new naming scheme to allow proper shutdown of IKE/CHILD_SAs
ike_sa_manager cleanups

12 files changed:
src/charon/config/policies/policy.h
src/charon/config/traffic_selector.c
src/charon/queues/jobs/incoming_packet_job.c
src/charon/sa/child_sa.c
src/charon/sa/ike_sa.c
src/charon/sa/ike_sa_manager.c
src/charon/sa/ike_sa_manager.h
src/charon/sa/transactions/ike_sa_init.c
src/charon/sa/transactions/rekey_ike_sa.c
src/charon/threads/kernel_interface.c
src/charon/threads/kernel_interface.h
src/charon/threads/stroke_interface.c

index 18e6ad0..48d9f70 100644 (file)
@@ -52,7 +52,7 @@ enum dpd_action_t {
 /**
  * String mappings for dpd_action_t
  */
-mapping_t dpd_action_m[];
+extern mapping_t dpd_action_m[];
 
 
 typedef struct policy_t policy_t;
index d8293b8..e567c6e 100644 (file)
@@ -24,6 +24,7 @@
 #include <arpa/inet.h>
 #include <string.h>
 #include <netdb.h>
+#include <stdio.h>
 
 #include "traffic_selector.h"
 
index f773a57..ec8163d 100644 (file)
@@ -152,7 +152,9 @@ static status_t execute(private_incoming_packet_job_t *this)
                                                  ike_sa_id->get_responder_spi(ike_sa_id));
                if (message->get_request(message))
                {
-                       send_notify_response(this, message, INVALID_IKE_SPI);
+                       /* TODO: send notify if we have NULL crypters, 
+                        * see todo in send_notify_response 
+                       send_notify_response(this, message, INVALID_IKE_SPI); */
                }
                ike_sa_id->destroy(ike_sa_id);  
                message->destroy(message);
index 8a7e64a..79cff7a 100644 (file)
@@ -24,6 +24,7 @@
 
 #include "child_sa.h"
 
+#include <stdio.h>
 #include <string.h>
 
 #include <daemon.h>
@@ -182,8 +183,14 @@ static char *get_name(private_child_sa_t *this)
  */
 static void set_name(private_child_sa_t *this, char* name)
 {
-       free(this->name);
-       this->name = strdup(name);
+       char buffer[64];
+       
+       if (snprintf(buffer, sizeof(buffer), "%s[%d]",
+                                name, this->reqid - REQID_START) > 0)
+       {
+               free(this->name);
+               this->name = strdup(buffer);
+       }
 }
 
 /**
@@ -468,6 +475,8 @@ static status_t add_policies(private_child_sa_t *this, linked_list_t *my_ts_list
 {
        iterator_t *my_iter, *other_iter;
        traffic_selector_t *my_ts, *other_ts;
+       /* use low prio for ROUTED policies */
+       bool high_prio = (this->state != CHILD_CREATED);
        
        /* iterate over both lists */
        my_iter = my_ts_list->create_iterator(my_ts_list, TRUE);
@@ -503,15 +512,15 @@ static status_t add_policies(private_child_sa_t *this, linked_list_t *my_ts_list
                        /* install 3 policies: out, in and forward */
                        status = charon->kernel_interface->add_policy(charon->kernel_interface,
                                        this->me.addr, this->other.addr, my_ts, other_ts, 
-                                       POLICY_OUT, this->protocol, this->reqid, FALSE);
+                                       POLICY_OUT, this->protocol, this->reqid, high_prio, FALSE);
                        
                        status |= charon->kernel_interface->add_policy(charon->kernel_interface,
                                        this->other.addr, this->me.addr, other_ts, my_ts,
-                                       POLICY_IN, this->protocol, this->reqid, FALSE);
+                                       POLICY_IN, this->protocol, this->reqid, high_prio, FALSE);
                        
                        status |= charon->kernel_interface->add_policy(charon->kernel_interface,
                                        this->other.addr, this->me.addr, other_ts, my_ts,
-                                       POLICY_FWD, this->protocol, this->reqid, FALSE);
+                                       POLICY_FWD, this->protocol, this->reqid, high_prio, FALSE);
                        
                        if (status != SUCCESS)
                        {
@@ -805,6 +814,7 @@ static status_t update_policy_hosts(private_child_sa_t *this, host_t *new_me, ho
        iterator_t *iterator;
        sa_policy_t *policy;
        status_t status;
+       /* we always use high priorities, as hosts getting updated are INSTALLED */
        
        iterator = this->policies->create_iterator(this->policies, TRUE);
        while (iterator->iterate(iterator, (void**)&policy))
@@ -813,19 +823,19 @@ static status_t update_policy_hosts(private_child_sa_t *this, host_t *new_me, ho
                                charon->kernel_interface,
                                new_me, new_other,
                                policy->my_ts, policy->other_ts,
-                               POLICY_OUT, this->protocol, this->reqid, TRUE);
+                               POLICY_OUT, this->protocol, this->reqid, TRUE, TRUE);
                
                status |= charon->kernel_interface->add_policy(
                                charon->kernel_interface,
                                new_other, new_me,
                                policy->other_ts, policy->my_ts,
-                               POLICY_IN, this->protocol, this->reqid, TRUE);
+                               POLICY_IN, this->protocol, this->reqid, TRUE, TRUE);
                
                status |= charon->kernel_interface->add_policy(
                                charon->kernel_interface,
                                new_other, new_me,
                                policy->other_ts, policy->my_ts,
-                               POLICY_FWD, this->protocol, this->reqid, TRUE);
+                               POLICY_FWD, this->protocol, this->reqid, TRUE, TRUE);
                
                if (status != SUCCESS)
                {
index c5d3a63..55c3302 100644 (file)
@@ -920,8 +920,6 @@ static status_t initiate(private_ike_sa_t *this,
                        
                        this->logger->log(this->logger, CONTROL, 
                                                          "initiating IKE_SA");
-                       
-                       set_name(this, connection->get_name(connection));
                        DESTROY_IF(this->my_host);
                        this->my_host = connection->get_my_host(connection);
                        this->my_host = this->my_host->clone(this->my_host);
@@ -1130,27 +1128,30 @@ static status_t route(private_ike_sa_t *this, connection_t *connection, policy_t
        iterator = this->child_sas->create_iterator(this->child_sas, TRUE);
        while (iterator->iterate(iterator, (void**)&child_sa))
        {
-               linked_list_t *my_ts_conf, *other_ts_conf;
-               
-               my_ts = child_sa->get_my_traffic_selectors(child_sa);
-               other_ts = child_sa->get_other_traffic_selectors(child_sa);
-               
-               my_ts_conf = policy->get_my_traffic_selectors(policy, this->my_host);
-               other_ts_conf = policy->get_other_traffic_selectors(policy, this->other_host);
-               
-               if (ts_list_equals(my_ts, my_ts_conf) &&
-                                 ts_list_equals(other_ts, other_ts_conf))
+               if (child_sa->get_state(child_sa) == CHILD_ROUTED)
                {
+                       linked_list_t *my_ts_conf, *other_ts_conf;
+                       
+                       my_ts = child_sa->get_my_traffic_selectors(child_sa);
+                       other_ts = child_sa->get_other_traffic_selectors(child_sa);
+                       
+                       my_ts_conf = policy->get_my_traffic_selectors(policy, this->my_host);
+                       other_ts_conf = policy->get_other_traffic_selectors(policy, this->other_host);
+                       
+                       if (ts_list_equals(my_ts, my_ts_conf) &&
+                                       ts_list_equals(other_ts, other_ts_conf))
+                       {
+                               ts_list_destroy(my_ts_conf);
+                               ts_list_destroy(other_ts_conf);
+                               iterator->destroy(iterator);
+                               this->logger->log(this->logger, CONTROL, 
+                                                               "a CHILD_SA with such a policy already routed");
+                               
+                               return FAILED;
+                       }
                        ts_list_destroy(my_ts_conf);
                        ts_list_destroy(other_ts_conf);
-                       iterator->destroy(iterator);
-                       this->logger->log(this->logger, CONTROL, 
-                                                         "a CHILD_SA with such a policy already routed");
-                       
-                       return FAILED;
                }
-               ts_list_destroy(my_ts_conf);
-               ts_list_destroy(other_ts_conf);
        }
        iterator->destroy(iterator);
        
index 46bf3a1..7984aa9 100644 (file)
@@ -134,58 +134,7 @@ struct private_ike_sa_manager_t {
         * Public interface of ike_sa_manager_t.
         */
         ike_sa_manager_t public;
-
-       /**
-        * @brief Get next spi.
-        *
-        * We give out SPIs from a pseudo random source
-        * 
-        * @param this                  the ike_sa_manager
-        * @return                              the next spi
-        */
-       u_int64_t (*get_next_spi) (private_ike_sa_manager_t *this);
-
-       /**
-        * @brief Find the ike_sa_entry_t object in the list by SPIs.
-        *
-        * This function simply iterates over the linked list. A hash-table
-        * would be more efficient when storing a lot of IKE_SAs...
-        *
-        * @param this                  calling object
-        * @param ike_sa_id             id of the ike_sa, containing SPIs
-        * @param[out] entry    pointer to set to the found entry
-        * @return                              
-        *                                              - SUCCESS when found,
-        *                                              - NOT_FOUND when no such ike_sa_id in list
-        */
-        status_t (*get_entry_by_id) (private_ike_sa_manager_t *this, ike_sa_id_t *ike_sa_id, ike_sa_entry_t **entry);
-
-        /**
-        * @brief Find the ike_sa_entry_t in the list by pointer to SA.
-        *
-        * This function simply iterates over the linked list. A hash-table
-        * would be more efficient when storing a lot of IKE_SAs...
-        *
-        * @param this                  calling object
-        * @param ike_sa                pointer to the ike_sa
-        * @param[out] entry    pointer to set to the found entry
-        * @return                              
-        *                                              - SUCCESS when found,
-        *                                              - NOT_FOUND when no such ike_sa_id in list
-        */
-        status_t (*get_entry_by_sa) (private_ike_sa_manager_t *this, ike_sa_t *ike_sa, ike_sa_entry_t **entry);
-        
-        /**
-         * @brief Delete an entry from the linked list.
-         *
-         * @param this                 calling object
-         * @param entry                entry to delete
-         * @return                             
-         *                                     - SUCCESS when found,
-         *                                     - NOT_FOUND when no such ike_sa_id in list
-         */
-        status_t (*delete_entry) (private_ike_sa_manager_t *this, ike_sa_entry_t *entry);
-
+       
         /**
          * Lock for exclusivly accessing the manager.
          */
@@ -321,6 +270,17 @@ static status_t delete_entry(private_ike_sa_manager_t *this, ike_sa_entry_t *ent
                iterator->current(iterator, (void**)&current);
                if (current == entry) 
                {
+                       /* mark it, so now new threads can get this entry */
+                       entry->driveout_new_threads = TRUE;
+                       /* wait until all workers have done their work */
+                       while (entry->waiting_threads)
+                       {
+                               /* wake up all */
+                               pthread_cond_broadcast(&(entry->condvar));
+                               /* they will wake us again when their work is done */
+                               pthread_cond_wait(&(entry->condvar), &(this->mutex));
+                       }
+                       
                        this->logger->log(this->logger, CONTROL|LEVEL2, 
                                                          "found entry by pointer. Going to delete it");
                        iterator->remove(iterator);
@@ -440,7 +400,7 @@ static ike_sa_t* checkout_by_id(private_ike_sa_manager_t *this,
                ike_sa_entry_t *new_ike_sa_entry;
                ike_sa_id_t *new_ike_sa_id;
                
-               initiator_spi = this->get_next_spi(this);
+               initiator_spi = get_next_spi(this);
                new_ike_sa_id = ike_sa_id_create(0, 0, TRUE);
                new_ike_sa_id->set_initiator_spi(new_ike_sa_id, initiator_spi);
                
@@ -501,7 +461,7 @@ static ike_sa_t* checkout(private_ike_sa_manager_t *this, ike_sa_id_t *ike_sa_id
                 */
                ike_sa_entry_t *entry;
                /* look for the entry */
-               if (this->get_entry_by_id(this, ike_sa_id, &entry) == SUCCESS)
+               if (get_entry_by_id(this, ike_sa_id, &entry) == SUCCESS)
                {
                        if (wait_for_entry(this, entry))
                        {
@@ -537,7 +497,7 @@ static ike_sa_t* checkout(private_ike_sa_manager_t *this, ike_sa_id_t *ike_sa_id
                ike_sa_entry_t *new_ike_sa_entry;
                
                /* set SPIs, we are the responder */
-               responder_spi = this->get_next_spi(this);
+               responder_spi = get_next_spi(this);
                
                /* we also set arguments spi, so its still valid */
                ike_sa_id->set_responder_spi(ike_sa_id, responder_spi);
@@ -558,7 +518,7 @@ static ike_sa_t* checkout(private_ike_sa_manager_t *this, ike_sa_id_t *ike_sa_id
                /* checkout of a new and unused IKE_SA, used for rekeying */
                ike_sa_entry_t *new_ike_sa_entry;
                
-               ike_sa_id->set_initiator_spi(ike_sa_id, this->get_next_spi(this));
+               ike_sa_id->set_initiator_spi(ike_sa_id, get_next_spi(this));
                /* create entry */
                new_ike_sa_entry = ike_sa_entry_create(ike_sa_id);
                this->logger->log(this->logger, CONTROL|LEVEL2,
@@ -621,7 +581,7 @@ static ike_sa_t* checkout_by_child(private_ike_sa_manager_t *this,
 /**
  * Implementation of ike_sa_manager_t.get_ike_sa_list.
  */
-linked_list_t *get_ike_sa_list(private_ike_sa_manager_t* this)
+static linked_list_t *get_ike_sa_list(private_ike_sa_manager_t* this)
 {
        linked_list_t *list;
        iterator_t *iterator;
@@ -643,32 +603,6 @@ linked_list_t *get_ike_sa_list(private_ike_sa_manager_t* this)
 }
 
 /**
- * Implementation of ike_sa_manager_t.get_ike_sa_list_by_name.
- */
-linked_list_t *get_ike_sa_list_by_name(private_ike_sa_manager_t* this, const char *name)
-{
-       linked_list_t *list;
-       iterator_t *iterator;
-       ike_sa_entry_t *entry;
-       
-       pthread_mutex_lock(&(this->mutex));
-       
-       list = linked_list_create();
-       iterator = this->ike_sa_list->create_iterator(this->ike_sa_list, TRUE);
-       while (iterator->iterate(iterator, (void**)&entry))
-       {
-               if (strcmp(name, entry->ike_sa->get_name(entry->ike_sa)) == 0)
-               {
-                       list->insert_last(list, (void*)entry->ike_sa_id->clone(entry->ike_sa_id));
-               }
-       }
-       iterator->destroy(iterator);
-       
-       pthread_mutex_unlock(&(this->mutex));
-       return list;
-}
-
-/**
  * Implementation of ike_sa_manager_t.log_status.
  */
 static void log_status(private_ike_sa_manager_t* this, logger_t* logger, char* name)
@@ -724,7 +658,7 @@ static status_t checkin(private_ike_sa_manager_t *this, ike_sa_t *ike_sa)
        pthread_mutex_lock(&(this->mutex));
 
        /* look for the entry */
-       if (this->get_entry_by_sa(this, ike_sa, &entry) == SUCCESS)
+       if (get_entry_by_sa(this, ike_sa, &entry) == SUCCESS)
        {
                /* ike_sa_id must be updated */
                entry->ike_sa_id->replace_values(entry->ike_sa_id, ike_sa->get_id(ike_sa));
@@ -772,23 +706,13 @@ static status_t checkin_and_destroy(private_ike_sa_manager_t *this, ike_sa_t *ik
 
        pthread_mutex_lock(&(this->mutex));
 
-       if (this->get_entry_by_sa(this, ike_sa, &entry) == SUCCESS)
+       if (get_entry_by_sa(this, ike_sa, &entry) == SUCCESS)
        {
-               /* mark it, so now new threads can acquire this SA */
-               entry->driveout_new_threads = TRUE;
-               /* additionaly, drive out waiting threads */
+               /* drive out waiting threads, as we are in hurry */
                entry->driveout_waiting_threads = TRUE;
-
-               /* wait until all workers have done their work */
-               while (entry->waiting_threads)
-               {
-                       /* let the other threads leave the manager */
-                       pthread_cond_broadcast(&(entry->condvar));
-                       /* and the nice thing, they will wake us again when their work is done */
-                       pthread_cond_wait(&(entry->condvar), &(this->mutex));
-               }
-               /* ok, we are alone now, no threads waiting in the entry's condvar */
-               this->delete_entry(this, entry);
+               
+               delete_entry(this, entry);
+               
                this->logger->log(this->logger, CONTROL|LEVEL1, 
                                                  "check-in and destroy of IKE_SA successful");
                retval = SUCCESS;
@@ -825,7 +749,7 @@ static status_t delete_(private_ike_sa_manager_t *this, ike_sa_id_t *ike_sa_id)
        
        pthread_mutex_lock(&(this->mutex));
        
-       if (this->get_entry_by_id(this, ike_sa_id, &entry) == SUCCESS)
+       if (get_entry_by_id(this, ike_sa_id, &entry) == SUCCESS)
        {
                /* we try a delete. If it succeeds, our job is done here. The
                 * other peer will reply, and the IKE SA gets the finally deleted...
@@ -837,25 +761,10 @@ static status_t delete_(private_ike_sa_manager_t *this, ike_sa_id_t *ike_sa_id)
                }
                /* but if the IKE SA is not in a state where the deletion is 
                 * negotiated with the other peer, we can destroy the IKE SA on our own. 
-                * For this, we must be sure that really NO other threads are 
-                * waiting for this SA...
                 */
                else
                {
-                       /* mark it, so now new threads can acquire this SA */
-                       entry->driveout_new_threads = TRUE;
-                       /* wait until all workers have done their work */
-                       while (entry->waiting_threads)
-                       {
-                               /* wake up all */
-                               pthread_cond_broadcast(&(entry->condvar));
-                               /* and the nice thing, they will wake us again when their work
-                                * is done */
-                               pthread_cond_wait(&(entry->condvar), &(this->mutex));
-                       }
-                       /* ok, we are alone now, no threads waiting in the entry's condvar */
-                       this->delete_entry(this, entry);
-                       this->logger->log(this->logger, CONTROL|LEVEL1, "destroyed IKE_SA");
+                       
                }
                retval = SUCCESS;
        }
@@ -871,6 +780,125 @@ static status_t delete_(private_ike_sa_manager_t *this, ike_sa_id_t *ike_sa_id)
 }
 
 /**
+ * Implementation of ike_sa_manager_t.delete_by_name.
+ */
+static status_t delete_by_name(private_ike_sa_manager_t *this, char *name)
+{
+       iterator_t *iterator;
+       iterator_t *child_iter;
+       ike_sa_entry_t *entry;
+       size_t name_len = strlen(name);
+       
+       pthread_mutex_lock(&(this->mutex));
+       
+       iterator = this->ike_sa_list->create_iterator(this->ike_sa_list, TRUE);
+       while (iterator->iterate(iterator, (void**)&entry))
+       {
+               if (wait_for_entry(this, entry))
+               {
+                       /* delete ike_sa if:
+                        * name{x} matches completely
+                        * name{} matches by name
+                        * name matches by name
+                        */
+                       bool del = FALSE;
+                       char *ike_name;
+                       char *child_name;
+                       child_sa_t *child_sa;
+                       
+                       ike_name = entry->ike_sa->get_name(entry->ike_sa);
+                       /* check if "name{x}" matches completely */
+                       if (strcmp(name, ike_name) == 0)
+                       {
+                               del = TRUE;
+                       }
+                       /* check if name is in form of "name{}" and matches to ike_name */
+                       else if (name_len > 1 &&
+                                        name[name_len - 2] == '{' && name[name_len - 1] == '}' &&
+                                        strlen(ike_name) > name_len &&
+                                        ike_name[name_len - 2] == '{' &&
+                                        strncmp(name, ike_name, name_len - 2) == 0)
+                       {
+                               del = TRUE;
+                       }
+                       /* finally, check if name is "name" and matches ike_name */
+                       else if (name_len == strchr(ike_name, '{') - ike_name &&
+                                        strncmp(name, ike_name, name_len) == 0)
+                       {
+                               del = TRUE;
+                       }
+                       
+                       if (del)
+                       {
+                               if (entry->ike_sa->delete(entry->ike_sa) == DESTROY_ME)
+                               {
+                                       delete_entry(this, entry);
+                                       iterator->reset(iterator);
+                               }
+                               /* no need to check children, as we delete all */
+                               continue;
+                       }
+                       
+                       /* and now the same game for all children. delete child_sa if:
+                        * name[x] matches completely
+                        * name[] matches by name
+                        * name matches by name
+                        */
+                       child_iter = entry->ike_sa->create_child_sa_iterator(entry->ike_sa);
+                       while (child_iter->iterate(child_iter, (void**)&child_sa))
+                       {
+                               /* skip ROUTED children, they have their "unroute" command */
+                               if (child_sa->get_state(child_sa) == CHILD_ROUTED)
+                               {
+                                       continue;
+                               }
+                               
+                               child_name = child_sa->get_name(child_sa);
+                               del = FALSE;
+                               /* check if "name[x]" matches completely */
+                               if (strcmp(name, child_name) == 0)
+                               {
+                                       del = TRUE;
+                               }
+                               /* check if name is in form of "name[]" and matches to child_name */
+                               else if (name_len > 1 &&
+                                                name[name_len - 2] == '[' && name[name_len - 1] == ']' &&
+                                                strlen(child_name) > name_len &&
+                                                child_name[name_len - 2] == '[' &&
+                                                strncmp(name, child_name, name_len - 2) == 0)
+                               {
+                                       del = TRUE;
+                               }
+                               /* finally, check if name is "name" and matches child_name */
+                               else if (name_len == strchr(child_name, '[') - child_name &&
+                                                strncmp(name, child_name, name_len) == 0)
+                               {
+                                       del = TRUE;
+                               }
+                               if (del)
+                               {
+                                       if (entry->ike_sa->delete_child_sa(entry->ike_sa,
+                                               child_sa->get_protocol(child_sa),
+                                               child_sa->get_spi(child_sa, TRUE)) == DESTROY_ME)
+                                       {
+                                               /* when a fatal error occurs, we are responsible to
+                                                * remove the IKE_SA */
+                                               delete_entry(this, entry);
+                                               iterator->reset(iterator);
+                                               break;
+                                       }
+                               }
+                       }
+                       child_iter->destroy(child_iter);
+               }
+       }
+       iterator->destroy(iterator);
+       pthread_mutex_unlock(&(this->mutex));
+       
+       return SUCCESS;
+}
+
+/**
  * Implementation of ike_sa_manager_t.destroy.
  */
 static void destroy(private_ike_sa_manager_t *this)
@@ -921,10 +949,9 @@ static void destroy(private_ike_sa_manager_t *this)
        
        this->logger->log(this->logger, CONTROL|LEVEL2, "destroy all entries");
        /* Step 4: destroy all entries */
-       while (list->get_count(list) > 0)
+       while (list->remove_last(list, (void**)&entry) == SUCCESS)
        {
-               list->get_first(list, (void**)&entry);
-               this->delete_entry(this, entry);
+               entry->destroy(entry);
        }
        list->destroy(list);
        pthread_mutex_unlock(&(this->mutex));
@@ -947,18 +974,12 @@ ike_sa_manager_t *ike_sa_manager_create()
        this->public.checkout = (ike_sa_t*(*)(ike_sa_manager_t*, ike_sa_id_t*))checkout;
        this->public.checkout_by_child = (ike_sa_t*(*)(ike_sa_manager_t*,u_int32_t))checkout_by_child;
        this->public.get_ike_sa_list = (linked_list_t*(*)(ike_sa_manager_t*))get_ike_sa_list;
-       this->public.get_ike_sa_list_by_name = (linked_list_t*(*)(ike_sa_manager_t*,const char*))get_ike_sa_list_by_name;
        this->public.log_status = (void(*)(ike_sa_manager_t*,logger_t*,char*))log_status;
        this->public.checkin = (status_t(*)(ike_sa_manager_t*,ike_sa_t*))checkin;
        this->public.delete = (status_t(*)(ike_sa_manager_t*,ike_sa_id_t*))delete_;
+       this->public.delete_by_name = (status_t(*)(ike_sa_manager_t*,char*))delete_by_name;
        this->public.checkin_and_destroy = (status_t(*)(ike_sa_manager_t*,ike_sa_t*))checkin_and_destroy;
 
-       /* initialize private functions */
-       this->get_next_spi = get_next_spi;
-       this->get_entry_by_sa = get_entry_by_sa;
-       this->get_entry_by_id = get_entry_by_id;
-       this->delete_entry = delete_entry;
-
        /* initialize private variables */
        this->logger = logger_manager->get_logger(logger_manager, IKE_SA_MANAGER);
        
index f0c90f3..db2efe5 100644 (file)
@@ -117,15 +117,6 @@ struct ike_sa_manager_t {
        linked_list_t *(*get_ike_sa_list) (ike_sa_manager_t* this);
        
        /**
-        * @brief Get a list of all IKE_SA SAs currently set up specified
-        * by the connections name.
-        * 
-        * @param this                          the manager object
-        * @return                                      a list with ike_sa_id_t s
-        */
-       linked_list_t *(*get_ike_sa_list_by_name) (ike_sa_manager_t* this, const char *name);
-       
-       /**
         * @brief Log the status of the IKE_SA's in the manager.
         *
         * A informational log is done to the supplied logger. If logger is 
@@ -172,6 +163,29 @@ struct ike_sa_manager_t {
        status_t (*delete) (ike_sa_manager_t* this, ike_sa_id_t *ike_sa_id);
        
        /**
+        * @brief Delete a SA identified by its name, which was not checked out.
+        *
+        * Using delete_by_name allows the delete of IKE_SAs and CHILD_SAs.
+        * The supplied name may have one of the following format:
+        *
+        * name{x}              => delete IKE_SA with "name" and unique id "x"
+        * name{}               => delete all IKE_SAs with "name"
+        * name[x]              => delete CHILD_SA with "name" and unique id "x"
+        * name[]               => delete all CHILD_SAs with "name"
+        * name                 => delete all CHILD_SAs or IKE_SAs with "name"
+        *
+        * @warning do not use this when the SA is already checked out, this will
+        * deadlock!
+        *
+        * @param this                          the manager object
+        * @param name                          name in one of the format described above
+        * @returns                             
+        *                                                      - SUCCESS if found
+        *                                                      - NOT_FOUND when no such SA is available
+        */
+       status_t (*delete_by_name) (ike_sa_manager_t* this, char *name);
+       
+       /**
         * @brief Destroy a checked out SA.
         *
         * The IKE SA is destroyed without notification of the remote peer.
index 7a78669..b14a074 100644 (file)
@@ -111,6 +111,11 @@ struct private_ike_sa_init_t {
        u_int32_t reqid;
        
        /**
+        * Unique ID for to enumerate all IKE_SAs in its name
+        */
+       u_int32_t unique_id;
+       
+       /**
         * Randomizer to generate nonces
         */
        randomizer_t *randomizer;
@@ -281,6 +286,7 @@ static status_t get_request(private_ike_sa_init_t *this, message_t **result)
        message_t *request;
        host_t *me, *other;
        identification_t *my_id, *other_id;
+       char name[64];
        
        /* check if we already have built a message (retransmission) */
        if (this->message)
@@ -298,6 +304,12 @@ static status_t get_request(private_ike_sa_init_t *this, message_t **result)
        other_id = this->policy->get_other_id(this->policy);
        this->ike_sa->set_my_id(this->ike_sa, my_id->clone(my_id));
        this->ike_sa->set_other_id(this->ike_sa, other_id->clone(other_id));
+       if (snprintf(name, sizeof(name), "%s{%d}",
+                                this->connection->get_name(this->connection),
+                                this->unique_id) > 0)
+       {
+               this->ike_sa->set_name(this->ike_sa, name);
+       }
        
        /* build the request */
        request = message_create();
@@ -516,6 +528,7 @@ static status_t get_response(private_ike_sa_init_t *this,
        nonce_payload_t *nonce_request = NULL;
        ike_sa_id_t *ike_sa_id;
        u_int32_t timeout;
+       char name[64];
        
        /* check if we already have built a response (retransmission) */
        if (this->message)
@@ -561,8 +574,13 @@ static status_t get_response(private_ike_sa_init_t *this,
                                                  me->get_string(me), other->get_string(other));
                return DESTROY_ME;
        }
-       this->ike_sa->set_name(this->ike_sa, 
-                                                  this->connection->get_name(this->connection));
+       
+       if (snprintf(name, sizeof(name), "%s{%d}",
+                                this->connection->get_name(this->connection),
+                                this->unique_id) > 0)
+       {
+               this->ike_sa->set_name(this->ike_sa, name);
+       }
        
        /* Precompute NAT-D hashes for incoming NAT notify comparison */
        ike_sa_id = request->get_ike_sa_id(request);
@@ -1077,6 +1095,7 @@ static void destroy(private_ike_sa_init_t *this)
  */
 ike_sa_init_t *ike_sa_init_create(ike_sa_t *ike_sa)
 {
+       static u_int unique_id = 0;
        private_ike_sa_init_t *this = malloc_thing(private_ike_sa_init_t);
 
        /* transaction interface functions */
@@ -1103,6 +1122,7 @@ ike_sa_init_t *ike_sa_init_create(ike_sa_t *ike_sa)
        this->connection = NULL;
        this->policy = NULL;
        this->proposal = NULL;
+       this->unique_id = ++unique_id;
        this->reqid = 0;
        this->randomizer = randomizer_create();
        this->nat_hasher = hasher_create(HASH_SHA1);
index d35d2c2..8f0b869 100644 (file)
@@ -376,7 +376,7 @@ static status_t switchto_new_sa(private_rekey_ike_sa_t* this, bool initiator)
        other_id = this->ike_sa->get_other_id(this->ike_sa);
        my_host = this->ike_sa->get_my_host(this->ike_sa);
        other_host = this->ike_sa->get_other_host(this->ike_sa);
-       name = this->connection->get_name(this->connection);
+       name = this->ike_sa->get_name(this->ike_sa);
        
        this->new_sa->set_my_id(this->new_sa, my_id->clone(my_id));
        this->new_sa->set_other_id(this->new_sa, other_id->clone(other_id));
index 796cd04..c74cf8f 100644 (file)
@@ -50,7 +50,8 @@
 #define KERNEL_AH 51
 
 /** default priority of installed policies */
-#define SPD_PRIORITY 1024
+#define PRIO_LOW 3000
+#define PRIO_HIGH 2000
 
 #define BUFFER_SIZE 1024
 
@@ -979,7 +980,7 @@ static status_t add_policy(private_kernel_interface_t *this,
                                                   traffic_selector_t *src_ts,
                                                   traffic_selector_t *dst_ts,
                                                   policy_dir_t direction, protocol_id_t protocol,
-                                                  u_int32_t reqid, bool update)
+                                                  u_int32_t reqid, bool high_prio, bool update)
 {
        iterator_t *iterator;
        kernel_policy_t *current, *policy;
@@ -1011,6 +1012,14 @@ static status_t add_policy(private_kernel_interface_t *this,
                                current->refcount++;
                                this->logger->log(this->logger, CONTROL|LEVEL1, 
                                                                  "policy already exists, increasing refcount");
+                               if (!high_prio)
+                               {
+                                       /* if added policy is for a ROUTED child_sa, do not
+                                        * overwrite existing INSTALLED policy */
+                                       iterator->destroy(iterator);
+                                       pthread_mutex_unlock(&this->pol_mutex);
+                                       return SUCCESS;
+                               }
                        }
                        policy = current;
                        found = TRUE;
@@ -1035,7 +1044,11 @@ static status_t add_policy(private_kernel_interface_t *this,
        policy_info = (struct xfrm_userpolicy_info*)NLMSG_DATA(hdr);
        policy_info->sel = policy->sel;
        policy_info->dir = policy->direction;
-       policy_info->priority = SPD_PRIORITY;
+       /* calculate priority based on source selector size, small size = high prio */
+       policy_info->priority = high_prio ? PRIO_HIGH : PRIO_LOW;
+       policy_info->priority -= policy->sel.prefixlen_s * 10;
+       policy_info->priority -= policy->sel.proto ? 2 : 0;
+       policy_info->priority -= policy->sel.sport_mask ? 1 : 0;
        policy_info->action = XFRM_POLICY_ALLOW;
        policy_info->share = XFRM_SHARE_ANY;
        pthread_mutex_unlock(&this->pol_mutex);
@@ -1272,7 +1285,7 @@ kernel_interface_t *kernel_interface_create()
        this->public.update_sa = (status_t(*)(kernel_interface_t*,host_t*,u_int32_t,protocol_id_t,host_t*,host_t*,host_diff_t,host_diff_t))update_sa;
        this->public.query_sa = (status_t(*)(kernel_interface_t*,host_t*,u_int32_t,protocol_id_t,u_int32_t*))query_sa;
        this->public.del_sa = (status_t(*)(kernel_interface_t*,host_t*,u_int32_t,protocol_id_t))del_sa;
-       this->public.add_policy = (status_t(*)(kernel_interface_t*,host_t*,host_t*,traffic_selector_t*,traffic_selector_t*,policy_dir_t,protocol_id_t,u_int32_t,bool))add_policy;
+       this->public.add_policy = (status_t(*)(kernel_interface_t*,host_t*,host_t*,traffic_selector_t*,traffic_selector_t*,policy_dir_t,protocol_id_t,u_int32_t,bool,bool))add_policy;
        this->public.query_policy = (status_t(*)(kernel_interface_t*,traffic_selector_t*,traffic_selector_t*,policy_dir_t,u_int32_t*))query_policy;
        this->public.del_policy = (status_t(*)(kernel_interface_t*,traffic_selector_t*,traffic_selector_t*,policy_dir_t))del_policy;
        this->public.destroy = (void(*)(kernel_interface_t*)) destroy;
index bafb1a6..4370e82 100644 (file)
@@ -207,6 +207,7 @@ struct kernel_interface_t {
         * @param direction             direction of traffic, POLICY_IN, POLICY_OUT, POLICY_FWD
         * @param protocol              protocol to use to protect traffic (AH/ESP)
         * @param reqid                 uniqe ID of an SA to use to enforce policy
+        * @param high_prio             if TRUE, uses a higher priority than any with FALSE
         * @param update                update an existing policy, if TRUE
         * @return
         *                                              - SUCCESS
@@ -217,7 +218,7 @@ struct kernel_interface_t {
                                                        traffic_selector_t *src_ts,
                                                        traffic_selector_t *dst_ts,
                                                        policy_dir_t direction, protocol_id_t protocol,
-                                                       u_int32_t reqid, bool update);
+                                                       u_int32_t reqid, bool high_prio, bool update);
        
        /**
         * @brief Query the use time of a policy.
index b8bdd5a..3a39990 100755 (executable)
@@ -601,58 +601,10 @@ static void stroke_route(private_stroke_t *this, stroke_msg_t *msg, bool route)
  */
 static void stroke_terminate(private_stroke_t *this, stroke_msg_t *msg)
 {
-       linked_list_t *ike_sas;
-       iterator_t *iterator;
-       int instances = 0;
-       connection_t *conn;
-       
        pop_string(msg, &(msg->terminate.name));
        this->logger->log(this->logger, CONTROL, "received stroke: terminate \"%s\"", msg->terminate.name);
        
-       /* we have to do tricky tricks to give the most comprehensive output to the user.
-        * There are different cases:
-        * 1. Connection is available, but IKEv1:
-        *    => just ignore it, let pluto print it
-        * 2. Connection is not available, but instances of a deleted connection template:
-        *    => terminate them, and print their termination
-        * 3. Connection is not available, and and no instances are there:
-        *    => show error about bad connection name
-        * 4. An IKEv2 connection is available, and may contain instances:
-        *    => terminate and print, simple
-        */
-       conn = charon->connections->get_connection_by_name(charon->connections, msg->terminate.name);
-       if (conn == NULL || conn->is_ikev2(conn))
-       {
-               ike_sas = charon->ike_sa_manager->get_ike_sa_list_by_name(charon->ike_sa_manager, msg->terminate.name);
-               
-               iterator = ike_sas->create_iterator(ike_sas, TRUE);
-               while (iterator->has_next(iterator))
-               {
-                       ike_sa_id_t *ike_sa_id;
-                       iterator->current(iterator, (void**)&ike_sa_id);
-                       charon->ike_sa_manager->delete(charon->ike_sa_manager, ike_sa_id);
-                       ike_sa_id->destroy(ike_sa_id);
-                       instances++;
-               }
-               iterator->destroy(iterator);
-               ike_sas->destroy(ike_sas);
-               if (conn == NULL && instances == 0)
-               {
-                       this->stroke_logger->log(this->stroke_logger, CONTROL, 
-                                                                        "no connection named \"%s\"", 
-                                                                        msg->terminate.name);
-               }
-               else
-               {
-                       this->stroke_logger->log(this->stroke_logger, CONTROL, 
-                                                                        "terminated %d instances of \"%s\"", 
-                                                                        instances, msg->terminate.name);
-               }
-       }
-       if (conn)
-       {
-               conn->destroy(conn);
-       }
+       charon->ike_sa_manager->delete_by_name(charon->ike_sa_manager, msg->terminate.name);
 }
 
 /**