1*85384332Sflorian /* $OpenBSD: unwind.c,v 1.49 2020/09/12 17:01:03 florian 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 269*85384332Sflorian rtfilter = ROUTE_FILTER(RTM_IFINFO) | ROUTE_FILTER(RTM_PROPOSAL) 270*85384332Sflorian | ROUTE_FILTER(RTM_IFANNOUNCE); 2719e627e00Sflorian if (setsockopt(frontend_routesock, AF_ROUTE, ROUTE_MSGFILTER, 272df69c215Sderaadt &rtfilter, sizeof(rtfilter)) == -1) 273018cebfbSflorian fatal("setsockopt(ROUTE_MSGFILTER)"); 274018cebfbSflorian 27528ba4729Sflorian if ((routesock = socket(AF_ROUTE, SOCK_RAW | SOCK_CLOEXEC | 27628ba4729Sflorian SOCK_NONBLOCK, AF_INET6)) == -1) 27728ba4729Sflorian fatal("route socket"); 27828ba4729Sflorian shutdown(SHUT_RD, routesock); 27928ba4729Sflorian 280d1b04a40Sflorian if ((ta_fd = open(TRUST_ANCHOR_FILE, O_RDWR | O_CREAT, 0644)) == -1) 281d1b04a40Sflorian log_warn("%s", TRUST_ANCHOR_FILE); 282d1b04a40Sflorian 283d1b04a40Sflorian /* receiver handles failed open correctly */ 284d1b04a40Sflorian main_imsg_compose_frontend_fd(IMSG_TAFD, 0, ta_fd); 285d1b04a40Sflorian 286018cebfbSflorian main_imsg_compose_frontend_fd(IMSG_CONTROLFD, 0, control_fd); 287018cebfbSflorian main_imsg_compose_frontend_fd(IMSG_ROUTESOCK, 0, frontend_routesock); 288018cebfbSflorian main_imsg_send_config(main_conf); 289018cebfbSflorian 2902d988276Sflorian if (main_conf->blocklist_file != NULL) 2912d988276Sflorian send_blocklist_fd(); 2922d988276Sflorian 29349a108abSflorian if (pledge("stdio rpath sendfd", NULL) == -1) 294018cebfbSflorian fatal("pledge"); 295018cebfbSflorian 296018cebfbSflorian main_imsg_compose_frontend(IMSG_STARTUP, 0, NULL, 0); 297296cf316Sflorian main_imsg_compose_resolver(IMSG_STARTUP, 0, NULL, 0); 298018cebfbSflorian 299018cebfbSflorian event_dispatch(); 300018cebfbSflorian 301018cebfbSflorian main_shutdown(); 302018cebfbSflorian return (0); 303018cebfbSflorian } 304018cebfbSflorian 305018cebfbSflorian __dead void 306018cebfbSflorian main_shutdown(void) 307018cebfbSflorian { 308018cebfbSflorian pid_t pid; 309018cebfbSflorian int status; 310018cebfbSflorian 311018cebfbSflorian /* Close pipes. */ 312018cebfbSflorian msgbuf_clear(&iev_frontend->ibuf.w); 313018cebfbSflorian close(iev_frontend->ibuf.fd); 314018cebfbSflorian msgbuf_clear(&iev_resolver->ibuf.w); 315018cebfbSflorian close(iev_resolver->ibuf.fd); 316018cebfbSflorian 317018cebfbSflorian config_clear(main_conf); 318018cebfbSflorian 319018cebfbSflorian log_debug("waiting for children to terminate"); 320018cebfbSflorian do { 321018cebfbSflorian pid = wait(&status); 322018cebfbSflorian if (pid == -1) { 323018cebfbSflorian if (errno != EINTR && errno != ECHILD) 324018cebfbSflorian fatal("wait"); 325018cebfbSflorian } else if (WIFSIGNALED(status)) 326018cebfbSflorian log_warnx("%s terminated; signal %d", 327018cebfbSflorian (pid == resolver_pid) ? "resolver" : 328018cebfbSflorian "frontend", WTERMSIG(status)); 329018cebfbSflorian } while (pid != -1 || (pid == -1 && errno == EINTR)); 330018cebfbSflorian 331018cebfbSflorian free(iev_frontend); 332018cebfbSflorian free(iev_resolver); 333018cebfbSflorian 334018cebfbSflorian log_info("terminating"); 335018cebfbSflorian exit(0); 336018cebfbSflorian } 337018cebfbSflorian 338018cebfbSflorian static pid_t 339018cebfbSflorian start_child(int p, char *argv0, int fd, int debug, int verbose) 340018cebfbSflorian { 341018cebfbSflorian char *argv[7]; 342018cebfbSflorian int argc = 0; 343018cebfbSflorian pid_t pid; 344018cebfbSflorian 345018cebfbSflorian switch (pid = fork()) { 346018cebfbSflorian case -1: 347018cebfbSflorian fatal("cannot fork"); 348018cebfbSflorian case 0: 349018cebfbSflorian break; 350018cebfbSflorian default: 351018cebfbSflorian close(fd); 352018cebfbSflorian return (pid); 353018cebfbSflorian } 354018cebfbSflorian 355ef4f5895Syasuoka if (fd != 3) { 356018cebfbSflorian if (dup2(fd, 3) == -1) 357018cebfbSflorian fatal("cannot setup imsg fd"); 358ef4f5895Syasuoka } else if (fcntl(fd, F_SETFD, 0) == -1) 359ef4f5895Syasuoka fatal("cannot setup imsg fd"); 360018cebfbSflorian 361018cebfbSflorian argv[argc++] = argv0; 362018cebfbSflorian switch (p) { 363018cebfbSflorian case PROC_MAIN: 364018cebfbSflorian fatalx("Can not start main process"); 365018cebfbSflorian case PROC_RESOLVER: 366018cebfbSflorian argv[argc++] = "-E"; 367018cebfbSflorian break; 368018cebfbSflorian case PROC_FRONTEND: 369018cebfbSflorian argv[argc++] = "-F"; 370018cebfbSflorian break; 371018cebfbSflorian } 372018cebfbSflorian if (debug) 373018cebfbSflorian argv[argc++] = "-d"; 374018cebfbSflorian if (verbose & OPT_VERBOSE) 375018cebfbSflorian argv[argc++] = "-v"; 376018cebfbSflorian if (verbose & OPT_VERBOSE2) 377018cebfbSflorian argv[argc++] = "-v"; 378e5d1a61aSflorian if (verbose & OPT_VERBOSE3) 379e5d1a61aSflorian argv[argc++] = "-v"; 380018cebfbSflorian argv[argc++] = NULL; 381018cebfbSflorian 382018cebfbSflorian execvp(argv0, argv); 383018cebfbSflorian fatal("execvp"); 384018cebfbSflorian } 385018cebfbSflorian 386018cebfbSflorian void 387018cebfbSflorian main_dispatch_frontend(int fd, short event, void *bula) 388018cebfbSflorian { 389018cebfbSflorian struct imsgev *iev = bula; 390018cebfbSflorian struct imsgbuf *ibuf; 391018cebfbSflorian struct imsg imsg; 392018cebfbSflorian ssize_t n; 393018cebfbSflorian int shut = 0, verbose; 394018cebfbSflorian 395018cebfbSflorian ibuf = &iev->ibuf; 396018cebfbSflorian 397018cebfbSflorian if (event & EV_READ) { 398018cebfbSflorian if ((n = imsg_read(ibuf)) == -1 && errno != EAGAIN) 399018cebfbSflorian fatal("imsg_read error"); 400018cebfbSflorian if (n == 0) /* Connection closed. */ 401018cebfbSflorian shut = 1; 402018cebfbSflorian } 403018cebfbSflorian if (event & EV_WRITE) { 404018cebfbSflorian if ((n = msgbuf_write(&ibuf->w)) == -1 && errno != EAGAIN) 405018cebfbSflorian fatal("msgbuf_write"); 406018cebfbSflorian if (n == 0) /* Connection closed. */ 407018cebfbSflorian shut = 1; 408018cebfbSflorian } 409018cebfbSflorian 410018cebfbSflorian for (;;) { 411018cebfbSflorian if ((n = imsg_get(ibuf, &imsg)) == -1) 412018cebfbSflorian fatal("imsg_get"); 413018cebfbSflorian if (n == 0) /* No more messages. */ 414018cebfbSflorian break; 415018cebfbSflorian 416018cebfbSflorian switch (imsg.hdr.type) { 417018cebfbSflorian case IMSG_STARTUP_DONE: 41828ba4729Sflorian solicit_dns_proposals(); 419018cebfbSflorian break; 420018cebfbSflorian case IMSG_CTL_RELOAD: 421018cebfbSflorian if (main_reload() == -1) 422018cebfbSflorian log_warnx("configuration reload failed"); 423018cebfbSflorian else 424018cebfbSflorian log_warnx("configuration reloaded"); 425018cebfbSflorian break; 426018cebfbSflorian case IMSG_CTL_LOG_VERBOSE: 427a9155f32Sflorian if (IMSG_DATA_SIZE(imsg) != sizeof(verbose)) 4282b821978Sflorian fatalx("%s: IMSG_CTL_LOG_VERBOSE wrong length: " 429a9155f32Sflorian "%lu", __func__, IMSG_DATA_SIZE(imsg)); 430018cebfbSflorian memcpy(&verbose, imsg.data, sizeof(verbose)); 431018cebfbSflorian log_setverbose(verbose); 432018cebfbSflorian break; 433018cebfbSflorian default: 434018cebfbSflorian log_debug("%s: error handling imsg %d", __func__, 435018cebfbSflorian imsg.hdr.type); 436018cebfbSflorian break; 437018cebfbSflorian } 438018cebfbSflorian imsg_free(&imsg); 439018cebfbSflorian } 440018cebfbSflorian if (!shut) 441018cebfbSflorian imsg_event_add(iev); 442018cebfbSflorian else { 443018cebfbSflorian /* This pipe is dead. Remove its event handler */ 444018cebfbSflorian event_del(&iev->ev); 445018cebfbSflorian event_loopexit(NULL); 446018cebfbSflorian } 447018cebfbSflorian } 448018cebfbSflorian 449018cebfbSflorian void 450018cebfbSflorian main_dispatch_resolver(int fd, short event, void *bula) 451018cebfbSflorian { 452018cebfbSflorian struct imsgev *iev = bula; 453018cebfbSflorian struct imsgbuf *ibuf; 454018cebfbSflorian struct imsg imsg; 455018cebfbSflorian ssize_t n; 456018cebfbSflorian int shut = 0; 457018cebfbSflorian 458018cebfbSflorian ibuf = &iev->ibuf; 459018cebfbSflorian 460018cebfbSflorian if (event & EV_READ) { 461018cebfbSflorian if ((n = imsg_read(ibuf)) == -1 && errno != EAGAIN) 462018cebfbSflorian fatal("imsg_read error"); 463018cebfbSflorian if (n == 0) /* Connection closed. */ 464018cebfbSflorian shut = 1; 465018cebfbSflorian } 466018cebfbSflorian if (event & EV_WRITE) { 467018cebfbSflorian if ((n = msgbuf_write(&ibuf->w)) == -1 && errno != EAGAIN) 468018cebfbSflorian fatal("msgbuf_write"); 469018cebfbSflorian if (n == 0) /* Connection closed. */ 470018cebfbSflorian shut = 1; 471018cebfbSflorian } 472018cebfbSflorian 473018cebfbSflorian for (;;) { 474018cebfbSflorian if ((n = imsg_get(ibuf, &imsg)) == -1) 475018cebfbSflorian fatal("imsg_get"); 476018cebfbSflorian if (n == 0) /* No more messages. */ 477018cebfbSflorian break; 478018cebfbSflorian 479018cebfbSflorian switch (imsg.hdr.type) { 480018cebfbSflorian default: 481018cebfbSflorian log_debug("%s: error handling imsg %d", __func__, 482018cebfbSflorian imsg.hdr.type); 483018cebfbSflorian break; 484018cebfbSflorian } 485018cebfbSflorian imsg_free(&imsg); 486018cebfbSflorian } 487018cebfbSflorian if (!shut) 488018cebfbSflorian imsg_event_add(iev); 489018cebfbSflorian else { 490018cebfbSflorian /* This pipe is dead. Remove its event handler. */ 491018cebfbSflorian event_del(&iev->ev); 492018cebfbSflorian event_loopexit(NULL); 493018cebfbSflorian } 494018cebfbSflorian } 495018cebfbSflorian 496018cebfbSflorian void 497018cebfbSflorian main_imsg_compose_frontend(int type, pid_t pid, void *data, uint16_t datalen) 498018cebfbSflorian { 499018cebfbSflorian if (iev_frontend) 500018cebfbSflorian imsg_compose_event(iev_frontend, type, 0, pid, -1, data, 501018cebfbSflorian datalen); 502018cebfbSflorian } 503018cebfbSflorian 504018cebfbSflorian void 505018cebfbSflorian main_imsg_compose_frontend_fd(int type, pid_t pid, int fd) 506018cebfbSflorian { 507018cebfbSflorian if (iev_frontend) 508018cebfbSflorian imsg_compose_event(iev_frontend, type, 0, pid, fd, NULL, 0); 509018cebfbSflorian } 510018cebfbSflorian 511018cebfbSflorian void 512018cebfbSflorian main_imsg_compose_resolver(int type, pid_t pid, void *data, uint16_t datalen) 513018cebfbSflorian { 514018cebfbSflorian if (iev_resolver) 515018cebfbSflorian imsg_compose_event(iev_resolver, type, 0, pid, -1, data, 516018cebfbSflorian datalen); 517018cebfbSflorian } 518018cebfbSflorian 519018cebfbSflorian void 520018cebfbSflorian imsg_event_add(struct imsgev *iev) 521018cebfbSflorian { 522018cebfbSflorian iev->events = EV_READ; 523018cebfbSflorian if (iev->ibuf.w.queued) 524018cebfbSflorian iev->events |= EV_WRITE; 525018cebfbSflorian 526018cebfbSflorian event_del(&iev->ev); 527018cebfbSflorian event_set(&iev->ev, iev->ibuf.fd, iev->events, iev->handler, iev); 528018cebfbSflorian event_add(&iev->ev, NULL); 529018cebfbSflorian } 530018cebfbSflorian 531018cebfbSflorian int 532018cebfbSflorian imsg_compose_event(struct imsgev *iev, uint16_t type, uint32_t peerid, 533018cebfbSflorian pid_t pid, int fd, void *data, uint16_t datalen) 534018cebfbSflorian { 535018cebfbSflorian int ret; 536018cebfbSflorian 537018cebfbSflorian if ((ret = imsg_compose(&iev->ibuf, type, peerid, pid, fd, data, 538018cebfbSflorian datalen)) != -1) 539018cebfbSflorian imsg_event_add(iev); 540018cebfbSflorian 541018cebfbSflorian return (ret); 542018cebfbSflorian } 543018cebfbSflorian 544018cebfbSflorian static int 545018cebfbSflorian main_imsg_send_ipc_sockets(struct imsgbuf *frontend_buf, 546f3ea9bf1Sflorian struct imsgbuf *resolver_buf) 547018cebfbSflorian { 548018cebfbSflorian int pipe_frontend2resolver[2]; 549018cebfbSflorian 550018cebfbSflorian if (socketpair(AF_UNIX, SOCK_STREAM | SOCK_CLOEXEC | SOCK_NONBLOCK, 551018cebfbSflorian PF_UNSPEC, pipe_frontend2resolver) == -1) 552018cebfbSflorian return (-1); 553018cebfbSflorian 554b2501eadSflorian if (imsg_compose(frontend_buf, IMSG_SOCKET_IPC_RESOLVER, 0, 0, 555018cebfbSflorian pipe_frontend2resolver[0], NULL, 0) == -1) 556018cebfbSflorian return (-1); 557b2501eadSflorian if (imsg_compose(resolver_buf, IMSG_SOCKET_IPC_FRONTEND, 0, 0, 558018cebfbSflorian pipe_frontend2resolver[1], NULL, 0) == -1) 559018cebfbSflorian return (-1); 560018cebfbSflorian 561018cebfbSflorian return (0); 562018cebfbSflorian } 563018cebfbSflorian 564018cebfbSflorian int 565018cebfbSflorian main_reload(void) 566018cebfbSflorian { 567bb81f7e1Sflorian struct uw_conf *xconf; 568018cebfbSflorian 569572e5ac0Skn if ((xconf = parse_config(conffile)) == NULL) 570018cebfbSflorian return (-1); 571018cebfbSflorian 572018cebfbSflorian if (main_imsg_send_config(xconf) == -1) 573018cebfbSflorian return (-1); 574018cebfbSflorian 575018cebfbSflorian merge_config(main_conf, xconf); 576018cebfbSflorian 5772d988276Sflorian if (main_conf->blocklist_file != NULL) 5782d988276Sflorian send_blocklist_fd(); 5792d988276Sflorian 580018cebfbSflorian return (0); 581018cebfbSflorian } 582018cebfbSflorian 583018cebfbSflorian int 584bb81f7e1Sflorian main_imsg_send_config(struct uw_conf *xconf) 585018cebfbSflorian { 586bb81f7e1Sflorian struct uw_forwarder *uw_forwarder; 587dd16127bSotto struct force_tree_entry *force_entry; 588018cebfbSflorian 589018cebfbSflorian /* Send fixed part of config to children. */ 590b2501eadSflorian if (main_sendall(IMSG_RECONF_CONF, xconf, sizeof(*xconf)) == -1) 591018cebfbSflorian return (-1); 592018cebfbSflorian 5932d988276Sflorian if (xconf->blocklist_file != NULL) { 5942d988276Sflorian if (main_sendall(IMSG_RECONF_BLOCKLIST_FILE, 5952d988276Sflorian xconf->blocklist_file, strlen(xconf->blocklist_file) + 1) 5962d988276Sflorian == -1) 5972d988276Sflorian return (-1); 5982d988276Sflorian } 5992d988276Sflorian 6003570995aSflorian /* send static forwarders to children */ 6017d055805Sflorian TAILQ_FOREACH(uw_forwarder, &xconf->uw_forwarder_list, entry) { 602bb81f7e1Sflorian if (main_sendall(IMSG_RECONF_FORWARDER, uw_forwarder, 603bb81f7e1Sflorian sizeof(*uw_forwarder)) == -1) 604018cebfbSflorian return (-1); 605018cebfbSflorian } 606018cebfbSflorian 6073570995aSflorian /* send static DoT forwarders to children */ 6087d055805Sflorian TAILQ_FOREACH(uw_forwarder, &xconf->uw_dot_forwarder_list, 6093570995aSflorian entry) { 610bb81f7e1Sflorian if (main_sendall(IMSG_RECONF_DOT_FORWARDER, uw_forwarder, 611bb81f7e1Sflorian sizeof(*uw_forwarder)) == -1) 6123570995aSflorian return (-1); 6133570995aSflorian } 614dd16127bSotto RB_FOREACH(force_entry, force_tree, &xconf->force) { 615dd16127bSotto if (main_sendall(IMSG_RECONF_FORCE, force_entry, 616dd16127bSotto sizeof(*force_entry)) == -1) 617dd16127bSotto return (-1); 618dd16127bSotto } 6193570995aSflorian 620018cebfbSflorian /* Tell children the revised config is now complete. */ 621b2501eadSflorian if (main_sendall(IMSG_RECONF_END, NULL, 0) == -1) 622018cebfbSflorian return (-1); 623018cebfbSflorian 624018cebfbSflorian return (0); 625018cebfbSflorian } 626018cebfbSflorian 627018cebfbSflorian int 628b2501eadSflorian main_sendall(enum imsg_type type, void *buf, uint16_t len) 629018cebfbSflorian { 630018cebfbSflorian if (imsg_compose_event(iev_frontend, type, 0, 0, -1, buf, len) == -1) 631018cebfbSflorian return (-1); 632018cebfbSflorian if (imsg_compose_event(iev_resolver, type, 0, 0, -1, buf, len) == -1) 633018cebfbSflorian return (-1); 634018cebfbSflorian return (0); 635018cebfbSflorian } 636018cebfbSflorian 637018cebfbSflorian void 638bb81f7e1Sflorian merge_config(struct uw_conf *conf, struct uw_conf *xconf) 639018cebfbSflorian { 640bb81f7e1Sflorian struct uw_forwarder *uw_forwarder; 641dd16127bSotto struct force_tree_entry *n, *nxt; 642018cebfbSflorian 643018cebfbSflorian /* Remove & discard existing forwarders. */ 6447d055805Sflorian while ((uw_forwarder = TAILQ_FIRST(&conf->uw_forwarder_list)) != 645bb81f7e1Sflorian NULL) { 6467d055805Sflorian TAILQ_REMOVE(&conf->uw_forwarder_list, uw_forwarder, entry); 647bb81f7e1Sflorian free(uw_forwarder); 648018cebfbSflorian } 6497d055805Sflorian while ((uw_forwarder = TAILQ_FIRST(&conf->uw_dot_forwarder_list)) != 650bb81f7e1Sflorian NULL) { 6517d055805Sflorian TAILQ_REMOVE(&conf->uw_dot_forwarder_list, uw_forwarder, entry); 652bb81f7e1Sflorian free(uw_forwarder); 6533570995aSflorian } 654018cebfbSflorian 655dd16127bSotto /* Remove & discard existing force tree. */ 656dd16127bSotto for (n = RB_MIN(force_tree, &conf->force); n != NULL; n = nxt) { 657dd16127bSotto nxt = RB_NEXT(force_tree, &conf->force, n); 658dd16127bSotto RB_REMOVE(force_tree, &conf->force, n); 659dd16127bSotto free(n); 660dd16127bSotto } 661dd16127bSotto 662fd873f7fSflorian memcpy(&conf->res_pref, &xconf->res_pref, 663fd873f7fSflorian sizeof(conf->res_pref)); 664018cebfbSflorian 6652d988276Sflorian free(conf->blocklist_file); 6662d988276Sflorian conf->blocklist_file = xconf->blocklist_file; 667ac71ec8eSflorian conf->blocklist_log = xconf->blocklist_log; 6682d988276Sflorian 669018cebfbSflorian /* Add new forwarders. */ 6702feeeacaSflorian TAILQ_CONCAT(&conf->uw_forwarder_list, &xconf->uw_forwarder_list, 6717d055805Sflorian entry); 6722feeeacaSflorian TAILQ_CONCAT(&conf->uw_dot_forwarder_list, 6732feeeacaSflorian &xconf->uw_dot_forwarder_list, entry); 674018cebfbSflorian 675dd16127bSotto for (n = RB_MIN(force_tree, &xconf->force); n != NULL; n = nxt) { 676dd16127bSotto nxt = RB_NEXT(force_tree, &xconf->force, n); 677dd16127bSotto RB_REMOVE(force_tree, &xconf->force, n); 678dd16127bSotto RB_INSERT(force_tree, &conf->force, n); 679dd16127bSotto } 680dd16127bSotto 681018cebfbSflorian free(xconf); 682018cebfbSflorian } 683018cebfbSflorian 684bb81f7e1Sflorian struct uw_conf * 685018cebfbSflorian config_new_empty(void) 686018cebfbSflorian { 687fd873f7fSflorian static enum uw_resolver_type default_res_pref[] = { 688fd873f7fSflorian UW_RES_DOT, 68915fe126bSflorian UW_RES_ODOT_FORWARDER, 690fd873f7fSflorian UW_RES_FORWARDER, 691fd873f7fSflorian UW_RES_RECURSOR, 69215fe126bSflorian UW_RES_ODOT_DHCP, 693530f5ecfSflorian UW_RES_DHCP, 694530f5ecfSflorian UW_RES_ASR}; 695bb81f7e1Sflorian struct uw_conf *xconf; 696018cebfbSflorian 697018cebfbSflorian xconf = calloc(1, sizeof(*xconf)); 698018cebfbSflorian if (xconf == NULL) 699018cebfbSflorian fatal(NULL); 700018cebfbSflorian 701d032132bSflorian memcpy(&xconf->res_pref.types, &default_res_pref, 702fd873f7fSflorian sizeof(default_res_pref)); 703d032132bSflorian xconf->res_pref.len = nitems(default_res_pref); 704fd873f7fSflorian 7057d055805Sflorian TAILQ_INIT(&xconf->uw_forwarder_list); 7067d055805Sflorian TAILQ_INIT(&xconf->uw_dot_forwarder_list); 707018cebfbSflorian 708dd16127bSotto RB_INIT(&xconf->force); 709dd16127bSotto 710018cebfbSflorian return (xconf); 711018cebfbSflorian } 712018cebfbSflorian 713018cebfbSflorian void 714bb81f7e1Sflorian config_clear(struct uw_conf *conf) 715018cebfbSflorian { 716bb81f7e1Sflorian struct uw_conf *xconf; 717018cebfbSflorian 718018cebfbSflorian /* Merge current config with an empty config. */ 719018cebfbSflorian xconf = config_new_empty(); 720018cebfbSflorian merge_config(conf, xconf); 721018cebfbSflorian 722018cebfbSflorian free(conf); 723018cebfbSflorian } 724018cebfbSflorian 725018cebfbSflorian void 726d265a5d3Sflorian open_ports(void) 727d265a5d3Sflorian { 728d265a5d3Sflorian struct addrinfo hints, *res0; 729d265a5d3Sflorian int udp4sock = -1, udp6sock = -1, error; 73015c8ad53Sjca int opt = 1; 731d265a5d3Sflorian 732d265a5d3Sflorian memset(&hints, 0, sizeof(hints)); 733d265a5d3Sflorian hints.ai_family = AF_INET; 734d265a5d3Sflorian hints.ai_socktype = SOCK_DGRAM; 735cc4fd5c4Stedu hints.ai_flags = AI_NUMERICHOST | AI_PASSIVE; 736d265a5d3Sflorian 737d265a5d3Sflorian error = getaddrinfo("127.0.0.1", "domain", &hints, &res0); 738d265a5d3Sflorian if (!error && res0) { 739d265a5d3Sflorian if ((udp4sock = socket(res0->ai_family, res0->ai_socktype, 740d265a5d3Sflorian res0->ai_protocol)) != -1) { 74115c8ad53Sjca if (setsockopt(udp4sock, SOL_SOCKET, SO_REUSEADDR, 74215c8ad53Sjca &opt, sizeof(opt)) == -1) 74315c8ad53Sjca log_warn("setting SO_REUSEADDR on socket"); 744d265a5d3Sflorian if (bind(udp4sock, res0->ai_addr, res0->ai_addrlen) 745d265a5d3Sflorian == -1) { 746d265a5d3Sflorian close(udp4sock); 747d265a5d3Sflorian udp4sock = -1; 748d265a5d3Sflorian } 749d265a5d3Sflorian } 750d265a5d3Sflorian } 751296cf316Sflorian if (res0) 752d265a5d3Sflorian freeaddrinfo(res0); 753d265a5d3Sflorian 754d265a5d3Sflorian hints.ai_family = AF_INET6; 755d265a5d3Sflorian error = getaddrinfo("::1", "domain", &hints, &res0); 756d265a5d3Sflorian if (!error && res0) { 757d265a5d3Sflorian if ((udp6sock = socket(res0->ai_family, res0->ai_socktype, 758d265a5d3Sflorian res0->ai_protocol)) != -1) { 75915c8ad53Sjca if (setsockopt(udp6sock, SOL_SOCKET, SO_REUSEADDR, 76015c8ad53Sjca &opt, sizeof(opt)) == -1) 76115c8ad53Sjca log_warn("setting SO_REUSEADDR on socket"); 762d265a5d3Sflorian if (bind(udp6sock, res0->ai_addr, res0->ai_addrlen) 763d265a5d3Sflorian == -1) { 764d265a5d3Sflorian close(udp6sock); 765d265a5d3Sflorian udp6sock = -1; 766d265a5d3Sflorian } 767d265a5d3Sflorian } 768d265a5d3Sflorian } 769296cf316Sflorian if (res0) 770d265a5d3Sflorian freeaddrinfo(res0); 771d265a5d3Sflorian 772d265a5d3Sflorian if (udp4sock == -1 && udp6sock == -1) 773d265a5d3Sflorian fatal("could not bind to 127.0.0.1 or ::1 on port 53"); 774d265a5d3Sflorian 775b04dd19dSflorian if (udp4sock != -1) 776d265a5d3Sflorian main_imsg_compose_frontend_fd(IMSG_UDP4SOCK, 0, udp4sock); 777b04dd19dSflorian if (udp6sock != -1) 778d265a5d3Sflorian main_imsg_compose_frontend_fd(IMSG_UDP6SOCK, 0, udp6sock); 779d265a5d3Sflorian } 7802f29e846Sflorian 7812f29e846Sflorian void 78228ba4729Sflorian solicit_dns_proposals(void) 78328ba4729Sflorian { 78428ba4729Sflorian struct rt_msghdr rtm; 78528ba4729Sflorian struct iovec iov[1]; 78628ba4729Sflorian int iovcnt = 0; 78728ba4729Sflorian 78828ba4729Sflorian memset(&rtm, 0, sizeof(rtm)); 78928ba4729Sflorian 79028ba4729Sflorian rtm.rtm_version = RTM_VERSION; 79128ba4729Sflorian rtm.rtm_type = RTM_PROPOSAL; 79228ba4729Sflorian rtm.rtm_msglen = sizeof(rtm); 79328ba4729Sflorian rtm.rtm_tableid = 0; 79428ba4729Sflorian rtm.rtm_index = 0; 79528ba4729Sflorian rtm.rtm_seq = arc4random(); 79628ba4729Sflorian rtm.rtm_priority = RTP_PROPOSAL_SOLICIT; 79728ba4729Sflorian 79828ba4729Sflorian iov[iovcnt].iov_base = &rtm; 79928ba4729Sflorian iov[iovcnt++].iov_len = sizeof(rtm); 80028ba4729Sflorian 80128ba4729Sflorian if (writev(routesock, iov, iovcnt) == -1) 80228ba4729Sflorian log_warn("failed to send solicitation"); 80328ba4729Sflorian } 80428ba4729Sflorian 80528ba4729Sflorian void 8062d988276Sflorian send_blocklist_fd(void) 8072d988276Sflorian { 8082d988276Sflorian int bl_fd; 8092d988276Sflorian 8102d988276Sflorian if ((bl_fd = open(main_conf->blocklist_file, O_RDONLY)) != -1) 8112d988276Sflorian main_imsg_compose_frontend_fd(IMSG_BLFD, 0, bl_fd); 8122d988276Sflorian else 8132d988276Sflorian log_warn("%s", main_conf->blocklist_file); 8142d988276Sflorian } 815679647feSflorian 816679647feSflorian void 817679647feSflorian imsg_receive_config(struct imsg *imsg, struct uw_conf **xconf) 818679647feSflorian { 819679647feSflorian struct uw_conf *nconf; 820679647feSflorian struct uw_forwarder *uw_forwarder; 821dd16127bSotto struct force_tree_entry *force_entry; 822679647feSflorian 823679647feSflorian nconf = *xconf; 824679647feSflorian 825679647feSflorian switch (imsg->hdr.type) { 826679647feSflorian case IMSG_RECONF_CONF: 827679647feSflorian if (nconf != NULL) 828679647feSflorian fatalx("%s: IMSG_RECONF_CONF already in " 829679647feSflorian "progress", __func__); 830679647feSflorian if (IMSG_DATA_SIZE(*imsg) != sizeof(struct uw_conf)) 831679647feSflorian fatalx("%s: IMSG_RECONF_CONF wrong length: %lu", 832679647feSflorian __func__, IMSG_DATA_SIZE(*imsg)); 833679647feSflorian if ((*xconf = malloc(sizeof(struct uw_conf))) == NULL) 834679647feSflorian fatal(NULL); 835679647feSflorian nconf = *xconf; 836679647feSflorian memcpy(nconf, imsg->data, sizeof(struct uw_conf)); 8377d055805Sflorian TAILQ_INIT(&nconf->uw_forwarder_list); 8387d055805Sflorian TAILQ_INIT(&nconf->uw_dot_forwarder_list); 839dd16127bSotto RB_INIT(&nconf->force); 840679647feSflorian break; 841679647feSflorian case IMSG_RECONF_BLOCKLIST_FILE: 842679647feSflorian /* make sure this is a string */ 843679647feSflorian ((char *)imsg->data)[IMSG_DATA_SIZE(*imsg) - 1] = '\0'; 844679647feSflorian if ((nconf->blocklist_file = strdup(imsg->data)) == 845679647feSflorian NULL) 846679647feSflorian fatal("%s: strdup", __func__); 847679647feSflorian break; 848679647feSflorian case IMSG_RECONF_FORWARDER: 849679647feSflorian if (IMSG_DATA_SIZE(*imsg) != sizeof(struct uw_forwarder)) 850679647feSflorian fatalx("%s: IMSG_RECONF_FORWARDER wrong length:" 851679647feSflorian " %lu", __func__, IMSG_DATA_SIZE(*imsg)); 852679647feSflorian if ((uw_forwarder = malloc(sizeof(struct 853679647feSflorian uw_forwarder))) == NULL) 854679647feSflorian fatal(NULL); 855679647feSflorian memcpy(uw_forwarder, imsg->data, sizeof(struct 856679647feSflorian uw_forwarder)); 8577d055805Sflorian TAILQ_INSERT_TAIL(&nconf->uw_forwarder_list, 858679647feSflorian uw_forwarder, entry); 859679647feSflorian break; 860679647feSflorian case IMSG_RECONF_DOT_FORWARDER: 861679647feSflorian if (IMSG_DATA_SIZE(*imsg) != sizeof(struct uw_forwarder)) 862679647feSflorian fatalx("%s: IMSG_RECONF_DOT_FORWARDER wrong " 863679647feSflorian "length: %lu", __func__, 864679647feSflorian IMSG_DATA_SIZE(*imsg)); 865679647feSflorian if ((uw_forwarder = malloc(sizeof(struct 866679647feSflorian uw_forwarder))) == NULL) 867679647feSflorian fatal(NULL); 868679647feSflorian memcpy(uw_forwarder, imsg->data, sizeof(struct 869679647feSflorian uw_forwarder)); 8707d055805Sflorian TAILQ_INSERT_TAIL(&nconf->uw_dot_forwarder_list, 871679647feSflorian uw_forwarder, entry); 872679647feSflorian break; 873dd16127bSotto case IMSG_RECONF_FORCE: 874dd16127bSotto if (IMSG_DATA_SIZE(*imsg) != sizeof(struct force_tree_entry)) 875dd16127bSotto fatalx("%s: IMSG_RECONF_FORCE wrong " 876dd16127bSotto "length: %lu", __func__, 877dd16127bSotto IMSG_DATA_SIZE(*imsg)); 878dd16127bSotto if ((force_entry = malloc(sizeof(struct 879dd16127bSotto force_tree_entry))) == NULL) 880dd16127bSotto fatal(NULL); 881dd16127bSotto memcpy(force_entry, imsg->data, sizeof(struct 882dd16127bSotto force_tree_entry)); 883dd16127bSotto RB_INSERT(force_tree, &nconf->force, force_entry); 884dd16127bSotto break; 885679647feSflorian default: 886679647feSflorian log_debug("%s: error handling imsg %d", __func__, 887679647feSflorian imsg->hdr.type); 888679647feSflorian break; 889679647feSflorian } 890679647feSflorian } 891