1*15c8ad53Sjca /* $OpenBSD: unwind.c,v 1.48 2020/08/29 22:29:27 jca Exp $ */ 2018cebfbSflorian 3018cebfbSflorian /* 4018cebfbSflorian * Copyright (c) 2018 Florian Obser <florian@openbsd.org> 5018cebfbSflorian * Copyright (c) 2005 Claudio Jeker <claudio@openbsd.org> 6018cebfbSflorian * Copyright (c) 2004 Esben Norby <norby@openbsd.org> 7018cebfbSflorian * Copyright (c) 2003, 2004 Henning Brauer <henning@openbsd.org> 8018cebfbSflorian * 9018cebfbSflorian * Permission to use, copy, modify, and distribute this software for any 10018cebfbSflorian * purpose with or without fee is hereby granted, provided that the above 11018cebfbSflorian * copyright notice and this permission notice appear in all copies. 12018cebfbSflorian * 13018cebfbSflorian * THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES 14018cebfbSflorian * WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF 15018cebfbSflorian * MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR 16018cebfbSflorian * ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES 17018cebfbSflorian * WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN 18018cebfbSflorian * ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF 19018cebfbSflorian * OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE. 20018cebfbSflorian */ 21018cebfbSflorian #include <sys/types.h> 22018cebfbSflorian #include <sys/queue.h> 23018cebfbSflorian #include <sys/socket.h> 24296cf316Sflorian #include <sys/stat.h> 25018cebfbSflorian #include <sys/syslog.h> 26018cebfbSflorian #include <sys/wait.h> 27018cebfbSflorian 28018cebfbSflorian #include <net/if.h> 29018cebfbSflorian #include <net/route.h> 30018cebfbSflorian 31018cebfbSflorian #include <err.h> 32018cebfbSflorian #include <errno.h> 33018cebfbSflorian #include <event.h> 34018cebfbSflorian #include <fcntl.h> 35018cebfbSflorian #include <imsg.h> 36018cebfbSflorian #include <netdb.h> 372f29e846Sflorian #include <asr.h> 38018cebfbSflorian #include <pwd.h> 39018cebfbSflorian #include <stdio.h> 40018cebfbSflorian #include <stdlib.h> 41018cebfbSflorian #include <string.h> 42018cebfbSflorian #include <signal.h> 43018cebfbSflorian #include <unistd.h> 44018cebfbSflorian 4558b5b9b8Sflorian #include "log.h" 46018cebfbSflorian #include "unwind.h" 47018cebfbSflorian #include "frontend.h" 48018cebfbSflorian #include "resolver.h" 49018cebfbSflorian #include "control.h" 50018cebfbSflorian 5190d56d5fSflorian #define TRUST_ANCHOR_FILE "/var/db/unwind.key" 52296cf316Sflorian 53018cebfbSflorian __dead void usage(void); 54018cebfbSflorian __dead void main_shutdown(void); 55018cebfbSflorian 56018cebfbSflorian void main_sig_handler(int, short, void *); 57018cebfbSflorian 58018cebfbSflorian static pid_t start_child(int, char *, int, int, int); 59018cebfbSflorian 60018cebfbSflorian void main_dispatch_frontend(int, short, void *); 61018cebfbSflorian void main_dispatch_resolver(int, short, void *); 62018cebfbSflorian 63f3ea9bf1Sflorian static int main_imsg_send_ipc_sockets(struct imsgbuf *, struct imsgbuf *); 64bb81f7e1Sflorian static int main_imsg_send_config(struct uw_conf *); 65018cebfbSflorian 66018cebfbSflorian int main_reload(void); 67b2501eadSflorian int main_sendall(enum imsg_type, void *, uint16_t); 68d265a5d3Sflorian void open_ports(void); 6928ba4729Sflorian void solicit_dns_proposals(void); 702d988276Sflorian void send_blocklist_fd(void); 71018cebfbSflorian 72bb81f7e1Sflorian struct uw_conf *main_conf; 73018cebfbSflorian struct imsgev *iev_frontend; 74018cebfbSflorian struct imsgev *iev_resolver; 75572e5ac0Skn char *conffile; 76018cebfbSflorian 77018cebfbSflorian pid_t frontend_pid; 78018cebfbSflorian pid_t resolver_pid; 79018cebfbSflorian 80018cebfbSflorian uint32_t cmd_opts; 81018cebfbSflorian 8228ba4729Sflorian int routesock; 8328ba4729Sflorian 84018cebfbSflorian void 85018cebfbSflorian main_sig_handler(int sig, short event, void *arg) 86018cebfbSflorian { 87018cebfbSflorian /* 88018cebfbSflorian * Normal signal handler rules don't apply because libevent 89018cebfbSflorian * decouples for us. 90018cebfbSflorian */ 91018cebfbSflorian 92018cebfbSflorian switch (sig) { 93018cebfbSflorian case SIGTERM: 94018cebfbSflorian case SIGINT: 955472663aSflorian main_shutdown(); 96018cebfbSflorian break; 97018cebfbSflorian case SIGHUP: 98018cebfbSflorian if (main_reload() == -1) 99018cebfbSflorian log_warnx("configuration reload failed"); 100018cebfbSflorian else 101018cebfbSflorian log_debug("configuration reloaded"); 102018cebfbSflorian break; 103018cebfbSflorian default: 104018cebfbSflorian fatalx("unexpected signal"); 105018cebfbSflorian } 106018cebfbSflorian } 107018cebfbSflorian 108018cebfbSflorian __dead void 109018cebfbSflorian usage(void) 110018cebfbSflorian { 111018cebfbSflorian extern char *__progname; 112018cebfbSflorian 113018cebfbSflorian fprintf(stderr, "usage: %s [-dnv] [-f file] [-s socket]\n", 114018cebfbSflorian __progname); 115018cebfbSflorian exit(1); 116018cebfbSflorian } 117018cebfbSflorian 118018cebfbSflorian int 119018cebfbSflorian main(int argc, char *argv[]) 120018cebfbSflorian { 121018cebfbSflorian struct event ev_sigint, ev_sigterm, ev_sighup; 122bb81f7e1Sflorian int ch, debug = 0, resolver_flag = 0, frontend_flag = 0; 123f3ea9bf1Sflorian int frontend_routesock, rtfilter; 124bb81f7e1Sflorian int pipe_main2frontend[2], pipe_main2resolver[2]; 125d1b04a40Sflorian int control_fd, ta_fd; 126bb81f7e1Sflorian char *csock, *saved_argv0; 127018cebfbSflorian 128018cebfbSflorian csock = UNWIND_SOCKET; 129018cebfbSflorian 130018cebfbSflorian log_init(1, LOG_DAEMON); /* Log to stderr until daemonized. */ 131018cebfbSflorian log_setverbose(1); 132018cebfbSflorian 133018cebfbSflorian saved_argv0 = argv[0]; 134018cebfbSflorian if (saved_argv0 == NULL) 135018cebfbSflorian saved_argv0 = "unwind"; 136018cebfbSflorian 137f3ea9bf1Sflorian while ((ch = getopt(argc, argv, "dEFf:ns:v")) != -1) { 138018cebfbSflorian switch (ch) { 139018cebfbSflorian case 'd': 140018cebfbSflorian debug = 1; 141018cebfbSflorian break; 142018cebfbSflorian case 'E': 143018cebfbSflorian resolver_flag = 1; 144018cebfbSflorian break; 145018cebfbSflorian case 'F': 146018cebfbSflorian frontend_flag = 1; 147018cebfbSflorian break; 148018cebfbSflorian case 'f': 149018cebfbSflorian conffile = optarg; 150018cebfbSflorian break; 151018cebfbSflorian case 'n': 152018cebfbSflorian cmd_opts |= OPT_NOACTION; 153018cebfbSflorian break; 154018cebfbSflorian case 's': 155018cebfbSflorian csock = optarg; 156018cebfbSflorian break; 157018cebfbSflorian case 'v': 158e5d1a61aSflorian if (cmd_opts & OPT_VERBOSE2) 159e5d1a61aSflorian cmd_opts |= OPT_VERBOSE3; 160018cebfbSflorian if (cmd_opts & OPT_VERBOSE) 161018cebfbSflorian cmd_opts |= OPT_VERBOSE2; 162018cebfbSflorian cmd_opts |= OPT_VERBOSE; 163018cebfbSflorian break; 164018cebfbSflorian default: 165018cebfbSflorian usage(); 166018cebfbSflorian } 167018cebfbSflorian } 168018cebfbSflorian 169018cebfbSflorian argc -= optind; 170018cebfbSflorian argv += optind; 171f3ea9bf1Sflorian if (argc > 0 || (resolver_flag && frontend_flag)) 172018cebfbSflorian usage(); 173018cebfbSflorian 174018cebfbSflorian if (resolver_flag) 175e5d1a61aSflorian resolver(debug, cmd_opts & (OPT_VERBOSE | OPT_VERBOSE2 | 176e5d1a61aSflorian OPT_VERBOSE3)); 177018cebfbSflorian else if (frontend_flag) 178e5d1a61aSflorian frontend(debug, cmd_opts & (OPT_VERBOSE | OPT_VERBOSE2 | 179e5d1a61aSflorian OPT_VERBOSE3)); 180018cebfbSflorian 181572e5ac0Skn if ((main_conf = parse_config(conffile)) == NULL) 182018cebfbSflorian exit(1); 183018cebfbSflorian 184018cebfbSflorian if (cmd_opts & OPT_NOACTION) { 185018cebfbSflorian if (cmd_opts & OPT_VERBOSE) 186018cebfbSflorian print_config(main_conf); 187018cebfbSflorian else 188018cebfbSflorian fprintf(stderr, "configuration OK\n"); 189018cebfbSflorian exit(0); 190018cebfbSflorian } 191018cebfbSflorian 192018cebfbSflorian /* Check for root privileges. */ 193018cebfbSflorian if (geteuid()) 194018cebfbSflorian errx(1, "need root privileges"); 195018cebfbSflorian 196018cebfbSflorian /* Check for assigned daemon user */ 197018cebfbSflorian if (getpwnam(UNWIND_USER) == NULL) 198018cebfbSflorian errx(1, "unknown user %s", UNWIND_USER); 199018cebfbSflorian 200018cebfbSflorian log_init(debug, LOG_DAEMON); 201e5d1a61aSflorian log_setverbose(cmd_opts & (OPT_VERBOSE | OPT_VERBOSE2 | OPT_VERBOSE3)); 202018cebfbSflorian 203018cebfbSflorian if (!debug) 204018cebfbSflorian daemon(1, 0); 205018cebfbSflorian 206018cebfbSflorian if (socketpair(AF_UNIX, SOCK_STREAM | SOCK_CLOEXEC | SOCK_NONBLOCK, 207018cebfbSflorian PF_UNSPEC, pipe_main2frontend) == -1) 208018cebfbSflorian fatal("main2frontend socketpair"); 209018cebfbSflorian if (socketpair(AF_UNIX, SOCK_STREAM | SOCK_CLOEXEC | SOCK_NONBLOCK, 210018cebfbSflorian PF_UNSPEC, pipe_main2resolver) == -1) 211018cebfbSflorian fatal("main2resolver socketpair"); 212018cebfbSflorian 213018cebfbSflorian /* Start children. */ 214018cebfbSflorian resolver_pid = start_child(PROC_RESOLVER, saved_argv0, 215018cebfbSflorian pipe_main2resolver[1], debug, cmd_opts & (OPT_VERBOSE | 216e5d1a61aSflorian OPT_VERBOSE2 | OPT_VERBOSE3)); 217018cebfbSflorian frontend_pid = start_child(PROC_FRONTEND, saved_argv0, 218018cebfbSflorian pipe_main2frontend[1], debug, cmd_opts & (OPT_VERBOSE | 219e5d1a61aSflorian OPT_VERBOSE2 | OPT_VERBOSE3)); 220018cebfbSflorian 221bb81f7e1Sflorian uw_process = PROC_MAIN; 222bb81f7e1Sflorian log_procinit(log_procnames[uw_process]); 223018cebfbSflorian 224018cebfbSflorian event_init(); 225018cebfbSflorian 226018cebfbSflorian /* Setup signal handler. */ 227018cebfbSflorian signal_set(&ev_sigint, SIGINT, main_sig_handler, NULL); 228018cebfbSflorian signal_set(&ev_sigterm, SIGTERM, main_sig_handler, NULL); 229018cebfbSflorian signal_set(&ev_sighup, SIGHUP, main_sig_handler, NULL); 230018cebfbSflorian signal_add(&ev_sigint, NULL); 231018cebfbSflorian signal_add(&ev_sigterm, NULL); 232018cebfbSflorian signal_add(&ev_sighup, NULL); 233018cebfbSflorian signal(SIGPIPE, SIG_IGN); 234018cebfbSflorian 235018cebfbSflorian /* Setup pipes to children. */ 236018cebfbSflorian 237018cebfbSflorian if ((iev_frontend = malloc(sizeof(struct imsgev))) == NULL || 238018cebfbSflorian (iev_resolver = malloc(sizeof(struct imsgev))) == NULL) 239018cebfbSflorian fatal(NULL); 240018cebfbSflorian imsg_init(&iev_frontend->ibuf, pipe_main2frontend[0]); 241018cebfbSflorian iev_frontend->handler = main_dispatch_frontend; 242018cebfbSflorian imsg_init(&iev_resolver->ibuf, pipe_main2resolver[0]); 243018cebfbSflorian iev_resolver->handler = main_dispatch_resolver; 244018cebfbSflorian 245b2501eadSflorian /* Setup event handlers for pipes. */ 246018cebfbSflorian iev_frontend->events = EV_READ; 247018cebfbSflorian event_set(&iev_frontend->ev, iev_frontend->ibuf.fd, 248018cebfbSflorian iev_frontend->events, iev_frontend->handler, iev_frontend); 249018cebfbSflorian event_add(&iev_frontend->ev, NULL); 250018cebfbSflorian 251018cebfbSflorian iev_resolver->events = EV_READ; 252bb81f7e1Sflorian event_set(&iev_resolver->ev, iev_resolver->ibuf.fd, 253bb81f7e1Sflorian iev_resolver->events, iev_resolver->handler, iev_resolver); 254018cebfbSflorian event_add(&iev_resolver->ev, NULL); 255018cebfbSflorian 256b2501eadSflorian if (main_imsg_send_ipc_sockets(&iev_frontend->ibuf, 257f3ea9bf1Sflorian &iev_resolver->ibuf)) 258018cebfbSflorian fatal("could not establish imsg links"); 259018cebfbSflorian 26049a108abSflorian open_ports(); 26149a108abSflorian 262018cebfbSflorian if ((control_fd = control_init(csock)) == -1) 263018cebfbSflorian fatalx("control socket setup failed"); 264018cebfbSflorian 2659e627e00Sflorian if ((frontend_routesock = socket(AF_ROUTE, SOCK_RAW | SOCK_CLOEXEC, 266df69c215Sderaadt AF_INET)) == -1) 267018cebfbSflorian fatal("route socket"); 268018cebfbSflorian 2692956dd86Sflorian rtfilter = ROUTE_FILTER(RTM_IFINFO) | ROUTE_FILTER(RTM_PROPOSAL); 2709e627e00Sflorian if (setsockopt(frontend_routesock, AF_ROUTE, ROUTE_MSGFILTER, 271df69c215Sderaadt &rtfilter, sizeof(rtfilter)) == -1) 272018cebfbSflorian fatal("setsockopt(ROUTE_MSGFILTER)"); 273018cebfbSflorian 27428ba4729Sflorian if ((routesock = socket(AF_ROUTE, SOCK_RAW | SOCK_CLOEXEC | 27528ba4729Sflorian SOCK_NONBLOCK, AF_INET6)) == -1) 27628ba4729Sflorian fatal("route socket"); 27728ba4729Sflorian shutdown(SHUT_RD, routesock); 27828ba4729Sflorian 279d1b04a40Sflorian if ((ta_fd = open(TRUST_ANCHOR_FILE, O_RDWR | O_CREAT, 0644)) == -1) 280d1b04a40Sflorian log_warn("%s", TRUST_ANCHOR_FILE); 281d1b04a40Sflorian 282d1b04a40Sflorian /* receiver handles failed open correctly */ 283d1b04a40Sflorian main_imsg_compose_frontend_fd(IMSG_TAFD, 0, ta_fd); 284d1b04a40Sflorian 285018cebfbSflorian main_imsg_compose_frontend_fd(IMSG_CONTROLFD, 0, control_fd); 286018cebfbSflorian main_imsg_compose_frontend_fd(IMSG_ROUTESOCK, 0, frontend_routesock); 287018cebfbSflorian main_imsg_send_config(main_conf); 288018cebfbSflorian 2892d988276Sflorian if (main_conf->blocklist_file != NULL) 2902d988276Sflorian send_blocklist_fd(); 2912d988276Sflorian 29249a108abSflorian if (pledge("stdio rpath sendfd", NULL) == -1) 293018cebfbSflorian fatal("pledge"); 294018cebfbSflorian 295018cebfbSflorian main_imsg_compose_frontend(IMSG_STARTUP, 0, NULL, 0); 296296cf316Sflorian main_imsg_compose_resolver(IMSG_STARTUP, 0, NULL, 0); 297018cebfbSflorian 298018cebfbSflorian event_dispatch(); 299018cebfbSflorian 300018cebfbSflorian main_shutdown(); 301018cebfbSflorian return (0); 302018cebfbSflorian } 303018cebfbSflorian 304018cebfbSflorian __dead void 305018cebfbSflorian main_shutdown(void) 306018cebfbSflorian { 307018cebfbSflorian pid_t pid; 308018cebfbSflorian int status; 309018cebfbSflorian 310018cebfbSflorian /* Close pipes. */ 311018cebfbSflorian msgbuf_clear(&iev_frontend->ibuf.w); 312018cebfbSflorian close(iev_frontend->ibuf.fd); 313018cebfbSflorian msgbuf_clear(&iev_resolver->ibuf.w); 314018cebfbSflorian close(iev_resolver->ibuf.fd); 315018cebfbSflorian 316018cebfbSflorian config_clear(main_conf); 317018cebfbSflorian 318018cebfbSflorian log_debug("waiting for children to terminate"); 319018cebfbSflorian do { 320018cebfbSflorian pid = wait(&status); 321018cebfbSflorian if (pid == -1) { 322018cebfbSflorian if (errno != EINTR && errno != ECHILD) 323018cebfbSflorian fatal("wait"); 324018cebfbSflorian } else if (WIFSIGNALED(status)) 325018cebfbSflorian log_warnx("%s terminated; signal %d", 326018cebfbSflorian (pid == resolver_pid) ? "resolver" : 327018cebfbSflorian "frontend", WTERMSIG(status)); 328018cebfbSflorian } while (pid != -1 || (pid == -1 && errno == EINTR)); 329018cebfbSflorian 330018cebfbSflorian free(iev_frontend); 331018cebfbSflorian free(iev_resolver); 332018cebfbSflorian 333018cebfbSflorian log_info("terminating"); 334018cebfbSflorian exit(0); 335018cebfbSflorian } 336018cebfbSflorian 337018cebfbSflorian static pid_t 338018cebfbSflorian start_child(int p, char *argv0, int fd, int debug, int verbose) 339018cebfbSflorian { 340018cebfbSflorian char *argv[7]; 341018cebfbSflorian int argc = 0; 342018cebfbSflorian pid_t pid; 343018cebfbSflorian 344018cebfbSflorian switch (pid = fork()) { 345018cebfbSflorian case -1: 346018cebfbSflorian fatal("cannot fork"); 347018cebfbSflorian case 0: 348018cebfbSflorian break; 349018cebfbSflorian default: 350018cebfbSflorian close(fd); 351018cebfbSflorian return (pid); 352018cebfbSflorian } 353018cebfbSflorian 354ef4f5895Syasuoka if (fd != 3) { 355018cebfbSflorian if (dup2(fd, 3) == -1) 356018cebfbSflorian fatal("cannot setup imsg fd"); 357ef4f5895Syasuoka } else if (fcntl(fd, F_SETFD, 0) == -1) 358ef4f5895Syasuoka fatal("cannot setup imsg fd"); 359018cebfbSflorian 360018cebfbSflorian argv[argc++] = argv0; 361018cebfbSflorian switch (p) { 362018cebfbSflorian case PROC_MAIN: 363018cebfbSflorian fatalx("Can not start main process"); 364018cebfbSflorian case PROC_RESOLVER: 365018cebfbSflorian argv[argc++] = "-E"; 366018cebfbSflorian break; 367018cebfbSflorian case PROC_FRONTEND: 368018cebfbSflorian argv[argc++] = "-F"; 369018cebfbSflorian break; 370018cebfbSflorian } 371018cebfbSflorian if (debug) 372018cebfbSflorian argv[argc++] = "-d"; 373018cebfbSflorian if (verbose & OPT_VERBOSE) 374018cebfbSflorian argv[argc++] = "-v"; 375018cebfbSflorian if (verbose & OPT_VERBOSE2) 376018cebfbSflorian argv[argc++] = "-v"; 377e5d1a61aSflorian if (verbose & OPT_VERBOSE3) 378e5d1a61aSflorian argv[argc++] = "-v"; 379018cebfbSflorian argv[argc++] = NULL; 380018cebfbSflorian 381018cebfbSflorian execvp(argv0, argv); 382018cebfbSflorian fatal("execvp"); 383018cebfbSflorian } 384018cebfbSflorian 385018cebfbSflorian void 386018cebfbSflorian main_dispatch_frontend(int fd, short event, void *bula) 387018cebfbSflorian { 388018cebfbSflorian struct imsgev *iev = bula; 389018cebfbSflorian struct imsgbuf *ibuf; 390018cebfbSflorian struct imsg imsg; 391018cebfbSflorian ssize_t n; 392018cebfbSflorian int shut = 0, verbose; 393018cebfbSflorian 394018cebfbSflorian ibuf = &iev->ibuf; 395018cebfbSflorian 396018cebfbSflorian if (event & EV_READ) { 397018cebfbSflorian if ((n = imsg_read(ibuf)) == -1 && errno != EAGAIN) 398018cebfbSflorian fatal("imsg_read error"); 399018cebfbSflorian if (n == 0) /* Connection closed. */ 400018cebfbSflorian shut = 1; 401018cebfbSflorian } 402018cebfbSflorian if (event & EV_WRITE) { 403018cebfbSflorian if ((n = msgbuf_write(&ibuf->w)) == -1 && errno != EAGAIN) 404018cebfbSflorian fatal("msgbuf_write"); 405018cebfbSflorian if (n == 0) /* Connection closed. */ 406018cebfbSflorian shut = 1; 407018cebfbSflorian } 408018cebfbSflorian 409018cebfbSflorian for (;;) { 410018cebfbSflorian if ((n = imsg_get(ibuf, &imsg)) == -1) 411018cebfbSflorian fatal("imsg_get"); 412018cebfbSflorian if (n == 0) /* No more messages. */ 413018cebfbSflorian break; 414018cebfbSflorian 415018cebfbSflorian switch (imsg.hdr.type) { 416018cebfbSflorian case IMSG_STARTUP_DONE: 41728ba4729Sflorian solicit_dns_proposals(); 418018cebfbSflorian break; 419018cebfbSflorian case IMSG_CTL_RELOAD: 420018cebfbSflorian if (main_reload() == -1) 421018cebfbSflorian log_warnx("configuration reload failed"); 422018cebfbSflorian else 423018cebfbSflorian log_warnx("configuration reloaded"); 424018cebfbSflorian break; 425018cebfbSflorian case IMSG_CTL_LOG_VERBOSE: 426a9155f32Sflorian if (IMSG_DATA_SIZE(imsg) != sizeof(verbose)) 4272b821978Sflorian fatalx("%s: IMSG_CTL_LOG_VERBOSE wrong length: " 428a9155f32Sflorian "%lu", __func__, IMSG_DATA_SIZE(imsg)); 429018cebfbSflorian memcpy(&verbose, imsg.data, sizeof(verbose)); 430018cebfbSflorian log_setverbose(verbose); 431018cebfbSflorian break; 432018cebfbSflorian default: 433018cebfbSflorian log_debug("%s: error handling imsg %d", __func__, 434018cebfbSflorian imsg.hdr.type); 435018cebfbSflorian break; 436018cebfbSflorian } 437018cebfbSflorian imsg_free(&imsg); 438018cebfbSflorian } 439018cebfbSflorian if (!shut) 440018cebfbSflorian imsg_event_add(iev); 441018cebfbSflorian else { 442018cebfbSflorian /* This pipe is dead. Remove its event handler */ 443018cebfbSflorian event_del(&iev->ev); 444018cebfbSflorian event_loopexit(NULL); 445018cebfbSflorian } 446018cebfbSflorian } 447018cebfbSflorian 448018cebfbSflorian void 449018cebfbSflorian main_dispatch_resolver(int fd, short event, void *bula) 450018cebfbSflorian { 451018cebfbSflorian struct imsgev *iev = bula; 452018cebfbSflorian struct imsgbuf *ibuf; 453018cebfbSflorian struct imsg imsg; 454018cebfbSflorian ssize_t n; 455018cebfbSflorian int shut = 0; 456018cebfbSflorian 457018cebfbSflorian ibuf = &iev->ibuf; 458018cebfbSflorian 459018cebfbSflorian if (event & EV_READ) { 460018cebfbSflorian if ((n = imsg_read(ibuf)) == -1 && errno != EAGAIN) 461018cebfbSflorian fatal("imsg_read error"); 462018cebfbSflorian if (n == 0) /* Connection closed. */ 463018cebfbSflorian shut = 1; 464018cebfbSflorian } 465018cebfbSflorian if (event & EV_WRITE) { 466018cebfbSflorian if ((n = msgbuf_write(&ibuf->w)) == -1 && errno != EAGAIN) 467018cebfbSflorian fatal("msgbuf_write"); 468018cebfbSflorian if (n == 0) /* Connection closed. */ 469018cebfbSflorian shut = 1; 470018cebfbSflorian } 471018cebfbSflorian 472018cebfbSflorian for (;;) { 473018cebfbSflorian if ((n = imsg_get(ibuf, &imsg)) == -1) 474018cebfbSflorian fatal("imsg_get"); 475018cebfbSflorian if (n == 0) /* No more messages. */ 476018cebfbSflorian break; 477018cebfbSflorian 478018cebfbSflorian switch (imsg.hdr.type) { 479018cebfbSflorian default: 480018cebfbSflorian log_debug("%s: error handling imsg %d", __func__, 481018cebfbSflorian imsg.hdr.type); 482018cebfbSflorian break; 483018cebfbSflorian } 484018cebfbSflorian imsg_free(&imsg); 485018cebfbSflorian } 486018cebfbSflorian if (!shut) 487018cebfbSflorian imsg_event_add(iev); 488018cebfbSflorian else { 489018cebfbSflorian /* This pipe is dead. Remove its event handler. */ 490018cebfbSflorian event_del(&iev->ev); 491018cebfbSflorian event_loopexit(NULL); 492018cebfbSflorian } 493018cebfbSflorian } 494018cebfbSflorian 495018cebfbSflorian void 496018cebfbSflorian main_imsg_compose_frontend(int type, pid_t pid, void *data, uint16_t datalen) 497018cebfbSflorian { 498018cebfbSflorian if (iev_frontend) 499018cebfbSflorian imsg_compose_event(iev_frontend, type, 0, pid, -1, data, 500018cebfbSflorian datalen); 501018cebfbSflorian } 502018cebfbSflorian 503018cebfbSflorian void 504018cebfbSflorian main_imsg_compose_frontend_fd(int type, pid_t pid, int fd) 505018cebfbSflorian { 506018cebfbSflorian if (iev_frontend) 507018cebfbSflorian imsg_compose_event(iev_frontend, type, 0, pid, fd, NULL, 0); 508018cebfbSflorian } 509018cebfbSflorian 510018cebfbSflorian void 511018cebfbSflorian main_imsg_compose_resolver(int type, pid_t pid, void *data, uint16_t datalen) 512018cebfbSflorian { 513018cebfbSflorian if (iev_resolver) 514018cebfbSflorian imsg_compose_event(iev_resolver, type, 0, pid, -1, data, 515018cebfbSflorian datalen); 516018cebfbSflorian } 517018cebfbSflorian 518018cebfbSflorian void 519018cebfbSflorian imsg_event_add(struct imsgev *iev) 520018cebfbSflorian { 521018cebfbSflorian iev->events = EV_READ; 522018cebfbSflorian if (iev->ibuf.w.queued) 523018cebfbSflorian iev->events |= EV_WRITE; 524018cebfbSflorian 525018cebfbSflorian event_del(&iev->ev); 526018cebfbSflorian event_set(&iev->ev, iev->ibuf.fd, iev->events, iev->handler, iev); 527018cebfbSflorian event_add(&iev->ev, NULL); 528018cebfbSflorian } 529018cebfbSflorian 530018cebfbSflorian int 531018cebfbSflorian imsg_compose_event(struct imsgev *iev, uint16_t type, uint32_t peerid, 532018cebfbSflorian pid_t pid, int fd, void *data, uint16_t datalen) 533018cebfbSflorian { 534018cebfbSflorian int ret; 535018cebfbSflorian 536018cebfbSflorian if ((ret = imsg_compose(&iev->ibuf, type, peerid, pid, fd, data, 537018cebfbSflorian datalen)) != -1) 538018cebfbSflorian imsg_event_add(iev); 539018cebfbSflorian 540018cebfbSflorian return (ret); 541018cebfbSflorian } 542018cebfbSflorian 543018cebfbSflorian static int 544018cebfbSflorian main_imsg_send_ipc_sockets(struct imsgbuf *frontend_buf, 545f3ea9bf1Sflorian struct imsgbuf *resolver_buf) 546018cebfbSflorian { 547018cebfbSflorian int pipe_frontend2resolver[2]; 548018cebfbSflorian 549018cebfbSflorian if (socketpair(AF_UNIX, SOCK_STREAM | SOCK_CLOEXEC | SOCK_NONBLOCK, 550018cebfbSflorian PF_UNSPEC, pipe_frontend2resolver) == -1) 551018cebfbSflorian return (-1); 552018cebfbSflorian 553b2501eadSflorian if (imsg_compose(frontend_buf, IMSG_SOCKET_IPC_RESOLVER, 0, 0, 554018cebfbSflorian pipe_frontend2resolver[0], NULL, 0) == -1) 555018cebfbSflorian return (-1); 556b2501eadSflorian if (imsg_compose(resolver_buf, IMSG_SOCKET_IPC_FRONTEND, 0, 0, 557018cebfbSflorian pipe_frontend2resolver[1], NULL, 0) == -1) 558018cebfbSflorian return (-1); 559018cebfbSflorian 560018cebfbSflorian return (0); 561018cebfbSflorian } 562018cebfbSflorian 563018cebfbSflorian int 564018cebfbSflorian main_reload(void) 565018cebfbSflorian { 566bb81f7e1Sflorian struct uw_conf *xconf; 567018cebfbSflorian 568572e5ac0Skn if ((xconf = parse_config(conffile)) == NULL) 569018cebfbSflorian return (-1); 570018cebfbSflorian 571018cebfbSflorian if (main_imsg_send_config(xconf) == -1) 572018cebfbSflorian return (-1); 573018cebfbSflorian 574018cebfbSflorian merge_config(main_conf, xconf); 575018cebfbSflorian 5762d988276Sflorian if (main_conf->blocklist_file != NULL) 5772d988276Sflorian send_blocklist_fd(); 5782d988276Sflorian 579018cebfbSflorian return (0); 580018cebfbSflorian } 581018cebfbSflorian 582018cebfbSflorian int 583bb81f7e1Sflorian main_imsg_send_config(struct uw_conf *xconf) 584018cebfbSflorian { 585bb81f7e1Sflorian struct uw_forwarder *uw_forwarder; 586dd16127bSotto struct force_tree_entry *force_entry; 587018cebfbSflorian 588018cebfbSflorian /* Send fixed part of config to children. */ 589b2501eadSflorian if (main_sendall(IMSG_RECONF_CONF, xconf, sizeof(*xconf)) == -1) 590018cebfbSflorian return (-1); 591018cebfbSflorian 5922d988276Sflorian if (xconf->blocklist_file != NULL) { 5932d988276Sflorian if (main_sendall(IMSG_RECONF_BLOCKLIST_FILE, 5942d988276Sflorian xconf->blocklist_file, strlen(xconf->blocklist_file) + 1) 5952d988276Sflorian == -1) 5962d988276Sflorian return (-1); 5972d988276Sflorian } 5982d988276Sflorian 5993570995aSflorian /* send static forwarders to children */ 6007d055805Sflorian TAILQ_FOREACH(uw_forwarder, &xconf->uw_forwarder_list, entry) { 601bb81f7e1Sflorian if (main_sendall(IMSG_RECONF_FORWARDER, uw_forwarder, 602bb81f7e1Sflorian sizeof(*uw_forwarder)) == -1) 603018cebfbSflorian return (-1); 604018cebfbSflorian } 605018cebfbSflorian 6063570995aSflorian /* send static DoT forwarders to children */ 6077d055805Sflorian TAILQ_FOREACH(uw_forwarder, &xconf->uw_dot_forwarder_list, 6083570995aSflorian entry) { 609bb81f7e1Sflorian if (main_sendall(IMSG_RECONF_DOT_FORWARDER, uw_forwarder, 610bb81f7e1Sflorian sizeof(*uw_forwarder)) == -1) 6113570995aSflorian return (-1); 6123570995aSflorian } 613dd16127bSotto RB_FOREACH(force_entry, force_tree, &xconf->force) { 614dd16127bSotto if (main_sendall(IMSG_RECONF_FORCE, force_entry, 615dd16127bSotto sizeof(*force_entry)) == -1) 616dd16127bSotto return (-1); 617dd16127bSotto } 6183570995aSflorian 619018cebfbSflorian /* Tell children the revised config is now complete. */ 620b2501eadSflorian if (main_sendall(IMSG_RECONF_END, NULL, 0) == -1) 621018cebfbSflorian return (-1); 622018cebfbSflorian 623018cebfbSflorian return (0); 624018cebfbSflorian } 625018cebfbSflorian 626018cebfbSflorian int 627b2501eadSflorian main_sendall(enum imsg_type type, void *buf, uint16_t len) 628018cebfbSflorian { 629018cebfbSflorian if (imsg_compose_event(iev_frontend, type, 0, 0, -1, buf, len) == -1) 630018cebfbSflorian return (-1); 631018cebfbSflorian if (imsg_compose_event(iev_resolver, type, 0, 0, -1, buf, len) == -1) 632018cebfbSflorian return (-1); 633018cebfbSflorian return (0); 634018cebfbSflorian } 635018cebfbSflorian 636018cebfbSflorian void 637bb81f7e1Sflorian merge_config(struct uw_conf *conf, struct uw_conf *xconf) 638018cebfbSflorian { 639bb81f7e1Sflorian struct uw_forwarder *uw_forwarder; 640dd16127bSotto struct force_tree_entry *n, *nxt; 641018cebfbSflorian 642018cebfbSflorian /* Remove & discard existing forwarders. */ 6437d055805Sflorian while ((uw_forwarder = TAILQ_FIRST(&conf->uw_forwarder_list)) != 644bb81f7e1Sflorian NULL) { 6457d055805Sflorian TAILQ_REMOVE(&conf->uw_forwarder_list, uw_forwarder, entry); 646bb81f7e1Sflorian free(uw_forwarder); 647018cebfbSflorian } 6487d055805Sflorian while ((uw_forwarder = TAILQ_FIRST(&conf->uw_dot_forwarder_list)) != 649bb81f7e1Sflorian NULL) { 6507d055805Sflorian TAILQ_REMOVE(&conf->uw_dot_forwarder_list, uw_forwarder, entry); 651bb81f7e1Sflorian free(uw_forwarder); 6523570995aSflorian } 653018cebfbSflorian 654dd16127bSotto /* Remove & discard existing force tree. */ 655dd16127bSotto for (n = RB_MIN(force_tree, &conf->force); n != NULL; n = nxt) { 656dd16127bSotto nxt = RB_NEXT(force_tree, &conf->force, n); 657dd16127bSotto RB_REMOVE(force_tree, &conf->force, n); 658dd16127bSotto free(n); 659dd16127bSotto } 660dd16127bSotto 661fd873f7fSflorian memcpy(&conf->res_pref, &xconf->res_pref, 662fd873f7fSflorian sizeof(conf->res_pref)); 663018cebfbSflorian 6642d988276Sflorian free(conf->blocklist_file); 6652d988276Sflorian conf->blocklist_file = xconf->blocklist_file; 666ac71ec8eSflorian conf->blocklist_log = xconf->blocklist_log; 6672d988276Sflorian 668018cebfbSflorian /* Add new forwarders. */ 6692feeeacaSflorian TAILQ_CONCAT(&conf->uw_forwarder_list, &xconf->uw_forwarder_list, 6707d055805Sflorian entry); 6712feeeacaSflorian TAILQ_CONCAT(&conf->uw_dot_forwarder_list, 6722feeeacaSflorian &xconf->uw_dot_forwarder_list, entry); 673018cebfbSflorian 674dd16127bSotto for (n = RB_MIN(force_tree, &xconf->force); n != NULL; n = nxt) { 675dd16127bSotto nxt = RB_NEXT(force_tree, &xconf->force, n); 676dd16127bSotto RB_REMOVE(force_tree, &xconf->force, n); 677dd16127bSotto RB_INSERT(force_tree, &conf->force, n); 678dd16127bSotto } 679dd16127bSotto 680018cebfbSflorian free(xconf); 681018cebfbSflorian } 682018cebfbSflorian 683bb81f7e1Sflorian struct uw_conf * 684018cebfbSflorian config_new_empty(void) 685018cebfbSflorian { 686fd873f7fSflorian static enum uw_resolver_type default_res_pref[] = { 687fd873f7fSflorian UW_RES_DOT, 68815fe126bSflorian UW_RES_ODOT_FORWARDER, 689fd873f7fSflorian UW_RES_FORWARDER, 690fd873f7fSflorian UW_RES_RECURSOR, 69115fe126bSflorian UW_RES_ODOT_DHCP, 692530f5ecfSflorian UW_RES_DHCP, 693530f5ecfSflorian UW_RES_ASR}; 694bb81f7e1Sflorian struct uw_conf *xconf; 695018cebfbSflorian 696018cebfbSflorian xconf = calloc(1, sizeof(*xconf)); 697018cebfbSflorian if (xconf == NULL) 698018cebfbSflorian fatal(NULL); 699018cebfbSflorian 700d032132bSflorian memcpy(&xconf->res_pref.types, &default_res_pref, 701fd873f7fSflorian sizeof(default_res_pref)); 702d032132bSflorian xconf->res_pref.len = nitems(default_res_pref); 703fd873f7fSflorian 7047d055805Sflorian TAILQ_INIT(&xconf->uw_forwarder_list); 7057d055805Sflorian TAILQ_INIT(&xconf->uw_dot_forwarder_list); 706018cebfbSflorian 707dd16127bSotto RB_INIT(&xconf->force); 708dd16127bSotto 709018cebfbSflorian return (xconf); 710018cebfbSflorian } 711018cebfbSflorian 712018cebfbSflorian void 713bb81f7e1Sflorian config_clear(struct uw_conf *conf) 714018cebfbSflorian { 715bb81f7e1Sflorian struct uw_conf *xconf; 716018cebfbSflorian 717018cebfbSflorian /* Merge current config with an empty config. */ 718018cebfbSflorian xconf = config_new_empty(); 719018cebfbSflorian merge_config(conf, xconf); 720018cebfbSflorian 721018cebfbSflorian free(conf); 722018cebfbSflorian } 723018cebfbSflorian 724018cebfbSflorian void 725d265a5d3Sflorian open_ports(void) 726d265a5d3Sflorian { 727d265a5d3Sflorian struct addrinfo hints, *res0; 728d265a5d3Sflorian int udp4sock = -1, udp6sock = -1, error; 729*15c8ad53Sjca int opt = 1; 730d265a5d3Sflorian 731d265a5d3Sflorian memset(&hints, 0, sizeof(hints)); 732d265a5d3Sflorian hints.ai_family = AF_INET; 733d265a5d3Sflorian hints.ai_socktype = SOCK_DGRAM; 734cc4fd5c4Stedu hints.ai_flags = AI_NUMERICHOST | AI_PASSIVE; 735d265a5d3Sflorian 736d265a5d3Sflorian error = getaddrinfo("127.0.0.1", "domain", &hints, &res0); 737d265a5d3Sflorian if (!error && res0) { 738d265a5d3Sflorian if ((udp4sock = socket(res0->ai_family, res0->ai_socktype, 739d265a5d3Sflorian res0->ai_protocol)) != -1) { 740*15c8ad53Sjca if (setsockopt(udp4sock, SOL_SOCKET, SO_REUSEADDR, 741*15c8ad53Sjca &opt, sizeof(opt)) == -1) 742*15c8ad53Sjca log_warn("setting SO_REUSEADDR on socket"); 743d265a5d3Sflorian if (bind(udp4sock, res0->ai_addr, res0->ai_addrlen) 744d265a5d3Sflorian == -1) { 745d265a5d3Sflorian close(udp4sock); 746d265a5d3Sflorian udp4sock = -1; 747d265a5d3Sflorian } 748d265a5d3Sflorian } 749d265a5d3Sflorian } 750296cf316Sflorian if (res0) 751d265a5d3Sflorian freeaddrinfo(res0); 752d265a5d3Sflorian 753d265a5d3Sflorian hints.ai_family = AF_INET6; 754d265a5d3Sflorian error = getaddrinfo("::1", "domain", &hints, &res0); 755d265a5d3Sflorian if (!error && res0) { 756d265a5d3Sflorian if ((udp6sock = socket(res0->ai_family, res0->ai_socktype, 757d265a5d3Sflorian res0->ai_protocol)) != -1) { 758*15c8ad53Sjca if (setsockopt(udp6sock, SOL_SOCKET, SO_REUSEADDR, 759*15c8ad53Sjca &opt, sizeof(opt)) == -1) 760*15c8ad53Sjca log_warn("setting SO_REUSEADDR on socket"); 761d265a5d3Sflorian if (bind(udp6sock, res0->ai_addr, res0->ai_addrlen) 762d265a5d3Sflorian == -1) { 763d265a5d3Sflorian close(udp6sock); 764d265a5d3Sflorian udp6sock = -1; 765d265a5d3Sflorian } 766d265a5d3Sflorian } 767d265a5d3Sflorian } 768296cf316Sflorian if (res0) 769d265a5d3Sflorian freeaddrinfo(res0); 770d265a5d3Sflorian 771d265a5d3Sflorian if (udp4sock == -1 && udp6sock == -1) 772d265a5d3Sflorian fatal("could not bind to 127.0.0.1 or ::1 on port 53"); 773d265a5d3Sflorian 774b04dd19dSflorian if (udp4sock != -1) 775d265a5d3Sflorian main_imsg_compose_frontend_fd(IMSG_UDP4SOCK, 0, udp4sock); 776b04dd19dSflorian if (udp6sock != -1) 777d265a5d3Sflorian main_imsg_compose_frontend_fd(IMSG_UDP6SOCK, 0, udp6sock); 778d265a5d3Sflorian } 7792f29e846Sflorian 7802f29e846Sflorian void 78128ba4729Sflorian solicit_dns_proposals(void) 78228ba4729Sflorian { 78328ba4729Sflorian struct rt_msghdr rtm; 78428ba4729Sflorian struct iovec iov[1]; 78528ba4729Sflorian int iovcnt = 0; 78628ba4729Sflorian 78728ba4729Sflorian memset(&rtm, 0, sizeof(rtm)); 78828ba4729Sflorian 78928ba4729Sflorian rtm.rtm_version = RTM_VERSION; 79028ba4729Sflorian rtm.rtm_type = RTM_PROPOSAL; 79128ba4729Sflorian rtm.rtm_msglen = sizeof(rtm); 79228ba4729Sflorian rtm.rtm_tableid = 0; 79328ba4729Sflorian rtm.rtm_index = 0; 79428ba4729Sflorian rtm.rtm_seq = arc4random(); 79528ba4729Sflorian rtm.rtm_priority = RTP_PROPOSAL_SOLICIT; 79628ba4729Sflorian 79728ba4729Sflorian iov[iovcnt].iov_base = &rtm; 79828ba4729Sflorian iov[iovcnt++].iov_len = sizeof(rtm); 79928ba4729Sflorian 80028ba4729Sflorian if (writev(routesock, iov, iovcnt) == -1) 80128ba4729Sflorian log_warn("failed to send solicitation"); 80228ba4729Sflorian } 80328ba4729Sflorian 80428ba4729Sflorian void 8052d988276Sflorian send_blocklist_fd(void) 8062d988276Sflorian { 8072d988276Sflorian int bl_fd; 8082d988276Sflorian 8092d988276Sflorian if ((bl_fd = open(main_conf->blocklist_file, O_RDONLY)) != -1) 8102d988276Sflorian main_imsg_compose_frontend_fd(IMSG_BLFD, 0, bl_fd); 8112d988276Sflorian else 8122d988276Sflorian log_warn("%s", main_conf->blocklist_file); 8132d988276Sflorian } 814679647feSflorian 815679647feSflorian void 816679647feSflorian imsg_receive_config(struct imsg *imsg, struct uw_conf **xconf) 817679647feSflorian { 818679647feSflorian struct uw_conf *nconf; 819679647feSflorian struct uw_forwarder *uw_forwarder; 820dd16127bSotto struct force_tree_entry *force_entry; 821679647feSflorian 822679647feSflorian nconf = *xconf; 823679647feSflorian 824679647feSflorian switch (imsg->hdr.type) { 825679647feSflorian case IMSG_RECONF_CONF: 826679647feSflorian if (nconf != NULL) 827679647feSflorian fatalx("%s: IMSG_RECONF_CONF already in " 828679647feSflorian "progress", __func__); 829679647feSflorian if (IMSG_DATA_SIZE(*imsg) != sizeof(struct uw_conf)) 830679647feSflorian fatalx("%s: IMSG_RECONF_CONF wrong length: %lu", 831679647feSflorian __func__, IMSG_DATA_SIZE(*imsg)); 832679647feSflorian if ((*xconf = malloc(sizeof(struct uw_conf))) == NULL) 833679647feSflorian fatal(NULL); 834679647feSflorian nconf = *xconf; 835679647feSflorian memcpy(nconf, imsg->data, sizeof(struct uw_conf)); 8367d055805Sflorian TAILQ_INIT(&nconf->uw_forwarder_list); 8377d055805Sflorian TAILQ_INIT(&nconf->uw_dot_forwarder_list); 838dd16127bSotto RB_INIT(&nconf->force); 839679647feSflorian break; 840679647feSflorian case IMSG_RECONF_BLOCKLIST_FILE: 841679647feSflorian /* make sure this is a string */ 842679647feSflorian ((char *)imsg->data)[IMSG_DATA_SIZE(*imsg) - 1] = '\0'; 843679647feSflorian if ((nconf->blocklist_file = strdup(imsg->data)) == 844679647feSflorian NULL) 845679647feSflorian fatal("%s: strdup", __func__); 846679647feSflorian break; 847679647feSflorian case IMSG_RECONF_FORWARDER: 848679647feSflorian if (IMSG_DATA_SIZE(*imsg) != sizeof(struct uw_forwarder)) 849679647feSflorian fatalx("%s: IMSG_RECONF_FORWARDER wrong length:" 850679647feSflorian " %lu", __func__, IMSG_DATA_SIZE(*imsg)); 851679647feSflorian if ((uw_forwarder = malloc(sizeof(struct 852679647feSflorian uw_forwarder))) == NULL) 853679647feSflorian fatal(NULL); 854679647feSflorian memcpy(uw_forwarder, imsg->data, sizeof(struct 855679647feSflorian uw_forwarder)); 8567d055805Sflorian TAILQ_INSERT_TAIL(&nconf->uw_forwarder_list, 857679647feSflorian uw_forwarder, entry); 858679647feSflorian break; 859679647feSflorian case IMSG_RECONF_DOT_FORWARDER: 860679647feSflorian if (IMSG_DATA_SIZE(*imsg) != sizeof(struct uw_forwarder)) 861679647feSflorian fatalx("%s: IMSG_RECONF_DOT_FORWARDER wrong " 862679647feSflorian "length: %lu", __func__, 863679647feSflorian IMSG_DATA_SIZE(*imsg)); 864679647feSflorian if ((uw_forwarder = malloc(sizeof(struct 865679647feSflorian uw_forwarder))) == NULL) 866679647feSflorian fatal(NULL); 867679647feSflorian memcpy(uw_forwarder, imsg->data, sizeof(struct 868679647feSflorian uw_forwarder)); 8697d055805Sflorian TAILQ_INSERT_TAIL(&nconf->uw_dot_forwarder_list, 870679647feSflorian uw_forwarder, entry); 871679647feSflorian break; 872dd16127bSotto case IMSG_RECONF_FORCE: 873dd16127bSotto if (IMSG_DATA_SIZE(*imsg) != sizeof(struct force_tree_entry)) 874dd16127bSotto fatalx("%s: IMSG_RECONF_FORCE wrong " 875dd16127bSotto "length: %lu", __func__, 876dd16127bSotto IMSG_DATA_SIZE(*imsg)); 877dd16127bSotto if ((force_entry = malloc(sizeof(struct 878dd16127bSotto force_tree_entry))) == NULL) 879dd16127bSotto fatal(NULL); 880dd16127bSotto memcpy(force_entry, imsg->data, sizeof(struct 881dd16127bSotto force_tree_entry)); 882dd16127bSotto RB_INSERT(force_tree, &nconf->force, force_entry); 883dd16127bSotto break; 884679647feSflorian default: 885679647feSflorian log_debug("%s: error handling imsg %d", __func__, 886679647feSflorian imsg->hdr.type); 887679647feSflorian break; 888679647feSflorian } 889679647feSflorian } 890