added possibility to route CHILD_SAs, without to set them up
support for auto=route parameter support for ipsec route and ipsec unroute initiating of CHILD and/or IKE_SAs based on kernel acquires
This commit is contained in:
@@ -46,6 +46,8 @@ queues/jobs/send_keepalive_job.c queues/jobs/send_keepalive_job.h \
|
||||
queues/jobs/rekey_child_sa_job.c queues/jobs/rekey_child_sa_job.h \
|
||||
queues/jobs/delete_child_sa_job.c queues/jobs/delete_child_sa_job.h \
|
||||
queues/jobs/send_dpd_job.c queues/jobs/send_dpd_job.h \
|
||||
queues/jobs/route_job.c queues/jobs/route_job.h \
|
||||
queues/jobs/acquire_job.c queues/jobs/acquire_job.h \
|
||||
queues/job_queue.c queues/event_queue.c queues/send_queue.h queues/job_queue.h queues/event_queue.h \
|
||||
queues/send_queue.c threads/kernel_interface.c threads/thread_pool.c threads/scheduler.c threads/sender.c \
|
||||
threads/sender.h threads/kernel_interface.h threads/scheduler.h threads/receiver.c threads/stroke_interface.c \
|
||||
|
||||
@@ -247,6 +247,29 @@ static traffic_selector_t *get_subset(private_traffic_selector_t *this, private_
|
||||
return NULL;
|
||||
}
|
||||
|
||||
/**
|
||||
* implements traffic_selector_t.equals
|
||||
*/
|
||||
static bool equals(private_traffic_selector_t *this, private_traffic_selector_t *other)
|
||||
{
|
||||
if (this->type != other->type)
|
||||
{
|
||||
return FALSE;
|
||||
}
|
||||
if (this->type == TS_IPV4_ADDR_RANGE)
|
||||
{
|
||||
if (this->from_addr_ipv4 == other->from_addr_ipv4 &&
|
||||
this->to_addr_ipv4 == other->to_addr_ipv4 &&
|
||||
this->from_port == other->from_port &&
|
||||
this->to_port == other->to_port &&
|
||||
this->protocol == other->protocol)
|
||||
{
|
||||
return TRUE;
|
||||
}
|
||||
}
|
||||
return FALSE;
|
||||
}
|
||||
|
||||
/**
|
||||
* Implements traffic_selector_t.get_from_address.
|
||||
*/
|
||||
@@ -518,6 +541,7 @@ static private_traffic_selector_t *traffic_selector_create(u_int8_t protocol, ts
|
||||
|
||||
/* public functions */
|
||||
this->public.get_subset = (traffic_selector_t*(*)(traffic_selector_t*,traffic_selector_t*))get_subset;
|
||||
this->public.equals = (bool(*)(traffic_selector_t*,traffic_selector_t*))equals;
|
||||
this->public.get_string = (char*(*)(traffic_selector_t*))get_string;
|
||||
this->public.get_from_address = (chunk_t(*)(traffic_selector_t*))get_from_address;
|
||||
this->public.get_to_address = (chunk_t(*)(traffic_selector_t*))get_to_address;
|
||||
|
||||
@@ -183,6 +183,15 @@ struct traffic_selector_t {
|
||||
*/
|
||||
char* (*get_string) (traffic_selector_t *this);
|
||||
|
||||
/**
|
||||
* @brief Compare two traffic selectors for equality.
|
||||
*
|
||||
* @param this first to compare
|
||||
* @param other second to compare with first
|
||||
* @return pointer to a string.
|
||||
*/
|
||||
bool (*equals) (traffic_selector_t *this, traffic_selector_t *other);
|
||||
|
||||
/**
|
||||
* @brief Destroys the ts object
|
||||
*
|
||||
|
||||
@@ -0,0 +1,104 @@
|
||||
/**
|
||||
* @file acquire_job.c
|
||||
*
|
||||
* @brief Implementation of acquire_job_t.
|
||||
*
|
||||
*/
|
||||
|
||||
/*
|
||||
* Copyright (C) 2006 Martin Willi
|
||||
* 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 "acquire_job.h"
|
||||
|
||||
#include <daemon.h>
|
||||
|
||||
|
||||
typedef struct private_acquire_job_t private_acquire_job_t;
|
||||
|
||||
/**
|
||||
* Private data of an acquire_job_t object.
|
||||
*/
|
||||
struct private_acquire_job_t {
|
||||
/**
|
||||
* Public acquire_job_t interface.
|
||||
*/
|
||||
acquire_job_t public;
|
||||
|
||||
/**
|
||||
* reqid of the child to rekey
|
||||
*/
|
||||
u_int32_t reqid;
|
||||
|
||||
/**
|
||||
* Logger ref
|
||||
*/
|
||||
logger_t *logger;
|
||||
};
|
||||
|
||||
/**
|
||||
* Implementation of job_t.get_type.
|
||||
*/
|
||||
static job_type_t get_type(private_acquire_job_t *this)
|
||||
{
|
||||
return ACQUIRE;
|
||||
}
|
||||
|
||||
/**
|
||||
* Implementation of job_t.execute.
|
||||
*/
|
||||
static status_t execute(private_acquire_job_t *this)
|
||||
{
|
||||
ike_sa_t *ike_sa;
|
||||
|
||||
ike_sa = charon->ike_sa_manager->checkout_by_child(charon->ike_sa_manager,
|
||||
this->reqid);
|
||||
if (ike_sa == NULL)
|
||||
{
|
||||
this->logger->log(this->logger, ERROR|LEVEL1,
|
||||
"CHILD_SA not found for acquiring");
|
||||
return DESTROY_ME;
|
||||
}
|
||||
ike_sa->acquire(ike_sa, this->reqid);
|
||||
|
||||
charon->ike_sa_manager->checkin(charon->ike_sa_manager, ike_sa);
|
||||
return DESTROY_ME;
|
||||
}
|
||||
|
||||
/**
|
||||
* Implementation of job_t.destroy.
|
||||
*/
|
||||
static void destroy(private_acquire_job_t *this)
|
||||
{
|
||||
free(this);
|
||||
}
|
||||
|
||||
/*
|
||||
* Described in header
|
||||
*/
|
||||
acquire_job_t *acquire_job_create(u_int32_t reqid)
|
||||
{
|
||||
private_acquire_job_t *this = malloc_thing(private_acquire_job_t);
|
||||
|
||||
/* interface functions */
|
||||
this->public.job_interface.get_type = (job_type_t (*) (job_t *)) get_type;
|
||||
this->public.job_interface.execute = (status_t (*) (job_t *)) execute;
|
||||
this->public.job_interface.destroy = (void (*)(job_t*)) destroy;
|
||||
|
||||
/* private variables */
|
||||
this->reqid = reqid;
|
||||
this->logger = logger_manager->get_logger(logger_manager, WORKER);
|
||||
|
||||
return &(this->public);
|
||||
}
|
||||
@@ -0,0 +1,61 @@
|
||||
/**
|
||||
* @file acquire_job.h
|
||||
*
|
||||
* @brief Interface of acquire_job_t.
|
||||
*
|
||||
*/
|
||||
|
||||
/*
|
||||
* Copyright (C) 2006 Martin Willi
|
||||
* 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.
|
||||
*/
|
||||
|
||||
#ifndef ACQUIRE_JOB_H_
|
||||
#define ACQUIRE_JOB_H_
|
||||
|
||||
#include <types.h>
|
||||
#include <queues/jobs/job.h>
|
||||
|
||||
|
||||
typedef struct acquire_job_t acquire_job_t;
|
||||
|
||||
/**
|
||||
* @brief Class representing an ACQUIRE Job.
|
||||
*
|
||||
* This job initiates a CHILD SA on kernel request.
|
||||
*
|
||||
* @b Constructors:
|
||||
* - acquire_job_create()
|
||||
*
|
||||
* @ingroup jobs
|
||||
*/
|
||||
struct acquire_job_t {
|
||||
/**
|
||||
* The job_t interface.
|
||||
*/
|
||||
job_t job_interface;
|
||||
};
|
||||
|
||||
/**
|
||||
* @brief Creates a job of type ACQUIRE.
|
||||
*
|
||||
* We use the reqid to find the routed CHILD_SA.
|
||||
*
|
||||
* @param reqid reqid of the CHILD_SA to acquire
|
||||
* @return acquire_job_t object
|
||||
*
|
||||
* @ingroup jobs
|
||||
*/
|
||||
acquire_job_t *acquire_job_create(u_int32_t reqid);
|
||||
|
||||
#endif /* REKEY_CHILD_SA_JOB_H_ */
|
||||
@@ -36,6 +36,11 @@ struct private_delete_child_sa_job_t {
|
||||
*/
|
||||
delete_child_sa_job_t public;
|
||||
|
||||
/**
|
||||
* reqid of the CHILD_SA
|
||||
*/
|
||||
u_int32_t reqid;
|
||||
|
||||
/**
|
||||
* protocol of the CHILD_SA (ESP/AH)
|
||||
*/
|
||||
@@ -66,12 +71,10 @@ static job_type_t get_type(private_delete_child_sa_job_t *this)
|
||||
static status_t execute(private_delete_child_sa_job_t *this)
|
||||
{
|
||||
ike_sa_t *ike_sa;
|
||||
status_t status;
|
||||
|
||||
status = charon->ike_sa_manager->checkout_by_child(charon->ike_sa_manager,
|
||||
this->protocol, this->spi,
|
||||
&ike_sa);
|
||||
if (status != SUCCESS)
|
||||
ike_sa = charon->ike_sa_manager->checkout_by_child(charon->ike_sa_manager,
|
||||
this->reqid);
|
||||
if (ike_sa == NULL)
|
||||
{
|
||||
this->logger->log(this->logger, ERROR|LEVEL1,
|
||||
"CHILD_SA not found for delete");
|
||||
@@ -94,7 +97,9 @@ static void destroy(private_delete_child_sa_job_t *this)
|
||||
/*
|
||||
* Described in header
|
||||
*/
|
||||
delete_child_sa_job_t *delete_child_sa_job_create(protocol_id_t protocol, u_int32_t spi)
|
||||
delete_child_sa_job_t *delete_child_sa_job_create(u_int32_t reqid,
|
||||
protocol_id_t protocol,
|
||||
u_int32_t spi)
|
||||
{
|
||||
private_delete_child_sa_job_t *this = malloc_thing(private_delete_child_sa_job_t);
|
||||
|
||||
@@ -104,6 +109,7 @@ delete_child_sa_job_t *delete_child_sa_job_create(protocol_id_t protocol, u_int3
|
||||
this->public.job_interface.destroy = (void (*)(job_t*)) destroy;
|
||||
|
||||
/* private variables */
|
||||
this->reqid = reqid;
|
||||
this->protocol = protocol;
|
||||
this->spi = spi;
|
||||
this->logger = logger_manager->get_logger(logger_manager, WORKER);
|
||||
|
||||
@@ -51,15 +51,18 @@ struct delete_child_sa_job_t {
|
||||
/**
|
||||
* @brief Creates a job of type DELETE_CHILD_SA.
|
||||
*
|
||||
* The CHILD_SA is identified by its protocol (AH/ESP) and its
|
||||
* The CHILD_SA is identified by its reqid, protocol (AH/ESP) and its
|
||||
* inbound SPI.
|
||||
*
|
||||
* @param reqid reqid of the CHILD_SA, as used in kernel
|
||||
* @param protocol protocol of the CHILD_SA
|
||||
* @param spi security parameter index of the CHILD_SA
|
||||
* @return delete_child_sa_job_t object
|
||||
*
|
||||
* @ingroup jobs
|
||||
*/
|
||||
delete_child_sa_job_t *delete_child_sa_job_create(protocol_id_t protocol, u_int32_t spi);
|
||||
delete_child_sa_job_t *delete_child_sa_job_create(u_int32_t reqid,
|
||||
protocol_id_t protocol,
|
||||
u_int32_t spi);
|
||||
|
||||
#endif /* DELETE_CHILD_SA_JOB_H_ */
|
||||
|
||||
@@ -57,6 +57,20 @@ enum job_type_t {
|
||||
*/
|
||||
INITIATE,
|
||||
|
||||
/**
|
||||
* Install SPD entries.
|
||||
*
|
||||
* Job is implemented in class route_job_t
|
||||
*/
|
||||
ROUTE,
|
||||
|
||||
/**
|
||||
* React on a acquire message from the kernel (e.g. setup CHILD_SA)
|
||||
*
|
||||
* Job is implemented in class acquire_job_t
|
||||
*/
|
||||
ACQUIRE,
|
||||
|
||||
/**
|
||||
* Delete an ike sa which is still not established.
|
||||
*
|
||||
|
||||
@@ -36,6 +36,11 @@ struct private_rekey_child_sa_job_t {
|
||||
*/
|
||||
rekey_child_sa_job_t public;
|
||||
|
||||
/**
|
||||
* reqid of the child to rekey
|
||||
*/
|
||||
u_int32_t reqid;
|
||||
|
||||
/**
|
||||
* protocol of the CHILD_SA (ESP/AH)
|
||||
*/
|
||||
@@ -66,12 +71,10 @@ static job_type_t get_type(private_rekey_child_sa_job_t *this)
|
||||
static status_t execute(private_rekey_child_sa_job_t *this)
|
||||
{
|
||||
ike_sa_t *ike_sa;
|
||||
status_t status;
|
||||
|
||||
status = charon->ike_sa_manager->checkout_by_child(charon->ike_sa_manager,
|
||||
this->protocol, this->spi,
|
||||
&ike_sa);
|
||||
if (status != SUCCESS)
|
||||
ike_sa = charon->ike_sa_manager->checkout_by_child(charon->ike_sa_manager,
|
||||
this->reqid);
|
||||
if (ike_sa == NULL)
|
||||
{
|
||||
this->logger->log(this->logger, ERROR|LEVEL1,
|
||||
"CHILD_SA not found for rekeying");
|
||||
@@ -94,7 +97,9 @@ static void destroy(private_rekey_child_sa_job_t *this)
|
||||
/*
|
||||
* Described in header
|
||||
*/
|
||||
rekey_child_sa_job_t *rekey_child_sa_job_create(protocol_id_t protocol, u_int32_t spi)
|
||||
rekey_child_sa_job_t *rekey_child_sa_job_create(u_int32_t reqid,
|
||||
protocol_id_t protocol,
|
||||
u_int32_t spi)
|
||||
{
|
||||
private_rekey_child_sa_job_t *this = malloc_thing(private_rekey_child_sa_job_t);
|
||||
|
||||
@@ -104,6 +109,7 @@ rekey_child_sa_job_t *rekey_child_sa_job_create(protocol_id_t protocol, u_int32_
|
||||
this->public.job_interface.destroy = (void (*)(job_t*)) destroy;
|
||||
|
||||
/* private variables */
|
||||
this->reqid = reqid;
|
||||
this->protocol = protocol;
|
||||
this->spi = spi;
|
||||
this->logger = logger_manager->get_logger(logger_manager, WORKER);
|
||||
|
||||
@@ -54,12 +54,13 @@ struct rekey_child_sa_job_t {
|
||||
* The CHILD_SA is identified by its protocol (AH/ESP) and its
|
||||
* inbound SPI.
|
||||
*
|
||||
* @param reqid reqid of the CHILD_SA to rekey
|
||||
* @param protocol protocol of the CHILD_SA
|
||||
* @param spi security parameter index of the CHILD_SA
|
||||
* @return rekey_child_sa_job_t object
|
||||
*
|
||||
* @ingroup jobs
|
||||
*/
|
||||
rekey_child_sa_job_t *rekey_child_sa_job_create(protocol_id_t protocol, u_int32_t spi);
|
||||
rekey_child_sa_job_t *rekey_child_sa_job_create(u_int32_t reqid, protocol_id_t protocol, u_int32_t spi);
|
||||
|
||||
#endif /* REKEY_CHILD_SA_JOB_H_ */
|
||||
|
||||
@@ -0,0 +1,133 @@
|
||||
/**
|
||||
* @file route_job.c
|
||||
*
|
||||
* @brief Implementation of route_job_t.
|
||||
*
|
||||
*/
|
||||
|
||||
/*
|
||||
* Copyright (C) 2005-2006 Martin Willi
|
||||
* 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 <stdlib.h>
|
||||
|
||||
#include "route_job.h"
|
||||
|
||||
#include <daemon.h>
|
||||
|
||||
typedef struct private_route_job_t private_route_job_t;
|
||||
|
||||
/**
|
||||
* Private data of an route_job_t Object
|
||||
*/
|
||||
struct private_route_job_t {
|
||||
/**
|
||||
* public route_job_t interface
|
||||
*/
|
||||
route_job_t public;
|
||||
|
||||
/**
|
||||
* associated connection to route
|
||||
*/
|
||||
connection_t *connection;
|
||||
|
||||
/**
|
||||
* associated policy to route
|
||||
*/
|
||||
policy_t *policy;
|
||||
|
||||
/**
|
||||
* route or unroute?
|
||||
*/
|
||||
bool route;
|
||||
|
||||
/**
|
||||
* logger
|
||||
*/
|
||||
logger_t *logger;
|
||||
};
|
||||
|
||||
/**
|
||||
* Implements route_job_t.get_type.
|
||||
*/
|
||||
static job_type_t get_type(private_route_job_t *this)
|
||||
{
|
||||
return ROUTE;
|
||||
}
|
||||
|
||||
/**
|
||||
* Implementation of job_t.execute.
|
||||
*/
|
||||
static status_t execute(private_route_job_t *this)
|
||||
{
|
||||
ike_sa_t *ike_sa;
|
||||
|
||||
this->logger->log(this->logger, CONTROL|LEVEL2, "getting an IKE SA");
|
||||
ike_sa = charon->ike_sa_manager->checkout_by_ids(charon->ike_sa_manager,
|
||||
this->policy->get_my_id(this->policy),
|
||||
this->policy->get_other_id(this->policy));
|
||||
|
||||
if (this->route)
|
||||
{
|
||||
if (ike_sa->route(ike_sa, this->connection, this->policy) != SUCCESS)
|
||||
{
|
||||
this->logger->log(this->logger, ERROR,
|
||||
"routing failed");
|
||||
}
|
||||
}
|
||||
else
|
||||
{
|
||||
if (ike_sa->unroute(ike_sa, this->policy) == DESTROY_ME)
|
||||
{
|
||||
this->logger->log(this->logger, ERROR,
|
||||
"removing IKE_SA, as last routed CHILD_SA unrouted");
|
||||
charon->ike_sa_manager->checkin_and_destroy(charon->ike_sa_manager, ike_sa);
|
||||
return DESTROY_ME;
|
||||
}
|
||||
}
|
||||
charon->ike_sa_manager->checkin(charon->ike_sa_manager, ike_sa);
|
||||
return DESTROY_ME;
|
||||
}
|
||||
|
||||
/**
|
||||
* Implements job_t.destroy.
|
||||
*/
|
||||
static void destroy(private_route_job_t *this)
|
||||
{
|
||||
this->connection->destroy(this->connection);
|
||||
this->policy->destroy(this->policy);
|
||||
free(this);
|
||||
}
|
||||
|
||||
/*
|
||||
* Described in header
|
||||
*/
|
||||
route_job_t *route_job_create(connection_t *connection, policy_t *policy, bool route)
|
||||
{
|
||||
private_route_job_t *this = malloc_thing(private_route_job_t);
|
||||
|
||||
/* interface functions */
|
||||
this->public.job_interface.get_type = (job_type_t (*) (job_t *)) get_type;
|
||||
this->public.job_interface.execute = (status_t (*) (job_t *)) execute;
|
||||
this->public.job_interface.destroy = (void (*) (job_t *)) destroy;
|
||||
|
||||
/* private variables */
|
||||
this->connection = connection;
|
||||
this->policy = policy;
|
||||
this->route = route;
|
||||
this->logger = logger_manager->get_logger(logger_manager, WORKER);
|
||||
|
||||
return &this->public;
|
||||
}
|
||||
@@ -0,0 +1,60 @@
|
||||
/**
|
||||
* @file route_job.h
|
||||
*
|
||||
* @brief Interface of route_job_t.
|
||||
*/
|
||||
|
||||
/*
|
||||
* Copyright (C) 2005-2006 Martin Willi
|
||||
* 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.
|
||||
*/
|
||||
|
||||
#ifndef ROUTE_JOB_H_
|
||||
#define ROUTE_JOB_H_
|
||||
|
||||
#include <types.h>
|
||||
#include <queues/jobs/job.h>
|
||||
#include <config/policies/policy.h>
|
||||
#include <config/connections/connection.h>
|
||||
|
||||
|
||||
typedef struct route_job_t route_job_t;
|
||||
|
||||
/**
|
||||
* @brief Class representing an ROUTE Job.
|
||||
*
|
||||
* @b Constructors:
|
||||
* - route_job_create()
|
||||
*
|
||||
* @ingroup jobs
|
||||
*/
|
||||
struct route_job_t {
|
||||
/**
|
||||
* implements job_t interface
|
||||
*/
|
||||
job_t job_interface;
|
||||
};
|
||||
|
||||
/**
|
||||
* @brief Creates a job of type ROUTE.
|
||||
*
|
||||
* @param connection connection used for routing
|
||||
* @param policy policy to set up
|
||||
* @param route TRUE to route, FALSE to unroute
|
||||
* @return route_job_t object
|
||||
*
|
||||
* @ingroup jobs
|
||||
*/
|
||||
route_job_t *route_job_create(connection_t *connection, policy_t *policy, bool route);
|
||||
|
||||
#endif /*ROUTE_JOB_H_*/
|
||||
+66
-49
@@ -33,6 +33,7 @@
|
||||
mapping_t child_sa_state_m[] = {
|
||||
{CHILD_CREATED, "CREATED"},
|
||||
{CHILD_INSTALLED, "INSTALLED"},
|
||||
{CHILD_ROUTED, "ROUTED"},
|
||||
{CHILD_REKEYING, "REKEYING"},
|
||||
{CHILD_DELETING, "DELETING"},
|
||||
{MAPPING_END, NULL}
|
||||
@@ -502,6 +503,13 @@ static status_t add_policies(private_child_sa_t *this, linked_list_t *my_ts_list
|
||||
}
|
||||
my_iter->destroy(my_iter);
|
||||
other_iter->destroy(other_iter);
|
||||
|
||||
/* switch to routed state if no SAD entry set up */
|
||||
if (this->state == CHILD_CREATED)
|
||||
{
|
||||
this->state = CHILD_ROUTED;
|
||||
}
|
||||
|
||||
return SUCCESS;
|
||||
}
|
||||
|
||||
@@ -597,66 +605,75 @@ static void log_status(private_child_sa_t *this, logger_t *logger, char* name)
|
||||
}
|
||||
now = (u_int32_t)time(NULL);
|
||||
|
||||
/* query SA times */
|
||||
status = charon->kernel_interface->query_sa(charon->kernel_interface,
|
||||
this->me.addr, this->me.spi, this->protocol, &use_in);
|
||||
if (status == SUCCESS && use_in)
|
||||
if (this->state == CHILD_INSTALLED)
|
||||
{
|
||||
snprintf(use_in_str, sizeof(use_in_str), "%ds", now - use_in);
|
||||
}
|
||||
status = charon->kernel_interface->query_sa(charon->kernel_interface,
|
||||
this->other.addr, this->other.spi, this->protocol, &use_out);
|
||||
if (status == SUCCESS && use_out)
|
||||
{
|
||||
snprintf(use_out_str, sizeof(use_out_str), "%ds", now - use_out);
|
||||
}
|
||||
|
||||
/* calculate rekey times */
|
||||
if (this->soft_lifetime)
|
||||
{
|
||||
rekeying = this->soft_lifetime - (now - this->install_time);
|
||||
snprintf(rekey_str, sizeof(rekey_str), "%ds", (int)rekeying);
|
||||
}
|
||||
|
||||
/* algorithms used */
|
||||
if (this->protocol == PROTO_ESP)
|
||||
{
|
||||
if (this->encryption.key_size)
|
||||
/* query SA times */
|
||||
status = charon->kernel_interface->query_sa(charon->kernel_interface,
|
||||
this->me.addr, this->me.spi, this->protocol, &use_in);
|
||||
if (status == SUCCESS && use_in)
|
||||
{
|
||||
snprintf(enc_str, sizeof(enc_str), "%s-%d,",
|
||||
mapping_find(encryption_algorithm_m, this->encryption.algorithm),
|
||||
this->encryption.key_size);
|
||||
snprintf(use_in_str, sizeof(use_in_str), "%ds", now - use_in);
|
||||
}
|
||||
status = charon->kernel_interface->query_sa(charon->kernel_interface,
|
||||
this->other.addr, this->other.spi, this->protocol, &use_out);
|
||||
if (status == SUCCESS && use_out)
|
||||
{
|
||||
snprintf(use_out_str, sizeof(use_out_str), "%ds", now - use_out);
|
||||
}
|
||||
|
||||
/* calculate rekey times */
|
||||
if (this->soft_lifetime)
|
||||
{
|
||||
rekeying = this->soft_lifetime - (now - this->install_time);
|
||||
snprintf(rekey_str, sizeof(rekey_str), "%ds", (int)rekeying);
|
||||
}
|
||||
|
||||
/* algorithms used */
|
||||
if (this->protocol == PROTO_ESP)
|
||||
{
|
||||
if (this->encryption.key_size)
|
||||
{
|
||||
snprintf(enc_str, sizeof(enc_str), "%s-%d,",
|
||||
mapping_find(encryption_algorithm_m, this->encryption.algorithm),
|
||||
this->encryption.key_size);
|
||||
}
|
||||
else
|
||||
{
|
||||
snprintf(enc_str, sizeof(enc_str), "%s,",
|
||||
mapping_find(encryption_algorithm_m, this->encryption.algorithm));
|
||||
}
|
||||
}
|
||||
if (this->integrity.key_size)
|
||||
{
|
||||
snprintf(int_str, sizeof(int_str), "%s-%d",
|
||||
mapping_find(integrity_algorithm_m, this->integrity.algorithm),
|
||||
this->integrity.key_size);
|
||||
}
|
||||
else
|
||||
{
|
||||
snprintf(enc_str, sizeof(enc_str), "%s,",
|
||||
mapping_find(encryption_algorithm_m, this->encryption.algorithm));
|
||||
snprintf(int_str, sizeof(int_str), "%s",
|
||||
mapping_find(integrity_algorithm_m, this->integrity.algorithm));
|
||||
}
|
||||
}
|
||||
if (this->integrity.key_size)
|
||||
{
|
||||
snprintf(int_str, sizeof(int_str), "%s-%d",
|
||||
mapping_find(integrity_algorithm_m, this->integrity.algorithm),
|
||||
this->integrity.key_size);
|
||||
|
||||
logger->log(logger, CONTROL|LEVEL1,
|
||||
" \"%s\": state: %s, reqid: %d, ",
|
||||
name, mapping_find(child_sa_state_m, this->state), this->reqid);
|
||||
logger->log(logger, CONTROL|LEVEL1,
|
||||
" \"%s\": %s (%s%s), SPIs (in/out): 0x%x/0x%x",
|
||||
name, this->protocol == PROTO_ESP ? "ESP" : "AH",
|
||||
enc_str, int_str,
|
||||
htonl(this->me.spi), htonl(this->other.spi));
|
||||
logger->log(logger, CONTROL|LEVEL1,
|
||||
" \"%s\": rekeying: %s, key age (in/out): %s/%s",
|
||||
name, rekey_str, use_in_str, use_out_str);
|
||||
}
|
||||
else
|
||||
{
|
||||
snprintf(int_str, sizeof(int_str), "%s",
|
||||
mapping_find(integrity_algorithm_m, this->integrity.algorithm));
|
||||
logger->log(logger, CONTROL|LEVEL1, " \"%s\": state: %s, reqid: %d",
|
||||
name, mapping_find(child_sa_state_m, this->state),
|
||||
this->reqid);
|
||||
}
|
||||
|
||||
logger->log(logger, CONTROL|LEVEL1,
|
||||
" \"%s\": %s (%s%s), SPIs (in/out): 0x%x/0x%x, reqid: %d",
|
||||
name,
|
||||
this->protocol == PROTO_ESP ? "ESP" : "AH",
|
||||
enc_str, int_str,
|
||||
htonl(this->me.spi), htonl(this->other.spi),
|
||||
this->reqid);
|
||||
logger->log(logger, CONTROL|LEVEL1,
|
||||
" \"%s\": state: %s, rekeying: %s, key age (in/out): %s/%s",
|
||||
name, mapping_find(child_sa_state_m, this->state),
|
||||
rekey_str, use_in_str, use_out_str);
|
||||
|
||||
iterator = this->policies->create_iterator(this->policies, TRUE);
|
||||
while (iterator->has_next(iterator))
|
||||
{
|
||||
|
||||
@@ -48,6 +48,11 @@ enum child_sa_state_t {
|
||||
*/
|
||||
CHILD_CREATED,
|
||||
|
||||
/**
|
||||
* Installed SPD, but no SAD entries
|
||||
*/
|
||||
CHILD_ROUTED,
|
||||
|
||||
/**
|
||||
* Installed an in-use CHILD_SA
|
||||
*/
|
||||
|
||||
+320
-30
@@ -329,10 +329,13 @@ static void update_hosts(private_ike_sa_t *this, host_t *me, host_t *other)
|
||||
child_sa_t *child_sa = NULL;
|
||||
host_diff_t my_diff, other_diff;
|
||||
|
||||
if (this->my_host == NULL || this->other_host == NULL)
|
||||
if (this->my_host->is_anyaddr(this->my_host) ||
|
||||
this->other_host->is_anyaddr(this->other_host))
|
||||
{
|
||||
/* on first received message */
|
||||
this->my_host->destroy(this->my_host);
|
||||
this->my_host = me->clone(me);
|
||||
this->other_host->destroy(this->other_host);
|
||||
this->other_host = other->clone(other);
|
||||
return;
|
||||
}
|
||||
@@ -792,9 +795,14 @@ static status_t initiate(private_ike_sa_t *this,
|
||||
*/
|
||||
ike_sa_init_t *ike_sa_init;
|
||||
|
||||
this->logger->log(this->logger, CONTROL,
|
||||
"initiating IKE_SA");
|
||||
|
||||
set_name(this, connection->get_name(connection));
|
||||
DESTROY_IF(this->my_host);
|
||||
this->my_host = connection->get_my_host(connection);
|
||||
this->my_host = this->my_host->clone(this->my_host);
|
||||
DESTROY_IF(this->other_host);
|
||||
this->other_host = connection->get_other_host(connection);
|
||||
this->other_host = this->other_host->clone(this->other_host);
|
||||
|
||||
@@ -806,6 +814,8 @@ static status_t initiate(private_ike_sa_t *this,
|
||||
case IKE_DELETING:
|
||||
{
|
||||
/* if we are in DELETING, we deny set up of a policy. */
|
||||
this->logger->log(this->logger, CONTROL,
|
||||
"creating CHILD_SA discarded, as IKE_SA is deleting");
|
||||
policy->destroy(policy);
|
||||
connection->destroy(connection);
|
||||
return FAILED;
|
||||
@@ -820,6 +830,9 @@ static status_t initiate(private_ike_sa_t *this,
|
||||
*/
|
||||
create_child_sa_t *create_child;
|
||||
|
||||
this->logger->log(this->logger, CONTROL,
|
||||
"initiating CHILD_SA");
|
||||
|
||||
connection->destroy(connection);
|
||||
create_child = create_child_sa_create(&this->public);
|
||||
create_child->set_policy(create_child, policy);
|
||||
@@ -834,33 +847,275 @@ static status_t initiate(private_ike_sa_t *this,
|
||||
*/
|
||||
static status_t acquire(private_ike_sa_t *this, u_int32_t reqid)
|
||||
{
|
||||
/* - get TS from child with reqid
|
||||
* - get a policy from TS
|
||||
* - get connection from policy
|
||||
*/
|
||||
connection_t *connection;
|
||||
policy_t *policy;
|
||||
iterator_t *iterator;
|
||||
child_sa_t *current, *child_sa = NULL;
|
||||
linked_list_t *my_ts, *other_ts;
|
||||
|
||||
if (this->state == IKE_DELETING)
|
||||
{
|
||||
this->logger->log(this->logger, CONTROL,
|
||||
"acquiring CHILD_SA with reqid %d discarded, as IKE_SA is deleting",
|
||||
reqid);
|
||||
return FAILED;
|
||||
}
|
||||
|
||||
|
||||
/* find CHILD_SA */
|
||||
iterator = this->child_sas->create_iterator(this->child_sas, TRUE);
|
||||
while (iterator->iterate(iterator, (void**)¤t))
|
||||
{
|
||||
if (current->get_reqid(current) == reqid)
|
||||
{
|
||||
iterator->remove(iterator);
|
||||
child_sa = current;
|
||||
break;
|
||||
}
|
||||
}
|
||||
iterator->destroy(iterator);
|
||||
if (!child_sa)
|
||||
{
|
||||
this->logger->log(this->logger, ERROR,
|
||||
"CHILD_SA with reqid %d not found, unable to acquire",
|
||||
reqid);
|
||||
return FAILED;
|
||||
}
|
||||
my_ts = child_sa->get_my_traffic_selectors(child_sa);
|
||||
other_ts = child_sa->get_other_traffic_selectors(child_sa);
|
||||
|
||||
policy = charon->policies->get_policy(charon->policies,
|
||||
this->my_id, this->other_id,
|
||||
my_ts, other_ts,
|
||||
this->my_host, this->other_host);
|
||||
child_sa->destroy(child_sa);
|
||||
if (policy == NULL)
|
||||
{
|
||||
this->logger->log(this->logger, ERROR,
|
||||
"no policy found to acquire CHILD_SA with reqid %d",
|
||||
reqid);
|
||||
return FAILED;
|
||||
}
|
||||
|
||||
switch (this->state)
|
||||
{
|
||||
case IKE_CREATED:
|
||||
/* ike_sa_init */
|
||||
break;
|
||||
{
|
||||
ike_sa_init_t *ike_sa_init;
|
||||
|
||||
this->logger->log(this->logger, CONTROL,
|
||||
"acquiring CHILD_SA with reqid %d, IKE_SA setup needed",
|
||||
reqid);
|
||||
|
||||
connection = charon->connections->get_connection_by_hosts(
|
||||
charon->connections, this->my_host, this->other_host);
|
||||
|
||||
if (connection == NULL)
|
||||
{
|
||||
this->logger->log(this->logger, ERROR,
|
||||
"no connection found to acquire IKE_SA for CHILD_SA with reqid %d",
|
||||
reqid);
|
||||
policy->destroy(policy);
|
||||
return FAILED;
|
||||
}
|
||||
|
||||
this->message_id_out = 1;
|
||||
ike_sa_init = ike_sa_init_create(&this->public);
|
||||
ike_sa_init->set_config(ike_sa_init, connection, policy);
|
||||
return queue_transaction(this, (transaction_t*)ike_sa_init, TRUE);
|
||||
}
|
||||
case IKE_CONNECTING:
|
||||
case IKE_ESTABLISHED:
|
||||
/* queue create_child_sa */
|
||||
break;
|
||||
case IKE_DELETING:
|
||||
/* deny */
|
||||
{
|
||||
create_child_sa_t *create_child;
|
||||
|
||||
this->logger->log(this->logger, CONTROL,
|
||||
"acquiring CHILD_SA with reqid %d",
|
||||
reqid);
|
||||
|
||||
create_child = create_child_sa_create(&this->public);
|
||||
create_child->set_policy(create_child, policy);
|
||||
return queue_transaction(this, (transaction_t*)create_child, FALSE);
|
||||
}
|
||||
default:
|
||||
break;
|
||||
}
|
||||
return FAILED;
|
||||
}
|
||||
|
||||
/**
|
||||
* destroy a list of traffic selectors
|
||||
*/
|
||||
static void ts_list_destroy(linked_list_t *list)
|
||||
{
|
||||
traffic_selector_t *ts;
|
||||
while (list->remove_last(list, (void**)&ts) == SUCCESS)
|
||||
{
|
||||
ts->destroy(ts);
|
||||
}
|
||||
list->destroy(list);
|
||||
}
|
||||
|
||||
/**
|
||||
* compare two lists of traffic selectors for equality
|
||||
*/
|
||||
static bool ts_list_equals(linked_list_t *l1, linked_list_t *l2)
|
||||
{
|
||||
bool equals = TRUE;
|
||||
iterator_t *i1, *i2;
|
||||
traffic_selector_t *t1, *t2;
|
||||
|
||||
i1 = l1->create_iterator(l1, TRUE);
|
||||
i2 = l2->create_iterator(l2, TRUE);
|
||||
while (i1->iterate(i1, (void**)&t1) && i2->iterate(i2, (void**)&t2))
|
||||
{
|
||||
if (!t1->equals(t1, t2))
|
||||
{
|
||||
equals = FALSE;
|
||||
break;
|
||||
}
|
||||
}
|
||||
/* check if one iterator is not at the end */
|
||||
if (i1->has_next(i1) || i2->has_next(i2))
|
||||
{
|
||||
equals = FALSE;
|
||||
}
|
||||
i1->destroy(i1);
|
||||
i2->destroy(i2);
|
||||
return equals;
|
||||
}
|
||||
|
||||
/**
|
||||
* Implementation of ike_sa_t.route.
|
||||
*/
|
||||
static status_t route(private_ike_sa_t *this, policy_t *policy)
|
||||
static status_t route(private_ike_sa_t *this, connection_t *connection, policy_t *policy)
|
||||
{
|
||||
/* TODO: create CHILD_SA, add policy */
|
||||
return FAILED;
|
||||
child_sa_t *child_sa = NULL;
|
||||
iterator_t *iterator;
|
||||
linked_list_t *my_ts, *other_ts;
|
||||
status_t status;
|
||||
|
||||
/* check if not already routed*/
|
||||
iterator = this->child_sas->create_iterator(this->child_sas, TRUE);
|
||||
while (iterator->iterate(iterator, (void**)&child_sa))
|
||||
{
|
||||
linked_list_t *my_ts_conf, *other_ts_conf;
|
||||
|
||||
my_ts = child_sa->get_my_traffic_selectors(child_sa);
|
||||
other_ts = child_sa->get_other_traffic_selectors(child_sa);
|
||||
|
||||
my_ts_conf = policy->get_my_traffic_selectors(policy, this->my_host);
|
||||
other_ts_conf = policy->get_other_traffic_selectors(policy, this->other_host);
|
||||
|
||||
if (ts_list_equals(my_ts, my_ts_conf) &&
|
||||
ts_list_equals(other_ts, other_ts_conf))
|
||||
{
|
||||
ts_list_destroy(my_ts_conf);
|
||||
ts_list_destroy(other_ts_conf);
|
||||
iterator->destroy(iterator);
|
||||
this->logger->log(this->logger, CONTROL,
|
||||
"a CHILD_SA with such a policy already routed");
|
||||
|
||||
return FAILED;
|
||||
}
|
||||
ts_list_destroy(my_ts_conf);
|
||||
ts_list_destroy(other_ts_conf);
|
||||
}
|
||||
iterator->destroy(iterator);
|
||||
|
||||
switch (this->state)
|
||||
{
|
||||
case IKE_CREATED:
|
||||
case IKE_CONNECTING:
|
||||
/* we update IKE_SA information as good as possible,
|
||||
* this allows us to set up the SA later when an acquire comes in. */
|
||||
if (this->my_id->get_type(this->my_id) == ID_ANY)
|
||||
{
|
||||
this->my_id->destroy(this->my_id);
|
||||
this->my_id = policy->get_my_id(policy);
|
||||
this->my_id = this->my_id->clone(this->my_id);
|
||||
}
|
||||
if (this->other_id->get_type(this->other_id) == ID_ANY)
|
||||
{
|
||||
this->other_id->destroy(this->other_id);
|
||||
this->other_id = policy->get_other_id(policy);
|
||||
this->other_id = this->other_id->clone(this->other_id);
|
||||
}
|
||||
if (this->my_host->is_anyaddr(this->my_host))
|
||||
{
|
||||
this->my_host->destroy(this->my_host);
|
||||
this->my_host = connection->get_my_host(connection);
|
||||
this->my_host = this->my_host->clone(this->my_host);
|
||||
}
|
||||
if (this->other_host->is_anyaddr(this->other_host))
|
||||
{
|
||||
this->other_host->destroy(this->other_host);
|
||||
this->other_host = connection->get_other_host(connection);
|
||||
this->other_host = this->other_host->clone(this->other_host);
|
||||
}
|
||||
set_name(this, connection->get_name(connection));
|
||||
break;
|
||||
case IKE_ESTABLISHED:
|
||||
/* nothing to do */
|
||||
break;
|
||||
case IKE_DELETING:
|
||||
/* deny */
|
||||
return FAILED;
|
||||
}
|
||||
|
||||
child_sa = child_sa_create(0, this->my_host, this->other_host, 0, 0, FALSE);
|
||||
my_ts = policy->get_my_traffic_selectors(policy, this->my_host);
|
||||
other_ts = policy->get_other_traffic_selectors(policy, this->other_host);
|
||||
status = child_sa->add_policies(child_sa, my_ts, other_ts);
|
||||
ts_list_destroy(my_ts);
|
||||
ts_list_destroy(other_ts);
|
||||
this->child_sas->insert_last(this->child_sas, child_sa);
|
||||
|
||||
return status;
|
||||
}
|
||||
|
||||
/**
|
||||
* Implementation of ike_sa_t.unroute.
|
||||
*/
|
||||
static status_t unroute(private_ike_sa_t *this, policy_t *policy)
|
||||
{
|
||||
iterator_t *iterator;
|
||||
child_sa_t *child_sa = NULL;
|
||||
linked_list_t *my_ts, *other_ts, *my_ts_conf, *other_ts_conf;
|
||||
|
||||
/* find CHILD_SA in ROUTED state */
|
||||
iterator = this->child_sas->create_iterator(this->child_sas, TRUE);
|
||||
while (iterator->iterate(iterator, (void**)&child_sa))
|
||||
{
|
||||
if (child_sa->get_state(child_sa) == CHILD_ROUTED)
|
||||
{
|
||||
my_ts = child_sa->get_my_traffic_selectors(child_sa);
|
||||
other_ts = child_sa->get_other_traffic_selectors(child_sa);
|
||||
|
||||
my_ts_conf = policy->get_my_traffic_selectors(policy, this->my_host);
|
||||
other_ts_conf = policy->get_other_traffic_selectors(policy, this->other_host);
|
||||
|
||||
if (ts_list_equals(my_ts, my_ts_conf) &&
|
||||
ts_list_equals(other_ts, other_ts_conf))
|
||||
{
|
||||
iterator->remove(iterator);
|
||||
child_sa->destroy(child_sa);
|
||||
ts_list_destroy(my_ts_conf);
|
||||
ts_list_destroy(other_ts_conf);
|
||||
break;
|
||||
}
|
||||
ts_list_destroy(my_ts_conf);
|
||||
ts_list_destroy(other_ts_conf);
|
||||
}
|
||||
}
|
||||
iterator->destroy(iterator);
|
||||
/* if we are not established, and we have no more routed childs, remove whole SA */
|
||||
if (this->state == IKE_CREATED &&
|
||||
this->child_sas->get_count(this->child_sas) == 0)
|
||||
{
|
||||
return DESTROY_ME;
|
||||
}
|
||||
return SUCCESS;
|
||||
}
|
||||
|
||||
/**
|
||||
@@ -1217,6 +1472,28 @@ static void add_child_sa(private_ike_sa_t *this, child_sa_t *child_sa)
|
||||
this->child_sas->insert_last(this->child_sas, child_sa);
|
||||
}
|
||||
|
||||
/**
|
||||
* Implementation of protected_ike_sa_t.has_child_sa.
|
||||
*/
|
||||
static bool has_child_sa(private_ike_sa_t *this, u_int32_t reqid)
|
||||
{
|
||||
iterator_t *iterator;
|
||||
child_sa_t *current;
|
||||
bool found = FALSE;
|
||||
|
||||
iterator = this->child_sas->create_iterator(this->child_sas, TRUE);
|
||||
while (iterator->iterate(iterator, (void**)¤t))
|
||||
{
|
||||
if (current->get_reqid(current) == reqid)
|
||||
{
|
||||
found = TRUE;
|
||||
break;
|
||||
}
|
||||
}
|
||||
iterator->destroy(iterator);
|
||||
return found;
|
||||
}
|
||||
|
||||
/**
|
||||
* Implementation of protected_ike_sa_t.get_child_sa.
|
||||
*/
|
||||
@@ -1226,12 +1503,12 @@ static child_sa_t* get_child_sa(private_ike_sa_t *this, protocol_id_t protocol,
|
||||
iterator_t *iterator;
|
||||
child_sa_t *current, *found = NULL;
|
||||
|
||||
iterator = this->child_sas->create_iterator(this->child_sas, FALSE);
|
||||
iterator = this->child_sas->create_iterator(this->child_sas, TRUE);
|
||||
while (iterator->has_next(iterator))
|
||||
{
|
||||
iterator->current(iterator, (void**)¤t);
|
||||
if (current->get_spi(current, inbound) == spi &&
|
||||
current->get_protocol(current) == protocol)
|
||||
current->get_protocol(current) == protocol)
|
||||
{
|
||||
found = current;
|
||||
}
|
||||
@@ -1353,17 +1630,28 @@ static void log_status(private_ike_sa_t *this, logger_t *logger, char *name)
|
||||
*/
|
||||
static status_t delete_(private_ike_sa_t *this)
|
||||
{
|
||||
delete_ike_sa_t *delete_ike_sa;
|
||||
delete_ike_sa = delete_ike_sa_create(&this->public);
|
||||
|
||||
if (this->transaction_out)
|
||||
switch (this->state)
|
||||
{
|
||||
/* already a transaction in progress. As this may hang
|
||||
* around a while, we don't inform the other peer. */
|
||||
return DESTROY_ME;
|
||||
case IKE_CONNECTING:
|
||||
case IKE_ESTABLISHED:
|
||||
{
|
||||
delete_ike_sa_t *delete_ike_sa;
|
||||
delete_ike_sa = delete_ike_sa_create(&this->public);
|
||||
if (this->transaction_out)
|
||||
{
|
||||
/* already a transaction in progress. As this may hang
|
||||
* around a while, we don't inform the other peer. */
|
||||
return DESTROY_ME;
|
||||
}
|
||||
return queue_transaction(this, (transaction_t*)delete_ike_sa, FALSE);
|
||||
}
|
||||
case IKE_CREATED:
|
||||
case IKE_DELETING:
|
||||
default:
|
||||
{
|
||||
return DESTROY_ME;
|
||||
}
|
||||
}
|
||||
|
||||
return queue_transaction(this, (transaction_t*)delete_ike_sa, FALSE);
|
||||
}
|
||||
|
||||
/**
|
||||
@@ -1483,7 +1771,8 @@ ike_sa_t * ike_sa_create(ike_sa_id_t *ike_sa_id)
|
||||
this->public.set_name = (void(*)(ike_sa_t*,char*))set_name;
|
||||
this->public.process_message = (status_t(*)(ike_sa_t*, message_t*)) process_message;
|
||||
this->public.initiate = (status_t(*)(ike_sa_t*,connection_t*,policy_t*)) initiate;
|
||||
this->public.route = (status_t(*)(ike_sa_t*,policy_t*)) route;
|
||||
this->public.route = (status_t(*)(ike_sa_t*,connection_t*,policy_t*)) route;
|
||||
this->public.unroute = (status_t(*)(ike_sa_t*,policy_t*)) unroute;
|
||||
this->public.acquire = (status_t(*)(ike_sa_t*,u_int32_t)) acquire;
|
||||
this->public.get_id = (ike_sa_id_t*(*)(ike_sa_t*)) get_id;
|
||||
this->public.get_my_host = (host_t*(*)(ike_sa_t*)) get_my_host;
|
||||
@@ -1505,6 +1794,7 @@ ike_sa_t * ike_sa_create(ike_sa_id_t *ike_sa_id)
|
||||
this->public.get_prf_auth_r = (prf_t *(*) (ike_sa_t *)) get_prf_auth_r;
|
||||
this->public.build_transforms = (status_t (*) (ike_sa_t *,proposal_t*,diffie_hellman_t*,chunk_t,chunk_t,bool)) build_transforms;
|
||||
this->public.add_child_sa = (void (*) (ike_sa_t*,child_sa_t*)) add_child_sa;
|
||||
this->public.has_child_sa = (bool(*)(ike_sa_t*,u_int32_t)) has_child_sa;
|
||||
this->public.get_child_sa = (child_sa_t* (*)(ike_sa_t*,protocol_id_t,u_int32_t,bool)) get_child_sa;
|
||||
this->public.rekey_child_sa = (status_t(*)(ike_sa_t*,protocol_id_t,u_int32_t)) rekey_child_sa;
|
||||
this->public.delete_child_sa = (status_t(*)(ike_sa_t*,protocol_id_t,u_int32_t)) delete_child_sa;
|
||||
@@ -1517,10 +1807,10 @@ ike_sa_t * ike_sa_create(ike_sa_id_t *ike_sa_id)
|
||||
this->ike_sa_id = ike_sa_id->clone(ike_sa_id);
|
||||
this->name = strdup("(uninitialized)");
|
||||
this->child_sas = linked_list_create();
|
||||
this->my_host = NULL;
|
||||
this->other_host = NULL;
|
||||
this->my_id = NULL;
|
||||
this->other_id = NULL;
|
||||
this->my_host = host_create(AF_INET, "0.0.0.0", 0);
|
||||
this->other_host = host_create(AF_INET, "0.0.0.0", 0);
|
||||
this->my_id = identification_create_from_encoding(ID_ANY, CHUNK_INITIALIZER);
|
||||
this->other_id = identification_create_from_encoding(ID_ANY, CHUNK_INITIALIZER);
|
||||
this->crypter_in = NULL;
|
||||
this->crypter_out = NULL;
|
||||
this->signer_in = NULL;
|
||||
|
||||
+25
-5
@@ -237,16 +237,27 @@ struct ike_sa_t {
|
||||
*
|
||||
* Installs the policies in the kernel. If traffic matches,
|
||||
* the kernel requests connection setup from the IKE_SA via acquire().
|
||||
* The policy is owned by the IKE_SA after the call, so
|
||||
* do not modify or destroy it.
|
||||
*
|
||||
* @param this calling object
|
||||
* @param connection connection definition used for routing
|
||||
* @param policy policy to route
|
||||
* @return
|
||||
* - SUCCESS if routed successfully
|
||||
* - FAILED if routing failed
|
||||
*/
|
||||
status_t (*route) (ike_sa_t *this, connection_t *connection, policy_t *policy);
|
||||
|
||||
/**
|
||||
* @brief Unroute a policy in the kernel previously routed.
|
||||
*
|
||||
* @param this calling object
|
||||
* @param policy policy to route
|
||||
* @return
|
||||
* - SUCCESS if initialization started
|
||||
* - DESTROY_ME if initialization failed and IKE_SA MUST be deleted
|
||||
* - SUCCESS if route removed
|
||||
* - DESTROY_ME if last route was removed from
|
||||
* an IKE_SA which was not established
|
||||
*/
|
||||
status_t (*route) (ike_sa_t *this, policy_t *policy);
|
||||
status_t (*unroute) (ike_sa_t *this, policy_t *policy);
|
||||
|
||||
/**
|
||||
* @brief Acquire connection setup for a policy.
|
||||
@@ -435,6 +446,15 @@ struct ike_sa_t {
|
||||
*/
|
||||
void (*add_child_sa) (ike_sa_t *this, child_sa_t *child_sa);
|
||||
|
||||
/**
|
||||
* @brief Check if an IKE_SA has one or more CHILD_SAs with a given reqid.
|
||||
*
|
||||
* @param this calling object
|
||||
* @param reqid reqid of the CHILD
|
||||
* @return TRUE if it has such a CHILD, FALSE if not
|
||||
*/
|
||||
bool (*has_child_sa) (ike_sa_t *this, u_int32_t reqid);
|
||||
|
||||
/**
|
||||
* @brief Get a CHILD_SA identified by protocol and SPI.
|
||||
*
|
||||
|
||||
@@ -554,12 +554,11 @@ static ike_sa_t* checkout(private_ike_sa_manager_t *this, ike_sa_id_t *ike_sa_id
|
||||
/**
|
||||
* Implementation of of ike_sa_manager.checkout_by_child.
|
||||
*/
|
||||
static status_t checkout_by_child(private_ike_sa_manager_t *this,
|
||||
protocol_id_t protocol, u_int32_t spi,
|
||||
ike_sa_t **ike_sa)
|
||||
static ike_sa_t* checkout_by_child(private_ike_sa_manager_t *this,
|
||||
u_int32_t reqid)
|
||||
{
|
||||
iterator_t *iterator;
|
||||
status_t status = NOT_FOUND;
|
||||
ike_sa_t *ike_sa = NULL;
|
||||
|
||||
pthread_mutex_lock(&(this->mutex));
|
||||
|
||||
@@ -572,12 +571,11 @@ static status_t checkout_by_child(private_ike_sa_manager_t *this,
|
||||
if (wait_for_entry(this, entry))
|
||||
{
|
||||
/* ok, access is exclusive for us, check for child */
|
||||
if (entry->ike_sa->get_child_sa(entry->ike_sa, protocol, spi, TRUE) != NULL)
|
||||
if (entry->ike_sa->has_child_sa(entry->ike_sa, reqid))
|
||||
{
|
||||
/* match */
|
||||
entry->checked_out = TRUE;
|
||||
*ike_sa = entry->ike_sa;
|
||||
status = SUCCESS;
|
||||
ike_sa = entry->ike_sa;
|
||||
break;
|
||||
}
|
||||
}
|
||||
@@ -585,7 +583,7 @@ static status_t checkout_by_child(private_ike_sa_manager_t *this,
|
||||
iterator->destroy(iterator);
|
||||
pthread_mutex_unlock(&(this->mutex));
|
||||
|
||||
return status;
|
||||
return ike_sa;
|
||||
}
|
||||
|
||||
/**
|
||||
@@ -915,7 +913,7 @@ ike_sa_manager_t *ike_sa_manager_create()
|
||||
this->public.destroy = (void(*)(ike_sa_manager_t*))destroy;
|
||||
this->public.checkout_by_ids = (ike_sa_t*(*)(ike_sa_manager_t*,identification_t*,identification_t*))checkout_by_ids;
|
||||
this->public.checkout = (ike_sa_t*(*)(ike_sa_manager_t*, ike_sa_id_t*))checkout;
|
||||
this->public.checkout_by_child = (status_t(*)(ike_sa_manager_t*,protocol_id_t,u_int32_t,ike_sa_t**))checkout_by_child;
|
||||
this->public.checkout_by_child = (ike_sa_t*(*)(ike_sa_manager_t*,u_int32_t))checkout_by_child;
|
||||
this->public.get_ike_sa_list = (linked_list_t*(*)(ike_sa_manager_t*))get_ike_sa_list;
|
||||
this->public.get_ike_sa_list_by_name = (linked_list_t*(*)(ike_sa_manager_t*,const char*))get_ike_sa_list_by_name;
|
||||
this->public.log_status = (void(*)(ike_sa_manager_t*,logger_t*,char*))log_status;
|
||||
|
||||
@@ -92,15 +92,12 @@ struct ike_sa_manager_t {
|
||||
* CHILD_SA the kernel wants to modify.
|
||||
*
|
||||
* @param this the manager object
|
||||
* @param protocol protocol of the CHILD_SA
|
||||
* @param spi SPI of the CHILD_SA
|
||||
* @param[out] ike_sa checked out SA
|
||||
* @param reqid reqid of the CHILD_SA
|
||||
* @return
|
||||
* - NOT_FOUND, if no IKE SA with such a child found
|
||||
* - SUCCESS, if ike_sa set
|
||||
* - checked out IKE_SA, if found
|
||||
* - NULL, if not found
|
||||
*/
|
||||
status_t (*checkout_by_child) (ike_sa_manager_t* this, protocol_id_t protocol,
|
||||
u_int32_t spi, ike_sa_t **ike_sa);
|
||||
ike_sa_t* (*checkout_by_child) (ike_sa_manager_t* this, u_int32_t reqid);
|
||||
|
||||
/**
|
||||
* @brief Get a list of all IKE_SA SAs currently set up.
|
||||
|
||||
@@ -43,6 +43,7 @@
|
||||
#include <utils/linked_list.h>
|
||||
#include <queues/jobs/delete_child_sa_job.h>
|
||||
#include <queues/jobs/rekey_child_sa_job.h>
|
||||
#include <queues/jobs/acquire_job.h>
|
||||
|
||||
/** kernel level protocol identifiers */
|
||||
#define KERNEL_ESP 50
|
||||
@@ -342,44 +343,65 @@ static void receive_messages(private_kernel_interface_t *this)
|
||||
break;
|
||||
}
|
||||
|
||||
/* we handle ACQUIRE and EXPIRE messages directly
|
||||
*/
|
||||
/* we handle ACQUIRE and EXPIRE messages directly */
|
||||
hdr = (struct nlmsghdr*)response;
|
||||
if (hdr->nlmsg_type == XFRM_MSG_ACQUIRE)
|
||||
{
|
||||
struct xfrm_user_acquire *acquire;
|
||||
|
||||
acquire = (struct xfrm_user_acquire*)NLMSG_DATA(hdr);
|
||||
this->logger->log(this->logger, CONTROL,
|
||||
"Received a XFRM_MSG_ACQUIRE with index %d. Ignored",
|
||||
acquire->policy.index);
|
||||
|
||||
u_int32_t reqid = 0;
|
||||
job_t *job;
|
||||
struct rtattr *rthdr = XFRM_RTA(hdr, struct xfrm_user_acquire);
|
||||
size_t rtsize = XFRM_PAYLOAD(hdr, struct xfrm_user_tmpl);
|
||||
if (RTA_OK(rthdr, rtsize))
|
||||
{
|
||||
if (rthdr->rta_type == XFRMA_TMPL)
|
||||
{
|
||||
struct xfrm_user_tmpl* tmpl = (struct xfrm_user_tmpl*)RTA_DATA(rthdr);
|
||||
reqid = tmpl->reqid;
|
||||
}
|
||||
}
|
||||
if (reqid == 0)
|
||||
{
|
||||
this->logger->log(this->logger, ERROR,
|
||||
"Received a XFRM_MSG_ACQUIRE, but no reqid found");
|
||||
}
|
||||
else
|
||||
{
|
||||
this->logger->log(this->logger, CONTROL|LEVEL1,
|
||||
"Received a XFRM_MSG_ACQUIRE");
|
||||
this->logger->log(this->logger, CONTROL,
|
||||
"creating acquire job for CHILD_SA with reqid %d",
|
||||
reqid);
|
||||
job = (job_t*)acquire_job_create(reqid);
|
||||
charon->job_queue->add(charon->job_queue, job);
|
||||
}
|
||||
}
|
||||
else if (hdr->nlmsg_type == XFRM_MSG_EXPIRE)
|
||||
{
|
||||
job_t *job;
|
||||
protocol_id_t protocol;
|
||||
u_int32_t spi;
|
||||
u_int32_t spi, reqid;
|
||||
struct xfrm_user_expire *expire;
|
||||
|
||||
expire = (struct xfrm_user_expire*)NLMSG_DATA(hdr);
|
||||
protocol = expire->state.id.proto == KERNEL_ESP ?
|
||||
PROTO_ESP : PROTO_AH;
|
||||
spi = expire->state.id.spi;
|
||||
reqid = expire->state.reqid;
|
||||
|
||||
this->logger->log(this->logger, CONTROL|LEVEL1,
|
||||
"Received a XFRM_MSG_EXPIRE");
|
||||
this->logger->log(this->logger, CONTROL,
|
||||
"creating %s job for %s CHILD_SA 0x%x",
|
||||
"creating %s job for %s CHILD_SA 0x%x (reqid %d)",
|
||||
expire->hard ? "delete" : "rekey",
|
||||
mapping_find(protocol_id_m, protocol), ntohl(spi));
|
||||
mapping_find(protocol_id_m, protocol), ntohl(spi),
|
||||
reqid);
|
||||
if (expire->hard)
|
||||
{
|
||||
job = (job_t*)delete_child_sa_job_create(protocol, spi);
|
||||
job = (job_t*)delete_child_sa_job_create(reqid, protocol, spi);
|
||||
}
|
||||
else
|
||||
{
|
||||
job = (job_t*)rekey_child_sa_job_create(protocol, spi);
|
||||
job = (job_t*)rekey_child_sa_job_create(reqid, protocol, spi);
|
||||
}
|
||||
charon->job_queue->add(charon->job_queue, job);
|
||||
}
|
||||
@@ -670,7 +692,7 @@ static status_t update_sa(
|
||||
sa_id->spi = spi;
|
||||
sa_id->proto = (protocol == PROTO_ESP) ? KERNEL_ESP : KERNEL_AH;
|
||||
sa_id->family = dst->get_family(dst);
|
||||
POS;
|
||||
|
||||
if (send_message(this, hdr, &update) != SUCCESS)
|
||||
{
|
||||
this->logger->log(this->logger, ERROR, "netlink communication failed");
|
||||
@@ -695,7 +717,6 @@ static status_t update_sa(
|
||||
free(update);
|
||||
return FAILED;
|
||||
}
|
||||
POS;
|
||||
|
||||
this->logger->log(this->logger, CONTROL|LEVEL2, "updating SA");
|
||||
update->nlmsg_flags = NLM_F_REQUEST | NLM_F_ACK;
|
||||
@@ -731,7 +752,7 @@ static status_t update_sa(
|
||||
rthdr = RTA_NEXT(rthdr, rtsize);
|
||||
}
|
||||
}
|
||||
POS;
|
||||
|
||||
if (send_message(this, update, &response) != SUCCESS)
|
||||
{
|
||||
this->logger->log(this->logger, ERROR, "netlink communication failed");
|
||||
@@ -754,8 +775,7 @@ static status_t update_sa(
|
||||
this->logger->log(this->logger, CONTROL|LEVEL2, "deleting old SA");
|
||||
status = this->public.del_sa(&this->public, dst, spi, protocol);
|
||||
}
|
||||
POS;
|
||||
|
||||
|
||||
free(update);
|
||||
free(response);
|
||||
return status;
|
||||
@@ -1052,7 +1072,7 @@ static status_t add_policy(private_kernel_interface_t *this,
|
||||
|
||||
struct xfrm_user_tmpl *tmpl = (struct xfrm_user_tmpl*)RTA_DATA(rthdr);
|
||||
tmpl->reqid = reqid;
|
||||
tmpl->id.proto = (protocol == PROTO_ESP) ? KERNEL_ESP : KERNEL_AH;
|
||||
tmpl->id.proto = (protocol == PROTO_AH) ? KERNEL_AH : KERNEL_ESP;
|
||||
tmpl->aalgos = tmpl->ealgos = tmpl->calgos = ~0;
|
||||
tmpl->mode = TRUE;
|
||||
|
||||
|
||||
@@ -38,6 +38,7 @@
|
||||
#include <daemon.h>
|
||||
#include <crypto/x509.h>
|
||||
#include <queues/jobs/initiate_job.h>
|
||||
#include <queues/jobs/route_job.h>
|
||||
|
||||
#define IKE_PORT 500
|
||||
#define PATH_BUF 256
|
||||
@@ -518,6 +519,56 @@ static void stroke_initiate(private_stroke_t *this, stroke_msg_t *msg)
|
||||
charon->job_queue->add(charon->job_queue, (job_t*)job);
|
||||
}
|
||||
|
||||
/**
|
||||
* route/unroute a policy (install SPD entries)
|
||||
*/
|
||||
static void stroke_route(private_stroke_t *this, stroke_msg_t *msg, bool route)
|
||||
{
|
||||
route_job_t *job;
|
||||
connection_t *connection;
|
||||
policy_t *policy;
|
||||
|
||||
pop_string(msg, &(msg->route.name));
|
||||
this->logger->log(this->logger, CONTROL,
|
||||
"received stroke: %s \"%s\"",
|
||||
route ? "route" : "unroute",
|
||||
msg->route.name);
|
||||
|
||||
/* we wouldn't need a connection, but we only want to route policies
|
||||
* whose connections are keyexchange=ikev2. */
|
||||
connection = charon->connections->get_connection_by_name(charon->connections,
|
||||
msg->route.name);
|
||||
if (connection == NULL)
|
||||
{
|
||||
this->stroke_logger->log(this->stroke_logger, ERROR,
|
||||
"no connection named \"%s\"",
|
||||
msg->route.name);
|
||||
return;
|
||||
}
|
||||
if (!connection->is_ikev2(connection))
|
||||
{
|
||||
connection->destroy(connection);
|
||||
return;
|
||||
}
|
||||
|
||||
policy = charon->policies->get_policy_by_name(charon->policies,
|
||||
msg->route.name);
|
||||
if (policy == NULL)
|
||||
{
|
||||
this->stroke_logger->log(this->stroke_logger, ERROR,
|
||||
"no policy named \"%s\"",
|
||||
msg->route.name);
|
||||
connection->destroy(connection);
|
||||
return;
|
||||
}
|
||||
this->stroke_logger->log(this->stroke_logger, CONTROL,
|
||||
"%s policy \"%s\"",
|
||||
route ? "routing" : "unrouting",
|
||||
msg->route.name);
|
||||
job = route_job_create(connection, policy, route);
|
||||
charon->job_queue->add(charon->job_queue, (job_t*)job);
|
||||
}
|
||||
|
||||
/**
|
||||
* terminate a connection by name
|
||||
*/
|
||||
@@ -795,6 +846,12 @@ static void stroke_receive(private_stroke_t *this)
|
||||
case STR_INITIATE:
|
||||
stroke_initiate(this, msg);
|
||||
break;
|
||||
case STR_ROUTE:
|
||||
stroke_route(this, msg, TRUE);
|
||||
break;
|
||||
case STR_UNROUTE:
|
||||
stroke_route(this, msg, FALSE);
|
||||
break;
|
||||
case STR_TERMINATE:
|
||||
stroke_terminate(this, msg);
|
||||
break;
|
||||
|
||||
@@ -174,6 +174,10 @@ route|unroute)
|
||||
then
|
||||
$IPSEC_WHACK --name "$1" "--$op"
|
||||
fi
|
||||
if test -e $IPSEC_CHARON_PID
|
||||
then
|
||||
$IPSEC_STROKE "$op" "$1"
|
||||
fi
|
||||
exit 0
|
||||
;;
|
||||
scencrypt|scdecrypt)
|
||||
|
||||
@@ -159,7 +159,7 @@ int starter_stroke_del_conn(starter_conn_t *conn)
|
||||
|
||||
msg.type = STR_DEL_CONN;
|
||||
msg.length = offsetof(stroke_msg_t, buffer);
|
||||
msg.install.name = push_string(&msg, connection_name(conn));
|
||||
msg.del_conn.name = push_string(&msg, connection_name(conn));
|
||||
return send_stroke_msg(&msg);
|
||||
}
|
||||
|
||||
@@ -167,9 +167,9 @@ int starter_stroke_route_conn(starter_conn_t *conn)
|
||||
{
|
||||
stroke_msg_t msg;
|
||||
|
||||
msg.type = STR_INSTALL;
|
||||
msg.type = STR_ROUTE;
|
||||
msg.length = offsetof(stroke_msg_t, buffer);
|
||||
msg.install.name = push_string(&msg, connection_name(conn));
|
||||
msg.route.name = push_string(&msg, connection_name(conn));
|
||||
return send_stroke_msg(&msg);
|
||||
}
|
||||
|
||||
|
||||
@@ -169,6 +169,26 @@ static int terminate_connection(char *name)
|
||||
return send_stroke_msg(&msg);
|
||||
}
|
||||
|
||||
static int route_connection(char *name)
|
||||
{
|
||||
stroke_msg_t msg;
|
||||
|
||||
msg.type = STR_ROUTE;
|
||||
msg.length = offsetof(stroke_msg_t, buffer);
|
||||
msg.route.name = push_string(&msg, name);
|
||||
return send_stroke_msg(&msg);
|
||||
}
|
||||
|
||||
static int unroute_connection(char *name)
|
||||
{
|
||||
stroke_msg_t msg;
|
||||
|
||||
msg.type = STR_UNROUTE;
|
||||
msg.length = offsetof(stroke_msg_t, buffer);
|
||||
msg.unroute.name = push_string(&msg, name);
|
||||
return send_stroke_msg(&msg);
|
||||
}
|
||||
|
||||
static int show_status(stroke_keyword_t kw, char *connection)
|
||||
{
|
||||
stroke_msg_t msg;
|
||||
@@ -336,6 +356,20 @@ int main(int argc, char *argv[])
|
||||
}
|
||||
res = terminate_connection(argv[2]);
|
||||
break;
|
||||
case STROKE_ROUTE:
|
||||
if (argc < 3)
|
||||
{
|
||||
exit_usage("\"route\" needs a connection name");
|
||||
}
|
||||
res = route_connection(argv[2]);
|
||||
break;
|
||||
case STROKE_UNROUTE:
|
||||
if (argc < 3)
|
||||
{
|
||||
exit_usage("\"unroute\" needs a connection name");
|
||||
}
|
||||
res = unroute_connection(argv[2]);
|
||||
break;
|
||||
case STROKE_LOGTYPE:
|
||||
if (argc < 5)
|
||||
{
|
||||
|
||||
+6
-4
@@ -99,8 +99,10 @@ struct stroke_msg_t {
|
||||
enum {
|
||||
/* initiate a connection */
|
||||
STR_INITIATE,
|
||||
/* install SPD entries for a connection */
|
||||
STR_INSTALL,
|
||||
/* install SPD entries for a policy */
|
||||
STR_ROUTE,
|
||||
/* uninstall SPD entries for a policy */
|
||||
STR_UNROUTE,
|
||||
/* add a connection */
|
||||
STR_ADD_CONN,
|
||||
/* delete a connection */
|
||||
@@ -123,10 +125,10 @@ struct stroke_msg_t {
|
||||
} type;
|
||||
|
||||
union {
|
||||
/* data for STR_INITIATE, STR_INSTALL, STR_UP, STR_DOWN, ... */
|
||||
/* data for STR_INITIATE, STR_ROUTE, STR_UP, STR_DOWN, ... */
|
||||
struct {
|
||||
char *name;
|
||||
} initiate, install, terminate, status, del_conn;
|
||||
} initiate, route, unroute, terminate, status, del_conn;
|
||||
|
||||
/* data for STR_ADD_CONN */
|
||||
struct {
|
||||
|
||||
@@ -23,6 +23,7 @@ typedef enum {
|
||||
STROKE_DEL,
|
||||
STROKE_DELETE,
|
||||
STROKE_ROUTE,
|
||||
STROKE_UNROUTE,
|
||||
STROKE_UP,
|
||||
STROKE_DOWN,
|
||||
STROKE_LOGTYPE,
|
||||
|
||||
@@ -30,6 +30,7 @@ add, STROKE_ADD
|
||||
del, STROKE_DEL
|
||||
delete, STROKE_DELETE
|
||||
route, STROKE_ROUTE
|
||||
unroute, STROKE_UNROUTE
|
||||
up, STROKE_UP
|
||||
down, STROKE_DOWN
|
||||
logtype, STROKE_LOGTYPE
|
||||
|
||||
Reference in New Issue
Block a user