1*92388deeStb /* $OpenBSD: relayd.c,v 1.192 2024/10/28 19:56:18 tb Exp $ */ 2feb9ff76Sreyk 3feb9ff76Sreyk /* 48df09a06Sreyk * Copyright (c) 2007 - 2016 Reyk Floeter <reyk@openbsd.org> 536f5dc5eSpyr * Copyright (c) 2006 Pierre-Yves Ritschard <pyr@openbsd.org> 6feb9ff76Sreyk * 7feb9ff76Sreyk * Permission to use, copy, modify, and distribute this software for any 8feb9ff76Sreyk * purpose with or without fee is hereby granted, provided that the above 9feb9ff76Sreyk * copyright notice and this permission notice appear in all copies. 10feb9ff76Sreyk * 11feb9ff76Sreyk * THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES 12feb9ff76Sreyk * WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF 13feb9ff76Sreyk * MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR 14feb9ff76Sreyk * ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES 15feb9ff76Sreyk * WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN 16feb9ff76Sreyk * ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF 17feb9ff76Sreyk * OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE. 18feb9ff76Sreyk */ 19feb9ff76Sreyk 20feb9ff76Sreyk #include <sys/types.h> 21feb9ff76Sreyk #include <sys/queue.h> 22feb9ff76Sreyk #include <sys/socket.h> 23e938bb13Sreyk #include <sys/stat.h> 24feb9ff76Sreyk #include <sys/wait.h> 25bb8fa3feSreyk #include <sys/resource.h> 260ca734d7Sreyk 27812c1ce4Sreyk #include <netinet/in.h> 28812c1ce4Sreyk #include <arpa/inet.h> 290ca734d7Sreyk 30e2318a52Sderaadt #include <signal.h> 31feb9ff76Sreyk #include <string.h> 32feb9ff76Sreyk #include <stdio.h> 33feb9ff76Sreyk #include <stdlib.h> 34a2195becSreyk #include <fcntl.h> 35feb9ff76Sreyk #include <getopt.h> 36c307a266Sreyk #include <fnmatch.h> 370f12961aSreyk #include <syslog.h> 38feb9ff76Sreyk #include <err.h> 39feb9ff76Sreyk #include <errno.h> 40feb9ff76Sreyk #include <event.h> 41feb9ff76Sreyk #include <unistd.h> 427fd39c52Sreyk #include <ctype.h> 43feb9ff76Sreyk #include <pwd.h> 447ae0cc5eSreyk #include <sha1.h> 457ae0cc5eSreyk #include <md5.h> 46feb9ff76Sreyk 4785e5f500Sclaudio #include <tls.h> 48e8fb3979Spyr 49748ceb64Sreyk #include "relayd.h" 50feb9ff76Sreyk 51e2318a52Sderaadt #define MAXIMUM(a, b) (((a) > (b)) ? (a) : (b)) 52e2318a52Sderaadt 53feb9ff76Sreyk __dead void usage(void); 54feb9ff76Sreyk 55a2195becSreyk int parent_configure(struct relayd *); 560dcba380Scamield void parent_configure_done(struct relayd *); 57a2195becSreyk void parent_reload(struct relayd *, u_int, const char *); 580325c666Sreyk void parent_sig_handler(int, short, void *); 590325c666Sreyk void parent_shutdown(struct relayd *); 600325c666Sreyk int parent_dispatch_pfe(int, struct privsep_proc *, struct imsg *); 610325c666Sreyk int parent_dispatch_hce(int, struct privsep_proc *, struct imsg *); 62b1feadc4Sbluhm int parent_dispatch_relay(int, struct privsep_proc *, 63b1feadc4Sbluhm struct imsg *); 643d77879fSreyk int parent_dispatch_ca(int, struct privsep_proc *, 653d77879fSreyk struct imsg *); 663c03a838Sreyk int bindany(struct ctl_bindany *); 679c908525Sclaudio void parent_tls_ticket_rekey(int, short, void *); 68feb9ff76Sreyk 69748ceb64Sreyk struct relayd *relayd_env; 704156152fSreyk 710325c666Sreyk static struct privsep_proc procs[] = { 720325c666Sreyk { "pfe", PROC_PFE, parent_dispatch_pfe, pfe }, 730325c666Sreyk { "hce", PROC_HCE, parent_dispatch_hce, hce }, 743d77879fSreyk { "relay", PROC_RELAY, parent_dispatch_relay, relay }, 753d77879fSreyk { "ca", PROC_CA, parent_dispatch_ca, ca } 760325c666Sreyk }; 77feb9ff76Sreyk 78488a4384Sderaadt enum privsep_procid privsep_process; 79488a4384Sderaadt 80feb9ff76Sreyk void 810325c666Sreyk parent_sig_handler(int sig, short event, void *arg) 82feb9ff76Sreyk { 830325c666Sreyk struct privsep *ps = arg; 84feb9ff76Sreyk 85feb9ff76Sreyk switch (sig) { 86feb9ff76Sreyk case SIGTERM: 87feb9ff76Sreyk case SIGINT: 880325c666Sreyk parent_shutdown(ps->ps_env); 89feb9ff76Sreyk break; 90feb9ff76Sreyk case SIGHUP: 91a2195becSreyk log_info("%s: reload requested with SIGHUP", __func__); 92a2195becSreyk 93a2195becSreyk /* 94a2195becSreyk * This is safe because libevent uses async signal handlers 95a2195becSreyk * that run in the event loop and not in signal context. 96a2195becSreyk */ 97a2195becSreyk parent_reload(ps->ps_env, CONFIG_RELOAD, NULL); 98feb9ff76Sreyk break; 99c7867281Sreyk case SIGPIPE: 100fb6ac98aSreyk case SIGUSR1: 101c7867281Sreyk /* ignore */ 102c7867281Sreyk break; 103feb9ff76Sreyk default: 104feb9ff76Sreyk fatalx("unexpected signal"); 105feb9ff76Sreyk } 106feb9ff76Sreyk } 107feb9ff76Sreyk 108feb9ff76Sreyk __dead void 109feb9ff76Sreyk usage(void) 110feb9ff76Sreyk { 111feb9ff76Sreyk extern char *__progname; 112feb9ff76Sreyk 1133d5126eaSsobrado fprintf(stderr, "usage: %s [-dnv] [-D macro=value] [-f file]\n", 1143d5126eaSsobrado __progname); 115feb9ff76Sreyk exit(1); 116feb9ff76Sreyk } 117feb9ff76Sreyk 118034b8021Sreyk int 119034b8021Sreyk main(int argc, char *argv[]) 120feb9ff76Sreyk { 121feb9ff76Sreyk int c; 122a2195becSreyk int debug = 0, verbose = 0; 123a2195becSreyk u_int32_t opts = 0; 124748ceb64Sreyk struct relayd *env; 1250325c666Sreyk struct privsep *ps; 126a2195becSreyk const char *conffile = CONF_FILE; 1273d6ff6edSreyk enum privsep_procid proc_id = PROC_PARENT; 1283d6ff6edSreyk int proc_instance = 0; 1293d6ff6edSreyk const char *errp, *title = NULL; 1303d6ff6edSreyk int argc0 = argc; 131feb9ff76Sreyk 1323d6ff6edSreyk while ((c = getopt(argc, argv, "dD:nI:P:f:v")) != -1) { 133feb9ff76Sreyk switch (c) { 134feb9ff76Sreyk case 'd': 1359648e8e4Sreyk debug = 2; 136feb9ff76Sreyk break; 137e97970e4Sreyk case 'D': 138e97970e4Sreyk if (cmdline_symset(optarg) < 0) 139e97970e4Sreyk log_warnx("could not parse macro definition %s", 140e97970e4Sreyk optarg); 141e97970e4Sreyk break; 142feb9ff76Sreyk case 'n': 1439648e8e4Sreyk debug = 2; 144748ceb64Sreyk opts |= RELAYD_OPT_NOACTION; 145feb9ff76Sreyk break; 146feb9ff76Sreyk case 'f': 147feb9ff76Sreyk conffile = optarg; 148feb9ff76Sreyk break; 149feb9ff76Sreyk case 'v': 150a2195becSreyk verbose++; 151748ceb64Sreyk opts |= RELAYD_OPT_VERBOSE; 152feb9ff76Sreyk break; 1533d6ff6edSreyk case 'P': 1543d6ff6edSreyk title = optarg; 1553d6ff6edSreyk proc_id = proc_getid(procs, nitems(procs), title); 1563d6ff6edSreyk if (proc_id == PROC_MAX) 1573d6ff6edSreyk fatalx("invalid process name"); 1583d6ff6edSreyk break; 1593d6ff6edSreyk case 'I': 1603d6ff6edSreyk proc_instance = strtonum(optarg, 0, 1613d6ff6edSreyk PROC_MAX_INSTANCES, &errp); 1623d6ff6edSreyk if (errp) 1633d6ff6edSreyk fatalx("invalid process instance"); 1643d6ff6edSreyk break; 165feb9ff76Sreyk default: 166feb9ff76Sreyk usage(); 167feb9ff76Sreyk } 168feb9ff76Sreyk } 169feb9ff76Sreyk 1700f12961aSreyk /* log to stderr until daemonized */ 1710f12961aSreyk log_init(debug ? debug : 1, LOG_DAEMON); 172c413bde0Sokan 173fde55bc4Spyr argc -= optind; 174fde55bc4Spyr if (argc > 0) 175fde55bc4Spyr usage(); 176fde55bc4Spyr 177a2195becSreyk if ((env = calloc(1, sizeof(*env))) == NULL || 1780325c666Sreyk (ps = calloc(1, sizeof(*ps))) == NULL) 179feb9ff76Sreyk exit(1); 1800325c666Sreyk 181748ceb64Sreyk relayd_env = env; 1820325c666Sreyk env->sc_ps = ps; 1830325c666Sreyk ps->ps_env = env; 18461da45abSblambert TAILQ_INIT(&ps->ps_rcsocks); 185a2195becSreyk env->sc_conffile = conffile; 186586b5f8aSreyk env->sc_conf.opts = opts; 1876e07057bSblambert TAILQ_INIT(&env->sc_hosts); 1886e07057bSblambert TAILQ_INIT(&env->sc_sessions); 189005c709bSbenno env->sc_rtable = getrtable(); 1909c908525Sclaudio /* initialize the TLS session id to a random key for all relay procs */ 191586b5f8aSreyk arc4random_buf(env->sc_conf.tls_sid, sizeof(env->sc_conf.tls_sid)); 192feb9ff76Sreyk 193a2195becSreyk if (parse_config(env->sc_conffile, env) == -1) 194a2195becSreyk exit(1); 195a2195becSreyk 1962edd718bSreyk if (debug) 197586b5f8aSreyk env->sc_conf.opts |= RELAYD_OPT_LOGUPDATE; 198feb9ff76Sreyk 199feb9ff76Sreyk if (geteuid()) 200feb9ff76Sreyk errx(1, "need root privileges"); 201feb9ff76Sreyk 2020325c666Sreyk if ((ps->ps_pw = getpwnam(RELAYD_USER)) == NULL) 203748ceb64Sreyk errx(1, "unknown user %s", RELAYD_USER); 204feb9ff76Sreyk 2050f12961aSreyk log_init(debug, LOG_DAEMON); 206871fc12cSreyk log_setverbose(verbose); 207feb9ff76Sreyk 208586b5f8aSreyk if (env->sc_conf.opts & RELAYD_OPT_NOACTION) 209a2195becSreyk ps->ps_noaction = 1; 210feb9ff76Sreyk 211586b5f8aSreyk ps->ps_instances[PROC_RELAY] = env->sc_conf.prefork_relay; 212586b5f8aSreyk ps->ps_instances[PROC_CA] = env->sc_conf.prefork_relay; 2133d6ff6edSreyk ps->ps_instance = proc_instance; 2143d6ff6edSreyk if (title != NULL) 2153d6ff6edSreyk ps->ps_title[proc_id] = title; 2169326d639Sreyk 2173d6ff6edSreyk /* only the parent returns */ 21838b34180Sbluhm proc_init(ps, procs, nitems(procs), debug, argc0, argv, proc_id); 2193d6ff6edSreyk 2200f12961aSreyk log_procinit("parent"); 2213d6ff6edSreyk 2223d6ff6edSreyk if (ps->ps_noaction == 0) 2233d6ff6edSreyk log_info("startup"); 224feb9ff76Sreyk 22515e2c682Smestre if (unveil("/", "rx") == -1) 226bc5a8259Sbeck err(1, "unveil /"); 22715e2c682Smestre if (unveil(NULL, NULL) == -1) 22815e2c682Smestre err(1, "unveil"); 22915e2c682Smestre 230feb9ff76Sreyk event_init(); 231feb9ff76Sreyk 2320325c666Sreyk signal_set(&ps->ps_evsigint, SIGINT, parent_sig_handler, ps); 2330325c666Sreyk signal_set(&ps->ps_evsigterm, SIGTERM, parent_sig_handler, ps); 2340325c666Sreyk signal_set(&ps->ps_evsighup, SIGHUP, parent_sig_handler, ps); 2350325c666Sreyk signal_set(&ps->ps_evsigpipe, SIGPIPE, parent_sig_handler, ps); 236fb6ac98aSreyk signal_set(&ps->ps_evsigusr1, SIGUSR1, parent_sig_handler, ps); 237c7867281Sreyk 2380325c666Sreyk signal_add(&ps->ps_evsigint, NULL); 2390325c666Sreyk signal_add(&ps->ps_evsigterm, NULL); 2400325c666Sreyk signal_add(&ps->ps_evsighup, NULL); 2410325c666Sreyk signal_add(&ps->ps_evsigpipe, NULL); 242fb6ac98aSreyk signal_add(&ps->ps_evsigusr1, NULL); 243feb9ff76Sreyk 2443d6ff6edSreyk proc_connect(ps); 245a2195becSreyk 246627e062aSbluhm relay_http(NULL); 247a2195becSreyk if (load_config(env->sc_conffile, env) == -1) { 248a2195becSreyk proc_kill(env->sc_ps); 249a2195becSreyk exit(1); 250a2195becSreyk } 251a2195becSreyk 252586b5f8aSreyk if (env->sc_conf.opts & RELAYD_OPT_NOACTION) { 253a2195becSreyk fprintf(stderr, "configuration OK\n"); 254a2195becSreyk proc_kill(env->sc_ps); 255a2195becSreyk exit(0); 256a2195becSreyk } 257a2195becSreyk 2589c908525Sclaudio /* rekey the TLS tickets before pushing the config */ 2599c908525Sclaudio parent_tls_ticket_rekey(0, 0, env); 260a2195becSreyk if (parent_configure(env) == -1) 261a2195becSreyk fatalx("configuration failed"); 262a2195becSreyk 26334438db4Sreyk init_routes(env); 26434438db4Sreyk 265feb9ff76Sreyk event_dispatch(); 266feb9ff76Sreyk 2670325c666Sreyk parent_shutdown(env); 26834926236Sjsg /* NOTREACHED */ 269a2195becSreyk 270feb9ff76Sreyk return (0); 271feb9ff76Sreyk } 272feb9ff76Sreyk 273a2195becSreyk int 274a2195becSreyk parent_configure(struct relayd *env) 275a2195becSreyk { 276a2195becSreyk struct table *tb; 277a2195becSreyk struct rdr *rdr; 278a2195becSreyk struct router *rt; 279a2195becSreyk struct protocol *proto; 280a2195becSreyk struct relay *rlay; 281a2195becSreyk int id; 28205b29ae0Sbenno int ret = -1; 283a2195becSreyk 284a2195becSreyk TAILQ_FOREACH(tb, env->sc_tables, entry) 285a2195becSreyk config_settable(env, tb); 286a2195becSreyk TAILQ_FOREACH(rdr, env->sc_rdrs, entry) 287a2195becSreyk config_setrdr(env, rdr); 288a2195becSreyk TAILQ_FOREACH(rt, env->sc_rts, rt_entry) 289a2195becSreyk config_setrt(env, rt); 290a2195becSreyk TAILQ_FOREACH(proto, env->sc_protos, entry) 291a2195becSreyk config_setproto(env, proto); 292cb8b0e56Sreyk TAILQ_FOREACH(proto, env->sc_protos, entry) 293cb8b0e56Sreyk config_setrule(env, proto); 294cf39ad79Sreyk TAILQ_FOREACH(rlay, env->sc_relays, rl_entry) { 2957bb52228Sreyk /* Check for TLS Inspection */ 2967bb52228Sreyk if ((rlay->rl_conf.flags & (F_TLS|F_TLSCLIENT)) == 297114ce177Sclaudio (F_TLS|F_TLSCLIENT) && rlay->rl_tls_cacert_fd != -1) 2987bb52228Sreyk rlay->rl_conf.flags |= F_TLSINSPECT; 299cf39ad79Sreyk 300a2195becSreyk config_setrelay(env, rlay); 301cf39ad79Sreyk } 302a2195becSreyk 3033d77879fSreyk /* HCE, PFE, CA and the relays need to reload their config. */ 304586b5f8aSreyk env->sc_reload = 2 + (2 * env->sc_conf.prefork_relay); 3050dcba380Scamield 306a2195becSreyk for (id = 0; id < PROC_MAX; id++) { 307a2195becSreyk if (id == privsep_process) 308a2195becSreyk continue; 309c2c37c5dSreyk proc_compose_imsg(env->sc_ps, id, -1, IMSG_CFG_DONE, -1, 31005b29ae0Sbenno -1, &env->sc_conf, sizeof(env->sc_conf)); 311a2195becSreyk } 312a2195becSreyk 313a2195becSreyk ret = 0; 314a2195becSreyk 3153d77879fSreyk config_purge(env, CONFIG_ALL & ~CONFIG_RELAYS); 316a2195becSreyk return (ret); 317a2195becSreyk } 318a2195becSreyk 319a2195becSreyk void 320a2195becSreyk parent_reload(struct relayd *env, u_int reset, const char *filename) 321a2195becSreyk { 322a2195becSreyk if (env->sc_reload) { 323a2195becSreyk log_debug("%s: already in progress: %d pending", 324a2195becSreyk __func__, env->sc_reload); 325a2195becSreyk return; 326a2195becSreyk } 327a2195becSreyk 328a2195becSreyk /* Switch back to the default config file */ 329a2195becSreyk if (filename == NULL || *filename == '\0') 330a2195becSreyk filename = env->sc_conffile; 331a2195becSreyk 332a2195becSreyk log_debug("%s: level %d config file %s", __func__, reset, filename); 333a2195becSreyk 334a2195becSreyk config_purge(env, CONFIG_ALL); 335a2195becSreyk 336a2195becSreyk if (reset == CONFIG_RELOAD) { 337a2195becSreyk if (load_config(filename, env) == -1) { 338a2195becSreyk log_debug("%s: failed to load config file %s", 339a2195becSreyk __func__, filename); 340a2195becSreyk } 341a2195becSreyk 342a2195becSreyk config_setreset(env, CONFIG_ALL); 343a2195becSreyk 344a2195becSreyk if (parent_configure(env) == -1) { 345a2195becSreyk log_debug("%s: failed to commit config from %s", 346a2195becSreyk __func__, filename); 347a2195becSreyk } 348a2195becSreyk } else 349a2195becSreyk config_setreset(env, reset); 350a2195becSreyk } 351a2195becSreyk 352feb9ff76Sreyk void 3530dcba380Scamield parent_configure_done(struct relayd *env) 3540dcba380Scamield { 3550dcba380Scamield int id; 3560dcba380Scamield 3570dcba380Scamield if (env->sc_reload == 0) { 3580dcba380Scamield log_warnx("%s: configuration already finished", __func__); 3590dcba380Scamield return; 3600dcba380Scamield } 3610dcba380Scamield 3620dcba380Scamield env->sc_reload--; 3630dcba380Scamield if (env->sc_reload == 0) { 3640dcba380Scamield for (id = 0; id < PROC_MAX; id++) { 3650dcba380Scamield if (id == privsep_process) 3660dcba380Scamield continue; 3670dcba380Scamield 368c2c37c5dSreyk proc_compose(env->sc_ps, id, IMSG_CTL_START, NULL, 0); 3690dcba380Scamield } 3700dcba380Scamield } 3710dcba380Scamield } 3720dcba380Scamield 3730dcba380Scamield void 3740325c666Sreyk parent_shutdown(struct relayd *env) 375feb9ff76Sreyk { 376a2195becSreyk config_purge(env, CONFIG_ALL); 377a2195becSreyk 3780325c666Sreyk proc_kill(env->sc_ps); 3790325c666Sreyk control_cleanup(&env->sc_ps->ps_csock); 3802edd718bSreyk carp_demote_shutdown(); 3810325c666Sreyk 3820325c666Sreyk free(env->sc_ps); 3830325c666Sreyk free(env); 3840325c666Sreyk 3850325c666Sreyk log_info("parent terminating, pid %d", getpid()); 3860325c666Sreyk 387feb9ff76Sreyk exit(0); 388feb9ff76Sreyk } 389feb9ff76Sreyk 3900229c564Spyr int 3910325c666Sreyk parent_dispatch_pfe(int fd, struct privsep_proc *p, struct imsg *imsg) 3920229c564Spyr { 393d0cb169fSreyk struct privsep *ps = p->p_ps; 394d0cb169fSreyk struct relayd *env = ps->ps_env; 3952edd718bSreyk struct ctl_demote demote; 39634438db4Sreyk struct ctl_netroute crt; 397a2195becSreyk u_int v; 398a2195becSreyk char *str = NULL; 399feb9ff76Sreyk 4000325c666Sreyk switch (imsg->hdr.type) { 4012edd718bSreyk case IMSG_DEMOTE: 4020325c666Sreyk IMSG_SIZE_CHECK(imsg, &demote); 4030325c666Sreyk memcpy(&demote, imsg->data, sizeof(demote)); 4042edd718bSreyk carp_demote_set(demote.group, demote.level); 4052edd718bSreyk break; 40634438db4Sreyk case IMSG_RTMSG: 4070325c666Sreyk IMSG_SIZE_CHECK(imsg, &crt); 4080325c666Sreyk memcpy(&crt, imsg->data, sizeof(crt)); 40934438db4Sreyk pfe_route(env, &crt); 41034438db4Sreyk break; 411a2195becSreyk case IMSG_CTL_RESET: 412a2195becSreyk IMSG_SIZE_CHECK(imsg, &v); 413a2195becSreyk memcpy(&v, imsg->data, sizeof(v)); 414a2195becSreyk parent_reload(env, v, NULL); 415a2195becSreyk break; 416c8bdf044Spyr case IMSG_CTL_RELOAD: 417a2195becSreyk if (IMSG_DATA_SIZE(imsg) > 0) 418a2195becSreyk str = get_string(imsg->data, IMSG_DATA_SIZE(imsg)); 419a2195becSreyk parent_reload(env, CONFIG_RELOAD, str); 420a2195becSreyk free(str); 421a2195becSreyk break; 422a2195becSreyk case IMSG_CTL_SHUTDOWN: 423a2195becSreyk parent_shutdown(env); 424a2195becSreyk break; 425a2195becSreyk case IMSG_CFG_DONE: 4260dcba380Scamield parent_configure_done(env); 427c8bdf044Spyr break; 428c26b8e61Smartijn case IMSG_AGENTXSOCK: 4294172793dSdv agentx_setsock(env, p->p_id); 4306e07057bSblambert break; 431feb9ff76Sreyk default: 4320325c666Sreyk return (-1); 433feb9ff76Sreyk } 434feb9ff76Sreyk 4350325c666Sreyk return (0); 4360325c666Sreyk } 4370325c666Sreyk 4380325c666Sreyk int 4390325c666Sreyk parent_dispatch_hce(int fd, struct privsep_proc *p, struct imsg *imsg) 440feb9ff76Sreyk { 441d0cb169fSreyk struct privsep *ps = p->p_ps; 442d0cb169fSreyk struct relayd *env = ps->ps_env; 4434156152fSreyk struct ctl_script scr; 444feb9ff76Sreyk 4450325c666Sreyk switch (imsg->hdr.type) { 4464156152fSreyk case IMSG_SCRIPT: 4470325c666Sreyk IMSG_SIZE_CHECK(imsg, &scr); 4480325c666Sreyk bcopy(imsg->data, &scr, sizeof(scr)); 4494156152fSreyk scr.retval = script_exec(env, &scr); 450c2c37c5dSreyk proc_compose(ps, PROC_HCE, IMSG_SCRIPT, &scr, sizeof(scr)); 4514156152fSreyk break; 452a2195becSreyk case IMSG_CFG_DONE: 4530dcba380Scamield parent_configure_done(env); 454fe250497Sreyk break; 455feb9ff76Sreyk default: 4560325c666Sreyk return (-1); 457feb9ff76Sreyk } 458feb9ff76Sreyk 4590325c666Sreyk return (0); 4600325c666Sreyk } 4610325c666Sreyk 4620325c666Sreyk int 4630325c666Sreyk parent_dispatch_relay(int fd, struct privsep_proc *p, struct imsg *imsg) 4642edd718bSreyk { 465d0cb169fSreyk struct privsep *ps = p->p_ps; 466d0cb169fSreyk struct relayd *env = ps->ps_env; 4673c03a838Sreyk struct ctl_bindany bnd; 4683c03a838Sreyk int s; 4692edd718bSreyk 4700325c666Sreyk switch (imsg->hdr.type) { 4713c03a838Sreyk case IMSG_BINDANY: 4720325c666Sreyk IMSG_SIZE_CHECK(imsg, &bnd); 4730325c666Sreyk bcopy(imsg->data, &bnd, sizeof(bnd)); 474586b5f8aSreyk if (bnd.bnd_proc > env->sc_conf.prefork_relay) 475efc39811Sbenno fatalx("%s: invalid relay proc", __func__); 4763c03a838Sreyk switch (bnd.bnd_proto) { 4773c03a838Sreyk case IPPROTO_TCP: 4783c03a838Sreyk case IPPROTO_UDP: 4793c03a838Sreyk break; 4803c03a838Sreyk default: 481efc39811Sbenno fatalx("%s: requested socket " 482efc39811Sbenno "for invalid protocol", __func__); 4833c03a838Sreyk /* NOTREACHED */ 4843c03a838Sreyk } 4853c03a838Sreyk s = bindany(&bnd); 4860325c666Sreyk proc_compose_imsg(ps, PROC_RELAY, bnd.bnd_proc, 487c2c37c5dSreyk IMSG_BINDANY, -1, s, &bnd.bnd_id, sizeof(bnd.bnd_id)); 4883c03a838Sreyk break; 489a2195becSreyk case IMSG_CFG_DONE: 4900dcba380Scamield parent_configure_done(env); 491a2195becSreyk break; 4922edd718bSreyk default: 4930325c666Sreyk return (-1); 4942edd718bSreyk } 4950325c666Sreyk 4960325c666Sreyk return (0); 4972edd718bSreyk } 4982edd718bSreyk 4993d77879fSreyk int 5003d77879fSreyk parent_dispatch_ca(int fd, struct privsep_proc *p, struct imsg *imsg) 5013d77879fSreyk { 502d0cb169fSreyk struct privsep *ps = p->p_ps; 503d0cb169fSreyk struct relayd *env = ps->ps_env; 5043d77879fSreyk 5053d77879fSreyk switch (imsg->hdr.type) { 5063d77879fSreyk case IMSG_CFG_DONE: 5073d77879fSreyk parent_configure_done(env); 5083d77879fSreyk break; 5093d77879fSreyk default: 5103d77879fSreyk return (-1); 5113d77879fSreyk } 5123d77879fSreyk 5133d77879fSreyk return (0); 5143d77879fSreyk } 5153d77879fSreyk 516a2195becSreyk void 5172c8c2287Sclaudio purge_table(struct relayd *env, struct tablelist *head, struct table *table) 518a2195becSreyk { 519a2195becSreyk struct host *host; 520a2195becSreyk 521a2195becSreyk while ((host = TAILQ_FIRST(&table->hosts)) != NULL) { 522a2195becSreyk TAILQ_REMOVE(&table->hosts, host, entry); 5232c8c2287Sclaudio TAILQ_REMOVE(&env->sc_hosts, host, globalentry); 524a2195becSreyk if (event_initialized(&host->cte.ev)) { 525a2195becSreyk event_del(&host->cte.ev); 526a2195becSreyk close(host->cte.s); 527a2195becSreyk } 528a2195becSreyk ibuf_free(host->cte.buf); 52985e5f500Sclaudio tls_free(host->cte.tls); 530a2195becSreyk free(host); 531a2195becSreyk } 532a2195becSreyk free(table->sendbuf); 5333f229715Srob ibuf_free(table->sendbinbuf); 53485e5f500Sclaudio tls_config_free(table->tls_cfg); 535a2195becSreyk 536a2195becSreyk if (head != NULL) 537a2195becSreyk TAILQ_REMOVE(head, table, entry); 538a2195becSreyk free(table); 539a2195becSreyk } 540a2195becSreyk 541a2195becSreyk void 54202a7d0f3Sfcambus purge_key(char **key, off_t len) 5433d77879fSreyk { 54402a7d0f3Sfcambus freezero(*key, len); 5453d77879fSreyk 54602a7d0f3Sfcambus *key = NULL; 5473d77879fSreyk } 5483d77879fSreyk 5493d77879fSreyk void 550a2195becSreyk purge_relay(struct relayd *env, struct relay *rlay) 551a2195becSreyk { 552a2195becSreyk struct rsession *con; 553416fa9c0Sreyk struct relay_table *rlt; 554f2f4e153Sreyk struct relay_cert *cert, *tmpcert; 555a2195becSreyk 556a2195becSreyk /* shutdown and remove relay */ 557a2195becSreyk if (event_initialized(&rlay->rl_ev)) 558a2195becSreyk event_del(&rlay->rl_ev); 559a2195becSreyk close(rlay->rl_s); 560a2195becSreyk TAILQ_REMOVE(env->sc_relays, rlay, rl_entry); 561a2195becSreyk 562a2195becSreyk /* cleanup sessions */ 563a2195becSreyk while ((con = 564a2195becSreyk SPLAY_ROOT(&rlay->rl_sessions)) != NULL) 5650be9d00aSbenno relay_close(con, NULL, 0); 566a2195becSreyk 567a2195becSreyk /* cleanup relay */ 568a2195becSreyk if (rlay->rl_bev != NULL) 569a2195becSreyk bufferevent_free(rlay->rl_bev); 570a2195becSreyk if (rlay->rl_dstbev != NULL) 571a2195becSreyk bufferevent_free(rlay->rl_dstbev); 572a2195becSreyk 5737bb52228Sreyk purge_key(&rlay->rl_tls_cakey, rlay->rl_conf.tls_cakey_len); 5743d77879fSreyk 5757bb52228Sreyk if (rlay->rl_tls_pkey != NULL) { 5767bb52228Sreyk EVP_PKEY_free(rlay->rl_tls_pkey); 5777bb52228Sreyk rlay->rl_tls_pkey = NULL; 5783d77879fSreyk } 5797bb52228Sreyk if (rlay->rl_tls_cacertx509 != NULL) { 5807bb52228Sreyk X509_free(rlay->rl_tls_cacertx509); 5817bb52228Sreyk rlay->rl_tls_cacertx509 = NULL; 58200ae3104Sreyk } 5837bb52228Sreyk if (rlay->rl_tls_capkey != NULL) { 5847bb52228Sreyk EVP_PKEY_free(rlay->rl_tls_capkey); 5857bb52228Sreyk rlay->rl_tls_capkey = NULL; 58600ae3104Sreyk } 5873d77879fSreyk 58885e5f500Sclaudio tls_free(rlay->rl_tls_ctx); 58985e5f500Sclaudio tls_config_free(rlay->rl_tls_cfg); 59085e5f500Sclaudio tls_config_free(rlay->rl_tls_client_cfg); 591a2195becSreyk 592416fa9c0Sreyk while ((rlt = TAILQ_FIRST(&rlay->rl_tables))) { 593416fa9c0Sreyk TAILQ_REMOVE(&rlay->rl_tables, rlt, rlt_entry); 594416fa9c0Sreyk free(rlt); 595416fa9c0Sreyk } 596416fa9c0Sreyk 597f2f4e153Sreyk TAILQ_FOREACH_SAFE(cert, env->sc_certs, cert_entry, tmpcert) { 598f2f4e153Sreyk if (rlay->rl_conf.id != cert->cert_relayid) 599f2f4e153Sreyk continue; 600f2f4e153Sreyk if (cert->cert_fd != -1) 601f2f4e153Sreyk close(cert->cert_fd); 602f2f4e153Sreyk if (cert->cert_key_fd != -1) 603f2f4e153Sreyk close(cert->cert_key_fd); 60431604b98Sreyk if (cert->cert_ocsp_fd != -1) 60531604b98Sreyk close(cert->cert_ocsp_fd); 606f2f4e153Sreyk if (cert->cert_pkey != NULL) 607f2f4e153Sreyk EVP_PKEY_free(cert->cert_pkey); 608f2f4e153Sreyk TAILQ_REMOVE(env->sc_certs, cert, cert_entry); 609f2f4e153Sreyk free(cert); 610f2f4e153Sreyk } 611f2f4e153Sreyk 612a2195becSreyk free(rlay); 613a2195becSreyk } 614a2195becSreyk 615cb8b0e56Sreyk struct kv * 616c9822c56Sreyk kv_add(struct kvtree *keys, char *key, char *value, int unique) 617cb8b0e56Sreyk { 618c307a266Sreyk struct kv *kv, *oldkv; 619cb8b0e56Sreyk 620cb8b0e56Sreyk if (key == NULL) 621cb8b0e56Sreyk return (NULL); 622cb8b0e56Sreyk if ((kv = calloc(1, sizeof(*kv))) == NULL) 623cb8b0e56Sreyk return (NULL); 624c9822c56Sreyk if ((kv->kv_key = strdup(key)) == NULL) 625c9822c56Sreyk goto fail; 626cb8b0e56Sreyk if (value != NULL && 627c9822c56Sreyk (kv->kv_value = strdup(value)) == NULL) 628c9822c56Sreyk goto fail; 629c307a266Sreyk TAILQ_INIT(&kv->kv_children); 630cb8b0e56Sreyk 631c307a266Sreyk if ((oldkv = RB_INSERT(kvtree, keys, kv)) != NULL) { 632c9822c56Sreyk /* 633c9822c56Sreyk * return error if the key should occur only once, 634c9822c56Sreyk * or add it to a list attached to the key's node. 635c9822c56Sreyk */ 636c9822c56Sreyk if (unique) 637c9822c56Sreyk goto fail; 638c307a266Sreyk TAILQ_INSERT_TAIL(&oldkv->kv_children, kv, kv_entry); 639c307a266Sreyk kv->kv_parent = oldkv; 640c307a266Sreyk } 641cb8b0e56Sreyk 642cb8b0e56Sreyk return (kv); 643c9822c56Sreyk fail: 644c9822c56Sreyk free(kv->kv_key); 645c9822c56Sreyk free(kv->kv_value); 646c9822c56Sreyk free(kv); 647c9822c56Sreyk return (NULL); 648cb8b0e56Sreyk } 649cb8b0e56Sreyk 650cb8b0e56Sreyk int 651cb8b0e56Sreyk kv_set(struct kv *kv, char *fmt, ...) 652cb8b0e56Sreyk { 653cb8b0e56Sreyk va_list ap; 654cb8b0e56Sreyk char *value = NULL; 655c307a266Sreyk struct kv *ckv; 6566eb056bfSmbuhl int ret; 657cb8b0e56Sreyk 658cb8b0e56Sreyk va_start(ap, fmt); 6596eb056bfSmbuhl ret = vasprintf(&value, fmt, ap); 660cb8b0e56Sreyk va_end(ap); 6616eb056bfSmbuhl if (ret == -1) 6626eb056bfSmbuhl return (-1); 663cb8b0e56Sreyk 664c307a266Sreyk /* Remove all children */ 665c307a266Sreyk while ((ckv = TAILQ_FIRST(&kv->kv_children)) != NULL) { 666c307a266Sreyk TAILQ_REMOVE(&kv->kv_children, ckv, kv_entry); 667c307a266Sreyk kv_free(ckv); 668c307a266Sreyk free(ckv); 669c307a266Sreyk } 670c307a266Sreyk 671c307a266Sreyk /* Set the new value */ 672cb8b0e56Sreyk free(kv->kv_value); 673cb8b0e56Sreyk kv->kv_value = value; 674cb8b0e56Sreyk 675cb8b0e56Sreyk return (0); 676cb8b0e56Sreyk } 677cb8b0e56Sreyk 678cb8b0e56Sreyk int 679cb8b0e56Sreyk kv_setkey(struct kv *kv, char *fmt, ...) 680cb8b0e56Sreyk { 681cb8b0e56Sreyk va_list ap; 682cb8b0e56Sreyk char *key = NULL; 6836eb056bfSmbuhl int ret; 684cb8b0e56Sreyk 685cb8b0e56Sreyk va_start(ap, fmt); 6866eb056bfSmbuhl ret = vasprintf(&key, fmt, ap); 687cb8b0e56Sreyk va_end(ap); 6886eb056bfSmbuhl if (ret == -1) 6896eb056bfSmbuhl return (-1); 690cb8b0e56Sreyk 691cb8b0e56Sreyk free(kv->kv_key); 692cb8b0e56Sreyk kv->kv_key = key; 693cb8b0e56Sreyk 694cb8b0e56Sreyk return (0); 695cb8b0e56Sreyk } 696cb8b0e56Sreyk 697cb8b0e56Sreyk void 698c307a266Sreyk kv_delete(struct kvtree *keys, struct kv *kv) 699cb8b0e56Sreyk { 700c307a266Sreyk struct kv *ckv; 701c307a266Sreyk 702c307a266Sreyk RB_REMOVE(kvtree, keys, kv); 703c307a266Sreyk 704c307a266Sreyk /* Remove all children */ 705c307a266Sreyk while ((ckv = TAILQ_FIRST(&kv->kv_children)) != NULL) { 706c307a266Sreyk TAILQ_REMOVE(&kv->kv_children, ckv, kv_entry); 707c307a266Sreyk kv_free(ckv); 708c307a266Sreyk free(ckv); 709c307a266Sreyk } 710c307a266Sreyk 711cb8b0e56Sreyk kv_free(kv); 712cb8b0e56Sreyk free(kv); 713cb8b0e56Sreyk } 714cb8b0e56Sreyk 715cb8b0e56Sreyk struct kv * 716c307a266Sreyk kv_extend(struct kvtree *keys, struct kv *kv, char *value) 717cb8b0e56Sreyk { 718cb8b0e56Sreyk char *newvalue; 719cb8b0e56Sreyk 720c307a266Sreyk if (kv == NULL) { 721cb8b0e56Sreyk return (NULL); 722c307a266Sreyk } else if (kv->kv_value != NULL) { 723637827c8Sreyk if (asprintf(&newvalue, "%s%s", kv->kv_value, value) == -1) 724cb8b0e56Sreyk return (NULL); 725cb8b0e56Sreyk 726cb8b0e56Sreyk free(kv->kv_value); 727cb8b0e56Sreyk kv->kv_value = newvalue; 728637827c8Sreyk } else if ((kv->kv_value = strdup(value)) == NULL) 729637827c8Sreyk return (NULL); 730cb8b0e56Sreyk 731cb8b0e56Sreyk return (kv); 732cb8b0e56Sreyk } 733cb8b0e56Sreyk 734cb8b0e56Sreyk void 735c307a266Sreyk kv_purge(struct kvtree *keys) 736cb8b0e56Sreyk { 737cb8b0e56Sreyk struct kv *kv; 738cb8b0e56Sreyk 739c307a266Sreyk while ((kv = RB_MIN(kvtree, keys)) != NULL) 740cb8b0e56Sreyk kv_delete(keys, kv); 741cb8b0e56Sreyk } 742cb8b0e56Sreyk 743cb8b0e56Sreyk void 744cb8b0e56Sreyk kv_free(struct kv *kv) 745cb8b0e56Sreyk { 746230b3145Sclaudio /* 747230b3145Sclaudio * This function does not clear memory referenced by 748230b3145Sclaudio * kv_children or stuff on the tailqs. Use kv_delete() instead. 749230b3145Sclaudio */ 750230b3145Sclaudio 751cb8b0e56Sreyk free(kv->kv_key); 752cb8b0e56Sreyk free(kv->kv_value); 753cb8b0e56Sreyk memset(kv, 0, sizeof(*kv)); 754cb8b0e56Sreyk } 755cb8b0e56Sreyk 756cb8b0e56Sreyk struct kv * 757cb8b0e56Sreyk kv_inherit(struct kv *dst, struct kv *src) 758cb8b0e56Sreyk { 759cb8b0e56Sreyk memset(dst, 0, sizeof(*dst)); 760cb8b0e56Sreyk memcpy(dst, src, sizeof(*dst)); 761c307a266Sreyk TAILQ_INIT(&dst->kv_children); 762cb8b0e56Sreyk 763cb8b0e56Sreyk if (src->kv_key != NULL) { 764cb8b0e56Sreyk if ((dst->kv_key = strdup(src->kv_key)) == NULL) { 765cb8b0e56Sreyk kv_free(dst); 766cb8b0e56Sreyk return (NULL); 767cb8b0e56Sreyk } 768cb8b0e56Sreyk } 769cb8b0e56Sreyk if (src->kv_value != NULL) { 770cb8b0e56Sreyk if ((dst->kv_value = strdup(src->kv_value)) == NULL) { 771cb8b0e56Sreyk kv_free(dst); 772cb8b0e56Sreyk return (NULL); 773cb8b0e56Sreyk } 774cb8b0e56Sreyk } 775cb8b0e56Sreyk 776cb8b0e56Sreyk if (src->kv_match != NULL) 777cb8b0e56Sreyk dst->kv_match = src->kv_match; 778c307a266Sreyk if (src->kv_matchtree != NULL) 779c307a266Sreyk dst->kv_matchtree = src->kv_matchtree; 780cb8b0e56Sreyk 781cb8b0e56Sreyk return (dst); 782cb8b0e56Sreyk } 783cb8b0e56Sreyk 784cb8b0e56Sreyk int 785c84d6099Sbenno kv_log(struct rsession *con, struct kv *kv, u_int16_t labelid, 786c84d6099Sbenno enum direction dir) 787cb8b0e56Sreyk { 788cb8b0e56Sreyk char *msg; 789cb8b0e56Sreyk 790c84d6099Sbenno if (con->se_log == NULL) 791cb8b0e56Sreyk return (0); 792c84d6099Sbenno if (asprintf(&msg, " %s%s%s%s%s%s%s", 793c84d6099Sbenno dir == RELAY_DIR_REQUEST ? "[" : "{", 794cb8b0e56Sreyk labelid == 0 ? "" : label_id2name(labelid), 795cb8b0e56Sreyk labelid == 0 ? "" : ", ", 796cb8b0e56Sreyk kv->kv_key == NULL ? "(unknown)" : kv->kv_key, 797cb8b0e56Sreyk kv->kv_value == NULL ? "" : ": ", 798c84d6099Sbenno kv->kv_value == NULL ? "" : kv->kv_value, 799c84d6099Sbenno dir == RELAY_DIR_REQUEST ? "]" : "}") == -1) 800cb8b0e56Sreyk return (-1); 801c84d6099Sbenno if (evbuffer_add(con->se_log, msg, strlen(msg)) == -1) { 802cb8b0e56Sreyk free(msg); 803cb8b0e56Sreyk return (-1); 804cb8b0e56Sreyk } 805cb8b0e56Sreyk free(msg); 806c84d6099Sbenno con->se_haslog = 1; 807cb8b0e56Sreyk return (0); 808cb8b0e56Sreyk } 809cb8b0e56Sreyk 810c307a266Sreyk struct kv * 811c307a266Sreyk kv_find(struct kvtree *keys, struct kv *kv) 812c307a266Sreyk { 813c307a266Sreyk struct kv *match; 814c307a266Sreyk const char *key; 815c307a266Sreyk 816c307a266Sreyk if (kv->kv_flags & KV_FLAG_GLOBBING) { 817c307a266Sreyk /* Test header key using shell globbing rules */ 818c307a266Sreyk key = kv->kv_key == NULL ? "" : kv->kv_key; 819c307a266Sreyk RB_FOREACH(match, kvtree, keys) { 820c307a266Sreyk if (fnmatch(key, match->kv_key, FNM_CASEFOLD) == 0) 821c307a266Sreyk break; 822c307a266Sreyk } 823c307a266Sreyk } else { 824c307a266Sreyk /* Fast tree-based lookup only works without globbing */ 825c307a266Sreyk match = RB_FIND(kvtree, keys, kv); 826c307a266Sreyk } 827c307a266Sreyk 828c307a266Sreyk return (match); 829c307a266Sreyk } 830c307a266Sreyk 831a168ef1aSreyk struct kv * 832a168ef1aSreyk kv_find_value(struct kvtree *keys, char *key, const char *value, 833a168ef1aSreyk const char *delim) 834a168ef1aSreyk { 835a168ef1aSreyk struct kv *match, kv; 836a168ef1aSreyk char *val = NULL, *next, *ptr; 837a168ef1aSreyk size_t len; 838a168ef1aSreyk 839a168ef1aSreyk kv.kv_key = key; 840a168ef1aSreyk if ((match = RB_FIND(kvtree, keys, &kv)) == NULL) 841a168ef1aSreyk return (NULL); 842a168ef1aSreyk 843a168ef1aSreyk if (match->kv_value == NULL) 844a168ef1aSreyk return (NULL); 845a168ef1aSreyk 846a168ef1aSreyk if (delim == NULL) { 847a168ef1aSreyk if (strcasecmp(match->kv_value, value) == 0) 848a168ef1aSreyk goto done; 849a168ef1aSreyk } else { 850a168ef1aSreyk if ((val = strdup(match->kv_value)) == NULL) 851a168ef1aSreyk return (NULL); 852a168ef1aSreyk for (next = ptr = val; ptr != NULL; 853a168ef1aSreyk ptr = strsep(&next, delim)) { 854a168ef1aSreyk /* strip whitespace */ 855a168ef1aSreyk ptr += strspn(ptr, " \t"); 856a168ef1aSreyk len = strcspn(ptr, " \t"); 857a168ef1aSreyk if (strncasecmp(ptr, value, len) == 0) 858a168ef1aSreyk goto done; 859a168ef1aSreyk } 860a168ef1aSreyk } 861a168ef1aSreyk 862a168ef1aSreyk /* not matched */ 863a168ef1aSreyk match = NULL; 864a168ef1aSreyk done: 865a168ef1aSreyk #ifdef DEBUG 866a168ef1aSreyk if (match != NULL) 867a168ef1aSreyk DPRINTF("%s: matched %s: %s", __func__, key, value); 868a168ef1aSreyk #endif 869a168ef1aSreyk free(val); 870a168ef1aSreyk return (match); 871a168ef1aSreyk } 872a168ef1aSreyk 873c307a266Sreyk int 874c307a266Sreyk kv_cmp(struct kv *a, struct kv *b) 875c307a266Sreyk { 876c307a266Sreyk return (strcasecmp(a->kv_key, b->kv_key)); 877c307a266Sreyk } 878c307a266Sreyk 879c307a266Sreyk RB_GENERATE(kvtree, kv, kv_node, kv_cmp); 880c307a266Sreyk 881cb8b0e56Sreyk int 882cb8b0e56Sreyk rule_add(struct protocol *proto, struct relay_rule *rule, const char *rulefile) 883cb8b0e56Sreyk { 884cb8b0e56Sreyk struct relay_rule *r = NULL; 885cb8b0e56Sreyk struct kv *kv = NULL; 886cb8b0e56Sreyk FILE *fp = NULL; 887cb8b0e56Sreyk char buf[BUFSIZ]; 888cb8b0e56Sreyk int ret = -1; 889cb8b0e56Sreyk u_int i; 890cb8b0e56Sreyk 891cb8b0e56Sreyk for (i = 0; i < KEY_TYPE_MAX; i++) { 892cb8b0e56Sreyk kv = &rule->rule_kv[i]; 893cb8b0e56Sreyk if (kv->kv_type != i) 894cb8b0e56Sreyk continue; 895cb8b0e56Sreyk 896cb8b0e56Sreyk switch (kv->kv_option) { 897cb8b0e56Sreyk case KEY_OPTION_LOG: 898cb8b0e56Sreyk /* log action needs a key or a file to be specified */ 899cb8b0e56Sreyk if (kv->kv_key == NULL && rulefile == NULL && 900cb8b0e56Sreyk (kv->kv_key = strdup("*")) == NULL) 901cb8b0e56Sreyk goto fail; 902cb8b0e56Sreyk break; 903cb8b0e56Sreyk default: 904cb8b0e56Sreyk break; 905cb8b0e56Sreyk } 906cb8b0e56Sreyk 907cb8b0e56Sreyk switch (kv->kv_type) { 908cb8b0e56Sreyk case KEY_TYPE_QUERY: 909cb8b0e56Sreyk case KEY_TYPE_PATH: 910cb8b0e56Sreyk case KEY_TYPE_URL: 911cb8b0e56Sreyk if (rule->rule_dir != RELAY_DIR_REQUEST) 912cb8b0e56Sreyk goto fail; 913cb8b0e56Sreyk break; 914cb8b0e56Sreyk default: 915cb8b0e56Sreyk break; 916cb8b0e56Sreyk } 917c307a266Sreyk 918c307a266Sreyk if (kv->kv_value != NULL && strchr(kv->kv_value, '$') != NULL) 919c307a266Sreyk kv->kv_flags |= KV_FLAG_MACRO; 920c307a266Sreyk if (kv->kv_key != NULL && strpbrk(kv->kv_key, "*?[") != NULL) 921c307a266Sreyk kv->kv_flags |= KV_FLAG_GLOBBING; 922cb8b0e56Sreyk } 923cb8b0e56Sreyk 924cb8b0e56Sreyk if (rulefile == NULL) { 925cb8b0e56Sreyk TAILQ_INSERT_TAIL(&proto->rules, rule, rule_entry); 926cb8b0e56Sreyk return (0); 927cb8b0e56Sreyk } 928cb8b0e56Sreyk 929cb8b0e56Sreyk if ((fp = fopen(rulefile, "r")) == NULL) 930cb8b0e56Sreyk goto fail; 931cb8b0e56Sreyk 932cb8b0e56Sreyk while (fgets(buf, sizeof(buf), fp) != NULL) { 933cb8b0e56Sreyk /* strip whitespace and newline characters */ 934cb8b0e56Sreyk buf[strcspn(buf, "\r\n\t ")] = '\0'; 935cb8b0e56Sreyk if (!strlen(buf) || buf[0] == '#') 936cb8b0e56Sreyk continue; 937cb8b0e56Sreyk 938cb8b0e56Sreyk if ((r = rule_inherit(rule)) == NULL) 939cb8b0e56Sreyk goto fail; 940cb8b0e56Sreyk 941cb8b0e56Sreyk for (i = 0; i < KEY_TYPE_MAX; i++) { 942cb8b0e56Sreyk kv = &r->rule_kv[i]; 943cb8b0e56Sreyk if (kv->kv_type != i) 944cb8b0e56Sreyk continue; 945cb8b0e56Sreyk free(kv->kv_key); 946cb8b0e56Sreyk if ((kv->kv_key = strdup(buf)) == NULL) { 947cb8b0e56Sreyk rule_free(r); 948cb8b0e56Sreyk free(r); 949cb8b0e56Sreyk goto fail; 950cb8b0e56Sreyk } 951cb8b0e56Sreyk } 952cb8b0e56Sreyk 953cb8b0e56Sreyk TAILQ_INSERT_TAIL(&proto->rules, r, rule_entry); 954cb8b0e56Sreyk } 955cb8b0e56Sreyk 956cb8b0e56Sreyk ret = 0; 957cb8b0e56Sreyk rule_free(rule); 958cb8b0e56Sreyk free(rule); 959cb8b0e56Sreyk 960cb8b0e56Sreyk fail: 961cb8b0e56Sreyk if (fp != NULL) 962cb8b0e56Sreyk fclose(fp); 963cb8b0e56Sreyk return (ret); 964cb8b0e56Sreyk } 965cb8b0e56Sreyk 966cb8b0e56Sreyk struct relay_rule * 967cb8b0e56Sreyk rule_inherit(struct relay_rule *rule) 968cb8b0e56Sreyk { 969cb8b0e56Sreyk struct relay_rule *r; 970cb8b0e56Sreyk u_int i; 971cb8b0e56Sreyk struct kv *kv; 972cb8b0e56Sreyk 973cb8b0e56Sreyk if ((r = calloc(1, sizeof(*r))) == NULL) 974cb8b0e56Sreyk return (NULL); 975cb8b0e56Sreyk memcpy(r, rule, sizeof(*r)); 976cb8b0e56Sreyk 977cb8b0e56Sreyk for (i = 0; i < KEY_TYPE_MAX; i++) { 978cb8b0e56Sreyk kv = &rule->rule_kv[i]; 979cb8b0e56Sreyk if (kv->kv_type != i) 980cb8b0e56Sreyk continue; 981cb8b0e56Sreyk if (kv_inherit(&r->rule_kv[i], kv) == NULL) { 982cb8b0e56Sreyk free(r); 983cb8b0e56Sreyk return (NULL); 984cb8b0e56Sreyk } 985cb8b0e56Sreyk } 986cb8b0e56Sreyk 987cb8b0e56Sreyk if (r->rule_label > 0) 988cb8b0e56Sreyk label_ref(r->rule_label); 989cb8b0e56Sreyk if (r->rule_tag > 0) 990cb8b0e56Sreyk tag_ref(r->rule_tag); 991cb8b0e56Sreyk if (r->rule_tagged > 0) 992cb8b0e56Sreyk tag_ref(r->rule_tagged); 993cb8b0e56Sreyk 994cb8b0e56Sreyk return (r); 995cb8b0e56Sreyk } 996cb8b0e56Sreyk 997cb8b0e56Sreyk void 998cb8b0e56Sreyk rule_free(struct relay_rule *rule) 999cb8b0e56Sreyk { 1000cb8b0e56Sreyk u_int i; 1001cb8b0e56Sreyk 1002cb8b0e56Sreyk for (i = 0; i < KEY_TYPE_MAX; i++) 1003cb8b0e56Sreyk kv_free(&rule->rule_kv[i]); 1004cb8b0e56Sreyk if (rule->rule_label > 0) 1005cb8b0e56Sreyk label_unref(rule->rule_label); 1006cb8b0e56Sreyk if (rule->rule_tag > 0) 1007cb8b0e56Sreyk tag_unref(rule->rule_tag); 1008cb8b0e56Sreyk if (rule->rule_tagged > 0) 1009cb8b0e56Sreyk tag_unref(rule->rule_tagged); 1010cb8b0e56Sreyk } 1011cb8b0e56Sreyk 1012cb8b0e56Sreyk void 1013cb8b0e56Sreyk rule_delete(struct relay_rules *rules, struct relay_rule *rule) 1014cb8b0e56Sreyk { 1015cb8b0e56Sreyk TAILQ_REMOVE(rules, rule, rule_entry); 1016cb8b0e56Sreyk rule_free(rule); 1017cb8b0e56Sreyk free(rule); 1018cb8b0e56Sreyk } 1019cb8b0e56Sreyk 1020cb8b0e56Sreyk void 1021cb8b0e56Sreyk rule_settable(struct relay_rules *rules, struct relay_table *rlt) 1022cb8b0e56Sreyk { 1023cb8b0e56Sreyk struct relay_rule *r; 1024cb8b0e56Sreyk char pname[TABLE_NAME_SIZE]; 1025cb8b0e56Sreyk 1026cb8b0e56Sreyk if (rlt->rlt_table == NULL || strlcpy(pname, rlt->rlt_table->conf.name, 1027cb8b0e56Sreyk sizeof(pname)) >= sizeof(pname)) 1028cb8b0e56Sreyk return; 1029cb8b0e56Sreyk 1030cb8b0e56Sreyk pname[strcspn(pname, ":")] = '\0'; 1031cb8b0e56Sreyk 1032cb8b0e56Sreyk TAILQ_FOREACH(r, rules, rule_entry) { 1033cb8b0e56Sreyk if (r->rule_tablename[0] && 1034a94502bfSbenno strcmp(pname, r->rule_tablename) == 0) 1035cb8b0e56Sreyk r->rule_table = rlt; 1036cb8b0e56Sreyk } 1037cb8b0e56Sreyk } 1038cb8b0e56Sreyk 1039a2195becSreyk /* 1040a2195becSreyk * Utility functions 1041a2195becSreyk */ 1042a2195becSreyk 1043feb9ff76Sreyk struct host * 1044748ceb64Sreyk host_find(struct relayd *env, objid_t id) 1045feb9ff76Sreyk { 1046feb9ff76Sreyk struct table *table; 1047feb9ff76Sreyk struct host *host; 1048feb9ff76Sreyk 104935d10c30Sreyk TAILQ_FOREACH(table, env->sc_tables, entry) 1050feb9ff76Sreyk TAILQ_FOREACH(host, &table->hosts, entry) 105168b79041Spyr if (host->conf.id == id) 1052feb9ff76Sreyk return (host); 1053feb9ff76Sreyk return (NULL); 1054feb9ff76Sreyk } 1055feb9ff76Sreyk 1056feb9ff76Sreyk struct table * 1057748ceb64Sreyk table_find(struct relayd *env, objid_t id) 1058feb9ff76Sreyk { 1059feb9ff76Sreyk struct table *table; 1060feb9ff76Sreyk 106135d10c30Sreyk TAILQ_FOREACH(table, env->sc_tables, entry) 106268b79041Spyr if (table->conf.id == id) 1063feb9ff76Sreyk return (table); 1064feb9ff76Sreyk return (NULL); 1065feb9ff76Sreyk } 1066feb9ff76Sreyk 10679591a9f7Spyr struct rdr * 10689591a9f7Spyr rdr_find(struct relayd *env, objid_t id) 1069feb9ff76Sreyk { 10709591a9f7Spyr struct rdr *rdr; 1071feb9ff76Sreyk 107235d10c30Sreyk TAILQ_FOREACH(rdr, env->sc_rdrs, entry) 10739591a9f7Spyr if (rdr->conf.id == id) 10749591a9f7Spyr return (rdr); 1075feb9ff76Sreyk return (NULL); 1076feb9ff76Sreyk } 1077ef1f2334Sreyk 10782edd718bSreyk struct relay * 1079748ceb64Sreyk relay_find(struct relayd *env, objid_t id) 10802edd718bSreyk { 10812edd718bSreyk struct relay *rlay; 10822edd718bSreyk 10834a5b9b3eSreyk TAILQ_FOREACH(rlay, env->sc_relays, rl_entry) 10844a5b9b3eSreyk if (rlay->rl_conf.id == id) 10852edd718bSreyk return (rlay); 10862edd718bSreyk return (NULL); 10872edd718bSreyk } 10882edd718bSreyk 1089a2195becSreyk struct protocol * 1090a2195becSreyk proto_find(struct relayd *env, objid_t id) 1091a2195becSreyk { 1092a2195becSreyk struct protocol *p; 1093a2195becSreyk 1094a2195becSreyk TAILQ_FOREACH(p, env->sc_protos, entry) 1095a2195becSreyk if (p->id == id) 1096a2195becSreyk return (p); 1097a2195becSreyk return (NULL); 1098a2195becSreyk } 1099a2195becSreyk 1100f4a6e73bSreyk struct rsession * 1101748ceb64Sreyk session_find(struct relayd *env, objid_t id) 11022edd718bSreyk { 11032edd718bSreyk struct relay *rlay; 1104f4a6e73bSreyk struct rsession *con; 11052edd718bSreyk 11064a5b9b3eSreyk TAILQ_FOREACH(rlay, env->sc_relays, rl_entry) 11074a5b9b3eSreyk SPLAY_FOREACH(con, session_tree, &rlay->rl_sessions) 1108f8eb77d7Sthib if (con->se_id == id) 11092edd718bSreyk return (con); 11102edd718bSreyk return (NULL); 11112edd718bSreyk } 11122edd718bSreyk 111334438db4Sreyk struct netroute * 111434438db4Sreyk route_find(struct relayd *env, objid_t id) 111534438db4Sreyk { 111634438db4Sreyk struct netroute *nr; 111734438db4Sreyk 111834438db4Sreyk TAILQ_FOREACH(nr, env->sc_routes, nr_route) 111934438db4Sreyk if (nr->nr_conf.id == id) 112034438db4Sreyk return (nr); 112134438db4Sreyk return (NULL); 112234438db4Sreyk } 112334438db4Sreyk 1124a2195becSreyk struct router * 1125a2195becSreyk router_find(struct relayd *env, objid_t id) 1126a2195becSreyk { 1127a2195becSreyk struct router *rt; 1128a2195becSreyk 1129a2195becSreyk TAILQ_FOREACH(rt, env->sc_rts, rt_entry) 1130a2195becSreyk if (rt->rt_conf.id == id) 1131a2195becSreyk return (rt); 1132a2195becSreyk return (NULL); 1133a2195becSreyk } 1134a2195becSreyk 1135ef1f2334Sreyk struct host * 1136748ceb64Sreyk host_findbyname(struct relayd *env, const char *name) 1137ef1f2334Sreyk { 1138ef1f2334Sreyk struct table *table; 1139ef1f2334Sreyk struct host *host; 1140ef1f2334Sreyk 114135d10c30Sreyk TAILQ_FOREACH(table, env->sc_tables, entry) 1142ef1f2334Sreyk TAILQ_FOREACH(host, &table->hosts, entry) 114368b79041Spyr if (strcmp(host->conf.name, name) == 0) 1144ef1f2334Sreyk return (host); 1145ef1f2334Sreyk return (NULL); 1146ef1f2334Sreyk } 1147ef1f2334Sreyk 1148ef1f2334Sreyk struct table * 1149748ceb64Sreyk table_findbyname(struct relayd *env, const char *name) 1150ef1f2334Sreyk { 1151ef1f2334Sreyk struct table *table; 1152ef1f2334Sreyk 115335d10c30Sreyk TAILQ_FOREACH(table, env->sc_tables, entry) 115468b79041Spyr if (strcmp(table->conf.name, name) == 0) 1155ef1f2334Sreyk return (table); 1156ef1f2334Sreyk return (NULL); 1157ef1f2334Sreyk } 1158ef1f2334Sreyk 1159af50a7a9Sreyk struct table * 1160af50a7a9Sreyk table_findbyconf(struct relayd *env, struct table *tb) 1161af50a7a9Sreyk { 1162af50a7a9Sreyk struct table *table; 1163af50a7a9Sreyk struct table_config a, b; 1164af50a7a9Sreyk 1165af50a7a9Sreyk bcopy(&tb->conf, &a, sizeof(a)); 11669591a9f7Spyr a.id = a.rdrid = 0; 1167af50a7a9Sreyk a.flags &= ~(F_USED|F_BACKUP); 1168af50a7a9Sreyk 116935d10c30Sreyk TAILQ_FOREACH(table, env->sc_tables, entry) { 1170af50a7a9Sreyk bcopy(&table->conf, &b, sizeof(b)); 11719591a9f7Spyr b.id = b.rdrid = 0; 1172af50a7a9Sreyk b.flags &= ~(F_USED|F_BACKUP); 1173af50a7a9Sreyk 1174af50a7a9Sreyk /* 1175af50a7a9Sreyk * Compare two tables and return the existing table if 1176af50a7a9Sreyk * the configuration seems to be the same. 1177af50a7a9Sreyk */ 1178af50a7a9Sreyk if (bcmp(&a, &b, sizeof(b)) == 0 && 1179af50a7a9Sreyk ((tb->sendbuf == NULL && table->sendbuf == NULL) || 1180af50a7a9Sreyk (tb->sendbuf != NULL && table->sendbuf != NULL && 1181af50a7a9Sreyk strcmp(tb->sendbuf, table->sendbuf) == 0))) 1182af50a7a9Sreyk return (table); 1183af50a7a9Sreyk } 1184af50a7a9Sreyk return (NULL); 1185af50a7a9Sreyk } 1186af50a7a9Sreyk 11879591a9f7Spyr struct rdr * 11889591a9f7Spyr rdr_findbyname(struct relayd *env, const char *name) 1189ef1f2334Sreyk { 11909591a9f7Spyr struct rdr *rdr; 1191ef1f2334Sreyk 119235d10c30Sreyk TAILQ_FOREACH(rdr, env->sc_rdrs, entry) 11939591a9f7Spyr if (strcmp(rdr->conf.name, name) == 0) 11949591a9f7Spyr return (rdr); 1195ef1f2334Sreyk return (NULL); 1196ef1f2334Sreyk } 119701d85ec5Sreyk 11982edd718bSreyk struct relay * 1199748ceb64Sreyk relay_findbyname(struct relayd *env, const char *name) 12002edd718bSreyk { 12012edd718bSreyk struct relay *rlay; 12022edd718bSreyk 12034a5b9b3eSreyk TAILQ_FOREACH(rlay, env->sc_relays, rl_entry) 12044a5b9b3eSreyk if (strcmp(rlay->rl_conf.name, name) == 0) 12052edd718bSreyk return (rlay); 12062edd718bSreyk return (NULL); 12072edd718bSreyk } 12082edd718bSreyk 12098a93e612Sreyk struct relay * 12108a93e612Sreyk relay_findbyaddr(struct relayd *env, struct relay_config *rc) 12118a93e612Sreyk { 12128a93e612Sreyk struct relay *rlay; 12138a93e612Sreyk 12148a93e612Sreyk TAILQ_FOREACH(rlay, env->sc_relays, rl_entry) 12158a93e612Sreyk if (bcmp(&rlay->rl_conf.ss, &rc->ss, sizeof(rc->ss)) == 0 && 12168a93e612Sreyk rlay->rl_conf.port == rc->port) 12178a93e612Sreyk return (rlay); 12188a93e612Sreyk return (NULL); 12198a93e612Sreyk } 12208a93e612Sreyk 122100ae3104Sreyk EVP_PKEY * 122285e5f500Sclaudio pkey_find(struct relayd *env, char * hash) 122300ae3104Sreyk { 122400ae3104Sreyk struct ca_pkey *pkey; 122500ae3104Sreyk 122600ae3104Sreyk TAILQ_FOREACH(pkey, env->sc_pkeys, pkey_entry) 122785e5f500Sclaudio if (strcmp(hash, pkey->pkey_hash) == 0) 122800ae3104Sreyk return (pkey->pkey); 122900ae3104Sreyk return (NULL); 123000ae3104Sreyk } 123100ae3104Sreyk 123200ae3104Sreyk struct ca_pkey * 123385e5f500Sclaudio pkey_add(struct relayd *env, EVP_PKEY *pkey, char *hash) 123400ae3104Sreyk { 123500ae3104Sreyk struct ca_pkey *ca_pkey; 123600ae3104Sreyk 123700ae3104Sreyk if (env->sc_pkeys == NULL) 123800ae3104Sreyk fatalx("pkeys"); 123900ae3104Sreyk 124000ae3104Sreyk if ((ca_pkey = calloc(1, sizeof(*ca_pkey))) == NULL) 124100ae3104Sreyk return (NULL); 124200ae3104Sreyk 124300ae3104Sreyk ca_pkey->pkey = pkey; 124485e5f500Sclaudio if (strlcpy(ca_pkey->pkey_hash, hash, sizeof(ca_pkey->pkey_hash)) >= 1245263b7135Sjsg sizeof(ca_pkey->pkey_hash)) { 1246263b7135Sjsg free(ca_pkey); 124785e5f500Sclaudio return (NULL); 1248263b7135Sjsg } 124900ae3104Sreyk 125000ae3104Sreyk TAILQ_INSERT_TAIL(env->sc_pkeys, ca_pkey, pkey_entry); 125100ae3104Sreyk 125200ae3104Sreyk return (ca_pkey); 125300ae3104Sreyk } 125400ae3104Sreyk 1255f2f4e153Sreyk struct relay_cert * 1256f2f4e153Sreyk cert_add(struct relayd *env, objid_t id) 1257f2f4e153Sreyk { 1258f2f4e153Sreyk static objid_t last_cert_id = 0; 1259f2f4e153Sreyk struct relay_cert *cert; 1260f2f4e153Sreyk 1261f2f4e153Sreyk if ((cert = calloc(1, sizeof(*cert))) == NULL) 1262f2f4e153Sreyk return (NULL); 1263f2f4e153Sreyk 1264f2f4e153Sreyk if (id == 0) 1265f2f4e153Sreyk id = ++last_cert_id; 1266f2f4e153Sreyk if (id == INT_MAX) { 1267f2f4e153Sreyk log_warnx("too many tls keypairs defined"); 1268f2f4e153Sreyk free(cert); 1269f2f4e153Sreyk return (NULL); 1270f2f4e153Sreyk } 1271f2f4e153Sreyk 1272f2f4e153Sreyk cert->cert_id = id; 1273f2f4e153Sreyk cert->cert_fd = -1; 1274f2f4e153Sreyk cert->cert_key_fd = -1; 127531604b98Sreyk cert->cert_ocsp_fd = -1; 1276f2f4e153Sreyk 1277f2f4e153Sreyk TAILQ_INSERT_TAIL(env->sc_certs, cert, cert_entry); 1278f2f4e153Sreyk 1279f2f4e153Sreyk return (cert); 1280f2f4e153Sreyk } 1281f2f4e153Sreyk 1282f2f4e153Sreyk struct relay_cert * 1283f2f4e153Sreyk cert_find(struct relayd *env, objid_t id) 1284f2f4e153Sreyk { 1285f2f4e153Sreyk struct relay_cert *cert; 1286f2f4e153Sreyk 1287f2f4e153Sreyk TAILQ_FOREACH(cert, env->sc_certs, cert_entry) 1288f2f4e153Sreyk if (cert->cert_id == id) 1289f2f4e153Sreyk return (cert); 1290f2f4e153Sreyk return (NULL); 1291f2f4e153Sreyk } 1292f2f4e153Sreyk 1293e938bb13Sreyk char * 1294e938bb13Sreyk relay_load_fd(int fd, off_t *len) 1295e938bb13Sreyk { 1296e938bb13Sreyk char *buf = NULL; 1297e938bb13Sreyk struct stat st; 1298e938bb13Sreyk off_t size; 1299e938bb13Sreyk ssize_t rv; 1300e938bb13Sreyk int err; 1301e938bb13Sreyk 1302e938bb13Sreyk if (fstat(fd, &st) != 0) 1303e938bb13Sreyk goto fail; 1304e938bb13Sreyk size = st.st_size; 1305e938bb13Sreyk if ((buf = calloc(1, size + 1)) == NULL) 1306e938bb13Sreyk goto fail; 1307e938bb13Sreyk if ((rv = pread(fd, buf, size, 0)) != size) 1308e938bb13Sreyk goto fail; 1309e938bb13Sreyk 1310e938bb13Sreyk close(fd); 1311e938bb13Sreyk 1312e938bb13Sreyk *len = size; 1313e938bb13Sreyk return (buf); 1314e938bb13Sreyk 1315e938bb13Sreyk fail: 1316e938bb13Sreyk err = errno; 1317e938bb13Sreyk free(buf); 1318e938bb13Sreyk close(fd); 1319e938bb13Sreyk errno = err; 1320e938bb13Sreyk return (NULL); 1321e938bb13Sreyk } 1322e938bb13Sreyk 1323e938bb13Sreyk int 13243ca2f577Sreyk relay_load_certfiles(struct relayd *env, struct relay *rlay, const char *name) 1325e938bb13Sreyk { 1326e938bb13Sreyk char certfile[PATH_MAX]; 13273ca2f577Sreyk char hbuf[PATH_MAX]; 1328e938bb13Sreyk struct protocol *proto = rlay->rl_proto; 1329f2f4e153Sreyk struct relay_cert *cert; 1330e938bb13Sreyk int useport = htons(rlay->rl_conf.port); 133131604b98Sreyk int cert_fd = -1, key_fd = -1, ocsp_fd = -1; 1332e938bb13Sreyk 1333e938bb13Sreyk if (rlay->rl_conf.flags & F_TLSCLIENT) { 1334f2f4e153Sreyk if (strlen(proto->tlsca) && rlay->rl_tls_ca_fd == -1) { 1335e938bb13Sreyk if ((rlay->rl_tls_ca_fd = 1336e938bb13Sreyk open(proto->tlsca, O_RDONLY)) == -1) 1337e938bb13Sreyk return (-1); 1338e938bb13Sreyk log_debug("%s: using ca %s", __func__, proto->tlsca); 1339e938bb13Sreyk } 1340f2f4e153Sreyk if (strlen(proto->tlscacert) && rlay->rl_tls_cacert_fd == -1) { 1341e938bb13Sreyk if ((rlay->rl_tls_cacert_fd = 1342e938bb13Sreyk open(proto->tlscacert, O_RDONLY)) == -1) 1343e938bb13Sreyk return (-1); 1344e938bb13Sreyk log_debug("%s: using ca certificate %s", __func__, 1345e938bb13Sreyk proto->tlscacert); 1346e938bb13Sreyk } 1347f2f4e153Sreyk if (strlen(proto->tlscakey) && !rlay->rl_conf.tls_cakey_len && 1348f2f4e153Sreyk proto->tlscapass != NULL) { 1349e938bb13Sreyk if ((rlay->rl_tls_cakey = 1350e938bb13Sreyk ssl_load_key(env, proto->tlscakey, 1351e938bb13Sreyk &rlay->rl_conf.tls_cakey_len, 1352e938bb13Sreyk proto->tlscapass)) == NULL) 1353e938bb13Sreyk return (-1); 1354e938bb13Sreyk log_debug("%s: using ca key %s", __func__, 1355e938bb13Sreyk proto->tlscakey); 1356e938bb13Sreyk } 1357e938bb13Sreyk } 1358e938bb13Sreyk 1359e938bb13Sreyk if ((rlay->rl_conf.flags & F_TLS) == 0) 1360e938bb13Sreyk return (0); 1361e938bb13Sreyk 1362*92388deeStb if (strlen(proto->tlsclientca) && rlay->rl_tls_client_ca_fd == -1) { 1363*92388deeStb if ((rlay->rl_tls_client_ca_fd = 1364*92388deeStb open(proto->tlsclientca, O_RDONLY)) == -1) 1365*92388deeStb return (-1); 1366*92388deeStb log_debug("%s: using client ca %s", __func__, 1367*92388deeStb proto->tlsclientca); 1368*92388deeStb } 1369*92388deeStb 13703ca2f577Sreyk if (name == NULL && 13713ca2f577Sreyk print_host(&rlay->rl_conf.ss, hbuf, sizeof(hbuf)) == NULL) 13723ca2f577Sreyk goto fail; 13733ca2f577Sreyk else if (name != NULL && 13743ca2f577Sreyk strlcpy(hbuf, name, sizeof(hbuf)) >= sizeof(hbuf)) 1375f2f4e153Sreyk goto fail; 1376e938bb13Sreyk 1377e938bb13Sreyk if (snprintf(certfile, sizeof(certfile), 1378e938bb13Sreyk "/etc/ssl/%s:%u.crt", hbuf, useport) == -1) 1379f2f4e153Sreyk goto fail; 1380f2f4e153Sreyk if ((cert_fd = open(certfile, O_RDONLY)) == -1) { 1381e938bb13Sreyk if (snprintf(certfile, sizeof(certfile), 1382e938bb13Sreyk "/etc/ssl/%s.crt", hbuf) == -1) 1383f2f4e153Sreyk goto fail; 1384f2f4e153Sreyk if ((cert_fd = open(certfile, O_RDONLY)) == -1) 1385f2f4e153Sreyk goto fail; 1386e938bb13Sreyk useport = 0; 1387e938bb13Sreyk } 1388e938bb13Sreyk log_debug("%s: using certificate %s", __func__, certfile); 1389e938bb13Sreyk 1390e938bb13Sreyk if (useport) { 1391e938bb13Sreyk if (snprintf(certfile, sizeof(certfile), 1392e938bb13Sreyk "/etc/ssl/private/%s:%u.key", hbuf, useport) == -1) 1393f2f4e153Sreyk goto fail; 1394e938bb13Sreyk } else { 1395e938bb13Sreyk if (snprintf(certfile, sizeof(certfile), 1396e938bb13Sreyk "/etc/ssl/private/%s.key", hbuf) == -1) 1397f2f4e153Sreyk goto fail; 1398e938bb13Sreyk } 1399f2f4e153Sreyk if ((key_fd = open(certfile, O_RDONLY)) == -1) 1400f2f4e153Sreyk goto fail; 1401e938bb13Sreyk log_debug("%s: using private key %s", __func__, certfile); 1402e938bb13Sreyk 140331604b98Sreyk if (useport) { 140431604b98Sreyk if (snprintf(certfile, sizeof(certfile), 140531604b98Sreyk "/etc/ssl/%s:%u.ocsp", hbuf, useport) == -1) 140631604b98Sreyk goto fail; 140731604b98Sreyk } else { 140831604b98Sreyk if (snprintf(certfile, sizeof(certfile), 140931604b98Sreyk "/etc/ssl/%s.ocsp", hbuf) == -1) 141031604b98Sreyk goto fail; 141131604b98Sreyk } 141231604b98Sreyk if ((ocsp_fd = open(certfile, O_RDONLY)) != -1) 141331604b98Sreyk log_debug("%s: using OCSP staple file %s", __func__, certfile); 141431604b98Sreyk 1415f2f4e153Sreyk if ((cert = cert_add(env, 0)) == NULL) 1416f2f4e153Sreyk goto fail; 1417f2f4e153Sreyk 1418f2f4e153Sreyk cert->cert_relayid = rlay->rl_conf.id; 1419f2f4e153Sreyk cert->cert_fd = cert_fd; 1420f2f4e153Sreyk cert->cert_key_fd = key_fd; 142131604b98Sreyk cert->cert_ocsp_fd = ocsp_fd; 1422f2f4e153Sreyk 1423e938bb13Sreyk return (0); 1424f2f4e153Sreyk 1425f2f4e153Sreyk fail: 1426f2f4e153Sreyk if (cert_fd != -1) 1427f2f4e153Sreyk close(cert_fd); 1428f2f4e153Sreyk if (key_fd != -1) 1429f2f4e153Sreyk close(key_fd); 143031604b98Sreyk if (ocsp_fd != -1) 143131604b98Sreyk close(ocsp_fd); 1432f2f4e153Sreyk 1433f2f4e153Sreyk return (-1); 1434e938bb13Sreyk } 1435e938bb13Sreyk 143601d85ec5Sreyk void 14376ae98884Spyr event_again(struct event *ev, int fd, short event, 14386ae98884Spyr void (*fn)(int, short, void *), 143901d85ec5Sreyk struct timeval *start, struct timeval *end, void *arg) 144001d85ec5Sreyk { 144101d85ec5Sreyk struct timeval tv_next, tv_now, tv; 144201d85ec5Sreyk 1443fd1841a3Sreyk getmonotime(&tv_now); 144401d85ec5Sreyk bcopy(end, &tv_next, sizeof(tv_next)); 144501d85ec5Sreyk timersub(&tv_now, start, &tv_now); 144601d85ec5Sreyk timersub(&tv_next, &tv_now, &tv_next); 144701d85ec5Sreyk 144801d85ec5Sreyk bzero(&tv, sizeof(tv)); 144901d85ec5Sreyk if (timercmp(&tv_next, &tv, >)) 145001d85ec5Sreyk bcopy(&tv_next, &tv, sizeof(tv)); 145101d85ec5Sreyk 14524173f6aaSjsg event_del(ev); 145301d85ec5Sreyk event_set(ev, fd, event, fn, arg); 145401d85ec5Sreyk event_add(ev, &tv); 145501d85ec5Sreyk } 14562edd718bSreyk 14572edd718bSreyk int 14582edd718bSreyk expand_string(char *label, size_t len, const char *srch, const char *repl) 14592edd718bSreyk { 14602edd718bSreyk char *tmp; 14612edd718bSreyk char *p, *q; 14622edd718bSreyk 14632edd718bSreyk if ((tmp = calloc(1, len)) == NULL) { 146485a8c65fSreyk log_debug("%s: calloc", __func__); 14652edd718bSreyk return (-1); 14662edd718bSreyk } 14672edd718bSreyk p = q = label; 14682edd718bSreyk while ((q = strstr(p, srch)) != NULL) { 14692edd718bSreyk *q = '\0'; 14702edd718bSreyk if ((strlcat(tmp, p, len) >= len) || 14712edd718bSreyk (strlcat(tmp, repl, len) >= len)) { 147285a8c65fSreyk log_debug("%s: string too long", __func__); 14732e5853e7Sjsg free(tmp); 14742edd718bSreyk return (-1); 14752edd718bSreyk } 14762edd718bSreyk q += strlen(srch); 14772edd718bSreyk p = q; 14782edd718bSreyk } 14792edd718bSreyk if (strlcat(tmp, p, len) >= len) { 148085a8c65fSreyk log_debug("%s: string too long", __func__); 14812e5853e7Sjsg free(tmp); 14822edd718bSreyk return (-1); 14832edd718bSreyk } 14848d6dea2fSreyk (void)strlcpy(label, tmp, len); /* always fits */ 14852edd718bSreyk free(tmp); 14862edd718bSreyk 14872edd718bSreyk return (0); 14882edd718bSreyk } 1489bdd8283dSpyr 1490bdd8283dSpyr void 1491bdd8283dSpyr translate_string(char *str) 1492bdd8283dSpyr { 1493bdd8283dSpyr char *reader; 1494bdd8283dSpyr char *writer; 1495bdd8283dSpyr 1496bdd8283dSpyr reader = writer = str; 1497bdd8283dSpyr 1498bdd8283dSpyr while (*reader) { 1499bdd8283dSpyr if (*reader == '\\') { 1500bdd8283dSpyr reader++; 1501bdd8283dSpyr switch (*reader) { 1502bdd8283dSpyr case 'n': 1503bdd8283dSpyr *writer++ = '\n'; 1504bdd8283dSpyr break; 1505bdd8283dSpyr case 'r': 1506bdd8283dSpyr *writer++ = '\r'; 1507bdd8283dSpyr break; 1508bdd8283dSpyr default: 1509bdd8283dSpyr *writer++ = *reader; 1510bdd8283dSpyr } 1511bdd8283dSpyr } else 1512bdd8283dSpyr *writer++ = *reader; 1513bdd8283dSpyr reader++; 1514bdd8283dSpyr } 1515bdd8283dSpyr *writer = '\0'; 1516bdd8283dSpyr } 15177ae0cc5eSreyk 15187ae0cc5eSreyk char * 15197ae0cc5eSreyk digeststr(enum digest_type type, const u_int8_t *data, size_t len, char *buf) 15207ae0cc5eSreyk { 15217ae0cc5eSreyk switch (type) { 15227ae0cc5eSreyk case DIGEST_SHA1: 15237ae0cc5eSreyk return (SHA1Data(data, len, buf)); 15247ae0cc5eSreyk break; 15257ae0cc5eSreyk case DIGEST_MD5: 15267ae0cc5eSreyk return (MD5Data(data, len, buf)); 15277ae0cc5eSreyk break; 15287ae0cc5eSreyk default: 15297ae0cc5eSreyk break; 15307ae0cc5eSreyk } 15317ae0cc5eSreyk return (NULL); 15327ae0cc5eSreyk } 1533812c1ce4Sreyk 1534812c1ce4Sreyk const char * 1535812c1ce4Sreyk canonicalize_host(const char *host, char *name, size_t len) 1536812c1ce4Sreyk { 1537812c1ce4Sreyk struct sockaddr_in sin4; 1538812c1ce4Sreyk struct sockaddr_in6 sin6; 15399660c10cStedu size_t i, j; 15407fd39c52Sreyk size_t plen; 15417fd39c52Sreyk char c; 1542812c1ce4Sreyk 15437fd39c52Sreyk if (len < 2) 15447fd39c52Sreyk goto fail; 15457fd39c52Sreyk 15467fd39c52Sreyk /* 15477fd39c52Sreyk * Canonicalize an IPv4/6 address 15487fd39c52Sreyk */ 1549812c1ce4Sreyk if (inet_pton(AF_INET, host, &sin4) == 1) 1550812c1ce4Sreyk return (inet_ntop(AF_INET, &sin4, name, len)); 1551812c1ce4Sreyk if (inet_pton(AF_INET6, host, &sin6) == 1) 1552812c1ce4Sreyk return (inet_ntop(AF_INET6, &sin6, name, len)); 1553812c1ce4Sreyk 15547fd39c52Sreyk /* 15557fd39c52Sreyk * Canonicalize a hostname 15567fd39c52Sreyk */ 15577fd39c52Sreyk 15587fd39c52Sreyk /* 1. remove repeated dots and convert upper case to lower case */ 15597fd39c52Sreyk plen = strlen(host); 15607fd39c52Sreyk bzero(name, len); 15617fd39c52Sreyk for (i = j = 0; i < plen; i++) { 15627fd39c52Sreyk if (j >= (len - 1)) 15637fd39c52Sreyk goto fail; 1564d0296ba2Sreyk c = tolower((unsigned char)host[i]); 15657fd39c52Sreyk if ((c == '.') && (j == 0 || name[j - 1] == '.')) 15667fd39c52Sreyk continue; 15677fd39c52Sreyk name[j++] = c; 1568812c1ce4Sreyk } 1569812c1ce4Sreyk 15707fd39c52Sreyk /* 2. remove trailing dots */ 15717fd39c52Sreyk for (i = j; i > 0; i--) { 15727fd39c52Sreyk if (name[i - 1] != '.') 15737fd39c52Sreyk break; 15747fd39c52Sreyk name[i - 1] = '\0'; 15757fd39c52Sreyk j--; 15767fd39c52Sreyk } 15777fd39c52Sreyk if (j <= 0) 15787fd39c52Sreyk goto fail; 15797fd39c52Sreyk 1580812c1ce4Sreyk return (name); 15817fd39c52Sreyk 15827fd39c52Sreyk fail: 15837fd39c52Sreyk errno = EINVAL; 15847fd39c52Sreyk return (NULL); 1585812c1ce4Sreyk } 158632b612c0Sreyk 15872faabbadSreyk int 1588c9822c56Sreyk parse_url(const char *url, char **protoptr, char **hostptr, char **pathptr) 1589c9822c56Sreyk { 1590c9822c56Sreyk char *p, *proto = NULL, *host = NULL, *path = NULL; 1591c9822c56Sreyk 1592c9822c56Sreyk /* return error if it is not a URL */ 1593c9822c56Sreyk if ((p = strstr(url, ":/")) == NULL || 1594c9822c56Sreyk (strcspn(url, ":/") != (size_t)(p - url))) 1595c9822c56Sreyk return (-1); 1596c9822c56Sreyk 1597c9822c56Sreyk /* get protocol */ 1598c9822c56Sreyk if ((proto = strdup(url)) == NULL) 1599c9822c56Sreyk goto fail; 1600c9822c56Sreyk p = proto + (p - url); 1601c9822c56Sreyk 1602c9822c56Sreyk /* get host */ 1603c9822c56Sreyk p += strspn(p, ":/"); 1604c9822c56Sreyk if (*p == '\0' || (host = strdup(p)) == NULL) 1605c9822c56Sreyk goto fail; 1606c9822c56Sreyk *p = '\0'; 1607c9822c56Sreyk 1608c9822c56Sreyk /* find and copy path or default to "/" */ 1609c9822c56Sreyk if ((p = strchr(host, '/')) == NULL) 1610c9822c56Sreyk p = "/"; 1611c9822c56Sreyk if ((path = strdup(p)) == NULL) 1612c9822c56Sreyk goto fail; 1613c9822c56Sreyk 1614c9822c56Sreyk /* strip path after host */ 1615c9822c56Sreyk host[strcspn(host, "/")] = '\0'; 1616c9822c56Sreyk 1617c9822c56Sreyk DPRINTF("%s: %s proto %s, host %s, path %s", __func__, 1618c9822c56Sreyk url, proto, host, path); 1619c9822c56Sreyk 1620c9822c56Sreyk *protoptr = proto; 1621c9822c56Sreyk *hostptr = host; 1622c9822c56Sreyk *pathptr = path; 1623c9822c56Sreyk 1624c9822c56Sreyk return (0); 1625c9822c56Sreyk 1626c9822c56Sreyk fail: 1627c9822c56Sreyk free(proto); 1628c9822c56Sreyk free(host); 1629c9822c56Sreyk free(path); 1630c9822c56Sreyk return (-1); 1631c9822c56Sreyk } 1632c9822c56Sreyk 1633c9822c56Sreyk int 16343c03a838Sreyk bindany(struct ctl_bindany *bnd) 16353c03a838Sreyk { 16363c03a838Sreyk int s, v; 16373c03a838Sreyk 16383c03a838Sreyk s = -1; 16393c03a838Sreyk v = 1; 16403c03a838Sreyk 16413c03a838Sreyk if (relay_socket_af(&bnd->bnd_ss, bnd->bnd_port) == -1) 16423c03a838Sreyk goto fail; 1643318e1f34Sreyk if ((s = socket(bnd->bnd_ss.ss_family, 1644318e1f34Sreyk bnd->bnd_proto == IPPROTO_TCP ? SOCK_STREAM : SOCK_DGRAM, 16453c03a838Sreyk bnd->bnd_proto)) == -1) 16463c03a838Sreyk goto fail; 16473c03a838Sreyk if (setsockopt(s, SOL_SOCKET, SO_BINDANY, 16483c03a838Sreyk &v, sizeof(v)) == -1) 16493c03a838Sreyk goto fail; 16503c03a838Sreyk if (bind(s, (struct sockaddr *)&bnd->bnd_ss, 16513c03a838Sreyk bnd->bnd_ss.ss_len) == -1) 16523c03a838Sreyk goto fail; 16533c03a838Sreyk 16543c03a838Sreyk return (s); 16553c03a838Sreyk 16563c03a838Sreyk fail: 16573c03a838Sreyk if (s != -1) 16583c03a838Sreyk close(s); 16593c03a838Sreyk return (-1); 16603c03a838Sreyk } 1661c564d004Sreyk 1662c564d004Sreyk int 1663c564d004Sreyk map6to4(struct sockaddr_storage *in6) 1664c564d004Sreyk { 1665c564d004Sreyk struct sockaddr_storage out4; 1666c564d004Sreyk struct sockaddr_in *sin4 = (struct sockaddr_in *)&out4; 1667c564d004Sreyk struct sockaddr_in6 *sin6 = (struct sockaddr_in6 *)in6; 1668c564d004Sreyk 1669c564d004Sreyk bzero(sin4, sizeof(*sin4)); 1670c564d004Sreyk sin4->sin_len = sizeof(*sin4); 1671c564d004Sreyk sin4->sin_family = AF_INET; 1672c564d004Sreyk sin4->sin_port = sin6->sin6_port; 1673c564d004Sreyk 1674c564d004Sreyk bcopy(&sin6->sin6_addr.s6_addr[12], &sin4->sin_addr.s_addr, 1675c564d004Sreyk sizeof(sin4->sin_addr)); 1676c564d004Sreyk 1677c564d004Sreyk if (sin4->sin_addr.s_addr == INADDR_ANY || 1678c564d004Sreyk sin4->sin_addr.s_addr == INADDR_BROADCAST || 1679c564d004Sreyk IN_MULTICAST(ntohl(sin4->sin_addr.s_addr))) 1680c564d004Sreyk return (-1); 1681c564d004Sreyk 1682c564d004Sreyk bcopy(&out4, in6, sizeof(*in6)); 1683c564d004Sreyk 1684c564d004Sreyk return (0); 1685c564d004Sreyk } 1686c564d004Sreyk 1687c564d004Sreyk int 1688c564d004Sreyk map4to6(struct sockaddr_storage *in4, struct sockaddr_storage *map) 1689c564d004Sreyk { 1690c564d004Sreyk struct sockaddr_storage out6; 1691c564d004Sreyk struct sockaddr_in *sin4 = (struct sockaddr_in *)in4; 1692c564d004Sreyk struct sockaddr_in6 *sin6 = (struct sockaddr_in6 *)&out6; 1693c564d004Sreyk struct sockaddr_in6 *map6 = (struct sockaddr_in6 *)map; 1694c564d004Sreyk 1695c564d004Sreyk if (sin4->sin_addr.s_addr == INADDR_ANY || 1696c564d004Sreyk sin4->sin_addr.s_addr == INADDR_BROADCAST || 1697c564d004Sreyk IN_MULTICAST(ntohl(sin4->sin_addr.s_addr))) 1698c564d004Sreyk return (-1); 1699c564d004Sreyk 1700c564d004Sreyk bcopy(map6, sin6, sizeof(*sin6)); 1701c564d004Sreyk sin6->sin6_len = sizeof(*sin6); 1702c564d004Sreyk sin6->sin6_family = AF_INET6; 1703c564d004Sreyk sin6->sin6_port = sin4->sin_port; 1704c564d004Sreyk 1705c564d004Sreyk bcopy(&sin4->sin_addr.s_addr, &sin6->sin6_addr.s6_addr[12], 1706c564d004Sreyk sizeof(sin4->sin_addr)); 1707c564d004Sreyk 1708c564d004Sreyk bcopy(&out6, in4, sizeof(*in4)); 1709c564d004Sreyk 1710c564d004Sreyk return (0); 1711c564d004Sreyk } 1712bb8fa3feSreyk 1713bb8fa3feSreyk void 1714bb8fa3feSreyk socket_rlimit(int maxfd) 1715bb8fa3feSreyk { 1716bb8fa3feSreyk struct rlimit rl; 1717bb8fa3feSreyk 1718bb8fa3feSreyk if (getrlimit(RLIMIT_NOFILE, &rl) == -1) 1719efc39811Sbenno fatal("%s: failed to get resource limit", __func__); 17200ccd53b9Sguenther log_debug("%s: max open files %llu", __func__, rl.rlim_max); 1721bb8fa3feSreyk 1722bb8fa3feSreyk /* 1723bb8fa3feSreyk * Allow the maximum number of open file descriptors for this 1724bb8fa3feSreyk * login class (which should be the class "daemon" by default). 1725bb8fa3feSreyk */ 1726bb8fa3feSreyk if (maxfd == -1) 1727bb8fa3feSreyk rl.rlim_cur = rl.rlim_max; 1728bb8fa3feSreyk else 1729e2318a52Sderaadt rl.rlim_cur = MAXIMUM(rl.rlim_max, (rlim_t)maxfd); 1730bb8fa3feSreyk if (setrlimit(RLIMIT_NOFILE, &rl) == -1) 1731efc39811Sbenno fatal("%s: failed to set resource limit", __func__); 1732bb8fa3feSreyk } 1733a2195becSreyk 1734a2195becSreyk char * 1735a2195becSreyk get_string(u_int8_t *ptr, size_t len) 1736a2195becSreyk { 1737a2195becSreyk size_t i; 1738a2195becSreyk 1739a2195becSreyk for (i = 0; i < len; i++) 1740d0296ba2Sreyk if (!(isprint((unsigned char)ptr[i]) || 1741d0296ba2Sreyk isspace((unsigned char)ptr[i]))) 1742a2195becSreyk break; 1743a2195becSreyk 1744b52b3078Smmcc return strndup(ptr, i); 1745a2195becSreyk } 1746a2195becSreyk 1747a2195becSreyk void * 1748a2195becSreyk get_data(u_int8_t *ptr, size_t len) 1749a2195becSreyk { 1750a2195becSreyk u_int8_t *data; 1751a2195becSreyk 1752b52b3078Smmcc if ((data = malloc(len)) == NULL) 1753a2195becSreyk return (NULL); 1754a2195becSreyk memcpy(data, ptr, len); 1755a2195becSreyk 1756a2195becSreyk return (data); 1757a2195becSreyk } 17582f89c21dSbenno 17592f89c21dSbenno int 1760cb8b0e56Sreyk sockaddr_cmp(struct sockaddr *a, struct sockaddr *b, int prefixlen) 1761cb8b0e56Sreyk { 1762cb8b0e56Sreyk struct sockaddr_in *a4, *b4; 1763cb8b0e56Sreyk struct sockaddr_in6 *a6, *b6; 1764cb8b0e56Sreyk u_int32_t av[4], bv[4], mv[4]; 1765cb8b0e56Sreyk 1766cb8b0e56Sreyk if (a->sa_family == AF_UNSPEC || b->sa_family == AF_UNSPEC) 1767cb8b0e56Sreyk return (0); 1768cb8b0e56Sreyk else if (a->sa_family > b->sa_family) 1769cb8b0e56Sreyk return (1); 1770cb8b0e56Sreyk else if (a->sa_family < b->sa_family) 1771cb8b0e56Sreyk return (-1); 1772cb8b0e56Sreyk 1773cb8b0e56Sreyk if (prefixlen == -1) 1774cb8b0e56Sreyk memset(&mv, 0xff, sizeof(mv)); 1775cb8b0e56Sreyk 1776cb8b0e56Sreyk switch (a->sa_family) { 1777cb8b0e56Sreyk case AF_INET: 1778cb8b0e56Sreyk a4 = (struct sockaddr_in *)a; 1779cb8b0e56Sreyk b4 = (struct sockaddr_in *)b; 1780cb8b0e56Sreyk 1781cb8b0e56Sreyk av[0] = a4->sin_addr.s_addr; 1782cb8b0e56Sreyk bv[0] = b4->sin_addr.s_addr; 1783cb8b0e56Sreyk if (prefixlen != -1) 1784cb8b0e56Sreyk mv[0] = prefixlen2mask(prefixlen); 1785cb8b0e56Sreyk 1786cb8b0e56Sreyk if ((av[0] & mv[0]) > (bv[0] & mv[0])) 1787cb8b0e56Sreyk return (1); 1788cb8b0e56Sreyk if ((av[0] & mv[0]) < (bv[0] & mv[0])) 1789cb8b0e56Sreyk return (-1); 1790cb8b0e56Sreyk break; 1791cb8b0e56Sreyk case AF_INET6: 1792cb8b0e56Sreyk a6 = (struct sockaddr_in6 *)a; 1793cb8b0e56Sreyk b6 = (struct sockaddr_in6 *)b; 1794cb8b0e56Sreyk 1795cb8b0e56Sreyk memcpy(&av, &a6->sin6_addr.s6_addr, 16); 1796cb8b0e56Sreyk memcpy(&bv, &b6->sin6_addr.s6_addr, 16); 1797cb8b0e56Sreyk if (prefixlen != -1) 1798cb8b0e56Sreyk prefixlen2mask6(prefixlen, mv); 1799cb8b0e56Sreyk 1800cb8b0e56Sreyk if ((av[3] & mv[3]) > (bv[3] & mv[3])) 1801cb8b0e56Sreyk return (1); 1802cb8b0e56Sreyk if ((av[3] & mv[3]) < (bv[3] & mv[3])) 1803cb8b0e56Sreyk return (-1); 1804cb8b0e56Sreyk if ((av[2] & mv[2]) > (bv[2] & mv[2])) 1805cb8b0e56Sreyk return (1); 1806cb8b0e56Sreyk if ((av[2] & mv[2]) < (bv[2] & mv[2])) 1807cb8b0e56Sreyk return (-1); 1808cb8b0e56Sreyk if ((av[1] & mv[1]) > (bv[1] & mv[1])) 1809cb8b0e56Sreyk return (1); 1810cb8b0e56Sreyk if ((av[1] & mv[1]) < (bv[1] & mv[1])) 1811cb8b0e56Sreyk return (-1); 1812cb8b0e56Sreyk if ((av[0] & mv[0]) > (bv[0] & mv[0])) 1813cb8b0e56Sreyk return (1); 1814cb8b0e56Sreyk if ((av[0] & mv[0]) < (bv[0] & mv[0])) 1815cb8b0e56Sreyk return (-1); 1816cb8b0e56Sreyk break; 1817cb8b0e56Sreyk } 1818cb8b0e56Sreyk 1819cb8b0e56Sreyk return (0); 1820cb8b0e56Sreyk } 1821cb8b0e56Sreyk 1822cb8b0e56Sreyk u_int32_t 1823cb8b0e56Sreyk prefixlen2mask(u_int8_t prefixlen) 1824cb8b0e56Sreyk { 1825cb8b0e56Sreyk if (prefixlen == 0) 1826cb8b0e56Sreyk return (0); 1827cb8b0e56Sreyk 1828cb8b0e56Sreyk if (prefixlen > 32) 1829cb8b0e56Sreyk prefixlen = 32; 1830cb8b0e56Sreyk 1831cb8b0e56Sreyk return (htonl(0xffffffff << (32 - prefixlen))); 1832cb8b0e56Sreyk } 1833cb8b0e56Sreyk 1834cb8b0e56Sreyk struct in6_addr * 1835cb8b0e56Sreyk prefixlen2mask6(u_int8_t prefixlen, u_int32_t *mask) 1836cb8b0e56Sreyk { 1837cb8b0e56Sreyk static struct in6_addr s6; 1838cb8b0e56Sreyk int i; 1839cb8b0e56Sreyk 1840cb8b0e56Sreyk if (prefixlen > 128) 1841cb8b0e56Sreyk prefixlen = 128; 1842cb8b0e56Sreyk 1843cb8b0e56Sreyk bzero(&s6, sizeof(s6)); 1844cb8b0e56Sreyk for (i = 0; i < prefixlen / 8; i++) 1845cb8b0e56Sreyk s6.s6_addr[i] = 0xff; 1846cb8b0e56Sreyk i = prefixlen % 8; 1847cb8b0e56Sreyk if (i) 1848cb8b0e56Sreyk s6.s6_addr[prefixlen / 8] = 0xff00 >> i; 1849cb8b0e56Sreyk 1850cb8b0e56Sreyk memcpy(mask, &s6, sizeof(s6)); 1851cb8b0e56Sreyk 1852cb8b0e56Sreyk return (&s6); 1853cb8b0e56Sreyk } 1854cb8b0e56Sreyk 1855cb8b0e56Sreyk int 18562f89c21dSbenno accept_reserve(int sockfd, struct sockaddr *addr, socklen_t *addrlen, 18572f89c21dSbenno int reserve, volatile int *counter) 18582f89c21dSbenno { 18592f89c21dSbenno int ret; 18602f89c21dSbenno if (getdtablecount() + reserve + 18612f89c21dSbenno *counter >= getdtablesize()) { 18622f89c21dSbenno errno = EMFILE; 18634bfdeee0Sandre return (-1); 18642f89c21dSbenno } 18652f89c21dSbenno 1866b045ffeeSreyk if ((ret = accept4(sockfd, addr, addrlen, SOCK_NONBLOCK)) > -1) { 18672f89c21dSbenno (*counter)++; 18684bfdeee0Sandre DPRINTF("%s: inflight incremented, now %d",__func__, *counter); 18692f89c21dSbenno } 18704bfdeee0Sandre return (ret); 18712f89c21dSbenno } 18729c908525Sclaudio 18739c908525Sclaudio void 18749c908525Sclaudio parent_tls_ticket_rekey(int fd, short events, void *arg) 18759c908525Sclaudio { 18769c908525Sclaudio static struct event rekeyev; 18779c908525Sclaudio struct relayd *env = arg; 18789c908525Sclaudio struct timeval tv; 187985e5f500Sclaudio struct relay_ticket_key key; 18809c908525Sclaudio 1881efc39811Sbenno log_debug("%s: rekeying tickets", __func__); 18829c908525Sclaudio 188385e5f500Sclaudio key.tt_keyrev = arc4random(); 188485e5f500Sclaudio arc4random_buf(key.tt_key, sizeof(key.tt_key)); 18859c908525Sclaudio 18869c908525Sclaudio proc_compose_imsg(env->sc_ps, PROC_RELAY, -1, IMSG_TLSTICKET_REKEY, 18879c908525Sclaudio -1, -1, &key, sizeof(key)); 18889c908525Sclaudio 18899c908525Sclaudio evtimer_set(&rekeyev, parent_tls_ticket_rekey, env); 18909c908525Sclaudio timerclear(&tv); 189185e5f500Sclaudio tv.tv_sec = TLS_SESSION_LIFETIME / 4; 18929c908525Sclaudio evtimer_add(&rekeyev, &tv); 18939c908525Sclaudio } 1894