From 08ee5250bd9c43fda5f24d10b791ca2c4c17fcee Mon Sep 17 00:00:00 2001 From: Rene Mayrhofer Date: Sun, 3 Jun 2007 17:36:35 +0000 Subject: [svn-upgrade] Integrating new upstream version, strongswan (4.1.3) --- src/charon/sa/authenticators/eap/eap_method.c | 35 +- src/charon/sa/authenticators/eap/eap_sim.c | 104 +++- src/charon/sa/authenticators/eap_authenticator.c | 58 +- src/charon/sa/authenticators/psk_authenticator.c | 10 +- src/charon/sa/authenticators/rsa_authenticator.c | 37 +- src/charon/sa/child_sa.c | 231 +++----- src/charon/sa/child_sa.h | 44 +- src/charon/sa/ike_sa.c | 713 +++++++++++------------ src/charon/sa/ike_sa.h | 124 ++-- src/charon/sa/ike_sa_id.c | 28 - src/charon/sa/ike_sa_manager.c | 24 +- src/charon/sa/task_manager.c | 22 +- src/charon/sa/task_manager.h | 40 ++ src/charon/sa/tasks/child_create.c | 259 +++++--- src/charon/sa/tasks/child_create.h | 6 +- src/charon/sa/tasks/child_delete.c | 22 + src/charon/sa/tasks/child_rekey.c | 19 +- src/charon/sa/tasks/ike_auth.c | 66 ++- src/charon/sa/tasks/ike_cert.c | 50 +- src/charon/sa/tasks/ike_config.c | 45 +- src/charon/sa/tasks/ike_config.h | 5 +- src/charon/sa/tasks/ike_delete.c | 3 +- src/charon/sa/tasks/ike_init.c | 137 ++--- src/charon/sa/tasks/ike_rekey.c | 77 +-- 24 files changed, 1174 insertions(+), 985 deletions(-) (limited to 'src/charon/sa') diff --git a/src/charon/sa/authenticators/eap/eap_method.c b/src/charon/sa/authenticators/eap/eap_method.c index a4d8abb58..e4a58f0a3 100644 --- a/src/charon/sa/authenticators/eap/eap_method.c +++ b/src/charon/sa/authenticators/eap/eap_method.c @@ -85,7 +85,7 @@ void eap_method_unload() while (modules->remove_last(modules, (void**)&entry) == SUCCESS) { - DBG2(DBG_CFG, "unloaded module for %s", eap_type_names, entry->type); + DBG2(DBG_CFG, "unloaded module for %N", eap_type_names, entry->type); dlclose(entry->handle); free(entry); } @@ -100,27 +100,10 @@ void eap_method_unload() void eap_method_load(char *directory) { struct dirent* entry; - struct stat stb; DIR* dir; eap_method_unload(); modules = linked_list_create(); - - if (stat(directory, &stb) == -1 || !(stb.st_mode & S_IFDIR)) - { - DBG1(DBG_CFG, "error opening EAP modules directory %s", directory); - return; - } - if (stb.st_uid != 0) - { - DBG1(DBG_CFG, "EAP modules directory %s not owned by root, skipped", directory); - return; - } - if (stb.st_mode & S_IWOTH || stb.st_mode & S_IWGRP) - { - DBG1(DBG_CFG, "EAP modules directory %s writable by others, skipped", directory); - return; - } dir = opendir(directory); if (dir == NULL) @@ -141,12 +124,6 @@ void eap_method_load(char *directory) snprintf(file, sizeof(file), "%s/%s", directory, entry->d_name); - if (stat(file, &stb) == -1 || !(stb.st_mode & S_IFREG)) - { - DBG2(DBG_CFG, " skipping %s, doesn't look like a file", - entry->d_name); - continue; - } ending = entry->d_name + strlen(entry->d_name) - 3; if (ending <= entry->d_name || !streq(ending, ".so")) { @@ -155,16 +132,6 @@ void eap_method_load(char *directory) entry->d_name); continue; } - if (stb.st_uid != 0) - { - DBG1(DBG_CFG, " skipping %s, file is not owned by root", entry->d_name); - return; - } - if (stb.st_mode & S_IWOTH || stb.st_mode & S_IWGRP) - { - DBG1(DBG_CFG, " skipping %s, file is writeable by others", entry->d_name); - continue; - } /* try to load the library */ module.handle = dlopen(file, RTLD_LAZY); diff --git a/src/charon/sa/authenticators/eap/eap_sim.c b/src/charon/sa/authenticators/eap/eap_sim.c index 3dc59fb6b..38d7f2534 100644 --- a/src/charon/sa/authenticators/eap/eap_sim.c +++ b/src/charon/sa/authenticators/eap/eap_sim.c @@ -398,6 +398,30 @@ static status_t process_start(private_eap_sim_t *this, eap_payload_t *in, /* only include AT_IDENTITY if requested */ include_id = AT_IDENTITY; break; + case AT_NOTIFICATION: + { + u_int16_t code = 0; + if (data.len == 2) + { + code = ntohs(*(u_int16_t*)data.ptr); + } + if (code <= 32767) /* no success bit */ + { + DBG1(DBG_IKE, "received %N error %d", + sim_attribute_names, attribute, code); + *out = build_payload(this, + in->get_identifier(in), SIM_CLIENT_ERROR, + AT_CLIENT_ERROR_CODE, client_error_general, + AT_END); + return NEED_MORE; + } + else + { + DBG1(DBG_IKE, "received %N code %d", + sim_attribute_names, attribute, code); + } + break; + } default: DBG1(DBG_IKE, "ignoring EAP_SIM attribute %N", sim_attribute_names, attribute); @@ -456,6 +480,30 @@ static status_t process_challenge(private_eap_sim_t *this, eap_payload_t *in, memset(data.ptr, 0, data.len); break; } + case AT_NOTIFICATION: + { + u_int16_t code = 0; + if (data.len == 2) + { + code = ntohs(*(u_int16_t*)data.ptr); + } + if (code <= 32767) /* no success bit */ + { + DBG1(DBG_IKE, "received %N error %d", + sim_attribute_names, attribute, code); + *out = build_payload(this, + in->get_identifier(in), SIM_CLIENT_ERROR, + AT_CLIENT_ERROR_CODE, client_error_general, + AT_END); + return NEED_MORE; + } + else + { + DBG1(DBG_IKE, "received %N code %d", + sim_attribute_names, attribute, code); + } + break; + } default: DBG1(DBG_IKE, "ignoring EAP_SIM attribute %N", sim_attribute_names, attribute); @@ -472,7 +520,7 @@ static status_t process_challenge(private_eap_sim_t *this, eap_payload_t *in, *out = build_payload(this, identifier, SIM_CLIENT_ERROR, AT_CLIENT_ERROR_CODE, client_error_insufficient, AT_END); - return FAILED; + return NEED_MORE; } if (mac.len != MAC_LEN) { @@ -556,6 +604,58 @@ static status_t process_challenge(private_eap_sim_t *this, eap_payload_t *in, return NEED_MORE; } +/** + * process an EAP-SIM/Request/Notification message + */ +static status_t process_notification(private_eap_sim_t *this, eap_payload_t *in, + eap_payload_t **out) +{ + chunk_t message, data; + sim_attribute_t attribute; + + message = in->get_data(in); + read_header(&message); + + while ((attribute = read_attribute(&message, &data)) != AT_END) + { + switch (attribute) + { + case AT_NOTIFICATION: + { + u_int16_t code = 0; + if (data.len == 2) + { + code = ntohs(*(u_int16_t*)data.ptr); + } + if (code <= 32767) /* no success bit */ + { + DBG1(DBG_IKE, "received %N error %d", + sim_attribute_names, attribute, code); + *out = build_payload(this, + in->get_identifier(in), SIM_CLIENT_ERROR, + AT_CLIENT_ERROR_CODE, client_error_general, + AT_END); + return NEED_MORE; + } + else + { + DBG1(DBG_IKE, "received %N code %d", + sim_attribute_names, attribute, code); + } + break; + } + default: + DBG1(DBG_IKE, "ignoring EAP_SIM attribute %N", + sim_attribute_names, attribute); + break; + } + } + /* reply with empty notification */ + *out = build_payload(this, in->get_identifier(in), SIM_NOTIFICATION, AT_END); + return NEED_MORE; +} + + /** * Implementation of eap_method_t.process for the peer */ @@ -574,6 +674,8 @@ static status_t process(private_eap_sim_t *this, return process_start(this, in, out); case SIM_CHALLENGE: return process_challenge(this, in, out); + case SIM_NOTIFICATION: + return process_notification(this, in, out); default: DBG1(DBG_IKE, "unable to process EAP_SIM subtype %N", sim_subtype_names, type); diff --git a/src/charon/sa/authenticators/eap_authenticator.c b/src/charon/sa/authenticators/eap_authenticator.c index 6c8ca8d8f..6e2f73a43 100644 --- a/src/charon/sa/authenticators/eap_authenticator.c +++ b/src/charon/sa/authenticators/eap_authenticator.c @@ -25,7 +25,7 @@ #include "eap_authenticator.h" #include -#include +#include #include typedef struct private_eap_authenticator_t private_eap_authenticator_t; @@ -61,21 +61,31 @@ struct private_eap_authenticator_t { chunk_t msk; }; +/** + * reuse shared key signature function from PSK authenticator + */ extern chunk_t build_shared_key_signature(chunk_t ike_sa_init, chunk_t nonce, - chunk_t secret, identification_t *id, - prf_t *prf_skp, prf_t *prf); - + chunk_t secret, identification_t *id, + chunk_t skp, prf_t *prf); /** * Implementation of authenticator_t.verify. */ static status_t verify(private_eap_authenticator_t *this, chunk_t ike_sa_init, chunk_t my_nonce, auth_payload_t *auth_payload) { - chunk_t auth_data, recv_auth_data; + chunk_t auth_data, recv_auth_data, secret; identification_t *other_id = this->ike_sa->get_other_id(this->ike_sa); - auth_data = build_shared_key_signature(ike_sa_init, my_nonce, this->msk, - other_id, this->ike_sa->get_auth_verify(this->ike_sa), + if (this->msk.len) + { /* use MSK if EAP method established one... */ + secret = this->msk; + } + else + { /* ... or use SKp if not */ + secret = this->ike_sa->get_skp_verify(this->ike_sa); + } + auth_data = build_shared_key_signature(ike_sa_init, my_nonce, secret, + other_id, this->ike_sa->get_skp_verify(this->ike_sa), this->ike_sa->get_prf(this->ike_sa)); recv_auth_data = auth_payload->get_data(auth_payload); @@ -98,14 +108,22 @@ static status_t verify(private_eap_authenticator_t *this, chunk_t ike_sa_init, static status_t build(private_eap_authenticator_t *this, chunk_t ike_sa_init, chunk_t other_nonce, auth_payload_t **auth_payload) { - chunk_t auth_data; + chunk_t auth_data, secret; identification_t *my_id = this->ike_sa->get_my_id(this->ike_sa); DBG1(DBG_IKE, "authentication of '%D' (myself) with %N", my_id, auth_method_names, AUTH_EAP); - - auth_data = build_shared_key_signature(ike_sa_init, other_nonce, this->msk, - my_id, this->ike_sa->get_auth_build(this->ike_sa), + + if (this->msk.len) + { /* use MSK if EAP method established one... */ + secret = this->msk; + } + else + { /* ... or use SKp if not */ + secret = this->ike_sa->get_skp_build(this->ike_sa); + } + auth_data = build_shared_key_signature(ike_sa_init, other_nonce, secret, + my_id, this->ike_sa->get_skp_build(this->ike_sa), this->ike_sa->get_prf(this->ike_sa)); *auth_payload = auth_payload_create(); @@ -233,13 +251,14 @@ static status_t process_server(private_eap_authenticator_t *this, DBG1(DBG_IKE, "EAP method %N succeded, MSK established", eap_type_names, this->method->get_type(this->method)); this->msk = chunk_clone(this->msk); - *out = eap_payload_create_code(EAP_SUCCESS); - return SUCCESS; } - DBG1(DBG_IKE, "EAP method %N succeded, but no MSK established", - eap_type_names, this->method->get_type(this->method)); - *out = eap_payload_create_code(EAP_FAILURE); - return FAILED; + else + { + DBG1(DBG_IKE, "EAP method %N succeded, no MSK established", + eap_type_names, this->method->get_type(this->method)); + } + *out = eap_payload_create_code(EAP_SUCCESS); + return SUCCESS; case FAILED: default: DBG1(DBG_IKE, "EAP method %N failed for peer %D", @@ -290,11 +309,8 @@ static status_t process(private_eap_authenticator_t *this, eap_payload_t *in, if (this->method->get_msk(this->method, &this->msk) == SUCCESS) { this->msk = chunk_clone(this->msk); - return SUCCESS; } - DBG1(DBG_IKE, "EAP method %N has no MSK established", - eap_type_names, this->method->get_type(this->method)); - return FAILED; + return SUCCESS; } case EAP_FAILURE: default: diff --git a/src/charon/sa/authenticators/psk_authenticator.c b/src/charon/sa/authenticators/psk_authenticator.c index 43aec0971..37465d029 100644 --- a/src/charon/sa/authenticators/psk_authenticator.c +++ b/src/charon/sa/authenticators/psk_authenticator.c @@ -25,7 +25,6 @@ #include "psk_authenticator.h" -#include #include /** @@ -78,11 +77,12 @@ chunk_t build_tbs_octets(chunk_t ike_sa_init, chunk_t nonce, */ chunk_t build_shared_key_signature(chunk_t ike_sa_init, chunk_t nonce, chunk_t secret, identification_t *id, - prf_t *prf_skp, prf_t *prf) + chunk_t skp, prf_t *prf) { chunk_t key_pad, key, auth_data, octets; - octets = build_tbs_octets(ike_sa_init, nonce, id, prf_skp); + prf->set_key(prf, skp); + octets = build_tbs_octets(ike_sa_init, nonce, id, prf); /* AUTH = prf(prf(Shared Secret,"Key Pad for IKEv2"), ) */ key_pad.ptr = IKEV2_KEY_PAD; key_pad.len = IKEV2_KEY_PAD_LENGTH; @@ -122,7 +122,7 @@ static status_t verify(private_psk_authenticator_t *this, chunk_t ike_sa_init, } auth_data = build_shared_key_signature(ike_sa_init, my_nonce, shared_key, - other_id, this->ike_sa->get_auth_verify(this->ike_sa), + other_id, this->ike_sa->get_skp_verify(this->ike_sa), this->ike_sa->get_prf(this->ike_sa)); chunk_free(&shared_key); @@ -165,7 +165,7 @@ static status_t build(private_psk_authenticator_t *this, chunk_t ike_sa_init, } auth_data = build_shared_key_signature(ike_sa_init, other_nonce, shared_key, - my_id, this->ike_sa->get_auth_build(this->ike_sa), + my_id, this->ike_sa->get_skp_build(this->ike_sa), this->ike_sa->get_prf(this->ike_sa)); DBG2(DBG_IKE, "successfully created shared key MAC"); chunk_free(&shared_key); diff --git a/src/charon/sa/authenticators/rsa_authenticator.c b/src/charon/sa/authenticators/rsa_authenticator.c index dfa01e332..e5c5cd60e 100644 --- a/src/charon/sa/authenticators/rsa_authenticator.c +++ b/src/charon/sa/authenticators/rsa_authenticator.c @@ -25,7 +25,6 @@ #include "rsa_authenticator.h" -#include #include @@ -61,8 +60,9 @@ static status_t verify(private_rsa_authenticator_t *this, chunk_t ike_sa_init, { status_t status; chunk_t auth_data, octets; - rsa_public_key_t *public_key; identification_t *other_id; + ca_info_t *issuer; + prf_t *prf; other_id = this->ike_sa->get_other_id(this->ike_sa); @@ -71,27 +71,20 @@ static status_t verify(private_rsa_authenticator_t *this, chunk_t ike_sa_init, return INVALID_ARG; } auth_data = auth_payload->get_data(auth_payload); - public_key = charon->credentials->get_trusted_public_key(charon->credentials, - other_id); - if (public_key == NULL) - { - DBG1(DBG_IKE, "no RSA public key found for '%D'", other_id); - return NOT_FOUND; - } - octets = build_tbs_octets(ike_sa_init, my_nonce, other_id, - this->ike_sa->get_auth_verify(this->ike_sa)); - status = public_key->verify_emsa_pkcs1_signature(public_key, octets, auth_data); + prf = this->ike_sa->get_prf(this->ike_sa); + prf->set_key(prf, this->ike_sa->get_skp_verify(this->ike_sa)); + octets = build_tbs_octets(ike_sa_init, my_nonce, other_id, prf); + status = charon->credentials->verify_signature(charon->credentials, + octets, auth_data, other_id, &issuer); chunk_free(&octets); - if (status != SUCCESS) + if (status == SUCCESS) { - DBG1(DBG_IKE, "RSA signature verification failed"); - return status; + this->ike_sa->set_other_ca(this->ike_sa, issuer); + DBG1(DBG_IKE, "authentication of '%D' with %N successful", + other_id, auth_method_names, AUTH_RSA); } - - DBG1(DBG_IKE, "authentication of '%D' with %N successful", - other_id, auth_method_names, AUTH_RSA); - return SUCCESS; + return status; } /** @@ -107,6 +100,7 @@ static status_t build(private_rsa_authenticator_t *this, chunk_t ike_sa_init, rsa_public_key_t *my_pubkey; rsa_private_key_t *my_key; identification_t *my_id; + prf_t *prf; my_id = this->ike_sa->get_my_id(this->ike_sa); DBG1(DBG_IKE, "authentication of '%D' (myself) with %N", @@ -131,8 +125,9 @@ static status_t build(private_rsa_authenticator_t *this, chunk_t ike_sa_init, } DBG2(DBG_IKE, "matching RSA private key found"); - octets = build_tbs_octets(ike_sa_init, other_nonce, my_id, - this->ike_sa->get_auth_build(this->ike_sa)); + prf = this->ike_sa->get_prf(this->ike_sa); + prf->set_key(prf, this->ike_sa->get_skp_build(this->ike_sa)); + octets = build_tbs_octets(ike_sa_init, other_nonce, my_id, prf); status = my_key->build_emsa_pkcs1_signature(my_key, HASH_SHA1, octets, &auth_data); chunk_free(&octets); diff --git a/src/charon/sa/child_sa.c b/src/charon/sa/child_sa.c index 19131389d..1e7b6cb2c 100644 --- a/src/charon/sa/child_sa.c +++ b/src/charon/sa/child_sa.c @@ -27,7 +27,6 @@ #include #include -#include #include @@ -154,9 +153,9 @@ struct private_child_sa_t { host_t *virtual_ip; /** - * policy used to create this child + * config used to create this child */ - policy_t *policy; + child_cfg_t *config; }; /** @@ -164,7 +163,7 @@ struct private_child_sa_t { */ static char *get_name(private_child_sa_t *this) { - return this->policy->get_name(this->policy);; + return this->config->get_name(this->config); } /** @@ -204,11 +203,57 @@ static child_sa_state_t get_state(private_child_sa_t *this) } /** - * Implements child_sa_t.get_policy + * Implements child_sa_t.get_config */ -static policy_t* get_policy(private_child_sa_t *this) +static child_cfg_t* get_config(private_child_sa_t *this) { - return this->policy; + return this->config; +} + +/** + * Implementation of child_sa_t.get_stats. + */ +static void get_stats(private_child_sa_t *this, mode_t *mode, + encryption_algorithm_t *encr_algo, size_t *encr_len, + integrity_algorithm_t *int_algo, size_t *int_len, + u_int32_t *rekey, u_int32_t *use_in, u_int32_t *use_out, + u_int32_t *use_fwd) +{ + sa_policy_t *policy; + iterator_t *iterator; + u_int32_t in = 0, out = 0, fwd = 0, time; + + iterator = this->policies->create_iterator(this->policies, TRUE); + while (iterator->iterate(iterator, (void**)&policy)) + { + + if (charon->kernel_interface->query_policy(charon->kernel_interface, + policy->other_ts, policy->my_ts, POLICY_IN, &time) == SUCCESS) + { + in = max(in, time); + } + if (charon->kernel_interface->query_policy(charon->kernel_interface, + policy->my_ts, policy->other_ts, POLICY_OUT, &time) == SUCCESS) + { + out = max(out, time); + } + if (charon->kernel_interface->query_policy(charon->kernel_interface, + policy->other_ts, policy->my_ts, POLICY_FWD, &time) == SUCCESS) + { + fwd = max(fwd, time); + } + } + iterator->destroy(iterator); + + *mode = this->mode; + *encr_algo = this->encryption.algorithm; + *encr_len = this->encryption.key_size; + *int_algo = this->integrity.algorithm; + *int_len = this->integrity.key_size; + *rekey = this->rekey_time; + *use_in = in; + *use_out = out; + *use_fwd = fwd; } /** @@ -220,7 +265,7 @@ static void updown(private_child_sa_t *this, bool up) iterator_t *iterator; char *script; - script = this->policy->get_updown(this->policy); + script = this->config->get_updown(this->config); if (script == NULL) { @@ -300,7 +345,7 @@ static void updown(private_child_sa_t *this, bool up) policy->my_ts->is_host(policy->my_ts, this->me.addr) ? "-host" : "-client", this->me.addr->get_family(this->me.addr) == AF_INET ? "" : "-ipv6", - this->policy->get_name(this->policy), + this->config->get_name(this->config), ifname ? ifname : "(unknown)", this->reqid, this->me.addr, @@ -316,7 +361,7 @@ static void updown(private_child_sa_t *this, bool up) policy->other_ts->get_from_port(policy->other_ts), policy->other_ts->get_protocol(policy->other_ts), virtual_ip, - this->policy->get_hostaccess(this->policy) ? + this->config->get_hostaccess(this->config) ? "PLUTO_HOST_ACCESS='1' " : "", script); free(ifname); @@ -528,8 +573,8 @@ static status_t install(private_child_sa_t *this, proposal_t *proposal, natt = NULL; } - soft = this->policy->get_soft_lifetime(this->policy); - hard = this->policy->get_hard_lifetime(this->policy); + soft = this->config->get_lifetime(this->config, TRUE); + hard = this->config->get_lifetime(this->config, FALSE); /* send SA down to the kernel */ DBG2(DBG_CHD, " SPI 0x%.8x, src %H dst %H", ntohl(spi), src, dst); @@ -542,7 +587,7 @@ static status_t install(private_child_sa_t *this, proposal_t *proposal, this->encryption = *enc_algo; this->integrity = *int_algo; this->install_time = time(NULL); - this->rekey_time = soft; + this->rekey_time = this->install_time + soft; return status; } @@ -628,7 +673,7 @@ static status_t add_policies(private_child_sa_t *this, if (my_ts->get_type(my_ts) != other_ts->get_type(other_ts)) { DBG2(DBG_CHD, - "CHILD_SA policy uses two different IP families, ignored"); + "CHILD_SA policy uses two different IP families - ignored"); continue; } @@ -637,7 +682,7 @@ static status_t add_policies(private_child_sa_t *this, my_ts->get_protocol(my_ts) && other_ts->get_protocol(other_ts)) { DBG2(DBG_CHD, - "CHILD_SA policy uses two different protocols, ignored"); + "CHILD_SA policy uses two different protocols - ignored"); continue; } @@ -665,10 +710,10 @@ static status_t add_policies(private_child_sa_t *this, policy = malloc_thing(sa_policy_t); policy->my_ts = my_ts->clone(my_ts); policy->other_ts = other_ts->clone(other_ts); - this->policies->insert_last(this->policies, (void*)policy); + this->policies->insert_last(this->policies, policy); /* add to separate list to query them via get_*_traffic_selectors() */ - this->my_ts->insert_last(this->my_ts, (void*)policy->my_ts); - this->other_ts->insert_last(this->other_ts, (void*)policy->other_ts); + this->my_ts->insert_last(this->my_ts, policy->my_ts); + this->other_ts->insert_last(this->other_ts, policy->other_ts); } } my_iter->destroy(my_iter); @@ -685,18 +730,14 @@ static status_t add_policies(private_child_sa_t *this, } /** - * Implementation of child_sa_t.get_my_traffic_selectors. + * Implementation of child_sa_t.get_traffic_selectors. */ -static linked_list_t *get_my_traffic_selectors(private_child_sa_t *this) -{ - return this->my_ts; -} - -/** - * Implementation of child_sa_t.get_my_traffic_selectors. - */ -static linked_list_t *get_other_traffic_selectors(private_child_sa_t *this) +static linked_list_t *get_traffic_selectors(private_child_sa_t *this, bool local) { + if (local) + { + return this->my_ts; + } return this->other_ts; } @@ -740,126 +781,6 @@ static status_t get_use_time(private_child_sa_t *this, bool inbound, time_t *use return status; } -/** - * output handler in printf() - */ -static int print(FILE *stream, const struct printf_info *info, - const void *const *args) -{ - private_child_sa_t *this = *((private_child_sa_t**)(args[0])); - iterator_t *iterator; - sa_policy_t *policy; - u_int32_t now, rekeying; - u_int32_t use, use_in, use_fwd; - status_t status; - size_t written = 0; - - if (this == NULL) - { - return fprintf(stream, "(null)"); - } - - now = time(NULL); - - written += fprintf(stream, "%12s{%d}: %N, %N", - this->policy->get_name(this->policy), this->reqid, - child_sa_state_names, this->state, - mode_names, this->mode); - - if (this->state == CHILD_INSTALLED) - { - written += fprintf(stream, ", %N SPIs: 0x%0x_i 0x%0x_o", - protocol_id_names, this->protocol, - htonl(this->me.spi), htonl(this->other.spi)); - - if (info->alt) - { - written += fprintf(stream, "\n%12s{%d}: ", - this->policy->get_name(this->policy), - this->reqid); - - if (this->protocol == PROTO_ESP) - { - written += fprintf(stream, "%N", encryption_algorithm_names, - this->encryption.algorithm); - - if (this->encryption.key_size) - { - written += fprintf(stream, "-%d", this->encryption.key_size); - } - written += fprintf(stream, "/"); - } - - written += fprintf(stream, "%N", integrity_algorithm_names, - this->integrity.algorithm); - if (this->integrity.key_size) - { - written += fprintf(stream, "-%d", this->integrity.key_size); - } - written += fprintf(stream, ", rekeying "); - - /* calculate rekey times */ - if (this->rekey_time) - { - rekeying = this->install_time + this->rekey_time - now; - written += fprintf(stream, "in %ds", rekeying); - } - else - { - written += fprintf(stream, "disabled"); - } - } - } - iterator = this->policies->create_iterator(this->policies, TRUE); - while (iterator->iterate(iterator, (void**)&policy)) - { - written += fprintf(stream, "\n%12s{%d}: %R===%R, last use: ", - this->policy->get_name(this->policy), this->reqid, - policy->my_ts, policy->other_ts); - - /* query time of last policy use */ - - /* inbound: POLICY_IN or POLICY_FWD */ - status = charon->kernel_interface->query_policy(charon->kernel_interface, - policy->other_ts, policy->my_ts, POLICY_IN, &use_in); - use_in = (status == SUCCESS)? use_in : 0; - status = charon->kernel_interface->query_policy(charon->kernel_interface, - policy->other_ts, policy->my_ts, POLICY_FWD, &use_fwd); - use_fwd = (status == SUCCESS)? use_fwd : 0; - use = max(use_in, use_fwd); - if (use) - { - written += fprintf(stream, "%ds_i ", now - use); - } - else - { - written += fprintf(stream, "no_i "); - } - - /* outbound: POLICY_OUT */ - status = charon->kernel_interface->query_policy(charon->kernel_interface, - policy->my_ts, policy->other_ts, POLICY_OUT, &use); - if (status == SUCCESS && use) - { - written += fprintf(stream, "%ds_o ", now - use); - } - else - { - written += fprintf(stream, "no_o "); - } - } - iterator->destroy(iterator); - return written; -} - -/** - * register printf() handlers - */ -static void __attribute__ ((constructor))print_register() -{ - register_printf_function(PRINTF_CHILD_SA, print, arginfo_ptr); -} - /** * Update the host adress/port of a SA */ @@ -1066,7 +987,7 @@ static void destroy(private_child_sa_t *this) this->other.addr->destroy(this->other.addr); this->me.id->destroy(this->me.id); this->other.id->destroy(this->other.id); - this->policy->destroy(this->policy); + this->config->destroy(this->config); DESTROY_IF(this->virtual_ip); free(this); } @@ -1076,7 +997,7 @@ static void destroy(private_child_sa_t *this) */ child_sa_t * child_sa_create(host_t *me, host_t* other, identification_t *my_id, identification_t *other_id, - policy_t *policy, u_int32_t rekey, bool use_natt) + child_cfg_t *config, u_int32_t rekey, bool use_natt) { static u_int32_t reqid = 0; private_child_sa_t *this = malloc_thing(private_child_sa_t); @@ -1086,17 +1007,17 @@ child_sa_t * child_sa_create(host_t *me, host_t* other, this->public.get_reqid = (u_int32_t(*)(child_sa_t*))get_reqid; this->public.get_spi = (u_int32_t(*)(child_sa_t*, bool))get_spi; this->public.get_protocol = (protocol_id_t(*)(child_sa_t*))get_protocol; + this->public.get_stats = (void(*)(child_sa_t*, mode_t*,encryption_algorithm_t*,size_t*,integrity_algorithm_t*,size_t*,u_int32_t*,u_int32_t*,u_int32_t*,u_int32_t*))get_stats; this->public.alloc = (status_t(*)(child_sa_t*,linked_list_t*))alloc; this->public.add = (status_t(*)(child_sa_t*,proposal_t*,mode_t,prf_plus_t*))add; this->public.update = (status_t(*)(child_sa_t*,proposal_t*,mode_t,prf_plus_t*))update; this->public.update_hosts = (status_t (*)(child_sa_t*,host_t*,host_t*,host_diff_t,host_diff_t))update_hosts; this->public.add_policies = (status_t (*)(child_sa_t*, linked_list_t*,linked_list_t*,mode_t))add_policies; - this->public.get_my_traffic_selectors = (linked_list_t*(*)(child_sa_t*))get_my_traffic_selectors; - this->public.get_other_traffic_selectors = (linked_list_t*(*)(child_sa_t*))get_other_traffic_selectors; + this->public.get_traffic_selectors = (linked_list_t*(*)(child_sa_t*,bool))get_traffic_selectors; this->public.get_use_time = (status_t (*)(child_sa_t*,bool,time_t*))get_use_time; this->public.set_state = (void(*)(child_sa_t*,child_sa_state_t))set_state; this->public.get_state = (child_sa_state_t(*)(child_sa_t*))get_state; - this->public.get_policy = (policy_t*(*)(child_sa_t*))get_policy; + this->public.get_config = (child_cfg_t*(*)(child_sa_t*))get_config; this->public.set_virtual_ip = (void(*)(child_sa_t*,host_t*))set_virtual_ip; this->public.destroy = (void(*)(child_sa_t*))destroy; @@ -1123,8 +1044,8 @@ child_sa_t * child_sa_create(host_t *me, host_t* other, this->protocol = PROTO_NONE; this->mode = MODE_TUNNEL; this->virtual_ip = NULL; - this->policy = policy; - policy->get_ref(policy); + this->config = config; + config->get_ref(config); return &this->public; } diff --git a/src/charon/sa/child_sa.h b/src/charon/sa/child_sa.h index 216e56659..cf5f3e7d7 100644 --- a/src/charon/sa/child_sa.h +++ b/src/charon/sa/child_sa.h @@ -32,7 +32,7 @@ typedef struct child_sa_t child_sa_t; #include #include #include -#include +#include /** * Where we should start with reqid enumeration @@ -101,7 +101,7 @@ extern enum_name_t *child_sa_state_names; struct child_sa_t { /** - * @brief Get the name of the policy this CHILD_SA uses. + * @brief Get the name of the config this CHILD_SA uses. * * @param this calling object * @return name @@ -140,6 +140,25 @@ struct child_sa_t { */ protocol_id_t (*get_protocol) (child_sa_t *this); + /** + * @brief Get info and statistics about this CHILD_SA. + * + * @param mode mode this IKE_SA uses + * @param encr_algo encryption algorithm used by this CHILD_SA. + * @param encr_len key length of the algorithm, if any + * @param int_algo integrity algorithm used by this CHILD_SA + * @param int_len key length of the algorithm, if any + * @param rekey time when rekeying is scheduled + * @param use_in time when last traffic was seen coming in + * @param use_out time when last traffic was seen going out + * @param use_fwd time when last traffic was getting forwarded + */ + void (*get_stats)(child_sa_t *this, mode_t *mode, + encryption_algorithm_t *encr, size_t *encr_len, + integrity_algorithm_t *int_algo, size_t *int_len, + u_int32_t *rekey, u_int32_t *use_in, u_int32_t *use_out, + u_int32_t *use_fwd); + /** * @brief Allocate SPIs for given proposals. * @@ -214,17 +233,10 @@ struct child_sa_t { * @brief Get the traffic selectors of added policies of local host. * * @param this calling object + * @param local TRUE for own traffic selectors, FALSE for remote * @return list of traffic selectors */ - linked_list_t* (*get_my_traffic_selectors) (child_sa_t *this); - - /** - * @brief Get the traffic selectors of added policies of remote host. - * - * @param this calling object - * @return list of traffic selectors - */ - linked_list_t* (*get_other_traffic_selectors) (child_sa_t *this); + linked_list_t* (*get_traffic_selectors) (child_sa_t *this, bool local); /** * @brief Get the time of this child_sa_t's last use (i.e. last use of any of its policies) @@ -251,12 +263,12 @@ struct child_sa_t { void (*set_state) (child_sa_t *this, child_sa_state_t state); /** - * @brief Get the policy used to set up this child sa. + * @brief Get the config used to set up this child sa. * * @param this calling object - * @return policy + * @return child_cfg */ - policy_t* (*get_policy) (child_sa_t *this); + child_cfg_t* (*get_config) (child_sa_t *this); /** * @brief Set the virtual IP used received from IRAS. @@ -284,7 +296,7 @@ struct child_sa_t { * @param other remote address * @param my_id id of own peer * @param other_id id of remote peer - * @param policy policy this CHILD_SA instantiates + * @param config config to use for this CHILD_SA * @param reqid reqid of old CHILD_SA when rekeying, 0 otherwise * @param use_natt TRUE if NAT traversal is used * @return child_sa_t object @@ -293,6 +305,6 @@ struct child_sa_t { */ child_sa_t * child_sa_create(host_t *me, host_t *other, identification_t *my_id, identification_t* other_id, - policy_t *policy, u_int32_t reqid, bool use_natt); + child_cfg_t *config, u_int32_t reqid, bool use_natt); #endif /*CHILD_SA_H_*/ diff --git a/src/charon/sa/ike_sa.c b/src/charon/sa/ike_sa.c index 68aba3064..8b4b53e10 100644 --- a/src/charon/sa/ike_sa.c +++ b/src/charon/sa/ike_sa.c @@ -26,6 +26,7 @@ #include #include #include +#include #include "ike_sa.h" @@ -56,13 +57,11 @@ #include #include #include -#include -#include -#include -#include -#include -#include -#include +#include +#include +#include +#include +#include #ifndef RESOLV_CONF @@ -105,14 +104,14 @@ struct private_ike_sa_t { ike_sa_state_t state; /** - * connection used to establish this IKE_SA. + * IKE configuration used to set up this IKE_SA */ - connection_t *connection; + ike_cfg_t *ike_cfg; /** * Peer and authentication information to establish IKE_SA. */ - policy_t *policy; + peer_cfg_t *peer_cfg; /** * Juggles tasks to process messages @@ -139,6 +138,11 @@ struct private_ike_sa_t { */ identification_t *other_id; + /** + * CA that issued the certificate of other + */ + ca_info_t *other_ca; + /** * Linked List containing the child sa's of the current IKE_SA. */ @@ -175,14 +179,14 @@ struct private_ike_sa_t { prf_t *child_prf; /** - * PRF to build outging authentication data + * Key to build outging authentication data (SKp) */ - prf_t *auth_build; + chunk_t skp_build; /** - * PRF to verify incoming authentication data + * Key to verify incoming authentication data (SKp) */ - prf_t *auth_verify; + chunk_t skp_verify; /** * NAT status of local host. @@ -273,79 +277,126 @@ static u_int32_t get_unique_id(private_ike_sa_t *this) */ static char *get_name(private_ike_sa_t *this) { - if (this->connection) + if (this->peer_cfg) { - return this->connection->get_name(this->connection); + return this->peer_cfg->get_name(this->peer_cfg); } return "(unnamed)"; } + /** - * Implementation of ike_sa_t.get_connection + * Implementation of ike_sa_t.get_stats. */ -static connection_t* get_connection(private_ike_sa_t *this) +static void get_stats(private_ike_sa_t *this, u_int32_t *next_rekeying) { - return this->connection; + if (next_rekeying) + { + *next_rekeying = this->time.rekey; + } } /** - * Implementation of ike_sa_t.set_connection + * Implementation of ike_sa_t.get_my_host. */ -static void set_connection(private_ike_sa_t *this, connection_t *connection) +static host_t *get_my_host(private_ike_sa_t *this) { - this->connection = connection; - connection->get_ref(connection); + return this->my_host; } /** - * Implementation of ike_sa_t.get_policy + * Implementation of ike_sa_t.set_my_host. */ -static policy_t *get_policy(private_ike_sa_t *this) +static void set_my_host(private_ike_sa_t *this, host_t *me) { - return this->policy; + DESTROY_IF(this->my_host); + this->my_host = me; } /** - * Implementation of ike_sa_t.set_policy + * Implementation of ike_sa_t.get_other_host. */ -static void set_policy(private_ike_sa_t *this, policy_t *policy) +static host_t *get_other_host(private_ike_sa_t *this) { - policy->get_ref(policy); - this->policy = policy; + return this->other_host; } /** - * Implementation of ike_sa_t.get_my_host. + * Implementation of ike_sa_t.set_other_host. */ -static host_t *get_my_host(private_ike_sa_t *this) +static void set_other_host(private_ike_sa_t *this, host_t *other) { - return this->my_host; + DESTROY_IF(this->other_host); + this->other_host = other; } /** - * Implementation of ike_sa_t.set_my_host. + * Implementation of ike_sa_t.get_peer_cfg */ -static void set_my_host(private_ike_sa_t *this, host_t *me) +static peer_cfg_t* get_peer_cfg(private_ike_sa_t *this) { - DESTROY_IF(this->my_host); - this->my_host = me; + return this->peer_cfg; } /** - * Implementation of ike_sa_t.get_other_host. + * Implementation of ike_sa_t.set_peer_cfg */ -static host_t *get_other_host(private_ike_sa_t *this) +static void set_peer_cfg(private_ike_sa_t *this, peer_cfg_t *peer_cfg) { - return this->other_host; + 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); + } + + /* apply values, so we are ready to initate/acquire */ + if (this->my_host->is_anyaddr(this->my_host)) + { + host_t *me = this->ike_cfg->get_my_host(this->ike_cfg); + + set_my_host(this, me->clone(me)); + } + if (this->other_host->is_anyaddr(this->other_host)) + { + host_t *other = this->ike_cfg->get_other_host(this->ike_cfg); + + set_other_host(this, other->clone(other)); + } + /* apply IDs if they are not already set */ + if (this->my_id->contains_wildcards(this->my_id)) + { + identification_t *my_id = this->peer_cfg->get_my_id(this->peer_cfg); + + DESTROY_IF(this->my_id); + this->my_id = my_id->clone(my_id); + } + if (this->other_id->contains_wildcards(this->other_id)) + { + identification_t *other_id = this->peer_cfg->get_other_id(this->peer_cfg); + + DESTROY_IF(this->other_id); + this->other_id = other_id->clone(other_id); + } } /** - * Implementation of ike_sa_t.set_other_host. + * Implementation of ike_sa_t.get_ike_cfg */ -static void set_other_host(private_ike_sa_t *this, host_t *other) +static ike_cfg_t *get_ike_cfg(private_ike_sa_t *this) { - DESTROY_IF(this->other_host); - this->other_host = other; + 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; } /** @@ -356,7 +407,7 @@ static status_t send_dpd(private_ike_sa_t *this) send_dpd_job_t *job; time_t diff, delay; - delay = this->connection->get_dpd_delay(this->connection); + delay = this->peer_cfg->get_dpd_delay(this->peer_cfg); if (delay == 0) { @@ -402,15 +453,14 @@ static status_t send_dpd(private_ike_sa_t *this) static void send_keepalive(private_ike_sa_t *this) { send_keepalive_job_t *job; - time_t last_out, now, diff, interval; + time_t last_out, now, diff; last_out = get_use_time(this, FALSE); now = time(NULL); diff = now - last_out; - interval = charon->configuration->get_keepalive_interval(charon->configuration); - if (diff >= interval) + if (diff >= KEEPALIVE_INTERVAL) { packet_t *packet; chunk_t data; @@ -428,7 +478,7 @@ static void send_keepalive(private_ike_sa_t *this) } job = send_keepalive_job_create(this->ike_sa_id); charon->event_queue->add_relative(charon->event_queue, (job_t*)job, - (interval - diff) * 1000); + (KEEPALIVE_INTERVAL - diff) * 1000); } /** @@ -464,9 +514,9 @@ static void set_state(private_ike_sa_t *this, ike_sa_state_t state) send_dpd(this); /* schedule rekeying/reauthentication */ - soft = this->connection->get_soft_lifetime(this->connection); - hard = this->connection->get_hard_lifetime(this->connection); - reauth = this->connection->get_reauth(this->connection); + soft = this->peer_cfg->get_lifetime(this->peer_cfg, TRUE); + hard = this->peer_cfg->get_lifetime(this->peer_cfg, FALSE); + reauth = this->peer_cfg->use_reauth(this->peer_cfg); DBG1(DBG_IKE, "scheduling %s in %ds, maximum lifetime %ds", reauth ? "reauthentication": "rekeying", soft, hard); @@ -492,9 +542,8 @@ static void set_state(private_ike_sa_t *this, ike_sa_state_t state) { /* 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->event_queue->add_relative(charon->event_queue, job, - charon->configuration->get_half_open_ike_sa_timeout( - charon->configuration)); + charon->event_queue->add_relative(charon->event_queue, job, + HALF_OPEN_IKE_SA_TIMEOUT); break; } default: @@ -521,7 +570,7 @@ static void reset(private_ike_sa_t *this) } /** - * Update connection host, as addresses may change (NAT) + * Update hosts, as addresses may change (NAT) */ static void update_hosts(private_ike_sa_t *this, host_t *me, host_t *other) { @@ -696,16 +745,16 @@ static status_t process_message(private_ike_sa_t *this, message_t *message) me = message->get_destination(message); other = message->get_source(message); - /* if this IKE_SA is virgin, we check for a connection */ - if (this->connection == NULL) + /* if this IKE_SA is virgin, we check for a config */ + if (this->ike_cfg == NULL) { job_t *job; - this->connection = charon->connections->get_connection_by_hosts( - charon->connections, me, other); - if (this->connection == NULL) + this->ike_cfg = charon->backends->get_ike_cfg(charon->backends, + me, other); + if (this->ike_cfg == NULL) { - /* no connection found for these hosts, destroy */ - DBG1(DBG_IKE, "no connection found for %H...%H, sending %N", + /* 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; @@ -713,11 +762,10 @@ static status_t process_message(private_ike_sa_t *this, message_t *message) /* add a timeout if peer does not establish it completely */ job = (job_t*)delete_ike_sa_job_create(this->ike_sa_id, FALSE); charon->event_queue->add_relative(charon->event_queue, job, - charon->configuration->get_half_open_ike_sa_timeout( - charon->configuration)); + HALF_OPEN_IKE_SA_TIMEOUT); } - - /* check if message is trustworthy, and update connection information */ + + /* check if message is trustworthy, and update host information */ if (this->state == IKE_CREATED || message->get_exchange_type(message) != IKE_SA_INIT) { @@ -728,47 +776,15 @@ static status_t process_message(private_ike_sa_t *this, message_t *message) } } -/** - * apply the connection/policy information to this IKE_SA - */ -static void apply_config(private_ike_sa_t *this, - connection_t *connection, policy_t *policy) -{ - host_t *me, *other; - identification_t *my_id, *other_id; - - if (this->connection == NULL && this->policy == NULL) - { - this->connection = connection; - connection->get_ref(connection); - this->policy = policy; - policy->get_ref(policy); - - me = connection->get_my_host(connection); - other = connection->get_other_host(connection); - my_id = policy->get_my_id(policy); - other_id = policy->get_other_id(policy); - set_my_host(this, me->clone(me)); - set_other_host(this, other->clone(other)); - DESTROY_IF(this->my_id); - DESTROY_IF(this->other_id); - this->my_id = my_id->clone(my_id); - this->other_id = other_id->clone(other_id); - } -} - /** * Implementation of ike_sa_t.initiate. */ -static status_t initiate(private_ike_sa_t *this, - connection_t *connection, policy_t *policy) +static status_t initiate(private_ike_sa_t *this, child_cfg_t *child_cfg) { task_t *task; if (this->state == IKE_CREATED) { - /* if we aren't established/establishing, do so */ - apply_config(this, connection, policy); if (this->other_host->is_anyaddr(this->other_host)) { @@ -785,11 +801,12 @@ static status_t initiate(private_ike_sa_t *this, 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_config_create(&this->public, policy); + task = (task_t*)ike_config_create(&this->public, TRUE); this->task_manager->queue_task(this->task_manager, task); } - task = (task_t*)child_create_create(&this->public, policy); + task = (task_t*)child_create_create(&this->public, child_cfg); + child_cfg->destroy(child_cfg); this->task_manager->queue_task(this->task_manager, task); return this->task_manager->initiate(this->task_manager); @@ -800,7 +817,7 @@ static status_t initiate(private_ike_sa_t *this, */ static status_t acquire(private_ike_sa_t *this, u_int32_t reqid) { - policy_t *policy; + child_cfg_t *child_cfg; iterator_t *iterator; child_sa_t *current, *child_sa = NULL; task_t *task; @@ -833,7 +850,6 @@ static status_t acquire(private_ike_sa_t *this, u_int32_t reqid) return FAILED; } - policy = child_sa->get_policy(child_sa); if (this->state == IKE_CREATED) { @@ -845,52 +861,24 @@ static status_t acquire(private_ike_sa_t *this, u_int32_t reqid) 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_config_create(&this->public, policy); + task = (task_t*)ike_config_create(&this->public, TRUE); this->task_manager->queue_task(this->task_manager, task); } - child_create = child_create_create(&this->public, policy); + child_cfg = child_sa->get_config(child_sa); + child_create = child_create_create(&this->public, child_cfg); child_create->use_reqid(child_create, reqid); this->task_manager->queue_task(this->task_manager, (task_t*)child_create); return this->task_manager->initiate(this->task_manager); } -/** - * compare two lists of traffic selectors for equality - */ -static bool ts_list_equals(linked_list_t *l1, linked_list_t *l2) -{ - bool equals = TRUE; - iterator_t *i1, *i2; - traffic_selector_t *t1, *t2; - - if (l1->get_count(l1) != l2->get_count(l2)) - { - return FALSE; - } - - i1 = l1->create_iterator(l1, TRUE); - i2 = l2->create_iterator(l2, TRUE); - while (i1->iterate(i1, (void**)&t1) && i2->iterate(i2, (void**)&t2)) - { - if (!t1->equals(t1, t2)) - { - equals = FALSE; - break; - } - } - i1->destroy(i1); - i2->destroy(i2); - return equals; -} - /** * Implementation of ike_sa_t.route. */ -static status_t route(private_ike_sa_t *this, connection_t *connection, policy_t *policy) +static status_t route(private_ike_sa_t *this, child_cfg_t *child_cfg) { - child_sa_t *child_sa = NULL; + child_sa_t *child_sa; iterator_t *iterator; linked_list_t *my_ts, *other_ts; status_t status; @@ -901,27 +889,12 @@ static status_t route(private_ike_sa_t *this, connection_t *connection, policy_t iterator = this->child_sas->create_iterator(this->child_sas, TRUE); while (iterator->iterate(iterator, (void**)&child_sa)) { - if (child_sa->get_state(child_sa) == CHILD_ROUTED) + if (child_sa->get_state(child_sa) == CHILD_ROUTED && + streq(child_sa->get_name(child_sa), child_cfg->get_name(child_cfg))) { - linked_list_t *my_ts_conf, *other_ts_conf; - - my_ts = child_sa->get_my_traffic_selectors(child_sa); - other_ts = child_sa->get_other_traffic_selectors(child_sa); - - my_ts_conf = policy->get_my_traffic_selectors(policy, this->my_host); - other_ts_conf = policy->get_other_traffic_selectors(policy, this->other_host); - - if (ts_list_equals(my_ts, my_ts_conf) && - ts_list_equals(other_ts, other_ts_conf)) - { - iterator->destroy(iterator); - my_ts_conf->destroy_offset(my_ts_conf, offsetof(traffic_selector_t, destroy)); - other_ts_conf->destroy_offset(other_ts_conf, offsetof(traffic_selector_t, destroy)); - SIG(CHILD_ROUTE_FAILED, "CHILD_SA with such a policy already routed"); - return FAILED; - } - my_ts_conf->destroy_offset(my_ts_conf, offsetof(traffic_selector_t, destroy)); - other_ts_conf->destroy_offset(other_ts_conf, offsetof(traffic_selector_t, destroy)); + iterator->destroy(iterator); + SIG(CHILD_ROUTE_FAILED, "CHILD_SA with such a config already routed"); + return FAILED; } } iterator->destroy(iterator); @@ -934,9 +907,6 @@ static status_t route(private_ike_sa_t *this, connection_t *connection, policy_t "unable to route CHILD_SA, as its IKE_SA gets deleted"); return FAILED; case IKE_CREATED: - /* apply connection information, we need it to acquire */ - apply_config(this, connection, policy); - break; case IKE_CONNECTING: case IKE_ESTABLISHED: default: @@ -944,29 +914,37 @@ static status_t route(private_ike_sa_t *this, connection_t *connection, policy_t } /* install kernel policies */ - child_sa = child_sa_create(this->my_host, this->other_host, - this->my_id, this->other_id, policy, FALSE, 0); + child_sa = child_sa_create(this->my_host, this->other_host, this->my_id, + this->other_id, child_cfg, FALSE, 0); - my_ts = policy->get_my_traffic_selectors(policy, this->my_host); - other_ts = policy->get_other_traffic_selectors(policy, this->other_host); + my_ts = child_cfg->get_traffic_selectors(child_cfg, TRUE, NULL, + this->my_host); + other_ts = child_cfg->get_traffic_selectors(child_cfg, FALSE, NULL, + this->other_host); status = child_sa->add_policies(child_sa, my_ts, other_ts, - policy->get_mode(policy)); + child_cfg->get_mode(child_cfg)); my_ts->destroy_offset(my_ts, offsetof(traffic_selector_t, destroy)); other_ts->destroy_offset(other_ts, offsetof(traffic_selector_t, destroy)); - this->child_sas->insert_last(this->child_sas, child_sa); - SIG(CHILD_ROUTE_SUCCESS, "CHILD_SA routed"); + if (status == SUCCESS) + { + this->child_sas->insert_last(this->child_sas, child_sa); + SIG(CHILD_ROUTE_SUCCESS, "CHILD_SA routed"); + } + else + { + SIG(CHILD_ROUTE_FAILED, "routing CHILD_SA failed"); + } return status; } /** * Implementation of ike_sa_t.unroute. */ -static status_t unroute(private_ike_sa_t *this, policy_t *policy) +static status_t unroute(private_ike_sa_t *this, u_int32_t reqid) { iterator_t *iterator; - child_sa_t *child_sa = NULL; + child_sa_t *child_sa; bool found = FALSE; - linked_list_t *my_ts, *other_ts, *my_ts_conf, *other_ts_conf; SIG(CHILD_UNROUTE_START, "unrouting CHILD_SA"); @@ -974,27 +952,14 @@ static status_t unroute(private_ike_sa_t *this, policy_t *policy) iterator = this->child_sas->create_iterator(this->child_sas, TRUE); while (iterator->iterate(iterator, (void**)&child_sa)) { - if (child_sa->get_state(child_sa) == CHILD_ROUTED) + if (child_sa->get_state(child_sa) == CHILD_ROUTED && + child_sa->get_reqid(child_sa) == reqid) { - my_ts = child_sa->get_my_traffic_selectors(child_sa); - other_ts = child_sa->get_other_traffic_selectors(child_sa); - - my_ts_conf = policy->get_my_traffic_selectors(policy, this->my_host); - other_ts_conf = policy->get_other_traffic_selectors(policy, this->other_host); - - if (ts_list_equals(my_ts, my_ts_conf) && - ts_list_equals(other_ts, other_ts_conf)) - { - iterator->remove(iterator); - SIG(CHILD_UNROUTE_SUCCESS, "CHILD_SA unrouted"); - child_sa->destroy(child_sa); - my_ts_conf->destroy_offset(my_ts_conf, offsetof(traffic_selector_t, destroy)); - other_ts_conf->destroy_offset(other_ts_conf, offsetof(traffic_selector_t, destroy)); - found = TRUE; - break; - } - my_ts_conf->destroy_offset(my_ts_conf, offsetof(traffic_selector_t, destroy)); - other_ts_conf->destroy_offset(other_ts_conf, offsetof(traffic_selector_t, destroy)); + iterator->remove(iterator); + SIG(CHILD_UNROUTE_SUCCESS, "CHILD_SA unrouted"); + child_sa->destroy(child_sa); + found = TRUE; + break; } } iterator->destroy(iterator); @@ -1021,7 +986,7 @@ static status_t retransmit(private_ike_sa_t *this, u_int32_t message_id) this->time.outbound = time(NULL); if (this->task_manager->retransmit(this->task_manager, message_id) != SUCCESS) { - policy_t *policy; + child_cfg_t *child_cfg; child_sa_t* child_sa; linked_list_t *to_route, *to_restart; iterator_t *iterator; @@ -1032,7 +997,7 @@ static status_t retransmit(private_ike_sa_t *this, u_int32_t message_id) case IKE_CONNECTING: { /* retry IKE_SA_INIT if we have multiple keyingtries */ - u_int32_t tries = this->connection->get_keyingtries(this->connection); + u_int32_t tries = this->peer_cfg->get_keyingtries(this->peer_cfg); this->keyingtry++; if (tries == 0 || tries > this->keyingtry) { @@ -1060,23 +1025,23 @@ static status_t retransmit(private_ike_sa_t *this, u_int32_t message_id) iterator = this->child_sas->create_iterator(this->child_sas, TRUE); while (iterator->iterate(iterator, (void**)&child_sa)) { - policy = child_sa->get_policy(child_sa); + child_cfg = child_sa->get_config(child_sa); if (child_sa->get_state(child_sa) == CHILD_ROUTED) { /* reroute routed CHILD_SAs */ - to_route->insert_last(to_route, policy); + to_route->insert_last(to_route, child_cfg); } else { /* use DPD action for established CHILD_SAs */ - switch (policy->get_dpd_action(policy)) + switch (this->peer_cfg->get_dpd_action(this->peer_cfg)) { case DPD_ROUTE: - to_route->insert_last(to_route, policy); + to_route->insert_last(to_route, child_cfg); break; case DPD_RESTART: - to_restart->insert_last(to_restart, policy); + to_restart->insert_last(to_restart, child_cfg); break; default: break; @@ -1094,15 +1059,15 @@ static status_t retransmit(private_ike_sa_t *this, u_int32_t message_id) new = (private_ike_sa_t*)charon->ike_sa_manager->checkout_new( charon->ike_sa_manager, TRUE); - apply_config(new, this->connection, this->policy); - /* use actual used host, not the wildcarded one in connection */ + set_peer_cfg(new, this->peer_cfg); + /* use actual used host, not the wildcarded one in config */ new->other_host->destroy(new->other_host); new->other_host = this->other_host->clone(this->other_host); /* install routes */ - while (to_route->remove_last(to_route, (void**)&policy) == SUCCESS) + while (to_route->remove_last(to_route, (void**)&child_cfg) == SUCCESS) { - route(new, new->connection, policy); + route(new, child_cfg); } /* restart children */ @@ -1114,14 +1079,14 @@ static status_t retransmit(private_ike_sa_t *this, u_int32_t message_id) new->task_manager->queue_task(new->task_manager, task); task = (task_t*)ike_cert_create(&new->public, TRUE); new->task_manager->queue_task(new->task_manager, task); - task = (task_t*)ike_config_create(&new->public, new->policy); + task = (task_t*)ike_config_create(&new->public, TRUE); new->task_manager->queue_task(new->task_manager, task); task = (task_t*)ike_auth_create(&new->public, TRUE); new->task_manager->queue_task(new->task_manager, task); - while (to_restart->remove_last(to_restart, (void**)&policy) == SUCCESS) + while (to_restart->remove_last(to_restart, (void**)&child_cfg) == SUCCESS) { - task = (task_t*)child_create_create(&new->public, policy); + task = (task_t*)child_create_create(&new->public, child_cfg); new->task_manager->queue_task(new->task_manager, task); } new->task_manager->initiate(new->task_manager); @@ -1152,19 +1117,19 @@ static prf_t *get_child_prf(private_ike_sa_t *this) } /** - * Implementation of ike_sa_t.get_auth_bild + * Implementation of ike_sa_t.get_skp_bild */ -static prf_t *get_auth_build(private_ike_sa_t *this) +static chunk_t get_skp_build(private_ike_sa_t *this) { - return this->auth_build; + return this->skp_build; } /** - * Implementation of ike_sa_t.get_auth_verify + * Implementation of ike_sa_t.get_skp_verify */ -static prf_t *get_auth_verify(private_ike_sa_t *this) +static chunk_t get_skp_verify(private_ike_sa_t *this) { - return this->auth_verify; + return this->skp_verify; } /** @@ -1209,6 +1174,71 @@ static void set_other_id(private_ike_sa_t *this, identification_t *other) this->other_id = other; } +/** + * Implementation of ike_sa_t.get_other_ca. + */ +static ca_info_t* get_other_ca(private_ike_sa_t *this) +{ + return this->other_ca; +} + +/** + * Implementation of ike_sa_t.set_other_ca. + */ +static void set_other_ca(private_ike_sa_t *this, ca_info_t *other_ca) +{ + this->other_ca = other_ca; +} + +/** + * 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 (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, + this->my_host); + this->my_virtual_ip->destroy(this->my_virtual_ip); + } + if (charon->kernel_interface->add_ip(charon->kernel_interface, ip, + this->my_host) == SUCCESS) + { + 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.derive_keys. */ @@ -1223,7 +1253,6 @@ static status_t derive_keys(private_ike_sa_t *this, size_t key_size; crypter_t *crypter_i, *crypter_r; signer_t *signer_i, *signer_r; - prf_t *prf_i, *prf_r; u_int8_t spi_i_buf[sizeof(u_int64_t)], spi_r_buf[sizeof(u_int64_t)]; chunk_t spi_i = chunk_from_buf(spi_i_buf); chunk_t spi_r = chunk_from_buf(spi_r_buf); @@ -1364,31 +1393,27 @@ static status_t derive_keys(private_ike_sa_t *this, this->crypter_out = crypter_r; } - /* SK_pi/SK_pr used for authentication => prf_auth_i, prf_auth_r */ - proposal->get_algorithm(proposal, PSEUDO_RANDOM_FUNCTION, &algo); - prf_i = prf_create(algo->algorithm); - prf_r = prf_create(algo->algorithm); - - key_size = prf_i->get_key_size(prf_i); + /* SK_pi/SK_pr used for authentication => stored for later */ + key_size = this->prf->get_key_size(this->prf); prf_plus->allocate_bytes(prf_plus, key_size, &key); DBG4(DBG_IKE, "Sk_pi secret %B", &key); - prf_i->set_key(prf_i, key); - chunk_free(&key); - + if (initiator) + { + this->skp_build = key; + } + else + { + this->skp_verify = key; + } prf_plus->allocate_bytes(prf_plus, key_size, &key); DBG4(DBG_IKE, "Sk_pr secret %B", &key); - prf_r->set_key(prf_r, key); - chunk_free(&key); - if (initiator) { - this->auth_verify = prf_r; - this->auth_build = prf_i; + this->skp_verify = key; } else { - this->auth_verify = prf_i; - this->auth_build = prf_r; + this->skp_build = key; } /* all done, prf_plus not needed anymore */ @@ -1507,8 +1532,6 @@ static status_t delete_(private_ike_sa_t *this) switch (this->state) { case IKE_ESTABLISHED: - DBG1(DBG_IKE, "deleting IKE_SA"); - /* do not log when rekeyed */ case IKE_REKEYING: ike_delete = ike_delete_create(&this->public, TRUE); this->task_manager->queue_task(this->task_manager, &ike_delete->task); @@ -1542,16 +1565,21 @@ static void reestablish(private_ike_sa_t *this) private_ike_sa_t *other; iterator_t *iterator; child_sa_t *child_sa; - policy_t *policy; + child_cfg_t *child_cfg; task_t *task; job_t *job; other = (private_ike_sa_t*)charon->ike_sa_manager->checkout_new( charon->ike_sa_manager, TRUE); - apply_config(other, this->connection, this->policy); + set_peer_cfg(other, this->peer_cfg); other->other_host->destroy(other->other_host); other->other_host = this->other_host->clone(this->other_host); + if (this->my_virtual_ip) + { + /* if we already have a virtual IP, we reuse it */ + set_virtual_ip(other, TRUE, this->my_virtual_ip); + } if (this->state == IKE_ESTABLISHED) { @@ -1561,7 +1589,7 @@ static void reestablish(private_ike_sa_t *this) other->task_manager->queue_task(other->task_manager, task); task = (task_t*)ike_cert_create(&other->public, TRUE); other->task_manager->queue_task(other->task_manager, task); - task = (task_t*)ike_config_create(&other->public, other->policy); + task = (task_t*)ike_config_create(&other->public, TRUE); other->task_manager->queue_task(other->task_manager, task); task = (task_t*)ike_auth_create(&other->public, TRUE); other->task_manager->queue_task(other->task_manager, task); @@ -1583,8 +1611,8 @@ static void reestablish(private_ike_sa_t *this) } default: { - policy = child_sa->get_policy(child_sa); - task = (task_t*)child_create_create(&other->public, policy); + child_cfg = child_sa->get_config(child_sa); + task = (task_t*)child_create_create(&other->public, child_cfg); other->task_manager->queue_task(other->task_manager, task); break; } @@ -1677,55 +1705,6 @@ static void enable_natt(private_ike_sa_t *this, bool local) } } -/** - * 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 (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, - this->my_host); - this->my_virtual_ip->destroy(this->my_virtual_ip); - } - if (charon->kernel_interface->add_ip(charon->kernel_interface, ip, - this->my_host) == SUCCESS) - { - 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.remove_dns_server */ @@ -1747,7 +1726,8 @@ static void remove_dns_servers(private_ike_sa_t *this) file = fopen(RESOLV_CONF, "r"); if (file == NULL || stat(RESOLV_CONF, &stats) != 0) { - DBG1(DBG_IKE, "unable to open DNS configuration file %s: %m", RESOLV_CONF); + DBG1(DBG_IKE, "unable to open DNS configuration file %s: %s", + RESOLV_CONF, strerror(errno)); return; } @@ -1755,7 +1735,7 @@ static void remove_dns_servers(private_ike_sa_t *this) if (fread(contents.ptr, 1, contents.len, file) != contents.len) { - DBG1(DBG_IKE, "unable to read DNS configuration file: %m"); + DBG1(DBG_IKE, "unable to read DNS configuration file: %s", strerror(errno)); fclose(file); return; } @@ -1764,7 +1744,8 @@ static void remove_dns_servers(private_ike_sa_t *this) file = fopen(RESOLV_CONF, "w"); if (file == NULL) { - DBG1(DBG_IKE, "unable to open DNS configuration file %s: %m", RESOLV_CONF); + DBG1(DBG_IKE, "unable to open DNS configuration file %s: %s", + RESOLV_CONF, strerror(errno)); return; } @@ -1820,7 +1801,8 @@ static void add_dns_server(private_ike_sa_t *this, host_t *dns) file = fopen(RESOLV_CONF, "a+"); if (file == NULL || stat(RESOLV_CONF, &stats) != 0) { - DBG1(DBG_IKE, "unable to open DNS configuration file %s: %m", RESOLV_CONF); + DBG1(DBG_IKE, "unable to open DNS configuration file %s: %s", + RESOLV_CONF, strerror(errno)); return; } @@ -1828,7 +1810,7 @@ static void add_dns_server(private_ike_sa_t *this, host_t *dns) if (fread(contents.ptr, 1, contents.len, file) != contents.len) { - DBG1(DBG_IKE, "unable to read DNS configuration file: %m"); + DBG1(DBG_IKE, "unable to read DNS configuration file: %s", strerror(errno)); fclose(file); return; } @@ -1837,14 +1819,15 @@ static void add_dns_server(private_ike_sa_t *this, host_t *dns) file = fopen(RESOLV_CONF, "w"); if (file == NULL) { - DBG1(DBG_IKE, "unable to open DNS configuration file %s: %m", RESOLV_CONF); + DBG1(DBG_IKE, "unable to open DNS configuration file %s: %s", + RESOLV_CONF, strerror(errno)); return; } if (fprintf(file, "nameserver %H # added by strongSwan, assigned by %D\n", dns, this->other_id) < 0) { - DBG1(DBG_IKE, "unable to write DNS configuration: %m"); + DBG1(DBG_IKE, "unable to write DNS configuration: %s", strerror(errno)); } else { @@ -1855,50 +1838,6 @@ static void add_dns_server(private_ike_sa_t *this, host_t *dns) fclose(file); } -/** - * output handler in printf() - */ -static int print(FILE *stream, const struct printf_info *info, - const void *const *args) -{ - int written = 0; - bool reauth = FALSE; - private_ike_sa_t *this = *((private_ike_sa_t**)(args[0])); - - if (this->connection) - { - reauth = this->connection->get_reauth(this->connection); - } - - if (this == NULL) - { - return fprintf(stream, "(null)"); - } - - written = fprintf(stream, "%12s[%d]: %N, %H[%D]...%H[%D]", get_name(this), - this->unique_id, ike_sa_state_names, this->state, - this->my_host, this->my_id, this->other_host, - this->other_id); - written += fprintf(stream, "\n%12s[%d]: IKE SPIs: %J, %s in %ds", - get_name(this), this->unique_id, this->ike_sa_id, - this->connection && reauth? "reauthentication":"rekeying", - this->time.rekey - time(NULL)); - - if (info->alt) - { - - } - return written; -} - -/** - * register printf() handlers - */ -static void __attribute__ ((constructor))print_register() -{ - register_printf_function(PRINTF_IKE_SA, print, arginfo_ptr); -} - /** * Implementation of ike_sa_t.destroy. */ @@ -1912,8 +1851,8 @@ static void destroy(private_ike_sa_t *this) DESTROY_IF(this->signer_out); DESTROY_IF(this->prf); DESTROY_IF(this->child_prf); - DESTROY_IF(this->auth_verify); - DESTROY_IF(this->auth_build); + chunk_free(&this->skp_verify); + chunk_free(&this->skp_build); if (this->my_virtual_ip) { @@ -1931,8 +1870,8 @@ static void destroy(private_ike_sa_t *this) DESTROY_IF(this->my_id); DESTROY_IF(this->other_id); - DESTROY_IF(this->connection); - DESTROY_IF(this->policy); + DESTROY_IF(this->ike_cfg); + DESTROY_IF(this->peer_cfg); this->ike_sa_id->destroy(this->ike_sa_id); this->task_manager->destroy(this->task_manager); @@ -1948,54 +1887,57 @@ ike_sa_t * ike_sa_create(ike_sa_id_t *ike_sa_id) 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.process_message = (status_t(*)(ike_sa_t*, message_t*)) process_message; - this->public.initiate = (status_t(*)(ike_sa_t*,connection_t*,policy_t*)) initiate; - this->public.route = (status_t(*)(ike_sa_t*,connection_t*,policy_t*)) route; - this->public.unroute = (status_t(*)(ike_sa_t*,policy_t*)) unroute; - this->public.acquire = (status_t(*)(ike_sa_t*,u_int32_t)) acquire; - this->public.get_connection = (connection_t*(*)(ike_sa_t*))get_connection; - this->public.set_connection = (void(*)(ike_sa_t*,connection_t*))set_connection; - this->public.get_policy = (policy_t*(*)(ike_sa_t*))get_policy; - this->public.set_policy = (void(*)(ike_sa_t*,policy_t*))set_policy; - 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.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.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.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_stats = (void (*)(ike_sa_t*,u_int32_t*))get_stats; + this->public.get_name = (char* (*)(ike_sa_t*))get_name; + this->public.process_message = (status_t (*)(ike_sa_t*, message_t*)) process_message; + this->public.initiate = (status_t (*)(ike_sa_t*,child_cfg_t*)) initiate; + this->public.route = (status_t (*)(ike_sa_t*,child_cfg_t*)) route; + this->public.unroute = (status_t (*)(ike_sa_t*,u_int32_t)) unroute; + this->public.acquire = (status_t (*)(ike_sa_t*,u_int32_t)) acquire; + 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_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.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.get_other_ca = (ca_info_t* (*)(ike_sa_t*)) get_other_ca; + this->public.set_other_ca = (void (*)(ike_sa_t*,ca_info_t*)) set_other_ca; + 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_prf = (prf_t *(*) (ike_sa_t *)) get_prf; - this->public.get_child_prf = (prf_t *(*) (ike_sa_t *)) get_child_prf; - this->public.get_auth_verify = (prf_t *(*) (ike_sa_t *)) get_auth_verify; - this->public.get_auth_build = (prf_t *(*) (ike_sa_t *)) get_auth_build; - this->public.derive_keys = (status_t (*) (ike_sa_t *,proposal_t*,chunk_t,chunk_t,chunk_t,bool,prf_t*,prf_t*)) derive_keys; - this->public.add_child_sa = (void (*) (ike_sa_t*,child_sa_t*)) add_child_sa; + this->public.get_prf = (prf_t* (*)(ike_sa_t*)) get_prf; + this->public.get_child_prf = (prf_t* (*)(ike_sa_t *)) get_child_prf; + this->public.get_skp_verify = (chunk_t (*)(ike_sa_t *)) get_skp_verify; + this->public.get_skp_build = (chunk_t (*)(ike_sa_t *)) get_skp_build; + this->public.derive_keys = (status_t (*)(ike_sa_t *,proposal_t*,chunk_t,chunk_t,chunk_t,bool,prf_t*,prf_t*)) derive_keys; + 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.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.enable_natt = (void(*)(ike_sa_t*, bool)) enable_natt; - this->public.is_natt_enabled = (bool(*)(ike_sa_t*)) is_natt_enabled; - this->public.rekey = (status_t(*)(ike_sa_t*))rekey; - this->public.reestablish = (void(*)(ike_sa_t*))reestablish; - 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_dns_server = (void(*)(ike_sa_t*,host_t*))add_dns_server; + this->public.enable_natt = (void (*)(ike_sa_t*, bool)) enable_natt; + this->public.is_natt_enabled = (bool (*)(ike_sa_t*)) is_natt_enabled; + this->public.rekey = (status_t (*)(ike_sa_t*))rekey; + this->public.reestablish = (void (*)(ike_sa_t*))reestablish; + 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_dns_server = (void (*)(ike_sa_t*,host_t*))add_dns_server; /* initialize private fields */ this->ike_sa_id = ike_sa_id->clone(ike_sa_id); @@ -2004,13 +1946,14 @@ ike_sa_t * ike_sa_create(ike_sa_id_t *ike_sa_id) 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->other_ca = NULL; this->crypter_in = NULL; this->crypter_out = NULL; this->signer_in = NULL; this->signer_out = NULL; this->prf = NULL; - this->auth_verify = NULL; - this->auth_build = NULL; + this->skp_verify = chunk_empty; + this->skp_build = chunk_empty; this->child_prf = NULL; this->nat_here = FALSE; this->nat_there = FALSE; @@ -2019,8 +1962,8 @@ ike_sa_t * ike_sa_create(ike_sa_id_t *ike_sa_id) this->time.established = 0; this->time.rekey = 0; this->time.delete = 0; - this->connection = NULL; - this->policy = NULL; + this->ike_cfg = NULL; + this->peer_cfg = NULL; this->task_manager = task_manager_create(&this->public); this->unique_id = ++unique_id; this->my_virtual_ip = NULL; diff --git a/src/charon/sa/ike_sa.h b/src/charon/sa/ike_sa.h index 604ec94a9..76942b208 100644 --- a/src/charon/sa/ike_sa.h +++ b/src/charon/sa/ike_sa.h @@ -34,14 +34,42 @@ typedef struct ike_sa_t ike_sa_t; #include #include #include -#include #include #include #include #include -#include -#include -#include +#include +#include +#include + +/** + * Timeout in milliseconds after that a half open IKE_SA gets deleted. + * + * @ingroup sa + */ +#define HALF_OPEN_IKE_SA_TIMEOUT 30000 + +/** + * Interval to send keepalives when NATed, in seconds. + * + * @ingroup sa + */ +#define KEEPALIVE_INTERVAL 20 + +/** + * After which time rekeying should be retried if it failed, in seconds. + * + * @ingroup sa + */ +#define RETRY_INTERVAL 30 + +/** + * Jitter to subtract from RETRY_INTERVAL to randomize rekey retry. + * + * @ingroup sa + */ +#define RETRY_JITTER 20 + /** * @brief State of an IKE_SA. @@ -156,6 +184,13 @@ struct ike_sa_t { */ ike_sa_state_t (*get_state) (ike_sa_t *this); + /** + * @brief Get some statistics about this IKE_SA. + * + * @param next_rekeying when the next rekeying is scheduled + */ + void (*get_stats)(ike_sa_t *this, u_int32_t *next_rekeying); + /** * @brief Set the state of the IKE_SA. * @@ -221,7 +256,7 @@ struct ike_sa_t { void (*set_my_id) (ike_sa_t *this, identification_t *me); /** - * @brief Get the other peers identification. + * @brief Get the other peer's identification. * * @param this calling object * @return identification @@ -229,7 +264,7 @@ struct ike_sa_t { identification_t* (*get_other_id) (ike_sa_t *this); /** - * @brief Set the other peers identification. + * @brief Set the other peer's identification. * * @param this calling object * @param other identification @@ -237,51 +272,65 @@ struct ike_sa_t { void (*set_other_id) (ike_sa_t *this, identification_t *other); /** - * @brief Get the connection used by this IKE_SA. + * @brief Get the other peer's certification authority + * + * @param this calling object + * @return ca_info_t record of other ca + */ + ca_info_t* (*get_other_ca) (ike_sa_t *this); + + /** + * @brief Set the other peer's certification authority + * + * @param this calling object + * @param other_ca ca_info_t record of other ca + */ + void (*set_other_ca) (ike_sa_t *this, ca_info_t *other_ca); + + /** + * @brief Get the config used to setup this IKE_SA. * * @param this calling object - * @return connection + * @return ike_config */ - connection_t* (*get_connection) (ike_sa_t *this); + ike_cfg_t* (*get_ike_cfg) (ike_sa_t *this); /** - * @brief Set the connection to use with this IKE_SA. + * @brief Set the config to setup this IKE_SA. * * @param this calling object - * @param connection connection to use + * @param config ike_config to use */ - void (*set_connection) (ike_sa_t *this, connection_t* connection); + void (*set_ike_cfg) (ike_sa_t *this, ike_cfg_t* config); /** - * @brief Get the policy used by this IKE_SA. + * @brief Get the peer config used by this IKE_SA. * * @param this calling object - * @return policy + * @return peer_config */ - policy_t* (*get_policy) (ike_sa_t *this); + peer_cfg_t* (*get_peer_cfg) (ike_sa_t *this); /** - * @brief Set the policy to use with this IKE_SA. + * @brief Set the peer config to use with this IKE_SA. * * @param this calling object - * @param policy policy to use + * @param config peer_config to use */ - void (*set_policy) (ike_sa_t *this, policy_t *policy); + void (*set_peer_cfg) (ike_sa_t *this, peer_cfg_t *config); /** * @brief Initiate a new connection. * - * The policy/connection is owned by the IKE_SA after the call, so - * do not modify or destroy it. + * The configs are owned by the IKE_SA after the call. * * @param this calling object - * @param connection connection to initiate - * @param policy policy to set up + * @param child_cfg child config to create CHILD from * @return * - SUCCESS if initialization started - * - DESTROY_ME if initialization failed and IKE_SA MUST be deleted + * - DESTROY_ME if initialization failed */ - status_t (*initiate) (ike_sa_t *this, connection_t *connection, policy_t *policy); + status_t (*initiate) (ike_sa_t *this, child_cfg_t *child_cfg); /** * @brief Route a policy in the kernel. @@ -290,28 +339,27 @@ struct ike_sa_t { * the kernel requests connection setup from the IKE_SA via acquire(). * * @param this calling object - * @param connection connection definition used for routing - * @param policy policy to route + * @param child_cfg child config to route * @return * - SUCCESS if routed successfully * - FAILED if routing failed */ - status_t (*route) (ike_sa_t *this, connection_t *connection, policy_t *policy); + status_t (*route) (ike_sa_t *this, child_cfg_t *child_cfg); /** * @brief Unroute a policy in the kernel previously routed. * * @param this calling object - * @param policy policy to route + * @param reqid reqid of CHILD_SA to unroute * @return * - SUCCESS if route removed - * - DESTROY_ME if last route was removed from - * an IKE_SA which was not established + * - NOT_FOUND if CHILD_SA not found + * - DESTROY_ME if last CHILD_SA was unrouted */ - status_t (*unroute) (ike_sa_t *this, policy_t *policy); + status_t (*unroute) (ike_sa_t *this, u_int32_t reqid); /** - * @brief Acquire connection setup for a policy. + * @brief Acquire connection setup for an installed kernel policy. * * If an installed policy raises an acquire, the kernel calls * this function to establish the CHILD_SA (and maybe the IKE_SA). @@ -320,7 +368,7 @@ struct ike_sa_t { * @param reqid reqid of the CHILD_SA the policy belongs to. * @return * - SUCCESS if initialization started - * - DESTROY_ME if initialization failed and IKE_SA MUST be deleted + * - DESTROY_ME if initialization failed */ status_t (*acquire) (ike_sa_t *this, u_int32_t reqid); @@ -456,7 +504,7 @@ struct ike_sa_t { bool initiator, prf_t *child_prf, prf_t *old_prf); /** - * @brief Get the multi purpose prf. + * @brief Get a multi purpose prf for the negotiated PRF function. * * @param this calling object * @return pointer to prf_t object @@ -472,20 +520,20 @@ struct ike_sa_t { prf_t *(*get_child_prf) (ike_sa_t *this); /** - * @brief Get the prf to build outgoing authentication data. + * @brief Get the key to build outgoing authentication data. * * @param this calling object * @return pointer to prf_t object */ - prf_t *(*get_auth_build) (ike_sa_t *this); + chunk_t (*get_skp_build) (ike_sa_t *this); /** - * @brief Get the prf to verify incoming authentication data. + * @brief Get the key to verify incoming authentication data. * * @param this calling object * @return pointer to prf_t object */ - prf_t *(*get_auth_verify) (ike_sa_t *this); + chunk_t (*get_skp_verify) (ike_sa_t *this); /** * @brief Associates a child SA to this IKE SA diff --git a/src/charon/sa/ike_sa_id.c b/src/charon/sa/ike_sa_id.c index c143fc0ba..a838c0b8a 100644 --- a/src/charon/sa/ike_sa_id.c +++ b/src/charon/sa/ike_sa_id.c @@ -24,7 +24,6 @@ #include "ike_sa_id.h" -#include #include @@ -152,33 +151,6 @@ static ike_sa_id_t* clone_(private_ike_sa_id_t *this) return ike_sa_id_create(this->initiator_spi, this->responder_spi, this->is_initiator_flag); } -/** - * output handler in printf() - */ -static int print(FILE *stream, const struct printf_info *info, - const void *const *args) -{ - private_ike_sa_id_t *this = *((private_ike_sa_id_t**)(args[0])); - - if (this == NULL) - { - return fprintf(stream, "(null)"); - } - return fprintf(stream, "0x%0llx_i%s 0x%0llx_r%s", - this->initiator_spi, - this->is_initiator_flag ? "*" : "", - this->responder_spi, - this->is_initiator_flag ? "" : "*"); -} - -/** - * register printf() handlers - */ -static void __attribute__ ((constructor))print_register() -{ - register_printf_function(PRINTF_IKE_SA_ID, print, arginfo_ptr); -} - /** * Implementation of ike_sa_id_t.destroy. */ diff --git a/src/charon/sa/ike_sa_manager.c b/src/charon/sa/ike_sa_manager.c index 791ef805e..a62ec5e3c 100644 --- a/src/charon/sa/ike_sa_manager.c +++ b/src/charon/sa/ike_sa_manager.c @@ -322,8 +322,8 @@ static ike_sa_t* checkout(private_ike_sa_manager_t *this, ike_sa_id_t *ike_sa_id ike_sa_t *ike_sa = NULL; entry_t *entry; - DBG2(DBG_MGR, "checkout IKE_SA: %J, %d IKE_SAs in manager", - ike_sa_id, this->ike_sa_list->get_count(this->ike_sa_list)); + DBG2(DBG_MGR, "checkout IKE_SA, %d IKE_SAs in manager", + this->ike_sa_list->get_count(this->ike_sa_list)); pthread_mutex_lock(&(this->mutex)); if (get_entry_by_id(this, ike_sa_id, &entry) == SUCCESS) @@ -356,13 +356,14 @@ static ike_sa_t *checkout_new(private_ike_sa_manager_t* this, bool initiator) { id = ike_sa_id_create(0, get_next_spi(this), FALSE); } - entry = entry_create(id); + entry = entry_create(id); + id->destroy(id); pthread_mutex_lock(&this->mutex); this->ike_sa_list->insert_last(this->ike_sa_list, entry); entry->checked_out = TRUE; pthread_mutex_unlock(&this->mutex); - DBG2(DBG_MGR, "created IKE_SA: %J, %d IKE_SAs in manager", - id, this->ike_sa_list->get_count(this->ike_sa_list)); + DBG2(DBG_MGR, "created IKE_SA, %d IKE_SAs in manager", + this->ike_sa_list->get_count(this->ike_sa_list)); return entry->ike_sa; } @@ -378,8 +379,8 @@ static ike_sa_t* checkout_by_message(private_ike_sa_manager_t* this, id = id->clone(id); id->switch_initiator(id); - DBG2(DBG_MGR, "checkout IKE_SA: %J by message, %d IKE_SAs in manager", - id, this->ike_sa_list->get_count(this->ike_sa_list)); + DBG2(DBG_MGR, "checkout IKE_SA by message, %d IKE_SAs in manager", + this->ike_sa_list->get_count(this->ike_sa_list)); if (message->get_request(message) && message->get_exchange_type(message) == IKE_SA_INIT) @@ -439,7 +440,8 @@ static ike_sa_t* checkout_by_message(private_ike_sa_manager_t* this, } else { - DBG1(DBG_MGR, "ignoring message for %J, no such IKE_SA", id); + chunk_free(&hash); + DBG1(DBG_MGR, "ignoring message, no such IKE_SA"); } } else @@ -554,7 +556,7 @@ static ike_sa_t* checkout_by_peer(private_ike_sa_manager_t *this, /* create entry */ new_entry = entry_create(new_ike_sa_id); - DBG2(DBG_MGR, "created IKE_SA: %J", new_ike_sa_id); + DBG2(DBG_MGR, "created IKE_SA"); new_ike_sa_id->destroy(new_ike_sa_id); this->ike_sa_list->insert_last(this->ike_sa_list, new_entry); @@ -720,7 +722,7 @@ static status_t checkin(private_ike_sa_manager_t *this, ike_sa_t *ike_sa) ike_sa_id = ike_sa->get_id(ike_sa); - DBG2(DBG_MGR, "checkin IKE_SA: %J", ike_sa_id); + DBG2(DBG_MGR, "checkin IKE_SA"); pthread_mutex_lock(&(this->mutex)); @@ -767,7 +769,7 @@ static status_t checkin_and_destroy(private_ike_sa_manager_t *this, ike_sa_t *ik ike_sa_id_t *ike_sa_id; ike_sa_id = ike_sa->get_id(ike_sa); - DBG2(DBG_MGR, "checkin and destroy IKE_SA: %J", ike_sa_id); + DBG2(DBG_MGR, "checkin and destroy IKE_SA"); pthread_mutex_lock(&(this->mutex)); diff --git a/src/charon/sa/task_manager.c b/src/charon/sa/task_manager.c index 844300735..e67508ed1 100644 --- a/src/charon/sa/task_manager.c +++ b/src/charon/sa/task_manager.c @@ -22,6 +22,8 @@ #include "task_manager.h" +#include + #include #include #include @@ -35,7 +37,7 @@ #include #include #include -#include +#include typedef struct exchange_t exchange_t; @@ -210,9 +212,12 @@ static status_t retransmit(private_task_manager_t *this, u_int32_t message_id) u_int32_t timeout; job_t *job; - timeout = charon->configuration->get_retransmit_timeout( - charon->configuration, this->initiating.retransmitted); - if (timeout == 0) + if (this->initiating.retransmitted <= RETRANSMIT_TRIES) + { + timeout = (u_int32_t)(RETRANSMIT_TIMEOUT * + pow(RETRANSMIT_BASE, this->initiating.retransmitted)); + } + else { DBG1(DBG_IKE, "giving up after %d retransmits", this->initiating.retransmitted - 1); @@ -262,6 +267,7 @@ static status_t build_request(private_task_manager_t *this) case IKE_CREATED: if (activate_task(this, IKE_INIT)) { + this->initiating.mid = 0; exchange = IKE_SA_INIT; activate_task(this, IKE_NATD); activate_task(this, IKE_CERT); @@ -274,7 +280,6 @@ static status_t build_request(private_task_manager_t *this) if (activate_task(this, CHILD_CREATE)) { exchange = CREATE_CHILD_SA; - activate_task(this, IKE_CONFIG); break; } if (activate_task(this, CHILD_DELETE)) @@ -328,6 +333,11 @@ static status_t build_request(private_task_manager_t *this) case IKE_AUTHENTICATE: exchange = IKE_AUTH; break; + case CHILD_CREATE: + case CHILD_REKEY: + case IKE_REKEY: + exchange = CREATE_CHILD_SA; + break; default: continue; } @@ -577,7 +587,7 @@ static status_t process_request(private_task_manager_t *this, this->passive_tasks->insert_last(this->passive_tasks, task); task = (task_t*)ike_auth_create(this->ike_sa, FALSE); this->passive_tasks->insert_last(this->passive_tasks, task); - task = (task_t*)ike_config_create(this->ike_sa, NULL); + task = (task_t*)ike_config_create(this->ike_sa, FALSE); this->passive_tasks->insert_last(this->passive_tasks, task); task = (task_t*)child_create_create(this->ike_sa, NULL); this->passive_tasks->insert_last(this->passive_tasks, task); diff --git a/src/charon/sa/task_manager.h b/src/charon/sa/task_manager.h index c766d4a65..fb34aab6a 100644 --- a/src/charon/sa/task_manager.h +++ b/src/charon/sa/task_manager.h @@ -30,6 +30,28 @@ typedef struct task_manager_t task_manager_t; #include #include +/** + * First retransmit timeout in milliseconds. + * + * @ingroup sa + */ +#define RETRANSMIT_TIMEOUT 4000 + +/** + * Base which is raised to the power of the retransmission try. + * + * @ingroup sa + */ +#define RETRANSMIT_BASE 1.8 + +/** + * Number of retransmits done before giving up. + * + * @ingroup sa + */ +#define RETRANSMIT_TRIES 5 + + /** * @brief The task manager, juggles task and handles message exchanges. * @@ -43,6 +65,24 @@ typedef struct task_manager_t task_manager_t; * For the initial IKE_SA setup, several tasks are queued: One for the * unauthenticated IKE_SA setup, one for authentication, one for CHILD_SA setup * and maybe one for virtual IP assignement. + * The task manager is also responsible for retransmission. It uses a backoff + * algorithm. The timeout is calculated using + * RETRANSMIT_TIMEOUT * (RETRANSMIT_BASE ** try). + * When try reaches RETRANSMIT_TRIES, retransmission is given up. + * + * Using an initial TIMEOUT of 4s, a BASE of 1.8, and 5 TRIES gives us: + * @verbatim + | relative | absolute + --------------------------------------------------------- + 4s * (1.8 ** 0) = 4s 4s + 4s * (1.8 ** 1) = 7s 11s + 4s * (1.8 ** 2) = 13s 24s + 4s * (1.8 ** 3) = 23s 47s + 4s * (1.8 ** 4) = 42s 89s + 4s * (1.8 ** 5) = 76s 165s + + @endberbatim + * The peer is considered dead after 2min 45s when no reply comes in. * * @b Constructors: * - task_manager_create() diff --git a/src/charon/sa/tasks/child_create.c b/src/charon/sa/tasks/child_create.c index 781d679f2..f70730b05 100644 --- a/src/charon/sa/tasks/child_create.c +++ b/src/charon/sa/tasks/child_create.c @@ -26,6 +26,7 @@ #include #include #include +#include #include #include #include @@ -64,9 +65,9 @@ struct private_child_create_t { chunk_t other_nonce; /** - * policy to create the CHILD_SA from + * config to create the CHILD_SA from */ - policy_t *policy; + child_cfg_t *config; /** * list of proposal candidates @@ -88,6 +89,16 @@ struct private_child_create_t { */ linked_list_t *tsr; + /** + * optional diffie hellman exchange + */ + diffie_hellman_t *dh; + + /** + * group used for DH exchange + */ + diffie_hellman_group_t dh_group; + /** * mode the new CHILD_SA uses (transport/tunnel/beet) */ @@ -162,21 +173,29 @@ static bool ts_list_is_host(linked_list_t *list, host_t *host) } /** - * Install a CHILD_SA for usage + * Install a CHILD_SA for usage, return value: + * - FAILED: no acceptable proposal + * - INVALID_ARG: diffie hellman group inacceptable + * - NOT_FOUND: TS inacceptable */ -static status_t select_and_install(private_child_create_t *this) +static status_t select_and_install(private_child_create_t *this, bool no_dh) { prf_plus_t *prf_plus; status_t status; - chunk_t nonce_i, nonce_r, seed; + chunk_t nonce_i, nonce_r, secret, seed; linked_list_t *my_ts, *other_ts; host_t *me, *other, *other_vip, *my_vip; - if (this->proposals == NULL || this->tsi == NULL || this->tsr == NULL) + if (this->proposals == NULL) { - SIG(CHILD_UP_FAILED, "SA/TS payloads missing in message"); + SIG(CHILD_UP_FAILED, "SA payload missing in message"); return FAILED; } + if (this->tsi == NULL || this->tsr == NULL) + { + SIG(CHILD_UP_FAILED, "TS payloads missing in message"); + return NOT_FOUND; + } if (this->initiator) { @@ -198,36 +217,61 @@ static status_t select_and_install(private_child_create_t *this) my_vip = this->ike_sa->get_virtual_ip(this->ike_sa, TRUE); other_vip = this->ike_sa->get_virtual_ip(this->ike_sa, FALSE); - this->proposal = this->policy->select_proposal(this->policy, this->proposals); - + this->proposal = this->config->select_proposal(this->config, this->proposals, + no_dh); if (this->proposal == NULL) { SIG(CHILD_UP_FAILED, "no acceptable proposal found"); return FAILED; } - if (this->initiator && my_vip) - { /* if we have a virtual IP, shorten our TS to the minimum */ - my_ts = this->policy->select_my_traffic_selectors(this->policy, my_ts, - my_vip); + if (!this->proposal->has_dh_group(this->proposal, this->dh_group)) + { + algorithm_t *algo; + if (this->proposal->get_algorithm(this->proposal, DIFFIE_HELLMAN_GROUP, + &algo)) + { + u_int16_t group = algo->algorithm; + SIG(CHILD_UP_FAILED, "DH group %N inacceptable, requesting %N", + diffie_hellman_group_names, this->dh_group, + diffie_hellman_group_names, group); + this->dh_group = group; + return INVALID_ARG; + } + else + { + SIG(CHILD_UP_FAILED, "no acceptable proposal found"); + return FAILED; + } + } + + if (my_vip == NULL) + { + my_vip = me; + } + else if (this->initiator) + { /* to setup firewall rules correctly, CHILD_SA needs the virtual IP */ this->child_sa->set_virtual_ip(this->child_sa, my_vip); } - else - { /* shorten in the host2host case only */ - my_ts = this->policy->select_my_traffic_selectors(this->policy, - my_ts, me); - } - if (other_vip) - { /* if other has a virtual IP, shorten it's traffic selectors to it */ - other_ts = this->policy->select_other_traffic_selectors(this->policy, - other_ts, other_vip); + if (other_vip == NULL) + { + other_vip = other; } - else - { /* use his host for the host2host case */ - other_ts = this->policy->select_other_traffic_selectors(this->policy, - other_ts, other); + + my_ts = this->config->get_traffic_selectors(this->config, TRUE, my_ts, + my_vip); + other_ts = this->config->get_traffic_selectors(this->config, FALSE, other_ts, + other_vip); + + if (my_ts->get_count(my_ts) == 0 || other_ts->get_count(other_ts) == 0) + { + my_ts->destroy_offset(my_ts, offsetof(traffic_selector_t, destroy)); + other_ts->destroy_offset(other_ts, offsetof(traffic_selector_t, destroy)); + SIG(CHILD_UP_FAILED, "no acceptable traffic selectors found"); + return NOT_FOUND; } + this->tsr->destroy_offset(this->tsr, offsetof(traffic_selector_t, destroy)); this->tsi->destroy_offset(this->tsi, offsetof(traffic_selector_t, destroy)); if (this->initiator) @@ -241,13 +285,6 @@ static status_t select_and_install(private_child_create_t *this) this->tsi = other_ts; } - if (this->tsi->get_count(this->tsi) == 0 || - this->tsr->get_count(this->tsr) == 0) - { - SIG(CHILD_UP_FAILED, "no acceptable traffic selectors found"); - return FAILED; - } - if (!this->initiator) { /* check if requested mode is acceptable, downgrade if required */ @@ -279,7 +316,20 @@ static status_t select_and_install(private_child_create_t *this) } } - seed = chunk_cata("cc", nonce_i, nonce_r); + if (this->dh) + { + if (this->dh->get_shared_secret(this->dh, &secret) != SUCCESS) + { + SIG(CHILD_UP_FAILED, "DH exchange incomplete"); + return FAILED; + } + DBG3(DBG_IKE, "DH secret %B", &secret); + seed = chunk_cata("mcc", secret, nonce_i, nonce_r); + } + else + { + seed = chunk_cata("cc", nonce_i, nonce_r); + } prf_plus = prf_plus_create(this->ike_sa->get_child_prf(this->ike_sa), seed); if (this->initiator) @@ -297,7 +347,7 @@ static status_t select_and_install(private_child_create_t *this) if (status != SUCCESS) { SIG(CHILD_UP_FAILED, "unable to install IPsec SA (SAD) in kernel"); - return status; + return FAILED; } status = this->child_sa->add_policies(this->child_sa, my_ts, other_ts, @@ -306,7 +356,7 @@ static status_t select_and_install(private_child_create_t *this) if (status != SUCCESS) { SIG(CHILD_UP_FAILED, "unable to install IPsec policies (SPD) in kernel"); - return status; + return NOT_FOUND; } /* add to IKE_SA, and remove from task */ this->child_sa->set_state(this->child_sa, CHILD_INSTALLED); @@ -321,8 +371,9 @@ static status_t select_and_install(private_child_create_t *this) static void build_payloads(private_child_create_t *this, message_t *message) { sa_payload_t *sa_payload; - ts_payload_t *ts_payload; nonce_payload_t *nonce_payload; + ke_payload_t *ke_payload; + ts_payload_t *ts_payload; /* add SA payload */ if (this->initiator) @@ -343,6 +394,13 @@ static void build_payloads(private_child_create_t *this, message_t *message) message->add_payload(message, (payload_t*)nonce_payload); } + /* diffie hellman exchange, if PFS enabled */ + if (this->dh) + { + ke_payload = ke_payload_create_from_diffie_hellman(this->dh); + message->add_payload(message, (payload_t*)ke_payload); + } + /* add TSi/TSr payloads */ ts_payload = ts_payload_create_from_traffic_selectors(TRUE, this->tsi); message->add_payload(message, (payload_t*)ts_payload); @@ -371,6 +429,7 @@ static void process_payloads(private_child_create_t *this, message_t *message) iterator_t *iterator; payload_t *payload; sa_payload_t *sa_payload; + ke_payload_t *ke_payload; ts_payload_t *ts_payload; notify_payload_t *notify_payload; @@ -386,6 +445,19 @@ static void process_payloads(private_child_create_t *this, message_t *message) sa_payload = (sa_payload_t*)payload; this->proposals = sa_payload->get_proposals(sa_payload); break; + case KEY_EXCHANGE: + ke_payload = (ke_payload_t*)payload; + if (!this->initiator) + { + this->dh_group = ke_payload->get_dh_group_number(ke_payload); + this->dh = diffie_hellman_create(this->dh_group); + } + if (this->dh) + { + this->dh->set_other_public_value(this->dh, + ke_payload->get_key_exchange_data(ke_payload)); + } + break; case TRAFFIC_SELECTOR_INITIATOR: ts_payload = (ts_payload_t*)payload; this->tsi = ts_payload->get_traffic_selectors(ts_payload); @@ -421,6 +493,7 @@ static void process_payloads(private_child_create_t *this, message_t *message) static status_t build_i(private_child_create_t *this, message_t *message) { host_t *me, *other, *vip; + peer_cfg_t *peer_cfg; switch (message->get_exchange_type(message)) { @@ -432,6 +505,10 @@ static status_t build_i(private_child_create_t *this, message_t *message) message->add_notify(message, FALSE, NO_PROPOSAL_CHOSEN, chunk_empty); return SUCCESS; } + if (this->dh_group == MODP_NONE) + { + this->dh_group = this->config->get_dh_group(this->config); + } break; case IKE_AUTH: if (!message->get_payload(message, ID_INITIATOR)) @@ -448,25 +525,30 @@ static status_t build_i(private_child_create_t *this, message_t *message) me = this->ike_sa->get_my_host(this->ike_sa); other = this->ike_sa->get_other_host(this->ike_sa); - vip = this->policy->get_virtual_ip(this->policy, NULL); + peer_cfg = this->ike_sa->get_peer_cfg(this->ike_sa); + vip = peer_cfg->get_my_virtual_ip(peer_cfg); if (vip) { /* propose a 0.0.0.0/0 subnet when we use virtual ip */ - this->tsi = this->policy->get_my_traffic_selectors(this->policy, NULL); + this->tsi = this->config->get_traffic_selectors(this->config, TRUE, + NULL, NULL); vip->destroy(vip); } else { /* but shorten a 0.0.0.0/0 subnet to the actual address if host2host */ - this->tsi = this->policy->get_my_traffic_selectors(this->policy, me); + this->tsi = this->config->get_traffic_selectors(this->config, TRUE, + NULL, me); } - this->tsr = this->policy->get_other_traffic_selectors(this->policy, other); - this->proposals = this->policy->get_proposals(this->policy); - this->mode = this->policy->get_mode(this->policy); + this->tsr = this->config->get_traffic_selectors(this->config, FALSE, + NULL, other); + this->proposals = this->config->get_proposals(this->config, + this->dh_group == MODP_NONE); + this->mode = this->config->get_mode(this->config); this->child_sa = child_sa_create(me, other, this->ike_sa->get_my_id(this->ike_sa), this->ike_sa->get_other_id(this->ike_sa), - this->policy, this->reqid, + this->config, this->reqid, this->ike_sa->is_natt_enabled(this->ike_sa)); if (this->child_sa->alloc(this->child_sa, this->proposals) != SUCCESS) @@ -475,6 +557,11 @@ static status_t build_i(private_child_create_t *this, message_t *message) return FAILED; } + if (this->dh_group != MODP_NONE) + { + this->dh = diffie_hellman_create(this->dh_group); + } + build_payloads(this, message); this->tsi->destroy_offset(this->tsi, offsetof(traffic_selector_t, destroy)); @@ -492,6 +579,8 @@ static status_t build_i(private_child_create_t *this, message_t *message) */ static status_t process_r(private_child_create_t *this, message_t *message) { + peer_cfg_t *peer_cfg; + switch (message->get_exchange_type(message)) { case IKE_SA_INIT: @@ -517,18 +606,13 @@ static status_t process_r(private_child_create_t *this, message_t *message) return NEED_MORE; } - this->policy = charon->policies->get_policy(charon->policies, - this->ike_sa->get_my_id(this->ike_sa), - this->ike_sa->get_other_id(this->ike_sa), - this->tsr, this->tsi, - this->ike_sa->get_my_host(this->ike_sa), - this->ike_sa->get_other_host(this->ike_sa)); - - if (this->policy && this->ike_sa->get_policy(this->ike_sa) == NULL) + peer_cfg = this->ike_sa->get_peer_cfg(this->ike_sa); + if (peer_cfg) { - this->ike_sa->set_policy(this->ike_sa, this->policy); + this->config = peer_cfg->select_child_cfg(peer_cfg, this->tsr, this->tsi, + this->ike_sa->get_my_host(this->ike_sa), + this->ike_sa->get_other_host(this->ike_sa)); } - return NEED_MORE; } @@ -537,6 +621,8 @@ static status_t process_r(private_child_create_t *this, message_t *message) */ static status_t build_r(private_child_create_t *this, message_t *message) { + bool no_dh = TRUE; + switch (message->get_exchange_type(message)) { case IKE_SA_INIT: @@ -547,6 +633,7 @@ static status_t build_r(private_child_create_t *this, message_t *message) message->add_notify(message, FALSE, NO_PROPOSAL_CHOSEN, chunk_empty); return SUCCESS; } + no_dh = FALSE; break; case IKE_AUTH: if (message->get_payload(message, EXTENSIBLE_AUTHENTICATION)) @@ -565,10 +652,11 @@ static status_t build_r(private_child_create_t *this, message_t *message) return SUCCESS; } - if (this->policy == NULL) + if (this->config == NULL) { - SIG(CHILD_UP_FAILED, "no acceptable policy found"); - message->add_notify(message, FALSE, NO_PROPOSAL_CHOSEN, chunk_empty); + SIG(CHILD_UP_FAILED, "traffic selectors %#R=== %#R inacceptable", + this->tsr, this->tsi); + message->add_notify(message, FALSE, TS_UNACCEPTABLE, chunk_empty); return SUCCESS; } @@ -576,13 +664,27 @@ static status_t build_r(private_child_create_t *this, message_t *message) this->ike_sa->get_other_host(this->ike_sa), this->ike_sa->get_my_id(this->ike_sa), this->ike_sa->get_other_id(this->ike_sa), - this->policy, this->reqid, + this->config, this->reqid, this->ike_sa->is_natt_enabled(this->ike_sa)); - if (select_and_install(this) != SUCCESS) + switch (select_and_install(this, no_dh)) { - message->add_notify(message, FALSE, TS_UNACCEPTABLE, chunk_empty); - return SUCCESS; + case SUCCESS: + break; + case NOT_FOUND: + message->add_notify(message, FALSE, TS_UNACCEPTABLE, chunk_empty); + return SUCCESS; + case INVALID_ARG: + { + u_int16_t group = htons(this->dh_group); + message->add_notify(message, FALSE, INVALID_KE_PAYLOAD, + chunk_from_thing(group)); + return SUCCESS; + } + case FAILED: + default: + message->add_notify(message, FALSE, NO_PROPOSAL_CHOSEN, chunk_empty); + return SUCCESS; } build_payloads(this, message); @@ -599,6 +701,7 @@ static status_t process_i(private_child_create_t *this, message_t *message) { iterator_t *iterator; payload_t *payload; + bool no_dh = TRUE; switch (message->get_exchange_type(message)) { @@ -606,6 +709,7 @@ static status_t process_i(private_child_create_t *this, message_t *message) return get_nonce(message, &this->other_nonce); case CREATE_CHILD_SA: get_nonce(message, &this->other_nonce); + no_dh = FALSE; break; case IKE_AUTH: if (message->get_payload(message, EXTENSIBLE_AUTHENTICATION)) @@ -643,6 +747,22 @@ static status_t process_i(private_child_create_t *this, message_t *message) /* an error in CHILD_SA creation is not critical */ return SUCCESS; } + case INVALID_KE_PAYLOAD: + { + chunk_t data; + diffie_hellman_group_t bad_group; + + bad_group = this->dh_group; + data = notify->get_notification_data(notify); + this->dh_group = ntohs(*((u_int16_t*)data.ptr)); + DBG1(DBG_IKE, "peer didn't accept DH group %N, " + "it requested %N", diffie_hellman_group_names, + bad_group, diffie_hellman_group_names, this->dh_group); + + this->public.task.migrate(&this->public.task, this->ike_sa); + iterator->destroy(iterator); + return NEED_MORE; + } default: break; } @@ -652,7 +772,7 @@ static status_t process_i(private_child_create_t *this, message_t *message) process_payloads(this, message); - if (select_and_install(this) == SUCCESS) + if (select_and_install(this, no_dh) == SUCCESS) { SIG(CHILD_UP_SUCCESS, "established CHILD_SA successfully"); } @@ -716,6 +836,7 @@ static void migrate(private_child_create_t *this, ike_sa_t *ike_sa) } DESTROY_IF(this->child_sa); DESTROY_IF(this->proposal); + DESTROY_IF(this->dh); if (this->proposals) { this->proposals->destroy_offset(this->proposals, offsetof(proposal_t, destroy)); @@ -725,6 +846,7 @@ static void migrate(private_child_create_t *this, ike_sa_t *ike_sa) this->proposals = NULL; this->tsi = NULL; this->tsr = NULL; + this->dh = NULL; this->child_sa = NULL; this->mode = MODE_TUNNEL; this->reqid = 0; @@ -751,19 +873,20 @@ static void destroy(private_child_create_t *this) DESTROY_IF(this->child_sa); } DESTROY_IF(this->proposal); + DESTROY_IF(this->dh); if (this->proposals) { this->proposals->destroy_offset(this->proposals, offsetof(proposal_t, destroy)); } - DESTROY_IF(this->policy); + DESTROY_IF(this->config); free(this); } /* * Described in header. */ -child_create_t *child_create_create(ike_sa_t *ike_sa, policy_t *policy) +child_create_t *child_create_create(ike_sa_t *ike_sa, child_cfg_t *config) { private_child_create_t *this = malloc_thing(private_child_create_t); @@ -773,12 +896,12 @@ child_create_t *child_create_create(ike_sa_t *ike_sa, policy_t *policy) this->public.task.get_type = (task_type_t(*)(task_t*))get_type; this->public.task.migrate = (void(*)(task_t*,ike_sa_t*))migrate; this->public.task.destroy = (void(*)(task_t*))destroy; - if (policy) + if (config) { this->public.task.build = (status_t(*)(task_t*,message_t*))build_i; this->public.task.process = (status_t(*)(task_t*,message_t*))process_i; this->initiator = TRUE; - policy->get_ref(policy); + config->get_ref(config); } else { @@ -788,13 +911,15 @@ child_create_t *child_create_create(ike_sa_t *ike_sa, policy_t *policy) } this->ike_sa = ike_sa; - this->policy = policy; + this->config = config; this->my_nonce = chunk_empty; this->other_nonce = chunk_empty; this->proposals = NULL; this->proposal = NULL; this->tsi = NULL; this->tsr = NULL; + this->dh = NULL; + this->dh_group = MODP_NONE; this->child_sa = NULL; this->mode = MODE_TUNNEL; this->reqid = 0; diff --git a/src/charon/sa/tasks/child_create.h b/src/charon/sa/tasks/child_create.h index 200d37457..9f4815215 100644 --- a/src/charon/sa/tasks/child_create.h +++ b/src/charon/sa/tasks/child_create.h @@ -28,7 +28,7 @@ typedef struct child_create_t child_create_t; #include #include #include -#include +#include /** * @brief Task of type CHILD_CREATE, established a new CHILD_SA. @@ -80,9 +80,9 @@ struct child_create_t { * @brief Create a new child_create task. * * @param ike_sa IKE_SA this task works for - * @param policy policy if task initiator, NULL if responder + * @param config child_cfg if task initiator, NULL if responder * @return child_create task to handle by the task_manager */ -child_create_t *child_create_create(ike_sa_t *ike_sa, policy_t *policy); +child_create_t *child_create_create(ike_sa_t *ike_sa, child_cfg_t *config); #endif /* CHILD_CREATE_H_ */ diff --git a/src/charon/sa/tasks/child_delete.c b/src/charon/sa/tasks/child_delete.c index 23d509de5..d0b34a276 100644 --- a/src/charon/sa/tasks/child_delete.c +++ b/src/charon/sa/tasks/child_delete.c @@ -176,11 +176,30 @@ static void destroy_children(private_child_delete_t *this) iterator->destroy(iterator); } +/** + * send closing signals for all CHILD_SAs over the bus + */ +static void log_children(private_child_delete_t *this) +{ + 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)) + { + SIG(CHILD_DOWN_START, "closing CHILD_SA %#R=== %#R", + child_sa->get_traffic_selectors(child_sa, TRUE), + child_sa->get_traffic_selectors(child_sa, FALSE)); + } + iterator->destroy(iterator); +} + /** * Implementation of task_t.build for initiator */ static status_t build_i(private_child_delete_t *this, message_t *message) { + log_children(this); build_payloads(this, message); return NEED_MORE; } @@ -196,6 +215,7 @@ static status_t process_i(private_child_delete_t *this, message_t *message) process_payloads(this, message); destroy_children(this); + SIG(CHILD_DOWN_SUCCESS, "CHILD_SA closed"); return SUCCESS; } @@ -205,6 +225,7 @@ static status_t process_i(private_child_delete_t *this, message_t *message) static status_t process_r(private_child_delete_t *this, message_t *message) { process_payloads(this, message); + log_children(this); return NEED_MORE; } @@ -219,6 +240,7 @@ static status_t build_r(private_child_delete_t *this, message_t *message) build_payloads(this, message); } destroy_children(this); + SIG(CHILD_DOWN_SUCCESS, "CHILD_SA closed"); return SUCCESS; } diff --git a/src/charon/sa/tasks/child_rekey.c b/src/charon/sa/tasks/child_rekey.c index 745895dbb..4f3c69034 100644 --- a/src/charon/sa/tasks/child_rekey.c +++ b/src/charon/sa/tasks/child_rekey.c @@ -27,7 +27,7 @@ #include #include #include -#include +#include typedef struct private_child_rekey_t private_child_rekey_t; @@ -183,7 +183,12 @@ static status_t process_i(private_child_rekey_t *this, message_t *message) u_int32_t spi; child_sa_t *to_delete; - this->child_create->task.process(&this->child_create->task, message); + if (this->child_create->task.process(&this->child_create->task, message) == NEED_MORE) + { + /* bad DH group while rekeying, try again */ + this->child_create->task.migrate(&this->child_create->task, this->ike_sa); + return NEED_MORE; + } if (message->get_payload(message, SECURITY_ASSOCIATION) == NULL) { /* establishing new child failed, reuse old. but not when we @@ -192,8 +197,8 @@ static status_t process_i(private_child_rekey_t *this, message_t *message) this->collision->get_type(this->collision) == CHILD_DELETE)) { job_t *job; - u_int32_t retry = charon->configuration->get_retry_interval( - charon->configuration); + u_int32_t retry = RETRY_INTERVAL - (random() % RETRY_JITTER); + job = (job_t*)rekey_child_sa_job_create( this->child_sa->get_reqid(this->child_sa), this->child_sa->get_protocol(this->child_sa), @@ -315,8 +320,8 @@ static void destroy(private_child_rekey_t *this) */ child_rekey_t *child_rekey_create(ike_sa_t *ike_sa, child_sa_t *child_sa) { + child_cfg_t *config; private_child_rekey_t *this = malloc_thing(private_child_rekey_t); - policy_t *policy; this->public.collide = (void (*)(child_rekey_t*,task_t*))collide; this->public.task.get_type = (task_type_t(*)(task_t*))get_type; @@ -327,8 +332,8 @@ child_rekey_t *child_rekey_create(ike_sa_t *ike_sa, child_sa_t *child_sa) this->public.task.build = (status_t(*)(task_t*,message_t*))build_i; this->public.task.process = (status_t(*)(task_t*,message_t*))process_i; this->initiator = TRUE; - policy = child_sa->get_policy(child_sa); - this->child_create = child_create_create(ike_sa, policy); + config = child_sa->get_config(child_sa); + this->child_create = child_create_create(ike_sa, config); } else { diff --git a/src/charon/sa/tasks/ike_auth.c b/src/charon/sa/tasks/ike_auth.c index 541e1bb37..d0dd49aee 100644 --- a/src/charon/sa/tasks/ike_auth.c +++ b/src/charon/sa/tasks/ike_auth.c @@ -100,18 +100,18 @@ static status_t build_auth(private_ike_auth_t *this, message_t *message) { authenticator_t *auth; auth_payload_t *auth_payload; - policy_t *policy; + peer_cfg_t *config; auth_method_t method; status_t status; /* create own authenticator and add auth payload */ - policy = this->ike_sa->get_policy(this->ike_sa); - if (!policy) + config = this->ike_sa->get_peer_cfg(this->ike_sa); + if (!config) { - SIG(IKE_UP_FAILED, "unable to authenticate, no policy found"); + SIG(IKE_UP_FAILED, "unable to authenticate, no peer config found"); return FAILED; } - method = policy->get_auth_method(policy); + method = config->get_auth_method(config); auth = authenticator_create(this->ike_sa, method); if (auth == NULL) @@ -140,15 +140,15 @@ static status_t build_id(private_ike_auth_t *this, message_t *message) { identification_t *me, *other; id_payload_t *id; - policy_t *policy; + peer_cfg_t *config; me = this->ike_sa->get_my_id(this->ike_sa); other = this->ike_sa->get_other_id(this->ike_sa); - policy = this->ike_sa->get_policy(this->ike_sa); + config = this->ike_sa->get_peer_cfg(this->ike_sa); if (me->contains_wildcards(me)) { - me = policy->get_my_id(policy); + me = config->get_my_id(config); if (me->contains_wildcards(me)) { SIG(IKE_UP_FAILED, "negotiation of own ID failed"); @@ -202,7 +202,7 @@ static status_t process_auth(private_ike_auth_t *this, message_t *message) auth->destroy(auth); if (status != SUCCESS) { - SIG(IKE_UP_FAILED, "authentication of %D using %N failed", + SIG(IKE_UP_FAILED, "authentication of '%D' with %N failed", this->ike_sa->get_other_id(this->ike_sa), auth_method_names, auth_method); return FAILED; @@ -215,7 +215,7 @@ static status_t process_auth(private_ike_auth_t *this, message_t *message) */ static status_t process_id(private_ike_auth_t *this, message_t *message) { - identification_t *id; + identification_t *id, *req; id_payload_t *idr, *idi; idi = (id_payload_t*)message->get_payload(message, ID_INITIATOR); @@ -230,6 +230,13 @@ static status_t process_id(private_ike_auth_t *this, message_t *message) if (this->initiator) { id = idr->get_identification(idr); + req = this->ike_sa->get_other_id(this->ike_sa); + if (!id->matches(id, req, NULL)) + { + SIG(IKE_UP_FAILED, "peer ID %D unacceptable, %D required", id, req); + id->destroy(id); + return FAILED; + } this->ike_sa->set_other_id(this->ike_sa, id); } else @@ -346,7 +353,7 @@ static status_t process_auth_eap(private_ike_auth_t *this, message_t *message) if (!this->peer_authenticated) { - SIG(IKE_UP_FAILED, "authentication of %D using %N failed", + SIG(IKE_UP_FAILED, "authentication of '%D' with %N failed", this->ike_sa->get_other_id(this->ike_sa), auth_method_names, AUTH_EAP); if (this->initiator) @@ -444,7 +451,7 @@ static status_t build_eap_r(private_ike_auth_t *this, message_t *message) this->public.task.process = (status_t(*)(task_t*,message_t*))process_auth_eap; break; default: - SIG(IKE_UP_FAILED, "authentication of %D using %N failed", + SIG(IKE_UP_FAILED, "authentication of '%D' with %N failed", this->ike_sa->get_other_id(this->ike_sa), auth_method_names, AUTH_EAP); status = FAILED; @@ -459,7 +466,7 @@ static status_t build_eap_r(private_ike_auth_t *this, message_t *message) */ static status_t build_i(private_ike_auth_t *this, message_t *message) { - policy_t *policy; + peer_cfg_t *config; if (message->get_exchange_type(message) == IKE_SA_INIT) { @@ -471,8 +478,8 @@ static status_t build_i(private_ike_auth_t *this, message_t *message) return FAILED; } - policy = this->ike_sa->get_policy(this->ike_sa); - if (policy->get_auth_method(policy) == AUTH_EAP) + config = this->ike_sa->get_peer_cfg(this->ike_sa); + if (config->get_auth_method(config) == AUTH_EAP) { this->eap_auth = eap_authenticator_create(this->ike_sa); } @@ -488,10 +495,12 @@ static status_t build_i(private_ike_auth_t *this, message_t *message) } /** - * Implementation of task_t.process for initiator + * Implementation of task_t.process for responder */ static status_t process_r(private_ike_auth_t *this, message_t *message) -{ +{ + peer_cfg_t *config; + if (message->get_exchange_type(message) == IKE_SA_INIT) { return collect_other_init_data(this, message); @@ -514,6 +523,17 @@ static status_t process_r(private_ike_auth_t *this, message_t *message) default: break; } + + config = charon->backends->get_peer_cfg(charon->backends, + this->ike_sa->get_my_id(this->ike_sa), + this->ike_sa->get_other_id(this->ike_sa), + this->ike_sa->get_other_ca(this->ike_sa)); + if (config) + { + this->ike_sa->set_peer_cfg(this->ike_sa, config); + config->destroy(config); + } + return NEED_MORE; } @@ -522,7 +542,7 @@ static status_t process_r(private_ike_auth_t *this, message_t *message) */ static status_t build_r(private_ike_auth_t *this, message_t *message) { - policy_t *policy; + peer_cfg_t *config; eap_type_t eap_type; eap_payload_t *eap_payload; status_t status; @@ -532,10 +552,12 @@ static status_t build_r(private_ike_auth_t *this, message_t *message) return collect_my_init_data(this, message); } - policy = this->ike_sa->get_policy(this->ike_sa); - if (policy == NULL) + config = this->ike_sa->get_peer_cfg(this->ike_sa); + if (config == NULL) { - SIG(IKE_UP_FAILED, "no acceptable policy found"); + SIG(IKE_UP_FAILED, "no matching config found for %D...%D", + this->ike_sa->get_my_id(this->ike_sa), + this->ike_sa->get_other_id(this->ike_sa)); message->add_notify(message, TRUE, AUTHENTICATION_FAILED, chunk_empty); return FAILED; } @@ -567,7 +589,7 @@ static status_t build_r(private_ike_auth_t *this, message_t *message) } /* initiate EAP authenitcation */ - eap_type = policy->get_eap_type(policy); + eap_type = config->get_eap_type(config); status = this->eap_auth->initiate(this->eap_auth, eap_type, &eap_payload); message->add_payload(message, (payload_t*)eap_payload); if (status != NEED_MORE) diff --git a/src/charon/sa/tasks/ike_cert.c b/src/charon/sa/tasks/ike_cert.c index 160600742..880ed9c42 100644 --- a/src/charon/sa/tasks/ike_cert.c +++ b/src/charon/sa/tasks/ike_cert.c @@ -84,7 +84,7 @@ static void process_certreqs(private_ike_cert_t *this, message_t *message) encoding = certreq->get_cert_encoding(certreq); if (encoding != CERT_X509_SIGNATURE) { - DBG1(DBG_IKE, "certreq payload %N not supported, ignored", + DBG1(DBG_IKE, "certreq payload %N not supported - ignored", cert_encoding_names, encoding); continue; } @@ -125,7 +125,7 @@ static void process_certs(private_ike_cert_t *this, message_t *message) encoding = cert_payload->get_cert_encoding(cert_payload); if (encoding != CERT_X509_SIGNATURE) { - DBG1(DBG_IKE, "certificate payload %N not supported, ignored", + DBG1(DBG_IKE, "certificate payload %N not supported - ignored", cert_encoding_names, encoding); continue; } @@ -134,31 +134,29 @@ static void process_certs(private_ike_cert_t *this, message_t *message) cert = x509_create_from_chunk(cert_data, 0); if (cert) { - if (charon->credentials->verify(charon->credentials, - cert, &found)) + if (charon->credentials->verify(charon->credentials, cert, &found)) { - DBG2(DBG_IKE, "received end entity certificate is trusted, " - "added to store"); - if (!found) + DBG2(DBG_IKE, "received end entity certificate is trusted - " + "added to store"); + if (found) { - charon->credentials->add_end_certificate( - charon->credentials, cert); + cert->destroy(cert); } else { - cert->destroy(cert); + charon->credentials->add_end_certificate(charon->credentials, cert); } } else { - DBG1(DBG_IKE, "received end entity certificate is not " - "trusted, discarded"); + DBG1(DBG_IKE, "received end entity certificate is not trusted - " + "discarded"); cert->destroy(cert); } } else { - DBG1(DBG_IKE, "parsing of received certificate failed, discarded"); + DBG1(DBG_IKE, "parsing of received certificate failed - discarded"); chunk_free(&cert_data); } } @@ -171,20 +169,20 @@ static void process_certs(private_ike_cert_t *this, message_t *message) */ static void build_certreqs(private_ike_cert_t *this, message_t *message) { - connection_t *connection; - policy_t *policy; + ike_cfg_t *ike_cfg; + peer_cfg_t *peer_cfg; identification_t *ca; certreq_payload_t *certreq; - connection = this->ike_sa->get_connection(this->ike_sa); + ike_cfg = this->ike_sa->get_ike_cfg(this->ike_sa); - if (connection->get_certreq_policy(connection) != CERT_NEVER_SEND) + if (ike_cfg->send_certreq(ike_cfg) != CERT_NEVER_SEND) { - policy = this->ike_sa->get_policy(this->ike_sa); + peer_cfg = this->ike_sa->get_peer_cfg(this->ike_sa); - if (policy) + if (peer_cfg) { - ca = policy->get_other_ca(policy); + ca = peer_cfg->get_other_ca(peer_cfg); if (ca && ca->get_type(ca) != ID_ANY) { @@ -212,17 +210,15 @@ static void build_certreqs(private_ike_cert_t *this, message_t *message) */ static void build_certs(private_ike_cert_t *this, message_t *message) { - policy_t *policy; - connection_t *connection; + peer_cfg_t *peer_cfg; x509_t *cert; cert_payload_t *payload; - policy = this->ike_sa->get_policy(this->ike_sa); - connection = this->ike_sa->get_connection(this->ike_sa); + peer_cfg = this->ike_sa->get_peer_cfg(this->ike_sa); - if (policy && policy->get_auth_method(policy) == AUTH_RSA) + if (peer_cfg && peer_cfg->get_auth_method(peer_cfg) == AUTH_RSA) { - switch (connection->get_cert_policy(connection)) + switch (peer_cfg->get_cert_policy(peer_cfg)) { case CERT_NEVER_SEND: break; @@ -236,7 +232,7 @@ static void build_certs(private_ike_cert_t *this, message_t *message) { /* TODO: respect CA cert request */ cert = charon->credentials->get_certificate(charon->credentials, - policy->get_my_id(policy)); + peer_cfg->get_my_id(peer_cfg)); if (cert) { payload = cert_payload_create_from_x509(cert); diff --git a/src/charon/sa/tasks/ike_config.c b/src/charon/sa/tasks/ike_config.c index ce29b9220..3c73395a5 100644 --- a/src/charon/sa/tasks/ike_config.c +++ b/src/charon/sa/tasks/ike_config.c @@ -48,11 +48,6 @@ struct private_ike_config_t { */ bool initiator; - /** - * associated policy with virtual IP configuration - */ - policy_t *policy; - /** * virtual ip */ @@ -266,7 +261,20 @@ static status_t build_i(private_ike_config_t *this, message_t *message) if (message->get_exchange_type(message) == IKE_AUTH && message->get_payload(message, ID_INITIATOR)) { - this->virtual_ip = this->policy->get_virtual_ip(this->policy, NULL); + peer_cfg_t *config; + host_t *vip; + + /* reuse virtual IP if we already have one */ + vip = this->ike_sa->get_virtual_ip(this->ike_sa, TRUE); + if (vip) + { + this->virtual_ip = vip->clone(vip); + } + else + { + config = this->ike_sa->get_peer_cfg(this->ike_sa); + this->virtual_ip = config->get_my_virtual_ip(config); + } build_payloads(this, message, CFG_REQUEST); } @@ -295,17 +303,18 @@ static status_t build_r(private_ike_config_t *this, message_t *message) if (message->get_exchange_type(message) == IKE_AUTH && message->get_payload(message, EXTENSIBLE_AUTHENTICATION) == NULL) { - this->policy = this->ike_sa->get_policy(this->ike_sa); + peer_cfg_t *config = this->ike_sa->get_peer_cfg(this->ike_sa); - if (this->policy && this->virtual_ip) + if (config && this->virtual_ip) { host_t *ip; DBG1(DBG_IKE, "peer requested virtual IP %H", this->virtual_ip); - ip = this->policy->get_virtual_ip(this->policy, this->virtual_ip); + ip = config->get_other_virtual_ip(config, this->virtual_ip); if (ip == NULL || ip->is_anyaddr(ip)) { DBG1(DBG_IKE, "not assigning a virtual IP to peer"); + DESTROY_IF(ip); return SUCCESS; } DBG1(DBG_IKE, "assigning virtual IP %H to peer", ip); @@ -340,13 +349,20 @@ static status_t process_i(private_ike_config_t *this, message_t *message) !message->get_payload(message, EXTENSIBLE_AUTHENTICATION)) { host_t *ip; + peer_cfg_t *config; DESTROY_IF(this->virtual_ip); this->virtual_ip = NULL; process_payloads(this, message); + + if (this->virtual_ip == NULL) + { /* force a configured virtual IP, even server didn't return one */ + config = this->ike_sa->get_peer_cfg(this->ike_sa); + this->virtual_ip = config->get_my_virtual_ip(config); + } - if (this->virtual_ip) + if (this->virtual_ip && !this->virtual_ip->is_anyaddr(this->virtual_ip)) { this->ike_sa->set_virtual_ip(this->ike_sa, TRUE, this->virtual_ip); @@ -398,7 +414,7 @@ static void destroy(private_ike_config_t *this) /* * Described in header. */ -ike_config_t *ike_config_create(ike_sa_t *ike_sa, policy_t *policy) +ike_config_t *ike_config_create(ike_sa_t *ike_sa, bool initiator) { private_ike_config_t *this = malloc_thing(private_ike_config_t); @@ -406,21 +422,18 @@ ike_config_t *ike_config_create(ike_sa_t *ike_sa, policy_t *policy) this->public.task.migrate = (void(*)(task_t*,ike_sa_t*))migrate; this->public.task.destroy = (void(*)(task_t*))destroy; - if (policy) + if (initiator) { this->public.task.build = (status_t(*)(task_t*,message_t*))build_i; this->public.task.process = (status_t(*)(task_t*,message_t*))process_i; - this->initiator = TRUE; } else { this->public.task.build = (status_t(*)(task_t*,message_t*))build_r; this->public.task.process = (status_t(*)(task_t*,message_t*))process_r; - this->initiator = FALSE; } - + this->initiator = initiator; this->ike_sa = ike_sa; - this->policy = policy; this->virtual_ip = NULL; this->dns = linked_list_create(); diff --git a/src/charon/sa/tasks/ike_config.h b/src/charon/sa/tasks/ike_config.h index 0c9b961b4..a7cfddff0 100644 --- a/src/charon/sa/tasks/ike_config.h +++ b/src/charon/sa/tasks/ike_config.h @@ -28,7 +28,6 @@ typedef struct ike_config_t ike_config_t; #include #include #include -#include /** * @brief Task of type IKE_CONFIG, sets up a virtual IP and other @@ -51,9 +50,9 @@ struct ike_config_t { * @brief Create a new ike_config task. * * @param ike_sa IKE_SA this task works for - * @param policy policy for the initiator, NULL for the responder + * @param initiator TRUE for initiator * @return ike_config task to handle by the task_manager */ -ike_config_t *ike_config_create(ike_sa_t *ike_sa, policy_t *policy); +ike_config_t *ike_config_create(ike_sa_t *ike_sa, bool initiator); #endif /* IKE_CONFIG_H_ */ diff --git a/src/charon/sa/tasks/ike_delete.c b/src/charon/sa/tasks/ike_delete.c index 9c4fdac0e..1a3656ca6 100644 --- a/src/charon/sa/tasks/ike_delete.c +++ b/src/charon/sa/tasks/ike_delete.c @@ -28,7 +28,7 @@ typedef struct private_ike_delete_t private_ike_delete_t; -/** +/**file * Private members of a ike_delete_t task. */ struct private_ike_delete_t { @@ -94,7 +94,6 @@ static status_t process_r(private_ike_delete_t *this, message_t *message) DBG1(DBG_IKE, "deleting IKE_SA on request"); break; case IKE_REKEYING: - DBG1(DBG_IKE, "initiated rekeying, but received delete for IKE_SA"); break; default: break; diff --git a/src/charon/sa/tasks/ike_init.c b/src/charon/sa/tasks/ike_init.c index 0b493666a..f78b5dd66 100644 --- a/src/charon/sa/tasks/ike_init.c +++ b/src/charon/sa/tasks/ike_init.c @@ -57,9 +57,9 @@ struct private_ike_init_t { bool initiator; /** - * Connection established by this IKE_SA + * IKE config to establish */ - connection_t *connection; + ike_cfg_t *config; /** * diffie hellman group to use @@ -69,7 +69,7 @@ struct private_ike_init_t { /** * Diffie hellman object used to generate public DH value. */ - diffie_hellman_t *diffie_hellman; + diffie_hellman_t *dh; /** * nonce chosen by us @@ -117,11 +117,11 @@ static void build_payloads(private_ike_init_t *this, message_t *message) id = this->ike_sa->get_id(this->ike_sa); - this->connection = this->ike_sa->get_connection(this->ike_sa); + this->config = this->ike_sa->get_ike_cfg(this->ike_sa); if (this->initiator) { - proposal_list = this->connection->get_proposals(this->connection); + proposal_list = this->config->get_proposals(this->config); if (this->old_sa) { /* include SPI of new IKE_SA when we are rekeying */ @@ -151,7 +151,7 @@ static void build_payloads(private_ike_init_t *this, message_t *message) nonce_payload->set_nonce(nonce_payload, this->my_nonce); message->add_payload(message, (payload_t*)nonce_payload); - ke_payload = ke_payload_create_from_diffie_hellman(this->diffie_hellman); + ke_payload = ke_payload_create_from_diffie_hellman(this->dh); message->add_payload(message, (payload_t*)ke_payload); } @@ -174,8 +174,8 @@ static void process_payloads(private_ike_init_t *this, message_t *message) linked_list_t *proposal_list; proposal_list = sa_payload->get_proposals(sa_payload); - this->proposal = this->connection->select_proposal( - this->connection, proposal_list); + this->proposal = this->config->select_proposal(this->config, + proposal_list); proposal_list->destroy_offset(proposal_list, offsetof(proposal_t, destroy)); break; @@ -183,34 +183,16 @@ static void process_payloads(private_ike_init_t *this, message_t *message) case KEY_EXCHANGE: { ke_payload_t *ke_payload = (ke_payload_t*)payload; - diffie_hellman_group_t dh_group; - chunk_t key_data; - dh_group = ke_payload->get_dh_group_number(ke_payload); - - if (this->initiator) + this->dh_group = ke_payload->get_dh_group_number(ke_payload); + if (!this->initiator) { - if (dh_group != this->dh_group) - { - DBG1(DBG_IKE, "received a DH group not requested (%N)", - diffie_hellman_group_names, dh_group); - break; - } + this->dh = diffie_hellman_create(this->dh_group); } - else + if (this->dh) { - this->dh_group = dh_group; - if (!this->connection->check_dh_group(this->connection, - dh_group)) - { - break; - } - this->diffie_hellman = diffie_hellman_create(dh_group); - } - if (this->diffie_hellman) - { - key_data = ke_payload->get_key_exchange_data(ke_payload); - this->diffie_hellman->set_other_public_value(this->diffie_hellman, key_data); + this->dh->set_other_public_value(this->dh, + ke_payload->get_key_exchange_data(ke_payload)); } break; } @@ -235,9 +217,9 @@ static status_t build_i(private_ike_init_t *this, message_t *message) randomizer_t *randomizer; status_t status; - this->connection = this->ike_sa->get_connection(this->ike_sa); + this->config = this->ike_sa->get_ike_cfg(this->ike_sa); SIG(IKE_UP_START, "initiating IKE_SA to %H", - this->connection->get_other_host(this->connection)); + this->config->get_other_host(this->config)); this->ike_sa->set_state(this->ike_sa, IKE_CONNECTING); if (this->retry++ >= MAX_RETRIES) @@ -247,11 +229,11 @@ static status_t build_i(private_ike_init_t *this, message_t *message) } /* if the DH group is set via use_dh_group(), we already have a DH object */ - if (!this->diffie_hellman) + if (!this->dh) { - this->dh_group = this->connection->get_dh_group(this->connection); - this->diffie_hellman = diffie_hellman_create(this->dh_group); - if (this->diffie_hellman == NULL) + this->dh_group = this->config->get_dh_group(this->config); + this->dh = diffie_hellman_create(this->dh_group); + if (this->dh == NULL) { SIG(IKE_UP_FAILED, "configured DH group %N not supported", diffie_hellman_group_names, this->dh_group); @@ -291,7 +273,7 @@ static status_t process_r(private_ike_init_t *this, message_t *message) { randomizer_t *randomizer; - this->connection = this->ike_sa->get_connection(this->ike_sa); + this->config = this->ike_sa->get_ike_cfg(this->ike_sa); SIG(IKE_UP_FAILED, "%H is initiating an IKE_SA", message->get_source(message)); this->ike_sa->set_state(this->ike_sa, IKE_CONNECTING); @@ -326,25 +308,29 @@ static status_t build_r(private_ike_init_t *this, message_t *message) return FAILED; } - if (this->diffie_hellman == NULL || - this->diffie_hellman->get_shared_secret(this->diffie_hellman, - &secret) != SUCCESS) + if (this->dh == NULL || + !this->proposal->has_dh_group(this->proposal, this->dh_group) || + this->dh->get_shared_secret(this->dh, &secret) != SUCCESS) { - chunk_t chunk; - u_int16_t dh_enc; - - SIG(IKE_UP_FAILED, "received inacceptable DH group (%N)", - diffie_hellman_group_names, this->dh_group); - this->dh_group = this->connection->get_dh_group(this->connection); - dh_enc = htons(this->dh_group); - chunk.ptr = (u_int8_t*)&dh_enc; - chunk.len = sizeof(dh_enc); - message->add_notify(message, TRUE, INVALID_KE_PAYLOAD, chunk); - DBG1(DBG_IKE, "requesting DH group %N", - diffie_hellman_group_names, this->dh_group); + algorithm_t *algo; + if (this->proposal->get_algorithm(this->proposal, DIFFIE_HELLMAN_GROUP, + &algo)) + { + u_int16_t group = algo->algorithm; + SIG(CHILD_UP_FAILED, "DH group %N inacceptable, requesting %N", + diffie_hellman_group_names, this->dh_group, + diffie_hellman_group_names, group); + this->dh_group = group; + group = htons(group); + message->add_notify(message, FALSE, INVALID_KE_PAYLOAD, + chunk_from_thing(group)); + } + else + { + SIG(IKE_UP_FAILED, "no acceptable proposal found"); + } return FAILED; } - if (this->old_sa) { @@ -405,27 +391,20 @@ static status_t process_i(private_ike_init_t *this, message_t *message) case INVALID_KE_PAYLOAD: { chunk_t data; - diffie_hellman_group_t old_dh_group; + diffie_hellman_group_t bad_group; - old_dh_group = this->dh_group; + bad_group = this->dh_group; data = notify->get_notification_data(notify); this->dh_group = ntohs(*((u_int16_t*)data.ptr)); - - DBG1(DBG_IKE, "peer didn't accept DH group %N, it requested" - " %N", diffie_hellman_group_names, old_dh_group, - diffie_hellman_group_names, this->dh_group); - if (!this->connection->check_dh_group(this->connection, - this->dh_group)) - { - DBG1(DBG_IKE, "requested DH group %N not acceptable, " - "giving up", diffie_hellman_group_names, - this->dh_group); - iterator->destroy(iterator); - return FAILED; + DBG1(DBG_IKE, "peer didn't accept DH group %N, " + "it requested %N", diffie_hellman_group_names, + bad_group, diffie_hellman_group_names, this->dh_group); + + if (this->old_sa == NULL) + { /* reset the IKE_SA if we are not rekeying */ + this->ike_sa->reset(this->ike_sa); } - this->ike_sa->reset(this->ike_sa); - iterator->destroy(iterator); return NEED_MORE; } @@ -470,9 +449,9 @@ static status_t process_i(private_ike_init_t *this, message_t *message) return FAILED; } - if (this->diffie_hellman == NULL || - this->diffie_hellman->get_shared_secret(this->diffie_hellman, - &secret) != SUCCESS) + if (this->dh == NULL || + !this->proposal->has_dh_group(this->proposal, this->dh_group) || + this->dh->get_shared_secret(this->dh, &secret) != SUCCESS) { SIG(IKE_UP_FAILED, "peers DH group selection invalid"); return FAILED; @@ -539,12 +518,12 @@ static chunk_t get_lower_nonce(private_ike_init_t *this) static void migrate(private_ike_init_t *this, ike_sa_t *ike_sa) { DESTROY_IF(this->proposal); - DESTROY_IF(this->diffie_hellman); + DESTROY_IF(this->dh); chunk_free(&this->other_nonce); this->ike_sa = ike_sa; this->proposal = NULL; - this->diffie_hellman = diffie_hellman_create(this->dh_group); + this->dh = diffie_hellman_create(this->dh_group); } /** @@ -553,7 +532,7 @@ static void migrate(private_ike_init_t *this, ike_sa_t *ike_sa) static void destroy(private_ike_init_t *this) { DESTROY_IF(this->proposal); - DESTROY_IF(this->diffie_hellman); + DESTROY_IF(this->dh); chunk_free(&this->my_nonce); chunk_free(&this->other_nonce); chunk_free(&this->cookie); @@ -585,12 +564,12 @@ ike_init_t *ike_init_create(ike_sa_t *ike_sa, bool initiator, ike_sa_t *old_sa) this->ike_sa = ike_sa; this->initiator = initiator; this->dh_group = MODP_NONE; - this->diffie_hellman = NULL; + this->dh = NULL; this->my_nonce = chunk_empty; this->other_nonce = chunk_empty; this->cookie = chunk_empty; this->proposal = NULL; - this->connection = NULL; + this->config = NULL; this->old_sa = old_sa; this->retry = 0; diff --git a/src/charon/sa/tasks/ike_rekey.c b/src/charon/sa/tasks/ike_rekey.c index a33e7ee34..d54fc3524 100644 --- a/src/charon/sa/tasks/ike_rekey.c +++ b/src/charon/sa/tasks/ike_rekey.c @@ -26,8 +26,8 @@ #include #include #include -#include -#include +#include +#include typedef struct private_ike_rekey_t private_ike_rekey_t; @@ -73,21 +73,20 @@ struct private_ike_rekey_t { */ static status_t build_i(private_ike_rekey_t *this, message_t *message) { - connection_t *connection; - policy_t *policy; + peer_cfg_t *peer_cfg; - this->new_sa = charon->ike_sa_manager->checkout_new(charon->ike_sa_manager, - TRUE); - - connection = this->ike_sa->get_connection(this->ike_sa); - policy = this->ike_sa->get_policy(this->ike_sa); - this->new_sa->set_connection(this->new_sa, connection); - this->new_sa->set_policy(this->new_sa, policy); - - this->ike_init = ike_init_create(this->new_sa, TRUE, this->ike_sa); + /* create new SA only on first try */ + if (this->new_sa == NULL) + { + this->new_sa = charon->ike_sa_manager->checkout_new(charon->ike_sa_manager, + TRUE); + + peer_cfg = this->ike_sa->get_peer_cfg(this->ike_sa); + this->new_sa->set_peer_cfg(this->new_sa, peer_cfg); + this->ike_init = ike_init_create(this->new_sa, TRUE, this->ike_sa); + this->ike_sa->set_state(this->ike_sa, IKE_REKEYING); + } this->ike_init->task.build(&this->ike_init->task, message); - - this->ike_sa->set_state(this->ike_sa, IKE_REKEYING); return NEED_MORE; } @@ -97,8 +96,7 @@ static status_t build_i(private_ike_rekey_t *this, message_t *message) */ static status_t process_r(private_ike_rekey_t *this, message_t *message) { - connection_t *connection; - policy_t *policy; + peer_cfg_t *peer_cfg; iterator_t *iterator; child_sa_t *child_sa; @@ -129,11 +127,8 @@ static status_t process_r(private_ike_rekey_t *this, message_t *message) this->new_sa = charon->ike_sa_manager->checkout_new(charon->ike_sa_manager, FALSE); - connection = this->ike_sa->get_connection(this->ike_sa); - policy = this->ike_sa->get_policy(this->ike_sa); - this->new_sa->set_connection(this->new_sa, connection); - this->new_sa->set_policy(this->new_sa, policy); - + peer_cfg = this->ike_sa->get_peer_cfg(this->ike_sa); + this->new_sa->set_peer_cfg(this->new_sa, peer_cfg); this->ike_init = ike_init_create(this->new_sa, FALSE, this->ike_sa); this->ike_init->task.process(&this->ike_init->task, message); @@ -171,23 +166,29 @@ static status_t process_i(private_ike_rekey_t *this, message_t *message) job_t *job; ike_sa_id_t *to_delete; - if (this->ike_init->task.process(&this->ike_init->task, message) == FAILED) + switch (this->ike_init->task.process(&this->ike_init->task, message)) { - /* rekeying failed, fallback to old SA */ - if (!(this->collision && - this->collision->get_type(this->collision) == IKE_DELETE)) - { - job_t *job; - u_int32_t retry = charon->configuration->get_retry_interval( - charon->configuration); - job = (job_t*)rekey_ike_sa_job_create( - this->ike_sa->get_id(this->ike_sa), FALSE); - DBG1(DBG_IKE, "IKE_SA rekeying failed, " - "trying again in %d seconds", retry); - this->ike_sa->set_state(this->ike_sa, IKE_ESTABLISHED); - charon->event_queue->add_relative(charon->event_queue, job, retry * 1000); - } - return SUCCESS; + case FAILED: + /* rekeying failed, fallback to old SA */ + if (!(this->collision && + this->collision->get_type(this->collision) == IKE_DELETE)) + { + job_t *job; + u_int32_t retry = RETRY_INTERVAL - (random() % RETRY_JITTER); + job = (job_t*)rekey_ike_sa_job_create( + this->ike_sa->get_id(this->ike_sa), FALSE); + DBG1(DBG_IKE, "IKE_SA rekeying failed, " + "trying again in %d seconds", retry); + this->ike_sa->set_state(this->ike_sa, IKE_ESTABLISHED); + charon->event_queue->add_relative(charon->event_queue, job, retry * 1000); + } + return SUCCESS; + case NEED_MORE: + /* bad dh group, try again */ + this->ike_init->task.migrate(&this->ike_init->task, this->new_sa); + return NEED_MORE; + default: + break; } this->new_sa->set_state(this->new_sa, IKE_ESTABLISHED); -- cgit v1.2.3