1*49a108abSflorian /* $OpenBSD: unwind.c,v 1.46 2019/12/20 08:30:27 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 log_info("startup"); 207018cebfbSflorian 208018cebfbSflorian if (socketpair(AF_UNIX, SOCK_STREAM | SOCK_CLOEXEC | SOCK_NONBLOCK, 209018cebfbSflorian PF_UNSPEC, pipe_main2frontend) == -1) 210018cebfbSflorian fatal("main2frontend socketpair"); 211018cebfbSflorian if (socketpair(AF_UNIX, SOCK_STREAM | SOCK_CLOEXEC | SOCK_NONBLOCK, 212018cebfbSflorian PF_UNSPEC, pipe_main2resolver) == -1) 213018cebfbSflorian fatal("main2resolver socketpair"); 214018cebfbSflorian 215018cebfbSflorian /* Start children. */ 216018cebfbSflorian resolver_pid = start_child(PROC_RESOLVER, saved_argv0, 217018cebfbSflorian pipe_main2resolver[1], debug, cmd_opts & (OPT_VERBOSE | 218e5d1a61aSflorian OPT_VERBOSE2 | OPT_VERBOSE3)); 219018cebfbSflorian frontend_pid = start_child(PROC_FRONTEND, saved_argv0, 220018cebfbSflorian pipe_main2frontend[1], debug, cmd_opts & (OPT_VERBOSE | 221e5d1a61aSflorian OPT_VERBOSE2 | OPT_VERBOSE3)); 222018cebfbSflorian 223bb81f7e1Sflorian uw_process = PROC_MAIN; 224bb81f7e1Sflorian log_procinit(log_procnames[uw_process]); 225018cebfbSflorian 226018cebfbSflorian event_init(); 227018cebfbSflorian 228018cebfbSflorian /* Setup signal handler. */ 229018cebfbSflorian signal_set(&ev_sigint, SIGINT, main_sig_handler, NULL); 230018cebfbSflorian signal_set(&ev_sigterm, SIGTERM, main_sig_handler, NULL); 231018cebfbSflorian signal_set(&ev_sighup, SIGHUP, main_sig_handler, NULL); 232018cebfbSflorian signal_add(&ev_sigint, NULL); 233018cebfbSflorian signal_add(&ev_sigterm, NULL); 234018cebfbSflorian signal_add(&ev_sighup, NULL); 235018cebfbSflorian signal(SIGPIPE, SIG_IGN); 236018cebfbSflorian 237018cebfbSflorian /* Setup pipes to children. */ 238018cebfbSflorian 239018cebfbSflorian if ((iev_frontend = malloc(sizeof(struct imsgev))) == NULL || 240018cebfbSflorian (iev_resolver = malloc(sizeof(struct imsgev))) == NULL) 241018cebfbSflorian fatal(NULL); 242018cebfbSflorian imsg_init(&iev_frontend->ibuf, pipe_main2frontend[0]); 243018cebfbSflorian iev_frontend->handler = main_dispatch_frontend; 244018cebfbSflorian imsg_init(&iev_resolver->ibuf, pipe_main2resolver[0]); 245018cebfbSflorian iev_resolver->handler = main_dispatch_resolver; 246018cebfbSflorian 247b2501eadSflorian /* Setup event handlers for pipes. */ 248018cebfbSflorian iev_frontend->events = EV_READ; 249018cebfbSflorian event_set(&iev_frontend->ev, iev_frontend->ibuf.fd, 250018cebfbSflorian iev_frontend->events, iev_frontend->handler, iev_frontend); 251018cebfbSflorian event_add(&iev_frontend->ev, NULL); 252018cebfbSflorian 253018cebfbSflorian iev_resolver->events = EV_READ; 254bb81f7e1Sflorian event_set(&iev_resolver->ev, iev_resolver->ibuf.fd, 255bb81f7e1Sflorian iev_resolver->events, iev_resolver->handler, iev_resolver); 256018cebfbSflorian event_add(&iev_resolver->ev, NULL); 257018cebfbSflorian 258b2501eadSflorian if (main_imsg_send_ipc_sockets(&iev_frontend->ibuf, 259f3ea9bf1Sflorian &iev_resolver->ibuf)) 260018cebfbSflorian fatal("could not establish imsg links"); 261018cebfbSflorian 262*49a108abSflorian open_ports(); 263*49a108abSflorian 264018cebfbSflorian if ((control_fd = control_init(csock)) == -1) 265018cebfbSflorian fatalx("control socket setup failed"); 266018cebfbSflorian 2679e627e00Sflorian if ((frontend_routesock = socket(AF_ROUTE, SOCK_RAW | SOCK_CLOEXEC, 268df69c215Sderaadt AF_INET)) == -1) 269018cebfbSflorian fatal("route socket"); 270018cebfbSflorian 2712956dd86Sflorian rtfilter = ROUTE_FILTER(RTM_IFINFO) | ROUTE_FILTER(RTM_PROPOSAL); 2729e627e00Sflorian if (setsockopt(frontend_routesock, AF_ROUTE, ROUTE_MSGFILTER, 273df69c215Sderaadt &rtfilter, sizeof(rtfilter)) == -1) 274018cebfbSflorian fatal("setsockopt(ROUTE_MSGFILTER)"); 275018cebfbSflorian 27628ba4729Sflorian if ((routesock = socket(AF_ROUTE, SOCK_RAW | SOCK_CLOEXEC | 27728ba4729Sflorian SOCK_NONBLOCK, AF_INET6)) == -1) 27828ba4729Sflorian fatal("route socket"); 27928ba4729Sflorian shutdown(SHUT_RD, routesock); 28028ba4729Sflorian 281d1b04a40Sflorian if ((ta_fd = open(TRUST_ANCHOR_FILE, O_RDWR | O_CREAT, 0644)) == -1) 282d1b04a40Sflorian log_warn("%s", TRUST_ANCHOR_FILE); 283d1b04a40Sflorian 284d1b04a40Sflorian /* receiver handles failed open correctly */ 285d1b04a40Sflorian main_imsg_compose_frontend_fd(IMSG_TAFD, 0, ta_fd); 286d1b04a40Sflorian 287018cebfbSflorian main_imsg_compose_frontend_fd(IMSG_CONTROLFD, 0, control_fd); 288018cebfbSflorian main_imsg_compose_frontend_fd(IMSG_ROUTESOCK, 0, frontend_routesock); 289018cebfbSflorian main_imsg_send_config(main_conf); 290018cebfbSflorian 2912d988276Sflorian if (main_conf->blocklist_file != NULL) 2922d988276Sflorian send_blocklist_fd(); 2932d988276Sflorian 294*49a108abSflorian if (pledge("stdio rpath sendfd", NULL) == -1) 295018cebfbSflorian fatal("pledge"); 296018cebfbSflorian 297018cebfbSflorian main_imsg_compose_frontend(IMSG_STARTUP, 0, NULL, 0); 298296cf316Sflorian main_imsg_compose_resolver(IMSG_STARTUP, 0, NULL, 0); 299018cebfbSflorian 300018cebfbSflorian event_dispatch(); 301018cebfbSflorian 302018cebfbSflorian main_shutdown(); 303018cebfbSflorian return (0); 304018cebfbSflorian } 305018cebfbSflorian 306018cebfbSflorian __dead void 307018cebfbSflorian main_shutdown(void) 308018cebfbSflorian { 309018cebfbSflorian pid_t pid; 310018cebfbSflorian int status; 311018cebfbSflorian 312018cebfbSflorian /* Close pipes. */ 313018cebfbSflorian msgbuf_clear(&iev_frontend->ibuf.w); 314018cebfbSflorian close(iev_frontend->ibuf.fd); 315018cebfbSflorian msgbuf_clear(&iev_resolver->ibuf.w); 316018cebfbSflorian close(iev_resolver->ibuf.fd); 317018cebfbSflorian 318018cebfbSflorian config_clear(main_conf); 319018cebfbSflorian 320018cebfbSflorian log_debug("waiting for children to terminate"); 321018cebfbSflorian do { 322018cebfbSflorian pid = wait(&status); 323018cebfbSflorian if (pid == -1) { 324018cebfbSflorian if (errno != EINTR && errno != ECHILD) 325018cebfbSflorian fatal("wait"); 326018cebfbSflorian } else if (WIFSIGNALED(status)) 327018cebfbSflorian log_warnx("%s terminated; signal %d", 328018cebfbSflorian (pid == resolver_pid) ? "resolver" : 329018cebfbSflorian "frontend", WTERMSIG(status)); 330018cebfbSflorian } while (pid != -1 || (pid == -1 && errno == EINTR)); 331018cebfbSflorian 332018cebfbSflorian free(iev_frontend); 333018cebfbSflorian free(iev_resolver); 334018cebfbSflorian 335018cebfbSflorian log_info("terminating"); 336018cebfbSflorian exit(0); 337018cebfbSflorian } 338018cebfbSflorian 339018cebfbSflorian static pid_t 340018cebfbSflorian start_child(int p, char *argv0, int fd, int debug, int verbose) 341018cebfbSflorian { 342018cebfbSflorian char *argv[7]; 343018cebfbSflorian int argc = 0; 344018cebfbSflorian pid_t pid; 345018cebfbSflorian 346018cebfbSflorian switch (pid = fork()) { 347018cebfbSflorian case -1: 348018cebfbSflorian fatal("cannot fork"); 349018cebfbSflorian case 0: 350018cebfbSflorian break; 351018cebfbSflorian default: 352018cebfbSflorian close(fd); 353018cebfbSflorian return (pid); 354018cebfbSflorian } 355018cebfbSflorian 356ef4f5895Syasuoka if (fd != 3) { 357018cebfbSflorian if (dup2(fd, 3) == -1) 358018cebfbSflorian fatal("cannot setup imsg fd"); 359ef4f5895Syasuoka } else if (fcntl(fd, F_SETFD, 0) == -1) 360ef4f5895Syasuoka fatal("cannot setup imsg fd"); 361018cebfbSflorian 362018cebfbSflorian argv[argc++] = argv0; 363018cebfbSflorian switch (p) { 364018cebfbSflorian case PROC_MAIN: 365018cebfbSflorian fatalx("Can not start main process"); 366018cebfbSflorian case PROC_RESOLVER: 367018cebfbSflorian argv[argc++] = "-E"; 368018cebfbSflorian break; 369018cebfbSflorian case PROC_FRONTEND: 370018cebfbSflorian argv[argc++] = "-F"; 371018cebfbSflorian break; 372018cebfbSflorian } 373018cebfbSflorian if (debug) 374018cebfbSflorian argv[argc++] = "-d"; 375018cebfbSflorian if (verbose & OPT_VERBOSE) 376018cebfbSflorian argv[argc++] = "-v"; 377018cebfbSflorian if (verbose & OPT_VERBOSE2) 378018cebfbSflorian argv[argc++] = "-v"; 379e5d1a61aSflorian if (verbose & OPT_VERBOSE3) 380e5d1a61aSflorian argv[argc++] = "-v"; 381018cebfbSflorian argv[argc++] = NULL; 382018cebfbSflorian 383018cebfbSflorian execvp(argv0, argv); 384018cebfbSflorian fatal("execvp"); 385018cebfbSflorian } 386018cebfbSflorian 387018cebfbSflorian void 388018cebfbSflorian main_dispatch_frontend(int fd, short event, void *bula) 389018cebfbSflorian { 390018cebfbSflorian struct imsgev *iev = bula; 391018cebfbSflorian struct imsgbuf *ibuf; 392018cebfbSflorian struct imsg imsg; 393018cebfbSflorian ssize_t n; 394018cebfbSflorian int shut = 0, verbose; 395018cebfbSflorian 396018cebfbSflorian ibuf = &iev->ibuf; 397018cebfbSflorian 398018cebfbSflorian if (event & EV_READ) { 399018cebfbSflorian if ((n = imsg_read(ibuf)) == -1 && errno != EAGAIN) 400018cebfbSflorian fatal("imsg_read error"); 401018cebfbSflorian if (n == 0) /* Connection closed. */ 402018cebfbSflorian shut = 1; 403018cebfbSflorian } 404018cebfbSflorian if (event & EV_WRITE) { 405018cebfbSflorian if ((n = msgbuf_write(&ibuf->w)) == -1 && errno != EAGAIN) 406018cebfbSflorian fatal("msgbuf_write"); 407018cebfbSflorian if (n == 0) /* Connection closed. */ 408018cebfbSflorian shut = 1; 409018cebfbSflorian } 410018cebfbSflorian 411018cebfbSflorian for (;;) { 412018cebfbSflorian if ((n = imsg_get(ibuf, &imsg)) == -1) 413018cebfbSflorian fatal("imsg_get"); 414018cebfbSflorian if (n == 0) /* No more messages. */ 415018cebfbSflorian break; 416018cebfbSflorian 417018cebfbSflorian switch (imsg.hdr.type) { 418018cebfbSflorian case IMSG_STARTUP_DONE: 41928ba4729Sflorian solicit_dns_proposals(); 420018cebfbSflorian break; 421018cebfbSflorian case IMSG_CTL_RELOAD: 422018cebfbSflorian if (main_reload() == -1) 423018cebfbSflorian log_warnx("configuration reload failed"); 424018cebfbSflorian else 425018cebfbSflorian log_warnx("configuration reloaded"); 426018cebfbSflorian break; 427018cebfbSflorian case IMSG_CTL_LOG_VERBOSE: 428a9155f32Sflorian if (IMSG_DATA_SIZE(imsg) != sizeof(verbose)) 4292b821978Sflorian fatalx("%s: IMSG_CTL_LOG_VERBOSE wrong length: " 430a9155f32Sflorian "%lu", __func__, IMSG_DATA_SIZE(imsg)); 431018cebfbSflorian memcpy(&verbose, imsg.data, sizeof(verbose)); 432018cebfbSflorian log_setverbose(verbose); 433018cebfbSflorian break; 434018cebfbSflorian default: 435018cebfbSflorian log_debug("%s: error handling imsg %d", __func__, 436018cebfbSflorian imsg.hdr.type); 437018cebfbSflorian break; 438018cebfbSflorian } 439018cebfbSflorian imsg_free(&imsg); 440018cebfbSflorian } 441018cebfbSflorian if (!shut) 442018cebfbSflorian imsg_event_add(iev); 443018cebfbSflorian else { 444018cebfbSflorian /* This pipe is dead. Remove its event handler */ 445018cebfbSflorian event_del(&iev->ev); 446018cebfbSflorian event_loopexit(NULL); 447018cebfbSflorian } 448018cebfbSflorian } 449018cebfbSflorian 450018cebfbSflorian void 451018cebfbSflorian main_dispatch_resolver(int fd, short event, void *bula) 452018cebfbSflorian { 453018cebfbSflorian struct imsgev *iev = bula; 454018cebfbSflorian struct imsgbuf *ibuf; 455018cebfbSflorian struct imsg imsg; 456018cebfbSflorian ssize_t n; 457018cebfbSflorian int shut = 0; 458018cebfbSflorian 459018cebfbSflorian ibuf = &iev->ibuf; 460018cebfbSflorian 461018cebfbSflorian if (event & EV_READ) { 462018cebfbSflorian if ((n = imsg_read(ibuf)) == -1 && errno != EAGAIN) 463018cebfbSflorian fatal("imsg_read error"); 464018cebfbSflorian if (n == 0) /* Connection closed. */ 465018cebfbSflorian shut = 1; 466018cebfbSflorian } 467018cebfbSflorian if (event & EV_WRITE) { 468018cebfbSflorian if ((n = msgbuf_write(&ibuf->w)) == -1 && errno != EAGAIN) 469018cebfbSflorian fatal("msgbuf_write"); 470018cebfbSflorian if (n == 0) /* Connection closed. */ 471018cebfbSflorian shut = 1; 472018cebfbSflorian } 473018cebfbSflorian 474018cebfbSflorian for (;;) { 475018cebfbSflorian if ((n = imsg_get(ibuf, &imsg)) == -1) 476018cebfbSflorian fatal("imsg_get"); 477018cebfbSflorian if (n == 0) /* No more messages. */ 478018cebfbSflorian break; 479018cebfbSflorian 480018cebfbSflorian switch (imsg.hdr.type) { 481018cebfbSflorian default: 482018cebfbSflorian log_debug("%s: error handling imsg %d", __func__, 483018cebfbSflorian imsg.hdr.type); 484018cebfbSflorian break; 485018cebfbSflorian } 486018cebfbSflorian imsg_free(&imsg); 487018cebfbSflorian } 488018cebfbSflorian if (!shut) 489018cebfbSflorian imsg_event_add(iev); 490018cebfbSflorian else { 491018cebfbSflorian /* This pipe is dead. Remove its event handler. */ 492018cebfbSflorian event_del(&iev->ev); 493018cebfbSflorian event_loopexit(NULL); 494018cebfbSflorian } 495018cebfbSflorian } 496018cebfbSflorian 497018cebfbSflorian void 498018cebfbSflorian main_imsg_compose_frontend(int type, pid_t pid, void *data, uint16_t datalen) 499018cebfbSflorian { 500018cebfbSflorian if (iev_frontend) 501018cebfbSflorian imsg_compose_event(iev_frontend, type, 0, pid, -1, data, 502018cebfbSflorian datalen); 503018cebfbSflorian } 504018cebfbSflorian 505018cebfbSflorian void 506018cebfbSflorian main_imsg_compose_frontend_fd(int type, pid_t pid, int fd) 507018cebfbSflorian { 508018cebfbSflorian if (iev_frontend) 509018cebfbSflorian imsg_compose_event(iev_frontend, type, 0, pid, fd, NULL, 0); 510018cebfbSflorian } 511018cebfbSflorian 512018cebfbSflorian void 513018cebfbSflorian main_imsg_compose_resolver(int type, pid_t pid, void *data, uint16_t datalen) 514018cebfbSflorian { 515018cebfbSflorian if (iev_resolver) 516018cebfbSflorian imsg_compose_event(iev_resolver, type, 0, pid, -1, data, 517018cebfbSflorian datalen); 518018cebfbSflorian } 519018cebfbSflorian 520018cebfbSflorian void 521018cebfbSflorian imsg_event_add(struct imsgev *iev) 522018cebfbSflorian { 523018cebfbSflorian iev->events = EV_READ; 524018cebfbSflorian if (iev->ibuf.w.queued) 525018cebfbSflorian iev->events |= EV_WRITE; 526018cebfbSflorian 527018cebfbSflorian event_del(&iev->ev); 528018cebfbSflorian event_set(&iev->ev, iev->ibuf.fd, iev->events, iev->handler, iev); 529018cebfbSflorian event_add(&iev->ev, NULL); 530018cebfbSflorian } 531018cebfbSflorian 532018cebfbSflorian int 533018cebfbSflorian imsg_compose_event(struct imsgev *iev, uint16_t type, uint32_t peerid, 534018cebfbSflorian pid_t pid, int fd, void *data, uint16_t datalen) 535018cebfbSflorian { 536018cebfbSflorian int ret; 537018cebfbSflorian 538018cebfbSflorian if ((ret = imsg_compose(&iev->ibuf, type, peerid, pid, fd, data, 539018cebfbSflorian datalen)) != -1) 540018cebfbSflorian imsg_event_add(iev); 541018cebfbSflorian 542018cebfbSflorian return (ret); 543018cebfbSflorian } 544018cebfbSflorian 545018cebfbSflorian static int 546018cebfbSflorian main_imsg_send_ipc_sockets(struct imsgbuf *frontend_buf, 547f3ea9bf1Sflorian struct imsgbuf *resolver_buf) 548018cebfbSflorian { 549018cebfbSflorian int pipe_frontend2resolver[2]; 550018cebfbSflorian 551018cebfbSflorian if (socketpair(AF_UNIX, SOCK_STREAM | SOCK_CLOEXEC | SOCK_NONBLOCK, 552018cebfbSflorian PF_UNSPEC, pipe_frontend2resolver) == -1) 553018cebfbSflorian return (-1); 554018cebfbSflorian 555b2501eadSflorian if (imsg_compose(frontend_buf, IMSG_SOCKET_IPC_RESOLVER, 0, 0, 556018cebfbSflorian pipe_frontend2resolver[0], NULL, 0) == -1) 557018cebfbSflorian return (-1); 558b2501eadSflorian if (imsg_compose(resolver_buf, IMSG_SOCKET_IPC_FRONTEND, 0, 0, 559018cebfbSflorian pipe_frontend2resolver[1], NULL, 0) == -1) 560018cebfbSflorian return (-1); 561018cebfbSflorian 562018cebfbSflorian return (0); 563018cebfbSflorian } 564018cebfbSflorian 565018cebfbSflorian int 566018cebfbSflorian main_reload(void) 567018cebfbSflorian { 568bb81f7e1Sflorian struct uw_conf *xconf; 569018cebfbSflorian 570572e5ac0Skn if ((xconf = parse_config(conffile)) == NULL) 571018cebfbSflorian return (-1); 572018cebfbSflorian 573018cebfbSflorian if (main_imsg_send_config(xconf) == -1) 574018cebfbSflorian return (-1); 575018cebfbSflorian 576018cebfbSflorian merge_config(main_conf, xconf); 577018cebfbSflorian 5782d988276Sflorian if (main_conf->blocklist_file != NULL) 5792d988276Sflorian send_blocklist_fd(); 5802d988276Sflorian 581018cebfbSflorian return (0); 582018cebfbSflorian } 583018cebfbSflorian 584018cebfbSflorian int 585bb81f7e1Sflorian main_imsg_send_config(struct uw_conf *xconf) 586018cebfbSflorian { 587bb81f7e1Sflorian struct uw_forwarder *uw_forwarder; 588dd16127bSotto struct force_tree_entry *force_entry; 589018cebfbSflorian 590018cebfbSflorian /* Send fixed part of config to children. */ 591b2501eadSflorian if (main_sendall(IMSG_RECONF_CONF, xconf, sizeof(*xconf)) == -1) 592018cebfbSflorian return (-1); 593018cebfbSflorian 5942d988276Sflorian if (xconf->blocklist_file != NULL) { 5952d988276Sflorian if (main_sendall(IMSG_RECONF_BLOCKLIST_FILE, 5962d988276Sflorian xconf->blocklist_file, strlen(xconf->blocklist_file) + 1) 5972d988276Sflorian == -1) 5982d988276Sflorian return (-1); 5992d988276Sflorian } 6002d988276Sflorian 6013570995aSflorian /* send static forwarders to children */ 6027d055805Sflorian TAILQ_FOREACH(uw_forwarder, &xconf->uw_forwarder_list, entry) { 603bb81f7e1Sflorian if (main_sendall(IMSG_RECONF_FORWARDER, uw_forwarder, 604bb81f7e1Sflorian sizeof(*uw_forwarder)) == -1) 605018cebfbSflorian return (-1); 606018cebfbSflorian } 607018cebfbSflorian 6083570995aSflorian /* send static DoT forwarders to children */ 6097d055805Sflorian TAILQ_FOREACH(uw_forwarder, &xconf->uw_dot_forwarder_list, 6103570995aSflorian entry) { 611bb81f7e1Sflorian if (main_sendall(IMSG_RECONF_DOT_FORWARDER, uw_forwarder, 612bb81f7e1Sflorian sizeof(*uw_forwarder)) == -1) 6133570995aSflorian return (-1); 6143570995aSflorian } 615dd16127bSotto RB_FOREACH(force_entry, force_tree, &xconf->force) { 616dd16127bSotto if (main_sendall(IMSG_RECONF_FORCE, force_entry, 617dd16127bSotto sizeof(*force_entry)) == -1) 618dd16127bSotto return (-1); 619dd16127bSotto } 6203570995aSflorian 621018cebfbSflorian /* Tell children the revised config is now complete. */ 622b2501eadSflorian if (main_sendall(IMSG_RECONF_END, NULL, 0) == -1) 623018cebfbSflorian return (-1); 624018cebfbSflorian 625018cebfbSflorian return (0); 626018cebfbSflorian } 627018cebfbSflorian 628018cebfbSflorian int 629b2501eadSflorian main_sendall(enum imsg_type type, void *buf, uint16_t len) 630018cebfbSflorian { 631018cebfbSflorian if (imsg_compose_event(iev_frontend, type, 0, 0, -1, buf, len) == -1) 632018cebfbSflorian return (-1); 633018cebfbSflorian if (imsg_compose_event(iev_resolver, type, 0, 0, -1, buf, len) == -1) 634018cebfbSflorian return (-1); 635018cebfbSflorian return (0); 636018cebfbSflorian } 637018cebfbSflorian 638018cebfbSflorian void 639bb81f7e1Sflorian merge_config(struct uw_conf *conf, struct uw_conf *xconf) 640018cebfbSflorian { 641bb81f7e1Sflorian struct uw_forwarder *uw_forwarder; 642dd16127bSotto struct force_tree_entry *n, *nxt; 643018cebfbSflorian 644018cebfbSflorian /* Remove & discard existing forwarders. */ 6457d055805Sflorian while ((uw_forwarder = TAILQ_FIRST(&conf->uw_forwarder_list)) != 646bb81f7e1Sflorian NULL) { 6477d055805Sflorian TAILQ_REMOVE(&conf->uw_forwarder_list, uw_forwarder, entry); 648bb81f7e1Sflorian free(uw_forwarder); 649018cebfbSflorian } 6507d055805Sflorian while ((uw_forwarder = TAILQ_FIRST(&conf->uw_dot_forwarder_list)) != 651bb81f7e1Sflorian NULL) { 6527d055805Sflorian TAILQ_REMOVE(&conf->uw_dot_forwarder_list, uw_forwarder, entry); 653bb81f7e1Sflorian free(uw_forwarder); 6543570995aSflorian } 655018cebfbSflorian 656dd16127bSotto /* Remove & discard existing force tree. */ 657dd16127bSotto for (n = RB_MIN(force_tree, &conf->force); n != NULL; n = nxt) { 658dd16127bSotto nxt = RB_NEXT(force_tree, &conf->force, n); 659dd16127bSotto RB_REMOVE(force_tree, &conf->force, n); 660dd16127bSotto free(n); 661dd16127bSotto } 662dd16127bSotto 663fd873f7fSflorian memcpy(&conf->res_pref, &xconf->res_pref, 664fd873f7fSflorian sizeof(conf->res_pref)); 665018cebfbSflorian 6662d988276Sflorian free(conf->blocklist_file); 6672d988276Sflorian conf->blocklist_file = xconf->blocklist_file; 668ac71ec8eSflorian conf->blocklist_log = xconf->blocklist_log; 6692d988276Sflorian 670018cebfbSflorian /* Add new forwarders. */ 6712feeeacaSflorian TAILQ_CONCAT(&conf->uw_forwarder_list, &xconf->uw_forwarder_list, 6727d055805Sflorian entry); 6732feeeacaSflorian TAILQ_CONCAT(&conf->uw_dot_forwarder_list, 6742feeeacaSflorian &xconf->uw_dot_forwarder_list, entry); 675018cebfbSflorian 676dd16127bSotto for (n = RB_MIN(force_tree, &xconf->force); n != NULL; n = nxt) { 677dd16127bSotto nxt = RB_NEXT(force_tree, &xconf->force, n); 678dd16127bSotto RB_REMOVE(force_tree, &xconf->force, n); 679dd16127bSotto RB_INSERT(force_tree, &conf->force, n); 680dd16127bSotto } 681dd16127bSotto 682018cebfbSflorian free(xconf); 683018cebfbSflorian } 684018cebfbSflorian 685bb81f7e1Sflorian struct uw_conf * 686018cebfbSflorian config_new_empty(void) 687018cebfbSflorian { 688fd873f7fSflorian static enum uw_resolver_type default_res_pref[] = { 689fd873f7fSflorian UW_RES_DOT, 69015fe126bSflorian UW_RES_ODOT_FORWARDER, 691fd873f7fSflorian UW_RES_FORWARDER, 692fd873f7fSflorian UW_RES_RECURSOR, 69315fe126bSflorian UW_RES_ODOT_DHCP, 694530f5ecfSflorian UW_RES_DHCP, 695530f5ecfSflorian UW_RES_ASR}; 696bb81f7e1Sflorian struct uw_conf *xconf; 697018cebfbSflorian 698018cebfbSflorian xconf = calloc(1, sizeof(*xconf)); 699018cebfbSflorian if (xconf == NULL) 700018cebfbSflorian fatal(NULL); 701018cebfbSflorian 702d032132bSflorian memcpy(&xconf->res_pref.types, &default_res_pref, 703fd873f7fSflorian sizeof(default_res_pref)); 704d032132bSflorian xconf->res_pref.len = nitems(default_res_pref); 705fd873f7fSflorian 7067d055805Sflorian TAILQ_INIT(&xconf->uw_forwarder_list); 7077d055805Sflorian TAILQ_INIT(&xconf->uw_dot_forwarder_list); 708018cebfbSflorian 709dd16127bSotto RB_INIT(&xconf->force); 710dd16127bSotto 711018cebfbSflorian return (xconf); 712018cebfbSflorian } 713018cebfbSflorian 714018cebfbSflorian void 715bb81f7e1Sflorian config_clear(struct uw_conf *conf) 716018cebfbSflorian { 717bb81f7e1Sflorian struct uw_conf *xconf; 718018cebfbSflorian 719018cebfbSflorian /* Merge current config with an empty config. */ 720018cebfbSflorian xconf = config_new_empty(); 721018cebfbSflorian merge_config(conf, xconf); 722018cebfbSflorian 723018cebfbSflorian free(conf); 724018cebfbSflorian } 725018cebfbSflorian 726018cebfbSflorian void 727d265a5d3Sflorian open_ports(void) 728d265a5d3Sflorian { 729d265a5d3Sflorian struct addrinfo hints, *res0; 730d265a5d3Sflorian int udp4sock = -1, udp6sock = -1, error; 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) { 741d265a5d3Sflorian if (bind(udp4sock, res0->ai_addr, res0->ai_addrlen) 742d265a5d3Sflorian == -1) { 743d265a5d3Sflorian close(udp4sock); 744d265a5d3Sflorian udp4sock = -1; 745d265a5d3Sflorian } 746d265a5d3Sflorian } 747d265a5d3Sflorian } 748296cf316Sflorian if (res0) 749d265a5d3Sflorian freeaddrinfo(res0); 750d265a5d3Sflorian 751d265a5d3Sflorian hints.ai_family = AF_INET6; 752d265a5d3Sflorian error = getaddrinfo("::1", "domain", &hints, &res0); 753d265a5d3Sflorian if (!error && res0) { 754d265a5d3Sflorian if ((udp6sock = socket(res0->ai_family, res0->ai_socktype, 755d265a5d3Sflorian res0->ai_protocol)) != -1) { 756d265a5d3Sflorian if (bind(udp6sock, res0->ai_addr, res0->ai_addrlen) 757d265a5d3Sflorian == -1) { 758d265a5d3Sflorian close(udp6sock); 759d265a5d3Sflorian udp6sock = -1; 760d265a5d3Sflorian } 761d265a5d3Sflorian } 762d265a5d3Sflorian } 763296cf316Sflorian if (res0) 764d265a5d3Sflorian freeaddrinfo(res0); 765d265a5d3Sflorian 766d265a5d3Sflorian if (udp4sock == -1 && udp6sock == -1) 767d265a5d3Sflorian fatal("could not bind to 127.0.0.1 or ::1 on port 53"); 768d265a5d3Sflorian 769b04dd19dSflorian if (udp4sock != -1) 770d265a5d3Sflorian main_imsg_compose_frontend_fd(IMSG_UDP4SOCK, 0, udp4sock); 771b04dd19dSflorian if (udp6sock != -1) 772d265a5d3Sflorian main_imsg_compose_frontend_fd(IMSG_UDP6SOCK, 0, udp6sock); 773d265a5d3Sflorian } 7742f29e846Sflorian 7752f29e846Sflorian void 77628ba4729Sflorian solicit_dns_proposals(void) 77728ba4729Sflorian { 77828ba4729Sflorian struct rt_msghdr rtm; 77928ba4729Sflorian struct iovec iov[1]; 78028ba4729Sflorian int iovcnt = 0; 78128ba4729Sflorian 78228ba4729Sflorian memset(&rtm, 0, sizeof(rtm)); 78328ba4729Sflorian 78428ba4729Sflorian rtm.rtm_version = RTM_VERSION; 78528ba4729Sflorian rtm.rtm_type = RTM_PROPOSAL; 78628ba4729Sflorian rtm.rtm_msglen = sizeof(rtm); 78728ba4729Sflorian rtm.rtm_tableid = 0; 78828ba4729Sflorian rtm.rtm_index = 0; 78928ba4729Sflorian rtm.rtm_seq = arc4random(); 79028ba4729Sflorian rtm.rtm_priority = RTP_PROPOSAL_SOLICIT; 79128ba4729Sflorian 79228ba4729Sflorian iov[iovcnt].iov_base = &rtm; 79328ba4729Sflorian iov[iovcnt++].iov_len = sizeof(rtm); 79428ba4729Sflorian 79528ba4729Sflorian if (writev(routesock, iov, iovcnt) == -1) 79628ba4729Sflorian log_warn("failed to send solicitation"); 79728ba4729Sflorian } 79828ba4729Sflorian 79928ba4729Sflorian void 8002d988276Sflorian send_blocklist_fd(void) 8012d988276Sflorian { 8022d988276Sflorian int bl_fd; 8032d988276Sflorian 8042d988276Sflorian if ((bl_fd = open(main_conf->blocklist_file, O_RDONLY)) != -1) 8052d988276Sflorian main_imsg_compose_frontend_fd(IMSG_BLFD, 0, bl_fd); 8062d988276Sflorian else 8072d988276Sflorian log_warn("%s", main_conf->blocklist_file); 8082d988276Sflorian } 809679647feSflorian 810679647feSflorian void 811679647feSflorian imsg_receive_config(struct imsg *imsg, struct uw_conf **xconf) 812679647feSflorian { 813679647feSflorian struct uw_conf *nconf; 814679647feSflorian struct uw_forwarder *uw_forwarder; 815dd16127bSotto struct force_tree_entry *force_entry; 816679647feSflorian 817679647feSflorian nconf = *xconf; 818679647feSflorian 819679647feSflorian switch (imsg->hdr.type) { 820679647feSflorian case IMSG_RECONF_CONF: 821679647feSflorian if (nconf != NULL) 822679647feSflorian fatalx("%s: IMSG_RECONF_CONF already in " 823679647feSflorian "progress", __func__); 824679647feSflorian if (IMSG_DATA_SIZE(*imsg) != sizeof(struct uw_conf)) 825679647feSflorian fatalx("%s: IMSG_RECONF_CONF wrong length: %lu", 826679647feSflorian __func__, IMSG_DATA_SIZE(*imsg)); 827679647feSflorian if ((*xconf = malloc(sizeof(struct uw_conf))) == NULL) 828679647feSflorian fatal(NULL); 829679647feSflorian nconf = *xconf; 830679647feSflorian memcpy(nconf, imsg->data, sizeof(struct uw_conf)); 8317d055805Sflorian TAILQ_INIT(&nconf->uw_forwarder_list); 8327d055805Sflorian TAILQ_INIT(&nconf->uw_dot_forwarder_list); 833dd16127bSotto RB_INIT(&nconf->force); 834679647feSflorian break; 835679647feSflorian case IMSG_RECONF_BLOCKLIST_FILE: 836679647feSflorian /* make sure this is a string */ 837679647feSflorian ((char *)imsg->data)[IMSG_DATA_SIZE(*imsg) - 1] = '\0'; 838679647feSflorian if ((nconf->blocklist_file = strdup(imsg->data)) == 839679647feSflorian NULL) 840679647feSflorian fatal("%s: strdup", __func__); 841679647feSflorian break; 842679647feSflorian case IMSG_RECONF_FORWARDER: 843679647feSflorian if (IMSG_DATA_SIZE(*imsg) != sizeof(struct uw_forwarder)) 844679647feSflorian fatalx("%s: IMSG_RECONF_FORWARDER wrong length:" 845679647feSflorian " %lu", __func__, IMSG_DATA_SIZE(*imsg)); 846679647feSflorian if ((uw_forwarder = malloc(sizeof(struct 847679647feSflorian uw_forwarder))) == NULL) 848679647feSflorian fatal(NULL); 849679647feSflorian memcpy(uw_forwarder, imsg->data, sizeof(struct 850679647feSflorian uw_forwarder)); 8517d055805Sflorian TAILQ_INSERT_TAIL(&nconf->uw_forwarder_list, 852679647feSflorian uw_forwarder, entry); 853679647feSflorian break; 854679647feSflorian case IMSG_RECONF_DOT_FORWARDER: 855679647feSflorian if (IMSG_DATA_SIZE(*imsg) != sizeof(struct uw_forwarder)) 856679647feSflorian fatalx("%s: IMSG_RECONF_DOT_FORWARDER wrong " 857679647feSflorian "length: %lu", __func__, 858679647feSflorian IMSG_DATA_SIZE(*imsg)); 859679647feSflorian if ((uw_forwarder = malloc(sizeof(struct 860679647feSflorian uw_forwarder))) == NULL) 861679647feSflorian fatal(NULL); 862679647feSflorian memcpy(uw_forwarder, imsg->data, sizeof(struct 863679647feSflorian uw_forwarder)); 8647d055805Sflorian TAILQ_INSERT_TAIL(&nconf->uw_dot_forwarder_list, 865679647feSflorian uw_forwarder, entry); 866679647feSflorian break; 867dd16127bSotto case IMSG_RECONF_FORCE: 868dd16127bSotto if (IMSG_DATA_SIZE(*imsg) != sizeof(struct force_tree_entry)) 869dd16127bSotto fatalx("%s: IMSG_RECONF_FORCE wrong " 870dd16127bSotto "length: %lu", __func__, 871dd16127bSotto IMSG_DATA_SIZE(*imsg)); 872dd16127bSotto if ((force_entry = malloc(sizeof(struct 873dd16127bSotto force_tree_entry))) == NULL) 874dd16127bSotto fatal(NULL); 875dd16127bSotto memcpy(force_entry, imsg->data, sizeof(struct 876dd16127bSotto force_tree_entry)); 877dd16127bSotto RB_INSERT(force_tree, &nconf->force, force_entry); 878dd16127bSotto break; 879679647feSflorian default: 880679647feSflorian log_debug("%s: error handling imsg %d", __func__, 881679647feSflorian imsg->hdr.type); 882679647feSflorian break; 883679647feSflorian } 884679647feSflorian } 885