xref: /openbsd-src/usr.sbin/relayd/relayd.c (revision 92388deed9318960f925fb877fdd678869b3dcd1)
1*92388deeStb /*	$OpenBSD: relayd.c,v 1.192 2024/10/28 19:56:18 tb Exp $	*/
2feb9ff76Sreyk 
3feb9ff76Sreyk /*
48df09a06Sreyk  * Copyright (c) 2007 - 2016 Reyk Floeter <reyk@openbsd.org>
536f5dc5eSpyr  * Copyright (c) 2006 Pierre-Yves Ritschard <pyr@openbsd.org>
6feb9ff76Sreyk  *
7feb9ff76Sreyk  * Permission to use, copy, modify, and distribute this software for any
8feb9ff76Sreyk  * purpose with or without fee is hereby granted, provided that the above
9feb9ff76Sreyk  * copyright notice and this permission notice appear in all copies.
10feb9ff76Sreyk  *
11feb9ff76Sreyk  * THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES
12feb9ff76Sreyk  * WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF
13feb9ff76Sreyk  * MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR
14feb9ff76Sreyk  * ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES
15feb9ff76Sreyk  * WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN
16feb9ff76Sreyk  * ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF
17feb9ff76Sreyk  * OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
18feb9ff76Sreyk  */
19feb9ff76Sreyk 
20feb9ff76Sreyk #include <sys/types.h>
21feb9ff76Sreyk #include <sys/queue.h>
22feb9ff76Sreyk #include <sys/socket.h>
23e938bb13Sreyk #include <sys/stat.h>
24feb9ff76Sreyk #include <sys/wait.h>
25bb8fa3feSreyk #include <sys/resource.h>
260ca734d7Sreyk 
27812c1ce4Sreyk #include <netinet/in.h>
28812c1ce4Sreyk #include <arpa/inet.h>
290ca734d7Sreyk 
30e2318a52Sderaadt #include <signal.h>
31feb9ff76Sreyk #include <string.h>
32feb9ff76Sreyk #include <stdio.h>
33feb9ff76Sreyk #include <stdlib.h>
34a2195becSreyk #include <fcntl.h>
35feb9ff76Sreyk #include <getopt.h>
36c307a266Sreyk #include <fnmatch.h>
370f12961aSreyk #include <syslog.h>
38feb9ff76Sreyk #include <err.h>
39feb9ff76Sreyk #include <errno.h>
40feb9ff76Sreyk #include <event.h>
41feb9ff76Sreyk #include <unistd.h>
427fd39c52Sreyk #include <ctype.h>
43feb9ff76Sreyk #include <pwd.h>
447ae0cc5eSreyk #include <sha1.h>
457ae0cc5eSreyk #include <md5.h>
46feb9ff76Sreyk 
4785e5f500Sclaudio #include <tls.h>
48e8fb3979Spyr 
49748ceb64Sreyk #include "relayd.h"
50feb9ff76Sreyk 
51e2318a52Sderaadt #define MAXIMUM(a, b)	(((a) > (b)) ? (a) : (b))
52e2318a52Sderaadt 
53feb9ff76Sreyk __dead void	 usage(void);
54feb9ff76Sreyk 
55a2195becSreyk int		 parent_configure(struct relayd *);
560dcba380Scamield void		 parent_configure_done(struct relayd *);
57a2195becSreyk void		 parent_reload(struct relayd *, u_int, const char *);
580325c666Sreyk void		 parent_sig_handler(int, short, void *);
590325c666Sreyk void		 parent_shutdown(struct relayd *);
600325c666Sreyk int		 parent_dispatch_pfe(int, struct privsep_proc *, struct imsg *);
610325c666Sreyk int		 parent_dispatch_hce(int, struct privsep_proc *, struct imsg *);
62b1feadc4Sbluhm int		 parent_dispatch_relay(int, struct privsep_proc *,
63b1feadc4Sbluhm 		    struct imsg *);
643d77879fSreyk int		 parent_dispatch_ca(int, struct privsep_proc *,
653d77879fSreyk 		    struct imsg *);
663c03a838Sreyk int		 bindany(struct ctl_bindany *);
679c908525Sclaudio void		 parent_tls_ticket_rekey(int, short, void *);
68feb9ff76Sreyk 
69748ceb64Sreyk struct relayd			*relayd_env;
704156152fSreyk 
710325c666Sreyk static struct privsep_proc procs[] = {
720325c666Sreyk 	{ "pfe",	PROC_PFE, parent_dispatch_pfe, pfe },
730325c666Sreyk 	{ "hce",	PROC_HCE, parent_dispatch_hce, hce },
743d77879fSreyk 	{ "relay",	PROC_RELAY, parent_dispatch_relay, relay },
753d77879fSreyk 	{ "ca",		PROC_CA, parent_dispatch_ca, ca }
760325c666Sreyk };
77feb9ff76Sreyk 
78488a4384Sderaadt enum privsep_procid privsep_process;
79488a4384Sderaadt 
80feb9ff76Sreyk void
810325c666Sreyk parent_sig_handler(int sig, short event, void *arg)
82feb9ff76Sreyk {
830325c666Sreyk 	struct privsep	*ps = arg;
84feb9ff76Sreyk 
85feb9ff76Sreyk 	switch (sig) {
86feb9ff76Sreyk 	case SIGTERM:
87feb9ff76Sreyk 	case SIGINT:
880325c666Sreyk 		parent_shutdown(ps->ps_env);
89feb9ff76Sreyk 		break;
90feb9ff76Sreyk 	case SIGHUP:
91a2195becSreyk 		log_info("%s: reload requested with SIGHUP", __func__);
92a2195becSreyk 
93a2195becSreyk 		/*
94a2195becSreyk 		 * This is safe because libevent uses async signal handlers
95a2195becSreyk 		 * that run in the event loop and not in signal context.
96a2195becSreyk 		 */
97a2195becSreyk 		parent_reload(ps->ps_env, CONFIG_RELOAD, NULL);
98feb9ff76Sreyk 		break;
99c7867281Sreyk 	case SIGPIPE:
100fb6ac98aSreyk 	case SIGUSR1:
101c7867281Sreyk 		/* ignore */
102c7867281Sreyk 		break;
103feb9ff76Sreyk 	default:
104feb9ff76Sreyk 		fatalx("unexpected signal");
105feb9ff76Sreyk 	}
106feb9ff76Sreyk }
107feb9ff76Sreyk 
108feb9ff76Sreyk __dead void
109feb9ff76Sreyk usage(void)
110feb9ff76Sreyk {
111feb9ff76Sreyk 	extern char	*__progname;
112feb9ff76Sreyk 
1133d5126eaSsobrado 	fprintf(stderr, "usage: %s [-dnv] [-D macro=value] [-f file]\n",
1143d5126eaSsobrado 	    __progname);
115feb9ff76Sreyk 	exit(1);
116feb9ff76Sreyk }
117feb9ff76Sreyk 
118034b8021Sreyk int
119034b8021Sreyk main(int argc, char *argv[])
120feb9ff76Sreyk {
121feb9ff76Sreyk 	int			 c;
122a2195becSreyk 	int			 debug = 0, verbose = 0;
123a2195becSreyk 	u_int32_t		 opts = 0;
124748ceb64Sreyk 	struct relayd		*env;
1250325c666Sreyk 	struct privsep		*ps;
126a2195becSreyk 	const char		*conffile = CONF_FILE;
1273d6ff6edSreyk 	enum privsep_procid	 proc_id = PROC_PARENT;
1283d6ff6edSreyk 	int			 proc_instance = 0;
1293d6ff6edSreyk 	const char		*errp, *title = NULL;
1303d6ff6edSreyk 	int			 argc0 = argc;
131feb9ff76Sreyk 
1323d6ff6edSreyk 	while ((c = getopt(argc, argv, "dD:nI:P:f:v")) != -1) {
133feb9ff76Sreyk 		switch (c) {
134feb9ff76Sreyk 		case 'd':
1359648e8e4Sreyk 			debug = 2;
136feb9ff76Sreyk 			break;
137e97970e4Sreyk 		case 'D':
138e97970e4Sreyk 			if (cmdline_symset(optarg) < 0)
139e97970e4Sreyk 				log_warnx("could not parse macro definition %s",
140e97970e4Sreyk 				    optarg);
141e97970e4Sreyk 			break;
142feb9ff76Sreyk 		case 'n':
1439648e8e4Sreyk 			debug = 2;
144748ceb64Sreyk 			opts |= RELAYD_OPT_NOACTION;
145feb9ff76Sreyk 			break;
146feb9ff76Sreyk 		case 'f':
147feb9ff76Sreyk 			conffile = optarg;
148feb9ff76Sreyk 			break;
149feb9ff76Sreyk 		case 'v':
150a2195becSreyk 			verbose++;
151748ceb64Sreyk 			opts |= RELAYD_OPT_VERBOSE;
152feb9ff76Sreyk 			break;
1533d6ff6edSreyk 		case 'P':
1543d6ff6edSreyk 			title = optarg;
1553d6ff6edSreyk 			proc_id = proc_getid(procs, nitems(procs), title);
1563d6ff6edSreyk 			if (proc_id == PROC_MAX)
1573d6ff6edSreyk 				fatalx("invalid process name");
1583d6ff6edSreyk 			break;
1593d6ff6edSreyk 		case 'I':
1603d6ff6edSreyk 			proc_instance = strtonum(optarg, 0,
1613d6ff6edSreyk 			    PROC_MAX_INSTANCES, &errp);
1623d6ff6edSreyk 			if (errp)
1633d6ff6edSreyk 				fatalx("invalid process instance");
1643d6ff6edSreyk 			break;
165feb9ff76Sreyk 		default:
166feb9ff76Sreyk 			usage();
167feb9ff76Sreyk 		}
168feb9ff76Sreyk 	}
169feb9ff76Sreyk 
1700f12961aSreyk 	/* log to stderr until daemonized */
1710f12961aSreyk 	log_init(debug ? debug : 1, LOG_DAEMON);
172c413bde0Sokan 
173fde55bc4Spyr 	argc -= optind;
174fde55bc4Spyr 	if (argc > 0)
175fde55bc4Spyr 		usage();
176fde55bc4Spyr 
177a2195becSreyk 	if ((env = calloc(1, sizeof(*env))) == NULL ||
1780325c666Sreyk 	    (ps = calloc(1, sizeof(*ps))) == NULL)
179feb9ff76Sreyk 		exit(1);
1800325c666Sreyk 
181748ceb64Sreyk 	relayd_env = env;
1820325c666Sreyk 	env->sc_ps = ps;
1830325c666Sreyk 	ps->ps_env = env;
18461da45abSblambert 	TAILQ_INIT(&ps->ps_rcsocks);
185a2195becSreyk 	env->sc_conffile = conffile;
186586b5f8aSreyk 	env->sc_conf.opts = opts;
1876e07057bSblambert 	TAILQ_INIT(&env->sc_hosts);
1886e07057bSblambert 	TAILQ_INIT(&env->sc_sessions);
189005c709bSbenno 	env->sc_rtable = getrtable();
1909c908525Sclaudio 	/* initialize the TLS session id to a random key for all relay procs */
191586b5f8aSreyk 	arc4random_buf(env->sc_conf.tls_sid, sizeof(env->sc_conf.tls_sid));
192feb9ff76Sreyk 
193a2195becSreyk 	if (parse_config(env->sc_conffile, env) == -1)
194a2195becSreyk 		exit(1);
195a2195becSreyk 
1962edd718bSreyk 	if (debug)
197586b5f8aSreyk 		env->sc_conf.opts |= RELAYD_OPT_LOGUPDATE;
198feb9ff76Sreyk 
199feb9ff76Sreyk 	if (geteuid())
200feb9ff76Sreyk 		errx(1, "need root privileges");
201feb9ff76Sreyk 
2020325c666Sreyk 	if ((ps->ps_pw =  getpwnam(RELAYD_USER)) == NULL)
203748ceb64Sreyk 		errx(1, "unknown user %s", RELAYD_USER);
204feb9ff76Sreyk 
2050f12961aSreyk 	log_init(debug, LOG_DAEMON);
206871fc12cSreyk 	log_setverbose(verbose);
207feb9ff76Sreyk 
208586b5f8aSreyk 	if (env->sc_conf.opts & RELAYD_OPT_NOACTION)
209a2195becSreyk 		ps->ps_noaction = 1;
210feb9ff76Sreyk 
211586b5f8aSreyk 	ps->ps_instances[PROC_RELAY] = env->sc_conf.prefork_relay;
212586b5f8aSreyk 	ps->ps_instances[PROC_CA] = env->sc_conf.prefork_relay;
2133d6ff6edSreyk 	ps->ps_instance = proc_instance;
2143d6ff6edSreyk 	if (title != NULL)
2153d6ff6edSreyk 		ps->ps_title[proc_id] = title;
2169326d639Sreyk 
2173d6ff6edSreyk 	/* only the parent returns */
21838b34180Sbluhm 	proc_init(ps, procs, nitems(procs), debug, argc0, argv, proc_id);
2193d6ff6edSreyk 
2200f12961aSreyk 	log_procinit("parent");
2213d6ff6edSreyk 
2223d6ff6edSreyk 	if (ps->ps_noaction == 0)
2233d6ff6edSreyk 		log_info("startup");
224feb9ff76Sreyk 
22515e2c682Smestre 	if (unveil("/", "rx") == -1)
226bc5a8259Sbeck 		err(1, "unveil /");
22715e2c682Smestre 	if (unveil(NULL, NULL) == -1)
22815e2c682Smestre 		err(1, "unveil");
22915e2c682Smestre 
230feb9ff76Sreyk 	event_init();
231feb9ff76Sreyk 
2320325c666Sreyk 	signal_set(&ps->ps_evsigint, SIGINT, parent_sig_handler, ps);
2330325c666Sreyk 	signal_set(&ps->ps_evsigterm, SIGTERM, parent_sig_handler, ps);
2340325c666Sreyk 	signal_set(&ps->ps_evsighup, SIGHUP, parent_sig_handler, ps);
2350325c666Sreyk 	signal_set(&ps->ps_evsigpipe, SIGPIPE, parent_sig_handler, ps);
236fb6ac98aSreyk 	signal_set(&ps->ps_evsigusr1, SIGUSR1, parent_sig_handler, ps);
237c7867281Sreyk 
2380325c666Sreyk 	signal_add(&ps->ps_evsigint, NULL);
2390325c666Sreyk 	signal_add(&ps->ps_evsigterm, NULL);
2400325c666Sreyk 	signal_add(&ps->ps_evsighup, NULL);
2410325c666Sreyk 	signal_add(&ps->ps_evsigpipe, NULL);
242fb6ac98aSreyk 	signal_add(&ps->ps_evsigusr1, NULL);
243feb9ff76Sreyk 
2443d6ff6edSreyk 	proc_connect(ps);
245a2195becSreyk 
246627e062aSbluhm 	relay_http(NULL);
247a2195becSreyk 	if (load_config(env->sc_conffile, env) == -1) {
248a2195becSreyk 		proc_kill(env->sc_ps);
249a2195becSreyk 		exit(1);
250a2195becSreyk 	}
251a2195becSreyk 
252586b5f8aSreyk 	if (env->sc_conf.opts & RELAYD_OPT_NOACTION) {
253a2195becSreyk 		fprintf(stderr, "configuration OK\n");
254a2195becSreyk 		proc_kill(env->sc_ps);
255a2195becSreyk 		exit(0);
256a2195becSreyk 	}
257a2195becSreyk 
2589c908525Sclaudio 	/* rekey the TLS tickets before pushing the config */
2599c908525Sclaudio 	parent_tls_ticket_rekey(0, 0, env);
260a2195becSreyk 	if (parent_configure(env) == -1)
261a2195becSreyk 		fatalx("configuration failed");
262a2195becSreyk 
26334438db4Sreyk 	init_routes(env);
26434438db4Sreyk 
265feb9ff76Sreyk 	event_dispatch();
266feb9ff76Sreyk 
2670325c666Sreyk 	parent_shutdown(env);
26834926236Sjsg 	/* NOTREACHED */
269a2195becSreyk 
270feb9ff76Sreyk 	return (0);
271feb9ff76Sreyk }
272feb9ff76Sreyk 
273a2195becSreyk int
274a2195becSreyk parent_configure(struct relayd *env)
275a2195becSreyk {
276a2195becSreyk 	struct table		*tb;
277a2195becSreyk 	struct rdr		*rdr;
278a2195becSreyk 	struct router		*rt;
279a2195becSreyk 	struct protocol		*proto;
280a2195becSreyk 	struct relay		*rlay;
281a2195becSreyk 	int			 id;
28205b29ae0Sbenno 	int			 ret = -1;
283a2195becSreyk 
284a2195becSreyk 	TAILQ_FOREACH(tb, env->sc_tables, entry)
285a2195becSreyk 		config_settable(env, tb);
286a2195becSreyk 	TAILQ_FOREACH(rdr, env->sc_rdrs, entry)
287a2195becSreyk 		config_setrdr(env, rdr);
288a2195becSreyk 	TAILQ_FOREACH(rt, env->sc_rts, rt_entry)
289a2195becSreyk 		config_setrt(env, rt);
290a2195becSreyk 	TAILQ_FOREACH(proto, env->sc_protos, entry)
291a2195becSreyk 		config_setproto(env, proto);
292cb8b0e56Sreyk 	TAILQ_FOREACH(proto, env->sc_protos, entry)
293cb8b0e56Sreyk 		config_setrule(env, proto);
294cf39ad79Sreyk 	TAILQ_FOREACH(rlay, env->sc_relays, rl_entry) {
2957bb52228Sreyk 		/* Check for TLS Inspection */
2967bb52228Sreyk 		if ((rlay->rl_conf.flags & (F_TLS|F_TLSCLIENT)) ==
297114ce177Sclaudio 		    (F_TLS|F_TLSCLIENT) && rlay->rl_tls_cacert_fd != -1)
2987bb52228Sreyk 			rlay->rl_conf.flags |= F_TLSINSPECT;
299cf39ad79Sreyk 
300a2195becSreyk 		config_setrelay(env, rlay);
301cf39ad79Sreyk 	}
302a2195becSreyk 
3033d77879fSreyk 	/* HCE, PFE, CA and the relays need to reload their config. */
304586b5f8aSreyk 	env->sc_reload = 2 + (2 * env->sc_conf.prefork_relay);
3050dcba380Scamield 
306a2195becSreyk 	for (id = 0; id < PROC_MAX; id++) {
307a2195becSreyk 		if (id == privsep_process)
308a2195becSreyk 			continue;
309c2c37c5dSreyk 		proc_compose_imsg(env->sc_ps, id, -1, IMSG_CFG_DONE, -1,
31005b29ae0Sbenno 		    -1, &env->sc_conf, sizeof(env->sc_conf));
311a2195becSreyk 	}
312a2195becSreyk 
313a2195becSreyk 	ret = 0;
314a2195becSreyk 
3153d77879fSreyk 	config_purge(env, CONFIG_ALL & ~CONFIG_RELAYS);
316a2195becSreyk 	return (ret);
317a2195becSreyk }
318a2195becSreyk 
319a2195becSreyk void
320a2195becSreyk parent_reload(struct relayd *env, u_int reset, const char *filename)
321a2195becSreyk {
322a2195becSreyk 	if (env->sc_reload) {
323a2195becSreyk 		log_debug("%s: already in progress: %d pending",
324a2195becSreyk 		    __func__, env->sc_reload);
325a2195becSreyk 		return;
326a2195becSreyk 	}
327a2195becSreyk 
328a2195becSreyk 	/* Switch back to the default config file */
329a2195becSreyk 	if (filename == NULL || *filename == '\0')
330a2195becSreyk 		filename = env->sc_conffile;
331a2195becSreyk 
332a2195becSreyk 	log_debug("%s: level %d config file %s", __func__, reset, filename);
333a2195becSreyk 
334a2195becSreyk 	config_purge(env, CONFIG_ALL);
335a2195becSreyk 
336a2195becSreyk 	if (reset == CONFIG_RELOAD) {
337a2195becSreyk 		if (load_config(filename, env) == -1) {
338a2195becSreyk 			log_debug("%s: failed to load config file %s",
339a2195becSreyk 			    __func__, filename);
340a2195becSreyk 		}
341a2195becSreyk 
342a2195becSreyk 		config_setreset(env, CONFIG_ALL);
343a2195becSreyk 
344a2195becSreyk 		if (parent_configure(env) == -1) {
345a2195becSreyk 			log_debug("%s: failed to commit config from %s",
346a2195becSreyk 			    __func__, filename);
347a2195becSreyk 		}
348a2195becSreyk 	} else
349a2195becSreyk 		config_setreset(env, reset);
350a2195becSreyk }
351a2195becSreyk 
352feb9ff76Sreyk void
3530dcba380Scamield parent_configure_done(struct relayd *env)
3540dcba380Scamield {
3550dcba380Scamield 	int	 id;
3560dcba380Scamield 
3570dcba380Scamield 	if (env->sc_reload == 0) {
3580dcba380Scamield 		log_warnx("%s: configuration already finished", __func__);
3590dcba380Scamield 		return;
3600dcba380Scamield 	}
3610dcba380Scamield 
3620dcba380Scamield 	env->sc_reload--;
3630dcba380Scamield 	if (env->sc_reload == 0) {
3640dcba380Scamield 		for (id = 0; id < PROC_MAX; id++) {
3650dcba380Scamield 			if (id == privsep_process)
3660dcba380Scamield 				continue;
3670dcba380Scamield 
368c2c37c5dSreyk 			proc_compose(env->sc_ps, id, IMSG_CTL_START, NULL, 0);
3690dcba380Scamield 		}
3700dcba380Scamield 	}
3710dcba380Scamield }
3720dcba380Scamield 
3730dcba380Scamield void
3740325c666Sreyk parent_shutdown(struct relayd *env)
375feb9ff76Sreyk {
376a2195becSreyk 	config_purge(env, CONFIG_ALL);
377a2195becSreyk 
3780325c666Sreyk 	proc_kill(env->sc_ps);
3790325c666Sreyk 	control_cleanup(&env->sc_ps->ps_csock);
3802edd718bSreyk 	carp_demote_shutdown();
3810325c666Sreyk 
3820325c666Sreyk 	free(env->sc_ps);
3830325c666Sreyk 	free(env);
3840325c666Sreyk 
3850325c666Sreyk 	log_info("parent terminating, pid %d", getpid());
3860325c666Sreyk 
387feb9ff76Sreyk 	exit(0);
388feb9ff76Sreyk }
389feb9ff76Sreyk 
3900229c564Spyr int
3910325c666Sreyk parent_dispatch_pfe(int fd, struct privsep_proc *p, struct imsg *imsg)
3920229c564Spyr {
393d0cb169fSreyk 	struct privsep		*ps = p->p_ps;
394d0cb169fSreyk 	struct relayd		*env = ps->ps_env;
3952edd718bSreyk 	struct ctl_demote	 demote;
39634438db4Sreyk 	struct ctl_netroute	 crt;
397a2195becSreyk 	u_int			 v;
398a2195becSreyk 	char			*str = NULL;
399feb9ff76Sreyk 
4000325c666Sreyk 	switch (imsg->hdr.type) {
4012edd718bSreyk 	case IMSG_DEMOTE:
4020325c666Sreyk 		IMSG_SIZE_CHECK(imsg, &demote);
4030325c666Sreyk 		memcpy(&demote, imsg->data, sizeof(demote));
4042edd718bSreyk 		carp_demote_set(demote.group, demote.level);
4052edd718bSreyk 		break;
40634438db4Sreyk 	case IMSG_RTMSG:
4070325c666Sreyk 		IMSG_SIZE_CHECK(imsg, &crt);
4080325c666Sreyk 		memcpy(&crt, imsg->data, sizeof(crt));
40934438db4Sreyk 		pfe_route(env, &crt);
41034438db4Sreyk 		break;
411a2195becSreyk 	case IMSG_CTL_RESET:
412a2195becSreyk 		IMSG_SIZE_CHECK(imsg, &v);
413a2195becSreyk 		memcpy(&v, imsg->data, sizeof(v));
414a2195becSreyk 		parent_reload(env, v, NULL);
415a2195becSreyk 		break;
416c8bdf044Spyr 	case IMSG_CTL_RELOAD:
417a2195becSreyk 		if (IMSG_DATA_SIZE(imsg) > 0)
418a2195becSreyk 			str = get_string(imsg->data, IMSG_DATA_SIZE(imsg));
419a2195becSreyk 		parent_reload(env, CONFIG_RELOAD, str);
420a2195becSreyk 		free(str);
421a2195becSreyk 		break;
422a2195becSreyk 	case IMSG_CTL_SHUTDOWN:
423a2195becSreyk 		parent_shutdown(env);
424a2195becSreyk 		break;
425a2195becSreyk 	case IMSG_CFG_DONE:
4260dcba380Scamield 		parent_configure_done(env);
427c8bdf044Spyr 		break;
428c26b8e61Smartijn 	case IMSG_AGENTXSOCK:
4294172793dSdv 		agentx_setsock(env, p->p_id);
4306e07057bSblambert 		break;
431feb9ff76Sreyk 	default:
4320325c666Sreyk 		return (-1);
433feb9ff76Sreyk 	}
434feb9ff76Sreyk 
4350325c666Sreyk 	return (0);
4360325c666Sreyk }
4370325c666Sreyk 
4380325c666Sreyk int
4390325c666Sreyk parent_dispatch_hce(int fd, struct privsep_proc *p, struct imsg *imsg)
440feb9ff76Sreyk {
441d0cb169fSreyk 	struct privsep		*ps = p->p_ps;
442d0cb169fSreyk 	struct relayd		*env = ps->ps_env;
4434156152fSreyk 	struct ctl_script	 scr;
444feb9ff76Sreyk 
4450325c666Sreyk 	switch (imsg->hdr.type) {
4464156152fSreyk 	case IMSG_SCRIPT:
4470325c666Sreyk 		IMSG_SIZE_CHECK(imsg, &scr);
4480325c666Sreyk 		bcopy(imsg->data, &scr, sizeof(scr));
4494156152fSreyk 		scr.retval = script_exec(env, &scr);
450c2c37c5dSreyk 		proc_compose(ps, PROC_HCE, IMSG_SCRIPT, &scr, sizeof(scr));
4514156152fSreyk 		break;
452a2195becSreyk 	case IMSG_CFG_DONE:
4530dcba380Scamield 		parent_configure_done(env);
454fe250497Sreyk 		break;
455feb9ff76Sreyk 	default:
4560325c666Sreyk 		return (-1);
457feb9ff76Sreyk 	}
458feb9ff76Sreyk 
4590325c666Sreyk 	return (0);
4600325c666Sreyk }
4610325c666Sreyk 
4620325c666Sreyk int
4630325c666Sreyk parent_dispatch_relay(int fd, struct privsep_proc *p, struct imsg *imsg)
4642edd718bSreyk {
465d0cb169fSreyk 	struct privsep		*ps = p->p_ps;
466d0cb169fSreyk 	struct relayd		*env = ps->ps_env;
4673c03a838Sreyk 	struct ctl_bindany	 bnd;
4683c03a838Sreyk 	int			 s;
4692edd718bSreyk 
4700325c666Sreyk 	switch (imsg->hdr.type) {
4713c03a838Sreyk 	case IMSG_BINDANY:
4720325c666Sreyk 		IMSG_SIZE_CHECK(imsg, &bnd);
4730325c666Sreyk 		bcopy(imsg->data, &bnd, sizeof(bnd));
474586b5f8aSreyk 		if (bnd.bnd_proc > env->sc_conf.prefork_relay)
475efc39811Sbenno 			fatalx("%s: invalid relay proc", __func__);
4763c03a838Sreyk 		switch (bnd.bnd_proto) {
4773c03a838Sreyk 		case IPPROTO_TCP:
4783c03a838Sreyk 		case IPPROTO_UDP:
4793c03a838Sreyk 			break;
4803c03a838Sreyk 		default:
481efc39811Sbenno 			fatalx("%s: requested socket "
482efc39811Sbenno 			    "for invalid protocol", __func__);
4833c03a838Sreyk 			/* NOTREACHED */
4843c03a838Sreyk 		}
4853c03a838Sreyk 		s = bindany(&bnd);
4860325c666Sreyk 		proc_compose_imsg(ps, PROC_RELAY, bnd.bnd_proc,
487c2c37c5dSreyk 		    IMSG_BINDANY, -1, s, &bnd.bnd_id, sizeof(bnd.bnd_id));
4883c03a838Sreyk 		break;
489a2195becSreyk 	case IMSG_CFG_DONE:
4900dcba380Scamield 		parent_configure_done(env);
491a2195becSreyk 		break;
4922edd718bSreyk 	default:
4930325c666Sreyk 		return (-1);
4942edd718bSreyk 	}
4950325c666Sreyk 
4960325c666Sreyk 	return (0);
4972edd718bSreyk }
4982edd718bSreyk 
4993d77879fSreyk int
5003d77879fSreyk parent_dispatch_ca(int fd, struct privsep_proc *p, struct imsg *imsg)
5013d77879fSreyk {
502d0cb169fSreyk 	struct privsep		*ps = p->p_ps;
503d0cb169fSreyk 	struct relayd		*env = ps->ps_env;
5043d77879fSreyk 
5053d77879fSreyk 	switch (imsg->hdr.type) {
5063d77879fSreyk 	case IMSG_CFG_DONE:
5073d77879fSreyk 		parent_configure_done(env);
5083d77879fSreyk 		break;
5093d77879fSreyk 	default:
5103d77879fSreyk 		return (-1);
5113d77879fSreyk 	}
5123d77879fSreyk 
5133d77879fSreyk 	return (0);
5143d77879fSreyk }
5153d77879fSreyk 
516a2195becSreyk void
5172c8c2287Sclaudio purge_table(struct relayd *env, struct tablelist *head, struct table *table)
518a2195becSreyk {
519a2195becSreyk 	struct host		*host;
520a2195becSreyk 
521a2195becSreyk 	while ((host = TAILQ_FIRST(&table->hosts)) != NULL) {
522a2195becSreyk 		TAILQ_REMOVE(&table->hosts, host, entry);
5232c8c2287Sclaudio 		TAILQ_REMOVE(&env->sc_hosts, host, globalentry);
524a2195becSreyk 		if (event_initialized(&host->cte.ev)) {
525a2195becSreyk 			event_del(&host->cte.ev);
526a2195becSreyk 			close(host->cte.s);
527a2195becSreyk 		}
528a2195becSreyk 		ibuf_free(host->cte.buf);
52985e5f500Sclaudio 		tls_free(host->cte.tls);
530a2195becSreyk 		free(host);
531a2195becSreyk 	}
532a2195becSreyk 	free(table->sendbuf);
5333f229715Srob 	ibuf_free(table->sendbinbuf);
53485e5f500Sclaudio 	tls_config_free(table->tls_cfg);
535a2195becSreyk 
536a2195becSreyk 	if (head != NULL)
537a2195becSreyk 		TAILQ_REMOVE(head, table, entry);
538a2195becSreyk 	free(table);
539a2195becSreyk }
540a2195becSreyk 
541a2195becSreyk void
54202a7d0f3Sfcambus purge_key(char **key, off_t len)
5433d77879fSreyk {
54402a7d0f3Sfcambus 	freezero(*key, len);
5453d77879fSreyk 
54602a7d0f3Sfcambus 	*key = NULL;
5473d77879fSreyk }
5483d77879fSreyk 
5493d77879fSreyk void
550a2195becSreyk purge_relay(struct relayd *env, struct relay *rlay)
551a2195becSreyk {
552a2195becSreyk 	struct rsession		*con;
553416fa9c0Sreyk 	struct relay_table	*rlt;
554f2f4e153Sreyk 	struct relay_cert	*cert, *tmpcert;
555a2195becSreyk 
556a2195becSreyk 	/* shutdown and remove relay */
557a2195becSreyk 	if (event_initialized(&rlay->rl_ev))
558a2195becSreyk 		event_del(&rlay->rl_ev);
559a2195becSreyk 	close(rlay->rl_s);
560a2195becSreyk 	TAILQ_REMOVE(env->sc_relays, rlay, rl_entry);
561a2195becSreyk 
562a2195becSreyk 	/* cleanup sessions */
563a2195becSreyk 	while ((con =
564a2195becSreyk 	    SPLAY_ROOT(&rlay->rl_sessions)) != NULL)
5650be9d00aSbenno 		relay_close(con, NULL, 0);
566a2195becSreyk 
567a2195becSreyk 	/* cleanup relay */
568a2195becSreyk 	if (rlay->rl_bev != NULL)
569a2195becSreyk 		bufferevent_free(rlay->rl_bev);
570a2195becSreyk 	if (rlay->rl_dstbev != NULL)
571a2195becSreyk 		bufferevent_free(rlay->rl_dstbev);
572a2195becSreyk 
5737bb52228Sreyk 	purge_key(&rlay->rl_tls_cakey, rlay->rl_conf.tls_cakey_len);
5743d77879fSreyk 
5757bb52228Sreyk 	if (rlay->rl_tls_pkey != NULL) {
5767bb52228Sreyk 		EVP_PKEY_free(rlay->rl_tls_pkey);
5777bb52228Sreyk 		rlay->rl_tls_pkey = NULL;
5783d77879fSreyk 	}
5797bb52228Sreyk 	if (rlay->rl_tls_cacertx509 != NULL) {
5807bb52228Sreyk 		X509_free(rlay->rl_tls_cacertx509);
5817bb52228Sreyk 		rlay->rl_tls_cacertx509 = NULL;
58200ae3104Sreyk 	}
5837bb52228Sreyk 	if (rlay->rl_tls_capkey != NULL) {
5847bb52228Sreyk 		EVP_PKEY_free(rlay->rl_tls_capkey);
5857bb52228Sreyk 		rlay->rl_tls_capkey = NULL;
58600ae3104Sreyk 	}
5873d77879fSreyk 
58885e5f500Sclaudio 	tls_free(rlay->rl_tls_ctx);
58985e5f500Sclaudio 	tls_config_free(rlay->rl_tls_cfg);
59085e5f500Sclaudio 	tls_config_free(rlay->rl_tls_client_cfg);
591a2195becSreyk 
592416fa9c0Sreyk 	while ((rlt = TAILQ_FIRST(&rlay->rl_tables))) {
593416fa9c0Sreyk 		TAILQ_REMOVE(&rlay->rl_tables, rlt, rlt_entry);
594416fa9c0Sreyk 		free(rlt);
595416fa9c0Sreyk 	}
596416fa9c0Sreyk 
597f2f4e153Sreyk 	TAILQ_FOREACH_SAFE(cert, env->sc_certs, cert_entry, tmpcert) {
598f2f4e153Sreyk 		if (rlay->rl_conf.id != cert->cert_relayid)
599f2f4e153Sreyk 			continue;
600f2f4e153Sreyk 		if (cert->cert_fd != -1)
601f2f4e153Sreyk 			close(cert->cert_fd);
602f2f4e153Sreyk 		if (cert->cert_key_fd != -1)
603f2f4e153Sreyk 			close(cert->cert_key_fd);
60431604b98Sreyk 		if (cert->cert_ocsp_fd != -1)
60531604b98Sreyk 			close(cert->cert_ocsp_fd);
606f2f4e153Sreyk 		if (cert->cert_pkey != NULL)
607f2f4e153Sreyk 			EVP_PKEY_free(cert->cert_pkey);
608f2f4e153Sreyk 		TAILQ_REMOVE(env->sc_certs, cert, cert_entry);
609f2f4e153Sreyk 		free(cert);
610f2f4e153Sreyk 	}
611f2f4e153Sreyk 
612a2195becSreyk 	free(rlay);
613a2195becSreyk }
614a2195becSreyk 
615cb8b0e56Sreyk struct kv *
616c9822c56Sreyk kv_add(struct kvtree *keys, char *key, char *value, int unique)
617cb8b0e56Sreyk {
618c307a266Sreyk 	struct kv	*kv, *oldkv;
619cb8b0e56Sreyk 
620cb8b0e56Sreyk 	if (key == NULL)
621cb8b0e56Sreyk 		return (NULL);
622cb8b0e56Sreyk 	if ((kv = calloc(1, sizeof(*kv))) == NULL)
623cb8b0e56Sreyk 		return (NULL);
624c9822c56Sreyk 	if ((kv->kv_key = strdup(key)) == NULL)
625c9822c56Sreyk 		goto fail;
626cb8b0e56Sreyk 	if (value != NULL &&
627c9822c56Sreyk 	    (kv->kv_value = strdup(value)) == NULL)
628c9822c56Sreyk 		goto fail;
629c307a266Sreyk 	TAILQ_INIT(&kv->kv_children);
630cb8b0e56Sreyk 
631c307a266Sreyk 	if ((oldkv = RB_INSERT(kvtree, keys, kv)) != NULL) {
632c9822c56Sreyk 		/*
633c9822c56Sreyk 		 * return error if the key should occur only once,
634c9822c56Sreyk 		 * or add it to a list attached to the key's node.
635c9822c56Sreyk 		 */
636c9822c56Sreyk 		if (unique)
637c9822c56Sreyk 			goto fail;
638c307a266Sreyk 		TAILQ_INSERT_TAIL(&oldkv->kv_children, kv, kv_entry);
639c307a266Sreyk 		kv->kv_parent = oldkv;
640c307a266Sreyk 	}
641cb8b0e56Sreyk 
642cb8b0e56Sreyk 	return (kv);
643c9822c56Sreyk  fail:
644c9822c56Sreyk 	free(kv->kv_key);
645c9822c56Sreyk 	free(kv->kv_value);
646c9822c56Sreyk 	free(kv);
647c9822c56Sreyk 	return (NULL);
648cb8b0e56Sreyk }
649cb8b0e56Sreyk 
650cb8b0e56Sreyk int
651cb8b0e56Sreyk kv_set(struct kv *kv, char *fmt, ...)
652cb8b0e56Sreyk {
653cb8b0e56Sreyk 	va_list		  ap;
654cb8b0e56Sreyk 	char		*value = NULL;
655c307a266Sreyk 	struct kv	*ckv;
6566eb056bfSmbuhl 	int		 ret;
657cb8b0e56Sreyk 
658cb8b0e56Sreyk 	va_start(ap, fmt);
6596eb056bfSmbuhl 	ret = vasprintf(&value, fmt, ap);
660cb8b0e56Sreyk 	va_end(ap);
6616eb056bfSmbuhl  	if (ret == -1)
6626eb056bfSmbuhl 		return (-1);
663cb8b0e56Sreyk 
664c307a266Sreyk 	/* Remove all children */
665c307a266Sreyk 	while ((ckv = TAILQ_FIRST(&kv->kv_children)) != NULL) {
666c307a266Sreyk 		TAILQ_REMOVE(&kv->kv_children, ckv, kv_entry);
667c307a266Sreyk 		kv_free(ckv);
668c307a266Sreyk 		free(ckv);
669c307a266Sreyk 	}
670c307a266Sreyk 
671c307a266Sreyk 	/* Set the new value */
672cb8b0e56Sreyk 	free(kv->kv_value);
673cb8b0e56Sreyk 	kv->kv_value = value;
674cb8b0e56Sreyk 
675cb8b0e56Sreyk 	return (0);
676cb8b0e56Sreyk }
677cb8b0e56Sreyk 
678cb8b0e56Sreyk int
679cb8b0e56Sreyk kv_setkey(struct kv *kv, char *fmt, ...)
680cb8b0e56Sreyk {
681cb8b0e56Sreyk 	va_list  ap;
682cb8b0e56Sreyk 	char	*key = NULL;
6836eb056bfSmbuhl 	int	 ret;
684cb8b0e56Sreyk 
685cb8b0e56Sreyk 	va_start(ap, fmt);
6866eb056bfSmbuhl 	ret = vasprintf(&key, fmt, ap);
687cb8b0e56Sreyk 	va_end(ap);
6886eb056bfSmbuhl 	if (ret == -1)
6896eb056bfSmbuhl 		return (-1);
690cb8b0e56Sreyk 
691cb8b0e56Sreyk 	free(kv->kv_key);
692cb8b0e56Sreyk 	kv->kv_key = key;
693cb8b0e56Sreyk 
694cb8b0e56Sreyk 	return (0);
695cb8b0e56Sreyk }
696cb8b0e56Sreyk 
697cb8b0e56Sreyk void
698c307a266Sreyk kv_delete(struct kvtree *keys, struct kv *kv)
699cb8b0e56Sreyk {
700c307a266Sreyk 	struct kv	*ckv;
701c307a266Sreyk 
702c307a266Sreyk 	RB_REMOVE(kvtree, keys, kv);
703c307a266Sreyk 
704c307a266Sreyk 	/* Remove all children */
705c307a266Sreyk 	while ((ckv = TAILQ_FIRST(&kv->kv_children)) != NULL) {
706c307a266Sreyk 		TAILQ_REMOVE(&kv->kv_children, ckv, kv_entry);
707c307a266Sreyk 		kv_free(ckv);
708c307a266Sreyk 		free(ckv);
709c307a266Sreyk 	}
710c307a266Sreyk 
711cb8b0e56Sreyk 	kv_free(kv);
712cb8b0e56Sreyk 	free(kv);
713cb8b0e56Sreyk }
714cb8b0e56Sreyk 
715cb8b0e56Sreyk struct kv *
716c307a266Sreyk kv_extend(struct kvtree *keys, struct kv *kv, char *value)
717cb8b0e56Sreyk {
718cb8b0e56Sreyk 	char		*newvalue;
719cb8b0e56Sreyk 
720c307a266Sreyk 	if (kv == NULL) {
721cb8b0e56Sreyk 		return (NULL);
722c307a266Sreyk 	} else if (kv->kv_value != NULL) {
723637827c8Sreyk 		if (asprintf(&newvalue, "%s%s", kv->kv_value, value) == -1)
724cb8b0e56Sreyk 			return (NULL);
725cb8b0e56Sreyk 
726cb8b0e56Sreyk 		free(kv->kv_value);
727cb8b0e56Sreyk 		kv->kv_value = newvalue;
728637827c8Sreyk 	} else if ((kv->kv_value = strdup(value)) == NULL)
729637827c8Sreyk 		return (NULL);
730cb8b0e56Sreyk 
731cb8b0e56Sreyk 	return (kv);
732cb8b0e56Sreyk }
733cb8b0e56Sreyk 
734cb8b0e56Sreyk void
735c307a266Sreyk kv_purge(struct kvtree *keys)
736cb8b0e56Sreyk {
737cb8b0e56Sreyk 	struct kv	*kv;
738cb8b0e56Sreyk 
739c307a266Sreyk 	while ((kv = RB_MIN(kvtree, keys)) != NULL)
740cb8b0e56Sreyk 		kv_delete(keys, kv);
741cb8b0e56Sreyk }
742cb8b0e56Sreyk 
743cb8b0e56Sreyk void
744cb8b0e56Sreyk kv_free(struct kv *kv)
745cb8b0e56Sreyk {
746230b3145Sclaudio 	/*
747230b3145Sclaudio 	 * This function does not clear memory referenced by
748230b3145Sclaudio 	 * kv_children or stuff on the tailqs. Use kv_delete() instead.
749230b3145Sclaudio 	 */
750230b3145Sclaudio 
751cb8b0e56Sreyk 	free(kv->kv_key);
752cb8b0e56Sreyk 	free(kv->kv_value);
753cb8b0e56Sreyk 	memset(kv, 0, sizeof(*kv));
754cb8b0e56Sreyk }
755cb8b0e56Sreyk 
756cb8b0e56Sreyk struct kv *
757cb8b0e56Sreyk kv_inherit(struct kv *dst, struct kv *src)
758cb8b0e56Sreyk {
759cb8b0e56Sreyk 	memset(dst, 0, sizeof(*dst));
760cb8b0e56Sreyk 	memcpy(dst, src, sizeof(*dst));
761c307a266Sreyk 	TAILQ_INIT(&dst->kv_children);
762cb8b0e56Sreyk 
763cb8b0e56Sreyk 	if (src->kv_key != NULL) {
764cb8b0e56Sreyk 		if ((dst->kv_key = strdup(src->kv_key)) == NULL) {
765cb8b0e56Sreyk 			kv_free(dst);
766cb8b0e56Sreyk 			return (NULL);
767cb8b0e56Sreyk 		}
768cb8b0e56Sreyk 	}
769cb8b0e56Sreyk 	if (src->kv_value != NULL) {
770cb8b0e56Sreyk 		if ((dst->kv_value = strdup(src->kv_value)) == NULL) {
771cb8b0e56Sreyk 			kv_free(dst);
772cb8b0e56Sreyk 			return (NULL);
773cb8b0e56Sreyk 		}
774cb8b0e56Sreyk 	}
775cb8b0e56Sreyk 
776cb8b0e56Sreyk 	if (src->kv_match != NULL)
777cb8b0e56Sreyk 		dst->kv_match = src->kv_match;
778c307a266Sreyk 	if (src->kv_matchtree != NULL)
779c307a266Sreyk 		dst->kv_matchtree = src->kv_matchtree;
780cb8b0e56Sreyk 
781cb8b0e56Sreyk 	return (dst);
782cb8b0e56Sreyk }
783cb8b0e56Sreyk 
784cb8b0e56Sreyk int
785c84d6099Sbenno kv_log(struct rsession *con, struct kv *kv, u_int16_t labelid,
786c84d6099Sbenno     enum direction dir)
787cb8b0e56Sreyk {
788cb8b0e56Sreyk 	char	*msg;
789cb8b0e56Sreyk 
790c84d6099Sbenno 	if (con->se_log == NULL)
791cb8b0e56Sreyk 		return (0);
792c84d6099Sbenno 	if (asprintf(&msg, " %s%s%s%s%s%s%s",
793c84d6099Sbenno 	    dir == RELAY_DIR_REQUEST ? "[" : "{",
794cb8b0e56Sreyk 	    labelid == 0 ? "" : label_id2name(labelid),
795cb8b0e56Sreyk 	    labelid == 0 ? "" : ", ",
796cb8b0e56Sreyk 	    kv->kv_key == NULL ? "(unknown)" : kv->kv_key,
797cb8b0e56Sreyk 	    kv->kv_value == NULL ? "" : ": ",
798c84d6099Sbenno 	    kv->kv_value == NULL ? "" : kv->kv_value,
799c84d6099Sbenno 	    dir == RELAY_DIR_REQUEST ? "]" : "}") == -1)
800cb8b0e56Sreyk 		return (-1);
801c84d6099Sbenno 	if (evbuffer_add(con->se_log, msg, strlen(msg)) == -1) {
802cb8b0e56Sreyk 		free(msg);
803cb8b0e56Sreyk 		return (-1);
804cb8b0e56Sreyk 	}
805cb8b0e56Sreyk 	free(msg);
806c84d6099Sbenno 	con->se_haslog = 1;
807cb8b0e56Sreyk 	return (0);
808cb8b0e56Sreyk }
809cb8b0e56Sreyk 
810c307a266Sreyk struct kv *
811c307a266Sreyk kv_find(struct kvtree *keys, struct kv *kv)
812c307a266Sreyk {
813c307a266Sreyk 	struct kv	*match;
814c307a266Sreyk 	const char	*key;
815c307a266Sreyk 
816c307a266Sreyk 	if (kv->kv_flags & KV_FLAG_GLOBBING) {
817c307a266Sreyk 		/* Test header key using shell globbing rules */
818c307a266Sreyk 		key = kv->kv_key == NULL ? "" : kv->kv_key;
819c307a266Sreyk 		RB_FOREACH(match, kvtree, keys) {
820c307a266Sreyk 			if (fnmatch(key, match->kv_key, FNM_CASEFOLD) == 0)
821c307a266Sreyk 				break;
822c307a266Sreyk 		}
823c307a266Sreyk 	} else {
824c307a266Sreyk 		/* Fast tree-based lookup only works without globbing */
825c307a266Sreyk 		match = RB_FIND(kvtree, keys, kv);
826c307a266Sreyk 	}
827c307a266Sreyk 
828c307a266Sreyk 	return (match);
829c307a266Sreyk }
830c307a266Sreyk 
831a168ef1aSreyk struct kv *
832a168ef1aSreyk kv_find_value(struct kvtree *keys, char *key, const char *value,
833a168ef1aSreyk     const char *delim)
834a168ef1aSreyk {
835a168ef1aSreyk 	struct kv	*match, kv;
836a168ef1aSreyk 	char		*val = NULL, *next, *ptr;
837a168ef1aSreyk 	size_t		 len;
838a168ef1aSreyk 
839a168ef1aSreyk 	kv.kv_key = key;
840a168ef1aSreyk 	if ((match = RB_FIND(kvtree, keys, &kv)) == NULL)
841a168ef1aSreyk 		return (NULL);
842a168ef1aSreyk 
843a168ef1aSreyk 	if (match->kv_value == NULL)
844a168ef1aSreyk 		return (NULL);
845a168ef1aSreyk 
846a168ef1aSreyk 	if (delim == NULL) {
847a168ef1aSreyk 		if (strcasecmp(match->kv_value, value) == 0)
848a168ef1aSreyk 			goto done;
849a168ef1aSreyk 	} else {
850a168ef1aSreyk 		if ((val = strdup(match->kv_value)) == NULL)
851a168ef1aSreyk 			return (NULL);
852a168ef1aSreyk 		for (next = ptr = val; ptr != NULL;
853a168ef1aSreyk 		    ptr = strsep(&next, delim)) {
854a168ef1aSreyk 			/* strip whitespace */
855a168ef1aSreyk 			ptr += strspn(ptr, " \t");
856a168ef1aSreyk 			len = strcspn(ptr, " \t");
857a168ef1aSreyk 			if (strncasecmp(ptr, value, len) == 0)
858a168ef1aSreyk 				goto done;
859a168ef1aSreyk 		}
860a168ef1aSreyk 	}
861a168ef1aSreyk 
862a168ef1aSreyk 	/* not matched */
863a168ef1aSreyk 	match = NULL;
864a168ef1aSreyk  done:
865a168ef1aSreyk #ifdef DEBUG
866a168ef1aSreyk 	if (match != NULL)
867a168ef1aSreyk 		DPRINTF("%s: matched %s: %s", __func__, key, value);
868a168ef1aSreyk #endif
869a168ef1aSreyk 	free(val);
870a168ef1aSreyk 	return (match);
871a168ef1aSreyk }
872a168ef1aSreyk 
873c307a266Sreyk int
874c307a266Sreyk kv_cmp(struct kv *a, struct kv *b)
875c307a266Sreyk {
876c307a266Sreyk 	return (strcasecmp(a->kv_key, b->kv_key));
877c307a266Sreyk }
878c307a266Sreyk 
879c307a266Sreyk RB_GENERATE(kvtree, kv, kv_node, kv_cmp);
880c307a266Sreyk 
881cb8b0e56Sreyk int
882cb8b0e56Sreyk rule_add(struct protocol *proto, struct relay_rule *rule, const char *rulefile)
883cb8b0e56Sreyk {
884cb8b0e56Sreyk 	struct relay_rule	*r = NULL;
885cb8b0e56Sreyk 	struct kv		*kv = NULL;
886cb8b0e56Sreyk 	FILE			*fp = NULL;
887cb8b0e56Sreyk 	char			 buf[BUFSIZ];
888cb8b0e56Sreyk 	int			 ret = -1;
889cb8b0e56Sreyk 	u_int			 i;
890cb8b0e56Sreyk 
891cb8b0e56Sreyk 	for (i = 0; i < KEY_TYPE_MAX; i++) {
892cb8b0e56Sreyk 		kv = &rule->rule_kv[i];
893cb8b0e56Sreyk 		if (kv->kv_type != i)
894cb8b0e56Sreyk 			continue;
895cb8b0e56Sreyk 
896cb8b0e56Sreyk 		switch (kv->kv_option) {
897cb8b0e56Sreyk 		case KEY_OPTION_LOG:
898cb8b0e56Sreyk 			/* log action needs a key or a file to be specified */
899cb8b0e56Sreyk 			if (kv->kv_key == NULL && rulefile == NULL &&
900cb8b0e56Sreyk 			    (kv->kv_key = strdup("*")) == NULL)
901cb8b0e56Sreyk 				goto fail;
902cb8b0e56Sreyk 			break;
903cb8b0e56Sreyk 		default:
904cb8b0e56Sreyk 			break;
905cb8b0e56Sreyk 		}
906cb8b0e56Sreyk 
907cb8b0e56Sreyk 		switch (kv->kv_type) {
908cb8b0e56Sreyk 		case KEY_TYPE_QUERY:
909cb8b0e56Sreyk 		case KEY_TYPE_PATH:
910cb8b0e56Sreyk 		case KEY_TYPE_URL:
911cb8b0e56Sreyk 			if (rule->rule_dir != RELAY_DIR_REQUEST)
912cb8b0e56Sreyk 				goto fail;
913cb8b0e56Sreyk 			break;
914cb8b0e56Sreyk 		default:
915cb8b0e56Sreyk 			break;
916cb8b0e56Sreyk 		}
917c307a266Sreyk 
918c307a266Sreyk 		if (kv->kv_value != NULL && strchr(kv->kv_value, '$') != NULL)
919c307a266Sreyk 			kv->kv_flags |= KV_FLAG_MACRO;
920c307a266Sreyk 		if (kv->kv_key != NULL && strpbrk(kv->kv_key, "*?[") != NULL)
921c307a266Sreyk 			kv->kv_flags |= KV_FLAG_GLOBBING;
922cb8b0e56Sreyk 	}
923cb8b0e56Sreyk 
924cb8b0e56Sreyk 	if (rulefile == NULL) {
925cb8b0e56Sreyk 		TAILQ_INSERT_TAIL(&proto->rules, rule, rule_entry);
926cb8b0e56Sreyk 		return (0);
927cb8b0e56Sreyk 	}
928cb8b0e56Sreyk 
929cb8b0e56Sreyk 	if ((fp = fopen(rulefile, "r")) == NULL)
930cb8b0e56Sreyk 		goto fail;
931cb8b0e56Sreyk 
932cb8b0e56Sreyk 	while (fgets(buf, sizeof(buf), fp) != NULL) {
933cb8b0e56Sreyk 		/* strip whitespace and newline characters */
934cb8b0e56Sreyk 		buf[strcspn(buf, "\r\n\t ")] = '\0';
935cb8b0e56Sreyk 		if (!strlen(buf) || buf[0] == '#')
936cb8b0e56Sreyk 			continue;
937cb8b0e56Sreyk 
938cb8b0e56Sreyk 		if ((r = rule_inherit(rule)) == NULL)
939cb8b0e56Sreyk 			goto fail;
940cb8b0e56Sreyk 
941cb8b0e56Sreyk 		for (i = 0; i < KEY_TYPE_MAX; i++) {
942cb8b0e56Sreyk 			kv = &r->rule_kv[i];
943cb8b0e56Sreyk 			if (kv->kv_type != i)
944cb8b0e56Sreyk 				continue;
945cb8b0e56Sreyk 			free(kv->kv_key);
946cb8b0e56Sreyk 			if ((kv->kv_key = strdup(buf)) == NULL) {
947cb8b0e56Sreyk 				rule_free(r);
948cb8b0e56Sreyk 				free(r);
949cb8b0e56Sreyk 				goto fail;
950cb8b0e56Sreyk 			}
951cb8b0e56Sreyk 		}
952cb8b0e56Sreyk 
953cb8b0e56Sreyk 		TAILQ_INSERT_TAIL(&proto->rules, r, rule_entry);
954cb8b0e56Sreyk 	}
955cb8b0e56Sreyk 
956cb8b0e56Sreyk 	ret = 0;
957cb8b0e56Sreyk 	rule_free(rule);
958cb8b0e56Sreyk 	free(rule);
959cb8b0e56Sreyk 
960cb8b0e56Sreyk  fail:
961cb8b0e56Sreyk 	if (fp != NULL)
962cb8b0e56Sreyk 		fclose(fp);
963cb8b0e56Sreyk 	return (ret);
964cb8b0e56Sreyk }
965cb8b0e56Sreyk 
966cb8b0e56Sreyk struct relay_rule *
967cb8b0e56Sreyk rule_inherit(struct relay_rule *rule)
968cb8b0e56Sreyk {
969cb8b0e56Sreyk 	struct relay_rule	*r;
970cb8b0e56Sreyk 	u_int			 i;
971cb8b0e56Sreyk 	struct kv		*kv;
972cb8b0e56Sreyk 
973cb8b0e56Sreyk 	if ((r = calloc(1, sizeof(*r))) == NULL)
974cb8b0e56Sreyk 		return (NULL);
975cb8b0e56Sreyk 	memcpy(r, rule, sizeof(*r));
976cb8b0e56Sreyk 
977cb8b0e56Sreyk 	for (i = 0; i < KEY_TYPE_MAX; i++) {
978cb8b0e56Sreyk 		kv = &rule->rule_kv[i];
979cb8b0e56Sreyk 		if (kv->kv_type != i)
980cb8b0e56Sreyk 			continue;
981cb8b0e56Sreyk 		if (kv_inherit(&r->rule_kv[i], kv) == NULL) {
982cb8b0e56Sreyk 			free(r);
983cb8b0e56Sreyk 			return (NULL);
984cb8b0e56Sreyk 		}
985cb8b0e56Sreyk 	}
986cb8b0e56Sreyk 
987cb8b0e56Sreyk 	if (r->rule_label > 0)
988cb8b0e56Sreyk 		label_ref(r->rule_label);
989cb8b0e56Sreyk 	if (r->rule_tag > 0)
990cb8b0e56Sreyk 		tag_ref(r->rule_tag);
991cb8b0e56Sreyk 	if (r->rule_tagged > 0)
992cb8b0e56Sreyk 		tag_ref(r->rule_tagged);
993cb8b0e56Sreyk 
994cb8b0e56Sreyk 	return (r);
995cb8b0e56Sreyk }
996cb8b0e56Sreyk 
997cb8b0e56Sreyk void
998cb8b0e56Sreyk rule_free(struct relay_rule *rule)
999cb8b0e56Sreyk {
1000cb8b0e56Sreyk 	u_int	i;
1001cb8b0e56Sreyk 
1002cb8b0e56Sreyk 	for (i = 0; i < KEY_TYPE_MAX; i++)
1003cb8b0e56Sreyk 		kv_free(&rule->rule_kv[i]);
1004cb8b0e56Sreyk 	if (rule->rule_label > 0)
1005cb8b0e56Sreyk 		label_unref(rule->rule_label);
1006cb8b0e56Sreyk 	if (rule->rule_tag > 0)
1007cb8b0e56Sreyk 		tag_unref(rule->rule_tag);
1008cb8b0e56Sreyk 	if (rule->rule_tagged > 0)
1009cb8b0e56Sreyk 		tag_unref(rule->rule_tagged);
1010cb8b0e56Sreyk }
1011cb8b0e56Sreyk 
1012cb8b0e56Sreyk void
1013cb8b0e56Sreyk rule_delete(struct relay_rules *rules, struct relay_rule *rule)
1014cb8b0e56Sreyk {
1015cb8b0e56Sreyk 	TAILQ_REMOVE(rules, rule, rule_entry);
1016cb8b0e56Sreyk 	rule_free(rule);
1017cb8b0e56Sreyk 	free(rule);
1018cb8b0e56Sreyk }
1019cb8b0e56Sreyk 
1020cb8b0e56Sreyk void
1021cb8b0e56Sreyk rule_settable(struct relay_rules *rules, struct relay_table *rlt)
1022cb8b0e56Sreyk {
1023cb8b0e56Sreyk 	struct relay_rule	*r;
1024cb8b0e56Sreyk 	char			 pname[TABLE_NAME_SIZE];
1025cb8b0e56Sreyk 
1026cb8b0e56Sreyk 	if (rlt->rlt_table == NULL || strlcpy(pname, rlt->rlt_table->conf.name,
1027cb8b0e56Sreyk 	    sizeof(pname)) >= sizeof(pname))
1028cb8b0e56Sreyk 		return;
1029cb8b0e56Sreyk 
1030cb8b0e56Sreyk 	pname[strcspn(pname, ":")] = '\0';
1031cb8b0e56Sreyk 
1032cb8b0e56Sreyk 	TAILQ_FOREACH(r, rules, rule_entry) {
1033cb8b0e56Sreyk 		if (r->rule_tablename[0] &&
1034a94502bfSbenno 		    strcmp(pname, r->rule_tablename) == 0)
1035cb8b0e56Sreyk 			r->rule_table = rlt;
1036cb8b0e56Sreyk 	}
1037cb8b0e56Sreyk }
1038cb8b0e56Sreyk 
1039a2195becSreyk /*
1040a2195becSreyk  * Utility functions
1041a2195becSreyk  */
1042a2195becSreyk 
1043feb9ff76Sreyk struct host *
1044748ceb64Sreyk host_find(struct relayd *env, objid_t id)
1045feb9ff76Sreyk {
1046feb9ff76Sreyk 	struct table	*table;
1047feb9ff76Sreyk 	struct host	*host;
1048feb9ff76Sreyk 
104935d10c30Sreyk 	TAILQ_FOREACH(table, env->sc_tables, entry)
1050feb9ff76Sreyk 		TAILQ_FOREACH(host, &table->hosts, entry)
105168b79041Spyr 			if (host->conf.id == id)
1052feb9ff76Sreyk 				return (host);
1053feb9ff76Sreyk 	return (NULL);
1054feb9ff76Sreyk }
1055feb9ff76Sreyk 
1056feb9ff76Sreyk struct table *
1057748ceb64Sreyk table_find(struct relayd *env, objid_t id)
1058feb9ff76Sreyk {
1059feb9ff76Sreyk 	struct table	*table;
1060feb9ff76Sreyk 
106135d10c30Sreyk 	TAILQ_FOREACH(table, env->sc_tables, entry)
106268b79041Spyr 		if (table->conf.id == id)
1063feb9ff76Sreyk 			return (table);
1064feb9ff76Sreyk 	return (NULL);
1065feb9ff76Sreyk }
1066feb9ff76Sreyk 
10679591a9f7Spyr struct rdr *
10689591a9f7Spyr rdr_find(struct relayd *env, objid_t id)
1069feb9ff76Sreyk {
10709591a9f7Spyr 	struct rdr	*rdr;
1071feb9ff76Sreyk 
107235d10c30Sreyk 	TAILQ_FOREACH(rdr, env->sc_rdrs, entry)
10739591a9f7Spyr 		if (rdr->conf.id == id)
10749591a9f7Spyr 			return (rdr);
1075feb9ff76Sreyk 	return (NULL);
1076feb9ff76Sreyk }
1077ef1f2334Sreyk 
10782edd718bSreyk struct relay *
1079748ceb64Sreyk relay_find(struct relayd *env, objid_t id)
10802edd718bSreyk {
10812edd718bSreyk 	struct relay	*rlay;
10822edd718bSreyk 
10834a5b9b3eSreyk 	TAILQ_FOREACH(rlay, env->sc_relays, rl_entry)
10844a5b9b3eSreyk 		if (rlay->rl_conf.id == id)
10852edd718bSreyk 			return (rlay);
10862edd718bSreyk 	return (NULL);
10872edd718bSreyk }
10882edd718bSreyk 
1089a2195becSreyk struct protocol *
1090a2195becSreyk proto_find(struct relayd *env, objid_t id)
1091a2195becSreyk {
1092a2195becSreyk 	struct protocol	*p;
1093a2195becSreyk 
1094a2195becSreyk 	TAILQ_FOREACH(p, env->sc_protos, entry)
1095a2195becSreyk 		if (p->id == id)
1096a2195becSreyk 			return (p);
1097a2195becSreyk 	return (NULL);
1098a2195becSreyk }
1099a2195becSreyk 
1100f4a6e73bSreyk struct rsession *
1101748ceb64Sreyk session_find(struct relayd *env, objid_t id)
11022edd718bSreyk {
11032edd718bSreyk 	struct relay		*rlay;
1104f4a6e73bSreyk 	struct rsession		*con;
11052edd718bSreyk 
11064a5b9b3eSreyk 	TAILQ_FOREACH(rlay, env->sc_relays, rl_entry)
11074a5b9b3eSreyk 		SPLAY_FOREACH(con, session_tree, &rlay->rl_sessions)
1108f8eb77d7Sthib 			if (con->se_id == id)
11092edd718bSreyk 				return (con);
11102edd718bSreyk 	return (NULL);
11112edd718bSreyk }
11122edd718bSreyk 
111334438db4Sreyk struct netroute *
111434438db4Sreyk route_find(struct relayd *env, objid_t id)
111534438db4Sreyk {
111634438db4Sreyk 	struct netroute	*nr;
111734438db4Sreyk 
111834438db4Sreyk 	TAILQ_FOREACH(nr, env->sc_routes, nr_route)
111934438db4Sreyk 		if (nr->nr_conf.id == id)
112034438db4Sreyk 			return (nr);
112134438db4Sreyk 	return (NULL);
112234438db4Sreyk }
112334438db4Sreyk 
1124a2195becSreyk struct router *
1125a2195becSreyk router_find(struct relayd *env, objid_t id)
1126a2195becSreyk {
1127a2195becSreyk 	struct router	*rt;
1128a2195becSreyk 
1129a2195becSreyk 	TAILQ_FOREACH(rt, env->sc_rts, rt_entry)
1130a2195becSreyk 		if (rt->rt_conf.id == id)
1131a2195becSreyk 			return (rt);
1132a2195becSreyk 	return (NULL);
1133a2195becSreyk }
1134a2195becSreyk 
1135ef1f2334Sreyk struct host *
1136748ceb64Sreyk host_findbyname(struct relayd *env, const char *name)
1137ef1f2334Sreyk {
1138ef1f2334Sreyk 	struct table	*table;
1139ef1f2334Sreyk 	struct host	*host;
1140ef1f2334Sreyk 
114135d10c30Sreyk 	TAILQ_FOREACH(table, env->sc_tables, entry)
1142ef1f2334Sreyk 		TAILQ_FOREACH(host, &table->hosts, entry)
114368b79041Spyr 			if (strcmp(host->conf.name, name) == 0)
1144ef1f2334Sreyk 				return (host);
1145ef1f2334Sreyk 	return (NULL);
1146ef1f2334Sreyk }
1147ef1f2334Sreyk 
1148ef1f2334Sreyk struct table *
1149748ceb64Sreyk table_findbyname(struct relayd *env, const char *name)
1150ef1f2334Sreyk {
1151ef1f2334Sreyk 	struct table	*table;
1152ef1f2334Sreyk 
115335d10c30Sreyk 	TAILQ_FOREACH(table, env->sc_tables, entry)
115468b79041Spyr 		if (strcmp(table->conf.name, name) == 0)
1155ef1f2334Sreyk 			return (table);
1156ef1f2334Sreyk 	return (NULL);
1157ef1f2334Sreyk }
1158ef1f2334Sreyk 
1159af50a7a9Sreyk struct table *
1160af50a7a9Sreyk table_findbyconf(struct relayd *env, struct table *tb)
1161af50a7a9Sreyk {
1162af50a7a9Sreyk 	struct table		*table;
1163af50a7a9Sreyk 	struct table_config	 a, b;
1164af50a7a9Sreyk 
1165af50a7a9Sreyk 	bcopy(&tb->conf, &a, sizeof(a));
11669591a9f7Spyr 	a.id = a.rdrid = 0;
1167af50a7a9Sreyk 	a.flags &= ~(F_USED|F_BACKUP);
1168af50a7a9Sreyk 
116935d10c30Sreyk 	TAILQ_FOREACH(table, env->sc_tables, entry) {
1170af50a7a9Sreyk 		bcopy(&table->conf, &b, sizeof(b));
11719591a9f7Spyr 		b.id = b.rdrid = 0;
1172af50a7a9Sreyk 		b.flags &= ~(F_USED|F_BACKUP);
1173af50a7a9Sreyk 
1174af50a7a9Sreyk 		/*
1175af50a7a9Sreyk 		 * Compare two tables and return the existing table if
1176af50a7a9Sreyk 		 * the configuration seems to be the same.
1177af50a7a9Sreyk 		 */
1178af50a7a9Sreyk 		if (bcmp(&a, &b, sizeof(b)) == 0 &&
1179af50a7a9Sreyk 		    ((tb->sendbuf == NULL && table->sendbuf == NULL) ||
1180af50a7a9Sreyk 		    (tb->sendbuf != NULL && table->sendbuf != NULL &&
1181af50a7a9Sreyk 		    strcmp(tb->sendbuf, table->sendbuf) == 0)))
1182af50a7a9Sreyk 			return (table);
1183af50a7a9Sreyk 	}
1184af50a7a9Sreyk 	return (NULL);
1185af50a7a9Sreyk }
1186af50a7a9Sreyk 
11879591a9f7Spyr struct rdr *
11889591a9f7Spyr rdr_findbyname(struct relayd *env, const char *name)
1189ef1f2334Sreyk {
11909591a9f7Spyr 	struct rdr	*rdr;
1191ef1f2334Sreyk 
119235d10c30Sreyk 	TAILQ_FOREACH(rdr, env->sc_rdrs, entry)
11939591a9f7Spyr 		if (strcmp(rdr->conf.name, name) == 0)
11949591a9f7Spyr 			return (rdr);
1195ef1f2334Sreyk 	return (NULL);
1196ef1f2334Sreyk }
119701d85ec5Sreyk 
11982edd718bSreyk struct relay *
1199748ceb64Sreyk relay_findbyname(struct relayd *env, const char *name)
12002edd718bSreyk {
12012edd718bSreyk 	struct relay	*rlay;
12022edd718bSreyk 
12034a5b9b3eSreyk 	TAILQ_FOREACH(rlay, env->sc_relays, rl_entry)
12044a5b9b3eSreyk 		if (strcmp(rlay->rl_conf.name, name) == 0)
12052edd718bSreyk 			return (rlay);
12062edd718bSreyk 	return (NULL);
12072edd718bSreyk }
12082edd718bSreyk 
12098a93e612Sreyk struct relay *
12108a93e612Sreyk relay_findbyaddr(struct relayd *env, struct relay_config *rc)
12118a93e612Sreyk {
12128a93e612Sreyk 	struct relay	*rlay;
12138a93e612Sreyk 
12148a93e612Sreyk 	TAILQ_FOREACH(rlay, env->sc_relays, rl_entry)
12158a93e612Sreyk 		if (bcmp(&rlay->rl_conf.ss, &rc->ss, sizeof(rc->ss)) == 0 &&
12168a93e612Sreyk 		    rlay->rl_conf.port == rc->port)
12178a93e612Sreyk 			return (rlay);
12188a93e612Sreyk 	return (NULL);
12198a93e612Sreyk }
12208a93e612Sreyk 
122100ae3104Sreyk EVP_PKEY *
122285e5f500Sclaudio pkey_find(struct relayd *env, char * hash)
122300ae3104Sreyk {
122400ae3104Sreyk 	struct ca_pkey	*pkey;
122500ae3104Sreyk 
122600ae3104Sreyk 	TAILQ_FOREACH(pkey, env->sc_pkeys, pkey_entry)
122785e5f500Sclaudio 		if (strcmp(hash, pkey->pkey_hash) == 0)
122800ae3104Sreyk 			return (pkey->pkey);
122900ae3104Sreyk 	return (NULL);
123000ae3104Sreyk }
123100ae3104Sreyk 
123200ae3104Sreyk struct ca_pkey *
123385e5f500Sclaudio pkey_add(struct relayd *env, EVP_PKEY *pkey, char *hash)
123400ae3104Sreyk {
123500ae3104Sreyk 	struct ca_pkey	*ca_pkey;
123600ae3104Sreyk 
123700ae3104Sreyk 	if (env->sc_pkeys == NULL)
123800ae3104Sreyk 		fatalx("pkeys");
123900ae3104Sreyk 
124000ae3104Sreyk 	if ((ca_pkey = calloc(1, sizeof(*ca_pkey))) == NULL)
124100ae3104Sreyk 		return (NULL);
124200ae3104Sreyk 
124300ae3104Sreyk 	ca_pkey->pkey = pkey;
124485e5f500Sclaudio 	if (strlcpy(ca_pkey->pkey_hash, hash, sizeof(ca_pkey->pkey_hash)) >=
1245263b7135Sjsg 	    sizeof(ca_pkey->pkey_hash)) {
1246263b7135Sjsg 		free(ca_pkey);
124785e5f500Sclaudio 		return (NULL);
1248263b7135Sjsg 	}
124900ae3104Sreyk 
125000ae3104Sreyk 	TAILQ_INSERT_TAIL(env->sc_pkeys, ca_pkey, pkey_entry);
125100ae3104Sreyk 
125200ae3104Sreyk 	return (ca_pkey);
125300ae3104Sreyk }
125400ae3104Sreyk 
1255f2f4e153Sreyk struct relay_cert *
1256f2f4e153Sreyk cert_add(struct relayd *env, objid_t id)
1257f2f4e153Sreyk {
1258f2f4e153Sreyk 	static objid_t		 last_cert_id = 0;
1259f2f4e153Sreyk 	struct relay_cert	*cert;
1260f2f4e153Sreyk 
1261f2f4e153Sreyk 	if ((cert = calloc(1, sizeof(*cert))) == NULL)
1262f2f4e153Sreyk 		return (NULL);
1263f2f4e153Sreyk 
1264f2f4e153Sreyk 	if (id == 0)
1265f2f4e153Sreyk 		id = ++last_cert_id;
1266f2f4e153Sreyk 	if (id == INT_MAX) {
1267f2f4e153Sreyk 		log_warnx("too many tls keypairs defined");
1268f2f4e153Sreyk 		free(cert);
1269f2f4e153Sreyk 		return (NULL);
1270f2f4e153Sreyk 	}
1271f2f4e153Sreyk 
1272f2f4e153Sreyk 	cert->cert_id = id;
1273f2f4e153Sreyk 	cert->cert_fd = -1;
1274f2f4e153Sreyk 	cert->cert_key_fd = -1;
127531604b98Sreyk 	cert->cert_ocsp_fd = -1;
1276f2f4e153Sreyk 
1277f2f4e153Sreyk 	TAILQ_INSERT_TAIL(env->sc_certs, cert, cert_entry);
1278f2f4e153Sreyk 
1279f2f4e153Sreyk 	return (cert);
1280f2f4e153Sreyk }
1281f2f4e153Sreyk 
1282f2f4e153Sreyk struct relay_cert *
1283f2f4e153Sreyk cert_find(struct relayd *env, objid_t id)
1284f2f4e153Sreyk {
1285f2f4e153Sreyk 	struct relay_cert	*cert;
1286f2f4e153Sreyk 
1287f2f4e153Sreyk 	TAILQ_FOREACH(cert, env->sc_certs, cert_entry)
1288f2f4e153Sreyk 		if (cert->cert_id == id)
1289f2f4e153Sreyk 			return (cert);
1290f2f4e153Sreyk 	return (NULL);
1291f2f4e153Sreyk }
1292f2f4e153Sreyk 
1293e938bb13Sreyk char *
1294e938bb13Sreyk relay_load_fd(int fd, off_t *len)
1295e938bb13Sreyk {
1296e938bb13Sreyk 	char		*buf = NULL;
1297e938bb13Sreyk 	struct stat	 st;
1298e938bb13Sreyk 	off_t		 size;
1299e938bb13Sreyk 	ssize_t		 rv;
1300e938bb13Sreyk 	int		 err;
1301e938bb13Sreyk 
1302e938bb13Sreyk 	if (fstat(fd, &st) != 0)
1303e938bb13Sreyk 		goto fail;
1304e938bb13Sreyk 	size = st.st_size;
1305e938bb13Sreyk 	if ((buf = calloc(1, size + 1)) == NULL)
1306e938bb13Sreyk 		goto fail;
1307e938bb13Sreyk 	if ((rv = pread(fd, buf, size, 0)) != size)
1308e938bb13Sreyk 		goto fail;
1309e938bb13Sreyk 
1310e938bb13Sreyk 	close(fd);
1311e938bb13Sreyk 
1312e938bb13Sreyk 	*len = size;
1313e938bb13Sreyk 	return (buf);
1314e938bb13Sreyk 
1315e938bb13Sreyk  fail:
1316e938bb13Sreyk 	err = errno;
1317e938bb13Sreyk 	free(buf);
1318e938bb13Sreyk 	close(fd);
1319e938bb13Sreyk 	errno = err;
1320e938bb13Sreyk 	return (NULL);
1321e938bb13Sreyk }
1322e938bb13Sreyk 
1323e938bb13Sreyk int
13243ca2f577Sreyk relay_load_certfiles(struct relayd *env, struct relay *rlay, const char *name)
1325e938bb13Sreyk {
1326e938bb13Sreyk 	char	 certfile[PATH_MAX];
13273ca2f577Sreyk 	char	 hbuf[PATH_MAX];
1328e938bb13Sreyk 	struct protocol *proto = rlay->rl_proto;
1329f2f4e153Sreyk 	struct relay_cert *cert;
1330e938bb13Sreyk 	int	 useport = htons(rlay->rl_conf.port);
133131604b98Sreyk 	int	 cert_fd = -1, key_fd = -1, ocsp_fd = -1;
1332e938bb13Sreyk 
1333e938bb13Sreyk 	if (rlay->rl_conf.flags & F_TLSCLIENT) {
1334f2f4e153Sreyk 		if (strlen(proto->tlsca) && rlay->rl_tls_ca_fd == -1) {
1335e938bb13Sreyk 			if ((rlay->rl_tls_ca_fd =
1336e938bb13Sreyk 			    open(proto->tlsca, O_RDONLY)) == -1)
1337e938bb13Sreyk 				return (-1);
1338e938bb13Sreyk 			log_debug("%s: using ca %s", __func__, proto->tlsca);
1339e938bb13Sreyk 		}
1340f2f4e153Sreyk 		if (strlen(proto->tlscacert) && rlay->rl_tls_cacert_fd == -1) {
1341e938bb13Sreyk 			if ((rlay->rl_tls_cacert_fd =
1342e938bb13Sreyk 			    open(proto->tlscacert, O_RDONLY)) == -1)
1343e938bb13Sreyk 				return (-1);
1344e938bb13Sreyk 			log_debug("%s: using ca certificate %s", __func__,
1345e938bb13Sreyk 			    proto->tlscacert);
1346e938bb13Sreyk 		}
1347f2f4e153Sreyk 		if (strlen(proto->tlscakey) && !rlay->rl_conf.tls_cakey_len &&
1348f2f4e153Sreyk 		    proto->tlscapass != NULL) {
1349e938bb13Sreyk 			if ((rlay->rl_tls_cakey =
1350e938bb13Sreyk 			    ssl_load_key(env, proto->tlscakey,
1351e938bb13Sreyk 			    &rlay->rl_conf.tls_cakey_len,
1352e938bb13Sreyk 			    proto->tlscapass)) == NULL)
1353e938bb13Sreyk 				return (-1);
1354e938bb13Sreyk 			log_debug("%s: using ca key %s", __func__,
1355e938bb13Sreyk 			    proto->tlscakey);
1356e938bb13Sreyk 		}
1357e938bb13Sreyk 	}
1358e938bb13Sreyk 
1359e938bb13Sreyk 	if ((rlay->rl_conf.flags & F_TLS) == 0)
1360e938bb13Sreyk 		return (0);
1361e938bb13Sreyk 
1362*92388deeStb 	if (strlen(proto->tlsclientca) && rlay->rl_tls_client_ca_fd == -1) {
1363*92388deeStb 		if ((rlay->rl_tls_client_ca_fd =
1364*92388deeStb 		    open(proto->tlsclientca, O_RDONLY)) == -1)
1365*92388deeStb 			return (-1);
1366*92388deeStb 		log_debug("%s: using client ca %s", __func__,
1367*92388deeStb 		    proto->tlsclientca);
1368*92388deeStb 	}
1369*92388deeStb 
13703ca2f577Sreyk 	if (name == NULL &&
13713ca2f577Sreyk 	    print_host(&rlay->rl_conf.ss, hbuf, sizeof(hbuf)) == NULL)
13723ca2f577Sreyk 		goto fail;
13733ca2f577Sreyk 	else if (name != NULL &&
13743ca2f577Sreyk 	    strlcpy(hbuf, name, sizeof(hbuf)) >= sizeof(hbuf))
1375f2f4e153Sreyk 		goto fail;
1376e938bb13Sreyk 
1377e938bb13Sreyk 	if (snprintf(certfile, sizeof(certfile),
1378e938bb13Sreyk 	    "/etc/ssl/%s:%u.crt", hbuf, useport) == -1)
1379f2f4e153Sreyk 		goto fail;
1380f2f4e153Sreyk 	if ((cert_fd = open(certfile, O_RDONLY)) == -1) {
1381e938bb13Sreyk 		if (snprintf(certfile, sizeof(certfile),
1382e938bb13Sreyk 		    "/etc/ssl/%s.crt", hbuf) == -1)
1383f2f4e153Sreyk 			goto fail;
1384f2f4e153Sreyk 		if ((cert_fd = open(certfile, O_RDONLY)) == -1)
1385f2f4e153Sreyk 			goto fail;
1386e938bb13Sreyk 		useport = 0;
1387e938bb13Sreyk 	}
1388e938bb13Sreyk 	log_debug("%s: using certificate %s", __func__, certfile);
1389e938bb13Sreyk 
1390e938bb13Sreyk 	if (useport) {
1391e938bb13Sreyk 		if (snprintf(certfile, sizeof(certfile),
1392e938bb13Sreyk 		    "/etc/ssl/private/%s:%u.key", hbuf, useport) == -1)
1393f2f4e153Sreyk 			goto fail;
1394e938bb13Sreyk 	} else {
1395e938bb13Sreyk 		if (snprintf(certfile, sizeof(certfile),
1396e938bb13Sreyk 		    "/etc/ssl/private/%s.key", hbuf) == -1)
1397f2f4e153Sreyk 			goto fail;
1398e938bb13Sreyk 	}
1399f2f4e153Sreyk 	if ((key_fd = open(certfile, O_RDONLY)) == -1)
1400f2f4e153Sreyk 		goto fail;
1401e938bb13Sreyk 	log_debug("%s: using private key %s", __func__, certfile);
1402e938bb13Sreyk 
140331604b98Sreyk 	if (useport) {
140431604b98Sreyk 		if (snprintf(certfile, sizeof(certfile),
140531604b98Sreyk 		    "/etc/ssl/%s:%u.ocsp", hbuf, useport) == -1)
140631604b98Sreyk 			goto fail;
140731604b98Sreyk 	} else {
140831604b98Sreyk 		if (snprintf(certfile, sizeof(certfile),
140931604b98Sreyk 		    "/etc/ssl/%s.ocsp", hbuf) == -1)
141031604b98Sreyk 			goto fail;
141131604b98Sreyk 	}
141231604b98Sreyk 	if ((ocsp_fd = open(certfile, O_RDONLY)) != -1)
141331604b98Sreyk 		log_debug("%s: using OCSP staple file %s", __func__, certfile);
141431604b98Sreyk 
1415f2f4e153Sreyk 	if ((cert = cert_add(env, 0)) == NULL)
1416f2f4e153Sreyk 		goto fail;
1417f2f4e153Sreyk 
1418f2f4e153Sreyk 	cert->cert_relayid = rlay->rl_conf.id;
1419f2f4e153Sreyk 	cert->cert_fd = cert_fd;
1420f2f4e153Sreyk 	cert->cert_key_fd = key_fd;
142131604b98Sreyk 	cert->cert_ocsp_fd = ocsp_fd;
1422f2f4e153Sreyk 
1423e938bb13Sreyk 	return (0);
1424f2f4e153Sreyk 
1425f2f4e153Sreyk  fail:
1426f2f4e153Sreyk 	if (cert_fd != -1)
1427f2f4e153Sreyk 		close(cert_fd);
1428f2f4e153Sreyk 	if (key_fd != -1)
1429f2f4e153Sreyk 		close(key_fd);
143031604b98Sreyk 	if (ocsp_fd != -1)
143131604b98Sreyk 		close(ocsp_fd);
1432f2f4e153Sreyk 
1433f2f4e153Sreyk 	return (-1);
1434e938bb13Sreyk }
1435e938bb13Sreyk 
143601d85ec5Sreyk void
14376ae98884Spyr event_again(struct event *ev, int fd, short event,
14386ae98884Spyr     void (*fn)(int, short, void *),
143901d85ec5Sreyk     struct timeval *start, struct timeval *end, void *arg)
144001d85ec5Sreyk {
144101d85ec5Sreyk 	struct timeval tv_next, tv_now, tv;
144201d85ec5Sreyk 
1443fd1841a3Sreyk 	getmonotime(&tv_now);
144401d85ec5Sreyk 	bcopy(end, &tv_next, sizeof(tv_next));
144501d85ec5Sreyk 	timersub(&tv_now, start, &tv_now);
144601d85ec5Sreyk 	timersub(&tv_next, &tv_now, &tv_next);
144701d85ec5Sreyk 
144801d85ec5Sreyk 	bzero(&tv, sizeof(tv));
144901d85ec5Sreyk 	if (timercmp(&tv_next, &tv, >))
145001d85ec5Sreyk 		bcopy(&tv_next, &tv, sizeof(tv));
145101d85ec5Sreyk 
14524173f6aaSjsg 	event_del(ev);
145301d85ec5Sreyk 	event_set(ev, fd, event, fn, arg);
145401d85ec5Sreyk 	event_add(ev, &tv);
145501d85ec5Sreyk }
14562edd718bSreyk 
14572edd718bSreyk int
14582edd718bSreyk expand_string(char *label, size_t len, const char *srch, const char *repl)
14592edd718bSreyk {
14602edd718bSreyk 	char *tmp;
14612edd718bSreyk 	char *p, *q;
14622edd718bSreyk 
14632edd718bSreyk 	if ((tmp = calloc(1, len)) == NULL) {
146485a8c65fSreyk 		log_debug("%s: calloc", __func__);
14652edd718bSreyk 		return (-1);
14662edd718bSreyk 	}
14672edd718bSreyk 	p = q = label;
14682edd718bSreyk 	while ((q = strstr(p, srch)) != NULL) {
14692edd718bSreyk 		*q = '\0';
14702edd718bSreyk 		if ((strlcat(tmp, p, len) >= len) ||
14712edd718bSreyk 		    (strlcat(tmp, repl, len) >= len)) {
147285a8c65fSreyk 			log_debug("%s: string too long", __func__);
14732e5853e7Sjsg 			free(tmp);
14742edd718bSreyk 			return (-1);
14752edd718bSreyk 		}
14762edd718bSreyk 		q += strlen(srch);
14772edd718bSreyk 		p = q;
14782edd718bSreyk 	}
14792edd718bSreyk 	if (strlcat(tmp, p, len) >= len) {
148085a8c65fSreyk 		log_debug("%s: string too long", __func__);
14812e5853e7Sjsg 		free(tmp);
14822edd718bSreyk 		return (-1);
14832edd718bSreyk 	}
14848d6dea2fSreyk 	(void)strlcpy(label, tmp, len);	/* always fits */
14852edd718bSreyk 	free(tmp);
14862edd718bSreyk 
14872edd718bSreyk 	return (0);
14882edd718bSreyk }
1489bdd8283dSpyr 
1490bdd8283dSpyr void
1491bdd8283dSpyr translate_string(char *str)
1492bdd8283dSpyr {
1493bdd8283dSpyr 	char	*reader;
1494bdd8283dSpyr 	char	*writer;
1495bdd8283dSpyr 
1496bdd8283dSpyr 	reader = writer = str;
1497bdd8283dSpyr 
1498bdd8283dSpyr 	while (*reader) {
1499bdd8283dSpyr 		if (*reader == '\\') {
1500bdd8283dSpyr 			reader++;
1501bdd8283dSpyr 			switch (*reader) {
1502bdd8283dSpyr 			case 'n':
1503bdd8283dSpyr 				*writer++ = '\n';
1504bdd8283dSpyr 				break;
1505bdd8283dSpyr 			case 'r':
1506bdd8283dSpyr 				*writer++ = '\r';
1507bdd8283dSpyr 				break;
1508bdd8283dSpyr 			default:
1509bdd8283dSpyr 				*writer++ = *reader;
1510bdd8283dSpyr 			}
1511bdd8283dSpyr 		} else
1512bdd8283dSpyr 			*writer++ = *reader;
1513bdd8283dSpyr 		reader++;
1514bdd8283dSpyr 	}
1515bdd8283dSpyr 	*writer = '\0';
1516bdd8283dSpyr }
15177ae0cc5eSreyk 
15187ae0cc5eSreyk char *
15197ae0cc5eSreyk digeststr(enum digest_type type, const u_int8_t *data, size_t len, char *buf)
15207ae0cc5eSreyk {
15217ae0cc5eSreyk 	switch (type) {
15227ae0cc5eSreyk 	case DIGEST_SHA1:
15237ae0cc5eSreyk 		return (SHA1Data(data, len, buf));
15247ae0cc5eSreyk 		break;
15257ae0cc5eSreyk 	case DIGEST_MD5:
15267ae0cc5eSreyk 		return (MD5Data(data, len, buf));
15277ae0cc5eSreyk 		break;
15287ae0cc5eSreyk 	default:
15297ae0cc5eSreyk 		break;
15307ae0cc5eSreyk 	}
15317ae0cc5eSreyk 	return (NULL);
15327ae0cc5eSreyk }
1533812c1ce4Sreyk 
1534812c1ce4Sreyk const char *
1535812c1ce4Sreyk canonicalize_host(const char *host, char *name, size_t len)
1536812c1ce4Sreyk {
1537812c1ce4Sreyk 	struct sockaddr_in	 sin4;
1538812c1ce4Sreyk 	struct sockaddr_in6	 sin6;
15399660c10cStedu 	size_t			 i, j;
15407fd39c52Sreyk 	size_t			 plen;
15417fd39c52Sreyk 	char			 c;
1542812c1ce4Sreyk 
15437fd39c52Sreyk 	if (len < 2)
15447fd39c52Sreyk 		goto fail;
15457fd39c52Sreyk 
15467fd39c52Sreyk 	/*
15477fd39c52Sreyk 	 * Canonicalize an IPv4/6 address
15487fd39c52Sreyk 	 */
1549812c1ce4Sreyk 	if (inet_pton(AF_INET, host, &sin4) == 1)
1550812c1ce4Sreyk 		return (inet_ntop(AF_INET, &sin4, name, len));
1551812c1ce4Sreyk 	if (inet_pton(AF_INET6, host, &sin6) == 1)
1552812c1ce4Sreyk 		return (inet_ntop(AF_INET6, &sin6, name, len));
1553812c1ce4Sreyk 
15547fd39c52Sreyk 	/*
15557fd39c52Sreyk 	 * Canonicalize a hostname
15567fd39c52Sreyk 	 */
15577fd39c52Sreyk 
15587fd39c52Sreyk 	/* 1. remove repeated dots and convert upper case to lower case */
15597fd39c52Sreyk 	plen = strlen(host);
15607fd39c52Sreyk 	bzero(name, len);
15617fd39c52Sreyk 	for (i = j = 0; i < plen; i++) {
15627fd39c52Sreyk 		if (j >= (len - 1))
15637fd39c52Sreyk 			goto fail;
1564d0296ba2Sreyk 		c = tolower((unsigned char)host[i]);
15657fd39c52Sreyk 		if ((c == '.') && (j == 0 || name[j - 1] == '.'))
15667fd39c52Sreyk 			continue;
15677fd39c52Sreyk 		name[j++] = c;
1568812c1ce4Sreyk 	}
1569812c1ce4Sreyk 
15707fd39c52Sreyk 	/* 2. remove trailing dots */
15717fd39c52Sreyk 	for (i = j; i > 0; i--) {
15727fd39c52Sreyk 		if (name[i - 1] != '.')
15737fd39c52Sreyk 			break;
15747fd39c52Sreyk 		name[i - 1] = '\0';
15757fd39c52Sreyk 		j--;
15767fd39c52Sreyk 	}
15777fd39c52Sreyk 	if (j <= 0)
15787fd39c52Sreyk 		goto fail;
15797fd39c52Sreyk 
1580812c1ce4Sreyk 	return (name);
15817fd39c52Sreyk 
15827fd39c52Sreyk  fail:
15837fd39c52Sreyk 	errno = EINVAL;
15847fd39c52Sreyk 	return (NULL);
1585812c1ce4Sreyk }
158632b612c0Sreyk 
15872faabbadSreyk int
1588c9822c56Sreyk parse_url(const char *url, char **protoptr, char **hostptr, char **pathptr)
1589c9822c56Sreyk {
1590c9822c56Sreyk 	char	*p, *proto = NULL, *host = NULL, *path = NULL;
1591c9822c56Sreyk 
1592c9822c56Sreyk 	/* return error if it is not a URL */
1593c9822c56Sreyk 	if ((p = strstr(url, ":/")) == NULL ||
1594c9822c56Sreyk 	    (strcspn(url, ":/") != (size_t)(p - url)))
1595c9822c56Sreyk 		return (-1);
1596c9822c56Sreyk 
1597c9822c56Sreyk 	/* get protocol */
1598c9822c56Sreyk 	if ((proto = strdup(url)) == NULL)
1599c9822c56Sreyk 		goto fail;
1600c9822c56Sreyk 	p = proto + (p - url);
1601c9822c56Sreyk 
1602c9822c56Sreyk 	/* get host */
1603c9822c56Sreyk 	p += strspn(p, ":/");
1604c9822c56Sreyk 	if (*p == '\0' || (host = strdup(p)) == NULL)
1605c9822c56Sreyk 		goto fail;
1606c9822c56Sreyk 	*p = '\0';
1607c9822c56Sreyk 
1608c9822c56Sreyk 	/* find and copy path or default to "/" */
1609c9822c56Sreyk 	if ((p = strchr(host, '/')) == NULL)
1610c9822c56Sreyk 		p = "/";
1611c9822c56Sreyk 	if ((path = strdup(p)) == NULL)
1612c9822c56Sreyk 		goto fail;
1613c9822c56Sreyk 
1614c9822c56Sreyk 	/* strip path after host */
1615c9822c56Sreyk 	host[strcspn(host, "/")] = '\0';
1616c9822c56Sreyk 
1617c9822c56Sreyk 	DPRINTF("%s: %s proto %s, host %s, path %s", __func__,
1618c9822c56Sreyk 	    url, proto, host, path);
1619c9822c56Sreyk 
1620c9822c56Sreyk 	*protoptr = proto;
1621c9822c56Sreyk 	*hostptr = host;
1622c9822c56Sreyk 	*pathptr = path;
1623c9822c56Sreyk 
1624c9822c56Sreyk 	return (0);
1625c9822c56Sreyk 
1626c9822c56Sreyk  fail:
1627c9822c56Sreyk 	free(proto);
1628c9822c56Sreyk 	free(host);
1629c9822c56Sreyk 	free(path);
1630c9822c56Sreyk 	return (-1);
1631c9822c56Sreyk }
1632c9822c56Sreyk 
1633c9822c56Sreyk int
16343c03a838Sreyk bindany(struct ctl_bindany *bnd)
16353c03a838Sreyk {
16363c03a838Sreyk 	int	s, v;
16373c03a838Sreyk 
16383c03a838Sreyk 	s = -1;
16393c03a838Sreyk 	v = 1;
16403c03a838Sreyk 
16413c03a838Sreyk 	if (relay_socket_af(&bnd->bnd_ss, bnd->bnd_port) == -1)
16423c03a838Sreyk 		goto fail;
1643318e1f34Sreyk 	if ((s = socket(bnd->bnd_ss.ss_family,
1644318e1f34Sreyk 	    bnd->bnd_proto == IPPROTO_TCP ? SOCK_STREAM : SOCK_DGRAM,
16453c03a838Sreyk 	    bnd->bnd_proto)) == -1)
16463c03a838Sreyk 		goto fail;
16473c03a838Sreyk 	if (setsockopt(s, SOL_SOCKET, SO_BINDANY,
16483c03a838Sreyk 	    &v, sizeof(v)) == -1)
16493c03a838Sreyk 		goto fail;
16503c03a838Sreyk 	if (bind(s, (struct sockaddr *)&bnd->bnd_ss,
16513c03a838Sreyk 	    bnd->bnd_ss.ss_len) == -1)
16523c03a838Sreyk 		goto fail;
16533c03a838Sreyk 
16543c03a838Sreyk 	return (s);
16553c03a838Sreyk 
16563c03a838Sreyk  fail:
16573c03a838Sreyk 	if (s != -1)
16583c03a838Sreyk 		close(s);
16593c03a838Sreyk 	return (-1);
16603c03a838Sreyk }
1661c564d004Sreyk 
1662c564d004Sreyk int
1663c564d004Sreyk map6to4(struct sockaddr_storage *in6)
1664c564d004Sreyk {
1665c564d004Sreyk 	struct sockaddr_storage	 out4;
1666c564d004Sreyk 	struct sockaddr_in	*sin4 = (struct sockaddr_in *)&out4;
1667c564d004Sreyk 	struct sockaddr_in6	*sin6 = (struct sockaddr_in6 *)in6;
1668c564d004Sreyk 
1669c564d004Sreyk 	bzero(sin4, sizeof(*sin4));
1670c564d004Sreyk 	sin4->sin_len = sizeof(*sin4);
1671c564d004Sreyk 	sin4->sin_family = AF_INET;
1672c564d004Sreyk 	sin4->sin_port = sin6->sin6_port;
1673c564d004Sreyk 
1674c564d004Sreyk 	bcopy(&sin6->sin6_addr.s6_addr[12], &sin4->sin_addr.s_addr,
1675c564d004Sreyk 	    sizeof(sin4->sin_addr));
1676c564d004Sreyk 
1677c564d004Sreyk 	if (sin4->sin_addr.s_addr == INADDR_ANY ||
1678c564d004Sreyk 	    sin4->sin_addr.s_addr == INADDR_BROADCAST ||
1679c564d004Sreyk 	    IN_MULTICAST(ntohl(sin4->sin_addr.s_addr)))
1680c564d004Sreyk 		return (-1);
1681c564d004Sreyk 
1682c564d004Sreyk 	bcopy(&out4, in6, sizeof(*in6));
1683c564d004Sreyk 
1684c564d004Sreyk 	return (0);
1685c564d004Sreyk }
1686c564d004Sreyk 
1687c564d004Sreyk int
1688c564d004Sreyk map4to6(struct sockaddr_storage *in4, struct sockaddr_storage *map)
1689c564d004Sreyk {
1690c564d004Sreyk 	struct sockaddr_storage	 out6;
1691c564d004Sreyk 	struct sockaddr_in	*sin4 = (struct sockaddr_in *)in4;
1692c564d004Sreyk 	struct sockaddr_in6	*sin6 = (struct sockaddr_in6 *)&out6;
1693c564d004Sreyk 	struct sockaddr_in6	*map6 = (struct sockaddr_in6 *)map;
1694c564d004Sreyk 
1695c564d004Sreyk 	if (sin4->sin_addr.s_addr == INADDR_ANY ||
1696c564d004Sreyk 	    sin4->sin_addr.s_addr == INADDR_BROADCAST ||
1697c564d004Sreyk 	    IN_MULTICAST(ntohl(sin4->sin_addr.s_addr)))
1698c564d004Sreyk 		return (-1);
1699c564d004Sreyk 
1700c564d004Sreyk 	bcopy(map6, sin6, sizeof(*sin6));
1701c564d004Sreyk 	sin6->sin6_len = sizeof(*sin6);
1702c564d004Sreyk 	sin6->sin6_family = AF_INET6;
1703c564d004Sreyk 	sin6->sin6_port = sin4->sin_port;
1704c564d004Sreyk 
1705c564d004Sreyk 	bcopy(&sin4->sin_addr.s_addr, &sin6->sin6_addr.s6_addr[12],
1706c564d004Sreyk 	    sizeof(sin4->sin_addr));
1707c564d004Sreyk 
1708c564d004Sreyk 	bcopy(&out6, in4, sizeof(*in4));
1709c564d004Sreyk 
1710c564d004Sreyk 	return (0);
1711c564d004Sreyk }
1712bb8fa3feSreyk 
1713bb8fa3feSreyk void
1714bb8fa3feSreyk socket_rlimit(int maxfd)
1715bb8fa3feSreyk {
1716bb8fa3feSreyk 	struct rlimit	 rl;
1717bb8fa3feSreyk 
1718bb8fa3feSreyk 	if (getrlimit(RLIMIT_NOFILE, &rl) == -1)
1719efc39811Sbenno 		fatal("%s: failed to get resource limit", __func__);
17200ccd53b9Sguenther 	log_debug("%s: max open files %llu", __func__, rl.rlim_max);
1721bb8fa3feSreyk 
1722bb8fa3feSreyk 	/*
1723bb8fa3feSreyk 	 * Allow the maximum number of open file descriptors for this
1724bb8fa3feSreyk 	 * login class (which should be the class "daemon" by default).
1725bb8fa3feSreyk 	 */
1726bb8fa3feSreyk 	if (maxfd == -1)
1727bb8fa3feSreyk 		rl.rlim_cur = rl.rlim_max;
1728bb8fa3feSreyk 	else
1729e2318a52Sderaadt 		rl.rlim_cur = MAXIMUM(rl.rlim_max, (rlim_t)maxfd);
1730bb8fa3feSreyk 	if (setrlimit(RLIMIT_NOFILE, &rl) == -1)
1731efc39811Sbenno 		fatal("%s: failed to set resource limit", __func__);
1732bb8fa3feSreyk }
1733a2195becSreyk 
1734a2195becSreyk char *
1735a2195becSreyk get_string(u_int8_t *ptr, size_t len)
1736a2195becSreyk {
1737a2195becSreyk 	size_t	 i;
1738a2195becSreyk 
1739a2195becSreyk 	for (i = 0; i < len; i++)
1740d0296ba2Sreyk 		if (!(isprint((unsigned char)ptr[i]) ||
1741d0296ba2Sreyk 		    isspace((unsigned char)ptr[i])))
1742a2195becSreyk 			break;
1743a2195becSreyk 
1744b52b3078Smmcc 	return strndup(ptr, i);
1745a2195becSreyk }
1746a2195becSreyk 
1747a2195becSreyk void *
1748a2195becSreyk get_data(u_int8_t *ptr, size_t len)
1749a2195becSreyk {
1750a2195becSreyk 	u_int8_t	*data;
1751a2195becSreyk 
1752b52b3078Smmcc 	if ((data = malloc(len)) == NULL)
1753a2195becSreyk 		return (NULL);
1754a2195becSreyk 	memcpy(data, ptr, len);
1755a2195becSreyk 
1756a2195becSreyk 	return (data);
1757a2195becSreyk }
17582f89c21dSbenno 
17592f89c21dSbenno int
1760cb8b0e56Sreyk sockaddr_cmp(struct sockaddr *a, struct sockaddr *b, int prefixlen)
1761cb8b0e56Sreyk {
1762cb8b0e56Sreyk 	struct sockaddr_in	*a4, *b4;
1763cb8b0e56Sreyk 	struct sockaddr_in6	*a6, *b6;
1764cb8b0e56Sreyk 	u_int32_t		 av[4], bv[4], mv[4];
1765cb8b0e56Sreyk 
1766cb8b0e56Sreyk 	if (a->sa_family == AF_UNSPEC || b->sa_family == AF_UNSPEC)
1767cb8b0e56Sreyk 		return (0);
1768cb8b0e56Sreyk 	else if (a->sa_family > b->sa_family)
1769cb8b0e56Sreyk 		return (1);
1770cb8b0e56Sreyk 	else if (a->sa_family < b->sa_family)
1771cb8b0e56Sreyk 		return (-1);
1772cb8b0e56Sreyk 
1773cb8b0e56Sreyk 	if (prefixlen == -1)
1774cb8b0e56Sreyk 		memset(&mv, 0xff, sizeof(mv));
1775cb8b0e56Sreyk 
1776cb8b0e56Sreyk 	switch (a->sa_family) {
1777cb8b0e56Sreyk 	case AF_INET:
1778cb8b0e56Sreyk 		a4 = (struct sockaddr_in *)a;
1779cb8b0e56Sreyk 		b4 = (struct sockaddr_in *)b;
1780cb8b0e56Sreyk 
1781cb8b0e56Sreyk 		av[0] = a4->sin_addr.s_addr;
1782cb8b0e56Sreyk 		bv[0] = b4->sin_addr.s_addr;
1783cb8b0e56Sreyk 		if (prefixlen != -1)
1784cb8b0e56Sreyk 			mv[0] = prefixlen2mask(prefixlen);
1785cb8b0e56Sreyk 
1786cb8b0e56Sreyk 		if ((av[0] & mv[0]) > (bv[0] & mv[0]))
1787cb8b0e56Sreyk 			return (1);
1788cb8b0e56Sreyk 		if ((av[0] & mv[0]) < (bv[0] & mv[0]))
1789cb8b0e56Sreyk 			return (-1);
1790cb8b0e56Sreyk 		break;
1791cb8b0e56Sreyk 	case AF_INET6:
1792cb8b0e56Sreyk 		a6 = (struct sockaddr_in6 *)a;
1793cb8b0e56Sreyk 		b6 = (struct sockaddr_in6 *)b;
1794cb8b0e56Sreyk 
1795cb8b0e56Sreyk 		memcpy(&av, &a6->sin6_addr.s6_addr, 16);
1796cb8b0e56Sreyk 		memcpy(&bv, &b6->sin6_addr.s6_addr, 16);
1797cb8b0e56Sreyk 		if (prefixlen != -1)
1798cb8b0e56Sreyk 			prefixlen2mask6(prefixlen, mv);
1799cb8b0e56Sreyk 
1800cb8b0e56Sreyk 		if ((av[3] & mv[3]) > (bv[3] & mv[3]))
1801cb8b0e56Sreyk 			return (1);
1802cb8b0e56Sreyk 		if ((av[3] & mv[3]) < (bv[3] & mv[3]))
1803cb8b0e56Sreyk 			return (-1);
1804cb8b0e56Sreyk 		if ((av[2] & mv[2]) > (bv[2] & mv[2]))
1805cb8b0e56Sreyk 			return (1);
1806cb8b0e56Sreyk 		if ((av[2] & mv[2]) < (bv[2] & mv[2]))
1807cb8b0e56Sreyk 			return (-1);
1808cb8b0e56Sreyk 		if ((av[1] & mv[1]) > (bv[1] & mv[1]))
1809cb8b0e56Sreyk 			return (1);
1810cb8b0e56Sreyk 		if ((av[1] & mv[1]) < (bv[1] & mv[1]))
1811cb8b0e56Sreyk 			return (-1);
1812cb8b0e56Sreyk 		if ((av[0] & mv[0]) > (bv[0] & mv[0]))
1813cb8b0e56Sreyk 			return (1);
1814cb8b0e56Sreyk 		if ((av[0] & mv[0]) < (bv[0] & mv[0]))
1815cb8b0e56Sreyk 			return (-1);
1816cb8b0e56Sreyk 		break;
1817cb8b0e56Sreyk 	}
1818cb8b0e56Sreyk 
1819cb8b0e56Sreyk 	return (0);
1820cb8b0e56Sreyk }
1821cb8b0e56Sreyk 
1822cb8b0e56Sreyk u_int32_t
1823cb8b0e56Sreyk prefixlen2mask(u_int8_t prefixlen)
1824cb8b0e56Sreyk {
1825cb8b0e56Sreyk 	if (prefixlen == 0)
1826cb8b0e56Sreyk 		return (0);
1827cb8b0e56Sreyk 
1828cb8b0e56Sreyk 	if (prefixlen > 32)
1829cb8b0e56Sreyk 		prefixlen = 32;
1830cb8b0e56Sreyk 
1831cb8b0e56Sreyk 	return (htonl(0xffffffff << (32 - prefixlen)));
1832cb8b0e56Sreyk }
1833cb8b0e56Sreyk 
1834cb8b0e56Sreyk struct in6_addr *
1835cb8b0e56Sreyk prefixlen2mask6(u_int8_t prefixlen, u_int32_t *mask)
1836cb8b0e56Sreyk {
1837cb8b0e56Sreyk 	static struct in6_addr  s6;
1838cb8b0e56Sreyk 	int			i;
1839cb8b0e56Sreyk 
1840cb8b0e56Sreyk 	if (prefixlen > 128)
1841cb8b0e56Sreyk 		prefixlen = 128;
1842cb8b0e56Sreyk 
1843cb8b0e56Sreyk 	bzero(&s6, sizeof(s6));
1844cb8b0e56Sreyk 	for (i = 0; i < prefixlen / 8; i++)
1845cb8b0e56Sreyk 		s6.s6_addr[i] = 0xff;
1846cb8b0e56Sreyk 	i = prefixlen % 8;
1847cb8b0e56Sreyk 	if (i)
1848cb8b0e56Sreyk 		s6.s6_addr[prefixlen / 8] = 0xff00 >> i;
1849cb8b0e56Sreyk 
1850cb8b0e56Sreyk 	memcpy(mask, &s6, sizeof(s6));
1851cb8b0e56Sreyk 
1852cb8b0e56Sreyk 	return (&s6);
1853cb8b0e56Sreyk }
1854cb8b0e56Sreyk 
1855cb8b0e56Sreyk int
18562f89c21dSbenno accept_reserve(int sockfd, struct sockaddr *addr, socklen_t *addrlen,
18572f89c21dSbenno     int reserve, volatile int *counter)
18582f89c21dSbenno {
18592f89c21dSbenno 	int ret;
18602f89c21dSbenno 	if (getdtablecount() + reserve +
18612f89c21dSbenno 	    *counter >= getdtablesize()) {
18622f89c21dSbenno 		errno = EMFILE;
18634bfdeee0Sandre 		return (-1);
18642f89c21dSbenno 	}
18652f89c21dSbenno 
1866b045ffeeSreyk 	if ((ret = accept4(sockfd, addr, addrlen, SOCK_NONBLOCK)) > -1) {
18672f89c21dSbenno 		(*counter)++;
18684bfdeee0Sandre 		DPRINTF("%s: inflight incremented, now %d",__func__, *counter);
18692f89c21dSbenno 	}
18704bfdeee0Sandre 	return (ret);
18712f89c21dSbenno }
18729c908525Sclaudio 
18739c908525Sclaudio void
18749c908525Sclaudio parent_tls_ticket_rekey(int fd, short events, void *arg)
18759c908525Sclaudio {
18769c908525Sclaudio 	static struct event	 rekeyev;
18779c908525Sclaudio 	struct relayd		*env = arg;
18789c908525Sclaudio 	struct timeval		 tv;
187985e5f500Sclaudio 	struct relay_ticket_key	 key;
18809c908525Sclaudio 
1881efc39811Sbenno 	log_debug("%s: rekeying tickets", __func__);
18829c908525Sclaudio 
188385e5f500Sclaudio 	key.tt_keyrev = arc4random();
188485e5f500Sclaudio 	arc4random_buf(key.tt_key, sizeof(key.tt_key));
18859c908525Sclaudio 
18869c908525Sclaudio 	proc_compose_imsg(env->sc_ps, PROC_RELAY, -1, IMSG_TLSTICKET_REKEY,
18879c908525Sclaudio 	    -1, -1, &key, sizeof(key));
18889c908525Sclaudio 
18899c908525Sclaudio 	evtimer_set(&rekeyev, parent_tls_ticket_rekey, env);
18909c908525Sclaudio 	timerclear(&tv);
189185e5f500Sclaudio 	tv.tv_sec = TLS_SESSION_LIFETIME / 4;
18929c908525Sclaudio 	evtimer_add(&rekeyev, &tv);
18939c908525Sclaudio }
1894