diff options
author | Yves-Alexis Perez <corsac@corsac.net> | 2012-06-28 21:16:07 +0200 |
---|---|---|
committer | Yves-Alexis Perez <corsac@corsac.net> | 2012-06-28 21:16:07 +0200 |
commit | b34738ed08c2227300d554b139e2495ca5da97d6 (patch) | |
tree | 62f33b52820f2e49f0e53c0f8c636312037c8054 /src/libcharon/sa | |
parent | 0a9d51a49042a68daa15b0c74a2b7f152f52606b (diff) | |
download | vyos-strongswan-b34738ed08c2227300d554b139e2495ca5da97d6.tar.gz vyos-strongswan-b34738ed08c2227300d554b139e2495ca5da97d6.zip |
Imported Upstream version 4.6.4
Diffstat (limited to 'src/libcharon/sa')
50 files changed, 1937 insertions, 2665 deletions
diff --git a/src/libcharon/sa/authenticators/authenticator.c b/src/libcharon/sa/authenticators/authenticator.c index 83f5fbaad..9ffe661cc 100644 --- a/src/libcharon/sa/authenticators/authenticator.c +++ b/src/libcharon/sa/authenticators/authenticator.c @@ -28,11 +28,12 @@ ENUM_BEGIN(auth_method_names, AUTH_RSA, AUTH_DSS, "RSA signature", "pre-shared key", "DSS signature"); -ENUM_NEXT(auth_method_names, AUTH_ECDSA_256, AUTH_ECDSA_521, AUTH_DSS, +ENUM_NEXT(auth_method_names, AUTH_ECDSA_256, AUTH_GSPM, AUTH_DSS, "ECDSA-256 signature", "ECDSA-384 signature", - "ECDSA-521 signature"); -ENUM_END(auth_method_names, AUTH_ECDSA_521); + "ECDSA-521 signature", + "secure password method"); +ENUM_END(auth_method_names, AUTH_GSPM); /** * Described in header. diff --git a/src/libcharon/sa/authenticators/authenticator.h b/src/libcharon/sa/authenticators/authenticator.h index d27e006a3..5042e4a73 100644 --- a/src/libcharon/sa/authenticators/authenticator.h +++ b/src/libcharon/sa/authenticators/authenticator.h @@ -67,6 +67,12 @@ enum auth_method_t { * ECDSA with SHA-512 on the P-521 curve as specified in RFC 4754 */ AUTH_ECDSA_521 = 11, + + /** + * Generic Secure Password Authentication Method as specified in RFC 6467 + */ + AUTH_GSPM = 12, + }; /** diff --git a/src/libcharon/sa/authenticators/eap/eap_method.c b/src/libcharon/sa/authenticators/eap/eap_method.c index 0fa4a00c5..a05e8c59a 100644 --- a/src/libcharon/sa/authenticators/eap/eap_method.c +++ b/src/libcharon/sa/authenticators/eap/eap_method.c @@ -15,8 +15,28 @@ #include "eap_method.h" +#include <daemon.h> + ENUM(eap_role_names, EAP_SERVER, EAP_PEER, "EAP_SERVER", "EAP_PEER", ); +/** + * See header + */ +bool eap_method_register(plugin_t *plugin, plugin_feature_t *feature, + bool reg, void *data) +{ + if (reg) + { + charon->eap->add_method(charon->eap, feature->arg.eap, 0, + feature->type == FEATURE_EAP_SERVER ? EAP_SERVER : EAP_PEER, + (eap_constructor_t)data); + } + else + { + charon->eap->remove_method(charon->eap, (eap_constructor_t)data); + } + return TRUE; +} diff --git a/src/libcharon/sa/authenticators/eap/eap_method.h b/src/libcharon/sa/authenticators/eap/eap_method.h index 0eab2b5ff..6242a5a6e 100644 --- a/src/libcharon/sa/authenticators/eap/eap_method.h +++ b/src/libcharon/sa/authenticators/eap/eap_method.h @@ -25,6 +25,7 @@ typedef struct eap_method_t eap_method_t; typedef enum eap_role_t eap_role_t; #include <library.h> +#include <plugins/plugin.h> #include <utils/identification.h> #include <eap/eap.h> #include <encoding/payloads/eap_payload.h> @@ -159,4 +160,18 @@ struct eap_method_t { typedef eap_method_t *(*eap_constructor_t)(identification_t *server, identification_t *peer); +/** + * Helper function to (un-)register EAP methods from plugin features. + * + * This function is a plugin_feature_callback_t and can be used with the + * PLUGIN_CALLBACK macro to register a EAP method constructor. + * + * @param plugin plugin registering the EAP method constructor + * @param feature associated plugin feature + * @param reg TRUE to register, FALSE to unregister. + * @param data data passed to callback, an eap_constructor_t + */ +bool eap_method_register(plugin_t *plugin, plugin_feature_t *feature, + bool reg, void *data); + #endif /** EAP_METHOD_H_ @}*/ diff --git a/src/libcharon/sa/authenticators/eap/sim_card.h b/src/libcharon/sa/authenticators/eap/sim_card.h deleted file mode 100644 index 5f5dc580b..000000000 --- a/src/libcharon/sa/authenticators/eap/sim_card.h +++ /dev/null @@ -1,125 +0,0 @@ -/* - * Copyright (C) 2008-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 <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. - */ - -/** - * @defgroup sim_card sim_card - * @{ @ingroup eap - */ - -#ifndef SIM_CARD_H_ -#define SIM_CARD_H_ - -typedef struct sim_card_t sim_card_t; - -/** - * Interface for a (U)SIM card (used as EAP client). - * - * The SIM card completes triplets/quintuplets requested in a challenge - * received from the server. - * An implementation supporting only one of SIM/AKA authentication may - * implement the other methods with return_false()/return NOT_SUPPORTED/NULL. - */ -struct sim_card_t { - - /** - * Calculate SRES/KC from a RAND for SIM authentication. - * - * @param id permanent identity to get a triplet for - * @param rand RAND input buffer, fixed size 16 bytes - * @param sres SRES output buffer, fixed size 4 byte - * @param kc KC output buffer, fixed size 8 bytes - * @return TRUE if SRES/KC calculated, FALSE on error/wrong identity - */ - bool (*get_triplet)(sim_card_t *this, identification_t *id, - char rand[SIM_RAND_LEN], char sres[SIM_SRES_LEN], - char kc[SIM_KC_LEN]); - - /** - * Calculate CK/IK/RES from RAND/AUTN for AKA authentication. - * - * If the received sequence number (in autn) is out of sync, INVALID_STATE - * is returned. - * The RES value is the only one with variable length. Pass a buffer - * of at least AKA_RES_MAX, the actual number of bytes is written to the - * res_len value. While the standard would allow any bit length between - * 32 and 128 bits, we support only full bytes for now. - * - * @param id permanent identity to request quintuplet for - * @param rand random value rand - * @param autn authentication token autn - * @param ck buffer receiving encryption key ck - * @param ik buffer receiving integrity key ik - * @param res buffer receiving authentication result res - * @param res_len nubmer of bytes written to res buffer - * @return SUCCESS, FAILED, or INVALID_STATE if out of sync - */ - status_t (*get_quintuplet)(sim_card_t *this, identification_t *id, - char rand[AKA_RAND_LEN], char autn[AKA_AUTN_LEN], - char ck[AKA_CK_LEN], char ik[AKA_IK_LEN], - char res[AKA_RES_MAX], int *res_len); - - /** - * Calculate AUTS from RAND for AKA resynchronization. - * - * @param id permanent identity to request quintuplet for - * @param rand random value rand - * @param auts resynchronization parameter auts - * @return TRUE if parameter generated successfully - */ - bool (*resync)(sim_card_t *this, identification_t *id, - char rand[AKA_RAND_LEN], char auts[AKA_AUTS_LEN]); - - /** - * Set the pseudonym to use for next authentication. - * - * @param id permanent identity of the peer - * @param pseudonym pseudonym identity received from the server - */ - void (*set_pseudonym)(sim_card_t *this, identification_t *id, - identification_t *pseudonym); - - /** - * Get the pseudonym previously stored via set_pseudonym(). - * - * @param id permanent identity of the peer - * @return associated pseudonym identity, NULL if none stored - */ - identification_t* (*get_pseudonym)(sim_card_t *this, identification_t *id); - - /** - * Store parameters to use for the next fast reauthentication. - * - * @param id permanent identity of the peer - * @param next next fast reauthentication identity to use - * @param mk master key MK to store for reauthentication - * @param counter counter value to store, host order - */ - void (*set_reauth)(sim_card_t *this, identification_t *id, - identification_t *next, char mk[HASH_SIZE_SHA1], - u_int16_t counter); - - /** - * Retrieve parameters for fast reauthentication stored via set_reauth(). - * - * @param id permanent identity of the peer - * @param mk buffer receiving master key MK - * @param counter pointer receiving counter value, in host order - * @return fast reauthentication identity, NULL if not found - */ - identification_t* (*get_reauth)(sim_card_t *this, identification_t *id, - char mk[HASH_SIZE_SHA1], u_int16_t *counter); -}; - -#endif /** SIM_CARD_H_ @}*/ diff --git a/src/libcharon/sa/authenticators/eap/sim_hooks.h b/src/libcharon/sa/authenticators/eap/sim_hooks.h deleted file mode 100644 index 0a675e4ab..000000000 --- a/src/libcharon/sa/authenticators/eap/sim_hooks.h +++ /dev/null @@ -1,53 +0,0 @@ -/* - * Copyright (C) 2008-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 <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. - */ - -/** - * @defgroup sim_hooks sim_hooks - * @{ @ingroup eap - */ - -#ifndef SIM_HOOKS_H_ -#define SIM_HOOKS_H_ - -typedef struct sim_hooks_t sim_hooks_t; - -/** - * Additional hooks invoked during EAP-SIM/AKA message processing. - */ -struct sim_hooks_t { - - /** - * SIM/AKA message parsing. - * - * As a SIM/AKA optionally contains encrypted attributes, the hook - * might get invoked twice, once before and once after decryption. - * - * @param message SIM/AKA message - * @param inbound TRUE for incoming messages, FALSE for outgoing - * @param decrypted TRUE if AT_ENCR_DATA has been decrypted - */ - void (*message)(sim_hooks_t *this, simaka_message_t *message, - bool inbound, bool decrypted); - - /** - * SIM/AKA encryption/authentication key hooks. - * - * @param k_encr derived SIM/AKA encryption key k_encr - * @param k_auth derived SIM/AKA authentication key k_auth - */ - void (*keys)(sim_hooks_t *this, chunk_t k_encr, chunk_t k_auth); -}; - -#endif /** SIM_HOOKS_H_ @}*/ diff --git a/src/libcharon/sa/authenticators/eap/sim_manager.c b/src/libcharon/sa/authenticators/eap/sim_manager.c deleted file mode 100644 index 9ccaf5298..000000000 --- a/src/libcharon/sa/authenticators/eap/sim_manager.c +++ /dev/null @@ -1,534 +0,0 @@ -/* - * Copyright (C) 2008 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. - */ - -#include "sim_manager.h" - -#include <daemon.h> -#include <utils/linked_list.h> -#include <threading/rwlock.h> - -typedef struct private_sim_manager_t private_sim_manager_t; - -/** - * Private data of an sim_manager_t object. - */ -struct private_sim_manager_t { - - /** - * Public sim_manager_t interface. - */ - sim_manager_t public; - - /** - * list of added cards - */ - linked_list_t *cards; - - /** - * list of added provider - */ - linked_list_t *providers; - - /** - * list of added hooks - */ - linked_list_t *hooks; - - /** - * lock for lists above - */ - rwlock_t *lock; -}; - -METHOD(sim_manager_t, add_card, void, - private_sim_manager_t *this, sim_card_t *card) -{ - this->lock->write_lock(this->lock); - this->cards->insert_last(this->cards, card); - this->lock->unlock(this->lock); -} - -METHOD(sim_manager_t, remove_card, void, - private_sim_manager_t *this, sim_card_t *card) -{ - this->lock->write_lock(this->lock); - this->cards->remove(this->cards, card, NULL); - this->lock->unlock(this->lock); -} - -METHOD(sim_manager_t, card_get_triplet, bool, - private_sim_manager_t *this, identification_t *id, - char rand[SIM_RAND_LEN], char sres[SIM_SRES_LEN], char kc[SIM_KC_LEN]) -{ - enumerator_t *enumerator; - sim_card_t *card; - int tried = 0; - - this->lock->read_lock(this->lock); - enumerator = this->cards->create_enumerator(this->cards); - while (enumerator->enumerate(enumerator, &card)) - { - if (card->get_triplet(card, id, rand, sres, kc)) - { - enumerator->destroy(enumerator); - this->lock->unlock(this->lock); - return TRUE; - } - tried++; - } - enumerator->destroy(enumerator); - this->lock->unlock(this->lock); - DBG1(DBG_IKE, "tried %d SIM cards, but none has triplets for '%Y'", - tried, id); - return FALSE; -} - -METHOD(sim_manager_t, card_get_quintuplet, status_t, - private_sim_manager_t *this, identification_t *id, char rand[AKA_RAND_LEN], - char autn[AKA_AUTN_LEN], char ck[AKA_CK_LEN], char ik[AKA_IK_LEN], - char res[AKA_RES_MAX], int *res_len) -{ - enumerator_t *enumerator; - sim_card_t *card; - status_t status = NOT_FOUND; - int tried = 0; - - this->lock->read_lock(this->lock); - enumerator = this->cards->create_enumerator(this->cards); - while (enumerator->enumerate(enumerator, &card)) - { - status = card->get_quintuplet(card, id, rand, autn, ck, ik, res, res_len); - switch (status) - { /* try next on error, but not on INVALID_STATE */ - case SUCCESS: - case INVALID_STATE: - enumerator->destroy(enumerator); - this->lock->unlock(this->lock); - return status; - case NOT_SUPPORTED: - case FAILED: - default: - tried++; - continue; - } - } - enumerator->destroy(enumerator); - this->lock->unlock(this->lock); - DBG1(DBG_IKE, "tried %d SIM cards, but none has quintuplets for '%Y'", - tried, id); - return status; -} - -METHOD(sim_manager_t, card_resync, bool, - private_sim_manager_t *this, identification_t *id, - char rand[AKA_RAND_LEN], char auts[AKA_AUTS_LEN]) -{ - enumerator_t *enumerator; - sim_card_t *card; - - this->lock->read_lock(this->lock); - enumerator = this->cards->create_enumerator(this->cards); - while (enumerator->enumerate(enumerator, &card)) - { - if (card->resync(card, id, rand, auts)) - { - enumerator->destroy(enumerator); - this->lock->unlock(this->lock); - return TRUE; - } - } - enumerator->destroy(enumerator); - this->lock->unlock(this->lock); - return FALSE; -} - -METHOD(sim_manager_t, card_set_pseudonym, void, - private_sim_manager_t *this, identification_t *id, - identification_t *pseudonym) -{ - enumerator_t *enumerator; - sim_card_t *card; - - DBG1(DBG_IKE, "storing pseudonym '%Y' for '%Y'", pseudonym, id); - - this->lock->read_lock(this->lock); - enumerator = this->cards->create_enumerator(this->cards); - while (enumerator->enumerate(enumerator, &card)) - { - card->set_pseudonym(card, id, pseudonym); - } - enumerator->destroy(enumerator); - this->lock->unlock(this->lock); -} - -METHOD(sim_manager_t, card_get_pseudonym, identification_t*, - private_sim_manager_t *this, identification_t *id) -{ - enumerator_t *enumerator; - sim_card_t *card; - identification_t *pseudonym = NULL; - - this->lock->read_lock(this->lock); - enumerator = this->cards->create_enumerator(this->cards); - while (enumerator->enumerate(enumerator, &card)) - { - pseudonym = card->get_pseudonym(card, id); - if (pseudonym) - { - DBG1(DBG_IKE, "using stored pseudonym identity '%Y' " - "instead of '%Y'", pseudonym, id); - break; - } - } - enumerator->destroy(enumerator); - this->lock->unlock(this->lock); - return pseudonym; -} - -METHOD(sim_manager_t, card_set_reauth, void, - private_sim_manager_t *this, identification_t *id, identification_t *next, - char mk[HASH_SIZE_SHA1], u_int16_t counter) -{ - enumerator_t *enumerator; - sim_card_t *card; - - DBG1(DBG_IKE, "storing next reauthentication identity '%Y' for '%Y'", - next, id); - - this->lock->read_lock(this->lock); - enumerator = this->cards->create_enumerator(this->cards); - while (enumerator->enumerate(enumerator, &card)) - { - card->set_reauth(card, id, next, mk, counter); - } - enumerator->destroy(enumerator); - this->lock->unlock(this->lock); -} - -METHOD(sim_manager_t, card_get_reauth, identification_t*, - private_sim_manager_t *this, identification_t *id, char mk[HASH_SIZE_SHA1], - u_int16_t *counter) -{ - enumerator_t *enumerator; - sim_card_t *card; - identification_t *reauth = NULL; - - this->lock->read_lock(this->lock); - enumerator = this->cards->create_enumerator(this->cards); - while (enumerator->enumerate(enumerator, &card)) - { - reauth = card->get_reauth(card, id, mk, counter); - if (reauth) - { - DBG1(DBG_IKE, "using stored reauthentication identity '%Y' " - "instead of '%Y'", reauth, id); - break; - } - } - enumerator->destroy(enumerator); - this->lock->unlock(this->lock); - return reauth; -} - -METHOD(sim_manager_t, add_provider, void, - private_sim_manager_t *this, sim_provider_t *provider) -{ - this->lock->write_lock(this->lock); - this->providers->insert_last(this->providers, provider); - this->lock->unlock(this->lock); -} - -METHOD(sim_manager_t, remove_provider, void, - private_sim_manager_t *this, sim_provider_t *provider) -{ - this->lock->write_lock(this->lock); - this->providers->remove(this->providers, provider, NULL); - this->lock->unlock(this->lock); -} - -METHOD(sim_manager_t, provider_get_triplet, bool, - private_sim_manager_t *this, identification_t *id, char rand[SIM_RAND_LEN], - char sres[SIM_SRES_LEN], char kc[SIM_KC_LEN]) -{ - enumerator_t *enumerator; - sim_provider_t *provider; - int tried = 0; - - this->lock->read_lock(this->lock); - enumerator = this->providers->create_enumerator(this->providers); - while (enumerator->enumerate(enumerator, &provider)) - { - if (provider->get_triplet(provider, id, rand, sres, kc)) - { - enumerator->destroy(enumerator); - this->lock->unlock(this->lock); - return TRUE; - } - tried++; - } - enumerator->destroy(enumerator); - this->lock->unlock(this->lock); - DBG1(DBG_IKE, "tried %d SIM providers, but none had a triplet for '%Y'", - tried, id); - return FALSE; -} - -METHOD(sim_manager_t, provider_get_quintuplet, bool, - private_sim_manager_t *this, identification_t *id, char rand[AKA_RAND_LEN], - char xres[AKA_RES_MAX], int *xres_len, char ck[AKA_CK_LEN], - char ik[AKA_IK_LEN], char autn[AKA_AUTN_LEN]) -{ - enumerator_t *enumerator; - sim_provider_t *provider; - int tried = 0; - - this->lock->read_lock(this->lock); - enumerator = this->providers->create_enumerator(this->providers); - while (enumerator->enumerate(enumerator, &provider)) - { - if (provider->get_quintuplet(provider, id, rand, xres, xres_len, - ck, ik, autn)) - { - enumerator->destroy(enumerator); - this->lock->unlock(this->lock); - return TRUE; - } - } - enumerator->destroy(enumerator); - this->lock->unlock(this->lock); - DBG1(DBG_IKE, "tried %d SIM providers, but none had a quintuplet for '%Y'", - tried, id); - return FALSE; -} - -METHOD(sim_manager_t, provider_resync, bool, - private_sim_manager_t *this, identification_t *id, - char rand[AKA_RAND_LEN], char auts[AKA_AUTS_LEN]) -{ - enumerator_t *enumerator; - sim_provider_t *provider; - - this->lock->read_lock(this->lock); - enumerator = this->providers->create_enumerator(this->providers); - while (enumerator->enumerate(enumerator, &provider)) - { - if (provider->resync(provider, id, rand, auts)) - { - enumerator->destroy(enumerator); - this->lock->unlock(this->lock); - return TRUE; - } - } - enumerator->destroy(enumerator); - this->lock->unlock(this->lock); - return FALSE; -} - -METHOD(sim_manager_t, provider_is_pseudonym, identification_t*, - private_sim_manager_t *this, identification_t *id) -{ - enumerator_t *enumerator; - sim_provider_t *provider; - identification_t *permanent = NULL; - - this->lock->read_lock(this->lock); - enumerator = this->providers->create_enumerator(this->providers); - while (enumerator->enumerate(enumerator, &provider)) - { - permanent = provider->is_pseudonym(provider, id); - if (permanent) - { - DBG1(DBG_IKE, "received pseudonym identity '%Y' " - "mapping to '%Y'", id, permanent); - break; - } - } - enumerator->destroy(enumerator); - this->lock->unlock(this->lock); - return permanent; -} - -METHOD(sim_manager_t, provider_gen_pseudonym, identification_t*, - private_sim_manager_t *this, identification_t *id) -{ - enumerator_t *enumerator; - sim_provider_t *provider; - identification_t *pseudonym = NULL; - - this->lock->read_lock(this->lock); - enumerator = this->providers->create_enumerator(this->providers); - while (enumerator->enumerate(enumerator, &provider)) - { - pseudonym = provider->gen_pseudonym(provider, id); - if (pseudonym) - { - DBG1(DBG_IKE, "proposing new pseudonym '%Y'", pseudonym); - break; - } - } - enumerator->destroy(enumerator); - this->lock->unlock(this->lock); - return pseudonym; -} - -METHOD(sim_manager_t, provider_is_reauth, identification_t*, - private_sim_manager_t *this, identification_t *id, char mk[HASH_SIZE_SHA1], - u_int16_t *counter) -{ - enumerator_t *enumerator; - sim_provider_t *provider; - identification_t *permanent = NULL; - - this->lock->read_lock(this->lock); - enumerator = this->providers->create_enumerator(this->providers); - while (enumerator->enumerate(enumerator, &provider)) - { - permanent = provider->is_reauth(provider, id, mk, counter); - if (permanent) - { - DBG1(DBG_IKE, "received reauthentication identity '%Y' " - "mapping to '%Y'", id, permanent); - break; - } - } - enumerator->destroy(enumerator); - this->lock->unlock(this->lock); - return permanent; -} - -METHOD(sim_manager_t, provider_gen_reauth, identification_t*, - private_sim_manager_t *this, identification_t *id, char mk[HASH_SIZE_SHA1]) -{ - enumerator_t *enumerator; - sim_provider_t *provider; - identification_t *reauth = NULL; - - this->lock->read_lock(this->lock); - enumerator = this->providers->create_enumerator(this->providers); - while (enumerator->enumerate(enumerator, &provider)) - { - reauth = provider->gen_reauth(provider, id, mk); - if (reauth) - { - DBG1(DBG_IKE, "proposing new reauthentication identity '%Y'", reauth); - break; - } - } - enumerator->destroy(enumerator); - this->lock->unlock(this->lock); - return reauth; -} - -METHOD(sim_manager_t, add_hooks, void, - private_sim_manager_t *this, sim_hooks_t *hooks) -{ - this->lock->write_lock(this->lock); - this->hooks->insert_last(this->hooks, hooks); - this->lock->unlock(this->lock); -} - -METHOD(sim_manager_t, remove_hooks, void, - private_sim_manager_t *this, sim_hooks_t *hooks) -{ - this->lock->write_lock(this->lock); - this->hooks->remove(this->hooks, hooks, NULL); - this->lock->unlock(this->lock); -} - -METHOD(sim_manager_t, message_hook, void, - private_sim_manager_t *this, simaka_message_t *message, - bool inbound, bool decrypted) -{ - enumerator_t *enumerator; - sim_hooks_t *hooks; - - this->lock->read_lock(this->lock); - enumerator = this->hooks->create_enumerator(this->hooks); - while (enumerator->enumerate(enumerator, &hooks)) - { - hooks->message(hooks, message, inbound, decrypted); - } - enumerator->destroy(enumerator); - this->lock->unlock(this->lock); -} - -METHOD(sim_manager_t, key_hook, void, - private_sim_manager_t *this, chunk_t k_encr, chunk_t k_auth) -{ - enumerator_t *enumerator; - sim_hooks_t *hooks; - - this->lock->read_lock(this->lock); - enumerator = this->hooks->create_enumerator(this->hooks); - while (enumerator->enumerate(enumerator, &hooks)) - { - hooks->keys(hooks, k_encr, k_auth); - } - enumerator->destroy(enumerator); - this->lock->unlock(this->lock); -} - -METHOD(sim_manager_t, destroy, void, - private_sim_manager_t *this) -{ - this->cards->destroy(this->cards); - this->providers->destroy(this->providers); - this->hooks->destroy(this->hooks); - this->lock->destroy(this->lock); - free(this); -} - -/** - * See header - */ -sim_manager_t *sim_manager_create() -{ - private_sim_manager_t *this; - - INIT(this, - .public = { - .add_card = _add_card, - .remove_card = _remove_card, - .card_get_triplet = _card_get_triplet, - .card_get_quintuplet = _card_get_quintuplet, - .card_resync = _card_resync, - .card_set_pseudonym = _card_set_pseudonym, - .card_get_pseudonym = _card_get_pseudonym, - .card_set_reauth = _card_set_reauth, - .card_get_reauth = _card_get_reauth, - .add_provider = _add_provider, - .remove_provider = _remove_provider, - .provider_get_triplet = _provider_get_triplet, - .provider_get_quintuplet = _provider_get_quintuplet, - .provider_resync = _provider_resync, - .provider_is_pseudonym = _provider_is_pseudonym, - .provider_gen_pseudonym = _provider_gen_pseudonym, - .provider_is_reauth = _provider_is_reauth, - .provider_gen_reauth = _provider_gen_reauth, - .add_hooks = _add_hooks, - .remove_hooks = _remove_hooks, - .message_hook = _message_hook, - .key_hook = _key_hook, - .destroy = _destroy, - }, - .cards = linked_list_create(), - .providers = linked_list_create(), - .hooks = linked_list_create(), - .lock = rwlock_create(RWLOCK_TYPE_DEFAULT), - ); - - return &this->public; -} - diff --git a/src/libcharon/sa/authenticators/eap/sim_manager.h b/src/libcharon/sa/authenticators/eap/sim_manager.h deleted file mode 100644 index db4a65011..000000000 --- a/src/libcharon/sa/authenticators/eap/sim_manager.h +++ /dev/null @@ -1,291 +0,0 @@ -/* - * Copyright (C) 2008-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 <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. - */ - -/** - * @defgroup sim_manager sim_manager - * @{ @ingroup eap - */ - -#ifndef SIM_MANAGER_H_ -#define SIM_MANAGER_H_ - -#include <crypto/hashers/hasher.h> -#include <utils/identification.h> -#include <utils/enumerator.h> -#include <sa/authenticators/eap/eap_method.h> - -typedef struct sim_manager_t sim_manager_t; - -/** implemented in libsimaka, but we need it for the message hook */ -typedef struct simaka_message_t simaka_message_t; - -#define SIM_RAND_LEN 16 -#define SIM_SRES_LEN 4 -#define SIM_KC_LEN 8 - -#define AKA_RAND_LEN 16 -#define AKA_RES_MAX 16 -#define AKA_CK_LEN 16 -#define AKA_IK_LEN 16 -#define AKA_AUTN_LEN 16 -#define AKA_AUTS_LEN 14 - -#include <sa/authenticators/eap/sim_card.h> -#include <sa/authenticators/eap/sim_provider.h> -#include <sa/authenticators/eap/sim_hooks.h> - -/** - * The SIM manager handles multiple (U)SIM cards/providers and hooks. - */ -struct sim_manager_t { - - /** - * Register a SIM card (client) at the manager. - * - * @param card sim card to register - */ - void (*add_card)(sim_manager_t *this, sim_card_t *card); - - /** - * Unregister a previously registered card from the manager. - * - * @param card sim card to unregister - */ - void (*remove_card)(sim_manager_t *this, sim_card_t *card); - - /** - * Calculate SIM triplets on one of the registered SIM cards. - * - * @param id permanent identity to get a triplet for - * @param rand RAND input buffer, fixed size 16 bytes - * @param sres SRES output buffer, fixed size 4 byte - * @param kc KC output buffer, fixed size 8 bytes - * @return TRUE if calculated, FALSE if no matching card found - */ - bool (*card_get_triplet)(sim_manager_t *this, identification_t *id, - char rand[SIM_RAND_LEN], char sres[SIM_SRES_LEN], - char kc[SIM_KC_LEN]); - - /** - * Calculate AKA quitpulets on one of the registered SIM cards. - * - * @param id permanent identity to request quintuplet for - * @param rand random value rand - * @param autn authentication token autn - * @param ck buffer receiving encryption key ck - * @param ik buffer receiving integrity key ik - * @param res buffer receiving authentication result res - * @param res_len nubmer of bytes written to res buffer - * @return SUCCESS, FAILED, or INVALID_STATE if out of sync - */ - status_t (*card_get_quintuplet)(sim_manager_t *this, identification_t *id, - char rand[AKA_RAND_LEN], char autn[AKA_AUTN_LEN], - char ck[AKA_CK_LEN], char ik[AKA_IK_LEN], - char res[AKA_RES_MAX], int *res_len); - - /** - * Calculate resynchronization data on one of the registered SIM cards. - * - * @param id permanent identity to request quintuplet for - * @param rand random value rand - * @param auts resynchronization parameter auts - * @return TRUE if calculated, FALSE if no matcing card found - */ - bool (*card_resync)(sim_manager_t *this, identification_t *id, - char rand[AKA_RAND_LEN], char auts[AKA_AUTS_LEN]); - - /** - * Store a received pseudonym on one of the registered SIM cards. - * - * @param id permanent identity of the peer - * @param pseudonym pseudonym identity received from the server - */ - void (*card_set_pseudonym)(sim_manager_t *this, identification_t *id, - identification_t *pseudonym); - - /** - * Get a stored pseudonym from one of the registerd SIM cards. - * - * @param id permanent identity of the peer - * @return associated pseudonym identity, NULL if none found - */ - identification_t* (*card_get_pseudonym)(sim_manager_t *this, - identification_t *id); - - /** - * Store fast reauthentication parameters on one of the registered cards. - * - * @param id permanent identity of the peer - * @param next next fast reauthentication identity to use - * @param mk master key MK to store for reauthentication - * @param counter counter value to store, host order - */ - void (*card_set_reauth)(sim_manager_t *this, identification_t *id, - identification_t *next, char mk[HASH_SIZE_SHA1], - u_int16_t counter); - - /** - * Retrieve fast reauthentication parameters from one of the registerd cards. - * - * @param id permanent identity of the peer - * @param mk buffer receiving master key MK - * @param counter pointer receiving counter value, in host order - * @return fast reauthentication identity, NULL if none found - */ - identification_t* (*card_get_reauth)(sim_manager_t *this, - identification_t *id, char mk[HASH_SIZE_SHA1], - u_int16_t *counter); - - /** - * Register a triplet provider (server) at the manager. - * - * @param card sim card to register - */ - void (*add_provider)(sim_manager_t *this, sim_provider_t *provider); - - /** - * Unregister a previously registered provider from the manager. - * - * @param card sim card to unregister - */ - void (*remove_provider)(sim_manager_t *this, sim_provider_t *provider); - - /** - * Get a SIM triplet from one of the registered providers. - * - * @param id permanent identity of peer to gen triplet for - * @param rand RAND output buffer, fixed size 16 bytes - * @param sres SRES output buffer, fixed size 4 byte - * @param kc KC output buffer, fixed size 8 bytes - * @return TRUE if triplet received, FALSE if no match found - */ - bool (*provider_get_triplet)(sim_manager_t *this, identification_t *id, - char rand[SIM_RAND_LEN], char sres[SIM_SRES_LEN], - char kc[SIM_KC_LEN]); - - /** - * Get a AKA quintuplet from one of the registered providers. - * - * @param id permanent identity of peer to create challenge for - * @param rand buffer receiving random value rand - * @param xres buffer receiving expected authentication result xres - * @param ck buffer receiving encryption key ck - * @param ik buffer receiving integrity key ik - * @param autn authentication token autn - * @return TRUE if quintuplet received, FALSE if no match found - */ - bool (*provider_get_quintuplet)(sim_manager_t *this, identification_t *id, - char rand[AKA_RAND_LEN], - char xres[AKA_RES_MAX], int *xres_len, - char ck[AKA_CK_LEN], char ik[AKA_IK_LEN], - char autn[AKA_AUTN_LEN]); - - /** - * Pass AKA resynchronization data to one of the registered providers. - * - * @param id permanent identity of peer requesting resynchronisation - * @param rand random value rand - * @param auts synchronization parameter auts - * @return TRUE if resynchronized, FALSE if not handled - */ - bool (*provider_resync)(sim_manager_t *this, identification_t *id, - char rand[AKA_RAND_LEN], char auts[AKA_AUTS_LEN]); - - /** - * Check if a peer uses a pseudonym using one of the registered providers. - * - * @param id pseudonym identity candidate - * @return permanent identity, NULL if id not a pseudonym - */ - identification_t* (*provider_is_pseudonym)(sim_manager_t *this, - identification_t *id); - - /** - * Generate a new pseudonym using one of the registered providers. - * - * @param id permanent identity to generate a pseudonym for - * @return generated pseudonym, NULL to not use a pseudonym identity - */ - identification_t* (*provider_gen_pseudonym)(sim_manager_t *this, - identification_t *id); - - /** - * Check if a peer uses a reauth id using one of the registered providers. - * - * @param id reauthentication identity (candidate) - * @param mk buffer receiving master key MK - * @param counter pointer receiving current counter value, host order - * @return permanent identity, NULL if not a known reauth identity - */ - identification_t* (*provider_is_reauth)(sim_manager_t *this, - identification_t *id, char mk[HASH_SIZE_SHA1], - u_int16_t *counter); - - /** - * Generate a fast reauth id using one of the registered providers. - * - * @param id permanent peer identity - * @param mk master key to store along with generated identity - * @return fast reauthentication identity, NULL to not use reauth - */ - identification_t* (*provider_gen_reauth)(sim_manager_t *this, - identification_t *id, char mk[HASH_SIZE_SHA1]); - - /** - * Register a set of hooks to the manager. - * - * @param hooks hook interface implementation to register - */ - void (*add_hooks)(sim_manager_t *this, sim_hooks_t *hooks); - - /** - * Unregister a set of hooks from the manager. - * - * @param hooks hook interface implementation to unregister - */ - void (*remove_hooks)(sim_manager_t *this, sim_hooks_t *hooks); - - /** - * Invoke SIM/AKA message hook. - * - * @param message SIM message - * @param inbound TRUE for incoming messages, FALSE for outgoing - * @param decrypted TRUE if AT_ENCR_DATA has been decrypted - */ - void (*message_hook)(sim_manager_t *this, simaka_message_t *message, - bool inbound, bool decrypted); - - /** - * Invoke SIM/AKA key hook. - * - * @param k_encr SIM/AKA encryption key k_encr - * @param k_auth SIM/AKA authentication key k_auth - */ - void (*key_hook)(sim_manager_t *this, chunk_t k_encr, chunk_t k_auth); - - /** - * Destroy a manager instance. - */ - void (*destroy)(sim_manager_t *this); -}; - -/** - * Create an SIM manager to handle multiple (U)SIM cards/providers. - * - * @return sim_t object - */ -sim_manager_t *sim_manager_create(); - -#endif /** SIM_MANAGER_H_ @}*/ diff --git a/src/libcharon/sa/authenticators/eap/sim_provider.h b/src/libcharon/sa/authenticators/eap/sim_provider.h deleted file mode 100644 index 191e094db..000000000 --- a/src/libcharon/sa/authenticators/eap/sim_provider.h +++ /dev/null @@ -1,124 +0,0 @@ -/* - * Copyright (C) 2008-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 <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. - */ - -/** - * @defgroup sim_provider sim_provider - * @{ @ingroup eap - */ - -#ifndef SIM_PROVIDER_H_ -#define SIM_PROVIDER_H_ - -typedef struct sim_provider_t sim_provider_t; - -/** - * Interface for a triplet/quintuplet provider (used as EAP server). - * - * A SIM provider hands out triplets for SIM authentication and quintuplets - * for AKA authentication. Multiple SIM provider instances can serve as - * authentication backend to authenticate clients using SIM/AKA. - * An implementation supporting only one of SIM/AKA authentication may - * implement the other methods with return_false(). - */ -struct sim_provider_t { - - /** - * Create a challenge for SIM authentication. - * - * @param id permanent identity of peer to gen triplet for - * @param rand RAND output buffer, fixed size 16 bytes - * @param sres SRES output buffer, fixed size 4 byte - * @param kc KC output buffer, fixed size 8 bytes - * @return TRUE if triplet received, FALSE otherwise - */ - bool (*get_triplet)(sim_provider_t *this, identification_t *id, - char rand[SIM_RAND_LEN], char sres[SIM_SRES_LEN], - char kc[SIM_KC_LEN]); - - /** - * Create a challenge for AKA authentication. - * - * The XRES value is the only one with variable length. Pass a buffer - * of at least AKA_RES_MAX, the actual number of bytes is written to the - * xres_len value. While the standard would allow any bit length between - * 32 and 128 bits, we support only full bytes for now. - * - * @param id permanent identity of peer to create challenge for - * @param rand buffer receiving random value rand - * @param xres buffer receiving expected authentication result xres - * @param xres_len nubmer of bytes written to xres buffer - * @param ck buffer receiving encryption key ck - * @param ik buffer receiving integrity key ik - * @param autn authentication token autn - * @return TRUE if quintuplet generated successfully - */ - bool (*get_quintuplet)(sim_provider_t *this, identification_t *id, - char rand[AKA_RAND_LEN], - char xres[AKA_RES_MAX], int *xres_len, - char ck[AKA_CK_LEN], char ik[AKA_IK_LEN], - char autn[AKA_AUTN_LEN]); - - /** - * Process AKA resynchroniusation request of a peer. - * - * @param id permanent identity of peer requesting resynchronisation - * @param rand random value rand - * @param auts synchronization parameter auts - * @return TRUE if resynchronized successfully - */ - bool (*resync)(sim_provider_t *this, identification_t *id, - char rand[AKA_RAND_LEN], char auts[AKA_AUTS_LEN]); - - /** - * Check if peer uses a pseudonym, get permanent identity. - * - * @param id pseudonym identity candidate - * @return permanent identity, NULL if id not a pseudonym - */ - identification_t* (*is_pseudonym)(sim_provider_t *this, - identification_t *id); - - /** - * Generate a pseudonym identitiy for a given peer identity. - * - * @param id permanent identity to generate a pseudonym for - * @return generated pseudonym, NULL to not use a pseudonym identity - */ - identification_t* (*gen_pseudonym)(sim_provider_t *this, - identification_t *id); - - /** - * Check if peer uses reauthentication, retrieve reauth parameters. - * - * @param id reauthentication identity (candidate) - * @param mk buffer receiving master key MK - * @param counter pointer receiving current counter value, host order - * @return permanent identity, NULL if id not a reauth identity - */ - identification_t* (*is_reauth)(sim_provider_t *this, identification_t *id, - char mk[HASH_SIZE_SHA1], u_int16_t *counter); - - /** - * Generate a fast reauthentication identity, associated to a master key. - * - * @param id permanent peer identity - * @param mk master key to store along with generated identity - * @return fast reauthentication identity, NULL to not use reauth - */ - identification_t* (*gen_reauth)(sim_provider_t *this, identification_t *id, - char mk[HASH_SIZE_SHA1]); -}; - -#endif /** SIM_CARD_H_ @}*/ diff --git a/src/libcharon/sa/authenticators/eap_authenticator.c b/src/libcharon/sa/authenticators/eap_authenticator.c index d442acb00..5c8f0b6ce 100644 --- a/src/libcharon/sa/authenticators/eap_authenticator.c +++ b/src/libcharon/sa/authenticators/eap_authenticator.c @@ -160,7 +160,9 @@ static eap_payload_t* server_initiate_eap(private_eap_authenticator_t *this, { if (this->method->initiate(this->method, &out) == NEED_MORE) { - DBG1(DBG_IKE, "initiating EAP-Identity request"); + DBG1(DBG_IKE, "initiating %N method (id 0x%02X)", + eap_type_names, EAP_IDENTITY, + this->method->get_identifier(this->method)); return out; } this->method->destroy(this->method); @@ -216,23 +218,12 @@ static eap_payload_t* server_initiate_eap(private_eap_authenticator_t *this, */ static void replace_eap_identity(private_eap_authenticator_t *this) { - enumerator_t *enumerator; - auth_rule_t rule; + identification_t *eap_identity; auth_cfg_t *cfg; - void *ptr; + eap_identity = this->eap_identity->clone(this->eap_identity); cfg = this->ike_sa->get_auth_cfg(this->ike_sa, FALSE); - enumerator = cfg->create_enumerator(cfg); - while (enumerator->enumerate(enumerator, &rule, &ptr)) - { - if (rule == AUTH_RULE_EAP_IDENTITY) - { - cfg->replace(cfg, enumerator, AUTH_RULE_EAP_IDENTITY, - this->eap_identity->clone(this->eap_identity)); - break; - } - } - enumerator->destroy(enumerator); + cfg->add(cfg, AUTH_RULE_EAP_IDENTITY, eap_identity); } /** @@ -349,8 +340,8 @@ static eap_payload_t* client_process_eap(private_eap_authenticator_t *this, { id = this->ike_sa->get_my_id(this->ike_sa); } - DBG1(DBG_IKE, "server requested %N, sending '%Y'", - eap_type_names, type, id); + DBG1(DBG_IKE, "server requested %N (id 0x%02X), sending '%Y'", + eap_type_names, type, in->get_identifier(in), id); this->eap_identity = id->clone(id); this->method = load_method(this, type, vendor, EAP_PEER); diff --git a/src/libcharon/sa/child_sa.c b/src/libcharon/sa/child_sa.c index dc42ba787..2130a5998 100644 --- a/src/libcharon/sa/child_sa.c +++ b/src/libcharon/sa/child_sa.c @@ -1,5 +1,5 @@ /* - * Copyright (C) 2006-2010 Tobias Brunner + * Copyright (C) 2006-2011 Tobias Brunner * Copyright (C) 2005-2008 Martin Willi * Copyright (C) 2006 Daniel Roethlisberger * Copyright (C) 2005 Jan Hutter @@ -657,6 +657,55 @@ METHOD(child_sa_t, install, status_t, return status; } +/** + * Install 3 policies: out, in and forward + */ +static status_t install_policies_internal(private_child_sa_t *this, + host_t *my_addr, host_t *other_addr, traffic_selector_t *my_ts, + traffic_selector_t *other_ts, ipsec_sa_cfg_t *my_sa, + ipsec_sa_cfg_t *other_sa, policy_type_t type, policy_priority_t priority) +{ + status_t status = SUCCESS; + status |= hydra->kernel_interface->add_policy(hydra->kernel_interface, + my_addr, other_addr, my_ts, other_ts, + POLICY_OUT, type, other_sa, + this->mark_out, priority); + + status |= hydra->kernel_interface->add_policy(hydra->kernel_interface, + other_addr, my_addr, other_ts, my_ts, + POLICY_IN, type, my_sa, + this->mark_in, priority); + if (this->mode != MODE_TRANSPORT) + { + status |= hydra->kernel_interface->add_policy(hydra->kernel_interface, + other_addr, my_addr, other_ts, my_ts, + POLICY_FWD, type, my_sa, + this->mark_in, priority); + } + return status; +} + +/** + * Delete 3 policies: out, in and forward + */ +static void del_policies_internal(private_child_sa_t *this, + traffic_selector_t *my_ts, traffic_selector_t *other_ts, + policy_priority_t priority) +{ + hydra->kernel_interface->del_policy(hydra->kernel_interface, + my_ts, other_ts, POLICY_OUT, this->reqid, + this->mark_out, priority); + hydra->kernel_interface->del_policy(hydra->kernel_interface, + other_ts, my_ts, POLICY_IN, this->reqid, + this->mark_in, priority); + if (this->mode != MODE_TRANSPORT) + { + hydra->kernel_interface->del_policy(hydra->kernel_interface, + other_ts, my_ts, POLICY_FWD, this->reqid, + this->mark_in, priority); + } +} + METHOD(child_sa_t, add_policies, status_t, private_child_sa_t *this, linked_list_t *my_ts_list, linked_list_t *other_ts_list) @@ -664,7 +713,6 @@ METHOD(child_sa_t, add_policies, status_t, enumerator_t *enumerator; traffic_selector_t *my_ts, *other_ts; status_t status = SUCCESS; - bool routed = (this->state == CHILD_CREATED); /* apply traffic selectors */ enumerator = my_ts_list->create_enumerator(my_ts_list); @@ -682,6 +730,7 @@ METHOD(child_sa_t, add_policies, status_t, if (this->config->install_policy(this->config)) { + policy_priority_t priority; ipsec_sa_cfg_t my_sa = { .mode = this->mode, .reqid = this->reqid, @@ -708,31 +757,28 @@ METHOD(child_sa_t, add_policies, status_t, other_sa.ah.spi = this->other_spi; } + priority = this->state == CHILD_CREATED ? POLICY_PRIORITY_ROUTED + : POLICY_PRIORITY_DEFAULT; + /* enumerate pairs of traffic selectors */ enumerator = create_policy_enumerator(this); while (enumerator->enumerate(enumerator, &my_ts, &other_ts)) { - /* install 3 policies: out, in and forward */ - status |= hydra->kernel_interface->add_policy( - hydra->kernel_interface, - this->my_addr, this->other_addr, my_ts, other_ts, - POLICY_OUT, POLICY_IPSEC, &other_sa, - this->mark_out, routed); - - status |= hydra->kernel_interface->add_policy( - hydra->kernel_interface, - this->other_addr, this->my_addr, other_ts, my_ts, - POLICY_IN, POLICY_IPSEC, &my_sa, - this->mark_in, routed); - if (this->mode != MODE_TRANSPORT) + /* install outbound drop policy to avoid packets leaving unencrypted + * when updating policies */ + if (priority == POLICY_PRIORITY_DEFAULT) { - status |= hydra->kernel_interface->add_policy( - hydra->kernel_interface, - this->other_addr, this->my_addr, other_ts, my_ts, - POLICY_FWD, POLICY_IPSEC, &my_sa, - this->mark_in, routed); + status |= install_policies_internal(this, this->my_addr, + this->other_addr, my_ts, other_ts, + &my_sa, &other_sa, POLICY_DROP, + POLICY_PRIORITY_FALLBACK); } + /* install policies */ + status |= install_policies_internal(this, this->my_addr, + this->other_addr, my_ts, other_ts, + &my_sa, &other_sa, POLICY_IPSEC, priority); + if (status != SUCCESS) { break; @@ -769,7 +815,7 @@ METHOD(child_sa_t, update, status_t, if (!transport_proxy_mode) { - /* update our (initator) SA */ + /* update our (initiator) SA */ if (this->my_spi) { if (hydra->kernel_interface->update_sa(hydra->kernel_interface, @@ -835,26 +881,22 @@ METHOD(child_sa_t, update, status_t, enumerator = create_policy_enumerator(this); while (enumerator->enumerate(enumerator, &my_ts, &other_ts)) { + traffic_selector_t *old_my_ts = NULL, *old_other_ts = NULL; /* remove old policies first */ - hydra->kernel_interface->del_policy(hydra->kernel_interface, - my_ts, other_ts, POLICY_OUT, this->mark_out, FALSE); - hydra->kernel_interface->del_policy(hydra->kernel_interface, - other_ts, my_ts, POLICY_IN, this->mark_in, FALSE); - if (this->mode != MODE_TRANSPORT) - { - hydra->kernel_interface->del_policy(hydra->kernel_interface, - other_ts, my_ts, POLICY_FWD, this->mark_in, FALSE); - } + del_policies_internal(this, my_ts, other_ts, + POLICY_PRIORITY_DEFAULT); - /* check whether we have to update a "dynamic" traffic selector */ + /* check if we have to update a "dynamic" traffic selector */ if (!me->ip_equals(me, this->my_addr) && my_ts->is_host(my_ts, this->my_addr)) { + old_my_ts = my_ts->clone(my_ts); my_ts->set_address(my_ts, me); } if (!other->ip_equals(other, this->other_addr) && other_ts->is_host(other_ts, this->other_addr)) { + old_other_ts = other_ts->clone(other_ts); other_ts->set_address(other_ts, other); } @@ -862,22 +904,28 @@ METHOD(child_sa_t, update, status_t, * correctly */ if (vip) { - hydra->kernel_interface->del_ip(hydra->kernel_interface, vip); - hydra->kernel_interface->add_ip(hydra->kernel_interface, vip, me); + hydra->kernel_interface->del_ip(hydra->kernel_interface, + vip); + hydra->kernel_interface->add_ip(hydra->kernel_interface, + vip, me); } /* reinstall updated policies */ - hydra->kernel_interface->add_policy(hydra->kernel_interface, - me, other, my_ts, other_ts, POLICY_OUT, POLICY_IPSEC, - &other_sa, this->mark_out, FALSE); - hydra->kernel_interface->add_policy(hydra->kernel_interface, - other, me, other_ts, my_ts, POLICY_IN, POLICY_IPSEC, - &my_sa, this->mark_in, FALSE); - if (this->mode != MODE_TRANSPORT) + install_policies_internal(this, me, other, my_ts, other_ts, + &my_sa, &other_sa, POLICY_IPSEC, + POLICY_PRIORITY_DEFAULT); + + /* update fallback policies after the new policy is in place */ + if (old_my_ts || old_other_ts) { - hydra->kernel_interface->add_policy(hydra->kernel_interface, - other, me, other_ts, my_ts, POLICY_FWD, POLICY_IPSEC, - &my_sa, this->mark_in, FALSE); + del_policies_internal(this, old_my_ts ?: my_ts, + old_other_ts ?: other_ts, + POLICY_PRIORITY_FALLBACK); + install_policies_internal(this, me, other, my_ts, other_ts, + &my_sa, &other_sa, POLICY_DROP, + POLICY_PRIORITY_FALLBACK); + DESTROY_IF(old_my_ts); + DESTROY_IF(old_other_ts); } } enumerator->destroy(enumerator); @@ -910,7 +958,10 @@ METHOD(child_sa_t, destroy, void, { enumerator_t *enumerator; traffic_selector_t *my_ts, *other_ts; - bool unrouted = (this->state == CHILD_ROUTED); + policy_priority_t priority; + + priority = this->state == CHILD_ROUTED ? POLICY_PRIORITY_ROUTED + : POLICY_PRIORITY_DEFAULT; set_state(this, CHILD_DESTROYING); @@ -942,14 +993,11 @@ METHOD(child_sa_t, destroy, void, enumerator = create_policy_enumerator(this); while (enumerator->enumerate(enumerator, &my_ts, &other_ts)) { - hydra->kernel_interface->del_policy(hydra->kernel_interface, - my_ts, other_ts, POLICY_OUT, this->mark_out, unrouted); - hydra->kernel_interface->del_policy(hydra->kernel_interface, - other_ts, my_ts, POLICY_IN, this->mark_in, unrouted); - if (this->mode != MODE_TRANSPORT) + del_policies_internal(this, my_ts, other_ts, priority); + if (priority == POLICY_PRIORITY_DEFAULT) { - hydra->kernel_interface->del_policy(hydra->kernel_interface, - other_ts, my_ts, POLICY_FWD, this->mark_in, unrouted); + del_policies_internal(this, my_ts, other_ts, + POLICY_PRIORITY_FALLBACK); } } enumerator->destroy(enumerator); diff --git a/src/libcharon/sa/connect_manager.c b/src/libcharon/sa/connect_manager.c index 972cc98ad..7b6ca430f 100644 --- a/src/libcharon/sa/connect_manager.c +++ b/src/libcharon/sa/connect_manager.c @@ -130,25 +130,24 @@ static void endpoint_pair_destroy(endpoint_pair_t *this) static endpoint_pair_t *endpoint_pair_create(endpoint_notify_t *initiator, endpoint_notify_t *responder, bool initiator_is_local) { - endpoint_pair_t *this = malloc_thing(endpoint_pair_t); - - this->id = 0; + endpoint_pair_t *this; u_int32_t pi = initiator->get_priority(initiator); u_int32_t pr = responder->get_priority(responder); - this->priority = pow(2, 32) * min(pi, pr) + 2 * max(pi, pr) + (pi > pr ? 1 : 0); - this->local = initiator_is_local ? initiator->get_base(initiator) - : responder->get_base(responder); + INIT(this, + .priority = pow(2, 32) * min(pi, pr) + 2 * max(pi, pr) + + (pi > pr ? 1 : 0), + .local = initiator_is_local ? initiator->get_base(initiator) + : responder->get_base(responder), + .remote = initiator_is_local ? responder->get_host(responder) + : initiator->get_host(initiator), + .state = CHECK_WAITING, + ); + this->local = this->local->clone(this->local); - this->remote = initiator_is_local ? responder->get_host(responder) - : initiator->get_host(initiator); this->remote = this->remote->clone(this->remote); - this->state = CHECK_WAITING; - this->retransmitted = 0; - this->packet = NULL; - return this; } @@ -239,23 +238,24 @@ static check_list_t *check_list_create(identification_t *initiator, linked_list_t *initiator_endpoints, bool is_initiator) { - check_list_t *this = malloc_thing(check_list_t); - - this->connect_id = chunk_clone(connect_id); - - this->initiator.id = initiator->clone(initiator); - this->initiator.key = chunk_clone(initiator_key); - this->initiator.endpoints = initiator_endpoints->clone_offset(initiator_endpoints, offsetof(endpoint_notify_t, clone)); - - this->responder.id = responder->clone(responder); - this->responder.key = chunk_empty; - this->responder.endpoints = NULL; - - this->pairs = linked_list_create(); - this->triggered = linked_list_create(); - this->state = CHECK_NONE; - this->is_initiator = is_initiator; - this->is_finishing = FALSE; + check_list_t *this; + + INIT(this, + .connect_id = chunk_clone(connect_id), + .initiator = { + .id = initiator->clone(initiator), + .key = chunk_clone(initiator_key), + .endpoints = initiator_endpoints->clone_offset(initiator_endpoints, + offsetof(endpoint_notify_t, clone)), + }, + .responder = { + .id = responder->clone(responder), + }, + .pairs = linked_list_create(), + .triggered = linked_list_create(), + .state = CHECK_NONE, + .is_initiator = is_initiator, + ); return this; } @@ -294,11 +294,13 @@ static void initiated_destroy(initiated_t *this) static initiated_t *initiated_create(identification_t *id, identification_t *peer_id) { - initiated_t *this = malloc_thing(initiated_t); + initiated_t *this; - this->id = id->clone(id); - this->peer_id = peer_id->clone(peer_id); - this->mediated = linked_list_create(); + INIT(this, + .id = id->clone(id), + .peer_id = peer_id->clone(peer_id), + .mediated = linked_list_create(), + ); return this; } @@ -351,16 +353,11 @@ static void check_destroy(check_t *this) */ static check_t *check_create() { - check_t *this = malloc_thing(check_t); - - this->connect_id = chunk_empty; - this->auth = chunk_empty; - this->endpoint_raw = chunk_empty; - this->src = NULL; - this->dst = NULL; - this->endpoint = NULL; + check_t *this; - this->mid = 0; + INIT(this, + .mid = 0, + ); return this; } @@ -396,10 +393,12 @@ static void callback_data_destroy(callback_data_t *this) static callback_data_t *callback_data_create(private_connect_manager_t *connect_manager, chunk_t connect_id) { - callback_data_t *this = malloc_thing(callback_data_t); - this->connect_manager = connect_manager; - this->connect_id = chunk_clone(connect_id); - this->mid = 0; + callback_data_t *this; + INIT(this, + .connect_manager = connect_manager, + .connect_id = chunk_clone(connect_id), + .mid = 0, + ); return this; } @@ -443,11 +442,11 @@ static void initiate_data_destroy(initiate_data_t *this) static initiate_data_t *initiate_data_create(check_list_t *checklist, initiated_t *initiated) { - initiate_data_t *this = malloc_thing(initiate_data_t); - - this->checklist = checklist; - this->initiated = initiated; - + initiate_data_t *this; + INIT(this, + .checklist = checklist, + .initiated = initiated, + ); return this; } @@ -476,19 +475,19 @@ static status_t get_initiated_by_ids(private_connect_manager_t *this, static void remove_initiated(private_connect_manager_t *this, initiated_t *initiated) { - iterator_t *iterator; + enumerator_t *enumerator; initiated_t *current; - iterator = this->initiated->create_iterator(this->initiated, TRUE); - while (iterator->iterate(iterator, (void**)¤t)) + enumerator = this->initiated->create_enumerator(this->initiated); + while (enumerator->enumerate(enumerator, (void**)¤t)) { if (current == initiated) { - iterator->remove(iterator); + this->initiated->remove_at(this->initiated, enumerator); break; } } - iterator->destroy(iterator); + enumerator->destroy(enumerator); } /** @@ -514,19 +513,19 @@ static status_t get_checklist_by_id(private_connect_manager_t *this, static void remove_checklist(private_connect_manager_t *this, check_list_t *checklist) { - iterator_t *iterator; + enumerator_t *enumerator; check_list_t *current; - iterator = this->checklists->create_iterator(this->checklists, TRUE); - while (iterator->iterate(iterator, (void**)¤t)) + enumerator = this->checklists->create_enumerator(this->checklists); + while (enumerator->enumerate(enumerator, (void**)¤t)) { if (current == checklist) { - iterator->remove(iterator); + this->checklists->remove_at(this->checklists, enumerator); break; } } - iterator->destroy(iterator); + enumerator->destroy(enumerator); } /** @@ -550,26 +549,15 @@ static status_t endpoints_contain(linked_list_t *endpoints, host_t *host, */ static void insert_pair_by_priority(linked_list_t *pairs, endpoint_pair_t *pair) { - iterator_t *iterator; + enumerator_t *enumerator = pairs->create_enumerator(pairs); endpoint_pair_t *current; - bool inserted = FALSE; - - iterator = pairs->create_iterator(pairs, TRUE); - while (iterator->iterate(iterator, (void**)¤t)) - { - if (current->priority < pair->priority) - { - iterator->insert_before(iterator, pair); - inserted = TRUE; - break; - } - } - iterator->destroy(iterator); - - if (!inserted) + while (enumerator->enumerate(enumerator, (void**)¤t) && + current->priority >= pair->priority) { - pairs->insert_last(pairs, pair); + continue; } + pairs->insert_before(pairs, enumerator, pair); + enumerator->destroy(enumerator); } /** @@ -631,14 +619,14 @@ static bool match_waiting_pair(endpoint_pair_t *current) static status_t get_triggered_pair(check_list_t *checklist, endpoint_pair_t **pair) { - iterator_t *iterator; + enumerator_t *enumerator; endpoint_pair_t *current; status_t status = NOT_FOUND; - iterator = checklist->triggered->create_iterator(checklist->triggered, TRUE); - while (iterator->iterate(iterator, (void**)¤t)) + enumerator = checklist->triggered->create_enumerator(checklist->triggered); + while (enumerator->enumerate(enumerator, (void**)¤t)) { - iterator->remove(iterator); + checklist->triggered->remove_at(checklist->triggered, enumerator); if (current->state == CHECK_WAITING) { @@ -650,7 +638,7 @@ static status_t get_triggered_pair(check_list_t *checklist, break; } } - iterator->destroy(iterator); + enumerator->destroy(enumerator); return status; } @@ -660,17 +648,17 @@ static status_t get_triggered_pair(check_list_t *checklist, */ static void print_checklist(check_list_t *checklist) { - iterator_t *iterator; + enumerator_t *enumerator; endpoint_pair_t *current; DBG1(DBG_IKE, "pairs on checklist %#B:", &checklist->connect_id); - iterator = checklist->pairs->create_iterator(checklist->pairs, TRUE); - while (iterator->iterate(iterator, (void**)¤t)) + enumerator = checklist->pairs->create_enumerator(checklist->pairs); + while (enumerator->enumerate(enumerator, (void**)¤t)) { DBG1(DBG_IKE, " * %#H - %#H (%d)", current->local, current->remote, current->priority); } - iterator->destroy(iterator); + enumerator->destroy(enumerator); } /** @@ -679,17 +667,17 @@ static void print_checklist(check_list_t *checklist) */ static void prune_pairs(linked_list_t *pairs) { - iterator_t *iterator, *search; + enumerator_t *enumerator, *search; endpoint_pair_t *current, *other; u_int32_t id = 0; - iterator = pairs->create_iterator(pairs, TRUE); - search = pairs->create_iterator(pairs, TRUE); - while (iterator->iterate(iterator, (void**)¤t)) + enumerator = pairs->create_enumerator(pairs); + search = pairs->create_enumerator(pairs); + while (enumerator->enumerate(enumerator, (void**)¤t)) { current->id = ++id; - while (search->iterate(search, (void**)&other)) + while (search->enumerate(search, (void**)&other)) { if (current == other) { @@ -705,14 +693,14 @@ static void prune_pairs(linked_list_t *pairs) * 'current', remove it */ DBG1(DBG_IKE, "pruning endpoint pair %#H - %#H with priority %d", other->local, other->remote, other->priority); - search->remove(search); + pairs->remove_at(pairs, search); endpoint_pair_destroy(other); } } - search->reset(search); + pairs->reset_enumerator(pairs, search); } search->destroy(search); - iterator->destroy(iterator); + enumerator->destroy(enumerator); } /** @@ -721,16 +709,16 @@ static void prune_pairs(linked_list_t *pairs) static void build_pairs(check_list_t *checklist) { /* FIXME: limit endpoints and pairs */ - iterator_t *iterator_i, *iterator_r; + enumerator_t *enumerator_i, *enumerator_r; endpoint_notify_t *initiator, *responder; - iterator_i = checklist->initiator.endpoints->create_iterator( - checklist->initiator.endpoints, TRUE); - while (iterator_i->iterate(iterator_i, (void**)&initiator)) + enumerator_i = checklist->initiator.endpoints->create_enumerator( + checklist->initiator.endpoints); + while (enumerator_i->enumerate(enumerator_i, (void**)&initiator)) { - iterator_r = checklist->responder.endpoints->create_iterator( - checklist->responder.endpoints, TRUE); - while (iterator_r->iterate(iterator_r, (void**)&responder)) + enumerator_r = checklist->responder.endpoints->create_enumerator( + checklist->responder.endpoints); + while (enumerator_r->enumerate(enumerator_r, (void**)&responder)) { if (initiator->get_family(initiator) != responder->get_family(responder)) { @@ -740,9 +728,9 @@ static void build_pairs(check_list_t *checklist) insert_pair_by_priority(checklist->pairs, endpoint_pair_create( initiator, responder, checklist->is_initiator)); } - iterator_r->destroy(iterator_r); + enumerator_r->destroy(enumerator_r); } - iterator_i->destroy(iterator_i); + enumerator_i->destroy(enumerator_i); print_checklist(checklist); @@ -895,19 +883,19 @@ static job_requeue_t initiator_finish(callback_data_t *data) static void update_checklist_state(private_connect_manager_t *this, check_list_t *checklist) { - iterator_t *iterator; + enumerator_t *enumerator; endpoint_pair_t *current; bool in_progress = FALSE, succeeded = FALSE; - iterator = checklist->pairs->create_iterator(checklist->pairs, TRUE); - while (iterator->iterate(iterator, (void**)¤t)) + enumerator = checklist->pairs->create_enumerator(checklist->pairs); + while (enumerator->enumerate(enumerator, (void**)¤t)) { switch(current->state) { case CHECK_WAITING: /* at least one is still waiting -> checklist remains * in waiting state */ - iterator->destroy(iterator); + enumerator->destroy(enumerator); return; case CHECK_IN_PROGRESS: in_progress = TRUE; @@ -919,7 +907,7 @@ static void update_checklist_state(private_connect_manager_t *this, break; } } - iterator->destroy(iterator); + enumerator->destroy(enumerator); if (checklist->is_initiator && succeeded && !checklist->is_finishing) { @@ -1185,8 +1173,9 @@ static job_requeue_t initiate_mediated(initiate_data_t *data) if (get_best_valid_pair(checklist, &pair) == SUCCESS) { ike_sa_id_t *waiting_sa; - iterator_t *iterator = initiated->mediated->create_iterator(initiated->mediated, TRUE); - while (iterator->iterate(iterator, (void**)&waiting_sa)) + enumerator_t *enumerator = initiated->mediated->create_enumerator( + initiated->mediated); + while (enumerator->enumerate(enumerator, (void**)&waiting_sa)) { ike_sa_t *sa = charon->ike_sa_manager->checkout(charon->ike_sa_manager, waiting_sa); if (sa->initiate_mediated(sa, pair->local, pair->remote, checklist->connect_id) != SUCCESS) @@ -1199,7 +1188,7 @@ static job_requeue_t initiate_mediated(initiate_data_t *data) charon->ike_sa_manager->checkin(charon->ike_sa_manager, sa); } } - iterator->destroy(iterator); + enumerator->destroy(enumerator); } else { @@ -1355,10 +1344,8 @@ static void process_request(private_connect_manager_t *this, check_t *check, check_destroy(response); } -/** - * Implementation of connect_manager_t.process_check. - */ -static void process_check(private_connect_manager_t *this, message_t *message) +METHOD(connect_manager_t, process_check, void, + private_connect_manager_t *this, message_t *message) { if (message->parse_body(message, NULL) != SUCCESS) { @@ -1421,12 +1408,9 @@ static void process_check(private_connect_manager_t *this, message_t *message) check_destroy(check); } -/** - * Implementation of connect_manager_t.check_and_register. - */ -static bool check_and_register(private_connect_manager_t *this, - identification_t *id, identification_t *peer_id, - ike_sa_id_t *mediated_sa) +METHOD(connect_manager_t, check_and_register, bool, + private_connect_manager_t *this, identification_t *id, + identification_t *peer_id, ike_sa_id_t *mediated_sa) { initiated_t *initiated; bool already_there = TRUE; @@ -1455,12 +1439,9 @@ static bool check_and_register(private_connect_manager_t *this, return already_there; } -/** - * Implementation of connect_manager_t.check_and_initiate. - */ -static void check_and_initiate(private_connect_manager_t *this, - ike_sa_id_t *mediation_sa, identification_t *id, - identification_t *peer_id) +METHOD(connect_manager_t, check_and_initiate, void, + private_connect_manager_t *this, ike_sa_id_t *mediation_sa, + identification_t *id, identification_t *peer_id) { initiated_t *initiated; @@ -1474,27 +1455,23 @@ static void check_and_initiate(private_connect_manager_t *this, } ike_sa_id_t *waiting_sa; - iterator_t *iterator = initiated->mediated->create_iterator( - initiated->mediated, TRUE); - while (iterator->iterate(iterator, (void**)&waiting_sa)) + enumerator_t *enumerator = initiated->mediated->create_enumerator( + initiated->mediated); + while (enumerator->enumerate(enumerator, (void**)&waiting_sa)) { job_t *job = (job_t*)reinitiate_mediation_job_create(mediation_sa, waiting_sa); lib->processor->queue_job(lib->processor, job); } - iterator->destroy(iterator); + enumerator->destroy(enumerator); this->mutex->unlock(this->mutex); } -/** - * Implementation of connect_manager_t.set_initiator_data. - */ -static status_t set_initiator_data(private_connect_manager_t *this, - identification_t *initiator, - identification_t *responder, - chunk_t connect_id, chunk_t key, - linked_list_t *endpoints, bool is_initiator) +METHOD(connect_manager_t, set_initiator_data, status_t, + private_connect_manager_t *this, identification_t *initiator, + identification_t *responder, chunk_t connect_id, chunk_t key, + linked_list_t *endpoints, bool is_initiator) { check_list_t *checklist; @@ -1517,12 +1494,9 @@ static status_t set_initiator_data(private_connect_manager_t *this, return SUCCESS; } -/** - * Implementation of connect_manager_t.set_responder_data. - */ -static status_t set_responder_data(private_connect_manager_t *this, - chunk_t connect_id, chunk_t key, - linked_list_t *endpoints) +METHOD(connect_manager_t, set_responder_data, status_t, + private_connect_manager_t *this, chunk_t connect_id, chunk_t key, + linked_list_t *endpoints) { check_list_t *checklist; @@ -1551,10 +1525,8 @@ static status_t set_responder_data(private_connect_manager_t *this, return SUCCESS; } -/** - * Implementation of connect_manager_t.stop_checks. - */ -static status_t stop_checks(private_connect_manager_t *this, chunk_t connect_id) +METHOD(connect_manager_t, stop_checks, status_t, + private_connect_manager_t *this, chunk_t connect_id) { check_list_t *checklist; @@ -1578,16 +1550,16 @@ static status_t stop_checks(private_connect_manager_t *this, chunk_t connect_id) return SUCCESS; } -/** - * Implementation of connect_manager_t.destroy. - */ -static void destroy(private_connect_manager_t *this) +METHOD(connect_manager_t, destroy, void, + private_connect_manager_t *this) { this->mutex->lock(this->mutex); - this->hasher->destroy(this->hasher); - this->checklists->destroy_function(this->checklists, (void*)check_list_destroy); - this->initiated->destroy_function(this->initiated, (void*)initiated_destroy); + this->checklists->destroy_function(this->checklists, + (void*)check_list_destroy); + this->initiated->destroy_function(this->initiated, + (void*)initiated_destroy); + DESTROY_IF(this->hasher); this->mutex->unlock(this->mutex); this->mutex->destroy(this->mutex); @@ -1599,28 +1571,30 @@ static void destroy(private_connect_manager_t *this) */ connect_manager_t *connect_manager_create() { - private_connect_manager_t *this = malloc_thing(private_connect_manager_t); - - this->public.destroy = (void(*)(connect_manager_t*))destroy; - this->public.check_and_register = (bool(*)(connect_manager_t*,identification_t*,identification_t*,ike_sa_id_t*))check_and_register; - this->public.check_and_initiate = (void(*)(connect_manager_t*,ike_sa_id_t*,identification_t*,identification_t*))check_and_initiate; - this->public.set_initiator_data = (status_t(*)(connect_manager_t*,identification_t*,identification_t*,chunk_t,chunk_t,linked_list_t*,bool))set_initiator_data; - this->public.set_responder_data = (status_t(*)(connect_manager_t*,chunk_t,chunk_t,linked_list_t*))set_responder_data; - this->public.process_check = (void(*)(connect_manager_t*,message_t*))process_check; - this->public.stop_checks = (status_t(*)(connect_manager_t*,chunk_t))stop_checks; + private_connect_manager_t *this; + + INIT(this, + .public = { + .destroy = _destroy, + .check_and_register = _check_and_register, + .check_and_initiate = _check_and_initiate, + .set_initiator_data = _set_initiator_data, + .set_responder_data = _set_responder_data, + .process_check = _process_check, + .stop_checks = _stop_checks, + }, + .hasher = lib->crypto->create_hasher(lib->crypto, HASH_SHA1), + .mutex = mutex_create(MUTEX_TYPE_DEFAULT), + .checklists = linked_list_create(), + .initiated = linked_list_create(), + ); - this->hasher = lib->crypto->create_hasher(lib->crypto, HASH_SHA1); if (this->hasher == NULL) { DBG1(DBG_IKE, "unable to create connect manager, SHA1 not supported"); - free(this); + destroy(this); return NULL; } - this->checklists = linked_list_create(); - this->initiated = linked_list_create(); - - this->mutex = mutex_create(MUTEX_TYPE_DEFAULT); - - return (connect_manager_t*)this; + return &this->public; } diff --git a/src/libcharon/sa/ike_sa.c b/src/libcharon/sa/ike_sa.c index 2fc186fe8..07d19381d 100644 --- a/src/libcharon/sa/ike_sa.c +++ b/src/libcharon/sa/ike_sa.c @@ -1,5 +1,5 @@ /* - * Copyright (C) 2006-2008 Tobias Brunner + * Copyright (C) 2006-2012 Tobias Brunner * Copyright (C) 2006 Daniel Roethlisberger * Copyright (C) 2005-2009 Martin Willi * Copyright (C) 2005 Jan Hutter @@ -208,9 +208,9 @@ struct private_ike_sa_t { linked_list_t *attributes; /** - * list of peers additional addresses, transmitted via MOBIKE + * list of peer's addresses, additional ones transmitted via MOBIKE */ - linked_list_t *additional_addresses; + linked_list_t *peer_addresses; /** * previously value of received DESTINATION_IP hash @@ -246,6 +246,11 @@ struct private_ike_sa_t { * remote host address to be used for IKE, set via MIGRATE kernel message */ host_t *remote_host; + + /** + * TRUE if we are currently reauthenticating this IKE_SA + */ + bool is_reauthenticating; }; /** @@ -349,8 +354,8 @@ METHOD(ike_sa_t, get_peer_cfg, peer_cfg_t*, METHOD(ike_sa_t, set_peer_cfg, void, private_ike_sa_t *this, peer_cfg_t *peer_cfg) { - DESTROY_IF(this->peer_cfg); peer_cfg->get_ref(peer_cfg); + DESTROY_IF(this->peer_cfg); this->peer_cfg = peer_cfg; if (this->ike_cfg == NULL) @@ -559,6 +564,10 @@ METHOD(ike_sa_t, send_dpd, status_t, job_t *job; time_t diff, delay; + if (this->state == IKE_PASSIVE) + { + return INVALID_STATE; + } delay = this->peer_cfg->get_dpd(this->peer_cfg); if (this->task_manager->busy(this->task_manager)) { @@ -615,6 +624,8 @@ METHOD(ike_sa_t, get_state, ike_sa_state_t, METHOD(ike_sa_t, set_state, void, private_ike_sa_t *this, ike_sa_state_t state) { + bool trigger_dpd = FALSE; + DBG2(DBG_IKE, "IKE_SA %s[%d] state change: %N => %N", get_name(this), this->unique_id, ike_sa_state_names, this->state, @@ -675,28 +686,20 @@ METHOD(ike_sa_t, set_state, void, lib->scheduler->schedule_job(lib->scheduler, job, t); DBG1(DBG_IKE, "maximum IKE_SA lifetime %ds", t); } - - /* start DPD checks */ - if (this->peer_cfg->get_dpd(this->peer_cfg)) - { - send_dpd(this); - } + trigger_dpd = this->peer_cfg->get_dpd(this->peer_cfg); } break; } - case IKE_DELETING: - { - /* delete may fail if a packet gets lost, so set a timeout */ - job_t *job = (job_t*)delete_ike_sa_job_create(this->ike_sa_id, TRUE); - lib->scheduler->schedule_job(lib->scheduler, job, - HALF_OPEN_IKE_SA_TIMEOUT); - break; - } default: break; } charon->bus->ike_state_change(charon->bus, &this->public, state); this->state = state; + + if (trigger_dpd) + { + send_dpd(this); + } } METHOD(ike_sa_t, reset, void, @@ -768,17 +771,37 @@ METHOD(ike_sa_t, get_virtual_ip, host_t*, } } -METHOD(ike_sa_t, add_additional_address, void, +METHOD(ike_sa_t, add_peer_address, void, private_ike_sa_t *this, host_t *host) { - this->additional_addresses->insert_last(this->additional_addresses, host); + this->peer_addresses->insert_last(this->peer_addresses, host); } -METHOD(ike_sa_t, create_additional_address_iterator, iterator_t*, +METHOD(ike_sa_t, create_peer_address_enumerator, enumerator_t*, private_ike_sa_t *this) { - return this->additional_addresses->create_iterator( - this->additional_addresses, TRUE); + if (this->peer_addresses->get_count(this->peer_addresses)) + { + return this->peer_addresses->create_enumerator(this->peer_addresses); + } + /* in case we don't have MOBIKE */ + return enumerator_create_single(this->other_host, NULL); +} + +METHOD(ike_sa_t, clear_peer_addresses, void, + private_ike_sa_t *this) +{ + enumerator_t *enumerator; + host_t *host; + + enumerator = this->peer_addresses->create_enumerator(this->peer_addresses); + while (enumerator->enumerate(enumerator, (void**)&host)) + { + this->peer_addresses->remove_at(this->peer_addresses, + enumerator); + host->destroy(host); + } + enumerator->destroy(enumerator); } METHOD(ike_sa_t, has_mapping_changed, bool, @@ -857,7 +880,7 @@ METHOD(ike_sa_t, update_hosts, void, if (!other->equals(other, this->other_host)) { - /* update others adress if we are NOT NATed */ + /* update others address if we are NOT NATed */ if (force || !has_condition(this, COND_NAT_HERE)) { set_other_host(this, other->clone(other)); @@ -869,11 +892,11 @@ METHOD(ike_sa_t, update_hosts, void, /* update all associated CHILD_SAs, if required */ if (update) { - iterator_t *iterator; + enumerator_t *enumerator; child_sa_t *child_sa; - iterator = this->child_sas->create_iterator(this->child_sas, TRUE); - while (iterator->iterate(iterator, (void**)&child_sa)) + enumerator = this->child_sas->create_enumerator(this->child_sas); + while (enumerator->enumerate(enumerator, (void**)&child_sa)) { if (child_sa->update(child_sa, this->my_host, this->other_host, this->my_virtual_ip, @@ -884,7 +907,7 @@ METHOD(ike_sa_t, update_hosts, void, child_sa->get_spi(child_sa, TRUE)); } } - iterator->destroy(iterator); + enumerator->destroy(enumerator); } } @@ -1094,7 +1117,11 @@ METHOD(ike_sa_t, initiate, status_t, if (this->state == IKE_CREATED) { - resolve_hosts(this); + if (this->my_host->is_anyaddr(this->my_host) || + this->other_host->is_anyaddr(this->other_host)) + { + resolve_hosts(this); + } if (this->other_host->is_anyaddr(this->other_host) #ifdef ME @@ -1104,6 +1131,7 @@ METHOD(ike_sa_t, initiate, status_t, { child_cfg->destroy(child_cfg); DBG1(DBG_IKE, "unable to initiate to %%any"); + charon->bus->alert(charon->bus, ALERT_PEER_ADDR_FAILED); return DESTROY_ME; } @@ -1289,7 +1317,8 @@ METHOD(ike_sa_t, process_message, status_t, /* add a timeout if peer does not establish it completely */ job = (job_t*)delete_ike_sa_job_create(this->ike_sa_id, FALSE); lib->scheduler->schedule_job(lib->scheduler, job, - HALF_OPEN_IKE_SA_TIMEOUT); + lib->settings->get_int(lib->settings, + "charon.half_open_timeout", HALF_OPEN_IKE_SA_TIMEOUT)); } this->stats[STAT_INBOUND] = time_monotonic(NULL); status = this->task_manager->process_message(this->task_manager, @@ -1376,11 +1405,11 @@ METHOD(ike_sa_t, add_child_sa, void, METHOD(ike_sa_t, get_child_sa, child_sa_t*, private_ike_sa_t *this, protocol_id_t protocol, u_int32_t spi, bool inbound) { - iterator_t *iterator; + enumerator_t *enumerator; child_sa_t *current, *found = NULL; - iterator = this->child_sas->create_iterator(this->child_sas, TRUE); - while (iterator->iterate(iterator, (void**)¤t)) + enumerator = this->child_sas->create_enumerator(this->child_sas); + while (enumerator->enumerate(enumerator, (void**)¤t)) { if (current->get_spi(current, inbound) == spi && current->get_protocol(current) == protocol) @@ -1388,14 +1417,26 @@ METHOD(ike_sa_t, get_child_sa, child_sa_t*, found = current; } } - iterator->destroy(iterator); + enumerator->destroy(enumerator); return found; } -METHOD(ike_sa_t, create_child_sa_iterator, iterator_t*, +METHOD(ike_sa_t, get_child_count, int, + private_ike_sa_t *this) +{ + return this->child_sas->get_count(this->child_sas); +} + +METHOD(ike_sa_t, create_child_sa_enumerator, enumerator_t*, private_ike_sa_t *this) { - return this->child_sas->create_iterator(this->child_sas, TRUE); + return this->child_sas->create_enumerator(this->child_sas); +} + +METHOD(ike_sa_t, remove_child_sa, void, + private_ike_sa_t *this, enumerator_t *enumerator) +{ + this->child_sas->remove_at(this->child_sas, enumerator); } METHOD(ike_sa_t, rekey_child_sa, status_t, @@ -1403,6 +1444,11 @@ METHOD(ike_sa_t, rekey_child_sa, status_t, { child_rekey_t *child_rekey; + if (this->state == IKE_PASSIVE) + { + return INVALID_STATE; + } + child_rekey = child_rekey_create(&this->public, protocol, spi); this->task_manager->queue_task(this->task_manager, &child_rekey->task); return this->task_manager->initiate(this->task_manager); @@ -1413,6 +1459,11 @@ METHOD(ike_sa_t, delete_child_sa, status_t, { child_delete_t *child_delete; + if (this->state == IKE_PASSIVE) + { + return INVALID_STATE; + } + child_delete = child_delete_create(&this->public, protocol, spi); this->task_manager->queue_task(this->task_manager, &child_delete->task); return this->task_manager->initiate(this->task_manager); @@ -1421,23 +1472,23 @@ METHOD(ike_sa_t, delete_child_sa, status_t, METHOD(ike_sa_t, destroy_child_sa, status_t, private_ike_sa_t *this, protocol_id_t protocol, u_int32_t spi) { - iterator_t *iterator; + enumerator_t *enumerator; child_sa_t *child_sa; status_t status = NOT_FOUND; - iterator = this->child_sas->create_iterator(this->child_sas, TRUE); - while (iterator->iterate(iterator, (void**)&child_sa)) + enumerator = this->child_sas->create_enumerator(this->child_sas); + while (enumerator->enumerate(enumerator, (void**)&child_sa)) { if (child_sa->get_protocol(child_sa) == protocol && child_sa->get_spi(child_sa, TRUE) == spi) { + this->child_sas->remove_at(this->child_sas, enumerator); child_sa->destroy(child_sa); - iterator->remove(iterator); status = SUCCESS; break; } } - iterator->destroy(iterator); + enumerator->destroy(enumerator); return status; } @@ -1472,6 +1523,10 @@ METHOD(ike_sa_t, rekey, status_t, { ike_rekey_t *ike_rekey; + if (this->state == IKE_PASSIVE) + { + return INVALID_STATE; + } ike_rekey = ike_rekey_create(&this->public, TRUE); this->task_manager->queue_task(this->task_manager, &ike_rekey->task); @@ -1483,6 +1538,10 @@ METHOD(ike_sa_t, reauth, status_t, { task_t *task; + if (this->state == IKE_PASSIVE) + { + return INVALID_STATE; + } /* we can't reauthenticate as responder when we use EAP or virtual IPs. * If the peer does not support RFC4478, there is no way to keep the * IKE_SA up. */ @@ -1497,17 +1556,26 @@ METHOD(ike_sa_t, reauth, status_t, #endif /* ME */ ) { - time_t now = time_monotonic(NULL); + time_t del, now; - DBG1(DBG_IKE, "IKE_SA will timeout in %V", - &now, &this->stats[STAT_DELETE]); + del = this->stats[STAT_DELETE]; + now = time_monotonic(NULL); + DBG1(DBG_IKE, "IKE_SA %s[%d] will timeout in %V", + get_name(this), this->unique_id, &now, &del); return FAILED; } else { - DBG1(DBG_IKE, "reauthenticating actively"); + DBG0(DBG_IKE, "reauthenticating IKE_SA %s[%d] actively", + get_name(this), this->unique_id); } } + else + { + DBG0(DBG_IKE, "reauthenticating IKE_SA %s[%d]", + get_name(this), this->unique_id); + } + this->is_reauthenticating = TRUE; task = (task_t*)ike_reauth_create(&this->public); this->task_manager->queue_task(this->task_manager, task); @@ -1520,45 +1588,64 @@ METHOD(ike_sa_t, reestablish, status_t, ike_sa_t *new; host_t *host; action_t action; - iterator_t *iterator; + enumerator_t *enumerator; child_sa_t *child_sa; child_cfg_t *child_cfg; bool restart = FALSE; status_t status = FAILED; - /* check if we have children to keep up at all */ - iterator = create_child_sa_iterator(this); - while (iterator->iterate(iterator, (void**)&child_sa)) - { - if (this->state == IKE_DELETING) + if (this->is_reauthenticating) + { /* only reauthenticate if we have children */ + if (this->child_sas->get_count(this->child_sas) == 0 +#ifdef ME + /* allow reauth of mediation connections without CHILD_SAs */ + && !this->peer_cfg->is_mediation(this->peer_cfg) +#endif /* ME */ + ) { - action = child_sa->get_close_action(child_sa); + DBG1(DBG_IKE, "unable to reauthenticate IKE_SA, no CHILD_SA " + "to recreate"); } else { - action = child_sa->get_dpd_action(child_sa); + restart = TRUE; } - switch (action) + } + else + { /* check if we have children to keep up at all */ + enumerator = this->child_sas->create_enumerator(this->child_sas); + while (enumerator->enumerate(enumerator, (void**)&child_sa)) { - case ACTION_RESTART: - restart = TRUE; - break; - case ACTION_ROUTE: - charon->traps->install(charon->traps, this->peer_cfg, - child_sa->get_config(child_sa)); - break; - default: - break; + if (this->state == IKE_DELETING) + { + action = child_sa->get_close_action(child_sa); + } + else + { + action = child_sa->get_dpd_action(child_sa); + } + switch (action) + { + case ACTION_RESTART: + restart = TRUE; + break; + case ACTION_ROUTE: + charon->traps->install(charon->traps, this->peer_cfg, + child_sa->get_config(child_sa)); + break; + default: + break; + } } - } - iterator->destroy(iterator); + enumerator->destroy(enumerator); #ifdef ME - /* mediation connections have no children, keep them up anyway */ - if (this->peer_cfg->is_mediation(this->peer_cfg)) - { - restart = TRUE; - } + /* mediation connections have no children, keep them up anyway */ + if (this->peer_cfg->is_mediation(this->peer_cfg)) + { + restart = TRUE; + } #endif /* ME */ + } if (!restart) { return FAILED; @@ -1598,16 +1685,37 @@ METHOD(ike_sa_t, reestablish, status_t, else #endif /* ME */ { - iterator = create_child_sa_iterator(this); - while (iterator->iterate(iterator, (void**)&child_sa)) + enumerator = this->child_sas->create_enumerator(this->child_sas); + while (enumerator->enumerate(enumerator, (void**)&child_sa)) { - if (this->state == IKE_DELETING) + if (this->is_reauthenticating) { - action = child_sa->get_close_action(child_sa); + switch (child_sa->get_state(child_sa)) + { + case CHILD_ROUTED: + { /* move routed child directly */ + this->child_sas->remove_at(this->child_sas, enumerator); + new->add_child_sa(new, child_sa); + action = ACTION_NONE; + break; + } + default: + { /* initiate/queue all other CHILD_SAs */ + action = ACTION_RESTART; + break; + } + } } else - { - action = child_sa->get_dpd_action(child_sa); + { /* only restart CHILD_SAs that are configured accordingly */ + if (this->state == IKE_DELETING) + { + action = child_sa->get_close_action(child_sa); + } + else + { + action = child_sa->get_dpd_action(child_sa); + } } switch (action) { @@ -1626,7 +1734,7 @@ METHOD(ike_sa_t, reestablish, status_t, break; } } - iterator->destroy(iterator); + enumerator->destroy(enumerator); } if (status == DESTROY_ME) @@ -1680,6 +1788,10 @@ static void requeue_init_tasks(private_ike_sa_t *this) METHOD(ike_sa_t, retransmit, status_t, private_ike_sa_t *this, u_int32_t message_id) { + if (this->state == IKE_PASSIVE) + { + return INVALID_STATE; + } this->stats[STAT_OUTBOUND] = time_monotonic(NULL); if (this->task_manager->retransmit(this->task_manager, message_id) != SUCCESS) { @@ -1696,6 +1808,7 @@ METHOD(ike_sa_t, retransmit, status_t, DBG1(DBG_IKE, "peer not responding, trying again (%d/%d)", this->keyingtry + 1, tries); reset(this); + resolve_hosts(this); requeue_init_tasks(this); return this->task_manager->initiate(this->task_manager); } @@ -1704,6 +1817,12 @@ METHOD(ike_sa_t, retransmit, status_t, } case IKE_DELETING: DBG1(DBG_IKE, "proper IKE_SA delete failed, peer not responding"); + if (this->is_reauthenticating) + { + DBG1(DBG_IKE, "delete during reauthentication failed, " + "trying to reestablish IKE_SA anyway"); + reestablish(this); + } break; case IKE_REKEYING: DBG1(DBG_IKE, "rekeying IKE_SA failed, peer not responding"); @@ -1717,35 +1836,67 @@ METHOD(ike_sa_t, retransmit, status_t, return SUCCESS; } -METHOD(ike_sa_t, set_auth_lifetime, void, +METHOD(ike_sa_t, set_auth_lifetime, status_t, private_ike_sa_t *this, u_int32_t lifetime) { - u_int32_t reduction = this->peer_cfg->get_over_time(this->peer_cfg); - u_int32_t reauth_time = time_monotonic(NULL) + lifetime - reduction; + u_int32_t diff, hard, soft, now; + ike_auth_lifetime_t *task; + bool send_update; - if (lifetime < reduction) + diff = this->peer_cfg->get_over_time(this->peer_cfg); + now = time_monotonic(NULL); + hard = now + lifetime; + soft = hard - diff; + + /* check if we have to send an AUTH_LIFETIME to enforce the new lifetime. + * We send the notify in IKE_AUTH if not yet ESTABLISHED. */ + send_update = this->state == IKE_ESTABLISHED && + !has_condition(this, COND_ORIGINAL_INITIATOR) && + (this->other_virtual_ip != NULL || + has_condition(this, COND_EAP_AUTHENTICATED)); + + if (lifetime < diff) { - DBG1(DBG_IKE, "received AUTH_LIFETIME of %ds, starting reauthentication", - lifetime); - lib->processor->queue_job(lib->processor, + this->stats[STAT_REAUTH] = now; + + if (!send_update) + { + DBG1(DBG_IKE, "received AUTH_LIFETIME of %ds, " + "starting reauthentication", lifetime); + lib->processor->queue_job(lib->processor, (job_t*)rekey_ike_sa_job_create(this->ike_sa_id, TRUE)); + } } else if (this->stats[STAT_REAUTH] == 0 || - this->stats[STAT_REAUTH] > reauth_time) + this->stats[STAT_REAUTH] > soft) { - this->stats[STAT_REAUTH] = reauth_time; - DBG1(DBG_IKE, "received AUTH_LIFETIME of %ds, scheduling reauthentication" - " in %ds", lifetime, lifetime - reduction); - lib->scheduler->schedule_job(lib->scheduler, + this->stats[STAT_REAUTH] = soft; + if (!send_update) + { + DBG1(DBG_IKE, "received AUTH_LIFETIME of %ds, scheduling " + "reauthentication in %ds", lifetime, lifetime - diff); + lib->scheduler->schedule_job(lib->scheduler, (job_t*)rekey_ike_sa_job_create(this->ike_sa_id, TRUE), - lifetime - reduction); + lifetime - diff); + } } else { DBG1(DBG_IKE, "received AUTH_LIFETIME of %ds, " "reauthentication already scheduled in %ds", lifetime, this->stats[STAT_REAUTH] - time_monotonic(NULL)); + send_update = FALSE; } + /* give at least some seconds to reauthenticate */ + this->stats[STAT_DELETE] = max(hard, now + 10); + + if (send_update) + { + task = ike_auth_lifetime_create(&this->public, TRUE); + this->task_manager->queue_task(this->task_manager, &task->task); + return this->task_manager->initiate(this->task_manager); + } + return SUCCESS; } /** @@ -1776,26 +1927,21 @@ static bool is_any_path_valid(private_ike_sa_t *this) { bool valid = FALSE; enumerator_t *enumerator; - host_t *src, *addr; + host_t *src = NULL, *addr; + DBG1(DBG_IKE, "old path is not available anymore, try to find another"); - src = hydra->kernel_interface->get_source_addr(hydra->kernel_interface, - this->other_host, NULL); - if (!src) + enumerator = create_peer_address_enumerator(this); + while (enumerator->enumerate(enumerator, &addr)) { - enumerator = this->additional_addresses->create_enumerator( - this->additional_addresses); - while (enumerator->enumerate(enumerator, &addr)) + DBG1(DBG_IKE, "looking for a route to %H ...", addr); + src = hydra->kernel_interface->get_source_addr( + hydra->kernel_interface, addr, NULL); + if (src) { - DBG1(DBG_IKE, "looking for a route to %H ...", addr); - src = hydra->kernel_interface->get_source_addr( - hydra->kernel_interface, addr, NULL); - if (src) - { - break; - } + break; } - enumerator->destroy(enumerator); } + enumerator->destroy(enumerator); if (src) { valid = TRUE; @@ -1874,6 +2020,8 @@ METHOD(ike_sa_t, roam, status_t, return SUCCESS; } DBG1(DBG_IKE, "reauthenticating IKE_SA due to address change"); + /* since our previous path is not valid anymore, try and find a new one */ + resolve_hosts(this); return reauth(this); } @@ -1902,6 +2050,8 @@ METHOD(ike_sa_t, inherit, void, private_ike_sa_t *other = (private_ike_sa_t*)other_public; child_sa_t *child_sa; attribute_entry_t *entry; + enumerator_t *enumerator; + auth_cfg_t *cfg; /* apply hosts and ids */ this->my_host->destroy(this->my_host); @@ -1925,6 +2075,20 @@ METHOD(ike_sa_t, inherit, void, other->other_virtual_ip = NULL; } + /* authentication information */ + enumerator = other->my_auths->create_enumerator(other->my_auths); + while (enumerator->enumerate(enumerator, &cfg)) + { + this->my_auths->insert_last(this->my_auths, cfg->clone(cfg)); + } + enumerator->destroy(enumerator); + enumerator = other->other_auths->create_enumerator(other->other_auths); + while (enumerator->enumerate(enumerator, &cfg)) + { + this->other_auths->insert_last(this->other_auths, cfg->clone(cfg)); + } + enumerator->destroy(enumerator); + /* ... and configuration attributes */ while (other->attributes->remove_last(other->attributes, (void**)&entry) == SUCCESS) @@ -2023,8 +2187,8 @@ METHOD(ike_sa_t, destroy, void, } this->other_virtual_ip->destroy(this->other_virtual_ip); } - this->additional_addresses->destroy_offset(this->additional_addresses, - offsetof(host_t, destroy)); + this->peer_addresses->destroy_offset(this->peer_addresses, + offsetof(host_t, destroy)); #ifdef ME if (this->is_mediation_server) { @@ -2101,8 +2265,9 @@ ike_sa_t * ike_sa_create(ike_sa_id_t *ike_sa_id) .has_condition = _has_condition, .set_pending_updates = _set_pending_updates, .get_pending_updates = _get_pending_updates, - .create_additional_address_iterator = _create_additional_address_iterator, - .add_additional_address = _add_additional_address, + .create_peer_address_enumerator = _create_peer_address_enumerator, + .add_peer_address = _add_peer_address, + .clear_peer_addresses = _clear_peer_addresses, .has_mapping_changed = _has_mapping_changed, .retransmit = _retransmit, .delete = _delete_, @@ -2112,7 +2277,9 @@ ike_sa_t * ike_sa_create(ike_sa_id_t *ike_sa_id) .get_keymat = _get_keymat, .add_child_sa = _add_child_sa, .get_child_sa = _get_child_sa, - .create_child_sa_iterator = _create_child_sa_iterator, + .get_child_count = _get_child_count, + .create_child_sa_enumerator = _create_child_sa_enumerator, + .remove_child_sa = _remove_child_sa, .rekey_child_sa = _rekey_child_sa, .delete_child_sa = _delete_child_sa, .destroy_child_sa = _destroy_child_sa, @@ -2156,13 +2323,13 @@ ike_sa_t * ike_sa_create(ike_sa_id_t *ike_sa_id) .other_auth = auth_cfg_create(), .my_auths = linked_list_create(), .other_auths = linked_list_create(), - .task_manager = task_manager_create(&this->public), .unique_id = ++unique_id, - .additional_addresses = linked_list_create(), + .peer_addresses = linked_list_create(), .attributes = linked_list_create(), .keepalive_interval = lib->settings->get_time(lib->settings, "charon.keep_alive", KEEPALIVE_INTERVAL), ); + this->task_manager = task_manager_create(&this->public); this->my_host->set_port(this->my_host, IKEV2_UDP_PORT); return &this->public; diff --git a/src/libcharon/sa/ike_sa.h b/src/libcharon/sa/ike_sa.h index 69a74d8b7..537565e89 100644 --- a/src/libcharon/sa/ike_sa.h +++ b/src/libcharon/sa/ike_sa.h @@ -1,5 +1,5 @@ /* - * Copyright (C) 2006-2008 Tobias Brunner + * Copyright (C) 2006-2012 Tobias Brunner * Copyright (C) 2006 Daniel Roethlisberger * Copyright (C) 2005-2009 Martin Willi * Copyright (C) 2005 Jan Hutter @@ -97,6 +97,11 @@ enum ike_extension_t { * peer supports EAP-only authentication, draft-eronen-ipsec-ikev2-eap-auth */ EXT_EAP_ONLY_AUTHENTICATION = (1<<5), + + /** + * peer is probably a Windows 7 RAS client + */ + EXT_MS_WINDOWS = (1<<6), }; /** @@ -260,14 +265,14 @@ struct ike_sa_t { * * Returned ike_sa_id_t object is not getting cloned! * - * @return ike_sa's ike_sa_id_t + * @return ike_sa's ike_sa_id_t */ ike_sa_id_t* (*get_id) (ike_sa_t *this); /** * Get the numerical ID uniquely defining this IKE_SA. * - * @return unique ID + * @return unique ID */ u_int32_t (*get_unique_id) (ike_sa_t *this); @@ -469,14 +474,19 @@ struct ike_sa_t { * * @param host host to add to list */ - void (*add_additional_address)(ike_sa_t *this, host_t *host); + void (*add_peer_address)(ike_sa_t *this, host_t *host); /** - * Create an iterator over all additional addresses of the peer. + * Create an enumerator over all known addresses of the peer. * - * @return iterator over addresses + * @return enumerator over addresses + */ + enumerator_t* (*create_peer_address_enumerator)(ike_sa_t *this); + + /** + * Remove all known addresses of the peer. */ - iterator_t* (*create_additional_address_iterator)(ike_sa_t *this); + void (*clear_peer_addresses)(ike_sa_t *this); /** * Check if mappings have changed on a NAT for our source address. @@ -567,8 +577,8 @@ struct ike_sa_t { * * @param mediated_cfg peer_cfg of the mediated connection * @return - * - SUCCESS if initialization started - * - DESTROY_ME if initialization failed + * - SUCCESS if initialization started + * - DESTROY_ME if initialization failed */ status_t (*initiate_mediation) (ike_sa_t *this, peer_cfg_t *mediated_cfg); @@ -579,8 +589,8 @@ struct ike_sa_t { * @param other remote endpoint (gets cloned) * @param connect_id connect ID (gets cloned) * @return - * - SUCCESS if initialization started - * - DESTROY_ME if initialization failed + * - SUCCESS if initialization started + * - DESTROY_ME if initialization failed */ status_t (*initiate_mediated) (ike_sa_t *this, host_t *me, host_t *other, chunk_t connect_id); @@ -597,8 +607,8 @@ struct ike_sa_t { * @param endpoints endpoints * @param response TRUE if this is a response * @return - * - SUCCESS if relay started - * - DESTROY_ME if relay failed + * - SUCCESS if relay started + * - DESTROY_ME if relay failed */ status_t (*relay) (ike_sa_t *this, identification_t *requester, chunk_t connect_id, chunk_t connect_key, @@ -611,8 +621,8 @@ struct ike_sa_t { * * @param peer_id ID of the other peer * @return - * - SUCCESS if response started - * - DESTROY_ME if response failed + * - SUCCESS if response started + * - DESTROY_ME if response failed */ status_t (*callback) (ike_sa_t *this, identification_t *peer_id); @@ -624,8 +634,8 @@ struct ike_sa_t { * @param peer_id ID of the other peer * @param connect_id the connect ID supplied by the initiator * @return - * - SUCCESS if response started - * - DESTROY_ME if response failed + * - SUCCESS if response started + * - DESTROY_ME if response failed */ status_t (*respond) (ike_sa_t *this, identification_t *peer_id, chunk_t connect_id); @@ -643,8 +653,8 @@ struct ike_sa_t { * @param tsi source of triggering packet * @param tsr destination of triggering packet. * @return - * - SUCCESS if initialization started - * - DESTROY_ME if initialization failed + * - SUCCESS if initialization started + * - DESTROY_ME if initialization failed */ status_t (*initiate) (ike_sa_t *this, child_cfg_t *child_cfg, u_int32_t reqid, traffic_selector_t *tsi, @@ -658,10 +668,10 @@ struct ike_sa_t { * the IKE SA gets deleted. * * @return - * - SUCCESS if deletion is initialized - * - DESTROY_ME, if the IKE_SA is not in - * an established state and can not be - * deleted (but destroyed). + * - SUCCESS if deletion is initialized + * - DESTROY_ME, if the IKE_SA is not in + * an established state and can not be + * deleted (but destroyed). */ status_t (*delete) (ike_sa_t *this); @@ -684,13 +694,13 @@ struct ike_sa_t { * * Message processing may fail. If a critical failure occurs, * process_message() return DESTROY_ME. Then the caller must - * destroy the IKE_SA immediatly, as it is unusable. + * destroy the IKE_SA immediately, as it is unusable. * - * @param message message to process + * @param message message to process * @return - * - SUCCESS - * - FAILED - * - DESTROY_ME if this IKE_SA MUST be deleted + * - SUCCESS + * - FAILED + * - DESTROY_ME if this IKE_SA MUST be deleted */ status_t (*process_message) (ike_sa_t *this, message_t *message); @@ -700,12 +710,12 @@ struct ike_sa_t { * This method generates all payloads in the message and encrypts/signs * the packet. * - * @param message message to generate + * @param message message to generate * @param packet generated output packet * @return - * - SUCCESS - * - FAILED - * - DESTROY_ME if this IKE_SA MUST be deleted + * - SUCCESS + * - FAILED + * - DESTROY_ME if this IKE_SA MUST be deleted */ status_t (*generate_message) (ike_sa_t *this, message_t *message, packet_t **packet); @@ -715,8 +725,8 @@ struct ike_sa_t { * * @param message_id ID of the request to retransmit * @return - * - SUCCESS - * - NOT_FOUND if request doesn't have to be retransmited + * - SUCCESS + * - NOT_FOUND if request doesn't have to be retransmited */ status_t (*retransmit) (ike_sa_t *this, u_int32_t message_id); @@ -728,8 +738,8 @@ struct ike_sa_t { * other traffic was received. * * @return - * - SUCCESS - * - DESTROY_ME, if peer did not respond + * - SUCCESS + * - DESTROY_ME, if peer did not respond */ status_t (*send_dpd) (ike_sa_t *this); @@ -769,11 +779,25 @@ struct ike_sa_t { u_int32_t spi, bool inbound); /** - * Create an iterator over all CHILD_SAs. + * Get the number of CHILD_SAs. + * + * @return number of CHILD_SAs + */ + int (*get_child_count) (ike_sa_t *this); + + /** + * Create an enumerator over all CHILD_SAs. + * + * @return enumerator + */ + enumerator_t* (*create_child_sa_enumerator) (ike_sa_t *this); + + /** + * Remove the CHILD_SA the given enumerator points to from this IKE_SA. * - * @return iterator + * @param enumerator enumerator pointing to CHILD_SA */ - iterator_t* (*create_child_sa_iterator) (ike_sa_t *this); + void (*remove_child_sa) (ike_sa_t *this, enumerator_t *enumerator); /** * Rekey the CHILD SA with the specified reqid. @@ -783,8 +807,8 @@ struct ike_sa_t { * @param protocol protocol of the SA * @param spi inbound SPI of the CHILD_SA * @return - * - NOT_FOUND, if IKE_SA has no such CHILD_SA - * - SUCCESS, if rekeying initiated + * - NOT_FOUND, if IKE_SA has no such CHILD_SA + * - SUCCESS, if rekeying initiated */ status_t (*rekey_child_sa) (ike_sa_t *this, protocol_id_t protocol, u_int32_t spi); @@ -798,8 +822,8 @@ struct ike_sa_t { * @param protocol protocol of the SA * @param spi inbound SPI of the CHILD_SA * @return - * - NOT_FOUND, if IKE_SA has no such CHILD_SA - * - SUCCESS, if delete message sent + * - NOT_FOUND, if IKE_SA has no such CHILD_SA + * - SUCCESS, if delete message sent */ status_t (*delete_child_sa) (ike_sa_t *this, protocol_id_t protocol, u_int32_t spi); @@ -811,8 +835,8 @@ struct ike_sa_t { * @param protocol protocol of the SA * @param spi inbound SPI of the CHILD_SA * @return - * - NOT_FOUND, if IKE_SA has no such CHILD_SA - * - SUCCESS + * - NOT_FOUND, if IKE_SA has no such CHILD_SA + * - SUCCESS */ status_t (*destroy_child_sa) (ike_sa_t *this, protocol_id_t protocol, u_int32_t spi); @@ -845,11 +869,15 @@ struct ike_sa_t { status_t (*reestablish) (ike_sa_t *this); /** - * Set the lifetime limit received from a AUTH_LIFETIME notify. + * Set the lifetime limit received/to send in a AUTH_LIFETIME notify. + * + * If the IKE_SA is already ESTABLISHED, an INFORMATIONAL is sent with + * an AUTH_LIFETIME notify. The call never fails on unestablished SAs. * * @param lifetime lifetime in seconds + * @return DESTROY_ME to destroy the IKE_SA */ - void (*set_auth_lifetime)(ike_sa_t *this, u_int32_t lifetime); + status_t (*set_auth_lifetime)(ike_sa_t *this, u_int32_t lifetime); /** * Set the virtual IP to use for this IKE_SA and its children. @@ -929,8 +957,8 @@ struct ike_sa_t { /** * Creates an ike_sa_t object with a specific ID. * - * @param ike_sa_id ike_sa_id_t object to associate with new IKE_SA - * @return ike_sa_t object + * @param ike_sa_id ike_sa_id_t object to associate with new IKE_SA + * @return ike_sa_t object */ ike_sa_t *ike_sa_create(ike_sa_id_t *ike_sa_id); diff --git a/src/libcharon/sa/ike_sa_id.c b/src/libcharon/sa/ike_sa_id.c index 94c5405f2..bea4c2124 100644 --- a/src/libcharon/sa/ike_sa_id.c +++ b/src/libcharon/sa/ike_sa_id.c @@ -46,42 +46,32 @@ struct private_ike_sa_id_t { bool is_initiator_flag; }; -/** - * Implementation of ike_sa_id_t.set_responder_spi. - */ -static void set_responder_spi (private_ike_sa_id_t *this, u_int64_t responder_spi) +METHOD(ike_sa_id_t, set_responder_spi, void, + private_ike_sa_id_t *this, u_int64_t responder_spi) { this->responder_spi = responder_spi; } -/** - * Implementation of ike_sa_id_t.set_initiator_spi. - */ -static void set_initiator_spi(private_ike_sa_id_t *this, u_int64_t initiator_spi) +METHOD(ike_sa_id_t, set_initiator_spi, void, + private_ike_sa_id_t *this, u_int64_t initiator_spi) { this->initiator_spi = initiator_spi; } -/** - * Implementation of ike_sa_id_t.get_initiator_spi. - */ -static u_int64_t get_initiator_spi (private_ike_sa_id_t *this) +METHOD(ike_sa_id_t, get_initiator_spi, u_int64_t, + private_ike_sa_id_t *this) { return this->initiator_spi; } -/** - * Implementation of ike_sa_id_t.get_responder_spi. - */ -static u_int64_t get_responder_spi (private_ike_sa_id_t *this) +METHOD(ike_sa_id_t, get_responder_spi, u_int64_t, + private_ike_sa_id_t *this) { return this->responder_spi; } -/** - * Implementation of ike_sa_id_t.equals. - */ -static bool equals (private_ike_sa_id_t *this, private_ike_sa_id_t *other) +METHOD(ike_sa_id_t, equals, bool, + private_ike_sa_id_t *this, private_ike_sa_id_t *other) { if (other == NULL) { @@ -101,28 +91,22 @@ static bool equals (private_ike_sa_id_t *this, private_ike_sa_id_t *other) } } -/** - * Implementation of ike_sa_id_t.replace_values. - */ -static void replace_values(private_ike_sa_id_t *this, private_ike_sa_id_t *other) +METHOD(ike_sa_id_t, replace_values, void, + private_ike_sa_id_t *this, private_ike_sa_id_t *other) { this->initiator_spi = other->initiator_spi; this->responder_spi = other->responder_spi; this->is_initiator_flag = other->is_initiator_flag; } -/** - * Implementation of ike_sa_id_t.is_initiator. - */ -static bool is_initiator(private_ike_sa_id_t *this) +METHOD(ike_sa_id_t, is_initiator, bool, + private_ike_sa_id_t *this) { return this->is_initiator_flag; } -/** - * Implementation of ike_sa_id_t.switch_initiator. - */ -static bool switch_initiator(private_ike_sa_id_t *this) +METHOD(ike_sa_id_t, switch_initiator, bool, + private_ike_sa_id_t *this) { if (this->is_initiator_flag) { @@ -135,18 +119,15 @@ static bool switch_initiator(private_ike_sa_id_t *this) return this->is_initiator_flag; } -/** - * Implementation of ike_sa_id_t.clone. - */ -static ike_sa_id_t* clone_(private_ike_sa_id_t *this) +METHOD(ike_sa_id_t, clone_, ike_sa_id_t*, + private_ike_sa_id_t *this) { - return ike_sa_id_create(this->initiator_spi, this->responder_spi, this->is_initiator_flag); + return ike_sa_id_create(this->initiator_spi, this->responder_spi, + this->is_initiator_flag); } -/** - * Implementation of ike_sa_id_t.destroy. - */ -static void destroy(private_ike_sa_id_t *this) +METHOD(ike_sa_id_t, destroy, void, + private_ike_sa_id_t *this) { free(this); } @@ -154,26 +135,28 @@ static void destroy(private_ike_sa_id_t *this) /* * Described in header. */ -ike_sa_id_t * ike_sa_id_create(u_int64_t initiator_spi, u_int64_t responder_spi, bool is_initiator_flag) +ike_sa_id_t * ike_sa_id_create(u_int64_t initiator_spi, u_int64_t responder_spi, + bool is_initiator_flag) { - private_ike_sa_id_t *this = malloc_thing(private_ike_sa_id_t); - - /* public functions */ - this->public.set_responder_spi = (void(*)(ike_sa_id_t*,u_int64_t)) set_responder_spi; - this->public.set_initiator_spi = (void(*)(ike_sa_id_t*,u_int64_t)) set_initiator_spi; - this->public.get_responder_spi = (u_int64_t(*)(ike_sa_id_t*)) get_responder_spi; - this->public.get_initiator_spi = (u_int64_t(*)(ike_sa_id_t*)) get_initiator_spi; - this->public.equals = (bool(*)(ike_sa_id_t*,ike_sa_id_t*)) equals; - this->public.replace_values = (void(*)(ike_sa_id_t*,ike_sa_id_t*)) replace_values; - this->public.is_initiator = (bool(*)(ike_sa_id_t*)) is_initiator; - this->public.switch_initiator = (bool(*)(ike_sa_id_t*)) switch_initiator; - this->public.clone = (ike_sa_id_t*(*)(ike_sa_id_t*)) clone_; - this->public.destroy = (void(*)(ike_sa_id_t*))destroy; - - /* private data */ - this->initiator_spi = initiator_spi; - this->responder_spi = responder_spi; - this->is_initiator_flag = is_initiator_flag; + private_ike_sa_id_t *this; + + INIT(this, + .public = { + .set_responder_spi = _set_responder_spi, + .set_initiator_spi = _set_initiator_spi, + .get_responder_spi = _get_responder_spi, + .get_initiator_spi = _get_initiator_spi, + .equals = (void*)_equals, + .replace_values = (void*)_replace_values, + .is_initiator = _is_initiator, + .switch_initiator = _switch_initiator, + .clone = _clone_, + .destroy = _destroy, + }, + .initiator_spi = initiator_spi, + .responder_spi = responder_spi, + .is_initiator_flag = is_initiator_flag, + ); return &this->public; } diff --git a/src/libcharon/sa/ike_sa_id.h b/src/libcharon/sa/ike_sa_id.h index a833aa9d6..fb55359bc 100644 --- a/src/libcharon/sa/ike_sa_id.h +++ b/src/libcharon/sa/ike_sa_id.h @@ -30,7 +30,7 @@ typedef struct ike_sa_id_t ike_sa_id_t; * An object of type ike_sa_id_t is used to identify an IKE_SA. * * An IKE_SA is identified by its initiator and responder spi's. - * Additionaly it contains the role of the actual running IKEv2-Daemon + * Additionally it contains the role of the actual running IKEv2 daemon * for the specific IKE_SA (original initiator or responder). */ struct ike_sa_id_t { @@ -40,28 +40,28 @@ struct ike_sa_id_t { * * This function is called when a request or reply of a IKE_SA_INIT is received. * - * @param responder_spi SPI of responder to set + * @param responder_spi SPI of responder to set */ void (*set_responder_spi) (ike_sa_id_t *this, u_int64_t responder_spi); /** * Set the SPI of the initiator. * - * @param initiator_spi SPI to set + * @param initiator_spi SPI to set */ void (*set_initiator_spi) (ike_sa_id_t *this, u_int64_t initiator_spi); /** * Get the initiator SPI. * - * @return SPI of the initiator + * @return SPI of the initiator */ u_int64_t (*get_initiator_spi) (ike_sa_id_t *this); /** * Get the responder SPI. * - * @return SPI of the responder + * @return SPI of the responder */ u_int64_t (*get_responder_spi) (ike_sa_id_t *this); @@ -70,8 +70,8 @@ struct ike_sa_id_t { * * Two ike_sa_id_t objects are equal if both SPI values and the role matches. * - * @param other ike_sa_id_t object to check if equal - * @return TRUE if given ike_sa_id_t are equal, FALSE otherwise + * @param other ike_sa_id_t object to check if equal + * @return TRUE if given ike_sa_id_t are equal, FALSE otherwise */ bool (*equals) (ike_sa_id_t *this, ike_sa_id_t *other); @@ -81,28 +81,28 @@ struct ike_sa_id_t { * * After calling this function, both objects are equal. * - * @param other ike_sa_id_t object from which values will be taken + * @param other ike_sa_id_t object from which values will be taken */ void (*replace_values) (ike_sa_id_t *this, ike_sa_id_t *other); /** * Get the initiator flag. * - * @return TRUE if we are the original initator + * @return TRUE if we are the original initiator */ bool (*is_initiator) (ike_sa_id_t *this); /** * Switche the original initiator flag. * - * @return TRUE if we are the original initator after switch, FALSE otherwise + * @return TRUE if we are the original initiator after switch, FALSE otherwise */ bool (*switch_initiator) (ike_sa_id_t *this); /** * Clones a given ike_sa_id_t object. * - * @return cloned ike_sa_id_t object + * @return cloned ike_sa_id_t object */ ike_sa_id_t *(*clone) (ike_sa_id_t *this); diff --git a/src/libcharon/sa/ike_sa_manager.c b/src/libcharon/sa/ike_sa_manager.c index d695c7f7c..731ae6007 100644 --- a/src/libcharon/sa/ike_sa_manager.c +++ b/src/libcharon/sa/ike_sa_manager.c @@ -307,72 +307,72 @@ struct private_ike_sa_manager_t { /** * Public interface of ike_sa_manager_t. */ - ike_sa_manager_t public; - - /** - * Hash table with entries for the ike_sa_t objects. - */ - linked_list_t **ike_sa_table; - - /** - * The size of the hash table. - */ - u_int table_size; - - /** - * Mask to map the hashes to table rows. - */ - u_int table_mask; - - /** - * Segments of the hash table. - */ - segment_t *segments; - - /** - * The number of segments. - */ - u_int segment_count; - - /** - * Mask to map a table row to a segment. - */ - u_int segment_mask; - - /** - * Hash table with half_open_t objects. - */ - linked_list_t **half_open_table; - - /** + ike_sa_manager_t public; + + /** + * Hash table with entries for the ike_sa_t objects. + */ + linked_list_t **ike_sa_table; + + /** + * The size of the hash table. + */ + u_int table_size; + + /** + * Mask to map the hashes to table rows. + */ + u_int table_mask; + + /** + * Segments of the hash table. + */ + segment_t *segments; + + /** + * The number of segments. + */ + u_int segment_count; + + /** + * Mask to map a table row to a segment. + */ + u_int segment_mask; + + /** + * Hash table with half_open_t objects. + */ + linked_list_t **half_open_table; + + /** * Segments of the "half-open" hash table. - */ - shareable_segment_t *half_open_segments; + */ + shareable_segment_t *half_open_segments; - /** - * Hash table with connected_peers_t objects. - */ - linked_list_t **connected_peers_table; + /** + * Hash table with connected_peers_t objects. + */ + linked_list_t **connected_peers_table; - /** - * Segments of the "connected peers" hash table. - */ - shareable_segment_t *connected_peers_segments; + /** + * Segments of the "connected peers" hash table. + */ + shareable_segment_t *connected_peers_segments; - /** - * RNG to get random SPIs for our side - */ - rng_t *rng; + /** + * RNG to get random SPIs for our side + */ + rng_t *rng; - /** - * SHA1 hasher for IKE_SA_INIT retransmit detection - */ - hasher_t *hasher; + /** + * SHA1 hasher for IKE_SA_INIT retransmit detection + */ + hasher_t *hasher; /** * reuse existing IKE_SAs in checkout_by_config */ - bool reuse_ikesa; + bool reuse_ikesa; }; /** @@ -1134,8 +1134,7 @@ METHOD(ike_sa_manager_t, checkout_by_config, ike_sa_t*, METHOD(ike_sa_manager_t, checkout_by_id, ike_sa_t*, private_ike_sa_manager_t *this, u_int32_t id, bool child) { - enumerator_t *enumerator; - iterator_t *children; + enumerator_t *enumerator, *children; entry_t *entry; ike_sa_t *ike_sa = NULL; child_sa_t *child_sa; @@ -1151,8 +1150,8 @@ METHOD(ike_sa_manager_t, checkout_by_id, ike_sa_t*, /* look for a child with such a reqid ... */ if (child) { - children = entry->ike_sa->create_child_sa_iterator(entry->ike_sa); - while (children->iterate(children, (void**)&child_sa)) + children = entry->ike_sa->create_child_sa_enumerator(entry->ike_sa); + while (children->enumerate(children, (void**)&child_sa)) { if (child_sa->get_reqid(child_sa) == id) { @@ -1188,8 +1187,7 @@ METHOD(ike_sa_manager_t, checkout_by_id, ike_sa_t*, METHOD(ike_sa_manager_t, checkout_by_name, ike_sa_t*, private_ike_sa_manager_t *this, char *name, bool child) { - enumerator_t *enumerator; - iterator_t *children; + enumerator_t *enumerator, *children; entry_t *entry; ike_sa_t *ike_sa = NULL; child_sa_t *child_sa; @@ -1203,8 +1201,8 @@ METHOD(ike_sa_manager_t, checkout_by_name, ike_sa_t*, /* look for a child with such a policy name ... */ if (child) { - children = entry->ike_sa->create_child_sa_iterator(entry->ike_sa); - while (children->iterate(children, (void**)&child_sa)) + children = entry->ike_sa->create_child_sa_enumerator(entry->ike_sa); + while (children->enumerate(children, (void**)&child_sa)) { if (streq(child_sa->get_name(child_sa), name)) { @@ -1238,10 +1236,10 @@ METHOD(ike_sa_manager_t, checkout_by_name, ike_sa_t*, } /** - * enumerator filter function + * enumerator filter function, waiting variant */ -static bool enumerator_filter(private_ike_sa_manager_t *this, - entry_t **in, ike_sa_t **out, u_int *segment) +static bool enumerator_filter_wait(private_ike_sa_manager_t *this, + entry_t **in, ike_sa_t **out, u_int *segment) { if (wait_for_entry(this, *in, *segment)) { @@ -1251,11 +1249,28 @@ static bool enumerator_filter(private_ike_sa_manager_t *this, return FALSE; } +/** + * enumerator filter function, skipping variant + */ +static bool enumerator_filter_skip(private_ike_sa_manager_t *this, + entry_t **in, ike_sa_t **out, u_int *segment) +{ + if (!(*in)->driveout_new_threads && + !(*in)->driveout_waiting_threads && + !(*in)->checked_out) + { + *out = (*in)->ike_sa; + return TRUE; + } + return FALSE; +} + METHOD(ike_sa_manager_t, create_enumerator, enumerator_t*, - private_ike_sa_manager_t* this) + private_ike_sa_manager_t* this, bool wait) { return enumerator_create_filter(create_table_enumerator(this), - (void*)enumerator_filter, this, NULL); + wait ? (void*)enumerator_filter_wait : (void*)enumerator_filter_skip, + this, NULL); } METHOD(ike_sa_manager_t, checkin, void, @@ -1539,14 +1554,30 @@ METHOD(ike_sa_manager_t, has_contact, bool, return found; } -METHOD(ike_sa_manager_t, get_half_open_count, int, +METHOD(ike_sa_manager_t, get_count, u_int, + private_ike_sa_manager_t *this) +{ + u_int segment, count = 0; + mutex_t *mutex; + + for (segment = 0; segment < this->segment_count; segment++) + { + mutex = this->segments[segment & this->segment_mask].mutex; + mutex->lock(mutex); + count += this->segments[segment].count; + mutex->unlock(mutex); + } + return count; +} + +METHOD(ike_sa_manager_t, get_half_open_count, u_int, private_ike_sa_manager_t *this, host_t *ip) { linked_list_t *list; u_int segment, row; rwlock_t *lock; chunk_t addr; - int count = 0; + u_int count = 0; if (ip) { @@ -1728,6 +1759,7 @@ ike_sa_manager_t *ike_sa_manager_create() .create_enumerator = _create_enumerator, .checkin = _checkin, .checkin_and_destroy = _checkin_and_destroy, + .get_count = _get_count, .get_half_open_count = _get_half_open_count, .flush = _flush, .destroy = _destroy, diff --git a/src/libcharon/sa/ike_sa_manager.h b/src/libcharon/sa/ike_sa_manager.h index ec157ab3a..5e542e7df 100644 --- a/src/libcharon/sa/ike_sa_manager.h +++ b/src/libcharon/sa/ike_sa_manager.h @@ -162,9 +162,10 @@ struct ike_sa_manager_t { * While enumerating an IKE_SA, it is temporarily checked out and * automatically checked in after the current enumeration step. * + * @param wait TRUE to wait for checked out SAs, FALSE to skip * @return enumerator over all IKE_SAs. */ - enumerator_t *(*create_enumerator) (ike_sa_manager_t* this); + enumerator_t *(*create_enumerator) (ike_sa_manager_t* this, bool wait); /** * Checkin the SA after usage. @@ -191,6 +192,13 @@ struct ike_sa_manager_t { void (*checkin_and_destroy) (ike_sa_manager_t* this, ike_sa_t *ike_sa); /** + * Get the number of IKE_SAs currently registered. + * + * @return number of registered IKE_SAs + */ + u_int (*get_count)(ike_sa_manager_t *this); + + /** * Get the number of IKE_SAs which are in the connecting state. * * To prevent the server from resource exhaustion, cookies and other @@ -203,7 +211,7 @@ struct ike_sa_manager_t { * @param ip NULL for all, IP for half open IKE_SAs with IP * @return number of half open IKE_SAs */ - int (*get_half_open_count) (ike_sa_manager_t *this, host_t *ip); + u_int (*get_half_open_count) (ike_sa_manager_t *this, host_t *ip); /** * Delete all existing IKE_SAs and destroy them immediately. diff --git a/src/libcharon/sa/keymat.c b/src/libcharon/sa/keymat.c index 33ece24b2..d762fa34e 100644 --- a/src/libcharon/sa/keymat.c +++ b/src/libcharon/sa/keymat.c @@ -99,7 +99,9 @@ keylen_entry_t keylen_enc[] = { */ keylen_entry_t keylen_int[] = { {AUTH_HMAC_MD5_96, 128}, + {AUTH_HMAC_MD5_128, 128}, {AUTH_HMAC_SHA1_96, 160}, + {AUTH_HMAC_SHA1_160, 160}, {AUTH_HMAC_SHA2_256_96, 256}, {AUTH_HMAC_SHA2_256_128, 256}, {AUTH_HMAC_SHA2_384_192, 384}, diff --git a/src/libcharon/sa/keymat.h b/src/libcharon/sa/keymat.h index 11e0fa79a..6c2b5d4b5 100644 --- a/src/libcharon/sa/keymat.h +++ b/src/libcharon/sa/keymat.h @@ -40,7 +40,12 @@ struct keymat_t { * * The diffie hellman is either for IKE negotiation/rekeying or * CHILD_SA rekeying (using PFS). The resulting DH object must be passed - * to derive_keys or to derive_child_keys and destroyed after use + * to derive_keys or to derive_child_keys and destroyed after use. + * + * Only DH objects allocated through this method are passed to other + * keymat_t methods, allowing private DH implementations. In some cases + * (such as retrying with a COOKIE), a DH object allocated from a different + * keymat_t instance may be passed to other methods. * * @param group diffie hellman group * @return DH object, NULL if group not supported diff --git a/src/libcharon/sa/mediation_manager.c b/src/libcharon/sa/mediation_manager.c index 2fbab7c7c..60eeb5d4b 100644 --- a/src/libcharon/sa/mediation_manager.c +++ b/src/libcharon/sa/mediation_manager.c @@ -53,13 +53,12 @@ static void peer_destroy(peer_t *this) */ static peer_t *peer_create(identification_t *id, ike_sa_id_t* ike_sa_id) { - peer_t *this = malloc_thing(peer_t); - - /* clone everything */ - this->id = id->clone(id); - this->ike_sa_id = ike_sa_id ? ike_sa_id->clone(ike_sa_id) : NULL; - this->requested_by = linked_list_create(); - + peer_t *this; + INIT(this, + .id = id->clone(id), + .ike_sa_id = ike_sa_id ? ike_sa_id->clone(ike_sa_id) : NULL, + .requested_by = linked_list_create(), + ); return this; } @@ -90,19 +89,19 @@ struct private_mediation_manager_t { */ static void register_peer(peer_t *peer, identification_t *peer_id) { - iterator_t *iterator; + enumerator_t *enumerator; identification_t *current; - iterator = peer->requested_by->create_iterator(peer->requested_by, TRUE); - while (iterator->iterate(iterator, (void**)¤t)) + enumerator = peer->requested_by->create_enumerator(peer->requested_by); + while (enumerator->enumerate(enumerator, (void**)¤t)) { if (peer_id->equals(peer_id, current)) { - iterator->destroy(iterator); + enumerator->destroy(enumerator); return; } } - iterator->destroy(iterator); + enumerator->destroy(enumerator); peer->requested_by->insert_last(peer->requested_by, peer_id->clone(peer_id)); @@ -114,12 +113,12 @@ static void register_peer(peer_t *peer, identification_t *peer_id) static status_t get_peer_by_id(private_mediation_manager_t *this, identification_t *id, peer_t **peer) { - iterator_t *iterator; + enumerator_t *enumerator; peer_t *current; status_t status = NOT_FOUND; - iterator = this->peers->create_iterator(this->peers, TRUE); - while (iterator->iterate(iterator, (void**)¤t)) + enumerator = this->peers->create_enumerator(this->peers); + while (enumerator->enumerate(enumerator, (void**)¤t)) { if (id->equals(id, current->id)) { @@ -131,7 +130,7 @@ static status_t get_peer_by_id(private_mediation_manager_t *this, break; } } - iterator->destroy(iterator); + enumerator->destroy(enumerator); return status; } @@ -144,52 +143,50 @@ static status_t get_peer_by_id(private_mediation_manager_t *this, static void unregister_peer(private_mediation_manager_t *this, identification_t *peer_id) { - iterator_t *iterator, *iterator_r; + enumerator_t *enumerator, *enumerator_r; peer_t *peer; identification_t *registered; - iterator = this->peers->create_iterator(this->peers, TRUE); - while (iterator->iterate(iterator, (void**)&peer)) + enumerator = this->peers->create_enumerator(this->peers); + while (enumerator->enumerate(enumerator, (void**)&peer)) { - iterator_r = peer->requested_by->create_iterator(peer->requested_by, - TRUE); - while (iterator_r->iterate(iterator_r, (void**)®istered)) + enumerator_r = peer->requested_by->create_enumerator(peer->requested_by); + while (enumerator_r->enumerate(enumerator_r, (void**)®istered)) { if (peer_id->equals(peer_id, registered)) { - iterator_r->remove(iterator_r); + peer->requested_by->remove_at(peer->requested_by, enumerator_r); registered->destroy(registered); break; } } - iterator_r->destroy(iterator_r); + enumerator_r->destroy(enumerator_r); - if (!peer->ike_sa_id && !peer->requested_by->get_count(peer->requested_by)) + if (!peer->ike_sa_id && + !peer->requested_by->get_count(peer->requested_by)) { - iterator->remove(iterator); + this->peers->remove_at(this->peers, enumerator); peer_destroy(peer); break; } } - iterator->destroy(iterator); + enumerator->destroy(enumerator); } -/** - * Implementation of mediation_manager_t.remove - */ -static void remove_sa(private_mediation_manager_t *this, ike_sa_id_t *ike_sa_id) +METHOD(mediation_manager_t, remove_sa, void, + private_mediation_manager_t *this, ike_sa_id_t *ike_sa_id) { - iterator_t *iterator; + enumerator_t *enumerator; peer_t *peer; this->mutex->lock(this->mutex); - iterator = this->peers->create_iterator(this->peers, TRUE); - while (iterator->iterate(iterator, (void**)&peer)) + enumerator = this->peers->create_enumerator(this->peers); + while (enumerator->enumerate(enumerator, (void**)&peer)) { if (ike_sa_id->equals(ike_sa_id, peer->ike_sa_id)) { - iterator->remove(iterator); + this->peers->remove_at(this->peers, enumerator); unregister_peer(this, peer->id); @@ -197,24 +194,23 @@ static void remove_sa(private_mediation_manager_t *this, ike_sa_id_t *ike_sa_id) break; } } - iterator->destroy(iterator); + enumerator->destroy(enumerator); this->mutex->unlock(this->mutex); } -/** - * Implementation of mediation_manager_t.update_sa_id - */ -static void update_sa_id(private_mediation_manager_t *this, identification_t *peer_id, ike_sa_id_t *ike_sa_id) +METHOD(mediation_manager_t, update_sa_id, void, + private_mediation_manager_t *this, identification_t *peer_id, + ike_sa_id_t *ike_sa_id) { - iterator_t *iterator; + enumerator_t *enumerator; peer_t *peer; bool found = FALSE; this->mutex->lock(this->mutex); - iterator = this->peers->create_iterator(this->peers, TRUE); - while (iterator->iterate(iterator, (void**)&peer)) + enumerator = this->peers->create_enumerator(this->peers); + while (enumerator->enumerate(enumerator, (void**)&peer)) { if (peer_id->equals(peer_id, peer->id)) { @@ -223,7 +219,7 @@ static void update_sa_id(private_mediation_manager_t *this, identification_t *pe break; } } - iterator->destroy(iterator); + enumerator->destroy(enumerator); if (!found) { @@ -248,11 +244,8 @@ static void update_sa_id(private_mediation_manager_t *this, identification_t *pe this->mutex->unlock(this->mutex); } -/** - * Implementation of mediation_manager_t.check. - */ -static ike_sa_id_t *check(private_mediation_manager_t *this, - identification_t *peer_id) +METHOD(mediation_manager_t, check, ike_sa_id_t*, + private_mediation_manager_t *this, identification_t *peer_id) { peer_t *peer; ike_sa_id_t *ike_sa_id; @@ -272,11 +265,9 @@ static ike_sa_id_t *check(private_mediation_manager_t *this, return ike_sa_id; } -/** - * Implementation of mediation_manager_t.check_and_register. - */ -static ike_sa_id_t *check_and_register(private_mediation_manager_t *this, - identification_t *peer_id, identification_t *requester) +METHOD(mediation_manager_t, check_and_register, ike_sa_id_t*, + private_mediation_manager_t *this, identification_t *peer_id, + identification_t *requester) { peer_t *peer; ike_sa_id_t *ike_sa_id; @@ -307,10 +298,8 @@ static ike_sa_id_t *check_and_register(private_mediation_manager_t *this, return ike_sa_id; } -/** - * Implementation of mediation_manager_t.destroy. - */ -static void destroy(private_mediation_manager_t *this) +METHOD(mediation_manager_t, destroy, void, + private_mediation_manager_t *this) { this->mutex->lock(this->mutex); @@ -326,16 +315,18 @@ static void destroy(private_mediation_manager_t *this) */ mediation_manager_t *mediation_manager_create() { - private_mediation_manager_t *this = malloc_thing(private_mediation_manager_t); - - this->public.destroy = (void(*)(mediation_manager_t*))destroy; - this->public.remove = (void(*)(mediation_manager_t*,ike_sa_id_t*))remove_sa; - this->public.update_sa_id = (void(*)(mediation_manager_t*,identification_t*,ike_sa_id_t*))update_sa_id; - this->public.check = (ike_sa_id_t*(*)(mediation_manager_t*,identification_t*))check; - this->public.check_and_register = (ike_sa_id_t*(*)(mediation_manager_t*,identification_t*,identification_t*))check_and_register; - - this->peers = linked_list_create(); - this->mutex = mutex_create(MUTEX_TYPE_DEFAULT); - - return (mediation_manager_t*)this; + private_mediation_manager_t *this; + + INIT(this, + .public = { + .destroy = _destroy, + .remove = _remove_sa, + .update_sa_id = _update_sa_id, + .check = _check, + .check_and_register = _check_and_register, + }, + .peers = linked_list_create(), + .mutex = mutex_create(MUTEX_TYPE_DEFAULT), + ); + return &this->public; } diff --git a/src/libcharon/sa/shunt_manager.c b/src/libcharon/sa/shunt_manager.c new file mode 100644 index 000000000..52b2ecd62 --- /dev/null +++ b/src/libcharon/sa/shunt_manager.c @@ -0,0 +1,251 @@ +/* + * Copyright (C) 2011 Andreas Steffen + * HSR 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. + */ + +#include "shunt_manager.h" + +#include <hydra.h> +#include <daemon.h> +#include <threading/rwlock.h> +#include <utils/linked_list.h> + + +typedef struct private_shunt_manager_t private_shunt_manager_t; + +/** + * Private data of an shunt_manager_t object. + */ +struct private_shunt_manager_t { + + /** + * Public shunt_manager_t interface. + */ + shunt_manager_t public; + + /** + * Installed shunts, as child_cfg_t + */ + linked_list_t *shunts; +}; + +/** + * Install in and out shunt policies in the kernel + */ +static bool install_shunt_policy(child_cfg_t *child) +{ + enumerator_t *e_my_ts, *e_other_ts; + linked_list_t *my_ts_list, *other_ts_list; + traffic_selector_t *my_ts, *other_ts; + host_t *host_any; + policy_type_t policy_type; + status_t status = SUCCESS; + ipsec_sa_cfg_t sa = { .mode = MODE_TRANSPORT }; + + policy_type = (child->get_mode(child) == MODE_PASS) ? + POLICY_PASS : POLICY_DROP; + my_ts_list = child->get_traffic_selectors(child, TRUE, NULL, NULL); + other_ts_list = child->get_traffic_selectors(child, FALSE, NULL, NULL); + host_any = host_create_any(AF_INET); + + /* enumerate pairs of traffic selectors */ + e_my_ts = my_ts_list->create_enumerator(my_ts_list); + while (e_my_ts->enumerate(e_my_ts, &my_ts)) + { + e_other_ts = other_ts_list->create_enumerator(other_ts_list); + while (e_other_ts->enumerate(e_other_ts, &other_ts)) + { + /* install out policy */ + status |= hydra->kernel_interface->add_policy( + hydra->kernel_interface, host_any, host_any, + my_ts, other_ts, POLICY_OUT, policy_type, + &sa, child->get_mark(child, FALSE), + POLICY_PRIORITY_DEFAULT); + + /* install in policy */ + status |= hydra->kernel_interface->add_policy( + hydra->kernel_interface, host_any, host_any, + other_ts, my_ts, POLICY_IN, policy_type, + &sa, child->get_mark(child, TRUE), + POLICY_PRIORITY_DEFAULT); + + /* install forward policy */ + status |= hydra->kernel_interface->add_policy( + hydra->kernel_interface, host_any, host_any, + other_ts, my_ts, POLICY_FWD, policy_type, + &sa, child->get_mark(child, TRUE), + POLICY_PRIORITY_DEFAULT); + } + e_other_ts->destroy(e_other_ts); + } + e_my_ts->destroy(e_my_ts); + + my_ts_list->destroy_offset(my_ts_list, + offsetof(traffic_selector_t, destroy)); + other_ts_list->destroy_offset(other_ts_list, + offsetof(traffic_selector_t, destroy)); + host_any->destroy(host_any); + + return status == SUCCESS; +} + +METHOD(shunt_manager_t, install, bool, + private_shunt_manager_t *this, child_cfg_t *child) +{ + enumerator_t *enumerator; + child_cfg_t *child_cfg; + bool found = FALSE; + + /* check if not already installed */ + enumerator = this->shunts->create_enumerator(this->shunts); + while (enumerator->enumerate(enumerator, &child_cfg)) + { + if (streq(child_cfg->get_name(child_cfg), child->get_name(child))) + { + found = TRUE; + break; + } + } + enumerator->destroy(enumerator); + + if (found) + { + DBG1(DBG_CFG, "shunt %N policy '%s' already installed", + ipsec_mode_names, child->get_mode(child), child->get_name(child)); + return TRUE; + } + this->shunts->insert_last(this->shunts, child->get_ref(child)); + + return install_shunt_policy(child); +} + +/** + * Uninstall in and out shunt policies in the kernel + */ +static void uninstall_shunt_policy(child_cfg_t *child) +{ + enumerator_t *e_my_ts, *e_other_ts; + linked_list_t *my_ts_list, *other_ts_list; + traffic_selector_t *my_ts, *other_ts; + status_t status = SUCCESS; + + my_ts_list = child->get_traffic_selectors(child, TRUE, NULL, NULL); + other_ts_list = child->get_traffic_selectors(child, FALSE, NULL, NULL); + + /* enumerate pairs of traffic selectors */ + e_my_ts = my_ts_list->create_enumerator(my_ts_list); + while (e_my_ts->enumerate(e_my_ts, &my_ts)) + { + e_other_ts = other_ts_list->create_enumerator(other_ts_list); + while (e_other_ts->enumerate(e_other_ts, &other_ts)) + { + /* uninstall out policy */ + status |= hydra->kernel_interface->del_policy( + hydra->kernel_interface, my_ts, other_ts, + POLICY_OUT, 0, child->get_mark(child, FALSE), + POLICY_PRIORITY_DEFAULT); + + /* uninstall in policy */ + status |= hydra->kernel_interface->del_policy( + hydra->kernel_interface, other_ts, my_ts, + POLICY_IN, 0, child->get_mark(child, TRUE), + POLICY_PRIORITY_DEFAULT); + + /* uninstall forward policy */ + status |= hydra->kernel_interface->del_policy( + hydra->kernel_interface, other_ts, my_ts, + POLICY_FWD, 0, child->get_mark(child, TRUE), + POLICY_PRIORITY_DEFAULT); + } + e_other_ts->destroy(e_other_ts); + } + e_my_ts->destroy(e_my_ts); + + my_ts_list->destroy_offset(my_ts_list, + offsetof(traffic_selector_t, destroy)); + other_ts_list->destroy_offset(other_ts_list, + offsetof(traffic_selector_t, destroy)); + + if (status != SUCCESS) + { + DBG1(DBG_CFG, "uninstalling shunt %N 'policy %s' failed", + ipsec_mode_names, child->get_mode(child), child->get_name(child)); + } +} + +METHOD(shunt_manager_t, uninstall, bool, + private_shunt_manager_t *this, char *name) +{ + enumerator_t *enumerator; + child_cfg_t *child, *found = NULL; + + enumerator = this->shunts->create_enumerator(this->shunts); + while (enumerator->enumerate(enumerator, &child)) + { + if (streq(name, child->get_name(child))) + { + this->shunts->remove_at(this->shunts, enumerator); + found = child; + break; + } + } + enumerator->destroy(enumerator); + + if (!found) + { + return FALSE; + } + uninstall_shunt_policy(child); + return TRUE; +} + +METHOD(shunt_manager_t, create_enumerator, enumerator_t*, + private_shunt_manager_t *this) +{ + return this->shunts->create_enumerator(this->shunts); +} + +METHOD(shunt_manager_t, destroy, void, + private_shunt_manager_t *this) +{ + child_cfg_t *child; + + while (this->shunts->remove_last(this->shunts, (void**)&child) == SUCCESS) + { + uninstall_shunt_policy(child); + child->destroy(child); + } + this->shunts->destroy(this->shunts); + free(this); +} + +/** + * See header + */ +shunt_manager_t *shunt_manager_create() +{ + private_shunt_manager_t *this; + + INIT(this, + .public = { + .install = _install, + .uninstall = _uninstall, + .create_enumerator = _create_enumerator, + .destroy = _destroy, + }, + .shunts = linked_list_create(), + ); + + return &this->public; +} + diff --git a/src/libcharon/sa/shunt_manager.h b/src/libcharon/sa/shunt_manager.h new file mode 100644 index 000000000..12ff08558 --- /dev/null +++ b/src/libcharon/sa/shunt_manager.h @@ -0,0 +1,69 @@ +/* + * Copyright (C) 2011 Andreas Steffen + * HSR 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. + */ + +/** + * @defgroup shunt_manager shunt_manager + * @{ @ingroup sa + */ + +#ifndef SHUNT_MANAGER_H_ +#define SHUNT_MANAGER_H_ + +#include <library.h> +#include <utils/enumerator.h> +#include <config/child_cfg.h> + +typedef struct shunt_manager_t shunt_manager_t; + +/** + * Manage PASS and DROP shunt policy excepting traffic from IPsec SAs. + */ +struct shunt_manager_t { + + /** + * Install a policy as a shunt. + * + * @param child child configuration to install as a shunt + * @return TRUE if installed successfully + */ + bool (*install)(shunt_manager_t *this, child_cfg_t *child); + + /** + * Uninstall a shunt policy. + * + * @param name name of child configuration to uninstall as a shunt + * @return TRUE if uninstalled successfully + */ + bool (*uninstall)(shunt_manager_t *this, char *name); + + /** + * Create an enumerator over all installed shunts. + * + * @return enumerator over (child_sa_t) + */ + enumerator_t* (*create_enumerator)(shunt_manager_t *this); + + /** + * Destroy a shunt_manager_t. + */ + void (*destroy)(shunt_manager_t *this); +}; + +/** + * Create a shunt_manager instance. + */ +shunt_manager_t *shunt_manager_create(); + +#endif /** SHUNT_MANAGER_H_ @}*/ diff --git a/src/libcharon/sa/task_manager.c b/src/libcharon/sa/task_manager.c index f07d2e384..022a5e3d6 100644 --- a/src/libcharon/sa/task_manager.c +++ b/src/libcharon/sa/task_manager.c @@ -159,15 +159,15 @@ struct private_task_manager_t { */ static void flush(private_task_manager_t *this) { - this->queued_tasks->destroy_offset(this->queued_tasks, - offsetof(task_t, destroy)); - this->queued_tasks = linked_list_create(); this->passive_tasks->destroy_offset(this->passive_tasks, offsetof(task_t, destroy)); this->passive_tasks = linked_list_create(); this->active_tasks->destroy_offset(this->active_tasks, offsetof(task_t, destroy)); this->active_tasks = linked_list_create(); + this->queued_tasks->destroy_offset(this->queued_tasks, + offsetof(task_t, destroy)); + this->queued_tasks = linked_list_create(); } /** @@ -175,23 +175,23 @@ static void flush(private_task_manager_t *this) */ static bool activate_task(private_task_manager_t *this, task_type_t type) { - iterator_t *iterator; + enumerator_t *enumerator; task_t *task; bool found = FALSE; - iterator = this->queued_tasks->create_iterator(this->queued_tasks, TRUE); - while (iterator->iterate(iterator, (void**)&task)) + enumerator = this->queued_tasks->create_enumerator(this->queued_tasks); + while (enumerator->enumerate(enumerator, (void**)&task)) { if (task->get_type(task) == type) { DBG2(DBG_IKE, " activating %N task", task_type_names, type); - iterator->remove(iterator); + this->queued_tasks->remove_at(this->queued_tasks, enumerator); this->active_tasks->insert_last(this->active_tasks, task); found = TRUE; break; } } - iterator->destroy(iterator); + enumerator->destroy(enumerator); return found; } @@ -202,14 +202,14 @@ METHOD(task_manager_t, retransmit, status_t, { u_int32_t timeout; job_t *job; - iterator_t *iterator; + enumerator_t *enumerator; packet_t *packet; task_t *task; ike_mobike_t *mobike = NULL; /* check if we are retransmitting a MOBIKE routability check */ - iterator = this->active_tasks->create_iterator(this->active_tasks, TRUE); - while (iterator->iterate(iterator, (void*)&task)) + enumerator = this->active_tasks->create_enumerator(this->active_tasks); + while (enumerator->enumerate(enumerator, (void*)&task)) { if (task->get_type(task) == IKE_MOBIKE) { @@ -221,7 +221,7 @@ METHOD(task_manager_t, retransmit, status_t, break; } } - iterator->destroy(iterator); + enumerator->destroy(enumerator); if (mobike == NULL) { @@ -282,7 +282,7 @@ METHOD(task_manager_t, retransmit, status_t, METHOD(task_manager_t, initiate, status_t, private_task_manager_t *this) { - iterator_t *iterator; + enumerator_t *enumerator; task_t *task; message_t *message; host_t *me, *other; @@ -366,6 +366,11 @@ METHOD(task_manager_t, initiate, status_t, exchange = INFORMATIONAL; break; } + if (activate_task(this, IKE_AUTH_LIFETIME)) + { + exchange = INFORMATIONAL; + break; + } #ifdef ME if (activate_task(this, IKE_ME)) { @@ -387,8 +392,8 @@ METHOD(task_manager_t, initiate, status_t, else { DBG2(DBG_IKE, "reinitiating already active tasks"); - iterator = this->active_tasks->create_iterator(this->active_tasks, TRUE); - while (iterator->iterate(iterator, (void**)&task)) + enumerator = this->active_tasks->create_enumerator(this->active_tasks); + while (enumerator->enumerate(enumerator, (void**)&task)) { DBG2(DBG_IKE, " %N task", task_type_names, task->get_type(task)); switch (task->get_type(task)) @@ -406,12 +411,13 @@ METHOD(task_manager_t, initiate, status_t, break; case IKE_MOBIKE: exchange = INFORMATIONAL; + break; default: continue; } break; } - iterator->destroy(iterator); + enumerator->destroy(enumerator); } if (exchange == 0) @@ -432,14 +438,14 @@ METHOD(task_manager_t, initiate, status_t, this->initiating.type = exchange; this->initiating.retransmitted = 0; - iterator = this->active_tasks->create_iterator(this->active_tasks, TRUE); - while (iterator->iterate(iterator, (void*)&task)) + enumerator = this->active_tasks->create_enumerator(this->active_tasks); + while (enumerator->enumerate(enumerator, (void*)&task)) { switch (task->build(task, message)) { case SUCCESS: /* task completed, remove it */ - iterator->remove(iterator); + this->active_tasks->remove_at(this->active_tasks, enumerator); task->destroy(task); break; case NEED_MORE: @@ -454,13 +460,13 @@ METHOD(task_manager_t, initiate, status_t, /* FALL */ case DESTROY_ME: /* critical failure, destroy IKE_SA */ - iterator->destroy(iterator); + enumerator->destroy(enumerator); message->destroy(message); flush(this); return DESTROY_ME; } } - iterator->destroy(iterator); + enumerator->destroy(enumerator); /* update exchange type if a task changed it */ this->initiating.type = message->get_exchange_type(message); @@ -487,7 +493,7 @@ METHOD(task_manager_t, initiate, status_t, static status_t process_response(private_task_manager_t *this, message_t *message) { - iterator_t *iterator; + enumerator_t *enumerator; task_t *task; if (message->get_exchange_type(message) != this->initiating.type) @@ -501,14 +507,14 @@ static status_t process_response(private_task_manager_t *this, /* catch if we get resetted while processing */ this->reset = FALSE; - iterator = this->active_tasks->create_iterator(this->active_tasks, TRUE); - while (iterator->iterate(iterator, (void*)&task)) + enumerator = this->active_tasks->create_enumerator(this->active_tasks); + while (enumerator->enumerate(enumerator, (void*)&task)) { switch (task->process(task, message)) { case SUCCESS: /* task completed, remove it */ - iterator->remove(iterator); + this->active_tasks->remove_at(this->active_tasks, enumerator); task->destroy(task); break; case NEED_MORE: @@ -520,19 +526,19 @@ static status_t process_response(private_task_manager_t *this, /* FALL */ case DESTROY_ME: /* critical failure, destroy IKE_SA */ - iterator->remove(iterator); - iterator->destroy(iterator); + this->active_tasks->remove_at(this->active_tasks, enumerator); + enumerator->destroy(enumerator); task->destroy(task); return DESTROY_ME; } if (this->reset) { /* start all over again if we were reset */ this->reset = FALSE; - iterator->destroy(iterator); + enumerator->destroy(enumerator); return initiate(this); } } - iterator->destroy(iterator); + enumerator->destroy(enumerator); this->initiating.mid++; this->initiating.type = EXCHANGE_TYPE_UNDEFINED; @@ -547,7 +553,7 @@ static status_t process_response(private_task_manager_t *this, */ static bool handle_collisions(private_task_manager_t *this, task_t *task) { - iterator_t *iterator; + enumerator_t *enumerator; task_t *active; task_type_t type; @@ -558,8 +564,8 @@ static bool handle_collisions(private_task_manager_t *this, task_t *task) type == CHILD_DELETE || type == IKE_DELETE || type == IKE_REAUTH) { /* find an exchange collision, and notify these tasks */ - iterator = this->active_tasks->create_iterator(this->active_tasks, TRUE); - while (iterator->iterate(iterator, (void**)&active)) + enumerator = this->active_tasks->create_enumerator(this->active_tasks); + while (enumerator->enumerate(enumerator, (void**)&active)) { switch (active->get_type(active)) { @@ -583,10 +589,10 @@ static bool handle_collisions(private_task_manager_t *this, task_t *task) default: continue; } - iterator->destroy(iterator); + enumerator->destroy(enumerator); return TRUE; } - iterator->destroy(iterator); + enumerator->destroy(enumerator); } return FALSE; } @@ -596,11 +602,11 @@ static bool handle_collisions(private_task_manager_t *this, task_t *task) */ static status_t build_response(private_task_manager_t *this, message_t *request) { - iterator_t *iterator; + enumerator_t *enumerator; task_t *task; message_t *message; host_t *me, *other; - bool delete = FALSE; + bool delete = FALSE, hook = FALSE; status_t status; me = request->get_destination(request); @@ -614,14 +620,14 @@ static status_t build_response(private_task_manager_t *this, message_t *request) message->set_message_id(message, this->responding.mid); message->set_request(message, FALSE); - iterator = this->passive_tasks->create_iterator(this->passive_tasks, TRUE); - while (iterator->iterate(iterator, (void*)&task)) + enumerator = this->passive_tasks->create_enumerator(this->passive_tasks); + while (enumerator->enumerate(enumerator, (void*)&task)) { switch (task->build(task, message)) { case SUCCESS: /* task completed, remove it */ - iterator->remove(iterator); + this->passive_tasks->remove_at(this->passive_tasks, enumerator); if (!handle_collisions(this, task)) { task->destroy(task); @@ -631,12 +637,13 @@ static status_t build_response(private_task_manager_t *this, message_t *request) /* processed, but task needs another exchange */ if (handle_collisions(this, task)) { - iterator->remove(iterator); + this->passive_tasks->remove_at(this->passive_tasks, + enumerator); } break; case FAILED: default: - charon->bus->ike_updown(charon->bus, this->ike_sa, FALSE); + hook = TRUE; /* FALL */ case DESTROY_ME: /* destroy IKE_SA, but SEND response first */ @@ -648,7 +655,7 @@ static status_t build_response(private_task_manager_t *this, message_t *request) break; } } - iterator->destroy(iterator); + enumerator->destroy(enumerator); /* remove resonder SPI if IKE_SA_INIT failed */ if (delete && request->get_exchange_type(request) == IKE_SA_INIT) @@ -673,6 +680,10 @@ static status_t build_response(private_task_manager_t *this, message_t *request) this->responding.packet->clone(this->responding.packet)); if (delete) { + if (hook) + { + charon->bus->ike_updown(charon->bus, this->ike_sa, FALSE); + } return DESTROY_ME; } return SUCCESS; @@ -685,7 +696,6 @@ static status_t process_request(private_task_manager_t *this, message_t *message) { enumerator_t *enumerator; - iterator_t *iterator; task_t *task = NULL; payload_t *payload; notify_payload_t *notify; @@ -854,14 +864,14 @@ static status_t process_request(private_task_manager_t *this, } /* let the tasks process the message */ - iterator = this->passive_tasks->create_iterator(this->passive_tasks, TRUE); - while (iterator->iterate(iterator, (void*)&task)) + enumerator = this->passive_tasks->create_enumerator(this->passive_tasks); + while (enumerator->enumerate(enumerator, (void*)&task)) { switch (task->process(task, message)) { case SUCCESS: /* task completed, remove it */ - iterator->remove(iterator); + this->passive_tasks->remove_at(this->passive_tasks, enumerator); task->destroy(task); break; case NEED_MORE: @@ -873,13 +883,13 @@ static status_t process_request(private_task_manager_t *this, /* FALL */ case DESTROY_ME: /* critical failure, destroy IKE_SA */ - iterator->remove(iterator); - iterator->destroy(iterator); + this->passive_tasks->remove_at(this->passive_tasks, enumerator); + enumerator->destroy(enumerator); task->destroy(task); return DESTROY_ME; } } - iterator->destroy(iterator); + enumerator->destroy(enumerator); return build_response(this, message); } @@ -978,20 +988,20 @@ METHOD(task_manager_t, queue_task, void, { if (task->get_type(task) == IKE_MOBIKE) { /* there is no need to queue more than one mobike task */ - iterator_t *iterator; + enumerator_t *enumerator; task_t *current; - iterator = this->queued_tasks->create_iterator(this->queued_tasks, TRUE); - while (iterator->iterate(iterator, (void**)¤t)) + enumerator = this->queued_tasks->create_enumerator(this->queued_tasks); + while (enumerator->enumerate(enumerator, (void**)¤t)) { if (current->get_type(current) == IKE_MOBIKE) { - iterator->destroy(iterator); + enumerator->destroy(enumerator); task->destroy(task); return; } } - iterator->destroy(iterator); + enumerator->destroy(enumerator); } DBG2(DBG_IKE, "queueing %N task", task_type_names, task->get_type(task)); this->queued_tasks->insert_last(this->queued_tasks, task); diff --git a/src/libcharon/sa/tasks/child_create.c b/src/libcharon/sa/tasks/child_create.c index fc02a334b..67c29d31f 100644 --- a/src/libcharon/sa/tasks/child_create.c +++ b/src/libcharon/sa/tasks/child_create.c @@ -213,13 +213,13 @@ static bool ts_list_is_host(linked_list_t *list, host_t *host) { traffic_selector_t *ts; bool is_host = TRUE; - iterator_t *iterator = list->create_iterator(list, TRUE); + enumerator_t *enumerator = list->create_enumerator(list); - while (is_host && iterator->iterate(iterator, (void**)&ts)) + while (is_host && enumerator->enumerate(enumerator, (void**)&ts)) { is_host = is_host && ts->is_host(ts, host); } - iterator->destroy(iterator); + enumerator->destroy(enumerator); return is_host; } @@ -886,6 +886,10 @@ static void handle_child_sa_failure(private_child_create_t *this, delete_ike_sa_job_create(this->ike_sa->get_id(this->ike_sa), TRUE), 100); } + else + { + DBG1(DBG_IKE, "failed to establish CHILD_SA, keeping IKE_SA"); + } } METHOD(task_t, build_r, status_t, diff --git a/src/libcharon/sa/tasks/child_delete.c b/src/libcharon/sa/tasks/child_delete.c index e6834a93c..dc4b30dd3 100644 --- a/src/libcharon/sa/tasks/child_delete.c +++ b/src/libcharon/sa/tasks/child_delete.c @@ -73,11 +73,11 @@ struct private_child_delete_t { static void build_payloads(private_child_delete_t *this, message_t *message) { delete_payload_t *ah = NULL, *esp = NULL; - iterator_t *iterator; + enumerator_t *enumerator; child_sa_t *child_sa; - iterator = this->child_sas->create_iterator(this->child_sas, TRUE); - while (iterator->iterate(iterator, (void**)&child_sa)) + enumerator = this->child_sas->create_enumerator(this->child_sas); + while (enumerator->enumerate(enumerator, (void**)&child_sa)) { protocol_id_t protocol = child_sa->get_protocol(child_sa); u_int32_t spi = child_sa->get_spi(child_sa, TRUE); @@ -109,7 +109,7 @@ static void build_payloads(private_child_delete_t *this, message_t *message) } child_sa->set_state(child_sa, CHILD_DELETING); } - iterator->destroy(iterator); + enumerator->destroy(enumerator); } /** @@ -186,7 +186,7 @@ static void process_payloads(private_child_delete_t *this, message_t *message) */ static status_t destroy_and_reestablish(private_child_delete_t *this) { - iterator_t *iterator; + enumerator_t *enumerator; child_sa_t *child_sa; child_cfg_t *child_cfg; protocol_id_t protocol; @@ -194,8 +194,8 @@ static status_t destroy_and_reestablish(private_child_delete_t *this) action_t action; status_t status = SUCCESS; - iterator = this->child_sas->create_iterator(this->child_sas, TRUE); - while (iterator->iterate(iterator, (void**)&child_sa)) + enumerator = this->child_sas->create_enumerator(this->child_sas); + while (enumerator->enumerate(enumerator, (void**)&child_sa)) { /* signal child down event if we are not rekeying */ if (!this->rekeyed) @@ -231,7 +231,7 @@ static status_t destroy_and_reestablish(private_child_delete_t *this) break; } } - iterator->destroy(iterator); + enumerator->destroy(enumerator); return status; } @@ -240,12 +240,12 @@ static status_t destroy_and_reestablish(private_child_delete_t *this) */ static void log_children(private_child_delete_t *this) { - iterator_t *iterator; + enumerator_t *enumerator; child_sa_t *child_sa; u_int64_t bytes_in, bytes_out; - iterator = this->child_sas->create_iterator(this->child_sas, TRUE); - while (iterator->iterate(iterator, (void**)&child_sa)) + enumerator = this->child_sas->create_enumerator(this->child_sas); + while (enumerator->enumerate(enumerator, (void**)&child_sa)) { child_sa->get_usestats(child_sa, TRUE, NULL, &bytes_in); child_sa->get_usestats(child_sa, FALSE, NULL, &bytes_out); @@ -258,13 +258,11 @@ static void log_children(private_child_delete_t *this) child_sa->get_traffic_selectors(child_sa, TRUE), child_sa->get_traffic_selectors(child_sa, FALSE)); } - iterator->destroy(iterator); + enumerator->destroy(enumerator); } -/** - * Implementation of task_t.build for initiator - */ -static status_t build_i(private_child_delete_t *this, message_t *message) +METHOD(task_t, build_i, status_t, + private_child_delete_t *this, message_t *message) { child_sa_t *child_sa; @@ -291,10 +289,8 @@ static status_t build_i(private_child_delete_t *this, message_t *message) return NEED_MORE; } -/** - * Implementation of task_t.process for initiator - */ -static status_t process_i(private_child_delete_t *this, message_t *message) +METHOD(task_t, process_i, status_t, + private_child_delete_t *this, message_t *message) { /* flush the list before adding new SAs */ this->child_sas->destroy(this->child_sas); @@ -305,20 +301,16 @@ static status_t process_i(private_child_delete_t *this, message_t *message) return destroy_and_reestablish(this); } -/** - * Implementation of task_t.process for initiator - */ -static status_t process_r(private_child_delete_t *this, message_t *message) +METHOD(task_t, process_r, status_t, + private_child_delete_t *this, message_t *message) { process_payloads(this, message); log_children(this); return NEED_MORE; } -/** - * Implementation of task_t.build for responder - */ -static status_t build_r(private_child_delete_t *this, message_t *message) +METHOD(task_t, build_r, status_t, + private_child_delete_t *this, message_t *message) { /* if we are rekeying, we send an empty informational */ if (this->ike_sa->get_state(this->ike_sa) != IKE_REKEYING) @@ -329,28 +321,22 @@ static status_t build_r(private_child_delete_t *this, message_t *message) return destroy_and_reestablish(this); } -/** - * Implementation of task_t.get_type - */ -static task_type_t get_type(private_child_delete_t *this) +METHOD(task_t, get_type, task_type_t, + private_child_delete_t *this) { return CHILD_DELETE; } -/** - * Implementation of child_delete_t.get_child - */ -static child_sa_t* get_child(private_child_delete_t *this) +METHOD(child_delete_t , get_child, child_sa_t*, + private_child_delete_t *this) { child_sa_t *child_sa = NULL; this->child_sas->get_first(this->child_sas, (void**)&child_sa); return child_sa; } -/** - * Implementation of task_t.migrate - */ -static void migrate(private_child_delete_t *this, ike_sa_t *ike_sa) +METHOD(task_t, migrate, void, + private_child_delete_t *this, ike_sa_t *ike_sa) { this->check_delete_action = FALSE; this->ike_sa = ike_sa; @@ -359,10 +345,8 @@ static void migrate(private_child_delete_t *this, ike_sa_t *ike_sa) this->child_sas = linked_list_create(); } -/** - * Implementation of task_t.destroy - */ -static void destroy(private_child_delete_t *this) +METHOD(task_t, destroy, void, + private_child_delete_t *this) { this->child_sas->destroy(this->child_sas); free(this); @@ -374,30 +358,33 @@ static void destroy(private_child_delete_t *this) child_delete_t *child_delete_create(ike_sa_t *ike_sa, protocol_id_t protocol, u_int32_t spi) { - private_child_delete_t *this = malloc_thing(private_child_delete_t); - - this->public.get_child = (child_sa_t*(*)(child_delete_t*))get_child; - this->public.task.get_type = (task_type_t(*)(task_t*))get_type; - this->public.task.migrate = (void(*)(task_t*,ike_sa_t*))migrate; - this->public.task.destroy = (void(*)(task_t*))destroy; - - this->ike_sa = ike_sa; - this->check_delete_action = FALSE; - this->child_sas = linked_list_create(); - this->protocol = protocol; - this->spi = spi; - this->rekeyed = FALSE; + private_child_delete_t *this; + + INIT(this, + .public = { + .task = { + .get_type = _get_type, + .migrate = _migrate, + .destroy = _destroy, + }, + .get_child = _get_child, + }, + .ike_sa = ike_sa, + .child_sas = linked_list_create(), + .protocol = protocol, + .spi = spi, + ); if (protocol != PROTO_NONE) { - this->public.task.build = (status_t(*)(task_t*,message_t*))build_i; - this->public.task.process = (status_t(*)(task_t*,message_t*))process_i; + this->public.task.build = _build_i; + this->public.task.process = _process_i; this->initiator = TRUE; } else { - this->public.task.build = (status_t(*)(task_t*,message_t*))build_r; - this->public.task.process = (status_t(*)(task_t*,message_t*))process_r; + this->public.task.build = _build_r; + this->public.task.process = _process_r; this->initiator = FALSE; } return &this->public; diff --git a/src/libcharon/sa/tasks/child_rekey.c b/src/libcharon/sa/tasks/child_rekey.c index b39a5fc67..76d185590 100644 --- a/src/libcharon/sa/tasks/child_rekey.c +++ b/src/libcharon/sa/tasks/child_rekey.c @@ -128,10 +128,8 @@ static void find_child(private_child_rekey_t *this, message_t *message) } } -/** - * Implementation of task_t.build for initiator - */ -static status_t build_i(private_child_rekey_t *this, message_t *message) +METHOD(task_t, build_i, status_t, + private_child_rekey_t *this, message_t *message) { notify_payload_t *notify; u_int32_t reqid; @@ -175,10 +173,8 @@ static status_t build_i(private_child_rekey_t *this, message_t *message) return NEED_MORE; } -/** - * Implementation of task_t.process for initiator - */ -static status_t process_r(private_child_rekey_t *this, message_t *message) +METHOD(task_t, process_r, status_t, + private_child_rekey_t *this, message_t *message) { /* let the CHILD_CREATE task process the message */ this->child_create->task.process(&this->child_create->task, message); @@ -188,10 +184,8 @@ static status_t process_r(private_child_rekey_t *this, message_t *message) return NEED_MORE; } -/** - * Implementation of task_t.build for responder - */ -static status_t build_r(private_child_rekey_t *this, message_t *message) +METHOD(task_t, build_r, status_t, + private_child_rekey_t *this, message_t *message) { u_int32_t reqid; @@ -252,7 +246,10 @@ static child_sa_t *handle_collision(private_child_rekey_t *this) { /* disable close action for the redundand child */ child_sa = other->child_create->get_child(other->child_create); - child_sa->set_close_action(child_sa, ACTION_NONE); + if (child_sa) + { + child_sa->set_close_action(child_sa, ACTION_NONE); + } } } else @@ -284,10 +281,8 @@ static child_sa_t *handle_collision(private_child_rekey_t *this) return to_delete; } -/** - * Implementation of task_t.process for initiator - */ -static status_t process_i(private_child_rekey_t *this, message_t *message) +METHOD(task_t, process_i, status_t, + private_child_rekey_t *this, message_t *message) { protocol_id_t protocol; u_int32_t spi; @@ -314,7 +309,7 @@ static status_t process_i(private_child_rekey_t *this, message_t *message) if (message->get_payload(message, SECURITY_ASSOCIATION) == NULL) { /* establishing new child failed, reuse old. but not when we - * recieved a delete in the meantime */ + * received a delete in the meantime */ if (!(this->collision && this->collision->get_type(this->collision) == CHILD_DELETE)) { @@ -364,18 +359,14 @@ static status_t process_i(private_child_rekey_t *this, message_t *message) return NEED_MORE; } -/** - * Implementation of task_t.get_type - */ -static task_type_t get_type(private_child_rekey_t *this) +METHOD(task_t, get_type, task_type_t, + private_child_rekey_t *this) { return CHILD_REKEY; } -/** - * Implementation of child_rekey_t.collide - */ -static void collide(private_child_rekey_t *this, task_t *other) +METHOD(child_rekey_t, collide, void, + private_child_rekey_t *this, task_t *other) { /* the task manager only detects exchange collision, but not if * the collision is for the same child. we check it here. */ @@ -418,10 +409,8 @@ static void collide(private_child_rekey_t *this, task_t *other) this->collision = other; } -/** - * Implementation of task_t.migrate - */ -static void migrate(private_child_rekey_t *this, ike_sa_t *ike_sa) +METHOD(task_t, migrate, void, + private_child_rekey_t *this, ike_sa_t *ike_sa) { if (this->child_create) { @@ -437,10 +426,8 @@ static void migrate(private_child_rekey_t *this, ike_sa_t *ike_sa) this->collision = NULL; } -/** - * Implementation of task_t.destroy - */ -static void destroy(private_child_rekey_t *this) +METHOD(task_t, destroy, void, + private_child_rekey_t *this) { if (this->child_create) { @@ -460,34 +447,36 @@ static void destroy(private_child_rekey_t *this) child_rekey_t *child_rekey_create(ike_sa_t *ike_sa, protocol_id_t protocol, u_int32_t spi) { - private_child_rekey_t *this = malloc_thing(private_child_rekey_t); - - this->public.collide = (void (*)(child_rekey_t*,task_t*))collide; - this->public.task.get_type = (task_type_t(*)(task_t*))get_type; - this->public.task.migrate = (void(*)(task_t*,ike_sa_t*))migrate; - this->public.task.destroy = (void(*)(task_t*))destroy; + private_child_rekey_t *this; + + INIT(this, + .public = { + .task = { + .get_type = _get_type, + .migrate = _migrate, + .destroy = _destroy, + }, + .collide = _collide, + }, + .ike_sa = ike_sa, + .protocol = protocol, + .spi = spi, + ); + if (protocol != PROTO_NONE) { - this->public.task.build = (status_t(*)(task_t*,message_t*))build_i; - this->public.task.process = (status_t(*)(task_t*,message_t*))process_i; + this->public.task.build = _build_i; + this->public.task.process = _process_i; this->initiator = TRUE; this->child_create = NULL; } else { - this->public.task.build = (status_t(*)(task_t*,message_t*))build_r; - this->public.task.process = (status_t(*)(task_t*,message_t*))process_r; + this->public.task.build = _build_r; + this->public.task.process = _process_r; this->initiator = FALSE; this->child_create = child_create_create(ike_sa, NULL, TRUE, NULL, NULL); } - this->ike_sa = ike_sa; - this->child_sa = NULL; - this->protocol = protocol; - this->spi = spi; - this->collision = NULL; - this->child_delete = NULL; - this->other_child_destroyed = FALSE; - return &this->public; } diff --git a/src/libcharon/sa/tasks/ike_auth.c b/src/libcharon/sa/tasks/ike_auth.c index 0756c7d60..665468fe8 100644 --- a/src/libcharon/sa/tasks/ike_auth.c +++ b/src/libcharon/sa/tasks/ike_auth.c @@ -1,4 +1,5 @@ /* + * Copyright (C) 2012 Tobias Brunner * Copyright (C) 2005-2009 Martin Willi * Copyright (C) 2005 Jan Hutter * Hochschule fuer Technik Rapperswil @@ -417,10 +418,14 @@ METHOD(task_t, build_i, status_t, cfg = this->ike_sa->get_auth_cfg(this->ike_sa, TRUE); cfg->merge(cfg, get_auth_cfg(this, TRUE), TRUE); idi = cfg->get(cfg, AUTH_RULE_IDENTITY); - if (!idi) - { - DBG1(DBG_CFG, "configuration misses IDi"); - return FAILED; + if (!idi || idi->get_type(idi) == ID_ANY) + { /* ID_ANY is invalid as IDi, use local IP address instead */ + host_t *me; + + DBG1(DBG_CFG, "no IDi configured, fall back on IP address"); + me = this->ike_sa->get_my_host(this->ike_sa); + idi = identification_create_from_sockaddr(me->get_sockaddr(me)); + cfg->add(cfg, AUTH_RULE_IDENTITY, idi); } this->ike_sa->set_my_id(this->ike_sa, idi->clone(idi)); id_payload = id_payload_create_from_identification(ID_INITIATOR, idi); @@ -669,8 +674,7 @@ METHOD(task_t, build_r, status_t, if (this->authentication_failed || this->peer_cfg == NULL) { - message->add_notify(message, TRUE, AUTHENTICATION_FAILED, chunk_empty); - return FAILED; + goto peer_auth_failed; } if (this->my_auth == NULL && this->do_another_auth) @@ -688,11 +692,14 @@ METHOD(task_t, build_r, status_t, if (id->get_type(id) == ID_ANY) { /* no IDr received, apply configured ID */ if (!id_cfg || id_cfg->contains_wildcards(id_cfg)) - { - DBG1(DBG_CFG, "IDr not configured and negotiation failed"); - message->add_notify(message, TRUE, AUTHENTICATION_FAILED, - chunk_empty); - return FAILED; + { /* no ID configured, use local IP address */ + host_t *me; + + DBG1(DBG_CFG, "no IDr configured, fall back on IP address"); + me = this->ike_sa->get_my_host(this->ike_sa); + id_cfg = identification_create_from_sockaddr( + me->get_sockaddr(me)); + cfg->add(cfg, AUTH_RULE_IDENTITY, id_cfg); } this->ike_sa->set_my_id(this->ike_sa, id_cfg->clone(id_cfg)); id = id_cfg; @@ -702,9 +709,7 @@ METHOD(task_t, build_r, status_t, if (id_cfg && !id->matches(id, id_cfg)) { DBG1(DBG_CFG, "received IDr %Y, but require %Y", id, id_cfg); - message->add_notify(message, TRUE, AUTHENTICATION_FAILED, - chunk_empty); - return FAILED; + goto peer_auth_failed; } } @@ -726,9 +731,7 @@ METHOD(task_t, build_r, status_t, { DBG1(DBG_IKE, "configured EAP-only authentication, but peer " "does not support it"); - message->add_notify(message, TRUE, AUTHENTICATION_FAILED, - chunk_empty); - return FAILED; + goto peer_auth_failed; } } else @@ -741,9 +744,7 @@ METHOD(task_t, build_r, status_t, this->reserved); if (!this->my_auth) { - message->add_notify(message, TRUE, AUTHENTICATION_FAILED, - chunk_empty); - return FAILED; + goto peer_auth_failed; } } } @@ -759,12 +760,11 @@ METHOD(task_t, build_r, status_t, case NEED_MORE: break; default: - if (!message->get_payload(message, EXTENSIBLE_AUTHENTICATION)) + if (message->get_payload(message, EXTENSIBLE_AUTHENTICATION)) { /* skip AUTHENTICATION_FAILED if we have EAP_FAILURE */ - message->add_notify(message, TRUE, AUTHENTICATION_FAILED, - chunk_empty); + goto peer_auth_failed_no_notify; } - return FAILED; + goto peer_auth_failed; } } if (this->my_auth) @@ -802,7 +802,7 @@ METHOD(task_t, build_r, status_t, if (charon->ike_sa_manager->check_uniqueness(charon->ike_sa_manager, this->ike_sa, FALSE)) { - DBG1(DBG_IKE, "cancelling IKE_SA setup due uniqueness policy"); + DBG1(DBG_IKE, "cancelling IKE_SA setup due to uniqueness policy"); message->add_notify(message, TRUE, AUTHENTICATION_FAILED, chunk_empty); return FAILED; @@ -810,9 +810,7 @@ METHOD(task_t, build_r, status_t, if (!charon->bus->authorize(charon->bus, TRUE)) { DBG1(DBG_IKE, "final authorization hook forbids IKE_SA, cancelling"); - message->add_notify(message, TRUE, AUTHENTICATION_FAILED, - chunk_empty); - return FAILED; + goto peer_auth_failed; } DBG0(DBG_IKE, "IKE_SA %s[%d] established between %H[%Y]...%H[%Y]", this->ike_sa->get_name(this->ike_sa), @@ -826,6 +824,13 @@ METHOD(task_t, build_r, status_t, return SUCCESS; } return NEED_MORE; + +peer_auth_failed: + message->add_notify(message, TRUE, AUTHENTICATION_FAILED, + chunk_empty); +peer_auth_failed_no_notify: + charon->bus->alert(charon->bus, ALERT_PEER_AUTH_FAILED); + return FAILED; } METHOD(task_t, process_i, status_t, @@ -908,7 +913,7 @@ METHOD(task_t, process_i, status_t, if (!id_payload) { DBG1(DBG_IKE, "IDr payload missing"); - return FAILED; + goto peer_auth_failed; } id = id_payload->get_identification(id_payload); get_reserved_id_bytes(this, id_payload); @@ -926,7 +931,7 @@ METHOD(task_t, process_i, status_t, this->reserved); if (!this->other_auth) { - return FAILED; + goto peer_auth_failed; } } else @@ -944,7 +949,7 @@ METHOD(task_t, process_i, status_t, case NEED_MORE: return NEED_MORE; default: - return FAILED; + goto peer_auth_failed; } this->other_auth->destroy(this->other_auth); this->other_auth = NULL; @@ -953,7 +958,7 @@ METHOD(task_t, process_i, status_t, if (!charon->bus->authorize(charon->bus, FALSE)) { DBG1(DBG_IKE, "authorization forbids IKE_SA, cancelling"); - return FAILED; + goto peer_auth_failed; } /* store authentication information, reset authenticator */ @@ -986,7 +991,7 @@ METHOD(task_t, process_i, status_t, if (!this->my_auth || !this->my_auth->is_mutual(this->my_auth)) { DBG1(DBG_IKE, "do not allow non-mutual EAP-only authentication"); - return FAILED; + goto peer_auth_failed; } DBG1(DBG_IKE, "allow mutual EAP-only authentication"); } @@ -999,12 +1004,13 @@ METHOD(task_t, process_i, status_t, { if (!update_cfg_candidates(this, TRUE)) { - return FAILED; + goto peer_auth_failed; } if (!charon->bus->authorize(charon->bus, TRUE)) { - DBG1(DBG_IKE, "final authorization hook forbids IKE_SA, cancelling"); - return FAILED; + DBG1(DBG_IKE, "final authorization hook forbids IKE_SA, " + "cancelling"); + goto peer_auth_failed; } DBG0(DBG_IKE, "IKE_SA %s[%d] established between %H[%Y]...%H[%Y]", this->ike_sa->get_name(this->ike_sa), @@ -1018,6 +1024,10 @@ METHOD(task_t, process_i, status_t, return SUCCESS; } return NEED_MORE; + +peer_auth_failed: + charon->bus->alert(charon->bus, ALERT_PEER_AUTH_FAILED); + return FAILED; } METHOD(task_t, get_type, task_type_t, diff --git a/src/libcharon/sa/tasks/ike_auth.h b/src/libcharon/sa/tasks/ike_auth.h index bba46d961..132907941 100644 --- a/src/libcharon/sa/tasks/ike_auth.h +++ b/src/libcharon/sa/tasks/ike_auth.h @@ -49,7 +49,7 @@ struct ike_auth_t { * Create a new task of type IKE_AUTHENTICATE. * * @param ike_sa IKE_SA this task works for - * @param initiator TRUE if thask is the initator of an exchange + * @param initiator TRUE if task is the initiator of an exchange * @return ike_auth task to handle by the task_manager */ ike_auth_t *ike_auth_create(ike_sa_t *ike_sa, bool initiator); diff --git a/src/libcharon/sa/tasks/ike_auth_lifetime.c b/src/libcharon/sa/tasks/ike_auth_lifetime.c index 75ff35168..a57cfd075 100644 --- a/src/libcharon/sa/tasks/ike_auth_lifetime.c +++ b/src/libcharon/sa/tasks/ike_auth_lifetime.c @@ -75,10 +75,8 @@ static void process_payloads(private_ike_auth_lifetime_t *this, message_t *messa } } -/** - * Implementation of task_t.process for initiator - */ -static status_t build_i(private_ike_auth_lifetime_t *this, message_t *message) +METHOD(task_t, build_i, status_t, + private_ike_auth_lifetime_t *this, message_t *message) { if (message->get_exchange_type(message) == INFORMATIONAL) { @@ -88,10 +86,8 @@ static status_t build_i(private_ike_auth_lifetime_t *this, message_t *message) return NEED_MORE; } -/** - * Implementation of task_t.process for responder - */ -static status_t process_r(private_ike_auth_lifetime_t *this, message_t *message) +METHOD(task_t, process_r, status_t, + private_ike_auth_lifetime_t *this, message_t *message) { if (message->get_exchange_type(message) == INFORMATIONAL) { @@ -101,10 +97,8 @@ static status_t process_r(private_ike_auth_lifetime_t *this, message_t *message) return NEED_MORE; } -/** - * Implementation of task_t.build for responder - */ -static status_t build_r(private_ike_auth_lifetime_t *this, message_t *message) +METHOD(task_t, build_r, status_t, + private_ike_auth_lifetime_t *this, message_t *message) { if (message->get_exchange_type(message) == IKE_AUTH && this->ike_sa->get_state(this->ike_sa) == IKE_ESTABLISHED) @@ -115,10 +109,8 @@ static status_t build_r(private_ike_auth_lifetime_t *this, message_t *message) return NEED_MORE; } -/** - * Implementation of task_t.process for initiator - */ -static status_t process_i(private_ike_auth_lifetime_t *this, message_t *message) +METHOD(task_t, process_i, status_t, + private_ike_auth_lifetime_t *this, message_t *message) { if (message->get_exchange_type(message) == IKE_AUTH && this->ike_sa->get_state(this->ike_sa) == IKE_ESTABLISHED) @@ -129,26 +121,20 @@ static status_t process_i(private_ike_auth_lifetime_t *this, message_t *message) return NEED_MORE; } -/** - * Implementation of task_t.get_type - */ -static task_type_t get_type(private_ike_auth_lifetime_t *this) +METHOD(task_t, get_type, task_type_t, + private_ike_auth_lifetime_t *this) { return IKE_AUTH_LIFETIME; } -/** - * Implementation of task_t.migrate - */ -static void migrate(private_ike_auth_lifetime_t *this, ike_sa_t *ike_sa) +METHOD(task_t, migrate, void, + private_ike_auth_lifetime_t *this, ike_sa_t *ike_sa) { this->ike_sa = ike_sa; } -/** - * Implementation of task_t.destroy - */ -static void destroy(private_ike_auth_lifetime_t *this) +METHOD(task_t, destroy, void, + private_ike_auth_lifetime_t *this) { free(this); } @@ -158,25 +144,30 @@ static void destroy(private_ike_auth_lifetime_t *this) */ ike_auth_lifetime_t *ike_auth_lifetime_create(ike_sa_t *ike_sa, bool initiator) { - private_ike_auth_lifetime_t *this = malloc_thing(private_ike_auth_lifetime_t); - - this->public.task.get_type = (task_type_t(*)(task_t*))get_type; - this->public.task.migrate = (void(*)(task_t*,ike_sa_t*))migrate; - this->public.task.destroy = (void(*)(task_t*))destroy; + private_ike_auth_lifetime_t *this; + + INIT(this, + .public = { + .task = { + .get_type = _get_type, + .migrate = _migrate, + .destroy = _destroy, + }, + }, + .ike_sa = ike_sa, + ); if (initiator) { - this->public.task.build = (status_t(*)(task_t*,message_t*))build_i; - this->public.task.process = (status_t(*)(task_t*,message_t*))process_i; + this->public.task.build = _build_i; + this->public.task.process = _process_i; } else { - this->public.task.build = (status_t(*)(task_t*,message_t*))build_r; - this->public.task.process = (status_t(*)(task_t*,message_t*))process_r; + this->public.task.build = _build_r; + this->public.task.process = _process_r; } - this->ike_sa = ike_sa; - return &this->public; } diff --git a/src/libcharon/sa/tasks/ike_cert_post.c b/src/libcharon/sa/tasks/ike_cert_post.c index cc810a49a..94af50eae 100644 --- a/src/libcharon/sa/tasks/ike_cert_post.c +++ b/src/libcharon/sa/tasks/ike_cert_post.c @@ -87,6 +87,7 @@ static cert_payload_t *build_cert_payload(private_ike_cert_post_t *this, if (enumerator->enumerate(enumerator, &url)) { payload = cert_payload_create_from_hash_and_url(hash, url); + DBG1(DBG_IKE, "sending hash-and-url \"%s\"", url); } else { @@ -167,28 +168,22 @@ static void build_certs(private_ike_cert_post_t *this, message_t *message) } } -/** - * Implementation of task_t.process for initiator - */ -static status_t build_i(private_ike_cert_post_t *this, message_t *message) +METHOD(task_t, build_i, status_t, + private_ike_cert_post_t *this, message_t *message) { build_certs(this, message); return NEED_MORE; } -/** - * Implementation of task_t.process for responder - */ -static status_t process_r(private_ike_cert_post_t *this, message_t *message) +METHOD(task_t, process_r, status_t, + private_ike_cert_post_t *this, message_t *message) { return NEED_MORE; } -/** - * Implementation of task_t.build for responder - */ -static status_t build_r(private_ike_cert_post_t *this, message_t *message) +METHOD(task_t, build_r, status_t, + private_ike_cert_post_t *this, message_t *message) { build_certs(this, message); @@ -199,10 +194,8 @@ static status_t build_r(private_ike_cert_post_t *this, message_t *message) return SUCCESS; } -/** - * Implementation of task_t.process for initiator - */ -static status_t process_i(private_ike_cert_post_t *this, message_t *message) +METHOD(task_t, process_i, status_t, + private_ike_cert_post_t *this, message_t *message) { if (this->ike_sa->get_state(this->ike_sa) != IKE_ESTABLISHED) { /* stay alive, we might have additional rounds with CERTS */ @@ -211,26 +204,20 @@ static status_t process_i(private_ike_cert_post_t *this, message_t *message) return SUCCESS; } -/** - * Implementation of task_t.get_type - */ -static task_type_t get_type(private_ike_cert_post_t *this) +METHOD(task_t, get_type, task_type_t, + private_ike_cert_post_t *this) { return IKE_CERT_POST; } -/** - * Implementation of task_t.migrate - */ -static void migrate(private_ike_cert_post_t *this, ike_sa_t *ike_sa) +METHOD(task_t, migrate, void, + private_ike_cert_post_t *this, ike_sa_t *ike_sa) { this->ike_sa = ike_sa; } -/** - * Implementation of task_t.destroy - */ -static void destroy(private_ike_cert_post_t *this) +METHOD(task_t, destroy, void, + private_ike_cert_post_t *this) { free(this); } @@ -240,26 +227,31 @@ static void destroy(private_ike_cert_post_t *this) */ ike_cert_post_t *ike_cert_post_create(ike_sa_t *ike_sa, bool initiator) { - private_ike_cert_post_t *this = malloc_thing(private_ike_cert_post_t); - - this->public.task.get_type = (task_type_t(*)(task_t*))get_type; - this->public.task.migrate = (void(*)(task_t*,ike_sa_t*))migrate; - this->public.task.destroy = (void(*)(task_t*))destroy; + private_ike_cert_post_t *this; + + INIT(this, + .public = { + .task = { + .get_type = _get_type, + .migrate = _migrate, + .destroy = _destroy, + }, + }, + .ike_sa = ike_sa, + .initiator = initiator, + ); if (initiator) { - this->public.task.build = (status_t(*)(task_t*,message_t*))build_i; - this->public.task.process = (status_t(*)(task_t*,message_t*))process_i; + this->public.task.build = _build_i; + this->public.task.process = _process_i; } else { - this->public.task.build = (status_t(*)(task_t*,message_t*))build_r; - this->public.task.process = (status_t(*)(task_t*,message_t*))process_r; + this->public.task.build = _build_r; + this->public.task.process = _process_r; } - this->ike_sa = ike_sa; - this->initiator = initiator; - return &this->public; } diff --git a/src/libcharon/sa/tasks/ike_cert_post.h b/src/libcharon/sa/tasks/ike_cert_post.h index a21f45927..b3881a01a 100644 --- a/src/libcharon/sa/tasks/ike_cert_post.h +++ b/src/libcharon/sa/tasks/ike_cert_post.h @@ -45,7 +45,7 @@ struct ike_cert_post_t { * of the certificate request. * * @param ike_sa IKE_SA this task works for - * @param initiator TRUE if thask is the original initator + * @param initiator TRUE if task is the original initiator * @return ike_cert_post task to handle by the task_manager */ ike_cert_post_t *ike_cert_post_create(ike_sa_t *ike_sa, bool initiator); diff --git a/src/libcharon/sa/tasks/ike_cert_pre.c b/src/libcharon/sa/tasks/ike_cert_pre.c index a59b8dcce..b33aebe46 100644 --- a/src/libcharon/sa/tasks/ike_cert_pre.c +++ b/src/libcharon/sa/tasks/ike_cert_pre.c @@ -51,7 +51,7 @@ struct private_ike_cert_pre_t { bool do_http_lookup; /** - * wheter this is the final authentication round + * whether this is the final authentication round */ bool final; }; @@ -424,10 +424,8 @@ static bool final_auth(message_t *message) return TRUE; } -/** - * Implementation of task_t.process for initiator - */ -static status_t build_i(private_ike_cert_pre_t *this, message_t *message) +METHOD(task_t, build_i, status_t, + private_ike_cert_pre_t *this, message_t *message) { if (message->get_message_id(message) == 1) { /* initiator sends CERTREQs in first IKE_AUTH */ @@ -436,10 +434,8 @@ static status_t build_i(private_ike_cert_pre_t *this, message_t *message) return NEED_MORE; } -/** - * Implementation of task_t.process for responder - */ -static status_t process_r(private_ike_cert_pre_t *this, message_t *message) +METHOD(task_t, process_r, status_t, + private_ike_cert_pre_t *this, message_t *message) { if (message->get_exchange_type(message) != IKE_SA_INIT) { /* handle certreqs/certs in any IKE_AUTH, just in case */ @@ -450,10 +446,8 @@ static status_t process_r(private_ike_cert_pre_t *this, message_t *message) return NEED_MORE; } -/** - * Implementation of task_t.build for responder - */ -static status_t build_r(private_ike_cert_pre_t *this, message_t *message) +METHOD(task_t, build_r, status_t, + private_ike_cert_pre_t *this, message_t *message) { if (message->get_exchange_type(message) == IKE_SA_INIT) { @@ -466,10 +460,8 @@ static status_t build_r(private_ike_cert_pre_t *this, message_t *message) return NEED_MORE; } -/** - * Implementation of task_t.process for initiator - */ -static status_t process_i(private_ike_cert_pre_t *this, message_t *message) +METHOD(task_t, process_i, status_t, + private_ike_cert_pre_t *this, message_t *message) { if (message->get_exchange_type(message) == IKE_SA_INIT) { @@ -484,26 +476,20 @@ static status_t process_i(private_ike_cert_pre_t *this, message_t *message) return NEED_MORE; } -/** - * Implementation of task_t.get_type - */ -static task_type_t get_type(private_ike_cert_pre_t *this) +METHOD(task_t, get_type, task_type_t, + private_ike_cert_pre_t *this) { return IKE_CERT_PRE; } -/** - * Implementation of task_t.migrate - */ -static void migrate(private_ike_cert_pre_t *this, ike_sa_t *ike_sa) +METHOD(task_t, migrate, void, + private_ike_cert_pre_t *this, ike_sa_t *ike_sa) { this->ike_sa = ike_sa; } -/** - * Implementation of task_t.destroy - */ -static void destroy(private_ike_cert_pre_t *this) +METHOD(task_t, destroy, void, + private_ike_cert_pre_t *this) { free(this); } @@ -513,27 +499,30 @@ static void destroy(private_ike_cert_pre_t *this) */ ike_cert_pre_t *ike_cert_pre_create(ike_sa_t *ike_sa, bool initiator) { - private_ike_cert_pre_t *this = malloc_thing(private_ike_cert_pre_t); - - this->public.task.get_type = (task_type_t(*)(task_t*))get_type; - this->public.task.migrate = (void(*)(task_t*,ike_sa_t*))migrate; - this->public.task.destroy = (void(*)(task_t*))destroy; + private_ike_cert_pre_t *this; + + INIT(this, + .public = { + .task = { + .get_type = _get_type, + .migrate = _migrate, + .destroy = _destroy, + }, + }, + .ike_sa = ike_sa, + .initiator = initiator, + ); if (initiator) { - this->public.task.build = (status_t(*)(task_t*,message_t*))build_i; - this->public.task.process = (status_t(*)(task_t*,message_t*))process_i; + this->public.task.build = _build_i; + this->public.task.process = _process_i; } else { - this->public.task.build = (status_t(*)(task_t*,message_t*))build_r; - this->public.task.process = (status_t(*)(task_t*,message_t*))process_r; + this->public.task.build = _build_r; + this->public.task.process = _process_r; } - this->ike_sa = ike_sa; - this->initiator = initiator; - this->do_http_lookup = FALSE; - this->final = FALSE; - return &this->public; } diff --git a/src/libcharon/sa/tasks/ike_cert_pre.h b/src/libcharon/sa/tasks/ike_cert_pre.h index 1541b80e5..4b2d0d470 100644 --- a/src/libcharon/sa/tasks/ike_cert_pre.h +++ b/src/libcharon/sa/tasks/ike_cert_pre.h @@ -45,7 +45,7 @@ struct ike_cert_pre_t { * of the certificate request. * * @param ike_sa IKE_SA this task works for - * @param initiator TRUE if thask is the original initator + * @param initiator TRUE if task is the original initiator * @return ike_cert_pre task to handle by the task_manager */ ike_cert_pre_t *ike_cert_pre_create(ike_sa_t *ike_sa, bool initiator); diff --git a/src/libcharon/sa/tasks/ike_config.c b/src/libcharon/sa/tasks/ike_config.c index a61663c48..4ef9c56a5 100644 --- a/src/libcharon/sa/tasks/ike_config.c +++ b/src/libcharon/sa/tasks/ike_config.c @@ -174,6 +174,11 @@ static void process_attribute(private_ike_config_t *this, } break; } + case INTERNAL_IP4_SERVER: + case INTERNAL_IP6_SERVER: + /* assume it's a Windows client if we see proprietary attributes */ + this->ike_sa->enable_extension(this->ike_sa, EXT_MS_WINDOWS); + /* fall */ default: { if (this->initiator) @@ -225,10 +230,8 @@ static void process_payloads(private_ike_config_t *this, message_t *message) enumerator->destroy(enumerator); } -/** - * Implementation of task_t.process for initiator - */ -static status_t build_i(private_ike_config_t *this, message_t *message) +METHOD(task_t, build_i, status_t, + private_ike_config_t *this, message_t *message) { if (message->get_message_id(message) == 1) { /* in first IKE_AUTH only */ @@ -287,10 +290,8 @@ static status_t build_i(private_ike_config_t *this, message_t *message) return NEED_MORE; } -/** - * Implementation of task_t.process for responder - */ -static status_t process_r(private_ike_config_t *this, message_t *message) +METHOD(task_t, process_r, status_t, + private_ike_config_t *this, message_t *message) { if (message->get_message_id(message) == 1) { /* in first IKE_AUTH only */ @@ -299,10 +300,8 @@ static status_t process_r(private_ike_config_t *this, message_t *message) return NEED_MORE; } -/** - * Implementation of task_t.build for responder - */ -static status_t build_r(private_ike_config_t *this, message_t *message) +METHOD(task_t, build_r, status_t, + private_ike_config_t *this, message_t *message) { if (this->ike_sa->get_state(this->ike_sa) == IKE_ESTABLISHED) { /* in last IKE_AUTH exchange */ @@ -366,10 +365,8 @@ static status_t build_r(private_ike_config_t *this, message_t *message) return NEED_MORE; } -/** - * Implementation of task_t.process for initiator - */ -static status_t process_i(private_ike_config_t *this, message_t *message) +METHOD(task_t, process_i, status_t, + private_ike_config_t *this, message_t *message) { if (this->ike_sa->get_state(this->ike_sa) == IKE_ESTABLISHED) { /* in last IKE_AUTH exchange */ @@ -385,18 +382,14 @@ static status_t process_i(private_ike_config_t *this, message_t *message) return NEED_MORE; } -/** - * Implementation of task_t.get_type - */ -static task_type_t get_type(private_ike_config_t *this) +METHOD(task_t, get_type, task_type_t, + private_ike_config_t *this) { return IKE_CONFIG; } -/** - * Implementation of task_t.migrate - */ -static void migrate(private_ike_config_t *this, ike_sa_t *ike_sa) +METHOD(task_t, migrate, void, + private_ike_config_t *this, ike_sa_t *ike_sa) { DESTROY_IF(this->virtual_ip); @@ -406,10 +399,8 @@ static void migrate(private_ike_config_t *this, ike_sa_t *ike_sa) this->requested = linked_list_create(); } -/** - * Implementation of task_t.destroy - */ -static void destroy(private_ike_config_t *this) +METHOD(task_t, destroy, void, + private_ike_config_t *this) { DESTROY_IF(this->virtual_ip); this->requested->destroy_function(this->requested, free); @@ -421,26 +412,30 @@ static void destroy(private_ike_config_t *this) */ ike_config_t *ike_config_create(ike_sa_t *ike_sa, bool initiator) { - private_ike_config_t *this = malloc_thing(private_ike_config_t); - - this->public.task.get_type = (task_type_t(*)(task_t*))get_type; - this->public.task.migrate = (void(*)(task_t*,ike_sa_t*))migrate; - this->public.task.destroy = (void(*)(task_t*))destroy; - - this->initiator = initiator; - this->ike_sa = ike_sa; - this->virtual_ip = NULL; - this->requested = linked_list_create(); + private_ike_config_t *this; + + INIT(this, + .public = { + .task = { + .get_type = _get_type, + .migrate = _migrate, + .destroy = _destroy, + }, + }, + .initiator = initiator, + .ike_sa = ike_sa, + .requested = linked_list_create(), + ); if (initiator) { - this->public.task.build = (status_t(*)(task_t*,message_t*))build_i; - this->public.task.process = (status_t(*)(task_t*,message_t*))process_i; + this->public.task.build = _build_i; + this->public.task.process = _process_i; } else { - this->public.task.build = (status_t(*)(task_t*,message_t*))build_r; - this->public.task.process = (status_t(*)(task_t*,message_t*))process_r; + this->public.task.build = _build_r; + this->public.task.process = _process_r; } return &this->public; diff --git a/src/libcharon/sa/tasks/ike_delete.c b/src/libcharon/sa/tasks/ike_delete.c index 130948836..d79674fe4 100644 --- a/src/libcharon/sa/tasks/ike_delete.c +++ b/src/libcharon/sa/tasks/ike_delete.c @@ -52,10 +52,8 @@ struct private_ike_delete_t { bool simultaneous; }; -/** - * Implementation of task_t.build for initiator - */ -static status_t build_i(private_ike_delete_t *this, message_t *message) +METHOD(task_t, build_i, status_t, + private_ike_delete_t *this, message_t *message) { delete_payload_t *delete_payload; @@ -83,10 +81,8 @@ static status_t build_i(private_ike_delete_t *this, message_t *message) return NEED_MORE; } -/** - * Implementation of task_t.process for initiator - */ -static status_t process_i(private_ike_delete_t *this, message_t *message) +METHOD(task_t, process_i, status_t, + private_ike_delete_t *this, message_t *message) { DBG0(DBG_IKE, "IKE_SA deleted"); if (!this->rekeyed) @@ -97,10 +93,8 @@ static status_t process_i(private_ike_delete_t *this, message_t *message) return DESTROY_ME; } -/** - * Implementation of task_t.process for responder - */ -static status_t process_r(private_ike_delete_t *this, message_t *message) +METHOD(task_t, process_r, status_t, + private_ike_delete_t *this, message_t *message) { /* we don't even scan the payloads, as the message wouldn't have * come so far without being correct */ @@ -134,16 +128,14 @@ static status_t process_r(private_ike_delete_t *this, message_t *message) return NEED_MORE; } -/** - * Implementation of task_t.build for responder - */ -static status_t build_r(private_ike_delete_t *this, message_t *message) +METHOD(task_t, build_r, status_t, + private_ike_delete_t *this, message_t *message) { DBG0(DBG_IKE, "IKE_SA deleted"); if (this->simultaneous) { - /* wait for peer's response for our delete request, but set a timeout */ + /* wait for peer's response for our delete request */ return SUCCESS; } if (!this->rekeyed) @@ -154,27 +146,21 @@ static status_t build_r(private_ike_delete_t *this, message_t *message) return DESTROY_ME; } -/** - * Implementation of task_t.get_type - */ -static task_type_t get_type(private_ike_delete_t *this) +METHOD(task_t, get_type, task_type_t, + private_ike_delete_t *this) { return IKE_DELETE; } -/** - * Implementation of task_t.migrate - */ -static void migrate(private_ike_delete_t *this, ike_sa_t *ike_sa) +METHOD(task_t, migrate, void, + private_ike_delete_t *this, ike_sa_t *ike_sa) { this->ike_sa = ike_sa; this->simultaneous = FALSE; } -/** - * Implementation of task_t.destroy - */ -static void destroy(private_ike_delete_t *this) +METHOD(task_t, destroy, void, + private_ike_delete_t *this) { free(this); } @@ -184,27 +170,30 @@ static void destroy(private_ike_delete_t *this) */ ike_delete_t *ike_delete_create(ike_sa_t *ike_sa, bool initiator) { - private_ike_delete_t *this = malloc_thing(private_ike_delete_t); - - this->public.task.get_type = (task_type_t(*)(task_t*))get_type; - this->public.task.migrate = (void(*)(task_t*,ike_sa_t*))migrate; - this->public.task.destroy = (void(*)(task_t*))destroy; + private_ike_delete_t *this; + + INIT(this, + .public = { + .task = { + .get_type = _get_type, + .migrate = _migrate, + .destroy = _destroy, + }, + }, + .ike_sa = ike_sa, + .initiator = initiator, + ); if (initiator) { - this->public.task.build = (status_t(*)(task_t*,message_t*))build_i; - this->public.task.process = (status_t(*)(task_t*,message_t*))process_i; + this->public.task.build = _build_i; + this->public.task.process = _process_i; } else { - this->public.task.build = (status_t(*)(task_t*,message_t*))build_r; - this->public.task.process = (status_t(*)(task_t*,message_t*))process_r; + this->public.task.build = _build_r; + this->public.task.process = _process_r; } - this->ike_sa = ike_sa; - this->initiator = initiator; - this->rekeyed = FALSE; - this->simultaneous = FALSE; - return &this->public; } diff --git a/src/libcharon/sa/tasks/ike_dpd.c b/src/libcharon/sa/tasks/ike_dpd.c index 4c6ba7662..106eff87c 100644 --- a/src/libcharon/sa/tasks/ike_dpd.c +++ b/src/libcharon/sa/tasks/ike_dpd.c @@ -31,44 +31,33 @@ struct private_ike_dpd_t { ike_dpd_t public; }; -/** - * Implementation of task_t.build for initiator - * Implementation of task_t.process for responder - */ -static status_t return_need_more(private_ike_dpd_t *this, message_t *message) +METHOD(task_t, return_need_more, status_t, + private_ike_dpd_t *this, message_t *message) { return NEED_MORE; } -/** - * Implementation of task_t.process for initiator - * Implementation of task_t.build for responder - */ -static status_t return_success(private_ike_dpd_t *this, message_t *message) +METHOD(task_t, return_success, status_t, + private_ike_dpd_t *this, message_t *message) { return SUCCESS; } -/** - * Implementation of task_t.get_type - */ -static task_type_t get_type(private_ike_dpd_t *this) +METHOD(task_t, get_type, task_type_t, + private_ike_dpd_t *this) { return IKE_DPD; } -/** - * Implementation of task_t.migrate - */ -static void migrate(private_ike_dpd_t *this, ike_sa_t *ike_sa) + +METHOD(task_t, migrate, void, + private_ike_dpd_t *this, ike_sa_t *ike_sa) { } -/** - * Implementation of task_t.destroy - */ -static void destroy(private_ike_dpd_t *this) +METHOD(task_t, destroy, void, + private_ike_dpd_t *this) { free(this); } @@ -78,21 +67,27 @@ static void destroy(private_ike_dpd_t *this) */ ike_dpd_t *ike_dpd_create(bool initiator) { - private_ike_dpd_t *this = malloc_thing(private_ike_dpd_t); - - this->public.task.get_type = (task_type_t(*)(task_t*))get_type; - this->public.task.migrate = (void(*)(task_t*,ike_sa_t*))migrate; - this->public.task.destroy = (void(*)(task_t*))destroy; + private_ike_dpd_t *this; + + INIT(this, + .public = { + .task = { + .get_type = _get_type, + .migrate = _migrate, + .destroy = _destroy, + }, + }, + ); if (initiator) { - this->public.task.build = (status_t(*)(task_t*,message_t*))return_need_more; - this->public.task.process = (status_t(*)(task_t*,message_t*))return_success; + this->public.task.build = _return_need_more; + this->public.task.process = _return_success; } else { - this->public.task.build = (status_t(*)(task_t*,message_t*))return_success; - this->public.task.process = (status_t(*)(task_t*,message_t*))return_need_more; + this->public.task.build = _return_success; + this->public.task.process = _return_need_more; } return &this->public; diff --git a/src/libcharon/sa/tasks/ike_dpd.h b/src/libcharon/sa/tasks/ike_dpd.h index 36388d15b..a9f68c31c 100644 --- a/src/libcharon/sa/tasks/ike_dpd.h +++ b/src/libcharon/sa/tasks/ike_dpd.h @@ -43,7 +43,7 @@ struct ike_dpd_t { /** * Create a new ike_dpd task. * - * @param initiator TRUE if thask is the original initator + * @param initiator TRUE if task is the original initiator * @return ike_dpd task to handle by the task_manager */ ike_dpd_t *ike_dpd_create(bool initiator); diff --git a/src/libcharon/sa/tasks/ike_init.c b/src/libcharon/sa/tasks/ike_init.c index dd4a5f5c0..dd8a4b086 100644 --- a/src/libcharon/sa/tasks/ike_init.c +++ b/src/libcharon/sa/tasks/ike_init.c @@ -112,7 +112,7 @@ static void build_payloads(private_ike_init_t *this, message_t *message) linked_list_t *proposal_list; ike_sa_id_t *id; proposal_t *proposal; - iterator_t *iterator; + enumerator_t *enumerator; id = this->ike_sa->get_id(this->ike_sa); @@ -124,12 +124,12 @@ static void build_payloads(private_ike_init_t *this, message_t *message) if (this->old_sa) { /* include SPI of new IKE_SA when we are rekeying */ - iterator = proposal_list->create_iterator(proposal_list, TRUE); - while (iterator->iterate(iterator, (void**)&proposal)) + enumerator = proposal_list->create_enumerator(proposal_list); + while (enumerator->enumerate(enumerator, (void**)&proposal)) { proposal->set_spi(proposal, id->get_initiator_spi(id)); } - iterator->destroy(iterator); + enumerator->destroy(enumerator); } sa_payload = sa_payload_create_from_proposal_list(proposal_list); @@ -221,10 +221,8 @@ static void process_payloads(private_ike_init_t *this, message_t *message) enumerator->destroy(enumerator); } -/** - * Implementation of task_t.process for initiator - */ -static status_t build_i(private_ike_init_t *this, message_t *message) +METHOD(task_t, build_i, status_t, + private_ike_init_t *this, message_t *message) { rng_t *rng; @@ -287,10 +285,8 @@ static status_t build_i(private_ike_init_t *this, message_t *message) return NEED_MORE; } -/** - * Implementation of task_t.process for responder - */ -static status_t process_r(private_ike_init_t *this, message_t *message) +METHOD(task_t, process_r, status_t, + private_ike_init_t *this, message_t *message) { rng_t *rng; @@ -361,10 +357,8 @@ static bool derive_keys(private_ike_init_t *this, return TRUE; } -/** - * Implementation of task_t.build for responder - */ -static status_t build_r(private_ike_init_t *this, message_t *message) +METHOD(task_t, build_r, status_t, + private_ike_init_t *this, message_t *message) { /* check if we have everything we need */ if (this->proposal == NULL || @@ -409,10 +403,8 @@ static status_t build_r(private_ike_init_t *this, message_t *message) return SUCCESS; } -/** - * Implementation of task_t.process for initiator - */ -static status_t process_i(private_ike_init_t *this, message_t *message) +METHOD(task_t, process_i, status_t, + private_ike_init_t *this, message_t *message) { enumerator_t *enumerator; payload_t *payload; @@ -510,34 +502,14 @@ static status_t process_i(private_ike_init_t *this, message_t *message) return SUCCESS; } -/** - * Implementation of task_t.get_type - */ -static task_type_t get_type(private_ike_init_t *this) +METHOD(task_t, get_type, task_type_t, + private_ike_init_t *this) { return IKE_INIT; } -/** - * Implementation of task_t.get_type - */ -static chunk_t get_lower_nonce(private_ike_init_t *this) -{ - if (memcmp(this->my_nonce.ptr, this->other_nonce.ptr, - min(this->my_nonce.len, this->other_nonce.len)) < 0) - { - return this->my_nonce; - } - else - { - return this->other_nonce; - } -} - -/** - * Implementation of task_t.migrate - */ -static void migrate(private_ike_init_t *this, ike_sa_t *ike_sa) +METHOD(task_t, migrate, void, + private_ike_init_t *this, ike_sa_t *ike_sa) { DESTROY_IF(this->proposal); chunk_free(&this->other_nonce); @@ -545,14 +517,15 @@ static void migrate(private_ike_init_t *this, ike_sa_t *ike_sa) this->ike_sa = ike_sa; this->keymat = ike_sa->get_keymat(ike_sa); this->proposal = NULL; - DESTROY_IF(this->dh); - this->dh = this->keymat->create_dh(this->keymat, this->dh_group); + if (this->dh && this->dh->get_dh_group(this->dh) != this->dh_group) + { /* reset DH value only if group changed (INVALID_KE_PAYLOAD) */ + this->dh->destroy(this->dh); + this->dh = this->keymat->create_dh(this->keymat, this->dh_group); + } } -/** - * Implementation of task_t.destroy - */ -static void destroy(private_ike_init_t *this) +METHOD(task_t, destroy, void, + private_ike_init_t *this) { DESTROY_IF(this->dh); DESTROY_IF(this->proposal); @@ -562,40 +535,53 @@ static void destroy(private_ike_init_t *this) free(this); } +METHOD(ike_init_t, get_lower_nonce, chunk_t, + private_ike_init_t *this) +{ + if (memcmp(this->my_nonce.ptr, this->other_nonce.ptr, + min(this->my_nonce.len, this->other_nonce.len)) < 0) + { + return this->my_nonce; + } + else + { + return this->other_nonce; + } +} + /* * Described in header. */ ike_init_t *ike_init_create(ike_sa_t *ike_sa, bool initiator, ike_sa_t *old_sa) { - private_ike_init_t *this = malloc_thing(private_ike_init_t); + private_ike_init_t *this; + + INIT(this, + .public = { + .task = { + .get_type = _get_type, + .migrate = _migrate, + .destroy = _destroy, + }, + .get_lower_nonce = _get_lower_nonce, + }, + .ike_sa = ike_sa, + .initiator = initiator, + .dh_group = MODP_NONE, + .keymat = ike_sa->get_keymat(ike_sa), + .old_sa = old_sa, + ); - this->public.get_lower_nonce = (chunk_t(*)(ike_init_t*))get_lower_nonce; - this->public.task.get_type = (task_type_t(*)(task_t*))get_type; - this->public.task.migrate = (void(*)(task_t*,ike_sa_t*))migrate; - this->public.task.destroy = (void(*)(task_t*))destroy; if (initiator) { - this->public.task.build = (status_t(*)(task_t*,message_t*))build_i; - this->public.task.process = (status_t(*)(task_t*,message_t*))process_i; + this->public.task.build = _build_i; + this->public.task.process = _process_i; } else { - this->public.task.build = (status_t(*)(task_t*,message_t*))build_r; - this->public.task.process = (status_t(*)(task_t*,message_t*))process_r; + this->public.task.build = _build_r; + this->public.task.process = _process_r; } - this->ike_sa = ike_sa; - this->initiator = initiator; - this->dh_group = MODP_NONE; - this->dh = NULL; - this->keymat = ike_sa->get_keymat(ike_sa); - this->my_nonce = chunk_empty; - this->other_nonce = chunk_empty; - this->cookie = chunk_empty; - this->proposal = NULL; - this->config = NULL; - this->old_sa = old_sa; - this->retry = 0; - return &this->public; } diff --git a/src/libcharon/sa/tasks/ike_init.h b/src/libcharon/sa/tasks/ike_init.h index 7bd784cff..4b7f60416 100644 --- a/src/libcharon/sa/tasks/ike_init.h +++ b/src/libcharon/sa/tasks/ike_init.h @@ -51,7 +51,7 @@ struct ike_init_t { * Create a new IKE_INIT task. * * @param ike_sa IKE_SA this task works for (new one when rekeying) - * @param initiator TRUE if thask is the original initator + * @param initiator TRUE if task is the original initiator * @param old_sa old IKE_SA when we are rekeying * @return ike_init task to handle by the task_manager */ diff --git a/src/libcharon/sa/tasks/ike_me.c b/src/libcharon/sa/tasks/ike_me.c index 1de6ae8fc..8f90efcc3 100644 --- a/src/libcharon/sa/tasks/ike_me.c +++ b/src/libcharon/sa/tasks/ike_me.c @@ -111,15 +111,15 @@ struct private_ike_me_t { */ static void add_endpoints_to_message(message_t *message, linked_list_t *endpoints) { - iterator_t *iterator; + enumerator_t *enumerator; endpoint_notify_t *endpoint; - iterator = endpoints->create_iterator(endpoints, TRUE); - while (iterator->iterate(iterator, (void**)&endpoint)) + enumerator = endpoints->create_enumerator(endpoints); + while (enumerator->enumerate(enumerator, (void**)&endpoint)) { message->add_payload(message, (payload_t*)endpoint->build_notify(endpoint)); } - iterator->destroy(iterator); + enumerator->destroy(enumerator); } /** @@ -242,10 +242,8 @@ static void process_payloads(private_ike_me_t *this, message_t *message) enumerator->destroy(enumerator); } -/** - * Implementation of task_t.build for initiator - */ -static status_t build_i(private_ike_me_t *this, message_t *message) +METHOD(task_t, build_i, status_t, + private_ike_me_t *this, message_t *message) { switch(message->get_exchange_type(message)) { @@ -321,10 +319,8 @@ static status_t build_i(private_ike_me_t *this, message_t *message) return NEED_MORE; } -/** - * Implementation of task_t.process for responder - */ -static status_t process_r(private_ike_me_t *this, message_t *message) +METHOD(task_t, process_r, status_t, + private_ike_me_t *this, message_t *message) { switch(message->get_exchange_type(message)) { @@ -381,10 +377,8 @@ static status_t process_r(private_ike_me_t *this, message_t *message) return NEED_MORE; } -/** - * Implementation of task_t.build for responder - */ -static status_t build_r(private_ike_me_t *this, message_t *message) +METHOD(task_t, build_r, status_t, + private_ike_me_t *this, message_t *message) { switch(message->get_exchange_type(message)) { @@ -440,10 +434,8 @@ static status_t build_r(private_ike_me_t *this, message_t *message) return SUCCESS; } -/** - * Implementation of task_t.process for initiator - */ -static status_t process_i(private_ike_me_t *this, message_t *message) +METHOD(task_t, process_i, status_t, + private_ike_me_t *this, message_t *message) { switch(message->get_exchange_type(message)) { @@ -520,9 +512,10 @@ static status_t process_i(private_ike_me_t *this, message_t *message) } /** - * Implementation of task_t.build for initiator (mediation server) + * For mediation server */ -static status_t build_i_ms(private_ike_me_t *this, message_t *message) +METHOD(task_t, build_i_ms, status_t, + private_ike_me_t *this, message_t *message) { switch(message->get_exchange_type(message)) { @@ -559,9 +552,10 @@ static status_t build_i_ms(private_ike_me_t *this, message_t *message) } /** - * Implementation of task_t.process for responder (mediation server) + * For mediation server */ -static status_t process_r_ms(private_ike_me_t *this, message_t *message) +METHOD(task_t, process_r_ms, status_t, + private_ike_me_t *this, message_t *message) { switch(message->get_exchange_type(message)) { @@ -632,9 +626,10 @@ static status_t process_r_ms(private_ike_me_t *this, message_t *message) } /** - * Implementation of task_t.build for responder (mediation server) + * For mediation server */ -static status_t build_r_ms(private_ike_me_t *this, message_t *message) +METHOD(task_t, build_r_ms, status_t, + private_ike_me_t *this, message_t *message) { switch(message->get_exchange_type(message)) { @@ -703,9 +698,10 @@ static status_t build_r_ms(private_ike_me_t *this, message_t *message) } /** - * Implementation of task_t.process for initiator (mediation server) + * For mediation server */ -static status_t process_i_ms(private_ike_me_t *this, message_t *message) +METHOD(task_t, process_i_ms, status_t, + private_ike_me_t *this, message_t *message) { /* FIXME: theoretically we should be prepared to receive a ME_CONNECT_FAILED * here if the responding peer is not able to proceed. in this case we shall @@ -714,40 +710,30 @@ static status_t process_i_ms(private_ike_me_t *this, message_t *message) return SUCCESS; } -/** - * Implementation of ike_me.connect - */ -static void me_connect(private_ike_me_t *this, identification_t *peer_id) +METHOD(ike_me_t, me_connect, void, + private_ike_me_t *this, identification_t *peer_id) { this->peer_id = peer_id->clone(peer_id); } -/** - * Implementation of ike_me.respond - */ -static void me_respond(private_ike_me_t *this, identification_t *peer_id, - chunk_t connect_id) +METHOD(ike_me_t, me_respond, void, + private_ike_me_t *this, identification_t *peer_id, chunk_t connect_id) { this->peer_id = peer_id->clone(peer_id); this->connect_id = chunk_clone(connect_id); this->response = TRUE; } -/** - * Implementation of ike_me.callback - */ -static void me_callback(private_ike_me_t *this, identification_t *peer_id) +METHOD(ike_me_t, me_callback, void, + private_ike_me_t *this, identification_t *peer_id) { this->peer_id = peer_id->clone(peer_id); this->callback = TRUE; } -/** - * Implementation of ike_me.relay - */ -static void relay(private_ike_me_t *this, identification_t *requester, - chunk_t connect_id, chunk_t connect_key, - linked_list_t *endpoints, bool response) +METHOD(ike_me_t, relay, void, + private_ike_me_t *this, identification_t *requester, chunk_t connect_id, + chunk_t connect_key, linked_list_t *endpoints, bool response) { this->peer_id = requester->clone(requester); this->connect_id = chunk_clone(connect_id); @@ -761,26 +747,20 @@ static void relay(private_ike_me_t *this, identification_t *requester, this->response = response; } -/** - * Implementation of task_t.get_type - */ -static task_type_t get_type(private_ike_me_t *this) +METHOD(task_t, get_type, task_type_t, + private_ike_me_t *this) { return IKE_ME; } -/** - * Implementation of task_t.migrate - */ -static void migrate(private_ike_me_t *this, ike_sa_t *ike_sa) +METHOD(task_t, migrate, void, + private_ike_me_t *this, ike_sa_t *ike_sa) { this->ike_sa = ike_sa; } -/** - * Implementation of task_t.destroy - */ -static void destroy(private_ike_me_t *this) +METHOD(task_t, destroy, void, + private_ike_me_t *this) { DESTROY_IF(this->peer_id); @@ -801,23 +781,37 @@ static void destroy(private_ike_me_t *this) */ ike_me_t *ike_me_create(ike_sa_t *ike_sa, bool initiator) { - private_ike_me_t *this = malloc_thing(private_ike_me_t); - - this->public.task.get_type = (task_type_t(*)(task_t*))get_type; - this->public.task.migrate = (void(*)(task_t*,ike_sa_t*))migrate; - this->public.task.destroy = (void(*)(task_t*))destroy; + private_ike_me_t *this; + + INIT(this, + .public = { + .task = { + .get_type = _get_type, + .migrate = _migrate, + .destroy = _destroy, + }, + .connect = _me_connect, + .respond = _me_respond, + .callback = _me_callback, + .relay = _relay, + }, + .ike_sa = ike_sa, + .initiator = initiator, + .local_endpoints = linked_list_create(), + .remote_endpoints = linked_list_create(), + ); if (ike_sa->has_condition(ike_sa, COND_ORIGINAL_INITIATOR)) { if (initiator) { - this->public.task.build = (status_t(*)(task_t*,message_t*))build_i; - this->public.task.process = (status_t(*)(task_t*,message_t*))process_i; + this->public.task.build = _build_i; + this->public.task.process = _process_i; } else { - this->public.task.build = (status_t(*)(task_t*,message_t*))build_r; - this->public.task.process = (status_t(*)(task_t*,message_t*))process_r; + this->public.task.build = _build_r; + this->public.task.process = _process_r; } } else @@ -825,36 +819,15 @@ ike_me_t *ike_me_create(ike_sa_t *ike_sa, bool initiator) /* mediation server */ if (initiator) { - this->public.task.build = (status_t(*)(task_t*,message_t*))build_i_ms; - this->public.task.process = (status_t(*)(task_t*,message_t*))process_i_ms; + this->public.task.build = _build_i_ms; + this->public.task.process = _process_i_ms; } else { - this->public.task.build = (status_t(*)(task_t*,message_t*))build_r_ms; - this->public.task.process = (status_t(*)(task_t*,message_t*))process_r_ms; + this->public.task.build = _build_r_ms; + this->public.task.process = _process_r_ms; } } - this->public.connect = (void(*)(ike_me_t*,identification_t*))me_connect; - this->public.respond = (void(*)(ike_me_t*,identification_t*,chunk_t))me_respond; - this->public.callback = (void(*)(ike_me_t*,identification_t*))me_callback; - this->public.relay = (void(*)(ike_me_t*,identification_t*,chunk_t,chunk_t,linked_list_t*,bool))relay; - - this->ike_sa = ike_sa; - this->initiator = initiator; - - this->peer_id = NULL; - this->connect_id = chunk_empty; - this->connect_key = chunk_empty; - this->local_endpoints = linked_list_create(); - this->remote_endpoints = linked_list_create(); - this->mediation = FALSE; - this->response = FALSE; - this->callback = FALSE; - this->failed = FALSE; - this->invalid_syntax = FALSE; - - this->mediated_cfg = NULL; - return &this->public; } diff --git a/src/libcharon/sa/tasks/ike_mobike.c b/src/libcharon/sa/tasks/ike_mobike.c index 5b12eaaac..fb1100028 100644 --- a/src/libcharon/sa/tasks/ike_mobike.c +++ b/src/libcharon/sa/tasks/ike_mobike.c @@ -1,4 +1,5 @@ /* + * Copyright (C) 2010-2012 Tobias Brunner * Copyright (C) 2007 Martin Willi * Hochschule fuer Technik Rapperswil * @@ -79,24 +80,6 @@ struct private_ike_mobike_t { }; /** - * flush the IKE_SAs list of additional addresses - */ -static void flush_additional_addresses(private_ike_mobike_t *this) -{ - iterator_t *iterator; - host_t *host; - - iterator = this->ike_sa->create_additional_address_iterator(this->ike_sa); - while (iterator->iterate(iterator, (void**)&host)) - { - iterator->remove(iterator); - host->destroy(host); - } - iterator->destroy(iterator); -} - - -/** * read notifys from message and evaluate them */ static void process_payloads(private_ike_mobike_t *this, message_t *message) @@ -152,13 +135,17 @@ static void process_payloads(private_ike_mobike_t *this, message_t *message) { if (first) { /* an ADDITIONAL_*_ADDRESS means replace, so flush once */ - flush_additional_addresses(this); + this->ike_sa->clear_peer_addresses(this->ike_sa); first = FALSE; + /* add the peer's current address to the list */ + host = message->get_source(message); + this->ike_sa->add_peer_address(this->ike_sa, + host->clone(host)); } data = notify->get_notification_data(notify); host = host_create_from_chunk(family, data, 0); DBG2(DBG_IKE, "got additional MOBIKE peer address: %H", host); - this->ike_sa->add_additional_address(this->ike_sa, host); + this->ike_sa->add_peer_address(this->ike_sa, host); this->addresses_updated = TRUE; break; } @@ -169,7 +156,10 @@ static void process_payloads(private_ike_mobike_t *this, message_t *message) } case NO_ADDITIONAL_ADDRESSES: { - flush_additional_addresses(this); + this->ike_sa->clear_peer_addresses(this->ike_sa); + /* add the peer's current address to the list */ + host = message->get_source(message); + this->ike_sa->add_peer_address(this->ike_sa, host->clone(host)); this->addresses_updated = TRUE; break; } @@ -256,11 +246,11 @@ static void build_cookie(private_ike_mobike_t *this, message_t *message) */ static void update_children(private_ike_mobike_t *this) { - iterator_t *iterator; + enumerator_t *enumerator; child_sa_t *child_sa; - iterator = this->ike_sa->create_child_sa_iterator(this->ike_sa); - while (iterator->iterate(iterator, (void**)&child_sa)) + enumerator = this->ike_sa->create_child_sa_enumerator(this->ike_sa); + while (enumerator->enumerate(enumerator, (void**)&child_sa)) { if (child_sa->update(child_sa, this->ike_sa->get_my_host(this->ike_sa), @@ -273,7 +263,7 @@ static void update_children(private_ike_mobike_t *this) child_sa->get_spi(child_sa, TRUE)); } } - iterator->destroy(iterator); + enumerator->destroy(enumerator); } /** @@ -296,7 +286,7 @@ METHOD(ike_mobike_t, transmit, void, private_ike_mobike_t *this, packet_t *packet) { host_t *me, *other, *me_old, *other_old; - iterator_t *iterator; + enumerator_t *enumerator; ike_cfg_t *ike_cfg; packet_t *copy; @@ -309,19 +299,8 @@ METHOD(ike_mobike_t, transmit, void, other_old = this->ike_sa->get_other_host(this->ike_sa); ike_cfg = this->ike_sa->get_ike_cfg(this->ike_sa); - me = hydra->kernel_interface->get_source_addr( - hydra->kernel_interface, other_old, NULL); - if (me) - { - apply_port(me, me_old, ike_cfg->get_my_port(ike_cfg)); - DBG1(DBG_IKE, "checking original path %#H - %#H", me, other_old); - copy = packet->clone(packet); - copy->set_source(copy, me); - charon->sender->send(charon->sender, copy); - } - - iterator = this->ike_sa->create_additional_address_iterator(this->ike_sa); - while (iterator->iterate(iterator, (void**)&other)) + enumerator = this->ike_sa->create_peer_address_enumerator(this->ike_sa); + while (enumerator->enumerate(enumerator, (void**)&other)) { me = hydra->kernel_interface->get_source_addr( hydra->kernel_interface, other, NULL); @@ -343,7 +322,7 @@ METHOD(ike_mobike_t, transmit, void, charon->sender->send(charon->sender, copy); } } - iterator->destroy(iterator); + enumerator->destroy(enumerator); } METHOD(task_t, build_i, status_t, diff --git a/src/libcharon/sa/tasks/ike_natd.c b/src/libcharon/sa/tasks/ike_natd.c index 7839b52eb..f06a518fa 100644 --- a/src/libcharon/sa/tasks/ike_natd.c +++ b/src/libcharon/sa/tasks/ike_natd.c @@ -256,10 +256,8 @@ static void process_payloads(private_ike_natd_t *this, message_t *message) } } -/** - * Implementation of task_t.process for initiator - */ -static status_t process_i(private_ike_natd_t *this, message_t *message) +METHOD(task_t, process_i, status_t, + private_ike_natd_t *this, message_t *message) { process_payloads(this, message); @@ -281,10 +279,8 @@ static status_t process_i(private_ike_natd_t *this, message_t *message) return SUCCESS; } -/** - * Implementation of task_t.process for initiator - */ -static status_t build_i(private_ike_natd_t *this, message_t *message) +METHOD(task_t, build_i, status_t, + private_ike_natd_t *this, message_t *message) { notify_payload_t *notify; enumerator_t *enumerator; @@ -345,15 +341,13 @@ static status_t build_i(private_ike_natd_t *this, message_t *message) return NEED_MORE; } -/** - * Implementation of task_t.build for responder - */ -static status_t build_r(private_ike_natd_t *this, message_t *message) +METHOD(task_t, build_r, status_t, + private_ike_natd_t *this, message_t *message) { notify_payload_t *notify; host_t *me, *other; - /* only add notifies on successfull responses. */ + /* only add notifies on successful responses. */ if (message->get_exchange_type(message) == IKE_SA_INIT && message->get_payload(message, SECURITY_ASSOCIATION) == NULL) { @@ -380,28 +374,22 @@ static status_t build_r(private_ike_natd_t *this, message_t *message) return SUCCESS; } -/** - * Implementation of task_t.process for responder - */ -static status_t process_r(private_ike_natd_t *this, message_t *message) +METHOD(task_t, process_r, status_t, + private_ike_natd_t *this, message_t *message) { process_payloads(this, message); return NEED_MORE; } -/** - * Implementation of task_t.get_type - */ -static task_type_t get_type(private_ike_natd_t *this) +METHOD(task_t, get_type, task_type_t, + private_ike_natd_t *this) { return IKE_NATD; } -/** - * Implementation of task_t.migrate - */ -static void migrate(private_ike_natd_t *this, ike_sa_t *ike_sa) +METHOD(task_t, migrate, void, + private_ike_natd_t *this, ike_sa_t *ike_sa) { this->ike_sa = ike_sa; this->src_seen = FALSE; @@ -411,21 +399,17 @@ static void migrate(private_ike_natd_t *this, ike_sa_t *ike_sa) this->mapping_changed = FALSE; } -/** - * Implementation of ike_natd_t.has_mapping_changed - */ -static bool has_mapping_changed(private_ike_natd_t *this) +METHOD(task_t, destroy, void, + private_ike_natd_t *this) { - return this->mapping_changed; + DESTROY_IF(this->hasher); + free(this); } -/** - * Implementation of task_t.destroy - */ -static void destroy(private_ike_natd_t *this) +METHOD(ike_natd_t, has_mapping_changed, bool, + private_ike_natd_t *this) { - DESTROY_IF(this->hasher); - free(this); + return this->mapping_changed; } /* @@ -433,33 +417,32 @@ static void destroy(private_ike_natd_t *this) */ ike_natd_t *ike_natd_create(ike_sa_t *ike_sa, bool initiator) { - private_ike_natd_t *this = malloc_thing(private_ike_natd_t); - - this->public.task.get_type = (task_type_t(*)(task_t*))get_type; - this->public.task.migrate = (void(*)(task_t*,ike_sa_t*))migrate; - this->public.task.destroy = (void(*)(task_t*))destroy; + private_ike_natd_t *this; + + INIT(this, + .public = { + .task = { + .get_type = _get_type, + .migrate = _migrate, + .destroy = _destroy, + }, + .has_mapping_changed = _has_mapping_changed, + }, + .ike_sa = ike_sa, + .initiator = initiator, + .hasher = lib->crypto->create_hasher(lib->crypto, HASH_SHA1), + ); if (initiator) { - this->public.task.build = (status_t(*)(task_t*,message_t*))build_i; - this->public.task.process = (status_t(*)(task_t*,message_t*))process_i; + this->public.task.build = _build_i; + this->public.task.process = _process_i; } else { - this->public.task.build = (status_t(*)(task_t*,message_t*))build_r; - this->public.task.process = (status_t(*)(task_t*,message_t*))process_r; + this->public.task.build = _build_r; + this->public.task.process = _process_r; } - this->public.has_mapping_changed = (bool(*)(ike_natd_t*))has_mapping_changed; - - this->ike_sa = ike_sa; - this->initiator = initiator; - this->hasher = lib->crypto->create_hasher(lib->crypto, HASH_SHA1); - this->src_seen = FALSE; - this->dst_seen = FALSE; - this->src_matched = FALSE; - this->dst_matched = FALSE; - this->mapping_changed = FALSE; - return &this->public; } diff --git a/src/libcharon/sa/tasks/ike_natd.h b/src/libcharon/sa/tasks/ike_natd.h index 97b652ead..68114af42 100644 --- a/src/libcharon/sa/tasks/ike_natd.h +++ b/src/libcharon/sa/tasks/ike_natd.h @@ -51,7 +51,7 @@ struct ike_natd_t { * Create a new ike_natd task. * * @param ike_sa IKE_SA this task works for - * @param initiator TRUE if thask is the original initator + * @param initiator TRUE if task is the original initiator * @return ike_natd task to handle by the task_manager */ ike_natd_t *ike_natd_create(ike_sa_t *ike_sa, bool initiator); diff --git a/src/libcharon/sa/tasks/ike_reauth.c b/src/libcharon/sa/tasks/ike_reauth.c index ac89c358b..48002d81c 100644 --- a/src/libcharon/sa/tasks/ike_reauth.c +++ b/src/libcharon/sa/tasks/ike_reauth.c @@ -42,134 +42,44 @@ struct private_ike_reauth_t { ike_delete_t *ike_delete; }; -/** - * Implementation of task_t.build for initiator - */ -static status_t build_i(private_ike_reauth_t *this, message_t *message) +METHOD(task_t, build_i, status_t, + private_ike_reauth_t *this, message_t *message) { return this->ike_delete->task.build(&this->ike_delete->task, message); } -/** - * Implementation of task_t.process for initiator - */ -static status_t process_i(private_ike_reauth_t *this, message_t *message) +METHOD(task_t, process_i, status_t, + private_ike_reauth_t *this, message_t *message) { - ike_sa_t *new; - host_t *host; - iterator_t *iterator; - child_sa_t *child_sa; - peer_cfg_t *peer_cfg; - /* process delete response first */ this->ike_delete->task.process(&this->ike_delete->task, message); - peer_cfg = this->ike_sa->get_peer_cfg(this->ike_sa); - - /* reauthenticate only if we have children */ - iterator = this->ike_sa->create_child_sa_iterator(this->ike_sa); - if (iterator->get_count(iterator) == 0 -#ifdef ME - /* we allow peers to reauth mediation connections (without children) */ - && !peer_cfg->is_mediation(peer_cfg) -#endif /* ME */ - ) + /* reestablish the IKE_SA with all children */ + if (this->ike_sa->reestablish(this->ike_sa) != SUCCESS) { - DBG1(DBG_IKE, "unable to reauthenticate IKE_SA, no CHILD_SA to recreate"); - iterator->destroy(iterator); + DBG1(DBG_IKE, "reauthenticating IKE_SA failed"); return FAILED; } - new = charon->ike_sa_manager->checkout_new(charon->ike_sa_manager, TRUE); - - new->set_peer_cfg(new, peer_cfg); - host = this->ike_sa->get_other_host(this->ike_sa); - new->set_other_host(new, host->clone(host)); - host = this->ike_sa->get_my_host(this->ike_sa); - new->set_my_host(new, host->clone(host)); - /* if we already have a virtual IP, we reuse it */ - host = this->ike_sa->get_virtual_ip(this->ike_sa, TRUE); - if (host) - { - new->set_virtual_ip(new, TRUE, host); - } - -#ifdef ME - /* we initiate the new IKE_SA of the mediation connection without CHILD_SA */ - if (peer_cfg->is_mediation(peer_cfg)) - { - if (new->initiate(new, NULL, 0, NULL, NULL) == DESTROY_ME) - { - charon->ike_sa_manager->checkin_and_destroy( - charon->ike_sa_manager, new); - /* set threads active IKE_SA after checkin */ - charon->bus->set_sa(charon->bus, this->ike_sa); - DBG1(DBG_IKE, "reauthenticating IKE_SA failed"); - return FAILED; - } - } -#endif /* ME */ - - while (iterator->iterate(iterator, (void**)&child_sa)) - { - switch (child_sa->get_state(child_sa)) - { - case CHILD_ROUTED: - { - /* move routed child directly */ - iterator->remove(iterator); - new->add_child_sa(new, child_sa); - break; - } - default: - { - /* initiate/queue all child SAs */ - child_cfg_t *child_cfg = child_sa->get_config(child_sa); - child_cfg->get_ref(child_cfg); - if (new->initiate(new, child_cfg, 0, NULL, NULL) == DESTROY_ME) - { - iterator->destroy(iterator); - charon->ike_sa_manager->checkin_and_destroy( - charon->ike_sa_manager, new); - /* set threads active IKE_SA after checkin */ - charon->bus->set_sa(charon->bus, this->ike_sa); - DBG1(DBG_IKE, "reauthenticating IKE_SA failed"); - return FAILED; - } - break; - } - } - } - iterator->destroy(iterator); - charon->ike_sa_manager->checkin(charon->ike_sa_manager, new); - /* set threads active IKE_SA after checkin */ - charon->bus->set_sa(charon->bus, this->ike_sa); - - /* we always return failed to delete the obsolete IKE_SA */ - return FAILED; + /* we always destroy the obsolete IKE_SA */ + return DESTROY_ME; } -/** - * Implementation of task_t.get_type - */ -static task_type_t get_type(private_ike_reauth_t *this) +METHOD(task_t, get_type, task_type_t, + private_ike_reauth_t *this) { return IKE_REAUTH; } -/** - * Implementation of task_t.migrate - */ -static void migrate(private_ike_reauth_t *this, ike_sa_t *ike_sa) +METHOD(task_t, migrate, void, + private_ike_reauth_t *this, ike_sa_t *ike_sa) { this->ike_delete->task.migrate(&this->ike_delete->task, ike_sa); this->ike_sa = ike_sa; } -/** - * Implementation of task_t.destroy - */ -static void destroy(private_ike_reauth_t *this) +METHOD(task_t, destroy, void, + private_ike_reauth_t *this) { this->ike_delete->task.destroy(&this->ike_delete->task); free(this); @@ -180,16 +90,21 @@ static void destroy(private_ike_reauth_t *this) */ ike_reauth_t *ike_reauth_create(ike_sa_t *ike_sa) { - private_ike_reauth_t *this = malloc_thing(private_ike_reauth_t); - - this->public.task.get_type = (task_type_t(*)(task_t*))get_type; - this->public.task.migrate = (void(*)(task_t*,ike_sa_t*))migrate; - this->public.task.destroy = (void(*)(task_t*))destroy; - this->public.task.build = (status_t(*)(task_t*,message_t*))build_i; - this->public.task.process = (status_t(*)(task_t*,message_t*))process_i; - - this->ike_sa = ike_sa; - this->ike_delete = ike_delete_create(ike_sa, TRUE); + private_ike_reauth_t *this; + + INIT(this, + .public = { + .task = { + .get_type = _get_type, + .migrate = _migrate, + .build = _build_i, + .process = _process_i, + .destroy = _destroy, + }, + }, + .ike_sa = ike_sa, + .ike_delete = ike_delete_create(ike_sa, TRUE), + ); return &this->public; } diff --git a/src/libcharon/sa/tasks/ike_rekey.c b/src/libcharon/sa/tasks/ike_rekey.c index c055dabc1..826d6e192 100644 --- a/src/libcharon/sa/tasks/ike_rekey.c +++ b/src/libcharon/sa/tasks/ike_rekey.c @@ -147,8 +147,8 @@ METHOD(task_t, build_i, status_t, METHOD(task_t, process_r, status_t, private_ike_rekey_t *this, message_t *message) { + enumerator_t *enumerator; peer_cfg_t *peer_cfg; - iterator_t *iterator; child_sa_t *child_sa; if (this->ike_sa->get_state(this->ike_sa) == IKE_DELETING) @@ -157,8 +157,8 @@ METHOD(task_t, process_r, status_t, return NEED_MORE; } - iterator = this->ike_sa->create_child_sa_iterator(this->ike_sa); - while (iterator->iterate(iterator, (void**)&child_sa)) + enumerator = this->ike_sa->create_child_sa_enumerator(this->ike_sa); + while (enumerator->enumerate(enumerator, (void**)&child_sa)) { switch (child_sa->get_state(child_sa)) { @@ -167,13 +167,13 @@ METHOD(task_t, process_r, status_t, case CHILD_DELETING: /* we do not allow rekeying while we have children in-progress */ DBG1(DBG_IKE, "peer initiated rekeying, but a child is half-open"); - iterator->destroy(iterator); + enumerator->destroy(enumerator); return NEED_MORE; default: break; } } - iterator->destroy(iterator); + enumerator->destroy(enumerator); this->new_sa = charon->ike_sa_manager->checkout_new(charon->ike_sa_manager, FALSE); diff --git a/src/libcharon/sa/tasks/ike_vendor.h b/src/libcharon/sa/tasks/ike_vendor.h index dcdd37424..6c353c447 100644 --- a/src/libcharon/sa/tasks/ike_vendor.h +++ b/src/libcharon/sa/tasks/ike_vendor.h @@ -42,7 +42,7 @@ struct ike_vendor_t { * Create a ike_vendor instance. * * @param ike_sa IKE_SA this task works for - * @param initiator TRUE if thask is the original initator + * @param initiator TRUE if task is the original initiator */ ike_vendor_t *ike_vendor_create(ike_sa_t *ike_sa, bool initiator); diff --git a/src/libcharon/sa/tasks/task.h b/src/libcharon/sa/tasks/task.h index 4468f2ebe..d57085954 100644 --- a/src/libcharon/sa/tasks/task.h +++ b/src/libcharon/sa/tasks/task.h @@ -89,7 +89,7 @@ extern enum_name_t *task_type_names; * A responder does the opposite; it calls process() first to handle an incoming * request and secondly calls build() to build an appropriate response. * Both methods return either SUCCESS, NEED_MORE or FAILED. A SUCCESS indicates - * that the task completed, even when the task completed unsuccesfully. The + * that the task completed, even when the task completed unsuccessfully. The * manager then removes the task from the list. A NEED_MORE is returned when * the task needs further build()/process() calls to complete, the manager * leaves the taks in the queue. A returned FAILED indicates a critical failure. @@ -102,7 +102,7 @@ struct task_t { * * @param message message to add payloads to * @return - * - FAILED if a critical error occured + * - FAILED if a critical error occurred * - DESTROY_ME if IKE_SA has been properly deleted * - NEED_MORE if another call to build/process needed * - SUCCESS if task completed @@ -114,7 +114,7 @@ struct task_t { * * @param message message to read payloads from * @return - * - FAILED if a critical error occured + * - FAILED if a critical error occurred * - DESTROY_ME if IKE_SA has been properly deleted * - NEED_MORE if another call to build/process needed * - SUCCESS if task completed diff --git a/src/libcharon/sa/trap_manager.c b/src/libcharon/sa/trap_manager.c index f91eff077..86d9f4c22 100644 --- a/src/libcharon/sa/trap_manager.c +++ b/src/libcharon/sa/trap_manager.c @@ -1,4 +1,5 @@ /* + * Copyright (C) 2011 Tobias Brunner * Copyright (C) 2009 Martin Willi * Hochschule fuer Technik Rapperswil * @@ -74,8 +75,10 @@ typedef struct { peer_cfg_t *peer_cfg; /** ref to instanciated CHILD_SA */ child_sa_t *child_sa; + /** TRUE if an acquire is pending */ + bool pending; /** pending IKE_SA connecting upon acquire */ - ike_sa_t *pending; + ike_sa_t *ike_sa; } entry_t; /** @@ -88,11 +91,8 @@ static void destroy_entry(entry_t *entry) free(entry); } -/** - * Implementation of trap_manager_t.install - */ -static u_int32_t install(private_trap_manager_t *this, peer_cfg_t *peer, - child_cfg_t *child) +METHOD(trap_manager_t, install, u_int32_t, + private_trap_manager_t *this, peer_cfg_t *peer, child_cfg_t *child) { entry_t *entry; ike_cfg_t *ike_cfg; @@ -158,8 +158,8 @@ static u_int32_t install(private_trap_manager_t *this, peer_cfg_t *peer, other->destroy(other); /* while we don't know the finally negotiated protocol (ESP|AH), we - * could iterate all proposals for a best guest (TODO). But as we - * support ESP only for now, we set here. */ + * could iterate all proposals for a best guess (TODO). But as we + * support ESP only for now, we set it here. */ child_sa->set_protocol(child_sa, PROTO_ESP); child_sa->set_mode(child_sa, child->get_mode(child)); status = child_sa->add_policies(child_sa, my_ts, other_ts); @@ -173,10 +173,10 @@ static u_int32_t install(private_trap_manager_t *this, peer_cfg_t *peer, } reqid = child_sa->get_reqid(child_sa); - entry = malloc_thing(entry_t); - entry->child_sa = child_sa; - entry->peer_cfg = peer->get_ref(peer); - entry->pending = NULL; + 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); @@ -185,10 +185,8 @@ static u_int32_t install(private_trap_manager_t *this, peer_cfg_t *peer, return reqid; } -/** - * Implementation of trap_manager_t.uninstall - */ -static bool uninstall(private_trap_manager_t *this, u_int32_t reqid) +METHOD(trap_manager_t, uninstall, bool, + private_trap_manager_t *this, u_int32_t reqid) { enumerator_t *enumerator; entry_t *entry, *found = NULL; @@ -234,10 +232,8 @@ static bool trap_filter(rwlock_t *lock, entry_t **entry, peer_cfg_t **peer_cfg, return TRUE; } -/** - * Implementation of trap_manager_t.create_enumerator - */ -static enumerator_t* create_enumerator(private_trap_manager_t *this) +METHOD(trap_manager_t, create_enumerator, enumerator_t*, + private_trap_manager_t *this) { this->lock->read_lock(this->lock); return enumerator_create_filter(this->traps->create_enumerator(this->traps), @@ -245,11 +241,9 @@ static enumerator_t* create_enumerator(private_trap_manager_t *this) (void*)this->lock->unlock); } -/** - * Implementation of trap_manager_t.acquire - */ -static void acquire(private_trap_manager_t *this, u_int32_t reqid, - traffic_selector_t *src, traffic_selector_t *dst) +METHOD(trap_manager_t, acquire, void, + private_trap_manager_t *this, u_int32_t reqid, + traffic_selector_t *src, traffic_selector_t *dst) { enumerator_t *enumerator; entry_t *entry, *found = NULL; @@ -272,35 +266,46 @@ static void acquire(private_trap_manager_t *this, u_int32_t reqid, if (!found) { DBG1(DBG_CFG, "trap not found, unable to acquire reqid %d",reqid); + this->lock->unlock(this->lock); + return; } - else if (found->pending) + if (!cas_bool(&found->pending, FALSE, TRUE)) { DBG1(DBG_CFG, "ignoring acquire, connection attempt pending"); + this->lock->unlock(this->lock); + return; } - else + peer = found->peer_cfg->get_ref(found->peer_cfg); + child = found->child_sa->get_config(found->child_sa); + child = child->get_ref(child); + reqid = found->child_sa->get_reqid(found->child_sa); + /* don't hold the lock while checking out the IKE_SA */ + this->lock->unlock(this->lock); + + ike_sa = charon->ike_sa_manager->checkout_by_config( + charon->ike_sa_manager, peer); + if (ike_sa->get_peer_cfg(ike_sa) == NULL) { - 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); - reqid = found->child_sa->get_reqid(found->child_sa); - if (ike_sa->initiate(ike_sa, child, reqid, src, dst) != DESTROY_ME) - { - found->pending = ike_sa; - charon->ike_sa_manager->checkin(charon->ike_sa_manager, ike_sa); - } - else + ike_sa->set_peer_cfg(ike_sa, peer); + } + 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) { - charon->ike_sa_manager->checkin_and_destroy( - charon->ike_sa_manager, ike_sa); + found->ike_sa = ike_sa; } + this->lock->unlock(this->lock); + charon->ike_sa_manager->checkin(charon->ike_sa_manager, ike_sa); } - this->lock->unlock(this->lock); + else + { + charon->ike_sa_manager->checkin_and_destroy( + charon->ike_sa_manager, ike_sa); + } + peer->destroy(peer); } /** @@ -316,7 +321,7 @@ static void complete(private_trap_manager_t *this, ike_sa_t *ike_sa, enumerator = this->traps->create_enumerator(this->traps); while (enumerator->enumerate(enumerator, &entry)) { - if (entry->pending != ike_sa) + if (entry->ike_sa != ike_sa) { continue; } @@ -325,17 +330,15 @@ static void complete(private_trap_manager_t *this, ike_sa_t *ike_sa, { continue; } - entry->pending = NULL; + entry->ike_sa = NULL; + entry->pending = FALSE; } enumerator->destroy(enumerator); this->lock->unlock(this->lock); } -/** - * Implementation of listener_t.ike_state_change - */ -static bool ike_state_change(trap_listener_t *listener, ike_sa_t *ike_sa, - ike_sa_state_t state) +METHOD(listener_t, ike_state_change, bool, + trap_listener_t *listener, ike_sa_t *ike_sa, ike_sa_state_t state) { switch (state) { @@ -347,11 +350,9 @@ static bool ike_state_change(trap_listener_t *listener, ike_sa_t *ike_sa, } } -/** - * Implementation of listener_t.child_state_change - */ -static bool child_state_change(trap_listener_t *listener, ike_sa_t *ike_sa, - child_sa_t *child_sa, child_sa_state_t state) +METHOD(listener_t, child_state_change, bool, + trap_listener_t *listener, ike_sa_t *ike_sa, child_sa_t *child_sa, + child_sa_state_t state) { switch (state) { @@ -364,14 +365,24 @@ static bool child_state_change(trap_listener_t *listener, ike_sa_t *ike_sa, } } -/** - * Implementation of trap_manager_t.destroy. - */ -static void destroy(private_trap_manager_t *this) +METHOD(trap_manager_t, flush, void, + private_trap_manager_t *this) +{ + linked_list_t *traps; + /* since destroying the CHILD_SA results in events which require a read + * lock we cannot destroy the list while holding the write lock */ + this->lock->write_lock(this->lock); + traps = this->traps; + this->traps = linked_list_create(); + this->lock->unlock(this->lock); + traps->destroy_function(traps, (void*)destroy_entry); +} + +METHOD(trap_manager_t, destroy, void, + private_trap_manager_t *this) { charon->bus->remove_listener(charon->bus, &this->listener.listener); - this->traps->invoke_function(this->traps, (void*)destroy_entry); - this->traps->destroy(this->traps); + this->traps->destroy_function(this->traps, (void*)destroy_entry); this->lock->destroy(this->lock); free(this); } @@ -379,24 +390,29 @@ static void destroy(private_trap_manager_t *this) /** * See header */ -trap_manager_t *trap_manager_create() +trap_manager_t *trap_manager_create(void) { - 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_int32_t id))uninstall; - this->public.create_enumerator = (enumerator_t*(*)(trap_manager_t*))create_enumerator; - this->public.acquire = (void(*)(trap_manager_t*, u_int32_t reqid, traffic_selector_t *src, traffic_selector_t *dst))acquire; - this->public.destroy = (void(*)(trap_manager_t*))destroy; - - this->traps = linked_list_create(); - this->lock = rwlock_create(RWLOCK_TYPE_DEFAULT); - - /* register listener for IKE state changes */ - this->listener.traps = this; - memset(&this->listener.listener, 0, sizeof(listener_t)); - this->listener.listener.ike_state_change = (void*)ike_state_change; - this->listener.listener.child_state_change = (void*)child_state_change; + private_trap_manager_t *this; + + INIT(this, + .public = { + .install = _install, + .uninstall = _uninstall, + .create_enumerator = _create_enumerator, + .acquire = _acquire, + .flush = _flush, + .destroy = _destroy, + }, + .listener = { + .traps = this, + .listener = { + .ike_state_change = _ike_state_change, + .child_state_change = _child_state_change, + }, + }, + .traps = linked_list_create(), + .lock = rwlock_create(RWLOCK_TYPE_DEFAULT), + ); charon->bus->add_listener(charon->bus, &this->listener.listener); return &this->public; diff --git a/src/libcharon/sa/trap_manager.h b/src/libcharon/sa/trap_manager.h index 37b42e2b0..928b2a49f 100644 --- a/src/libcharon/sa/trap_manager.h +++ b/src/libcharon/sa/trap_manager.h @@ -68,6 +68,11 @@ struct trap_manager_t { traffic_selector_t *src, traffic_selector_t *dst); /** + * Clear any installed trap. + */ + void (*flush)(trap_manager_t *this); + + /** * Destroy a trap_manager_t. */ void (*destroy)(trap_manager_t *this); |