1*f4d46194Sclaudio /* $OpenBSD: config.c,v 1.47 2024/10/31 13:37:44 claudio Exp $ */ 2a2195becSreyk 3a2195becSreyk /* 43d77879fSreyk * Copyright (c) 2011 - 2014 Reyk Floeter <reyk@openbsd.org> 5a2195becSreyk * 6a2195becSreyk * Permission to use, copy, modify, and distribute this software for any 7a2195becSreyk * purpose with or without fee is hereby granted, provided that the above 8a2195becSreyk * copyright notice and this permission notice appear in all copies. 9a2195becSreyk * 10a2195becSreyk * THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES 11a2195becSreyk * WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF 12a2195becSreyk * MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR 13a2195becSreyk * ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES 14a2195becSreyk * WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN 15a2195becSreyk * ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF 16a2195becSreyk * OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE. 17a2195becSreyk */ 18a2195becSreyk 19a2195becSreyk #include <sys/types.h> 20a2195becSreyk #include <sys/queue.h> 21f04ff968Sreyk #include <sys/time.h> 22a2195becSreyk #include <sys/uio.h> 23a2195becSreyk 24a2195becSreyk #include <stdio.h> 25f04ff968Sreyk #include <stdlib.h> 26f04ff968Sreyk #include <unistd.h> 27f04ff968Sreyk #include <limits.h> 28a2195becSreyk #include <string.h> 29f04ff968Sreyk #include <imsg.h> 30a2195becSreyk 31a2195becSreyk #include "relayd.h" 32a2195becSreyk 33a2195becSreyk int 34a2195becSreyk config_init(struct relayd *env) 35a2195becSreyk { 36a2195becSreyk struct privsep *ps = env->sc_ps; 37a2195becSreyk u_int what; 38a2195becSreyk 39a2195becSreyk /* Global configuration */ 40a2195becSreyk if (privsep_process == PROC_PARENT) { 41586b5f8aSreyk env->sc_conf.timeout.tv_sec = CHECK_TIMEOUT / 1000; 42586b5f8aSreyk env->sc_conf.timeout.tv_usec = (CHECK_TIMEOUT % 1000) * 1000; 43586b5f8aSreyk env->sc_conf.interval.tv_sec = CHECK_INTERVAL; 44586b5f8aSreyk env->sc_conf.interval.tv_usec = 0; 45586b5f8aSreyk env->sc_conf.prefork_relay = RELAY_NUMPROC; 46586b5f8aSreyk env->sc_conf.statinterval.tv_sec = RELAY_STATINTERVAL; 47ec4c1254Sbenno env->sc_ps->ps_csock.cs_name = RELAYD_SOCKET; 48052f96e2Sreyk } 49a2195becSreyk 50a2195becSreyk ps->ps_what[PROC_PARENT] = CONFIG_ALL; 51114ce177Sclaudio ps->ps_what[PROC_PFE] = CONFIG_ALL & ~(CONFIG_PROTOS|CONFIG_CERTS); 52a2195becSreyk ps->ps_what[PROC_HCE] = CONFIG_TABLES; 53114ce177Sclaudio ps->ps_what[PROC_CA] = CONFIG_RELAYS|CONFIG_CERTS; 54114ce177Sclaudio ps->ps_what[PROC_RELAY] = CONFIG_RELAYS|CONFIG_CERTS| 553d77879fSreyk CONFIG_TABLES|CONFIG_PROTOS|CONFIG_CA_ENGINE; 56a2195becSreyk 57a2195becSreyk /* Other configuration */ 58a2195becSreyk what = ps->ps_what[privsep_process]; 59a2195becSreyk if (what & CONFIG_TABLES) { 60a2195becSreyk if ((env->sc_tables = 61a2195becSreyk calloc(1, sizeof(*env->sc_tables))) == NULL) 62a2195becSreyk return (-1); 63a2195becSreyk TAILQ_INIT(env->sc_tables); 64a2195becSreyk 65a2195becSreyk memset(&env->sc_empty_table, 0, sizeof(env->sc_empty_table)); 66a2195becSreyk env->sc_empty_table.conf.id = EMPTY_TABLE; 67a2195becSreyk env->sc_empty_table.conf.flags |= F_DISABLE; 68a2195becSreyk (void)strlcpy(env->sc_empty_table.conf.name, "empty", 69a2195becSreyk sizeof(env->sc_empty_table.conf.name)); 70a2195becSreyk 71a2195becSreyk } 72a2195becSreyk if (what & CONFIG_RDRS) { 73a2195becSreyk if ((env->sc_rdrs = 74a2195becSreyk calloc(1, sizeof(*env->sc_rdrs))) == NULL) 75a2195becSreyk return (-1); 76a2195becSreyk TAILQ_INIT(env->sc_rdrs); 77a2195becSreyk 78a2195becSreyk } 79a2195becSreyk if (what & CONFIG_RELAYS) { 80a2195becSreyk if ((env->sc_relays = 81a2195becSreyk calloc(1, sizeof(*env->sc_relays))) == NULL) 82a2195becSreyk return (-1); 83a2195becSreyk TAILQ_INIT(env->sc_relays); 84f2f4e153Sreyk 85f2f4e153Sreyk if ((env->sc_certs = 86f2f4e153Sreyk calloc(1, sizeof(*env->sc_certs))) == NULL) 87f2f4e153Sreyk return (-1); 88f2f4e153Sreyk TAILQ_INIT(env->sc_certs); 89f2f4e153Sreyk 9000ae3104Sreyk if ((env->sc_pkeys = 9100ae3104Sreyk calloc(1, sizeof(*env->sc_pkeys))) == NULL) 9200ae3104Sreyk return (-1); 9300ae3104Sreyk TAILQ_INIT(env->sc_pkeys); 94a2195becSreyk } 95a2195becSreyk if (what & CONFIG_PROTOS) { 96a2195becSreyk if ((env->sc_protos = 97a2195becSreyk calloc(1, sizeof(*env->sc_protos))) == NULL) 98a2195becSreyk return (-1); 99a2195becSreyk TAILQ_INIT(env->sc_protos); 100a2195becSreyk 101a2195becSreyk bzero(&env->sc_proto_default, sizeof(env->sc_proto_default)); 102a2195becSreyk env->sc_proto_default.id = EMPTY_ID; 103a2195becSreyk env->sc_proto_default.flags = F_USED; 104a2195becSreyk env->sc_proto_default.tcpflags = TCPFLAG_DEFAULT; 105a2195becSreyk env->sc_proto_default.tcpbacklog = RELAY_BACKLOG; 1067bb52228Sreyk env->sc_proto_default.tlsflags = TLSFLAG_DEFAULT; 1073ca2f577Sreyk TAILQ_INIT(&env->sc_proto_default.tlscerts); 1087bb52228Sreyk (void)strlcpy(env->sc_proto_default.tlsciphers, 1097bb52228Sreyk TLSCIPHERS_DEFAULT, 1107bb52228Sreyk sizeof(env->sc_proto_default.tlsciphers)); 111353c00bcSclaudio (void)strlcpy(env->sc_proto_default.tlsecdhecurves, 112353c00bcSclaudio TLSECDHECURVES_DEFAULT, 113353c00bcSclaudio sizeof(env->sc_proto_default.tlsecdhecurves)); 11485e5f500Sclaudio (void)strlcpy(env->sc_proto_default.tlsdhparams, 11585e5f500Sclaudio TLSDHPARAM_DEFAULT, 11685e5f500Sclaudio sizeof(env->sc_proto_default.tlsdhparams)); 117a2195becSreyk env->sc_proto_default.type = RELAY_PROTO_TCP; 118a2195becSreyk (void)strlcpy(env->sc_proto_default.name, "default", 119a2195becSreyk sizeof(env->sc_proto_default.name)); 120a2195becSreyk } 121a2195becSreyk if (what & CONFIG_RTS) { 122a2195becSreyk if ((env->sc_rts = 123a2195becSreyk calloc(1, sizeof(*env->sc_rts))) == NULL) 124a2195becSreyk return (-1); 125a2195becSreyk TAILQ_INIT(env->sc_rts); 126a2195becSreyk } 127a2195becSreyk if (what & CONFIG_ROUTES) { 128a2195becSreyk if ((env->sc_routes = 129a2195becSreyk calloc(1, sizeof(*env->sc_routes))) == NULL) 130a2195becSreyk return (-1); 131a2195becSreyk TAILQ_INIT(env->sc_routes); 132a2195becSreyk } 133a2195becSreyk 134a2195becSreyk return (0); 135a2195becSreyk } 136a2195becSreyk 137a2195becSreyk void 138a2195becSreyk config_purge(struct relayd *env, u_int reset) 139a2195becSreyk { 140a2195becSreyk struct privsep *ps = env->sc_ps; 141a2195becSreyk struct table *table; 142a2195becSreyk struct rdr *rdr; 143a2195becSreyk struct address *virt; 144a2195becSreyk struct protocol *proto; 145cb8b0e56Sreyk struct relay_rule *rule; 146a2195becSreyk struct relay *rlay; 147a2195becSreyk struct netroute *nr; 148a2195becSreyk struct router *rt; 14900ae3104Sreyk struct ca_pkey *pkey; 1503ca2f577Sreyk struct keyname *keyname; 151a2195becSreyk u_int what; 152a2195becSreyk 153a2195becSreyk what = ps->ps_what[privsep_process] & reset; 154a2195becSreyk 155a2195becSreyk if (what & CONFIG_TABLES && env->sc_tables != NULL) { 156a2195becSreyk while ((table = TAILQ_FIRST(env->sc_tables)) != NULL) 1572c8c2287Sclaudio purge_table(env, env->sc_tables, table); 158a2195becSreyk env->sc_tablecount = 0; 159a2195becSreyk } 160a2195becSreyk if (what & CONFIG_RDRS && env->sc_rdrs != NULL) { 161a2195becSreyk while ((rdr = TAILQ_FIRST(env->sc_rdrs)) != NULL) { 162a2195becSreyk TAILQ_REMOVE(env->sc_rdrs, rdr, entry); 163a2195becSreyk while ((virt = TAILQ_FIRST(&rdr->virts)) != NULL) { 164a2195becSreyk TAILQ_REMOVE(&rdr->virts, virt, entry); 165a2195becSreyk free(virt); 166a2195becSreyk } 167a2195becSreyk free(rdr); 168a2195becSreyk } 169a2195becSreyk env->sc_rdrcount = 0; 170a2195becSreyk } 17100ae3104Sreyk if (what & CONFIG_RELAYS && env->sc_pkeys != NULL) { 17200ae3104Sreyk while ((pkey = TAILQ_FIRST(env->sc_pkeys)) != NULL) { 17300ae3104Sreyk TAILQ_REMOVE(env->sc_pkeys, pkey, pkey_entry); 17400ae3104Sreyk free(pkey); 17500ae3104Sreyk } 17600ae3104Sreyk } 177a2195becSreyk if (what & CONFIG_RELAYS && env->sc_relays != NULL) { 178a2195becSreyk while ((rlay = TAILQ_FIRST(env->sc_relays)) != NULL) 179a2195becSreyk purge_relay(env, rlay); 180a2195becSreyk env->sc_relaycount = 0; 181a2195becSreyk } 182a2195becSreyk if (what & CONFIG_PROTOS && env->sc_protos != NULL) { 183a2195becSreyk while ((proto = TAILQ_FIRST(env->sc_protos)) != NULL) { 184a2195becSreyk TAILQ_REMOVE(env->sc_protos, proto, entry); 185cb8b0e56Sreyk while ((rule = TAILQ_FIRST(&proto->rules)) != NULL) 186cb8b0e56Sreyk rule_delete(&proto->rules, rule); 187cb8b0e56Sreyk proto->rulecount = 0; 188cb8b0e56Sreyk } 189cb8b0e56Sreyk } 190cb8b0e56Sreyk if (what & CONFIG_PROTOS && env->sc_protos != NULL) { 191cb8b0e56Sreyk while ((proto = TAILQ_FIRST(env->sc_protos)) != NULL) { 192cb8b0e56Sreyk TAILQ_REMOVE(env->sc_protos, proto, entry); 193a2195becSreyk free(proto->style); 1947bb52228Sreyk free(proto->tlscapass); 1953ca2f577Sreyk while ((keyname = 1963ca2f577Sreyk TAILQ_FIRST(&proto->tlscerts)) != NULL) { 1973ca2f577Sreyk TAILQ_REMOVE(&proto->tlscerts, keyname, entry); 1983ca2f577Sreyk free(keyname->name); 1993ca2f577Sreyk free(keyname); 2003ca2f577Sreyk } 20151ff6749Sjsg free(proto); 202a2195becSreyk } 203a2195becSreyk env->sc_protocount = 0; 204a2195becSreyk } 205a2195becSreyk if (what & CONFIG_RTS && env->sc_rts != NULL) { 206a2195becSreyk while ((rt = TAILQ_FIRST(env->sc_rts)) != NULL) { 207a2195becSreyk TAILQ_REMOVE(env->sc_rts, rt, rt_entry); 208a2195becSreyk while ((nr = TAILQ_FIRST(&rt->rt_netroutes)) != NULL) { 209a2195becSreyk TAILQ_REMOVE(&rt->rt_netroutes, nr, nr_entry); 210a2195becSreyk TAILQ_REMOVE(env->sc_routes, nr, nr_route); 211a2195becSreyk free(nr); 212a2195becSreyk env->sc_routecount--; 213a2195becSreyk } 214a2195becSreyk free(rt); 215a2195becSreyk } 216a2195becSreyk env->sc_routercount = 0; 217a2195becSreyk } 218a2195becSreyk if (what & CONFIG_ROUTES && env->sc_routes != NULL) { 219a2195becSreyk while ((nr = TAILQ_FIRST(env->sc_routes)) != NULL) { 220a2195becSreyk if ((rt = nr->nr_router) != NULL) 221a2195becSreyk TAILQ_REMOVE(&rt->rt_netroutes, nr, nr_entry); 222a2195becSreyk TAILQ_REMOVE(env->sc_routes, nr, nr_route); 223a2195becSreyk free(nr); 224a2195becSreyk } 225a2195becSreyk env->sc_routecount = 0; 226a2195becSreyk } 227a2195becSreyk } 228a2195becSreyk 229a2195becSreyk int 230a2195becSreyk config_setreset(struct relayd *env, u_int reset) 231a2195becSreyk { 232a2195becSreyk struct privsep *ps = env->sc_ps; 233a2195becSreyk int id; 234a2195becSreyk 235a2195becSreyk for (id = 0; id < PROC_MAX; id++) { 236a2195becSreyk if ((reset & ps->ps_what[id]) == 0 || 237a2195becSreyk id == privsep_process) 238a2195becSreyk continue; 239c2c37c5dSreyk proc_compose(ps, id, IMSG_CTL_RESET, &reset, sizeof(reset)); 2405d304668Sreyk 2415d304668Sreyk /* 2425d304668Sreyk * XXX Make sure that the reset message is sent 2435d304668Sreyk * immediately by flushing the imsg output buffer, before 2445d304668Sreyk * sending any other imsg that potentially include an fd. 2455d304668Sreyk * This should better be fixed in the imsg API itself. 2465d304668Sreyk */ 2475d304668Sreyk proc_flush_imsg(ps, id, -1); 248a2195becSreyk } 249a2195becSreyk 250a2195becSreyk return (0); 251a2195becSreyk } 252a2195becSreyk 253a2195becSreyk int 254a2195becSreyk config_getreset(struct relayd *env, struct imsg *imsg) 255a2195becSreyk { 256a2195becSreyk u_int mode; 257a2195becSreyk 258a2195becSreyk IMSG_SIZE_CHECK(imsg, &mode); 259a2195becSreyk memcpy(&mode, imsg->data, sizeof(mode)); 260a2195becSreyk 261a2195becSreyk config_purge(env, mode); 262a2195becSreyk 263a2195becSreyk return (0); 264a2195becSreyk } 265a2195becSreyk 266a2195becSreyk int 267a2195becSreyk config_getcfg(struct relayd *env, struct imsg *imsg) 268a2195becSreyk { 269a2195becSreyk struct privsep *ps = env->sc_ps; 270a2195becSreyk struct table *tb; 271a2195becSreyk struct host *h, *ph; 2723d77879fSreyk u_int what; 273a2195becSreyk 274586b5f8aSreyk if (IMSG_DATA_SIZE(imsg) != sizeof(struct relayd_config)) 275a2195becSreyk return (0); /* ignore */ 276a2195becSreyk 277a2195becSreyk /* Update runtime flags */ 278586b5f8aSreyk memcpy(&env->sc_conf, imsg->data, sizeof(env->sc_conf)); 279a2195becSreyk 2803d77879fSreyk what = ps->ps_what[privsep_process]; 2813d77879fSreyk 2823d77879fSreyk if (what & CONFIG_TABLES) { 283a2195becSreyk /* Update the tables */ 284a2195becSreyk TAILQ_FOREACH(tb, env->sc_tables, entry) { 285a2195becSreyk TAILQ_FOREACH(h, &tb->hosts, entry) { 286a2195becSreyk if (h->conf.parentid && (ph = host_find(env, 287a2195becSreyk h->conf.parentid)) != NULL) { 288a2195becSreyk SLIST_INSERT_HEAD(&ph->children, 289a2195becSreyk h, child); 290a2195becSreyk } 291a2195becSreyk } 292a2195becSreyk } 293a2195becSreyk } 294a2195becSreyk 295586b5f8aSreyk if (env->sc_conf.flags & (F_TLS|F_TLSCLIENT)) { 2961013dd2eSreyk if (what & CONFIG_CA_ENGINE) 2971013dd2eSreyk ca_engine_init(env); 2983d77879fSreyk } 299a2195becSreyk 300a2195becSreyk if (privsep_process != PROC_PARENT) 301c2c37c5dSreyk proc_compose(env->sc_ps, PROC_PARENT, IMSG_CFG_DONE, NULL, 0); 302a2195becSreyk 303a2195becSreyk return (0); 304a2195becSreyk } 305a2195becSreyk 306a2195becSreyk int 307a2195becSreyk config_settable(struct relayd *env, struct table *tb) 308a2195becSreyk { 309a2195becSreyk struct privsep *ps = env->sc_ps; 310a2195becSreyk struct host *host; 311a2195becSreyk int id, c; 312a2195becSreyk struct iovec iov[2]; 313a2195becSreyk 314a2195becSreyk for (id = 0; id < PROC_MAX; id++) { 315a2195becSreyk if ((ps->ps_what[id] & CONFIG_TABLES) == 0 || 316a2195becSreyk id == privsep_process) 317a2195becSreyk continue; 318a2195becSreyk 319a2195becSreyk /* XXX need to send table to pfe for control socket */ 320a2195becSreyk if (id == PROC_HCE && tb->conf.check == CHECK_NOCHECK) 321a2195becSreyk continue; 322a2195becSreyk 323a2195becSreyk DPRINTF("%s: sending table %s %d to %s", __func__, 324a2195becSreyk tb->conf.name, tb->conf.id, env->sc_ps->ps_title[id]); 325a2195becSreyk 326a2195becSreyk c = 0; 327a2195becSreyk iov[c].iov_base = &tb->conf; 328a2195becSreyk iov[c++].iov_len = sizeof(tb->conf); 329a2195becSreyk if (tb->sendbuf != NULL) { 330a2195becSreyk iov[c].iov_base = tb->sendbuf; 331a2195becSreyk iov[c++].iov_len = strlen(tb->sendbuf); 332a2195becSreyk } 333a2195becSreyk 334c2c37c5dSreyk proc_composev(ps, id, IMSG_CFG_TABLE, iov, c); 335a2195becSreyk 336a2195becSreyk TAILQ_FOREACH(host, &tb->hosts, entry) { 337c2c37c5dSreyk proc_compose(ps, id, IMSG_CFG_HOST, 338a2195becSreyk &host->conf, sizeof(host->conf)); 339a2195becSreyk } 340a2195becSreyk } 341a2195becSreyk 342a2195becSreyk return (0); 343a2195becSreyk } 344a2195becSreyk 345a2195becSreyk int 346a2195becSreyk config_gettable(struct relayd *env, struct imsg *imsg) 347a2195becSreyk { 348a2195becSreyk struct table *tb; 349a2195becSreyk size_t sb; 350a2195becSreyk u_int8_t *p = imsg->data; 351a2195becSreyk size_t s; 352a2195becSreyk 353a2195becSreyk if ((tb = calloc(1, sizeof(*tb))) == NULL) 354a2195becSreyk return (-1); 355a2195becSreyk 356a2195becSreyk IMSG_SIZE_CHECK(imsg, &tb->conf); 357a2195becSreyk memcpy(&tb->conf, p, sizeof(tb->conf)); 358a2195becSreyk s = sizeof(tb->conf); 359a2195becSreyk 360a2195becSreyk sb = IMSG_DATA_SIZE(imsg) - s; 361de71eb7fSreyk if (sb > 0) { 362de71eb7fSreyk if ((tb->sendbuf = get_string(p + s, sb)) == NULL) { 363de71eb7fSreyk free(tb); 364de71eb7fSreyk return (-1); 365de71eb7fSreyk } 366de71eb7fSreyk } 3673f229715Srob if (tb->conf.check == CHECK_BINSEND_EXPECT) { 3683f229715Srob tb->sendbinbuf = string2binary(tb->sendbuf); 3693f229715Srob if (tb->sendbinbuf == NULL) { 3703f229715Srob free(tb); 3713f229715Srob return (-1); 3723f229715Srob } 3733f229715Srob } 374a2195becSreyk 375a2195becSreyk TAILQ_INIT(&tb->hosts); 376a2195becSreyk TAILQ_INSERT_TAIL(env->sc_tables, tb, entry); 377a2195becSreyk 378a2195becSreyk env->sc_tablecount++; 379a2195becSreyk 380a2195becSreyk DPRINTF("%s: %s %d received table %d (%s)", __func__, 381a2195becSreyk env->sc_ps->ps_title[privsep_process], env->sc_ps->ps_instance, 382a2195becSreyk tb->conf.id, tb->conf.name); 383a2195becSreyk 384a2195becSreyk return (0); 385a2195becSreyk } 386a2195becSreyk 387a2195becSreyk int 388a2195becSreyk config_gethost(struct relayd *env, struct imsg *imsg) 389a2195becSreyk { 390a2195becSreyk struct table *tb; 391a2195becSreyk struct host *host; 392a2195becSreyk 393a2195becSreyk if ((host = calloc(1, sizeof(*host))) == NULL) 394a2195becSreyk return (-1); 395a2195becSreyk 396a2195becSreyk IMSG_SIZE_CHECK(imsg, &host->conf); 397a2195becSreyk memcpy(&host->conf, imsg->data, sizeof(host->conf)); 398a2195becSreyk 399a2195becSreyk if (host_find(env, host->conf.id) != NULL) { 400a2195becSreyk log_debug("%s: host %d already exists", 401a2195becSreyk __func__, host->conf.id); 402a2195becSreyk free(host); 403a2195becSreyk return (-1); 404a2195becSreyk } 405a2195becSreyk 406a2195becSreyk if ((tb = table_find(env, host->conf.tableid)) == NULL) { 407a2195becSreyk log_debug("%s: " 408a2195becSreyk "received host for unknown table %d", __func__, 409a2195becSreyk host->conf.tableid); 410a2195becSreyk free(host); 411a2195becSreyk return (-1); 412a2195becSreyk } 413a2195becSreyk 414a2195becSreyk host->tablename = tb->conf.name; 415a2195becSreyk host->cte.s = -1; 416a2195becSreyk 417a2195becSreyk SLIST_INIT(&host->children); 418a2195becSreyk TAILQ_INSERT_TAIL(&tb->hosts, host, entry); 4196e07057bSblambert TAILQ_INSERT_TAIL(&env->sc_hosts, host, globalentry); 420a2195becSreyk 421a2195becSreyk DPRINTF("%s: %s %d received host %s for table %s", __func__, 422a2195becSreyk env->sc_ps->ps_title[privsep_process], env->sc_ps->ps_instance, 423a2195becSreyk host->conf.name, tb->conf.name); 424a2195becSreyk 425a2195becSreyk return (0); 426a2195becSreyk } 427a2195becSreyk 428a2195becSreyk int 429a2195becSreyk config_setrdr(struct relayd *env, struct rdr *rdr) 430a2195becSreyk { 431a2195becSreyk struct privsep *ps = env->sc_ps; 432a2195becSreyk struct address *virt; 433a2195becSreyk int id; 434a2195becSreyk 435a2195becSreyk for (id = 0; id < PROC_MAX; id++) { 436a2195becSreyk if ((ps->ps_what[id] & CONFIG_RDRS) == 0 || 437a2195becSreyk id == privsep_process) 438a2195becSreyk continue; 439a2195becSreyk 440a2195becSreyk DPRINTF("%s: sending rdr %s to %s", __func__, 441a2195becSreyk rdr->conf.name, ps->ps_title[id]); 442a2195becSreyk 443c2c37c5dSreyk proc_compose(ps, id, IMSG_CFG_RDR, 444a2195becSreyk &rdr->conf, sizeof(rdr->conf)); 445a2195becSreyk 446a2195becSreyk TAILQ_FOREACH(virt, &rdr->virts, entry) { 447a2195becSreyk virt->rdrid = rdr->conf.id; 448c2c37c5dSreyk proc_compose(ps, id, IMSG_CFG_VIRT, 449a2195becSreyk virt, sizeof(*virt)); 450a2195becSreyk } 451a2195becSreyk } 452a2195becSreyk 453a2195becSreyk return (0); 454a2195becSreyk } 455a2195becSreyk 456a2195becSreyk int 457a2195becSreyk config_getrdr(struct relayd *env, struct imsg *imsg) 458a2195becSreyk { 459a2195becSreyk struct rdr *rdr; 460a2195becSreyk 461a2195becSreyk if ((rdr = calloc(1, sizeof(*rdr))) == NULL) 462a2195becSreyk return (-1); 463a2195becSreyk 464a2195becSreyk IMSG_SIZE_CHECK(imsg, &rdr->conf); 465a2195becSreyk memcpy(&rdr->conf, imsg->data, sizeof(rdr->conf)); 466a2195becSreyk 467a2195becSreyk if ((rdr->table = table_find(env, rdr->conf.table_id)) == NULL) { 468a2195becSreyk log_debug("%s: table not found", __func__); 469a2195becSreyk free(rdr); 470a2195becSreyk return (-1); 471a2195becSreyk } 472a2195becSreyk if ((rdr->backup = table_find(env, rdr->conf.backup_id)) == NULL) { 473a2195becSreyk rdr->conf.backup_id = EMPTY_TABLE; 474a2195becSreyk rdr->backup = &env->sc_empty_table; 475a2195becSreyk } 476a2195becSreyk 477a2195becSreyk TAILQ_INIT(&rdr->virts); 478a2195becSreyk TAILQ_INSERT_TAIL(env->sc_rdrs, rdr, entry); 479a2195becSreyk 480a2195becSreyk env->sc_rdrcount++; 481a2195becSreyk 482a2195becSreyk DPRINTF("%s: %s %d received rdr %s", __func__, 483a2195becSreyk env->sc_ps->ps_title[privsep_process], env->sc_ps->ps_instance, 484a2195becSreyk rdr->conf.name); 485a2195becSreyk 486a2195becSreyk return (0); 487a2195becSreyk } 488a2195becSreyk 489a2195becSreyk int 490a2195becSreyk config_getvirt(struct relayd *env, struct imsg *imsg) 491a2195becSreyk { 492a2195becSreyk struct rdr *rdr; 493a2195becSreyk struct address *virt; 494a2195becSreyk 495a2195becSreyk IMSG_SIZE_CHECK(imsg, virt); 496a2195becSreyk 497a2195becSreyk if ((virt = calloc(1, sizeof(*virt))) == NULL) 498a2195becSreyk return (-1); 499a2195becSreyk memcpy(virt, imsg->data, sizeof(*virt)); 500a2195becSreyk 501a2195becSreyk if ((rdr = rdr_find(env, virt->rdrid)) == NULL) { 502a2195becSreyk log_debug("%s: rdr not found", __func__); 503a2195becSreyk free(virt); 504a2195becSreyk return (-1); 505a2195becSreyk } 506a2195becSreyk 507a2195becSreyk TAILQ_INSERT_TAIL(&rdr->virts, virt, entry); 508a2195becSreyk 509a2195becSreyk DPRINTF("%s: %s %d received address for rdr %s", __func__, 510a2195becSreyk env->sc_ps->ps_title[privsep_process], env->sc_ps->ps_instance, 511a2195becSreyk rdr->conf.name); 512a2195becSreyk 513a2195becSreyk return (0); 514a2195becSreyk } 515a2195becSreyk 516a2195becSreyk int 517a2195becSreyk config_setrt(struct relayd *env, struct router *rt) 518a2195becSreyk { 519a2195becSreyk struct privsep *ps = env->sc_ps; 520a2195becSreyk struct netroute *nr; 521a2195becSreyk int id; 522a2195becSreyk 523a2195becSreyk for (id = 0; id < PROC_MAX; id++) { 524a2195becSreyk if ((ps->ps_what[id] & CONFIG_RTS) == 0 || 525a2195becSreyk id == privsep_process) 526a2195becSreyk continue; 527a2195becSreyk 528a2195becSreyk DPRINTF("%s: sending router %s to %s tbl %d", __func__, 529a2195becSreyk rt->rt_conf.name, ps->ps_title[id], rt->rt_conf.gwtable); 530a2195becSreyk 531c2c37c5dSreyk proc_compose(ps, id, IMSG_CFG_ROUTER, 532a2195becSreyk &rt->rt_conf, sizeof(rt->rt_conf)); 533a2195becSreyk 534a2195becSreyk TAILQ_FOREACH(nr, &rt->rt_netroutes, nr_entry) { 535c2c37c5dSreyk proc_compose(ps, id, IMSG_CFG_ROUTE, 536a2195becSreyk &nr->nr_conf, sizeof(nr->nr_conf)); 537a2195becSreyk } 538a2195becSreyk } 539a2195becSreyk 540a2195becSreyk return (0); 541a2195becSreyk } 542a2195becSreyk 543a2195becSreyk int 544a2195becSreyk config_getrt(struct relayd *env, struct imsg *imsg) 545a2195becSreyk { 546a2195becSreyk struct router *rt; 547a2195becSreyk 548a2195becSreyk if ((rt = calloc(1, sizeof(*rt))) == NULL) 549a2195becSreyk return (-1); 550a2195becSreyk 551a2195becSreyk IMSG_SIZE_CHECK(imsg, &rt->rt_conf); 552a2195becSreyk memcpy(&rt->rt_conf, imsg->data, sizeof(rt->rt_conf)); 553a2195becSreyk 554a2195becSreyk if ((rt->rt_gwtable = table_find(env, rt->rt_conf.gwtable)) == NULL) { 555a2195becSreyk log_debug("%s: table not found", __func__); 556a2195becSreyk free(rt); 557a2195becSreyk return (-1); 558a2195becSreyk } 559a2195becSreyk 560a2195becSreyk TAILQ_INIT(&rt->rt_netroutes); 561a2195becSreyk TAILQ_INSERT_TAIL(env->sc_rts, rt, rt_entry); 562a2195becSreyk 563a2195becSreyk env->sc_routercount++; 564a2195becSreyk 565a2195becSreyk DPRINTF("%s: %s %d received router %s", __func__, 566a2195becSreyk env->sc_ps->ps_title[privsep_process], env->sc_ps->ps_instance, 567a2195becSreyk rt->rt_conf.name); 568a2195becSreyk 569a2195becSreyk return (0); 570a2195becSreyk } 571a2195becSreyk 572a2195becSreyk int 573a2195becSreyk config_getroute(struct relayd *env, struct imsg *imsg) 574a2195becSreyk { 575a2195becSreyk struct router *rt; 576a2195becSreyk struct netroute *nr; 577a2195becSreyk 578a2195becSreyk if ((nr = calloc(1, sizeof(*nr))) == NULL) 579a2195becSreyk return (-1); 580a2195becSreyk 581a2195becSreyk IMSG_SIZE_CHECK(imsg, &nr->nr_conf); 582a2195becSreyk memcpy(&nr->nr_conf, imsg->data, sizeof(nr->nr_conf)); 583a2195becSreyk 584a2195becSreyk if (route_find(env, nr->nr_conf.id) != NULL) { 585a2195becSreyk log_debug("%s: route %d already exists", 586a2195becSreyk __func__, nr->nr_conf.id); 587a2195becSreyk free(nr); 588a2195becSreyk return (-1); 589a2195becSreyk } 590a2195becSreyk 591a2195becSreyk if ((rt = router_find(env, nr->nr_conf.routerid)) == NULL) { 592a2195becSreyk log_debug("%s: received route for unknown router", __func__); 593a2195becSreyk free(nr); 594a2195becSreyk return (-1); 595a2195becSreyk } 596a2195becSreyk 597a2195becSreyk nr->nr_router = rt; 598a2195becSreyk 599a2195becSreyk TAILQ_INSERT_TAIL(env->sc_routes, nr, nr_route); 600a2195becSreyk TAILQ_INSERT_TAIL(&rt->rt_netroutes, nr, nr_entry); 601a2195becSreyk 602a2195becSreyk env->sc_routecount++; 603a2195becSreyk 604a2195becSreyk DPRINTF("%s: %s %d received route %d for router %s", __func__, 605a2195becSreyk env->sc_ps->ps_title[privsep_process], env->sc_ps->ps_instance, 606a2195becSreyk nr->nr_conf.id, rt->rt_conf.name); 607a2195becSreyk 608a2195becSreyk return (0); 609a2195becSreyk } 610a2195becSreyk 611a2195becSreyk int 612a2195becSreyk config_setproto(struct relayd *env, struct protocol *proto) 613a2195becSreyk { 614a2195becSreyk struct privsep *ps = env->sc_ps; 615a2195becSreyk int id; 616cb8b0e56Sreyk struct iovec iov[IOV_MAX]; 617a2195becSreyk size_t c; 618a2195becSreyk 619a2195becSreyk for (id = 0; id < PROC_MAX; id++) { 620a2195becSreyk if ((ps->ps_what[id] & CONFIG_PROTOS) == 0 || 621a2195becSreyk id == privsep_process) 622a2195becSreyk continue; 623a2195becSreyk 624a2195becSreyk DPRINTF("%s: sending protocol %s to %s", __func__, 625a2195becSreyk proto->name, ps->ps_title[id]); 626a2195becSreyk 627a2195becSreyk c = 0; 628a2195becSreyk iov[c].iov_base = proto; 629a2195becSreyk iov[c++].iov_len = sizeof(*proto); 630a2195becSreyk 631a2195becSreyk if (proto->style != NULL) { 632a2195becSreyk iov[c].iov_base = proto->style; 6338f340ff2Sjsg iov[c++].iov_len = strlen(proto->style) + 1; 634a2195becSreyk } 635a2195becSreyk 636c2c37c5dSreyk proc_composev(ps, id, IMSG_CFG_PROTO, iov, c); 637cb8b0e56Sreyk } 638a2195becSreyk 639cb8b0e56Sreyk return (0); 640cb8b0e56Sreyk } 641cb8b0e56Sreyk 642cb8b0e56Sreyk int 643cb8b0e56Sreyk config_setrule(struct relayd *env, struct protocol *proto) 644cb8b0e56Sreyk { 645cb8b0e56Sreyk struct privsep *ps = env->sc_ps; 646cb8b0e56Sreyk struct relay_rule *rule; 647cb8b0e56Sreyk struct iovec iov[IOV_MAX]; 648cb8b0e56Sreyk int id; 649cb8b0e56Sreyk size_t c, i; 650cb8b0e56Sreyk 651cb8b0e56Sreyk for (id = 0; id < PROC_MAX; id++) { 652cb8b0e56Sreyk if ((ps->ps_what[id] & CONFIG_PROTOS) == 0 || 653cb8b0e56Sreyk id == privsep_process) 654cb8b0e56Sreyk continue; 655cb8b0e56Sreyk 656cb8b0e56Sreyk DPRINTF("%s: sending rules %s to %s", __func__, 657cb8b0e56Sreyk proto->name, ps->ps_title[id]); 658cb8b0e56Sreyk 659cb8b0e56Sreyk /* Now send all the rules */ 660cb8b0e56Sreyk TAILQ_FOREACH(rule, &proto->rules, rule_entry) { 661cb8b0e56Sreyk rule->rule_protoid = proto->id; 662cb8b0e56Sreyk bzero(&rule->rule_ctl, sizeof(rule->rule_ctl)); 663cb8b0e56Sreyk c = 0; 664cb8b0e56Sreyk iov[c].iov_base = rule; 665cb8b0e56Sreyk iov[c++].iov_len = sizeof(*rule); 666cb8b0e56Sreyk for (i = 1; i < KEY_TYPE_MAX; i++) { 667cb8b0e56Sreyk if (rule->rule_kv[i].kv_key != NULL) { 668cb8b0e56Sreyk rule->rule_ctl.kvlen[i].key = 669cb8b0e56Sreyk strlen(rule->rule_kv[i].kv_key); 670cb8b0e56Sreyk iov[c].iov_base = 671cb8b0e56Sreyk rule->rule_kv[i].kv_key; 672cb8b0e56Sreyk iov[c++].iov_len = 673cb8b0e56Sreyk rule->rule_ctl.kvlen[i].key; 674cb8b0e56Sreyk } else 675cb8b0e56Sreyk rule->rule_ctl.kvlen[i].key = -1; 676cb8b0e56Sreyk if (rule->rule_kv[i].kv_value != NULL) { 677cb8b0e56Sreyk rule->rule_ctl.kvlen[i].value = 678cb8b0e56Sreyk strlen(rule->rule_kv[i].kv_value); 679cb8b0e56Sreyk iov[c].iov_base = 680cb8b0e56Sreyk rule->rule_kv[i].kv_value; 681cb8b0e56Sreyk iov[c++].iov_len = 682cb8b0e56Sreyk rule->rule_ctl.kvlen[i].value; 683cb8b0e56Sreyk } else 684cb8b0e56Sreyk rule->rule_ctl.kvlen[i].value = -1; 685cb8b0e56Sreyk } 686cb8b0e56Sreyk 687c2c37c5dSreyk proc_composev(ps, id, IMSG_CFG_RULE, iov, c); 688cb8b0e56Sreyk } 689a2195becSreyk } 690a2195becSreyk 691a2195becSreyk return (0); 692a2195becSreyk } 693a2195becSreyk 694a2195becSreyk int 695a2195becSreyk config_getproto(struct relayd *env, struct imsg *imsg) 696a2195becSreyk { 697a2195becSreyk struct protocol *proto; 698a2195becSreyk size_t styl; 699de71eb7fSreyk size_t s; 700de71eb7fSreyk u_int8_t *p = imsg->data; 701a2195becSreyk 702a2195becSreyk if ((proto = calloc(1, sizeof(*proto))) == NULL) 703a2195becSreyk return (-1); 704a2195becSreyk 705a2195becSreyk IMSG_SIZE_CHECK(imsg, proto); 706de71eb7fSreyk memcpy(proto, p, sizeof(*proto)); 707de71eb7fSreyk s = sizeof(*proto); 708a2195becSreyk 709de71eb7fSreyk styl = IMSG_DATA_SIZE(imsg) - s; 7108f340ff2Sjsg proto->style = NULL; 711de71eb7fSreyk if (styl > 0) { 7128f340ff2Sjsg if ((proto->style = get_string(p + s, styl - 1)) == NULL) { 713de71eb7fSreyk free(proto); 714de71eb7fSreyk return (-1); 715de71eb7fSreyk } 716de71eb7fSreyk } 717a2195becSreyk 718cb8b0e56Sreyk TAILQ_INIT(&proto->rules); 7193ca2f577Sreyk TAILQ_INIT(&proto->tlscerts); 7207bb52228Sreyk proto->tlscapass = NULL; 721a2195becSreyk 722a2195becSreyk TAILQ_INSERT_TAIL(env->sc_protos, proto, entry); 723a2195becSreyk 724a2195becSreyk env->sc_protocount++; 725a2195becSreyk 726a2195becSreyk DPRINTF("%s: %s %d received protocol %s", __func__, 727a2195becSreyk env->sc_ps->ps_title[privsep_process], env->sc_ps->ps_instance, 728a2195becSreyk proto->name); 729a2195becSreyk 730a2195becSreyk return (0); 731a2195becSreyk } 732a2195becSreyk 733a2195becSreyk int 734cb8b0e56Sreyk config_getrule(struct relayd *env, struct imsg *imsg) 735a2195becSreyk { 736cb8b0e56Sreyk struct protocol *proto; 737cb8b0e56Sreyk struct relay_rule *rule; 738cb8b0e56Sreyk size_t s, i; 739a2195becSreyk u_int8_t *p = imsg->data; 740cb8b0e56Sreyk ssize_t len; 741a2195becSreyk 742cb8b0e56Sreyk if ((rule = calloc(1, sizeof(*rule))) == NULL) 743cb8b0e56Sreyk return (-1); 744a2195becSreyk 745cb8b0e56Sreyk IMSG_SIZE_CHECK(imsg, rule); 746cb8b0e56Sreyk memcpy(rule, p, sizeof(*rule)); 747cb8b0e56Sreyk s = sizeof(*rule); 748cb8b0e56Sreyk len = IMSG_DATA_SIZE(imsg) - s; 749a2195becSreyk 750cb8b0e56Sreyk if ((proto = proto_find(env, rule->rule_protoid)) == NULL) { 751cb8b0e56Sreyk free(rule); 752a2195becSreyk return (-1); 753a2195becSreyk } 754a2195becSreyk 755cb8b0e56Sreyk #define GETKV(_n, _f) { \ 756cb8b0e56Sreyk if (rule->rule_ctl.kvlen[_n]._f >= 0) { \ 757cb8b0e56Sreyk /* Also accept "empty" 0-length strings */ \ 758cb8b0e56Sreyk if ((len < rule->rule_ctl.kvlen[_n]._f) || \ 759cb8b0e56Sreyk (rule->rule_kv[_n].kv_##_f = \ 760cb8b0e56Sreyk get_string(p + s, \ 761cb8b0e56Sreyk rule->rule_ctl.kvlen[_n]._f)) == NULL) { \ 762cb8b0e56Sreyk free(rule); \ 763cb8b0e56Sreyk return (-1); \ 764cb8b0e56Sreyk } \ 765cb8b0e56Sreyk s += rule->rule_ctl.kvlen[_n]._f; \ 766cb8b0e56Sreyk len -= rule->rule_ctl.kvlen[_n]._f; \ 767cb8b0e56Sreyk \ 768cb8b0e56Sreyk DPRINTF("%s: %s %s (len %ld, option %d): %s", __func__, \ 769cb8b0e56Sreyk #_n, #_f, rule->rule_ctl.kvlen[_n]._f, \ 770cb8b0e56Sreyk rule->rule_kv[_n].kv_option, \ 771cb8b0e56Sreyk rule->rule_kv[_n].kv_##_f); \ 772cb8b0e56Sreyk } \ 7731ac2a6baSbenno } 774a2195becSreyk 77553ad1bbfSreyk memset(&rule->rule_kv[0], 0, sizeof(struct kv)); 776cb8b0e56Sreyk for (i = 1; i < KEY_TYPE_MAX; i++) { 777c307a266Sreyk TAILQ_INIT(&rule->rule_kv[i].kv_children); 778cb8b0e56Sreyk GETKV(i, key); 779cb8b0e56Sreyk GETKV(i, value); 780a2195becSreyk } 781a2195becSreyk 782cb8b0e56Sreyk if (rule->rule_labelname[0]) 783cb8b0e56Sreyk rule->rule_label = label_name2id(rule->rule_labelname); 784a2195becSreyk 785cb8b0e56Sreyk if (rule->rule_tagname[0]) 786cb8b0e56Sreyk rule->rule_tag = tag_name2id(rule->rule_tagname); 787cb8b0e56Sreyk 788cb8b0e56Sreyk if (rule->rule_taggedname[0]) 789cb8b0e56Sreyk rule->rule_tagged = tag_name2id(rule->rule_taggedname); 790cb8b0e56Sreyk 791cb8b0e56Sreyk rule->rule_id = proto->rulecount++; 792cb8b0e56Sreyk 793cb8b0e56Sreyk TAILQ_INSERT_TAIL(&proto->rules, rule, rule_entry); 794cb8b0e56Sreyk 795cb8b0e56Sreyk DPRINTF("%s: %s %d received rule %u for protocol %s", __func__, 796a2195becSreyk env->sc_ps->ps_title[privsep_process], env->sc_ps->ps_instance, 797cb8b0e56Sreyk rule->rule_id, proto->name); 798a2195becSreyk 799a2195becSreyk return (0); 800a2195becSreyk } 801a2195becSreyk 802114ce177Sclaudio static int 803f2f4e153Sreyk config_setrelayfd(struct privsep *ps, int id, int n, 804f2f4e153Sreyk objid_t obj_id, objid_t rlay_id, enum fd_type type, int ofd) 805114ce177Sclaudio { 806114ce177Sclaudio struct ctl_relayfd rfd; 807114ce177Sclaudio int fd; 808114ce177Sclaudio 809f2f4e153Sreyk rfd.id = obj_id; 810114ce177Sclaudio rfd.relayid = rlay_id; 811114ce177Sclaudio rfd.type = type; 812114ce177Sclaudio 813114ce177Sclaudio if ((fd = dup(ofd)) == -1) 814114ce177Sclaudio return (-1); 815114ce177Sclaudio if (proc_compose_imsg(ps, id, n, IMSG_CFG_RELAY_FD, -1, fd, 816114ce177Sclaudio &rfd, sizeof(rfd)) != 0) 817114ce177Sclaudio return (-1); 818114ce177Sclaudio 819114ce177Sclaudio return (0); 820114ce177Sclaudio } 821114ce177Sclaudio 822a2195becSreyk int 823a2195becSreyk config_setrelay(struct relayd *env, struct relay *rlay) 824a2195becSreyk { 825a2195becSreyk struct privsep *ps = env->sc_ps; 826416fa9c0Sreyk struct ctl_relaytable crt; 827416fa9c0Sreyk struct relay_table *rlt; 8283d77879fSreyk struct relay_config rl; 829f2f4e153Sreyk struct relay_cert *cert; 830a2195becSreyk int id; 831a2195becSreyk int fd, n, m; 832c71a6e4bSjsg struct iovec iov[6]; 833a2195becSreyk size_t c; 8343d77879fSreyk u_int what; 835a2195becSreyk 836a2195becSreyk /* opens listening sockets etc. */ 837a2195becSreyk if (relay_privinit(rlay) == -1) 838a2195becSreyk return (-1); 839a2195becSreyk 840a2195becSreyk for (id = 0; id < PROC_MAX; id++) { 8413d77879fSreyk what = ps->ps_what[id]; 8423d77879fSreyk 8433d77879fSreyk if ((what & CONFIG_RELAYS) == 0 || id == privsep_process) 844a2195becSreyk continue; 845a2195becSreyk 846a2195becSreyk DPRINTF("%s: sending relay %s to %s fd %d", __func__, 847a2195becSreyk rlay->rl_conf.name, ps->ps_title[id], rlay->rl_s); 848a2195becSreyk 8493d77879fSreyk memcpy(&rl, &rlay->rl_conf, sizeof(rl)); 8503d77879fSreyk 851a2195becSreyk c = 0; 8523d77879fSreyk iov[c].iov_base = &rl; 8533d77879fSreyk iov[c++].iov_len = sizeof(rl); 854114ce177Sclaudio 8553d77879fSreyk if ((what & CONFIG_CA_ENGINE) == 0 && 8567bb52228Sreyk rl.tls_cakey_len) { 8577bb52228Sreyk iov[c].iov_base = rlay->rl_tls_cakey; 8587bb52228Sreyk iov[c++].iov_len = rl.tls_cakey_len; 85900ae3104Sreyk } else 8607bb52228Sreyk rl.tls_cakey_len = 0; 861a2195becSreyk 862a2195becSreyk if (id == PROC_RELAY) { 863a2195becSreyk /* XXX imsg code will close the fd after 1st call */ 864a2195becSreyk n = -1; 865a2195becSreyk proc_range(ps, id, &n, &m); 866a2195becSreyk for (n = 0; n < m; n++) { 867a2195becSreyk if ((fd = dup(rlay->rl_s)) == -1) 868a2195becSreyk return (-1); 86951cb1125Sreyk if (proc_composev_imsg(ps, id, n, 87051cb1125Sreyk IMSG_CFG_RELAY, -1, fd, iov, c) != 0) { 87151cb1125Sreyk log_warn("%s: failed to compose " 87251cb1125Sreyk "IMSG_CFG_RELAY imsg for `%s'", 87351cb1125Sreyk __func__, rlay->rl_conf.name); 87451cb1125Sreyk return (-1); 87551cb1125Sreyk } 87651cb1125Sreyk /* Prevent fd exhaustion in the parent. */ 87751cb1125Sreyk if (proc_flush_imsg(ps, id, n) == -1) { 87851cb1125Sreyk log_warn("%s: failed to flush " 87951cb1125Sreyk "IMSG_CFG_RELAY imsg for `%s'", 88051cb1125Sreyk __func__, rlay->rl_conf.name); 88151cb1125Sreyk return (-1); 88251cb1125Sreyk } 883a2195becSreyk } 884a2195becSreyk } else { 88551cb1125Sreyk if (proc_composev(ps, id, 88651cb1125Sreyk IMSG_CFG_RELAY, iov, c) != 0) { 88751cb1125Sreyk log_warn("%s: failed to compose " 88851cb1125Sreyk "IMSG_CFG_RELAY imsg for `%s'", 88951cb1125Sreyk __func__, rlay->rl_conf.name); 89051cb1125Sreyk return (-1); 89151cb1125Sreyk } 892a2195becSreyk } 893416fa9c0Sreyk 894f2f4e153Sreyk /* cert keypairs */ 895f2f4e153Sreyk TAILQ_FOREACH(cert, env->sc_certs, cert_entry) { 896f2f4e153Sreyk if (cert->cert_relayid != rlay->rl_conf.id) 897f2f4e153Sreyk continue; 898114ce177Sclaudio n = -1; 899114ce177Sclaudio proc_range(ps, id, &n, &m); 900f2f4e153Sreyk for (n = 0; (what & CONFIG_CERTS) && n < m; n++) { 901f2f4e153Sreyk if (cert->cert_fd != -1 && 902114ce177Sclaudio config_setrelayfd(ps, id, n, 903f2f4e153Sreyk cert->cert_id, cert->cert_relayid, 904f2f4e153Sreyk RELAY_FD_CERT, cert->cert_fd) == -1) { 905114ce177Sclaudio log_warn("%s: fd passing failed for " 906114ce177Sclaudio "`%s'", __func__, 907114ce177Sclaudio rlay->rl_conf.name); 908114ce177Sclaudio return (-1); 909114ce177Sclaudio } 91031604b98Sreyk if (id == PROC_RELAY && 91131604b98Sreyk cert->cert_ocsp_fd != -1 && 91231604b98Sreyk config_setrelayfd(ps, id, n, 91331604b98Sreyk cert->cert_id, cert->cert_relayid, 91431604b98Sreyk RELAY_FD_OCSP, cert->cert_ocsp_fd) == -1) { 91531604b98Sreyk log_warn("%s: fd passing failed for " 91631604b98Sreyk "`%s'", __func__, 91731604b98Sreyk rlay->rl_conf.name); 91831604b98Sreyk return (-1); 91931604b98Sreyk } 920f2f4e153Sreyk if (id == PROC_CA && 921f2f4e153Sreyk cert->cert_key_fd != -1 && 922114ce177Sclaudio config_setrelayfd(ps, id, n, 923f2f4e153Sreyk cert->cert_id, cert->cert_relayid, 924f2f4e153Sreyk RELAY_FD_KEY, cert->cert_key_fd) == -1) { 925f2f4e153Sreyk log_warn("%s: fd passing failed for " 926f2f4e153Sreyk "`%s'", __func__, 927f2f4e153Sreyk rlay->rl_conf.name); 928f2f4e153Sreyk return (-1); 929f2f4e153Sreyk } 930f2f4e153Sreyk } 931f2f4e153Sreyk } 932f2f4e153Sreyk 933f2f4e153Sreyk /* CA certs */ 934f2f4e153Sreyk if (what & CONFIG_CERTS) { 935f2f4e153Sreyk n = -1; 936f2f4e153Sreyk proc_range(ps, id, &n, &m); 937f2f4e153Sreyk for (n = 0; n < m; n++) { 938f2f4e153Sreyk if (rlay->rl_tls_ca_fd != -1 && 939f2f4e153Sreyk config_setrelayfd(ps, id, n, 0, 940114ce177Sclaudio rlay->rl_conf.id, RELAY_FD_CACERT, 941114ce177Sclaudio rlay->rl_tls_ca_fd) == -1) { 942114ce177Sclaudio log_warn("%s: fd passing failed for " 943114ce177Sclaudio "`%s'", __func__, 944114ce177Sclaudio rlay->rl_conf.name); 945114ce177Sclaudio return (-1); 946114ce177Sclaudio } 947114ce177Sclaudio if (rlay->rl_tls_cacert_fd != -1 && 948f2f4e153Sreyk config_setrelayfd(ps, id, n, 0, 949114ce177Sclaudio rlay->rl_conf.id, RELAY_FD_CAFILE, 950114ce177Sclaudio rlay->rl_tls_cacert_fd) == -1) { 951114ce177Sclaudio log_warn("%s: fd passing failed for " 952114ce177Sclaudio "`%s'", __func__, 953114ce177Sclaudio rlay->rl_conf.name); 954114ce177Sclaudio return (-1); 955114ce177Sclaudio } 95692388deeStb if (rlay->rl_tls_client_ca_fd != -1 && 95792388deeStb config_setrelayfd(ps, id, n, 0, 95892388deeStb rlay->rl_conf.id, RELAY_FD_CLIENTCACERT, 95992388deeStb rlay->rl_tls_client_ca_fd) == -1) { 96092388deeStb log_warn("%s: fd passing failed for " 96192388deeStb "`%s'", __func__, 96292388deeStb rlay->rl_conf.name); 96392388deeStb return (-1); 96492388deeStb } 965114ce177Sclaudio /* Prevent fd exhaustion in the parent. */ 966114ce177Sclaudio if (proc_flush_imsg(ps, id, n) == -1) { 967114ce177Sclaudio log_warn("%s: failed to flush " 968114ce177Sclaudio "IMSG_CFG_RELAY imsg for `%s'", 969114ce177Sclaudio __func__, rlay->rl_conf.name); 970114ce177Sclaudio return (-1); 971114ce177Sclaudio } 972114ce177Sclaudio } 973114ce177Sclaudio } 974114ce177Sclaudio 9753d77879fSreyk if ((what & CONFIG_TABLES) == 0) 9763d77879fSreyk continue; 9773d77879fSreyk 978416fa9c0Sreyk /* Now send the tables associated to this relay */ 979416fa9c0Sreyk TAILQ_FOREACH(rlt, &rlay->rl_tables, rlt_entry) { 980416fa9c0Sreyk crt.id = rlt->rlt_table->conf.id; 981416fa9c0Sreyk crt.relayid = rlay->rl_conf.id; 982416fa9c0Sreyk crt.mode = rlt->rlt_mode; 983118081d7Sreyk crt.flags = rlt->rlt_flags; 984416fa9c0Sreyk 985416fa9c0Sreyk c = 0; 986416fa9c0Sreyk iov[c].iov_base = &crt; 987416fa9c0Sreyk iov[c++].iov_len = sizeof(crt); 988416fa9c0Sreyk 989c2c37c5dSreyk proc_composev(ps, id, IMSG_CFG_RELAY_TABLE, iov, c); 990416fa9c0Sreyk } 991a2195becSreyk } 992a2195becSreyk 99351cb1125Sreyk /* Close server socket early to prevent fd exhaustion in the parent. */ 99451cb1125Sreyk if (rlay->rl_s != -1) { 995a2195becSreyk close(rlay->rl_s); 996a2195becSreyk rlay->rl_s = -1; 99751cb1125Sreyk } 99892388deeStb if (rlay->rl_tls_client_ca_fd != -1) { 99992388deeStb close(rlay->rl_tls_client_ca_fd); 100092388deeStb rlay->rl_tls_client_ca_fd = -1; 100192388deeStb } 1002114ce177Sclaudio if (rlay->rl_tls_cacert_fd != -1) { 1003114ce177Sclaudio close(rlay->rl_tls_cacert_fd); 1004114ce177Sclaudio rlay->rl_tls_cacert_fd = -1; 1005114ce177Sclaudio } 1006114ce177Sclaudio if (rlay->rl_tls_ca_fd != -1) { 1007114ce177Sclaudio close(rlay->rl_tls_ca_fd); 1008114ce177Sclaudio rlay->rl_tls_ca_fd = -1; 1009114ce177Sclaudio } 1010f2f4e153Sreyk TAILQ_FOREACH(cert, env->sc_certs, cert_entry) { 1011f2f4e153Sreyk if (cert->cert_relayid != rlay->rl_conf.id) 1012f2f4e153Sreyk continue; 1013f2f4e153Sreyk 1014f2f4e153Sreyk if (cert->cert_fd != -1) { 1015f2f4e153Sreyk close(cert->cert_fd); 1016f2f4e153Sreyk cert->cert_fd = -1; 1017f2f4e153Sreyk } 1018f2f4e153Sreyk if (cert->cert_key_fd != -1) { 1019f2f4e153Sreyk close(cert->cert_key_fd); 1020f2f4e153Sreyk cert->cert_key_fd = -1; 1021f2f4e153Sreyk } 102231604b98Sreyk if (cert->cert_ocsp_fd != -1) { 102331604b98Sreyk close(cert->cert_ocsp_fd); 102431604b98Sreyk cert->cert_ocsp_fd = -1; 102531604b98Sreyk } 1026f2f4e153Sreyk } 102792388deeStb if (rlay->rl_tls_client_ca_fd != -1) { 102892388deeStb close(rlay->rl_tls_client_ca_fd); 102992388deeStb rlay->rl_tls_client_ca_fd = -1; 103092388deeStb } 1031a2195becSreyk 1032a2195becSreyk return (0); 1033a2195becSreyk } 1034a2195becSreyk 1035a2195becSreyk int 1036a2195becSreyk config_getrelay(struct relayd *env, struct imsg *imsg) 1037a2195becSreyk { 1038a2195becSreyk struct privsep *ps = env->sc_ps; 1039a2195becSreyk struct relay *rlay; 1040a2195becSreyk u_int8_t *p = imsg->data; 1041a2195becSreyk size_t s; 1042a2195becSreyk 1043a2195becSreyk if ((rlay = calloc(1, sizeof(*rlay))) == NULL) 1044a2195becSreyk return (-1); 1045a2195becSreyk 1046a2195becSreyk IMSG_SIZE_CHECK(imsg, &rlay->rl_conf); 1047a2195becSreyk memcpy(&rlay->rl_conf, p, sizeof(rlay->rl_conf)); 1048a2195becSreyk s = sizeof(rlay->rl_conf); 1049a2195becSreyk 1050a1416996Sclaudio rlay->rl_s = imsg_get_fd(imsg); 1051114ce177Sclaudio rlay->rl_tls_ca_fd = -1; 1052114ce177Sclaudio rlay->rl_tls_cacert_fd = -1; 105392388deeStb rlay->rl_tls_client_ca_fd = -1; 1054a2195becSreyk 1055a2195becSreyk if (ps->ps_what[privsep_process] & CONFIG_PROTOS) { 1056a2195becSreyk if (rlay->rl_conf.proto == EMPTY_ID) 1057a2195becSreyk rlay->rl_proto = &env->sc_proto_default; 1058a2195becSreyk else if ((rlay->rl_proto = 1059a2195becSreyk proto_find(env, rlay->rl_conf.proto)) == NULL) { 1060a2195becSreyk log_debug("%s: unknown protocol", __func__); 1061a2195becSreyk goto fail; 1062a2195becSreyk } 1063a2195becSreyk } 1064a2195becSreyk 10659660c10cStedu if ((off_t)(IMSG_DATA_SIZE(imsg) - s) < 1066f2f4e153Sreyk (rlay->rl_conf.tls_cakey_len)) { 1067a2195becSreyk log_debug("%s: invalid message length", __func__); 1068a2195becSreyk goto fail; 1069a2195becSreyk } 1070a2195becSreyk 10717bb52228Sreyk if (rlay->rl_conf.tls_cakey_len) { 10727bb52228Sreyk if ((rlay->rl_tls_cakey = get_data(p + s, 10737bb52228Sreyk rlay->rl_conf.tls_cakey_len)) == NULL) 1074cf39ad79Sreyk goto fail; 10757bb52228Sreyk s += rlay->rl_conf.tls_cakey_len; 1076cf39ad79Sreyk } 1077a2195becSreyk 1078416fa9c0Sreyk TAILQ_INIT(&rlay->rl_tables); 1079a2195becSreyk TAILQ_INSERT_TAIL(env->sc_relays, rlay, rl_entry); 1080a2195becSreyk 1081a2195becSreyk env->sc_relaycount++; 1082a2195becSreyk 1083a2195becSreyk DPRINTF("%s: %s %d received relay %s", __func__, 1084a2195becSreyk ps->ps_title[privsep_process], ps->ps_instance, 1085a2195becSreyk rlay->rl_conf.name); 1086a2195becSreyk 1087a2195becSreyk return (0); 1088a2195becSreyk 1089a2195becSreyk fail: 1090114ce177Sclaudio free(rlay->rl_tls_cakey); 1091a2195becSreyk close(rlay->rl_s); 1092a2195becSreyk free(rlay); 1093a2195becSreyk return (-1); 1094a2195becSreyk } 1095416fa9c0Sreyk 1096416fa9c0Sreyk int 1097416fa9c0Sreyk config_getrelaytable(struct relayd *env, struct imsg *imsg) 1098416fa9c0Sreyk { 1099416fa9c0Sreyk struct relay_table *rlt = NULL; 1100416fa9c0Sreyk struct ctl_relaytable crt; 1101416fa9c0Sreyk struct relay *rlay; 1102416fa9c0Sreyk struct table *table; 1103416fa9c0Sreyk u_int8_t *p = imsg->data; 1104416fa9c0Sreyk 1105416fa9c0Sreyk IMSG_SIZE_CHECK(imsg, &crt); 1106416fa9c0Sreyk memcpy(&crt, p, sizeof(crt)); 1107416fa9c0Sreyk 1108416fa9c0Sreyk if ((rlay = relay_find(env, crt.relayid)) == NULL) { 1109416fa9c0Sreyk log_debug("%s: unknown relay", __func__); 1110416fa9c0Sreyk goto fail; 1111416fa9c0Sreyk } 1112416fa9c0Sreyk 1113416fa9c0Sreyk if ((table = table_find(env, crt.id)) == NULL) { 1114416fa9c0Sreyk log_debug("%s: unknown table", __func__); 1115416fa9c0Sreyk goto fail; 1116416fa9c0Sreyk } 1117416fa9c0Sreyk 1118416fa9c0Sreyk if ((rlt = calloc(1, sizeof(*rlt))) == NULL) 1119416fa9c0Sreyk goto fail; 1120416fa9c0Sreyk 1121416fa9c0Sreyk rlt->rlt_table = table; 1122416fa9c0Sreyk rlt->rlt_mode = crt.mode; 1123118081d7Sreyk rlt->rlt_flags = crt.flags; 1124416fa9c0Sreyk 1125416fa9c0Sreyk TAILQ_INSERT_TAIL(&rlay->rl_tables, rlt, rlt_entry); 1126416fa9c0Sreyk 1127416fa9c0Sreyk DPRINTF("%s: %s %d received relay table %s for relay %s", __func__, 1128416fa9c0Sreyk env->sc_ps->ps_title[privsep_process], env->sc_ps->ps_instance, 1129416fa9c0Sreyk table->conf.name, rlay->rl_conf.name); 1130416fa9c0Sreyk 1131416fa9c0Sreyk return (0); 1132416fa9c0Sreyk 1133416fa9c0Sreyk fail: 1134416fa9c0Sreyk free(rlt); 1135416fa9c0Sreyk return (-1); 1136416fa9c0Sreyk } 1137114ce177Sclaudio 1138114ce177Sclaudio int 1139114ce177Sclaudio config_getrelayfd(struct relayd *env, struct imsg *imsg) 1140114ce177Sclaudio { 1141114ce177Sclaudio struct ctl_relayfd crfd; 1142f2f4e153Sreyk struct relay *rlay = NULL; 1143f2f4e153Sreyk struct relay_cert *cert; 1144114ce177Sclaudio u_int8_t *p = imsg->data; 1145114ce177Sclaudio 1146114ce177Sclaudio IMSG_SIZE_CHECK(imsg, &crfd); 1147114ce177Sclaudio memcpy(&crfd, p, sizeof(crfd)); 1148114ce177Sclaudio 1149f2f4e153Sreyk switch (crfd.type) { 1150f2f4e153Sreyk case RELAY_FD_CERT: 1151f2f4e153Sreyk case RELAY_FD_KEY: 115231604b98Sreyk case RELAY_FD_OCSP: 1153f2f4e153Sreyk if ((cert = cert_find(env, crfd.id)) == NULL) { 1154f2f4e153Sreyk if ((cert = cert_add(env, crfd.id)) == NULL) 1155f2f4e153Sreyk return (-1); 1156f2f4e153Sreyk cert->cert_relayid = crfd.relayid; 1157f2f4e153Sreyk } 1158f2f4e153Sreyk /* FALLTHROUGH */ 1159f2f4e153Sreyk default: 1160114ce177Sclaudio if ((rlay = relay_find(env, crfd.relayid)) == NULL) { 1161114ce177Sclaudio log_debug("%s: unknown relay", __func__); 1162f2f4e153Sreyk return (-1); 1163f2f4e153Sreyk } 1164f2f4e153Sreyk break; 1165114ce177Sclaudio } 1166114ce177Sclaudio 1167114ce177Sclaudio switch (crfd.type) { 1168114ce177Sclaudio case RELAY_FD_CERT: 1169a1416996Sclaudio cert->cert_fd = imsg_get_fd(imsg); 1170f2f4e153Sreyk break; 1171f2f4e153Sreyk case RELAY_FD_KEY: 1172a1416996Sclaudio cert->cert_key_fd = imsg_get_fd(imsg); 1173114ce177Sclaudio break; 117431604b98Sreyk case RELAY_FD_OCSP: 1175a1416996Sclaudio cert->cert_ocsp_fd = imsg_get_fd(imsg); 117631604b98Sreyk break; 1177114ce177Sclaudio case RELAY_FD_CACERT: 1178a1416996Sclaudio rlay->rl_tls_ca_fd = imsg_get_fd(imsg); 1179114ce177Sclaudio break; 1180114ce177Sclaudio case RELAY_FD_CAFILE: 1181a1416996Sclaudio rlay->rl_tls_cacert_fd = imsg_get_fd(imsg); 1182114ce177Sclaudio break; 118392388deeStb case RELAY_FD_CLIENTCACERT: 1184*f4d46194Sclaudio rlay->rl_tls_client_ca_fd = imsg_get_fd(imsg); 118592388deeStb break; 1186114ce177Sclaudio } 1187114ce177Sclaudio 1188114ce177Sclaudio DPRINTF("%s: %s %d received relay fd %d type %d for relay %s", __func__, 1189114ce177Sclaudio env->sc_ps->ps_title[privsep_process], env->sc_ps->ps_instance, 1190114ce177Sclaudio imsg->fd, crfd.type, rlay->rl_conf.name); 1191114ce177Sclaudio 1192114ce177Sclaudio return (0); 1193114ce177Sclaudio } 1194