summaryrefslogtreecommitdiff
path: root/src/libcharon/sa/ikev2/tasks
diff options
context:
space:
mode:
Diffstat (limited to 'src/libcharon/sa/ikev2/tasks')
-rw-r--r--src/libcharon/sa/ikev2/tasks/child_create.c301
-rw-r--r--src/libcharon/sa/ikev2/tasks/child_delete.c32
-rw-r--r--src/libcharon/sa/ikev2/tasks/child_rekey.c17
-rw-r--r--src/libcharon/sa/ikev2/tasks/ike_auth.c30
-rw-r--r--src/libcharon/sa/ikev2/tasks/ike_cert_pre.h2
-rw-r--r--src/libcharon/sa/ikev2/tasks/ike_delete.c8
-rw-r--r--src/libcharon/sa/ikev2/tasks/ike_init.c20
-rw-r--r--src/libcharon/sa/ikev2/tasks/ike_natd.c19
8 files changed, 338 insertions, 91 deletions
diff --git a/src/libcharon/sa/ikev2/tasks/child_create.c b/src/libcharon/sa/ikev2/tasks/child_create.c
index 32c0e8c4a..8ae36af84 100644
--- a/src/libcharon/sa/ikev2/tasks/child_create.c
+++ b/src/libcharon/sa/ikev2/tasks/child_create.c
@@ -27,6 +27,7 @@
#include <encoding/payloads/ts_payload.h>
#include <encoding/payloads/nonce_payload.h>
#include <encoding/payloads/notify_payload.h>
+#include <encoding/payloads/delete_payload.h>
#include <processing/jobs/delete_ike_sa_job.h>
#include <processing/jobs/inactivity_job.h>
@@ -342,6 +343,79 @@ static linked_list_t *get_dynamic_hosts(ike_sa_t *ike_sa, bool local)
}
/**
+ * Substitude any host address with NATed address in traffic selector
+ */
+static linked_list_t* get_transport_nat_ts(private_child_create_t *this,
+ bool local, linked_list_t *in)
+{
+ enumerator_t *enumerator;
+ linked_list_t *out;
+ traffic_selector_t *ts;
+ host_t *ike, *first = NULL;
+ u_int8_t mask;
+
+ if (local)
+ {
+ ike = this->ike_sa->get_my_host(this->ike_sa);
+ }
+ else
+ {
+ ike = this->ike_sa->get_other_host(this->ike_sa);
+ }
+
+ out = linked_list_create();
+
+ enumerator = in->create_enumerator(in);
+ while (enumerator->enumerate(enumerator, &ts))
+ {
+ /* require that all selectors match the first "host" selector */
+ if (ts->is_host(ts, first))
+ {
+ if (!first)
+ {
+ ts->to_subnet(ts, &first, &mask);
+ }
+ ts = ts->clone(ts);
+ ts->set_address(ts, ike);
+ out->insert_last(out, ts);
+ }
+ }
+ enumerator->destroy(enumerator);
+ DESTROY_IF(first);
+
+ return out;
+}
+
+/**
+ * Narrow received traffic selectors with configuration
+ */
+static linked_list_t* narrow_ts(private_child_create_t *this, bool local,
+ linked_list_t *in)
+{
+ linked_list_t *hosts, *nat, *ts;
+ ike_condition_t cond;
+
+ cond = local ? COND_NAT_HERE : COND_NAT_THERE;
+ hosts = get_dynamic_hosts(this->ike_sa, local);
+
+ if (this->mode == MODE_TRANSPORT &&
+ this->ike_sa->has_condition(this->ike_sa, cond))
+ {
+ nat = get_transport_nat_ts(this, local, in);
+ ts = this->config->get_traffic_selectors(this->config, local, nat, hosts);
+ nat->destroy_offset(nat, offsetof(traffic_selector_t, destroy));
+ }
+ else
+ {
+ ts = this->config->get_traffic_selectors(this->config, local, in, hosts);
+ }
+
+ hosts->destroy(hosts);
+
+ return ts;
+}
+
+/**
* Install a CHILD_SA for usage, return value:
* - FAILED: no acceptable proposal
* - INVALID_ARG: diffie hellman group inacceptable
@@ -354,7 +428,7 @@ static status_t select_and_install(private_child_create_t *this,
chunk_t nonce_i, nonce_r;
chunk_t encr_i = chunk_empty, encr_r = chunk_empty;
chunk_t integ_i = chunk_empty, integ_r = chunk_empty;
- linked_list_t *my_ts, *other_ts, *list;
+ linked_list_t *my_ts, *other_ts;
host_t *me, *other;
bool private;
@@ -415,24 +489,16 @@ static status_t select_and_install(private_child_create_t *this,
{
nonce_i = this->my_nonce;
nonce_r = this->other_nonce;
- my_ts = this->tsi;
- other_ts = this->tsr;
+ my_ts = narrow_ts(this, TRUE, this->tsi);
+ other_ts = narrow_ts(this, FALSE, this->tsr);
}
else
{
nonce_r = this->my_nonce;
nonce_i = this->other_nonce;
- my_ts = this->tsr;
- other_ts = this->tsi;
+ my_ts = narrow_ts(this, TRUE, this->tsr);
+ other_ts = narrow_ts(this, FALSE, this->tsi);
}
- list = get_dynamic_hosts(this->ike_sa, TRUE);
- my_ts = this->config->get_traffic_selectors(this->config,
- TRUE, my_ts, list);
- list->destroy(list);
- list = get_dynamic_hosts(this->ike_sa, FALSE);
- other_ts = this->config->get_traffic_selectors(this->config,
- FALSE, other_ts, list);
- list->destroy(list);
if (this->initiator)
{
@@ -489,10 +555,9 @@ static status_t select_and_install(private_child_create_t *this,
this->mode = MODE_TUNNEL;
DBG1(DBG_IKE, "not using transport mode, not host-to-host");
}
- else if (this->ike_sa->has_condition(this->ike_sa, COND_NAT_ANY))
+ if (this->config->get_mode(this->config) != MODE_TRANSPORT)
{
this->mode = MODE_TUNNEL;
- DBG1(DBG_IKE, "not using transport mode, connection NATed");
}
break;
case MODE_BEET:
@@ -502,6 +567,10 @@ static status_t select_and_install(private_child_create_t *this,
this->mode = MODE_TUNNEL;
DBG1(DBG_IKE, "not using BEET mode, not host-to-host");
}
+ if (this->config->get_mode(this->config) != MODE_BEET)
+ {
+ this->mode = MODE_TUNNEL;
+ }
break;
default:
break;
@@ -525,20 +594,20 @@ static status_t select_and_install(private_child_create_t *this,
{
if (this->initiator)
{
- status_i = this->child_sa->install(this->child_sa,
- encr_r, integ_r, this->my_spi, this->my_cpi,
+ status_i = this->child_sa->install(this->child_sa, encr_r, integ_r,
+ this->my_spi, this->my_cpi, this->initiator,
TRUE, this->tfcv3, my_ts, other_ts);
- status_o = this->child_sa->install(this->child_sa,
- encr_i, integ_i, this->other_spi, this->other_cpi,
+ status_o = this->child_sa->install(this->child_sa, encr_i, integ_i,
+ this->other_spi, this->other_cpi, this->initiator,
FALSE, this->tfcv3, my_ts, other_ts);
}
else
{
- status_i = this->child_sa->install(this->child_sa,
- encr_i, integ_i, this->my_spi, this->my_cpi,
+ status_i = this->child_sa->install(this->child_sa, encr_i, integ_i,
+ this->my_spi, this->my_cpi, this->initiator,
TRUE, this->tfcv3, my_ts, other_ts);
- status_o = this->child_sa->install(this->child_sa,
- encr_r, integ_r, this->other_spi, this->other_cpi,
+ status_o = this->child_sa->install(this->child_sa, encr_r, integ_r,
+ this->other_spi, this->other_cpi, this->initiator,
FALSE, this->tfcv3, my_ts, other_ts);
}
}
@@ -604,6 +673,22 @@ static status_t select_and_install(private_child_create_t *this,
{ /* a rekeyed SA uses the same reqid, no need for a new job */
schedule_inactivity_timeout(this);
}
+
+ my_ts = linked_list_create_from_enumerator(
+ this->child_sa->create_ts_enumerator(this->child_sa, TRUE));
+ other_ts = linked_list_create_from_enumerator(
+ this->child_sa->create_ts_enumerator(this->child_sa, FALSE));
+
+ DBG0(DBG_IKE, "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)), my_ts, other_ts);
+
+ my_ts->destroy(my_ts);
+ other_ts->destroy(other_ts);
+
return SUCCESS;
}
@@ -678,13 +763,6 @@ static void build_payloads(private_child_create_t *this, message_t *message)
static void add_ipcomp_notify(private_child_create_t *this,
message_t *message, u_int8_t ipcomp)
{
- 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 disabled");
- return;
- }
-
this->my_cpi = this->child_sa->alloc_cpi(this->child_sa);
if (this->my_cpi)
{
@@ -901,12 +979,6 @@ METHOD(task_t, build_i, status_t,
this->proposals = this->config->get_proposals(this->config,
this->dh_group == MODP_NONE);
this->mode = this->config->get_mode(this->config);
- if (this->mode == MODE_TRANSPORT &&
- this->ike_sa->has_condition(this->ike_sa, COND_NAT_ANY))
- {
- this->mode = MODE_TUNNEL;
- DBG1(DBG_IKE, "not using transport mode, connection NATed");
- }
this->child_sa = child_sa_create(this->ike_sa->get_my_host(this->ike_sa),
this->ike_sa->get_other_host(this->ike_sa), this->config, this->reqid,
@@ -1002,10 +1074,77 @@ static void handle_child_sa_failure(private_child_create_t *this,
}
}
+/**
+ * Substitute transport mode NAT selectors, if applicable
+ */
+static linked_list_t* get_ts_if_nat_transport(private_child_create_t *this,
+ bool local, linked_list_t *in)
+{
+ linked_list_t *out = NULL;
+ ike_condition_t cond;
+
+ if (this->mode == MODE_TRANSPORT)
+ {
+ cond = local ? COND_NAT_HERE : COND_NAT_THERE;
+ if (this->ike_sa->has_condition(this->ike_sa, cond))
+ {
+ out = get_transport_nat_ts(this, local, in);
+ if (out->get_count(out) == 0)
+ {
+ out->destroy(out);
+ out = NULL;
+ }
+ }
+ }
+ return out;
+}
+
+/**
+ * Select a matching CHILD config as responder
+ */
+static child_cfg_t* select_child_cfg(private_child_create_t *this)
+{
+ peer_cfg_t *peer_cfg;
+ child_cfg_t *child_cfg = NULL;;
+
+ peer_cfg = this->ike_sa->get_peer_cfg(this->ike_sa);
+ if (peer_cfg && this->tsi && this->tsr)
+ {
+ linked_list_t *listr, *listi, *tsr, *tsi;
+
+ tsr = get_ts_if_nat_transport(this, TRUE, this->tsr);
+ tsi = get_ts_if_nat_transport(this, FALSE, this->tsi);
+
+ listr = get_dynamic_hosts(this->ike_sa, TRUE);
+ listi = get_dynamic_hosts(this->ike_sa, FALSE);
+ child_cfg = peer_cfg->select_child_cfg(peer_cfg,
+ tsr ?: this->tsr, tsi ?: this->tsi,
+ listr, listi);
+ if ((tsi || tsr) && child_cfg &&
+ child_cfg->get_mode(child_cfg) != MODE_TRANSPORT)
+ {
+ /* found a CHILD config, but it doesn't use transport mode */
+ child_cfg->destroy(child_cfg);
+ child_cfg = NULL;
+ }
+ if (!child_cfg && (tsi || tsr))
+ {
+ /* no match for the substituted NAT selectors, try it without */
+ child_cfg = peer_cfg->select_child_cfg(peer_cfg,
+ this->tsr, this->tsi, listr, listi);
+ }
+ listr->destroy(listr);
+ listi->destroy(listi);
+ DESTROY_OFFSET_IF(tsi, offsetof(traffic_selector_t, destroy));
+ DESTROY_OFFSET_IF(tsr, offsetof(traffic_selector_t, destroy));
+ }
+
+ return child_cfg;
+}
+
METHOD(task_t, build_r, status_t,
private_child_create_t *this, message_t *message)
{
- peer_cfg_t *peer_cfg;
payload_t *payload;
enumerator_t *enumerator;
bool no_dh = TRUE, ike_auth = FALSE;
@@ -1040,19 +1179,10 @@ METHOD(task_t, build_r, status_t,
return SUCCESS;
}
- peer_cfg = this->ike_sa->get_peer_cfg(this->ike_sa);
- if (!this->config && peer_cfg && this->tsi && this->tsr)
+ if (this->config == NULL)
{
- linked_list_t *listr, *listi;
-
- listr = get_dynamic_hosts(this->ike_sa, TRUE);
- listi = get_dynamic_hosts(this->ike_sa, FALSE);
- this->config = peer_cfg->select_child_cfg(peer_cfg,
- this->tsr, this->tsi, listr, listi);
- listr->destroy(listr);
- listi->destroy(listi);
+ this->config = select_child_cfg(this);
}
-
if (this->config == NULL)
{
DBG1(DBG_IKE, "traffic selectors %#R=== %#R inacceptable",
@@ -1131,15 +1261,6 @@ METHOD(task_t, build_r, status_t,
build_payloads(this, message);
- DBG0(DBG_IKE, "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));
-
if (!this->rekey)
{ /* invoke the child_up() hook if we are not rekeying */
charon->bus->child_updown(charon->bus, this->child_sa, TRUE);
@@ -1147,6 +1268,57 @@ METHOD(task_t, build_r, status_t,
return SUCCESS;
}
+/**
+ * Raise alerts for received notify errors
+ */
+static void raise_alerts(private_child_create_t *this, notify_type_t type)
+{
+ linked_list_t *list;
+
+ switch (type)
+ {
+ case NO_PROPOSAL_CHOSEN:
+ list = this->config->get_proposals(this->config, FALSE);
+ charon->bus->alert(charon->bus, ALERT_PROPOSAL_MISMATCH_CHILD, list);
+ list->destroy_offset(list, offsetof(proposal_t, destroy));
+ break;
+ default:
+ break;
+ }
+}
+
+METHOD(task_t, build_i_delete, status_t,
+ private_child_create_t *this, message_t *message)
+{
+ message->set_exchange_type(message, INFORMATIONAL);
+ if (this->child_sa && this->proposal)
+ {
+ protocol_id_t proto;
+ delete_payload_t *del;
+ u_int32_t spi;
+
+ proto = this->proposal->get_protocol(this->proposal);
+ spi = this->child_sa->get_spi(this->child_sa, TRUE);
+ del = delete_payload_create(DELETE, proto);
+ del->add_spi(del, spi);
+ message->add_payload(message, (payload_t*)del);
+
+ DBG1(DBG_IKE, "sending DELETE for %N CHILD_SA with SPI %.8x",
+ protocol_id_names, proto, ntohl(spi));
+ }
+ return NEED_MORE;
+}
+
+/**
+ * Change task to delete the failed CHILD_SA as initiator
+ */
+static status_t delete_failed_sa(private_child_create_t *this)
+{
+ this->public.task.build = _build_i_delete;
+ this->public.task.process = (void*)return_success;
+ return NEED_MORE;
+}
+
METHOD(task_t, process_i, status_t,
private_child_create_t *this, message_t *message)
{
@@ -1195,6 +1367,7 @@ METHOD(task_t, process_i, status_t,
DBG1(DBG_IKE, "received %N notify, no CHILD_SA built",
notify_type_names, type);
enumerator->destroy(enumerator);
+ raise_alerts(this, type);
handle_child_sa_failure(this, message);
/* an error in CHILD_SA creation is not critical */
return SUCCESS;
@@ -1247,7 +1420,7 @@ METHOD(task_t, process_i, status_t,
DBG1(DBG_IKE, "received an IPCOMP_SUPPORTED notify without requesting"
" one, no CHILD_SA built");
handle_child_sa_failure(this, message);
- return SUCCESS;
+ return delete_failed_sa(this);
}
else if (this->ipcomp != IPCOMP_NONE && this->ipcomp_received == IPCOMP_NONE)
{
@@ -1260,20 +1433,11 @@ METHOD(task_t, process_i, status_t,
DBG1(DBG_IKE, "received an IPCOMP_SUPPORTED notify we didn't propose, "
"no CHILD_SA built");
handle_child_sa_failure(this, message);
- return SUCCESS;
+ return delete_failed_sa(this);
}
if (select_and_install(this, no_dh, ike_auth) == SUCCESS)
{
- DBG0(DBG_IKE, "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));
-
if (!this->rekey)
{ /* invoke the child_up() hook if we are not rekeying */
charon->bus->child_updown(charon->bus, this->child_sa, TRUE);
@@ -1282,6 +1446,7 @@ METHOD(task_t, process_i, status_t,
else
{
handle_child_sa_failure(this, message);
+ return delete_failed_sa(this);
}
return SUCCESS;
}
diff --git a/src/libcharon/sa/ikev2/tasks/child_delete.c b/src/libcharon/sa/ikev2/tasks/child_delete.c
index 8652942ad..eaaca2039 100644
--- a/src/libcharon/sa/ikev2/tasks/child_delete.c
+++ b/src/libcharon/sa/ikev2/tasks/child_delete.c
@@ -177,8 +177,11 @@ static void process_payloads(private_child_delete_t *this, message_t *message)
default:
break;
}
-
- this->child_sas->insert_last(this->child_sas, child_sa);
+ if (this->child_sas->find_first(this->child_sas, NULL,
+ (void**)&child_sa) != SUCCESS)
+ {
+ this->child_sas->insert_last(this->child_sas, child_sa);
+ }
}
spis->destroy(spis);
}
@@ -219,12 +222,13 @@ static status_t destroy_and_reestablish(private_child_delete_t *this)
{
case ACTION_RESTART:
child_cfg->get_ref(child_cfg);
- status = this->ike_sa->initiate(this->ike_sa, child_cfg, 0,
- NULL, NULL);
+ status = this->ike_sa->initiate(this->ike_sa, child_cfg,
+ child_sa->get_reqid(child_sa), NULL, NULL);
break;
case ACTION_ROUTE:
charon->traps->install(charon->traps,
- this->ike_sa->get_peer_cfg(this->ike_sa), child_cfg);
+ this->ike_sa->get_peer_cfg(this->ike_sa), child_cfg,
+ child_sa->get_reqid(child_sa));
break;
default:
break;
@@ -245,6 +249,7 @@ static status_t destroy_and_reestablish(private_child_delete_t *this)
*/
static void log_children(private_child_delete_t *this)
{
+ linked_list_t *my_ts, *other_ts;
enumerator_t *enumerator;
child_sa_t *child_sa;
u_int64_t bytes_in, bytes_out;
@@ -252,15 +257,17 @@ static void log_children(private_child_delete_t *this)
enumerator = this->child_sas->create_enumerator(this->child_sas);
while (enumerator->enumerate(enumerator, (void**)&child_sa))
{
+ my_ts = linked_list_create_from_enumerator(
+ child_sa->create_ts_enumerator(child_sa, TRUE));
+ other_ts = linked_list_create_from_enumerator(
+ child_sa->create_ts_enumerator(child_sa, FALSE));
if (this->expired)
{
DBG0(DBG_IKE, "closing expired CHILD_SA %s{%d} "
"with SPIs %.8x_i %.8x_o and TS %#R=== %#R",
child_sa->get_name(child_sa), child_sa->get_reqid(child_sa),
ntohl(child_sa->get_spi(child_sa, TRUE)),
- ntohl(child_sa->get_spi(child_sa, FALSE)),
- child_sa->get_traffic_selectors(child_sa, TRUE),
- child_sa->get_traffic_selectors(child_sa, FALSE));
+ ntohl(child_sa->get_spi(child_sa, FALSE)), my_ts, other_ts);
}
else
{
@@ -272,9 +279,10 @@ static void log_children(private_child_delete_t *this)
child_sa->get_name(child_sa), child_sa->get_reqid(child_sa),
ntohl(child_sa->get_spi(child_sa, TRUE)), bytes_in,
ntohl(child_sa->get_spi(child_sa, FALSE)), bytes_out,
- child_sa->get_traffic_selectors(child_sa, TRUE),
- child_sa->get_traffic_selectors(child_sa, FALSE));
+ my_ts, other_ts);
}
+ my_ts->destroy(my_ts);
+ other_ts->destroy(other_ts);
}
enumerator->destroy(enumerator);
}
@@ -310,10 +318,6 @@ METHOD(task_t, build_i, status_t,
METHOD(task_t, process_i, status_t,
private_child_delete_t *this, message_t *message)
{
- /* flush the list before adding new SAs */
- this->child_sas->destroy(this->child_sas);
- this->child_sas = linked_list_create();
-
process_payloads(this, message);
DBG1(DBG_IKE, "CHILD_SA closed");
return destroy_and_reestablish(this);
diff --git a/src/libcharon/sa/ikev2/tasks/child_rekey.c b/src/libcharon/sa/ikev2/tasks/child_rekey.c
index 262cb10e0..d2003bb45 100644
--- a/src/libcharon/sa/ikev2/tasks/child_rekey.c
+++ b/src/libcharon/sa/ikev2/tasks/child_rekey.c
@@ -399,12 +399,19 @@ METHOD(child_rekey_t, collide, void,
else if (other->get_type(other) == TASK_CHILD_DELETE)
{
child_delete_t *del = (child_delete_t*)other;
- if (del->get_child(del) == this->child_create->get_child(this->child_create))
+ if (this->collision &&
+ this->collision->get_type(this->collision) == TASK_CHILD_REKEY)
{
- /* peer deletes redundant child created in collision */
- this->other_child_destroyed = TRUE;
- other->destroy(other);
- return;
+ private_child_rekey_t *rekey;
+
+ rekey = (private_child_rekey_t*)this->collision;
+ if (del->get_child(del) == rekey->child_create->get_child(rekey->child_create))
+ {
+ /* peer deletes redundant child created in collision */
+ this->other_child_destroyed = TRUE;
+ other->destroy(other);
+ return;
+ }
}
if (del->get_child(del) != this->child_sa)
{
diff --git a/src/libcharon/sa/ikev2/tasks/ike_auth.c b/src/libcharon/sa/ikev2/tasks/ike_auth.c
index 942f97cf5..8f83c4884 100644
--- a/src/libcharon/sa/ikev2/tasks/ike_auth.c
+++ b/src/libcharon/sa/ikev2/tasks/ike_auth.c
@@ -852,6 +852,33 @@ local_auth_failed:
return FAILED;
}
+/**
+ * Send an INFORMATIONAL message with an AUTH_FAILED before closing IKE_SA
+ */
+static void send_auth_failed_informational(private_ike_auth_t *this,
+ message_t *reply)
+{
+ message_t *message;
+ packet_t *packet;
+ host_t *host;
+
+ message = message_create(IKEV2_MAJOR_VERSION, IKEV2_MINOR_VERSION);
+ message->set_message_id(message, reply->get_message_id(reply) + 1);
+ host = this->ike_sa->get_my_host(this->ike_sa);
+ message->set_source(message, host->clone(host));
+ host = this->ike_sa->get_other_host(this->ike_sa);
+ message->set_destination(message, host->clone(host));
+ message->set_exchange_type(message, INFORMATIONAL);
+ message->add_notify(message, FALSE, AUTHENTICATION_FAILED, chunk_empty);
+
+ if (this->ike_sa->generate_message(this->ike_sa, message,
+ &packet) == SUCCESS)
+ {
+ charon->sender->send(charon->sender, packet);
+ }
+ message->destroy(message);
+}
+
METHOD(task_t, process_i, status_t,
private_ike_auth_t *this, message_t *message)
{
@@ -908,6 +935,7 @@ METHOD(task_t, process_i, status_t,
DBG1(DBG_IKE, "received %N notify error",
notify_type_names, type);
enumerator->destroy(enumerator);
+ charon->bus->alert(charon->bus, ALERT_LOCAL_AUTH_FAILED);
return FAILED;
}
DBG2(DBG_IKE, "received %N notify",
@@ -1004,6 +1032,7 @@ METHOD(task_t, process_i, status_t,
break;
default:
charon->bus->alert(charon->bus, ALERT_LOCAL_AUTH_FAILED);
+ send_auth_failed_informational(this, message);
return FAILED;
}
}
@@ -1048,6 +1077,7 @@ METHOD(task_t, process_i, status_t,
peer_auth_failed:
charon->bus->alert(charon->bus, ALERT_PEER_AUTH_FAILED);
+ send_auth_failed_informational(this, message);
return FAILED;
}
diff --git a/src/libcharon/sa/ikev2/tasks/ike_cert_pre.h b/src/libcharon/sa/ikev2/tasks/ike_cert_pre.h
index ac1a85c29..c1f8635ce 100644
--- a/src/libcharon/sa/ikev2/tasks/ike_cert_pre.h
+++ b/src/libcharon/sa/ikev2/tasks/ike_cert_pre.h
@@ -28,7 +28,7 @@ typedef struct ike_cert_pre_t ike_cert_pre_t;
#include <sa/task.h>
/**
- * Task of type ike_cert_post, certificate processing before authentication.
+ * Task of type ike_cert_pre, certificate processing before authentication.
*/
struct ike_cert_pre_t {
diff --git a/src/libcharon/sa/ikev2/tasks/ike_delete.c b/src/libcharon/sa/ikev2/tasks/ike_delete.c
index f127b0c15..9bc62bf2a 100644
--- a/src/libcharon/sa/ikev2/tasks/ike_delete.c
+++ b/src/libcharon/sa/ikev2/tasks/ike_delete.c
@@ -109,6 +109,14 @@ METHOD(task_t, process_r, status_t,
this->ike_sa->get_other_host(this->ike_sa),
this->ike_sa->get_other_id(this->ike_sa));
+ if (message->get_exchange_type(message) == INFORMATIONAL &&
+ message->get_notify(message, AUTHENTICATION_FAILED))
+ {
+ /* a late AUTHENTICATION_FAILED notify from the initiator after
+ * we have established the IKE_SA: signal auth failure */
+ charon->bus->alert(charon->bus, ALERT_LOCAL_AUTH_FAILED);
+ }
+
switch (this->ike_sa->get_state(this->ike_sa))
{
case IKE_ESTABLISHED:
diff --git a/src/libcharon/sa/ikev2/tasks/ike_init.c b/src/libcharon/sa/ikev2/tasks/ike_init.c
index 7542937b3..278bdc3f2 100644
--- a/src/libcharon/sa/ikev2/tasks/ike_init.c
+++ b/src/libcharon/sa/ikev2/tasks/ike_init.c
@@ -420,6 +420,25 @@ METHOD(task_t, build_r, status_t,
return SUCCESS;
}
+/**
+ * Raise alerts for received notify errors
+ */
+static void raise_alerts(private_ike_init_t *this, notify_type_t type)
+{
+ linked_list_t *list;
+
+ switch (type)
+ {
+ case NO_PROPOSAL_CHOSEN:
+ list = this->config->get_proposals(this->config);
+ charon->bus->alert(charon->bus, ALERT_PROPOSAL_MISMATCH_IKE, list);
+ list->destroy_offset(list, offsetof(proposal_t, destroy));
+ break;
+ default:
+ break;
+ }
+}
+
METHOD(task_t, process_i, status_t,
private_ike_init_t *this, message_t *message)
{
@@ -482,6 +501,7 @@ METHOD(task_t, process_i, status_t,
DBG1(DBG_IKE, "received %N notify error",
notify_type_names, type);
enumerator->destroy(enumerator);
+ raise_alerts(this, type);
return FAILED;
}
DBG2(DBG_IKE, "received %N notify",
diff --git a/src/libcharon/sa/ikev2/tasks/ike_natd.c b/src/libcharon/sa/ikev2/tasks/ike_natd.c
index 0a93db9ed..4fc968f25 100644
--- a/src/libcharon/sa/ikev2/tasks/ike_natd.c
+++ b/src/libcharon/sa/ikev2/tasks/ike_natd.c
@@ -78,6 +78,19 @@ struct private_ike_natd_t {
bool mapping_changed;
};
+/**
+ * Check if UDP encapsulation has to be forced either by config or required
+ * by the kernel interface
+ */
+static bool force_encap(ike_cfg_t *ike_cfg)
+{
+ if (!ike_cfg->force_encap(ike_cfg))
+ {
+ return hydra->kernel_interface->get_features(hydra->kernel_interface) &
+ KERNEL_REQUIRE_UDP_ENCAPSULATION;
+ }
+ return TRUE;
+}
/**
* Build NAT detection hash for a host
@@ -147,7 +160,7 @@ static notify_payload_t *build_natd_payload(private_ike_natd_t *this,
ike_sa_id = this->ike_sa->get_id(this->ike_sa);
config = this->ike_sa->get_ike_cfg(this->ike_sa);
- if (config->force_encap(config) && type == NAT_DETECTION_SOURCE_IP)
+ if (force_encap(config) && type == NAT_DETECTION_SOURCE_IP)
{
hash = generate_natd_hash_faked(this);
}
@@ -256,7 +269,7 @@ static void process_payloads(private_ike_natd_t *this, message_t *message)
!this->src_matched);
config = this->ike_sa->get_ike_cfg(this->ike_sa);
if (this->dst_matched && this->src_matched &&
- config->force_encap(config))
+ force_encap(config))
{
this->ike_sa->set_condition(this->ike_sa, COND_NAT_FAKE, TRUE);
}
@@ -316,7 +329,7 @@ METHOD(task_t, build_i, status_t,
* 3. Include all possbile addresses
*/
host = message->get_source(message);
- if (!host->is_anyaddr(host) || ike_cfg->force_encap(ike_cfg))
+ if (!host->is_anyaddr(host) || force_encap(ike_cfg))
{ /* 1. or if we force UDP encap, as it doesn't matter if it's %any */
notify = build_natd_payload(this, NAT_DETECTION_SOURCE_IP, host);
if (notify)