2012-07-13 11:32:27 +00:00
|
|
|
/*
|
|
|
|
* Copyright (C) 2012 Tobias Brunner
|
|
|
|
* Copyright (C) 2012 Giuliano Grassi
|
|
|
|
* Copyright (C) 2012 Ralf Sager
|
2018-05-23 14:04:50 +00:00
|
|
|
* HSR Hochschule fuer Technik Rapperswil
|
2012-07-13 11:32:27 +00:00
|
|
|
*
|
|
|
|
* 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 "ipsec_event_relay.h"
|
|
|
|
|
|
|
|
#include <library.h>
|
2012-10-16 14:03:21 +00:00
|
|
|
#include <utils/debug.h>
|
2012-07-13 11:32:27 +00:00
|
|
|
#include <threading/rwlock.h>
|
2012-10-16 12:54:16 +00:00
|
|
|
#include <collections/linked_list.h>
|
|
|
|
#include <collections/blocking_queue.h>
|
2012-07-13 11:32:27 +00:00
|
|
|
#include <processing/jobs/callback_job.h>
|
|
|
|
|
|
|
|
typedef struct private_ipsec_event_relay_t private_ipsec_event_relay_t;
|
|
|
|
|
|
|
|
/**
|
|
|
|
* Private additions to ipsec_event_relay_t.
|
|
|
|
*/
|
|
|
|
struct private_ipsec_event_relay_t {
|
|
|
|
|
|
|
|
/**
|
|
|
|
* Public members
|
|
|
|
*/
|
|
|
|
ipsec_event_relay_t public;
|
|
|
|
|
|
|
|
/**
|
|
|
|
* Registered listeners
|
|
|
|
*/
|
|
|
|
linked_list_t *listeners;
|
|
|
|
|
|
|
|
/**
|
|
|
|
* Lock to safely access the list of listeners
|
|
|
|
*/
|
|
|
|
rwlock_t *lock;
|
|
|
|
|
|
|
|
/**
|
|
|
|
* Blocking queue for events
|
|
|
|
*/
|
|
|
|
blocking_queue_t *queue;
|
|
|
|
};
|
|
|
|
|
|
|
|
/**
|
|
|
|
* Helper struct used to manage events in a queue
|
|
|
|
*/
|
|
|
|
typedef struct {
|
|
|
|
|
|
|
|
/**
|
|
|
|
* Type of the event
|
|
|
|
*/
|
|
|
|
enum {
|
|
|
|
IPSEC_EVENT_EXPIRE,
|
|
|
|
} type;
|
|
|
|
|
|
|
|
/**
|
2014-10-27 14:07:05 +00:00
|
|
|
* Protocol of the SA
|
2012-07-13 11:32:27 +00:00
|
|
|
*/
|
2016-03-22 12:22:01 +00:00
|
|
|
uint8_t protocol;
|
2012-07-13 11:32:27 +00:00
|
|
|
|
|
|
|
/**
|
|
|
|
* SPI of the SA, if any
|
|
|
|
*/
|
2016-03-22 12:22:01 +00:00
|
|
|
uint32_t spi;
|
2012-07-13 11:32:27 +00:00
|
|
|
|
2014-10-27 14:07:05 +00:00
|
|
|
/**
|
|
|
|
* SA destination address
|
|
|
|
*/
|
|
|
|
host_t *dst;
|
|
|
|
|
2012-07-13 11:32:27 +00:00
|
|
|
/**
|
|
|
|
* Additional data for specific event types
|
|
|
|
*/
|
|
|
|
union {
|
|
|
|
|
|
|
|
struct {
|
|
|
|
/** TRUE in case of a hard expire */
|
|
|
|
bool hard;
|
|
|
|
} expire;
|
|
|
|
|
|
|
|
} data;
|
|
|
|
|
|
|
|
} ipsec_event_t;
|
|
|
|
|
2014-10-27 14:07:05 +00:00
|
|
|
/**
|
|
|
|
* Destroy IPsec event data
|
|
|
|
*/
|
|
|
|
static void ipsec_event_destroy(ipsec_event_t *event)
|
|
|
|
{
|
|
|
|
event->dst->destroy(event->dst);
|
|
|
|
free(event);
|
|
|
|
}
|
|
|
|
|
2012-07-13 11:32:27 +00:00
|
|
|
/**
|
|
|
|
* Dequeue events and relay them to listeners
|
|
|
|
*/
|
|
|
|
static job_requeue_t handle_events(private_ipsec_event_relay_t *this)
|
|
|
|
{
|
|
|
|
enumerator_t *enumerator;
|
|
|
|
ipsec_event_listener_t *current;
|
|
|
|
ipsec_event_t *event;
|
|
|
|
|
|
|
|
event = this->queue->dequeue(this->queue);
|
|
|
|
|
|
|
|
this->lock->read_lock(this->lock);
|
|
|
|
enumerator = this->listeners->create_enumerator(this->listeners);
|
|
|
|
while (enumerator->enumerate(enumerator, (void**)¤t))
|
|
|
|
{
|
|
|
|
switch (event->type)
|
|
|
|
{
|
|
|
|
case IPSEC_EVENT_EXPIRE:
|
|
|
|
if (current->expire)
|
|
|
|
{
|
2014-10-27 14:07:05 +00:00
|
|
|
current->expire(event->protocol, event->spi, event->dst,
|
|
|
|
event->data.expire.hard);
|
2012-07-13 11:32:27 +00:00
|
|
|
}
|
|
|
|
break;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
enumerator->destroy(enumerator);
|
|
|
|
this->lock->unlock(this->lock);
|
2014-10-27 14:07:05 +00:00
|
|
|
ipsec_event_destroy(event);
|
2012-07-13 11:32:27 +00:00
|
|
|
return JOB_REQUEUE_DIRECT;
|
|
|
|
}
|
|
|
|
|
|
|
|
METHOD(ipsec_event_relay_t, expire, void,
|
2016-03-22 12:22:01 +00:00
|
|
|
private_ipsec_event_relay_t *this, uint8_t protocol, uint32_t spi,
|
2014-10-27 14:07:05 +00:00
|
|
|
host_t *dst, bool hard)
|
2012-07-13 11:32:27 +00:00
|
|
|
{
|
|
|
|
ipsec_event_t *event;
|
|
|
|
|
|
|
|
INIT(event,
|
|
|
|
.type = IPSEC_EVENT_EXPIRE,
|
2014-10-27 14:07:05 +00:00
|
|
|
.protocol = protocol,
|
2012-07-13 11:32:27 +00:00
|
|
|
.spi = spi,
|
2014-10-27 14:07:05 +00:00
|
|
|
.dst = dst->clone(dst),
|
2012-07-13 11:32:27 +00:00
|
|
|
.data = {
|
|
|
|
.expire = {
|
|
|
|
.hard = hard,
|
|
|
|
},
|
|
|
|
},
|
|
|
|
);
|
|
|
|
this->queue->enqueue(this->queue, event);
|
|
|
|
}
|
|
|
|
|
|
|
|
METHOD(ipsec_event_relay_t, register_listener, void,
|
|
|
|
private_ipsec_event_relay_t *this, ipsec_event_listener_t *listener)
|
|
|
|
{
|
|
|
|
this->lock->write_lock(this->lock);
|
|
|
|
this->listeners->insert_last(this->listeners, listener);
|
|
|
|
this->lock->unlock(this->lock);
|
|
|
|
}
|
|
|
|
|
|
|
|
METHOD(ipsec_event_relay_t, unregister_listener, void,
|
|
|
|
private_ipsec_event_relay_t *this, ipsec_event_listener_t *listener)
|
|
|
|
{
|
|
|
|
this->lock->write_lock(this->lock);
|
|
|
|
this->listeners->remove(this->listeners, listener, NULL);
|
|
|
|
this->lock->unlock(this->lock);
|
|
|
|
}
|
|
|
|
|
|
|
|
METHOD(ipsec_event_relay_t, destroy, void,
|
|
|
|
private_ipsec_event_relay_t *this)
|
|
|
|
{
|
|
|
|
this->queue->destroy_function(this->queue, free);
|
|
|
|
this->listeners->destroy(this->listeners);
|
|
|
|
this->lock->destroy(this->lock);
|
|
|
|
free(this);
|
|
|
|
}
|
|
|
|
|
|
|
|
/**
|
|
|
|
* Described in header.
|
|
|
|
*/
|
|
|
|
ipsec_event_relay_t *ipsec_event_relay_create()
|
|
|
|
{
|
|
|
|
private_ipsec_event_relay_t *this;
|
|
|
|
|
|
|
|
INIT(this,
|
|
|
|
.public = {
|
|
|
|
.expire = _expire,
|
|
|
|
.register_listener = _register_listener,
|
|
|
|
.unregister_listener = _unregister_listener,
|
|
|
|
.destroy = _destroy,
|
|
|
|
},
|
|
|
|
.listeners = linked_list_create(),
|
|
|
|
.lock = rwlock_create(RWLOCK_TYPE_DEFAULT),
|
|
|
|
.queue = blocking_queue_create(),
|
|
|
|
);
|
|
|
|
|
|
|
|
lib->processor->queue_job(lib->processor,
|
|
|
|
(job_t*)callback_job_create((callback_job_cb_t)handle_events, this,
|
|
|
|
NULL, (callback_job_cancel_t)return_false));
|
|
|
|
|
|
|
|
return &this->public;
|
|
|
|
}
|