File: | src/usr.sbin/relayd/relayd.c |
Warning: | line 1460, column 6 Although the value stored to 'q' is used in the enclosing expression, the value is never actually read from 'q' |
Press '?' to see keyboard shortcuts
Keyboard shortcuts:
1 | /* $OpenBSD: relayd.c,v 1.187 2021/07/12 15:09:21 beck Exp $ */ |
2 | |
3 | /* |
4 | * Copyright (c) 2007 - 2016 Reyk Floeter <reyk@openbsd.org> |
5 | * Copyright (c) 2006 Pierre-Yves Ritschard <pyr@openbsd.org> |
6 | * |
7 | * Permission to use, copy, modify, and distribute this software for any |
8 | * purpose with or without fee is hereby granted, provided that the above |
9 | * copyright notice and this permission notice appear in all copies. |
10 | * |
11 | * THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES |
12 | * WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF |
13 | * MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR |
14 | * ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES |
15 | * WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN |
16 | * ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF |
17 | * OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE. |
18 | */ |
19 | |
20 | #include <sys/types.h> |
21 | #include <sys/queue.h> |
22 | #include <sys/socket.h> |
23 | #include <sys/stat.h> |
24 | #include <sys/wait.h> |
25 | #include <sys/resource.h> |
26 | |
27 | #include <netinet/in.h> |
28 | #include <arpa/inet.h> |
29 | |
30 | #include <signal.h> |
31 | #include <string.h> |
32 | #include <stdio.h> |
33 | #include <stdlib.h> |
34 | #include <fcntl.h> |
35 | #include <getopt.h> |
36 | #include <fnmatch.h> |
37 | #include <syslog.h> |
38 | #include <err.h> |
39 | #include <errno(*__errno()).h> |
40 | #include <event.h> |
41 | #include <unistd.h> |
42 | #include <ctype.h> |
43 | #include <pwd.h> |
44 | #include <sha1.h> |
45 | #include <md5.h> |
46 | |
47 | #include <tls.h> |
48 | |
49 | #include "relayd.h" |
50 | |
51 | #define MAXIMUM(a, b)(((a) > (b)) ? (a) : (b)) (((a) > (b)) ? (a) : (b)) |
52 | |
53 | __dead__attribute__((__noreturn__)) void usage(void); |
54 | |
55 | int parent_configure(struct relayd *); |
56 | void parent_configure_done(struct relayd *); |
57 | void parent_reload(struct relayd *, u_int, const char *); |
58 | void parent_sig_handler(int, short, void *); |
59 | void parent_shutdown(struct relayd *); |
60 | int parent_dispatch_pfe(int, struct privsep_proc *, struct imsg *); |
61 | int parent_dispatch_hce(int, struct privsep_proc *, struct imsg *); |
62 | int parent_dispatch_relay(int, struct privsep_proc *, |
63 | struct imsg *); |
64 | int parent_dispatch_ca(int, struct privsep_proc *, |
65 | struct imsg *); |
66 | int bindany(struct ctl_bindany *); |
67 | void parent_tls_ticket_rekey(int, short, void *); |
68 | |
69 | struct relayd *relayd_env; |
70 | |
71 | static struct privsep_proc procs[] = { |
72 | { "pfe", PROC_PFE, parent_dispatch_pfe, pfe }, |
73 | { "hce", PROC_HCE, parent_dispatch_hce, hce }, |
74 | { "relay", PROC_RELAY, parent_dispatch_relay, relay }, |
75 | { "ca", PROC_CA, parent_dispatch_ca, ca } |
76 | }; |
77 | |
78 | enum privsep_procid privsep_process; |
79 | |
80 | void |
81 | parent_sig_handler(int sig, short event, void *arg) |
82 | { |
83 | struct privsep *ps = arg; |
84 | |
85 | switch (sig) { |
86 | case SIGTERM15: |
87 | case SIGINT2: |
88 | parent_shutdown(ps->ps_env); |
89 | break; |
90 | case SIGHUP1: |
91 | log_info("%s: reload requested with SIGHUP", __func__); |
92 | |
93 | /* |
94 | * This is safe because libevent uses async signal handlers |
95 | * that run in the event loop and not in signal context. |
96 | */ |
97 | parent_reload(ps->ps_env, CONFIG_RELOAD0x00, NULL((void*)0)); |
98 | break; |
99 | case SIGPIPE13: |
100 | case SIGUSR130: |
101 | /* ignore */ |
102 | break; |
103 | default: |
104 | fatalx("unexpected signal"); |
105 | } |
106 | } |
107 | |
108 | __dead__attribute__((__noreturn__)) void |
109 | usage(void) |
110 | { |
111 | extern char *__progname; |
112 | |
113 | fprintf(stderr(&__sF[2]), "usage: %s [-dnv] [-D macro=value] [-f file]\n", |
114 | __progname); |
115 | exit(1); |
116 | } |
117 | |
118 | int |
119 | main(int argc, char *argv[]) |
120 | { |
121 | int c; |
122 | int debug = 0, verbose = 0; |
123 | u_int32_t opts = 0; |
124 | struct relayd *env; |
125 | struct privsep *ps; |
126 | const char *conffile = CONF_FILE"/etc/relayd.conf"; |
127 | enum privsep_procid proc_id = PROC_PARENT; |
128 | int proc_instance = 0; |
129 | const char *errp, *title = NULL((void*)0); |
130 | int argc0 = argc; |
131 | |
132 | while ((c = getopt(argc, argv, "dD:nI:P:f:v")) != -1) { |
133 | switch (c) { |
134 | case 'd': |
135 | debug = 2; |
136 | break; |
137 | case 'D': |
138 | if (cmdline_symset(optarg) < 0) |
139 | log_warnx("could not parse macro definition %s", |
140 | optarg); |
141 | break; |
142 | case 'n': |
143 | debug = 2; |
144 | opts |= RELAYD_OPT_NOACTION0x04; |
145 | break; |
146 | case 'f': |
147 | conffile = optarg; |
148 | break; |
149 | case 'v': |
150 | verbose++; |
151 | opts |= RELAYD_OPT_VERBOSE0x01; |
152 | break; |
153 | case 'P': |
154 | title = optarg; |
155 | proc_id = proc_getid(procs, nitems(procs)(sizeof((procs)) / sizeof((procs)[0])), title); |
156 | if (proc_id == PROC_MAX) |
157 | fatalx("invalid process name"); |
158 | break; |
159 | case 'I': |
160 | proc_instance = strtonum(optarg, 0, |
161 | PROC_MAX_INSTANCES32, &errp); |
162 | if (errp) |
163 | fatalx("invalid process instance"); |
164 | break; |
165 | default: |
166 | usage(); |
167 | } |
168 | } |
169 | |
170 | /* log to stderr until daemonized */ |
171 | log_init(debug ? debug : 1, LOG_DAEMON(3<<3)); |
172 | |
173 | argc -= optind; |
174 | if (argc > 0) |
175 | usage(); |
176 | |
177 | if ((env = calloc(1, sizeof(*env))) == NULL((void*)0) || |
178 | (ps = calloc(1, sizeof(*ps))) == NULL((void*)0)) |
179 | exit(1); |
180 | |
181 | relayd_env = env; |
182 | env->sc_ps = ps; |
183 | ps->ps_env = env; |
184 | TAILQ_INIT(&ps->ps_rcsocks)do { (&ps->ps_rcsocks)->tqh_first = ((void*)0); (& ps->ps_rcsocks)->tqh_last = &(&ps->ps_rcsocks )->tqh_first; } while (0); |
185 | env->sc_conffile = conffile; |
186 | env->sc_conf.opts = opts; |
187 | TAILQ_INIT(&env->sc_hosts)do { (&env->sc_hosts)->tqh_first = ((void*)0); (& env->sc_hosts)->tqh_last = &(&env->sc_hosts) ->tqh_first; } while (0); |
188 | TAILQ_INIT(&env->sc_sessions)do { (&env->sc_sessions)->tqh_first = ((void*)0); ( &env->sc_sessions)->tqh_last = &(&env->sc_sessions )->tqh_first; } while (0); |
189 | env->sc_rtable = getrtable(); |
190 | /* initialize the TLS session id to a random key for all relay procs */ |
191 | arc4random_buf(env->sc_conf.tls_sid, sizeof(env->sc_conf.tls_sid)); |
192 | |
193 | if (parse_config(env->sc_conffile, env) == -1) |
194 | exit(1); |
195 | |
196 | if (debug) |
197 | env->sc_conf.opts |= RELAYD_OPT_LOGUPDATE0x08; |
198 | |
199 | if (geteuid()) |
200 | errx(1, "need root privileges"); |
201 | |
202 | if ((ps->ps_pw = getpwnam(RELAYD_USER"_relayd")) == NULL((void*)0)) |
203 | errx(1, "unknown user %s", RELAYD_USER"_relayd"); |
204 | |
205 | log_init(debug, LOG_DAEMON(3<<3)); |
206 | log_setverbose(verbose); |
207 | |
208 | if (env->sc_conf.opts & RELAYD_OPT_NOACTION0x04) |
209 | ps->ps_noaction = 1; |
210 | |
211 | ps->ps_instances[PROC_RELAY] = env->sc_conf.prefork_relay; |
212 | ps->ps_instances[PROC_CA] = env->sc_conf.prefork_relay; |
213 | ps->ps_instance = proc_instance; |
214 | if (title != NULL((void*)0)) |
215 | ps->ps_title[proc_id] = title; |
216 | |
217 | /* only the parent returns */ |
218 | proc_init(ps, procs, nitems(procs)(sizeof((procs)) / sizeof((procs)[0])), debug, argc0, argv, proc_id); |
219 | |
220 | log_procinit("parent"); |
221 | if (!debug && daemon(1, 0) == -1) |
222 | err(1, "failed to daemonize"); |
223 | |
224 | if (ps->ps_noaction == 0) |
225 | log_info("startup"); |
226 | |
227 | if (unveil("/", "rx") == -1) |
228 | err(1, "unveil /"); |
229 | if (unveil(NULL((void*)0), NULL((void*)0)) == -1) |
230 | err(1, "unveil"); |
231 | |
232 | event_init(); |
233 | |
234 | signal_set(&ps->ps_evsigint, SIGINT, parent_sig_handler, ps)event_set(&ps->ps_evsigint, 2, 0x08|0x10, parent_sig_handler , ps); |
235 | signal_set(&ps->ps_evsigterm, SIGTERM, parent_sig_handler, ps)event_set(&ps->ps_evsigterm, 15, 0x08|0x10, parent_sig_handler , ps); |
236 | signal_set(&ps->ps_evsighup, SIGHUP, parent_sig_handler, ps)event_set(&ps->ps_evsighup, 1, 0x08|0x10, parent_sig_handler , ps); |
237 | signal_set(&ps->ps_evsigpipe, SIGPIPE, parent_sig_handler, ps)event_set(&ps->ps_evsigpipe, 13, 0x08|0x10, parent_sig_handler , ps); |
238 | signal_set(&ps->ps_evsigusr1, SIGUSR1, parent_sig_handler, ps)event_set(&ps->ps_evsigusr1, 30, 0x08|0x10, parent_sig_handler , ps); |
239 | |
240 | signal_add(&ps->ps_evsigint, NULL)event_add(&ps->ps_evsigint, ((void*)0)); |
241 | signal_add(&ps->ps_evsigterm, NULL)event_add(&ps->ps_evsigterm, ((void*)0)); |
242 | signal_add(&ps->ps_evsighup, NULL)event_add(&ps->ps_evsighup, ((void*)0)); |
243 | signal_add(&ps->ps_evsigpipe, NULL)event_add(&ps->ps_evsigpipe, ((void*)0)); |
244 | signal_add(&ps->ps_evsigusr1, NULL)event_add(&ps->ps_evsigusr1, ((void*)0)); |
245 | |
246 | proc_connect(ps); |
247 | |
248 | relay_http(NULL((void*)0)); |
249 | if (load_config(env->sc_conffile, env) == -1) { |
250 | proc_kill(env->sc_ps); |
251 | exit(1); |
252 | } |
253 | |
254 | if (env->sc_conf.opts & RELAYD_OPT_NOACTION0x04) { |
255 | fprintf(stderr(&__sF[2]), "configuration OK\n"); |
256 | proc_kill(env->sc_ps); |
257 | exit(0); |
258 | } |
259 | |
260 | if (env->sc_conf.flags & (F_TLS0x00000800|F_TLSCLIENT0x00200000)) |
261 | ssl_init(env); |
262 | |
263 | /* rekey the TLS tickets before pushing the config */ |
264 | parent_tls_ticket_rekey(0, 0, env); |
265 | if (parent_configure(env) == -1) |
266 | fatalx("configuration failed"); |
267 | |
268 | init_routes(env); |
269 | |
270 | event_dispatch(); |
271 | |
272 | parent_shutdown(env); |
273 | /* NOTREACHED */ |
274 | |
275 | return (0); |
276 | } |
277 | |
278 | int |
279 | parent_configure(struct relayd *env) |
280 | { |
281 | struct table *tb; |
282 | struct rdr *rdr; |
283 | struct router *rt; |
284 | struct protocol *proto; |
285 | struct relay *rlay; |
286 | int id; |
287 | int ret = -1; |
288 | |
289 | TAILQ_FOREACH(tb, env->sc_tables, entry)for((tb) = ((env->sc_tables)->tqh_first); (tb) != ((void *)0); (tb) = ((tb)->entry.tqe_next)) |
290 | config_settable(env, tb); |
291 | TAILQ_FOREACH(rdr, env->sc_rdrs, entry)for((rdr) = ((env->sc_rdrs)->tqh_first); (rdr) != ((void *)0); (rdr) = ((rdr)->entry.tqe_next)) |
292 | config_setrdr(env, rdr); |
293 | TAILQ_FOREACH(rt, env->sc_rts, rt_entry)for((rt) = ((env->sc_rts)->tqh_first); (rt) != ((void*) 0); (rt) = ((rt)->rt_entry.tqe_next)) |
294 | config_setrt(env, rt); |
295 | TAILQ_FOREACH(proto, env->sc_protos, entry)for((proto) = ((env->sc_protos)->tqh_first); (proto) != ((void*)0); (proto) = ((proto)->entry.tqe_next)) |
296 | config_setproto(env, proto); |
297 | TAILQ_FOREACH(proto, env->sc_protos, entry)for((proto) = ((env->sc_protos)->tqh_first); (proto) != ((void*)0); (proto) = ((proto)->entry.tqe_next)) |
298 | config_setrule(env, proto); |
299 | TAILQ_FOREACH(rlay, env->sc_relays, rl_entry)for((rlay) = ((env->sc_relays)->tqh_first); (rlay) != ( (void*)0); (rlay) = ((rlay)->rl_entry.tqe_next)) { |
300 | /* Check for TLS Inspection */ |
301 | if ((rlay->rl_conf.flags & (F_TLS0x00000800|F_TLSCLIENT0x00200000)) == |
302 | (F_TLS0x00000800|F_TLSCLIENT0x00200000) && rlay->rl_tls_cacert_fd != -1) |
303 | rlay->rl_conf.flags |= F_TLSINSPECT0x04000000; |
304 | |
305 | config_setrelay(env, rlay); |
306 | } |
307 | |
308 | /* HCE, PFE, CA and the relays need to reload their config. */ |
309 | env->sc_reload = 2 + (2 * env->sc_conf.prefork_relay); |
310 | |
311 | for (id = 0; id < PROC_MAX; id++) { |
312 | if (id == privsep_process) |
313 | continue; |
314 | proc_compose_imsg(env->sc_ps, id, -1, IMSG_CFG_DONE, -1, |
315 | -1, &env->sc_conf, sizeof(env->sc_conf)); |
316 | } |
317 | |
318 | ret = 0; |
319 | |
320 | config_purge(env, CONFIG_ALL0xff & ~CONFIG_RELAYS0x04); |
321 | return (ret); |
322 | } |
323 | |
324 | void |
325 | parent_reload(struct relayd *env, u_int reset, const char *filename) |
326 | { |
327 | if (env->sc_reload) { |
328 | log_debug("%s: already in progress: %d pending", |
329 | __func__, env->sc_reload); |
330 | return; |
331 | } |
332 | |
333 | /* Switch back to the default config file */ |
334 | if (filename == NULL((void*)0) || *filename == '\0') |
335 | filename = env->sc_conffile; |
336 | |
337 | log_debug("%s: level %d config file %s", __func__, reset, filename); |
338 | |
339 | config_purge(env, CONFIG_ALL0xff); |
340 | |
341 | if (reset == CONFIG_RELOAD0x00) { |
342 | if (load_config(filename, env) == -1) { |
343 | log_debug("%s: failed to load config file %s", |
344 | __func__, filename); |
345 | } |
346 | |
347 | config_setreset(env, CONFIG_ALL0xff); |
348 | |
349 | if (parent_configure(env) == -1) { |
350 | log_debug("%s: failed to commit config from %s", |
351 | __func__, filename); |
352 | } |
353 | } else |
354 | config_setreset(env, reset); |
355 | } |
356 | |
357 | void |
358 | parent_configure_done(struct relayd *env) |
359 | { |
360 | int id; |
361 | |
362 | if (env->sc_reload == 0) { |
363 | log_warnx("%s: configuration already finished", __func__); |
364 | return; |
365 | } |
366 | |
367 | env->sc_reload--; |
368 | if (env->sc_reload == 0) { |
369 | for (id = 0; id < PROC_MAX; id++) { |
370 | if (id == privsep_process) |
371 | continue; |
372 | |
373 | proc_compose(env->sc_ps, id, IMSG_CTL_START, NULL((void*)0), 0); |
374 | } |
375 | } |
376 | } |
377 | |
378 | void |
379 | parent_shutdown(struct relayd *env) |
380 | { |
381 | config_purge(env, CONFIG_ALL0xff); |
382 | |
383 | proc_kill(env->sc_ps); |
384 | control_cleanup(&env->sc_ps->ps_csock); |
385 | carp_demote_shutdown(); |
386 | |
387 | free(env->sc_ps); |
388 | free(env); |
389 | |
390 | log_info("parent terminating, pid %d", getpid()); |
391 | |
392 | exit(0); |
393 | } |
394 | |
395 | int |
396 | parent_dispatch_pfe(int fd, struct privsep_proc *p, struct imsg *imsg) |
397 | { |
398 | struct privsep *ps = p->p_ps; |
399 | struct relayd *env = ps->ps_env; |
400 | struct ctl_demote demote; |
401 | struct ctl_netroute crt; |
402 | u_int v; |
403 | char *str = NULL((void*)0); |
404 | |
405 | switch (imsg->hdr.type) { |
406 | case IMSG_DEMOTE: |
407 | IMSG_SIZE_CHECK(imsg, &demote)do { if (((imsg)->hdr.len - sizeof(struct imsg_hdr)) < sizeof (*&demote)) fatalx("bad length imsg received"); } while ( 0); |
408 | memcpy(&demote, imsg->data, sizeof(demote)); |
409 | carp_demote_set(demote.group, demote.level); |
410 | break; |
411 | case IMSG_RTMSG: |
412 | IMSG_SIZE_CHECK(imsg, &crt)do { if (((imsg)->hdr.len - sizeof(struct imsg_hdr)) < sizeof (*&crt)) fatalx("bad length imsg received"); } while (0); |
413 | memcpy(&crt, imsg->data, sizeof(crt)); |
414 | pfe_route(env, &crt); |
415 | break; |
416 | case IMSG_CTL_RESET: |
417 | IMSG_SIZE_CHECK(imsg, &v)do { if (((imsg)->hdr.len - sizeof(struct imsg_hdr)) < sizeof (*&v)) fatalx("bad length imsg received"); } while (0); |
418 | memcpy(&v, imsg->data, sizeof(v)); |
419 | parent_reload(env, v, NULL((void*)0)); |
420 | break; |
421 | case IMSG_CTL_RELOAD: |
422 | if (IMSG_DATA_SIZE(imsg)((imsg)->hdr.len - sizeof(struct imsg_hdr)) > 0) |
423 | str = get_string(imsg->data, IMSG_DATA_SIZE(imsg)((imsg)->hdr.len - sizeof(struct imsg_hdr))); |
424 | parent_reload(env, CONFIG_RELOAD0x00, str); |
425 | free(str); |
426 | break; |
427 | case IMSG_CTL_SHUTDOWN: |
428 | parent_shutdown(env); |
429 | break; |
430 | case IMSG_CFG_DONE: |
431 | parent_configure_done(env); |
432 | break; |
433 | case IMSG_AGENTXSOCK: |
434 | (void)agentx_setsock(env, p->p_id); |
435 | break; |
436 | default: |
437 | return (-1); |
438 | } |
439 | |
440 | return (0); |
441 | } |
442 | |
443 | int |
444 | parent_dispatch_hce(int fd, struct privsep_proc *p, struct imsg *imsg) |
445 | { |
446 | struct privsep *ps = p->p_ps; |
447 | struct relayd *env = ps->ps_env; |
448 | struct ctl_script scr; |
449 | |
450 | switch (imsg->hdr.type) { |
451 | case IMSG_SCRIPT: |
452 | IMSG_SIZE_CHECK(imsg, &scr)do { if (((imsg)->hdr.len - sizeof(struct imsg_hdr)) < sizeof (*&scr)) fatalx("bad length imsg received"); } while (0); |
453 | bcopy(imsg->data, &scr, sizeof(scr)); |
454 | scr.retval = script_exec(env, &scr); |
455 | proc_compose(ps, PROC_HCE, IMSG_SCRIPT, &scr, sizeof(scr)); |
456 | break; |
457 | case IMSG_CFG_DONE: |
458 | parent_configure_done(env); |
459 | break; |
460 | default: |
461 | return (-1); |
462 | } |
463 | |
464 | return (0); |
465 | } |
466 | |
467 | int |
468 | parent_dispatch_relay(int fd, struct privsep_proc *p, struct imsg *imsg) |
469 | { |
470 | struct privsep *ps = p->p_ps; |
471 | struct relayd *env = ps->ps_env; |
472 | struct ctl_bindany bnd; |
473 | int s; |
474 | |
475 | switch (imsg->hdr.type) { |
476 | case IMSG_BINDANY: |
477 | IMSG_SIZE_CHECK(imsg, &bnd)do { if (((imsg)->hdr.len - sizeof(struct imsg_hdr)) < sizeof (*&bnd)) fatalx("bad length imsg received"); } while (0); |
478 | bcopy(imsg->data, &bnd, sizeof(bnd)); |
479 | if (bnd.bnd_proc > env->sc_conf.prefork_relay) |
480 | fatalx("%s: invalid relay proc", __func__); |
481 | switch (bnd.bnd_proto) { |
482 | case IPPROTO_TCP6: |
483 | case IPPROTO_UDP17: |
484 | break; |
485 | default: |
486 | fatalx("%s: requested socket " |
487 | "for invalid protocol", __func__); |
488 | /* NOTREACHED */ |
489 | } |
490 | s = bindany(&bnd); |
491 | proc_compose_imsg(ps, PROC_RELAY, bnd.bnd_proc, |
492 | IMSG_BINDANY, -1, s, &bnd.bnd_id, sizeof(bnd.bnd_id)); |
493 | break; |
494 | case IMSG_CFG_DONE: |
495 | parent_configure_done(env); |
496 | break; |
497 | default: |
498 | return (-1); |
499 | } |
500 | |
501 | return (0); |
502 | } |
503 | |
504 | int |
505 | parent_dispatch_ca(int fd, struct privsep_proc *p, struct imsg *imsg) |
506 | { |
507 | struct privsep *ps = p->p_ps; |
508 | struct relayd *env = ps->ps_env; |
509 | |
510 | switch (imsg->hdr.type) { |
511 | case IMSG_CFG_DONE: |
512 | parent_configure_done(env); |
513 | break; |
514 | default: |
515 | return (-1); |
516 | } |
517 | |
518 | return (0); |
519 | } |
520 | |
521 | void |
522 | purge_table(struct relayd *env, struct tablelist *head, struct table *table) |
523 | { |
524 | struct host *host; |
525 | |
526 | while ((host = TAILQ_FIRST(&table->hosts)((&table->hosts)->tqh_first)) != NULL((void*)0)) { |
527 | TAILQ_REMOVE(&table->hosts, host, entry)do { if (((host)->entry.tqe_next) != ((void*)0)) (host)-> entry.tqe_next->entry.tqe_prev = (host)->entry.tqe_prev ; else (&table->hosts)->tqh_last = (host)->entry .tqe_prev; *(host)->entry.tqe_prev = (host)->entry.tqe_next ; ; ; } while (0); |
528 | TAILQ_REMOVE(&env->sc_hosts, host, globalentry)do { if (((host)->globalentry.tqe_next) != ((void*)0)) (host )->globalentry.tqe_next->globalentry.tqe_prev = (host)-> globalentry.tqe_prev; else (&env->sc_hosts)->tqh_last = (host)->globalentry.tqe_prev; *(host)->globalentry.tqe_prev = (host)->globalentry.tqe_next; ; ; } while (0); |
529 | if (event_initialized(&host->cte.ev)((&host->cte.ev)->ev_flags & 0x80)) { |
530 | event_del(&host->cte.ev); |
531 | close(host->cte.s); |
532 | } |
533 | ibuf_free(host->cte.buf); |
534 | tls_free(host->cte.tls); |
535 | free(host); |
536 | } |
537 | free(table->sendbuf); |
538 | ibuf_free(table->sendbinbuf); |
539 | tls_config_free(table->tls_cfg); |
540 | |
541 | if (head != NULL((void*)0)) |
542 | TAILQ_REMOVE(head, table, entry)do { if (((table)->entry.tqe_next) != ((void*)0)) (table)-> entry.tqe_next->entry.tqe_prev = (table)->entry.tqe_prev ; else (head)->tqh_last = (table)->entry.tqe_prev; *(table )->entry.tqe_prev = (table)->entry.tqe_next; ; ; } while (0); |
543 | free(table); |
544 | } |
545 | |
546 | void |
547 | purge_key(char **key, off_t len) |
548 | { |
549 | freezero(*key, len); |
550 | |
551 | *key = NULL((void*)0); |
552 | } |
553 | |
554 | void |
555 | purge_relay(struct relayd *env, struct relay *rlay) |
556 | { |
557 | struct rsession *con; |
558 | struct relay_table *rlt; |
559 | struct relay_cert *cert, *tmpcert; |
560 | |
561 | /* shutdown and remove relay */ |
562 | if (event_initialized(&rlay->rl_ev)((&rlay->rl_ev)->ev_flags & 0x80)) |
563 | event_del(&rlay->rl_ev); |
564 | close(rlay->rl_s); |
565 | TAILQ_REMOVE(env->sc_relays, rlay, rl_entry)do { if (((rlay)->rl_entry.tqe_next) != ((void*)0)) (rlay) ->rl_entry.tqe_next->rl_entry.tqe_prev = (rlay)->rl_entry .tqe_prev; else (env->sc_relays)->tqh_last = (rlay)-> rl_entry.tqe_prev; *(rlay)->rl_entry.tqe_prev = (rlay)-> rl_entry.tqe_next; ; ; } while (0); |
566 | |
567 | /* cleanup sessions */ |
568 | while ((con = |
569 | SPLAY_ROOT(&rlay->rl_sessions)(&rlay->rl_sessions)->sph_root) != NULL((void*)0)) |
570 | relay_close(con, NULL((void*)0), 0); |
571 | |
572 | /* cleanup relay */ |
573 | if (rlay->rl_bev != NULL((void*)0)) |
574 | bufferevent_free(rlay->rl_bev); |
575 | if (rlay->rl_dstbev != NULL((void*)0)) |
576 | bufferevent_free(rlay->rl_dstbev); |
577 | |
578 | purge_key(&rlay->rl_tls_cakey, rlay->rl_conf.tls_cakey_len); |
579 | |
580 | if (rlay->rl_tls_pkey != NULL((void*)0)) { |
581 | EVP_PKEY_free(rlay->rl_tls_pkey); |
582 | rlay->rl_tls_pkey = NULL((void*)0); |
583 | } |
584 | if (rlay->rl_tls_cacertx509 != NULL((void*)0)) { |
585 | X509_free(rlay->rl_tls_cacertx509); |
586 | rlay->rl_tls_cacertx509 = NULL((void*)0); |
587 | } |
588 | if (rlay->rl_tls_capkey != NULL((void*)0)) { |
589 | EVP_PKEY_free(rlay->rl_tls_capkey); |
590 | rlay->rl_tls_capkey = NULL((void*)0); |
591 | } |
592 | |
593 | tls_free(rlay->rl_tls_ctx); |
594 | tls_config_free(rlay->rl_tls_cfg); |
595 | tls_config_free(rlay->rl_tls_client_cfg); |
596 | |
597 | while ((rlt = TAILQ_FIRST(&rlay->rl_tables)((&rlay->rl_tables)->tqh_first))) { |
598 | TAILQ_REMOVE(&rlay->rl_tables, rlt, rlt_entry)do { if (((rlt)->rlt_entry.tqe_next) != ((void*)0)) (rlt)-> rlt_entry.tqe_next->rlt_entry.tqe_prev = (rlt)->rlt_entry .tqe_prev; else (&rlay->rl_tables)->tqh_last = (rlt )->rlt_entry.tqe_prev; *(rlt)->rlt_entry.tqe_prev = (rlt )->rlt_entry.tqe_next; ; ; } while (0); |
599 | free(rlt); |
600 | } |
601 | |
602 | TAILQ_FOREACH_SAFE(cert, env->sc_certs, cert_entry, tmpcert)for ((cert) = ((env->sc_certs)->tqh_first); (cert) != ( (void*)0) && ((tmpcert) = ((cert)->cert_entry.tqe_next ), 1); (cert) = (tmpcert)) { |
603 | if (rlay->rl_conf.id != cert->cert_relayid) |
604 | continue; |
605 | if (cert->cert_fd != -1) |
606 | close(cert->cert_fd); |
607 | if (cert->cert_key_fd != -1) |
608 | close(cert->cert_key_fd); |
609 | if (cert->cert_ocsp_fd != -1) |
610 | close(cert->cert_ocsp_fd); |
611 | if (cert->cert_pkey != NULL((void*)0)) |
612 | EVP_PKEY_free(cert->cert_pkey); |
613 | TAILQ_REMOVE(env->sc_certs, cert, cert_entry)do { if (((cert)->cert_entry.tqe_next) != ((void*)0)) (cert )->cert_entry.tqe_next->cert_entry.tqe_prev = (cert)-> cert_entry.tqe_prev; else (env->sc_certs)->tqh_last = ( cert)->cert_entry.tqe_prev; *(cert)->cert_entry.tqe_prev = (cert)->cert_entry.tqe_next; ; ; } while (0); |
614 | free(cert); |
615 | } |
616 | |
617 | free(rlay); |
618 | } |
619 | |
620 | struct kv * |
621 | kv_add(struct kvtree *keys, char *key, char *value, int unique) |
622 | { |
623 | struct kv *kv, *oldkv; |
624 | |
625 | if (key == NULL((void*)0)) |
626 | return (NULL((void*)0)); |
627 | if ((kv = calloc(1, sizeof(*kv))) == NULL((void*)0)) |
628 | return (NULL((void*)0)); |
629 | if ((kv->kv_key = strdup(key)) == NULL((void*)0)) |
630 | goto fail; |
631 | if (value != NULL((void*)0) && |
632 | (kv->kv_value = strdup(value)) == NULL((void*)0)) |
633 | goto fail; |
634 | TAILQ_INIT(&kv->kv_children)do { (&kv->kv_children)->tqh_first = ((void*)0); (& kv->kv_children)->tqh_last = &(&kv->kv_children )->tqh_first; } while (0); |
635 | |
636 | if ((oldkv = RB_INSERT(kvtree, keys, kv)kvtree_RB_INSERT(keys, kv)) != NULL((void*)0)) { |
637 | /* |
638 | * return error if the key should occur only once, |
639 | * or add it to a list attached to the key's node. |
640 | */ |
641 | if (unique) |
642 | goto fail; |
643 | TAILQ_INSERT_TAIL(&oldkv->kv_children, kv, kv_entry)do { (kv)->kv_entry.tqe_next = ((void*)0); (kv)->kv_entry .tqe_prev = (&oldkv->kv_children)->tqh_last; *(& oldkv->kv_children)->tqh_last = (kv); (&oldkv->kv_children )->tqh_last = &(kv)->kv_entry.tqe_next; } while (0); |
644 | kv->kv_parent = oldkv; |
645 | } |
646 | |
647 | return (kv); |
648 | fail: |
649 | free(kv->kv_key); |
650 | free(kv->kv_value); |
651 | free(kv); |
652 | return (NULL((void*)0)); |
653 | } |
654 | |
655 | int |
656 | kv_set(struct kv *kv, char *fmt, ...) |
657 | { |
658 | va_list ap; |
659 | char *value = NULL((void*)0); |
660 | struct kv *ckv; |
661 | |
662 | va_start(ap, fmt)__builtin_va_start(ap, fmt); |
663 | if (vasprintf(&value, fmt, ap) == -1) |
664 | return (-1); |
665 | va_end(ap)__builtin_va_end(ap); |
666 | |
667 | /* Remove all children */ |
668 | while ((ckv = TAILQ_FIRST(&kv->kv_children)((&kv->kv_children)->tqh_first)) != NULL((void*)0)) { |
669 | TAILQ_REMOVE(&kv->kv_children, ckv, kv_entry)do { if (((ckv)->kv_entry.tqe_next) != ((void*)0)) (ckv)-> kv_entry.tqe_next->kv_entry.tqe_prev = (ckv)->kv_entry. tqe_prev; else (&kv->kv_children)->tqh_last = (ckv) ->kv_entry.tqe_prev; *(ckv)->kv_entry.tqe_prev = (ckv)-> kv_entry.tqe_next; ; ; } while (0); |
670 | kv_free(ckv); |
671 | free(ckv); |
672 | } |
673 | |
674 | /* Set the new value */ |
675 | free(kv->kv_value); |
676 | kv->kv_value = value; |
677 | |
678 | return (0); |
679 | } |
680 | |
681 | int |
682 | kv_setkey(struct kv *kv, char *fmt, ...) |
683 | { |
684 | va_list ap; |
685 | char *key = NULL((void*)0); |
686 | |
687 | va_start(ap, fmt)__builtin_va_start(ap, fmt); |
688 | if (vasprintf(&key, fmt, ap) == -1) |
689 | return (-1); |
690 | va_end(ap)__builtin_va_end(ap); |
691 | |
692 | free(kv->kv_key); |
693 | kv->kv_key = key; |
694 | |
695 | return (0); |
696 | } |
697 | |
698 | void |
699 | kv_delete(struct kvtree *keys, struct kv *kv) |
700 | { |
701 | struct kv *ckv; |
702 | |
703 | RB_REMOVE(kvtree, keys, kv)kvtree_RB_REMOVE(keys, kv); |
704 | |
705 | /* Remove all children */ |
706 | while ((ckv = TAILQ_FIRST(&kv->kv_children)((&kv->kv_children)->tqh_first)) != NULL((void*)0)) { |
707 | TAILQ_REMOVE(&kv->kv_children, ckv, kv_entry)do { if (((ckv)->kv_entry.tqe_next) != ((void*)0)) (ckv)-> kv_entry.tqe_next->kv_entry.tqe_prev = (ckv)->kv_entry. tqe_prev; else (&kv->kv_children)->tqh_last = (ckv) ->kv_entry.tqe_prev; *(ckv)->kv_entry.tqe_prev = (ckv)-> kv_entry.tqe_next; ; ; } while (0); |
708 | kv_free(ckv); |
709 | free(ckv); |
710 | } |
711 | |
712 | kv_free(kv); |
713 | free(kv); |
714 | } |
715 | |
716 | struct kv * |
717 | kv_extend(struct kvtree *keys, struct kv *kv, char *value) |
718 | { |
719 | char *newvalue; |
720 | |
721 | if (kv == NULL((void*)0)) { |
722 | return (NULL((void*)0)); |
723 | } else if (kv->kv_value != NULL((void*)0)) { |
724 | if (asprintf(&newvalue, "%s%s", kv->kv_value, value) == -1) |
725 | return (NULL((void*)0)); |
726 | |
727 | free(kv->kv_value); |
728 | kv->kv_value = newvalue; |
729 | } else if ((kv->kv_value = strdup(value)) == NULL((void*)0)) |
730 | return (NULL((void*)0)); |
731 | |
732 | return (kv); |
733 | } |
734 | |
735 | void |
736 | kv_purge(struct kvtree *keys) |
737 | { |
738 | struct kv *kv; |
739 | |
740 | while ((kv = RB_MIN(kvtree, keys)kvtree_RB_MINMAX(keys, -1)) != NULL((void*)0)) |
741 | kv_delete(keys, kv); |
742 | } |
743 | |
744 | void |
745 | kv_free(struct kv *kv) |
746 | { |
747 | /* |
748 | * This function does not clear memory referenced by |
749 | * kv_children or stuff on the tailqs. Use kv_delete() instead. |
750 | */ |
751 | |
752 | free(kv->kv_key); |
753 | free(kv->kv_value); |
754 | memset(kv, 0, sizeof(*kv)); |
755 | } |
756 | |
757 | struct kv * |
758 | kv_inherit(struct kv *dst, struct kv *src) |
759 | { |
760 | memset(dst, 0, sizeof(*dst)); |
761 | memcpy(dst, src, sizeof(*dst)); |
762 | TAILQ_INIT(&dst->kv_children)do { (&dst->kv_children)->tqh_first = ((void*)0); ( &dst->kv_children)->tqh_last = &(&dst->kv_children )->tqh_first; } while (0); |
763 | |
764 | if (src->kv_key != NULL((void*)0)) { |
765 | if ((dst->kv_key = strdup(src->kv_key)) == NULL((void*)0)) { |
766 | kv_free(dst); |
767 | return (NULL((void*)0)); |
768 | } |
769 | } |
770 | if (src->kv_value != NULL((void*)0)) { |
771 | if ((dst->kv_value = strdup(src->kv_value)) == NULL((void*)0)) { |
772 | kv_free(dst); |
773 | return (NULL((void*)0)); |
774 | } |
775 | } |
776 | |
777 | if (src->kv_match != NULL((void*)0)) |
778 | dst->kv_match = src->kv_match; |
779 | if (src->kv_matchtree != NULL((void*)0)) |
780 | dst->kv_matchtree = src->kv_matchtree; |
781 | |
782 | return (dst); |
783 | } |
784 | |
785 | int |
786 | kv_log(struct rsession *con, struct kv *kv, u_int16_t labelid, |
787 | enum direction dir) |
788 | { |
789 | char *msg; |
790 | |
791 | if (con->se_log == NULL((void*)0)) |
792 | return (0); |
793 | if (asprintf(&msg, " %s%s%s%s%s%s%s", |
794 | dir == RELAY_DIR_REQUEST ? "[" : "{", |
795 | labelid == 0 ? "" : label_id2name(labelid), |
796 | labelid == 0 ? "" : ", ", |
797 | kv->kv_key == NULL((void*)0) ? "(unknown)" : kv->kv_key, |
798 | kv->kv_value == NULL((void*)0) ? "" : ": ", |
799 | kv->kv_value == NULL((void*)0) ? "" : kv->kv_value, |
800 | dir == RELAY_DIR_REQUEST ? "]" : "}") == -1) |
801 | return (-1); |
802 | if (evbuffer_add(con->se_log, msg, strlen(msg)) == -1) { |
803 | free(msg); |
804 | return (-1); |
805 | } |
806 | free(msg); |
807 | con->se_haslog = 1; |
808 | return (0); |
809 | } |
810 | |
811 | struct kv * |
812 | kv_find(struct kvtree *keys, struct kv *kv) |
813 | { |
814 | struct kv *match; |
815 | const char *key; |
816 | |
817 | if (kv->kv_flags & KV_FLAG_GLOBBING0x04) { |
818 | /* Test header key using shell globbing rules */ |
819 | key = kv->kv_key == NULL((void*)0) ? "" : kv->kv_key; |
820 | RB_FOREACH(match, kvtree, keys)for ((match) = kvtree_RB_MINMAX(keys, -1); (match) != ((void* )0); (match) = kvtree_RB_NEXT(match)) { |
821 | if (fnmatch(key, match->kv_key, FNM_CASEFOLD0x10) == 0) |
822 | break; |
823 | } |
824 | } else { |
825 | /* Fast tree-based lookup only works without globbing */ |
826 | match = RB_FIND(kvtree, keys, kv)kvtree_RB_FIND(keys, kv); |
827 | } |
828 | |
829 | return (match); |
830 | } |
831 | |
832 | struct kv * |
833 | kv_find_value(struct kvtree *keys, char *key, const char *value, |
834 | const char *delim) |
835 | { |
836 | struct kv *match, kv; |
837 | char *val = NULL((void*)0), *next, *ptr; |
838 | size_t len; |
839 | |
840 | kv.kv_key = key; |
841 | if ((match = RB_FIND(kvtree, keys, &kv)kvtree_RB_FIND(keys, &kv)) == NULL((void*)0)) |
842 | return (NULL((void*)0)); |
843 | |
844 | if (match->kv_value == NULL((void*)0)) |
845 | return (NULL((void*)0)); |
846 | |
847 | if (delim == NULL((void*)0)) { |
848 | if (strcasecmp(match->kv_value, value) == 0) |
849 | goto done; |
850 | } else { |
851 | if ((val = strdup(match->kv_value)) == NULL((void*)0)) |
852 | return (NULL((void*)0)); |
853 | for (next = ptr = val; ptr != NULL((void*)0); |
854 | ptr = strsep(&next, delim)) { |
855 | /* strip whitespace */ |
856 | ptr += strspn(ptr, " \t"); |
857 | len = strcspn(ptr, " \t"); |
858 | if (strncasecmp(ptr, value, len) == 0) |
859 | goto done; |
860 | } |
861 | } |
862 | |
863 | /* not matched */ |
864 | match = NULL((void*)0); |
865 | done: |
866 | #ifdef DEBUG |
867 | if (match != NULL((void*)0)) |
868 | DPRINTF("%s: matched %s: %s", __func__, key, value)do {} while(0); |
869 | #endif |
870 | free(val); |
871 | return (match); |
872 | } |
873 | |
874 | int |
875 | kv_cmp(struct kv *a, struct kv *b) |
876 | { |
877 | return (strcasecmp(a->kv_key, b->kv_key)); |
878 | } |
879 | |
880 | RB_GENERATE(kvtree, kv, kv_node, kv_cmp)void kvtree_RB_INSERT_COLOR(struct kvtree *head, struct kv *elm ) { struct kv *parent, *gparent, *tmp; while ((parent = (elm) ->kv_node.rbe_parent) && (parent)->kv_node.rbe_color == 1) { gparent = (parent)->kv_node.rbe_parent; if (parent == (gparent)->kv_node.rbe_left) { tmp = (gparent)->kv_node .rbe_right; if (tmp && (tmp)->kv_node.rbe_color == 1) { (tmp)->kv_node.rbe_color = 0; do { (parent)->kv_node .rbe_color = 0; (gparent)->kv_node.rbe_color = 1; } while ( 0); elm = gparent; continue; } if ((parent)->kv_node.rbe_right == elm) { do { (tmp) = (parent)->kv_node.rbe_right; if (( (parent)->kv_node.rbe_right = (tmp)->kv_node.rbe_left)) { ((tmp)->kv_node.rbe_left)->kv_node.rbe_parent = (parent ); } do {} while (0); if (((tmp)->kv_node.rbe_parent = (parent )->kv_node.rbe_parent)) { if ((parent) == ((parent)->kv_node .rbe_parent)->kv_node.rbe_left) ((parent)->kv_node.rbe_parent )->kv_node.rbe_left = (tmp); else ((parent)->kv_node.rbe_parent )->kv_node.rbe_right = (tmp); } else (head)->rbh_root = (tmp); (tmp)->kv_node.rbe_left = (parent); (parent)->kv_node .rbe_parent = (tmp); do {} while (0); if (((tmp)->kv_node. rbe_parent)) do {} while (0); } while (0); tmp = parent; parent = elm; elm = tmp; } do { (parent)->kv_node.rbe_color = 0; (gparent)->kv_node.rbe_color = 1; } while (0); do { (tmp) = (gparent)->kv_node.rbe_left; if (((gparent)->kv_node .rbe_left = (tmp)->kv_node.rbe_right)) { ((tmp)->kv_node .rbe_right)->kv_node.rbe_parent = (gparent); } do {} while (0); if (((tmp)->kv_node.rbe_parent = (gparent)->kv_node .rbe_parent)) { if ((gparent) == ((gparent)->kv_node.rbe_parent )->kv_node.rbe_left) ((gparent)->kv_node.rbe_parent)-> kv_node.rbe_left = (tmp); else ((gparent)->kv_node.rbe_parent )->kv_node.rbe_right = (tmp); } else (head)->rbh_root = (tmp); (tmp)->kv_node.rbe_right = (gparent); (gparent)-> kv_node.rbe_parent = (tmp); do {} while (0); if (((tmp)->kv_node .rbe_parent)) do {} while (0); } while (0); } else { tmp = (gparent )->kv_node.rbe_left; if (tmp && (tmp)->kv_node. rbe_color == 1) { (tmp)->kv_node.rbe_color = 0; do { (parent )->kv_node.rbe_color = 0; (gparent)->kv_node.rbe_color = 1; } while (0); elm = gparent; continue; } if ((parent)-> kv_node.rbe_left == elm) { do { (tmp) = (parent)->kv_node. rbe_left; if (((parent)->kv_node.rbe_left = (tmp)->kv_node .rbe_right)) { ((tmp)->kv_node.rbe_right)->kv_node.rbe_parent = (parent); } do {} while (0); if (((tmp)->kv_node.rbe_parent = (parent)->kv_node.rbe_parent)) { if ((parent) == ((parent )->kv_node.rbe_parent)->kv_node.rbe_left) ((parent)-> kv_node.rbe_parent)->kv_node.rbe_left = (tmp); else ((parent )->kv_node.rbe_parent)->kv_node.rbe_right = (tmp); } else (head)->rbh_root = (tmp); (tmp)->kv_node.rbe_right = ( parent); (parent)->kv_node.rbe_parent = (tmp); do {} while (0); if (((tmp)->kv_node.rbe_parent)) do {} while (0); } while (0); tmp = parent; parent = elm; elm = tmp; } do { (parent)-> kv_node.rbe_color = 0; (gparent)->kv_node.rbe_color = 1; } while (0); do { (tmp) = (gparent)->kv_node.rbe_right; if ( ((gparent)->kv_node.rbe_right = (tmp)->kv_node.rbe_left )) { ((tmp)->kv_node.rbe_left)->kv_node.rbe_parent = (gparent ); } do {} while (0); if (((tmp)->kv_node.rbe_parent = (gparent )->kv_node.rbe_parent)) { if ((gparent) == ((gparent)-> kv_node.rbe_parent)->kv_node.rbe_left) ((gparent)->kv_node .rbe_parent)->kv_node.rbe_left = (tmp); else ((gparent)-> kv_node.rbe_parent)->kv_node.rbe_right = (tmp); } else (head )->rbh_root = (tmp); (tmp)->kv_node.rbe_left = (gparent ); (gparent)->kv_node.rbe_parent = (tmp); do {} while (0); if (((tmp)->kv_node.rbe_parent)) do {} while (0); } while (0); } } (head->rbh_root)->kv_node.rbe_color = 0; } void kvtree_RB_REMOVE_COLOR(struct kvtree *head, struct kv *parent , struct kv *elm) { struct kv *tmp; while ((elm == ((void*)0) || (elm)->kv_node.rbe_color == 0) && elm != (head )->rbh_root) { if ((parent)->kv_node.rbe_left == elm) { tmp = (parent)->kv_node.rbe_right; if ((tmp)->kv_node. rbe_color == 1) { do { (tmp)->kv_node.rbe_color = 0; (parent )->kv_node.rbe_color = 1; } while (0); do { (tmp) = (parent )->kv_node.rbe_right; if (((parent)->kv_node.rbe_right = (tmp)->kv_node.rbe_left)) { ((tmp)->kv_node.rbe_left)-> kv_node.rbe_parent = (parent); } do {} while (0); if (((tmp)-> kv_node.rbe_parent = (parent)->kv_node.rbe_parent)) { if ( (parent) == ((parent)->kv_node.rbe_parent)->kv_node.rbe_left ) ((parent)->kv_node.rbe_parent)->kv_node.rbe_left = (tmp ); else ((parent)->kv_node.rbe_parent)->kv_node.rbe_right = (tmp); } else (head)->rbh_root = (tmp); (tmp)->kv_node .rbe_left = (parent); (parent)->kv_node.rbe_parent = (tmp) ; do {} while (0); if (((tmp)->kv_node.rbe_parent)) do {} while (0); } while (0); tmp = (parent)->kv_node.rbe_right; } if (((tmp)->kv_node.rbe_left == ((void*)0) || ((tmp)->kv_node .rbe_left)->kv_node.rbe_color == 0) && ((tmp)-> kv_node.rbe_right == ((void*)0) || ((tmp)->kv_node.rbe_right )->kv_node.rbe_color == 0)) { (tmp)->kv_node.rbe_color = 1; elm = parent; parent = (elm)->kv_node.rbe_parent; } else { if ((tmp)->kv_node.rbe_right == ((void*)0) || ((tmp)-> kv_node.rbe_right)->kv_node.rbe_color == 0) { struct kv *oleft ; if ((oleft = (tmp)->kv_node.rbe_left)) (oleft)->kv_node .rbe_color = 0; (tmp)->kv_node.rbe_color = 1; do { (oleft) = (tmp)->kv_node.rbe_left; if (((tmp)->kv_node.rbe_left = (oleft)->kv_node.rbe_right)) { ((oleft)->kv_node.rbe_right )->kv_node.rbe_parent = (tmp); } do {} while (0); if (((oleft )->kv_node.rbe_parent = (tmp)->kv_node.rbe_parent)) { if ((tmp) == ((tmp)->kv_node.rbe_parent)->kv_node.rbe_left ) ((tmp)->kv_node.rbe_parent)->kv_node.rbe_left = (oleft ); else ((tmp)->kv_node.rbe_parent)->kv_node.rbe_right = (oleft); } else (head)->rbh_root = (oleft); (oleft)->kv_node .rbe_right = (tmp); (tmp)->kv_node.rbe_parent = (oleft); do {} while (0); if (((oleft)->kv_node.rbe_parent)) do {} while (0); } while (0); tmp = (parent)->kv_node.rbe_right; } (tmp )->kv_node.rbe_color = (parent)->kv_node.rbe_color; (parent )->kv_node.rbe_color = 0; if ((tmp)->kv_node.rbe_right) ((tmp)->kv_node.rbe_right)->kv_node.rbe_color = 0; do { (tmp) = (parent)->kv_node.rbe_right; if (((parent)->kv_node .rbe_right = (tmp)->kv_node.rbe_left)) { ((tmp)->kv_node .rbe_left)->kv_node.rbe_parent = (parent); } do {} while ( 0); if (((tmp)->kv_node.rbe_parent = (parent)->kv_node. rbe_parent)) { if ((parent) == ((parent)->kv_node.rbe_parent )->kv_node.rbe_left) ((parent)->kv_node.rbe_parent)-> kv_node.rbe_left = (tmp); else ((parent)->kv_node.rbe_parent )->kv_node.rbe_right = (tmp); } else (head)->rbh_root = (tmp); (tmp)->kv_node.rbe_left = (parent); (parent)->kv_node .rbe_parent = (tmp); do {} while (0); if (((tmp)->kv_node. rbe_parent)) do {} while (0); } while (0); elm = (head)->rbh_root ; break; } } else { tmp = (parent)->kv_node.rbe_left; if ( (tmp)->kv_node.rbe_color == 1) { do { (tmp)->kv_node.rbe_color = 0; (parent)->kv_node.rbe_color = 1; } while (0); do { ( tmp) = (parent)->kv_node.rbe_left; if (((parent)->kv_node .rbe_left = (tmp)->kv_node.rbe_right)) { ((tmp)->kv_node .rbe_right)->kv_node.rbe_parent = (parent); } do {} while ( 0); if (((tmp)->kv_node.rbe_parent = (parent)->kv_node. rbe_parent)) { if ((parent) == ((parent)->kv_node.rbe_parent )->kv_node.rbe_left) ((parent)->kv_node.rbe_parent)-> kv_node.rbe_left = (tmp); else ((parent)->kv_node.rbe_parent )->kv_node.rbe_right = (tmp); } else (head)->rbh_root = (tmp); (tmp)->kv_node.rbe_right = (parent); (parent)-> kv_node.rbe_parent = (tmp); do {} while (0); if (((tmp)->kv_node .rbe_parent)) do {} while (0); } while (0); tmp = (parent)-> kv_node.rbe_left; } if (((tmp)->kv_node.rbe_left == ((void *)0) || ((tmp)->kv_node.rbe_left)->kv_node.rbe_color == 0) && ((tmp)->kv_node.rbe_right == ((void*)0) || ( (tmp)->kv_node.rbe_right)->kv_node.rbe_color == 0)) { ( tmp)->kv_node.rbe_color = 1; elm = parent; parent = (elm)-> kv_node.rbe_parent; } else { if ((tmp)->kv_node.rbe_left == ((void*)0) || ((tmp)->kv_node.rbe_left)->kv_node.rbe_color == 0) { struct kv *oright; if ((oright = (tmp)->kv_node.rbe_right )) (oright)->kv_node.rbe_color = 0; (tmp)->kv_node.rbe_color = 1; do { (oright) = (tmp)->kv_node.rbe_right; if (((tmp) ->kv_node.rbe_right = (oright)->kv_node.rbe_left)) { (( oright)->kv_node.rbe_left)->kv_node.rbe_parent = (tmp); } do {} while (0); if (((oright)->kv_node.rbe_parent = (tmp )->kv_node.rbe_parent)) { if ((tmp) == ((tmp)->kv_node. rbe_parent)->kv_node.rbe_left) ((tmp)->kv_node.rbe_parent )->kv_node.rbe_left = (oright); else ((tmp)->kv_node.rbe_parent )->kv_node.rbe_right = (oright); } else (head)->rbh_root = (oright); (oright)->kv_node.rbe_left = (tmp); (tmp)-> kv_node.rbe_parent = (oright); do {} while (0); if (((oright) ->kv_node.rbe_parent)) do {} while (0); } while (0); tmp = (parent)->kv_node.rbe_left; } (tmp)->kv_node.rbe_color = (parent)->kv_node.rbe_color; (parent)->kv_node.rbe_color = 0; if ((tmp)->kv_node.rbe_left) ((tmp)->kv_node.rbe_left )->kv_node.rbe_color = 0; do { (tmp) = (parent)->kv_node .rbe_left; if (((parent)->kv_node.rbe_left = (tmp)->kv_node .rbe_right)) { ((tmp)->kv_node.rbe_right)->kv_node.rbe_parent = (parent); } do {} while (0); if (((tmp)->kv_node.rbe_parent = (parent)->kv_node.rbe_parent)) { if ((parent) == ((parent )->kv_node.rbe_parent)->kv_node.rbe_left) ((parent)-> kv_node.rbe_parent)->kv_node.rbe_left = (tmp); else ((parent )->kv_node.rbe_parent)->kv_node.rbe_right = (tmp); } else (head)->rbh_root = (tmp); (tmp)->kv_node.rbe_right = ( parent); (parent)->kv_node.rbe_parent = (tmp); do {} while (0); if (((tmp)->kv_node.rbe_parent)) do {} while (0); } while (0); elm = (head)->rbh_root; break; } } } if (elm) (elm)-> kv_node.rbe_color = 0; } struct kv * kvtree_RB_REMOVE(struct kvtree *head, struct kv *elm) { struct kv *child, *parent, *old = elm ; int color; if ((elm)->kv_node.rbe_left == ((void*)0)) child = (elm)->kv_node.rbe_right; else if ((elm)->kv_node.rbe_right == ((void*)0)) child = (elm)->kv_node.rbe_left; else { struct kv *left; elm = (elm)->kv_node.rbe_right; while ((left = ( elm)->kv_node.rbe_left)) elm = left; child = (elm)->kv_node .rbe_right; parent = (elm)->kv_node.rbe_parent; color = (elm )->kv_node.rbe_color; if (child) (child)->kv_node.rbe_parent = parent; if (parent) { if ((parent)->kv_node.rbe_left == elm) (parent)->kv_node.rbe_left = child; else (parent)-> kv_node.rbe_right = child; do {} while (0); } else (head)-> rbh_root = child; if ((elm)->kv_node.rbe_parent == old) parent = elm; (elm)->kv_node = (old)->kv_node; if ((old)-> kv_node.rbe_parent) { if (((old)->kv_node.rbe_parent)-> kv_node.rbe_left == old) ((old)->kv_node.rbe_parent)->kv_node .rbe_left = elm; else ((old)->kv_node.rbe_parent)->kv_node .rbe_right = elm; do {} while (0); } else (head)->rbh_root = elm; ((old)->kv_node.rbe_left)->kv_node.rbe_parent = elm; if ((old)->kv_node.rbe_right) ((old)->kv_node.rbe_right )->kv_node.rbe_parent = elm; if (parent) { left = parent; do { do {} while (0); } while ((left = (left)->kv_node.rbe_parent )); } goto color; } parent = (elm)->kv_node.rbe_parent; color = (elm)->kv_node.rbe_color; if (child) (child)->kv_node .rbe_parent = parent; if (parent) { if ((parent)->kv_node. rbe_left == elm) (parent)->kv_node.rbe_left = child; else ( parent)->kv_node.rbe_right = child; do {} while (0); } else (head)->rbh_root = child; color: if (color == 0) kvtree_RB_REMOVE_COLOR (head, parent, child); return (old); } struct kv * kvtree_RB_INSERT (struct kvtree *head, struct kv *elm) { struct kv *tmp; struct kv *parent = ((void*)0); int comp = 0; tmp = (head)->rbh_root ; while (tmp) { parent = tmp; comp = (kv_cmp)(elm, parent); if (comp < 0) tmp = (tmp)->kv_node.rbe_left; else if (comp > 0) tmp = (tmp)->kv_node.rbe_right; else return (tmp) ; } do { (elm)->kv_node.rbe_parent = parent; (elm)->kv_node .rbe_left = (elm)->kv_node.rbe_right = ((void*)0); (elm)-> kv_node.rbe_color = 1; } while (0); if (parent != ((void*)0)) { if (comp < 0) (parent)->kv_node.rbe_left = elm; else (parent)->kv_node.rbe_right = elm; do {} while (0); } else (head)->rbh_root = elm; kvtree_RB_INSERT_COLOR(head, elm) ; return (((void*)0)); } struct kv * kvtree_RB_FIND(struct kvtree *head, struct kv *elm) { struct kv *tmp = (head)->rbh_root ; int comp; while (tmp) { comp = kv_cmp(elm, tmp); if (comp < 0) tmp = (tmp)->kv_node.rbe_left; else if (comp > 0) tmp = (tmp)->kv_node.rbe_right; else return (tmp); } return ( ((void*)0)); } struct kv * kvtree_RB_NFIND(struct kvtree *head , struct kv *elm) { struct kv *tmp = (head)->rbh_root; struct kv *res = ((void*)0); int comp; while (tmp) { comp = kv_cmp( elm, tmp); if (comp < 0) { res = tmp; tmp = (tmp)->kv_node .rbe_left; } else if (comp > 0) tmp = (tmp)->kv_node.rbe_right ; else return (tmp); } return (res); } struct kv * kvtree_RB_NEXT (struct kv *elm) { if ((elm)->kv_node.rbe_right) { elm = ( elm)->kv_node.rbe_right; while ((elm)->kv_node.rbe_left ) elm = (elm)->kv_node.rbe_left; } else { if ((elm)->kv_node .rbe_parent && (elm == ((elm)->kv_node.rbe_parent) ->kv_node.rbe_left)) elm = (elm)->kv_node.rbe_parent; else { while ((elm)->kv_node.rbe_parent && (elm == ((elm )->kv_node.rbe_parent)->kv_node.rbe_right)) elm = (elm) ->kv_node.rbe_parent; elm = (elm)->kv_node.rbe_parent; } } return (elm); } struct kv * kvtree_RB_PREV(struct kv *elm) { if ((elm)->kv_node.rbe_left) { elm = (elm)->kv_node. rbe_left; while ((elm)->kv_node.rbe_right) elm = (elm)-> kv_node.rbe_right; } else { if ((elm)->kv_node.rbe_parent && (elm == ((elm)->kv_node.rbe_parent)->kv_node.rbe_right )) elm = (elm)->kv_node.rbe_parent; else { while ((elm)-> kv_node.rbe_parent && (elm == ((elm)->kv_node.rbe_parent )->kv_node.rbe_left)) elm = (elm)->kv_node.rbe_parent; elm = (elm)->kv_node.rbe_parent; } } return (elm); } struct kv * kvtree_RB_MINMAX(struct kvtree *head, int val) { struct kv *tmp = (head)->rbh_root; struct kv *parent = ((void*)0); while (tmp) { parent = tmp; if (val < 0) tmp = (tmp)->kv_node .rbe_left; else tmp = (tmp)->kv_node.rbe_right; } return ( parent); }; |
881 | |
882 | int |
883 | rule_add(struct protocol *proto, struct relay_rule *rule, const char *rulefile) |
884 | { |
885 | struct relay_rule *r = NULL((void*)0); |
886 | struct kv *kv = NULL((void*)0); |
887 | FILE *fp = NULL((void*)0); |
888 | char buf[BUFSIZ1024]; |
889 | int ret = -1; |
890 | u_int i; |
891 | |
892 | for (i = 0; i < KEY_TYPE_MAX; i++) { |
893 | kv = &rule->rule_kv[i]; |
894 | if (kv->kv_type != i) |
895 | continue; |
896 | |
897 | switch (kv->kv_option) { |
898 | case KEY_OPTION_LOG: |
899 | /* log action needs a key or a file to be specified */ |
900 | if (kv->kv_key == NULL((void*)0) && rulefile == NULL((void*)0) && |
901 | (kv->kv_key = strdup("*")) == NULL((void*)0)) |
902 | goto fail; |
903 | break; |
904 | default: |
905 | break; |
906 | } |
907 | |
908 | switch (kv->kv_type) { |
909 | case KEY_TYPE_QUERY: |
910 | case KEY_TYPE_PATH: |
911 | case KEY_TYPE_URL: |
912 | if (rule->rule_dir != RELAY_DIR_REQUEST) |
913 | goto fail; |
914 | break; |
915 | default: |
916 | break; |
917 | } |
918 | |
919 | if (kv->kv_value != NULL((void*)0) && strchr(kv->kv_value, '$') != NULL((void*)0)) |
920 | kv->kv_flags |= KV_FLAG_MACRO0x01; |
921 | if (kv->kv_key != NULL((void*)0) && strpbrk(kv->kv_key, "*?[") != NULL((void*)0)) |
922 | kv->kv_flags |= KV_FLAG_GLOBBING0x04; |
923 | } |
924 | |
925 | if (rulefile == NULL((void*)0)) { |
926 | TAILQ_INSERT_TAIL(&proto->rules, rule, rule_entry)do { (rule)->rule_entry.tqe_next = ((void*)0); (rule)-> rule_entry.tqe_prev = (&proto->rules)->tqh_last; *( &proto->rules)->tqh_last = (rule); (&proto-> rules)->tqh_last = &(rule)->rule_entry.tqe_next; } while (0); |
927 | return (0); |
928 | } |
929 | |
930 | if ((fp = fopen(rulefile, "r")) == NULL((void*)0)) |
931 | goto fail; |
932 | |
933 | while (fgets(buf, sizeof(buf), fp) != NULL((void*)0)) { |
934 | /* strip whitespace and newline characters */ |
935 | buf[strcspn(buf, "\r\n\t ")] = '\0'; |
936 | if (!strlen(buf) || buf[0] == '#') |
937 | continue; |
938 | |
939 | if ((r = rule_inherit(rule)) == NULL((void*)0)) |
940 | goto fail; |
941 | |
942 | for (i = 0; i < KEY_TYPE_MAX; i++) { |
943 | kv = &r->rule_kv[i]; |
944 | if (kv->kv_type != i) |
945 | continue; |
946 | free(kv->kv_key); |
947 | if ((kv->kv_key = strdup(buf)) == NULL((void*)0)) { |
948 | rule_free(r); |
949 | free(r); |
950 | goto fail; |
951 | } |
952 | } |
953 | |
954 | TAILQ_INSERT_TAIL(&proto->rules, r, rule_entry)do { (r)->rule_entry.tqe_next = ((void*)0); (r)->rule_entry .tqe_prev = (&proto->rules)->tqh_last; *(&proto ->rules)->tqh_last = (r); (&proto->rules)->tqh_last = &(r)->rule_entry.tqe_next; } while (0); |
955 | } |
956 | |
957 | ret = 0; |
958 | rule_free(rule); |
959 | free(rule); |
960 | |
961 | fail: |
962 | if (fp != NULL((void*)0)) |
963 | fclose(fp); |
964 | return (ret); |
965 | } |
966 | |
967 | struct relay_rule * |
968 | rule_inherit(struct relay_rule *rule) |
969 | { |
970 | struct relay_rule *r; |
971 | u_int i; |
972 | struct kv *kv; |
973 | |
974 | if ((r = calloc(1, sizeof(*r))) == NULL((void*)0)) |
975 | return (NULL((void*)0)); |
976 | memcpy(r, rule, sizeof(*r)); |
977 | |
978 | for (i = 0; i < KEY_TYPE_MAX; i++) { |
979 | kv = &rule->rule_kv[i]; |
980 | if (kv->kv_type != i) |
981 | continue; |
982 | if (kv_inherit(&r->rule_kv[i], kv) == NULL((void*)0)) { |
983 | free(r); |
984 | return (NULL((void*)0)); |
985 | } |
986 | } |
987 | |
988 | if (r->rule_label > 0) |
989 | label_ref(r->rule_label); |
990 | if (r->rule_tag > 0) |
991 | tag_ref(r->rule_tag); |
992 | if (r->rule_tagged > 0) |
993 | tag_ref(r->rule_tagged); |
994 | |
995 | return (r); |
996 | } |
997 | |
998 | void |
999 | rule_free(struct relay_rule *rule) |
1000 | { |
1001 | u_int i; |
1002 | |
1003 | for (i = 0; i < KEY_TYPE_MAX; i++) |
1004 | kv_free(&rule->rule_kv[i]); |
1005 | if (rule->rule_label > 0) |
1006 | label_unref(rule->rule_label); |
1007 | if (rule->rule_tag > 0) |
1008 | tag_unref(rule->rule_tag); |
1009 | if (rule->rule_tagged > 0) |
1010 | tag_unref(rule->rule_tagged); |
1011 | } |
1012 | |
1013 | void |
1014 | rule_delete(struct relay_rules *rules, struct relay_rule *rule) |
1015 | { |
1016 | TAILQ_REMOVE(rules, rule, rule_entry)do { if (((rule)->rule_entry.tqe_next) != ((void*)0)) (rule )->rule_entry.tqe_next->rule_entry.tqe_prev = (rule)-> rule_entry.tqe_prev; else (rules)->tqh_last = (rule)->rule_entry .tqe_prev; *(rule)->rule_entry.tqe_prev = (rule)->rule_entry .tqe_next; ; ; } while (0); |
1017 | rule_free(rule); |
1018 | free(rule); |
1019 | } |
1020 | |
1021 | void |
1022 | rule_settable(struct relay_rules *rules, struct relay_table *rlt) |
1023 | { |
1024 | struct relay_rule *r; |
1025 | char pname[TABLE_NAME_SIZE64]; |
1026 | |
1027 | if (rlt->rlt_table == NULL((void*)0) || strlcpy(pname, rlt->rlt_table->conf.name, |
1028 | sizeof(pname)) >= sizeof(pname)) |
1029 | return; |
1030 | |
1031 | pname[strcspn(pname, ":")] = '\0'; |
1032 | |
1033 | TAILQ_FOREACH(r, rules, rule_entry)for((r) = ((rules)->tqh_first); (r) != ((void*)0); (r) = ( (r)->rule_entry.tqe_next)) { |
1034 | if (r->rule_tablename[0] && |
1035 | strcmp(pname, r->rule_tablename) == 0) |
1036 | r->rule_table = rlt; |
1037 | } |
1038 | } |
1039 | |
1040 | /* |
1041 | * Utility functions |
1042 | */ |
1043 | |
1044 | struct host * |
1045 | host_find(struct relayd *env, objid_t id) |
1046 | { |
1047 | struct table *table; |
1048 | struct host *host; |
1049 | |
1050 | TAILQ_FOREACH(table, env->sc_tables, entry)for((table) = ((env->sc_tables)->tqh_first); (table) != ((void*)0); (table) = ((table)->entry.tqe_next)) |
1051 | TAILQ_FOREACH(host, &table->hosts, entry)for((host) = ((&table->hosts)->tqh_first); (host) != ((void*)0); (host) = ((host)->entry.tqe_next)) |
1052 | if (host->conf.id == id) |
1053 | return (host); |
1054 | return (NULL((void*)0)); |
1055 | } |
1056 | |
1057 | struct table * |
1058 | table_find(struct relayd *env, objid_t id) |
1059 | { |
1060 | struct table *table; |
1061 | |
1062 | TAILQ_FOREACH(table, env->sc_tables, entry)for((table) = ((env->sc_tables)->tqh_first); (table) != ((void*)0); (table) = ((table)->entry.tqe_next)) |
1063 | if (table->conf.id == id) |
1064 | return (table); |
1065 | return (NULL((void*)0)); |
1066 | } |
1067 | |
1068 | struct rdr * |
1069 | rdr_find(struct relayd *env, objid_t id) |
1070 | { |
1071 | struct rdr *rdr; |
1072 | |
1073 | TAILQ_FOREACH(rdr, env->sc_rdrs, entry)for((rdr) = ((env->sc_rdrs)->tqh_first); (rdr) != ((void *)0); (rdr) = ((rdr)->entry.tqe_next)) |
1074 | if (rdr->conf.id == id) |
1075 | return (rdr); |
1076 | return (NULL((void*)0)); |
1077 | } |
1078 | |
1079 | struct relay * |
1080 | relay_find(struct relayd *env, objid_t id) |
1081 | { |
1082 | struct relay *rlay; |
1083 | |
1084 | TAILQ_FOREACH(rlay, env->sc_relays, rl_entry)for((rlay) = ((env->sc_relays)->tqh_first); (rlay) != ( (void*)0); (rlay) = ((rlay)->rl_entry.tqe_next)) |
1085 | if (rlay->rl_conf.id == id) |
1086 | return (rlay); |
1087 | return (NULL((void*)0)); |
1088 | } |
1089 | |
1090 | struct protocol * |
1091 | proto_find(struct relayd *env, objid_t id) |
1092 | { |
1093 | struct protocol *p; |
1094 | |
1095 | TAILQ_FOREACH(p, env->sc_protos, entry)for((p) = ((env->sc_protos)->tqh_first); (p) != ((void* )0); (p) = ((p)->entry.tqe_next)) |
1096 | if (p->id == id) |
1097 | return (p); |
1098 | return (NULL((void*)0)); |
1099 | } |
1100 | |
1101 | struct rsession * |
1102 | session_find(struct relayd *env, objid_t id) |
1103 | { |
1104 | struct relay *rlay; |
1105 | struct rsession *con; |
1106 | |
1107 | TAILQ_FOREACH(rlay, env->sc_relays, rl_entry)for((rlay) = ((env->sc_relays)->tqh_first); (rlay) != ( (void*)0); (rlay) = ((rlay)->rl_entry.tqe_next)) |
1108 | SPLAY_FOREACH(con, session_tree, &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)) |
1109 | if (con->se_id == id) |
1110 | return (con); |
1111 | return (NULL((void*)0)); |
1112 | } |
1113 | |
1114 | struct netroute * |
1115 | route_find(struct relayd *env, objid_t id) |
1116 | { |
1117 | struct netroute *nr; |
1118 | |
1119 | TAILQ_FOREACH(nr, env->sc_routes, nr_route)for((nr) = ((env->sc_routes)->tqh_first); (nr) != ((void *)0); (nr) = ((nr)->nr_route.tqe_next)) |
1120 | if (nr->nr_conf.id == id) |
1121 | return (nr); |
1122 | return (NULL((void*)0)); |
1123 | } |
1124 | |
1125 | struct router * |
1126 | router_find(struct relayd *env, objid_t id) |
1127 | { |
1128 | struct router *rt; |
1129 | |
1130 | TAILQ_FOREACH(rt, env->sc_rts, rt_entry)for((rt) = ((env->sc_rts)->tqh_first); (rt) != ((void*) 0); (rt) = ((rt)->rt_entry.tqe_next)) |
1131 | if (rt->rt_conf.id == id) |
1132 | return (rt); |
1133 | return (NULL((void*)0)); |
1134 | } |
1135 | |
1136 | struct host * |
1137 | host_findbyname(struct relayd *env, const char *name) |
1138 | { |
1139 | struct table *table; |
1140 | struct host *host; |
1141 | |
1142 | TAILQ_FOREACH(table, env->sc_tables, entry)for((table) = ((env->sc_tables)->tqh_first); (table) != ((void*)0); (table) = ((table)->entry.tqe_next)) |
1143 | TAILQ_FOREACH(host, &table->hosts, entry)for((host) = ((&table->hosts)->tqh_first); (host) != ((void*)0); (host) = ((host)->entry.tqe_next)) |
1144 | if (strcmp(host->conf.name, name) == 0) |
1145 | return (host); |
1146 | return (NULL((void*)0)); |
1147 | } |
1148 | |
1149 | struct table * |
1150 | table_findbyname(struct relayd *env, const char *name) |
1151 | { |
1152 | struct table *table; |
1153 | |
1154 | TAILQ_FOREACH(table, env->sc_tables, entry)for((table) = ((env->sc_tables)->tqh_first); (table) != ((void*)0); (table) = ((table)->entry.tqe_next)) |
1155 | if (strcmp(table->conf.name, name) == 0) |
1156 | return (table); |
1157 | return (NULL((void*)0)); |
1158 | } |
1159 | |
1160 | struct table * |
1161 | table_findbyconf(struct relayd *env, struct table *tb) |
1162 | { |
1163 | struct table *table; |
1164 | struct table_config a, b; |
1165 | |
1166 | bcopy(&tb->conf, &a, sizeof(a)); |
1167 | a.id = a.rdrid = 0; |
1168 | a.flags &= ~(F_USED0x00000004|F_BACKUP0x00000002); |
1169 | |
1170 | TAILQ_FOREACH(table, env->sc_tables, entry)for((table) = ((env->sc_tables)->tqh_first); (table) != ((void*)0); (table) = ((table)->entry.tqe_next)) { |
1171 | bcopy(&table->conf, &b, sizeof(b)); |
1172 | b.id = b.rdrid = 0; |
1173 | b.flags &= ~(F_USED0x00000004|F_BACKUP0x00000002); |
1174 | |
1175 | /* |
1176 | * Compare two tables and return the existing table if |
1177 | * the configuration seems to be the same. |
1178 | */ |
1179 | if (bcmp(&a, &b, sizeof(b)) == 0 && |
1180 | ((tb->sendbuf == NULL((void*)0) && table->sendbuf == NULL((void*)0)) || |
1181 | (tb->sendbuf != NULL((void*)0) && table->sendbuf != NULL((void*)0) && |
1182 | strcmp(tb->sendbuf, table->sendbuf) == 0))) |
1183 | return (table); |
1184 | } |
1185 | return (NULL((void*)0)); |
1186 | } |
1187 | |
1188 | struct rdr * |
1189 | rdr_findbyname(struct relayd *env, const char *name) |
1190 | { |
1191 | struct rdr *rdr; |
1192 | |
1193 | TAILQ_FOREACH(rdr, env->sc_rdrs, entry)for((rdr) = ((env->sc_rdrs)->tqh_first); (rdr) != ((void *)0); (rdr) = ((rdr)->entry.tqe_next)) |
1194 | if (strcmp(rdr->conf.name, name) == 0) |
1195 | return (rdr); |
1196 | return (NULL((void*)0)); |
1197 | } |
1198 | |
1199 | struct relay * |
1200 | relay_findbyname(struct relayd *env, const char *name) |
1201 | { |
1202 | struct relay *rlay; |
1203 | |
1204 | TAILQ_FOREACH(rlay, env->sc_relays, rl_entry)for((rlay) = ((env->sc_relays)->tqh_first); (rlay) != ( (void*)0); (rlay) = ((rlay)->rl_entry.tqe_next)) |
1205 | if (strcmp(rlay->rl_conf.name, name) == 0) |
1206 | return (rlay); |
1207 | return (NULL((void*)0)); |
1208 | } |
1209 | |
1210 | struct relay * |
1211 | relay_findbyaddr(struct relayd *env, struct relay_config *rc) |
1212 | { |
1213 | struct relay *rlay; |
1214 | |
1215 | TAILQ_FOREACH(rlay, env->sc_relays, rl_entry)for((rlay) = ((env->sc_relays)->tqh_first); (rlay) != ( (void*)0); (rlay) = ((rlay)->rl_entry.tqe_next)) |
1216 | if (bcmp(&rlay->rl_conf.ss, &rc->ss, sizeof(rc->ss)) == 0 && |
1217 | rlay->rl_conf.port == rc->port) |
1218 | return (rlay); |
1219 | return (NULL((void*)0)); |
1220 | } |
1221 | |
1222 | EVP_PKEY * |
1223 | pkey_find(struct relayd *env, char * hash) |
1224 | { |
1225 | struct ca_pkey *pkey; |
1226 | |
1227 | TAILQ_FOREACH(pkey, env->sc_pkeys, pkey_entry)for((pkey) = ((env->sc_pkeys)->tqh_first); (pkey) != (( void*)0); (pkey) = ((pkey)->pkey_entry.tqe_next)) |
1228 | if (strcmp(hash, pkey->pkey_hash) == 0) |
1229 | return (pkey->pkey); |
1230 | return (NULL((void*)0)); |
1231 | } |
1232 | |
1233 | struct ca_pkey * |
1234 | pkey_add(struct relayd *env, EVP_PKEY *pkey, char *hash) |
1235 | { |
1236 | struct ca_pkey *ca_pkey; |
1237 | |
1238 | if (env->sc_pkeys == NULL((void*)0)) |
1239 | fatalx("pkeys"); |
1240 | |
1241 | if ((ca_pkey = calloc(1, sizeof(*ca_pkey))) == NULL((void*)0)) |
1242 | return (NULL((void*)0)); |
1243 | |
1244 | ca_pkey->pkey = pkey; |
1245 | if (strlcpy(ca_pkey->pkey_hash, hash, sizeof(ca_pkey->pkey_hash)) >= |
1246 | sizeof(ca_pkey->pkey_hash)) { |
1247 | free(ca_pkey); |
1248 | return (NULL((void*)0)); |
1249 | } |
1250 | |
1251 | TAILQ_INSERT_TAIL(env->sc_pkeys, ca_pkey, pkey_entry)do { (ca_pkey)->pkey_entry.tqe_next = ((void*)0); (ca_pkey )->pkey_entry.tqe_prev = (env->sc_pkeys)->tqh_last; * (env->sc_pkeys)->tqh_last = (ca_pkey); (env->sc_pkeys )->tqh_last = &(ca_pkey)->pkey_entry.tqe_next; } while (0); |
1252 | |
1253 | return (ca_pkey); |
1254 | } |
1255 | |
1256 | struct relay_cert * |
1257 | cert_add(struct relayd *env, objid_t id) |
1258 | { |
1259 | static objid_t last_cert_id = 0; |
1260 | struct relay_cert *cert; |
1261 | |
1262 | if ((cert = calloc(1, sizeof(*cert))) == NULL((void*)0)) |
1263 | return (NULL((void*)0)); |
1264 | |
1265 | if (id == 0) |
1266 | id = ++last_cert_id; |
1267 | if (id == INT_MAX2147483647) { |
1268 | log_warnx("too many tls keypairs defined"); |
1269 | free(cert); |
1270 | return (NULL((void*)0)); |
1271 | } |
1272 | |
1273 | cert->cert_id = id; |
1274 | cert->cert_fd = -1; |
1275 | cert->cert_key_fd = -1; |
1276 | cert->cert_ocsp_fd = -1; |
1277 | |
1278 | TAILQ_INSERT_TAIL(env->sc_certs, cert, cert_entry)do { (cert)->cert_entry.tqe_next = ((void*)0); (cert)-> cert_entry.tqe_prev = (env->sc_certs)->tqh_last; *(env-> sc_certs)->tqh_last = (cert); (env->sc_certs)->tqh_last = &(cert)->cert_entry.tqe_next; } while (0); |
1279 | |
1280 | return (cert); |
1281 | } |
1282 | |
1283 | struct relay_cert * |
1284 | cert_find(struct relayd *env, objid_t id) |
1285 | { |
1286 | struct relay_cert *cert; |
1287 | |
1288 | TAILQ_FOREACH(cert, env->sc_certs, cert_entry)for((cert) = ((env->sc_certs)->tqh_first); (cert) != (( void*)0); (cert) = ((cert)->cert_entry.tqe_next)) |
1289 | if (cert->cert_id == id) |
1290 | return (cert); |
1291 | return (NULL((void*)0)); |
1292 | } |
1293 | |
1294 | char * |
1295 | relay_load_fd(int fd, off_t *len) |
1296 | { |
1297 | char *buf = NULL((void*)0); |
1298 | struct stat st; |
1299 | off_t size; |
1300 | ssize_t rv; |
1301 | int err; |
1302 | |
1303 | if (fstat(fd, &st) != 0) |
1304 | goto fail; |
1305 | size = st.st_size; |
1306 | if ((buf = calloc(1, size + 1)) == NULL((void*)0)) |
1307 | goto fail; |
1308 | if ((rv = pread(fd, buf, size, 0)) != size) |
1309 | goto fail; |
1310 | |
1311 | close(fd); |
1312 | |
1313 | *len = size; |
1314 | return (buf); |
1315 | |
1316 | fail: |
1317 | err = errno(*__errno()); |
1318 | free(buf); |
1319 | close(fd); |
1320 | errno(*__errno()) = err; |
1321 | return (NULL((void*)0)); |
1322 | } |
1323 | |
1324 | int |
1325 | relay_load_certfiles(struct relayd *env, struct relay *rlay, const char *name) |
1326 | { |
1327 | char certfile[PATH_MAX1024]; |
1328 | char hbuf[PATH_MAX1024]; |
1329 | struct protocol *proto = rlay->rl_proto; |
1330 | struct relay_cert *cert; |
1331 | int useport = htons(rlay->rl_conf.port)(__uint16_t)(__builtin_constant_p(rlay->rl_conf.port) ? (__uint16_t )(((__uint16_t)(rlay->rl_conf.port) & 0xffU) << 8 | ((__uint16_t)(rlay->rl_conf.port) & 0xff00U) >> 8) : __swap16md(rlay->rl_conf.port)); |
1332 | int cert_fd = -1, key_fd = -1, ocsp_fd = -1; |
1333 | |
1334 | if (rlay->rl_conf.flags & F_TLSCLIENT0x00200000) { |
1335 | if (strlen(proto->tlsca) && rlay->rl_tls_ca_fd == -1) { |
1336 | if ((rlay->rl_tls_ca_fd = |
1337 | open(proto->tlsca, O_RDONLY0x0000)) == -1) |
1338 | return (-1); |
1339 | log_debug("%s: using ca %s", __func__, proto->tlsca); |
1340 | } |
1341 | if (strlen(proto->tlscacert) && rlay->rl_tls_cacert_fd == -1) { |
1342 | if ((rlay->rl_tls_cacert_fd = |
1343 | open(proto->tlscacert, O_RDONLY0x0000)) == -1) |
1344 | return (-1); |
1345 | log_debug("%s: using ca certificate %s", __func__, |
1346 | proto->tlscacert); |
1347 | } |
1348 | if (strlen(proto->tlscakey) && !rlay->rl_conf.tls_cakey_len && |
1349 | proto->tlscapass != NULL((void*)0)) { |
1350 | if ((rlay->rl_tls_cakey = |
1351 | ssl_load_key(env, proto->tlscakey, |
1352 | &rlay->rl_conf.tls_cakey_len, |
1353 | proto->tlscapass)) == NULL((void*)0)) |
1354 | return (-1); |
1355 | log_debug("%s: using ca key %s", __func__, |
1356 | proto->tlscakey); |
1357 | } |
1358 | } |
1359 | |
1360 | if ((rlay->rl_conf.flags & F_TLS0x00000800) == 0) |
1361 | return (0); |
1362 | |
1363 | if (name == NULL((void*)0) && |
1364 | print_host(&rlay->rl_conf.ss, hbuf, sizeof(hbuf)) == NULL((void*)0)) |
1365 | goto fail; |
1366 | else if (name != NULL((void*)0) && |
1367 | strlcpy(hbuf, name, sizeof(hbuf)) >= sizeof(hbuf)) |
1368 | goto fail; |
1369 | |
1370 | if (snprintf(certfile, sizeof(certfile), |
1371 | "/etc/ssl/%s:%u.crt", hbuf, useport) == -1) |
1372 | goto fail; |
1373 | if ((cert_fd = open(certfile, O_RDONLY0x0000)) == -1) { |
1374 | if (snprintf(certfile, sizeof(certfile), |
1375 | "/etc/ssl/%s.crt", hbuf) == -1) |
1376 | goto fail; |
1377 | if ((cert_fd = open(certfile, O_RDONLY0x0000)) == -1) |
1378 | goto fail; |
1379 | useport = 0; |
1380 | } |
1381 | log_debug("%s: using certificate %s", __func__, certfile); |
1382 | |
1383 | if (useport) { |
1384 | if (snprintf(certfile, sizeof(certfile), |
1385 | "/etc/ssl/private/%s:%u.key", hbuf, useport) == -1) |
1386 | goto fail; |
1387 | } else { |
1388 | if (snprintf(certfile, sizeof(certfile), |
1389 | "/etc/ssl/private/%s.key", hbuf) == -1) |
1390 | goto fail; |
1391 | } |
1392 | if ((key_fd = open(certfile, O_RDONLY0x0000)) == -1) |
1393 | goto fail; |
1394 | log_debug("%s: using private key %s", __func__, certfile); |
1395 | |
1396 | if (useport) { |
1397 | if (snprintf(certfile, sizeof(certfile), |
1398 | "/etc/ssl/%s:%u.ocsp", hbuf, useport) == -1) |
1399 | goto fail; |
1400 | } else { |
1401 | if (snprintf(certfile, sizeof(certfile), |
1402 | "/etc/ssl/%s.ocsp", hbuf) == -1) |
1403 | goto fail; |
1404 | } |
1405 | if ((ocsp_fd = open(certfile, O_RDONLY0x0000)) != -1) |
1406 | log_debug("%s: using OCSP staple file %s", __func__, certfile); |
1407 | |
1408 | if ((cert = cert_add(env, 0)) == NULL((void*)0)) |
1409 | goto fail; |
1410 | |
1411 | cert->cert_relayid = rlay->rl_conf.id; |
1412 | cert->cert_fd = cert_fd; |
1413 | cert->cert_key_fd = key_fd; |
1414 | cert->cert_ocsp_fd = ocsp_fd; |
1415 | |
1416 | return (0); |
1417 | |
1418 | fail: |
1419 | if (cert_fd != -1) |
1420 | close(cert_fd); |
1421 | if (key_fd != -1) |
1422 | close(key_fd); |
1423 | if (ocsp_fd != -1) |
1424 | close(ocsp_fd); |
1425 | |
1426 | return (-1); |
1427 | } |
1428 | |
1429 | void |
1430 | event_again(struct event *ev, int fd, short event, |
1431 | void (*fn)(int, short, void *), |
1432 | struct timeval *start, struct timeval *end, void *arg) |
1433 | { |
1434 | struct timeval tv_next, tv_now, tv; |
1435 | |
1436 | getmonotime(&tv_now); |
1437 | bcopy(end, &tv_next, sizeof(tv_next)); |
1438 | timersub(&tv_now, start, &tv_now)do { (&tv_now)->tv_sec = (&tv_now)->tv_sec - (start )->tv_sec; (&tv_now)->tv_usec = (&tv_now)->tv_usec - (start)->tv_usec; if ((&tv_now)->tv_usec < 0) { (&tv_now)->tv_sec--; (&tv_now)->tv_usec += 1000000 ; } } while (0); |
1439 | timersub(&tv_next, &tv_now, &tv_next)do { (&tv_next)->tv_sec = (&tv_next)->tv_sec - ( &tv_now)->tv_sec; (&tv_next)->tv_usec = (&tv_next )->tv_usec - (&tv_now)->tv_usec; if ((&tv_next) ->tv_usec < 0) { (&tv_next)->tv_sec--; (&tv_next )->tv_usec += 1000000; } } while (0); |
1440 | |
1441 | bzero(&tv, sizeof(tv)); |
1442 | if (timercmp(&tv_next, &tv, >)(((&tv_next)->tv_sec == (&tv)->tv_sec) ? ((& tv_next)->tv_usec > (&tv)->tv_usec) : ((&tv_next )->tv_sec > (&tv)->tv_sec))) |
1443 | bcopy(&tv_next, &tv, sizeof(tv)); |
1444 | |
1445 | event_del(ev); |
1446 | event_set(ev, fd, event, fn, arg); |
1447 | event_add(ev, &tv); |
1448 | } |
1449 | |
1450 | int |
1451 | expand_string(char *label, size_t len, const char *srch, const char *repl) |
1452 | { |
1453 | char *tmp; |
1454 | char *p, *q; |
1455 | |
1456 | if ((tmp = calloc(1, len)) == NULL((void*)0)) { |
1457 | log_debug("%s: calloc", __func__); |
1458 | return (-1); |
1459 | } |
1460 | p = q = label; |
Although the value stored to 'q' is used in the enclosing expression, the value is never actually read from 'q' | |
1461 | while ((q = strstr(p, srch)) != NULL((void*)0)) { |
1462 | *q = '\0'; |
1463 | if ((strlcat(tmp, p, len) >= len) || |
1464 | (strlcat(tmp, repl, len) >= len)) { |
1465 | log_debug("%s: string too long", __func__); |
1466 | free(tmp); |
1467 | return (-1); |
1468 | } |
1469 | q += strlen(srch); |
1470 | p = q; |
1471 | } |
1472 | if (strlcat(tmp, p, len) >= len) { |
1473 | log_debug("%s: string too long", __func__); |
1474 | free(tmp); |
1475 | return (-1); |
1476 | } |
1477 | (void)strlcpy(label, tmp, len); /* always fits */ |
1478 | free(tmp); |
1479 | |
1480 | return (0); |
1481 | } |
1482 | |
1483 | void |
1484 | translate_string(char *str) |
1485 | { |
1486 | char *reader; |
1487 | char *writer; |
1488 | |
1489 | reader = writer = str; |
1490 | |
1491 | while (*reader) { |
1492 | if (*reader == '\\') { |
1493 | reader++; |
1494 | switch (*reader) { |
1495 | case 'n': |
1496 | *writer++ = '\n'; |
1497 | break; |
1498 | case 'r': |
1499 | *writer++ = '\r'; |
1500 | break; |
1501 | default: |
1502 | *writer++ = *reader; |
1503 | } |
1504 | } else |
1505 | *writer++ = *reader; |
1506 | reader++; |
1507 | } |
1508 | *writer = '\0'; |
1509 | } |
1510 | |
1511 | char * |
1512 | digeststr(enum digest_type type, const u_int8_t *data, size_t len, char *buf) |
1513 | { |
1514 | switch (type) { |
1515 | case DIGEST_SHA1: |
1516 | return (SHA1Data(data, len, buf)); |
1517 | break; |
1518 | case DIGEST_MD5: |
1519 | return (MD5Data(data, len, buf)); |
1520 | break; |
1521 | default: |
1522 | break; |
1523 | } |
1524 | return (NULL((void*)0)); |
1525 | } |
1526 | |
1527 | const char * |
1528 | canonicalize_host(const char *host, char *name, size_t len) |
1529 | { |
1530 | struct sockaddr_in sin4; |
1531 | struct sockaddr_in6 sin6; |
1532 | size_t i, j; |
1533 | size_t plen; |
1534 | char c; |
1535 | |
1536 | if (len < 2) |
1537 | goto fail; |
1538 | |
1539 | /* |
1540 | * Canonicalize an IPv4/6 address |
1541 | */ |
1542 | if (inet_pton(AF_INET2, host, &sin4) == 1) |
1543 | return (inet_ntop(AF_INET2, &sin4, name, len)); |
1544 | if (inet_pton(AF_INET624, host, &sin6) == 1) |
1545 | return (inet_ntop(AF_INET624, &sin6, name, len)); |
1546 | |
1547 | /* |
1548 | * Canonicalize a hostname |
1549 | */ |
1550 | |
1551 | /* 1. remove repeated dots and convert upper case to lower case */ |
1552 | plen = strlen(host); |
1553 | bzero(name, len); |
1554 | for (i = j = 0; i < plen; i++) { |
1555 | if (j >= (len - 1)) |
1556 | goto fail; |
1557 | c = tolower((unsigned char)host[i]); |
1558 | if ((c == '.') && (j == 0 || name[j - 1] == '.')) |
1559 | continue; |
1560 | name[j++] = c; |
1561 | } |
1562 | |
1563 | /* 2. remove trailing dots */ |
1564 | for (i = j; i > 0; i--) { |
1565 | if (name[i - 1] != '.') |
1566 | break; |
1567 | name[i - 1] = '\0'; |
1568 | j--; |
1569 | } |
1570 | if (j <= 0) |
1571 | goto fail; |
1572 | |
1573 | return (name); |
1574 | |
1575 | fail: |
1576 | errno(*__errno()) = EINVAL22; |
1577 | return (NULL((void*)0)); |
1578 | } |
1579 | |
1580 | int |
1581 | parse_url(const char *url, char **protoptr, char **hostptr, char **pathptr) |
1582 | { |
1583 | char *p, *proto = NULL((void*)0), *host = NULL((void*)0), *path = NULL((void*)0); |
1584 | |
1585 | /* return error if it is not a URL */ |
1586 | if ((p = strstr(url, ":/")) == NULL((void*)0) || |
1587 | (strcspn(url, ":/") != (size_t)(p - url))) |
1588 | return (-1); |
1589 | |
1590 | /* get protocol */ |
1591 | if ((proto = strdup(url)) == NULL((void*)0)) |
1592 | goto fail; |
1593 | p = proto + (p - url); |
1594 | |
1595 | /* get host */ |
1596 | p += strspn(p, ":/"); |
1597 | if (*p == '\0' || (host = strdup(p)) == NULL((void*)0)) |
1598 | goto fail; |
1599 | *p = '\0'; |
1600 | |
1601 | /* find and copy path or default to "/" */ |
1602 | if ((p = strchr(host, '/')) == NULL((void*)0)) |
1603 | p = "/"; |
1604 | if ((path = strdup(p)) == NULL((void*)0)) |
1605 | goto fail; |
1606 | |
1607 | /* strip path after host */ |
1608 | host[strcspn(host, "/")] = '\0'; |
1609 | |
1610 | DPRINTF("%s: %s proto %s, host %s, path %s", __func__,do {} while(0) |
1611 | url, proto, host, path)do {} while(0); |
1612 | |
1613 | *protoptr = proto; |
1614 | *hostptr = host; |
1615 | *pathptr = path; |
1616 | |
1617 | return (0); |
1618 | |
1619 | fail: |
1620 | free(proto); |
1621 | free(host); |
1622 | free(path); |
1623 | return (-1); |
1624 | } |
1625 | |
1626 | int |
1627 | bindany(struct ctl_bindany *bnd) |
1628 | { |
1629 | int s, v; |
1630 | |
1631 | s = -1; |
1632 | v = 1; |
1633 | |
1634 | if (relay_socket_af(&bnd->bnd_ss, bnd->bnd_port) == -1) |
1635 | goto fail; |
1636 | if ((s = socket(bnd->bnd_ss.ss_family, |
1637 | bnd->bnd_proto == IPPROTO_TCP6 ? SOCK_STREAM1 : SOCK_DGRAM2, |
1638 | bnd->bnd_proto)) == -1) |
1639 | goto fail; |
1640 | if (setsockopt(s, SOL_SOCKET0xffff, SO_BINDANY0x1000, |
1641 | &v, sizeof(v)) == -1) |
1642 | goto fail; |
1643 | if (bind(s, (struct sockaddr *)&bnd->bnd_ss, |
1644 | bnd->bnd_ss.ss_len) == -1) |
1645 | goto fail; |
1646 | |
1647 | return (s); |
1648 | |
1649 | fail: |
1650 | if (s != -1) |
1651 | close(s); |
1652 | return (-1); |
1653 | } |
1654 | |
1655 | int |
1656 | map6to4(struct sockaddr_storage *in6) |
1657 | { |
1658 | struct sockaddr_storage out4; |
1659 | struct sockaddr_in *sin4 = (struct sockaddr_in *)&out4; |
1660 | struct sockaddr_in6 *sin6 = (struct sockaddr_in6 *)in6; |
1661 | |
1662 | bzero(sin4, sizeof(*sin4)); |
1663 | sin4->sin_len = sizeof(*sin4); |
1664 | sin4->sin_family = AF_INET2; |
1665 | sin4->sin_port = sin6->sin6_port; |
1666 | |
1667 | bcopy(&sin6->sin6_addr.s6_addr__u6_addr.__u6_addr8[12], &sin4->sin_addr.s_addr, |
1668 | sizeof(sin4->sin_addr)); |
1669 | |
1670 | if (sin4->sin_addr.s_addr == INADDR_ANY((u_int32_t)(0x00000000)) || |
1671 | sin4->sin_addr.s_addr == INADDR_BROADCAST((u_int32_t)(0xffffffff)) || |
1672 | IN_MULTICAST(ntohl(sin4->sin_addr.s_addr))(((u_int32_t)((__uint32_t)(__builtin_constant_p(sin4->sin_addr .s_addr) ? (__uint32_t)(((__uint32_t)(sin4->sin_addr.s_addr ) & 0xff) << 24 | ((__uint32_t)(sin4->sin_addr.s_addr ) & 0xff00) << 8 | ((__uint32_t)(sin4->sin_addr. s_addr) & 0xff0000) >> 8 | ((__uint32_t)(sin4->sin_addr .s_addr) & 0xff000000) >> 24) : __swap32md(sin4-> sin_addr.s_addr))) & ((u_int32_t)(0xf0000000))) == ((u_int32_t )(0xe0000000)))) |
1673 | return (-1); |
1674 | |
1675 | bcopy(&out4, in6, sizeof(*in6)); |
1676 | |
1677 | return (0); |
1678 | } |
1679 | |
1680 | int |
1681 | map4to6(struct sockaddr_storage *in4, struct sockaddr_storage *map) |
1682 | { |
1683 | struct sockaddr_storage out6; |
1684 | struct sockaddr_in *sin4 = (struct sockaddr_in *)in4; |
1685 | struct sockaddr_in6 *sin6 = (struct sockaddr_in6 *)&out6; |
1686 | struct sockaddr_in6 *map6 = (struct sockaddr_in6 *)map; |
1687 | |
1688 | if (sin4->sin_addr.s_addr == INADDR_ANY((u_int32_t)(0x00000000)) || |
1689 | sin4->sin_addr.s_addr == INADDR_BROADCAST((u_int32_t)(0xffffffff)) || |
1690 | IN_MULTICAST(ntohl(sin4->sin_addr.s_addr))(((u_int32_t)((__uint32_t)(__builtin_constant_p(sin4->sin_addr .s_addr) ? (__uint32_t)(((__uint32_t)(sin4->sin_addr.s_addr ) & 0xff) << 24 | ((__uint32_t)(sin4->sin_addr.s_addr ) & 0xff00) << 8 | ((__uint32_t)(sin4->sin_addr. s_addr) & 0xff0000) >> 8 | ((__uint32_t)(sin4->sin_addr .s_addr) & 0xff000000) >> 24) : __swap32md(sin4-> sin_addr.s_addr))) & ((u_int32_t)(0xf0000000))) == ((u_int32_t )(0xe0000000)))) |
1691 | return (-1); |
1692 | |
1693 | bcopy(map6, sin6, sizeof(*sin6)); |
1694 | sin6->sin6_len = sizeof(*sin6); |
1695 | sin6->sin6_family = AF_INET624; |
1696 | sin6->sin6_port = sin4->sin_port; |
1697 | |
1698 | bcopy(&sin4->sin_addr.s_addr, &sin6->sin6_addr.s6_addr__u6_addr.__u6_addr8[12], |
1699 | sizeof(sin4->sin_addr)); |
1700 | |
1701 | bcopy(&out6, in4, sizeof(*in4)); |
1702 | |
1703 | return (0); |
1704 | } |
1705 | |
1706 | void |
1707 | socket_rlimit(int maxfd) |
1708 | { |
1709 | struct rlimit rl; |
1710 | |
1711 | if (getrlimit(RLIMIT_NOFILE8, &rl) == -1) |
1712 | fatal("%s: failed to get resource limit", __func__); |
1713 | log_debug("%s: max open files %llu", __func__, rl.rlim_max); |
1714 | |
1715 | /* |
1716 | * Allow the maximum number of open file descriptors for this |
1717 | * login class (which should be the class "daemon" by default). |
1718 | */ |
1719 | if (maxfd == -1) |
1720 | rl.rlim_cur = rl.rlim_max; |
1721 | else |
1722 | rl.rlim_cur = MAXIMUM(rl.rlim_max, (rlim_t)maxfd)(((rl.rlim_max) > ((rlim_t)maxfd)) ? (rl.rlim_max) : ((rlim_t )maxfd)); |
1723 | if (setrlimit(RLIMIT_NOFILE8, &rl) == -1) |
1724 | fatal("%s: failed to set resource limit", __func__); |
1725 | } |
1726 | |
1727 | char * |
1728 | get_string(u_int8_t *ptr, size_t len) |
1729 | { |
1730 | size_t i; |
1731 | |
1732 | for (i = 0; i < len; i++) |
1733 | if (!(isprint((unsigned char)ptr[i]) || |
1734 | isspace((unsigned char)ptr[i]))) |
1735 | break; |
1736 | |
1737 | return strndup(ptr, i); |
1738 | } |
1739 | |
1740 | void * |
1741 | get_data(u_int8_t *ptr, size_t len) |
1742 | { |
1743 | u_int8_t *data; |
1744 | |
1745 | if ((data = malloc(len)) == NULL((void*)0)) |
1746 | return (NULL((void*)0)); |
1747 | memcpy(data, ptr, len); |
1748 | |
1749 | return (data); |
1750 | } |
1751 | |
1752 | int |
1753 | sockaddr_cmp(struct sockaddr *a, struct sockaddr *b, int prefixlen) |
1754 | { |
1755 | struct sockaddr_in *a4, *b4; |
1756 | struct sockaddr_in6 *a6, *b6; |
1757 | u_int32_t av[4], bv[4], mv[4]; |
1758 | |
1759 | if (a->sa_family == AF_UNSPEC0 || b->sa_family == AF_UNSPEC0) |
1760 | return (0); |
1761 | else if (a->sa_family > b->sa_family) |
1762 | return (1); |
1763 | else if (a->sa_family < b->sa_family) |
1764 | return (-1); |
1765 | |
1766 | if (prefixlen == -1) |
1767 | memset(&mv, 0xff, sizeof(mv)); |
1768 | |
1769 | switch (a->sa_family) { |
1770 | case AF_INET2: |
1771 | a4 = (struct sockaddr_in *)a; |
1772 | b4 = (struct sockaddr_in *)b; |
1773 | |
1774 | av[0] = a4->sin_addr.s_addr; |
1775 | bv[0] = b4->sin_addr.s_addr; |
1776 | if (prefixlen != -1) |
1777 | mv[0] = prefixlen2mask(prefixlen); |
1778 | |
1779 | if ((av[0] & mv[0]) > (bv[0] & mv[0])) |
1780 | return (1); |
1781 | if ((av[0] & mv[0]) < (bv[0] & mv[0])) |
1782 | return (-1); |
1783 | break; |
1784 | case AF_INET624: |
1785 | a6 = (struct sockaddr_in6 *)a; |
1786 | b6 = (struct sockaddr_in6 *)b; |
1787 | |
1788 | memcpy(&av, &a6->sin6_addr.s6_addr__u6_addr.__u6_addr8, 16); |
1789 | memcpy(&bv, &b6->sin6_addr.s6_addr__u6_addr.__u6_addr8, 16); |
1790 | if (prefixlen != -1) |
1791 | prefixlen2mask6(prefixlen, mv); |
1792 | |
1793 | if ((av[3] & mv[3]) > (bv[3] & mv[3])) |
1794 | return (1); |
1795 | if ((av[3] & mv[3]) < (bv[3] & mv[3])) |
1796 | return (-1); |
1797 | if ((av[2] & mv[2]) > (bv[2] & mv[2])) |
1798 | return (1); |
1799 | if ((av[2] & mv[2]) < (bv[2] & mv[2])) |
1800 | return (-1); |
1801 | if ((av[1] & mv[1]) > (bv[1] & mv[1])) |
1802 | return (1); |
1803 | if ((av[1] & mv[1]) < (bv[1] & mv[1])) |
1804 | return (-1); |
1805 | if ((av[0] & mv[0]) > (bv[0] & mv[0])) |
1806 | return (1); |
1807 | if ((av[0] & mv[0]) < (bv[0] & mv[0])) |
1808 | return (-1); |
1809 | break; |
1810 | } |
1811 | |
1812 | return (0); |
1813 | } |
1814 | |
1815 | u_int32_t |
1816 | prefixlen2mask(u_int8_t prefixlen) |
1817 | { |
1818 | if (prefixlen == 0) |
1819 | return (0); |
1820 | |
1821 | if (prefixlen > 32) |
1822 | prefixlen = 32; |
1823 | |
1824 | return (htonl(0xffffffff << (32 - prefixlen))(__uint32_t)(__builtin_constant_p(0xffffffff << (32 - prefixlen )) ? (__uint32_t)(((__uint32_t)(0xffffffff << (32 - prefixlen )) & 0xff) << 24 | ((__uint32_t)(0xffffffff << (32 - prefixlen)) & 0xff00) << 8 | ((__uint32_t)(0xffffffff << (32 - prefixlen)) & 0xff0000) >> 8 | ((__uint32_t )(0xffffffff << (32 - prefixlen)) & 0xff000000) >> 24) : __swap32md(0xffffffff << (32 - prefixlen)))); |
1825 | } |
1826 | |
1827 | struct in6_addr * |
1828 | prefixlen2mask6(u_int8_t prefixlen, u_int32_t *mask) |
1829 | { |
1830 | static struct in6_addr s6; |
1831 | int i; |
1832 | |
1833 | if (prefixlen > 128) |
1834 | prefixlen = 128; |
1835 | |
1836 | bzero(&s6, sizeof(s6)); |
1837 | for (i = 0; i < prefixlen / 8; i++) |
1838 | s6.s6_addr__u6_addr.__u6_addr8[i] = 0xff; |
1839 | i = prefixlen % 8; |
1840 | if (i) |
1841 | s6.s6_addr__u6_addr.__u6_addr8[prefixlen / 8] = 0xff00 >> i; |
1842 | |
1843 | memcpy(mask, &s6, sizeof(s6)); |
1844 | |
1845 | return (&s6); |
1846 | } |
1847 | |
1848 | int |
1849 | accept_reserve(int sockfd, struct sockaddr *addr, socklen_t *addrlen, |
1850 | int reserve, volatile int *counter) |
1851 | { |
1852 | int ret; |
1853 | if (getdtablecount() + reserve + |
1854 | *counter >= getdtablesize()) { |
1855 | errno(*__errno()) = EMFILE24; |
1856 | return (-1); |
1857 | } |
1858 | |
1859 | if ((ret = accept4(sockfd, addr, addrlen, SOCK_NONBLOCK0x4000)) > -1) { |
1860 | (*counter)++; |
1861 | DPRINTF("%s: inflight incremented, now %d",__func__, *counter)do {} while(0); |
1862 | } |
1863 | return (ret); |
1864 | } |
1865 | |
1866 | void |
1867 | parent_tls_ticket_rekey(int fd, short events, void *arg) |
1868 | { |
1869 | static struct event rekeyev; |
1870 | struct relayd *env = arg; |
1871 | struct timeval tv; |
1872 | struct relay_ticket_key key; |
1873 | |
1874 | log_debug("%s: rekeying tickets", __func__); |
1875 | |
1876 | key.tt_keyrev = arc4random(); |
1877 | arc4random_buf(key.tt_key, sizeof(key.tt_key)); |
1878 | |
1879 | proc_compose_imsg(env->sc_ps, PROC_RELAY, -1, IMSG_TLSTICKET_REKEY, |
1880 | -1, -1, &key, sizeof(key)); |
1881 | |
1882 | evtimer_set(&rekeyev, parent_tls_ticket_rekey, env)event_set(&rekeyev, -1, 0, parent_tls_ticket_rekey, env); |
1883 | timerclear(&tv)(&tv)->tv_sec = (&tv)->tv_usec = 0; |
1884 | tv.tv_sec = TLS_SESSION_LIFETIME(2 * 3600) / 4; |
1885 | evtimer_add(&rekeyev, &tv)event_add(&rekeyev, &tv); |
1886 | } |