using dpd actions to enforce connection state
authorMartin Willi <martin@strongswan.org>
Fri, 11 Apr 2008 08:14:48 +0000 (08:14 -0000)
committerMartin Willi <martin@strongswan.org>
Fri, 11 Apr 2008 08:14:48 +0000 (08:14 -0000)
dpd actions a per child-, not peer ike-sa

12 files changed:
src/charon/config/child_cfg.c
src/charon/config/child_cfg.h
src/charon/config/peer_cfg.c
src/charon/config/peer_cfg.h
src/charon/plugins/sql/sql_config.c
src/charon/plugins/stroke/stroke_config.c
src/charon/processing/jobs/rekey_ike_sa_job.c
src/charon/sa/ike_sa.c
src/charon/sa/ike_sa.h
src/charon/sa/tasks/child_delete.c
src/charon/sa/tasks/ike_delete.c
src/charon/sa/tasks/ike_reauth.c

index 9a22dcf..510d9a6 100644 (file)
@@ -28,6 +28,12 @@ ENUM(mode_names, MODE_TRANSPORT, MODE_BEET,
        "BEET",
 );
 
+ENUM(action_names, ACTION_NONE, ACTION_RESTART,
+       "ACTION_NONE",
+       "ACTION_ROUTE",
+       "ACTION_RESTART",
+);
+
 typedef struct private_child_cfg_t private_child_cfg_t;
 
 /**
@@ -81,6 +87,11 @@ struct private_child_cfg_t {
        mode_t mode;
        
        /**
+        * action to take on DPD/passive close
+        */
+       action_t action;
+       
+       /**
         * Time before an SA gets invalid
         */
        u_int32_t lifetime;
@@ -338,7 +349,7 @@ static u_int32_t get_lifetime(private_child_cfg_t *this, bool rekey)
 }
 
 /**
- * Implementation of child_cfg_t.get_name
+ * Implementation of child_cfg_t.get_mode
  */
 static mode_t get_mode(private_child_cfg_t *this)
 {
@@ -346,6 +357,14 @@ static mode_t get_mode(private_child_cfg_t *this)
 }
 
 /**
+ * Implementation of child_cfg_t.get_action
+ */
+static action_t get_action(private_child_cfg_t *this)
+{
+       return this->action;
+}
+
+/**
  * Implementation of child_cfg_t.get_dh_group.
  */
 static diffie_hellman_group_t get_dh_group(private_child_cfg_t *this)
@@ -398,11 +417,11 @@ static void destroy(private_child_cfg_t *this)
  */
 child_cfg_t *child_cfg_create(char *name, u_int32_t lifetime,
                                                          u_int32_t rekeytime, u_int32_t jitter,
-                                                         char *updown, bool hostaccess, mode_t mode)
+                                                         char *updown, bool hostaccess, mode_t mode,
+                                                         action_t action)
 {
        private_child_cfg_t *this = malloc_thing(private_child_cfg_t);
 
-       /* public functions */
        this->public.get_name = (char* (*) (child_cfg_t*))get_name;
        this->public.add_traffic_selector = (void (*)(child_cfg_t*,bool,traffic_selector_t*))add_traffic_selector;
        this->public.get_traffic_selectors = (linked_list_t*(*)(child_cfg_t*,bool,linked_list_t*,host_t*))get_traffic_selectors;
@@ -412,12 +431,12 @@ child_cfg_t *child_cfg_create(char *name, u_int32_t lifetime,
        this->public.get_updown = (char* (*) (child_cfg_t*))get_updown;
        this->public.get_hostaccess = (bool (*) (child_cfg_t*))get_hostaccess;
        this->public.get_mode = (mode_t (*) (child_cfg_t *))get_mode;
+       this->public.get_action = (action_t (*) (child_cfg_t *))get_action;
        this->public.get_lifetime = (u_int32_t (*) (child_cfg_t *,bool))get_lifetime;
        this->public.get_dh_group = (diffie_hellman_group_t(*)(child_cfg_t*)) get_dh_group;
        this->public.get_ref = (void (*) (child_cfg_t*))get_ref;
        this->public.destroy = (void (*) (child_cfg_t*))destroy;
        
-       /* apply init values */
        this->name = strdup(name);
        this->lifetime = lifetime;
        this->rekeytime = rekeytime;
@@ -425,8 +444,7 @@ child_cfg_t *child_cfg_create(char *name, u_int32_t lifetime,
        this->updown = updown ? strdup(updown) : NULL;
        this->hostaccess = hostaccess;
        this->mode = mode;
-       
-       /* initialize private members*/
+       this->action = action;
        this->refcount = 1;
        this->proposals = linked_list_create();
        this->my_ts = linked_list_create();
@@ -434,3 +452,4 @@ child_cfg_t *child_cfg_create(char *name, u_int32_t lifetime,
 
        return &this->public;
 }
+
index c7401d6..7c65e0a 100644 (file)
@@ -25,6 +25,7 @@
 #define CHILD_CFG_H_
 
 typedef enum mode_t mode_t;
+typedef enum action_t action_t;
 typedef struct child_cfg_t child_cfg_t;
 
 #include <library.h>
@@ -51,6 +52,23 @@ enum mode_t {
 extern enum_name_t *mode_names;
 
 /**
+ * Action to take when DPD detected/connection gets closed by peer.
+ */
+enum action_t {
+       /** No action */
+       ACTION_NONE,
+       /** Route config to reestablish on demand */
+       ACTION_ROUTE,
+       /** Restart config immediately */
+       ACTION_RESTART,
+};
+
+/**
+ * enum names for action_t.
+ */
+extern enum_name_t *action_names;
+
+/**
  * A child_cfg_t defines the config template for a CHILD_SA.
  *
  * After creation, proposals and traffic selectors may be added to the config.
@@ -170,11 +188,18 @@ struct child_cfg_t {
         * The mode is either tunnel, transport or BEET. The peer must agree
         * on the method, fallback is tunnel mode.
         * 
-        * @return                              lifetime in seconds
+        * @return                              ipsec mode
         */
        mode_t (*get_mode) (child_cfg_t *this);
        
        /**
+        * Action to take on DPD/passive close
+        *
+        * @return                              DPD/passive close action
+        */     
+       action_t (*get_action) (child_cfg_t *this);
+       
+       /**
         * Get the DH group to use for CHILD_SA setup.
         * 
         * @return                              dh group to use
@@ -218,10 +243,12 @@ struct child_cfg_t {
  * @param updown                       updown script to execute on up/down event
  * @param hostaccess           TRUE to allow access to the local host
  * @param mode                         mode to propose for CHILD_SA, transport, tunnel or BEET
+ * @param action                       DPD/passive close action
  * @return                                     child_cfg_t object
  */
 child_cfg_t *child_cfg_create(char *name, u_int32_t lifetime,
                                                          u_int32_t rekeytime, u_int32_t jitter,
-                                                         char *updown, bool hostaccess, mode_t mode);
+                                                         char *updown, bool hostaccess, mode_t mode,
+                                                         action_t action);
 
 #endif /* CHILD_CFG_H_ @} */
index f0804d9..85fa22a 100644 (file)
@@ -31,13 +31,6 @@ ENUM(cert_policy_names, CERT_ALWAYS_SEND, CERT_NEVER_SEND,
        "CERT_NEVER_SEND"
 );
 
-ENUM(dpd_action_names, DPD_NONE, DPD_RESTART,
-       "DPD_NONE",
-       "DPD_CLEAR",
-       "DPD_ROUTE",
-       "DPD_RESTART"
-);
-
 typedef struct private_peer_cfg_t private_peer_cfg_t;
 
 /**
@@ -141,14 +134,9 @@ struct private_peer_cfg_t {
        u_int32_t over_time;
        
        /**
-        * What to do with an SA when other peer seams to be dead?
-        */
-       bool dpd_delay;
-       
-       /**
-        * What to do with CHILDren when other peer seams to be dead?
+        * DPD check intervall
         */
-       bool dpd_action;
+       u_int32_t dpd;
        
        /**
         * virtual IP to use locally
@@ -380,19 +368,11 @@ static bool use_mobike(private_peer_cfg_t *this)
 }
 
 /**
- * Implements peer_cfg_t.get_dpd_delay
- */
-static u_int32_t get_dpd_delay(private_peer_cfg_t *this)
-{
-       return this->dpd_delay;
-}
-
-/**
- * Implements peer_cfg_t.get_dpd_action
+ * Implements peer_cfg_t.get_dpd
  */
-static dpd_action_t get_dpd_action(private_peer_cfg_t *this)
+static u_int32_t get_dpd(private_peer_cfg_t *this)
 {
-       return this->dpd_action;
+       return this->dpd;
 }
 
 /**
@@ -473,8 +453,7 @@ static bool equals(private_peer_cfg_t *this, private_peer_cfg_t *other)
                this->reauth_time == other->reauth_time &&
                this->jitter_time == other->jitter_time &&
                this->over_time == other->over_time &&
-               this->dpd_delay == other->dpd_delay &&
-               this->dpd_action == other->dpd_action &&
+               this->dpd == other->dpd &&
                (this->virtual_ip == other->virtual_ip ||
                 (this->virtual_ip && other->virtual_ip &&
                  this->virtual_ip->equals(this->virtual_ip, other->virtual_ip))) &&
@@ -531,8 +510,7 @@ peer_cfg_t *peer_cfg_create(char *name, u_int ike_version, ike_cfg_t *ike_cfg,
                                                        u_int32_t eap_vendor,
                                                        u_int32_t keyingtries, u_int32_t rekey_time,
                                                        u_int32_t reauth_time, u_int32_t jitter_time,
-                                                       u_int32_t over_time, bool mobike,
-                                                       u_int32_t dpd_delay, dpd_action_t dpd_action,
+                                                       u_int32_t over_time, bool mobike, u_int32_t dpd,
                                                        host_t *virtual_ip, char *pool,
                                                        bool mediation, peer_cfg_t *mediated_by,
                                                        identification_t *peer_id)
@@ -557,8 +535,7 @@ peer_cfg_t *peer_cfg_create(char *name, u_int ike_version, ike_cfg_t *ike_cfg,
        this->public.get_reauth_time = (u_int32_t(*)(peer_cfg_t*))get_reauth_time;
        this->public.get_over_time = (u_int32_t(*)(peer_cfg_t*))get_over_time;
        this->public.use_mobike = (bool (*) (peer_cfg_t *))use_mobike;
-       this->public.get_dpd_delay = (u_int32_t (*) (peer_cfg_t *))get_dpd_delay;
-       this->public.get_dpd_action = (dpd_action_t (*) (peer_cfg_t *))get_dpd_action;
+       this->public.get_dpd = (u_int32_t (*) (peer_cfg_t *))get_dpd;
        this->public.get_virtual_ip = (host_t* (*) (peer_cfg_t *))get_virtual_ip;
        this->public.get_pool = (char*(*)(peer_cfg_t*))get_pool;
        this->public.get_auth = (auth_info_t*(*)(peer_cfg_t*))get_auth;
@@ -597,8 +574,7 @@ peer_cfg_t *peer_cfg_create(char *name, u_int ike_version, ike_cfg_t *ike_cfg,
        this->jitter_time = jitter_time;
        this->over_time = over_time;
        this->use_mobike = mobike;
-       this->dpd_delay = dpd_delay;
-       this->dpd_action = dpd_action;
+       this->dpd = dpd;
        this->virtual_ip = virtual_ip;
        this->pool = pool ? strdup(pool) : NULL;
        this->auth = auth_info_create();
index dedabf0..29de4af 100644 (file)
@@ -25,7 +25,6 @@
 #ifndef PEER_CFG_H_
 #define PEER_CFG_H_
 
-typedef enum dpd_action_t dpd_action_t;
 typedef enum cert_policy_t cert_policy_t;
 typedef struct peer_cfg_t peer_cfg_t;
 
@@ -64,27 +63,6 @@ enum cert_policy_t {
 extern enum_name_t *cert_policy_names;
 
 /**
- * Actions to take when a peer does not respond (dead peer detected).
- *
- * These values are the same as in pluto/starter, so do not modify them!
- */
-enum dpd_action_t {
-       /** DPD disabled */
-       DPD_NONE,
-       /** remove CHILD_SAs without replacement */
-       DPD_CLEAR,
-       /** route the CHILD_SAs to resetup when needed */
-       DPD_ROUTE,
-       /** restart CHILD_SAs in a new IKE_SA, immediately */
-       DPD_RESTART,
-};
-
-/**
- * enum names for dpd_action_t.
- */
-extern enum_name_t *dpd_action_names;
-
-/**
  * Configuration of a peer, specified by IDs.
  *
  * The peer config defines a connection between two given IDs. It contains
@@ -259,14 +237,7 @@ struct peer_cfg_t {
         * 
         * @return                      dpd_delay in seconds
         */
-       u_int32_t (*get_dpd_delay) (peer_cfg_t *this);
-       
-       /**
-        * What should be done with a CHILD_SA, when other peer does not respond.
-        *
-        * @return                      dpd action
-        */     
-       dpd_action_t (*get_dpd_action) (peer_cfg_t *this);
+       u_int32_t (*get_dpd) (peer_cfg_t *this);
        
        /**
         * Get a virtual IP for the local peer.
@@ -371,8 +342,7 @@ struct peer_cfg_t {
  * @param over_time                    maximum overtime before closing a rekeying/reauth SA
  * @param reauth                       sould be done reauthentication instead of rekeying?
  * @param mobike                       use MOBIKE (RFC4555) if peer supports it
- * @param dpd_delay                    after how many seconds of inactivity to check DPD
- * @param dpd_action           what to do with CHILD_SAs when detected a dead peer
+ * @param dpd                          DPD check interval, 0 to disable
  * @param virtual_ip           virtual IP for local host, or NULL
  * @param pool                         pool name to get configuration attributes from, or NULL
  * @param mediation                    TRUE if this is a mediation connection
@@ -387,8 +357,7 @@ peer_cfg_t *peer_cfg_create(char *name, u_int ikev_version, ike_cfg_t *ike_cfg,
                                                        u_int32_t eap_vendor,
                                                        u_int32_t keyingtries, u_int32_t rekey_time,
                                                        u_int32_t reauth_time, u_int32_t jitter_time,
-                                                       u_int32_t over_time, bool mobike,
-                                                       u_int32_t dpd_delay, dpd_action_t dpd_action,
+                                                       u_int32_t over_time, bool mobike, u_int32_t dpd,
                                                        host_t *virtual_ip, char *pool,
                                                        bool mediation, peer_cfg_t *mediated_by,
                                                        identification_t *peer_id);
index 38c16b2..e13bc31 100644 (file)
@@ -133,7 +133,7 @@ static child_cfg_t *build_child_cfg(private_sql_config_t *this, enumerator_t *e)
                                                &updown, &hostaccess, &mode))
        {
                child_cfg = child_cfg_create(name, lifetime, rekeytime, jitter,
-                                                                        updown, hostaccess, mode);
+                                                                        updown, hostaccess, mode, ACTION_NONE);
                /* TODO: read proposal from db */
                child_cfg->add_proposal(child_cfg, proposal_create_default(PROTO_ESP));
                add_traffic_selectors(this, child_cfg, id);
@@ -311,7 +311,7 @@ static peer_cfg_t *build_peer_cfg(private_sql_config_t *this, enumerator_t *e,
                                                        name, 2, ike, local_id, remote_id, cert_policy,
                                                        auth_method, eap_type, eap_vendor, keyingtries, 
                                                        rekeytime, reauthtime, jitter, overtime, mobike,
-                                                       dpd_delay, dpd_action, NULL, NULL,
+                                                       dpd_delay, NULL, NULL,
                                                        mediation, mediated_cfg, peer_id);
                        add_child_cfgs(this, peer_cfg, id);
                        return peer_cfg;
index f4f3dbc..a7a7232 100644 (file)
@@ -491,7 +491,7 @@ static peer_cfg_t *build_peer_cfg(private_stroke_config_t *this,
                msg->add_conn.me.sendcert, msg->add_conn.auth_method,
                msg->add_conn.eap_type, msg->add_conn.eap_vendor,
                msg->add_conn.rekey.tries, rekey, reauth, jitter, over,
-               msg->add_conn.mobike, msg->add_conn.dpd.delay, msg->add_conn.dpd.action,
+               msg->add_conn.mobike, msg->add_conn.dpd.delay,
                vip, msg->add_conn.other.sourceip ? msg->add_conn.name : NULL,
                msg->add_conn.ikeme.mediation, mediated_by, peer_id);
 }
@@ -626,13 +626,26 @@ static child_cfg_t *build_child_cfg(private_stroke_config_t *this,
 {
        child_cfg_t *child_cfg;
        traffic_selector_t *ts;
+       action_t action;
        
+       switch (msg->add_conn.dpd.action)
+       {       /* map startes magic values to our action type */
+               case 2: /* =hold */
+                       action = ACTION_ROUTE;
+                       break;
+               case 3: /* =restart */
+                       action = ACTION_RESTART;
+                       break;
+               default:
+                       action = ACTION_NONE;
+                       break;
+       }
        child_cfg = child_cfg_create(
                                msg->add_conn.name, 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, 
                                msg->add_conn.me.updown, msg->add_conn.me.hostaccess,
-                               msg->add_conn.mode);
+                               msg->add_conn.mode, action);
        
        ts = build_ts(this, &msg->add_conn.me);
        if (!ts)
index 0960f51..3b038c8 100644 (file)
@@ -68,7 +68,7 @@ static void execute(private_rekey_ike_sa_job_t *this)
        {
                if (this->reauth)
                {
-                       status = ike_sa->reestablish(ike_sa);
+                       status = ike_sa->reauth(ike_sa);
                }
                else
                {
index 911270a..281a091 100644 (file)
@@ -599,7 +599,7 @@ static status_t send_dpd(private_ike_sa_t *this)
        send_dpd_job_t *job;
        time_t diff, delay;
        
-       delay = this->peer_cfg->get_dpd_delay(this->peer_cfg);
+       delay = this->peer_cfg->get_dpd(this->peer_cfg);
        
        if (delay == 0)
        {
@@ -1435,147 +1435,6 @@ static status_t process_message(private_ike_sa_t *this, message_t *message)
 }
 
 /**
- * Implementation of ike_sa_t.retransmit.
- */
-static status_t retransmit(private_ike_sa_t *this, u_int32_t message_id)
-{      /* FIXME: IKE-ME */
-       this->time.outbound = time(NULL);
-       if (this->task_manager->retransmit(this->task_manager, message_id) != SUCCESS)
-       {
-               child_cfg_t *child_cfg;
-               child_sa_t* child_sa;
-               linked_list_t *to_route, *to_restart;
-               iterator_t *iterator;
-               
-               /* send a proper signal to brief interested bus listeners */
-               switch (this->state)
-               {
-                       case IKE_CONNECTING:
-                       {
-                               /* retry IKE_SA_INIT if we have multiple keyingtries */
-                               u_int32_t tries = this->peer_cfg->get_keyingtries(this->peer_cfg);
-                               this->keyingtry++;
-                               if (tries == 0 || tries > this->keyingtry)
-                               {
-                                       SIG(IKE_UP_FAILED, "peer not responding, trying again "
-                                               "(%d/%d) in background ", this->keyingtry + 1, tries);
-                                       reset(this);
-                                       return this->task_manager->initiate(this->task_manager);
-                               }
-                               SIG(IKE_UP_FAILED, "establishing IKE_SA failed, peer not responding");
-                               break;
-                       }
-                       case IKE_REKEYING:
-                               SIG(IKE_REKEY_FAILED, "rekeying IKE_SA failed, peer not responding");
-                               break;
-                       case IKE_DELETING:
-                               SIG(IKE_DOWN_FAILED, "proper IKE_SA delete failed, peer not responding");
-                               break;
-                       default:
-                               break;
-               }
-               
-               /* summarize how we have to handle each child */
-               to_route = linked_list_create();
-               to_restart = linked_list_create();
-               iterator = this->child_sas->create_iterator(this->child_sas, TRUE);
-               while (iterator->iterate(iterator, (void**)&child_sa))
-               {
-                       child_cfg = child_sa->get_config(child_sa);
-                       
-                       if (child_sa->get_state(child_sa) == CHILD_ROUTED)
-                       {
-                               /* reroute routed CHILD_SAs */
-                               to_route->insert_last(to_route, child_cfg);
-                       }
-                       else
-                       {
-                               /* use DPD action for established CHILD_SAs */
-                               switch (this->peer_cfg->get_dpd_action(this->peer_cfg))
-                               {
-                                       case DPD_ROUTE:
-                                               to_route->insert_last(to_route, child_cfg);
-                                               break;
-                                       case DPD_RESTART:
-                                               to_restart->insert_last(to_restart, child_cfg);
-                                               break;
-                                       default:
-                                               break;
-                               }
-                       }
-               }
-               iterator->destroy(iterator);
-               
-               /* create a new IKE_SA if we have to route or to restart */
-               if (to_route->get_count(to_route) || to_restart->get_count(to_restart))
-               {
-                       private_ike_sa_t *new;
-                       task_t *task;
-                       
-                       new = (private_ike_sa_t*)charon->ike_sa_manager->checkout_new(
-                                                                                               charon->ike_sa_manager, TRUE);
-                       
-                       set_peer_cfg(new, this->peer_cfg);
-                       /* use actual used host, not the wildcarded one in config */
-                       new->other_host->destroy(new->other_host);
-                       new->other_host = this->other_host->clone(this->other_host);
-                       /* reset port to 500, but only if peer is not NATed */
-                       if (!has_condition(this, COND_NAT_THERE))
-                       {
-                               new->other_host->set_port(new->other_host, IKEV2_UDP_PORT);
-                       }
-                       /* take over virtual ip, as we need it for a proper route */
-                       if (this->my_virtual_ip)
-                       {
-                               set_virtual_ip(new, TRUE, this->my_virtual_ip);
-                       }
-                       
-                       /* install routes */
-                       while (to_route->remove_last(to_route, (void**)&child_cfg) == SUCCESS)
-                       {
-                               route(new, child_cfg);
-                       }
-                       
-                       /* restart children */
-                       if (to_restart->get_count(to_restart))
-                       {
-                               task = (task_t*)ike_init_create(&new->public, TRUE, NULL);
-                               new->task_manager->queue_task(new->task_manager, task);
-                               task = (task_t*)ike_natd_create(&new->public, TRUE);
-                               new->task_manager->queue_task(new->task_manager, task);
-                               task = (task_t*)ike_cert_pre_create(&new->public, TRUE);
-                               new->task_manager->queue_task(new->task_manager, task);
-                               task = (task_t*)ike_config_create(&new->public, TRUE);
-                               new->task_manager->queue_task(new->task_manager, task);
-                               task = (task_t*)ike_auth_create(&new->public, TRUE);
-                               new->task_manager->queue_task(new->task_manager, task);
-                               task = (task_t*)ike_cert_post_create(&new->public, TRUE);
-                               new->task_manager->queue_task(new->task_manager, task);
-                               
-                               while (to_restart->remove_last(to_restart, (void**)&child_cfg) == SUCCESS)
-                               {
-                                       task = (task_t*)child_create_create(&new->public, child_cfg);
-                                       new->task_manager->queue_task(new->task_manager, task);
-                               }               
-                               task = (task_t*)ike_auth_lifetime_create(&new->public, TRUE);
-                               new->task_manager->queue_task(new->task_manager, task);
-                               if (this->peer_cfg->use_mobike(this->peer_cfg))
-                               {
-                                       task = (task_t*)ike_mobike_create(&new->public, TRUE);
-                                       new->task_manager->queue_task(new->task_manager, task);
-                               }
-                               new->task_manager->initiate(new->task_manager);
-                       }
-                       charon->ike_sa_manager->checkin(charon->ike_sa_manager, &new->public);
-               }
-               to_route->destroy(to_route);
-               to_restart->destroy(to_restart);
-               return DESTROY_ME;
-       }
-       return SUCCESS;
-}
-
-/**
  * Implementation of ike_sa_t.get_prf.
  */
 static prf_t *get_prf(private_ike_sa_t *this)
@@ -1978,9 +1837,9 @@ static status_t rekey(private_ike_sa_t *this)
 }
 
 /**
- * Implementation of ike_sa_t.reestablish
+ * Implementation of ike_sa_t.reauth
  */
-static status_t reestablish(private_ike_sa_t *this)
+static status_t reauth(private_ike_sa_t *this)
 {
        task_t *task;
 
@@ -2015,6 +1874,134 @@ static status_t reestablish(private_ike_sa_t *this)
 }
 
 /**
+ * Implementation of ike_sa_t.reestablish
+ */
+static status_t reestablish(private_ike_sa_t *this)
+{
+       ike_sa_t *new;
+       host_t *host;
+       iterator_t *iterator;
+       child_sa_t *child_sa;
+       child_cfg_t *child_cfg;
+       action_t action;
+       bool required = FALSE;
+       status_t status = FAILED;
+       
+       if (!this->ike_initiator &&
+               (this->other_virtual_ip != NULL ||
+                has_condition(this, COND_EAP_AUTHENTICATED)
+#ifdef ME
+                || this->is_mediation_server
+#endif /* ME */
+               ))
+       {
+               return FAILED;
+       }
+       
+       new = charon->ike_sa_manager->checkout_new(charon->ike_sa_manager, TRUE);
+       new->set_peer_cfg(new, this->peer_cfg);
+       host = this->other_host;
+       new->set_other_host(new, host->clone(host));
+       host = this->my_host;
+       new->set_my_host(new, host->clone(host));
+       /* if we already have a virtual IP, we reuse it */
+       host = this->my_virtual_ip;
+       if (host)
+       {
+               new->set_virtual_ip(new, TRUE, host);
+       }
+       
+#ifdef ME
+       /* we initiate the new IKE_SA of the mediation connection without CHILD_SA */
+       if (this->peer_cfg->is_mediation(this->peer_cfg))
+       {
+               required = TRUE;
+       }
+#endif /* ME */
+       
+       iterator = create_child_sa_iterator(this);
+       while (iterator->iterate(iterator, (void**)&child_sa))
+       {
+               child_cfg = child_sa->get_config(child_sa);
+               action = child_cfg->get_action(child_cfg);
+       
+               if (action == ACTION_RESTART || action == ACTION_ROUTE)
+               {
+                       required = TRUE;
+                       if (action == ACTION_RESTART)
+                       {
+                               DBG1(DBG_IKE, "restarting CHILD_SA %s",
+                                        child_cfg->get_name(child_cfg));
+                               child_cfg->get_ref(child_cfg);
+                               status = new->initiate(new, child_cfg);
+                               if (status == DESTROY_ME)
+                               {
+                                       required = FALSE;
+                                       break;
+                               }
+                       }
+                       else
+                       {
+                               new->route(new, child_cfg);
+                       }
+               }
+       }
+       iterator->destroy(iterator);
+       
+       if (required)
+       {
+               charon->ike_sa_manager->checkin(charon->ike_sa_manager, new);
+       }
+       else
+       {
+               charon->ike_sa_manager->checkin_and_destroy(charon->ike_sa_manager, new);
+               DBG1(DBG_IKE, "unable to reestablish IKE_SA, no CHILD_SA to recreate");
+       }
+       return status;
+}
+
+/**
+ * Implementation of ike_sa_t.retransmit.
+ */
+static status_t retransmit(private_ike_sa_t *this, u_int32_t message_id)
+{
+       this->time.outbound = time(NULL);
+       if (this->task_manager->retransmit(this->task_manager, message_id) != SUCCESS)
+       {
+               /* send a proper signal to brief interested bus listeners */
+               switch (this->state)
+               {
+                       case IKE_CONNECTING:
+                       {
+                               /* retry IKE_SA_INIT if we have multiple keyingtries */
+                               u_int32_t tries = this->peer_cfg->get_keyingtries(this->peer_cfg);
+                               this->keyingtry++;
+                               if (tries == 0 || tries > this->keyingtry)
+                               {
+                                       SIG(IKE_UP_FAILED, "peer not responding, trying again "
+                                               "(%d/%d) in background ", this->keyingtry + 1, tries);
+                                       reset(this);
+                                       return this->task_manager->initiate(this->task_manager);
+                               }
+                               SIG(IKE_UP_FAILED, "establishing IKE_SA failed, peer not responding");
+                               break;
+                       }
+                       case IKE_REKEYING:
+                               SIG(IKE_REKEY_FAILED, "rekeying IKE_SA failed, peer not responding");
+                               break;
+                       case IKE_DELETING:
+                               SIG(IKE_DOWN_FAILED, "proper IKE_SA delete failed, peer not responding");
+                               break;
+                       default:
+                               break;
+               }
+               reestablish(this);
+               return DESTROY_ME;
+       }
+       return SUCCESS;
+}
+
+/**
  * Implementation of ike_sa_t.set_auth_lifetime.
  */
 static void set_auth_lifetime(private_ike_sa_t *this, u_int32_t lifetime)
@@ -2087,9 +2074,9 @@ static status_t roam(private_ike_sa_t *this, bool address)
                this->task_manager->queue_task(this->task_manager, (task_t*)mobike);
                return this->task_manager->initiate(this->task_manager);
        }
-       DBG1(DBG_IKE, "reestablishing IKE_SA due address change");
-       /* ... reestablish if not */
-       return reestablish(this);
+       DBG1(DBG_IKE, "reauthenticating IKE_SA due address change");
+       /* ... reauth if not */
+       return reauth(this);
 }
 
 /**
@@ -2436,6 +2423,7 @@ ike_sa_t * ike_sa_create(ike_sa_id_t *ike_sa_id)
        this->public.delete_child_sa = (status_t (*)(ike_sa_t*,protocol_id_t,u_int32_t)) delete_child_sa;
        this->public.destroy_child_sa = (status_t (*)(ike_sa_t*,protocol_id_t,u_int32_t))destroy_child_sa;
        this->public.rekey = (status_t (*)(ike_sa_t*))rekey;
+       this->public.reauth = (status_t (*)(ike_sa_t*))reauth;
        this->public.reestablish = (status_t (*)(ike_sa_t*))reestablish;
        this->public.set_auth_lifetime = (void(*)(ike_sa_t*, u_int32_t lifetime))set_auth_lifetime;
        this->public.roam = (status_t(*)(ike_sa_t*,bool))roam;
index af25f27..1f0595c 100644 (file)
@@ -115,7 +115,7 @@ enum ike_condition_t {
        /**
         * received a certificate request from the peer
         */
-       COND_CERTREQ_SEEN = (1<<4),
+       COND_CERTREQ_SEEN = (1<<5),
 };
 
 /**
@@ -803,13 +803,22 @@ struct ike_sa_t {
        status_t (*rekey) (ike_sa_t *this);
 
        /**
-        * Restablish the IKE_SA.
+        * Reauthenticate the IKE_SA.
         *
         * Create a completely new IKE_SA with authentication, recreates all children
         * within the IKE_SA, closes this IKE_SA.
         *
         * @return                              DESTROY_ME to destroy the IKE_SA
         */
+       status_t (*reauth) (ike_sa_t *this);
+
+       /**
+        * Restablish the IKE_SA.
+        *
+        * Reestablish an IKE_SA after it has been closed.
+        *
+        * @return                              DESTROY_ME to destroy the IKE_SA
+        */
        status_t (*reestablish) (ike_sa_t *this);
        
        /**
index 2c1db2a..4de4113 100644 (file)
@@ -152,23 +152,48 @@ static void process_payloads(private_child_delete_t *this, message_t *message)
 }
 
 /**
- * destroy the children listed in this->child_sas
+ * destroy the children listed in this->child_sas, reestablish by policy
  */
-static void destroy_children(private_child_delete_t *this)
+static status_t destroy_and_reestablish(private_child_delete_t *this)
 {
        iterator_t *iterator;
        child_sa_t *child_sa;
+       child_cfg_t *child_cfg;
        protocol_id_t protocol;
        u_int32_t spi;
+       status_t status = SUCCESS;
        
        iterator = this->child_sas->create_iterator(this->child_sas, TRUE);
        while (iterator->iterate(iterator, (void**)&child_sa))
        {
                spi = child_sa->get_spi(child_sa, TRUE);
                protocol = child_sa->get_protocol(child_sa);
+               child_cfg = child_sa->get_config(child_sa);
+               child_cfg->get_ref(child_cfg);
                this->ike_sa->destroy_child_sa(this->ike_sa, protocol, spi);
+               if (!this->initiator)
+               {       /* enforce child_cfg policy if deleted passively */
+                       switch (child_cfg->get_action(child_cfg))
+                       {
+                               case ACTION_RESTART:
+                                       child_cfg->get_ref(child_cfg);
+                                       status = this->ike_sa->initiate(this->ike_sa, child_cfg);
+                                       break;
+                               case ACTION_ROUTE:
+                                       status = this->ike_sa->route(this->ike_sa, child_cfg);
+                                       break;
+                               default:
+                                       break;
+                       }
+               }
+               child_cfg->destroy(child_cfg);
+               if (status != SUCCESS)
+               {
+                       break;
+               }
        }
        iterator->destroy(iterator);
+       return status;
 }
 
 /**
@@ -209,9 +234,8 @@ static status_t process_i(private_child_delete_t *this, message_t *message)
        this->child_sas = linked_list_create();
        
        process_payloads(this, message);
-       destroy_children(this);
        SIG(CHILD_DOWN_SUCCESS, "CHILD_SA closed");
-       return SUCCESS;
+       return destroy_and_reestablish(this);
 }
 
 /**
@@ -234,9 +258,8 @@ static status_t build_r(private_child_delete_t *this, message_t *message)
        {
                build_payloads(this, message);  
        }
-       destroy_children(this);
        SIG(CHILD_DOWN_SUCCESS, "CHILD_SA closed");
-       return SUCCESS;
+       return destroy_and_reestablish(this);
 }
 
 /**
index 6e1ee8b..02d8c16 100644 (file)
@@ -87,6 +87,7 @@ static status_t process_r(private_ike_delete_t *this, message_t *message)
                        break;
                case IKE_ESTABLISHED:
                        DBG1(DBG_IKE, "deleting IKE_SA on request");
+                       this->ike_sa->reestablish(this->ike_sa);
                        break;
                case IKE_REKEYING:
                        break;
index 47d5c28..849e42e 100644 (file)
@@ -68,7 +68,7 @@ static status_t process_i(private_ike_reauth_t *this, message_t *message)
        
        peer_cfg = this->ike_sa->get_peer_cfg(this->ike_sa);
        
-       /* reestablish only if we have children */
+       /* reauthenticate only if we have children */
        iterator = this->ike_sa->create_child_sa_iterator(this->ike_sa);
        if (iterator->get_count(iterator) == 0
 #ifdef ME
@@ -77,7 +77,7 @@ static status_t process_i(private_ike_reauth_t *this, message_t *message)
 #endif /* ME */
                )
        {
-               DBG1(DBG_IKE, "unable to reestablish IKE_SA, no CHILD_SA to recreate");
+               DBG1(DBG_IKE, "unable to reauthenticate IKE_SA, no CHILD_SA to recreate");
                iterator->destroy(iterator);
                return FAILED;
        }
@@ -104,7 +104,7 @@ static status_t process_i(private_ike_reauth_t *this, message_t *message)
                {
                        charon->ike_sa_manager->checkin_and_destroy(
                                                                charon->ike_sa_manager, new);
-                       DBG1(DBG_IKE, "reestablishing IKE_SA failed");
+                       DBG1(DBG_IKE, "reauthenticating IKE_SA failed");
                        return FAILED;
                }
        }
@@ -131,7 +131,7 @@ static status_t process_i(private_ike_reauth_t *this, message_t *message)
                                        iterator->destroy(iterator);
                                        charon->ike_sa_manager->checkin_and_destroy(
                                                                                charon->ike_sa_manager, new);
-                                       DBG1(DBG_IKE, "reestablishing IKE_SA failed");
+                                       DBG1(DBG_IKE, "reauthenticating IKE_SA failed");
                                        return FAILED;
                                }
                                break;