xref: /openbsd/usr.sbin/relayd/hce.c (revision c0dc99f6)
1*c0dc99f6Sreyk /*	$OpenBSD: hce.c,v 1.46 2008/12/05 16:37:55 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;
53feb9ff76Sreyk struct imsgbuf		*ibuf_pfe;
54feb9ff76Sreyk struct imsgbuf		*ibuf_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;
65feb9ff76Sreyk 	default:
66feb9ff76Sreyk 		fatalx("hce_sig_handler: unexpected signal");
67feb9ff76Sreyk 	}
68feb9ff76Sreyk }
69feb9ff76Sreyk 
70feb9ff76Sreyk pid_t
71748ceb64Sreyk hce(struct relayd *x_env, int pipe_parent2pfe[2], int pipe_parent2hce[2],
72053249cdSpyr     int pipe_parent2relay[RELAY_MAXPROC][2], int pipe_pfe2hce[2],
732edd718bSreyk     int pipe_pfe2relay[RELAY_MAXPROC][2])
74feb9ff76Sreyk {
75feb9ff76Sreyk 	pid_t		 pid;
76feb9ff76Sreyk 	struct passwd	*pw;
772edd718bSreyk 	int		 i;
78641b8bafSpyr 	struct event	 ev_sigint;
79641b8bafSpyr 	struct event	 ev_sigterm;
80feb9ff76Sreyk 
81feb9ff76Sreyk 	switch (pid = fork()) {
82feb9ff76Sreyk 	case -1:
83feb9ff76Sreyk 		fatal("hce: cannot fork");
84feb9ff76Sreyk 	case 0:
85feb9ff76Sreyk 		break;
86feb9ff76Sreyk 	default:
87feb9ff76Sreyk 		return (pid);
88feb9ff76Sreyk 	}
89feb9ff76Sreyk 
90feb9ff76Sreyk 	env = x_env;
919591a9f7Spyr 	purge_config(env, PURGE_RDRS|PURGE_RELAYS|PURGE_PROTOS);
92feb9ff76Sreyk 
93748ceb64Sreyk 	if ((pw = getpwnam(RELAYD_USER)) == NULL)
94feb9ff76Sreyk 		fatal("hce: getpwnam");
95feb9ff76Sreyk 
96adf98c11Spyr #ifndef DEBUG
97feb9ff76Sreyk 	if (chroot(pw->pw_dir) == -1)
98feb9ff76Sreyk 		fatal("hce: chroot");
99feb9ff76Sreyk 	if (chdir("/") == -1)
100feb9ff76Sreyk 		fatal("hce: chdir(\"/\")");
101adf98c11Spyr #else
102adf98c11Spyr #warning disabling privilege revocation and chroot in DEBUG mode
103adf98c11Spyr #endif
104feb9ff76Sreyk 
105feb9ff76Sreyk 	setproctitle("host check engine");
106748ceb64Sreyk 	relayd_process = PROC_HCE;
107feb9ff76Sreyk 
10801d85ec5Sreyk 	/* this is needed for icmp tests */
10901d85ec5Sreyk 	icmp_init(env);
11001d85ec5Sreyk 
111adf98c11Spyr #ifndef DEBUG
112feb9ff76Sreyk 	if (setgroups(1, &pw->pw_gid) ||
113feb9ff76Sreyk 	    setresgid(pw->pw_gid, pw->pw_gid, pw->pw_gid) ||
114feb9ff76Sreyk 	    setresuid(pw->pw_uid, pw->pw_uid, pw->pw_uid))
115feb9ff76Sreyk 		fatal("hce: can't drop privileges");
116adf98c11Spyr #endif
117feb9ff76Sreyk 
118641b8bafSpyr 	event_init();
119feb9ff76Sreyk 
120641b8bafSpyr 	if ((ibuf_pfe = calloc(1, sizeof(struct imsgbuf))) == NULL ||
121641b8bafSpyr 	    (ibuf_main = calloc(1, sizeof(struct imsgbuf))) == NULL)
122641b8bafSpyr 		fatal("hce");
123641b8bafSpyr 	imsg_init(ibuf_pfe, pipe_pfe2hce[0], hce_dispatch_imsg);
124641b8bafSpyr 	imsg_init(ibuf_main, pipe_parent2hce[1], hce_dispatch_parent);
125641b8bafSpyr 
126641b8bafSpyr 	ibuf_pfe->events = EV_READ;
127641b8bafSpyr 	event_set(&ibuf_pfe->ev, ibuf_pfe->fd, ibuf_pfe->events,
128641b8bafSpyr 	    ibuf_pfe->handler, ibuf_pfe);
129641b8bafSpyr 	event_add(&ibuf_pfe->ev, NULL);
130641b8bafSpyr 
131641b8bafSpyr 	ibuf_main->events = EV_READ;
132641b8bafSpyr 	event_set(&ibuf_main->ev, ibuf_main->fd, ibuf_main->events,
133641b8bafSpyr 	    ibuf_main->handler, ibuf_main);
134641b8bafSpyr 	event_add(&ibuf_main->ev, NULL);
135641b8bafSpyr 
136641b8bafSpyr 	signal_set(&ev_sigint, SIGINT, hce_sig_handler, NULL);
137641b8bafSpyr 	signal_set(&ev_sigterm, SIGTERM, hce_sig_handler, NULL);
138641b8bafSpyr 	signal_add(&ev_sigint, NULL);
139641b8bafSpyr 	signal_add(&ev_sigterm, NULL);
140641b8bafSpyr 	signal(SIGPIPE, SIG_IGN);
141fda2844dSpyr 	signal(SIGHUP, SIG_IGN);
142feb9ff76Sreyk 
143feb9ff76Sreyk 	/* setup pipes */
144feb9ff76Sreyk 	close(pipe_pfe2hce[1]);
145feb9ff76Sreyk 	close(pipe_parent2hce[0]);
146feb9ff76Sreyk 	close(pipe_parent2pfe[0]);
147feb9ff76Sreyk 	close(pipe_parent2pfe[1]);
14835d10c30Sreyk 	for (i = 0; i < env->sc_prefork_relay; i++) {
149053249cdSpyr 		close(pipe_parent2relay[i][0]);
150053249cdSpyr 		close(pipe_parent2relay[i][1]);
1512edd718bSreyk 		close(pipe_pfe2relay[i][0]);
1522edd718bSreyk 		close(pipe_pfe2relay[i][1]);
1532edd718bSreyk 	}
154feb9ff76Sreyk 
155641b8bafSpyr 	hce_setup_events();
156641b8bafSpyr 	event_dispatch();
157780e8f79Spyr 	hce_shutdown();
158780e8f79Spyr 
159780e8f79Spyr 	return (0);
160780e8f79Spyr }
161780e8f79Spyr 
162780e8f79Spyr void
163641b8bafSpyr hce_setup_events(void)
164780e8f79Spyr {
165780e8f79Spyr 	struct timeval	 tv;
166780e8f79Spyr 	struct table	*table;
167780e8f79Spyr 
168fe250497Sreyk 	snmp_init(env, ibuf_main);
169fe250497Sreyk 
17035d10c30Sreyk 	if (!TAILQ_EMPTY(env->sc_tables)) {
17135d10c30Sreyk 		evtimer_set(&env->sc_ev, hce_launch_checks, env);
17201d85ec5Sreyk 		bzero(&tv, sizeof(tv));
17335d10c30Sreyk 		evtimer_add(&env->sc_ev, &tv);
1742edd718bSreyk 	}
175feb9ff76Sreyk 
17635d10c30Sreyk 	if (env->sc_flags & F_SSL) {
177e8fb3979Spyr 		ssl_init(env);
17835d10c30Sreyk 		TAILQ_FOREACH(table, env->sc_tables, entry) {
17968b79041Spyr 			if (!(table->conf.flags & F_SSL))
180e8fb3979Spyr 				continue;
181e8fb3979Spyr 			table->ssl_ctx = ssl_ctx_create(env);
182e8fb3979Spyr 		}
183e8fb3979Spyr 	}
184641b8bafSpyr }
185641b8bafSpyr 
186641b8bafSpyr void
187641b8bafSpyr hce_disable_events(void)
188641b8bafSpyr {
189641b8bafSpyr 	struct table	*table;
190641b8bafSpyr 	struct host	*host;
191641b8bafSpyr 
19235d10c30Sreyk 	evtimer_del(&env->sc_ev);
19335d10c30Sreyk 	TAILQ_FOREACH(table, env->sc_tables, entry) {
194641b8bafSpyr 		TAILQ_FOREACH(host, &table->hosts, entry) {
195*c0dc99f6Sreyk 			host->he = HCE_ABORT;
196641b8bafSpyr 			event_del(&host->cte.ev);
197641b8bafSpyr 			close(host->cte.s);
198641b8bafSpyr 		}
199641b8bafSpyr 	}
20035d10c30Sreyk 	if (env->sc_has_icmp) {
20135d10c30Sreyk 		event_del(&env->sc_icmp_send.ev);
20235d10c30Sreyk 		event_del(&env->sc_icmp_recv.ev);
203641b8bafSpyr 	}
20435d10c30Sreyk 	if (env->sc_has_icmp6) {
20535d10c30Sreyk 		event_del(&env->sc_icmp6_send.ev);
20635d10c30Sreyk 		event_del(&env->sc_icmp6_recv.ev);
207641b8bafSpyr 	}
208feb9ff76Sreyk }
209feb9ff76Sreyk 
210feb9ff76Sreyk void
211feb9ff76Sreyk hce_launch_checks(int fd, short event, void *arg)
212feb9ff76Sreyk {
213feb9ff76Sreyk 	struct host		*host;
214feb9ff76Sreyk 	struct table		*table;
21501d85ec5Sreyk 	struct timeval		 tv;
21601d85ec5Sreyk 
21701d85ec5Sreyk 	/*
21801d85ec5Sreyk 	 * notify pfe checks are done and schedule next check
21901d85ec5Sreyk 	 */
2207a0be62eSmsf 	imsg_compose(ibuf_pfe, IMSG_SYNC, 0, 0, -1, NULL, 0);
22135d10c30Sreyk 	TAILQ_FOREACH(table, env->sc_tables, entry) {
22201d85ec5Sreyk 		TAILQ_FOREACH(host, &table->hosts, entry) {
223*c0dc99f6Sreyk 			if ((host->flags & F_CHECK_DONE) == 0)
224*c0dc99f6Sreyk 				host->he = HCE_INTERVAL_TIMEOUT;
22501d85ec5Sreyk 			host->flags &= ~(F_CHECK_SENT|F_CHECK_DONE);
22601d85ec5Sreyk 			event_del(&host->cte.ev);
22701d85ec5Sreyk 		}
22801d85ec5Sreyk 	}
22901d85ec5Sreyk 
2306a899317Sthib 	if (gettimeofday(&tv, NULL) == -1)
23101d85ec5Sreyk 		fatal("hce_launch_checks: gettimeofday");
232feb9ff76Sreyk 
23335d10c30Sreyk 	TAILQ_FOREACH(table, env->sc_tables, entry) {
23468b79041Spyr 		if (table->conf.flags & F_DISABLE)
2357e351ffdSreyk 			continue;
23618de159aSpyr 		if (table->conf.skip_cnt) {
23718de159aSpyr 			if (table->skipped++ > table->conf.skip_cnt)
23818de159aSpyr 				table->skipped = 0;
23918de159aSpyr 			if (table->skipped != 1)
24018de159aSpyr 				continue;
24118de159aSpyr 		}
24268b79041Spyr 		if (table->conf.check == CHECK_NOCHECK)
2437e351ffdSreyk 			fatalx("hce_launch_checks: unknown check type");
24401d85ec5Sreyk 
2457e351ffdSreyk 		TAILQ_FOREACH(host, &table->hosts, entry) {
246c723f8edSreyk 			if (host->flags & F_DISABLE || host->conf.parentid)
2477e351ffdSreyk 				continue;
2484156152fSreyk 			switch (table->conf.check) {
2494156152fSreyk 			case CHECK_ICMP:
25001d85ec5Sreyk 				schedule_icmp(env, host);
2514156152fSreyk 				break;
2524156152fSreyk 			case CHECK_SCRIPT:
2534156152fSreyk 				check_script(host);
2544156152fSreyk 				break;
2554156152fSreyk 			default:
25601d85ec5Sreyk 				/* Any other TCP-style checks */
2577e351ffdSreyk 				bzero(&host->cte, sizeof(host->cte));
2587e351ffdSreyk 				host->last_up = host->up;
2597e351ffdSreyk 				host->cte.host = host;
2607e351ffdSreyk 				host->cte.table = table;
26101d85ec5Sreyk 				bcopy(&tv, &host->cte.tv_start,
26201d85ec5Sreyk 				    sizeof(host->cte.tv_start));
2637e351ffdSreyk 				check_tcp(&host->cte);
2644156152fSreyk 				break;
2654156152fSreyk 			}
2667e351ffdSreyk 		}
2677e351ffdSreyk 	}
26801d85ec5Sreyk 	check_icmp(env, &tv);
26901d85ec5Sreyk 
27035d10c30Sreyk 	bcopy(&env->sc_interval, &tv, sizeof(tv));
27135d10c30Sreyk 	evtimer_add(&env->sc_ev, &tv);
2727e351ffdSreyk }
2737e351ffdSreyk 
2747e351ffdSreyk void
275*c0dc99f6Sreyk hce_notify_done(struct host *host, enum host_error he)
2767e351ffdSreyk {
277609cf3a7Sreyk 	struct table		*table;
2787e351ffdSreyk 	struct ctl_status	 st;
279609cf3a7Sreyk 	struct timeval		 tv_now, tv_dur;
280609cf3a7Sreyk 	u_long			 duration;
281609cf3a7Sreyk 	u_int			 logopt;
282c723f8edSreyk 	struct host		*h;
283c723f8edSreyk 	int			 hostup;
284*c0dc99f6Sreyk 	const char		*msg;
285c723f8edSreyk 
286c723f8edSreyk 	hostup = host->up;
287*c0dc99f6Sreyk 	host->he = he;
2887e351ffdSreyk 
2892edd718bSreyk 	if (host->up == HOST_DOWN && host->retry_cnt) {
2902edd718bSreyk 		log_debug("hce_notify_done: host %s retry %d",
29168b79041Spyr 		    host->conf.name, host->retry_cnt);
292bd2508bcSreyk 		host->up = host->last_up;
2932edd718bSreyk 		host->retry_cnt--;
2942edd718bSreyk 	} else
29568b79041Spyr 		host->retry_cnt = host->conf.retry;
2962edd718bSreyk 	if (host->up != HOST_UNKNOWN) {
2972edd718bSreyk 		host->check_cnt++;
2982edd718bSreyk 		if (host->up == HOST_UP)
2992edd718bSreyk 			host->up_cnt++;
3002edd718bSreyk 	}
30168b79041Spyr 	st.id = host->conf.id;
302feb9ff76Sreyk 	st.up = host->up;
3032edd718bSreyk 	st.check_cnt = host->check_cnt;
3042edd718bSreyk 	st.retry_cnt = host->retry_cnt;
305*c0dc99f6Sreyk 	st.he = he;
30601d85ec5Sreyk 	host->flags |= (F_CHECK_SENT|F_CHECK_DONE);
307*c0dc99f6Sreyk 	msg = host_error(he);
3087e351ffdSreyk 	if (msg)
30968b79041Spyr 		log_debug("hce_notify_done: %s (%s)", host->conf.name, msg);
310609cf3a7Sreyk 
3117a0be62eSmsf 	imsg_compose(ibuf_pfe, IMSG_HOST_STATUS, 0, 0, -1, &st, sizeof(st));
3122edd718bSreyk 	if (host->up != host->last_up)
313748ceb64Sreyk 		logopt = RELAYD_OPT_LOGUPDATE;
3142edd718bSreyk 	else
315748ceb64Sreyk 		logopt = RELAYD_OPT_LOGNOTIFY;
316609cf3a7Sreyk 
3176a899317Sthib 	if (gettimeofday(&tv_now, NULL) == -1)
318609cf3a7Sreyk 		fatal("hce_notify_done: gettimeofday");
319609cf3a7Sreyk 	timersub(&tv_now, &host->cte.tv_start, &tv_dur);
320609cf3a7Sreyk 	if (timercmp(&host->cte.tv_start, &tv_dur, >))
321609cf3a7Sreyk 		duration = (tv_dur.tv_sec * 1000) + (tv_dur.tv_usec / 1000.0);
322609cf3a7Sreyk 	else
323609cf3a7Sreyk 		duration = 0;
324609cf3a7Sreyk 
32568b79041Spyr 	if ((table = table_find(env, host->conf.tableid)) == NULL)
3262edd718bSreyk 		fatalx("hce_notify_done: invalid table id");
3272edd718bSreyk 
32835d10c30Sreyk 	if (env->sc_opts & logopt) {
3292edd718bSreyk 		log_info("host %s, check %s%s (%lums), state %s -> %s, "
3302edd718bSreyk 		    "availability %s",
33168b79041Spyr 		    host->conf.name, table_check(table->conf.check),
33268b79041Spyr 		    (table->conf.flags & F_SSL) ? " use ssl" : "", duration,
3332edd718bSreyk 		    host_status(host->last_up), host_status(host->up),
3342edd718bSreyk 		    print_availability(host->check_cnt, host->up_cnt));
335feb9ff76Sreyk 	}
336fe250497Sreyk 
337fe250497Sreyk 	if (host->last_up != host->up)
338fe250497Sreyk 		snmp_hosttrap(table, host);
339fe250497Sreyk 
340609cf3a7Sreyk 	host->last_up = host->up;
341c723f8edSreyk 
3421584e35dSreyk 	if (SLIST_EMPTY(&host->children))
343c723f8edSreyk 		return;
344c723f8edSreyk 
345c723f8edSreyk 	/* Notify for all other hosts that inherit the state from this one */
3461584e35dSreyk 	SLIST_FOREACH(h, &host->children, child) {
347c723f8edSreyk 		h->up = hostup;
348*c0dc99f6Sreyk 		hce_notify_done(h, he);
349c723f8edSreyk 	}
350feb9ff76Sreyk }
351feb9ff76Sreyk 
352feb9ff76Sreyk void
353feb9ff76Sreyk hce_shutdown(void)
354feb9ff76Sreyk {
355feb9ff76Sreyk 	log_info("host check engine exiting");
356feb9ff76Sreyk 	_exit(0);
357feb9ff76Sreyk }
358feb9ff76Sreyk 
359feb9ff76Sreyk void
360feb9ff76Sreyk hce_dispatch_imsg(int fd, short event, void *ptr)
361feb9ff76Sreyk {
362feb9ff76Sreyk 	struct imsgbuf		*ibuf;
363feb9ff76Sreyk 	struct imsg		 imsg;
364feb9ff76Sreyk 	ssize_t			 n;
365feb9ff76Sreyk 	objid_t			 id;
366feb9ff76Sreyk 	struct host		*host;
367feb9ff76Sreyk 	struct table		*table;
368feb9ff76Sreyk 
369feb9ff76Sreyk 	ibuf = ptr;
370feb9ff76Sreyk 	switch (event) {
371feb9ff76Sreyk 	case EV_READ:
372feb9ff76Sreyk 		if ((n = imsg_read(ibuf)) == -1)
373feb9ff76Sreyk 			fatal("hce_dispatch_imsg: imsg_read_error");
374ddfd9103Spyr 		if (n == 0) {
375ddfd9103Spyr 			/* this pipe is dead, so remove the event handler */
376ddfd9103Spyr 			event_del(&ibuf->ev);
377ddfd9103Spyr 			event_loopexit(NULL);
378ddfd9103Spyr 			return;
379ddfd9103Spyr 		}
380feb9ff76Sreyk 		break;
381feb9ff76Sreyk 	case EV_WRITE:
382feb9ff76Sreyk 		if (msgbuf_write(&ibuf->w) == -1)
383feb9ff76Sreyk 			fatal("hce_dispatch_imsg: msgbuf_write");
384feb9ff76Sreyk 		imsg_event_add(ibuf);
385feb9ff76Sreyk 		return;
386feb9ff76Sreyk 	default:
387feb9ff76Sreyk 		fatalx("hce_dispatch_imsg: unknown event");
388feb9ff76Sreyk 	}
389feb9ff76Sreyk 
390feb9ff76Sreyk 	for (;;) {
391feb9ff76Sreyk 		if ((n = imsg_get(ibuf, &imsg)) == -1)
392feb9ff76Sreyk 			fatal("hce_dispatch_imsg: imsg_read error");
393feb9ff76Sreyk 		if (n == 0)
394feb9ff76Sreyk 			break;
395feb9ff76Sreyk 
396feb9ff76Sreyk 		switch (imsg.hdr.type) {
397feb9ff76Sreyk 		case IMSG_HOST_DISABLE:
398feb9ff76Sreyk 			memcpy(&id, imsg.data, sizeof(id));
399feb9ff76Sreyk 			if ((host = host_find(env, id)) == NULL)
400feb9ff76Sreyk 				fatalx("hce_dispatch_imsg: desynchronized");
401feb9ff76Sreyk 			host->flags |= F_DISABLE;
402feb9ff76Sreyk 			host->up = HOST_UNKNOWN;
4032edd718bSreyk 			host->check_cnt = 0;
4042edd718bSreyk 			host->up_cnt = 0;
405*c0dc99f6Sreyk 			host->he = HCE_NONE;
406feb9ff76Sreyk 			break;
407feb9ff76Sreyk 		case IMSG_HOST_ENABLE:
408feb9ff76Sreyk 			memcpy(&id, imsg.data, sizeof(id));
409feb9ff76Sreyk 			if ((host = host_find(env, id)) == NULL)
410feb9ff76Sreyk 				fatalx("hce_dispatch_imsg: desynchronized");
411feb9ff76Sreyk 			host->flags &= ~(F_DISABLE);
412feb9ff76Sreyk 			host->up = HOST_UNKNOWN;
413*c0dc99f6Sreyk 			host->he = HCE_NONE;
414feb9ff76Sreyk 			break;
415feb9ff76Sreyk 		case IMSG_TABLE_DISABLE:
416feb9ff76Sreyk 			memcpy(&id, imsg.data, sizeof(id));
417feb9ff76Sreyk 			if ((table = table_find(env, id)) == NULL)
418feb9ff76Sreyk 				fatalx("hce_dispatch_imsg: desynchronized");
41968b79041Spyr 			table->conf.flags |= F_DISABLE;
420feb9ff76Sreyk 			TAILQ_FOREACH(host, &table->hosts, entry)
421feb9ff76Sreyk 				host->up = HOST_UNKNOWN;
422feb9ff76Sreyk 			break;
423feb9ff76Sreyk 		case IMSG_TABLE_ENABLE:
424feb9ff76Sreyk 			memcpy(&id, imsg.data, sizeof(id));
425feb9ff76Sreyk 			if ((table = table_find(env, id)) == NULL)
426feb9ff76Sreyk 				fatalx("hce_dispatch_imsg: desynchronized");
42768b79041Spyr 			table->conf.flags &= ~(F_DISABLE);
428feb9ff76Sreyk 			TAILQ_FOREACH(host, &table->hosts, entry)
429feb9ff76Sreyk 				host->up = HOST_UNKNOWN;
430feb9ff76Sreyk 			break;
431cd65ce7bSpyr 		case IMSG_CTL_POLL:
43235d10c30Sreyk 			evtimer_del(&env->sc_ev);
43335d10c30Sreyk 			TAILQ_FOREACH(table, env->sc_tables, entry)
434f98352d8Spyr 				table->skipped = 0;
435cd65ce7bSpyr 			hce_launch_checks(-1, EV_TIMEOUT, env);
436cd65ce7bSpyr 			break;
437feb9ff76Sreyk 		default:
438feb9ff76Sreyk 			log_debug("hce_dispatch_msg: unexpected imsg %d",
439feb9ff76Sreyk 			    imsg.hdr.type);
440feb9ff76Sreyk 			break;
441feb9ff76Sreyk 		}
442feb9ff76Sreyk 		imsg_free(&imsg);
443feb9ff76Sreyk 	}
444feb9ff76Sreyk 	imsg_event_add(ibuf);
445feb9ff76Sreyk }
446feb9ff76Sreyk 
447feb9ff76Sreyk void
448feb9ff76Sreyk hce_dispatch_parent(int fd, short event, void * ptr)
449feb9ff76Sreyk {
450feb9ff76Sreyk 	struct imsgbuf		*ibuf;
451feb9ff76Sreyk 	struct imsg		 imsg;
4524156152fSreyk 	struct ctl_script	 scr;
453feb9ff76Sreyk 	ssize_t			 n;
454adf98c11Spyr 	size_t			 len;
455adf98c11Spyr 
456adf98c11Spyr 	static struct table	*table = NULL;
457adf98c11Spyr 	struct host		*host;
458feb9ff76Sreyk 
459feb9ff76Sreyk 	ibuf = ptr;
460feb9ff76Sreyk 	switch (event) {
461feb9ff76Sreyk 	case EV_READ:
462feb9ff76Sreyk 		if ((n = imsg_read(ibuf)) == -1)
463feb9ff76Sreyk 			fatal("hce_dispatch_parent: imsg_read error");
464ddfd9103Spyr 		if (n == 0) {
465ddfd9103Spyr 			/* this pipe is dead, so remove the event handler */
466ddfd9103Spyr 			event_del(&ibuf->ev);
467ddfd9103Spyr 			event_loopexit(NULL);
468ddfd9103Spyr 			return;
469ddfd9103Spyr 		}
470feb9ff76Sreyk 		break;
471feb9ff76Sreyk 	case EV_WRITE:
472feb9ff76Sreyk 		if (msgbuf_write(&ibuf->w) == -1)
473feb9ff76Sreyk 			fatal("hce_dispatch_parent: msgbuf_write");
474feb9ff76Sreyk 		imsg_event_add(ibuf);
475feb9ff76Sreyk 		return;
476feb9ff76Sreyk 	default:
477feb9ff76Sreyk 		fatalx("hce_dispatch_parent: unknown event");
478feb9ff76Sreyk 	}
479feb9ff76Sreyk 
480feb9ff76Sreyk 	for (;;) {
481feb9ff76Sreyk 		if ((n = imsg_get(ibuf, &imsg)) == -1)
482feb9ff76Sreyk 			fatal("hce_dispatch_parent: imsg_read error");
483feb9ff76Sreyk 		if (n == 0)
484feb9ff76Sreyk 			break;
485feb9ff76Sreyk 
486feb9ff76Sreyk 		switch (imsg.hdr.type) {
4874156152fSreyk 		case IMSG_SCRIPT:
4884156152fSreyk 			if (imsg.hdr.len - IMSG_HEADER_SIZE !=
4894156152fSreyk 			    sizeof(scr))
4904156152fSreyk 				fatalx("hce_dispatch_parent: "
4914156152fSreyk 				    "invalid size of script request");
4924156152fSreyk 			bcopy(imsg.data, &scr, sizeof(scr));
4934156152fSreyk 			script_done(env, &scr);
4944156152fSreyk 			break;
495adf98c11Spyr 		case IMSG_RECONF:
496adf98c11Spyr 			log_debug("hce: reloading configuration");
497adf98c11Spyr 			if (imsg.hdr.len !=
498748ceb64Sreyk 			    sizeof(struct relayd) + IMSG_HEADER_SIZE)
499adf98c11Spyr 				fatalx("corrupted reload data");
500adf98c11Spyr 			hce_disable_events();
501adf98c11Spyr 			purge_config(env, PURGE_TABLES);
502748ceb64Sreyk 			merge_config(env, (struct relayd *)imsg.data);
503adf98c11Spyr 
50435d10c30Sreyk 			env->sc_tables = calloc(1, sizeof(*env->sc_tables));
50535d10c30Sreyk 			if (env->sc_tables == NULL)
506adf98c11Spyr 				fatal(NULL);
507adf98c11Spyr 
50835d10c30Sreyk 			TAILQ_INIT(env->sc_tables);
509adf98c11Spyr 			break;
510adf98c11Spyr 		case IMSG_RECONF_TABLE:
511adf98c11Spyr 			if ((table = calloc(1, sizeof(*table))) == NULL)
512adf98c11Spyr 				fatal(NULL);
513adf98c11Spyr 			memcpy(&table->conf, imsg.data, sizeof(table->conf));
514adf98c11Spyr 			TAILQ_INIT(&table->hosts);
51535d10c30Sreyk 			TAILQ_INSERT_TAIL(env->sc_tables, table, entry);
516adf98c11Spyr 			break;
517adf98c11Spyr 		case IMSG_RECONF_SENDBUF:
518adf98c11Spyr 			len = imsg.hdr.len - IMSG_HEADER_SIZE;
519adf98c11Spyr 			table->sendbuf = calloc(1, len);
520adf98c11Spyr 			(void)strlcpy(table->sendbuf, (char *)imsg.data, len);
521adf98c11Spyr 			break;
522adf98c11Spyr 		case IMSG_RECONF_HOST:
523adf98c11Spyr 			if ((host = calloc(1, sizeof(*host))) == NULL)
524adf98c11Spyr 				fatal(NULL);
525adf98c11Spyr 			memcpy(&host->conf, imsg.data, sizeof(host->conf));
526adf98c11Spyr 			host->tablename = table->conf.name;
527adf98c11Spyr 			TAILQ_INSERT_TAIL(&table->hosts, host, entry);
528adf98c11Spyr 			break;
529adf98c11Spyr 		case IMSG_RECONF_END:
530adf98c11Spyr 			log_warnx("hce: configuration reloaded");
531adf98c11Spyr 			hce_setup_events();
532adf98c11Spyr 			break;
533feb9ff76Sreyk 		default:
534feb9ff76Sreyk 			log_debug("hce_dispatch_parent: unexpected imsg %d",
535feb9ff76Sreyk 			    imsg.hdr.type);
536feb9ff76Sreyk 			break;
537feb9ff76Sreyk 		}
538feb9ff76Sreyk 		imsg_free(&imsg);
539feb9ff76Sreyk 	}
5404156152fSreyk 	imsg_event_add(ibuf);
541feb9ff76Sreyk }
542