evt.c revision 1.5.16.1
1/* $NetBSD: evt.c,v 1.5.16.1 2008/03/24 07:14:29 keiichi 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 "gcmalloc.h" 52#include "evt.h" 53 54#ifdef ENABLE_ADMINPORT 55 56static EVT_LISTENER_LIST(evt_listeners); 57static EVT_LISTENER_LIST(evt_fds); 58 59struct evt_message { 60 struct admin_com adm; 61 struct evt_async evt; 62}; 63 64struct evt { 65 struct evtdump *dump; 66 TAILQ_ENTRY(evt) next; 67}; 68 69TAILQ_HEAD(evtlist, evt); 70 71#define EVTLIST_MAX 32 72 73static struct evtlist evtlist = TAILQ_HEAD_INITIALIZER(evtlist); 74static int evtlist_len = 0; 75static int evtlist_inuse = 0; 76 77static struct { 78 int newtype, oldtype; 79} evttype_map[] = { 80 { EVT_RACOON_QUIT, EVTT_RACOON_QUIT }, 81 { EVT_PHASE1_UP, EVTT_PHASE1_UP }, 82 { EVT_PHASE1_DOWN, EVTT_PHASE1_DOWN }, 83 { EVT_PHASE1_NO_RESPONSE, EVTT_PEER_NO_RESPONSE }, 84 { EVT_PHASE1_NO_PROPOSAL, EVTT_PEERPH1_NOPROP }, 85 { EVT_PHASE1_AUTH_FAILED, EVTT_PEERPH1AUTH_FAILED }, 86 { EVT_PHASE1_DPD_TIMEOUT, EVTT_DPD_TIMEOUT }, 87 { EVT_PHASE1_PEER_DELETED, EVTT_PEER_DELETE }, 88 { EVT_PHASE1_MODE_CFG, EVTT_ISAKMP_CFG_DONE }, 89 { EVT_PHASE1_XAUTH_SUCCESS, EVTT_XAUTH_SUCCESS }, 90 { EVT_PHASE1_XAUTH_FAILED, EVTT_XAUTH_FAILED }, 91 { EVT_PHASE2_NO_PHASE1, -1 }, 92 { EVT_PHASE2_UP, EVTT_PHASE2_UP }, 93 { EVT_PHASE2_DOWN, EVTT_PHASE2_DOWN }, 94 { EVT_PHASE2_NO_RESPONSE, EVTT_PEER_NO_RESPONSE }, 95}; 96 97static void 98evt_push(src, dst, type, optdata) 99 struct sockaddr *src; 100 struct sockaddr *dst; 101 int type; 102 vchar_t *optdata; 103{ 104 struct evtdump *evtdump; 105 struct evt *evt; 106 size_t len; 107 int i; 108 109 /* If admin socket is disabled, silently discard anything */ 110 if (adminsock_path == NULL || !evtlist_inuse) 111 return; 112 113 /* Map the event type to old */ 114 for (i = 0; i < sizeof(evttype_map) / sizeof(evttype_map[0]); i++) 115 if (evttype_map[i].newtype == type) 116 break; 117 if (i >= sizeof(evttype_map) / sizeof(evttype_map[0])) 118 return; 119 120 type = evttype_map[i].oldtype; 121 if (type < 0) 122 return; 123 124 /* If we are above the limit, don't record anything */ 125 if (evtlist_len > EVTLIST_MAX) { 126 plog(LLV_DEBUG, LOCATION, NULL, 127 "Cannot record event: event queue overflowed\n"); 128 return; 129 } 130 131 /* If we hit the limit, record an overflow event instead */ 132 if (evtlist_len == EVTLIST_MAX) { 133 plog(LLV_ERROR, LOCATION, NULL, 134 "Cannot record event: event queue overflow\n"); 135 src = NULL; 136 dst = NULL; 137 type = EVTT_OVERFLOW; 138 optdata = NULL; 139 } 140 141 len = sizeof(*evtdump); 142 if (optdata) 143 len += optdata->l; 144 145 if ((evtdump = racoon_malloc(len)) == NULL) { 146 plog(LLV_ERROR, LOCATION, NULL, "Cannot record event: %s\n", 147 strerror(errno)); 148 return; 149 } 150 151 if ((evt = racoon_malloc(sizeof(*evt))) == NULL) { 152 plog(LLV_ERROR, LOCATION, NULL, "Cannot record event: %s\n", 153 strerror(errno)); 154 racoon_free(evtdump); 155 return; 156 } 157 158 if (src) 159 memcpy(&evtdump->src, src, sysdep_sa_len(src)); 160 if (dst) 161 memcpy(&evtdump->dst, dst, sysdep_sa_len(dst)); 162 evtdump->len = len; 163 evtdump->type = type; 164 time(&evtdump->timestamp); 165 166 if (optdata) 167 memcpy(evtdump + 1, optdata->v, optdata->l); 168 169 evt->dump = evtdump; 170 TAILQ_INSERT_TAIL(&evtlist, evt, next); 171 172 evtlist_len++; 173 174 return; 175} 176 177static struct evtdump * 178evt_pop(void) { 179 struct evtdump *evtdump; 180 struct evt *evt; 181 182 if ((evt = TAILQ_FIRST(&evtlist)) == NULL) 183 return NULL; 184 185 evtdump = evt->dump; 186 TAILQ_REMOVE(&evtlist, evt, next); 187 racoon_free(evt); 188 evtlist_len--; 189 190 return evtdump; 191} 192 193vchar_t * 194evt_dump(void) { 195 struct evtdump *evtdump; 196 vchar_t *buf = NULL; 197 198 if (!evtlist_inuse) { 199 evtlist_inuse = 1; 200 plog(LLV_ERROR, LOCATION, NULL, 201 "evt_dump: deprecated event polling used\n"); 202 } 203 204 if ((evtdump = evt_pop()) != NULL) { 205 if ((buf = vmalloc(evtdump->len)) == NULL) { 206 plog(LLV_ERROR, LOCATION, NULL, 207 "evt_dump failed: %s\n", strerror(errno)); 208 return NULL; 209 } 210 memcpy(buf->v, evtdump, evtdump->len); 211 racoon_free(evtdump); 212 } 213 214 return buf; 215} 216 217static struct evt_message * 218evtmsg_create(type, optdata) 219 int type; 220 vchar_t *optdata; 221{ 222 struct evt_message *e; 223 size_t len; 224 225 len = sizeof(struct evt_message); 226 if (optdata != NULL) 227 len += optdata->l; 228 229 if ((e = racoon_malloc(len)) == NULL) { 230 plog(LLV_ERROR, LOCATION, NULL, "Cannot allocate event: %s\n", 231 strerror(errno)); 232 return NULL; 233 } 234 235 memset(e, 0, sizeof(struct evt_message)); 236 e->adm.ac_len = len; 237 e->adm.ac_cmd = ADMIN_SHOW_EVT; 238 e->adm.ac_errno = 0; 239 e->adm.ac_proto = 0; 240 e->evt.ec_type = type; 241 time(&e->evt.ec_timestamp); 242 if (optdata != NULL) 243 memcpy(e + 1, optdata->v, optdata->l); 244 245 return e; 246} 247 248static void 249evt_unsubscribe(l) 250 struct evt_listener *l; 251{ 252 plog(LLV_DEBUG, LOCATION, NULL, 253 "[%d] admin connection released\n", l->fd); 254 255 LIST_REMOVE(l, ll_chain); 256 LIST_REMOVE(l, fd_chain); 257 close(l->fd); 258 racoon_free(l); 259} 260 261static void 262evtmsg_broadcast(ll, e) 263 const struct evt_listener_list *ll; 264 struct evt_message *e; 265{ 266 struct evt_listener *l, *nl; 267 268 for (l = LIST_FIRST(ll); l != NULL; l = nl) { 269 nl = LIST_NEXT(l, ll_chain); 270 271 if (send(l->fd, e, e->adm.ac_len, 272 MSG_NOSIGNAL | MSG_DONTWAIT) < 0) { 273 plog(LLV_DEBUG, LOCATION, NULL, "Cannot send event to fd: %s\n", 274 strerror(errno)); 275 evt_unsubscribe(l); 276 } 277 } 278} 279 280void 281evt_generic(type, optdata) 282 int type; 283 vchar_t *optdata; 284{ 285 struct evt_message *e; 286 287 if ((e = evtmsg_create(type, optdata)) == NULL) 288 return; 289 290 evtmsg_broadcast(&evt_listeners, e); 291 evt_push(&e->evt.ec_ph1src, &e->evt.ec_ph1dst, type, optdata); 292 293 racoon_free(e); 294} 295 296void 297evt_phase1(ph1, type, optdata) 298 const struct ph1handle *ph1; 299 int type; 300 vchar_t *optdata; 301{ 302 struct evt_message *e; 303 304 if ((e = evtmsg_create(type, optdata)) == NULL) 305 return; 306 307 if (ph1->local) 308 memcpy(&e->evt.ec_ph1src, ph1->local, sysdep_sa_len(ph1->local)); 309 if (ph1->remote) 310 memcpy(&e->evt.ec_ph1dst, ph1->remote, sysdep_sa_len(ph1->remote)); 311 312 evtmsg_broadcast(&ph1->evt_listeners, e); 313 evtmsg_broadcast(&evt_listeners, e); 314 evt_push(&e->evt.ec_ph1src, &e->evt.ec_ph1dst, type, optdata); 315 316 racoon_free(e); 317} 318 319void 320evt_phase2(ph2, type, optdata) 321 const struct ph2handle *ph2; 322 int type; 323 vchar_t *optdata; 324{ 325 struct evt_message *e; 326 struct ph1handle *ph1 = ph2->ph1; 327 328 if ((e = evtmsg_create(type, optdata)) == NULL) 329 return; 330 331 if (ph1) { 332 if (ph1->local) 333 memcpy(&e->evt.ec_ph1src, ph1->local, sysdep_sa_len(ph1->local)); 334 if (ph1->remote) 335 memcpy(&e->evt.ec_ph1dst, ph1->remote, sysdep_sa_len(ph1->remote)); 336 } 337 e->evt.ec_ph2msgid = ph2->msgid; 338 339 evtmsg_broadcast(&ph2->evt_listeners, e); 340 if (ph1) 341 evtmsg_broadcast(&ph1->evt_listeners, e); 342 evtmsg_broadcast(&evt_listeners, e); 343 evt_push(&e->evt.ec_ph1src, &e->evt.ec_ph1dst, type, optdata); 344 345 racoon_free(e); 346} 347 348int 349evt_subscribe(list, fd) 350 struct evt_listener_list *list; 351 int fd; 352{ 353 struct evt_listener *l; 354 355 if ((l = racoon_malloc(sizeof(*l))) == NULL) { 356 plog(LLV_ERROR, LOCATION, NULL, 357 "Cannot allocate event listener: %s\n", 358 strerror(errno)); 359 return errno; 360 } 361 362 if (list == NULL) 363 list = &evt_listeners; 364 365 LIST_INSERT_HEAD(list, l, ll_chain); 366 LIST_INSERT_HEAD(&evt_fds, l, fd_chain); 367 l->fd = fd; 368 369 plog(LLV_DEBUG, LOCATION, NULL, 370 "[%d] admin connection is polling events\n", fd); 371 372 return -2; 373} 374 375void 376evt_list_init(list) 377 struct evt_listener_list *list; 378{ 379 LIST_INIT(list); 380} 381 382void 383evt_list_cleanup(list) 384 struct evt_listener_list *list; 385{ 386 while (!LIST_EMPTY(list)) 387 evt_unsubscribe(LIST_FIRST(list)); 388} 389 390int 391evt_get_fdmask(nfds, fdset) 392 int nfds; 393 fd_set *fdset; 394{ 395 struct evt_listener *l; 396 397 LIST_FOREACH(l, &evt_fds, fd_chain) { 398 FD_SET(l->fd, fdset); 399 if (l->fd + 1 > nfds) 400 nfds = l->fd + 1; 401 } 402 403 return nfds; 404} 405 406void 407evt_handle_fdmask(fdset) 408 fd_set *fdset; 409{ 410 struct evt_listener *l, *nl; 411 412 for (l = LIST_FIRST(&evt_fds); l != NULL; l = nl) { 413 nl = LIST_NEXT(l, ll_chain); 414 415 if (FD_ISSET(l->fd, fdset)) 416 evt_unsubscribe(l); 417 } 418} 419 420 421#endif /* ENABLE_ADMINPORT */ 422