1*7d055805Sflorian /* $OpenBSD: unwind.c,v 1.34 2019/11/09 16:28:10 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" 50b2501eadSflorian #include "captiveportal.h" 51018cebfbSflorian 52296cf316Sflorian #define LEASE_DB_DIR "/var/db/" 53296cf316Sflorian #define _PATH_LEASE_DB "/var/db/dhclient.leases." 54296cf316Sflorian 5590d56d5fSflorian #define TRUST_ANCHOR_FILE "/var/db/unwind.key" 56296cf316Sflorian 57018cebfbSflorian __dead void usage(void); 58018cebfbSflorian __dead void main_shutdown(void); 59018cebfbSflorian 60018cebfbSflorian void main_sig_handler(int, short, void *); 61018cebfbSflorian 62018cebfbSflorian static pid_t start_child(int, char *, int, int, int); 63018cebfbSflorian 64018cebfbSflorian void main_dispatch_frontend(int, short, void *); 65018cebfbSflorian void main_dispatch_resolver(int, short, void *); 66b2501eadSflorian void main_dispatch_captiveportal(int, short, void *); 67018cebfbSflorian 68b2501eadSflorian static int main_imsg_send_ipc_sockets(struct imsgbuf *, struct imsgbuf *, 69b2501eadSflorian 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); 74018cebfbSflorian void open_dhcp_lease(int); 75d265a5d3Sflorian void open_ports(void); 762f29e846Sflorian void resolve_captive_portal(void); 772f29e846Sflorian void resolve_captive_portal_done(struct asr_result *, void *); 782d988276Sflorian void send_blocklist_fd(void); 79018cebfbSflorian 80bb81f7e1Sflorian struct uw_conf *main_conf; 81018cebfbSflorian struct imsgev *iev_frontend; 82018cebfbSflorian struct imsgev *iev_resolver; 83b2501eadSflorian struct imsgev *iev_captiveportal; 84018cebfbSflorian char *conffile; 85018cebfbSflorian 86018cebfbSflorian pid_t frontend_pid; 87018cebfbSflorian pid_t resolver_pid; 88b2501eadSflorian pid_t captiveportal_pid; 89018cebfbSflorian 90018cebfbSflorian uint32_t cmd_opts; 91018cebfbSflorian 92018cebfbSflorian void 93018cebfbSflorian main_sig_handler(int sig, short event, void *arg) 94018cebfbSflorian { 95018cebfbSflorian /* 96018cebfbSflorian * Normal signal handler rules don't apply because libevent 97018cebfbSflorian * decouples for us. 98018cebfbSflorian */ 99018cebfbSflorian 100018cebfbSflorian switch (sig) { 101018cebfbSflorian case SIGTERM: 102018cebfbSflorian case SIGINT: 1035472663aSflorian main_shutdown(); 104018cebfbSflorian break; 105018cebfbSflorian case SIGHUP: 106018cebfbSflorian if (main_reload() == -1) 107018cebfbSflorian log_warnx("configuration reload failed"); 108018cebfbSflorian else 109018cebfbSflorian log_debug("configuration reloaded"); 110018cebfbSflorian break; 111018cebfbSflorian default: 112018cebfbSflorian fatalx("unexpected signal"); 113018cebfbSflorian } 114018cebfbSflorian } 115018cebfbSflorian 116018cebfbSflorian __dead void 117018cebfbSflorian usage(void) 118018cebfbSflorian { 119018cebfbSflorian extern char *__progname; 120018cebfbSflorian 121018cebfbSflorian fprintf(stderr, "usage: %s [-dnv] [-f file] [-s socket]\n", 122018cebfbSflorian __progname); 123018cebfbSflorian exit(1); 124018cebfbSflorian } 125018cebfbSflorian 126018cebfbSflorian int 127018cebfbSflorian main(int argc, char *argv[]) 128018cebfbSflorian { 129018cebfbSflorian struct event ev_sigint, ev_sigterm, ev_sighup; 130bb81f7e1Sflorian int ch, debug = 0, resolver_flag = 0, frontend_flag = 0; 131bb81f7e1Sflorian int captiveportal_flag = 0, frontend_routesock, rtfilter; 132bb81f7e1Sflorian int pipe_main2frontend[2], pipe_main2resolver[2]; 133b2501eadSflorian int pipe_main2captiveportal[2]; 134d1b04a40Sflorian int control_fd, ta_fd; 135bb81f7e1Sflorian char *csock, *saved_argv0; 136018cebfbSflorian 137018cebfbSflorian conffile = CONF_FILE; 138018cebfbSflorian csock = UNWIND_SOCKET; 139018cebfbSflorian 140018cebfbSflorian log_init(1, LOG_DAEMON); /* Log to stderr until daemonized. */ 141018cebfbSflorian log_setverbose(1); 142018cebfbSflorian 143018cebfbSflorian saved_argv0 = argv[0]; 144018cebfbSflorian if (saved_argv0 == NULL) 145018cebfbSflorian saved_argv0 = "unwind"; 146018cebfbSflorian 147b2501eadSflorian while ((ch = getopt(argc, argv, "CdEFf:ns:v")) != -1) { 148018cebfbSflorian switch (ch) { 149b2501eadSflorian case 'C': 150b2501eadSflorian captiveportal_flag = 1; 151b2501eadSflorian break; 152018cebfbSflorian case 'd': 153018cebfbSflorian debug = 1; 154018cebfbSflorian break; 155018cebfbSflorian case 'E': 156018cebfbSflorian resolver_flag = 1; 157018cebfbSflorian break; 158018cebfbSflorian case 'F': 159018cebfbSflorian frontend_flag = 1; 160018cebfbSflorian break; 161018cebfbSflorian case 'f': 162018cebfbSflorian conffile = optarg; 163018cebfbSflorian break; 164018cebfbSflorian case 'n': 165018cebfbSflorian cmd_opts |= OPT_NOACTION; 166018cebfbSflorian break; 167018cebfbSflorian case 's': 168018cebfbSflorian csock = optarg; 169018cebfbSflorian break; 170018cebfbSflorian case 'v': 171018cebfbSflorian if (cmd_opts & OPT_VERBOSE) 172018cebfbSflorian cmd_opts |= OPT_VERBOSE2; 173018cebfbSflorian cmd_opts |= OPT_VERBOSE; 174018cebfbSflorian break; 175018cebfbSflorian default: 176018cebfbSflorian usage(); 177018cebfbSflorian } 178018cebfbSflorian } 179018cebfbSflorian 180018cebfbSflorian argc -= optind; 181018cebfbSflorian argv += optind; 182b2501eadSflorian if (argc > 0 || (resolver_flag && frontend_flag && captiveportal_flag)) 183018cebfbSflorian usage(); 184018cebfbSflorian 185018cebfbSflorian if (resolver_flag) 186018cebfbSflorian resolver(debug, cmd_opts & (OPT_VERBOSE | OPT_VERBOSE2)); 187018cebfbSflorian else if (frontend_flag) 188018cebfbSflorian frontend(debug, cmd_opts & (OPT_VERBOSE | OPT_VERBOSE2)); 189b2501eadSflorian else if (captiveportal_flag) 190b2501eadSflorian captiveportal(debug, cmd_opts & (OPT_VERBOSE | OPT_VERBOSE2)); 191018cebfbSflorian 192588e8263Sflorian if ((main_conf = parse_config(conffile)) == NULL) 193018cebfbSflorian exit(1); 194018cebfbSflorian 195018cebfbSflorian if (cmd_opts & OPT_NOACTION) { 196018cebfbSflorian if (cmd_opts & OPT_VERBOSE) 197018cebfbSflorian print_config(main_conf); 198018cebfbSflorian else 199018cebfbSflorian fprintf(stderr, "configuration OK\n"); 200018cebfbSflorian exit(0); 201018cebfbSflorian } 202018cebfbSflorian 203018cebfbSflorian /* Check for root privileges. */ 204018cebfbSflorian if (geteuid()) 205018cebfbSflorian errx(1, "need root privileges"); 206018cebfbSflorian 207018cebfbSflorian /* Check for assigned daemon user */ 208018cebfbSflorian if (getpwnam(UNWIND_USER) == NULL) 209018cebfbSflorian errx(1, "unknown user %s", UNWIND_USER); 210018cebfbSflorian 211018cebfbSflorian log_init(debug, LOG_DAEMON); 212018cebfbSflorian log_setverbose(cmd_opts & OPT_VERBOSE); 213018cebfbSflorian 214018cebfbSflorian if (!debug) 215018cebfbSflorian daemon(1, 0); 216018cebfbSflorian 217018cebfbSflorian log_info("startup"); 218018cebfbSflorian 219018cebfbSflorian if (socketpair(AF_UNIX, SOCK_STREAM | SOCK_CLOEXEC | SOCK_NONBLOCK, 220018cebfbSflorian PF_UNSPEC, pipe_main2frontend) == -1) 221018cebfbSflorian fatal("main2frontend socketpair"); 222018cebfbSflorian if (socketpair(AF_UNIX, SOCK_STREAM | SOCK_CLOEXEC | SOCK_NONBLOCK, 223018cebfbSflorian PF_UNSPEC, pipe_main2resolver) == -1) 224018cebfbSflorian fatal("main2resolver socketpair"); 225b2501eadSflorian if (socketpair(AF_UNIX, SOCK_STREAM | SOCK_CLOEXEC | SOCK_NONBLOCK, 226b2501eadSflorian PF_UNSPEC, pipe_main2captiveportal) == -1) 227b2501eadSflorian fatal("main2captiveportal socketpair"); 228018cebfbSflorian 229018cebfbSflorian /* Start children. */ 230018cebfbSflorian resolver_pid = start_child(PROC_RESOLVER, saved_argv0, 231018cebfbSflorian pipe_main2resolver[1], debug, cmd_opts & (OPT_VERBOSE | 232018cebfbSflorian OPT_VERBOSE2)); 233018cebfbSflorian frontend_pid = start_child(PROC_FRONTEND, saved_argv0, 234018cebfbSflorian pipe_main2frontend[1], debug, cmd_opts & (OPT_VERBOSE | 235018cebfbSflorian OPT_VERBOSE2)); 236b2501eadSflorian captiveportal_pid = start_child(PROC_CAPTIVEPORTAL, saved_argv0, 237b2501eadSflorian pipe_main2captiveportal[1], debug, cmd_opts & (OPT_VERBOSE | 238b2501eadSflorian OPT_VERBOSE2)); 239018cebfbSflorian 240bb81f7e1Sflorian uw_process = PROC_MAIN; 241bb81f7e1Sflorian log_procinit(log_procnames[uw_process]); 242018cebfbSflorian 243018cebfbSflorian event_init(); 244018cebfbSflorian 245018cebfbSflorian /* Setup signal handler. */ 246018cebfbSflorian signal_set(&ev_sigint, SIGINT, main_sig_handler, NULL); 247018cebfbSflorian signal_set(&ev_sigterm, SIGTERM, main_sig_handler, NULL); 248018cebfbSflorian signal_set(&ev_sighup, SIGHUP, main_sig_handler, NULL); 249018cebfbSflorian signal_add(&ev_sigint, NULL); 250018cebfbSflorian signal_add(&ev_sigterm, NULL); 251018cebfbSflorian signal_add(&ev_sighup, NULL); 252018cebfbSflorian signal(SIGPIPE, SIG_IGN); 253018cebfbSflorian 254018cebfbSflorian /* Setup pipes to children. */ 255018cebfbSflorian 256018cebfbSflorian if ((iev_frontend = malloc(sizeof(struct imsgev))) == NULL || 257b2501eadSflorian (iev_captiveportal = malloc(sizeof(struct imsgev))) == NULL || 258018cebfbSflorian (iev_resolver = malloc(sizeof(struct imsgev))) == NULL) 259018cebfbSflorian fatal(NULL); 260018cebfbSflorian imsg_init(&iev_frontend->ibuf, pipe_main2frontend[0]); 261018cebfbSflorian iev_frontend->handler = main_dispatch_frontend; 262018cebfbSflorian imsg_init(&iev_resolver->ibuf, pipe_main2resolver[0]); 263018cebfbSflorian iev_resolver->handler = main_dispatch_resolver; 264b2501eadSflorian imsg_init(&iev_captiveportal->ibuf, pipe_main2captiveportal[0]); 265b2501eadSflorian iev_captiveportal->handler = main_dispatch_captiveportal; 266018cebfbSflorian 267b2501eadSflorian /* Setup event handlers for pipes. */ 268018cebfbSflorian iev_frontend->events = EV_READ; 269018cebfbSflorian event_set(&iev_frontend->ev, iev_frontend->ibuf.fd, 270018cebfbSflorian iev_frontend->events, iev_frontend->handler, iev_frontend); 271018cebfbSflorian event_add(&iev_frontend->ev, NULL); 272018cebfbSflorian 273018cebfbSflorian iev_resolver->events = EV_READ; 274bb81f7e1Sflorian event_set(&iev_resolver->ev, iev_resolver->ibuf.fd, 275bb81f7e1Sflorian iev_resolver->events, iev_resolver->handler, iev_resolver); 276018cebfbSflorian event_add(&iev_resolver->ev, NULL); 277018cebfbSflorian 278b2501eadSflorian iev_captiveportal->events = EV_READ; 279b2501eadSflorian event_set(&iev_captiveportal->ev, iev_captiveportal->ibuf.fd, 280b2501eadSflorian iev_captiveportal->events, iev_captiveportal->handler, 281b2501eadSflorian iev_captiveportal); 282b2501eadSflorian event_add(&iev_captiveportal->ev, NULL); 283b2501eadSflorian 284b2501eadSflorian if (main_imsg_send_ipc_sockets(&iev_frontend->ibuf, 285b2501eadSflorian &iev_resolver->ibuf, &iev_captiveportal->ibuf)) 286018cebfbSflorian fatal("could not establish imsg links"); 287018cebfbSflorian 288018cebfbSflorian if ((control_fd = control_init(csock)) == -1) 289018cebfbSflorian fatalx("control socket setup failed"); 290018cebfbSflorian 2919e627e00Sflorian if ((frontend_routesock = socket(AF_ROUTE, SOCK_RAW | SOCK_CLOEXEC, 292df69c215Sderaadt AF_INET)) == -1) 293018cebfbSflorian fatal("route socket"); 294018cebfbSflorian 295018cebfbSflorian rtfilter = ROUTE_FILTER(RTM_IFINFO) | ROUTE_FILTER(RTM_PROPOSAL) | 296018cebfbSflorian ROUTE_FILTER(RTM_GET); 2979e627e00Sflorian if (setsockopt(frontend_routesock, AF_ROUTE, ROUTE_MSGFILTER, 298df69c215Sderaadt &rtfilter, sizeof(rtfilter)) == -1) 299018cebfbSflorian fatal("setsockopt(ROUTE_MSGFILTER)"); 300018cebfbSflorian 301d1b04a40Sflorian if ((ta_fd = open(TRUST_ANCHOR_FILE, O_RDWR | O_CREAT, 0644)) == -1) 302d1b04a40Sflorian log_warn("%s", TRUST_ANCHOR_FILE); 303d1b04a40Sflorian 304d1b04a40Sflorian /* receiver handles failed open correctly */ 305d1b04a40Sflorian main_imsg_compose_frontend_fd(IMSG_TAFD, 0, ta_fd); 306d1b04a40Sflorian 307018cebfbSflorian main_imsg_compose_frontend_fd(IMSG_CONTROLFD, 0, control_fd); 308018cebfbSflorian main_imsg_compose_frontend_fd(IMSG_ROUTESOCK, 0, frontend_routesock); 309018cebfbSflorian main_imsg_send_config(main_conf); 310018cebfbSflorian 3112d988276Sflorian if (main_conf->blocklist_file != NULL) 3122d988276Sflorian send_blocklist_fd(); 3132d988276Sflorian 314d1b04a40Sflorian if (pledge("stdio inet dns rpath sendfd", NULL) == -1) 315018cebfbSflorian fatal("pledge"); 316018cebfbSflorian 317018cebfbSflorian main_imsg_compose_frontend(IMSG_STARTUP, 0, NULL, 0); 318296cf316Sflorian main_imsg_compose_resolver(IMSG_STARTUP, 0, NULL, 0); 319018cebfbSflorian 320018cebfbSflorian event_dispatch(); 321018cebfbSflorian 322018cebfbSflorian main_shutdown(); 323018cebfbSflorian return (0); 324018cebfbSflorian } 325018cebfbSflorian 326018cebfbSflorian __dead void 327018cebfbSflorian main_shutdown(void) 328018cebfbSflorian { 329018cebfbSflorian pid_t pid; 330018cebfbSflorian int status; 331018cebfbSflorian 332018cebfbSflorian /* Close pipes. */ 333018cebfbSflorian msgbuf_clear(&iev_frontend->ibuf.w); 334018cebfbSflorian close(iev_frontend->ibuf.fd); 335018cebfbSflorian msgbuf_clear(&iev_resolver->ibuf.w); 336018cebfbSflorian close(iev_resolver->ibuf.fd); 337b2501eadSflorian msgbuf_clear(&iev_captiveportal->ibuf.w); 338b2501eadSflorian close(iev_captiveportal->ibuf.fd); 339018cebfbSflorian 340018cebfbSflorian config_clear(main_conf); 341018cebfbSflorian 342018cebfbSflorian log_debug("waiting for children to terminate"); 343018cebfbSflorian do { 344018cebfbSflorian pid = wait(&status); 345018cebfbSflorian if (pid == -1) { 346018cebfbSflorian if (errno != EINTR && errno != ECHILD) 347018cebfbSflorian fatal("wait"); 348018cebfbSflorian } else if (WIFSIGNALED(status)) 349018cebfbSflorian log_warnx("%s terminated; signal %d", 350018cebfbSflorian (pid == resolver_pid) ? "resolver" : 351018cebfbSflorian "frontend", WTERMSIG(status)); 352018cebfbSflorian } while (pid != -1 || (pid == -1 && errno == EINTR)); 353018cebfbSflorian 354018cebfbSflorian free(iev_frontend); 355018cebfbSflorian free(iev_resolver); 356b2501eadSflorian free(iev_captiveportal); 357018cebfbSflorian 358018cebfbSflorian log_info("terminating"); 359018cebfbSflorian exit(0); 360018cebfbSflorian } 361018cebfbSflorian 362018cebfbSflorian static pid_t 363018cebfbSflorian start_child(int p, char *argv0, int fd, int debug, int verbose) 364018cebfbSflorian { 365018cebfbSflorian char *argv[7]; 366018cebfbSflorian int argc = 0; 367018cebfbSflorian pid_t pid; 368018cebfbSflorian 369018cebfbSflorian switch (pid = fork()) { 370018cebfbSflorian case -1: 371018cebfbSflorian fatal("cannot fork"); 372018cebfbSflorian case 0: 373018cebfbSflorian break; 374018cebfbSflorian default: 375018cebfbSflorian close(fd); 376018cebfbSflorian return (pid); 377018cebfbSflorian } 378018cebfbSflorian 379ef4f5895Syasuoka if (fd != 3) { 380018cebfbSflorian if (dup2(fd, 3) == -1) 381018cebfbSflorian fatal("cannot setup imsg fd"); 382ef4f5895Syasuoka } else if (fcntl(fd, F_SETFD, 0) == -1) 383ef4f5895Syasuoka fatal("cannot setup imsg fd"); 384018cebfbSflorian 385018cebfbSflorian argv[argc++] = argv0; 386018cebfbSflorian switch (p) { 387018cebfbSflorian case PROC_MAIN: 388018cebfbSflorian fatalx("Can not start main process"); 389018cebfbSflorian case PROC_RESOLVER: 390018cebfbSflorian argv[argc++] = "-E"; 391018cebfbSflorian break; 392018cebfbSflorian case PROC_FRONTEND: 393018cebfbSflorian argv[argc++] = "-F"; 394018cebfbSflorian break; 395b2501eadSflorian case PROC_CAPTIVEPORTAL: 396b2501eadSflorian argv[argc++] = "-C"; 397b2501eadSflorian break; 398018cebfbSflorian } 399018cebfbSflorian if (debug) 400018cebfbSflorian argv[argc++] = "-d"; 401018cebfbSflorian if (verbose & OPT_VERBOSE) 402018cebfbSflorian argv[argc++] = "-v"; 403018cebfbSflorian if (verbose & OPT_VERBOSE2) 404018cebfbSflorian argv[argc++] = "-v"; 405018cebfbSflorian argv[argc++] = NULL; 406018cebfbSflorian 407018cebfbSflorian execvp(argv0, argv); 408018cebfbSflorian fatal("execvp"); 409018cebfbSflorian } 410018cebfbSflorian 411018cebfbSflorian void 412018cebfbSflorian main_dispatch_frontend(int fd, short event, void *bula) 413018cebfbSflorian { 414018cebfbSflorian struct imsgev *iev = bula; 415018cebfbSflorian struct imsgbuf *ibuf; 416018cebfbSflorian struct imsg imsg; 417018cebfbSflorian ssize_t n; 418018cebfbSflorian int shut = 0, verbose; 419018cebfbSflorian u_short rtm_index; 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: 44422731bb8Sflorian open_ports(); 445018cebfbSflorian break; 446018cebfbSflorian case IMSG_CTL_RELOAD: 447018cebfbSflorian if (main_reload() == -1) 448018cebfbSflorian log_warnx("configuration reload failed"); 449018cebfbSflorian else 450018cebfbSflorian log_warnx("configuration reloaded"); 451018cebfbSflorian break; 452018cebfbSflorian case IMSG_CTL_LOG_VERBOSE: 453a9155f32Sflorian if (IMSG_DATA_SIZE(imsg) != sizeof(verbose)) 4542b821978Sflorian fatalx("%s: IMSG_CTL_LOG_VERBOSE wrong length: " 455a9155f32Sflorian "%lu", __func__, IMSG_DATA_SIZE(imsg)); 456018cebfbSflorian memcpy(&verbose, imsg.data, sizeof(verbose)); 457018cebfbSflorian log_setverbose(verbose); 458018cebfbSflorian break; 459018cebfbSflorian case IMSG_OPEN_DHCP_LEASE: 460a9155f32Sflorian if (IMSG_DATA_SIZE(imsg) != sizeof(rtm_index)) 4612b821978Sflorian fatalx("%s: IMSG_OPEN_DHCP_LEASE wrong length: " 462a9155f32Sflorian "%lu", __func__, IMSG_DATA_SIZE(imsg)); 463018cebfbSflorian memcpy(&rtm_index, imsg.data, sizeof(rtm_index)); 464018cebfbSflorian open_dhcp_lease(rtm_index); 465018cebfbSflorian break; 466018cebfbSflorian default: 467018cebfbSflorian log_debug("%s: error handling imsg %d", __func__, 468018cebfbSflorian imsg.hdr.type); 469018cebfbSflorian break; 470018cebfbSflorian } 471018cebfbSflorian imsg_free(&imsg); 472018cebfbSflorian } 473018cebfbSflorian if (!shut) 474018cebfbSflorian imsg_event_add(iev); 475018cebfbSflorian else { 476018cebfbSflorian /* This pipe is dead. Remove its event handler */ 477018cebfbSflorian event_del(&iev->ev); 478018cebfbSflorian event_loopexit(NULL); 479018cebfbSflorian } 480018cebfbSflorian } 481018cebfbSflorian 482018cebfbSflorian void 483018cebfbSflorian main_dispatch_resolver(int fd, short event, void *bula) 484018cebfbSflorian { 485018cebfbSflorian struct imsgev *iev = bula; 486018cebfbSflorian struct imsgbuf *ibuf; 487018cebfbSflorian struct imsg imsg; 488b2501eadSflorian ssize_t n; 4892f29e846Sflorian int shut = 0; 490b2501eadSflorian 491b2501eadSflorian ibuf = &iev->ibuf; 492b2501eadSflorian 493b2501eadSflorian if (event & EV_READ) { 494b2501eadSflorian if ((n = imsg_read(ibuf)) == -1 && errno != EAGAIN) 495b2501eadSflorian fatal("imsg_read error"); 496b2501eadSflorian if (n == 0) /* Connection closed. */ 497b2501eadSflorian shut = 1; 498b2501eadSflorian } 499b2501eadSflorian if (event & EV_WRITE) { 500b2501eadSflorian if ((n = msgbuf_write(&ibuf->w)) == -1 && errno != EAGAIN) 501b2501eadSflorian fatal("msgbuf_write"); 502b2501eadSflorian if (n == 0) /* Connection closed. */ 503b2501eadSflorian shut = 1; 504b2501eadSflorian } 505b2501eadSflorian 506b2501eadSflorian for (;;) { 507b2501eadSflorian if ((n = imsg_get(ibuf, &imsg)) == -1) 508b2501eadSflorian fatal("imsg_get"); 509b2501eadSflorian if (n == 0) /* No more messages. */ 510b2501eadSflorian break; 511b2501eadSflorian 512b2501eadSflorian switch (imsg.hdr.type) { 5132f29e846Sflorian case IMSG_RESOLVE_CAPTIVE_PORTAL: 5142f29e846Sflorian resolve_captive_portal(); 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 693018cebfbSflorian 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 */ 745*7d055805Sflorian 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 */ 752*7d055805Sflorian 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. */ 785*7d055805Sflorian while ((uw_forwarder = TAILQ_FIRST(&conf->uw_forwarder_list)) != 786bb81f7e1Sflorian NULL) { 787*7d055805Sflorian TAILQ_REMOVE(&conf->uw_forwarder_list, uw_forwarder, entry); 788bb81f7e1Sflorian free(uw_forwarder); 789018cebfbSflorian } 790*7d055805Sflorian while ((uw_forwarder = TAILQ_FIRST(&conf->uw_dot_forwarder_list)) != 791bb81f7e1Sflorian NULL) { 792*7d055805Sflorian 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. */ 820*7d055805Sflorian while ((uw_forwarder = TAILQ_FIRST(&xconf->uw_forwarder_list)) != 821bb81f7e1Sflorian NULL) { 822*7d055805Sflorian TAILQ_REMOVE(&xconf->uw_forwarder_list, uw_forwarder, entry); 823*7d055805Sflorian TAILQ_INSERT_TAIL(&conf->uw_forwarder_list, 824bb81f7e1Sflorian uw_forwarder, entry); 825018cebfbSflorian } 826*7d055805Sflorian while ((uw_forwarder = TAILQ_FIRST(&xconf->uw_dot_forwarder_list)) != 827bb81f7e1Sflorian NULL) { 828*7d055805Sflorian TAILQ_REMOVE(&xconf->uw_dot_forwarder_list, uw_forwarder, 829*7d055805Sflorian entry); 830*7d055805Sflorian 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 856*7d055805Sflorian TAILQ_INIT(&xconf->uw_forwarder_list); 857*7d055805Sflorian 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 881018cebfbSflorian open_dhcp_lease(int if_idx) 882018cebfbSflorian { 883018cebfbSflorian static char lease_filename[sizeof(_PATH_LEASE_DB) + IF_NAMESIZE] = 884018cebfbSflorian _PATH_LEASE_DB; 885018cebfbSflorian 886018cebfbSflorian int fd; 887018cebfbSflorian char *bufp; 888018cebfbSflorian 889018cebfbSflorian bufp = lease_filename + sizeof(_PATH_LEASE_DB) - 1; 890018cebfbSflorian bufp = if_indextoname(if_idx, bufp); 891018cebfbSflorian 892018cebfbSflorian if (bufp == NULL) { 893018cebfbSflorian log_debug("cannot find interface %d", if_idx); 894018cebfbSflorian return; 895018cebfbSflorian } 896018cebfbSflorian 897018cebfbSflorian log_debug("lease file name: %s", lease_filename); 898018cebfbSflorian 899018cebfbSflorian if ((fd = open(lease_filename, O_RDONLY)) == -1) { 9004a26c82dSjca if (errno != ENOENT) 9014a26c82dSjca log_warn("cannot open lease file %s", lease_filename); 902018cebfbSflorian return; 903018cebfbSflorian } 904018cebfbSflorian 905018cebfbSflorian main_imsg_compose_frontend_fd(IMSG_LEASEFD, 0, fd); 906018cebfbSflorian } 907d265a5d3Sflorian 908d265a5d3Sflorian void 909d265a5d3Sflorian open_ports(void) 910d265a5d3Sflorian { 911d265a5d3Sflorian struct addrinfo hints, *res0; 912d265a5d3Sflorian int udp4sock = -1, udp6sock = -1, error; 913d265a5d3Sflorian 914d265a5d3Sflorian memset(&hints, 0, sizeof(hints)); 915d265a5d3Sflorian hints.ai_family = AF_INET; 916d265a5d3Sflorian hints.ai_socktype = SOCK_DGRAM; 917cc4fd5c4Stedu hints.ai_flags = AI_NUMERICHOST | AI_PASSIVE; 918d265a5d3Sflorian 919d265a5d3Sflorian error = getaddrinfo("127.0.0.1", "domain", &hints, &res0); 920d265a5d3Sflorian if (!error && res0) { 921d265a5d3Sflorian if ((udp4sock = socket(res0->ai_family, res0->ai_socktype, 922d265a5d3Sflorian res0->ai_protocol)) != -1) { 923d265a5d3Sflorian if (bind(udp4sock, res0->ai_addr, res0->ai_addrlen) 924d265a5d3Sflorian == -1) { 925d265a5d3Sflorian close(udp4sock); 926d265a5d3Sflorian udp4sock = -1; 927d265a5d3Sflorian } 928d265a5d3Sflorian } 929d265a5d3Sflorian } 930296cf316Sflorian if (res0) 931d265a5d3Sflorian freeaddrinfo(res0); 932d265a5d3Sflorian 933d265a5d3Sflorian hints.ai_family = AF_INET6; 934d265a5d3Sflorian error = getaddrinfo("::1", "domain", &hints, &res0); 935d265a5d3Sflorian if (!error && res0) { 936d265a5d3Sflorian if ((udp6sock = socket(res0->ai_family, res0->ai_socktype, 937d265a5d3Sflorian res0->ai_protocol)) != -1) { 938d265a5d3Sflorian if (bind(udp6sock, res0->ai_addr, res0->ai_addrlen) 939d265a5d3Sflorian == -1) { 940d265a5d3Sflorian close(udp6sock); 941d265a5d3Sflorian udp6sock = -1; 942d265a5d3Sflorian } 943d265a5d3Sflorian } 944d265a5d3Sflorian } 945296cf316Sflorian if (res0) 946d265a5d3Sflorian freeaddrinfo(res0); 947d265a5d3Sflorian 948d265a5d3Sflorian if (udp4sock == -1 && udp6sock == -1) 949d265a5d3Sflorian fatal("could not bind to 127.0.0.1 or ::1 on port 53"); 950d265a5d3Sflorian 951b04dd19dSflorian if (udp4sock != -1) 952d265a5d3Sflorian main_imsg_compose_frontend_fd(IMSG_UDP4SOCK, 0, udp4sock); 953b04dd19dSflorian if (udp6sock != -1) 954d265a5d3Sflorian main_imsg_compose_frontend_fd(IMSG_UDP6SOCK, 0, udp6sock); 955d265a5d3Sflorian } 9562f29e846Sflorian 9572f29e846Sflorian void 9582f29e846Sflorian resolve_captive_portal(void) 9592f29e846Sflorian { 9602f29e846Sflorian struct addrinfo hints; 9612f29e846Sflorian void *as; 9622f29e846Sflorian 9632f29e846Sflorian if (main_conf->captive_portal_host == NULL) 9642f29e846Sflorian return; 9652f29e846Sflorian 9662f29e846Sflorian memset(&hints, 0, sizeof(hints)); 9672f29e846Sflorian hints.ai_family = PF_INET; 9682f29e846Sflorian hints.ai_socktype = SOCK_STREAM; 9692f29e846Sflorian 9702f29e846Sflorian log_debug("%s: %s", __func__, main_conf->captive_portal_host); 9712f29e846Sflorian 9722f29e846Sflorian if ((as = getaddrinfo_async(main_conf->captive_portal_host, "www", 9732f29e846Sflorian &hints, NULL)) != NULL) 9742f29e846Sflorian event_asr_run(as, resolve_captive_portal_done, NULL); 9752f29e846Sflorian else 9762f29e846Sflorian log_warn("%s: getaddrinfo_async", __func__); 9772f29e846Sflorian 9782f29e846Sflorian } 9792f29e846Sflorian 9802f29e846Sflorian void 9812f29e846Sflorian resolve_captive_portal_done(struct asr_result *ar, void *arg) 9822f29e846Sflorian { 9832f29e846Sflorian struct addrinfo *res; 9842f29e846Sflorian int httpsock; 9852f29e846Sflorian 9862f29e846Sflorian if (ar->ar_gai_errno) { 9872f29e846Sflorian log_warnx("%s: %s", __func__, gai_strerror(ar->ar_gai_errno)); 9882f29e846Sflorian return; 9892f29e846Sflorian } 9902f29e846Sflorian 9912f29e846Sflorian for (res = ar->ar_addrinfo; res; res = res->ai_next) { 9922f29e846Sflorian if (res->ai_family != PF_INET) 9932f29e846Sflorian continue; 9942f29e846Sflorian log_debug("%s: ip_port: %s", __func__, 9952f29e846Sflorian ip_port(res->ai_addr)); 9962f29e846Sflorian 9972f29e846Sflorian if ((httpsock = socket(AF_INET, SOCK_STREAM | 9982f29e846Sflorian SOCK_CLOEXEC | SOCK_NONBLOCK, 0)) == -1) { 9992f29e846Sflorian log_warn("%s: socket", __func__); 10002f29e846Sflorian break; 10012f29e846Sflorian } 10022f29e846Sflorian if (connect(httpsock, res->ai_addr, res->ai_addrlen) == -1) { 10032f29e846Sflorian if (errno != EINPROGRESS) { 10042f29e846Sflorian log_warn("%s: connect", __func__); 10052f29e846Sflorian close(httpsock); 10062f29e846Sflorian break; 10072f29e846Sflorian } 10082f29e846Sflorian } 10092f29e846Sflorian main_imsg_compose_captiveportal_fd(IMSG_HTTPSOCK, 0, 10102f29e846Sflorian httpsock); 10112f29e846Sflorian } 10122f29e846Sflorian 10132f29e846Sflorian freeaddrinfo(ar->ar_addrinfo); 10142f29e846Sflorian } 10152d988276Sflorian 10162d988276Sflorian void 10172d988276Sflorian send_blocklist_fd(void) 10182d988276Sflorian { 10192d988276Sflorian int bl_fd; 10202d988276Sflorian 10212d988276Sflorian if ((bl_fd = open(main_conf->blocklist_file, O_RDONLY)) != -1) 10222d988276Sflorian main_imsg_compose_frontend_fd(IMSG_BLFD, 0, bl_fd); 10232d988276Sflorian else 10242d988276Sflorian log_warn("%s", main_conf->blocklist_file); 10252d988276Sflorian } 1026679647feSflorian 1027679647feSflorian void 1028679647feSflorian imsg_receive_config(struct imsg *imsg, struct uw_conf **xconf) 1029679647feSflorian { 1030679647feSflorian struct uw_conf *nconf; 1031679647feSflorian struct uw_forwarder *uw_forwarder; 1032679647feSflorian 1033679647feSflorian nconf = *xconf; 1034679647feSflorian 1035679647feSflorian switch (imsg->hdr.type) { 1036679647feSflorian case IMSG_RECONF_CONF: 1037679647feSflorian if (nconf != NULL) 1038679647feSflorian fatalx("%s: IMSG_RECONF_CONF already in " 1039679647feSflorian "progress", __func__); 1040679647feSflorian if (IMSG_DATA_SIZE(*imsg) != sizeof(struct uw_conf)) 1041679647feSflorian fatalx("%s: IMSG_RECONF_CONF wrong length: %lu", 1042679647feSflorian __func__, IMSG_DATA_SIZE(*imsg)); 1043679647feSflorian if ((*xconf = malloc(sizeof(struct uw_conf))) == NULL) 1044679647feSflorian fatal(NULL); 1045679647feSflorian nconf = *xconf; 1046679647feSflorian memcpy(nconf, imsg->data, sizeof(struct uw_conf)); 1047679647feSflorian nconf->captive_portal_host = NULL; 1048679647feSflorian nconf->captive_portal_path = NULL; 1049679647feSflorian nconf->captive_portal_expected_response = NULL; 1050*7d055805Sflorian TAILQ_INIT(&nconf->uw_forwarder_list); 1051*7d055805Sflorian TAILQ_INIT(&nconf->uw_dot_forwarder_list); 1052679647feSflorian break; 1053679647feSflorian case IMSG_RECONF_CAPTIVE_PORTAL_HOST: 1054679647feSflorian /* make sure this is a string */ 1055679647feSflorian ((char *)imsg->data)[IMSG_DATA_SIZE(*imsg) - 1] = '\0'; 1056679647feSflorian if ((nconf->captive_portal_host = strdup(imsg->data)) == 1057679647feSflorian NULL) 1058679647feSflorian fatal("%s: strdup", __func__); 1059679647feSflorian break; 1060679647feSflorian case IMSG_RECONF_CAPTIVE_PORTAL_PATH: 1061679647feSflorian /* make sure this is a string */ 1062679647feSflorian ((char *)imsg->data)[IMSG_DATA_SIZE(*imsg) - 1] = '\0'; 1063679647feSflorian if ((nconf->captive_portal_path = strdup(imsg->data)) == 1064679647feSflorian NULL) 1065679647feSflorian fatal("%s: strdup", __func__); 1066679647feSflorian break; 1067679647feSflorian case IMSG_RECONF_CAPTIVE_PORTAL_EXPECTED_RESPONSE: 1068679647feSflorian /* make sure this is a string */ 1069679647feSflorian ((char *)imsg->data)[IMSG_DATA_SIZE(*imsg) - 1] = '\0'; 1070679647feSflorian if ((nconf->captive_portal_expected_response = 1071679647feSflorian strdup(imsg->data)) == NULL) 1072679647feSflorian fatal("%s: strdup", __func__); 1073679647feSflorian break; 1074679647feSflorian case IMSG_RECONF_BLOCKLIST_FILE: 1075679647feSflorian /* make sure this is a string */ 1076679647feSflorian ((char *)imsg->data)[IMSG_DATA_SIZE(*imsg) - 1] = '\0'; 1077679647feSflorian if ((nconf->blocklist_file = strdup(imsg->data)) == 1078679647feSflorian NULL) 1079679647feSflorian fatal("%s: strdup", __func__); 1080679647feSflorian break; 1081679647feSflorian case IMSG_RECONF_FORWARDER: 1082679647feSflorian if (IMSG_DATA_SIZE(*imsg) != sizeof(struct uw_forwarder)) 1083679647feSflorian fatalx("%s: IMSG_RECONF_FORWARDER wrong length:" 1084679647feSflorian " %lu", __func__, IMSG_DATA_SIZE(*imsg)); 1085679647feSflorian if ((uw_forwarder = malloc(sizeof(struct 1086679647feSflorian uw_forwarder))) == NULL) 1087679647feSflorian fatal(NULL); 1088679647feSflorian memcpy(uw_forwarder, imsg->data, sizeof(struct 1089679647feSflorian uw_forwarder)); 1090*7d055805Sflorian TAILQ_INSERT_TAIL(&nconf->uw_forwarder_list, 1091679647feSflorian uw_forwarder, entry); 1092679647feSflorian break; 1093679647feSflorian case IMSG_RECONF_DOT_FORWARDER: 1094679647feSflorian if (IMSG_DATA_SIZE(*imsg) != sizeof(struct uw_forwarder)) 1095679647feSflorian fatalx("%s: IMSG_RECONF_DOT_FORWARDER wrong " 1096679647feSflorian "length: %lu", __func__, 1097679647feSflorian IMSG_DATA_SIZE(*imsg)); 1098679647feSflorian if ((uw_forwarder = malloc(sizeof(struct 1099679647feSflorian uw_forwarder))) == NULL) 1100679647feSflorian fatal(NULL); 1101679647feSflorian memcpy(uw_forwarder, imsg->data, sizeof(struct 1102679647feSflorian uw_forwarder)); 1103*7d055805Sflorian TAILQ_INSERT_TAIL(&nconf->uw_dot_forwarder_list, 1104679647feSflorian uw_forwarder, entry); 1105679647feSflorian break; 1106679647feSflorian default: 1107679647feSflorian log_debug("%s: error handling imsg %d", __func__, 1108679647feSflorian imsg->hdr.type); 1109679647feSflorian break; 1110679647feSflorian } 1111679647feSflorian } 1112