implemented handling of dpdaction and dpddelay ipsec.conf parameters
authorMartin Willi <martin@strongswan.org>
Fri, 8 Sep 2006 06:12:02 +0000 (06:12 -0000)
committerMartin Willi <martin@strongswan.org>
Fri, 8 Sep 2006 06:12:02 +0000 (06:12 -0000)
src/charon/config/connections/local_connection_store.c
src/charon/config/policies/policy.c
src/charon/config/policies/policy.h
src/charon/sa/child_sa.c
src/charon/sa/child_sa.h
src/charon/sa/ike_sa.c
src/charon/sa/transactions/ike_auth.c
src/charon/threads/stroke_interface.c
src/starter/starterstroke.c
src/stroke/stroke.c
src/stroke/stroke.h

index 024754e..72265b5 100644 (file)
@@ -126,7 +126,7 @@ static connection_t *get_connection_by_hosts(private_local_connection_store_t *t
                host_t *found_my_host    = found->get_my_host(found);
                host_t *found_other_host = found->get_other_host(found);
                
-               this->logger->log(this->logger, CONTROL,
+               this->logger->log(this->logger, CONTROL|LEVEL1,
                                                 "found matching connection \"%s\": %s...%s (prio=%d)",
                                                  found->get_name(found),
                                                  found_my_host->get_string(found_my_host),
index 71fadbd..f64447a 100644 (file)
 #include <utils/identification.h>
 #include <utils/logger_manager.h>
 
+mapping_t dpd_action_m[] = {
+       {DPD_CLEAR, "DPD_CLEAR"},
+       {DPD_ROUTE, "DPD_ROUTE"},
+       {DPD_RESTART, "DPD_RESTART"},
+       {MAPPING_END, NULL},
+};
+
 typedef struct private_policy_t private_policy_t;
 
 /**
@@ -110,9 +117,9 @@ struct private_policy_t {
        u_int32_t jitter;
        
        /**
-        * Should the SA get ROUTED when peer detected as dead?
+        * What to do with an SA when other peer seams to be dead?
         */
-       bool dpd_route;
+       bool dpd_action;
        
        /**
         * logger
@@ -334,6 +341,15 @@ static char* get_updown(private_policy_t *this)
 }
 
 /**
+ * Implements policy_t.get_dpd_action
+ */
+static dpd_action_t get_dpd_action(private_policy_t *this)
+{
+       return this->dpd_action;
+}
+
+
+/**
  * Implementation of policy_t.add_my_traffic_selector
  */
 static void add_my_traffic_selector(private_policy_t *this, traffic_selector_t *traffic_selector)
@@ -446,7 +462,7 @@ static void destroy(private_policy_t *this)
  */
 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, char *updown, bool dpd_route)
+                                               u_int32_t jitter, char *updown, dpd_action_t dpd_action)
 {
        private_policy_t *this = malloc_thing(private_policy_t);
 
@@ -465,6 +481,7 @@ policy_t *policy_create(char *name, identification_t *my_id, identification_t *o
        this->public.add_proposal = (void(*)(policy_t*,proposal_t*))add_proposal;
        this->public.add_authorities = (void(*)(policy_t*,identification_t*, identification_t*))add_authorities;
        this->public.get_updown = (char*(*)(policy_t*))get_updown;
+       this->public.get_dpd_action = (dpd_action_t(*)(policy_t*))get_dpd_action;
        this->public.get_soft_lifetime = (u_int32_t (*) (policy_t *))get_soft_lifetime;
        this->public.get_hard_lifetime = (u_int32_t (*) (policy_t *))get_hard_lifetime;
        this->public.get_ref = (void(*)(policy_t*))get_ref;
@@ -478,7 +495,7 @@ policy_t *policy_create(char *name, identification_t *my_id, identification_t *o
        this->soft_lifetime = soft_lifetime;
        this->jitter = jitter;
        this->updown = (updown == NULL) ? NULL : strdup(updown);
-       this->dpd_route = dpd_route;
+       this->dpd_action = dpd_action;
        
        /* initialize private members*/
        this->refcount = 1;
index 9505e53..18e6ad0 100644 (file)
 #include <encoding/payloads/auth_payload.h>
 
 
+typedef enum dpd_action_t dpd_action_t;
+
+/**
+ * @brief 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!
+ *
+ * @ingroup config
+ */
+enum dpd_action_t {
+       /** remove CHILD_SA without replacement */
+       DPD_CLEAR = 1,
+       /** route the CHILD_SA to resetup when needed */
+       DPD_ROUTE = 2,
+       /** restart CHILD_SA in a new IKE_SA, immediately */
+       DPD_RESTART = 3,
+};
+
+/**
+ * String mappings for dpd_action_t
+ */
+mapping_t dpd_action_m[];
+
+
 typedef struct policy_t policy_t;
 
 /**
@@ -202,6 +226,14 @@ struct policy_t {
         * @return                              path to updown script
         */
        char* (*get_updown) (policy_t *this);
+       
+       /**
+        * @brief What should be done with a CHILD_SA, when other peer does not respond.
+        *
+        * @param this          calling object
+        * @return                      dpd action
+        */     
+       dpd_action_t (*get_dpd_action) (policy_t *this);
 
        /**
         * @brief Get the lifetime of a policy, before rekeying starts.
@@ -264,7 +296,7 @@ struct policy_t {
  * @param soft_lifetime                lifetime before rekeying an SA
  * @param jitter                       range of randomization time
  * @param updown                       updown script to execute on up/down event
- * @param dpd_route                    should the connection go to routed state if DPD detected?
+ * @param dpd_action           what to to with a CHILD_SA when other peer does not respond
  * @return                                     policy_t object
  * 
  * @ingroup config
@@ -272,6 +304,6 @@ struct policy_t {
 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, char *updown, bool dpd_route);
+                                               u_int32_t jitter, char *updown, dpd_action_t dpd_action);
 
 #endif /* POLICY_H_ */
index 2e81556..8a7e64a 100644 (file)
@@ -157,6 +157,11 @@ struct private_child_sa_t {
         * Specifies if NAT traversal is used
         */
        bool use_natt;
+
+       /**
+        * Specifies if CHILD_SA goes to ROUTED state if DPD detected
+        */
+       bool stays_routed;
        
        /**
         * CHILD_SAs own logger
index abba8e4..5129ffe 100644 (file)
@@ -197,8 +197,8 @@ struct child_sa_t {
         * @param other_diff    differences to apply for other
         * @return                              SUCCESS or FAILED
         */
-       status_t (*update_hosts) (child_sa_t *this, host_t *new_me, host_t *new_other, 
-       host_diff_t my_diff, host_diff_t other_diff);
+       status_t (*update_hosts)(child_sa_t *this, host_t *new_me, host_t *new_other,
+                                                        host_diff_t my_diff, host_diff_t other_diff);
        
        /**
         * @brief Install the policies using some traffic selectors.
@@ -211,7 +211,9 @@ struct child_sa_t {
         * @param other_ts      traffic selectors for remote site
         * @return                      SUCCESS or FAILED
         */     
-       status_t (*add_policies) (child_sa_t *this, linked_list_t *my_ts_list, linked_list_t *other_ts_list);
+       status_t (*add_policies)(child_sa_t *this, 
+                                                        linked_list_t *my_ts_list,
+                                                        linked_list_t *other_ts_list);
        
        /**
         * @brief Get the traffic selectors of added policies of local host.
index 6488cc2..c5d3a63 100644 (file)
@@ -55,6 +55,8 @@
 #include <queues/jobs/send_dpd_job.h>
 #include <queues/jobs/send_keepalive_job.h>
 #include <queues/jobs/rekey_ike_sa_job.h>
+#include <queues/jobs/route_job.h>
+#include <queues/jobs/initiate_job.h>
 
 /**
  * String mappings for ike_sa_state_t.
@@ -426,6 +428,80 @@ static void update_hosts(private_ike_sa_t *this, host_t *me, host_t *other)
 }
 
 /**
+ * called when the peer is not responding anymore
+ */
+static void dpd_detected(private_ike_sa_t *this)
+{
+       /* check for childrens with dpdaction=hold */
+       connection_t *connection = NULL;
+       policy_t *policy;
+       linked_list_t *my_ts, *other_ts;
+       child_sa_t* child_sa;
+       dpd_action_t action;
+       job_t *job;
+       
+       this->logger->log(this->logger, CONTROL|LEVEL1,
+                                         "dead peer detected, handling CHILD_SAs dpd action");
+       
+       while(this->child_sas->remove_first(this->child_sas,
+                                                                                       (void**)&child_sa) == SUCCESS)
+       {
+               /* get the policy which belongs to this CHILD */
+               my_ts = child_sa->get_my_traffic_selectors(child_sa);
+               other_ts = child_sa->get_other_traffic_selectors(child_sa);
+               policy = charon->policies->get_policy(charon->policies,
+                                                                                         this->my_id, this->other_id,
+                                                                                         my_ts, other_ts,
+                                                                                         this->my_host, this->other_host);
+               if (policy == NULL)
+               {
+                       this->logger->log(this->logger, ERROR,
+                                                         "no policy found for this CHILD_SA");
+                       continue;
+               }
+               
+               action = policy->get_dpd_action(policy);
+               /* get a connection for further actions */
+               if (connection == NULL && 
+                       (action == DPD_ROUTE || action == DPD_RESTART))
+               {
+                       connection = charon->connections->get_connection_by_hosts(
+                                                                                       charon->connections,
+                                                                                       this->my_host, this->other_host);
+                       if (connection == NULL)
+                       {
+                               this->logger->log(this->logger, ERROR,
+                                                                 "no connection found for this IKE_SA");
+                               break;
+                       }
+               }
+               
+               this->logger->log(this->logger, CONTROL, "dpd action for %s is %s", 
+                                                 policy->get_name(policy),
+                                                 mapping_find(dpd_action_m, action));
+               
+               switch (action)
+               {
+                       case DPD_ROUTE:
+                               connection->get_ref(connection);
+                               job = (job_t*)route_job_create(connection, policy, TRUE);
+                               charon->job_queue->add(charon->job_queue, job);
+                               break;
+                       case DPD_RESTART:
+                               connection->get_ref(connection);
+                               job = (job_t*)initiate_job_create(connection, policy);
+                               charon->job_queue->add(charon->job_queue, job);
+                               break;
+                       default:
+                               policy->destroy(policy);
+                               break;
+               }
+               child_sa->destroy(child_sa);
+       }
+       DESTROY_IF(connection);
+}
+
+/**
  * send a request and schedule retransmission
  */
 static status_t transmit_request(private_ike_sa_t *this)
@@ -439,20 +515,16 @@ static status_t transmit_request(private_ike_sa_t *this)
        transaction_t *transaction = this->transaction_out;
        u_int32_t message_id;
        
-       
-       this->logger->log(this->logger, CONTROL,
-                                         "transmitting request");
-       
        transmitted = transaction->requested(transaction);
        timeout = charon->configuration->get_retransmit_timeout(charon->configuration,
                                                                                                                        transmitted,
                                                                                                                        this->retrans_sequences);
        if (timeout == 0)
        {
-               /* giving up. TODO: check for childrens with dpdaction=hold */
                this->logger->log(this->logger, ERROR,
                                                  "giving up after %d retransmits, deleting IKE_SA",
                                                  transmitted - 1);
+               dpd_detected(this);
                return DESTROY_ME;
        }
        
@@ -502,8 +574,6 @@ static status_t retransmit_request(private_ike_sa_t *this, u_int32_t message_id)
        if (this->transaction_out == NULL ||
                this->transaction_out->get_message_id(this->transaction_out) != message_id)
        {
-               if (this->transaction_out)
-               printf("trans_out->mid = %d, mid = %d\n", this->transaction_out->get_message_id(this->transaction_out), message_id);
                /* no retransmit necessary, transaction did already complete */
                return SUCCESS;
        }
@@ -925,7 +995,7 @@ static status_t acquire(private_ike_sa_t *this, u_int32_t reqid)
        {
                if (current->get_reqid(current) == reqid)
                {
-                       iterator->remove(iterator);
+                       //iterator->remove(iterator);
                        child_sa = current;
                        break;
                }
@@ -945,7 +1015,7 @@ static status_t acquire(private_ike_sa_t *this, u_int32_t reqid)
                                                                                  this->my_id, this->other_id, 
                                                                                  my_ts, other_ts, 
                                                                                  this->my_host, this->other_host);
-       child_sa->destroy(child_sa);
+       //child_sa->destroy(child_sa);
        if (policy == NULL)
        {
                this->logger->log(this->logger, ERROR, 
@@ -1128,7 +1198,8 @@ static status_t route(private_ike_sa_t *this, connection_t *connection, policy_t
                        return FAILED;
        }
        
-       child_sa = child_sa_create(0, this->my_host, this->other_host, 0, 0, FALSE);
+       child_sa = child_sa_create(0, this->my_host, this->other_host,
+                                                          0, 0, FALSE);
        child_sa->set_name(child_sa, policy->get_name(policy));
        my_ts = policy->get_my_traffic_selectors(policy, this->my_host);
        other_ts = policy->get_other_traffic_selectors(policy, this->other_host);
index 1d15dae..0632fe4 100644 (file)
@@ -312,12 +312,15 @@ static status_t get_request(private_ike_auth_t *this, message_t **result)
                linked_list_t *proposal_list;
                sa_payload_t *sa_payload;
                u_int32_t soft_lifetime, hard_lifetime;
+               bool enable_natt;
                
                proposal_list = this->policy->get_proposals(this->policy);
                soft_lifetime = this->policy->get_soft_lifetime(this->policy);
                hard_lifetime = this->policy->get_hard_lifetime(this->policy);
-               this->child_sa = child_sa_create(this->reqid, me, other, soft_lifetime, hard_lifetime,
-                                                                                this->ike_sa->is_natt_enabled(this->ike_sa));
+               enable_natt = this->ike_sa->is_natt_enabled(this->ike_sa);
+               this->child_sa = child_sa_create(this->reqid, me, other, 
+                                                                                soft_lifetime, hard_lifetime,
+                                                                                enable_natt);
                this->child_sa->set_name(this->child_sa, this->policy->get_name(this->policy));
                if (this->child_sa->alloc(this->child_sa, proposal_list) != SUCCESS)
                {
index 55a3b79..b8bdd5a 100755 (executable)
@@ -412,7 +412,7 @@ static void stroke_add_conn(private_stroke_t *this, stroke_msg_t *msg)
                                                   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.dpd.route);
+                                                  msg->add_conn.me.updown, msg->add_conn.dpd.action);
        policy->add_my_traffic_selector(policy, my_ts);
        policy->add_other_traffic_selector(policy, other_ts);
        policy->add_authorities(policy, my_ca, other_ca);
index 32866be..e54931a 100644 (file)
@@ -181,7 +181,7 @@ int starter_stroke_add_conn(starter_conn_t *conn)
        msg.add_conn.algorithms.ike = push_string(&msg, conn->ike);
        msg.add_conn.algorithms.esp = push_string(&msg, conn->esp);
        msg.add_conn.dpd.delay = conn->dpd_delay;
-       msg.add_conn.dpd.route = conn->dpd_action == DPD_ACTION_HOLD ? 1 : 0;
+       msg.add_conn.dpd.action = conn->dpd_action;
 
        starter_stroke_add_end(&msg, &msg.add_conn.me, &conn->right);
        starter_stroke_add_end(&msg, &msg.add_conn.other, &conn->left);
index 03a5ca2..6ca07a8 100644 (file)
@@ -117,7 +117,7 @@ static int add_connection(char *name,
        msg.add_conn.algorithms.esp = NULL;
        
        msg.add_conn.dpd.delay = 0;
-       msg.add_conn.dpd.route = 0;
+       msg.add_conn.dpd.action = 1;
        
        msg.add_conn.me.id = push_string(&msg, my_id);
        msg.add_conn.me.address = push_string(&msg, my_addr);
index 3202842..39a529c 100644 (file)
@@ -147,7 +147,7 @@ struct stroke_msg_t {
                        } rekey;
                        struct {
                                time_t delay;
-                               bool route;
+                               int action;
                        } dpd;
                        stroke_end_t me, other;
                } add_conn;