summaryrefslogtreecommitdiff
path: root/src/libcharon/sa/ike_sa.c
diff options
context:
space:
mode:
Diffstat (limited to 'src/libcharon/sa/ike_sa.c')
-rw-r--r--src/libcharon/sa/ike_sa.c557
1 files changed, 464 insertions, 93 deletions
diff --git a/src/libcharon/sa/ike_sa.c b/src/libcharon/sa/ike_sa.c
index dcf9d5f2c..bcbff3211 100644
--- a/src/libcharon/sa/ike_sa.c
+++ b/src/libcharon/sa/ike_sa.c
@@ -46,7 +46,6 @@
#include "ike_sa.h"
#include <library.h>
-#include <hydra.h>
#include <daemon.h>
#include <collections/array.h>
#include <utils/lexparser.h>
@@ -57,6 +56,9 @@
#include <processing/jobs/rekey_ike_sa_job.h>
#include <processing/jobs/retry_initiate_job.h>
#include <sa/ikev2/tasks/ike_auth_lifetime.h>
+#include <sa/ikev2/tasks/ike_reauth_complete.h>
+#include <sa/ikev2/tasks/ike_redirect.h>
+#include <credentials/sets/auth_cfg_wrapper.h>
#ifdef ME
#include <sa/ikev2/tasks/ike_me.h>
@@ -239,6 +241,11 @@ struct private_ike_sa_t {
u_int32_t keepalive_interval;
/**
+ * The schedueld keep alive job, if any
+ */
+ send_keepalive_job_t *keepalive_job;
+
+ /**
* interval for retries during initiation (e.g. if DNS resolution failed),
* 0 to disable (default)
*/
@@ -278,6 +285,21 @@ struct private_ike_sa_t {
* Maximum length of a single fragment, 0 for address-specific defaults
*/
size_t fragment_size;
+
+ /**
+ * Whether to follow IKEv2 redirects
+ */
+ bool follow_redirects;
+
+ /**
+ * Original gateway address from which we got redirected
+ */
+ host_t *redirected_from;
+
+ /**
+ * Timestamps of redirect attempts to handle loops
+ */
+ array_t *redirected_at;
};
/**
@@ -382,6 +404,12 @@ METHOD(ike_sa_t, set_other_host, void,
this->other_host = other;
}
+METHOD(ike_sa_t, get_redirected_from, host_t*,
+ private_ike_sa_t *this)
+{
+ return this->redirected_from;
+}
+
METHOD(ike_sa_t, get_peer_cfg, peer_cfg_t*,
private_ike_sa_t *this)
{
@@ -455,6 +483,113 @@ static void flush_auth_cfgs(private_ike_sa_t *this)
}
}
+METHOD(ike_sa_t, verify_peer_certificate, bool,
+ private_ike_sa_t *this)
+{
+ enumerator_t *e1, *e2, *certs;
+ auth_cfg_t *cfg, *cfg_done;
+ certificate_t *peer, *cert;
+ public_key_t *key;
+ auth_cfg_t *auth;
+ auth_cfg_wrapper_t *wrapper;
+ time_t not_before, not_after;
+ bool valid = TRUE, found;
+
+ if (this->state != IKE_ESTABLISHED)
+ {
+ DBG1(DBG_IKE, "unable to verify peer certificate in state %N",
+ ike_sa_state_names, this->state);
+ return FALSE;
+ }
+
+ if (!this->flush_auth_cfg &&
+ lib->settings->get_bool(lib->settings,
+ "%s.flush_auth_cfg", FALSE, lib->ns))
+ { /* we can do this check only once if auth configs are flushed */
+ DBG1(DBG_IKE, "unable to verify peer certificate as authentication "
+ "information has been flushed");
+ return FALSE;
+ }
+ this->public.set_condition(&this->public, COND_ONLINE_VALIDATION_SUSPENDED,
+ FALSE);
+
+ e1 = this->peer_cfg->create_auth_cfg_enumerator(this->peer_cfg, FALSE);
+ e2 = array_create_enumerator(this->other_auths);
+ while (e1->enumerate(e1, &cfg))
+ {
+ if (!e2->enumerate(e2, &cfg_done))
+ { /* this should not happen as the authentication should never have
+ * succeeded */
+ valid = FALSE;
+ break;
+ }
+ if ((uintptr_t)cfg_done->get(cfg_done,
+ AUTH_RULE_AUTH_CLASS) != AUTH_CLASS_PUBKEY)
+ {
+ continue;
+ }
+ peer = cfg_done->get(cfg_done, AUTH_RULE_SUBJECT_CERT);
+ if (!peer)
+ {
+ DBG1(DBG_IKE, "no subject certificate found, skipping certificate "
+ "verification");
+ continue;
+ }
+ if (!peer->get_validity(peer, NULL, &not_before, &not_after))
+ {
+ DBG1(DBG_IKE, "peer certificate invalid (valid from %T to %T)",
+ &not_before, FALSE, &not_after, FALSE);
+ valid = FALSE;
+ break;
+ }
+ key = peer->get_public_key(peer);
+ if (!key)
+ {
+ DBG1(DBG_IKE, "unable to retrieve public key, skipping certificate "
+ "verification");
+ continue;
+ }
+ DBG1(DBG_IKE, "verifying peer certificate");
+ /* serve received certificates */
+ wrapper = auth_cfg_wrapper_create(cfg_done);
+ lib->credmgr->add_local_set(lib->credmgr, &wrapper->set, FALSE);
+ certs = lib->credmgr->create_trusted_enumerator(lib->credmgr,
+ key->get_type(key), peer->get_subject(peer), TRUE);
+ key->destroy(key);
+
+ found = FALSE;
+ while (certs->enumerate(certs, &cert, &auth))
+ {
+ if (peer->equals(peer, cert))
+ {
+ cfg_done->add(cfg_done, AUTH_RULE_CERT_VALIDATION_SUSPENDED,
+ FALSE);
+ cfg_done->merge(cfg_done, auth, FALSE);
+ valid = cfg_done->complies(cfg_done, cfg, TRUE);
+ found = TRUE;
+ break;
+ }
+ }
+ certs->destroy(certs);
+ lib->credmgr->remove_local_set(lib->credmgr, &wrapper->set);
+ wrapper->destroy(wrapper);
+ if (!found || !valid)
+ {
+ valid = FALSE;
+ break;
+ }
+ }
+ e1->destroy(e1);
+ e2->destroy(e2);
+
+ if (this->flush_auth_cfg)
+ {
+ this->flush_auth_cfg = FALSE;
+ flush_auth_cfgs(this);
+ }
+ return valid;
+}
+
METHOD(ike_sa_t, get_proposal, proposal_t*,
private_ike_sa_t *this)
{
@@ -482,14 +617,20 @@ METHOD(ike_sa_t, set_message_id, void,
}
METHOD(ike_sa_t, send_keepalive, void,
- private_ike_sa_t *this)
+ private_ike_sa_t *this, bool scheduled)
{
- send_keepalive_job_t *job;
time_t last_out, now, diff;
- if (!(this->conditions & COND_NAT_HERE) || this->keepalive_interval == 0 ||
- this->state == IKE_PASSIVE)
- { /* disable keep alives if we are not NATed anymore, or we are passive */
+ if (scheduled)
+ {
+ this->keepalive_job = NULL;
+ }
+ if (!this->keepalive_interval || this->state == IKE_PASSIVE)
+ { /* keepalives disabled either by configuration or for passive IKE_SAs */
+ return;
+ }
+ if (!(this->conditions & COND_NAT_HERE) || (this->conditions & COND_STALE))
+ { /* disable keepalives if we are not NATed anymore, or the SA is stale */
return;
}
@@ -514,9 +655,12 @@ METHOD(ike_sa_t, send_keepalive, void,
charon->sender->send_no_marker(charon->sender, packet);
diff = 0;
}
- job = send_keepalive_job_create(this->ike_sa_id);
- lib->scheduler->schedule_job(lib->scheduler, (job_t*)job,
- this->keepalive_interval - diff);
+ if (!this->keepalive_job)
+ {
+ this->keepalive_job = send_keepalive_job_create(this->ike_sa_id);
+ lib->scheduler->schedule_job(lib->scheduler, (job_t*)this->keepalive_job,
+ this->keepalive_interval - diff);
+ }
}
METHOD(ike_sa_t, get_ike_cfg, ike_cfg_t*,
@@ -563,7 +707,7 @@ METHOD(ike_sa_t, set_condition, void,
case COND_NAT_HERE:
DBG1(DBG_IKE, "local host is behind NAT, sending keep alives");
this->conditions |= COND_NAT_ANY;
- send_keepalive(this);
+ send_keepalive(this, FALSE);
break;
case COND_NAT_THERE:
DBG1(DBG_IKE, "remote host is behind NAT");
@@ -590,6 +734,9 @@ METHOD(ike_sa_t, set_condition, void,
has_condition(this, COND_NAT_THERE) ||
has_condition(this, COND_NAT_FAKE));
break;
+ case COND_STALE:
+ send_keepalive(this, FALSE);
+ break;
default:
break;
}
@@ -727,6 +874,8 @@ METHOD(ike_sa_t, set_state, void,
{
keepalives = TRUE;
}
+ DESTROY_IF(this->redirected_from);
+ this->redirected_from = NULL;
}
break;
}
@@ -749,7 +898,7 @@ METHOD(ike_sa_t, set_state, void,
}
if (keepalives)
{
- send_keepalive(this);
+ send_keepalive(this, FALSE);
}
}
@@ -786,12 +935,12 @@ METHOD(ike_sa_t, add_virtual_ip, void,
{
char *iface;
- if (hydra->kernel_interface->get_interface(hydra->kernel_interface,
- this->my_host, &iface))
+ if (charon->kernel->get_interface(charon->kernel, this->my_host,
+ &iface))
{
DBG1(DBG_IKE, "installing new virtual IP %H", ip);
- if (hydra->kernel_interface->add_ip(hydra->kernel_interface,
- ip, -1, iface) == SUCCESS)
+ if (charon->kernel->add_ip(charon->kernel, ip, -1,
+ iface) == SUCCESS)
{
array_insert_create(&this->my_vips, ARRAY_TAIL, ip->clone(ip));
}
@@ -828,8 +977,7 @@ METHOD(ike_sa_t, clear_virtual_ips, void,
{
if (local)
{
- hydra->kernel_interface->del_ip(hydra->kernel_interface,
- vip, -1, TRUE);
+ charon->kernel->del_ip(charon->kernel, vip, -1, TRUE);
}
vip->destroy(vip);
}
@@ -1265,8 +1413,8 @@ static void resolve_hosts(private_ike_sa_t *this)
!this->other_host->is_anyaddr(this->other_host))
{
host->destroy(host);
- host = hydra->kernel_interface->get_source_addr(
- hydra->kernel_interface, this->other_host, NULL);
+ host = charon->kernel->get_source_addr(charon->kernel,
+ this->other_host, NULL);
if (host)
{
host->set_port(host, this->ike_cfg->get_my_port(this->ike_cfg));
@@ -1401,9 +1549,14 @@ METHOD(ike_sa_t, process_message, status_t,
status = this->task_manager->process_message(this->task_manager, message);
if (this->flush_auth_cfg && this->state == IKE_ESTABLISHED)
{
- /* authentication completed */
- this->flush_auth_cfg = FALSE;
- flush_auth_cfgs(this);
+ /* authentication completed but if the online validation is suspended we
+ * need the auth cfgs until we did the delayed verification, we flush
+ * them afterwards */
+ if (!has_condition(this, COND_ONLINE_VALIDATION_SUSPENDED))
+ {
+ this->flush_auth_cfg = FALSE;
+ flush_auth_cfgs(this);
+ }
}
return status;
}
@@ -1735,6 +1888,86 @@ static bool is_child_queued(private_ike_sa_t *this, task_queue_t queue)
return found;
}
+/**
+ * Reestablish CHILD_SAs and migrate queued tasks.
+ *
+ * If force is true all SAs are restarted, otherwise their close/dpd_action
+ * is followed.
+ */
+static status_t reestablish_children(private_ike_sa_t *this, ike_sa_t *new,
+ bool force)
+{
+ enumerator_t *enumerator;
+ child_sa_t *child_sa;
+ child_cfg_t *child_cfg;
+ action_t action;
+ status_t status = FAILED;
+
+ /* handle existing CHILD_SAs */
+ enumerator = create_child_sa_enumerator(this);
+ while (enumerator->enumerate(enumerator, (void**)&child_sa))
+ {
+ if (force)
+ {
+ switch (child_sa->get_state(child_sa))
+ {
+ case CHILD_ROUTED:
+ { /* move routed child directly */
+ remove_child_sa(this, enumerator);
+ new->add_child_sa(new, child_sa);
+ action = ACTION_NONE;
+ break;
+ }
+ default:
+ { /* initiate/queue all other CHILD_SAs */
+ action = ACTION_RESTART;
+ break;
+ }
+ }
+ }
+ else
+ { /* only restart CHILD_SAs that are configured accordingly */
+ if (this->state == IKE_DELETING)
+ {
+ action = child_sa->get_close_action(child_sa);
+ }
+ else
+ {
+ action = child_sa->get_dpd_action(child_sa);
+ }
+ }
+ switch (action)
+ {
+ case ACTION_RESTART:
+ child_cfg = child_sa->get_config(child_sa);
+ DBG1(DBG_IKE, "restarting CHILD_SA %s",
+ child_cfg->get_name(child_cfg));
+ child_cfg->get_ref(child_cfg);
+ status = new->initiate(new, child_cfg,
+ child_sa->get_reqid(child_sa), NULL, NULL);
+ break;
+ default:
+ continue;
+ }
+ if (status == DESTROY_ME)
+ {
+ break;
+ }
+ }
+ enumerator->destroy(enumerator);
+ /* adopt any active or queued CHILD-creating tasks */
+ if (status != DESTROY_ME)
+ {
+ task_manager_t *other_tasks = ((private_ike_sa_t*)new)->task_manager;
+ other_tasks->adopt_child_tasks(other_tasks, this->task_manager);
+ if (new->get_state(new) == IKE_CREATED)
+ {
+ status = new->initiate(new, NULL, 0, NULL, NULL);
+ }
+ }
+ return status;
+}
+
METHOD(ike_sa_t, reestablish, status_t,
private_ike_sa_t *this)
{
@@ -1743,7 +1976,6 @@ METHOD(ike_sa_t, reestablish, status_t,
action_t action;
enumerator_t *enumerator;
child_sa_t *child_sa;
- child_cfg_t *child_cfg;
bool restart = FALSE;
status_t status = FAILED;
@@ -1836,8 +2068,11 @@ METHOD(ike_sa_t, reestablish, status_t,
host = this->my_host;
new->set_my_host(new, host->clone(host));
charon->bus->ike_reestablish_pre(charon->bus, &this->public, new);
- /* resolve hosts but use the old addresses above as fallback */
- resolve_hosts((private_ike_sa_t*)new);
+ if (!has_condition(this, COND_REAUTHENTICATING))
+ { /* reauthenticate to the same addresses, but resolve hosts if
+ * reestablishing (old addresses serve as fallback) */
+ resolve_hosts((private_ike_sa_t*)new);
+ }
/* if we already have a virtual IP, we reuse it */
enumerator = array_create_enumerator(this->my_vips);
while (enumerator->enumerate(enumerator, &host))
@@ -1854,68 +2089,8 @@ METHOD(ike_sa_t, reestablish, status_t,
else
#endif /* ME */
{
- /* handle existing CHILD_SAs */
- enumerator = create_child_sa_enumerator(this);
- while (enumerator->enumerate(enumerator, (void**)&child_sa))
- {
- if (has_condition(this, COND_REAUTHENTICATING))
- {
- switch (child_sa->get_state(child_sa))
- {
- case CHILD_ROUTED:
- { /* move routed child directly */
- remove_child_sa(this, enumerator);
- new->add_child_sa(new, child_sa);
- action = ACTION_NONE;
- break;
- }
- default:
- { /* initiate/queue all other CHILD_SAs */
- action = ACTION_RESTART;
- break;
- }
- }
- }
- else
- { /* only restart CHILD_SAs that are configured accordingly */
- if (this->state == IKE_DELETING)
- {
- action = child_sa->get_close_action(child_sa);
- }
- else
- {
- action = child_sa->get_dpd_action(child_sa);
- }
- }
- switch (action)
- {
- case ACTION_RESTART:
- child_cfg = child_sa->get_config(child_sa);
- DBG1(DBG_IKE, "restarting CHILD_SA %s",
- child_cfg->get_name(child_cfg));
- child_cfg->get_ref(child_cfg);
- status = new->initiate(new, child_cfg,
- child_sa->get_reqid(child_sa), NULL, NULL);
- break;
- default:
- continue;
- }
- if (status == DESTROY_ME)
- {
- break;
- }
- }
- enumerator->destroy(enumerator);
- /* adopt any active or queued CHILD-creating tasks */
- if (status != DESTROY_ME)
- {
- task_manager_t *other_tasks = ((private_ike_sa_t*)new)->task_manager;
- other_tasks->adopt_child_tasks(other_tasks, this->task_manager);
- if (new->get_state(new) == IKE_CREATED)
- {
- status = new->initiate(new, NULL, 0, NULL, NULL);
- }
- }
+ status = reestablish_children(this, new,
+ has_condition(this, COND_REAUTHENTICATING));
}
if (status == DESTROY_ME)
@@ -1936,6 +2111,195 @@ METHOD(ike_sa_t, reestablish, status_t,
return status;
}
+/**
+ * Resolve the given gateway ID
+ */
+static host_t *resolve_gateway_id(identification_t *gateway)
+{
+ char gw[BUF_LEN];
+ host_t *addr;
+
+ snprintf(gw, sizeof(gw), "%Y", gateway);
+ gw[sizeof(gw)-1] = '\0';
+ addr = host_create_from_dns(gw, AF_UNSPEC, IKEV2_UDP_PORT);
+ if (!addr)
+ {
+ DBG1(DBG_IKE, "unable to resolve gateway ID '%Y', redirect failed",
+ gateway);
+ }
+ return addr;
+}
+
+/**
+ * Redirect the current SA to the given target host
+ */
+static bool redirect_established(private_ike_sa_t *this, identification_t *to)
+{
+ private_ike_sa_t *new_priv;
+ ike_sa_t *new;
+ host_t *other;
+ time_t redirect;
+
+ new = charon->ike_sa_manager->checkout_new(charon->ike_sa_manager,
+ this->version, TRUE);
+ if (!new)
+ {
+ return FALSE;
+ }
+ new_priv = (private_ike_sa_t*)new;
+ new->set_peer_cfg(new, this->peer_cfg);
+ new_priv->redirected_from = this->other_host->clone(this->other_host);
+ charon->bus->ike_reestablish_pre(charon->bus, &this->public, new);
+ other = resolve_gateway_id(to);
+ if (other)
+ {
+ set_my_host(new_priv, this->my_host->clone(this->my_host));
+ /* this allows us to force the remote address while we still properly
+ * resolve the local address */
+ new_priv->remote_host = other;
+ resolve_hosts(new_priv);
+ new_priv->redirected_at = array_create(sizeof(time_t), MAX_REDIRECTS);
+ while (array_remove(this->redirected_at, ARRAY_HEAD, &redirect))
+ {
+ array_insert(new_priv->redirected_at, ARRAY_TAIL, &redirect);
+ }
+ if (reestablish_children(this, new, TRUE) != DESTROY_ME)
+ {
+#ifdef USE_IKEV2
+ new->queue_task(new, (task_t*)ike_reauth_complete_create(new,
+ this->ike_sa_id));
+#endif
+ charon->bus->ike_reestablish_post(charon->bus, &this->public, new,
+ TRUE);
+ charon->ike_sa_manager->checkin(charon->ike_sa_manager, new);
+ charon->bus->set_sa(charon->bus, &this->public);
+ return TRUE;
+ }
+ }
+ charon->bus->ike_reestablish_post(charon->bus, &this->public, new,
+ FALSE);
+ charon->ike_sa_manager->checkin_and_destroy(charon->ike_sa_manager, new);
+ charon->bus->set_sa(charon->bus, &this->public);
+ return FALSE;
+}
+
+/**
+ * Redirect the current connecting SA to the given target host
+ */
+static bool redirect_connecting(private_ike_sa_t *this, identification_t *to)
+{
+ host_t *other;
+
+ other = resolve_gateway_id(to);
+ if (!other)
+ {
+ return FALSE;
+ }
+ reset(this);
+ DESTROY_IF(this->redirected_from);
+ this->redirected_from = this->other_host->clone(this->other_host);
+ DESTROY_IF(this->remote_host);
+ /* this allows us to force the remote address while we still properly
+ * resolve the local address */
+ this->remote_host = other;
+ resolve_hosts(this);
+ return TRUE;
+}
+
+/**
+ * Check if the current redirect exceeds the limits for redirects
+ */
+static bool redirect_count_exceeded(private_ike_sa_t *this)
+{
+ time_t now, redirect;
+
+ now = time_monotonic(NULL);
+ /* remove entries outside the defined period */
+ while (array_get(this->redirected_at, ARRAY_HEAD, &redirect) &&
+ now - redirect >= REDIRECT_LOOP_DETECT_PERIOD)
+ {
+ array_remove(this->redirected_at, ARRAY_HEAD, NULL);
+ }
+ if (array_count(this->redirected_at) < MAX_REDIRECTS)
+ {
+ if (!this->redirected_at)
+ {
+ this->redirected_at = array_create(sizeof(time_t), MAX_REDIRECTS);
+ }
+ array_insert(this->redirected_at, ARRAY_TAIL, &now);
+ return FALSE;
+ }
+ return TRUE;
+}
+
+METHOD(ike_sa_t, handle_redirect, bool,
+ private_ike_sa_t *this, identification_t *gateway)
+{
+ DBG1(DBG_IKE, "redirected to %Y", gateway);
+ if (!this->follow_redirects)
+ {
+ DBG1(DBG_IKE, "server sent REDIRECT even though we disabled it");
+ return FALSE;
+ }
+ if (redirect_count_exceeded(this))
+ {
+ DBG1(DBG_IKE, "only %d redirects are allowed within %d seconds",
+ MAX_REDIRECTS, REDIRECT_LOOP_DETECT_PERIOD);
+ return FALSE;
+ }
+
+ switch (this->state)
+ {
+ case IKE_CONNECTING:
+ return redirect_connecting(this, gateway);
+ case IKE_ESTABLISHED:
+ return redirect_established(this, gateway);
+ default:
+ DBG1(DBG_IKE, "unable to handle redirect for IKE_SA in state %N",
+ ike_sa_state_names, this->state);
+ return FALSE;
+ }
+}
+
+METHOD(ike_sa_t, redirect, status_t,
+ private_ike_sa_t *this, identification_t *gateway)
+{
+ switch (this->state)
+ {
+ case IKE_CONNECTING:
+ case IKE_ESTABLISHED:
+ case IKE_REKEYING:
+ if (has_condition(this, COND_REDIRECTED))
+ { /* IKE_SA already got redirected */
+ return SUCCESS;
+ }
+ if (has_condition(this, COND_ORIGINAL_INITIATOR))
+ {
+ DBG1(DBG_IKE, "unable to redirect IKE_SA as initiator");
+ return FAILED;
+ }
+ if (this->version == IKEV1)
+ {
+ DBG1(DBG_IKE, "unable to redirect IKEv1 SA");
+ return FAILED;
+ }
+ if (!supports_extension(this, EXT_IKE_REDIRECTION))
+ {
+ DBG1(DBG_IKE, "client does not support IKE redirection");
+ return FAILED;
+ }
+#ifdef USE_IKEV2
+ this->task_manager->queue_task(this->task_manager,
+ (task_t*)ike_redirect_create(&this->public, gateway));
+#endif
+ return this->task_manager->initiate(this->task_manager);
+ default:
+ DBG1(DBG_IKE, "unable to redirect IKE_SA in state %N",
+ ike_sa_state_names, this->state);
+ return INVALID_STATE;
+ }
+}
+
METHOD(ike_sa_t, retransmit, status_t,
private_ike_sa_t *this, u_int32_t message_id)
{
@@ -2067,8 +2431,8 @@ static bool is_current_path_valid(private_ike_sa_t *this)
{
bool valid = FALSE;
host_t *src;
- src = hydra->kernel_interface->get_source_addr(hydra->kernel_interface,
- this->other_host, this->my_host);
+ src = charon->kernel->get_source_addr(charon->kernel, this->other_host,
+ this->my_host);
if (src)
{
if (src->ip_equals(src, this->my_host))
@@ -2112,8 +2476,7 @@ static bool is_any_path_valid(private_ike_sa_t *this)
continue;
}
DBG1(DBG_IKE, "looking for a route to %H ...", addr);
- src = hydra->kernel_interface->get_source_addr(
- hydra->kernel_interface, addr, NULL);
+ src = charon->kernel->get_source_addr(charon->kernel, addr, NULL);
if (src)
{
break;
@@ -2323,7 +2686,7 @@ METHOD(ike_sa_t, inherit_post, void,
this->conditions = other->conditions;
if (this->conditions & COND_NAT_HERE)
{
- send_keepalive(this);
+ send_keepalive(this, FALSE);
}
#ifdef ME
@@ -2401,7 +2764,7 @@ METHOD(ike_sa_t, destroy, void,
}
while (array_remove(this->my_vips, ARRAY_TAIL, &vip))
{
- hydra->kernel_interface->del_ip(hydra->kernel_interface, vip, -1, TRUE);
+ charon->kernel->del_ip(charon->kernel, vip, -1, TRUE);
vip->destroy(vip);
}
if (array_count(this->other_vips))
@@ -2450,6 +2813,8 @@ METHOD(ike_sa_t, destroy, void,
DESTROY_IF(this->other_id);
DESTROY_IF(this->local_host);
DESTROY_IF(this->remote_host);
+ DESTROY_IF(this->redirected_from);
+ array_destroy(this->redirected_at);
DESTROY_IF(this->ike_cfg);
DESTROY_IF(this->peer_cfg);
@@ -2498,6 +2863,7 @@ ike_sa_t * ike_sa_create(ike_sa_id_t *ike_sa_id, bool initiator,
.set_peer_cfg = _set_peer_cfg,
.get_auth_cfg = _get_auth_cfg,
.create_auth_cfg_enumerator = _create_auth_cfg_enumerator,
+ .verify_peer_certificate = _verify_peer_certificate,
.add_auth_cfg = _add_auth_cfg,
.get_proposal = _get_proposal,
.set_proposal = _set_proposal,
@@ -2529,6 +2895,9 @@ ike_sa_t * ike_sa_create(ike_sa_id_t *ike_sa_id, bool initiator,
.destroy = _destroy,
.send_dpd = _send_dpd,
.send_keepalive = _send_keepalive,
+ .redirect = _redirect,
+ .handle_redirect = _handle_redirect,
+ .get_redirected_from = _get_redirected_from,
.get_keymat = _get_keymat,
.add_child_sa = _add_child_sa,
.get_child_sa = _get_child_sa,
@@ -2594,6 +2963,8 @@ ike_sa_t * ike_sa_create(ike_sa_id_t *ike_sa_id, bool initiator,
"%s.flush_auth_cfg", FALSE, lib->ns),
.fragment_size = lib->settings->get_int(lib->settings,
"%s.fragment_size", 0, lib->ns),
+ .follow_redirects = lib->settings->get_bool(lib->settings,
+ "%s.follow_redirects", TRUE, lib->ns),
);
if (version == IKEV2)