ike: Only consider number of half-open SAs as responder when deciding whether COOKIEs...
authorTobias Brunner <tobias@strongswan.org>
Mon, 24 Aug 2015 10:18:16 +0000 (12:18 +0200)
committerTobias Brunner <tobias@strongswan.org>
Thu, 27 Aug 2015 09:18:51 +0000 (11:18 +0200)
src/libcharon/control/controller.c
src/libcharon/network/receiver.c
src/libcharon/plugins/stroke/stroke_list.c
src/libcharon/plugins/vici/vici_query.c
src/libcharon/sa/ike_sa_manager.c
src/libcharon/sa/ike_sa_manager.h

index 097f5ac..6dd54b4 100644 (file)
@@ -381,7 +381,7 @@ METHOD(job_t, initiate_execute, job_requeue_t,
                u_int half_open, limit_half_open, limit_job_load;
 
                half_open = charon->ike_sa_manager->get_half_open_count(
-                                                                               charon->ike_sa_manager, NULL);
+                                                                               charon->ike_sa_manager, NULL, FALSE);
                limit_half_open = lib->settings->get_int(lib->settings,
                                                                                "%s.init_limit_half_open", 0, lib->ns);
                limit_job_load = lib->settings->get_int(lib->settings,
index 0762332..a2f2016 100644 (file)
@@ -322,16 +322,18 @@ static bool cookie_required(private_receiver_t *this,
  */
 static bool drop_ike_sa_init(private_receiver_t *this, message_t *message)
 {
-       u_int half_open;
+       u_int half_open, half_open_r;
        u_int32_t now;
 
        now = time_monotonic(NULL);
        half_open = charon->ike_sa_manager->get_half_open_count(
-                                                                               charon->ike_sa_manager, NULL);
+                                                                               charon->ike_sa_manager, NULL, FALSE);
+       half_open_r = charon->ike_sa_manager->get_half_open_count(
+                                                                               charon->ike_sa_manager, NULL, TRUE);
 
        /* check for cookies in IKEv2 */
        if (message->get_major_version(message) == IKEV2_MAJOR_VERSION &&
-               cookie_required(this, half_open, now) && !check_cookie(this, message))
+               cookie_required(this, half_open_r, now) && !check_cookie(this, message))
        {
                chunk_t cookie;
 
@@ -372,7 +374,7 @@ static bool drop_ike_sa_init(private_receiver_t *this, message_t *message)
        /* check if peer has too many IKE_SAs half open */
        if (this->block_threshold &&
                charon->ike_sa_manager->get_half_open_count(charon->ike_sa_manager,
-                               message->get_source(message)) >= this->block_threshold)
+                               message->get_source(message), TRUE) >= this->block_threshold)
        {
                DBG1(DBG_NET, "ignoring IKE_SA setup from %H, "
                         "peer too aggressive", message->get_source(message));
@@ -381,7 +383,7 @@ static bool drop_ike_sa_init(private_receiver_t *this, message_t *message)
 
        /* check if global half open IKE_SA limit reached */
        if (this->init_limit_half_open &&
-               half_open >= this->init_limit_half_open)
+           half_open >= this->init_limit_half_open)
        {
                DBG1(DBG_NET, "ignoring IKE_SA setup from %H, half open IKE_SA "
                         "count of %d exceeds limit of %d", message->get_source(message),
index 68b8232..c7e4c9c 100644 (file)
@@ -647,7 +647,7 @@ METHOD(stroke_list_t, status, void,
        enumerator->destroy(enumerator);
 
        half_open = charon->ike_sa_manager->get_half_open_count(
-                                                                                               charon->ike_sa_manager, NULL);
+                                                                               charon->ike_sa_manager, NULL, FALSE);
        fprintf(out, "Security Associations (%u up, %u connecting):\n",
                charon->ike_sa_manager->get_count(charon->ike_sa_manager) - half_open,
                half_open);
index e4d0d62..98d264f 100644 (file)
@@ -929,7 +929,7 @@ CALLBACK(stats, vici_message_t*,
                charon->ike_sa_manager->get_count(charon->ike_sa_manager));
        b->add_kv(b, "half-open", "%u",
                charon->ike_sa_manager->get_half_open_count(charon->ike_sa_manager,
-                                                                                                       NULL));
+                                                                                                       NULL, FALSE));
        b->end_section(b);
 
        b->begin_list(b, "plugins");
index 137920a..9f4496a 100644 (file)
@@ -206,6 +206,9 @@ struct half_open_t {
 
        /** the number of half-open IKE_SAs with that host */
        u_int count;
+
+       /** the number of half-open IKE_SAs we responded to with that host */
+       u_int count_responder;
 };
 
 /**
@@ -361,6 +364,11 @@ struct private_ike_sa_manager_t {
        refcount_t half_open_count;
 
        /**
+        * Total number of half-open IKE_SAs as responder.
+        */
+       refcount_t half_open_count_responder;
+
+       /**
         * Hash table with connected_peers_t objects.
         */
        table_item_t **connected_peers_table;
@@ -737,9 +745,11 @@ static void put_half_open(private_ike_sa_manager_t *this, entry_t *entry)
        table_item_t *item;
        u_int row, segment;
        rwlock_t *lock;
+       ike_sa_id_t *ike_id;
        half_open_t *half_open;
        chunk_t addr;
 
+       ike_id = entry->ike_sa_id;
        addr = entry->other->get_address(entry->other);
        row = chunk_hash(addr) & this->table_mask;
        segment = row & this->segment_mask;
@@ -752,7 +762,6 @@ static void put_half_open(private_ike_sa_manager_t *this, entry_t *entry)
 
                if (chunk_equals(addr, half_open->other))
                {
-                       half_open->count++;
                        break;
                }
                item = item->next;
@@ -762,7 +771,6 @@ static void put_half_open(private_ike_sa_manager_t *this, entry_t *entry)
        {
                INIT(half_open,
                        .other = chunk_clone(addr),
-                       .count = 1,
                );
                INIT(item,
                        .value = half_open,
@@ -770,8 +778,14 @@ static void put_half_open(private_ike_sa_manager_t *this, entry_t *entry)
                );
                this->half_open_table[row] = item;
        }
-       this->half_open_segments[segment].count++;
+       half_open->count++;
        ref_get(&this->half_open_count);
+       if (!ike_id->is_initiator(ike_id))
+       {
+               half_open->count_responder++;
+               ref_get(&this->half_open_count_responder);
+       }
+       this->half_open_segments[segment].count++;
        lock->unlock(lock);
 }
 
@@ -783,8 +797,10 @@ static void remove_half_open(private_ike_sa_manager_t *this, entry_t *entry)
        table_item_t *item, *prev = NULL;
        u_int row, segment;
        rwlock_t *lock;
+       ike_sa_id_t *ike_id;
        chunk_t addr;
 
+       ike_id = entry->ike_sa_id;
        addr = entry->other->get_address(entry->other);
        row = chunk_hash(addr) & this->table_mask;
        segment = row & this->segment_mask;
@@ -797,6 +813,12 @@ static void remove_half_open(private_ike_sa_manager_t *this, entry_t *entry)
 
                if (chunk_equals(addr, half_open->other))
                {
+                       if (!ike_id->is_initiator(ike_id))
+                       {
+                               half_open->count_responder--;
+                               ignore_result(ref_put(&this->half_open_count_responder));
+                       }
+                       ignore_result(ref_put(&this->half_open_count));
                        if (--half_open->count == 0)
                        {
                                if (prev)
@@ -811,7 +833,6 @@ static void remove_half_open(private_ike_sa_manager_t *this, entry_t *entry)
                                free(item);
                        }
                        this->half_open_segments[segment].count--;
-                       ignore_result(ref_put(&this->half_open_count));
                        break;
                }
                prev = item;
@@ -1945,7 +1966,7 @@ METHOD(ike_sa_manager_t, get_count, u_int,
 }
 
 METHOD(ike_sa_manager_t, get_half_open_count, u_int,
-       private_ike_sa_manager_t *this, host_t *ip)
+       private_ike_sa_manager_t *this, host_t *ip, bool responder_only)
 {
        table_item_t *item;
        u_int row, segment;
@@ -1967,7 +1988,8 @@ METHOD(ike_sa_manager_t, get_half_open_count, u_int,
 
                        if (chunk_equals(addr, half_open->other))
                        {
-                               count = half_open->count;
+                               count = responder_only ? half_open->count_responder
+                                                                          : half_open->count;
                                break;
                        }
                        item = item->next;
@@ -1976,7 +1998,8 @@ METHOD(ike_sa_manager_t, get_half_open_count, u_int,
        }
        else
        {
-               count = (u_int)ref_cur(&this->half_open_count);
+               count = responder_only ? (u_int)ref_cur(&this->half_open_count_responder)
+                                                          : (u_int)ref_cur(&this->half_open_count);
        }
        return count;
 }
index f259d8e..3ea928e 100644 (file)
@@ -216,14 +216,15 @@ struct ike_sa_manager_t {
         * To prevent the server from resource exhaustion, cookies and other
         * mechanisms are used. The number of half open IKE_SAs is a good
         * indicator to see if a peer is flooding the server.
-        * If a host is supplied, only the number of half open IKE_SAs initiated
-        * from this IP are counted.
-        * Only SAs for which we are the responder are counted.
+        * If a host is supplied, only the number of half open IKE_SAs with this IP
+        * are counted.
         *
         * @param ip                            NULL for all, IP for half open IKE_SAs with IP
+        * @param responder_only        TRUE to return only the number of responding SAs
         * @return                                      number of half open IKE_SAs
         */
-       u_int (*get_half_open_count) (ike_sa_manager_t *this, host_t *ip);
+       u_int (*get_half_open_count)(ike_sa_manager_t *this, host_t *ip,
+                                                                bool responder_only);
 
        /**
         * Delete all existing IKE_SAs and destroy them immediately.