diff options
Diffstat (limited to 'src/charon/sa/ike_sa.c')
-rw-r--r-- | src/charon/sa/ike_sa.c | 2192 |
1 files changed, 0 insertions, 2192 deletions
diff --git a/src/charon/sa/ike_sa.c b/src/charon/sa/ike_sa.c deleted file mode 100644 index 975a0904a..000000000 --- a/src/charon/sa/ike_sa.c +++ /dev/null @@ -1,2192 +0,0 @@ -/* - * Copyright (C) 2006-2008 Tobias Brunner - * Copyright (C) 2006 Daniel Roethlisberger - * Copyright (C) 2005-2009 Martin Willi - * Copyright (C) 2005 Jan Hutter - * Hochschule fuer Technik Rapperswil - * - * This program is free software; you can redistribute it and/or modify it - * under the terms of the GNU General Public License as published by the - * Free Software Foundation; either version 2 of the License, or (at your - * option) any later version. See <http://www.fsf.org/copyleft/gpl.txt>. - * - * This program is distributed in the hope that it will be useful, but - * WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY - * or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License - * for more details. - */ - -#include <string.h> -#include <sys/stat.h> -#include <errno.h> -#include <time.h> - -#include "ike_sa.h" - -#include <library.h> -#include <daemon.h> -#include <utils/linked_list.h> -#include <utils/lexparser.h> -#include <sa/task_manager.h> -#include <sa/tasks/ike_init.h> -#include <sa/tasks/ike_natd.h> -#include <sa/tasks/ike_mobike.h> -#include <sa/tasks/ike_auth.h> -#include <sa/tasks/ike_auth_lifetime.h> -#include <sa/tasks/ike_config.h> -#include <sa/tasks/ike_cert_pre.h> -#include <sa/tasks/ike_cert_post.h> -#include <sa/tasks/ike_rekey.h> -#include <sa/tasks/ike_reauth.h> -#include <sa/tasks/ike_delete.h> -#include <sa/tasks/ike_dpd.h> -#include <sa/tasks/ike_vendor.h> -#include <sa/tasks/child_create.h> -#include <sa/tasks/child_delete.h> -#include <sa/tasks/child_rekey.h> -#include <processing/jobs/retransmit_job.h> -#include <processing/jobs/delete_ike_sa_job.h> -#include <processing/jobs/send_dpd_job.h> -#include <processing/jobs/send_keepalive_job.h> -#include <processing/jobs/rekey_ike_sa_job.h> - -#ifdef ME -#include <sa/tasks/ike_me.h> -#include <processing/jobs/initiate_mediation_job.h> -#endif - -ENUM(ike_sa_state_names, IKE_CREATED, IKE_DESTROYING, - "CREATED", - "CONNECTING", - "ESTABLISHED", - "PASSIVE", - "REKEYING", - "DELETING", - "DESTROYING", -); - -typedef struct private_ike_sa_t private_ike_sa_t; -typedef struct attribute_entry_t attribute_entry_t; - -/** - * Private data of an ike_sa_t object. - */ -struct private_ike_sa_t { - - /** - * Public members - */ - ike_sa_t public; - - /** - * Identifier for the current IKE_SA. - */ - ike_sa_id_t *ike_sa_id; - - /** - * unique numerical ID for this IKE_SA. - */ - u_int32_t unique_id; - - /** - * Current state of the IKE_SA - */ - ike_sa_state_t state; - - /** - * IKE configuration used to set up this IKE_SA - */ - ike_cfg_t *ike_cfg; - - /** - * Peer and authentication information to establish IKE_SA. - */ - peer_cfg_t *peer_cfg; - - /** - * currently used authentication ruleset, local (as auth_cfg_t) - */ - auth_cfg_t *my_auth; - - /** - * list of completed local authentication rounds - */ - linked_list_t *my_auths; - - /** - * list of completed remote authentication rounds - */ - linked_list_t *other_auths; - - /** - * currently used authentication constraints, remote (as auth_cfg_t) - */ - auth_cfg_t *other_auth; - - /** - * Selected IKE proposal - */ - proposal_t *proposal; - - /** - * Juggles tasks to process messages - */ - task_manager_t *task_manager; - - /** - * Address of local host - */ - host_t *my_host; - - /** - * Address of remote host - */ - host_t *other_host; - -#ifdef ME - /** - * Are we mediation server - */ - bool is_mediation_server; - - /** - * Server reflexive host - */ - host_t *server_reflexive_host; - - /** - * Connect ID - */ - chunk_t connect_id; -#endif /* ME */ - - /** - * Identification used for us - */ - identification_t *my_id; - - /** - * Identification used for other - */ - identification_t *other_id; - - /** - * set of extensions the peer supports - */ - ike_extension_t extensions; - - /** - * set of condition flags currently enabled for this IKE_SA - */ - ike_condition_t conditions; - - /** - * Linked List containing the child sa's of the current IKE_SA. - */ - linked_list_t *child_sas; - - /** - * keymat of this IKE_SA - */ - keymat_t *keymat; - - /** - * Virtual IP on local host, if any - */ - host_t *my_virtual_ip; - - /** - * Virtual IP on remote host, if any - */ - host_t *other_virtual_ip; - - /** - * List of configuration attributes (attribute_entry_t) - */ - linked_list_t *attributes; - - /** - * list of peers additional addresses, transmitted via MOBIKE - */ - 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 - */ - u_int32_t stats[STAT_MAX]; - - /** - * how many times we have retried so far (keyingtries) - */ - u_int32_t keyingtry; - - /** - * local host address to be used for IKE, set via MIGRATE kernel message - */ - host_t *local_host; - - /** - * remote host address to be used for IKE, set via MIGRATE kernel message - */ - host_t *remote_host; -}; - -/** - * Entry to maintain install configuration attributes during IKE_SA lifetime - */ -struct attribute_entry_t { - /** handler used to install this attribute */ - attribute_handler_t *handler; - /** attribute type */ - configuration_attribute_type_t type; - /** attribute data */ - chunk_t data; -}; - -/** - * get the time of the latest traffic processed by the kernel - */ -static time_t get_use_time(private_ike_sa_t* this, bool inbound) -{ - enumerator_t *enumerator; - child_sa_t *child_sa; - time_t use_time, current; - - if (inbound) - { - use_time = this->stats[STAT_INBOUND]; - } - else - { - use_time = this->stats[STAT_OUTBOUND]; - } - enumerator = this->child_sas->create_enumerator(this->child_sas); - while (enumerator->enumerate(enumerator, &child_sa)) - { - child_sa->get_usestats(child_sa, inbound, ¤t, NULL); - use_time = max(use_time, current); - } - enumerator->destroy(enumerator); - - return use_time; -} - -/** - * Implementation of ike_sa_t.get_unique_id - */ -static u_int32_t get_unique_id(private_ike_sa_t *this) -{ - return this->unique_id; -} - -/** - * Implementation of ike_sa_t.get_name. - */ -static char *get_name(private_ike_sa_t *this) -{ - if (this->peer_cfg) - { - return this->peer_cfg->get_name(this->peer_cfg); - } - return "(unnamed)"; -} - -/** - * Implementation of ike_sa_t.get_statistic. - */ -static u_int32_t get_statistic(private_ike_sa_t *this, statistic_t kind) -{ - if (kind < STAT_MAX) - { - return this->stats[kind]; - } - return 0; -} - -/** - * Implementation of ike_sa_t.get_my_host. - */ -static host_t *get_my_host(private_ike_sa_t *this) -{ - return this->my_host; -} - -/** - * Implementation of ike_sa_t.set_my_host. - */ -static void set_my_host(private_ike_sa_t *this, host_t *me) -{ - DESTROY_IF(this->my_host); - this->my_host = me; -} - -/** - * Implementation of ike_sa_t.get_other_host. - */ -static host_t *get_other_host(private_ike_sa_t *this) -{ - return this->other_host; -} - -/** - * Implementation of ike_sa_t.set_other_host. - */ -static void set_other_host(private_ike_sa_t *this, host_t *other) -{ - DESTROY_IF(this->other_host); - this->other_host = other; -} - -/** - * Implementation of ike_sa_t.get_peer_cfg - */ -static peer_cfg_t* get_peer_cfg(private_ike_sa_t *this) -{ - return this->peer_cfg; -} - -/** - * Implementation of ike_sa_t.set_peer_cfg - */ -static void set_peer_cfg(private_ike_sa_t *this, peer_cfg_t *peer_cfg) -{ - DESTROY_IF(this->peer_cfg); - peer_cfg->get_ref(peer_cfg); - this->peer_cfg = peer_cfg; - - if (this->ike_cfg == NULL) - { - this->ike_cfg = peer_cfg->get_ike_cfg(peer_cfg); - this->ike_cfg->get_ref(this->ike_cfg); - } -} - -/** - * Implementation of ike_sa_t.get_auth_cfg - */ -static auth_cfg_t* get_auth_cfg(private_ike_sa_t *this, bool local) -{ - if (local) - { - return this->my_auth; - } - return this->other_auth; -} - -/** - * Implementation of ike_sa_t.add_auth_cfg - */ -static void add_auth_cfg(private_ike_sa_t *this, bool local, auth_cfg_t *cfg) -{ - if (local) - { - this->my_auths->insert_last(this->my_auths, cfg); - } - else - { - this->other_auths->insert_last(this->other_auths, cfg); - } -} - -/** - * Implementation of ike_sa_t.create_auth_cfg_enumerator - */ -static enumerator_t* create_auth_cfg_enumerator(private_ike_sa_t *this, - bool local) -{ - if (local) - { - return this->my_auths->create_enumerator(this->my_auths); - } - return this->other_auths->create_enumerator(this->other_auths); -} - -/** - * Flush the stored authentication round information - */ -static void flush_auth_cfgs(private_ike_sa_t *this) -{ - auth_cfg_t *cfg; - - if (lib->settings->get_bool(lib->settings, "charon.flush_auth_cfg", TRUE)) - { - while (this->my_auths->remove_last(this->my_auths, - (void**)&cfg) == SUCCESS) - { - cfg->destroy(cfg); - } - while (this->other_auths->remove_last(this->other_auths, - (void**)&cfg) == SUCCESS) - { - cfg->destroy(cfg); - } - } -} - -/** - * Implementation of ike_sa_t.get_proposal - */ -static proposal_t* get_proposal(private_ike_sa_t *this) -{ - return this->proposal; -} - -/** - * Implementation of ike_sa_t.set_proposal - */ -static void set_proposal(private_ike_sa_t *this, proposal_t *proposal) -{ - DESTROY_IF(this->proposal); - this->proposal = proposal->clone(proposal); -} - -/** - * Implementation of ike_sa_t.set_message_id - */ -static void set_message_id(private_ike_sa_t *this, bool initiate, u_int32_t mid) -{ - if (initiate) - { - this->task_manager->reset(this->task_manager, mid, UINT_MAX); - } - else - { - this->task_manager->reset(this->task_manager, UINT_MAX, mid); - } -} - -/** - * Implementation of ike_sa_t.send_keepalive - */ -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) || this->keepalive_interval == 0) - { /* disable keep alives if we are not NATed anymore */ - return; - } - - last_out = get_use_time(this, FALSE); - now = time_monotonic(NULL); - - diff = now - last_out; - - if (diff >= this->keepalive_interval) - { - packet_t *packet; - chunk_t data; - - packet = packet_create(); - packet->set_source(packet, this->my_host->clone(this->my_host)); - packet->set_destination(packet, this->other_host->clone(this->other_host)); - data.ptr = malloc(1); - data.ptr[0] = 0xFF; - data.len = 1; - packet->set_data(packet, data); - DBG1(DBG_IKE, "sending keep alive"); - charon->sender->send(charon->sender, packet); - diff = 0; - } - job = send_keepalive_job_create(this->ike_sa_id); - charon->scheduler->schedule_job(charon->scheduler, (job_t*)job, - this->keepalive_interval - diff); -} - -/** - * Implementation of ike_sa_t.get_ike_cfg - */ -static ike_cfg_t *get_ike_cfg(private_ike_sa_t *this) -{ - return this->ike_cfg; -} - -/** - * Implementation of ike_sa_t.set_ike_cfg - */ -static void set_ike_cfg(private_ike_sa_t *this, ike_cfg_t *ike_cfg) -{ - ike_cfg->get_ref(ike_cfg); - this->ike_cfg = ike_cfg; -} - -/** - * Implementation of ike_sa_t.enable_extension. - */ -static void enable_extension(private_ike_sa_t *this, ike_extension_t extension) -{ - this->extensions |= extension; -} - -/** - * Implementation of ike_sa_t.has_extension. - */ -static bool supports_extension(private_ike_sa_t *this, ike_extension_t extension) -{ - return (this->extensions & extension) != FALSE; -} - -/** - * Implementation of ike_sa_t.has_condition. - */ -static bool has_condition(private_ike_sa_t *this, ike_condition_t condition) -{ - return (this->conditions & condition) != FALSE; -} - -/** - * Implementation of ike_sa_t.enable_condition. - */ -static void set_condition(private_ike_sa_t *this, ike_condition_t condition, - bool enable) -{ - if (has_condition(this, condition) != enable) - { - if (enable) - { - this->conditions |= condition; - switch (condition) - { - case COND_NAT_HERE: - DBG1(DBG_IKE, "local host is behind NAT, sending keep alives"); - this->conditions |= COND_NAT_ANY; - send_keepalive(this); - break; - case COND_NAT_THERE: - DBG1(DBG_IKE, "remote host is behind NAT"); - this->conditions |= COND_NAT_ANY; - break; - case COND_NAT_FAKE: - DBG1(DBG_IKE, "faking NAT situation to enforce UDP encapsulation"); - this->conditions |= COND_NAT_ANY; - break; - default: - break; - } - } - else - { - this->conditions &= ~condition; - switch (condition) - { - case COND_NAT_HERE: - case COND_NAT_FAKE: - case COND_NAT_THERE: - set_condition(this, COND_NAT_ANY, - has_condition(this, COND_NAT_HERE) || - has_condition(this, COND_NAT_THERE) || - has_condition(this, COND_NAT_FAKE)); - break; - default: - break; - } - } - } -} - -/** - * Implementation of ike_sa_t.send_dpd - */ -static status_t send_dpd(private_ike_sa_t *this) -{ - job_t *job; - time_t diff, delay; - - delay = this->peer_cfg->get_dpd(this->peer_cfg); - - if (delay == 0) - { - /* DPD disabled */ - return SUCCESS; - } - - if (this->task_manager->busy(this->task_manager)) - { - /* an exchange is in the air, no need to start a DPD check */ - diff = 0; - } - else - { - /* check if there was any inbound traffic */ - time_t last_in, now; - last_in = get_use_time(this, TRUE); - now = time_monotonic(NULL); - diff = now - last_in; - if (diff >= delay) - { - /* to long ago, initiate dead peer detection */ - task_t *task; - ike_mobike_t *mobike; - - 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"); - - this->task_manager->queue_task(this->task_manager, task); - this->task_manager->initiate(this->task_manager); - } - } - /* recheck in "interval" seconds */ - job = (job_t*)send_dpd_job_create(this->ike_sa_id); - charon->scheduler->schedule_job(charon->scheduler, job, delay - diff); - return SUCCESS; -} - -/** - * Implementation of ike_sa_t.get_state. - */ -static ike_sa_state_t get_state(private_ike_sa_t *this) -{ - return this->state; -} - -/** - * Implementation of ike_sa_t.set_state. - */ -static void set_state(private_ike_sa_t *this, ike_sa_state_t state) -{ - 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); - - switch (state) - { - case IKE_ESTABLISHED: - { - if (this->state == IKE_CONNECTING || - this->state == IKE_PASSIVE) - { - job_t *job; - u_int32_t t; - - /* calculate rekey, reauth and lifetime */ - this->stats[STAT_ESTABLISHED] = time_monotonic(NULL); - - /* schedule rekeying if we have a time which is smaller than - * an already scheduled rekeying */ - t = this->peer_cfg->get_rekey_time(this->peer_cfg); - if (t && (this->stats[STAT_REKEY] == 0 || - (this->stats[STAT_REKEY] > t + this->stats[STAT_ESTABLISHED]))) - { - 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); - DBG1(DBG_IKE, "scheduling rekeying in %ds", t); - } - t = this->peer_cfg->get_reauth_time(this->peer_cfg); - if (t && (this->stats[STAT_REAUTH] == 0 || - (this->stats[STAT_REAUTH] > t + this->stats[STAT_ESTABLISHED]))) - { - 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); - DBG1(DBG_IKE, "scheduling reauthentication in %ds", t); - } - t = this->peer_cfg->get_over_time(this->peer_cfg); - if (this->stats[STAT_REKEY] || this->stats[STAT_REAUTH]) - { - if (this->stats[STAT_REAUTH] == 0) - { - this->stats[STAT_DELETE] = this->stats[STAT_REKEY]; - } - else if (this->stats[STAT_REKEY] == 0) - { - this->stats[STAT_DELETE] = this->stats[STAT_REAUTH]; - } - else - { - this->stats[STAT_DELETE] = min(this->stats[STAT_REKEY], - this->stats[STAT_REAUTH]); - } - 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); - DBG1(DBG_IKE, "maximum IKE_SA lifetime %ds", t); - } - - /* start DPD checks */ - send_dpd(this); - } - break; - } - case IKE_DELETING: - { - /* delete may fail if a packet gets lost, so set a timeout */ - job_t *job = (job_t*)delete_ike_sa_job_create(this->ike_sa_id, TRUE); - charon->scheduler->schedule_job(charon->scheduler, job, - HALF_OPEN_IKE_SA_TIMEOUT); - break; - } - default: - break; - } - charon->bus->ike_state_change(charon->bus, &this->public, state); - this->state = state; -} - -/** - * Implementation of ike_sa_t.reset - */ -static void reset(private_ike_sa_t *this) -{ - /* the responder ID is reset, as peer may choose another one */ - if (this->ike_sa_id->is_initiator(this->ike_sa_id)) - { - this->ike_sa_id->set_responder_spi(this->ike_sa_id, 0); - } - - set_state(this, IKE_CREATED); - - this->task_manager->reset(this->task_manager, 0, 0); -} - -/** - * Implementation of ike_sa_t.get_keymat - */ -static keymat_t* get_keymat(private_ike_sa_t *this) -{ - return this->keymat; -} - -/** - * Implementation of ike_sa_t.set_virtual_ip - */ -static void set_virtual_ip(private_ike_sa_t *this, bool local, host_t *ip) -{ - 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 (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); - } - DESTROY_IF(this->my_virtual_ip); - this->my_virtual_ip = ip->clone(ip); - } - else - { - DBG1(DBG_IKE, "installing virtual IP %H failed", ip); - this->my_virtual_ip = NULL; - } - } - else - { - DESTROY_IF(this->other_virtual_ip); - this->other_virtual_ip = ip->clone(ip); - } -} - -/** - * Implementation of ike_sa_t.get_virtual_ip - */ -static host_t* get_virtual_ip(private_ike_sa_t *this, bool local) -{ - if (local) - { - return this->my_virtual_ip; - } - else - { - return this->other_virtual_ip; - } -} - -/** - * Implementation of ike_sa_t.add_additional_address. - */ -static void add_additional_address(private_ike_sa_t *this, host_t *host) -{ - this->additional_addresses->insert_last(this->additional_addresses, host); -} - -/** - * Implementation of ike_sa_t.create_additional_address_iterator. - */ -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. - */ -static void set_pending_updates(private_ike_sa_t *this, u_int32_t updates) -{ - this->pending_updates = updates; -} - -/** - * Implementation of ike_sa_t.get_pending_updates. - */ -static u_int32_t get_pending_updates(private_ike_sa_t *this) -{ - return this->pending_updates; -} - -/** - * Update hosts, as addresses may change (NAT) - */ -static void update_hosts(private_ike_sa_t *this, host_t *me, host_t *other) -{ - bool update = FALSE; - - if (me == NULL) - { - me = this->my_host; - } - if (other == NULL) - { - other = this->other_host; - } - - /* apply hosts on first received message */ - if (this->my_host->is_anyaddr(this->my_host) || - this->other_host->is_anyaddr(this->other_host)) - { - set_my_host(this, me->clone(me)); - set_other_host(this, other->clone(other)); - update = TRUE; - } - else - { - /* update our address in any case */ - if (!me->equals(me, this->my_host)) - { - set_my_host(this, me->clone(me)); - update = TRUE; - } - - 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)) - { - set_other_host(this, other->clone(other)); - update = TRUE; - } - } - } - - /* update all associated CHILD_SAs, if required */ - if (update) - { - 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)) - { - if (child_sa->update(child_sa, this->my_host, - this->other_host, this->my_virtual_ip, - has_condition(this, COND_NAT_ANY)) == NOT_SUPPORTED) - { - this->public.rekey_child_sa(&this->public, - child_sa->get_protocol(child_sa), - child_sa->get_spi(child_sa, TRUE)); - } - } - iterator->destroy(iterator); - } -} - -/** - * Implementation of ike_sa_t.generate - */ -static status_t generate_message(private_ike_sa_t *this, message_t *message, - packet_t **packet) -{ - 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); -} - -/** - * send a notify back to the sender - */ -static void send_notify_response(private_ike_sa_t *this, message_t *request, - notify_type_t type) -{ - message_t *response; - packet_t *packet; - - response = message_create(); - response->set_exchange_type(response, request->get_exchange_type(request)); - response->set_request(response, FALSE); - response->set_message_id(response, request->get_message_id(request)); - response->add_notify(response, FALSE, type, chunk_empty); - if (this->my_host->is_anyaddr(this->my_host)) - { - this->my_host->destroy(this->my_host); - this->my_host = request->get_destination(request); - this->my_host = this->my_host->clone(this->my_host); - } - if (this->other_host->is_anyaddr(this->other_host)) - { - this->other_host->destroy(this->other_host); - this->other_host = request->get_source(request); - this->other_host = this->other_host->clone(this->other_host); - } - response->set_source(response, this->my_host->clone(this->my_host)); - response->set_destination(response, this->other_host->clone(this->other_host)); - if (generate_message(this, response, &packet) == SUCCESS) - { - charon->sender->send(charon->sender, packet); - } - response->destroy(response); -} - -/** - * Implementation of ike_sa_t.set_kmaddress. - */ -static void set_kmaddress(private_ike_sa_t *this, host_t *local, host_t *remote) -{ - DESTROY_IF(this->local_host); - DESTROY_IF(this->remote_host); - this->local_host = local->clone(local); - this->remote_host = remote->clone(remote); -} - -#ifdef ME -/** - * Implementation of ike_sa_t.act_as_mediation_server. - */ -static void act_as_mediation_server(private_ike_sa_t *this) -{ - charon->mediation_manager->update_sa_id(charon->mediation_manager, - this->other_id, this->ike_sa_id); - this->is_mediation_server = TRUE; -} - -/** - * Implementation of ike_sa_t.get_server_reflexive_host. - */ -static host_t *get_server_reflexive_host(private_ike_sa_t *this) -{ - return this->server_reflexive_host; -} - -/** - * Implementation of ike_sa_t.set_server_reflexive_host. - */ -static void set_server_reflexive_host(private_ike_sa_t *this, host_t *host) -{ - DESTROY_IF(this->server_reflexive_host); - this->server_reflexive_host = host; -} - -/** - * Implementation of ike_sa_t.get_connect_id. - */ -static chunk_t get_connect_id(private_ike_sa_t *this) -{ - return this->connect_id; -} - -/** - * Implementation of ike_sa_t.respond - */ -static status_t respond(private_ike_sa_t *this, identification_t *peer_id, - chunk_t connect_id) -{ - ike_me_t *task = ike_me_create(&this->public, TRUE); - task->respond(task, peer_id, connect_id); - this->task_manager->queue_task(this->task_manager, (task_t*)task); - return this->task_manager->initiate(this->task_manager); -} - -/** - * Implementation of ike_sa_t.callback - */ -static status_t callback(private_ike_sa_t *this, identification_t *peer_id) -{ - ike_me_t *task = ike_me_create(&this->public, TRUE); - task->callback(task, peer_id); - this->task_manager->queue_task(this->task_manager, (task_t*)task); - return this->task_manager->initiate(this->task_manager); -} - -/** - * Implementation of ike_sa_t.relay - */ -static status_t relay(private_ike_sa_t *this, identification_t *requester, - chunk_t connect_id, chunk_t connect_key, - linked_list_t *endpoints, bool response) -{ - ike_me_t *task = ike_me_create(&this->public, TRUE); - task->relay(task, requester, connect_id, connect_key, endpoints, response); - this->task_manager->queue_task(this->task_manager, (task_t*)task); - return this->task_manager->initiate(this->task_manager); -} - -/** - * Implementation of ike_sa_t.initiate_mediation - */ -static status_t initiate_mediation(private_ike_sa_t *this, - peer_cfg_t *mediated_cfg) -{ - ike_me_t *task = ike_me_create(&this->public, TRUE); - task->connect(task, mediated_cfg->get_peer_id(mediated_cfg)); - this->task_manager->queue_task(this->task_manager, (task_t*)task); - return this->task_manager->initiate(this->task_manager); -} - -/** - * Implementation of ike_sa_t.initiate_mediated - */ -static status_t initiate_mediated(private_ike_sa_t *this, host_t *me, - host_t *other, chunk_t connect_id) -{ - set_my_host(this, me->clone(me)); - set_other_host(this, other->clone(other)); - chunk_free(&this->connect_id); - this->connect_id = chunk_clone(connect_id); - return this->task_manager->initiate(this->task_manager); -} -#endif /* ME */ - -/** - * Resolve DNS host in configuration - */ -static void resolve_hosts(private_ike_sa_t *this) -{ - host_t *host; - - if (this->remote_host) - { - host = this->remote_host->clone(this->remote_host); - host->set_port(host, IKEV2_UDP_PORT); - } - else - { - host = host_create_from_dns(this->ike_cfg->get_other_addr(this->ike_cfg), - 0, IKEV2_UDP_PORT); - } - if (host) - { - set_other_host(this, host); - } - - if (this->local_host) - { - host = this->local_host->clone(this->local_host); - host->set_port(host, IKEV2_UDP_PORT); - } - else - { - int family = 0; - - /* use same address family as for other */ - if (!this->other_host->is_anyaddr(this->other_host)) - { - family = this->other_host->get_family(this->other_host); - } - host = host_create_from_dns(this->ike_cfg->get_my_addr(this->ike_cfg), - family, 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); - } - else - { /* fallback to address family specific %any(6), if configured */ - host = host_create_from_dns( - this->ike_cfg->get_my_addr(this->ike_cfg), - 0, IKEV2_UDP_PORT); - } - } - } - if (host) - { - set_my_host(this, host); - } -} - -/** - * Implementation of ike_sa_t.initiate - */ -static status_t initiate(private_ike_sa_t *this, - child_cfg_t *child_cfg, u_int32_t reqid, - traffic_selector_t *tsi, traffic_selector_t *tsr) -{ - task_t *task; - - if (this->state == IKE_CREATED) - { - resolve_hosts(this); - - if (this->other_host->is_anyaddr(this->other_host) -#ifdef ME - && !this->peer_cfg->get_mediated_by(this->peer_cfg) -#endif /* ME */ - ) - { - child_cfg->destroy(child_cfg); - DBG1(DBG_IKE, "unable to initiate to %%any"); - return DESTROY_ME; - } - - set_condition(this, COND_ORIGINAL_INITIATOR, TRUE); - - task = (task_t*)ike_init_create(&this->public, TRUE, NULL); - this->task_manager->queue_task(this->task_manager, task); - task = (task_t*)ike_vendor_create(&this->public, TRUE); - this->task_manager->queue_task(this->task_manager, task); - task = (task_t*)ike_natd_create(&this->public, TRUE); - this->task_manager->queue_task(this->task_manager, task); - task = (task_t*)ike_cert_pre_create(&this->public, TRUE); - this->task_manager->queue_task(this->task_manager, task); - task = (task_t*)ike_auth_create(&this->public, TRUE); - this->task_manager->queue_task(this->task_manager, task); - task = (task_t*)ike_cert_post_create(&this->public, TRUE); - this->task_manager->queue_task(this->task_manager, task); - task = (task_t*)ike_config_create(&this->public, TRUE); - this->task_manager->queue_task(this->task_manager, task); - task = (task_t*)ike_auth_lifetime_create(&this->public, TRUE); - this->task_manager->queue_task(this->task_manager, task); - if (this->peer_cfg->use_mobike(this->peer_cfg)) - { - task = (task_t*)ike_mobike_create(&this->public, TRUE); - this->task_manager->queue_task(this->task_manager, task); - } -#ifdef ME - task = (task_t*)ike_me_create(&this->public, TRUE); - this->task_manager->queue_task(this->task_manager, task); -#endif /* ME */ - } - -#ifdef ME - if (this->peer_cfg->is_mediation(this->peer_cfg)) - { - if (this->state == IKE_ESTABLISHED) - { - /* mediation connection is already established, retrigger state - * change to notify bus listeners */ - DBG1(DBG_IKE, "mediation connection is already up"); - set_state(this, IKE_ESTABLISHED); - } - DESTROY_IF(child_cfg); - } - else -#endif /* ME */ - { - /* normal IKE_SA with CHILD_SA */ - task = (task_t*)child_create_create(&this->public, child_cfg, FALSE, - tsi, tsr); - child_cfg->destroy(child_cfg); - if (reqid) - { - child_create_t *child_create = (child_create_t*)task; - child_create->use_reqid(child_create, reqid); - } - this->task_manager->queue_task(this->task_manager, task); - -#ifdef ME - if (this->peer_cfg->get_mediated_by(this->peer_cfg)) - { - /* 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); - return SUCCESS; - } -#endif /* ME */ - } - - return this->task_manager->initiate(this->task_manager); -} - -/** - * Implementation of ike_sa_t.process_message. - */ -static status_t process_message(private_ike_sa_t *this, message_t *message) -{ - status_t status; - bool is_request; - - if (this->state == IKE_PASSIVE) - { /* do not handle messages in passive state */ - return FAILED; - } - - 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)); - if (status != SUCCESS) - { - - if (is_request) - { - switch (status) - { - case NOT_SUPPORTED: - DBG1(DBG_IKE, "critical unknown payloads found"); - if (is_request) - { - send_notify_response(this, message, UNSUPPORTED_CRITICAL_PAYLOAD); - } - break; - case PARSE_ERROR: - DBG1(DBG_IKE, "message parsing failed"); - if (is_request) - { - send_notify_response(this, message, INVALID_SYNTAX); - } - break; - case VERIFY_ERROR: - DBG1(DBG_IKE, "message verification failed"); - if (is_request) - { - send_notify_response(this, message, INVALID_SYNTAX); - } - break; - case FAILED: - DBG1(DBG_IKE, "integrity check failed"); - /* ignored */ - break; - case INVALID_STATE: - DBG1(DBG_IKE, "found encrypted message, but no keys available"); - if (is_request) - { - send_notify_response(this, message, INVALID_SYNTAX); - } - default: - break; - } - } - DBG1(DBG_IKE, "%N %s with message ID %d processing failed", - exchange_type_names, message->get_exchange_type(message), - message->get_request(message) ? "request" : "response", - message->get_message_id(message)); - - if (this->state == IKE_CREATED) - { /* invalid initiation attempt, close SA */ - return DESTROY_ME; - } - } - 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; - this->ike_cfg = charon->backends->get_ike_cfg(charon->backends, - me, other); - if (this->ike_cfg == NULL) - { - /* no config found for these hosts, destroy */ - DBG1(DBG_IKE, "no IKE config found for %H...%H, sending %N", - me, other, notify_type_names, NO_PROPOSAL_CHOSEN); - send_notify_response(this, message, NO_PROPOSAL_CHOSEN); - return DESTROY_ME; - } - /* 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); - } - 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); - if (message->get_exchange_type(message) == IKE_AUTH && - this->state == IKE_ESTABLISHED) - { /* authentication completed */ - flush_auth_cfgs(this); - } - } - return status; -} - -/** - * Implementation of ike_sa_t.get_id. - */ -static ike_sa_id_t* get_id(private_ike_sa_t *this) -{ - return this->ike_sa_id; -} - -/** - * Implementation of ike_sa_t.get_my_id. - */ -static identification_t* get_my_id(private_ike_sa_t *this) -{ - return this->my_id; -} - -/** - * Implementation of ike_sa_t.set_my_id. - */ -static void set_my_id(private_ike_sa_t *this, identification_t *me) -{ - DESTROY_IF(this->my_id); - this->my_id = me; -} - -/** - * Implementation of ike_sa_t.get_other_id. - */ -static identification_t* get_other_id(private_ike_sa_t *this) -{ - return this->other_id; -} - -/** - * Implementation of ike_sa_t.set_other_id. - */ -static void set_other_id(private_ike_sa_t *this, identification_t *other) -{ - DESTROY_IF(this->other_id); - this->other_id = other; -} - -/** - * Implementation of ike_sa_t.add_child_sa. - */ -static void add_child_sa(private_ike_sa_t *this, child_sa_t *child_sa) -{ - this->child_sas->insert_last(this->child_sas, child_sa); -} - -/** - * Implementation of ike_sa_t.get_child_sa. - */ -static child_sa_t* get_child_sa(private_ike_sa_t *this, protocol_id_t protocol, - u_int32_t spi, bool inbound) -{ - iterator_t *iterator; - child_sa_t *current, *found = NULL; - - iterator = this->child_sas->create_iterator(this->child_sas, TRUE); - while (iterator->iterate(iterator, (void**)¤t)) - { - if (current->get_spi(current, inbound) == spi && - current->get_protocol(current) == protocol) - { - found = current; - } - } - iterator->destroy(iterator); - return found; -} - -/** - * Implementation of ike_sa_t.create_child_sa_iterator. - */ -static iterator_t* create_child_sa_iterator(private_ike_sa_t *this) -{ - return this->child_sas->create_iterator(this->child_sas, TRUE); -} - -/** - * Implementation of ike_sa_t.rekey_child_sa. - */ -static status_t rekey_child_sa(private_ike_sa_t *this, protocol_id_t protocol, - u_int32_t spi) -{ - child_rekey_t *child_rekey; - - child_rekey = child_rekey_create(&this->public, protocol, spi); - this->task_manager->queue_task(this->task_manager, &child_rekey->task); - return this->task_manager->initiate(this->task_manager); -} - -/** - * Implementation of ike_sa_t.delete_child_sa. - */ -static status_t delete_child_sa(private_ike_sa_t *this, protocol_id_t protocol, - u_int32_t spi) -{ - child_delete_t *child_delete; - - child_delete = child_delete_create(&this->public, protocol, spi); - this->task_manager->queue_task(this->task_manager, &child_delete->task); - return this->task_manager->initiate(this->task_manager); -} - -/** - * Implementation of ike_sa_t.destroy_child_sa. - */ -static status_t destroy_child_sa(private_ike_sa_t *this, protocol_id_t protocol, - u_int32_t spi) -{ - iterator_t *iterator; - child_sa_t *child_sa; - status_t status = NOT_FOUND; - - iterator = this->child_sas->create_iterator(this->child_sas, TRUE); - while (iterator->iterate(iterator, (void**)&child_sa)) - { - if (child_sa->get_protocol(child_sa) == protocol && - child_sa->get_spi(child_sa, TRUE) == spi) - { - child_sa->destroy(child_sa); - iterator->remove(iterator); - status = SUCCESS; - break; - } - } - iterator->destroy(iterator); - return status; -} - -/** - * Implementation of public_ike_sa_t.delete. - */ -static status_t delete_(private_ike_sa_t *this) -{ - ike_delete_t *ike_delete; - - switch (this->state) - { - case IKE_ESTABLISHED: - case IKE_REKEYING: - ike_delete = ike_delete_create(&this->public, TRUE); - this->task_manager->queue_task(this->task_manager, &ike_delete->task); - return this->task_manager->initiate(this->task_manager); - case IKE_CREATED: - DBG1(DBG_IKE, "deleting unestablished IKE_SA"); - break; - case IKE_PASSIVE: - break; - default: - DBG1(DBG_IKE, "destroying IKE_SA in state %N " - "without notification", ike_sa_state_names, this->state); - break; - } - return DESTROY_ME; -} - -/** - * Implementation of ike_sa_t.rekey. - */ -static status_t rekey(private_ike_sa_t *this) -{ - ike_rekey_t *ike_rekey; - - ike_rekey = ike_rekey_create(&this->public, TRUE); - - this->task_manager->queue_task(this->task_manager, &ike_rekey->task); - return this->task_manager->initiate(this->task_manager); -} - -/** - * Implementation of ike_sa_t.reauth - */ -static status_t reauth(private_ike_sa_t *this) -{ - task_t *task; - - /* we can't reauthenticate as responder when we use EAP or virtual IPs. - * If the peer does not support RFC4478, there is no way to keep the - * IKE_SA up. */ - if (!has_condition(this, COND_ORIGINAL_INITIATOR)) - { - DBG1(DBG_IKE, "initiator did not reauthenticate as requested"); - if (this->other_virtual_ip != NULL || - has_condition(this, COND_EAP_AUTHENTICATED) -#ifdef ME - /* as mediation server we too cannot reauth the IKE_SA */ - || this->is_mediation_server -#endif /* ME */ - ) - { - time_t now = time_monotonic(NULL); - - DBG1(DBG_IKE, "IKE_SA will timeout in %V", - &now, &this->stats[STAT_DELETE]); - return FAILED; - } - else - { - DBG1(DBG_IKE, "reauthenticating actively"); - } - } - task = (task_t*)ike_reauth_create(&this->public); - this->task_manager->queue_task(this->task_manager, task); - - return this->task_manager->initiate(this->task_manager); -} - -/** - * Implementation of ike_sa_t.reestablish - */ -static status_t reestablish(private_ike_sa_t *this) -{ - ike_sa_t *new; - host_t *host; - action_t action; - iterator_t *iterator; - child_sa_t *child_sa; - child_cfg_t *child_cfg; - bool restart = FALSE; - status_t status = FAILED; - - /* check if we have children to keep up at all */ - iterator = create_child_sa_iterator(this); - while (iterator->iterate(iterator, (void**)&child_sa)) - { - child_cfg = child_sa->get_config(child_sa); - if (this->state == IKE_DELETING) - { - action = child_cfg->get_close_action(child_cfg); - } - else - { - action = child_cfg->get_dpd_action(child_cfg); - } - switch (action) - { - case ACTION_RESTART: - restart = TRUE; - break; - case ACTION_ROUTE: - charon->traps->install(charon->traps, this->peer_cfg, child_cfg); - break; - default: - break; - } - } - iterator->destroy(iterator); -#ifdef ME - /* mediation connections have no children, keep them up anyway */ - if (this->peer_cfg->is_mediation(this->peer_cfg)) - { - restart = TRUE; - } -#endif /* ME */ - if (!restart) - { - return FAILED; - } - - /* check if we are able to reestablish this IKE_SA */ - if (!has_condition(this, COND_ORIGINAL_INITIATOR) && - (this->other_virtual_ip != NULL || - has_condition(this, COND_EAP_AUTHENTICATED) -#ifdef ME - || this->is_mediation_server -#endif /* ME */ - )) - { - DBG1(DBG_IKE, "unable to reestablish IKE_SA due asymetric setup"); - return FAILED; - } - - new = charon->ike_sa_manager->checkout_new(charon->ike_sa_manager, TRUE); - new->set_peer_cfg(new, this->peer_cfg); - host = this->other_host; - new->set_other_host(new, host->clone(host)); - host = this->my_host; - new->set_my_host(new, host->clone(host)); - /* if we already have a virtual IP, we reuse it */ - host = this->my_virtual_ip; - if (host) - { - new->set_virtual_ip(new, TRUE, host); - } - -#ifdef ME - if (this->peer_cfg->is_mediation(this->peer_cfg)) - { - status = new->initiate(new, NULL, 0, NULL, NULL); - } - else -#endif /* ME */ - { - iterator = create_child_sa_iterator(this); - while (iterator->iterate(iterator, (void**)&child_sa)) - { - child_cfg = child_sa->get_config(child_sa); - if (this->state == IKE_DELETING) - { - action = child_cfg->get_close_action(child_cfg); - } - else - { - action = child_cfg->get_dpd_action(child_cfg); - } - switch (action) - { - case ACTION_RESTART: - DBG1(DBG_IKE, "restarting CHILD_SA %s", - child_cfg->get_name(child_cfg)); - child_cfg->get_ref(child_cfg); - status = new->initiate(new, child_cfg, 0, NULL, NULL); - break; - default: - continue; - } - if (status == DESTROY_ME) - { - break; - } - } - iterator->destroy(iterator); - } - - if (status == DESTROY_ME) - { - charon->ike_sa_manager->checkin_and_destroy(charon->ike_sa_manager, new); - status = FAILED; - } - else - { - charon->ike_sa_manager->checkin(charon->ike_sa_manager, new); - status = SUCCESS; - } - charon->bus->set_sa(charon->bus, &this->public); - return status; -} - -/** - * Implementation of ike_sa_t.retransmit. - */ -static status_t retransmit(private_ike_sa_t *this, u_int32_t message_id) -{ - this->stats[STAT_OUTBOUND] = time_monotonic(NULL); - if (this->task_manager->retransmit(this->task_manager, message_id) != SUCCESS) - { - /* send a proper signal to brief interested bus listeners */ - switch (this->state) - { - case IKE_CONNECTING: - { - /* retry IKE_SA_INIT if we have multiple keyingtries */ - u_int32_t tries = this->peer_cfg->get_keyingtries(this->peer_cfg); - this->keyingtry++; - if (tries == 0 || tries > this->keyingtry) - { - DBG1(DBG_IKE, "peer not responding, trying again (%d/%d)", - this->keyingtry + 1, tries); - reset(this); - return this->task_manager->initiate(this->task_manager); - } - DBG1(DBG_IKE, "establishing IKE_SA failed, peer not responding"); - break; - } - case IKE_DELETING: - DBG1(DBG_IKE, "proper IKE_SA delete failed, peer not responding"); - break; - case IKE_REKEYING: - DBG1(DBG_IKE, "rekeying IKE_SA failed, peer not responding"); - /* FALL */ - default: - reestablish(this); - break; - } - return DESTROY_ME; - } - return SUCCESS; -} - -/** - * Implementation of ike_sa_t.set_auth_lifetime. - */ -static void set_auth_lifetime(private_ike_sa_t *this, u_int32_t lifetime) -{ - u_int32_t reduction = this->peer_cfg->get_over_time(this->peer_cfg); - u_int32_t reauth_time = time_monotonic(NULL) + lifetime - reduction; - - if (lifetime < reduction) - { - DBG1(DBG_IKE, "received AUTH_LIFETIME of %ds, starting reauthentication", - lifetime); - charon->processor->queue_job(charon->processor, - (job_t*)rekey_ike_sa_job_create(this->ike_sa_id, TRUE)); - } - else if (this->stats[STAT_REAUTH] == 0 || - this->stats[STAT_REAUTH] > reauth_time) - { - this->stats[STAT_REAUTH] = reauth_time; - DBG1(DBG_IKE, "received AUTH_LIFETIME of %ds, scheduling reauthentication" - " in %ds", lifetime, lifetime - reduction); - charon->scheduler->schedule_job(charon->scheduler, - (job_t*)rekey_ike_sa_job_create(this->ike_sa_id, TRUE), - lifetime - reduction); - } - else - { - DBG1(DBG_IKE, "received AUTH_LIFETIME of %ds, " - "reauthentication already scheduled in %ds", lifetime, - this->stats[STAT_REAUTH] - time_monotonic(NULL)); - } -} - -/** - * Implementation of ike_sa_t.roam. - */ -static status_t roam(private_ike_sa_t *this, bool address) -{ - host_t *src; - ike_mobike_t *mobike; - - switch (this->state) - { - case IKE_CREATED: - case IKE_DELETING: - case IKE_DESTROYING: - case IKE_PASSIVE: - return SUCCESS; - default: - break; - } - /* responder just updates the peer about changed address config */ - if (!this->ike_sa_id->is_initiator(this->ike_sa_id)) - { - if (supports_extension(this, EXT_MOBIKE) && address) - { - 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); - 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 (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); - } - 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"); - 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 */ - return reauth(this); -} - -/** - * Implementation of ike_sa_t.add_configuration_attribute - */ -static void add_configuration_attribute(private_ike_sa_t *this, - attribute_handler_t *handler, - configuration_attribute_type_t type, chunk_t data) -{ - attribute_entry_t *entry = malloc_thing(attribute_entry_t); - - entry->handler = handler; - entry->type = type; - entry->data = chunk_clone(data); - - this->attributes->insert_last(this->attributes, entry); -} - -/** - * Implementation of ike_sa_t.inherit. - */ -static status_t inherit(private_ike_sa_t *this, private_ike_sa_t *other) -{ - child_sa_t *child_sa; - attribute_entry_t *entry; - - /* apply hosts and ids */ - this->my_host->destroy(this->my_host); - this->other_host->destroy(this->other_host); - this->my_id->destroy(this->my_id); - this->other_id->destroy(this->other_id); - this->my_host = other->my_host->clone(other->my_host); - this->other_host = other->other_host->clone(other->other_host); - this->my_id = other->my_id->clone(other->my_id); - this->other_id = other->other_id->clone(other->other_id); - - /* apply virtual assigned IPs... */ - if (other->my_virtual_ip) - { - this->my_virtual_ip = other->my_virtual_ip; - other->my_virtual_ip = NULL; - } - if (other->other_virtual_ip) - { - this->other_virtual_ip = other->other_virtual_ip; - other->other_virtual_ip = NULL; - } - - /* ... and configuration attributes */ - while (other->attributes->remove_last(other->attributes, - (void**)&entry) == SUCCESS) - { - this->attributes->insert_first(this->attributes, entry); - } - - /* inherit all conditions */ - this->conditions = other->conditions; - if (this->conditions & COND_NAT_HERE) - { - send_keepalive(this); - } - -#ifdef ME - if (other->is_mediation_server) - { - act_as_mediation_server(this); - } - else if (other->server_reflexive_host) - { - this->server_reflexive_host = other->server_reflexive_host->clone( - other->server_reflexive_host); - } -#endif /* ME */ - - /* adopt all children */ - while (other->child_sas->remove_last(other->child_sas, - (void**)&child_sa) == SUCCESS) - { - this->child_sas->insert_first(this->child_sas, (void*)child_sa); - } - - /* move pending tasks to the new IKE_SA */ - this->task_manager->adopt_tasks(this->task_manager, other->task_manager); - - /* reauthentication timeout survives a rekeying */ - if (other->stats[STAT_REAUTH]) - { - time_t reauth, delete, now = time_monotonic(NULL); - - this->stats[STAT_REAUTH] = other->stats[STAT_REAUTH]; - reauth = this->stats[STAT_REAUTH] - now; - delete = reauth + this->peer_cfg->get_over_time(this->peer_cfg); - 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, - (job_t*)rekey_ike_sa_job_create(this->ike_sa_id, TRUE), reauth); - charon->scheduler->schedule_job(charon->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 */ - return this->task_manager->initiate(this->task_manager); -} - -/** - * Implementation of ike_sa_t.destroy. - */ -static void destroy(private_ike_sa_t *this) -{ - attribute_entry_t *entry; - - charon->bus->set_sa(charon->bus, &this->public); - - set_state(this, IKE_DESTROYING); - - /* remove attributes first, as we pass the IKE_SA to the handler */ - while (this->attributes->remove_last(this->attributes, - (void**)&entry) == SUCCESS) - { - lib->attributes->release(lib->attributes, entry->handler, - this->other_id, entry->type, entry->data); - free(entry->data.ptr); - free(entry); - } - this->attributes->destroy(this->attributes); - - this->child_sas->destroy_offset(this->child_sas, offsetof(child_sa_t, destroy)); - - /* unset SA after here to avoid usage by the listeners */ - charon->bus->set_sa(charon->bus, NULL); - - this->task_manager->destroy(this->task_manager); - this->keymat->destroy(this->keymat); - - if (this->my_virtual_ip) - { - charon->kernel_interface->del_ip(charon->kernel_interface, - this->my_virtual_ip); - this->my_virtual_ip->destroy(this->my_virtual_ip); - } - if (this->other_virtual_ip) - { - if (this->peer_cfg && this->peer_cfg->get_pool(this->peer_cfg)) - { - lib->attributes->release_address(lib->attributes, - this->peer_cfg->get_pool(this->peer_cfg), - this->other_virtual_ip, this->other_id); - } - this->other_virtual_ip->destroy(this->other_virtual_ip); - } - this->additional_addresses->destroy_offset(this->additional_addresses, - offsetof(host_t, destroy)); -#ifdef ME - if (this->is_mediation_server) - { - charon->mediation_manager->remove(charon->mediation_manager, - this->ike_sa_id); - } - 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->local_host); - DESTROY_IF(this->remote_host); - - DESTROY_IF(this->ike_cfg); - DESTROY_IF(this->peer_cfg); - DESTROY_IF(this->proposal); - this->my_auth->destroy(this->my_auth); - this->other_auth->destroy(this->other_auth); - this->my_auths->destroy_offset(this->my_auths, - offsetof(auth_cfg_t, destroy)); - this->other_auths->destroy_offset(this->other_auths, - offsetof(auth_cfg_t, destroy)); - - this->ike_sa_id->destroy(this->ike_sa_id); - free(this); -} - -/* - * Described in header. - */ -ike_sa_t * ike_sa_create(ike_sa_id_t *ike_sa_id) -{ - private_ike_sa_t *this = malloc_thing(private_ike_sa_t); - static u_int32_t unique_id = 0; - - /* Public functions */ - this->public.get_state = (ike_sa_state_t (*)(ike_sa_t*)) get_state; - this->public.set_state = (void (*)(ike_sa_t*,ike_sa_state_t)) set_state; - this->public.get_name = (char* (*)(ike_sa_t*))get_name; - this->public.get_statistic = (u_int32_t(*)(ike_sa_t*, statistic_t kind))get_statistic; - this->public.process_message = (status_t (*)(ike_sa_t*, message_t*)) process_message; - this->public.initiate = (status_t (*)(ike_sa_t*,child_cfg_t*,u_int32_t,traffic_selector_t*,traffic_selector_t*)) initiate; - this->public.get_ike_cfg = (ike_cfg_t* (*)(ike_sa_t*))get_ike_cfg; - this->public.set_ike_cfg = (void (*)(ike_sa_t*,ike_cfg_t*))set_ike_cfg; - this->public.get_peer_cfg = (peer_cfg_t* (*)(ike_sa_t*))get_peer_cfg; - this->public.set_peer_cfg = (void (*)(ike_sa_t*,peer_cfg_t*))set_peer_cfg; - this->public.get_auth_cfg = (auth_cfg_t*(*)(ike_sa_t*, bool local))get_auth_cfg; - this->public.create_auth_cfg_enumerator = (enumerator_t*(*)(ike_sa_t*, bool local))create_auth_cfg_enumerator; - this->public.add_auth_cfg = (void(*)(ike_sa_t*, bool local, auth_cfg_t *cfg))add_auth_cfg; - this->public.get_proposal = (proposal_t*(*)(ike_sa_t*))get_proposal; - this->public.set_proposal = (void(*)(ike_sa_t*, proposal_t *proposal))set_proposal; - this->public.get_id = (ike_sa_id_t* (*)(ike_sa_t*)) get_id; - this->public.get_my_host = (host_t* (*)(ike_sa_t*)) get_my_host; - this->public.set_my_host = (void (*)(ike_sa_t*,host_t*)) set_my_host; - this->public.get_other_host = (host_t* (*)(ike_sa_t*)) get_other_host; - this->public.set_other_host = (void (*)(ike_sa_t*,host_t*)) set_other_host; - this->public.set_message_id = (void(*)(ike_sa_t*, bool inbound, u_int32_t mid))set_message_id; - this->public.update_hosts = (void(*)(ike_sa_t*, host_t *me, host_t *other))update_hosts; - this->public.get_my_id = (identification_t* (*)(ike_sa_t*)) get_my_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.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; - this->public.has_condition = (bool (*)(ike_sa_t*,ike_condition_t)) has_condition; - this->public.set_pending_updates = (void(*)(ike_sa_t*, u_int32_t updates))set_pending_updates; - this->public.get_pending_updates = (u_int32_t(*)(ike_sa_t*))get_pending_updates; - 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; - this->public.send_dpd = (status_t (*)(ike_sa_t*)) send_dpd; - this->public.send_keepalive = (void (*)(ike_sa_t*)) send_keepalive; - this->public.get_keymat = (keymat_t*(*)(ike_sa_t*))get_keymat; - this->public.add_child_sa = (void (*)(ike_sa_t*,child_sa_t*)) add_child_sa; - this->public.get_child_sa = (child_sa_t* (*)(ike_sa_t*,protocol_id_t,u_int32_t,bool)) get_child_sa; - this->public.create_child_sa_iterator = (iterator_t* (*)(ike_sa_t*)) create_child_sa_iterator; - this->public.rekey_child_sa = (status_t (*)(ike_sa_t*,protocol_id_t,u_int32_t)) rekey_child_sa; - this->public.delete_child_sa = (status_t (*)(ike_sa_t*,protocol_id_t,u_int32_t)) delete_child_sa; - this->public.destroy_child_sa = (status_t (*)(ike_sa_t*,protocol_id_t,u_int32_t))destroy_child_sa; - this->public.rekey = (status_t (*)(ike_sa_t*))rekey; - this->public.reauth = (status_t (*)(ike_sa_t*))reauth; - this->public.reestablish = (status_t (*)(ike_sa_t*))reestablish; - this->public.set_auth_lifetime = (void(*)(ike_sa_t*, u_int32_t lifetime))set_auth_lifetime; - this->public.roam = (status_t(*)(ike_sa_t*,bool))roam; - this->public.inherit = (status_t (*)(ike_sa_t*,ike_sa_t*))inherit; - this->public.generate_message = (status_t (*)(ike_sa_t*,message_t*,packet_t**))generate_message; - this->public.reset = (void (*)(ike_sa_t*))reset; - this->public.get_unique_id = (u_int32_t (*)(ike_sa_t*))get_unique_id; - this->public.set_virtual_ip = (void (*)(ike_sa_t*,bool,host_t*))set_virtual_ip; - this->public.get_virtual_ip = (host_t* (*)(ike_sa_t*,bool))get_virtual_ip; - this->public.add_configuration_attribute = (void(*)(ike_sa_t*, attribute_handler_t *handler,configuration_attribute_type_t type, chunk_t data))add_configuration_attribute; - this->public.set_kmaddress = (void (*)(ike_sa_t*,host_t*,host_t*))set_kmaddress; -#ifdef ME - this->public.act_as_mediation_server = (void (*)(ike_sa_t*)) act_as_mediation_server; - this->public.get_server_reflexive_host = (host_t* (*)(ike_sa_t*)) get_server_reflexive_host; - this->public.set_server_reflexive_host = (void (*)(ike_sa_t*,host_t*)) set_server_reflexive_host; - this->public.get_connect_id = (chunk_t (*)(ike_sa_t*)) get_connect_id; - this->public.initiate_mediation = (status_t (*)(ike_sa_t*,peer_cfg_t*)) initiate_mediation; - this->public.initiate_mediated = (status_t (*)(ike_sa_t*,host_t*,host_t*,chunk_t)) initiate_mediated; - this->public.relay = (status_t (*)(ike_sa_t*,identification_t*,chunk_t,chunk_t,linked_list_t*,bool)) relay; - this->public.callback = (status_t (*)(ike_sa_t*,identification_t*)) callback; - this->public.respond = (status_t (*)(ike_sa_t*,identification_t*,chunk_t)) respond; -#endif /* ME */ - - /* initialize private fields */ - this->ike_sa_id = ike_sa_id->clone(ike_sa_id); - this->child_sas = linked_list_create(); - this->my_host = host_create_any(AF_INET); - this->my_host->set_port(this->my_host, IKEV2_UDP_PORT); - this->other_host = host_create_any(AF_INET); - this->my_id = identification_create_from_encoding(ID_ANY, chunk_empty); - this->other_id = identification_create_from_encoding(ID_ANY, chunk_empty); - this->extensions = 0; - this->conditions = 0; - this->keymat = keymat_create(ike_sa_id->is_initiator(ike_sa_id)); - this->state = IKE_CREATED; - this->keepalive_interval = lib->settings->get_time(lib->settings, - "charon.keep_alive", KEEPALIVE_INTERVAL); - memset(this->stats, 0, sizeof(this->stats)); - this->stats[STAT_INBOUND] = this->stats[STAT_OUTBOUND] = time_monotonic(NULL); - this->ike_cfg = NULL; - this->peer_cfg = NULL; - this->my_auth = auth_cfg_create(); - this->other_auth = auth_cfg_create(); - this->my_auths = linked_list_create(); - this->other_auths = linked_list_create(); - this->proposal = NULL; - this->task_manager = task_manager_create(&this->public); - this->unique_id = ++unique_id; - this->my_virtual_ip = NULL; - this->other_virtual_ip = NULL; - this->additional_addresses = linked_list_create(); - this->attributes = linked_list_create(); - this->nat_detection_dest = chunk_empty; - this->pending_updates = 0; - this->keyingtry = 0; - this->local_host = NULL; - this->remote_host = NULL; -#ifdef ME - this->is_mediation_server = FALSE; - this->server_reflexive_host = NULL; - this->connect_id = chunk_empty; -#endif /* ME */ - - return &this->public; -} |