unit-tests: Keep track of installed IPsec SAs in mock kernel_ipsec_t implementation
authorTobias Brunner <tobias@strongswan.org>
Wed, 8 Mar 2017 14:45:41 +0000 (15:45 +0100)
committerTobias Brunner <tobias@strongswan.org>
Tue, 23 May 2017 16:46:49 +0000 (18:46 +0200)
src/libcharon/tests/utils/mock_ipsec.c
src/libcharon/tests/utils/mock_ipsec.h

index d57a26a..c11f5c9 100644 (file)
@@ -1,5 +1,5 @@
 /*
- * Copyright (C) 2016 Tobias Brunner
+ * Copyright (C) 2016-2017 Tobias Brunner
  * Copyright (C) 2008 Martin Willi
  * HSR Hochschule fuer Technik Rapperswil
  *
 
 #include "mock_ipsec.h"
 
+#include <daemon.h>
+#include <collections/hashtable.h>
+
+#include <assert.h>
+
 typedef struct private_kernel_ipsec_t private_kernel_ipsec_t;
 
 /**
@@ -32,13 +37,72 @@ struct private_kernel_ipsec_t {
         * Allocated SPI
         */
        refcount_t spi;
+
+       /**
+        * Installed SAs
+        */
+       hashtable_t *sas;
 };
 
+/**
+ * Global instance
+ */
+static private_kernel_ipsec_t *instance;
+
+/**
+ * Data about installed IPsec SAs
+ */
+typedef struct {
+       /**
+        * SPI of the SA
+        */
+       uint32_t spi;
+
+       /**
+        * Associated IKE_SA
+        */
+       ike_sa_t *ike_sa;
+
+       /**
+        * TRUE if this was an allocated SPI
+        */
+       bool alloc;
+
+} entry_t;
+
+/**
+ * Hash an IPsec SA entry
+ */
+static u_int entry_hash(const void *key)
+{
+       entry_t *entry = (entry_t*)key;
+       return chunk_hash_inc(chunk_from_thing(entry->spi),
+                                                 chunk_hash(chunk_from_thing(entry->ike_sa)));
+}
+
+/**
+ * Compare an IPsec SA entry
+ */
+static bool entry_equals(const void *key, const void *other_key)
+{
+       entry_t *a = (entry_t*)key, *b = (entry_t*)other_key;
+       return a->spi == b->spi && a->ike_sa == b->ike_sa;
+}
+
 METHOD(kernel_ipsec_t, get_spi, status_t,
        private_kernel_ipsec_t *this, host_t *src, host_t *dst, uint8_t protocol,
        uint32_t *spi)
 {
+       entry_t *entry;
+
        *spi = (uint32_t)ref_get(&this->spi);
+       INIT(entry,
+               .spi = *spi,
+               .ike_sa = charon->bus->get_sa(charon->bus),
+               .alloc = TRUE,
+       );
+       entry = this->sas->put(this->sas, entry, entry);
+       assert(!entry);
        return SUCCESS;
 }
 
@@ -52,6 +116,23 @@ METHOD(kernel_ipsec_t, add_sa, status_t,
        private_kernel_ipsec_t *this, kernel_ipsec_sa_id_t *id,
        kernel_ipsec_add_sa_t *data)
 {
+       entry_t *entry;
+
+       INIT(entry,
+               .spi = id->spi,
+               .ike_sa = charon->bus->get_sa(charon->bus),
+       );
+       if (data->inbound)
+       {
+               entry = this->sas->put(this->sas, entry, entry);
+               assert(entry && entry->alloc);
+               free(entry);
+       }
+       else
+       {
+               entry = this->sas->put(this->sas, entry, entry);
+               assert(!entry);
+       }
        return SUCCESS;
 }
 
@@ -74,6 +155,14 @@ METHOD(kernel_ipsec_t, del_sa, status_t,
        private_kernel_ipsec_t *this, kernel_ipsec_sa_id_t *id,
        kernel_ipsec_del_sa_t *data)
 {
+       entry_t *entry, lookup = {
+               .spi = id->spi,
+               .ike_sa = charon->bus->get_sa(charon->bus),
+       };
+
+       entry = this->sas->remove(this->sas, &lookup);
+       assert(entry);
+       free(entry);
        return SUCCESS;
 }
 
@@ -99,6 +188,13 @@ METHOD(kernel_ipsec_t, del_policy, status_t,
        return SUCCESS;
 }
 
+METHOD(kernel_ipsec_t, destroy, void,
+       private_kernel_ipsec_t *this)
+{
+       this->sas->destroy(this->sas);
+       free(this);
+}
+
 /*
  * Described in header
  */
@@ -121,8 +217,37 @@ kernel_ipsec_t *mock_ipsec_create()
                        .flush_policies = (void*)return_failed,
                        .bypass_socket = (void*)return_true,
                        .enable_udp_decap = (void*)return_true,
-                       .destroy = (void*)free,
+                       .destroy = _destroy,
                },
+               .sas = hashtable_create(entry_hash, entry_equals, 8),
        );
+
+       instance = this;
+
        return &this->public;
 }
+
+/**
+ * Filter SAs
+ */
+static bool filter_sas(void *data, entry_t **entry, ike_sa_t **ike_sa,
+                                          void *unused, uint32_t *spi)
+{
+       if ((*entry)->alloc)
+       {
+               return FALSE;
+       }
+       *ike_sa = (*entry)->ike_sa;
+       *spi = (*entry)->spi;
+       return TRUE;
+}
+
+/*
+ * Described in header
+ */
+enumerator_t *mock_ipsec_create_sa_enumerator()
+{
+       return enumerator_create_filter(
+                                                       instance->sas->create_enumerator(instance->sas),
+                                                       (void*)filter_sas, NULL, NULL);
+}
index cbf2152..95038a5 100644 (file)
@@ -1,5 +1,5 @@
 /*
- * Copyright (C) 2016 Tobias Brunner
+ * Copyright (C) 2016-2017 Tobias Brunner
  * HSR Hochschule fuer Technik Rapperswil
  *
  * This program is free software; you can redistribute it and/or modify it
@@ -15,7 +15,7 @@
 
 /**
  * kernel_ipsec_t implementation used for exchange unit tests.  Currently
- * returns sequential SPIs, all other methods are noops.
+ * returns sequential SPIs, and keeps track of installed SAs.
  *
  * @defgroup mock_ipsec mock_ipsec
  * @{ @ingroup test_utils_c
  */
 kernel_ipsec_t *mock_ipsec_create();
 
+/**
+ * Enumerate the installed SAs
+ *
+ * @return             enumerator over (ike_sa_t*, uint32_t)
+ */
+enumerator_t *mock_ipsec_create_sa_enumerator();
+
 #endif /** MOCK_IPSEC_H_ @}*/