From 08a3ee0cce1b6f09da22d213c0cc91f552094e79 Mon Sep 17 00:00:00 2001 From: Tobias Brunner Date: Tue, 27 Oct 2020 17:02:21 +0100 Subject: [PATCH 1/4] bus: Change ike_update() signature and only call it once This avoids multiple events when both addresses change (e.g. switching address families). --- src/libcharon/bus/bus.c | 7 ++-- src/libcharon/bus/bus.h | 9 ++--- src/libcharon/bus/listeners/listener.h | 10 +++--- .../plugins/connmark/connmark_listener.c | 17 ++------- .../plugins/forecast/forecast_listener.c | 15 ++------ src/libcharon/sa/ike_sa.c | 35 ++++++++++++------- 6 files changed, 43 insertions(+), 50 deletions(-) diff --git a/src/libcharon/bus/bus.c b/src/libcharon/bus/bus.c index b7348f0f9..f5b0651f7 100644 --- a/src/libcharon/bus/bus.c +++ b/src/libcharon/bus/bus.c @@ -1,5 +1,5 @@ /* - * Copyright (C) 2011-2016 Tobias Brunner + * Copyright (C) 2011-2020 Tobias Brunner * Copyright (C) 2006 Martin Willi * HSR Hochschule fuer Technik Rapperswil * @@ -866,7 +866,7 @@ METHOD(bus_t, ike_rekey, void, } METHOD(bus_t, ike_update, void, - private_bus_t *this, ike_sa_t *ike_sa, bool local, host_t *new) + private_bus_t *this, ike_sa_t *ike_sa, host_t *local, host_t *remote) { enumerator_t *enumerator; entry_t *entry; @@ -881,7 +881,8 @@ METHOD(bus_t, ike_update, void, continue; } entry->calling++; - keep = entry->listener->ike_update(entry->listener, ike_sa, local, new); + keep = entry->listener->ike_update(entry->listener, ike_sa, local, + remote); entry->calling--; if (!keep) { diff --git a/src/libcharon/bus/bus.h b/src/libcharon/bus/bus.h index abf95a4c9..22248f7a0 100644 --- a/src/libcharon/bus/bus.h +++ b/src/libcharon/bus/bus.h @@ -1,5 +1,5 @@ /* - * Copyright (C) 2012-2016 Tobias Brunner + * Copyright (C) 2012-2020 Tobias Brunner * Copyright (C) 2006-2009 Martin Willi * HSR Hochschule fuer Technik Rapperswil * @@ -417,10 +417,11 @@ struct bus_t { * IKE_SA peer endpoint update hook. * * @param ike_sa updated IKE_SA, having old endpoints set - * @param local TRUE if local endpoint gets updated, FALSE for remote - * @param new new endpoint address and port + * @param local new/current local endpoint address and port + * @param remote new/current remote endpoint address and port */ - void (*ike_update)(bus_t *this, ike_sa_t *ike_sa, bool local, host_t *new); + void (*ike_update)(bus_t *this, ike_sa_t *ike_sa, host_t *local, + host_t *remote); /** * IKE_SA reestablishing hook (before resolving hosts). diff --git a/src/libcharon/bus/listeners/listener.h b/src/libcharon/bus/listeners/listener.h index 0f3b8578a..b24785a62 100644 --- a/src/libcharon/bus/listeners/listener.h +++ b/src/libcharon/bus/listeners/listener.h @@ -1,5 +1,5 @@ /* - * Copyright (C) 2011-2016 Tobias Brunner + * Copyright (C) 2011-2020 Tobias Brunner * Copyright (C) 2009 Martin Willi * HSR Hochschule fuer Technik Rapperswil * @@ -160,13 +160,15 @@ struct listener_t { /** * Hook called for IKE_SA peer endpoint updates. * + * At least one endpoint has changed when this is invoked. + * * @param ike_sa updated IKE_SA, having old endpoints set - * @param local TRUE if local endpoint gets updated, FALSE for remote - * @param new new endpoint address and port + * @param local new/current local endpoint address and port + * @param remote new/current remote endpoint address and port * @return TRUE to stay registered, FALSE to unregister */ bool (*ike_update)(listener_t *this, ike_sa_t *ike_sa, - bool local, host_t *new); + host_t *local, host_t *remote); /** * Hook called when an initiator reestablishes an IKE_SA. diff --git a/src/libcharon/plugins/connmark/connmark_listener.c b/src/libcharon/plugins/connmark/connmark_listener.c index 7d23f1a23..824f7a199 100644 --- a/src/libcharon/plugins/connmark/connmark_listener.c +++ b/src/libcharon/plugins/connmark/connmark_listener.c @@ -494,24 +494,13 @@ METHOD(listener_t, child_rekey, bool, METHOD(listener_t, ike_update, bool, private_connmark_listener_t *this, ike_sa_t *ike_sa, - bool local, host_t *new) + host_t *local, host_t *remote) { struct iptc_handle *ipth; enumerator_t *enumerator; child_sa_t *child_sa; - host_t *dst, *src; bool oldencap, newencap; - if (local) - { - dst = new; - src = ike_sa->get_other_host(ike_sa); - } - else - { - dst = ike_sa->get_my_host(ike_sa); - src = new; - } /* during ike_update(), has_encap() on the CHILD_SA has not yet been * updated, but shows the old state. */ newencap = ike_sa->has_condition(ike_sa, COND_NAT_ANY); @@ -525,9 +514,9 @@ METHOD(listener_t, ike_update, bool, ipth = init_handle(); if (ipth) { - if (manage_policies(this, ipth, dst, src, oldencap, + if (manage_policies(this, ipth, local, remote, oldencap, child_sa, FALSE) && - manage_policies(this, ipth, dst, src, newencap, + manage_policies(this, ipth, local, remote, newencap, child_sa, TRUE)) { commit_handle(ipth); diff --git a/src/libcharon/plugins/forecast/forecast_listener.c b/src/libcharon/plugins/forecast/forecast_listener.c index b928cad35..f4d4081e3 100644 --- a/src/libcharon/plugins/forecast/forecast_listener.c +++ b/src/libcharon/plugins/forecast/forecast_listener.c @@ -569,24 +569,13 @@ METHOD(listener_t, child_rekey, bool, METHOD(listener_t, ike_update, bool, private_forecast_listener_t *this, ike_sa_t *ike_sa, - bool local, host_t *new) + host_t *local, host_t *remote) { struct iptc_handle *ipth; enumerator_t *enumerator; child_sa_t *child_sa; - host_t *lhost, *rhost; bool encap; - if (local) - { - lhost = new; - rhost = ike_sa->get_other_host(ike_sa); - } - else - { - lhost = ike_sa->get_my_host(ike_sa); - rhost = new; - } /* during ike_update(), has_encap() on the CHILD_SA has not yet been * updated, but shows the old state. */ encap = ike_sa->has_condition(ike_sa, COND_NAT_ANY); @@ -600,7 +589,7 @@ METHOD(listener_t, ike_update, bool, if (ipth) { if (remove_entry(this, ipth, child_sa) && - add_entry(this, ipth, lhost, rhost, child_sa, encap)) + add_entry(this, ipth, local, remote, child_sa, encap)) { commit_handle(ipth); } diff --git a/src/libcharon/sa/ike_sa.c b/src/libcharon/sa/ike_sa.c index f1e3e8fe5..b8fdcbb07 100644 --- a/src/libcharon/sa/ike_sa.c +++ b/src/libcharon/sa/ike_sa.c @@ -1116,7 +1116,8 @@ METHOD(ike_sa_t, float_ports, void, METHOD(ike_sa_t, update_hosts, void, private_ike_sa_t *this, host_t *me, host_t *other, bool force) { - bool update = FALSE; + host_t *new_me = NULL, *new_other = NULL; + bool silent = FALSE; if (me == NULL) { @@ -1131,18 +1132,16 @@ METHOD(ike_sa_t, update_hosts, void, if (this->my_host->is_anyaddr(this->my_host) || this->other_host->is_anyaddr(this->other_host)) { - set_my_host(this, me->clone(me)); - set_other_host(this, other->clone(other)); - update = TRUE; + new_me = me; + new_other = other; + silent = TRUE; } else { /* update our address in any case */ if (force && !me->equals(me, this->my_host)) { - charon->bus->ike_update(charon->bus, &this->public, TRUE, me); - set_my_host(this, me->clone(me)); - update = TRUE; + new_me = me; } if (!other->equals(other, this->other_host) && @@ -1154,20 +1153,32 @@ METHOD(ike_sa_t, update_hosts, void, (!has_condition(this, COND_NAT_HERE) || !has_condition(this, COND_ORIGINAL_INITIATOR))) { - charon->bus->ike_update(charon->bus, &this->public, FALSE, other); - set_other_host(this, other->clone(other)); - update = TRUE; + new_other = other; } } } - /* update all associated CHILD_SAs, if required */ - if (update) + if (new_me || new_other) { enumerator_t *enumerator; child_sa_t *child_sa; linked_list_t *vips; + if (!silent) + { + charon->bus->ike_update(charon->bus, &this->public, + new_me ?: this->my_host, + new_other ?: this->other_host); + } + if (new_me) + { + set_my_host(this, new_me->clone(new_me)); + } + if (new_other) + { + set_other_host(this, new_other->clone(new_other)); + } + vips = linked_list_create_from_enumerator( array_create_enumerator(this->my_vips)); From 51c7cf9a04c61f655032b7fc53e801c160426f74 Mon Sep 17 00:00:00 2001 From: Tobias Brunner Date: Tue, 27 Oct 2020 19:06:21 +0100 Subject: [PATCH 2/4] ike-sa: Add flags to force updating hosts/CHILD_SAs This allows more fine grained control over what's updated and does not require multiple calls of the method. Plus we'll be able to use it in the ike-mobike task. --- src/libcharon/processing/jobs/update_sa_job.c | 2 +- src/libcharon/sa/ike_sa.c | 14 +++++----- src/libcharon/sa/ike_sa.h | 27 ++++++++++++++++--- src/libcharon/sa/ikev1/task_manager_v1.c | 4 +-- .../sa/ikev1/tasks/aggressive_mode.c | 3 ++- src/libcharon/sa/ikev1/tasks/main_mode.c | 3 ++- src/libcharon/sa/ikev2/task_manager_v2.c | 16 ++++++----- 7 files changed, 47 insertions(+), 22 deletions(-) diff --git a/src/libcharon/processing/jobs/update_sa_job.c b/src/libcharon/processing/jobs/update_sa_job.c index dfb85f690..6fe211357 100644 --- a/src/libcharon/processing/jobs/update_sa_job.c +++ b/src/libcharon/processing/jobs/update_sa_job.c @@ -76,7 +76,7 @@ METHOD(job_t, execute, job_requeue_t, } else { - ike_sa->update_hosts(ike_sa, NULL, this->new, FALSE); + ike_sa->update_hosts(ike_sa, NULL, this->new, 0); charon->ike_sa_manager->checkin(charon->ike_sa_manager, ike_sa); } return JOB_REQUEUE_NONE; diff --git a/src/libcharon/sa/ike_sa.c b/src/libcharon/sa/ike_sa.c index b8fdcbb07..24fb4cd23 100644 --- a/src/libcharon/sa/ike_sa.c +++ b/src/libcharon/sa/ike_sa.c @@ -1114,7 +1114,7 @@ METHOD(ike_sa_t, float_ports, void, } METHOD(ike_sa_t, update_hosts, void, - private_ike_sa_t *this, host_t *me, host_t *other, bool force) + private_ike_sa_t *this, host_t *me, host_t *other, update_hosts_flag_t flags) { host_t *new_me = NULL, *new_other = NULL; bool silent = FALSE; @@ -1138,18 +1138,18 @@ METHOD(ike_sa_t, update_hosts, void, } else { - /* update our address in any case */ - if (force && !me->equals(me, this->my_host)) + /* update our address only if forced */ + if ((flags & UPDATE_HOSTS_FORCE_LOCAL) && !me->equals(me, this->my_host)) { new_me = me; } if (!other->equals(other, this->other_host) && - (force || has_condition(this, COND_NAT_THERE))) + ((flags & UPDATE_HOSTS_FORCE_REMOTE) || has_condition(this, COND_NAT_THERE))) { /* only update other's address if we are behind a static NAT, * which we assume is the case if we are not initiator */ - if (force || + if ((flags & UPDATE_HOSTS_FORCE_REMOTE) || (!has_condition(this, COND_NAT_HERE) || !has_condition(this, COND_ORIGINAL_INITIATOR))) { @@ -1158,13 +1158,13 @@ METHOD(ike_sa_t, update_hosts, void, } } - if (new_me || new_other) + if (new_me || new_other || (flags & UPDATE_HOSTS_FORCE_CHILDREN)) { enumerator_t *enumerator; child_sa_t *child_sa; linked_list_t *vips; - if (!silent) + if ((new_me || new_other) && !silent) { charon->bus->ike_update(charon->bus, &this->public, new_me ?: this->my_host, diff --git a/src/libcharon/sa/ike_sa.h b/src/libcharon/sa/ike_sa.h index b965a49c9..f15455930 100644 --- a/src/libcharon/sa/ike_sa.h +++ b/src/libcharon/sa/ike_sa.h @@ -28,6 +28,7 @@ typedef enum ike_extension_t ike_extension_t; typedef enum ike_condition_t ike_condition_t; typedef enum ike_sa_state_t ike_sa_state_t; typedef enum statistic_t statistic_t; +typedef enum update_hosts_flag_t update_hosts_flag_t; typedef struct ike_sa_t ike_sa_t; #include @@ -264,6 +265,25 @@ enum statistic_t { STAT_MAX }; +/** + * Flags used when updating addresses + */ +enum update_hosts_flag_t { + /** Force updating the local address (otherwise not updated if an address + * is already set). */ + UPDATE_HOSTS_FORCE_LOCAL = (1<<0), + /** Force updating the remote address (otherwise only updated if peer is + * behind a NAT). */ + UPDATE_HOSTS_FORCE_REMOTE = (1<<1), + /** Force updating both addresses. */ + UPDATE_HOSTS_FORCE_ADDRS = UPDATE_HOSTS_FORCE_LOCAL|UPDATE_HOSTS_FORCE_REMOTE, + /** Force updating the CHILD_SAs even if no addresses changed, useful if + * NAT state may have changed. */ + UPDATE_HOSTS_FORCE_CHILDREN = (1<<2), + /** Force updating everything. */ + UPDATE_HOSTS_FORCE_ALL = UPDATE_HOSTS_FORCE_ADDRS|UPDATE_HOSTS_FORCE_CHILDREN, +}; + /** * State of an IKE_SA. * @@ -454,15 +474,16 @@ struct ike_sa_t { void (*float_ports)(ike_sa_t *this); /** - * Update the IKE_SAs host. + * Update the IKE_SAs host and CHILD_SAs. * * Hosts may be NULL to use current host. * * @param me new local host address, or NULL * @param other new remote host address, or NULL - * @param force force update + * @param flags flags to force certain updates */ - void (*update_hosts)(ike_sa_t *this, host_t *me, host_t *other, bool force); + void (*update_hosts)(ike_sa_t *this, host_t *me, host_t *other, + update_hosts_flag_t flags); /** * Get the own identification. diff --git a/src/libcharon/sa/ikev1/task_manager_v1.c b/src/libcharon/sa/ikev1/task_manager_v1.c index 2a8bcfae7..f49a8eb8e 100644 --- a/src/libcharon/sa/ikev1/task_manager_v1.c +++ b/src/libcharon/sa/ikev1/task_manager_v1.c @@ -1408,7 +1408,7 @@ METHOD(task_manager_t, process_message, status_t, } this->ike_sa->set_statistic(this->ike_sa, STAT_INBOUND, time_monotonic(NULL)); - this->ike_sa->update_hosts(this->ike_sa, me, other, TRUE); + this->ike_sa->update_hosts(this->ike_sa, me, other, UPDATE_HOSTS_FORCE_ADDRS); charon->bus->message(charon->bus, msg, TRUE, TRUE); if (process_response(this, msg) != SUCCESS) { @@ -1528,7 +1528,7 @@ METHOD(task_manager_t, process_message, status_t, "%s.half_open_timeout", HALF_OPEN_IKE_SA_TIMEOUT, lib->ns)); } - this->ike_sa->update_hosts(this->ike_sa, me, other, TRUE); + this->ike_sa->update_hosts(this->ike_sa, me, other, UPDATE_HOSTS_FORCE_ADDRS); charon->bus->message(charon->bus, msg, TRUE, TRUE); if (process_request(this, msg) != SUCCESS) { diff --git a/src/libcharon/sa/ikev1/tasks/aggressive_mode.c b/src/libcharon/sa/ikev1/tasks/aggressive_mode.c index 7314f8872..c38276c9c 100644 --- a/src/libcharon/sa/ikev1/tasks/aggressive_mode.c +++ b/src/libcharon/sa/ikev1/tasks/aggressive_mode.c @@ -384,7 +384,8 @@ METHOD(task_t, process_r, status_t, this->ike_sa->update_hosts(this->ike_sa, message->get_destination(message), - message->get_source(message), TRUE); + message->get_source(message), + UPDATE_HOSTS_FORCE_ADDRS); sa_payload = (sa_payload_t*)message->get_payload(message, PLV1_SECURITY_ASSOCIATION); diff --git a/src/libcharon/sa/ikev1/tasks/main_mode.c b/src/libcharon/sa/ikev1/tasks/main_mode.c index c1d12046f..35e860f09 100644 --- a/src/libcharon/sa/ikev1/tasks/main_mode.c +++ b/src/libcharon/sa/ikev1/tasks/main_mode.c @@ -376,7 +376,8 @@ METHOD(task_t, process_r, status_t, this->ike_sa->update_hosts(this->ike_sa, message->get_destination(message), - message->get_source(message), TRUE); + message->get_source(message), + UPDATE_HOSTS_FORCE_ADDRS); sa_payload = (sa_payload_t*)message->get_payload(message, PLV1_SECURITY_ASSOCIATION); diff --git a/src/libcharon/sa/ikev2/task_manager_v2.c b/src/libcharon/sa/ikev2/task_manager_v2.c index 64d95f581..9a3c1cae3 100644 --- a/src/libcharon/sa/ikev2/task_manager_v2.c +++ b/src/libcharon/sa/ikev2/task_manager_v2.c @@ -1649,8 +1649,10 @@ METHOD(task_manager_t, process_message, status_t, return FAILED; } if (!this->ike_sa->supports_extension(this->ike_sa, EXT_MOBIKE)) - { /* with MOBIKE, we do no implicit updates */ - this->ike_sa->update_hosts(this->ike_sa, me, other, mid == 1); + { /* only do implicit updates without MOBIKE, and only force + * updates for IKE_AUTH (ports might change due to NAT-T) */ + this->ike_sa->update_hosts(this->ike_sa, me, other, + mid == 1 ? UPDATE_HOSTS_FORCE_ADDRS : 0); } status = handle_fragment(this, &this->responding.defrag, msg); if (status != SUCCESS) @@ -1718,11 +1720,11 @@ METHOD(task_manager_t, process_message, status_t, msg->get_exchange_type(msg) != IKE_SA_INIT) { /* only do updates based on verified messages (or initial ones) */ if (!this->ike_sa->supports_extension(this->ike_sa, EXT_MOBIKE)) - { /* with MOBIKE, we do no implicit updates. we force an - * update of the local address on IKE_SA_INIT, but never - * for the remote address */ - this->ike_sa->update_hosts(this->ike_sa, me, NULL, mid == 0); - this->ike_sa->update_hosts(this->ike_sa, NULL, other, FALSE); + { /* only do implicit updates without MOBIKE, we force an + * update of the local address on IKE_SA_INIT as we might + * not know it yet, but never for the remote address */ + this->ike_sa->update_hosts(this->ike_sa, me, other, + mid == 0 ? UPDATE_HOSTS_FORCE_LOCAL : 0); } } status = handle_fragment(this, &this->initiating.defrag, msg); From 2b255f01afbce321a7930bb70c0c8caf06d4600c Mon Sep 17 00:00:00 2001 From: Tobias Brunner Date: Tue, 27 Oct 2020 17:18:41 +0100 Subject: [PATCH 3/4] ike-mobike: Use ike_sa_t::update_hosts() to trigger events We should trigger the ike_update() event for MOBIKE updates and since update_hosts() updates the children we can reuse that code too. --- src/libcharon/sa/ikev2/tasks/ike_mobike.c | 137 +++++++--------------- 1 file changed, 44 insertions(+), 93 deletions(-) diff --git a/src/libcharon/sa/ikev2/tasks/ike_mobike.c b/src/libcharon/sa/ikev2/tasks/ike_mobike.c index b2ad0a02a..81f7d21ae 100644 --- a/src/libcharon/sa/ikev2/tasks/ike_mobike.c +++ b/src/libcharon/sa/ikev2/tasks/ike_mobike.c @@ -1,5 +1,5 @@ /* - * Copyright (C) 2010-2018 Tobias Brunner + * Copyright (C) 2010-2020 Tobias Brunner * Copyright (C) 2007 Martin Willi * HSR Hochschule fuer Technik Rapperswil * @@ -269,55 +269,6 @@ static bool build_cookie(private_ike_mobike_t *this, message_t *message) return TRUE; } -/** - * update addresses of associated CHILD_SAs - */ -static void update_children(private_ike_mobike_t *this) -{ - enumerator_t *enumerator; - child_sa_t *child_sa; - linked_list_t *vips; - status_t status; - host_t *host; - - vips = linked_list_create(); - - enumerator = this->ike_sa->create_virtual_ip_enumerator(this->ike_sa, TRUE); - while (enumerator->enumerate(enumerator, &host)) - { - vips->insert_last(vips, host); - } - enumerator->destroy(enumerator); - - enumerator = this->ike_sa->create_child_sa_enumerator(this->ike_sa); - while (enumerator->enumerate(enumerator, (void**)&child_sa)) - { - status = child_sa->update(child_sa, - this->ike_sa->get_my_host(this->ike_sa), - this->ike_sa->get_other_host(this->ike_sa), vips, - this->ike_sa->has_condition(this->ike_sa, COND_NAT_ANY)); - switch (status) - { - case NOT_SUPPORTED: - this->ike_sa->rekey_child_sa(this->ike_sa, - child_sa->get_protocol(child_sa), - child_sa->get_spi(child_sa, TRUE)); - break; - case SUCCESS: - charon->child_sa_manager->remove(charon->child_sa_manager, - child_sa); - charon->child_sa_manager->add(charon->child_sa_manager, - child_sa, this->ike_sa); - break; - default: - break; - } - } - enumerator->destroy(enumerator); - - vips->destroy(vips); -} - /** * Apply the port of the old host, if its ip equals the new, use port otherwise. */ @@ -448,7 +399,6 @@ METHOD(task_t, build_i, status_t, { return FAILED; } - update_children(this); } if (this->address && !this->check) { @@ -472,34 +422,41 @@ METHOD(task_t, process_r, status_t, } else if (message->get_exchange_type(message) == INFORMATIONAL) { - process_payloads(this, message); - if (this->update) - { - host_t *me, *other; + host_t *me_new = NULL, *other, *other_old, *other_new = NULL; - me = message->get_destination(message); - other = message->get_source(message); - this->ike_sa->set_my_host(this->ike_sa, me->clone(me)); - this->ike_sa->set_other_host(this->ike_sa, other->clone(other)); - } + process_payloads(this, message); if (this->natd) { this->natd->task.process(&this->natd->task, message); } - if (this->addresses_updated && this->ike_sa->has_condition(this->ike_sa, - COND_ORIGINAL_INITIATOR)) + + if (this->update) { - host_t *other = message->get_source(message); - host_t *other_old = this->ike_sa->get_other_host(this->ike_sa); + me_new = message->get_destination(message); + other_new = message->get_source(message); + } + else if (this->addresses_updated && + this->ike_sa->has_condition(this->ike_sa, COND_ORIGINAL_INITIATOR)) + { + other = message->get_source(message); + other_old = this->ike_sa->get_other_host(this->ike_sa); if (!other->equals(other, other_old)) { DBG1(DBG_IKE, "remote address changed from %H to %H", other_old, other); - this->ike_sa->set_other_host(this->ike_sa, other->clone(other)); - this->update = TRUE; + other_new = other; + /* our address might have changed too if the responder used + * a different address from our list to reach us */ + me_new = message->get_destination(message); } } + + if (me_new || other_new) + { + this->ike_sa->update_hosts(this->ike_sa, me_new, + other_new, UPDATE_HOSTS_FORCE_ALL); + } } return NEED_MORE; } @@ -528,10 +485,6 @@ METHOD(task_t, build_r, status_t, message->add_notify(message, FALSE, COOKIE2, this->cookie2); chunk_free(&this->cookie2); } - if (this->update) - { - update_children(this); - } return SUCCESS; } return NEED_MORE; @@ -574,49 +527,47 @@ METHOD(task_t, process_i, status_t, if (this->natd) { this->natd->task.process(&this->natd->task, message); - if (!this->update && this->natd->has_mapping_changed(this->natd)) - { - /* force an update if mappings have changed */ - this->update = this->check = TRUE; + + if (this->update) + { /* update children again, as NAT state may have changed */ + this->ike_sa->update_hosts(this->ike_sa, NULL, NULL, + UPDATE_HOSTS_FORCE_CHILDREN); + } + else if (this->natd->has_mapping_changed(this->natd)) + { /* force a check/update if mappings have changed during a DPD */ + this->check = TRUE; DBG1(DBG_IKE, "detected changes in NAT mappings, " "initiating MOBIKE update"); } } - if (this->update) - { - /* update again, as NAT state may have changed */ - update_children(this); - } if (this->check) { - host_t *me_new, *me_old, *other_new, *other_old; + host_t *me, *me_new = NULL, *other, *other_new = NULL; - me_new = message->get_destination(message); - other_new = message->get_source(message); - me_old = this->ike_sa->get_my_host(this->ike_sa); - other_old = this->ike_sa->get_other_host(this->ike_sa); + me = message->get_destination(message); + other = message->get_source(message); - if (!me_new->equals(me_new, me_old)) + if (!me->equals(me, this->ike_sa->get_my_host(this->ike_sa))) { - this->update = TRUE; - this->ike_sa->set_my_host(this->ike_sa, me_new->clone(me_new)); + me_new = me; } - if (!other_new->equals(other_new, other_old)) + if (!other->equals(other, this->ike_sa->get_other_host(this->ike_sa))) { - this->update = TRUE; - this->ike_sa->set_other_host(this->ike_sa, other_new->clone(other_new)); + other_new = other; } - if (this->update) + if (me_new || other_new) { + this->ike_sa->update_hosts(this->ike_sa, me_new, other_new, + UPDATE_HOSTS_FORCE_ALL); /* use the same task to ... */ if (!this->ike_sa->has_condition(this->ike_sa, COND_ORIGINAL_INITIATOR)) { /*... send an updated list of addresses as responder */ - update_children(this); - this->update = FALSE; + this->address = TRUE; } else { /* ... send the update as original initiator */ + this->update = TRUE; if (this->natd) { this->natd->task.destroy(&this->natd->task); From d79cefc3fcfa6de4b7740b92933317c66c6c25e1 Mon Sep 17 00:00:00 2001 From: Tobias Brunner Date: Thu, 22 Oct 2020 19:12:39 +0200 Subject: [PATCH 4/4] vici: Expose ike-update event --- src/libcharon/plugins/vici/README.md | 16 +++++++++++ src/libcharon/plugins/vici/vici_query.c | 35 ++++++++++++++++++++++++- 2 files changed, 50 insertions(+), 1 deletion(-) diff --git a/src/libcharon/plugins/vici/README.md b/src/libcharon/plugins/vici/README.md index cf2e7482e..11c6e8166 100644 --- a/src/libcharon/plugins/vici/README.md +++ b/src/libcharon/plugins/vici/README.md @@ -976,6 +976,22 @@ The _ike-rekey_ event is issued when an IKE_SA is rekeyed. } } +### ike-update ### + +The _ike-update_ event is issued when the local or remote endpoint address of an +IKE_SA is about to change (at least one address/port is different). + + { + local-host = + local-port = + remote-host = + remote-port = + = { + + } + } + ### child-updown ### The _child-updown_ event is issued when a CHILD_SA is established or terminated. diff --git a/src/libcharon/plugins/vici/vici_query.c b/src/libcharon/plugins/vici/vici_query.c index ad07ff12d..fb65b1447 100644 --- a/src/libcharon/plugins/vici/vici_query.c +++ b/src/libcharon/plugins/vici/vici_query.c @@ -1,5 +1,5 @@ /* - * Copyright (C) 2015-2017 Tobias Brunner + * Copyright (C) 2015-2020 Tobias Brunner * Copyright (C) 2015-2018 Andreas Steffen * HSR Hochschule fuer Technik Rapperswil * @@ -510,6 +510,7 @@ CALLBACK(list_sas, vici_message_t*, bool bl; char buf[BUF_LEN]; + bl = request->get_str(request, NULL, "noblock") == NULL; ike = request->get_str(request, NULL, "ike"); ike_id = request->get_int(request, 0, "ike-id"); @@ -1683,6 +1684,7 @@ static void manage_commands(private_vici_query_t *this, bool 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, "ike-rekey", reg); + this->dispatcher->manage_event(this->dispatcher, "ike-update", reg); this->dispatcher->manage_event(this->dispatcher, "child-updown", reg); this->dispatcher->manage_event(this->dispatcher, "child-rekey", reg); manage_command(this, "list-sas", list_sas, reg); @@ -1755,6 +1757,36 @@ METHOD(listener_t, ike_rekey, bool, return TRUE; } +METHOD(listener_t, ike_update, bool, + private_vici_query_t *this, ike_sa_t *ike_sa, host_t *local, host_t *remote) +{ + vici_builder_t *b; + time_t now; + + if (!this->dispatcher->has_event_listeners(this->dispatcher, "ike-update")) + { + return TRUE; + } + + now = time_monotonic(NULL); + + b = vici_builder_create(); + + b->add_kv(b, "local-host", "%H", local); + b->add_kv(b, "local-port", "%d", local->get_port(local)); + b->add_kv(b, "remote-host", "%H", remote); + b->add_kv(b, "remote-port", "%d", remote->get_port(remote)); + + b->begin_section(b, ike_sa->get_name(ike_sa)); + list_ike(this, b, ike_sa, now); + b->end_section(b); + + this->dispatcher->raise_event(this->dispatcher, + "ike-update", 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) { @@ -1853,6 +1885,7 @@ vici_query_t *vici_query_create(vici_dispatcher_t *dispatcher) .listener = { .ike_updown = _ike_updown, .ike_rekey = _ike_rekey, + .ike_update = _ike_update, .child_updown = _child_updown, .child_rekey = _child_rekey, },