xref: /openbsd-src/usr.sbin/relayd/config.c (revision f4d4619418045870d88b8c2bca7fe56f3381dbcb)
1*f4d46194Sclaudio /*	$OpenBSD: config.c,v 1.47 2024/10/31 13:37:44 claudio Exp $	*/
2a2195becSreyk 
3a2195becSreyk /*
43d77879fSreyk  * Copyright (c) 2011 - 2014 Reyk Floeter <reyk@openbsd.org>
5a2195becSreyk  *
6a2195becSreyk  * Permission to use, copy, modify, and distribute this software for any
7a2195becSreyk  * purpose with or without fee is hereby granted, provided that the above
8a2195becSreyk  * copyright notice and this permission notice appear in all copies.
9a2195becSreyk  *
10a2195becSreyk  * THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES
11a2195becSreyk  * WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF
12a2195becSreyk  * MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR
13a2195becSreyk  * ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES
14a2195becSreyk  * WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN
15a2195becSreyk  * ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF
16a2195becSreyk  * OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
17a2195becSreyk  */
18a2195becSreyk 
19a2195becSreyk #include <sys/types.h>
20a2195becSreyk #include <sys/queue.h>
21f04ff968Sreyk #include <sys/time.h>
22a2195becSreyk #include <sys/uio.h>
23a2195becSreyk 
24a2195becSreyk #include <stdio.h>
25f04ff968Sreyk #include <stdlib.h>
26f04ff968Sreyk #include <unistd.h>
27f04ff968Sreyk #include <limits.h>
28a2195becSreyk #include <string.h>
29f04ff968Sreyk #include <imsg.h>
30a2195becSreyk 
31a2195becSreyk #include "relayd.h"
32a2195becSreyk 
33a2195becSreyk int
34a2195becSreyk config_init(struct relayd *env)
35a2195becSreyk {
36a2195becSreyk 	struct privsep	*ps = env->sc_ps;
37a2195becSreyk 	u_int		 what;
38a2195becSreyk 
39a2195becSreyk 	/* Global configuration */
40a2195becSreyk 	if (privsep_process == PROC_PARENT) {
41586b5f8aSreyk 		env->sc_conf.timeout.tv_sec = CHECK_TIMEOUT / 1000;
42586b5f8aSreyk 		env->sc_conf.timeout.tv_usec = (CHECK_TIMEOUT % 1000) * 1000;
43586b5f8aSreyk 		env->sc_conf.interval.tv_sec = CHECK_INTERVAL;
44586b5f8aSreyk 		env->sc_conf.interval.tv_usec = 0;
45586b5f8aSreyk 		env->sc_conf.prefork_relay = RELAY_NUMPROC;
46586b5f8aSreyk 		env->sc_conf.statinterval.tv_sec = RELAY_STATINTERVAL;
47ec4c1254Sbenno 		env->sc_ps->ps_csock.cs_name = RELAYD_SOCKET;
48052f96e2Sreyk 	}
49a2195becSreyk 
50a2195becSreyk 	ps->ps_what[PROC_PARENT] = CONFIG_ALL;
51114ce177Sclaudio 	ps->ps_what[PROC_PFE] = CONFIG_ALL & ~(CONFIG_PROTOS|CONFIG_CERTS);
52a2195becSreyk 	ps->ps_what[PROC_HCE] = CONFIG_TABLES;
53114ce177Sclaudio 	ps->ps_what[PROC_CA] = CONFIG_RELAYS|CONFIG_CERTS;
54114ce177Sclaudio 	ps->ps_what[PROC_RELAY] = CONFIG_RELAYS|CONFIG_CERTS|
553d77879fSreyk 	    CONFIG_TABLES|CONFIG_PROTOS|CONFIG_CA_ENGINE;
56a2195becSreyk 
57a2195becSreyk 	/* Other configuration */
58a2195becSreyk 	what = ps->ps_what[privsep_process];
59a2195becSreyk 	if (what & CONFIG_TABLES) {
60a2195becSreyk 		if ((env->sc_tables =
61a2195becSreyk 		    calloc(1, sizeof(*env->sc_tables))) == NULL)
62a2195becSreyk 			return (-1);
63a2195becSreyk 		TAILQ_INIT(env->sc_tables);
64a2195becSreyk 
65a2195becSreyk 		memset(&env->sc_empty_table, 0, sizeof(env->sc_empty_table));
66a2195becSreyk 		env->sc_empty_table.conf.id = EMPTY_TABLE;
67a2195becSreyk 		env->sc_empty_table.conf.flags |= F_DISABLE;
68a2195becSreyk 		(void)strlcpy(env->sc_empty_table.conf.name, "empty",
69a2195becSreyk 		    sizeof(env->sc_empty_table.conf.name));
70a2195becSreyk 
71a2195becSreyk 	}
72a2195becSreyk 	if (what & CONFIG_RDRS) {
73a2195becSreyk 		if ((env->sc_rdrs =
74a2195becSreyk 		    calloc(1, sizeof(*env->sc_rdrs))) == NULL)
75a2195becSreyk 			return (-1);
76a2195becSreyk 		TAILQ_INIT(env->sc_rdrs);
77a2195becSreyk 
78a2195becSreyk 	}
79a2195becSreyk 	if (what & CONFIG_RELAYS) {
80a2195becSreyk 		if ((env->sc_relays =
81a2195becSreyk 		    calloc(1, sizeof(*env->sc_relays))) == NULL)
82a2195becSreyk 			return (-1);
83a2195becSreyk 		TAILQ_INIT(env->sc_relays);
84f2f4e153Sreyk 
85f2f4e153Sreyk 		if ((env->sc_certs =
86f2f4e153Sreyk 		    calloc(1, sizeof(*env->sc_certs))) == NULL)
87f2f4e153Sreyk 			return (-1);
88f2f4e153Sreyk 		TAILQ_INIT(env->sc_certs);
89f2f4e153Sreyk 
9000ae3104Sreyk 		if ((env->sc_pkeys =
9100ae3104Sreyk 		    calloc(1, sizeof(*env->sc_pkeys))) == NULL)
9200ae3104Sreyk 			return (-1);
9300ae3104Sreyk 		TAILQ_INIT(env->sc_pkeys);
94a2195becSreyk 	}
95a2195becSreyk 	if (what & CONFIG_PROTOS) {
96a2195becSreyk 		if ((env->sc_protos =
97a2195becSreyk 		    calloc(1, sizeof(*env->sc_protos))) == NULL)
98a2195becSreyk 			return (-1);
99a2195becSreyk 		TAILQ_INIT(env->sc_protos);
100a2195becSreyk 
101a2195becSreyk 		bzero(&env->sc_proto_default, sizeof(env->sc_proto_default));
102a2195becSreyk 		env->sc_proto_default.id = EMPTY_ID;
103a2195becSreyk 		env->sc_proto_default.flags = F_USED;
104a2195becSreyk 		env->sc_proto_default.tcpflags = TCPFLAG_DEFAULT;
105a2195becSreyk 		env->sc_proto_default.tcpbacklog = RELAY_BACKLOG;
1067bb52228Sreyk 		env->sc_proto_default.tlsflags = TLSFLAG_DEFAULT;
1073ca2f577Sreyk 		TAILQ_INIT(&env->sc_proto_default.tlscerts);
1087bb52228Sreyk 		(void)strlcpy(env->sc_proto_default.tlsciphers,
1097bb52228Sreyk 		    TLSCIPHERS_DEFAULT,
1107bb52228Sreyk 		    sizeof(env->sc_proto_default.tlsciphers));
111353c00bcSclaudio 		(void)strlcpy(env->sc_proto_default.tlsecdhecurves,
112353c00bcSclaudio 		    TLSECDHECURVES_DEFAULT,
113353c00bcSclaudio 		    sizeof(env->sc_proto_default.tlsecdhecurves));
11485e5f500Sclaudio 		(void)strlcpy(env->sc_proto_default.tlsdhparams,
11585e5f500Sclaudio 		    TLSDHPARAM_DEFAULT,
11685e5f500Sclaudio 		    sizeof(env->sc_proto_default.tlsdhparams));
117a2195becSreyk 		env->sc_proto_default.type = RELAY_PROTO_TCP;
118a2195becSreyk 		(void)strlcpy(env->sc_proto_default.name, "default",
119a2195becSreyk 		    sizeof(env->sc_proto_default.name));
120a2195becSreyk 	}
121a2195becSreyk 	if (what & CONFIG_RTS) {
122a2195becSreyk 		if ((env->sc_rts =
123a2195becSreyk 		    calloc(1, sizeof(*env->sc_rts))) == NULL)
124a2195becSreyk 			return (-1);
125a2195becSreyk 		TAILQ_INIT(env->sc_rts);
126a2195becSreyk 	}
127a2195becSreyk 	if (what & CONFIG_ROUTES) {
128a2195becSreyk 		if ((env->sc_routes =
129a2195becSreyk 		    calloc(1, sizeof(*env->sc_routes))) == NULL)
130a2195becSreyk 			return (-1);
131a2195becSreyk 		TAILQ_INIT(env->sc_routes);
132a2195becSreyk 	}
133a2195becSreyk 
134a2195becSreyk 	return (0);
135a2195becSreyk }
136a2195becSreyk 
137a2195becSreyk void
138a2195becSreyk config_purge(struct relayd *env, u_int reset)
139a2195becSreyk {
140a2195becSreyk 	struct privsep		*ps = env->sc_ps;
141a2195becSreyk 	struct table		*table;
142a2195becSreyk 	struct rdr		*rdr;
143a2195becSreyk 	struct address		*virt;
144a2195becSreyk 	struct protocol		*proto;
145cb8b0e56Sreyk 	struct relay_rule	*rule;
146a2195becSreyk 	struct relay		*rlay;
147a2195becSreyk 	struct netroute		*nr;
148a2195becSreyk 	struct router		*rt;
14900ae3104Sreyk 	struct ca_pkey		*pkey;
1503ca2f577Sreyk 	struct keyname		*keyname;
151a2195becSreyk 	u_int			 what;
152a2195becSreyk 
153a2195becSreyk 	what = ps->ps_what[privsep_process] & reset;
154a2195becSreyk 
155a2195becSreyk 	if (what & CONFIG_TABLES && env->sc_tables != NULL) {
156a2195becSreyk 		while ((table = TAILQ_FIRST(env->sc_tables)) != NULL)
1572c8c2287Sclaudio 			purge_table(env, env->sc_tables, table);
158a2195becSreyk 		env->sc_tablecount = 0;
159a2195becSreyk 	}
160a2195becSreyk 	if (what & CONFIG_RDRS && env->sc_rdrs != NULL) {
161a2195becSreyk 		while ((rdr = TAILQ_FIRST(env->sc_rdrs)) != NULL) {
162a2195becSreyk 			TAILQ_REMOVE(env->sc_rdrs, rdr, entry);
163a2195becSreyk 			while ((virt = TAILQ_FIRST(&rdr->virts)) != NULL) {
164a2195becSreyk 				TAILQ_REMOVE(&rdr->virts, virt, entry);
165a2195becSreyk 				free(virt);
166a2195becSreyk 			}
167a2195becSreyk 			free(rdr);
168a2195becSreyk 		}
169a2195becSreyk 		env->sc_rdrcount = 0;
170a2195becSreyk 	}
17100ae3104Sreyk 	if (what & CONFIG_RELAYS && env->sc_pkeys != NULL) {
17200ae3104Sreyk 		while ((pkey = TAILQ_FIRST(env->sc_pkeys)) != NULL) {
17300ae3104Sreyk 			TAILQ_REMOVE(env->sc_pkeys, pkey, pkey_entry);
17400ae3104Sreyk 			free(pkey);
17500ae3104Sreyk 		}
17600ae3104Sreyk 	}
177a2195becSreyk 	if (what & CONFIG_RELAYS && env->sc_relays != NULL) {
178a2195becSreyk 		while ((rlay = TAILQ_FIRST(env->sc_relays)) != NULL)
179a2195becSreyk 			purge_relay(env, rlay);
180a2195becSreyk 		env->sc_relaycount = 0;
181a2195becSreyk 	}
182a2195becSreyk 	if (what & CONFIG_PROTOS && env->sc_protos != NULL) {
183a2195becSreyk 		while ((proto = TAILQ_FIRST(env->sc_protos)) != NULL) {
184a2195becSreyk 			TAILQ_REMOVE(env->sc_protos, proto, entry);
185cb8b0e56Sreyk 			while ((rule = TAILQ_FIRST(&proto->rules)) != NULL)
186cb8b0e56Sreyk 				rule_delete(&proto->rules, rule);
187cb8b0e56Sreyk 			proto->rulecount = 0;
188cb8b0e56Sreyk 		}
189cb8b0e56Sreyk 	}
190cb8b0e56Sreyk 	if (what & CONFIG_PROTOS && env->sc_protos != NULL) {
191cb8b0e56Sreyk 		while ((proto = TAILQ_FIRST(env->sc_protos)) != NULL) {
192cb8b0e56Sreyk 			TAILQ_REMOVE(env->sc_protos, proto, entry);
193a2195becSreyk 			free(proto->style);
1947bb52228Sreyk 			free(proto->tlscapass);
1953ca2f577Sreyk 			while ((keyname =
1963ca2f577Sreyk 			    TAILQ_FIRST(&proto->tlscerts)) != NULL) {
1973ca2f577Sreyk 				TAILQ_REMOVE(&proto->tlscerts, keyname, entry);
1983ca2f577Sreyk 				free(keyname->name);
1993ca2f577Sreyk 				free(keyname);
2003ca2f577Sreyk 			}
20151ff6749Sjsg 			free(proto);
202a2195becSreyk 		}
203a2195becSreyk 		env->sc_protocount = 0;
204a2195becSreyk 	}
205a2195becSreyk 	if (what & CONFIG_RTS && env->sc_rts != NULL) {
206a2195becSreyk 		while ((rt = TAILQ_FIRST(env->sc_rts)) != NULL) {
207a2195becSreyk 			TAILQ_REMOVE(env->sc_rts, rt, rt_entry);
208a2195becSreyk 			while ((nr = TAILQ_FIRST(&rt->rt_netroutes)) != NULL) {
209a2195becSreyk 				TAILQ_REMOVE(&rt->rt_netroutes, nr, nr_entry);
210a2195becSreyk 				TAILQ_REMOVE(env->sc_routes, nr, nr_route);
211a2195becSreyk 				free(nr);
212a2195becSreyk 				env->sc_routecount--;
213a2195becSreyk 			}
214a2195becSreyk 			free(rt);
215a2195becSreyk 		}
216a2195becSreyk 		env->sc_routercount = 0;
217a2195becSreyk 	}
218a2195becSreyk 	if (what & CONFIG_ROUTES && env->sc_routes != NULL) {
219a2195becSreyk 		while ((nr = TAILQ_FIRST(env->sc_routes)) != NULL) {
220a2195becSreyk 			if ((rt = nr->nr_router) != NULL)
221a2195becSreyk 				TAILQ_REMOVE(&rt->rt_netroutes, nr, nr_entry);
222a2195becSreyk 			TAILQ_REMOVE(env->sc_routes, nr, nr_route);
223a2195becSreyk 			free(nr);
224a2195becSreyk 		}
225a2195becSreyk 		env->sc_routecount = 0;
226a2195becSreyk 	}
227a2195becSreyk }
228a2195becSreyk 
229a2195becSreyk int
230a2195becSreyk config_setreset(struct relayd *env, u_int reset)
231a2195becSreyk {
232a2195becSreyk 	struct privsep	*ps = env->sc_ps;
233a2195becSreyk 	int		 id;
234a2195becSreyk 
235a2195becSreyk 	for (id = 0; id < PROC_MAX; id++) {
236a2195becSreyk 		if ((reset & ps->ps_what[id]) == 0 ||
237a2195becSreyk 		    id == privsep_process)
238a2195becSreyk 			continue;
239c2c37c5dSreyk 		proc_compose(ps, id, IMSG_CTL_RESET, &reset, sizeof(reset));
2405d304668Sreyk 
2415d304668Sreyk 		/*
2425d304668Sreyk 		 * XXX Make sure that the reset message is sent
2435d304668Sreyk 		 * immediately by flushing the imsg output buffer, before
2445d304668Sreyk 		 * sending any other imsg that potentially include an fd.
2455d304668Sreyk 		 * This should better be fixed in the imsg API itself.
2465d304668Sreyk 		 */
2475d304668Sreyk 		proc_flush_imsg(ps, id, -1);
248a2195becSreyk 	}
249a2195becSreyk 
250a2195becSreyk 	return (0);
251a2195becSreyk }
252a2195becSreyk 
253a2195becSreyk int
254a2195becSreyk config_getreset(struct relayd *env, struct imsg *imsg)
255a2195becSreyk {
256a2195becSreyk 	u_int		 mode;
257a2195becSreyk 
258a2195becSreyk 	IMSG_SIZE_CHECK(imsg, &mode);
259a2195becSreyk 	memcpy(&mode, imsg->data, sizeof(mode));
260a2195becSreyk 
261a2195becSreyk 	config_purge(env, mode);
262a2195becSreyk 
263a2195becSreyk 	return (0);
264a2195becSreyk }
265a2195becSreyk 
266a2195becSreyk int
267a2195becSreyk config_getcfg(struct relayd *env, struct imsg *imsg)
268a2195becSreyk {
269a2195becSreyk 	struct privsep		*ps = env->sc_ps;
270a2195becSreyk 	struct table		*tb;
271a2195becSreyk 	struct host		*h, *ph;
2723d77879fSreyk 	u_int			 what;
273a2195becSreyk 
274586b5f8aSreyk 	if (IMSG_DATA_SIZE(imsg) != sizeof(struct relayd_config))
275a2195becSreyk 		return (0); /* ignore */
276a2195becSreyk 
277a2195becSreyk 	/* Update runtime flags */
278586b5f8aSreyk 	memcpy(&env->sc_conf, imsg->data, sizeof(env->sc_conf));
279a2195becSreyk 
2803d77879fSreyk 	what = ps->ps_what[privsep_process];
2813d77879fSreyk 
2823d77879fSreyk 	if (what & CONFIG_TABLES) {
283a2195becSreyk 		/* Update the tables */
284a2195becSreyk 		TAILQ_FOREACH(tb, env->sc_tables, entry) {
285a2195becSreyk 			TAILQ_FOREACH(h, &tb->hosts, entry) {
286a2195becSreyk 				if (h->conf.parentid && (ph = host_find(env,
287a2195becSreyk 				    h->conf.parentid)) != NULL) {
288a2195becSreyk 					SLIST_INSERT_HEAD(&ph->children,
289a2195becSreyk 					    h, child);
290a2195becSreyk 				}
291a2195becSreyk 			}
292a2195becSreyk 		}
293a2195becSreyk 	}
294a2195becSreyk 
295586b5f8aSreyk 	if (env->sc_conf.flags & (F_TLS|F_TLSCLIENT)) {
2961013dd2eSreyk 		if (what & CONFIG_CA_ENGINE)
2971013dd2eSreyk 			ca_engine_init(env);
2983d77879fSreyk 	}
299a2195becSreyk 
300a2195becSreyk 	if (privsep_process != PROC_PARENT)
301c2c37c5dSreyk 		proc_compose(env->sc_ps, PROC_PARENT, IMSG_CFG_DONE, NULL, 0);
302a2195becSreyk 
303a2195becSreyk 	return (0);
304a2195becSreyk }
305a2195becSreyk 
306a2195becSreyk int
307a2195becSreyk config_settable(struct relayd *env, struct table *tb)
308a2195becSreyk {
309a2195becSreyk 	struct privsep	*ps = env->sc_ps;
310a2195becSreyk 	struct host	*host;
311a2195becSreyk 	int		 id, c;
312a2195becSreyk 	struct iovec	 iov[2];
313a2195becSreyk 
314a2195becSreyk 	for (id = 0; id < PROC_MAX; id++) {
315a2195becSreyk 		if ((ps->ps_what[id] & CONFIG_TABLES) == 0 ||
316a2195becSreyk 		    id == privsep_process)
317a2195becSreyk 			continue;
318a2195becSreyk 
319a2195becSreyk 		/* XXX need to send table to pfe for control socket */
320a2195becSreyk 		if (id == PROC_HCE && tb->conf.check == CHECK_NOCHECK)
321a2195becSreyk 			continue;
322a2195becSreyk 
323a2195becSreyk 		DPRINTF("%s: sending table %s %d to %s", __func__,
324a2195becSreyk 		    tb->conf.name, tb->conf.id, env->sc_ps->ps_title[id]);
325a2195becSreyk 
326a2195becSreyk 		c = 0;
327a2195becSreyk 		iov[c].iov_base = &tb->conf;
328a2195becSreyk 		iov[c++].iov_len = sizeof(tb->conf);
329a2195becSreyk 		if (tb->sendbuf != NULL) {
330a2195becSreyk 			iov[c].iov_base = tb->sendbuf;
331a2195becSreyk 			iov[c++].iov_len = strlen(tb->sendbuf);
332a2195becSreyk 		}
333a2195becSreyk 
334c2c37c5dSreyk 		proc_composev(ps, id, IMSG_CFG_TABLE, iov, c);
335a2195becSreyk 
336a2195becSreyk 		TAILQ_FOREACH(host, &tb->hosts, entry) {
337c2c37c5dSreyk 			proc_compose(ps, id, IMSG_CFG_HOST,
338a2195becSreyk 			    &host->conf, sizeof(host->conf));
339a2195becSreyk 		}
340a2195becSreyk 	}
341a2195becSreyk 
342a2195becSreyk 	return (0);
343a2195becSreyk }
344a2195becSreyk 
345a2195becSreyk int
346a2195becSreyk config_gettable(struct relayd *env, struct imsg *imsg)
347a2195becSreyk {
348a2195becSreyk 	struct table		*tb;
349a2195becSreyk 	size_t			 sb;
350a2195becSreyk 	u_int8_t		*p = imsg->data;
351a2195becSreyk 	size_t			 s;
352a2195becSreyk 
353a2195becSreyk 	if ((tb = calloc(1, sizeof(*tb))) == NULL)
354a2195becSreyk 		return (-1);
355a2195becSreyk 
356a2195becSreyk 	IMSG_SIZE_CHECK(imsg, &tb->conf);
357a2195becSreyk 	memcpy(&tb->conf, p, sizeof(tb->conf));
358a2195becSreyk 	s = sizeof(tb->conf);
359a2195becSreyk 
360a2195becSreyk 	sb = IMSG_DATA_SIZE(imsg) - s;
361de71eb7fSreyk 	if (sb > 0) {
362de71eb7fSreyk 		if ((tb->sendbuf = get_string(p + s, sb)) == NULL) {
363de71eb7fSreyk 			free(tb);
364de71eb7fSreyk 			return (-1);
365de71eb7fSreyk 		}
366de71eb7fSreyk 	}
3673f229715Srob 	if (tb->conf.check == CHECK_BINSEND_EXPECT) {
3683f229715Srob 		tb->sendbinbuf = string2binary(tb->sendbuf);
3693f229715Srob 		if (tb->sendbinbuf == NULL) {
3703f229715Srob 			free(tb);
3713f229715Srob 			return (-1);
3723f229715Srob 		}
3733f229715Srob 	}
374a2195becSreyk 
375a2195becSreyk 	TAILQ_INIT(&tb->hosts);
376a2195becSreyk 	TAILQ_INSERT_TAIL(env->sc_tables, tb, entry);
377a2195becSreyk 
378a2195becSreyk 	env->sc_tablecount++;
379a2195becSreyk 
380a2195becSreyk 	DPRINTF("%s: %s %d received table %d (%s)", __func__,
381a2195becSreyk 	    env->sc_ps->ps_title[privsep_process], env->sc_ps->ps_instance,
382a2195becSreyk 	    tb->conf.id, tb->conf.name);
383a2195becSreyk 
384a2195becSreyk 	return (0);
385a2195becSreyk }
386a2195becSreyk 
387a2195becSreyk int
388a2195becSreyk config_gethost(struct relayd *env, struct imsg *imsg)
389a2195becSreyk {
390a2195becSreyk 	struct table		*tb;
391a2195becSreyk 	struct host		*host;
392a2195becSreyk 
393a2195becSreyk 	if ((host = calloc(1, sizeof(*host))) == NULL)
394a2195becSreyk 		return (-1);
395a2195becSreyk 
396a2195becSreyk 	IMSG_SIZE_CHECK(imsg, &host->conf);
397a2195becSreyk 	memcpy(&host->conf, imsg->data, sizeof(host->conf));
398a2195becSreyk 
399a2195becSreyk 	if (host_find(env, host->conf.id) != NULL) {
400a2195becSreyk 		log_debug("%s: host %d already exists",
401a2195becSreyk 		    __func__, host->conf.id);
402a2195becSreyk 		free(host);
403a2195becSreyk 		return (-1);
404a2195becSreyk 	}
405a2195becSreyk 
406a2195becSreyk 	if ((tb = table_find(env, host->conf.tableid)) == NULL) {
407a2195becSreyk 		log_debug("%s: "
408a2195becSreyk 		    "received host for unknown table %d", __func__,
409a2195becSreyk 		    host->conf.tableid);
410a2195becSreyk 		free(host);
411a2195becSreyk 		return (-1);
412a2195becSreyk 	}
413a2195becSreyk 
414a2195becSreyk 	host->tablename = tb->conf.name;
415a2195becSreyk 	host->cte.s = -1;
416a2195becSreyk 
417a2195becSreyk 	SLIST_INIT(&host->children);
418a2195becSreyk 	TAILQ_INSERT_TAIL(&tb->hosts, host, entry);
4196e07057bSblambert 	TAILQ_INSERT_TAIL(&env->sc_hosts, host, globalentry);
420a2195becSreyk 
421a2195becSreyk 	DPRINTF("%s: %s %d received host %s for table %s", __func__,
422a2195becSreyk 	    env->sc_ps->ps_title[privsep_process], env->sc_ps->ps_instance,
423a2195becSreyk 	    host->conf.name, tb->conf.name);
424a2195becSreyk 
425a2195becSreyk 	return (0);
426a2195becSreyk }
427a2195becSreyk 
428a2195becSreyk int
429a2195becSreyk config_setrdr(struct relayd *env, struct rdr *rdr)
430a2195becSreyk {
431a2195becSreyk 	struct privsep	*ps = env->sc_ps;
432a2195becSreyk 	struct address	*virt;
433a2195becSreyk 	int		 id;
434a2195becSreyk 
435a2195becSreyk 	for (id = 0; id < PROC_MAX; id++) {
436a2195becSreyk 		if ((ps->ps_what[id] & CONFIG_RDRS) == 0 ||
437a2195becSreyk 		    id == privsep_process)
438a2195becSreyk 			continue;
439a2195becSreyk 
440a2195becSreyk 		DPRINTF("%s: sending rdr %s to %s", __func__,
441a2195becSreyk 		    rdr->conf.name, ps->ps_title[id]);
442a2195becSreyk 
443c2c37c5dSreyk 		proc_compose(ps, id, IMSG_CFG_RDR,
444a2195becSreyk 		    &rdr->conf, sizeof(rdr->conf));
445a2195becSreyk 
446a2195becSreyk 		TAILQ_FOREACH(virt, &rdr->virts, entry) {
447a2195becSreyk 			virt->rdrid = rdr->conf.id;
448c2c37c5dSreyk 			proc_compose(ps, id, IMSG_CFG_VIRT,
449a2195becSreyk 			    virt, sizeof(*virt));
450a2195becSreyk 		}
451a2195becSreyk 	}
452a2195becSreyk 
453a2195becSreyk 	return (0);
454a2195becSreyk }
455a2195becSreyk 
456a2195becSreyk int
457a2195becSreyk config_getrdr(struct relayd *env, struct imsg *imsg)
458a2195becSreyk {
459a2195becSreyk 	struct rdr		*rdr;
460a2195becSreyk 
461a2195becSreyk 	if ((rdr = calloc(1, sizeof(*rdr))) == NULL)
462a2195becSreyk 		return (-1);
463a2195becSreyk 
464a2195becSreyk 	IMSG_SIZE_CHECK(imsg, &rdr->conf);
465a2195becSreyk 	memcpy(&rdr->conf, imsg->data, sizeof(rdr->conf));
466a2195becSreyk 
467a2195becSreyk 	if ((rdr->table = table_find(env, rdr->conf.table_id)) == NULL) {
468a2195becSreyk 		log_debug("%s: table not found", __func__);
469a2195becSreyk 		free(rdr);
470a2195becSreyk 		return (-1);
471a2195becSreyk 	}
472a2195becSreyk 	if ((rdr->backup = table_find(env, rdr->conf.backup_id)) == NULL) {
473a2195becSreyk 		rdr->conf.backup_id = EMPTY_TABLE;
474a2195becSreyk 		rdr->backup = &env->sc_empty_table;
475a2195becSreyk 	}
476a2195becSreyk 
477a2195becSreyk 	TAILQ_INIT(&rdr->virts);
478a2195becSreyk 	TAILQ_INSERT_TAIL(env->sc_rdrs, rdr, entry);
479a2195becSreyk 
480a2195becSreyk 	env->sc_rdrcount++;
481a2195becSreyk 
482a2195becSreyk 	DPRINTF("%s: %s %d received rdr %s", __func__,
483a2195becSreyk 	    env->sc_ps->ps_title[privsep_process], env->sc_ps->ps_instance,
484a2195becSreyk 	    rdr->conf.name);
485a2195becSreyk 
486a2195becSreyk 	return (0);
487a2195becSreyk }
488a2195becSreyk 
489a2195becSreyk int
490a2195becSreyk config_getvirt(struct relayd *env, struct imsg *imsg)
491a2195becSreyk {
492a2195becSreyk 	struct rdr	*rdr;
493a2195becSreyk 	struct address	*virt;
494a2195becSreyk 
495a2195becSreyk 	IMSG_SIZE_CHECK(imsg, virt);
496a2195becSreyk 
497a2195becSreyk 	if ((virt = calloc(1, sizeof(*virt))) == NULL)
498a2195becSreyk 		return (-1);
499a2195becSreyk 	memcpy(virt, imsg->data, sizeof(*virt));
500a2195becSreyk 
501a2195becSreyk 	if ((rdr = rdr_find(env, virt->rdrid)) == NULL) {
502a2195becSreyk 		log_debug("%s: rdr not found", __func__);
503a2195becSreyk 		free(virt);
504a2195becSreyk 		return (-1);
505a2195becSreyk 	}
506a2195becSreyk 
507a2195becSreyk 	TAILQ_INSERT_TAIL(&rdr->virts, virt, entry);
508a2195becSreyk 
509a2195becSreyk 	DPRINTF("%s: %s %d received address for rdr %s", __func__,
510a2195becSreyk 	    env->sc_ps->ps_title[privsep_process], env->sc_ps->ps_instance,
511a2195becSreyk 	    rdr->conf.name);
512a2195becSreyk 
513a2195becSreyk 	return (0);
514a2195becSreyk }
515a2195becSreyk 
516a2195becSreyk int
517a2195becSreyk config_setrt(struct relayd *env, struct router *rt)
518a2195becSreyk {
519a2195becSreyk 	struct privsep	*ps = env->sc_ps;
520a2195becSreyk 	struct netroute	*nr;
521a2195becSreyk 	int		 id;
522a2195becSreyk 
523a2195becSreyk 	for (id = 0; id < PROC_MAX; id++) {
524a2195becSreyk 		if ((ps->ps_what[id] & CONFIG_RTS) == 0 ||
525a2195becSreyk 		    id == privsep_process)
526a2195becSreyk 			continue;
527a2195becSreyk 
528a2195becSreyk 		DPRINTF("%s: sending router %s to %s tbl %d", __func__,
529a2195becSreyk 		    rt->rt_conf.name, ps->ps_title[id], rt->rt_conf.gwtable);
530a2195becSreyk 
531c2c37c5dSreyk 		proc_compose(ps, id, IMSG_CFG_ROUTER,
532a2195becSreyk 		    &rt->rt_conf, sizeof(rt->rt_conf));
533a2195becSreyk 
534a2195becSreyk 		TAILQ_FOREACH(nr, &rt->rt_netroutes, nr_entry) {
535c2c37c5dSreyk 			proc_compose(ps, id, IMSG_CFG_ROUTE,
536a2195becSreyk 			    &nr->nr_conf, sizeof(nr->nr_conf));
537a2195becSreyk 		}
538a2195becSreyk 	}
539a2195becSreyk 
540a2195becSreyk 	return (0);
541a2195becSreyk }
542a2195becSreyk 
543a2195becSreyk int
544a2195becSreyk config_getrt(struct relayd *env, struct imsg *imsg)
545a2195becSreyk {
546a2195becSreyk 	struct router		*rt;
547a2195becSreyk 
548a2195becSreyk 	if ((rt = calloc(1, sizeof(*rt))) == NULL)
549a2195becSreyk 		return (-1);
550a2195becSreyk 
551a2195becSreyk 	IMSG_SIZE_CHECK(imsg, &rt->rt_conf);
552a2195becSreyk 	memcpy(&rt->rt_conf, imsg->data, sizeof(rt->rt_conf));
553a2195becSreyk 
554a2195becSreyk 	if ((rt->rt_gwtable = table_find(env, rt->rt_conf.gwtable)) == NULL) {
555a2195becSreyk 		log_debug("%s: table not found", __func__);
556a2195becSreyk 		free(rt);
557a2195becSreyk 		return (-1);
558a2195becSreyk 	}
559a2195becSreyk 
560a2195becSreyk 	TAILQ_INIT(&rt->rt_netroutes);
561a2195becSreyk 	TAILQ_INSERT_TAIL(env->sc_rts, rt, rt_entry);
562a2195becSreyk 
563a2195becSreyk 	env->sc_routercount++;
564a2195becSreyk 
565a2195becSreyk 	DPRINTF("%s: %s %d received router %s", __func__,
566a2195becSreyk 	    env->sc_ps->ps_title[privsep_process], env->sc_ps->ps_instance,
567a2195becSreyk 	    rt->rt_conf.name);
568a2195becSreyk 
569a2195becSreyk 	return (0);
570a2195becSreyk }
571a2195becSreyk 
572a2195becSreyk int
573a2195becSreyk config_getroute(struct relayd *env, struct imsg *imsg)
574a2195becSreyk {
575a2195becSreyk 	struct router		*rt;
576a2195becSreyk 	struct netroute		*nr;
577a2195becSreyk 
578a2195becSreyk 	if ((nr = calloc(1, sizeof(*nr))) == NULL)
579a2195becSreyk 		return (-1);
580a2195becSreyk 
581a2195becSreyk 	IMSG_SIZE_CHECK(imsg, &nr->nr_conf);
582a2195becSreyk 	memcpy(&nr->nr_conf, imsg->data, sizeof(nr->nr_conf));
583a2195becSreyk 
584a2195becSreyk 	if (route_find(env, nr->nr_conf.id) != NULL) {
585a2195becSreyk 		log_debug("%s: route %d already exists",
586a2195becSreyk 		    __func__, nr->nr_conf.id);
587a2195becSreyk 		free(nr);
588a2195becSreyk 		return (-1);
589a2195becSreyk 	}
590a2195becSreyk 
591a2195becSreyk 	if ((rt = router_find(env, nr->nr_conf.routerid)) == NULL) {
592a2195becSreyk 		log_debug("%s: received route for unknown router", __func__);
593a2195becSreyk 		free(nr);
594a2195becSreyk 		return (-1);
595a2195becSreyk 	}
596a2195becSreyk 
597a2195becSreyk 	nr->nr_router = rt;
598a2195becSreyk 
599a2195becSreyk 	TAILQ_INSERT_TAIL(env->sc_routes, nr, nr_route);
600a2195becSreyk 	TAILQ_INSERT_TAIL(&rt->rt_netroutes, nr, nr_entry);
601a2195becSreyk 
602a2195becSreyk 	env->sc_routecount++;
603a2195becSreyk 
604a2195becSreyk 	DPRINTF("%s: %s %d received route %d for router %s", __func__,
605a2195becSreyk 	    env->sc_ps->ps_title[privsep_process], env->sc_ps->ps_instance,
606a2195becSreyk 	    nr->nr_conf.id, rt->rt_conf.name);
607a2195becSreyk 
608a2195becSreyk 	return (0);
609a2195becSreyk }
610a2195becSreyk 
611a2195becSreyk int
612a2195becSreyk config_setproto(struct relayd *env, struct protocol *proto)
613a2195becSreyk {
614a2195becSreyk 	struct privsep		*ps = env->sc_ps;
615a2195becSreyk 	int			 id;
616cb8b0e56Sreyk 	struct iovec		 iov[IOV_MAX];
617a2195becSreyk 	size_t			 c;
618a2195becSreyk 
619a2195becSreyk 	for (id = 0; id < PROC_MAX; id++) {
620a2195becSreyk 		if ((ps->ps_what[id] & CONFIG_PROTOS) == 0 ||
621a2195becSreyk 		    id == privsep_process)
622a2195becSreyk 			continue;
623a2195becSreyk 
624a2195becSreyk 		DPRINTF("%s: sending protocol %s to %s", __func__,
625a2195becSreyk 		    proto->name, ps->ps_title[id]);
626a2195becSreyk 
627a2195becSreyk 		c = 0;
628a2195becSreyk 		iov[c].iov_base = proto;
629a2195becSreyk 		iov[c++].iov_len = sizeof(*proto);
630a2195becSreyk 
631a2195becSreyk 		if (proto->style != NULL) {
632a2195becSreyk 			iov[c].iov_base = proto->style;
6338f340ff2Sjsg 			iov[c++].iov_len = strlen(proto->style) + 1;
634a2195becSreyk 		}
635a2195becSreyk 
636c2c37c5dSreyk 		proc_composev(ps, id, IMSG_CFG_PROTO, iov, c);
637cb8b0e56Sreyk 	}
638a2195becSreyk 
639cb8b0e56Sreyk 	return (0);
640cb8b0e56Sreyk }
641cb8b0e56Sreyk 
642cb8b0e56Sreyk int
643cb8b0e56Sreyk config_setrule(struct relayd *env, struct protocol *proto)
644cb8b0e56Sreyk {
645cb8b0e56Sreyk 	struct privsep		*ps = env->sc_ps;
646cb8b0e56Sreyk 	struct relay_rule	*rule;
647cb8b0e56Sreyk 	struct iovec		 iov[IOV_MAX];
648cb8b0e56Sreyk 	int			 id;
649cb8b0e56Sreyk 	size_t			 c, i;
650cb8b0e56Sreyk 
651cb8b0e56Sreyk 	for (id = 0; id < PROC_MAX; id++) {
652cb8b0e56Sreyk 		if ((ps->ps_what[id] & CONFIG_PROTOS) == 0 ||
653cb8b0e56Sreyk 		    id == privsep_process)
654cb8b0e56Sreyk 			continue;
655cb8b0e56Sreyk 
656cb8b0e56Sreyk 		DPRINTF("%s: sending rules %s to %s", __func__,
657cb8b0e56Sreyk 		    proto->name, ps->ps_title[id]);
658cb8b0e56Sreyk 
659cb8b0e56Sreyk 		/* Now send all the rules */
660cb8b0e56Sreyk 		TAILQ_FOREACH(rule, &proto->rules, rule_entry) {
661cb8b0e56Sreyk 			rule->rule_protoid = proto->id;
662cb8b0e56Sreyk 			bzero(&rule->rule_ctl, sizeof(rule->rule_ctl));
663cb8b0e56Sreyk 			c = 0;
664cb8b0e56Sreyk 			iov[c].iov_base = rule;
665cb8b0e56Sreyk 			iov[c++].iov_len = sizeof(*rule);
666cb8b0e56Sreyk 			for (i = 1; i < KEY_TYPE_MAX; i++) {
667cb8b0e56Sreyk 				if (rule->rule_kv[i].kv_key != NULL) {
668cb8b0e56Sreyk 					rule->rule_ctl.kvlen[i].key =
669cb8b0e56Sreyk 					    strlen(rule->rule_kv[i].kv_key);
670cb8b0e56Sreyk 					iov[c].iov_base =
671cb8b0e56Sreyk 					    rule->rule_kv[i].kv_key;
672cb8b0e56Sreyk 					iov[c++].iov_len =
673cb8b0e56Sreyk 					    rule->rule_ctl.kvlen[i].key;
674cb8b0e56Sreyk 				} else
675cb8b0e56Sreyk 					rule->rule_ctl.kvlen[i].key = -1;
676cb8b0e56Sreyk 				if (rule->rule_kv[i].kv_value != NULL) {
677cb8b0e56Sreyk 					rule->rule_ctl.kvlen[i].value =
678cb8b0e56Sreyk 					    strlen(rule->rule_kv[i].kv_value);
679cb8b0e56Sreyk 					iov[c].iov_base =
680cb8b0e56Sreyk 					    rule->rule_kv[i].kv_value;
681cb8b0e56Sreyk 					iov[c++].iov_len =
682cb8b0e56Sreyk 					    rule->rule_ctl.kvlen[i].value;
683cb8b0e56Sreyk 				} else
684cb8b0e56Sreyk 					rule->rule_ctl.kvlen[i].value = -1;
685cb8b0e56Sreyk 			}
686cb8b0e56Sreyk 
687c2c37c5dSreyk 			proc_composev(ps, id, IMSG_CFG_RULE, iov, c);
688cb8b0e56Sreyk 		}
689a2195becSreyk 	}
690a2195becSreyk 
691a2195becSreyk 	return (0);
692a2195becSreyk }
693a2195becSreyk 
694a2195becSreyk int
695a2195becSreyk config_getproto(struct relayd *env, struct imsg *imsg)
696a2195becSreyk {
697a2195becSreyk 	struct protocol		*proto;
698a2195becSreyk 	size_t			 styl;
699de71eb7fSreyk 	size_t			 s;
700de71eb7fSreyk 	u_int8_t		*p = imsg->data;
701a2195becSreyk 
702a2195becSreyk 	if ((proto = calloc(1, sizeof(*proto))) == NULL)
703a2195becSreyk 		return (-1);
704a2195becSreyk 
705a2195becSreyk 	IMSG_SIZE_CHECK(imsg, proto);
706de71eb7fSreyk 	memcpy(proto, p, sizeof(*proto));
707de71eb7fSreyk 	s = sizeof(*proto);
708a2195becSreyk 
709de71eb7fSreyk 	styl = IMSG_DATA_SIZE(imsg) - s;
7108f340ff2Sjsg 	proto->style = NULL;
711de71eb7fSreyk 	if (styl > 0) {
7128f340ff2Sjsg 		if ((proto->style = get_string(p + s, styl - 1)) == NULL) {
713de71eb7fSreyk 			free(proto);
714de71eb7fSreyk 			return (-1);
715de71eb7fSreyk 		}
716de71eb7fSreyk 	}
717a2195becSreyk 
718cb8b0e56Sreyk 	TAILQ_INIT(&proto->rules);
7193ca2f577Sreyk 	TAILQ_INIT(&proto->tlscerts);
7207bb52228Sreyk 	proto->tlscapass = NULL;
721a2195becSreyk 
722a2195becSreyk 	TAILQ_INSERT_TAIL(env->sc_protos, proto, entry);
723a2195becSreyk 
724a2195becSreyk 	env->sc_protocount++;
725a2195becSreyk 
726a2195becSreyk 	DPRINTF("%s: %s %d received protocol %s", __func__,
727a2195becSreyk 	    env->sc_ps->ps_title[privsep_process], env->sc_ps->ps_instance,
728a2195becSreyk 	    proto->name);
729a2195becSreyk 
730a2195becSreyk 	return (0);
731a2195becSreyk }
732a2195becSreyk 
733a2195becSreyk int
734cb8b0e56Sreyk config_getrule(struct relayd *env, struct imsg *imsg)
735a2195becSreyk {
736cb8b0e56Sreyk 	struct protocol		*proto;
737cb8b0e56Sreyk 	struct relay_rule	*rule;
738cb8b0e56Sreyk 	size_t			 s, i;
739a2195becSreyk 	u_int8_t		*p = imsg->data;
740cb8b0e56Sreyk 	ssize_t			 len;
741a2195becSreyk 
742cb8b0e56Sreyk 	if ((rule = calloc(1, sizeof(*rule))) == NULL)
743cb8b0e56Sreyk 		return (-1);
744a2195becSreyk 
745cb8b0e56Sreyk 	IMSG_SIZE_CHECK(imsg, rule);
746cb8b0e56Sreyk 	memcpy(rule, p, sizeof(*rule));
747cb8b0e56Sreyk 	s = sizeof(*rule);
748cb8b0e56Sreyk 	len = IMSG_DATA_SIZE(imsg) - s;
749a2195becSreyk 
750cb8b0e56Sreyk 	if ((proto = proto_find(env, rule->rule_protoid)) == NULL) {
751cb8b0e56Sreyk 		free(rule);
752a2195becSreyk 		return (-1);
753a2195becSreyk 	}
754a2195becSreyk 
755cb8b0e56Sreyk #define GETKV(_n, _f)	{						\
756cb8b0e56Sreyk 	if (rule->rule_ctl.kvlen[_n]._f >= 0) {				\
757cb8b0e56Sreyk 		/* Also accept "empty" 0-length strings */		\
758cb8b0e56Sreyk 		if ((len < rule->rule_ctl.kvlen[_n]._f) ||		\
759cb8b0e56Sreyk 		    (rule->rule_kv[_n].kv_##_f =			\
760cb8b0e56Sreyk 		    get_string(p + s,					\
761cb8b0e56Sreyk 		    rule->rule_ctl.kvlen[_n]._f)) == NULL) {		\
762cb8b0e56Sreyk 			free(rule);					\
763cb8b0e56Sreyk 			return (-1);					\
764cb8b0e56Sreyk 		}							\
765cb8b0e56Sreyk 		s += rule->rule_ctl.kvlen[_n]._f;			\
766cb8b0e56Sreyk 		len -= rule->rule_ctl.kvlen[_n]._f;			\
767cb8b0e56Sreyk 									\
768cb8b0e56Sreyk 		DPRINTF("%s: %s %s (len %ld, option %d): %s", __func__,	\
769cb8b0e56Sreyk 		    #_n, #_f, rule->rule_ctl.kvlen[_n]._f,		\
770cb8b0e56Sreyk 		    rule->rule_kv[_n].kv_option,			\
771cb8b0e56Sreyk 		    rule->rule_kv[_n].kv_##_f);				\
772cb8b0e56Sreyk 	}								\
7731ac2a6baSbenno }
774a2195becSreyk 
77553ad1bbfSreyk 	memset(&rule->rule_kv[0], 0, sizeof(struct kv));
776cb8b0e56Sreyk 	for (i = 1; i < KEY_TYPE_MAX; i++) {
777c307a266Sreyk 		TAILQ_INIT(&rule->rule_kv[i].kv_children);
778cb8b0e56Sreyk 		GETKV(i, key);
779cb8b0e56Sreyk 		GETKV(i, value);
780a2195becSreyk 	}
781a2195becSreyk 
782cb8b0e56Sreyk 	if (rule->rule_labelname[0])
783cb8b0e56Sreyk 		rule->rule_label = label_name2id(rule->rule_labelname);
784a2195becSreyk 
785cb8b0e56Sreyk 	if (rule->rule_tagname[0])
786cb8b0e56Sreyk 		rule->rule_tag = tag_name2id(rule->rule_tagname);
787cb8b0e56Sreyk 
788cb8b0e56Sreyk 	if (rule->rule_taggedname[0])
789cb8b0e56Sreyk 		rule->rule_tagged = tag_name2id(rule->rule_taggedname);
790cb8b0e56Sreyk 
791cb8b0e56Sreyk 	rule->rule_id = proto->rulecount++;
792cb8b0e56Sreyk 
793cb8b0e56Sreyk 	TAILQ_INSERT_TAIL(&proto->rules, rule, rule_entry);
794cb8b0e56Sreyk 
795cb8b0e56Sreyk 	DPRINTF("%s: %s %d received rule %u for protocol %s", __func__,
796a2195becSreyk 	    env->sc_ps->ps_title[privsep_process], env->sc_ps->ps_instance,
797cb8b0e56Sreyk 	    rule->rule_id, proto->name);
798a2195becSreyk 
799a2195becSreyk 	return (0);
800a2195becSreyk }
801a2195becSreyk 
802114ce177Sclaudio static int
803f2f4e153Sreyk config_setrelayfd(struct privsep *ps, int id, int n,
804f2f4e153Sreyk     objid_t obj_id, objid_t rlay_id, enum fd_type type, int ofd)
805114ce177Sclaudio {
806114ce177Sclaudio 	struct ctl_relayfd	rfd;
807114ce177Sclaudio 	int			fd;
808114ce177Sclaudio 
809f2f4e153Sreyk 	rfd.id = obj_id;
810114ce177Sclaudio 	rfd.relayid = rlay_id;
811114ce177Sclaudio 	rfd.type = type;
812114ce177Sclaudio 
813114ce177Sclaudio 	if ((fd = dup(ofd)) == -1)
814114ce177Sclaudio 		return (-1);
815114ce177Sclaudio 	if (proc_compose_imsg(ps, id, n, IMSG_CFG_RELAY_FD, -1, fd,
816114ce177Sclaudio 	    &rfd, sizeof(rfd)) != 0)
817114ce177Sclaudio 		return (-1);
818114ce177Sclaudio 
819114ce177Sclaudio 	return (0);
820114ce177Sclaudio }
821114ce177Sclaudio 
822a2195becSreyk int
823a2195becSreyk config_setrelay(struct relayd *env, struct relay *rlay)
824a2195becSreyk {
825a2195becSreyk 	struct privsep		*ps = env->sc_ps;
826416fa9c0Sreyk 	struct ctl_relaytable	 crt;
827416fa9c0Sreyk 	struct relay_table	*rlt;
8283d77879fSreyk 	struct relay_config	 rl;
829f2f4e153Sreyk 	struct relay_cert	*cert;
830a2195becSreyk 	int			 id;
831a2195becSreyk 	int			 fd, n, m;
832c71a6e4bSjsg 	struct iovec		 iov[6];
833a2195becSreyk 	size_t			 c;
8343d77879fSreyk 	u_int			 what;
835a2195becSreyk 
836a2195becSreyk 	/* opens listening sockets etc. */
837a2195becSreyk 	if (relay_privinit(rlay) == -1)
838a2195becSreyk 		return (-1);
839a2195becSreyk 
840a2195becSreyk 	for (id = 0; id < PROC_MAX; id++) {
8413d77879fSreyk 		what = ps->ps_what[id];
8423d77879fSreyk 
8433d77879fSreyk 		if ((what & CONFIG_RELAYS) == 0 || id == privsep_process)
844a2195becSreyk 			continue;
845a2195becSreyk 
846a2195becSreyk 		DPRINTF("%s: sending relay %s to %s fd %d", __func__,
847a2195becSreyk 		    rlay->rl_conf.name, ps->ps_title[id], rlay->rl_s);
848a2195becSreyk 
8493d77879fSreyk 		memcpy(&rl, &rlay->rl_conf, sizeof(rl));
8503d77879fSreyk 
851a2195becSreyk 		c = 0;
8523d77879fSreyk 		iov[c].iov_base = &rl;
8533d77879fSreyk 		iov[c++].iov_len = sizeof(rl);
854114ce177Sclaudio 
8553d77879fSreyk 		if ((what & CONFIG_CA_ENGINE) == 0 &&
8567bb52228Sreyk 		    rl.tls_cakey_len) {
8577bb52228Sreyk 			iov[c].iov_base = rlay->rl_tls_cakey;
8587bb52228Sreyk 			iov[c++].iov_len = rl.tls_cakey_len;
85900ae3104Sreyk 		} else
8607bb52228Sreyk 			rl.tls_cakey_len = 0;
861a2195becSreyk 
862a2195becSreyk 		if (id == PROC_RELAY) {
863a2195becSreyk 			/* XXX imsg code will close the fd after 1st call */
864a2195becSreyk 			n = -1;
865a2195becSreyk 			proc_range(ps, id, &n, &m);
866a2195becSreyk 			for (n = 0; n < m; n++) {
867a2195becSreyk 				if ((fd = dup(rlay->rl_s)) == -1)
868a2195becSreyk 					return (-1);
86951cb1125Sreyk 				if (proc_composev_imsg(ps, id, n,
87051cb1125Sreyk 				    IMSG_CFG_RELAY, -1, fd, iov, c) != 0) {
87151cb1125Sreyk 					log_warn("%s: failed to compose "
87251cb1125Sreyk 					    "IMSG_CFG_RELAY imsg for `%s'",
87351cb1125Sreyk 					    __func__, rlay->rl_conf.name);
87451cb1125Sreyk 					return (-1);
87551cb1125Sreyk 				}
87651cb1125Sreyk 				/* Prevent fd exhaustion in the parent. */
87751cb1125Sreyk 				if (proc_flush_imsg(ps, id, n) == -1) {
87851cb1125Sreyk 					log_warn("%s: failed to flush "
87951cb1125Sreyk 					    "IMSG_CFG_RELAY imsg for `%s'",
88051cb1125Sreyk 					    __func__, rlay->rl_conf.name);
88151cb1125Sreyk 					return (-1);
88251cb1125Sreyk 				}
883a2195becSreyk 			}
884a2195becSreyk 		} else {
88551cb1125Sreyk 			if (proc_composev(ps, id,
88651cb1125Sreyk 			    IMSG_CFG_RELAY, iov, c) != 0) {
88751cb1125Sreyk 				log_warn("%s: failed to compose "
88851cb1125Sreyk 				    "IMSG_CFG_RELAY imsg for `%s'",
88951cb1125Sreyk 				    __func__, rlay->rl_conf.name);
89051cb1125Sreyk 				return (-1);
89151cb1125Sreyk 			}
892a2195becSreyk 		}
893416fa9c0Sreyk 
894f2f4e153Sreyk 		/* cert keypairs */
895f2f4e153Sreyk 		TAILQ_FOREACH(cert, env->sc_certs, cert_entry) {
896f2f4e153Sreyk 			if (cert->cert_relayid != rlay->rl_conf.id)
897f2f4e153Sreyk 				continue;
898114ce177Sclaudio 			n = -1;
899114ce177Sclaudio 			proc_range(ps, id, &n, &m);
900f2f4e153Sreyk 			for (n = 0; (what & CONFIG_CERTS) && n < m; n++) {
901f2f4e153Sreyk 				if (cert->cert_fd != -1 &&
902114ce177Sclaudio 				    config_setrelayfd(ps, id, n,
903f2f4e153Sreyk 				    cert->cert_id, cert->cert_relayid,
904f2f4e153Sreyk 				    RELAY_FD_CERT, cert->cert_fd) == -1) {
905114ce177Sclaudio 					log_warn("%s: fd passing failed for "
906114ce177Sclaudio 					    "`%s'", __func__,
907114ce177Sclaudio 					    rlay->rl_conf.name);
908114ce177Sclaudio 					return (-1);
909114ce177Sclaudio 				}
91031604b98Sreyk 				if (id == PROC_RELAY &&
91131604b98Sreyk 				    cert->cert_ocsp_fd != -1 &&
91231604b98Sreyk 				    config_setrelayfd(ps, id, n,
91331604b98Sreyk 				    cert->cert_id, cert->cert_relayid,
91431604b98Sreyk 				    RELAY_FD_OCSP, cert->cert_ocsp_fd) == -1) {
91531604b98Sreyk 					log_warn("%s: fd passing failed for "
91631604b98Sreyk 					    "`%s'", __func__,
91731604b98Sreyk 					    rlay->rl_conf.name);
91831604b98Sreyk 					return (-1);
91931604b98Sreyk 				}
920f2f4e153Sreyk 				if (id == PROC_CA &&
921f2f4e153Sreyk 				    cert->cert_key_fd != -1 &&
922114ce177Sclaudio 				    config_setrelayfd(ps, id, n,
923f2f4e153Sreyk 				    cert->cert_id, cert->cert_relayid,
924f2f4e153Sreyk 				    RELAY_FD_KEY, cert->cert_key_fd) == -1) {
925f2f4e153Sreyk 					log_warn("%s: fd passing failed for "
926f2f4e153Sreyk 					    "`%s'", __func__,
927f2f4e153Sreyk 					    rlay->rl_conf.name);
928f2f4e153Sreyk 					return (-1);
929f2f4e153Sreyk 				}
930f2f4e153Sreyk 			}
931f2f4e153Sreyk 		}
932f2f4e153Sreyk 
933f2f4e153Sreyk 		/* CA certs */
934f2f4e153Sreyk 		if (what & CONFIG_CERTS) {
935f2f4e153Sreyk 			n = -1;
936f2f4e153Sreyk 			proc_range(ps, id, &n, &m);
937f2f4e153Sreyk 			for (n = 0; n < m; n++) {
938f2f4e153Sreyk 				if (rlay->rl_tls_ca_fd != -1 &&
939f2f4e153Sreyk 				    config_setrelayfd(ps, id, n, 0,
940114ce177Sclaudio 				    rlay->rl_conf.id, RELAY_FD_CACERT,
941114ce177Sclaudio 				    rlay->rl_tls_ca_fd) == -1) {
942114ce177Sclaudio 					log_warn("%s: fd passing failed for "
943114ce177Sclaudio 					    "`%s'", __func__,
944114ce177Sclaudio 					    rlay->rl_conf.name);
945114ce177Sclaudio 					return (-1);
946114ce177Sclaudio 				}
947114ce177Sclaudio 				if (rlay->rl_tls_cacert_fd != -1 &&
948f2f4e153Sreyk 				    config_setrelayfd(ps, id, n, 0,
949114ce177Sclaudio 				    rlay->rl_conf.id, RELAY_FD_CAFILE,
950114ce177Sclaudio 				    rlay->rl_tls_cacert_fd) == -1) {
951114ce177Sclaudio 					log_warn("%s: fd passing failed for "
952114ce177Sclaudio 					    "`%s'", __func__,
953114ce177Sclaudio 					    rlay->rl_conf.name);
954114ce177Sclaudio 					return (-1);
955114ce177Sclaudio 				}
95692388deeStb 				if (rlay->rl_tls_client_ca_fd != -1 &&
95792388deeStb 				    config_setrelayfd(ps, id, n, 0,
95892388deeStb 				    rlay->rl_conf.id, RELAY_FD_CLIENTCACERT,
95992388deeStb 				    rlay->rl_tls_client_ca_fd) == -1) {
96092388deeStb 					log_warn("%s: fd passing failed for "
96192388deeStb 					    "`%s'", __func__,
96292388deeStb 					    rlay->rl_conf.name);
96392388deeStb 					return (-1);
96492388deeStb 				}
965114ce177Sclaudio 				/* Prevent fd exhaustion in the parent. */
966114ce177Sclaudio 				if (proc_flush_imsg(ps, id, n) == -1) {
967114ce177Sclaudio 					log_warn("%s: failed to flush "
968114ce177Sclaudio 					    "IMSG_CFG_RELAY imsg for `%s'",
969114ce177Sclaudio 					    __func__, rlay->rl_conf.name);
970114ce177Sclaudio 					return (-1);
971114ce177Sclaudio 				}
972114ce177Sclaudio 			}
973114ce177Sclaudio 		}
974114ce177Sclaudio 
9753d77879fSreyk 		if ((what & CONFIG_TABLES) == 0)
9763d77879fSreyk 			continue;
9773d77879fSreyk 
978416fa9c0Sreyk 		/* Now send the tables associated to this relay */
979416fa9c0Sreyk 		TAILQ_FOREACH(rlt, &rlay->rl_tables, rlt_entry) {
980416fa9c0Sreyk 			crt.id = rlt->rlt_table->conf.id;
981416fa9c0Sreyk 			crt.relayid = rlay->rl_conf.id;
982416fa9c0Sreyk 			crt.mode = rlt->rlt_mode;
983118081d7Sreyk 			crt.flags = rlt->rlt_flags;
984416fa9c0Sreyk 
985416fa9c0Sreyk 			c = 0;
986416fa9c0Sreyk 			iov[c].iov_base = &crt;
987416fa9c0Sreyk 			iov[c++].iov_len = sizeof(crt);
988416fa9c0Sreyk 
989c2c37c5dSreyk 			proc_composev(ps, id, IMSG_CFG_RELAY_TABLE, iov, c);
990416fa9c0Sreyk 		}
991a2195becSreyk 	}
992a2195becSreyk 
99351cb1125Sreyk 	/* Close server socket early to prevent fd exhaustion in the parent. */
99451cb1125Sreyk 	if (rlay->rl_s != -1) {
995a2195becSreyk 		close(rlay->rl_s);
996a2195becSreyk 		rlay->rl_s = -1;
99751cb1125Sreyk 	}
99892388deeStb 	if (rlay->rl_tls_client_ca_fd != -1) {
99992388deeStb 		close(rlay->rl_tls_client_ca_fd);
100092388deeStb 		rlay->rl_tls_client_ca_fd = -1;
100192388deeStb 	}
1002114ce177Sclaudio 	if (rlay->rl_tls_cacert_fd != -1) {
1003114ce177Sclaudio 		close(rlay->rl_tls_cacert_fd);
1004114ce177Sclaudio 		rlay->rl_tls_cacert_fd = -1;
1005114ce177Sclaudio 	}
1006114ce177Sclaudio 	if (rlay->rl_tls_ca_fd != -1) {
1007114ce177Sclaudio 		close(rlay->rl_tls_ca_fd);
1008114ce177Sclaudio 		rlay->rl_tls_ca_fd = -1;
1009114ce177Sclaudio 	}
1010f2f4e153Sreyk 	TAILQ_FOREACH(cert, env->sc_certs, cert_entry) {
1011f2f4e153Sreyk 		if (cert->cert_relayid != rlay->rl_conf.id)
1012f2f4e153Sreyk 			continue;
1013f2f4e153Sreyk 
1014f2f4e153Sreyk 		if (cert->cert_fd != -1) {
1015f2f4e153Sreyk 			close(cert->cert_fd);
1016f2f4e153Sreyk 			cert->cert_fd = -1;
1017f2f4e153Sreyk 		}
1018f2f4e153Sreyk 		if (cert->cert_key_fd != -1) {
1019f2f4e153Sreyk 			close(cert->cert_key_fd);
1020f2f4e153Sreyk 			cert->cert_key_fd = -1;
1021f2f4e153Sreyk 		}
102231604b98Sreyk 		if (cert->cert_ocsp_fd != -1) {
102331604b98Sreyk 			close(cert->cert_ocsp_fd);
102431604b98Sreyk 			cert->cert_ocsp_fd = -1;
102531604b98Sreyk 		}
1026f2f4e153Sreyk 	}
102792388deeStb 	if (rlay->rl_tls_client_ca_fd != -1) {
102892388deeStb 		close(rlay->rl_tls_client_ca_fd);
102992388deeStb 		rlay->rl_tls_client_ca_fd = -1;
103092388deeStb 	}
1031a2195becSreyk 
1032a2195becSreyk 	return (0);
1033a2195becSreyk }
1034a2195becSreyk 
1035a2195becSreyk int
1036a2195becSreyk config_getrelay(struct relayd *env, struct imsg *imsg)
1037a2195becSreyk {
1038a2195becSreyk 	struct privsep		*ps = env->sc_ps;
1039a2195becSreyk 	struct relay		*rlay;
1040a2195becSreyk 	u_int8_t		*p = imsg->data;
1041a2195becSreyk 	size_t			 s;
1042a2195becSreyk 
1043a2195becSreyk 	if ((rlay = calloc(1, sizeof(*rlay))) == NULL)
1044a2195becSreyk 		return (-1);
1045a2195becSreyk 
1046a2195becSreyk 	IMSG_SIZE_CHECK(imsg, &rlay->rl_conf);
1047a2195becSreyk 	memcpy(&rlay->rl_conf, p, sizeof(rlay->rl_conf));
1048a2195becSreyk 	s = sizeof(rlay->rl_conf);
1049a2195becSreyk 
1050a1416996Sclaudio 	rlay->rl_s = imsg_get_fd(imsg);
1051114ce177Sclaudio 	rlay->rl_tls_ca_fd = -1;
1052114ce177Sclaudio 	rlay->rl_tls_cacert_fd = -1;
105392388deeStb 	rlay->rl_tls_client_ca_fd = -1;
1054a2195becSreyk 
1055a2195becSreyk 	if (ps->ps_what[privsep_process] & CONFIG_PROTOS) {
1056a2195becSreyk 		if (rlay->rl_conf.proto == EMPTY_ID)
1057a2195becSreyk 			rlay->rl_proto = &env->sc_proto_default;
1058a2195becSreyk 		else if ((rlay->rl_proto =
1059a2195becSreyk 		    proto_find(env, rlay->rl_conf.proto)) == NULL) {
1060a2195becSreyk 			log_debug("%s: unknown protocol", __func__);
1061a2195becSreyk 			goto fail;
1062a2195becSreyk 		}
1063a2195becSreyk 	}
1064a2195becSreyk 
10659660c10cStedu 	if ((off_t)(IMSG_DATA_SIZE(imsg) - s) <
1066f2f4e153Sreyk 	    (rlay->rl_conf.tls_cakey_len)) {
1067a2195becSreyk 		log_debug("%s: invalid message length", __func__);
1068a2195becSreyk 		goto fail;
1069a2195becSreyk 	}
1070a2195becSreyk 
10717bb52228Sreyk 	if (rlay->rl_conf.tls_cakey_len) {
10727bb52228Sreyk 		if ((rlay->rl_tls_cakey = get_data(p + s,
10737bb52228Sreyk 		    rlay->rl_conf.tls_cakey_len)) == NULL)
1074cf39ad79Sreyk 			goto fail;
10757bb52228Sreyk 		s += rlay->rl_conf.tls_cakey_len;
1076cf39ad79Sreyk 	}
1077a2195becSreyk 
1078416fa9c0Sreyk 	TAILQ_INIT(&rlay->rl_tables);
1079a2195becSreyk 	TAILQ_INSERT_TAIL(env->sc_relays, rlay, rl_entry);
1080a2195becSreyk 
1081a2195becSreyk 	env->sc_relaycount++;
1082a2195becSreyk 
1083a2195becSreyk 	DPRINTF("%s: %s %d received relay %s", __func__,
1084a2195becSreyk 	    ps->ps_title[privsep_process], ps->ps_instance,
1085a2195becSreyk 	    rlay->rl_conf.name);
1086a2195becSreyk 
1087a2195becSreyk 	return (0);
1088a2195becSreyk 
1089a2195becSreyk  fail:
1090114ce177Sclaudio 	free(rlay->rl_tls_cakey);
1091a2195becSreyk 	close(rlay->rl_s);
1092a2195becSreyk 	free(rlay);
1093a2195becSreyk 	return (-1);
1094a2195becSreyk }
1095416fa9c0Sreyk 
1096416fa9c0Sreyk int
1097416fa9c0Sreyk config_getrelaytable(struct relayd *env, struct imsg *imsg)
1098416fa9c0Sreyk {
1099416fa9c0Sreyk 	struct relay_table	*rlt = NULL;
1100416fa9c0Sreyk 	struct ctl_relaytable	 crt;
1101416fa9c0Sreyk 	struct relay		*rlay;
1102416fa9c0Sreyk 	struct table		*table;
1103416fa9c0Sreyk 	u_int8_t		*p = imsg->data;
1104416fa9c0Sreyk 
1105416fa9c0Sreyk 	IMSG_SIZE_CHECK(imsg, &crt);
1106416fa9c0Sreyk 	memcpy(&crt, p, sizeof(crt));
1107416fa9c0Sreyk 
1108416fa9c0Sreyk 	if ((rlay = relay_find(env, crt.relayid)) == NULL) {
1109416fa9c0Sreyk 		log_debug("%s: unknown relay", __func__);
1110416fa9c0Sreyk 		goto fail;
1111416fa9c0Sreyk 	}
1112416fa9c0Sreyk 
1113416fa9c0Sreyk 	if ((table = table_find(env, crt.id)) == NULL) {
1114416fa9c0Sreyk 		log_debug("%s: unknown table", __func__);
1115416fa9c0Sreyk 		goto fail;
1116416fa9c0Sreyk 	}
1117416fa9c0Sreyk 
1118416fa9c0Sreyk 	if ((rlt = calloc(1, sizeof(*rlt))) == NULL)
1119416fa9c0Sreyk 		goto fail;
1120416fa9c0Sreyk 
1121416fa9c0Sreyk 	rlt->rlt_table = table;
1122416fa9c0Sreyk 	rlt->rlt_mode = crt.mode;
1123118081d7Sreyk 	rlt->rlt_flags = crt.flags;
1124416fa9c0Sreyk 
1125416fa9c0Sreyk 	TAILQ_INSERT_TAIL(&rlay->rl_tables, rlt, rlt_entry);
1126416fa9c0Sreyk 
1127416fa9c0Sreyk 	DPRINTF("%s: %s %d received relay table %s for relay %s", __func__,
1128416fa9c0Sreyk 	    env->sc_ps->ps_title[privsep_process], env->sc_ps->ps_instance,
1129416fa9c0Sreyk 	    table->conf.name, rlay->rl_conf.name);
1130416fa9c0Sreyk 
1131416fa9c0Sreyk 	return (0);
1132416fa9c0Sreyk 
1133416fa9c0Sreyk  fail:
1134416fa9c0Sreyk 	free(rlt);
1135416fa9c0Sreyk 	return (-1);
1136416fa9c0Sreyk }
1137114ce177Sclaudio 
1138114ce177Sclaudio int
1139114ce177Sclaudio config_getrelayfd(struct relayd *env, struct imsg *imsg)
1140114ce177Sclaudio {
1141114ce177Sclaudio 	struct ctl_relayfd	 crfd;
1142f2f4e153Sreyk 	struct relay		*rlay = NULL;
1143f2f4e153Sreyk 	struct relay_cert	*cert;
1144114ce177Sclaudio 	u_int8_t		*p = imsg->data;
1145114ce177Sclaudio 
1146114ce177Sclaudio 	IMSG_SIZE_CHECK(imsg, &crfd);
1147114ce177Sclaudio 	memcpy(&crfd, p, sizeof(crfd));
1148114ce177Sclaudio 
1149f2f4e153Sreyk 	switch (crfd.type) {
1150f2f4e153Sreyk 	case RELAY_FD_CERT:
1151f2f4e153Sreyk 	case RELAY_FD_KEY:
115231604b98Sreyk 	case RELAY_FD_OCSP:
1153f2f4e153Sreyk 		if ((cert = cert_find(env, crfd.id)) == NULL) {
1154f2f4e153Sreyk 			if ((cert = cert_add(env, crfd.id)) == NULL)
1155f2f4e153Sreyk 				return (-1);
1156f2f4e153Sreyk 			cert->cert_relayid = crfd.relayid;
1157f2f4e153Sreyk 		}
1158f2f4e153Sreyk 		/* FALLTHROUGH */
1159f2f4e153Sreyk 	default:
1160114ce177Sclaudio 		if ((rlay = relay_find(env, crfd.relayid)) == NULL) {
1161114ce177Sclaudio 			log_debug("%s: unknown relay", __func__);
1162f2f4e153Sreyk 			return (-1);
1163f2f4e153Sreyk 		}
1164f2f4e153Sreyk 		break;
1165114ce177Sclaudio 	}
1166114ce177Sclaudio 
1167114ce177Sclaudio 	switch (crfd.type) {
1168114ce177Sclaudio 	case RELAY_FD_CERT:
1169a1416996Sclaudio 		cert->cert_fd = imsg_get_fd(imsg);
1170f2f4e153Sreyk 		break;
1171f2f4e153Sreyk 	case RELAY_FD_KEY:
1172a1416996Sclaudio 		cert->cert_key_fd = imsg_get_fd(imsg);
1173114ce177Sclaudio 		break;
117431604b98Sreyk 	case RELAY_FD_OCSP:
1175a1416996Sclaudio 		cert->cert_ocsp_fd = imsg_get_fd(imsg);
117631604b98Sreyk 		break;
1177114ce177Sclaudio 	case RELAY_FD_CACERT:
1178a1416996Sclaudio 		rlay->rl_tls_ca_fd = imsg_get_fd(imsg);
1179114ce177Sclaudio 		break;
1180114ce177Sclaudio 	case RELAY_FD_CAFILE:
1181a1416996Sclaudio 		rlay->rl_tls_cacert_fd = imsg_get_fd(imsg);
1182114ce177Sclaudio 		break;
118392388deeStb 	case RELAY_FD_CLIENTCACERT:
1184*f4d46194Sclaudio 		rlay->rl_tls_client_ca_fd = imsg_get_fd(imsg);
118592388deeStb 		break;
1186114ce177Sclaudio 	}
1187114ce177Sclaudio 
1188114ce177Sclaudio 	DPRINTF("%s: %s %d received relay fd %d type %d for relay %s", __func__,
1189114ce177Sclaudio 	    env->sc_ps->ps_title[privsep_process], env->sc_ps->ps_instance,
1190114ce177Sclaudio 	    imsg->fd, crfd.type, rlay->rl_conf.name);
1191114ce177Sclaudio 
1192114ce177Sclaudio 	return (0);
1193114ce177Sclaudio }
1194