GCC Code Coverage Report
Directory: ./ Exec Total Coverage
File: usr.sbin/relayd/hce.c Lines: 0 185 0.0 %
Date: 2017-11-07 Branches: 0 120 0.0 %

Line Branch Exec Source
1
/*	$OpenBSD: hce.c,v 1.77 2017/05/28 10:39:15 benno Exp $	*/
2
3
/*
4
 * Copyright (c) 2006 Pierre-Yves Ritschard <pyr@openbsd.org>
5
 *
6
 * Permission to use, copy, modify, and distribute this software for any
7
 * purpose with or without fee is hereby granted, provided that the above
8
 * copyright notice and this permission notice appear in all copies.
9
 *
10
 * THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES
11
 * WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF
12
 * MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR
13
 * ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES
14
 * WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN
15
 * ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF
16
 * OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
17
 */
18
19
#include <sys/types.h>
20
#include <sys/queue.h>
21
#include <sys/time.h>
22
#include <sys/uio.h>
23
24
#include <event.h>
25
#include <stdlib.h>
26
#include <string.h>
27
#include <unistd.h>
28
#include <imsg.h>
29
30
#include "relayd.h"
31
32
void	 hce_init(struct privsep *, struct privsep_proc *p, void *);
33
void	 hce_sig_handler(int sig, short, void *);
34
void	 hce_launch_checks(int, short, void *);
35
void	 hce_setup_events(void);
36
void	 hce_disable_events(void);
37
38
int	 hce_dispatch_parent(int, struct privsep_proc *, struct imsg *);
39
int	 hce_dispatch_pfe(int, struct privsep_proc *, struct imsg *);
40
int	 hce_dispatch_relay(int, struct privsep_proc *, struct imsg *);
41
42
static struct relayd *env = NULL;
43
int			 running = 0;
44
45
static struct privsep_proc procs[] = {
46
	{ "parent",	PROC_PARENT,	hce_dispatch_parent },
47
	{ "pfe",	PROC_PFE,	hce_dispatch_pfe },
48
	{ "relay",	PROC_RELAY,	hce_dispatch_relay },
49
};
50
51
void
52
hce(struct privsep *ps, struct privsep_proc *p)
53
{
54
	env = ps->ps_env;
55
56
	/* this is needed for icmp tests */
57
	icmp_init(env);
58
59
	proc_run(ps, p, procs, nitems(procs), hce_init, NULL);
60
}
61
62
void
63
hce_init(struct privsep *ps, struct privsep_proc *p, void *arg)
64
{
65
	if (config_init(ps->ps_env) == -1)
66
		fatal("failed to initialize configuration");
67
68
	env->sc_id = getpid() & 0xffff;
69
70
	/* Allow maximum available sockets for TCP checks */
71
	socket_rlimit(-1);
72
73
	if (pledge("stdio recvfd inet flock rpath cpath wpath", NULL) == -1)
74
		fatal("%s: pledge", __func__);
75
}
76
77
void
78
hce_setup_events(void)
79
{
80
	struct timeval	 tv;
81
	struct table	*table;
82
83
	if (!(TAILQ_EMPTY(env->sc_tables) ||
84
	    event_initialized(&env->sc_ev))) {
85
		evtimer_set(&env->sc_ev, hce_launch_checks, env);
86
		bzero(&tv, sizeof(tv));
87
		evtimer_add(&env->sc_ev, &tv);
88
	}
89
90
	if (env->sc_conf.flags & F_TLS) {
91
		TAILQ_FOREACH(table, env->sc_tables, entry) {
92
			if (!(table->conf.flags & F_TLS) ||
93
			    table->tls_cfg != NULL)
94
				continue;
95
			table->tls_cfg = tls_config_new();
96
			tls_config_insecure_noverifycert(table->tls_cfg);
97
			tls_config_insecure_noverifyname(table->tls_cfg);
98
		}
99
	}
100
}
101
102
void
103
hce_disable_events(void)
104
{
105
	struct table	*table;
106
	struct host	*host;
107
108
	evtimer_del(&env->sc_ev);
109
	TAILQ_FOREACH(table, env->sc_tables, entry) {
110
		TAILQ_FOREACH(host, &table->hosts, entry) {
111
			host->he = HCE_ABORT;
112
			if (event_initialized(&host->cte.ev)) {
113
				event_del(&host->cte.ev);
114
				close(host->cte.s);
115
			}
116
		}
117
	}
118
	if (env->sc_has_icmp) {
119
		event_del(&env->sc_icmp_send.ev);
120
		event_del(&env->sc_icmp_recv.ev);
121
	}
122
	if (env->sc_has_icmp6) {
123
		event_del(&env->sc_icmp6_send.ev);
124
		event_del(&env->sc_icmp6_recv.ev);
125
	}
126
}
127
128
void
129
hce_launch_checks(int fd, short event, void *arg)
130
{
131
	struct host		*host;
132
	struct table		*table;
133
	struct timeval		 tv;
134
135
	/*
136
	 * notify pfe checks are done and schedule next check
137
	 */
138
	proc_compose(env->sc_ps, PROC_PFE, IMSG_SYNC, NULL, 0);
139
	TAILQ_FOREACH(table, env->sc_tables, entry) {
140
		TAILQ_FOREACH(host, &table->hosts, entry) {
141
			if ((host->flags & F_CHECK_DONE) == 0)
142
				host->he = HCE_INTERVAL_TIMEOUT;
143
			host->flags &= ~(F_CHECK_SENT|F_CHECK_DONE);
144
			if (event_initialized(&host->cte.ev)) {
145
				event_del(&host->cte.ev);
146
				close(host->cte.s);
147
			}
148
			host->cte.s = -1;
149
		}
150
	}
151
152
	getmonotime(&tv);
153
154
	TAILQ_FOREACH(table, env->sc_tables, entry) {
155
		if (table->conf.flags & F_DISABLE)
156
			continue;
157
		if (table->conf.skip_cnt) {
158
			if (table->skipped++ > table->conf.skip_cnt)
159
				table->skipped = 0;
160
			if (table->skipped != 1)
161
				continue;
162
		}
163
		if (table->conf.check == CHECK_NOCHECK)
164
			fatalx("%s: unknown check type", __func__);
165
166
		TAILQ_FOREACH(host, &table->hosts, entry) {
167
			if (host->flags & F_DISABLE || host->conf.parentid)
168
				continue;
169
			bcopy(&tv, &host->cte.tv_start,
170
			    sizeof(host->cte.tv_start));
171
			switch (table->conf.check) {
172
			case CHECK_ICMP:
173
				schedule_icmp(env, host);
174
				break;
175
			case CHECK_SCRIPT:
176
				check_script(env, host);
177
				break;
178
			default:
179
				/* Any other TCP-style checks */
180
				host->last_up = host->up;
181
				host->cte.host = host;
182
				host->cte.table = table;
183
				check_tcp(&host->cte);
184
				break;
185
			}
186
		}
187
	}
188
	check_icmp(env, &tv);
189
190
	bcopy(&env->sc_conf.interval, &tv, sizeof(tv));
191
	evtimer_add(&env->sc_ev, &tv);
192
}
193
194
void
195
hce_notify_done(struct host *host, enum host_error he)
196
{
197
	struct table		*table;
198
	struct ctl_status	 st;
199
	struct timeval		 tv_now, tv_dur;
200
	u_long			 duration;
201
	u_int			 logopt;
202
	struct host		*h, *hostnst;
203
	int			 hostup;
204
	const char		*msg;
205
	char			*codemsg = NULL;
206
207
	if ((hostnst = host_find(env, host->conf.id)) == NULL)
208
		fatalx("%s: desynchronized", __func__);
209
210
	if ((table = table_find(env, host->conf.tableid)) == NULL)
211
		fatalx("%s: invalid table id", __func__);
212
213
	if (hostnst->flags & F_DISABLE) {
214
		if (env->sc_conf.opts & RELAYD_OPT_LOGUPDATE) {
215
			log_info("host %s, check %s%s (ignoring result, "
216
			    "host disabled)",
217
			    host->conf.name, table_check(table->conf.check),
218
			    (table->conf.flags & F_TLS) ? " use tls" : "");
219
		}
220
		host->flags |= (F_CHECK_SENT|F_CHECK_DONE);
221
		return;
222
	}
223
224
	hostup = host->up;
225
	host->he = he;
226
227
	if (host->up == HOST_DOWN && host->retry_cnt) {
228
		log_debug("%s: host %s retry %d", __func__,
229
		    host->conf.name, host->retry_cnt);
230
		host->up = host->last_up;
231
		host->retry_cnt--;
232
	} else
233
		host->retry_cnt = host->conf.retry;
234
	if (host->up != HOST_UNKNOWN) {
235
		host->check_cnt++;
236
		if (host->up == HOST_UP)
237
			host->up_cnt++;
238
	}
239
	st.id = host->conf.id;
240
	st.up = host->up;
241
	st.check_cnt = host->check_cnt;
242
	st.retry_cnt = host->retry_cnt;
243
	st.he = he;
244
	host->flags |= (F_CHECK_SENT|F_CHECK_DONE);
245
	msg = host_error(he);
246
	if (msg)
247
		log_debug("%s: %s (%s)", __func__, host->conf.name, msg);
248
249
	proc_compose(env->sc_ps, PROC_PFE, IMSG_HOST_STATUS, &st, sizeof(st));
250
	if (host->up != host->last_up)
251
		logopt = RELAYD_OPT_LOGUPDATE;
252
	else
253
		logopt = RELAYD_OPT_LOGNOTIFY;
254
255
	getmonotime(&tv_now);
256
	timersub(&tv_now, &host->cte.tv_start, &tv_dur);
257
	if (timercmp(&host->cte.tv_start, &tv_dur, >))
258
		duration = (tv_dur.tv_sec * 1000) + (tv_dur.tv_usec / 1000.0);
259
	else
260
		duration = 0;
261
262
	if (env->sc_conf.opts & logopt) {
263
		if (host->code > 0)
264
		    asprintf(&codemsg, ",%d", host->code);
265
		log_info("host %s, check %s%s (%lums,%s%s), state %s -> %s, "
266
		    "availability %s",
267
		    host->conf.name, table_check(table->conf.check),
268
		    (table->conf.flags & F_TLS) ? " use tls" : "", duration,
269
		    msg, (codemsg != NULL) ? codemsg : "",
270
		    host_status(host->last_up), host_status(host->up),
271
		    print_availability(host->check_cnt, host->up_cnt));
272
		free(codemsg);
273
	}
274
275
	host->last_up = host->up;
276
277
	if (SLIST_EMPTY(&host->children))
278
		return;
279
280
	/* Notify for all other hosts that inherit the state from this one */
281
	SLIST_FOREACH(h, &host->children, child) {
282
		h->up = hostup;
283
		hce_notify_done(h, he);
284
	}
285
}
286
287
int
288
hce_dispatch_pfe(int fd, struct privsep_proc *p, struct imsg *imsg)
289
{
290
	objid_t			 id;
291
	struct host		*host;
292
	struct table		*table;
293
294
	switch (imsg->hdr.type) {
295
	case IMSG_HOST_DISABLE:
296
		memcpy(&id, imsg->data, sizeof(id));
297
		if ((host = host_find(env, id)) == NULL)
298
			fatalx("%s: desynchronized", __func__);
299
		host->flags |= F_DISABLE;
300
		host->up = HOST_UNKNOWN;
301
		host->check_cnt = 0;
302
		host->up_cnt = 0;
303
		host->he = HCE_NONE;
304
		break;
305
	case IMSG_HOST_ENABLE:
306
		memcpy(&id, imsg->data, sizeof(id));
307
		if ((host = host_find(env, id)) == NULL)
308
			fatalx("%s: desynchronized", __func__);
309
		host->flags &= ~(F_DISABLE);
310
		host->up = HOST_UNKNOWN;
311
		host->he = HCE_NONE;
312
		break;
313
	case IMSG_TABLE_DISABLE:
314
		memcpy(&id, imsg->data, sizeof(id));
315
		if ((table = table_find(env, id)) == NULL)
316
			fatalx("%s: desynchronized", __func__);
317
		table->conf.flags |= F_DISABLE;
318
		TAILQ_FOREACH(host, &table->hosts, entry)
319
			host->up = HOST_UNKNOWN;
320
		break;
321
	case IMSG_TABLE_ENABLE:
322
		memcpy(&id, imsg->data, sizeof(id));
323
		if ((table = table_find(env, id)) == NULL)
324
			fatalx("%s: desynchronized", __func__);
325
		table->conf.flags &= ~(F_DISABLE);
326
		TAILQ_FOREACH(host, &table->hosts, entry)
327
			host->up = HOST_UNKNOWN;
328
		break;
329
	case IMSG_CTL_POLL:
330
		evtimer_del(&env->sc_ev);
331
		TAILQ_FOREACH(table, env->sc_tables, entry)
332
			table->skipped = 0;
333
		hce_launch_checks(-1, EV_TIMEOUT, env);
334
		break;
335
	default:
336
		return (-1);
337
	}
338
339
	return (0);
340
}
341
342
int
343
hce_dispatch_parent(int fd, struct privsep_proc *p, struct imsg *imsg)
344
{
345
	struct ctl_script	 scr;
346
347
	switch (imsg->hdr.type) {
348
	case IMSG_SCRIPT:
349
		IMSG_SIZE_CHECK(imsg, &scr);
350
		bcopy(imsg->data, &scr, sizeof(scr));
351
		script_done(env, &scr);
352
		break;
353
	case IMSG_CFG_TABLE:
354
		config_gettable(env, imsg);
355
		break;
356
	case IMSG_CFG_HOST:
357
		config_gethost(env, imsg);
358
		break;
359
	case IMSG_CFG_DONE:
360
		config_getcfg(env, imsg);
361
		break;
362
	case IMSG_CTL_START:
363
		hce_setup_events();
364
		break;
365
	case IMSG_CTL_RESET:
366
		config_getreset(env, imsg);
367
		break;
368
	default:
369
		return (-1);
370
	}
371
372
	return (0);
373
}
374
375
int
376
hce_dispatch_relay(int fd, struct privsep_proc *p, struct imsg *imsg)
377
{
378
	switch (imsg->hdr.type) {
379
	default:
380
		break;
381
	}
382
383
	return (-1);
384
}