diff options
Diffstat (limited to 'src/libcharon/sa/trap_manager.c')
-rw-r--r-- | src/libcharon/sa/trap_manager.c | 176 |
1 files changed, 111 insertions, 65 deletions
diff --git a/src/libcharon/sa/trap_manager.c b/src/libcharon/sa/trap_manager.c index 86d9f4c22..37426fc47 100644 --- a/src/libcharon/sa/trap_manager.c +++ b/src/libcharon/sa/trap_manager.c @@ -1,5 +1,5 @@ /* - * Copyright (C) 2011 Tobias Brunner + * Copyright (C) 2011-2012 Tobias Brunner * Copyright (C) 2009 Martin Willi * Hochschule fuer Technik Rapperswil * @@ -19,7 +19,7 @@ #include <hydra.h> #include <daemon.h> #include <threading/rwlock.h> -#include <utils/linked_list.h> +#include <collections/linked_list.h> typedef struct private_trap_manager_t private_trap_manager_t; @@ -92,49 +92,28 @@ static void destroy_entry(entry_t *entry) } METHOD(trap_manager_t, install, u_int32_t, - private_trap_manager_t *this, peer_cfg_t *peer, child_cfg_t *child) + private_trap_manager_t *this, peer_cfg_t *peer, child_cfg_t *child, + u_int32_t reqid) { - entry_t *entry; + entry_t *entry, *found = NULL; ike_cfg_t *ike_cfg; child_sa_t *child_sa; host_t *me, *other; - linked_list_t *my_ts, *other_ts; + linked_list_t *my_ts, *other_ts, *list; enumerator_t *enumerator; - bool found = FALSE; status_t status; - u_int32_t reqid; - - /* check if not already done */ - this->lock->read_lock(this->lock); - 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->lock->unlock(this->lock); - 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), + other = host_create_from_dns(ike_cfg->get_other_addr(ike_cfg, NULL), 0, ike_cfg->get_other_port(ike_cfg)); if (!other || other->is_anyaddr(other)) { + DESTROY_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), + me = host_create_from_dns(ike_cfg->get_my_addr(ike_cfg, NULL), other->get_family(other), ike_cfg->get_my_port(ike_cfg)); if (!me || me->is_anyaddr(me)) { @@ -150,12 +129,38 @@ METHOD(trap_manager_t, install, u_int32_t, me->set_port(me, ike_cfg->get_my_port(ike_cfg)); } + this->lock->write_lock(this->lock); + 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))) + { + this->traps->remove_at(this->traps, enumerator); + found = entry; + break; + } + } + enumerator->destroy(enumerator); + this->lock->unlock(this->lock); + + if (found) + { /* config might have changed so update everything */ + DBG1(DBG_CFG, "updating already routed CHILD_SA '%s'", + child->get_name(child)); + reqid = found->child_sa->get_reqid(found->child_sa); + } + /* 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 = child_sa_create(me, other, child, reqid, FALSE); + + list = linked_list_create_with_items(me, NULL); + my_ts = child->get_traffic_selectors(child, TRUE, NULL, list); + list->destroy_offset(list, offsetof(host_t, destroy)); + + list = linked_list_create_with_items(other, NULL); + other_ts = child->get_traffic_selectors(child, FALSE, NULL, list); + list->destroy_offset(list, offsetof(host_t, destroy)); /* while we don't know the finally negotiated protocol (ESP|AH), we * could iterate all proposals for a best guess (TODO). But as we @@ -167,21 +172,30 @@ METHOD(trap_manager_t, install, u_int32_t, 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 = 0; + /* hold off destroying the CHILD_SA until we released the lock */ + } + else + { + INIT(entry, + .child_sa = child_sa, + .peer_cfg = peer->get_ref(peer), + ); + this->lock->write_lock(this->lock); + this->traps->insert_last(this->traps, entry); + this->lock->unlock(this->lock); + reqid = child_sa->get_reqid(child_sa); } - reqid = child_sa->get_reqid(child_sa); - INIT(entry, - .child_sa = child_sa, - .peer_cfg = peer->get_ref(peer), - ); - - this->lock->write_lock(this->lock); - this->traps->insert_last(this->traps, entry); - this->lock->unlock(this->lock); - + if (status != SUCCESS) + { + child_sa->destroy(child_sa); + } + if (found) + { + destroy_entry(found); + } return reqid; } @@ -241,6 +255,31 @@ METHOD(trap_manager_t, create_enumerator, enumerator_t*, (void*)this->lock->unlock); } +METHOD(trap_manager_t, find_reqid, u_int32_t, + private_trap_manager_t *this, child_cfg_t *child) +{ + enumerator_t *enumerator; + child_cfg_t *current; + entry_t *entry; + u_int32_t reqid = 0; + + this->lock->read_lock(this->lock); + enumerator = this->traps->create_enumerator(this->traps); + while (enumerator->enumerate(enumerator, &entry)) + { + current = entry->child_sa->get_config(entry->child_sa); + if (streq(current->get_name(current), child->get_name(child))) + { + reqid = entry->child_sa->get_reqid(entry->child_sa); + break; + } + } + enumerator->destroy(enumerator); + this->lock->unlock(this->lock); + + return reqid; +} + METHOD(trap_manager_t, acquire, void, private_trap_manager_t *this, u_int32_t reqid, traffic_selector_t *src, traffic_selector_t *dst) @@ -284,26 +323,33 @@ METHOD(trap_manager_t, acquire, void, 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); - } - if (ike_sa->initiate(ike_sa, child, reqid, src, dst) != DESTROY_ME) + if (ike_sa) { - /* make sure the entry is still there */ - this->lock->read_lock(this->lock); - if (this->traps->find_first(this->traps, NULL, - (void**)&found) == SUCCESS) + if (ike_sa->get_peer_cfg(ike_sa) == NULL) { - found->ike_sa = ike_sa; + ike_sa->set_peer_cfg(ike_sa, peer); + } + if (ike_sa->get_version(ike_sa) == IKEV1) + { /* in IKEv1, don't prepend the acquiring packet TS, as we only + * have a single TS that we can establish in a Quick Mode. */ + src = dst = NULL; + } + if (ike_sa->initiate(ike_sa, child, reqid, src, dst) != DESTROY_ME) + { + /* make sure the entry is still there */ + this->lock->read_lock(this->lock); + if (this->traps->find_first(this->traps, NULL, + (void**)&found) == SUCCESS) + { + found->ike_sa = ike_sa; + } + this->lock->unlock(this->lock); + charon->ike_sa_manager->checkin(charon->ike_sa_manager, ike_sa); + } + else + { + ike_sa->destroy(ike_sa); } - this->lock->unlock(this->lock); - charon->ike_sa_manager->checkin(charon->ike_sa_manager, ike_sa); - } - else - { - charon->ike_sa_manager->checkin_and_destroy( - charon->ike_sa_manager, ike_sa); } peer->destroy(peer); } @@ -399,6 +445,7 @@ trap_manager_t *trap_manager_create(void) .install = _install, .uninstall = _uninstall, .create_enumerator = _create_enumerator, + .find_reqid = _find_reqid, .acquire = _acquire, .flush = _flush, .destroy = _destroy, @@ -417,4 +464,3 @@ trap_manager_t *trap_manager_create(void) return &this->public; } - |