workaround for peers rekeying at the same time
authorMartin Willi <martin@strongswan.org>
Mon, 12 Jun 2006 07:33:20 +0000 (07:33 -0000)
committerMartin Willi <martin@strongswan.org>
Mon, 12 Jun 2006 07:33:20 +0000 (07:33 -0000)
loading lifetime policies from ipsec.conf

14 files changed:
src/charon/config/connections/connection.c
src/charon/config/policies/policy.c
src/charon/config/policies/policy.h
src/charon/sa/child_sa.c
src/charon/sa/states/create_child_sa_requested.c
src/charon/sa/states/delete_child_sa_requested.c
src/charon/sa/states/ike_sa_established.c
src/charon/sa/states/responder_init.c
src/charon/threads/stroke_interface.c
src/libstrongswan/crypto/diffie_hellman.c
src/libstrongswan/crypto/diffie_hellman.h
src/starter/starterstroke.c
src/stroke/stroke.c
src/stroke/stroke.h

index 9893c8a..9a90f76 100644 (file)
@@ -213,7 +213,7 @@ static diffie_hellman_group_t get_dh_group(private_connection_t *this)
                }
        }
        iterator->destroy(iterator);
-       return MODP_UNDEFINED;
+       return MODP_NONE;
 }
 
 /**
index 5f6706b..22c63c5 100644 (file)
@@ -22,6 +22,7 @@
 
 #include <time.h>
 #include <string.h>
+#include <unistd.h>
 
 #include "policy.h"
 
@@ -80,7 +81,23 @@ struct private_policy_t {
         * list for traffic selectors for others site
         */
        linked_list_t *other_ts;
-
+       
+       /**
+        * Time before an SA gets invalid
+        */
+       u_int32_t soft_lifetime;
+       
+       /**
+        * Time before an SA gets rekeyed
+        */
+       u_int32_t hard_lifetime;
+       
+       /**
+        * Time, which specifies the range of a random value
+        * substracted from soft_lifetime.
+        */
+       u_int32_t jitter;
+       
        /**
         * select_traffic_selectors for both
         */
@@ -313,18 +330,18 @@ static void add_proposal(private_policy_t *this, proposal_t *proposal)
 /**
  * Implementation of policy_t.get_soft_lifetime
  */
-static u_int32_t get_soft_lifetime(policy_t *this)
+static u_int32_t get_soft_lifetime(private_policy_t *this)
 {
        srandom(time(NULL)+getpid());
-       return 5 + (random() % 10);
+       return this->soft_lifetime - (random() % this->jitter);
 }
 
 /**
  * Implementation of policy_t.get_hard_lifetime
  */
-static u_int32_t get_hard_lifetime(policy_t *this)
+static u_int32_t get_hard_lifetime(private_policy_t *this)
 {
-       return 20;
+       return this->hard_lifetime;
 }
 
 /**
@@ -334,7 +351,9 @@ static policy_t *clone(private_policy_t *this)
 {
        private_policy_t *clone = (private_policy_t*)policy_create(this->name,
                                                                                                                           this->my_id->clone(this->my_id),
-                                                                                                                          this->other_id->clone(this->other_id));
+                                                                                                                          this->other_id->clone(this->other_id),
+                                                                                                                          this->hard_lifetime, this->soft_lifetime,
+                                                                                                                          this->jitter);
        iterator_t *iterator;
        proposal_t *proposal;
        traffic_selector_t *ts;
@@ -434,7 +453,9 @@ static status_t destroy(private_policy_t *this)
 /*
  * Described in header-file
  */
-policy_t *policy_create(char *name, identification_t *my_id, identification_t *other_id)
+policy_t *policy_create(char *name, identification_t *my_id, identification_t *other_id,
+                                               u_int32_t hard_lifetime, u_int32_t soft_lifetime, 
+                                               u_int32_t jitter)
 {
        private_policy_t *this = malloc_thing(private_policy_t);
 
@@ -465,6 +486,9 @@ policy_t *policy_create(char *name, identification_t *my_id, identification_t *o
        this->name = strdup(name);
        this->my_id = my_id;
        this->other_id = other_id;
+       this->hard_lifetime = hard_lifetime;
+       this->soft_lifetime = soft_lifetime;
+       this->jitter = jitter;
        
        /* initialize private members*/
        this->my_ca = NULL;
index 44ed192..089d751 100644 (file)
@@ -277,14 +277,23 @@ struct policy_t {
  * @brief Create a configuration object for IKE_AUTH and later.
  * 
  * name-string gets cloned, ID's not.
+ * Lifetimes are in seconds. To prevent to peers to start rekeying at the
+ * same time, a jitter may be specified. Rekeying of an SA starts at
+ * (soft_lifetime - random(0, jitter)). After a successful rekeying, 
+ * the hard_lifetime limit counter is reset. You should specify
+ * hard_lifetime > soft_lifetime > jitter.
  * 
  * @param name                         name of the policy
  * @param my_id                        identification_t for ourselves
  * @param other_id                     identification_t for the remote guy
+ * @param hard_lifetime                lifetime before deleting an SA
+ * @param soft_lifetime                lifetime before rekeying an SA
+ * @param jitter                       range of randomization time
  * @return                                     policy_t object
  * 
  * @ingroup config
  */
-policy_t *policy_create(char *name, identification_t *my_id, identification_t *other_id);
+policy_t *policy_create(char *name, identification_t *my_id, identification_t *other_id,
+                                               u_int32_t hard_lifetime, u_int32_t soft_lifetime, u_int32_t jitter);
 
 #endif /* POLICY_H_ */
index e1dff27..2b2b6a7 100644 (file)
@@ -83,6 +83,11 @@ struct private_child_sa_t {
        u_int32_t reqid;
        
        /**
+        * time, on which SA was installed
+        */
+       time_t install_time;
+       
+       /**
         * Lifetime before rekeying
         */
        u_int32_t soft_lifetime;
@@ -239,6 +244,8 @@ static status_t install(private_child_sa_t *this, proposal_t *proposal, prf_plus
                                                                                                mine ? 0 : this->soft_lifetime,
                                                                                                this->hard_lifetime,
                                                                                                enc_algo, int_algo, prf_plus, mine);
+       
+       this->install_time = time(NULL);
 
        return status;
 }
@@ -406,11 +413,12 @@ static void log_status(private_child_sa_t *this, logger_t *logger, char* name)
        {
                logger = this->logger;
        }
-       logger->log(logger, CONTROL|LEVEL1, "  \"%s\":   protected with %s (0x%x/0x%x), reqid %d:",
+       logger->log(logger, CONTROL|LEVEL1, "  \"%s\":   protected with %s (0x%x/0x%x), reqid %d, rekeying in %ds:",
                                name,
                                this->protocol == PROTO_ESP ? "ESP" : "AH",
                                htonl(this->me.spi), htonl(this->other.spi),
-                               this->reqid);
+                               this->reqid, 
+                               this->soft_lifetime - (time(NULL) - this->install_time));
        iterator = this->policies->create_iterator(this->policies, TRUE);
        while (iterator->has_next(iterator))
        {
index b9bf280..ebd9469 100644 (file)
@@ -223,7 +223,15 @@ static status_t process_message(private_create_child_sa_requested_t *this, messa
        if (response->get_request(response))
        {
                this->logger->log(this->logger, ERROR | LEVEL1, "CREATE_CHILD_SA requests not allowed state create_child_sa_requested");
-               return FAILED;
+               /* TODO: our state implementation currently can not handle incoming requests cleanly here.
+                * If a request comes in before an outstanding reply, we can not handle it the correct way.
+                * Currently, we create a ESTABLISHED state and let it process the message... But we
+                * need changes in the whole state mechanism.
+                */
+               state_t *state = (state_t*)ike_sa_established_create(this->ike_sa);
+               state->process_message(state, response);
+               state->destroy(state);
+               return SUCCESS;
        }
        
        /* get signer for verification and crypter for decryption */
index 4d4ea5f..8cad93d 100644 (file)
@@ -80,7 +80,15 @@ static status_t process_message(private_delete_child_sa_requested_t *this, messa
        if (response->get_request(response))
        {
                this->logger->log(this->logger, ERROR | LEVEL1, "INFORMATIONAL requests not allowed state delete_child_sa_requested");
-               return FAILED;
+               /* TODO: our state implementation currently can not handle incoming requests cleanly here.
+                * If a request comes in before an outstanding reply, we can not handle it cleanly.
+                * Currently, we create a ESTABLISHED state and let it process the message... But we
+                * need changes in the whole state mechanism.
+                */
+               state_t *state = (state_t*)ike_sa_established_create(this->ike_sa);
+               state->process_message(state, response);
+               state->destroy(state);
+               return SUCCESS;
        }
        
        /* get signer for verification and crypter for decryption */
index 5841f74..66f0c10 100644 (file)
@@ -274,6 +274,17 @@ static status_t process_create_child_sa(private_ike_sa_established_t *this, mess
                                nonce_request = (nonce_payload_t*)payload;
                                break;  
                        }
+                       case KEY_EXCHANGE:
+                       {
+                               /* we currently do not support a diffie hellman exchange
+                                * for CHILD_SAs. */
+                               u_int16_t no_group[1];
+                               no_group[0] = htons(MODP_NONE);
+                               chunk_t no_group_chunk = chunk_from_buf(no_group);
+                               this->ike_sa->send_notify(this->ike_sa, CREATE_CHILD_SA, INVALID_KE_PAYLOAD, no_group_chunk);
+                               payloads->destroy(payloads);
+                               return FAILED;
+                       }
                        case NOTIFY:
                        {
                                notify = (notify_payload_t*)payload;
index 2923bbb..07fcaab 100644 (file)
@@ -369,7 +369,7 @@ static status_t build_ke_payload(private_responder_init_t *this,ke_payload_t *ke
        this->logger->log(this->logger, CONTROL | LEVEL2, "Process received KE payload");
        group = ke_request->get_dh_group_number(ke_request);
                                
-       if (group == MODP_UNDEFINED)
+       if (group == MODP_NONE)
        {
                this->logger->log(this->logger, AUDIT, "No diffie hellman group to select. Deleting IKE_SA");
                return DESTROY_ME;
@@ -560,7 +560,7 @@ responder_init_t *responder_init_create(protected_ike_sa_t *ike_sa)
        this->logger = logger_manager->get_logger(logger_manager, IKE_SA);
        this->sent_nonce = CHUNK_INITIALIZER;
        this->received_nonce = CHUNK_INITIALIZER;
-       this->dh_group_number = MODP_UNDEFINED;
+       this->dh_group_number = MODP_NONE;
        this->diffie_hellman = NULL;
        this->proposal = NULL;
 
index b2d49c9..2ca9a0a 100755 (executable)
@@ -332,7 +332,10 @@ static void stroke_add_conn(private_stroke_t *this, stroke_msg_t *msg)
                                          other_host->get_address(other_host),
                                          other_id->get_string(other_id));
        
-       policy = policy_create(msg->add_conn.name, my_id, other_id);
+       policy = policy_create(msg->add_conn.name, my_id, other_id,
+                                                  msg->add_conn.rekey.ipsec_lifetime,
+                                                  msg->add_conn.rekey.ipsec_lifetime - msg->add_conn.rekey.margin,
+                                                  msg->add_conn.rekey.margin * msg->add_conn.rekey.fuzz / 100);
        proposal = proposal_create(PROTO_ESP);
        proposal->add_algorithm(proposal, ENCRYPTION_ALGORITHM, ENCR_AES_CBC, 128);
        proposal->add_algorithm(proposal, ENCRYPTION_ALGORITHM, ENCR_AES_CBC, 256);
index 1e3dcc7..0a3eef3 100644 (file)
@@ -34,7 +34,7 @@
  * String mappings for diffie_hellman_group_t.
  */
 mapping_t diffie_hellman_group_m[] = {
-       {MODP_UNDEFINED, "MODP_UNDEFINED"},
+       {MODP_NONE, "MODP_NONE"},
        {MODP_768_BIT, "MODP_768_BIT"},
        {MODP_1024_BIT, "MODP_1024_BIT"},
        {MODP_1536_BIT, "MODP_1536_BIT"},
index 48a1655..4f9ba49 100644 (file)
@@ -38,7 +38,7 @@ typedef enum diffie_hellman_group_t diffie_hellman_group_t;
  * @ingroup transforms
  */
 enum diffie_hellman_group_t {
-       MODP_UNDEFINED = 1024,
+       MODP_NONE = 0,
        MODP_768_BIT = 1,
        MODP_1024_BIT = 2,
        MODP_1536_BIT = 5,
index 16d911f..b4f85b3 100644 (file)
@@ -125,6 +125,11 @@ int starter_stroke_add_conn(starter_conn_t *conn)
        msg.length = offsetof(stroke_msg_t, buffer);
        msg.add_conn.ikev2 = conn->keyexchange == KEY_EXCHANGE_IKEV2;
        msg.add_conn.name = push_string(&msg, connection_name(conn));
+       msg.add_conn.rekey.ipsec_lifetime = conn->sa_ipsec_life_seconds;
+       msg.add_conn.rekey.ike_lifetime = conn->sa_ike_life_seconds;
+       msg.add_conn.rekey.margin = conn->sa_rekey_margin;
+       msg.add_conn.rekey.tries = conn->sa_keying_tries;
+       msg.add_conn.rekey.fuzz = conn->sa_rekey_fuzz;
 
        starter_stroke_add_end(&msg, &msg.add_conn.me, &conn->right);
        starter_stroke_add_end(&msg, &msg.add_conn.other, &conn->left);
index 3e2c473..d535722 100644 (file)
@@ -28,8 +28,6 @@
 
 #include "stroke.h"
 
-#define streq(a, b) (strcmp((a), (b)) == 0) /* clearer shorthand */
-
 static char* push_string(stroke_msg_t *msg, char *string)
 {
        u_int string_start = msg->length;
@@ -103,6 +101,12 @@ static int add_connection(char *name,
        msg.add_conn.name = push_string(&msg, name);
        msg.add_conn.ikev2 = 1;
        
+       msg.add_conn.rekey.ipsec_lifetime = 0;
+       msg.add_conn.rekey.ike_lifetime = 0;
+       msg.add_conn.rekey.margin = 0;
+       msg.add_conn.rekey.tries = 0;
+       msg.add_conn.rekey.fuzz = 0;
+       
        msg.add_conn.me.id = push_string(&msg, my_id);
        msg.add_conn.me.address = push_string(&msg, my_addr);
        msg.add_conn.me.subnet = push_string(&msg, my_net);
index fd7870f..e9bdedd 100644 (file)
@@ -86,6 +86,13 @@ struct stroke_msg_t {
                struct {
                        char *name;
                        bool ikev2;
+                       struct {
+                               time_t ipsec_lifetime;
+                               time_t ike_lifetime;
+                               time_t margin;
+                               unsigned long tries;
+                               unsigned long fuzz;
+                       } rekey;
                        stroke_end_t me, other;
                } add_conn;