From 38831507795fdde6a31a21b18e6ef5b7d652b78a Mon Sep 17 00:00:00 2001 From: Martin Willi Date: Wed, 9 Feb 2011 16:15:21 +0100 Subject: [PATCH] Notify duplicate detections over a UNIX sockets to listening applications --- src/libcharon/plugins/duplicheck/Makefile.am | 6 +- .../plugins/duplicheck/duplicheck_listener.c | 9 +- .../plugins/duplicheck/duplicheck_listener.h | 7 +- .../plugins/duplicheck/duplicheck_notify.c | 211 +++++++++++++++++++++ .../plugins/duplicheck/duplicheck_notify.h | 51 +++++ .../plugins/duplicheck/duplicheck_plugin.c | 15 +- 6 files changed, 294 insertions(+), 5 deletions(-) create mode 100644 src/libcharon/plugins/duplicheck/duplicheck_notify.c create mode 100644 src/libcharon/plugins/duplicheck/duplicheck_notify.h diff --git a/src/libcharon/plugins/duplicheck/Makefile.am b/src/libcharon/plugins/duplicheck/Makefile.am index 1e2ea7f..b3acb2b 100644 --- a/src/libcharon/plugins/duplicheck/Makefile.am +++ b/src/libcharon/plugins/duplicheck/Makefile.am @@ -2,7 +2,8 @@ INCLUDES = -I$(top_srcdir)/src/libstrongswan -I$(top_srcdir)/src/libhydra \ -I$(top_srcdir)/src/libcharon -AM_CFLAGS = -rdynamic +AM_CFLAGS = -rdynamic \ + -DIPSEC_PIDDIR=\"${piddir}\" if MONOLITHIC noinst_LTLIBRARIES = libstrongswan-duplicheck.la @@ -11,6 +12,7 @@ plugin_LTLIBRARIES = libstrongswan-duplicheck.la endif libstrongswan_duplicheck_la_SOURCES = duplicheck_plugin.h duplicheck_plugin.c \ - duplicheck_listener.h duplicheck_listener.c + duplicheck_listener.h duplicheck_listener.c \ + duplicheck_notify.h duplicheck_notify.c libstrongswan_duplicheck_la_LDFLAGS = -module -avoid-version diff --git a/src/libcharon/plugins/duplicheck/duplicheck_listener.c b/src/libcharon/plugins/duplicheck/duplicheck_listener.c index 6e23daa..0902a67 100644 --- a/src/libcharon/plugins/duplicheck/duplicheck_listener.c +++ b/src/libcharon/plugins/duplicheck/duplicheck_listener.c @@ -34,6 +34,11 @@ struct private_duplicheck_listener_t { duplicheck_listener_t public; /** + * Socket to send notifications to + */ + duplicheck_notify_t *notify; + + /** * Mutex to lock hashtables */ mutex_t *mutex; @@ -176,6 +181,7 @@ METHOD(listener_t, message_hook, bool, (job_t*)delete_ike_sa_job_create(entry->sa, TRUE)); entry_destroy(entry); } + this->notify->send(this->notify, id); } } return TRUE; @@ -211,7 +217,7 @@ METHOD(duplicheck_listener_t, destroy, void, /** * See header */ -duplicheck_listener_t *duplicheck_listener_create() +duplicheck_listener_t *duplicheck_listener_create(duplicheck_notify_t *notify) { private_duplicheck_listener_t *this; @@ -224,6 +230,7 @@ duplicheck_listener_t *duplicheck_listener_create() }, .destroy = _destroy, }, + .notify = notify, .mutex = mutex_create(MUTEX_TYPE_DEFAULT), .active = hashtable_create((hashtable_hash_t)hash, (hashtable_equals_t)equals, 32), diff --git a/src/libcharon/plugins/duplicheck/duplicheck_listener.h b/src/libcharon/plugins/duplicheck/duplicheck_listener.h index 8f1a27e..7c575dd 100644 --- a/src/libcharon/plugins/duplicheck/duplicheck_listener.h +++ b/src/libcharon/plugins/duplicheck/duplicheck_listener.h @@ -21,6 +21,8 @@ #ifndef DUPLICHECK_LISTENER_H_ #define DUPLICHECK_LISTENER_H_ +#include "duplicheck_notify.h" + #include typedef struct duplicheck_listener_t duplicheck_listener_t; @@ -43,7 +45,10 @@ struct duplicheck_listener_t { /** * Create a duplicheck_listener instance. + * + * @param notify socket to send notifications to + * @return listener */ -duplicheck_listener_t *duplicheck_listener_create(); +duplicheck_listener_t *duplicheck_listener_create(duplicheck_notify_t *notify); #endif /** DUPLICHECK_LISTENER_H_ @}*/ diff --git a/src/libcharon/plugins/duplicheck/duplicheck_notify.c b/src/libcharon/plugins/duplicheck/duplicheck_notify.c new file mode 100644 index 0000000..4e76182 --- /dev/null +++ b/src/libcharon/plugins/duplicheck/duplicheck_notify.c @@ -0,0 +1,211 @@ +/* + * Copyright (C) 2011 Martin Willi + * Copyright (C) 2011 revosec AG + * + * 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 . + * + * 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 "duplicheck_notify.h" + +#include +#include +#include +#include +#include +#include + +#include +#include +#include +#include +#include + +#define DUPLICHECK_SOCKET IPSEC_PIDDIR "/charon.dck" + +typedef struct private_duplicheck_notify_t private_duplicheck_notify_t; + +/** + * Private data of an duplicheck_notify_t object. + */ +struct private_duplicheck_notify_t { + + /** + * Public duplicheck_notify_t interface. + */ + duplicheck_notify_t public; + + /** + * Callback job dispatching connections + */ + callback_job_t *job; + + /** + * Mutex to lock list + */ + mutex_t *mutex; + + /** + * List of connected sockets + */ + linked_list_t *connected; + + /** + * Socket dispatching connections + */ + int socket; +}; + +/** + * Open duplicheck unix socket + */ +static bool open_socket(private_duplicheck_notify_t *this) +{ + struct sockaddr_un addr; + mode_t old; + + addr.sun_family = AF_UNIX; + strcpy(addr.sun_path, DUPLICHECK_SOCKET); + + this->socket = socket(AF_UNIX, SOCK_SEQPACKET, 0); + if (this->socket == -1) + { + DBG1(DBG_CFG, "creating duplicheck socket failed"); + return FALSE; + } + unlink(addr.sun_path); + old = umask(~(S_IRWXU | S_IRWXG)); + if (bind(this->socket, (struct sockaddr*)&addr, sizeof(addr)) < 0) + { + DBG1(DBG_CFG, "binding duplicheck socket failed: %s", strerror(errno)); + close(this->socket); + return FALSE; + } + umask(old); + if (chown(addr.sun_path, charon->uid, charon->gid) != 0) + { + DBG1(DBG_CFG, "changing duplicheck socket permissions failed: %s", + strerror(errno)); + } + if (listen(this->socket, 3) < 0) + { + DBG1(DBG_CFG, "listening on duplicheck socket failed: %s", + strerror(errno)); + close(this->socket); + unlink(addr.sun_path); + return FALSE; + } + return TRUE; +} + +/** + * Accept duplicheck notification connections + */ +static job_requeue_t receive(private_duplicheck_notify_t *this) +{ + struct sockaddr_un addr; + int len = sizeof(addr); + uintptr_t fd; + bool oldstate; + + oldstate = thread_cancelability(TRUE); + fd = accept(this->socket, (struct sockaddr*)&addr, &len); + thread_cancelability(oldstate); + + if (fd != -1) + { + this->mutex->lock(this->mutex); + this->connected->insert_last(this->connected, (void*)fd); + this->mutex->unlock(this->mutex); + } + else + { + DBG1(DBG_CFG, "accepting duplicheck connection failed: %s", + strerror(errno)); + } + return JOB_REQUEUE_FAIR; +} + +METHOD(duplicheck_notify_t, send_, void, + private_duplicheck_notify_t *this, identification_t *id) +{ + char buf[128]; + enumerator_t *enumerator; + uintptr_t fd; + int len; + + len = snprintf(buf, sizeof(buf), "%Y", id); + if (len > 0 && len < sizeof(buf)) + { + this->mutex->lock(this->mutex); + enumerator = this->connected->create_enumerator(this->connected); + while (enumerator->enumerate(enumerator, &fd)) + { + if (send(fd, &buf, len + 1, 0) != len + 1) + { + DBG1(DBG_CFG, "sending duplicheck notify failed: %s", + strerror(errno)); + this->connected->remove_at(this->connected, enumerator); + close(fd); + } + } + enumerator->destroy(enumerator); + this->mutex->unlock(this->mutex); + } +} + +METHOD(duplicheck_notify_t, destroy, void, + private_duplicheck_notify_t *this) +{ + enumerator_t *enumerator; + uintptr_t fd; + + if (this->job) + { + this->job->cancel(this->job); + } + enumerator = this->connected->create_enumerator(this->connected); + while (enumerator->enumerate(enumerator, &fd)) + { + close(fd); + } + enumerator->destroy(enumerator); + this->connected->destroy(this->connected); + this->mutex->destroy(this->mutex); + free(this); +} + +/** + * See header + */ +duplicheck_notify_t *duplicheck_notify_create() +{ + private_duplicheck_notify_t *this; + + INIT(this, + .public = { + .send = _send_, + .destroy = _destroy, + }, + .connected = linked_list_create(), + .mutex = mutex_create(MUTEX_TYPE_DEFAULT), + ); + + if (!open_socket(this)) + { + destroy(this); + return NULL; + } + this->job = callback_job_create((callback_job_cb_t)receive, + this, NULL, NULL); + lib->processor->queue_job(lib->processor, (job_t*)this->job); + + return &this->public; +} diff --git a/src/libcharon/plugins/duplicheck/duplicheck_notify.h b/src/libcharon/plugins/duplicheck/duplicheck_notify.h new file mode 100644 index 0000000..43dd20c --- /dev/null +++ b/src/libcharon/plugins/duplicheck/duplicheck_notify.h @@ -0,0 +1,51 @@ +/* + * Copyright (C) 2011 Martin Willi + * Copyright (C) 2011 revosec AG + * + * 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 . + * + * This program is distributed in the hope that it will be useful, but + * WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY + * or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License + * for more details. + */ + +/** + * @defgroup duplicheck_notify duplicheck_notify + * @{ @ingroup duplicheck + */ + +#ifndef DUPLICHECK_NOTIFY_H_ +#define DUPLICHECK_NOTIFY_H_ + +#include + +typedef struct duplicheck_notify_t duplicheck_notify_t; + +/** + * Sends notifications over a unix socket when duplicates are detected. + */ +struct duplicheck_notify_t { + + /** + * Send a notification message if duplicate IKE_SA detected. + * + * @param id identity a duplicate tunnel has been detected + */ + void (*send)(duplicheck_notify_t *this, identification_t *id); + + /** + * Destroy a duplicheck_notify_t. + */ + void (*destroy)(duplicheck_notify_t *this); +}; + +/** + * Create a duplicheck_notify instance. + */ +duplicheck_notify_t *duplicheck_notify_create(); + +#endif /** DUPLICHECK_NOTIFY_H_ @}*/ diff --git a/src/libcharon/plugins/duplicheck/duplicheck_plugin.c b/src/libcharon/plugins/duplicheck/duplicheck_plugin.c index cbb575a..1441712 100644 --- a/src/libcharon/plugins/duplicheck/duplicheck_plugin.c +++ b/src/libcharon/plugins/duplicheck/duplicheck_plugin.c @@ -15,6 +15,7 @@ #include "duplicheck_plugin.h" +#include "duplicheck_notify.h" #include "duplicheck_listener.h" #include @@ -35,12 +36,18 @@ struct private_duplicheck_plugin_t { * Listener doing duplicate checks */ duplicheck_listener_t *listener; + + /** + * Notification sender facility + */ + duplicheck_notify_t *notify; }; METHOD(plugin_t, destroy, void, private_duplicheck_plugin_t *this) { charon->bus->remove_listener(charon->bus, &this->listener->listener); + this->notify->destroy(this->notify); this->listener->destroy(this->listener); free(this); } @@ -58,9 +65,15 @@ plugin_t *duplicheck_plugin_create() .destroy = _destroy, }, }, - .listener = duplicheck_listener_create(), + .notify = duplicheck_notify_create(), ); + if (!this->notify) + { + free(this); + return NULL; + } + this->listener = duplicheck_listener_create(this->notify); charon->bus->add_listener(charon->bus, &this->listener->listener); return &this->public.plugin; -- 2.7.4