migrate_job() finds a matching child_cfg
authorAndreas Steffen <andreas.steffen@strongswan.org>
Mon, 3 Nov 2008 02:05:41 +0000 (02:05 -0000)
committerAndreas Steffen <andreas.steffen@strongswan.org>
Mon, 3 Nov 2008 02:05:41 +0000 (02:05 -0000)
src/charon/Makefile.am
src/charon/config/child_cfg.c
src/charon/config/child_cfg.h
src/charon/plugins/kernel_netlink/kernel_netlink_ipsec.c
src/charon/plugins/kernel_pfkey/kernel_pfkey_ipsec.c
src/charon/processing/jobs/migrate_job.c [new file with mode: 0644]
src/charon/processing/jobs/migrate_job.h [new file with mode: 0644]

index b14abc5..d66eb55 100644 (file)
@@ -52,6 +52,7 @@ processing/jobs/acquire_job.c processing/jobs/acquire_job.h \
 processing/jobs/callback_job.c processing/jobs/callback_job.h \
 processing/jobs/delete_child_sa_job.c processing/jobs/delete_child_sa_job.h \
 processing/jobs/delete_ike_sa_job.c processing/jobs/delete_ike_sa_job.h \
+processing/jobs/migrate_job.c processing/jobs/migrate_job.h \
 processing/jobs/process_message_job.c processing/jobs/process_message_job.h \
 processing/jobs/rekey_child_sa_job.c processing/jobs/rekey_child_sa_job.h \
 processing/jobs/rekey_ike_sa_job.c processing/jobs/rekey_ike_sa_job.h \
index 5129493..706d69a 100644 (file)
@@ -337,6 +337,31 @@ static linked_list_t* get_traffic_selectors(private_child_cfg_t *this, bool loca
 }
 
 /**
+ * Implementation of child_cfg_t.equal_traffic_selectors.
+ */
+bool equal_traffic_selectors(private_child_cfg_t *this, bool local, traffic_selector_t *ts)
+{
+       linked_list_t *list;
+       enumerator_t *enumerator;
+       traffic_selector_t *other_ts;
+       bool result;
+
+       list = (local) ? this->my_ts : this->other_ts;
+
+       if (list->get_count(list) != 1)
+       {
+               return FALSE;
+       }
+       enumerator = list->create_enumerator(list);
+       enumerator->enumerate(enumerator, &other_ts);
+               
+       result = ts->equals(ts, other_ts);
+
+       enumerator->destroy(enumerator);
+       return result;
+}
+
+/**
  * Implementation of child_cfg_t.get_updown.
  */
 static char* get_updown(private_child_cfg_t *this)
@@ -462,6 +487,7 @@ child_cfg_t *child_cfg_create(char *name, u_int32_t lifetime,
        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;
+       this->public.equal_traffic_selectors = (bool (*)(child_cfg_t*,bool,traffic_selector_t*))equal_traffic_selectors;
        this->public.add_proposal = (void (*) (child_cfg_t*,proposal_t*))add_proposal;
        this->public.get_proposals = (linked_list_t* (*) (child_cfg_t*,bool))get_proposals;
        this->public.select_proposal = (proposal_t* (*) (child_cfg_t*,linked_list_t*,bool))select_proposal;
index 885537f..be21cc0 100644 (file)
@@ -154,6 +154,16 @@ struct child_cfg_t {
                                                                                        host_t *host);
 
        /**
+        * Checks the [single] traffic selectors for equality 
+        *
+        * @param local                 TRUE for TS on local side, FALSE for remote
+        * @param ts                    single traffic selector to compare with
+        * @return                              TRUE if TS are equal, FALSE otherwise
+        */ 
+       bool (*equal_traffic_selectors)(child_cfg_t *this, bool local,
+                                                                  traffic_selector_t *ts);
+
+       /**
         * Get the updown script to run for the CHILD_SA.
         * 
         * @return                              path to updown script
index fc7f78a..cdf9c1e 100644 (file)
@@ -39,6 +39,7 @@
 #include <utils/linked_list.h>
 #include <processing/jobs/callback_job.h>
 #include <processing/jobs/acquire_job.h>
+#include <processing/jobs/migrate_job.h>
 #include <processing/jobs/rekey_child_sa_job.h>
 #include <processing/jobs/delete_child_sa_job.h>
 #include <processing/jobs/update_sa_job.h>
@@ -501,7 +502,7 @@ static void process_acquire(private_kernel_netlink_ipsec_t *this, struct nlmsghd
        }
        src_ts = selector2ts(&acquire->sel, TRUE);
        dst_ts = selector2ts(&acquire->sel, FALSE);
-       DBG1(DBG_KNL, "creating acquire job %R === %R for CHILD_SA with reqid {%d}",
+       DBG1(DBG_KNL, "creating acquire job for policy %R === %R with reqid {%u}",
                                        src_ts, dst_ts, reqid);
        job = (job_t*)acquire_job_create(reqid, src_ts, dst_ts);
        charon->processor->queue_job(charon->processor, job);
@@ -526,7 +527,7 @@ static void process_expire(private_kernel_netlink_ipsec_t *this, struct nlmsghdr
        
        if (protocol != PROTO_ESP && protocol != PROTO_AH)
        {
-               DBG2(DBG_KNL, "ignoring XFRM_MSG_EXPIRE for SA with SPI %.8x and reqid {%d} "
+               DBG2(DBG_KNL, "ignoring XFRM_MSG_EXPIRE for SA with SPI %.8x and reqid {%u} "
                                          "which is not a CHILD_SA", ntohl(spi), reqid);
                return;
        }
@@ -558,6 +559,7 @@ static void process_migrate(private_kernel_netlink_ipsec_t *this, struct nlmsghd
        struct rtattr *rta;
        size_t rtasize;
        u_int32_t reqid = 0;
+       policy_dir_t dir;
        job_t *job;
 
        policy_id = (struct xfrm_userpolicy_id*)NLMSG_DATA(hdr);
@@ -568,8 +570,10 @@ static void process_migrate(private_kernel_netlink_ipsec_t *this, struct nlmsghd
        
        src_ts = selector2ts(&policy_id->sel, TRUE);
        dst_ts = selector2ts(&policy_id->sel, FALSE);
+       dir = (policy_dir_t)policy_id->dir;
+
        DBG2(DBG_KNL, "  policy: %R === %R %N, index %u", src_ts, dst_ts,
-                                  policy_dir_names, policy_id->dir, policy_id->index);
+                                  policy_dir_names, dir, policy_id->index);
 
        while (RTA_OK(rta, rtasize))
        {
@@ -605,9 +609,21 @@ static void process_migrate(private_kernel_netlink_ipsec_t *this, struct nlmsghd
                }
                rta = RTA_NEXT(rta, rtasize);
        }
-       DESTROY_IF(src_ts);
-       DESTROY_IF(dst_ts);
-       DESTROY_IF(local);
+
+       if (src_ts && dst_ts)
+       {
+               DBG1(DBG_KNL, "creating migrate job for policy %R === %R %N "
+                                         "with reqid {%u}, kmaddress = %H",
+                                          src_ts, dst_ts, policy_dir_names, dir, reqid, local);
+               job = (job_t*)migrate_job_create(reqid, src_ts, dst_ts, dir, local);
+               charon->processor->queue_job(charon->processor, job);
+       }
+       else
+       {
+               DESTROY_IF(src_ts);
+               DESTROY_IF(dst_ts);
+               DESTROY_IF(local);
+       }
 }
 
 /**
@@ -634,7 +650,7 @@ static void process_mapping(private_kernel_netlink_ipsec_t *this,
                if (host)
                {
                        DBG1(DBG_KNL, "NAT mappings of ESP CHILD_SA with SPI %.8x and "
-                               "reqid {%d} changed, queuing update job", ntohl(spi), reqid);
+                               "reqid {%u} changed, queuing update job", ntohl(spi), reqid);
                        job = (job_t*)update_sa_job_create(reqid, host);
                        charon->processor->queue_job(charon->processor, job);
                }
@@ -782,16 +798,16 @@ static status_t get_spi(private_kernel_netlink_ipsec_t *this,
                                                protocol_id_t protocol, u_int32_t reqid,
                                                u_int32_t *spi)
 {
-       DBG2(DBG_KNL, "getting SPI for reqid {%d}", reqid);
+       DBG2(DBG_KNL, "getting SPI for reqid {%u}", reqid);
        
        if (get_spi_internal(this, src, dst, proto_ike2kernel(protocol),
                        0xc0000000, 0xcFFFFFFF, reqid, spi) != SUCCESS)
        {
-               DBG1(DBG_KNL, "unable to get SPI for reqid {%d}", reqid);
+               DBG1(DBG_KNL, "unable to get SPI for reqid {%u}", reqid);
                return FAILED;
        }
        
-       DBG2(DBG_KNL, "got SPI %.8x for reqid {%d}", ntohl(*spi), reqid);
+       DBG2(DBG_KNL, "got SPI %.8x for reqid {%u}", ntohl(*spi), reqid);
        
        return SUCCESS;
 }
@@ -805,18 +821,18 @@ static status_t get_cpi(private_kernel_netlink_ipsec_t *this,
 {
        u_int32_t received_spi = 0;
 
-       DBG2(DBG_KNL, "getting CPI for reqid {%d}", reqid);
+       DBG2(DBG_KNL, "getting CPI for reqid {%u}", reqid);
        
        if (get_spi_internal(this, src, dst,
                        IPPROTO_COMP, 0x100, 0xEFFF, reqid, &received_spi) != SUCCESS)
        {
-               DBG1(DBG_KNL, "unable to get CPI for reqid {%d}", reqid);
+               DBG1(DBG_KNL, "unable to get CPI for reqid {%u}", reqid);
                return FAILED;
        }
        
        *cpi = htons((u_int16_t)ntohl(received_spi));
        
-       DBG2(DBG_KNL, "got CPI %.4x for reqid {%d}", ntohs(*cpi), reqid);
+       DBG2(DBG_KNL, "got CPI %.4x for reqid {%u}", ntohs(*cpi), reqid);
        
        return SUCCESS;
 }
@@ -841,7 +857,7 @@ static status_t add_sa(private_kernel_netlink_ipsec_t *this,
        
        memset(&request, 0, sizeof(request));
        
-       DBG2(DBG_KNL, "adding SAD entry with SPI %.8x and reqid {%d}",
+       DBG2(DBG_KNL, "adding SAD entry with SPI %.8x and reqid {%u}",
                 ntohl(spi), reqid);
        
        hdr = (struct nlmsghdr*)request;
index 487be57..406ae2e 100644 (file)
@@ -31,6 +31,7 @@
 #include <utils/host.h>
 #include <processing/jobs/callback_job.h>
 #include <processing/jobs/acquire_job.h>
+#include <processing/jobs/migrate_job.h>
 #include <processing/jobs/rekey_child_sa_job.h>
 #include <processing/jobs/delete_child_sa_job.h>
 #include <processing/jobs/update_sa_job.h>
@@ -777,8 +778,8 @@ static void process_acquire(private_kernel_pfkey_ipsec_t *this, struct sadb_msg*
        dst_ts = sadb_address2ts(response.dst);
        pthread_mutex_unlock(&this->mutex);
        
-       DBG1(DBG_KNL, "creating acquire job %R === %R for CHILD_SA with reqid {%d}",
-                                       src_ts, dst_ts, reqid);
+       DBG1(DBG_KNL, "creating acquire job for policy %R === %R with reqid {%u}",
+                                  src_ts, dst_ts, reqid);
        job = (job_t*)acquire_job_create(reqid, src_ts, dst_ts);
        charon->processor->queue_job(charon->processor, job);
 }
@@ -809,12 +810,12 @@ static void process_expire(private_kernel_pfkey_ipsec_t *this, struct sadb_msg*
        
        if (protocol != PROTO_ESP && protocol != PROTO_AH)
        {
-               DBG2(DBG_KNL, "ignoring SADB_EXPIRE for SA with SPI %.8x and reqid {%d} "
+               DBG2(DBG_KNL, "ignoring SADB_EXPIRE for SA with SPI %.8x and reqid {%u} "
                                          "which is not a CHILD_SA", ntohl(spi), reqid);
                return;
        }
        
-       DBG1(DBG_KNL, "creating %s job for %N CHILD_SA with SPI %.8x and reqid {%d}",
+       DBG1(DBG_KNL, "creating %s job for %N CHILD_SA with SPI %.8x and reqid {%u}",
                 hard ? "delete" : "rekey",  protocol_id_names,
                 protocol, ntohl(spi), reqid);
        if (hard)
@@ -836,7 +837,9 @@ static void process_migrate(private_kernel_pfkey_ipsec_t *this, struct sadb_msg*
        pfkey_msg_t response;
        traffic_selector_t *src_ts, *dst_ts;
        policy_dir_t dir;
+       u_int32_t reqid = 0;
        host_t *local;
+       job_t *job;
 
        DBG2(DBG_KNL, "received an SADB_X_MIGRATE");
 
@@ -853,9 +856,20 @@ static void process_migrate(private_kernel_pfkey_ipsec_t *this, struct sadb_msg*
                                         policy_dir_names, dir, response.x_policy->sadb_x_policy_id);
        DBG2(DBG_KNL, "  kmaddress: %H", local);
        
-       src_ts->destroy(src_ts);
-       dst_ts->destroy(dst_ts);
-       local->destroy(local);
+       if (src_ts && dst_ts)
+       {
+               DBG1(DBG_KNL, "creating migrate job for policy %R === %R %N "
+                                         "with reqid {%u}, kmaddress = %H",
+                                          src_ts, dst_ts, policy_dir_names, dir, reqid, local);
+               job = (job_t*)migrate_job_create(reqid, src_ts, dst_ts, dir, local);
+               charon->processor->queue_job(charon->processor, job);
+       }
+       else
+       {
+               DESTROY_IF(src_ts);
+               DESTROY_IF(dst_ts);
+               DESTROY_IF(local);
+       }
 }
 
 /**
@@ -907,7 +921,7 @@ static void process_mapping(private_kernel_pfkey_ipsec_t *this, struct sadb_msg*
                if (host)
                {
                        DBG1(DBG_KNL, "NAT mappings of ESP CHILD_SA with SPI %.8x and "
-                               "reqid {%d} changed, queuing update job", ntohl(spi), reqid);
+                               "reqid {%u} changed, queuing update job", ntohl(spi), reqid);
                        job = (job_t*)update_sa_job_create(reqid, host);
                        charon->processor->queue_job(charon->processor, job);
                }
@@ -1086,7 +1100,7 @@ static status_t add_sa(private_kernel_pfkey_ipsec_t *this,
        
        memset(&request, 0, sizeof(request));
        
-       DBG2(DBG_KNL, "adding SAD entry with SPI %.8x and reqid {%d}", ntohl(spi), reqid);
+       DBG2(DBG_KNL, "adding SAD entry with SPI %.8x and reqid {%u}", ntohl(spi), reqid);
        
        msg = (struct sadb_msg*)request;
        msg->sadb_msg_version = PF_KEY_V2;
diff --git a/src/charon/processing/jobs/migrate_job.c b/src/charon/processing/jobs/migrate_job.c
new file mode 100644 (file)
index 0000000..c9c835d
--- /dev/null
@@ -0,0 +1,157 @@
+/*
+ * Copyright (C) 2006 Martin Willi
+ * Hochschule fuer Technik Rapperswil
+ *
+ * This program is free software; you can redistribute it and/or modify it
+ * under the terms of the GNU General Public License as published by the
+ * Free Software Foundation; either version 2 of the License, or (at your
+ * option) any later version.  See <http://www.fsf.org/copyleft/gpl.txt>.
+ *
+ * This program is distributed in the hope that it will be useful, but
+ * WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY
+ * or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License
+ * for more details.
+ *
+ * $Id: acquire_job.c 4535 2008-10-31 01:43:23Z andreas $
+ */
+
+#include "migrate_job.h"
+
+#include <daemon.h>
+
+#include <config/child_cfg.h>
+
+
+typedef struct private_migrate_job_t private_migrate_job_t;
+
+/**
+ * Private data of a migrate_job_t object.
+ */
+struct private_migrate_job_t {
+       /**
+        * Public migrate_job_t interface.
+        */
+       migrate_job_t public;
+       
+       /**
+        * reqid of the CHILD_SA if it already exists
+        */
+       u_int32_t reqid;
+
+       /**
+        * source traffic selector
+        */
+       traffic_selector_t *src_ts;
+
+       /**
+        * destination traffic selector
+        */
+       traffic_selector_t *dst_ts;
+
+       /**
+        * local host address to be used
+        */
+       host_t *local;
+};
+
+/**
+ * Implementation of job_t.destroy.
+ */
+static void destroy(private_migrate_job_t *this)
+{
+       DESTROY_IF(this->src_ts);
+       DESTROY_IF(this->dst_ts);
+       DESTROY_IF(this->local);
+       free(this);
+}
+
+/**
+ * Implementation of job_t.execute.
+ */
+static void execute(private_migrate_job_t *this)
+{
+       ike_sa_t *ike_sa = NULL;
+       
+       if (this->reqid)
+       {
+               ike_sa = charon->ike_sa_manager->checkout_by_id(charon->ike_sa_manager,
+                                                                                                               this->reqid, TRUE);
+       }
+       if (ike_sa == NULL)
+       {
+               enumerator_t *enumerator, *children;
+               peer_cfg_t *peer_cfg;
+               child_cfg_t *found_cfg = NULL;
+                               
+               enumerator = charon->backends->create_peer_cfg_enumerator(charon->backends);
+               while (enumerator->enumerate(enumerator, (void**)&peer_cfg))
+               {
+                       ike_cfg_t *ike_cfg;
+                       child_cfg_t *child_cfg;
+
+                       if (peer_cfg->get_ike_version(peer_cfg) != 2)
+                       {
+                               continue;
+                       }
+
+                       ike_cfg = peer_cfg->get_ike_cfg(peer_cfg);
+                       children = peer_cfg->create_child_cfg_enumerator(peer_cfg);
+                       while (children->enumerate(children, &child_cfg))
+                       {
+                               if (child_cfg->equal_traffic_selectors(child_cfg, TRUE, this->src_ts) &&
+                                       child_cfg->equal_traffic_selectors(child_cfg, FALSE, this->dst_ts))
+                               {
+                                       found_cfg = child_cfg;
+                                       break;
+                               }
+                       }
+                       children->destroy(children);
+                       if (found_cfg)
+                       {
+                               break;
+                       }
+               }
+               enumerator->destroy(enumerator);
+               if (found_cfg)
+               {
+                       DBG1(DBG_JOB, "found matching child_cfg '%s'",
+                                                  found_cfg->get_name(found_cfg));
+               }
+               else
+               {
+                       DBG1(DBG_JOB, "no matching child_cfg found");
+               }
+       }
+       else
+       {
+               DBG1(DBG_JOB, "migrate job found CHILD_SA with reqid {%d}", this->reqid);
+
+               /* set my_host to local */
+               charon->ike_sa_manager->checkin(charon->ike_sa_manager, ike_sa);
+       }
+       destroy(this);
+}
+
+/*
+ * Described in header
+ */
+migrate_job_t *migrate_job_create(u_int32_t reqid,
+                                                                 traffic_selector_t *src_ts,
+                                                                 traffic_selector_t *dst_ts,
+                                                                 policy_dir_t dir,
+                                                                 host_t *local)
+{
+       private_migrate_job_t *this = malloc_thing(private_migrate_job_t);
+       
+       /* interface functions */
+       this->public.job_interface.execute = (void (*) (job_t *)) execute;
+       this->public.job_interface.destroy = (void (*)(job_t*)) destroy;
+       
+       /* private variables */
+       this->reqid = reqid;
+       this->src_ts = (dir == POLICY_OUT) ? src_ts : dst_ts;
+       this->dst_ts = (dir == POLICY_OUT) ? dst_ts : src_ts;
+       this->local = local;
+       
+       return &this->public;
+}
diff --git a/src/charon/processing/jobs/migrate_job.h b/src/charon/processing/jobs/migrate_job.h
new file mode 100644 (file)
index 0000000..d23236b
--- /dev/null
@@ -0,0 +1,63 @@
+/*
+ * Copyright (C) 2006 Martin Willi
+ * Hochschule fuer Technik Rapperswil
+ *
+ * This program is free software; you can redistribute it and/or modify it
+ * under the terms of the GNU General Public License as published by the
+ * Free Software Foundation; either version 2 of the License, or (at your
+ * option) any later version.  See <http://www.fsf.org/copyleft/gpl.txt>.
+ *
+ * This program is distributed in the hope that it will be useful, but
+ * WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY
+ * or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License
+ * for more details.
+ *
+ * $Id: acquire_job.h 4535 2008-10-31 01:43:23Z andreas $
+ */
+
+/**
+ * @defgroup migrate_job migrate_job
+ * @{ @ingroup jobs
+ */
+
+#ifndef MIGRATE_JOB_H_
+#define MIGRATE_JOB_H_
+
+typedef struct migrate_job_t migrate_job_t;
+
+#include <library.h>
+#include <utils/host.h>
+#include <config/traffic_selector.h>
+#include <kernel/kernel_ipsec.h>
+#include <processing/jobs/job.h>
+
+/**
+ * Class representing a MIGRATE Job.
+ * 
+ * This job sets a routed CHILD_SA for an existing IPsec policy. 
+ */
+struct migrate_job_t {
+       /**
+        * The job_t interface.
+        */
+       job_t job_interface;
+};
+
+/**
+ * Creates a job of type MIGRATE.
+ *
+ * We use the reqid or the traffic selectors to find a matching CHILD_SA.
+ *
+ * @param reqid                reqid of the CHILD_SA to acquire
+ * @param src_ts       source traffic selector
+ * @param dst_ts       destination traffic selector
+ * @param local     local host address to be used in the IKE_SA
+ * @return                     migrate_job_t object
+ */
+migrate_job_t *migrate_job_create(u_int32_t reqid,
+                                                                 traffic_selector_t *src_ts,
+                                                                 traffic_selector_t *dst_ts,
+                                                                 policy_dir_t dir,
+                                                                 host_t *local);
+
+#endif /* MIGRATE_JOB_H_ @} */