1/* $NetBSD: evt.c,v 1.11 2018/05/19 20:14:56 maxv Exp $ */ 2 3/* Id: evt.c,v 1.5 2006/06/22 20:11:35 manubsd Exp */ 4 5/* 6 * Copyright (C) 2004 Emmanuel Dreyfus 7 * Copyright (C) 2008 Timo Teras 8 * All rights reserved. 9 * 10 * Redistribution and use in source and binary forms, with or without 11 * modification, are permitted provided that the following conditions 12 * are met: 13 * 1. Redistributions of source code must retain the above copyright 14 * notice, this list of conditions and the following disclaimer. 15 * 2. Redistributions in binary form must reproduce the above copyright 16 * notice, this list of conditions and the following disclaimer in the 17 * documentation and/or other materials provided with the distribution. 18 * 3. Neither the name of the project nor the names of its contributors 19 * may be used to endorse or promote products derived from this software 20 * without specific prior written permission. 21 * 22 * THIS SOFTWARE IS PROVIDED BY THE PROJECT AND CONTRIBUTORS ``AS IS'' AND 23 * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE 24 * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE 25 * ARE DISCLAIMED. IN NO EVENT SHALL THE PROJECT OR CONTRIBUTORS BE LIABLE 26 * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL 27 * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS 28 * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) 29 * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT 30 * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY 31 * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF 32 * SUCH DAMAGE. 33 */ 34 35#include "config.h" 36 37#include <errno.h> 38#include <string.h> 39#include <stdio.h> 40#include <time.h> 41#include <unistd.h> 42#include <stdlib.h> 43#include <sys/queue.h> 44#include <sys/socket.h> 45 46#include "vmbuf.h" 47#include "plog.h" 48#include "misc.h" 49#include "admin.h" 50#include "handler.h" 51#include "session.h" 52#include "gcmalloc.h" 53#include "evt.h" 54#include "var.h" 55 56#ifdef ENABLE_ADMINPORT 57 58static EVT_LISTENER_LIST(evt_listeners); 59 60struct evt_message { 61 struct admin_com adm; 62 struct evt_async evt; 63}; 64 65struct evt { 66 struct evtdump *dump; 67 TAILQ_ENTRY(evt) next; 68}; 69 70TAILQ_HEAD(evtlist, evt); 71 72#define EVTLIST_MAX 32 73 74static struct evtlist evtlist = TAILQ_HEAD_INITIALIZER(evtlist); 75static int evtlist_len = 0; 76static int evtlist_inuse = 0; 77 78static struct { 79 int newtype, oldtype; 80} evttype_map[] = { 81 { EVT_RACOON_QUIT, EVTT_RACOON_QUIT }, 82 { EVT_PHASE1_UP, EVTT_PHASE1_UP }, 83 { EVT_PHASE1_DOWN, EVTT_PHASE1_DOWN }, 84 { EVT_PHASE1_NO_RESPONSE, EVTT_PEER_NO_RESPONSE }, 85 { EVT_PHASE1_NO_PROPOSAL, EVTT_PEERPH1_NOPROP }, 86 { EVT_PHASE1_AUTH_FAILED, EVTT_PEERPH1AUTH_FAILED }, 87 { EVT_PHASE1_DPD_TIMEOUT, EVTT_DPD_TIMEOUT }, 88 { EVT_PHASE1_PEER_DELETED, EVTT_PEER_DELETE }, 89 { EVT_PHASE1_MODE_CFG, EVTT_ISAKMP_CFG_DONE }, 90 { EVT_PHASE1_XAUTH_SUCCESS, EVTT_XAUTH_SUCCESS }, 91 { EVT_PHASE1_XAUTH_FAILED, EVTT_XAUTH_FAILED }, 92 { EVT_PHASE2_NO_PHASE1, -1 }, 93 { EVT_PHASE2_UP, EVTT_PHASE2_UP }, 94 { EVT_PHASE2_DOWN, EVTT_PHASE2_DOWN }, 95 { EVT_PHASE2_NO_RESPONSE, EVTT_PEER_NO_RESPONSE }, 96}; 97 98static void 99evt_push(src, dst, type, optdata) 100 struct sockaddr *src; 101 struct sockaddr *dst; 102 int type; 103 vchar_t *optdata; 104{ 105 struct evtdump *evtdump; 106 struct evt *evt; 107 size_t len; 108 int i; 109 110 /* If admin socket is disabled, silently discard anything */ 111 if (adminsock_path == NULL || !evtlist_inuse) 112 return; 113 114 /* Map the event type to old */ 115 for (i = 0; i < sizeof(evttype_map) / sizeof(evttype_map[0]); i++) 116 if (evttype_map[i].newtype == type) 117 break; 118 if (i >= sizeof(evttype_map) / sizeof(evttype_map[0])) 119 return; 120 121 type = evttype_map[i].oldtype; 122 if (type < 0) 123 return; 124 125 /* If we are above the limit, don't record anything */ 126 if (evtlist_len > EVTLIST_MAX) { 127 plog(LLV_DEBUG, LOCATION, NULL, 128 "Cannot record event: event queue overflowed\n"); 129 return; 130 } 131 132 /* If we hit the limit, record an overflow event instead */ 133 if (evtlist_len == EVTLIST_MAX) { 134 plog(LLV_ERROR, LOCATION, NULL, 135 "Cannot record event: event queue overflow\n"); 136 src = NULL; 137 dst = NULL; 138 type = EVTT_OVERFLOW; 139 optdata = NULL; 140 } 141 142 len = sizeof(*evtdump); 143 if (optdata) 144 len += optdata->l; 145 146 if ((evtdump = racoon_malloc(len)) == NULL) { 147 plog(LLV_ERROR, LOCATION, NULL, "Cannot record event: %s\n", 148 strerror(errno)); 149 return; 150 } 151 152 if ((evt = racoon_malloc(sizeof(*evt))) == NULL) { 153 plog(LLV_ERROR, LOCATION, NULL, "Cannot record event: %s\n", 154 strerror(errno)); 155 racoon_free(evtdump); 156 return; 157 } 158 159 if (src) 160 memcpy(&evtdump->src, src, sysdep_sa_len(src)); 161 if (dst) 162 memcpy(&evtdump->dst, dst, sysdep_sa_len(dst)); 163 evtdump->len = len; 164 evtdump->type = type; 165 time(&evtdump->timestamp); 166 167 if (optdata) 168 memcpy(evtdump + 1, optdata->v, optdata->l); 169 170 evt->dump = evtdump; 171 TAILQ_INSERT_TAIL(&evtlist, evt, next); 172 173 evtlist_len++; 174 175 return; 176} 177 178static struct evtdump * 179evt_pop(void) { 180 struct evtdump *evtdump; 181 struct evt *evt; 182 183 if ((evt = TAILQ_FIRST(&evtlist)) == NULL) 184 return NULL; 185 186 evtdump = evt->dump; 187 TAILQ_REMOVE(&evtlist, evt, next); 188 racoon_free(evt); 189 evtlist_len--; 190 191 return evtdump; 192} 193 194vchar_t * 195evt_dump(void) { 196 struct evtdump *evtdump; 197 vchar_t *buf = NULL; 198 199 if (!evtlist_inuse) { 200 evtlist_inuse = 1; 201 plog(LLV_ERROR, LOCATION, NULL, 202 "evt_dump: deprecated event polling used\n"); 203 } 204 205 if ((evtdump = evt_pop()) != NULL) { 206 if ((buf = vmalloc(evtdump->len)) == NULL) { 207 plog(LLV_ERROR, LOCATION, NULL, 208 "evt_dump failed: %s\n", strerror(errno)); 209 return NULL; 210 } 211 memcpy(buf->v, evtdump, evtdump->len); 212 racoon_free(evtdump); 213 } 214 215 return buf; 216} 217 218static struct evt_message * 219evtmsg_create(int type, vchar_t *optdata) 220{ 221 struct evt_message *e; 222 size_t len; 223 224 len = sizeof(struct evt_message); 225 if (optdata != NULL) 226 len += optdata->l; 227 228 if ((e = racoon_malloc(len)) == NULL) { 229 plog(LLV_ERROR, LOCATION, NULL, "Cannot allocate event: %s\n", 230 strerror(errno)); 231 return NULL; 232 } 233 234 memset(e, 0, sizeof(struct evt_message)); 235 e->adm.ac_len = len; 236 e->adm.ac_cmd = ADMIN_SHOW_EVT; 237 e->adm.ac_errno = 0; 238 e->adm.ac_proto = 0; 239 e->evt.ec_type = type; 240 time(&e->evt.ec_timestamp); 241 if (optdata != NULL) 242 memcpy(e + 1, optdata->v, optdata->l); 243 244 return e; 245} 246 247static void 248evt_unsubscribe(struct evt_listener *l) 249{ 250 plog(LLV_DEBUG, LOCATION, NULL, 251 "[%d] admin connection released\n", l->fd); 252 253 LIST_REMOVE(l, ll_chain); 254 unmonitor_fd(l->fd); 255 close(l->fd); 256 racoon_free(l); 257} 258 259static int 260evt_unsubscribe_cb(void *ctx, int fd) 261{ 262 evt_unsubscribe((struct evt_listener *) ctx); 263 return 0; 264} 265 266static void 267evtmsg_broadcast(const struct evt_listener_list *ll, struct evt_message *e) 268{ 269 struct evt_listener *l, *nl; 270 271 for (l = LIST_FIRST(ll); l != NULL; l = nl) { 272 nl = LIST_NEXT(l, ll_chain); 273 274 if (send(l->fd, e, e->adm.ac_len, MSG_DONTWAIT) < 0) { 275 plog(LLV_DEBUG, LOCATION, NULL, "Cannot send event to fd: %s\n", 276 strerror(errno)); 277 evt_unsubscribe(l); 278 } 279 } 280} 281 282void 283evt_generic(type, optdata) 284 int type; 285 vchar_t *optdata; 286{ 287 struct evt_message *e; 288 289 if ((e = evtmsg_create(type, optdata)) == NULL) 290 return; 291 292 evtmsg_broadcast(&evt_listeners, e); 293 evt_push(&e->evt.ec_ph1src, &e->evt.ec_ph1dst, type, optdata); 294 295 racoon_free(e); 296} 297 298void 299evt_phase1(ph1, type, optdata) 300 const struct ph1handle *ph1; 301 int type; 302 vchar_t *optdata; 303{ 304 struct evt_message *e; 305 306 if ((e = evtmsg_create(type, optdata)) == NULL) 307 return; 308 309 if (ph1->local) 310 memcpy(&e->evt.ec_ph1src, ph1->local, sysdep_sa_len(ph1->local)); 311 if (ph1->remote) 312 memcpy(&e->evt.ec_ph1dst, ph1->remote, sysdep_sa_len(ph1->remote)); 313 314 evtmsg_broadcast(&ph1->evt_listeners, e); 315 evtmsg_broadcast(&evt_listeners, e); 316 evt_push(&e->evt.ec_ph1src, &e->evt.ec_ph1dst, type, optdata); 317 318 racoon_free(e); 319} 320 321void 322evt_phase2(ph2, type, optdata) 323 const struct ph2handle *ph2; 324 int type; 325 vchar_t *optdata; 326{ 327 struct evt_message *e; 328 struct ph1handle *ph1 = ph2->ph1; 329 330 if ((e = evtmsg_create(type, optdata)) == NULL) 331 return; 332 333 if (ph1) { 334 if (ph1->local) 335 memcpy(&e->evt.ec_ph1src, ph1->local, sysdep_sa_len(ph1->local)); 336 if (ph1->remote) 337 memcpy(&e->evt.ec_ph1dst, ph1->remote, sysdep_sa_len(ph1->remote)); 338 } 339 e->evt.ec_ph2msgid = ph2->msgid; 340 341 evtmsg_broadcast(&ph2->evt_listeners, e); 342 if (ph1) 343 evtmsg_broadcast(&ph1->evt_listeners, e); 344 evtmsg_broadcast(&evt_listeners, e); 345 evt_push(&e->evt.ec_ph1src, &e->evt.ec_ph1dst, type, optdata); 346 347 racoon_free(e); 348} 349 350int 351evt_subscribe(list, fd) 352 struct evt_listener_list *list; 353 int fd; 354{ 355 struct evt_listener *l; 356 357 if ((l = racoon_malloc(sizeof(*l))) == NULL) { 358 plog(LLV_ERROR, LOCATION, NULL, 359 "Cannot allocate event listener: %s\n", 360 strerror(errno)); 361 return errno; 362 } 363 364 if (list == NULL) 365 list = &evt_listeners; 366 367 LIST_INSERT_HEAD(list, l, ll_chain); 368 l->fd = fd; 369 monitor_fd(l->fd, evt_unsubscribe_cb, l, 0); 370 371 plog(LLV_DEBUG, LOCATION, NULL, 372 "[%d] admin connection is polling events\n", fd); 373 374 return -2; 375} 376 377void 378evt_list_init(list) 379 struct evt_listener_list *list; 380{ 381 LIST_INIT(list); 382} 383 384void 385evt_list_cleanup(list) 386 struct evt_listener_list *list; 387{ 388 while (!LIST_EMPTY(list)) 389 evt_unsubscribe(LIST_FIRST(list)); 390} 391 392#endif /* ENABLE_ADMINPORT */ 393