1*572e5ac0Skn /* $OpenBSD: unwind.c,v 1.39 2019/11/26 19:35:13 kn 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" 50b2501eadSflorian #include "captiveportal.h" 51018cebfbSflorian 5290d56d5fSflorian #define TRUST_ANCHOR_FILE "/var/db/unwind.key" 53296cf316Sflorian 54018cebfbSflorian __dead void usage(void); 55018cebfbSflorian __dead void main_shutdown(void); 56018cebfbSflorian 57018cebfbSflorian void main_sig_handler(int, short, void *); 58018cebfbSflorian 59018cebfbSflorian static pid_t start_child(int, char *, int, int, int); 60018cebfbSflorian 61018cebfbSflorian void main_dispatch_frontend(int, short, void *); 62018cebfbSflorian void main_dispatch_resolver(int, short, void *); 63b2501eadSflorian void main_dispatch_captiveportal(int, short, void *); 64018cebfbSflorian 65b2501eadSflorian static int main_imsg_send_ipc_sockets(struct imsgbuf *, struct imsgbuf *, 66b2501eadSflorian struct imsgbuf *); 67bb81f7e1Sflorian static int main_imsg_send_config(struct uw_conf *); 68018cebfbSflorian 69018cebfbSflorian int main_reload(void); 70b2501eadSflorian int main_sendall(enum imsg_type, void *, uint16_t); 71d265a5d3Sflorian void open_ports(void); 7228ba4729Sflorian void solicit_dns_proposals(void); 73cfffd8c7Sflorian void connect_captive_portal_host(struct in_addr *); 742d988276Sflorian void send_blocklist_fd(void); 75018cebfbSflorian 76bb81f7e1Sflorian struct uw_conf *main_conf; 77018cebfbSflorian struct imsgev *iev_frontend; 78018cebfbSflorian struct imsgev *iev_resolver; 79b2501eadSflorian struct imsgev *iev_captiveportal; 80*572e5ac0Skn char *conffile; 81018cebfbSflorian 82018cebfbSflorian pid_t frontend_pid; 83018cebfbSflorian pid_t resolver_pid; 84b2501eadSflorian pid_t captiveportal_pid; 85018cebfbSflorian 86018cebfbSflorian uint32_t cmd_opts; 87018cebfbSflorian 8828ba4729Sflorian int routesock; 8928ba4729Sflorian 90018cebfbSflorian void 91018cebfbSflorian main_sig_handler(int sig, short event, void *arg) 92018cebfbSflorian { 93018cebfbSflorian /* 94018cebfbSflorian * Normal signal handler rules don't apply because libevent 95018cebfbSflorian * decouples for us. 96018cebfbSflorian */ 97018cebfbSflorian 98018cebfbSflorian switch (sig) { 99018cebfbSflorian case SIGTERM: 100018cebfbSflorian case SIGINT: 1015472663aSflorian main_shutdown(); 102018cebfbSflorian break; 103018cebfbSflorian case SIGHUP: 104018cebfbSflorian if (main_reload() == -1) 105018cebfbSflorian log_warnx("configuration reload failed"); 106018cebfbSflorian else 107018cebfbSflorian log_debug("configuration reloaded"); 108018cebfbSflorian break; 109018cebfbSflorian default: 110018cebfbSflorian fatalx("unexpected signal"); 111018cebfbSflorian } 112018cebfbSflorian } 113018cebfbSflorian 114018cebfbSflorian __dead void 115018cebfbSflorian usage(void) 116018cebfbSflorian { 117018cebfbSflorian extern char *__progname; 118018cebfbSflorian 119018cebfbSflorian fprintf(stderr, "usage: %s [-dnv] [-f file] [-s socket]\n", 120018cebfbSflorian __progname); 121018cebfbSflorian exit(1); 122018cebfbSflorian } 123018cebfbSflorian 124018cebfbSflorian int 125018cebfbSflorian main(int argc, char *argv[]) 126018cebfbSflorian { 127018cebfbSflorian struct event ev_sigint, ev_sigterm, ev_sighup; 128bb81f7e1Sflorian int ch, debug = 0, resolver_flag = 0, frontend_flag = 0; 129bb81f7e1Sflorian int captiveportal_flag = 0, frontend_routesock, rtfilter; 130bb81f7e1Sflorian int pipe_main2frontend[2], pipe_main2resolver[2]; 131b2501eadSflorian int pipe_main2captiveportal[2]; 132d1b04a40Sflorian int control_fd, ta_fd; 133bb81f7e1Sflorian char *csock, *saved_argv0; 134018cebfbSflorian 135018cebfbSflorian csock = UNWIND_SOCKET; 136018cebfbSflorian 137018cebfbSflorian log_init(1, LOG_DAEMON); /* Log to stderr until daemonized. */ 138018cebfbSflorian log_setverbose(1); 139018cebfbSflorian 140018cebfbSflorian saved_argv0 = argv[0]; 141018cebfbSflorian if (saved_argv0 == NULL) 142018cebfbSflorian saved_argv0 = "unwind"; 143018cebfbSflorian 144b2501eadSflorian while ((ch = getopt(argc, argv, "CdEFf:ns:v")) != -1) { 145018cebfbSflorian switch (ch) { 146b2501eadSflorian case 'C': 147b2501eadSflorian captiveportal_flag = 1; 148b2501eadSflorian break; 149018cebfbSflorian case 'd': 150018cebfbSflorian debug = 1; 151018cebfbSflorian break; 152018cebfbSflorian case 'E': 153018cebfbSflorian resolver_flag = 1; 154018cebfbSflorian break; 155018cebfbSflorian case 'F': 156018cebfbSflorian frontend_flag = 1; 157018cebfbSflorian break; 158018cebfbSflorian case 'f': 159018cebfbSflorian conffile = optarg; 160018cebfbSflorian break; 161018cebfbSflorian case 'n': 162018cebfbSflorian cmd_opts |= OPT_NOACTION; 163018cebfbSflorian break; 164018cebfbSflorian case 's': 165018cebfbSflorian csock = optarg; 166018cebfbSflorian break; 167018cebfbSflorian case 'v': 168018cebfbSflorian if (cmd_opts & OPT_VERBOSE) 169018cebfbSflorian cmd_opts |= OPT_VERBOSE2; 170018cebfbSflorian cmd_opts |= OPT_VERBOSE; 171018cebfbSflorian break; 172018cebfbSflorian default: 173018cebfbSflorian usage(); 174018cebfbSflorian } 175018cebfbSflorian } 176018cebfbSflorian 177018cebfbSflorian argc -= optind; 178018cebfbSflorian argv += optind; 179b2501eadSflorian if (argc > 0 || (resolver_flag && frontend_flag && captiveportal_flag)) 180018cebfbSflorian usage(); 181018cebfbSflorian 182018cebfbSflorian if (resolver_flag) 183018cebfbSflorian resolver(debug, cmd_opts & (OPT_VERBOSE | OPT_VERBOSE2)); 184018cebfbSflorian else if (frontend_flag) 185018cebfbSflorian frontend(debug, cmd_opts & (OPT_VERBOSE | OPT_VERBOSE2)); 186b2501eadSflorian else if (captiveportal_flag) 187b2501eadSflorian captiveportal(debug, cmd_opts & (OPT_VERBOSE | OPT_VERBOSE2)); 188018cebfbSflorian 189*572e5ac0Skn if ((main_conf = parse_config(conffile)) == NULL) 190018cebfbSflorian exit(1); 191018cebfbSflorian 192018cebfbSflorian if (cmd_opts & OPT_NOACTION) { 193018cebfbSflorian if (cmd_opts & OPT_VERBOSE) 194018cebfbSflorian print_config(main_conf); 195018cebfbSflorian else 196018cebfbSflorian fprintf(stderr, "configuration OK\n"); 197018cebfbSflorian exit(0); 198018cebfbSflorian } 199018cebfbSflorian 200018cebfbSflorian /* Check for root privileges. */ 201018cebfbSflorian if (geteuid()) 202018cebfbSflorian errx(1, "need root privileges"); 203018cebfbSflorian 204018cebfbSflorian /* Check for assigned daemon user */ 205018cebfbSflorian if (getpwnam(UNWIND_USER) == NULL) 206018cebfbSflorian errx(1, "unknown user %s", UNWIND_USER); 207018cebfbSflorian 208018cebfbSflorian log_init(debug, LOG_DAEMON); 209018cebfbSflorian log_setverbose(cmd_opts & OPT_VERBOSE); 210018cebfbSflorian 211018cebfbSflorian if (!debug) 212018cebfbSflorian daemon(1, 0); 213018cebfbSflorian 214018cebfbSflorian log_info("startup"); 215018cebfbSflorian 216018cebfbSflorian if (socketpair(AF_UNIX, SOCK_STREAM | SOCK_CLOEXEC | SOCK_NONBLOCK, 217018cebfbSflorian PF_UNSPEC, pipe_main2frontend) == -1) 218018cebfbSflorian fatal("main2frontend socketpair"); 219018cebfbSflorian if (socketpair(AF_UNIX, SOCK_STREAM | SOCK_CLOEXEC | SOCK_NONBLOCK, 220018cebfbSflorian PF_UNSPEC, pipe_main2resolver) == -1) 221018cebfbSflorian fatal("main2resolver socketpair"); 222b2501eadSflorian if (socketpair(AF_UNIX, SOCK_STREAM | SOCK_CLOEXEC | SOCK_NONBLOCK, 223b2501eadSflorian PF_UNSPEC, pipe_main2captiveportal) == -1) 224b2501eadSflorian fatal("main2captiveportal socketpair"); 225018cebfbSflorian 226018cebfbSflorian /* Start children. */ 227018cebfbSflorian resolver_pid = start_child(PROC_RESOLVER, saved_argv0, 228018cebfbSflorian pipe_main2resolver[1], debug, cmd_opts & (OPT_VERBOSE | 229018cebfbSflorian OPT_VERBOSE2)); 230018cebfbSflorian frontend_pid = start_child(PROC_FRONTEND, saved_argv0, 231018cebfbSflorian pipe_main2frontend[1], debug, cmd_opts & (OPT_VERBOSE | 232018cebfbSflorian OPT_VERBOSE2)); 233b2501eadSflorian captiveportal_pid = start_child(PROC_CAPTIVEPORTAL, saved_argv0, 234b2501eadSflorian pipe_main2captiveportal[1], debug, cmd_opts & (OPT_VERBOSE | 235b2501eadSflorian OPT_VERBOSE2)); 236018cebfbSflorian 237bb81f7e1Sflorian uw_process = PROC_MAIN; 238bb81f7e1Sflorian log_procinit(log_procnames[uw_process]); 239018cebfbSflorian 240018cebfbSflorian event_init(); 241018cebfbSflorian 242018cebfbSflorian /* Setup signal handler. */ 243018cebfbSflorian signal_set(&ev_sigint, SIGINT, main_sig_handler, NULL); 244018cebfbSflorian signal_set(&ev_sigterm, SIGTERM, main_sig_handler, NULL); 245018cebfbSflorian signal_set(&ev_sighup, SIGHUP, main_sig_handler, NULL); 246018cebfbSflorian signal_add(&ev_sigint, NULL); 247018cebfbSflorian signal_add(&ev_sigterm, NULL); 248018cebfbSflorian signal_add(&ev_sighup, NULL); 249018cebfbSflorian signal(SIGPIPE, SIG_IGN); 250018cebfbSflorian 251018cebfbSflorian /* Setup pipes to children. */ 252018cebfbSflorian 253018cebfbSflorian if ((iev_frontend = malloc(sizeof(struct imsgev))) == NULL || 254b2501eadSflorian (iev_captiveportal = malloc(sizeof(struct imsgev))) == NULL || 255018cebfbSflorian (iev_resolver = malloc(sizeof(struct imsgev))) == NULL) 256018cebfbSflorian fatal(NULL); 257018cebfbSflorian imsg_init(&iev_frontend->ibuf, pipe_main2frontend[0]); 258018cebfbSflorian iev_frontend->handler = main_dispatch_frontend; 259018cebfbSflorian imsg_init(&iev_resolver->ibuf, pipe_main2resolver[0]); 260018cebfbSflorian iev_resolver->handler = main_dispatch_resolver; 261b2501eadSflorian imsg_init(&iev_captiveportal->ibuf, pipe_main2captiveportal[0]); 262b2501eadSflorian iev_captiveportal->handler = main_dispatch_captiveportal; 263018cebfbSflorian 264b2501eadSflorian /* Setup event handlers for pipes. */ 265018cebfbSflorian iev_frontend->events = EV_READ; 266018cebfbSflorian event_set(&iev_frontend->ev, iev_frontend->ibuf.fd, 267018cebfbSflorian iev_frontend->events, iev_frontend->handler, iev_frontend); 268018cebfbSflorian event_add(&iev_frontend->ev, NULL); 269018cebfbSflorian 270018cebfbSflorian iev_resolver->events = EV_READ; 271bb81f7e1Sflorian event_set(&iev_resolver->ev, iev_resolver->ibuf.fd, 272bb81f7e1Sflorian iev_resolver->events, iev_resolver->handler, iev_resolver); 273018cebfbSflorian event_add(&iev_resolver->ev, NULL); 274018cebfbSflorian 275b2501eadSflorian iev_captiveportal->events = EV_READ; 276b2501eadSflorian event_set(&iev_captiveportal->ev, iev_captiveportal->ibuf.fd, 277b2501eadSflorian iev_captiveportal->events, iev_captiveportal->handler, 278b2501eadSflorian iev_captiveportal); 279b2501eadSflorian event_add(&iev_captiveportal->ev, NULL); 280b2501eadSflorian 281b2501eadSflorian if (main_imsg_send_ipc_sockets(&iev_frontend->ibuf, 282b2501eadSflorian &iev_resolver->ibuf, &iev_captiveportal->ibuf)) 283018cebfbSflorian fatal("could not establish imsg links"); 284018cebfbSflorian 285018cebfbSflorian if ((control_fd = control_init(csock)) == -1) 286018cebfbSflorian fatalx("control socket setup failed"); 287018cebfbSflorian 2889e627e00Sflorian if ((frontend_routesock = socket(AF_ROUTE, SOCK_RAW | SOCK_CLOEXEC, 289df69c215Sderaadt AF_INET)) == -1) 290018cebfbSflorian fatal("route socket"); 291018cebfbSflorian 2922956dd86Sflorian rtfilter = ROUTE_FILTER(RTM_IFINFO) | ROUTE_FILTER(RTM_PROPOSAL); 2939e627e00Sflorian if (setsockopt(frontend_routesock, AF_ROUTE, ROUTE_MSGFILTER, 294df69c215Sderaadt &rtfilter, sizeof(rtfilter)) == -1) 295018cebfbSflorian fatal("setsockopt(ROUTE_MSGFILTER)"); 296018cebfbSflorian 29728ba4729Sflorian if ((routesock = socket(AF_ROUTE, SOCK_RAW | SOCK_CLOEXEC | 29828ba4729Sflorian SOCK_NONBLOCK, AF_INET6)) == -1) 29928ba4729Sflorian fatal("route socket"); 30028ba4729Sflorian shutdown(SHUT_RD, routesock); 30128ba4729Sflorian 302d1b04a40Sflorian if ((ta_fd = open(TRUST_ANCHOR_FILE, O_RDWR | O_CREAT, 0644)) == -1) 303d1b04a40Sflorian log_warn("%s", TRUST_ANCHOR_FILE); 304d1b04a40Sflorian 305d1b04a40Sflorian /* receiver handles failed open correctly */ 306d1b04a40Sflorian main_imsg_compose_frontend_fd(IMSG_TAFD, 0, ta_fd); 307d1b04a40Sflorian 308018cebfbSflorian main_imsg_compose_frontend_fd(IMSG_CONTROLFD, 0, control_fd); 309018cebfbSflorian main_imsg_compose_frontend_fd(IMSG_ROUTESOCK, 0, frontend_routesock); 310018cebfbSflorian main_imsg_send_config(main_conf); 311018cebfbSflorian 3122d988276Sflorian if (main_conf->blocklist_file != NULL) 3132d988276Sflorian send_blocklist_fd(); 3142d988276Sflorian 315cfffd8c7Sflorian if (pledge("stdio inet rpath sendfd", NULL) == -1) 316018cebfbSflorian fatal("pledge"); 317018cebfbSflorian 318018cebfbSflorian main_imsg_compose_frontend(IMSG_STARTUP, 0, NULL, 0); 319296cf316Sflorian main_imsg_compose_resolver(IMSG_STARTUP, 0, NULL, 0); 320018cebfbSflorian 321018cebfbSflorian event_dispatch(); 322018cebfbSflorian 323018cebfbSflorian main_shutdown(); 324018cebfbSflorian return (0); 325018cebfbSflorian } 326018cebfbSflorian 327018cebfbSflorian __dead void 328018cebfbSflorian main_shutdown(void) 329018cebfbSflorian { 330018cebfbSflorian pid_t pid; 331018cebfbSflorian int status; 332018cebfbSflorian 333018cebfbSflorian /* Close pipes. */ 334018cebfbSflorian msgbuf_clear(&iev_frontend->ibuf.w); 335018cebfbSflorian close(iev_frontend->ibuf.fd); 336018cebfbSflorian msgbuf_clear(&iev_resolver->ibuf.w); 337018cebfbSflorian close(iev_resolver->ibuf.fd); 338b2501eadSflorian msgbuf_clear(&iev_captiveportal->ibuf.w); 339b2501eadSflorian close(iev_captiveportal->ibuf.fd); 340018cebfbSflorian 341018cebfbSflorian config_clear(main_conf); 342018cebfbSflorian 343018cebfbSflorian log_debug("waiting for children to terminate"); 344018cebfbSflorian do { 345018cebfbSflorian pid = wait(&status); 346018cebfbSflorian if (pid == -1) { 347018cebfbSflorian if (errno != EINTR && errno != ECHILD) 348018cebfbSflorian fatal("wait"); 349018cebfbSflorian } else if (WIFSIGNALED(status)) 350018cebfbSflorian log_warnx("%s terminated; signal %d", 351018cebfbSflorian (pid == resolver_pid) ? "resolver" : 352018cebfbSflorian "frontend", WTERMSIG(status)); 353018cebfbSflorian } while (pid != -1 || (pid == -1 && errno == EINTR)); 354018cebfbSflorian 355018cebfbSflorian free(iev_frontend); 356018cebfbSflorian free(iev_resolver); 357b2501eadSflorian free(iev_captiveportal); 358018cebfbSflorian 359018cebfbSflorian log_info("terminating"); 360018cebfbSflorian exit(0); 361018cebfbSflorian } 362018cebfbSflorian 363018cebfbSflorian static pid_t 364018cebfbSflorian start_child(int p, char *argv0, int fd, int debug, int verbose) 365018cebfbSflorian { 366018cebfbSflorian char *argv[7]; 367018cebfbSflorian int argc = 0; 368018cebfbSflorian pid_t pid; 369018cebfbSflorian 370018cebfbSflorian switch (pid = fork()) { 371018cebfbSflorian case -1: 372018cebfbSflorian fatal("cannot fork"); 373018cebfbSflorian case 0: 374018cebfbSflorian break; 375018cebfbSflorian default: 376018cebfbSflorian close(fd); 377018cebfbSflorian return (pid); 378018cebfbSflorian } 379018cebfbSflorian 380ef4f5895Syasuoka if (fd != 3) { 381018cebfbSflorian if (dup2(fd, 3) == -1) 382018cebfbSflorian fatal("cannot setup imsg fd"); 383ef4f5895Syasuoka } else if (fcntl(fd, F_SETFD, 0) == -1) 384ef4f5895Syasuoka fatal("cannot setup imsg fd"); 385018cebfbSflorian 386018cebfbSflorian argv[argc++] = argv0; 387018cebfbSflorian switch (p) { 388018cebfbSflorian case PROC_MAIN: 389018cebfbSflorian fatalx("Can not start main process"); 390018cebfbSflorian case PROC_RESOLVER: 391018cebfbSflorian argv[argc++] = "-E"; 392018cebfbSflorian break; 393018cebfbSflorian case PROC_FRONTEND: 394018cebfbSflorian argv[argc++] = "-F"; 395018cebfbSflorian break; 396b2501eadSflorian case PROC_CAPTIVEPORTAL: 397b2501eadSflorian argv[argc++] = "-C"; 398b2501eadSflorian break; 399018cebfbSflorian } 400018cebfbSflorian if (debug) 401018cebfbSflorian argv[argc++] = "-d"; 402018cebfbSflorian if (verbose & OPT_VERBOSE) 403018cebfbSflorian argv[argc++] = "-v"; 404018cebfbSflorian if (verbose & OPT_VERBOSE2) 405018cebfbSflorian argv[argc++] = "-v"; 406018cebfbSflorian argv[argc++] = NULL; 407018cebfbSflorian 408018cebfbSflorian execvp(argv0, argv); 409018cebfbSflorian fatal("execvp"); 410018cebfbSflorian } 411018cebfbSflorian 412018cebfbSflorian void 413018cebfbSflorian main_dispatch_frontend(int fd, short event, void *bula) 414018cebfbSflorian { 415018cebfbSflorian struct imsgev *iev = bula; 416018cebfbSflorian struct imsgbuf *ibuf; 417018cebfbSflorian struct imsg imsg; 418018cebfbSflorian ssize_t n; 419018cebfbSflorian int shut = 0, verbose; 420018cebfbSflorian 421018cebfbSflorian ibuf = &iev->ibuf; 422018cebfbSflorian 423018cebfbSflorian if (event & EV_READ) { 424018cebfbSflorian if ((n = imsg_read(ibuf)) == -1 && errno != EAGAIN) 425018cebfbSflorian fatal("imsg_read error"); 426018cebfbSflorian if (n == 0) /* Connection closed. */ 427018cebfbSflorian shut = 1; 428018cebfbSflorian } 429018cebfbSflorian if (event & EV_WRITE) { 430018cebfbSflorian if ((n = msgbuf_write(&ibuf->w)) == -1 && errno != EAGAIN) 431018cebfbSflorian fatal("msgbuf_write"); 432018cebfbSflorian if (n == 0) /* Connection closed. */ 433018cebfbSflorian shut = 1; 434018cebfbSflorian } 435018cebfbSflorian 436018cebfbSflorian for (;;) { 437018cebfbSflorian if ((n = imsg_get(ibuf, &imsg)) == -1) 438018cebfbSflorian fatal("imsg_get"); 439018cebfbSflorian if (n == 0) /* No more messages. */ 440018cebfbSflorian break; 441018cebfbSflorian 442018cebfbSflorian switch (imsg.hdr.type) { 443018cebfbSflorian case IMSG_STARTUP_DONE: 44428ba4729Sflorian solicit_dns_proposals(); 44522731bb8Sflorian open_ports(); 446018cebfbSflorian break; 447018cebfbSflorian case IMSG_CTL_RELOAD: 448018cebfbSflorian if (main_reload() == -1) 449018cebfbSflorian log_warnx("configuration reload failed"); 450018cebfbSflorian else 451018cebfbSflorian log_warnx("configuration reloaded"); 452018cebfbSflorian break; 453018cebfbSflorian case IMSG_CTL_LOG_VERBOSE: 454a9155f32Sflorian if (IMSG_DATA_SIZE(imsg) != sizeof(verbose)) 4552b821978Sflorian fatalx("%s: IMSG_CTL_LOG_VERBOSE wrong length: " 456a9155f32Sflorian "%lu", __func__, IMSG_DATA_SIZE(imsg)); 457018cebfbSflorian memcpy(&verbose, imsg.data, sizeof(verbose)); 458018cebfbSflorian log_setverbose(verbose); 459018cebfbSflorian break; 460018cebfbSflorian default: 461018cebfbSflorian log_debug("%s: error handling imsg %d", __func__, 462018cebfbSflorian imsg.hdr.type); 463018cebfbSflorian break; 464018cebfbSflorian } 465018cebfbSflorian imsg_free(&imsg); 466018cebfbSflorian } 467018cebfbSflorian if (!shut) 468018cebfbSflorian imsg_event_add(iev); 469018cebfbSflorian else { 470018cebfbSflorian /* This pipe is dead. Remove its event handler */ 471018cebfbSflorian event_del(&iev->ev); 472018cebfbSflorian event_loopexit(NULL); 473018cebfbSflorian } 474018cebfbSflorian } 475018cebfbSflorian 476018cebfbSflorian void 477018cebfbSflorian main_dispatch_resolver(int fd, short event, void *bula) 478018cebfbSflorian { 479018cebfbSflorian struct imsgev *iev = bula; 480018cebfbSflorian struct imsgbuf *ibuf; 481018cebfbSflorian struct imsg imsg; 482cfffd8c7Sflorian struct in_addr *in; 483b2501eadSflorian ssize_t n; 4842f29e846Sflorian int shut = 0; 485b2501eadSflorian 486b2501eadSflorian ibuf = &iev->ibuf; 487b2501eadSflorian 488b2501eadSflorian if (event & EV_READ) { 489b2501eadSflorian if ((n = imsg_read(ibuf)) == -1 && errno != EAGAIN) 490b2501eadSflorian fatal("imsg_read error"); 491b2501eadSflorian if (n == 0) /* Connection closed. */ 492b2501eadSflorian shut = 1; 493b2501eadSflorian } 494b2501eadSflorian if (event & EV_WRITE) { 495b2501eadSflorian if ((n = msgbuf_write(&ibuf->w)) == -1 && errno != EAGAIN) 496b2501eadSflorian fatal("msgbuf_write"); 497b2501eadSflorian if (n == 0) /* Connection closed. */ 498b2501eadSflorian shut = 1; 499b2501eadSflorian } 500b2501eadSflorian 501b2501eadSflorian for (;;) { 502b2501eadSflorian if ((n = imsg_get(ibuf, &imsg)) == -1) 503b2501eadSflorian fatal("imsg_get"); 504b2501eadSflorian if (n == 0) /* No more messages. */ 505b2501eadSflorian break; 506b2501eadSflorian 507b2501eadSflorian switch (imsg.hdr.type) { 508cfffd8c7Sflorian case IMSG_CONNECT_CAPTIVE_PORTAL_HOST: 509cfffd8c7Sflorian if (IMSG_DATA_SIZE(imsg) != sizeof(*in)) 510cfffd8c7Sflorian fatalx("%s: IMSG_CONNECT_CAPTIVE_PORTAL_HOST " 511cfffd8c7Sflorian "wrong length: %lu", __func__, 512cfffd8c7Sflorian IMSG_DATA_SIZE(imsg)); 513cfffd8c7Sflorian in = (struct in_addr *)imsg.data; 514cfffd8c7Sflorian connect_captive_portal_host(in); 515b2501eadSflorian break; 516b2501eadSflorian default: 517b2501eadSflorian log_debug("%s: error handling imsg %d", __func__, 518b2501eadSflorian imsg.hdr.type); 519b2501eadSflorian break; 520b2501eadSflorian } 521b2501eadSflorian imsg_free(&imsg); 522b2501eadSflorian } 523b2501eadSflorian if (!shut) 524b2501eadSflorian imsg_event_add(iev); 525b2501eadSflorian else { 526b2501eadSflorian /* This pipe is dead. Remove its event handler. */ 527b2501eadSflorian event_del(&iev->ev); 528b2501eadSflorian event_loopexit(NULL); 529b2501eadSflorian } 530b2501eadSflorian } 531b2501eadSflorian 532b2501eadSflorian void 533b2501eadSflorian main_dispatch_captiveportal(int fd, short event, void *bula) 534b2501eadSflorian { 535b2501eadSflorian struct imsgev *iev = bula; 536b2501eadSflorian struct imsgbuf *ibuf; 537b2501eadSflorian struct imsg imsg; 538018cebfbSflorian ssize_t n; 539018cebfbSflorian int shut = 0; 540018cebfbSflorian 541018cebfbSflorian ibuf = &iev->ibuf; 542018cebfbSflorian 543018cebfbSflorian if (event & EV_READ) { 544018cebfbSflorian if ((n = imsg_read(ibuf)) == -1 && errno != EAGAIN) 545018cebfbSflorian fatal("imsg_read error"); 546018cebfbSflorian if (n == 0) /* Connection closed. */ 547018cebfbSflorian shut = 1; 548018cebfbSflorian } 549018cebfbSflorian if (event & EV_WRITE) { 550018cebfbSflorian if ((n = msgbuf_write(&ibuf->w)) == -1 && errno != EAGAIN) 551018cebfbSflorian fatal("msgbuf_write"); 552018cebfbSflorian if (n == 0) /* Connection closed. */ 553018cebfbSflorian shut = 1; 554018cebfbSflorian } 555018cebfbSflorian 556018cebfbSflorian for (;;) { 557018cebfbSflorian if ((n = imsg_get(ibuf, &imsg)) == -1) 558018cebfbSflorian fatal("imsg_get"); 559018cebfbSflorian if (n == 0) /* No more messages. */ 560018cebfbSflorian break; 561018cebfbSflorian 562018cebfbSflorian switch (imsg.hdr.type) { 563018cebfbSflorian default: 564018cebfbSflorian log_debug("%s: error handling imsg %d", __func__, 565018cebfbSflorian imsg.hdr.type); 566018cebfbSflorian break; 567018cebfbSflorian } 568018cebfbSflorian imsg_free(&imsg); 569018cebfbSflorian } 570018cebfbSflorian if (!shut) 571018cebfbSflorian imsg_event_add(iev); 572018cebfbSflorian else { 573018cebfbSflorian /* This pipe is dead. Remove its event handler. */ 574018cebfbSflorian event_del(&iev->ev); 575018cebfbSflorian event_loopexit(NULL); 576018cebfbSflorian } 577018cebfbSflorian } 578018cebfbSflorian 579018cebfbSflorian void 580018cebfbSflorian main_imsg_compose_frontend(int type, pid_t pid, void *data, uint16_t datalen) 581018cebfbSflorian { 582018cebfbSflorian if (iev_frontend) 583018cebfbSflorian imsg_compose_event(iev_frontend, type, 0, pid, -1, data, 584018cebfbSflorian datalen); 585018cebfbSflorian } 586018cebfbSflorian 587018cebfbSflorian void 588018cebfbSflorian main_imsg_compose_frontend_fd(int type, pid_t pid, int fd) 589018cebfbSflorian { 590018cebfbSflorian if (iev_frontend) 591018cebfbSflorian imsg_compose_event(iev_frontend, type, 0, pid, fd, NULL, 0); 592018cebfbSflorian } 593018cebfbSflorian 594018cebfbSflorian void 595018cebfbSflorian main_imsg_compose_resolver(int type, pid_t pid, void *data, uint16_t datalen) 596018cebfbSflorian { 597018cebfbSflorian if (iev_resolver) 598018cebfbSflorian imsg_compose_event(iev_resolver, type, 0, pid, -1, data, 599018cebfbSflorian datalen); 600018cebfbSflorian } 601018cebfbSflorian 602018cebfbSflorian void 603b2501eadSflorian main_imsg_compose_captiveportal(int type, pid_t pid, void *data, 604b2501eadSflorian uint16_t datalen) 605b2501eadSflorian { 606b2501eadSflorian if (iev_captiveportal) 607b2501eadSflorian imsg_compose_event(iev_captiveportal, type, 0, pid, -1, data, 608b2501eadSflorian datalen); 609b2501eadSflorian } 610b2501eadSflorian 611b2501eadSflorian void 612b2501eadSflorian main_imsg_compose_captiveportal_fd(int type, pid_t pid, int fd) 613b2501eadSflorian { 614b2501eadSflorian if (iev_frontend) 615b2501eadSflorian imsg_compose_event(iev_captiveportal, type, 0, pid, fd, NULL, 616b2501eadSflorian 0); 617b2501eadSflorian } 618b2501eadSflorian 619b2501eadSflorian void 620018cebfbSflorian imsg_event_add(struct imsgev *iev) 621018cebfbSflorian { 622018cebfbSflorian iev->events = EV_READ; 623018cebfbSflorian if (iev->ibuf.w.queued) 624018cebfbSflorian iev->events |= EV_WRITE; 625018cebfbSflorian 626018cebfbSflorian event_del(&iev->ev); 627018cebfbSflorian event_set(&iev->ev, iev->ibuf.fd, iev->events, iev->handler, iev); 628018cebfbSflorian event_add(&iev->ev, NULL); 629018cebfbSflorian } 630018cebfbSflorian 631018cebfbSflorian int 632018cebfbSflorian imsg_compose_event(struct imsgev *iev, uint16_t type, uint32_t peerid, 633018cebfbSflorian pid_t pid, int fd, void *data, uint16_t datalen) 634018cebfbSflorian { 635018cebfbSflorian int ret; 636018cebfbSflorian 637018cebfbSflorian if ((ret = imsg_compose(&iev->ibuf, type, peerid, pid, fd, data, 638018cebfbSflorian datalen)) != -1) 639018cebfbSflorian imsg_event_add(iev); 640018cebfbSflorian 641018cebfbSflorian return (ret); 642018cebfbSflorian } 643018cebfbSflorian 644018cebfbSflorian static int 645018cebfbSflorian main_imsg_send_ipc_sockets(struct imsgbuf *frontend_buf, 646b2501eadSflorian struct imsgbuf *resolver_buf, struct imsgbuf *captiveportal_buf) 647018cebfbSflorian { 648018cebfbSflorian int pipe_frontend2resolver[2]; 649b2501eadSflorian int pipe_frontend2captiveportal[2]; 650b2501eadSflorian int pipe_resolver2captiveportal[2]; 651018cebfbSflorian 652018cebfbSflorian if (socketpair(AF_UNIX, SOCK_STREAM | SOCK_CLOEXEC | SOCK_NONBLOCK, 653018cebfbSflorian PF_UNSPEC, pipe_frontend2resolver) == -1) 654018cebfbSflorian return (-1); 655018cebfbSflorian 656b2501eadSflorian if (socketpair(AF_UNIX, SOCK_STREAM | SOCK_CLOEXEC | SOCK_NONBLOCK, 657b2501eadSflorian PF_UNSPEC, pipe_frontend2captiveportal) == -1) 658b2501eadSflorian return (-1); 659b2501eadSflorian 660b2501eadSflorian if (socketpair(AF_UNIX, SOCK_STREAM | SOCK_CLOEXEC | SOCK_NONBLOCK, 661b2501eadSflorian PF_UNSPEC, pipe_resolver2captiveportal) == -1) 662b2501eadSflorian return (-1); 663b2501eadSflorian 664b2501eadSflorian if (imsg_compose(frontend_buf, IMSG_SOCKET_IPC_RESOLVER, 0, 0, 665018cebfbSflorian pipe_frontend2resolver[0], NULL, 0) == -1) 666018cebfbSflorian return (-1); 667b2501eadSflorian if (imsg_compose(resolver_buf, IMSG_SOCKET_IPC_FRONTEND, 0, 0, 668018cebfbSflorian pipe_frontend2resolver[1], NULL, 0) == -1) 669018cebfbSflorian return (-1); 670018cebfbSflorian 671b2501eadSflorian if (imsg_compose(frontend_buf, IMSG_SOCKET_IPC_CAPTIVEPORTAL, 0, 0, 672b2501eadSflorian pipe_frontend2captiveportal[0], NULL, 0) == -1) 673b2501eadSflorian return (-1); 674b2501eadSflorian if (imsg_compose(captiveportal_buf, IMSG_SOCKET_IPC_FRONTEND, 0, 0, 675b2501eadSflorian pipe_frontend2captiveportal[1], NULL, 0) == -1) 676b2501eadSflorian return (-1); 677b2501eadSflorian 678b2501eadSflorian if (imsg_compose(resolver_buf, IMSG_SOCKET_IPC_CAPTIVEPORTAL, 0, 0, 679b2501eadSflorian pipe_resolver2captiveportal[0], NULL, 0) == -1) 680b2501eadSflorian return (-1); 681b2501eadSflorian if (imsg_compose(captiveportal_buf, IMSG_SOCKET_IPC_RESOLVER, 0, 0, 682b2501eadSflorian pipe_resolver2captiveportal[1], NULL, 0) == -1) 683b2501eadSflorian return (-1); 684b2501eadSflorian 685018cebfbSflorian return (0); 686018cebfbSflorian } 687018cebfbSflorian 688018cebfbSflorian int 689018cebfbSflorian main_reload(void) 690018cebfbSflorian { 691bb81f7e1Sflorian struct uw_conf *xconf; 692018cebfbSflorian 693*572e5ac0Skn if ((xconf = parse_config(conffile)) == NULL) 694018cebfbSflorian return (-1); 695018cebfbSflorian 696018cebfbSflorian if (main_imsg_send_config(xconf) == -1) 697018cebfbSflorian return (-1); 698018cebfbSflorian 699018cebfbSflorian merge_config(main_conf, xconf); 700018cebfbSflorian 7012d988276Sflorian if (main_conf->blocklist_file != NULL) 7022d988276Sflorian send_blocklist_fd(); 7032d988276Sflorian 704018cebfbSflorian return (0); 705018cebfbSflorian } 706018cebfbSflorian 707018cebfbSflorian int 708bb81f7e1Sflorian main_imsg_send_config(struct uw_conf *xconf) 709018cebfbSflorian { 710bb81f7e1Sflorian struct uw_forwarder *uw_forwarder; 711018cebfbSflorian 712018cebfbSflorian /* Send fixed part of config to children. */ 713b2501eadSflorian if (main_sendall(IMSG_RECONF_CONF, xconf, sizeof(*xconf)) == -1) 714018cebfbSflorian return (-1); 715b2501eadSflorian if (xconf->captive_portal_host != NULL) { 716b2501eadSflorian if (main_sendall(IMSG_RECONF_CAPTIVE_PORTAL_HOST, 717b2501eadSflorian xconf->captive_portal_host, 718b2501eadSflorian strlen(xconf->captive_portal_host) + 1) == -1) 719b2501eadSflorian return (-1); 720b2501eadSflorian } 721b2501eadSflorian 722b2501eadSflorian if (xconf->captive_portal_path != NULL) { 723b2501eadSflorian if (main_sendall(IMSG_RECONF_CAPTIVE_PORTAL_PATH, 724b2501eadSflorian xconf->captive_portal_path, 725b2501eadSflorian strlen(xconf->captive_portal_path) + 1) == -1) 726b2501eadSflorian return (-1); 727b2501eadSflorian } 728b2501eadSflorian 729b2501eadSflorian if (xconf->captive_portal_expected_response != NULL) { 730b2501eadSflorian if (main_sendall(IMSG_RECONF_CAPTIVE_PORTAL_EXPECTED_RESPONSE, 731b2501eadSflorian xconf->captive_portal_expected_response, 732b2501eadSflorian strlen(xconf->captive_portal_expected_response) + 1) 733b2501eadSflorian == -1) 734b2501eadSflorian return (-1); 735b2501eadSflorian } 736018cebfbSflorian 7372d988276Sflorian if (xconf->blocklist_file != NULL) { 7382d988276Sflorian if (main_sendall(IMSG_RECONF_BLOCKLIST_FILE, 7392d988276Sflorian xconf->blocklist_file, strlen(xconf->blocklist_file) + 1) 7402d988276Sflorian == -1) 7412d988276Sflorian return (-1); 7422d988276Sflorian } 7432d988276Sflorian 7443570995aSflorian /* send static forwarders to children */ 7457d055805Sflorian TAILQ_FOREACH(uw_forwarder, &xconf->uw_forwarder_list, entry) { 746bb81f7e1Sflorian if (main_sendall(IMSG_RECONF_FORWARDER, uw_forwarder, 747bb81f7e1Sflorian sizeof(*uw_forwarder)) == -1) 748018cebfbSflorian return (-1); 749018cebfbSflorian } 750018cebfbSflorian 7513570995aSflorian /* send static DoT forwarders to children */ 7527d055805Sflorian TAILQ_FOREACH(uw_forwarder, &xconf->uw_dot_forwarder_list, 7533570995aSflorian entry) { 754bb81f7e1Sflorian if (main_sendall(IMSG_RECONF_DOT_FORWARDER, uw_forwarder, 755bb81f7e1Sflorian sizeof(*uw_forwarder)) == -1) 7563570995aSflorian return (-1); 7573570995aSflorian } 7583570995aSflorian 759018cebfbSflorian /* Tell children the revised config is now complete. */ 760b2501eadSflorian if (main_sendall(IMSG_RECONF_END, NULL, 0) == -1) 761018cebfbSflorian return (-1); 762018cebfbSflorian 763018cebfbSflorian return (0); 764018cebfbSflorian } 765018cebfbSflorian 766018cebfbSflorian int 767b2501eadSflorian main_sendall(enum imsg_type type, void *buf, uint16_t len) 768018cebfbSflorian { 769018cebfbSflorian if (imsg_compose_event(iev_frontend, type, 0, 0, -1, buf, len) == -1) 770018cebfbSflorian return (-1); 771018cebfbSflorian if (imsg_compose_event(iev_resolver, type, 0, 0, -1, buf, len) == -1) 772018cebfbSflorian return (-1); 773b2501eadSflorian if (imsg_compose_event(iev_captiveportal, type, 0, 0, -1, buf, len) == 774b2501eadSflorian -1) 775b2501eadSflorian return (-1); 776018cebfbSflorian return (0); 777018cebfbSflorian } 778018cebfbSflorian 779018cebfbSflorian void 780bb81f7e1Sflorian merge_config(struct uw_conf *conf, struct uw_conf *xconf) 781018cebfbSflorian { 782bb81f7e1Sflorian struct uw_forwarder *uw_forwarder; 783018cebfbSflorian 784018cebfbSflorian /* Remove & discard existing forwarders. */ 7857d055805Sflorian while ((uw_forwarder = TAILQ_FIRST(&conf->uw_forwarder_list)) != 786bb81f7e1Sflorian NULL) { 7877d055805Sflorian TAILQ_REMOVE(&conf->uw_forwarder_list, uw_forwarder, entry); 788bb81f7e1Sflorian free(uw_forwarder); 789018cebfbSflorian } 7907d055805Sflorian while ((uw_forwarder = TAILQ_FIRST(&conf->uw_dot_forwarder_list)) != 791bb81f7e1Sflorian NULL) { 7927d055805Sflorian TAILQ_REMOVE(&conf->uw_dot_forwarder_list, uw_forwarder, entry); 793bb81f7e1Sflorian free(uw_forwarder); 7943570995aSflorian } 795018cebfbSflorian 796fd873f7fSflorian conf->res_pref_len = xconf->res_pref_len; 797fd873f7fSflorian memcpy(&conf->res_pref, &xconf->res_pref, 798fd873f7fSflorian sizeof(conf->res_pref)); 799018cebfbSflorian 800b2501eadSflorian free(conf->captive_portal_host); 801b2501eadSflorian conf->captive_portal_host = xconf->captive_portal_host; 802b2501eadSflorian 803b2501eadSflorian free(conf->captive_portal_path); 804b2501eadSflorian conf->captive_portal_path = xconf->captive_portal_path; 805b2501eadSflorian 806b2501eadSflorian free(conf->captive_portal_expected_response); 807b2501eadSflorian conf->captive_portal_expected_response = 808b2501eadSflorian xconf->captive_portal_expected_response; 809b2501eadSflorian 810b2501eadSflorian conf->captive_portal_expected_status = 811b2501eadSflorian xconf->captive_portal_expected_status; 812b2501eadSflorian 813b2501eadSflorian conf->captive_portal_auto = xconf->captive_portal_auto; 814b2501eadSflorian 8152d988276Sflorian free(conf->blocklist_file); 8162d988276Sflorian conf->blocklist_file = xconf->blocklist_file; 817ac71ec8eSflorian conf->blocklist_log = xconf->blocklist_log; 8182d988276Sflorian 819018cebfbSflorian /* Add new forwarders. */ 8207d055805Sflorian while ((uw_forwarder = TAILQ_FIRST(&xconf->uw_forwarder_list)) != 821bb81f7e1Sflorian NULL) { 8227d055805Sflorian TAILQ_REMOVE(&xconf->uw_forwarder_list, uw_forwarder, entry); 8237d055805Sflorian TAILQ_INSERT_TAIL(&conf->uw_forwarder_list, 824bb81f7e1Sflorian uw_forwarder, entry); 825018cebfbSflorian } 8267d055805Sflorian while ((uw_forwarder = TAILQ_FIRST(&xconf->uw_dot_forwarder_list)) != 827bb81f7e1Sflorian NULL) { 8287d055805Sflorian TAILQ_REMOVE(&xconf->uw_dot_forwarder_list, uw_forwarder, 8297d055805Sflorian entry); 8307d055805Sflorian TAILQ_INSERT_TAIL(&conf->uw_dot_forwarder_list, 831bb81f7e1Sflorian uw_forwarder, entry); 8323570995aSflorian } 833018cebfbSflorian 834018cebfbSflorian free(xconf); 835018cebfbSflorian } 836018cebfbSflorian 837bb81f7e1Sflorian struct uw_conf * 838018cebfbSflorian config_new_empty(void) 839018cebfbSflorian { 840fd873f7fSflorian static enum uw_resolver_type default_res_pref[] = { 841fd873f7fSflorian UW_RES_DOT, 842fd873f7fSflorian UW_RES_FORWARDER, 843fd873f7fSflorian UW_RES_RECURSOR, 844530f5ecfSflorian UW_RES_DHCP, 845530f5ecfSflorian UW_RES_ASR}; 846bb81f7e1Sflorian struct uw_conf *xconf; 847018cebfbSflorian 848018cebfbSflorian xconf = calloc(1, sizeof(*xconf)); 849018cebfbSflorian if (xconf == NULL) 850018cebfbSflorian fatal(NULL); 851018cebfbSflorian 852fd873f7fSflorian memcpy(&xconf->res_pref, &default_res_pref, 853fd873f7fSflorian sizeof(default_res_pref)); 854530f5ecfSflorian xconf->res_pref_len = 5; 855fd873f7fSflorian 8567d055805Sflorian TAILQ_INIT(&xconf->uw_forwarder_list); 8577d055805Sflorian TAILQ_INIT(&xconf->uw_dot_forwarder_list); 858018cebfbSflorian 859b2501eadSflorian if ((xconf->captive_portal_expected_response = strdup("")) == NULL) 860b2501eadSflorian fatal(NULL); 861bb81f7e1Sflorian 862b2501eadSflorian xconf->captive_portal_expected_status = 200; 863b2501eadSflorian xconf->captive_portal_auto = 1; 864b2501eadSflorian 865018cebfbSflorian return (xconf); 866018cebfbSflorian } 867018cebfbSflorian 868018cebfbSflorian void 869bb81f7e1Sflorian config_clear(struct uw_conf *conf) 870018cebfbSflorian { 871bb81f7e1Sflorian struct uw_conf *xconf; 872018cebfbSflorian 873018cebfbSflorian /* Merge current config with an empty config. */ 874018cebfbSflorian xconf = config_new_empty(); 875018cebfbSflorian merge_config(conf, xconf); 876018cebfbSflorian 877018cebfbSflorian free(conf); 878018cebfbSflorian } 879018cebfbSflorian 880018cebfbSflorian void 881d265a5d3Sflorian open_ports(void) 882d265a5d3Sflorian { 883d265a5d3Sflorian struct addrinfo hints, *res0; 884d265a5d3Sflorian int udp4sock = -1, udp6sock = -1, error; 885d265a5d3Sflorian 886d265a5d3Sflorian memset(&hints, 0, sizeof(hints)); 887d265a5d3Sflorian hints.ai_family = AF_INET; 888d265a5d3Sflorian hints.ai_socktype = SOCK_DGRAM; 889cc4fd5c4Stedu hints.ai_flags = AI_NUMERICHOST | AI_PASSIVE; 890d265a5d3Sflorian 891d265a5d3Sflorian error = getaddrinfo("127.0.0.1", "domain", &hints, &res0); 892d265a5d3Sflorian if (!error && res0) { 893d265a5d3Sflorian if ((udp4sock = socket(res0->ai_family, res0->ai_socktype, 894d265a5d3Sflorian res0->ai_protocol)) != -1) { 895d265a5d3Sflorian if (bind(udp4sock, res0->ai_addr, res0->ai_addrlen) 896d265a5d3Sflorian == -1) { 897d265a5d3Sflorian close(udp4sock); 898d265a5d3Sflorian udp4sock = -1; 899d265a5d3Sflorian } 900d265a5d3Sflorian } 901d265a5d3Sflorian } 902296cf316Sflorian if (res0) 903d265a5d3Sflorian freeaddrinfo(res0); 904d265a5d3Sflorian 905d265a5d3Sflorian hints.ai_family = AF_INET6; 906d265a5d3Sflorian error = getaddrinfo("::1", "domain", &hints, &res0); 907d265a5d3Sflorian if (!error && res0) { 908d265a5d3Sflorian if ((udp6sock = socket(res0->ai_family, res0->ai_socktype, 909d265a5d3Sflorian res0->ai_protocol)) != -1) { 910d265a5d3Sflorian if (bind(udp6sock, res0->ai_addr, res0->ai_addrlen) 911d265a5d3Sflorian == -1) { 912d265a5d3Sflorian close(udp6sock); 913d265a5d3Sflorian udp6sock = -1; 914d265a5d3Sflorian } 915d265a5d3Sflorian } 916d265a5d3Sflorian } 917296cf316Sflorian if (res0) 918d265a5d3Sflorian freeaddrinfo(res0); 919d265a5d3Sflorian 920d265a5d3Sflorian if (udp4sock == -1 && udp6sock == -1) 921d265a5d3Sflorian fatal("could not bind to 127.0.0.1 or ::1 on port 53"); 922d265a5d3Sflorian 923b04dd19dSflorian if (udp4sock != -1) 924d265a5d3Sflorian main_imsg_compose_frontend_fd(IMSG_UDP4SOCK, 0, udp4sock); 925b04dd19dSflorian if (udp6sock != -1) 926d265a5d3Sflorian main_imsg_compose_frontend_fd(IMSG_UDP6SOCK, 0, udp6sock); 927d265a5d3Sflorian } 9282f29e846Sflorian 9292f29e846Sflorian void 93028ba4729Sflorian solicit_dns_proposals(void) 93128ba4729Sflorian { 93228ba4729Sflorian struct rt_msghdr rtm; 93328ba4729Sflorian struct iovec iov[1]; 93428ba4729Sflorian int iovcnt = 0; 93528ba4729Sflorian 93628ba4729Sflorian memset(&rtm, 0, sizeof(rtm)); 93728ba4729Sflorian 93828ba4729Sflorian rtm.rtm_version = RTM_VERSION; 93928ba4729Sflorian rtm.rtm_type = RTM_PROPOSAL; 94028ba4729Sflorian rtm.rtm_msglen = sizeof(rtm); 94128ba4729Sflorian rtm.rtm_tableid = 0; 94228ba4729Sflorian rtm.rtm_index = 0; 94328ba4729Sflorian rtm.rtm_seq = arc4random(); 94428ba4729Sflorian rtm.rtm_priority = RTP_PROPOSAL_SOLICIT; 94528ba4729Sflorian 94628ba4729Sflorian iov[iovcnt].iov_base = &rtm; 94728ba4729Sflorian iov[iovcnt++].iov_len = sizeof(rtm); 94828ba4729Sflorian 94928ba4729Sflorian if (writev(routesock, iov, iovcnt) == -1) 95028ba4729Sflorian log_warn("failed to send solicitation"); 95128ba4729Sflorian } 95228ba4729Sflorian 95328ba4729Sflorian void 954cfffd8c7Sflorian connect_captive_portal_host(struct in_addr *in) 9552f29e846Sflorian { 956cfffd8c7Sflorian struct sockaddr *sa; 957cfffd8c7Sflorian struct sockaddr_in sin; 9582f29e846Sflorian int httpsock; 9592f29e846Sflorian 960cfffd8c7Sflorian sa = (struct sockaddr *)&sin; 961cfffd8c7Sflorian memset(&sin, 0, sizeof(sin)); 962cfffd8c7Sflorian sin.sin_len = sizeof(sin); 963cfffd8c7Sflorian sin.sin_family = AF_INET; 964cfffd8c7Sflorian sin.sin_addr = *in; 965cfffd8c7Sflorian sin.sin_port = htons(80); 966cfffd8c7Sflorian log_debug("%s: ip_port: %s", __func__, ip_port(sa)); 9672f29e846Sflorian 9682f29e846Sflorian if ((httpsock = socket(AF_INET, SOCK_STREAM | 9692f29e846Sflorian SOCK_CLOEXEC | SOCK_NONBLOCK, 0)) == -1) { 9702f29e846Sflorian log_warn("%s: socket", __func__); 971cfffd8c7Sflorian return; 9722f29e846Sflorian } 973cfffd8c7Sflorian if (connect(httpsock, sa, sizeof(sin)) == -1) { 9742f29e846Sflorian if (errno != EINPROGRESS) { 9752f29e846Sflorian log_warn("%s: connect", __func__); 9762f29e846Sflorian close(httpsock); 977cfffd8c7Sflorian return; 9782f29e846Sflorian } 9792f29e846Sflorian } 9802f29e846Sflorian 981cfffd8c7Sflorian main_imsg_compose_captiveportal_fd(IMSG_HTTPSOCK, 0, 982cfffd8c7Sflorian httpsock); 9832f29e846Sflorian } 9842d988276Sflorian 9852d988276Sflorian void 9862d988276Sflorian send_blocklist_fd(void) 9872d988276Sflorian { 9882d988276Sflorian int bl_fd; 9892d988276Sflorian 9902d988276Sflorian if ((bl_fd = open(main_conf->blocklist_file, O_RDONLY)) != -1) 9912d988276Sflorian main_imsg_compose_frontend_fd(IMSG_BLFD, 0, bl_fd); 9922d988276Sflorian else 9932d988276Sflorian log_warn("%s", main_conf->blocklist_file); 9942d988276Sflorian } 995679647feSflorian 996679647feSflorian void 997679647feSflorian imsg_receive_config(struct imsg *imsg, struct uw_conf **xconf) 998679647feSflorian { 999679647feSflorian struct uw_conf *nconf; 1000679647feSflorian struct uw_forwarder *uw_forwarder; 1001679647feSflorian 1002679647feSflorian nconf = *xconf; 1003679647feSflorian 1004679647feSflorian switch (imsg->hdr.type) { 1005679647feSflorian case IMSG_RECONF_CONF: 1006679647feSflorian if (nconf != NULL) 1007679647feSflorian fatalx("%s: IMSG_RECONF_CONF already in " 1008679647feSflorian "progress", __func__); 1009679647feSflorian if (IMSG_DATA_SIZE(*imsg) != sizeof(struct uw_conf)) 1010679647feSflorian fatalx("%s: IMSG_RECONF_CONF wrong length: %lu", 1011679647feSflorian __func__, IMSG_DATA_SIZE(*imsg)); 1012679647feSflorian if ((*xconf = malloc(sizeof(struct uw_conf))) == NULL) 1013679647feSflorian fatal(NULL); 1014679647feSflorian nconf = *xconf; 1015679647feSflorian memcpy(nconf, imsg->data, sizeof(struct uw_conf)); 1016679647feSflorian nconf->captive_portal_host = NULL; 1017679647feSflorian nconf->captive_portal_path = NULL; 1018679647feSflorian nconf->captive_portal_expected_response = NULL; 10197d055805Sflorian TAILQ_INIT(&nconf->uw_forwarder_list); 10207d055805Sflorian TAILQ_INIT(&nconf->uw_dot_forwarder_list); 1021679647feSflorian break; 1022679647feSflorian case IMSG_RECONF_CAPTIVE_PORTAL_HOST: 1023679647feSflorian /* make sure this is a string */ 1024679647feSflorian ((char *)imsg->data)[IMSG_DATA_SIZE(*imsg) - 1] = '\0'; 1025679647feSflorian if ((nconf->captive_portal_host = strdup(imsg->data)) == 1026679647feSflorian NULL) 1027679647feSflorian fatal("%s: strdup", __func__); 1028679647feSflorian break; 1029679647feSflorian case IMSG_RECONF_CAPTIVE_PORTAL_PATH: 1030679647feSflorian /* make sure this is a string */ 1031679647feSflorian ((char *)imsg->data)[IMSG_DATA_SIZE(*imsg) - 1] = '\0'; 1032679647feSflorian if ((nconf->captive_portal_path = strdup(imsg->data)) == 1033679647feSflorian NULL) 1034679647feSflorian fatal("%s: strdup", __func__); 1035679647feSflorian break; 1036679647feSflorian case IMSG_RECONF_CAPTIVE_PORTAL_EXPECTED_RESPONSE: 1037679647feSflorian /* make sure this is a string */ 1038679647feSflorian ((char *)imsg->data)[IMSG_DATA_SIZE(*imsg) - 1] = '\0'; 1039679647feSflorian if ((nconf->captive_portal_expected_response = 1040679647feSflorian strdup(imsg->data)) == NULL) 1041679647feSflorian fatal("%s: strdup", __func__); 1042679647feSflorian break; 1043679647feSflorian case IMSG_RECONF_BLOCKLIST_FILE: 1044679647feSflorian /* make sure this is a string */ 1045679647feSflorian ((char *)imsg->data)[IMSG_DATA_SIZE(*imsg) - 1] = '\0'; 1046679647feSflorian if ((nconf->blocklist_file = strdup(imsg->data)) == 1047679647feSflorian NULL) 1048679647feSflorian fatal("%s: strdup", __func__); 1049679647feSflorian break; 1050679647feSflorian case IMSG_RECONF_FORWARDER: 1051679647feSflorian if (IMSG_DATA_SIZE(*imsg) != sizeof(struct uw_forwarder)) 1052679647feSflorian fatalx("%s: IMSG_RECONF_FORWARDER wrong length:" 1053679647feSflorian " %lu", __func__, IMSG_DATA_SIZE(*imsg)); 1054679647feSflorian if ((uw_forwarder = malloc(sizeof(struct 1055679647feSflorian uw_forwarder))) == NULL) 1056679647feSflorian fatal(NULL); 1057679647feSflorian memcpy(uw_forwarder, imsg->data, sizeof(struct 1058679647feSflorian uw_forwarder)); 10597d055805Sflorian TAILQ_INSERT_TAIL(&nconf->uw_forwarder_list, 1060679647feSflorian uw_forwarder, entry); 1061679647feSflorian break; 1062679647feSflorian case IMSG_RECONF_DOT_FORWARDER: 1063679647feSflorian if (IMSG_DATA_SIZE(*imsg) != sizeof(struct uw_forwarder)) 1064679647feSflorian fatalx("%s: IMSG_RECONF_DOT_FORWARDER wrong " 1065679647feSflorian "length: %lu", __func__, 1066679647feSflorian IMSG_DATA_SIZE(*imsg)); 1067679647feSflorian if ((uw_forwarder = malloc(sizeof(struct 1068679647feSflorian uw_forwarder))) == NULL) 1069679647feSflorian fatal(NULL); 1070679647feSflorian memcpy(uw_forwarder, imsg->data, sizeof(struct 1071679647feSflorian uw_forwarder)); 10727d055805Sflorian TAILQ_INSERT_TAIL(&nconf->uw_dot_forwarder_list, 1073679647feSflorian uw_forwarder, entry); 1074679647feSflorian break; 1075679647feSflorian default: 1076679647feSflorian log_debug("%s: error handling imsg %d", __func__, 1077679647feSflorian imsg->hdr.type); 1078679647feSflorian break; 1079679647feSflorian } 1080679647feSflorian } 1081