diff options
author | Rene Mayrhofer <rene@mayrhofer.eu.org> | 2008-10-29 20:30:44 +0000 |
---|---|---|
committer | Rene Mayrhofer <rene@mayrhofer.eu.org> | 2008-10-29 20:30:44 +0000 |
commit | 74f0bbfc53cb5fa519e4e27ece53735ab51b397c (patch) | |
tree | 0dbab9c835be15577ff05b474b6361bb326d66ce /src/charon/sa | |
parent | 5c1fa2516bda1ccf8eb00178c0beb196c2020a94 (diff) | |
download | vyos-strongswan-74f0bbfc53cb5fa519e4e27ece53735ab51b397c.tar.gz vyos-strongswan-74f0bbfc53cb5fa519e4e27ece53735ab51b397c.zip |
- New upstream release.
Diffstat (limited to 'src/charon/sa')
30 files changed, 1289 insertions, 357 deletions
diff --git a/src/charon/sa/authenticators/authenticator.c b/src/charon/sa/authenticators/authenticator.c index c301e4933..827c7a69a 100644 --- a/src/charon/sa/authenticators/authenticator.c +++ b/src/charon/sa/authenticators/authenticator.c @@ -1,6 +1,6 @@ /* * Copyright (C) 2008 Tobias Brunner - * Copyright (C) 2006 Martin Willi + * Copyright (C) 2006-2008 Martin Willi * Hochschule fuer Technik Rapperswil * * This program is free software; you can redistribute it and/or modify it @@ -13,7 +13,7 @@ * or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License * for more details. * - * $Id: authenticator.c 4051 2008-06-10 09:08:27Z tobias $ + * $Id: authenticator.c 4276 2008-08-22 10:44:51Z martin $ */ #include <string.h> @@ -33,22 +33,27 @@ ENUM_NEXT(auth_method_names, AUTH_ECDSA_256, AUTH_ECDSA_521, AUTH_DSS, "ECDSA-256 signature", "ECDSA-384 signature", "ECDSA-521 signature"); -ENUM_NEXT(auth_method_names, AUTH_EAP, AUTH_EAP, AUTH_ECDSA_521, - "EAP"); -ENUM_END(auth_method_names, AUTH_EAP); +ENUM_END(auth_method_names, AUTH_ECDSA_521); + +ENUM(auth_class_names, AUTH_CLASS_PUBKEY, AUTH_CLASS_EAP, + "public key", + "pre-shared key", + "EAP", +); /** * Described in header. */ -authenticator_t *authenticator_create(ike_sa_t *ike_sa, config_auth_method_t auth_method) +authenticator_t *authenticator_create_from_class(ike_sa_t *ike_sa, + auth_class_t class) { - switch (auth_method) + switch (class) { - case CONF_AUTH_PUBKEY: + case AUTH_CLASS_PUBKEY: return (authenticator_t*)pubkey_authenticator_create(ike_sa); - case CONF_AUTH_PSK: + case AUTH_CLASS_PSK: return (authenticator_t*)psk_authenticator_create(ike_sa); - case CONF_AUTH_EAP: + case AUTH_CLASS_EAP: return (authenticator_t*)eap_authenticator_create(ike_sa); default: return NULL; @@ -58,9 +63,10 @@ authenticator_t *authenticator_create(ike_sa_t *ike_sa, config_auth_method_t aut /** * Described in header. */ -authenticator_t *authenticator_create_from_auth_payload(ike_sa_t *ike_sa, auth_payload_t *auth_payload) +authenticator_t *authenticator_create_from_method(ike_sa_t *ike_sa, + auth_method_t method) { - switch (auth_payload->get_auth_method(auth_payload)) + switch (method) { case AUTH_RSA: case AUTH_ECDSA_256: diff --git a/src/charon/sa/authenticators/authenticator.h b/src/charon/sa/authenticators/authenticator.h index 3c961d23e..aa5a73e86 100644 --- a/src/charon/sa/authenticators/authenticator.h +++ b/src/charon/sa/authenticators/authenticator.h @@ -1,6 +1,6 @@ /* * Copyright (C) 2008 Tobias Brunner - * Copyright (C) 2005-2006 Martin Willi + * Copyright (C) 2005-2008 Martin Willi * Copyright (C) 2005 Jan Hutter * Hochschule fuer Technik Rapperswil * @@ -14,7 +14,7 @@ * or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License * for more details. * - * $Id: authenticator.h 4051 2008-06-10 09:08:27Z tobias $ + * $Id: authenticator.h 4276 2008-08-22 10:44:51Z martin $ */ /** @@ -26,6 +26,7 @@ #define AUTHENTICATOR_H_ typedef enum auth_method_t auth_method_t; +typedef enum auth_class_t auth_class_t; typedef struct authenticator_t authenticator_t; #include <library.h> @@ -34,7 +35,7 @@ typedef struct authenticator_t authenticator_t; #include <encoding/payloads/auth_payload.h> /** - * Method to use for authentication. + * Method to use for authentication, as defined in IKEv2. */ enum auth_method_t { /** @@ -70,12 +71,6 @@ enum auth_method_t { * ECDSA with SHA-512 on the P-521 curve as specified in RFC 4754 */ AUTH_ECDSA_521 = 11, - - /** - * EAP authentication. This value is never negotiated and therefore - * a value from private use. - */ - AUTH_EAP = 201, }; /** @@ -84,11 +79,31 @@ enum auth_method_t { extern enum_name_t *auth_method_names; /** + * Class of authentication to use. This is different to auth_method_t in that + * it does not specify a method, but a class of acceptable methods. The found + * certificate finally dictates wich method is used. + */ +enum auth_class_t { + /** authentication using public keys (RSA, ECDSA) */ + AUTH_CLASS_PUBKEY = 1, + /** authentication using a pre-shared secrets */ + AUTH_CLASS_PSK = 2, + /** authentication using EAP */ + AUTH_CLASS_EAP = 3, +}; + +/** + * enum strings for auth_class_t + */ +extern enum_name_t *auth_class_names; + +/** * Authenticator interface implemented by the various authenticators. * * Currently the following two AUTH methods are supported: * - shared key message integrity code * - RSA digital signature + * - EAP using the EAP framework and one of the EAP plugins * - ECDSA is supported using OpenSSL */ struct authenticator_t { @@ -96,15 +111,14 @@ struct authenticator_t { /** * Verify a received authentication payload. * - * @param ike_sa_init binary representation of received ike_sa_init - * @param my_nonce the sent nonce - * @param auth_payload authentication payload to verify - * + * @param ike_sa_init binary representation of received ike_sa_init + * @param my_nonce the sent nonce + * @param auth_payload authentication payload to verify * @return - * - SUCCESS, - * - FAILED if verification failed - * - INVALID_ARG if auth_method does not match - * - NOT_FOUND if credentials not found + * - SUCCESS, + * - FAILED if verification failed + * - INVALID_ARG if auth_method does not match + * - NOT_FOUND if credentials not found */ status_t (*verify) (authenticator_t *this, chunk_t ike_sa_init, chunk_t my_nonce, auth_payload_t *auth_payload); @@ -112,13 +126,12 @@ struct authenticator_t { /** * Build an authentication payload to send to the other peer. * - * @param ike_sa_init binary representation of sent ike_sa_init - * @param other_nonce the received nonce - * @param[out] auth_payload the resulting authentication payload - * + * @param ike_sa_init binary representation of sent ike_sa_init + * @param other_nonce the received nonce + * @param auth_payload the resulting authentication payload * @return - * - SUCCESS, - * - NOT_FOUND if the data for AUTH method could not be found + * - SUCCESS, + * - NOT_FOUND if credentials not found */ status_t (*build) (authenticator_t *this, chunk_t ike_sa_init, chunk_t other_nonce, auth_payload_t **auth_payload); @@ -130,23 +143,23 @@ struct authenticator_t { }; /** - * Creates an authenticator for the specified auth method (as configured). + * Creates an authenticator for the specified auth class (as configured). * * @param ike_sa associated ike_sa - * @param auth_method authentication method to use for build()/verify() - * + * @param class class of authentication to use * @return authenticator_t object */ -authenticator_t *authenticator_create(ike_sa_t *ike_sa, config_auth_method_t auth_method); +authenticator_t *authenticator_create_from_class(ike_sa_t *ike_sa, + auth_class_t class); /** - * Creates an authenticator from the given auth payload. + * Creates an authenticator for method (as received in payload). * * @param ike_sa associated ike_sa - * @param auth_payload auth payload - * + * @param method method as found in payload * @return authenticator_t object */ -authenticator_t *authenticator_create_from_auth_payload(ike_sa_t *ike_sa, auth_payload_t *auth_payload); +authenticator_t *authenticator_create_from_method(ike_sa_t *ike_sa, + auth_method_t method); #endif /* AUTHENTICATOR_H_ @} */ diff --git a/src/charon/sa/authenticators/eap/eap_method.c b/src/charon/sa/authenticators/eap/eap_method.c index 5e2db5489..11b12fb49 100644 --- a/src/charon/sa/authenticators/eap/eap_method.c +++ b/src/charon/sa/authenticators/eap/eap_method.c @@ -12,19 +12,19 @@ * or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License * for more details. * - * $Id: eap_method.c 3589 2008-03-13 14:14:44Z martin $ + * $Id: eap_method.c 4269 2008-08-21 12:10:07Z martin $ */ #include "eap_method.h" -ENUM_BEGIN(eap_type_names, EAP_IDENTITY, EAP_TOKEN_CARD, +ENUM_BEGIN(eap_type_names, EAP_IDENTITY, EAP_GTC, "EAP_IDENTITY", "EAP_NOTIFICATION", "EAP_NAK", "EAP_MD5", - "EAP_ONE_TIME_PASSWORD", - "EAP_TOKEN_CARD"); -ENUM_NEXT(eap_type_names, EAP_SIM, EAP_SIM, EAP_TOKEN_CARD, + "EAP_OTP", + "EAP_GTC"); +ENUM_NEXT(eap_type_names, EAP_SIM, EAP_SIM, EAP_GTC, "EAP_SIM"); ENUM_NEXT(eap_type_names, EAP_AKA, EAP_AKA, EAP_SIM, "EAP_AKA"); diff --git a/src/charon/sa/authenticators/eap/eap_method.h b/src/charon/sa/authenticators/eap/eap_method.h index eda6f545e..663117931 100644 --- a/src/charon/sa/authenticators/eap/eap_method.h +++ b/src/charon/sa/authenticators/eap/eap_method.h @@ -12,7 +12,7 @@ * or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License * for more details. * - * $Id: eap_method.h 3589 2008-03-13 14:14:44Z martin $ + * $Id: eap_method.h 4276 2008-08-22 10:44:51Z martin $ */ /** @@ -52,8 +52,8 @@ enum eap_type_t { EAP_NOTIFICATION = 2, EAP_NAK = 3, EAP_MD5 = 4, - EAP_ONE_TIME_PASSWORD = 5, - EAP_TOKEN_CARD = 6, + EAP_OTP = 5, + EAP_GTC = 6, EAP_SIM = 18, EAP_AKA = 23, EAP_EXPANDED = 254, @@ -95,6 +95,8 @@ extern enum_name_t *eap_code_names; * authentication. Even if a mutual EAP method is used, the traditional * AUTH payloads are required. Only these include the nonces and messages from * ike_sa_init and therefore prevent man in the middle attacks. + * The EAP method must use an initial EAP identifier value != 0, as a preceding + * EAP-Identity exchange always uses identifier 0. */ struct eap_method_t { @@ -148,7 +150,8 @@ struct eap_method_t { /** * Get the MSK established by this EAP method. * - * Not all EAP methods establish a shared secret. + * Not all EAP methods establish a shared secret. For implementations of + * the EAP-Identity method, get_msk() returns the received identity. * * @param msk chunk receiving internal stored MSK * @return @@ -171,6 +174,8 @@ struct eap_method_t { * Constructors for server and peers are identical, to support both roles * of a EAP method, a plugin needs register two constructors in the * eap_manager_t. + * The passed identites are of type ID_EAP and valid only during the + * constructor invocation. * * @param server ID of the server to use for credential lookup * @param peer ID of the peer to use for credential lookup diff --git a/src/charon/sa/authenticators/eap/sim_manager.c b/src/charon/sa/authenticators/eap/sim_manager.c new file mode 100644 index 000000000..e6817ca20 --- /dev/null +++ b/src/charon/sa/authenticators/eap/sim_manager.c @@ -0,0 +1,125 @@ +/* + * 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. + * + * $Id$ + */ + +#include "sim_manager.h" + +#include <utils/linked_list.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 *provider; +}; + +/** + * Implementation of sim_manager_t.add_card + */ +static void add_card(private_sim_manager_t *this, sim_card_t *card) +{ + this->cards->insert_last(this->cards, card); +} + +/** + * Implementation of sim_manager_t.remove_card + */ +static void remove_card(private_sim_manager_t *this, sim_card_t *card) +{ + this->cards->remove(this->cards, card, NULL); +} + +/** + * Implementation of sim_manager_t.create_card_enumerator + */ +static enumerator_t* create_card_enumerator(private_sim_manager_t *this) +{ + return this->cards->create_enumerator(this->cards); +} + +/** + * Implementation of sim_manager_t.add_provider + */ +static void add_provider(private_sim_manager_t *this, + sim_provider_t *provider) +{ + this->provider->insert_last(this->provider, provider); +} + +/** + * Implementation of sim_manager_t.remove_provider + */ +static void remove_provider(private_sim_manager_t *this, + sim_provider_t *provider) +{ + this->provider->remove(this->provider, provider, NULL); +} + +/** + * Implementation of sim_manager_t.create_provider_enumerator + */ +static enumerator_t* create_provider_enumerator(private_sim_manager_t *this) +{ + return this->provider->create_enumerator(this->provider); +} + +/** + * Implementation of sim_manager_t.destroy. + */ +static void destroy(private_sim_manager_t *this) +{ + this->cards->destroy(this->cards); + this->provider->destroy(this->provider); + free(this); +} + +/** + * See header + */ +sim_manager_t *sim_manager_create() +{ + private_sim_manager_t *this = malloc_thing(private_sim_manager_t); + + this->public.add_card = (void(*)(sim_manager_t*, sim_card_t *card))add_card; + this->public.remove_card = (void(*)(sim_manager_t*, sim_card_t *card))remove_card; + this->public.create_card_enumerator = (enumerator_t*(*)(sim_manager_t*))create_card_enumerator; + this->public.add_provider = (void(*)(sim_manager_t*, sim_provider_t *provider))add_provider; + this->public.remove_provider = (void(*)(sim_manager_t*, sim_provider_t *provider))remove_provider; + this->public.create_provider_enumerator = (enumerator_t*(*)(sim_manager_t*))create_provider_enumerator; + this->public.destroy = (void(*)(sim_manager_t*))destroy; + + this->cards = linked_list_create(); + this->provider = linked_list_create(); + + return &this->public; +} + diff --git a/src/charon/sa/authenticators/eap/sim_manager.h b/src/charon/sa/authenticators/eap/sim_manager.h new file mode 100644 index 000000000..7fb1f2858 --- /dev/null +++ b/src/charon/sa/authenticators/eap/sim_manager.h @@ -0,0 +1,136 @@ +/* + * 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. + */ + +/** + * @defgroup sim_manager sim_manager + * @{ @ingroup eap + */ + +#ifndef SIM_MANAGER_H_ +#define SIM_MANAGER_H_ + +#include <utils/identification.h> +#include <utils/enumerator.h> + +typedef struct sim_manager_t sim_manager_t; +typedef struct sim_card_t sim_card_t; +typedef struct sim_provider_t sim_provider_t; + +/** + * Interface for a SIM card (used as EAP client). + */ +struct sim_card_t { + + /** + * Get the identity of a SIM card. + * + * The returned identity owned by the sim_card and not destroyed outside. + * The SIM card may return ID_ANY if it does not support/use an IMSI. + * + * @return identity of type ID_EAP/ID_ANY + */ + identification_t* (*get_imsi)(sim_card_t *this); + + /** + * Calculate SRES/KC from a RAND. + * + * @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 + */ + bool (*get_triplet)(sim_card_t *this, + char rand[16], char sres[4], char kc[8]); +}; + +/** + * Interface for a triplet provider (used as EAP server). + */ +struct sim_provider_t { + + /** + * Get a single triplet to authenticate a EAP client. + * + * @param imsi client identity of type ID_EAP + * @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 *imsi, + char rand[16], char sres[4], char kc[8]); +}; + +/** + * The EAP-SIM manager handles multiple SIM cards and providers. + */ +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); + + /** + * Create an enumerator over all registered cards. + * + * @return enumerator over sim_card_t's + */ + enumerator_t* (*create_card_enumerator)(sim_manager_t *this); + + /** + * 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); + + /** + * Create an enumerator over all registered provider. + * + * @return enumerator over sim_provider_t's + */ + enumerator_t* (*create_provider_enumerator)(sim_manager_t *this); + + /** + * Destroy a manager instance. + */ + void (*destroy)(sim_manager_t *this); +}; + +/** + * Create an SIM manager to handle multiple SIM cards/providers. + * + * @return sim_t object + */ +sim_manager_t *sim_manager_create(); + +#endif /* SIM_MANAGER_H_ @}*/ diff --git a/src/charon/sa/authenticators/eap_authenticator.c b/src/charon/sa/authenticators/eap_authenticator.c index 95bb5e57f..0909d6563 100644 --- a/src/charon/sa/authenticators/eap_authenticator.c +++ b/src/charon/sa/authenticators/eap_authenticator.c @@ -12,7 +12,7 @@ * or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License * for more details. * - * $Id: eap_authenticator.c 3589 2008-03-13 14:14:44Z martin $ + * $Id: eap_authenticator.c 4292 2008-08-26 19:54:47Z andreas $ */ #include <string.h> @@ -54,6 +54,21 @@ struct private_eap_authenticator_t { * MSK used to build and verify auth payload */ chunk_t msk; + + /** + * should we do a EAP-Identity exchange as server? + */ + bool do_eap_identity; + + /** + * saved EAP type if we do eap_identity + */ + eap_type_t type; + + /** + * saved vendor id if we do eap_identity + */ + u_int32_t vendor; }; /** @@ -93,7 +108,7 @@ static status_t verify(private_eap_authenticator_t *this, chunk_t ike_sa_init, chunk_free(&auth_data); DBG1(DBG_IKE, "authentication of '%D' with %N successful", - other_id, auth_method_names, AUTH_EAP); + other_id, auth_class_names, AUTH_CLASS_EAP); return SUCCESS; } @@ -107,7 +122,7 @@ static status_t build(private_eap_authenticator_t *this, chunk_t ike_sa_init, identification_t *my_id = this->ike_sa->get_my_id(this->ike_sa); DBG1(DBG_IKE, "authentication of '%D' (myself) with %N", - my_id, auth_method_names, AUTH_EAP); + my_id, auth_class_names, AUTH_CLASS_EAP); if (this->msk.len) { /* use MSK if EAP method established one... */ @@ -130,6 +145,79 @@ static status_t build(private_eap_authenticator_t *this, chunk_t ike_sa_init, } /** + * get the peers identity to use in the EAP method + */ +static identification_t *get_peer_id(private_eap_authenticator_t *this) +{ + identification_t *id; + peer_cfg_t *config; + auth_info_t *auth; + + id = this->ike_sa->get_eap_identity(this->ike_sa); + if (!id) + { + config = this->ike_sa->get_peer_cfg(this->ike_sa); + auth = config->get_auth(config); + if (!auth->get_item(auth, AUTHN_EAP_IDENTITY, (void**)&id)) + { + if (this->role == EAP_PEER) + { + id = this->ike_sa->get_my_id(this->ike_sa); + } + else + { + id = this->ike_sa->get_other_id(this->ike_sa); + } + } + } + if (id->get_type(id) == ID_EAP) + { + return id->clone(id); + } + return identification_create_from_encoding(ID_EAP, id->get_encoding(id)); +} + +/** + * get the servers identity to use in the EAP method + */ +static identification_t *get_server_id(private_eap_authenticator_t *this) +{ + identification_t *id; + + if (this->role == EAP_SERVER) + { + id = this->ike_sa->get_my_id(this->ike_sa); + } + else + { + id = this->ike_sa->get_other_id(this->ike_sa); + } + if (id->get_type(id) == ID_EAP) + { + return id->clone(id); + } + return identification_create_from_encoding(ID_EAP, id->get_encoding(id)); +} + +/** + * load an EAP method using the correct identities + */ +static eap_method_t *load_method(private_eap_authenticator_t *this, + eap_type_t type, u_int32_t vendor, eap_role_t role) +{ + identification_t *server, *peer; + eap_method_t *method; + + server = get_server_id(this); + peer = get_peer_id(this); + method = charon->eap->create_instance(charon->eap, type, vendor, role, + server, peer); + server->destroy(server); + peer->destroy(peer); + return method; +} + +/** * Implementation of eap_authenticator_t.initiate */ static status_t initiate(private_eap_authenticator_t *this, eap_type_t type, @@ -138,6 +226,14 @@ static status_t initiate(private_eap_authenticator_t *this, eap_type_t type, /* if initiate() is called, role is always server */ this->role = EAP_SERVER; + if (this->do_eap_identity) + { /* do an EAP-Identity request first */ + this->type = type; + this->vendor = vendor; + vendor = 0; + type = EAP_IDENTITY; + } + if (type == 0) { DBG1(DBG_IKE, @@ -148,20 +244,23 @@ static status_t initiate(private_eap_authenticator_t *this, eap_type_t type, if (vendor) { - DBG1(DBG_IKE, "requesting vendor specific EAP authentication %d-%d", + DBG1(DBG_IKE, "requesting vendor specific EAP method %d-%d", type, vendor); } else { - DBG1(DBG_IKE, "requesting %N authentication", eap_type_names, type); + DBG1(DBG_IKE, "requesting EAP method %N", eap_type_names, type); } - this->method = charon->eap->create_instance(charon->eap, type, vendor, - this->role, this->ike_sa->get_my_id(this->ike_sa), - this->ike_sa->get_other_id(this->ike_sa)); - + this->method = load_method(this, type, vendor, this->role); if (this->method == NULL) { - + if (vendor == 0 && type == EAP_IDENTITY) + { + DBG1(DBG_IKE, "skipping %N, no implementation found", + eap_type_names, type); + this->do_eap_identity = FALSE; + return initiate(this, this->type, this->vendor, out); + } DBG1(DBG_IKE, "configured EAP server method not supported, sending %N", eap_code_names, EAP_FAILURE); *out = eap_payload_create_code(EAP_FAILURE, 0); @@ -192,10 +291,7 @@ static status_t process_peer(private_eap_authenticator_t *this, { eap_method_t *method; - method = charon->eap->create_instance(charon->eap, type, 0, EAP_PEER, - this->ike_sa->get_other_id(this->ike_sa), - this->ike_sa->get_my_id(this->ike_sa)); - + method = load_method(this, type, 0, EAP_PEER); if (method == NULL || method->process(method, in, out) != SUCCESS) { DBG1(DBG_IKE, "EAP server requested %N, but unable to process", @@ -203,10 +299,7 @@ static status_t process_peer(private_eap_authenticator_t *this, DESTROY_IF(method); return FAILED; } - - DBG1(DBG_IKE, "EAP server requested %N, sending IKE identity", - eap_type_names, type); - + DBG1(DBG_IKE, "EAP server requested %N", eap_type_names, type); method->destroy(method); return NEED_MORE; } @@ -224,10 +317,7 @@ static status_t process_peer(private_eap_authenticator_t *this, DBG1(DBG_IKE, "EAP server requested %N authentication", eap_type_names, type); } - this->method = charon->eap->create_instance(charon->eap, - type, vendor, EAP_PEER, - this->ike_sa->get_other_id(this->ike_sa), - this->ike_sa->get_my_id(this->ike_sa)); + this->method = load_method(this, type, vendor, EAP_PEER); if (this->method == NULL) { DBG1(DBG_IKE, "EAP server requested unsupported " @@ -251,7 +341,7 @@ static status_t process_peer(private_eap_authenticator_t *this, } else { - DBG1(DBG_IKE, "EAP method %N succeded", eap_type_names, type); + DBG1(DBG_IKE, "EAP method %N succeeded", eap_type_names, type); } return SUCCESS; case FAILED: @@ -271,6 +361,27 @@ static status_t process_peer(private_eap_authenticator_t *this, } /** + * handle an EAP-Identity response on the server + */ +static status_t process_eap_identity(private_eap_authenticator_t *this, + eap_payload_t **out) +{ + chunk_t data; + identification_t *id; + + if (this->method->get_msk(this->method, &data) == SUCCESS) + { + id = identification_create_from_encoding(ID_EAP, data); + DBG1(DBG_IKE, "using EAP identity '%D'", id); + this->ike_sa->set_eap_identity(this->ike_sa, id); + } + /* restart EAP exchange, but with real method */ + this->method->destroy(this->method); + this->do_eap_identity = FALSE; + return initiate(this, this->type, this->vendor, out); +} + +/** * Processing method for a server */ static status_t process_server(private_eap_authenticator_t *this, @@ -286,6 +397,10 @@ static status_t process_server(private_eap_authenticator_t *this, case NEED_MORE: return NEED_MORE; case SUCCESS: + if (this->do_eap_identity) + { + return process_eap_identity(this, out); + } if (this->method->get_msk(this->method, &this->msk) == SUCCESS) { this->msk = chunk_clone(this->msk); @@ -409,6 +524,9 @@ static void destroy(private_eap_authenticator_t *this) */ eap_authenticator_t *eap_authenticator_create(ike_sa_t *ike_sa) { + peer_cfg_t *config; + auth_info_t *auth; + identification_t *id; private_eap_authenticator_t *this = malloc_thing(private_eap_authenticator_t); /* public functions */ @@ -425,6 +543,25 @@ eap_authenticator_t *eap_authenticator_create(ike_sa_t *ike_sa) this->role = EAP_PEER; this->method = NULL; this->msk = chunk_empty; + this->do_eap_identity = FALSE; + this->type = 0; + this->vendor = 0; + config = ike_sa->get_peer_cfg(ike_sa); + if (config) + { + auth = config->get_auth(config); + if (auth->get_item(auth, AUTHN_EAP_IDENTITY, (void**)&id)) + { + if (id->get_type(id) == ID_ANY) + { /* %any as configured EAP identity runs EAP-Identity first */ + this->do_eap_identity = TRUE; + } + else + { + ike_sa->set_eap_identity(ike_sa, id->clone(id)); + } + } + } return &this->public; } diff --git a/src/charon/sa/authenticators/eap_authenticator.h b/src/charon/sa/authenticators/eap_authenticator.h index 2dad59fbb..bd300a584 100644 --- a/src/charon/sa/authenticators/eap_authenticator.h +++ b/src/charon/sa/authenticators/eap_authenticator.h @@ -12,7 +12,7 @@ * or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License * for more details. * - * $Id: eap_authenticator.h 3589 2008-03-13 14:14:44Z martin $ + * $Id: eap_authenticator.h 4276 2008-08-22 10:44:51Z martin $ */ /** @@ -29,7 +29,7 @@ typedef struct eap_authenticator_t eap_authenticator_t; #include <encoding/payloads/eap_payload.h> /** - * Implementation of the authenticator_t interface using AUTH_EAP. + * Implementation of the authenticator_t interface using AUTH_CLASS_EAP. * * Authentication using EAP involves the most complex authenticator. It stays * alive over multiple ike_auth transactions and handles multiple EAP @@ -137,7 +137,7 @@ struct eap_authenticator_t { }; /** - * Creates an authenticator for AUTH_EAP. + * Creates an authenticator for AUTH_CLASS_EAP. * * @param ike_sa associated ike_sa * @return eap_authenticator_t object diff --git a/src/charon/sa/child_sa.c b/src/charon/sa/child_sa.c index 2a6b6f67c..7c4b398cf 100644 --- a/src/charon/sa/child_sa.c +++ b/src/charon/sa/child_sa.c @@ -15,7 +15,7 @@ * or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License * for more details. * - * $Id: child_sa.c 3920 2008-05-08 16:19:11Z tobias $ + * $Id: child_sa.c 4358 2008-09-25 13:56:23Z tobias $ */ #define _GNU_SOURCE @@ -163,7 +163,7 @@ struct private_child_sa_t { /** * mode this SA uses, tunnel/transport */ - mode_t mode; + ipsec_mode_t mode; /** * virtual IP assinged to local host @@ -210,6 +210,18 @@ u_int32_t get_spi(private_child_sa_t *this, bool inbound) } /** + * Implements child_sa_t.get_cpi + */ +u_int16_t get_cpi(private_child_sa_t *this, bool inbound) +{ + if (inbound) + { + return this->me.cpi; + } + return this->other.cpi; +} + +/** * Implements child_sa_t.get_protocol */ protocol_id_t get_protocol(private_child_sa_t *this) @@ -236,7 +248,7 @@ static child_cfg_t* get_config(private_child_sa_t *this) /** * Implementation of child_sa_t.get_stats. */ -static void get_stats(private_child_sa_t *this, mode_t *mode, +static void get_stats(private_child_sa_t *this, ipsec_mode_t *mode, encryption_algorithm_t *encr_algo, size_t *encr_len, integrity_algorithm_t *int_algo, size_t *int_len, u_int32_t *rekey, u_int32_t *use_in, u_int32_t *use_out, @@ -514,7 +526,7 @@ static status_t alloc(private_child_sa_t *this, linked_list_t *proposals) } static status_t install(private_child_sa_t *this, proposal_t *proposal, - mode_t mode, prf_plus_t *prf_plus, bool mine) + ipsec_mode_t mode, prf_plus_t *prf_plus, bool mine) { u_int32_t spi, soft, hard; host_t *src; @@ -605,7 +617,7 @@ static status_t install(private_child_sa_t *this, proposal_t *proposal, } static status_t add(private_child_sa_t *this, proposal_t *proposal, - mode_t mode, prf_plus_t *prf_plus) + ipsec_mode_t mode, prf_plus_t *prf_plus) { u_int32_t outbound_spi, inbound_spi; @@ -637,7 +649,7 @@ static status_t add(private_child_sa_t *this, proposal_t *proposal, } static status_t update(private_child_sa_t *this, proposal_t *proposal, - mode_t mode, prf_plus_t *prf_plus) + ipsec_mode_t mode, prf_plus_t *prf_plus) { u_int32_t inbound_spi; @@ -662,14 +674,19 @@ static status_t update(private_child_sa_t *this, proposal_t *proposal, } static status_t add_policies(private_child_sa_t *this, - linked_list_t *my_ts_list, - linked_list_t *other_ts_list, mode_t mode) + linked_list_t *my_ts_list, linked_list_t *other_ts_list, + ipsec_mode_t mode, protocol_id_t proto) { iterator_t *my_iter, *other_iter; traffic_selector_t *my_ts, *other_ts; /* use low prio for ROUTED policies */ bool high_prio = (this->state != CHILD_CREATED); + if (this->protocol == PROTO_NONE) + { /* update if not set yet */ + this->protocol = proto; + } + /* iterate over both lists */ my_iter = my_ts_list->create_iterator(my_ts_list, TRUE); other_iter = other_ts_list->create_iterator(other_ts_list, TRUE); @@ -919,9 +936,9 @@ static void activate_ipcomp(private_child_sa_t *this, ipcomp_transform_t ipcomp, } /** - * Implementation of child_sa_t.get_my_cpi. + * Implementation of child_sa_t.allocate_cpi. */ -static u_int16_t get_my_cpi(private_child_sa_t *this) +static u_int16_t allocate_cpi(private_child_sa_t *this) { if (!this->cpi_allocated) { @@ -968,7 +985,7 @@ static void destroy(private_child_sa_t *this) if (this->me.cpi) { charon->kernel_interface->del_sa(charon->kernel_interface, - this->other.addr, htonl(ntohs(this->me.cpi)), IPPROTO_COMP); + this->me.addr, htonl(ntohs(this->me.cpi)), IPPROTO_COMP); } if (this->other.cpi) { @@ -1023,20 +1040,21 @@ child_sa_t * child_sa_create(host_t *me, host_t* other, this->public.get_name = (char*(*)(child_sa_t*))get_name; this->public.get_reqid = (u_int32_t(*)(child_sa_t*))get_reqid; this->public.get_spi = (u_int32_t(*)(child_sa_t*, bool))get_spi; + this->public.get_cpi = (u_int16_t(*)(child_sa_t*, bool))get_cpi; this->public.get_protocol = (protocol_id_t(*)(child_sa_t*))get_protocol; - this->public.get_stats = (void(*)(child_sa_t*, mode_t*,encryption_algorithm_t*,size_t*,integrity_algorithm_t*,size_t*,u_int32_t*,u_int32_t*,u_int32_t*,u_int32_t*))get_stats; + this->public.get_stats = (void(*)(child_sa_t*, ipsec_mode_t*,encryption_algorithm_t*,size_t*,integrity_algorithm_t*,size_t*,u_int32_t*,u_int32_t*,u_int32_t*,u_int32_t*))get_stats; this->public.alloc = (status_t(*)(child_sa_t*,linked_list_t*))alloc; - this->public.add = (status_t(*)(child_sa_t*,proposal_t*,mode_t,prf_plus_t*))add; - this->public.update = (status_t(*)(child_sa_t*,proposal_t*,mode_t,prf_plus_t*))update; + this->public.add = (status_t(*)(child_sa_t*,proposal_t*,ipsec_mode_t,prf_plus_t*))add; + this->public.update = (status_t(*)(child_sa_t*,proposal_t*,ipsec_mode_t,prf_plus_t*))update; this->public.update_hosts = (status_t (*)(child_sa_t*,host_t*,host_t*,bool))update_hosts; - this->public.add_policies = (status_t (*)(child_sa_t*, linked_list_t*,linked_list_t*,mode_t))add_policies; + this->public.add_policies = (status_t (*)(child_sa_t*, linked_list_t*,linked_list_t*,ipsec_mode_t,protocol_id_t))add_policies; this->public.get_traffic_selectors = (linked_list_t*(*)(child_sa_t*,bool))get_traffic_selectors; this->public.get_use_time = (status_t (*)(child_sa_t*,bool,time_t*))get_use_time; this->public.set_state = (void(*)(child_sa_t*,child_sa_state_t))set_state; this->public.get_state = (child_sa_state_t(*)(child_sa_t*))get_state; this->public.get_config = (child_cfg_t*(*)(child_sa_t*))get_config; this->public.activate_ipcomp = (void(*)(child_sa_t*,ipcomp_transform_t,u_int16_t))activate_ipcomp; - this->public.get_my_cpi = (u_int16_t(*)(child_sa_t*))get_my_cpi; + this->public.allocate_cpi = (u_int16_t(*)(child_sa_t*))allocate_cpi; this->public.set_virtual_ip = (void(*)(child_sa_t*,host_t*))set_virtual_ip; this->public.destroy = (void(*)(child_sa_t*))destroy; diff --git a/src/charon/sa/child_sa.h b/src/charon/sa/child_sa.h index 5bd66acad..2f7961e03 100644 --- a/src/charon/sa/child_sa.h +++ b/src/charon/sa/child_sa.h @@ -14,7 +14,7 @@ * or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License * for more details. * - * $Id: child_sa.h 3920 2008-05-08 16:19:11Z tobias $ + * $Id: child_sa.h 4358 2008-09-25 13:56:23Z tobias $ */ /** @@ -114,11 +114,23 @@ struct child_sa_t { * FALSE to get those we use for sending packets. * * @param inbound TRUE to get inbound SPI, FALSE for outbound. - * @return spi of the CHILD SA + * @return SPI of the CHILD SA */ u_int32_t (*get_spi) (child_sa_t *this, bool inbound); /** + * Get the CPI of this CHILD_SA. + * + * Set the boolean parameter inbound to TRUE to + * get the CPI for which we receive packets, use + * FALSE to get those we use for sending packets. + * + * @param inbound TRUE to get inbound CPI, FALSE for outbound. + * @return CPI of the CHILD SA + */ + u_int16_t (*get_cpi) (child_sa_t *this, bool inbound); + + /** * Get the protocol which this CHILD_SA uses to protect traffic. * * @return AH | ESP @@ -138,7 +150,7 @@ struct child_sa_t { * @param use_out time when last traffic was seen going out * @param use_fwd time when last traffic was getting forwarded */ - void (*get_stats)(child_sa_t *this, mode_t *mode, + void (*get_stats)(child_sa_t *this, ipsec_mode_t *mode, encryption_algorithm_t *encr, size_t *encr_len, integrity_algorithm_t *int_algo, size_t *int_len, u_int32_t *rekey, u_int32_t *use_in, u_int32_t *use_out, @@ -165,7 +177,7 @@ struct child_sa_t { * @param prf_plus key material to use for key derivation * @return SUCCESS or FAILED */ - status_t (*add)(child_sa_t *this, proposal_t *proposal, mode_t mode, + status_t (*add)(child_sa_t *this, proposal_t *proposal, ipsec_mode_t mode, prf_plus_t *prf_plus); /** @@ -178,7 +190,7 @@ struct child_sa_t { * @param prf_plus key material to use for key derivation * @return SUCCESS or FAILED */ - status_t (*update)(child_sa_t *this, proposal_t *proposal, mode_t mode, + status_t (*update)(child_sa_t *this, proposal_t *proposal, ipsec_mode_t mode, prf_plus_t *prf_plus); /** @@ -203,10 +215,12 @@ struct child_sa_t { * @param my_ts traffic selectors for local site * @param other_ts traffic selectors for remote site * @param mode mode for the SA: tunnel/transport + * @param proto protocol for policy, ESP/AH * @return SUCCESS or FAILED */ status_t (*add_policies)(child_sa_t *this, linked_list_t *my_ts_list, - linked_list_t *other_ts_list, mode_t mode); + linked_list_t *other_ts_list, ipsec_mode_t mode, + protocol_id_t proto); /** * Get the traffic selectors of added policies of local host. @@ -268,7 +282,7 @@ struct child_sa_t { * * @return allocated CPI */ - u_int16_t (*get_my_cpi) (child_sa_t *this); + u_int16_t (*allocate_cpi) (child_sa_t *this); /** * Destroys a child_sa. diff --git a/src/charon/sa/connect_manager.c b/src/charon/sa/connect_manager.c index 19ceea666..d24ce8fc7 100644 --- a/src/charon/sa/connect_manager.c +++ b/src/charon/sa/connect_manager.c @@ -12,7 +12,7 @@ * or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License * for more details. * - * $Id: connect_manager.c 3792 2008-04-10 12:51:04Z tobias $ + * $Id: connect_manager.c 4192 2008-07-18 15:51:40Z martin $ */ #include "connect_manager.h" @@ -1160,7 +1160,7 @@ static job_requeue_t initiate_mediated(initiate_data_t *data) 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) { - SIG(IKE_UP_FAILED, "establishing the mediated connection failed"); + SIG_IKE(UP_FAILED, "establishing the mediated connection failed"); charon->ike_sa_manager->checkin_and_destroy(charon->ike_sa_manager, sa); } charon->ike_sa_manager->checkin(charon->ike_sa_manager, sa); diff --git a/src/charon/sa/ike_sa.c b/src/charon/sa/ike_sa.c index 384226380..7b2608e07 100644 --- a/src/charon/sa/ike_sa.c +++ b/src/charon/sa/ike_sa.c @@ -15,7 +15,7 @@ * or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License * for more details. * - * $Id: ike_sa.c 4106 2008-06-25 11:40:50Z martin $ + * $Id: ike_sa.c 4394 2008-10-09 08:25:11Z martin $ */ #include <sys/time.h> @@ -170,6 +170,11 @@ struct private_ike_sa_t { identification_t *other_id; /** + * EAP Identity exchange in EAP-Identity method + */ + identification_t *eap_identity;; + + /** * set of extensions the peer supports */ ike_extension_t extensions; @@ -250,11 +255,21 @@ struct private_ike_sa_t { linked_list_t *additional_addresses; /** + * previously value of received DESTINATION_IP hash + */ + chunk_t nat_detection_dest; + + /** * number pending UPDATE_SA_ADDRESS (MOBIKE) */ u_int32_t pending_updates; /** + * NAT keep alive interval + */ + u_int32_t keepalive_interval; + + /** * Timestamps for this IKE_SA */ struct { @@ -454,7 +469,7 @@ static void send_keepalive(private_ike_sa_t *this) send_keepalive_job_t *job; time_t last_out, now, diff; - if (!(this->conditions & COND_NAT_HERE)) + if (!(this->conditions & COND_NAT_HERE) || this->keepalive_interval == 0) { /* disable keep alives if we are not NATed anymore */ return; } @@ -464,7 +479,7 @@ static void send_keepalive(private_ike_sa_t *this) diff = now - last_out; - if (diff >= KEEPALIVE_INTERVAL) + if (diff >= this->keepalive_interval) { packet_t *packet; chunk_t data; @@ -482,7 +497,7 @@ static void send_keepalive(private_ike_sa_t *this) } job = send_keepalive_job_create(this->ike_sa_id); charon->scheduler->schedule_job(charon->scheduler, (job_t*)job, - (KEEPALIVE_INTERVAL - diff) * 1000); + (this->keepalive_interval - diff) * 1000); } /** @@ -616,8 +631,20 @@ static status_t send_dpd(private_ike_sa_t *this) { /* to long ago, initiate dead peer detection */ task_t *task; + ike_mobike_t *mobike; - task = (task_t*)ike_dpd_create(TRUE); + if (supports_extension(this, EXT_MOBIKE) && + has_condition(this, COND_NAT_HERE)) + { + /* use mobike enabled DPD to detect NAT mapping changes */ + mobike = ike_mobike_create(&this->public, TRUE); + mobike->dpd(mobike); + task = &mobike->task; + } + else + { + task = (task_t*)ike_dpd_create(TRUE); + } diff = 0; DBG1(DBG_IKE, "sending DPD request"); @@ -645,8 +672,8 @@ static ike_sa_state_t get_state(private_ike_sa_t *this) */ static void set_state(private_ike_sa_t *this, ike_sa_state_t state) { - DBG1(DBG_IKE, "IKE_SA '%s' state change: %N => %N", - get_name(this), + DBG2(DBG_IKE, "IKE_SA %s[%d] state change: %N => %N", + get_name(this), this->unique_id, ike_sa_state_names, this->state, ike_sa_state_names, state); @@ -807,7 +834,26 @@ static iterator_t* create_additional_address_iterator(private_ike_sa_t *this) return this->additional_addresses->create_iterator( this->additional_addresses, TRUE); } - + +/** + * Implementation of ike_sa_t.has_mapping_changed + */ +static bool has_mapping_changed(private_ike_sa_t *this, chunk_t hash) +{ + if (this->nat_detection_dest.ptr == NULL) + { + this->nat_detection_dest = chunk_clone(hash); + return FALSE; + } + if (chunk_equals(hash, this->nat_detection_dest)) + { + return FALSE; + } + free(this->nat_detection_dest.ptr); + this->nat_detection_dest = chunk_clone(hash); + return TRUE; +} + /** * Implementation of ike_sa_t.set_pending_updates. */ @@ -831,11 +877,6 @@ static void update_hosts(private_ike_sa_t *this, host_t *me, host_t *other) { bool update = FALSE; - if (supports_extension(this, EXT_MOBIKE)) - { /* if peer speaks mobike, address updates are explicit only */ - return; - } - if (me == NULL) { me = this->my_host; @@ -1041,18 +1082,31 @@ static void resolve_hosts(private_ike_sa_t *this) { host_t *host; - host = host_create_from_dns(this->ike_cfg->get_my_addr(this->ike_cfg), 0, - IKEV2_UDP_PORT); + host = host_create_from_dns(this->ike_cfg->get_other_addr(this->ike_cfg), + 0, IKEV2_UDP_PORT); if (host) { - set_my_host(this, host); + set_other_host(this, host); } - host = host_create_from_dns(this->ike_cfg->get_other_addr(this->ike_cfg), + + host = host_create_from_dns(this->ike_cfg->get_my_addr(this->ike_cfg), this->my_host->get_family(this->my_host), IKEV2_UDP_PORT); + + if (host && host->is_anyaddr(host) && + !this->other_host->is_anyaddr(this->other_host)) + { + host->destroy(host); + host = charon->kernel_interface->get_source_addr( + charon->kernel_interface, this->other_host, NULL); + if (host) + { + host->set_port(host, IKEV2_UDP_PORT); + } + } if (host) { - set_other_host(this, host); + set_my_host(this, host); } } @@ -1074,8 +1128,8 @@ static status_t initiate_with_reqid(private_ike_sa_t *this, child_cfg_t *child_c ) { child_cfg->destroy(child_cfg); - SIG(IKE_UP_START, "initiating IKE_SA"); - SIG(IKE_UP_FAILED, "unable to initiate to %%any"); + SIG_IKE(UP_START, "initiating IKE_SA"); + SIG_IKE(UP_FAILED, "unable to initiate to %%any"); return DESTROY_ME; } @@ -1112,7 +1166,7 @@ static status_t initiate_with_reqid(private_ike_sa_t *this, child_cfg_t *child_c /* mediation connection */ if (this->state == IKE_ESTABLISHED) { /* FIXME: we should try to find a better solution to this */ - SIG(CHILD_UP_SUCCESS, "mediation connection is already up and running"); + SIG_CHD(UP_SUCCESS, NULL, "mediation connection is already up and running"); } DESTROY_IF(child_cfg); } @@ -1162,8 +1216,8 @@ static status_t acquire(private_ike_sa_t *this, u_int32_t reqid) if (this->state == IKE_DELETING) { - SIG(CHILD_UP_START, "acquiring CHILD_SA on kernel request"); - SIG(CHILD_UP_FAILED, "acquiring CHILD_SA (reqid %d) failed: " + SIG_CHD(UP_START, NULL, "acquiring CHILD_SA on kernel request"); + SIG_CHD(UP_FAILED, NULL, "acquiring CHILD_SA {reqid %d} failed: " "IKE_SA is deleting", reqid); return FAILED; } @@ -1181,8 +1235,8 @@ static status_t acquire(private_ike_sa_t *this, u_int32_t reqid) iterator->destroy(iterator); if (!child_sa) { - SIG(CHILD_UP_START, "acquiring CHILD_SA on kernel request"); - SIG(CHILD_UP_FAILED, "acquiring CHILD_SA (reqid %d) failed: " + SIG_CHD(UP_START, NULL, "acquiring CHILD_SA on kernel request"); + SIG_CHD(UP_FAILED, NULL, "acquiring CHILD_SA {reqid %d} failed: " "CHILD_SA not found", reqid); return FAILED; } @@ -1204,7 +1258,7 @@ static status_t route(private_ike_sa_t *this, child_cfg_t *child_cfg) host_t *me, *other; status_t status; - SIG(CHILD_ROUTE_START, "routing CHILD_SA"); + SIG_CHD(ROUTE_START, NULL, "routing CHILD_SA"); /* check if not already routed*/ iterator = this->child_sas->create_iterator(this->child_sas, TRUE); @@ -1214,7 +1268,7 @@ static status_t route(private_ike_sa_t *this, child_cfg_t *child_cfg) streq(child_sa->get_name(child_sa), child_cfg->get_name(child_cfg))) { iterator->destroy(iterator); - SIG(CHILD_ROUTE_FAILED, "CHILD_SA with such a config already routed"); + SIG_CHD(ROUTE_FAILED, child_sa, "CHILD_SA with such a config already routed"); return FAILED; } } @@ -1224,7 +1278,7 @@ static status_t route(private_ike_sa_t *this, child_cfg_t *child_cfg) { case IKE_DELETING: case IKE_REKEYING: - SIG(CHILD_ROUTE_FAILED, + SIG_CHD(ROUTE_FAILED, NULL, "unable to route CHILD_SA, as its IKE_SA gets deleted"); return FAILED; case IKE_CREATED: @@ -1253,17 +1307,17 @@ static status_t route(private_ike_sa_t *this, child_cfg_t *child_cfg) my_ts = child_cfg->get_traffic_selectors(child_cfg, TRUE, NULL, me); other_ts = child_cfg->get_traffic_selectors(child_cfg, FALSE, NULL, other); status = child_sa->add_policies(child_sa, my_ts, other_ts, - child_cfg->get_mode(child_cfg)); + child_cfg->get_mode(child_cfg), PROTO_NONE); my_ts->destroy_offset(my_ts, offsetof(traffic_selector_t, destroy)); other_ts->destroy_offset(other_ts, offsetof(traffic_selector_t, destroy)); if (status == SUCCESS) { this->child_sas->insert_last(this->child_sas, child_sa); - SIG(CHILD_ROUTE_SUCCESS, "CHILD_SA routed"); + SIG_CHD(ROUTE_SUCCESS, child_sa, "CHILD_SA routed"); } else { - SIG(CHILD_ROUTE_FAILED, "routing CHILD_SA failed"); + SIG_CHD(ROUTE_FAILED, child_sa, "routing CHILD_SA failed"); } return status; } @@ -1277,7 +1331,7 @@ static status_t unroute(private_ike_sa_t *this, u_int32_t reqid) child_sa_t *child_sa; bool found = FALSE; - SIG(CHILD_UNROUTE_START, "unrouting CHILD_SA"); + SIG_CHD(UNROUTE_START, NULL, "unrouting CHILD_SA"); /* find CHILD_SA in ROUTED state */ iterator = this->child_sas->create_iterator(this->child_sas, TRUE); @@ -1287,7 +1341,7 @@ static status_t unroute(private_ike_sa_t *this, u_int32_t reqid) child_sa->get_reqid(child_sa) == reqid) { iterator->remove(iterator); - SIG(CHILD_UNROUTE_SUCCESS, "CHILD_SA unrouted"); + SIG_CHD(UNROUTE_SUCCESS, child_sa, "CHILD_SA unrouted"); child_sa->destroy(child_sa); found = TRUE; break; @@ -1297,7 +1351,7 @@ static status_t unroute(private_ike_sa_t *this, u_int32_t reqid) if (!found) { - SIG(CHILD_UNROUTE_FAILED, "CHILD_SA to unroute not found"); + SIG_CHD(UNROUTE_FAILED, NULL, "CHILD_SA to unroute not found"); return FAILED; } /* if we are not established, and we have no more routed childs, remove whole SA */ @@ -1397,13 +1451,15 @@ static status_t process_message(private_ike_sa_t *this, message_t *message) charon->scheduler->schedule_job(charon->scheduler, job, HALF_OPEN_IKE_SA_TIMEOUT); } - + this->time.inbound = time(NULL); /* check if message is trustworthy, and update host information */ if (this->state == IKE_CREATED || this->state == IKE_CONNECTING || message->get_exchange_type(message) != IKE_SA_INIT) { - update_hosts(this, me, other); - this->time.inbound = time(NULL); + if (!supports_extension(this, EXT_MOBIKE)) + { /* with MOBIKE, we do no implicit updates */ + update_hosts(this, me, other); + } } status = this->task_manager->process_message(this->task_manager, message); if (status != DESTROY_ME) @@ -1528,6 +1584,23 @@ static void set_other_id(private_ike_sa_t *this, identification_t *other) } /** + * Implementation of ike_sa_t.get_eap_identity. + */ +static identification_t* get_eap_identity(private_ike_sa_t *this) +{ + return this->eap_identity; +} + +/** + * Implementation of ike_sa_t.set_eap_identity. + */ +static void set_eap_identity(private_ike_sa_t *this, identification_t *id) +{ + DESTROY_IF(this->eap_identity); + this->eap_identity = id; +} + +/** * Implementation of ike_sa_t.derive_keys. */ static status_t derive_keys(private_ike_sa_t *this, @@ -1866,10 +1939,10 @@ static status_t delete_(private_ike_sa_t *this) this->task_manager->queue_task(this->task_manager, &ike_delete->task); return this->task_manager->initiate(this->task_manager); case IKE_CREATED: - SIG(IKE_DOWN_SUCCESS, "deleting unestablished IKE_SA"); + SIG_IKE(DOWN_SUCCESS, "deleting unestablished IKE_SA"); break; default: - SIG(IKE_DOWN_SUCCESS, "destroying IKE_SA in state %N " + SIG_IKE(DOWN_SUCCESS, "destroying IKE_SA in state %N " "without notification", ike_sa_state_names, this->state); break; } @@ -2073,19 +2146,19 @@ static status_t retransmit(private_ike_sa_t *this, u_int32_t message_id) this->keyingtry++; if (tries == 0 || tries > this->keyingtry) { - SIG(IKE_UP_FAILED, "peer not responding, trying again " + SIG_IKE(UP_FAILED, "peer not responding, trying again " "(%d/%d) in background ", this->keyingtry + 1, tries); reset(this); return this->task_manager->initiate(this->task_manager); } - SIG(IKE_UP_FAILED, "establishing IKE_SA failed, peer not responding"); + SIG_IKE(UP_FAILED, "establishing IKE_SA failed, peer not responding"); break; } case IKE_DELETING: - SIG(IKE_DOWN_FAILED, "proper IKE_SA delete failed, peer not responding"); + SIG_IKE(DOWN_FAILED, "proper IKE_SA delete failed, peer not responding"); break; case IKE_REKEYING: - SIG(IKE_REKEY_FAILED, "rekeying IKE_SA failed, peer not responding"); + SIG_IKE(REKEY_FAILED, "rekeying IKE_SA failed, peer not responding"); /* FALL */ default: reestablish(this); @@ -2101,24 +2174,29 @@ static status_t retransmit(private_ike_sa_t *this, u_int32_t message_id) */ static void set_auth_lifetime(private_ike_sa_t *this, u_int32_t lifetime) { - job_t *job; u_int32_t reduction = this->peer_cfg->get_over_time(this->peer_cfg); + u_int32_t reauth_time = time(NULL) + lifetime - reduction; - this->time.reauth = time(NULL) + lifetime - reduction; - job = (job_t*)rekey_ike_sa_job_create(this->ike_sa_id, TRUE); - if (lifetime < reduction) { DBG1(DBG_IKE, "received AUTH_LIFETIME of %ds, starting reauthentication", lifetime); - charon->processor->queue_job(charon->processor, job); + charon->processor->queue_job(charon->processor, + (job_t*)rekey_ike_sa_job_create(this->ike_sa_id, TRUE)); } - else + else if (this->time.reauth == 0 || this->time.reauth > reauth_time) { + this->time.reauth = reauth_time; DBG1(DBG_IKE, "received AUTH_LIFETIME of %ds, scheduling reauthentication" " in %ds", lifetime, lifetime - reduction); - charon->scheduler->schedule_job(charon->scheduler, job, - (lifetime - reduction) * 1000); + charon->scheduler->schedule_job(charon->scheduler, + (job_t*)rekey_ike_sa_job_create(this->ike_sa_id, TRUE), + (lifetime - reduction) * 1000); + } + else + { + DBG1(DBG_IKE, "received AUTH_LIFETIME of %ds, reauthentication already " + "scheduled in %ds", lifetime, this->time.reauth - time(NULL)); } } @@ -2127,7 +2205,7 @@ static void set_auth_lifetime(private_ike_sa_t *this, u_int32_t lifetime) */ static status_t roam(private_ike_sa_t *this, bool address) { - host_t *me, *other; + host_t *src; ike_mobike_t *mobike; switch (this->state) @@ -2151,21 +2229,19 @@ static status_t roam(private_ike_sa_t *this, bool address) return SUCCESS; } - /* get best address pair to use */ - other = this->other_host; - me = charon->kernel_interface->get_source_addr(charon->kernel_interface, - other); - - if (me) + /* keep existing path if possible */ + src = charon->kernel_interface->get_source_addr(charon->kernel_interface, + this->other_host, this->my_host); + if (src) { - if (me->ip_equals(me, this->my_host) && - other->ip_equals(other, this->other_host)) + if (src->ip_equals(src, this->my_host)) { - DBG2(DBG_IKE, "keeping connection path %H - %H", this->other_host, me); - me->destroy(me); + DBG2(DBG_IKE, "keeping connection path %H - %H", + src, this->other_host); + src->destroy(src); return SUCCESS; } - me->destroy(me); + src->destroy(src); } /* update addresses with mobike, if supported ... */ @@ -2177,7 +2253,7 @@ static status_t roam(private_ike_sa_t *this, bool address) this->task_manager->queue_task(this->task_manager, (task_t*)mobike); return this->task_manager->initiate(this->task_manager); } - DBG1(DBG_IKE, "reauthenticating IKE_SA due address change"); + DBG1(DBG_IKE, "reauthenticating IKE_SA due to address change"); /* ... reauth if not */ return reauth(this); } @@ -2453,11 +2529,13 @@ static void destroy(private_ike_sa_t *this) DESTROY_IF(this->server_reflexive_host); chunk_free(&this->connect_id); #endif /* ME */ + free(this->nat_detection_dest.ptr); DESTROY_IF(this->my_host); DESTROY_IF(this->other_host); DESTROY_IF(this->my_id); DESTROY_IF(this->other_id); + DESTROY_IF(this->eap_identity); DESTROY_IF(this->ike_cfg); DESTROY_IF(this->peer_cfg); @@ -2502,6 +2580,8 @@ ike_sa_t * ike_sa_create(ike_sa_id_t *ike_sa_id) this->public.set_my_id = (void (*)(ike_sa_t*,identification_t*)) set_my_id; this->public.get_other_id = (identification_t* (*)(ike_sa_t*)) get_other_id; this->public.set_other_id = (void (*)(ike_sa_t*,identification_t*)) set_other_id; + this->public.get_eap_identity = (identification_t* (*)(ike_sa_t*)) get_eap_identity; + this->public.set_eap_identity = (void (*)(ike_sa_t*,identification_t*)) set_eap_identity; this->public.enable_extension = (void(*)(ike_sa_t*, ike_extension_t extension))enable_extension; this->public.supports_extension = (bool(*)(ike_sa_t*, ike_extension_t extension))supports_extension; this->public.set_condition = (void (*)(ike_sa_t*, ike_condition_t,bool)) set_condition; @@ -2511,6 +2591,7 @@ ike_sa_t * ike_sa_create(ike_sa_id_t *ike_sa_id) this->public.is_ike_initiator = (bool (*)(ike_sa_t*))is_ike_initiator; this->public.create_additional_address_iterator = (iterator_t*(*)(ike_sa_t*))create_additional_address_iterator; this->public.add_additional_address = (void(*)(ike_sa_t*, host_t *host))add_additional_address; + this->public.has_mapping_changed = (bool(*)(ike_sa_t*, chunk_t hash))has_mapping_changed; this->public.retransmit = (status_t (*)(ike_sa_t *, u_int32_t)) retransmit; this->public.delete = (status_t (*)(ike_sa_t*))delete_; this->public.destroy = (void (*)(ike_sa_t*))destroy; @@ -2560,6 +2641,7 @@ ike_sa_t * ike_sa_create(ike_sa_id_t *ike_sa_id) this->other_host = host_create_from_string("0.0.0.0", IKEV2_UDP_PORT); this->my_id = identification_create_from_encoding(ID_ANY, chunk_empty); this->other_id = identification_create_from_encoding(ID_ANY, chunk_empty); + this->eap_identity = NULL; this->extensions = 0; this->conditions = 0; this->selected_proposal = NULL; @@ -2572,6 +2654,8 @@ ike_sa_t * ike_sa_create(ike_sa_id_t *ike_sa_id) this->skp_build = chunk_empty; this->child_prf = NULL; this->state = IKE_CREATED; + this->keepalive_interval = lib->settings->get_time(lib->settings, + "charon.keep_alive", KEEPALIVE_INTERVAL); this->time.inbound = this->time.outbound = time(NULL); this->time.established = 0; this->time.rekey = 0; @@ -2587,6 +2671,7 @@ ike_sa_t * ike_sa_create(ike_sa_id_t *ike_sa_id) this->other_virtual_ip = NULL; this->dns_servers = linked_list_create(); this->additional_addresses = linked_list_create(); + this->nat_detection_dest = chunk_empty; this->pending_updates = 0; this->keyingtry = 0; this->ike_initiator = FALSE; diff --git a/src/charon/sa/ike_sa.h b/src/charon/sa/ike_sa.h index 0935f5d6b..717d41647 100644 --- a/src/charon/sa/ike_sa.h +++ b/src/charon/sa/ike_sa.h @@ -15,7 +15,7 @@ * or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License * for more details. * - * $Id: ike_sa.h 4086 2008-06-22 11:24:33Z andreas $ + * $Id: ike_sa.h 4368 2008-10-06 13:37:04Z martin $ */ /** @@ -330,6 +330,22 @@ struct ike_sa_t { void (*set_other_id) (ike_sa_t *this, identification_t *other); /** + * Get the peers EAP identity. + * + * The EAP identity is exchanged in a EAP-Identity exchange. + * + * @return identification, NULL if none set + */ + identification_t* (*get_eap_identity) (ike_sa_t *this); + + /** + * Set the peer's EAP identity. + * + * @param id identification + */ + void (*set_eap_identity) (ike_sa_t *this, identification_t *id); + + /** * Get the config used to setup this IKE_SA. * * @return ike_config @@ -391,6 +407,14 @@ struct ike_sa_t { iterator_t* (*create_additional_address_iterator)(ike_sa_t *this); /** + * Check if mappings have changed on a NAT for our source address. + * + * @param hash received DESTINATION_IP hash + * @return TRUE if mappings have changed + */ + bool (*has_mapping_changed)(ike_sa_t *this, chunk_t hash); + + /** * Enable an extension the peer supports. * * If support for an IKE extension is detected, this method is called diff --git a/src/charon/sa/ike_sa_manager.c b/src/charon/sa/ike_sa_manager.c index 9c1b2d413..bd7b84c6f 100644 --- a/src/charon/sa/ike_sa_manager.c +++ b/src/charon/sa/ike_sa_manager.c @@ -13,7 +13,7 @@ * or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License * for more details. * - * $Id: ike_sa_manager.c 4044 2008-06-06 15:05:54Z martin $ + * $Id: ike_sa_manager.c 4234 2008-07-30 14:15:08Z martin $ */ #include <pthread.h> @@ -80,6 +80,16 @@ struct entry_t { host_t *other; /** + * own identity, required for duplicate checking + */ + identification_t *my_id; + + /** + * remote identity, required for duplicate checking + */ + identification_t *other_id; + + /** * message ID currently processing, if any */ u_int32_t message_id; @@ -95,6 +105,8 @@ static status_t entry_destroy(entry_t *this) this->ike_sa_id->destroy(this->ike_sa_id); chunk_free(&this->init_hash); DESTROY_IF(this->other); + DESTROY_IF(this->my_id); + DESTROY_IF(this->other_id); free(this); return SUCCESS; } @@ -116,6 +128,8 @@ static entry_t *entry_create(ike_sa_id_t *ike_sa_id) this->message_id = -1; this->init_hash = chunk_empty; this->other = NULL; + this->my_id = NULL; + this->other_id = NULL; /* ike_sa_id is always cloned */ this->ike_sa_id = ike_sa_id->clone(ike_sa_id); @@ -157,6 +171,11 @@ struct private_ike_sa_manager_t { * SHA1 hasher for IKE_SA_INIT retransmit detection */ hasher_t *hasher; + + /** + * reuse existing IKE_SAs in checkout_by_config + */ + bool reuse_ikesa; }; /** @@ -504,7 +523,7 @@ static ike_sa_t* checkout_by_config(private_ike_sa_manager_t *this, pthread_mutex_lock(&(this->mutex)); - if (my_host && other_host) + if (my_host && other_host && this->reuse_ikesa) { enumerator = this->ike_sa_list->create_enumerator(this->ike_sa_list); while (enumerator->enumerate(enumerator, &entry)) @@ -721,10 +740,13 @@ static ike_sa_t* checkout_duplicate(private_ike_sa_manager_t *this, { /* self is not a duplicate */ continue; } - if (wait_for_entry(this, entry)) - { - if (me->equals(me, entry->ike_sa->get_my_id(entry->ike_sa)) && - other->equals(other, entry->ike_sa->get_other_id(entry->ike_sa))) + if (entry->my_id && me->equals(me, entry->my_id) && + entry->other_id && other->equals(other, entry->other_id)) + { + /* we are sure that the other entry is not calling + * checkout_duplicate here, as the identities in entry would not + * have been set yet. Otherwise we would risk a deadlock. */ + if (wait_for_entry(this, entry)) { duplicate = entry->ike_sa; entry->checked_out = TRUE; @@ -784,6 +806,7 @@ static status_t checkin(private_ike_sa_manager_t *this, ike_sa_t *ike_sa) entry_t *entry; ike_sa_id_t *ike_sa_id; host_t *other; + identification_t *my_id, *other_id; ike_sa_id = ike_sa->get_id(ike_sa); @@ -806,6 +829,21 @@ static status_t checkin(private_ike_sa_manager_t *this, ike_sa_t *ike_sa) DESTROY_IF(entry->other); entry->other = other->clone(other); } + /* apply identities for diplicate test */ + my_id = ike_sa->get_my_id(ike_sa); + other_id = ike_sa->get_other_id(ike_sa); + if (!entry->my_id || + entry->my_id->get_type(entry->my_id) == ID_ANY) + { + DESTROY_IF(entry->my_id); + entry->my_id = my_id->clone(my_id); + } + if (!entry->other_id || + entry->other_id->get_type(entry->other_id) == ID_ANY) + { + DESTROY_IF(entry->other_id); + entry->other_id = other_id->clone(other_id); + } DBG2(DBG_MGR, "check-in of IKE_SA successful."); pthread_cond_signal(&(entry->condvar)); retval = SUCCESS; @@ -1009,6 +1047,8 @@ ike_sa_manager_t *ike_sa_manager_create() } this->ike_sa_list = linked_list_create(); pthread_mutex_init(&this->mutex, NULL); + this->reuse_ikesa = lib->settings->get_bool(lib->settings, + "charon.reuse_ikesa", TRUE); return &this->public; } diff --git a/src/charon/sa/task_manager.c b/src/charon/sa/task_manager.c index e453fff00..25089477b 100644 --- a/src/charon/sa/task_manager.c +++ b/src/charon/sa/task_manager.c @@ -13,7 +13,7 @@ * or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License * for more details. * - * $Id: task_manager.c 3666 2008-03-26 18:40:19Z tobias $ + * $Id: task_manager.c 4320 2008-09-02 14:02:40Z martin $ */ #include "task_manager.h" @@ -159,22 +159,22 @@ static void flush(private_task_manager_t *this) switch (task->get_type(task)) { case IKE_AUTH: - SIG(IKE_UP_FAILED, "establishing IKE_SA failed"); + SIG_IKE(UP_FAILED, "establishing IKE_SA failed"); break; case IKE_DELETE: - SIG(IKE_DOWN_FAILED, "IKE_SA deleted"); + SIG_IKE(DOWN_FAILED, "IKE_SA deleted"); break; case IKE_REKEY: - SIG(IKE_REKEY_FAILED, "rekeying IKE_SA failed"); + SIG_IKE(REKEY_FAILED, "rekeying IKE_SA failed"); break; case CHILD_CREATE: - SIG(CHILD_UP_FAILED, "establishing CHILD_SA failed"); + SIG_CHD(UP_FAILED, NULL, "establishing CHILD_SA failed"); break; case CHILD_DELETE: - SIG(CHILD_DOWN_FAILED, "deleting CHILD_SA failed"); + SIG_CHD(DOWN_FAILED, NULL, "deleting CHILD_SA failed"); break; case CHILD_REKEY: - SIG(IKE_REKEY_FAILED, "rekeying CHILD_SA failed"); + SIG_IKE(REKEY_FAILED, "rekeying CHILD_SA failed"); break; default: break; @@ -775,6 +775,8 @@ static status_t process_request(private_task_manager_t *this, case UNACCEPTABLE_ADDRESSES: case UNEXPECTED_NAT_DETECTED: case COOKIE2: + case NAT_DETECTION_SOURCE_IP: + case NAT_DETECTION_DESTINATION_IP: task = (task_t*)ike_mobike_create( this->ike_sa, FALSE); break; diff --git a/src/charon/sa/tasks/child_create.c b/src/charon/sa/tasks/child_create.c index 4638da03e..bddca621b 100644 --- a/src/charon/sa/tasks/child_create.c +++ b/src/charon/sa/tasks/child_create.c @@ -14,7 +14,7 @@ * or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License * for more details. * - * $Id: child_create.c 3920 2008-05-08 16:19:11Z tobias $ + * $Id: child_create.c 4358 2008-09-25 13:56:23Z tobias $ */ #include "child_create.h" @@ -26,6 +26,7 @@ #include <encoding/payloads/ts_payload.h> #include <encoding/payloads/nonce_payload.h> #include <encoding/payloads/notify_payload.h> +#include <processing/jobs/delete_ike_sa_job.h> typedef struct private_child_create_t private_child_create_t; @@ -98,7 +99,7 @@ struct private_child_create_t { /** * mode the new CHILD_SA uses (transport/tunnel/beet) */ - mode_t mode; + ipsec_mode_t mode; /** * IPComp transform to use @@ -198,12 +199,12 @@ static status_t select_and_install(private_child_create_t *this, bool no_dh) if (this->proposals == NULL) { - SIG(CHILD_UP_FAILED, "SA payload missing in message"); + SIG_CHD(UP_FAILED, this->child_sa, "SA payload missing in message"); return FAILED; } if (this->tsi == NULL || this->tsr == NULL) { - SIG(CHILD_UP_FAILED, "TS payloads missing in message"); + SIG_CHD(UP_FAILED, this->child_sa, "TS payloads missing in message"); return NOT_FOUND; } @@ -231,7 +232,7 @@ static status_t select_and_install(private_child_create_t *this, bool no_dh) no_dh); if (this->proposal == NULL) { - SIG(CHILD_UP_FAILED, "no acceptable proposal found"); + SIG_CHD(UP_FAILED, this->child_sa, "no acceptable proposal found"); return FAILED; } @@ -242,15 +243,15 @@ static status_t select_and_install(private_child_create_t *this, bool no_dh) if (this->proposal->get_algorithm(this->proposal, DIFFIE_HELLMAN_GROUP, &group, NULL)) { - SIG(CHILD_UP_FAILED, "DH group %N inacceptable, requesting %N", - diffie_hellman_group_names, this->dh_group, - diffie_hellman_group_names, group); + SIG_CHD(UP_FAILED, this->child_sa, "DH group %N inacceptable, " + "requesting %N", diffie_hellman_group_names, this->dh_group, + diffie_hellman_group_names, group); this->dh_group = group; return INVALID_ARG; } else { - SIG(CHILD_UP_FAILED, "no acceptable proposal found"); + SIG_CHD(UP_FAILED, this->child_sa, "no acceptable proposal found"); return FAILED; } } @@ -278,7 +279,7 @@ static status_t select_and_install(private_child_create_t *this, bool no_dh) { my_ts->destroy_offset(my_ts, offsetof(traffic_selector_t, destroy)); other_ts->destroy_offset(other_ts, offsetof(traffic_selector_t, destroy)); - SIG(CHILD_UP_FAILED, "no acceptable traffic selectors found"); + SIG_CHD(UP_FAILED, this->child_sa, "no acceptable traffic selectors found"); return NOT_FOUND; } @@ -330,7 +331,7 @@ static status_t select_and_install(private_child_create_t *this, bool no_dh) { if (this->dh->get_shared_secret(this->dh, &secret) != SUCCESS) { - SIG(CHILD_UP_FAILED, "DH exchange incomplete"); + SIG_CHD(UP_FAILED, this->child_sa, "DH exchange incomplete"); return FAILED; } DBG3(DBG_IKE, "DH secret %B", &secret); @@ -340,7 +341,6 @@ static status_t select_and_install(private_child_create_t *this, bool no_dh) { seed = chunk_cata("cc", nonce_i, nonce_r); } - prf_plus = prf_plus_create(this->ike_sa->get_child_prf(this->ike_sa), seed); if (this->ipcomp != IPCOMP_NONE) { @@ -348,6 +348,16 @@ static status_t select_and_install(private_child_create_t *this, bool no_dh) this->other_cpi); } + status = this->child_sa->add_policies(this->child_sa, my_ts, other_ts, + this->mode, this->proposal->get_protocol(this->proposal)); + if (status != SUCCESS) + { + SIG_CHD(UP_FAILED, this->child_sa, + "unable to install IPsec policies (SPD) in kernel"); + return NOT_FOUND; + } + + prf_plus = prf_plus_create(this->ike_sa->get_child_prf(this->ike_sa), seed); if (this->initiator) { status = this->child_sa->update(this->child_sa, this->proposal, @@ -362,18 +372,10 @@ static status_t select_and_install(private_child_create_t *this, bool no_dh) if (status != SUCCESS) { - SIG(CHILD_UP_FAILED, "unable to install IPsec SA (SAD) in kernel"); + SIG_CHD(UP_FAILED, this->child_sa, + "unable to install IPsec SA (SAD) in kernel"); return FAILED; } - - status = this->child_sa->add_policies(this->child_sa, my_ts, other_ts, - this->mode); - - if (status != SUCCESS) - { - SIG(CHILD_UP_FAILED, "unable to install IPsec policies (SPD) in kernel"); - return NOT_FOUND; - } /* add to IKE_SA, and remove from task */ this->child_sa->set_state(this->child_sa, CHILD_INSTALLED); this->ike_sa->add_child_sa(this->ike_sa, this->child_sa); @@ -440,29 +442,30 @@ static void build_payloads(private_child_create_t *this, message_t *message) /** * Adds an IPCOMP_SUPPORTED notify to the message, if possible */ -static void build_ipcomp_supported_notify(private_child_create_t *this, message_t *message) +static void build_ipcomp_supported_notify(private_child_create_t *this, + message_t *message) { + u_int16_t cpi; + u_int8_t tid; + if (this->ike_sa->has_condition(this->ike_sa, COND_NAT_ANY)) { - DBG1(DBG_IKE, "IPComp is not supported if either peer is natted, IPComp is disabled"); + DBG1(DBG_IKE, "IPComp is not supported if either peer is natted, " + "IPComp disabled"); this->ipcomp = IPCOMP_NONE; return; } - u_int16_t cpi = this->child_sa->get_my_cpi(this->child_sa); + cpi = this->child_sa->allocate_cpi(this->child_sa); + tid = this->ipcomp; if (cpi) { - chunk_t cpi_chunk, tid_chunk, data; - u_int8_t tid = this->ipcomp; - cpi_chunk = chunk_from_thing(cpi); - tid_chunk = chunk_from_thing(tid); - data = chunk_cat("cc", cpi_chunk, tid_chunk); - message->add_notify(message, FALSE, IPCOMP_SUPPORTED, data); - chunk_free(&data); + message->add_notify(message, FALSE, IPCOMP_SUPPORTED, + chunk_cata("cc", chunk_from_thing(cpi), chunk_from_thing(tid))); } else { - DBG1(DBG_IKE, "unable to allocate a CPI from kernel, IPComp is disabled"); + DBG1(DBG_IKE, "unable to allocate a CPI from kernel, IPComp disabled"); this->ipcomp = IPCOMP_NONE; } } @@ -587,7 +590,16 @@ static status_t build_i(private_child_create_t *this, message_t *message) break; } - SIG(CHILD_UP_START, "establishing CHILD_SA"); + if (this->reqid) + { + SIG_CHD(UP_START, NULL, "establishing CHILD_SA %s{%d}", + this->config->get_name(this->config), this->reqid); + } + else + { + SIG_CHD(UP_START, NULL, "establishing CHILD_SA %s", + this->config->get_name(this->config)); + } /* reuse virtual IP if we already have one */ me = this->ike_sa->get_virtual_ip(this->ike_sa, TRUE); @@ -638,7 +650,8 @@ static status_t build_i(private_child_create_t *this, message_t *message) if (this->child_sa->alloc(this->child_sa, this->proposals) != SUCCESS) { - SIG(CHILD_UP_FAILED, "unable to allocate SPIs from kernel"); + SIG_CHD(UP_FAILED, this->child_sa, + "unable to allocate SPIs from kernel"); return FAILED; } @@ -720,10 +733,31 @@ static status_t process_r(private_child_create_t *this, message_t *message) } /** + * handle CHILD_SA setup failure + */ +static void handle_child_sa_failure(private_child_create_t *this, + message_t *message) +{ + if (message->get_exchange_type(message) == IKE_AUTH && + lib->settings->get_bool(lib->settings, + "charon.close_ike_on_child_failure", FALSE)) + { + /* we delay the delete for 100ms, as the IKE_AUTH response must arrive + * first */ + DBG1(DBG_IKE, "closing IKE_SA due CHILD_SA setup failure"); + charon->scheduler->schedule_job(charon->scheduler, (job_t*) + delete_ike_sa_job_create(this->ike_sa->get_id(this->ike_sa), TRUE), + 100); + } +} + +/** * Implementation of task_t.build for responder */ static status_t build_r(private_child_create_t *this, message_t *message) { + payload_t *payload; + iterator_t *iterator; bool no_dh = TRUE; switch (message->get_exchange_type(message)) @@ -733,7 +767,8 @@ static status_t build_r(private_child_create_t *this, message_t *message) case CREATE_CHILD_SA: if (generate_nonce(&this->my_nonce) != SUCCESS) { - message->add_notify(message, FALSE, NO_PROPOSAL_CHOSEN, chunk_empty); + message->add_notify(message, FALSE, NO_PROPOSAL_CHOSEN, + chunk_empty); return SUCCESS; } no_dh = FALSE; @@ -750,19 +785,47 @@ static status_t build_r(private_child_create_t *this, message_t *message) if (this->ike_sa->get_state(this->ike_sa) == IKE_REKEYING) { - SIG(CHILD_UP_FAILED, "unable to create CHILD_SA while rekeying IKE_SA"); + SIG_CHD(UP_FAILED, NULL, + "unable to create CHILD_SA while rekeying IKE_SA"); message->add_notify(message, TRUE, NO_ADDITIONAL_SAS, chunk_empty); return SUCCESS; } if (this->config == NULL) { - SIG(CHILD_UP_FAILED, "traffic selectors %#R=== %#R inacceptable", + SIG_CHD(UP_FAILED, NULL, "traffic selectors %#R=== %#R inacceptable", this->tsr, this->tsi); message->add_notify(message, FALSE, TS_UNACCEPTABLE, chunk_empty); + handle_child_sa_failure(this, message); return SUCCESS; } + /* check if ike_config_t included non-critical error notifies */ + iterator = message->get_payload_iterator(message); + while (iterator->iterate(iterator, (void**)&payload)) + { + if (payload->get_type(payload) == NOTIFY) + { + notify_payload_t *notify = (notify_payload_t*)payload; + + switch (notify->get_notify_type(notify)) + { + case INTERNAL_ADDRESS_FAILURE: + case FAILED_CP_REQUIRED: + { + SIG_CHD(UP_FAILED, NULL, "configuration payload negotation " + "failed, no CHILD_SA built"); + iterator->destroy(iterator); + handle_child_sa_failure(this, message); + return SUCCESS; + } + default: + break; + } + } + } + iterator->destroy(iterator); + this->child_sa = child_sa_create( this->ike_sa->get_my_host(this->ike_sa), this->ike_sa->get_other_host(this->ike_sa), @@ -770,14 +833,16 @@ static status_t build_r(private_child_create_t *this, message_t *message) this->ike_sa->get_other_id(this->ike_sa), this->config, this->reqid, this->ike_sa->has_condition(this->ike_sa, COND_NAT_ANY)); - if (this->config->use_ipcomp(this->config) && this->ipcomp_received != IPCOMP_NONE) + if (this->config->use_ipcomp(this->config) && + this->ipcomp_received != IPCOMP_NONE) { this->ipcomp = this->ipcomp_received; build_ipcomp_supported_notify(this, message); } else if (this->ipcomp_received != IPCOMP_NONE) { - DBG1(DBG_IKE, "received IPCOMP_SUPPORTED notify but IPComp is disabled, ignoring"); + DBG1(DBG_IKE, "received %N notify but IPComp is disabled, ignoring", + notify_type_names, IPCOMP_SUPPORTED); } switch (select_and_install(this, no_dh)) @@ -786,24 +851,33 @@ static status_t build_r(private_child_create_t *this, message_t *message) break; case NOT_FOUND: message->add_notify(message, FALSE, TS_UNACCEPTABLE, chunk_empty); + handle_child_sa_failure(this, message); return SUCCESS; case INVALID_ARG: { u_int16_t group = htons(this->dh_group); message->add_notify(message, FALSE, INVALID_KE_PAYLOAD, chunk_from_thing(group)); + handle_child_sa_failure(this, message); return SUCCESS; } case FAILED: default: message->add_notify(message, FALSE, NO_PROPOSAL_CHOSEN, chunk_empty); + handle_child_sa_failure(this, message); return SUCCESS; } build_payloads(this, message); - SIG(CHILD_UP_SUCCESS, "CHILD_SA '%s' established successfully", - this->child_sa->get_name(this->child_sa)); + SIG_CHD(UP_SUCCESS, this->child_sa, "CHILD_SA %s{%d} established " + "with SPIs %.8x_i %.8x_o and TS %#R=== %#R", + this->child_sa->get_name(this->child_sa), + this->child_sa->get_reqid(this->child_sa), + ntohl(this->child_sa->get_spi(this->child_sa, TRUE)), + ntohl(this->child_sa->get_spi(this->child_sa, FALSE)), + this->child_sa->get_traffic_selectors(this->child_sa, TRUE), + this->child_sa->get_traffic_selectors(this->child_sa, FALSE)); return SUCCESS; } @@ -855,9 +929,10 @@ static status_t process_i(private_child_create_t *this, message_t *message) case TS_UNACCEPTABLE: case INVALID_SELECTORS: { - SIG(CHILD_UP_FAILED, "received %N notify, no CHILD_SA built", - notify_type_names, type); + SIG_CHD(UP_FAILED, this->child_sa, "received %N notify, " + "no CHILD_SA built", notify_type_names, type); iterator->destroy(iterator); + handle_child_sa_failure(this, message); /* an error in CHILD_SA creation is not critical */ return SUCCESS; } @@ -888,8 +963,9 @@ static status_t process_i(private_child_create_t *this, message_t *message) if (this->ipcomp == IPCOMP_NONE && this->ipcomp_received != IPCOMP_NONE) { - SIG(CHILD_UP_FAILED, "received an IPCOMP_SUPPORTED notify but we did not " - "send one previously, no CHILD_SA built"); + SIG_CHD(UP_FAILED, this->child_sa, "received an IPCOMP_SUPPORTED notify" + " but we did not send one previously, no CHILD_SA built"); + handle_child_sa_failure(this, message); return SUCCESS; } else if (this->ipcomp != IPCOMP_NONE && this->ipcomp_received == IPCOMP_NONE) @@ -900,15 +976,26 @@ static status_t process_i(private_child_create_t *this, message_t *message) } else if (this->ipcomp != IPCOMP_NONE && this->ipcomp != this->ipcomp_received) { - SIG(CHILD_UP_FAILED, "received an IPCOMP_SUPPORTED notify for a transform " - "we did not propose, no CHILD_SA built"); + SIG_CHD(UP_FAILED, this->child_sa, "received an IPCOMP_SUPPORTED notify" + " for a transform we did not propose, no CHILD_SA built"); + handle_child_sa_failure(this, message); return SUCCESS; } if (select_and_install(this, no_dh) == SUCCESS) { - SIG(CHILD_UP_SUCCESS, "CHILD_SA '%s' established successfully", - this->child_sa->get_name(this->child_sa)); + SIG_CHD(UP_SUCCESS, this->child_sa, "CHILD_SA %s{%d} established " + "with SPIs %.8x_i %.8x_o and TS %#R=== %#R", + this->child_sa->get_name(this->child_sa), + this->child_sa->get_reqid(this->child_sa), + ntohl(this->child_sa->get_spi(this->child_sa, TRUE)), + ntohl(this->child_sa->get_spi(this->child_sa, FALSE)), + this->child_sa->get_traffic_selectors(this->child_sa, TRUE), + this->child_sa->get_traffic_selectors(this->child_sa, FALSE)); + } + else + { + handle_child_sa_failure(this, message); } return SUCCESS; } diff --git a/src/charon/sa/tasks/child_delete.c b/src/charon/sa/tasks/child_delete.c index 4156f9704..a3c74dc90 100644 --- a/src/charon/sa/tasks/child_delete.c +++ b/src/charon/sa/tasks/child_delete.c @@ -12,7 +12,7 @@ * or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License * for more details. * - * $Id: child_delete.c 3802 2008-04-14 08:17:18Z martin $ + * $Id: child_delete.c 4366 2008-10-03 16:01:14Z martin $ */ #include "child_delete.h" @@ -44,6 +44,11 @@ struct private_child_delete_t { bool initiator; /** + * wheter to enforce delete action policy + */ + bool check_delete_action; + + /** * CHILD_SAs which get deleted */ linked_list_t *child_sas; @@ -54,16 +59,17 @@ struct private_child_delete_t { */ static void build_payloads(private_child_delete_t *this, message_t *message) { - iterator_t *iterator; delete_payload_t *ah = NULL, *esp = NULL; - u_int32_t spi; + iterator_t *iterator; child_sa_t *child_sa; iterator = this->child_sas->create_iterator(this->child_sas, TRUE); while (iterator->iterate(iterator, (void**)&child_sa)) { - spi = child_sa->get_spi(child_sa, TRUE); - switch (child_sa->get_protocol(child_sa)) + protocol_id_t protocol = child_sa->get_protocol(child_sa); + u_int32_t spi = child_sa->get_spi(child_sa, TRUE); + + switch (protocol) { case PROTO_ESP: if (esp == NULL) @@ -72,6 +78,8 @@ static void build_payloads(private_child_delete_t *this, message_t *message) message->add_payload(message, (payload_t*)esp); } esp->add_spi(esp, spi); + DBG1(DBG_IKE, "sending DELETE for %N CHILD_SA with SPI %.8x", + protocol_id_names, protocol, ntohl(spi)); break; case PROTO_AH: if (ah == NULL) @@ -80,6 +88,8 @@ static void build_payloads(private_child_delete_t *this, message_t *message) message->add_payload(message, (payload_t*)ah); } ah->add_spi(ah, spi); + DBG1(DBG_IKE, "sending DELETE for %N CHILD_SA with SPI %.8x", + protocol_id_names, protocol, ntohl(spi)); break; default: break; @@ -119,11 +129,11 @@ static void process_payloads(private_child_delete_t *this, message_t *message) *spi, FALSE); if (child_sa == NULL) { - DBG1(DBG_IKE, "received DELETE for %N CHILD_SA with SPI 0x%x, " + DBG1(DBG_IKE, "received DELETE for %N CHILD_SA with SPI %.8x, " "but no such SA", protocol_id_names, protocol, ntohl(*spi)); continue; } - DBG2(DBG_IKE, "received DELETE for %N CHILD_SA with SPI 0x%x", + DBG1(DBG_IKE, "received DELETE for %N CHILD_SA with SPI %.8x", protocol_id_names, protocol, ntohl(*spi)); switch (child_sa->get_state(child_sa)) @@ -139,6 +149,11 @@ static void process_payloads(private_child_delete_t *this, message_t *message) protocol, *spi); continue; } + case CHILD_INSTALLED: + if (!this->initiator) + { /* reestablish installed children if required */ + this->check_delete_action = TRUE; + } default: break; } @@ -171,7 +186,7 @@ static status_t destroy_and_reestablish(private_child_delete_t *this) child_cfg = child_sa->get_config(child_sa); child_cfg->get_ref(child_cfg); this->ike_sa->destroy_child_sa(this->ike_sa, protocol, spi); - if (!this->initiator) + if (this->check_delete_action) { /* enforce child_cfg policy if deleted passively */ switch (child_cfg->get_close_action(child_cfg)) { @@ -207,9 +222,14 @@ static void log_children(private_child_delete_t *this) iterator = this->child_sas->create_iterator(this->child_sas, TRUE); while (iterator->iterate(iterator, (void**)&child_sa)) { - SIG(CHILD_DOWN_START, "closing CHILD_SA %#R=== %#R", - child_sa->get_traffic_selectors(child_sa, TRUE), - child_sa->get_traffic_selectors(child_sa, FALSE)); + SIG_CHD(DOWN_START, child_sa, "closing CHILD_SA %s{%d} " + "with SPIs %.8x_i %.8x_o and TS %#R=== %#R", + child_sa->get_name(child_sa), + child_sa->get_reqid(child_sa), + ntohl(child_sa->get_spi(child_sa, TRUE)), + ntohl(child_sa->get_spi(child_sa, FALSE)), + child_sa->get_traffic_selectors(child_sa, TRUE), + child_sa->get_traffic_selectors(child_sa, FALSE)); } iterator->destroy(iterator); } @@ -234,7 +254,7 @@ static status_t process_i(private_child_delete_t *this, message_t *message) this->child_sas = linked_list_create(); process_payloads(this, message); - SIG(CHILD_DOWN_SUCCESS, "CHILD_SA closed"); + SIG_CHD(DOWN_SUCCESS, NULL, "CHILD_SA closed"); return destroy_and_reestablish(this); } @@ -258,7 +278,7 @@ static status_t build_r(private_child_delete_t *this, message_t *message) { build_payloads(this, message); } - SIG(CHILD_DOWN_SUCCESS, "CHILD_SA closed"); + SIG_CHD(DOWN_SUCCESS, NULL, "CHILD_SA closed"); return destroy_and_reestablish(this); } @@ -285,6 +305,7 @@ static child_sa_t* get_child(private_child_delete_t *this) */ static void migrate(private_child_delete_t *this, ike_sa_t *ike_sa) { + this->check_delete_action = FALSE; this->ike_sa = ike_sa; this->child_sas->destroy(this->child_sas); @@ -313,6 +334,7 @@ child_delete_t *child_delete_create(ike_sa_t *ike_sa, child_sa_t *child_sa) this->public.task.destroy = (void(*)(task_t*))destroy; this->ike_sa = ike_sa; + this->check_delete_action = FALSE; this->child_sas = linked_list_create(); if (child_sa != NULL) diff --git a/src/charon/sa/tasks/ike_auth.c b/src/charon/sa/tasks/ike_auth.c index fd5012ee6..51f37f1b0 100644 --- a/src/charon/sa/tasks/ike_auth.c +++ b/src/charon/sa/tasks/ike_auth.c @@ -13,7 +13,7 @@ * or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License * for more details * - * $Id: ike_auth.c 4051 2008-06-10 09:08:27Z tobias $ + * $Id: ike_auth.c 4276 2008-08-22 10:44:51Z martin $ */ #include "ike_auth.h" @@ -29,7 +29,6 @@ #include <sa/authenticators/eap_authenticator.h> - typedef struct private_ike_auth_t private_ike_auth_t; /** @@ -151,6 +150,44 @@ static bool check_uniqueness(private_ike_auth_t *this) } /** + * get the authentication class of a config + */ +auth_class_t get_auth_class(peer_cfg_t *config) +{ + auth_class_t *class; + auth_info_t *auth_info; + + auth_info = config->get_auth(config); + if (auth_info->get_item(auth_info, AUTHN_AUTH_CLASS, (void**)&class)) + { + return *class; + } + /* fallback to pubkey authentication */ + return AUTH_CLASS_PUBKEY; +} + +/** + * get the eap type/vendor + */ +static eap_type_t get_eap_type(peer_cfg_t *config, u_int32_t *vendor) +{ + auth_info_t *auth_info; + u_int *ptr; + + *vendor = 0; + auth_info = config->get_auth(config); + if (auth_info->get_item(auth_info, AUTHN_EAP_VENDOR, (void**)&ptr)) + { + *vendor = *ptr; + } + if (auth_info->get_item(auth_info, AUTHN_EAP_TYPE, (void**)&ptr)) + { + return *ptr; + } + return EAP_NAK; +} + +/** * build the AUTH payload */ static status_t build_auth(private_ike_auth_t *this, message_t *message) @@ -158,23 +195,21 @@ static status_t build_auth(private_ike_auth_t *this, message_t *message) authenticator_t *auth; auth_payload_t *auth_payload; peer_cfg_t *config; - config_auth_method_t method; status_t status; /* create own authenticator and add auth payload */ config = this->ike_sa->get_peer_cfg(this->ike_sa); if (!config) { - SIG(IKE_UP_FAILED, "unable to authenticate, no peer config found"); + SIG_IKE(UP_FAILED, "unable to authenticate, no peer config found"); return FAILED; } - method = config->get_auth_method(config); - auth = authenticator_create(this->ike_sa, method); + auth = authenticator_create_from_class(this->ike_sa, get_auth_class(config)); if (auth == NULL) { - SIG(IKE_UP_FAILED, "configured authentication method %N not supported", - config_auth_method_names, method); + SIG_IKE(UP_FAILED, "configured authentication class %N not supported", + auth_class_names, get_auth_class(config)); return FAILED; } @@ -183,7 +218,7 @@ static status_t build_auth(private_ike_auth_t *this, message_t *message) auth->destroy(auth); if (status != SUCCESS) { - SIG(IKE_UP_FAILED, "generating authentication data failed"); + SIG_IKE(UP_FAILED, "generating authentication data failed"); return FAILED; } message->add_payload(message, (payload_t*)auth_payload); @@ -208,7 +243,7 @@ static status_t build_id(private_ike_auth_t *this, message_t *message) me = config->get_my_id(config); if (me->contains_wildcards(me)) { - SIG(IKE_UP_FAILED, "negotiation of own ID failed"); + SIG_IKE(UP_FAILED, "negotiation of own ID failed"); return FAILED; } this->ike_sa->set_my_id(this->ike_sa, me->clone(me)); @@ -245,11 +280,11 @@ static status_t process_auth(private_ike_auth_t *this, message_t *message) } auth_method = auth_payload->get_auth_method(auth_payload); - auth = authenticator_create_from_auth_payload(this->ike_sa, auth_payload); - + auth = authenticator_create_from_method(this->ike_sa, + auth_payload->get_auth_method(auth_payload)); if (auth == NULL) { - SIG(IKE_UP_FAILED, "authentication method %N used by '%D' not " + SIG_IKE(UP_FAILED, "authentication method %N used by '%D' not " "supported", auth_method_names, auth_method, this->ike_sa->get_other_id(this->ike_sa)); return NOT_SUPPORTED; @@ -259,7 +294,7 @@ static status_t process_auth(private_ike_auth_t *this, message_t *message) auth->destroy(auth); if (status != SUCCESS) { - SIG(IKE_UP_FAILED, "authentication of '%D' with %N failed", + SIG_IKE(UP_FAILED, "authentication of '%D' with %N failed", this->ike_sa->get_other_id(this->ike_sa), auth_method_names, auth_method); return FAILED; @@ -280,7 +315,7 @@ static status_t process_id(private_ike_auth_t *this, message_t *message) if ((this->initiator && idr == NULL) || (!this->initiator && idi == NULL)) { - SIG(IKE_UP_FAILED, "ID payload missing in message"); + SIG_IKE(UP_FAILED, "ID payload missing in message"); return FAILED; } @@ -290,7 +325,7 @@ static status_t process_id(private_ike_auth_t *this, message_t *message) req = this->ike_sa->get_other_id(this->ike_sa); if (!id->matches(id, req)) { - SIG(IKE_UP_FAILED, "peer ID '%D' unacceptable, '%D' required", id, req); + SIG_IKE(UP_FAILED, "peer ID '%D' unacceptable, '%D' required", id, req); id->destroy(id); return FAILED; } @@ -367,7 +402,7 @@ static status_t build_auth_eap(private_ike_auth_t *this, message_t *message) if (auth->build(auth, this->my_packet->get_data(this->my_packet), this->other_nonce, &auth_payload) != SUCCESS) { - SIG(IKE_UP_FAILED, "generating authentication data failed"); + SIG_IKE(UP_FAILED, "generating authentication data failed"); if (!this->initiator) { message->add_notify(message, TRUE, AUTHENTICATION_FAILED, chunk_empty); @@ -378,12 +413,13 @@ static status_t build_auth_eap(private_ike_auth_t *this, message_t *message) if (!this->initiator) { this->ike_sa->set_state(this->ike_sa, IKE_ESTABLISHED); - SIG(IKE_UP_SUCCESS, "IKE_SA '%s' established between %H[%D]...[%D]%H", + SIG_IKE(UP_SUCCESS, "IKE_SA %s[%d] established between %H[%D]...%H[%D]", this->ike_sa->get_name(this->ike_sa), + this->ike_sa->get_unique_id(this->ike_sa), this->ike_sa->get_my_host(this->ike_sa), this->ike_sa->get_my_id(this->ike_sa), - this->ike_sa->get_other_id(this->ike_sa), - this->ike_sa->get_other_host(this->ike_sa)); + this->ike_sa->get_other_host(this->ike_sa), + this->ike_sa->get_other_id(this->ike_sa)); return SUCCESS; } return NEED_MORE; @@ -412,9 +448,9 @@ static status_t process_auth_eap(private_ike_auth_t *this, message_t *message) if (!this->peer_authenticated) { - SIG(IKE_UP_FAILED, "authentication of '%D' with %N failed", + SIG_IKE(UP_FAILED, "authentication of '%D' with %N failed", this->ike_sa->get_other_id(this->ike_sa), - auth_method_names, AUTH_EAP); + auth_class_names, AUTH_CLASS_EAP); if (this->initiator) { return FAILED; @@ -424,12 +460,13 @@ static status_t process_auth_eap(private_ike_auth_t *this, message_t *message) if (this->initiator) { this->ike_sa->set_state(this->ike_sa, IKE_ESTABLISHED); - SIG(IKE_UP_SUCCESS, "IKE_SA '%s' established between %H[%D]...[%D]%H", + SIG_IKE(UP_SUCCESS, "IKE_SA %s[%d] established between %H[%D]...%H[%D]", this->ike_sa->get_name(this->ike_sa), + this->ike_sa->get_unique_id(this->ike_sa), this->ike_sa->get_my_host(this->ike_sa), this->ike_sa->get_my_id(this->ike_sa), - this->ike_sa->get_other_id(this->ike_sa), - this->ike_sa->get_other_host(this->ike_sa)); + this->ike_sa->get_other_host(this->ike_sa), + this->ike_sa->get_other_id(this->ike_sa)); return SUCCESS; } return NEED_MORE; @@ -445,7 +482,7 @@ static status_t process_eap_i(private_ike_auth_t *this, message_t *message) eap = (eap_payload_t*)message->get_payload(message, EXTENSIBLE_AUTHENTICATION); if (eap == NULL) { - SIG(IKE_UP_FAILED, "EAP payload missing"); + SIG_IKE(UP_FAILED, "EAP payload missing"); return FAILED; } switch (this->eap_auth->process(this->eap_auth, eap, &eap)) @@ -461,7 +498,7 @@ static status_t process_eap_i(private_ike_auth_t *this, message_t *message) return NEED_MORE; default: this->eap_payload = NULL; - SIG(IKE_UP_FAILED, "failed to authenticate against '%D' using EAP", + SIG_IKE(UP_FAILED, "failed to authenticate against '%D' using EAP", this->ike_sa->get_other_id(this->ike_sa)); return FAILED; } @@ -496,7 +533,7 @@ static status_t build_eap_r(private_ike_auth_t *this, message_t *message) if (this->eap_payload == NULL) { - SIG(IKE_UP_FAILED, "EAP payload missing"); + SIG_IKE(UP_FAILED, "EAP payload missing"); return FAILED; } @@ -511,9 +548,9 @@ static status_t build_eap_r(private_ike_auth_t *this, message_t *message) this->public.task.process = (status_t(*)(task_t*,message_t*))process_auth_eap; break; default: - SIG(IKE_UP_FAILED, "authentication of '%D' with %N failed", + SIG_IKE(UP_FAILED, "authentication of '%D' with %N failed", this->ike_sa->get_other_id(this->ike_sa), - auth_method_names, AUTH_EAP); + auth_class_names, AUTH_CLASS_EAP); status = FAILED; break; } @@ -539,7 +576,7 @@ static status_t build_i(private_ike_auth_t *this, message_t *message) } config = this->ike_sa->get_peer_cfg(this->ike_sa); - if (config->get_auth_method(config) == CONF_AUTH_EAP) + if (get_auth_class(config) == AUTH_CLASS_EAP) { this->eap_auth = eap_authenticator_create(this->ike_sa); } @@ -579,13 +616,14 @@ static status_t process_r(private_ike_auth_t *this, message_t *message) case NOT_FOUND: /* use EAP if no AUTH payload found */ this->ike_sa->set_condition(this->ike_sa, COND_EAP_AUTHENTICATED, TRUE); - this->eap_auth = eap_authenticator_create(this->ike_sa); break; default: return NEED_MORE; } config = charon->backends->get_peer_cfg(charon->backends, + this->ike_sa->get_my_host(this->ike_sa), + this->ike_sa->get_other_host(this->ike_sa), this->ike_sa->get_my_id(this->ike_sa), this->ike_sa->get_other_id(this->ike_sa), this->ike_sa->get_other_auth(this->ike_sa)); @@ -594,7 +632,10 @@ static status_t process_r(private_ike_auth_t *this, message_t *message) this->ike_sa->set_peer_cfg(this->ike_sa, config); config->destroy(config); } - + if (!this->peer_authenticated) + { + this->eap_auth = eap_authenticator_create(this->ike_sa); + } return NEED_MORE; } @@ -624,7 +665,7 @@ static status_t build_r(private_ike_auth_t *this, message_t *message) config = this->ike_sa->get_peer_cfg(this->ike_sa); if (config == NULL) { - SIG(IKE_UP_FAILED, "no matching config found for '%D'...'%D'", + SIG_IKE(UP_FAILED, "no matching config found for '%D'...'%D'", this->ike_sa->get_my_id(this->ike_sa), this->ike_sa->get_other_id(this->ike_sa)); message->add_notify(message, TRUE, AUTHENTICATION_FAILED, chunk_empty); @@ -648,23 +689,24 @@ static status_t build_r(private_ike_auth_t *this, message_t *message) if (this->peer_authenticated) { this->ike_sa->set_state(this->ike_sa, IKE_ESTABLISHED); - SIG(IKE_UP_SUCCESS, "IKE_SA '%s' established between %H[%D]...[%D]%H", + SIG_IKE(UP_SUCCESS, "IKE_SA %s[%d] established between %H[%D]...%H[%D]", this->ike_sa->get_name(this->ike_sa), + this->ike_sa->get_unique_id(this->ike_sa), this->ike_sa->get_my_host(this->ike_sa), this->ike_sa->get_my_id(this->ike_sa), - this->ike_sa->get_other_id(this->ike_sa), - this->ike_sa->get_other_host(this->ike_sa)); + this->ike_sa->get_other_host(this->ike_sa), + this->ike_sa->get_other_id(this->ike_sa)); return SUCCESS; } /* initiate EAP authenitcation */ - eap_type = config->get_eap_type(config, &eap_vendor); + eap_type = get_eap_type(config, &eap_vendor); status = this->eap_auth->initiate(this->eap_auth, eap_type, eap_vendor, &eap_payload); message->add_payload(message, (payload_t*)eap_payload); if (status != NEED_MORE) { - SIG(IKE_UP_FAILED, "unable to initiate EAP authentication"); + SIG_IKE(UP_FAILED, "unable to initiate EAP authentication"); return FAILED; } @@ -724,7 +766,7 @@ static status_t process_i(private_ike_auth_t *this, message_t *message) { if (type < 16383) { - SIG(IKE_UP_FAILED, "received %N notify error", + SIG_IKE(UP_FAILED, "received %N notify error", notify_type_names, type); iterator->destroy(iterator); return FAILED; @@ -756,17 +798,18 @@ static status_t process_i(private_ike_auth_t *this, message_t *message) auth = this->ike_sa->get_other_auth(this->ike_sa); if (!auth->complies(auth, config->get_auth(config))) { - SIG(IKE_UP_FAILED, "authorization of '%D' for config %s failed", + SIG_IKE(UP_FAILED, "authorization of '%D' for config %s failed", this->ike_sa->get_other_id(this->ike_sa), config->get_name(config)); return FAILED; } this->ike_sa->set_state(this->ike_sa, IKE_ESTABLISHED); - SIG(IKE_UP_SUCCESS, "IKE_SA '%s' established between %H[%D]...[%D]%H", + SIG_IKE(UP_SUCCESS, "IKE_SA %s[%d] established between %H[%D]...%H[%D]", this->ike_sa->get_name(this->ike_sa), + this->ike_sa->get_unique_id(this->ike_sa), this->ike_sa->get_my_host(this->ike_sa), this->ike_sa->get_my_id(this->ike_sa), - this->ike_sa->get_other_id(this->ike_sa), - this->ike_sa->get_other_host(this->ike_sa)); + this->ike_sa->get_other_host(this->ike_sa), + this->ike_sa->get_other_id(this->ike_sa)); return SUCCESS; } diff --git a/src/charon/sa/tasks/ike_cert_post.c b/src/charon/sa/tasks/ike_cert_post.c index 184868b28..cb533236e 100644 --- a/src/charon/sa/tasks/ike_cert_post.c +++ b/src/charon/sa/tasks/ike_cert_post.c @@ -13,7 +13,7 @@ * or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License * for more details. * - * $Id: ike_cert_post.c 4051 2008-06-10 09:08:27Z tobias $ + * $Id: ike_cert_post.c 4276 2008-08-22 10:44:51Z martin $ */ #include "ike_cert_post.h" @@ -98,6 +98,11 @@ static cert_payload_t *build_cert_payload(private_ike_cert_post_t *this, certifi } /** + * from ike_auth.c + */ +auth_class_t get_auth_class(peer_cfg_t *config); + +/** * add certificates to message */ static void build_certs(private_ike_cert_post_t *this, message_t *message) @@ -105,7 +110,7 @@ static void build_certs(private_ike_cert_post_t *this, message_t *message) peer_cfg_t *peer_cfg; peer_cfg = this->ike_sa->get_peer_cfg(this->ike_sa); - if (peer_cfg && peer_cfg->get_auth_method(peer_cfg) == CONF_AUTH_PUBKEY) + if (peer_cfg && get_auth_class(peer_cfg) == AUTH_CLASS_PUBKEY) { switch (peer_cfg->get_cert_policy(peer_cfg)) { diff --git a/src/charon/sa/tasks/ike_cert_pre.c b/src/charon/sa/tasks/ike_cert_pre.c index 3568a214e..353b76a22 100644 --- a/src/charon/sa/tasks/ike_cert_pre.c +++ b/src/charon/sa/tasks/ike_cert_pre.c @@ -13,7 +13,7 @@ * or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License * for more details. * - * $Id: ike_cert_pre.c 3852 2008-04-18 21:27:08Z andreas $ + * $Id: ike_cert_pre.c 4285 2008-08-26 05:15:34Z andreas $ */ #include "ike_cert_pre.h" @@ -320,11 +320,10 @@ static void add_certreq_payload(message_t *message, certreq_payload_t **reqp, static void build_certreqs(private_ike_cert_pre_t *this, message_t *message) { ike_cfg_t *ike_cfg; + peer_cfg_t *peer_cfg; enumerator_t *enumerator; certificate_t *cert; - auth_info_t *auth; bool restricted = FALSE; - auth_item_t item; certreq_payload_t *x509_req = NULL; ike_cfg = this->ike_sa->get_ike_cfg(this->ike_sa); @@ -332,19 +331,43 @@ static void build_certreqs(private_ike_cert_pre_t *this, message_t *message) { return; } - auth = this->ike_sa->get_other_auth(this->ike_sa); /* check if we require a specific CA for that peer */ - enumerator = auth->create_item_enumerator(auth); - while (enumerator->enumerate(enumerator, &item, &cert)) + peer_cfg = this->ike_sa->get_peer_cfg(this->ike_sa); + if (peer_cfg) { - if (item == AUTHN_CA_CERT) + void *ptr; + identification_t *id; + auth_item_t item; + auth_info_t *auth = peer_cfg->get_auth(peer_cfg); + enumerator_t *auth_enumerator = auth->create_item_enumerator(auth); + + while (auth_enumerator->enumerate(auth_enumerator, &item, &ptr)) { - restricted = TRUE; - add_certreq_payload(message, &x509_req, cert); + switch (item) + { + case AUTHZ_CA_CERT: + cert = (certificate_t *)ptr; + add_certreq_payload(message, &x509_req, cert); + restricted = TRUE; + break; + case AUTHZ_CA_CERT_NAME: + id = (identification_t *)ptr; + enumerator = charon->credentials->create_cert_enumerator( + charon->credentials, CERT_ANY, KEY_ANY, id, TRUE); + while (enumerator->enumerate(enumerator, &cert, TRUE)) + { + add_certreq_payload(message, &x509_req, cert); + restricted = TRUE; + } + enumerator->destroy(enumerator); + break; + default: + break; + } } + auth_enumerator->destroy(auth_enumerator); } - enumerator->destroy(enumerator); if (!restricted) { diff --git a/src/charon/sa/tasks/ike_config.c b/src/charon/sa/tasks/ike_config.c index c31e62750..e89f381d3 100644 --- a/src/charon/sa/tasks/ike_config.c +++ b/src/charon/sa/tasks/ike_config.c @@ -13,7 +13,7 @@ * or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License * for more details. * - * $Id: ike_config.c 3800 2008-04-14 07:18:16Z martin $ + * $Id: ike_config.c 4129 2008-07-01 06:36:52Z martin $ */ #include "ike_config.h" @@ -315,7 +315,10 @@ static status_t build_r(private_ike_config_t *this, message_t *message) } if (ip == NULL) { - DBG1(DBG_IKE, "not assigning a virtual IP to peer"); + DBG1(DBG_IKE, "no virtual IP found, sending %N", + notify_type_names, INTERNAL_ADDRESS_FAILURE); + message->add_notify(message, FALSE, INTERNAL_ADDRESS_FAILURE, + chunk_empty); return SUCCESS; } DBG1(DBG_IKE, "assigning virtual IP %H to peer", ip); diff --git a/src/charon/sa/tasks/ike_delete.c b/src/charon/sa/tasks/ike_delete.c index aa7950ef7..295f908cb 100644 --- a/src/charon/sa/tasks/ike_delete.c +++ b/src/charon/sa/tasks/ike_delete.c @@ -12,7 +12,7 @@ * or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License * for more details. * - * $Id: ike_delete.c 3802 2008-04-14 08:17:18Z martin $ + * $Id: ike_delete.c 4211 2008-07-23 18:46:34Z andreas $ */ #include "ike_delete.h" @@ -56,11 +56,22 @@ static status_t build_i(private_ike_delete_t *this, message_t *message) { delete_payload_t *delete_payload; + SIG_IKE(DOWN_START, "deleting IKE_SA %s[%d] between %H[%D]...%H[%D]", + this->ike_sa->get_name(this->ike_sa), + this->ike_sa->get_unique_id(this->ike_sa), + this->ike_sa->get_my_host(this->ike_sa), + this->ike_sa->get_my_id(this->ike_sa), + this->ike_sa->get_other_host(this->ike_sa), + this->ike_sa->get_other_id(this->ike_sa)); + delete_payload = delete_payload_create(PROTO_IKE); message->add_payload(message, (payload_t*)delete_payload); - this->ike_sa->set_state(this->ike_sa, IKE_DELETING); - + + DBG1(DBG_IKE, "sending DELETE for IKE_SA %s[%d]", + this->ike_sa->get_name(this->ike_sa), + this->ike_sa->get_unique_id(this->ike_sa)); + return NEED_MORE; } @@ -74,16 +85,26 @@ static status_t process_i(private_ike_delete_t *this, message_t *message) } /** - * Implementation of task_t.process for initiator + * Implementation of task_t.process for responder */ static status_t process_r(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 */ + DBG1(DBG_IKE, "received DELETE for IKE_SA %s[%d]", + this->ike_sa->get_name(this->ike_sa), + this->ike_sa->get_unique_id(this->ike_sa)); + SIG_IKE(DOWN_START, "deleting IKE_SA %s[%d] between %H[%D]...%H[%D]", + this->ike_sa->get_name(this->ike_sa), + this->ike_sa->get_unique_id(this->ike_sa), + this->ike_sa->get_my_host(this->ike_sa), + this->ike_sa->get_my_id(this->ike_sa), + this->ike_sa->get_other_host(this->ike_sa), + this->ike_sa->get_other_id(this->ike_sa)); + switch (this->ike_sa->get_state(this->ike_sa)) { case IKE_ESTABLISHED: - DBG1(DBG_IKE, "deleting IKE_SA on request"); this->ike_sa->set_state(this->ike_sa, IKE_DELETING); this->ike_sa->reestablish(this->ike_sa); break; @@ -102,9 +123,11 @@ static status_t process_r(private_ike_delete_t *this, message_t *message) */ static status_t build_r(private_ike_delete_t *this, message_t *message) { + SIG_IKE(DOWN_SUCCESS, "IKE_SA deleted"); + if (this->simultaneous) { - /* wait for peers response for our delete request, but set a timeout */ + /* wait for peer's response for our delete request, but set a timeout */ return SUCCESS; } /* completed, delete IKE_SA by returning FAILED */ diff --git a/src/charon/sa/tasks/ike_init.c b/src/charon/sa/tasks/ike_init.c index 7def3a556..609b37a39 100644 --- a/src/charon/sa/tasks/ike_init.c +++ b/src/charon/sa/tasks/ike_init.c @@ -14,7 +14,7 @@ * or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License * for more details. * - * $Id: ike_init.c 4086 2008-06-22 11:24:33Z andreas $ + * $Id: ike_init.c 4206 2008-07-22 17:10:10Z andreas $ */ #include "ike_init.h" @@ -26,6 +26,7 @@ #include <encoding/payloads/sa_payload.h> #include <encoding/payloads/ke_payload.h> #include <encoding/payloads/nonce_payload.h> +#include <encoding/payloads/vendor_id_payload.h> /** maximum retries to do with cookies/other dh groups */ #define MAX_RETRIES 5 @@ -203,9 +204,17 @@ static void process_payloads(private_ike_init_t *this, message_t *message) case NONCE: { nonce_payload_t *nonce_payload = (nonce_payload_t*)payload; + this->other_nonce = nonce_payload->get_nonce(nonce_payload); break; } + case VENDOR_ID: + { + vendor_id_payload_t *vendor_id = (vendor_id_payload_t*)payload; + chunk_t vid = vendor_id->get_data(vendor_id); + + DBG1(DBG_ENC, "received vendor id: %#B", &vid); + } default: break; } @@ -221,14 +230,15 @@ static status_t build_i(private_ike_init_t *this, message_t *message) rng_t *rng; this->config = this->ike_sa->get_ike_cfg(this->ike_sa); - SIG(IKE_UP_START, "initiating IKE_SA '%s' to %H", + SIG_IKE(UP_START, "initiating IKE_SA %s[%d] to %H", this->ike_sa->get_name(this->ike_sa), + this->ike_sa->get_unique_id(this->ike_sa), this->ike_sa->get_other_host(this->ike_sa)); this->ike_sa->set_state(this->ike_sa, IKE_CONNECTING); if (this->retry++ >= MAX_RETRIES) { - SIG(IKE_UP_FAILED, "giving up after %d retries", MAX_RETRIES); + SIG_IKE(UP_FAILED, "giving up after %d retries", MAX_RETRIES); return FAILED; } @@ -239,7 +249,7 @@ static status_t build_i(private_ike_init_t *this, message_t *message) this->dh = lib->crypto->create_dh(lib->crypto, this->dh_group); if (this->dh == NULL) { - SIG(IKE_UP_FAILED, "configured DH group %N not supported", + SIG_IKE(UP_FAILED, "configured DH group %N not supported", diffie_hellman_group_names, this->dh_group); return FAILED; } @@ -251,7 +261,7 @@ static status_t build_i(private_ike_init_t *this, message_t *message) rng = lib->crypto->create_rng(lib->crypto, RNG_WEAK); if (!rng) { - SIG(IKE_UP_FAILED, "error generating nonce"); + SIG_IKE(UP_FAILED, "error generating nonce"); return FAILED; } rng->allocate_bytes(rng, NONCE_SIZE, &this->my_nonce); @@ -286,7 +296,7 @@ static status_t process_r(private_ike_init_t *this, message_t *message) rng_t *rng; this->config = this->ike_sa->get_ike_cfg(this->ike_sa); - SIG(IKE_UP_START, "%H is initiating an IKE_SA", + SIG_IKE(UP_START, "%H is initiating an IKE_SA", message->get_source(message)); this->ike_sa->set_state(this->ike_sa, IKE_CONNECTING); @@ -366,7 +376,7 @@ static status_t build_r(private_ike_init_t *this, message_t *message) if (this->proposal == NULL || this->other_nonce.len == 0 || this->my_nonce.len == 0) { - SIG(IKE_UP_FAILED, "received proposals inacceptable"); + SIG_IKE(UP_FAILED, "received proposals inacceptable"); message->add_notify(message, TRUE, NO_PROPOSAL_CHOSEN, chunk_empty); return FAILED; } @@ -380,7 +390,7 @@ static status_t build_r(private_ike_init_t *this, message_t *message) if (this->proposal->get_algorithm(this->proposal, DIFFIE_HELLMAN_GROUP, &group, NULL)) { - SIG(CHILD_UP_FAILED, "DH group %N inacceptable, requesting %N", + SIG_CHD(UP_FAILED, NULL, "DH group %N inacceptable, requesting %N", diffie_hellman_group_names, this->dh_group, diffie_hellman_group_names, group); this->dh_group = group; @@ -390,7 +400,7 @@ static status_t build_r(private_ike_init_t *this, message_t *message) } else { - SIG(IKE_UP_FAILED, "no acceptable proposal found"); + SIG_IKE(UP_FAILED, "no acceptable proposal found"); } return FAILED; } @@ -420,7 +430,7 @@ static status_t build_r(private_ike_init_t *this, message_t *message) } if (status != SUCCESS) { - SIG(IKE_UP_FAILED, "key derivation failed"); + SIG_IKE(UP_FAILED, "key derivation failed"); message->add_notify(message, TRUE, NO_PROPOSAL_CHOSEN, chunk_empty); return FAILED; } @@ -495,7 +505,7 @@ static status_t process_i(private_ike_init_t *this, message_t *message) { if (type < 16383) { - SIG(IKE_UP_FAILED, "received %N notify error", + SIG_IKE(UP_FAILED, "received %N notify error", notify_type_names, type); iterator->destroy(iterator); return FAILED; @@ -515,7 +525,7 @@ static status_t process_i(private_ike_init_t *this, message_t *message) if (this->proposal == NULL || this->other_nonce.len == 0 || this->my_nonce.len == 0) { - SIG(IKE_UP_FAILED, "peer's proposal selection invalid"); + SIG_IKE(UP_FAILED, "peer's proposal selection invalid"); return FAILED; } @@ -523,7 +533,7 @@ static status_t process_i(private_ike_init_t *this, message_t *message) !this->proposal->has_dh_group(this->proposal, this->dh_group) || this->dh->get_shared_secret(this->dh, &secret) != SUCCESS) { - SIG(IKE_UP_FAILED, "peer's DH group selection invalid"); + SIG_IKE(UP_FAILED, "peer's DH group selection invalid"); return FAILED; } @@ -552,7 +562,7 @@ static status_t process_i(private_ike_init_t *this, message_t *message) } if (status != SUCCESS) { - SIG(IKE_UP_FAILED, "key derivation failed"); + SIG_IKE(UP_FAILED, "key derivation failed"); return FAILED; } diff --git a/src/charon/sa/tasks/ike_me.c b/src/charon/sa/tasks/ike_me.c index 2d7c64d70..a203dee58 100644 --- a/src/charon/sa/tasks/ike_me.c +++ b/src/charon/sa/tasks/ike_me.c @@ -12,7 +12,7 @@ * or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License * for more details. * - * $Id: ike_me.c 3806 2008-04-15 05:56:35Z martin $ + * $Id: ike_me.c 4355 2008-09-25 07:56:58Z tobias $ */ #include "ike_me.h" @@ -128,7 +128,7 @@ static void add_endpoints_to_message(message_t *message, linked_list_t *endpoint */ static void gather_and_add_endpoints(private_ike_me_t *this, message_t *message) { - iterator_t *iterator; + enumerator_t *enumerator; host_t *addr, *host; u_int16_t port; @@ -136,9 +136,9 @@ static void gather_and_add_endpoints(private_ike_me_t *this, message_t *message) host = this->ike_sa->get_my_host(this->ike_sa); port = host->get_port(host); - iterator = charon->kernel_interface->create_address_iterator( - charon->kernel_interface); - while (iterator->iterate(iterator, (void**)&addr)) + enumerator = charon->kernel_interface->create_address_enumerator( + charon->kernel_interface, FALSE, FALSE); + while (enumerator->enumerate(enumerator, (void**)&addr)) { host = addr->clone(addr); host->set_port(host, port); @@ -148,7 +148,7 @@ static void gather_and_add_endpoints(private_ike_me_t *this, message_t *message) host->destroy(host); } - iterator->destroy(iterator); + enumerator->destroy(enumerator); host = this->ike_sa->get_server_reflexive_host(this->ike_sa); if (host) @@ -461,7 +461,8 @@ static status_t process_i(private_ike_me_t *this, message_t *message) this->ike_sa->set_server_reflexive_host(this->ike_sa, endpoint->clone(endpoint)); } /* FIXME: what if it failed? e.g. AUTH failure */ - SIG(CHILD_UP_SUCCESS, "established mediation connection without CHILD_SA successfully"); + SIG_CHD(UP_SUCCESS, NULL, "established mediation connection " + "without CHILD_SA successfully"); break; } @@ -641,7 +642,8 @@ static status_t build_r_ms(private_ike_me_t *this, message_t *message) /* FIXME: we actually must delete any existing IKE_SAs with the same remote id */ this->ike_sa->act_as_mediation_server(this->ike_sa); - SIG(CHILD_UP_SUCCESS, "established mediation connection without CHILD_SA successfully"); + SIG_CHD(UP_SUCCESS, NULL, "established mediation connection " + "without CHILD_SA successfully"); break; } diff --git a/src/charon/sa/tasks/ike_mobike.c b/src/charon/sa/tasks/ike_mobike.c index 23c68b9e9..f6ee3f6ad 100644 --- a/src/charon/sa/tasks/ike_mobike.c +++ b/src/charon/sa/tasks/ike_mobike.c @@ -12,7 +12,7 @@ * or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License * for more details. * - * $Id: ike_mobike.c 4006 2008-05-23 15:43:42Z martin $ + * $Id: ike_mobike.c 4394 2008-10-09 08:25:11Z martin $ */ #include "ike_mobike.h" @@ -117,8 +117,19 @@ static void process_payloads(private_ike_mobike_t *this, message_t *message) { case MOBIKE_SUPPORTED: { - DBG1(DBG_IKE, "peer supports MOBIKE"); - this->ike_sa->enable_extension(this->ike_sa, EXT_MOBIKE); + peer_cfg_t *peer_cfg; + + peer_cfg = this->ike_sa->get_peer_cfg(this->ike_sa); + if (!this->initiator && + peer_cfg && !peer_cfg->use_mobike(peer_cfg)) + { + DBG1(DBG_IKE, "peer supports MOBIKE, but disabled in config"); + } + else + { + DBG1(DBG_IKE, "peer supports MOBIKE"); + this->ike_sa->enable_extension(this->ike_sa, EXT_MOBIKE); + } break; } case COOKIE2: @@ -177,15 +188,15 @@ static void process_payloads(private_ike_mobike_t *this, message_t *message) */ static void build_address_list(private_ike_mobike_t *this, message_t *message) { - iterator_t *iterator; + enumerator_t *enumerator; host_t *host, *me; notify_type_t type; bool additional = FALSE; me = this->ike_sa->get_my_host(this->ike_sa); - iterator = charon->kernel_interface->create_address_iterator( - charon->kernel_interface); - while (iterator->iterate(iterator, (void**)&host)) + enumerator = charon->kernel_interface->create_address_enumerator( + charon->kernel_interface, FALSE, FALSE); + while (enumerator->enumerate(enumerator, (void**)&host)) { if (me->ip_equals(me, host)) { /* "ADDITIONAL" means do not include IKE_SAs host */ @@ -209,7 +220,7 @@ static void build_address_list(private_ike_mobike_t *this, message_t *message) { message->add_notify(message, FALSE, NO_ADDITIONAL_ADDRESSES, chunk_empty); } - iterator->destroy(iterator); + enumerator->destroy(enumerator); } /** @@ -266,7 +277,7 @@ static void transmit(private_ike_mobike_t *this, packet_t *packet) other_old = this->ike_sa->get_other_host(this->ike_sa); me = charon->kernel_interface->get_source_addr( - charon->kernel_interface, other_old); + charon->kernel_interface, other_old, NULL); if (me) { me->set_port(me, me->ip_equals(me, me_old) ? @@ -278,7 +289,7 @@ static void transmit(private_ike_mobike_t *this, packet_t *packet) while (iterator->iterate(iterator, (void**)&other)) { me = charon->kernel_interface->get_source_addr( - charon->kernel_interface, other); + charon->kernel_interface, other, NULL); if (me) { if (me->get_family(me) != other->get_family(other)) @@ -318,6 +329,24 @@ static status_t build_i(private_ike_mobike_t *this, message_t *message) } else if (message->get_exchange_type(message) == INFORMATIONAL) { + host_t *old, *new; + + /* we check if the existing address is still valid */ + old = message->get_source(message); + new = charon->kernel_interface->get_source_addr(charon->kernel_interface, + message->get_destination(message), old); + if (new) + { + if (!new->ip_equals(new, old)) + { + new->set_port(new, old->get_port(old)); + message->set_source(message, new); + } + else + { + new->destroy(new); + } + } if (this->update) { message->add_notify(message, FALSE, UPDATE_SA_ADDRESSES, chunk_empty); @@ -423,7 +452,7 @@ static status_t process_i(private_ike_mobike_t *this, message_t *message) return SUCCESS; } if (this->cookie2.ptr) - { /* check cookie if we included none */ + { /* check cookie if we included one */ chunk_t cookie2; cookie2 = this->cookie2; @@ -444,6 +473,13 @@ static status_t process_i(private_ike_mobike_t *this, message_t *message) if (this->natd) { this->natd->task.process(&this->natd->task, message); + if (this->natd->has_mapping_changed(this->natd)) + { + /* force an update if mappings have changed */ + this->update = this->check = TRUE; + DBG1(DBG_IKE, "detected changes in NAT mappings, " + "initiating MOBIKE update"); + } } if (this->update) { @@ -496,6 +532,20 @@ static void roam(private_ike_mobike_t *this, bool address) } /** + * Implementation of ike_mobike_t.dpd + */ +static void dpd(private_ike_mobike_t *this) +{ + if (!this->natd) + { + this->natd = ike_natd_create(this->ike_sa, this->initiator); + } + this->address = FALSE; + this->ike_sa->set_pending_updates(this->ike_sa, + this->ike_sa->get_pending_updates(this->ike_sa) + 1); +} + +/** * Implementation of ike_mobike_t.is_probing. */ static bool is_probing(private_ike_mobike_t *this) @@ -545,6 +595,7 @@ ike_mobike_t *ike_mobike_create(ike_sa_t *ike_sa, bool initiator) private_ike_mobike_t *this = malloc_thing(private_ike_mobike_t); this->public.roam = (void(*)(ike_mobike_t*,bool))roam; + this->public.dpd = (void(*)(ike_mobike_t*))dpd; this->public.transmit = (void(*)(ike_mobike_t*,packet_t*))transmit; this->public.is_probing = (bool(*)(ike_mobike_t*))is_probing; this->public.task.get_type = (task_type_t(*)(task_t*))get_type; diff --git a/src/charon/sa/tasks/ike_mobike.h b/src/charon/sa/tasks/ike_mobike.h index 9dd29970e..f8f094456 100644 --- a/src/charon/sa/tasks/ike_mobike.h +++ b/src/charon/sa/tasks/ike_mobike.h @@ -12,7 +12,7 @@ * or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License * for more details. * - * $Id: ike_mobike.h 3589 2008-03-13 14:14:44Z martin $ + * $Id: ike_mobike.h 4368 2008-10-06 13:37:04Z martin $ */ /** @@ -55,6 +55,11 @@ struct ike_mobike_t { void (*roam)(ike_mobike_t *this, bool address); /** + * Use the task for a DPD check which detects changes in NAT mappings. + */ + void (*dpd)(ike_mobike_t *this); + + /** * Transmision hook, called by task manager. * * The task manager calls this hook whenever it transmits a packet. It diff --git a/src/charon/sa/tasks/ike_natd.c b/src/charon/sa/tasks/ike_natd.c index 69e5bac26..9e62fcbdf 100644 --- a/src/charon/sa/tasks/ike_natd.c +++ b/src/charon/sa/tasks/ike_natd.c @@ -13,7 +13,7 @@ * or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License * for more details. * - * $Id: ike_natd.c 3806 2008-04-15 05:56:35Z martin $ + * $Id: ike_natd.c 4386 2008-10-08 08:23:46Z martin $ */ #include "ike_natd.h" @@ -72,6 +72,11 @@ struct private_ike_natd_t { * Have we found a matching destination address NAT hash? */ bool dst_matched; + + /** + * whether NAT mappings for our NATed address has changed + */ + bool mapping_changed; }; @@ -192,15 +197,24 @@ static void process_payloads(private_ike_natd_t *this, message_t *message) case NAT_DETECTION_DESTINATION_IP: { this->dst_seen = TRUE; + hash = notify->get_notification_data(notify); if (!this->dst_matched) { - hash = notify->get_notification_data(notify); DBG3(DBG_IKE, "received dst_hash %B", &hash); if (chunk_equals(hash, dst_hash)) { this->dst_matched = TRUE; } } + /* RFC4555 says we should also compare against IKE_SA_INIT + * NATD payloads, but this does not work: We are running + * there at port 500, but use 4500 afterwards... */ + if (message->get_exchange_type(message) == INFORMATIONAL && + this->initiator && !this->dst_matched) + { + this->mapping_changed = this->ike_sa->has_mapping_changed( + this->ike_sa, hash); + } break; } case NAT_DETECTION_SOURCE_IP: @@ -300,7 +314,7 @@ static status_t process_i(private_ike_natd_t *this, message_t *message) static status_t build_i(private_ike_natd_t *this, message_t *message) { notify_payload_t *notify; - iterator_t *iterator; + enumerator_t *enumerator; host_t *host; if (this->hasher == NULL) @@ -327,9 +341,8 @@ static status_t build_i(private_ike_natd_t *this, message_t *message) } else { - host = charon->kernel_interface->get_source_addr( - charon->kernel_interface, - this->ike_sa->get_other_host(this->ike_sa)); + host = charon->kernel_interface->get_source_addr(charon->kernel_interface, + this->ike_sa->get_other_host(this->ike_sa), NULL); if (host) { /* 2. */ host->set_port(host, IKEV2_UDP_PORT); @@ -339,14 +352,14 @@ static status_t build_i(private_ike_natd_t *this, message_t *message) } else { /* 3. */ - iterator = charon->kernel_interface->create_address_iterator( - charon->kernel_interface); - while (iterator->iterate(iterator, (void**)&host)) + enumerator = charon->kernel_interface->create_address_enumerator( + charon->kernel_interface, FALSE, FALSE); + while (enumerator->enumerate(enumerator, (void**)&host)) { notify = build_natd_payload(this, NAT_DETECTION_SOURCE_IP, host); message->add_payload(message, (payload_t*)notify); } - iterator->destroy(iterator); + enumerator->destroy(enumerator); } } return NEED_MORE; @@ -415,6 +428,15 @@ static void migrate(private_ike_natd_t *this, ike_sa_t *ike_sa) this->dst_seen = FALSE; this->src_matched = FALSE; this->dst_matched = FALSE; + this->mapping_changed = FALSE; +} + +/** + * Implementation of ike_natd_t.has_mapping_changed + */ +static bool has_mapping_changed(private_ike_natd_t *this) +{ + return this->mapping_changed; } /** @@ -448,6 +470,8 @@ ike_natd_t *ike_natd_create(ike_sa_t *ike_sa, bool initiator) this->public.task.process = (status_t(*)(task_t*,message_t*))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); @@ -455,6 +479,7 @@ ike_natd_t *ike_natd_create(ike_sa_t *ike_sa, bool initiator) this->dst_seen = FALSE; this->src_matched = FALSE; this->dst_matched = FALSE; + this->mapping_changed = FALSE; return &this->public; } diff --git a/src/charon/sa/tasks/ike_natd.h b/src/charon/sa/tasks/ike_natd.h index d78c931d9..7e1e58bc0 100644 --- a/src/charon/sa/tasks/ike_natd.h +++ b/src/charon/sa/tasks/ike_natd.h @@ -12,7 +12,7 @@ * or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License * for more details. * - * $Id: ike_natd.h 3589 2008-03-13 14:14:44Z martin $ + * $Id: ike_natd.h 4368 2008-10-06 13:37:04Z martin $ */ /** @@ -38,6 +38,15 @@ struct ike_natd_t { * Implements the task_t interface */ task_t task; + + /** + * Check if the NAT mapping has changed for our address. + * + * MOBIKE uses NAT payloads in DPD to detect changes in the NAT mappings. + * + * @return TRUE if mappings have changed + */ + bool (*has_mapping_changed)(ike_natd_t *this); }; /** diff --git a/src/charon/sa/tasks/ike_reauth.c b/src/charon/sa/tasks/ike_reauth.c index 854e9359d..b84b2a387 100644 --- a/src/charon/sa/tasks/ike_reauth.c +++ b/src/charon/sa/tasks/ike_reauth.c @@ -12,7 +12,7 @@ * or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License * for more details. * - * $Id: ike_reauth.c 3793 2008-04-11 08:14:48Z martin $ + * $Id: ike_reauth.c 4211 2008-07-23 18:46:34Z andreas $ */ #include "ike_reauth.h" @@ -65,7 +65,8 @@ static status_t process_i(private_ike_reauth_t *this, message_t *message) /* process delete response first */ this->ike_delete->task.process(&this->ike_delete->task, message); - + SIG_IKE(DOWN_SUCCESS, "IKE_SA deleted"); + peer_cfg = this->ike_sa->get_peer_cfg(this->ike_sa); /* reauthenticate only if we have children */ diff --git a/src/charon/sa/tasks/ike_rekey.c b/src/charon/sa/tasks/ike_rekey.c index 9c0d1805c..6c4ef4354 100644 --- a/src/charon/sa/tasks/ike_rekey.c +++ b/src/charon/sa/tasks/ike_rekey.c @@ -13,7 +13,7 @@ * or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License * for more details. * - * $Id: ike_rekey.c 3589 2008-03-13 14:14:44Z martin $ + * $Id: ike_rekey.c 4211 2008-07-23 18:46:34Z andreas $ */ #include "ike_rekey.h" @@ -69,6 +69,7 @@ struct private_ike_rekey_t { static status_t build_i(private_ike_rekey_t *this, message_t *message) { peer_cfg_t *peer_cfg; + host_t *other_host; /* create new SA only on first try */ if (this->new_sa == NULL) @@ -77,7 +78,9 @@ static status_t build_i(private_ike_rekey_t *this, message_t *message) TRUE); peer_cfg = this->ike_sa->get_peer_cfg(this->ike_sa); + other_host = this->ike_sa->get_other_host(this->ike_sa); this->new_sa->set_peer_cfg(this->new_sa, peer_cfg); + this->new_sa->set_other_host(this->new_sa, other_host->clone(other_host)); this->ike_init = ike_init_create(this->new_sa, TRUE, this->ike_sa); this->ike_sa->set_state(this->ike_sa, IKE_REKEYING); } @@ -87,7 +90,7 @@ static status_t build_i(private_ike_rekey_t *this, message_t *message) } /** - * Implementation of task_t.process for initiator + * Implementation of task_t.process for responder */ static status_t process_r(private_ike_rekey_t *this, message_t *message) { @@ -149,6 +152,13 @@ static status_t build_r(private_ike_rekey_t *this, message_t *message) this->ike_sa->set_state(this->ike_sa, IKE_REKEYING); this->new_sa->set_state(this->new_sa, IKE_ESTABLISHED); + SIG_IKE(UP_SUCCESS, "IKE_SA %s[%d] established between %H[%D]...%H[%D]", + this->new_sa->get_name(this->new_sa), + this->new_sa->get_unique_id(this->new_sa), + this->ike_sa->get_my_host(this->ike_sa), + this->ike_sa->get_my_id(this->ike_sa), + this->ike_sa->get_other_host(this->ike_sa), + this->ike_sa->get_other_id(this->ike_sa)); return SUCCESS; } @@ -188,6 +198,14 @@ static status_t process_i(private_ike_rekey_t *this, message_t *message) } this->new_sa->set_state(this->new_sa, IKE_ESTABLISHED); + SIG_IKE(UP_SUCCESS, "IKE_SA %s[%d] established between %H[%D]...%H[%D]", + this->new_sa->get_name(this->new_sa), + this->new_sa->get_unique_id(this->new_sa), + this->ike_sa->get_my_host(this->ike_sa), + this->ike_sa->get_my_id(this->ike_sa), + this->ike_sa->get_other_host(this->ike_sa), + this->ike_sa->get_other_id(this->ike_sa)); + to_delete = this->ike_sa->get_id(this->ike_sa); /* check for collisions */ |