- improved strokeing

- down connection
	- status
- some other tweaks
This commit is contained in:
Martin Willi 2006-04-04 12:45:29 +00:00
parent efadbf79e9
commit f2ee13a7e8
21 changed files with 1028 additions and 363 deletions

View File

@ -28,7 +28,7 @@ MAIN_DIR= ./
LDFLAGS= -lgmp -lpthread
CFLAGS+= -I. -Wall -g -DLEAK_DETECTIVE
CFLAGS+= -I. -O3#-Wall -g -DLEAK_DETECTIVE
# objects is extended by each included Makefile
OBJS=

View File

@ -48,7 +48,7 @@ struct private_der_decoder_t {
asn1_rule_t *rule;
/**
* First rule of the hole ruleset
* First rule of the whole ruleset
*/
asn1_rule_t *first_rule;
@ -273,6 +273,11 @@ status_t read_bitstring(private_der_decoder_t *this, chunk_t data)
data.ptr += 1;
data.len -= 1;
if (data.len < 1)
{
return FAILED;
}
chunk_t *chunk = (chunk_t*)((u_int8_t*)this->output + this->rule->data_offset);
*chunk = allocator_clone_chunk(data);
@ -302,6 +307,11 @@ u_int32_t read_length(chunk_t *data)
u_int8_t n;
size_t len;
if (data->len < 1)
{
return -1;
}
/* read first octet of length field */
n = *data->ptr;
data->ptr++; data->len--;

View File

@ -31,7 +31,6 @@
#include <types.h>
#include <utils/allocator.h>
#include <threads/stroke.h>
typedef struct private_daemon_t private_daemon_t;

View File

@ -28,7 +28,7 @@
#include <threads/scheduler.h>
#include <threads/kernel_interface.h>
#include <threads/thread_pool.h>
#include <threads/stroke.h>
#include <threads/stroke_interface.h>
#include <network/socket.h>
#include <sa/ike_sa_manager.h>
#include <queues/send_queue.h>

View File

@ -59,6 +59,60 @@
#error "BYTE_ORDER must be defined"
#endif
/**
* @mainpage
*
* @section Threading Architecture
*
* All IKEv2 stuff is handled in charon. It uses a newer and more flexible
* architecture than pluto. Charon uses a thread-pool, which allows parallel
* execution SA-management. Beside the thread-pool, there are some special purpose
* threads which do their job for the common health of the daemon.
@verbatim
+------+
| E Q |
| v u |---+ +------+ +------+
| e e | | | | | IKE- |
| n u | +-----------+ | |--| SA |
| t e | | | | I M | +------+
+------------+ | - | | Scheduler | | K a |
| receiver | +------+ | | | E n | +------+
+----+-------+ +-----------+ | - a | | IKE- |
| | +------+ | | S g |--| SA |
+-------+--+ +-----| J Q |---+ +------------+ | A e | +------+
-| socket | | o u | | | | - r |
+-------+--+ | b e | | Thread- | | |
| | - u | | Pool | | |
+----+-------+ | e |------| |---| |
| sender | +------+ +------------+ +------+
+----+-------+
| +------+
| | S Q |
| | e u |
| | n e |
+------------| d u |
| - e |
+--+---+
@endverbatim
* The thread-pool is the heart of the architecture. It processes jobs from a
* (fully synchronized) job-queue. Mostly, a job is associated with a specific
* IKE SA. These IKE SAs are synchronized, only one thread can work one an IKE SA.
* This makes it unnecesary to use further synchronisation methods once a IKE SA
* is checked out. The (rather complex) synchronization of IKE SAs is completely
* done in the IKE SA manager.
* The sceduler is responsible for event firing. It waits until a event in the
* (fully synchronized) event-queue is ready for processing and pushes the event
* down to the job-queue. A thread form the pool will pick it up as quick as
* possible. Every thread can queue events or jobs. Furter, an event can place a
* packet in the send-queue. The sender thread waits for those packets and sends
* them over the wire, via the socket. The receiver does exactly the opposite of
* the sender. It waits on the socket, reads in packets an places them on the
* job-queue for further processing by a thread from the pool.
* There are even more threads, not drawn in the upper scheme. The stroke thread
* is responsible for reading and processessing commands from another process. The
* kernel interface thread handles communication from and to the kernel via a
* netlink socket. It waits for kernel events and processes them appropriately.
*/
/**
* @defgroup config config

View File

@ -9,35 +9,35 @@ Charon uses another socket interface, called stroke. Stroke uses another
format as whack and therefore is not compatible to whack. The starter utility,
wich does fast configuration parsing, speaks both the protocols, whack and
stroke. It also handles daemon startup and termination.
Pluto uses starter for some commans, for other it uses the whack utility. To be
Pluto uses starter for some commands, for other it uses the whack utility. To be
as close to pluto as possible, charon has the same split up of commands to
starter and stroke. All commands are wrapped together in the ipsec script, which
allows transparent control of both daemons.
+-----------------------------------------+
¦ ipsec ¦
| ipsec |
+-----+--------------+---------------+----+
¦ ¦ ¦
¦ ¦ ¦
¦ +-----+-----+ ¦
+-----+----+ ¦ ¦ +-----+----+
¦ ¦ ¦ starter ¦ ¦ ¦
¦ stroke ¦ ¦ ¦ ¦ whack ¦
¦ ¦ +---+--+----+ ¦ ¦
+------+---+ ¦ ¦ +--+-------+
¦ ¦ ¦ ¦
+---+------+ ¦ ¦ +------+--+
¦ ¦ ¦ ¦ ¦ ¦
¦ charon +----+ +----+ pluto ¦
¦ ¦ ¦ ¦
| | |
| | |
| +-----+-----+ |
+-----+----+ | | +-----+----+
| | | starter | | |
| stroke | | | | whack |
| | +---+--+----+ | |
+------+---+ | | +--+-------+
| | | |
+---+------+ | | +------+--+
| | | | | |
| charon +----+ +----+ pluto |
| | | |
+-----+----+ +----+----+
¦ ¦
+-----+----+ ¦
¦ LSF ¦ ¦
+-----+----+ ¦
¦ ¦
| |
+-----+----+ |
| LSF | |
+-----+----+ |
| |
+-----+----+ +----+----+
¦ RAW Sock ¦ ¦ UDP/500 ¦
| RAW Sock | | UDP/500 |
+----------+ +---------+
Since IKEv2 uses the same port as IKEv1, both daemons must listen to UDP port
@ -60,28 +60,28 @@ execution SA-management. Beside the thread-pool, there are some special purpose
threads which do their job for the common health of the daemon.
+------+
¦ E Q ¦
¦ v u ¦---+ +------+ +------+
¦ e e ¦ ¦ ¦ ¦ ¦ IKE- ¦
¦ n u ¦ +-----------+ ¦ ¦--¦ SA ¦
¦ t e ¦ ¦ ¦ ¦ I M ¦ +------+
+------------+ ¦ - ¦ ¦ Scheduler ¦ ¦ K a ¦
¦ receiver ¦ +------+ ¦ ¦ ¦ E n ¦ +------+
+----+-------+ +-----------+ ¦ - a ¦ ¦ IKE- ¦
¦ ¦ +------+ ¦ ¦ S g ¦--¦ SA ¦
+-------+--+ +-----¦ J Q ¦---+ +------------+ ¦ A e ¦ +------+
-¦ socket ¦ ¦ o u ¦ ¦ ¦ ¦ - r ¦
+-------+--+ ¦ b e ¦ ¦ Thread- ¦ ¦ ¦
¦ ¦ - u ¦ ¦ Pool ¦ ¦ ¦
+----+-------+ ¦ e ¦------¦ ¦---¦ ¦
¦ sender ¦ +------+ +------------+ +------+
| E Q |
| v u |---+ +------+ +------+
| e e | | | | | IKE- |
| n u | +-----------+ | |--| SA |
| t e | | | | I M | +------+
+------------+ | - | | Scheduler | | K a |
| receiver | +------+ | | | E n | +------+
+----+-------+ +-----------+ | - a | | IKE- |
| | +------+ | | S g |--| SA |
+-------+--+ +-----| J Q |---+ +------------+ | A e | +------+
-| socket | | o u | | | | - r |
+-------+--+ | b e | | Thread- | | |
| | - u | | Pool | | |
+----+-------+ | e |------| |---| |
| sender | +------+ +------------+ +------+
+----+-------+
¦ +------+
¦ ¦ S Q ¦
¦ ¦ e u ¦
¦ ¦ n e ¦
+------------¦ d u ¦
¦ - e ¦
| +------+
| | S Q |
| | e u |
| | n e |
+------------| d u |
| - e |
+--+---+
The thread-pool is the heart of the architecture. It processes jobs from a

View File

@ -0,0 +1,41 @@
TODO-List for charon
======================
+ = done, - = todo, ordered by priority
+ private key loading: der, without passphrase
+ load all private keys from ipsec.d/private/ in stroke.c
+ handle leftcert and rightcert in starterstroke.c/stroke.c
+ load specified certs in stroke.c
+ extract public keys from certs
+ public key authentication
+ release for Andreas
+ stroke loglevels
+ stroke up
+ ike_sa_manager checkout_by_hosts
+ stroke down
- stroke output redirection
- stroke status
- libx509
- new charon build - libstrong?
- transforms
- utils (plus host)
- integrate asn1 parser/oid (asn1/oid)
- integrate PEM loading (pem)
- ... (more to come, for sure)
- ipsec.secrets parsing
- certificate DN parsing
- certificate subjectAltName parsing
- certificate lookup via ID
- certificate validation/chaining
- certificate exchange
- trapping
- delete notify, when to send?
- notifys on connection setup failure
- create child sa message

View File

@ -353,7 +353,8 @@ static status_t compute_auth_data (private_authenticator_t *this,
allocator_free_chunk(&octets);
if (status != SUCCESS)
{
return status;
private_key->destroy(private_key);
return status;
}
*auth_payload = auth_payload_create();

View File

@ -288,7 +288,7 @@ static status_t initiate_connection(private_ike_sa_t *this, connection_t *connec
initiator_init_t *current_state;
/* Work is done in state object of type INITIATOR_INIT. All other states are not
* initial states and so don't have a initialize_connection function */
* initial states and so don't have a initiate_connection function */
if (this->current_state->get_state(this->current_state) != INITIATOR_INIT)
{
@ -350,13 +350,29 @@ static void send_delete_ike_sa_request (private_ike_sa_t *this)
}
/**
* Implementation of protected_ike_sa_t.get_id.
* Implementation of ike_sa_t.get_id.
*/
static ike_sa_id_t* get_id(private_ike_sa_t *this)
{
return this->ike_sa_id;
}
/**
* Implementation of ike_sa_t.get_my_host.
*/
static host_t* get_my_host(private_ike_sa_t *this)
{
return this->connection->get_my_host(this->connection);;
}
/**
* Implementation of ike_sa_t.get_other_host.
*/
static host_t* get_other_host(private_ike_sa_t *this)
{
return this->connection->get_other_host(this->connection);;
}
/**
* Implementation of private_ike_sa_t.resend_last_reply.
*/
@ -998,6 +1014,12 @@ static void destroy (private_ike_sa_t *this)
}
if (this->connection)
{
host_t *me, *other;
me = this->connection->get_my_host(this->connection);
other = this->connection->get_other_host(this->connection);
this->logger->log(this->logger, AUDIT, "IKE_SA deleted between %s - %s",
me->get_address(me), other->get_address(other));
this->connection->destroy(this->connection);
}
if (this->policy)
@ -1030,6 +1052,8 @@ ike_sa_t * ike_sa_create(ike_sa_id_t *ike_sa_id)
this->protected.public.process_message = (status_t(*)(ike_sa_t*, message_t*)) process_message;
this->protected.public.initiate_connection = (status_t(*)(ike_sa_t*,connection_t*)) initiate_connection;
this->protected.public.get_id = (ike_sa_id_t*(*)(ike_sa_t*)) get_id;
this->protected.public.get_my_host = (host_t*(*)(ike_sa_t*)) get_my_host;
this->protected.public.get_other_host = (host_t*(*)(ike_sa_t*)) get_other_host;
this->protected.public.retransmit_request = (status_t (*) (ike_sa_t *, u_int32_t)) retransmit_request;
this->protected.public.get_state = (ike_sa_state_t (*) (ike_sa_t *this)) get_state;
this->protected.public.send_delete_ike_sa_request = (void (*)(ike_sa_t*)) send_delete_ike_sa_request;

View File

@ -120,6 +120,22 @@ struct ike_sa_t {
* @return ike_sa's ike_sa_id_t
*/
ike_sa_id_t* (*get_id) (ike_sa_t *this);
/**
* @brief Get local peer address of the IKE_SA.
*
* @param this calling object
* @return local host_t
*/
host_t* (*get_my_host) (ike_sa_t *this);
/**
* @brief Get remote peer address of the IKE_SA.
*
* @param this calling object
* @return remote host_t
*/
host_t* (*get_other_host) (ike_sa_t *this);
/**
* @brief Get the state of type of associated state object.

View File

@ -489,6 +489,91 @@ static status_t checkout(private_ike_sa_manager_t *this, ike_sa_id_t *ike_sa_id,
return retval;
}
/**
* Implementation of of ike_sa_manager.checkout_by_hosts.
*/
static status_t checkout_by_hosts(private_ike_sa_manager_t *this, host_t *me, host_t *other, ike_sa_t **ike_sa)
{
iterator_t *iterator;
ike_sa_id_t *ike_sa_id = NULL;
pthread_mutex_lock(&(this->mutex));
iterator = this->ike_sa_list->create_iterator(this->ike_sa_list, TRUE);
while (iterator->has_next(iterator))
{
ike_sa_entry_t *current;
host_t *sa_me, *sa_other;
iterator->current(iterator, (void**)&current);
sa_me = current->ike_sa->get_my_host(current->ike_sa);
sa_other = current->ike_sa->get_other_host(current->ike_sa);
/* one end may be default/any, but not both */
if (me->is_default_route(me))
{
if (other->is_default_route(other))
{
break;
}
if (other->equals(other, sa_other))
{
/* other matches */
ike_sa_id = current->ike_sa_id;
}
}
else if (other->is_default_route(other))
{
if (me->equals(me, sa_me))
{
/* ME matches */
ike_sa_id = current->ike_sa_id;
}
}
else
{
if (me->equals(me, sa_me) && other->equals(other, sa_other))
{
/* both matches */
ike_sa_id = current->ike_sa_id;
}
}
}
iterator->destroy(iterator);
pthread_mutex_unlock(&(this->mutex));
if (ike_sa_id)
{
/* checkout is done in the checkout function, since its rather complex */
return checkout(this, ike_sa_id, ike_sa);
}
return NOT_FOUND;
}
/**
* Implementation of ike_sa_manager_t.get_ike_sa_list.
*/
linked_list_t *get_ike_sa_list(private_ike_sa_manager_t* this)
{
linked_list_t *list;
iterator_t *iterator;
pthread_mutex_lock(&(this->mutex));
list = linked_list_create();
iterator = this->ike_sa_list->create_iterator(this->ike_sa_list, TRUE);
while (iterator->has_next(iterator))
{
ike_sa_entry_t *entry;
iterator->current(iterator, (void**)&entry);
list->insert_last(list, (void*)entry->ike_sa_id->clone(entry->ike_sa_id));
}
iterator->destroy(iterator);
pthread_mutex_unlock(&(this->mutex));
return list;
}
/**
* Implementation of ike_sa_manager_t.checkin.
*/
@ -518,7 +603,7 @@ static status_t checkin(private_ike_sa_manager_t *this, ike_sa_t *ike_sa)
else
{
this->logger->log(this->logger,ERROR,"Fatal Error: Tried to checkin nonexisting IKE_SA");
/* this SA is no more, this RELEVEL3Y should not happen */
/* this SA is no more, this REALLY should not happen */
retval = NOT_FOUND;
}
pthread_mutex_unlock(&(this->mutex));
@ -679,11 +764,13 @@ ike_sa_manager_t *ike_sa_manager_create()
/* assign public functions */
this->public.destroy = (void(*)(ike_sa_manager_t*))destroy;
this->public.create_and_checkout = (void(*)(ike_sa_manager_t*, ike_sa_t **sa))create_and_checkout;
this->public.checkout = (status_t(*)(ike_sa_manager_t*, ike_sa_id_t *sa_id, ike_sa_t **sa))checkout;
this->public.checkin = (status_t(*)(ike_sa_manager_t*, ike_sa_t *sa))checkin;
this->public.delete = (status_t(*)(ike_sa_manager_t*, ike_sa_id_t *sa_id))delete;
this->public.checkin_and_delete = (status_t(*)(ike_sa_manager_t*, ike_sa_t *ike_sa))checkin_and_delete;
this->public.create_and_checkout = (void(*)(ike_sa_manager_t*,ike_sa_t**))create_and_checkout;
this->public.checkout = (status_t(*)(ike_sa_manager_t*, ike_sa_id_t*,ike_sa_t**))checkout;
this->public.checkout_by_hosts = (status_t(*)(ike_sa_manager_t*,host_t*,host_t*,ike_sa_t**))checkout_by_hosts;
this->public.get_ike_sa_list = (linked_list_t*(*)(ike_sa_manager_t*))get_ike_sa_list;
this->public.checkin = (status_t(*)(ike_sa_manager_t*,ike_sa_t*))checkin;
this->public.delete = (status_t(*)(ike_sa_manager_t*,ike_sa_id_t*))delete;
this->public.checkin_and_delete = (status_t(*)(ike_sa_manager_t*,ike_sa_t*))checkin_and_delete;
/* initialize private functions */
this->get_next_spi = get_next_spi;

View File

@ -78,7 +78,37 @@ struct ike_sa_manager_t {
* @param ike_sa[out] checked out SA
*/
void (*create_and_checkout) (ike_sa_manager_t* ike_sa_manager,ike_sa_t **ike_sa);
/**
* @brief Check out an IKE_SA, defined be the two peers.
*
* Checking out an IKE_SA by their peer addresses may be necessary
* for kernel traps, status querying and so on... one of the hosts
* may be 0.0.0.0 (defaultroute/any), but not both.
*
* @param ike_sa_manager the manager object
* @param me host on local side
* @param other host on remote side
* @param ike_sa[out] checked out SA
* @return
* - NOT_FOUND, if no such SA found
* - SUCCESS, if SA found and ike_sa set appropriatly
*/
status_t (*checkout_by_hosts) (ike_sa_manager_t* ike_sa_manager, host_t *me, host_t *other, ike_sa_t **ike_sa);
/**
* @brief Get a list of all IKE_SA SAs currently set up.
*
* The resulting list with all IDs must be destroyd by
* the caller. There is no guarantee an ike_sa with the
* corrensponding ID really exists, since it may be deleted
* in the meantime by another thread.
*
* @param ike_sa_manager the manager object
* @return a list with ike_sa_id_t s
*/
linked_list_t *(*get_ike_sa_list) (ike_sa_manager_t* ike_sa_manager);
/**
* @brief Checkin the SA after usage.
*
@ -93,6 +123,7 @@ struct ike_sa_manager_t {
* - NOT_FOUND when not found (shouldn't happen!)
*/
status_t (*checkin) (ike_sa_manager_t* ike_sa_manager, ike_sa_t *ike_sa);
/**
* @brief Delete a SA, which was not checked out.
*

View File

@ -12,13 +12,19 @@
* for more details.
*/
#include <sys/un.h>
#include <linux/stddef.h>
#include <unistd.h>
#include <stdlib.h>
#include <sys/types.h>
#include <sys/stat.h>
#include <sys/socket.h>
#include <sys/un.h>
#include <sys/fcntl.h>
#include <unistd.h>
#include <dirent.h>
#include <errno.h>
#include <stdio.h>
#include <linux/stddef.h>
#include <threads/stroke.h>
#include "stroke.h"
static char* push_string(stroke_msg_t **strm, char *string)
{
@ -44,43 +50,51 @@ static int send_stroke_msg (stroke_msg_t *msg)
{
struct sockaddr_un ctl_addr = { AF_UNIX, STROKE_SOCKET };
int sock;
char buffer[64];
int byte_count;
sock = socket(AF_UNIX, SOCK_STREAM, 0);
if (sock < 0)
{
printf("Opening unix socket %s: %s\n", STROKE_SOCKET, strerror(errno));
fprintf(stderr, "Opening unix socket %s: %s\n", STROKE_SOCKET, strerror(errno));
return -1;
}
if (connect(sock, (struct sockaddr *)&ctl_addr,
offsetof(struct sockaddr_un, sun_path) + strlen(ctl_addr.sun_path)) < 0)
{
printf("Connect to socket failed: %s\n", strerror(errno));
fprintf(stderr, "Connect to socket failed: %s\n", strerror(errno));
close(sock);
return -1;
}
if (dup2(sock, 1) != 1)
{
printf("Unable to redirect socket output: %s\n", strerror(errno));
}
/* send message */
if (write(sock, msg, msg->length) != msg->length)
{
printf("writing to socket failed: %s\n", strerror(errno));
fprintf(stderr, "writing to socket failed: %s\n", strerror(errno));
close(sock);
return -1;
}
while ((byte_count = read(sock, buffer, sizeof(buffer)-1)) > 0)
{
buffer[byte_count] = '\0';
printf("%s", buffer);
}
if (byte_count < 0)
{
fprintf(stderr, "reading from socket failed: %s\n", strerror(errno));
}
close(sock);
return 0;
}
static int add_connection(char *name,
char *my_id, char *other_id,
char *my_addr, char *other_addr,
char *my_cert, char *other_cert,
char *my_addr, char *other_addr,
char *my_net, char *other_net,
u_int8_t my_netmask, u_int8_t other_netmask)
u_int my_netmask, u_int other_netmask)
{
stroke_msg_t *msg = malloc(sizeof(stroke_msg_t));
int res;
@ -91,11 +105,13 @@ static int add_connection(char *name,
msg->add_conn.name = push_string(&msg, name);
msg->add_conn.me.id = push_string(&msg, my_id);
msg->add_conn.me.cert = push_string(&msg, my_cert);
msg->add_conn.me.address = push_string(&msg, my_addr);
msg->add_conn.me.subnet = push_string(&msg, my_net);
msg->add_conn.me.subnet_mask = my_netmask;
msg->add_conn.other.id = push_string(&msg, other_id);
msg->add_conn.other.cert = push_string(&msg, other_cert);
msg->add_conn.other.address = push_string(&msg, other_addr);
msg->add_conn.other.subnet = push_string(&msg, other_net);
msg->add_conn.other.subnet_mask = other_netmask;
@ -118,20 +134,171 @@ static int initiate_connection(char *name)
return res;
}
static int terminate_connection(char *name)
{
stroke_msg_t *msg = malloc(sizeof(stroke_msg_t));
int res;
msg->length = sizeof(stroke_msg_t);
msg->type = STR_TERMINATE;
msg->initiate.name = push_string(&msg, name);
res = send_stroke_msg(msg);
free(msg);
return res;
}
static int show_status()
{
stroke_msg_t *msg = malloc(sizeof(stroke_msg_t));
int res;
msg->length = sizeof(stroke_msg_t);
msg->type = STR_STATUS;
res = send_stroke_msg(msg);
free(msg);
return res;
}
static int set_logtype(char *context, char *type, int enable)
{
stroke_msg_t *msg = malloc(sizeof(stroke_msg_t));
int res;
msg->length = sizeof(stroke_msg_t);
msg->type = STR_LOGTYPE;
msg->logtype.context = push_string(&msg, context);
msg->logtype.type = push_string(&msg, type);
msg->logtype.enable = enable;
res = send_stroke_msg(msg);
free(msg);
return res;
}
static int set_loglevel(char *context, u_int level)
{
stroke_msg_t *msg = malloc(sizeof(stroke_msg_t));
int res;
msg->length = sizeof(stroke_msg_t);
msg->type = STR_LOGLEVEL;
msg->loglevel.context = push_string(&msg, context);
msg->loglevel.level = level;
res = send_stroke_msg(msg);
free(msg);
return res;
}
static void exit_error(char *error)
{
if (error)
{
fprintf(stderr, "%s\n", error);
}
exit(-1);
}
static void exit_usage(char *error)
{
printf("Usage:\n");
printf(" Add a connection:\n");
printf(" stroke add NAME MY_ID OTHER_ID MY_CERT OTHER_CERT\\\n");
printf(" MY_ADDR OTHER_ADDR MY_NET OTHER_NET\\\n");
printf(" MY_NETBITS OTHER_NETBITS\n");
printf(" where: ID is any IKEv2 ID (currently only IPv4 adresses\n");
printf(" CERT is a certificate filename\n");
printf(" ADDR is a IPv4 address\n");
printf(" NET is a IPv4 address of the subnet to tunnel\n");
printf(" NETBITS is the size of the subnet, as the \"24\" in 192.168.0.0/24\n");
printf(" Initiate a connection:\n");
printf(" stroke up NAME\n");
printf(" where: NAME is a connection name added with \"stroke add\"\n");
printf(" Terminate a connection:\n");
printf(" stroke down NAME\n");
printf(" where: NAME is a connection name added with \"stroke add\"\n");
printf(" Set logtype for a logging context:\n");
printf(" stroke logtype CONTEXT TYPE ENABLE\n");
printf(" where: CONTEXT is PARSR|GNRAT|IKESA|SAMGR|CHDSA|MESSG|TPOOL|WORKR|SCHED|\n");
printf(" SENDR|RECVR|SOCKT|TESTR|DAEMN|CONFG|ENCPL|PAYLD\n");
printf(" TYPE is CONTROL|ERROR|AUDIT|RAW|PRIVATE\n");
printf(" ENABLE is 0|1\n");
printf(" Set loglevel for a logging context:\n");
printf(" stroke loglevel CONTEXT LEVEL\n");
printf(" where: CONTEXT is PARSR|GNRAT|IKESA|SAMGR|CHDSA|MESSG|TPOOL|WORKR|SCHED|\n");
printf(" SENDR|RECVR|SOCKT|TESTR|DAEMN|CONFG|ENCPL|PAYLD\n");
printf(" LEVEL is 0|1|2|3\n");
printf(" Show connection status:\n");
printf(" stroke status\n");
exit_error(error);
}
int main(int argc, char *argv[])
{
add_connection("alice", NULL, NULL,
"192.168.0.1", "192.168.0.2",
"10.1.0.0", "10.2.0.0", 16, 16);
int res;
add_connection("bob", "192.168.0.2", "192.168.0.1",
"192.168.0.2", "192.168.0.1",
"10.2.0.0", "10.1.0.0", 16, 16);
if (argc == 2)
if (argc < 2)
{
initiate_connection(argv[1]);
exit_usage(NULL);
}
if (strcmp(argv[1], "status") == 0 ||
strcmp(argv[1], "statusall") == 0)
{
res = show_status();
}
else if (strcmp(argv[1], "up") == 0)
{
if (argc < 3)
{
exit_usage("\"up\" needs a connection name");
}
res = initiate_connection(argv[2]);
}
else if (strcmp(argv[1], "down") == 0)
{
if (argc < 3)
{
exit_usage("\"down\" needs a connection name");
}
res = terminate_connection(argv[2]);
}
else if (strcmp(argv[1], "add") == 0)
{
if (argc < 13)
{
exit_usage("\"add\" needs more parameters...");
}
res = add_connection(argv[2],
argv[3], argv[4],
argv[5], argv[6],
argv[7], argv[8],
argv[9], argv[10],
atoi(argv[11]), atoi(argv[12]));
}
else if (strcmp(argv[1], "logtype") == 0)
{
if (argc < 5)
{
exit_usage("\"logtype\" needs more parameters...");
}
res = set_logtype(argv[2], argv[3], atoi(argv[4]));
}
else if (strcmp(argv[1], "loglevel") == 0)
{
if (argc < 4)
{
exit_usage("\"logtype\" needs more parameters...");
}
res = set_loglevel(argv[2], atoi(argv[3]));
}
else
{
exit_usage(NULL);
}
if (res)
{
exit_error("communication with charon failed!\n");
}
return 0;
}

View File

@ -85,14 +85,11 @@ static char certificate_buffer[] = {
*/
void test_certificate(protected_tester_t *tester)
{
//chunk_t certificate = {certificate_buffer, sizeof(certificate_buffer)};
chunk_t certificate = {certificate_buffer, sizeof(certificate_buffer)};
//certificate_t *cert = certificate_create_from_chunk(certificate);
certificate_t *cert = certificate_create_from_chunk(certificate);
certificate_t *cert = certificate_create_from_file("myCert.der");
//certificate_t *cert = certificate_create_from_file("myCert.der");
cert->destroy(cert);
}

View File

@ -34,6 +34,6 @@ OBJS+= $(BUILD_DIR)kernel_interface.o
$(BUILD_DIR)kernel_interface.o :$(THREADS_DIR)kernel_interface.c $(THREADS_DIR)kernel_interface.h
$(CC) $(CFLAGS) -c -o $@ $<
OBJS+= $(BUILD_DIR)stroke.o
$(BUILD_DIR)stroke.o : $(THREADS_DIR)stroke.c $(THREADS_DIR)stroke.h
OBJS+= $(BUILD_DIR)stroke_interface.o
$(BUILD_DIR)stroke_interface.o :$(THREADS_DIR)stroke_interface.c $(THREADS_DIR)stroke_interface.h
$(CC) $(CFLAGS) -c -o $@ $<

View File

@ -31,8 +31,9 @@
#include <errno.h>
#include <pthread.h>
#include "stroke.h"
#include "stroke_interface.h"
#include <stroke.h>
#include <types.h>
#include <daemon.h>
#include <transforms/certificate.h>
@ -145,12 +146,17 @@ struct private_stroke_t {
linked_list_t *private_keys;
/**
* Assigned logger_t object.
* Assigned logger_t object in charon.
*/
logger_t *logger;
/**
* Logger which logs to stroke
*/
logger_t *stroke_logger;
/**
* Unix socket to use for communication
* Unix socket to listen for strokes
*/
int socket;
@ -260,6 +266,420 @@ static void load_private_keys(private_stroke_t *this)
closedir(dir);
}
/**
* Add a connection to the configuration list
*/
static void stroke_add_conn(private_stroke_t *this, stroke_msg_t *msg)
{
connection_t *connection;
policy_t *policy;
identification_t *my_id, *other_id;
host_t *my_host, *other_host, *my_subnet, *other_subnet;
proposal_t *proposal;
traffic_selector_t *my_ts, *other_ts;
certificate_t *my_cert, *other_cert;
rsa_private_key_t *private_key = NULL;
rsa_public_key_t *public_key = NULL;
pop_string(msg, &msg->add_conn.name);
pop_string(msg, &msg->add_conn.me.address);
pop_string(msg, &msg->add_conn.other.address);
pop_string(msg, &msg->add_conn.me.id);
pop_string(msg, &msg->add_conn.other.id);
pop_string(msg, &msg->add_conn.me.cert);
pop_string(msg, &msg->add_conn.other.cert);
pop_string(msg, &msg->add_conn.me.subnet);
pop_string(msg, &msg->add_conn.other.subnet);
this->logger->log(this->logger, CONTROL, "received stroke: add connection \"%s\"", msg->add_conn.name);
my_host = host_create(AF_INET, msg->add_conn.me.address, 500);
if (my_host == NULL)
{
this->stroke_logger->log(this->stroke_logger, ERROR, "invalid host: %s", msg->add_conn.me.address);
return;
}
other_host = host_create(AF_INET, msg->add_conn.other.address, 500);
if (other_host == NULL)
{
this->stroke_logger->log(this->stroke_logger, ERROR, "invalid host: %s", msg->add_conn.other.address);
my_host->destroy(my_host);
return;
}
my_id = identification_create_from_string(ID_IPV4_ADDR,
*msg->add_conn.me.id ? msg->add_conn.me.id : msg->add_conn.me.address);
if (my_id == NULL)
{
this->stroke_logger->log(this->stroke_logger, ERROR, "invalid id: %s", msg->add_conn.me.id);
my_host->destroy(my_host);
other_host->destroy(other_host);
return;
}
other_id = identification_create_from_string(ID_IPV4_ADDR,
*msg->add_conn.other.id ? msg->add_conn.other.id : msg->add_conn.other.address);
if (other_id == NULL)
{
my_host->destroy(my_host);
other_host->destroy(other_host);
my_id->destroy(my_id);
this->stroke_logger->log(this->stroke_logger, ERROR, "invalid id: %s", msg->add_conn.other.id);
return;
}
my_subnet = host_create(AF_INET, *msg->add_conn.me.subnet ? msg->add_conn.me.subnet : msg->add_conn.me.address, 500);
if (my_subnet == NULL)
{
my_host->destroy(my_host);
other_host->destroy(other_host);
my_id->destroy(my_id);
other_id->destroy(other_id);
this->stroke_logger->log(this->stroke_logger, ERROR, "invalid subnet: %s", msg->add_conn.me.subnet);
return;
}
other_subnet = host_create(AF_INET, *msg->add_conn.other.subnet ? msg->add_conn.other.subnet : msg->add_conn.other.address, 500);
if (other_subnet == NULL)
{
my_host->destroy(my_host);
other_host->destroy(other_host);
my_id->destroy(my_id);
other_id->destroy(other_id);
my_subnet->destroy(my_subnet);
this->stroke_logger->log(this->stroke_logger, ERROR, "invalid subnet: %s", msg->add_conn.me.subnet);
return;
}
my_ts = traffic_selector_create_from_subnet(my_subnet, *msg->add_conn.me.subnet ? msg->add_conn.me.subnet_mask : 32);
my_subnet->destroy(my_subnet);
other_ts = traffic_selector_create_from_subnet(other_subnet, *msg->add_conn.other.subnet ? msg->add_conn.other.subnet_mask : 32);
other_subnet->destroy(other_subnet);
if (charon->socket->is_listening_on(charon->socket, other_host))
{
this->stroke_logger->log(this->stroke_logger, CONTROL|LEVEL1, "left is other host, switching");
host_t *tmp_host = my_host;
identification_t *tmp_id = my_id;
traffic_selector_t *tmp_ts = my_ts;
char *tmp_cert = msg->add_conn.me.cert;
my_host = other_host;
other_host = tmp_host;
my_id = other_id;
other_id = tmp_id;
my_ts = other_ts;
other_ts = tmp_ts;
msg->add_conn.me.cert = msg->add_conn.other.cert;
msg->add_conn.other.cert = tmp_cert;
}
else if (charon->socket->is_listening_on(charon->socket, my_host))
{
this->stroke_logger->log(this->stroke_logger, CONTROL|LEVEL1, "left is own host, not switching");
}
else
{
this->stroke_logger->log(this->stroke_logger, ERROR, "left nor right host is our, aborting");
my_host->destroy(my_host);
other_host->destroy(other_host);
my_id->destroy(my_id);
other_id->destroy(other_id);
my_ts->destroy(my_ts);
other_ts->destroy(other_ts);
return;
}
connection = connection_create(my_host, other_host, my_id->clone(my_id), other_id->clone(other_id),
RSA_DIGITAL_SIGNATURE);
proposal = proposal_create(1);
proposal->add_algorithm(proposal, PROTO_IKE, ENCRYPTION_ALGORITHM, ENCR_AES_CBC, 16);
proposal->add_algorithm(proposal, PROTO_IKE, INTEGRITY_ALGORITHM, AUTH_HMAC_SHA1_96, 0);
proposal->add_algorithm(proposal, PROTO_IKE, INTEGRITY_ALGORITHM, AUTH_HMAC_MD5_96, 0);
proposal->add_algorithm(proposal, PROTO_IKE, PSEUDO_RANDOM_FUNCTION, PRF_HMAC_SHA1, 0);
proposal->add_algorithm(proposal, PROTO_IKE, PSEUDO_RANDOM_FUNCTION, PRF_HMAC_MD5, 0);
proposal->add_algorithm(proposal, PROTO_IKE, DIFFIE_HELLMAN_GROUP, MODP_2048_BIT, 0);
proposal->add_algorithm(proposal, PROTO_IKE, DIFFIE_HELLMAN_GROUP, MODP_1536_BIT, 0);
proposal->add_algorithm(proposal, PROTO_IKE, DIFFIE_HELLMAN_GROUP, MODP_1024_BIT, 0);
proposal->add_algorithm(proposal, PROTO_IKE, DIFFIE_HELLMAN_GROUP, MODP_4096_BIT, 0);
proposal->add_algorithm(proposal, PROTO_IKE, DIFFIE_HELLMAN_GROUP, MODP_8192_BIT, 0);
connection->add_proposal(connection, proposal);
policy = policy_create(my_id, other_id);
proposal = proposal_create(1);
proposal->add_algorithm(proposal, PROTO_ESP, ENCRYPTION_ALGORITHM, ENCR_AES_CBC, 16);
proposal->add_algorithm(proposal, PROTO_ESP, INTEGRITY_ALGORITHM, AUTH_HMAC_SHA1_96, 0);
proposal->add_algorithm(proposal, PROTO_ESP, INTEGRITY_ALGORITHM, AUTH_HMAC_MD5_96, 0);
policy->add_proposal(policy, proposal);
policy->add_my_traffic_selector(policy, my_ts);
policy->add_other_traffic_selector(policy, other_ts);
chdir(CERTIFICATE_DIR);
my_cert = certificate_create_from_file(msg->add_conn.me.cert);
if (my_cert == NULL)
{
this->stroke_logger->log(this->stroke_logger, ERROR, "loading own certificate \"%s%s\" failed",
CERTIFICATE_DIR, msg->add_conn.me.cert);
}
else
{
public_key = my_cert->get_public_key(my_cert);
private_key = find_private_key(this, public_key);
public_key->destroy(public_key);
if (private_key)
{
this->stroke_logger->log(this->stroke_logger, CONTROL|LEVEL1, "found private key for certificate \"%s%s\"",
CERTIFICATE_DIR, msg->add_conn.me.cert);
}
else
{
this->stroke_logger->log(this->stroke_logger, ERROR, "no private key for certificate \"%s%s\" found",
CERTIFICATE_DIR, msg->add_conn.me.cert);
}
my_cert->destroy(my_cert);
}
other_cert = certificate_create_from_file(msg->add_conn.other.cert);
public_key = NULL;
if (other_cert == NULL)
{
this->stroke_logger->log(this->stroke_logger, ERROR, "loading peers certificate \"%s%s\" failed",
CERTIFICATE_DIR, msg->add_conn.other.cert);
}
else
{
public_key = other_cert->get_public_key(other_cert);
this->stroke_logger->log(this->stroke_logger, CONTROL|LEVEL1, "loaded certificate \"%s%s\" (%p)",
CERTIFICATE_DIR, msg->add_conn.other.cert, public_key);
other_cert->destroy(other_cert);
}
this->configurations->insert_last(this->configurations,
configuration_entry_create(msg->add_conn.name, connection, policy, private_key, public_key));
this->stroke_logger->log(this->stroke_logger, CONTROL|LEVEL1, "connection \"%s\" added (%d in store)",
msg->add_conn.name,
this->configurations->get_count(this->configurations));
}
/**
* initiate a connection by name
*/
static void stroke_initiate(private_stroke_t *this, stroke_msg_t *msg)
{
initiate_ike_sa_job_t *job;
connection_t *connection;
pop_string(msg, &(msg->initiate.name));
this->logger->log(this->logger, CONTROL, "received stroke: initiate \"%s\"", msg->initiate.name);
connection = this->get_connection_by_name(this, msg->initiate.name);
if (connection == NULL)
{
this->stroke_logger->log(this->stroke_logger, ERROR, "could not find a connection named \"%s\"", msg->initiate.name);
}
else
{
job = initiate_ike_sa_job_create(connection->clone(connection));
charon->job_queue->add(charon->job_queue, (job_t*)job);
}
}
/**
* terminate a connection by name
*/
static void stroke_terminate(private_stroke_t *this, stroke_msg_t *msg)
{
connection_t *connection;
ike_sa_t *ike_sa;
host_t *my_host, *other_host;
status_t status;
pop_string(msg, &(msg->terminate.name));
this->logger->log(this->logger, CONTROL, "received stroke: terminate \"%s\"", msg->terminate.name);
connection = this->get_connection_by_name(this, msg->terminate.name);
if (connection)
{
my_host = connection->get_my_host(connection);
other_host = connection->get_other_host(connection);
status = charon->ike_sa_manager->checkout_by_hosts(charon->ike_sa_manager,
my_host, other_host, &ike_sa);
if (status == SUCCESS)
{
this->stroke_logger->log(this->stroke_logger, CONTROL, "deleting IKE SA between %s - %s",
my_host->get_address(my_host), other_host->get_address(other_host));
charon->ike_sa_manager->checkin_and_delete(charon->ike_sa_manager, ike_sa);
}
else
{
this->stroke_logger->log(this->stroke_logger, ERROR, "no active connection found between %s - %s",
my_host->get_address(my_host), other_host->get_address(other_host));
}
}
else
{
this->stroke_logger->log(this->stroke_logger, ERROR, "could not find a connection named \"%s\"", msg->terminate.name);
}
}
/**
* show status of (established) connections
*/
static void stroke_status(private_stroke_t *this, stroke_msg_t *msg)
{
linked_list_t *list;
iterator_t *iterator;
status_t status;
list = charon->ike_sa_manager->get_ike_sa_list(charon->ike_sa_manager);
iterator = list->create_iterator(list, TRUE);
while (iterator->has_next(iterator))
{
ike_sa_id_t *ike_sa_id;
ike_sa_t *ike_sa;
iterator->current(iterator, (void**)&ike_sa_id);
status = charon->ike_sa_manager->checkout(charon->ike_sa_manager, ike_sa_id, &ike_sa);
if (status == SUCCESS)
{
host_t *me, *other;
me = ike_sa->get_my_host(ike_sa);
other = ike_sa->get_other_host(ike_sa);
this->stroke_logger->log(this->stroke_logger, CONTROL, "IKE SA in state %s as %s",
mapping_find(ike_sa_state_m, ike_sa->get_state(ike_sa)),
ike_sa_id->is_initiator ? "initiator" : "responder");
this->stroke_logger->log(this->stroke_logger, CONTROL, " SPIs: %15lld - %-15lld",
ike_sa_id->get_initiator_spi(ike_sa_id),
ike_sa_id->get_responder_spi(ike_sa_id));
this->stroke_logger->log(this->stroke_logger, CONTROL, " Addr: %15s - %-15s",
me->get_address(me), other->get_address(other));
charon->ike_sa_manager->checkin(charon->ike_sa_manager, ike_sa);
}
ike_sa_id->destroy(ike_sa_id);
}
iterator->destroy(iterator);
list->destroy(list);
}
logger_context_t get_context(char *context)
{
if (strcasecmp(context, "ALL") == 0) return ALL_LOGGERS;
else if (strcasecmp(context, "PARSR") == 0) return PARSER;
else if (strcasecmp(context, "GNRAT") == 0) return GENERATOR;
else if (strcasecmp(context, "IKESA") == 0) return IKE_SA;
else if (strcasecmp(context, "SAMGR") == 0) return IKE_SA_MANAGER;
else if (strcasecmp(context, "CHDSA") == 0) return CHILD_SA;
else if (strcasecmp(context, "MESSG") == 0) return MESSAGE;
else if (strcasecmp(context, "TPOOL") == 0) return THREAD_POOL;
else if (strcasecmp(context, "WORKR") == 0) return WORKER;
else if (strcasecmp(context, "SCHED") == 0) return SCHEDULER;
else if (strcasecmp(context, "SENDR") == 0) return SENDER;
else if (strcasecmp(context, "RECVR") == 0) return RECEIVER;
else if (strcasecmp(context, "SOCKT") == 0) return SOCKET;
else if (strcasecmp(context, "TESTR") == 0) return TESTER;
else if (strcasecmp(context, "DAEMN") == 0) return DAEMON;
else if (strcasecmp(context, "CONFG") == 0) return CONFIG;
else if (strcasecmp(context, "ENCPL") == 0) return ENCRYPTION_PAYLOAD;
else if (strcasecmp(context, "PAYLD") == 0) return PAYLOAD;
else return -2;
}
/**
* set the type of logged messages in a context
*/
static void stroke_logtype(private_stroke_t *this, stroke_msg_t *msg)
{
pop_string(msg, &(msg->logtype.context));
pop_string(msg, &(msg->logtype.type));
this->logger->log(this->logger, CONTROL, "received stroke: logtype for %s", msg->logtype.context);
log_level_t level;
logger_context_t context = get_context(msg->logtype.context);
if (context == -2)
{
this->stroke_logger->log(this->stroke_logger, ERROR, "invalid context (%s)!", msg->logtype.context);
return;
}
if (strcasecmp(msg->logtype.type, "CONTROL") == 0) level = CONTROL;
else if (strcasecmp(msg->logtype.type, "ERROR") == 0) level = ERROR;
else if (strcasecmp(msg->logtype.type, "AUDIT") == 0) level = AUDIT;
else if (strcasecmp(msg->logtype.type, "RAW") == 0) level = RAW;
else if (strcasecmp(msg->logtype.type, "PRIVATE") == 0) level = PRIVATE;
else
{
this->stroke_logger->log(this->stroke_logger, ERROR, "invalid type (%s)!", msg->logtype.type);
return;
}
if (msg->logtype.enable)
{
charon->logger_manager->enable_log_level(charon->logger_manager,
context, level);
}
else
{
charon->logger_manager->disable_log_level(charon->logger_manager,
context, level);
}
}
/**
* set the verbosity of a logger
*/
static void stroke_loglevel(private_stroke_t *this, stroke_msg_t *msg)
{
pop_string(msg, &(msg->loglevel.context));
this->logger->log(this->logger, CONTROL, "received stroke: log_level for %s", msg->loglevel.context);
log_level_t level;
logger_context_t context = get_context(msg->loglevel.context);
if (context == -2)
{
this->stroke_logger->log(this->stroke_logger, ERROR, "invalid context (%s)!", msg->loglevel.context);
return;
}
if (msg->loglevel.level == 0)
{
level = LEVEL0;
}
else if (msg->loglevel.level == 1)
{
level = LEVEL1;
}
else if (msg->loglevel.level == 2)
{
level = LEVEL2;
}
else if (msg->loglevel.level == 3)
{
level = LEVEL3;
}
else
{
this->stroke_logger->log(this->stroke_logger, ERROR, "invalid level (%d)!", msg->loglevel.level);
return;
}
charon->logger_manager->enable_log_level(charon->logger_manager, context, level);
}
/**
* Implementation of private_stroke_t.stroke_receive.
*/
@ -271,6 +691,7 @@ static void stroke_receive(private_stroke_t *this)
int strokeaddrlen = sizeof(strokeaddr);
ssize_t bytes_read;
int strokefd;
FILE *strokefile;
while (1)
{
@ -278,7 +699,7 @@ static void stroke_receive(private_stroke_t *this)
if (strokefd < 0)
{
this->logger->log(this->logger, ERROR, "accepting stroke connection failed");
this->logger->log(this->logger, ERROR, "accepting stroke connection failed: %s", strerror(errno));
continue;
}
@ -296,233 +717,61 @@ static void stroke_receive(private_stroke_t *this)
bytes_read = recv(strokefd, msg, msg_length, 0);
if (bytes_read != msg_length)
{
this->logger->log(this->logger, ERROR, "reading stroke message failed");
this->logger->log(this->logger, ERROR, "reading stroke message failed: %s");
close(strokefd);
continue;
}
strokefile = fdopen(dup(strokefd), "w");
if (strokefile == NULL)
{
this->logger->log(this->logger, ERROR, "opening stroke output channel failed:", strerror(errno));
close(strokefd);
allocator_free(msg);
continue;
}
this->stroke_logger = logger_create("-", CONTROL|ERROR, FALSE, strokefile);
this->logger->log_bytes(this->logger, RAW, "stroke message", (void*)msg, msg_length);
switch (msg->type)
{
case STR_INITIATE:
{
initiate_ike_sa_job_t *job;
connection_t *connection;
pop_string(msg, &(msg->initiate.name));
this->logger->log(this->logger, CONTROL, "received stroke: initiate \"%s\"", msg->initiate.name);
connection = this->get_connection_by_name(this, msg->initiate.name);
if (connection == NULL)
{
this->logger->log(this->logger, ERROR, "could not find a connection named \"%s\"", msg->initiate.name);
}
else
{
job = initiate_ike_sa_job_create(connection);
charon->job_queue->add(charon->job_queue, (job_t*)job);
}
stroke_initiate(this, msg);
break;
}
case STR_INSTALL:
case STR_TERMINATE:
{
pop_string(msg, &(msg->install.name));
this->logger->log(this->logger, CONTROL, "received stroke: install \"%s\"", msg->install.name);
stroke_terminate(this, msg);
break;
}
case STR_STATUS:
{
stroke_status(this, msg);
break;
}
case STR_ADD_CONN:
{
connection_t *connection;
policy_t *policy;
identification_t *my_id, *other_id;
host_t *my_host, *other_host, *my_subnet, *other_subnet;
proposal_t *proposal;
traffic_selector_t *my_ts, *other_ts;
certificate_t *my_cert, *other_cert;
rsa_private_key_t *private_key = NULL;
rsa_public_key_t *public_key = NULL;
pop_string(msg, &msg->add_conn.name);
pop_string(msg, &msg->add_conn.me.address);
pop_string(msg, &msg->add_conn.other.address);
pop_string(msg, &msg->add_conn.me.id);
pop_string(msg, &msg->add_conn.other.id);
pop_string(msg, &msg->add_conn.me.cert);
pop_string(msg, &msg->add_conn.other.cert);
pop_string(msg, &msg->add_conn.me.subnet);
pop_string(msg, &msg->add_conn.other.subnet);
this->logger->log(this->logger, CONTROL, "received stroke: add connection \"%s\"", msg->add_conn.name);
my_host = host_create(AF_INET, msg->add_conn.me.address, 500);
if (my_host == NULL)
{
this->logger->log(this->logger, ERROR, "received invalid host: %s", msg->add_conn.me.address);
break;
}
other_host = host_create(AF_INET, msg->add_conn.other.address, 500);
if (other_host == NULL)
{
this->logger->log(this->logger, ERROR, "received invalid host: %s", msg->add_conn.other.address);
my_host->destroy(my_host);
break;
}
my_id = identification_create_from_string(ID_IPV4_ADDR,
*msg->add_conn.me.id ? msg->add_conn.me.id : msg->add_conn.me.address);
if (my_id == NULL)
{
this->logger->log(this->logger, ERROR, "received invalid id: %s", msg->add_conn.me.id);
my_host->destroy(my_host);
other_host->destroy(other_host);
break;
}
other_id = identification_create_from_string(ID_IPV4_ADDR,
*msg->add_conn.other.id ? msg->add_conn.other.id : msg->add_conn.other.address);
if (other_id == NULL)
{
my_host->destroy(my_host);
other_host->destroy(other_host);
my_id->destroy(my_id);
this->logger->log(this->logger, ERROR, "received invalid id: %s", msg->add_conn.other.id);
break;
}
my_subnet = host_create(AF_INET, *msg->add_conn.me.subnet ? msg->add_conn.me.subnet : msg->add_conn.me.address, 500);
if (my_subnet == NULL)
{
my_host->destroy(my_host);
other_host->destroy(other_host);
my_id->destroy(my_id);
other_id->destroy(other_id);
this->logger->log(this->logger, ERROR, "received invalid subnet: %s", msg->add_conn.me.subnet);
break;
}
other_subnet = host_create(AF_INET, *msg->add_conn.other.subnet ? msg->add_conn.other.subnet : msg->add_conn.other.address, 500);
if (other_subnet == NULL)
{
my_host->destroy(my_host);
other_host->destroy(other_host);
my_id->destroy(my_id);
other_id->destroy(other_id);
my_subnet->destroy(my_subnet);
this->logger->log(this->logger, ERROR, "received invalid subnet: %s", msg->add_conn.me.subnet);
break;
}
my_ts = traffic_selector_create_from_subnet(my_subnet, *msg->add_conn.me.subnet ? msg->add_conn.me.subnet_mask : 32);
my_subnet->destroy(my_subnet);
other_ts = traffic_selector_create_from_subnet(other_subnet, *msg->add_conn.other.subnet ? msg->add_conn.other.subnet_mask : 32);
other_subnet->destroy(other_subnet);
if (charon->socket->is_listening_on(charon->socket, other_host))
{
this->logger->log(this->logger, CONTROL|LEVEL1, "left is other host, switching");
host_t *tmp_host = my_host;
identification_t *tmp_id = my_id;
traffic_selector_t *tmp_ts = my_ts;
char *tmp_cert = msg->add_conn.me.cert;
my_host = other_host;
other_host = tmp_host;
my_id = other_id;
other_id = tmp_id;
my_ts = other_ts;
other_ts = tmp_ts;
msg->add_conn.me.cert = msg->add_conn.other.cert;
msg->add_conn.other.cert = tmp_cert;
}
else if (charon->socket->is_listening_on(charon->socket, my_host))
{
this->logger->log(this->logger, CONTROL|LEVEL1, "left is own host, not switching");
}
else
{
this->logger->log(this->logger, ERROR, "left nor right host is our, aborting");
my_host->destroy(my_host);
other_host->destroy(other_host);
my_id->destroy(my_id);
other_id->destroy(other_id);
my_ts->destroy(my_ts);
other_ts->destroy(other_ts);
break;
}
connection = connection_create(my_host, other_host, my_id->clone(my_id), other_id->clone(other_id),
RSA_DIGITAL_SIGNATURE);
proposal = proposal_create(1);
proposal->add_algorithm(proposal, PROTO_IKE, ENCRYPTION_ALGORITHM, ENCR_AES_CBC, 16);
proposal->add_algorithm(proposal, PROTO_IKE, INTEGRITY_ALGORITHM, AUTH_HMAC_SHA1_96, 0);
proposal->add_algorithm(proposal, PROTO_IKE, INTEGRITY_ALGORITHM, AUTH_HMAC_MD5_96, 0);
proposal->add_algorithm(proposal, PROTO_IKE, PSEUDO_RANDOM_FUNCTION, PRF_HMAC_SHA1, 0);
proposal->add_algorithm(proposal, PROTO_IKE, PSEUDO_RANDOM_FUNCTION, PRF_HMAC_MD5, 0);
proposal->add_algorithm(proposal, PROTO_IKE, DIFFIE_HELLMAN_GROUP, MODP_2048_BIT, 0);
proposal->add_algorithm(proposal, PROTO_IKE, DIFFIE_HELLMAN_GROUP, MODP_1536_BIT, 0);
proposal->add_algorithm(proposal, PROTO_IKE, DIFFIE_HELLMAN_GROUP, MODP_1024_BIT, 0);
proposal->add_algorithm(proposal, PROTO_IKE, DIFFIE_HELLMAN_GROUP, MODP_4096_BIT, 0);
proposal->add_algorithm(proposal, PROTO_IKE, DIFFIE_HELLMAN_GROUP, MODP_8192_BIT, 0);
connection->add_proposal(connection, proposal);
policy = policy_create(my_id, other_id);
proposal = proposal_create(1);
proposal->add_algorithm(proposal, PROTO_ESP, ENCRYPTION_ALGORITHM, ENCR_AES_CBC, 16);
proposal->add_algorithm(proposal, PROTO_ESP, INTEGRITY_ALGORITHM, AUTH_HMAC_SHA1_96, 0);
proposal->add_algorithm(proposal, PROTO_ESP, INTEGRITY_ALGORITHM, AUTH_HMAC_MD5_96, 0);
policy->add_proposal(policy, proposal);
policy->add_my_traffic_selector(policy, my_ts);
policy->add_other_traffic_selector(policy, other_ts);
chdir(CERTIFICATE_DIR);
my_cert = certificate_create_from_file(msg->add_conn.me.cert);
if (my_cert == NULL)
{
this->logger->log(this->logger, ERROR, "loading own certificate \"%s%s\" failed",
CERTIFICATE_DIR, msg->add_conn.me.cert);
}
else
{
private_key = find_private_key(this, my_cert->get_public_key(my_cert));
if (private_key)
{
this->logger->log(this->logger, CONTROL|LEVEL1, "found private key for certificate \"%s%s\"",
CERTIFICATE_DIR, msg->add_conn.me.cert);
}
else
{
this->logger->log(this->logger, ERROR, "no private key for certificate \"%s%s\" found",
CERTIFICATE_DIR, msg->add_conn.me.cert);
}
}
other_cert = certificate_create_from_file(msg->add_conn.other.cert);
if (other_cert == NULL)
{
this->logger->log(this->logger, ERROR, "loading peers certificate \"%s%s\" failed",
CERTIFICATE_DIR, msg->add_conn.other.cert);
}
else
{
public_key = other_cert->get_public_key(other_cert);
this->logger->log(this->logger, CONTROL|LEVEL1, "loaded certificate \"%s%s\" (%p)",
CERTIFICATE_DIR, msg->add_conn.other.cert, public_key);
}
this->configurations->insert_last(this->configurations,
configuration_entry_create(msg->add_conn.name, connection, policy, private_key, public_key));
this->logger->log(this->logger, CONTROL|LEVEL1, "connection \"%s\" added (%d in store)",
msg->add_conn.name,
this->configurations->get_count(this->configurations));
stroke_add_conn(this, msg);
break;
}
case STR_LOGTYPE:
{
stroke_logtype(this, msg);
break;
}
case STR_LOGLEVEL:
{
stroke_loglevel(this, msg);
break;
}
case STR_DEL_CONN:
default:
this->logger->log(this->logger, ERROR, "received invalid stroke");
}
this->stroke_logger->destroy(this->stroke_logger);
fclose(strokefile);
close(strokefd);
allocator_free(msg);
}
@ -657,7 +906,7 @@ static connection_t *get_connection_by_name(private_stroke_t *this, char *name)
if (strcmp(entry->name,name) == 0)
{
/* found configuration */
found = entry->connection->clone(entry->connection);
found = entry->connection;
break;
}
}
@ -752,7 +1001,7 @@ static status_t get_rsa_public_key(credential_store_t *store, identification_t *
if (config->public_key)
{
iterator->destroy(iterator);
*public_key = config->public_key;
*public_key = config->public_key->clone(config->public_key);
return SUCCESS;
}
}
@ -780,7 +1029,7 @@ static status_t get_rsa_private_key(credential_store_t *store, identification_t
if (config->private_key)
{
iterator->destroy(iterator);
*private_key = config->private_key;
*private_key = config->private_key->clone(config->private_key);
return SUCCESS;
}
}

View File

@ -28,52 +28,10 @@
#include <config/credential_store.h>
#define STROKE_SOCKET "/var/run/charon.ctl"
#define IPSEC_DIR "/etc/ipsec.d/"
#define PRIVATE_KEY_DIR IPSEC_DIR "private/"
#define CERTIFICATE_DIR IPSEC_DIR "certs/"
/**
* @brief A stroke message sent over the unix socket.
*
*/
typedef struct stroke_msg_t stroke_msg_t;
struct stroke_msg_t {
/* length of this message with all strings */
u_int16_t length;
/* type of the message */
enum {
/* initiate a connection */
STR_INITIATE,
/* install SPD entries for a connection */
STR_INSTALL,
/* add a connection */
STR_ADD_CONN,
/* delete a connection */
STR_DEL_CONN,
/* more to come */
} type;
union {
/* data for STR_INITIATE, STR_INSTALL */
struct {
char *name;
} initiate, install;
/* data for STR_ADD_CONN */
struct {
char *name;
struct {
char *id;
char *cert;
char *address;
char *subnet;
u_int8_t subnet_mask;
} me, other;
} add_conn;
};
u_int8_t buffer[];
};
typedef struct stroke_t stroke_t;

View File

@ -145,7 +145,6 @@ static rsa_public_key_t *get_public_key(private_certificate_t *this)
return this->public_key->clone(this->public_key);
}
/**
* Implementation of certificate.destroy.
*/

View File

@ -155,6 +155,8 @@ static asn1_rule_t rsa_private_key_rules[] = {
{ASN1_END, 0, 0, 0},
};
static private_rsa_private_key_t *rsa_private_key_create_empty();
/**
* Implementation of private_rsa_private_key_t.compute_prime.
*/
@ -389,6 +391,25 @@ bool belongs_to(private_rsa_private_key_t *this, rsa_public_key_t *public)
return FALSE;
}
/**
* Implementation of rsa_private_key.clone.
*/
static rsa_private_key_t* _clone(private_rsa_private_key_t *this)
{
private_rsa_private_key_t *clone = rsa_private_key_create_empty();
mpz_init_set(clone->n, this->n);
mpz_init_set(clone->e, this->e);
mpz_init_set(clone->p, this->p);
mpz_init_set(clone->q, this->q);
mpz_init_set(clone->d, this->d);
mpz_init_set(clone->exp1, this->exp1);
mpz_init_set(clone->exp2, this->exp2);
mpz_init_set(clone->coeff, this->coeff);
clone->k = this->k;
return &clone->public;
}
/**
* Implementation of rsa_private_key.destroy.
@ -419,6 +440,7 @@ static private_rsa_private_key_t *rsa_private_key_create_empty()
this->public.save_key = (status_t (*) (rsa_private_key_t*,char*))save_key;
this->public.get_public_key = (rsa_public_key_t *(*) (rsa_private_key_t*))get_public_key;
this->public.belongs_to = (bool (*) (rsa_private_key_t*,rsa_public_key_t*))belongs_to;
this->public.clone = (rsa_private_key_t*(*)(rsa_private_key_t*))_clone;
this->public.destroy = (void (*) (rsa_private_key_t*))destroy;
/* private functions */

View File

@ -125,6 +125,14 @@ struct rsa_private_key_t {
*/
bool (*belongs_to) (rsa_private_key_t *this, rsa_public_key_t *public);
/**
* @brief Clone the private key.
*
* @param this private key to clone
* @return clone of this
*/
rsa_private_key_t *(*clone) (rsa_private_key_t *this);
/**
* @brief Destroys the private key.
*

View File

@ -54,31 +54,33 @@ mapping_t logger_context_t_mappings[] = {
{MAPPING_END, NULL},
};
#define DEFAULT_OUTPUT NULL
struct {
char *name;
log_level_t level;
bool log_thread_ids;
FILE *output;
} logger_defaults[] = {
{ "PARSR", ERROR|CONTROL|AUDIT|LEVEL0, TRUE, NULL}, /* PARSER */
{ "GNRAT", ERROR|CONTROL|AUDIT|LEVEL0, TRUE, NULL}, /* GENERATOR */
{ "IKESA", ERROR|CONTROL|AUDIT|LEVEL0, TRUE, NULL}, /* IKE_SA */
{ "SAMGR", ERROR|CONTROL|AUDIT|LEVEL0, TRUE, NULL}, /* IKE_SA_MANAGER */
{ "CHDSA", ERROR|CONTROL|AUDIT|LEVEL0, TRUE, NULL}, /* CHILD_SA */
{ "MESSG", ERROR|CONTROL|AUDIT|LEVEL0, TRUE, NULL}, /* MESSAGE */
{ "TPOOL", ERROR|CONTROL|AUDIT|LEVEL0, FALSE, NULL}, /* THREAD_POOL */
{ "WORKR", ERROR|CONTROL|AUDIT|LEVEL0, TRUE, NULL}, /* WORKER */
{ "SCHED", ERROR|CONTROL|AUDIT|LEVEL0, FALSE, NULL}, /* SCHEDULER */
{ "SENDR", ERROR|CONTROL|AUDIT|LEVEL0, FALSE, NULL}, /* SENDER */
{ "RECVR", ERROR|CONTROL|AUDIT|LEVEL0, FALSE, NULL}, /* RECEIVER */
{ "SOCKT", ERROR|CONTROL|AUDIT|LEVEL0, FALSE, NULL}, /* SOCKET */
{ "TESTR", ERROR|CONTROL|AUDIT|LEVEL0, FALSE, NULL}, /* TESTER */
{ "DAEMN", ERROR|CONTROL|AUDIT|LEVEL0, FALSE, NULL}, /* DAEMON */
{ "CONFG", ERROR|CONTROL|AUDIT|LEVEL0, TRUE, NULL}, /* CONFIG */
{ "ENCPL", ERROR|CONTROL|AUDIT|LEVEL0, TRUE, NULL}, /* ENCRYPTION_PAYLOAD */
{ "PAYLD", ERROR|CONTROL|AUDIT|LEVEL0, TRUE, NULL}, /* PAYLOAD */
{ "DERDC", ERROR|CONTROL|AUDIT|LEVEL0, TRUE, NULL}, /* DER_DECODER */
{ "DEREC", ERROR|CONTROL|AUDIT|LEVEL0, TRUE, NULL}, /* DER_ENCODER */
{ "PARSR", ERROR|CONTROL|AUDIT|LEVEL0, TRUE, DEFAULT_OUTPUT}, /* PARSER */
{ "GNRAT", ERROR|CONTROL|AUDIT|LEVEL0, TRUE, DEFAULT_OUTPUT}, /* GENERATOR */
{ "IKESA", ERROR|CONTROL|AUDIT|LEVEL0, TRUE, DEFAULT_OUTPUT}, /* IKE_SA */
{ "SAMGR", ERROR|CONTROL|AUDIT|LEVEL0, TRUE, DEFAULT_OUTPUT}, /* IKE_SA_MANAGER */
{ "CHDSA", ERROR|CONTROL|AUDIT|LEVEL0, TRUE, DEFAULT_OUTPUT}, /* CHILD_SA */
{ "MESSG", ERROR|CONTROL|AUDIT|LEVEL0, TRUE, DEFAULT_OUTPUT}, /* MESSAGE */
{ "TPOOL", ERROR|CONTROL|AUDIT|LEVEL0, FALSE, DEFAULT_OUTPUT}, /* THREAD_POOL */
{ "WORKR", ERROR|CONTROL|AUDIT|LEVEL0, TRUE, DEFAULT_OUTPUT}, /* WORKER */
{ "SCHED", ERROR|CONTROL|AUDIT|LEVEL0, FALSE, DEFAULT_OUTPUT}, /* SCHEDULER */
{ "SENDR", ERROR|CONTROL|AUDIT|LEVEL0, FALSE, DEFAULT_OUTPUT}, /* SENDER */
{ "RECVR", ERROR|CONTROL|AUDIT|LEVEL0, FALSE, DEFAULT_OUTPUT}, /* RECEIVER */
{ "SOCKT", ERROR|CONTROL|AUDIT|LEVEL0, FALSE, DEFAULT_OUTPUT}, /* SOCKET */
{ "TESTR", ERROR|CONTROL|AUDIT|LEVEL0, FALSE, DEFAULT_OUTPUT}, /* TESTER */
{ "DAEMN", ERROR|CONTROL|AUDIT|LEVEL0, FALSE, DEFAULT_OUTPUT}, /* DAEMON */
{ "CONFG", ERROR|CONTROL|AUDIT|LEVEL0, TRUE, DEFAULT_OUTPUT}, /* CONFIG */
{ "ENCPL", ERROR|CONTROL|AUDIT|LEVEL0, TRUE, DEFAULT_OUTPUT}, /* ENCRYPTION_PAYLOAD */
{ "PAYLD", ERROR|CONTROL|AUDIT|LEVEL0, TRUE, DEFAULT_OUTPUT}, /* PAYLOAD */
{ "DERDC", ERROR|CONTROL|AUDIT|LEVEL0, TRUE, DEFAULT_OUTPUT}, /* DER_DECODER */
{ "DEREC", ERROR|CONTROL|AUDIT|LEVEL0, TRUE, DEFAULT_OUTPUT}, /* DER_ENCODER */
};
@ -202,7 +204,7 @@ logger_manager_t *logger_manager_create(log_level_t default_log_level)
for (i = 0; i < LOGGER_CONTEXT_ROOF; i++)
{
this->loggers[i] = logger_create(logger_defaults[i].name, logger_defaults[i].level,
logger_defaults[i].log_thread_ids, logger_defaults[i].output);
logger_defaults[i].log_thread_ids, stdout);//logger_defaults[i].output);
}
return &this->public;