Diff for /embedaddon/strongswan/src/libcharon/sa/ike_sa_manager.c between versions 1.1.1.1 and 1.1.1.2

version 1.1.1.1, 2020/06/03 09:46:45 version 1.1.1.2, 2021/03/17 00:20:09
Line 2 Line 2
  * Copyright (C) 2005-2011 Martin Willi   * Copyright (C) 2005-2011 Martin Willi
  * Copyright (C) 2011 revosec AG   * Copyright (C) 2011 revosec AG
  *   *
 * Copyright (C) 2008-2018 Tobias Brunner * Copyright (C) 2008-2021 Tobias Brunner
  * Copyright (C) 2005 Jan Hutter   * Copyright (C) 2005 Jan Hutter
  * HSR Hochschule fuer Technik Rapperswil   * HSR Hochschule fuer Technik Rapperswil
  *   *
Line 29 Line 29
 #include <threading/condvar.h>  #include <threading/condvar.h>
 #include <threading/mutex.h>  #include <threading/mutex.h>
 #include <threading/rwlock.h>  #include <threading/rwlock.h>
   #include <collections/array.h>
 #include <collections/linked_list.h>  #include <collections/linked_list.h>
 #include <crypto/hashers/hasher.h>  #include <crypto/hashers/hasher.h>
 #include <processing/jobs/delete_ike_sa_job.h>  #include <processing/jobs/delete_ike_sa_job.h>
Line 391  struct private_ike_sa_manager_t { Line 392  struct private_ike_sa_manager_t {
         table_item_t **init_hashes_table;          table_item_t **init_hashes_table;
   
         /**          /**
          * Segments of the "hashes" hash table.         * Segments of the "hashes" hash table.
          */           */
         segment_t *init_hashes_segments;          segment_t *init_hashes_segments;
   
         /**          /**
            * Configs for which an SA is currently being checked out.
            */
           array_t *config_checkouts;
   
           /**
            * Mutex to protect access to configs.
            */
           mutex_t *config_mutex;
   
           /**
            * Condvar to indicate changes in checkout configs.
            */
           condvar_t *config_condvar;
   
           /**
          * RNG to get random SPIs for our side           * RNG to get random SPIs for our side
          */           */
         rng_t *rng;          rng_t *rng;
Line 871  static void remove_half_open(private_ike_sa_manager_t  Line 887  static void remove_half_open(private_ike_sa_manager_t 
         lock->unlock(lock);          lock->unlock(lock);
 }  }
   
   /**
    * Create an entry and put it into the hash table.
    * Note: The caller has to unlock the segment.
    */
   static u_int create_and_put_entry(private_ike_sa_manager_t *this,
                                                                     ike_sa_t *ike_sa, entry_t **entry)
   {
           ike_sa_id_t *ike_sa_id = ike_sa->get_id(ike_sa);
           host_t *other = ike_sa->get_other_host(ike_sa);
   
           *entry = entry_create();
           (*entry)->ike_sa_id = ike_sa_id->clone(ike_sa_id);
           (*entry)->ike_sa = ike_sa;
   
           if (ike_sa->get_state(ike_sa) == IKE_CONNECTING)
           {
                   (*entry)->half_open = TRUE;
                   (*entry)->other = other->clone(other);
                   put_half_open(this, *entry);
           }
           return put_entry(this, *entry);
   }
   
 CALLBACK(id_matches, bool,  CALLBACK(id_matches, bool,
         ike_sa_id_t *a, va_list args)          ike_sa_id_t *a, va_list args)
 {  {
Line 1202  METHOD(ike_sa_manager_t, checkout, ike_sa_t*, Line 1241  METHOD(ike_sa_manager_t, checkout, ike_sa_t*,
         return ike_sa;          return ike_sa;
 }  }
   
METHOD(ike_sa_manager_t, checkout_new, ike_sa_t*,METHOD(ike_sa_manager_t, create_new, ike_sa_t*,
         private_ike_sa_manager_t* this, ike_version_t version, bool initiator)          private_ike_sa_manager_t* this, ike_version_t version, bool initiator)
 {  {
         ike_sa_id_t *ike_sa_id;          ike_sa_id_t *ike_sa_id;
Line 1238  METHOD(ike_sa_manager_t, checkout_new, ike_sa_t*, Line 1277  METHOD(ike_sa_manager_t, checkout_new, ike_sa_t*,
         return ike_sa;          return ike_sa;
 }  }
   
   METHOD(ike_sa_manager_t, checkout_new, void,
           private_ike_sa_manager_t *this, ike_sa_t *ike_sa)
   {
           u_int segment;
           entry_t *entry;
   
           segment = create_and_put_entry(this, ike_sa, &entry);
           entry->checked_out = thread_current();
           unlock_single_segment(this, segment);
   }
   
 /**  /**
  * Get the message ID or message hash to detect early retransmissions   * Get the message ID or message hash to detect early retransmissions
  */   */
Line 1422  out: Line 1472  out:
         return ike_sa;          return ike_sa;
 }  }
   
   /**
    * Data used to track checkouts by config.
    */
   typedef struct {
           /** The peer config for which an IKE_SA is being checked out. */
           peer_cfg_t *cfg;
           /** Number of threads checking out SAs for the same config. */
           int threads;
           /** A thread is currently creating/finding an SA for this config. */
           bool working;
   } config_entry_t;
   
 METHOD(ike_sa_manager_t, checkout_by_config, ike_sa_t*,  METHOD(ike_sa_manager_t, checkout_by_config, ike_sa_t*,
         private_ike_sa_manager_t *this, peer_cfg_t *peer_cfg)          private_ike_sa_manager_t *this, peer_cfg_t *peer_cfg)
 {  {
Line 1430  METHOD(ike_sa_manager_t, checkout_by_config, ike_sa_t* Line 1492  METHOD(ike_sa_manager_t, checkout_by_config, ike_sa_t*
         ike_sa_t *ike_sa = NULL;          ike_sa_t *ike_sa = NULL;
         peer_cfg_t *current_peer;          peer_cfg_t *current_peer;
         ike_cfg_t *current_ike;          ike_cfg_t *current_ike;
           config_entry_t *config_entry, *found = NULL;
         u_int segment;          u_int segment;
           int i;
   
         DBG2(DBG_MGR, "checkout IKE_SA by config");          DBG2(DBG_MGR, "checkout IKE_SA by config");
   
         if (!this->reuse_ikesa && peer_cfg->get_ike_version(peer_cfg) != IKEV1)          if (!this->reuse_ikesa && peer_cfg->get_ike_version(peer_cfg) != IKEV1)
         {       /* IKE_SA reuse disabled by config (not possible for IKEv1) */          {       /* IKE_SA reuse disabled by config (not possible for IKEv1) */
                ike_sa = checkout_new(this, peer_cfg->get_ike_version(peer_cfg), TRUE);                ike_sa = create_new(this, peer_cfg->get_ike_version(peer_cfg), TRUE);
                 if (ike_sa)
                 {
                         ike_sa->set_peer_cfg(ike_sa, peer_cfg);
                         checkout_new(this, ike_sa);
                 }
                 charon->bus->set_sa(charon->bus, ike_sa);                  charon->bus->set_sa(charon->bus, ike_sa);
                 goto out;                  goto out;
         }          }
   
           this->config_mutex->lock(this->config_mutex);
           for (i = 0; i < array_count(this->config_checkouts); i++)
           {
                   array_get(this->config_checkouts, i, &config_entry);
                   if (config_entry->cfg->equals(config_entry->cfg, peer_cfg))
                   {
                           current_ike = config_entry->cfg->get_ike_cfg(config_entry->cfg);
                           if (current_ike->equals(current_ike,
                                                                           peer_cfg->get_ike_cfg(peer_cfg)))
                           {
                                   found = config_entry;
                                   break;
                           }
                   }
           }
           if (!found)
           {
                   INIT(found,
                           .cfg = peer_cfg->get_ref(peer_cfg),
                   );
                   array_insert_create(&this->config_checkouts, ARRAY_TAIL, found);
           }
           found->threads++;
           while (found->working)
           {
                   this->config_condvar->wait(this->config_condvar, this->config_mutex);
           }
           found->working = TRUE;
           this->config_mutex->unlock(this->config_mutex);
   
         enumerator = create_table_enumerator(this);          enumerator = create_table_enumerator(this);
         while (enumerator->enumerate(enumerator, &entry, &segment))          while (enumerator->enumerate(enumerator, &entry, &segment))
         {          {
Line 1463  METHOD(ike_sa_manager_t, checkout_by_config, ike_sa_t* Line 1562  METHOD(ike_sa_manager_t, checkout_by_config, ike_sa_t*
                         {                          {
                                 entry->checked_out = thread_current();                                  entry->checked_out = thread_current();
                                 ike_sa = entry->ike_sa;                                  ike_sa = entry->ike_sa;
                                DBG2(DBG_MGR, "found existing IKE_SA %u with a '%s' config",                                DBG2(DBG_MGR, "found existing IKE_SA %u with config '%s'",
                                                 ike_sa->get_unique_id(ike_sa),                                                  ike_sa->get_unique_id(ike_sa),
                                                 current_peer->get_name(current_peer));                                                  current_peer->get_name(current_peer));
                                 break;                                  break;
Line 1475  METHOD(ike_sa_manager_t, checkout_by_config, ike_sa_t* Line 1574  METHOD(ike_sa_manager_t, checkout_by_config, ike_sa_t*
         enumerator->destroy(enumerator);          enumerator->destroy(enumerator);
   
         if (!ike_sa)          if (!ike_sa)
        {       /* no IKE_SA using such a config, hand out a new */        {
                ike_sa = checkout_new(this, peer_cfg->get_ike_version(peer_cfg), TRUE);                ike_sa = create_new(this, peer_cfg->get_ike_version(peer_cfg), TRUE);
                 if (ike_sa)
                 {
                         ike_sa->set_peer_cfg(ike_sa, peer_cfg);
                         checkout_new(this, ike_sa);
                 }
         }          }
         charon->bus->set_sa(charon->bus, ike_sa);          charon->bus->set_sa(charon->bus, ike_sa);
   
           this->config_mutex->lock(this->config_mutex);
           found->working = FALSE;
           found->threads--;
           if (!found->threads)
           {
                   for (i = 0; i < array_count(this->config_checkouts); i++)
                   {
                           array_get(this->config_checkouts, i, &config_entry);
                           if (config_entry == found)
                           {
                                   array_remove(this->config_checkouts, i, NULL);
                                   found->cfg->destroy(found->cfg);
                                   free(found);
                                   break;
                           }
                   }
           }
           this->config_condvar->signal(this->config_condvar);
           this->config_mutex->unlock(this->config_mutex);
   
 out:  out:
         if (!ike_sa)          if (!ike_sa)
         {          {
Line 1784  METHOD(ike_sa_manager_t, checkin, void, Line 1908  METHOD(ike_sa_manager_t, checkin, void,
         }          }
         else          else
         {          {
                entry = entry_create();                segment = create_and_put_entry(this, ike_sa, &entry);
                entry->ike_sa_id = ike_sa_id->clone(ike_sa_id); 
                entry->ike_sa = ike_sa; 
                if (ike_sa->get_state(ike_sa) == IKE_CONNECTING) 
                { 
                        entry->half_open = TRUE; 
                        entry->other = other->clone(other); 
                        put_half_open(this, entry); 
                } 
                segment = put_entry(this, entry); 
         }          }
         DBG2(DBG_MGR, "checkin of IKE_SA successful");          DBG2(DBG_MGR, "checkin of IKE_SA successful");
   
Line 2326  METHOD(ike_sa_manager_t, destroy, void, Line 2441  METHOD(ike_sa_manager_t, destroy, void,
         free(this->connected_peers_segments);          free(this->connected_peers_segments);
         free(this->init_hashes_segments);          free(this->init_hashes_segments);
   
           array_destroy(this->config_checkouts);
           this->config_mutex->destroy(this->config_mutex);
           this->config_condvar->destroy(this->config_condvar);
   
         this->spi_lock->destroy(this->spi_lock);          this->spi_lock->destroy(this->spi_lock);
         free(this);          free(this);
 }  }
Line 2359  ike_sa_manager_t *ike_sa_manager_create() Line 2478  ike_sa_manager_t *ike_sa_manager_create()
   
         INIT(this,          INIT(this,
                 .public = {                  .public = {
                        .checkout = _checkout,                        .create_new = _create_new,
                         .checkout_new = _checkout_new,                          .checkout_new = _checkout_new,
                           .checkout = _checkout,
                         .checkout_by_message = _checkout_by_message,                          .checkout_by_message = _checkout_by_message,
                         .checkout_by_config = _checkout_by_config,                          .checkout_by_config = _checkout_by_config,
                         .checkout_by_id = _checkout_by_id,                          .checkout_by_id = _checkout_by_id,
Line 2448  ike_sa_manager_t *ike_sa_manager_create() Line 2568  ike_sa_manager_t *ike_sa_manager_create()
         {          {
                 this->init_hashes_segments[i].mutex = mutex_create(MUTEX_TYPE_RECURSIVE);                  this->init_hashes_segments[i].mutex = mutex_create(MUTEX_TYPE_RECURSIVE);
         }          }
   
           this->config_mutex = mutex_create(MUTEX_TYPE_DEFAULT);
           this->config_condvar = condvar_create(CONDVAR_TYPE_DEFAULT);
   
         this->reuse_ikesa = lib->settings->get_bool(lib->settings,          this->reuse_ikesa = lib->settings->get_bool(lib->settings,
                                                                                         "%s.reuse_ikesa", TRUE, lib->ns);                                                                                          "%s.reuse_ikesa", TRUE, lib->ns);

Removed from v.1.1.1.1  
changed lines
  Added in v.1.1.1.2


FreeBSD-CVSweb <freebsd-cvsweb@FreeBSD.org>