summaryrefslogtreecommitdiff
path: root/src/libcharon
diff options
context:
space:
mode:
Diffstat (limited to 'src/libcharon')
-rw-r--r--src/libcharon/bus/bus.c34
-rw-r--r--src/libcharon/bus/bus.h13
-rw-r--r--src/libcharon/bus/listeners/listener.h17
-rw-r--r--src/libcharon/encoding/message.c66
-rw-r--r--src/libcharon/encoding/payloads/encrypted_payload.c5
-rw-r--r--src/libcharon/encoding/payloads/payload.c2
-rw-r--r--src/libcharon/encoding/payloads/payload.h7
-rw-r--r--src/libcharon/encoding/payloads/unknown_payload.c8
-rw-r--r--src/libcharon/encoding/payloads/unknown_payload.h8
-rw-r--r--src/libcharon/network/receiver.c2
-rw-r--r--src/libcharon/plugins/eap_aka/eap_aka_server.c5
-rw-r--r--src/libcharon/plugins/eap_aka_3gpp2/eap_aka_3gpp2_card.c3
-rw-r--r--src/libcharon/plugins/eap_aka_3gpp2/eap_aka_3gpp2_provider.c3
-rw-r--r--src/libcharon/plugins/eap_md5/eap_md5.c3
-rw-r--r--src/libcharon/plugins/eap_mschapv2/eap_mschapv2.c7
-rw-r--r--src/libcharon/plugins/eap_radius/eap_radius_accounting.c390
-rw-r--r--src/libcharon/plugins/eap_sim/eap_sim_peer.c3
-rw-r--r--src/libcharon/plugins/eap_sim/eap_sim_server.c3
-rw-r--r--src/libcharon/plugins/eap_sim_file/eap_sim_file_card.c3
-rw-r--r--src/libcharon/plugins/ha/ha_cache.c12
-rw-r--r--src/libcharon/plugins/ha/ha_cache.h3
-rw-r--r--src/libcharon/plugins/ha/ha_plugin.c128
-rw-r--r--src/libcharon/plugins/vici/libvici.h29
-rw-r--r--src/libcharon/plugins/vici/python/Makefile.am12
-rw-r--r--src/libcharon/plugins/vici/python/Makefile.in17
-rw-r--r--src/libcharon/plugins/vici/ruby/Makefile.am4
-rw-r--r--src/libcharon/plugins/vici/ruby/Makefile.in14
-rw-r--r--src/libcharon/plugins/vici/vici_config.c37
-rw-r--r--src/libcharon/plugins/vici/vici_dispatcher.c41
-rw-r--r--src/libcharon/plugins/vici/vici_dispatcher.h33
-rw-r--r--src/libcharon/plugins/vici/vici_plugin.c24
-rw-r--r--src/libcharon/plugins/vici/vici_query.c85
-rw-r--r--src/libcharon/plugins/vici/vici_query.h28
-rw-r--r--src/libcharon/plugins/vici/vici_socket.c46
-rw-r--r--src/libcharon/plugins/xauth_generic/xauth_generic.c2
-rw-r--r--src/libcharon/processing/jobs/adopt_children_job.c20
-rw-r--r--src/libcharon/sa/ike_sa_manager.c4
-rw-r--r--src/libcharon/sa/ikev1/authenticators/psk_v1_authenticator.c2
-rw-r--r--src/libcharon/sa/ikev1/task_manager_v1.c5
-rw-r--r--src/libcharon/sa/ikev2/authenticators/eap_authenticator.c2
-rw-r--r--src/libcharon/sa/ikev2/authenticators/psk_authenticator.c2
-rw-r--r--src/libcharon/sa/ikev2/keymat_v2.c15
-rw-r--r--src/libcharon/sa/ikev2/task_manager_v2.c18
-rw-r--r--src/libcharon/sa/ikev2/tasks/child_create.c43
-rw-r--r--src/libcharon/sa/ikev2/tasks/ike_init.c53
-rw-r--r--src/libcharon/sa/ikev2/tasks/ike_mobike.c2
-rw-r--r--src/libcharon/sa/ikev2/tasks/ike_vendor.c10
47 files changed, 1028 insertions, 245 deletions
diff --git a/src/libcharon/bus/bus.c b/src/libcharon/bus/bus.c
index 7938f46cc..53ded6be7 100644
--- a/src/libcharon/bus/bus.c
+++ b/src/libcharon/bus/bus.c
@@ -1,5 +1,5 @@
/*
- * Copyright (C) 2011-2014 Tobias Brunner
+ * Copyright (C) 2011-2015 Tobias Brunner
* Copyright (C) 2006 Martin Willi
* Hochschule fuer Technik Rapperswil
*
@@ -687,6 +687,37 @@ METHOD(bus_t, child_rekey, void,
this->mutex->unlock(this->mutex);
}
+METHOD(bus_t, children_migrate, void,
+ private_bus_t *this, ike_sa_id_t *new, u_int32_t unique)
+{
+ enumerator_t *enumerator;
+ ike_sa_t *ike_sa;
+ entry_t *entry;
+ bool keep;
+
+ ike_sa = this->thread_sa->get(this->thread_sa);
+
+ this->mutex->lock(this->mutex);
+ enumerator = this->listeners->create_enumerator(this->listeners);
+ while (enumerator->enumerate(enumerator, &entry))
+ {
+ if (entry->calling || !entry->listener->children_migrate)
+ {
+ continue;
+ }
+ entry->calling++;
+ keep = entry->listener->children_migrate(entry->listener, ike_sa, new,
+ unique);
+ entry->calling--;
+ if (!keep)
+ {
+ unregister_listener(this, entry, enumerator);
+ }
+ }
+ enumerator->destroy(enumerator);
+ this->mutex->unlock(this->mutex);
+}
+
METHOD(bus_t, ike_updown, void,
private_bus_t *this, ike_sa_t *ike_sa, bool up)
{
@@ -1038,6 +1069,7 @@ bus_t *bus_create()
.ike_reestablish_post = _ike_reestablish_post,
.child_updown = _child_updown,
.child_rekey = _child_rekey,
+ .children_migrate = _children_migrate,
.authorize = _authorize,
.narrow = _narrow,
.assign_vips = _assign_vips,
diff --git a/src/libcharon/bus/bus.h b/src/libcharon/bus/bus.h
index 051c429f9..b6757b140 100644
--- a/src/libcharon/bus/bus.h
+++ b/src/libcharon/bus/bus.h
@@ -1,5 +1,5 @@
/*
- * Copyright (C) 2012-2014 Tobias Brunner
+ * Copyright (C) 2012-2015 Tobias Brunner
* Copyright (C) 2006-2009 Martin Willi
* Hochschule fuer Technik Rapperswil
*
@@ -130,7 +130,8 @@ enum alert_t {
ALERT_UNIQUE_REPLACE,
/** IKE_SA deleted because of "keep" unique policy, no argument */
ALERT_UNIQUE_KEEP,
- /** IKE_SA kept on failed child SA establishment, no argument */
+ /** IKE_SA kept on failed child SA establishment, argument is an int (!=0 if
+ * first child SA) */
ALERT_KEEP_ON_CHILD_SA_FAILURE,
/** allocating virtual IP failed, linked_list_t of host_t requested */
ALERT_VIP_FAILURE,
@@ -426,6 +427,14 @@ struct bus_t {
void (*child_rekey)(bus_t *this, child_sa_t *old, child_sa_t *new);
/**
+ * CHILD_SA migration hook.
+ *
+ * @param new ID of new SA when called for the old, NULL otherwise
+ * @param uniue unique ID of new SA when called for the old, 0 otherwise
+ */
+ void (*children_migrate)(bus_t *this, ike_sa_id_t *new, u_int32_t unique);
+
+ /**
* Virtual IP assignment hook.
*
* @param ike_sa IKE_SA the VIPs are assigned to
diff --git a/src/libcharon/bus/listeners/listener.h b/src/libcharon/bus/listeners/listener.h
index 3447d8f99..c7a8d8d1e 100644
--- a/src/libcharon/bus/listeners/listener.h
+++ b/src/libcharon/bus/listeners/listener.h
@@ -1,5 +1,5 @@
/*
- * Copyright (C) 2011-2014 Tobias Brunner
+ * Copyright (C) 2011-2015 Tobias Brunner
* Copyright (C) 2009 Martin Willi
* Hochschule fuer Technik Rapperswil
*
@@ -188,6 +188,21 @@ struct listener_t {
child_sa_t *old, child_sa_t *new);
/**
+ * Hook called when CHILD_SAs get migrated from one IKE_SA to another during
+ * IKEv1 reauthentication.
+ *
+ * This is called twice, once for the old IKE_SA before the CHILD_SAs are
+ * removed, and once for the new IKE_SA just after they got added.
+ *
+ * @param ike_sa new or old IKE_SA
+ * @param new ID of new SA when called for the old, NULL otherwise
+ * @param unique unique ID of new SA when called for the old, 0 otherwise
+ * @return TRUE to stay registered, FALSE to unregister
+ */
+ bool (*children_migrate)(listener_t *this, ike_sa_t *ike_sa,
+ ike_sa_id_t *new, u_int32_t unique);
+
+ /**
* Hook called to invoke additional authorization rules.
*
* An authorization hook gets invoked several times: After each
diff --git a/src/libcharon/encoding/message.c b/src/libcharon/encoding/message.c
index 0a596ffb0..3303024cd 100644
--- a/src/libcharon/encoding/message.c
+++ b/src/libcharon/encoding/message.c
@@ -1411,6 +1411,55 @@ static char* get_string(private_message_t *this, char *buf, int len)
len -= written;
}
}
+ if (payload->get_type(payload) == PLV1_FRAGMENT)
+ {
+ fragment_payload_t *frag;
+
+ frag = (fragment_payload_t*)payload;
+ if (frag->is_last(frag))
+ {
+ written = snprintf(pos, len, "(%u/%u)",
+ frag->get_number(frag), frag->get_number(frag));
+ }
+ else
+ {
+ written = snprintf(pos, len, "(%u)", frag->get_number(frag));
+ }
+ if (written >= len || written < 0)
+ {
+ return buf;
+ }
+ pos += written;
+ len -= written;
+ }
+ if (payload->get_type(payload) == PLV2_FRAGMENT)
+ {
+ encrypted_fragment_payload_t *frag;
+
+ frag = (encrypted_fragment_payload_t*)payload;
+ written = snprintf(pos, len, "(%u/%u)",
+ frag->get_fragment_number(frag),
+ frag->get_total_fragments(frag));
+ if (written >= len || written < 0)
+ {
+ return buf;
+ }
+ pos += written;
+ len -= written;
+ }
+ if (payload->get_type(payload) == PL_UNKNOWN)
+ {
+ unknown_payload_t *unknown;
+
+ unknown = (unknown_payload_t*)payload;
+ written = snprintf(pos, len, "(%d)", unknown->get_type(unknown));
+ if (written >= len || written < 0)
+ {
+ return buf;
+ }
+ pos += written;
+ len -= written;
+ }
}
enumerator->destroy(enumerator);
@@ -2237,9 +2286,16 @@ static status_t parse_payloads(private_message_t *this)
payload->destroy(payload);
return VERIFY_ERROR;
}
-
- DBG2(DBG_ENC, "%N payload verified, adding to payload list",
- payload_type_names, type);
+ if (payload->get_type(payload) == PL_UNKNOWN)
+ {
+ DBG2(DBG_ENC, "%N payload unknown or not allowed",
+ payload_type_names, type);
+ }
+ else
+ {
+ DBG2(DBG_ENC, "%N payload verified, adding to payload list",
+ payload_type_names, type);
+ }
this->payloads->insert_last(this->payloads, payload);
/* an encrypted (fragment) payload MUST be the last one, so STOP here.
@@ -2477,7 +2533,7 @@ static status_t decrypt_payloads(private_message_t *this, keymat_t *keymat)
was_encrypted = "encrypted fragment payload";
}
- if (payload_is_known(type, this->major_version) && !was_encrypted &&
+ if (type != PL_UNKNOWN && !was_encrypted &&
!is_connectivity_check(this, payload) &&
this->exchange_type != AGGRESSIVE)
{
@@ -2625,7 +2681,7 @@ METHOD(message_t, parse_body, status_t,
other_hash = hash_payload->get_hash(hash_payload);
DBG3(DBG_ENC, "HASH received %B\nHASH expected %B",
&other_hash, &hash);
- if (!chunk_equals(hash, other_hash))
+ if (!chunk_equals_const(hash, other_hash))
{
DBG1(DBG_ENC, "received HASH payload does not match");
chunk_free(&hash);
diff --git a/src/libcharon/encoding/payloads/encrypted_payload.c b/src/libcharon/encoding/payloads/encrypted_payload.c
index 04372fdf0..d1a267836 100644
--- a/src/libcharon/encoding/payloads/encrypted_payload.c
+++ b/src/libcharon/encoding/payloads/encrypted_payload.c
@@ -502,6 +502,8 @@ METHOD(encrypted_payload_t, encrypt, status_t,
generator = generator_create();
plain = generate(this, generator);
assoc = append_header(this, assoc);
+ /* lower 32-bits are for fragment number, if used */
+ mid <<= 32;
status = encrypt_content("encrypted payload", this->aead, mid, plain, assoc,
&this->encrypted);
generator->destroy(generator);
@@ -932,6 +934,9 @@ METHOD(encrypted_payload_t, frag_encrypt, status_t,
}
free(this->encrypted.ptr);
assoc = append_header_frag(this, assoc);
+ /* IKEv2 message IDs are not unique if fragmentation is used, hence include
+ * the fragment number to make it unique */
+ mid = mid << 32 | this->fragment_number;
status = encrypt_content("encrypted fragment payload", this->aead, mid,
this->plain, assoc, &this->encrypted);
free(assoc.ptr);
diff --git a/src/libcharon/encoding/payloads/payload.c b/src/libcharon/encoding/payloads/payload.c
index a1cd2f945..f7c2754e0 100644
--- a/src/libcharon/encoding/payloads/payload.c
+++ b/src/libcharon/encoding/payloads/payload.c
@@ -97,6 +97,7 @@ ENUM_NEXT(payload_type_names, PLV1_NAT_D_DRAFT_00_03, PLV1_FRAGMENT, PLV2_FRAGME
#endif /* ME */
ENUM_NEXT(payload_type_names, PL_HEADER, PLV1_ENCRYPTED, PLV1_FRAGMENT,
"HEADER",
+ "UNKNOWN",
"PROPOSAL_SUBSTRUCTURE",
"PROPOSAL_SUBSTRUCTURE_V1",
"TRANSFORM_SUBSTRUCTURE",
@@ -167,6 +168,7 @@ ENUM_NEXT(payload_type_short_names, PLV1_NAT_D_DRAFT_00_03, PLV1_FRAGMENT, PLV2_
#endif /* ME */
ENUM_NEXT(payload_type_short_names, PL_HEADER, PLV1_ENCRYPTED, PLV1_FRAGMENT,
"HDR",
+ "UNKN",
"PROP",
"PROP",
"TRANS",
diff --git a/src/libcharon/encoding/payloads/payload.h b/src/libcharon/encoding/payloads/payload.h
index 920779bd1..72003894f 100644
--- a/src/libcharon/encoding/payloads/payload.h
+++ b/src/libcharon/encoding/payloads/payload.h
@@ -1,5 +1,5 @@
/*
- * Copyright (C) 2007 Tobias Brunner
+ * Copyright (C) 2007-2015 Tobias Brunner
* Copyright (C) 2005-2006 Martin Willi
* Copyright (C) 2005 Jan Hutter
* Hochschule fuer Technik Rapperswil
@@ -264,6 +264,11 @@ enum payload_type_t {
PL_HEADER = 256,
/**
+ * Used to handle unknown or invalid payload types.
+ */
+ PL_UNKNOWN,
+
+ /**
* PLV2_PROPOSAL_SUBSTRUCTURE, IKEv2 proposals in a SA payload.
*/
PLV2_PROPOSAL_SUBSTRUCTURE,
diff --git a/src/libcharon/encoding/payloads/unknown_payload.c b/src/libcharon/encoding/payloads/unknown_payload.c
index 45b91fd0b..c69254fc0 100644
--- a/src/libcharon/encoding/payloads/unknown_payload.c
+++ b/src/libcharon/encoding/payloads/unknown_payload.c
@@ -1,4 +1,5 @@
/*
+ * Copyright (C) 2015 Tobias Brunner
* Copyright (C) 2005-2006 Martin Willi
* Copyright (C) 2005 Jan Hutter
* Hochschule fuer Technik Rapperswil
@@ -121,6 +122,12 @@ METHOD(payload_t, get_header_length, int,
METHOD(payload_t, get_payload_type, payload_type_t,
private_unknown_payload_t *this)
{
+ return PL_UNKNOWN;
+}
+
+METHOD(unknown_payload_t, get_type, payload_type_t,
+ private_unknown_payload_t *this)
+{
return this->type;
}
@@ -181,6 +188,7 @@ unknown_payload_t *unknown_payload_create(payload_type_t type)
.destroy = _destroy,
},
.is_critical = _is_critical,
+ .get_type = _get_type,
.get_data = _get_data,
.destroy = _destroy,
},
diff --git a/src/libcharon/encoding/payloads/unknown_payload.h b/src/libcharon/encoding/payloads/unknown_payload.h
index 326b550cd..09341bcc7 100644
--- a/src/libcharon/encoding/payloads/unknown_payload.h
+++ b/src/libcharon/encoding/payloads/unknown_payload.h
@@ -1,4 +1,5 @@
/*
+ * Copyright (C) 2015 Tobias Brunner
* Copyright (C) 2005-2006 Martin Willi
* Copyright (C) 2005 Jan Hutter
* Hochschule fuer Technik Rapperswil
@@ -42,6 +43,13 @@ struct unknown_payload_t {
payload_t payload_interface;
/**
+ * Get the original payload type as sent by the peer.
+ *
+ * @return type of the original payload
+ */
+ payload_type_t (*get_type) (unknown_payload_t *this);
+
+ /**
* Get the raw data of this payload, without
* the generic payload header.
*
diff --git a/src/libcharon/network/receiver.c b/src/libcharon/network/receiver.c
index 5ce9471bd..6902c4847 100644
--- a/src/libcharon/network/receiver.c
+++ b/src/libcharon/network/receiver.c
@@ -247,7 +247,7 @@ static bool cookie_verify(private_receiver_t *this, message_t *message,
{
return FALSE;
}
- if (chunk_equals(reference, cookie))
+ if (chunk_equals_const(reference, cookie))
{
chunk_free(&reference);
return TRUE;
diff --git a/src/libcharon/plugins/eap_aka/eap_aka_server.c b/src/libcharon/plugins/eap_aka/eap_aka_server.c
index eba7af874..04bfc170b 100644
--- a/src/libcharon/plugins/eap_aka/eap_aka_server.c
+++ b/src/libcharon/plugins/eap_aka/eap_aka_server.c
@@ -425,7 +425,7 @@ static status_t process_challenge(private_eap_aka_server_t *this,
enumerator->destroy(enumerator);
/* compare received RES against stored XRES */
- if (!chunk_equals(res, this->xres))
+ if (!chunk_equals_const(res, this->xres))
{
DBG1(DBG_IKE, "received RES does not match XRES");
return FAILED;
@@ -486,7 +486,7 @@ static status_t process_reauthentication(private_eap_aka_server_t *this,
this->crypto->clear_keys(this->crypto);
return challenge(this, out);
}
- if (!chunk_equals(counter, this->counter))
+ if (!chunk_equals_const(counter, this->counter))
{
DBG1(DBG_IKE, "received counter does not match");
return FAILED;
@@ -730,4 +730,3 @@ eap_aka_server_t *eap_aka_server_create(identification_t *server,
return &this->public;
}
-
diff --git a/src/libcharon/plugins/eap_aka_3gpp2/eap_aka_3gpp2_card.c b/src/libcharon/plugins/eap_aka_3gpp2/eap_aka_3gpp2_card.c
index a71dae78a..e38ee5b70 100644
--- a/src/libcharon/plugins/eap_aka_3gpp2/eap_aka_3gpp2_card.c
+++ b/src/libcharon/plugins/eap_aka_3gpp2/eap_aka_3gpp2_card.c
@@ -87,7 +87,7 @@ METHOD(simaka_card_t, get_quintuplet, status_t,
{
return FAILED;
}
- if (!memeq(mac, xmac, AKA_MAC_LEN))
+ if (!memeq_const(mac, xmac, AKA_MAC_LEN))
{
DBG1(DBG_IKE, "received MAC does not match XMAC");
DBG3(DBG_IKE, "MAC %b\nXMAC %b", mac, AKA_MAC_LEN, xmac, AKA_MAC_LEN);
@@ -184,4 +184,3 @@ eap_aka_3gpp2_card_t *eap_aka_3gpp2_card_create(eap_aka_3gpp2_functions_t *f)
return &this->public;
}
-
diff --git a/src/libcharon/plugins/eap_aka_3gpp2/eap_aka_3gpp2_provider.c b/src/libcharon/plugins/eap_aka_3gpp2/eap_aka_3gpp2_provider.c
index 0be122158..f272e1ec8 100644
--- a/src/libcharon/plugins/eap_aka_3gpp2/eap_aka_3gpp2_provider.c
+++ b/src/libcharon/plugins/eap_aka_3gpp2/eap_aka_3gpp2_provider.c
@@ -158,7 +158,7 @@ METHOD(simaka_provider_t, resync, bool,
{
return FALSE;
}
- if (!memeq(macs, xmacs, AKA_MAC_LEN))
+ if (!memeq_const(macs, xmacs, AKA_MAC_LEN))
{
DBG1(DBG_IKE, "received MACS does not match XMACS");
DBG3(DBG_IKE, "MACS %b XMACS %b",
@@ -205,4 +205,3 @@ eap_aka_3gpp2_provider_t *eap_aka_3gpp2_provider_create(
return &this->public;
}
-
diff --git a/src/libcharon/plugins/eap_md5/eap_md5.c b/src/libcharon/plugins/eap_md5/eap_md5.c
index b2640d104..d314e7a9e 100644
--- a/src/libcharon/plugins/eap_md5/eap_md5.c
+++ b/src/libcharon/plugins/eap_md5/eap_md5.c
@@ -193,7 +193,7 @@ METHOD(eap_method_t, process_server, status_t,
}
response = chunk_create(data.ptr + 6, data.ptr[5]);
if (response.len < expected.len ||
- !memeq(response.ptr, expected.ptr, expected.len))
+ !memeq_const(response.ptr, expected.ptr, expected.len))
{
chunk_free(&expected);
DBG1(DBG_IKE, "EAP-MD5 verification failed");
@@ -299,4 +299,3 @@ eap_md5_t *eap_md5_create_peer(identification_t *server, identification_t *peer)
return &this->public;
}
-
diff --git a/src/libcharon/plugins/eap_mschapv2/eap_mschapv2.c b/src/libcharon/plugins/eap_mschapv2/eap_mschapv2.c
index 511506869..f7f39f984 100644
--- a/src/libcharon/plugins/eap_mschapv2/eap_mschapv2.c
+++ b/src/libcharon/plugins/eap_mschapv2/eap_mschapv2.c
@@ -812,7 +812,7 @@ static status_t process_peer_success(private_eap_mschapv2_t *this,
goto error;
}
- if (!chunk_equals(this->auth_response, auth_string))
+ if (!chunk_equals_const(this->auth_response, auth_string))
{
DBG1(DBG_IKE, "EAP-MS-CHAPv2 verification failed");
goto error;
@@ -1087,8 +1087,8 @@ static status_t process_server_response(private_eap_mschapv2_t *this,
userid->destroy(userid);
chunk_clear(&nt_hash);
- if (memeq(res->response.nt_response, this->nt_response.ptr,
- this->nt_response.len))
+ if (memeq_const(res->response.nt_response, this->nt_response.ptr,
+ this->nt_response.len))
{
chunk_t hex;
char msg[AUTH_RESPONSE_LEN + sizeof(SUCCESS_MESSAGE)];
@@ -1267,4 +1267,3 @@ eap_mschapv2_t *eap_mschapv2_create_peer(identification_t *server, identificatio
return &this->public;
}
-
diff --git a/src/libcharon/plugins/eap_radius/eap_radius_accounting.c b/src/libcharon/plugins/eap_radius/eap_radius_accounting.c
index ac4ecfc86..cef19305c 100644
--- a/src/libcharon/plugins/eap_radius/eap_radius_accounting.c
+++ b/src/libcharon/plugins/eap_radius/eap_radius_accounting.c
@@ -1,4 +1,7 @@
/*
+ * Copyright (C) 2015 Tobias Brunner
+ * Hochschule fuer Technik Rapperswil
+ *
* Copyright (C) 2012 Martin Willi
* Copyright (C) 2012 revosec AG
*
@@ -21,6 +24,7 @@
#include <radius_message.h>
#include <radius_client.h>
#include <daemon.h>
+#include <collections/array.h>
#include <collections/hashtable.h>
#include <threading/mutex.h>
#include <processing/jobs/callback_job.h>
@@ -93,6 +97,62 @@ typedef enum {
} radius_acct_terminate_cause_t;
/**
+ * Usage stats for bytes and packets
+ */
+typedef struct {
+ struct {
+ u_int64_t sent;
+ u_int64_t received;
+ } bytes, packets;
+} usage_t;
+
+/**
+ * Add usage stats (modifies a)
+ */
+static inline void add_usage(usage_t *a, usage_t b)
+{
+ a->bytes.sent += b.bytes.sent;
+ a->bytes.received += b.bytes.received;
+ a->packets.sent += b.packets.sent;
+ a->packets.received += b.packets.received;
+}
+
+/**
+ * Subtract usage stats (modifies a)
+ */
+static inline void sub_usage(usage_t *a, usage_t b)
+{
+ a->bytes.sent -= b.bytes.sent;
+ a->bytes.received -= b.bytes.received;
+ a->packets.sent -= b.packets.sent;
+ a->packets.received -= b.packets.received;
+}
+
+/**
+ * Usage stats for a cached/migrated SAs
+ */
+typedef struct {
+ /** unique CHILD_SA identifier */
+ u_int32_t id;
+ /** usage stats for this SA */
+ usage_t usage;
+} sa_entry_t;
+
+/**
+ * Clone an sa_entry_t
+ */
+static sa_entry_t *clone_sa(sa_entry_t *sa)
+{
+ sa_entry_t *this;
+
+ INIT(this,
+ .id = sa->id,
+ .usage = sa->usage,
+ );
+ return this;
+}
+
+/**
* Hashtable entry with usage stats
*/
typedef struct {
@@ -100,11 +160,12 @@ typedef struct {
ike_sa_id_t *id;
/** RADIUS accounting session ID */
char sid[24];
- /** number of sent/received octets/packets */
- struct {
- u_int64_t sent;
- u_int64_t received;
- } bytes, packets;
+ /** number of sent/received octets/packets for expired SAs */
+ usage_t usage;
+ /** list of cached SAs, sa_entry_t (sorted by their unique ID) */
+ array_t *cached;
+ /** list of migrated SAs, sa_entry_t (sorted by their unique ID) */
+ array_t *migrated;
/** session creation time */
time_t created;
/** terminate cause */
@@ -123,6 +184,8 @@ typedef struct {
*/
static void destroy_entry(entry_t *this)
{
+ array_destroy_function(this->cached, (void*)free, NULL);
+ array_destroy_function(this->migrated, (void*)free, NULL);
this->id->destroy(this->id);
free(this);
}
@@ -155,30 +218,157 @@ static bool equals(ike_sa_id_t *a, ike_sa_id_t *b)
}
/**
+ * Sort cached SAs
+ */
+static int sa_sort(const void *a, const void *b, void *user)
+{
+ const sa_entry_t *ra = a, *rb = b;
+ return ra->id - rb->id;
+}
+
+/**
+ * Find a cached SA
+ */
+static int sa_find(const void *a, const void *b)
+{
+ return sa_sort(a, b, NULL);
+}
+
+/**
+ * Update or create usage counters of a cached SA
+ */
+static void update_sa(entry_t *entry, u_int32_t id, usage_t usage)
+{
+ sa_entry_t *sa, lookup;
+
+ lookup.id = id;
+ if (array_bsearch(entry->cached, &lookup, sa_find, &sa) == -1)
+ {
+ INIT(sa,
+ .id = id,
+ );
+ array_insert_create(&entry->cached, ARRAY_TAIL, sa);
+ array_sort(entry->cached, sa_sort, NULL);
+ }
+ sa->usage = usage;
+}
+
+/**
* Update usage counter when a CHILD_SA rekeys/goes down
*/
static void update_usage(private_eap_radius_accounting_t *this,
ike_sa_t *ike_sa, child_sa_t *child_sa)
{
- u_int64_t bytes_in, bytes_out, packets_in, packets_out;
+ usage_t usage;
entry_t *entry;
- child_sa->get_usestats(child_sa, FALSE, NULL, &bytes_out, &packets_out);
- child_sa->get_usestats(child_sa, TRUE, NULL, &bytes_in, &packets_in);
+ child_sa->get_usestats(child_sa, TRUE, NULL, &usage.bytes.received,
+ &usage.packets.received);
+ child_sa->get_usestats(child_sa, FALSE, NULL, &usage.bytes.sent,
+ &usage.packets.sent);
this->mutex->lock(this->mutex);
entry = this->sessions->get(this->sessions, ike_sa->get_id(ike_sa));
if (entry)
{
- entry->bytes.sent += bytes_out;
- entry->bytes.received += bytes_in;
- entry->packets.sent += packets_out;
- entry->packets.received += packets_in;
+ update_sa(entry, child_sa->get_unique_id(child_sa), usage);
}
this->mutex->unlock(this->mutex);
}
/**
+ * Collect usage stats for all CHILD_SAs of the given IKE_SA, optionally returns
+ * the total number of bytes and packets
+ */
+static array_t *collect_stats(ike_sa_t *ike_sa, usage_t *total)
+{
+ enumerator_t *enumerator;
+ child_sa_t *child_sa;
+ array_t *stats;
+ sa_entry_t *sa;
+ usage_t usage;
+
+ if (total)
+ {
+ *total = (usage_t){};
+ }
+
+ stats = array_create(0, 0);
+ enumerator = ike_sa->create_child_sa_enumerator(ike_sa);
+ while (enumerator->enumerate(enumerator, &child_sa))
+ {
+ INIT(sa,
+ .id = child_sa->get_unique_id(child_sa),
+ );
+ array_insert(stats, ARRAY_TAIL, sa);
+ array_sort(stats, sa_sort, NULL);
+
+ child_sa->get_usestats(child_sa, TRUE, NULL, &usage.bytes.received,
+ &usage.packets.received);
+ child_sa->get_usestats(child_sa, FALSE, NULL, &usage.bytes.sent,
+ &usage.packets.sent);
+ sa->usage = usage;
+ if (total)
+ {
+ add_usage(total, usage);
+ }
+ }
+ enumerator->destroy(enumerator);
+ return stats;
+}
+
+/**
+ * Cleanup cached SAs
+ */
+static void cleanup_sas(private_eap_radius_accounting_t *this, ike_sa_t *ike_sa,
+ entry_t *entry)
+{
+ enumerator_t *enumerator;
+ child_sa_t *child_sa;
+ sa_entry_t *sa, *found;
+ array_t *sas;
+
+ sas = array_create(0, 0);
+ enumerator = ike_sa->create_child_sa_enumerator(ike_sa);
+ while (enumerator->enumerate(enumerator, &child_sa))
+ {
+ INIT(sa,
+ .id = child_sa->get_unique_id(child_sa),
+ );
+ array_insert(sas, ARRAY_TAIL, sa);
+ array_sort(sas, sa_sort, NULL);
+ }
+ enumerator->destroy(enumerator);
+
+ enumerator = array_create_enumerator(entry->cached);
+ while (enumerator->enumerate(enumerator, &sa))
+ {
+ if (array_bsearch(sas, sa, sa_find, &found) == -1)
+ {
+ /* SA is gone, add its latest stats to the total for this IKE_SA
+ * and remove the cache entry */
+ add_usage(&entry->usage, sa->usage);
+ array_remove_at(entry->cached, enumerator);
+ free(sa);
+ }
+ }
+ enumerator->destroy(enumerator);
+ enumerator = array_create_enumerator(entry->migrated);
+ while (enumerator->enumerate(enumerator, &sa))
+ {
+ if (array_bsearch(sas, sa, sa_find, &found) == -1)
+ {
+ /* SA is gone, subtract stats from the total for this IKE_SA */
+ sub_usage(&entry->usage, sa->usage);
+ array_remove_at(entry->migrated, enumerator);
+ free(sa);
+ }
+ }
+ enumerator->destroy(enumerator);
+ array_destroy_function(sas, (void*)free, NULL);
+}
+
+/**
* Send a RADIUS message, wait for response
*/
static bool send_message(private_eap_radius_accounting_t *this,
@@ -273,17 +463,15 @@ static void add_ike_sa_parameters(private_eap_radius_accounting_t *this,
* Get an existing or create a new entry from the locked session table
*/
static entry_t* get_or_create_entry(private_eap_radius_accounting_t *this,
- ike_sa_t *ike_sa)
+ ike_sa_id_t *id, u_int32_t unique)
{
- ike_sa_id_t *id;
entry_t *entry;
time_t now;
- entry = this->sessions->get(this->sessions, ike_sa->get_id(ike_sa));
+ entry = this->sessions->get(this->sessions, id);
if (!entry)
{
now = time_monotonic(NULL);
- id = ike_sa->get_id(ike_sa);
INIT(entry,
.id = id->clone(id),
@@ -294,8 +482,7 @@ static entry_t* get_or_create_entry(private_eap_radius_accounting_t *this,
/* default terminate cause, if none other catched */
.cause = ACCT_CAUSE_USER_REQUEST,
);
- snprintf(entry->sid, sizeof(entry->sid), "%u-%u",
- this->prefix, ike_sa->get_unique_id(ike_sa));
+ snprintf(entry->sid, sizeof(entry->sid), "%u-%u", this->prefix, unique);
this->sessions->put(this->sessions, entry->id, entry);
}
return entry;
@@ -330,31 +517,21 @@ void destroy_interim_data(interim_data_t *this)
static job_requeue_t send_interim(interim_data_t *data)
{
private_eap_radius_accounting_t *this = data->this;
- u_int64_t bytes_in = 0, bytes_out = 0, packets_in = 0, packets_out = 0;
- u_int64_t bytes, packets;
+ usage_t usage;
radius_message_t *message = NULL;
enumerator_t *enumerator;
- child_sa_t *child_sa;
ike_sa_t *ike_sa;
entry_t *entry;
u_int32_t value;
+ array_t *stats;
+ sa_entry_t *sa, *found;
ike_sa = charon->ike_sa_manager->checkout(charon->ike_sa_manager, data->id);
if (!ike_sa)
{
return JOB_REQUEUE_NONE;
}
- enumerator = ike_sa->create_child_sa_enumerator(ike_sa);
- while (enumerator->enumerate(enumerator, &child_sa))
- {
- child_sa->get_usestats(child_sa, FALSE, NULL, &bytes, &packets);
- bytes_out += bytes;
- packets_out += packets;
- child_sa->get_usestats(child_sa, TRUE, NULL, &bytes, &packets);
- bytes_in += bytes;
- packets_in += packets;
- }
- enumerator->destroy(enumerator);
+ stats = collect_stats(ike_sa, &usage);
charon->ike_sa_manager->checkin(charon->ike_sa_manager, ike_sa);
/* avoid any races by returning IKE_SA before acquiring lock */
@@ -365,10 +542,45 @@ static job_requeue_t send_interim(interim_data_t *data)
{
entry->interim.last = time_monotonic(NULL);
- bytes_in += entry->bytes.received;
- bytes_out += entry->bytes.sent;
- packets_in += entry->packets.received;
- packets_out += entry->packets.sent;
+ enumerator = array_create_enumerator(entry->cached);
+ while (enumerator->enumerate(enumerator, &sa))
+ {
+ if (array_bsearch(stats, sa, sa_find, &found) != -1)
+ {
+ /* SA is still around, update stats (e.g. for IKEv1 where
+ * SA might get used even after rekeying) */
+ sa->usage = found->usage;
+ }
+ else
+ {
+ /* SA is gone, add its last stats to the total for this IKE_SA
+ * and remove the cache entry */
+ add_usage(&entry->usage, sa->usage);
+ array_remove_at(entry->cached, enumerator);
+ free(sa);
+ }
+ }
+ enumerator->destroy(enumerator);
+
+ enumerator = array_create_enumerator(entry->migrated);
+ while (enumerator->enumerate(enumerator, &sa))
+ {
+ if (array_bsearch(stats, sa, sa_find, &found) != -1)
+ {
+ /* SA is still around, but we have to compensate */
+ sub_usage(&usage, sa->usage);
+ }
+ else
+ {
+ /* SA is gone, subtract stats from the total for this IKE_SA */
+ sub_usage(&entry->usage, sa->usage);
+ array_remove_at(entry->migrated, enumerator);
+ free(sa);
+ }
+ }
+ enumerator->destroy(enumerator);
+
+ add_usage(&usage, entry->usage);
message = radius_message_create(RMC_ACCOUNTING_REQUEST);
value = htonl(ACCT_STATUS_INTERIM_UPDATE);
@@ -377,26 +589,26 @@ static job_requeue_t send_interim(interim_data_t *data)
chunk_create(entry->sid, strlen(entry->sid)));
add_ike_sa_parameters(this, message, ike_sa);
- value = htonl(bytes_out);
+ value = htonl(usage.bytes.sent);
message->add(message, RAT_ACCT_OUTPUT_OCTETS, chunk_from_thing(value));
- value = htonl(bytes_out >> 32);
+ value = htonl(usage.bytes.sent >> 32);
if (value)
{
message->add(message, RAT_ACCT_OUTPUT_GIGAWORDS,
chunk_from_thing(value));
}
- value = htonl(packets_out);
+ value = htonl(usage.packets.sent);
message->add(message, RAT_ACCT_OUTPUT_PACKETS, chunk_from_thing(value));
- value = htonl(bytes_in);
+ value = htonl(usage.bytes.received);
message->add(message, RAT_ACCT_INPUT_OCTETS, chunk_from_thing(value));
- value = htonl(bytes_in >> 32);
+ value = htonl(usage.bytes.received >> 32);
if (value)
{
message->add(message, RAT_ACCT_INPUT_GIGAWORDS,
chunk_from_thing(value));
}
- value = htonl(packets_in);
+ value = htonl(usage.packets.received);
message->add(message, RAT_ACCT_INPUT_PACKETS, chunk_from_thing(value));
value = htonl(entry->interim.last - entry->created);
@@ -405,6 +617,7 @@ static job_requeue_t send_interim(interim_data_t *data)
schedule_interim(this, entry);
}
this->mutex->unlock(this->mutex);
+ array_destroy_function(stats, (void*)free, NULL);
if (message)
{
@@ -479,7 +692,8 @@ static void send_start(private_eap_radius_accounting_t *this, ike_sa_t *ike_sa)
this->mutex->lock(this->mutex);
- entry = get_or_create_entry(this, ike_sa);
+ entry = get_or_create_entry(this, ike_sa->get_id(ike_sa),
+ ike_sa->get_unique_id(ike_sa));
entry->start_sent = TRUE;
message = radius_message_create(RMC_ACCOUNTING_REQUEST);
@@ -515,7 +729,9 @@ static void send_start(private_eap_radius_accounting_t *this, ike_sa_t *ike_sa)
static void send_stop(private_eap_radius_accounting_t *this, ike_sa_t *ike_sa)
{
radius_message_t *message;
+ enumerator_t *enumerator;
entry_t *entry;
+ sa_entry_t *sa;
u_int32_t value;
this->mutex->lock(this->mutex);
@@ -528,6 +744,20 @@ static void send_stop(private_eap_radius_accounting_t *this, ike_sa_t *ike_sa)
destroy_entry(entry);
return;
}
+ enumerator = array_create_enumerator(entry->cached);
+ while (enumerator->enumerate(enumerator, &sa))
+ {
+ add_usage(&entry->usage, sa->usage);
+ }
+ enumerator->destroy(enumerator);
+
+ enumerator = array_create_enumerator(entry->migrated);
+ while (enumerator->enumerate(enumerator, &sa))
+ {
+ sub_usage(&entry->usage, sa->usage);
+ }
+ enumerator->destroy(enumerator);
+
message = radius_message_create(RMC_ACCOUNTING_REQUEST);
value = htonl(ACCT_STATUS_STOP);
message->add(message, RAT_ACCT_STATUS_TYPE, chunk_from_thing(value));
@@ -535,26 +765,26 @@ static void send_stop(private_eap_radius_accounting_t *this, ike_sa_t *ike_sa)
chunk_create(entry->sid, strlen(entry->sid)));
add_ike_sa_parameters(this, message, ike_sa);
- value = htonl(entry->bytes.sent);
+ value = htonl(entry->usage.bytes.sent);
message->add(message, RAT_ACCT_OUTPUT_OCTETS, chunk_from_thing(value));
- value = htonl(entry->bytes.sent >> 32);
+ value = htonl(entry->usage.bytes.sent >> 32);
if (value)
{
message->add(message, RAT_ACCT_OUTPUT_GIGAWORDS,
chunk_from_thing(value));
}
- value = htonl(entry->packets.sent);
+ value = htonl(entry->usage.packets.sent);
message->add(message, RAT_ACCT_OUTPUT_PACKETS, chunk_from_thing(value));
- value = htonl(entry->bytes.received);
+ value = htonl(entry->usage.bytes.received);
message->add(message, RAT_ACCT_INPUT_OCTETS, chunk_from_thing(value));
- value = htonl(entry->bytes.received >> 32);
+ value = htonl(entry->usage.bytes.received >> 32);
if (value)
{
message->add(message, RAT_ACCT_INPUT_GIGAWORDS,
chunk_from_thing(value));
}
- value = htonl(entry->packets.received);
+ value = htonl(entry->usage.packets.received);
message->add(message, RAT_ACCT_INPUT_PACKETS, chunk_from_thing(value));
value = htonl(time_monotonic(NULL) - entry->created);
@@ -660,6 +890,8 @@ METHOD(listener_t, ike_rekey, bool,
/* fire new interim update job, old gets invalid */
schedule_interim(this, entry);
+ cleanup_sas(this, new, entry);
+
entry = this->sessions->put(this->sessions, entry->id, entry);
if (entry)
{
@@ -675,8 +907,64 @@ METHOD(listener_t, child_rekey, bool,
private_eap_radius_accounting_t *this, ike_sa_t *ike_sa,
child_sa_t *old, child_sa_t *new)
{
+ entry_t *entry;
+
update_usage(this, ike_sa, old);
+ this->mutex->lock(this->mutex);
+ entry = this->sessions->get(this->sessions, ike_sa->get_id(ike_sa));
+ if (entry)
+ {
+ cleanup_sas(this, ike_sa, entry);
+ }
+ this->mutex->unlock(this->mutex);
+ return TRUE;
+}
+
+METHOD(listener_t, children_migrate, bool,
+ private_eap_radius_accounting_t *this, ike_sa_t *ike_sa, ike_sa_id_t *new,
+ u_int32_t unique)
+{
+ enumerator_t *enumerator;
+ sa_entry_t *sa, *sa_new, *cached;
+ entry_t *entry_old, *entry_new;
+ array_t *stats;
+ if (!new)
+ {
+ return TRUE;
+ }
+ stats = collect_stats(ike_sa, NULL);
+ this->mutex->lock(this->mutex);
+ entry_old = this->sessions->get(this->sessions, ike_sa->get_id(ike_sa));
+ if (entry_old)
+ {
+ entry_new = get_or_create_entry(this, new, unique);
+ enumerator = array_create_enumerator(stats);
+ while (enumerator->enumerate(enumerator, &sa))
+ {
+ /* if the SA was already rekeyed/cached we cache it too on the new
+ * SA to track it properly until it's finally gone */
+ if (array_bsearch(entry_old->cached, sa, sa_find, &cached) != -1)
+ {
+ sa_new = clone_sa(sa);
+ array_insert_create(&entry_new->cached, ARRAY_TAIL, sa_new);
+ array_sort(entry_new->cached, sa_sort, NULL);
+ }
+ /* if the SA was used, we store it to compensate on the new SA */
+ if (sa->usage.bytes.sent || sa->usage.bytes.received ||
+ sa->usage.packets.sent || sa->usage.packets.received)
+ {
+ sa_new = clone_sa(sa);
+ array_insert_create(&entry_new->migrated, ARRAY_TAIL, sa_new);
+ array_sort(entry_new->migrated, sa_sort, NULL);
+ /* store/update latest stats on old SA to report in Stop */
+ update_sa(entry_old, sa->id, sa->usage);
+ }
+ }
+ enumerator->destroy(enumerator);
+ }
+ this->mutex->unlock(this->mutex);
+ array_destroy_function(stats, (void*)free, NULL);
return TRUE;
}
@@ -717,6 +1005,7 @@ eap_radius_accounting_t *eap_radius_accounting_create()
.message = _message_hook,
.child_updown = _child_updown,
.child_rekey = _child_rekey,
+ .children_migrate = _children_migrate,
},
.destroy = _destroy,
},
@@ -759,7 +1048,8 @@ void eap_radius_accounting_start_interim(ike_sa_t *ike_sa, u_int32_t interval)
DBG1(DBG_CFG, "scheduling RADIUS Interim-Updates every %us", interval);
singleton->mutex->lock(singleton->mutex);
- entry = get_or_create_entry(singleton, ike_sa);
+ entry = get_or_create_entry(singleton, ike_sa->get_id(ike_sa),
+ ike_sa->get_unique_id(ike_sa));
entry->interim.interval = interval;
singleton->mutex->unlock(singleton->mutex);
}
diff --git a/src/libcharon/plugins/eap_sim/eap_sim_peer.c b/src/libcharon/plugins/eap_sim/eap_sim_peer.c
index ff96e9279..2637b4314 100644
--- a/src/libcharon/plugins/eap_sim/eap_sim_peer.c
+++ b/src/libcharon/plugins/eap_sim/eap_sim_peer.c
@@ -310,7 +310,7 @@ static status_t process_challenge(private_eap_sim_peer_t *this,
/* excepting two or three RAND, each 16 bytes. We require two valid
* and different RANDs */
if ((rands.len != 2 * SIM_RAND_LEN && rands.len != 3 * SIM_RAND_LEN) ||
- memeq(rands.ptr, rands.ptr + SIM_RAND_LEN, SIM_RAND_LEN))
+ memeq_const(rands.ptr, rands.ptr + SIM_RAND_LEN, SIM_RAND_LEN))
{
DBG1(DBG_IKE, "no valid AT_RAND received");
if (!create_client_error(this, SIM_INSUFFICIENT_CHALLENGES, out))
@@ -734,4 +734,3 @@ eap_sim_peer_t *eap_sim_peer_create(identification_t *server,
return &this->public;
}
-
diff --git a/src/libcharon/plugins/eap_sim/eap_sim_server.c b/src/libcharon/plugins/eap_sim/eap_sim_server.c
index f22266bda..5aa54db3e 100644
--- a/src/libcharon/plugins/eap_sim/eap_sim_server.c
+++ b/src/libcharon/plugins/eap_sim/eap_sim_server.c
@@ -262,7 +262,7 @@ static status_t process_reauthentication(private_eap_sim_server_t *this,
this->crypto->clear_keys(this->crypto);
return initiate(this, out);
}
- if (!chunk_equals(counter, this->counter))
+ if (!chunk_equals_const(counter, this->counter))
{
DBG1(DBG_IKE, "received counter does not match");
return FAILED;
@@ -644,4 +644,3 @@ eap_sim_server_t *eap_sim_server_create(identification_t *server,
return &this->public;
}
-
diff --git a/src/libcharon/plugins/eap_sim_file/eap_sim_file_card.c b/src/libcharon/plugins/eap_sim_file/eap_sim_file_card.c
index bd47e5085..0a6aec083 100644
--- a/src/libcharon/plugins/eap_sim_file/eap_sim_file_card.c
+++ b/src/libcharon/plugins/eap_sim_file/eap_sim_file_card.c
@@ -52,7 +52,7 @@ METHOD(simaka_card_t, get_triplet, bool,
c_rand, SIM_RAND_LEN, c_sres, SIM_SRES_LEN, c_kc, SIM_KC_LEN);
if (id->matches(id, cand))
{
- if (memeq(c_rand, rand, SIM_RAND_LEN))
+ if (memeq_const(c_rand, rand, SIM_RAND_LEN))
{
DBG2(DBG_CFG, " => triplet matches");
memcpy(sres, c_sres, SIM_SRES_LEN);
@@ -105,4 +105,3 @@ eap_sim_file_card_t *eap_sim_file_card_create(eap_sim_file_triplets_t *triplets)
return &this->public;
}
-
diff --git a/src/libcharon/plugins/ha/ha_cache.c b/src/libcharon/plugins/ha/ha_cache.c
index 6c1b3471d..0650f7fd9 100644
--- a/src/libcharon/plugins/ha/ha_cache.c
+++ b/src/libcharon/plugins/ha/ha_cache.c
@@ -43,6 +43,11 @@ struct private_ha_cache_t {
ha_socket_t *socket;
/**
+ * Tunnel securing sync messages
+ */
+ ha_tunnel_t *tunnel;
+
+ /**
* Total number of segments
*/
u_int count;
@@ -259,6 +264,10 @@ static void rekey_segment(private_ha_cache_t *this, u_int segment)
charon->ike_sa_manager, TRUE);
while (enumerator->enumerate(enumerator, &ike_sa))
{
+ if (this->tunnel && this->tunnel->is_sa(this->tunnel, ike_sa))
+ {
+ continue;
+ }
if (ike_sa->get_state(ike_sa) == IKE_ESTABLISHED &&
this->kernel->get_segment(this->kernel,
ike_sa->get_other_host(ike_sa)) == segment)
@@ -365,7 +374,7 @@ METHOD(ha_cache_t, destroy, void,
* See header
*/
ha_cache_t *ha_cache_create(ha_kernel_t *kernel, ha_socket_t *socket,
- bool sync, u_int count)
+ ha_tunnel_t *tunnel, bool sync, u_int count)
{
private_ha_cache_t *this;
@@ -379,6 +388,7 @@ ha_cache_t *ha_cache_create(ha_kernel_t *kernel, ha_socket_t *socket,
.count = count,
.kernel = kernel,
.socket = socket,
+ .tunnel = tunnel,
.cache = hashtable_create(hashtable_hash_ptr, hashtable_equals_ptr, 8),
.mutex = mutex_create(MUTEX_TYPE_DEFAULT),
);
diff --git a/src/libcharon/plugins/ha/ha_cache.h b/src/libcharon/plugins/ha/ha_cache.h
index 5e3936a20..8cfcbb24c 100644
--- a/src/libcharon/plugins/ha/ha_cache.h
+++ b/src/libcharon/plugins/ha/ha_cache.h
@@ -69,10 +69,11 @@ struct ha_cache_t {
*
* @param kernel kernel helper
* @param socket socket to send resync messages
+ * @param tunnel HA tunnel
* @param resync request a resync during startup?
* @param count total number of segments
*/
ha_cache_t *ha_cache_create(ha_kernel_t *kernel, ha_socket_t *socket,
- bool resync, u_int count);
+ ha_tunnel_t *tunnel, bool resync, u_int count);
#endif /** HA_CACHE_H_ @}*/
diff --git a/src/libcharon/plugins/ha/ha_plugin.c b/src/libcharon/plugins/ha/ha_plugin.c
index a58377bab..037b69bac 100644
--- a/src/libcharon/plugins/ha/ha_plugin.c
+++ b/src/libcharon/plugins/ha/ha_plugin.c
@@ -97,13 +97,73 @@ METHOD(plugin_t, get_name, char*,
}
/**
- * Register listener
+ * Initialize plugin
+ */
+static bool initialize_plugin(private_ha_plugin_t *this)
+{
+ char *local, *remote, *secret;
+ u_int count;
+ bool fifo, monitor, resync;
+
+ local = lib->settings->get_str(lib->settings,
+ "%s.plugins.ha.local", NULL, lib->ns);
+ remote = lib->settings->get_str(lib->settings,
+ "%s.plugins.ha.remote", NULL, lib->ns);
+ secret = lib->settings->get_str(lib->settings,
+ "%s.plugins.ha.secret", NULL, lib->ns);
+ fifo = lib->settings->get_bool(lib->settings,
+ "%s.plugins.ha.fifo_interface", TRUE, lib->ns);
+ monitor = lib->settings->get_bool(lib->settings,
+ "%s.plugins.ha.monitor", TRUE, lib->ns);
+ resync = lib->settings->get_bool(lib->settings,
+ "%s.plugins.ha.resync", TRUE, lib->ns);
+ count = min(SEGMENTS_MAX, lib->settings->get_int(lib->settings,
+ "%s.plugins.ha.segment_count", 1, lib->ns));
+ if (!local || !remote)
+ {
+ DBG1(DBG_CFG, "HA config misses local/remote address");
+ return FALSE;
+ }
+
+ if (secret)
+ {
+ this->tunnel = ha_tunnel_create(local, remote, secret);
+ }
+ this->socket = ha_socket_create(local, remote);
+ if (!this->socket)
+ {
+ return FALSE;
+ }
+ this->kernel = ha_kernel_create(count);
+ this->segments = ha_segments_create(this->socket, this->kernel, this->tunnel,
+ count, strcmp(local, remote) > 0, monitor);
+ this->cache = ha_cache_create(this->kernel, this->socket, this->tunnel,
+ resync, count);
+ if (fifo)
+ {
+ this->ctl = ha_ctl_create(this->segments, this->cache);
+ }
+ this->attr = ha_attribute_create(this->kernel, this->segments);
+ this->dispatcher = ha_dispatcher_create(this->socket, this->segments,
+ this->cache, this->kernel, this->attr);
+ this->ike = ha_ike_create(this->socket, this->tunnel, this->cache);
+ this->child = ha_child_create(this->socket, this->tunnel, this->segments,
+ this->kernel);
+ return TRUE;
+}
+
+/**
+ * Initialize plugin and register listener
*/
static bool plugin_cb(private_ha_plugin_t *this,
plugin_feature_t *feature, bool reg, void *cb_data)
{
if (reg)
{
+ if (!initialize_plugin(this))
+ {
+ return FALSE;
+ }
charon->bus->add_listener(charon->bus, &this->segments->listener);
charon->bus->add_listener(charon->bus, &this->ike->listener);
charon->bus->add_listener(charon->bus, &this->child->listener);
@@ -127,6 +187,7 @@ METHOD(plugin_t, get_features, int,
static plugin_feature_t f[] = {
PLUGIN_CALLBACK((plugin_feature_callback_t)plugin_cb, NULL),
PLUGIN_PROVIDE(CUSTOM, "ha"),
+ PLUGIN_SDEPEND(CUSTOM, "kernel-ipsec"),
};
*features = f;
return countof(f);
@@ -136,14 +197,14 @@ METHOD(plugin_t, destroy, void,
private_ha_plugin_t *this)
{
DESTROY_IF(this->ctl);
- this->ike->destroy(this->ike);
- this->child->destroy(this->child);
- this->dispatcher->destroy(this->dispatcher);
- this->attr->destroy(this->attr);
- this->cache->destroy(this->cache);
- this->segments->destroy(this->segments);
- this->kernel->destroy(this->kernel);
- this->socket->destroy(this->socket);
+ DESTROY_IF(this->ike);
+ DESTROY_IF(this->child);
+ DESTROY_IF(this->dispatcher);
+ DESTROY_IF(this->attr);
+ DESTROY_IF(this->cache);
+ DESTROY_IF(this->segments);
+ DESTROY_IF(this->kernel);
+ DESTROY_IF(this->socket);
DESTROY_IF(this->tunnel);
free(this);
}
@@ -154,29 +215,6 @@ METHOD(plugin_t, destroy, void,
plugin_t *ha_plugin_create()
{
private_ha_plugin_t *this;
- char *local, *remote, *secret;
- u_int count;
- bool fifo, monitor, resync;
-
- local = lib->settings->get_str(lib->settings,
- "%s.plugins.ha.local", NULL, lib->ns);
- remote = lib->settings->get_str(lib->settings,
- "%s.plugins.ha.remote", NULL, lib->ns);
- secret = lib->settings->get_str(lib->settings,
- "%s.plugins.ha.secret", NULL, lib->ns);
- fifo = lib->settings->get_bool(lib->settings,
- "%s.plugins.ha.fifo_interface", TRUE, lib->ns);
- monitor = lib->settings->get_bool(lib->settings,
- "%s.plugins.ha.monitor", TRUE, lib->ns);
- resync = lib->settings->get_bool(lib->settings,
- "%s.plugins.ha.resync", TRUE, lib->ns);
- count = min(SEGMENTS_MAX, lib->settings->get_int(lib->settings,
- "%s.plugins.ha.segment_count", 1, lib->ns));
- if (!local || !remote)
- {
- DBG1(DBG_CFG, "HA config misses local/remote address");
- return NULL;
- }
if (!lib->caps->keep(lib->caps, CAP_CHOWN))
{ /* required to chown(2) control socket, ha_kernel also needs it at
@@ -195,31 +233,5 @@ plugin_t *ha_plugin_create()
},
);
- if (secret)
- {
- this->tunnel = ha_tunnel_create(local, remote, secret);
- }
- this->socket = ha_socket_create(local, remote);
- if (!this->socket)
- {
- DESTROY_IF(this->tunnel);
- free(this);
- return NULL;
- }
- this->kernel = ha_kernel_create(count);
- this->segments = ha_segments_create(this->socket, this->kernel, this->tunnel,
- count, strcmp(local, remote) > 0, monitor);
- this->cache = ha_cache_create(this->kernel, this->socket, resync, count);
- if (fifo)
- {
- this->ctl = ha_ctl_create(this->segments, this->cache);
- }
- this->attr = ha_attribute_create(this->kernel, this->segments);
- this->dispatcher = ha_dispatcher_create(this->socket, this->segments,
- this->cache, this->kernel, this->attr);
- this->ike = ha_ike_create(this->socket, this->tunnel, this->cache);
- this->child = ha_child_create(this->socket, this->tunnel, this->segments,
- this->kernel);
-
return &this->public.plugin;
}
diff --git a/src/libcharon/plugins/vici/libvici.h b/src/libcharon/plugins/vici/libvici.h
index 641370efd..3ca9de424 100644
--- a/src/libcharon/plugins/vici/libvici.h
+++ b/src/libcharon/plugins/vici/libvici.h
@@ -2,15 +2,26 @@
* Copyright (C) 2014 Martin Willi
* Copyright (C) 2014 revosec AG
*
- * This program is free software; you can redistribute it and/or modify it
- * under the terms of the GNU General Public License as published by the
- * Free Software Foundation; either version 2 of the License, or (at your
- * option) any later version. See <http://www.fsf.org/copyleft/gpl.txt>.
- *
- * This program is distributed in the hope that it will be useful, but
- * WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY
- * or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License
- * for more details.
+ * libvici.h is MIT-licensed to simplify reuse, but please note that libvici.c
+ * is not, as it depends on the GPLv2 licensed libstrongswan.
+ *
+ * Permission is hereby granted, free of charge, to any person obtaining a copy
+ * of this software and associated documentation files (the "Software"), to deal
+ * in the Software without restriction, including without limitation the rights
+ * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
+ * copies of the Software, and to permit persons to whom the Software is
+ * furnished to do so, subject to the following conditions:
+ *
+ * The above copyright notice and this permission notice shall be included in
+ * all copies or substantial portions of the Software.
+ *
+ * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
+ * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
+ * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
+ * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
+ * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
+ * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
+ * THE SOFTWARE.
*/
/**
diff --git a/src/libcharon/plugins/vici/python/Makefile.am b/src/libcharon/plugins/vici/python/Makefile.am
index f51737870..5936f2a5e 100644
--- a/src/libcharon/plugins/vici/python/Makefile.am
+++ b/src/libcharon/plugins/vici/python/Makefile.am
@@ -8,25 +8,27 @@ EXTRA_DIST = LICENSE MANIFEST.in \
vici/protocol.py \
vici/session.py
-setup.py: $(srcdir)/setup.py.in
+$(srcdir)/setup.py: $(srcdir)/setup.py.in
$(AM_V_GEN) sed \
-e "s:@EGG_VERSION@:$(PACKAGE_VERSION):" \
$(srcdir)/setup.py.in > $@
all-local: dist/vici-$(PACKAGE_VERSION)-py$(PYTHON_VERSION).egg
-dist/vici-$(PACKAGE_VERSION)-py$(PYTHON_VERSION).egg: $(EXTRA_DIST) setup.py
+dist/vici-$(PACKAGE_VERSION)-py$(PYTHON_VERSION).egg: $(EXTRA_DIST) $(srcdir)/setup.py
(cd $(srcdir); $(PYTHON) setup.py bdist_egg \
-b $(shell readlink -f $(builddir))/build \
-d $(shell readlink -f $(builddir))/dist)
-clean-local: setup.py
- $(PYTHON) setup.py clean -a
- rm -rf vici.egg-info dist setup.py
+clean-local:
+ (cd $(srcdir); [ ! -f setup.py ] || $(PYTHON) setup.py clean -a)
+ rm -rf $(srcdir)/setup.py $(srcdir)/vici.egg-info $(builddir)/dist
+if PYTHON_EGGS_INSTALL
install-exec-local: dist/vici-$(PACKAGE_VERSION)-py$(PYTHON_VERSION).egg
$(EASY_INSTALL) $(PYTHONEGGINSTALLDIR) \
dist/vici-$(PACKAGE_VERSION)-py$(PYTHON_VERSION).egg
+endif
if USE_PY_TEST
TESTS = $(PY_TEST)
diff --git a/src/libcharon/plugins/vici/python/Makefile.in b/src/libcharon/plugins/vici/python/Makefile.in
index 3a5e5ea72..eb4bab6ca 100644
--- a/src/libcharon/plugins/vici/python/Makefile.in
+++ b/src/libcharon/plugins/vici/python/Makefile.in
@@ -579,6 +579,7 @@ distclean-generic:
maintainer-clean-generic:
@echo "This command is intended for maintainers to use"
@echo "it deletes files that may require special tools to rebuild."
+@PYTHON_EGGS_INSTALL_FALSE@install-exec-local:
clean: clean-am
clean-am: clean-generic clean-libtool clean-local mostlyclean-am
@@ -661,25 +662,25 @@ uninstall-am:
tags-am uninstall uninstall-am
-setup.py: $(srcdir)/setup.py.in
+$(srcdir)/setup.py: $(srcdir)/setup.py.in
$(AM_V_GEN) sed \
-e "s:@EGG_VERSION@:$(PACKAGE_VERSION):" \
$(srcdir)/setup.py.in > $@
all-local: dist/vici-$(PACKAGE_VERSION)-py$(PYTHON_VERSION).egg
-dist/vici-$(PACKAGE_VERSION)-py$(PYTHON_VERSION).egg: $(EXTRA_DIST) setup.py
+dist/vici-$(PACKAGE_VERSION)-py$(PYTHON_VERSION).egg: $(EXTRA_DIST) $(srcdir)/setup.py
(cd $(srcdir); $(PYTHON) setup.py bdist_egg \
-b $(shell readlink -f $(builddir))/build \
-d $(shell readlink -f $(builddir))/dist)
-clean-local: setup.py
- $(PYTHON) setup.py clean -a
- rm -rf vici.egg-info dist setup.py
+clean-local:
+ (cd $(srcdir); [ ! -f setup.py ] || $(PYTHON) setup.py clean -a)
+ rm -rf $(srcdir)/setup.py $(srcdir)/vici.egg-info $(builddir)/dist
-install-exec-local: dist/vici-$(PACKAGE_VERSION)-py$(PYTHON_VERSION).egg
- $(EASY_INSTALL) $(PYTHONEGGINSTALLDIR) \
- dist/vici-$(PACKAGE_VERSION)-py$(PYTHON_VERSION).egg
+@PYTHON_EGGS_INSTALL_TRUE@install-exec-local: dist/vici-$(PACKAGE_VERSION)-py$(PYTHON_VERSION).egg
+@PYTHON_EGGS_INSTALL_TRUE@ $(EASY_INSTALL) $(PYTHONEGGINSTALLDIR) \
+@PYTHON_EGGS_INSTALL_TRUE@ dist/vici-$(PACKAGE_VERSION)-py$(PYTHON_VERSION).egg
# Tell versions [3.59,3.63) of GNU make to not export all variables.
# Otherwise a system limit (for SysV at least) may be exceeded.
diff --git a/src/libcharon/plugins/vici/ruby/Makefile.am b/src/libcharon/plugins/vici/ruby/Makefile.am
index 3e12f86cc..e2d340431 100644
--- a/src/libcharon/plugins/vici/ruby/Makefile.am
+++ b/src/libcharon/plugins/vici/ruby/Makefile.am
@@ -15,10 +15,12 @@ all-local: vici-$(PACKAGE_VERSION).gem
clean-local:
rm -f vici.gemspec vici-$(PACKAGE_VERSION).gem
+if RUBY_GEMS_INSTALL
install-data-local: vici-$(PACKAGE_VERSION).gem
- $(GEM) install --install-dir $(DESTDIR)$(RUBYGEMDIR) \
+ $(GEM) install --no-user-install --install-dir $(DESTDIR)$(RUBYGEMDIR) \
vici-$(PACKAGE_VERSION).gem
uninstall-local:
$(GEM) uninstall --install-dir $(DESTDIR)$(RUBYGEMDIR) \
--version $(PACKAGE_VERSION) vici
+endif
diff --git a/src/libcharon/plugins/vici/ruby/Makefile.in b/src/libcharon/plugins/vici/ruby/Makefile.in
index f37c09ea2..bf81e5395 100644
--- a/src/libcharon/plugins/vici/ruby/Makefile.in
+++ b/src/libcharon/plugins/vici/ruby/Makefile.in
@@ -453,6 +453,8 @@ distclean-generic:
maintainer-clean-generic:
@echo "This command is intended for maintainers to use"
@echo "it deletes files that may require special tools to rebuild."
+@RUBY_GEMS_INSTALL_FALSE@uninstall-local:
+@RUBY_GEMS_INSTALL_FALSE@install-data-local:
clean: clean-am
clean-am: clean-generic clean-libtool clean-local mostlyclean-am
@@ -550,13 +552,13 @@ all-local: vici-$(PACKAGE_VERSION).gem
clean-local:
rm -f vici.gemspec vici-$(PACKAGE_VERSION).gem
-install-data-local: vici-$(PACKAGE_VERSION).gem
- $(GEM) install --install-dir $(DESTDIR)$(RUBYGEMDIR) \
- vici-$(PACKAGE_VERSION).gem
+@RUBY_GEMS_INSTALL_TRUE@install-data-local: vici-$(PACKAGE_VERSION).gem
+@RUBY_GEMS_INSTALL_TRUE@ $(GEM) install --no-user-install --install-dir $(DESTDIR)$(RUBYGEMDIR) \
+@RUBY_GEMS_INSTALL_TRUE@ vici-$(PACKAGE_VERSION).gem
-uninstall-local:
- $(GEM) uninstall --install-dir $(DESTDIR)$(RUBYGEMDIR) \
- --version $(PACKAGE_VERSION) vici
+@RUBY_GEMS_INSTALL_TRUE@uninstall-local:
+@RUBY_GEMS_INSTALL_TRUE@ $(GEM) uninstall --install-dir $(DESTDIR)$(RUBYGEMDIR) \
+@RUBY_GEMS_INSTALL_TRUE@ --version $(PACKAGE_VERSION) vici
# Tell versions [3.59,3.63) of GNU make to not export all variables.
# Otherwise a system limit (for SysV at least) may be exceeded.
diff --git a/src/libcharon/plugins/vici/vici_config.c b/src/libcharon/plugins/vici/vici_config.c
index 649161020..d23259912 100644
--- a/src/libcharon/plugins/vici/vici_config.c
+++ b/src/libcharon/plugins/vici/vici_config.c
@@ -13,6 +13,28 @@
* for more details.
*/
+/*
+ * Copyright (C) 2014 Timo Teräs <timo.teras@iki.fi>
+ *
+ * Permission is hereby granted, free of charge, to any person obtaining a copy
+ * of this software and associated documentation files (the "Software"), to deal
+ * in the Software without restriction, including without limitation the rights
+ * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
+ * copies of the Software, and to permit persons to whom the Software is
+ * furnished to do so, subject to the following conditions:
+ *
+ * The above copyright notice and this permission notice shall be included in
+ * all copies or substantial portions of the Software.
+ *
+ * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
+ * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
+ * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
+ * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
+ * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
+ * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
+ * THE SOFTWARE.
+ */
+
#define _GNU_SOURCE
#include "vici_config.h"
@@ -1460,6 +1482,21 @@ CALLBACK(peer_sn, bool,
return FALSE;
}
+ if (!auth.cfg->get(auth.cfg, AUTH_RULE_IDENTITY))
+ {
+ identification_t *id;
+ certificate_t *cert;
+
+ cert = auth.cfg->get(auth.cfg, AUTH_RULE_SUBJECT_CERT);
+ if (cert)
+ {
+ id = cert->get_subject(cert);
+ DBG1(DBG_CFG, " id not specified, defaulting to cert id '%Y'",
+ id);
+ auth.cfg->add(auth.cfg, AUTH_RULE_IDENTITY, id->clone(id));
+ }
+ }
+
if (strcasepfx(name, "local"))
{
peer->local->insert_last(peer->local, auth.cfg);
diff --git a/src/libcharon/plugins/vici/vici_dispatcher.c b/src/libcharon/plugins/vici/vici_dispatcher.c
index 6db36fbe0..31292d6b3 100644
--- a/src/libcharon/plugins/vici/vici_dispatcher.c
+++ b/src/libcharon/plugins/vici/vici_dispatcher.c
@@ -13,6 +13,28 @@
* for more details.
*/
+/*
+ * Copyright (C) 2014 Timo Teräs <timo.teras@iki.fi>
+ *
+ * Permission is hereby granted, free of charge, to any person obtaining a copy
+ * of this software and associated documentation files (the "Software"), to deal
+ * in the Software without restriction, including without limitation the rights
+ * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
+ * copies of the Software, and to permit persons to whom the Software is
+ * furnished to do so, subject to the following conditions:
+ *
+ * The above copyright notice and this permission notice shall be included in
+ * all copies or substantial portions of the Software.
+ *
+ * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
+ * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
+ * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
+ * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
+ * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
+ * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
+ * THE SOFTWARE.
+ */
+
#include "vici_dispatcher.h"
#include "vici_socket.h"
@@ -446,6 +468,24 @@ METHOD(vici_dispatcher_t, manage_event, void,
this->mutex->unlock(this->mutex);
}
+METHOD(vici_dispatcher_t, has_event_listeners, bool,
+ private_vici_dispatcher_t *this, char *name)
+{
+ bool retval = FALSE;
+
+ this->mutex->lock(this->mutex);
+ if (this->events->get(this->events, name))
+ {
+ /* the entry might be getting destroyed, but returning
+ * false positive is not a problem as a later raise_event
+ * will check things again. */
+ retval = TRUE;
+ }
+ this->mutex->unlock(this->mutex);
+
+ return retval;
+}
+
METHOD(vici_dispatcher_t, raise_event, void,
private_vici_dispatcher_t *this, char *name, u_int id,
vici_message_t *message)
@@ -504,6 +544,7 @@ vici_dispatcher_t *vici_dispatcher_create(char *uri)
.public = {
.manage_command = _manage_command,
.manage_event = _manage_event,
+ .has_event_listeners = _has_event_listeners,
.raise_event = _raise_event,
.destroy = _destroy,
},
diff --git a/src/libcharon/plugins/vici/vici_dispatcher.h b/src/libcharon/plugins/vici/vici_dispatcher.h
index 2297a80bd..e48cf3bd1 100644
--- a/src/libcharon/plugins/vici/vici_dispatcher.h
+++ b/src/libcharon/plugins/vici/vici_dispatcher.h
@@ -13,6 +13,28 @@
* for more details.
*/
+/*
+ * Copyright (C) 2014 Timo Teräs <timo.teras@iki.fi>
+ *
+ * Permission is hereby granted, free of charge, to any person obtaining a copy
+ * of this software and associated documentation files (the "Software"), to deal
+ * in the Software without restriction, including without limitation the rights
+ * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
+ * copies of the Software, and to permit persons to whom the Software is
+ * furnished to do so, subject to the following conditions:
+ *
+ * The above copyright notice and this permission notice shall be included in
+ * all copies or substantial portions of the Software.
+ *
+ * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
+ * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
+ * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
+ * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
+ * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
+ * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
+ * THE SOFTWARE.
+ */
+
/**
* @defgroup vici_dispatcher vici_dispatcher
* @{ @ingroup vici
@@ -96,6 +118,17 @@ struct vici_dispatcher_t {
void (*manage_event)(vici_dispatcher_t *this, char *name, bool reg);
/**
+ * Check if an event has listeners.
+ *
+ * This can be used to check if a vici message needs to be generated or not,
+ * as in some cases the generation can be a heavy operation.
+ *
+ * @param name event name to check
+ * @return TRUE if event has listeners
+ */
+ bool (*has_event_listeners)(vici_dispatcher_t *this, char *name);
+
+ /**
* Raise an event to a specific or all clients registered to that event.
*
* @param name event name to raise
diff --git a/src/libcharon/plugins/vici/vici_plugin.c b/src/libcharon/plugins/vici/vici_plugin.c
index af8bd283b..7ae58a317 100644
--- a/src/libcharon/plugins/vici/vici_plugin.c
+++ b/src/libcharon/plugins/vici/vici_plugin.c
@@ -13,6 +13,28 @@
* for more details.
*/
+/*
+ * Copyright (C) 2014 Timo Teräs <timo.teras@iki.fi>
+ *
+ * Permission is hereby granted, free of charge, to any person obtaining a copy
+ * of this software and associated documentation files (the "Software"), to deal
+ * in the Software without restriction, including without limitation the rights
+ * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
+ * copies of the Software, and to permit persons to whom the Software is
+ * furnished to do so, subject to the following conditions:
+ *
+ * The above copyright notice and this permission notice shall be included in
+ * all copies or substantial portions of the Software.
+ *
+ * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
+ * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
+ * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
+ * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
+ * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
+ * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
+ * THE SOFTWARE.
+ */
+
#include "vici_plugin.h"
#include "vici_dispatcher.h"
#include "vici_query.h"
@@ -106,12 +128,14 @@ static bool register_vici(private_vici_plugin_t *this,
charon->attributes->add_provider(charon->attributes,
&this->attrs->provider);
charon->bus->add_logger(charon->bus, &this->logger->logger);
+ charon->bus->add_listener(charon->bus, &this->query->listener);
return TRUE;
}
return FALSE;
}
else
{
+ charon->bus->remove_listener(charon->bus, &this->query->listener);
charon->bus->remove_logger(charon->bus, &this->logger->logger);
charon->attributes->remove_provider(charon->attributes,
&this->attrs->provider);
diff --git a/src/libcharon/plugins/vici/vici_query.c b/src/libcharon/plugins/vici/vici_query.c
index 3e0d73cdf..d94d760b9 100644
--- a/src/libcharon/plugins/vici/vici_query.c
+++ b/src/libcharon/plugins/vici/vici_query.c
@@ -13,6 +13,28 @@
* for more details.
*/
+/*
+ * Copyright (C) 2014 Timo Teräs <timo.teras@iki.fi>
+ *
+ * Permission is hereby granted, free of charge, to any person obtaining a copy
+ * of this software and associated documentation files (the "Software"), to deal
+ * in the Software without restriction, including without limitation the rights
+ * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
+ * copies of the Software, and to permit persons to whom the Software is
+ * furnished to do so, subject to the following conditions:
+ *
+ * The above copyright notice and this permission notice shall be included in
+ * all copies or substantial portions of the Software.
+ *
+ * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
+ * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
+ * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
+ * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
+ * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
+ * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
+ * THE SOFTWARE.
+ */
+
#include "vici_query.h"
#include "vici_builder.h"
@@ -1008,6 +1030,8 @@ static void manage_commands(private_vici_query_t *this, bool reg)
this->dispatcher->manage_event(this->dispatcher, "list-policy", reg);
this->dispatcher->manage_event(this->dispatcher, "list-conn", reg);
this->dispatcher->manage_event(this->dispatcher, "list-cert", reg);
+ this->dispatcher->manage_event(this->dispatcher, "ike-updown", reg);
+ this->dispatcher->manage_event(this->dispatcher, "child-updown", reg);
manage_command(this, "list-sas", list_sas, reg);
manage_command(this, "list-policies", list_policies, reg);
manage_command(this, "list-conns", list_conns, reg);
@@ -1016,6 +1040,63 @@ static void manage_commands(private_vici_query_t *this, bool reg)
manage_command(this, "stats", stats, reg);
}
+METHOD(listener_t, ike_updown, bool,
+ private_vici_query_t *this, ike_sa_t *ike_sa, bool up)
+{
+ vici_builder_t *b;
+ time_t now;
+
+ if (!this->dispatcher->has_event_listeners(this->dispatcher, "ike-updown"))
+ {
+ return TRUE;
+ }
+
+ now = time_monotonic(NULL);
+
+ b = vici_builder_create();
+ b->begin_section(b, ike_sa->get_name(ike_sa));
+ list_ike(this, b, ike_sa, now);
+ b->begin_section(b, "child-sas");
+ b->end_section(b);
+ b->end_section(b);
+
+ this->dispatcher->raise_event(this->dispatcher,
+ "ike-updown", 0, b->finalize(b));
+
+ return TRUE;
+}
+
+METHOD(listener_t, child_updown, bool,
+ private_vici_query_t *this, ike_sa_t *ike_sa, child_sa_t *child_sa, bool up)
+{
+ vici_builder_t *b;
+ time_t now;
+
+ if (!this->dispatcher->has_event_listeners(this->dispatcher, "child-updown"))
+ {
+ return TRUE;
+ }
+
+ now = time_monotonic(NULL);
+ b = vici_builder_create();
+
+ b->begin_section(b, ike_sa->get_name(ike_sa));
+ list_ike(this, b, ike_sa, now);
+ b->begin_section(b, "child-sas");
+
+ b->begin_section(b, child_sa->get_name(child_sa));
+ list_child(this, b, child_sa, now);
+ b->end_section(b);
+
+ b->end_section(b);
+ b->end_section(b);
+
+ this->dispatcher->raise_event(this->dispatcher,
+ "child-updown", 0, b->finalize(b));
+
+ return TRUE;
+}
+
METHOD(vici_query_t, destroy, void,
private_vici_query_t *this)
{
@@ -1032,6 +1113,10 @@ vici_query_t *vici_query_create(vici_dispatcher_t *dispatcher)
INIT(this,
.public = {
+ .listener = {
+ .ike_updown = _ike_updown,
+ .child_updown = _child_updown,
+ },
.destroy = _destroy,
},
.dispatcher = dispatcher,
diff --git a/src/libcharon/plugins/vici/vici_query.h b/src/libcharon/plugins/vici/vici_query.h
index da72b1411..0149e8d4f 100644
--- a/src/libcharon/plugins/vici/vici_query.h
+++ b/src/libcharon/plugins/vici/vici_query.h
@@ -13,11 +13,34 @@
* for more details.
*/
+/*
+ * Copyright (C) 2014 Timo Teräs <timo.teras@iki.fi>
+ *
+ * Permission is hereby granted, free of charge, to any person obtaining a copy
+ * of this software and associated documentation files (the "Software"), to deal
+ * in the Software without restriction, including without limitation the rights
+ * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
+ * copies of the Software, and to permit persons to whom the Software is
+ * furnished to do so, subject to the following conditions:
+ *
+ * The above copyright notice and this permission notice shall be included in
+ * all copies or substantial portions of the Software.
+ *
+ * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
+ * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
+ * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
+ * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
+ * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
+ * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
+ * THE SOFTWARE.
+ */
+
/**
* @defgroup vici_query vici_query
* @{ @ingroup vici
*/
+#include <bus/listeners/listener.h>
#include "vici_dispatcher.h"
#ifndef VICI_QUERY_H_
@@ -31,6 +54,11 @@ typedef struct vici_query_t vici_query_t;
struct vici_query_t {
/**
+ * Implements listener_t.
+ */
+ listener_t listener;
+
+ /**
* Destroy a vici_query_t.
*/
void (*destroy)(vici_query_t *this);
diff --git a/src/libcharon/plugins/vici/vici_socket.c b/src/libcharon/plugins/vici/vici_socket.c
index 916772871..67fd7e8e3 100644
--- a/src/libcharon/plugins/vici/vici_socket.c
+++ b/src/libcharon/plugins/vici/vici_socket.c
@@ -118,6 +118,8 @@ typedef struct {
array_t *queue;
/** do we have job processing input queue? */
bool has_processor;
+ /** is this client disconnecting */
+ bool disconnecting;
/** client connection identifier */
u_int id;
/** any users reading over this connection? */
@@ -187,6 +189,10 @@ static entry_t* find_entry(private_vici_socket_t *this, stream_t *stream,
continue;
}
}
+ if (entry->disconnecting)
+ {
+ continue;
+ }
candidate = TRUE;
if ((reader && entry->readers) ||
@@ -304,7 +310,7 @@ static void disconnect(private_vici_socket_t *this, u_int id)
* Write queued output data
*/
static bool do_write(private_vici_socket_t *this, entry_t *entry,
- stream_t *stream)
+ stream_t *stream, char *errmsg, size_t errlen)
{
msg_buf_t *out;
ssize_t len;
@@ -326,7 +332,8 @@ static bool do_write(private_vici_socket_t *this, entry_t *entry,
{
return TRUE;
}
- DBG1(DBG_CFG, "vici header write error: %s", strerror(errno));
+ snprintf(errmsg, errlen, "vici header write error: %s",
+ strerror(errno));
return FALSE;
}
out->hdrlen += len;
@@ -339,7 +346,7 @@ static bool do_write(private_vici_socket_t *this, entry_t *entry,
out->buf.len - out->done, FALSE);
if (len == 0)
{
- DBG1(DBG_CFG, "premature vici disconnect");
+ snprintf(errmsg, errlen, "premature vici disconnect");
return FALSE;
}
if (len < 0)
@@ -348,7 +355,7 @@ static bool do_write(private_vici_socket_t *this, entry_t *entry,
{
return TRUE;
}
- DBG1(DBG_CFG, "vici write error: %s", strerror(errno));
+ snprintf(errmsg, errlen, "vici write error: %s", strerror(errno));
return FALSE;
}
out->done += len;
@@ -369,13 +376,14 @@ static bool do_write(private_vici_socket_t *this, entry_t *entry,
CALLBACK(on_write, bool,
private_vici_socket_t *this, stream_t *stream)
{
+ char errmsg[256] = "";
entry_t *entry;
bool ret = FALSE;
entry = find_entry(this, stream, 0, FALSE, TRUE);
if (entry)
{
- ret = do_write(this, entry, stream);
+ ret = do_write(this, entry, stream, errmsg, sizeof(errmsg));
if (ret)
{
/* unregister if we have no more messages to send */
@@ -383,9 +391,15 @@ CALLBACK(on_write, bool,
}
else
{
+ entry->disconnecting = TRUE;
disconnect(entry->this, entry->id);
}
put_entry(this, entry, FALSE, TRUE);
+
+ if (!ret && errmsg[0])
+ {
+ DBG1(DBG_CFG, errmsg);
+ }
}
return ret;
@@ -395,7 +409,7 @@ CALLBACK(on_write, bool,
* Read in available header with data, non-blocking cumulating to buffer
*/
static bool do_read(private_vici_socket_t *this, entry_t *entry,
- stream_t *stream)
+ stream_t *stream, char *errmsg, size_t errlen)
{
u_int32_t msglen;
ssize_t len;
@@ -415,7 +429,8 @@ static bool do_read(private_vici_socket_t *this, entry_t *entry,
{
return TRUE;
}
- DBG1(DBG_CFG, "vici header read error: %s", strerror(errno));
+ snprintf(errmsg, errlen, "vici header read error: %s",
+ strerror(errno));
return FALSE;
}
entry->in.hdrlen += len;
@@ -424,8 +439,8 @@ static bool do_read(private_vici_socket_t *this, entry_t *entry,
msglen = untoh32(entry->in.hdr);
if (msglen > VICI_MESSAGE_SIZE_MAX)
{
- DBG1(DBG_CFG, "vici message length %u exceeds %u bytes limit, "
- "ignored", msglen, VICI_MESSAGE_SIZE_MAX);
+ snprintf(errmsg, errlen, "vici message length %u exceeds %u "
+ "bytes limit, ignored", msglen, VICI_MESSAGE_SIZE_MAX);
return FALSE;
}
/* header complete, continue with data */
@@ -440,7 +455,7 @@ static bool do_read(private_vici_socket_t *this, entry_t *entry,
entry->in.buf.len - entry->in.done, FALSE);
if (len == 0)
{
- DBG1(DBG_CFG, "premature vici disconnect");
+ snprintf(errmsg, errlen, "premature vici disconnect");
return FALSE;
}
if (len < 0)
@@ -449,7 +464,7 @@ static bool do_read(private_vici_socket_t *this, entry_t *entry,
{
return TRUE;
}
- DBG1(DBG_CFG, "vici read error: %s", strerror(errno));
+ snprintf(errmsg, errlen, "vici read error: %s", strerror(errno));
return FALSE;
}
entry->in.done += len;
@@ -502,6 +517,7 @@ CALLBACK(process_queue, job_requeue_t,
CALLBACK(on_read, bool,
private_vici_socket_t *this, stream_t *stream)
{
+ char errmsg[256] = "";
entry_selector_t *sel;
entry_t *entry;
bool ret = FALSE;
@@ -509,9 +525,10 @@ CALLBACK(on_read, bool,
entry = find_entry(this, stream, 0, TRUE, FALSE);
if (entry)
{
- ret = do_read(this, entry, stream);
+ ret = do_read(this, entry, stream, errmsg, sizeof(errmsg));
if (!ret)
{
+ entry->disconnecting = TRUE;
disconnect(this, entry->id);
}
else if (entry->in.hdrlen == sizeof(entry->in.hdr) &&
@@ -534,6 +551,11 @@ CALLBACK(on_read, bool,
}
}
put_entry(this, entry, TRUE, FALSE);
+
+ if (!ret && errmsg[0])
+ {
+ DBG1(DBG_CFG, errmsg);
+ }
}
return ret;
diff --git a/src/libcharon/plugins/xauth_generic/xauth_generic.c b/src/libcharon/plugins/xauth_generic/xauth_generic.c
index c37da0cb0..e65d1a1fe 100644
--- a/src/libcharon/plugins/xauth_generic/xauth_generic.c
+++ b/src/libcharon/plugins/xauth_generic/xauth_generic.c
@@ -180,7 +180,7 @@ METHOD(xauth_method_t, process_server, status_t,
SHARED_EAP, this->server, this->peer);
while (enumerator->enumerate(enumerator, &shared, NULL, NULL))
{
- if (chunk_equals(shared->get_key(shared), pass))
+ if (chunk_equals_const(shared->get_key(shared), pass))
{
status = SUCCESS;
break;
diff --git a/src/libcharon/processing/jobs/adopt_children_job.c b/src/libcharon/processing/jobs/adopt_children_job.c
index c8a9c17de..b4f135a57 100644
--- a/src/libcharon/processing/jobs/adopt_children_job.c
+++ b/src/libcharon/processing/jobs/adopt_children_job.c
@@ -21,6 +21,7 @@
#include <daemon.h>
#include <hydra.h>
#include <collections/array.h>
+#include <processing/jobs/delete_ike_sa_job.h>
typedef struct private_adopt_children_job_t private_adopt_children_job_t;
@@ -64,11 +65,13 @@ METHOD(job_t, execute, job_requeue_t,
ike_sa_id_t *id;
ike_sa_t *ike_sa;
child_sa_t *child_sa;
+ u_int32_t unique;
ike_sa = charon->ike_sa_manager->checkout(charon->ike_sa_manager, this->id);
if (ike_sa)
{
/* get what we need from new SA */
+ unique = ike_sa->get_unique_id(ike_sa);
me = ike_sa->get_my_host(ike_sa);
me = me->clone(me);
other = ike_sa->get_other_host(ike_sa);
@@ -106,6 +109,7 @@ METHOD(job_t, execute, job_requeue_t,
other_id->equals(other_id, ike_sa->get_other_id(ike_sa)) &&
cfg->equals(cfg, ike_sa->get_peer_cfg(ike_sa)))
{
+ charon->bus->children_migrate(charon->bus, this->id, unique);
subenum = ike_sa->create_child_sa_enumerator(ike_sa);
while (subenum->enumerate(subenum, &child_sa))
{
@@ -130,10 +134,19 @@ METHOD(job_t, execute, job_requeue_t,
"adopting %d children and %d virtual IPs",
children->get_count(children), vips->get_count(vips));
}
- ike_sa->set_state(ike_sa, IKE_DELETING);
- charon->bus->ike_updown(charon->bus, ike_sa, FALSE);
- charon->ike_sa_manager->checkin_and_destroy(
+ if (ike_sa->get_state(ike_sa) == IKE_PASSIVE)
+ {
+ charon->ike_sa_manager->checkin_and_destroy(
+ charon->ike_sa_manager, ike_sa);
+ }
+ else
+ {
+ lib->scheduler->schedule_job(lib->scheduler, (job_t*)
+ delete_ike_sa_job_create(ike_sa->get_id(ike_sa),
+ TRUE), 10);
+ charon->ike_sa_manager->checkin(
charon->ike_sa_manager, ike_sa);
+ }
}
else
{
@@ -176,6 +189,7 @@ METHOD(job_t, execute, job_requeue_t,
}
charon->bus->assign_vips(charon->bus, ike_sa, TRUE);
}
+ charon->bus->children_migrate(charon->bus, NULL, 0);
charon->ike_sa_manager->checkin(charon->ike_sa_manager, ike_sa);
}
}
diff --git a/src/libcharon/sa/ike_sa_manager.c b/src/libcharon/sa/ike_sa_manager.c
index 13fc74ff7..938f7848f 100644
--- a/src/libcharon/sa/ike_sa_manager.c
+++ b/src/libcharon/sa/ike_sa_manager.c
@@ -1737,7 +1737,8 @@ static void adopt_children_and_vips(ike_sa_t *old, ike_sa_t *new)
host_t *vip;
int chcount = 0, vipcount = 0;
-
+ charon->bus->children_migrate(charon->bus, new->get_id(new),
+ new->get_unique_id(new));
enumerator = old->create_child_sa_enumerator(old);
while (enumerator->enumerate(enumerator, &child_sa))
{
@@ -1760,6 +1761,7 @@ static void adopt_children_and_vips(ike_sa_t *old, ike_sa_t *new)
/* ...trigger the analogous event on the new SA */
charon->bus->set_sa(charon->bus, new);
charon->bus->assign_vips(charon->bus, new, TRUE);
+ charon->bus->children_migrate(charon->bus, NULL, 0);
charon->bus->set_sa(charon->bus, old);
if (chcount || vipcount)
diff --git a/src/libcharon/sa/ikev1/authenticators/psk_v1_authenticator.c b/src/libcharon/sa/ikev1/authenticators/psk_v1_authenticator.c
index bb187f07c..5debeeb37 100644
--- a/src/libcharon/sa/ikev1/authenticators/psk_v1_authenticator.c
+++ b/src/libcharon/sa/ikev1/authenticators/psk_v1_authenticator.c
@@ -124,7 +124,7 @@ METHOD(authenticator_t, process, status_t,
return FAILED;
}
free(dh.ptr);
- if (chunk_equals(hash, hash_payload->get_hash(hash_payload)))
+ if (chunk_equals_const(hash, hash_payload->get_hash(hash_payload)))
{
free(hash.ptr);
if (!this->hybrid)
diff --git a/src/libcharon/sa/ikev1/task_manager_v1.c b/src/libcharon/sa/ikev1/task_manager_v1.c
index cb22bf606..ed547c4c2 100644
--- a/src/libcharon/sa/ikev1/task_manager_v1.c
+++ b/src/libcharon/sa/ikev1/task_manager_v1.c
@@ -1475,6 +1475,8 @@ METHOD(task_manager_t, queue_ike_reauth, void,
}
enumerator->destroy(enumerator);
+ charon->bus->children_migrate(charon->bus, new->get_id(new),
+ new->get_unique_id(new));
enumerator = this->ike_sa->create_child_sa_enumerator(this->ike_sa);
while (enumerator->enumerate(enumerator, &child_sa))
{
@@ -1482,6 +1484,9 @@ METHOD(task_manager_t, queue_ike_reauth, void,
new->add_child_sa(new, child_sa);
}
enumerator->destroy(enumerator);
+ charon->bus->set_sa(charon->bus, new);
+ charon->bus->children_migrate(charon->bus, NULL, 0);
+ charon->bus->set_sa(charon->bus, this->ike_sa);
if (!new->get_child_count(new))
{ /* check if a Quick Mode task is queued (UNITY_LOAD_BALANCE case) */
diff --git a/src/libcharon/sa/ikev2/authenticators/eap_authenticator.c b/src/libcharon/sa/ikev2/authenticators/eap_authenticator.c
index ebef31930..f1442096c 100644
--- a/src/libcharon/sa/ikev2/authenticators/eap_authenticator.c
+++ b/src/libcharon/sa/ikev2/authenticators/eap_authenticator.c
@@ -464,7 +464,7 @@ static bool verify_auth(private_eap_authenticator_t *this, message_t *message,
return FALSE;
}
recv_auth_data = auth_payload->get_data(auth_payload);
- if (!auth_data.len || !chunk_equals(auth_data, recv_auth_data))
+ if (!auth_data.len || !chunk_equals_const(auth_data, recv_auth_data))
{
DBG1(DBG_IKE, "verification of AUTH payload with%s EAP MSK failed",
this->msk.ptr ? "" : "out");
diff --git a/src/libcharon/sa/ikev2/authenticators/psk_authenticator.c b/src/libcharon/sa/ikev2/authenticators/psk_authenticator.c
index c6a4b6ba4..535581068 100644
--- a/src/libcharon/sa/ikev2/authenticators/psk_authenticator.c
+++ b/src/libcharon/sa/ikev2/authenticators/psk_authenticator.c
@@ -123,7 +123,7 @@ METHOD(authenticator_t, process, status_t,
{
continue;
}
- if (auth_data.len && chunk_equals(auth_data, recv_auth_data))
+ if (auth_data.len && chunk_equals_const(auth_data, recv_auth_data))
{
DBG1(DBG_IKE, "authentication of '%Y' with %N successful",
other_id, auth_method_names, AUTH_PSK);
diff --git a/src/libcharon/sa/ikev2/keymat_v2.c b/src/libcharon/sa/ikev2/keymat_v2.c
index f70f5cfed..6fedc8eb5 100644
--- a/src/libcharon/sa/ikev2/keymat_v2.c
+++ b/src/libcharon/sa/ikev2/keymat_v2.c
@@ -193,6 +193,7 @@ static bool derive_ike_traditional(private_keymat_v2_t *this, u_int16_t enc_alg,
{
crypter_t *crypter_i = NULL, *crypter_r = NULL;
signer_t *signer_i, *signer_r;
+ iv_gen_t *ivg_i, *ivg_r;
size_t key_size;
chunk_t key = chunk_empty;
@@ -264,15 +265,21 @@ static bool derive_ike_traditional(private_keymat_v2_t *this, u_int16_t enc_alg,
goto failure;
}
+ ivg_i = iv_gen_create_for_alg(enc_alg);
+ ivg_r = iv_gen_create_for_alg(enc_alg);
+ if (!ivg_i || !ivg_r)
+ {
+ goto failure;
+ }
if (this->initiator)
{
- this->aead_in = aead_create(crypter_r, signer_r);
- this->aead_out = aead_create(crypter_i, signer_i);
+ this->aead_in = aead_create(crypter_r, signer_r, ivg_r);
+ this->aead_out = aead_create(crypter_i, signer_i, ivg_i);
}
else
{
- this->aead_in = aead_create(crypter_i, signer_i);
- this->aead_out = aead_create(crypter_r, signer_r);
+ this->aead_in = aead_create(crypter_i, signer_i, ivg_i);
+ this->aead_out = aead_create(crypter_r, signer_r, ivg_r);
}
signer_i = signer_r = NULL;
crypter_i = crypter_r = NULL;
diff --git a/src/libcharon/sa/ikev2/task_manager_v2.c b/src/libcharon/sa/ikev2/task_manager_v2.c
index 298167703..4676867df 100644
--- a/src/libcharon/sa/ikev2/task_manager_v2.c
+++ b/src/libcharon/sa/ikev2/task_manager_v2.c
@@ -1184,15 +1184,17 @@ static status_t parse_message(private_task_manager_t *this, message_t *msg)
enumerator = msg->create_payload_enumerator(msg);
while (enumerator->enumerate(enumerator, &payload))
{
- unknown = (unknown_payload_t*)payload;
- type = payload->get_type(payload);
- if (!payload_is_known(type, msg->get_major_version(msg)) &&
- unknown->is_critical(unknown))
+ if (payload->get_type(payload) == PL_UNKNOWN)
{
- DBG1(DBG_ENC, "payload type %N is not supported, "
- "but its critical!", payload_type_names, type);
- status = NOT_SUPPORTED;
- break;
+ unknown = (unknown_payload_t*)payload;
+ if (unknown->is_critical(unknown))
+ {
+ type = unknown->get_type(unknown);
+ DBG1(DBG_ENC, "payload type %N is not supported, "
+ "but its critical!", payload_type_names, type);
+ status = NOT_SUPPORTED;
+ break;
+ }
}
}
enumerator->destroy(enumerator);
diff --git a/src/libcharon/sa/ikev2/tasks/child_create.c b/src/libcharon/sa/ikev2/tasks/child_create.c
index 6d9132a68..e0f930c3c 100644
--- a/src/libcharon/sa/ikev2/tasks/child_create.c
+++ b/src/libcharon/sa/ikev2/tasks/child_create.c
@@ -65,6 +65,11 @@ struct private_child_create_t {
chunk_t other_nonce;
/**
+ * nonce generator
+ */
+ nonce_gen_t *nonceg;
+
+ /**
* config to create the CHILD_SA from
*/
child_cfg_t *config;
@@ -214,25 +219,21 @@ static status_t get_nonce(message_t *message, chunk_t *nonce)
/**
* generate a new nonce to include in a CREATE_CHILD_SA message
*/
-static status_t generate_nonce(private_child_create_t *this)
+static bool generate_nonce(private_child_create_t *this)
{
- nonce_gen_t *nonceg;
-
- nonceg = this->keymat->keymat.create_nonce_gen(&this->keymat->keymat);
- if (!nonceg)
+ this->nonceg = this->keymat->keymat.create_nonce_gen(&this->keymat->keymat);
+ if (!this->nonceg)
{
DBG1(DBG_IKE, "no nonce generator found to create nonce");
- return FAILED;
+ return FALSE;
}
- if (!nonceg->allocate_nonce(nonceg, NONCE_SIZE, &this->my_nonce))
+ if (!this->nonceg->allocate_nonce(this->nonceg, NONCE_SIZE,
+ &this->my_nonce))
{
DBG1(DBG_IKE, "nonce allocation failed");
- nonceg->destroy(nonceg);
- return FAILED;
+ return FALSE;
}
- nonceg->destroy(nonceg);
-
- return SUCCESS;
+ return TRUE;
}
/**
@@ -933,9 +934,10 @@ METHOD(task_t, build_i, status_t,
case IKE_SA_INIT:
return get_nonce(message, &this->my_nonce);
case CREATE_CHILD_SA:
- if (generate_nonce(this) != SUCCESS)
+ if (!generate_nonce(this))
{
- message->add_notify(message, FALSE, NO_PROPOSAL_CHOSEN, chunk_empty);
+ message->add_notify(message, FALSE, NO_PROPOSAL_CHOSEN,
+ chunk_empty);
return SUCCESS;
}
if (!this->retry)
@@ -1092,7 +1094,10 @@ METHOD(task_t, process_r, status_t,
static void handle_child_sa_failure(private_child_create_t *this,
message_t *message)
{
- if (message->get_exchange_type(message) == IKE_AUTH &&
+ bool is_first;
+
+ is_first = message->get_exchange_type(message) == IKE_AUTH;
+ if (is_first &&
lib->settings->get_bool(lib->settings,
"%s.close_ike_on_child_failure", FALSE, lib->ns))
{
@@ -1106,7 +1111,8 @@ static void handle_child_sa_failure(private_child_create_t *this,
else
{
DBG1(DBG_IKE, "failed to establish CHILD_SA, keeping IKE_SA");
- charon->bus->alert(charon->bus, ALERT_KEEP_ON_CHILD_SA_FAILURE);
+ charon->bus->alert(charon->bus, ALERT_KEEP_ON_CHILD_SA_FAILURE,
+ is_first);
}
}
@@ -1190,7 +1196,7 @@ METHOD(task_t, build_r, status_t,
case IKE_SA_INIT:
return get_nonce(message, &this->my_nonce);
case CREATE_CHILD_SA:
- if (generate_nonce(this) != SUCCESS )
+ if (!generate_nonce(this))
{
message->add_notify(message, FALSE, NO_PROPOSAL_CHOSEN,
chunk_empty);
@@ -1575,6 +1581,7 @@ METHOD(task_t, migrate, void,
}
DESTROY_IF(this->child_sa);
DESTROY_IF(this->proposal);
+ DESTROY_IF(this->nonceg);
DESTROY_IF(this->dh);
this->dh_failed = FALSE;
if (this->proposals)
@@ -1627,6 +1634,7 @@ METHOD(task_t, destroy, void,
}
DESTROY_IF(this->config);
+ DESTROY_IF(this->nonceg);
free(this);
}
@@ -1678,6 +1686,5 @@ child_create_t *child_create_create(ike_sa_t *ike_sa,
this->public.task.process = _process_r;
this->initiator = FALSE;
}
-
return &this->public;
}
diff --git a/src/libcharon/sa/ikev2/tasks/ike_init.c b/src/libcharon/sa/ikev2/tasks/ike_init.c
index 0d5700ef2..1ff643d62 100644
--- a/src/libcharon/sa/ikev2/tasks/ike_init.c
+++ b/src/libcharon/sa/ikev2/tasks/ike_init.c
@@ -90,6 +90,11 @@ struct private_ike_init_t {
chunk_t other_nonce;
/**
+ * nonce generator
+ */
+ nonce_gen_t *nonceg;
+
+ /**
* Negotiated proposal used for IKE_SA
*/
proposal_t *proposal;
@@ -116,6 +121,25 @@ struct private_ike_init_t {
};
/**
+ * Allocate our own nonce value
+ */
+static bool generate_nonce(private_ike_init_t *this)
+{
+ if (!this->nonceg)
+ {
+ DBG1(DBG_IKE, "no nonce generator found to create nonce");
+ return FALSE;
+ }
+ if (!this->nonceg->allocate_nonce(this->nonceg, NONCE_SIZE,
+ &this->my_nonce))
+ {
+ DBG1(DBG_IKE, "nonce allocation failed");
+ return FALSE;
+ }
+ return TRUE;
+}
+
+/**
* Notify the peer about the hash algorithms we support or expect,
* as per RFC 7427
*/
@@ -428,21 +452,10 @@ METHOD(task_t, build_i, status_t,
/* generate nonce only when we are trying the first time */
if (this->my_nonce.ptr == NULL)
{
- nonce_gen_t *nonceg;
-
- nonceg = this->keymat->keymat.create_nonce_gen(&this->keymat->keymat);
- if (!nonceg)
+ if (!generate_nonce(this))
{
- DBG1(DBG_IKE, "no nonce generator found to create nonce");
return FAILED;
}
- if (!nonceg->allocate_nonce(nonceg, NONCE_SIZE, &this->my_nonce))
- {
- DBG1(DBG_IKE, "nonce allocation failed");
- nonceg->destroy(nonceg);
- return FAILED;
- }
- nonceg->destroy(nonceg);
}
if (this->cookie.ptr)
@@ -471,25 +484,14 @@ METHOD(task_t, build_i, status_t,
METHOD(task_t, process_r, status_t,
private_ike_init_t *this, message_t *message)
{
- nonce_gen_t *nonceg;
-
this->config = this->ike_sa->get_ike_cfg(this->ike_sa);
DBG0(DBG_IKE, "%H is initiating an IKE_SA", message->get_source(message));
this->ike_sa->set_state(this->ike_sa, IKE_CONNECTING);
- nonceg = this->keymat->keymat.create_nonce_gen(&this->keymat->keymat);
- if (!nonceg)
+ if (!generate_nonce(this))
{
- DBG1(DBG_IKE, "no nonce generator found to create nonce");
return FAILED;
}
- if (!nonceg->allocate_nonce(nonceg, NONCE_SIZE, &this->my_nonce))
- {
- DBG1(DBG_IKE, "nonce allocation failed");
- nonceg->destroy(nonceg);
- return FAILED;
- }
- nonceg->destroy(nonceg);
#ifdef ME
{
@@ -756,6 +758,7 @@ METHOD(task_t, destroy, void,
{
DESTROY_IF(this->dh);
DESTROY_IF(this->proposal);
+ DESTROY_IF(this->nonceg);
chunk_free(&this->my_nonce);
chunk_free(&this->other_nonce);
chunk_free(&this->cookie);
@@ -800,6 +803,7 @@ ike_init_t *ike_init_create(ike_sa_t *ike_sa, bool initiator, ike_sa_t *old_sa)
.signature_authentication = lib->settings->get_bool(lib->settings,
"%s.signature_authentication", TRUE, lib->ns),
);
+ this->nonceg = this->keymat->keymat.create_nonce_gen(&this->keymat->keymat);
if (initiator)
{
@@ -811,6 +815,5 @@ ike_init_t *ike_init_create(ike_sa_t *ike_sa, bool initiator, ike_sa_t *old_sa)
this->public.task.build = _build_r;
this->public.task.process = _process_r;
}
-
return &this->public;
}
diff --git a/src/libcharon/sa/ikev2/tasks/ike_mobike.c b/src/libcharon/sa/ikev2/tasks/ike_mobike.c
index 6295d7960..11b0bb281 100644
--- a/src/libcharon/sa/ikev2/tasks/ike_mobike.c
+++ b/src/libcharon/sa/ikev2/tasks/ike_mobike.c
@@ -537,7 +537,7 @@ METHOD(task_t, process_i, status_t,
cookie2 = this->cookie2;
this->cookie2 = chunk_empty;
process_payloads(this, message);
- if (!chunk_equals(cookie2, this->cookie2))
+ if (!chunk_equals_const(cookie2, this->cookie2))
{
chunk_free(&cookie2);
DBG1(DBG_IKE, "COOKIE2 mismatch, closing IKE_SA");
diff --git a/src/libcharon/sa/ikev2/tasks/ike_vendor.c b/src/libcharon/sa/ikev2/tasks/ike_vendor.c
index d536af218..cb3c270dc 100644
--- a/src/libcharon/sa/ikev2/tasks/ike_vendor.c
+++ b/src/libcharon/sa/ikev2/tasks/ike_vendor.c
@@ -76,6 +76,16 @@ static vid_data_t vids[] = {
"CISCO(COPYRIGHT)&Copyright (c) 2009 Cisco Systems, Inc." },
{ "FRAGMENTATION", 0, 16,
"\x40\x48\xb7\xd5\x6e\xbc\xe8\x85\x25\xe7\xde\x7f\x00\xd6\xc2\xd3"},
+ { "MS NT5 ISAKMPOAKLEY v7", 0, 20,
+ "\x1e\x2b\x51\x69\x05\x99\x1c\x7d\x7c\x96\xfc\xbf\xb5\x87\xe4\x61\x00\x00\x00\x07"},
+ { "MS NT5 ISAKMPOAKLEY v8", 0, 20,
+ "\x1e\x2b\x51\x69\x05\x99\x1c\x7d\x7c\x96\xfc\xbf\xb5\x87\xe4\x61\x00\x00\x00\x08"},
+ { "MS NT5 ISAKMPOAKLEY v9", 0, 20,
+ "\x1e\x2b\x51\x69\x05\x99\x1c\x7d\x7c\x96\xfc\xbf\xb5\x87\xe4\x61\x00\x00\x00\x09"},
+ { "MS-Negotiation Discovery Capable", 0, 16,
+ "\xfb\x1d\xe3\xcd\xf3\x41\xb7\xea\x16\xb7\xe5\xbe\x08\x55\xf1\x20"},
+ { "Vid-Initial-Contact", 0, 16,
+ "\x26\x24\x4d\x38\xed\xdb\x61\xb3\x17\x2a\x36\xe3\xd0\xcf\xb8\x19"},
};
METHOD(task_t, build, status_t,