Bug Summary

File:src/usr.sbin/relayd/relay.c
Warning:line 1635, column 3
Use of memory after it is freed

Annotated Source Code

Press '?' to see keyboard shortcuts

clang -cc1 -cc1 -triple amd64-unknown-openbsd7.0 -analyze -disable-free -disable-llvm-verifier -discard-value-names -main-file-name relay.c -analyzer-store=region -analyzer-opt-analyze-nested-blocks -analyzer-checker=core -analyzer-checker=apiModeling -analyzer-checker=unix -analyzer-checker=deadcode -analyzer-checker=security.insecureAPI.UncheckedReturn -analyzer-checker=security.insecureAPI.getpw -analyzer-checker=security.insecureAPI.gets -analyzer-checker=security.insecureAPI.mktemp -analyzer-checker=security.insecureAPI.mkstemp -analyzer-checker=security.insecureAPI.vfork -analyzer-checker=nullability.NullPassedToNonnull -analyzer-checker=nullability.NullReturnedFromNonnull -analyzer-output plist -w -setup-static-analyzer -mrelocation-model pic -pic-level 1 -pic-is-pie -mframe-pointer=all -relaxed-aliasing -fno-rounding-math -mconstructor-aliases -munwind-tables -target-cpu x86-64 -target-feature +retpoline-indirect-calls -target-feature +retpoline-indirect-branches -tune-cpu generic -debugger-tuning=gdb -fcoverage-compilation-dir=/usr/src/usr.sbin/relayd/obj -resource-dir /usr/local/lib/clang/13.0.0 -I /usr/src/usr.sbin/relayd -internal-isystem /usr/local/lib/clang/13.0.0/include -internal-externc-isystem /usr/include -O2 -fdebug-compilation-dir=/usr/src/usr.sbin/relayd/obj -ferror-limit 19 -fwrapv -D_RET_PROTECTOR -ret-protector -fgnuc-version=4.2.1 -vectorize-loops -vectorize-slp -fno-builtin-malloc -fno-builtin-calloc -fno-builtin-realloc -fno-builtin-valloc -fno-builtin-free -fno-builtin-strdup -fno-builtin-strndup -analyzer-output=html -faddrsig -D__GCC_HAVE_DWARF2_CFI_ASM=1 -o /home/ben/Projects/vmm/scan-build/2022-01-12-194120-40624-1 -x c /usr/src/usr.sbin/relayd/relay.c
1/* $OpenBSD: relay.c,v 1.254 2021/03/24 20:59:53 benno Exp $ */
2
3/*
4 * Copyright (c) 2006 - 2014 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/socket.h>
23#include <sys/tree.h>
24
25#include <netinet/in.h>
26#include <netinet/tcp.h>
27#include <arpa/inet.h>
28
29#include <limits.h>
30#include <netdb.h>
31#include <poll.h>
32#include <stdio.h>
33#include <stdlib.h>
34#include <errno(*__errno()).h>
35#include <fcntl.h>
36#include <string.h>
37#include <unistd.h>
38#include <event.h>
39#include <siphash.h>
40#include <imsg.h>
41
42#include <tls.h>
43
44#include "relayd.h"
45
46#define MINIMUM(a, b)(((a) < (b)) ? (a) : (b)) (((a) < (b)) ? (a) : (b))
47
48void relay_statistics(int, short, void *);
49int relay_dispatch_parent(int, struct privsep_proc *,
50 struct imsg *);
51int relay_dispatch_pfe(int, struct privsep_proc *,
52 struct imsg *);
53int relay_dispatch_ca(int, struct privsep_proc *,
54 struct imsg *);
55int relay_dispatch_hce(int, struct privsep_proc *,
56 struct imsg *);
57void relay_shutdown(void);
58
59void relay_protodebug(struct relay *);
60void relay_ruledebug(struct relay_rule *);
61void relay_init(struct privsep *, struct privsep_proc *p, void *);
62void relay_launch(void);
63int relay_socket(struct sockaddr_storage *, in_port_t,
64 struct protocol *, int, int);
65int relay_socket_listen(struct sockaddr_storage *, in_port_t,
66 struct protocol *);
67int relay_socket_connect(struct sockaddr_storage *, in_port_t,
68 struct protocol *, int);
69
70void relay_accept(int, short, void *);
71void relay_input(struct rsession *);
72
73void relay_hash_addr(SIPHASH_CTX *, struct sockaddr_storage *, int);
74
75int relay_tls_ctx_create(struct relay *);
76void relay_tls_transaction(struct rsession *,
77 struct ctl_relay_event *);
78void relay_tls_handshake(int, short, void *);
79void relay_tls_connected(struct ctl_relay_event *);
80void relay_tls_readcb(int, short, void *);
81void relay_tls_writecb(int, short, void *);
82
83void relay_connect_retry(int, short, void *);
84void relay_connect_state(struct rsession *,
85 struct ctl_relay_event *, enum relay_state);
86
87extern void bufferevent_read_pressure_cb(struct evbuffer *, size_t,
88 size_t, void *);
89
90volatile int relay_sessions;
91volatile int relay_inflight = 0;
92objid_t relay_conid;
93
94static struct relayd *env = NULL((void*)0);
95
96static struct privsep_proc procs[] = {
97 { "parent", PROC_PARENT, relay_dispatch_parent },
98 { "pfe", PROC_PFE, relay_dispatch_pfe },
99 { "ca", PROC_CA, relay_dispatch_ca },
100 { "hce", PROC_HCE, relay_dispatch_hce },
101};
102
103void
104relay(struct privsep *ps, struct privsep_proc *p)
105{
106 env = ps->ps_env;
107 proc_run(ps, p, procs, nitems(procs)(sizeof((procs)) / sizeof((procs)[0])), relay_init, NULL((void*)0));
108 relay_http(env);
109}
110
111void
112relay_shutdown(void)
113{
114 config_purge(env, CONFIG_ALL0xff);
115 usleep(200); /* XXX relay needs to shutdown last */
116}
117
118void
119relay_ruledebug(struct relay_rule *rule)
120{
121 struct kv *kv = NULL((void*)0);
122 u_int i;
123 char buf[NI_MAXHOST256];
124
125 fprintf(stderr(&__sF[2]), "\t\t");
126
127 switch (rule->rule_action) {
128 case RULE_ACTION_MATCH:
129 fprintf(stderr(&__sF[2]), "match ");
130 break;
131 case RULE_ACTION_BLOCK:
132 fprintf(stderr(&__sF[2]), "block ");
133 break;
134 case RULE_ACTION_PASS:
135 fprintf(stderr(&__sF[2]), "pass ");
136 break;
137 }
138
139 switch (rule->rule_dir) {
140 case RELAY_DIR_ANY:
141 break;
142 case RELAY_DIR_REQUEST:
143 fprintf(stderr(&__sF[2]), "request ");
144 break;
145 case RELAY_DIR_RESPONSE:
146 fprintf(stderr(&__sF[2]), "response ");
147 break;
148 default:
149 return;
150 /* NOTREACHED */
151 break;
152 }
153
154 if (rule->rule_flags & RULE_FLAG_QUICK0x01)
155 fprintf(stderr(&__sF[2]), "quick ");
156
157 switch (rule->rule_af) {
158 case AF_INET2:
159 fprintf(stderr(&__sF[2]), "inet ");
160 break;
161 case AF_INET624:
162 fprintf(stderr(&__sF[2]), "inet6 ");
163 break;
164 }
165
166 if (rule->rule_src.addr.ss_family != AF_UNSPEC0)
167 fprintf(stderr(&__sF[2]), "from %s/%d ",
168 print_host(&rule->rule_src.addr, buf, sizeof(buf)),
169 rule->rule_src.addr_mask);
170
171 if (rule->rule_dst.addr.ss_family != AF_UNSPEC0)
172 fprintf(stderr(&__sF[2]), "to %s/%d ",
173 print_host(&rule->rule_dst.addr, buf, sizeof(buf)),
174 rule->rule_dst.addr_mask);
175
176 for (i = 1; i < KEY_TYPE_MAX; i++) {
177 kv = &rule->rule_kv[i];
178 if (kv->kv_type != i)
179 continue;
180
181 switch (kv->kv_type) {
182 case KEY_TYPE_COOKIE:
183 fprintf(stderr(&__sF[2]), "cookie ");
184 break;
185 case KEY_TYPE_HEADER:
186 fprintf(stderr(&__sF[2]), "header ");
187 break;
188 case KEY_TYPE_PATH:
189 fprintf(stderr(&__sF[2]), "path ");
190 break;
191 case KEY_TYPE_QUERY:
192 fprintf(stderr(&__sF[2]), "query ");
193 break;
194 case KEY_TYPE_URL:
195 fprintf(stderr(&__sF[2]), "url ");
196 break;
197 default:
198 continue;
199 }
200
201 switch (kv->kv_option) {
202 case KEY_OPTION_APPEND:
203 fprintf(stderr(&__sF[2]), "append ");
204 break;
205 case KEY_OPTION_SET:
206 fprintf(stderr(&__sF[2]), "set ");
207 break;
208 case KEY_OPTION_REMOVE:
209 fprintf(stderr(&__sF[2]), "remove ");
210 break;
211 case KEY_OPTION_HASH:
212 fprintf(stderr(&__sF[2]), "hash ");
213 break;
214 case KEY_OPTION_LOG:
215 fprintf(stderr(&__sF[2]), "log ");
216 break;
217 case KEY_OPTION_STRIP:
218 fprintf(stderr(&__sF[2]), "strip ");
219 break;
220 case KEY_OPTION_NONE:
221 break;
222 }
223
224 switch (kv->kv_digest) {
225 case DIGEST_SHA1:
226 case DIGEST_MD5:
227 fprintf(stderr(&__sF[2]), "digest ");
228 break;
229 default:
230 break;
231 }
232
233 int kvv = (kv->kv_option == KEY_OPTION_STRIP ||
234 kv->kv_value == NULL((void*)0));
235 fprintf(stderr(&__sF[2]), "%s%s%s%s%s%s ",
236 kv->kv_key == NULL((void*)0) ? "" : "\"",
237 kv->kv_key == NULL((void*)0) ? "" : kv->kv_key,
238 kv->kv_key == NULL((void*)0) ? "" : "\"",
239 kvv ? "" : " value \"",
240 kv->kv_value == NULL((void*)0) ? "" : kv->kv_value,
241 kvv ? "" : "\"");
242 }
243
244 if (rule->rule_tablename[0])
245 fprintf(stderr(&__sF[2]), "forward to <%s> ", rule->rule_tablename);
246
247 if (rule->rule_tag == -1)
248 fprintf(stderr(&__sF[2]), "no tag ");
249 else if (rule->rule_tag && rule->rule_tagname[0])
250 fprintf(stderr(&__sF[2]), "tag \"%s\" ",
251 rule->rule_tagname);
252
253 if (rule->rule_tagged && rule->rule_taggedname[0])
254 fprintf(stderr(&__sF[2]), "tagged \"%s\" ",
255 rule->rule_taggedname);
256
257 if (rule->rule_label == -1)
258 fprintf(stderr(&__sF[2]), "no label ");
259 else if (rule->rule_label && rule->rule_labelname[0])
260 fprintf(stderr(&__sF[2]), "label \"%s\" ",
261 rule->rule_labelname);
262
263 fprintf(stderr(&__sF[2]), "\n");
264}
265
266void
267relay_protodebug(struct relay *rlay)
268{
269 struct protocol *proto = rlay->rl_proto;
270 struct relay_rule *rule = NULL((void*)0);
271
272 fprintf(stderr(&__sF[2]), "protocol %d: name %s\n",
273 proto->id, proto->name);
274 fprintf(stderr(&__sF[2]), "\tflags: %s, relay flags: %s\n",
275 printb_flags(proto->flags, F_BITS"\10\01DISABLE\02BACKUP\03USED\04DOWN\05ADD\06DEL\07CHANGED" "\10STICKY-ADDRESS\11CHECK_DONE\12ACTIVE_RULESET\13CHECK_SENT"
"\14TLS\15NAT_LOOKUP\16DEMOTE\17LOOKUP_PATH\20DEMOTED\21UDP"
"\22RETURN\23TRAP\24NEEDPF\25PORT\26TLS_CLIENT\27NEEDRT" "\30MATCH\31DIVERT\32SCRIPT\33TLS_INSPECT\34HASHKEY"
"\35AGENTX_TRAPONLY"
),
276 printb_flags(rlay->rl_conf.flags, F_BITS"\10\01DISABLE\02BACKUP\03USED\04DOWN\05ADD\06DEL\07CHANGED" "\10STICKY-ADDRESS\11CHECK_DONE\12ACTIVE_RULESET\13CHECK_SENT"
"\14TLS\15NAT_LOOKUP\16DEMOTE\17LOOKUP_PATH\20DEMOTED\21UDP"
"\22RETURN\23TRAP\24NEEDPF\25PORT\26TLS_CLIENT\27NEEDRT" "\30MATCH\31DIVERT\32SCRIPT\33TLS_INSPECT\34HASHKEY"
"\35AGENTX_TRAPONLY"
));
277 if (proto->tcpflags)
278 fprintf(stderr(&__sF[2]), "\ttcp flags: %s\n",
279 printb_flags(proto->tcpflags, TCPFLAG_BITS"\10\01NODELAY\02NO_NODELAY\03SACK\04NO_SACK" "\05SOCKET_BUFFER_SIZE\06IP_TTL\07IP_MINTTL\10NO_SPLICE"));
280 if ((rlay->rl_conf.flags & (F_TLS0x00000800|F_TLSCLIENT0x00200000)) && proto->tlsflags)
281 fprintf(stderr(&__sF[2]), "\ttls flags: %s\n",
282 printb_flags(proto->tlsflags, TLSFLAG_BITS"\06\01sslv3\02tlsv1.0\03tlsv1.1\04tlsv1.2\05tlsv1.3" "\06cipher-server-preference\07client-renegotiation"));
283 fprintf(stderr(&__sF[2]), "\ttls session tickets: %s\n",
284 (proto->tickets == 1) ? "enabled" : "disabled");
285 fprintf(stderr(&__sF[2]), "\ttype: ");
286 switch (proto->type) {
287 case RELAY_PROTO_TCP:
288 fprintf(stderr(&__sF[2]), "tcp\n");
289 break;
290 case RELAY_PROTO_HTTP:
291 fprintf(stderr(&__sF[2]), "http\n");
292 break;
293 case RELAY_PROTO_DNS:
294 fprintf(stderr(&__sF[2]), "dns\n");
295 break;
296 }
297
298 rule = TAILQ_FIRST(&proto->rules)((&proto->rules)->tqh_first);
299 while (rule != NULL((void*)0)) {
300 relay_ruledebug(rule);
301 rule = TAILQ_NEXT(rule, rule_entry)((rule)->rule_entry.tqe_next);
302 }
303}
304
305int
306relay_privinit(struct relay *rlay)
307{
308 log_debug("%s: adding relay %s", __func__, rlay->rl_conf.name);
309
310 if (log_getverbose() > 1)
311 relay_protodebug(rlay);
312
313 switch (rlay->rl_proto->type) {
314 case RELAY_PROTO_DNS:
315 relay_udp_privinit(rlay);
316 break;
317 case RELAY_PROTO_TCP:
318 break;
319 case RELAY_PROTO_HTTP:
320 break;
321 }
322
323 if (rlay->rl_conf.flags & F_UDP0x00010000)
324 rlay->rl_s = relay_udp_bind(&rlay->rl_conf.ss,
325 rlay->rl_conf.port, rlay->rl_proto);
326 else
327 rlay->rl_s = relay_socket_listen(&rlay->rl_conf.ss,
328 rlay->rl_conf.port, rlay->rl_proto);
329 if (rlay->rl_s == -1)
330 return (-1);
331
332 return (0);
333}
334
335void
336relay_init(struct privsep *ps, struct privsep_proc *p, void *arg)
337{
338 struct timeval tv;
339
340 if (config_init(ps->ps_env) == -1)
341 fatal("failed to initialize configuration");
342
343 /* We use a custom shutdown callback */
344 p->p_shutdown = relay_shutdown;
345
346 /* Unlimited file descriptors (use system limits) */
347 socket_rlimit(-1);
348
349 if (pledge("stdio recvfd inet", NULL((void*)0)) == -1)
350 fatal("pledge");
351
352 /* Schedule statistics timer */
353 evtimer_set(&env->sc_statev, relay_statistics, ps)event_set(&env->sc_statev, -1, 0, relay_statistics, ps
)
;
354 bcopy(&env->sc_conf.statinterval, &tv, sizeof(tv));
355 evtimer_add(&env->sc_statev, &tv)event_add(&env->sc_statev, &tv);
356}
357
358void
359relay_session_publish(struct rsession *s)
360{
361 proc_compose(env->sc_ps, PROC_PFE, IMSG_SESS_PUBLISH, s, sizeof(*s));
362}
363
364void
365relay_session_unpublish(struct rsession *s)
366{
367 proc_compose(env->sc_ps, PROC_PFE, IMSG_SESS_UNPUBLISH,
368 &s->se_id, sizeof(s->se_id));
369}
370
371void
372relay_statistics(int fd, short events, void *arg)
373{
374 struct privsep *ps = arg;
375 struct relay *rlay;
376 struct ctl_stats crs, *cur;
377 struct timeval tv, tv_now;
378 int resethour = 0, resetday = 0;
379 struct rsession *con, *next_con;
380
381 /*
382 * This is a hack to calculate some average statistics.
383 * It doesn't try to be very accurate, but could be improved...
384 */
385
386 timerclear(&tv)(&tv)->tv_sec = (&tv)->tv_usec = 0;
387 getmonotime(&tv_now);
388
389 TAILQ_FOREACH(rlay, env->sc_relays, rl_entry)for((rlay) = ((env->sc_relays)->tqh_first); (rlay) != (
(void*)0); (rlay) = ((rlay)->rl_entry.tqe_next))
{
390 bzero(&crs, sizeof(crs));
391 resethour = resetday = 0;
392
393 cur = &rlay->rl_stats[ps->ps_instance];
394 cur->cnt += cur->last;
395 cur->tick++;
396 cur->avg = (cur->last + cur->avg) / 2;
397 cur->last_hour += cur->last;
398 if ((cur->tick %
399 (3600 / env->sc_conf.statinterval.tv_sec)) == 0) {
400 cur->avg_hour = (cur->last_hour + cur->avg_hour) / 2;
401 resethour++;
402 }
403 cur->last_day += cur->last;
404 if ((cur->tick %
405 (86400 / env->sc_conf.statinterval.tv_sec)) == 0) {
406 cur->avg_day = (cur->last_day + cur->avg_day) / 2;
407 resethour++;
408 }
409 bcopy(cur, &crs, sizeof(crs));
410
411 cur->last = 0;
412 if (resethour)
413 cur->last_hour = 0;
414 if (resetday)
415 cur->last_day = 0;
416
417 crs.id = rlay->rl_conf.id;
418 crs.proc = ps->ps_instance;
419 proc_compose(env->sc_ps, PROC_PFE, IMSG_STATISTICS,
420 &crs, sizeof(crs));
421
422 for (con = SPLAY_ROOT(&rlay->rl_sessions)(&rlay->rl_sessions)->sph_root;
423 con != NULL((void*)0); con = next_con) {
424 next_con = SPLAY_NEXT(session_tree,session_tree_SPLAY_NEXT(&rlay->rl_sessions, con)
425 &rlay->rl_sessions, con)session_tree_SPLAY_NEXT(&rlay->rl_sessions, con);
426 timersub(&tv_now, &con->se_tv_last, &tv)do { (&tv)->tv_sec = (&tv_now)->tv_sec - (&
con->se_tv_last)->tv_sec; (&tv)->tv_usec = (&
tv_now)->tv_usec - (&con->se_tv_last)->tv_usec; if
((&tv)->tv_usec < 0) { (&tv)->tv_sec--; (&
tv)->tv_usec += 1000000; } } while (0)
;
427 if (timercmp(&tv, &rlay->rl_conf.timeout, >=)(((&tv)->tv_sec == (&rlay->rl_conf.timeout)->
tv_sec) ? ((&tv)->tv_usec >= (&rlay->rl_conf
.timeout)->tv_usec) : ((&tv)->tv_sec >= (&rlay
->rl_conf.timeout)->tv_sec))
)
428 relay_close(con, "hard timeout", 1);
429 }
430 }
431
432 /* Schedule statistics timer */
433 evtimer_set(&env->sc_statev, relay_statistics, ps)event_set(&env->sc_statev, -1, 0, relay_statistics, ps
)
;
434 bcopy(&env->sc_conf.statinterval, &tv, sizeof(tv));
435 evtimer_add(&env->sc_statev, &tv)event_add(&env->sc_statev, &tv);
436}
437
438void
439relay_launch(void)
440{
441 void (*callback)(int, short, void *);
442 struct relay *rlay;
443 struct host *host;
444 struct relay_table *rlt;
445
446 TAILQ_FOREACH(rlay, env->sc_relays, rl_entry)for((rlay) = ((env->sc_relays)->tqh_first); (rlay) != (
(void*)0); (rlay) = ((rlay)->rl_entry.tqe_next))
{
447 if ((rlay->rl_conf.flags & (F_TLS0x00000800|F_TLSCLIENT0x00200000)) &&
448 relay_tls_ctx_create(rlay) == -1)
449 fatalx("%s: failed to create TLS context", __func__);
450
451 TAILQ_FOREACH(rlt, &rlay->rl_tables, rlt_entry)for((rlt) = ((&rlay->rl_tables)->tqh_first); (rlt) !=
((void*)0); (rlt) = ((rlt)->rlt_entry.tqe_next))
{
452 /*
453 * set rule->rule_table in advance and save time
454 * looking up for this later on rule/connection
455 * evalution
456 */
457 rule_settable(&rlay->rl_proto->rules, rlt);
458
459 rlt->rlt_index = 0;
460 rlt->rlt_nhosts = 0;
461 TAILQ_FOREACH(host, &rlt->rlt_table->hosts, entry)for((host) = ((&rlt->rlt_table->hosts)->tqh_first
); (host) != ((void*)0); (host) = ((host)->entry.tqe_next)
)
{
462 if (rlt->rlt_nhosts >= RELAY_MAXHOSTS32)
463 fatal("%s: too many hosts in table",
464 __func__);
465 host->idx = rlt->rlt_nhosts;
466 rlt->rlt_host[rlt->rlt_nhosts++] = host;
467 }
468 log_info("adding %d hosts from table %s%s",
469 rlt->rlt_nhosts, rlt->rlt_table->conf.name,
470 rlt->rlt_table->conf.check ? "" : " (no check)");
471 }
472
473 switch (rlay->rl_proto->type) {
474 case RELAY_PROTO_DNS:
475 relay_udp_init(env, rlay);
476 break;
477 case RELAY_PROTO_TCP:
478 case RELAY_PROTO_HTTP:
479 relay_http_init(rlay);
480 /* Use defaults */
481 break;
482 }
483
484 log_debug("%s: running relay %s", __func__,
485 rlay->rl_conf.name);
486
487 rlay->rl_up = HOST_UP;
488
489 if (rlay->rl_conf.flags & F_UDP0x00010000)
490 callback = relay_udp_server;
491 else
492 callback = relay_accept;
493
494 event_set(&rlay->rl_ev, rlay->rl_s, EV_READ0x02,
495 callback, rlay);
496 event_add(&rlay->rl_ev, NULL((void*)0));
497 evtimer_set(&rlay->rl_evt, callback, rlay)event_set(&rlay->rl_evt, -1, 0, callback, rlay);
498 }
499}
500
501int
502relay_socket_af(struct sockaddr_storage *ss, in_port_t port)
503{
504 switch (ss->ss_family) {
505 case AF_INET2:
506 ((struct sockaddr_in *)ss)->sin_port = port;
507 ((struct sockaddr_in *)ss)->sin_len =
508 sizeof(struct sockaddr_in);
509 break;
510 case AF_INET624:
511 ((struct sockaddr_in6 *)ss)->sin6_port = port;
512 ((struct sockaddr_in6 *)ss)->sin6_len =
513 sizeof(struct sockaddr_in6);
514 break;
515 default:
516 return (-1);
517 }
518
519 return (0);
520}
521
522in_port_t
523relay_socket_getport(struct sockaddr_storage *ss)
524{
525 switch (ss->ss_family) {
526 case AF_INET2:
527 return (((struct sockaddr_in *)ss)->sin_port);
528 case AF_INET624:
529 return (((struct sockaddr_in6 *)ss)->sin6_port);
530 default:
531 return (0);
532 }
533
534 /* NOTREACHED */
535 return (0);
536}
537
538int
539relay_socket(struct sockaddr_storage *ss, in_port_t port,
540 struct protocol *proto, int fd, int reuseport)
541{
542 struct linger lng;
543 int s = -1, val;
544
545 if (relay_socket_af(ss, port) == -1)
546 goto bad;
547
548 s = fd == -1 ? socket(ss->ss_family,
549 SOCK_STREAM1 | SOCK_NONBLOCK0x4000, IPPROTO_TCP6) : fd;
550 if (s == -1)
551 goto bad;
552
553 /*
554 * Socket options
555 */
556 bzero(&lng, sizeof(lng));
557 if (setsockopt(s, SOL_SOCKET0xffff, SO_LINGER0x0080, &lng, sizeof(lng)) == -1)
558 goto bad;
559 if (reuseport) {
560 val = 1;
561 if (setsockopt(s, SOL_SOCKET0xffff, SO_REUSEPORT0x0200, &val,
562 sizeof(int)) == -1)
563 goto bad;
564 }
565 if (proto->tcpflags & TCPFLAG_BUFSIZ0x10) {
566 val = proto->tcpbufsiz;
567 if (setsockopt(s, SOL_SOCKET0xffff, SO_RCVBUF0x1002,
568 &val, sizeof(val)) == -1)
569 goto bad;
570 val = proto->tcpbufsiz;
571 if (setsockopt(s, SOL_SOCKET0xffff, SO_SNDBUF0x1001,
572 &val, sizeof(val)) == -1)
573 goto bad;
574 }
575
576 /*
577 * IP options
578 */
579 if (proto->tcpflags & TCPFLAG_IPTTL0x20) {
580 val = (int)proto->tcpipttl;
581 switch (ss->ss_family) {
582 case AF_INET2:
583 if (setsockopt(s, IPPROTO_IP0, IP_TTL4,
584 &val, sizeof(val)) == -1)
585 goto bad;
586 break;
587 case AF_INET624:
588 if (setsockopt(s, IPPROTO_IPV641, IPV6_UNICAST_HOPS4,
589 &val, sizeof(val)) == -1)
590 goto bad;
591 break;
592 }
593 }
594 if (proto->tcpflags & TCPFLAG_IPMINTTL0x40) {
595 val = (int)proto->tcpipminttl;
596 switch (ss->ss_family) {
597 case AF_INET2:
598 if (setsockopt(s, IPPROTO_IP0, IP_MINTTL32,
599 &val, sizeof(val)) == -1)
600 goto bad;
601 break;
602 case AF_INET624:
603 if (setsockopt(s, IPPROTO_IPV641, IPV6_MINHOPCOUNT65,
604 &val, sizeof(val)) == -1)
605 goto bad;
606 break;
607 }
608 }
609
610 /*
611 * TCP options
612 */
613 if (proto->tcpflags & (TCPFLAG_NODELAY0x01|TCPFLAG_NNODELAY0x02)) {
614 if (proto->tcpflags & TCPFLAG_NNODELAY0x02)
615 val = 0;
616 else
617 val = 1;
618 if (setsockopt(s, IPPROTO_TCP6, TCP_NODELAY0x01,
619 &val, sizeof(val)) == -1)
620 goto bad;
621 }
622 if (proto->tcpflags & (TCPFLAG_SACK0x04|TCPFLAG_NSACK0x08)) {
623 if (proto->tcpflags & TCPFLAG_NSACK0x08)
624 val = 0;
625 else
626 val = 1;
627 if (setsockopt(s, IPPROTO_TCP6, TCP_SACK_ENABLE0x08,
628 &val, sizeof(val)) == -1)
629 goto bad;
630 }
631
632 return (s);
633
634 bad:
635 if (s != -1)
636 close(s);
637 return (-1);
638}
639
640int
641relay_socket_connect(struct sockaddr_storage *ss, in_port_t port,
642 struct protocol *proto, int fd)
643{
644 int s;
645
646 if ((s = relay_socket(ss, port, proto, fd, 0)) == -1)
647 return (-1);
648
649 if (connect(s, (struct sockaddr *)ss, ss->ss_len) == -1) {
650 if (errno(*__errno()) != EINPROGRESS36)
651 goto bad;
652 }
653
654 return (s);
655
656 bad:
657 close(s);
658 return (-1);
659}
660
661int
662relay_socket_listen(struct sockaddr_storage *ss, in_port_t port,
663 struct protocol *proto)
664{
665 int s;
666
667 if ((s = relay_socket(ss, port, proto, -1, 1)) == -1)
668 return (-1);
669
670 if (bind(s, (struct sockaddr *)ss, ss->ss_len) == -1)
671 goto bad;
672 if (listen(s, proto->tcpbacklog) == -1)
673 goto bad;
674
675 return (s);
676
677 bad:
678 close(s);
679 return (-1);
680}
681
682void
683relay_connected(int fd, short sig, void *arg)
684{
685 char obuf[128];
686 struct rsession *con = arg;
687 struct relay *rlay = con->se_relay;
688 struct protocol *proto = rlay->rl_proto;
689 evbuffercb outrd = relay_read;
690 evbuffercb outwr = relay_write;
691 struct bufferevent *bev;
692 struct ctl_relay_event *out = &con->se_out;
693 char *msg;
694 socklen_t len;
695 int error;
696
697 if (sig
25.1
'sig' is not equal to EV_TIMEOUT
== EV_TIMEOUT0x01) {
26
Taking false branch
698 relay_abort_http(con, 504, "connect timeout", 0);
699 return;
700 }
701
702 len = sizeof(error);
703 if (getsockopt(fd, SOL_SOCKET0xffff, SO_ERROR0x1007, &error, &len) == -1) {
27
Assuming the condition is false
28
Taking false branch
704 relay_abort_http(con, 500, "getsockopt failed", 0);
705 return;
706 }
707 if (error) {
29
Assuming 'error' is 0
30
Taking false branch
708 errno(*__errno()) = error;
709 if (asprintf(&msg, "socket error: %s",
710 strerror(error)) >= 0) {
711 relay_abort_http(con, 500, msg, 0);
712 free(msg);
713 return;
714 } else {
715 relay_abort_http(con, 500,
716 "socket error and asprintf failed", 0);
717 return;
718 }
719 }
720
721 if ((rlay->rl_conf.flags & F_TLSCLIENT0x00200000) && (out->tls == NULL((void*)0))) {
31
Assuming the condition is false
722 relay_tls_transaction(con, out);
723 return;
724 }
725
726 DPRINTF("%s: session %d: successful", __func__, con->se_id)do {} while(0);
32
Loop condition is false. Exiting loop
727
728 /* Log destination if it was changed in a keep-alive connection */
729 if ((con->se_table != con->se_table0) &&
33
Assuming field 'se_table' is equal to field 'se_table0'
730 (env->sc_conf.opts & (RELAYD_OPT_LOGCON0x20|RELAYD_OPT_LOGCONERR0x40))) {
731 con->se_table0 = con->se_table;
732 memset(&obuf, 0, sizeof(obuf));
733 (void)print_host(&con->se_out.ss, obuf, sizeof(obuf));
734 if (asprintf(&msg, " -> %s:%d",
735 obuf, ntohs(con->se_out.port)(__uint16_t)(__builtin_constant_p(con->se_out.port) ? (__uint16_t
)(((__uint16_t)(con->se_out.port) & 0xffU) << 8 |
((__uint16_t)(con->se_out.port) & 0xff00U) >> 8
) : __swap16md(con->se_out.port))
) == -1) {
736 relay_abort_http(con, 500,
737 "connection changed and asprintf failed", 0);
738 return;
739 }
740 relay_log(con, msg);
741 free(msg);
742 }
743
744 switch (rlay->rl_proto->type) {
34
Control jumps to 'case RELAY_PROTO_HTTP:' at line 745
745 case RELAY_PROTO_HTTP:
746 if (relay_httpdesc_init(out) == -1) {
35
Assuming the condition is true
36
Taking true branch
747 relay_close(con,
37
Calling 'relay_close'
54
Returning; memory was released via 1st parameter
748 "failed to allocate http descriptor", 1);
749 return;
750 }
751 con->se_out.toread = TOREAD_HTTP_HEADER;
752 outrd = relay_read_http;
753 break;
754 case RELAY_PROTO_TCP:
755 /* Use defaults */
756 break;
757 default:
758 fatalx("%s: unknown protocol", __func__);
759 }
760
761 /*
762 * Relay <-> Server
763 */
764 bev = bufferevent_new(fd, outrd, outwr, relay_error, &con->se_out);
765 if (bev == NULL((void*)0)) {
766 relay_abort_http(con, 500,
767 "failed to allocate output buffer event", 0);
768 return;
769 }
770 /* write pending output buffer now */
771 if (bufferevent_write_buffer(bev, con->se_out.output)) {
772 relay_abort_http(con, 500, strerror(errno(*__errno())), 0);
773 return;
774 }
775 con->se_out.bev = bev;
776
777 /* Initialize the TLS wrapper */
778 if ((rlay->rl_conf.flags & F_TLSCLIENT0x00200000) && (out->tls != NULL((void*)0)))
779 relay_tls_connected(out);
780
781 bufferevent_settimeout(bev,
782 rlay->rl_conf.timeout.tv_sec, rlay->rl_conf.timeout.tv_sec);
783 bufferevent_setwatermark(bev, EV_WRITE0x04,
784 RELAY_MIN_PREFETCHED32 * proto->tcpbufsiz, 0);
785 bufferevent_enable(bev, EV_READ0x02|EV_WRITE0x04);
786 if (con->se_in.bev)
787 bufferevent_enable(con->se_in.bev, EV_READ0x02);
788
789 if (relay_splice(&con->se_out) == -1)
790 relay_close(con, strerror(errno(*__errno())), 1);
791}
792
793void
794relay_input(struct rsession *con)
795{
796 struct relay *rlay = con->se_relay;
797 struct protocol *proto = rlay->rl_proto;
798 evbuffercb inrd = relay_read;
799 evbuffercb inwr = relay_write;
800
801 switch (rlay->rl_proto->type) {
802 case RELAY_PROTO_HTTP:
803 if (relay_http_priv_init(con) == -1) {
804 relay_close(con,
805 "failed to allocate http descriptor", 1);
806 return;
807 }
808 con->se_in.toread = TOREAD_HTTP_HEADER;
809 inrd = relay_read_http;
810 break;
811 case RELAY_PROTO_TCP:
812 /* Use defaults */
813 break;
814 default:
815 fatalx("%s: unknown protocol", __func__);
816 }
817
818 /*
819 * Client <-> Relay
820 */
821 con->se_in.bev = bufferevent_new(con->se_in.s, inrd, inwr,
822 relay_error, &con->se_in);
823 if (con->se_in.bev == NULL((void*)0)) {
824 relay_close(con, "failed to allocate input buffer event", 1);
825 return;
826 }
827
828 /* Initialize the TLS wrapper */
829 if ((rlay->rl_conf.flags & F_TLS0x00000800) && con->se_in.tls != NULL((void*)0))
830 relay_tls_connected(&con->se_in);
831
832 bufferevent_settimeout(con->se_in.bev,
833 rlay->rl_conf.timeout.tv_sec, rlay->rl_conf.timeout.tv_sec);
834 bufferevent_setwatermark(con->se_in.bev, EV_WRITE0x04,
835 RELAY_MIN_PREFETCHED32 * proto->tcpbufsiz, 0);
836 bufferevent_enable(con->se_in.bev, EV_READ0x02|EV_WRITE0x04);
837
838 if (relay_splice(&con->se_in) == -1)
839 relay_close(con, strerror(errno(*__errno())), 1);
840}
841
842void
843relay_write(struct bufferevent *bev, void *arg)
844{
845 struct ctl_relay_event *cre = arg;
846 struct rsession *con = cre->con;
847
848 getmonotime(&con->se_tv_last);
849
850 if (con->se_done && EVBUFFER_LENGTH(EVBUFFER_OUTPUT(bev))((bev)->output)->off == 0)
851 goto done;
852 if (cre->dst->bev)
853 bufferevent_enable(cre->dst->bev, EV_READ0x02);
854 if (relay_splice(cre->dst) == -1)
855 goto fail;
856
857 return;
858 done:
859 relay_close(con, "last write (done)", 0);
860 return;
861 fail:
862 relay_close(con, strerror(errno(*__errno())), 1);
863}
864
865void
866relay_dump(struct ctl_relay_event *cre, const void *buf, size_t len)
867{
868 if (!len)
869 return;
870
871 /*
872 * This function will dump the specified message directly
873 * to the underlying session, without waiting for success
874 * of non-blocking events etc. This is useful to print an
875 * error message before gracefully closing the session.
876 */
877 if (cre->tls != NULL((void*)0))
878 (void)tls_write(cre->tls, buf, len);
879 else
880 (void)write(cre->s, buf, len);
881}
882
883void
884relay_read(struct bufferevent *bev, void *arg)
885{
886 struct ctl_relay_event *cre = arg;
887 struct rsession *con = cre->con;
888 struct protocol *proto = con->se_relay->rl_proto;
889 struct evbuffer *src = EVBUFFER_INPUT(bev)(bev)->input;
890
891 getmonotime(&con->se_tv_last);
892 cre->timedout = 0;
893
894 if (!EVBUFFER_LENGTH(src)(src)->off)
895 return;
896 if (relay_bufferevent_write_buffer(cre->dst, src) == -1)
897 goto fail;
898 if (con->se_done)
899 goto done;
900 if (cre->dst->bev)
901 bufferevent_enable(cre->dst->bev, EV_READ0x02);
902 if (cre->dst->bev && EVBUFFER_LENGTH(EVBUFFER_OUTPUT(cre->dst->bev))((cre->dst->bev)->output)->off >
903 (size_t)RELAY_MAX_PREFETCH256 * proto->tcpbufsiz)
904 bufferevent_disable(bev, EV_READ0x02);
905
906 return;
907 done:
908 relay_close(con, "last read (done)", 0);
909 return;
910 fail:
911 relay_close(con, strerror(errno(*__errno())), 1);
912}
913
914/*
915 * Splice sockets from cre to cre->dst if applicable. Returns:
916 * -1 socket splicing has failed
917 * 0 socket splicing is currently not possible
918 * 1 socket splicing was successful
919 */
920int
921relay_splice(struct ctl_relay_event *cre)
922{
923 struct rsession *con = cre->con;
924 struct relay *rlay = con->se_relay;
925 struct protocol *proto = rlay->rl_proto;
926 struct splice sp;
927
928 if ((rlay->rl_conf.flags & (F_TLS0x00000800|F_TLSCLIENT0x00200000)) ||
929 (proto->tcpflags & TCPFLAG_NSPLICE0x80))
930 return (0);
931
932 if (cre->splicelen >= 0)
933 return (0);
934
935 /* still not connected */
936 if (cre->bev == NULL((void*)0) || cre->dst->bev == NULL((void*)0))
937 return (0);
938
939 if (!(cre->toread == TOREAD_UNLIMITED || cre->toread > 0)) {
940 DPRINTF("%s: session %d: splice dir %d, nothing to read %lld",do {} while(0)
941 __func__, con->se_id, cre->dir, cre->toread)do {} while(0);
942 return (0);
943 }
944
945 /* do not splice before buffers have not been completely flushed */
946 if (EVBUFFER_LENGTH(cre->bev->input)(cre->bev->input)->off ||
947 EVBUFFER_LENGTH(cre->dst->bev->output)(cre->dst->bev->output)->off) {
948 DPRINTF("%s: session %d: splice dir %d, dirty buffer",do {} while(0)
949 __func__, con->se_id, cre->dir)do {} while(0);
950 bufferevent_disable(cre->bev, EV_READ0x02);
951 return (0);
952 }
953
954 bzero(&sp, sizeof(sp));
955 sp.sp_fd = cre->dst->s;
956 sp.sp_max = cre->toread > 0 ? cre->toread : 0;
957 bcopy(&rlay->rl_conf.timeout, &sp.sp_idle, sizeof(sp.sp_idle));
958 if (setsockopt(cre->s, SOL_SOCKET0xffff, SO_SPLICE0x1023, &sp, sizeof(sp)) == -1) {
959 log_debug("%s: session %d: splice dir %d failed: %s",
960 __func__, con->se_id, cre->dir, strerror(errno(*__errno())));
961 return (-1);
962 }
963 cre->splicelen = 0;
964 bufferevent_enable(cre->bev, EV_READ0x02);
965
966 DPRINTF("%s: session %d: splice dir %d, maximum %lld, successful",do {} while(0)
967 __func__, con->se_id, cre->dir, cre->toread)do {} while(0);
968
969 return (1);
970}
971
972int
973relay_splicelen(struct ctl_relay_event *cre)
974{
975 struct rsession *con = cre->con;
976 off_t len;
977 socklen_t optlen;
978
979 if (cre->splicelen < 0)
980 return (0);
981
982 optlen = sizeof(len);
983 if (getsockopt(cre->s, SOL_SOCKET0xffff, SO_SPLICE0x1023, &len, &optlen) == -1) {
984 log_debug("%s: session %d: splice dir %d get length failed: %s",
985 __func__, con->se_id, cre->dir, strerror(errno(*__errno())));
986 return (-1);
987 }
988
989 DPRINTF("%s: session %d: splice dir %d, length %lld",do {} while(0)
990 __func__, con->se_id, cre->dir, len)do {} while(0);
991
992 if (len > cre->splicelen) {
993 getmonotime(&con->se_tv_last);
994
995 cre->splicelen = len;
996 return (1);
997 }
998
999 return (0);
1000}
1001
1002int
1003relay_spliceadjust(struct ctl_relay_event *cre)
1004{
1005 if (cre->splicelen < 0)
1006 return (0);
1007 if (relay_splicelen(cre) == -1)
1008 return (-1);
1009 if (cre->splicelen > 0 && cre->toread > 0)
1010 cre->toread -= cre->splicelen;
1011 cre->splicelen = -1;
1012
1013 return (0);
1014}
1015
1016void
1017relay_error(struct bufferevent *bev, short error, void *arg)
1018{
1019 struct ctl_relay_event *cre = arg;
1020 struct rsession *con = cre->con;
1021 struct evbuffer *dst;
1022
1023 DPRINTF("%s: session %d: dir %d state %d to read %lld event error %x",do {} while(0)
1024 __func__, con->se_id, cre->dir, cre->state, cre->toread, error)do {} while(0);
1025 if (error & EVBUFFER_TIMEOUT0x40) {
1026 if (cre->splicelen >= 0) {
1027 bufferevent_enable(bev, EV_READ0x02);
1028 } else if (cre->dst->splicelen >= 0) {
1029 switch (relay_splicelen(cre->dst)) {
1030 case -1:
1031 goto fail;
1032 case 0:
1033 relay_close(con, "buffer event timeout", 1);
1034 break;
1035 case 1:
1036 cre->timedout = 1;
1037 bufferevent_enable(bev, EV_READ0x02);
1038 break;
1039 }
1040 } else {
1041 relay_close(con, "buffer event timeout", 1);
1042 }
1043 return;
1044 }
1045 if (error & EVBUFFER_ERROR0x20 && errno(*__errno()) == ETIMEDOUT60) {
1046 if (cre->dst->splicelen >= 0) {
1047 switch (relay_splicelen(cre->dst)) {
1048 case -1:
1049 goto fail;
1050 case 0:
1051 relay_close(con, "splice timeout", 1);
1052 return;
1053 case 1:
1054 bufferevent_enable(bev, EV_READ0x02);
1055 break;
1056 }
1057 } else if (cre->dst->timedout) {
1058 relay_close(con, "splice timeout", 1);
1059 return;
1060 }
1061 if (relay_spliceadjust(cre) == -1)
1062 goto fail;
1063 if (relay_splice(cre) == -1)
1064 goto fail;
1065 return;
1066 }
1067 if (error & EVBUFFER_ERROR0x20 && errno(*__errno()) == EFBIG27) {
1068 if (relay_spliceadjust(cre) == -1)
1069 goto fail;
1070 bufferevent_enable(cre->bev, EV_READ0x02);
1071 return;
1072 }
1073 if (error & (EVBUFFER_READ0x01|EVBUFFER_WRITE0x02|EVBUFFER_EOF0x10)) {
1074 bufferevent_disable(bev, EV_READ0x02|EV_WRITE0x04);
1075
1076 con->se_done = 1;
1077 if (cre->dst->bev != NULL((void*)0)) {
1078 dst = EVBUFFER_OUTPUT(cre->dst->bev)(cre->dst->bev)->output;
1079 if (EVBUFFER_LENGTH(dst)(dst)->off)
1080 return;
1081 } else if (cre->toread == TOREAD_UNLIMITED || cre->toread == 0)
1082 return;
1083
1084 relay_close(con, "done", 0);
1085 return;
1086 }
1087 relay_close(con, "buffer event error", 1);
1088 return;
1089 fail:
1090 relay_close(con, strerror(errno(*__errno())), 1);
1091}
1092
1093void
1094relay_accept(int fd, short event, void *arg)
1095{
1096 struct privsep *ps = env->sc_ps;
1097 struct relay *rlay = arg;
1098 struct rsession *con = NULL((void*)0);
1099 struct ctl_natlook *cnl = NULL((void*)0);
1100 socklen_t slen;
1101 struct timeval tv;
1102 struct sockaddr_storage ss;
1103 int s = -1;
1104
1105 event_add(&rlay->rl_ev, NULL((void*)0));
1106 if ((event & EV_TIMEOUT0x01))
1107 return;
1108
1109 slen = sizeof(ss);
1110 if ((s = accept_reserve(fd, (struct sockaddr *)&ss,
1111 &slen, FD_RESERVE5, &relay_inflight)) == -1) {
1112 /*
1113 * Pause accept if we are out of file descriptors, or
1114 * libevent will haunt us here too.
1115 */
1116 if (errno(*__errno()) == ENFILE23 || errno(*__errno()) == EMFILE24) {
1117 struct timeval evtpause = { 1, 0 };
1118
1119 event_del(&rlay->rl_ev);
1120 evtimer_add(&rlay->rl_evt, &evtpause)event_add(&rlay->rl_evt, &evtpause);
1121 log_debug("%s: deferring connections", __func__);
1122 }
1123 return;
1124 }
1125 if (rlay->rl_conf.flags & F_DISABLE0x00000001)
1126 goto err;
1127
1128 if ((con = calloc(1, sizeof(*con))) == NULL((void*)0))
1129 goto err;
1130
1131 /* Pre-allocate log buffer */
1132 con->se_haslog = 0;
1133 con->se_log = evbuffer_new();
1134 if (con->se_log == NULL((void*)0))
1135 goto err;
1136
1137 con->se_in.s = s;
1138 con->se_in.tls = NULL((void*)0);
1139 con->se_out.s = -1;
1140 con->se_out.tls = NULL((void*)0);
1141 con->se_in.dst = &con->se_out;
1142 con->se_out.dst = &con->se_in;
1143 con->se_in.con = con;
1144 con->se_out.con = con;
1145 con->se_in.splicelen = -1;
1146 con->se_out.splicelen = -1;
1147 con->se_in.toread = TOREAD_UNLIMITED;
1148 con->se_out.toread = TOREAD_UNLIMITED;
1149 con->se_relay = rlay;
1150 con->se_id = ++relay_conid;
1151 con->se_relayid = rlay->rl_conf.id;
1152 con->se_pid = getpid();
1153 con->se_in.dir = RELAY_DIR_REQUEST;
1154 con->se_out.dir = RELAY_DIR_RESPONSE;
1155 con->se_retry = rlay->rl_conf.dstretry;
1156 con->se_bnds = -1;
1157 con->se_out.port = rlay->rl_conf.dstport;
1158 switch (ss.ss_family) {
1159 case AF_INET2:
1160 con->se_in.port = ((struct sockaddr_in *)&ss)->sin_port;
1161 break;
1162 case AF_INET624:
1163 con->se_in.port = ((struct sockaddr_in6 *)&ss)->sin6_port;
1164 break;
1165 }
1166 memcpy(&con->se_in.ss, &ss, sizeof(con->se_in.ss));
1167
1168 slen = sizeof(con->se_sockname);
1169 if (getsockname(s, (struct sockaddr *)&con->se_sockname, &slen) == -1) {
1170 relay_close(con, "sockname lookup failed", 1);
1171 return;
1172 }
1173
1174 getmonotime(&con->se_tv_start);
1175 bcopy(&con->se_tv_start, &con->se_tv_last, sizeof(con->se_tv_last));
1176
1177 if (rlay->rl_conf.flags & F_HASHKEY0x08000000) {
1178 SipHash24_Init(&con->se_siphashctx,SipHash_Init((&con->se_siphashctx), (&rlay->rl_conf
.hashkey.siphashkey))
1179 &rlay->rl_conf.hashkey.siphashkey)SipHash_Init((&con->se_siphashctx), (&rlay->rl_conf
.hashkey.siphashkey))
;
1180 }
1181
1182 relay_sessions++;
1183 SPLAY_INSERT(session_tree, &rlay->rl_sessions, con)session_tree_SPLAY_INSERT(&rlay->rl_sessions, con);
1184 relay_session_publish(con);
1185
1186 /* Increment the per-relay session counter */
1187 rlay->rl_stats[ps->ps_instance].last++;
1188
1189 /* Pre-allocate output buffer */
1190 con->se_out.output = evbuffer_new();
1191 if (con->se_out.output == NULL((void*)0)) {
1192 relay_close(con, "failed to allocate output buffer", 1);
1193 return;
1194 }
1195
1196 if (rlay->rl_conf.flags & F_DIVERT0x01000000) {
1197 memcpy(&con->se_out.ss, &con->se_sockname,
1198 sizeof(con->se_out.ss));
1199 con->se_out.port = relay_socket_getport(&con->se_out.ss);
1200
1201 /* Detect loop and fall back to the alternate forward target */
1202 if (bcmp(&rlay->rl_conf.ss, &con->se_out.ss,
1203 sizeof(con->se_out.ss)) == 0 &&
1204 con->se_out.port == rlay->rl_conf.port)
1205 con->se_out.ss.ss_family = AF_UNSPEC0;
1206 } else if (rlay->rl_conf.flags & F_NATLOOK0x00001000) {
1207 if ((cnl = calloc(1, sizeof(*cnl))) == NULL((void*)0)) {
1208 relay_close(con, "failed to allocate nat lookup", 1);
1209 return;
1210 }
1211
1212 con->se_cnl = cnl;
1213 bzero(cnl, sizeof(*cnl));
1214 cnl->in = -1;
1215 cnl->id = con->se_id;
1216 cnl->proc = ps->ps_instance;
1217 cnl->proto = IPPROTO_TCP6;
1218
1219 memcpy(&cnl->src, &con->se_in.ss, sizeof(cnl->src));
1220 memcpy(&cnl->dst, &con->se_sockname, sizeof(cnl->dst));
1221
1222 proc_compose(env->sc_ps, PROC_PFE, IMSG_NATLOOK,
1223 cnl, sizeof(*cnl));
1224
1225 /* Schedule timeout */
1226 evtimer_set(&con->se_ev, relay_natlook, con)event_set(&con->se_ev, -1, 0, relay_natlook, con);
1227 bcopy(&rlay->rl_conf.timeout, &tv, sizeof(tv));
1228 evtimer_add(&con->se_ev, &tv)event_add(&con->se_ev, &tv);
1229 return;
1230 }
1231
1232 if (rlay->rl_conf.flags & F_TLSINSPECT0x04000000) {
1233 relay_preconnect(con);
1234 return;
1235 }
1236
1237 relay_session(con);
1238 return;
1239 err:
1240 if (s != -1) {
1241 close(s);
1242 free(con);
1243 /*
1244 * the session struct was not completely set up, but still
1245 * counted as an inflight session. account for this.
1246 */
1247 relay_inflight--;
1248 log_debug("%s: inflight decremented, now %d",
1249 __func__, relay_inflight);
1250 }
1251}
1252
1253void
1254relay_hash_addr(SIPHASH_CTX *ctx, struct sockaddr_storage *ss, int portset)
1255{
1256 struct sockaddr_in *sin4;
1257 struct sockaddr_in6 *sin6;
1258 in_port_t port;
1259
1260 if (ss->ss_family == AF_INET2) {
1261 sin4 = (struct sockaddr_in *)ss;
1262 SipHash24_Update(ctx, &sin4->sin_addr,SipHash_Update((ctx), 2, 4, (&sin4->sin_addr), (sizeof
(struct in_addr)))
1263 sizeof(struct in_addr))SipHash_Update((ctx), 2, 4, (&sin4->sin_addr), (sizeof
(struct in_addr)))
;
1264 } else {
1265 sin6 = (struct sockaddr_in6 *)ss;
1266 SipHash24_Update(ctx, &sin6->sin6_addr,SipHash_Update((ctx), 2, 4, (&sin6->sin6_addr), (sizeof
(struct in6_addr)))
1267 sizeof(struct in6_addr))SipHash_Update((ctx), 2, 4, (&sin6->sin6_addr), (sizeof
(struct in6_addr)))
;
1268 }
1269
1270 if (portset != -1) {
1271 port = (in_port_t)portset;
1272 SipHash24_Update(ctx, &port, sizeof(port))SipHash_Update((ctx), 2, 4, (&port), (sizeof(port)));
1273 }
1274}
1275
1276int
1277relay_from_table(struct rsession *con)
1278{
1279 struct relay *rlay = con->se_relay;
1280 struct host *host = NULL((void*)0);
1281 struct relay_table *rlt = NULL((void*)0);
1282 struct table *table = NULL((void*)0);
1283 int idx = -1;
1284 int cnt = 0;
1285 int maxtries;
1286 u_int64_t p = 0;
1287
1288 /* the table is already selected */
1289 if (con->se_table != NULL((void*)0)) {
1290 rlt = con->se_table;
1291 table = rlt->rlt_table;
1292 if (table->conf.check && !table->up)
1293 table = NULL((void*)0);
1294 goto gottable;
1295 }
1296
1297 /* otherwise grep the first active table */
1298 TAILQ_FOREACH(rlt, &rlay->rl_tables, rlt_entry)for((rlt) = ((&rlay->rl_tables)->tqh_first); (rlt) !=
((void*)0); (rlt) = ((rlt)->rlt_entry.tqe_next))
{
1299 table = rlt->rlt_table;
1300 if ((rlt->rlt_flags & F_USED0x00000004) == 0 ||
1301 (table->conf.check && !table->up))
1302 table = NULL((void*)0);
1303 else
1304 break;
1305 }
1306
1307 gottable:
1308 if (table == NULL((void*)0)) {
1309 log_debug("%s: session %d: no active hosts",
1310 __func__, con->se_id);
1311 return (-1);
1312 }
1313
1314 switch (rlt->rlt_mode) {
1315 case RELAY_DSTMODE_ROUNDROBIN:
1316 if ((int)rlt->rlt_index >= rlt->rlt_nhosts)
1317 rlt->rlt_index = 0;
1318 idx = (int)rlt->rlt_index;
1319 break;
1320 case RELAY_DSTMODE_RANDOM:
1321 idx = (int)arc4random_uniform(rlt->rlt_nhosts);
1322 break;
1323 case RELAY_DSTMODE_SRCHASH:
1324 /* Source IP address without port */
1325 relay_hash_addr(&con->se_siphashctx, &con->se_in.ss, -1);
1326 break;
1327 case RELAY_DSTMODE_LOADBALANCE:
1328 /* Source IP address without port */
1329 relay_hash_addr(&con->se_siphashctx, &con->se_in.ss, -1);
1330 /* FALLTHROUGH */
1331 case RELAY_DSTMODE_HASH:
1332 /* Local "destination" IP address and port */
1333 relay_hash_addr(&con->se_siphashctx, &rlay->rl_conf.ss,
1334 rlay->rl_conf.port);
1335 break;
1336 default:
1337 fatalx("%s: unsupported mode", __func__);
1338 /* NOTREACHED */
1339 }
1340 if (idx == -1) {
1341 /* handle all hashing algorithms */
1342 p = SipHash24_End(&con->se_siphashctx)SipHash_End((&con->se_siphashctx), 2, 4);
1343
1344 /* Reset hash context */
1345 SipHash24_Init(&con->se_siphashctx,SipHash_Init((&con->se_siphashctx), (&rlay->rl_conf
.hashkey.siphashkey))
1346 &rlay->rl_conf.hashkey.siphashkey)SipHash_Init((&con->se_siphashctx), (&rlay->rl_conf
.hashkey.siphashkey))
;
1347
1348 maxtries = (rlt->rlt_nhosts < RELAY_MAX_HASH_RETRIES5 ?
1349 rlt->rlt_nhosts : RELAY_MAX_HASH_RETRIES5);
1350 for (cnt = 0; cnt < maxtries; cnt++) {
1351 if ((idx = p % rlt->rlt_nhosts) >= RELAY_MAXHOSTS32)
1352 return (-1);
1353
1354 host = rlt->rlt_host[idx];
1355
1356 DPRINTF("%s: session %d: table %s host %s, "do {} while(0)
1357 "p 0x%016llx, idx %d, cnt %d, max %d",do {} while(0)
1358 __func__, con->se_id, table->conf.name,do {} while(0)
1359 host->conf.name, p, idx, cnt, maxtries)do {} while(0);
1360
1361 if (!table->conf.check || host->up == HOST_UP)
1362 goto found;
1363 p = p >> 1;
1364 }
1365 } else {
1366 /* handle all non-hashing algorithms */
1367 host = rlt->rlt_host[idx];
1368 DPRINTF("%s: session %d: table %s host %s, p 0x%016llx, idx %d",do {} while(0)
1369 __func__, con->se_id, table->conf.name, host->conf.name,do {} while(0)
1370 p, idx)do {} while(0);
1371 }
1372
1373 while (host != NULL((void*)0)) {
1374 DPRINTF("%s: session %d: host %s", __func__,do {} while(0)
1375 con->se_id, host->conf.name)do {} while(0);
1376 if (!table->conf.check || host->up == HOST_UP)
1377 goto found;
1378 host = TAILQ_NEXT(host, entry)((host)->entry.tqe_next);
1379 }
1380 TAILQ_FOREACH(host, &table->hosts, entry)for((host) = ((&table->hosts)->tqh_first); (host) !=
((void*)0); (host) = ((host)->entry.tqe_next))
{
1381 DPRINTF("%s: session %d: next host %s",do {} while(0)
1382 __func__, con->se_id, host->conf.name)do {} while(0);
1383 if (!table->conf.check || host->up == HOST_UP)
1384 goto found;
1385 }
1386
1387 /* Should not happen */
1388 fatalx("%s: no active hosts, desynchronized", __func__);
1389
1390 found:
1391 if (rlt->rlt_mode == RELAY_DSTMODE_ROUNDROBIN)
1392 rlt->rlt_index = host->idx + 1;
1393 con->se_retry = host->conf.retry;
1394 con->se_out.port = table->conf.port;
1395 bcopy(&host->conf.ss, &con->se_out.ss, sizeof(con->se_out.ss));
1396
1397 return (0);
1398}
1399
1400void
1401relay_natlook(int fd, short event, void *arg)
1402{
1403 struct rsession *con = arg;
1404 struct relay *rlay = con->se_relay;
1405 struct ctl_natlook *cnl = con->se_cnl;
1406
1407 if (cnl == NULL((void*)0))
1408 fatalx("invalid NAT lookup");
1409
1410 if (con->se_out.ss.ss_family == AF_UNSPEC0 && cnl->in == -1 &&
1411 rlay->rl_conf.dstss.ss_family == AF_UNSPEC0 &&
1412 TAILQ_EMPTY(&rlay->rl_tables)(((&rlay->rl_tables)->tqh_first) == ((void*)0))) {
1413 relay_close(con, "session NAT lookup failed", 1);
1414 return;
1415 }
1416 if (cnl->in != -1) {
1417 bcopy(&cnl->rdst, &con->se_out.ss, sizeof(con->se_out.ss));
1418 con->se_out.port = cnl->rdport;
1419 }
1420 free(con->se_cnl);
1421 con->se_cnl = NULL((void*)0);
1422
1423 relay_session(con);
1424}
1425
1426void
1427relay_session(struct rsession *con)
1428{
1429 struct relay *rlay = con->se_relay;
1430 struct ctl_relay_event *in = &con->se_in, *out = &con->se_out;
1431
1432 if (bcmp(&rlay->rl_conf.ss, &out->ss, sizeof(out->ss)) == 0 &&
9
Assuming the condition is false
1433 out->port == rlay->rl_conf.port) {
1434 log_debug("%s: session %d: looping", __func__, con->se_id);
1435 relay_close(con, "session aborted", 1);
1436 return;
1437 }
1438
1439 if (rlay->rl_conf.flags & F_UDP0x00010000) {
10
Assuming the condition is false
11
Taking false branch
1440 /*
1441 * Call the UDP protocol-specific handler
1442 */
1443 if (rlay->rl_proto->request == NULL((void*)0))
1444 fatalx("invalide UDP session");
1445 if ((*rlay->rl_proto->request)(con) == -1)
1446 relay_close(con, "session failed", 1);
1447 return;
1448 }
1449
1450 if ((rlay->rl_conf.flags & F_TLS0x00000800) && (in->tls == NULL((void*)0))) {
12
Assuming the condition is false
1451 relay_tls_transaction(con, in);
1452 return;
1453 }
1454
1455 if (rlay->rl_proto->type != RELAY_PROTO_HTTP) {
13
Assuming field 'type' is not equal to RELAY_PROTO_HTTP
14
Taking true branch
1456 if (rlay->rl_conf.fwdmode == FWD_TRANS)
15
Assuming field 'fwdmode' is not equal to FWD_TRANS
16
Taking false branch
1457 relay_bindanyreq(con, 0, IPPROTO_TCP6);
1458 else if (relay_connect(con) == -1) {
17
Calling 'relay_connect'
1459 relay_close(con, "session failed", 1);
1460 return;
1461 }
1462 }
1463
1464 relay_input(con);
1465}
1466
1467void
1468relay_bindanyreq(struct rsession *con, in_port_t port, int proto)
1469{
1470 struct privsep *ps = env->sc_ps;
1471 struct relay *rlay = con->se_relay;
1472 struct ctl_bindany bnd;
1473 struct timeval tv;
1474
1475 bzero(&bnd, sizeof(bnd));
1476 bnd.bnd_id = con->se_id;
1477 bnd.bnd_proc = ps->ps_instance;
1478 bnd.bnd_port = port;
1479 bnd.bnd_proto = proto;
1480 bcopy(&con->se_in.ss, &bnd.bnd_ss, sizeof(bnd.bnd_ss));
1481 proc_compose(env->sc_ps, PROC_PARENT, IMSG_BINDANY,
1482 &bnd, sizeof(bnd));
1483
1484 /* Schedule timeout */
1485 evtimer_set(&con->se_ev, relay_bindany, con)event_set(&con->se_ev, -1, 0, relay_bindany, con);
1486 bcopy(&rlay->rl_conf.timeout, &tv, sizeof(tv));
1487 evtimer_add(&con->se_ev, &tv)event_add(&con->se_ev, &tv);
1488}
1489
1490void
1491relay_bindany(int fd, short event, void *arg)
1492{
1493 struct rsession *con = arg;
1494
1495 if (con->se_bnds == -1) {
1496 relay_close(con, "bindany failed, invalid socket", 1);
1497 return;
1498 }
1499 if (relay_connect(con) == -1)
1500 relay_close(con, "session failed", 1);
1501}
1502
1503void
1504relay_connect_state(struct rsession *con, struct ctl_relay_event *cre,
1505 enum relay_state new)
1506{
1507 DPRINTF("%s: session %d: %s state %s -> %s",do {} while(0)
1508 __func__, con->se_id,do {} while(0)
1509 cre->dir == RELAY_DIR_REQUEST ? "accept" : "connect",do {} while(0)
1510 relay_state(cre->state), relay_state(new))do {} while(0);
1511 cre->state = new;
1512}
1513
1514void
1515relay_connect_retry(int fd, short sig, void *arg)
1516{
1517 struct timeval evtpause = { 1, 0 };
1518 struct rsession *con = arg;
1519 struct relay *rlay = con->se_relay;
1520 int bnds = -1;
1521
1522 if (relay_inflight < 1) {
1523 log_warnx("%s: no connection in flight", __func__);
1524 relay_inflight = 1;
1525 }
1526
1527 DPRINTF("%s: retry %d of %d, inflight: %d",__func__,do {} while(0)
1528 con->se_retrycount, con->se_retry, relay_inflight)do {} while(0);
1529
1530 if (sig != EV_TIMEOUT0x01)
1531 fatalx("%s: called without timeout", __func__);
1532
1533 evtimer_del(&con->se_inflightevt)event_del(&con->se_inflightevt);
1534
1535 /*
1536 * XXX we might want to check if the inbound socket is still
1537 * available: client could have closed it while we were waiting?
1538 */
1539
1540 DPRINTF("%s: got EV_TIMEOUT", __func__)do {} while(0);
1541
1542 if (getdtablecount() + FD_RESERVE5 +
1543 relay_inflight > getdtablesize()) {
1544 if (con->se_retrycount < RELAY_OUTOF_FD_RETRIES5) {
1545 evtimer_add(&con->se_inflightevt, &evtpause)event_add(&con->se_inflightevt, &evtpause);
1546 return;
1547 }
1548 /* we waited for RELAY_OUTOF_FD_RETRIES seconds, give up */
1549 event_add(&rlay->rl_ev, NULL((void*)0));
1550 relay_abort_http(con, 504, "connection timed out", 0);
1551 return;
1552 }
1553
1554 if (rlay->rl_conf.fwdmode == FWD_TRANS) {
1555 /* con->se_bnds cannot be unset */
1556 bnds = con->se_bnds;
1557 }
1558
1559 retry:
1560 if ((con->se_out.s = relay_socket_connect(&con->se_out.ss,
1561 con->se_out.port, rlay->rl_proto, bnds)) == -1) {
1562 log_debug("%s: session %d: "
1563 "forward failed: %s, %s", __func__,
1564 con->se_id, strerror(errno(*__errno())),
1565 con->se_retry ? "next retry" : "last retry");
1566
1567 con->se_retrycount++;
1568
1569 if ((errno(*__errno()) == ENFILE23 || errno(*__errno()) == EMFILE24) &&
1570 (con->se_retrycount < con->se_retry)) {
1571 event_del(&rlay->rl_ev);
1572 evtimer_add(&con->se_inflightevt, &evtpause)event_add(&con->se_inflightevt, &evtpause);
1573 evtimer_add(&rlay->rl_evt, &evtpause)event_add(&rlay->rl_evt, &evtpause);
1574 return;
1575 } else if (con->se_retrycount < con->se_retry)
1576 goto retry;
1577 event_add(&rlay->rl_ev, NULL((void*)0));
1578 relay_abort_http(con, 504, "connect failed", 0);
1579 return;
1580 }
1581
1582 if (rlay->rl_conf.flags & F_TLSINSPECT0x04000000)
1583 relay_connect_state(con, &con->se_out, STATE_PRECONNECT);
1584 else
1585 relay_connect_state(con, &con->se_out, STATE_CONNECTED);
1586 relay_inflight--;
1587 DPRINTF("%s: inflight decremented, now %d",__func__, relay_inflight)do {} while(0);
1588
1589 event_add(&rlay->rl_ev, NULL((void*)0));
1590
1591 if (errno(*__errno()) == EINPROGRESS36)
1592 event_again(&con->se_ev, con->se_out.s, EV_WRITE0x04|EV_TIMEOUT0x01,
1593 relay_connected, &con->se_tv_start, &rlay->rl_conf.timeout,
1594 con);
1595 else
1596 relay_connected(con->se_out.s, EV_WRITE0x04, con);
1597
1598 return;
1599}
1600
1601int
1602relay_preconnect(struct rsession *con)
1603{
1604 int rv;
1605
1606 log_debug("%s: session %d: process %d", __func__,
1607 con->se_id, privsep_process);
1608 rv = relay_connect(con);
1609 if (con->se_out.state == STATE_CONNECTED)
1610 relay_connect_state(con, &con->se_out, STATE_PRECONNECT);
1611 return (rv);
1612}
1613
1614int
1615relay_connect(struct rsession *con)
1616{
1617 struct relay *rlay = con->se_relay;
1618 struct timeval evtpause = { 1, 0 };
1619 int bnds = -1, ret;
1620
1621 /* relay_connect should only be called once per relay */
1622 if (con->se_out.state == STATE_CONNECTED) {
18
Assuming field 'state' is not equal to STATE_CONNECTED
19
Taking false branch
1623 log_debug("%s: connect already called once", __func__);
1624 return (0);
1625 }
1626
1627 /* Connection is already established but session not active */
1628 if ((rlay->rl_conf.flags & F_TLSINSPECT0x04000000) &&
20
Assuming the condition is true
22
Taking true branch
1629 con->se_out.state == STATE_PRECONNECT) {
21
Assuming field 'state' is equal to STATE_PRECONNECT
1630 if (con->se_out.tls == NULL((void*)0)) {
23
Assuming field 'tls' is not equal to NULL
24
Taking false branch
1631 log_debug("%s: tls connect failed", __func__);
1632 return (-1);
1633 }
1634 relay_connected(con->se_out.s, EV_WRITE0x04, con);
25
Calling 'relay_connected'
55
Returning; memory was released via 3rd parameter
1635 relay_connect_state(con, &con->se_out, STATE_CONNECTED);
56
Use of memory after it is freed
1636 return (0);
1637 }
1638
1639 if (relay_inflight < 1) {
1640 log_warnx("relay_connect: no connection in flight");
1641 relay_inflight = 1;
1642 }
1643
1644 getmonotime(&con->se_tv_start);
1645
1646 if (con->se_out.ss.ss_family == AF_UNSPEC0 &&
1647 !TAILQ_EMPTY(&rlay->rl_tables)(((&rlay->rl_tables)->tqh_first) == ((void*)0))) {
1648 if (relay_from_table(con) != 0)
1649 return (-1);
1650 } else if (con->se_out.ss.ss_family == AF_UNSPEC0) {
1651 bcopy(&rlay->rl_conf.dstss, &con->se_out.ss,
1652 sizeof(con->se_out.ss));
1653 con->se_out.port = rlay->rl_conf.dstport;
1654 }
1655
1656 if (rlay->rl_conf.fwdmode == FWD_TRANS) {
1657 if (con->se_bnds == -1) {
1658 log_debug("%s: could not bind any sock", __func__);
1659 return (-1);
1660 }
1661 bnds = con->se_bnds;
1662 }
1663
1664 /* Do the IPv4-to-IPv6 or IPv6-to-IPv4 translation if requested */
1665 if (rlay->rl_conf.dstaf.ss_family != AF_UNSPEC0) {
1666 if (con->se_out.ss.ss_family == AF_INET2 &&
1667 rlay->rl_conf.dstaf.ss_family == AF_INET624)
1668 ret = map4to6(&con->se_out.ss, &rlay->rl_conf.dstaf);
1669 else if (con->se_out.ss.ss_family == AF_INET624 &&
1670 rlay->rl_conf.dstaf.ss_family == AF_INET2)
1671 ret = map6to4(&con->se_out.ss);
1672 else
1673 ret = 0;
1674 if (ret != 0) {
1675 log_debug("%s: mapped to invalid address", __func__);
1676 return (-1);
1677 }
1678 }
1679
1680 retry:
1681 if ((con->se_out.s = relay_socket_connect(&con->se_out.ss,
1682 con->se_out.port, rlay->rl_proto, bnds)) == -1) {
1683 if (errno(*__errno()) == ENFILE23 || errno(*__errno()) == EMFILE24) {
1684 log_debug("%s: session %d: forward failed: %s",
1685 __func__, con->se_id, strerror(errno(*__errno())));
1686 evtimer_set(&con->se_inflightevt, relay_connect_retry,event_set(&con->se_inflightevt, -1, 0, relay_connect_retry
, con)
1687 con)event_set(&con->se_inflightevt, -1, 0, relay_connect_retry
, con)
;
1688 event_del(&rlay->rl_ev);
1689 evtimer_add(&con->se_inflightevt, &evtpause)event_add(&con->se_inflightevt, &evtpause);
1690 evtimer_add(&rlay->rl_evt, &evtpause)event_add(&rlay->rl_evt, &evtpause);
1691
1692 /* this connect is pending */
1693 relay_connect_state(con, &con->se_out, STATE_PENDING);
1694 return (0);
1695 } else {
1696 if (con->se_retry) {
1697 con->se_retry--;
1698 log_debug("%s: session %d: "
1699 "forward failed: %s, %s", __func__,
1700 con->se_id, strerror(errno(*__errno())),
1701 con->se_retry ?
1702 "next retry" : "last retry");
1703 goto retry;
1704 }
1705 log_debug("%s: session %d: forward failed: %s",
1706 __func__, con->se_id, strerror(errno(*__errno())));
1707 return (-1);
1708 }
1709 }
1710
1711 relay_connect_state(con, &con->se_out, STATE_CONNECTED);
1712 relay_inflight--;
1713 DPRINTF("%s: inflight decremented, now %d",__func__,do {} while(0)
1714 relay_inflight)do {} while(0);
1715
1716 if (errno(*__errno()) == EINPROGRESS36)
1717 event_again(&con->se_ev, con->se_out.s, EV_WRITE0x04|EV_TIMEOUT0x01,
1718 relay_connected, &con->se_tv_start, &rlay->rl_conf.timeout,
1719 con);
1720 else
1721 relay_connected(con->se_out.s, EV_WRITE0x04, con);
1722
1723 return (0);
1724}
1725
1726void
1727relay_close(struct rsession *con, const char *msg, int err)
1728{
1729 char ibuf[128], obuf[128], *ptr = NULL((void*)0);
1730 struct relay *rlay = con->se_relay;
1731 struct protocol *proto = rlay->rl_proto;
1732
1733 SPLAY_REMOVE(session_tree, &rlay->rl_sessions, con)session_tree_SPLAY_REMOVE(&rlay->rl_sessions, con);
1734 relay_session_unpublish(con);
1735
1736 event_del(&con->se_ev);
1737
1738 if ((env->sc_conf.opts & (RELAYD_OPT_LOGCON0x20|RELAYD_OPT_LOGCONERR0x40)) &&
38
Assuming the condition is false
1739 msg != NULL((void*)0)) {
1740 bzero(&ibuf, sizeof(ibuf));
1741 bzero(&obuf, sizeof(obuf));
1742 (void)print_host(&con->se_in.ss, ibuf, sizeof(ibuf));
1743 (void)print_host(&con->se_out.ss, obuf, sizeof(obuf));
1744 if (EVBUFFER_LENGTH(con->se_log)(con->se_log)->off &&
1745 evbuffer_add_printf(con->se_log, "\r\n") != -1) {
1746 ptr = evbuffer_readln(con->se_log, NULL((void*)0),
1747 EVBUFFER_EOL_CRLF);
1748 }
1749 if (err == 0 && (env->sc_conf.opts & RELAYD_OPT_LOGCON0x20))
1750 log_info("relay %s, "
1751 "session %d (%d active), %s, %s -> %s:%d, "
1752 "%s%s%s", rlay->rl_conf.name, con->se_id,
1753 relay_sessions, con->se_tag != 0 ?
1754 tag_id2name(con->se_tag) : "0", ibuf, obuf,
1755 ntohs(con->se_out.port)(__uint16_t)(__builtin_constant_p(con->se_out.port) ? (__uint16_t
)(((__uint16_t)(con->se_out.port) & 0xffU) << 8 |
((__uint16_t)(con->se_out.port) & 0xff00U) >> 8
) : __swap16md(con->se_out.port))
, msg, ptr == NULL((void*)0) ?
1756 "" : ",", ptr == NULL((void*)0) ? "" : ptr);
1757 if (err == 1 && (env->sc_conf.opts & RELAYD_OPT_LOGCONERR0x40))
1758 log_warn("relay %s, "
1759 "session %d (%d active), %s, %s -> %s:%d, "
1760 "%s%s%s", rlay->rl_conf.name, con->se_id,
1761 relay_sessions, con->se_tag != 0 ?
1762 tag_id2name(con->se_tag) : "0", ibuf, obuf,
1763 ntohs(con->se_out.port)(__uint16_t)(__builtin_constant_p(con->se_out.port) ? (__uint16_t
)(((__uint16_t)(con->se_out.port) & 0xffU) << 8 |
((__uint16_t)(con->se_out.port) & 0xff00U) >> 8
) : __swap16md(con->se_out.port))
, msg, ptr == NULL((void*)0) ?
1764 "" : ",", ptr == NULL((void*)0) ? "" : ptr);
1765 free(ptr);
1766 }
1767
1768 if (proto->close != NULL((void*)0))
39
Assuming field 'close' is equal to NULL
40
Taking false branch
1769 (*proto->close)(con);
1770
1771 free(con->se_priv);
1772
1773 relay_connect_state(con, &con->se_in, STATE_DONE);
1774 if (relay_reset_event(con, &con->se_in)) {
41
Assuming the condition is false
42
Taking false branch
1775 if (con->se_out.s == -1) {
1776 /*
1777 * the output was never connected,
1778 * thus this was an inflight session.
1779 */
1780 relay_inflight--;
1781 log_debug("%s: sessions inflight decremented, now %d",
1782 __func__, relay_inflight);
1783 }
1784 }
1785 if (con->se_in.output != NULL((void*)0))
43
Assuming field 'output' is equal to NULL
44
Taking false branch
1786 evbuffer_free(con->se_in.output);
1787
1788 relay_connect_state(con, &con->se_out, STATE_DONE);
1789 if (relay_reset_event(con, &con->se_out)) {
45
Assuming the condition is false
46
Taking false branch
1790 /* Some file descriptors are available again. */
1791 if (evtimer_pending(&rlay->rl_evt, NULL)event_pending(&rlay->rl_evt, 0x01, ((void*)0))) {
1792 evtimer_del(&rlay->rl_evt)event_del(&rlay->rl_evt);
1793 event_add(&rlay->rl_ev, NULL((void*)0));
1794 }
1795 }
1796 if (con->se_out.output != NULL((void*)0))
47
Assuming field 'output' is equal to NULL
48
Taking false branch
1797 evbuffer_free(con->se_out.output);
1798
1799 if (con->se_log != NULL((void*)0))
49
Assuming field 'se_log' is equal to NULL
50
Taking false branch
1800 evbuffer_free(con->se_log);
1801
1802 if (con->se_cnl != NULL((void*)0)) {
51
Assuming field 'se_cnl' is equal to NULL
52
Taking false branch
1803#if 0
1804 proc_compose_imsg(env->sc_ps, PROC_PFE, -1, IMSG_KILLSTATES, -1,
1805 cnl, sizeof(*cnl));
1806#endif
1807 free(con->se_cnl);
1808 }
1809
1810 free(con);
53
Memory is released
1811 relay_sessions--;
1812}
1813
1814int
1815relay_reset_event(struct rsession *con, struct ctl_relay_event *cre)
1816{
1817 int rv = 0;
1818
1819 if (cre->state != STATE_DONE)
1820 relay_connect_state(con, cre, STATE_CLOSED);
1821 if (cre->bev != NULL((void*)0)) {
1822 bufferevent_disable(cre->bev, EV_READ0x02|EV_WRITE0x04);
1823 bufferevent_free(cre->bev);
1824 }
1825 if (cre->tls != NULL((void*)0))
1826 tls_close(cre->tls);
1827 tls_free(cre->tls);
1828 tls_free(cre->tls_ctx);
1829 tls_config_free(cre->tls_cfg);
1830 free(cre->tlscert);
1831 if (cre->s != -1) {
1832 close(cre->s);
1833 rv = 1;
1834 }
1835 cre->bev = NULL((void*)0);
1836 cre->tls = NULL((void*)0);
1837 cre->tls_cfg = NULL((void*)0);
1838 cre->tlscert = NULL((void*)0);
1839 cre->s = -1;
1840
1841 return (rv);
1842}
1843
1844int
1845relay_dispatch_pfe(int fd, struct privsep_proc *p, struct imsg *imsg)
1846{
1847 struct relay *rlay;
1848 struct rsession *con, se;
1849 struct ctl_natlook cnl;
1850 struct timeval tv;
1851 struct host *host;
1852 struct table *table;
1853 struct ctl_status st;
1854 objid_t id;
1855 int cid;
1856
1857 switch (imsg->hdr.type) {
1858 case IMSG_HOST_DISABLE:
1859 memcpy(&id, imsg->data, sizeof(id));
1860 if ((host = host_find(env, id)) == NULL((void*)0))
1861 fatalx("%s: desynchronized", __func__);
1862 if ((table = table_find(env, host->conf.tableid)) ==
1863 NULL((void*)0))
1864 fatalx("%s: invalid table id", __func__);
1865 if (host->up == HOST_UP)
1866 table->up--;
1867 host->flags |= F_DISABLE0x00000001;
1868 host->up = HOST_UNKNOWN;
1869 break;
1870 case IMSG_HOST_ENABLE:
1871 memcpy(&id, imsg->data, sizeof(id));
1872 if ((host = host_find(env, id)) == NULL((void*)0))
1873 fatalx("%s: desynchronized", __func__);
1874 host->flags &= ~(F_DISABLE0x00000001);
1875 host->up = HOST_UNKNOWN;
1876 break;
1877 case IMSG_TABLE_DISABLE:
1878 memcpy(&id, imsg->data, sizeof(id));
1879 if ((table = table_find(env, id)) == NULL((void*)0))
1880 fatalx("%s: desynchronized", __func__);
1881 table->conf.flags |= F_DISABLE0x00000001;
1882 table->up = 0;
1883 TAILQ_FOREACH(host, &table->hosts, entry)for((host) = ((&table->hosts)->tqh_first); (host) !=
((void*)0); (host) = ((host)->entry.tqe_next))
1884 host->up = HOST_UNKNOWN;
1885 break;
1886 case IMSG_TABLE_ENABLE:
1887 memcpy(&id, imsg->data, sizeof(id));
1888 if ((table = table_find(env, id)) == NULL((void*)0))
1889 fatalx("%s: desynchronized", __func__);
1890 table->conf.flags &= ~(F_DISABLE0x00000001);
1891 table->up = 0;
1892 TAILQ_FOREACH(host, &table->hosts, entry)for((host) = ((&table->hosts)->tqh_first); (host) !=
((void*)0); (host) = ((host)->entry.tqe_next))
1893 host->up = HOST_UNKNOWN;
1894 break;
1895 case IMSG_HOST_STATUS:
1896 IMSG_SIZE_CHECK(imsg, &st)do { if (((imsg)->hdr.len - sizeof(struct imsg_hdr)) < sizeof
(*&st)) fatalx("bad length imsg received"); } while (0)
;
1897 memcpy(&st, imsg->data, sizeof(st));
1898 if ((host = host_find(env, st.id)) == NULL((void*)0))
1899 fatalx("%s: invalid host id", __func__);
1900 if (host->flags & F_DISABLE0x00000001)
1901 break;
1902 if (host->up == st.up) {
1903 log_debug("%s: host %d => %d", __func__,
1904 host->conf.id, host->up);
1905 fatalx("%s: desynchronized", __func__);
1906 }
1907
1908 if ((table = table_find(env, host->conf.tableid))
1909 == NULL((void*)0))
1910 fatalx("%s: invalid table id", __func__);
1911
1912 DPRINTF("%s: [%d] state %d for "do {} while(0)
1913 "host %u %s", __func__, p->p_ps->ps_instance, st.up,do {} while(0)
1914 host->conf.id, host->conf.name)do {} while(0);
1915
1916 if ((st.up == HOST_UNKNOWN && host->up == HOST_DOWN) ||
1917 (st.up == HOST_DOWN && host->up == HOST_UNKNOWN)) {
1918 host->up = st.up;
1919 break;
1920 }
1921 if (st.up == HOST_UP)
1922 table->up++;
1923 else
1924 table->up--;
1925 host->up = st.up;
1926 break;
1927 case IMSG_NATLOOK:
1928 bcopy(imsg->data, &cnl, sizeof(cnl));
1929 if ((con = session_find(env, cnl.id)) == NULL((void*)0) ||
1930 con->se_cnl == NULL((void*)0)) {
1931 log_debug("%s: session %d: expired",
1932 __func__, cnl.id);
1933 break;
1934 }
1935 bcopy(&cnl, con->se_cnl, sizeof(*con->se_cnl));
1936 evtimer_del(&con->se_ev)event_del(&con->se_ev);
1937 evtimer_set(&con->se_ev, relay_natlook, con)event_set(&con->se_ev, -1, 0, relay_natlook, con);
1938 bzero(&tv, sizeof(tv));
1939 evtimer_add(&con->se_ev, &tv)event_add(&con->se_ev, &tv);
1940 break;
1941 case IMSG_CTL_SESSION:
1942 IMSG_SIZE_CHECK(imsg, &cid)do { if (((imsg)->hdr.len - sizeof(struct imsg_hdr)) < sizeof
(*&cid)) fatalx("bad length imsg received"); } while (0)
;
1943 memcpy(&cid, imsg->data, sizeof(cid));
1944 TAILQ_FOREACH(rlay, env->sc_relays, rl_entry)for((rlay) = ((env->sc_relays)->tqh_first); (rlay) != (
(void*)0); (rlay) = ((rlay)->rl_entry.tqe_next))
{
1945 SPLAY_FOREACH(con, session_tree,for ((con) = (((&rlay->rl_sessions)->sph_root == ((
void*)0)) ? ((void*)0) : session_tree_SPLAY_MIN_MAX(&rlay
->rl_sessions, -1)); (con) != ((void*)0); (con) = session_tree_SPLAY_NEXT
(&rlay->rl_sessions, con))
1946 &rlay->rl_sessions)for ((con) = (((&rlay->rl_sessions)->sph_root == ((
void*)0)) ? ((void*)0) : session_tree_SPLAY_MIN_MAX(&rlay
->rl_sessions, -1)); (con) != ((void*)0); (con) = session_tree_SPLAY_NEXT
(&rlay->rl_sessions, con))
{
1947 memcpy(&se, con, sizeof(se));
1948 se.se_cid = cid;
1949 proc_compose(env->sc_ps, p->p_id,
1950 IMSG_CTL_SESSION, &se, sizeof(se));
1951 }
1952 }
1953 proc_compose(env->sc_ps, p->p_id, IMSG_CTL_END,
1954 &cid, sizeof(cid));
1955 break;
1956 default:
1957 return (-1);
1958 }
1959
1960 return (0);
1961}
1962
1963int
1964relay_dispatch_ca(int fd, struct privsep_proc *p, struct imsg *imsg)
1965{
1966 switch (imsg->hdr.type) {
1967 case IMSG_CA_PRIVENC:
1968 case IMSG_CA_PRIVDEC:
1969 log_warnx("%s: priv%s result after timeout", __func__,
1970 imsg->hdr.type == IMSG_CA_PRIVENC ? "enc" : "dec");
1971 return (0);
1972 }
1973
1974 return (-1);
1975}
1976
1977int
1978relay_dispatch_parent(int fd, struct privsep_proc *p, struct imsg *imsg)
1979{
1980 struct relay_ticket_key ticket;
1981 struct relay *rlay;
1982 struct rsession *con;
1983 struct timeval tv;
1984 objid_t id;
1985
1986 switch (imsg->hdr.type) {
1987 case IMSG_BINDANY:
1988 bcopy(imsg->data, &id, sizeof(id));
1989 if ((con = session_find(env, id)) == NULL((void*)0)) {
1990 log_debug("%s: session %d: expired",
1991 __func__, id);
1992 break;
1993 }
1994
1995 /* Will validate the result later */
1996 con->se_bnds = imsg->fd;
1997
1998 evtimer_del(&con->se_ev)event_del(&con->se_ev);
1999 evtimer_set(&con->se_ev, relay_bindany, con)event_set(&con->se_ev, -1, 0, relay_bindany, con);
2000 bzero(&tv, sizeof(tv));
2001 evtimer_add(&con->se_ev, &tv)event_add(&con->se_ev, &tv);
2002 break;
2003 case IMSG_CFG_TABLE:
2004 config_gettable(env, imsg);
2005 break;
2006 case IMSG_CFG_HOST:
2007 config_gethost(env, imsg);
2008 break;
2009 case IMSG_CFG_PROTO:
2010 config_getproto(env, imsg);
2011 break;
2012 case IMSG_CFG_RULE:
2013 config_getrule(env, imsg);
2014 break;
2015 case IMSG_CFG_RELAY:
2016 config_getrelay(env, imsg);
2017 break;
2018 case IMSG_CFG_RELAY_TABLE:
2019 config_getrelaytable(env, imsg);
2020 break;
2021 case IMSG_CFG_RELAY_FD:
2022 config_getrelayfd(env, imsg);
2023 break;
2024 case IMSG_CFG_DONE:
2025 config_getcfg(env, imsg);
2026 break;
2027 case IMSG_CTL_START:
2028 relay_launch();
2029 break;
2030 case IMSG_CTL_RESET:
2031 config_getreset(env, imsg);
2032 break;
2033 case IMSG_TLSTICKET_REKEY:
2034 IMSG_SIZE_CHECK(imsg, (&ticket))do { if (((imsg)->hdr.len - sizeof(struct imsg_hdr)) < sizeof
(*(&ticket))) fatalx("bad length imsg received"); } while
(0)
;
2035 memcpy(&env->sc_ticket, imsg->data, sizeof(env->sc_ticket));
2036 TAILQ_FOREACH(rlay, env->sc_relays, rl_entry)for((rlay) = ((env->sc_relays)->tqh_first); (rlay) != (
(void*)0); (rlay) = ((rlay)->rl_entry.tqe_next))
{
2037 if (rlay->rl_conf.flags & F_TLS0x00000800)
2038 tls_config_add_ticket_key(rlay->rl_tls_cfg,
2039 env->sc_ticket.tt_keyrev,
2040 env->sc_ticket.tt_key,
2041 sizeof(env->sc_ticket.tt_key));
2042 }
2043 break;
2044 default:
2045 return (-1);
2046 }
2047
2048 return (0);
2049}
2050
2051int
2052relay_dispatch_hce(int fd, struct privsep_proc *p, struct imsg *imsg)
2053{
2054 switch (imsg->hdr.type) {
2055 default:
2056 break;
2057 }
2058
2059 return (-1);
2060}
2061
2062static int
2063relay_tls_ctx_create_proto(struct protocol *proto, struct tls_config *tls_cfg)
2064{
2065 uint32_t protocols = 0;
2066
2067 /* Set the allowed SSL protocols */
2068 if (proto->tlsflags & TLSFLAG_TLSV1_00x02)
2069 protocols |= TLS_PROTOCOL_TLSv1_0(1 << 1);
2070 if (proto->tlsflags & TLSFLAG_TLSV1_10x04)
2071 protocols |= TLS_PROTOCOL_TLSv1_1(1 << 2);
2072 if (proto->tlsflags & TLSFLAG_TLSV1_20x08)
2073 protocols |= TLS_PROTOCOL_TLSv1_2(1 << 3);
2074 if (proto->tlsflags & TLSFLAG_TLSV1_30x10)
2075 protocols |= TLS_PROTOCOL_TLSv1_3(1 << 4);
2076 if (tls_config_set_protocols(tls_cfg, protocols) == -1) {
2077 log_warnx("could not set the TLS protocol: %s",
2078 tls_config_error(tls_cfg));
2079 return (-1);
2080 }
2081
2082 if (tls_config_set_ciphers(tls_cfg, proto->tlsciphers)) {
2083 log_warnx("could not set the TLS cypers: %s",
2084 tls_config_error(tls_cfg));
2085 return (-1);
2086 }
2087
2088 if ((proto->tlsflags & TLSFLAG_CIPHER_SERVER_PREF0x20) == 0)
2089 tls_config_prefer_ciphers_client(tls_cfg);
2090
2091 /*
2092 * Set session ID context to a random value. It needs to be the
2093 * same accross all relay processes or session caching will fail.
2094 */
2095 if (tls_config_set_session_id(tls_cfg, env->sc_conf.tls_sid,
2096 sizeof(env->sc_conf.tls_sid)) == -1) {
2097 log_warnx("could not set the TLS session ID: %s",
2098 tls_config_error(tls_cfg));
2099 return (-1);
2100 }
2101
2102 /* Set callback for TLS session tickets if enabled */
2103 if (proto->tickets == 1) {
2104 /* set timeout to the ticket rekey time */
2105 tls_config_set_session_lifetime(tls_cfg, TLS_SESSION_LIFETIME(2 * 3600));
2106
2107 tls_config_add_ticket_key(tls_cfg,
2108 env->sc_ticket.tt_keyrev, env->sc_ticket.tt_key,
2109 sizeof(env->sc_ticket.tt_key));
2110 }
2111
2112 if (tls_config_set_ecdhecurves(tls_cfg, proto->tlsecdhecurves) != 0) {
2113 log_warnx("failed to set ecdhe curves %s: %s",
2114 proto->tlsecdhecurves, tls_config_error(tls_cfg));
2115 return (-1);
2116 }
2117
2118 if (tls_config_set_dheparams(tls_cfg, proto->tlsdhparams) != 0) {
2119 log_warnx("failed to set dh params %s: %s",
2120 proto->tlsdhparams, tls_config_error(tls_cfg));
2121 return (-1);
2122 }
2123
2124 return (0);
2125}
2126
2127/*
2128 * This function is not publicy exported because it is a hack until libtls
2129 * has a proper privsep setup
2130 */
2131void tls_config_use_fake_private_key(struct tls_config *config);
2132
2133int
2134relay_tls_ctx_create(struct relay *rlay)
2135{
2136 struct tls_config *tls_cfg, *tls_client_cfg;
2137 struct tls *tls = NULL((void*)0);
2138 struct relay_cert *cert;
2139 int keyfound = 0;
2140 char *buf = NULL((void*)0), *cabuf = NULL((void*)0), *ocspbuf = NULL((void*)0);
2141 off_t len = 0, calen = 0, ocsplen = 0;
2142
2143 if ((tls_cfg = tls_config_new()) == NULL((void*)0)) {
2144 log_warnx("unable to allocate TLS config");
2145 return (-1);
2146 }
2147 if ((tls_client_cfg = tls_config_new()) == NULL((void*)0)) {
2148 log_warnx("unable to allocate TLS config");
2149 return (-1);
2150 }
2151
2152 if (relay_tls_ctx_create_proto(rlay->rl_proto, tls_cfg) == -1)
2153 goto err;
2154 if (relay_tls_ctx_create_proto(rlay->rl_proto, tls_client_cfg) == -1)
2155 goto err;
2156
2157 /* Verify the server certificate if we have a CA chain */
2158 if (rlay->rl_conf.flags & F_TLSCLIENT0x00200000) {
2159 /*
2160 * Currently relayd can't verify the name of certs and changing
2161 * this is non trivial. For now just disable name verification.
2162 */
2163 tls_config_insecure_noverifyname(tls_client_cfg);
2164
2165 if (rlay->rl_tls_ca_fd != -1) {
2166 if ((buf = relay_load_fd(rlay->rl_tls_ca_fd, &len)) ==
2167 NULL((void*)0)) {
2168 log_warn("failed to read root certificates");
2169 goto err;
2170 }
2171 rlay->rl_tls_ca_fd = -1;
2172
2173 if (tls_config_set_ca_mem(tls_client_cfg, buf, len) !=
2174 0) {
2175 log_warnx("failed to set root certificates: %s",
2176 tls_config_error(tls_client_cfg));
2177 goto err;
2178 }
2179 purge_key(&buf, len);
2180 } else {
2181 /* No root cert available so disable the checking */
2182 tls_config_insecure_noverifycert(tls_client_cfg);
2183 }
2184
2185 rlay->rl_tls_client_cfg = tls_client_cfg;
2186 }
2187
2188 if (rlay->rl_conf.flags & F_TLS0x00000800) {
2189 log_debug("%s: loading certificate", __func__);
2190 /*
2191 * Use the public key as the "private" key - the secret key
2192 * parameters are hidden in an extra process that will be
2193 * contacted by the RSA engine. The SSL/TLS library needs at
2194 * least the public key parameters in the current process.
2195 */
2196 tls_config_use_fake_private_key(tls_cfg);
2197
2198 TAILQ_FOREACH(cert, env->sc_certs, cert_entry)for((cert) = ((env->sc_certs)->tqh_first); (cert) != ((
void*)0); (cert) = ((cert)->cert_entry.tqe_next))
{
2199 if (cert->cert_relayid != rlay->rl_conf.id ||
2200 cert->cert_fd == -1)
2201 continue;
2202 keyfound++;
2203
2204 if ((buf = relay_load_fd(cert->cert_fd,
2205 &len)) == NULL((void*)0)) {
2206 log_warn("failed to load tls certificate");
2207 goto err;
2208 }
2209 cert->cert_fd = -1;
2210
2211 if (cert->cert_ocsp_fd != -1 &&
2212 (ocspbuf = relay_load_fd(cert->cert_ocsp_fd,
2213 &ocsplen)) == NULL((void*)0)) {
2214 log_warn("failed to load OCSP staplefile");
2215 goto err;
2216 }
2217 if (ocsplen == 0)
2218 purge_key(&ocspbuf, ocsplen);
2219 cert->cert_ocsp_fd = -1;
2220
2221 if (keyfound == 1 &&
2222 tls_config_set_keypair_ocsp_mem(tls_cfg, buf, len,
2223 NULL((void*)0), 0, ocspbuf, ocsplen) != 0) {
2224 log_warnx("failed to set tls certificate: %s",
2225 tls_config_error(tls_cfg));
2226 goto err;
2227 }
2228
2229 /* loading certificate public key */
2230 if (keyfound == 1 &&
2231 !ssl_load_pkey(buf, len, NULL((void*)0), &rlay->rl_tls_pkey))
2232 goto err;
2233
2234 if (tls_config_add_keypair_ocsp_mem(tls_cfg, buf, len,
2235 NULL((void*)0), 0, ocspbuf, ocsplen) != 0) {
2236 log_warnx("failed to add tls certificate: %s",
2237 tls_config_error(tls_cfg));
2238 goto err;
2239 }
2240
2241 purge_key(&buf, len);
2242 purge_key(&ocspbuf, ocsplen);
2243 }
2244
2245 if (rlay->rl_tls_cacert_fd != -1) {
2246 if ((cabuf = relay_load_fd(rlay->rl_tls_cacert_fd,
2247 &calen)) == NULL((void*)0)) {
2248 log_warn("failed to load tls CA certificate");
2249 goto err;
2250 }
2251 log_debug("%s: loading CA certificate", __func__);
2252 if (!ssl_load_pkey(cabuf, calen,
2253 &rlay->rl_tls_cacertx509, &rlay->rl_tls_capkey))
2254 goto err;
2255 }
2256 rlay->rl_tls_cacert_fd = -1;
2257
2258 tls = tls_server();
2259 if (tls == NULL((void*)0)) {
2260 log_warnx("unable to allocate TLS context");
2261 goto err;
2262 }
2263 if (tls_configure(tls, tls_cfg) == -1) {
2264 log_warnx("could not configure the TLS context: %s",
2265 tls_error(tls));
2266 tls_free(tls);
2267 goto err;
2268 }
2269 rlay->rl_tls_cfg = tls_cfg;
2270 rlay->rl_tls_ctx = tls;
2271
2272 purge_key(&cabuf, calen);
2273 }
2274
2275 if (rlay->rl_tls_client_cfg == NULL((void*)0))
2276 tls_config_free(tls_client_cfg);
2277 if (rlay->rl_tls_cfg == NULL((void*)0))
2278 tls_config_free(tls_cfg);
2279
2280 return (0);
2281 err:
2282 purge_key(&ocspbuf, ocsplen);
2283 purge_key(&cabuf, calen);
2284 purge_key(&buf, len);
2285
2286 tls_config_free(tls_client_cfg);
2287 tls_config_free(tls_cfg);
2288 return (-1);
2289}
2290
2291static struct tls *
2292relay_tls_inspect_create(struct relay *rlay, struct ctl_relay_event *cre)
2293{
2294 struct tls_config *tls_cfg;
2295 struct tls *tls = NULL((void*)0);
2296
2297 /* TLS inspection: use session-specific certificate */
2298 if ((tls_cfg = tls_config_new()) == NULL((void*)0)) {
2299 log_warnx("unable to allocate TLS config");
2300 goto err;
2301 }
2302 if (relay_tls_ctx_create_proto(rlay->rl_proto, tls_cfg) == -1) {
2303 /* error already printed */
2304 goto err;
2305 }
2306
2307 tls_config_use_fake_private_key(tls_cfg);
2308
2309 if (tls_config_set_keypair_ocsp_mem(tls_cfg,
2310 cre->tlscert, cre->tlscert_len, NULL((void*)0), 0, NULL((void*)0), 0) != 0) {
2311 log_warnx("failed to set tls certificate: %s",
2312 tls_config_error(tls_cfg));
2313 goto err;
2314 }
2315
2316 tls = tls_server();
2317 if (tls == NULL((void*)0)) {
2318 log_warnx("unable to allocate TLS context");
2319 goto err;
2320 }
2321 if (tls_configure(tls, tls_cfg) == -1) {
2322 log_warnx("could not configure the TLS context: %s",
2323 tls_error(tls));
2324 tls_free(tls);
2325 goto err;
2326 }
2327
2328 cre->tls_cfg = tls_cfg;
2329 cre->tls_ctx = tls;
2330 return (tls);
2331 err:
2332 tls_config_free(tls_cfg);
2333 return (NULL((void*)0));
2334}
2335
2336void
2337relay_tls_transaction(struct rsession *con, struct ctl_relay_event *cre)
2338{
2339 struct relay *rlay = con->se_relay;
2340 struct tls *tls_server;
2341 const char *errstr;
2342 u_int flag;
2343
2344 if (cre->dir == RELAY_DIR_REQUEST) {
2345 if (cre->tlscert != NULL((void*)0))
2346 tls_server = relay_tls_inspect_create(rlay, cre);
2347 else
2348 tls_server = rlay->rl_tls_ctx;
2349 if (tls_server == NULL((void*)0)) {
2350 errstr = "no TLS server context available";
2351 goto err;
2352 }
2353
2354 if (tls_accept_socket(tls_server, &cre->tls, cre->s) == -1) {
2355 errstr = "could not accept the TLS connection";
2356 goto err;
2357 }
2358 flag = EV_READ0x02;
2359 } else {
2360 cre->tls = tls_client();
2361 if (cre->tls == NULL((void*)0) ||
2362 tls_configure(cre->tls, rlay->rl_tls_client_cfg) == -1) {
2363 errstr = "could not configure the TLS client context";
2364 goto err;
2365 }
2366 if (tls_connect_socket(cre->tls, cre->s, NULL((void*)0)) == -1) {
2367 errstr = "could not connect the TLS connection";
2368 goto err;
2369 }
2370 flag = EV_WRITE0x04;
2371 }
2372
2373 log_debug("%s: session %d: scheduling on %s", __func__, con->se_id,
2374 (flag == EV_READ0x02) ? "EV_READ" : "EV_WRITE");
2375 event_again(&con->se_ev, cre->s, EV_TIMEOUT0x01|flag, relay_tls_handshake,
2376 &con->se_tv_start, &rlay->rl_conf.timeout, cre);
2377 return;
2378
2379 err:
2380 relay_close(con, errstr, 1);
2381}
2382
2383void
2384relay_tls_handshake(int fd, short event, void *arg)
2385{
2386 struct ctl_relay_event *cre = arg;
2387 struct rsession *con = cre->con;
2388 struct relay *rlay = con->se_relay;
2389 int retry_flag = 0;
2390 int ret;
2391 char *msg;
2392
2393 if (event == EV_TIMEOUT0x01) {
1
Assuming 'event' is not equal to EV_TIMEOUT
2
Taking false branch
2394 relay_close(con, "TLS handshake timeout", 1);
2395 return;
2396 }
2397
2398 ret = tls_handshake(cre->tls);
2399 if (ret == 0) {
3
Assuming 'ret' is equal to 0
4
Taking true branch
2400#ifdef DEBUG
2401 log_info(
2402#else
2403 log_debug(
2404#endif
2405 "relay %s, tls session %d %s (%d active)",
2406 rlay->rl_conf.name, con->se_id,
2407 cre->dir == RELAY_DIR_REQUEST ? "established" : "connected",
5
Assuming field 'dir' is equal to RELAY_DIR_REQUEST
6
'?' condition is true
2408 relay_sessions);
2409
2410 if (cre->dir
6.1
Field 'dir' is equal to RELAY_DIR_REQUEST
== RELAY_DIR_REQUEST) {
7
Taking true branch
2411 relay_session(con);
8
Calling 'relay_session'
2412 return;
2413 }
2414
2415 if (rlay->rl_conf.flags & F_TLSINSPECT0x04000000) {
2416 const uint8_t *servercert;
2417 size_t len;
2418
2419 servercert = tls_peer_cert_chain_pem(con->se_out.tls,
2420 &len);
2421 if (servercert != NULL((void*)0)) {
2422 con->se_in.tlscert = ssl_update_certificate(
2423 servercert, len,
2424 rlay->rl_tls_pkey, rlay->rl_tls_capkey,
2425 rlay->rl_tls_cacertx509,
2426 &con->se_in.tlscert_len);
2427 } else
2428 con->se_in.tlscert = NULL((void*)0);
2429 if (con->se_in.tlscert == NULL((void*)0))
2430 relay_close(con,
2431 "could not create certificate", 1);
2432 else
2433 relay_session(con);
2434 return;
2435 }
2436 relay_connected(fd, EV_WRITE0x04, con);
2437 return;
2438 } else if (ret == TLS_WANT_POLLIN-2) {
2439 retry_flag = EV_READ0x02;
2440 } else if (ret == TLS_WANT_POLLOUT-3) {
2441 retry_flag = EV_WRITE0x04;
2442 } else {
2443 if (asprintf(&msg, "TLS handshake error: %s",
2444 tls_error(cre->tls)) >= 0) {
2445 relay_close(con, msg, 1);
2446 free(msg);
2447 } else {
2448 relay_close(con, "TLS handshake error", 1);
2449 }
2450 return;
2451 }
2452
2453 DPRINTF("%s: session %d: scheduling on %s", __func__, con->se_id,do {} while(0)
2454 (retry_flag == EV_READ) ? "EV_READ" : "EV_WRITE")do {} while(0);
2455 event_again(&con->se_ev, fd, EV_TIMEOUT0x01|retry_flag, relay_tls_handshake,
2456 &con->se_tv_start, &rlay->rl_conf.timeout, cre);
2457}
2458
2459void
2460relay_tls_connected(struct ctl_relay_event *cre)
2461{
2462 /*
2463 * Hack libevent - we overwrite the internal bufferevent I/O
2464 * functions to handle the TLS abstraction.
2465 */
2466 event_del(&cre->bev->ev_read);
2467 event_del(&cre->bev->ev_write);
2468
2469 event_set(&cre->bev->ev_read, cre->s, EV_READ0x02,
2470 relay_tls_readcb, cre->bev);
2471 event_set(&cre->bev->ev_write, cre->s, EV_WRITE0x04,
2472 relay_tls_writecb, cre->bev);
2473}
2474
2475void
2476relay_tls_readcb(int fd, short event, void *arg)
2477{
2478 char rbuf[IBUF_READ_SIZE65535];
2479 struct bufferevent *bufev = arg;
2480 struct ctl_relay_event *cre = bufev->cbarg;
2481 short what = EVBUFFER_READ0x01;
2482 int howmuch = IBUF_READ_SIZE65535;
2483 ssize_t ret;
2484 size_t len;
2485
2486 if (event == EV_TIMEOUT0x01) {
2487 what |= EVBUFFER_TIMEOUT0x40;
2488 goto err;
2489 }
2490
2491 if (bufev->wm_read.high != 0)
2492 howmuch = MINIMUM(sizeof(rbuf), bufev->wm_read.high)(((sizeof(rbuf)) < (bufev->wm_read.high)) ? (sizeof(rbuf
)) : (bufev->wm_read.high))
;
2493
2494 ret = tls_read(cre->tls, rbuf, howmuch);
2495 if (ret == TLS_WANT_POLLIN-2 || ret == TLS_WANT_POLLOUT-3) {
2496 goto retry;
2497 } else if (ret == -1) {
2498 what |= EVBUFFER_ERROR0x20;
2499 goto err;
2500 }
2501 len = ret;
2502
2503 if (len == 0) {
2504 what |= EVBUFFER_EOF0x10;
2505 goto err;
2506 }
2507
2508 if (evbuffer_add(bufev->input, rbuf, ret) == -1) {
2509 what |= EVBUFFER_ERROR0x20;
2510 goto err;
2511 }
2512
2513 relay_bufferevent_add(&bufev->ev_read, bufev->timeout_read);
2514
2515 len = EVBUFFER_LENGTH(bufev->input)(bufev->input)->off;
2516 if (bufev->wm_read.low != 0 && len < bufev->wm_read.low)
2517 return;
2518 if (bufev->wm_read.high != 0 && len > bufev->wm_read.high) {
2519 struct evbuffer *buf = bufev->input;
2520 event_del(&bufev->ev_read);
2521 evbuffer_setcb(buf, bufferevent_read_pressure_cb, bufev);
2522 return;
2523 }
2524
2525 if (bufev->readcb != NULL((void*)0))
2526 (*bufev->readcb)(bufev, bufev->cbarg);
2527 return;
2528
2529 retry:
2530 relay_bufferevent_add(&bufev->ev_read, bufev->timeout_read);
2531 return;
2532
2533 err:
2534 (*bufev->errorcb)(bufev, what, bufev->cbarg);
2535}
2536
2537void
2538relay_tls_writecb(int fd, short event, void *arg)
2539{
2540 struct bufferevent *bufev = arg;
2541 struct ctl_relay_event *cre = bufev->cbarg;
2542 ssize_t ret;
2543 size_t len;
2544 short what = EVBUFFER_WRITE0x02;
2545
2546 if (event == EV_TIMEOUT0x01) {
2547 what |= EVBUFFER_TIMEOUT0x40;
2548 goto err;
2549 }
2550
2551 if (EVBUFFER_LENGTH(bufev->output)(bufev->output)->off) {
2552 ret = tls_write(cre->tls, EVBUFFER_DATA(bufev->output)(bufev->output)->buffer,
2553 EVBUFFER_LENGTH(bufev->output)(bufev->output)->off);
2554 if (ret == TLS_WANT_POLLIN-2 || ret == TLS_WANT_POLLOUT-3) {
2555 goto retry;
2556 } else if (ret == -1) {
2557 what |= EVBUFFER_ERROR0x20;
2558 goto err;
2559 }
2560 len = ret;
2561 evbuffer_drain(bufev->output, len);
2562 }
2563
2564 if (EVBUFFER_LENGTH(bufev->output)(bufev->output)->off != 0)
2565 relay_bufferevent_add(&bufev->ev_write, bufev->timeout_write);
2566
2567 if (bufev->writecb != NULL((void*)0) &&
2568 EVBUFFER_LENGTH(bufev->output)(bufev->output)->off <= bufev->wm_write.low)
2569 (*bufev->writecb)(bufev, bufev->cbarg);
2570 return;
2571
2572 retry:
2573 relay_bufferevent_add(&bufev->ev_write, bufev->timeout_write);
2574 return;
2575
2576 err:
2577 (*bufev->errorcb)(bufev, what, bufev->cbarg);
2578}
2579
2580int
2581relay_bufferevent_add(struct event *ev, int timeout)
2582{
2583 struct timeval tv, *ptv = NULL((void*)0);
2584
2585 if (timeout) {
2586 timerclear(&tv)(&tv)->tv_sec = (&tv)->tv_usec = 0;
2587 tv.tv_sec = timeout;
2588 ptv = &tv;
2589 }
2590
2591 return (event_add(ev, ptv));
2592}
2593
2594#ifdef notyet
2595int
2596relay_bufferevent_printf(struct ctl_relay_event *cre, const char *fmt, ...)
2597{
2598 int ret;
2599 va_list ap;
2600
2601 va_start(ap, fmt)__builtin_va_start(ap, fmt);
2602 ret = evbuffer_add_vprintf(cre->output, fmt, ap);
2603 va_end(ap)__builtin_va_end(ap);
2604
2605 if (cre->bev != NULL((void*)0) &&
2606 ret != -1 && EVBUFFER_LENGTH(cre->output)(cre->output)->off > 0 &&
2607 (cre->bev->enabled & EV_WRITE0x04))
2608 bufferevent_enable(cre->bev, EV_WRITE0x04);
2609
2610 return (ret);
2611}
2612#endif
2613
2614int
2615relay_bufferevent_print(struct ctl_relay_event *cre, const char *str)
2616{
2617 if (cre->bev == NULL((void*)0))
2618 return (evbuffer_add(cre->output, str, strlen(str)));
2619 return (bufferevent_write(cre->bev, str, strlen(str)));
2620}
2621
2622int
2623relay_bufferevent_write_buffer(struct ctl_relay_event *cre,
2624 struct evbuffer *buf)
2625{
2626 if (cre->bev == NULL((void*)0))
2627 return (evbuffer_add_buffer(cre->output, buf));
2628 return (bufferevent_write_buffer(cre->bev, buf));
2629}
2630
2631int
2632relay_bufferevent_write_chunk(struct ctl_relay_event *cre,
2633 struct evbuffer *buf, size_t size)
2634{
2635 int ret;
2636 ret = relay_bufferevent_write(cre, buf->buffer, size);
2637 if (ret != -1)
2638 evbuffer_drain(buf, size);
2639 return (ret);
2640}
2641
2642int
2643relay_bufferevent_write(struct ctl_relay_event *cre, void *data, size_t size)
2644{
2645 if (cre->bev == NULL((void*)0))
2646 return (evbuffer_add(cre->output, data, size));
2647 return (bufferevent_write(cre->bev, data, size));
2648}
2649
2650int
2651relay_cmp_af(struct sockaddr_storage *a, struct sockaddr_storage *b)
2652{
2653 int ret = -1;
2654 struct sockaddr_in ia, ib;
2655 struct sockaddr_in6 ia6, ib6;
2656
2657 switch (a->ss_family) {
2658 case AF_INET2:
2659 bcopy(a, &ia, sizeof(struct sockaddr_in));
2660 bcopy(b, &ib, sizeof(struct sockaddr_in));
2661
2662 ret = memcmp(&ia.sin_addr, &ib.sin_addr,
2663 sizeof(ia.sin_addr));
2664 if (ret == 0)
2665 ret = memcmp(&ia.sin_port, &ib.sin_port,
2666 sizeof(ia.sin_port));
2667 break;
2668 case AF_INET624:
2669 bcopy(a, &ia6, sizeof(struct sockaddr_in6));
2670 bcopy(b, &ib6, sizeof(struct sockaddr_in6));
2671
2672 ret = memcmp(&ia6.sin6_addr, &ib6.sin6_addr,
2673 sizeof(ia6.sin6_addr));
2674 if (ret == 0)
2675 ret = memcmp(&ia6.sin6_port, &ib6.sin6_port,
2676 sizeof(ia6.sin6_port));
2677 break;
2678 default:
2679 break;
2680 }
2681
2682 return (ret);
2683}
2684
2685int
2686relay_session_cmp(struct rsession *a, struct rsession *b)
2687{
2688 struct relay *rlay = b->se_relay;
2689 struct protocol *proto = rlay->rl_proto;
2690
2691 if (proto != NULL((void*)0) && proto->cmp != NULL((void*)0))
2692 return ((*proto->cmp)(a, b));
2693
2694 return ((int)a->se_id - b->se_id);
2695}
2696
2697void
2698relay_log(struct rsession *con, char *msg)
2699{
2700 if (con->se_haslog && con->se_log != NULL((void*)0)) {
2701 evbuffer_add(con->se_log, msg, strlen(msg));
2702 }
2703}
2704
2705SPLAY_GENERATE(session_tree, rsession, se_nodes, relay_session_cmp)struct rsession * session_tree_SPLAY_INSERT(struct session_tree
*head, struct rsession *elm) { if (((head)->sph_root == (
(void*)0))) { (elm)->se_nodes.spe_left = (elm)->se_nodes
.spe_right = ((void*)0); } else { int __comp; session_tree_SPLAY
(head, elm); __comp = (relay_session_cmp)(elm, (head)->sph_root
); if(__comp < 0) { (elm)->se_nodes.spe_left = ((head)->
sph_root)->se_nodes.spe_left; (elm)->se_nodes.spe_right
= (head)->sph_root; ((head)->sph_root)->se_nodes.spe_left
= ((void*)0); } else if (__comp > 0) { (elm)->se_nodes
.spe_right = ((head)->sph_root)->se_nodes.spe_right; (elm
)->se_nodes.spe_left = (head)->sph_root; ((head)->sph_root
)->se_nodes.spe_right = ((void*)0); } else return ((head)->
sph_root); } (head)->sph_root = (elm); return (((void*)0))
; } struct rsession * session_tree_SPLAY_REMOVE(struct session_tree
*head, struct rsession *elm) { struct rsession *__tmp; if ((
(head)->sph_root == ((void*)0))) return (((void*)0)); session_tree_SPLAY
(head, elm); if ((relay_session_cmp)(elm, (head)->sph_root
) == 0) { if (((head)->sph_root)->se_nodes.spe_left == (
(void*)0)) { (head)->sph_root = ((head)->sph_root)->
se_nodes.spe_right; } else { __tmp = ((head)->sph_root)->
se_nodes.spe_right; (head)->sph_root = ((head)->sph_root
)->se_nodes.spe_left; session_tree_SPLAY(head, elm); ((head
)->sph_root)->se_nodes.spe_right = __tmp; } return (elm
); } return (((void*)0)); } void session_tree_SPLAY(struct session_tree
*head, struct rsession *elm) { struct rsession __node, *__left
, *__right, *__tmp; int __comp; (&__node)->se_nodes.spe_left
= (&__node)->se_nodes.spe_right = ((void*)0); __left =
__right = &__node; while ((__comp = (relay_session_cmp)(
elm, (head)->sph_root))) { if (__comp < 0) { __tmp = ((
head)->sph_root)->se_nodes.spe_left; if (__tmp == ((void
*)0)) break; if ((relay_session_cmp)(elm, __tmp) < 0){ do {
((head)->sph_root)->se_nodes.spe_left = (__tmp)->se_nodes
.spe_right; (__tmp)->se_nodes.spe_right = (head)->sph_root
; (head)->sph_root = __tmp; } while (0); if (((head)->sph_root
)->se_nodes.spe_left == ((void*)0)) break; } do { (__right
)->se_nodes.spe_left = (head)->sph_root; __right = (head
)->sph_root; (head)->sph_root = ((head)->sph_root)->
se_nodes.spe_left; } while (0); } else if (__comp > 0) { __tmp
= ((head)->sph_root)->se_nodes.spe_right; if (__tmp ==
((void*)0)) break; if ((relay_session_cmp)(elm, __tmp) > 0
){ do { ((head)->sph_root)->se_nodes.spe_right = (__tmp
)->se_nodes.spe_left; (__tmp)->se_nodes.spe_left = (head
)->sph_root; (head)->sph_root = __tmp; } while (0); if (
((head)->sph_root)->se_nodes.spe_right == ((void*)0)) break
; } do { (__left)->se_nodes.spe_right = (head)->sph_root
; __left = (head)->sph_root; (head)->sph_root = ((head)
->sph_root)->se_nodes.spe_right; } while (0); } } do { (
__left)->se_nodes.spe_right = ((head)->sph_root)->se_nodes
.spe_left; (__right)->se_nodes.spe_left = ((head)->sph_root
)->se_nodes.spe_right; ((head)->sph_root)->se_nodes.
spe_left = (&__node)->se_nodes.spe_right; ((head)->
sph_root)->se_nodes.spe_right = (&__node)->se_nodes
.spe_left; } while (0); } void session_tree_SPLAY_MINMAX(struct
session_tree *head, int __comp) { struct rsession __node, *__left
, *__right, *__tmp; (&__node)->se_nodes.spe_left = (&
__node)->se_nodes.spe_right = ((void*)0); __left = __right
= &__node; while (1) { if (__comp < 0) { __tmp = ((head
)->sph_root)->se_nodes.spe_left; if (__tmp == ((void*)0
)) break; if (__comp < 0){ do { ((head)->sph_root)->
se_nodes.spe_left = (__tmp)->se_nodes.spe_right; (__tmp)->
se_nodes.spe_right = (head)->sph_root; (head)->sph_root
= __tmp; } while (0); if (((head)->sph_root)->se_nodes
.spe_left == ((void*)0)) break; } do { (__right)->se_nodes
.spe_left = (head)->sph_root; __right = (head)->sph_root
; (head)->sph_root = ((head)->sph_root)->se_nodes.spe_left
; } while (0); } else if (__comp > 0) { __tmp = ((head)->
sph_root)->se_nodes.spe_right; if (__tmp == ((void*)0)) break
; if (__comp > 0) { do { ((head)->sph_root)->se_nodes
.spe_right = (__tmp)->se_nodes.spe_left; (__tmp)->se_nodes
.spe_left = (head)->sph_root; (head)->sph_root = __tmp;
} while (0); if (((head)->sph_root)->se_nodes.spe_right
== ((void*)0)) break; } do { (__left)->se_nodes.spe_right
= (head)->sph_root; __left = (head)->sph_root; (head)->
sph_root = ((head)->sph_root)->se_nodes.spe_right; } while
(0); } } do { (__left)->se_nodes.spe_right = ((head)->
sph_root)->se_nodes.spe_left; (__right)->se_nodes.spe_left
= ((head)->sph_root)->se_nodes.spe_right; ((head)->
sph_root)->se_nodes.spe_left = (&__node)->se_nodes.
spe_right; ((head)->sph_root)->se_nodes.spe_right = (&
__node)->se_nodes.spe_left; } while (0); }
;