From ef6d339c096bdce7f0b53d4fcdffcdf05a38fdee Mon Sep 17 00:00:00 2001 From: Andreas Steffen Date: Mon, 3 Nov 2008 02:05:41 +0000 Subject: [PATCH] migrate_job() finds a matching child_cfg --- src/charon/Makefile.am | 1 + src/charon/config/child_cfg.c | 26 +++ src/charon/config/child_cfg.h | 10 ++ .../kernel_netlink/kernel_netlink_ipsec.c | 44 +++-- .../plugins/kernel_pfkey/kernel_pfkey_ipsec.c | 32 +++- src/charon/processing/jobs/migrate_job.c | 157 ++++++++++++++++++ src/charon/processing/jobs/migrate_job.h | 63 +++++++ 7 files changed, 310 insertions(+), 23 deletions(-) create mode 100644 src/charon/processing/jobs/migrate_job.c create mode 100644 src/charon/processing/jobs/migrate_job.h diff --git a/src/charon/Makefile.am b/src/charon/Makefile.am index b14abc530..d66eb5510 100644 --- a/src/charon/Makefile.am +++ b/src/charon/Makefile.am @@ -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 \ diff --git a/src/charon/config/child_cfg.c b/src/charon/config/child_cfg.c index 512949355..706d69a93 100644 --- a/src/charon/config/child_cfg.c +++ b/src/charon/config/child_cfg.c @@ -336,6 +336,31 @@ static linked_list_t* get_traffic_selectors(private_child_cfg_t *this, bool loca return result; } +/** + * 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. */ @@ -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; diff --git a/src/charon/config/child_cfg.h b/src/charon/config/child_cfg.h index 885537f84..be21cc0e3 100644 --- a/src/charon/config/child_cfg.h +++ b/src/charon/config/child_cfg.h @@ -153,6 +153,16 @@ struct child_cfg_t { linked_list_t *supplied, 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. * diff --git a/src/charon/plugins/kernel_netlink/kernel_netlink_ipsec.c b/src/charon/plugins/kernel_netlink/kernel_netlink_ipsec.c index fc7f78aee..cdf9c1e99 100644 --- a/src/charon/plugins/kernel_netlink/kernel_netlink_ipsec.c +++ b/src/charon/plugins/kernel_netlink/kernel_netlink_ipsec.c @@ -39,6 +39,7 @@ #include #include #include +#include #include #include #include @@ -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; diff --git a/src/charon/plugins/kernel_pfkey/kernel_pfkey_ipsec.c b/src/charon/plugins/kernel_pfkey/kernel_pfkey_ipsec.c index 487be57f1..406ae2ea8 100644 --- a/src/charon/plugins/kernel_pfkey/kernel_pfkey_ipsec.c +++ b/src/charon/plugins/kernel_pfkey/kernel_pfkey_ipsec.c @@ -31,6 +31,7 @@ #include #include #include +#include #include #include #include @@ -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 index 000000000..c9c835d74 --- /dev/null +++ b/src/charon/processing/jobs/migrate_job.c @@ -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 . + * + * 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 + +#include + + +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 index 000000000..d23236bc4 --- /dev/null +++ b/src/charon/processing/jobs/migrate_job.h @@ -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 . + * + * 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 +#include +#include +#include +#include + +/** + * 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_ @} */