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