GCC Code Coverage Report
Directory: ./ Exec Total Coverage
File: usr.sbin/relayd/pfe.c Lines: 0 446 0.0 %
Date: 2017-11-13 Branches: 0 276 0.0 %

Line Branch Exec Source
1
/*	$OpenBSD: pfe.c,v 1.89 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/socket.h>
22
#include <sys/time.h>
23
#include <sys/uio.h>
24
#include <sys/ioctl.h>
25
#include <net/if.h>
26
#include <net/pfvar.h>
27
28
#include <event.h>
29
#include <fcntl.h>
30
#include <stdlib.h>
31
#include <string.h>
32
#include <unistd.h>
33
#include <imsg.h>
34
35
#include "relayd.h"
36
37
void	 pfe_init(struct privsep *, struct privsep_proc *p, void *);
38
void	 pfe_shutdown(void);
39
void	 pfe_setup_events(void);
40
void	 pfe_disable_events(void);
41
void	 pfe_sync(void);
42
void	 pfe_statistics(int, short, void *);
43
44
int	 pfe_dispatch_parent(int, struct privsep_proc *, struct imsg *);
45
int	 pfe_dispatch_hce(int, struct privsep_proc *, struct imsg *);
46
int	 pfe_dispatch_relay(int, struct privsep_proc *, struct imsg *);
47
48
static struct relayd		*env = NULL;
49
50
static struct privsep_proc procs[] = {
51
	{ "parent",	PROC_PARENT,	pfe_dispatch_parent },
52
	{ "relay",	PROC_RELAY,	pfe_dispatch_relay },
53
	{ "hce",	PROC_HCE,	pfe_dispatch_hce }
54
};
55
56
void
57
pfe(struct privsep *ps, struct privsep_proc *p)
58
{
59
	int			s;
60
	struct pf_status	status;
61
62
	env = ps->ps_env;
63
64
	if ((s = open(PF_SOCKET, O_RDWR)) == -1) {
65
		fatal("%s: cannot open pf socket", __func__);
66
	}
67
	if (env->sc_pf == NULL) {
68
		if ((env->sc_pf = calloc(1, sizeof(*(env->sc_pf)))) == NULL)
69
			fatal("calloc");
70
		env->sc_pf->dev = s;
71
	}
72
	if (ioctl(env->sc_pf->dev, DIOCGETSTATUS, &status) == -1)
73
		fatal("%s: DIOCGETSTATUS", __func__);
74
	if (!status.running)
75
		fatalx("%s: pf is disabled", __func__);
76
	log_debug("%s: filter init done", __func__);
77
78
	proc_run(ps, p, procs, nitems(procs), pfe_init, NULL);
79
}
80
81
void
82
pfe_init(struct privsep *ps, struct privsep_proc *p, void *arg)
83
{
84
	if (config_init(ps->ps_env) == -1)
85
		fatal("failed to initialize configuration");
86
87
	if (pledge("stdio recvfd unix pf flock rpath cpath wpath", NULL) == -1)
88
		fatal("pledge");
89
90
	p->p_shutdown = pfe_shutdown;
91
}
92
93
void
94
pfe_shutdown(void)
95
{
96
	flush_rulesets(env);
97
	config_purge(env, CONFIG_ALL);
98
}
99
100
void
101
pfe_setup_events(void)
102
{
103
	struct timeval	 tv;
104
105
	/* Schedule statistics timer */
106
	if (!event_initialized(&env->sc_statev)) {
107
		evtimer_set(&env->sc_statev, pfe_statistics, NULL);
108
		bcopy(&env->sc_conf.statinterval, &tv, sizeof(tv));
109
		evtimer_add(&env->sc_statev, &tv);
110
	}
111
}
112
113
void
114
pfe_disable_events(void)
115
{
116
	event_del(&env->sc_statev);
117
}
118
119
int
120
pfe_dispatch_hce(int fd, struct privsep_proc *p, struct imsg *imsg)
121
{
122
	struct host		*host;
123
	struct table		*table;
124
	struct ctl_status	 st;
125
126
	control_imsg_forward(p->p_ps, imsg);
127
128
	switch (imsg->hdr.type) {
129
	case IMSG_HOST_STATUS:
130
		IMSG_SIZE_CHECK(imsg, &st);
131
		memcpy(&st, imsg->data, sizeof(st));
132
		if ((host = host_find(env, st.id)) == NULL)
133
			fatalx("%s: invalid host id", __func__);
134
		host->he = st.he;
135
		if (host->flags & F_DISABLE)
136
			break;
137
		host->retry_cnt = st.retry_cnt;
138
		if (st.up != HOST_UNKNOWN) {
139
			host->check_cnt++;
140
			if (st.up == HOST_UP)
141
				host->up_cnt++;
142
		}
143
		if (host->check_cnt != st.check_cnt) {
144
			log_debug("%s: host %d => %d", __func__,
145
			    host->conf.id, host->up);
146
			fatalx("%s: desynchronized", __func__);
147
		}
148
149
		if (host->up == st.up)
150
			break;
151
152
		/* Forward to relay engine(s) */
153
		proc_compose(env->sc_ps, PROC_RELAY,
154
		    IMSG_HOST_STATUS, &st, sizeof(st));
155
156
		if ((table = table_find(env, host->conf.tableid))
157
		    == NULL)
158
			fatalx("%s: invalid table id", __func__);
159
160
		log_debug("%s: state %d for host %u %s", __func__,
161
		    st.up, host->conf.id, host->conf.name);
162
163
		snmp_hosttrap(env, table, host);
164
165
		/*
166
		 * Do not change the table state when the host
167
		 * state switches between UNKNOWN and DOWN.
168
		 */
169
		if (HOST_ISUP(st.up)) {
170
			table->conf.flags |= F_CHANGED;
171
			table->up++;
172
			host->flags |= F_ADD;
173
			host->flags &= ~(F_DEL);
174
		} else if (HOST_ISUP(host->up)) {
175
			table->up--;
176
			table->conf.flags |= F_CHANGED;
177
			host->flags |= F_DEL;
178
			host->flags &= ~(F_ADD);
179
			host->up = st.up;
180
			pfe_sync();
181
		}
182
183
		host->up = st.up;
184
		break;
185
	case IMSG_SYNC:
186
		pfe_sync();
187
		break;
188
	default:
189
		return (-1);
190
	}
191
192
	return (0);
193
}
194
195
int
196
pfe_dispatch_parent(int fd, struct privsep_proc *p, struct imsg *imsg)
197
{
198
	switch (imsg->hdr.type) {
199
	case IMSG_CFG_TABLE:
200
		config_gettable(env, imsg);
201
		break;
202
	case IMSG_CFG_HOST:
203
		config_gethost(env, imsg);
204
		break;
205
	case IMSG_CFG_RDR:
206
		config_getrdr(env, imsg);
207
		break;
208
	case IMSG_CFG_VIRT:
209
		config_getvirt(env, imsg);
210
		break;
211
	case IMSG_CFG_ROUTER:
212
		config_getrt(env, imsg);
213
		break;
214
	case IMSG_CFG_ROUTE:
215
		config_getroute(env, imsg);
216
		break;
217
	case IMSG_CFG_PROTO:
218
		config_getproto(env, imsg);
219
		break;
220
	case IMSG_CFG_RELAY:
221
		config_getrelay(env, imsg);
222
		break;
223
	case IMSG_CFG_RELAY_TABLE:
224
		config_getrelaytable(env, imsg);
225
		break;
226
	case IMSG_CFG_DONE:
227
		config_getcfg(env, imsg);
228
		init_tables(env);
229
		snmp_init(env, PROC_PARENT);
230
		break;
231
	case IMSG_CTL_START:
232
		pfe_setup_events();
233
		pfe_sync();
234
		break;
235
	case IMSG_CTL_RESET:
236
		config_getreset(env, imsg);
237
		break;
238
	case IMSG_SNMPSOCK:
239
		snmp_getsock(env, imsg);
240
		break;
241
	default:
242
		return (-1);
243
	}
244
245
	return (0);
246
}
247
248
int
249
pfe_dispatch_relay(int fd, struct privsep_proc *p, struct imsg *imsg)
250
{
251
	struct ctl_natlook	 cnl;
252
	struct ctl_stats	 crs;
253
	struct relay		*rlay;
254
	struct ctl_conn		*c;
255
	struct rsession		 con, *s, *t;
256
	int			 cid;
257
	objid_t			 sid;
258
259
	switch (imsg->hdr.type) {
260
	case IMSG_NATLOOK:
261
		IMSG_SIZE_CHECK(imsg, &cnl);
262
		bcopy(imsg->data, &cnl, sizeof(cnl));
263
		if (cnl.proc > env->sc_conf.prefork_relay)
264
			fatalx("%s: invalid relay proc", __func__);
265
		if (natlook(env, &cnl) != 0)
266
			cnl.in = -1;
267
		proc_compose_imsg(env->sc_ps, PROC_RELAY, cnl.proc,
268
		    IMSG_NATLOOK, -1, -1, &cnl, sizeof(cnl));
269
		break;
270
	case IMSG_STATISTICS:
271
		IMSG_SIZE_CHECK(imsg, &crs);
272
		bcopy(imsg->data, &crs, sizeof(crs));
273
		if (crs.proc > env->sc_conf.prefork_relay)
274
			fatalx("%s: invalid relay proc", __func__);
275
		if ((rlay = relay_find(env, crs.id)) == NULL)
276
			fatalx("%s: invalid relay id", __func__);
277
		bcopy(&crs, &rlay->rl_stats[crs.proc], sizeof(crs));
278
		rlay->rl_stats[crs.proc].interval =
279
		    env->sc_conf.statinterval.tv_sec;
280
		break;
281
	case IMSG_CTL_SESSION:
282
		IMSG_SIZE_CHECK(imsg, &con);
283
		memcpy(&con, imsg->data, sizeof(con));
284
		if ((c = control_connbyfd(con.se_cid)) == NULL) {
285
			log_debug("%s: control connection %d not found",
286
			    __func__, con.se_cid);
287
			return (0);
288
		}
289
		imsg_compose_event(&c->iev,
290
		    IMSG_CTL_SESSION, 0, 0, -1,
291
		    &con, sizeof(con));
292
		break;
293
	case IMSG_CTL_END:
294
		IMSG_SIZE_CHECK(imsg, &cid);
295
		memcpy(&cid, imsg->data, sizeof(cid));
296
		if ((c = control_connbyfd(cid)) == NULL) {
297
			log_debug("%s: control connection %d not found",
298
			    __func__, cid);
299
			return (0);
300
		}
301
		if (c->waiting == 0) {
302
			log_debug("%s: no pending control requests", __func__);
303
			return (0);
304
		} else if (--c->waiting == 0) {
305
			/* Last ack for a previous request */
306
			imsg_compose_event(&c->iev, IMSG_CTL_END,
307
			    0, 0, -1, NULL, 0);
308
		}
309
		break;
310
	case IMSG_SESS_PUBLISH:
311
		IMSG_SIZE_CHECK(imsg, s);
312
		if ((s = calloc(1, sizeof(*s))) == NULL)
313
			return (0);		/* XXX */
314
		memcpy(s, imsg->data, sizeof(*s));
315
		TAILQ_FOREACH(t, &env->sc_sessions, se_entry) {
316
			/* duplicate registration */
317
			if (t->se_id == s->se_id) {
318
				free(s);
319
				return (0);
320
			}
321
			if (t->se_id > s->se_id)
322
				break;
323
		}
324
		if (t)
325
			TAILQ_INSERT_BEFORE(t, s, se_entry);
326
		else
327
			TAILQ_INSERT_TAIL(&env->sc_sessions, s, se_entry);
328
		break;
329
	case IMSG_SESS_UNPUBLISH:
330
		IMSG_SIZE_CHECK(imsg, &sid);
331
		memcpy(&sid, imsg->data, sizeof(sid));
332
		TAILQ_FOREACH(s, &env->sc_sessions, se_entry)
333
			if (s->se_id == sid)
334
				break;
335
		if (s) {
336
			TAILQ_REMOVE(&env->sc_sessions, s, se_entry);
337
			free(s);
338
		} else {
339
			DPRINTF("removal of unpublished session %i", sid);
340
		}
341
		break;
342
	default:
343
		return (-1);
344
	}
345
346
	return (0);
347
}
348
349
void
350
show(struct ctl_conn *c)
351
{
352
	struct rdr		*rdr;
353
	struct host		*host;
354
	struct relay		*rlay;
355
	struct router		*rt;
356
	struct netroute		*nr;
357
	struct relay_table	*rlt;
358
359
	if (env->sc_rdrs == NULL)
360
		goto relays;
361
	TAILQ_FOREACH(rdr, env->sc_rdrs, entry) {
362
		imsg_compose_event(&c->iev, IMSG_CTL_RDR, 0, 0, -1,
363
		    rdr, sizeof(*rdr));
364
		if (rdr->conf.flags & F_DISABLE)
365
			continue;
366
367
		imsg_compose_event(&c->iev, IMSG_CTL_RDR_STATS, 0, 0, -1,
368
		    &rdr->stats, sizeof(rdr->stats));
369
370
		imsg_compose_event(&c->iev, IMSG_CTL_TABLE, 0, 0, -1,
371
		    rdr->table, sizeof(*rdr->table));
372
		if (!(rdr->table->conf.flags & F_DISABLE))
373
			TAILQ_FOREACH(host, &rdr->table->hosts, entry)
374
				imsg_compose_event(&c->iev, IMSG_CTL_HOST,
375
				    0, 0, -1, host, sizeof(*host));
376
377
		if (rdr->backup->conf.id == EMPTY_TABLE)
378
			continue;
379
		imsg_compose_event(&c->iev, IMSG_CTL_TABLE, 0, 0, -1,
380
		    rdr->backup, sizeof(*rdr->backup));
381
		if (!(rdr->backup->conf.flags & F_DISABLE))
382
			TAILQ_FOREACH(host, &rdr->backup->hosts, entry)
383
				imsg_compose_event(&c->iev, IMSG_CTL_HOST,
384
				    0, 0, -1, host, sizeof(*host));
385
	}
386
relays:
387
	if (env->sc_relays == NULL)
388
		goto routers;
389
	TAILQ_FOREACH(rlay, env->sc_relays, rl_entry) {
390
		rlay->rl_stats[env->sc_conf.prefork_relay].id = EMPTY_ID;
391
		imsg_compose_event(&c->iev, IMSG_CTL_RELAY, 0, 0, -1,
392
		    rlay, sizeof(*rlay));
393
		imsg_compose_event(&c->iev, IMSG_CTL_RELAY_STATS, 0, 0, -1,
394
		    &rlay->rl_stats, sizeof(rlay->rl_stats));
395
396
		TAILQ_FOREACH(rlt, &rlay->rl_tables, rlt_entry) {
397
			imsg_compose_event(&c->iev, IMSG_CTL_TABLE, 0, 0, -1,
398
			    rlt->rlt_table, sizeof(*rlt->rlt_table));
399
			if (!(rlt->rlt_table->conf.flags & F_DISABLE))
400
				TAILQ_FOREACH(host,
401
				    &rlt->rlt_table->hosts, entry)
402
					imsg_compose_event(&c->iev,
403
					    IMSG_CTL_HOST, 0, 0, -1,
404
					    host, sizeof(*host));
405
		}
406
	}
407
408
routers:
409
	if (env->sc_rts == NULL)
410
		goto end;
411
	TAILQ_FOREACH(rt, env->sc_rts, rt_entry) {
412
		imsg_compose_event(&c->iev, IMSG_CTL_ROUTER, 0, 0, -1,
413
		    rt, sizeof(*rt));
414
		if (rt->rt_conf.flags & F_DISABLE)
415
			continue;
416
417
		TAILQ_FOREACH(nr, &rt->rt_netroutes, nr_entry)
418
			imsg_compose_event(&c->iev, IMSG_CTL_NETROUTE,
419
			    0, 0, -1, nr, sizeof(*nr));
420
		imsg_compose_event(&c->iev, IMSG_CTL_TABLE, 0, 0, -1,
421
		    rt->rt_gwtable, sizeof(*rt->rt_gwtable));
422
		if (!(rt->rt_gwtable->conf.flags & F_DISABLE))
423
			TAILQ_FOREACH(host, &rt->rt_gwtable->hosts, entry)
424
				imsg_compose_event(&c->iev, IMSG_CTL_HOST,
425
				    0, 0, -1, host, sizeof(*host));
426
	}
427
428
end:
429
	imsg_compose_event(&c->iev, IMSG_CTL_END, 0, 0, -1, NULL, 0);
430
}
431
432
void
433
show_sessions(struct ctl_conn *c)
434
{
435
	int			 proc, cid;
436
437
	for (proc = 0; proc < env->sc_conf.prefork_relay; proc++) {
438
		cid = c->iev.ibuf.fd;
439
440
		/*
441
		 * Request all the running sessions from the process
442
		 */
443
		proc_compose_imsg(env->sc_ps, PROC_RELAY, proc,
444
		    IMSG_CTL_SESSION, -1, -1, &cid, sizeof(cid));
445
		c->waiting++;
446
	}
447
}
448
449
int
450
disable_rdr(struct ctl_conn *c, struct ctl_id *id)
451
{
452
	struct rdr	*rdr;
453
454
	if (id->id == EMPTY_ID)
455
		rdr = rdr_findbyname(env, id->name);
456
	else
457
		rdr = rdr_find(env, id->id);
458
	if (rdr == NULL)
459
		return (-1);
460
	id->id = rdr->conf.id;
461
462
	if (rdr->conf.flags & F_DISABLE)
463
		return (0);
464
465
	rdr->conf.flags |= F_DISABLE;
466
	rdr->conf.flags &= ~(F_ADD);
467
	rdr->conf.flags |= F_DEL;
468
	rdr->table->conf.flags |= F_DISABLE;
469
	log_debug("%s: redirect %d", __func__, rdr->conf.id);
470
	pfe_sync();
471
	return (0);
472
}
473
474
int
475
enable_rdr(struct ctl_conn *c, struct ctl_id *id)
476
{
477
	struct rdr	*rdr;
478
	struct ctl_id	 eid;
479
480
	if (id->id == EMPTY_ID)
481
		rdr = rdr_findbyname(env, id->name);
482
	else
483
		rdr = rdr_find(env, id->id);
484
	if (rdr == NULL)
485
		return (-1);
486
	id->id = rdr->conf.id;
487
488
	if (!(rdr->conf.flags & F_DISABLE))
489
		return (0);
490
491
	rdr->conf.flags &= ~(F_DISABLE);
492
	rdr->conf.flags &= ~(F_DEL);
493
	rdr->conf.flags |= F_ADD;
494
	log_debug("%s: redirect %d", __func__, rdr->conf.id);
495
496
	bzero(&eid, sizeof(eid));
497
498
	/* XXX: we're syncing twice */
499
	eid.id = rdr->table->conf.id;
500
	if (enable_table(c, &eid) == -1)
501
		return (-1);
502
	if (rdr->backup->conf.id == EMPTY_ID)
503
		return (0);
504
	eid.id = rdr->backup->conf.id;
505
	if (enable_table(c, &eid) == -1)
506
		return (-1);
507
	return (0);
508
}
509
510
int
511
disable_table(struct ctl_conn *c, struct ctl_id *id)
512
{
513
	struct table	*table;
514
	struct host	*host;
515
516
	if (id->id == EMPTY_ID)
517
		table = table_findbyname(env, id->name);
518
	else
519
		table = table_find(env, id->id);
520
	if (table == NULL)
521
		return (-1);
522
	id->id = table->conf.id;
523
	if (table->conf.rdrid > 0 && rdr_find(env, table->conf.rdrid) == NULL)
524
		fatalx("%s: desynchronised", __func__);
525
526
	if (table->conf.flags & F_DISABLE)
527
		return (0);
528
	table->conf.flags |= (F_DISABLE|F_CHANGED);
529
	table->up = 0;
530
	TAILQ_FOREACH(host, &table->hosts, entry)
531
		host->up = HOST_UNKNOWN;
532
	proc_compose(env->sc_ps, PROC_HCE, IMSG_TABLE_DISABLE,
533
	    &table->conf.id, sizeof(table->conf.id));
534
535
	/* Forward to relay engine(s) */
536
	proc_compose(env->sc_ps, PROC_RELAY, IMSG_TABLE_DISABLE,
537
	    &table->conf.id, sizeof(table->conf.id));
538
539
	log_debug("%s: table %d", __func__, table->conf.id);
540
	pfe_sync();
541
	return (0);
542
}
543
544
int
545
enable_table(struct ctl_conn *c, struct ctl_id *id)
546
{
547
	struct table	*table;
548
	struct host	*host;
549
550
	if (id->id == EMPTY_ID)
551
		table = table_findbyname(env, id->name);
552
	else
553
		table = table_find(env, id->id);
554
	if (table == NULL)
555
		return (-1);
556
	id->id = table->conf.id;
557
558
	if (table->conf.rdrid > 0 && rdr_find(env, table->conf.rdrid) == NULL)
559
		fatalx("%s: desynchronised", __func__);
560
561
	if (!(table->conf.flags & F_DISABLE))
562
		return (0);
563
	table->conf.flags &= ~(F_DISABLE);
564
	table->conf.flags |= F_CHANGED;
565
	table->up = 0;
566
	TAILQ_FOREACH(host, &table->hosts, entry)
567
		host->up = HOST_UNKNOWN;
568
	proc_compose(env->sc_ps, PROC_HCE, IMSG_TABLE_ENABLE,
569
	    &table->conf.id, sizeof(table->conf.id));
570
571
	/* Forward to relay engine(s) */
572
	proc_compose(env->sc_ps, PROC_RELAY, IMSG_TABLE_ENABLE,
573
	    &table->conf.id, sizeof(table->conf.id));
574
575
	log_debug("%s: table %d", __func__, table->conf.id);
576
	pfe_sync();
577
	return (0);
578
}
579
580
int
581
disable_host(struct ctl_conn *c, struct ctl_id *id, struct host *host)
582
{
583
	struct host	*h;
584
	struct table	*table;
585
586
	if (host == NULL) {
587
		if (id->id == EMPTY_ID)
588
			host = host_findbyname(env, id->name);
589
		else
590
			host = host_find(env, id->id);
591
		if (host == NULL || host->conf.parentid)
592
			return (-1);
593
	}
594
	id->id = host->conf.id;
595
596
	if (host->flags & F_DISABLE)
597
		return (0);
598
599
	if (host->up == HOST_UP) {
600
		if ((table = table_find(env, host->conf.tableid)) == NULL)
601
			fatalx("%s: invalid table id", __func__);
602
		table->up--;
603
		table->conf.flags |= F_CHANGED;
604
	}
605
606
	host->up = HOST_UNKNOWN;
607
	host->flags |= F_DISABLE;
608
	host->flags |= F_DEL;
609
	host->flags &= ~(F_ADD);
610
	host->check_cnt = 0;
611
	host->up_cnt = 0;
612
613
	proc_compose(env->sc_ps, PROC_HCE, IMSG_HOST_DISABLE,
614
	    &host->conf.id, sizeof(host->conf.id));
615
616
	/* Forward to relay engine(s) */
617
	proc_compose(env->sc_ps, PROC_RELAY, IMSG_HOST_DISABLE,
618
	    &host->conf.id, sizeof(host->conf.id));
619
	log_debug("%s: host %d", __func__, host->conf.id);
620
621
	if (!host->conf.parentid) {
622
		/* Disable all children */
623
		SLIST_FOREACH(h, &host->children, child)
624
			disable_host(c, id, h);
625
		pfe_sync();
626
	}
627
	return (0);
628
}
629
630
int
631
enable_host(struct ctl_conn *c, struct ctl_id *id, struct host *host)
632
{
633
	struct host	*h;
634
635
	if (host == NULL) {
636
		if (id->id == EMPTY_ID)
637
			host = host_findbyname(env, id->name);
638
		else
639
			host = host_find(env, id->id);
640
		if (host == NULL || host->conf.parentid)
641
			return (-1);
642
	}
643
	id->id = host->conf.id;
644
645
	if (!(host->flags & F_DISABLE))
646
		return (0);
647
648
	host->up = HOST_UNKNOWN;
649
	host->flags &= ~(F_DISABLE);
650
	host->flags &= ~(F_DEL);
651
	host->flags &= ~(F_ADD);
652
653
	proc_compose(env->sc_ps, PROC_HCE, IMSG_HOST_ENABLE,
654
	    &host->conf.id, sizeof (host->conf.id));
655
656
	/* Forward to relay engine(s) */
657
	proc_compose(env->sc_ps, PROC_RELAY, IMSG_HOST_ENABLE,
658
	    &host->conf.id, sizeof(host->conf.id));
659
660
	log_debug("%s: host %d", __func__, host->conf.id);
661
662
	if (!host->conf.parentid) {
663
		/* Enable all children */
664
		SLIST_FOREACH(h, &host->children, child)
665
			enable_host(c, id, h);
666
		pfe_sync();
667
	}
668
	return (0);
669
}
670
671
void
672
pfe_sync(void)
673
{
674
	struct rdr		*rdr;
675
	struct table		*active;
676
	struct table		*table;
677
	struct ctl_id		 id;
678
	struct imsg		 imsg;
679
	struct ctl_demote	 demote;
680
	struct router		*rt;
681
682
	bzero(&id, sizeof(id));
683
	bzero(&imsg, sizeof(imsg));
684
	TAILQ_FOREACH(rdr, env->sc_rdrs, entry) {
685
		rdr->conf.flags &= ~(F_BACKUP);
686
		rdr->conf.flags &= ~(F_DOWN);
687
688
		if (rdr->conf.flags & F_DISABLE ||
689
		    (rdr->table->up == 0 && rdr->backup->up == 0)) {
690
			rdr->conf.flags |= F_DOWN;
691
			active = NULL;
692
		} else if (rdr->table->up == 0 && rdr->backup->up > 0) {
693
			rdr->conf.flags |= F_BACKUP;
694
			active = rdr->backup;
695
			active->conf.flags |=
696
			    rdr->table->conf.flags & F_CHANGED;
697
			active->conf.flags |=
698
			    rdr->backup->conf.flags & F_CHANGED;
699
		} else
700
			active = rdr->table;
701
702
		if (active != NULL && active->conf.flags & F_CHANGED) {
703
			id.id = active->conf.id;
704
			imsg.hdr.type = IMSG_CTL_TABLE_CHANGED;
705
			imsg.hdr.len = sizeof(id) + IMSG_HEADER_SIZE;
706
			imsg.data = &id;
707
			sync_table(env, rdr, active);
708
			control_imsg_forward(env->sc_ps, &imsg);
709
		}
710
711
		if (rdr->conf.flags & F_DOWN) {
712
			if (rdr->conf.flags & F_ACTIVE_RULESET) {
713
				flush_table(env, rdr);
714
				log_debug("%s: disabling ruleset", __func__);
715
				rdr->conf.flags &= ~(F_ACTIVE_RULESET);
716
				id.id = rdr->conf.id;
717
				imsg.hdr.type = IMSG_CTL_PULL_RULESET;
718
				imsg.hdr.len = sizeof(id) + IMSG_HEADER_SIZE;
719
				imsg.data = &id;
720
				sync_ruleset(env, rdr, 0);
721
				control_imsg_forward(env->sc_ps, &imsg);
722
			}
723
		} else if (!(rdr->conf.flags & F_ACTIVE_RULESET)) {
724
			log_debug("%s: enabling ruleset", __func__);
725
			rdr->conf.flags |= F_ACTIVE_RULESET;
726
			id.id = rdr->conf.id;
727
			imsg.hdr.type = IMSG_CTL_PUSH_RULESET;
728
			imsg.hdr.len = sizeof(id) + IMSG_HEADER_SIZE;
729
			imsg.data = &id;
730
			sync_ruleset(env, rdr, 1);
731
			control_imsg_forward(env->sc_ps, &imsg);
732
		}
733
	}
734
735
	TAILQ_FOREACH(rt, env->sc_rts, rt_entry) {
736
		rt->rt_conf.flags &= ~(F_BACKUP);
737
		rt->rt_conf.flags &= ~(F_DOWN);
738
739
		if ((rt->rt_gwtable->conf.flags & F_CHANGED))
740
			sync_routes(env, rt);
741
	}
742
743
	TAILQ_FOREACH(table, env->sc_tables, entry) {
744
		if (table->conf.check == CHECK_NOCHECK)
745
			continue;
746
747
		/*
748
		 * clean up change flag.
749
		 */
750
		table->conf.flags &= ~(F_CHANGED);
751
752
		/*
753
		 * handle demotion.
754
		 */
755
		if ((table->conf.flags & F_DEMOTE) == 0)
756
			continue;
757
		demote.level = 0;
758
		if (table->up && table->conf.flags & F_DEMOTED) {
759
			demote.level = -1;
760
			table->conf.flags &= ~F_DEMOTED;
761
		}
762
		else if (!table->up && !(table->conf.flags & F_DEMOTED)) {
763
			demote.level = 1;
764
			table->conf.flags |= F_DEMOTED;
765
		}
766
		if (demote.level == 0)
767
			continue;
768
		log_debug("%s: demote %d table '%s' group '%s'", __func__,
769
		    demote.level, table->conf.name, table->conf.demote_group);
770
		(void)strlcpy(demote.group, table->conf.demote_group,
771
		    sizeof(demote.group));
772
		proc_compose(env->sc_ps, PROC_PARENT, IMSG_DEMOTE,
773
		    &demote, sizeof(demote));
774
	}
775
}
776
777
void
778
pfe_statistics(int fd, short events, void *arg)
779
{
780
	struct rdr		*rdr;
781
	struct ctl_stats	*cur;
782
	struct timeval		 tv, tv_now;
783
	int			 resethour, resetday;
784
	u_long			 cnt;
785
786
	timerclear(&tv);
787
	getmonotime(&tv_now);
788
789
	TAILQ_FOREACH(rdr, env->sc_rdrs, entry) {
790
		cnt = check_table(env, rdr, rdr->table);
791
		if (rdr->conf.backup_id != EMPTY_TABLE)
792
			cnt += check_table(env, rdr, rdr->backup);
793
794
		resethour = resetday = 0;
795
796
		cur = &rdr->stats;
797
		cur->last = cnt > cur->cnt ? cnt - cur->cnt : 0;
798
799
		cur->cnt = cnt;
800
		cur->tick++;
801
		cur->avg = (cur->last + cur->avg) / 2;
802
		cur->last_hour += cur->last;
803
		if ((cur->tick %
804
		    (3600 / env->sc_conf.statinterval.tv_sec)) == 0) {
805
			cur->avg_hour = (cur->last_hour + cur->avg_hour) / 2;
806
			resethour++;
807
		}
808
		cur->last_day += cur->last;
809
		if ((cur->tick %
810
		    (86400 / env->sc_conf.statinterval.tv_sec)) == 0) {
811
			cur->avg_day = (cur->last_day + cur->avg_day) / 2;
812
			resethour++;
813
		}
814
		if (resethour)
815
			cur->last_hour = 0;
816
		if (resetday)
817
			cur->last_day = 0;
818
819
		rdr->stats.interval = env->sc_conf.statinterval.tv_sec;
820
	}
821
822
	/* Schedule statistics timer */
823
	evtimer_set(&env->sc_statev, pfe_statistics, NULL);
824
	bcopy(&env->sc_conf.statinterval, &tv, sizeof(tv));
825
	evtimer_add(&env->sc_statev, &tv);
826
}