From eb8ed130afc7f8587da449b2bfaae721e1fe7881 Mon Sep 17 00:00:00 2001 From: Martin Willi Date: Wed, 6 May 2009 19:45:11 +0200 Subject: [PATCH] added a trap-manager to handle routed policies outside of IKE_SAs --- src/charon/Makefile.am | 1 + src/charon/sa/trap_manager.c | 297 +++++++++++++++++++++++++++++++++++ src/charon/sa/trap_manager.h | 82 ++++++++++ 3 files changed, 380 insertions(+) create mode 100644 src/charon/sa/trap_manager.c create mode 100644 src/charon/sa/trap_manager.h diff --git a/src/charon/Makefile.am b/src/charon/Makefile.am index 1d27d13cd..475010825 100644 --- a/src/charon/Makefile.am +++ b/src/charon/Makefile.am @@ -78,6 +78,7 @@ sa/ike_sa_id.c sa/ike_sa_id.h \ sa/ike_sa_manager.c sa/ike_sa_manager.h \ sa/task_manager.c sa/task_manager.h \ sa/keymat.c sa/keymat.h \ +sa/trap_manager.c sa/trap_manager.h \ sa/tasks/child_create.c sa/tasks/child_create.h \ sa/tasks/child_delete.c sa/tasks/child_delete.h \ sa/tasks/child_rekey.c sa/tasks/child_rekey.h \ diff --git a/src/charon/sa/trap_manager.c b/src/charon/sa/trap_manager.c new file mode 100644 index 000000000..15d232a85 --- /dev/null +++ b/src/charon/sa/trap_manager.c @@ -0,0 +1,297 @@ +/* + * Copyright (C) 2009 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$ + */ + +#include "trap_manager.h" + +#include +#include +#include + + +typedef struct private_trap_manager_t private_trap_manager_t; + +/** + * Private data of an trap_manager_t object. + */ +struct private_trap_manager_t { + + /** + * Public trap_manager_t interface. + */ + trap_manager_t public; + + /** + * Installed traps, as entry_t + */ + linked_list_t *traps; + + /** + * mutex to lock traps list + */ + mutex_t *mutex; +}; + +/** + * A installed trap entry + */ +typedef struct { + /** ref to peer_cfg to initiate */ + peer_cfg_t *peer_cfg; + /** ref to instanciated CHILD_SA */ + child_sa_t *child_sa; +} entry_t; + +/** + * actually uninstall and destroy an installed entry + */ +static void destroy_entry(entry_t *entry) +{ + entry->child_sa->destroy(entry->child_sa); + entry->peer_cfg->destroy(entry->peer_cfg); + free(entry); +} + +/** + * Implementation of trap_manager_t.install + */ +static u_int install(private_trap_manager_t *this, peer_cfg_t *peer, + child_cfg_t *child) +{ + entry_t *entry; + ike_cfg_t *ike_cfg; + child_sa_t *child_sa; + host_t *me, *other; + linked_list_t *my_ts, *other_ts; + enumerator_t *enumerator; + bool found = FALSE; + status_t status; + u_int reqid; + + /* check if not already done */ + this->mutex->lock(this->mutex); + enumerator = this->traps->create_enumerator(this->traps); + while (enumerator->enumerate(enumerator, &entry)) + { + if (streq(entry->child_sa->get_name(entry->child_sa), + child->get_name(child))) + { + found = TRUE; + break; + } + } + enumerator->destroy(enumerator); + this->mutex->unlock(this->mutex); + if (found) + { + DBG1(DBG_CFG, "CHILD_SA named '%s' already routed", + child->get_name(child)); + return 0; + } + + /* try to resolve addresses */ + ike_cfg = peer->get_ike_cfg(peer); + other = host_create_from_dns(ike_cfg->get_other_addr(ike_cfg), + 0, IKEV2_UDP_PORT); + if (!other) + { + DBG1(DBG_CFG, "installing trap failed, remote address unknown"); + return 0; + } + me = host_create_from_dns(ike_cfg->get_my_addr(ike_cfg), + other->get_family(other), IKEV2_UDP_PORT); + if (!me || me->is_anyaddr(me)) + { + DESTROY_IF(me); + me = charon->kernel_interface->get_source_addr( + charon->kernel_interface, other, NULL); + if (!me) + { + DBG1(DBG_CFG, "installing trap failed, local address unknown"); + other->destroy(other); + return 0; + } + me->set_port(me, IKEV2_UDP_PORT); + } + + /* create and route CHILD_SA */ + child_sa = child_sa_create(me, other, child, 0, FALSE); + my_ts = child->get_traffic_selectors(child, TRUE, NULL, me); + other_ts = child->get_traffic_selectors(child, FALSE, NULL, other); + me->destroy(me); + other->destroy(other); + + child_sa->set_mode(child_sa, child->get_mode(child)); + status = child_sa->add_policies(child_sa, my_ts, other_ts); + my_ts->destroy_offset(my_ts, offsetof(traffic_selector_t, destroy)); + other_ts->destroy_offset(other_ts, offsetof(traffic_selector_t, destroy)); + if (status != SUCCESS) + { + child_sa->destroy(child_sa); + DBG1(DBG_CFG, "installing trap failed"); + return 0; + } + + reqid = child_sa->get_reqid(child_sa); + entry = malloc_thing(entry_t); + entry->child_sa = child_sa; + entry->peer_cfg = peer->get_ref(peer); + + this->mutex->lock(this->mutex); + this->traps->insert_last(this->traps, entry); + this->mutex->unlock(this->mutex); + + return reqid; +} + +/** + * Implementation of trap_manager_t.uninstall + */ +static bool uninstall(private_trap_manager_t *this, u_int reqid) +{ + enumerator_t *enumerator; + entry_t *entry, *found = NULL; + + this->mutex->lock(this->mutex); + enumerator = this->traps->create_enumerator(this->traps); + while (enumerator->enumerate(enumerator, &entry)) + { + if (entry->child_sa->get_reqid(entry->child_sa) == reqid) + { + this->traps->remove_at(this->traps, enumerator); + found = entry; + break; + } + } + enumerator->destroy(enumerator); + this->mutex->unlock(this->mutex); + + if (!found) + { + DBG1(DBG_CFG, "trap %d not found to uninstall", reqid); + return FALSE; + } + + destroy_entry(found); + return TRUE; +} + +/** + * convert enumerated entries to peer_cfg, child_sa + */ +static bool trap_filter(mutex_t *mutex, entry_t **entry, peer_cfg_t **peer_cfg, + void *none, child_sa_t **child_sa) +{ + if (peer_cfg) + { + *peer_cfg = (*entry)->peer_cfg; + } + if (child_sa) + { + *child_sa = (*entry)->child_sa; + } + return TRUE; +} + +/** + * Implementation of trap_manager_t.create_enumerator + */ +static enumerator_t* create_enumerator(private_trap_manager_t *this) +{ + this->mutex->lock(this->mutex); + return enumerator_create_filter(this->traps->create_enumerator(this->traps), + (void*)trap_filter, this->mutex, + (void*)this->mutex->unlock); +} + +/** + * Implementation of trap_manager_t.acquire + */ +static void acquire(private_trap_manager_t *this, u_int reqid, + traffic_selector_t *src, traffic_selector_t *dst) +{ + enumerator_t *enumerator; + entry_t *entry, *found = NULL; + peer_cfg_t *peer; + child_cfg_t *child; + ike_sa_t *ike_sa; + + this->mutex->lock(this->mutex); + enumerator = this->traps->create_enumerator(this->traps); + while (enumerator->enumerate(enumerator, &entry)) + { + if (entry->child_sa->get_reqid(entry->child_sa) == reqid) + { + found = entry; + break; + } + } + enumerator->destroy(enumerator); + + if (!found) + { + DBG1(DBG_CFG, "trap not found, unable to acquire reqid %d",reqid); + return; + } + + child = found->child_sa->get_config(found->child_sa); + peer = found->peer_cfg; + ike_sa = charon->ike_sa_manager->checkout_by_config(charon->ike_sa_manager, + peer); + if (ike_sa->get_peer_cfg(ike_sa) == NULL) + { + ike_sa->set_peer_cfg(ike_sa, peer); + } + child->get_ref(child); + this->mutex->unlock(this->mutex); + if (ike_sa->initiate(ike_sa, child) != DESTROY_ME) + { + charon->ike_sa_manager->checkin(charon->ike_sa_manager, ike_sa); + return; + } + charon->ike_sa_manager->checkin_and_destroy(charon->ike_sa_manager, ike_sa); +} + +/** + * Implementation of trap_manager_t.destroy. + */ +static void destroy(private_trap_manager_t *this) +{ + this->traps->invoke_function(this->traps, (void*)destroy_entry); + this->traps->destroy(this->traps); + this->mutex->destroy(this->mutex); + free(this); +} + +/** + * See header + */ +trap_manager_t *trap_manager_create() +{ + private_trap_manager_t *this = malloc_thing(private_trap_manager_t); + + this->public.install = (u_int(*)(trap_manager_t*, peer_cfg_t *peer, child_cfg_t *child))install; + this->public.uninstall = (bool(*)(trap_manager_t*, u_int id))uninstall; + this->public.create_enumerator = (enumerator_t*(*)(trap_manager_t*))create_enumerator; + this->public.acquire = (void(*)(trap_manager_t*, u_int reqid, traffic_selector_t *src, traffic_selector_t *dst))acquire; + this->public.destroy = (void(*)(trap_manager_t*))destroy; + + this->traps = linked_list_create(); + this->mutex = mutex_create(MUTEX_DEFAULT); + + return &this->public; +} + diff --git a/src/charon/sa/trap_manager.h b/src/charon/sa/trap_manager.h new file mode 100644 index 000000000..21c68438c --- /dev/null +++ b/src/charon/sa/trap_manager.h @@ -0,0 +1,82 @@ +/* + * Copyright (C) 2009 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$ + */ + +/** + * @defgroup trap_manager trap_manager + * @{ @ingroup sa + */ + +#ifndef TRAP_MANAGER_H_ +#define TRAP_MANAGER_H_ + +#include +#include +#include + +typedef struct trap_manager_t trap_manager_t; + +/** + * Manage policies to create SAs from traffic. + */ +struct trap_manager_t { + + /** + * Install a policy as a trap. + * + * @param peer peer configuration to initiate on trap + * @param child child configuration to install as a trap + * @return reqid of installed CHILD_SA, 0 if failed + */ + u_int (*install)(trap_manager_t *this, peer_cfg_t *peer, child_cfg_t *child); + + /** + * Uninstall a trap policy. + * + * @param id reqid of CHILD_SA to uninstall, returned by install() + * @return TRUE if uninstalled successfully + */ + bool (*uninstall)(trap_manager_t *this, u_int reqid); + + /** + * Create an enumerator over all installed traps. + * + * @return enumerator over (peer_cfg_t, child_sa_t) + */ + enumerator_t* (*create_enumerator)(trap_manager_t *this); + + /** + * Acquire an SA triggered by an installed trap. + * + * @param reqid requid of the triggering CHILD_SA + * @param src source of the triggering packet + * @param dst destination of the triggering packet + */ + void (*acquire)(trap_manager_t *this, u_int reqid, traffic_selector_t *src, + traffic_selector_t *dst); + + /** + * Destroy a trap_manager_t. + */ + void (*destroy)(trap_manager_t *this); +}; + +/** + * Create a trap_manager instance. + */ +trap_manager_t *trap_manager_create(); + +#endif /* TRAP_MANAGER_ @}*/