diff options
Diffstat (limited to 'src/libcharon/sa')
-rw-r--r-- | src/libcharon/sa/eap/eap_inner_method.h | 57 | ||||
-rw-r--r-- | src/libcharon/sa/ike_sa.c | 50 | ||||
-rw-r--r-- | src/libcharon/sa/ike_sa_manager.c | 76 | ||||
-rw-r--r-- | src/libcharon/sa/ikev1/task_manager_v1.c | 16 | ||||
-rw-r--r-- | src/libcharon/sa/ikev1/tasks/quick_mode.c | 4 | ||||
-rw-r--r-- | src/libcharon/sa/ikev2/task_manager_v2.c | 12 | ||||
-rw-r--r-- | src/libcharon/sa/ikev2/tasks/child_create.c | 9 | ||||
-rw-r--r-- | src/libcharon/sa/ikev2/tasks/ike_dpd.c | 10 |
8 files changed, 176 insertions, 58 deletions
diff --git a/src/libcharon/sa/eap/eap_inner_method.h b/src/libcharon/sa/eap/eap_inner_method.h new file mode 100644 index 000000000..500852965 --- /dev/null +++ b/src/libcharon/sa/eap/eap_inner_method.h @@ -0,0 +1,57 @@ +/* + * Copyright (C) 2013 Andreas Steffen + * HSR Hochschule fuer Technik Rapperswil + * + * This program is free software; you can redistribute it and/or modify it + * under the terms of the GNU General Public License as published by the + * Free Software Foundation; either version 2 of the License, or (at your + * option) any later version. See <http://www.fsf.org/copyleft/gpl.txt>. + * + * This program is distributed in the hope that it will be useful, but + * WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY + * or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License + * for more details. + */ + +/** + * @defgroup eap_inner_method eap_inner_method + * @{ @ingroup eap + */ + +#ifndef EAP_INNER_METHOD_H_ +#define EAP_INNER_METHOD_H_ + +typedef struct eap_inner_method_t eap_inner_method_t; + +#include <library.h> + +#include "eap_method.h" + +/** + * Interface of a weak inner EAP method like EAP-TNC or PT-EAP + * that must be encapsulated in a strong TLS-based EAP method + */ +struct eap_inner_method_t { + + /* + * Public EAP method interface + */ + eap_method_t eap_method; + + /* + * Get type of outer EAP authentication method + * + * @return outer EAP authentication type + */ + eap_type_t (*get_auth_type)(eap_inner_method_t *this); + + /* + * Set type of outer EAP Client/Server authentication + * + * @param type outer EAP authentication type + */ + void (*set_auth_type)(eap_inner_method_t *this, eap_type_t type); + +}; + +#endif /** EAP_INNER_METHOD_H_ @}*/ diff --git a/src/libcharon/sa/ike_sa.c b/src/libcharon/sa/ike_sa.c index 4029db11d..0157599c1 100644 --- a/src/libcharon/sa/ike_sa.c +++ b/src/libcharon/sa/ike_sa.c @@ -900,7 +900,7 @@ METHOD(ike_sa_t, update_hosts, void, else { /* update our address in any case */ - if (!me->equals(me, this->my_host)) + if (force && !me->equals(me, this->my_host)) { set_my_host(this, me->clone(me)); update = TRUE; @@ -909,7 +909,8 @@ METHOD(ike_sa_t, update_hosts, void, if (!other->equals(other, this->other_host)) { /* update others address if we are NOT NATed */ - if (force || !has_condition(this, COND_NAT_HERE)) + if ((has_condition(this, COND_NAT_THERE) && + !has_condition(this, COND_NAT_HERE)) || force ) { set_other_host(this, other->clone(other)); update = TRUE; @@ -939,14 +940,38 @@ METHOD(ike_sa_t, update_hosts, void, } } +/** + * Set configured DSCP value on packet + */ +static void set_dscp(private_ike_sa_t *this, packet_t *packet) +{ + ike_cfg_t *ike_cfg; + + /* prefer IKE config on peer_cfg, as its selection is more accurate + * then the initial IKE config */ + if (this->peer_cfg) + { + ike_cfg = this->peer_cfg->get_ike_cfg(this->peer_cfg); + } + else + { + ike_cfg = this->ike_cfg; + } + if (ike_cfg) + { + packet->set_dscp(packet, ike_cfg->get_dscp(ike_cfg)); + } +} + METHOD(ike_sa_t, generate_message, status_t, private_ike_sa_t *this, message_t *message, packet_t **packet) { status_t status; if (message->is_encoded(message)) - { /* already done */ + { /* already encoded in task, but set DSCP value */ *packet = message->get_packet(message); + set_dscp(this, *packet); return SUCCESS; } this->stats[STAT_OUTBOUND] = time_monotonic(NULL); @@ -955,6 +980,7 @@ METHOD(ike_sa_t, generate_message, status_t, status = message->generate(message, this->keymat, packet); if (status == SUCCESS) { + set_dscp(this, *packet); charon->bus->message(charon->bus, message, FALSE, FALSE); } return status; @@ -1225,24 +1251,6 @@ METHOD(ike_sa_t, process_message, status_t, { /* do not handle messages in passive state */ return FAILED; } - switch (message->get_exchange_type(message)) - { - case ID_PROT: - case AGGRESSIVE: - case IKE_SA_INIT: - case IKE_AUTH: - if (this->state != IKE_CREATED && - this->state != IKE_CONNECTING && - message->get_first_payload_type(message) != FRAGMENT_V1) - { - DBG1(DBG_IKE, "ignoring %N in established IKE_SA state", - exchange_type_names, message->get_exchange_type(message)); - return FAILED; - } - break; - default: - break; - } if (message->get_major_version(message) != this->version) { DBG1(DBG_IKE, "ignoring %N IKEv%u exchange on %N SA", diff --git a/src/libcharon/sa/ike_sa_manager.c b/src/libcharon/sa/ike_sa_manager.c index 2ac8c3123..4fbc4da8e 100644 --- a/src/libcharon/sa/ike_sa_manager.c +++ b/src/libcharon/sa/ike_sa_manager.c @@ -108,9 +108,9 @@ struct entry_t { identification_t *other_id; /** - * message ID currently processing, if any + * message ID or hash of currently processing message, -1 if none */ - u_int32_t message_id; + u_int32_t processing; }; /** @@ -135,23 +135,12 @@ static status_t entry_destroy(entry_t *this) */ static entry_t *entry_create() { - entry_t *this = malloc_thing(entry_t); - - this->waiting_threads = 0; - this->condvar = condvar_create(CONDVAR_TYPE_DEFAULT); - - /* we set checkout flag when we really give it out */ - this->checked_out = FALSE; - this->driveout_new_threads = FALSE; - this->driveout_waiting_threads = FALSE; - this->message_id = -1; - this->init_hash = chunk_empty; - this->other = NULL; - this->half_open = FALSE; - this->my_id = NULL; - this->other_id = NULL; - this->ike_sa_id = NULL; - this->ike_sa = NULL; + entry_t *this; + + INIT(this, + .condvar = condvar_create(CONDVAR_TYPE_DEFAULT), + .processing = -1, + ); return this; } @@ -1171,6 +1160,20 @@ METHOD(ike_sa_manager_t, checkout_new, ike_sa_t*, return ike_sa; } +/** + * Get the message ID or message hash to detect early retransmissions + */ +static u_int32_t get_message_id_or_hash(message_t *message) +{ + /* Use the message ID, or the message hash in IKEv1 Main/Aggressive mode */ + if (message->get_major_version(message) == IKEV1_MAJOR_VERSION && + message->get_message_id(message) == 0) + { + return chunk_hash(message->get_packet_data(message)); + } + return message->get_message_id(message); +} + METHOD(ike_sa_manager_t, checkout_by_message, ike_sa_t*, private_ike_sa_manager_t* this, message_t *message) { @@ -1246,7 +1249,7 @@ METHOD(ike_sa_manager_t, checkout_by_message, ike_sa_t*, entry->checked_out = TRUE; unlock_single_segment(this, segment); - entry->message_id = message->get_message_id(message); + entry->processing = get_message_id_or_hash(message); entry->init_hash = hash; DBG2(DBG_MGR, "created IKE_SA %s[%u]", @@ -1290,12 +1293,11 @@ METHOD(ike_sa_manager_t, checkout_by_message, ike_sa_t*, if (get_entry_by_id(this, id, &entry, &segment) == SUCCESS) { - /* only check out in IKEv2 if we are not already processing it */ - if (message->get_request(message) && - message->get_message_id(message) == entry->message_id) + /* only check out if we are not already processing it. */ + if (entry->processing == get_message_id_or_hash(message)) { DBG1(DBG_MGR, "ignoring request with ID %u, already processing", - entry->message_id); + entry->processing); } else if (wait_for_entry(this, entry, segment)) { @@ -1305,7 +1307,7 @@ METHOD(ike_sa_manager_t, checkout_by_message, ike_sa_t*, entry->checked_out = TRUE; if (message->get_first_payload_type(message) != FRAGMENT_V1) { - entry->message_id = message->get_message_id(message); + entry->processing = get_message_id_or_hash(message); } if (ike_id->get_responder_spi(ike_id) == 0) { @@ -1564,7 +1566,7 @@ METHOD(ike_sa_manager_t, checkin, void, entry->ike_sa_id->replace_values(entry->ike_sa_id, ike_sa->get_id(ike_sa)); /* signal waiting threads */ entry->checked_out = FALSE; - entry->message_id = -1; + entry->processing = -1; /* check if this SA is half-open */ if (entry->half_open && ike_sa->get_state(ike_sa) != IKE_CONNECTING) { @@ -1745,6 +1747,23 @@ METHOD(ike_sa_manager_t, create_id_enumerator, enumerator_t*, (void*)id_enumerator_cleanup, ids); } +/** + * Move all CHILD_SAs from old to new + */ +static void adopt_children(ike_sa_t *old, ike_sa_t *new) +{ + enumerator_t *enumerator; + child_sa_t *child_sa; + + enumerator = old->create_child_sa_enumerator(old); + while (enumerator->enumerate(enumerator, &child_sa)) + { + old->remove_child_sa(old, enumerator); + new->add_child_sa(new, child_sa); + } + enumerator->destroy(enumerator); +} + METHOD(ike_sa_manager_t, check_uniqueness, bool, private_ike_sa_manager_t *this, ike_sa_t *ike_sa, bool force_replace) { @@ -1782,6 +1801,7 @@ METHOD(ike_sa_manager_t, check_uniqueness, bool, { DBG1(DBG_IKE, "destroying duplicate IKE_SA for peer '%Y', " "received INITIAL_CONTACT", other); + charon->bus->ike_updown(charon->bus, duplicate, FALSE); checkin_and_destroy(this, duplicate); continue; } @@ -1796,6 +1816,10 @@ METHOD(ike_sa_manager_t, check_uniqueness, bool, { case UNIQUE_REPLACE: charon->bus->alert(charon->bus, ALERT_UNIQUE_REPLACE); + if (duplicate->get_version(duplicate) == IKEV1) + { + adopt_children(duplicate, ike_sa); + } DBG1(DBG_IKE, "deleting duplicate IKE_SA for peer " "'%Y' due to uniqueness policy", other); status = duplicate->delete(duplicate); diff --git a/src/libcharon/sa/ikev1/task_manager_v1.c b/src/libcharon/sa/ikev1/task_manager_v1.c index 8a4761d5c..7a84d1cef 100644 --- a/src/libcharon/sa/ikev1/task_manager_v1.c +++ b/src/libcharon/sa/ikev1/task_manager_v1.c @@ -1471,6 +1471,21 @@ METHOD(task_manager_t, process_message, status_t, charon->bus->alert(charon->bus, ALERT_RETRANSMIT_RECEIVE, msg); return SUCCESS; } + + /* reject Main/Agressive Modes once established */ + if (msg->get_exchange_type(msg) == ID_PROT || + msg->get_exchange_type(msg) == AGGRESSIVE) + { + if (this->ike_sa->get_state(this->ike_sa) != IKE_CREATED && + this->ike_sa->get_state(this->ike_sa) != IKE_CONNECTING && + msg->get_first_payload_type(msg) != FRAGMENT_V1) + { + DBG1(DBG_IKE, "ignoring %N in established IKE_SA state", + exchange_type_names, msg->get_exchange_type(msg)); + return FAILED; + } + } + if (msg->get_exchange_type(msg) == TRANSACTION && this->active_tasks->get_count(this->active_tasks)) { /* main mode not yet complete, queue XAuth/Mode config tasks */ @@ -2030,4 +2045,3 @@ task_manager_v1_t *task_manager_v1_create(ike_sa_t *ike_sa) return &this->public; } - diff --git a/src/libcharon/sa/ikev1/tasks/quick_mode.c b/src/libcharon/sa/ikev1/tasks/quick_mode.c index 1eae6aa93..16c47630d 100644 --- a/src/libcharon/sa/ikev1/tasks/quick_mode.c +++ b/src/libcharon/sa/ikev1/tasks/quick_mode.c @@ -576,12 +576,12 @@ static bool get_ts(private_quick_mode_t *this, message_t *message) if (!tsi) { tsi = traffic_selector_create_from_subnet(hsi->clone(hsi), - hsi->get_family(hsi) == AF_INET ? 32 : 128, 0, 0); + hsi->get_family(hsi) == AF_INET ? 32 : 128, 0, 0, 65535); } if (!tsr) { tsr = traffic_selector_create_from_subnet(hsr->clone(hsr), - hsr->get_family(hsr) == AF_INET ? 32 : 128, 0, 0); + hsr->get_family(hsr) == AF_INET ? 32 : 128, 0, 0, 65535); } if (this->mode == MODE_TRANSPORT && this->udp && (!tsi->is_host(tsi, hsi) || !tsr->is_host(tsr, hsr))) diff --git a/src/libcharon/sa/ikev2/task_manager_v2.c b/src/libcharon/sa/ikev2/task_manager_v2.c index ea0117c54..29d8d830e 100644 --- a/src/libcharon/sa/ikev2/task_manager_v2.c +++ b/src/libcharon/sa/ikev2/task_manager_v2.c @@ -1123,6 +1123,18 @@ METHOD(task_manager_t, process_message, status_t, { if (mid == this->responding.mid) { + /* reject initial messages once established */ + if (msg->get_exchange_type(msg) == IKE_SA_INIT || + msg->get_exchange_type(msg) == IKE_AUTH) + { + if (this->ike_sa->get_state(this->ike_sa) != IKE_CREATED && + this->ike_sa->get_state(this->ike_sa) != IKE_CONNECTING) + { + DBG1(DBG_IKE, "ignoring %N in established IKE_SA state", + exchange_type_names, msg->get_exchange_type(msg)); + return FAILED; + } + } if (this->ike_sa->get_state(this->ike_sa) == IKE_CREATED || this->ike_sa->get_state(this->ike_sa) == IKE_CONNECTING || msg->get_exchange_type(msg) != IKE_SA_INIT) diff --git a/src/libcharon/sa/ikev2/tasks/child_create.c b/src/libcharon/sa/ikev2/tasks/child_create.c index eb3972c29..32c0e8c4a 100644 --- a/src/libcharon/sa/ikev2/tasks/child_create.c +++ b/src/libcharon/sa/ikev2/tasks/child_create.c @@ -18,6 +18,7 @@ #include "child_create.h" #include <daemon.h> +#include <hydra.h> #include <sa/ikev2/keymat_v2.h> #include <crypto/diffie_hellman.h> #include <credentials/certificates/x509.h> @@ -615,6 +616,7 @@ static void build_payloads(private_child_create_t *this, message_t *message) nonce_payload_t *nonce_payload; ke_payload_t *ke_payload; ts_payload_t *ts_payload; + kernel_feature_t features; /* add SA payload */ if (this->initiator) @@ -661,6 +663,13 @@ static void build_payloads(private_child_create_t *this, message_t *message) default: break; } + + features = hydra->kernel_interface->get_features(hydra->kernel_interface); + if (!(features & KERNEL_ESP_V3_TFC)) + { + message->add_notify(message, FALSE, ESP_TFC_PADDING_NOT_SUPPORTED, + chunk_empty); + } } /** diff --git a/src/libcharon/sa/ikev2/tasks/ike_dpd.c b/src/libcharon/sa/ikev2/tasks/ike_dpd.c index 28ccc2efe..7a33f7938 100644 --- a/src/libcharon/sa/ikev2/tasks/ike_dpd.c +++ b/src/libcharon/sa/ikev2/tasks/ike_dpd.c @@ -37,12 +37,6 @@ METHOD(task_t, return_need_more, status_t, return NEED_MORE; } -METHOD(task_t, return_success, status_t, - private_ike_dpd_t *this, message_t *message) -{ - return SUCCESS; -} - METHOD(task_t, get_type, task_type_t, private_ike_dpd_t *this) { @@ -82,11 +76,11 @@ ike_dpd_t *ike_dpd_create(bool initiator) if (initiator) { this->public.task.build = _return_need_more; - this->public.task.process = _return_success; + this->public.task.process = (void*)return_success; } else { - this->public.task.build = _return_success; + this->public.task.build = (void*)return_success; this->public.task.process = _return_need_more; } |