vici: Add redirect command
authorTobias Brunner <tobias@strongswan.org>
Tue, 28 Apr 2015 15:45:52 +0000 (17:45 +0200)
committerTobias Brunner <tobias@strongswan.org>
Fri, 4 Mar 2016 15:02:59 +0000 (16:02 +0100)
This allows redirecting IKE_SAs by multiple different selectors, if none
are given all SAs are redirected.

src/libcharon/plugins/vici/README.md
src/libcharon/plugins/vici/perl/Vici-Session/lib/Vici/Session.pm
src/libcharon/plugins/vici/python/vici/session.py
src/libcharon/plugins/vici/ruby/lib/vici.rb
src/libcharon/plugins/vici/vici_control.c

index 773ef1a..d084883 100644 (file)
@@ -289,6 +289,21 @@ Terminates an SA while streaming _control-log_ events.
 The default timeout of 0 waits indefinitely for a result, and a timeout value
 of -1 returns a result immediately.
 
+### redirect() ###
+
+Redirect a client-initiated IKE_SA to another gateway.  Only for IKEv2 and if
+supported by the peer.
+
+       {
+               ike = <redirect an IKE_SA by configuration name>
+               ike-id = <redirect an IKE_SA by its unique id>
+               peer-ip = <redirect an IKE_SA with matching peer IP>
+               peer-id = <redirect an IKE_SA with matching peer identity>
+       } => {
+               success = <yes or no>
+               errmsg = <error string on failure>
+       }
+
 ### install() ###
 
 Install a trap, drop or bypass policy defined by a CHILD_SA config.
index 5252296..7819713 100644 (file)
@@ -36,6 +36,10 @@ sub terminate {
     return request_vars_res('terminate', @_);
 }
 
+sub redirect {
+    return request_vars_res('redirect', @_);
+}
+
 sub install {
     return request_vars_res('install', @_);
 }
index 283e3d1..66de859 100644 (file)
@@ -53,6 +53,14 @@ class Session(object):
         """
         return self.handler.streamed_request("terminate", "control-log", sa)
 
+    def redirect(self, sa):
+        """Redirect an IKE_SA.
+
+        :param sa: the SA to redirect
+        :type sa: dict
+        """
+        self.handler.request("redirect", sa)
+
     def install(self, policy):
         """Install a trap, drop or bypass policy defined by a CHILD_SA config.
 
index f8169ad..018f507 100644 (file)
@@ -505,6 +505,12 @@ module Vici
     end
 
     ##
+    # Redirect an IKE_SA.
+    def redirect(options)
+      check_success(@transp.request("redirect", Message.new(options)))
+    end
+
+    ##
     # Install a shunt/route policy.
     def install(policy)
       check_success(@transp.request("install", Message.new(policy)))
index 87794d2..7bcab0e 100644 (file)
@@ -1,4 +1,7 @@
 /*
+ * Copyright (C) 2015 Tobias Brunner
+ * Hochschule fuer Technik Rapperswil
+ *
  * Copyright (C) 2014 Martin Willi
  * Copyright (C) 2014 revosec AG
  *
@@ -20,6 +23,7 @@
 
 #include <daemon.h>
 #include <collections/array.h>
+#include <processing/jobs/redirect_job.h>
 
 typedef struct private_vici_control_t private_vici_control_t;
 
@@ -356,6 +360,118 @@ CALLBACK(terminate, vici_message_t*,
        return builder->finalize(builder);
 }
 
+CALLBACK(redirect, vici_message_t*,
+       private_vici_control_t *this, char *name, u_int id, vici_message_t *request)
+{
+       enumerator_t *sas;
+       char *ike, *peer_ip, *peer_id, *gw, *errmsg = NULL;
+       u_int ike_id, current, found = 0;
+       identification_t *gateway, *identity = NULL;
+       host_t *address = NULL;
+       ike_sa_t *ike_sa;
+       vici_builder_t *builder;
+
+       ike = request->get_str(request, NULL, "ike");
+       ike_id = request->get_int(request, 0, "ike-id");
+       peer_ip = request->get_str(request, NULL, "peer-ip");
+       peer_id = request->get_str(request, NULL, "peer-id");
+       gw = request->get_str(request, NULL, "gateway");
+
+       if (!gw || !(gateway = identification_create_from_string(gw)))
+       {
+               return send_reply(this, "missing target gateway");
+       }
+       switch (gateway->get_type(gateway))
+       {
+               case ID_IPV4_ADDR:
+               case ID_IPV6_ADDR:
+               case ID_FQDN:
+                       break;
+               default:
+                       return send_reply(this, "unsupported gateway identity");
+       }
+       if (peer_ip)
+       {
+               address = host_create_from_string(peer_ip, 0);
+               if (!address)
+               {
+                       return send_reply(this, "invalid peer IP selector");
+               }
+               DBG1(DBG_CFG, "vici redirect IKE_SAs with src %H to %Y", address,
+                        gateway);
+       }
+       if (peer_id)
+       {
+               identity = identification_create_from_string(peer_id);
+               if (!identity)
+               {
+                       DESTROY_IF(address);
+                       return send_reply(this, "invalid peer identity selector");
+               }
+               DBG1(DBG_CFG, "vici redirect IKE_SAs with ID '%Y' to %Y", identity,
+                        gateway);
+       }
+       if (ike_id)
+       {
+               DBG1(DBG_CFG, "vici redirect IKE_SA #%d to %Y", ike_id, gateway);
+       }
+       if (ike)
+       {
+               DBG1(DBG_CFG, "vici redirect IKE_SA '%s' to %Y", ike, gateway);
+       }
+       if (!peer_ip && !peer_id && !ike && !ike_id)
+       {
+               DBG1(DBG_CFG, "vici redirect all IKE_SAs to %Y", gateway);
+       }
+
+       sas = charon->controller->create_ike_sa_enumerator(charon->controller, TRUE);
+       while (sas->enumerate(sas, &ike_sa))
+       {
+               if (ike_sa->get_version(ike_sa) != IKEV2)
+               {
+                       continue;
+               }
+               current = ike_sa->get_unique_id(ike_sa);
+               if (ike_id && ike_id != current)
+               {
+                       continue;
+               }
+               if (ike && !streq(ike, ike_sa->get_name(ike_sa)))
+               {
+                       continue;
+               }
+               if (address &&
+                       !address->ip_equals(address, ike_sa->get_other_host(ike_sa)))
+               {
+                       continue;
+               }
+               if (identity &&
+                       !identity->equals(identity, ike_sa->get_other_eap_id(ike_sa)))
+               {
+                       continue;
+               }
+               lib->processor->queue_job(lib->processor,
+                               (job_t*)redirect_job_create(ike_sa->get_id(ike_sa), gateway));
+               found++;
+       }
+       sas->destroy(sas);
+
+       builder = vici_builder_create();
+       if (!found)
+       {
+               errmsg = "no matching SAs to redirect found";
+       }
+       builder->add_kv(builder, "success", errmsg ? "no" : "yes");
+       if (errmsg)
+       {
+               builder->add_kv(builder, "errmsg", "%s", errmsg);
+       }
+       gateway->destroy(gateway);
+       DESTROY_IF(identity);
+       DESTROY_IF(address);
+       return builder->finalize(builder);
+}
+
 /**
  * Find reqid of an existing CHILD_SA
  */
@@ -498,6 +614,7 @@ static void manage_commands(private_vici_control_t *this, bool reg)
 {
        manage_command(this, "initiate", initiate, reg);
        manage_command(this, "terminate", terminate, reg);
+       manage_command(this, "redirect", redirect, reg);
        manage_command(this, "install", install, reg);
        manage_command(this, "uninstall", uninstall, reg);
        manage_command(this, "reload-settings", reload_settings, reg);