diff options
Diffstat (limited to 'src/libcharon/sa/ike_sa.c')
-rw-r--r-- | src/libcharon/sa/ike_sa.c | 451 |
1 files changed, 142 insertions, 309 deletions
diff --git a/src/libcharon/sa/ike_sa.c b/src/libcharon/sa/ike_sa.c index e0473e290..e94ebb15e 100644 --- a/src/libcharon/sa/ike_sa.c +++ b/src/libcharon/sa/ike_sa.c @@ -28,32 +28,15 @@ #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> -#include <encoding/payloads/unknown_payload.h> +#include <sa/ikev2/tasks/ike_auth_lifetime.h> #ifdef ME -#include <sa/tasks/ike_me.h> +#include <sa/ikev2/tasks/ike_me.h> #include <processing/jobs/initiate_mediation_job.h> #endif @@ -86,6 +69,11 @@ struct private_ike_sa_t { ike_sa_id_t *ike_sa_id; /** + * IKE version of this SA. + */ + ike_version_t version; + + /** * unique numerical ID for this IKE_SA. */ u_int32_t unique_id; @@ -246,6 +234,11 @@ struct private_ike_sa_t { * remote host address to be used for IKE, set via MIGRATE kernel message */ host_t *remote_host; + + /** + * Flush auth configs once established? + */ + bool flush_auth_cfg; }; /** @@ -314,6 +307,15 @@ METHOD(ike_sa_t, get_statistic, u_int32_t, return 0; } +METHOD(ike_sa_t, set_statistic, void, + private_ike_sa_t *this, statistic_t kind, u_int32_t value) +{ + if (kind < STAT_MAX) + { + this->stats[kind] = value; + } +} + METHOD(ike_sa_t, get_my_host, host_t*, private_ike_sa_t *this) { @@ -400,6 +402,9 @@ static void flush_auth_cfgs(private_ike_sa_t *this) { auth_cfg_t *cfg; + this->my_auth->purge(this->my_auth, FALSE); + this->other_auth->purge(this->other_auth, FALSE); + while (this->my_auths->remove_last(this->my_auths, (void**)&cfg) == SUCCESS) { @@ -579,26 +584,9 @@ METHOD(ike_sa_t, send_dpd, status_t, if (!delay || 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); + this->task_manager->queue_dpd(this->task_manager); + diff = 0; } } /* recheck in "interval" seconds */ @@ -607,7 +595,7 @@ METHOD(ike_sa_t, send_dpd, status_t, job = (job_t*)send_dpd_job_create(this->ike_sa_id); lib->scheduler->schedule_job(lib->scheduler, job, delay - diff); } - return SUCCESS; + return this->task_manager->initiate(this->task_manager); } METHOD(ike_sa_t, get_state, ike_sa_state_t, @@ -641,7 +629,7 @@ METHOD(ike_sa_t, set_state, void, /* 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); + t = this->peer_cfg->get_rekey_time(this->peer_cfg, TRUE); if (t && (this->stats[STAT_REKEY] == 0 || (this->stats[STAT_REKEY] > t + this->stats[STAT_ESTABLISHED]))) { @@ -650,7 +638,7 @@ METHOD(ike_sa_t, set_state, void, 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); + t = this->peer_cfg->get_reauth_time(this->peer_cfg, TRUE); if (t && (this->stats[STAT_REAUTH] == 0 || (this->stats[STAT_REAUTH] > t + this->stats[STAT_ESTABLISHED]))) { @@ -701,7 +689,14 @@ METHOD(ike_sa_t, set_state, void, if (trigger_dpd) { - send_dpd(this); + if (supports_extension(this, EXT_DPD)) + { + send_dpd(this); + } + else + { + DBG1(DBG_IKE, "DPD not supported by peer, disabled"); + } } } @@ -719,7 +714,8 @@ METHOD(ike_sa_t, reset, void, flush_auth_cfgs(this); this->keymat->destroy(this->keymat); - this->keymat = keymat_create(this->ike_sa_id->is_initiator(this->ike_sa_id)); + this->keymat = keymat_create(this->version, + this->ike_sa_id->is_initiator(this->ike_sa_id)); this->task_manager->reset(this->task_manager, 0, 0); } @@ -911,6 +907,8 @@ METHOD(ike_sa_t, update_hosts, void, 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 */ *packet = message->get_packet(message); @@ -918,44 +916,13 @@ 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); - charon->bus->message(charon->bus, message, FALSE); - return message->generate(message, - this->keymat->get_aead(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, chunk_t data) -{ - 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, data); - 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->bus->message(charon->bus, message, FALSE, TRUE); + status = message->generate(message, this->keymat, packet); + if (status == SUCCESS) { - charon->sender->send(charon->sender, packet); + charon->bus->message(charon->bus, message, FALSE, FALSE); } - response->destroy(response); + return status; } METHOD(ike_sa_t, set_kmaddress, void, @@ -1110,11 +1077,13 @@ METHOD(ike_sa_t, initiate, status_t, 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->my_host->is_anyaddr(this->my_host) || + this->other_host->is_anyaddr(this->other_host)) + { + resolve_hosts(this); + } if (this->other_host->is_anyaddr(this->other_host) #ifdef ME @@ -1122,39 +1091,14 @@ METHOD(ike_sa_t, initiate, status_t, #endif /* ME */ ) { - child_cfg->destroy(child_cfg); + DESTROY_IF(child_cfg); DBG1(DBG_IKE, "unable to initiate to %%any"); charon->bus->alert(charon->bus, ALERT_PEER_ADDR_FAILED); return DESTROY_ME; } set_condition(this, COND_ORIGINAL_INITIATOR, TRUE); - - task = (task_t*)ike_vendor_create(&this->public, TRUE); - this->task_manager->queue_task(this->task_manager, task); - task = (task_t*)ike_init_create(&this->public, TRUE, NULL); - 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 */ + this->task_manager->queue_ike(this->task_manager); } #ifdef ME @@ -1171,18 +1115,11 @@ METHOD(ike_sa_t, initiate, status_t, } else #endif /* ME */ + if (child_cfg) { /* 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); - + this->task_manager->queue_child(this->task_manager, child_cfg, reqid, + tsi, tsr); #ifdef ME if (this->peer_cfg->get_mediated_by(this->peer_cfg)) { @@ -1201,128 +1138,27 @@ METHOD(ike_sa_t, process_message, status_t, private_ike_sa_t *this, message_t *message) { status_t status; - bool is_request; - u_int8_t type = 0; 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_aead(this->keymat, TRUE)); - if (status == SUCCESS) - { /* check for unsupported critical payloads */ - enumerator_t *enumerator; - unknown_payload_t *unknown; - payload_t *payload; - - enumerator = message->create_payload_enumerator(message); - while (enumerator->enumerate(enumerator, &payload)) - { - unknown = (unknown_payload_t*)payload; - type = payload->get_type(payload); - if (!payload_is_known(type) && - unknown->is_critical(unknown)) - { - DBG1(DBG_ENC, "payload type %N is not supported, " - "but its critical!", payload_type_names, type); - status = NOT_SUPPORTED; - } - } - enumerator->destroy(enumerator); - } - if (status != SUCCESS) + if (message->get_major_version(message) != this->version) { - 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, - chunk_from_thing(type)); - this->task_manager->incr_mid(this->task_manager, FALSE); - } - break; - case PARSE_ERROR: - DBG1(DBG_IKE, "message parsing failed"); - if (is_request) - { - send_notify_response(this, message, - INVALID_SYNTAX, chunk_empty); - this->task_manager->incr_mid(this->task_manager, FALSE); - } - break; - case VERIFY_ERROR: - DBG1(DBG_IKE, "message verification failed"); - if (is_request) - { - send_notify_response(this, message, - INVALID_SYNTAX, chunk_empty); - this->task_manager->incr_mid(this->task_manager, FALSE); - } - break; - case FAILED: - DBG1(DBG_IKE, "integrity check failed"); - /* ignored */ - break; - case INVALID_STATE: - DBG1(DBG_IKE, "found encrypted message, but no keys available"); - default: - break; - } - } - DBG1(DBG_IKE, "%N %s with message ID %d processing failed", + DBG1(DBG_IKE, "ignoring %N IKEv%u exchange on %N SA", 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; - } + message->get_major_version(message), + ike_version_names, this->version); + /* TODO-IKEv1: fall back to IKEv1 if we receive an IKEv1 + * INVALID_MAJOR_VERSION on an IKEv2 SA. */ + return FAILED; } - else + status = this->task_manager->process_message(this->task_manager, message); + if (this->flush_auth_cfg && this->state == IKE_ESTABLISHED) { - /* 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) - { - /* 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, chunk_empty); - 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); - lib->scheduler->schedule_job(lib->scheduler, job, - lib->settings->get_int(lib->settings, - "charon.half_open_timeout", HALF_OPEN_IKE_SA_TIMEOUT)); - } - this->stats[STAT_INBOUND] = time_monotonic(NULL); - status = this->task_manager->process_message(this->task_manager, - message); - if (message->get_exchange_type(message) == IKE_AUTH && - this->state == IKE_ESTABLISHED && - lib->settings->get_bool(lib->settings, - "charon.flush_auth_cfg", FALSE)) - { /* authentication completed */ - flush_auth_cfgs(this); - } + /* authentication completed */ + this->flush_auth_cfg = FALSE; + flush_auth_cfgs(this); } return status; } @@ -1333,6 +1169,12 @@ METHOD(ike_sa_t, get_id, ike_sa_id_t*, return this->ike_sa_id; } +METHOD(ike_sa_t, get_version, ike_version_t, + private_ike_sa_t *this) +{ + return this->version; +} + METHOD(ike_sa_t, get_my_id, identification_t*, private_ike_sa_t *this) { @@ -1366,6 +1208,10 @@ METHOD(ike_sa_t, get_other_eap_id, identification_t*, current = cfg->get(cfg, AUTH_RULE_EAP_IDENTITY); if (!current || current->get_type(current) == ID_ANY) { + current = cfg->get(cfg, AUTH_RULE_XAUTH_IDENTITY); + } + if (!current || current->get_type(current) == ID_ANY) + { current = cfg->get(cfg, AUTH_RULE_IDENTITY); } if (current && current->get_type(current) != ID_ANY) @@ -1435,30 +1281,23 @@ METHOD(ike_sa_t, remove_child_sa, void, METHOD(ike_sa_t, rekey_child_sa, status_t, private_ike_sa_t *this, protocol_id_t protocol, u_int32_t spi) { - child_rekey_t *child_rekey; - if (this->state == IKE_PASSIVE) { return INVALID_STATE; } - - child_rekey = child_rekey_create(&this->public, protocol, spi); - this->task_manager->queue_task(this->task_manager, &child_rekey->task); + this->task_manager->queue_child_rekey(this->task_manager, protocol, spi); return this->task_manager->initiate(this->task_manager); } METHOD(ike_sa_t, delete_child_sa, status_t, - private_ike_sa_t *this, protocol_id_t protocol, u_int32_t spi) + private_ike_sa_t *this, protocol_id_t protocol, u_int32_t spi, bool expired) { - child_delete_t *child_delete; - if (this->state == IKE_PASSIVE) { return INVALID_STATE; } - - child_delete = child_delete_create(&this->public, protocol, spi); - this->task_manager->queue_task(this->task_manager, &child_delete->task); + this->task_manager->queue_child_delete(this->task_manager, + protocol, spi, expired); return this->task_manager->initiate(this->task_manager); } @@ -1488,14 +1327,17 @@ METHOD(ike_sa_t, destroy_child_sa, status_t, METHOD(ike_sa_t, delete_, status_t, 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); + if (this->version == IKEV1) + { /* SA has been reauthenticated, delete */ + charon->bus->ike_updown(charon->bus, &this->public, FALSE); + break; + } + /* FALL */ + case IKE_ESTABLISHED: + this->task_manager->queue_ike_delete(this->task_manager); return this->task_manager->initiate(this->task_manager); case IKE_CREATED: DBG1(DBG_IKE, "deleting unestablished IKE_SA"); @@ -1514,23 +1356,17 @@ METHOD(ike_sa_t, delete_, status_t, METHOD(ike_sa_t, rekey, status_t, private_ike_sa_t *this) { - ike_rekey_t *ike_rekey; - if (this->state == IKE_PASSIVE) { return INVALID_STATE; } - ike_rekey = ike_rekey_create(&this->public, TRUE); - - this->task_manager->queue_task(this->task_manager, &ike_rekey->task); + this->task_manager->queue_ike_rekey(this->task_manager); return this->task_manager->initiate(this->task_manager); } METHOD(ike_sa_t, reauth, status_t, private_ike_sa_t *this) { - task_t *task; - if (this->state == IKE_PASSIVE) { return INVALID_STATE; @@ -1542,6 +1378,7 @@ METHOD(ike_sa_t, reauth, status_t, { DBG1(DBG_IKE, "initiator did not reauthenticate as requested"); if (this->other_virtual_ip != NULL || + has_condition(this, COND_XAUTH_AUTHENTICATED) || has_condition(this, COND_EAP_AUTHENTICATED) #ifdef ME /* as mediation server we too cannot reauth the IKE_SA */ @@ -1568,9 +1405,7 @@ METHOD(ike_sa_t, reauth, status_t, DBG0(DBG_IKE, "reauthenticating IKE_SA %s[%d]", get_name(this), this->unique_id); } - task = (task_t*)ike_reauth_create(&this->public); - this->task_manager->queue_task(this->task_manager, task); - + this->task_manager->queue_ike_reauth(this->task_manager); return this->task_manager->initiate(this->task_manager); } @@ -1637,7 +1472,12 @@ METHOD(ike_sa_t, reestablish, status_t, return FAILED; } - new = charon->ike_sa_manager->checkout_new(charon->ike_sa_manager, TRUE); + new = charon->ike_sa_manager->checkout_new(charon->ike_sa_manager, + this->version, TRUE); + if (!new) + { + return FAILED; + } new->set_peer_cfg(new, this->peer_cfg); host = this->other_host; new->set_other_host(new, host->clone(host)); @@ -1703,40 +1543,6 @@ METHOD(ike_sa_t, reestablish, status_t, return status; } -/** - * Requeue the IKE_SA_INIT tasks for initiation, if required - */ -static void requeue_init_tasks(private_ike_sa_t *this) -{ - enumerator_t *enumerator; - bool has_init = FALSE; - task_t *task; - - /* if we have advanced to IKE_AUTH, the IKE_INIT and related tasks - * have already completed. Recreate them if necessary. */ - enumerator = this->task_manager->create_task_enumerator( - this->task_manager, TASK_QUEUE_QUEUED); - while (enumerator->enumerate(enumerator, &task)) - { - if (task->get_type(task) == IKE_INIT) - { - has_init = TRUE; - break; - } - } - enumerator->destroy(enumerator); - - if (!has_init) - { - 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_init_create(&this->public, TRUE, NULL); - this->task_manager->queue_task(this->task_manager, task); - } -} - METHOD(ike_sa_t, retransmit, status_t, private_ike_sa_t *this, u_int32_t message_id) { @@ -1752,7 +1558,7 @@ METHOD(ike_sa_t, retransmit, status_t, { case IKE_CONNECTING: { - /* retry IKE_SA_INIT if we have multiple keyingtries */ + /* retry IKE_SA_INIT/Main Mode 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) @@ -1761,7 +1567,7 @@ METHOD(ike_sa_t, retransmit, status_t, this->keyingtry + 1, tries); reset(this); resolve_hosts(this); - requeue_init_tasks(this); + this->task_manager->queue_ike(this->task_manager); return this->task_manager->initiate(this->task_manager); } DBG1(DBG_IKE, "establishing IKE_SA failed, peer not responding"); @@ -1796,7 +1602,7 @@ METHOD(ike_sa_t, set_auth_lifetime, status_t, /* check if we have to send an AUTH_LIFETIME to enforce the new lifetime. * We send the notify in IKE_AUTH if not yet ESTABLISHED. */ - send_update = this->state == IKE_ESTABLISHED && + send_update = this->state == IKE_ESTABLISHED && this->version == IKEV2 && !has_condition(this, COND_ORIGINAL_INITIATOR) && (this->other_virtual_ip != NULL || has_condition(this, COND_EAP_AUTHENTICATED)); @@ -1899,8 +1705,6 @@ static bool is_any_path_valid(private_ike_sa_t *this) METHOD(ike_sa_t, roam, status_t, private_ike_sa_t *this, bool address) { - ike_mobike_t *mobike; - switch (this->state) { case IKE_CREATED: @@ -1922,10 +1726,7 @@ METHOD(ike_sa_t, roam, status_t, 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); - mobike->addresses(mobike); - this->task_manager->queue_task(this->task_manager, - (task_t*)mobike); + this->task_manager->queue_mobike(this->task_manager, FALSE, TRUE); return this->task_manager->initiate(this->task_manager); } return SUCCESS; @@ -1953,9 +1754,7 @@ METHOD(ike_sa_t, roam, status_t, { 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); + this->task_manager->queue_mobike(this->task_manager, TRUE, address); return this->task_manager->initiate(this->task_manager); } @@ -1988,6 +1787,12 @@ METHOD(ike_sa_t, create_task_enumerator, enumerator_t*, return this->task_manager->create_task_enumerator(this->task_manager, queue); } +METHOD(ike_sa_t, queue_task, void, + private_ike_sa_t *this, task_t *task) +{ + this->task_manager->queue_task(this->task_manager, task); +} + METHOD(ike_sa_t, inherit, void, private_ike_sa_t *this, ike_sa_t *other_public) { @@ -2095,7 +1900,7 @@ METHOD(ike_sa_t, destroy, void, charon->bus->set_sa(charon->bus, &this->public); set_state(this, IKE_DESTROYING); - this->task_manager->destroy(this->task_manager); + DESTROY_IF(this->task_manager); /* remove attributes first, as we pass the IKE_SA to the handler */ while (this->attributes->remove_last(this->attributes, @@ -2113,7 +1918,7 @@ METHOD(ike_sa_t, destroy, void, /* unset SA after here to avoid usage by the listeners */ charon->bus->set_sa(charon->bus, NULL); - this->keymat->destroy(this->keymat); + DESTROY_IF(this->keymat); if (this->my_virtual_ip) { @@ -2168,17 +1973,29 @@ METHOD(ike_sa_t, destroy, void, /* * Described in header. */ -ike_sa_t * ike_sa_create(ike_sa_id_t *ike_sa_id) +ike_sa_t * ike_sa_create(ike_sa_id_t *ike_sa_id, bool initiator, + ike_version_t version) { private_ike_sa_t *this; static u_int32_t unique_id = 0; + if (version == IKE_ANY) + { /* prefer IKEv2 if protocol not specified */ +#ifdef USE_IKEV2 + version = IKEV2; +#else + version = IKEV1; +#endif + } + INIT(this, .public = { + .get_version = _get_version, .get_state = _get_state, .set_state = _set_state, .get_name = _get_name, .get_statistic = _get_statistic, + .set_statistic = _set_statistic, .process_message = _process_message, .initiate = _initiate, .get_ike_cfg = _get_ike_cfg, @@ -2241,6 +2058,7 @@ ike_sa_t * ike_sa_create(ike_sa_id_t *ike_sa_id) .add_configuration_attribute = _add_configuration_attribute, .set_kmaddress = _set_kmaddress, .create_task_enumerator = _create_task_enumerator, + .queue_task = _queue_task, #ifdef ME .act_as_mediation_server = _act_as_mediation_server, .get_server_reflexive_host = _get_server_reflexive_host, @@ -2254,12 +2072,13 @@ ike_sa_t * ike_sa_create(ike_sa_id_t *ike_sa_id) #endif /* ME */ }, .ike_sa_id = ike_sa_id->clone(ike_sa_id), + .version = version, .child_sas = linked_list_create(), .my_host = host_create_any(AF_INET), .other_host = host_create_any(AF_INET), .my_id = identification_create_from_encoding(ID_ANY, chunk_empty), .other_id = identification_create_from_encoding(ID_ANY, chunk_empty), - .keymat = keymat_create(ike_sa_id->is_initiator(ike_sa_id)), + .keymat = keymat_create(version, initiator), .state = IKE_CREATED, .stats[STAT_INBOUND] = time_monotonic(NULL), .stats[STAT_OUTBOUND] = time_monotonic(NULL), @@ -2272,9 +2091,23 @@ ike_sa_t * ike_sa_create(ike_sa_id_t *ike_sa_id) .attributes = linked_list_create(), .keepalive_interval = lib->settings->get_time(lib->settings, "charon.keep_alive", KEEPALIVE_INTERVAL), + .flush_auth_cfg = lib->settings->get_bool(lib->settings, + "charon.flush_auth_cfg", FALSE), ); + + if (version == IKEV2) + { /* always supported with IKEv2 */ + enable_extension(this, EXT_DPD); + } + this->task_manager = task_manager_create(&this->public); this->my_host->set_port(this->my_host, IKEV2_UDP_PORT); + if (!this->task_manager || !this->keymat) + { + DBG1(DBG_IKE, "IKE version %d not supported", this->version); + destroy(this); + return NULL; + } return &this->public; } |