diff options
Diffstat (limited to 'src/libcharon')
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, |