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