Added a stroke rekey command to trigger IKE/CHILD_SA rekeying manually
authorMartin Willi <martin@revosec.ch>
Wed, 3 Nov 2010 14:12:05 +0000 (15:12 +0100)
committerMartin Willi <martin@revosec.ch>
Wed, 3 Nov 2010 14:12:05 +0000 (15:12 +0100)
src/libcharon/plugins/stroke/stroke_control.c
src/libcharon/plugins/stroke/stroke_control.h
src/libcharon/plugins/stroke/stroke_socket.c
src/stroke/stroke.c
src/stroke/stroke_keywords.h
src/stroke/stroke_keywords.txt
src/stroke/stroke_msg.h

index e0398ba..11c1103 100644 (file)
@@ -17,6 +17,8 @@
 
 #include <daemon.h>
 #include <processing/jobs/delete_ike_sa_job.h>
+#include <processing/jobs/rekey_ike_sa_job.h>
+#include <processing/jobs/rekey_child_sa_job.h>
 
 typedef struct private_stroke_control_t private_stroke_control_t;
 
@@ -137,76 +139,91 @@ static void initiate(private_stroke_control_t *this, stroke_msg_t *msg, FILE *ou
 }
 
 /**
- * Implementation of stroke_control_t.terminate.
+ * Parse a terminate/rekey specifier
  */
-static void terminate(private_stroke_control_t *this, stroke_msg_t *msg, FILE *out)
+static bool parse_specifier(char *string, u_int32_t *id,
+                                                       char **name, bool *child, bool *all)
 {
-       char *string, *pos = NULL, *name = NULL;
-       u_int32_t id = 0;
-       bool child, all = FALSE;
        int len;
-       ike_sa_t *ike_sa;
-       enumerator_t *enumerator;
-       linked_list_t *ike_list, *child_list;
-       stroke_log_info_t info;
-       uintptr_t del;
+       char *pos = NULL;
 
-       string = msg->terminate.name;
+       *id = 0;
+       *name = NULL;
+       *all = FALSE;
 
        len = strlen(string);
        if (len < 1)
        {
-               DBG1(DBG_CFG, "error parsing string");
-               return;
+               return FALSE;
        }
        switch (string[len-1])
        {
                case '}':
-                       child = TRUE;
+                       *child = TRUE;
                        pos = strchr(string, '{');
                        break;
                case ']':
-                       child = FALSE;
+                       *child = FALSE;
                        pos = strchr(string, '[');
                        break;
                default:
-                       name = string;
-                       child = FALSE;
+                       *name = string;
+                       *child = FALSE;
                        break;
        }
 
-       if (name)
+       if (*name)
        {
                /* is a single name */
        }
        else if (pos == string + len - 2)
        {       /* is name[] or name{} */
                string[len-2] = '\0';
-               name = string;
+               *name = string;
        }
        else
        {
                if (!pos)
                {
-                       DBG1(DBG_CFG, "error parsing string");
-                       return;
+                       return FALSE;
                }
                if (*(pos + 1) == '*')
                {       /* is name[*] */
-                       all = TRUE;
+                       *all = TRUE;
                        *pos = '\0';
-                       name = string;
+                       *name = string;
                }
                else
                {       /* is name[123] or name{23} */
-                       id = atoi(pos + 1);
-                       if (id == 0)
+                       *id = atoi(pos + 1);
+                       if (*id == 0)
                        {
-                               DBG1(DBG_CFG, "error parsing string");
-                               return;
+                               return FALSE;
                        }
                }
        }
+       return TRUE;
+}
+
+/**
+ * Implementation of stroke_control_t.terminate.
+ */
+static void terminate(private_stroke_control_t *this, stroke_msg_t *msg, FILE *out)
+{
+       char *name;
+       u_int32_t id;
+       bool child, all;
+       ike_sa_t *ike_sa;
+       enumerator_t *enumerator;
+       linked_list_t *ike_list, *child_list;
+       stroke_log_info_t info;
+       uintptr_t del;
+
+       if (!parse_specifier(msg->terminate.name, &id, &name, &child, &all))
+       {
+               DBG1(DBG_CFG, "error parsing specifier string");
+               return;
+       }
 
        info.out = out;
        info.level = msg->output_verbosity;
@@ -294,6 +311,68 @@ static void terminate(private_stroke_control_t *this, stroke_msg_t *msg, FILE *o
 }
 
 /**
+ * Implementation of stroke_control_t.rekey.
+ */
+static void rekey(private_stroke_control_t *this, stroke_msg_t *msg, FILE *out)
+{
+       char *name;
+       u_int32_t id;
+       bool child, all, finished = FALSE;
+       ike_sa_t *ike_sa;
+       enumerator_t *enumerator;
+
+       if (!parse_specifier(msg->terminate.name, &id, &name, &child, &all))
+       {
+               DBG1(DBG_CFG, "error parsing specifier string");
+               return;
+       }
+       enumerator = charon->controller->create_ike_sa_enumerator(charon->controller);
+       while (enumerator->enumerate(enumerator, &ike_sa))
+       {
+               child_sa_t *child_sa;
+               iterator_t *children;
+
+               if (child)
+               {
+                       children = ike_sa->create_child_sa_iterator(ike_sa);
+                       while (children->iterate(children, (void**)&child_sa))
+                       {
+                               if ((name && streq(name, child_sa->get_name(child_sa))) ||
+                                       (id && id == child_sa->get_reqid(child_sa)))
+                               {
+                                       lib->processor->queue_job(lib->processor,
+                                               (job_t*)rekey_child_sa_job_create(
+                                                               child_sa->get_reqid(child_sa),
+                                                               child_sa->get_protocol(child_sa),
+                                                               child_sa->get_spi(child_sa, TRUE)));
+                                       if (!all)
+                                       {
+                                               finished = TRUE;
+                                               break;
+                                       }
+                               }
+                       }
+                       children->destroy(children);
+               }
+               else if ((name && streq(name, ike_sa->get_name(ike_sa))) ||
+                                (id && id == ike_sa->get_unique_id(ike_sa)))
+               {
+                       lib->processor->queue_job(lib->processor,
+                               (job_t*)rekey_ike_sa_job_create(ike_sa->get_id(ike_sa), FALSE));
+                       if (!all)
+                       {
+                               finished = TRUE;
+                       }
+               }
+               if (finished)
+               {
+                       break;
+               }
+       }
+       enumerator->destroy(enumerator);
+}
+
+/**
  * Implementation of stroke_control_t.terminate_srcip.
  */
 static void terminate_srcip(private_stroke_control_t *this,
@@ -486,6 +565,7 @@ stroke_control_t *stroke_control_create()
        this->public.initiate = (void(*)(stroke_control_t*, stroke_msg_t *msg, FILE *out))initiate;
        this->public.terminate = (void(*)(stroke_control_t*, stroke_msg_t *msg, FILE *out))terminate;
        this->public.terminate_srcip = (void(*)(stroke_control_t*, stroke_msg_t *msg, FILE *out))terminate_srcip;
+       this->public.rekey = (void(*)(stroke_control_t*, stroke_msg_t *msg, FILE *out))rekey;
        this->public.purge_ike = (void(*)(stroke_control_t*, stroke_msg_t *msg, FILE *out))purge_ike;
        this->public.route = (void(*)(stroke_control_t*, stroke_msg_t *msg, FILE *out))route;
        this->public.unroute = (void(*)(stroke_control_t*, stroke_msg_t *msg, FILE *out))unroute;
index 9b49bdc..869aab3 100644 (file)
@@ -54,6 +54,13 @@ struct stroke_control_t {
        void (*terminate_srcip)(stroke_control_t *this, stroke_msg_t *msg, FILE *out);
 
        /**
+        * Rekey a connection.
+        *
+        * @param msg           stroke message
+        */
+       void (*rekey)(stroke_control_t *this, stroke_msg_t *msg, FILE *out);
+
+       /**
         * Delete IKE_SAs without a CHILD_SA.
         *
         * @param msg           stroke message
index 0a5110f..2e321f8 100644 (file)
@@ -246,6 +246,17 @@ static void stroke_terminate_srcip(private_stroke_socket_t *this,
 }
 
 /**
+ * rekey a connection by name/id
+ */
+static void stroke_rekey(private_stroke_socket_t *this, stroke_msg_t *msg, FILE *out)
+{
+       pop_string(msg, &msg->terminate.name);
+       DBG1(DBG_CFG, "received stroke: rekey '%s'", msg->rekey.name);
+
+       this->control->rekey(this->control, msg, out);
+}
+
+/**
  * route a policy (install SPD entries)
  */
 static void stroke_route(private_stroke_socket_t *this, stroke_msg_t *msg, FILE *out)
@@ -510,6 +521,9 @@ static job_requeue_t process(stroke_job_context_t *ctx)
                case STR_TERMINATE_SRCIP:
                        stroke_terminate_srcip(this, msg, out);
                        break;
+               case STR_REKEY:
+                       stroke_rekey(this, msg, out);
+                       break;
                case STR_STATUS:
                        stroke_status(this, msg, out, FALSE);
                        break;
index 103617f..7c27e12 100644 (file)
@@ -197,6 +197,16 @@ static int terminate_connection_srcip(char *start, char *end)
        return send_stroke_msg(&msg);
 }
 
+static int rekey_connection(char *name)
+{
+       stroke_msg_t msg;
+
+       msg.type = STR_REKEY;
+       msg.length = offsetof(stroke_msg_t, buffer);
+       msg.rekey.name = push_string(&msg, name);
+       return send_stroke_msg(&msg);
+}
+
 static int route_connection(char *name)
 {
        stroke_msg_t msg;
@@ -443,6 +453,13 @@ int main(int argc, char *argv[])
                        }
                        res = terminate_connection_srcip(argv[2], argc > 3 ? argv[3] : NULL);
                        break;
+               case STROKE_REKEY:
+                       if (argc < 3)
+                       {
+                               exit_usage("\"rekey\" needs a connection name");
+                       }
+                       res = rekey_connection(argv[2]);
+                       break;
                case STROKE_ROUTE:
                        if (argc < 3)
                        {
index 4a38265..a57415e 100644 (file)
@@ -25,6 +25,7 @@ typedef enum {
        STROKE_UP,
        STROKE_DOWN,
        STROKE_DOWN_SRCIP,
+       STROKE_REKEY,
        STROKE_LOGLEVEL,
        STROKE_STATUS,
        STROKE_STATUSALL,
index 0b80929..7633da4 100644 (file)
@@ -32,6 +32,7 @@ unroute,         STROKE_UNROUTE
 up,              STROKE_UP
 down,            STROKE_DOWN
 down-srcip,      STROKE_DOWN_SRCIP
+rekey,           STROKE_REKEY
 loglevel,        STROKE_LOGLEVEL
 status,          STROKE_STATUS
 statusall,       STROKE_STATUSALL
index 9466cf0..1abaf6c 100644 (file)
@@ -183,6 +183,8 @@ struct stroke_msg_t {
                STR_TERMINATE,
                /* terminate connection by peers srcip/virtual ip */
                STR_TERMINATE_SRCIP,
+               /* rekey a connection */
+               STR_REKEY,
                /* show connection status */
                STR_STATUS,
                /* show verbose connection status */
@@ -215,7 +217,7 @@ struct stroke_msg_t {
                /* data for STR_INITIATE, STR_ROUTE, STR_UP, STR_DOWN, ... */
                struct {
                        char *name;
-               } initiate, route, unroute, terminate, status, del_conn, del_ca;
+               } initiate, route, unroute, terminate, rekey, status, del_conn, del_ca;
 
                /* data for STR_TERMINATE_SRCIP */
                struct {