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:
@@ -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
|
||||
|
||||
@@ -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
|
||||
|
||||
|
||||
@@ -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
|
||||
|
||||
@@ -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;
|
||||
|
||||
@@ -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.
|
||||
*/
|
||||
|
||||
@@ -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)
|
||||
|
||||
@@ -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
@@ -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)
|
||||
|
||||
@@ -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.
|
||||
*
|
||||
|
||||
@@ -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;
|
||||
|
||||
@@ -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();
|
||||
|
||||
@@ -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
|
||||
{
|
||||
|
||||
@@ -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_ @}*/
|
||||
@@ -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);
|
||||
}
|
||||
@@ -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_ @}*/
|
||||
@@ -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_ @}*/
|
||||
@@ -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
@@ -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.
|
||||
*/
|
||||
|
||||
@@ -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 \
|
||||
|
||||
@@ -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)
|
||||
|
||||
@@ -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"},
|
||||
}
|
||||
});
|
||||
}
|
||||
@@ -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"
|
||||
Reference in New Issue
Block a user