diff options
Diffstat (limited to 'ipsec-tools/src/racoon/evt.c')
-rw-r--r-- | ipsec-tools/src/racoon/evt.c | 399 |
1 files changed, 399 insertions, 0 deletions
diff --git a/ipsec-tools/src/racoon/evt.c b/ipsec-tools/src/racoon/evt.c new file mode 100644 index 00000000..11d96954 --- /dev/null +++ b/ipsec-tools/src/racoon/evt.c @@ -0,0 +1,399 @@ +/* $NetBSD: evt.c,v 1.10 2010/10/21 06:15:28 tteras Exp $ */ + +/* Id: evt.c,v 1.5 2006/06/22 20:11:35 manubsd Exp */ + +/* + * Copyright (C) 2004 Emmanuel Dreyfus + * Copyright (C) 2008 Timo Teras + * All rights reserved. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions + * are met: + * 1. Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * 2. Redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in the + * documentation and/or other materials provided with the distribution. + * 3. Neither the name of the project nor the names of its contributors + * may be used to endorse or promote products derived from this software + * without specific prior written permission. + * + * THIS SOFTWARE IS PROVIDED BY THE PROJECT AND CONTRIBUTORS ``AS IS'' AND + * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE + * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE + * ARE DISCLAIMED. IN NO EVENT SHALL THE PROJECT OR CONTRIBUTORS BE LIABLE + * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL + * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS + * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) + * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT + * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY + * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF + * SUCH DAMAGE. + */ + +#include "config.h" + +#include <errno.h> +#include <string.h> +#include <stdio.h> +#include <time.h> +#include <unistd.h> +#include <stdlib.h> +#include <sys/queue.h> +#include <sys/socket.h> + +#include "vmbuf.h" +#include "plog.h" +#include "misc.h" +#include "admin.h" +#include "handler.h" +#include "session.h" +#include "gcmalloc.h" +#include "evt.h" +#include "var.h" + +#ifdef ENABLE_ADMINPORT + +static EVT_LISTENER_LIST(evt_listeners); + +struct evt_message { + struct admin_com adm; + struct evt_async evt; +}; + +struct evt { + struct evtdump *dump; + TAILQ_ENTRY(evt) next; +}; + +TAILQ_HEAD(evtlist, evt); + +#define EVTLIST_MAX 32 + +static struct evtlist evtlist = TAILQ_HEAD_INITIALIZER(evtlist); +static int evtlist_len = 0; +static int evtlist_inuse = 0; + +static struct { + int newtype, oldtype; +} evttype_map[] = { + { EVT_RACOON_QUIT, EVTT_RACOON_QUIT }, + { EVT_PHASE1_UP, EVTT_PHASE1_UP }, + { EVT_PHASE1_DOWN, EVTT_PHASE1_DOWN }, + { EVT_PHASE1_NO_RESPONSE, EVTT_PEER_NO_RESPONSE }, + { EVT_PHASE1_NO_PROPOSAL, EVTT_PEERPH1_NOPROP }, + { EVT_PHASE1_AUTH_FAILED, EVTT_PEERPH1AUTH_FAILED }, + { EVT_PHASE1_DPD_TIMEOUT, EVTT_DPD_TIMEOUT }, + { EVT_PHASE1_PEER_DELETED, EVTT_PEER_DELETE }, + { EVT_PHASE1_MODE_CFG, EVTT_ISAKMP_CFG_DONE }, + { EVT_PHASE1_XAUTH_SUCCESS, EVTT_XAUTH_SUCCESS }, + { EVT_PHASE1_XAUTH_FAILED, EVTT_XAUTH_FAILED }, + { EVT_PHASE2_NO_PHASE1, -1 }, + { EVT_PHASE2_UP, EVTT_PHASE2_UP }, + { EVT_PHASE2_DOWN, EVTT_PHASE2_DOWN }, + { EVT_PHASE2_NO_RESPONSE, EVTT_PEER_NO_RESPONSE }, +}; + +static void +evt_push(src, dst, type, optdata) + struct sockaddr *src; + struct sockaddr *dst; + int type; + vchar_t *optdata; +{ + struct evtdump *evtdump; + struct evt *evt; + size_t len; + int i; + + /* If admin socket is disabled, silently discard anything */ + if (adminsock_path == NULL || !evtlist_inuse) + return; + + /* Map the event type to old */ + for (i = 0; i < sizeof(evttype_map) / sizeof(evttype_map[0]); i++) + if (evttype_map[i].newtype == type) + break; + if (i >= sizeof(evttype_map) / sizeof(evttype_map[0])) + return; + + type = evttype_map[i].oldtype; + if (type < 0) + return; + + /* If we are above the limit, don't record anything */ + if (evtlist_len > EVTLIST_MAX) { + plog(LLV_DEBUG, LOCATION, NULL, + "Cannot record event: event queue overflowed\n"); + return; + } + + /* If we hit the limit, record an overflow event instead */ + if (evtlist_len == EVTLIST_MAX) { + plog(LLV_ERROR, LOCATION, NULL, + "Cannot record event: event queue overflow\n"); + src = NULL; + dst = NULL; + type = EVTT_OVERFLOW; + optdata = NULL; + } + + len = sizeof(*evtdump); + if (optdata) + len += optdata->l; + + if ((evtdump = racoon_malloc(len)) == NULL) { + plog(LLV_ERROR, LOCATION, NULL, "Cannot record event: %s\n", + strerror(errno)); + return; + } + + if ((evt = racoon_malloc(sizeof(*evt))) == NULL) { + plog(LLV_ERROR, LOCATION, NULL, "Cannot record event: %s\n", + strerror(errno)); + racoon_free(evtdump); + return; + } + + if (src) + memcpy(&evtdump->src, src, sysdep_sa_len(src)); + if (dst) + memcpy(&evtdump->dst, dst, sysdep_sa_len(dst)); + evtdump->len = len; + evtdump->type = type; + time(&evtdump->timestamp); + + if (optdata) + memcpy(evtdump + 1, optdata->v, optdata->l); + + evt->dump = evtdump; + TAILQ_INSERT_TAIL(&evtlist, evt, next); + + evtlist_len++; + + return; +} + +static struct evtdump * +evt_pop(void) { + struct evtdump *evtdump; + struct evt *evt; + + if ((evt = TAILQ_FIRST(&evtlist)) == NULL) + return NULL; + + evtdump = evt->dump; + TAILQ_REMOVE(&evtlist, evt, next); + racoon_free(evt); + evtlist_len--; + + return evtdump; +} + +vchar_t * +evt_dump(void) { + struct evtdump *evtdump; + vchar_t *buf = NULL; + + if (!evtlist_inuse) { + evtlist_inuse = 1; + plog(LLV_ERROR, LOCATION, NULL, + "evt_dump: deprecated event polling used\n"); + } + + if ((evtdump = evt_pop()) != NULL) { + if ((buf = vmalloc(evtdump->len)) == NULL) { + plog(LLV_ERROR, LOCATION, NULL, + "evt_dump failed: %s\n", strerror(errno)); + return NULL; + } + memcpy(buf->v, evtdump, evtdump->len); + racoon_free(evtdump); + } + + return buf; +} + +static struct evt_message * +evtmsg_create(type, optdata) + int type; + vchar_t *optdata; +{ + struct evt_message *e; + size_t len; + + len = sizeof(struct evt_message); + if (optdata != NULL) + len += optdata->l; + + if ((e = racoon_malloc(len)) == NULL) { + plog(LLV_ERROR, LOCATION, NULL, "Cannot allocate event: %s\n", + strerror(errno)); + return NULL; + } + + memset(e, 0, sizeof(struct evt_message)); + e->adm.ac_len = len; + e->adm.ac_cmd = ADMIN_SHOW_EVT; + e->adm.ac_errno = 0; + e->adm.ac_proto = 0; + e->evt.ec_type = type; + time(&e->evt.ec_timestamp); + if (optdata != NULL) + memcpy(e + 1, optdata->v, optdata->l); + + return e; +} + +static void +evt_unsubscribe(l) + struct evt_listener *l; +{ + plog(LLV_DEBUG, LOCATION, NULL, + "[%d] admin connection released\n", l->fd); + + LIST_REMOVE(l, ll_chain); + unmonitor_fd(l->fd); + close(l->fd); + racoon_free(l); +} + +static int +evt_unsubscribe_cb(ctx, fd) + void *ctx; + int fd; +{ + evt_unsubscribe((struct evt_listener *) ctx); + return 0; +} + +static void +evtmsg_broadcast(ll, e) + const struct evt_listener_list *ll; + struct evt_message *e; +{ + struct evt_listener *l, *nl; + + for (l = LIST_FIRST(ll); l != NULL; l = nl) { + nl = LIST_NEXT(l, ll_chain); + + if (send(l->fd, e, e->adm.ac_len, MSG_DONTWAIT) < 0) { + plog(LLV_DEBUG, LOCATION, NULL, "Cannot send event to fd: %s\n", + strerror(errno)); + evt_unsubscribe(l); + } + } +} + +void +evt_generic(type, optdata) + int type; + vchar_t *optdata; +{ + struct evt_message *e; + + if ((e = evtmsg_create(type, optdata)) == NULL) + return; + + evtmsg_broadcast(&evt_listeners, e); + evt_push(&e->evt.ec_ph1src, &e->evt.ec_ph1dst, type, optdata); + + racoon_free(e); +} + +void +evt_phase1(ph1, type, optdata) + const struct ph1handle *ph1; + int type; + vchar_t *optdata; +{ + struct evt_message *e; + + if ((e = evtmsg_create(type, optdata)) == NULL) + return; + + if (ph1->local) + memcpy(&e->evt.ec_ph1src, ph1->local, sysdep_sa_len(ph1->local)); + if (ph1->remote) + memcpy(&e->evt.ec_ph1dst, ph1->remote, sysdep_sa_len(ph1->remote)); + + evtmsg_broadcast(&ph1->evt_listeners, e); + evtmsg_broadcast(&evt_listeners, e); + evt_push(&e->evt.ec_ph1src, &e->evt.ec_ph1dst, type, optdata); + + racoon_free(e); +} + +void +evt_phase2(ph2, type, optdata) + const struct ph2handle *ph2; + int type; + vchar_t *optdata; +{ + struct evt_message *e; + struct ph1handle *ph1 = ph2->ph1; + + if ((e = evtmsg_create(type, optdata)) == NULL) + return; + + if (ph1) { + if (ph1->local) + memcpy(&e->evt.ec_ph1src, ph1->local, sysdep_sa_len(ph1->local)); + if (ph1->remote) + memcpy(&e->evt.ec_ph1dst, ph1->remote, sysdep_sa_len(ph1->remote)); + } + e->evt.ec_ph2msgid = ph2->msgid; + + evtmsg_broadcast(&ph2->evt_listeners, e); + if (ph1) + evtmsg_broadcast(&ph1->evt_listeners, e); + evtmsg_broadcast(&evt_listeners, e); + evt_push(&e->evt.ec_ph1src, &e->evt.ec_ph1dst, type, optdata); + + racoon_free(e); +} + +int +evt_subscribe(list, fd) + struct evt_listener_list *list; + int fd; +{ + struct evt_listener *l; + + if ((l = racoon_malloc(sizeof(*l))) == NULL) { + plog(LLV_ERROR, LOCATION, NULL, + "Cannot allocate event listener: %s\n", + strerror(errno)); + return errno; + } + + if (list == NULL) + list = &evt_listeners; + + LIST_INSERT_HEAD(list, l, ll_chain); + l->fd = fd; + monitor_fd(l->fd, evt_unsubscribe_cb, l, 0); + + plog(LLV_DEBUG, LOCATION, NULL, + "[%d] admin connection is polling events\n", fd); + + return -2; +} + +void +evt_list_init(list) + struct evt_listener_list *list; +{ + LIST_INIT(list); +} + +void +evt_list_cleanup(list) + struct evt_listener_list *list; +{ + while (!LIST_EMPTY(list)) + evt_unsubscribe(LIST_FIRST(list)); +} + +#endif /* ENABLE_ADMINPORT */ |