1*0e59d0d1Sclaudio /* $OpenBSD: unwind.c,v 1.75 2024/11/21 13:35:20 claudio 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 53d223f0d9Sflorian enum uw_process { 54d223f0d9Sflorian PROC_MAIN, 55d223f0d9Sflorian PROC_RESOLVER, 56d223f0d9Sflorian PROC_FRONTEND, 57d223f0d9Sflorian }; 58d223f0d9Sflorian 59018cebfbSflorian __dead void usage(void); 60018cebfbSflorian __dead void main_shutdown(void); 61018cebfbSflorian 62018cebfbSflorian void main_sig_handler(int, short, void *); 63018cebfbSflorian 64d223f0d9Sflorian static pid_t start_child(enum uw_process, char *, int, int, int); 65018cebfbSflorian 66018cebfbSflorian void main_dispatch_frontend(int, short, void *); 67018cebfbSflorian void main_dispatch_resolver(int, short, void *); 68018cebfbSflorian 69f3ea9bf1Sflorian static int main_imsg_send_ipc_sockets(struct imsgbuf *, struct imsgbuf *); 70bb81f7e1Sflorian static int main_imsg_send_config(struct uw_conf *); 71018cebfbSflorian 72018cebfbSflorian int main_reload(void); 73b2501eadSflorian int main_sendall(enum imsg_type, void *, uint16_t); 74d265a5d3Sflorian void open_ports(void); 7528ba4729Sflorian void solicit_dns_proposals(void); 762d988276Sflorian void send_blocklist_fd(void); 77018cebfbSflorian 78bb81f7e1Sflorian struct uw_conf *main_conf; 79d81b02e2Sflorian static struct imsgev *iev_frontend; 80d81b02e2Sflorian static struct imsgev *iev_resolver; 81572e5ac0Skn char *conffile; 82018cebfbSflorian pid_t frontend_pid; 83018cebfbSflorian pid_t resolver_pid; 84018cebfbSflorian uint32_t cmd_opts; 8528ba4729Sflorian int routesock; 8628ba4729Sflorian 87018cebfbSflorian void 88018cebfbSflorian main_sig_handler(int sig, short event, void *arg) 89018cebfbSflorian { 90018cebfbSflorian /* 91018cebfbSflorian * Normal signal handler rules don't apply because libevent 92018cebfbSflorian * decouples for us. 93018cebfbSflorian */ 94018cebfbSflorian 95018cebfbSflorian switch (sig) { 96018cebfbSflorian case SIGTERM: 97018cebfbSflorian case SIGINT: 985472663aSflorian main_shutdown(); 99018cebfbSflorian break; 100018cebfbSflorian case SIGHUP: 101018cebfbSflorian if (main_reload() == -1) 102018cebfbSflorian log_warnx("configuration reload failed"); 103018cebfbSflorian else 104018cebfbSflorian log_debug("configuration reloaded"); 105018cebfbSflorian break; 106018cebfbSflorian default: 107018cebfbSflorian fatalx("unexpected signal"); 108018cebfbSflorian } 109018cebfbSflorian } 110018cebfbSflorian 111018cebfbSflorian __dead void 112018cebfbSflorian usage(void) 113018cebfbSflorian { 114018cebfbSflorian extern char *__progname; 115018cebfbSflorian 116018cebfbSflorian fprintf(stderr, "usage: %s [-dnv] [-f file] [-s socket]\n", 117018cebfbSflorian __progname); 118018cebfbSflorian exit(1); 119018cebfbSflorian } 120018cebfbSflorian 121018cebfbSflorian int 122018cebfbSflorian main(int argc, char *argv[]) 123018cebfbSflorian { 124018cebfbSflorian struct event ev_sigint, ev_sigterm, ev_sighup; 125bb81f7e1Sflorian int ch, debug = 0, resolver_flag = 0, frontend_flag = 0; 126f3ea9bf1Sflorian int frontend_routesock, rtfilter; 127bb81f7e1Sflorian int pipe_main2frontend[2], pipe_main2resolver[2]; 128abb04357Sflorian int control_fd, ta_fd; 129bb81f7e1Sflorian char *csock, *saved_argv0; 130018cebfbSflorian 131ee5be195Sflorian csock = _PATH_UNWIND_SOCKET; 132018cebfbSflorian 133018cebfbSflorian log_init(1, LOG_DAEMON); /* Log to stderr until daemonized. */ 134018cebfbSflorian log_setverbose(1); 135018cebfbSflorian 136018cebfbSflorian saved_argv0 = argv[0]; 137018cebfbSflorian if (saved_argv0 == NULL) 138018cebfbSflorian saved_argv0 = "unwind"; 139018cebfbSflorian 140f3ea9bf1Sflorian while ((ch = getopt(argc, argv, "dEFf:ns:v")) != -1) { 141018cebfbSflorian switch (ch) { 142018cebfbSflorian case 'd': 143018cebfbSflorian debug = 1; 144018cebfbSflorian break; 145018cebfbSflorian case 'E': 146018cebfbSflorian resolver_flag = 1; 147018cebfbSflorian break; 148018cebfbSflorian case 'F': 149018cebfbSflorian frontend_flag = 1; 150018cebfbSflorian break; 151018cebfbSflorian case 'f': 152018cebfbSflorian conffile = optarg; 153018cebfbSflorian break; 154018cebfbSflorian case 'n': 155018cebfbSflorian cmd_opts |= OPT_NOACTION; 156018cebfbSflorian break; 157018cebfbSflorian case 's': 158018cebfbSflorian csock = optarg; 159018cebfbSflorian break; 160018cebfbSflorian case 'v': 161e5d1a61aSflorian if (cmd_opts & OPT_VERBOSE2) 162e5d1a61aSflorian cmd_opts |= OPT_VERBOSE3; 163018cebfbSflorian if (cmd_opts & OPT_VERBOSE) 164018cebfbSflorian cmd_opts |= OPT_VERBOSE2; 165018cebfbSflorian cmd_opts |= OPT_VERBOSE; 166018cebfbSflorian break; 167018cebfbSflorian default: 168018cebfbSflorian usage(); 169018cebfbSflorian } 170018cebfbSflorian } 171018cebfbSflorian 172018cebfbSflorian argc -= optind; 173018cebfbSflorian argv += optind; 174f3ea9bf1Sflorian if (argc > 0 || (resolver_flag && frontend_flag)) 175018cebfbSflorian usage(); 176018cebfbSflorian 177018cebfbSflorian if (resolver_flag) 178e5d1a61aSflorian resolver(debug, cmd_opts & (OPT_VERBOSE | OPT_VERBOSE2 | 179e5d1a61aSflorian OPT_VERBOSE3)); 180018cebfbSflorian else if (frontend_flag) 181e5d1a61aSflorian frontend(debug, cmd_opts & (OPT_VERBOSE | OPT_VERBOSE2 | 182e5d1a61aSflorian OPT_VERBOSE3)); 183018cebfbSflorian 184572e5ac0Skn if ((main_conf = parse_config(conffile)) == NULL) 185018cebfbSflorian exit(1); 186018cebfbSflorian 187018cebfbSflorian if (cmd_opts & OPT_NOACTION) { 188018cebfbSflorian if (cmd_opts & OPT_VERBOSE) 189018cebfbSflorian print_config(main_conf); 190018cebfbSflorian else 191018cebfbSflorian fprintf(stderr, "configuration OK\n"); 192018cebfbSflorian exit(0); 193018cebfbSflorian } 194018cebfbSflorian 195018cebfbSflorian /* Check for root privileges. */ 196018cebfbSflorian if (geteuid()) 197018cebfbSflorian errx(1, "need root privileges"); 198018cebfbSflorian 199018cebfbSflorian /* Check for assigned daemon user */ 200018cebfbSflorian if (getpwnam(UNWIND_USER) == NULL) 201018cebfbSflorian errx(1, "unknown user %s", UNWIND_USER); 202018cebfbSflorian 203018cebfbSflorian log_init(debug, LOG_DAEMON); 204e5d1a61aSflorian log_setverbose(cmd_opts & (OPT_VERBOSE | OPT_VERBOSE2 | OPT_VERBOSE3)); 205018cebfbSflorian 206018cebfbSflorian if (!debug) 207018cebfbSflorian daemon(1, 0); 208018cebfbSflorian 209018cebfbSflorian if (socketpair(AF_UNIX, SOCK_STREAM | SOCK_CLOEXEC | SOCK_NONBLOCK, 210018cebfbSflorian PF_UNSPEC, pipe_main2frontend) == -1) 211018cebfbSflorian fatal("main2frontend socketpair"); 212018cebfbSflorian if (socketpair(AF_UNIX, SOCK_STREAM | SOCK_CLOEXEC | SOCK_NONBLOCK, 213018cebfbSflorian PF_UNSPEC, pipe_main2resolver) == -1) 214018cebfbSflorian fatal("main2resolver socketpair"); 215018cebfbSflorian 216018cebfbSflorian /* Start children. */ 217018cebfbSflorian resolver_pid = start_child(PROC_RESOLVER, saved_argv0, 218018cebfbSflorian pipe_main2resolver[1], debug, cmd_opts & (OPT_VERBOSE | 219e5d1a61aSflorian OPT_VERBOSE2 | OPT_VERBOSE3)); 220018cebfbSflorian frontend_pid = start_child(PROC_FRONTEND, saved_argv0, 221018cebfbSflorian pipe_main2frontend[1], debug, cmd_opts & (OPT_VERBOSE | 222e5d1a61aSflorian OPT_VERBOSE2 | OPT_VERBOSE3)); 223018cebfbSflorian 224d223f0d9Sflorian log_procinit("main"); 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); 242*0e59d0d1Sclaudio if (imsgbuf_init(&iev_frontend->ibuf, pipe_main2frontend[0]) == -1) 243*0e59d0d1Sclaudio fatal(NULL); 244*0e59d0d1Sclaudio imsgbuf_allow_fdpass(&iev_frontend->ibuf); 245018cebfbSflorian iev_frontend->handler = main_dispatch_frontend; 246*0e59d0d1Sclaudio if (imsgbuf_init(&iev_resolver->ibuf, pipe_main2resolver[0]) == -1) 247*0e59d0d1Sclaudio fatal(NULL); 248*0e59d0d1Sclaudio imsgbuf_allow_fdpass(&iev_resolver->ibuf); 249018cebfbSflorian iev_resolver->handler = main_dispatch_resolver; 250018cebfbSflorian 251b2501eadSflorian /* Setup event handlers for pipes. */ 252018cebfbSflorian iev_frontend->events = EV_READ; 253018cebfbSflorian event_set(&iev_frontend->ev, iev_frontend->ibuf.fd, 254018cebfbSflorian iev_frontend->events, iev_frontend->handler, iev_frontend); 255018cebfbSflorian event_add(&iev_frontend->ev, NULL); 256018cebfbSflorian 257018cebfbSflorian iev_resolver->events = EV_READ; 258bb81f7e1Sflorian event_set(&iev_resolver->ev, iev_resolver->ibuf.fd, 259bb81f7e1Sflorian iev_resolver->events, iev_resolver->handler, iev_resolver); 260018cebfbSflorian event_add(&iev_resolver->ev, NULL); 261018cebfbSflorian 262b2501eadSflorian if (main_imsg_send_ipc_sockets(&iev_frontend->ibuf, 263f3ea9bf1Sflorian &iev_resolver->ibuf)) 264018cebfbSflorian fatal("could not establish imsg links"); 265018cebfbSflorian 26649a108abSflorian open_ports(); 26749a108abSflorian 268018cebfbSflorian if ((control_fd = control_init(csock)) == -1) 269018cebfbSflorian fatalx("control socket setup failed"); 270018cebfbSflorian 2715ebe2a79Sflorian if ((frontend_routesock = socket(AF_ROUTE, SOCK_RAW | SOCK_CLOEXEC | 2725ebe2a79Sflorian SOCK_NONBLOCK, 0)) == -1) 273018cebfbSflorian fatal("route socket"); 274018cebfbSflorian 27585384332Sflorian rtfilter = ROUTE_FILTER(RTM_IFINFO) | ROUTE_FILTER(RTM_PROPOSAL) 2765dca88ceSflorian | ROUTE_FILTER(RTM_IFANNOUNCE) | ROUTE_FILTER(RTM_NEWADDR) 2775dca88ceSflorian | ROUTE_FILTER(RTM_DELADDR); 2789e627e00Sflorian if (setsockopt(frontend_routesock, AF_ROUTE, ROUTE_MSGFILTER, 279df69c215Sderaadt &rtfilter, sizeof(rtfilter)) == -1) 280018cebfbSflorian fatal("setsockopt(ROUTE_MSGFILTER)"); 281018cebfbSflorian 28228ba4729Sflorian if ((routesock = socket(AF_ROUTE, SOCK_RAW | SOCK_CLOEXEC | 2835ebe2a79Sflorian SOCK_NONBLOCK, 0)) == -1) 28428ba4729Sflorian fatal("route socket"); 285fe9a5e47Sflorian shutdown(routesock, SHUT_RD); 28628ba4729Sflorian 287abb04357Sflorian if ((ta_fd = open(TRUST_ANCHOR_FILE, O_RDWR | O_CREAT, 0644)) == -1) 288abb04357Sflorian log_warn("%s", TRUST_ANCHOR_FILE); 289abb04357Sflorian 290abb04357Sflorian /* receiver handles failed open correctly */ 291abb04357Sflorian main_imsg_compose_frontend_fd(IMSG_TAFD, 0, ta_fd); 292abb04357Sflorian 293018cebfbSflorian main_imsg_compose_frontend_fd(IMSG_CONTROLFD, 0, control_fd); 294018cebfbSflorian main_imsg_compose_frontend_fd(IMSG_ROUTESOCK, 0, frontend_routesock); 295018cebfbSflorian main_imsg_send_config(main_conf); 296018cebfbSflorian 2972d988276Sflorian if (main_conf->blocklist_file != NULL) 2982d988276Sflorian send_blocklist_fd(); 2992d988276Sflorian 300abb04357Sflorian if (pledge("stdio rpath sendfd", NULL) == -1) 301018cebfbSflorian fatal("pledge"); 302018cebfbSflorian 303018cebfbSflorian main_imsg_compose_frontend(IMSG_STARTUP, 0, NULL, 0); 304296cf316Sflorian main_imsg_compose_resolver(IMSG_STARTUP, 0, NULL, 0); 305018cebfbSflorian 306018cebfbSflorian event_dispatch(); 307018cebfbSflorian 308018cebfbSflorian main_shutdown(); 309018cebfbSflorian return (0); 310018cebfbSflorian } 311018cebfbSflorian 312018cebfbSflorian __dead void 313018cebfbSflorian main_shutdown(void) 314018cebfbSflorian { 315018cebfbSflorian pid_t pid; 316018cebfbSflorian int status; 317018cebfbSflorian 318018cebfbSflorian /* Close pipes. */ 3199cbf9e90Sclaudio imsgbuf_clear(&iev_frontend->ibuf); 320018cebfbSflorian close(iev_frontend->ibuf.fd); 3219cbf9e90Sclaudio imsgbuf_clear(&iev_resolver->ibuf); 322018cebfbSflorian close(iev_resolver->ibuf.fd); 323018cebfbSflorian 324018cebfbSflorian config_clear(main_conf); 325018cebfbSflorian 326018cebfbSflorian log_debug("waiting for children to terminate"); 327018cebfbSflorian do { 328018cebfbSflorian pid = wait(&status); 329018cebfbSflorian if (pid == -1) { 330018cebfbSflorian if (errno != EINTR && errno != ECHILD) 331018cebfbSflorian fatal("wait"); 332018cebfbSflorian } else if (WIFSIGNALED(status)) 333018cebfbSflorian log_warnx("%s terminated; signal %d", 334018cebfbSflorian (pid == resolver_pid) ? "resolver" : 335018cebfbSflorian "frontend", WTERMSIG(status)); 336018cebfbSflorian } while (pid != -1 || (pid == -1 && errno == EINTR)); 337018cebfbSflorian 338018cebfbSflorian free(iev_frontend); 339018cebfbSflorian free(iev_resolver); 340018cebfbSflorian 341018cebfbSflorian log_info("terminating"); 342018cebfbSflorian exit(0); 343018cebfbSflorian } 344018cebfbSflorian 345018cebfbSflorian static pid_t 346d223f0d9Sflorian start_child(enum uw_process p, char *argv0, int fd, int debug, int verbose) 347018cebfbSflorian { 348018cebfbSflorian char *argv[7]; 349018cebfbSflorian int argc = 0; 350018cebfbSflorian pid_t pid; 351018cebfbSflorian 352018cebfbSflorian switch (pid = fork()) { 353018cebfbSflorian case -1: 354018cebfbSflorian fatal("cannot fork"); 355018cebfbSflorian case 0: 356018cebfbSflorian break; 357018cebfbSflorian default: 358018cebfbSflorian close(fd); 359018cebfbSflorian return (pid); 360018cebfbSflorian } 361018cebfbSflorian 362ef4f5895Syasuoka if (fd != 3) { 363018cebfbSflorian if (dup2(fd, 3) == -1) 364018cebfbSflorian fatal("cannot setup imsg fd"); 365ef4f5895Syasuoka } else if (fcntl(fd, F_SETFD, 0) == -1) 366ef4f5895Syasuoka fatal("cannot setup imsg fd"); 367018cebfbSflorian 368018cebfbSflorian argv[argc++] = argv0; 369018cebfbSflorian switch (p) { 370018cebfbSflorian case PROC_MAIN: 371018cebfbSflorian fatalx("Can not start main process"); 372018cebfbSflorian case PROC_RESOLVER: 373018cebfbSflorian argv[argc++] = "-E"; 374018cebfbSflorian break; 375018cebfbSflorian case PROC_FRONTEND: 376018cebfbSflorian argv[argc++] = "-F"; 377018cebfbSflorian break; 378018cebfbSflorian } 379018cebfbSflorian if (debug) 380018cebfbSflorian argv[argc++] = "-d"; 381018cebfbSflorian if (verbose & OPT_VERBOSE) 382018cebfbSflorian argv[argc++] = "-v"; 383018cebfbSflorian if (verbose & OPT_VERBOSE2) 384018cebfbSflorian argv[argc++] = "-v"; 385e5d1a61aSflorian if (verbose & OPT_VERBOSE3) 386e5d1a61aSflorian argv[argc++] = "-v"; 387018cebfbSflorian argv[argc++] = NULL; 388018cebfbSflorian 389018cebfbSflorian execvp(argv0, argv); 390018cebfbSflorian fatal("execvp"); 391018cebfbSflorian } 392018cebfbSflorian 393018cebfbSflorian void 394018cebfbSflorian main_dispatch_frontend(int fd, short event, void *bula) 395018cebfbSflorian { 396018cebfbSflorian struct imsgev *iev = bula; 397018cebfbSflorian struct imsgbuf *ibuf; 398018cebfbSflorian struct imsg imsg; 399018cebfbSflorian ssize_t n; 400018cebfbSflorian int shut = 0, verbose; 401018cebfbSflorian 402018cebfbSflorian ibuf = &iev->ibuf; 403018cebfbSflorian 404018cebfbSflorian if (event & EV_READ) { 405668e5ba9Sclaudio if ((n = imsgbuf_read(ibuf)) == -1) 406dd7efffeSclaudio fatal("imsgbuf_read error"); 407018cebfbSflorian if (n == 0) /* Connection closed. */ 408018cebfbSflorian shut = 1; 409018cebfbSflorian } 410018cebfbSflorian if (event & EV_WRITE) { 411dd7efffeSclaudio if (imsgbuf_write(ibuf) == -1) { 412e3b6409cSclaudio if (errno == EPIPE) /* Connection closed. */ 413018cebfbSflorian shut = 1; 414e3b6409cSclaudio else 415dd7efffeSclaudio fatal("imsgbuf_write"); 416e3b6409cSclaudio } 417018cebfbSflorian } 418018cebfbSflorian 419018cebfbSflorian for (;;) { 420018cebfbSflorian if ((n = imsg_get(ibuf, &imsg)) == -1) 421018cebfbSflorian fatal("imsg_get"); 422018cebfbSflorian if (n == 0) /* No more messages. */ 423018cebfbSflorian break; 424018cebfbSflorian 425018cebfbSflorian switch (imsg.hdr.type) { 426018cebfbSflorian case IMSG_STARTUP_DONE: 42728ba4729Sflorian solicit_dns_proposals(); 428018cebfbSflorian break; 429018cebfbSflorian case IMSG_CTL_RELOAD: 430018cebfbSflorian if (main_reload() == -1) 431018cebfbSflorian log_warnx("configuration reload failed"); 432018cebfbSflorian else 433018cebfbSflorian log_warnx("configuration reloaded"); 434018cebfbSflorian break; 435018cebfbSflorian case IMSG_CTL_LOG_VERBOSE: 436a9155f32Sflorian if (IMSG_DATA_SIZE(imsg) != sizeof(verbose)) 4372b821978Sflorian fatalx("%s: IMSG_CTL_LOG_VERBOSE wrong length: " 438a9155f32Sflorian "%lu", __func__, IMSG_DATA_SIZE(imsg)); 439018cebfbSflorian memcpy(&verbose, imsg.data, sizeof(verbose)); 440018cebfbSflorian log_setverbose(verbose); 441018cebfbSflorian break; 442018cebfbSflorian default: 443018cebfbSflorian log_debug("%s: error handling imsg %d", __func__, 444018cebfbSflorian imsg.hdr.type); 445018cebfbSflorian break; 446018cebfbSflorian } 447018cebfbSflorian imsg_free(&imsg); 448018cebfbSflorian } 449018cebfbSflorian if (!shut) 450018cebfbSflorian imsg_event_add(iev); 451018cebfbSflorian else { 452018cebfbSflorian /* This pipe is dead. Remove its event handler */ 453018cebfbSflorian event_del(&iev->ev); 454018cebfbSflorian event_loopexit(NULL); 455018cebfbSflorian } 456018cebfbSflorian } 457018cebfbSflorian 458018cebfbSflorian void 459018cebfbSflorian main_dispatch_resolver(int fd, short event, void *bula) 460018cebfbSflorian { 461018cebfbSflorian struct imsgev *iev = bula; 462018cebfbSflorian struct imsgbuf *ibuf; 463018cebfbSflorian struct imsg imsg; 464018cebfbSflorian ssize_t n; 465018cebfbSflorian int shut = 0; 466018cebfbSflorian 467018cebfbSflorian ibuf = &iev->ibuf; 468018cebfbSflorian 469018cebfbSflorian if (event & EV_READ) { 470668e5ba9Sclaudio if ((n = imsgbuf_read(ibuf)) == -1) 471dd7efffeSclaudio fatal("imsgbuf_read error"); 472018cebfbSflorian if (n == 0) /* Connection closed. */ 473018cebfbSflorian shut = 1; 474018cebfbSflorian } 475018cebfbSflorian if (event & EV_WRITE) { 476dd7efffeSclaudio if (imsgbuf_write(ibuf) == -1) { 477e3b6409cSclaudio if (errno == EPIPE) /* Connection closed. */ 478018cebfbSflorian shut = 1; 479e3b6409cSclaudio else 480dd7efffeSclaudio fatal("imsgbuf_write"); 481e3b6409cSclaudio } 482018cebfbSflorian } 483018cebfbSflorian 484018cebfbSflorian for (;;) { 485018cebfbSflorian if ((n = imsg_get(ibuf, &imsg)) == -1) 486018cebfbSflorian fatal("imsg_get"); 487018cebfbSflorian if (n == 0) /* No more messages. */ 488018cebfbSflorian break; 489018cebfbSflorian 490018cebfbSflorian switch (imsg.hdr.type) { 491018cebfbSflorian default: 492018cebfbSflorian log_debug("%s: error handling imsg %d", __func__, 493018cebfbSflorian imsg.hdr.type); 494018cebfbSflorian break; 495018cebfbSflorian } 496018cebfbSflorian imsg_free(&imsg); 497018cebfbSflorian } 498018cebfbSflorian if (!shut) 499018cebfbSflorian imsg_event_add(iev); 500018cebfbSflorian else { 501018cebfbSflorian /* This pipe is dead. Remove its event handler. */ 502018cebfbSflorian event_del(&iev->ev); 503018cebfbSflorian event_loopexit(NULL); 504018cebfbSflorian } 505018cebfbSflorian } 506018cebfbSflorian 507018cebfbSflorian void 508018cebfbSflorian main_imsg_compose_frontend(int type, pid_t pid, void *data, uint16_t datalen) 509018cebfbSflorian { 510018cebfbSflorian if (iev_frontend) 511018cebfbSflorian imsg_compose_event(iev_frontend, type, 0, pid, -1, data, 512018cebfbSflorian datalen); 513018cebfbSflorian } 514018cebfbSflorian 515018cebfbSflorian void 516018cebfbSflorian main_imsg_compose_frontend_fd(int type, pid_t pid, int fd) 517018cebfbSflorian { 518018cebfbSflorian if (iev_frontend) 519018cebfbSflorian imsg_compose_event(iev_frontend, type, 0, pid, fd, NULL, 0); 520018cebfbSflorian } 521018cebfbSflorian 522018cebfbSflorian void 523018cebfbSflorian main_imsg_compose_resolver(int type, pid_t pid, void *data, uint16_t datalen) 524018cebfbSflorian { 525018cebfbSflorian if (iev_resolver) 526018cebfbSflorian imsg_compose_event(iev_resolver, type, 0, pid, -1, data, 527018cebfbSflorian datalen); 528018cebfbSflorian } 529018cebfbSflorian 530018cebfbSflorian void 531018cebfbSflorian imsg_event_add(struct imsgev *iev) 532018cebfbSflorian { 533018cebfbSflorian iev->events = EV_READ; 53431be28caSclaudio if (imsgbuf_queuelen(&iev->ibuf) > 0) 535018cebfbSflorian iev->events |= EV_WRITE; 536018cebfbSflorian 537018cebfbSflorian event_del(&iev->ev); 538018cebfbSflorian event_set(&iev->ev, iev->ibuf.fd, iev->events, iev->handler, iev); 539018cebfbSflorian event_add(&iev->ev, NULL); 540018cebfbSflorian } 541018cebfbSflorian 542018cebfbSflorian int 543018cebfbSflorian imsg_compose_event(struct imsgev *iev, uint16_t type, uint32_t peerid, 544018cebfbSflorian pid_t pid, int fd, void *data, uint16_t datalen) 545018cebfbSflorian { 546018cebfbSflorian int ret; 547018cebfbSflorian 548018cebfbSflorian if ((ret = imsg_compose(&iev->ibuf, type, peerid, pid, fd, data, 549018cebfbSflorian datalen)) != -1) 550018cebfbSflorian imsg_event_add(iev); 551018cebfbSflorian 552018cebfbSflorian return (ret); 553018cebfbSflorian } 554018cebfbSflorian 555018cebfbSflorian static int 556018cebfbSflorian main_imsg_send_ipc_sockets(struct imsgbuf *frontend_buf, 557f3ea9bf1Sflorian struct imsgbuf *resolver_buf) 558018cebfbSflorian { 559018cebfbSflorian int pipe_frontend2resolver[2]; 560018cebfbSflorian 561018cebfbSflorian if (socketpair(AF_UNIX, SOCK_STREAM | SOCK_CLOEXEC | SOCK_NONBLOCK, 562018cebfbSflorian PF_UNSPEC, pipe_frontend2resolver) == -1) 563018cebfbSflorian return (-1); 564018cebfbSflorian 565b2501eadSflorian if (imsg_compose(frontend_buf, IMSG_SOCKET_IPC_RESOLVER, 0, 0, 566018cebfbSflorian pipe_frontend2resolver[0], NULL, 0) == -1) 567018cebfbSflorian return (-1); 568b2501eadSflorian if (imsg_compose(resolver_buf, IMSG_SOCKET_IPC_FRONTEND, 0, 0, 569018cebfbSflorian pipe_frontend2resolver[1], NULL, 0) == -1) 570018cebfbSflorian return (-1); 571018cebfbSflorian 572018cebfbSflorian return (0); 573018cebfbSflorian } 574018cebfbSflorian 575018cebfbSflorian int 576018cebfbSflorian main_reload(void) 577018cebfbSflorian { 578bb81f7e1Sflorian struct uw_conf *xconf; 579018cebfbSflorian 580572e5ac0Skn if ((xconf = parse_config(conffile)) == NULL) 581018cebfbSflorian return (-1); 582018cebfbSflorian 583018cebfbSflorian if (main_imsg_send_config(xconf) == -1) 584018cebfbSflorian return (-1); 585018cebfbSflorian 586018cebfbSflorian merge_config(main_conf, xconf); 587018cebfbSflorian 5882d988276Sflorian if (main_conf->blocklist_file != NULL) 5892d988276Sflorian send_blocklist_fd(); 5902d988276Sflorian 591018cebfbSflorian return (0); 592018cebfbSflorian } 593018cebfbSflorian 594018cebfbSflorian int 595bb81f7e1Sflorian main_imsg_send_config(struct uw_conf *xconf) 596018cebfbSflorian { 597bb81f7e1Sflorian struct uw_forwarder *uw_forwarder; 598dd16127bSotto struct force_tree_entry *force_entry; 599018cebfbSflorian 600018cebfbSflorian /* Send fixed part of config to children. */ 601b2501eadSflorian if (main_sendall(IMSG_RECONF_CONF, xconf, sizeof(*xconf)) == -1) 602018cebfbSflorian return (-1); 603018cebfbSflorian 6042d988276Sflorian if (xconf->blocklist_file != NULL) { 6052d988276Sflorian if (main_sendall(IMSG_RECONF_BLOCKLIST_FILE, 6062d988276Sflorian xconf->blocklist_file, strlen(xconf->blocklist_file) + 1) 6072d988276Sflorian == -1) 6082d988276Sflorian return (-1); 6092d988276Sflorian } 6102d988276Sflorian 6113570995aSflorian /* send static forwarders to children */ 6127d055805Sflorian TAILQ_FOREACH(uw_forwarder, &xconf->uw_forwarder_list, entry) { 613bb81f7e1Sflorian if (main_sendall(IMSG_RECONF_FORWARDER, uw_forwarder, 614bb81f7e1Sflorian sizeof(*uw_forwarder)) == -1) 615018cebfbSflorian return (-1); 616018cebfbSflorian } 617018cebfbSflorian 6183570995aSflorian /* send static DoT forwarders to children */ 6197d055805Sflorian TAILQ_FOREACH(uw_forwarder, &xconf->uw_dot_forwarder_list, 6203570995aSflorian entry) { 621bb81f7e1Sflorian if (main_sendall(IMSG_RECONF_DOT_FORWARDER, uw_forwarder, 622bb81f7e1Sflorian sizeof(*uw_forwarder)) == -1) 6233570995aSflorian return (-1); 6243570995aSflorian } 625dd16127bSotto RB_FOREACH(force_entry, force_tree, &xconf->force) { 626dd16127bSotto if (main_sendall(IMSG_RECONF_FORCE, force_entry, 627dd16127bSotto sizeof(*force_entry)) == -1) 628dd16127bSotto return (-1); 629dd16127bSotto } 6303570995aSflorian 631018cebfbSflorian /* Tell children the revised config is now complete. */ 632b2501eadSflorian if (main_sendall(IMSG_RECONF_END, NULL, 0) == -1) 633018cebfbSflorian return (-1); 634018cebfbSflorian 635018cebfbSflorian return (0); 636018cebfbSflorian } 637018cebfbSflorian 638018cebfbSflorian int 639b2501eadSflorian main_sendall(enum imsg_type type, void *buf, uint16_t len) 640018cebfbSflorian { 641018cebfbSflorian if (imsg_compose_event(iev_frontend, type, 0, 0, -1, buf, len) == -1) 642018cebfbSflorian return (-1); 643018cebfbSflorian if (imsg_compose_event(iev_resolver, type, 0, 0, -1, buf, len) == -1) 644018cebfbSflorian return (-1); 645018cebfbSflorian return (0); 646018cebfbSflorian } 647018cebfbSflorian 648018cebfbSflorian void 649bb81f7e1Sflorian merge_config(struct uw_conf *conf, struct uw_conf *xconf) 650018cebfbSflorian { 651bb81f7e1Sflorian struct uw_forwarder *uw_forwarder; 652dd16127bSotto struct force_tree_entry *n, *nxt; 653018cebfbSflorian 654018cebfbSflorian /* Remove & discard existing forwarders. */ 6557d055805Sflorian while ((uw_forwarder = TAILQ_FIRST(&conf->uw_forwarder_list)) != 656bb81f7e1Sflorian NULL) { 6577d055805Sflorian TAILQ_REMOVE(&conf->uw_forwarder_list, uw_forwarder, entry); 658bb81f7e1Sflorian free(uw_forwarder); 659018cebfbSflorian } 6607d055805Sflorian while ((uw_forwarder = TAILQ_FIRST(&conf->uw_dot_forwarder_list)) != 661bb81f7e1Sflorian NULL) { 6627d055805Sflorian TAILQ_REMOVE(&conf->uw_dot_forwarder_list, uw_forwarder, entry); 663bb81f7e1Sflorian free(uw_forwarder); 6643570995aSflorian } 665018cebfbSflorian 666dd16127bSotto /* Remove & discard existing force tree. */ 6673bcff273Stb RB_FOREACH_SAFE(n, force_tree, &conf->force, nxt) { 668dd16127bSotto RB_REMOVE(force_tree, &conf->force, n); 669dd16127bSotto free(n); 670dd16127bSotto } 671dd16127bSotto 67211753c42Skn memcpy(&conf->enabled_resolvers, &xconf->enabled_resolvers, 67311753c42Skn sizeof(conf->enabled_resolvers)); 67411753c42Skn 675fd873f7fSflorian memcpy(&conf->res_pref, &xconf->res_pref, 676fd873f7fSflorian sizeof(conf->res_pref)); 677018cebfbSflorian 6782d988276Sflorian free(conf->blocklist_file); 6792d988276Sflorian conf->blocklist_file = xconf->blocklist_file; 680ac71ec8eSflorian conf->blocklist_log = xconf->blocklist_log; 6812d988276Sflorian 682018cebfbSflorian /* Add new forwarders. */ 6832feeeacaSflorian TAILQ_CONCAT(&conf->uw_forwarder_list, &xconf->uw_forwarder_list, 6847d055805Sflorian entry); 6852feeeacaSflorian TAILQ_CONCAT(&conf->uw_dot_forwarder_list, 6862feeeacaSflorian &xconf->uw_dot_forwarder_list, entry); 687018cebfbSflorian 6883bcff273Stb RB_FOREACH_SAFE(n, force_tree, &xconf->force, nxt) { 689dd16127bSotto RB_REMOVE(force_tree, &xconf->force, n); 690dd16127bSotto RB_INSERT(force_tree, &conf->force, n); 691dd16127bSotto } 692dd16127bSotto 693018cebfbSflorian free(xconf); 694018cebfbSflorian } 695018cebfbSflorian 696bb81f7e1Sflorian struct uw_conf * 697018cebfbSflorian config_new_empty(void) 698018cebfbSflorian { 699bb81f7e1Sflorian struct uw_conf *xconf; 700018cebfbSflorian 701018cebfbSflorian xconf = calloc(1, sizeof(*xconf)); 702018cebfbSflorian if (xconf == NULL) 703018cebfbSflorian fatal(NULL); 704018cebfbSflorian 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; 72915c83d0cSflorian int udp4sock = -1, udp6sock = -1, error, bsize = 65535; 730297af7e1Sflorian int tcp4sock = -1, tcp6sock = -1; 73115c8ad53Sjca int opt = 1; 732d265a5d3Sflorian 733d265a5d3Sflorian memset(&hints, 0, sizeof(hints)); 734d265a5d3Sflorian hints.ai_family = AF_INET; 735d265a5d3Sflorian hints.ai_socktype = SOCK_DGRAM; 736cc4fd5c4Stedu hints.ai_flags = AI_NUMERICHOST | AI_PASSIVE; 737d265a5d3Sflorian 738d265a5d3Sflorian error = getaddrinfo("127.0.0.1", "domain", &hints, &res0); 739d265a5d3Sflorian if (!error && res0) { 740d265a5d3Sflorian if ((udp4sock = socket(res0->ai_family, res0->ai_socktype, 741d265a5d3Sflorian res0->ai_protocol)) != -1) { 74215c8ad53Sjca if (setsockopt(udp4sock, SOL_SOCKET, SO_REUSEADDR, 74315c8ad53Sjca &opt, sizeof(opt)) == -1) 74415c8ad53Sjca log_warn("setting SO_REUSEADDR on socket"); 74515c83d0cSflorian if (setsockopt(udp4sock, SOL_SOCKET, SO_SNDBUF, &bsize, 74615c83d0cSflorian sizeof(bsize)) == -1) 74715c83d0cSflorian log_warn("setting SO_SNDBUF on socket"); 748d265a5d3Sflorian if (bind(udp4sock, res0->ai_addr, res0->ai_addrlen) 749d265a5d3Sflorian == -1) { 750d265a5d3Sflorian close(udp4sock); 751d265a5d3Sflorian udp4sock = -1; 752d265a5d3Sflorian } 753d265a5d3Sflorian } 754d265a5d3Sflorian } 755296cf316Sflorian if (res0) 756d265a5d3Sflorian freeaddrinfo(res0); 757d265a5d3Sflorian 758d265a5d3Sflorian hints.ai_family = AF_INET6; 759d265a5d3Sflorian error = getaddrinfo("::1", "domain", &hints, &res0); 760d265a5d3Sflorian if (!error && res0) { 761d265a5d3Sflorian if ((udp6sock = socket(res0->ai_family, res0->ai_socktype, 762d265a5d3Sflorian res0->ai_protocol)) != -1) { 76315c8ad53Sjca if (setsockopt(udp6sock, SOL_SOCKET, SO_REUSEADDR, 76415c8ad53Sjca &opt, sizeof(opt)) == -1) 76515c8ad53Sjca log_warn("setting SO_REUSEADDR on socket"); 76615c83d0cSflorian if (setsockopt(udp6sock, SOL_SOCKET, SO_SNDBUF, &bsize, 76715c83d0cSflorian sizeof(bsize)) == -1) 76815c83d0cSflorian log_warn("setting SO_SNDBUF on socket"); 769d265a5d3Sflorian if (bind(udp6sock, res0->ai_addr, res0->ai_addrlen) 770d265a5d3Sflorian == -1) { 771d265a5d3Sflorian close(udp6sock); 772d265a5d3Sflorian udp6sock = -1; 773d265a5d3Sflorian } 774d265a5d3Sflorian } 775d265a5d3Sflorian } 776296cf316Sflorian if (res0) 777d265a5d3Sflorian freeaddrinfo(res0); 778d265a5d3Sflorian 779297af7e1Sflorian hints.ai_family = AF_INET; 780297af7e1Sflorian hints.ai_socktype = SOCK_STREAM; 781297af7e1Sflorian 782297af7e1Sflorian error = getaddrinfo("127.0.0.1", "domain", &hints, &res0); 783297af7e1Sflorian if (!error && res0) { 784297af7e1Sflorian if ((tcp4sock = socket(res0->ai_family, 785297af7e1Sflorian res0->ai_socktype | SOCK_NONBLOCK, 786297af7e1Sflorian res0->ai_protocol)) != -1) { 787297af7e1Sflorian if (setsockopt(tcp4sock, SOL_SOCKET, SO_REUSEADDR, 788297af7e1Sflorian &opt, sizeof(opt)) == -1) 789297af7e1Sflorian log_warn("setting SO_REUSEADDR on socket"); 790297af7e1Sflorian if (setsockopt(tcp4sock, SOL_SOCKET, SO_SNDBUF, &bsize, 791297af7e1Sflorian sizeof(bsize)) == -1) 792297af7e1Sflorian log_warn("setting SO_SNDBUF on socket"); 793297af7e1Sflorian if (bind(tcp4sock, res0->ai_addr, res0->ai_addrlen) 794297af7e1Sflorian == -1) { 795297af7e1Sflorian close(tcp4sock); 796297af7e1Sflorian tcp4sock = -1; 797297af7e1Sflorian } 798297af7e1Sflorian if (listen(tcp4sock, 5) == -1) { 799297af7e1Sflorian close(tcp4sock); 800297af7e1Sflorian tcp4sock = -1; 801297af7e1Sflorian } 802297af7e1Sflorian } 803297af7e1Sflorian } 804297af7e1Sflorian if (res0) 805297af7e1Sflorian freeaddrinfo(res0); 806297af7e1Sflorian 807297af7e1Sflorian hints.ai_family = AF_INET6; 808297af7e1Sflorian error = getaddrinfo("::1", "domain", &hints, &res0); 809297af7e1Sflorian if (!error && res0) { 810297af7e1Sflorian if ((tcp6sock = socket(res0->ai_family, 811297af7e1Sflorian res0->ai_socktype | SOCK_NONBLOCK, 812297af7e1Sflorian res0->ai_protocol)) != -1) { 813297af7e1Sflorian if (setsockopt(tcp6sock, SOL_SOCKET, SO_REUSEADDR, 814297af7e1Sflorian &opt, sizeof(opt)) == -1) 815297af7e1Sflorian log_warn("setting SO_REUSEADDR on socket"); 816297af7e1Sflorian if (setsockopt(tcp6sock, SOL_SOCKET, SO_SNDBUF, &bsize, 817297af7e1Sflorian sizeof(bsize)) == -1) 818297af7e1Sflorian log_warn("setting SO_SNDBUF on socket"); 819297af7e1Sflorian if (bind(tcp6sock, res0->ai_addr, res0->ai_addrlen) 820297af7e1Sflorian == -1) { 821297af7e1Sflorian close(tcp6sock); 822297af7e1Sflorian tcp6sock = -1; 823297af7e1Sflorian } 824297af7e1Sflorian if (listen(tcp6sock, 5) == -1) { 825297af7e1Sflorian close(tcp6sock); 826297af7e1Sflorian tcp6sock = -1; 827297af7e1Sflorian } 828297af7e1Sflorian } 829297af7e1Sflorian } 830297af7e1Sflorian if (res0) 831297af7e1Sflorian freeaddrinfo(res0); 832297af7e1Sflorian 833297af7e1Sflorian if ((udp4sock == -1 || tcp4sock == -1) && (udp6sock == -1 || 834297af7e1Sflorian tcp6sock == -1)) 835afd6e24dSflorian fatalx("could not bind to 127.0.0.1 or ::1 on port 53"); 836d265a5d3Sflorian 837b04dd19dSflorian if (udp4sock != -1) 838d265a5d3Sflorian main_imsg_compose_frontend_fd(IMSG_UDP4SOCK, 0, udp4sock); 839b04dd19dSflorian if (udp6sock != -1) 840d265a5d3Sflorian main_imsg_compose_frontend_fd(IMSG_UDP6SOCK, 0, udp6sock); 841297af7e1Sflorian if (tcp4sock != -1) 842297af7e1Sflorian main_imsg_compose_frontend_fd(IMSG_TCP4SOCK, 0, tcp4sock); 843297af7e1Sflorian if (tcp6sock != -1) 844297af7e1Sflorian main_imsg_compose_frontend_fd(IMSG_TCP6SOCK, 0, tcp6sock); 845d265a5d3Sflorian } 8462f29e846Sflorian 8472f29e846Sflorian void 84828ba4729Sflorian solicit_dns_proposals(void) 84928ba4729Sflorian { 85028ba4729Sflorian struct rt_msghdr rtm; 85128ba4729Sflorian struct iovec iov[1]; 85228ba4729Sflorian int iovcnt = 0; 85328ba4729Sflorian 85428ba4729Sflorian memset(&rtm, 0, sizeof(rtm)); 85528ba4729Sflorian 85628ba4729Sflorian rtm.rtm_version = RTM_VERSION; 85728ba4729Sflorian rtm.rtm_type = RTM_PROPOSAL; 85828ba4729Sflorian rtm.rtm_msglen = sizeof(rtm); 85928ba4729Sflorian rtm.rtm_tableid = 0; 86028ba4729Sflorian rtm.rtm_index = 0; 86128ba4729Sflorian rtm.rtm_seq = arc4random(); 86228ba4729Sflorian rtm.rtm_priority = RTP_PROPOSAL_SOLICIT; 86328ba4729Sflorian 86428ba4729Sflorian iov[iovcnt].iov_base = &rtm; 86528ba4729Sflorian iov[iovcnt++].iov_len = sizeof(rtm); 86628ba4729Sflorian 86728ba4729Sflorian if (writev(routesock, iov, iovcnt) == -1) 86828ba4729Sflorian log_warn("failed to send solicitation"); 86928ba4729Sflorian } 87028ba4729Sflorian 87128ba4729Sflorian void 8722d988276Sflorian send_blocklist_fd(void) 8732d988276Sflorian { 8742d988276Sflorian int bl_fd; 8752d988276Sflorian 8762d988276Sflorian if ((bl_fd = open(main_conf->blocklist_file, O_RDONLY)) != -1) 8772d988276Sflorian main_imsg_compose_frontend_fd(IMSG_BLFD, 0, bl_fd); 8782d988276Sflorian else 8792d988276Sflorian log_warn("%s", main_conf->blocklist_file); 8802d988276Sflorian } 881679647feSflorian 882679647feSflorian void 883679647feSflorian imsg_receive_config(struct imsg *imsg, struct uw_conf **xconf) 884679647feSflorian { 885679647feSflorian struct uw_conf *nconf; 886679647feSflorian struct uw_forwarder *uw_forwarder; 887dd16127bSotto struct force_tree_entry *force_entry; 888679647feSflorian 889679647feSflorian nconf = *xconf; 890679647feSflorian 891679647feSflorian switch (imsg->hdr.type) { 892679647feSflorian case IMSG_RECONF_CONF: 893679647feSflorian if (nconf != NULL) 894679647feSflorian fatalx("%s: IMSG_RECONF_CONF already in " 895679647feSflorian "progress", __func__); 896679647feSflorian if (IMSG_DATA_SIZE(*imsg) != sizeof(struct uw_conf)) 897679647feSflorian fatalx("%s: IMSG_RECONF_CONF wrong length: %lu", 898679647feSflorian __func__, IMSG_DATA_SIZE(*imsg)); 899679647feSflorian if ((*xconf = malloc(sizeof(struct uw_conf))) == NULL) 900679647feSflorian fatal(NULL); 901679647feSflorian nconf = *xconf; 902679647feSflorian memcpy(nconf, imsg->data, sizeof(struct uw_conf)); 9037d055805Sflorian TAILQ_INIT(&nconf->uw_forwarder_list); 9047d055805Sflorian TAILQ_INIT(&nconf->uw_dot_forwarder_list); 905dd16127bSotto RB_INIT(&nconf->force); 906679647feSflorian break; 907679647feSflorian case IMSG_RECONF_BLOCKLIST_FILE: 908159ce6f4Sflorian if (((char *)imsg->data)[IMSG_DATA_SIZE(*imsg) - 1] != '\0') 909159ce6f4Sflorian fatalx("Invalid blocklist file"); 910679647feSflorian if ((nconf->blocklist_file = strdup(imsg->data)) == 911679647feSflorian NULL) 912679647feSflorian fatal("%s: strdup", __func__); 913679647feSflorian break; 914679647feSflorian case IMSG_RECONF_FORWARDER: 915679647feSflorian if (IMSG_DATA_SIZE(*imsg) != sizeof(struct uw_forwarder)) 916679647feSflorian fatalx("%s: IMSG_RECONF_FORWARDER wrong length:" 917679647feSflorian " %lu", __func__, IMSG_DATA_SIZE(*imsg)); 918679647feSflorian if ((uw_forwarder = malloc(sizeof(struct 919679647feSflorian uw_forwarder))) == NULL) 920679647feSflorian fatal(NULL); 921679647feSflorian memcpy(uw_forwarder, imsg->data, sizeof(struct 922679647feSflorian uw_forwarder)); 9237d055805Sflorian TAILQ_INSERT_TAIL(&nconf->uw_forwarder_list, 924679647feSflorian uw_forwarder, entry); 925679647feSflorian break; 926679647feSflorian case IMSG_RECONF_DOT_FORWARDER: 927679647feSflorian if (IMSG_DATA_SIZE(*imsg) != sizeof(struct uw_forwarder)) 928679647feSflorian fatalx("%s: IMSG_RECONF_DOT_FORWARDER wrong " 929679647feSflorian "length: %lu", __func__, 930679647feSflorian IMSG_DATA_SIZE(*imsg)); 931679647feSflorian if ((uw_forwarder = malloc(sizeof(struct 932679647feSflorian uw_forwarder))) == NULL) 933679647feSflorian fatal(NULL); 934679647feSflorian memcpy(uw_forwarder, imsg->data, sizeof(struct 935679647feSflorian uw_forwarder)); 9367d055805Sflorian TAILQ_INSERT_TAIL(&nconf->uw_dot_forwarder_list, 937679647feSflorian uw_forwarder, entry); 938679647feSflorian break; 939dd16127bSotto case IMSG_RECONF_FORCE: 940dd16127bSotto if (IMSG_DATA_SIZE(*imsg) != sizeof(struct force_tree_entry)) 941dd16127bSotto fatalx("%s: IMSG_RECONF_FORCE wrong " 942dd16127bSotto "length: %lu", __func__, 943dd16127bSotto IMSG_DATA_SIZE(*imsg)); 944dd16127bSotto if ((force_entry = malloc(sizeof(struct 945dd16127bSotto force_tree_entry))) == NULL) 946dd16127bSotto fatal(NULL); 947dd16127bSotto memcpy(force_entry, imsg->data, sizeof(struct 948dd16127bSotto force_tree_entry)); 949dbebd753Stb if (RB_INSERT(force_tree, &nconf->force, force_entry) != NULL) { 950dbebd753Stb free(force_entry); 951dbebd753Stb fatalx("%s: IMSG_RECONF_FORCE duplicate entry", 952dbebd753Stb __func__); 953dbebd753Stb } 954dd16127bSotto break; 955679647feSflorian default: 956679647feSflorian log_debug("%s: error handling imsg %d", __func__, 957679647feSflorian imsg->hdr.type); 958679647feSflorian break; 959679647feSflorian } 960679647feSflorian } 961