Merge branch 'ike-redirect'

This adds support for IKEv2 redirection (RFC 5685).  There is currently
no default implementation of the redirect_provider_t interface provided.
Plugins may implement the interface to decide if and when to redirect
connecting clients.  It is also possible to redirect established IKE_SAs
via VICI/swanctl.
This commit is contained in:
Tobias Brunner
2016-03-04 16:03:07 +01:00
50 changed files with 2168 additions and 122 deletions
+3
View File
@@ -97,6 +97,9 @@ charon.flush_auth_cfg = no
this might conflict with plugins that later need access to e.g. the used
certificates.
charon.follow_redirects = yes
Whether to follow IKEv2 redirects (RFC 5685).
charon.fragment_size = 0
Maximum size (complete IP datagram size in bytes) of a sent IKE fragment
when using proprietary IKEv1 or standardized IKEv2 fragmentation (0 for
+3
View File
@@ -59,6 +59,7 @@ processing/jobs/delete_child_sa_job.c processing/jobs/delete_child_sa_job.h \
processing/jobs/delete_ike_sa_job.c processing/jobs/delete_ike_sa_job.h \
processing/jobs/migrate_job.c processing/jobs/migrate_job.h \
processing/jobs/process_message_job.c processing/jobs/process_message_job.h \
processing/jobs/redirect_job.c processing/jobs/redirect_job.h \
processing/jobs/rekey_child_sa_job.c processing/jobs/rekey_child_sa_job.h \
processing/jobs/rekey_ike_sa_job.c processing/jobs/rekey_ike_sa_job.h \
processing/jobs/retransmit_job.c processing/jobs/retransmit_job.h \
@@ -84,6 +85,7 @@ sa/child_sa_manager.c sa/child_sa_manager.h \
sa/task_manager.h sa/task_manager.c \
sa/shunt_manager.c sa/shunt_manager.h \
sa/trap_manager.c sa/trap_manager.h \
sa/redirect_provider.h sa/redirect_manager.c sa/redirect_manager.h \
sa/task.c sa/task.h
libcharon_la_SOURCES += \
@@ -107,6 +109,7 @@ sa/ikev2/tasks/ike_mobike.c sa/ikev2/tasks/ike_mobike.h \
sa/ikev2/tasks/ike_rekey.c sa/ikev2/tasks/ike_rekey.h \
sa/ikev2/tasks/ike_reauth.c sa/ikev2/tasks/ike_reauth.h \
sa/ikev2/tasks/ike_reauth_complete.c sa/ikev2/tasks/ike_reauth_complete.h \
sa/ikev2/tasks/ike_redirect.c sa/ikev2/tasks/ike_redirect.h \
sa/ikev2/tasks/ike_auth_lifetime.c sa/ikev2/tasks/ike_auth_lifetime.h \
sa/ikev2/tasks/ike_vendor.c sa/ikev2/tasks/ike_vendor.h
+3
View File
@@ -58,6 +58,7 @@ processing/jobs/delete_child_sa_job.c processing/jobs/delete_child_sa_job.h \
processing/jobs/delete_ike_sa_job.c processing/jobs/delete_ike_sa_job.h \
processing/jobs/migrate_job.c processing/jobs/migrate_job.h \
processing/jobs/process_message_job.c processing/jobs/process_message_job.h \
processing/jobs/redirect_job.c processing/jobs/redirect_job.h \
processing/jobs/rekey_child_sa_job.c processing/jobs/rekey_child_sa_job.h \
processing/jobs/rekey_ike_sa_job.c processing/jobs/rekey_ike_sa_job.h \
processing/jobs/retransmit_job.c processing/jobs/retransmit_job.h \
@@ -83,6 +84,7 @@ sa/child_sa_manager.c sa/child_sa_manager.h \
sa/task_manager.h sa/task_manager.c \
sa/shunt_manager.c sa/shunt_manager.h \
sa/trap_manager.c sa/trap_manager.h \
sa/redirect_provider.h sa/redirect_manager.c sa/redirect_manager.h \
sa/task.c sa/task.h
if USE_IKEV2
@@ -107,6 +109,7 @@ sa/ikev2/tasks/ike_mobike.c sa/ikev2/tasks/ike_mobike.h \
sa/ikev2/tasks/ike_rekey.c sa/ikev2/tasks/ike_rekey.h \
sa/ikev2/tasks/ike_reauth.c sa/ikev2/tasks/ike_reauth.h \
sa/ikev2/tasks/ike_reauth_complete.c sa/ikev2/tasks/ike_reauth_complete.h \
sa/ikev2/tasks/ike_redirect.c sa/ikev2/tasks/ike_redirect.h \
sa/ikev2/tasks/ike_auth_lifetime.c sa/ikev2/tasks/ike_auth_lifetime.h \
sa/ikev2/tasks/ike_vendor.c sa/ikev2/tasks/ike_vendor.h
endif
+2
View File
@@ -680,6 +680,7 @@ static void destroy(private_daemon_t *this)
DESTROY_IF(this->kernel_handler);
DESTROY_IF(this->public.traps);
DESTROY_IF(this->public.shunts);
DESTROY_IF(this->public.redirect);
DESTROY_IF(this->public.controller);
DESTROY_IF(this->public.eap);
DESTROY_IF(this->public.xauth);
@@ -872,6 +873,7 @@ private_daemon_t *daemon_create()
this->public.socket = socket_manager_create();
this->public.traps = trap_manager_create();
this->public.shunts = shunt_manager_create();
this->public.redirect = redirect_manager_create();
this->kernel_handler = kernel_handler_create();
return this;
+6
View File
@@ -190,6 +190,7 @@ typedef struct daemon_t daemon_t;
#include <sa/child_sa_manager.h>
#include <sa/trap_manager.h>
#include <sa/shunt_manager.h>
#include <sa/redirect_manager.h>
#include <config/backend_manager.h>
#include <sa/eap/eap_manager.h>
#include <sa/xauth/xauth_manager.h>
@@ -264,6 +265,11 @@ struct daemon_t {
*/
shunt_manager_t *shunts;
/**
* Manager for IKE redirect providers
*/
redirect_manager_t *redirect;
/**
* Manager for the different configuration backends.
*/
+17
View File
@@ -289,6 +289,23 @@ Terminates an SA while streaming _control-log_ events.
The default timeout of 0 waits indefinitely for a result, and a timeout value
of -1 returns a result immediately.
### redirect() ###
Redirect a client-initiated IKE_SA to another gateway. Only for IKEv2 and if
supported by the peer.
{
ike = <redirect an IKE_SA by configuration name>
ike-id = <redirect an IKE_SA by its unique id>
peer-ip = <redirect an IKE_SA with matching peer IP, may also be a
subnet in CIDR notation or an IP range>
peer-id = <redirect an IKE_SA with matching peer identity, may contain
wildcards>
} => {
success = <yes or no>
errmsg = <error string on failure>
}
### install() ###
Install a trap, drop or bypass policy defined by a CHILD_SA config.
@@ -36,6 +36,10 @@ sub terminate {
return request_vars_res('terminate', @_);
}
sub redirect {
return request_vars_res('redirect', @_);
}
sub install {
return request_vars_res('install', @_);
}
@@ -53,6 +53,14 @@ class Session(object):
"""
return self.handler.streamed_request("terminate", "control-log", sa)
def redirect(self, sa):
"""Redirect an IKE_SA.
:param sa: the SA to redirect
:type sa: dict
"""
self.handler.request("redirect", sa)
def install(self, policy):
"""Install a trap, drop or bypass policy defined by a CHILD_SA config.
@@ -504,6 +504,12 @@ module Vici
"control-log", &block))
end
##
# Redirect an IKE_SA.
def redirect(options)
check_success(@transp.request("redirect", Message.new(options)))
end
##
# Install a shunt/route policy.
def install(policy)
+149
View File
@@ -1,4 +1,7 @@
/*
* Copyright (C) 2015 Tobias Brunner
* Hochschule fuer Technik Rapperswil
*
* Copyright (C) 2014 Martin Willi
* Copyright (C) 2014 revosec AG
*
@@ -20,6 +23,7 @@
#include <daemon.h>
#include <collections/array.h>
#include <processing/jobs/redirect_job.h>
typedef struct private_vici_control_t private_vici_control_t;
@@ -356,6 +360,150 @@ CALLBACK(terminate, vici_message_t*,
return builder->finalize(builder);
}
/**
* Parse a peer-ip specified, which can be a subnet in CIDR notation, a range
* or a single IP address.
*/
static traffic_selector_t *parse_peer_ip(char *ip)
{
traffic_selector_t *ts;
host_t *from, *to;
ts_type_t type;
if (host_create_from_range(ip, &from, &to))
{
if (to->get_family(to) == AF_INET)
{
type = TS_IPV4_ADDR_RANGE;
}
else
{
type = TS_IPV6_ADDR_RANGE;
}
ts = traffic_selector_create_from_bytes(0, type,
from->get_address(from), 0,
to->get_address(to), 0xFFFF);
from->destroy(from);
to->destroy(to);
return ts;
}
return traffic_selector_create_from_cidr(ip, 0, 0, 0xFFFF);
}
CALLBACK(redirect, vici_message_t*,
private_vici_control_t *this, char *name, u_int id, vici_message_t *request)
{
enumerator_t *sas;
char *ike, *peer_ip, *peer_id, *gw, *errmsg = NULL;
u_int ike_id, current, found = 0;
identification_t *gateway, *identity = NULL, *other_id;
traffic_selector_t *ts = NULL;
ike_sa_t *ike_sa;
vici_builder_t *builder;
ike = request->get_str(request, NULL, "ike");
ike_id = request->get_int(request, 0, "ike-id");
peer_ip = request->get_str(request, NULL, "peer-ip");
peer_id = request->get_str(request, NULL, "peer-id");
gw = request->get_str(request, NULL, "gateway");
if (!gw || !(gateway = identification_create_from_string(gw)))
{
return send_reply(this, "missing target gateway");
}
switch (gateway->get_type(gateway))
{
case ID_IPV4_ADDR:
case ID_IPV6_ADDR:
case ID_FQDN:
break;
default:
return send_reply(this, "unsupported gateway identity");
}
if (peer_ip)
{
ts = parse_peer_ip(peer_ip);
if (!ts)
{
return send_reply(this, "invalid peer IP selector");
}
DBG1(DBG_CFG, "vici redirect IKE_SAs with src %R to %Y", ts,
gateway);
}
if (peer_id)
{
identity = identification_create_from_string(peer_id);
if (!identity)
{
DESTROY_IF(ts);
return send_reply(this, "invalid peer identity selector");
}
DBG1(DBG_CFG, "vici redirect IKE_SAs with ID '%Y' to %Y", identity,
gateway);
}
if (ike_id)
{
DBG1(DBG_CFG, "vici redirect IKE_SA #%d to '%Y'", ike_id, gateway);
}
if (ike)
{
DBG1(DBG_CFG, "vici redirect IKE_SA '%s' to '%Y'", ike, gateway);
}
if (!peer_ip && !peer_id && !ike && !ike_id)
{
return send_reply(this, "missing redirect selector");
}
sas = charon->controller->create_ike_sa_enumerator(charon->controller, TRUE);
while (sas->enumerate(sas, &ike_sa))
{
if (ike_sa->get_version(ike_sa) != IKEV2)
{
continue;
}
current = ike_sa->get_unique_id(ike_sa);
if (ike_id && ike_id != current)
{
continue;
}
if (ike && !streq(ike, ike_sa->get_name(ike_sa)))
{
continue;
}
if (ts && !ts->includes(ts, ike_sa->get_other_host(ike_sa)))
{
continue;
}
if (identity)
{
other_id = ike_sa->get_other_eap_id(ike_sa);
if (!other_id->matches(other_id, identity))
{
continue;
}
}
lib->processor->queue_job(lib->processor,
(job_t*)redirect_job_create(ike_sa->get_id(ike_sa), gateway));
found++;
}
sas->destroy(sas);
builder = vici_builder_create();
if (!found)
{
errmsg = "no matching SAs to redirect found";
}
builder->add_kv(builder, "success", errmsg ? "no" : "yes");
if (errmsg)
{
builder->add_kv(builder, "errmsg", "%s", errmsg);
}
gateway->destroy(gateway);
DESTROY_IF(identity);
DESTROY_IF(ts);
return builder->finalize(builder);
}
/**
* Find reqid of an existing CHILD_SA
*/
@@ -498,6 +646,7 @@ static void manage_commands(private_vici_control_t *this, bool reg)
{
manage_command(this, "initiate", initiate, reg);
manage_command(this, "terminate", terminate, reg);
manage_command(this, "redirect", redirect, reg);
manage_command(this, "install", install, reg);
manage_command(this, "uninstall", uninstall, reg);
manage_command(this, "reload-settings", reload_settings, reg);
@@ -0,0 +1,106 @@
/*
* Copyright (C) 2015 Tobias Brunner
* Hochschule fuer Technik Rapperswil
*
* 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.
*/
#include <daemon.h>
#include "redirect_job.h"
typedef struct private_redirect_job_t private_redirect_job_t;
/**
* Private data
*/
struct private_redirect_job_t {
/**
* Public interface
*/
redirect_job_t public;
/**
* ID of the IKE_SA to redirect
*/
ike_sa_id_t *ike_sa_id;
/**
* Target gateway identity
*/
identification_t *gateway;
};
METHOD(job_t, destroy, void,
private_redirect_job_t *this)
{
this->ike_sa_id->destroy(this->ike_sa_id);
this->gateway->destroy(this->gateway);
free(this);
}
METHOD(job_t, execute, job_requeue_t,
private_redirect_job_t *this)
{
ike_sa_t *ike_sa;
ike_sa = charon->ike_sa_manager->checkout(charon->ike_sa_manager,
this->ike_sa_id);
if (ike_sa)
{
if (ike_sa->get_state(ike_sa) == IKE_PASSIVE)
{
charon->ike_sa_manager->checkin(charon->ike_sa_manager, ike_sa);
return JOB_REQUEUE_NONE;
}
if (ike_sa->redirect(ike_sa, this->gateway) == DESTROY_ME)
{
charon->ike_sa_manager->checkin_and_destroy(
charon->ike_sa_manager, ike_sa);
}
else
{
charon->ike_sa_manager->checkin(charon->ike_sa_manager, ike_sa);
}
}
return JOB_REQUEUE_NONE;
}
METHOD(job_t, get_priority, job_priority_t,
private_redirect_job_t *this)
{
return JOB_PRIO_MEDIUM;
}
/*
* Described in header
*/
redirect_job_t *redirect_job_create(ike_sa_id_t *ike_sa_id,
identification_t *gateway)
{
private_redirect_job_t *this;
INIT(this,
.public = {
.job_interface = {
.execute = _execute,
.get_priority = _get_priority,
.destroy = _destroy,
},
},
.ike_sa_id = ike_sa_id->clone(ike_sa_id),
.gateway = gateway->clone(gateway),
);
return &(this->public);
}
@@ -0,0 +1,51 @@
/*
* Copyright (C) 2015 Tobias Brunner
* Hochschule fuer Technik Rapperswil
*
* 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.
*/
/**
* @defgroup redirect_job redirect_job
* @{ @ingroup cjobs
*/
#ifndef REDIRECT_JOB_H_
#define REDIRECT_JOB_H_
typedef struct redirect_job_t redirect_job_t;
#include <library.h>
#include <sa/ike_sa_id.h>
#include <processing/jobs/job.h>
/**
* Job used to redirect an IKE_SA.
*/
struct redirect_job_t {
/**
* The job_t interface.
*/
job_t job_interface;
};
/**
* Creates a job to redirect an IKE_SA.
*
* @param ike_sa_id id of the IKE_SA to redirect (cloned)
* @param gateway gateway identity (IP or FQDN) of target (cloned)
* @return created redirect_job_t object
*/
redirect_job_t *redirect_job_create(ike_sa_id_t *ike_sa_id,
identification_t *gateway);
#endif /** REDIRECT_JOB_H_ @}*/
+308 -65
View File
@@ -56,6 +56,8 @@
#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>
#ifdef ME
#include <sa/ikev2/tasks/ike_me.h>
@@ -282,6 +284,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;
};
/**
@@ -386,6 +403,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)
{
@@ -743,6 +766,8 @@ METHOD(ike_sa_t, set_state, void,
{
keepalives = TRUE;
}
DESTROY_IF(this->redirected_from);
this->redirected_from = NULL;
}
break;
}
@@ -1750,6 +1775,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)
{
@@ -1758,7 +1863,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;
@@ -1851,8 +1955,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))
@@ -1869,68 +1976,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)
@@ -1951,6 +1998,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)
{
@@ -2464,6 +2700,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);
@@ -2543,6 +2781,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,
@@ -2608,6 +2849,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)
+47 -1
View File
@@ -1,5 +1,5 @@
/*
* Copyright (C) 2006-2014 Tobias Brunner
* Copyright (C) 2006-2015 Tobias Brunner
* Copyright (C) 2006 Daniel Roethlisberger
* Copyright (C) 2005-2009 Martin Willi
* Copyright (C) 2005 Jan Hutter
@@ -65,6 +65,16 @@ typedef struct ike_sa_t ike_sa_t;
*/
#define RETRY_JITTER 20
/**
* Number of redirects allowed within REDIRECT_LOOP_DETECT_PERIOD.
*/
#define MAX_REDIRECTS 5
/**
* Time period in seconds in which at most MAX_REDIRECTS are allowed.
*/
#define REDIRECT_LOOP_DETECT_PERIOD 300
/**
* Extensions (or optional features) the peer supports
*/
@@ -136,6 +146,11 @@ enum ike_extension_t {
* Signature Authentication, RFC 7427
*/
EXT_SIGNATURE_AUTH = (1<<12),
/**
* IKEv2 Redirect Mechanism, RFC 5685
*/
EXT_IKE_REDIRECTION = (1<<13),
};
/**
@@ -197,6 +212,11 @@ enum ike_condition_t {
* This IKE_SA is currently being reauthenticated
*/
COND_REAUTHENTICATING = (1<<10),
/**
* This IKE_SA has been redirected
*/
COND_REDIRECTED = (1<<11),
};
/**
@@ -842,6 +862,32 @@ struct ike_sa_t {
*/
void (*send_keepalive) (ike_sa_t *this, bool scheduled);
/**
* Redirect an active IKE_SA.
*
* @param gateway gateway ID (IP or FQDN) of the target
* @return state, including DESTROY_ME, if this IKE_SA MUST be
* destroyed
*/
status_t (*redirect)(ike_sa_t *this, identification_t *gateway);
/**
* Handle a redirect request.
*
* The behavior is different depending on the state of the IKE_SA.
*
* @param gateway gateway ID (IP or FQDN) of the target
* @return FALSE if redirect not possible, TRUE otherwise
*/
bool (*handle_redirect)(ike_sa_t *this, identification_t *gateway);
/**
* Get the address of the gateway that redirected us.
*
* @return original gateway address
*/
host_t *(*get_redirected_from)(ike_sa_t *this);
/**
* Get the keying material of this IKE_SA.
*
+85 -5
View File
@@ -1,5 +1,5 @@
/*
* Copyright (C) 2007-2014 Tobias Brunner
* Copyright (C) 2007-2015 Tobias Brunner
* Copyright (C) 2007-2010 Martin Willi
* Hochschule fuer Technik Rapperswil
*
@@ -30,6 +30,7 @@
#include <sa/ikev2/tasks/ike_rekey.h>
#include <sa/ikev2/tasks/ike_reauth.h>
#include <sa/ikev2/tasks/ike_reauth_complete.h>
#include <sa/ikev2/tasks/ike_redirect.h>
#include <sa/ikev2/tasks/ike_delete.h>
#include <sa/ikev2/tasks/ike_config.h>
#include <sa/ikev2/tasks/ike_dpd.h>
@@ -474,6 +475,11 @@ METHOD(task_manager_t, initiate, status_t,
exchange = INFORMATIONAL;
break;
}
if (activate_task(this, TASK_IKE_REDIRECT))
{
exchange = INFORMATIONAL;
break;
}
if (activate_task(this, TASK_CHILD_DELETE))
{
exchange = INFORMATIONAL;
@@ -656,6 +662,32 @@ static status_t process_response(private_task_manager_t *this,
return DESTROY_ME;
}
enumerator = array_create_enumerator(this->active_tasks);
while (enumerator->enumerate(enumerator, &task))
{
if (!task->pre_process)
{
continue;
}
switch (task->pre_process(task, message))
{
case SUCCESS:
break;
case FAILED:
default:
/* just ignore the message */
DBG1(DBG_IKE, "ignore invalid %N response",
exchange_type_names, message->get_exchange_type(message));
enumerator->destroy(enumerator);
return SUCCESS;
case DESTROY_ME:
/* critical failure, destroy IKE_SA */
enumerator->destroy(enumerator);
return DESTROY_ME;
}
}
enumerator->destroy(enumerator);
/* catch if we get resetted while processing */
this->reset = FALSE;
enumerator = array_create_enumerator(this->active_tasks);
@@ -992,6 +1024,11 @@ static status_t process_request(private_task_manager_t *this,
* invokes all the required hooks. */
task = (task_t*)ike_delete_create(
this->ike_sa, FALSE);
break;
case REDIRECT:
task = (task_t*)ike_redirect_create(
this->ike_sa, NULL);
break;
default:
break;
}
@@ -1041,6 +1078,44 @@ static status_t process_request(private_task_manager_t *this,
}
}
enumerator = array_create_enumerator(this->passive_tasks);
while (enumerator->enumerate(enumerator, &task))
{
if (!task->pre_process)
{
continue;
}
switch (task->pre_process(task, message))
{
case SUCCESS:
break;
case FAILED:
default:
/* just ignore the message */
DBG1(DBG_IKE, "ignore invalid %N request",
exchange_type_names, message->get_exchange_type(message));
enumerator->destroy(enumerator);
switch (message->get_exchange_type(message))
{
case IKE_SA_INIT:
/* no point in keeping the SA when it was created with
* an invalid IKE_SA_INIT message */
return DESTROY_ME;
default:
/* remove tasks we queued for this request */
flush_queue(this, TASK_QUEUE_PASSIVE);
/* fall-through */
case IKE_AUTH:
return NEED_MORE;
}
case DESTROY_ME:
/* critical failure, destroy IKE_SA */
enumerator->destroy(enumerator);
return DESTROY_ME;
}
}
enumerator->destroy(enumerator);
/* let the tasks process the message */
enumerator = array_create_enumerator(this->passive_tasks);
while (enumerator->enumerate(enumerator, (void*)&task))
@@ -1331,12 +1406,17 @@ METHOD(task_manager_t, process_message, status_t,
{ /* ignore messages altered to EXCHANGE_TYPE_UNDEFINED */
return SUCCESS;
}
if (process_request(this, msg) != SUCCESS)
switch (process_request(this, msg))
{
flush(this);
return DESTROY_ME;
case SUCCESS:
this->responding.mid++;
break;
case NEED_MORE:
break;
default:
flush(this);
return DESTROY_ME;
}
this->responding.mid++;
}
else if ((mid == this->responding.mid - 1) &&
array_count(this->responding.packets))
@@ -1220,6 +1220,10 @@ METHOD(task_t, build_r, status_t,
{ /* wait until all authentication round completed */
return NEED_MORE;
}
if (this->ike_sa->has_condition(this->ike_sa, COND_REDIRECTED))
{ /* no CHILD_SA is created for redirected SAs */
return SUCCESS;
}
ike_auth = TRUE;
default:
break;
+95 -49
View File
@@ -1,5 +1,5 @@
/*
* Copyright (C) 2012 Tobias Brunner
* Copyright (C) 2012-2015 Tobias Brunner
* Copyright (C) 2005-2009 Martin Willi
* Copyright (C) 2005 Jan Hutter
* Hochschule fuer Technik Rapperswil
@@ -25,6 +25,7 @@
#include <encoding/payloads/eap_payload.h>
#include <encoding/payloads/nonce_payload.h>
#include <sa/ikev2/authenticators/eap_authenticator.h>
#include <processing/jobs/delete_ike_sa_job.h>
typedef struct private_ike_auth_t private_ike_auth_t;
@@ -117,6 +118,11 @@ struct private_ike_auth_t {
* Is EAP acceptable, did we strictly authenticate peer?
*/
bool eap_acceptable;
/**
* Gateway ID if redirected
*/
identification_t *redirect_to;
};
/**
@@ -685,6 +691,7 @@ METHOD(task_t, process_r, status_t,
METHOD(task_t, build_r, status_t,
private_ike_auth_t *this, message_t *message)
{
identification_t *gateway;
auth_cfg_t *cfg;
if (message->get_exchange_type(message) == IKE_SA_INIT)
@@ -817,34 +824,56 @@ METHOD(task_t, build_r, status_t,
{
this->do_another_auth = FALSE;
}
if (!this->do_another_auth && !this->expect_another_auth)
if (this->do_another_auth || this->expect_another_auth)
{
if (charon->ike_sa_manager->check_uniqueness(charon->ike_sa_manager,
this->ike_sa, FALSE))
{
DBG1(DBG_IKE, "cancelling IKE_SA setup due to uniqueness policy");
charon->bus->alert(charon->bus, ALERT_UNIQUE_KEEP);
message->add_notify(message, TRUE, AUTHENTICATION_FAILED,
chunk_empty);
return FAILED;
}
if (!charon->bus->authorize(charon->bus, TRUE))
{
DBG1(DBG_IKE, "final authorization hook forbids IKE_SA, cancelling");
goto peer_auth_failed;
}
DBG0(DBG_IKE, "IKE_SA %s[%d] established between %H[%Y]...%H[%Y]",
this->ike_sa->get_name(this->ike_sa),
this->ike_sa->get_unique_id(this->ike_sa),
this->ike_sa->get_my_host(this->ike_sa),
this->ike_sa->get_my_id(this->ike_sa),
this->ike_sa->get_other_host(this->ike_sa),
this->ike_sa->get_other_id(this->ike_sa));
this->ike_sa->set_state(this->ike_sa, IKE_ESTABLISHED);
charon->bus->ike_updown(charon->bus, this->ike_sa, TRUE);
return SUCCESS;
return NEED_MORE;
}
return NEED_MORE;
if (charon->ike_sa_manager->check_uniqueness(charon->ike_sa_manager,
this->ike_sa, FALSE))
{
DBG1(DBG_IKE, "cancelling IKE_SA setup due to uniqueness policy");
charon->bus->alert(charon->bus, ALERT_UNIQUE_KEEP);
message->add_notify(message, TRUE, AUTHENTICATION_FAILED,
chunk_empty);
return FAILED;
}
if (!charon->bus->authorize(charon->bus, TRUE))
{
DBG1(DBG_IKE, "final authorization hook forbids IKE_SA, cancelling");
goto peer_auth_failed;
}
if (this->ike_sa->supports_extension(this->ike_sa, EXT_IKE_REDIRECTION) &&
charon->redirect->redirect_on_auth(charon->redirect, this->ike_sa,
&gateway))
{
delete_ike_sa_job_t *job;
chunk_t data;
DBG1(DBG_IKE, "redirecting peer to %Y", gateway);
data = redirect_data_create(gateway, chunk_empty);
message->add_notify(message, FALSE, REDIRECT, data);
gateway->destroy(gateway);
chunk_free(&data);
/* we use this condition to prevent the CHILD_SA from getting created */
this->ike_sa->set_condition(this->ike_sa, COND_REDIRECTED, TRUE);
/* if the peer does not delete the SA we do so after a while */
job = delete_ike_sa_job_create(this->ike_sa->get_id(this->ike_sa), TRUE);
lib->scheduler->schedule_job(lib->scheduler, (job_t*)job,
lib->settings->get_int(lib->settings,
"%s.half_open_timeout", HALF_OPEN_IKE_SA_TIMEOUT,
lib->ns));
}
DBG0(DBG_IKE, "IKE_SA %s[%d] established between %H[%Y]...%H[%Y]",
this->ike_sa->get_name(this->ike_sa),
this->ike_sa->get_unique_id(this->ike_sa),
this->ike_sa->get_my_host(this->ike_sa),
this->ike_sa->get_my_id(this->ike_sa),
this->ike_sa->get_other_host(this->ike_sa),
this->ike_sa->get_other_id(this->ike_sa));
this->ike_sa->set_state(this->ike_sa, IKE_ESTABLISHED);
charon->bus->ike_updown(charon->bus, this->ike_sa, TRUE);
return SUCCESS;
peer_auth_failed:
message->add_notify(message, TRUE, AUTHENTICATION_FAILED, chunk_empty);
@@ -964,6 +993,15 @@ METHOD(task_t, process_i, status_t,
case ME_ENDPOINT:
/* handled in ike_me task */
break;
case REDIRECT:
DESTROY_IF(this->redirect_to);
this->redirect_to = redirect_data_parse(
notify->get_notification_data(notify), NULL);
if (!this->redirect_to)
{
DBG1(DBG_IKE, "received invalid REDIRECT notify");
}
break;
default:
{
if (type <= 16383)
@@ -1094,30 +1132,35 @@ METHOD(task_t, process_i, status_t,
{
this->expect_another_auth = FALSE;
}
if (!this->expect_another_auth && !this->do_another_auth && !this->my_auth)
if (this->expect_another_auth || this->do_another_auth || this->my_auth)
{
if (!update_cfg_candidates(this, TRUE))
{
goto peer_auth_failed;
}
if (!charon->bus->authorize(charon->bus, TRUE))
{
DBG1(DBG_IKE, "final authorization hook forbids IKE_SA, "
"cancelling");
goto peer_auth_failed;
}
DBG0(DBG_IKE, "IKE_SA %s[%d] established between %H[%Y]...%H[%Y]",
this->ike_sa->get_name(this->ike_sa),
this->ike_sa->get_unique_id(this->ike_sa),
this->ike_sa->get_my_host(this->ike_sa),
this->ike_sa->get_my_id(this->ike_sa),
this->ike_sa->get_other_host(this->ike_sa),
this->ike_sa->get_other_id(this->ike_sa));
this->ike_sa->set_state(this->ike_sa, IKE_ESTABLISHED);
charon->bus->ike_updown(charon->bus, this->ike_sa, TRUE);
return SUCCESS;
return NEED_MORE;
}
return NEED_MORE;
if (!update_cfg_candidates(this, TRUE))
{
goto peer_auth_failed;
}
if (!charon->bus->authorize(charon->bus, TRUE))
{
DBG1(DBG_IKE, "final authorization hook forbids IKE_SA, "
"cancelling");
goto peer_auth_failed;
}
DBG0(DBG_IKE, "IKE_SA %s[%d] established between %H[%Y]...%H[%Y]",
this->ike_sa->get_name(this->ike_sa),
this->ike_sa->get_unique_id(this->ike_sa),
this->ike_sa->get_my_host(this->ike_sa),
this->ike_sa->get_my_id(this->ike_sa),
this->ike_sa->get_other_host(this->ike_sa),
this->ike_sa->get_other_id(this->ike_sa));
this->ike_sa->set_state(this->ike_sa, IKE_ESTABLISHED);
charon->bus->ike_updown(charon->bus, this->ike_sa, TRUE);
if (this->redirect_to)
{
this->ike_sa->handle_redirect(this->ike_sa, this->redirect_to);
}
return SUCCESS;
peer_auth_failed:
charon->bus->alert(charon->bus, ALERT_PEER_AUTH_FAILED);
@@ -1141,6 +1184,7 @@ METHOD(task_t, migrate, void,
DESTROY_IF(this->peer_cfg);
DESTROY_IF(this->my_auth);
DESTROY_IF(this->other_auth);
DESTROY_IF(this->redirect_to);
this->candidates->destroy_offset(this->candidates, offsetof(peer_cfg_t, destroy));
this->my_packet = NULL;
@@ -1149,6 +1193,7 @@ METHOD(task_t, migrate, void,
this->peer_cfg = NULL;
this->my_auth = NULL;
this->other_auth = NULL;
this->redirect_to = NULL;
this->do_another_auth = TRUE;
this->expect_another_auth = TRUE;
this->authentication_failed = FALSE;
@@ -1165,6 +1210,7 @@ METHOD(task_t, destroy, void,
DESTROY_IF(this->my_auth);
DESTROY_IF(this->other_auth);
DESTROY_IF(this->peer_cfg);
DESTROY_IF(this->redirect_to);
this->candidates->destroy_offset(this->candidates, offsetof(peer_cfg_t, destroy));
free(this);
}
@@ -333,6 +333,11 @@ METHOD(task_t, build_r, status_t,
linked_list_t *vips, *pools;
host_t *requested;
if (this->ike_sa->has_condition(this->ike_sa, COND_REDIRECTED))
{ /* don't assign attributes for redirected SAs */
return SUCCESS;
}
id = this->ike_sa->get_other_eap_id(this->ike_sa);
config = this->ike_sa->get_peer_cfg(this->ike_sa);
vips = linked_list_create();
+144
View File
@@ -118,6 +118,11 @@ struct private_ike_init_t {
* Whether to use Signature Authentication as per RFC 7427
*/
bool signature_authentication;
/**
* Whether to follow IKEv2 redirects as per RFC 5685
*/
bool follow_redirects;
};
/**
@@ -324,6 +329,29 @@ static bool build_payloads(private_ike_init_t *this, message_t *message)
send_supported_hash_algorithms(this, message);
}
}
/* notify other peer if we support redirection */
if (!this->old_sa && this->initiator && this->follow_redirects)
{
identification_t *gateway;
host_t *from;
chunk_t data;
from = this->ike_sa->get_redirected_from(this->ike_sa);
if (from)
{
gateway = identification_create_from_sockaddr(
from->get_sockaddr(from));
data = redirect_data_create(gateway, chunk_empty);
message->add_notify(message, FALSE, REDIRECTED_FROM, data);
chunk_free(&data);
gateway->destroy(gateway);
}
else
{
message->add_notify(message, FALSE, REDIRECT_SUPPORTED,
chunk_empty);
}
}
return TRUE;
}
@@ -391,6 +419,30 @@ static void process_payloads(private_ike_init_t *this, message_t *message)
handle_supported_hash_algorithms(this, notify);
}
break;
case REDIRECTED_FROM:
{
identification_t *gateway;
chunk_t data;
data = notify->get_notification_data(notify);
gateway = redirect_data_parse(data, NULL);
if (!gateway)
{
DBG1(DBG_IKE, "received invalid REDIRECTED_FROM "
"notify, ignored");
break;
}
DBG1(DBG_IKE, "client got redirected from %Y", gateway);
gateway->destroy(gateway);
/* fall-through */
}
case REDIRECT_SUPPORTED:
if (!this->old_sa)
{
this->ike_sa->enable_extension(this->ike_sa,
EXT_IKE_REDIRECTION);
}
break;
default:
/* other notifies are handled elsewhere */
break;
@@ -550,6 +602,8 @@ static bool derive_keys(private_ike_init_t *this,
METHOD(task_t, build_r, status_t,
private_ike_init_t *this, message_t *message)
{
identification_t *gateway;
/* check if we have everything we need */
if (this->proposal == NULL ||
this->other_nonce.len == 0 || this->my_nonce.len == 0)
@@ -560,6 +614,22 @@ METHOD(task_t, build_r, status_t,
}
this->ike_sa->set_proposal(this->ike_sa, this->proposal);
/* check if we'd have to redirect the client */
if (!this->old_sa &&
this->ike_sa->supports_extension(this->ike_sa, EXT_IKE_REDIRECTION) &&
charon->redirect->redirect_on_init(charon->redirect, this->ike_sa,
&gateway))
{
chunk_t data;
DBG1(DBG_IKE, "redirecting peer to %Y", gateway);
data = redirect_data_create(gateway, this->other_nonce);
message->add_notify(message, TRUE, REDIRECT, data);
gateway->destroy(gateway);
chunk_free(&data);
return FAILED;
}
if (this->dh == NULL ||
!this->proposal->has_dh_group(this->proposal, this->dh_group))
{
@@ -623,6 +693,54 @@ static void raise_alerts(private_ike_init_t *this, notify_type_t type)
}
}
METHOD(task_t, pre_process_i, status_t,
private_ike_init_t *this, message_t *message)
{
enumerator_t *enumerator;
payload_t *payload;
/* check for erroneous notifies */
enumerator = message->create_payload_enumerator(message);
while (enumerator->enumerate(enumerator, &payload))
{
if (payload->get_type(payload) == PLV2_NOTIFY)
{
notify_payload_t *notify = (notify_payload_t*)payload;
notify_type_t type = notify->get_notify_type(notify);
switch (type)
{
case REDIRECT:
{
identification_t *gateway;
chunk_t data, nonce = chunk_empty;
status_t status = SUCCESS;
if (this->old_sa)
{
break;
}
data = notify->get_notification_data(notify);
gateway = redirect_data_parse(data, &nonce);
if (!gateway || !chunk_equals(nonce, this->my_nonce))
{
DBG1(DBG_IKE, "received invalid REDIRECT notify");
status = FAILED;
}
DESTROY_IF(gateway);
chunk_free(&nonce);
enumerator->destroy(enumerator);
return status;
}
default:
break;
}
}
}
enumerator->destroy(enumerator);
return SUCCESS;
}
METHOD(task_t, process_i, status_t,
private_ike_init_t *this, message_t *message)
{
@@ -678,6 +796,29 @@ METHOD(task_t, process_i, status_t,
this->retry++;
return NEED_MORE;
}
case REDIRECT:
{
identification_t *gateway;
chunk_t data, nonce = chunk_empty;
status_t status = FAILED;
if (this->old_sa)
{
DBG1(DBG_IKE, "received REDIRECT notify during rekeying"
", ignored");
break;
}
data = notify->get_notification_data(notify);
gateway = redirect_data_parse(data, &nonce);
if (this->ike_sa->handle_redirect(this->ike_sa, gateway))
{
status = NEED_MORE;
}
DESTROY_IF(gateway);
chunk_free(&nonce);
enumerator->destroy(enumerator);
return status;
}
default:
{
if (type <= 16383)
@@ -802,6 +943,8 @@ ike_init_t *ike_init_create(ike_sa_t *ike_sa, bool initiator, ike_sa_t *old_sa)
.old_sa = old_sa,
.signature_authentication = lib->settings->get_bool(lib->settings,
"%s.signature_authentication", TRUE, lib->ns),
.follow_redirects = lib->settings->get_bool(lib->settings,
"%s.follow_redirects", TRUE, lib->ns),
);
this->nonceg = this->keymat->keymat.create_nonce_gen(&this->keymat->keymat);
@@ -809,6 +952,7 @@ ike_init_t *ike_init_create(ike_sa_t *ike_sa, bool initiator, ike_sa_t *old_sa)
{
this->public.task.build = _build_i;
this->public.task.process = _process_i;
this->public.task.pre_process = _pre_process_i;
}
else
{
+150
View File
@@ -0,0 +1,150 @@
/*
* Copyright (C) 2015 Tobias Brunner
* Hochschule fuer Technik Rapperswil
*
* 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.
*/
#include "ike_redirect.h"
#include <daemon.h>
#include <processing/jobs/delete_ike_sa_job.h>
typedef struct private_ike_redirect_t private_ike_redirect_t;
/**
* Private members
*/
struct private_ike_redirect_t {
/**
* Public interface
*/
ike_redirect_t public;
/**
* Assigned IKE_SA
*/
ike_sa_t *ike_sa;
/**
* Gateway ID to redirect to
*/
identification_t *gateway;
};
METHOD(task_t, build_i, status_t,
private_ike_redirect_t *this, message_t *message)
{
chunk_t data;
DBG1(DBG_IKE, "redirecting peer to %Y", this->gateway);
data = redirect_data_create(this->gateway, chunk_empty);
message->add_notify(message, FALSE, REDIRECT, data);
chunk_free(&data);
this->ike_sa->set_condition(this->ike_sa, COND_REDIRECTED, TRUE);
return NEED_MORE;
}
METHOD(task_t, process_r, status_t,
private_ike_redirect_t *this, message_t *message)
{
notify_payload_t *notify;
identification_t *to;
notify = message->get_notify(message, REDIRECT);
if (!notify)
{
return SUCCESS;
}
to = redirect_data_parse(notify->get_notification_data(notify), NULL);
if (!to)
{
DBG1(DBG_IKE, "received invalid REDIRECT notify");
}
else
{
this->ike_sa->handle_redirect(this->ike_sa, to);
to->destroy(to);
}
return SUCCESS;
}
METHOD(task_t, build_r, status_t,
private_ike_redirect_t *this, message_t *message)
{
/* not called because SUCCESS is returned above */
return SUCCESS;
}
METHOD(task_t, process_i, status_t,
private_ike_redirect_t *this, message_t *message)
{
delete_ike_sa_job_t *job;
/* if the peer does not delete the SA we do so after a while */
job = delete_ike_sa_job_create(this->ike_sa->get_id(this->ike_sa), TRUE);
lib->scheduler->schedule_job(lib->scheduler, (job_t*)job,
lib->settings->get_int(lib->settings,
"%s.half_open_timeout", HALF_OPEN_IKE_SA_TIMEOUT,
lib->ns));
return SUCCESS;
}
METHOD(task_t, get_type, task_type_t,
private_ike_redirect_t *this)
{
return TASK_IKE_REDIRECT;
}
METHOD(task_t, migrate, void,
private_ike_redirect_t *this, ike_sa_t *ike_sa)
{
this->ike_sa = ike_sa;
}
METHOD(task_t, destroy, void,
private_ike_redirect_t *this)
{
DESTROY_IF(this->gateway);
free(this);
}
/*
* Described in header.
*/
ike_redirect_t *ike_redirect_create(ike_sa_t *ike_sa, identification_t *to)
{
private_ike_redirect_t *this;
INIT(this,
.public = {
.task = {
.get_type = _get_type,
.build = _build_r,
.process = _process_r,
.migrate = _migrate,
.destroy = _destroy,
},
},
.ike_sa = ike_sa,
);
if (to)
{
this->gateway = to->clone(to);
this->public.task.build = _build_i;
this->public.task.process = _process_i;
}
return &this->public;
}
@@ -0,0 +1,54 @@
/*
* Copyright (C) 2015 Tobias Brunner
* Hochschule fuer Technik Rapperswil
*
* 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.
*/
/**
* @defgroup ike_redirect ike_redirect
* @{ @ingroup tasks_v2
*/
#ifndef IKE_REDIRECT_H_
#define IKE_REDIRECT_H_
typedef struct ike_redirect_t ike_redirect_t;
#include <library.h>
#include <sa/ike_sa.h>
#include <sa/task.h>
/**
* Task that handles redirection requests for established SAs.
*/
struct ike_redirect_t {
/**
* Implements the task_t interface
*/
task_t task;
};
/**
* Create a new ike_redirect_t task.
*
* As initiator (i.e. original responder) pass the ID of the target gateway,
* as responder (i.e. original initiator) this argument is NULL.
*
* @param ike_sa IKE_SA this task works for
* @param to gateway ID (gets cloned), or NULL as responder
* @return task instance
*/
ike_redirect_t *ike_redirect_create(ike_sa_t *ike_sa,
identification_t *to);
#endif /** IKE_REDIRECT_H_ @}*/
+274
View File
@@ -0,0 +1,274 @@
/*
* Copyright (C) 2015 Tobias Brunner
* Hochschule fuer Technik Rapperswil
*
* 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.
*/
#include "redirect_manager.h"
#include <collections/linked_list.h>
#include <threading/rwlock.h>
#include <bio/bio_reader.h>
#include <bio/bio_writer.h>
typedef struct private_redirect_manager_t private_redirect_manager_t;
/**
* Private data
*/
struct private_redirect_manager_t {
/**
* Public interface
*/
redirect_manager_t public;
/**
* Registered providers
*/
linked_list_t *providers;
/**
* Lock to access list of providers
*/
rwlock_t *lock;
};
/**
* Gateway identify types
*
* The encoding is the same as that for corresponding ID payloads.
*/
typedef enum {
/** IPv4 address of the VPN gateway */
GATEWAY_ID_TYPE_IPV4 = 1,
/** IPv6 address of the VPN gateway */
GATEWAY_ID_TYPE_IPV6 = 2,
/** FQDN of the VPN gateway */
GATEWAY_ID_TYPE_FQDN = 3,
} gateway_id_type_t;
/**
* Mapping of gateway identity types to identity types
*/
static id_type_t gateway_to_id_type(gateway_id_type_t type)
{
switch (type)
{
case GATEWAY_ID_TYPE_IPV4:
return ID_IPV4_ADDR;
case GATEWAY_ID_TYPE_IPV6:
return ID_IPV6_ADDR;
case GATEWAY_ID_TYPE_FQDN:
return ID_FQDN;
default:
return 0;
}
}
/**
* Mapping of identity types to gateway identity types
*/
static gateway_id_type_t id_type_to_gateway(id_type_t type)
{
switch (type)
{
case ID_IPV4_ADDR:
return GATEWAY_ID_TYPE_IPV4;
case ID_IPV6_ADDR:
return GATEWAY_ID_TYPE_IPV6;
case ID_FQDN:
return GATEWAY_ID_TYPE_FQDN;
default:
return 0;
}
}
METHOD(redirect_manager_t, add_provider, void,
private_redirect_manager_t *this, redirect_provider_t *provider)
{
this->lock->write_lock(this->lock);
this->providers->insert_last(this->providers, provider);
this->lock->unlock(this->lock);
}
METHOD(redirect_manager_t, remove_provider, void,
private_redirect_manager_t *this, redirect_provider_t *provider)
{
this->lock->write_lock(this->lock);
this->providers->remove(this->providers, provider, NULL);
this->lock->unlock(this->lock);
}
/**
* Determine whether a client should be redirected using the callback with the
* given offset into the redirect_provider_t interface.
*/
static bool should_redirect(private_redirect_manager_t *this, ike_sa_t *ike_sa,
identification_t **gateway, size_t offset)
{
enumerator_t *enumerator;
void *provider;
bool redirect = FALSE;
this->lock->read_lock(this->lock);
enumerator = this->providers->create_enumerator(this->providers);
while (enumerator->enumerate(enumerator, &provider))
{
bool (**method)(void*,ike_sa_t*,identification_t**) = provider + offset;
if (*method && (*method)(provider, ike_sa, gateway))
{
if (*gateway && id_type_to_gateway((*gateway)->get_type(*gateway)))
{
redirect = TRUE;
break;
}
else
{
DBG1(DBG_CFG, "redirect provider returned invalid gateway ID");
DESTROY_IF(*gateway);
}
}
}
enumerator->destroy(enumerator);
this->lock->unlock(this->lock);
return redirect;
}
METHOD(redirect_manager_t, redirect_on_init, bool,
private_redirect_manager_t *this, ike_sa_t *ike_sa,
identification_t **gateway)
{
return should_redirect(this, ike_sa, gateway,
offsetof(redirect_provider_t, redirect_on_init));
}
METHOD(redirect_manager_t, redirect_on_auth, bool,
private_redirect_manager_t *this, ike_sa_t *ike_sa,
identification_t **gateway)
{
return should_redirect(this, ike_sa, gateway,
offsetof(redirect_provider_t, redirect_on_auth));
}
METHOD(redirect_manager_t, destroy, void,
private_redirect_manager_t *this)
{
this->providers->destroy(this->providers);
this->lock->destroy(this->lock);
free(this);
}
/*
* Described in header
*/
redirect_manager_t *redirect_manager_create()
{
private_redirect_manager_t *this;
INIT(this,
.public = {
.add_provider = _add_provider,
.remove_provider = _remove_provider,
.redirect_on_init = _redirect_on_init,
.redirect_on_auth = _redirect_on_auth,
.destroy = _destroy,
},
.providers = linked_list_create(),
.lock = rwlock_create(RWLOCK_TYPE_DEFAULT),
);
return &this->public;
}
/*
* Encoding of a REDIRECT or REDIRECTED_FROM notify
*
1 2 3
0 1 2 3 4 5 6 7 8 9 0 1 2 3 4 5 6 7 8 9 0 1 2 3 4 5 6 7 8 9 0 1
+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
| Next Payload |C| RESERVED | Payload Length |
+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
|Protocol ID(=0)| SPI Size (=0) | Notify Message Type |
+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
| GW Ident Type | GW Ident Len | |
+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+ ~
~ New Responder GW Identity ~
| |
+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
| |
~ Nonce Data ~
| |
+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
*/
/*
* Described in header
*/
chunk_t redirect_data_create(identification_t *gw, chunk_t nonce)
{
gateway_id_type_t type;
bio_writer_t *writer;
chunk_t data;
type = id_type_to_gateway(gw->get_type(gw));
if (!type)
{
return chunk_empty;
}
writer = bio_writer_create(0);
writer->write_uint8(writer, type);
writer->write_data8(writer, gw->get_encoding(gw));
if (nonce.ptr)
{
writer->write_data(writer, nonce);
}
data = writer->extract_buf(writer);
writer->destroy(writer);
return data;
}
/*
* Described in header
*/
identification_t *redirect_data_parse(chunk_t data, chunk_t *nonce)
{
bio_reader_t *reader;
id_type_t id_type;
chunk_t gateway;
u_int8_t type;
reader = bio_reader_create(data);
if (!reader->read_uint8(reader, &type) ||
!reader->read_data8(reader, &gateway))
{
DBG1(DBG_ENC, "invalid REDIRECT notify data");
reader->destroy(reader);
return NULL;
}
id_type = gateway_to_id_type(type);
if (!id_type)
{
DBG1(DBG_ENC, "invalid gateway ID type (%d) in REDIRECT notify", type);
reader->destroy(reader);
return NULL;
}
if (nonce)
{
*nonce = chunk_clone(reader->peek(reader));
}
reader->destroy(reader);
return identification_create_from_encoding(id_type, gateway);
}
+109
View File
@@ -0,0 +1,109 @@
/*
* Copyright (C) 2015 Tobias Brunner
* Hochschule fuer Technik Rapperswil
*
* 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.
*/
/**
* @defgroup redirect_manager redirect_manager
* @{ @ingroup sa
*/
#ifndef REDIRECT_MANAGER_H_
#define REDIRECT_MANAGER_H_
typedef struct redirect_manager_t redirect_manager_t;
#include <sa/redirect_provider.h>
/**
* Manages redirect providers.
*/
struct redirect_manager_t {
/**
* Add a redirect provider.
*
* All registered providers are queried until one of them decides to
* redirect a client.
*
* A provider may be called concurrently for different IKE_SAs.
*
* @param provider provider to register
*/
void (*add_provider)(redirect_manager_t *this,
redirect_provider_t *provider);
/**
* Remove a redirect provider.
*
* @param provider provider to unregister
*/
void (*remove_provider)(redirect_manager_t *this,
redirect_provider_t *provider);
/**
* Determine whether a client should be redirected upon receipt of the
* IKE_SA_INIT message.
*
* @param ike_sa IKE_SA for which this is called
* @param gateway[out] new IKE gateway (IP or FQDN)
* @return TRUE if client should be redirected, FALSE otherwise
*/
bool (*redirect_on_init)(redirect_manager_t *this, ike_sa_t *ike_sa,
identification_t **gateway);
/**
* Determine whether a client should be redirected after the IKE_AUTH has
* been handled. Should be called after the client is authenticated and
* when the server authenticates itself.
*
* @param ike_sa IKE_SA for which this is called
* @param gateway[out] new IKE gateway (IP or FQDN)
* @return TRUE if client should be redirected, FALSE otherwise
*/
bool (*redirect_on_auth)(redirect_manager_t *this, ike_sa_t *ike_sa,
identification_t **gateway);
/**
* Destroy this instance.
*/
void (*destroy)(redirect_manager_t *this);
};
/**
* Create a redirect manager instance.
*
* @return manager instance
*/
redirect_manager_t *redirect_manager_create();
/**
* Create notification data of a REDIRECT or REDIRECT_FROM payload using the
* given gateway identity and optional nonce (only used during IKE_SA_INIT).
*
* @param gw gateway identity (IP or FQDN), gets cloned
* @param nonce nonce value, or chunk_empty, gets cloned
* @return notify data, chunk_empty if ID type is not supported
*/
chunk_t redirect_data_create(identification_t *gw, chunk_t nonce);
/**
* Parse notification data of a REDIRECT or REDIRECTED_FROM notify payload.
*
* @param data notification data to parse
* @param nonce[out] nonce data (allocated), if any was provided
* @return gateway identity, NULL if data is invalid
*/
identification_t *redirect_data_parse(chunk_t data, chunk_t *nonce);
#endif /** REDIRECT_MANAGER_H_ @}*/
+59
View File
@@ -0,0 +1,59 @@
/*
* Copyright (C) 2015 Tobias Brunner
* Hochschule fuer Technik Rapperswil
*
* 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.
*/
/**
* @defgroup redirect_provider redirect_provider
* @{ @ingroup sa
*/
#ifndef REDIRECT_PROVIDER_H_
#define REDIRECT_PROVIDER_H_
typedef struct redirect_provider_t redirect_provider_t;
#include <library.h>
#include <sa/ike_sa.h>
/**
* Interface that allows implementations to decide whether a client is
* redirected during IKE_SA_INIT or IKE_AUTH using RFC 5685.
*/
struct redirect_provider_t {
/**
* Decide whether a client is redirect directly upon receipt of the
* IKE_SA_INIT message.
*
* @param ike_sa IKE_SA for which this is called
* @param gateway[out] new IKE gateway (IP or FQDN)
* @return TRUE if client should be redirected, FALSE otherwise
*/
bool (*redirect_on_init)(redirect_provider_t *this, ike_sa_t *ike_sa,
identification_t **gateway);
/**
* Decide whether a client is redirect after the IKE_AUTH has been
* handled. This is called after the client is authenticated and when the
* server authenticates itself.
*
* @param ike_sa IKE_SA for which this is called
* @param gateway[out] new IKE gateway (IP or FQDN)
* @return TRUE if client should be redirected, FALSE otherwise
*/
bool (*redirect_on_auth)(redirect_provider_t *this, ike_sa_t *ike_sa,
identification_t **gateway);
};
#endif /** REDIRECT_PROVIDER_H_ @}*/
+1
View File
@@ -28,6 +28,7 @@ ENUM(task_type_names, TASK_IKE_INIT, TASK_ISAKMP_CERT_POST,
"IKE_REKEY",
"IKE_REAUTH",
"IKE_REAUTH_COMPLETE",
"IKE_REDIRECT",
"IKE_DELETE",
"IKE_DPD",
"IKE_VENDOR",
+15 -1
View File
@@ -1,5 +1,5 @@
/*
* Copyright (C) 2007 Tobias Brunner
* Copyright (C) 2007-2015 Tobias Brunner
* Copyright (C) 2006 Martin Willi
* Hochschule fuer Technik Rapperswil
*
@@ -57,6 +57,8 @@ enum task_type_t {
TASK_IKE_REAUTH,
/** completion task for make-before-break IKE_SA re-authentication */
TASK_IKE_REAUTH_COMPLETE,
/** redirect an active IKE_SA */
TASK_IKE_REDIRECT,
/** delete an IKE_SA */
TASK_IKE_DELETE,
/** liveness check */
@@ -153,6 +155,18 @@ struct task_t {
*/
status_t (*process) (task_t *this, message_t *message);
/**
* Verify a message before processing it (optional to implement by tasks).
*
* @param message message to verify
* @return
* - FAILED if verification is not successful, the
* message will be silently discarded
* - DESTROY_ME if IKE_SA has to be destroyed
* - SUCCESS if verification is successful
*/
status_t (*pre_process) (task_t *this, message_t *message);
/**
* Get the type of the task implementation.
*/
+1
View File
@@ -4,6 +4,7 @@ swanctl_SOURCES = \
command.c command.h \
commands/initiate.c \
commands/terminate.c \
commands/redirect.c \
commands/install.c \
commands/list_sas.c \
commands/list_pols.c \
+1 -1
View File
@@ -27,7 +27,7 @@
/**
* Maximum number of commands (+1).
*/
#define MAX_COMMANDS 22
#define MAX_COMMANDS 23
/**
* Maximum number of options in a command (+3)
+132
View File
@@ -0,0 +1,132 @@
/*
* Copyright (C) 2015 Tobias Brunner
* Hochschule fuer Technik Rapperswil
*
* 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.
*/
#include "command.h"
#include <errno.h>
static int redirect(vici_conn_t *conn)
{
vici_req_t *req;
vici_res_t *res;
command_format_options_t format = COMMAND_FORMAT_NONE;
char *arg, *peer_ip = NULL, *peer_id = NULL, *ike = NULL, *gateway = NULL;
int ret = 0, ike_id = 0;
while (TRUE)
{
switch (command_getopt(&arg))
{
case 'h':
return command_usage(NULL);
case 'P':
format |= COMMAND_FORMAT_PRETTY;
/* fall through to raw */
case 'r':
format |= COMMAND_FORMAT_RAW;
continue;
case 'i':
ike = arg;
continue;
case 'I':
ike_id = atoi(arg);
continue;
case 'p':
peer_ip = arg;
continue;
case 'd':
peer_id = arg;
continue;
case 'g':
gateway = arg;
continue;
case EOF:
break;
default:
return command_usage("invalid --redirect option");
}
break;
}
req = vici_begin("redirect");
if (ike)
{
vici_add_key_valuef(req, "ike", "%s", ike);
}
if (ike_id)
{
vici_add_key_valuef(req, "ike-id", "%d", ike_id);
}
if (peer_ip)
{
vici_add_key_valuef(req, "peer-ip", "%s", peer_ip);
}
if (peer_id)
{
vici_add_key_valuef(req, "peer-id", "%s", peer_id);
}
if (gateway)
{
vici_add_key_valuef(req, "gateway", "%s", gateway);
}
res = vici_submit(req, conn);
if (!res)
{
ret = errno;
fprintf(stderr, "redirect request failed: %s\n", strerror(errno));
return ret;
}
if (format & COMMAND_FORMAT_RAW)
{
vici_dump(res, "redirect reply", format & COMMAND_FORMAT_PRETTY,
stdout);
}
else
{
if (streq(vici_find_str(res, "no", "success"), "yes"))
{
printf("redirect completed successfully\n");
}
else
{
fprintf(stderr, "redirect failed: %s\n",
vici_find_str(res, "", "errmsg"));
ret = 1;
}
}
vici_free_res(res);
return ret;
}
/**
* Register the command.
*/
static void __attribute__ ((constructor))reg()
{
command_register((command_t) {
redirect, 'd', "redirect", "redirect an IKE_SA",
{"--ike <name> | --ike-id <id> | --peer-ip <ip|subnet|range>",
"--peer-id <id|wildcards> | --gateway <ip|fqdn> [--raw|--pretty]"},
{
{"help", 'h', 0, "show usage information"},
{"ike", 'i', 1, "redirect by IKE_SA name"},
{"ike-id", 'I', 1, "redirect by IKE_SA unique identifier"},
{"peer-ip", 'p', 1, "redirect by client IP"},
{"peer-id", 'd', 1, "redirect by IKE_SA name"},
{"gateway", 'g', 1, "target gateway (IP or FQDN)"},
{"raw", 'r', 0, "dump raw response message"},
{"pretty", 'P', 0, "dump raw response message in pretty print"},
}
});
}
+4
View File
@@ -41,6 +41,10 @@ initiate a connection
\-\-terminate\fR
terminate a connection
.TP
.B "\-d, \-\-redirect"
\-\-redirect\fR
redirect an IKE_SA
.TP
.B "\-p, \-\-install"
install a trap or shunt policy
.TP
@@ -0,0 +1,8 @@
The roadwarriors <b>carol</b> and <b>dave</b> set up a connection each
to gateway <b>alice</b>, which identifies itself as <b>mars</b>.
Host <b>venus</b> in the subnet behind this gateway uses gateway <b>moon</b> as
default gateway, so it is not fully reachable by the two roadwarriors.
Then both SAs are actively redirected with the <em>swanctl --redirect</em>
command to gateway <b>moon</b> (also identified as <b>mars</b>) using the
mechanism described in <b>RFC 5685</b> enabling the roadwarriors to
ping <b>venus</b>.
@@ -0,0 +1,28 @@
alice::ipsec status 2> /dev/null::rw\[1].*ESTABLISHED.*mars.strongswan.org.*[email protected]::YES
alice::ipsec status 2> /dev/null::rw\[2].*ESTABLISHED.*mars.strongswan.org.*[email protected]::YES
carol::ipsec status 2> /dev/null::home.*ESTABLISHED.*[email protected].*mars.strongswan.org::YES
dave:: ipsec status 2> /dev/null::home.*ESTABLISHED.*[email protected].*mars.strongswan.org::YES
carol::ping -c 1 -W 1 PH_IP_VENUS::64 bytes from PH_IP_VENUS: icmp_req=1::NO
dave:: ping -c 1 -W 1 PH_IP_VENUS::64 bytes from PH_IP_VENUS: icmp_req=1::NO
alice::swanctl --redirect --peer-ip PH_IP_CAROL --gateway 192.168.0.1::redirect completed successfully::YES
alice::swanctl --redirect --peer-id [email protected] --gateway moon.strongswan.org::redirect completed successfully::YES
carol::sleep 1::No output expected::NO
carol::cat /var/log/daemon.log::redirected to 192.168.0.1::YES
dave::cat /var/log/daemon.log::redirected to moon.strongswan.org::YES
moon::cat /var/log/daemon.log::client got redirected from 192.168.0.5::YES
moon::ipsec status 2> /dev/null::rw\[1].*ESTABLISHED.*mars.strongswan.org.*[email protected]::YES
moon::ipsec status 2> /dev/null::rw\[2].*ESTABLISHED.*mars.strongswan.org.*[email protected]::YES
carol::ping -c 1 PH_IP_VENUS::64 bytes from PH_IP_VENUS: icmp_req=1::YES
dave:: ping -c 1 PH_IP_VENUS::64 bytes from PH_IP_VENUS: icmp_req=1::YES
carol::tcpdump::IP carol.strongswan.org > mars.strongswan.org: ESP::YES
carol::tcpdump::IP mars.strongswan.org > carol.strongswan.org: ESP::NO
carol::tcpdump::IP carol.strongswan.org > moon.strongswan.org: ESP::YES
carol::tcpdump::IP moon.strongswan.org > carol.strongswan.org: ESP::YES
dave::tcpdump::IP dave.strongswan.org > mars.strongswan.org: ESP::YES
dave::tcpdump::IP mars.strongswan.org > dave.strongswan.org: ESP::NO
dave::tcpdump::IP dave.strongswan.org > moon.strongswan.org: ESP::YES
dave::tcpdump::IP moon.strongswan.org > dave.strongswan.org: ESP::YES
venus::tcpdump::IP carol.strongswan.org > venus.strongswan.org: ICMP echo request::YES
venus::tcpdump::IP venus.strongswan.org > carol.strongswan.org: ICMP echo reply::YES
venus::tcpdump::IP dave.strongswan.org > venus.strongswan.org: ICMP echo request::YES
venus::tcpdump::IP venus.strongswan.org > dave.strongswan.org: ICMP echo reply::YES
@@ -0,0 +1,19 @@
# /etc/ipsec.conf - strongSwan IPsec configuration file
config setup
conn %default
ikelifetime=60m
keylife=20m
rekeymargin=3m
keyingtries=1
conn rw
left=192.168.0.5
leftcert=marsCert.pem
leftid=mars.strongswan.org
leftsubnet=10.1.0.0/16
leftfirewall=yes
right=%any
keyexchange=ikev2
auto=add
@@ -0,0 +1,25 @@
-----BEGIN CERTIFICATE-----
MIIEQDCCAyigAwIBAgIBNDANBgkqhkiG9w0BAQsFADBFMQswCQYDVQQGEwJDSDEZ
MBcGA1UEChMQTGludXggc3Ryb25nU3dhbjEbMBkGA1UEAxMSc3Ryb25nU3dhbiBS
b290IENBMB4XDTE1MTEyNjA4MjQ1M1oXDTE5MDkwNjA4MjQ1M1owZDELMAkGA1UE
BhMCQ0gxGTAXBgNVBAoTEExpbnV4IHN0cm9uZ1N3YW4xHDAaBgNVBAsTE1ZpcnR1
YWwgVlBOIEdhdGV3YXkxHDAaBgNVBAMTE21hcnMuc3Ryb25nc3dhbi5vcmcwggEi
MA0GCSqGSIb3DQEBAQUAA4IBDwAwggEKAoIBAQCxTvcinIErfzu8YZKl+a2MNTVY
+qjG83OkweWjWed/egAugxRjTyWeKjrSNf6DWpXC0pNhzja+Sj0njz4Kq8VczkFB
/yYEkFKpdpFQHXvbQo5h7wn1i3Omhvou5x0rRfddRpLGl7Z/Xg8gnHsZMHHN60hI
qiLZdRSu5QF25WNcy9tO58gz8Hvo5jsk8YDu6eGYolaygQo3cqxx/r8yWzehju0F
oWm4sLOrq+OTegeCQYI8PsOALAwLWgWdGfMPMT0ntq9tD97AcUD0EilvcXVdmwUW
44/hM9BZ0JS7N7Wv6fgIChC7xhZj1yo6vY+FDsmNMhz7vdeulKx2dqRJkn0XAgMB
AAGjggEaMIIBFjAJBgNVHRMEAjAAMAsGA1UdDwQEAwIDqDAdBgNVHQ4EFgQUvo44
06FQwLI8P6VqNehTNHa2LNMwbQYDVR0jBGYwZIAUXafdcAZRMn7ntm2zteXgYOou
Te+hSaRHMEUxCzAJBgNVBAYTAkNIMRkwFwYDVQQKExBMaW51eCBzdHJvbmdTd2Fu
MRswGQYDVQQDExJzdHJvbmdTd2FuIFJvb3QgQ0GCAQAwHgYDVR0RBBcwFYITbWFy
cy5zdHJvbmdzd2FuLm9yZzATBgNVHSUEDDAKBggrBgEFBQcDATA5BgNVHR8EMjAw
MC6gLKAqhihodHRwOi8vY3JsLnN0cm9uZ3N3YW4ub3JnL3N0cm9uZ3N3YW4uY3Js
MA0GCSqGSIb3DQEBCwUAA4IBAQCWvHc0v5BhxsLRxPvcOu1bVoeexzA/5nftfRly
PumU2hYFQ8p7soJiT/jYPmnfNvl6halnmS0FrqLdTMNfXj/6WCZ3w4Xnokc5PYW4
oL1VqdEgR7jyQjifZuzRkuPw+yAFoT+HbMttLdRMVTq9NXlPXtGaJTWbx5Z/gGP3
1Ry47WhvzJyRSysPh/+9WJFOwS6nf6DFbNuyVtNXQRzXjpsGefZgN9ysntNRFMMZ
V0j+zFIkLBLh2WBkJsuLQM9EFAlZrpQZ7iwHuz7gU0jATxN6Qxnn9AemNPl4k8T3
igPXeVhDbZFeTc+u/Z7X5i1HXhks2QGz/zGee6no54XOnBWB
-----END CERTIFICATE-----
@@ -0,0 +1,27 @@
-----BEGIN RSA PRIVATE KEY-----
MIIEpAIBAAKCAQEAsU73IpyBK387vGGSpfmtjDU1WPqoxvNzpMHlo1nnf3oALoMU
Y08lnio60jX+g1qVwtKTYc42vko9J48+CqvFXM5BQf8mBJBSqXaRUB1720KOYe8J
9Ytzpob6LucdK0X3XUaSxpe2f14PIJx7GTBxzetISKoi2XUUruUBduVjXMvbTufI
M/B76OY7JPGA7unhmKJWsoEKN3Kscf6/Mls3oY7tBaFpuLCzq6vjk3oHgkGCPD7D
gCwMC1oFnRnzDzE9J7avbQ/ewHFA9BIpb3F1XZsFFuOP4TPQWdCUuze1r+n4CAoQ
u8YWY9cqOr2PhQ7JjTIc+73XrpSsdnakSZJ9FwIDAQABAoIBAQCe+TYMClamMUXV
+YYK2noIJAzY4qVA/DbLmi3S8GDnovNWwKAfCm+oCCUFJPQ1wZpVO4h5QPNEWjvK
pFv0JV6nfyZzjdkAboYu+uf+9PB//oS6uiAr0AS5YnweYYl9qxXGw+gFtzEhsavO
iX61bwIapsIApMrqPld1GE7f03vrTjyqYeJC+V5WEVZe1fkZtKFFJiHN1boPwoWt
VRQ4UGlq9eto5pddmMcPl/uR9/TItdMC8AZ7fcRYP9RdYFEp8jS+tx3CDNs0XrlF
qKlroDSdwBt475Ud5irtNwjGoohl3xCHvEne9l+fjlmQFynfRNeOb9rgVIsT3OoO
MFSeW9HBAoGBAOiAjYCWoQHSlbi3Nkd5fsfTd4iZOkeeZi+2PJOhDByH1Hsq87CP
KoYejjYUQ6QvJY2WDJCU8qXxPJkDuI6XZ6QbTDPad2xXDkA4pxuPi/c+Hb/eqLQ+
24ebIzauC5iLdddp22oQXQOngKwUMihYggKs9cIpem8G99bcMfq1OeaDAoGBAMM6
Z790eySPDIaKZZ/KVOu4hJe1s5vIJqN9xtV0o55PTR2wFCgwCogiXQchyhF8Qo6q
BEpcKpY1bAivmL8T2PBsLUuKC4LAr8uzW8rVFbG3HfC62RoaVOZWmH+yBABi6eej
Lh8KNhal+HzVOlMsw78FAkhq9aubWBywxfULFyrdAoGAPmnsEn3dIPkf+iMsrgk+
cHQjHYdMrtclxV8daeAMuUf5UUsZeeck2jYvpPLRqayCXzzNiK6DaOqWgtkN3TFl
wBcX4L+f2XSRPco3id2CDFAfeldSYHiTRBbwYAhe0od1jes73IAiCA4aK5eMU2pX
FFLL8mBiHpX3SDV6MTwfG/MCgYEApgLXUC3LvVXLL+kl65ARUHUSgzNmrNSxTptY
5hCORcNnbxRYv6fCfOrDspngC6hfrJMUnOrs59g7qtMvD2TgN+m1RqP3j9Msagp1
xvAVx45QbnFkxdaYVVpTyVpmHrH99xSC1rBHOFEgEX78XtgVCC1JOK2DhM7PSW5k
lzA8Hh0CgYBVXNnQsy4x+9D09zeFP2TKXsk7N154yUP6oxXu6OjZC+cfxHOGyi/g
PVe8ukBIknZkFRz+ZXdfZzXXuJslENOVeFEInqVAu2W55KeCPc/3SU6hB2lj6MBl
WIZ7yrUmtdalU3cPkFnHkQTL2glYAzjB2z22AxyXNzy37ZhtFpovtg==
-----END RSA PRIVATE KEY-----
@@ -0,0 +1,3 @@
# /etc/ipsec.secrets - strongSwan IPsec secrets file
: RSA marsKey.pem
@@ -0,0 +1,34 @@
*filter
# default policy is DROP
-P INPUT DROP
-P OUTPUT DROP
-P FORWARD DROP
# forward ESP-tunneled traffic
-A FORWARD -i eth1 -m policy --dir in --pol ipsec --proto esp -s PH_IP_CAROL -j ACCEPT
-A FORWARD -i eth1 -m policy --dir in --pol ipsec --proto esp -s PH_IP_DAVE -j ACCEPT
-A FORWARD -o eth1 -m policy --dir out --pol ipsec --proto esp -j ACCEPT
# allow esp
-A INPUT -p 50 -j ACCEPT
-A OUTPUT -p 50 -d PH_IP_CAROL -j ACCEPT
-A OUTPUT -p 50 -d PH_IP_DAVE -j ACCEPT
# allow IKE
-A INPUT -i eth1 -p udp --sport 500 --dport 500 -j ACCEPT
-A OUTPUT -o eth1 -p udp --dport 500 --sport 500 -j ACCEPT
# allow MobIKE
-A INPUT -i eth1 -p udp --sport 4500 --dport 4500 -j ACCEPT
-A OUTPUT -o eth1 -p udp --dport 4500 --sport 4500 -j ACCEPT
# allow crl fetch from winnetou
-A INPUT -i eth1 -p tcp --sport 80 -s PH_IP_WINNETOU -j ACCEPT
-A OUTPUT -o eth1 -p tcp --dport 80 -d PH_IP_WINNETOU -j ACCEPT
# allow ssh
-A INPUT -p tcp --dport 22 -j ACCEPT
-A OUTPUT -p tcp --sport 22 -j ACCEPT
COMMIT
@@ -0,0 +1,6 @@
# /etc/strongswan.conf - strongSwan configuration file
charon {
load = aes des sha1 sha2 md5 pem pkcs1 gmp random nonce x509 curl revocation hmac stroke kernel-netlink socket-default updown vici
}
@@ -0,0 +1,19 @@
# /etc/ipsec.conf - strongSwan IPsec configuration file
config setup
charondebug="knl 2"
conn %default
ikelifetime=60m
keylife=20m
rekeymargin=3m
keyingtries=1
conn home
leftcert=carolCert.pem
[email protected]
leftfirewall=yes
right=192.168.0.5
rightid=mars.strongswan.org
rightsubnet=10.1.0.0/16
keyexchange=ikev2
auto=add
@@ -0,0 +1,5 @@
# /etc/strongswan.conf - strongSwan configuration file
charon {
load = aes des sha1 sha2 md5 pem pkcs1 gmp random nonce x509 curl revocation hmac xcbc ctr ccm gcm stroke kernel-netlink socket-default updown
}
@@ -0,0 +1,19 @@
# /etc/ipsec.conf - strongSwan IPsec configuration file
config setup
conn %default
ikelifetime=60m
keylife=20m
rekeymargin=3m
keyingtries=1
conn home
leftcert=daveCert.pem
[email protected]
leftfirewall=yes
right=192.168.0.5
rightid=mars.strongswan.org
rightsubnet=10.1.0.0/16
keyexchange=ikev2
auto=add
@@ -0,0 +1,6 @@
# /etc/strongswan.conf - strongSwan configuration file
charon {
load = aes des sha1 sha2 md5 pem pkcs1 gmp random nonce x509 curl revocation hmac xcbc ctr ccm gcm stroke kernel-netlink socket-default updown
}
@@ -0,0 +1,18 @@
# /etc/ipsec.conf - strongSwan IPsec configuration file
config setup
conn %default
ikelifetime=60m
keylife=20m
rekeymargin=3m
keyingtries=1
conn rw
leftcert=marsCert.pem
leftid=mars.strongswan.org
leftsubnet=10.1.0.0/16
leftfirewall=yes
right=%any
keyexchange=ikev2
auto=add
@@ -0,0 +1,25 @@
-----BEGIN CERTIFICATE-----
MIIEQDCCAyigAwIBAgIBNDANBgkqhkiG9w0BAQsFADBFMQswCQYDVQQGEwJDSDEZ
MBcGA1UEChMQTGludXggc3Ryb25nU3dhbjEbMBkGA1UEAxMSc3Ryb25nU3dhbiBS
b290IENBMB4XDTE1MTEyNjA4MjQ1M1oXDTE5MDkwNjA4MjQ1M1owZDELMAkGA1UE
BhMCQ0gxGTAXBgNVBAoTEExpbnV4IHN0cm9uZ1N3YW4xHDAaBgNVBAsTE1ZpcnR1
YWwgVlBOIEdhdGV3YXkxHDAaBgNVBAMTE21hcnMuc3Ryb25nc3dhbi5vcmcwggEi
MA0GCSqGSIb3DQEBAQUAA4IBDwAwggEKAoIBAQCxTvcinIErfzu8YZKl+a2MNTVY
+qjG83OkweWjWed/egAugxRjTyWeKjrSNf6DWpXC0pNhzja+Sj0njz4Kq8VczkFB
/yYEkFKpdpFQHXvbQo5h7wn1i3Omhvou5x0rRfddRpLGl7Z/Xg8gnHsZMHHN60hI
qiLZdRSu5QF25WNcy9tO58gz8Hvo5jsk8YDu6eGYolaygQo3cqxx/r8yWzehju0F
oWm4sLOrq+OTegeCQYI8PsOALAwLWgWdGfMPMT0ntq9tD97AcUD0EilvcXVdmwUW
44/hM9BZ0JS7N7Wv6fgIChC7xhZj1yo6vY+FDsmNMhz7vdeulKx2dqRJkn0XAgMB
AAGjggEaMIIBFjAJBgNVHRMEAjAAMAsGA1UdDwQEAwIDqDAdBgNVHQ4EFgQUvo44
06FQwLI8P6VqNehTNHa2LNMwbQYDVR0jBGYwZIAUXafdcAZRMn7ntm2zteXgYOou
Te+hSaRHMEUxCzAJBgNVBAYTAkNIMRkwFwYDVQQKExBMaW51eCBzdHJvbmdTd2Fu
MRswGQYDVQQDExJzdHJvbmdTd2FuIFJvb3QgQ0GCAQAwHgYDVR0RBBcwFYITbWFy
cy5zdHJvbmdzd2FuLm9yZzATBgNVHSUEDDAKBggrBgEFBQcDATA5BgNVHR8EMjAw
MC6gLKAqhihodHRwOi8vY3JsLnN0cm9uZ3N3YW4ub3JnL3N0cm9uZ3N3YW4uY3Js
MA0GCSqGSIb3DQEBCwUAA4IBAQCWvHc0v5BhxsLRxPvcOu1bVoeexzA/5nftfRly
PumU2hYFQ8p7soJiT/jYPmnfNvl6halnmS0FrqLdTMNfXj/6WCZ3w4Xnokc5PYW4
oL1VqdEgR7jyQjifZuzRkuPw+yAFoT+HbMttLdRMVTq9NXlPXtGaJTWbx5Z/gGP3
1Ry47WhvzJyRSysPh/+9WJFOwS6nf6DFbNuyVtNXQRzXjpsGefZgN9ysntNRFMMZ
V0j+zFIkLBLh2WBkJsuLQM9EFAlZrpQZ7iwHuz7gU0jATxN6Qxnn9AemNPl4k8T3
igPXeVhDbZFeTc+u/Z7X5i1HXhks2QGz/zGee6no54XOnBWB
-----END CERTIFICATE-----
@@ -0,0 +1,27 @@
-----BEGIN RSA PRIVATE KEY-----
MIIEpAIBAAKCAQEAsU73IpyBK387vGGSpfmtjDU1WPqoxvNzpMHlo1nnf3oALoMU
Y08lnio60jX+g1qVwtKTYc42vko9J48+CqvFXM5BQf8mBJBSqXaRUB1720KOYe8J
9Ytzpob6LucdK0X3XUaSxpe2f14PIJx7GTBxzetISKoi2XUUruUBduVjXMvbTufI
M/B76OY7JPGA7unhmKJWsoEKN3Kscf6/Mls3oY7tBaFpuLCzq6vjk3oHgkGCPD7D
gCwMC1oFnRnzDzE9J7avbQ/ewHFA9BIpb3F1XZsFFuOP4TPQWdCUuze1r+n4CAoQ
u8YWY9cqOr2PhQ7JjTIc+73XrpSsdnakSZJ9FwIDAQABAoIBAQCe+TYMClamMUXV
+YYK2noIJAzY4qVA/DbLmi3S8GDnovNWwKAfCm+oCCUFJPQ1wZpVO4h5QPNEWjvK
pFv0JV6nfyZzjdkAboYu+uf+9PB//oS6uiAr0AS5YnweYYl9qxXGw+gFtzEhsavO
iX61bwIapsIApMrqPld1GE7f03vrTjyqYeJC+V5WEVZe1fkZtKFFJiHN1boPwoWt
VRQ4UGlq9eto5pddmMcPl/uR9/TItdMC8AZ7fcRYP9RdYFEp8jS+tx3CDNs0XrlF
qKlroDSdwBt475Ud5irtNwjGoohl3xCHvEne9l+fjlmQFynfRNeOb9rgVIsT3OoO
MFSeW9HBAoGBAOiAjYCWoQHSlbi3Nkd5fsfTd4iZOkeeZi+2PJOhDByH1Hsq87CP
KoYejjYUQ6QvJY2WDJCU8qXxPJkDuI6XZ6QbTDPad2xXDkA4pxuPi/c+Hb/eqLQ+
24ebIzauC5iLdddp22oQXQOngKwUMihYggKs9cIpem8G99bcMfq1OeaDAoGBAMM6
Z790eySPDIaKZZ/KVOu4hJe1s5vIJqN9xtV0o55PTR2wFCgwCogiXQchyhF8Qo6q
BEpcKpY1bAivmL8T2PBsLUuKC4LAr8uzW8rVFbG3HfC62RoaVOZWmH+yBABi6eej
Lh8KNhal+HzVOlMsw78FAkhq9aubWBywxfULFyrdAoGAPmnsEn3dIPkf+iMsrgk+
cHQjHYdMrtclxV8daeAMuUf5UUsZeeck2jYvpPLRqayCXzzNiK6DaOqWgtkN3TFl
wBcX4L+f2XSRPco3id2CDFAfeldSYHiTRBbwYAhe0od1jes73IAiCA4aK5eMU2pX
FFLL8mBiHpX3SDV6MTwfG/MCgYEApgLXUC3LvVXLL+kl65ARUHUSgzNmrNSxTptY
5hCORcNnbxRYv6fCfOrDspngC6hfrJMUnOrs59g7qtMvD2TgN+m1RqP3j9Msagp1
xvAVx45QbnFkxdaYVVpTyVpmHrH99xSC1rBHOFEgEX78XtgVCC1JOK2DhM7PSW5k
lzA8Hh0CgYBVXNnQsy4x+9D09zeFP2TKXsk7N154yUP6oxXu6OjZC+cfxHOGyi/g
PVe8ukBIknZkFRz+ZXdfZzXXuJslENOVeFEInqVAu2W55KeCPc/3SU6hB2lj6MBl
WIZ7yrUmtdalU3cPkFnHkQTL2glYAzjB2z22AxyXNzy37ZhtFpovtg==
-----END RSA PRIVATE KEY-----
@@ -0,0 +1,3 @@
# /etc/ipsec.secrets - strongSwan IPsec secrets file
: RSA marsKey.pem
@@ -0,0 +1,6 @@
# /etc/strongswan.conf - strongSwan configuration file
charon {
load = aes des sha1 sha2 md5 pem pkcs1 gmp random nonce x509 curl revocation hmac stroke kernel-netlink socket-default updown
}
@@ -0,0 +1,10 @@
carol::ipsec stop
dave::ipsec stop
moon::ipsec stop
alice::ipsec stop
moon::iptables-restore < /etc/iptables.flush
alice::iptables-restore < /etc/iptables.flush
carol::iptables-restore < /etc/iptables.flush
dave::iptables-restore < /etc/iptables.flush
alice::ip addr del 192.168.0.5/24 dev eth1
alice::ifdown eth1
@@ -0,0 +1,13 @@
alice::ifup eth1
alice::ip addr add 192.168.0.5/24 dev eth1
moon::iptables-restore < /etc/iptables.rules
alice::iptables-restore < /etc/iptables.rules
carol::iptables-restore < /etc/iptables.rules
dave::iptables-restore < /etc/iptables.rules
moon::ipsec start
alice::ipsec start
carol::ipsec start
dave::ipsec start
carol::sleep 1
carol::ipsec up home
dave::ipsec up home
@@ -0,0 +1,21 @@
#!/bin/bash
#
# This configuration file provides information on the
# guest instances used for this test
# All guest instances that are required for this test
#
VIRTHOSTS="alice venus moon carol winnetou dave"
# Corresponding block diagram
#
DIAGRAM="a-v-m-c-w-d.png"
# Guest instances on which tcpdump is to be started
#
TCPDUMPHOSTS="venus carol dave"
# Guest instances on which IPsec is started
# Used for IPsec logging purposes
#
IPSECHOSTS="alice moon carol dave"