diff options
Diffstat (limited to 'src/libcharon/sa/ike_sa.c')
-rw-r--r-- | src/libcharon/sa/ike_sa.c | 237 |
1 files changed, 136 insertions, 101 deletions
diff --git a/src/libcharon/sa/ike_sa.c b/src/libcharon/sa/ike_sa.c index 7536662ca..a4e4028ab 100644 --- a/src/libcharon/sa/ike_sa.c +++ b/src/libcharon/sa/ike_sa.c @@ -24,8 +24,8 @@ #include "ike_sa.h" #include <library.h> -#include <daemon.h> #include <hydra.h> +#include <daemon.h> #include <utils/linked_list.h> #include <utils/lexparser.h> #include <sa/task_manager.h> @@ -470,8 +470,8 @@ METHOD(ike_sa_t, send_keepalive, void, diff = 0; } job = send_keepalive_job_create(this->ike_sa_id); - charon->scheduler->schedule_job(charon->scheduler, (job_t*)job, - this->keepalive_interval - diff); + lib->scheduler->schedule_job(lib->scheduler, (job_t*)job, + this->keepalive_interval - diff); } METHOD(ike_sa_t, get_ike_cfg, ike_cfg_t*, @@ -605,7 +605,7 @@ METHOD(ike_sa_t, send_dpd, status_t, } /* recheck in "interval" seconds */ job = (job_t*)send_dpd_job_create(this->ike_sa_id); - charon->scheduler->schedule_job(charon->scheduler, job, delay - diff); + lib->scheduler->schedule_job(lib->scheduler, job, delay - diff); return SUCCESS; } @@ -644,7 +644,7 @@ METHOD(ike_sa_t, set_state, void, { this->stats[STAT_REKEY] = t + this->stats[STAT_ESTABLISHED]; job = (job_t*)rekey_ike_sa_job_create(this->ike_sa_id, FALSE); - charon->scheduler->schedule_job(charon->scheduler, job, t); + lib->scheduler->schedule_job(lib->scheduler, job, t); DBG1(DBG_IKE, "scheduling rekeying in %ds", t); } t = this->peer_cfg->get_reauth_time(this->peer_cfg); @@ -653,7 +653,7 @@ METHOD(ike_sa_t, set_state, void, { this->stats[STAT_REAUTH] = t + this->stats[STAT_ESTABLISHED]; job = (job_t*)rekey_ike_sa_job_create(this->ike_sa_id, TRUE); - charon->scheduler->schedule_job(charon->scheduler, job, t); + lib->scheduler->schedule_job(lib->scheduler, job, t); DBG1(DBG_IKE, "scheduling reauthentication in %ds", t); } t = this->peer_cfg->get_over_time(this->peer_cfg); @@ -675,7 +675,7 @@ METHOD(ike_sa_t, set_state, void, this->stats[STAT_DELETE] += t; t = this->stats[STAT_DELETE] - this->stats[STAT_ESTABLISHED]; job = (job_t*)delete_ike_sa_job_create(this->ike_sa_id, TRUE); - charon->scheduler->schedule_job(charon->scheduler, job, t); + lib->scheduler->schedule_job(lib->scheduler, job, t); DBG1(DBG_IKE, "maximum IKE_SA lifetime %ds", t); } @@ -688,8 +688,8 @@ METHOD(ike_sa_t, set_state, void, { /* delete may fail if a packet gets lost, so set a timeout */ job_t *job = (job_t*)delete_ike_sa_job_create(this->ike_sa_id, TRUE); - charon->scheduler->schedule_job(charon->scheduler, job, - HALF_OPEN_IKE_SA_TIMEOUT); + lib->scheduler->schedule_job(lib->scheduler, job, + HALF_OPEN_IKE_SA_TIMEOUT); break; } default: @@ -730,14 +730,14 @@ METHOD(ike_sa_t, set_virtual_ip, void, if (local) { DBG1(DBG_IKE, "installing new virtual IP %H", ip); - if (charon->kernel_interface->add_ip(charon->kernel_interface, ip, - this->my_host) == SUCCESS) + if (hydra->kernel_interface->add_ip(hydra->kernel_interface, ip, + this->my_host) == SUCCESS) { if (this->my_virtual_ip) { DBG1(DBG_IKE, "removing old virtual IP %H", this->my_virtual_ip); - charon->kernel_interface->del_ip(charon->kernel_interface, - this->my_virtual_ip); + hydra->kernel_interface->del_ip(hydra->kernel_interface, + this->my_virtual_ip); } DESTROY_IF(this->my_virtual_ip); this->my_virtual_ip = ip->clone(ip); @@ -810,6 +810,20 @@ METHOD(ike_sa_t, get_pending_updates, u_int32_t, return this->pending_updates; } +METHOD(ike_sa_t, float_ports, void, + private_ike_sa_t *this) +{ + /* do not switch if we have a custom port from MOBIKE/NAT */ + if (this->my_host->get_port(this->my_host) == IKEV2_UDP_PORT) + { + this->my_host->set_port(this->my_host, IKEV2_NATT_PORT); + } + if (this->other_host->get_port(this->other_host) == IKEV2_UDP_PORT) + { + this->other_host->set_port(this->other_host, IKEV2_NATT_PORT); + } +} + METHOD(ike_sa_t, update_hosts, void, private_ike_sa_t *this, host_t *me, host_t *other) { @@ -843,10 +857,8 @@ METHOD(ike_sa_t, update_hosts, void, if (!other->equals(other, this->other_host)) { - /* update others adress if we are NOT NATed, - * and allow port changes if we are NATed */ - if (!has_condition(this, COND_NAT_HERE) || - other->ip_equals(other, this->other_host)) + /* update others adress if we are NOT NATed */ + if (!has_condition(this, COND_NAT_HERE)) { set_other_host(this, other->clone(other)); update = TRUE; @@ -882,8 +894,7 @@ METHOD(ike_sa_t, generate_message, status_t, this->stats[STAT_OUTBOUND] = time_monotonic(NULL); message->set_ike_sa_id(message, this->ike_sa_id); return message->generate(message, - this->keymat->get_crypter(this->keymat, FALSE), - this->keymat->get_signer(this->keymat, FALSE), packet); + this->keymat->get_aead(this->keymat, FALSE), packet); } /** @@ -1049,8 +1060,8 @@ static void resolve_hosts(private_ike_sa_t *this) !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); + host = hydra->kernel_interface->get_source_addr( + hydra->kernel_interface, this->other_host, NULL); if (host) { host->set_port(host, this->ike_cfg->get_my_port(this->ike_cfg)); @@ -1150,7 +1161,7 @@ METHOD(ike_sa_t, initiate, status_t, { /* mediated connection, initiate mediation process */ job_t *job = (job_t*)initiate_mediation_job_create(this->ike_sa_id); - charon->processor->queue_job(charon->processor, job); + lib->processor->queue_job(lib->processor, job); return SUCCESS; } #endif /* ME */ @@ -1173,8 +1184,7 @@ METHOD(ike_sa_t, process_message, status_t, is_request = message->get_request(message); status = message->parse_body(message, - this->keymat->get_crypter(this->keymat, TRUE), - this->keymat->get_signer(this->keymat, TRUE)); + this->keymat->get_aead(this->keymat, TRUE)); if (status != SUCCESS) { @@ -1229,15 +1239,12 @@ METHOD(ike_sa_t, process_message, status_t, } else { - host_t *me, *other; - - me = message->get_destination(message); - other = message->get_source(message); - /* if this IKE_SA is virgin, we check for a config */ if (this->ike_cfg == NULL) { job_t *job; + host_t *me = message->get_destination(message), + *other = message->get_source(message); this->ike_cfg = charon->backends->get_ike_cfg(charon->backends, me, other); if (this->ike_cfg == NULL) @@ -1250,20 +1257,12 @@ METHOD(ike_sa_t, process_message, status_t, } /* add a timeout if peer does not establish it completely */ job = (job_t*)delete_ike_sa_job_create(this->ike_sa_id, FALSE); - charon->scheduler->schedule_job(charon->scheduler, job, - HALF_OPEN_IKE_SA_TIMEOUT); + lib->scheduler->schedule_job(lib->scheduler, job, + HALF_OPEN_IKE_SA_TIMEOUT); } this->stats[STAT_INBOUND] = time_monotonic(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) - { - 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); + status = this->task_manager->process_message(this->task_manager, + message); if (message->get_exchange_type(message) == IKE_AUTH && this->state == IKE_ESTABLISHED && lib->settings->get_bool(lib->settings, @@ -1697,7 +1696,7 @@ METHOD(ike_sa_t, set_auth_lifetime, void, { DBG1(DBG_IKE, "received AUTH_LIFETIME of %ds, starting reauthentication", lifetime); - charon->processor->queue_job(charon->processor, + lib->processor->queue_job(lib->processor, (job_t*)rekey_ike_sa_job_create(this->ike_sa_id, TRUE)); } else if (this->stats[STAT_REAUTH] == 0 || @@ -1706,7 +1705,7 @@ METHOD(ike_sa_t, set_auth_lifetime, void, this->stats[STAT_REAUTH] = reauth_time; DBG1(DBG_IKE, "received AUTH_LIFETIME of %ds, scheduling reauthentication" " in %ds", lifetime, lifetime - reduction); - charon->scheduler->schedule_job(charon->scheduler, + lib->scheduler->schedule_job(lib->scheduler, (job_t*)rekey_ike_sa_job_create(this->ike_sa_id, TRUE), lifetime - reduction); } @@ -1718,10 +1717,65 @@ METHOD(ike_sa_t, set_auth_lifetime, void, } } +/** + * Check if the current combination of source and destination address is still + * valid. + */ +static bool is_current_path_valid(private_ike_sa_t *this) +{ + bool valid = FALSE; + host_t *src; + src = hydra->kernel_interface->get_source_addr(hydra->kernel_interface, + this->other_host, this->my_host); + if (src) + { + if (src->ip_equals(src, this->my_host)) + { + valid = TRUE; + } + src->destroy(src); + } + return valid; +} + +/** + * Check if we have any path avialable for this IKE SA. + */ +static bool is_any_path_valid(private_ike_sa_t *this) +{ + bool valid = FALSE; + enumerator_t *enumerator; + host_t *src, *addr; + DBG1(DBG_IKE, "old path is not available anymore, try to find another"); + src = hydra->kernel_interface->get_source_addr(hydra->kernel_interface, + this->other_host, NULL); + if (!src) + { + enumerator = this->additional_addresses->create_enumerator( + this->additional_addresses); + while (enumerator->enumerate(enumerator, &addr)) + { + DBG1(DBG_IKE, "looking for a route to %H ...", addr); + src = hydra->kernel_interface->get_source_addr( + hydra->kernel_interface, addr, NULL); + if (src) + { + break; + } + } + enumerator->destroy(enumerator); + } + if (src) + { + valid = TRUE; + src->destroy(src); + } + return valid; +} + METHOD(ike_sa_t, roam, status_t, private_ike_sa_t *this, bool address) { - host_t *src; ike_mobike_t *mobike; switch (this->state) @@ -1734,81 +1788,61 @@ METHOD(ike_sa_t, roam, status_t, default: break; } - /* responder just updates the peer about changed address config */ - if (!this->ike_sa_id->is_initiator(this->ike_sa_id)) + + /* keep existing path if possible */ + if (is_current_path_valid(this)) { + DBG2(DBG_IKE, "keeping connection path %H - %H", + this->my_host, this->other_host); + set_condition(this, COND_STALE, FALSE); + if (supports_extension(this, EXT_MOBIKE) && address) - { + { /* if any addresses changed, send an updated list */ DBG1(DBG_IKE, "sending address list update using MOBIKE"); mobike = ike_mobike_create(&this->public, TRUE); - this->task_manager->queue_task(this->task_manager, (task_t*)mobike); + mobike->addresses(mobike); + this->task_manager->queue_task(this->task_manager, + (task_t*)mobike); return this->task_manager->initiate(this->task_manager); } return SUCCESS; } - /* keep existing path if possible */ - src = charon->kernel_interface->get_source_addr(charon->kernel_interface, - this->other_host, this->my_host); - if (src) + if (!is_any_path_valid(this)) { - if (src->ip_equals(src, this->my_host)) - { - DBG2(DBG_IKE, "keeping connection path %H - %H", - src, this->other_host); - src->destroy(src); - set_condition(this, COND_STALE, FALSE); - return SUCCESS; - } - src->destroy(src); - - } - else - { - /* check if we find a route at all */ - enumerator_t *enumerator; - host_t *addr; - - src = charon->kernel_interface->get_source_addr(charon->kernel_interface, - this->other_host, NULL); - if (!src) - { - enumerator = this->additional_addresses->create_enumerator( - this->additional_addresses); - while (enumerator->enumerate(enumerator, &addr)) - { - DBG1(DBG_IKE, "looking for a route to %H ...", addr); - src = charon->kernel_interface->get_source_addr( - charon->kernel_interface, addr, NULL); - if (src) - { - break; - } - } - enumerator->destroy(enumerator); - } - if (!src) - { - DBG1(DBG_IKE, "no route found to reach %H, MOBIKE update deferred", - this->other_host); - set_condition(this, COND_STALE, TRUE); - return SUCCESS; - } - src->destroy(src); + DBG1(DBG_IKE, "no route found to reach %H, MOBIKE update deferred", + this->other_host); + set_condition(this, COND_STALE, TRUE); + return SUCCESS; } set_condition(this, COND_STALE, FALSE); /* update addresses with mobike, if supported ... */ if (supports_extension(this, EXT_MOBIKE)) { - DBG1(DBG_IKE, "requesting address change using MOBIKE"); + if (!has_condition(this, COND_ORIGINAL_INITIATOR)) + { /* responder updates the peer about changed address config */ + DBG1(DBG_IKE, "sending address list update using MOBIKE, " + "implicitly requesting an address change"); + address = TRUE; + } + else + { + DBG1(DBG_IKE, "requesting address change using MOBIKE"); + } mobike = ike_mobike_create(&this->public, TRUE); mobike->roam(mobike, 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 to address change"); + /* ... reauth if not */ + if (!has_condition(this, COND_ORIGINAL_INITIATOR)) + { /* responder does not reauthenticate */ + set_condition(this, COND_STALE, TRUE); + return SUCCESS; + } + DBG1(DBG_IKE, "reauthenticating IKE_SA due to address change"); return reauth(this); } @@ -1907,9 +1941,9 @@ METHOD(ike_sa_t, inherit, status_t, this->stats[STAT_DELETE] = this->stats[STAT_REAUTH] + delete; DBG1(DBG_IKE, "rescheduling reauthentication in %ds after rekeying, " "lifetime reduced to %ds", reauth, delete); - charon->scheduler->schedule_job(charon->scheduler, + lib->scheduler->schedule_job(lib->scheduler, (job_t*)rekey_ike_sa_job_create(this->ike_sa_id, TRUE), reauth); - charon->scheduler->schedule_job(charon->scheduler, + lib->scheduler->schedule_job(lib->scheduler, (job_t*)delete_ike_sa_job_create(this->ike_sa_id, TRUE), delete); } /* we have to initate here, there may be new tasks to handle */ @@ -1946,8 +1980,8 @@ METHOD(ike_sa_t, destroy, void, if (this->my_virtual_ip) { - charon->kernel_interface->del_ip(charon->kernel_interface, - this->my_virtual_ip); + hydra->kernel_interface->del_ip(hydra->kernel_interface, + this->my_virtual_ip); this->my_virtual_ip->destroy(this->my_virtual_ip); } if (this->other_virtual_ip) @@ -2025,6 +2059,7 @@ ike_sa_t * ike_sa_create(ike_sa_id_t *ike_sa_id) .get_other_host = _get_other_host, .set_other_host = _set_other_host, .set_message_id = _set_message_id, + .float_ports = _float_ports, .update_hosts = _update_hosts, .get_my_id = _get_my_id, .set_my_id = _set_my_id, |