summaryrefslogtreecommitdiff
path: root/src/charon/sa/tasks/child_create.c
diff options
context:
space:
mode:
Diffstat (limited to 'src/charon/sa/tasks/child_create.c')
-rw-r--r--src/charon/sa/tasks/child_create.c187
1 files changed, 137 insertions, 50 deletions
diff --git a/src/charon/sa/tasks/child_create.c b/src/charon/sa/tasks/child_create.c
index 4638da03e..bddca621b 100644
--- a/src/charon/sa/tasks/child_create.c
+++ b/src/charon/sa/tasks/child_create.c
@@ -14,7 +14,7 @@
* or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License
* for more details.
*
- * $Id: child_create.c 3920 2008-05-08 16:19:11Z tobias $
+ * $Id: child_create.c 4358 2008-09-25 13:56:23Z tobias $
*/
#include "child_create.h"
@@ -26,6 +26,7 @@
#include <encoding/payloads/ts_payload.h>
#include <encoding/payloads/nonce_payload.h>
#include <encoding/payloads/notify_payload.h>
+#include <processing/jobs/delete_ike_sa_job.h>
typedef struct private_child_create_t private_child_create_t;
@@ -98,7 +99,7 @@ struct private_child_create_t {
/**
* mode the new CHILD_SA uses (transport/tunnel/beet)
*/
- mode_t mode;
+ ipsec_mode_t mode;
/**
* IPComp transform to use
@@ -198,12 +199,12 @@ static status_t select_and_install(private_child_create_t *this, bool no_dh)
if (this->proposals == NULL)
{
- SIG(CHILD_UP_FAILED, "SA payload missing in message");
+ SIG_CHD(UP_FAILED, this->child_sa, "SA payload missing in message");
return FAILED;
}
if (this->tsi == NULL || this->tsr == NULL)
{
- SIG(CHILD_UP_FAILED, "TS payloads missing in message");
+ SIG_CHD(UP_FAILED, this->child_sa, "TS payloads missing in message");
return NOT_FOUND;
}
@@ -231,7 +232,7 @@ static status_t select_and_install(private_child_create_t *this, bool no_dh)
no_dh);
if (this->proposal == NULL)
{
- SIG(CHILD_UP_FAILED, "no acceptable proposal found");
+ SIG_CHD(UP_FAILED, this->child_sa, "no acceptable proposal found");
return FAILED;
}
@@ -242,15 +243,15 @@ static status_t select_and_install(private_child_create_t *this, bool no_dh)
if (this->proposal->get_algorithm(this->proposal, DIFFIE_HELLMAN_GROUP,
&group, NULL))
{
- SIG(CHILD_UP_FAILED, "DH group %N inacceptable, requesting %N",
- diffie_hellman_group_names, this->dh_group,
- diffie_hellman_group_names, group);
+ SIG_CHD(UP_FAILED, this->child_sa, "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");
+ SIG_CHD(UP_FAILED, this->child_sa, "no acceptable proposal found");
return FAILED;
}
}
@@ -278,7 +279,7 @@ static status_t select_and_install(private_child_create_t *this, bool no_dh)
{
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");
+ SIG_CHD(UP_FAILED, this->child_sa, "no acceptable traffic selectors found");
return NOT_FOUND;
}
@@ -330,7 +331,7 @@ static status_t select_and_install(private_child_create_t *this, bool no_dh)
{
if (this->dh->get_shared_secret(this->dh, &secret) != SUCCESS)
{
- SIG(CHILD_UP_FAILED, "DH exchange incomplete");
+ SIG_CHD(UP_FAILED, this->child_sa, "DH exchange incomplete");
return FAILED;
}
DBG3(DBG_IKE, "DH secret %B", &secret);
@@ -340,7 +341,6 @@ static status_t select_and_install(private_child_create_t *this, bool no_dh)
{
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->ipcomp != IPCOMP_NONE)
{
@@ -348,6 +348,16 @@ static status_t select_and_install(private_child_create_t *this, bool no_dh)
this->other_cpi);
}
+ status = this->child_sa->add_policies(this->child_sa, my_ts, other_ts,
+ this->mode, this->proposal->get_protocol(this->proposal));
+ if (status != SUCCESS)
+ {
+ SIG_CHD(UP_FAILED, this->child_sa,
+ "unable to install IPsec policies (SPD) in kernel");
+ return NOT_FOUND;
+ }
+
+ prf_plus = prf_plus_create(this->ike_sa->get_child_prf(this->ike_sa), seed);
if (this->initiator)
{
status = this->child_sa->update(this->child_sa, this->proposal,
@@ -362,18 +372,10 @@ static status_t select_and_install(private_child_create_t *this, bool no_dh)
if (status != SUCCESS)
{
- SIG(CHILD_UP_FAILED, "unable to install IPsec SA (SAD) in kernel");
+ SIG_CHD(UP_FAILED, this->child_sa,
+ "unable to install IPsec SA (SAD) in kernel");
return FAILED;
}
-
- status = this->child_sa->add_policies(this->child_sa, my_ts, other_ts,
- this->mode);
-
- if (status != SUCCESS)
- {
- SIG(CHILD_UP_FAILED, "unable to install IPsec policies (SPD) in kernel");
- return NOT_FOUND;
- }
/* add to IKE_SA, and remove from task */
this->child_sa->set_state(this->child_sa, CHILD_INSTALLED);
this->ike_sa->add_child_sa(this->ike_sa, this->child_sa);
@@ -440,29 +442,30 @@ static void build_payloads(private_child_create_t *this, message_t *message)
/**
* Adds an IPCOMP_SUPPORTED notify to the message, if possible
*/
-static void build_ipcomp_supported_notify(private_child_create_t *this, message_t *message)
+static void build_ipcomp_supported_notify(private_child_create_t *this,
+ message_t *message)
{
+ u_int16_t cpi;
+ u_int8_t tid;
+
if (this->ike_sa->has_condition(this->ike_sa, COND_NAT_ANY))
{
- DBG1(DBG_IKE, "IPComp is not supported if either peer is natted, IPComp is disabled");
+ DBG1(DBG_IKE, "IPComp is not supported if either peer is natted, "
+ "IPComp disabled");
this->ipcomp = IPCOMP_NONE;
return;
}
- u_int16_t cpi = this->child_sa->get_my_cpi(this->child_sa);
+ cpi = this->child_sa->allocate_cpi(this->child_sa);
+ tid = this->ipcomp;
if (cpi)
{
- chunk_t cpi_chunk, tid_chunk, data;
- u_int8_t tid = this->ipcomp;
- cpi_chunk = chunk_from_thing(cpi);
- tid_chunk = chunk_from_thing(tid);
- data = chunk_cat("cc", cpi_chunk, tid_chunk);
- message->add_notify(message, FALSE, IPCOMP_SUPPORTED, data);
- chunk_free(&data);
+ message->add_notify(message, FALSE, IPCOMP_SUPPORTED,
+ chunk_cata("cc", chunk_from_thing(cpi), chunk_from_thing(tid)));
}
else
{
- DBG1(DBG_IKE, "unable to allocate a CPI from kernel, IPComp is disabled");
+ DBG1(DBG_IKE, "unable to allocate a CPI from kernel, IPComp disabled");
this->ipcomp = IPCOMP_NONE;
}
}
@@ -587,7 +590,16 @@ static status_t build_i(private_child_create_t *this, message_t *message)
break;
}
- SIG(CHILD_UP_START, "establishing CHILD_SA");
+ if (this->reqid)
+ {
+ SIG_CHD(UP_START, NULL, "establishing CHILD_SA %s{%d}",
+ this->config->get_name(this->config), this->reqid);
+ }
+ else
+ {
+ SIG_CHD(UP_START, NULL, "establishing CHILD_SA %s",
+ this->config->get_name(this->config));
+ }
/* reuse virtual IP if we already have one */
me = this->ike_sa->get_virtual_ip(this->ike_sa, TRUE);
@@ -638,7 +650,8 @@ static status_t build_i(private_child_create_t *this, message_t *message)
if (this->child_sa->alloc(this->child_sa, this->proposals) != SUCCESS)
{
- SIG(CHILD_UP_FAILED, "unable to allocate SPIs from kernel");
+ SIG_CHD(UP_FAILED, this->child_sa,
+ "unable to allocate SPIs from kernel");
return FAILED;
}
@@ -720,10 +733,31 @@ static status_t process_r(private_child_create_t *this, message_t *message)
}
/**
+ * handle CHILD_SA setup failure
+ */
+static void handle_child_sa_failure(private_child_create_t *this,
+ message_t *message)
+{
+ if (message->get_exchange_type(message) == IKE_AUTH &&
+ lib->settings->get_bool(lib->settings,
+ "charon.close_ike_on_child_failure", FALSE))
+ {
+ /* we delay the delete for 100ms, as the IKE_AUTH response must arrive
+ * first */
+ DBG1(DBG_IKE, "closing IKE_SA due CHILD_SA setup failure");
+ charon->scheduler->schedule_job(charon->scheduler, (job_t*)
+ delete_ike_sa_job_create(this->ike_sa->get_id(this->ike_sa), TRUE),
+ 100);
+ }
+}
+
+/**
* Implementation of task_t.build for responder
*/
static status_t build_r(private_child_create_t *this, message_t *message)
{
+ payload_t *payload;
+ iterator_t *iterator;
bool no_dh = TRUE;
switch (message->get_exchange_type(message))
@@ -733,7 +767,8 @@ static status_t build_r(private_child_create_t *this, message_t *message)
case CREATE_CHILD_SA:
if (generate_nonce(&this->my_nonce) != SUCCESS)
{
- message->add_notify(message, FALSE, NO_PROPOSAL_CHOSEN, chunk_empty);
+ message->add_notify(message, FALSE, NO_PROPOSAL_CHOSEN,
+ chunk_empty);
return SUCCESS;
}
no_dh = FALSE;
@@ -750,19 +785,47 @@ static status_t build_r(private_child_create_t *this, message_t *message)
if (this->ike_sa->get_state(this->ike_sa) == IKE_REKEYING)
{
- SIG(CHILD_UP_FAILED, "unable to create CHILD_SA while rekeying IKE_SA");
+ SIG_CHD(UP_FAILED, NULL,
+ "unable to create CHILD_SA while rekeying IKE_SA");
message->add_notify(message, TRUE, NO_ADDITIONAL_SAS, chunk_empty);
return SUCCESS;
}
if (this->config == NULL)
{
- SIG(CHILD_UP_FAILED, "traffic selectors %#R=== %#R inacceptable",
+ SIG_CHD(UP_FAILED, NULL, "traffic selectors %#R=== %#R inacceptable",
this->tsr, this->tsi);
message->add_notify(message, FALSE, TS_UNACCEPTABLE, chunk_empty);
+ handle_child_sa_failure(this, message);
return SUCCESS;
}
+ /* check if ike_config_t included non-critical error notifies */
+ iterator = message->get_payload_iterator(message);
+ while (iterator->iterate(iterator, (void**)&payload))
+ {
+ if (payload->get_type(payload) == NOTIFY)
+ {
+ notify_payload_t *notify = (notify_payload_t*)payload;
+
+ switch (notify->get_notify_type(notify))
+ {
+ case INTERNAL_ADDRESS_FAILURE:
+ case FAILED_CP_REQUIRED:
+ {
+ SIG_CHD(UP_FAILED, NULL, "configuration payload negotation "
+ "failed, no CHILD_SA built");
+ iterator->destroy(iterator);
+ handle_child_sa_failure(this, message);
+ return SUCCESS;
+ }
+ default:
+ break;
+ }
+ }
+ }
+ iterator->destroy(iterator);
+
this->child_sa = child_sa_create(
this->ike_sa->get_my_host(this->ike_sa),
this->ike_sa->get_other_host(this->ike_sa),
@@ -770,14 +833,16 @@ static status_t build_r(private_child_create_t *this, message_t *message)
this->ike_sa->get_other_id(this->ike_sa), this->config, this->reqid,
this->ike_sa->has_condition(this->ike_sa, COND_NAT_ANY));
- if (this->config->use_ipcomp(this->config) && this->ipcomp_received != IPCOMP_NONE)
+ if (this->config->use_ipcomp(this->config) &&
+ this->ipcomp_received != IPCOMP_NONE)
{
this->ipcomp = this->ipcomp_received;
build_ipcomp_supported_notify(this, message);
}
else if (this->ipcomp_received != IPCOMP_NONE)
{
- DBG1(DBG_IKE, "received IPCOMP_SUPPORTED notify but IPComp is disabled, ignoring");
+ DBG1(DBG_IKE, "received %N notify but IPComp is disabled, ignoring",
+ notify_type_names, IPCOMP_SUPPORTED);
}
switch (select_and_install(this, no_dh))
@@ -786,24 +851,33 @@ static status_t build_r(private_child_create_t *this, message_t *message)
break;
case NOT_FOUND:
message->add_notify(message, FALSE, TS_UNACCEPTABLE, chunk_empty);
+ handle_child_sa_failure(this, message);
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));
+ handle_child_sa_failure(this, message);
return SUCCESS;
}
case FAILED:
default:
message->add_notify(message, FALSE, NO_PROPOSAL_CHOSEN, chunk_empty);
+ handle_child_sa_failure(this, message);
return SUCCESS;
}
build_payloads(this, message);
- SIG(CHILD_UP_SUCCESS, "CHILD_SA '%s' established successfully",
- this->child_sa->get_name(this->child_sa));
+ SIG_CHD(UP_SUCCESS, this->child_sa, "CHILD_SA %s{%d} established "
+ "with SPIs %.8x_i %.8x_o and TS %#R=== %#R",
+ this->child_sa->get_name(this->child_sa),
+ this->child_sa->get_reqid(this->child_sa),
+ ntohl(this->child_sa->get_spi(this->child_sa, TRUE)),
+ ntohl(this->child_sa->get_spi(this->child_sa, FALSE)),
+ this->child_sa->get_traffic_selectors(this->child_sa, TRUE),
+ this->child_sa->get_traffic_selectors(this->child_sa, FALSE));
return SUCCESS;
}
@@ -855,9 +929,10 @@ static status_t process_i(private_child_create_t *this, message_t *message)
case TS_UNACCEPTABLE:
case INVALID_SELECTORS:
{
- SIG(CHILD_UP_FAILED, "received %N notify, no CHILD_SA built",
- notify_type_names, type);
+ SIG_CHD(UP_FAILED, this->child_sa, "received %N notify, "
+ "no CHILD_SA built", notify_type_names, type);
iterator->destroy(iterator);
+ handle_child_sa_failure(this, message);
/* an error in CHILD_SA creation is not critical */
return SUCCESS;
}
@@ -888,8 +963,9 @@ static status_t process_i(private_child_create_t *this, message_t *message)
if (this->ipcomp == IPCOMP_NONE && this->ipcomp_received != IPCOMP_NONE)
{
- SIG(CHILD_UP_FAILED, "received an IPCOMP_SUPPORTED notify but we did not "
- "send one previously, no CHILD_SA built");
+ SIG_CHD(UP_FAILED, this->child_sa, "received an IPCOMP_SUPPORTED notify"
+ " but we did not send one previously, no CHILD_SA built");
+ handle_child_sa_failure(this, message);
return SUCCESS;
}
else if (this->ipcomp != IPCOMP_NONE && this->ipcomp_received == IPCOMP_NONE)
@@ -900,15 +976,26 @@ static status_t process_i(private_child_create_t *this, message_t *message)
}
else if (this->ipcomp != IPCOMP_NONE && this->ipcomp != this->ipcomp_received)
{
- SIG(CHILD_UP_FAILED, "received an IPCOMP_SUPPORTED notify for a transform "
- "we did not propose, no CHILD_SA built");
+ SIG_CHD(UP_FAILED, this->child_sa, "received an IPCOMP_SUPPORTED notify"
+ " for a transform we did not propose, no CHILD_SA built");
+ handle_child_sa_failure(this, message);
return SUCCESS;
}
if (select_and_install(this, no_dh) == SUCCESS)
{
- SIG(CHILD_UP_SUCCESS, "CHILD_SA '%s' established successfully",
- this->child_sa->get_name(this->child_sa));
+ SIG_CHD(UP_SUCCESS, this->child_sa, "CHILD_SA %s{%d} established "
+ "with SPIs %.8x_i %.8x_o and TS %#R=== %#R",
+ this->child_sa->get_name(this->child_sa),
+ this->child_sa->get_reqid(this->child_sa),
+ ntohl(this->child_sa->get_spi(this->child_sa, TRUE)),
+ ntohl(this->child_sa->get_spi(this->child_sa, FALSE)),
+ this->child_sa->get_traffic_selectors(this->child_sa, TRUE),
+ this->child_sa->get_traffic_selectors(this->child_sa, FALSE));
+ }
+ else
+ {
+ handle_child_sa_failure(this, message);
}
return SUCCESS;
}