1*85a8c65fSreyk /* $OpenBSD: hce.c,v 1.58 2011/05/05 12:01:43 reyk Exp $ */ 2feb9ff76Sreyk 3feb9ff76Sreyk /* 436f5dc5eSpyr * Copyright (c) 2006 Pierre-Yves Ritschard <pyr@openbsd.org> 5feb9ff76Sreyk * 6feb9ff76Sreyk * Permission to use, copy, modify, and distribute this software for any 7feb9ff76Sreyk * purpose with or without fee is hereby granted, provided that the above 8feb9ff76Sreyk * copyright notice and this permission notice appear in all copies. 9feb9ff76Sreyk * 10feb9ff76Sreyk * THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES 11feb9ff76Sreyk * WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF 12feb9ff76Sreyk * MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR 13feb9ff76Sreyk * ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES 14feb9ff76Sreyk * WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN 15feb9ff76Sreyk * ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF 16feb9ff76Sreyk * OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE. 17feb9ff76Sreyk */ 18feb9ff76Sreyk 19feb9ff76Sreyk #include <sys/param.h> 200ca734d7Sreyk #include <sys/queue.h> 21feb9ff76Sreyk #include <sys/time.h> 22feb9ff76Sreyk #include <sys/stat.h> 23feb9ff76Sreyk #include <sys/socket.h> 24feb9ff76Sreyk #include <sys/un.h> 250ca734d7Sreyk 260ca734d7Sreyk #include <net/if.h> 27feb9ff76Sreyk #include <netinet/in_systm.h> 28feb9ff76Sreyk #include <netinet/in.h> 29feb9ff76Sreyk #include <netinet/ip.h> 300ca734d7Sreyk 31feb9ff76Sreyk #include <errno.h> 32feb9ff76Sreyk #include <event.h> 33feb9ff76Sreyk #include <fcntl.h> 34feb9ff76Sreyk #include <stdlib.h> 35feb9ff76Sreyk #include <string.h> 36feb9ff76Sreyk #include <unistd.h> 37feb9ff76Sreyk #include <err.h> 38feb9ff76Sreyk #include <pwd.h> 39feb9ff76Sreyk 40e8fb3979Spyr #include <openssl/ssl.h> 41e8fb3979Spyr 42748ceb64Sreyk #include "relayd.h" 43feb9ff76Sreyk 44c99a0f3cSblambert __dead void hce_shutdown(void); 45feb9ff76Sreyk void hce_sig_handler(int sig, short, void *); 46feb9ff76Sreyk void hce_dispatch_imsg(int, short, void *); 47feb9ff76Sreyk void hce_dispatch_parent(int, short, void *); 48feb9ff76Sreyk void hce_launch_checks(int, short, void *); 49641b8bafSpyr void hce_setup_events(void); 50641b8bafSpyr void hce_disable_events(void); 51feb9ff76Sreyk 52748ceb64Sreyk static struct relayd *env = NULL; 53f07d0e3bSpyr struct imsgev *iev_pfe; 54f07d0e3bSpyr struct imsgev *iev_main; 55780e8f79Spyr int running = 0; 56feb9ff76Sreyk 57feb9ff76Sreyk void 58feb9ff76Sreyk hce_sig_handler(int sig, short event, void *arg) 59feb9ff76Sreyk { 60feb9ff76Sreyk switch (sig) { 61feb9ff76Sreyk case SIGINT: 62feb9ff76Sreyk case SIGTERM: 63feb9ff76Sreyk hce_shutdown(); 64780e8f79Spyr break; 65c7867281Sreyk case SIGCHLD: 66c7867281Sreyk case SIGHUP: 67c7867281Sreyk case SIGPIPE: 68c7867281Sreyk /* ignore */ 69c7867281Sreyk break; 70feb9ff76Sreyk default: 71feb9ff76Sreyk fatalx("hce_sig_handler: unexpected signal"); 72feb9ff76Sreyk } 73feb9ff76Sreyk } 74feb9ff76Sreyk 75feb9ff76Sreyk pid_t 76748ceb64Sreyk hce(struct relayd *x_env, int pipe_parent2pfe[2], int pipe_parent2hce[2], 77053249cdSpyr int pipe_parent2relay[RELAY_MAXPROC][2], int pipe_pfe2hce[2], 782edd718bSreyk int pipe_pfe2relay[RELAY_MAXPROC][2]) 79feb9ff76Sreyk { 80feb9ff76Sreyk pid_t pid; 81feb9ff76Sreyk struct passwd *pw; 822edd718bSreyk int i; 83feb9ff76Sreyk 84feb9ff76Sreyk switch (pid = fork()) { 85feb9ff76Sreyk case -1: 86feb9ff76Sreyk fatal("hce: cannot fork"); 87feb9ff76Sreyk case 0: 88feb9ff76Sreyk break; 89feb9ff76Sreyk default: 90feb9ff76Sreyk return (pid); 91feb9ff76Sreyk } 92feb9ff76Sreyk 93feb9ff76Sreyk env = x_env; 949591a9f7Spyr purge_config(env, PURGE_RDRS|PURGE_RELAYS|PURGE_PROTOS); 95feb9ff76Sreyk 96748ceb64Sreyk if ((pw = getpwnam(RELAYD_USER)) == NULL) 97feb9ff76Sreyk fatal("hce: getpwnam"); 98feb9ff76Sreyk 99adf98c11Spyr #ifndef DEBUG 100feb9ff76Sreyk if (chroot(pw->pw_dir) == -1) 101feb9ff76Sreyk fatal("hce: chroot"); 102feb9ff76Sreyk if (chdir("/") == -1) 103feb9ff76Sreyk fatal("hce: chdir(\"/\")"); 104adf98c11Spyr #else 105adf98c11Spyr #warning disabling privilege revocation and chroot in DEBUG mode 106adf98c11Spyr #endif 107feb9ff76Sreyk 108feb9ff76Sreyk setproctitle("host check engine"); 109748ceb64Sreyk relayd_process = PROC_HCE; 110feb9ff76Sreyk 11101d85ec5Sreyk /* this is needed for icmp tests */ 11201d85ec5Sreyk icmp_init(env); 11301d85ec5Sreyk 114adf98c11Spyr #ifndef DEBUG 115feb9ff76Sreyk if (setgroups(1, &pw->pw_gid) || 116feb9ff76Sreyk setresgid(pw->pw_gid, pw->pw_gid, pw->pw_gid) || 117feb9ff76Sreyk setresuid(pw->pw_uid, pw->pw_uid, pw->pw_uid)) 118feb9ff76Sreyk fatal("hce: can't drop privileges"); 119adf98c11Spyr #endif 120feb9ff76Sreyk 121641b8bafSpyr event_init(); 122feb9ff76Sreyk 123bb8fa3feSreyk /* Allow maximum available sockets for TCP checks */ 124bb8fa3feSreyk socket_rlimit(-1); 125bb8fa3feSreyk 126f07d0e3bSpyr if ((iev_pfe = calloc(1, sizeof(struct imsgev))) == NULL || 127f07d0e3bSpyr (iev_main = calloc(1, sizeof(struct imsgev))) == NULL) 128641b8bafSpyr fatal("hce"); 129f07d0e3bSpyr imsg_init(&iev_pfe->ibuf, pipe_pfe2hce[0]); 130f07d0e3bSpyr iev_pfe->handler = hce_dispatch_imsg; 131f07d0e3bSpyr imsg_init(&iev_main->ibuf, pipe_parent2hce[1]); 132f07d0e3bSpyr iev_main->handler = hce_dispatch_parent; 133641b8bafSpyr 134f07d0e3bSpyr iev_pfe->events = EV_READ; 135f07d0e3bSpyr event_set(&iev_pfe->ev, iev_pfe->ibuf.fd, iev_pfe->events, 136f07d0e3bSpyr iev_pfe->handler, iev_pfe); 137f07d0e3bSpyr event_add(&iev_pfe->ev, NULL); 138641b8bafSpyr 139f07d0e3bSpyr iev_main->events = EV_READ; 140f07d0e3bSpyr event_set(&iev_main->ev, iev_main->ibuf.fd, iev_main->events, 141f07d0e3bSpyr iev_main->handler, iev_main); 142f07d0e3bSpyr event_add(&iev_main->ev, NULL); 143641b8bafSpyr 144c7867281Sreyk signal_set(&env->sc_evsigint, SIGINT, hce_sig_handler, env); 145c7867281Sreyk signal_set(&env->sc_evsigterm, SIGTERM, hce_sig_handler, env); 146c7867281Sreyk signal_set(&env->sc_evsigchld, SIGCHLD, hce_sig_handler, env); 147c7867281Sreyk signal_set(&env->sc_evsighup, SIGHUP, hce_sig_handler, env); 148c7867281Sreyk signal_set(&env->sc_evsigpipe, SIGPIPE, hce_sig_handler, env); 149c7867281Sreyk 150c7867281Sreyk signal_add(&env->sc_evsigint, NULL); 151c7867281Sreyk signal_add(&env->sc_evsigterm, NULL); 152c7867281Sreyk signal_add(&env->sc_evsigchld, NULL); 153c7867281Sreyk signal_add(&env->sc_evsighup, NULL); 154c7867281Sreyk signal_add(&env->sc_evsigpipe, NULL); 155feb9ff76Sreyk 156feb9ff76Sreyk /* setup pipes */ 157feb9ff76Sreyk close(pipe_pfe2hce[1]); 158feb9ff76Sreyk close(pipe_parent2hce[0]); 159feb9ff76Sreyk close(pipe_parent2pfe[0]); 160feb9ff76Sreyk close(pipe_parent2pfe[1]); 16135d10c30Sreyk for (i = 0; i < env->sc_prefork_relay; i++) { 162053249cdSpyr close(pipe_parent2relay[i][0]); 163053249cdSpyr close(pipe_parent2relay[i][1]); 1642edd718bSreyk close(pipe_pfe2relay[i][0]); 1652edd718bSreyk close(pipe_pfe2relay[i][1]); 1662edd718bSreyk } 167feb9ff76Sreyk 168641b8bafSpyr hce_setup_events(); 169641b8bafSpyr event_dispatch(); 170780e8f79Spyr hce_shutdown(); 171780e8f79Spyr 172780e8f79Spyr return (0); 173780e8f79Spyr } 174780e8f79Spyr 175780e8f79Spyr void 176641b8bafSpyr hce_setup_events(void) 177780e8f79Spyr { 178780e8f79Spyr struct timeval tv; 179780e8f79Spyr struct table *table; 180780e8f79Spyr 181f07d0e3bSpyr snmp_init(env, iev_main); 182fe250497Sreyk 18335d10c30Sreyk if (!TAILQ_EMPTY(env->sc_tables)) { 18435d10c30Sreyk evtimer_set(&env->sc_ev, hce_launch_checks, env); 18501d85ec5Sreyk bzero(&tv, sizeof(tv)); 18635d10c30Sreyk evtimer_add(&env->sc_ev, &tv); 1872edd718bSreyk } 188feb9ff76Sreyk 18935d10c30Sreyk if (env->sc_flags & F_SSL) { 190e8fb3979Spyr ssl_init(env); 19135d10c30Sreyk TAILQ_FOREACH(table, env->sc_tables, entry) { 19268b79041Spyr if (!(table->conf.flags & F_SSL)) 193e8fb3979Spyr continue; 194e8fb3979Spyr table->ssl_ctx = ssl_ctx_create(env); 195e8fb3979Spyr } 196e8fb3979Spyr } 197641b8bafSpyr } 198641b8bafSpyr 199641b8bafSpyr void 200641b8bafSpyr hce_disable_events(void) 201641b8bafSpyr { 202641b8bafSpyr struct table *table; 203641b8bafSpyr struct host *host; 204641b8bafSpyr 20535d10c30Sreyk evtimer_del(&env->sc_ev); 20635d10c30Sreyk TAILQ_FOREACH(table, env->sc_tables, entry) { 207641b8bafSpyr TAILQ_FOREACH(host, &table->hosts, entry) { 208c0dc99f6Sreyk host->he = HCE_ABORT; 209641b8bafSpyr event_del(&host->cte.ev); 210641b8bafSpyr close(host->cte.s); 211641b8bafSpyr } 212641b8bafSpyr } 21335d10c30Sreyk if (env->sc_has_icmp) { 21435d10c30Sreyk event_del(&env->sc_icmp_send.ev); 21535d10c30Sreyk event_del(&env->sc_icmp_recv.ev); 216641b8bafSpyr } 21735d10c30Sreyk if (env->sc_has_icmp6) { 21835d10c30Sreyk event_del(&env->sc_icmp6_send.ev); 21935d10c30Sreyk event_del(&env->sc_icmp6_recv.ev); 220641b8bafSpyr } 221feb9ff76Sreyk } 222feb9ff76Sreyk 223feb9ff76Sreyk void 224feb9ff76Sreyk hce_launch_checks(int fd, short event, void *arg) 225feb9ff76Sreyk { 226feb9ff76Sreyk struct host *host; 227feb9ff76Sreyk struct table *table; 22801d85ec5Sreyk struct timeval tv; 22901d85ec5Sreyk 23001d85ec5Sreyk /* 23101d85ec5Sreyk * notify pfe checks are done and schedule next check 23201d85ec5Sreyk */ 233f07d0e3bSpyr imsg_compose_event(iev_pfe, IMSG_SYNC, 0, 0, -1, NULL, 0); 23435d10c30Sreyk TAILQ_FOREACH(table, env->sc_tables, entry) { 23501d85ec5Sreyk TAILQ_FOREACH(host, &table->hosts, entry) { 236c0dc99f6Sreyk if ((host->flags & F_CHECK_DONE) == 0) 237c0dc99f6Sreyk host->he = HCE_INTERVAL_TIMEOUT; 23801d85ec5Sreyk host->flags &= ~(F_CHECK_SENT|F_CHECK_DONE); 23901d85ec5Sreyk event_del(&host->cte.ev); 24001d85ec5Sreyk } 24101d85ec5Sreyk } 24201d85ec5Sreyk 2436a899317Sthib if (gettimeofday(&tv, NULL) == -1) 24401d85ec5Sreyk fatal("hce_launch_checks: gettimeofday"); 245feb9ff76Sreyk 24635d10c30Sreyk TAILQ_FOREACH(table, env->sc_tables, entry) { 24768b79041Spyr if (table->conf.flags & F_DISABLE) 2487e351ffdSreyk continue; 24918de159aSpyr if (table->conf.skip_cnt) { 25018de159aSpyr if (table->skipped++ > table->conf.skip_cnt) 25118de159aSpyr table->skipped = 0; 25218de159aSpyr if (table->skipped != 1) 25318de159aSpyr continue; 25418de159aSpyr } 25568b79041Spyr if (table->conf.check == CHECK_NOCHECK) 2567e351ffdSreyk fatalx("hce_launch_checks: unknown check type"); 25701d85ec5Sreyk 2587e351ffdSreyk TAILQ_FOREACH(host, &table->hosts, entry) { 259c723f8edSreyk if (host->flags & F_DISABLE || host->conf.parentid) 2607e351ffdSreyk continue; 261a7da800aSsthen bcopy(&tv, &host->cte.tv_start, 262a7da800aSsthen sizeof(host->cte.tv_start)); 2634156152fSreyk switch (table->conf.check) { 2644156152fSreyk case CHECK_ICMP: 26501d85ec5Sreyk schedule_icmp(env, host); 2664156152fSreyk break; 2674156152fSreyk case CHECK_SCRIPT: 2684156152fSreyk check_script(host); 2694156152fSreyk break; 2704156152fSreyk default: 27101d85ec5Sreyk /* Any other TCP-style checks */ 2727e351ffdSreyk host->last_up = host->up; 2737e351ffdSreyk host->cte.host = host; 2747e351ffdSreyk host->cte.table = table; 2757e351ffdSreyk check_tcp(&host->cte); 2764156152fSreyk break; 2774156152fSreyk } 2787e351ffdSreyk } 2797e351ffdSreyk } 28001d85ec5Sreyk check_icmp(env, &tv); 28101d85ec5Sreyk 28235d10c30Sreyk bcopy(&env->sc_interval, &tv, sizeof(tv)); 28335d10c30Sreyk evtimer_add(&env->sc_ev, &tv); 2847e351ffdSreyk } 2857e351ffdSreyk 2867e351ffdSreyk void 287c0dc99f6Sreyk hce_notify_done(struct host *host, enum host_error he) 2887e351ffdSreyk { 289609cf3a7Sreyk struct table *table; 2907e351ffdSreyk struct ctl_status st; 291609cf3a7Sreyk struct timeval tv_now, tv_dur; 292609cf3a7Sreyk u_long duration; 293609cf3a7Sreyk u_int logopt; 294c723f8edSreyk struct host *h; 295c723f8edSreyk int hostup; 296c0dc99f6Sreyk const char *msg; 297c723f8edSreyk 298c723f8edSreyk hostup = host->up; 299c0dc99f6Sreyk host->he = he; 3007e351ffdSreyk 3012edd718bSreyk if (host->up == HOST_DOWN && host->retry_cnt) { 302*85a8c65fSreyk log_debug("%s: host %s retry %d", __func__, 30368b79041Spyr host->conf.name, host->retry_cnt); 304bd2508bcSreyk host->up = host->last_up; 3052edd718bSreyk host->retry_cnt--; 3062edd718bSreyk } else 30768b79041Spyr host->retry_cnt = host->conf.retry; 3082edd718bSreyk if (host->up != HOST_UNKNOWN) { 3092edd718bSreyk host->check_cnt++; 3102edd718bSreyk if (host->up == HOST_UP) 3112edd718bSreyk host->up_cnt++; 3122edd718bSreyk } 31368b79041Spyr st.id = host->conf.id; 314feb9ff76Sreyk st.up = host->up; 3152edd718bSreyk st.check_cnt = host->check_cnt; 3162edd718bSreyk st.retry_cnt = host->retry_cnt; 317c0dc99f6Sreyk st.he = he; 31801d85ec5Sreyk host->flags |= (F_CHECK_SENT|F_CHECK_DONE); 319c0dc99f6Sreyk msg = host_error(he); 3207e351ffdSreyk if (msg) 321*85a8c65fSreyk log_debug("%s: %s (%s)", __func__, host->conf.name, msg); 322609cf3a7Sreyk 323f07d0e3bSpyr imsg_compose_event(iev_pfe, IMSG_HOST_STATUS, 324069bf5e4Spyr 0, 0, -1, &st, sizeof(st)); 3252edd718bSreyk if (host->up != host->last_up) 326748ceb64Sreyk logopt = RELAYD_OPT_LOGUPDATE; 3272edd718bSreyk else 328748ceb64Sreyk logopt = RELAYD_OPT_LOGNOTIFY; 329609cf3a7Sreyk 3306a899317Sthib if (gettimeofday(&tv_now, NULL) == -1) 331609cf3a7Sreyk fatal("hce_notify_done: gettimeofday"); 332609cf3a7Sreyk timersub(&tv_now, &host->cte.tv_start, &tv_dur); 333609cf3a7Sreyk if (timercmp(&host->cte.tv_start, &tv_dur, >)) 334609cf3a7Sreyk duration = (tv_dur.tv_sec * 1000) + (tv_dur.tv_usec / 1000.0); 335609cf3a7Sreyk else 336609cf3a7Sreyk duration = 0; 337609cf3a7Sreyk 33868b79041Spyr if ((table = table_find(env, host->conf.tableid)) == NULL) 3392edd718bSreyk fatalx("hce_notify_done: invalid table id"); 3402edd718bSreyk 34135d10c30Sreyk if (env->sc_opts & logopt) { 3422edd718bSreyk log_info("host %s, check %s%s (%lums), state %s -> %s, " 3432edd718bSreyk "availability %s", 34468b79041Spyr host->conf.name, table_check(table->conf.check), 34568b79041Spyr (table->conf.flags & F_SSL) ? " use ssl" : "", duration, 3462edd718bSreyk host_status(host->last_up), host_status(host->up), 3472edd718bSreyk print_availability(host->check_cnt, host->up_cnt)); 348feb9ff76Sreyk } 349fe250497Sreyk 350fe250497Sreyk if (host->last_up != host->up) 351fe250497Sreyk snmp_hosttrap(table, host); 352fe250497Sreyk 353609cf3a7Sreyk host->last_up = host->up; 354c723f8edSreyk 3551584e35dSreyk if (SLIST_EMPTY(&host->children)) 356c723f8edSreyk return; 357c723f8edSreyk 358c723f8edSreyk /* Notify for all other hosts that inherit the state from this one */ 3591584e35dSreyk SLIST_FOREACH(h, &host->children, child) { 360c723f8edSreyk h->up = hostup; 361c0dc99f6Sreyk hce_notify_done(h, he); 362c723f8edSreyk } 363feb9ff76Sreyk } 364feb9ff76Sreyk 365feb9ff76Sreyk void 366feb9ff76Sreyk hce_shutdown(void) 367feb9ff76Sreyk { 368feb9ff76Sreyk log_info("host check engine exiting"); 369feb9ff76Sreyk _exit(0); 370feb9ff76Sreyk } 371feb9ff76Sreyk 372feb9ff76Sreyk void 373feb9ff76Sreyk hce_dispatch_imsg(int fd, short event, void *ptr) 374feb9ff76Sreyk { 375f07d0e3bSpyr struct imsgev *iev; 376feb9ff76Sreyk struct imsgbuf *ibuf; 377feb9ff76Sreyk struct imsg imsg; 378feb9ff76Sreyk ssize_t n; 379feb9ff76Sreyk objid_t id; 380feb9ff76Sreyk struct host *host; 381feb9ff76Sreyk struct table *table; 382f579a0f7Sjsg int verbose; 383feb9ff76Sreyk 384f07d0e3bSpyr iev = ptr; 385f07d0e3bSpyr ibuf = &iev->ibuf; 3862668107aSreyk 3872668107aSreyk if (event & EV_READ) { 388feb9ff76Sreyk if ((n = imsg_read(ibuf)) == -1) 389feb9ff76Sreyk fatal("hce_dispatch_imsg: imsg_read_error"); 390ddfd9103Spyr if (n == 0) { 391ddfd9103Spyr /* this pipe is dead, so remove the event handler */ 392f07d0e3bSpyr event_del(&iev->ev); 393ddfd9103Spyr event_loopexit(NULL); 394ddfd9103Spyr return; 395ddfd9103Spyr } 3962668107aSreyk } 3972668107aSreyk 3982668107aSreyk if (event & EV_WRITE) { 399feb9ff76Sreyk if (msgbuf_write(&ibuf->w) == -1) 400feb9ff76Sreyk fatal("hce_dispatch_imsg: msgbuf_write"); 401feb9ff76Sreyk } 402feb9ff76Sreyk 403feb9ff76Sreyk for (;;) { 404feb9ff76Sreyk if ((n = imsg_get(ibuf, &imsg)) == -1) 405feb9ff76Sreyk fatal("hce_dispatch_imsg: imsg_read error"); 406feb9ff76Sreyk if (n == 0) 407feb9ff76Sreyk break; 408feb9ff76Sreyk 409feb9ff76Sreyk switch (imsg.hdr.type) { 410feb9ff76Sreyk case IMSG_HOST_DISABLE: 411feb9ff76Sreyk memcpy(&id, imsg.data, sizeof(id)); 412feb9ff76Sreyk if ((host = host_find(env, id)) == NULL) 413feb9ff76Sreyk fatalx("hce_dispatch_imsg: desynchronized"); 414feb9ff76Sreyk host->flags |= F_DISABLE; 415feb9ff76Sreyk host->up = HOST_UNKNOWN; 4162edd718bSreyk host->check_cnt = 0; 4172edd718bSreyk host->up_cnt = 0; 418c0dc99f6Sreyk host->he = HCE_NONE; 419feb9ff76Sreyk break; 420feb9ff76Sreyk case IMSG_HOST_ENABLE: 421feb9ff76Sreyk memcpy(&id, imsg.data, sizeof(id)); 422feb9ff76Sreyk if ((host = host_find(env, id)) == NULL) 423feb9ff76Sreyk fatalx("hce_dispatch_imsg: desynchronized"); 424feb9ff76Sreyk host->flags &= ~(F_DISABLE); 425feb9ff76Sreyk host->up = HOST_UNKNOWN; 426c0dc99f6Sreyk host->he = HCE_NONE; 427feb9ff76Sreyk break; 428feb9ff76Sreyk case IMSG_TABLE_DISABLE: 429feb9ff76Sreyk memcpy(&id, imsg.data, sizeof(id)); 430feb9ff76Sreyk if ((table = table_find(env, id)) == NULL) 431feb9ff76Sreyk fatalx("hce_dispatch_imsg: desynchronized"); 43268b79041Spyr table->conf.flags |= F_DISABLE; 433feb9ff76Sreyk TAILQ_FOREACH(host, &table->hosts, entry) 434feb9ff76Sreyk host->up = HOST_UNKNOWN; 435feb9ff76Sreyk break; 436feb9ff76Sreyk case IMSG_TABLE_ENABLE: 437feb9ff76Sreyk memcpy(&id, imsg.data, sizeof(id)); 438feb9ff76Sreyk if ((table = table_find(env, id)) == NULL) 439feb9ff76Sreyk fatalx("hce_dispatch_imsg: desynchronized"); 44068b79041Spyr table->conf.flags &= ~(F_DISABLE); 441feb9ff76Sreyk TAILQ_FOREACH(host, &table->hosts, entry) 442feb9ff76Sreyk host->up = HOST_UNKNOWN; 443feb9ff76Sreyk break; 444cd65ce7bSpyr case IMSG_CTL_POLL: 44535d10c30Sreyk evtimer_del(&env->sc_ev); 44635d10c30Sreyk TAILQ_FOREACH(table, env->sc_tables, entry) 447f98352d8Spyr table->skipped = 0; 448cd65ce7bSpyr hce_launch_checks(-1, EV_TIMEOUT, env); 449cd65ce7bSpyr break; 450f579a0f7Sjsg case IMSG_CTL_LOG_VERBOSE: 451f579a0f7Sjsg memcpy(&verbose, imsg.data, sizeof(verbose)); 452f579a0f7Sjsg log_verbose(verbose); 453f579a0f7Sjsg break; 454feb9ff76Sreyk default: 455*85a8c65fSreyk log_debug("%s: unexpected imsg %d", __func__, 456feb9ff76Sreyk imsg.hdr.type); 457feb9ff76Sreyk break; 458feb9ff76Sreyk } 459feb9ff76Sreyk imsg_free(&imsg); 460feb9ff76Sreyk } 461f07d0e3bSpyr imsg_event_add(iev); 462feb9ff76Sreyk } 463feb9ff76Sreyk 464feb9ff76Sreyk void 465feb9ff76Sreyk hce_dispatch_parent(int fd, short event, void * ptr) 466feb9ff76Sreyk { 467f07d0e3bSpyr struct imsgev *iev; 468feb9ff76Sreyk struct imsgbuf *ibuf; 469feb9ff76Sreyk struct imsg imsg; 4704156152fSreyk struct ctl_script scr; 471feb9ff76Sreyk ssize_t n; 472adf98c11Spyr size_t len; 473adf98c11Spyr static struct table *table = NULL; 474212c0cdeSreyk struct host *host, *parent; 475feb9ff76Sreyk 476f07d0e3bSpyr iev = ptr; 477f07d0e3bSpyr ibuf = &iev->ibuf; 4782668107aSreyk 4792668107aSreyk if (event & EV_READ) { 480feb9ff76Sreyk if ((n = imsg_read(ibuf)) == -1) 481feb9ff76Sreyk fatal("hce_dispatch_parent: imsg_read error"); 482ddfd9103Spyr if (n == 0) { 483ddfd9103Spyr /* this pipe is dead, so remove the event handler */ 484f07d0e3bSpyr event_del(&iev->ev); 485ddfd9103Spyr event_loopexit(NULL); 486ddfd9103Spyr return; 487ddfd9103Spyr } 4882668107aSreyk } 4892668107aSreyk 4902668107aSreyk if (event & EV_WRITE) { 491feb9ff76Sreyk if (msgbuf_write(&ibuf->w) == -1) 492feb9ff76Sreyk fatal("hce_dispatch_parent: msgbuf_write"); 493feb9ff76Sreyk } 494feb9ff76Sreyk 495feb9ff76Sreyk for (;;) { 496feb9ff76Sreyk if ((n = imsg_get(ibuf, &imsg)) == -1) 497feb9ff76Sreyk fatal("hce_dispatch_parent: imsg_read error"); 498feb9ff76Sreyk if (n == 0) 499feb9ff76Sreyk break; 500feb9ff76Sreyk 501feb9ff76Sreyk switch (imsg.hdr.type) { 5024156152fSreyk case IMSG_SCRIPT: 5034156152fSreyk if (imsg.hdr.len - IMSG_HEADER_SIZE != 5044156152fSreyk sizeof(scr)) 5054156152fSreyk fatalx("hce_dispatch_parent: " 5064156152fSreyk "invalid size of script request"); 5074156152fSreyk bcopy(imsg.data, &scr, sizeof(scr)); 5084156152fSreyk script_done(env, &scr); 5094156152fSreyk break; 510adf98c11Spyr case IMSG_RECONF: 511*85a8c65fSreyk log_debug("%s: reloading configuration", __func__); 512adf98c11Spyr if (imsg.hdr.len != 513748ceb64Sreyk sizeof(struct relayd) + IMSG_HEADER_SIZE) 514adf98c11Spyr fatalx("corrupted reload data"); 515adf98c11Spyr hce_disable_events(); 516adf98c11Spyr purge_config(env, PURGE_TABLES); 517748ceb64Sreyk merge_config(env, (struct relayd *)imsg.data); 518adf98c11Spyr 51935d10c30Sreyk env->sc_tables = calloc(1, sizeof(*env->sc_tables)); 52035d10c30Sreyk if (env->sc_tables == NULL) 521adf98c11Spyr fatal(NULL); 522adf98c11Spyr 52335d10c30Sreyk TAILQ_INIT(env->sc_tables); 524adf98c11Spyr break; 525adf98c11Spyr case IMSG_RECONF_TABLE: 526adf98c11Spyr if ((table = calloc(1, sizeof(*table))) == NULL) 527adf98c11Spyr fatal(NULL); 528adf98c11Spyr memcpy(&table->conf, imsg.data, sizeof(table->conf)); 529adf98c11Spyr TAILQ_INIT(&table->hosts); 53035d10c30Sreyk TAILQ_INSERT_TAIL(env->sc_tables, table, entry); 531adf98c11Spyr break; 532adf98c11Spyr case IMSG_RECONF_SENDBUF: 533adf98c11Spyr len = imsg.hdr.len - IMSG_HEADER_SIZE; 534adf98c11Spyr table->sendbuf = calloc(1, len); 535adf98c11Spyr (void)strlcpy(table->sendbuf, (char *)imsg.data, len); 536adf98c11Spyr break; 537adf98c11Spyr case IMSG_RECONF_HOST: 538adf98c11Spyr if ((host = calloc(1, sizeof(*host))) == NULL) 539adf98c11Spyr fatal(NULL); 540adf98c11Spyr memcpy(&host->conf, imsg.data, sizeof(host->conf)); 541adf98c11Spyr host->tablename = table->conf.name; 542adf98c11Spyr TAILQ_INSERT_TAIL(&table->hosts, host, entry); 543212c0cdeSreyk if (host->conf.parentid) { 544212c0cdeSreyk parent = host_find(env, host->conf.parentid); 545212c0cdeSreyk SLIST_INSERT_HEAD(&parent->children, 546212c0cdeSreyk host, child); 547212c0cdeSreyk } 548adf98c11Spyr break; 549adf98c11Spyr case IMSG_RECONF_END: 550*85a8c65fSreyk log_warnx("%s: configuration reloaded", __func__); 551adf98c11Spyr hce_setup_events(); 552adf98c11Spyr break; 553feb9ff76Sreyk default: 554*85a8c65fSreyk log_debug("%s: unexpected imsg %d", __func__, 555feb9ff76Sreyk imsg.hdr.type); 556feb9ff76Sreyk break; 557feb9ff76Sreyk } 558feb9ff76Sreyk imsg_free(&imsg); 559feb9ff76Sreyk } 560f07d0e3bSpyr imsg_event_add(iev); 561feb9ff76Sreyk } 562