xref: /openbsd-src/usr.sbin/relayd/config.c (revision d13be5d47e4149db2549a9828e244d59dbc43f15)
1 /*	$OpenBSD: config.c,v 1.2 2011/05/19 09:13:07 reyk Exp $	*/
2 
3 /*
4  * Copyright (c) 2011 Reyk Floeter <reyk@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/socket.h>
21 #include <sys/stat.h>
22 #include <sys/queue.h>
23 #include <sys/uio.h>
24 
25 #include <net/if.h>
26 #include <net/pfvar.h>
27 #include <netinet/in.h>
28 #include <arpa/inet.h>
29 #include <arpa/nameser.h>
30 #include <net/route.h>
31 
32 #include <ctype.h>
33 #include <unistd.h>
34 #include <err.h>
35 #include <errno.h>
36 #include <event.h>
37 #include <limits.h>
38 #include <stdint.h>
39 #include <stdarg.h>
40 #include <stdio.h>
41 #include <netdb.h>
42 #include <string.h>
43 #include <ifaddrs.h>
44 
45 #include <openssl/ssl.h>
46 
47 #include "relayd.h"
48 
49 int
50 config_init(struct relayd *env)
51 {
52 	struct privsep	*ps = env->sc_ps;
53 	u_int		 what;
54 
55 	/* Global configuration */
56 	if (privsep_process == PROC_PARENT) {
57 		env->sc_timeout.tv_sec = CHECK_TIMEOUT / 1000;
58 		env->sc_timeout.tv_usec = (CHECK_TIMEOUT % 1000) * 1000;
59 		env->sc_interval.tv_sec = CHECK_INTERVAL;
60 		env->sc_interval.tv_usec = 0;
61 		env->sc_prefork_relay = RELAY_NUMPROC;
62 		env->sc_statinterval.tv_sec = RELAY_STATINTERVAL;
63 
64 		ps->ps_what[PROC_PARENT] = CONFIG_ALL;
65 		ps->ps_what[PROC_PFE] = CONFIG_ALL & ~CONFIG_PROTOS;
66 		ps->ps_what[PROC_HCE] = CONFIG_TABLES;
67 		ps->ps_what[PROC_RELAY] =
68 		    CONFIG_TABLES|CONFIG_RELAYS|CONFIG_PROTOS;
69 	}
70 
71 	/* Other configuration */
72 	what = ps->ps_what[privsep_process];
73 	if (what & CONFIG_TABLES) {
74 		if ((env->sc_tables =
75 		    calloc(1, sizeof(*env->sc_tables))) == NULL)
76 			return (-1);
77 		TAILQ_INIT(env->sc_tables);
78 
79 		memset(&env->sc_empty_table, 0, sizeof(env->sc_empty_table));
80 		env->sc_empty_table.conf.id = EMPTY_TABLE;
81 		env->sc_empty_table.conf.flags |= F_DISABLE;
82 		(void)strlcpy(env->sc_empty_table.conf.name, "empty",
83 		    sizeof(env->sc_empty_table.conf.name));
84 
85 	}
86 	if (what & CONFIG_RDRS) {
87 		if ((env->sc_rdrs =
88 		    calloc(1, sizeof(*env->sc_rdrs))) == NULL)
89 			return (-1);
90 		TAILQ_INIT(env->sc_rdrs);
91 
92 	}
93 	if (what & CONFIG_RELAYS) {
94 		if ((env->sc_relays =
95 		    calloc(1, sizeof(*env->sc_relays))) == NULL)
96 			return (-1);
97 		TAILQ_INIT(env->sc_relays);
98 	}
99 	if (what & CONFIG_PROTOS) {
100 		if ((env->sc_protos =
101 		    calloc(1, sizeof(*env->sc_protos))) == NULL)
102 			return (-1);
103 		TAILQ_INIT(env->sc_protos);
104 
105 		bzero(&env->sc_proto_default, sizeof(env->sc_proto_default));
106 		env->sc_proto_default.id = EMPTY_ID;
107 		env->sc_proto_default.flags = F_USED;
108 		env->sc_proto_default.cache = RELAY_CACHESIZE;
109 		env->sc_proto_default.tcpflags = TCPFLAG_DEFAULT;
110 		env->sc_proto_default.tcpbacklog = RELAY_BACKLOG;
111 		env->sc_proto_default.sslflags = SSLFLAG_DEFAULT;
112 		(void)strlcpy(env->sc_proto_default.sslciphers,
113 		    SSLCIPHERS_DEFAULT,
114 		    sizeof(env->sc_proto_default.sslciphers));
115 		env->sc_proto_default.type = RELAY_PROTO_TCP;
116 		(void)strlcpy(env->sc_proto_default.name, "default",
117 		    sizeof(env->sc_proto_default.name));
118 		RB_INIT(&env->sc_proto_default.request_tree);
119 		RB_INIT(&env->sc_proto_default.response_tree);
120 	}
121 	if (what & CONFIG_RTS) {
122 		if ((env->sc_rts =
123 		    calloc(1, sizeof(*env->sc_rts))) == NULL)
124 			return (-1);
125 		TAILQ_INIT(env->sc_rts);
126 	}
127 	if (what & CONFIG_ROUTES) {
128 		if ((env->sc_routes =
129 		    calloc(1, sizeof(*env->sc_routes))) == NULL)
130 			return (-1);
131 		TAILQ_INIT(env->sc_routes);
132 	}
133 
134 	return (0);
135 }
136 
137 void
138 config_purge(struct relayd *env, u_int reset)
139 {
140 	struct privsep		*ps = env->sc_ps;
141 	struct table		*table;
142 	struct rdr		*rdr;
143 	struct address		*virt;
144 	struct protocol		*proto;
145 	struct relay		*rlay;
146 	struct netroute		*nr;
147 	struct router		*rt;
148 	u_int			 what;
149 
150 	what = ps->ps_what[privsep_process] & reset;
151 
152 	if (what & CONFIG_TABLES && env->sc_tables != NULL) {
153 		while ((table = TAILQ_FIRST(env->sc_tables)) != NULL)
154 			purge_table(env->sc_tables, table);
155 		env->sc_tablecount = 0;
156 	}
157 	if (what & CONFIG_RDRS && env->sc_rdrs != NULL) {
158 		while ((rdr = TAILQ_FIRST(env->sc_rdrs)) != NULL) {
159 			TAILQ_REMOVE(env->sc_rdrs, rdr, entry);
160 			while ((virt = TAILQ_FIRST(&rdr->virts)) != NULL) {
161 				TAILQ_REMOVE(&rdr->virts, virt, entry);
162 				free(virt);
163 			}
164 			free(rdr);
165 		}
166 		env->sc_rdrcount = 0;
167 	}
168 	if (what & CONFIG_RELAYS && env->sc_relays != NULL) {
169 		while ((rlay = TAILQ_FIRST(env->sc_relays)) != NULL)
170 			purge_relay(env, rlay);
171 		env->sc_relaycount = 0;
172 	}
173 	if (what & CONFIG_PROTOS && env->sc_protos != NULL) {
174 		while ((proto = TAILQ_FIRST(env->sc_protos)) != NULL) {
175 			TAILQ_REMOVE(env->sc_protos, proto, entry);
176 			purge_tree(&proto->request_tree);
177 			purge_tree(&proto->response_tree);
178 			if (proto->style != NULL)
179 				free(proto->style);
180 			free(proto);
181 		}
182 		env->sc_protocount = 0;
183 	}
184 	if (what & CONFIG_RTS && env->sc_rts != NULL) {
185 		while ((rt = TAILQ_FIRST(env->sc_rts)) != NULL) {
186 			TAILQ_REMOVE(env->sc_rts, rt, rt_entry);
187 			while ((nr = TAILQ_FIRST(&rt->rt_netroutes)) != NULL) {
188 				TAILQ_REMOVE(&rt->rt_netroutes, nr, nr_entry);
189 				TAILQ_REMOVE(env->sc_routes, nr, nr_route);
190 				free(nr);
191 				env->sc_routecount--;
192 			}
193 			free(rt);
194 		}
195 		env->sc_routercount = 0;
196 	}
197 	if (what & CONFIG_ROUTES && env->sc_routes != NULL) {
198 		while ((nr = TAILQ_FIRST(env->sc_routes)) != NULL) {
199 			if ((rt = nr->nr_router) != NULL)
200 				TAILQ_REMOVE(&rt->rt_netroutes, nr, nr_entry);
201 			TAILQ_REMOVE(env->sc_routes, nr, nr_route);
202 			free(nr);
203 		}
204 		env->sc_routecount = 0;
205 	}
206 }
207 
208 int
209 config_setreset(struct relayd *env, u_int reset)
210 {
211 	struct privsep	*ps = env->sc_ps;
212 	int		 id;
213 
214 	for (id = 0; id < PROC_MAX; id++) {
215 		if ((reset & ps->ps_what[id]) == 0 ||
216 		    id == privsep_process)
217 			continue;
218 		proc_compose_imsg(ps, id, -1, IMSG_CTL_RESET, -1,
219 		    &reset, sizeof(reset));
220 	}
221 
222 	return (0);
223 }
224 
225 int
226 config_getreset(struct relayd *env, struct imsg *imsg)
227 {
228 	u_int		 mode;
229 
230 	IMSG_SIZE_CHECK(imsg, &mode);
231 	memcpy(&mode, imsg->data, sizeof(mode));
232 
233 	config_purge(env, mode);
234 
235 	return (0);
236 }
237 
238 int
239 config_getcfg(struct relayd *env, struct imsg *imsg)
240 {
241 	struct privsep		*ps = env->sc_ps;
242 	struct table		*tb;
243 	struct host		*h, *ph;
244 	struct ctl_flags	 cf;
245 
246 	if (IMSG_DATA_SIZE(imsg) != sizeof(cf))
247 		return (0); /* ignore */
248 
249 	/* Update runtime flags */
250 	memcpy(&cf, imsg->data, sizeof(cf));
251 	env->sc_opts = cf.cf_opts;
252 	env->sc_flags = cf.cf_flags;
253 
254 	if (ps->ps_what[privsep_process] & CONFIG_TABLES) {
255 		/* Update the tables */
256 		TAILQ_FOREACH(tb, env->sc_tables, entry) {
257 			TAILQ_FOREACH(h, &tb->hosts, entry) {
258 				if (h->conf.parentid && (ph = host_find(env,
259 				    h->conf.parentid)) != NULL) {
260 					SLIST_INSERT_HEAD(&ph->children,
261 					    h, child);
262 				}
263 			}
264 		}
265 	}
266 
267 	if (env->sc_flags & (F_SSL|F_SSLCLIENT))
268 		ssl_init(env);
269 
270 	if (privsep_process != PROC_PARENT)
271 		proc_compose_imsg(env->sc_ps, PROC_PARENT, -1,
272 		    IMSG_CFG_DONE, -1, NULL, 0);
273 
274 	return (0);
275 }
276 
277 int
278 config_settable(struct relayd *env, struct table *tb)
279 {
280 	struct privsep	*ps = env->sc_ps;
281 	struct host	*host;
282 	int		 id, c;
283 	struct iovec	 iov[2];
284 
285 	for (id = 0; id < PROC_MAX; id++) {
286 		if ((ps->ps_what[id] & CONFIG_TABLES) == 0 ||
287 		    id == privsep_process)
288 			continue;
289 
290 		/* XXX need to send table to pfe for control socket */
291 		if (id == PROC_HCE && tb->conf.check == CHECK_NOCHECK)
292 			continue;
293 
294 		DPRINTF("%s: sending table %s %d to %s", __func__,
295 		    tb->conf.name, tb->conf.id, env->sc_ps->ps_title[id]);
296 
297 		c = 0;
298 		iov[c].iov_base = &tb->conf;
299 		iov[c++].iov_len = sizeof(tb->conf);
300 		if (tb->sendbuf != NULL) {
301 			iov[c].iov_base = tb->sendbuf;
302 			iov[c++].iov_len = strlen(tb->sendbuf);
303 		}
304 
305 		proc_composev_imsg(ps, id, -1, IMSG_CFG_TABLE, -1, iov, c);
306 
307 		TAILQ_FOREACH(host, &tb->hosts, entry) {
308 			proc_compose_imsg(ps, id, -1, IMSG_CFG_HOST, -1,
309 			    &host->conf, sizeof(host->conf));
310 		}
311 	}
312 
313 	return (0);
314 }
315 
316 int
317 config_gettable(struct relayd *env, struct imsg *imsg)
318 {
319 	struct table		*tb;
320 	size_t			 sb;
321 	u_int8_t		*p = imsg->data;
322 	size_t			 s;
323 
324 	if ((tb = calloc(1, sizeof(*tb))) == NULL)
325 		return (-1);
326 
327 	IMSG_SIZE_CHECK(imsg, &tb->conf);
328 	memcpy(&tb->conf, p, sizeof(tb->conf));
329 	s = sizeof(tb->conf);
330 
331 	sb = IMSG_DATA_SIZE(imsg) - s;
332 	if (sb > 0) {
333 		if ((tb->sendbuf = get_string(p + s, sb)) == NULL) {
334 			free(tb);
335 			return (-1);
336 		}
337 	}
338 
339 	TAILQ_INIT(&tb->hosts);
340 	TAILQ_INSERT_TAIL(env->sc_tables, tb, entry);
341 
342 	env->sc_tablecount++;
343 
344 	DPRINTF("%s: %s %d received table %d (%s)", __func__,
345 	    env->sc_ps->ps_title[privsep_process], env->sc_ps->ps_instance,
346 	    tb->conf.id, tb->conf.name);
347 
348 	return (0);
349 }
350 
351 int
352 config_gethost(struct relayd *env, struct imsg *imsg)
353 {
354 	struct table		*tb;
355 	struct host		*host;
356 
357 	if ((host = calloc(1, sizeof(*host))) == NULL)
358 		return (-1);
359 
360 	IMSG_SIZE_CHECK(imsg, &host->conf);
361 	memcpy(&host->conf, imsg->data, sizeof(host->conf));
362 
363 	if (host_find(env, host->conf.id) != NULL) {
364 		log_debug("%s: host %d already exists",
365 		    __func__, host->conf.id);
366 		free(host);
367 		return (-1);
368 	}
369 
370 	if ((tb = table_find(env, host->conf.tableid)) == NULL) {
371 		log_debug("%s: "
372 		    "received host for unknown table %d", __func__,
373 		    host->conf.tableid);
374 		free(host);
375 		return (-1);
376 	}
377 
378 	host->tablename = tb->conf.name;
379 	host->cte.s = -1;
380 
381 	SLIST_INIT(&host->children);
382 	TAILQ_INSERT_TAIL(&tb->hosts, host, entry);
383 
384 	DPRINTF("%s: %s %d received host %s for table %s", __func__,
385 	    env->sc_ps->ps_title[privsep_process], env->sc_ps->ps_instance,
386 	    host->conf.name, tb->conf.name);
387 
388 	return (0);
389 }
390 
391 int
392 config_setrdr(struct relayd *env, struct rdr *rdr)
393 {
394 	struct privsep	*ps = env->sc_ps;
395 	struct address	*virt;
396 	int		 id;
397 
398 	for (id = 0; id < PROC_MAX; id++) {
399 		if ((ps->ps_what[id] & CONFIG_RDRS) == 0 ||
400 		    id == privsep_process)
401 			continue;
402 
403 		DPRINTF("%s: sending rdr %s to %s", __func__,
404 		    rdr->conf.name, ps->ps_title[id]);
405 
406 		proc_compose_imsg(ps, id, -1, IMSG_CFG_RDR, -1,
407 		    &rdr->conf, sizeof(rdr->conf));
408 
409 		TAILQ_FOREACH(virt, &rdr->virts, entry) {
410 			virt->rdrid = rdr->conf.id;
411 			proc_compose_imsg(ps, id, -1, IMSG_CFG_VIRT, -1,
412 			    virt, sizeof(*virt));
413 		}
414 	}
415 
416 	return (0);
417 }
418 
419 int
420 config_getrdr(struct relayd *env, struct imsg *imsg)
421 {
422 	struct rdr		*rdr;
423 
424 	if ((rdr = calloc(1, sizeof(*rdr))) == NULL)
425 		return (-1);
426 
427 	IMSG_SIZE_CHECK(imsg, &rdr->conf);
428 	memcpy(&rdr->conf, imsg->data, sizeof(rdr->conf));
429 
430 	if ((rdr->table = table_find(env, rdr->conf.table_id)) == NULL) {
431 		log_debug("%s: table not found", __func__);
432 		free(rdr);
433 		return (-1);
434 	}
435 	if ((rdr->backup = table_find(env, rdr->conf.backup_id)) == NULL) {
436 		rdr->conf.backup_id = EMPTY_TABLE;
437 		rdr->backup = &env->sc_empty_table;
438 	}
439 
440 	TAILQ_INIT(&rdr->virts);
441 	TAILQ_INSERT_TAIL(env->sc_rdrs, rdr, entry);
442 
443 	env->sc_rdrcount++;
444 
445 	DPRINTF("%s: %s %d received rdr %s", __func__,
446 	    env->sc_ps->ps_title[privsep_process], env->sc_ps->ps_instance,
447 	    rdr->conf.name);
448 
449 	return (0);
450 }
451 
452 int
453 config_getvirt(struct relayd *env, struct imsg *imsg)
454 {
455 	struct rdr	*rdr;
456 	struct address	*virt;
457 
458 	IMSG_SIZE_CHECK(imsg, virt);
459 
460 	if ((virt = calloc(1, sizeof(*virt))) == NULL)
461 		return (-1);
462 	memcpy(virt, imsg->data, sizeof(*virt));
463 
464 	if ((rdr = rdr_find(env, virt->rdrid)) == NULL) {
465 		log_debug("%s: rdr not found", __func__);
466 		free(virt);
467 		return (-1);
468 	}
469 
470 	TAILQ_INSERT_TAIL(&rdr->virts, virt, entry);
471 
472 	DPRINTF("%s: %s %d received address for rdr %s", __func__,
473 	    env->sc_ps->ps_title[privsep_process], env->sc_ps->ps_instance,
474 	    rdr->conf.name);
475 
476 	return (0);
477 }
478 
479 int
480 config_setrt(struct relayd *env, struct router *rt)
481 {
482 	struct privsep	*ps = env->sc_ps;
483 	struct netroute	*nr;
484 	int		 id;
485 
486 	for (id = 0; id < PROC_MAX; id++) {
487 		if ((ps->ps_what[id] & CONFIG_RTS) == 0 ||
488 		    id == privsep_process)
489 			continue;
490 
491 		DPRINTF("%s: sending router %s to %s tbl %d", __func__,
492 		    rt->rt_conf.name, ps->ps_title[id], rt->rt_conf.gwtable);
493 
494 		proc_compose_imsg(ps, id, -1, IMSG_CFG_ROUTER, -1,
495 		    &rt->rt_conf, sizeof(rt->rt_conf));
496 
497 		TAILQ_FOREACH(nr, &rt->rt_netroutes, nr_entry) {
498 			proc_compose_imsg(ps, id, -1, IMSG_CFG_ROUTE, -1,
499 			    &nr->nr_conf, sizeof(nr->nr_conf));
500 		}
501 	}
502 
503 	return (0);
504 }
505 
506 int
507 config_getrt(struct relayd *env, struct imsg *imsg)
508 {
509 	struct router		*rt;
510 
511 	if ((rt = calloc(1, sizeof(*rt))) == NULL)
512 		return (-1);
513 
514 	IMSG_SIZE_CHECK(imsg, &rt->rt_conf);
515 	memcpy(&rt->rt_conf, imsg->data, sizeof(rt->rt_conf));
516 
517 	if ((rt->rt_gwtable = table_find(env, rt->rt_conf.gwtable)) == NULL) {
518 		log_debug("%s: table not found", __func__);
519 		free(rt);
520 		return (-1);
521 	}
522 
523 	TAILQ_INIT(&rt->rt_netroutes);
524 	TAILQ_INSERT_TAIL(env->sc_rts, rt, rt_entry);
525 
526 	env->sc_routercount++;
527 
528 	DPRINTF("%s: %s %d received router %s", __func__,
529 	    env->sc_ps->ps_title[privsep_process], env->sc_ps->ps_instance,
530 	    rt->rt_conf.name);
531 
532 	return (0);
533 }
534 
535 int
536 config_getroute(struct relayd *env, struct imsg *imsg)
537 {
538 	struct router		*rt;
539 	struct netroute		*nr;
540 
541 	if ((nr = calloc(1, sizeof(*nr))) == NULL)
542 		return (-1);
543 
544 	IMSG_SIZE_CHECK(imsg, &nr->nr_conf);
545 	memcpy(&nr->nr_conf, imsg->data, sizeof(nr->nr_conf));
546 
547 	if (route_find(env, nr->nr_conf.id) != NULL) {
548 		log_debug("%s: route %d already exists",
549 		    __func__, nr->nr_conf.id);
550 		free(nr);
551 		return (-1);
552 	}
553 
554 	if ((rt = router_find(env, nr->nr_conf.routerid)) == NULL) {
555 		log_debug("%s: received route for unknown router", __func__);
556 		free(nr);
557 		return (-1);
558 	}
559 
560 	nr->nr_router = rt;
561 
562 	TAILQ_INSERT_TAIL(env->sc_routes, nr, nr_route);
563 	TAILQ_INSERT_TAIL(&rt->rt_netroutes, nr, nr_entry);
564 
565 	env->sc_routecount++;
566 
567 	DPRINTF("%s: %s %d received route %d for router %s", __func__,
568 	    env->sc_ps->ps_title[privsep_process], env->sc_ps->ps_instance,
569 	    nr->nr_conf.id, rt->rt_conf.name);
570 
571 	return (0);
572 }
573 
574 int
575 config_setproto(struct relayd *env, struct protocol *proto)
576 {
577 	struct privsep		*ps = env->sc_ps;
578 	int			 id;
579 	struct iovec		 iov[2];
580 	size_t			 c;
581 
582 	for (id = 0; id < PROC_MAX; id++) {
583 		if ((ps->ps_what[id] & CONFIG_PROTOS) == 0 ||
584 		    id == privsep_process)
585 			continue;
586 
587 		DPRINTF("%s: sending protocol %s to %s", __func__,
588 		    proto->name, ps->ps_title[id]);
589 
590 		c = 0;
591 		iov[c].iov_base = proto;
592 		iov[c++].iov_len = sizeof(*proto);
593 
594 		if (proto->style != NULL) {
595 			iov[c].iov_base = proto->style;
596 			iov[c++].iov_len = strlen(proto->style);
597 		}
598 
599 		/* XXX struct protocol should be split */
600 		proc_composev_imsg(ps, id, -1, IMSG_CFG_PROTO, -1, iov, c);
601 
602 		/* Now send all the protocol key/value nodes */
603 		if (config_setprotonode(env, id, proto,
604 		    RELAY_DIR_REQUEST) == -1 ||
605 		    config_setprotonode(env, id, proto,
606 		    RELAY_DIR_RESPONSE) == -1)
607 			return (-1);
608 	}
609 
610 	return (0);
611 }
612 
613 int
614 config_getproto(struct relayd *env, struct imsg *imsg)
615 {
616 	struct protocol		*proto;
617 	size_t			 styl;
618 	size_t			 s;
619 	u_int8_t		*p = imsg->data;
620 
621 	if ((proto = calloc(1, sizeof(*proto))) == NULL)
622 		return (-1);
623 
624 	IMSG_SIZE_CHECK(imsg, proto);
625 	memcpy(proto, p, sizeof(*proto));
626 	s = sizeof(*proto);
627 
628 	styl = IMSG_DATA_SIZE(imsg) - s;
629 	if (styl > 0) {
630 		if ((proto->style = get_string(p + s, styl)) == NULL) {
631 			free(proto);
632 			return (-1);
633 		}
634 	}
635 
636 	proto->request_nodes = 0;
637 	proto->response_nodes = 0;
638 	RB_INIT(&proto->request_tree);
639 	RB_INIT(&proto->response_tree);
640 
641 	TAILQ_INSERT_TAIL(env->sc_protos, proto, entry);
642 
643 	env->sc_protocount++;
644 
645 	DPRINTF("%s: %s %d received protocol %s", __func__,
646 	    env->sc_ps->ps_title[privsep_process], env->sc_ps->ps_instance,
647 	    proto->name);
648 
649 	return (0);
650 }
651 
652 int
653 config_setprotonode(struct relayd *env, enum privsep_procid id,
654     struct protocol *proto, enum direction dir)
655 {
656 	struct privsep		*ps = env->sc_ps;
657 	struct iovec		 iov[IOV_MAX];
658 	size_t			 c, sz;
659 	struct protonode	*proot, *pn;
660 	struct proto_tree	*tree;
661 
662 	if (dir == RELAY_DIR_RESPONSE)
663 		tree = &proto->response_tree;
664 	else
665 		tree = &proto->request_tree;
666 
667 	sz = c = 0;
668 	RB_FOREACH(proot, proto_tree, tree) {
669 		PROTONODE_FOREACH(pn, proot, entry) {
670 			pn->conf.protoid = proto->id;
671 			pn->conf.dir = dir;
672 			pn->conf.keylen = pn->key ? strlen(pn->key) : 0;
673 			pn->conf.valuelen = pn->value ? strlen(pn->value) : 0;
674 			pn->conf.len = sizeof(*pn) +
675 			    pn->conf.keylen + pn->conf.valuelen;
676 
677 			if (pn->conf.len > (MAX_IMSGSIZE - IMSG_HEADER_SIZE))
678 				return (-1);
679 
680 			if (c && ((c + 3) >= IOV_MAX || (sz + pn->conf.len) >
681 			    (MAX_IMSGSIZE - IMSG_HEADER_SIZE))) {
682 				proc_composev_imsg(ps, id, -1,
683 				    IMSG_CFG_PROTONODE, -1, iov, c);
684 				c = sz = 0;
685 			}
686 
687 			iov[c].iov_base = pn;
688 			iov[c++].iov_len = sizeof(*pn);
689 			if (pn->conf.keylen) {
690 				iov[c].iov_base = pn->key;
691 				iov[c++].iov_len = pn->conf.keylen;
692 			}
693 			if (pn->conf.valuelen) {
694 				iov[c].iov_base = pn->value;
695 				iov[c++].iov_len = pn->conf.valuelen;
696 			}
697 			sz += pn->conf.len;
698 		}
699 	}
700 
701 	if (c && sz)
702 		proc_composev_imsg(ps, id, -1, IMSG_CFG_PROTONODE, -1, iov, c);
703 
704 	return (0);
705 }
706 
707 int
708 config_getprotonode(struct relayd *env, struct imsg *imsg)
709 {
710 	struct protocol		*proto = NULL;
711 	struct protonode	 pn;
712 	size_t			 z, s, c = 0;
713 	u_int8_t		*p = imsg->data;
714 
715 	bzero(&pn, sizeof(pn));
716 
717 	IMSG_SIZE_CHECK(imsg, &pn);
718 	for (z = 0; z < (IMSG_DATA_SIZE(imsg) - sizeof(pn)); z += pn.conf.len) {
719 		s = z;
720 		memcpy(&pn, p + s, sizeof(pn));
721 		s += sizeof(pn);
722 
723 		if ((proto = proto_find(env, pn.conf.protoid)) == NULL) {
724 			log_debug("%s: unknown protocol %d", __func__,
725 			    pn.conf.protoid);
726 			return (-1);
727 		}
728 
729 		pn.key = pn.value = NULL;
730 		bzero(&pn.entry, sizeof(pn.entry));
731 		bzero(&pn.nodes, sizeof(pn.nodes));
732 		bzero(&pn.head, sizeof(pn.head));
733 
734 		if (pn.conf.keylen) {
735 			if ((pn.key = get_string(p + s,
736 			    pn.conf.keylen)) == NULL) {
737 				log_debug("%s: failed to get key", __func__);
738 				return (-1);
739 			}
740 			s += pn.conf.keylen;
741 		}
742 		if (pn.conf.valuelen) {
743 			if ((pn.value = get_string(p + s,
744 			    pn.conf.valuelen)) == NULL) {
745 				log_debug("%s: failed to get value", __func__);
746 				if (pn.key != NULL)
747 					free(pn.key);
748 				return (-1);
749 			}
750 			s += pn.conf.valuelen;
751 		}
752 
753 		if (protonode_add(pn.conf.dir, proto, &pn) == -1) {
754 			if (pn.key != NULL)
755 				free(pn.key);
756 			if (pn.value != NULL)
757 				free(pn.value);
758 			log_debug("%s: failed to add protocol node", __func__);
759 			return (-1);
760 		}
761 		c++;
762 	}
763 
764 	if (!c)
765 		return (0);
766 
767 	DPRINTF("%s: %s %d received %d nodes for protocol %s", __func__,
768 	    env->sc_ps->ps_title[privsep_process], env->sc_ps->ps_instance,
769 	    c, proto->name);
770 
771 	return (0);
772 }
773 
774 int
775 config_setrelay(struct relayd *env, struct relay *rlay)
776 {
777 	struct privsep	*ps = env->sc_ps;
778 	int		 id;
779 	int		 fd, n, m;
780 	struct iovec	 iov[4];
781 	size_t		 c;
782 
783 	/* opens listening sockets etc. */
784 	if (relay_privinit(rlay) == -1)
785 		return (-1);
786 
787 	for (id = 0; id < PROC_MAX; id++) {
788 		if ((ps->ps_what[id] & CONFIG_RELAYS) == 0 ||
789 		    id == privsep_process)
790 			continue;
791 
792 		DPRINTF("%s: sending relay %s to %s fd %d", __func__,
793 		    rlay->rl_conf.name, ps->ps_title[id], rlay->rl_s);
794 
795 		c = 0;
796 		iov[c].iov_base = &rlay->rl_conf;
797 		iov[c++].iov_len = sizeof(rlay->rl_conf);
798 		if (rlay->rl_conf.ssl_cert_len) {
799 			iov[c].iov_base = rlay->rl_ssl_cert;
800 			iov[c++].iov_len = rlay->rl_conf.ssl_cert_len;
801 		}
802 		if (rlay->rl_conf.ssl_key_len) {
803 			iov[c].iov_base = rlay->rl_ssl_key;
804 			iov[c++].iov_len = rlay->rl_conf.ssl_key_len;
805 		}
806 		if (rlay->rl_conf.ssl_ca_len) {
807 			iov[c].iov_base = rlay->rl_ssl_ca;
808 			iov[c++].iov_len = rlay->rl_conf.ssl_ca_len;
809 		}
810 
811 		if (id == PROC_RELAY) {
812 			/* XXX imsg code will close the fd after 1st call */
813 			n = -1;
814 			proc_range(ps, id, &n, &m);
815 			for (n = 0; n < m; n++) {
816 				if ((fd = dup(rlay->rl_s)) == -1)
817 					return (-1);
818 				proc_composev_imsg(ps, id, n,
819 				    IMSG_CFG_RELAY, fd, iov, c);
820 			}
821 		} else {
822 			proc_composev_imsg(ps, id, -1, IMSG_CFG_RELAY, -1,
823 			    iov, c);
824 		}
825 	}
826 
827 	close(rlay->rl_s);
828 	rlay->rl_s = -1;
829 
830 	return (0);
831 }
832 
833 int
834 config_getrelay(struct relayd *env, struct imsg *imsg)
835 {
836 	struct privsep		*ps = env->sc_ps;
837 	struct relay		*rlay;
838 	u_int8_t		*p = imsg->data;
839 	size_t			 s;
840 
841 	if ((rlay = calloc(1, sizeof(*rlay))) == NULL)
842 		return (-1);
843 
844 	IMSG_SIZE_CHECK(imsg, &rlay->rl_conf);
845 	memcpy(&rlay->rl_conf, p, sizeof(rlay->rl_conf));
846 	s = sizeof(rlay->rl_conf);
847 
848 	rlay->rl_s = imsg->fd;
849 
850 	if (ps->ps_what[privsep_process] & CONFIG_PROTOS) {
851 		if (rlay->rl_conf.proto == EMPTY_ID)
852 			rlay->rl_proto = &env->sc_proto_default;
853 		else if ((rlay->rl_proto =
854 		    proto_find(env, rlay->rl_conf.proto)) == NULL) {
855 			log_debug("%s: unknown protocol", __func__);
856 			goto fail;
857 		}
858 	}
859 
860 	if (rlay->rl_conf.dsttable != EMPTY_ID &&
861 	    (rlay->rl_dsttable = table_find(env,
862 	    rlay->rl_conf.dsttable)) == NULL) {
863 		log_debug("%s: unknown table", __func__);
864 		goto fail;
865 	}
866 
867 	rlay->rl_backuptable = &env->sc_empty_table;
868 	if (rlay->rl_conf.backuptable != EMPTY_ID &&
869 	    (rlay->rl_backuptable = table_find(env,
870 	    rlay->rl_conf.backuptable)) == NULL) {
871 		log_debug("%s: unknown backup table", __func__);
872 		goto fail;
873 	}
874 
875 	if ((u_int)(IMSG_DATA_SIZE(imsg) - s) <
876 	    (rlay->rl_conf.ssl_cert_len +
877 	    rlay->rl_conf.ssl_key_len +
878 	    rlay->rl_conf.ssl_ca_len)) {
879 		log_debug("%s: invalid message length", __func__);
880 		goto fail;
881 	}
882 
883 	if (rlay->rl_conf.ssl_cert_len) {
884 		if ((rlay->rl_ssl_cert = get_data(p + s,
885 		    rlay->rl_conf.ssl_cert_len)) == NULL)
886 			goto fail;
887 		s += rlay->rl_conf.ssl_cert_len;
888 	}
889 	if (rlay->rl_conf.ssl_key_len) {
890 		if ((rlay->rl_ssl_key = get_data(p + s,
891 		    rlay->rl_conf.ssl_key_len)) == NULL)
892 			goto fail;
893 		s += rlay->rl_conf.ssl_key_len;
894 	}
895 	if (rlay->rl_conf.ssl_ca_len) {
896 		if ((rlay->rl_ssl_ca = get_data(p + s,
897 		    rlay->rl_conf.ssl_ca_len)) == NULL)
898 			goto fail;
899 		s += rlay->rl_conf.ssl_ca_len;
900 	}
901 
902 	TAILQ_INSERT_TAIL(env->sc_relays, rlay, rl_entry);
903 
904 	env->sc_relaycount++;
905 
906 	DPRINTF("%s: %s %d received relay %s", __func__,
907 	    ps->ps_title[privsep_process], ps->ps_instance,
908 	    rlay->rl_conf.name);
909 
910 	return (0);
911 
912  fail:
913 	if (rlay->rl_ssl_cert)
914 		free(rlay->rl_ssl_cert);
915 	if (rlay->rl_ssl_key)
916 		free(rlay->rl_ssl_key);
917 	if (rlay->rl_ssl_ca)
918 		free(rlay->rl_ssl_ca);
919 	close(rlay->rl_s);
920 	free(rlay);
921 	return (-1);
922 }
923