xref: /openbsd-src/usr.sbin/relayd/relay.c (revision d13be5d47e4149db2549a9828e244d59dbc43f15)
1 /*	$OpenBSD: relay.c,v 1.141 2011/09/04 20:26:58 bluhm Exp $	*/
2 
3 /*
4  * Copyright (c) 2006, 2007, 2008 Reyk Floeter <reyk@openbsd.org>
5  *
6  * Permission to use, copy, modify, and distribute this software for any
7  * purpose with or without fee is hereby granted, provided that the above
8  * copyright notice and this permission notice appear in all copies.
9  *
10  * THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES
11  * WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF
12  * MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR
13  * ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES
14  * WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN
15  * ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF
16  * OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
17  */
18 
19 #include <sys/types.h>
20 #include <sys/queue.h>
21 #include <sys/time.h>
22 #include <sys/stat.h>
23 #include <sys/socket.h>
24 #include <sys/un.h>
25 #include <sys/tree.h>
26 #include <sys/hash.h>
27 
28 #include <net/if.h>
29 #include <netinet/in_systm.h>
30 #include <netinet/in.h>
31 #include <netinet/ip.h>
32 #include <netinet/tcp.h>
33 #include <arpa/inet.h>
34 
35 #include <errno.h>
36 #include <fcntl.h>
37 #include <stdlib.h>
38 #include <string.h>
39 #include <unistd.h>
40 #include <stdio.h>
41 #include <err.h>
42 #include <pwd.h>
43 #include <event.h>
44 #include <fnmatch.h>
45 
46 #include <openssl/ssl.h>
47 
48 #include "relayd.h"
49 
50 void		 relay_statistics(int, short, void *);
51 int		 relay_dispatch_parent(int, struct privsep_proc *,
52 		    struct imsg *);
53 int		 relay_dispatch_pfe(int, struct privsep_proc *,
54 		    struct imsg *);
55 void		 relay_shutdown(void);
56 
57 void		 relay_nodedebug(const char *, struct protonode *);
58 void		 relay_protodebug(struct relay *);
59 void		 relay_init(struct privsep *, struct privsep_proc *p, void *);
60 void		 relay_launch(void);
61 int		 relay_socket(struct sockaddr_storage *, in_port_t,
62 		    struct protocol *, int, int);
63 int		 relay_socket_listen(struct sockaddr_storage *, in_port_t,
64 		    struct protocol *);
65 int		 relay_socket_connect(struct sockaddr_storage *, in_port_t,
66 		    struct protocol *, int);
67 
68 void		 relay_accept(int, short, void *);
69 void		 relay_input(struct rsession *);
70 
71 int		 relay_connect(struct rsession *);
72 void		 relay_connected(int, short, void *);
73 void		 relay_bindanyreq(struct rsession *, in_port_t, int);
74 void		 relay_bindany(int, short, void *);
75 
76 u_int32_t	 relay_hash_addr(struct sockaddr_storage *, u_int32_t);
77 
78 void		 relay_write(struct bufferevent *, void *);
79 void		 relay_read(struct bufferevent *, void *);
80 int		 relay_splicelen(struct ctl_relay_event *);
81 void		 relay_error(struct bufferevent *, short, void *);
82 void		 relay_dump(struct ctl_relay_event *, const void *, size_t);
83 
84 int		 relay_resolve(struct ctl_relay_event *,
85 		    struct protonode *, struct protonode *);
86 int		 relay_handle_http(struct ctl_relay_event *,
87 		    struct protonode *, struct protonode *,
88 		    struct protonode *, int);
89 int		 relay_lognode(struct rsession *,
90 		    struct protonode *, struct protonode *, char *, size_t);
91 void		 relay_read_http(struct bufferevent *, void *);
92 static int	_relay_lookup_url(struct ctl_relay_event *, char *, char *,
93 		    char *, enum digest_type);
94 int		 relay_lookup_url(struct ctl_relay_event *,
95 		    const char *, enum digest_type);
96 int		 relay_lookup_query(struct ctl_relay_event *);
97 int		 relay_lookup_cookie(struct ctl_relay_event *, const char *);
98 void		 relay_read_httpcontent(struct bufferevent *, void *);
99 void		 relay_read_httpchunks(struct bufferevent *, void *);
100 char		*relay_expand_http(struct ctl_relay_event *, char *,
101 		    char *, size_t);
102 void		 relay_close_http(struct rsession *, u_int, const char *,
103 		    u_int16_t);
104 void		 relay_http_request_close(struct ctl_relay_event *);
105 
106 SSL_CTX		*relay_ssl_ctx_create(struct relay *);
107 void		 relay_ssl_transaction(struct rsession *,
108 		    struct ctl_relay_event *);
109 void		 relay_ssl_accept(int, short, void *);
110 void		 relay_ssl_connect(int, short, void *);
111 void		 relay_ssl_connected(struct ctl_relay_event *);
112 void		 relay_ssl_readcb(int, short, void *);
113 void		 relay_ssl_writecb(int, short, void *);
114 
115 int		 relay_bufferevent_add(struct event *, int);
116 #ifdef notyet
117 int		 relay_bufferevent_printf(struct ctl_relay_event *,
118 		    const char *, ...);
119 #endif
120 int		 relay_bufferevent_print(struct ctl_relay_event *, char *);
121 int		 relay_bufferevent_write_buffer(struct ctl_relay_event *,
122 		    struct evbuffer *);
123 int		 relay_bufferevent_write_chunk(struct ctl_relay_event *,
124 		    struct evbuffer *, size_t);
125 int		 relay_bufferevent_write(struct ctl_relay_event *,
126 		    void *, size_t);
127 char		*relay_load_file(const char *, off_t *);
128 static __inline int
129 		 relay_proto_cmp(struct protonode *, struct protonode *);
130 extern void	 bufferevent_read_pressure_cb(struct evbuffer *, size_t,
131 		    size_t, void *);
132 
133 volatile sig_atomic_t relay_sessions;
134 objid_t relay_conid;
135 
136 static struct relayd		*env = NULL;
137 int				 proc_id;
138 
139 static struct privsep_proc procs[] = {
140 	{ "parent",	PROC_PARENT,	relay_dispatch_parent },
141 	{ "pfe",	PROC_PFE,	relay_dispatch_pfe },
142 };
143 
144 pid_t
145 relay(struct privsep *ps, struct privsep_proc *p)
146 {
147 	env = ps->ps_env;
148 	return (proc_run(ps, p, procs, nitems(procs), relay_init, NULL));
149 }
150 
151 void
152 relay_shutdown(void)
153 {
154 	config_purge(env, CONFIG_ALL);
155 	usleep(200);	/* XXX relay needs to shutdown last */
156 }
157 
158 void
159 relay_nodedebug(const char *name, struct protonode *pn)
160 {
161 	const char	*s;
162 	int		 digest;
163 
164 	if (pn->action == NODE_ACTION_NONE)
165 		return;
166 
167 	fprintf(stderr, "\t\t");
168 	fprintf(stderr, "%s ", name);
169 
170 	switch (pn->type) {
171 	case NODE_TYPE_HEADER:
172 		break;
173 	case NODE_TYPE_QUERY:
174 		fprintf(stderr, "query ");
175 		break;
176 	case NODE_TYPE_COOKIE:
177 		fprintf(stderr, "cookie ");
178 		break;
179 	case NODE_TYPE_PATH:
180 		fprintf(stderr, "path ");
181 		break;
182 	case NODE_TYPE_URL:
183 		fprintf(stderr, "url ");
184 		break;
185 	}
186 
187 	switch (pn->action) {
188 	case NODE_ACTION_APPEND:
189 		fprintf(stderr, "append \"%s\" to \"%s\"",
190 		    pn->value, pn->key);
191 		break;
192 	case NODE_ACTION_CHANGE:
193 		fprintf(stderr, "change \"%s\" to \"%s\"",
194 		    pn->key, pn->value);
195 		break;
196 	case NODE_ACTION_REMOVE:
197 		fprintf(stderr, "remove \"%s\"",
198 		    pn->key);
199 		break;
200 	case NODE_ACTION_EXPECT:
201 	case NODE_ACTION_FILTER:
202 		s = pn->action == NODE_ACTION_EXPECT ? "expect" : "filter";
203 		digest = pn->flags & PNFLAG_LOOKUP_URL_DIGEST;
204 		if (strcmp(pn->value, "*") == 0)
205 			fprintf(stderr, "%s %s\"%s\"", s,
206 			    digest ? "digest " : "", pn->key);
207 		else
208 			fprintf(stderr, "%s \"%s\" from \"%s\"", s,
209 			    pn->value, pn->key);
210 		break;
211 	case NODE_ACTION_HASH:
212 		fprintf(stderr, "hash \"%s\"", pn->key);
213 		break;
214 	case NODE_ACTION_LOG:
215 		fprintf(stderr, "log \"%s\"", pn->key);
216 		break;
217 	case NODE_ACTION_MARK:
218 		if (strcmp(pn->value, "*") == 0)
219 			fprintf(stderr, "mark \"%s\"", pn->key);
220 		else
221 			fprintf(stderr, "mark \"%s\" from \"%s\"",
222 			    pn->value, pn->key);
223 		break;
224 	case NODE_ACTION_NONE:
225 		break;
226 	}
227 	fprintf(stderr, "\n");
228 }
229 
230 void
231 relay_protodebug(struct relay *rlay)
232 {
233 	struct protocol		*proto = rlay->rl_proto;
234 	struct protonode	*proot, *pn;
235 	struct proto_tree	*tree;
236 	const char		*name;
237 	int			 i;
238 
239 	fprintf(stderr, "protocol %d: name %s\n",
240 	    proto->id, proto->name);
241 	fprintf(stderr, "\tflags: %s, relay flags: %s\n",
242 	    printb_flags(proto->flags, F_BITS),
243 	    printb_flags(rlay->rl_conf.flags, F_BITS));
244 	if (proto->tcpflags)
245 		fprintf(stderr, "\ttcp flags: %s\n",
246 		    printb_flags(proto->tcpflags, TCPFLAG_BITS));
247 	if ((rlay->rl_conf.flags & (F_SSL|F_SSLCLIENT)) && proto->sslflags)
248 		fprintf(stderr, "\tssl flags: %s\n",
249 		    printb_flags(proto->sslflags, SSLFLAG_BITS));
250 	if (proto->cache != -1)
251 		fprintf(stderr, "\tssl session cache: %d\n", proto->cache);
252 	fprintf(stderr, "\ttype: ");
253 	switch (proto->type) {
254 	case RELAY_PROTO_TCP:
255 		fprintf(stderr, "tcp\n");
256 		break;
257 	case RELAY_PROTO_HTTP:
258 		fprintf(stderr, "http\n");
259 		break;
260 	case RELAY_PROTO_DNS:
261 		fprintf(stderr, "dns\n");
262 		break;
263 	}
264 
265 	name = "request";
266 	tree = &proto->request_tree;
267  show:
268 	i = 0;
269 	RB_FOREACH(proot, proto_tree, tree) {
270 #if DEBUG > 1
271 		i = 0;
272 #endif
273 		PROTONODE_FOREACH(pn, proot, entry) {
274 #if DEBUG > 1
275 			i = 0;
276 #endif
277 			if (++i > 100)
278 				break;
279 			relay_nodedebug(name, pn);
280 		}
281 		/* Limit the number of displayed lines */
282 		if (++i > 100) {
283 			fprintf(stderr, "\t\t...\n");
284 			break;
285 		}
286 	}
287 	if (tree == &proto->request_tree) {
288 		name = "response";
289 		tree = &proto->response_tree;
290 		goto show;
291 	}
292 }
293 
294 int
295 relay_privinit(struct relay *rlay)
296 {
297 	extern int	 debug;
298 
299 	log_debug("%s: adding relay %s", __func__, rlay->rl_conf.name);
300 
301 	if (debug)
302 		relay_protodebug(rlay);
303 
304 	switch (rlay->rl_proto->type) {
305 	case RELAY_PROTO_DNS:
306 		relay_udp_privinit(env, rlay);
307 		break;
308 	case RELAY_PROTO_TCP:
309 	case RELAY_PROTO_HTTP:
310 		/* Use defaults */
311 		break;
312 	}
313 
314 	if (rlay->rl_conf.flags & F_UDP)
315 		rlay->rl_s = relay_udp_bind(&rlay->rl_conf.ss,
316 		    rlay->rl_conf.port, rlay->rl_proto);
317 	else
318 		rlay->rl_s = relay_socket_listen(&rlay->rl_conf.ss,
319 		    rlay->rl_conf.port, rlay->rl_proto);
320 	if (rlay->rl_s == -1)
321 		return (-1);
322 
323 	return (0);
324 }
325 
326 void
327 relay_init(struct privsep *ps, struct privsep_proc *p, void *arg)
328 {
329 	struct timeval	 tv;
330 
331 	if (config_init(ps->ps_env) == -1)
332 		fatal("failed to initialize configuration");
333 
334 	/* We use a custom shutdown callback */
335 	p->p_shutdown = relay_shutdown;
336 
337 	/* Unlimited file descriptors (use system limits) */
338 	socket_rlimit(-1);
339 
340 	/* Schedule statistics timer */
341 	evtimer_set(&env->sc_statev, relay_statistics, NULL);
342 	bcopy(&env->sc_statinterval, &tv, sizeof(tv));
343 	evtimer_add(&env->sc_statev, &tv);
344 }
345 
346 void
347 relay_statistics(int fd, short events, void *arg)
348 {
349 	struct relay		*rlay;
350 	struct ctl_stats	 crs, *cur;
351 	struct timeval		 tv, tv_now;
352 	int			 resethour = 0, resetday = 0;
353 	struct rsession		*con, *next_con;
354 
355 	/*
356 	 * This is a hack to calculate some average statistics.
357 	 * It doesn't try to be very accurate, but could be improved...
358 	 */
359 
360 	timerclear(&tv);
361 	if (gettimeofday(&tv_now, NULL) == -1)
362 		fatal("relay_init: gettimeofday");
363 
364 	TAILQ_FOREACH(rlay, env->sc_relays, rl_entry) {
365 		bzero(&crs, sizeof(crs));
366 		resethour = resetday = 0;
367 
368 		cur = &rlay->rl_stats[proc_id];
369 		cur->cnt += cur->last;
370 		cur->tick++;
371 		cur->avg = (cur->last + cur->avg) / 2;
372 		cur->last_hour += cur->last;
373 		if ((cur->tick % (3600 / env->sc_statinterval.tv_sec)) == 0) {
374 			cur->avg_hour = (cur->last_hour + cur->avg_hour) / 2;
375 			resethour++;
376 		}
377 		cur->last_day += cur->last;
378 		if ((cur->tick % (86400 / env->sc_statinterval.tv_sec)) == 0) {
379 			cur->avg_day = (cur->last_day + cur->avg_day) / 2;
380 			resethour++;
381 		}
382 		bcopy(cur, &crs, sizeof(crs));
383 
384 		cur->last = 0;
385 		if (resethour)
386 			cur->last_hour = 0;
387 		if (resetday)
388 			cur->last_day = 0;
389 
390 		crs.id = rlay->rl_conf.id;
391 		crs.proc = proc_id;
392 		proc_compose_imsg(env->sc_ps, PROC_PFE, -1, IMSG_STATISTICS, -1,
393 		    &crs, sizeof(crs));
394 
395 		for (con = SPLAY_ROOT(&rlay->rl_sessions);
396 		    con != NULL; con = next_con) {
397 			next_con = SPLAY_NEXT(session_tree,
398 			    &rlay->rl_sessions, con);
399 			timersub(&tv_now, &con->se_tv_last, &tv);
400 			if (timercmp(&tv, &rlay->rl_conf.timeout, >=))
401 				relay_close(con, "hard timeout");
402 		}
403 	}
404 
405 	/* Schedule statistics timer */
406 	evtimer_set(&env->sc_statev, relay_statistics, NULL);
407 	bcopy(&env->sc_statinterval, &tv, sizeof(tv));
408 	evtimer_add(&env->sc_statev, &tv);
409 }
410 
411 void
412 relay_launch(void)
413 {
414 	void		(*callback)(int, short, void *);
415 	struct relay	*rlay;
416 	struct host	*host;
417 
418 	TAILQ_FOREACH(rlay, env->sc_relays, rl_entry) {
419 		if ((rlay->rl_conf.flags & (F_SSL|F_SSLCLIENT)) &&
420 		    (rlay->rl_ssl_ctx = relay_ssl_ctx_create(rlay)) == NULL)
421 			fatal("relay_init: failed to create SSL context");
422 
423 		if (rlay->rl_dsttable != NULL) {
424 			switch (rlay->rl_conf.dstmode) {
425 			case RELAY_DSTMODE_ROUNDROBIN:
426 				rlay->rl_dstkey = 0;
427 				break;
428 			case RELAY_DSTMODE_LOADBALANCE:
429 			case RELAY_DSTMODE_HASH:
430 				rlay->rl_dstkey =
431 				    hash32_str(rlay->rl_conf.name, HASHINIT);
432 				rlay->rl_dstkey =
433 				    hash32_str(rlay->rl_dsttable->conf.name,
434 				    rlay->rl_dstkey);
435 				break;
436 			}
437 			rlay->rl_dstnhosts = 0;
438 			TAILQ_FOREACH(host, &rlay->rl_dsttable->hosts, entry) {
439 				if (rlay->rl_dstnhosts >= RELAY_MAXHOSTS)
440 					fatal("relay_init: "
441 					    "too many hosts in table");
442 				host->idx = rlay->rl_dstnhosts;
443 				rlay->rl_dsthost[rlay->rl_dstnhosts++] = host;
444 			}
445 			log_info("adding %d hosts from table %s%s",
446 			    rlay->rl_dstnhosts, rlay->rl_dsttable->conf.name,
447 			    rlay->rl_dsttable->conf.check ? "" : " (no check)");
448 		}
449 
450 		switch (rlay->rl_proto->type) {
451 		case RELAY_PROTO_DNS:
452 			relay_udp_init(rlay);
453 			break;
454 		case RELAY_PROTO_TCP:
455 		case RELAY_PROTO_HTTP:
456 			/* Use defaults */
457 			break;
458 		}
459 
460 		log_debug("%s: running relay %s", __func__,
461 		    rlay->rl_conf.name);
462 
463 		rlay->rl_up = HOST_UP;
464 
465 		if (rlay->rl_conf.flags & F_UDP)
466 			callback = relay_udp_server;
467 		else
468 			callback = relay_accept;
469 
470 		event_set(&rlay->rl_ev, rlay->rl_s, EV_READ|EV_PERSIST,
471 		    callback, rlay);
472 		event_add(&rlay->rl_ev, NULL);
473 	}
474 }
475 
476 int
477 relay_socket_af(struct sockaddr_storage *ss, in_port_t port)
478 {
479 	switch (ss->ss_family) {
480 	case AF_INET:
481 		((struct sockaddr_in *)ss)->sin_port = port;
482 		((struct sockaddr_in *)ss)->sin_len =
483 		    sizeof(struct sockaddr_in);
484 		break;
485 	case AF_INET6:
486 		((struct sockaddr_in6 *)ss)->sin6_port = port;
487 		((struct sockaddr_in6 *)ss)->sin6_len =
488 		    sizeof(struct sockaddr_in6);
489 		break;
490 	default:
491 		return (-1);
492 	}
493 
494 	return (0);
495 }
496 
497 in_port_t
498 relay_socket_getport(struct sockaddr_storage *ss)
499 {
500 	switch (ss->ss_family) {
501 	case AF_INET:
502 		return (((struct sockaddr_in *)ss)->sin_port);
503 	case AF_INET6:
504 		return (((struct sockaddr_in6 *)ss)->sin6_port);
505 	default:
506 		return (0);
507 	}
508 
509 	/* NOTREACHED */
510 	return (0);
511 }
512 
513 int
514 relay_socket(struct sockaddr_storage *ss, in_port_t port,
515     struct protocol *proto, int fd, int reuseport)
516 {
517 	int s = -1, val;
518 	struct linger lng;
519 
520 	if (relay_socket_af(ss, port) == -1)
521 		goto bad;
522 
523 	s = fd == -1 ? socket(ss->ss_family, SOCK_STREAM, IPPROTO_TCP) : fd;
524 	if (s == -1)
525 		goto bad;
526 
527 	/*
528 	 * Socket options
529 	 */
530 	bzero(&lng, sizeof(lng));
531 	if (setsockopt(s, SOL_SOCKET, SO_LINGER, &lng, sizeof(lng)) == -1)
532 		goto bad;
533 	if (reuseport) {
534 		val = 1;
535 		if (setsockopt(s, SOL_SOCKET, SO_REUSEPORT, &val,
536 			sizeof(int)) == -1)
537 			goto bad;
538 	}
539 	if (fcntl(s, F_SETFL, O_NONBLOCK) == -1)
540 		goto bad;
541 	if (proto->tcpflags & TCPFLAG_BUFSIZ) {
542 		val = proto->tcpbufsiz;
543 		if (setsockopt(s, SOL_SOCKET, SO_RCVBUF,
544 		    &val, sizeof(val)) == -1)
545 			goto bad;
546 		val = proto->tcpbufsiz;
547 		if (setsockopt(s, SOL_SOCKET, SO_SNDBUF,
548 		    &val, sizeof(val)) == -1)
549 			goto bad;
550 	}
551 
552 	/*
553 	 * IP options
554 	 */
555 	if (proto->tcpflags & TCPFLAG_IPTTL) {
556 		val = (int)proto->tcpipttl;
557 		if (setsockopt(s, IPPROTO_IP, IP_TTL,
558 		    &val, sizeof(val)) == -1)
559 			goto bad;
560 	}
561 	if (proto->tcpflags & TCPFLAG_IPMINTTL) {
562 		val = (int)proto->tcpipminttl;
563 		if (setsockopt(s, IPPROTO_IP, IP_MINTTL,
564 		    &val, sizeof(val)) == -1)
565 			goto bad;
566 	}
567 
568 	/*
569 	 * TCP options
570 	 */
571 	if (proto->tcpflags & (TCPFLAG_NODELAY|TCPFLAG_NNODELAY)) {
572 		if (proto->tcpflags & TCPFLAG_NNODELAY)
573 			val = 0;
574 		else
575 			val = 1;
576 		if (setsockopt(s, IPPROTO_TCP, TCP_NODELAY,
577 		    &val, sizeof(val)) == -1)
578 			goto bad;
579 	}
580 	if (proto->tcpflags & (TCPFLAG_SACK|TCPFLAG_NSACK)) {
581 		if (proto->tcpflags & TCPFLAG_NSACK)
582 			val = 0;
583 		else
584 			val = 1;
585 		if (setsockopt(s, IPPROTO_TCP, TCP_SACK_ENABLE,
586 		    &val, sizeof(val)) == -1)
587 			goto bad;
588 	}
589 
590 	return (s);
591 
592  bad:
593 	if (s != -1)
594 		close(s);
595 	return (-1);
596 }
597 
598 int
599 relay_socket_connect(struct sockaddr_storage *ss, in_port_t port,
600     struct protocol *proto, int fd)
601 {
602 	int	s;
603 
604 	if ((s = relay_socket(ss, port, proto, fd, 0)) == -1)
605 		return (-1);
606 
607 	if (connect(s, (struct sockaddr *)ss, ss->ss_len) == -1) {
608 		if (errno != EINPROGRESS)
609 			goto bad;
610 	}
611 
612 	return (s);
613 
614  bad:
615 	close(s);
616 	return (-1);
617 }
618 
619 int
620 relay_socket_listen(struct sockaddr_storage *ss, in_port_t port,
621     struct protocol *proto)
622 {
623 	int s;
624 
625 	if ((s = relay_socket(ss, port, proto, -1, 1)) == -1)
626 		return (-1);
627 
628 	if (bind(s, (struct sockaddr *)ss, ss->ss_len) == -1)
629 		goto bad;
630 	if (listen(s, proto->tcpbacklog) == -1)
631 		goto bad;
632 
633 	return (s);
634 
635  bad:
636 	close(s);
637 	return (-1);
638 }
639 
640 void
641 relay_connected(int fd, short sig, void *arg)
642 {
643 	struct rsession		*con = (struct rsession *)arg;
644 	struct relay		*rlay = (struct relay *)con->se_relay;
645 	struct protocol		*proto = rlay->rl_proto;
646 	evbuffercb		 outrd = relay_read;
647 	evbuffercb		 outwr = relay_write;
648 	struct bufferevent	*bev;
649 	struct ctl_relay_event	*out = &con->se_out;
650 
651 	if (sig == EV_TIMEOUT) {
652 		relay_close_http(con, 504, "connect timeout", 0);
653 		return;
654 	}
655 
656 	if ((rlay->rl_conf.flags & F_SSLCLIENT) && (out->ssl == NULL)) {
657 		relay_ssl_transaction(con, out);
658 		return;
659 	}
660 
661 	DPRINTF("%s: session %d: %ssuccessful", __func__,
662 	    con->se_id, rlay->rl_proto->lateconnect ? "late connect " : "");
663 
664 	switch (rlay->rl_proto->type) {
665 	case RELAY_PROTO_HTTP:
666 		/* Check the servers's HTTP response */
667 		if (!RB_EMPTY(&rlay->rl_proto->response_tree)) {
668 			outrd = relay_read_http;
669 			if ((con->se_out.nodes = calloc(proto->response_nodes,
670 			    sizeof(u_int8_t))) == NULL) {
671 				relay_close_http(con, 500,
672 				    "failed to allocate nodes", 0);
673 				return;
674 			}
675 		}
676 		break;
677 	case RELAY_PROTO_TCP:
678 		if ((proto->tcpflags & TCPFLAG_NSPLICE) ||
679 		    (rlay->rl_conf.flags & (F_SSL|F_SSLCLIENT)))
680 			break;
681 		if (setsockopt(con->se_in.s, SOL_SOCKET, SO_SPLICE,
682 		    &con->se_out.s, sizeof(int)) == -1) {
683 			log_debug("%s: session %d: splice forward failed: %s",
684 			    __func__, con->se_id, strerror(errno));
685 			return;
686 		}
687 		con->se_in.splicelen = 0;
688 		if (setsockopt(con->se_out.s, SOL_SOCKET, SO_SPLICE,
689 		    &con->se_in.s, sizeof(int)) == -1) {
690 			log_debug("%s: session %d: splice backward failed: %s",
691 			    __func__, con->se_id, strerror(errno));
692 			return;
693 		}
694 		con->se_out.splicelen = 0;
695 		break;
696 	default:
697 		fatalx("relay_input: unknown protocol");
698 	}
699 
700 	/*
701 	 * Relay <-> Server
702 	 */
703 	bev = bufferevent_new(fd, outrd, outwr, relay_error, &con->se_out);
704 	if (bev == NULL) {
705 		relay_close_http(con, 500,
706 		    "failed to allocate output buffer event", 0);
707 		return;
708 	}
709 	evbuffer_free(bev->output);
710 	bev->output = con->se_out.output;
711 	if (bev->output == NULL)
712 		fatal("relay_connected: invalid output buffer");
713 	con->se_out.bev = bev;
714 
715 	/* Initialize the SSL wrapper */
716 	if ((rlay->rl_conf.flags & F_SSLCLIENT) && (out->ssl != NULL))
717 		relay_ssl_connected(out);
718 
719 	bufferevent_settimeout(bev,
720 	    rlay->rl_conf.timeout.tv_sec, rlay->rl_conf.timeout.tv_sec);
721 	bufferevent_enable(bev, EV_READ|EV_WRITE);
722 }
723 
724 void
725 relay_input(struct rsession *con)
726 {
727 	struct relay	*rlay = (struct relay *)con->se_relay;
728 	struct protocol *proto = rlay->rl_proto;
729 	evbuffercb	 inrd = relay_read;
730 	evbuffercb	 inwr = relay_write;
731 
732 	switch (rlay->rl_proto->type) {
733 	case RELAY_PROTO_HTTP:
734 		/* Check the client's HTTP request */
735 		if (!RB_EMPTY(&rlay->rl_proto->request_tree) ||
736 		    proto->lateconnect) {
737 			inrd = relay_read_http;
738 			if ((con->se_in.nodes = calloc(proto->request_nodes,
739 			    sizeof(u_int8_t))) == NULL) {
740 				relay_close(con, "failed to allocate nodes");
741 				return;
742 			}
743 		}
744 		break;
745 	case RELAY_PROTO_TCP:
746 		/* Use defaults */
747 		break;
748 	default:
749 		fatalx("relay_input: unknown protocol");
750 	}
751 
752 	/*
753 	 * Client <-> Relay
754 	 */
755 	con->se_in.bev = bufferevent_new(con->se_in.s, inrd, inwr,
756 	    relay_error, &con->se_in);
757 	if (con->se_in.bev == NULL) {
758 		relay_close(con, "failed to allocate input buffer event");
759 		return;
760 	}
761 
762 	/* Initialize the SSL wrapper */
763 	if ((rlay->rl_conf.flags & F_SSL) && con->se_in.ssl != NULL)
764 		relay_ssl_connected(&con->se_in);
765 
766 	bufferevent_settimeout(con->se_in.bev,
767 	    rlay->rl_conf.timeout.tv_sec, rlay->rl_conf.timeout.tv_sec);
768 	bufferevent_enable(con->se_in.bev, EV_READ|EV_WRITE);
769 }
770 
771 void
772 relay_write(struct bufferevent *bev, void *arg)
773 {
774 	struct ctl_relay_event	*cre = (struct ctl_relay_event *)arg;
775 	struct rsession		*con = cre->con;
776 	if (gettimeofday(&con->se_tv_last, NULL) == -1)
777 		con->se_done = 1;
778 	if (con->se_done)
779 		relay_close(con, "last write (done)");
780 }
781 
782 void
783 relay_dump(struct ctl_relay_event *cre, const void *buf, size_t len)
784 {
785 	if (!len)
786 		return;
787 
788 	/*
789 	 * This function will dump the specified message directly
790 	 * to the underlying session, without waiting for success
791 	 * of non-blocking events etc. This is useful to print an
792 	 * error message before gracefully closing the session.
793 	 */
794 	if (cre->ssl != NULL)
795 		(void)SSL_write(cre->ssl, buf, len);
796 	else
797 		(void)write(cre->s, buf, len);
798 }
799 
800 void
801 relay_read(struct bufferevent *bev, void *arg)
802 {
803 	struct ctl_relay_event	*cre = (struct ctl_relay_event *)arg;
804 	struct rsession		*con = cre->con;
805 	struct evbuffer		*src = EVBUFFER_INPUT(bev);
806 
807 	if (gettimeofday(&con->se_tv_last, NULL) == -1)
808 		goto fail;
809 	if (!EVBUFFER_LENGTH(src))
810 		return;
811 	if (relay_bufferevent_write_buffer(cre->dst, src) == -1)
812 		goto fail;
813 	if (con->se_done)
814 		goto done;
815 	if (cre->dst->bev)
816 		bufferevent_enable(cre->dst->bev, EV_READ);
817 	return;
818  done:
819 	relay_close(con, "last read (done)");
820 	return;
821  fail:
822 	relay_close(con, strerror(errno));
823 }
824 
825 int
826 relay_resolve(struct ctl_relay_event *cre,
827     struct protonode *proot, struct protonode *pn)
828 {
829 	struct rsession		*con = cre->con;
830 	char			 buf[IBUF_READ_SIZE], *ptr;
831 	int			 id;
832 
833 	if (pn->mark && (pn->mark != con->se_mark))
834 		return (0);
835 
836 	switch (pn->action) {
837 	case NODE_ACTION_FILTER:
838 		id = cre->nodes[proot->id];
839 		if (SIMPLEQ_NEXT(pn, entry) == NULL)
840 			cre->nodes[proot->id] = 0;
841 		if (id <= 1)
842 			return (0);
843 		break;
844 	case NODE_ACTION_EXPECT:
845 		id = cre->nodes[proot->id];
846 		if (SIMPLEQ_NEXT(pn, entry) == NULL)
847 			cre->nodes[proot->id] = 0;
848 		if (id > 1)
849 			return (0);
850 		break;
851 	default:
852 		if (cre->nodes[pn->id]) {
853 			cre->nodes[pn->id] = 0;
854 			return (0);
855 		}
856 		break;
857 	}
858 	switch (pn->action) {
859 	case NODE_ACTION_APPEND:
860 	case NODE_ACTION_CHANGE:
861 		ptr = pn->value;
862 		if ((pn->flags & PNFLAG_MACRO) &&
863 		    (ptr = relay_expand_http(cre, pn->value,
864 		    buf, sizeof(buf))) == NULL)
865 			break;
866 		if (relay_bufferevent_print(cre->dst, pn->key) == -1 ||
867 		    relay_bufferevent_print(cre->dst, ": ") == -1 ||
868 		    relay_bufferevent_print(cre->dst, ptr) == -1 ||
869 		    relay_bufferevent_print(cre->dst, "\r\n") == -1) {
870 			relay_close_http(con, 500,
871 			    "failed to modify header", 0);
872 			return (-1);
873 		}
874 		DPRINTF("%s: add '%s: %s'", __func__, pn->key, ptr);
875 		break;
876 	case NODE_ACTION_EXPECT:
877 		DPRINTF("%s: missing '%s: %s'", __func__, pn->key, pn->value);
878 		relay_close_http(con, 403, "incomplete request", pn->label);
879 		return (-1);
880 	case NODE_ACTION_FILTER:
881 		DPRINTF("%s: filtered '%s: %s'", __func__, pn->key, pn->value);
882 		relay_close_http(con, 403, "rejecting request", pn->label);
883 		return (-1);
884 	default:
885 		break;
886 	}
887 	return (0);
888 }
889 
890 char *
891 relay_expand_http(struct ctl_relay_event *cre, char *val, char *buf, size_t len)
892 {
893 	struct rsession	*con = cre->con;
894 	struct relay	*rlay = (struct relay *)con->se_relay;
895 	char		 ibuf[128];
896 
897 	(void)strlcpy(buf, val, len);
898 
899 	if (strstr(val, "$REMOTE_") != NULL) {
900 		if (strstr(val, "$REMOTE_ADDR") != NULL) {
901 			if (print_host(&cre->ss, ibuf, sizeof(ibuf)) == NULL)
902 				return (NULL);
903 			if (expand_string(buf, len,
904 			    "$REMOTE_ADDR", ibuf) != 0)
905 				return (NULL);
906 		}
907 		if (strstr(val, "$REMOTE_PORT") != NULL) {
908 			snprintf(ibuf, sizeof(ibuf), "%u", ntohs(cre->port));
909 			if (expand_string(buf, len,
910 			    "$REMOTE_PORT", ibuf) != 0)
911 				return (NULL);
912 		}
913 	}
914 	if (strstr(val, "$SERVER_") != NULL) {
915 		if (strstr(val, "$SERVER_ADDR") != NULL) {
916 			if (print_host(&rlay->rl_conf.ss,
917 			    ibuf, sizeof(ibuf)) == NULL)
918 				return (NULL);
919 			if (expand_string(buf, len,
920 			    "$SERVER_ADDR", ibuf) != 0)
921 				return (NULL);
922 		}
923 		if (strstr(val, "$SERVER_PORT") != NULL) {
924 			snprintf(ibuf, sizeof(ibuf), "%u",
925 			    ntohs(rlay->rl_conf.port));
926 			if (expand_string(buf, len,
927 			    "$SERVER_PORT", ibuf) != 0)
928 				return (NULL);
929 		}
930 		if (strstr(val, "$SERVER_NAME") != NULL) {
931 			if (expand_string(buf, len,
932 			    "$SERVER_NAME", RELAYD_SERVERNAME) != 0)
933 				return (NULL);
934 		}
935 	}
936 	if (strstr(val, "$TIMEOUT") != NULL) {
937 		snprintf(ibuf, sizeof(ibuf), "%lu",
938 		    rlay->rl_conf.timeout.tv_sec);
939 		if (expand_string(buf, len, "$TIMEOUT", ibuf) != 0)
940 			return (NULL);
941 	}
942 
943 	return (buf);
944 }
945 
946 int
947 relay_lognode(struct rsession *con, struct protonode *pn, struct protonode *pk,
948     char *buf, size_t len)
949 {
950 	const char		*label = NULL;
951 
952 	if ((pn->flags & PNFLAG_LOG) == 0)
953 		return (0);
954 	bzero(buf, len);
955 	if (pn->label != 0)
956 		label = pn_id2name(pn->label);
957 	if (snprintf(buf, len, " [%s%s%s: %s]",
958 	    label == NULL ? "" : label,
959 	    label == NULL ? "" : ", ",
960 	    pk->key, pk->value) == -1 ||
961 	    evbuffer_add(con->se_log, buf, strlen(buf)) == -1)
962 		return (-1);
963 	return (0);
964 }
965 
966 int
967 relay_handle_http(struct ctl_relay_event *cre, struct protonode *proot,
968     struct protonode *pn, struct protonode *pk, int header)
969 {
970 	struct rsession		*con = cre->con;
971 	char			 buf[IBUF_READ_SIZE], *ptr;
972 	int			 ret = PN_DROP, mark = 0;
973 	struct protonode	*next;
974 
975 	/* Check if this action depends on a marked session */
976 	if (pn->mark != 0)
977 		mark = pn->mark == con->se_mark ? 1 : -1;
978 
979 	switch (pn->action) {
980 	case NODE_ACTION_EXPECT:
981 	case NODE_ACTION_FILTER:
982 	case NODE_ACTION_MARK:
983 		break;
984 	default:
985 		if (mark == -1)
986 			return (PN_PASS);
987 		break;
988 	}
989 
990 	switch (pn->action) {
991 	case NODE_ACTION_APPEND:
992 		if (!header)
993 			return (PN_PASS);
994 		ptr = pn->value;
995 		if ((pn->flags & PNFLAG_MACRO) &&
996 		    (ptr = relay_expand_http(cre, pn->value,
997 		    buf, sizeof(buf))) == NULL)
998 			break;
999 		if (relay_bufferevent_print(cre->dst, pn->key) == -1 ||
1000 		    relay_bufferevent_print(cre->dst, ": ") == -1 ||
1001 		    relay_bufferevent_print(cre->dst, pk->value) == -1 ||
1002 		    relay_bufferevent_print(cre->dst, ", ") == -1 ||
1003 		    relay_bufferevent_print(cre->dst, ptr) == -1 ||
1004 		    relay_bufferevent_print(cre->dst, "\r\n") == -1)
1005 			goto fail;
1006 		cre->nodes[pn->id] = 1;
1007 		DPRINTF("%s: append '%s: %s, %s'", __func__,
1008 		    pk->key, pk->value, ptr);
1009 		break;
1010 	case NODE_ACTION_CHANGE:
1011 	case NODE_ACTION_REMOVE:
1012 		if (!header)
1013 			return (PN_PASS);
1014 		DPRINTF("%s: change/remove '%s: %s'", __func__,
1015 		    pk->key, pk->value);
1016 		break;
1017 	case NODE_ACTION_EXPECT:
1018 		/*
1019 		 * A client may specify the header line for multiple times
1020 		 * trying to circumvent the filter.
1021 		 */
1022 		if (cre->nodes[proot->id] > 1) {
1023 			relay_close_http(con, 400, "repeated header line", 0);
1024 			return (PN_FAIL);
1025 		}
1026 		/* FALLTHROUGH */
1027 	case NODE_ACTION_FILTER:
1028 		DPRINTF("%s: %s '%s: %s'", __func__,
1029 		    (pn->action == NODE_ACTION_EXPECT) ? "expect" : "filter",
1030 		    pn->key, pn->value);
1031 
1032 		/* Do not drop the entity */
1033 		ret = PN_PASS;
1034 
1035 		if (mark != -1 &&
1036 		    fnmatch(pn->value, pk->value, FNM_CASEFOLD) == 0) {
1037 			cre->nodes[proot->id] = 1;
1038 
1039 			/* Fail instantly */
1040 			if (pn->action == NODE_ACTION_FILTER) {
1041 				(void)relay_lognode(con, pn, pk,
1042 				    buf, sizeof(buf));
1043 				relay_close_http(con, 403,
1044 				    "rejecting request", pn->label);
1045 				return (PN_FAIL);
1046 			}
1047 		}
1048 		next = SIMPLEQ_NEXT(pn, entry);
1049 		if (next == NULL || next->action != pn->action)
1050 			cre->nodes[proot->id]++;
1051 		break;
1052 	case NODE_ACTION_HASH:
1053 		DPRINTF("%s: hash '%s: %s'", __func__,
1054 		    pn->key, pk->value);
1055 		con->se_hashkey = hash32_str(pk->value, con->se_hashkey);
1056 		ret = PN_PASS;
1057 		break;
1058 	case NODE_ACTION_LOG:
1059 		DPRINTF("%s: log '%s: %s'", __func__,
1060 		    pn->key, pk->value);
1061 		ret = PN_PASS;
1062 		break;
1063 	case NODE_ACTION_MARK:
1064 		DPRINTF("%s: mark '%s: %s'", __func__,
1065 		    pn->key, pk->value);
1066 		if (fnmatch(pn->value, pk->value, FNM_CASEFOLD) == 0)
1067 			con->se_mark = pn->mark;
1068 		ret = PN_PASS;
1069 		break;
1070 	case NODE_ACTION_NONE:
1071 		return (PN_PASS);
1072 	}
1073 	if (mark != -1 && relay_lognode(con, pn, pk, buf, sizeof(buf)) == -1)
1074 		goto fail;
1075 
1076 	return (ret);
1077  fail:
1078 	relay_close_http(con, 500, strerror(errno), 0);
1079 	return (PN_FAIL);
1080 }
1081 
1082 void
1083 relay_read_httpcontent(struct bufferevent *bev, void *arg)
1084 {
1085 	struct ctl_relay_event	*cre = (struct ctl_relay_event *)arg;
1086 	struct rsession		*con = cre->con;
1087 	struct evbuffer		*src = EVBUFFER_INPUT(bev);
1088 	size_t			 size;
1089 
1090 	if (gettimeofday(&con->se_tv_last, NULL) == -1)
1091 		goto fail;
1092 	size = EVBUFFER_LENGTH(src);
1093 	DPRINTF("%s: size %d, to read %d", __func__,
1094 	    size, cre->toread);
1095 	if (!size)
1096 		return;
1097 	if (relay_bufferevent_write_buffer(cre->dst, src) == -1)
1098 		goto fail;
1099 	if (size >= cre->toread)
1100 		bev->readcb = relay_read_http;
1101 	cre->toread -= size;
1102 	DPRINTF("%s: done, size %d, to read %d", __func__,
1103 	    size, cre->toread);
1104 	if (con->se_done)
1105 		goto done;
1106 	if (bev->readcb != relay_read_httpcontent)
1107 		bev->readcb(bev, arg);
1108 	bufferevent_enable(bev, EV_READ);
1109 	return;
1110  done:
1111 	relay_close(con, "last http content read");
1112 	return;
1113  fail:
1114 	relay_close(con, strerror(errno));
1115 }
1116 
1117 void
1118 relay_read_httpchunks(struct bufferevent *bev, void *arg)
1119 {
1120 	struct ctl_relay_event	*cre = (struct ctl_relay_event *)arg;
1121 	struct rsession		*con = cre->con;
1122 	struct evbuffer		*src = EVBUFFER_INPUT(bev);
1123 	char			*line;
1124 	long			 lval;
1125 	size_t			 size;
1126 
1127 	if (gettimeofday(&con->se_tv_last, NULL) == -1)
1128 		goto fail;
1129 	size = EVBUFFER_LENGTH(src);
1130 	DPRINTF("%s: size %d, to read %d", __func__,
1131 	    size, cre->toread);
1132 	if (!size)
1133 		return;
1134 
1135 	if (!cre->toread) {
1136 		line = evbuffer_readline(src);
1137 		if (line == NULL) {
1138 			/* Ignore empty line, continue */
1139 			bufferevent_enable(bev, EV_READ);
1140 			return;
1141 		}
1142 		if (!strlen(line)) {
1143 			free(line);
1144 			goto next;
1145 		}
1146 
1147 		/* Read prepended chunk size in hex, ingore the trailer */
1148 		if (sscanf(line, "%lx", &lval) != 1) {
1149 			free(line);
1150 			relay_close(con, "invalid chunk size");
1151 			return;
1152 		}
1153 
1154 		if (relay_bufferevent_print(cre->dst, line) == -1 ||
1155 		    relay_bufferevent_print(cre->dst, "\r\n") == -1) {
1156 			free(line);
1157 			goto fail;
1158 		}
1159 		free(line);
1160 
1161 		/* Last chunk is 0 bytes followed by an empty newline */
1162 		if ((cre->toread = lval) == 0) {
1163 			DPRINTF("%s: last chunk", __func__);
1164 
1165 			line = evbuffer_readline(src);
1166 			if (line == NULL) {
1167 				relay_close(con, "invalid last chunk");
1168 				return;
1169 			}
1170 			free(line);
1171 			if (relay_bufferevent_print(cre->dst, "\r\n") == -1)
1172 				goto fail;
1173 
1174 			/* Switch to HTTP header mode */
1175 			bev->readcb = relay_read_http;
1176 		}
1177 	} else {
1178 		/* Read chunk data */
1179 		if (size > cre->toread)
1180 			size = cre->toread;
1181 		if (relay_bufferevent_write_chunk(cre->dst, src, size) == -1)
1182 			goto fail;
1183 		cre->toread -= size;
1184 		DPRINTF("%s: done, size %d, to read %d", __func__,
1185 		    size, cre->toread);
1186 
1187 		if (cre->toread == 0) {
1188 			/* Chunk is terminated by an empty (empty) newline */
1189 			line = evbuffer_readline(src);
1190 			if (line != NULL)
1191 				free(line);
1192 			if (relay_bufferevent_print(cre->dst, "\r\n\r\n") == -1)
1193 				goto fail;
1194 		}
1195 	}
1196 
1197  next:
1198 	if (con->se_done)
1199 		goto done;
1200 	if (EVBUFFER_LENGTH(src))
1201 		bev->readcb(bev, arg);
1202 	bufferevent_enable(bev, EV_READ);
1203 	return;
1204 
1205  done:
1206 	relay_close(con, "last http chunk read (done)");
1207 	return;
1208  fail:
1209 	relay_close(con, strerror(errno));
1210 }
1211 
1212 void
1213 relay_http_request_close(struct ctl_relay_event *cre)
1214 {
1215 	if (cre->path != NULL) {
1216 		free(cre->path);
1217 		cre->path = NULL;
1218 	}
1219 
1220 	cre->args = NULL;
1221 	cre->version = NULL;
1222 
1223 	if (cre->buf != NULL) {
1224 		free(cre->buf);
1225 		cre->buf = NULL;
1226 		cre->buflen = 0;
1227 	}
1228 
1229 	cre->line = 0;
1230 	cre->method = 0;
1231 	cre->done = 0;
1232 	cre->chunked = 0;
1233 }
1234 
1235 void
1236 relay_read_http(struct bufferevent *bev, void *arg)
1237 {
1238 	struct ctl_relay_event	*cre = (struct ctl_relay_event *)arg;
1239 	struct rsession		*con = cre->con;
1240 	struct relay		*rlay = (struct relay *)con->se_relay;
1241 	struct protocol		*proto = rlay->rl_proto;
1242 	struct evbuffer		*src = EVBUFFER_INPUT(bev);
1243 	struct protonode	*pn, pk, *proot, *pnv = NULL, pkv;
1244 	char			*line;
1245 	int			 header = 0, ret, pass = 0;
1246 	const char		*errstr;
1247 	size_t			 size;
1248 
1249 	if (gettimeofday(&con->se_tv_last, NULL) == -1)
1250 		goto fail;
1251 	size = EVBUFFER_LENGTH(src);
1252 	DPRINTF("%s: size %d, to read %d", __func__, size, cre->toread);
1253 	if (!size) {
1254 		if (cre->dir == RELAY_DIR_RESPONSE)
1255 			return;
1256 		cre->toread = 0;
1257 		goto done;
1258 	}
1259 
1260 	pk.type = NODE_TYPE_HEADER;
1261 
1262 	while (!cre->done && (line = evbuffer_readline(src)) != NULL) {
1263 		/*
1264 		 * An empty line indicates the end of the request.
1265 		 * libevent already stripped the \r\n for us.
1266 		 */
1267 		if (!strlen(line)) {
1268 			cre->done = 1;
1269 			free(line);
1270 			break;
1271 		}
1272 		pk.key = line;
1273 
1274 		/*
1275 		 * The first line is the GET/POST/PUT/... request,
1276 		 * subsequent lines are HTTP headers.
1277 		 */
1278 		if (++cre->line == 1) {
1279 			pk.value = strchr(pk.key, ' ');
1280 		} else
1281 			pk.value = strchr(pk.key, ':');
1282 		if (pk.value == NULL || strlen(pk.value) < 3) {
1283 			if (cre->line == 1) {
1284 				free(line);
1285 				relay_close_http(con, 400, "malformed", 0);
1286 				return;
1287 			}
1288 
1289 			DPRINTF("%s: request '%s'", __func__, line);
1290 			/* Append line to the output buffer */
1291 			if (relay_bufferevent_print(cre->dst, line) == -1 ||
1292 			    relay_bufferevent_print(cre->dst, "\r\n") == -1) {
1293 				free(line);
1294 				goto fail;
1295 			}
1296 			free(line);
1297 			continue;
1298 		}
1299 		if (*pk.value == ':') {
1300 			*pk.value++ = '\0';
1301 			pk.value += strspn(pk.value, " \t\r\n");
1302 			header = 1;
1303 		} else {
1304 			*pk.value++ = '\0';
1305 			header = 0;
1306 		}
1307 
1308 		DPRINTF("%s: header '%s: %s'", __func__, pk.key, pk.value);
1309 
1310 		/*
1311 		 * Identify and handle specific HTTP request methods
1312 		 */
1313 		if (cre->line == 1) {
1314 			if (cre->dir == RELAY_DIR_RESPONSE) {
1315 				cre->method = HTTP_METHOD_RESPONSE;
1316 				goto lookup;
1317 			} else if (strcmp("HEAD", pk.key) == 0)
1318 				cre->method = HTTP_METHOD_HEAD;
1319 			else if (strcmp("POST", pk.key) == 0)
1320 				cre->method = HTTP_METHOD_POST;
1321 			else if (strcmp("PUT", pk.key) == 0)
1322 				cre->method = HTTP_METHOD_PUT;
1323 			else if (strcmp("DELETE", pk.key) == 0)
1324 				cre->method = HTTP_METHOD_DELETE;
1325 			else if (strcmp("OPTIONS", pk.key) == 0)
1326 				cre->method = HTTP_METHOD_OPTIONS;
1327 			else if (strcmp("TRACE", pk.key) == 0)
1328 				cre->method = HTTP_METHOD_TRACE;
1329 			else if (strcmp("CONNECT", pk.key) == 0)
1330 				cre->method = HTTP_METHOD_CONNECT;
1331 			else {
1332 				/* Use GET method as the default */
1333 				cre->method = HTTP_METHOD_GET;
1334 			}
1335 
1336 			/*
1337 			 * Decode the path and query
1338 			 */
1339 			cre->path = strdup(pk.value);
1340 			if (cre->path == NULL) {
1341 				free(line);
1342 				goto fail;
1343 			}
1344 			cre->version = strchr(cre->path, ' ');
1345 			if (cre->version != NULL)
1346 				*cre->version++ = '\0';
1347 			cre->args = strchr(cre->path, '?');
1348 			if (cre->args != NULL)
1349 				*cre->args++ = '\0';
1350 #ifdef DEBUG
1351 			char	 buf[BUFSIZ];
1352 			if (snprintf(buf, sizeof(buf), " \"%s\"",
1353 			    cre->path) == -1 ||
1354 			    evbuffer_add(con->se_log, buf, strlen(buf)) == -1) {
1355 				free(line);
1356 				goto fail;
1357 			}
1358 #endif
1359 
1360 			/*
1361 			 * Lookup protocol handlers in the URL path
1362 			 */
1363 			if ((proto->flags & F_LOOKUP_PATH) == 0)
1364 				goto lookup;
1365 
1366 			pkv.key = cre->path;
1367 			pkv.type = NODE_TYPE_PATH;
1368 			pkv.value = cre->args == NULL ? "" : cre->args;
1369 
1370 			DPRINTF("%s: lookup path '%s: %s'",
1371 			    __func__, pkv.key, pkv.value);
1372 
1373 			if ((proot = RB_FIND(proto_tree,
1374 			    cre->tree, &pkv)) == NULL)
1375 				goto lookup;
1376 
1377 			PROTONODE_FOREACH(pnv, proot, entry) {
1378 				ret = relay_handle_http(cre, proot,
1379 				    pnv, &pkv, 0);
1380 				if (ret == PN_FAIL)
1381 					goto abort;
1382 			}
1383 		} else if ((cre->method == HTTP_METHOD_POST ||
1384 		    cre->method == HTTP_METHOD_PUT ||
1385 		    cre->method == HTTP_METHOD_RESPONSE) &&
1386 		    strcasecmp("Content-Length", pk.key) == 0) {
1387 			/*
1388 			 * Need to read data from the client after the
1389 			 * HTTP header.
1390 			 * XXX What about non-standard clients not using
1391 			 * the carriage return? And some browsers seem to
1392 			 * include the line length in the content-length.
1393 			 */
1394 			cre->toread = strtonum(pk.value, 0, INT_MAX, &errstr);
1395 			if (errstr) {
1396 				relay_close_http(con, 500, errstr, 0);
1397 				goto abort;
1398 			}
1399 		}
1400  lookup:
1401 		if (strcasecmp("Transfer-Encoding", pk.key) == 0 &&
1402 		    strcasecmp("chunked", pk.value) == 0)
1403 			cre->chunked = 1;
1404 
1405 		/* Match the HTTP header */
1406 		if ((pn = RB_FIND(proto_tree, cre->tree, &pk)) == NULL)
1407 			goto next;
1408 
1409 		if (cre->dir == RELAY_DIR_RESPONSE)
1410 			goto handle;
1411 
1412 		if (pn->flags & PNFLAG_LOOKUP_URL) {
1413 			/*
1414 			 * Lookup the URL of type example.com/path?args.
1415 			 * Either as a plain string or SHA1/MD5 digest.
1416 			 */
1417 			if ((pn->flags & PNFLAG_LOOKUP_DIGEST(0)) &&
1418 			    relay_lookup_url(cre, pk.value,
1419 			    DIGEST_NONE) == PN_FAIL)
1420 				goto abort;
1421 			if ((pn->flags & PNFLAG_LOOKUP_DIGEST(DIGEST_SHA1)) &&
1422 			    relay_lookup_url(cre, pk.value,
1423 			    DIGEST_SHA1) == PN_FAIL)
1424 				goto abort;
1425 			if ((pn->flags & PNFLAG_LOOKUP_DIGEST(DIGEST_MD5)) &&
1426 			    relay_lookup_url(cre, pk.value,
1427 			    DIGEST_MD5) == PN_FAIL)
1428 				goto abort;
1429 		} else if (pn->flags & PNFLAG_LOOKUP_QUERY) {
1430 			/* Lookup the HTTP query arguments */
1431 			if (relay_lookup_query(cre) == PN_FAIL)
1432 				goto abort;
1433 		} else if (pn->flags & PNFLAG_LOOKUP_COOKIE) {
1434 			/* Lookup the HTTP cookie */
1435 			if (relay_lookup_cookie(cre, pk.value) == PN_FAIL)
1436 				goto abort;
1437 		}
1438 
1439  handle:
1440 		pass = 0;
1441 		PROTONODE_FOREACH(pnv, pn, entry) {
1442 			ret = relay_handle_http(cre, pn, pnv, &pk, header);
1443 			if (ret == PN_PASS)
1444 				pass = 1;
1445 			else if (ret == PN_FAIL)
1446 				goto abort;
1447 		}
1448 
1449 		if (pass) {
1450  next:
1451 			if (relay_bufferevent_print(cre->dst, pk.key) == -1 ||
1452 			    relay_bufferevent_print(cre->dst,
1453 			    header ? ": " : " ") == -1 ||
1454 			    relay_bufferevent_print(cre->dst, pk.value) == -1 ||
1455 			    relay_bufferevent_print(cre->dst, "\r\n") == -1) {
1456 				free(line);
1457 				goto fail;
1458 			}
1459 		}
1460 		free(line);
1461 	}
1462 	if (cre->done) {
1463 		RB_FOREACH(proot, proto_tree, cre->tree) {
1464 			PROTONODE_FOREACH(pn, proot, entry)
1465 				if (relay_resolve(cre, proot, pn) != 0)
1466 					return;
1467 		}
1468 
1469 		switch (cre->method) {
1470 		case HTTP_METHOD_NONE:
1471 			relay_close_http(con, 406, "no method", 0);
1472 			return;
1473 		case HTTP_METHOD_CONNECT:
1474 			/* Data stream */
1475 			bev->readcb = relay_read;
1476 			break;
1477 		case HTTP_METHOD_POST:
1478 		case HTTP_METHOD_PUT:
1479 		case HTTP_METHOD_RESPONSE:
1480 			/* HTTP request payload */
1481 			if (cre->toread) {
1482 				bev->readcb = relay_read_httpcontent;
1483 				break;
1484 			}
1485 
1486 			/* Single-pass HTTP response */
1487 			bev->readcb = relay_read;
1488 			break;
1489 		default:
1490 			/* HTTP handler */
1491 			bev->readcb = relay_read_http;
1492 			break;
1493 		}
1494 		if (cre->chunked) {
1495 			/* Chunked transfer encoding */
1496 			cre->toread = 0;
1497 			bev->readcb = relay_read_httpchunks;
1498 		}
1499 
1500 		/* Write empty newline and switch to relay mode */
1501 		if (relay_bufferevent_print(cre->dst, "\r\n") == -1)
1502 			goto fail;
1503 
1504 		relay_http_request_close(cre);
1505 
1506  done:
1507 		if (cre->dir == RELAY_DIR_REQUEST && !cre->toread &&
1508 		    proto->lateconnect && cre->dst->bev == NULL) {
1509 			if (rlay->rl_conf.fwdmode == FWD_TRANS) {
1510 				relay_bindanyreq(con, 0, IPPROTO_TCP);
1511 				return;
1512 			}
1513 			if (relay_connect(con) == -1)
1514 				relay_close_http(con, 502, "session failed", 0);
1515 			return;
1516 		}
1517 	}
1518 	if (con->se_done) {
1519 		relay_close(con, "last http read (done)");
1520 		return;
1521 	}
1522 	if (EVBUFFER_LENGTH(src) && bev->readcb != relay_read_http)
1523 		bev->readcb(bev, arg);
1524 	bufferevent_enable(bev, EV_READ);
1525 	return;
1526  fail:
1527 	relay_close_http(con, 500, strerror(errno), 0);
1528 	return;
1529  abort:
1530 	free(line);
1531 }
1532 
1533 static int
1534 _relay_lookup_url(struct ctl_relay_event *cre, char *host, char *path,
1535     char *query, enum digest_type type)
1536 {
1537 	struct rsession		*con = cre->con;
1538 	struct protonode	*proot, *pnv, pkv;
1539 	char			*val, *md = NULL;
1540 	int			 ret = PN_FAIL;
1541 
1542 	if (asprintf(&val, "%s%s%s%s",
1543 	    host, path,
1544 	    query == NULL ? "" : "?",
1545 	    query == NULL ? "" : query) == -1) {
1546 		relay_close_http(con, 500, "failed to allocate URL", 0);
1547 		return (PN_FAIL);
1548 	}
1549 
1550 	DPRINTF("%s: %s", __func__, val);
1551 
1552 	switch (type) {
1553 	case DIGEST_SHA1:
1554 	case DIGEST_MD5:
1555 		if ((md = digeststr(type, val, strlen(val), NULL)) == NULL) {
1556 			relay_close_http(con, 500,
1557 			    "failed to allocate digest", 0);
1558 			goto fail;
1559 		}
1560 		pkv.key = md;
1561 		break;
1562 	case DIGEST_NONE:
1563 		pkv.key = val;
1564 		break;
1565 	}
1566 	pkv.type = NODE_TYPE_URL;
1567 	pkv.value = "";
1568 
1569 	if ((proot = RB_FIND(proto_tree, cre->tree, &pkv)) == NULL)
1570 		goto done;
1571 
1572 	PROTONODE_FOREACH(pnv, proot, entry) {
1573 		ret = relay_handle_http(cre, proot, pnv, &pkv, 0);
1574 		if (ret == PN_FAIL)
1575 			goto fail;
1576 	}
1577 
1578  done:
1579 	ret = PN_PASS;
1580  fail:
1581 	if (md != NULL)
1582 		free(md);
1583 	free(val);
1584 	return (ret);
1585 }
1586 
1587 int
1588 relay_lookup_url(struct ctl_relay_event *cre, const char *str,
1589     enum digest_type type)
1590 {
1591 	struct rsession	*con = cre->con;
1592 	int		 i, j, dots;
1593 	char		*hi[RELAY_MAXLOOKUPLEVELS], *p, *pp, *c, ch;
1594 	char		 ph[MAXHOSTNAMELEN];
1595 	int		 ret;
1596 
1597 	if (cre->path == NULL)
1598 		return (PN_PASS);
1599 
1600 	/*
1601 	 * This is an URL lookup algorithm inspired by
1602 	 * http://code.google.com/apis/safebrowsing/
1603 	 *     developers_guide.html#PerformingLookups
1604 	 */
1605 
1606 	DPRINTF("%s: host: '%s', path: '%s', query: '%s'", __func__,
1607 	    str, cre->path, cre->args == NULL ? "" : cre->args);
1608 
1609 	if (canonicalize_host(str, ph, sizeof(ph)) == NULL) {
1610 		relay_close_http(con, 400, "invalid host name", 0);
1611 		return (PN_FAIL);
1612 	}
1613 
1614 	bzero(hi, sizeof(hi));
1615 	for (dots = -1, i = strlen(ph) - 1; i > 0; i--) {
1616 		if (ph[i] == '.' && ++dots)
1617 			hi[dots - 1] = &ph[i + 1];
1618 		if (dots > (RELAY_MAXLOOKUPLEVELS - 2))
1619 			break;
1620 	}
1621 	if (dots == -1)
1622 		dots = 0;
1623 	hi[dots] = ph;
1624 
1625 	if ((pp = strdup(cre->path)) == NULL) {
1626 		relay_close_http(con, 500, "failed to allocate path", 0);
1627 		return (PN_FAIL);
1628 	}
1629 	for (i = (RELAY_MAXLOOKUPLEVELS - 1); i >= 0; i--) {
1630 		if (hi[i] == NULL)
1631 			continue;
1632 
1633 		/* 1. complete path with query */
1634 		if (cre->args != NULL)
1635 			if ((ret = _relay_lookup_url(cre, hi[i],
1636 			    pp, cre->args, type)) != PN_PASS)
1637 				goto done;
1638 
1639 		/* 2. complete path without query */
1640 		if ((ret = _relay_lookup_url(cre, hi[i],
1641 		    pp, NULL, type)) != PN_PASS)
1642 			goto done;
1643 
1644 		/* 3. traverse path */
1645 		for (j = 0, p = strchr(pp, '/');
1646 		    p != NULL; p = strchr(p, '/'), j++) {
1647 			if (j > (RELAY_MAXLOOKUPLEVELS - 2) || ++p == '\0')
1648 				break;
1649 			c = &pp[p - pp];
1650 			ch = *c;
1651 			*c = '\0';
1652 			if ((ret = _relay_lookup_url(cre, hi[i],
1653 			    pp, NULL, type)) != PN_PASS)
1654 				goto done;
1655 			*c = ch;
1656 		}
1657 	}
1658 
1659 	ret = PN_PASS;
1660  done:
1661 	free(pp);
1662 	return (ret);
1663 }
1664 
1665 int
1666 relay_lookup_query(struct ctl_relay_event *cre)
1667 {
1668 	struct rsession		*con = cre->con;
1669 	struct protonode	*proot, *pnv, pkv;
1670 	char			*val, *ptr;
1671 	int			 ret;
1672 
1673 	if (cre->path == NULL || cre->args == NULL || strlen(cre->args) < 2)
1674 		return (PN_PASS);
1675 	if ((val = strdup(cre->args)) == NULL) {
1676 		relay_close_http(con, 500, "failed to allocate query", 0);
1677 		return (PN_FAIL);
1678 	}
1679 
1680 	ptr = val;
1681 	while (ptr != NULL && strlen(ptr)) {
1682 		pkv.key = ptr;
1683 		pkv.type = NODE_TYPE_QUERY;
1684 		if ((ptr = strchr(ptr, '&')) != NULL)
1685 			*ptr++ = '\0';
1686 		if ((pkv.value =
1687 		    strchr(pkv.key, '=')) == NULL ||
1688 		    strlen(pkv.value) < 1)
1689 			continue;
1690 		*pkv.value++ = '\0';
1691 
1692 		if ((proot = RB_FIND(proto_tree, cre->tree, &pkv)) == NULL)
1693 			continue;
1694 		PROTONODE_FOREACH(pnv, proot, entry) {
1695 			ret = relay_handle_http(cre, proot,
1696 			    pnv, &pkv, 0);
1697 			if (ret == PN_FAIL)
1698 				goto done;
1699 		}
1700 	}
1701 
1702 	ret = PN_PASS;
1703  done:
1704 	free(val);
1705 	return (ret);
1706 }
1707 
1708 int
1709 relay_lookup_cookie(struct ctl_relay_event *cre, const char *str)
1710 {
1711 	struct rsession		*con = cre->con;
1712 	struct protonode	*proot, *pnv, pkv;
1713 	char			*val, *ptr;
1714 	int			 ret;
1715 
1716 	if ((val = strdup(str)) == NULL) {
1717 		relay_close_http(con, 500, "failed to allocate cookie", 0);
1718 		return (PN_FAIL);
1719 	}
1720 
1721 	for (ptr = val; ptr != NULL && strlen(ptr);) {
1722 		if (*ptr == ' ')
1723 			*ptr++ = '\0';
1724 		pkv.key = ptr;
1725 		pkv.type = NODE_TYPE_COOKIE;
1726 		if ((ptr = strchr(ptr, ';')) != NULL)
1727 			*ptr++ = '\0';
1728 		/*
1729 		 * XXX We do not handle attributes
1730 		 * ($Path, $Domain, or $Port)
1731 		 */
1732 		if (*pkv.key == '$')
1733 			continue;
1734 
1735 		if ((pkv.value =
1736 		    strchr(pkv.key, '=')) == NULL ||
1737 		    strlen(pkv.value) < 1)
1738 			continue;
1739 		*pkv.value++ = '\0';
1740 		if (*pkv.value == '"')
1741 			*pkv.value++ = '\0';
1742 		if (pkv.value[strlen(pkv.value) - 1] == '"')
1743 			pkv.value[strlen(pkv.value) - 1] = '\0';
1744 		if ((proot = RB_FIND(proto_tree, cre->tree, &pkv)) == NULL)
1745 			continue;
1746 		PROTONODE_FOREACH(pnv, proot, entry) {
1747 			ret = relay_handle_http(cre, proot, pnv, &pkv, 0);
1748 			if (ret == PN_FAIL)
1749 				goto done;
1750 		}
1751 	}
1752 
1753 	ret = PN_PASS;
1754  done:
1755 	free(val);
1756 	return (ret);
1757 }
1758 
1759 void
1760 relay_close_http(struct rsession *con, u_int code, const char *msg,
1761     u_int16_t labelid)
1762 {
1763 	struct relay		*rlay = (struct relay *)con->se_relay;
1764 	struct bufferevent	*bev = con->se_in.bev;
1765 	const char		*httperr = print_httperror(code), *text = "";
1766 	char			*httpmsg;
1767 	time_t			 t;
1768 	struct tm		*lt;
1769 	char			 tmbuf[32], hbuf[128];
1770 	const char		*style, *label = NULL;
1771 
1772 	/* In some cases this function may be called from generic places */
1773 	if (rlay->rl_proto->type != RELAY_PROTO_HTTP ||
1774 	    (rlay->rl_proto->flags & F_RETURN) == 0) {
1775 		relay_close(con, msg);
1776 		return;
1777 	}
1778 
1779 	if (bev == NULL)
1780 		goto done;
1781 
1782 	/* Some system information */
1783 	if (print_host(&rlay->rl_conf.ss, hbuf, sizeof(hbuf)) == NULL)
1784 		goto done;
1785 
1786 	/* RFC 2616 "tolerates" asctime() */
1787 	time(&t);
1788 	lt = localtime(&t);
1789 	tmbuf[0] = '\0';
1790 	if (asctime_r(lt, tmbuf) != NULL)
1791 		tmbuf[strlen(tmbuf) - 1] = '\0';	/* skip final '\n' */
1792 
1793 	/* Do not send details of the Internal Server Error */
1794 	if (code != 500)
1795 		text = msg;
1796 	if (labelid != 0)
1797 		label = pn_id2name(labelid);
1798 
1799 	/* A CSS stylesheet allows minimal customization by the user */
1800 	if ((style = rlay->rl_proto->style) == NULL)
1801 		style = "body { background-color: #a00000; color: white; }";
1802 
1803 	/* Generate simple HTTP+HTML error document */
1804 	if (asprintf(&httpmsg,
1805 	    "HTTP/1.x %03d %s\r\n"
1806 	    "Date: %s\r\n"
1807 	    "Server: %s\r\n"
1808 	    "Connection: close\r\n"
1809 	    "Content-Type: text/html\r\n"
1810 	    "\r\n"
1811 	    "<!DOCTYPE HTML PUBLIC "
1812 	    "\"-//W3C//DTD HTML 4.01 Transitional//EN\">\n"
1813 	    "<html>\n"
1814 	    "<head>\n"
1815 	    "<title>%03d %s</title>\n"
1816 	    "<style type=\"text/css\"><!--\n%s\n--></style>\n"
1817 	    "</head>\n"
1818 	    "<body>\n"
1819 	    "<h1>%s</h1>\n"
1820 	    "<div id='m'>%s</div>\n"
1821 	    "<div id='l'>%s</div>\n"
1822 	    "<hr><address>%s at %s port %d</address>\n"
1823 	    "</body>\n"
1824 	    "</html>\n",
1825 	    code, httperr, tmbuf, RELAYD_SERVERNAME,
1826 	    code, httperr, style, httperr, text,
1827 	    label == NULL ? "" : label,
1828 	    RELAYD_SERVERNAME, hbuf, ntohs(rlay->rl_conf.port)) == -1)
1829 		goto done;
1830 
1831 	/* Dump the message without checking for success */
1832 	relay_dump(&con->se_in, httpmsg, strlen(httpmsg));
1833 	free(httpmsg);
1834 
1835  done:
1836 	if (asprintf(&httpmsg, "%s (%03d %s)", msg, code, httperr) == -1)
1837 		relay_close(con, msg);
1838 	else {
1839 		relay_close(con, httpmsg);
1840 		free(httpmsg);
1841 	}
1842 }
1843 
1844 int
1845 relay_splicelen(struct ctl_relay_event *cre)
1846 {
1847 	struct rsession *con = cre->con;
1848 	off_t len;
1849 	socklen_t optlen;
1850 
1851 	optlen = sizeof(len);
1852 	if (getsockopt(cre->s, SOL_SOCKET, SO_SPLICE, &len, &optlen) == -1) {
1853 		relay_close(con, strerror(errno));
1854 		return (0);
1855 	}
1856 	if (len > cre->splicelen) {
1857 		cre->splicelen = len;
1858 		return (1);
1859 	}
1860 	return (0);
1861 }
1862 
1863 void
1864 relay_error(struct bufferevent *bev, short error, void *arg)
1865 {
1866 	struct ctl_relay_event *cre = (struct ctl_relay_event *)arg;
1867 	struct rsession *con = cre->con;
1868 	struct evbuffer *dst;
1869 	struct timeval tv, tv_now;
1870 
1871 	if (error & EVBUFFER_TIMEOUT) {
1872 		if (gettimeofday(&tv_now, NULL) == -1) {
1873 			relay_close(con, strerror(errno));
1874 			return;
1875 		}
1876 		if (cre->splicelen >= 0 && relay_splicelen(cre))
1877 			con->se_tv_last = tv_now;
1878 		if (cre->dst->splicelen >= 0 && relay_splicelen(cre->dst))
1879 			con->se_tv_last = tv_now;
1880 		timersub(&tv_now, &con->se_tv_last, &tv);
1881 		if (timercmp(&tv, &con->se_relay->rl_conf.timeout, >=))
1882 			relay_close(con, "buffer event timeout");
1883 		else
1884 			bufferevent_enable(cre->bev, EV_READ);
1885 		return;
1886 	}
1887 	if (error & (EVBUFFER_READ|EVBUFFER_WRITE|EVBUFFER_EOF)) {
1888 		bufferevent_disable(bev, EV_READ|EV_WRITE);
1889 
1890 		con->se_done = 1;
1891 		if (cre->dst->bev != NULL) {
1892 			dst = EVBUFFER_OUTPUT(cre->dst->bev);
1893 			if (EVBUFFER_LENGTH(dst))
1894 				return;
1895 		} else
1896 			return;
1897 
1898 		relay_close(con, "done");
1899 		return;
1900 	}
1901 	relay_close(con, "buffer event error");
1902 }
1903 
1904 void
1905 relay_accept(int fd, short sig, void *arg)
1906 {
1907 	struct relay *rlay = (struct relay *)arg;
1908 	struct protocol *proto = rlay->rl_proto;
1909 	struct rsession *con = NULL;
1910 	struct ctl_natlook *cnl = NULL;
1911 	socklen_t slen;
1912 	struct timeval tv;
1913 	struct sockaddr_storage ss;
1914 	int s = -1;
1915 
1916 	slen = sizeof(ss);
1917 	if ((s = accept(fd, (struct sockaddr *)&ss, (socklen_t *)&slen)) == -1)
1918 		return;
1919 
1920 	if (relay_sessions >= RELAY_MAX_SESSIONS ||
1921 	    rlay->rl_conf.flags & F_DISABLE)
1922 		goto err;
1923 
1924 	if (fcntl(s, F_SETFL, O_NONBLOCK) == -1)
1925 		goto err;
1926 
1927 	if ((con = calloc(1, sizeof(*con))) == NULL)
1928 		goto err;
1929 
1930 	con->se_in.s = s;
1931 	con->se_in.ssl = NULL;
1932 	con->se_out.s = -1;
1933 	con->se_out.ssl = NULL;
1934 	con->se_in.dst = &con->se_out;
1935 	con->se_out.dst = &con->se_in;
1936 	con->se_in.con = con;
1937 	con->se_out.con = con;
1938 	con->se_in.splicelen = -1;
1939 	con->se_out.splicelen = -1;
1940 	con->se_relay = rlay;
1941 	con->se_id = ++relay_conid;
1942 	con->se_relayid = rlay->rl_conf.id;
1943 	con->se_pid = getpid();
1944 	con->se_hashkey = rlay->rl_dstkey;
1945 	con->se_in.tree = &proto->request_tree;
1946 	con->se_out.tree = &proto->response_tree;
1947 	con->se_in.dir = RELAY_DIR_REQUEST;
1948 	con->se_out.dir = RELAY_DIR_RESPONSE;
1949 	con->se_retry = rlay->rl_conf.dstretry;
1950 	con->se_bnds = -1;
1951 	if (gettimeofday(&con->se_tv_start, NULL) == -1)
1952 		goto err;
1953 	bcopy(&con->se_tv_start, &con->se_tv_last, sizeof(con->se_tv_last));
1954 	bcopy(&ss, &con->se_in.ss, sizeof(con->se_in.ss));
1955 	con->se_out.port = rlay->rl_conf.dstport;
1956 	switch (ss.ss_family) {
1957 	case AF_INET:
1958 		con->se_in.port = ((struct sockaddr_in *)&ss)->sin_port;
1959 		break;
1960 	case AF_INET6:
1961 		con->se_in.port = ((struct sockaddr_in6 *)&ss)->sin6_port;
1962 		break;
1963 	}
1964 
1965 	relay_sessions++;
1966 	SPLAY_INSERT(session_tree, &rlay->rl_sessions, con);
1967 
1968 	/* Increment the per-relay session counter */
1969 	rlay->rl_stats[proc_id].last++;
1970 
1971 	/* Pre-allocate output buffer */
1972 	con->se_out.output = evbuffer_new();
1973 	if (con->se_out.output == NULL) {
1974 		relay_close(con, "failed to allocate output buffer");
1975 		return;
1976 	}
1977 
1978 	/* Pre-allocate log buffer */
1979 	con->se_log = evbuffer_new();
1980 	if (con->se_log == NULL) {
1981 		relay_close(con, "failed to allocate log buffer");
1982 		return;
1983 	}
1984 
1985 	if (rlay->rl_conf.flags & F_DIVERT) {
1986 		slen = sizeof(con->se_out.ss);
1987 		if (getsockname(s, (struct sockaddr *)&con->se_out.ss,
1988 		    &slen) == -1) {
1989 			relay_close(con, "peer lookup failed");
1990 			return;
1991 		}
1992 		con->se_out.port = relay_socket_getport(&con->se_out.ss);
1993 
1994 		/* Detect loop and fall back to the alternate forward target */
1995 		if (bcmp(&rlay->rl_conf.ss, &con->se_out.ss,
1996 		    sizeof(con->se_out.ss)) == 0 &&
1997 		    con->se_out.port == rlay->rl_conf.port)
1998 			con->se_out.ss.ss_family = AF_UNSPEC;
1999 	} else if (rlay->rl_conf.flags & F_NATLOOK) {
2000 		if ((cnl = (struct ctl_natlook *)
2001 		    calloc(1, sizeof(struct ctl_natlook))) == NULL) {
2002 			relay_close(con, "failed to allocate nat lookup");
2003 			return;
2004 		}
2005 
2006 		con->se_cnl = cnl;
2007 		bzero(cnl, sizeof(*cnl));
2008 		cnl->in = -1;
2009 		cnl->id = con->se_id;
2010 		cnl->proc = proc_id;
2011 		cnl->proto = IPPROTO_TCP;
2012 
2013 		bcopy(&con->se_in.ss, &cnl->src, sizeof(cnl->src));
2014 		slen = sizeof(cnl->dst);
2015 		if (getsockname(s,
2016 		    (struct sockaddr *)&cnl->dst, &slen) == -1) {
2017 			relay_close(con, "failed to get local address");
2018 			return;
2019 		}
2020 
2021 		proc_compose_imsg(env->sc_ps, PROC_PFE, -1, IMSG_NATLOOK, -1,
2022 		    cnl, sizeof(*cnl));
2023 
2024 		/* Schedule timeout */
2025 		evtimer_set(&con->se_ev, relay_natlook, con);
2026 		bcopy(&rlay->rl_conf.timeout, &tv, sizeof(tv));
2027 		evtimer_add(&con->se_ev, &tv);
2028 		return;
2029 	}
2030 
2031 	relay_session(con);
2032 	return;
2033  err:
2034 	if (s != -1) {
2035 		close(s);
2036 		if (con != NULL)
2037 			free(con);
2038 	}
2039 }
2040 
2041 u_int32_t
2042 relay_hash_addr(struct sockaddr_storage *ss, u_int32_t p)
2043 {
2044 	struct sockaddr_in	*sin4;
2045 	struct sockaddr_in6	*sin6;
2046 
2047 	if (ss->ss_family == AF_INET) {
2048 		sin4 = (struct sockaddr_in *)ss;
2049 		p = hash32_buf(&sin4->sin_addr,
2050 		    sizeof(struct in_addr), p);
2051 	} else {
2052 		sin6 = (struct sockaddr_in6 *)ss;
2053 		p = hash32_buf(&sin6->sin6_addr,
2054 		    sizeof(struct in6_addr), p);
2055 	}
2056 
2057 	return (p);
2058 }
2059 
2060 int
2061 relay_from_table(struct rsession *con)
2062 {
2063 	struct relay		*rlay = (struct relay *)con->se_relay;
2064 	struct host		*host;
2065 	struct table		*table = rlay->rl_dsttable;
2066 	u_int32_t		 p = con->se_hashkey;
2067 	int			 idx = 0;
2068 
2069 	if (table->conf.check && !table->up && !rlay->rl_backuptable->up) {
2070 		log_debug("%s: no active hosts", __func__);
2071 		return (-1);
2072 	} else if (!table->up && rlay->rl_backuptable->up) {
2073 		table = rlay->rl_backuptable;
2074 	}
2075 
2076 	switch (rlay->rl_conf.dstmode) {
2077 	case RELAY_DSTMODE_ROUNDROBIN:
2078 		if ((int)rlay->rl_dstkey >= rlay->rl_dstnhosts)
2079 			rlay->rl_dstkey = 0;
2080 		idx = (int)rlay->rl_dstkey;
2081 		break;
2082 	case RELAY_DSTMODE_LOADBALANCE:
2083 		p = relay_hash_addr(&con->se_in.ss, p);
2084 		/* FALLTHROUGH */
2085 	case RELAY_DSTMODE_HASH:
2086 		p = relay_hash_addr(&rlay->rl_conf.ss, p);
2087 		p = hash32_buf(&rlay->rl_conf.port,
2088 		    sizeof(rlay->rl_conf.port), p);
2089 		if ((idx = p % rlay->rl_dstnhosts) >= RELAY_MAXHOSTS)
2090 			return (-1);
2091 	}
2092 	host = rlay->rl_dsthost[idx];
2093 	DPRINTF("%s: host %s, p 0x%08x, idx %d", __func__,
2094 	    host->conf.name, p, idx);
2095 	while (host != NULL) {
2096 		DPRINTF("%s: host %s", __func__, host->conf.name);
2097 		if (!table->conf.check || host->up == HOST_UP)
2098 			goto found;
2099 		host = TAILQ_NEXT(host, entry);
2100 	}
2101 	TAILQ_FOREACH(host, &table->hosts, entry) {
2102 		DPRINTF("%s: next host %s", __func__, host->conf.name);
2103 		if (!table->conf.check || host->up == HOST_UP)
2104 			goto found;
2105 	}
2106 
2107 	/* Should not happen */
2108 	fatalx("relay_from_table: no active hosts, desynchronized");
2109 
2110  found:
2111 	if (rlay->rl_conf.dstmode == RELAY_DSTMODE_ROUNDROBIN)
2112 		rlay->rl_dstkey = host->idx + 1;
2113 	con->se_retry = host->conf.retry;
2114 	con->se_out.port = table->conf.port;
2115 	bcopy(&host->conf.ss, &con->se_out.ss, sizeof(con->se_out.ss));
2116 
2117 	return (0);
2118 }
2119 
2120 void
2121 relay_natlook(int fd, short event, void *arg)
2122 {
2123 	struct rsession		*con = (struct rsession *)arg;
2124 	struct relay		*rlay = (struct relay *)con->se_relay;
2125 	struct ctl_natlook	*cnl = con->se_cnl;
2126 
2127 	if (cnl == NULL)
2128 		fatalx("invalid NAT lookup");
2129 
2130 	if (con->se_out.ss.ss_family == AF_UNSPEC && cnl->in == -1 &&
2131 	    rlay->rl_conf.dstss.ss_family == AF_UNSPEC &&
2132 	    rlay->rl_dsttable == NULL) {
2133 		relay_close(con, "session NAT lookup failed");
2134 		return;
2135 	}
2136 	if (cnl->in != -1) {
2137 		bcopy(&cnl->rdst, &con->se_out.ss, sizeof(con->se_out.ss));
2138 		con->se_out.port = cnl->rdport;
2139 	}
2140 	free(con->se_cnl);
2141 	con->se_cnl = NULL;
2142 
2143 	relay_session(con);
2144 }
2145 
2146 void
2147 relay_session(struct rsession *con)
2148 {
2149 	struct relay		*rlay = (struct relay *)con->se_relay;
2150 	struct ctl_relay_event	*in = &con->se_in, *out = &con->se_out;
2151 
2152 	if (bcmp(&rlay->rl_conf.ss, &out->ss, sizeof(out->ss)) == 0 &&
2153 	    out->port == rlay->rl_conf.port) {
2154 		log_debug("%s: session %d: looping", __func__, con->se_id);
2155 		relay_close(con, "session aborted");
2156 		return;
2157 	}
2158 
2159 	if (rlay->rl_conf.flags & F_UDP) {
2160 		/*
2161 		 * Call the UDP protocol-specific handler
2162 		 */
2163 		if (rlay->rl_proto->request == NULL)
2164 			fatalx("invalide UDP session");
2165 		if ((*rlay->rl_proto->request)(con) == -1)
2166 			relay_close(con, "session failed");
2167 		return;
2168 	}
2169 
2170 	if ((rlay->rl_conf.flags & F_SSL) && (in->ssl == NULL)) {
2171 		relay_ssl_transaction(con, in);
2172 		return;
2173 	}
2174 
2175 	if (!rlay->rl_proto->lateconnect) {
2176 		if (rlay->rl_conf.fwdmode == FWD_TRANS)
2177 			relay_bindanyreq(con, 0, IPPROTO_TCP);
2178 		else if (relay_connect(con) == -1) {
2179 			relay_close(con, "session failed");
2180 			return;
2181 		}
2182 	}
2183 
2184 	relay_input(con);
2185 }
2186 
2187 void
2188 relay_bindanyreq(struct rsession *con, in_port_t port, int proto)
2189 {
2190 	struct relay		*rlay = (struct relay *)con->se_relay;
2191 	struct ctl_bindany	 bnd;
2192 	struct timeval		 tv;
2193 
2194 	bzero(&bnd, sizeof(bnd));
2195 	bnd.bnd_id = con->se_id;
2196 	bnd.bnd_proc = proc_id;
2197 	bnd.bnd_port = port;
2198 	bnd.bnd_proto = proto;
2199 	bcopy(&con->se_in.ss, &bnd.bnd_ss, sizeof(bnd.bnd_ss));
2200 	proc_compose_imsg(env->sc_ps, PROC_PARENT, -1, IMSG_BINDANY,
2201 	    -1, &bnd, sizeof(bnd));
2202 
2203 	/* Schedule timeout */
2204 	evtimer_set(&con->se_ev, relay_bindany, con);
2205 	bcopy(&rlay->rl_conf.timeout, &tv, sizeof(tv));
2206 	evtimer_add(&con->se_ev, &tv);
2207 }
2208 
2209 void
2210 relay_bindany(int fd, short event, void *arg)
2211 {
2212 	struct rsession	*con = (struct rsession *)arg;
2213 
2214 	if (con->se_bnds == -1) {
2215 		relay_close(con, "bindany failed, invalid socket");
2216 		return;
2217 	}
2218 
2219 	if (relay_connect(con) == -1)
2220 		relay_close(con, "session failed");
2221 }
2222 
2223 int
2224 relay_connect(struct rsession *con)
2225 {
2226 	struct relay	*rlay = (struct relay *)con->se_relay;
2227 	int		 bnds = -1, ret;
2228 
2229 	if (gettimeofday(&con->se_tv_start, NULL) == -1)
2230 		return (-1);
2231 
2232 	if (rlay->rl_dsttable != NULL) {
2233 		if (relay_from_table(con) != 0)
2234 			return (-1);
2235 	} else if (con->se_out.ss.ss_family == AF_UNSPEC) {
2236 		bcopy(&rlay->rl_conf.dstss, &con->se_out.ss,
2237 		    sizeof(con->se_out.ss));
2238 		con->se_out.port = rlay->rl_conf.dstport;
2239 	}
2240 
2241 	if (rlay->rl_conf.fwdmode == FWD_TRANS) {
2242 		if (con->se_bnds == -1) {
2243 			log_debug("%s: could not bind any sock", __func__);
2244 			return (-1);
2245 		}
2246 		bnds = con->se_bnds;
2247 	}
2248 
2249 	/* Do the IPv4-to-IPv6 or IPv6-to-IPv4 translation if requested */
2250 	if (rlay->rl_conf.dstaf.ss_family != AF_UNSPEC) {
2251 		if (con->se_out.ss.ss_family == AF_INET &&
2252 		    rlay->rl_conf.dstaf.ss_family == AF_INET6)
2253 			ret = map4to6(&con->se_out.ss, &rlay->rl_conf.dstaf);
2254 		else if (con->se_out.ss.ss_family == AF_INET6 &&
2255 		    rlay->rl_conf.dstaf.ss_family == AF_INET)
2256 			ret = map6to4(&con->se_out.ss);
2257 		else
2258 			ret = 0;
2259 		if (ret != 0) {
2260 			log_debug("%s: mapped to invalid address", __func__);
2261 			return (-1);
2262 		}
2263 	}
2264 
2265  retry:
2266 	if ((con->se_out.s = relay_socket_connect(&con->se_out.ss,
2267 	    con->se_out.port, rlay->rl_proto, bnds)) == -1) {
2268 		if (con->se_retry) {
2269 			con->se_retry--;
2270 			log_debug("%s: session %d: "
2271 			    "forward failed: %s, %s", __func__,
2272 			    con->se_id, strerror(errno),
2273 			    con->se_retry ? "next retry" : "last retry");
2274 			goto retry;
2275 		}
2276 		log_debug("%s: session %d: forward failed: %s", __func__,
2277 		    con->se_id, strerror(errno));
2278 		return (-1);
2279 	}
2280 
2281 	if (errno == EINPROGRESS)
2282 		event_again(&con->se_ev, con->se_out.s, EV_WRITE|EV_TIMEOUT,
2283 		    relay_connected, &con->se_tv_start, &rlay->rl_conf.timeout,
2284 		    con);
2285 	else
2286 		relay_connected(con->se_out.s, EV_WRITE, con);
2287 
2288 	return (0);
2289 }
2290 
2291 void
2292 relay_close(struct rsession *con, const char *msg)
2293 {
2294 	struct relay	*rlay = (struct relay *)con->se_relay;
2295 	char		 ibuf[128], obuf[128], *ptr = NULL;
2296 
2297 	SPLAY_REMOVE(session_tree, &rlay->rl_sessions, con);
2298 
2299 	event_del(&con->se_ev);
2300 	if (con->se_in.bev != NULL)
2301 		bufferevent_disable(con->se_in.bev, EV_READ|EV_WRITE);
2302 	if (con->se_out.bev != NULL)
2303 		bufferevent_disable(con->se_out.bev, EV_READ|EV_WRITE);
2304 
2305 	if ((env->sc_opts & RELAYD_OPT_LOGUPDATE) && msg != NULL) {
2306 		bzero(&ibuf, sizeof(ibuf));
2307 		bzero(&obuf, sizeof(obuf));
2308 		(void)print_host(&con->se_in.ss, ibuf, sizeof(ibuf));
2309 		(void)print_host(&con->se_out.ss, obuf, sizeof(obuf));
2310 		if (EVBUFFER_LENGTH(con->se_log) &&
2311 		    evbuffer_add_printf(con->se_log, "\r\n") != -1)
2312 			ptr = evbuffer_readline(con->se_log);
2313 		log_info("relay %s, "
2314 		    "session %d (%d active), %d, %s -> %s:%d, "
2315 		    "%s%s%s", rlay->rl_conf.name, con->se_id, relay_sessions,
2316 		    con->se_mark, ibuf, obuf, ntohs(con->se_out.port), msg,
2317 		    ptr == NULL ? "" : ",", ptr == NULL ? "" : ptr);
2318 		if (ptr != NULL)
2319 			free(ptr);
2320 	}
2321 
2322 	if (con->se_priv != NULL)
2323 		free(con->se_priv);
2324 	if (con->se_in.bev != NULL)
2325 		bufferevent_free(con->se_in.bev);
2326 	else if (con->se_in.output != NULL)
2327 		evbuffer_free(con->se_in.output);
2328 	if (con->se_in.ssl != NULL) {
2329 		/* XXX handle non-blocking shutdown */
2330 		if (SSL_shutdown(con->se_in.ssl) == 0)
2331 			SSL_shutdown(con->se_in.ssl);
2332 		SSL_free(con->se_in.ssl);
2333 	}
2334 	if (con->se_in.s != -1)
2335 		close(con->se_in.s);
2336 	if (con->se_in.path != NULL)
2337 		free(con->se_in.path);
2338 	if (con->se_in.buf != NULL)
2339 		free(con->se_in.buf);
2340 	if (con->se_in.nodes != NULL)
2341 		free(con->se_in.nodes);
2342 
2343 	if (con->se_out.bev != NULL)
2344 		bufferevent_free(con->se_out.bev);
2345 	else if (con->se_out.output != NULL)
2346 		evbuffer_free(con->se_out.output);
2347 	if (con->se_out.ssl != NULL) {
2348 		/* XXX handle non-blocking shutdown */
2349 		if (SSL_shutdown(con->se_out.ssl) == 0)
2350 			SSL_shutdown(con->se_out.ssl);
2351 		SSL_free(con->se_out.ssl);
2352 	}
2353 	if (con->se_out.s != -1)
2354 		close(con->se_out.s);
2355 	if (con->se_out.path != NULL)
2356 		free(con->se_out.path);
2357 	if (con->se_out.buf != NULL)
2358 		free(con->se_out.buf);
2359 	if (con->se_out.nodes != NULL)
2360 		free(con->se_out.nodes);
2361 
2362 	if (con->se_log != NULL)
2363 		evbuffer_free(con->se_log);
2364 
2365 	if (con->se_cnl != NULL) {
2366 #if 0
2367 		proc_compose_imsg(env->sc_ps, PROC_PFE, -1, IMSG_KILLSTATES, -1,
2368 		    cnl, sizeof(*cnl));
2369 #endif
2370 		free(con->se_cnl);
2371 	}
2372 
2373 	free(con);
2374 	relay_sessions--;
2375 }
2376 
2377 int
2378 relay_dispatch_pfe(int fd, struct privsep_proc *p, struct imsg *imsg)
2379 {
2380 	struct relay		*rlay;
2381 	struct rsession		*con, se;
2382 	struct ctl_natlook	 cnl;
2383 	struct timeval		 tv;
2384 	struct host		*host;
2385 	struct table		*table;
2386 	struct ctl_status	 st;
2387 	objid_t			 id;
2388 	int			 cid;
2389 
2390 	switch (imsg->hdr.type) {
2391 	case IMSG_HOST_DISABLE:
2392 		memcpy(&id, imsg->data, sizeof(id));
2393 		if ((host = host_find(env, id)) == NULL)
2394 			fatalx("relay_dispatch_pfe: desynchronized");
2395 		if ((table = table_find(env, host->conf.tableid)) ==
2396 		    NULL)
2397 			fatalx("relay_dispatch_pfe: invalid table id");
2398 		if (host->up == HOST_UP)
2399 			table->up--;
2400 		host->flags |= F_DISABLE;
2401 		host->up = HOST_UNKNOWN;
2402 		break;
2403 	case IMSG_HOST_ENABLE:
2404 		memcpy(&id, imsg->data, sizeof(id));
2405 		if ((host = host_find(env, id)) == NULL)
2406 			fatalx("relay_dispatch_pfe: desynchronized");
2407 		host->flags &= ~(F_DISABLE);
2408 		host->up = HOST_UNKNOWN;
2409 		break;
2410 	case IMSG_TABLE_DISABLE:
2411 		memcpy(&id, imsg->data, sizeof(id));
2412 		if ((table = table_find(env, id)) == NULL)
2413 			fatalx("relay_dispatch_pfe: desynchronized");
2414 		table->conf.flags |= F_DISABLE;
2415 		table->up = 0;
2416 		TAILQ_FOREACH(host, &table->hosts, entry)
2417 			host->up = HOST_UNKNOWN;
2418 		break;
2419 	case IMSG_TABLE_ENABLE:
2420 		memcpy(&id, imsg->data, sizeof(id));
2421 		if ((table = table_find(env, id)) == NULL)
2422 			fatalx("relay_dispatch_pfe: desynchronized");
2423 		table->conf.flags &= ~(F_DISABLE);
2424 		table->up = 0;
2425 		TAILQ_FOREACH(host, &table->hosts, entry)
2426 			host->up = HOST_UNKNOWN;
2427 		break;
2428 	case IMSG_HOST_STATUS:
2429 		IMSG_SIZE_CHECK(imsg, &st);
2430 		memcpy(&st, imsg->data, sizeof(st));
2431 		if ((host = host_find(env, st.id)) == NULL)
2432 			fatalx("relay_dispatch_pfe: invalid host id");
2433 		if (host->flags & F_DISABLE)
2434 			break;
2435 		if (host->up == st.up) {
2436 			log_debug("%s: host %d => %d", __func__,
2437 			    host->conf.id, host->up);
2438 			fatalx("relay_dispatch_pfe: desynchronized");
2439 		}
2440 
2441 		if ((table = table_find(env, host->conf.tableid))
2442 		    == NULL)
2443 			fatalx("relay_dispatch_pfe: invalid table id");
2444 
2445 		DPRINTF("%s: [%d] state %d for "
2446 		    "host %u %s", __func__, proc_id, st.up,
2447 		    host->conf.id, host->conf.name);
2448 
2449 		if ((st.up == HOST_UNKNOWN && host->up == HOST_DOWN) ||
2450 		    (st.up == HOST_DOWN && host->up == HOST_UNKNOWN)) {
2451 			host->up = st.up;
2452 			break;
2453 		}
2454 		if (st.up == HOST_UP)
2455 			table->up++;
2456 		else
2457 			table->up--;
2458 		host->up = st.up;
2459 		break;
2460 	case IMSG_NATLOOK:
2461 		bcopy(imsg->data, &cnl, sizeof(cnl));
2462 		if ((con = session_find(env, cnl.id)) == NULL ||
2463 		    con->se_cnl == NULL) {
2464 			log_debug("%s: session %d: expired",
2465 			    __func__, cnl.id);
2466 			break;
2467 		}
2468 		bcopy(&cnl, con->se_cnl, sizeof(*con->se_cnl));
2469 		evtimer_del(&con->se_ev);
2470 		evtimer_set(&con->se_ev, relay_natlook, con);
2471 		bzero(&tv, sizeof(tv));
2472 		evtimer_add(&con->se_ev, &tv);
2473 		break;
2474 	case IMSG_CTL_SESSION:
2475 		IMSG_SIZE_CHECK(imsg, &cid);
2476 		memcpy(&cid, imsg->data, sizeof(cid));
2477 		TAILQ_FOREACH(rlay, env->sc_relays, rl_entry) {
2478 			SPLAY_FOREACH(con, session_tree,
2479 			    &rlay->rl_sessions) {
2480 				memcpy(&se, con, sizeof(se));
2481 				se.se_cid = cid;
2482 				proc_compose_imsg(env->sc_ps, p->p_id, -1,
2483 				    IMSG_CTL_SESSION,
2484 				    -1, &se, sizeof(se));
2485 			}
2486 		}
2487 		proc_compose_imsg(env->sc_ps, p->p_id, -1, IMSG_CTL_END,
2488 		    -1, &cid, sizeof(cid));
2489 		break;
2490 	default:
2491 		return (-1);
2492 	}
2493 
2494 	return (0);
2495 }
2496 
2497 int
2498 relay_dispatch_parent(int fd, struct privsep_proc *p, struct imsg *imsg)
2499 {
2500 	struct rsession		*con;
2501 	struct timeval		 tv;
2502 	objid_t			 id;
2503 
2504 	switch (imsg->hdr.type) {
2505 	case IMSG_BINDANY:
2506 		bcopy(imsg->data, &id, sizeof(id));
2507 		if ((con = session_find(env, id)) == NULL) {
2508 			log_debug("%s: session %d: expired",
2509 			    __func__, id);
2510 			break;
2511 		}
2512 
2513 		/* Will validate the result later */
2514 		con->se_bnds = imsg->fd;
2515 
2516 		evtimer_del(&con->se_ev);
2517 		evtimer_set(&con->se_ev, relay_bindany, con);
2518 		bzero(&tv, sizeof(tv));
2519 		evtimer_add(&con->se_ev, &tv);
2520 		break;
2521 	case IMSG_CFG_TABLE:
2522 		config_gettable(env, imsg);
2523 		break;
2524 	case IMSG_CFG_HOST:
2525 		config_gethost(env, imsg);
2526 		break;
2527 	case IMSG_CFG_PROTO:
2528 		config_getproto(env, imsg);
2529 		break;
2530 	case IMSG_CFG_PROTONODE:
2531 		return (config_getprotonode(env, imsg));
2532 	case IMSG_CFG_RELAY:
2533 		config_getrelay(env, imsg);
2534 		break;
2535 	case IMSG_CFG_DONE:
2536 		config_getcfg(env, imsg);
2537 		relay_launch();
2538 		break;
2539 	case IMSG_CTL_RESET:
2540 		config_getreset(env, imsg);
2541 		break;
2542 	default:
2543 		return (-1);
2544 	}
2545 
2546 	return (0);
2547 }
2548 
2549 SSL_CTX *
2550 relay_ssl_ctx_create(struct relay *rlay)
2551 {
2552 	struct protocol *proto = rlay->rl_proto;
2553 	SSL_CTX *ctx;
2554 
2555 	ctx = SSL_CTX_new(SSLv23_method());
2556 	if (ctx == NULL)
2557 		goto err;
2558 
2559 	/* Modify session timeout and cache size*/
2560 	SSL_CTX_set_timeout(ctx, rlay->rl_conf.timeout.tv_sec);
2561 	if (proto->cache < -1) {
2562 		SSL_CTX_set_session_cache_mode(ctx, SSL_SESS_CACHE_OFF);
2563 	} else if (proto->cache >= -1) {
2564 		SSL_CTX_set_session_cache_mode(ctx, SSL_SESS_CACHE_SERVER);
2565 		if (proto->cache >= 0)
2566 			SSL_CTX_sess_set_cache_size(ctx, proto->cache);
2567 	}
2568 
2569 	/* Enable all workarounds and set SSL options */
2570 	SSL_CTX_set_options(ctx, SSL_OP_ALL);
2571 	SSL_CTX_set_options(ctx,
2572 	    SSL_OP_NO_SESSION_RESUMPTION_ON_RENEGOTIATION);
2573 
2574 	/* Set the allowed SSL protocols */
2575 	if ((proto->sslflags & SSLFLAG_SSLV2) == 0)
2576 		SSL_CTX_set_options(ctx, SSL_OP_NO_SSLv2);
2577 	if ((proto->sslflags & SSLFLAG_SSLV3) == 0)
2578 		SSL_CTX_set_options(ctx, SSL_OP_NO_SSLv3);
2579 	if ((proto->sslflags & SSLFLAG_TLSV1) == 0)
2580 		SSL_CTX_set_options(ctx, SSL_OP_NO_TLSv1);
2581 
2582 	if (!SSL_CTX_set_cipher_list(ctx, proto->sslciphers))
2583 		goto err;
2584 
2585 	/* Verify the server certificate if we have a CA chain */
2586 	if ((rlay->rl_conf.flags & F_SSLCLIENT) &&
2587 	    (rlay->rl_ssl_ca != NULL)) {
2588 		if (!ssl_ctx_load_verify_memory(ctx,
2589 		    rlay->rl_ssl_ca, rlay->rl_conf.ssl_ca_len))
2590 			goto err;
2591 		SSL_CTX_set_verify(ctx, SSL_VERIFY_PEER, NULL);
2592 	}
2593 
2594 	if ((rlay->rl_conf.flags & F_SSL) == 0)
2595 		return (ctx);
2596 
2597 	log_debug("%s: loading certificate", __func__);
2598 	if (!ssl_ctx_use_certificate_chain(ctx,
2599 	    rlay->rl_ssl_cert, rlay->rl_conf.ssl_cert_len))
2600 		goto err;
2601 
2602 	log_debug("%s: loading private key", __func__);
2603 	if (!ssl_ctx_use_private_key(ctx, rlay->rl_ssl_key,
2604 	    rlay->rl_conf.ssl_key_len))
2605 		goto err;
2606 	if (!SSL_CTX_check_private_key(ctx))
2607 		goto err;
2608 
2609 	/* Set session context to the local relay name */
2610 	if (!SSL_CTX_set_session_id_context(ctx, rlay->rl_conf.name,
2611 	    strlen(rlay->rl_conf.name)))
2612 		goto err;
2613 
2614 	return (ctx);
2615 
2616  err:
2617 	if (ctx != NULL)
2618 		SSL_CTX_free(ctx);
2619 	ssl_error(rlay->rl_conf.name, "relay_ssl_ctx_create");
2620 	return (NULL);
2621 }
2622 
2623 void
2624 relay_ssl_transaction(struct rsession *con, struct ctl_relay_event *cre)
2625 {
2626 	struct relay		*rlay = (struct relay *)con->se_relay;
2627 	SSL			*ssl;
2628 	const SSL_METHOD	*method;
2629 	void			(*cb)(int, short, void *);
2630 	u_int			 flag;
2631 
2632 	ssl = SSL_new(rlay->rl_ssl_ctx);
2633 	if (ssl == NULL)
2634 		goto err;
2635 
2636 	if (cre->dir == RELAY_DIR_REQUEST) {
2637 		cb = relay_ssl_accept;
2638 		method = SSLv23_server_method();
2639 		flag = EV_READ;
2640 	} else {
2641 		cb = relay_ssl_connect;
2642 		method = SSLv23_client_method();
2643 		flag = EV_WRITE;
2644 	}
2645 
2646 	if (!SSL_set_ssl_method(ssl, method))
2647 		goto err;
2648 	if (!SSL_set_fd(ssl, cre->s))
2649 		goto err;
2650 
2651 	if (cre->dir == RELAY_DIR_REQUEST)
2652 		SSL_set_accept_state(ssl);
2653 	else
2654 		SSL_set_connect_state(ssl);
2655 
2656 	cre->ssl = ssl;
2657 
2658 	DPRINTF("%s: session %d: scheduling on %s", __func__, con->se_id,
2659 	    (flag == EV_READ) ? "EV_READ" : "EV_WRITE");
2660 	event_again(&con->se_ev, cre->s, EV_TIMEOUT|flag, cb,
2661 	    &con->se_tv_start, &rlay->rl_conf.timeout, con);
2662 	return;
2663 
2664  err:
2665 	if (ssl != NULL)
2666 		SSL_free(ssl);
2667 	ssl_error(rlay->rl_conf.name, "relay_ssl_transaction");
2668 	relay_close(con, "session ssl failed");
2669 }
2670 
2671 void
2672 relay_ssl_accept(int fd, short event, void *arg)
2673 {
2674 	struct rsession	*con = (struct rsession *)arg;
2675 	struct relay	*rlay = (struct relay *)con->se_relay;
2676 	int		 ret;
2677 	int		 ssl_err;
2678 	int		 retry_flag;
2679 
2680 	if (event == EV_TIMEOUT) {
2681 		relay_close(con, "SSL accept timeout");
2682 		return;
2683 	}
2684 
2685 	retry_flag = ssl_err = 0;
2686 
2687 	ret = SSL_accept(con->se_in.ssl);
2688 	if (ret <= 0) {
2689 		ssl_err = SSL_get_error(con->se_in.ssl, ret);
2690 
2691 		switch (ssl_err) {
2692 		case SSL_ERROR_WANT_READ:
2693 			retry_flag = EV_READ;
2694 			goto retry;
2695 		case SSL_ERROR_WANT_WRITE:
2696 			retry_flag = EV_WRITE;
2697 			goto retry;
2698 		case SSL_ERROR_ZERO_RETURN:
2699 		case SSL_ERROR_SYSCALL:
2700 			if (ret == 0) {
2701 				relay_close(con, "closed");
2702 				return;
2703 			}
2704 			/* FALLTHROUGH */
2705 		default:
2706 			ssl_error(rlay->rl_conf.name, "relay_ssl_accept");
2707 			relay_close(con, "SSL accept error");
2708 			return;
2709 		}
2710 	}
2711 
2712 
2713 #ifdef DEBUG
2714 	log_info(
2715 #else
2716 	log_debug(
2717 #endif
2718 	    "relay %s, session %d established (%d active)",
2719 	    rlay->rl_conf.name, con->se_id, relay_sessions);
2720 
2721 	relay_session(con);
2722 	return;
2723 
2724 retry:
2725 	DPRINTF("%s: session %d: scheduling on %s", __func__, con->se_id,
2726 	    (retry_flag == EV_READ) ? "EV_READ" : "EV_WRITE");
2727 	event_again(&con->se_ev, fd, EV_TIMEOUT|retry_flag, relay_ssl_accept,
2728 	    &con->se_tv_start, &rlay->rl_conf.timeout, con);
2729 }
2730 
2731 void
2732 relay_ssl_connect(int fd, short event, void *arg)
2733 {
2734 	struct rsession	*con = (struct rsession *)arg;
2735 	struct relay	*rlay = (struct relay *)con->se_relay;
2736 	int		 ret;
2737 	int		 ssl_err;
2738 	int		 retry_flag;
2739 
2740 	if (event == EV_TIMEOUT) {
2741 		relay_close(con, "SSL connect timeout");
2742 		return;
2743 	}
2744 
2745 	retry_flag = ssl_err = 0;
2746 
2747 	ret = SSL_connect(con->se_out.ssl);
2748 	if (ret <= 0) {
2749 		ssl_err = SSL_get_error(con->se_out.ssl, ret);
2750 
2751 		switch (ssl_err) {
2752 		case SSL_ERROR_WANT_READ:
2753 			retry_flag = EV_READ;
2754 			goto retry;
2755 		case SSL_ERROR_WANT_WRITE:
2756 			retry_flag = EV_WRITE;
2757 			goto retry;
2758 		case SSL_ERROR_ZERO_RETURN:
2759 		case SSL_ERROR_SYSCALL:
2760 			if (ret == 0) {
2761 				relay_close(con, "closed");
2762 				return;
2763 			}
2764 			/* FALLTHROUGH */
2765 		default:
2766 			ssl_error(rlay->rl_conf.name, "relay_ssl_connect");
2767 			relay_close(con, "SSL connect error");
2768 			return;
2769 		}
2770 	}
2771 
2772 #ifdef DEBUG
2773 	log_info(
2774 #else
2775 	log_debug(
2776 #endif
2777 	    "relay %s, session %d connected (%d active)",
2778 	    rlay->rl_conf.name, con->se_id, relay_sessions);
2779 
2780 	relay_connected(fd, EV_WRITE, con);
2781 	return;
2782 
2783 retry:
2784 	DPRINTF("%s: session %d: scheduling on %s", __func__, con->se_id,
2785 	    (retry_flag == EV_READ) ? "EV_READ" : "EV_WRITE");
2786 	event_again(&con->se_ev, fd, EV_TIMEOUT|retry_flag, relay_ssl_connect,
2787 	    &con->se_tv_start, &rlay->rl_conf.timeout, con);
2788 }
2789 
2790 void
2791 relay_ssl_connected(struct ctl_relay_event *cre)
2792 {
2793 	/*
2794 	 * Hack libevent - we overwrite the internal bufferevent I/O
2795 	 * functions to handle the SSL abstraction.
2796 	 */
2797 	event_set(&cre->bev->ev_read, cre->s, EV_READ,
2798 	    relay_ssl_readcb, cre->bev);
2799 	event_set(&cre->bev->ev_write, cre->s, EV_WRITE,
2800 	    relay_ssl_writecb, cre->bev);
2801 }
2802 
2803 void
2804 relay_ssl_readcb(int fd, short event, void *arg)
2805 {
2806 	struct bufferevent *bufev = arg;
2807 	struct ctl_relay_event *cre = (struct ctl_relay_event *)bufev->cbarg;
2808 	struct rsession *con = cre->con;
2809 	struct relay *rlay = (struct relay *)con->se_relay;
2810 	int ret = 0, ssl_err = 0;
2811 	short what = EVBUFFER_READ;
2812 	size_t len;
2813 	char rbuf[IBUF_READ_SIZE];
2814 	int howmuch = IBUF_READ_SIZE;
2815 
2816 	if (event == EV_TIMEOUT) {
2817 		what |= EVBUFFER_TIMEOUT;
2818 		goto err;
2819 	}
2820 
2821 	if (bufev->wm_read.high != 0)
2822 		howmuch = MIN(sizeof(rbuf), bufev->wm_read.high);
2823 
2824 	ret = SSL_read(cre->ssl, rbuf, howmuch);
2825 	if (ret <= 0) {
2826 		ssl_err = SSL_get_error(cre->ssl, ret);
2827 
2828 		switch (ssl_err) {
2829 		case SSL_ERROR_WANT_READ:
2830 			DPRINTF("%s: session %d: want read",
2831 			    __func__, con->se_id);
2832 			goto retry;
2833 		case SSL_ERROR_WANT_WRITE:
2834 			DPRINTF("%s: session %d: want write",
2835 			    __func__, con->se_id);
2836 			goto retry;
2837 		default:
2838 			if (ret == 0)
2839 				what |= EVBUFFER_EOF;
2840 			else {
2841 				ssl_error(rlay->rl_conf.name,
2842 				    "relay_ssl_readcb");
2843 				what |= EVBUFFER_ERROR;
2844 			}
2845 			goto err;
2846 		}
2847 	}
2848 
2849 	if (evbuffer_add(bufev->input, rbuf, ret) == -1) {
2850 		what |= EVBUFFER_ERROR;
2851 		goto err;
2852 	}
2853 
2854 	relay_bufferevent_add(&bufev->ev_read, bufev->timeout_read);
2855 
2856 	len = EVBUFFER_LENGTH(bufev->input);
2857 	if (bufev->wm_read.low != 0 && len < bufev->wm_read.low)
2858 		return;
2859 	if (bufev->wm_read.high != 0 && len > bufev->wm_read.high) {
2860 		struct evbuffer *buf = bufev->input;
2861 		event_del(&bufev->ev_read);
2862 		evbuffer_setcb(buf, bufferevent_read_pressure_cb, bufev);
2863 		return;
2864 	}
2865 
2866 	if (bufev->readcb != NULL)
2867 		(*bufev->readcb)(bufev, bufev->cbarg);
2868 	return;
2869 
2870  retry:
2871 	relay_bufferevent_add(&bufev->ev_read, bufev->timeout_read);
2872 	return;
2873 
2874  err:
2875 	(*bufev->errorcb)(bufev, what, bufev->cbarg);
2876 }
2877 
2878 void
2879 relay_ssl_writecb(int fd, short event, void *arg)
2880 {
2881 	struct bufferevent *bufev = arg;
2882 	struct ctl_relay_event *cre = (struct ctl_relay_event *)bufev->cbarg;
2883 	struct rsession *con = cre->con;
2884 	struct relay *rlay = (struct relay *)con->se_relay;
2885 	int ret = 0, ssl_err;
2886 	short what = EVBUFFER_WRITE;
2887 
2888 	if (event == EV_TIMEOUT) {
2889 		what |= EVBUFFER_TIMEOUT;
2890 		goto err;
2891 	}
2892 
2893 	if (EVBUFFER_LENGTH(bufev->output)) {
2894 		if (cre->buf == NULL) {
2895 			cre->buflen = EVBUFFER_LENGTH(bufev->output);
2896 			if ((cre->buf = malloc(cre->buflen)) == NULL) {
2897 				what |= EVBUFFER_ERROR;
2898 				goto err;
2899 			}
2900 			bcopy(EVBUFFER_DATA(bufev->output),
2901 			    cre->buf, cre->buflen);
2902 		}
2903 
2904 		ret = SSL_write(cre->ssl, cre->buf, cre->buflen);
2905 		if (ret <= 0) {
2906 			ssl_err = SSL_get_error(cre->ssl, ret);
2907 
2908 			switch (ssl_err) {
2909 			case SSL_ERROR_WANT_READ:
2910 				DPRINTF("%s: session %d: want read",
2911 				    __func__, con->se_id);
2912 				goto retry;
2913 			case SSL_ERROR_WANT_WRITE:
2914 				DPRINTF("%s: session %d: want write",
2915 				    __func__, con->se_id);
2916 				goto retry;
2917 			default:
2918 				if (ret == 0)
2919 					what |= EVBUFFER_EOF;
2920 				else {
2921 					ssl_error(rlay->rl_conf.name,
2922 					    "relay_ssl_writecb");
2923 					what |= EVBUFFER_ERROR;
2924 				}
2925 				goto err;
2926 			}
2927 		}
2928 		evbuffer_drain(bufev->output, ret);
2929 	}
2930 	if (cre->buf != NULL) {
2931 		free(cre->buf);
2932 		cre->buf = NULL;
2933 		cre->buflen = 0;
2934 	}
2935 
2936 	if (EVBUFFER_LENGTH(bufev->output) != 0)
2937 		relay_bufferevent_add(&bufev->ev_write, bufev->timeout_write);
2938 
2939 	if (bufev->writecb != NULL &&
2940 	    EVBUFFER_LENGTH(bufev->output) <= bufev->wm_write.low)
2941 		(*bufev->writecb)(bufev, bufev->cbarg);
2942 	return;
2943 
2944  retry:
2945 	if (cre->buflen != 0)
2946 		relay_bufferevent_add(&bufev->ev_write, bufev->timeout_write);
2947 	return;
2948 
2949  err:
2950 	if (cre->buf != NULL) {
2951 		free(cre->buf);
2952 		cre->buf = NULL;
2953 		cre->buflen = 0;
2954 	}
2955 	(*bufev->errorcb)(bufev, what, bufev->cbarg);
2956 }
2957 
2958 int
2959 relay_bufferevent_add(struct event *ev, int timeout)
2960 {
2961 	struct timeval tv, *ptv = NULL;
2962 
2963 	if (timeout) {
2964 		timerclear(&tv);
2965 		tv.tv_sec = timeout;
2966 		ptv = &tv;
2967 	}
2968 
2969 	return (event_add(ev, ptv));
2970 }
2971 
2972 #ifdef notyet
2973 int
2974 relay_bufferevent_printf(struct ctl_relay_event *cre, const char *fmt, ...)
2975 {
2976 	int ret;
2977 	va_list ap;
2978 
2979 	va_start(ap, fmt);
2980 	ret = evbuffer_add_vprintf(cre->output, fmt, ap);
2981 	va_end(ap);
2982 
2983 	if (cre->bev != NULL &&
2984 	    ret != -1 && EVBUFFER_LENGTH(cre->output) > 0 &&
2985 	    (cre->bev->enabled & EV_WRITE))
2986 		bufferevent_enable(cre->bev, EV_WRITE);
2987 
2988 	return (ret);
2989 }
2990 #endif
2991 
2992 int
2993 relay_bufferevent_print(struct ctl_relay_event *cre, char *str)
2994 {
2995 	if (cre->bev == NULL)
2996 		return (evbuffer_add(cre->output, str, strlen(str)));
2997 	return (bufferevent_write(cre->bev, str, strlen(str)));
2998 }
2999 
3000 int
3001 relay_bufferevent_write_buffer(struct ctl_relay_event *cre,
3002     struct evbuffer *buf)
3003 {
3004 	if (cre->bev == NULL)
3005 		return (evbuffer_add_buffer(cre->output, buf));
3006 	return (bufferevent_write_buffer(cre->bev, buf));
3007 }
3008 
3009 int
3010 relay_bufferevent_write_chunk(struct ctl_relay_event *cre,
3011     struct evbuffer *buf, size_t size)
3012 {
3013 	int ret;
3014 	ret = relay_bufferevent_write(cre, buf->buffer, size);
3015 	if (ret != -1)
3016 		evbuffer_drain(buf, size);
3017 	return (ret);
3018 }
3019 
3020 int
3021 relay_bufferevent_write(struct ctl_relay_event *cre, void *data, size_t size)
3022 {
3023 	if (cre->bev == NULL)
3024 		return (evbuffer_add(cre->output, data, size));
3025 	return (bufferevent_write(cre->bev, data, size));
3026 }
3027 
3028 int
3029 relay_cmp_af(struct sockaddr_storage *a, struct sockaddr_storage *b)
3030 {
3031 	int ret = -1;
3032 	struct sockaddr_in ia, ib;
3033 	struct sockaddr_in6 ia6, ib6;
3034 
3035 	switch (a->ss_family) {
3036 	case AF_INET:
3037 		bcopy(a, &ia, sizeof(struct sockaddr_in));
3038 		bcopy(b, &ib, sizeof(struct sockaddr_in));
3039 
3040 		ret = memcmp(&ia.sin_addr, &ib.sin_addr,
3041 		    sizeof(ia.sin_addr));
3042 		if (ret == 0)
3043 			ret = memcmp(&ia.sin_port, &ib.sin_port,
3044 			    sizeof(ia.sin_port));
3045 		break;
3046 	case AF_INET6:
3047 		bcopy(a, &ia6, sizeof(struct sockaddr_in6));
3048 		bcopy(b, &ib6, sizeof(struct sockaddr_in6));
3049 
3050 		ret = memcmp(&ia6.sin6_addr, &ib6.sin6_addr,
3051 		    sizeof(ia6.sin6_addr));
3052 		if (ret == 0)
3053 			ret = memcmp(&ia6.sin6_port, &ib6.sin6_port,
3054 			    sizeof(ia6.sin6_port));
3055 		break;
3056 	default:
3057 		break;
3058 	}
3059 
3060 	return (ret);
3061 }
3062 
3063 char *
3064 relay_load_file(const char *name, off_t *len)
3065 {
3066 	struct stat	 st;
3067 	off_t		 size;
3068 	u_int8_t	*buf = NULL;
3069 	int		 fd;
3070 
3071 	if ((fd = open(name, O_RDONLY)) == -1)
3072 		return (NULL);
3073 	if (fstat(fd, &st) != 0)
3074 		goto fail;
3075 	size = st.st_size;
3076 	if ((buf = (char *)calloc(1, size + 1)) == NULL)
3077 		goto fail;
3078 	if (read(fd, buf, size) != size)
3079 		goto fail;
3080 
3081 	close(fd);
3082 
3083 	*len = size;
3084 	return (buf);
3085 
3086  fail:
3087 	if (buf != NULL)
3088 		free(buf);
3089 	close(fd);
3090 	return (NULL);
3091 }
3092 
3093 int
3094 relay_load_certfiles(struct relay *rlay)
3095 {
3096 	struct protocol *proto = rlay->rl_proto;
3097 	char	 certfile[PATH_MAX];
3098 	char	 hbuf[sizeof("ffff:ffff:ffff:ffff:ffff:ffff:255.255.255.255")];
3099 
3100 	if ((rlay->rl_conf.flags & F_SSLCLIENT) && strlen(proto->sslca)) {
3101 		if ((rlay->rl_ssl_ca = relay_load_file(proto->sslca,
3102 		    &rlay->rl_conf.ssl_ca_len)) == NULL)
3103 			return (-1);
3104 		log_debug("%s: using ca %s", __func__, proto->sslca);
3105 	}
3106 
3107 	if ((rlay->rl_conf.flags & F_SSL) == 0)
3108 		return (0);
3109 
3110 	if (print_host(&rlay->rl_conf.ss, hbuf, sizeof(hbuf)) == NULL)
3111 		return (-1);
3112 
3113 	if (snprintf(certfile, sizeof(certfile),
3114 	    "/etc/ssl/%s.crt", hbuf) == -1)
3115 		return (-1);
3116 	if ((rlay->rl_ssl_cert = relay_load_file(certfile,
3117 	    &rlay->rl_conf.ssl_cert_len)) == NULL)
3118 		return (-1);
3119 	log_debug("%s: using certificate %s", __func__, certfile);
3120 
3121 	if (snprintf(certfile, sizeof(certfile),
3122 	    "/etc/ssl/private/%s.key", hbuf) == -1)
3123 		return -1;
3124 	if ((rlay->rl_ssl_key = relay_load_file(certfile,
3125 	    &rlay->rl_conf.ssl_key_len)) == NULL)
3126 		return (-1);
3127 	log_debug("%s: using private key %s", __func__, certfile);
3128 
3129 	return (0);
3130 }
3131 
3132 static __inline int
3133 relay_proto_cmp(struct protonode *a, struct protonode *b)
3134 {
3135 	int ret;
3136 	ret = strcasecmp(a->key, b->key);
3137 	if (ret == 0)
3138 		ret = (int)a->type - b->type;
3139 	return (ret);
3140 }
3141 
3142 RB_GENERATE(proto_tree, protonode, nodes, relay_proto_cmp);
3143 
3144 int
3145 relay_session_cmp(struct rsession *a, struct rsession *b)
3146 {
3147 	struct relay	*rlay = (struct relay *)b->se_relay;
3148 	struct protocol	*proto = rlay->rl_proto;
3149 
3150 	if (proto != NULL && proto->cmp != NULL)
3151 		return ((*proto->cmp)(a, b));
3152 
3153 	return ((int)a->se_id - b->se_id);
3154 }
3155 
3156 SPLAY_GENERATE(session_tree, rsession, se_nodes, relay_session_cmp);
3157